Skip to content

Add deterministic tracked AI setup delivery - #5

Merged
sergak01 merged 5 commits into
mainfrom
feat/tracked-ai-setup-delivery
Aug 12, 2026
Merged

Add deterministic tracked AI setup delivery#5
sergak01 merged 5 commits into
mainfrom
feat/tracked-ai-setup-delivery

Conversation

@sergak01

@sergak01 sergak01 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Publish a prebuilt private GitHub Package with CI, release validation, provenance, and packaged-artifact smoke tests.
  • Add deterministic check and update flows for tracked Cursor and Claude setup files, including safe conflict detection and migrations.
  • Add agent-facing setup health markers and conservative AGENTS.md merging that never destroys repository-owned guidance.

Key changes

  • Record package version, release commit, template revision, and portable per-file hashes in schema 6 metadata.
  • Classify managed, protected, and structured files so updates can overwrite, preserve, merge, or report conflicts safely.
  • Generate .assistant-setup/SETUP_STATUS.md plus an always-on health rule for missing or stale setup detection.
  • Publish immutable stable/next packages through protected GitHub Actions workflows using Node 24 actions.
  • Remove tracked IDE metadata and document developer authentication, installation, update PRs, and rollback.

Included commits

  • 3f94b4a feat: add deterministic tracked setup updates
  • 9df94b0 ci: publish prebuilt private package
  • 1864062 docs: document tracked setup delivery

Testing

  • npm test — 151 tests passed
  • npm run lint
  • npm run typecheck
  • npm run test:package — packaged CLI generated 71 files successfully

Release configuration

Before the first release, configure the protected package-release GitHub environment and the METRICINSIGHTS_PACKAGES_TOKEN secret with package write access.

Merge Request: origin/feat/tracked-ai-setup-deliveryorigin/main

Summary by CodeRabbit

  • New Features
    • Added check and update commands to detect setup drift, conflicts, missing files, and obsolete files.
    • Added --version support and clearer command-line validation.
    • Added setup health status reporting and release provenance metadata.
    • Added safe reconciliation with dry-run support, file adoption, merging, and conflict protection.
  • Bug Fixes
    • Existing AGENTS.md content is preserved, including with force operations; generated agent entries are merged safely.
  • Documentation
    • Updated installation, publishing, setup-health, and shared environment guidance.
  • Chores
    • Added automated validation and release workflows.

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.
@sergak01 sergak01 self-assigned this Aug 12, 2026
@sergak01
sergak01 requested a review from Sadilenko August 12, 2026 15:01
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@sergak01, you've reached your PR review limit, so we couldn't start this review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 510deca3-2ced-4391-9646-3041a7d363a0

📥 Commits

Reviewing files that changed from the base of the PR and between 1864062 and 04c3ddb.

📒 Files selected for processing (15)
  • .github/workflows/release.yml
  • README.md
  • package.json
  • src/cli-summary.ts
  • src/cli.ts
  • src/constants.ts
  • src/generator.ts
  • src/reconcile.ts
  • src/setup-metadata.ts
  • templates/cursor/rules/assistant-setup-health.mdc
  • tests/cli.test.ts
  • tests/generator.test.ts
  • tests/mcp-json-merge.test.ts
  • tests/reconcile.test.ts
  • tests/setup-metadata.test.ts
📝 Walkthrough

Walkthrough

The pull request adds package validation and release workflows, GitHub Packages publishing, deterministic setup metadata, check and update CLI modes, reconciliation logic, protected AGENTS.md merging, setup-health guidance, and comprehensive tests.

Changes

Package distribution and release

