@expo/code-review-cli 0.2.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +183 -6
- package/build/cli.js +24 -17
- package/build/commands/ci.js +427 -28
- package/build/commands/dismiss.js +16 -16
- package/build/commands/doctor.js +172 -32
- package/build/commands/init.js +244 -34
- package/build/commands/review.js +124 -30
- package/build/commands/verify-config.js +214 -0
- package/build/config/load.js +155 -52
- package/build/config/routing.js +122 -0
- package/build/config/schema.js +127 -8
- package/build/core/auth.js +101 -38
- package/build/core/coordinator.js +5 -5
- package/build/core/diff.js +19 -19
- package/build/core/exec.js +10 -10
- package/build/core/log.js +3 -3
- package/build/core/noise.js +52 -52
- package/build/core/opencode.js +98 -44
- package/build/core/prompts.js +157 -148
- package/build/core/render.js +202 -48
- package/build/core/review.js +187 -81
- package/build/core/router.js +10 -10
- package/build/core/schema.js +26 -12
- package/build/core/step-summary.js +18 -0
- package/build/core/suppress.js +7 -7
- package/build/core/tools.js +9 -9
- package/build/core/util.js +2 -2
- package/build/core/verify.js +25 -25
- package/build/reporters/github.js +103 -51
- package/build/reporters/terminal.js +19 -19
- package/build/sources/github-pr.js +21 -21
- package/build/sources/local-git.js +20 -20
- package/build/sources/source.js +35 -1
- package/package.json +6 -1
- package/templates/agents/security.md +5 -0
- package/templates/command.yml +164 -0
- package/templates/config.jsonc +10 -0
- package/templates/coordinator.md +5 -3
- package/templates/dismiss.yml +110 -0
- package/templates/routing.jsonc +27 -0
- package/templates/scope-config.jsonc +25 -0
- package/templates/shared.md +12 -0
- package/templates/workflow.yml +58 -23
package/templates/workflow.yml
CHANGED
|
@@ -17,36 +17,30 @@ concurrency:
|
|
|
17
17
|
jobs:
|
|
18
18
|
review:
|
|
19
19
|
runs-on: ubuntu-latest
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
env:
|
|
21
|
+
# Version of the published engine used for BOTH the guard and the review, so
|
|
22
|
+
# the guard that clears a config is the same engine that then reads it. Override
|
|
23
|
+
# with repo variable ECR_VERSION; pin to a specific version to freeze it.
|
|
24
|
+
ECR_VERSION: ${{ vars.ECR_VERSION || 'latest' }}
|
|
25
|
+
# Trigger policy lives in .expo-code-review/config.jsonc (review.trigger); `ecr ci`
|
|
26
|
+
# self-gates on it (and honors the ai-review:skip label). This coarse gate just
|
|
27
|
+
# avoids spinning up a runner for a PR that explicitly opted out. Uses the array
|
|
28
|
+
# form of contains() for an EXACT label match ("ai-review:skip" is not "ai-review").
|
|
29
|
+
# Prefer to gate entirely here instead? Set config trigger to "label" and replace
|
|
30
|
+
# the line below with, e.g.:
|
|
31
|
+
# if: contains(github.event.pull_request.labels.*.name, 'ai-review')
|
|
32
|
+
if: ${{ !contains(github.event.pull_request.labels.*.name, 'ai-review:skip') }}
|
|
23
33
|
# Backstop so a stalled review fails fast instead of hanging.
|
|
24
34
|
timeout-minutes: 60
|
|
25
35
|
# A reviewer failure must never fail the PR's checks.
|
|
26
36
|
continue-on-error: true
|
|
27
37
|
steps:
|
|
28
|
-
- uses: actions/checkout@
|
|
38
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
29
39
|
with:
|
|
30
40
|
# Shallow is enough — the reviewer gets the diff from the API (`gh`).
|
|
31
41
|
fetch-depth: 1
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
# .expo-code-review/config.jsonc, whose auth.tokenEnv names the env var the CLI
|
|
35
|
-
# forwards as the model credential. Refuse to run unless it's the expected value
|
|
36
|
-
# (below / repo var ECR_EXPECTED_TOKEN_ENV) so a PR can't repoint it at another
|
|
37
|
-
# secret in the runner. Keep this in sync with auth.tokenEnv in config.jsonc.
|
|
38
|
-
- name: Guard config.jsonc tokenEnv
|
|
39
|
-
env:
|
|
40
|
-
EXPECTED: ${{ vars.ECR_EXPECTED_TOKEN_ENV || 'ANTHROPIC_OAUTH_API_KEY' }}
|
|
41
|
-
run: |
|
|
42
|
-
values=$(grep -oE '"tokenEnv"[[:space:]]*:[[:space:]]*"[A-Za-z0-9_]+"' .expo-code-review/config.jsonc | sed -E 's/.*"([A-Za-z0-9_]+)"$/\1/')
|
|
43
|
-
count=$(printf '%s\n' "$values" | grep -c .)
|
|
44
|
-
if [ "$count" != "1" ] || [ "$values" != "$EXPECTED" ]; then
|
|
45
|
-
echo "::error::.expo-code-review/config.jsonc auth.tokenEnv must be \"$EXPECTED\" (found: \"${values:-none}\"). Refusing to run so a PR can't redirect which secret is forwarded to the model provider."
|
|
46
|
-
exit 1
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
- uses: actions/setup-node@v5
|
|
43
|
+
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
50
44
|
with:
|
|
51
45
|
node-version: 24
|
|
52
46
|
# The reviewer runs via npx and never installs with a package manager, so
|
|
@@ -54,16 +48,57 @@ jobs:
|
|
|
54
48
|
# to save an empty cache and error).
|
|
55
49
|
package-manager-cache: false
|
|
56
50
|
|
|
51
|
+
# SECURITY: this workflow checks out the PR's code, including every
|
|
52
|
+
# .expo-code-review/config.jsonc + routing.jsonc, whose auth.tokenEnv names the
|
|
53
|
+
# env var the CLI forwards as the model credential. The canonical guard ships
|
|
54
|
+
# with the CLI: `ecr verify-config` sweeps every config (root + routing + all
|
|
55
|
+
# scopes, referenced or not) with the engine's real JSONC parser and refuses
|
|
56
|
+
# unless tokenEnv appears exactly once, in a ROOT-owned file, equal to the
|
|
57
|
+
# expected value (repo var ECR_EXPECTED_TOKEN_ENV) — so a PR can't repoint it at
|
|
58
|
+
# another runner secret, sneak in a JSON-escaped key, or stage an unreferenced
|
|
59
|
+
# scope config with its own auth. This is layer 2; layer 1 is the runtime
|
|
60
|
+
# ECR_EXPECTED_TOKEN_ENV lock in `ecr ci` itself, so guard/loader drift fails safe.
|
|
61
|
+
#
|
|
62
|
+
# This step MUST run BEFORE `ecr ci` (before any PR code is built or loaded).
|
|
63
|
+
# Only setup-node (runtime install) precedes it; running the PUBLISHED package
|
|
64
|
+
# via npx is safe pre-review because npx fetches @expo/code-review-cli@$ECR_VERSION
|
|
65
|
+
# from the registry — it never builds or executes the PR's code.
|
|
66
|
+
- name: Guard config tokenEnv (root + routing + all scopes)
|
|
67
|
+
env:
|
|
68
|
+
ECR_EXPECTED_TOKEN_ENV: ${{ vars.ECR_EXPECTED_TOKEN_ENV || 'ANTHROPIC_OAUTH_API_KEY' }}
|
|
69
|
+
run: npx --yes -p "@expo/code-review-cli@$ECR_VERSION" ecr verify-config
|
|
70
|
+
|
|
57
71
|
- name: Run AI review
|
|
58
72
|
# npx installs @expo/code-review-cli and its bundled `opencode` binary and
|
|
59
|
-
# puts them on PATH for this process
|
|
60
|
-
run: npx --yes -p "@expo/code-review-cli
|
|
73
|
+
# puts them on PATH for this process — the SAME $ECR_VERSION the guard cleared.
|
|
74
|
+
run: npx --yes -p "@expo/code-review-cli@$ECR_VERSION" ecr ci
|
|
61
75
|
continue-on-error: true
|
|
62
76
|
env:
|
|
63
77
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
78
|
+
# Layer-1 auth lock: the CLI refuses to run when the tokenEnv it would
|
|
79
|
+
# honor (root config.jsonc, or routing.jsonc defaults.auth) differs from
|
|
80
|
+
# this — it catches what the guard step above can't. Keep it in sync
|
|
81
|
+
# with the guard.
|
|
82
|
+
ECR_EXPECTED_TOKEN_ENV: ${{ vars.ECR_EXPECTED_TOKEN_ENV || 'ANTHROPIC_OAUTH_API_KEY' }}
|
|
64
83
|
# Claude Pro/Max OAuth token (from `claude setup-token`) — the env var
|
|
65
84
|
# named by auth.tokenEnv in config.jsonc. Store it as a repo secret.
|
|
66
85
|
# (For an API key instead, set auth.mode "api-key" and pass that key here.)
|
|
67
86
|
ANTHROPIC_OAUTH_API_KEY: ${{ secrets.ANTHROPIC_OAUTH_API_KEY }}
|
|
68
87
|
# Optional: override the model for every agent (uses your OpenCode login).
|
|
69
88
|
REVIEWER_MODEL: ${{ vars.REVIEWER_MODEL }}
|
|
89
|
+
|
|
90
|
+
# Observability: the per-run log (token/cache/cost totals + per-pass timing +
|
|
91
|
+
# coverage notes) is written under .expo-code-review/.runs/ but git-ignored, so
|
|
92
|
+
# in CI it is otherwise ephemeral — gone when the runner is torn down. Upload it
|
|
93
|
+
# as an artifact so a reviewer run can be inspected after the fact (why a finding
|
|
94
|
+
# did/didn't surface, cache-reuse, spend). always() so it is captured even when
|
|
95
|
+
# the review step timed out or errored; if-no-files-found: ignore because a run
|
|
96
|
+
# that failed before writing the log (or a no-op skip) legitimately has no file.
|
|
97
|
+
- name: Upload review run log
|
|
98
|
+
if: always()
|
|
99
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
100
|
+
with:
|
|
101
|
+
name: review-run-log-pr${{ github.event.pull_request.number }}
|
|
102
|
+
path: .expo-code-review/.runs/reviews.jsonl
|
|
103
|
+
if-no-files-found: ignore
|
|
104
|
+
retention-days: 14
|