@delegance/claude-autopilot 2.5.0 → 5.0.0-alpha.1

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.
Files changed (129) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +164 -106
  3. package/bin/_launcher.js +77 -0
  4. package/bin/claude-autopilot.js +3 -0
  5. package/bin/guardrail.js +3 -0
  6. package/package.json +15 -9
  7. package/presets/generic/guardrail.config.yaml +35 -0
  8. package/presets/generic/stack.md +40 -0
  9. package/presets/nextjs-supabase/{autopilot.config.yaml → guardrail.config.yaml} +7 -0
  10. package/scripts/autoregress.ts +27 -11
  11. package/skills/autopilot/SKILL.md +170 -0
  12. package/skills/claude-autopilot.md +80 -0
  13. package/skills/guardrail.md +39 -0
  14. package/skills/migrate/SKILL.md +83 -0
  15. package/src/adapters/council/claude.ts +41 -0
  16. package/src/adapters/council/openai.ts +40 -0
  17. package/src/adapters/council/types.ts +7 -0
  18. package/src/adapters/loader.ts +7 -7
  19. package/src/adapters/review-engine/auto.ts +2 -2
  20. package/src/adapters/review-engine/claude.ts +9 -11
  21. package/src/adapters/review-engine/codex.ts +9 -11
  22. package/src/adapters/review-engine/gemini.ts +9 -11
  23. package/src/adapters/review-engine/openai-compatible.ts +10 -12
  24. package/src/adapters/review-engine/parse-output.ts +32 -6
  25. package/src/adapters/review-engine/prompt-builder.ts +19 -0
  26. package/src/adapters/review-engine/types.ts +1 -1
  27. package/src/adapters/vcs-host/commit-status.ts +39 -0
  28. package/src/adapters/vcs-host/github.ts +2 -2
  29. package/src/cli/baseline.ts +125 -0
  30. package/src/cli/ci.ts +11 -8
  31. package/src/cli/costs.ts +2 -2
  32. package/src/cli/council.ts +96 -0
  33. package/src/cli/detector.ts +21 -5
  34. package/src/cli/explain.ts +197 -0
  35. package/src/cli/fix.ts +173 -111
  36. package/src/cli/hook.ts +72 -27
  37. package/src/cli/ignore-helper.ts +116 -0
  38. package/src/cli/index.ts +272 -31
  39. package/src/cli/init.ts +12 -12
  40. package/src/cli/lsp.ts +200 -0
  41. package/src/cli/mcp.ts +206 -0
  42. package/src/cli/pr-comment.ts +5 -5
  43. package/src/cli/pr-desc.ts +168 -0
  44. package/src/cli/pr-review-comments.ts +3 -3
  45. package/src/cli/pr.ts +76 -0
  46. package/src/cli/preflight.ts +15 -32
  47. package/src/cli/report.ts +186 -0
  48. package/src/cli/run.ts +140 -36
  49. package/src/cli/scan.ts +233 -0
  50. package/src/cli/setup.ts +121 -15
  51. package/src/cli/test-gen.ts +125 -0
  52. package/src/cli/triage.ts +137 -0
  53. package/src/cli/watch.ts +52 -31
  54. package/src/cli/worker.ts +109 -0
  55. package/src/core/cache/review-cache.ts +2 -2
  56. package/src/core/chunking/index.ts +2 -2
  57. package/src/core/config/loader.ts +10 -10
  58. package/src/core/config/preset-resolver.ts +6 -6
  59. package/src/core/config/schema.ts +103 -2
  60. package/src/core/config/types.ts +57 -2
  61. package/src/core/council/config.ts +71 -0
  62. package/src/core/council/context.ts +17 -0
  63. package/src/core/council/runner.ts +83 -0
  64. package/src/core/council/types.ts +45 -0
  65. package/src/core/detect/llm-key.ts +89 -0
  66. package/src/core/detect/workspaces.ts +103 -0
  67. package/src/core/errors.ts +4 -4
  68. package/src/core/fix/generator.ts +149 -0
  69. package/src/core/ignore/index.ts +4 -4
  70. package/src/core/mcp/concurrency.ts +16 -0
  71. package/src/core/mcp/handlers/fix-finding.ts +126 -0
  72. package/src/core/mcp/handlers/get-capabilities.ts +62 -0
  73. package/src/core/mcp/handlers/get-findings.ts +36 -0
  74. package/src/core/mcp/handlers/review-diff.ts +65 -0
  75. package/src/core/mcp/handlers/scan-files.ts +65 -0
  76. package/src/core/mcp/handlers/validate-fix.ts +41 -0
  77. package/src/core/mcp/run-store.ts +85 -0
  78. package/src/core/mcp/workspace.ts +35 -0
  79. package/src/core/persist/baseline.ts +112 -0
  80. package/src/core/persist/cost-log.ts +1 -1
  81. package/src/core/persist/findings-cache.ts +1 -1
  82. package/src/core/persist/triage.ts +112 -0
  83. package/src/core/phases/static-rules.ts +18 -5
  84. package/src/core/pipeline/review-phase.ts +65 -26
  85. package/src/core/pipeline/run.ts +42 -10
  86. package/src/core/runtime/lock.ts +2 -2
  87. package/src/core/runtime/state.ts +2 -2
  88. package/src/core/schema-alignment/detector.ts +59 -0
  89. package/src/core/schema-alignment/extractor/index.ts +24 -0
  90. package/src/core/schema-alignment/extractor/prisma.ts +21 -0
  91. package/src/core/schema-alignment/extractor/sql.ts +99 -0
  92. package/src/core/schema-alignment/llm-check.ts +91 -0
  93. package/src/core/schema-alignment/scanner.ts +107 -0
  94. package/src/core/schema-alignment/types.ts +43 -0
  95. package/src/core/shell.ts +3 -3
  96. package/src/core/static-rules/registry.ts +17 -8
  97. package/src/core/static-rules/rules/brand-tokens.ts +145 -0
  98. package/src/core/static-rules/rules/hardcoded-secrets.ts +27 -1
  99. package/src/core/static-rules/rules/insecure-redirect.ts +67 -0
  100. package/src/core/static-rules/rules/missing-auth.ts +70 -0
  101. package/src/core/static-rules/rules/schema-alignment.ts +132 -0
  102. package/src/core/static-rules/rules/sql-injection.ts +71 -0
  103. package/src/core/static-rules/rules/ssrf.ts +63 -0
  104. package/src/core/static-rules/tailwind-extractor.ts +38 -0
  105. package/src/core/test-gen/coverage-analyzer.ts +93 -0
  106. package/src/core/test-gen/framework-detector.ts +21 -0
  107. package/src/core/test-gen/test-writer.ts +33 -0
  108. package/src/core/ui/design-context-loader.ts +87 -0
  109. package/src/core/worker/client.ts +46 -0
  110. package/src/core/worker/lockfile.ts +38 -0
  111. package/src/core/worker/server.ts +81 -0
  112. package/src/formatters/junit.ts +52 -0
  113. package/src/formatters/sarif.ts +2 -2
  114. package/src/index.ts +1 -2
  115. package/tests/snapshots/baselines/src-formatters-sarif.json +4 -4
  116. package/tests/snapshots/index.json +3 -3
  117. package/tests/snapshots/src-formatters-sarif.snap.ts +1 -1
  118. package/tests/snapshots/src-snapshots-impact-selector.snap.ts +3 -3
  119. package/tests/snapshots/src-snapshots-import-scanner.snap.ts +3 -3
  120. package/tests/snapshots/src-snapshots-serializer.snap.ts +2 -2
  121. package/bin/autopilot.js +0 -20
  122. package/skills/autopilot.md +0 -157
  123. /package/presets/go/{autopilot.config.yaml → guardrail.config.yaml} +0 -0
  124. /package/presets/python-fastapi/{autopilot.config.yaml → guardrail.config.yaml} +0 -0
  125. /package/presets/rails-postgres/{autopilot.config.yaml → guardrail.config.yaml} +0 -0
  126. /package/presets/t3/{autopilot.config.yaml → guardrail.config.yaml} +0 -0
  127. /package/{src → scripts}/snapshots/impact-selector.ts +0 -0
  128. /package/{src → scripts}/snapshots/import-scanner.ts +0 -0
  129. /package/{src → scripts}/snapshots/serializer.ts +0 -0
