feat/RR-1024-cli-rocketride-init#1034
Conversation
…indsurf / Copilot / CLAUDE.md / AGENTS.md)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`import * as process from 'process'` compiles to __importStar(), which copies only own-enumerable properties and drops EventEmitter prototype methods like process.on. On Node >=~20 (seen on Node 26) this crashed the CLI binary at startup in setupSignalHandlers (process.on is not a function), breaking every command. process is a Node global, so the import is removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nts-core-and-init
📝 WalkthroughWalkthroughAdds a headless Changesrocketride init CLI Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
No description provided. |
The custom ./builder discovers per-package scripts/tasks.js; agents-core had none, so it was never built (or tested) in CI. client-typescript:compile-cli runs 'tsc -p tsconfig.cli.json' and imports @rocketride/agents-core, which needs its built dist/index.d.ts — absent in CI, causing TS2307. - Add packages/agents-core/scripts/tasks.js with agents-core:build / :test / :clean (auto-discovered by the builder; build/test now run in CI). - Prepend agents-core:build to client-typescript:build steps so the CLI compile resolves agents-core types regardless of parallel module ordering. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/agents-core/package.json`:
- Around line 19-23: The package.json currently mixes Jest major versions:
"`@jest/globals`" and "`@types/jest`" are v30 while "jest" and "ts-jest" are v29;
pick a single major and make all jest-related dependencies consistent (update
either "jest" and "ts-jest" to v30 to match "`@jest/globals`"/"`@types/jest`" or
downgrade "`@jest/globals`" and "`@types/jest`" to v29), adjusting the versions for
the keys "jest", "ts-jest", "`@jest/globals`", and "`@types/jest`" accordingly, then
reinstall/update lockfile and run the test suite to verify tooling/type
compatibility.
In `@packages/agents-core/src/catalog-sync.ts`:
- Around line 76-88: The map creating catalog must guard against null/undefined
service entries: inside the serviceNames.map callback, check if services[name]
(svc) is nullish before accessing properties and build a safe entry with
defaults (e.g., classType: [], description: undefined/'' via firstSentence,
lanes: {}, and only add invoke when present); update the logic around const svc
= services[name] as Record<string, unknown> and the entry creation in the
catalog variable so accessing svc.classType, svc.description or svc.lanes cannot
throw when svc is null.
In `@packages/agents-core/src/installers/base-installer.ts`:
- Around line 53-60: The uninstall flow in base-installer.ts is returning true
even when no markers were found because stripMarkedContent(existing) returns the
original content; change the logic in the uninstall method (the block that uses
stripMarkedContent and fs.unlink/fs.writeFile) to detect when stripped ===
existing and return false (no-op) instead of true; keep the existing behavior of
removing the file when stripped.trim() is empty and writing when different, and
make the same change to the second similar block (the one around lines 83-87) so
both locations return false when there is no content change.
In `@packages/agents-core/test/smoke.test.ts`:
- Around line 5-25: The smoke test currently uses defaultBundle() (from
packages/agents-core) which resolves docs via __dirname in source layout and
misses issues in the emitted ESM/dist artifact; update the test to exercise the
same bundle resolution used in production by invoking the packaged entrypoint
(import/require the built/compiled module that exports defaultBundle or call
AgentManager.installAll against the runtime-resolved artifact bundle) instead of
calling defaultBundle() from src, so the test imports/loads the bundle path the
distributed package would use and then runs mkTempWorkspace(), new
AgentManager(), and installAll(...) to assert the same DOC_FILES and stub paths
exist; reference defaultBundle(), AgentManager.installAll, and mkTempWorkspace()
when making this change.
In `@packages/client-typescript/src/cli/init.ts`:
- Around line 108-126: Refactor scaffoldEnv to be async and use fs/promises:
replace synchronous fs calls (existsSync, readFileSync, writeFileSync) with the
promise-based APIs (fs.promises.access or stat to check existence, readFile,
writeFile) and propagate errors appropriately; update scaffoldEnv signature to
async scaffoldEnv(cwd: string, log: (msg: string) => void): Promise<void> and
ensure it returns after awaiting file operations. Also update the runInit caller
to await scaffoldEnv(...) so the init flow waits for the async I/O to complete.
Keep the same behavior (create .env if missing, append .env to .gitignore if not
present) and preserve log('Created .env') when the file is created.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6203586e-600d-4d41-910c-1d268f019f47
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (45)
docs/superpowers/plans/2026-05-29-p2-rocketride-init.mddocs/superpowers/specs/2026-05-29-rocketride-init-design.mdpackages/agents-core/.gitignorepackages/agents-core/docs/ROCKETRIDE_COMMON_MISTAKES.mdpackages/agents-core/docs/ROCKETRIDE_COMPONENT_REFERENCE.mdpackages/agents-core/docs/ROCKETRIDE_OBSERVABILITY.mdpackages/agents-core/docs/ROCKETRIDE_PIPELINE_RULES.mdpackages/agents-core/docs/ROCKETRIDE_QUICKSTART.mdpackages/agents-core/docs/ROCKETRIDE_README.mdpackages/agents-core/docs/ROCKETRIDE_python_API.mdpackages/agents-core/docs/ROCKETRIDE_typescript_API.mdpackages/agents-core/docs/stubs/AGENTS.mdpackages/agents-core/docs/stubs/CLAUDE.mdpackages/agents-core/docs/stubs/claude-code.mdpackages/agents-core/docs/stubs/copilot-instructions.mdpackages/agents-core/docs/stubs/cursor.mdcpackages/agents-core/docs/stubs/windsurf.mdpackages/agents-core/jest.config.jspackages/agents-core/package.jsonpackages/agents-core/scripts/sync-bundle.tspackages/agents-core/src/agent-manager.tspackages/agents-core/src/catalog-sync.tspackages/agents-core/src/docs-sync.tspackages/agents-core/src/index.tspackages/agents-core/src/installers/agents-md-installer.tspackages/agents-core/src/installers/base-installer.tspackages/agents-core/src/installers/claude-code-installer.tspackages/agents-core/src/installers/claude-md-installer.tspackages/agents-core/src/installers/copilot-installer.tspackages/agents-core/src/installers/cursor-installer.tspackages/agents-core/src/installers/windsurf-installer.tspackages/agents-core/src/types.tspackages/agents-core/test/agent-manager.test.tspackages/agents-core/test/base-installer.test.tspackages/agents-core/test/catalog-sync.test.tspackages/agents-core/test/docs-sync.test.tspackages/agents-core/test/helpers.tspackages/agents-core/test/installers.test.tspackages/agents-core/test/smoke.test.tspackages/agents-core/tsconfig.jsonpackages/client-typescript/package.jsonpackages/client-typescript/src/cli/init.tspackages/client-typescript/src/cli/rocketride.tspackages/client-typescript/tests/init.test.tspnpm-workspace.yaml
| const stripped = this.stripMarkedContent(existing); | ||
| if (stripped.trim() === '') { | ||
| await fs.unlink(target); | ||
| } else { | ||
| await fs.writeFile(target, stripped, 'utf8'); | ||
| } | ||
| return true; | ||
| } |
There was a problem hiding this comment.
Return false when uninstall makes no content change.
If markers are missing/invalid, stripMarkedContent() returns the original content, but uninstall() still returns true. That reports a successful uninstall when nothing was removed.
Targeted fix
async uninstall(workspaceRoot: string): Promise<boolean> {
@@
const stripped = this.stripMarkedContent(existing);
+ if (stripped === existing) {
+ return false;
+ }
if (stripped.trim() === '') {
await fs.unlink(target);
} else {
await fs.writeFile(target, stripped, 'utf8');
}
return true;
}Also applies to: 83-87
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/agents-core/src/installers/base-installer.ts` around lines 53 - 60,
The uninstall flow in base-installer.ts is returning true even when no markers
were found because stripMarkedContent(existing) returns the original content;
change the logic in the uninstall method (the block that uses stripMarkedContent
and fs.unlink/fs.writeFile) to detect when stripped === existing and return
false (no-op) instead of true; keep the existing behavior of removing the file
when stripped.trim() is empty and writing when different, and make the same
change to the second similar block (the one around lines 83-87) so both
locations return false when there is no content change.
| describe('smoke: installAll using bundled docs', () => { | ||
| it('produces the canonical .rocketride/ + agent stub layout', async () => { | ||
| const ws = await mkTempWorkspace(); | ||
| const mgr = new AgentManager(); | ||
| await mgr.installAll(defaultBundle(), ws, () => undefined); | ||
|
|
||
| for (const f of DOC_FILES) { | ||
| expect(await exists(path.join(ws, '.rocketride/docs', f))).toBe(true); | ||
| } | ||
| expect(await exists(path.join(ws, '.gitignore'))).toBe(true); | ||
| for (const stubTarget of [ | ||
| '.claude/rules/rocketride.md', | ||
| '.cursor/rules/rocketride.mdc', | ||
| '.windsurf/rules/rocketride.md', | ||
| '.github/copilot-instructions.md', | ||
| 'CLAUDE.md', | ||
| 'AGENTS.md', | ||
| ]) { | ||
| expect(await exists(path.join(ws, stubTarget))).toBe(true); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Smoke test won't validate the packaged artifact's bundle path.
This relies on defaultBundle(), which resolves __dirname/../docs. Under ts-jest it runs against the src/ layout as CommonJS, so it passes even if the emitted ESM/dist artifact resolves the docs path incorrectly or trips over an undefined __dirname. This is the downstream blind spot for the defaultBundle() concern raised in packages/agents-core/src/index.ts; resolving the root cause there covers this.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/agents-core/test/smoke.test.ts` around lines 5 - 25, The smoke test
currently uses defaultBundle() (from packages/agents-core) which resolves docs
via __dirname in source layout and misses issues in the emitted ESM/dist
artifact; update the test to exercise the same bundle resolution used in
production by invoking the packaged entrypoint (import/require the
built/compiled module that exports defaultBundle or call AgentManager.installAll
against the runtime-resolved artifact bundle) instead of calling defaultBundle()
from src, so the test imports/loads the bundle path the distributed package
would use and then runs mkTempWorkspace(), new AgentManager(), and
installAll(...) to assert the same DOC_FILES and stub paths exist; reference
defaultBundle(), AgentManager.installAll, and mkTempWorkspace() when making this
change.
- agents-core: pin Jest devDeps to v29 line (package.json) - agents-core: add null-guard in catalog-sync.ts - cli: refactor scaffoldEnv to async (init.ts) - docs: add P1 agents-core extraction plan - chore: add copilot-instructions, devcontainer lock, discord workflow tweak Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/discord-discussions.yml:
- Around line 213-219: The current code strips query params from
DISCORD_WEBHOOK_URL into BASE, losing thread-scoping (e.g. thread_id) for the
POST; preserve query params for the POST but keep a cleaned BASE for
PATCH/DELETE. Keep the existing BASE logic (BASE="${DISCORD_WEBHOOK_URL%%\?*}"
and BASE="${BASE%/}") for constructing PATCH/DELETE URLs like
"$BASE/messages/$DISCORD_MSG_ID" / "$BASE/messages/$NEW_MSG_ID", and separately
construct a POST_URL from the original DISCORD_WEBHOOK_URL (preserving any
existing query string) by appending wait=true with the correct separator (use &
if a query exists, ? otherwise). Use POST_URL for the POST request and
BASE/messages/... for PATCH/DELETE.
In `@docs/superpowers/plans/2026-05-28-p1-agents-core-extraction.md`:
- Around line 25-67: The fenced code blocks in the plan (e.g., the package tree
block in docs/superpowers/plans/2026-05-28-p1-agents-core-extraction.md) are
missing explicit languages and surrounding blank lines causing MD040/MD031 lint
warnings; update every fenced block to use a consistent fence style (triple
backticks) with an explicit language token (use "text" for plain tree/layout
blocks) and ensure there is a blank line before and after each fence so all
occurrences (the package tree and any other ``` blocks) conform to markdownlint
rules.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: c86e6fda-de92-4f9b-b96e-741d6ac93449
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (7)
.devcontainer/devcontainer-lock.json.github/copilot-instructions.md.github/workflows/discord-discussions.ymldocs/superpowers/plans/2026-05-28-p1-agents-core-extraction.mdpackages/agents-core/package.jsonpackages/agents-core/src/catalog-sync.tspackages/client-typescript/src/cli/init.ts
| # Normalize webhook URL so POST and PATCH share one base. The previous | ||
| # awk-split approach desynced if DISCORD_DISCUSSIONS_WEBHOOK_URL had a | ||
| # trailing slash or query string (e.g. ?thread_id=...): PATCH 404'd, | ||
| # the 404 branch deleted the marker as "message gone", then fell through | ||
| # to POST → fresh repost on every discussion update. | ||
| BASE="${DISCORD_WEBHOOK_URL%%\?*}" | ||
| BASE="${BASE%/}" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does Discord's webhook API require preserving query parameters such as thread_idon execute/edit/delete message endpoints, and canthread_idbe combined withwait=true on webhook POST requests?
💡 Result:
Discord's webhook API allows you to combine query parameters, including thread_id and wait=true, on POST requests [1][2][3]. Regarding the requirements for preserving thread_id across different endpoints: 1. Execute Webhook (POST): When sending a message to a specific thread, you must append the thread_id as a query parameter to the webhook URL [1][4][2]. If you want the API response to return the created message object (which includes the message ID), you must also include wait=true as a query parameter [1][5]. These parameters can be combined (e.g., ?thread_id=123&wait=true) [1][2][3]. 2. Edit/Delete Message (PATCH/DELETE): The endpoints for editing (PATCH) or deleting (DELETE) a webhook message typically follow the path pattern /webhooks/{webhook.id}/{webhook.token}/messages/{message.id} [5]. Once you have obtained the message.id (usually by using wait=true on the initial POST request), the thread_id is generally not required to perform subsequent operations on that specific message, as the message ID is unique to the webhook [5]. Therefore, you do not need to pass thread_id to the edit or delete endpoints to target the message itself [5].
Citations:
- 1: https://docs.discord.com/developers/resources/webhook
- 2: https://stackoverflow.com/questions/71561978/discord-thread-webhook
- 3: https://discord.js.org/docs/packages/discord.js/14.18.0/RESTPostAPIWebhookWithTokenQuery:Interface
- 4: https://discord-webhook.com/en/blog/discord-webhook-threads-forums/
- 5: https://hookdeck.com/webhooks/platforms/how-to-get-started-with-discord-webhooks
Preserve webhook query parameters (e.g., thread_id) when constructing the POST URL
Line 218 strips everything after ? from DISCORD_WEBHOOK_URL, so the POST at "$BASE?wait=true" loses thread-scoping params; Discord supports combining thread_id with wait=true on webhook POSTs, and that matters for where the message is created. The subsequent PATCH/DELETE calls operate on messages/{message.id}, so they don’t need thread_id.
♻️ Minimal direction for the fix
- BASE="${DISCORD_WEBHOOK_URL%%\?*}"
- BASE="${BASE%/}"
+ WEBHOOK_URL="${DISCORD_WEBHOOK_URL%/}"
+ BASE="${WEBHOOK_URL%%\?*}"
+ QUERY="${WEBHOOK_URL#"$BASE"}"
+
+ if [ -n "$QUERY" ]; then
+ POST_URL="$BASE${QUERY}&wait=true"
+ else
+ POST_URL="$BASE?wait=true"
+ fiThen use "$POST_URL" for the POST, and leave the PATCH/DELETE URLs as "$BASE/messages/$DISCORD_MSG_ID" / "$BASE/messages/$NEW_MSG_ID" (no query-string appending).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/discord-discussions.yml around lines 213 - 219, The
current code strips query params from DISCORD_WEBHOOK_URL into BASE, losing
thread-scoping (e.g. thread_id) for the POST; preserve query params for the POST
but keep a cleaned BASE for PATCH/DELETE. Keep the existing BASE logic
(BASE="${DISCORD_WEBHOOK_URL%%\?*}" and BASE="${BASE%/}") for constructing
PATCH/DELETE URLs like "$BASE/messages/$DISCORD_MSG_ID" /
"$BASE/messages/$NEW_MSG_ID", and separately construct a POST_URL from the
original DISCORD_WEBHOOK_URL (preserving any existing query string) by appending
wait=true with the correct separator (use & if a query exists, ? otherwise). Use
POST_URL for the POST request and BASE/messages/... for PATCH/DELETE.
| ``` | ||
| packages/agents-core/ | ||
| ├── package.json | ||
| ├── tsconfig.json | ||
| ├── jest.config.js | ||
| ├── src/ | ||
| │ ├── index.ts Public API surface; re-exports. | ||
| │ ├── types.ts Logger type + shared interfaces. | ||
| │ ├── installers/ | ||
| │ │ ├── base-installer.ts Marker-based idempotent install/uninstall. | ||
| │ │ ├── claude-code-installer.ts | ||
| │ │ ├── cursor-installer.ts | ||
| │ │ ├── windsurf-installer.ts | ||
| │ │ ├── copilot-installer.ts | ||
| │ │ ├── claude-md-installer.ts | ||
| │ │ └── agents-md-installer.ts | ||
| │ ├── agent-manager.ts Orchestrator: installAll / installFromList / uninstallAll. | ||
| │ ├── docs-sync.ts installDocs + ensureGitignore (was inline in extension's AgentManager). | ||
| │ └── catalog-sync.ts syncServiceCatalog (was apps/vscode/src/agents/services.ts). | ||
| ├── docs/ Bundled doc files (checked in; copied from <repo>/docs/agents/). | ||
| │ ├── ROCKETRIDE_README.md | ||
| │ ├── ROCKETRIDE_QUICKSTART.md | ||
| │ ├── ROCKETRIDE_PIPELINE_RULES.md | ||
| │ ├── ROCKETRIDE_COMPONENT_REFERENCE.md | ||
| │ ├── ROCKETRIDE_COMMON_MISTAKES.md | ||
| │ ├── ROCKETRIDE_python_API.md | ||
| │ ├── ROCKETRIDE_typescript_API.md | ||
| │ ├── ROCKETRIDE_OBSERVABILITY.md | ||
| │ └── stubs/ Bundled stub files (from <repo>/docs/stubs/). | ||
| │ ├── claude-code.md | ||
| │ ├── cursor.mdc | ||
| │ ├── windsurf.md | ||
| │ ├── copilot-instructions.md | ||
| │ ├── CLAUDE.md | ||
| │ └── AGENTS.md | ||
| └── test/ | ||
| ├── helpers.ts tmpdir + writeBundle + readWorkspace helpers. | ||
| ├── base-installer.test.ts | ||
| ├── installers.test.ts | ||
| ├── docs-sync.test.ts | ||
| ├── catalog-sync.test.ts | ||
| └── agent-manager.test.ts | ||
| ``` |
There was a problem hiding this comment.
Fix the repeated markdownlint fence violations in this plan.
This file has many fenced blocks without a language and several fences missing surrounding blank lines, which is already triggering MD040/MD031 warnings. Please make the fence style consistent throughout the document so the new plan doesn't add lint noise.
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/superpowers/plans/2026-05-28-p1-agents-core-extraction.md` around lines
25 - 67, The fenced code blocks in the plan (e.g., the package tree block in
docs/superpowers/plans/2026-05-28-p1-agents-core-extraction.md) are missing
explicit languages and surrounding blank lines causing MD040/MD031 lint
warnings; update every fenced block to use a consistent fence style (triple
backticks) with an explicit language token (use "text" for plain tree/layout
blocks) and ensure there is a blank line before and after each fence so all
occurrences (the package tree and any other ``` blocks) conform to markdownlint
rules.
joshuadarron
left a comment
There was a problem hiding this comment.
Thanks @EdwardLien0426. One bit of housekeeping before review: the diff is carrying a few files that aren't part of agents-core or rocketride init:
.github/workflows/discord-discussions.yml.devcontainer/devcontainer-lock.json.github/copilot-instructions.md(the repo-root one, not the stub this PR adds underpackages/agents-core/docs/stubs/)
Those are develop-owned files. You already have a Merge upstream/develop commit (08ef524), so you synced once, but develop has moved on since then. GitHub diffs the PR from the merge base, and right now the branch's merge base is behind develop's tip, so changes that landed on develop after your merge are leaking in here. Rebasing onto the latest develop (or merging develop again) moves the merge base forward and drops them out.
Heads up that this won't shrink the file count by much. agents-core is a new workspace package with bundled docs and stubs, so most of the ~50 files are legitimately yours. The rebase is just to clear those three so the diff only shows what this PR actually changes.
…1024-agents-core-and-init
Neither file belongs to the agents-core / rocketride-init work: - .github/copilot-instructions.md (repo root) was the CopilotInstaller's generated output (starts with the ROCKETRIDE marker), not source. The PR's actual Copilot stub lives at packages/agents-core/docs/stubs/. - .devcontainer/devcontainer-lock.json is auto-generated devcontainer tooling; develop tracks only devcontainer.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the review @joshuadarron! I've cleared those 3 develop-owned files ( |
Closes #1024
Why
Make the VS Code extension's project scaffolding available headlessly via
rocketride init. The extension's installers were coupled to vscode APIs, soP1 extracts a framework-agnostic core and P2 builds the CLI on top.
What
P1 —
@rocketride/agents-core(new workspace package)syncServiceCatalog, AgentManager —
fs/promises+pathonly, novscode.Logger; bundles the 8 docs + 6 stubs so it's self-contained.P2 —
rocketride init(inpackages/client-typescript)init [--agent <slug...>] [--no-catalog] [--apikey] [--uri]; default installsall agents; slugs map to canonical names; unknown slug exits 1.
.rocketride/docs, agent stubs,.gitignore, and a.envtemplate(created only if absent;
.envadded to.gitignore).import * as process(crashed the CLI bin at startup on Node 26).Out of scope
Verification
pnpm -F @rocketride/agents-core test→ 29 passedpnpm -F ./packages/client-typescript exec jest init.test.ts→ 9 passedpnpm -F ./packages/client-typescript exec tsc -p tsconfig.cli.json --noEmit→ cleanrocketride init --no-catalogscaffolds correctly;--agent fooexits 1Summary by CodeRabbit
New Features
rocketride initCLI to scaffold projects with agent stubs, non‑destructive.envcreation, optional service-catalog sync, and idempotent installsDocumentation
Tests
Chores