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,244 +0,0 @@
1
- import { extractFirstJson } from "../utils/json-extract.js";
2
- import { getLanguageInstruction } from "../utils/locale.js";
3
- import { section, buildPromptLayout, joinLayout, STABLE, VOLATILE } from "./prompt-layout.js";
4
-
5
- const SUBAGENT_PREAMBLE = [
6
- "IMPORTANT: You are running as a Karajan sub-agent.",
7
- "Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
8
- "Do NOT use any MCP tools. Focus only on evaluating HUs."
9
- ].join(" ");
10
-
11
- const VALID_VERDICTS = new Set(["certified", "needs_rewrite", "needs_context"]);
12
- const VALID_ANTIPATTERNS = new Set([
13
- "ghost_user", "swiss_army_knife", "implementation_leak",
14
- "moving_goalpost", "orphan_story", "invisible_dependency", "premature_optimization"
15
- ]);
16
- const DIMENSION_KEYS = [
17
- "D1_jtbd_context", "D2_user_specificity", "D3_behavior_change",
18
- "D4_control_zone", "D5_time_constraints", "D6_survivable_experiment"
19
- ];
20
-
21
- /**
22
- * Build the prompt for the HU reviewer agent.
23
- * @param {{stories: Array<{id: string, text: string}>, instructions: string|null, context?: string|null}} params
24
- * @returns {string} The assembled prompt.
25
- */
26
- /**
27
- * Build the HU-reviewer prompt as a { stable, volatile } layout (Φ1,
28
- * KJC-PCS-0057): preamble, instructions, JSON schema and contexts are
29
- * identical across batches on the same project; the stories under
30
- * evaluation and the per-batch additional context go last.
31
- */
32
- function buildHuReviewerPromptLayout({ stories, instructions, context = null, productContext = null, domainContext = null, hu_language = "en" }) {
33
- const langInstruction = getLanguageInstruction(hu_language);
34
-
35
- return buildPromptLayout([
36
- section(SUBAGENT_PREAMBLE, STABLE),
37
- section(langInstruction, STABLE),
38
- section(instructions, STABLE),
39
- section("Return a single valid JSON object and nothing else.", STABLE),
40
- section(`JSON schema: {"evaluations":[{"story_id":string,"scores":{"D1_jtbd_context":number,"D2_user_specificity":number,"D3_behavior_change":number,"D4_control_zone":number,"D5_time_constraints":number,"D6_survivable_experiment":number},"total":number,"antipatterns_detected":[string],"verdict":"certified|needs_rewrite|needs_context","evaluation_notes":string,"rewritten":object|null,"certified_hu":object|null,"context_needed":object|null}],"batch_summary":{"total":number,"certified":number,"needs_rewrite":number,"needs_context":number,"consolidated_questions":string}}`, STABLE),
41
- section(productContext ? `## Product Context\n${productContext}` : null, STABLE),
42
- section(domainContext ? `## Domain Context\n${domainContext}` : null, STABLE),
43
- section("## Stories to Evaluate", VOLATILE),
44
- ...stories.map((story) => section(`### ${story.id}\n${story.text}`, VOLATILE)),
45
- section(context ? `## Additional Context\n${context}` : null, VOLATILE),
46
- ]);
47
- }
48
-
49
- export function buildHuReviewerPrompt(options) {
50
- return joinLayout(buildHuReviewerPromptLayout(options));
51
- }
52
-
53
- /**
54
- * Clamp a score to 0-10 range.
55
- * @param {*} value
56
- * @returns {number}
57
- */
58
- function clampScore(value) {
59
- const n = Number(value);
60
- if (!Number.isFinite(n)) return 0;
61
- return Math.max(0, Math.min(10, Math.round(n)));
62
- }
63
-
64
- /**
65
- * Parse and validate a single evaluation object.
66
- * @param {object} raw
67
- * @returns {object|null}
68
- */
69
- function parseEvaluation(raw) {
70
- if (!raw || !raw.story_id || !raw.scores) return null;
71
-
72
- const scores = {};
73
- for (const key of DIMENSION_KEYS) {
74
- scores[key] = clampScore(raw.scores[key]);
75
- }
76
-
77
- const total = Object.values(scores).reduce((sum, v) => sum + v, 0);
78
- const antipatterns = (Array.isArray(raw.antipatterns_detected) ? raw.antipatterns_detected : [])
79
- .filter(ap => VALID_ANTIPATTERNS.has(ap));
80
-
81
- const rawVerdict = String(raw.verdict || "").toLowerCase();
82
- const verdict = VALID_VERDICTS.has(rawVerdict) ? rawVerdict : "needs_context";
83
-
84
- return {
85
- story_id: raw.story_id,
86
- scores,
87
- total,
88
- antipatterns_detected: antipatterns,
89
- verdict,
90
- evaluation_notes: raw.evaluation_notes || "",
91
- rewritten: raw.rewritten || null,
92
- certified_hu: raw.certified_hu || null,
93
- context_needed: raw.context_needed || null
94
- };
95
- }
96
-
97
- const AC_PREFIX_RE = /^\[(GHERKIN|CHECKLIST|PRE_POST|INVARIANT)]\s*/i;
98
-
99
- /**
100
- * Detect the format of a single acceptance criterion.
101
- * Supports both prefixed strings ("[GHERKIN] Given...") and legacy Gherkin objects ({given, when, then}).
102
- * @param {string|object} criterion
103
- * @returns {{format: string, text: string}}
104
- */
105
- export function detectAcFormat(criterion) {
106
- if (typeof criterion === "object" && criterion !== null && ("given" in criterion || "when" in criterion || "then" in criterion)) {
107
- const text = `Given ${criterion.given || "..."}, When ${criterion.when || "..."}, Then ${criterion.then || "..."}`;
108
- return { format: "gherkin", text };
109
- }
110
- if (typeof criterion === "string") {
111
- const match = AC_PREFIX_RE.exec(criterion);
112
- if (match) {
113
- const format = match[1].toLowerCase();
114
- const text = criterion.slice(match[0].length);
115
- return { format, text };
116
- }
117
- return { format: "checklist", text: criterion };
118
- }
119
- return { format: "checklist", text: String(criterion) };
120
- }
121
-
122
- /**
123
- * Normalize an acceptance_criteria array to a uniform structure.
124
- * Handles both legacy Gherkin objects and prefixed strings.
125
- * @param {Array} criteria
126
- * @returns {Array<{format: string, text: string}>}
127
- */
128
- export function normalizeAcceptanceCriteria(criteria) {
129
- if (!Array.isArray(criteria)) return [];
130
- return criteria.map(detectAcFormat);
131
- }
132
-
133
- /**
134
- * Build a prompt that asks the AI to decompose a complex task into 2-5 formal HUs.
135
- * Each HU follows the role/goal/benefit format with acceptance criteria and optional dependencies.
136
- * @param {string} task - The complex task description to decompose.
137
- * @returns {string} The assembled decomposition prompt.
138
- */
139
- export function buildDecompositionPrompt(task, { criteria = [] } = {}) {
140
- const sections = [SUBAGENT_PREAMBLE];
141
-
142
- sections.push("## Task Decomposition");
143
- sections.push(
144
- "You are a senior product owner. Decompose the following complex task into 2-5 independent, implementable user stories (HUs).",
145
- "Each HU must be small enough to implement in a single iteration and must follow the role/goal/benefit format."
146
- );
147
-
148
- sections.push(`## Task to Decompose\n${task}`);
149
-
150
- // KJC-TSK-0989 (#1894): the card's criteria are the contract; each one must
151
- // land in an HU, by number, or the run implements stories of its own invention.
152
- if (criteria.length > 0) {
153
- const numbered = criteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
154
- sections.push(`## Acceptance criteria of the card (the contract)\n${numbered}`);
155
- }
156
-
157
- sections.push(
158
- "Return a single valid JSON object and nothing else.",
159
- `JSON schema: {"stories":[{"id":string,"title":string,"role":string,"goal":string,"benefit":string,"acceptanceCriteria":[string],"dependsOn":[string],"covers":[number],"tier":"trivial"|"standard"|"deep","tierReason":string}]}`,
160
- "Rules:",
161
- "- Generate between 2 and 5 HUs",
162
- "- Each id must be unique, formatted as HU-DECOMP-NNN (e.g. HU-DECOMP-001)",
163
- "- dependsOn is an array of other HU ids from this decomposition that must be completed first (empty array if no dependencies)",
164
- "- acceptanceCriteria should be concrete, testable statements",
165
- "- tier is how hard the HU is to implement right (trivial: a local change; standard: several files or one module; deep: design decisions, many modules, or security/migrations), and tierReason says why in one line",
166
- "- Order stories so that dependencies are respected (a story should only depend on stories with lower ids)",
167
- ...(criteria.length > 0 ? [
168
- "- covers lists the numbers of the card's acceptance criteria this HU implements; EVERY card criterion must appear in the covers of at least one HU, and an HU's acceptanceCriteria must include each criterion it covers, verbatim",
169
- ] : ["- covers is an empty array"])
170
- );
171
-
172
- return sections.join("\n\n");
173
- }
174
-
175
- /**
176
- * KJC-TSK-0989: the card's criteria no HU covers, by number and text.
177
- * @param {Array<{covers?: number[]}>} stories
178
- * @param {string[]} criteria
179
- * @returns {Array<{index: number, text: string}>}
180
- */
181
- export function uncoveredCriteria(stories, criteria) {
182
- const covered = new Set(stories.flatMap((s) => s.covers ?? []));
183
- return criteria.map((text, i) => ({ index: i + 1, text })).filter((c) => !covered.has(c.index));
184
- }
185
-
186
- /**
187
- * Parse the output from a decomposition prompt.
188
- * @param {string} raw - Raw text output from the agent.
189
- * @returns {Array<{id: string, title: string, role: string, goal: string, benefit: string, acceptanceCriteria: string[], dependsOn: string[]}>|null}
190
- */
191
- export function parseDecompositionOutput(raw) {
192
- const parsed = extractFirstJson(raw);
193
- if (!parsed || !Array.isArray(parsed.stories)) return null;
194
-
195
- const stories = parsed.stories
196
- .filter(s => s && s.id && s.title)
197
- .map(s => ({
198
- id: s.id,
199
- title: s.title,
200
- role: s.role || "developer",
201
- goal: s.goal || s.title,
202
- benefit: s.benefit || "",
203
- acceptanceCriteria: Array.isArray(s.acceptanceCriteria) ? s.acceptanceCriteria : [],
204
- dependsOn: Array.isArray(s.dependsOn) ? s.dependsOn : [],
205
- covers: Array.isArray(s.covers) ? s.covers.map(Number).filter(Number.isInteger) : [],
206
- tier: s.tier ?? null,
207
- tierReason: s.tierReason ?? null
208
- }));
209
-
210
- return stories.length > 0 ? stories : null;
211
- }
212
-
213
- /**
214
- * Parse the raw output from the HU reviewer agent.
215
- * @param {string} raw - Raw text output from the agent.
216
- * @returns {object|null} Parsed result with evaluations and batch_summary, or null.
217
- */
218
- export function parseHuReviewerOutput(raw) {
219
- const parsed = extractFirstJson(raw);
220
- if (!parsed) return null;
221
-
222
- if (!Array.isArray(parsed.evaluations)) return null;
223
-
224
- const evaluations = parsed.evaluations
225
- .map(parseEvaluation)
226
- .filter(Boolean);
227
-
228
- if (evaluations.length === 0) return null;
229
-
230
- const certified = evaluations.filter(e => e.verdict === "certified").length;
231
- const needsRewrite = evaluations.filter(e => e.verdict === "needs_rewrite").length;
232
- const needsContext = evaluations.filter(e => e.verdict === "needs_context").length;
233
-
234
- return {
235
- evaluations,
236
- batch_summary: {
237
- total: evaluations.length,
238
- certified,
239
- needs_rewrite: needsRewrite,
240
- needs_context: needsContext,
241
- consolidated_questions: parsed.batch_summary?.consolidated_questions || ""
242
- }
243
- };
244
- }
@@ -1,31 +0,0 @@
1
- // KJC-TSK-0375 — Prompt builder for the ToolCorrectnessJudge role.
2
- // Inspired by deepeval's tool-correctness metric.
3
-
4
- const PREAMBLE = "IMPORTANT: You are running as a Karajan sub-agent. "
5
- + "Do NOT use any MCP tools, do NOT mention Karajan. "
6
- + "Your job is to judge another agent's tool choices.";
7
-
8
- export function buildToolCorrectnessJudgePrompt({ task, toolCalls, instructions }) {
9
- const calls = toolCalls
10
- .map((c, i) => `${i + 1}. **${c.tool}** — args: ${JSON.stringify(c.args)}`)
11
- .join("\n");
12
- const body = [
13
- "You are the ToolCorrectnessJudge for Karajan Code.",
14
- "Input: (a) a task description and (b) the ordered tool calls an LLM coder",
15
- "made (Read/Edit/Write/Bash/Glob/Grep/MultiEdit). Judge each call on:",
16
- " - tool choice: right tool for the intent?",
17
- " - argument quality: paths plausible, commands valid, no garbage placeholders?",
18
- "Per-call verdict: `correct=true|false` + one-sentence `reason`.",
19
- "Aggregate into a single 0-100 score:",
20
- " - 100 = every call right with clean args",
21
- " - 70-99 = mostly right, minor missteps",
22
- " - 40-69 = several wrong choices, budget wasted",
23
- " - 0-39 = predominantly bad, retry advised",
24
- "Return a single valid JSON object and nothing else.",
25
- 'Schema: {"score":0-100,"summary":string,"breakdown":[{"tool":string,"args":object,"correct":boolean,"reason":string}]}',
26
- ].join("\n");
27
- const sections = [PREAMBLE];
28
- if (instructions) sections.push(instructions);
29
- sections.push(body, `## Task\n${task}`, `## Tool calls (${toolCalls.length})\n${calls || "(no tool calls captured)"}`);
30
- return sections.join("\n\n");
31
- }
@@ -1,57 +0,0 @@
1
- const SUBAGENT_PREAMBLE = [
2
- "IMPORTANT: You are running as a Karajan sub-agent.",
3
- "Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
4
- "Do NOT use any MCP tools. Focus only on task complexity triage."
5
- ].join(" ");
6
-
7
- const ROLE_DESCRIPTIONS = [
8
- { role: "planner", description: "Generates an implementation plan before coding. Useful for complex multi-file tasks." },
9
- { role: "researcher", description: "Investigates the codebase for context before coding. Useful when understanding existing code is needed." },
10
- { role: "tester", description: "Runs dedicated testing pass after coding. Ensures tests exist and pass." },
11
- { role: "security", description: "Audits code for security vulnerabilities. Checks auth, input validation, injection risks." },
12
- { role: "refactorer", description: "Cleans up and refactors code after the main implementation." },
13
- { role: "reviewer", description: "Reviews the code diff for quality issues. Standard quality gate." },
14
- { role: "architect", description: "Designs solution architecture — layers, patterns, data model, API contracts, tradeoffs. Activate when task creates new module/app, affects data model/APIs, complexity is medium/complex, or design is ambiguous." },
15
- { role: "hu-reviewer", description: "Certifies user stories before coding. Activate for medium/complex tasks that need story decomposition." }
16
- ];
17
-
18
- export function buildTriagePrompt({ task, instructions, availableRoles }) {
19
- const sections = [SUBAGENT_PREAMBLE];
20
-
21
- if (instructions) {
22
- sections.push(instructions);
23
- }
24
-
25
- const roles = availableRoles || ROLE_DESCRIPTIONS;
26
-
27
- sections.push(
28
- "You are a task triage agent for Karajan Code, a multi-agent coding orchestrator.",
29
- "Analyze the following task and determine which pipeline roles should be activated.",
30
- "## Available Roles",
31
- roles.map((r) => `- **${r.role}**: ${r.description}`).join("\n"),
32
- "## Decision Guidelines",
33
- [
34
- "- **planner**: Enable for complex tasks (multi-file, architectural changes, data model changes). Disable for simple fixes.",
35
- "- **researcher**: Enable when the task needs codebase context, API understanding, or investigation. Disable for standalone new files.",
36
- "- **tester**: Enable for any task with logic, APIs, components, services. Disable ONLY for pure documentation, comments, or CSS-only changes.",
37
- "- **security**: Enable for authentication, APIs, user input handling, data access, external integrations. Disable for UI-only or doc changes.",
38
- "- **refactorer**: Enable only when explicitly requested or when the task is a refactoring task.",
39
- "- **reviewer**: Enable for most tasks as a quality gate. Disable only for trivial, single-line changes.",
40
- "- **architect**: Enable when creating new modules/apps, changing data models or APIs, medium/complex tasks, or when design approach is ambiguous. Disable for simple fixes, doc-only, or CSS-only changes.",
41
- "- **hu-reviewer**: Enable for medium/complex tasks that benefit from story decomposition and certification. Disable for trivial/simple tasks, doc-only, or CSS-only changes.",
42
- "- **audit/analysis taskType**: Set taskType to \"audit\" or \"analysis\" for tasks that only require reading/inspecting code without making changes (e.g., audit, review, analyze, check, verify, inspect, scan, auditar, revisar, analizar, comprobar, verificar, inspeccionar). The coder and reviewer will be skipped entirely for these tasks.",
43
- "- **no-code taskType**: Use no-code when the task is about data analysis, document generation, SQL queries, CSV transformation, report generation, or any non-programming task. The coder will generate output (not source code), and TDD/SonarQube will be disabled. The reviewer still runs to validate logic/correctness.",
44
- "",
45
- "Note: coder is ALWAYS active for coding tasks — you don't need to decide on it. However, for audit/analysis taskTypes the coder is skipped."
46
- ].join("\n"),
47
- "Classify the task complexity, determine its taskType, recommend only the necessary pipeline roles, and assess whether the task should be decomposed into smaller subtasks.",
48
- "Keep the reasoning short and practical.",
49
- "Return a single valid JSON object and nothing else.",
50
- 'JSON schema: {"level":"trivial|simple|medium|complex","roles":["planner|researcher|refactorer|reviewer|tester|security|architect|hu-reviewer"],"taskType":"sw|infra|doc|add-tests|refactor|audit|analysis|no-code","reasoning":string,"shouldDecompose":boolean,"subtasks":string[]}',
51
- `## Task\n${task}`
52
- );
53
-
54
- return sections.join("\n\n");
55
- }
56
-
57
- export { ROLE_DESCRIPTIONS };
@@ -1,2 +0,0 @@
1
- // Shim: embedder now lives in karajan-core/rag (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedder";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/_cloud-base";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/cohere";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/mistral";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/onnx";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/openai";
@@ -1,2 +0,0 @@
1
- // Shim: moved to karajan-core/rag/embedders (KJC-TSK-0632 PR3).
2
- export * from "karajan-core/rag/embedders/voyage";
package/src/rag/rerank.js DELETED
@@ -1,4 +0,0 @@
1
- // Shim: rerank now lives in karajan-core/rag so the hu-board workspace
2
- // can consume it without a relative dep on the CLI src tree.
3
- // KJC-TSK-0632 PR2.
4
- export { RerankError, _resetPipeline, rerank } from "karajan-core/rag/rerank";
@@ -1,4 +0,0 @@
1
- // Shim: where-parser now lives in karajan-core/rag so the hu-board
2
- // workspace can consume it without a relative dep on the CLI src tree.
3
- // KJC-TSK-0632 PR2.
4
- export { parseWhere, buildWhereSql } from "karajan-core/rag/where-parser";
@@ -1,88 +0,0 @@
1
- import { createHash } from "node:crypto";
2
-
3
- const DEFAULT_THRESHOLD = 2;
4
-
5
- function normalizeIssueKey(value) {
6
- if (value === null || value === undefined) return "";
7
- return String(value).trim();
8
- }
9
-
10
- function buildIssueSignature(issues, keySelector) {
11
- const counts = new Map();
12
- for (const issue of issues || []) {
13
- const key = normalizeIssueKey(keySelector(issue));
14
- if (!key) continue;
15
- counts.set(key, (counts.get(key) || 0) + 1);
16
- }
17
- if (counts.size === 0) return "";
18
- return Array.from(counts.entries())
19
- .sort(([a], [b]) => a.localeCompare(b))
20
- .map(([key, count]) => `${key}:${count}`)
21
- .join("|");
22
- }
23
-
24
- function hashSignature(signature) {
25
- if (!signature) return "";
26
- return createHash("sha256").update(signature).digest("hex");
27
- }
28
-
29
- function updateRepeatState(state, signatureHash) {
30
- if (!signatureHash) {
31
- return { lastHash: null, repeatCount: 0 };
32
- }
33
- const nextCount = signatureHash === state.lastHash ? state.repeatCount + 1 : 1;
34
- return { lastHash: signatureHash, repeatCount: nextCount };
35
- }
36
-
37
- function parseThreshold(value) {
38
- const parsed = Number(value);
39
- if (Number.isFinite(parsed) && parsed > 0) return parsed;
40
- return DEFAULT_THRESHOLD;
41
- }
42
-
43
- export function getRepeatThreshold(config) {
44
- const raw =
45
- config?.failFast?.repeatThreshold ??
46
- config?.session?.repeat_detection_threshold ??
47
- config?.session?.fail_fast_repeats ??
48
- 2;
49
- const value = Number(raw);
50
- if (Number.isFinite(value) && value > 0) return value;
51
- return 2;
52
- }
53
-
54
- export class RepeatDetector {
55
- constructor({ threshold = DEFAULT_THRESHOLD } = {}) {
56
- this.threshold = parseThreshold(threshold);
57
- this.sonar = { lastHash: null, repeatCount: 0 };
58
- this.reviewer = { lastHash: null, repeatCount: 0 };
59
- }
60
-
61
- addIteration(sonarIssues, reviewerIssues) {
62
- const sonarSignature = buildIssueSignature(
63
- sonarIssues || [],
64
- (issue) => issue?.rule || issue?.message
65
- );
66
- const reviewerSignature = buildIssueSignature(
67
- reviewerIssues || [],
68
- (issue) => issue?.description || issue?.content || issue?.id
69
- );
70
-
71
- this.sonar = updateRepeatState(this.sonar, hashSignature(sonarSignature));
72
- this.reviewer = updateRepeatState(this.reviewer, hashSignature(reviewerSignature));
73
- }
74
-
75
- isStalled() {
76
- if (this.sonar.repeatCount >= this.threshold) {
77
- return { stalled: true, reason: "sonar_repeat" };
78
- }
79
- if (this.reviewer.repeatCount >= this.threshold) {
80
- return { stalled: true, reason: "reviewer_repeat" };
81
- }
82
- return { stalled: false, reason: "" };
83
- }
84
-
85
- getRepeatCounts() {
86
- return { sonar: this.sonar.repeatCount, reviewer: this.reviewer.repeatCount };
87
- }
88
- }
@@ -1,112 +0,0 @@
1
- import { runCommand } from "../utils/process.js";
2
- import { generateSnapshotDiff } from "./snapshot-diff.js";
3
- import { getRunContext } from "../utils/run-context.js";
4
-
5
- // Module-scope back-compat state for callers outside a `withRunContext`
6
- // scope. When inside a pipeline, `getRunContext()` provides per-run
7
- // isolation (TSK-0338) — the module-level values below are only consulted
8
- // as a last resort.
9
-
10
- /** @type {((command: string, args?: string[], options?: object) => Promise<object>)|null} */
11
- let _runner = null;
12
-
13
- /** @type {Map<string, string>|null} — pre-coder filesystem snapshot for git-free diff */
14
- let _snapshot = null;
15
-
16
- /** @type {string|null} — project directory scope for git diff (prevents leaking unrelated changes) */
17
- let _projectDir = null;
18
-
19
- /** Retained for back-compat; pipelines should use `withRunContext({ projectDir })` for isolation. */
20
- export function setProjectDir(dir) {
21
- _projectDir = dir;
22
- }
23
-
24
- /** Retained for back-compat; pipelines should use `withRunContext({ snapshot })` for isolation. */
25
- export function setSnapshot(snapshot) {
26
- _snapshot = snapshot;
27
- }
28
-
29
- /** Retained for back-compat; pipelines should use `withRunContext({ runner })` for isolation. */
30
- export function setRunner(runner) {
31
- _runner = runner;
32
- }
33
-
34
- function resolveRunner() {
35
- return getRunContext()?.runner || _runner || runCommand;
36
- }
37
-
38
- function resolveProjectDir() {
39
- const ctx = getRunContext();
40
- if (ctx && "projectDir" in ctx) return ctx.projectDir;
41
- return _projectDir;
42
- }
43
-
44
- function resolveSnapshot() {
45
- const ctx = getRunContext();
46
- if (ctx && "snapshot" in ctx) return ctx.snapshot;
47
- return _snapshot;
48
- }
49
-
50
- function run(command, args, ...rest) {
51
- return resolveRunner()(command, args, ...rest);
52
- }
53
-
54
- export async function computeBaseRef({ baseBranch = "main", baseRef = null }) {
55
- if (baseRef) return baseRef;
56
-
57
- try {
58
- const mergeBase = await run("git", ["merge-base", "HEAD", `origin/${baseBranch}`]);
59
- if (mergeBase.exitCode === 0) return mergeBase.stdout.trim();
60
-
61
- const fallback = await run("git", ["rev-parse", "HEAD~1"]);
62
- if (fallback.exitCode === 0) return fallback.stdout.trim();
63
-
64
- // Empty repo (zero commits): diff against the empty tree
65
- const emptyTree = await run("git", ["hash-object", "-t", "tree", "/dev/null"]);
66
- if (emptyTree.exitCode === 0) return emptyTree.stdout.trim();
67
- } catch { /* git not available */ }
68
-
69
- // No git or all strategies failed — return sentinel for snapshot-based diff
70
- return "__snapshot__";
71
- }
72
-
73
- export async function generateDiff({ baseRef, stageNewFiles = false, projectDir = null }) {
74
- // Auto-resolve projectDir from run context (TSK-0338) or module fallback
75
- const scopeDir = projectDir || resolveProjectDir() || null;
76
- const snapshot = resolveSnapshot();
77
-
78
- // Try git diff first
79
- try {
80
- if (stageNewFiles) {
81
- const addArgs = scopeDir ? ["-A", scopeDir] : ["-A"];
82
- await run("git", ["add", ...addArgs]);
83
- }
84
- const diffArgs = ["diff", stageNewFiles ? "--cached" : "", `${baseRef}`].filter(Boolean);
85
- // Scope diff to projectDir when it's a subdirectory (prevents leaking unrelated changes)
86
- if (scopeDir) diffArgs.push("--", scopeDir);
87
- const result = await run("git", diffArgs);
88
- if (result.exitCode === 0) {
89
- return result.stdout;
90
- }
91
- } catch { /* git not available or failed */ }
92
-
93
- // Fallback: snapshot-based diff (no git needed)
94
- if (snapshot) {
95
- const dir = projectDir || process.cwd();
96
- return generateSnapshotDiff(snapshot, null, dir);
97
- }
98
-
99
- // No git and no snapshot — generate diff of all files as new.
100
- // TSK-0340: dropped a stray `const { takeSnapshot } = await import(...)`
101
- // that was never used in this branch (we synthesize an empty Map and
102
- // let generateSnapshotDiff do the file walk itself).
103
- const dir = projectDir || process.cwd();
104
- const emptySnapshot = new Map();
105
- return generateSnapshotDiff(emptySnapshot, null, dir);
106
- }
107
-
108
- export async function getUntrackedFiles(cwd = null) {
109
- const result = await run("git", ["ls-files", "--others", "--exclude-standard"], cwd ? { cwd } : {});
110
- if (result.exitCode !== 0) return [];
111
- return result.stdout.trim().split("\n").filter(Boolean);
112
- }