package/src/cli/index.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * autopilot CLI — entry point
3
+ * guardrail CLI — entry point
4
4
  *
5
5
  * Usage:
6
- * autopilot init scaffold autopilot.config.yaml from a preset
7
- * autopilot run run the pipeline on git-changed files
8
- * autopilot run --base main diff against a specific branch
9
- * autopilot run --dry-run show what would run, no execution
10
- * autopilot watch re-run pipeline on every file save (debounced)
11
- * autopilot doctor check prerequisites (alias: preflight)
6
+ * guardrail run review git-changed files
7
+ * guardrail scan src/auth/ review any path (no git required)
8
+ * guardrail scan --ask "..." ask a targeted question about code
9
+ * guardrail ci opinionated CI entrypoint
10
+ * guardrail watch re-run on every file save
11
+ * guardrail doctor check prerequisites
12
12
  */
13
13
  import { runCommand } from './run.ts';
14
14
  import { runWatch } from './watch.ts';
@@ -16,6 +16,17 @@ import { runSetup } from './setup.ts';
16
16
  import { runDoctor } from './preflight.ts';
17
17
  import { runCi } from './ci.ts';
18
18
  import { runFix } from './fix.ts';
19
+ import { runScan } from './scan.ts';
20
+ import { runReport } from './report.ts';
21
+ import { runExplain } from './explain.ts';
22
+ import { runIgnore } from './ignore-helper.ts';
23
+ import { runPr } from './pr.ts';
24
+ import { runBaseline } from './baseline.ts';
25
+ import { runTriage } from './triage.ts';
26
+ import { runLsp } from './lsp.ts';
27
+ import { runWorker } from './worker.ts';
28
+ import { runTestGen } from './test-gen.ts';
29
+ import { runCouncilCmd } from './council.ts';
19
30
 
