@delegance/claude-autopilot 5.0.1 โ†’ 5.0.3

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 (412) hide show
  1. package/dist/src/adapters/review-engine/codex.js +13 -1
  2. package/dist/src/cli/index.js +39 -1
  3. package/dist/src/cli/preflight.js +17 -4
  4. package/dist/src/cli/scan.js +12 -0
  5. package/package.json +4 -3
  6. package/dist/presets/go/rules/go-sql-injection.d.ts.map +0 -1
  7. package/dist/presets/go/rules/go-sql-injection.js.map +0 -1
  8. package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.d.ts.map +0 -1
  9. package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.js.map +0 -1
  10. package/dist/presets/python-fastapi/rules/fastapi-missing-auth.d.ts.map +0 -1
  11. package/dist/presets/python-fastapi/rules/fastapi-missing-auth.js.map +0 -1
  12. package/dist/presets/rails-postgres/rules/rails-sql-injection.d.ts.map +0 -1
  13. package/dist/presets/rails-postgres/rules/rails-sql-injection.js.map +0 -1
  14. package/dist/presets/t3/rules/t3-server-only.d.ts.map +0 -1
  15. package/dist/presets/t3/rules/t3-server-only.js.map +0 -1
  16. package/dist/src/adapters/base.d.ts.map +0 -1
  17. package/dist/src/adapters/base.js.map +0 -1
  18. package/dist/src/adapters/council/claude.d.ts.map +0 -1
  19. package/dist/src/adapters/council/claude.js.map +0 -1
  20. package/dist/src/adapters/council/openai.d.ts.map +0 -1
  21. package/dist/src/adapters/council/openai.js.map +0 -1
  22. package/dist/src/adapters/council/types.d.ts.map +0 -1
  23. package/dist/src/adapters/council/types.js.map +0 -1
  24. package/dist/src/adapters/loader.d.ts.map +0 -1
  25. package/dist/src/adapters/loader.js.map +0 -1
  26. package/dist/src/adapters/migration-runner/supabase.d.ts.map +0 -1
  27. package/dist/src/adapters/migration-runner/supabase.js.map +0 -1
  28. package/dist/src/adapters/migration-runner/types.d.ts.map +0 -1
  29. package/dist/src/adapters/migration-runner/types.js.map +0 -1
  30. package/dist/src/adapters/review-bot-parser/cursor.d.ts.map +0 -1
  31. package/dist/src/adapters/review-bot-parser/cursor.js.map +0 -1
  32. package/dist/src/adapters/review-bot-parser/declarative-base.d.ts.map +0 -1
  33. package/dist/src/adapters/review-bot-parser/declarative-base.js.map +0 -1
  34. package/dist/src/adapters/review-bot-parser/types.d.ts.map +0 -1
  35. package/dist/src/adapters/review-bot-parser/types.js.map +0 -1
  36. package/dist/src/adapters/review-engine/auto.d.ts.map +0 -1
  37. package/dist/src/adapters/review-engine/auto.js.map +0 -1
  38. package/dist/src/adapters/review-engine/claude.d.ts.map +0 -1
  39. package/dist/src/adapters/review-engine/claude.js.map +0 -1
  40. package/dist/src/adapters/review-engine/codex.d.ts.map +0 -1
  41. package/dist/src/adapters/review-engine/codex.js.map +0 -1
  42. package/dist/src/adapters/review-engine/gemini.d.ts.map +0 -1
  43. package/dist/src/adapters/review-engine/gemini.js.map +0 -1
  44. package/dist/src/adapters/review-engine/openai-compatible.d.ts.map +0 -1
  45. package/dist/src/adapters/review-engine/openai-compatible.js.map +0 -1
  46. package/dist/src/adapters/review-engine/parse-output.d.ts.map +0 -1
  47. package/dist/src/adapters/review-engine/parse-output.js.map +0 -1
  48. package/dist/src/adapters/review-engine/prompt-builder.d.ts.map +0 -1
  49. package/dist/src/adapters/review-engine/prompt-builder.js.map +0 -1
  50. package/dist/src/adapters/review-engine/types.d.ts.map +0 -1
  51. package/dist/src/adapters/review-engine/types.js.map +0 -1
  52. package/dist/src/adapters/vcs-host/commit-status.d.ts.map +0 -1
  53. package/dist/src/adapters/vcs-host/commit-status.js.map +0 -1
  54. package/dist/src/adapters/vcs-host/github.d.ts.map +0 -1
  55. package/dist/src/adapters/vcs-host/github.js.map +0 -1
  56. package/dist/src/adapters/vcs-host/types.d.ts.map +0 -1
  57. package/dist/src/adapters/vcs-host/types.js.map +0 -1
  58. package/dist/src/cli/_pkg-root.d.ts.map +0 -1
  59. package/dist/src/cli/_pkg-root.js.map +0 -1
  60. package/dist/src/cli/autoregress-bridge.d.ts.map +0 -1
  61. package/dist/src/cli/autoregress-bridge.js.map +0 -1
  62. package/dist/src/cli/baseline.d.ts.map +0 -1
  63. package/dist/src/cli/baseline.js.map +0 -1
  64. package/dist/src/cli/ci.d.ts.map +0 -1
  65. package/dist/src/cli/ci.js.map +0 -1
  66. package/dist/src/cli/costs.d.ts.map +0 -1
  67. package/dist/src/cli/costs.js.map +0 -1
  68. package/dist/src/cli/council.d.ts.map +0 -1
  69. package/dist/src/cli/council.js.map +0 -1
  70. package/dist/src/cli/detector.d.ts.map +0 -1
  71. package/dist/src/cli/detector.js.map +0 -1
  72. package/dist/src/cli/explain.d.ts.map +0 -1
  73. package/dist/src/cli/explain.js.map +0 -1
  74. package/dist/src/cli/fix.d.ts.map +0 -1
  75. package/dist/src/cli/fix.js.map +0 -1
  76. package/dist/src/cli/hook.d.ts.map +0 -1
  77. package/dist/src/cli/hook.js.map +0 -1
  78. package/dist/src/cli/ignore-helper.d.ts.map +0 -1
  79. package/dist/src/cli/ignore-helper.js.map +0 -1
  80. package/dist/src/cli/index.d.ts.map +0 -1
  81. package/dist/src/cli/index.js.map +0 -1
  82. package/dist/src/cli/lsp.d.ts.map +0 -1
  83. package/dist/src/cli/lsp.js.map +0 -1
  84. package/dist/src/cli/mcp.d.ts.map +0 -1
  85. package/dist/src/cli/mcp.js.map +0 -1
  86. package/dist/src/cli/migrate-v4.d.ts.map +0 -1
  87. package/dist/src/cli/migrate-v4.js.map +0 -1
  88. package/dist/src/cli/pr-comment.d.ts.map +0 -1
  89. package/dist/src/cli/pr-comment.js.map +0 -1
  90. package/dist/src/cli/pr-desc.d.ts.map +0 -1
  91. package/dist/src/cli/pr-desc.js.map +0 -1
  92. package/dist/src/cli/pr-review-comments.d.ts.map +0 -1
  93. package/dist/src/cli/pr-review-comments.js.map +0 -1
  94. package/dist/src/cli/pr.d.ts.map +0 -1
  95. package/dist/src/cli/pr.js.map +0 -1
  96. package/dist/src/cli/preflight.d.ts.map +0 -1
  97. package/dist/src/cli/preflight.js.map +0 -1
  98. package/dist/src/cli/report.d.ts.map +0 -1
  99. package/dist/src/cli/report.js.map +0 -1
  100. package/dist/src/cli/run.d.ts.map +0 -1
  101. package/dist/src/cli/run.js.map +0 -1
  102. package/dist/src/cli/scan.d.ts.map +0 -1
  103. package/dist/src/cli/scan.js.map +0 -1
  104. package/dist/src/cli/setup.d.ts.map +0 -1
  105. package/dist/src/cli/setup.js.map +0 -1
  106. package/dist/src/cli/test-gen.d.ts.map +0 -1
  107. package/dist/src/cli/test-gen.js.map +0 -1
  108. package/dist/src/cli/triage.d.ts.map +0 -1
  109. package/dist/src/cli/triage.js.map +0 -1
  110. package/dist/src/cli/watch.d.ts.map +0 -1
  111. package/dist/src/cli/watch.js.map +0 -1
  112. package/dist/src/cli/worker.d.ts.map +0 -1
  113. package/dist/src/cli/worker.js.map +0 -1
  114. package/dist/src/core/cache/cached-engine.d.ts.map +0 -1
  115. package/dist/src/core/cache/cached-engine.js.map +0 -1
  116. package/dist/src/core/cache/review-cache.d.ts.map +0 -1
  117. package/dist/src/core/cache/review-cache.js.map +0 -1
  118. package/dist/src/core/chunking/index.d.ts.map +0 -1
  119. package/dist/src/core/chunking/index.js.map +0 -1
  120. package/dist/src/core/chunking/risk-ranker.d.ts.map +0 -1
  121. package/dist/src/core/chunking/risk-ranker.js.map +0 -1
  122. package/dist/src/core/config/loader.d.ts.map +0 -1
  123. package/dist/src/core/config/loader.js.map +0 -1
  124. package/dist/src/core/config/preset-resolver.d.ts.map +0 -1
  125. package/dist/src/core/config/preset-resolver.js.map +0 -1
  126. package/dist/src/core/config/schema.d.ts.map +0 -1
  127. package/dist/src/core/config/schema.js.map +0 -1
  128. package/dist/src/core/config/types.d.ts.map +0 -1
  129. package/dist/src/core/config/types.js.map +0 -1
  130. package/dist/src/core/council/config.d.ts.map +0 -1
  131. package/dist/src/core/council/config.js.map +0 -1
  132. package/dist/src/core/council/context.d.ts.map +0 -1
  133. package/dist/src/core/council/context.js.map +0 -1
  134. package/dist/src/core/council/runner.d.ts.map +0 -1
  135. package/dist/src/core/council/runner.js.map +0 -1
  136. package/dist/src/core/council/types.d.ts.map +0 -1
  137. package/dist/src/core/council/types.js.map +0 -1
  138. package/dist/src/core/detect/git-context.d.ts.map +0 -1
  139. package/dist/src/core/detect/git-context.js.map +0 -1
  140. package/dist/src/core/detect/llm-key.d.ts.map +0 -1
  141. package/dist/src/core/detect/llm-key.js.map +0 -1
  142. package/dist/src/core/detect/protected-paths.d.ts.map +0 -1
  143. package/dist/src/core/detect/protected-paths.js.map +0 -1
  144. package/dist/src/core/detect/provider-usage.d.ts.map +0 -1
  145. package/dist/src/core/detect/provider-usage.js.map +0 -1
  146. package/dist/src/core/detect/stack.d.ts.map +0 -1
  147. package/dist/src/core/detect/stack.js.map +0 -1
  148. package/dist/src/core/detect/workspaces.d.ts.map +0 -1
  149. package/dist/src/core/detect/workspaces.js.map +0 -1
  150. package/dist/src/core/errors.d.ts.map +0 -1
  151. package/dist/src/core/errors.js.map +0 -1
  152. package/dist/src/core/findings/dedup.d.ts.map +0 -1
  153. package/dist/src/core/findings/dedup.js.map +0 -1
  154. package/dist/src/core/findings/types.d.ts.map +0 -1
  155. package/dist/src/core/findings/types.js.map +0 -1
  156. package/dist/src/core/fix/generator.d.ts.map +0 -1
  157. package/dist/src/core/fix/generator.js.map +0 -1
  158. package/dist/src/core/git/diff-hunks.d.ts.map +0 -1
  159. package/dist/src/core/git/diff-hunks.js.map +0 -1
  160. package/dist/src/core/git/touched-files.d.ts.map +0 -1
  161. package/dist/src/core/git/touched-files.js.map +0 -1
  162. package/dist/src/core/ignore/index.d.ts.map +0 -1
  163. package/dist/src/core/ignore/index.js.map +0 -1
  164. package/dist/src/core/index.d.ts.map +0 -1
  165. package/dist/src/core/index.js.map +0 -1
  166. package/dist/src/core/logging/ndjson-writer.d.ts.map +0 -1
  167. package/dist/src/core/logging/ndjson-writer.js.map +0 -1
  168. package/dist/src/core/logging/redaction.d.ts.map +0 -1
  169. package/dist/src/core/logging/redaction.js.map +0 -1
  170. package/dist/src/core/mcp/concurrency.d.ts.map +0 -1
  171. package/dist/src/core/mcp/concurrency.js.map +0 -1
  172. package/dist/src/core/mcp/handlers/fix-finding.d.ts.map +0 -1
  173. package/dist/src/core/mcp/handlers/fix-finding.js.map +0 -1
  174. package/dist/src/core/mcp/handlers/get-capabilities.d.ts.map +0 -1
  175. package/dist/src/core/mcp/handlers/get-capabilities.js.map +0 -1
  176. package/dist/src/core/mcp/handlers/get-findings.d.ts.map +0 -1
  177. package/dist/src/core/mcp/handlers/get-findings.js.map +0 -1
  178. package/dist/src/core/mcp/handlers/review-diff.d.ts.map +0 -1
  179. package/dist/src/core/mcp/handlers/review-diff.js.map +0 -1
  180. package/dist/src/core/mcp/handlers/scan-files.d.ts.map +0 -1
  181. package/dist/src/core/mcp/handlers/scan-files.js.map +0 -1
  182. package/dist/src/core/mcp/handlers/validate-fix.d.ts.map +0 -1
  183. package/dist/src/core/mcp/handlers/validate-fix.js.map +0 -1
  184. package/dist/src/core/mcp/run-store.d.ts.map +0 -1
  185. package/dist/src/core/mcp/run-store.js.map +0 -1
  186. package/dist/src/core/mcp/workspace.d.ts.map +0 -1
  187. package/dist/src/core/mcp/workspace.js.map +0 -1
  188. package/dist/src/core/persist/baseline.d.ts.map +0 -1
  189. package/dist/src/core/persist/baseline.js.map +0 -1
  190. package/dist/src/core/persist/cost-log.d.ts.map +0 -1
  191. package/dist/src/core/persist/cost-log.js.map +0 -1
  192. package/dist/src/core/persist/findings-cache.d.ts.map +0 -1
  193. package/dist/src/core/persist/findings-cache.js.map +0 -1
  194. package/dist/src/core/persist/triage.d.ts.map +0 -1
  195. package/dist/src/core/persist/triage.js.map +0 -1
  196. package/dist/src/core/phases/static-rules.d.ts.map +0 -1
  197. package/dist/src/core/phases/static-rules.js.map +0 -1
  198. package/dist/src/core/phases/tests.d.ts.map +0 -1
  199. package/dist/src/core/phases/tests.js.map +0 -1
  200. package/dist/src/core/pipeline/review-phase.d.ts.map +0 -1
  201. package/dist/src/core/pipeline/review-phase.js.map +0 -1
  202. package/dist/src/core/pipeline/run.d.ts.map +0 -1
  203. package/dist/src/core/pipeline/run.js.map +0 -1
  204. package/dist/src/core/runtime/idempotency.d.ts.map +0 -1
  205. package/dist/src/core/runtime/idempotency.js.map +0 -1
  206. package/dist/src/core/runtime/lock.d.ts.map +0 -1
  207. package/dist/src/core/runtime/lock.js.map +0 -1
  208. package/dist/src/core/runtime/state.d.ts.map +0 -1
  209. package/dist/src/core/runtime/state.js.map +0 -1
  210. package/dist/src/core/schema-alignment/detector.d.ts.map +0 -1
  211. package/dist/src/core/schema-alignment/detector.js.map +0 -1
  212. package/dist/src/core/schema-alignment/extractor/index.d.ts.map +0 -1
  213. package/dist/src/core/schema-alignment/extractor/index.js.map +0 -1
  214. package/dist/src/core/schema-alignment/extractor/prisma.d.ts.map +0 -1
  215. package/dist/src/core/schema-alignment/extractor/prisma.js.map +0 -1
  216. package/dist/src/core/schema-alignment/extractor/sql.d.ts.map +0 -1
  217. package/dist/src/core/schema-alignment/extractor/sql.js.map +0 -1
  218. package/dist/src/core/schema-alignment/llm-check.d.ts.map +0 -1
  219. package/dist/src/core/schema-alignment/llm-check.js.map +0 -1
  220. package/dist/src/core/schema-alignment/scanner.d.ts.map +0 -1
  221. package/dist/src/core/schema-alignment/scanner.js.map +0 -1
  222. package/dist/src/core/schema-alignment/types.d.ts.map +0 -1
  223. package/dist/src/core/schema-alignment/types.js.map +0 -1
  224. package/dist/src/core/shell.d.ts.map +0 -1
  225. package/dist/src/core/shell.js.map +0 -1
  226. package/dist/src/core/static-rules/registry.d.ts.map +0 -1
  227. package/dist/src/core/static-rules/registry.js.map +0 -1
  228. package/dist/src/core/static-rules/rules/brand-tokens.d.ts.map +0 -1
  229. package/dist/src/core/static-rules/rules/brand-tokens.js.map +0 -1
  230. package/dist/src/core/static-rules/rules/console-log.d.ts.map +0 -1
  231. package/dist/src/core/static-rules/rules/console-log.js.map +0 -1
  232. package/dist/src/core/static-rules/rules/hardcoded-secrets.d.ts.map +0 -1
  233. package/dist/src/core/static-rules/rules/hardcoded-secrets.js.map +0 -1
  234. package/dist/src/core/static-rules/rules/insecure-redirect.d.ts.map +0 -1
  235. package/dist/src/core/static-rules/rules/insecure-redirect.js.map +0 -1
  236. package/dist/src/core/static-rules/rules/large-file.d.ts.map +0 -1
  237. package/dist/src/core/static-rules/rules/large-file.js.map +0 -1
  238. package/dist/src/core/static-rules/rules/missing-auth.d.ts.map +0 -1
  239. package/dist/src/core/static-rules/rules/missing-auth.js.map +0 -1
  240. package/dist/src/core/static-rules/rules/missing-tests.d.ts.map +0 -1
  241. package/dist/src/core/static-rules/rules/missing-tests.js.map +0 -1
  242. package/dist/src/core/static-rules/rules/npm-audit.d.ts.map +0 -1
  243. package/dist/src/core/static-rules/rules/npm-audit.js.map +0 -1
  244. package/dist/src/core/static-rules/rules/package-lock-sync.d.ts.map +0 -1
  245. package/dist/src/core/static-rules/rules/package-lock-sync.js.map +0 -1
  246. package/dist/src/core/static-rules/rules/schema-alignment.d.ts.map +0 -1
  247. package/dist/src/core/static-rules/rules/schema-alignment.js.map +0 -1
  248. package/dist/src/core/static-rules/rules/sql-injection.d.ts.map +0 -1
  249. package/dist/src/core/static-rules/rules/sql-injection.js.map +0 -1
  250. package/dist/src/core/static-rules/rules/ssrf.d.ts.map +0 -1
  251. package/dist/src/core/static-rules/rules/ssrf.js.map +0 -1
  252. package/dist/src/core/static-rules/rules/todo-fixme.d.ts.map +0 -1
  253. package/dist/src/core/static-rules/rules/todo-fixme.js.map +0 -1
  254. package/dist/src/core/static-rules/tailwind-extractor.d.ts.map +0 -1
  255. package/dist/src/core/static-rules/tailwind-extractor.js.map +0 -1
  256. package/dist/src/core/test-gen/coverage-analyzer.d.ts.map +0 -1
  257. package/dist/src/core/test-gen/coverage-analyzer.js.map +0 -1
  258. package/dist/src/core/test-gen/framework-detector.d.ts.map +0 -1
  259. package/dist/src/core/test-gen/framework-detector.js.map +0 -1
  260. package/dist/src/core/test-gen/test-writer.d.ts.map +0 -1
  261. package/dist/src/core/test-gen/test-writer.js.map +0 -1
  262. package/dist/src/core/ui/design-context-loader.d.ts.map +0 -1
  263. package/dist/src/core/ui/design-context-loader.js.map +0 -1
  264. package/dist/src/core/worker/client.d.ts.map +0 -1
  265. package/dist/src/core/worker/client.js.map +0 -1
  266. package/dist/src/core/worker/lockfile.d.ts.map +0 -1
  267. package/dist/src/core/worker/lockfile.js.map +0 -1
  268. package/dist/src/core/worker/server.d.ts.map +0 -1
  269. package/dist/src/core/worker/server.js.map +0 -1
  270. package/dist/src/formatters/github-annotations.d.ts.map +0 -1
  271. package/dist/src/formatters/github-annotations.js.map +0 -1
  272. package/dist/src/formatters/index.d.ts.map +0 -1
  273. package/dist/src/formatters/index.js.map +0 -1
  274. package/dist/src/formatters/junit.d.ts.map +0 -1
  275. package/dist/src/formatters/junit.js.map +0 -1
  276. package/dist/src/formatters/sarif.d.ts.map +0 -1
  277. package/dist/src/formatters/sarif.js.map +0 -1
  278. package/dist/src/index.d.ts.map +0 -1
  279. package/dist/src/index.js.map +0 -1
  280. package/src/adapters/base.ts +0 -19
  281. package/src/adapters/council/claude.ts +0 -41
  282. package/src/adapters/council/openai.ts +0 -40
  283. package/src/adapters/council/types.ts +0 -7
  284. package/src/adapters/loader.ts +0 -108
  285. package/src/adapters/migration-runner/supabase.ts +0 -56
  286. package/src/adapters/migration-runner/types.ts +0 -36
  287. package/src/adapters/review-bot-parser/cursor.ts +0 -13
  288. package/src/adapters/review-bot-parser/declarative-base.ts +0 -64
  289. package/src/adapters/review-bot-parser/types.ts +0 -9
  290. package/src/adapters/review-engine/auto.ts +0 -94
  291. package/src/adapters/review-engine/claude.ts +0 -100
  292. package/src/adapters/review-engine/codex.ts +0 -82
  293. package/src/adapters/review-engine/gemini.ts +0 -105
  294. package/src/adapters/review-engine/openai-compatible.ts +0 -100
  295. package/src/adapters/review-engine/parse-output.ts +0 -74
  296. package/src/adapters/review-engine/prompt-builder.ts +0 -19
  297. package/src/adapters/review-engine/types.ts +0 -19
  298. package/src/adapters/vcs-host/commit-status.ts +0 -39
  299. package/src/adapters/vcs-host/github.ts +0 -77
  300. package/src/adapters/vcs-host/types.ts +0 -44
  301. package/src/cli/_pkg-root.ts +0 -85
  302. package/src/cli/autoregress-bridge.ts +0 -30
  303. package/src/cli/baseline.ts +0 -125
  304. package/src/cli/ci.ts +0 -45
  305. package/src/cli/costs.ts +0 -80
  306. package/src/cli/council.ts +0 -96
  307. package/src/cli/detector.ts +0 -92
  308. package/src/cli/explain.ts +0 -197
  309. package/src/cli/fix.ts +0 -249
  310. package/src/cli/hook.ts +0 -124
  311. package/src/cli/ignore-helper.ts +0 -116
  312. package/src/cli/index.ts +0 -612
  313. package/src/cli/lsp.ts +0 -200
  314. package/src/cli/mcp.ts +0 -206
  315. package/src/cli/migrate-v4.ts +0 -388
  316. package/src/cli/pr-comment.ts +0 -139
  317. package/src/cli/pr-desc.ts +0 -168
  318. package/src/cli/pr-review-comments.ts +0 -92
  319. package/src/cli/pr.ts +0 -76
  320. package/src/cli/preflight.ts +0 -235
  321. package/src/cli/report.ts +0 -186
  322. package/src/cli/run.ts +0 -425
  323. package/src/cli/scan.ts +0 -233
  324. package/src/cli/setup.ts +0 -191
  325. package/src/cli/test-gen.ts +0 -125
  326. package/src/cli/triage.ts +0 -137
  327. package/src/cli/watch.ts +0 -190
  328. package/src/cli/worker.ts +0 -109
  329. package/src/core/.gitkeep +0 -0
  330. package/src/core/cache/cached-engine.ts +0 -32
  331. package/src/core/cache/review-cache.ts +0 -70
  332. package/src/core/chunking/index.ts +0 -113
  333. package/src/core/chunking/risk-ranker.ts +0 -56
  334. package/src/core/config/loader.ts +0 -53
  335. package/src/core/config/preset-resolver.ts +0 -46
  336. package/src/core/config/schema.ts +0 -181
  337. package/src/core/config/types.ts +0 -98
  338. package/src/core/council/config.ts +0 -71
  339. package/src/core/council/context.ts +0 -17
  340. package/src/core/council/runner.ts +0 -83
  341. package/src/core/council/types.ts +0 -45
  342. package/src/core/detect/git-context.ts +0 -27
  343. package/src/core/detect/llm-key.ts +0 -89
  344. package/src/core/detect/protected-paths.ts +0 -63
  345. package/src/core/detect/provider-usage.ts +0 -74
  346. package/src/core/detect/stack.ts +0 -153
  347. package/src/core/detect/workspaces.ts +0 -103
  348. package/src/core/errors.ts +0 -37
  349. package/src/core/findings/dedup.ts +0 -14
  350. package/src/core/findings/types.ts +0 -39
  351. package/src/core/fix/generator.ts +0 -149
  352. package/src/core/git/diff-hunks.ts +0 -86
  353. package/src/core/git/touched-files.ts +0 -73
  354. package/src/core/ignore/index.ts +0 -54
  355. package/src/core/index.ts +0 -1
  356. package/src/core/logging/ndjson-writer.ts +0 -37
  357. package/src/core/logging/redaction.ts +0 -19
  358. package/src/core/mcp/concurrency.ts +0 -16
  359. package/src/core/mcp/handlers/fix-finding.ts +0 -126
  360. package/src/core/mcp/handlers/get-capabilities.ts +0 -62
  361. package/src/core/mcp/handlers/get-findings.ts +0 -36
  362. package/src/core/mcp/handlers/review-diff.ts +0 -65
  363. package/src/core/mcp/handlers/scan-files.ts +0 -65
  364. package/src/core/mcp/handlers/validate-fix.ts +0 -41
  365. package/src/core/mcp/run-store.ts +0 -85
  366. package/src/core/mcp/workspace.ts +0 -35
  367. package/src/core/persist/baseline.ts +0 -112
  368. package/src/core/persist/cost-log.ts +0 -30
  369. package/src/core/persist/findings-cache.ts +0 -43
  370. package/src/core/persist/triage.ts +0 -112
  371. package/src/core/phases/static-rules.ts +0 -93
  372. package/src/core/phases/tests.ts +0 -51
  373. package/src/core/pipeline/review-phase.ts +0 -182
  374. package/src/core/pipeline/run.ts +0 -116
  375. package/src/core/runtime/idempotency.ts +0 -6
  376. package/src/core/runtime/lock.ts +0 -29
  377. package/src/core/runtime/state.ts +0 -97
  378. package/src/core/schema-alignment/detector.ts +0 -59
  379. package/src/core/schema-alignment/extractor/index.ts +0 -24
  380. package/src/core/schema-alignment/extractor/prisma.ts +0 -21
  381. package/src/core/schema-alignment/extractor/sql.ts +0 -99
  382. package/src/core/schema-alignment/llm-check.ts +0 -91
  383. package/src/core/schema-alignment/scanner.ts +0 -107
  384. package/src/core/schema-alignment/types.ts +0 -43
  385. package/src/core/shell.ts +0 -48
  386. package/src/core/static-rules/registry.ts +0 -59
  387. package/src/core/static-rules/rules/brand-tokens.ts +0 -145
  388. package/src/core/static-rules/rules/console-log.ts +0 -42
  389. package/src/core/static-rules/rules/hardcoded-secrets.ts +0 -83
  390. package/src/core/static-rules/rules/insecure-redirect.ts +0 -67
  391. package/src/core/static-rules/rules/large-file.ts +0 -37
  392. package/src/core/static-rules/rules/missing-auth.ts +0 -70
  393. package/src/core/static-rules/rules/missing-tests.ts +0 -57
  394. package/src/core/static-rules/rules/npm-audit.ts +0 -38
  395. package/src/core/static-rules/rules/package-lock-sync.ts +0 -54
  396. package/src/core/static-rules/rules/schema-alignment.ts +0 -132
  397. package/src/core/static-rules/rules/sql-injection.ts +0 -71
  398. package/src/core/static-rules/rules/ssrf.ts +0 -63
  399. package/src/core/static-rules/rules/todo-fixme.ts +0 -40
  400. package/src/core/static-rules/tailwind-extractor.ts +0 -38
  401. package/src/core/test-gen/coverage-analyzer.ts +0 -93
  402. package/src/core/test-gen/framework-detector.ts +0 -21
  403. package/src/core/test-gen/test-writer.ts +0 -33
  404. package/src/core/ui/design-context-loader.ts +0 -87
  405. package/src/core/worker/client.ts +0 -46
  406. package/src/core/worker/lockfile.ts +0 -38
  407. package/src/core/worker/server.ts +0 -81
  408. package/src/formatters/github-annotations.ts +0 -36
  409. package/src/formatters/index.ts +0 -3
  410. package/src/formatters/junit.ts +0 -52
  411. package/src/formatters/sarif.ts +0 -103
  412. package/src/index.ts +0 -3
