Skip to content

feat(install): add the agent-bundle/install package-bound lifecycle entry (#724) - #730

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
feat/724-package-bound-install
Sep 7, 2026
Merged

feat(install): add the agent-bundle/install package-bound lifecycle entry (#724)#730
ScriptedAlchemy merged 4 commits into
mainfrom
feat/724-package-bound-install

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Fixes #724.

What

agent-bundle/install — one public entry so a published plugin ships a package-bound installer bin without bundling agent-bundle-src/.../src/install/*, probing for its artifact root, or parsing argv itself.

  • runInstallCli(argv, { from, name }): the agent-bundle CLI's own install <host> / uninstall <host> / doctor commands with the bundle root pinned to from. Same flags, receipts, replacement rules, --plan, data policy, --json, exit codes (0 / 1 + one diagnostics line on stderr / 2 usage). No --from is exposed once pinned.
  • Also exports installBundle, uninstallBundle, runDoctor, formatInstallResult, formatUninstallResult, new formatDoctorReport, and their option/result types.
  • The three commands are declared once in src/install/commands.ts and src/cli.ts is rewired onto it in the same change (no duplicate parser); humanDoctor moved to install/format.ts as formatDoctorReport.
  • Entry lives in the runtime lib (rslib.config.ts), i.e. re-bundle-safe placement like web-host: the consumer's package build inlines it into the bin (AB7014 confirmed that inlining during the fixture's first run).

The whole consumer installer becomes:

import { fileURLToPath } from 'node:url';
import { runInstallCli } from 'agent-bundle/install';

export const main = (argv: readonly string[]) =>
  runInstallCli(argv, { from: fileURLToPath(new URL('..', import.meta.url)), name: 'cargo-hauler-install' });

Rung chosen: the public agent-bundle CLI cannot satisfy an installed consumer (it would need agent-bundle as a runtime dependency, which AB7014 rejects and which drags the compiler into end-user installs), and the generated install.mjs is Cursor-only. install --plan is not added: doctor --host <host> is the real read-only preview (current / stale / version-mismatch / foreign / not-installed), so the consumer's approximate plan is deleted rather than reproduced.

Proof

  • tests/install-cli.test.ts (unit): argv → installBundle / uninstallBundle / runDoctor mapping with the pinned root, --from rejected, help/usage/failure exit codes.
  • tests/packed-install-bin.test.ts (packed pool): a consumer with bin: { 'demo-install': './src/install-bin.ts' } importing agent-bundle/install, prepack, npm pack dist, installed into a clean consumer with no agent-bundle on disk, source project deleted; then the bin runs install cursor (installed, receipt), again (already-installed), after content drift (replaced), doctor --host cursor (current), uninstall --plan (planned, exact paths, nothing removed), uninstall (uninstalled), and reports not-installed afterwards; --from exits 2; the bin carries no agent-bundle import.

Docs

website/docs/{en,zh}/guide/distribution/installation.mdx (“A package-bound installer bin”), website/docs/{en,zh}/reference/api.mdx row, TypeDoc entry point.

Exit codes follow the agent-bundle CLI: doctor writes its report (human or --json) to stdout and exits 1 when it carries an error finding; a failed install/uninstall or any thrown error writes one diagnostics JSON line to stderr and exits 1; usage errors exit 2. tests/install-cli.test.ts asserts the stream for both.

Local gate (branch contains current origin/main b5cf757; final tree 78b966a)

pnpm build                       ok
pnpm typecheck                   ok
pnpm lint                        ok (1487 files)
pnpm test:unit                   301 files, 4441 passed, 6 skipped, 0 failed
integration (rstest.integration.config.ts): cli.test, public-api.test, publint-gate.test,
  host-install-proof.test, dev-host-install.test          58 passed, 0 failed
pnpm test:packed (whole packed pool, incl. packed-install-bin)   15 files, 41 passed, 1 skipped, 0 failed
  packed-install-bin re-run on the final tree             2 passed
pnpm docs:site:build             ok, 0 broken links, language parity ok

Deslop: Claude Fable 5.1, 3 edits (collapsed the --from option helper; dropped an unused re-exported type; removed a now-unused errorMessage import in cli.ts).

Self-review

Reviewer: GPT-5.6 Sol Max (two passes; the tracedecay-bound change-risk-reviewer was unavailable, so a general reviewer read the diff).

Pass 1 — six findings, all fixed:

  1. Exit-code contract claimed every exit 1 writes a diagnostics line to stderr; doctor writes its report to stdout. → JSDoc, en/zh guides, changeset corrected; stream test added. (Same as the Codex P2 thread, resolved.)
  2. Public result types referenced unexported nested types. → export type * from install.ts/uninstall.ts/doctor.ts.
  3. cli.ts lifecycle loader imported all three implementations on any lifecycle command. → per-call lazy import, matching the previous behavior.
  4. diagnosticsFor duplicated between cli.ts and the entry. → moved to core/diagnostics.ts, one copy.
  5. Guide overstated “probes nothing” / doctor as an install preview. → narrowed to “never searches for another artifact root” and “read-only status check”.
  6. Changeset carried implementation detail. → trimmed to user-facing behavior.

Pass 2 — one finding, fixed: pinned bins still evaluated process.cwd() while registering, so a deleted cwd broke --help. → process.cwd() is read only when --from is actually registered.

@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 78b966a

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 Patch

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 Sep 7, 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-09-07T03:19:08.542697Z ab28ff1 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.

@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: ab28ff11d5

ℹ️ 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".

Comment thread packages/agent-bundle/src/install/index.ts Outdated
@ScriptedAlchemy
ScriptedAlchemy merged commit 596d337 into main Sep 7, 2026
1 of 3 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/724-package-bound-install branch September 7, 2026 03:54
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.

[P2] Provide a supported package-bound install entry so consumers do not bundle private installer source

1 participant