karajan-code 4.70.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/retired-commands.js +49 -0
  68. package/src/cli.js +18 -5
  69. package/src/commands/agent-run.js +40 -26
  70. package/src/commands/audit.js +127 -124
  71. package/src/commands/board.js +5 -9
  72. package/src/commands/check.js +29 -16
  73. package/src/commands/doctor.js +2 -0
  74. package/src/commands/env.js +176 -150
  75. package/src/commands/go.js +71 -53
  76. package/src/commands/harden.js +90 -81
  77. package/src/commands/hu-start.js +52 -0
  78. package/src/commands/hu.js +288 -221
  79. package/src/commands/identity.js +111 -78
  80. package/src/commands/init-atril.js +47 -0
  81. package/src/commands/init.js +11 -40
  82. package/src/commands/install-tools.js +70 -85
  83. package/src/commands/main-guard.js +78 -0
  84. package/src/commands/policy.js +226 -184
  85. package/src/commands/qmd.js +27 -21
  86. package/src/commands/rag.js +75 -48
  87. package/src/commands/review-gate.js +421 -341
  88. package/src/commands/start.js +4 -5
  89. package/src/commands/steward.js +96 -47
  90. package/src/commands/tournament.js +46 -37
  91. package/src/commands/worktree.js +94 -25
  92. package/src/config/loader.js +34 -17
  93. package/src/config/secrets.js +36 -0
  94. package/src/config.js +1 -0
  95. package/src/environment/adr.js +16 -2
  96. package/src/git/karajan-label.js +20 -8
  97. package/src/guards/main-guard.js +54 -0
  98. package/src/harden/hook-templates.js +16 -1
  99. package/src/harden/sentinel/posttooluse.mjs +18 -6
  100. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  101. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  102. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  103. package/src/harden/sentinel/sessionstart.mjs +3 -2
  104. package/src/harden/sentinel/stop.mjs +5 -4
  105. package/src/harden/workflow-templates.js +1 -1
  106. package/src/hu/board-lookup.js +29 -0
  107. package/src/hu/gh-identity.js +23 -0
  108. package/src/hu/github-board.js +4 -2
  109. package/src/hu/lane-prune.js +15 -7
  110. package/src/hu/lane-setup.js +65 -0
  111. package/src/hu/lanes.js +66 -0
  112. package/src/hu/team-board-mirror.js +3 -2
  113. package/src/infrastructure/command-runner.js +1 -1
  114. package/src/infrastructure/file-system-service.js +1 -1
  115. package/src/mcp/handlers/direct-handlers.js +2 -292
  116. package/src/mcp/handlers/hu-handlers.js +1 -35
  117. package/src/mcp/handlers/management-handlers.js +2 -42
  118. package/src/mcp/server-handlers.js +16 -22
  119. package/src/mcp/tools.js +1 -196
  120. package/src/plan/lane-plans.js +54 -0
  121. package/src/plan/plan-store.js +7 -4
  122. package/src/policy/add.js +26 -12
  123. package/src/policy/adr-number-check.js +31 -0
  124. package/src/prompts/audit.js +299 -339
  125. package/src/prompts/card-context.js +10 -5
  126. package/src/prompts/reviewer.js +5 -2
  127. package/src/rag/auto-update.js +56 -43
  128. package/src/rag/bootstrap-index.js +28 -54
  129. package/src/rag/migrate.js +1 -1
  130. package/src/rag/onnx-fallback.js +2 -2
  131. package/src/rag/pid-lease.js +70 -0
  132. package/src/rag/project-store.js +2 -12
  133. package/src/review/card-first.js +57 -46
  134. package/src/review/gate-gitignore.js +23 -4
  135. package/src/review/gate-hook.js +12 -4
  136. package/src/review/one-shot-review.js +45 -35
  137. package/src/review/publish-pr.js +14 -2
  138. package/src/review/repo-docs.js +73 -0
  139. package/src/review/repo-stack.js +59 -0
  140. package/src/review/reviewer-fallback.js +19 -4
  141. package/src/review/seal-commit.js +29 -0
  142. package/src/review/sonar-pregate.js +59 -44
  143. package/src/review/third-party-review.js +90 -16
  144. package/src/review/third-party-size.js +43 -0
  145. package/src/review/third-party-skills.js +54 -0
  146. package/src/review/verify-pr.js +1 -24
  147. package/src/roles/audit-role.js +106 -125
  148. package/src/skills/atril-skills.js +5 -4
  149. package/src/sonar/scanner.js +116 -101
  150. package/src/steward/invariants.js +5 -4
  151. package/src/steward/phantom-sweep.js +66 -0
  152. package/src/tournament/judge.js +60 -53
  153. package/src/utils/gh-account.js +37 -0
  154. package/src/utils/git.js +0 -13
  155. package/src/utils/home-migration.js +7 -1
  156. package/src/utils/main-checkout.js +53 -0
  157. package/src/utils/qmd-collection.js +3 -1
  158. package/src/utils/welcome.js +3 -3
  159. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  160. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  161. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  162. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  163. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  164. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  165. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  166. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  167. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  172. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  173. package/packages/hu-board/src/run-tracker.js +0 -121
  174. package/src/activity-log.js +0 -59
  175. package/src/agents/host-agent.js +0 -38
  176. package/src/agents/model-registry.js +0 -142
  177. package/src/audit/plan-adherence.js +0 -224
  178. package/src/autonomy/arbiter-role.js +0 -71
  179. package/src/autonomy/arbiter.js +0 -22
  180. package/src/autonomy/decider.js +0 -18
  181. package/src/autonomy/decision-resolver.js +0 -58
  182. package/src/autonomy/outcome-report.js +0 -55
  183. package/src/autonomy/stage-ask.js +0 -30
  184. package/src/brain/decision-tracker.js +0 -125
  185. package/src/brain/decisor.js +0 -243
  186. package/src/brain/solomon-consult.js +0 -171
  187. package/src/brain/standby-scheduler.js +0 -8
  188. package/src/budget/comparison.js +0 -96
  189. package/src/canvas/parse-md.js +0 -238
  190. package/src/canvas/schema.js +0 -101
  191. package/src/canvas/to-flat.js +0 -85
  192. package/src/canvas/validate.js +0 -163
  193. package/src/ci/dispatch.js +0 -99
  194. package/src/ci/index.js +0 -3
  195. package/src/ci/pr-diff.js +0 -26
  196. package/src/cli/register-standby.js +0 -26
  197. package/src/commands/architect.js +0 -111
  198. package/src/commands/autorun.js +0 -49
  199. package/src/commands/researcher.js +0 -54
  200. package/src/commands/resume.js +0 -72
  201. package/src/commands/review.js +0 -89
  202. package/src/commands/run.js +0 -185
  203. package/src/commands/standby.js +0 -117
  204. package/src/commands/status.js +0 -36
  205. package/src/commands/triage.js +0 -78
  206. package/src/commands/undo.js +0 -62
  207. package/src/domains/domain-loader.js +0 -245
  208. package/src/domains/domain-registry.js +0 -140
  209. package/src/domains/domain-synthesizer.js +0 -129
  210. package/src/git/automation.js +0 -433
  211. package/src/git/coder-commit-guard.js +0 -40
  212. package/src/git/hu-automation.js +0 -243
  213. package/src/git/hu-snapshot.js +0 -10
  214. package/src/git/symlink-targets.js +0 -57
  215. package/src/golden/asserter.js +0 -92
  216. package/src/golden/loader.js +0 -52
  217. package/src/golden/runner.js +0 -92
  218. package/src/golden/schema.js +0 -41
  219. package/src/guards/duplicate-members.js +0 -86
  220. package/src/guards/intent-guard.js +0 -161
  221. package/src/guards/perf-guard.js +0 -126
  222. package/src/guards/policy-guard.js +0 -90
  223. package/src/guards/policy-resolver.js +0 -85
  224. package/src/guards/secret-redactor.js +0 -71
  225. package/src/hu/acceptance-runner.js +0 -138
  226. package/src/hu/lazy-planner.js +0 -109
  227. package/src/hu/parallel-executor.js +0 -94
  228. package/src/hu/routing-metrics.js +0 -17
  229. package/src/hu/split-validator.js +0 -143
  230. package/src/hu/splitting-detector.js +0 -158
  231. package/src/hu/splitting-generator.js +0 -175
  232. package/src/hu/store.js +0 -394
  233. package/src/infrastructure/mocks.js +0 -182
  234. package/src/mcp/handlers/run-handler.js +0 -318
  235. package/src/mcp/sovereignty-guard.js +0 -113
  236. package/src/mcp/tool-arg-normalizers.js +0 -16
  237. package/src/mutate/reviewer-signal.js +0 -76
  238. package/src/orchestrator/agent-fallback.js +0 -81
  239. package/src/orchestrator/brain-coordinator.js +0 -186
  240. package/src/orchestrator/ci-integration.js +0 -139
  241. package/src/orchestrator/config-init.js +0 -426
  242. package/src/orchestrator/direct-actions.js +0 -217
  243. package/src/orchestrator/drivers/error-recovery.js +0 -287
  244. package/src/orchestrator/drivers/init-context.js +0 -238
  245. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  246. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  247. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  248. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  249. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  250. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  251. package/src/orchestrator/drivers/post-loop.js +0 -404
  252. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  253. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  254. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  255. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  256. package/src/orchestrator/drivers/pre-loop.js +0 -524
  257. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  258. package/src/orchestrator/feedback-enrichment.js +0 -140
  259. package/src/orchestrator/feedback-queue.js +0 -151
  260. package/src/orchestrator/flow-control.js +0 -170
  261. package/src/orchestrator/flow-runner.js +0 -365
  262. package/src/orchestrator/fs-leak-detector.js +0 -228
  263. package/src/orchestrator/hu-scheduler.js +0 -114
  264. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  265. package/src/orchestrator/iteration-gate.js +0 -73
  266. package/src/orchestrator/iteration-stages.js +0 -9
  267. package/src/orchestrator/parallel-limiter.js +0 -74
  268. package/src/orchestrator/pipeline-context.js +0 -72
  269. package/src/orchestrator/post-loop-stages.js +0 -468
  270. package/src/orchestrator/pre-loop-stages.js +0 -11
  271. package/src/orchestrator/preflight-checks.js +0 -487
  272. package/src/orchestrator/repair/repair-detector.js +0 -117
  273. package/src/orchestrator/repair/repair-runner.js +0 -142
  274. package/src/orchestrator/reviewer-fallback.js +0 -45
  275. package/src/orchestrator/role-output-compressor.js +0 -189
  276. package/src/orchestrator/session-journal.js +0 -308
  277. package/src/orchestrator/solomon-escalation.js +0 -331
  278. package/src/orchestrator/solomon-rules.js +0 -212
  279. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  280. package/src/orchestrator/stages/architect-stage.js +0 -172
  281. package/src/orchestrator/stages/coder-stage.js +0 -506
  282. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  283. package/src/orchestrator/stages/format-stage.js +0 -61
  284. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  285. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  286. package/src/orchestrator/stages/perf-stage.js +0 -140
  287. package/src/orchestrator/stages/planner-stage.js +0 -85
  288. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  289. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  290. package/src/orchestrator/stages/research-stage.js +0 -69
  291. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  292. package/src/orchestrator/stages/sonar-stage.js +0 -439
  293. package/src/orchestrator/stages/stage-classes.js +0 -84
  294. package/src/orchestrator/stages/stage-executor.js +0 -155
  295. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  296. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  297. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  298. package/src/orchestrator/stages/triage-stage.js +0 -172
  299. package/src/orchestrator/standby.js +0 -71
  300. package/src/orchestrator/verification-gate.js +0 -183
  301. package/src/orchestrator.js +0 -22
  302. package/src/plan/adr-generator.js +0 -170
  303. package/src/plan/adr-loader.js +0 -60
  304. package/src/plan/plan-executor.js +0 -100
  305. package/src/plan/plan-validation.js +0 -4
  306. package/src/prompts/acceptance-coverage.js +0 -32
  307. package/src/prompts/arbiter.js +0 -38
  308. package/src/prompts/architect.js +0 -103
  309. package/src/prompts/hu-reviewer.js +0 -244
  310. package/src/prompts/tool-correctness-judge.js +0 -31
  311. package/src/prompts/triage.js +0 -57
  312. package/src/rag/embedder.js +0 -2
  313. package/src/rag/embedders/_cloud-base.js +0 -2
  314. package/src/rag/embedders/cohere.js +0 -2
  315. package/src/rag/embedders/mistral.js +0 -2
  316. package/src/rag/embedders/onnx.js +0 -2
  317. package/src/rag/embedders/openai.js +0 -2
  318. package/src/rag/embedders/voyage.js +0 -2
  319. package/src/rag/rerank.js +0 -4
  320. package/src/rag/where-parser.js +0 -4
  321. package/src/repeat-detector.js +0 -88
  322. package/src/review/diff-generator.js +0 -112
  323. package/src/review/git-stash-helper.js +0 -104
  324. package/src/review/schema.js +0 -31
  325. package/src/review/scope-filter.js +0 -152
  326. package/src/review/snapshot-diff.js +0 -122
  327. package/src/review/tdd-discipline.js +0 -90
  328. package/src/review/tdd-policy.js +0 -69
  329. package/src/roles/acceptance-coverage-role.js +0 -78
  330. package/src/roles/architect-role.js +0 -77
  331. package/src/roles/coder-role.js +0 -113
  332. package/src/roles/commiter-role.js +0 -113
  333. package/src/roles/domain-curator-role.js +0 -134
  334. package/src/roles/hu-reviewer-role.js +0 -64
  335. package/src/roles/impeccable-role.js +0 -85
  336. package/src/roles/index.js +0 -18
  337. package/src/roles/karajan-brain-role.js +0 -134
  338. package/src/roles/perf-role.js +0 -122
  339. package/src/roles/planner-role.js +0 -151
  340. package/src/roles/refactorer-role.js +0 -30
  341. package/src/roles/repairer-role.js +0 -181
  342. package/src/roles/researcher-role.js +0 -70
  343. package/src/roles/reviewer-role.js +0 -115
  344. package/src/roles/security-role.js +0 -73
  345. package/src/roles/solomon-role.js +0 -271
  346. package/src/roles/sonar-role.js +0 -72
  347. package/src/roles/tester-role.js +0 -235
  348. package/src/roles/tool-correctness-judge-role.js +0 -78
  349. package/src/roles/triage-role.js +0 -99
  350. package/src/session/journal/decisions-writer.js +0 -200
  351. package/src/session/journal/iteration-logger.js +0 -194
  352. package/src/session/journal/summary-writer.js +0 -320
  353. package/src/session/journal/tree-writer.js +0 -164
  354. package/src/session/journal/write-all.js +0 -89
  355. package/src/session-cleanup.js +0 -116
  356. package/src/skills/semantic-detector.js +0 -167
  357. package/src/skills/skill-detector.js +0 -385
  358. package/src/sonar/cloud-scanner.js +0 -78
  359. package/src/tracker-bootstrap.js +0 -44
  360. package/src/types/index.js +0 -38
  361. package/src/types/policy.js +0 -43
  362. package/src/types/solomon.js +0 -87
  363. package/src/utils/async-lock.js +0 -31
  364. package/src/utils/budget.js +0 -229
  365. package/src/utils/cwd-confirm.js +0 -39
  366. package/src/utils/display/event-handlers.js +0 -403
  367. package/src/utils/display/formatters.js +0 -132
  368. package/src/utils/display/header.js +0 -47
  369. package/src/utils/display/session-summary.js +0 -118
  370. package/src/utils/display/solomon.js +0 -42
  371. package/src/utils/pricing.js +0 -29
  372. package/src/utils/quota-simulator.js +0 -56
  373. package/src/utils/role-assigner.js +0 -137
  374. package/src/utils/rtk-wrapper.js +0 -87
  375. package/src/utils/run-registry.js +0 -9
  376. package/src/utils/status-dashboard.js +0 -254
  377. package/src/utils/tool-call-extractor.js +0 -56
  378. package/src/webperf/devtools-detect.js +0 -112
  379. package/src/webperf/webperf-role-integration.js +0 -66
  380. package/templates/skills/kj-run.md +0 -73
