Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/rslib-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"agent-bundle": patch
"@agent-bundle/runtime": patch
"create-agent-bundle": patch
---

Build on Rslib 1.0 and Rsbuild 2.2 so a project installs one Rspack engine and one native
binding instead of two; `create-agent-bundle` templates pin `@rstest/core` 0.11.12. Plugin
builds stay self-contained (`output.autoExternal: false`, Node builtins the only externals) and
keep `new URL(…, import.meta.url)` and `new Worker(new URL(…))` expressions verbatim.
`agent-bundle inspect --bundler` lowers in production mode regardless of `NODE_ENV` and shows the
new `bundlerChain` invariant beside `tools.rspack`. Published `.d.ts` files (`agent-bundle`,
`@agent-bundle/runtime`) now import their siblings with `.js` specifiers; every `exports` entry
resolves as before. (#575)
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

- Generated plugin output is self-contained. The compiler profile in
`packages/agent-bundle/src/build/rslib.ts` (`composeEntryLibConfig`) bundles
every dependency of a generated executable — `autoExternal: false`,
every dependency of a generated executable — `output.autoExternal: false`,
`bundle: true`, `splitChunks: false`, no `externals`. Rslib's `node` target
leaves only Node built-ins (and `pnpapi`) external, and the only bare
specifiers `AB6005` accepts in a host-pack module are Node built-ins, so a
Expand Down
1 change: 0 additions & 1 deletion docs/effect-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,6 @@ soon as the trigger fires and retire the row.

| Recorded | Pin (where) | Observed registry state | Trigger / action |
| --- | --- | --- | --- |
| 2026-09-03 | `@rslib/core` **`0.23.2`** — root, `packages/agent-bundle`, `packages/rsc-runtime`, `packages/create-agent-bundle` devDependencies. Stays on `0.23.x` until rslib 1.0 leaves rc. | `npm view @rslib/core dist-tags`: `latest` `0.23.2`, `rc` `1.0.0-rc.2`, `beta` `1.0.0-beta.3`, `canary` `0.20.0-canary-202603101`. | `latest` becomes `1.x`. Bump all four pins in one chore; re-run `pnpm build` (publint runs inside it), `check:release`, and the Rslib-driven compile tests. |
| 2026-09-03 | `effect-rstest` **pkg.pr.new preview `e5f8d5f`** (`https://pkg.pr.new/ScriptedAlchemy/effect-rstest@e5f8d5f`) — `packages/agent-bundle`, `packages/rsc-runtime`, `packages/create-agent-bundle` devDependencies (three pins). Needs a real release pin once published. | `npm view effect-rstest versions`: **E404 — not published to npm** (no versions, no dist-tags). | First npm publish of `effect-rstest`. Replace all three preview URLs with the exact published version, refresh `pnpm-lock.yaml`, re-run `pnpm test:unit` (`it.effect` / `it.live` suites). |
| 2026-09-03 | `effect` **`4.0.0-rc.112`** (`packages/agent-bundle`, `packages/rsc-runtime`, `packages/workbench`, `packages/create-agent-bundle`), `@effect/atom-react` `4.0.0-rc.112` (`packages/workbench`), `@effect/platform-node` `4.0.0-rc.112` (`packages/create-agent-bundle`), `@effect/platform-node-shared` `4.0.0-rc.112` (`packages/agent-bundle`), `@effect/language-service` `0.87.2` and `@effect/tsgo` `0.39.0` (root). Auto re-pin in lockstep + `repos/effect` subtree + Workbench atom phase 4 unblock (stream-backed derived atoms) once the post-rc.112 disposal fix ships. | `npm view effect dist-tags`: `rc` **`4.0.0-rc.112`** (unchanged), `beta` `4.0.0-beta.107`, `latest` `3.22.1`. `@effect/atom-react`: `rc` `4.0.0-rc.112`. `@effect/language-service`: `latest` `0.87.2`. `@effect/tsgo`: `latest` `0.39.1` (patch ahead of the `0.39.0` pin; rides the lockstep chore). | `effect@rc` advances past `4.0.0-rc.112`. Run the re-pin chore steps 1–6 above, bumping `effect`, `@effect/atom-react`, `@effect/language-service`, and `@effect/tsgo` together, then lift the stream-backed derived-atom ban in the Workbench if the disposal fix is in the new RC. |
| 2026-09-03 | Agent Plugins specification **`1.0.0`** — `packages/agent-bundle/src/adapters/schemas/portable/{plugin,mcp}.schema.json` + `PROVENANCE.json` (spec repo `agentplugins/agent-plugins-spec` @ `ff8ab5e392cc87bd88d87c060815a87490e51003`, 2026-08-19), portable `adapterRevision` `1.8.0`, pins in `tests/adapter-metadata.test.ts`. Spec watch for #426; not an npm pin, so re-verify with `curl`/`gh api`, not `npm view`. | Live `https://agent-plugins.org/schemas/1.0.0/{plugin,mcp}.schema.json` rehash to the pinned sha256 (1805 / 3408 bytes). Repo `main` HEAD unchanged at the pinned commit; **no tags, no GitHub releases**. `spec/1.1.0.md` is "Status: Working Draft" (started 2026-08-15, `a2afd7ec`); in-repo `schemas/1.1.0/*.schema.json` differ from 1.0.0 only in the `$id`/`const`/`description` version strings; `https://agent-plugins.org/schemas/1.1.0/*.schema.json` → 404. Observed latest published version: **1.0.0**. | `spec/1.1.0.md` (or later) flips to "Published" **and** `agent-plugins.org/schemas/<version>/` serves both schemas. Re-pin under `schemas/portable/` with a dated `PROVENANCE.json` (sha/bytes/date/commit), bump the portable `adapterRevision`, refresh the metadata pins, run `pnpm test:unit` (portable adapter + plugin-validation suites) and `pnpm test:host-install:build`, and add a capability row per additive field. |
40 changes: 23 additions & 17 deletions docs/entry-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1208,10 +1208,15 @@ module specifier (`agent-bundle/meta`, or a registry specifier such as
and through a post-build scan of the emitted bundle for function-form
`externals` — because generated executables must stay self-contained. The
hatch customizes *how code compiles*, never *what the artifact promises*. The
framework's own profile keeps the same promise: `autoExternal` is off,
`bundle: true`, `splitChunks: false`, and no `externals` are added, so Rslib's
`node` target leaves only Node built-ins (and `pnpapi`) external, and `AB6005`
fails any bare specifier that is not a Node built-in in a host-pack module.
framework's own profile keeps the same promise: `output.autoExternal` is
`false`, `bundle: true`, `splitChunks: false`, and no `externals` are added, so
Rslib's `node` target leaves only Node built-ins (and `pnpapi`) external, and
`AB6005` fails any bare specifier that is not a Node built-in in a host-pack
module. Run-time path references are kept the same way: a
`new URL(…, import.meta.url)` or `new Worker(new URL(…))` in consumer or
generated code names a file beside the artifact, so the invariant layer turns
the bundler's URL and worker asset processing off after the hatch and the
expression reaches the artifact verbatim.

The hatch merges *beside* the framework profile, not over it: `plugins`
arrays concatenate, and Rsbuild's plugin manager appends every plugin it is
Expand All @@ -1223,16 +1228,17 @@ reports that as `AB4724` (an error, like the other `tools` shape checks) with
the plugin and package name; remove the entry, the framework already
registers it.

The hatch executes under two different bundler engine copies. Artifact
scripts, MCP entries, hook wrappers, and the package build compile through
Rslib, which runs the Rsbuild/Rspack versions nested inside `@rslib/core`
(currently the 2.1.x line); MCP App views compile through the
workspace-pinned `@rsbuild/core` (currently 2.2.x), until Rslib catches up to
the Rsbuild 2.2 line. So a hatch must never construct plugins or run
`instanceof` checks against an imported `@rspack/core`: a class imported from
a separately installed `@rspack/core` has a different identity than whichever
engine executes the config. Use instead the utils argument Rslib/Rsbuild pass
to `tools.rspack` mutator functions —
The hatch executes on one bundler engine. Artifact scripts, MCP entries,
hook wrappers, and the package build compile through Rslib; MCP App views
compile through `@rsbuild/core`; and agent-bundle pins `@rsbuild/core` inside
the range its `@rslib/core` accepts, so a consumer installs a single
`@rsbuild/core`, a single `@rspack/core`, and a single native Rspack binding
(a packed-consumer test holds that line). That engine is agent-bundle's
dependency, not the consumer's: a class imported from a separately installed
`@rspack/core` can have a different identity than the engine executing the
config. So a hatch must never construct plugins or run `instanceof` checks
against an imported `@rspack/core`. Use instead the utils argument
Rslib/Rsbuild pass to `tools.rspack` mutator functions —
`tools: { rspack: (config, { rspack }) => { ... } }` — which always hands the
engine's own `rspack` object.

Expand Down Expand Up @@ -1285,9 +1291,9 @@ agent-bundle inspect --bundler [--target <t>] [--json]
Dumps the synthesized bundler configuration for every output the build
composes — artifact scripts, MCP entries, hook wrappers, the per-target MCP
Apps Rsbuild config, and the `dist/` package build — exactly as the build
lowers it: the framework profile with the consumer `tools` hatch merged over
it and the invariant hook appended last (functions render as
`[function <name>]`). Entries the framework wraps also carry the generated
lowers it: in production mode whatever `NODE_ENV` says, the framework profile
with the consumer `tools` hatch merged over it and the invariant hook appended
last (functions render as `[function <name>]`). Entries the framework wraps also carry the generated
wrapper module source (`generatedEntry`). The composition comes from the same
functions the build uses, so the dump cannot drift from what compiles.

Expand Down
2 changes: 1 addition & 1 deletion examples/audiobook-curator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
},
"devDependencies": {
"@agent-bundle/runtime": "workspace:*",
"@rstest/core": "0.11.10",
"@rstest/core": "0.11.12",
"@types/react": "19.2.18",
"agent-bundle": "workspace:*",
"react": "19.2.8",
Expand Down
2 changes: 1 addition & 1 deletion examples/host-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"devDependencies": {
"@agent-bundle/runtime": "workspace:*",
"@modelcontextprotocol/server": "2.0.0",
"@rstest/core": "0.11.10",
"@rstest/core": "0.11.12",
"@types/react": "19.2.18",
"agent-bundle": "workspace:*",
"react": "19.2.8",
Expand Down
6 changes: 3 additions & 3 deletions examples/mcp-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"devDependencies": {
"@modelcontextprotocol/ext-apps": "1.7.5",
"@modelcontextprotocol/server": "2.0.0",
"@rstest/browser": "0.11.10",
"@rstest/core": "0.11.10",
"@rstest/playwright": "0.11.10",
"@rstest/browser": "0.11.12",
"@rstest/core": "0.11.12",
"@rstest/playwright": "0.11.12",
"agent-bundle": "workspace:*",
"playwright": "1.62.1",
"zod": "4.5.4"
Expand Down
2 changes: 1 addition & 1 deletion examples/rsc-agent-runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ for stateless consumers because the driver lives behind its own subpath. It is
suitable local single-workspace storage, not concurrent/distributed production
storage. The RSC-facing packages are exact pins because their framework-facing
surface is not treated as stable here: React `19.2.8`, `react-dom` `19.2.8`,
`react-server-dom-rspack` `0.1.0`, Rsbuild `2.2.1`, and `rsbuild-plugin-rsc`
`react-server-dom-rspack` `0.1.0`, Rsbuild `2.2.3`, and `rsbuild-plugin-rsc`
`0.1.1`.

Existing Agent Bundle skills, static MCPs, evaluations, and normal hooks neither require nor activate this runtime. Nothing under `packages/agent-bundle` imports the example or React/RSC runtime packages.
Expand Down
4 changes: 2 additions & 2 deletions examples/rsc-agent-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"zod": "4.5.4"
},
"devDependencies": {
"@rsbuild/core": "2.2.1",
"@rsbuild/core": "2.2.3",
"@rsbuild/plugin-react": "2.1.0",
"@rstest/core": "0.11.10",
"@rstest/core": "0.11.12",
"@types/express": "5.0.6",
"@types/react": "19.2.18",
"@types/react-dom": "19.2.5",
Expand Down
2 changes: 1 addition & 1 deletion examples/worktree-proximity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"devDependencies": {
"@agent-bundle/runtime": "workspace:*",
"@rstest/core": "0.11.10",
"@rstest/core": "0.11.12",
"@types/react": "19.2.18",
"agent-bundle": "workspace:*",
"react": "19.2.8",
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@
"@effect/tsgo": "0.39.0",
"@modelcontextprotocol/conformance": "0.1.16",
"@modelcontextprotocol/server": "2.0.0",
"@rsbuild/core": "2.2.1",
"@rsbuild/core": "2.2.3",
"@rsbuild/plugin-react": "2.1.0",
"@rslib/core": "0.23.2",
"@rslib/core": "1.0.0",
"@rslint/core": "0.8.2",
"@rstest/adapter-rslib": "0.11.10",
"@rstest/core": "0.11.10",
"@rstest/playwright": "0.11.10",
"@rstest/adapter-rslib": "0.11.12",
"@rstest/core": "0.11.12",
"@rstest/playwright": "0.11.12",
"@types/node": "26.4.0",
"agent-bundle": "workspace:*",
"commander": "15.0.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/agent-bundle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@
"@modelcontextprotocol/client": "2.0.0",
"@modelcontextprotocol/node": "2.0.0",
"@modelcontextprotocol/server": "2.0.0",
"@rsbuild/core": "2.2.1",
"@rsbuild/core": "2.2.3",
"@rsbuild/plugin-react": "2.1.0",
"@rslib/core": "0.23.2",
"@rslib/core": "1.0.0",
"@rslint/core": "0.8.2",
"@rstackjs/load-config": "0.1.2",
"acorn": "8.18.0",
Expand Down
11 changes: 11 additions & 0 deletions packages/agent-bundle/rslib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ export default defineConfig({
// extractor never reaches it.
config.ignoreWarnings = [...(config.ignoreWarnings ?? []), /Can't resolve 'source-map-support'/u];
config.node = { ...(typeof config.node === 'object' ? config.node : {}), __dirname: false, __filename: false };
// `externalsType` stays Rslib 1.x's ESM default, `modern-module`, on
// purpose. The only externals this bundle loads through CommonJS
// `require()` are the Node builtins the bundled TypeScript parser
// reads (`fs`, `path`, `os`, `crypto`, `inspector`, `perf_hooks`), and
// Rslib 0.x already emitted those through a `createRequire()` shim
// chunk; `modern-module` reproduces that chunk byte for byte, while
// pinning `module-import` would turn them into hoisted
// `import * as` namespaces — a change, not a preservation. The shim
// chunk is reachable only from the parser chunk, never from the
// runtime entries the compiler re-bundles into consumer artifacts, so
// the artifact bundler never has to see through a `createRequire()`.
},
},
source: {
Expand Down
17 changes: 11 additions & 6 deletions packages/agent-bundle/src/build/entries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { existsSync } from 'node:fs';
import { readFile, stat } from 'node:fs/promises';
import { basename, dirname, extname, relative, resolve } from 'node:path';
import { basename, dirname, extname, join, relative, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

import type { NoticeDeliveryAdvertisement } from '../adapters/notice-delivery.ts';
Expand Down Expand Up @@ -49,13 +49,18 @@ import type { CompiledMcpApp } from './mcp-apps.ts';
import type { ArtifactOutputKind } from './provenance.ts';
import type { RslibEntry, RslibSurfacePlan } from './rslib.ts';

/**
* Spelled as paths, not `new URL(…, import.meta.url)`: the package's own
* Rslib build would otherwise read the template as a directory context and
* replace it with a lookup that throws at run time.
*/
const eventRuntimeModulePath = (module: 'ipc' | 'project'): string => {
for (const candidate of [
new URL(`./event-${module}.js`, import.meta.url),
new URL(`../../dist/event-${module}.js`, import.meta.url),
new URL(`../events/${module}.ts`, import.meta.url),
const here = dirname(fileURLToPath(import.meta.url));
for (const path of [
join(here, `event-${module}.js`),
join(here, '..', '..', 'dist', `event-${module}.js`),
join(here, '..', 'events', `${module}.ts`),
]) {
const path = fileURLToPath(candidate);
if (existsSync(path)) return path;
}
throw new Error(`Unable to locate the compiler-owned event ${module} runtime module.`);
Expand Down
23 changes: 7 additions & 16 deletions packages/agent-bundle/src/build/entry-shell.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { existsSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';

import { eventIpcRuntimeSpecifier, eventProjectRuntimeSpecifier } from '../adapters/hook-contract.ts';
Expand Down Expand Up @@ -36,14 +37,13 @@ const noticeInboxRuntimeSpecifier = '@agent-bundle/runtime/notices/inbox-route';
* the emitted artifact (artifacts must stay self-contained). From the bundled
* package this module's URL is `dist/<bundle>.js` with `<name>.js` as a
* sibling; from checked-out sources it is `src/build/entry-shell.ts` with
* `../<name>.ts`.
* `../<name>.ts`. Spelled as paths, not `new URL(…, import.meta.url)`: the
* package's own Rslib build would otherwise read the template as a directory
* context and replace it with a lookup that throws at run time.
*/
const runtimeModulePath = (name: string): string => {
for (const candidate of [
new URL(`./${name}.js`, import.meta.url),
new URL(`../${name}.ts`, import.meta.url),
]) {
const path = fileURLToPath(candidate);
const here = dirname(fileURLToPath(import.meta.url));
for (const path of [join(here, `${name}.js`), join(here, '..', `${name}.ts`)]) {
if (existsSync(path)) return path;
}
throw new Error(`Unable to locate the agent-bundle/${name} runtime module for generated entries.`);
Expand Down Expand Up @@ -158,16 +158,7 @@ export const cliEntryRuntimeSpecifier = 'agent-bundle/cli-entry';
* aliased into generated CLI executables exactly like the mcp-entry
* lifecycle so emitted bins stay self-contained.
*/
export const cliEntryRuntimePath = (): string => {
for (const candidate of [
new URL('./cli-entry.js', import.meta.url),
new URL('../cli-entry.ts', import.meta.url),
]) {
const path = fileURLToPath(candidate);
if (existsSync(path)) return path;
}
throw new Error('Unable to locate the agent-bundle/cli-entry runtime module for generated CLI executables.');
};
export const cliEntryRuntimePath = (): string => runtimeModulePath('cli-entry');

export const installEntryRuntimeSpecifier = 'agent-bundle/install-entry';

Expand Down
7 changes: 4 additions & 3 deletions packages/agent-bundle/src/build/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ interface VirtualModulesEngine {
* surface is the cost of never touching the artifact tree with build-time
* scratch files. This narrow feature check turns an upstream rename or
* removal into an actionable diagnostic instead of an opaque resolution
* failure deep inside a build. Rsbuild and Rslib carry independent Rspack
* copies (the dual-engine reality documented on `AgentBundleToolsConfig`),
* so each build path checks its own `rspack` and names its own package.
* failure deep inside a build. Rsbuild and Rslib resolve their Rspack
* independently (one engine today, held by a packed test; see
* `AgentBundleToolsConfig`), so each build path checks the `rspack` it
* actually executes under and names its own package.
*/
export const virtualModulesPluginConstructor = <Engine extends VirtualModulesEngine>(
rspack: Engine,
Expand Down
Loading
Loading