20
31
  const args = process.argv.slice(2);
21
32
 
@@ -29,8 +40,38 @@ if (args[0] === '--version' || args[0] === '-v') {
29
40
  process.exit(0);
30
41
  }
31
42
 
32
- const SUBCOMMANDS = ['init', 'run', 'ci', 'fix', 'costs', 'watch', 'hook', 'autoregress', 'doctor', 'preflight', 'setup', 'help', '--help', '-h'] as const;
33
- const VALUE_FLAGS = ['base', 'config', 'files', 'format', 'output', 'debounce'];
43
+ const SUBCOMMANDS = ['init', 'run', 'scan', 'report', 'explain', 'ignore', 'ci', 'pr', 'fix', 'costs', 'watch', 'hook', 'autoregress', 'baseline', 'triage', 'lsp', 'worker', 'mcp', 'test-gen', 'pr-desc', 'doctor', 'preflight', 'setup', 'council', 'help', '--help', '-h'] as const;
44
+ const VALUE_FLAGS = ['base', 'config', 'files', 'format', 'output', 'debounce', 'ask', 'focus', 'fail-on', 'note', 'reason', 'expires', 'profile', 'severity', 'prompt', 'context-file'];
45
+
46
+ // Bare invocation — no subcommand, no flags → show welcome guide
47
+ if (args.length === 0) {
48
+ const hasKey = !!(process.env.ANTHROPIC_API_KEY || process.env.GEMINI_API_KEY ||
49
+ process.env.GOOGLE_API_KEY || process.env.OPENAI_API_KEY || process.env.GROQ_API_KEY);
50
+ const keyLine = hasKey
51
+ ? '\x1b[32m✓\x1b[0m LLM API key detected'
52
+ : '\x1b[33m!\x1b[0m No LLM API key found — set one of:\n ANTHROPIC_API_KEY https://console.anthropic.com/\n OPENAI_API_KEY https://platform.openai.com/api-keys\n GEMINI_API_KEY https://aistudio.google.com/app/apikey\n GROQ_API_KEY https://console.groq.com/keys (fast free tier)';
53
+ console.log(`
54
+ \x1b[1m@delegance/guardrail\x1b[0m — LLM-powered code review for your PR diffs
55
+
56
+ ${keyLine}
57
+
58
+ \x1b[1mQuick start:\x1b[0m
59
+
60
+ \x1b[36mnpx guardrail run --base main\x1b[0m Review files changed vs main
61
+ \x1b[36mnpx guardrail scan src/auth/\x1b[0m Scan any path (no git required)
62
+ \x1b[36mnpx guardrail scan --ask "SQL injection?" src/db/\x1b[0m
63
+ \x1b[36mnpx guardrail fix\x1b[0m Auto-fix cached findings
64
+ \x1b[36mnpx guardrail pr-desc\x1b[0m Generate PR description from current diff
65
+
66
+ \x1b[1mSetup:\x1b[0m
67
+
68
+ \x1b[36mnpx guardrail setup\x1b[0m Auto-detect stack, write config, install hook
69
+ \x1b[36mnpx guardrail doctor\x1b[0m Check prerequisites
70
+
71
+ Run \x1b[36mnpx guardrail --help\x1b[0m for full command reference.
72
+ `);
73
+ process.exit(0);
74
+ }
34
75
 