@@ -1,161 +0,0 @@
1
- import { VALID_TASK_TYPES } from "./policy-resolver.js";
2
-
3
- /**
4
- * Built-in intent patterns for deterministic pre-triage classification.
5
- * Each pattern maps keywords/regex to a taskType + complexity level.
6
- * Evaluated top-down; first match with confidence >= threshold wins.
7
- */
8
- const INTENT_PATTERNS = [
9
- // No-code tasks (data analysis, document generation, SQL queries, CSV transforms)
10
- // Placed before audit so specific multi-word patterns win over single-word "analizar"/"analyze"
11
- {
12
- id: "no-code",
13
- keywords: [
14
- "generate report", "create document", "analyze data", "transform csv",
15
- "sql query", "sql queries", "generate queries", "data analysis", "process data",
16
- "export to", "import from", "convert data", "parse file",
17
- "generar informe", "crear documento", "analizar datos", "transformar csv",
18
- "consulta sql", "generar consultas", "analisis de datos", "procesar datos",
19
- "exportar a", "importar de", "convertir datos", "parsear fichero",
20
- ],
21
- taskType: "no-code",
22
- level: "simple",
23
- confidence: 0.9,
24
- message: "No-code task detected — TDD and SonarQube disabled, coder generates non-code output",
25
- },
26
- // Audit / analysis tasks (no code changes, read-only analysis)
27
- {
28
- id: "audit",
29
- keywords: ["audit", "review", "analyze", "check", "verify", "inspect", "scan", "auditar", "revisar", "analizar", "comprobar", "verificar", "inspeccionar"],
30
- taskType: "audit",
31
- level: "simple",
32
- confidence: 0.9,
33
- message: "Audit/analysis task detected — skipping coder and reviewer",
34
- },
35
- // Documentation-only tasks
36
- {
37
- id: "doc-readme",
38
- keywords: ["readme", "docs", "documentation", "jsdoc", "typedoc", "changelog"],
39
- taskType: "doc",
40
- level: "trivial",
41
- confidence: 0.95,
42
- message: "Documentation-only task detected",
43
- },
44
- // Test-only tasks
45
- {
46
- id: "add-tests",
47
- keywords: ["add test", "write test", "missing test", "test coverage", "add spec", "write spec", "unit test", "integration test"],
48
- taskType: "add-tests",
49
- level: "simple",
50
- confidence: 0.9,
51
- message: "Test-addition task detected",
52
- },
53
- // Refactoring tasks
54
- {
55
- id: "refactor",
56
- keywords: ["refactor", "rename", "extract method", "extract function", "clean up", "cleanup", "reorganize", "restructure", "simplify"],
57
- taskType: "refactor",
58
- level: "simple",
59
- confidence: 0.85,
60
- message: "Refactoring task detected",
61
- },
62
- // Infrastructure / DevOps tasks
63
- {
64
- id: "infra-devops",
65
- keywords: ["ci/cd", "pipeline", "dockerfile", "docker-compose", "kubernetes", "k8s", "terraform", "deploy", "nginx", "github actions", "gitlab ci"],
66
- taskType: "infra",
67
- level: "simple",
68
- confidence: 0.85,
69
- message: "Infrastructure/DevOps task detected",
70
- },
71
- // Trivial fixes (typos, comments, formatting)
72
- {
73
- id: "trivial-fix",
74
- keywords: ["typo", "fix typo", "spelling", "comment", "fix comment", "formatting", "lint", "fix lint", "whitespace"],
75
- taskType: "sw",
76
- level: "trivial",
77
- confidence: 0.9,
78
- message: "Trivial fix detected",
79
- },
80
- // Frontend / UI tasks (sets hasFrontend flag for impeccable role activation)
81
- {
82
- id: "frontend-ui",
83
- keywords: ["html", "css", "ui", "landing", "component", "responsive", "accessibility", "a11y", "frontend", "design", "layout", "styling", "dark mode", "animation"],
84
- taskType: "sw",
85
- level: "simple",
86
- confidence: 0.8,
87
- message: "Frontend/UI task detected",
88
- hasFrontend: true,
89
- },
90
- ];
91
-
92
- /**
93
- * Compile custom intent patterns from config.guards.intent.patterns
94
- * Custom patterns are evaluated BEFORE built-in ones.
95
- */
96
- export function compileIntentPatterns(configGuards) {
97
- const custom = Array.isArray(configGuards?.intent?.patterns)
98
- ? configGuards.intent.patterns.map(p => ({
99
- id: p.id || "custom-intent",
100
- keywords: Array.isArray(p.keywords) ? p.keywords : [],
101
- taskType: VALID_TASK_TYPES.has(p.taskType) ? p.taskType : "sw",
102
- level: p.level || "simple",
103
- confidence: typeof p.confidence === "number" ? p.confidence : 0.85,
104
- message: p.message || "Custom intent pattern matched",
105
- }))
106
- : [];
107
-
108
- return [...custom, ...INTENT_PATTERNS];
109
- }
110
-
111
- /**
112
- * Check if a task description matches any of the keywords.
113
- * Returns true if at least one keyword (case-insensitive substring) appears in the task.
114
- */
115
- function matchesKeywords(task, keywords) {
116
- const lower = task.toLowerCase();
117
- for (const kw of keywords) {
118
- if (lower.includes(kw.toLowerCase())) {
119
- return true;
120
- }
121
- }
122
- return false;
123
- }
124
-
125
- /**
126
- * Classify a task description using deterministic keyword patterns.
127
- *
128
- * Returns:
129
- * { classified: true, taskType, level, confidence, patternId, message }
130
- * or { classified: false } if no pattern matches above threshold
131
- */
132
- export function classifyIntent(task, config = {}) {
133
- if (!task || typeof task !== "string") {
134
- return { classified: false };
135
- }
136
-
137
- const configGuards = config?.guards || {};
138
- const threshold = configGuards?.intent?.confidence_threshold ?? 0.85;
139
- const patterns = compileIntentPatterns(configGuards);
140
-
141
- for (const pattern of patterns) {
142
- if (!matchesKeywords(task, pattern.keywords)) continue;
143
-
144
- if (pattern.confidence >= threshold) {
145
- const result = {
146
- classified: true,
147
- taskType: pattern.taskType,
148
- level: pattern.level,
149
- confidence: pattern.confidence,
150
- patternId: pattern.id,
151
- message: pattern.message,
152
- };
153
- if (pattern.hasFrontend) result.hasFrontend = true;
154
- return result;
155
- }
156
- }
157
-
158
- return { classified: false };
159
- }
160
-
161
- export { INTENT_PATTERNS };
@@ -1,126 +0,0 @@
1
- const FRONTEND_EXTENSIONS = new Set([".html", ".htm", ".css", ".jsx", ".tsx", ".astro", ".vue", ".svelte"]);
2
-
3
- // Built-in perf anti-patterns (applied to added lines in frontend files)
4
- const PERF_PATTERNS = [
5
- { id: "img-no-dimensions", pattern: /<img\b(?![^>]*\bwidth\b)(?![^>]*\bheight\b)[^>]*>/i, severity: "warning", message: "Image without width/height attributes (causes CLS)" },
6
- { id: "img-no-lazy", pattern: /<img\b(?![^>]*\bloading\s*=)(?![^>]*\bfetchpriority\s*=)[^>]*>/i, severity: "info", message: "Image without loading=\"lazy\" or fetchpriority (consider lazy loading)" },
7
- { id: "script-no-defer", pattern: /<script\b(?![^>]*\b(?:defer|async)\b)(?![^>]*type\s*=\s*["']module["'])[^>]*src\s*=/i, severity: "warning", message: "External script without defer/async (render-blocking)" },
8
- { id: "font-no-display", pattern: /@font-face\s*\{(?![^}]*font-display)/i, severity: "warning", message: "@font-face without font-display (causes FOIT)" },
9
- { id: "css-import", pattern: /@import\s+(?:url\()?["'](?!.*\.module\.)/i, severity: "info", message: "CSS @import (causes sequential loading, prefer <link>)" },
10
- { id: "inline-style-large", pattern: /style\s*=\s*["'][^"']{200,}["']/i, severity: "warning", message: "Large inline style (>200 chars, consider external CSS)" },
11
- { id: "document-write", pattern: /document\.write\s*\(/, severity: "warning", message: "document.write() blocks parsing and degrades performance" },
12
- ];
13
-
14
- // Patterns for package.json changes (heavy dependencies added)
15
- const HEAVY_DEPS = [
16
- { id: "heavy-moment", pattern: /"moment"/, severity: "info", message: "moment.js added (consider dayjs or date-fns for smaller bundle)" },
17
- { id: "heavy-lodash", pattern: /"lodash"(?!\/)/, severity: "info", message: "Full lodash added (consider lodash-es or individual imports)" },
18
- { id: "heavy-jquery", pattern: /"jquery"/, severity: "info", message: "jQuery added (consider native DOM APIs)" },
19
- ];
20
-
21
- function getExtension(filePath) {
22
- if (!filePath) return "";
23
- const dot = filePath.lastIndexOf(".");
24
- return dot >= 0 ? filePath.slice(dot).toLowerCase() : "";
25
- }
26
-
27
- /**
28
- * Check if any modified file in the diff is a frontend file
29
- */
30
- export function hasFrontendFiles(diff) {
31
- if (!diff) return false;
32
- for (const line of diff.split("\n")) {
33
- if (line.startsWith("+++ b/")) {
34
- const ext = getExtension(line.slice(6));
35
- if (FRONTEND_EXTENSIONS.has(ext)) return true;
36
- }
37
- }
38
- return false;
39
- }
40
-
41
- /**
42
- * Extract added lines grouped by file from a unified diff
43
- */
44
- function extractAddedLinesByFile(diff) {
45
- const results = [];
46
- let currentFile = null;
47
- let lineNum = 0;
48
-
49
- for (const line of diff.split("\n")) {
50
- if (line.startsWith("+++ b/")) {
51
- currentFile = line.slice(6);
52
- continue;
53
- }
54
- if (line.startsWith("@@ ")) {
55
- const match = /@@ -\d+(?:,\d+)? \+(\d+)/.exec(line);
56
- lineNum = match ? Number.parseInt(match[1], 10) - 1 : 0;
57
- continue;
58
- }
59
- if (line.startsWith("+") && !line.startsWith("+++")) {
60
- lineNum += 1;
61
- results.push({ file: currentFile, line: lineNum, content: line.slice(1) });
62
- } else if (!line.startsWith("-")) {
63
- lineNum += 1;
64
- }
65
- }
66
- return results;
67
- }
68
-
69
- /**
70
- * Scan diff for frontend performance anti-patterns.
71
- * Returns { pass: boolean, violations: [...], skipped: boolean }
72
- */
73
- export function scanPerfDiff(diff, config = {}) {
74
- if (!diff || typeof diff !== "string") {
75
- return { pass: true, violations: [], skipped: true };
76
- }
77
-
78
- if (!hasFrontendFiles(diff)) {
79
- return { pass: true, violations: [], skipped: true };
80
- }
81
-
82
- const customPatterns = Array.isArray(config?.guards?.perf?.patterns)
83
- ? config.guards.perf.patterns.map(p => ({
84
- id: p.id || "custom-perf",
85
- pattern: typeof p.pattern === "string" ? new RegExp(p.pattern, p.flags || "i") : p.pattern,
86
- severity: p.severity || "warning",
87
- message: p.message || "Custom perf pattern matched",
88
- }))
89
- : [];
90
-
91
- const allPatterns = [...PERF_PATTERNS, ...customPatterns];
92
- const addedLines = extractAddedLinesByFile(diff);
93
- const violations = [];
94
-
95
- for (const { file, line, content } of addedLines) {
96
- const ext = getExtension(file);
97
- const isFrontend = FRONTEND_EXTENSIONS.has(ext);
98
- const isPackageJson = file?.endsWith("package.json");
99
-
100
- if (isFrontend) {
101
- for (const { id, pattern, severity, message } of allPatterns) {
102
- if (pattern.test(content)) {
103
- violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
104
- }
105
- }
106
- }
107
-
108
- if (isPackageJson) {
109
- for (const { id, pattern, severity, message } of HEAVY_DEPS) {
110
- if (pattern.test(content)) {
111
- violations.push({ id, severity, file, line, message, matchedContent: content.trim().slice(0, 200) });
112
- }
113
- }
114
- }
115
- }
116
-
117
- // perf-guard is advisory by default — only blocks on critical (none built-in are critical)
118
- const blockOnWarning = Boolean(config?.guards?.perf?.block_on_warning);
119
- const hasCritical = violations.some(v => v.severity === "critical");
120
- const hasWarning = violations.some(v => v.severity === "warning");
121
- const pass = !hasCritical && !(blockOnWarning && hasWarning);
122
-
123
- return { pass, violations, skipped: false };
124
- }
125
-
126
- export { PERF_PATTERNS, HEAVY_DEPS, FRONTEND_EXTENSIONS };
@@ -1,90 +0,0 @@
1
- /**
2
- * Policy guard for kj_resume answers.
3
- *
4
- * Detects host-AI attempts to bypass pipeline policies (skip TDD, ignore
5
- * reviewer, disable security, etc.) and rejects them with context-aware
6
- * suggestions for valid alternatives.
7
- */
8
-
9
- const BYPASS_PATTERNS = [
10
- { regex: /\b(?:skip|omit|drop)\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
11
- { regex: /\bdisable\s+(?:the\s+)?(?:tests?|tdd|testing)\b/i, policy: "tdd" },
12
- { regex: /\b(?:don'?t|do\s+not|no\s+need\s+(?:for|to))\s+(?:run\s+)?tests?\b/i, policy: "tdd" },
13
- { regex: /\bcontinue\s+without\s+test/i, policy: "tdd" },
14
- { regex: /\bswitch\s+(?:to\s+)?(?:standard\s+)?methodology/i, policy: "tdd" },
15
- { regex: /\bswitch\s+methodology/i, policy: "tdd" },
16
- { regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:review(?:er)?|code\s+review)\b/i, policy: "reviewer" },
17
- { regex: /\b(?:approve|pass)\s+without\s+review/i, policy: "reviewer" },
18
- { regex: /\bmark\s+as\s+approved\b/i, policy: "reviewer" },
19
- { regex: /\bjust\s+ship\s+it/i, policy: "reviewer" },
20
- { regex: /\bignore\s+(?:the\s+)?(?:review(?:er)?\s+)?feedback\b/i, policy: "reviewer" },
21
- { regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?(?:sonar|sonarqube|quality\s+gate)/i, policy: "sonar" },
22
- { regex: /\bignore\s+sonar\s+issues?\b/i, policy: "sonar" },
23
- { regex: /\b(?:skip|ignore|bypass|disable)\s+(?:the\s+)?security(?:\s+checks?)?\b/i, policy: "security" },
24
- ];
25
-
26
- const SUGGESTIONS_BY_POLICY = {
27
- tdd: [
28
- "Provide specific guidance for the coder on how to fix the failing tests",
29
- "Describe the expected behavior so the coder can write correct tests",
30
- "Suggest a different approach to implement the feature that is easier to test",
31
- ],
32
- reviewer: [
33
- "Provide technical guidance to address the reviewer's feedback",
34
- "Explain why the current approach is correct if you disagree with the review",
35
- "Suggest alternative implementations that satisfy the reviewer's concerns",
36
- ],
37
- sonar: [
38
- "Provide guidance on how to resolve the SonarQube issues",
39
- "Explain the code changes needed to satisfy quality gate requirements",
40
- ],
41
- security: [
42
- "Provide guidance on how to fix the security issues found",
43
- "Explain the secure alternative for the flagged pattern",
44
- ],
45
- };
46
-
47
- const CONTEXT_SUGGESTIONS = {
48
- reviewer_fail_fast: [
49
- "Provide specific technical guidance for the coder to address the reviewer's feedback",
50
- "Suggest a different approach that resolves the reviewer's concerns",
51
- ],
52
- max_iterations: [
53
- "Provide focused guidance to help the coder converge on a solution",
54
- "Narrow the scope: specify exactly which file/function to change and how",
55
- "Continue with additional iterations by choosing option 1 or 2",
56
- ],
57
- standby_exhausted: [
58
- "Wait and retry — the provider may be temporarily overloaded",
59
- "Continue to resume from where the pipeline left off",
60
- ],
61
- };
62
-
63
- /**
64
- * Validate a resume answer against pipeline policies.
65
- *
66
- * @param {string|null} answer - The resume answer from the host
67
- * @param {string} [pauseContext] - The context of the pause (e.g. "reviewer_fail_fast")
68
- * @returns {{ valid: boolean, reason?: string, suggestions?: string[] }}
69
- */
70
- export function validatePolicyCompliance(answer, pauseContext) {
71
- if (answer == null || answer === "") return { valid: true };
72
- if (typeof answer !== "string") return { valid: true };
73
-
74
- const text = answer.trim();
75
- for (const { regex, policy } of BYPASS_PATTERNS) {
76
- if (regex.test(text)) {
77
- const suggestions = [
78
- ...(CONTEXT_SUGGESTIONS[pauseContext] || []),
79
- ...(SUGGESTIONS_BY_POLICY[policy] || []),
80
- ];
81
- return {
82
- valid: false,
83
- reason: `Pipeline policy "${policy}" cannot be bypassed. Provide technical guidance instead.`,
84
- suggestions: [...new Set(suggestions)],
85
- };
86
- }
87
- }
88
-
89
- return { valid: true };
90
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * Policy resolution: map task type + config toggles to concrete pipeline
3
- * flags (TDD, Sonar, reviewer retries, tests required, coder required, ...).
4
- *
5
- * @typedef {import("../types/policy.js").ResolvedPolicies} ResolvedPolicies
6
- * @typedef {import("../types/config.js").KarajanConfig} KarajanConfig
7
- */
8
-
9
- // KJC-TSK-0400: spike y research añadidos como tipos no-code. Comparten
10
- // las defaults restrictivas (tdd/sonar/testsRequired off) porque NO
11
- // producen código que medir: un SPIKE es un .md de decisión, un research
12
- // es una nota de investigación. Forzar Sonar les hace fallar siempre.
13
- export const VALID_TASK_TYPES = new Set([
14
- "sw", "infra", "doc", "add-tests", "refactor",
15
- "audit", "analysis", "no-code", "spike", "research",
16
- ]);
17
-
18
- export const DEFAULT_POLICIES = {
19
- sw: { tdd: true, sonar: true, reviewer: true, testsRequired: true },
20
- infra: { tdd: false, sonar: false, reviewer: false, testsRequired: false },
21
- doc: { tdd: false, sonar: false, reviewer: true, testsRequired: false },
22
- "add-tests": { tdd: false, sonar: true, reviewer: true, testsRequired: true },
23
- refactor: { tdd: true, sonar: true, reviewer: true, testsRequired: false },
24
- audit: { tdd: false, sonar: false, reviewer: false, testsRequired: false, coderRequired: false },
25
- analysis: { tdd: false, sonar: false, reviewer: false, testsRequired: false, coderRequired: false },
26
- "no-code": { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
27
- spike: { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
28
- research: { tdd: false, sonar: false, reviewer: true, testsRequired: false, coderRequired: true },
29
- };
30
-
31
- // KJC-TSK-0400: si el title arranca con [SPIKE] / [DOC] / [RESEARCH] /
32
- // [NOCODE], inferimos el task_type del prefijo. Pensado para casos donde
33
- // el planner emite task_type='sw' por defecto pero el title declara
34
- // claramente que la HU no produce código. Devuelve null si no hay match.
35
- const TITLE_PREFIX_TO_TYPE = {
36
- SPIKE: "spike",
37
- RESEARCH: "research",
38
- DOC: "doc",
39
- NOCODE: "no-code",
40
- "NO-CODE": "no-code",
41
- };
42
-
43
- export function inferTaskTypeFromTitle(title) {
44
- if (typeof title !== "string") return null;
45
- const m = title.match(/^\s*\[([A-Z][A-Z-]+)\]/);
46
- if (!m) return null;
47
- return TITLE_PREFIX_TO_TYPE[m[1].toUpperCase()] || null;
48
- }
49
-
50
- // KJC-TSK-0400: dado un HU del plan, devuelve el task_type efectivo:
51
- // explícito en story.task_type si es válido, si no inferido del title.
52
- // Fallback 'sw' (conservador, mantiene gates activos cuando hay duda).
53
- export function effectiveTaskType(story) {
54
- if (!story || typeof story !== "object") return "sw";
55
- if (VALID_TASK_TYPES.has(story.task_type)) return story.task_type;
56
- return inferTaskTypeFromTitle(story.title) || "sw";
57
- }
58
-
59
- const FALLBACK_TYPE = "sw";
60
-
61
- /**
62
- * Resolve pipeline policies for a given taskType.
63
- * Unknown / null / undefined taskType falls back to "sw" (conservative).
64
- * configOverrides optionally merges over defaults per taskType.
65
- */
66
- export function resolvePolicies(taskType, configOverrides) {
67
- const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
68
- const base = { ...DEFAULT_POLICIES[resolvedType] };
69
- const overrides = configOverrides?.[resolvedType];
70
- if (overrides && typeof overrides === "object") {
71
- Object.assign(base, overrides);
72
- }
73
- return base;
74
- }
75
-
76
- /**
77
- * Resolve policies for a taskType and return a flat object with the resolved
78
- * taskType plus all policy flags. This is the main entry point for the
79
- * orchestrator to determine which pipeline stages to enable/disable.
80
- */
81
- export function applyPolicies({ taskType, policies } = {}) {
82
- const resolvedType = VALID_TASK_TYPES.has(taskType) ? taskType : FALLBACK_TYPE;
83
- const resolved = resolvePolicies(taskType, policies);
84
- return { taskType: resolvedType, ...resolved };
85
- }
@@ -1,71 +0,0 @@
1
- // KJC-TSK-0583 — Inbound secret redaction for the review boundary.
2
- //
3
- // The outbound boundary (output-guard.js) already blocks committing secrets.
4
- // This closes the *inbound* gap: a hardcoded credential in the working tree
5
- // would otherwise reach the (possibly cloud) reviewer model verbatim inside the
6
- // diff. `redactSecrets` masks each credential before the model sees it, reusing
7
- // the SAME catalog as output-guard — no new patterns, no AI cost, deterministic.
8
- import { CREDENTIAL_PATTERNS } from "./output-guard.js";
9
-
10
- // Families whose match begins with a fixed, identifiable literal prefix. The
11
- // placeholder keeps that prefix so the reviewer can still tell WHAT kind of
12
- // secret was redacted (and say "move it to .env") without seeing the value.
13
- const STABLE_PREFIX_BY_ID = {
14
- "aws-key": "AKIA",
15
- "npm-token": "npm_",
16
- "openai-key": "sk-",
17
- "anthropic-key": "sk-ant-",
18
- "stripe-key": "sk_live_",
19
- "stripe-test": "sk_test_",
20
- "google-api-key": "AIza",
21
- };
22
-
23
- // Families with a dynamic prefix: keep the real match up to and including the
24
- // first separator (ghp_/gho_/…, xoxb-/xoxp-/…), then mask the rest.
25
- const DYNAMIC_SEPARATOR_BY_ID = {
26
- "github-token": "_",
27
- "slack-token": "-",
28
- };
29
-
30
- const GENERIC = "***REDACTED-SECRET***";
31
- const SUFFIX = "***REDACTED***";
32
-
33
- function placeholderFor(id, match) {
34
- const stable = STABLE_PREFIX_BY_ID[id];
35
- if (stable) return `${stable}${SUFFIX}`;
36
- const sep = DYNAMIC_SEPARATOR_BY_ID[id];
37
- if (sep) {
38
- const idx = match.indexOf(sep);
39
- return idx >= 0 ? `${match.slice(0, idx + 1)}${SUFFIX}` : GENERIC;
40
- }
41
- return GENERIC;
42
- }
43
-
44
- // Apply the most specific prefixes first so `sk-ant-` wins over `sk-`; families
45
- // without a stable prefix keep their catalog order (stable sort) and run last.
46
- function orderedPatterns() {
47
- return [...CREDENTIAL_PATTERNS].sort(
48
- (a, b) => (STABLE_PREFIX_BY_ID[b.id]?.length ?? 0) - (STABLE_PREFIX_BY_ID[a.id]?.length ?? 0)
49
- );
50
- }
51
-
52
- /**
53
- * Mask every credential in `text`, preserving line structure. Pure and
54
- * deterministic: clean text is returned untouched (no-op, no cost).
55
- * @param {string} text
56
- * @returns {string}
57
- */
58
- export function redactSecrets(text) {
59
- if (typeof text !== "string" || text.length === 0) return text;
60
- let out = text;
61
- for (const { id, pattern } of orderedPatterns()) {
62
- const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
63
- out = out.replace(new RegExp(pattern.source, flags), (match) =>
64
- // Idempotent: a broad pattern (generic-secret, hardcoded-key-assignment)
65
- // can span an already-masked value; leave the more specific placeholder
66
- // in place instead of clobbering it with the generic one.
67
- match.includes("REDACTED") ? match : placeholderFor(id, match)
68
- );
69
- }
70
- return out;
71
- }
@@ -1,138 +0,0 @@
1
- /**
2
- * HU Acceptance Test Runner.
3
- * Executes acceptance_tests commands for an HU and returns structured results.
4
- * Brain uses this to determine if an HU is done (all pass) or needs fixing (with diagnostics).
5
- */
6
- import { runCommand } from "../utils/process.js";
7
-
8
- /**
9
- * Run a single acceptance test command.
10
- * @param {string} cmd - Shell command to execute
11
- * @param {string} cwd - Working directory
12
- * @param {number} [timeoutMs=30000] - Timeout per test
13
- * @returns {Promise<{cmd: string, passed: boolean, output: string, exitCode: number}>}
14
- */
15
- async function runSingleTest(cmd, cwd, timeoutMs = 30000, env = null) {
16
- try {
17
- const result = await runCommand("bash", ["-c", cmd], {
18
- timeout: timeoutMs,
19
- cwd,
20
- // PAR-H (KJC-TSK-0631): lane env (KJ_LANE_SLOT / KJ_PORT_OFFSET) so
21
- // tests that start services can offset their ports. execa merges
22
- // this on top of process.env.
23
- ...(env ? { env } : {})
24
- });
25
- const output = (result.stdout || "") + (result.stderr || "");
26
- return {
27
- cmd,
28
- passed: result.exitCode === 0,
29
- output: output.slice(-500), // last 500 chars for diagnostics
30
- exitCode: result.exitCode
31
- };
32
- } catch (err) {
33
- return {
34
- cmd,
35
- passed: false,
36
- output: err.message?.slice(-500) || "Command timed out or crashed",
37
- exitCode: -1
38
- };
39
- }
40
- }
41
-
42
- /**
43
- * Run all acceptance tests for an HU.
44
- *
45
- * Accepts two shapes:
46
- * - Legacy: plain string shell command.
47
- * - v2.7.5: { type: "shell" | "gherkin", content, file? }
48
- *
49
- * Shell entries execute immediately (exit code 0 = pass). Gherkin entries
50
- * cannot be executed directly — that's Phase 3 of tests-first where the
51
- * tester role translates them into real code tests. Until then, we report
52
- * them as "pending" and skip rather than failing the whole gate.
53
- *
54
- * @param {Array<string|object>} tests - Array of shell commands OR structured entries
55
- * @param {string} cwd - Working directory
56
- * @returns {Promise<{allPassed: boolean, results: object[], summary: string, diagnostics: string|null, pending: number}>}
57
- */
58
- export async function runAcceptanceTests(tests, cwd, { env = null } = {}) {
59
- if (!tests || tests.length === 0) {
60
- return { allPassed: false, results: [], summary: "No acceptance tests defined", diagnostics: null, pending: 0 };
61
- }
62
-
63
- const results = [];
64
- let pending = 0;
65
- for (const entry of tests) {
66
- let type = "shell";
67
- let cmd;
68
- if (typeof entry === "string") {
69
- cmd = entry;
70
- } else if (entry && typeof entry === "object" && typeof entry.content === "string") {
71
- type = entry.type === "gherkin" ? "gherkin" : "shell";
72
- cmd = entry.content;
73
- } else {
74
- results.push({ cmd: JSON.stringify(entry), passed: false, output: "Malformed acceptance_test entry", exitCode: -2, type: "invalid" });
75
- continue;
76
- }
77
- if (type === "gherkin") {
78
- // Gherkin entries need a translator (Phase 3). Mark them pending
79
- // so the coder/tester sees they haven't been validated yet —
80
- // better than silently passing (would lie) or hard-failing
81
- // (would block the whole pipeline).
82
- pending += 1;
83
- results.push({
84
- cmd,
85
- passed: false,
86
- output: "Gherkin test not yet executable (awaits tester translation — Phase 3)",
87
- exitCode: 0,
88
- type: "gherkin",
89
- pending: true,
90
- });
91
- continue;
92
- }
93
- const result = await runSingleTest(cmd, cwd, 30000, env);
94
- results.push({ ...result, type: "shell" });
95
- }
96
-
97
- const executedResults = results.filter((r) => !r.pending);
98
- const passed = executedResults.filter((r) => r.passed);
99
- const failed = executedResults.filter((r) => !r.passed);
100
- const allPassed = failed.length === 0;
101
-
102
- const shellSummary = `${passed.length}/${executedResults.length} shell tests passed`;
103
- const summary = pending > 0
104
- ? `${shellSummary}, ${pending} gherkin test(s) pending translation`
105
- : shellSummary;
106
-
107
- let diagnostics = null;
108
- if (!allPassed) {
109
- diagnostics = failed.map((f) =>
110
- `FAIL: ${f.cmd}\n exit=${f.exitCode}\n output: ${f.output.trim().split("\n").slice(-5).join("\n ")}`
111
- ).join("\n\n");
112
- }
113
-
114
- return { allPassed, results, summary, diagnostics, pending };
115
- }
116
-
117
- /**
118
- * Build a concrete diagnostic prompt for Brain to send to the coder.
119
- * Reads the failed test outputs and produces actionable instructions.
120
- * @param {object[]} failedResults - Array of failed test results
121
- * @returns {string} Prompt for the coder with concrete fix instructions
122
- */
123
- export function buildDiagnosticPrompt(failedResults) {
124
- if (!failedResults || failedResults.length === 0) return "";
125
- const lines = ["The following acceptance tests FAILED. Fix each one:", ""];
126
- for (const f of failedResults) {
127
- lines.push(`❌ Command: ${f.cmd}`);
128
- lines.push(` Exit code: ${f.exitCode}`);
129
- const lastLines = f.output.trim().split("\n").slice(-8);
130
- lines.push(` Last output:`);
131
- for (const l of lastLines) {
132
- lines.push(` ${l}`);
133
- }
134
- lines.push("");
135
- }
136
- lines.push("Fix ALL failing tests. Run each command yourself to verify before finishing.");
137
- return lines.join("\n");
138
- }