Skip to content

feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby#452

Open
rhuanbarreto wants to merge 16 commits into
mainfrom
claude/ast-aware-rule-context
Open

feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby#452
rhuanbarreto wants to merge 16 commits into
mainfrom
claude/ast-aware-rule-context

Conversation

@rhuanbarreto

Copy link
Copy Markdown
Contributor

Summary

Implements the AST-Aware Rule Context feature from .archgate/PRDs/ast-aware-rule-context.md, governed by ARCH-022. .rules.ts authors get a single new RuleContext method:

ast(path: string, language: "typescript" | "javascript" | "python" | "ruby"): Promise<AstNode>

Structural (AST-based) checks now replace fragile regex/line heuristics — for TypeScript/JavaScript in-process, and for Python/Ruby via each interpreter's own standard-library AST facility.

Delivers the full four-language scope (TS/JS + Python/Ruby together), satisfying every PRD success criterion in one PR.

What's included

Engine

  • ctx.ast() on RuleContext, dispatched entirely inside createRuleContext().
  • TS/JS: in-process via the shared meriyah parser (src/engine/js-parser.ts) — the duplicated parseModule() calls in rule-scanner.ts are factored out as ARCH-022 mandates. TypeScript is transpiled first; .cjs parses in sloppy script mode.
  • Python/Ruby: Bun.spawn subprocesses running the stdlib ast module / Ripper, serialized to JSON. Zero new dependencies.
  • Four-guardrail ordering (path safety → language plausibility → cached interpreter probe → guarded array-args invocation). Throws (never null) on parse failure or missing interpreter, with distinguishable messages; rides the existing per-rule isolation + exit-code-2 category.

Dogfooding

  • ARCH-004 (no-barrel-files) and ARCH-008 (typed-command-options) rewritten to use ctx.ast() — the two rules ARCH-022 names as motivating consumers. The ARCH-008 rewrite now catches multi-line .option() calls the old per-line regex missed.
  • ARCH-022 flipped to rules: true with four companion checks (guardrail ordering — itself parsed via ctx.ast() — subprocess containment, single-method, and Python -I isolation).

Docs: ctx.ast() reference + AstNode shapes, interpreter-PATH callouts, and one example rule per language, translated into nb + pt-br.

Tests: unit coverage for the parser/probe/subprocess/serializers + runChecks integration (all four guardrails, failure semantics, real Python/Ruby structural rules).

Adversarial review

A multi-lens review (ADR compliance, sandbox/security, cross-platform, serializer correctness, test quality, docs) with per-finding adversarial verification surfaced and fixed:

  • CRITICAL — Python subprocess could execute arbitrary target-project code via sys.path cwd shadowing (a planted ast.py). Fixed with python -I isolated mode; verified end-to-end against a live shadow, and now guarded by both an integration test and the static python-subprocess-isolated rule.
  • Windows py launcher probing; .cjs sloppy-mode parsing; UTF-8 BOM stripping; ARCH-008 3-arg .option() coverage regression; and the transpiled-loc caveat documented across code, ADR, and all locales.

Verification

  • bun run validate green: 1388 pass / 0 fail, 43/43 ADR rules pass, 0 warnings, build compiles.
  • @reviewer skill: APPROVED across Architecture / General / Legal domains.
  • Python 3.14 + Ruby 4.0 exercised locally end-to-end.

Closes the PRD; ARCH-022 amended to reflect shipped state.

https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX

RuleContext gains a single ast(path, language) method supporting
typescript/javascript (in-process via the shared meriyah parser) and
python/ruby (stdlib ast module / Ripper via Bun.spawn subprocesses).

Guardrail ordering per ARCH-022: safePath sandbox, language
plausibility, cached interpreter probe, array-args-only invocation.
Throws (never null) on parse failure or missing interpreter, with
distinguishable messages riding the existing per-rule error isolation.

The duplicated parseModule() calls in rule-scanner.ts are factored
into the shared js-parser.ts helper as mandated by the ADR.

Tests for the new modules land in the follow-up commit in this PR
(ARCH-005 flags them until then).

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Flips ARCH-022 to rules:true as its own Compliance section mandates
once ctx.ast() ships. The guardrail-ordering rule parses runner.ts
via ctx.ast() itself — the first structural (non-regex) rule in the
repo — plus subprocess-containment and single-method checks.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Unit coverage for js-parser and ast-support (probe, subprocess
runner, serializer programs gated on interpreter availability) plus
runChecks-level integration tests for the four guardrails, failure
semantics, and real Python/Ruby structural rules. Resolves the
ARCH-005 gap from the core commit.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Replaces the line-stripping barrel heuristic and the single-line
.option() regexes with ESTree structural checks — the two fragile
rules ARCH-022 names as motivating consumers. The ARCH-008 rules now
catch multi-line .option() calls the old per-line regex missed.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Adds the ast() method reference, AstNode shapes table, interpreter
PATH requirement callouts, and a structural-checks guide section with
one example rule per supported language, translated into both locales
per GEN-002.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Python's utf-8 codec preserves the BOM as U+FEFF, which ast.parse
rejects as a syntax error; utf-8-sig strips it. Ruby gets the
equivalent r:bom|utf-8 read mode.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
- Python subprocess runs with -I (isolated mode): without it, `python
  -c` puts the target project cwd on sys.path, letting a hostile
  project shadow stdlib modules (ast.py/json.py) and run arbitrary
  code. Verified end-to-end against a shadow ast.py.
- Windows interpreter probe adds the `py` launcher: the python.org
  installer registers it even when PATH opt-in is unchecked.
- .cjs files parse in sloppy script mode (globalReturn) so CommonJS
  top-level return no longer fails under module grammar.
- ARCH-008 choices rule uses args.length < 2, not !== 2, so a
  fixed-choice .option() with a trailing default value is still
  flagged (regression vs the old regex).
- AstNode JSDoc + ARCH-022 note the transpiled-loc caveat and py.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Adds coverage for Ruby extensionless basenames (Rakefile/Gemfile),
.tsx/.jsx dispatch, .cjs sloppy-script mode vs .mjs rejection,
per-language plausibility rejection, and a security regression guard
that the Python -I isolation blocks a hostile cwd ast.py shadow.
Updates the Windows candidate-order assertion for the py launcher.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
For language "typescript", loc positions refer to Bun.Transpiler
output, not the original .ts source, so line numbers drift. Documents
that rules must re-locate matches in the original source before
reporting a line; loc is source-accurate only for "javascript".
Regenerates llms-full.txt.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Adds a fourth companion rule (python-subprocess-isolated) that
statically asserts the Python invocation keeps its -I flag, plus
Do/Don't guidance for -I isolation, BOM stripping, and the
transpiled-loc caveat — the security/correctness lessons surfaced by
the adversarial review, so a future refactor cannot silently drop
them.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Captures the generalizable kernel from the ctx.ast review (python -I
cwd-shadow RCE, BOM codec, transpiled loc drift, Windows py launcher)
for future interpreter-subprocess work beyond ctx.ast itself.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 803fbc63-1b4b-4d4e-bd14-5517ce1395f8

📥 Commits

Reviewing files that changed from the base of the PR and between 1ede26b and 5e2dd8a.

📒 Files selected for processing (1)
  • .archgate/adrs/ARCH-004-no-barrel-files.rules.ts
📝 Walkthrough

Walkthrough

This PR adds ctx.ast() support to the rule engine for structural parsing across TypeScript, JavaScript, Python, and Ruby. It introduces AST parsing helpers and parser wrappers, rewires runner execution and rule scanning, expands public AST types and RuleContext, migrates existing ADR rules to AST-based checks, adds new ADR-022 enforcement rules, and updates docs in multiple locales. New tests cover parsing behavior, subprocess handling, guardrails, and runner integration.

Related PRs: None identified
Suggested labels: documentation, enhancement, engine
Suggested reviewers: None specified

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding an AST-aware rule context for TS/JS/Python/Ruby.
Description check ✅ Passed The description is strongly related to the changeset and accurately describes the new ctx.ast feature, updates, docs, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 5, 2026

Copy link
Copy Markdown