@@ -1,92 +0,0 @@
1
- import { runSafe } from '../core/shell.ts';
2
- import type { Finding } from '../core/findings/types.ts';
3
-
4
- const REVIEW_MARKER = '<!-- guardrail-inline -->';
5
-
6
- function getRepoNwo(cwd: string): string | null {
7
- const raw = runSafe('gh', ['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner'], { cwd });
8
- return raw ? raw.trim() : null;
9
- }
10
-
11
- /** True when a review with our marker already exists on this PR (avoids duplicates on re-runs). */
12
- function findExistingReviewId(pr: number, nwo: string, cwd: string): number | null {
13
- const raw = runSafe('gh', [
14
- 'api', `repos/${nwo}/pulls/${pr}/reviews`,
15
- '--jq', `[.[] | select(.body | startswith("${REVIEW_MARKER}")) | .id] | first`,
16
- ], { cwd });
17
- if (!raw) return null;
18
- const n = parseInt(raw.trim(), 10);
19
- return isNaN(n) ? null : n;
20
- }
21
-
22
- export interface PostReviewCommentsResult {
23
- posted: number;
24
- skipped: number; // findings with no line number
25
- }
26
-
27
- /**
28
- * Posts (or re-submits) a PR review with inline comments for each finding
29
- * that has a file + line number. Findings without line numbers are skipped.
30
- * Re-runs dismiss the previous autopilot review first to avoid stacking.
31
- */
32
- export async function postReviewComments(
33
- pr: number,
34
- findings: Finding[],
35
- cwd: string,
36
- ): Promise<PostReviewCommentsResult> {
37
- const nwo = getRepoNwo(cwd);
38
- if (!nwo) throw new Error('Could not determine repository name โ€” is gh authenticated?');
39
-
40
- const commentable = findings.filter(
41
- f => f.line !== undefined && f.file && f.file !== '<unspecified>' && f.file !== '<pipeline>',
42
- );
43
- const skipped = findings.length - commentable.length;
44
-
45
- if (commentable.length === 0) return { posted: 0, skipped };
46
-
47
- // Dismiss existing review so we don't stack on re-runs
48
- const existingId = findExistingReviewId(pr, nwo, cwd);
49
- if (existingId) {
50
- runSafe('gh', [
51
- 'api', `repos/${nwo}/pulls/${pr}/reviews/${existingId}/dismissals`,
52
- '--method', 'PUT',
53
- '--field', 'message=Superseded by updated guardrail review',
54
- ], { cwd });
55
- }
56
-
57
- // Build review body
58
- const body = [
59
- REVIEW_MARKER,
60
- `**Autopilot** found ${commentable.length} inline finding${commentable.length !== 1 ? 's' : ''}.`,
61
- ].join('\n');
62
-
63
- // Build comments array as JSON
64
- const comments = commentable.map(f => ({
65
- path: f.file,
66
- line: f.line,
67
- side: 'RIGHT',
68
- body: formatFindingBody(f),
69
- }));
70
-
71
- // gh api doesn't support array fields well via --field, use --input with JSON
72
- const payload = JSON.stringify({ body, event: 'COMMENT', comments });
73
- const result = runSafe('gh', [
74
- 'api', `repos/${nwo}/pulls/${pr}/reviews`,
75
- '--method', 'POST',
76
- '--input', '-',
77
- ], { cwd, input: payload });
78
-
79
- if (!result) throw new Error('Failed to post review โ€” gh api returned no output');
80
-
81
- return { posted: commentable.length, skipped };
82
- }
83
-
84
- function formatFindingBody(f: Finding): string {
85
- const sev = f.severity === 'critical' ? '๐Ÿšจ **CRITICAL**'
86
- : f.severity === 'warning' ? 'โš ๏ธ **Warning**'
87
- : '๐Ÿ’ก **Note**';
88
- const lines = [`${sev} โ€” ${f.message}`];
89
- if (f.suggestion) lines.push(`\n> **Suggestion:** ${f.suggestion}`);
90
- lines.push(`\n*[@delegance/guardrail](https://github.com/axledbetter/guardrail)*`);
91
- return lines.join('');
92
- }
package/src/cli/pr.ts DELETED
@@ -1,76 +0,0 @@
1
- import * as path from 'node:path';
2
- import * as fs from 'node:fs';
3
- import { spawnSync } from 'node:child_process';
4
- import { runCommand } from './run.ts';
5
-
6
- const C = {
7
- reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
8
- green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m',
9
- };
10
- const fmt = (c: keyof typeof C, t: string) => `${C[c]}${t}${C.reset}`;
11
-
12
- export interface PrCommandOptions {
13
- cwd?: string;
14
- configPath?: string;
15
- prNumber?: string;
16
- noPostComments?: boolean;
17
- noInlineComments?: boolean;
18
- }
19
-
20
- function ghJson<T>(args: string[], cwd: string): T | null {
21
- const r = spawnSync('gh', args, { cwd, encoding: 'utf8' });
22
- if (r.status !== 0) return null;
23
- try { return JSON.parse(r.stdout) as T; } catch { return null; }
24
- }
25
-
26
- function gitFetch(remote: string, ref: string, cwd: string): boolean {
27
- const r = spawnSync('git', ['fetch', remote, ref], { cwd, encoding: 'utf8', stdio: 'pipe' });
28
- return r.status === 0;
29
- }
30
-
31
- export async function runPr(options: PrCommandOptions = {}): Promise<number> {
32
- const cwd = options.cwd ?? process.cwd();
33
- const configPath = options.configPath ?? path.join(cwd, 'guardrail.config.yaml');
34
-
35
- if (!fs.existsSync(configPath)) {
36
- console.error(fmt('red', `[pr] guardrail.config.yaml not found at ${configPath}`));
37
- return 1;
38
- }
39
-
40
- // Resolve PR number
41
- let prNumber = options.prNumber;
42
- if (!prNumber) {
43
- const detected = ghJson<{ number: number }>(['pr', 'view', '--json', 'number'], cwd);
44
- if (!detected) {
45
- console.error(fmt('red', '[pr] No PR number given and no open PR found for current branch.'));
46
- console.error(fmt('dim', ' Usage: guardrail pr <number>'));
47
- return 1;
48
- }
49
- prNumber = String(detected.number);
50
- }
51
-
52
- // Look up PR metadata
53
- interface PrMeta { number: number; baseRefName: string; headRefName: string; title: string }
54
- const pr = ghJson<PrMeta>(['pr', 'view', prNumber, '--json', 'number,baseRefName,headRefName,title'], cwd);
55
- if (!pr) {
56
- console.error(fmt('red', `[pr] Could not fetch PR #${prNumber} โ€” is gh authenticated?`));
57
- return 1;
58
- }
59
-
60
- console.log(`\n${fmt('bold', `[pr]`)} #${pr.number} ${fmt('dim', pr.title)}`);
61
- console.log(fmt('dim', ` base: ${pr.baseRefName} head: ${pr.headRefName}`));
62
-
63
- // Fetch base ref so diff works locally
64
- const fetched = gitFetch('origin', pr.baseRefName, cwd);
65
- if (!fetched) {
66
- console.log(fmt('yellow', ` [pr] Warning: could not fetch origin/${pr.baseRefName} โ€” diff may be stale`));
67
- }
68
-
69
- return runCommand({
70
- cwd,
71
- configPath,
72
- base: `origin/${pr.baseRefName}`,
73
- postComments: !options.noPostComments,
74
- inlineComments: !options.noInlineComments,
75
- });
76
- }
@@ -1,235 +0,0 @@
1
- #!/usr/bin/env node
2
- import * as fs from 'node:fs';
3
- import * as path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { runSafe } from '../core/shell.ts';
6
- import { detectLLMKey, loadEnvFile, LLM_KEY_NAMES } from '../core/detect/llm-key.ts';
7
-
8
- const PASS = '\x1b[32mโœ“\x1b[0m';
9
- const FAIL = '\x1b[31mโœ—\x1b[0m';
10
- const WARN = '\x1b[33m!\x1b[0m';
11
-
12
- const ENV_CANDIDATES = ['.env.local', '.env.dev', '.env.development', '.env'];
13
-
14
- interface Check {
15
- name: string;
16
- result: 'pass' | 'fail' | 'warn';
17
- message?: string;
18
- }
19
-
20
- export interface DoctorResult {
21
- blockers: number;
22
- warnings: number;
23
- }
24
-
25
- /**
26
- * Checks that the superpowers plugin skills required by the pipeline are resolvable
27
- * from the usual Claude Code plugin paths. Returns skill names that weren't found.
28
- */
29
- const REQUIRED_SUPERPOWERS_SKILLS = [
30
- 'writing-plans',
31
- 'using-git-worktrees',
32
- 'subagent-driven-development',
33
- ] as const;
34
-
35
- function skillRoots(): string[] {
36
- const home = process.env.HOME || process.env.USERPROFILE || '';
37
- const cwd = process.cwd();
38
- const roots: string[] = [];
39
- // Project-local plugin install
40
- roots.push(path.join(cwd, '.claude', 'plugins'));
41
- // User-global plugin install
42
- if (home) roots.push(path.join(home, '.claude', 'plugins'));
43
- return roots.filter(p => fs.existsSync(p));
44
- }
45
-
46
- export function findMissingSuperpowersSkills(): string[] {
47
- // Traverse each root once, collect all discovered skill names, then diff against
48
- // the required set. Previous implementation did N ร— roots separate recursive walks.
49
- const discovered = new Set<string>();
50
- const MAX_DIRS_PER_ROOT = 2000; // safety cap to prevent pathological plugin trees
51
-
52
- for (const root of skillRoots()) {
53
- collectSkills(root, discovered, { visited: { n: 0 }, max: MAX_DIRS_PER_ROOT });
54
- }
55
-
56
- return REQUIRED_SUPERPOWERS_SKILLS.filter(s => !discovered.has(s));
57
- }
58
-
59
- // Walks up to 8 levels deep, capped at `max` directories total. When it finds a
60
- // `skills/` directory, records every `<skill-name>/SKILL.md` and `<skill-name>.md`
61
- // entry directly into the Set. Never revisits by name (Claude Code plugin caches
62
- // can contain many parallel copies โ€” we only care whether a skill exists *somewhere*).
63
- function collectSkills(
64
- dir: string,
65
- out: Set<string>,
66
- ctx: { visited: { n: number }; max: number },
67
- depth = 0,
68
- ): void {
69
- if (depth > 8) return;
70
- if (ctx.visited.n >= ctx.max) return;
71
- ctx.visited.n++;
72
-
73
- let entries: fs.Dirent[];
74
- try {
75
- entries = fs.readdirSync(dir, { withFileTypes: true });
76
- } catch {
77
- return;
78
- }
79
-
80
- // If this dir has a skills/ child, record every skill inside it
81
- for (const entry of entries) {
82
- if (entry.isDirectory() && entry.name === 'skills') {
83
- const skillsDir = path.join(dir, 'skills');
84
- try {
85
- for (const skill of fs.readdirSync(skillsDir, { withFileTypes: true })) {
86
- if (skill.isDirectory() && fs.existsSync(path.join(skillsDir, skill.name, 'SKILL.md'))) {
87
- out.add(skill.name);
88
- } else if (skill.isFile() && skill.name.endsWith('.md') && skill.name !== 'README.md') {
89
- out.add(skill.name.slice(0, -3)); // strip .md
90
- }
91
- }
92
- } catch { /* ignore */ }
93
- }
94
- }
95
-
96
- // Recurse into non-skills dirs (bounded depth + visit cap prevent pathological scans)
97
- for (const entry of entries) {
98
- if (!entry.isDirectory()) continue;
99
- if (entry.name.startsWith('.')) continue;
100
- if (entry.name === 'node_modules') continue;
101
- if (entry.name === 'skills') continue; // already handled above
102
- collectSkills(path.join(dir, entry.name), out, ctx, depth + 1);
103
- }
104
- }
105
-
106
- export async function runDoctor(): Promise<DoctorResult> {
107
- const checks: Check[] = [];
108
-
109
- // 1. Node version
110
- const nodeVersion = process.version;
111
- const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]!, 10);
112
- checks.push({
113
- name: `Node.js ${nodeVersion}`,
114
- result: nodeMajor >= 22 ? 'pass' : 'fail',
115
- message: nodeMajor < 22 ? `Node 22+ required โ€” current: ${nodeVersion}. Install via nvm: nvm install 22` : undefined,
116
- });
117
-
118
- // 2. tsx available
119
- const localTsx = path.join(process.cwd(), 'node_modules', '.bin', 'tsx');
120
- const tsxVersion = fs.existsSync(localTsx)
121
- ? runSafe(localTsx, ['--version'])
122
- : runSafe('tsx', ['--version']);
123
- checks.push({
124
- name: 'tsx available',
125
- result: tsxVersion ? 'pass' : 'fail',
126
- message: !tsxVersion ? 'tsx not found โ€” run: npm install @delegance/claude-autopilot@alpha (includes tsx for dev builds)' : undefined,
127
- });
128
-
129
- // 3. gh CLI authenticated
130
- const ghAuth = runSafe('gh', ['auth', 'status']);
131
- checks.push({
132
- name: 'gh CLI authenticated',
133
- result: ghAuth !== null ? 'pass' : 'fail',
134
- message: ghAuth === null ? 'gh CLI not authenticated โ€” run: gh auth login' : undefined,
135
- });
136
-
137
- // 4. guardrail.config.yaml in cwd
138
- const configYaml = path.join(process.cwd(), 'guardrail.config.yaml');
139
- checks.push({
140
- name: 'guardrail.config.yaml',
141
- result: fs.existsSync(configYaml) ? 'pass' : 'warn',
142
- message: !fs.existsSync(configYaml)
143
- ? 'guardrail.config.yaml not found in current directory โ€” copy from a preset: presets/nextjs-supabase/guardrail.config.yaml'
144
- : undefined,
145
- });
146
-
147
- // 5. Local env file exists
148
- const envFile = ENV_CANDIDATES.find(f => fs.existsSync(f));
149
- checks.push({
150
- name: `Local env file (${envFile ?? 'none found'})`,
151
- result: envFile ? 'pass' : 'warn',
152
- message: !envFile
153
- ? `No env file found. Looked for: ${ENV_CANDIDATES.join(', ')}. Create one with one of: ${LLM_KEY_NAMES.join(', ')}.`
154
- : undefined,
155
- });
156
-
157
- // 6. LLM API key โ€” shared detection with setup/scan/run (all 5 providers)
158
- const envVars = envFile ? loadEnvFile(envFile) : {};
159
- const { hasKey, preferred } = detectLLMKey({ extraEnv: envVars });
160
- checks.push({
161
- name: `LLM API key (${preferred ?? 'none'})`,
162
- result: hasKey ? 'pass' : 'warn',
163
- message: !hasKey
164
- ? `No LLM API key found โ€” set one of: ${LLM_KEY_NAMES.join(', ')} to enable review`
165
- : undefined,
166
- });
167
-
168
- // 7. claude CLI available
169
- const claudeVersion = runSafe('claude', ['--version']);
170
- checks.push({
171
- name: 'claude CLI',
172
- result: claudeVersion ? 'pass' : 'fail',
173
- message: !claudeVersion
174
- ? 'claude CLI not found โ€” required for autofix. Install Claude Code: https://claude.ai/claude-code'
175
- : undefined,
176
- });
177
-
178
- // 8. git user config
179
- const gitName = runSafe('git', ['config', 'user.name']);
180
- const gitEmail = runSafe('git', ['config', 'user.email']);
181
- const gitConfigOk = !!(gitName?.trim()) && !!(gitEmail?.trim());
182
- checks.push({
183
- name: 'git user config',
184
- result: gitConfigOk ? 'pass' : 'warn',
185
- message: !gitConfigOk
186
- ? 'git user.name / user.email not set โ€” commits will fail.'
187
- : undefined,
188
- });
189
-
190
- // 9. Superpowers plugin โ€” required for pipeline phases, optional for review-only use
191
- const missingSkills = findMissingSuperpowersSkills();
192
- const allSkillsFound = missingSkills.length === 0;
193
- checks.push({
194
- name: `Superpowers plugin${allSkillsFound ? '' : ` (missing: ${missingSkills.join(', ')})`}`,
195
- // Treat as warn, not fail โ€” users who only run `claude-autopilot run` (review phase)
196
- // don't need superpowers. Pipeline invocations (`autopilot` skill) will hard-fail at
197
- // their own entry point.
198
- result: allSkillsFound ? 'pass' : 'warn',
199
- message: !allSkillsFound
200
- ? 'Install: `claude plugin install superpowers` (required for pipeline phases โ€” brainstorm/plan/implement)'
201
- : undefined,
202
- });
203
-
204
- // Print results
205
- console.log('\n\x1b[1m[doctor] claude-autopilot prerequisite check\x1b[0m\n');
206
- let blockers = 0;
207
- let warnings = 0;
208
- for (const check of checks) {
209
- const icon = check.result === 'pass' ? PASS : check.result === 'warn' ? WARN : FAIL;
210
- console.log(` ${icon} ${check.name}`);
211
- if (check.message) {
212
- console.log(` \x1b[2m${check.message}\x1b[0m`);
213
- }
214
- if (check.result === 'fail') blockers++;
215
- if (check.result === 'warn') warnings++;
216
- }
217
-
218
- console.log('');
219
- if (blockers > 0) {
220
- console.log(`\x1b[31m[doctor] ${blockers} blocker(s) โ€” fix before running npx guardrail run\x1b[0m\n`);
221
- } else if (warnings > 0) {
222
- console.log(`\x1b[33m[doctor] ${warnings} warning(s) โ€” pipeline will run but some steps may be skipped\x1b[0m\n`);
223
- } else {
224
- console.log(`\x1b[32m[doctor] All checks passed โ€” ready to run\x1b[0m\n`);
225
- }
226
-
227
- return { blockers, warnings };
228
- }
229
-
230
- // Run when invoked directly
231
- const isMain = process.argv[1] !== undefined &&
232
- fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
233
- if (isMain) {
234
- runDoctor().then(r => process.exit(r.blockers > 0 ? 1 : 0));
235
- }
package/src/cli/report.ts DELETED
@@ -1,186 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { loadCachedFindings } from '../core/persist/findings-cache.ts';
4
- import { readCostLog } from '../core/persist/cost-log.ts';
5
- import type { Finding } from '../core/findings/types.ts';
6
-
7
- const C = {
8
- reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
9
- green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m',
10
- };
11
- const fmt = (c: keyof typeof C, t: string) => `${C[c]}${t}${C.reset}`;
12
-
13
- export interface ReportCommandOptions {
14
- cwd?: string;
15
- output?: string; // file path to write markdown (default: stdout)
16
- trend?: boolean; // include trend analysis from cost log run history
17
- }
18
-
19
- function severityOrder(s: Finding['severity']): number {
20
- return s === 'critical' ? 0 : s === 'warning' ? 1 : 2;
21
- }
22
-
23
- function buildTrendSection(cwd: string): string {
24
- const log = readCostLog(cwd);
25
- if (log.length === 0) return '';
26
-
27
- const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
28
- const recent = log.filter(e => new Date(e.timestamp).getTime() >= sevenDaysAgo);
29
- const totalCost = log.reduce((s, e) => s + e.costUSD, 0);
30
- const avgFiles = log.reduce((s, e) => s + e.files, 0) / log.length;
31
-
32
- const lines: string[] = [
33
- '## ๐Ÿ“ˆ Trend',
34
- '',
35
- `| Metric | Value |`,
36
- `|--------|-------|`,
37
- `| Runs (7d) | ${recent.length} |`,
38
- `| Runs (all-time) | ${log.length} |`,
39
- `| All-time cost | $${totalCost.toFixed(4)} |`,
40
- `| Avg files/run | ${avgFiles.toFixed(1)} |`,
41
- '',
42
- ];
43
-
44
- if (recent.length > 0) {
45
- lines.push('### Recent runs', '');
46
- lines.push('| Date | Files | Cost |');
47
- lines.push('|------|-------|------|');
48
- for (const e of recent.slice(-7).reverse()) {
49
- const d = new Date(e.timestamp).toLocaleDateString();
50
- lines.push(`| ${d} | ${e.files} | $${e.costUSD.toFixed(4)} |`);
51
- }
52
- lines.push('');
53
- }
54
-
55
- return lines.join('\n');
56
- }
57
-
58
- function buildFileBreakdown(findings: Finding[]): string {
59
- const withFiles = findings.filter(f => f.file && f.file !== '<unspecified>' && f.file !== '<pipeline>');
60
- if (withFiles.length === 0) return '';
61
-
62
- const counts = new Map<string, { critical: number; warning: number; note: number; total: number }>();
63
- for (const f of withFiles) {
64
- const entry = counts.get(f.file) ?? { critical: 0, warning: 0, note: 0, total: 0 };
65
- entry[f.severity]++;
66
- entry.total++;
67
- counts.set(f.file, entry);
68
- }
69
-
70
- const sorted = [...counts.entries()].sort((a, b) => b[1].total - a[1].total).slice(0, 10);
71
- if (sorted.length < 2) return ''; // single file โ€” not worth a table
72
-
73
- const lines = [
74
- '## ๐Ÿ“ By File',
75
- '',
76
- '| File | Critical | Warning | Note | Total |',
77
- '|------|----------|---------|------|-------|',
78
- ];
79
- for (const [file, c] of sorted) {
80
- lines.push(`| \`${file}\` | ${c.critical || 'โ€“'} | ${c.warning || 'โ€“'} | ${c.note || 'โ€“'} | **${c.total}** |`);
81
- }
82
- if (counts.size > 10) lines.push(`| *(${counts.size - 10} more files)* | | | | |`);
83
- lines.push('');
84
- return lines.join('\n');
85
- }
86
-
87
- function buildSourceBreakdown(findings: Finding[]): string {
88
- const counts = new Map<string, number>();
89
- for (const f of findings) {
90
- counts.set(f.source, (counts.get(f.source) ?? 0) + 1);
91
- }
92
- if (counts.size < 2) return '';
93
-
94
- const lines = ['## ๐Ÿ”ฌ By Source', '', '| Source | Findings |', '|--------|----------|'];
95
- for (const [source, n] of [...counts.entries()].sort((a, b) => b[1] - a[1])) {
96
- lines.push(`| ${source} | ${n} |`);
97
- }
98
- lines.push('');
99
- return lines.join('\n');
100
- }
101
-
102
- function buildMarkdown(findings: Finding[], cwd: string, trend: boolean): string {
103
- const critical = findings.filter(f => f.severity === 'critical');
104
- const warnings = findings.filter(f => f.severity === 'warning');
105
- const notes = findings.filter(f => f.severity === 'note');
106
- const fixable = critical.length + warnings.length;
107
-
108
- const lines: string[] = [
109
- '# Guardrail Report',
110
- '',
111
- `> Generated ${new Date().toISOString()}`,
112
- '',
113
- '## Summary',
114
- '',
115
- `| Severity | Count |`,
116
- `|----------|-------|`,
117
- `| ๐Ÿšจ Critical | ${critical.length} |`,
118
- `| โš ๏ธ Warning | ${warnings.length} |`,
119
- `| โ„น๏ธ Note | ${notes.length} |`,
120
- `| **Total** | **${findings.length}** |`,
121
- '',
122
- ];
123
-
124
- if (fixable > 0) {
125
- lines.push(`> **${fixable} finding${fixable !== 1 ? 's' : ''} can be auto-fixed** โ€” run \`guardrail fix\` to attempt repairs.`, '');
126
- }
127
-
128
- if (trend) {
129
- const trendSection = buildTrendSection(cwd);
130
- if (trendSection) lines.push(trendSection);
131
- }
132
-
133
- const fileBreakdown = buildFileBreakdown(findings);
134
- if (fileBreakdown) lines.push(fileBreakdown);
135
-
136
- const sourceBreakdown = buildSourceBreakdown(findings);
137
- if (sourceBreakdown) lines.push(sourceBreakdown);
138
-
139
- function renderGroup(label: string, icon: string, group: Finding[]) {
140
- if (group.length === 0) return;
141
- lines.push(`## ${icon} ${label}`, '');
142
- for (const f of group) {
143
- const loc = f.file && f.file !== '<unspecified>' && f.file !== '<pipeline>'
144
- ? `\`${f.file}${f.line ? `:${f.line}` : ''}\``
145
- : null;
146
- lines.push(`### ${loc ? `${loc} โ€” ` : ''}${f.message}`);
147
- if (f.suggestion) lines.push('', `> **Suggestion:** ${f.suggestion}`);
148
- lines.push('', `*Source: ${f.source} ยท Rule: ${f.id}*`, '');
149
- }
150
- }
151
-
152
- renderGroup('Critical', '๐Ÿšจ', critical);
153
- renderGroup('Warnings', 'โš ๏ธ', warnings);
154
- renderGroup('Notes', 'โ„น๏ธ', notes);
155
-
156
- if (findings.length === 0) {
157
- lines.push('## โœ… No findings', '', 'No cached findings โ€” run `guardrail run` or `guardrail scan` first.', '');
158
- }
159
-
160
- return lines.join('\n');
161
- }
162
-
163
- export async function runReport(options: ReportCommandOptions = {}): Promise<number> {
164
- const cwd = options.cwd ?? process.cwd();
165
- const findings = loadCachedFindings(cwd);
166
-
167
- if (findings.length === 0) {
168
- console.log(fmt('yellow', '[report] No cached findings โ€” run `guardrail run` or `guardrail scan` first.'));
169
- return 0;
170
- }
171
-
172
- const sorted = [...findings].sort((a, b) => severityOrder(a.severity) - severityOrder(b.severity));
173
- const md = buildMarkdown(sorted, cwd, options.trend ?? false);
174
-
175
- if (options.output) {
176
- fs.writeFileSync(options.output, md, 'utf8');
177
- const critical = findings.filter(f => f.severity === 'critical').length;
178
- const warnings = findings.filter(f => f.severity === 'warning').length;
179
- console.log(fmt('bold', `[report] Written to ${options.output}`));
180
- console.log(` ${critical > 0 ? fmt('red', `${critical} critical`) : fmt('green', '0 critical')} ${warnings > 0 ? fmt('yellow', `${warnings} warning${warnings !== 1 ? 's' : ''}`) : fmt('dim', '0 warnings')}`);
181
- } else {
182
- process.stdout.write(md + '\n');
183
- }
184
-
185
- return findings.some(f => f.severity === 'critical') ? 1 : 0;
186
- }