Files
sausage/extensions/README.md
T

83 lines
4.3 KiB
Markdown

# World extensions
The harness loads `/src/sausage` from its `main` branch.
Each extension occupies `extensions/<name>/server.ts` in that repository.
The default export is an extension or a factory that receives a `Host`.
The extension name must match its folder.
An optional numeric `order` export controls order. Names break ties.
## Reload contract
A change to the branch ref or `packed-refs` triggers a reload.
The harness creates a detached world worktree at `/run/sausage/extensions/<sha>`.
Imports read that snapshot through the world VFS, not the editable checkout.
Relative imports must include their file extensions.
TypeScript modules use the same `deno_ast` transpiler as the harness.
The harness imports and validates the whole commit before it changes the live registry.
An import error, factory error, name mismatch, or registry validation error retains the previous commit.
A running tool call keeps its old implementation. The next call uses the new implementation.
Removed extensions leave the registry after a successful reload.
`/proc/extensions` contains JSON with `good`, `current`, and `error`.
A session document persists these values in the harness database.
On startup, the harness tries the tip, then the last good commit, before `resume()`.
Tasks without a registered definition remain blocked.
The snapshot worktrees disappear with `/run` on restart. The loader prunes stale worktree registrations before it recreates them.
## Host
The host supplies these members:
- `harness()`, `storage.scanSubmissions`, `models()`, and the conversation `metadata` document token.
- `settings()`, from `/src/sausage/settings.json`. The VFS watcher detects changes to this file.
- `fs.read`, `write`, `append`, `list`, `stat`, `lstat`, `mkdir`, `remove`, and `rename` on world paths.
- `exec(command, options)` for shell strings or argument arrays. Its result contains `code`, `stdout`, and `stderr`.
- Exec options: `cwd`, `env` pairs, `timeout` in seconds, `conversations`, `signal`, and `onOutput(text, stream)`.
- `git(cwd, ...args)`, which returns trimmed stdout and throws with stderr on failure.
- `implement(api, value)`, which stages a service until the commit installs.
- `need(api)`, which returns a proxy. Every method call resolves the current provider, including a retained method reference.
- `want(api)`, which returns a proxy or `undefined` when no provider exists.
- `onOpen(callback)` and `onClose(callback)` for facet lifecycle.
- `resource(key, create)`, which retains a value across reloads. Keys belong to their extension name.
- `notice(message)`, which writes a console line and the latest notice to `/proc/extensions`.
P3-d will add `emit`, `react`, and `eventLog` at the marked seam in `host/js/extensions.ts`.
Those APIs will supply transactional events and persistent reactor cursors.
The synthetic package modules reuse the bundle's instances:
- `@earendil-works/pi-durable` and `/tools`
- `@earendil-works/pi-ai` and `/models`
- `@earendil-works/pi-schema`
- `@earendil-works/chord` and `/context`
New package surfaces require a namespace in `registerModules()`.
They must not bundle a second pi-durable instance.
The registry supplies the default extension selection for existing conversations.
New root conversations do not pin the built-ins.
Explicit per-conversation extension selections remain explicit.
## Revert
Run this command inside the world:
```sh
extensions-revert
```
The Rust program lives in `userland/exec-tools/src/revert.rs`.
It reads `/src/sausage/.git/sausage-last-good` and calls world git to update `refs/heads/main`.
The loader writes this helper file after it persists the session status.
An empty helper file means no commit succeeded yet.
The command preserves the editable checkout. The branch change triggers the normal reload.
## Tests
`host/tests/extensions.rs` runs `host/js/extensions-test-bundle.js` with world git and a faux model.
It tests A, broken B, changed C, an old call across reload, a retained service handle, and restart recovery.
It also tests the revert command, file operations, and exec environment options.
The world git and helper components use the executor's shared `CARGO_TARGET_DIR`.
The API and hook fixtures use that directory too.
The Nix shell overrides `CARGO_HOME`. Unset that variable before Cargo commands to preserve the configured kache wrapper.