Skip to content

feat(build): agent-bundle owns the package build — bin/lib, entry conventions, stdio entry shell, tools hatch, mcp run (RFC #50 Phase 1) - #52

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
feat/framework-owned-build
Aug 31, 2026
Merged

feat(build): agent-bundle owns the package build — bin/lib, entry conventions, stdio entry shell, tools hatch, mcp run (RFC #50 Phase 1)#52
ScriptedAlchemy merged 4 commits into
mainfrom
feat/framework-owned-build

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Implements RFC #50 Phase 1: agent-bundle owns the package build.

Summary

One agent-bundle.config.ts now produces the npm package build alongside host artifacts — the second bundler config, hand-maintained build tsconfig, and hand-written bin shim that every published-package consumer previously carried are gone.

  • bin / lib config, lowered onto the internal Rslib synthesis (packages/agent-bundle/src/build/package-build.ts): bin entries become self-executing dist/bin/<name>.js bundles (shebang, executable bit, generated main(argv) process envelope when the module exports one), lib becomes a single-entry ESM library with bundled declarations. Outputs are staged and published atomically with byte/SHA-256/source-input provenance on the build result, exactly like artifact files. Declaration generation synthesizes a tsconfig that extends the project's own, pins rootDir, and includes only the entry's subtree.
  • Framework-owned stdio MCP entry shell (packages/agent-bundle/src/mcp-entry.ts, public as agent-bundle/mcp-entry, modeled on movie-library's src/stdio-lifecycle.ts): console-to-stderr guard installed before the consumer module evaluates (raw stdout restored for protocol frames), SIGINT 130 / SIGTERM 143, stdin-EOF exit 0 so clients can respawn, bounded shutdown race against wedged transports, heartbeat/activity logging. agent-bundle build wraps every factory-exporting MCP server entry in this lifecycle; self-connecting entries keep their behavior byte for byte.
  • Entry conventions with config-wins fallback: src/cli.ts → package bin named after plugin.name, src/index.ts → library with declarations, src/mcp/<server-id>.ts → stdio entry for a declared server naming no entry/command/url. bin: false / lib: false opt out; explicit config always suppresses the convention. Documented in docs/entry-conventions.md.
  • tools.rsbuild / tools.rspack escape hatch: the single blessed bundler hatch, merged last into every synthesized config (scripts, MCP entries, hooks, MCP Apps, package build) and still bounded by the artifact invariant assertions.
  • agent-bundle mcp run --server <name> --target <target> (packages/agent-bundle/src/services/mcp-run.ts): runs one built stdio server in the foreground, resolving its content-hashed generated entry from the target manifest after artifact validation; forwards SIGINT/SIGTERM and the child's exit code; refuses non-stdio servers.
  • audiobook-curator migrates in-PR as proof: loses rslib.config.ts, tsconfig.build.json, bin/audiobook-curator.js, and src/cli-entry.ts; package.json bin now points at the framework-built dist/bin/audiobook-curator.js. CLI behavior is covered by the existing parity tests, all green.
  • Changeset: agent-bundle minor.

Packed-suite extension

packed-consumer.test.ts now builds a conventional bin/lib/MCP project against the installed tarball alone (no repository source tree): asserts the shebang'd executable bin, importable lib with declarations, a self-contained generated stdio entry (no agent-bundle import in the emitted artifact), clean exit 0 on stdin EOF, and mcp list through the packaged CLI. One test-only fix landed during shepherding: execFile never closes the child's stdin pipe, so the EOF assertion now delivers the EOF explicitly (child.stdin.end()) instead of hanging a real server until timeout-kill.

Test plan

  • pnpm build — green
  • pnpm typecheck (root + workbench) — green
  • pnpm lint (rslint, 0 errors 0 warnings) — green
  • pnpm test:unit — green
  • pnpm test:packed — green (19/19, including the new tarball-only framework-build scenario)
  • pnpm examples:check (all examples, including migrated audiobook-curator parity suites) — green
  • publint — All good
  • Targeted integration run over the agent-bundle suites — 152/152

…amework stdio entry shell, entry conventions, tools hatch, mcp run (RFC #50 Phase 1)

One agent-bundle.config.ts now produces the npm package build alongside host
artifacts: bin/lib (or the src/cli.ts / src/index.ts / src/mcp/<id>.ts
conventions) lower onto the internal Rslib synthesis, factory-exporting MCP
entries are wrapped in the framework stdio lifecycle shell (public as
agent-bundle/mcp-entry), tools.rsbuild/tools.rspack is the single bounded
bundler escape hatch, and `agent-bundle mcp run` launches a built stdio server
from the target manifest. audiobook-curator migrates in-PR as proof: drops
rslib.config.ts, tsconfig.build.json, and the bin shim with byte-equivalent
CLI behavior.
…shell entry

execFile never closes the child's stdin pipe, so a real server's transport
held the generated entry alive until the 30s timeout killed it. End the
child's stdin so the EOF path under test actually executes.
@changeset-bot

changeset-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4b8f35d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T01:07:32.984504Z 273269d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@52
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/rsc-runtime@52

commit: 4b8f35d

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 273269d167

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

await writeFile(path, `${JSON.stringify({
...(existsSync(projectTsconfig) ? { extends: projectTsconfig } : {}),
compilerOptions: { rootDir: options.sourceDir },
include: [`${options.sourceDir}/**/*.ts`, `${options.sourceDir}/**/*.tsx`],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude colocated tests from the declaration program

When a package keeps tests beneath the library source directory (for example, src/index.test.ts), these broad includes add them to the declaration program, so test-only imports or type errors can fail agent-bundle build and successful builds can publish test declarations into dist. Restrict the synthesized project to the library entry and its dependency graph, or explicitly exclude recognized test files, to uphold the documented isolation from tests.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4b8f35d: the synthesized declaration tsconfig now excludes **/*.test.*, **/*.spec.*, and **/__tests__/** under the lib source directory, with a regression test proving a colocated src/answer.test.ts type error neither fails the build nor publishes answer.test.d.ts.

Comment thread packages/agent-bundle/src/api.ts Outdated
const workspaceRoot = resolve(options.root);
return temporaryArtifact({ ...options, registry }, async (artifact) => runMcpForeground({
artifact,
pluginDataRoot: join(workspaceRoot, '.agent-bundle', 'mcp-run', options.target, options.server),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Contain MCP state paths derived from server names

For an accepted MCP server name containing path components such as ../shared, this direct join traverses out of the intended <target>/<server> state directory; different targets or servers can consequently share or overwrite state, and sufficiently many .. components escape .agent-bundle entirely. Since source validation only requires server names to be nonempty, encode/hash this component or assert the resulting path remains within the MCP-run root before creating it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4b8f35d: server names that are not a plain single path segment now map to a content-addressed server-<sha256[0:16]> state directory (mcpServerStateDirectory), so ../shared-style names can no longer traverse out of .agent-bundle/mcp-run. Unit-tested for hostile and safe names.

…try shell, entry conventions, tools hatch, mcp run (RFC #50 Phase 1)

One agent-bundle.config.ts now produces the npm package build alongside host
artifacts: `bin` entries become self-executing dist/bin/<name>.js bundles
(shebang, exec bit, generated main(argv) envelope) and `lib` becomes a
single-entry ESM build with declarations, both lowered through the existing
buildWithRslib synthesis with its invariant assertions intact. Factory-
exporting MCP server entries are wrapped in the new framework stdio lifecycle
shell (agent-bundle/mcp-entry: console-to-stderr guard with raw stdout
restore, SIGINT 130 / SIGTERM 143, stdin-EOF exit 0, bounded shutdown,
heartbeat). src/cli.ts, src/index.ts, and src/mcp/<server-id>.ts conventions
fill silent config with 'conventional' provenance; config always wins.
tools.rsbuild/tools.rspack is the single bundler escape hatch, merged
last-but-bounded into every synthesized config. `agent-bundle mcp run`
resolves the content-hashed generated entry from the target manifest and runs
it in the foreground.

audiobook-curator migrates in-tree as the reference consumer: rslib.config.ts,
tsconfig.build.json, bin/audiobook-curator.js, src/cli-entry.ts, and the dual
build script chain are deleted; package.json bin/exports now point at the
framework-built dist.

References #50 (Phase 1).
…gram, contain MCP state paths

The synthesized declaration tsconfig now excludes *.test.*, *.spec.*, and
__tests__ under the lib source directory, so colocated tests can neither fail
`agent-bundle build` nor publish test declarations into dist/. MCP server
names that are not a plain single path segment (e.g. `../shared`) map to a
content-addressed state directory instead of traversing out of
.agent-bundle/mcp-run.
@ScriptedAlchemy
ScriptedAlchemy merged commit da5df1d into main Aug 31, 2026
9 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/framework-owned-build branch August 31, 2026 02:08
ScriptedAlchemy added a commit that referenced this pull request Aug 31, 2026
…cp-entry lifecycle in the self-built stdio entry (RFC #50 Phase 2) (#57)

The demo's stdio MCP entry replaces its naive run().catch bootstrap (no
console guard, no signals, no stdin-EOF, no bounded shutdown) with the
framework's public lifecycle API: redirectConsoleToStderr installs the
stdout guard before the server module and v1.30 SDK evaluate (both
deferred via dynamic import, mirroring the generated shell), then
runStdioServer owns SIGINT->130, SIGTERM->143, stdin-EOF->0, bounded
shutdown, and heartbeat attribution over the demo's own SDK transport.
The entry stays compiled by the demo's rsbuild at the stable
dist/runtime/mcp/stdio.js path pinned by packaging and tests; the
structural lifecycle types accept the v1.x SDK without migration and
the import bundles into the entry (no lockfile change).

The transport suite gains a lifecycle test (handshake-then-act exit
codes plus heartbeat), the README ownership-boundary paragraph notes
the entry consumes the framework lifecycle while remaining self-built,
and the generated topology doc is regenerated (one line stale on main
since #52).
ScriptedAlchemy added a commit that referenced this pull request Aug 31, 2026
…user-facing scripts, align check chains (#68)

* chore(examples): canonicalize defineConfig imports, drop --json from user-facing scripts, align check chains

The examples split on three cosmetic conventions the audit called out.
Canonicalizes the defineConfig import to 'agent-bundle/config' — the root
README quick start already teaches that path — across the three examples
still importing from 'agent-bundle'. Drops --json from example build and
validate package scripts so pnpm build/validate speak the post-#52 human
writers instead of dumping machine JSON (CI examples:check consumes exit
codes only). Reorders the rsc example's check to the canonical
validate && build && typecheck && test chain. Also renames the deleted
src/cli-entry.ts self-executing pattern to src/cli.ts with the
exported-main envelope teaching in the rsc-runtime package README and its
test fixture strings.

* chore(examples/audiobook-curator): canonicalize the new real defineConfig import to agent-bundle/config
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