Skip to content

feat: create-agent-bundle scaffolding package (RFC #50 Phase 3) - #62

Merged
ScriptedAlchemy merged 2 commits into
mainfrom
feat/create-agent-bundle
Aug 31, 2026
Merged

feat: create-agent-bundle scaffolding package (RFC #50 Phase 3)#62
ScriptedAlchemy merged 2 commits into
mainfrom
feat/create-agent-bundle

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

RFC #50 Phase 3, item 1: the create-agent-bundle scaffolder — npm create agent-bundle (once npm releases exist) / npx create-agent-bundle, shipped through the same pkg.pr.new preview channel as the other workspace packages.

UX (modeled on the rstack create-* family, rstackjs/create-rstack)

  • Prompt-driven (project name/path, template, host targets) via @clack/prompts — the same toolkit create-rstack uses (and the repo already carries transitively via @changesets/cli). Bundled by Rslib as a devDependency, so the published package has zero runtime dependencies, matching create-rstack's tarball shape. Flag parsing is node:util parseArgs — no CLI framework.
  • Full non-interactive flags: --template, --targets, --package-manager, --no-install, --framework-version, -d/--dir, -h/--help. Adopted from create-rstack: the positional-dir → --dir fallback, foo/bar / @scope/name project-name semantics (formatProjectName), package-manager detection from npm_config_user_agent, prompt cancellation exiting 0, and the "directory + template on the command line means scripted — ask nothing" rule. Deliberately not adopted: --override (a non-empty target directory is a hard error) and git init.
  • Framework pinning: templates carry agent-bundle: "workspace:*" as the placeholder (the same placeholder convention create-rstack's updatePackageJson rewrites). The scaffolder pins it to --framework-version verbatim, or derives the pkg.pr.new preview URL from its own -preview-<sha> version at run time — both tarballs of one commit share the sha, so scaffolder and framework always pair. A non-preview build refuses to guess, because the agent-bundle npm name belongs to an unrelated package (see below).

Templates (real checked-in dirs under templates/, copied file-by-file)

Template Mirrors Contents
minimal skills-starter one Skill (skills/getting-started), skills-only config
mcp-server mcp-app (post-Phase-2) conventional src/mcp/status.ts factory entry (framework lifecycle shell) + one artifact script + shared domain module
cli-tool audiobook-curator (post-Phase-1, without the domain) src/cli.ts bin convention + src/index.ts lib with dts; the CLI is also declared as a script — one bundle, two destinations

Every template: agent-bundle.config.ts, manifest, standalone tsconfig, one passing test, README with preview-channel install notes (per docs/preview-packages.md), .gitignore, and a check script (validate + build + typecheck + test). Scaffolded output validates with zero diagnostics including the AB473x nudges (asserted in the e2e). Template manifests are checked in as package_json and .gitignore as gitignore (the create-rstack rename-table trick) so the published tarball stays publint-clean and npm cannot strip files.

Tests

  • Unit (parallel pool): flag/prompt resolution, project-name semantics, framework-spec derivation, and template emission (exact inventories, placeholder/workspace:* elimination, targets rewrite).
  • Packed e2e (test:packed pool, not the integration pool — it runs npm pack/npm install): reuses the packed-consumer mechanism (copy package → rslib build --dist-pathnpm packnpm install --ignore-scripts <tarball>). It installs the scaffolder tarball, scaffolds each template with --framework-version file:<agent-bundle tarball> (no pkg.pr.new dependency), runs each project's own check end to end, and asserts: clean validate, lifecycle-shell wrap + mcp list/invoke for mcp-server, and the framework-built executable bin + lib dts + artifact script for cli-tool. The minimal leg covers the scaffolder-driven auto-install path.

npm name finding

npm view create-agent-bundle404, the name is unclaimed. agent-bundle remains taken by an unrelated package (0.1.2, "CLI tool and framework for defining, developing, and shipping AI agent skills"). The scaffolder ships to the preview channel regardless; the real-name decision stays deferred repo-wide.

Wiring

Root build, lint:package (publint), typecheck, preview:publish, and test:packed cover the new package; template test files are excluded from the workspace pools (they run inside scaffolded projects). Changeset: create-agent-bundle minor — changesets versions the unreleased package from its checked-in 0.0.0 to 0.1.0 on first release.

Gate results (local)

  • pnpm build ✅ · pnpm typecheck ✅ · pnpm lint ✅ (0 errors, 0 warnings, templates included) · pnpm lint:package ✅ (publint "All good!" for both packages)
  • pnpm test:unit ✅ 1757 passed / 0 failed
  • Scaffolder packed e2e ✅ 3/3 through the packed pool config
  • Examples untouched (git status examples/ clean); examples-contract.test.ts spot run ✅ 3/3

Refs #50 (Phase 3).

`npm create agent-bundle` / `npx create-agent-bundle` scaffolds a
ready-to-run plugin project from one of three checked-in templates —
minimal (skills-only), mcp-server (conventional src/mcp/<id>.ts factory
entry plus an artifact script), and cli-tool (src/cli.ts bin convention
plus a src/index.ts library export). Prompt-driven (name, template, host
targets) with full non-interactive flags (--template, --targets,
--package-manager, --no-install, --framework-version); scaffolded
projects pin agent-bundle to the pkg.pr.new preview of the same commit
the scaffolder shipped from, and validate with zero diagnostics
including the AB473x convention nudges. The packed e2e drives the
installed scaffolder tarball and each scaffolded project's own check
against the real agent-bundle tarball.
@changeset-bot

changeset-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 546a23e

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

This PR includes changesets to release 1 package
Name Type
create-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

@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026

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

commit: 546a23e

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

ℹ️ 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 on lines +156 to +159
const cleaned = bare
.replace(/[^a-zA-Z0-9._-]+/gu, '-')
.replace(/^[^a-zA-Z0-9]+/u, '')
.replace(/[^a-zA-Z0-9]+$/u, '');

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 Normalize names for selectable Cursor targets

When the project name contains uppercase letters or underscores and the user selects cursor or the unified plugin target, this sanitizer preserves those characters, while the Cursor adapter accepts only lowercase letters, digits, dots, and hyphens (packages/agent-bundle/src/adapters/cursor.ts:67-71). The newly scaffolded project's validate/check therefore fails immediately; normalize to a Cursor-compatible name or reject and re-prompt for these target selections.

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 546a23e: the derived plugin name is now sanitized to the strictest host contract — Cursor's lowercase kebab-case (/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/, 64-char cap), which the unified plugin target enforces too and which remains a valid safe package-output name. Every target selection now validates regardless of the input casing; the unit test locks the mirrored pattern (My_Appmy-app, @scope/My.Toolmy.tool, plus non-ASCII and over-length inputs).

@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-31T05:42:29.797854Z dc70d67 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.

…ase kebab-case contract

The derived plugin name previously kept uppercase letters and mapped
underscores through, which the Cursor adapter (and the unified plugin
target) reject — a cursor/plugin target selection would scaffold a
project whose own validate fails. The sanitizer now lowers to the
strictest host contract (lowercase letters, digits, dots, hyphens,
64-char cap), which is also a valid safe package-output name, so every
selectable target validates. Review finding on #62.
@ScriptedAlchemy
ScriptedAlchemy merged commit 13210fd into main Aug 31, 2026
9 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/create-agent-bundle branch August 31, 2026 06:16
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