Deploying archgate-cli with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5e2dd8a
Status: ✅  Deploy successful!
Preview URL: https://a2426760.archgate-cli.pages.dev
Branch Preview URL: https://claude-ast-aware-rule-contex.archgate-cli.pages.dev

View logs

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8c59cd8. Configure here.

Comment thread .archgate/adrs/ARCH-008-typed-command-options.rules.ts
Comment thread src/engine/ast-support.ts
Comment thread .archgate/adrs/ARCH-004-no-barrel-files.rules.ts Outdated

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

🤖 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 @.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts:
- Around line 81-93: Replace the loc-based ordering in the guardrail sequence
logic with a visitation-based ordinal, since ARCH-022 says not to trust node.loc
for "typescript" ASTs. In the firstSeen tracking inside the walk(astMethodBody,
...) loop, use the walk traversal order itself (for example, an incrementing
counter when a guardrail Identifier is first encountered) instead of computing
positions from n.loc.start.line and column. Keep the change localized to the
ordering logic around firstSeen, walk, and GUARDRAIL_SEQUENCE so the rule still
compares first occurrences without relying on transpiled-relative locations.

In `@src/engine/ast-support.ts`:
- Line 16: The timeout in runAstSubprocess is tied to the hardcoded
AST_SUBPROCESS_TIMEOUT_MS constant, which prevents fast coverage of the timeout
branch. Update runAstSubprocess to accept an optional timeout parameter that
defaults to AST_SUBPROCESS_TIMEOUT_MS, then use that parameter everywhere the
subprocess timeout is enforced so tests can inject a tiny value. Keep the
existing AST_SUBPROCESS_TIMEOUT_MS export unchanged for production callers and
adjust the timeout test in tests/engine/ast-support.test.ts to pass a small
timeout and cover the branch deterministically.
- Around line 141-168: The timeout branch in runAstSubprocess kills the
Bun.spawned process but does not wait for proc.exited to settle afterward.
Update the timeout handling so that after proc.kill() you still await
proc.exited before throwing, ensuring the subprocess is fully reaped; keep the
fix localized to runAstSubprocess and preserve the existing stdout/stderr
collection flow.
- Around line 107-133: `probeInterpreter` can hang forever because it only waits
on `proc.exited` and `stdout`, so add the same timeout protection used by
`runAstSubprocess` (or a shared helper) when spawning candidates in
`src/engine/ast-support.ts`. Update the `probeInterpreter` loop to race each
`Bun.spawn` probe against `AST_SUBPROCESS_TIMEOUT_MS`, and on timeout kill the
process and continue to the next candidate so stalled binaries like `python3` on
macOS do not block `ctx.ast()`.

In `@src/engine/runner.ts`:
- Around line 309-331: The TypeScript parsing path in runner.ts treats every
.ts/.tsx input as a module, which breaks supported .cts files that may use
CommonJS-only script syntax. Update the TypeScript branch in the runner’s parse
flow to detect the .cts extension and pass sourceType: "script" into
parseJsModule, similar to the existing .cjs handling; if .cts is not intended to
be supported, remove it from the supported TypeScript extension list instead.

In `@tests/engine/ast-support.test.ts`:
- Around line 61-83: The runAstSubprocess tests only cover stdout and stderr
cases, so the timeout branch that kills the child process and throws remains
untested. Update the tests around runAstSubprocess to exercise the injectable
timeout parameter mentioned in src/engine/ast-support.ts, and add a case that
starts a long-running subprocess, uses a short timeout, and asserts the promise
rejects with a timeout message while the subprocess is killed.
- Around line 130-243: Add a BOM-specific end-to-end case for the AST serializer
paths so `PYTHON_AST_PROGRAM` and `RUBY_AST_PROGRAM` are exercised with a UTF-8
BOM fixture, not just plain UTF-8 input. Update the existing
`describe("PYTHON_AST_PROGRAM end-to-end", ...)` and `describe("RUBY_AST_PROGRAM
end-to-end", ...)` blocks, or add the coverage in
`tests/engine/runner-ast.test.ts`, to verify BOM handling still works for the
subprocess flow. Make sure the test targets the serializer/runner path that uses
`encoding="utf-8-sig"` or `mode: "r:bom|utf-8"` so the regression is caught.

In `@tests/engine/js-parser.test.ts`:
- Around line 1-53: Add coverage for the missing `sourceType: "script"` path in
`parseJsModule` by extending the existing `parseJsModule` tests to verify script
mode behavior, especially that CommonJS-style syntax such as a top-level
`return` is accepted when `sourceType: "script"` is passed and still rejected in
module mode. Use the existing `parseJsModule` helper in
`tests/engine/js-parser.test.ts` to keep the assertion close to the current
module/JSX/syntax tests.

In `@tests/engine/runner-ast.test.ts`:
- Around line 388-429: Add an analogous regression test in the existing
.cjs/.mjs parsing test suite to cover the .cts gap mentioned by runner.ts. Use a
.cts fixture and a construct that only parses in "script" mode, then assert the
parser behavior and sourceType the same way this test does for cjsSourceType and
mjs error handling. Reuse the same test pattern in runner-ast.test.ts so the new
case clearly verifies whether .cts is treated like sloppy CommonJS or still
needs a fix in the AST routing logic.
🪄 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: 25225b9d-ad05-4469-9965-11820e7e8f00

📥 Commits

Reviewing files that changed from the base of the PR and between 21829b5 and 8c59cd8.

📒 Files selected for processing (21)
  • .archgate/adrs/ARCH-004-no-barrel-files.rules.ts
  • .archgate/adrs/ARCH-008-typed-command-options.rules.ts
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
  • .claude/agent-memory/archgate-developer/project_rules_engine_internals.md
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • src/engine/ast-support.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/js-parser.test.ts
  • tests/engine/runner-ast.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Cloudflare Pages
⚠️ CI failures not shown inline (4)

