Skip to content

fix!: rework plugin configuration block - #33

Merged
sanchitrk merged 10 commits into
devfrom
fix-plugin-loader
Sep 17, 2026
Merged

sanchitrk merged 10 commits into
devfrom
fix-plugin-loader

Conversation

@sanchitrk

Copy link
Copy Markdown
Contributor

No description provided.

`codework serve` boots the harness once and serves session, sandbox, and event
RPCs over a WebSocket; `codework run --server <url>` drives a session remotely
through the same contract.

Harness changes this required:

- Execution lifecycle events: a busy period publishes `session.execution.started`
  and exactly one of `succeeded`, `failed`, or `interrupted`. A failure carries a
  namespaced category rather than a squashed cause string, and an interruption
  carries the reason its caller gave instead of one inferred from the cause.
- `Control.interrupt` acknowledges without waiting and returns whether there was
  work to stop. `awaitSettlement` waits for that execution alone, where
  `awaitIdle` follows successors admitted during its cleanup.
- Plugins declare the events they publish with `Plugin.define({ events })`.
  `EventRegistry.flatten` collects them before the event system builds and fails
  the boot on a kernel collision, a duplicate across plugins, or a type outside
  `plugin.<plugin-id>.*`.
- `optional()` used the source schema as its own `decodeTo` target, so nested
  transforms ran twice: an Option encoded to null, then null re-encoded as an
  Option.

Events reach clients through one feed that encodes each event once and fans it
out, so a slow client fails alone and a type nothing declared never costs a
client its queue capacity. Sessions are shared, so a terminal event arriving
before the client's own prompt is promoted is remembered rather than raised, and
the client reconciles against `session.message` before reporting — the volatile
stream is never the last word.
- one hung remote sandbox like Daytona or Vercel request can prevent the server process from exiting indefinitely.
- shutdown interrupts every active session and awaits settlement.
- mount finalizers release their sandbox leases.
- `Sandbox.stop` rechecks the current refCount while holding the sandbox lifecycle gate.
- If refCount > 0, it returns SandboxBusyError; shutdown logs that failure and continues.
- add location-level errors for missing paths and paths that are not directories,
 and expose them through the session.create and session.relink RPC contracts.
- preserve Runner.SandboxDirectoryNotFoundError for persisted session directories that disappear during execution.
- mark sandbox filesystem adapter layers as fresh so long-running servers do not reuse a memory or SQLite filesystem for later local mounts.
- add RPC coverage for relative sandbox paths, invalid local paths, relinking, and filesystem isolation across sandbox mounts.
A `plugins` entry is now either a module or a configuration object. A module is a
definition, a path, a `file:` URL, or a package spec; it loads and takes the position
it is written at. A configuration object names a plugin something else selected, by ID
(`plugin`) or by the package it came from (`package`), and never loads, installs or
reorders anything — a name matching nothing in the selection is ignored.

- Replace the `"!id"` disable syntax with `{ "plugin": "...", "enabled": false }`.
- Deliver a per-plugin `options` block as `setup(ctx, options)`. The block is opaque:
  it replaces rather than merges, and survives settings normalization and the layer
  merge so a `null` inside it reaches the plugin.
- Alias a loaded module by its package name, spec, path and manifest name, so a
  configuration entry can address it without knowing the plugin ID.
- Treat a plugin ID as a key: the last module to claim it owns it, and configuration
  written against it stays with the key.
- Fail on corrupt configuration instead of absorbing it. A settings file that exists
  and cannot be read, parsed or decoded fails the load with its path, reason and
  offending key, at construction and at the capture after an edit breaks it.
- Carry `SettingsError` through the run error channel as the `settings` failure
  category, and give it and `SnapshotError` a `message`, which clients received empty.
- Validate entry shape in `prepare` for callers that never pass through decoding.
- Add worked examples under `extras/`: `@acme/codework-tool-proc`,
  `codework-prompt-life`, and two single-file plugins, loaded for real by the tests.

BREAKING CHANGE: a bare string is a module only, so a built-in is no longer selected
by ID; settings address built-ins through `{ "plugin": "codework.tool.bash", ... }`,
and an embedder composing its own order passes its whole selection. `Plugin.setup`
takes a second argument. A malformed settings file now fails instead of warning.
@sanchitrk sanchitrk changed the title Fix plugin loader fix(harness)!: rework plugin configuration block Sep 17, 2026
@sanchitrk sanchitrk changed the title fix(harness)!: rework plugin configuration block fix!: rework plugin configuration block Sep 17, 2026
@sanchitrk
sanchitrk merged commit 34398dd into dev Sep 17, 2026
@sanchitrk
sanchitrk deleted the fix-plugin-loader branch September 22, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant