@delegance/claude-autopilot 5.0.1 โ†’ 5.0.2

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 (410) hide show
  1. package/dist/src/cli/index.js +39 -1
  2. package/dist/src/cli/preflight.js +17 -4
  3. package/package.json +4 -3
  4. package/dist/presets/go/rules/go-sql-injection.d.ts.map +0 -1
  5. package/dist/presets/go/rules/go-sql-injection.js.map +0 -1
  6. package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.d.ts.map +0 -1
  7. package/dist/presets/nextjs-supabase/rules/supabase-rls-bypass.js.map +0 -1
  8. package/dist/presets/python-fastapi/rules/fastapi-missing-auth.d.ts.map +0 -1
  9. package/dist/presets/python-fastapi/rules/fastapi-missing-auth.js.map +0 -1
  10. package/dist/presets/rails-postgres/rules/rails-sql-injection.d.ts.map +0 -1
  11. package/dist/presets/rails-postgres/rules/rails-sql-injection.js.map +0 -1
  12. package/dist/presets/t3/rules/t3-server-only.d.ts.map +0 -1
  13. package/dist/presets/t3/rules/t3-server-only.js.map +0 -1
  14. package/dist/src/adapters/base.d.ts.map +0 -1
  15. package/dist/src/adapters/base.js.map +0 -1
  16. package/dist/src/adapters/council/claude.d.ts.map +0 -1
  17. package/dist/src/adapters/council/claude.js.map +0 -1
  18. package/dist/src/adapters/council/openai.d.ts.map +0 -1
  19. package/dist/src/adapters/council/openai.js.map +0 -1
  20. package/dist/src/adapters/council/types.d.ts.map +0 -1
  21. package/dist/src/adapters/council/types.js.map +0 -1
  22. package/dist/src/adapters/loader.d.ts.map +0 -1
  23. package/dist/src/adapters/loader.js.map +0 -1
  24. package/dist/src/adapters/migration-runner/supabase.d.ts.map +0 -1
  25. package/dist/src/adapters/migration-runner/supabase.js.map +0 -1
  26. package/dist/src/adapters/migration-runner/types.d.ts.map +0 -1
  27. package/dist/src/adapters/migration-runner/types.js.map +0 -1
  28. package/dist/src/adapters/review-bot-parser/cursor.d.ts.map +0 -1
  29. package/dist/src/adapters/review-bot-parser/cursor.js.map +0 -1
  30. package/dist/src/adapters/review-bot-parser/declarative-base.d.ts.map +0 -1
  31. package/dist/src/adapters/review-bot-parser/declarative-base.js.map +0 -1
  32. package/dist/src/adapters/review-bot-parser/types.d.ts.map +0 -1
  33. package/dist/src/adapters/review-bot-parser/types.js.map +0 -1
  34. package/dist/src/adapters/review-engine/auto.d.ts.map +0 -1
  35. package/dist/src/adapters/review-engine/auto.js.map +0 -1
  36. package/dist/src/adapters/review-engine/claude.d.ts.map +0 -1
  37. package/dist/src/adapters/review-engine/claude.js.map +0 -1
  38. package/dist/src/adapters/review-engine/codex.d.ts.map +0 -1
  39. package/dist/src/adapters/review-engine/codex.js.map +0 -1
  40. package/dist/src/adapters/review-engine/gemini.d.ts.map +0 -1
  41. package/dist/src/adapters/review-engine/gemini.js.map +0 -1
  42. package/dist/src/adapters/review-engine/openai-compatible.d.ts.map +0 -1
  43. package/dist/src/adapters/review-engine/openai-compatible.js.map +0 -1
  44. package/dist/src/adapters/review-engine/parse-output.d.ts.map +0 -1
  45. package/dist/src/adapters/review-engine/parse-output.js.map +0 -1
  46. package/dist/src/adapters/review-engine/prompt-builder.d.ts.map +0 -1
  47. package/dist/src/adapters/review-engine/prompt-builder.js.map +0 -1
  48. package/dist/src/adapters/review-engine/types.d.ts.map +0 -1
  49. package/dist/src/adapters/review-engine/types.js.map +0 -1
  50. package/dist/src/adapters/vcs-host/commit-status.d.ts.map +0 -1
  51. package/dist/src/adapters/vcs-host/commit-status.js.map +0 -1
  52. package/dist/src/adapters/vcs-host/github.d.ts.map +0 -1
  53. package/dist/src/adapters/vcs-host/github.js.map +0 -1
  54. package/dist/src/adapters/vcs-host/types.d.ts.map +0 -1
  55. package/dist/src/adapters/vcs-host/types.js.map +0 -1
  56. package/dist/src/cli/_pkg-root.d.ts.map +0 -1
  57. package/dist/src/cli/_pkg-root.js.map +0 -1
  58. package/dist/src/cli/autoregress-bridge.d.ts.map +0 -1
  59. package/dist/src/cli/autoregress-bridge.js.map +0 -1
  60. package/dist/src/cli/baseline.d.ts.map +0 -1
  61. package/dist/src/cli/baseline.js.map +0 -1
  62. package/dist/src/cli/ci.d.ts.map +0 -1
  63. package/dist/src/cli/ci.js.map +0 -1
  64. package/dist/src/cli/costs.d.ts.map +0 -1
  65. package/dist/src/cli/costs.js.map +0 -1
  66. package/dist/src/cli/council.d.ts.map +0 -1
  67. package/dist/src/cli/council.js.map +0 -1
  68. package/dist/src/cli/detector.d.ts.map +0 -1
  69. package/dist/src/cli/detector.js.map +0 -1
  70. package/dist/src/cli/explain.d.ts.map +0 -1
  71. package/dist/src/cli/explain.js.map +0 -1
  72. package/dist/src/cli/fix.d.ts.map +0 -1
  73. package/dist/src/cli/fix.js.map +0 -1
  74. package/dist/src/cli/hook.d.ts.map +0 -1
  75. package/dist/src/cli/hook.js.map +0 -1
  76. package/dist/src/cli/ignore-helper.d.ts.map +0 -1
  77. package/dist/src/cli/ignore-helper.js.map +0 -1
  78. package/dist/src/cli/index.d.ts.map +0 -1
  79. package/dist/src/cli/index.js.map +0 -1
  80. package/dist/src/cli/lsp.d.ts.map +0 -1
  81. package/dist/src/cli/lsp.js.map +0 -1
  82. package/dist/src/cli/mcp.d.ts.map +0 -1
  83. package/dist/src/cli/mcp.js.map +0 -1
  84. package/dist/src/cli/migrate-v4.d.ts.map +0 -1
  85. package/dist/src/cli/migrate-v4.js.map +0 -1
  86. package/dist/src/cli/pr-comment.d.ts.map +0 -1
  87. package/dist/src/cli/pr-comment.js.map +0 -1
  88. package/dist/src/cli/pr-desc.d.ts.map +0 -1
  89. package/dist/src/cli/pr-desc.js.map +0 -1
  90. package/dist/src/cli/pr-review-comments.d.ts.map +0 -1
  91. package/dist/src/cli/pr-review-comments.js.map +0 -1
  92. package/dist/src/cli/pr.d.ts.map +0 -1
  93. package/dist/src/cli/pr.js.map +0 -1
  94. package/dist/src/cli/preflight.d.ts.map +0 -1
  95. package/dist/src/cli/preflight.js.map +0 -1
  96. package/dist/src/cli/report.d.ts.map +0 -1
  97. package/dist/src/cli/report.js.map +0 -1
  98. package/dist/src/cli/run.d.ts.map +0 -1
  99. package/dist/src/cli/run.js.map +0 -1
  100. package/dist/src/cli/scan.d.ts.map +0 -1
  101. package/dist/src/cli/scan.js.map +0 -1
  102. package/dist/src/cli/setup.d.ts.map +0 -1
  103. package/dist/src/cli/setup.js.map +0 -1
  104. package/dist/src/cli/test-gen.d.ts.map +0 -1
  105. package/dist/src/cli/test-gen.js.map +0 -1
  106. package/dist/src/cli/triage.d.ts.map +0 -1
  107. package/dist/src/cli/triage.js.map +0 -1
  108. package/dist/src/cli/watch.d.ts.map +0 -1
  109. package/dist/src/cli/watch.js.map +0 -1
  110. package/dist/src/cli/worker.d.ts.map +0 -1
  111. package/dist/src/cli/worker.js.map +0 -1
  112. package/dist/src/core/cache/cached-engine.d.ts.map +0 -1
  113. package/dist/src/core/cache/cached-engine.js.map +0 -1
  114. package/dist/src/core/cache/review-cache.d.ts.map +0 -1
  115. package/dist/src/core/cache/review-cache.js.map +0 -1
  116. package/dist/src/core/chunking/index.d.ts.map +0 -1
  117. package/dist/src/core/chunking/index.js.map +0 -1
  118. package/dist/src/core/chunking/risk-ranker.d.ts.map +0 -1
  119. package/dist/src/core/chunking/risk-ranker.js.map +0 -1
  120. package/dist/src/core/config/loader.d.ts.map +0 -1
  121. package/dist/src/core/config/loader.js.map +0 -1
  122. package/dist/src/core/config/preset-resolver.d.ts.map +0 -1
  123. package/dist/src/core/config/preset-resolver.js.map +0 -1
  124. package/dist/src/core/config/schema.d.ts.map +0 -1
  125. package/dist/src/core/config/schema.js.map +0 -1
  126. package/dist/src/core/config/types.d.ts.map +0 -1
  127. package/dist/src/core/config/types.js.map +0 -1
  128. package/dist/src/core/council/config.d.ts.map +0 -1
  129. package/dist/src/core/council/config.js.map +0 -1
  130. package/dist/src/core/council/context.d.ts.map +0 -1
  131. package/dist/src/core/council/context.js.map +0 -1
  132. package/dist/src/core/council/runner.d.ts.map +0 -1
  133. package/dist/src/core/council/runner.js.map +0 -1
  134. package/dist/src/core/council/types.d.ts.map +0 -1
  135. package/dist/src/core/council/types.js.map +0 -1
  136. package/dist/src/core/detect/git-context.d.ts.map +0 -1
  137. package/dist/src/core/detect/git-context.js.map +0 -1
  138. package/dist/src/core/detect/llm-key.d.ts.map +0 -1
  139. package/dist/src/core/detect/llm-key.js.map +0 -1
  140. package/dist/src/core/detect/protected-paths.d.ts.map +0 -1
  141. package/dist/src/core/detect/protected-paths.js.map +0 -1
  142. package/dist/src/core/detect/provider-usage.d.ts.map +0 -1
  143. package/dist/src/core/detect/provider-usage.js.map +0 -1
  144. package/dist/src/core/detect/stack.d.ts.map +0 -1
  145. package/dist/src/core/detect/stack.js.map +0 -1
  146. package/dist/src/core/detect/workspaces.d.ts.map +0 -1
  147. package/dist/src/core/detect/workspaces.js.map +0 -1
  148. package/dist/src/core/errors.d.ts.map +0 -1
  149. package/dist/src/core/errors.js.map +0 -1
  150. package/dist/src/core/findings/dedup.d.ts.map +0 -1
  151. package/dist/src/core/findings/dedup.js.map +0 -1
  152. package/dist/src/core/findings/types.d.ts.map +0 -1
  153. package/dist/src/core/findings/types.js.map +0 -1
  154. package/dist/src/core/fix/generator.d.ts.map +0 -1
  155. package/dist/src/core/fix/generator.js.map +0 -1
  156. package/dist/src/core/git/diff-hunks.d.ts.map +0 -1
  157. package/dist/src/core/git/diff-hunks.js.map +0 -1
  158. package/dist/src/core/git/touched-files.d.ts.map +0 -1
  159. package/dist/src/core/git/touched-files.js.map +0 -1
  160. package/dist/src/core/ignore/index.d.ts.map +0 -1
  161. package/dist/src/core/ignore/index.js.map +0 -1
  162. package/dist/src/core/index.d.ts.map +0 -1
  163. package/dist/src/core/index.js.map +0 -1
  164. package/dist/src/core/logging/ndjson-writer.d.ts.map +0 -1
  165. package/dist/src/core/logging/ndjson-writer.js.map +0 -1
  166. package/dist/src/core/logging/redaction.d.ts.map +0 -1
  167. package/dist/src/core/logging/redaction.js.map +0 -1
  168. package/dist/src/core/mcp/concurrency.d.ts.map +0 -1
  169. package/dist/src/core/mcp/concurrency.js.map +0 -1
  170. package/dist/src/core/mcp/handlers/fix-finding.d.ts.map +0 -1
  171. package/dist/src/core/mcp/handlers/fix-finding.js.map +0 -1
  172. package/dist/src/core/mcp/handlers/get-capabilities.d.ts.map +0 -1
  173. package/dist/src/core/mcp/handlers/get-capabilities.js.map +0 -1
  174. package/dist/src/core/mcp/handlers/get-findings.d.ts.map +0 -1
  175. package/dist/src/core/mcp/handlers/get-findings.js.map +0 -1
  176. package/dist/src/core/mcp/handlers/review-diff.d.ts.map +0 -1
  177. package/dist/src/core/mcp/handlers/review-diff.js.map +0 -1
  178. package/dist/src/core/mcp/handlers/scan-files.d.ts.map +0 -1
  179. package/dist/src/core/mcp/handlers/scan-files.js.map +0 -1
  180. package/dist/src/core/mcp/handlers/validate-fix.d.ts.map +0 -1
  181. package/dist/src/core/mcp/handlers/validate-fix.js.map +0 -1
  182. package/dist/src/core/mcp/run-store.d.ts.map +0 -1
  183. package/dist/src/core/mcp/run-store.js.map +0 -1
  184. package/dist/src/core/mcp/workspace.d.ts.map +0 -1
  185. package/dist/src/core/mcp/workspace.js.map +0 -1
  186. package/dist/src/core/persist/baseline.d.ts.map +0 -1
  187. package/dist/src/core/persist/baseline.js.map +0 -1
  188. package/dist/src/core/persist/cost-log.d.ts.map +0 -1
  189. package/dist/src/core/persist/cost-log.js.map +0 -1
  190. package/dist/src/core/persist/findings-cache.d.ts.map +0 -1
  191. package/dist/src/core/persist/findings-cache.js.map +0 -1
  192. package/dist/src/core/persist/triage.d.ts.map +0 -1
  193. package/dist/src/core/persist/triage.js.map +0 -1
  194. package/dist/src/core/phases/static-rules.d.ts.map +0 -1
  195. package/dist/src/core/phases/static-rules.js.map +0 -1
  196. package/dist/src/core/phases/tests.d.ts.map +0 -1
  197. package/dist/src/core/phases/tests.js.map +0 -1
  198. package/dist/src/core/pipeline/review-phase.d.ts.map +0 -1
  199. package/dist/src/core/pipeline/review-phase.js.map +0 -1
  200. package/dist/src/core/pipeline/run.d.ts.map +0 -1
  201. package/dist/src/core/pipeline/run.js.map +0 -1
  202. package/dist/src/core/runtime/idempotency.d.ts.map +0 -1
  203. package/dist/src/core/runtime/idempotency.js.map +0 -1
  204. package/dist/src/core/runtime/lock.d.ts.map +0 -1
  205. package/dist/src/core/runtime/lock.js.map +0 -1
  206. package/dist/src/core/runtime/state.d.ts.map +0 -1
  207. package/dist/src/core/runtime/state.js.map +0 -1
  208. package/dist/src/core/schema-alignment/detector.d.ts.map +0 -1
  209. package/dist/src/core/schema-alignment/detector.js.map +0 -1
  210. package/dist/src/core/schema-alignment/extractor/index.d.ts.map +0 -1
  211. package/dist/src/core/schema-alignment/extractor/index.js.map +0 -1
  212. package/dist/src/core/schema-alignment/extractor/prisma.d.ts.map +0 -1
  213. package/dist/src/core/schema-alignment/extractor/prisma.js.map +0 -1
  214. package/dist/src/core/schema-alignment/extractor/sql.d.ts.map +0 -1
  215. package/dist/src/core/schema-alignment/extractor/sql.js.map +0 -1
  216. package/dist/src/core/schema-alignment/llm-check.d.ts.map +0 -1
  217. package/dist/src/core/schema-alignment/llm-check.js.map +0 -1
  218. package/dist/src/core/schema-alignment/scanner.d.ts.map +0 -1
  219. package/dist/src/core/schema-alignment/scanner.js.map +0 -1
  220. package/dist/src/core/schema-alignment/types.d.ts.map +0 -1
  221. package/dist/src/core/schema-alignment/types.js.map +0 -1
  222. package/dist/src/core/shell.d.ts.map +0 -1
  223. package/dist/src/core/shell.js.map +0 -1
  224. package/dist/src/core/static-rules/registry.d.ts.map +0 -1
  225. package/dist/src/core/static-rules/registry.js.map +0 -1
  226. package/dist/src/core/static-rules/rules/brand-tokens.d.ts.map +0 -1
  227. package/dist/src/core/static-rules/rules/brand-tokens.js.map +0 -1
  228. package/dist/src/core/static-rules/rules/console-log.d.ts.map +0 -1
  229. package/dist/src/core/static-rules/rules/console-log.js.map +0 -1
  230. package/dist/src/core/static-rules/rules/hardcoded-secrets.d.ts.map +0 -1
  231. package/dist/src/core/static-rules/rules/hardcoded-secrets.js.map +0 -1
  232. package/dist/src/core/static-rules/rules/insecure-redirect.d.ts.map +0 -1
  233. package/dist/src/core/static-rules/rules/insecure-redirect.js.map +0 -1
  234. package/dist/src/core/static-rules/rules/large-file.d.ts.map +0 -1
  235. package/dist/src/core/static-rules/rules/large-file.js.map +0 -1
  236. package/dist/src/core/static-rules/rules/missing-auth.d.ts.map +0 -1
  237. package/dist/src/core/static-rules/rules/missing-auth.js.map +0 -1
  238. package/dist/src/core/static-rules/rules/missing-tests.d.ts.map +0 -1
  239. package/dist/src/core/static-rules/rules/missing-tests.js.map +0 -1
  240. package/dist/src/core/static-rules/rules/npm-audit.d.ts.map +0 -1
  241. package/dist/src/core/static-rules/rules/npm-audit.js.map +0 -1
  242. package/dist/src/core/static-rules/rules/package-lock-sync.d.ts.map +0 -1
  243. package/dist/src/core/static-rules/rules/package-lock-sync.js.map +0 -1
  244. package/dist/src/core/static-rules/rules/schema-alignment.d.ts.map +0 -1
  245. package/dist/src/core/static-rules/rules/schema-alignment.js.map +0 -1
  246. package/dist/src/core/static-rules/rules/sql-injection.d.ts.map +0 -1
  247. package/dist/src/core/static-rules/rules/sql-injection.js.map +0 -1
  248. package/dist/src/core/static-rules/rules/ssrf.d.ts.map +0 -1
  249. package/dist/src/core/static-rules/rules/ssrf.js.map +0 -1
  250. package/dist/src/core/static-rules/rules/todo-fixme.d.ts.map +0 -1
  251. package/dist/src/core/static-rules/rules/todo-fixme.js.map +0 -1
  252. package/dist/src/core/static-rules/tailwind-extractor.d.ts.map +0 -1
  253. package/dist/src/core/static-rules/tailwind-extractor.js.map +0 -1
  254. package/dist/src/core/test-gen/coverage-analyzer.d.ts.map +0 -1
  255. package/dist/src/core/test-gen/coverage-analyzer.js.map +0 -1
  256. package/dist/src/core/test-gen/framework-detector.d.ts.map +0 -1
  257. package/dist/src/core/test-gen/framework-detector.js.map +0 -1
  258. package/dist/src/core/test-gen/test-writer.d.ts.map +0 -1
  259. package/dist/src/core/test-gen/test-writer.js.map +0 -1
  260. package/dist/src/core/ui/design-context-loader.d.ts.map +0 -1
  261. package/dist/src/core/ui/design-context-loader.js.map +0 -1
  262. package/dist/src/core/worker/client.d.ts.map +0 -1
  263. package/dist/src/core/worker/client.js.map +0 -1
  264. package/dist/src/core/worker/lockfile.d.ts.map +0 -1
  265. package/dist/src/core/worker/lockfile.js.map +0 -1
  266. package/dist/src/core/worker/server.d.ts.map +0 -1
  267. package/dist/src/core/worker/server.js.map +0 -1
  268. package/dist/src/formatters/github-annotations.d.ts.map +0 -1
  269. package/dist/src/formatters/github-annotations.js.map +0 -1
  270. package/dist/src/formatters/index.d.ts.map +0 -1
  271. package/dist/src/formatters/index.js.map +0 -1
  272. package/dist/src/formatters/junit.d.ts.map +0 -1
  273. package/dist/src/formatters/junit.js.map +0 -1
  274. package/dist/src/formatters/sarif.d.ts.map +0 -1
  275. package/dist/src/formatters/sarif.js.map +0 -1
  276. package/dist/src/index.d.ts.map +0 -1
  277. package/dist/src/index.js.map +0 -1
  278. package/src/adapters/base.ts +0 -19
  279. package/src/adapters/council/claude.ts +0 -41
  280. package/src/adapters/council/openai.ts +0 -40
  281. package/src/adapters/council/types.ts +0 -7
  282. package/src/adapters/loader.ts +0 -108
  283. package/src/adapters/migration-runner/supabase.ts +0 -56
  284. package/src/adapters/migration-runner/types.ts +0 -36
  285. package/src/adapters/review-bot-parser/cursor.ts +0 -13
  286. package/src/adapters/review-bot-parser/declarative-base.ts +0 -64
  287. package/src/adapters/review-bot-parser/types.ts +0 -9
  288. package/src/adapters/review-engine/auto.ts +0 -94
  289. package/src/adapters/review-engine/claude.ts +0 -100
  290. package/src/adapters/review-engine/codex.ts +0 -82
  291. package/src/adapters/review-engine/gemini.ts +0 -105
  292. package/src/adapters/review-engine/openai-compatible.ts +0 -100
  293. package/src/adapters/review-engine/parse-output.ts +0 -74
  294. package/src/adapters/review-engine/prompt-builder.ts +0 -19
  295. package/src/adapters/review-engine/types.ts +0 -19
  296. package/src/adapters/vcs-host/commit-status.ts +0 -39
  297. package/src/adapters/vcs-host/github.ts +0 -77
  298. package/src/adapters/vcs-host/types.ts +0 -44
  299. package/src/cli/_pkg-root.ts +0 -85
  300. package/src/cli/autoregress-bridge.ts +0 -30
  301. package/src/cli/baseline.ts +0 -125
  302. package/src/cli/ci.ts +0 -45
  303. package/src/cli/costs.ts +0 -80
  304. package/src/cli/council.ts +0 -96
  305. package/src/cli/detector.ts +0 -92
  306. package/src/cli/explain.ts +0 -197
  307. package/src/cli/fix.ts +0 -249
  308. package/src/cli/hook.ts +0 -124
  309. package/src/cli/ignore-helper.ts +0 -116
  310. package/src/cli/index.ts +0 -612
  311. package/src/cli/lsp.ts +0 -200
  312. package/src/cli/mcp.ts +0 -206
  313. package/src/cli/migrate-v4.ts +0 -388
  314. package/src/cli/pr-comment.ts +0 -139
  315. package/src/cli/pr-desc.ts +0 -168
  316. package/src/cli/pr-review-comments.ts +0 -92
  317. package/src/cli/pr.ts +0 -76
  318. package/src/cli/preflight.ts +0 -235
  319. package/src/cli/report.ts +0 -186
  320. package/src/cli/run.ts +0 -425
  321. package/src/cli/scan.ts +0 -233
  322. package/src/cli/setup.ts +0 -191
  323. package/src/cli/test-gen.ts +0 -125
  324. package/src/cli/triage.ts +0 -137
  325. package/src/cli/watch.ts +0 -190
  326. package/src/cli/worker.ts +0 -109
  327. package/src/core/.gitkeep +0 -0
  328. package/src/core/cache/cached-engine.ts +0 -32
  329. package/src/core/cache/review-cache.ts +0 -70
  330. package/src/core/chunking/index.ts +0 -113
  331. package/src/core/chunking/risk-ranker.ts +0 -56
  332. package/src/core/config/loader.ts +0 -53
  333. package/src/core/config/preset-resolver.ts +0 -46
  334. package/src/core/config/schema.ts +0 -181
  335. package/src/core/config/types.ts +0 -98
  336. package/src/core/council/config.ts +0 -71
  337. package/src/core/council/context.ts +0 -17
  338. package/src/core/council/runner.ts +0 -83
  339. package/src/core/council/types.ts +0 -45
  340. package/src/core/detect/git-context.ts +0 -27
  341. package/src/core/detect/llm-key.ts +0 -89
  342. package/src/core/detect/protected-paths.ts +0 -63
  343. package/src/core/detect/provider-usage.ts +0 -74
  344. package/src/core/detect/stack.ts +0 -153
  345. package/src/core/detect/workspaces.ts +0 -103
  346. package/src/core/errors.ts +0 -37
  347. package/src/core/findings/dedup.ts +0 -14
  348. package/src/core/findings/types.ts +0 -39
  349. package/src/core/fix/generator.ts +0 -149
  350. package/src/core/git/diff-hunks.ts +0 -86
  351. package/src/core/git/touched-files.ts +0 -73
  352. package/src/core/ignore/index.ts +0 -54
  353. package/src/core/index.ts +0 -1
  354. package/src/core/logging/ndjson-writer.ts +0 -37
  355. package/src/core/logging/redaction.ts +0 -19
  356. package/src/core/mcp/concurrency.ts +0 -16
  357. package/src/core/mcp/handlers/fix-finding.ts +0 -126
  358. package/src/core/mcp/handlers/get-capabilities.ts +0 -62
  359. package/src/core/mcp/handlers/get-findings.ts +0 -36
  360. package/src/core/mcp/handlers/review-diff.ts +0 -65
  361. package/src/core/mcp/handlers/scan-files.ts +0 -65
  362. package/src/core/mcp/handlers/validate-fix.ts +0 -41
  363. package/src/core/mcp/run-store.ts +0 -85
  364. package/src/core/mcp/workspace.ts +0 -35
  365. package/src/core/persist/baseline.ts +0 -112
  366. package/src/core/persist/cost-log.ts +0 -30
  367. package/src/core/persist/findings-cache.ts +0 -43
  368. package/src/core/persist/triage.ts +0 -112
  369. package/src/core/phases/static-rules.ts +0 -93
  370. package/src/core/phases/tests.ts +0 -51
  371. package/src/core/pipeline/review-phase.ts +0 -182
  372. package/src/core/pipeline/run.ts +0 -116
  373. package/src/core/runtime/idempotency.ts +0 -6
  374. package/src/core/runtime/lock.ts +0 -29
  375. package/src/core/runtime/state.ts +0 -97
  376. package/src/core/schema-alignment/detector.ts +0 -59
  377. package/src/core/schema-alignment/extractor/index.ts +0 -24
  378. package/src/core/schema-alignment/extractor/prisma.ts +0 -21
  379. package/src/core/schema-alignment/extractor/sql.ts +0 -99
  380. package/src/core/schema-alignment/llm-check.ts +0 -91
  381. package/src/core/schema-alignment/scanner.ts +0 -107
  382. package/src/core/schema-alignment/types.ts +0 -43
  383. package/src/core/shell.ts +0 -48
  384. package/src/core/static-rules/registry.ts +0 -59
  385. package/src/core/static-rules/rules/brand-tokens.ts +0 -145
  386. package/src/core/static-rules/rules/console-log.ts +0 -42
  387. package/src/core/static-rules/rules/hardcoded-secrets.ts +0 -83
  388. package/src/core/static-rules/rules/insecure-redirect.ts +0 -67
  389. package/src/core/static-rules/rules/large-file.ts +0 -37
  390. package/src/core/static-rules/rules/missing-auth.ts +0 -70
  391. package/src/core/static-rules/rules/missing-tests.ts +0 -57
  392. package/src/core/static-rules/rules/npm-audit.ts +0 -38
  393. package/src/core/static-rules/rules/package-lock-sync.ts +0 -54
  394. package/src/core/static-rules/rules/schema-alignment.ts +0 -132
  395. package/src/core/static-rules/rules/sql-injection.ts +0 -71
  396. package/src/core/static-rules/rules/ssrf.ts +0 -63
  397. package/src/core/static-rules/rules/todo-fixme.ts +0 -40
  398. package/src/core/static-rules/tailwind-extractor.ts +0 -38
  399. package/src/core/test-gen/coverage-analyzer.ts +0 -93
  400. package/src/core/test-gen/framework-detector.ts +0 -21
  401. package/src/core/test-gen/test-writer.ts +0 -33
  402. package/src/core/ui/design-context-loader.ts +0 -87
  403. package/src/core/worker/client.ts +0 -46
  404. package/src/core/worker/lockfile.ts +0 -38
  405. package/src/core/worker/server.ts +0 -81
  406. package/src/formatters/github-annotations.ts +0 -36
  407. package/src/formatters/index.ts +0 -3
  408. package/src/formatters/junit.ts +0 -52
  409. package/src/formatters/sarif.ts +0 -103
  410. 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
- }