83 lines
4.2 KiB
Markdown
83 lines
4.2 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 preserves the user's Cargo configuration and its kache wrapper.
|