Add deterministic tracked AI setup delivery - #5
Conversation
Track package provenance and hashes, reconcile safe updates, expose agent status markers, and preserve AGENTS.md customizations.
Build and smoke-test immutable artifacts in CI, publish tagged releases to GitHub Packages, and remove tracked IDE files.
Explain private package authentication, deterministic update PRs, setup health markers, and conservative AGENTS.md merging.
|
Warning Review limit reached
Next review available in: 31 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughThe pull request adds package validation and release workflows, GitHub Packages publishing, deterministic setup metadata, ChangesPackage distribution and release
Setup metadata and generation
CLI reconciliation
Setup guidance
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Operator
participant CLI
participant SetupMetadata
participant Reconcile
participant Repository
Operator->>CLI: run check or update
CLI->>SetupMetadata: load and validate metadata
CLI->>Reconcile: build reconciliation plan
Reconcile->>Repository: read current files
Reconcile-->>CLI: return file states and conflicts
CLI->>Reconcile: apply update when no conflict blocks it
Reconcile->>Repository: write, merge, or remove setup files
Reconcile-->>CLI: return reconciliation result
CLI-->>Operator: print summary and exit status
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (11)
tests/mcp-json-merge.test.ts (1)
271-295: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for the header-only registry table.
mergeAgentsMdgained a branch that inserts rows after the separator of an existing| File | Purpose |table that has no data rows yet. The new tests cover the no-table case and the empty-file case, but not that branch. It is the only path that computesinsertAt = headerIndex + 2, and it also depends on the case-insensitive header pattern.💚 Proposed test
+test('mergeAgentsMd inserts rows into an existing table that has no data rows', () => { + const existing = ['# Repository instructions', '', '| file | purpose |', '| ---- | ------- |', ''].join('\n'); + const incoming = '| `code-style.md` | Generated code style agent. |\n'; + const result = mergeAgentsMd(existing, incoming); + + assert.match(result, /\| ---- \| ------- \|\n\| `code-style\.md` \|/); + assert.doesNotMatch(result, /Registered agents added by ca-ai-tools-setup/); +});🤖 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 `@tests/mcp-json-merge.test.ts` around lines 271 - 295, Add a test for mergeAgentsMd covering an existing document with a case-insensitive “File”/“Purpose” registry header and separator but no data rows. Assert custom content is preserved and generated registry rows are inserted after the separator, exercising the insertAt = headerIndex + 2 branch.src/mcp-json-merge.ts (2)
241-241: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the generated section heading into a shared constant.
The literal
'## Registered agents added by ca-ai-tools-setup'is asserted bytests/cli.test.ts,tests/mcp-json-merge.test.ts, andtests/reconcile.test.tsas separate regular expressions. Export the heading text and reuse it, so a wording change does not silently break three test files.🤖 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 `@src/mcp-json-merge.ts` at line 241, Extract the `'## Registered agents added by ca-ai-tools-setup'` heading into an exported shared constant near the MCP JSON merge implementation, then reuse that constant where the generated section is constructed and in the assertions in cli.test.ts, mcp-json-merge.test.ts, and reconcile.test.ts.
229-245: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winThe insertion heuristic can target an unrelated table before this fallback runs.
The fallback correctly handles a header-only registry table and, failing that, appends a self-contained section. However, it is reached only when no line in the file matches
dataRowPattern. That pattern matches any row whose first cell is backticked, anywhere in the file. A repositoryAGENTS.mdthat documents commands in a table such as| `npm run build` | Compiles the app. |therefore captures the insertion point, and generated agent rows are spliced into that table instead of a registry table.Consider restricting the last-data-row search to rows that follow a
tableHeaderPatternmatch.🤖 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 `@src/mcp-json-merge.ts` around lines 229 - 245, The data-row insertion search in the surrounding merge logic must only consider rows belonging to a table whose header matches tableHeaderPattern, rather than matching any backticked first-cell row in the file. Scope the last-data-row lookup and resulting insertAt to the relevant registry table, while preserving the header-only handling and self-contained fallback section.tests/reconcile.test.ts (1)
10-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTemporary directories are never removed.
Each test creates a directory with
fs.mkdtempSyncand generates a full setup tree into it. None of the 13 tests removes the directory, so every test run leaves the trees behind in the system temporary directory. Register cleanup with the test context.♻️ Proposed cleanup helper
-function makeTempDir(): string { - return fs.mkdtempSync(path.join(os.tmpdir(), 'ca-ai-tools-reconcile-')); -} +function makeTempDir(t: test.TestContext): string { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ca-ai-tools-reconcile-')); + + t.after(() => fs.rmSync(dir, { recursive: true, force: true })); + + return dir; +}Each test then takes the context, for example
test('checkSetup reports a clean generated setup', (t) => { const dir = makeTempDir(t); ... }).🤖 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 `@tests/reconcile.test.ts` around lines 10 - 12, Update makeTempDir to accept the test context and register cleanup that recursively removes the directory after each test. Pass the context from all tests that create temporary directories, such as the checkSetup test, while preserving the existing mkdtemp setup behavior.tests/cli-args.test.ts (1)
27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd the accepted cases to the validation test.
The test only asserts the throwing paths. Add
assert.doesNotThrowfor the supported forms, so a future change tomaximumPositionalscannot reject valid input unnoticed:💚 Proposed additional assertions
assert.throws(() => validateCliArgs(parseCliArgs(['check', '../repo', 'extra'])), /Too many positional/); + assert.doesNotThrow(() => validateCliArgs(parseCliArgs(['../repo']))); + assert.doesNotThrow(() => validateCliArgs(parseCliArgs(['update', '../repo']))); + assert.doesNotThrow(() => validateCliArgs(parseCliArgs(['--target', '../repo']))); });🤖 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 `@tests/cli-args.test.ts` around lines 27 - 33, Extend the test validateCliArgs rejects command typos with an additional target to cover supported inputs with assert.doesNotThrow, including valid check invocations with an accepted positional target and the supported command form without extra arguments. Keep the existing assertions for unknown commands and excessive positionals unchanged.tests/cli.test.ts (2)
267-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the status of the initial generate run.
The
checktest at Line 256 capturesgeneratedand assertsgenerated.status. These four tests discard the result of the setuprunClicall. If generation fails, the failure surfaces later as a confusingENOENTfromfs.rmSyncor as an unexpected exit code. Capture the result and assert the status in each test.Also applies to: 283-298, 300-317, 319-332
🤖 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 `@tests/cli.test.ts` around lines 267 - 281, Capture the initial setup runCli result in each affected test, including the missing-file test and the ranges at 283-298, 300-317, and 319-332, then assert its status matches the expected successful generation status before performing filesystem mutations or running check. Keep the existing test-specific assertions unchanged.
300-317: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd CLI coverage for
update --dry-run.The module-level dry-run path is covered in
tests/reconcile.test.ts. At the CLI level there is no test forupdate --dry-run, so the preview label, the "Planned changes:" heading, and the exit code are unverified. This is the path where the exit code differs fromcheck.🤖 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 `@tests/cli.test.ts` around lines 300 - 317, Add a CLI test alongside the existing update conflict test that runs `update --dry-run` against a target with planned changes. Assert the preview label and “Planned changes:” heading appear in stdout, and verify the command’s expected dry-run exit code, distinct from `check`.src/cli-prompts.ts (1)
177-182: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe final
mergeLabelbranch is now unreachable.
AGENTS.mdreturns at Line 174, so the label'Merge — append new agent table rows not already listed'can no longer be selected. The remaining mergeable paths are.cursor/mcp.json,.mcp.json, and.claude/settings.json, and each has its own branch. Remove the dead fallback or reduce the expression to a lookup.🤖 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 `@src/cli-prompts.ts` around lines 177 - 182, Remove the unreachable fallback branch from the mergeLabel logic near the AGENTS.md return, and simplify it to cover only .cursor/mcp.json, .mcp.json, and .claude/settings.json using the existing labels. Preserve the current label text and ensure no dead fallback remains.src/cli.ts (1)
113-139: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
updateskips the QA AI rules hook silently when the flag is absent.
runExplicitQaSetuprequiresparseQaAiRulesArg(qaAiRulesCliRaw(args)) === true. Duringupdate,configuration.qaAiRulesIncludecan still betruefrom the saved defaults, andgetGeneratedFilesthen produces the QA-related files. In that case the files are reconciled butqa-ai-rules initnever runs, andprintReconcileSummaryprints no QA line. The user gets no indication.Add a summary line that states whether the QA hook ran, was skipped, or was not requested.
Also applies to: 181-185
🤖 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 `@src/cli.ts` around lines 113 - 139, Update runExplicitQaSetup and the reconcile summary flow to report QA hook status when qaAiRulesInclude is enabled from saved configuration even without an explicit CLI flag. Distinguish and display whether the hook ran, was skipped, or was not requested, including the existing no-package-json skip case, and ensure printReconcileSummary receives and renders this status.src/cli-args.ts (1)
31-53: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueA single mistyped command is silently used as a target directory.
cliModeonly recognizescheckandupdate.validateCliArgsonly throws when the positional count exceeds the limit. Soca-ai-tools-setup chekparses as generate mode with target directorychek, and the CLI then creates that directory instead of reporting the typo. The two-argument form (chek ../repo) is rejected correctly, so the behavior is inconsistent.Consider rejecting a single positional that looks like a command word, or requiring
--targetfor generate mode.🤖 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 `@src/cli-args.ts` around lines 31 - 53, Update validateCliArgs and cliMode handling so a single unknown command-like positional is rejected instead of being treated as the generate target directory. Preserve valid generate targets and recognized check/update commands, while ensuring mistyped command words such as “chek” produce the existing unknown-command validation error.src/reconcile.ts (1)
485-519: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
mergeFileruns twice for every merged path, and empty directories remain after removal.Two points in this function:
- Line 500 computes the merge result to write it.
buildUpdatedMetadataat Line 449 computes the same merge again to record the hash. The results agree becausemergeFileis deterministic, but the coupling is implicit. Compute the final content once, then reuse it for both the write and the metadata record.fs.rmSyncwithforce: trueremoves the file but leaves the parent directory. After a managed rule set is dropped, empty directories such as.cursor/skills/ui-check/stay in the repository.🤖 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 `@src/reconcile.ts` around lines 485 - 519, Update updateSetup to compute each merged file’s final content once, reuse that content for both writeFile and buildUpdatedMetadata’s hash recording, and avoid a second mergeFile call. When processing remove actions, remove the managed file and clean up now-empty parent directories while preserving non-empty directories and unrelated files.
🔇 Additional comments (38)
.github/workflows/ci.yml (1)
1-39: LGTM!.gitignore (1)
3-3: LGTM!package.json (1)
6-17: LGTM!Also applies to: 30-34, 58-58
scripts/write-release-info.mjs (1)
1-25: LGTM!src/setup-log.ts (1)
49-137: LGTM!src/package-manager.ts (1)
155-155: LGTM!Also applies to: 207-208, 296-296
src/constants.ts (1)
7-7: LGTM!README.md (1)
340-340: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winCorrect the
--forceoverwrite description.This line says that
--forceoverwrites every generated path. It conflicts with theAGENTS.mdpolicy and with the earlier update rules. State that--forceoverwrites MCP JSON files instead of merging them. State that it does not replaceAGENTS.md.As per coding guidelines, “Existing
AGENTS.mdis never replaced, including with--force.”⛔ Skipped due to learnings
Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/AGENTS.md:0-0 Timestamp: 2026-08-11T14:51:02.852Z Learning: Applies to templates/**/AGENTS.md : When re-running `ca-ai-tools-setup` without `--force`, preserve the existing `AGENTS.md`; use `--force` only after backing up the file, or manually merge template updates.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-06-24T07:56:31.851Z Learning: MCP JSON files should be handled interactively with Skip/Merge/Overwrite; they are left unchanged with `--yes` and fully replaced with `--force`.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: AGENTS.md:0-0 Timestamp: 2026-06-24T07:57:04.074Z Learning: Applies to src/{cli.ts,generator.ts,mcp-json-merge.ts} : Handle MCP JSON files with interactive Skip/Merge/Overwrite prompting; leave them unchanged when `--yes` is used, and fully replace them when `--force` is used.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/AGENTS.md:0-0 Timestamp: 2026-08-11T14:51:02.852Z Learning: Applies to templates/**/AGENTS.md : Customize the `AGENTS.md` agent table for the repository by correcting descriptions, adding agents, and removing rows for deleted files.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/AGENTS.md : Keep `AGENTS.md` aligned when agent files are added, renamed, or removed.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-06-24T07:56:31.851Z Learning: `CLAUDE.md`, `.cursorrules`, `.cursor/skills/ui-check/SKILL.md`, `.claude/skills/ui-check/SKILL.md`, `.claude/settings.json`, `AGENTS.md`, and `.dev-environment.md` should be created on first run and skipped on subsequent runs unless `--force` is used.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/AGENTS.md:0-0 Timestamp: 2026-08-11T14:51:02.852Z Learning: Applies to templates/**/AGENTS.md : Keep the repo-root `AGENTS.md` index synchronized with `.claude/agents/`, adding a row for each new agent and removing rows for deleted agents.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/* : Read `AGENTS.md` and `README.md` before making non-trivial code changes.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: AGENTS.md:0-0 Timestamp: 2026-06-24T07:57:04.074Z Learning: Applies to src/generator.ts : Treat `CLAUDE.md`, `.cursorrules`, `.cursor/skills/*`, `.claude/skills/*`, `.claude/settings.json`, `AGENTS.md`, and `.dev-environment.md` as create-on-first-run files that are skipped on subsequent runs unless `--force` is used.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/.claude/settings.json : Do not assume rerunning `ca-ai-tools-setup` without `--force` overwrites existing settings; extend the file in place or manually merge template keys.Source: Coding guidelines
scripts/clean-dist.mjs (1)
1-7: LGTM!scripts/package-smoke.mjs (1)
69-70: 🔒 Security & Privacy
⚠️ Unverified finding
Sandbox verification was unavailable.Verify publication rejects unknown provenance.
Line 70 permits
unknownfor local package smoke tests. If a stable or next workflow uses this check, require a 40-character commit beforenpm publish.src/previous-setup.ts (1)
2-2: 📐 Maintainability & Code QualityRun the required TypeScript validation commands.
No validation output is included.
src/previous-setup.ts#L2-L2: runnpm run typecheckandnpm run lint.tests/setup-metadata.test.ts#L1-L155: runnpm run typecheckandnpm test.tests/generator.test.ts#L35-L375: runnpm testandtsx --test tests/generator.test.ts.tests/templates-contract.test.ts#L13-L88: runnpm run typecheckandnpm test.Source: Coding guidelines
templates/cursor/rules/assistant-setup-health.mdc (1)
1-21: LGTM!templates/setup-claude-assistant.md (1)
323-336: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winTreat
.dev-environment.mdas a shared baseline, not machine state.These changes make
.dev-environment.mdtracked and shared. Earlier text calls it the source of truth “for this machine.” A shared file can be stale or incompatible with a developer machine.
templates/setup-claude-assistant.md#L323-L336: revise the earlier instruction to treat the file as shared repository guidance and require local URL and shell verification.templates/setup-cursor-assistant.md#L311-L324: make the same wording change.Proposed wording
- Follow that file as the source of truth for this machine; align questions and commands with the recorded OS/shell. + Treat that file as the source of truth for shared repository guidance. Confirm the current machine URL, OS, and shell before running commands.⛔ Skipped due to learnings
Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: AGENTS.md:0-0 Timestamp: 2026-06-24T07:57:04.074Z Learning: Applies to templates/setup-*-assistant.md : Always overwrite the setup assistant markdown templates (`setup-cursor-assistant.md` and `setup-claude-assistant.md`).Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-06-24T07:56:31.851Z Learning: Setup assistant markdown files (`setup-cursor-assistant.md` and `setup-claude-assistant.md`) are always overwritten.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/.env* : Keep authentication and API quirks in `.dev-environment.md` or `.env`; never invent or commit secrets.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/* : Read `AGENTS.md` and `README.md` before making non-trivial code changes.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/.claude/settings.json : Do not assume rerunning `ca-ai-tools-setup` without `--force` overwrites existing settings; extend the file in place or manually merge template keys.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/.claude/settings.json : Treat `/.claude/settings.json` as the shared Claude Code configuration for permissions, hooks, and environment settings.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-06-24T07:56:31.851Z Learning: `CLAUDE.md`, `.cursorrules`, `.cursor/skills/ui-check/SKILL.md`, `.claude/skills/ui-check/SKILL.md`, `.claude/settings.json`, `AGENTS.md`, and `.dev-environment.md` should be created on first run and skipped on subsequent runs unless `--force` is used.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/*.{ts,tsx,js,jsx,scss,css,html} : Follow `.claude/agents/code-style.md` for Portal Page naming, SCSS modules, BEM, `app-context`/`app-provider`, `constants.ts`, and `index.html` globals.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: AGENTS.md:0-0 Timestamp: 2026-06-24T07:57:04.074Z Learning: Applies to src/generator.ts : Treat `CLAUDE.md`, `.cursorrules`, `.cursor/skills/*`, `.claude/skills/*`, `.claude/settings.json`, `AGENTS.md`, and `.dev-environment.md` as create-on-first-run files that are skipped on subsequent runs unless `--force` is used.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/claude/CLAUDE.md:0-0 Timestamp: 2026-08-11T14:50:55.755Z Learning: Applies to templates/claude/**/AGENTS.md : Keep `AGENTS.md` aligned when agent files are added, renamed, or removed.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/AGENTS.md:0-0 Timestamp: 2026-08-11T14:51:02.852Z Learning: Applies to templates/**/AGENTS.md : When re-running `ca-ai-tools-setup` without `--force`, preserve the existing `AGENTS.md`; use `--force` only after backing up the file, or manually merge template updates.Learnt from: CR Repo: mi-examples/ca-ai-tools-setup PR: 0 File: templates/AGENTS.md:0-0 Timestamp: 2026-08-11T14:51:02.852Z Learning: Applies to templates/**/AGENTS.md : Keep the repo-root `AGENTS.md` index synchronized with `.claude/agents/`, adding a row for each new agent and removing rows for deleted agents.src/generator.ts (1)
3-17: LGTM!Also applies to: 168-185, 294-305, 413-459
src/generators/cursor.ts (1)
54-58: LGTM!src/generators/portal-page-ai.ts (1)
13-14: LGTM!Also applies to: 28-28, 50-50, 87-87
AGENTS.md (1)
54-55: LGTM!CLAUDE.md (1)
53-54: LGTM!templates/AGENTS.md (1)
5-22: LGTM!Also applies to: 31-31
templates/assistant-setup/dev-environment.md (1)
3-4: LGTM!Also applies to: 181-181
templates/claude/CLAUDE.md (1)
10-12: LGTM!templates/cursor/rules/README.md (1)
33-33: LGTM!src/cli-args.ts (1)
11-15: LGTM!Also applies to: 17-29, 80-80
src/cli-prompts.ts (1)
172-176: 🗄️ Data Integrity & Integration
⚠️ Unverified finding
Sandbox verification was unavailable.Verify that the
--force,--yes, and--dry-runpaths still mergeAGENTS.md.The guard at Line 155 returns an empty action map when
args.force,args.dryRun, orargs.yesis set. In those runs the new'merge'action forAGENTS.mdis never recorded here, so the preservation must come fromgenerator.tsinstead. The coding guidelines require that an existingAGENTS.mdis never replaced, including with--force.Confirm that
generator.tsforces the merge action forAGENTS.mdindependently of this prompt helper.As per coding guidelines: "Existing
AGENTS.mdis never replaced, including with--force; missing generated agent rows are merged while repository-owned content is preserved".src/cli.ts (3)
6-15: LGTM!Also applies to: 24-33, 104-111
141-157: 🗄️ Data Integrity & Integration
⚠️ Unverified finding
Sandbox verification was unavailable.Verify that
loadPreviousInteractiveDefaultssucceeds for schema 5 metadata.Reconciliation aborts when
previousis falsy, and the message tells the user to run the initial setup. Schema 5 migration is a supported path inbuildReconcilePlan(metadataIsLegacy), andtests/reconcile.test.tscovers it at the module level. However,tests/cli.test.tshas no CLI-level schema 5 case. IfloadPreviousInteractiveDefaultsreturnsnullfor schema 5 files, thecheckandupdatecommands reject legacy installs before the migration logic runs.
192-213: LGTM!src/reconcile.ts (3)
21-98: LGTM!
305-332: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
⚠️ Unverified finding
Sandbox verification was unavailable.Orphan paths read from the metadata file are not validated as safe setup paths.
desiredSetupFilesvalidates every generated path withisSafeSetupPathand throws on unsafe values. The orphan loop takesfilePathdirectly frompreviousMetadata.fileskeys and passes it toreadCurrentFileand, for theremoveaction, tofs.rmSync(path.join(options.targetDir, filePath), { force: true }).path.joindoes not contain traversal, so a key such as../../.ssh/authorized_keysresolves outsidetargetDir.
.assistant-setup/ca-ai-tools-setup.jsonlives in the target repository and is therefore untrusted input. IfloadSetupMetadatadoes not reject unsafe keys, runningupdateinside a cloned repository can delete files outside that repository.Apply the same validation used for generated paths.
🔒 Proposed guard for metadata-supplied paths
if (previousMetadata) { for (const [filePath, previous] of Object.entries(previousMetadata.files)) { if (desiredPaths.has(filePath)) { continue; } + if (!isSafeSetupPath(filePath)) { + throw new Error(`Recorded setup path is unsafe: ${filePath}`); + } + const currentContent = readCurrentFile(options.targetDir, filePath);Also applies to: 502-504
100-269: LGTM!Also applies to: 271-304, 334-374, 376-423
src/cli-summary.ts (2)
4-4: LGTM!Also applies to: 163-166
193-207: LGTM!Also applies to: 214-280
src/mcp-json-merge.ts (1)
187-192: LGTM!Also applies to: 215-219
tests/cli-args.test.ts (1)
1-33: LGTM!tests/cli.test.ts (1)
40-40: LGTM!Also applies to: 135-135, 158-159, 203-203, 225-227
tests/mcp-json-merge.test.ts (1)
261-262: LGTM!Also applies to: 271-288, 290-295
tests/reconcile.test.ts (2)
14-22: 📐 Maintainability & Code Quality
⚠️ Unverified finding
Sandbox verification was unavailable.Verify that the omitted
generateSetupoptions are optional.
createCursorSetuppasses onlytargetDir,assistants,force,dryRun, andplaywrightMcpInclude. It omitsfigmaMcpInclude,qaAiRulesInclude,existingFileActions, andfiles, all of whichsrc/cli.tssupplies at Lines 45-55. If any of those fields is required on the options type,npm run typecheckfails, because the coding guidelines runtsc --noEmitoversrc/andtests/.As per coding guidelines: "
**/*.ts: npm run typecheck # tsc --noEmit over src/ and tests/".
24-37: LGTM!Also applies to: 39-324
🤖 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/release.yml:
- Around line 3-6: Update the release workflow triggered by the v* tag pattern
to fetch origin/main and verify that the tagged commit is reachable from
origin/main before publishing. Reject non-ancestor tags and prevent subsequent
release steps from running, while preserving the existing reviewed-main release
path.
In `@src/cli-summary.ts`:
- Around line 208-212: Update the metadata summary conditional in the CLI
summary flow to prioritize applied, non-dry-run results: report “Metadata:
updated” when result.applied is true and dryRun is false, and only report schema
migration required for work that remains unapplied or is a dry run. Keep the
existing result metadata fields and printLine behavior.
In `@src/cli.ts`:
- Around line 187-189: Extend the preview exit-status condition in src/cli.ts
lines 187-189 to include args.dryRun, so update --dry-run exits 2 when the plan
has changes or conflicts. Add coverage in tests/cli.test.ts lines 300-317 using
runCli(['update', targetDir, '--dry-run']) that asserts exit code 2, the “Setup
update preview completed.” label, the “Planned changes:” heading, and that no
file is written.
In `@src/generator.ts`:
- Around line 460-472: Update the writeOneFile call for SETUP_METADATA_PATH in
the setup generation flow to always replace the generated metadata, independent
of options.force or existing-file actions. Ensure the newly calculated hashes,
configuration, and merged baselines are written after setup files are processed.
In `@src/reconcile.ts`:
- Around line 432-483: Update buildUpdatedMetadata to carry forward metadata
records for planned orphan files whose action is not remove, including preserved
or modified action:none entries, instead of limiting metadata.files to
desiredFiles. Reuse each orphan’s existing metadata record and retain its path
and baseline information so subsequent check/update runs continue reporting
preserved obsolete files.
In `@src/setup-metadata.ts`:
- Around line 177-203: Update parseCurrentMetadata to reject metadata unless
every raw.assistants entry passes isAssistant and no assistant value is
duplicated; do not use filter(isAssistant), which silently discards invalid
entries. Preserve the existing empty-assistant rejection and continue
constructing metadata only after the full assistant list has been validated.
In `@tests/cli.test.ts`:
- Around line 246-252: Update the cli --version test to read the expected
version from the package manifest instead of hardcoding '0.1.0'. Preserve the
newline in the stdout assertion and keep the existing status and stderr checks
unchanged.
---
Nitpick comments:
In `@src/cli-args.ts`:
- Around line 31-53: Update validateCliArgs and cliMode handling so a single
unknown command-like positional is rejected instead of being treated as the
generate target directory. Preserve valid generate targets and recognized
check/update commands, while ensuring mistyped command words such as “chek”
produce the existing unknown-command validation error.
In `@src/cli-prompts.ts`:
- Around line 177-182: Remove the unreachable fallback branch from the
mergeLabel logic near the AGENTS.md return, and simplify it to cover only
.cursor/mcp.json, .mcp.json, and .claude/settings.json using the existing
labels. Preserve the current label text and ensure no dead fallback remains.
In `@src/cli.ts`:
- Around line 113-139: Update runExplicitQaSetup and the reconcile summary flow
to report QA hook status when qaAiRulesInclude is enabled from saved
configuration even without an explicit CLI flag. Distinguish and display whether
the hook ran, was skipped, or was not requested, including the existing
no-package-json skip case, and ensure printReconcileSummary receives and renders
this status.
In `@src/mcp-json-merge.ts`:
- Line 241: Extract the `'## Registered agents added by ca-ai-tools-setup'`
heading into an exported shared constant near the MCP JSON merge implementation,
then reuse that constant where the generated section is constructed and in the
assertions in cli.test.ts, mcp-json-merge.test.ts, and reconcile.test.ts.
- Around line 229-245: The data-row insertion search in the surrounding merge
logic must only consider rows belonging to a table whose header matches
tableHeaderPattern, rather than matching any backticked first-cell row in the
file. Scope the last-data-row lookup and resulting insertAt to the relevant
registry table, while preserving the header-only handling and self-contained
fallback section.
In `@src/reconcile.ts`:
- Around line 485-519: Update updateSetup to compute each merged file’s final
content once, reuse that content for both writeFile and buildUpdatedMetadata’s
hash recording, and avoid a second mergeFile call. When processing remove
actions, remove the managed file and clean up now-empty parent directories while
preserving non-empty directories and unrelated files.
In `@tests/cli-args.test.ts`:
- Around line 27-33: Extend the test validateCliArgs rejects command typos with
an additional target to cover supported inputs with assert.doesNotThrow,
including valid check invocations with an accepted positional target and the
supported command form without extra arguments. Keep the existing assertions for
unknown commands and excessive positionals unchanged.
In `@tests/cli.test.ts`:
- Around line 267-281: Capture the initial setup runCli result in each affected
test, including the missing-file test and the ranges at 283-298, 300-317, and
319-332, then assert its status matches the expected successful generation
status before performing filesystem mutations or running check. Keep the
existing test-specific assertions unchanged.
- Around line 300-317: Add a CLI test alongside the existing update conflict
test that runs `update --dry-run` against a target with planned changes. Assert
the preview label and “Planned changes:” heading appear in stdout, and verify
the command’s expected dry-run exit code, distinct from `check`.
In `@tests/mcp-json-merge.test.ts`:
- Around line 271-295: Add a test for mergeAgentsMd covering an existing
document with a case-insensitive “File”/“Purpose” registry header and separator
but no data rows. Assert custom content is preserved and generated registry rows
are inserted after the separator, exercising the insertAt = headerIndex + 2
branch.
In `@tests/reconcile.test.ts`:
- Around line 10-12: Update makeTempDir to accept the test context and register
cleanup that recursively removes the directory after each test. Pass the context
from all tests that create temporary directories, such as the checkSetup test,
while preserving the existing mkdtemp setup behavior.
🪄 Autofix
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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: bdbf5f1f-669a-42b8-8f19-19cd7fe71093
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (43)
.github/workflows/ci.yml.github/workflows/release.yml.gitignore.idea/.gitignore.idea/ca-ai-tools-setup.iml.idea/inspectionProfiles/Project_Default.xml.idea/modules.xml.idea/vcs.xmlAGENTS.mdCLAUDE.mdREADME.mdpackage.jsonscripts/clean-dist.mjsscripts/package-smoke.mjsscripts/write-release-info.mjssrc/cli-args.tssrc/cli-prompts.tssrc/cli-summary.tssrc/cli.tssrc/constants.tssrc/generator.tssrc/generators/cursor.tssrc/generators/portal-page-ai.tssrc/mcp-json-merge.tssrc/package-manager.tssrc/previous-setup.tssrc/reconcile.tssrc/setup-log.tssrc/setup-metadata.tstemplates/AGENTS.mdtemplates/assistant-setup/dev-environment.mdtemplates/claude/CLAUDE.mdtemplates/cursor/rules/README.mdtemplates/cursor/rules/assistant-setup-health.mdctemplates/setup-claude-assistant.mdtemplates/setup-cursor-assistant.mdtests/cli-args.test.tstests/cli.test.tstests/generator.test.tstests/mcp-json-merge.test.tstests/reconcile.test.tstests/setup-metadata.test.tstests/templates-contract.test.ts
💤 Files with no reviewable changes (5)
- .idea/ca-ai-tools-setup.iml
- .idea/.gitignore
- .idea/vcs.xml
- .idea/inspectionProfiles/Project_Default.xml
- .idea/modules.xml
| if (result.metadataMigrationRequired) { | ||
| printLine('Metadata: schema 5 migration required'); | ||
| } else if (result.metadataUpdated) { | ||
| printLine('Metadata: updated'); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
After an applied update the summary still reports the migration as required.
result.metadataMigrationRequired mirrors plan.metadataMigrationRequired, which is just metadataIsLegacy from the pre-update plan. updateSetup writes schema 6 metadata when there are no conflicts, so a successful, non-dry-run update prints "Metadata: schema 5 migration required" for work that has already completed. The metadataUpdated branch is then never reached in that run.
Report the state based on result.applied and dryRun.
🔧 Proposed wording fix
if (result.metadataMigrationRequired) {
- printLine('Metadata: schema 5 migration required');
+ printLine(
+ result.applied && !dryRun ? 'Metadata: migrated from schema 5' : 'Metadata: schema 5 migration required',
+ );
} else if (result.metadataUpdated) {
- printLine('Metadata: updated');
+ printLine(result.applied && !dryRun ? 'Metadata: updated' : 'Metadata: update pending');
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (result.metadataMigrationRequired) { | |
| printLine('Metadata: schema 5 migration required'); | |
| } else if (result.metadataUpdated) { | |
| printLine('Metadata: updated'); | |
| } | |
| if (result.metadataMigrationRequired) { | |
| printLine( | |
| result.applied && !dryRun ? 'Metadata: migrated from schema 5' : 'Metadata: schema 5 migration required', | |
| ); | |
| } else if (result.metadataUpdated) { | |
| printLine(result.applied && !dryRun ? 'Metadata: updated' : 'Metadata: update pending'); | |
| } |
🤖 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 `@src/cli-summary.ts` around lines 208 - 212, Update the metadata summary
conditional in the CLI summary flow to prioritize applied, non-dry-run results:
report “Metadata: updated” when result.applied is true and dryRun is false, and
only report schema migration required for work that remains unapplied or is a
dry run. Keep the existing result metadata fields and printLine behavior.
Ship the packed tarball as a public release asset instead of GitHub Packages so developers can install without registry auth.
Keep metadata and orphan records accurate, reject invalid assistants, and make update dry-run exit codes match the check preview contract.
Summary
checkandupdateflows for tracked Cursor and Claude setup files, including safe conflict detection and migrations.AGENTS.mdmerging that never destroys repository-owned guidance.Key changes
.assistant-setup/SETUP_STATUS.mdplus an always-on health rule for missing or stale setup detection.stable/nextpackages through protected GitHub Actions workflows using Node 24 actions.Included commits
3f94b4afeat: add deterministic tracked setup updates9df94b0ci: publish prebuilt private package1864062docs: document tracked setup deliveryTesting
npm test— 151 tests passednpm run lintnpm run typechecknpm run test:package— packaged CLI generated 71 files successfullyRelease configuration
Before the first release, configure the protected
package-releaseGitHub environment and theMETRICINSIGHTS_PACKAGES_TOKENsecret with package write access.Merge Request:
origin/feat/tracked-ai-setup-delivery→origin/mainSummary by CodeRabbit
checkandupdatecommands to detect setup drift, conflicts, missing files, and obsolete files.--versionsupport and clearer command-line validation.AGENTS.mdcontent is preserved, including with force operations; generated agent entries are merged safely.