Skip to content

Commit 4a37174

Browse files
Merge origin/main into feat/564-web-surface
api.mdx: main's per-module table with the web-host row in place of the removed serve-app-command; api/_meta.json follows; package.json keeps the web-host tsconfig in typecheck.
2 parents ef3a25d + 9b02115 commit 4a37174

73 files changed

Lines changed: 4531 additions & 316 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agent-bundle": patch
3+
---
4+
5+
Allow an event route under `src/events/**` to declare a `preflight` gate — `export { default as preflight } from './<name>.js'`, a sync or async function that receives the frozen `{ canonical, host, signal, terminal }` context and returns `'execute'`, `{ outcome: 'continue' }`, or `{ outcome: 'deny', reason }` — which the generated hook entry runs on the canonical event before the rendered route runtime, React, or any application provider loads. `inspect`, `validate`, `build`, and `dev` report `AB4840` when `preflight` is declared inline, exported more than once, re-exported from a bare package or under a binding other than `default`, unresolvable, cyclic, or not a function, naming the route module and, once a re-export was found, its specifier. Allow an executed event route to declare the provider keys it requires (`config.providers: ['<key>', …]`) so only that subset resolves, in the existing deterministic key/source order with `processLifetime` seeded first; a route without a declaration still resolves every conventional provider, `[]` mounts `processLifetime` alone, and `AB4841` reports a malformed declaration, a duplicate key, the reserved `processLifetime`, or a key that matches no discovered `src/providers/*` module — unknown keys list the project's provider keys. Export `EventPreflight`, `EventPreflightContext`, `EventPreflightResult`, `validateEventPreflightResult`, and `eventFamilyAllowsPreflightDeny` from `agent-bundle`, `agent-bundle/api`, and `agent-bundle/routes`. Export the payload-free `EventTraceEvent` union, `createEventTracer`, and `installEventTraceObserver` for developer tooling. (#618)

