@delegance/claude-autopilot 1.9.0 → 2.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.0] — 2026-04-22
4
+
5
+ ### Added
6
+ - **Risk-weighted file ordering** (`src/core/chunking/risk-ranker.ts`) — ranks files before sending to LLM: protected paths (score 100) → auth/security (80) → payment/billing (70) → core logic (50) → config files (40) → everything else (30) → tests (10) → docs (5); ensures most sensitive code appears at the start of the LLM's context window
7
+ - `BuildChunksInput.protectedPaths` — passed from config through review-phase to ranker so glob patterns from `protectedPaths:` config key are respected
8
+ - 9 new tests for `rankByRisk` — **224 total**
9
+
10
+ ## [2.0.0] — 2026-04-22
11
+
12
+ ### Added
13
+ - **`autopilot ci`** — opinionated single-command CI entrypoint; defaults to `--post-comments`, `--format sarif`, and base ref from `GITHUB_BASE_REF`/`CI_MERGE_REQUEST_TARGET_BRANCH_NAME`/`HEAD~1`; supports `--base`, `--output`, `--no-post-comments`
14
+ - **`.github/actions/ci/action.yml`** — composite GitHub Actions action; accepts `anthropic-api-key`, `openai-api-key`, `gemini-api-key`, `groq-api-key`, `base-ref`, `config`, `sarif-output`, `post-comments` inputs; runs `npx autopilot ci`, uploads SARIF via `codeql-action/upload-sarif@v3`
15
+ - **Updated `skills/autopilot.md`** — complete rewrite covering all adapters, auto-detection, `--post-comments`, `ci` command, action.yml usage
16
+
3
17
  ## [1.9.0] — 2026-04-22
4
18
 