35
76
  // Detect first non-flag arg as subcommand, default to 'run'
36
77
  const subcommand = (args[0] && !args[0].startsWith('--')) ? args[0] : 'run';
@@ -41,7 +82,7 @@ function flag(name: string): string | undefined {
41
82
  if (idx < 0) return undefined;
42
83
  const val = args[idx + 1];
43
84
  if (val === undefined || val.startsWith('--')) {
44
- console.error(`\x1b[31m[autopilot] --${name} requires a value\x1b[0m`);
85
+ console.error(`\x1b[31m[guardrail] --${name} requires a value\x1b[0m`);
45
86
  process.exit(1);
46
87
  }
47
88
  return val;
@@ -53,18 +94,29 @@ function boolFlag(name: string): boolean {
53
94
 
54
95
  function printUsage(): void {
55
96
  console.log(`
56
- Usage: autopilot <command> [options]
97
+ Usage: guardrail <command> [options]
57
98
 
58
99
  Commands:
59
- run Run the pipeline on git-changed files (default)
60
- watch Watch for file changes and re-run pipeline on each save
61
- init Scaffold autopilot.config.yaml from a preset
62
- doctor Check prerequisites and show exact fix commands (alias: preflight)
63
- autoregress Run snapshot regression tests (run|diff|update|generate)
100
+ run Review git-changed files (default)
101
+ scan Review any path no git required
102
+ report Render cached findings as a markdown report
103
+ explain Deep-dive explanation + remediation for a specific finding
104
+ ignore Interactively add findings to .guardrail-ignore
105
+ watch Watch for file changes and re-run on each save
106
+ pr Review a specific PR by number (auto-detects if on PR branch)
107
+ fix Auto-fix cached findings using the configured LLM
108
+ costs Show per-run cost summary
109
+ ci Opinionated CI entrypoint (post comments + SARIF)
110
+ init Scaffold guardrail.config.yaml from a preset
111
+ doctor Check prerequisites (alias: preflight)
112
+ autoregress Snapshot regression tests (run|diff|update|generate)
113
+ lsp Language server — publishes findings as LSP diagnostics (stdin/stdout)
114
+ worker Persistent review daemon for multi-terminal parallel usage (start|stop|status)
115
+ test-gen Detect uncovered exports and generate test cases using the LLM
64
116
 
65
117
  Options (run):
66
118
  --base <ref> Git base ref for diff (default: HEAD~1)
67
- --config <path> Path to config file (default: ./autopilot.config.yaml)
119
+ --config <path> Path to config file (default: ./guardrail.config.yaml)
68
120
  --files <a,b,c> Explicit comma-separated file list (skips git detection)
69
121
  --dry-run Show what would run without executing
70
122
  --diff Send git diff hunks instead of full files (~70% fewer tokens)
@@ -74,8 +126,19 @@ Options (run):
74
126
  --format <text|sarif> Output format (default: text)
75
127
  --output <path> Output file path (required with --format sarif)
76
128
 
77
- fix Auto-fix cached findings using the configured LLM
78
- costs Show per-run cost summary from .autopilot-cache/costs.jsonl
129
+ Options (scan):
130
+ <path> [path...] Files or directories to scan (or --all for entire codebase)
131
+ --all Scan entire codebase
132
+ --ask <question> Targeted question to inject into the LLM review prompt
133
+ --focus <type> security | logic | performance (default: all)
134
+ --dry-run List files that would be scanned without running
135
+ --config <path> Path to config file
136
+
137
+ Options (pr):
138
+ <number> PR number to review (optional if on a PR branch)
139
+ --no-post-comments Skip posting/updating PR summary comment
140
+ --no-inline-comments Skip posting per-line inline annotations
141
+ --config <path> Path to config file
79
142
 
80
143
  Options (fix):
81
144
  --severity <critical|warning|all> Which findings to fix (default: critical)
@@ -83,7 +146,7 @@ Options (fix):
83
146
  --config <path> Path to config file
84
147
 
85
148
  Options (watch):
86
- --config <path> Path to config file (default: ./autopilot.config.yaml)
149
+ --config <path> Path to config file (default: ./guardrail.config.yaml)
87
150
  --debounce <ms> Debounce delay in ms (default: 300)
88
151
 
89
152
  Options (autoregress):
@@ -95,8 +158,32 @@ Options (autoregress):
95
158
  }
96
159
 
97
160
  switch (subcommand) {
161
+ case 'scan': {
162
+ const config = flag('config');
163
+ const ask = flag('ask');
164
+ const focusArg = flag('focus');
165
+ if (focusArg && !['security', 'logic', 'performance', 'brand', 'all'].includes(focusArg)) {
166
+ console.error(`\x1b[31m[guardrail] --focus must be "security", "logic", "performance", or "all"\x1b[0m`);
167
+ process.exit(1);
168
+ }
169
+ const dryRun = boolFlag('dry-run');
170
+ const all = boolFlag('all');
171
+ // Remaining non-flag args after 'scan' are paths
172
+ const targets = args.slice(1).filter(a => !a.startsWith('--') && a !== ask && a !== focusArg && a !== config);
173
+ const code = await runScan({
174
+ configPath: config,
175
+ targets: targets.length > 0 ? targets : undefined,
176
+ all,
177
+ ask,
178
+ focus: focusArg as 'security' | 'logic' | 'performance' | 'brand' | 'all' | undefined,
179
+ dryRun,
180
+ });
181
+ process.exit(code);
182
+ break;
183
+ }
184
+
98
185
  case 'init': {
99
- console.log('\x1b[33m[init] autopilot init is deprecated — use: npx autopilot setup\x1b[0m\n');
186
+ console.log('\x1b[33m[init] guardrail init is deprecated — use: npx guardrail setup\x1b[0m\n');
100
187
  const force = args.includes('--force');
101
188
  await runSetup({ force });
102
189
  break;
@@ -120,7 +207,7 @@ switch (subcommand) {
120
207
  const debounceArg = flag('debounce');
121
208
  const debounceMs = debounceArg ? parseInt(debounceArg, 10) : undefined;
122
209
  if (debounceArg && (isNaN(debounceMs!) || debounceMs! < 0)) {
123
- console.error(`\x1b[31m[autopilot] --debounce must be a non-negative integer\x1b[0m`);
210
+ console.error(`\x1b[31m[guardrail] --debounce must be a non-negative integer\x1b[0m`);
124
211
  process.exit(1);
125
212
  }
126
213
  await runWatch({ configPath: config, debounceMs });
@@ -134,20 +221,28 @@ switch (subcommand) {
134
221
  const dryRun = boolFlag('dry-run');
135
222
  const diff = boolFlag('diff');
136
223
  const delta = boolFlag('delta');
224
+ const staticOnly = args.includes('--static-only');
137
225
  const inlineComments = boolFlag('inline-comments');
138
226
  const postComments = boolFlag('post-comments');
139
227
  const formatArg = flag('format');
140
228
  const outputPath = flag('output');
141
229
 
142
- if (formatArg && formatArg !== 'text' && formatArg !== 'sarif') {
143
- console.error(`\x1b[31m[autopilot] --format must be "text" or "sarif"\x1b[0m`);
230
+ if (formatArg && formatArg !== 'text' && formatArg !== 'sarif' && formatArg !== 'junit') {
231
+ console.error(`\x1b[31m[guardrail] --format must be "text", "sarif", or "junit"\x1b[0m`);
144
232
  process.exit(1);
145
233
  }
146
- if (formatArg === 'sarif' && !outputPath) {
147
- console.error(`\x1b[31m[autopilot] --format sarif requires --output <path>\x1b[0m`);
234
+ if ((formatArg === 'sarif' || formatArg === 'junit') && !outputPath) {
235
+ console.error(`\x1b[31m[guardrail] --format ${formatArg} requires --output <path>\x1b[0m`);
148
236
  process.exit(1);
149
237
  }
150
238
 
239
+ const failOnArg = flag('fail-on');
240
+ if (failOnArg && !['critical', 'warning', 'note', 'none'].includes(failOnArg)) {
241
+ console.error(`\x1b[31m[guardrail] --fail-on must be "critical", "warning", "note", or "none"\x1b[0m`);
242
+ process.exit(1);
243
+ }
244
+ const newOnly = boolFlag('new-only');
245
+
151
246
  const code = await runCommand({
152
247
  base,
153
248
  configPath: config,
@@ -155,10 +250,13 @@ switch (subcommand) {
155
250
  dryRun,
156
251
  diff,
157
252
  delta,
253
+ newOnly,
254
+ failOn: failOnArg as 'critical' | 'warning' | 'note' | 'none' | undefined,
158
255
  inlineComments,
159
256
  postComments,
160
- format: formatArg as 'text' | 'sarif' | undefined,
257
+ format: formatArg as 'text' | 'sarif' | 'junit' | undefined,
161
258
  outputPath,
259
+ skipReview: staticOnly,
162
260
  });
163
261
  process.exit(code);
164
262
  break;
@@ -171,6 +269,8 @@ switch (subcommand) {
171
269
  const noPostComments = boolFlag('no-post-comments');
172
270
  const noInlineComments = boolFlag('no-inline-comments');
173
271
  const diff = boolFlag('diff');
272
+ const newOnly = boolFlag('new-only');
273
+ const failOnArg = flag('fail-on');
174
274
  const code = await runCi({
175
275
  configPath: config,
176
276
  base,
@@ -178,6 +278,33 @@ switch (subcommand) {
178
278
  postComments: noPostComments ? false : undefined,
179
279
  inlineComments: noInlineComments ? false : undefined,
180
280
  diff,
281
+ newOnly,
282
+ failOn: failOnArg as 'critical' | 'warning' | 'note' | 'none' | undefined,
283
+ });
284
+ process.exit(code);
285
+ break;
286
+ }
287
+
288
+ case 'baseline': {
289
+ const { runBaseline: rb } = await import('./baseline.ts');
290
+ const sub = args[1] ?? 'show';
291
+ const note = flag('note');
292
+ const config = flag('config');
293
+ const code = await rb(sub, { cwd: process.cwd(), note, baselinePath: config });
294
+ process.exit(code);
295
+ break;
296
+ }
297
+
298
+ case 'pr': {
299
+ const config = flag('config');
300
+ const noPostComments = boolFlag('no-post-comments');
301
+ const noInlineComments = boolFlag('no-inline-comments');
302
+ const prNumber = args.slice(1).find(a => !a.startsWith('--') && /^\d+$/.test(a));
303
+ const code = await runPr({
304
+ configPath: config,
305
+ prNumber,
306
+ noPostComments,
307
+ noInlineComments,
181
308
  });
182
309
  process.exit(code);
183
310
  break;
@@ -187,7 +314,11 @@ switch (subcommand) {
187
314
  const { runHook } = await import('./hook.ts');
188
315
  const hookSub = args[1] ?? 'status';
189
316
  const force = boolFlag('force');
190
- const code = await runHook(hookSub, { force });
317
+ const code = await runHook(hookSub, {
318
+ force,
319
+ preCommitOnly: args.includes('--pre-commit-only'),
320
+ prePushOnly: args.includes('--pre-push-only'),
321
+ });
191
322
  process.exit(code);
192
323
  break;
193
324
  }
@@ -203,19 +334,67 @@ switch (subcommand) {
203
334
  const config = flag('config');
204
335
  const severityArg = flag('severity');
205
336
  if (severityArg && !['critical', 'warning', 'all'].includes(severityArg)) {
206
- console.error(`\x1b[31m[autopilot] --severity must be "critical", "warning", or "all"\x1b[0m`);
337
+ console.error(`\x1b[31m[guardrail] --severity must be "critical", "warning", or "all"\x1b[0m`);
207
338
  process.exit(1);
208
339
  }
209
340
  const dryRun = boolFlag('dry-run');
341
+ const noVerify = boolFlag('no-verify');
210
342
  const code = await runFix({
211
343
  configPath: config,
212
344
  severity: severityArg as 'critical' | 'warning' | 'all' | undefined,
213
345
  dryRun,
346
+ noVerify,
214
347
  });
215
348
  process.exit(code);
216
349
  break;
217
350
  }
218
351
 
352
+ case 'triage': {
353
+ const sub = args[1];
354
+ const rest = args.slice(2);
355
+ const code = await runTriage(sub, rest);
356
+ process.exit(code);
357
+ break;
358
+ }
359
+
360
+ case 'test-gen': {
361
+ const config = flag('config');
362
+ const base = flag('base');
363
+ const dryRun = boolFlag('dry-run');
364
+ const verify = boolFlag('verify');
365
+ const targets = args.slice(1).filter(a => !a.startsWith('--') && a !== config && a !== base);
366
+ const code = await runTestGen({
367
+ cwd: process.cwd(),
368
+ configPath: config,
369
+ targets: targets.length > 0 ? targets : undefined,
370
+ base,
371
+ dryRun,
372
+ verify,
373
+ });
374
+ process.exit(code);
375
+ break;
376
+ }
377
+
378
+ case 'pr-desc': {
379
+ const { runPrDesc } = await import('./pr-desc.ts');
380
+ const baseIdx = args.indexOf('--base');
381
+ const base = baseIdx !== -1 ? args[baseIdx + 1] : undefined;
382
+ const outputIdx = args.indexOf('--output');
383
+ const output = outputIdx !== -1 ? args[outputIdx + 1] : undefined;
384
+ await runPrDesc({
385
+ base,
386
+ post: args.includes('--post'),
387
+ yes: args.includes('--yes'),
388
+ output,
389
+ });
390
+ break;
391
+ }
392
+
393
+ case 'lsp': {
394
+ await runLsp({ cwd: process.cwd() });
395
+ break;
396
+ }
397
+
219
398
  case 'costs': {
220
399
  const { runCosts } = await import('./costs.ts');
221
400
  const code = await runCosts();
@@ -223,14 +402,76 @@ switch (subcommand) {
223
402
  break;
224
403
  }
225
404
 
405
+ case 'report': {
406
+ const outputPath = flag('output');
407
+ const trend = boolFlag('trend');
408
+ const code = await runReport({ output: outputPath, trend });
409
+ process.exit(code);
410
+ break;
411
+ }
412
+
413
+ case 'explain': {
414
+ const config = flag('config');
415
+ // Target is the first non-flag arg after 'explain'
416
+ const target = args.slice(1).find(a => !a.startsWith('--'));
417
+ const code = await runExplain({ configPath: config, target });
418
+ process.exit(code);
419
+ break;
420
+ }
421
+
422
+ case 'ignore': {
423
+ const all = boolFlag('all');
424
+ const dryRun = boolFlag('dry-run');
425
+ const code = await runIgnore({ all, dryRun });
426
+ process.exit(code);
427
+ break;
428
+ }
429
+
226
430
  case 'setup': {
227
431
  const force = args.includes('--force');
228
- await runSetup({ force });
432
+ const profileArg = flag('profile');
433
+ if (profileArg && !['security-strict', 'team', 'solo'].includes(profileArg)) {
434
+ console.error(`\x1b[31m[guardrail] --profile must be "security-strict", "team", or "solo"\x1b[0m`);
435
+ process.exit(1);
436
+ }
437
+ await runSetup({ force, profile: profileArg as 'security-strict' | 'team' | 'solo' | undefined });
438
+ break;
439
+ }
440
+
441
+ case 'worker': {
442
+ const sub = args[1];
443
+ const config = flag('config');
444
+ const code = await runWorker(sub, { cwd: process.cwd(), configPath: config });
445
+ process.exit(code);
446
+ break;
447
+ }
448
+
449
+ case 'council': {
450
+ const config = flag('config');
451
+ const prompt = flag('prompt');
452
+ const contextFile = flag('context-file');
453
+ const dryRun = boolFlag('dry-run');
454
+ const noSynthesize = boolFlag('no-synthesize');
455
+ const code = await runCouncilCmd({
456
+ prompt,
457
+ contextFile,
458
+ configPath: config,
459
+ dryRun,
460
+ noSynthesize,
461
+ });
462
+ process.exit(code);
463
+ break;
464
+ }
465
+
466
+ case 'mcp': {
467
+ const { runMcp } = await import('./mcp.ts');
468
+ const configPath = flag('config');
469
+ await runMcp({ cwd: process.cwd(), configPath });
229
470
  break;
230
471
  }
231
472
 
232
473
  default:
233
- console.error(`\x1b[31m[autopilot] Unknown subcommand: "${subcommand}"\x1b[0m`);
474
+ console.error(`\x1b[31m[guardrail] Unknown subcommand: "${subcommand}"\x1b[0m`);
234
475
  printUsage();
235
476
  process.exit(1);
236
477
  }
package/src/cli/init.ts CHANGED
@@ -17,14 +17,14 @@ const PRESET_DESCRIPTIONS: Record<string, string> = {
17
17
  const PRESET_NAMES = Object.keys(PRESET_DESCRIPTIONS);
18
18
 
19
19
  export async function runInit(cwd: string = process.cwd()): Promise<void> {
20
- const dest = path.join(cwd, 'autopilot.config.yaml');
20
+ const dest = path.join(cwd, 'guardrail.config.yaml');
21
21
 
22
22
  if (fs.existsSync(dest)) {
23
- console.error(`\x1b[33m[init] autopilot.config.yaml already exists — remove it first to re-init\x1b[0m`);
23
+ console.error(`\x1b[33m[init] guardrail.config.yaml already exists — remove it first to re-init\x1b[0m`);
24
24
  process.exit(1);
25
25
  }
26
26
 
27
- console.log('\n\x1b[1m[autopilot init] Choose a preset:\x1b[0m\n');
27
+ console.log('\n\x1b[1m[guardrail init] Choose a preset:\x1b[0m\n');
28
28
  PRESET_NAMES.forEach((name, i) => {
29
29
  console.log(` ${i + 1}. ${name.padEnd(22)} ${PRESET_DESCRIPTIONS[name]}`);
30
30
  });
@@ -63,27 +63,27 @@ export async function runInit(cwd: string = process.cwd()): Promise<void> {
63
63
  const presetContent = await fsAsync.readFile(presetConfigPath, 'utf8');
64
64
  await fsAsync.writeFile(dest, presetContent, 'utf8');
65
65
 
66
- console.log(`\n\x1b[32m✓\x1b[0m Created autopilot.config.yaml from preset \x1b[1m${presetName}\x1b[0m`);
66
+ console.log(`\n\x1b[32m✓\x1b[0m Created guardrail.config.yaml from preset \x1b[1m${presetName}\x1b[0m`);
67
67
  console.log('\nNext steps:');
68
- console.log(' 1. Review autopilot.config.yaml and adjust testCommand / protectedPaths');
68
+ console.log(' 1. Review guardrail.config.yaml and adjust testCommand / protectedPaths');
69
69
  console.log(' 2. Set OPENAI_API_KEY in your environment (for Codex review)');
70
70
  console.log(' 3. Run your first pipeline to verify the setup:');
71
- console.log(' npx autopilot run');
71
+ console.log(' npx guardrail run');
72
72
  console.log(' 4. Generate snapshot baselines after your first feature lands:');
73
- console.log(' npx autopilot autoregress generate');
73
+ console.log(' npx guardrail autoregress generate');
74
74
  console.log(' 5. Install the pre-push git hook (enforces snapshots on push):');
75
- console.log(' npx autopilot hook install');
75
+ console.log(' npx guardrail hook install');
76
76
  console.log(' 6. (Optional) Add CI with GitHub Actions:');
77
- console.log(' uses: axledbetter/claude-autopilot/.github/actions/ci@main\n');
77
+ console.log(' uses: axledbetter/guardrail/.github/actions/ci@main\n');
78
78
  }
79
79
 
80
80
  function presetSearchPaths(name: string): string[] {
81
81
  // fileURLToPath handles encoded chars and Windows drive letters safely
82
82
  const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
83
83
  return [
84
- path.join(pkgRoot, 'presets', name, 'autopilot.config.yaml'),
85
- path.join(process.cwd(), 'presets', name, 'autopilot.config.yaml'),
86
- path.join(process.cwd(), 'node_modules', '@delegance', 'claude-autopilot', 'presets', name, 'autopilot.config.yaml'),
84
+ path.join(pkgRoot, 'presets', name, 'guardrail.config.yaml'),
85
+ path.join(process.cwd(), 'presets', name, 'guardrail.config.yaml'),
86
+ path.join(process.cwd(), 'node_modules', '@delegance', 'claude-autopilot', 'presets', name, 'guardrail.config.yaml'),
87
87
  ];
88
88
  }
89
89