Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
# `wasi-stdio-validate`
## Purpose
ABI surface validator for the WASI-stdio variant. Inspects a
`WebAssembly.Module`'s imports and exports BEFORE instantiation and
raises `SAND_WASM_BRIDGE.INVALID_PLUGIN_SURFACE` if the module is
missing any of the five required WASI imports
(`wasi_snapshot_preview1.{fd_read, fd_write, environ_get,
environ_sizes_get, proc_exit}`) OR the two required exports (`memory`,
`_start`). The check is the WASI-stdio mirror of `validateWasmAbi`
in `abi-direct/wasm-abi/`; it does NOT require the six
`__suaveplan_*` direct-variant exports because Javy-compiled plugins
cannot emit them.
## Features
- Module-level (pre-instantiation) check — operators see the failure
before the host commits to instantiating the plugin.
- Both required imports and required exports are validated in a single
pass; `context.missing` carries the sorted union of absent symbols.
- Namespace-qualified diagnostic for imports
(`wasi_snapshot_preview1.fd_read`) vs bare for exports (`_start`)
makes the absent surface obvious at a glance.
- The required-symbol lists are sorted constants so a future addition
surfaces as a typecheck divergence rather than a silent drift.
## Usage: Basic
```ts
import { validateWasiStdioAbi } from
"@suaveplan/api-sandbox-wasm-host-bridge/abi-wasi-stdio";
declare const module: WebAssembly.Module;
validateWasiStdioAbi(module, "example");
// Throws SandboxWasmBridgeError on missing surface.
```
## Usage: Advanced
```ts
import { validateWasiStdioAbi } from
"@suaveplan/api-sandbox-wasm-host-bridge/abi-wasi-stdio";
import {
SAND_WASM_BRIDGE_CODES,
SandboxWasmBridgeError,
} from "@suaveplan/api-sandbox-wasm-host-bridge/error-codes";
declare const module: WebAssembly.Module;
try {
validateWasiStdioAbi(module, "billing");
} catch (err) {
if (
err instanceof SandboxWasmBridgeError &&
err.code === SAND_WASM_BRIDGE_CODES.INVALID_PLUGIN_SURFACE
) {
const missing = (err.context as { missing?: readonly string[] })
.missing;
// missing → ["_start"] OR ["wasi_snapshot_preview1.fd_read", ...]
void missing;
}
}
```
## API Reference
### `validateWasiStdioAbi(module, pluginName): void`
- `module: WebAssembly.Module` — pre-compiled module under inspection.
- `pluginName: string` — error-context label.
Throws `SandboxWasmBridgeError` with code
`SAND_WASM_BRIDGE.INVALID_PLUGIN_SURFACE` and
`context.abiVariant = "wasi-stdio"` + sorted `context.missing`.
### `REQUIRED_WASI_STDIO_IMPORTS: readonly string[]`
Sorted list: `environ_get`, `environ_sizes_get`, `fd_read`, `fd_write`,
`proc_exit`.
### `REQUIRED_WASI_STDIO_EXPORTS: readonly string[]`
Sorted list: `_start`, `memory`.
## Implementation Notes
- The validator walks `WebAssembly.Module.imports(module)` and
`WebAssembly.Module.exports(module)` once each — both are O(n) over
the module's metadata and never touch the linear memory. Running
them BEFORE instantiation costs effectively nothing.
- The required-imports list is intentionally minimal: it captures the
five hooks any WASI-stdio guest MUST call. A guest that uses
additional WASI imports (e.g. `clock_time_get`, `random_get`) is
fine — those are wired by the runner but their absence is not a
surface error.
- `context.abiVariant` carries the literal `"wasi-stdio"` string so
operators reading a stack trace can tell which variant raised
without inferring it from the plugin's manifest. The direct
validator does not set this field for the inverse reason: the
direct path is the default and the absence of the field implies
it.