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,81 @@
# lifecycle
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the idempotency wrapper around a `VmSandboxHandle`'s
`start` / `dispose` lifecycle. The host's lifecycle driver may invoke
these hooks multiple times (e.g. a hot-reload's stop+start pair, or a
test harness's deterministic shutdown sequence); the wrapper makes the
double-invocation case a silent no-op rather than a throw, and
reflects under-the-hood sandbox throws via the bridge's
`LIFECYCLE_FAILED` code so the host's error boundary sees a uniform
shape.
Splitting the wrapper into its own module keeps the bridge factory
small (no inline state machine) and gives the conformance harness a
direct seam for asserting idempotency without standing up the full
bridge.
## Features
- Idempotent `start` — second call returns without re-invoking
`sandbox.start()`.
- Idempotent `dispose` — second call returns without re-invoking
`sandbox.dispose()`.
- Forbidden start-after-dispose — calling `start()` after `dispose()`
raises `LIFECYCLE_FAILED` so the host can fail the hot-reload
cleanly rather than silently swallowing the request.
- Error wrapping — underlying sandbox throws surface as
`SandboxVmBridgeError` with `code: LIFECYCLE_FAILED` and the
original error preserved as `cause`.
- Inspection helpers — `hasStarted()` and `isDisposed()` for the
bridge's internal request-pipeline guard.
## Usage: Basic
```ts
import { createSandboxLifecycleForwarder } from "@suaveplan/api-sandbox-vm-host-bridge/lifecycle/lifecycle";
const forwarder = createSandboxLifecycleForwarder(sandbox);
await forwarder.start();
forwarder.dispose();
forwarder.dispose(); // no-op
```
## Usage: Advanced
```ts
import { createSandboxLifecycleForwarder } from "@suaveplan/api-sandbox-vm-host-bridge/lifecycle/lifecycle";
const forwarder = createSandboxLifecycleForwarder(sandbox);
try {
await forwarder.start();
} catch (err) {
// err.code === "SAND_VM_BRIDGE.LIFECYCLE_FAILED"
// err.cause is the original SandboxVmError
rollbackJournal.markFailed(err);
}
```
## API Reference
- `interface SandboxLifecycleForwarder` — `start()`, `dispose()`,
`hasStarted()`, `isDisposed()`.
- `createSandboxLifecycleForwarder(sandbox: VmSandboxHandle):
SandboxLifecycleForwarder` — factory; returns a frozen object.
## Implementation Notes
The internal `started` / `disposed` flags are kept in a closure rather
than on the returned object so the sandbox cannot mutate them via a
property-set on the forwarder. The forwarder itself is `Object.freeze`d
so consumers cannot patch `dispose` to skip the cleanup. Errors raised
inside `dispose()` are caught and rewrapped — the alternative (letting
them propagate raw) would mean the host's error boundary sees a mixed
shape (sometimes `SandboxVmError`, sometimes
`SandboxVmBridgeError`); the wrap keeps the boundary's branch arm
tight.