Layer / File(s) Summary
Package distribution and release validation
.github/workflows/*, package.json, scripts/*, README.md, .gitignore, .idea/*
CI validates linting, types, tests, and packed artifacts. Release tags publish version-matched packages to GitHub Packages. Package smoke tests verify installation and CLI output. IntelliJ project files were removed and .idea/ was ignored.

Setup metadata and generation

Layer / File(s) Summary
Setup metadata and generated files
src/setup-metadata.ts, src/generator.ts, src/setup-log.ts, src/previous-setup.ts, src/generators/*, src/constants.ts, templates/*, tests/generator.test.ts, tests/setup-metadata.test.ts
Setup status and schema version 6 metadata now record normalized paths, ownership, hashes, configuration, and provenance. Generation writes metadata after setup files and always merges existing AGENTS.md content.

CLI reconciliation

Layer / File(s) Summary
CLI reconciliation workflows
src/cli-args.ts, src/cli.ts, src/reconcile.ts, src/cli-summary.ts, src/mcp-json-merge.ts, tests/cli-args.test.ts, tests/cli.test.ts, tests/reconcile.test.ts, tests/mcp-json-merge.test.ts
The CLI supports --version, check, and update. Reconciliation detects missing, changed, preserved, mergeable, orphaned, and conflicting files, then applies safe updates and reports results.

Setup guidance

Layer / File(s) Summary
Protected files and setup guidance
AGENTS.md, CLAUDE.md, templates/AGENTS.md, templates/claude/*, templates/cursor/*, templates/assistant-setup/*, tests/templates-contract.test.ts
Documentation and templates describe setup-health checks, approval requirements, preserved AGENTS.md content, and tracked shared developer-environment 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
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's main change: deterministic delivery of tracked AI setup files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tracked-ai-setup-delivery

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🧹 Nitpick comments (11)
tests/mcp-json-merge.test.ts (1)

271-295: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the header-only registry table.

mergeAgentsMd gained 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 computes insertAt = 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 value

Extract the generated section heading into a shared constant.

The literal '## Registered agents added by ca-ai-tools-setup' is asserted by tests/cli.test.ts, tests/mcp-json-merge.test.ts, and tests/reconcile.test.ts as 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 win

The 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 repository AGENTS.md that 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 tableHeaderPattern match.

🤖 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 value

Temporary directories are never removed.

Each test creates a directory with fs.mkdtempSync and 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 value

Add the accepted cases to the validation test.

The test only asserts the throwing paths. Add assert.doesNotThrow for the supported forms, so a future change to maximumPositionals cannot 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 win

Assert the status of the initial generate run.

The check test at Line 256 captures generated and asserts generated.status. These four tests discard the result of the setup runCli call. If generation fails, the failure surfaces later as a confusing ENOENT from fs.rmSync or 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 win

Add 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 for update --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 from check.

🤖 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 value

The final mergeLabel branch is now unreachable.

AGENTS.md returns 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

update skips the QA AI rules hook silently when the flag is absent.

runExplicitQaSetup requires parseQaAiRulesArg(qaAiRulesCliRaw(args)) === true. During update, configuration.qaAiRulesInclude can still be true from the saved defaults, and getGeneratedFiles then produces the QA-related files. In that case the files are reconciled but qa-ai-rules init never runs, and printReconcileSummary prints 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 value

A single mistyped command is silently used as a target directory.

cliMode only recognizes check and update. validateCliArgs only throws when the positional count exceeds the limit. So ca-ai-tools-setup chek parses as generate mode with target directory chek, 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 --target for 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

mergeFile runs twice for every merged path, and empty directories remain after removal.

Two points in this function:

  1. Line 500 computes the merge result to write it. buildUpdatedMetadata at Line 449 computes the same merge again to record the hash. The results agree because mergeFile is deterministic, but the coupling is implicit. Compute the final content once, then reuse it for both the write and the metadata record.
  2. fs.rmSync with force: true removes 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 win

Correct the --force overwrite description.

This line says that --force overwrites every generated path. It conflicts with the AGENTS.md policy and with the earlier update rules. State that --force overwrites MCP JSON files instead of merging them. State that it does not replace AGENTS.md.

As per coding guidelines, “Existing AGENTS.md is 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 unknown for local package smoke tests. If a stable or next workflow uses this check, require a 40-character commit before npm publish.

src/previous-setup.ts (1)

2-2: 📐 Maintainability & Code Quality

Run the required TypeScript validation commands.

No validation output is included.

  • src/previous-setup.ts#L2-L2: run npm run typecheck and npm run lint.
  • tests/setup-metadata.test.ts#L1-L155: run npm run typecheck and npm test.
  • tests/generator.test.ts#L35-L375: run npm test and tsx --test tests/generator.test.ts.
  • tests/templates-contract.test.ts#L13-L88: run npm run typecheck and npm 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 win

Treat .dev-environment.md as a shared baseline, not machine state.

These changes make .dev-environment.md tracked 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-run paths still merge AGENTS.md.

The guard at Line 155 returns an empty action map when args.force, args.dryRun, or args.yes is set. In those runs the new 'merge' action for AGENTS.md is never recorded here, so the preservation must come from generator.ts instead. The coding guidelines require that an existing AGENTS.md is never replaced, including with --force.

Confirm that generator.ts forces the merge action for AGENTS.md independently of this prompt helper.

As per coding guidelines: "Existing AGENTS.md is 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 loadPreviousInteractiveDefaults succeeds for schema 5 metadata.

Reconciliation aborts when previous is falsy, and the message tells the user to run the initial setup. Schema 5 migration is a supported path in buildReconcilePlan (metadataIsLegacy), and tests/reconcile.test.ts covers it at the module level. However, tests/cli.test.ts has no CLI-level schema 5 case. If loadPreviousInteractiveDefaults returns null for schema 5 files, the check and update commands 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.

desiredSetupFiles validates every generated path with isSafeSetupPath and throws on unsafe values. The orphan loop takes filePath directly from previousMetadata.files keys and passes it to readCurrentFile and, for the remove action, to fs.rmSync(path.join(options.targetDir, filePath), { force: true }). path.join does not contain traversal, so a key such as ../../.ssh/authorized_keys resolves outside targetDir.

.assistant-setup/ca-ai-tools-setup.json lives in the target repository and is therefore untrusted input. If loadSetupMetadata does not reject unsafe keys, running update inside 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 generateSetup options are optional.

createCursorSetup passes only targetDir, assistants, force, dryRun, and playwrightMcpInclude. It omits figmaMcpInclude, qaAiRulesInclude, existingFileActions, and files, all of which src/cli.ts supplies at Lines 45-55. If any of those fields is required on the options type, npm run typecheck fails, because the coding guidelines run tsc --noEmit over src/ and tests/.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4f83e5f and 1864062.

⛔ Files ignored due to path filters (1)
  • package-lock.json is 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.xml
  • AGENTS.md
  • CLAUDE.md
  • README.md
  • package.json
  • scripts/clean-dist.mjs
  • scripts/package-smoke.mjs
  • scripts/write-release-info.mjs
  • src/cli-args.ts
  • src/cli-prompts.ts
  • src/cli-summary.ts
  • src/cli.ts
  • src/constants.ts
  • src/generator.ts
  • src/generators/cursor.ts
  • src/generators/portal-page-ai.ts
  • src/mcp-json-merge.ts
  • src/package-manager.ts
  • src/previous-setup.ts
  • src/reconcile.ts
  • src/setup-log.ts
  • src/setup-metadata.ts
  • templates/AGENTS.md
  • templates/assistant-setup/dev-environment.md
  • templates/claude/CLAUDE.md
  • templates/cursor/rules/README.md
  • templates/cursor/rules/assistant-setup-health.mdc
  • templates/setup-claude-assistant.md
  • templates/setup-cursor-assistant.md
  • tests/cli-args.test.ts
  • tests/cli.test.ts
  • tests/generator.test.ts
  • tests/mcp-json-merge.test.ts
  • tests/reconcile.test.ts
  • tests/setup-metadata.test.ts
  • tests/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

Comment thread .github/workflows/release.yml
Comment thread src/cli-summary.ts
Comment on lines +208 to +212
if (result.metadataMigrationRequired) {
printLine('Metadata: schema 5 migration required');
} else if (result.metadataUpdated) {
printLine('Metadata: updated');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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.

Suggested change
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.

Comment thread src/cli.ts Outdated
Comment thread src/generator.ts
Comment thread src/reconcile.ts
Comment thread src/setup-metadata.ts
Comment thread tests/cli.test.ts
Sadilenko
Sadilenko previously approved these changes Aug 12, 2026
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.
@sergak01
sergak01 merged commit 86257bb into main Aug 12, 2026
2 checks passed
@sergak01
sergak01 deleted the feat/tracked-ai-setup-delivery branch August 12, 2026 15:37
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.

2 participants