refactor: remove all as type assertions from source code#459
Conversation
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_48d4a800-b42c-46a1-b3e4-2735d2185602) |
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. 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: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (33)
📝 WalkthroughWalkthroughChangesThis PR replaces multiple unsafe casts with Zod-based validation and stricter typing across CLI, engine, formats, auth, settings, session parsing, and repo probing. It also adds a Compact Metadata Sequence Diagram(s)Not applicable beyond the hidden artifact diagrams. Related Issues: None specified 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
Deploying archgate-cli with
|
| Latest commit: |
7562794
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6e20b831.archgate-cli.pages.dev |
| Branch Preview URL: | https://refactor-remove-as-type-asse.archgate-cli.pages.dev |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_4e1b9df2-95d1-4e5b-aef9-abf7ffe1fbc5) |
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_47f7c7a1-b8e9-4be8-b133-c075b1238216) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a123ed46-0475-4f87-85f4-5d19ff8226a1) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_041989e0-60ca-44b9-b998-bef323c5573a) |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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 `@src/formats/pack.ts`:
- Around line 33-35: Update parsePackMetadata() to treat malformed pack metadata
as a user-facing validation error instead of letting PackMetadataSchema.parse()
throw a ZodError. Mirror the pattern used by parseAdr(): use
PackMetadataSchema.safeParse() on Bun.YAML.parse(raw), and when validation fails
throw a UserError populated with the schema’s error messages. Keep the fix
localized to parsePackMetadata() and any nearby error handling that formats the
validation message.
In `@src/helpers/auth.ts`:
- Around line 213-215: The error-body handling in the auth flow should not
assume response.json() returns an object, since ErrorResponseSchema.parse(...)
can throw and mask the intended UserError/signup path. Update the parsing in the
relevant auth helper around ErrorResponseSchema to use safeParse on the JSON
result, and fall back to an empty object when the body is a string, array, or
otherwise invalid. Keep the fix localized to the response parsing logic so the
existing error flow continues through the same auth/signup functions.
In `@src/helpers/binary-upgrade.ts`:
- Around line 95-97: `fetchLatestGitHubVersion()` currently uses
`GitHubReleaseSchema.parse(...)`, which can throw and break the null-on-failure
contract; update the schema handling in this function to use `safeParse()`
instead, and return `null` when validation fails so the existing `upgrade.ts`
`if (!tag)` flow continues to handle bad responses gracefully. Keep the change
localized around `GitHubReleaseSchema` parsing and preserve the existing
`logDebug`/return behavior for valid responses.
In `@src/helpers/claude-settings.ts`:
- Around line 8-23: The whole-object validation in ClaudeSettingsSchema can
cause configureClaudeSettings to treat a partially invalid settings file as
empty and overwrite unrelated user data. Update the settings read/merge flow to
validate fields independently, or otherwise preserve the existing object when
agent or permissions fail validation, so existing custom keys and valid
permission entries are not discarded. Use ClaudeSettingsSchema,
ClaudePermissionsSchema, and the configureClaudeSettings merge logic to locate
the fix.
In `@src/helpers/opencode-settings.ts`:
- Around line 27-31: The whole-object safeParse flow in OpencodeConfigSchema
causes data loss when default_agent is invalid because the entire parsed object
is discarded and configureOpencodeSettings then rewrites opencode.json without
the user’s other passthrough keys. Update the parsing/merge logic in
configureOpencodeSettings to preserve the existing config object even when
default_agent fails validation, and only sanitize or drop the invalid
default_agent field while keeping all other keys intact.
In `@src/helpers/signup.ts`:
- Around line 70-72: `requestSignup()` currently uses `z.object(...).parse(...)`
on the response body, which can still throw for valid JSON with an invalid
`token` and break the `SignupResult` flow. Replace this parsing step with
`safeParse()` on the existing zod schema so the function handles malformed
`token` values gracefully and continues returning the expected `{ ok, token }`
shape without escaping errors.
In `@src/helpers/vscode-settings.ts`:
- Around line 16-20: The whole-object validation in VscodeSettingsSchema and
addMarketplaceToUserSettings can erase unrelated VS Code settings when parsing
fails. Change the flow so malformed or unexpected values for
"chat.plugins.marketplaces" do not reset the entire settings object; instead,
preserve the existing settings and only normalize/repair that single key before
writing. Use VscodeSettingsSchema, VscodeUserSettings, and
addMarketplaceToUserSettings as the main touchpoints, and keep passthrough
behavior so unrelated entries in settings.json are never dropped.
- Around line 152-156: The VS Code settings loader in the helper that reads
settingsPath should handle malformed JSONC the same way as the sibling helpers
do. Wrap the Bun.JSONC.parse/content read path in try/catch inside the existing
settings merge flow, and on parse or read failure leave existing as an empty
object so the merge remains additive and resilient. Use the symbols
VscodeSettingsSchema, Bun.JSONC.parse, and settingsPath to locate the fix.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 3f4e7bca-44fa-47e7-a11b-64bdee2be669
📒 Files selected for processing (25)
src/cli.tssrc/commands/adr/create.tssrc/commands/check.tssrc/engine/ast-support.tssrc/engine/reporter.tssrc/engine/rule-scanner.tssrc/engine/runner.tssrc/formats/adr.tssrc/formats/pack.tssrc/helpers/adr-writer.tssrc/helpers/auth.tssrc/helpers/binary-upgrade.tssrc/helpers/claude-settings.tssrc/helpers/opencode-settings.tssrc/helpers/project-config.tssrc/helpers/prompt.tssrc/helpers/repo-probe.tssrc/helpers/session-context-copilot.tssrc/helpers/session-context.tssrc/helpers/signup.tssrc/helpers/stack-detect.tssrc/helpers/telemetry-config.tssrc/helpers/vscode-settings.tstests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Smoke Test (Windows) / Windows
- GitHub Check: Cloudflare Pages
⚠️ CI failures not shown inline (4)
GitHub Actions: DCO / DCO Sign-off Check: refactor: remove all as type assertions from source code
Conclusion: failure
##[group]Run base="67d0e2ace0607873c32894f24c2d5e6c6bb13f1d"
�[36;1mbase="67d0e2ace0607873c32894f24c2d5e6c6bb13f1d"�[0m
�[36;1mhead="17fd8691cb78f93605b330398db67d9799712bdf"�[0m
�[36;1mfailed=0�[0m
�[36;1m�[0m
�[36;1mfor sha in $(git rev-list --no-merges "$base".."$head"); do�[0m
�[36;1m if ! git log -1 --format='%B' "$sha" | grep -qiE '^Signed-off-by: .+ <.+>'; then�[0m
�[36;1m echo "::error::Commit $sha is missing a DCO Signed-off-by line."�[0m
GitHub Actions: DCO / 0_DCO Sign-off Check.txt: refactor: remove all as type assertions from source code
Conclusion: failure
##[group]Run base="67d0e2ace0607873c32894f24c2d5e6c6bb13f1d"
�[36;1mbase="67d0e2ace0607873c32894f24c2d5e6c6bb13f1d"�[0m
�[36;1mhead="17fd8691cb78f93605b330398db67d9799712bdf"�[0m
�[36;1mfailed=0�[0m
�[36;1m�[0m
�[36;1mfor sha in $(git rev-list --no-merges "$base".."$head"); do�[0m
�[36;1m if ! git log -1 --format='%B' "$sha" | grep -qiE '^Signed-off-by: .+ <.+>'; then�[0m
�[36;1m echo "::error::Commit $sha is missing a DCO Signed-off-by line."�[0m
GitHub Actions: Code Quality: PR #459 / Analyze (go): Code Quality: PR #459
Conclusion: failure
,"bundleSupportsIncludeLogs":true,"bundleSupportsOverlay":true,"databaseInterpretResultsSupportsSarifRunProperty":true,"featuresInVersionResult":true,"indirectTracingSupportsStaticBinaries":false,"informsAboutUnsupportedPathFilters":true,"supportsPython312":true,"mrvaPackCreate":true,"threatModelOption":true,"traceCommandUseBuildMode":true,"v2ramSizing":true,"mrvaPackCreateMultipleQueries":true,"setsCodeqlRunnerEnvVar":true,"sarifMergeRunsFromEqualCategory":true,"forceOverwrite":true,"generateSummarySymbolMap":true,"pythonDefaultIsToNotExtractStdlib":true,"queryServerRunQueries":true,"queryServerTrimCacheWithMode":true,"builtinExtractorsSpecifyDefaultQueries":true,"bqrsDiffResultSets":true,"bundleSupportsIncludeOption":true,"suppressesMissingFileBaselineWarning":true}}}
CODEQL_ACTION_GO_BINARY: /home/runner/work/_temp/codeql-action-go-tracing/bin/go
CODEQL_RAM: 14575
CODEQL_THREADS: 4
CODEQL_PROXY_HOST:
CODEQL_PROXY_PORT:
CODEQL_PROXY_CA_CERTIFICATE:
CODEQL_PROXY_URLS:
##[endgroup]
##[group]Attempting to automatically build go code
[command]/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/codeql database trace-command --use-build-mode --working-dir /home/runner/work/cli/cli /home/runner/work/_temp/codeql_databases/go
Picked up JAVA_TOOL_OPTIONS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false
Running command in /home/runner/work/cli/cli: [/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/go/tools/autobuild.sh]
[] [build-stderr] 2026/07/07 00:48:45 Autobuilder was built with go1.26.0, environment has go1.24.13
[] [build-stderr] 2026/07/07 00:48:45 LGTM_SRC is /home/runner/work/cli/cli
[] [build-stderr] 2026/07/07 00:48:45 Found no go.work files in the workspace; looking for go.mod files...
[] [build-stderr] 2026/07/07 00:48:45 Found 1 go.mod files in: shims/go/go.mod.
[] [build-stderr] 2026/07/07 00:48:45 Found 1 go.mod file(s).
[] [build-stderr] 2026/07/07 00:48:45 Import path is 'github.com/archgate/cli'
[] [build-stderr] 2026/07/...
GitHub Actions: Code Quality: PR #459 / 1_Analyze (go).txt: Code Quality: PR #459
Conclusion: failure
xtracting types for package crypto/aes.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/aes.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/des.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/des.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/des.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Done extracting types for package crypto/ecdh.
[] [build-stderr] 2026/07/07 00:48:54 Processing package crypto/elliptic.
[] [build-stderr] 2026/07/07 00:48:54 Extracting types for package crypto/elliptic.
[] [build-std...
🧰 Additional context used
📓 Path-based instructions (13)
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests undertests/mirroring thesrc/directory structure with<module-name>.test.tsnaming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up inafterEachorafterAll.
Close external SDK instances (servers, clients, transports, connections) inafterEachorafterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runsgit commit, configure localuser.emailanduser.nameimmediately aftergit init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnabletest()/it()must contain at least oneexpect()assertion; smoke tests must make the contract explicit withexpect(() => fn()).not.toThrow()orawait expect(promise).resolves.toBeUndefined().
Usetest.skip,test.skipIf, ortest.todofor intentionally empty or disabled tests; do not use barereturnor empty callbacks to skip work.
If the firstexpect()is being added to a previously assertion-less test file, addexpectto thebun:testimport.
When mockingfetchin tests, assign directly toglobalThis.fetchand restore the original or usemock.restore()afterward.
WrapspyOn()and inlinemockImplementation()usage intry/finally, or create and restore spies in hooks, somockRestore()always runs.
Only raise a per-test timeout above the globalbun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules withimport * as modplusspyOn(mod, "fn"), notmock.module().
When a test needs to redirect user-scope paths, mockos.homedir()instead of relying onHOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...
Files:
tests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)
**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file,Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, useBun.file()instead offs.readFile()for simple reads.
Prefernode:built-in modules such asnode:util,node:path, andnode:fsover npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper likepick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; usebunxfor one-off tools.
Files:
tests/helpers/claude-settings.test.tssrc/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tstests/helpers/vscode-settings.test.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
tests/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
In test files, use
_resetPlatformCache()to simulate different platforms instead of mocking or mutatingprocess.platformdirectly.
Files:
tests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
{src,tests}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)
{src,tests}/**/*.ts: Every TypeScript source file insrc/andtests/must begin with// SPDX-License-Identifier: Apache-2.0followed by// Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example#!/usr/bin/env buninsrc/cli.ts), the SPDX license header must appear immediately after the shebang.
Use single-line//comments for the SPDX header; do not use block comments (/* */) or alternate license identifiers.
Files:
tests/helpers/claude-settings.test.tssrc/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tstests/helpers/vscode-settings.test.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
**
⚙️ CodeRabbit configuration file
**: # CLAUDE.mdArchgate is a CLI tool for AI governance via Architecture Decision Records (ADRs) — combining human-readable docs with machine-checkable rules. The CLI dogfoods itself via ADRs in
.archgate/adrs/. AI features are delivered as a Claude Code plugin (../plugins/claude-code), not via direct API calls.Technology Stack
- Runtime: Bun (>=1.2.21) — not Node.js compatible
- Language: TypeScript (strict mode, ESNext, ES modules)
- CLI framework: Commander.js (
@commander-js/extra-typings)- Linter: Oxlint | Formatter: Oxfmt | Dead exports: Knip | Commits: Conventional Commits
Commands
bun run src/cli.ts <command> # run CLI locally bun run lint # oxlint bun run typecheck # tsc --build bun run format # oxfmt --write bun run format:check # oxfmt --check bun run test # all tests (not bare `bun test` — picks up --timeout; see GEN-003) bun run knip # dead export detection bun run validate # MANDATORY: lint + typecheck + format:check + test + ADR check + knip + build check bun run build:check # verify build compiles (CI builds binaries via release workflow) bun run commit # conventional commit wizardValidation Gate
bun run validatemust pass before any task is considered complete. Fail-fast pipeline: lint → typecheck → format:check → test → ADR check → knip → build check. Mirrors CI in.github/workflows/code-pull-request.yml.Git Hooks (Git 2.54+)
Config-based hooks in
.githooksrun validation locally before commits and pushes:
- pre-commit: lint + typecheck + format:check (~15s)
- pre-push: full
bun run validate(~60s, mirrors CI)Activate once per clone:
git config --local include.path ../.githooksOpt out of a specific hook:
git config --local hook.<name>.enabled false. Skip all hooks for a single commit:git commit --no-verify.#...
Files:
tests/helpers/claude-settings.test.tssrc/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tstests/helpers/vscode-settings.test.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
⚙️ CodeRabbit configuration file
**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in.archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.tsfile with automated checks that run viaarchgate check.When reviewing, you must:
- Treat ADR violations as blocking issues, not suggestions.
- Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
- Focus on semantic and contextual violations that automated rules cannot catch —
the.rules.tsfiles already cover syntactic/structural patterns.- If you are unsure whether something violates an ADR, flag it as a question
rather than approving it.
Files:
tests/helpers/claude-settings.test.tssrc/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tstests/helpers/vscode-settings.test.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
src/commands/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-001-command-structure.md)
src/commands/**/*.ts: Each command module undersrc/commands/must export aregister*Command(program)function, with one command per file (or one command group viaindex.ts).
Command files must be thin: they should only parse arguments, call engine/helpers, and format output; business logic must live insrc/engine/,src/helpers/, orsrc/formats/.
Command modules must not useexecutableDir()for command discovery, must not call.parse()themselves, and must not spawn child processes for subcommand execution.
Subcommand groups should live in nested directories with anindex.tsthat composes child commands (for example,src/commands/adr/index.ts).
src/commands/**/*.ts: In command files undersrc/commands/**/*.ts, options that need type narrowing beyond plain strings MUST usenew Option()with.addOption()instead of plain.option().
Insrc/commands/**/*.ts, importOptionfrom@commander-js/extra-typingsalongsideCommandso typed options get full type inference.
Insrc/commands/**/*.ts, enum-like options with a fixed set of allowed values must use.choices()on anOptionto provide runtime validation and compile-time type narrowing.
Insrc/commands/**/*.ts, options that require type conversion must use.argParser()on anOptionobject, not a parser function passed as the third argument to.option().
Insrc/commands/**/*.ts, register typed options with.addOption()rather than.option().
Insrc/commands/**/*.ts, pass both the choices array and default values withas constwhen using.choices()and.default()to preserve literal types.
Insrc/commands/**/*.ts, do not add manual validation for choice options (for exampleif (!VALID.includes(val))), because Commander handles invalid-value rejection automatically.
src/commands/**/*.ts: Commands that operate on.archgate/project resources must usefindProjectRoot()fromsrc/helpers/paths.tsto locate the project root; direct use of `process.cw...
Files:
src/commands/adr/create.tssrc/commands/check.ts
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
src/**/*.ts: UselogError()fromsrc/helpers/log.tsfor user-facing errors instead of printing errors directly.
Exit with code1for expected failures such as missing config, invalid input, or validation violations.
Let unexpected errors crash naturally so they are treated as internal errors with exit code2.
Include actionable suggestions in user-facing error messages whenever possible.
Write user-facing errors to stderr vialogError(); do not send them to stdout.
WhenfindProjectRoot()returnsnullfor commands that do not require.archgate/, fall back toprocess.cwd()as the path key or working directory.
CatchExitPromptErrorfrom Inquirer in the top-level error boundary and treat it as user cancellation: exit with code130without logging an error or sending it to Sentry.
Do not useconsole.error()directly; uselogError()for consistent formatting.
Do not exit with codes other than0,1,2, or130.
Do not send user-cancellation errors such as InquirerExitPromptErrorto Sentry; filter them inbeforeSend.
src/**/*.ts: UsestyleText(format, text)fromnode:utilfor all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support--jsonmust emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports--json, useformatJSON()fromsrc/helpers/output.tsfor JSON serialization, and passforcePretty: truewhen the user explicitly provided--json.
UseisAgentContext()fromsrc/helpers/output.tsto enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout withconsole.log(), and send errors, warnings, and debug messages to stderr vialogError(),logWarn(), andlogDebug().
Keep CLI output concise and scannabl...
Files:
src/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
src/**/!(*platform).ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
src/**/!(*platform).ts: Insrc/TypeScript source files, do not readprocess.platformdirectly; usesrc/helpers/platform.ts(isWindows(),isMacOS(),isLinux(),isWSL(),getPlatformInfo()) for all platform detection.
Use the centralized platform helper instead of duplicating OS/WSL detection logic inline anywhere insrc/TypeScript source.
When behavior differs between Linux and Windows, account for WSL by usingisWSL()rather than assuming `
Files:
src/commands/adr/create.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/commands/check.tssrc/helpers/adr-writer.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/formats/adr.tssrc/helpers/signup.tssrc/cli.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
src/{helpers,engine}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
Do not use
console.log(),console.warn(), orconsole.info()directly in helper or engine files; uselogInfo()orlogWarn()instead. Command files are exempt because they are the I/O layer.
Files:
src/helpers/opencode-settings.tssrc/helpers/adr-writer.tssrc/engine/ast-support.tssrc/helpers/prompt.tssrc/helpers/signup.tssrc/helpers/binary-upgrade.tssrc/engine/reporter.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/engine/rule-scanner.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/engine/runner.tssrc/helpers/telemetry-config.ts
src/formats/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Zod schemas are the single source of truth; derive types with
z.infer<>, do not define separate interfaces, usesafeParse(), and reuseAdrFrontmatterSchema.shape.*instead of duplicating enums.
Files:
src/formats/pack.tssrc/formats/adr.ts
src/commands/{*.ts,*/index.ts}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-015-cli-command-documentation-coverage.md)
Every top-level CLI command registered via
register*Command(program)must live insrc/commands/<name>.tsorsrc/commands/<name>/index.tsso it can be matched to a docs page.
Files:
src/commands/check.ts
{src/commands/{*.ts,*/index.ts},docs/src/content/docs/reference/cli/!(index).mdx}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-015-cli-command-documentation-coverage.md)
{src/commands/{*.ts,*/index.ts},docs/src/content/docs/reference/cli/!(index).mdx}: When a top-level command is added, its docs page must be added in the same change; when a top-level command is removed, its matching docs page must be deleted in the same change.
Keep command and documentation stems aligned when renaming a top-level command file; renamingsrc/commands/<name>.tsorsrc/commands/<name>/index.tsmust be paired with renamingdocs/src/content/docs/reference/cli/<name>.mdx.
Files:
src/commands/check.ts
src/cli.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-001-command-structure.md)
src/cli.ts: The main entry point must explicitly import and register every command; no auto-discovery is allowed.
All async bootstrap logic insrc/cli.tsmust be wrapped in an asyncmain()function and invoked withmain().catch((err) => { logError(String(err)); process.exit(2); }); top-level await is forbidden.
The CLI must run in-process in the same Bun process as the entry point; command execution should not rely on child processes.
Files:
src/cli.ts
🧠 Learnings (1)
📚 Learning: 2026-07-02T16:03:33.031Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 446
File: src/helpers/session-context-opencode.ts:81-100
Timestamp: 2026-07-02T16:03:33.031Z
Learning: For synchronous helper functions that use Bun’s sqlite sync API (i.e., they must remain synchronous), it’s acceptable to use `existsSync` from `node:fs` to check whether the SQLite database file exists. Avoid using `Bun.file(path).exists()` for this purpose because it’s async and would force the helper to become async (no equivalent synchronous Bun alternative). If the DB file is missing, throw/return a clear, actionable "No database found" error (per ARCH-006) rather than letting the sqlite open fail with a generic DB-open error.
Applied to files:
src/helpers/opencode-settings.tssrc/helpers/adr-writer.tssrc/helpers/prompt.tssrc/helpers/signup.tssrc/helpers/binary-upgrade.tssrc/helpers/stack-detect.tssrc/helpers/session-context-copilot.tssrc/helpers/vscode-settings.tssrc/helpers/auth.tssrc/helpers/repo-probe.tssrc/helpers/session-context.tssrc/helpers/claude-settings.tssrc/helpers/project-config.tssrc/helpers/telemetry-config.ts
🔇 Additional comments (30)
src/engine/ast-support.ts (1)
192-204: Cast removal is a no-op here — same lack of validation as before.
JSON.parse(stdout)can technically return a scalar (not the declaredRecord<string, unknown> | unknown[]), but this was equally true with the previous cast. No new risk introduced by this change; flagging only as an observation, not a regression.src/cli.ts (1)
4-8: LGTM!Also applies to: 31-31, 118-140, 176-188
src/commands/adr/create.ts (1)
88-88: LGTM!src/commands/check.ts (1)
23-26: LGTM!Also applies to: 171-171
src/engine/reporter.ts (1)
179-194: LGTM!Also applies to: 315-331
src/engine/runner.ts (1)
163-252: LGTM! Verified against ARCH-022's four-guardrail ordering, sharedparseJsModulereuse, isolated-mode Python invocation, and the single-doorast: astImplcontract — all preserved.src/engine/rule-scanner.ts (2)
124-252: Faithful mechanical refactor — behavior preserved.Cast-based property access replaced with type-guard helpers (
childNode/strProp/boolProp); every violation condition and message text is unchanged.Also applies to: 315-388
36-61: 🎯 Functional CorrectnessNo issue:
AstNodealready has an index signature, sonode[key]is valid here.> Likely an incorrect or invalid review comment.src/formats/adr.ts (1)
60-68: LGTM!src/helpers/adr-writer.ts (1)
94-101: LGTM!src/helpers/auth.ts (2)
35-60: LGTM!
86-86: LGTM!Also applies to: 129-129, 183-183, 226-226
src/helpers/telemetry-config.ts (2)
26-33: LGTM!
88-100: 🎯 Functional Correctness
JSON.parse(readFileSync(...))conflicts with the Bun JSON-read guideline — likely an intentional sync exception.The coding guidelines require
await Bun.file(path).json()for JSON reads and explicitly forbidJSON.parse(fs.readFileSync(path, "utf-8")). This function is deliberately synchronous ("Synchronous read for startup-path performance"), and Bun has no synchronous equivalent toBun.file().json(), soreadFileSync+JSON.parseappears to be the only viable option here — similar to the previously-accepted exception for usingexistsSyncin sync-constrained helpers.Worth confirming this is an intentional, accepted exception to the "no JSON.parse+readFileSync" guideline rather than an oversight, since the rule has no explicit carve-out for sync-only code paths.
Based on learnings, sync-only helper constraints can justify deviating from the async-preferred pattern (as previously accepted for
existsSyncin a synchronous helper), and per coding guidelines "Useawait Bun.file(path).json()when reading JSON files in Bun TypeScript source code; do not use ...JSON.parse(fs.readFileSync(path, "utf-8"))for file reads."Sources: Coding guidelines, Learnings
src/helpers/stack-detect.ts (1)
29-42: LGTM!src/helpers/binary-upgrade.ts (1)
175-178: LGTM!src/helpers/claude-settings.ts (1)
65-66: LGTM!tests/helpers/claude-settings.test.ts (1)
73-79: LGTM!src/helpers/vscode-settings.ts (1)
55-55: LGTM!tests/helpers/vscode-settings.test.ts (1)
70-79: LGTM!src/helpers/project-config.ts (2)
17-17: LGTM!Also applies to: 147-148, 159-167, 196-203
43-59: 🎯 Functional CorrectnessNo action here —
loadProjectConfig()is still a synchronous helper used by other synchronous readers (getMergedDomainPrefixes(),resolveDomainPrefix(),getConfiguredBaseBranch(),listDomainEntries()), so moving it toBun.file().json()would require a broader async refactor outside this change.> Likely an incorrect or invalid review comment.src/helpers/prompt.ts (2)
83-97: LGTM!
112-125: 📐 Maintainability & Code QualityKeep the suppression. Oxlint accepts
// eslint-disable-next-line@typescript-eslint/no-explicit-any``, so this isn’t a lint issue here.unknown[]is optional cleanup, not required.> Likely an incorrect or invalid review comment.src/helpers/repo-probe.ts (1)
19-30: LGTM!Also applies to: 76-76, 120-140, 142-160, 162-179, 190-213
src/helpers/session-context.ts (3)
7-8: LGTM!
101-129: LGTM!
55-63: 🩺 Stability & AvailabilityNo change needed here.
TranscriptEntrySchemais used behind a hard-fail JSONL parse, and the other session readers follow the same pattern. Filtering invalid entries or switching tonullish()would change the current error behavior rather than fix a regression.> Likely an incorrect or invalid review comment.src/helpers/session-context-copilot.ts (2)
6-7: LGTM!Also applies to: 18-26, 118-120, 211-212
192-195: 🩺 Stability & AvailabilityNo issue here.
events.jsonlalready falls back to the generic transcript error, and the malformed-file case is covered; thesafeParsechange isn’t needed.> Likely an incorrect or invalid review comment.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_318df59e-47dc-44e5-b638-f55296b33d34) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_1ac8c139-f860-476f-81cc-918de9de4ed8) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_8a25750c-16ac-4dcf-b651-a756aacd3504) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_135dc3b8-06a5-4108-b5cc-ca6895f4794e) |
Replace every `as Type` assertion in src/ with type-safe alternatives:
- HTTP responses: Zod schemas (auth, repo-probe, binary-upgrade, signup)
- Config files: typed Zod schemas with .passthrough() for read-modify-write
(claude-settings, vscode-settings, opencode-settings)
- Session data: Zod array/object schemas (session-context, session-context-copilot)
- AST walking: type guard functions — isAstNode(), childNode(), strProp(),
boolProp() (rule-scanner)
- Function overloads: Promise<any> return type for implementation (runner)
- Function patching: Proxy with apply/get traps (prompt)
- Commander options: proper type narrowing, typed return (cli, check, reporter)
- Property access: type-safe alternatives — .some(), Object.entries(),
Object.fromEntries() (project-config, adr-writer, stack-detect)
- Telemetry config: Zod schema replacing manual field checks
Zero `as Type` assertions remain in src/. Only `as const` (safe literal
narrowing) and `import { X as Y }` (renaming) remain.
Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
- project-config: pass JSON.parse directly to safeParse, no intermediate - pack: pass YAML.parse directly to Zod .parse(), no intermediate - stack-detect: let spread result type be inferred - session-context: use `in` narrowing instead of annotated Record cast Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
- cli: use CommandUnknownOpts from Commander instead of custom CommandLike interface - reporter: use `as const` on ternary branches instead of explicit type annotation for sevColor Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
…annotation Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Use Object.entries().find() instead of widening DOMAIN_PREFIXES to Record<string, string | undefined> for string key indexing. Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Replace isAstNode/childNode/strProp/boolProp type guard functions with a recursive AstNodeSchema Zod schema. The schema validates node structure including type, name, value, computed, and recursive child fields (source, object, property, callee, left). The value field accepts both literals and child nodes (Property.value can be an ObjectExpression). Walk functions now access typed fields directly from the schema-validated node instead of manual property extraction. Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
- cli: remove redundant type annotation on `current` variable - runner: replace Promise<any> with overloaded function declaration matching RuleContext["ast"] signatures — no any or as needed - adr: use Zod PlainObjectSchema instead of manual isPlainObject guard - pack: use safeParse + UserError (matching parseAdr pattern) - auth: use safeParse for error body to handle non-object JSON - binary-upgrade: use safeParse to preserve null-on-failure contract - signup: use safeParse for response validation - claude/vscode/opencode settings: add .catch(undefined) on schema fields to prevent whole-object wipe when a single field is invalid - vscode-settings: wrap JSONC parse in try/catch for corrupted files - session-context: use discriminated union schema for content blocks (text/tool_use/tool_result) — replaces manual in-checks - stack-detect: use PackageJsonSchema with typed deps/devDeps fields - ARCH-022 rule: add FunctionDeclaration case for overloaded astImpl Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Address review feedback: set defaults in Zod schemas instead of using
?? at consumer sites.
- session-context: type/role default to "" via schema, removing ?? ""
and non-null assertions (!) from consumers
- session-context-copilot: event type defaults to "" via schema
- auth: email defaults to null via .nullable().default(null)
- signup: token defaults to null via .nullable().default(null)
- claude-settings: permissions.allow/deny default to [] via schema,
catch invalid permissions to { allow: [], deny: [] }
- vscode-settings: catch invalid marketplaces to []
- Add regression tests for invalid-data graceful handling through
schema .catch() (claude-settings, vscode-settings)
Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
985c4a5 to
60b414a
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_721ebbe0-f96d-404a-b161-da5dec1ad67e) |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
tests/helpers/claude-settings.test.ts (1)
10-93: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winTest coverage doesn't exercise a malformed (non-string)
agentfield.Given the
"agent" in mergedbehavior flagged insrc/helpers/claude-settings.ts(lines 15-23), a test likemergeClaudeSettings(parse({ agent: 123 }), ARCHGATE_CLAUDE_SETTINGS)would have caught that the archgate default agent is silently skipped whenagentis present but invalid. Consider adding this case alongside the existing "handles non-object permissions gracefully" test once the source-side fix lands.🤖 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/helpers/claude-settings.test.ts` around lines 10 - 93, Add a test case in claude-settings.test.ts for a malformed agent value, using mergeClaudeSettings and parse to cover something like a non-string agent input. This should verify that ClaudeSettingsSchema/mergeClaudeSettings do not let an invalid agent presence block the archgate default from being applied, alongside the existing non-object permissions coverage. Reference the mergeClaudeSettings behavior around the "agent" in merged check so the test fails until the source fix lands.src/helpers/session-context-copilot.ts (1)
195-198: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winWhole-transcript data loss on a single malformed event.
CopilotEventsSchema.parse(...)hard-fails the entire array if even one entry doesn't matchCopilotEventSchema(e.g.datapresent but not an object). The catch block then reports "Session exists but has no conversation transcript" for the whole session, even though only one event was malformed. Contrast with lines 214-215 just below, where individualcontentvalues are validated withsafeParseand fall back gracefully — the same graceful-degradation pattern should apply at the event level.🐛 Proposed fix
- let rawEntries: z.infer<typeof CopilotEventsSchema>; + let rawEntries: z.infer<typeof CopilotEventSchema>[]; try { const raw = await Bun.file(eventsFile).text(); - rawEntries = CopilotEventsSchema.parse(Bun.JSONL.parse(raw)); + const parsed = Bun.JSONL.parse(raw); + rawEntries = Array.isArray(parsed) + ? parsed + .map((e) => CopilotEventSchema.safeParse(e)) + .filter((r) => r.success) + .map((r) => r.data) + : []; } catch {🤖 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/helpers/session-context-copilot.ts` around lines 195 - 198, The transcript load in session-context-copilot is too strict because CopilotEventsSchema.parse() fails the entire session on one malformed event. Update the event parsing around the rawEntries assignment to validate each parsed JSONL entry individually, using a safeParse-style fallback like the content validation below, so one bad CopilotEventSchema item is skipped or sanitized instead of discarding the whole transcript.src/helpers/auth.ts (1)
86-86: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winRemaining raw
.parse()calls on external HTTP responses can crash with exit code 2 instead of a gracefulUserError.Unlike the
ErrorResponseSchema.safeParse(...)fix applied at lines 213-216 in this same file,DeviceCodeResponseSchema.parse(...)(86),DeviceTokenResponseSchema.parse(...)(129),GitHubUserSchema.parse(...)(183), andTokenResponseSchema.parse(...)(227) still use.parse(). If GitHub or the plugins service ever returns a shape these schemas don't cover (e.g. an additional device-flow error code likeslow_downduring polling, or a malformed 200 response), the thrownZodErrorpropagates uncaught — bypassingUserError/exit-code-1 handling and surfacing as an unexpected internal error (exit 2) instead of an expected external-call failure.For consistency with the already-fixed error path in this file, convert these to
safeParse()and throw aUserError(or handle gracefully) on failure.As per coding guidelines: "Exit with code
1for expected failures such as missing config, invalid input, or validation violations" and "Let unexpected errors crash naturally so they are treated as internal errors with exit code2" — a malformed external API response is an expected-failure case, not an internal bug.Also applies to: 129-129, 183-183, 227-227
🤖 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/helpers/auth.ts` at line 86, The remaining external-response validations in auth helpers still use direct schema parsing, which can throw uncaught validation errors instead of a graceful UserError. Update the response handling in DeviceCodeResponseSchema.parse, DeviceTokenResponseSchema.parse, GitHubUserSchema.parse, and TokenResponseSchema.parse to use safeParse and explicitly convert failures into a handled UserError (or equivalent expected-failure path), matching the existing ErrorResponseSchema safeParse pattern in src/helpers/auth.ts.Source: Coding guidelines
🤖 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 `@src/formats/pack.ts`:
- Around line 5-6: The Zod error formatting logic in pack.ts duplicates the same
path-to-message mapping already used in adr.ts, so extract that formatter into a
shared helper and reuse it from both places. Update the validation error
handling in the pack formatting flow to call the shared helper instead of
building the message inline, keeping the formatter behavior consistent across
Pack and ADR.
In `@src/helpers/claude-settings.ts`:
- Around line 15-23: The archgate default check for ClaudeSettingsSchema.agent
currently uses an in-operator presence test, which fails when agent is present
but parsed to undefined by ClaudeSettingsSchema. Update the merge logic that
reads from merged to use a nullish check on merged.agent instead of checking key
presence, so invalid or missing values are handled consistently and the default
is applied when agent is undefined.
In `@src/helpers/session-context.ts`:
- Around line 55-75: `ContentBlockSchema` is too restrictive and causes
`TranscriptEntrySchema` to reject newer Anthropic transcript blocks. Update the
discriminated union in `session-context.ts` to accept the additional block types
used by current Claude sessions, or add a safe fallback that preserves unknown
blocks instead of failing validation. Keep the fix centered around
`ContentBlockSchema`, `MessageContentSchema`, and the session reader path that
parses JSONL so unreadable transcripts no longer fall back to "Failed to read
session file".
---
Outside diff comments:
In `@src/helpers/auth.ts`:
- Line 86: The remaining external-response validations in auth helpers still use
direct schema parsing, which can throw uncaught validation errors instead of a
graceful UserError. Update the response handling in
DeviceCodeResponseSchema.parse, DeviceTokenResponseSchema.parse,
GitHubUserSchema.parse, and TokenResponseSchema.parse to use safeParse and
explicitly convert failures into a handled UserError (or equivalent
expected-failure path), matching the existing ErrorResponseSchema safeParse
pattern in src/helpers/auth.ts.
In `@src/helpers/session-context-copilot.ts`:
- Around line 195-198: The transcript load in session-context-copilot is too
strict because CopilotEventsSchema.parse() fails the entire session on one
malformed event. Update the event parsing around the rawEntries assignment to
validate each parsed JSONL entry individually, using a safeParse-style fallback
like the content validation below, so one bad CopilotEventSchema item is skipped
or sanitized instead of discarding the whole transcript.
In `@tests/helpers/claude-settings.test.ts`:
- Around line 10-93: Add a test case in claude-settings.test.ts for a malformed
agent value, using mergeClaudeSettings and parse to cover something like a
non-string agent input. This should verify that
ClaudeSettingsSchema/mergeClaudeSettings do not let an invalid agent presence
block the archgate default from being applied, alongside the existing non-object
permissions coverage. Reference the mergeClaudeSettings behavior around the
"agent" in merged check so the test fails until the source fix lands.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 20cf7437-559b-4a04-b8d1-1f0f0fd6fd69
📒 Files selected for processing (18)
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.tssrc/cli.tssrc/engine/rule-scanner.tssrc/engine/runner.tssrc/formats/adr.tssrc/formats/pack.tssrc/helpers/auth.tssrc/helpers/binary-upgrade.tssrc/helpers/claude-settings.tssrc/helpers/opencode-settings.tssrc/helpers/session-context-copilot.tssrc/helpers/session-context-opencode.tssrc/helpers/session-context.tssrc/helpers/signup.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tstests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Cloudflare Pages
⚠️ CI failures not shown inline (2)
GitHub Actions: Code Quality: PR #459 / Analyze (go): Code Quality: PR #459
Conclusion: failure
,"bundleSupportsIncludeLogs":true,"bundleSupportsOverlay":true,"databaseInterpretResultsSupportsSarifRunProperty":true,"featuresInVersionResult":true,"indirectTracingSupportsStaticBinaries":false,"informsAboutUnsupportedPathFilters":true,"supportsPython312":true,"mrvaPackCreate":true,"threatModelOption":true,"traceCommandUseBuildMode":true,"v2ramSizing":true,"mrvaPackCreateMultipleQueries":true,"setsCodeqlRunnerEnvVar":true,"sarifMergeRunsFromEqualCategory":true,"forceOverwrite":true,"generateSummarySymbolMap":true,"pythonDefaultIsToNotExtractStdlib":true,"queryServerRunQueries":true,"queryServerTrimCacheWithMode":true,"builtinExtractorsSpecifyDefaultQueries":true,"bqrsDiffResultSets":true,"bundleSupportsIncludeOption":true,"suppressesMissingFileBaselineWarning":true}}}
CODEQL_ACTION_GO_BINARY: /home/runner/work/_temp/codeql-action-go-tracing/bin/go
CODEQL_RAM: 14575
CODEQL_THREADS: 4
CODEQL_PROXY_HOST:
CODEQL_PROXY_PORT:
CODEQL_PROXY_CA_CERTIFICATE:
CODEQL_PROXY_URLS:
##[endgroup]
##[group]Attempting to automatically build go code
[command]/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/codeql database trace-command --use-build-mode --working-dir /home/runner/work/cli/cli /home/runner/work/_temp/codeql_databases/go
Picked up JAVA_TOOL_OPTIONS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false
Running command in /home/runner/work/cli/cli: [/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/go/tools/autobuild.sh]
[] [build-stderr] 2026/07/07 08:46:07 Autobuilder was built with go1.26.0, environment has go1.24.13
[] [build-stderr] 2026/07/07 08:46:07 LGTM_SRC is /home/runner/work/cli/cli
[] [build-stderr] 2026/07/07 08:46:07 Found no go.work files in the workspace; looking for go.mod files...
[] [build-stderr] 2026/07/07 08:46:07 Found 1 go.mod files in: shims/go/go.mod.
[] [build-stderr] 2026/07/07 08:46:07 Found 1 go.mod file(s).
[] [build-stderr] 2026/07/07 08:46:07 Import path is 'github.com/archgate/cli'
[] [build-stderr] 2026/07/...
GitHub Actions: Code Quality: PR #459 / 2_Analyze (go).txt: Code Quality: PR #459
Conclusion: failure
6 Extracting types for package crypto/aes.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/aes.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/des.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/des.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/des.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/internal/fips140/nistec/fiat.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/internal/fips140/nistec.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/internal/fips140/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/internal/fips140/edwards25519/field.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Done extracting types for package crypto/ecdh.
[] [build-stderr] 2026/07/07 08:46:16 Processing package crypto/elliptic.
[] [build-stderr] 2026/07/07 08:46:16 Extracting types for package crypto/elliptic.
[] [build-...
🧰 Additional context used
📓 Path-based instructions (13)
tests/**/*.test.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-005-testing-standards.md)
tests/**/*.test.ts: Use Bun's built-in test runner (bun:test) for all test files, and place tests undertests/mirroring thesrc/directory structure with<module-name>.test.tsnaming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up inafterEachorafterAll.
Close external SDK instances (servers, clients, transports, connections) inafterEachorafterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runsgit commit, configure localuser.emailanduser.nameimmediately aftergit init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnabletest()/it()must contain at least oneexpect()assertion; smoke tests must make the contract explicit withexpect(() => fn()).not.toThrow()orawait expect(promise).resolves.toBeUndefined().
Usetest.skip,test.skipIf, ortest.todofor intentionally empty or disabled tests; do not use barereturnor empty callbacks to skip work.
If the firstexpect()is being added to a previously assertion-less test file, addexpectto thebun:testimport.
When mockingfetchin tests, assign directly toglobalThis.fetchand restore the original or usemock.restore()afterward.
WrapspyOn()and inlinemockImplementation()usage intry/finally, or create and restore spies in hooks, somockRestore()always runs.
Only raise a per-test timeout above the globalbun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules withimport * as modplusspyOn(mod, "fn"), notmock.module().
When a test needs to redirect user-scope paths, mockos.homedir()instead of relying onHOME/Bun.env.HOME; restore the spy in test hooks.
Do not depend on network access in unit tests.
Do not leave temp files after test runs.
Do not leave external SDK instances open after tests...
Files:
tests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
**/*.{ts,tsx,js,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-006-dependency-policy.md)
**/*.{ts,tsx,js,jsx,mjs,cjs}: Use Bun built-ins for file I/O (Bun.file,Bun.write), HTTP, subprocess execution (Bun.spawn), globbing (Bun.Glob), and testing (bun:test).
Do not use Node.js-specific APIs when Bun alternatives exist; for example, useBun.file()instead offs.readFile()for simple reads.
Prefernode:built-in modules such asnode:util,node:path, andnode:fsover npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper likepick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; usebunxfor one-off tools.
Files:
tests/helpers/claude-settings.test.tssrc/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tstests/helpers/vscode-settings.test.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
tests/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
In test files, use
_resetPlatformCache()to simulate different platforms instead of mocking or mutatingprocess.platformdirectly.
Files:
tests/helpers/claude-settings.test.tstests/helpers/vscode-settings.test.ts
{src,tests}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)
{src,tests}/**/*.ts: Every TypeScript source file insrc/andtests/must begin with// SPDX-License-Identifier: Apache-2.0followed by// Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example#!/usr/bin/env buninsrc/cli.ts), the SPDX license header must appear immediately after the shebang.
Use single-line//comments for the SPDX header; do not use block comments (/* */) or alternate license identifiers.
Files:
tests/helpers/claude-settings.test.tssrc/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tstests/helpers/vscode-settings.test.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
**
⚙️ CodeRabbit configuration file
**: # CLAUDE.mdArchgate is a CLI tool for AI governance via Architecture Decision Records (ADRs) — combining human-readable docs with machine-checkable rules. The CLI dogfoods itself via ADRs in
.archgate/adrs/. AI features are delivered as a Claude Code plugin (../plugins/claude-code), not via direct API calls.Technology Stack
- Runtime: Bun (>=1.2.21) — not Node.js compatible
- Language: TypeScript (strict mode, ESNext, ES modules)
- CLI framework: Commander.js (
@commander-js/extra-typings)- Linter: Oxlint | Formatter: Oxfmt | Dead exports: Knip | Commits: Conventional Commits
Commands
bun run src/cli.ts <command> # run CLI locally bun run lint # oxlint bun run typecheck # tsc --build bun run format # oxfmt --write bun run format:check # oxfmt --check bun run test # all tests (not bare `bun test` — picks up --timeout; see GEN-003) bun run knip # dead export detection bun run validate # MANDATORY: lint + typecheck + format:check + test + ADR check + knip + build check bun run build:check # verify build compiles (CI builds binaries via release workflow) bun run commit # conventional commit wizardValidation Gate
bun run validatemust pass before any task is considered complete. Fail-fast pipeline: lint → typecheck → format:check → test → ADR check → knip → build check. Mirrors CI in.github/workflows/code-pull-request.yml.Git Hooks (Git 2.54+)
Config-based hooks in
.githooksrun validation locally before commits and pushes:
- pre-commit: lint + typecheck + format:check (~15s)
- pre-push: full
bun run validate(~60s, mirrors CI)Activate once per clone:
git config --local include.path ../.githooksOpt out of a specific hook:
git config --local hook.<name>.enabled false. Skip all hooks for a single commit:git commit --no-verify.#...
Files:
tests/helpers/claude-settings.test.tssrc/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tstests/helpers/vscode-settings.test.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
⚙️ CodeRabbit configuration file
**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in.archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.tsfile with automated checks that run viaarchgate check.When reviewing, you must:
- Treat ADR violations as blocking issues, not suggestions.
- Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
- Focus on semantic and contextual violations that automated rules cannot catch —
the.rules.tsfiles already cover syntactic/structural patterns.- If you are unsure whether something violates an ADR, flag it as a question
rather than approving it.
Files:
tests/helpers/claude-settings.test.tssrc/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tstests/helpers/vscode-settings.test.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
.archgate/adrs/**
⚙️ CodeRabbit configuration file
.archgate/adrs/**: ---
id: ARCH-001
title: Command Structure
domain: architecture
rules: true
files: ["src/commands/**/*.ts"]Context
The CLI needs a consistent pattern for defining and registering commands. As the command surface grows (init, check, adr, review-context, session-context, upgrade, clean), the registration mechanism must scale without introducing hidden coupling or making the dependency graph opaque.
Alternatives considered:
- Auto-discovery via
executableDir()— Commander.js supports automatic command discovery by scanning a directory for executable files. This eliminates manual imports but hides the dependency graph: adding or removing a command has no type-checked reference, making dead command detection impossible. It also requires each command to be a standalone executable, which prevents in-process testing and forces separate process spawning for every subcommand invocation.- Plugin-based registration — A plugin system where commands register themselves via a manifest or hook (similar to Oclif or Clipanion). This adds flexibility for third-party extensions but introduces significant complexity for an internal CLI with a known, finite set of commands. The indirection makes it harder to trace which code handles which command.
- Single-file command map — Define all commands in a single file as a map of name-to-handler. Simple but creates a monolithic file that grows with every command, making merge conflicts frequent and readability poor.
The explicit register pattern strikes the right balance: each command owns its registration logic, the entry point makes all commands visible at a glance, and in-process execution enables straightforward testing without process spawning.
Decision
Commands live in src/commands/ and export a register*Command(program) function. The main entry point (src/cli.ts) explicitly imports and calls each register function. Subcommands (e.g., adr create, adr list) use nested directories wi...
Files:
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
src/cli.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-001-command-structure.md)
src/cli.ts: The main entry point must explicitly import and register every command; no auto-discovery is allowed.
All async bootstrap logic insrc/cli.tsmust be wrapped in an asyncmain()function and invoked withmain().catch((err) => { logError(String(err)); process.exit(2); }); top-level await is forbidden.
The CLI must run in-process in the same Bun process as the entry point; command execution should not rely on child processes.The CLI entry point must be
src/cli.tsand use the#!/usr/bin/env bunshebang.
Files:
src/cli.ts
src/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
src/**/*.ts: UselogError()fromsrc/helpers/log.tsfor user-facing errors instead of printing errors directly.
Exit with code1for expected failures such as missing config, invalid input, or validation violations.
Let unexpected errors crash naturally so they are treated as internal errors with exit code2.
Include actionable suggestions in user-facing error messages whenever possible.
Write user-facing errors to stderr vialogError(); do not send them to stdout.
WhenfindProjectRoot()returnsnullfor commands that do not require.archgate/, fall back toprocess.cwd()as the path key or working directory.
CatchExitPromptErrorfrom Inquirer in the top-level error boundary and treat it as user cancellation: exit with code130without logging an error or sending it to Sentry.
Do not useconsole.error()directly; uselogError()for consistent formatting.
Do not exit with codes other than0,1,2, or130.
Do not send user-cancellation errors such as InquirerExitPromptErrorto Sentry; filter them inbeforeSend.
src/**/*.ts: UsestyleText(format, text)fromnode:utilfor all terminal colors and formatting in CLI source files; do not use raw ANSI escape codes or third-party color libraries.
Commands that produce structured results and support--jsonmust emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports--json, useformatJSON()fromsrc/helpers/output.tsfor JSON serialization, and passforcePretty: truewhen the user explicitly provided--json.
UseisAgentContext()fromsrc/helpers/output.tsto enable auto-JSON behavior for commands that support both human-readable and JSON output modes.
CLI output must not include emoji; use text symbols and colors instead.
Send normal command output to stdout withconsole.log(), and send errors, warnings, and debug messages to stderr vialogError(),logWarn(), andlogDebug().
Keep CLI output concise and scannabl...
Files:
src/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
src/**/!(*platform).ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)
src/**/!(*platform).ts: Insrc/TypeScript source files, do not readprocess.platformdirectly; usesrc/helpers/platform.ts(isWindows(),isMacOS(),isLinux(),isWSL(),getPlatformInfo()) for all platform detection.
Use the centralized platform helper instead of duplicating OS/WSL detection logic inline anywhere insrc/TypeScript source.
When behavior differs between Linux and Windows, account for WSL by usingisWSL()rather than assuming `
Files:
src/cli.tssrc/helpers/opencode-settings.tssrc/formats/pack.tssrc/helpers/binary-upgrade.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/formats/adr.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
src/{helpers,engine}/**/*.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)
Do not use
console.log(),console.warn(), orconsole.info()directly in helper or engine files; uselogInfo()orlogWarn()instead. Command files are exempt because they are the I/O layer.
Files:
src/helpers/opencode-settings.tssrc/helpers/binary-upgrade.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/engine/runner.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.tssrc/engine/rule-scanner.ts
src/formats/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use Zod schemas as the single source of truth; derive types with
z.infer<>instead of defining separate interfaces, usesafeParse(), and reuseAdrFrontmatterSchema.shape.*to avoid duplicating enums.
Files:
src/formats/pack.tssrc/formats/adr.ts
src/engine/runner.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/runner.ts: Implementctx.ast(path, language)insidecreateRuleContext()with all dispatch hidden from rule authors.
Forlanguage: "typescript"and"javascript",ctx.ast()must reuse the existing in-processmeriyahparser; no subprocess may be spawned for these branches.
Factor the duplicatedparseModule()logic into a shared helper that is used by bothrule-scanner.tsand thectx.ast()TypeScript/JavaScript branch.
Forlanguage: "python"and"ruby",ctx.ast()must useBun.spawnwith array-based arguments only, with no shell interpolation.
Before any Python/Ruby interpreter is invoked,ctx.ast()must run the guardrail sequence in order: path safety, language plausibility check, interpreter availability probe, then guarded invocation.
ctx.ast()must use the samesafePath()sandboxing asreadFile/globbefore accessing a target file.
ctx.ast()must reject files whose extension and/or leading content do not plausibly match the requested language before running an interpreter.
ctx.ast()must probe interpreter availability once percheckinvocation, cache the result, and reuse the first working candidate executable name.
On Windows, the interpreter probe must consider platform-appropriate candidates in order (includingpyviaisWindows()); on non-Windows, it must use the non-Windows candidate order.
The Python branch must run in isolated mode (python -I -c ...) to prevent the working directory from shadowing standard-library imports.
The Python and Ruby serializers must strip a leading UTF-8 BOM before parsing.
ctx.ast()must throw on missing interpreter or parse failure, and must not returnnullor any other sentinel value.
The thrown error messages fromctx.ast()must distinguish interpreter-unavailable failures from parse-failure errors.
ctx.ast()must not exposeBun.spawn,child_process, or any other raw subprocess primitive onRuleContext; it is the only sanctioned tooling entrypoint.
`ctx.ast(...
Files:
src/engine/runner.ts
src/engine/rule-scanner.ts
📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)
src/engine/rule-scanner.ts: Keeprule-scanner.tsusing the sharedparseModule()helper instead of duplicating the parser call inline again.
rule-scanner.tsmust continue blocking banned imports, dangerousBun.*property access,eval/Function, non-literal dynamicimport(), andglobalThis/process.envmutation in.rules.tssource.
The sandbox must continue to blockBun.spawnandBun.spawnSyncfrom.rules.tscode.
The sandbox must continue to forbid.rules.tscode from reaching subprocess primitives directly, leavingctx.ast()as the only sanctioned path.
Files:
src/engine/rule-scanner.ts
🧠 Learnings (1)
📚 Learning: 2026-07-02T16:03:33.031Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 446
File: src/helpers/session-context-opencode.ts:81-100
Timestamp: 2026-07-02T16:03:33.031Z
Learning: For synchronous helper functions that use Bun’s sqlite sync API (i.e., they must remain synchronous), it’s acceptable to use `existsSync` from `node:fs` to check whether the SQLite database file exists. Avoid using `Bun.file(path).exists()` for this purpose because it’s async and would force the helper to become async (no equivalent synchronous Bun alternative). If the DB file is missing, throw/return a clear, actionable "No database found" error (per ARCH-006) rather than letting the sqlite open fail with a generic DB-open error.
Applied to files:
src/helpers/opencode-settings.tssrc/helpers/binary-upgrade.tssrc/helpers/signup.tssrc/helpers/session-context-opencode.tssrc/helpers/stack-detect.tssrc/helpers/vscode-settings.tssrc/helpers/session-context-copilot.tssrc/helpers/claude-settings.tssrc/helpers/session-context.tssrc/helpers/auth.ts
🔇 Additional comments (21)
src/cli.ts (1)
4-8: LGTM!Also applies to: 31-31, 120-124, 177-188
src/engine/runner.ts (2)
8-11: LGTM! Guardrail ordering (path safety → language plausibility → interpreter probe → guarded invocation) matches ARCH-022 exactly, and thepython -Iisolation flag is preserved.Also applies to: 166-257
258-259: 🎯 Functional CorrectnessNo cast required.
parseAstJsonalready returnsRecord<string, unknown> | unknown[], so this branch does not depend on overload-based narrowing.> Likely an incorrect or invalid review comment.src/engine/rule-scanner.ts (2)
44-70: 🔒 Security & Privacy | 🏗️ Heavy liftZod schema's cascading validation failure lets crafted computed-access/assignment expressions silently evade the sandbox scanner.
AstNodeSchemarecursively validatesobject,property,callee,left, andsourceviaz.lazy(() => AstNodeSchema), and constrainsvaluetostring | number | boolean | null | AstNode. In Zod, if any declared field on an object fails to validate,.safeParse()fails for the entire object — there's no partial/lenient pass-through for a single bad field.meriyah follows ESTree and constructs real
RegExpobjects for regex-literalvalue(validated via the JS runtime) and nativebigintforBigIntLiteral.value— neither matches thevalueunion. Becauseobject/property/left/sourceare validated eagerly and recursively as part of the parent's own schema check (not just via the genericObject.values()walk), a regex/BigInt literal embedded anywhere inside one of these specific chains poisons every ancestor reachable through them.Concrete bypass of the "Block computed access: Bun[x], globalThis[x]" check (lines 171-177):
Bun[/spawn/.source](cmd); // computed access to Bun.spawn
propertyis(/spawn/).source— aMemberExpressionwhose ownobjectis the regexLiteral. Validating that innerobjectfails (regexvaluemismatch) → the innerMemberExpressionfails → the outerMemberExpression'spropertyfield fails →parseNode()on the entireBun[...]node returnsnull→walk()never visits it, so the computed-access guard never fires.The same technique bypasses the
AssignmentExpression/globalThismutation check vialeft(e.g.globalThis[/x/] = 1;) and theImportExpressionnon-literal-source check viasource.The previous hand-rolled guards (
isAstNode/childNode/strProp/boolProp, per the summary) did lightweight duck-typing and didn't have this "one bad field fails the whole subtree" propagation — this is a regression introduced by switching to strict recursive Zod validation for a security-sandboxing scanner whose entire job is to catch exactly these constructs.Suggested direction: don't require
value/object/property/callee/left/sourceto satisfy the full recursiveAstNodeSchemawhen merely inspecting one level of shape. For example, loosenvaluetoz.unknown()(it's only ever compared withtypeof x === "string"in this file) and validate the named node-shaped fields shallowly (just{ type: z.string() }.passthrough()) rather than viaz.lazy(() => AstNodeSchema), so an incompatible literal buried deeper in the tree can't fail an unrelated ancestor's own shape check.🔒 Illustrative fix direction (loosen recursive fields to avoid cascading failure)
const AstNodeSchema: z.ZodType<AstNode> = z .object({ type: z.string(), name: z.string().optional(), - value: z - .union([ - z.string(), - z.number(), - z.boolean(), - z.null(), - z.lazy(() => AstNodeSchema), - ]) - .optional(), + // Only ever compared with `typeof x === "string"` in this file — don't + // let non-string literal value shapes (RegExp, bigint) fail the whole node. + value: z.unknown().optional(), computed: z.boolean().optional(), - source: z.lazy(() => AstNodeSchema).optional(), - object: z.lazy(() => AstNodeSchema).optional(), - property: z.lazy(() => AstNodeSchema).optional(), - callee: z.lazy(() => AstNodeSchema).optional(), - left: z.lazy(() => AstNodeSchema).optional(), + // Shallow shape check only — do NOT recurse into the full AstNodeSchema, + // or an incompatible literal buried deeper in this subtree fails this + // unrelated ancestor's own validation and hides it from the walker. + source: z.object({ type: z.string() }).passthrough().optional(), + object: z.object({ type: z.string() }).passthrough().optional(), + property: z.object({ type: z.string() }).passthrough().optional(), + callee: z.object({ type: z.string() }).passthrough().optional(), + left: z.object({ type: z.string() }).passthrough().optional(), }) .passthrough();Please add regression tests for
Bun[/x/.source](...)andglobalThis[/x/] = 1style computed-access payloads toscanRuleSource/scanImportedRuleSource— as per coding guidelines,rule-scanner.ts"must continue blocking dangerousBun.*property access" and the sandbox "must continue to forbid.rules.tscode from reaching subprocess primitives directly."Also applies to: 154-179, 209-216, 218-238, 245-256, 326-386
Source: Coding guidelines
83-153: LGTM otherwise — the narrowing to direct field access (node.callee?.name,node.source?.value, etc.) is a clean replacement for the removed cast-based guards for the non-computed/non-nested cases.Also applies to: 180-208, 239-244, 257-373
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (1)
69-76: LGTM! Correctly extends detection to the overloadedfunction astImpldeclaration form now used inrunner.ts.src/helpers/claude-settings.ts (1)
70-75: LGTM!src/helpers/vscode-settings.ts (2)
16-21: LGTM!
156-163: LGTM!tests/helpers/vscode-settings.test.ts (1)
15-15: LGTM!Also applies to: 71-90
src/helpers/session-context.ts (1)
244-244: These segments are internally correct given the current schema (proper narrowing ofentry.type/entry.role, no more optional chaining/non-null assertions). The only concern is the shared root-cause issue onContentBlockSchema/MessageContentSchemaflagged above (lines 55-75), which affects the.parse()calls at lines 244 and 391 directly.Also applies to: 255-257, 391-391, 402-404
src/helpers/opencode-settings.ts (1)
27-32: LGTM!src/helpers/stack-detect.ts (1)
6-24: LGTM!Also applies to: 42-57
src/helpers/session-context-copilot.ts (2)
19-26: LGTM!Also applies to: 121-123
210-219: LGTM!src/helpers/session-context-opencode.ts (1)
282-286: LGTM!src/formats/adr.ts (1)
59-63: LGTM!src/helpers/auth.ts (1)
213-216: LGTM!src/helpers/binary-upgrade.ts (2)
95-101: LGTM!
179-182: 🗄️ Data Integrity & IntegrationRedundant buffer slice The
Uint8Arrayis allocated withdownloadedBytes, socombined.buffer.slice(combined.byteOffset, combined.byteOffset + combined.byteLength)always returns the full payload and cannot truncate or extend it.> Likely an incorrect or invalid review comment.src/helpers/signup.ts (1)
70-78: LGTM!
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_b6b199d2-1b78-4cc8-a069-bb4271ec0ff0) |
63283e3 to
ff9836f
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_185272d3-5d04-45ec-bc91-654f05dfd560) |
ff9836f to
b9716f7
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c0ac2aa3-3f54-4843-8e8a-b60a2303991a) |
- git-files: use optional chaining instead of ! on adrFileGlobs - login-flow: type SignupEditor as literal union of editor values, eliminating the ! assertion and the ?? fallback - init: use SignupEditor type for SIGNUP_EDITORS map Zero non-null assertions (!) remain in src/. Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
b9716f7 to
a16d2f9
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_cc83c3ee-48b2-44ff-a468-80b51165b9a5) |
- Extract formatZodErrors into shared export from adr.ts, reuse in pack.ts instead of duplicating the path:message mapping - claude-settings: use nullish check on merged.agent instead of `in` operator, so invalid values caught to undefined get the default - session-context: expand ContentBlockSchema with catch-all for unknown Anthropic block types (thinking, image, etc.) so newer Claude sessions don't fail parsing. Known blocks (text, tool_use, tool_result) are still typed; unknown blocks are silently skipped in content preview Claude-Session: https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_faaafde5-781b-4446-935c-8b55f083b603) |
Summary
as Typeassertion fromsrc/(70+ instances across 23 files), replacing with type-safe alternativesProxyfor function patching instead of signature castsApproach by category
.passthrough()isAstNode,childNode,strProp,boolProp)Promise<any>return for implementationProxywithapply/gettrapsgetExitCodereturn.some(),Object.entries(),Object.fromEntries()Result
as Typeassertions insrc/(onlyas constandimport asremain)Test plan
bun run validatepasses (lint, typecheck, format, test, ADR check, knip, build)https://claude.ai/code/session_01P2kzr4bcBvg7AtaRhyHdMa