‎.changeset/quiet-chairs-report.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agent-bundle": patch
3+
---
4+
5+
Move invalid `--port`, `--trials`, `dev --install-host`, and install or uninstall `<host>`, `--mode`, and `--scope` values in the `agent-bundle` CLI away from `AB5000` diagnostics and exit code 1 to Commander usage errors and exit code 2. (#615)

‎.github/dependabot.yml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ updates:
44
directory: /
55
schedule:
66
interval: weekly
7+
groups:
8+
# website/ pins @rspress/core and @rspress/shared to the same exact
9+
# version: plugins/mirror-api-locale.ts imports the slugger Rspress runs
10+
# from @rspress/shared/github-slugger so heading ids match byte for byte,
11+
# which only holds while the two move together. One PR per release.
12+
rspress:
13+
patterns:
14+
- '@rspress/*'
715
ignore:
816
# typescript@7.0.x is a native compiler: import('typescript') is only
917
# { version, versionMajorMinor }. website/rspress.config.ts,

‎AGENTS.md‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@
152152

153153
## Pull requests
154154

155+
- Every PR gets a deslop pass before review: read the full diff against
156+
`origin/main` and remove what a human author would not have written —
157+
comments that restate the code or break the file's style, defensive checks
158+
and `try`/`catch` on trusted paths, `as any` / `as unknown as` casts that
159+
only silence the type checker, nesting that early returns would flatten,
160+
helpers that `dev/http.ts` or `core/*` already own, placeholder prose in
161+
the PR body. Behavior stays unchanged unless the pass finds a clear bug.
162+
Record it in the PR body ("Deslop: model, N edits").
155163
- Every PR gets a self-review before merge: spawn a local reviewer subagent
156164
(`change-risk-reviewer` if available, else `generalPurpose`; a different
157165
model from the author's, e.g. `gpt-5.6-sol-high` or a Claude model — never
@@ -167,9 +175,10 @@
167175
after each push until none remain. Only then merge.
168176
- PRs are squash-merged. Review threads left on an already-merged PR must
169177
still be answered, in a follow-up PR.
170-
- `main` is protected: PRs land only with every required check green and
171-
the branch up to date with `main` (`gh pr update-branch`, then
172-
`gh pr merge --squash --auto`); never bypass with `--admin`.
178+
- `main` is protected: PRs land only with every required check green
179+
(`gh pr merge --squash --auto`; `gh pr update-branch` only when GitHub
180+
reports the branch as conflicting — up-to-date-ness is not enforced, and
181+
CI runs again on `main` after the merge); never bypass with `--admin`.
173182

174183
## Vendored repos
175184

‎docs/diagnostics.md‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ even when no error diagnostic was reported.
3030
| `AB4765`–`AB4766` | Artifact-hosted routed CLI: a target without the `cli` capability omits `bin/<name>.mjs`; a host-emitted file collides with it (see below). |
3131
| `AB477x` | MCP App view compilation (`AB4770`: compile error with file, line, column and the bundler message; `AB4771`: compile warning; `AB4772`: emitted-size advisory; see below). |
3232
| `AB490x`/`AB492x` | Conventional host components (#100 stage 2): rules `src/rules/*.mdc` (`AB4900`–`AB4908`) and commands `src/commands/*.md` (`AB4920`–`AB4928`), including per-host feature-set enforcement (`AB4907`/`AB4908`, `AB4927`/`AB4928`); see below. |
33-
| `AB48xx`/`AB494x` | Route graph, state, layout (`AB4830`–`AB4832`), generated route declarations outside the TypeScript program (`AB4834`), route render budgets (`AB4835`), tool task support (`AB4836`), a route module that value-imports a compiler-carrying framework entry (`AB4837`), a CLI route `inputSchema` reference the static resolver cannot follow (`AB4838`) or that cycles (`AB4839`), and provider conventions (see below). |
33+
| `AB48xx`/`AB494x` | Route graph, state, layout (`AB4830`–`AB4832`), generated route declarations outside the TypeScript program (`AB4834`), route render budgets (`AB4835`), tool task support (`AB4836`), a route module that value-imports a compiler-carrying framework entry (`AB4837`), a CLI route `inputSchema` reference the static resolver cannot follow (`AB4838`) or that cycles (`AB4839`), an event route's `preflight` gate export (`AB4840`), an event route's declared provider keys (`AB4841`), and provider conventions (see below). |
3434
| `AB5000` | General CLI and adapter failures (see below). |
3535
| `AB60xx` | Built-artifact validation, including schema documents and referenced files (`AB6005`: an emitted JavaScript module — a host-pack module or a package build `dist` bundle (`dist/bin/*.js`, the Flight workers, the `lib` entry), prebuilt payloads excepted — has an import that is neither a Node built-in nor a relative or `file:` specifier resolving to a listed regular file inside its tree, or a non-literal dynamic import; a `dist` finding names `dist/<path>`; `AB6011`/`AB6012`: a target's required pinned-schema document is missing or invalid; `AB6025`: a manifest-declared `logo` path is missing from the artifact or escapes the deploy tree; `AB6034`: emitted Skill Markdown has no instruction body; `AB6035`–`AB6038`: Agent Plugins portable validation, see below). |
3636
| `AB6200`–`AB6202` | Workbench artifact inspection over published epochs: `AB6200` the epoch does not validate or its provenance is inconsistent, `AB6201` an epoch reference could not be released, `AB6202` unsafe runtime metadata (see below). |
@@ -1204,6 +1204,56 @@ graphs whose schemas are all inline keep their recorded digests.
12041204
Workbench route detail shows a route's contract origin and the other routes
12051205
sharing it.
12061206

1207+
An event route (`src/events/<family>/*`) may add a **preflight gate** (#595):
1208+
a named `preflight` export the generated hook entry runs after envelope
1209+
decoding, host validation, and canonical event construction, and before any
1210+
of the rendered route runtime — React, the RSC renderer, layouts, providers,
1211+
state, notices — is loaded. The gate is sync or async, receives a frozen
1212+
context of the `canonical` identity and payload the route would receive, the
1213+
compiled host identity and native event name, the request `signal` owned by
1214+
the hook deadline, and translated `terminal` capability metadata (never
1215+
`native`, state, notices, lineage, providers, or
1216+
the request context), and returns exactly one of `'execute'` (load the route
1217+
runtime, resolve its declared providers, render), `{ outcome: 'continue' }`
1218+
(pass through with no host decision), or `{ outcome: 'deny', reason }` (a
1219+
denial projected through the family's canonical outcome rules;
1220+
observation-only families cannot deny). `undefined`, an unknown outcome, an
1221+
extra field, or an empty reason fails closed at hook time. A gate is only
1222+
cheap when the compiler can bundle it on its own, so exactly one authoring
1223+
form is accepted: a single `export { default as preflight } from './<name>.js'`
1224+
in the route module, whose relative target (a `.js` specifier resolves to the
1225+
`.ts`/`.tsx` source, as route imports do) is a readable module whose default
1226+
export is a function — followed, like a route's default re-export, through an
1227+
acyclic chain of relative default re-exports. The compiler records that module
1228+
on the route's own graph node (`preflight` on the compiled route, part of the
1229+
graph digest) and keeps it out of route discovery, so
1230+
`src/events/tool/before.preflight.ts` beside `before.tsx` is application code
1231+
the route names, never a second event route. A `preflight` declared inline in
1232+
the route module (`export const preflight = …`, `export function preflight`)
1233+
is rejected too: evaluating the route module evaluates its rendering and
1234+
provider imports, the very cost the gate exists to avoid. Every rejected form
1235+
is `AB4840`, once per route on the route module; the route compiles without a
1236+
gate beside the error, and because the diagnostic is an error the build fails
1237+
instead of silently taking the expensive path.
1238+
1239+
Provider laziness is declaration-driven (#595). Preflight materializes no
1240+
application providers. An executed event route with no provider declaration
1241+
resolves every conventional provider, as before; a route that declares the
1242+
provider keys it requires — `config.providers: ['<key>', …]`, string literals
1243+
inside the static config grammar — loads and resolves only that subset, still
1244+
once per request, sequentially in the deterministic key-then-source order
1245+
(never declaration order), fail-closed, with the framework-owned
1246+
`processLifetime` seeded first. `[]` is a valid declaration that mounts
1247+
`processLifetime` alone. Keys are the camel-cased `src/providers/<name>.*`
1248+
stems the graph derives (`retry-policy.ts` is `retryPolicy`), the same keys
1249+
the generated `AgentBundleProviders` declares; `processLifetime` is not one of
1250+
them and must not be declared. The declaration is judged when the route graph
1251+
compiles: a declaration that is not an array of string literals, a key listed
1252+
twice, the reserved `processLifetime`, or a key naming no discovered provider
1253+
module is `AB4841`, once per route with every defect in one message; a
1254+
declaration with any defect selects nothing, so the build fails rather than
1255+
resolving a provider set the author did not write.
1256+
12071257
| Code | Severity | Trigger |
12081258
| --- | --- | --- |
12091259
| `AB4800` | error | An MCP server has both discovered route modules under `src/mcp/<id>/` and an existing entry claim (the conventional `src/mcp/<id>.ts` module, or a declared `entry`/`command`/`url`) without an explicit `routes.servers.<id>` mode. |
@@ -1246,6 +1296,8 @@ sharing it.
12461296
| `AB4837` | error | A route module of any kind except an App — a `src/cli/**` command, a `src/scripts/**` script, a tool, resource, or prompt route of a generated server, an event route — a layout, or a provider, or a module one of them reaches through relative value imports, imports `agent-bundle`, `agent-bundle/api`, `agent-bundle/config`, `agent-bundle/eval`, `agent-bundle/rstest`, `agent-bundle/test`, or `agent-bundle/test/browser` as a value (a static import whose binding is read at run time, `import 'agent-bundle/api'`, `import('agent-bundle/api')` with a literal specifier, or a non-type re-export). Those entries carry the compiler, and the generated executable is self-contained (#387): the bundler would inline the compiler and fail on the framework's runtime-relative module references (`Module not found: Can't resolve '../events'`), or the artifact validator would reject the inlined compiler's non-literal dynamic imports with `AB6005` — either way naming a generated file instead of the route (#558). Judged statically when the route graph compiles, so `inspect`, `validate`, `build`, and `dev` all report it, once per module, naming the route and the helper the import lives in. `import type`, `type`-qualified specifiers, and imports used only in type positions are elided by the bundler and never reported; routes of a server that is not generated (`custom`/`command`/`remote`, or an `AB4800` conflict) or of a CLI that is not generated (`conventional`, or an `AB4801` conflict) are never bundled, so they are not judged; likewise a layout that no bundled rendered route composes through (a worker imports only the layouts its routes reach: the tool, resource, and prompt routes of a generated server, the rendered `.tsx` commands of a generated CLI, and rendered `.tsx` scripts), and a provider in a project whose only executables are plain `.ts` scripts, which are bundled from their own source and mount none. Keep framework calls in a host process: expose an MCP App with `web.apps` and open it from the installed artifact with `<plugin> web`; keep other framework calls in host processes (`package.json` scripts, a hand-written `.mjs` run from the checkout). The bundle-safe entries stay allowed: `agent-bundle/app` (the browser MCP App client, a leaf with no Zod, Node, or compiler import), `agent-bundle/routes`, `agent-bundle/launch-env`, `agent-bundle/meta`, `agent-bundle/mcp-apps`, `agent-bundle/mcp-entry`, `agent-bundle/cli-entry`, `agent-bundle/terminal-capability`, and `agent-bundle/web-host`. |
12471297
| `AB4838` | error | A CLI route's `inputSchema` references a binding the static resolver cannot follow. The message is `CLI route <path> inputSchema: <chain> <reason>.` — the chain is the reference path from `inputSchema`, each step `<binding>`, or `<binding> (<module>)` when it crosses into another module (`inputSchema -> statusInputSchema (src/lib/protocol-schemas.ts) -> requestStatusSchema -> requestStatuses`), and the reason names the boundary: a specifier that `is not a relative module path`, one that `resolves outside the project` or `does not resolve to a module inside the project` (missing or unreadable), a target module that does not declare a top-level `export const <name>`, a binding that is not a top-level `const` (`let`/`var`, destructuring, a function, a class, a default or namespace import — the message says what it is), an identifier that `is neither a top-level const in this module nor a named import from a relative module`, or a dynamic initializer — one that is neither a method chain, an object or array literal, nor a static literal (`whose initializer is a call expression`, `a function expression`, `a template literal with substitutions`). Reported on the route module; the recovery names the supported forms — relative imports inside the project, `export const`, alias chains — then says to inspect again. Only CLI routes raise it, because only there the static contract is load-bearing: an MCP, script, or event route whose schema the resolver cannot follow compiles without a static contract, as an out-of-grammar inline schema does, and the runtime derives its MCP JSON Schema from the real zod object. A reference that resolves but whose schema leaves the grammar is `AB4814`. |
12481298
| `AB4839` | error | A CLI route's `inputSchema` reference chain is cyclic — `a` → `b` → `a`, within one module or across several: every visited `<module>#<binding>` is recorded and revisiting one stops the walk. The message is `CLI route <path> inputSchema: <chain> is a reference cycle.` and prints the cycle; it is reported on the route module, with the same recovery and the same CLI-only rule as `AB4838`. |
1299+
| `AB4840` | error | An event route's `preflight` gate (#595) is not the one physically cheap form the compiler can bundle on its own. Rejected: `preflight` declared inline in the route module (`export const preflight = …`, `export function preflight`) or exported more than once; re-exported under a binding other than `default` (`export { gate as preflight } from './gate.js'`, `export { preflight } from './gate.js'`); re-exported from a non-relative specifier (a bare package such as `'@scope/gate'`); a relative target that is missing, unreadable, or part of a re-export cycle; a target default export that cannot be followed through an acyclic chain of relative default re-exports; or a target default export that is not a function the scan can see. The message names the route module and, once a re-export was found, its specifier. Judged statically when the route graph compiles, so `inspect`, `validate`, `build`, and `dev` all report it, once per route with the route module as `sourcePath`; the route compiles without a gate beside the error, and the build fails rather than silently taking the expensive rendered path. Write exactly `export { default as preflight } from './<name>.js'` in the route module, and make that module default-export one sync or async function receiving `{ canonical, host, signal, terminal }` and returning `'execute'`, `{ outcome: 'continue' }`, or `{ outcome: 'deny', reason }`. |
1300+
| `AB4841` | error | An event route's static required-provider declaration (#595) does not select a known set of conventional providers: `config.providers` is not an array of provider-key strings; a key is declared more than once; a key is the reserved `processLifetime`; or a key matches no conventional provider the route graph discovered under `src/providers/`. The message names the route and every offending key. Declare each key exactly once, spelled as the camel-cased stem of its `src/providers/<name>.*` module, drop `processLifetime`, declare `[]` to mount `processLifetime` alone, or omit `config.providers` to preserve the all-provider compatibility default. |
12491301
| `AB4940` | error | A conventional provider module has no default export or its default export is not a function. Default-export a factory receiving `{ invocation, plugin, signal }`. |
12501302
| `AB4941` | error | Two provider filenames derive the same camel-cased provider key. Rename one file so every provider key is unique. |
12511303
| `AB4942` | error | A provider filename derives the reserved `processLifetime` key. Rename the file so its camel-cased key does not collide with the framework-owned provider. |

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"test:watch": "rstest --config rstest.config.ts --watch",
2323
"lint": "rslint .",
2424
"bench:hook-cold-start": "node scripts/measure-hook-cold-start.mjs",
25+
"bench:preflight-cold-start": "node scripts/measure-preflight-cold-start.mjs",
2526
"typecheck": "node scripts/check-dist-fresh.mjs && tsc --noEmit && tsc --project packages/workbench/tsconfig.json && tsc --project packages/create-agent-bundle/tsconfig.json && tsc --project packages/rsc-markdown-stream/tsconfig.json && tsc --project packages/agent-bundle/tsconfig.web-host.json && pnpm --filter @agent-bundle/docs typecheck",
2627
"check": "pnpm build && pnpm test:unit && pnpm test:route-unit && pnpm test:projection && pnpm test:integration:run && pnpm lint && pnpm typecheck",
2728
"check:local-ci": "node scripts/local-ci.mjs",

0 commit comments

Comments
 (0)