5
19
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delegance/claude-autopilot",
3
- "version": "1.9.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "description": "Claude Code automation pipeline: spec → plan → implement → validate → PR",
6
6
  "keywords": [
@@ -5,138 +5,153 @@ description: Run the @delegance/claude-autopilot code review pipeline — static
5
5
 
6
6
  # autopilot — Code Review Pipeline
7
7
 
8
- Runs static rules, optional LLM review (Codex), and impact-aware snapshot regression tests on git-changed files. Outputs findings inline and optionally as SARIF for GitHub Code Scanning.
8
+ Runs static rules, optional LLM review, and impact-aware snapshot regression on git-changed files. Auto-detects stack, protected paths, and test command from the project. Outputs findings inline and optionally as SARIF for GitHub Code Scanning.
9
9
 
10
10
  ## When to Use
11
11
 
12
- - Before creating a PR (catch issues before review)
13
- - After completing a feature branch (validate the full changeset)
14
- - Inside a CI pipeline step (use `--format sarif --output results.sarif`)
15
- - Anytime `validate` is called in a dev pipeline
12
+ - Before creating a PR: `npx autopilot run --base main`
13
+ - Inside CI: `npx autopilot ci` (one-command, posts PR comment + SARIF)
14
+ - Dev loop: `npx autopilot watch`
15
+ - First setup: `npx autopilot setup && npx autopilot doctor`
16
16
 
17
17
  ## Prerequisites
18
18
 
19
- Run `npx autopilot doctor` once per project setup to verify:
20
- - Node 22+, tsx, gh CLI authenticated, claude CLI, OPENAI_API_KEY, git user config
19
+ ```bash
20
+ npx autopilot doctor # checks Node 22+, tsx, gh CLI, API key, git config
21
+ ```
21
22
 
22
23
  ## Commands
23
24
 
24
- ### Run pipeline on changed files
25
+ ### `run` pipeline on git-changed files
25
26
 
26
27
  ```bash
27
- # Diff against HEAD~1 (default — last commit)
28
- npx autopilot run
29
-
30
- # Diff against a branch (typical pre-PR use)
31
- npx autopilot run --base main
32
-
33
- # Explicit file list (skip git detection)
34
- npx autopilot run --files src/foo.ts,src/bar.ts
35
-
36
- # Dry run — show what would run, no execution
37
- npx autopilot run --dry-run
38
-
39
- # SARIF output for GitHub Code Scanning
28
+ npx autopilot run # diff HEAD~1 (default)
29
+ npx autopilot run --base main # diff against branch
30
+ npx autopilot run --files src/a.ts,src/b.ts # explicit files
31
+ npx autopilot run --dry-run # show what would run
32
+ npx autopilot run --post-comments # post/update summary on open PR
40
33
  npx autopilot run --format sarif --output autopilot.sarif
41
34
  ```
42
35
 
43
- ### Zero-prompt setup (new project)
36
+ ### `ci` opinionated CI entrypoint
44
37
 
45
38
  ```bash
46
- npx autopilot setup
39
+ npx autopilot ci # base=GITHUB_BASE_REF, post-comments=true, sarif written
40
+ npx autopilot ci --base develop
41
+ npx autopilot ci --no-post-comments
42
+ npx autopilot ci --output results.sarif
47
43
  ```
48
44
 
49
- Auto-detects project type (Go, Rails, FastAPI, T3, Next.js+Supabase), writes `autopilot.config.yaml`, installs pre-push hook, runs doctor.
45
+ Equivalent to `run --base <ref> --post-comments --format sarif --output <path>`. Base ref resolves from `GITHUB_BASE_REF` `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` `HEAD~1`.
50
46
 
51
- ### Check prerequisites
47
+ ### `setup` — zero-prompt first run
52
48
 
53
49
  ```bash
54
- npx autopilot doctor
50
+ npx autopilot setup # auto-detect stack, write config, install hook
51
+ npx autopilot setup --force # overwrite existing config
55
52
  ```
56
53
 
57
- Exits 1 if blockers found. Safe to re-run anytime.
54
+ Auto-detects: Go, Rails, FastAPI, T3, Next.js+Supabase. Runs doctor at end.
58
55
 
59
- ### Watch mode (dev loop)
56
+ ### `watch` dev loop
60
57
 
61
58
  ```bash
62
- npx autopilot watch # re-run on every file save
59
+ npx autopilot watch
63
60
  npx autopilot watch --debounce 500
64
61
  ```
65
62
 
66
- ### Snapshot regression testing
63
+ ### `autoregress` — snapshot regression
67
64
 
68
65
  ```bash
69
- # Generate baselines for changed files (requires OPENAI_API_KEY)
70
- npx autopilot autoregress generate
71
-
72
- # Run only impact-selected snapshots (default fast)
73
- npx autopilot autoregress run
74
-
75
- # Run all snapshots
76
- npx autopilot autoregress run --all
77
-
78
- # Show diffs vs baselines
79
- npx autopilot autoregress diff
80
-
81
- # Overwrite baselines after intentional behavior change
82
- npx autopilot autoregress update
66
+ npx autopilot autoregress generate # create baselines for changed files
67
+ npx autopilot autoregress run # run impact-selected snapshots
68
+ npx autopilot autoregress run --all # run all snapshots
69
+ npx autopilot autoregress diff # show diffs vs baselines
70
+ npx autopilot autoregress update # overwrite baselines after intentional change
83
71
  ```
84
72
 
85
- ### Pre-push git hook
73
+ ### `hook` — pre-push git hook
86
74
 
87
75
  ```bash
88
- npx autopilot hook install # write .git/hooks/pre-push
76
+ npx autopilot hook install
89
77
  npx autopilot hook uninstall
90
78
  npx autopilot hook status
91
79
  ```
92
80
 
81
+ ## LLM Review Adapters
82
+
83
+ Configure via `reviewEngine.adapter` in `autopilot.config.yaml`:
84
+
85
+ | Adapter | Key env var | Notes |
86
+ |---------|-------------|-------|
87
+ | `auto` | any | Picks available provider; prefers the one already used in code |
88
+ | `claude` | `ANTHROPIC_API_KEY` | Claude Opus 4.7 |
89
+ | `gemini` | `GEMINI_API_KEY` or `GOOGLE_API_KEY` | Gemini 2.5 Pro, 1M context |
90
+ | `codex` | `OPENAI_API_KEY` | gpt-5.3-codex via responses API |
91
+ | `openai-compatible` | configurable | Any OpenAI-API endpoint (Groq, Ollama, Together) |
92
+
93
+ `auto` priority order: Anthropic → Gemini → OpenAI → Groq. When multiple keys are present, `auto` scans the project source files and prefers the provider already referenced most.
94
+
95
+ ## Auto-Detection
96
+
97
+ When config fields are absent, `autopilot run` fills them in automatically:
98
+
99
+ - **stack** — parsed from `package.json`, `go.mod`, `Cargo.toml`, `requirements.txt`, `Gemfile`; injected into review prompt
100
+ - **protectedPaths** — migration dirs (`data/deltas/`, `migrations/`, `prisma/migrations/`, etc.), schema files, infra dirs (`terraform/`, `.github/workflows/`)
101
+ - **testCommand** — re-detected at run time from project files; set `testCommand: null` to disable explicitly
102
+ - **git context** — branch + last commit injected as `Change context: branch: X | last commit: Y`
103
+
104
+ Detection lines are printed dim after the file count: `auto-detected: stack: Next.js + Supabase | protected: data/deltas/** ...`
105
+
93
106
  ## Interpreting Results
94
107
 
95
- **Exit code 0** — no findings, or only warnings. Safe to proceed.
108
+ **Exit code 0** — pass or warnings only. Safe to proceed.
109
+ **Exit code 1** — blocking findings. Fix before merging.
96
110
 
97
- **Exit code 1** one or more blocking findings. Fix before merging.
111
+ Finding severities: `critical` blocks merge, `warning` should fix, `note` informational.
98
112
 
99
- **Finding severities:**
100
- - `error` — blocks merge (hardcoded secrets, npm audit Critical/High, failed tests)
101
- - `warning` — should fix, won't block
102
- - `info` — informational
113
+ PR comment (via `--post-comments` or `ci`): status badge, phase table, critical/warning findings, cost footer. Edits existing comment on re-runs (tracked via `<!-- autopilot-review -->` marker).
103
114
 
104
- **SARIF output** upload to GitHub Code Scanning with `github/codeql-action/upload-sarif@v3` for inline PR annotations.
115
+ SARIF output: upload with `github/codeql-action/upload-sarif@v3` for inline PR diff annotations. Also auto-emits `::error`/`::warning` annotations when `GITHUB_ACTIONS=true`.
105
116
 
106
117
  ## Config (`autopilot.config.yaml`)
107
118
 
108
119
  ```yaml
109
120
  configVersion: 1
110
121
  reviewEngine:
111
- adapter: codex # LLM review via OpenAI (requires OPENAI_API_KEY)
112
- testCommand: npm test
113
- protectedPaths:
114
- - src/core/**
122
+ adapter: auto # auto, claude, gemini, codex, openai-compatible
123
+ testCommand: npm test # null to disable
124
+ protectedPaths: # auto-detected if omitted
125
+ - data/deltas/**
126
+ - .github/workflows/**
115
127
  staticRules:
116
128
  - hardcoded-secrets
117
129
  - npm-audit
130
+ - package-lock-sync
131
+ - console-log
132
+ - todo-fixme
133
+ - large-file
134
+ - missing-tests
118
135
  ```
119
136
 
120
- Full schema and preset defaults: `node_modules/@delegance/claude-autopilot/presets/<name>/autopilot.config.yaml`
137
+ Preset defaults at: `node_modules/@delegance/claude-autopilot/presets/<name>/autopilot.config.yaml`
121
138
 
122
- ## Integration with Development Pipeline
139
+ ## GitHub Actions
140
+
141
+ ```yaml
142
+ - uses: axledbetter/claude-autopilot/.github/actions/ci@main
143
+ with:
144
+ anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} # or openai/gemini/groq
145
+ ```
146
+
147
+ Runs `npx autopilot ci`, uploads SARIF, annotates PR diff. All API key inputs optional — whichever is set gets used by `auto`.
123
148
 
124
- In a full spec→PR pipeline, `autopilot run` replaces the validate step:
149
+ ## Integration with Development Pipeline
125
150
 
126
151
  ```bash
127
- # After implementing feature on branch
152
+ # After implementing feature
128
153
  npx autopilot run --base main
129
154
 
130
155
  # If findings → fix → re-run (max 3 iterations)
131
156
  # If clean → push → create PR
132
157
  ```
133
-
134
- ## GitHub Actions
135
-
136
- ```yaml
137
- - uses: axledbetter/claude-autopilot/.github/actions/ci@main
138
- with:
139
- openai-api-key: ${{ secrets.OPENAI_API_KEY }}
140
- ```
141
-
142
- Runs the pipeline, uploads SARIF, annotates the PR diff inline.
package/src/cli/ci.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { runCommand } from './run.ts';
2
+
3
+ export interface CiCommandOptions {
4
+ cwd?: string;
5
+ configPath?: string;
6
+ base?: string;
7
+ postComments?: boolean;
8
+ sarifOutput?: string;
9
+ }
10
+
11
+ /**
12
+ * `autopilot ci` — opinionated single-command CI entrypoint.
13
+ *
14
+ * Equivalent to:
15
+ * autopilot run --base <ref> --post-comments --format sarif --output <path>
16
+ *
17
+ * Defaults:
18
+ * base GITHUB_BASE_REF → HEAD~1
19
+ * output autopilot.sarif
20
+ * post-comments true (skip if no PR detected — run.ts handles gracefully)
21
+ */
22
+ export async function runCi(options: CiCommandOptions = {}): Promise<number> {
23
+ const base = options.base
24
+ ?? process.env.GITHUB_BASE_REF
25
+ ?? process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME // GitLab
26
+ ?? 'HEAD~1';
27
+
28
+ const sarifOutput = options.sarifOutput ?? 'autopilot.sarif';
29
+
30
+ return runCommand({
31
+ cwd: options.cwd,
32
+ configPath: options.configPath,
33
+ base,
34
+ postComments: options.postComments ?? true,
35
+ format: 'sarif',
36
+ outputPath: sarifOutput,
37
+ });
38
+ }
package/src/cli/index.ts CHANGED
@@ -14,6 +14,7 @@ import { runCommand } from './run.ts';
14
14
  import { runWatch } from './watch.ts';
15
15
  import { runSetup } from './setup.ts';
16
16
  import { runDoctor } from './preflight.ts';
17
+ import { runCi } from './ci.ts';
17
18
 
18
19
  const args = process.argv.slice(2);
19
20
 
@@ -27,7 +28,7 @@ if (args[0] === '--version' || args[0] === '-v') {
27
28
  process.exit(0);
28
29
  }
29
30
 
30
- const SUBCOMMANDS = ['init', 'run', 'watch', 'hook', 'autoregress', 'doctor', 'preflight', 'setup', 'help', '--help', '-h'] as const;
31
+ const SUBCOMMANDS = ['init', 'run', 'ci', 'watch', 'hook', 'autoregress', 'doctor', 'preflight', 'setup', 'help', '--help', '-h'] as const;
31
32
  const VALUE_FLAGS = ['base', 'config', 'files', 'format', 'output', 'debounce'];
32
33
 
33
34
  // Detect first non-flag arg as subcommand, default to 'run'
@@ -145,6 +146,21 @@ switch (subcommand) {
145
146
  break;
146
147
  }
147
148
 
149
+ case 'ci': {
150
+ const base = flag('base');
151
+ const config = flag('config');
152
+ const outputPath = flag('output');
153
+ const noPostComments = boolFlag('no-post-comments');
154
+ const code = await runCi({
155
+ configPath: config,
156
+ base,
157
+ sarifOutput: outputPath,
158
+ postComments: noPostComments ? false : undefined,
159
+ });
160
+ process.exit(code);
161
+ break;
162
+ }
163
+
148
164
  case 'hook': {
149
165
  const { runHook } = await import('./hook.ts');
150
166
  const hookSub = args[1] ?? 'status';
@@ -2,6 +2,7 @@ import * as fs from 'node:fs/promises';
2
2
  import * as path from 'node:path';
3
3
  import type { ReviewEngine, ReviewInput } from '../../adapters/review-engine/types.ts';
4
4
  import type { AutopilotConfig } from '../config/types.ts';
5
+ import { rankByRisk } from './risk-ranker.ts';
5
6
 
6
7
  export interface ReviewChunk {
7
8
  content: string;
@@ -15,6 +16,7 @@ export interface BuildChunksInput {
15
16
  chunking?: AutopilotConfig['chunking'];
16
17
  engine: ReviewEngine;
17
18
  cwd?: string;
19
+ protectedPaths?: string[];
18
20
  }
19
21
 
20
22
  const DEFAULT_SMALL_TIER_TOKENS = 8000;
@@ -24,7 +26,8 @@ export async function buildReviewChunks(input: BuildChunksInput): Promise<Review
24
26
  const smallMax = input.chunking?.smallTierMaxTokens ?? DEFAULT_SMALL_TIER_TOKENS;
25
27
  const fileMax = input.chunking?.perFileMaxTokens ?? DEFAULT_FILE_TIER_TOKENS;
26
28
 
27
- const fileContents = await readFiles(input.touchedFiles, input.cwd);
29
+ const ranked = rankByRisk(input.touchedFiles, { protectedPaths: input.protectedPaths });
30
+ const fileContents = await readFiles(ranked, input.cwd);
28
31
 
29
32
  if (input.strategy === 'single-pass') {
30
33
  const combined = formatBatch(fileContents);
@@ -0,0 +1,56 @@
1
+ import { minimatch } from 'minimatch';
2
+
3
+ interface RankOptions {
4
+ protectedPaths?: string[];
5
+ }
6
+
7
+ const AUTH_PATTERNS = [
8
+ /auth/i, /login/i, /logout/i, /session/i, /token/i, /jwt/i, /oauth/i,
9
+ /password/i, /credential/i, /secret/i, /permission/i, /role/i, /acl/i,
10
+ ];
11
+
12
+ const PAYMENT_PATTERNS = [
13
+ /payment/i, /billing/i, /stripe/i, /checkout/i, /invoice/i, /charge/i,
14
+ /subscription/i, /wallet/i, /transaction/i, /refund/i,
15
+ ];
16
+
17
+ const CORE_PATTERNS = [
18
+ /\/services\//i, /\/core\//i, /\/api\//i, /\/routes?\//i,
19
+ /\/controllers?\//i, /\/models?\//i, /\/middleware\//i, /\/handlers?\//i,
20
+ ];
21
+
22
+ const TEST_EXT = /\.(test|spec)\.[a-z]+$/i;
23
+ const DOC_EXT = /\.(md|txt|rst|adoc)$/i;
24
+ const CONFIG_EXT = /\.(ya?ml|json|toml|ini|env)$/i;
25
+ const CONFIG_NAMES = /(config|settings|env|constants)\./i;
26
+
27
+ function scoreFile(file: string, protectedPaths: string[]): number {
28
+ const norm = file.replace(/\\/g, '/');
29
+
30
+ // Protected paths are highest risk
31
+ for (const pattern of protectedPaths) {
32
+ if (minimatch(norm, pattern, { matchBase: false }) ||
33
+ minimatch(norm, pattern, { matchBase: true })) {
34
+ return 100;
35
+ }
36
+ }
37
+
38
+ if (TEST_EXT.test(norm)) return 10;
39
+ if (DOC_EXT.test(norm)) return 5;
40
+
41
+ if (AUTH_PATTERNS.some(p => p.test(norm))) return 80;
42
+ if (PAYMENT_PATTERNS.some(p => p.test(norm))) return 70;
43
+ if (CORE_PATTERNS.some(p => p.test(norm))) return 50;
44
+ if (CONFIG_EXT.test(norm) || CONFIG_NAMES.test(norm)) return 40;
45
+
46
+ return 30;
47
+ }
48
+
49
+ /**
50
+ * Returns files sorted highest-risk first so LLM sees the most sensitive code
51
+ * at the start of its context window.
52
+ */
53
+ export function rankByRisk(files: string[], options: RankOptions = {}): string[] {
54
+ const protectedPaths = options.protectedPaths ?? [];
55
+ return [...files].sort((a, b) => scoreFile(b, protectedPaths) - scoreFile(a, protectedPaths));
56
+ }
@@ -34,6 +34,7 @@ export async function runReviewPhase(input: ReviewPhaseInput): Promise<ReviewPha
34
34
  chunking: input.config.chunking,
35
35
  engine: input.engine,
36
36
  cwd: input.cwd,
37
+ protectedPaths: input.config.protectedPaths,
37
38
  });
38
39
 
39
40
  const allFindings: Finding[] = [];