GitHub Actions: DCO / 0_DCO Sign-off Check.txt: feat: AST-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run base="21829b56e22cbf7442bc4fe66502ba988073c049"
 �[36;1mbase="21829b56e22cbf7442bc4fe66502ba988073c049"�[0m
 �[36;1mhead="8c59cd869f6cc1131fa8879969bf3416e6033558"�[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 / DCO Sign-off Check: feat: AST-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run base="21829b56e22cbf7442bc4fe66502ba988073c049"
 �[36;1mbase="21829b56e22cbf7442bc4fe66502ba988073c049"�[0m
 �[36;1mhead="8c59cd869f6cc1131fa8879969bf3416e6033558"�[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 #452 / Analyze (go): Code Quality: PR #452

Conclusion: failure

View job details

,"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/05 11:36:28 Autobuilder was built with go1.26.0, environment has go1.24.13
 [] [build-stderr] 2026/07/05 11:36:28 LGTM_SRC is /home/runner/work/cli/cli
 [] [build-stderr] 2026/07/05 11:36:28 Found no go.work files in the workspace; looking for go.mod files...
 [] [build-stderr] 2026/07/05 11:36:28 Found 1 go.mod files in: shims/go/go.mod.
 [] [build-stderr] 2026/07/05 11:36:28 Found 1 go.mod file(s).
 [] [build-stderr] 2026/07/05 11:36:28 Import path is 'github.com/archgate/cli'
 [] [build-stderr] 2026/07/...

GitHub Actions: Code Quality: PR #452 / 0_Analyze (go).txt: Code Quality: PR #452

Conclusion: failure

View job details

:36 Extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/des.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Done extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 11:36:36 Processing package crypto/elliptic.
 [] [build-stderr] 2026/07/05 11:36:36 Extracting types for package crypto/elliptic.
 [] [buil...
🧰 Additional context used
📓 Path-based instructions (21)
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 under tests/ mirroring the src/ directory structure with <module-name>.test.ts naming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up in afterEach or afterAll.
Close external SDK instances (servers, clients, transports, connections) in afterEach or afterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runs git commit, configure local user.email and user.name immediately after git init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnable test()/it() must contain at least one expect() assertion; smoke tests must make the contract explicit with expect(() => fn()).not.toThrow() or await expect(promise).resolves.toBeUndefined().
Use test.skip, test.skipIf, or test.todo for intentionally empty or disabled tests; do not use bare return or empty callbacks to skip work.
If the first expect() is being added to a previously assertion-less test file, add expect to the bun:test import.
When mocking fetch in tests, assign directly to globalThis.fetch and restore the original or use mock.restore() afterward.
Wrap spyOn() and inline mockImplementation() usage in try/finally, or create and restore spies in hooks, so mockRestore() always runs.
Only raise a per-test timeout above the global bun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules with import * as mod plus spyOn(mod, "fn"), not mock.module().
When a test needs to redirect user-scope paths, mock os.homedir() instead of relying on HOME/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/engine/js-parser.test.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast.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, use Bun.file() instead of fs.readFile() for simple reads.
Prefer node: built-in modules such as node:util, node:path, and node:fs over npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper like pick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; use bunx for one-off tools.

Files:

  • tests/engine/js-parser.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/rule-scanner.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast.test.ts
  • src/engine/ast-support.ts
  • src/engine/runner.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 mutating process.platform directly.

Files:

  • tests/engine/js-parser.test.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast.test.ts
{src,tests}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)

{src,tests}/**/*.ts: Every TypeScript source file in src/ and tests/ must begin with // SPDX-License-Identifier: Apache-2.0 followed by // Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example #!/usr/bin/env bun in src/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/engine/js-parser.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/rule-scanner.ts
  • tests/engine/ast-support.test.ts
  • tests/engine/runner-ast.test.ts
  • src/engine/ast-support.ts
  • src/engine/runner.ts
**

⚙️ CodeRabbit configuration file

**: # CLAUDE.md

Archgate 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 wizard

Validation Gate

bun run validate must 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 .githooks run 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 ../.githooks

Opt 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/engine/js-parser.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • src/engine/rule-scanner.ts
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • tests/engine/ast-support.test.ts
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/public/llms-full.txt
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • tests/engine/runner-ast.test.ts
  • src/engine/ast-support.ts
  • src/engine/runner.ts
  • docs/src/content/docs/guides/writing-rules.mdx

⚙️ 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.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • tests/engine/js-parser.test.ts
  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • src/engine/rule-scanner.ts
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • tests/engine/ast-support.test.ts
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/public/llms-full.txt
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • tests/engine/runner-ast.test.ts
  • src/engine/ast-support.ts
  • src/engine/runner.ts
  • docs/src/content/docs/guides/writing-rules.mdx
src/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

src/**/*.ts: Use logError() from src/helpers/log.ts for user-facing errors instead of printing errors directly.
Exit with code 1 for 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 code 2.
Include actionable suggestions in user-facing error messages whenever possible.
Write user-facing errors to stderr via logError(); do not send them to stdout.
When findProjectRoot() returns null for commands that do not require .archgate/, fall back to process.cwd() as the path key or working directory.
Catch ExitPromptError from Inquirer in the top-level error boundary and treat it as user cancellation: exit with code 130 without logging an error or sending it to Sentry.
Do not use console.error() directly; use logError() for consistent formatting.
Do not exit with codes other than 0, 1, 2, or 130.
Do not send user-cancellation errors such as Inquirer ExitPromptError to Sentry; filter them in beforeSend.

src/**/*.ts: Use styleText(format, text) from node:util for 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 --json must emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports --json, use formatJSON() from src/helpers/output.ts for JSON serialization, and pass forcePretty: true when the user explicitly provided --json.
Use isAgentContext() from src/helpers/output.ts to 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 with console.log(), and send errors, warnings, and debug messages to stderr via logError(), logWarn(), and logDebug().
Keep CLI output concise and scannabl...

Files:

  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/rule-scanner.ts
  • src/engine/ast-support.ts
  • src/engine/runner.ts
src/{helpers,engine}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

Do not use console.log(), console.warn(), or console.info() directly in helper or engine files; use logInfo() or logWarn() instead. Command files are exempt because they are the I/O layer.

Files:

  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/engine/rule-scanner.ts
  • src/engine/ast-support.ts
  • src/engine/runner.ts
src/**/!(*platform).ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

src/**/!(*platform).ts: In src/ TypeScript source files, do not read process.platform directly; use src/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 in src/ TypeScript source.
When behavior differs between Linux and Windows, account for WSL by using isWSL() rather than assuming `

Files:

  • src/engine/js-parser.ts
  • src/helpers/rules-shim.ts
  • src/formats/rules.ts
  • src/engine/rule-scanner.ts
  • src/engine/ast-support.ts
  • src/engine/runner.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-008-typed-command-options.rules.ts
  • .archgate/adrs/ARCH-004-no-barrel-files.rules.ts
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.md
src/helpers/rules-shim.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

The generated RuleContext shim for .rules.ts authors must mirror the single ast(path, language) method signature and not add per-language variants.

Files:

  • src/helpers/rules-shim.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, use safeParse(), and reuse AdrFrontmatterSchema.shape.* instead of duplicating enums.

Files:

  • src/formats/rules.ts
src/formats/rules.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

RuleContext must expose a single ast(path: string, language: "typescript" | "javascript" | "python" | "ruby"): Promise<AstNode> method (no per-language variants).

Files:

  • src/formats/rules.ts
docs/src/content/docs/**/*.mdx

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

docs/src/content/docs/**/*.mdx: Use MDX (.mdx) for all content pages under docs/src/content/docs/.
Escape literal curly braces in MDX when showing template syntax; do not use bare {} in prose or code-fence labels.

Files:

  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
{docs/src/content/docs/**/*.mdx,docs/astro.config.mjs}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

When adding a new documentation page, create the MDX file in docs/src/content/docs/<category>/<slug>.mdx and add the page to docs/astro.config.mjs sidebar configuration.

Files:

  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
docs/src/content/docs/**

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

Do not create documentation content files outside docs/src/content/docs/; Starlight content must live in that exact directory structure.

Files:

  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
docs/src/content/docs/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

docs/src/content/docs/**/*.{mdx,md}: For every English docs page under docs/src/content/docs/, create a translated file in each locale directory with the exact same relative path and filename, and ensure every locale file corresponds to an existing root file (no orphan translations).
When adding or modifying English documentation content, update the corresponding locale files in the same pull request.
Translate all user-facing prose in docs pages, including titles, descriptions, headings, paragraphs, list items, table text, and admonition content.
Translate user-visible text props in Starlight components such as <Card title="..."> and <LinkCard description="...">.
Keep code blocks, CLI commands, file paths, TypeScript identifiers, technical terms, import statements, component names, and link/href/slug attribute values in English.
Keep internal links unchanged and do not add locale prefixes (for example, use /guides/... rather than /pt-br/guides/...).
Preserve MDX curly-brace escaping (\{\}) in translated content.
Preserve Starlight component import statements identically in translated files.

Files:

  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/guides/writing-rules.mdx
docs/src/content/docs/pt-br/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use correct Portuguese diacritical marks in Brazilian Portuguese translations; never write unaccented Portuguese.

Files:

  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
src/engine/rule-scanner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

Factor the duplicated parseModule() invocation into a shared exported parse helper, and have the scanner use that helper instead of an inline parse call.

Files:

  • src/engine/rule-scanner.ts
docs/src/content/docs/reference/**/*.mdx

📄 CodeRabbit inference engine (.archgate/adrs/GEN-001-documentation-site.md)

Keep reference pages accurate to the CLI source code; when CLI APIs change, update the corresponding reference docs in the same PR.

Files:

  • docs/src/content/docs/reference/rule-api.mdx
docs/src/content/docs/nb/**/*.{mdx,md}

📄 CodeRabbit inference engine (.archgate/adrs/GEN-002-docs-i18n.md)

Use Norwegian Bokmål (not Nynorsk) for Norwegian translations, with the informal du form and correct Norwegian characters (æ, ø, å).

Files:

  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
src/engine/runner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/runner.ts: Implement ctx.ast() inside createRuleContext() with internal dispatch only; rule authors must not see or control the dispatch mechanism.
For ctx.ast() on TypeScript/JavaScript, reuse the existing in-process meriyah parser; do not spawn a subprocess for these languages.
For ctx.ast() on Python/Ruby, invoke the language's standard-library AST facility via Bun.spawn using array-based arguments only.
Before any Python/Ruby subprocess is spawned, run guardrails in this order: path safety, language plausibility, interpreter availability probe, then guarded invocation.
Use the same safePath() sandboxing for ctx.ast() that is already applied to readFile and glob.
Probe interpreter availability once per check invocation, cache the result, and use platform-appropriate executable names (python/python3/py, ruby).
Run Python in isolated mode (python -I -c ...) when parsing files through ctx.ast().
Strip a leading UTF-8 BOM before parsing in the Python and Ruby serializers.
ctx.ast() must throw on missing interpreter or parse failure; it must not return null or another sentinel.
Do not trust node.loc for TypeScript ASTs parsed from transpiled output; re-locate positions in the original source before reporting.
Do not use Bun.$ or shell-interpolated command strings for any subprocess invocation in this feature.

Files:

  • src/engine/runner.ts
🧠 Learnings (2)
📚 Learning: 2026-06-11T12:50:28.661Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 406
File: .claude/agent-memory/archgate-developer/feedback_prefer_tests_over_adr_rules.md:8-18
Timestamp: 2026-06-11T12:50:28.661Z
Learning: In `archgate/cli`, for markdown files under `.claude/agent-memory/`, follow the established convention: use YAML frontmatter (with a `name:` field used as the document title) and do not require a top-level `#` (H1) heading. During code review, do not flag missing first-line/first-top-level H1 headings (e.g., MD041) for these agent-memory files since markdownlint is not part of the repo’s `bun run validate` lint pipeline (oxlint/oxfmt only).

Applied to files:

  • .claude/agent-memory/archgate-developer/project_rules_engine_internals.md
📚 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/rules-shim.ts
🪛 LanguageTool
docs/src/content/docs/pt-br/reference/rule-api.mdx

[uncategorized] ~180-~180: Pontuação duplicada
Context: ...a árvore retornada difere por linguagem -- veja AstNode. ```typescrip...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~196-~196: Pontuação duplicada
Context: ...este arquivo tem um erro de sintaxe". :::caution Regras de Python e Ruby exigem o...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~198-~198: Pontuação duplicada
Context: ...chgate e não precisa de interpretador. ::: --- ## RuleReport A interface de rel...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~302-~302: Pontuação duplicada
Context: ...a | Arrays aninhados de Ripper.sexp: ["program", [["command", ...]]] com pares de posição ...

(DOUBLE_PUNCTUATION_XML)

docs/src/content/docs/pt-br/guides/writing-rules.mdx

[uncategorized] ~179-~179: Pontuação duplicada
Context: ...falha de parse ou interpretador ausente -- nunca retorna null. ```typescript co...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~221-~221: Pontuação duplicada
Context: ... "isto é uma cláusula except: vazia?" -- declarações multilinha, comentários e c...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~227-~227: Pontuação duplicada
Context: ...iblioteca padrão: arrays aninhados como ["program", [["command", ...]]] com pares de posição ...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~229-~229: Pontuação duplicada
Context: ...ha de parse ou de interpretador ausente -- nunca retorna null. A exceção fica is...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~231-~231: Pontuação duplicada
Context: ...a visível em vez de um falso sucesso. :::caution O parsing de Python e Ruby invoc...

(DOUBLE_PUNCTUATION_XML)


[style] ~232-~232: Três frases seguidas começam com a mesma palavra. Considere reformular a frase ou use um dicionário para encontrar um sinônimo.
Context: ...a máquina de desenvolvedor e no CI. O parsing de TypeScript e JavaScript é em...

(PORTUGUESE_WORD_REPEAT_BEGINNING_RULE)


[uncategorized] ~233-~233: Pontuação duplicada
Context: ...chgate e não precisa de interpretador. ::: ### TypeScript: sem barrel files Um b...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~280-~280: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...esloca posições: os números de linha em loc referem-se ao texto transpilado, não a...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~280-~280: Esta locução deve ser separada por vírgulas.
Context: ... a construção no código-fonte original (por exemplo com ctx.readFile() e indexOf) antes...

(VERB_COMMA_CONJUNCTION)


[grammar] ~284-~284: Deve-se usar a próclise quando o verbo for precedido imediatamente por palavras de negação e determinados pronomes, conjunções e advérbios.
Context: ...e arrays cobre todos os tipos de nó sem enumerá-los: ```typescript /// <reference path=".....

(COLOCACAO_PRONOMINAL_COM_ATRATOR_SIMPLES)


[uncategorized] ~336-~336: Se é uma abreviatura, falta um ponto. Se for uma expressão, coloque entre aspas.
Context: ...ha no código-fonte original, já que seu loc refere-se à saída transpilada. ### Py...

(ABREVIATIONS_PUNCTUATION)


[uncategorized] ~340-~340: Pontuação duplicada
Context: ...guarda a expressão da exceção capturada -- um except: vazio tem "type": null. ...

(DOUBLE_PUNCTUATION_XML)


[uncategorized] ~389-~389: Pontuação duplicada
Context: ...er.sexprepresentaputs "hello"como["command", ["@ident", "puts", [1, 0]], [...args]]-- o par[linha, coluna]`...

(DOUBLE_PUNCTUATION_XML)

.archgate/adrs/ARCH-022-ast-aware-rule-context.md

[style] ~42-~42: Consider removing “of” to be more concise
Context: ...nandBun.spawnSyncfrom rule code). All of the following MUST execute insidecreateRu...

(ALL_OF_THE)

🔇 Additional comments (22)
docs/public/llms-full.txt (1)

2873-2884: LGTM!

Also applies to: 2915-3133, 5121-5121, 5224-5251, 5340-5359

docs/src/content/docs/guides/writing-rules.mdx (1)

177-188: LGTM!

Also applies to: 219-234, 235-281, 282-337, 338-385, 387-438

docs/src/content/docs/reference/rule-api.mdx (1)

68-68: LGTM!

Also applies to: 171-199, 288-307

docs/src/content/docs/nb/guides/writing-rules.mdx (1)

177-188: LGTM!

Also applies to: 219-234, 235-280, 282-337, 338-386, 387-438

docs/src/content/docs/nb/reference/rule-api.mdx (1)

68-68: LGTM!

Also applies to: 171-199, 288-307

docs/src/content/docs/pt-br/guides/writing-rules.mdx (1)

177-188: LGTM!

Also applies to: 219-234, 235-337, 338-438

docs/src/content/docs/pt-br/reference/rule-api.mdx (1)

68-68: LGTM!

Also applies to: 171-199, 288-307

src/engine/js-parser.ts (1)

1-41: LGTM! Correctly centralizes the meriyah call site per ARCH-022, and the .cjs/globalReturn rationale is well documented.

src/engine/rule-scanner.ts (1)

3-3: LGTM! Clean migration to the shared parseJsModule helper — closes the exact duplication gap ARCH-022 calls out.

Also applies to: 73-75, 265-267

src/engine/runner.ts (1)

285-372: Guardrail ordering, throw semantics, and cache sharing all verified compliant with ARCH-022.

Path safety → plausibility → (in-process TS/JS or interpreter probe → guarded invocation) matches the mandated order exactly; every failure path throws (never returns null/sentinel) with distinguishable messages; the per-runChecks interpreterCache is created once and shared across all ADRs/rules as required. The -I Python isolation flag is confirmed correct — Python's own docs state -c/REPL invocations otherwise prepend an empty string (cwd) to sys.path, which -I explicitly suppresses, closing the shadow-module RCE vector this ADR calls out.

Also applies to: 422-425, 462-463

src/formats/rules.ts (1)

65-112: LGTM! Accurate, thorough documentation of the per-language AST shape divergence and the TS loc caveat — matches the actual runner.ts behavior and ARCH-022's failure-semantics requirement.

tests/engine/runner-ast.test.ts (1)

1-508: LGTM otherwise! Strong coverage of guardrail ordering, sandbox/plausibility rejection, the exit-code-2 failure-visibility contract, and the -I shadow-import regression — this last one is a genuinely valuable security regression test.

tests/engine/js-parser.test.ts (1)

1-53: LGTM!

src/engine/ast-support.ts (2)

22-30: LGTM on the plausibility table, Python/Ruby serializer programs (BOM handling and float/complex/bytes fallback to repr() match the documented contract), and interpreterCandidates platform ordering.

Also applies to: 38-83


175-195: LGTM!

tests/engine/ast-support.test.ts (1)

1-243: Good coverage of probeInterpreter, runAstSubprocess, parseAstJson, parseErrorMessage, and end-to-end serializer behavior for both interpreters, with proper test.skipIf gating and temp-dir cleanup.

src/helpers/rules-shim.ts (1)

72-112: LGTM! The generated typings correctly expose a single ast(path, language) method, document the throw-not-null contract, and call out the TypeScript loc caveat (transpiled output vs. source-accurate JavaScript parsing) exactly as required.

.archgate/adrs/ARCH-004-no-barrel-files.rules.ts (1)

4-58: LGTM!

Also applies to: 72-89

.archgate/adrs/ARCH-008-typed-command-options.rules.ts (1)

3-97: LGTM!

Also applies to: 106-139, 148-185

.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (1)

118-182: LGTM!

.archgate/adrs/ARCH-022-ast-aware-rule-context.md (1)

5-9: LGTM!

Also applies to: 40-46, 63-64, 77-78, 110-115

.claude/agent-memory/archgate-developer/project_rules_engine_internals.md (1)

12-12: LGTM! Consistent with the ADR-022 doc and directly informs the loc-usage concern flagged in ARCH-022-ast-aware-rule-context.rules.ts.

Based on learnings, agent-memory files under .claude/agent-memory/ are not required to have a top-level H1 heading given their established frontmatter convention.

Source: Learnings

Comment thread .archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
Comment thread src/engine/ast-support.ts
Comment thread src/engine/ast-support.ts
Comment thread src/engine/ast-support.ts
Comment thread src/engine/runner.ts Outdated
Comment thread tests/engine/ast-support.test.ts
Comment thread tests/engine/ast-support.test.ts
Comment thread tests/engine/js-parser.test.ts
Comment thread tests/engine/runner-ast.test.ts
RuleContext.ast() is now overloaded on the language literal so authors
get a precise, autocompletable return type instead of the loose
AstNode union:
  ast(p, "typescript"|"javascript") -> EsTreeProgram
  ast(p, "python")                   -> PythonAstModule
  ast(p, "ruby")                     -> RubyAstNode
  ast(p, AstLanguage)                -> AstNode   (fallback)

Adds self-contained public shapes (EsTreeNode/EsTreeProgram,
PythonAstNode/PythonAstModule, RubyAstNode) to the ambient rules.d.ts
so .rules.ts authors get them with zero imports. The internal meriyah
return type is renamed MeriyahProgram to avoid clashing with the
public EsTreeProgram. Existing ast() tests now access per-language
fields without casts, so a regression to the broad union fails
typecheck. The guardrail-ordering rule follows the impl into its new
const form.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>

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

♻️ Duplicate comments (1)
src/engine/runner.ts (1)

196-216: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

.cts files are always parsed as ESM modules, breaking CommonJS-only .cts syntax.

.cts is listed as a supported TypeScript extension in AST_LANGUAGE_EXTENSIONS, but the TypeScript branch (lines 199-203) always feeds the transpiled output to parseJsModule(js) with no sourceType, so it defaults to strict module grammar. A .cts file using CommonJS-only syntax (e.g. top-level return, with) will fail to parse, exactly the same gap already identified for .js/.cjs and fixed via sourceType: "script" a few lines below (line 209) for the plain-JS branch. This was flagged in a prior review round and is still present in this revision.

🐛 Proposed fix — mirror the `.cjs` handling for `.cts`
         if (language === "typescript") {
           const loader = lowerPath.endsWith(".tsx") ? "tsx" : "ts";
           const js = new Bun.Transpiler({ loader }).transformSync(source);
-          return parseJsModule(js) as unknown as EsTreeProgram;
+          return parseJsModule(js, {
+            sourceType: lowerPath.endsWith(".cts") ? "script" : "module",
+          }) as unknown as EsTreeProgram;
         }

Based on learnings, a prior review already raised this exact gap for .cts in this file (and suggested a companion test in runner-ast.test.ts).

🤖 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/engine/runner.ts` around lines 196 - 216, The TypeScript parsing path in
runner.ts still treats .cts output as a module, so CommonJS-only syntax can fail
to parse. Update the TypeScript branch in the runner logic that calls
Bun.Transpiler.transformSync and parseJsModule so .cts files are parsed with
script sourceType instead of the default module grammar, mirroring the existing
.cjs handling in the JavaScript branch. Also add or adjust a test in
runner-ast.test.ts to cover a .cts file using CommonJS-only syntax.
🤖 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.

Duplicate comments:
In `@src/engine/runner.ts`:
- Around line 196-216: The TypeScript parsing path in runner.ts still treats
.cts output as a module, so CommonJS-only syntax can fail to parse. Update the
TypeScript branch in the runner logic that calls Bun.Transpiler.transformSync
and parseJsModule so .cts files are parsed with script sourceType instead of the
default module grammar, mirroring the existing .cjs handling in the JavaScript
branch. Also add or adjust a test in runner-ast.test.ts to cover a .cts file
using CommonJS-only syntax.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c92e39af-084e-4fe2-b475-1e1f94c8529d

📥 Commits

Reviewing files that changed from the base of the PR and between 8c59cd8 and 7514ccd.

📒 Files selected for processing (7)
  • .archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • src/helpers/rules-shim.ts
  • tests/engine/runner-ast.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Smoke Test (Windows) / Windows
⚠️ CI failures not shown inline (4)

GitHub Actions: DCO / 0_DCO Sign-off Check.txt: feat: AST-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run base="21829b56e22cbf7442bc4fe66502ba988073c049"
 �[36;1mbase="21829b56e22cbf7442bc4fe66502ba988073c049"�[0m
 �[36;1mhead="7514ccd76a902bee80b3f40b2a83e10391697728"�[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 / DCO Sign-off Check: feat: AST-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run base="21829b56e22cbf7442bc4fe66502ba988073c049"
 �[36;1mbase="21829b56e22cbf7442bc4fe66502ba988073c049"�[0m
 �[36;1mhead="7514ccd76a902bee80b3f40b2a83e10391697728"�[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 #452 / Analyze (go): Code Quality: PR #452

Conclusion: failure

View job details

,"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/05 13:01:00 Autobuilder was built with go1.26.0, environment has go1.24.13
 [] [build-stderr] 2026/07/05 13:01:00 LGTM_SRC is /home/runner/work/cli/cli
 [] [build-stderr] 2026/07/05 13:01:00 Found no go.work files in the workspace; looking for go.mod files...
 [] [build-stderr] 2026/07/05 13:01:00 Found 1 go.mod files in: shims/go/go.mod.
 [] [build-stderr] 2026/07/05 13:01:00 Found 1 go.mod file(s).
 [] [build-stderr] 2026/07/05 13:01:00 Import path is 'github.com/archgate/cli'
 [] [build-stderr] 2026/07/...

GitHub Actions: Code Quality: PR #452 / 5_Analyze (go).txt: Code Quality: PR #452

Conclusion: failure

View job details

8 Extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/des.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Done extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 13:01:08 Processing package crypto/elliptic.
 [] [build-stderr] 2026/07/05 13:01:08 Extracting types for package crypto/elliptic.
 [] [build-...
🧰 Additional context used
📓 Path-based instructions (15)
src/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

src/**/*.ts: Use logError() from src/helpers/log.ts for user-facing errors instead of printing errors directly.
Exit with code 1 for 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 code 2.
Include actionable suggestions in user-facing error messages whenever possible.
Write user-facing errors to stderr via logError(); do not send them to stdout.
When findProjectRoot() returns null for commands that do not require .archgate/, fall back to process.cwd() as the path key or working directory.
Catch ExitPromptError from Inquirer in the top-level error boundary and treat it as user cancellation: exit with code 130 without logging an error or sending it to Sentry.
Do not use console.error() directly; use logError() for consistent formatting.
Do not exit with codes other than 0, 1, 2, or 130.
Do not send user-cancellation errors such as Inquirer ExitPromptError to Sentry; filter them in beforeSend.

src/**/*.ts: Use styleText(format, text) from node:util for 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 --json must emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports --json, use formatJSON() from src/helpers/output.ts for JSON serialization, and pass forcePretty: true when the user explicitly provided --json.
Use isAgentContext() from src/helpers/output.ts to 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 with console.log(), and send errors, warnings, and debug messages to stderr via logError(), logWarn(), and logDebug().
Keep CLI output concise and scannabl...

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
src/{helpers,engine}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

Do not use console.log(), console.warn(), or console.info() directly in helper or engine files; use logInfo() or logWarn() instead. Command files are exempt because they are the I/O layer.

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.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, use Bun.file() instead of fs.readFile() for simple reads.
Prefer node: built-in modules such as node:util, node:path, and node:fs over npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper like pick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; use bunx for one-off tools.

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast.test.ts
src/**/!(*platform).ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

src/**/!(*platform).ts: In src/ TypeScript source files, do not read process.platform directly; use src/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 in src/ TypeScript source.
When behavior differs between Linux and Windows, account for WSL by using isWSL() rather than assuming `

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
{src,tests}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)

{src,tests}/**/*.ts: Every TypeScript source file in src/ and tests/ must begin with // SPDX-License-Identifier: Apache-2.0 followed by // Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example #!/usr/bin/env bun in src/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:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast.test.ts
src/helpers/rules-shim.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

The generated .rules.ts shim must mirror RuleContext with the same single ast(path, language) method.

Files:

  • src/helpers/rules-shim.ts
**

⚙️ CodeRabbit configuration file

**: # CLAUDE.md

Archgate 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 wizard

Validation Gate

bun run validate must 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 .githooks run 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 ../.githooks

Opt out of a specific hook: git config --local hook.<name>.enabled false. Skip all hooks for a single commit: git commit --no-verify.

#...

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast.test.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.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • src/helpers/rules-shim.ts
  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
  • src/formats/rules.ts
  • tests/engine/runner-ast.test.ts
src/engine/

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

Do not expose or use raw subprocess primitives such as Bun.spawn, Bun.spawnSync, or child_process directly outside the sanctioned AST and git helpers.

Files:

  • src/engine/js-parser.ts
  • src/engine/rule-scanner.ts
  • src/engine/runner.ts
src/engine/rule-scanner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

Factor the duplicated parseModule() invocation into a shared exported parse helper instead of keeping inline copies in the scanner.

Files:

  • src/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/engine/runner.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

src/engine/runner.ts: Implement ctx.ast() inside createRuleContext() with internal dispatch only; rule authors must not see the dispatch mechanism.
For language: "typescript" and language: "javascript", ctx.ast() must reuse the existing in-process meriyah parser and must not spawn a subprocess.
For language: "python" and language: "ruby", ctx.ast() must invoke the language's standard-library AST facility through Bun.spawn using array-based arguments only.
ctx.ast() must perform guardrails in this order before any subprocess is spawned: path safety, language plausibility, interpreter availability probe, then guarded invocation.
ctx.ast() must throw on missing interpreter or parse failure; it must not return null or another sentinel.
The Python branch must run in isolated mode with -I, and must strip a leading UTF-8 BOM before parsing.
The Python/Ruby interpreter availability probe must be cached once per check invocation and must use platform-appropriate candidate executable names.
Do not trust node.loc for language: "typescript"; re-locate reported constructs in the original source before reporting line numbers.
Do not drop the Python -I flag when refactoring the guarded invocation.
Do not add per-language RuleContext methods such as pythonAst() or rubyAst(); expose only ast(path, language).

Files:

  • src/engine/runner.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, use safeParse(), and reuse AdrFrontmatterSchema.shape.* instead of duplicating enums.

Files:

  • src/formats/rules.ts
src/formats/rules.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

RuleContext must expose a single ast(path, language) method.

Files:

  • src/formats/rules.ts
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 under tests/ mirroring the src/ directory structure with <module-name>.test.ts naming.
Use temp directories (mkdtemp) for filesystem tests, and clean them up in afterEach or afterAll.
Close external SDK instances (servers, clients, transports, connections) in afterEach or afterAll, managing their lifecycle in hooks rather than inside individual test bodies.
When a test creates a temporary git repository and runs git commit, configure local user.email and user.name immediately after git init.
Test public module interfaces, not private implementation details.
Use descriptive test names that explain the expected behavior.
Every runnable test()/it() must contain at least one expect() assertion; smoke tests must make the contract explicit with expect(() => fn()).not.toThrow() or await expect(promise).resolves.toBeUndefined().
Use test.skip, test.skipIf, or test.todo for intentionally empty or disabled tests; do not use bare return or empty callbacks to skip work.
If the first expect() is being added to a previously assertion-less test file, add expect to the bun:test import.
When mocking fetch in tests, assign directly to globalThis.fetch and restore the original or use mock.restore() afterward.
Wrap spyOn() and inline mockImplementation() usage in try/finally, or create and restore spies in hooks, so mockRestore() always runs.
Only raise a per-test timeout above the global bun test --timeout 60000; never set a shorter per-test timeout.
Mock first-party modules with import * as mod plus spyOn(mod, "fn"), not mock.module().
When a test needs to redirect user-scope paths, mock os.homedir() instead of relying on HOME/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/engine/runner-ast.test.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 mutating process.platform directly.

Files:

  • tests/engine/runner-ast.test.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/rules-shim.ts
🔇 Additional comments (7)
.archgate/adrs/ARCH-022-ast-aware-rule-context.rules.ts (1)

59-86: LGTM!

src/engine/js-parser.ts (1)

27-45: LGTM!

src/engine/runner.ts (1)

143-195: LGTM!

Also applies to: 217-251, 373-375, 425-428, 465-466

src/formats/rules.ts (1)

65-133: LGTM!

Also applies to: 146-168

src/helpers/rules-shim.ts (1)

72-137: LGTM!

Also applies to: 148-169

tests/engine/runner-ast.test.ts (1)

93-511: LGTM!

src/engine/rule-scanner.ts (1)

3-3: 🎯 Functional Correctness

Clean type-level consolidation. The shared parseJsModule() helper keeps the scanner behavior unchanged.

…ds narrow

With per-language overloads returning EsTreeProgram / PythonAstModule
/ RubyAstNode, the `as { body: ... }` and `as { _type: ... }` casts
throughout rules, tests, and docs examples are dead weight. Removes
them and replaces local EsNode/EstreeStatement interfaces with the
ambient EsTreeNode/PythonAstNode from rules.d.ts, so consumers see
how the typed API is intended to be used — cast-free.

Walk helpers still cast `unknown` children to the node type; these
are inherent to tree traversal and cannot be removed without a
polymorphic tree library.

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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_24840329-e88a-41a6-9e7f-cc1987a3538a)

@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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_80d9a19d-dbbd-4d98-9254-9ee5744e11f1)

- probeInterpreter: add 5s timeout so a stalled binary (e.g. macOS
  Xcode dialog on python3) cannot hang the cached probe indefinitely
- runAstSubprocess: await proc.exited after kill on timeout so the
  subprocess is confirmed dead before throwing
- ARCH-008 rules: catch per-file parse errors so one unparseable file
  does not abort the entire rule via Promise.all rejection
- ARCH-004 barrel fallback: split on newlines instead of semicolons
  so a semicolon inside a module specifier string does not break the
  type-only barrel heuristic

Claude-Session: https://claude.ai/code/session_012tjbzRdRBG1SLVdXvTA9dX
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>

@rhuanbarreto rhuanbarreto left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re: guardrail-ordering rule uses loc — This is intentional. The rule compares loc positions against each other to verify ordering (is safePath before AST_LANGUAGE_EXTENSIONS before probeInterpreter before runAstSubprocess?). Transpilation shifts absolute line numbers but preserves relative ordering — statement A before statement B in the source is still before it after transpilation. The ARCH-022 Don't ("don't trust loc for reporting") applies to reporting lines to the user, not to internal ordinal comparisons.

Re: inject timeout for testing / no timeout test — The 15s timeout path is intentionally untested (confirmed in the adversarial review as an acceptable gap). Making it injectable is a valid follow-up but out of scope for this PR.

Re: missing sourceType: "script" test in js-parser.test.ts — This is tested through runChecks in tests/engine/runner-ast.test.ts (the .cjs sloppy-mode test), which exercises the full sourceType: "script" path end-to-end including globalReturn.

Re: .cts gap — Agreed this is a valid follow-up. .cts files are rare in practice; tracking separately.

Re: BOM test — The BOM codec fix is tested indirectly through the Python/Ruby serializer end-to-end tests (any BOM-bearing file on a Windows machine with default notepad encoding would exercise it). A dedicated BOM fixture test is nice-to-have but not blocking.

@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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_75d988a3-cf61-47fb-b34c-ecae28afed06)

@rhuanbarreto rhuanbarreto changed the title feat: AST-aware rule context (ctx.ast) for TS/JS/Python/Ruby feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby Jul 5, 2026
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 90.1% (7359 / 8170)
Threshold 90% minimum — met
Platforms Linux + Windows

Full HTML report available in workflow artifacts.

Per-directory breakdown
Directory Coverage Lines
src/commands/ 88.7% 1994 / 2249
src/engine/ 90.9% 1626 / 1788
src/formats/ 100.0% 142 / 142
src/helpers/ 90.1% 3597 / 3991

@rhuanbarreto

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🤖 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 @.archgate/adrs/ARCH-004-no-barrel-files.rules.ts:
- Around line 43-48: The fallback in isTypeOnlyBarrel only checks each trimmed
line prefix, so multi-line type-only re-exports like export type { ... } from
"./x" are incorrectly rejected when continuation lines are present. Update the
detection logic in isTypeOnlyBarrel to treat the whole statement as one unit
before checking, or use token-based parsing, so grouped export type blocks still
count as barrel files even when formatted across multiple lines.
🪄 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: a667b701-8226-41cc-8ec3-05abe8878803

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1dc38 and 1ede26b.

📒 Files selected for processing (11)
  • .archgate/adrs/ARCH-004-no-barrel-files.rules.ts
  • .archgate/adrs/ARCH-008-typed-command-options.rules.ts
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/reference/rule-api.mdx
  • src/engine/ast-support.ts
  • tests/engine/runner-ast.test.ts
💤 Files with no reviewable changes (8)
  • docs/src/content/docs/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/reference/rule-api.mdx
  • docs/src/content/docs/pt-br/guides/writing-rules.mdx
  • docs/public/llms-full.txt
  • docs/src/content/docs/guides/writing-rules.mdx
  • docs/src/content/docs/nb/reference/rule-api.mdx
  • tests/engine/runner-ast.test.ts
  • docs/src/content/docs/nb/guides/writing-rules.mdx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Cloudflare Pages
⚠️ CI failures not shown inline (7)

GitHub Actions: DCO / 0_DCO Sign-off Check.txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run base="21829b56e22cbf7442bc4fe66502ba988073c049"
 �[36;1mbase="21829b56e22cbf7442bc4fe66502ba988073c049"�[0m
 �[36;1mhead="1ede26be4da7ad38d82e7967a9cc7bfa90e77f92"�[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: Validate / 0_Validate Code.txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run # shim-tests is skipped when no shim files changed — treat skipped as success.
 �[36;1m# shim-tests is skipped when no shim files changed — treat skipped as success.�[0m
 �[36;1mSHIM_OK="skipped"�[0m
 �[36;1mif [[ "$SHIM_OK" == "skipped" ]]; then SHIM_OK="success"; fi�[0m
 �[36;1m�[0m
 �[36;1mif [[ "success" != "success" ]] || \�[0m
 �[36;1m   [[ "$SHIM_OK" != "success" ]] || \�[0m
 �[36;1m   [[ "success" != "success" ]] || \�[0m
 �[36;1m   [[ "success" != "success" ]] || \�[0m
 �[36;1m   [[ "success" != "success" ]] || \�[0m
 �[36;1m   [[ "success" != "success" ]] || \�[0m
 �[36;1m   [[ "success" != "success" ]]; then�[0m
 �[36;1m  echo "::error::One or more jobs failed:"�[0m

GitHub Actions: Validate / 1_Coverage Report.txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run COVERAGE="90.1"
 �[36;1mCOVERAGE="90.1"�[0m
 �[36;1mMIN_COVERAGE=90�[0m
 �[36;1mBELOW=$(awk "BEGIN{print ($COVERAGE < $MIN_COVERAGE) ? 1 : 0}")�[0m
 �[36;1mif [ "$BELOW" = "1" ]; then�[0m
 �[36;1m  echo "::error::Code coverage is ${COVERAGE}%, which is below the minimum threshold of ${MIN_COVERAGE}%."�[0m

GitHub Actions: Validate / 3_Smoke Test (Linux) _ Linux.txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run if [ -z "$ARCHGATE_VERSION" ]; then
 �[36;1mif [ -z "$ARCHGATE_VERSION" ]; then�[0m
 �[36;1m  # Find the newest release that already has the Linux asset uploaded.�[0m
 �[36;1m  # On release-commit pushes the Validate and Release workflows start�[0m
 �[36;1m  # concurrently, so the latest tag may exist before its binaries are�[0m
 �[36;1m  # uploaded by release-binaries.yml — hitting a 404.�[0m
 �[36;1m  asset="archgate-linux-x64.tar.gz"�[0m
 �[36;1m  tags="$(gh release list --limit 5 --json tagName --jq '.[].tagName' 2>/dev/null || true)"�[0m
 �[36;1m  if [ -z "$tags" ]; then�[0m
 �[36;1m    echo "::warning::No releases found, skipping install.sh smoke test"�[0m
 �[36;1m    exit 0�[0m
 �[36;1m  fi�[0m
 �[36;1m  found=""�[0m
 �[36;1m  for tag in $tags; do�[0m
 �[36;1m    assets="$(gh release view "$tag" --json assets --jq '.assets[].name' 2>/dev/null || true)"�[0m
 �[36;1m    if echo "$assets" | grep -qF "$asset"; then�[0m
 �[36;1m      ARCHGATE_VERSION="$tag"�[0m
 �[36;1m      found=1�[0m
 �[36;1m      break�[0m
 �[36;1m    fi�[0m
 �[36;1m  done�[0m
 �[36;1m  if [ -z "$found" ]; then�[0m
 �[36;1m    echo "::warning::No release with $asset found, skipping install.sh smoke test"�[0m
 �[36;1m    exit 0�[0m
 �[36;1m  fi�[0m
 �[36;1m  export ARCHGATE_VERSION�[0m
 �[36;1mfi�[0m
 �[36;1mecho "Testing install.sh with version $ARCHGATE_VERSION"�[0m
 �[36;1m�[0m
 �[36;1mARCHGATE_INSTALL_DIR="$(mktemp -d)"�[0m
 �[36;1mexport ARCHGATE_INSTALL_DIR�[0m
 �[36;1m�[0m
 �[36;1msh install.sh�[0m
 �[36;1m�[0m
 �[36;1mif [ ! -f "$ARCHGATE_INSTALL_DIR/archgate" ]; then�[0m
 �[36;1m  echo "::error::archgate binary not found at $ARCHGATE_INSTALL_DIR/archgate after install"�[0m

GitHub Actions: Validate / 4_Lint, Test & Check.txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run bun run docs/scripts/generate-llms-full.ts
 �[36;1mbun run docs/scripts/generate-llms-full.ts�[0m
 �[36;1mgit diff --exit-code docs/public/llms-full.txt || {�[0m
 �[36;1m  echo "::error::docs/public/llms-full.txt is out of date. Run 'bun run docs/scripts/generate-llms-full.ts' and commit the result."�[0m

GitHub Actions: Validate / 5_Zizmor (Workflow Security).txt: feat: ast-aware rule context (ctx.ast) for TS/JS/Python/Ruby

Conclusion: failure

View job details

##[group]Run "${GITHUB_ACTION_PATH}/action.sh"
 �[36;1m"${GITHUB_ACTION_PATH}/action.sh"�[0m
 shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
 env:
   ARCHGATE_TELEMETRY: 0
   GHA_ZIZMOR_INPUTS: .
   GHA_ZIZMOR_ONLINE_AUDITS: true
   GHA_ZIZMOR_PERSONA: regular
   GHA_ZIZMOR_MIN_SEVERITY:
   GHA_ZIZMOR_MIN_CONFIDENCE:
   GHA_ZIZMOR_VERSION: latest
   GHA_ZIZMOR_***REDACTED***
   GHA_ZIZMOR_ADVANCED_SECURITY: true
   GHA_ZIZMOR_COLOR: true
   GHA_ZIZMOR_ANNOTATIONS: false
   GHA_ZIZMOR_CONFIG: zizmor.yml
   GHA_ZIZMOR_FAIL_ON_NO_INPUTS: true
 ##[endgroup]
 Unable to find image 'ghcr.io/zizmorcore/zizmor:latest@sha256:***REDACTED***' locally
 ghcr.io/zizmorcore/zizmor@sha256:***REDACTED***: Pulling from zizmorcore/zizmor
 0514fcfd8680: Pulling fs layer
 7677d1f93ece: Pulling fs layer
 d3cc9d64a2f9: Pulling fs layer
 c920184a3208: Pulling fs layer
 9201e51fe8c1: Pulling fs layer
 69cbafd2417b: Pulling fs layer
 9041c2dcdd9f: Pulling fs layer
 8d99fd8fea9c: Pulling fs layer
 5f460b97a17e: Pulling fs layer
 cdea145aa115: Pulling fs layer
 5bb3233a44f9: Pulling fs layer
 85c67978dd22: Pulling fs layer
 8d99fd8fea9c: Waiting
 5f460b97a17e: Waiting
 5bb3233a44f9: Waiting
 c920184a3208: Waiting
 85c67978dd22: Waiting
 9201e51fe8c1: Waiting
 cdea145aa115: Waiting
 69cbafd2417b: Waiting
 9041c2dcdd9f: Waiting
 0514fcfd8680: Verifying Checksum
 0514fcfd8680: Download complete
 d3cc9d64a2f9: Verifying Checksum
 d3cc9d64a2f9: Download complete
 7677d1f93ece: Verifying Checksum
 7677d1f93ece: Download complete
 0514fcfd8680: Pull complete
 c920184a3208: Download complete
 9201e51fe8c1: Download complete
 69cbafd2417b: Verifying Checksum
 69cbafd2417b: Download complete
 5f460b97a17e: Verifying Checksum
 5f460b97a17e: Download complete
 8d99fd8fea9c: Verifying Checksum
 8d99fd8fea9c: Download complete
 9041c2dcdd9f: Verifying Checksum
 9041c2dcdd9f: Download complete
 7677d1f93ece: Pull complete
 cdea145aa115: Verifying Checksum
 cdea145aa115: Download complete
 5bb32...

GitHub Actions: Code Quality: PR #452 / 1_Analyze (go).txt: Code Quality: PR #452

Conclusion: failure

View job details

Extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/des.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/des.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Done extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/05 16:04:16 Processing package crypto/elliptic.
 [] [build-stderr] 2026/07/05 16:04:16 Extracting types for package crypto/elliptic.
 [] [build-st...
🧰 Additional context used
📓 Path-based instructions (8)
.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-004-no-barrel-files.rules.ts
  • .archgate/adrs/ARCH-008-typed-command-options.rules.ts
src/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

src/**/*.ts: Use logError() from src/helpers/log.ts for user-facing errors instead of printing errors directly.
Exit with code 1 for 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 code 2.
Include actionable suggestions in user-facing error messages whenever possible.
Write user-facing errors to stderr via logError(); do not send them to stdout.
When findProjectRoot() returns null for commands that do not require .archgate/, fall back to process.cwd() as the path key or working directory.
Catch ExitPromptError from Inquirer in the top-level error boundary and treat it as user cancellation: exit with code 130 without logging an error or sending it to Sentry.
Do not use console.error() directly; use logError() for consistent formatting.
Do not exit with codes other than 0, 1, 2, or 130.
Do not send user-cancellation errors such as Inquirer ExitPromptError to Sentry; filter them in beforeSend.

src/**/*.ts: Use styleText(format, text) from node:util for 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 --json must emit machine-readable JSON to stdout with no colors or decorative formatting.
When a command supports --json, use formatJSON() from src/helpers/output.ts for JSON serialization, and pass forcePretty: true when the user explicitly provided --json.
Use isAgentContext() from src/helpers/output.ts to 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 with console.log(), and send errors, warnings, and debug messages to stderr via logError(), logWarn(), and logDebug().
Keep CLI output concise and scannabl...

Files:

  • src/engine/ast-support.ts
src/{helpers,engine}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-002-error-handling.md)

Do not use console.log(), console.warn(), or console.info() directly in helper or engine files; use logInfo() or logWarn() instead. Command files are exempt because they are the I/O layer.

Files:

  • src/engine/ast-support.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, use Bun.file() instead of fs.readFile() for simple reads.
Prefer node: built-in modules such as node:util, node:path, and node:fs over npm alternatives.
Do not use utility libraries for single functions, such as importing lodash for one helper like pick.
Do not use path aliases (tsconfig paths); use relative imports with Bun's native module resolution.
Do not install packages globally during development; use bunx for one-off tools.

Files:

  • src/engine/ast-support.ts
src/**/!(*platform).ts

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-009-platform-detection-helper.md)

src/**/!(*platform).ts: In src/ TypeScript source files, do not read process.platform directly; use src/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 in src/ TypeScript source.
When behavior differs between Linux and Windows, account for WSL by using isWSL() rather than assuming `

Files:

  • src/engine/ast-support.ts
{src,tests}/**/*.ts

📄 CodeRabbit inference engine (.archgate/adrs/LEGAL-001-spdx-license-headers.md)

{src,tests}/**/*.ts: Every TypeScript source file in src/ and tests/ must begin with // SPDX-License-Identifier: Apache-2.0 followed by // Copyright 2026 Archgate.
If a TypeScript file has a shebang line (for example #!/usr/bin/env bun in src/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:

  • src/engine/ast-support.ts
src/engine/**

📄 CodeRabbit inference engine (.archgate/adrs/ARCH-022-ast-aware-rule-context.md)

Do not introduce unsanctioned Bun.spawn/Bun.spawnSync calls or child_process imports anywhere in the engine outside the approved helpers.

Files:

  • src/engine/ast-support.ts
**

⚙️ CodeRabbit configuration file

**: # CLAUDE.md

Archgate 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 wizard

Validation Gate

bun run validate must 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 .githooks run 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 ../.githooks

Opt out of a specific hook: git config --local hook.<name>.enabled false. Skip all hooks for a single commit: git commit --no-verify.

#...

Files:

  • src/engine/ast-support.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.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • src/engine/ast-support.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: archgate/cli

Timestamp: 2026-07-06T01:59:20.557Z
Learning: Do not add tree-sitter, web-tree-sitter, or any other new production dependency for this ADR.
Learnt from: CR
Repo: archgate/cli

Timestamp: 2026-07-06T01:59:20.557Z
Learning: Do not normalize Python or Ruby AST output into a single ESTree-like shape; `ctx.ast()` may return language-native node shapes.
🔇 Additional comments (3)
.archgate/adrs/ARCH-008-typed-command-options.rules.ts (1)

101-106: LGTM!

Also applies to: 145-150

src/engine/ast-support.ts (2)

110-150: LGTM!


176-182: 🩺 Stability & Availability

Timeout branch still leaves stream readers unsettled. If new Response(proc.stdout).text() or new Response(proc.stderr).text() can reject after proc.kill(), this path can turn a timeout into an unhandled rejection. await Promise.allSettled([stdoutPromise, stderrPromise]) before throwing.

Comment thread .archgate/adrs/ARCH-004-no-barrel-files.rules.ts Outdated
Track brace depth in isTypeOnlyBarrel so continuation lines inside
destructured export type { A, B, } blocks are recognized as part of
the enclosing import/export statement, not as separate non-barrel lines.

Claude-Session: https://claude.ai/code/session_01H7XPPVhN1t6HzH8F3xN4DP
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
@cursor

cursor Bot commented Jul 6, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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_c0897a2b-6629-48c7-81bf-7951b26299db)

@rhuanbarreto

Copy link
Copy Markdown
Contributor Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant