karajan-code 4.70.3 → 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 (388) 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/ai-surface.js +9 -7
  61. package/src/checks/config-files.js +8 -7
  62. package/src/checks/dir-setup.js +34 -1
  63. package/src/checks/native-build.js +21 -39
  64. package/src/checks/runner.js +128 -142
  65. package/src/cli/advanced-commands.js +6 -6
  66. package/src/cli/register-meta.js +42 -82
  67. package/src/cli/register-pipeline.js +8 -140
  68. package/src/cli/register-plan.js +9 -100
  69. package/src/cli/retired-commands.js +49 -0
  70. package/src/cli.js +18 -5
  71. package/src/commands/agent-run.js +40 -26
  72. package/src/commands/audit.js +127 -124
  73. package/src/commands/board.js +5 -9
  74. package/src/commands/check.js +29 -16
  75. package/src/commands/doctor.js +2 -0
  76. package/src/commands/env.js +176 -148
  77. package/src/commands/go.js +76 -55
  78. package/src/commands/harden.js +105 -86
  79. package/src/commands/hu-start.js +52 -0
  80. package/src/commands/hu.js +288 -221
  81. package/src/commands/identity.js +111 -78
  82. package/src/commands/init-atril.js +47 -0
  83. package/src/commands/init.js +11 -40
  84. package/src/commands/install-tools.js +70 -85
  85. package/src/commands/main-guard.js +78 -0
  86. package/src/commands/policy.js +226 -184
  87. package/src/commands/qmd.js +27 -21
  88. package/src/commands/rag.js +75 -48
  89. package/src/commands/review-gate.js +422 -339
  90. package/src/commands/start.js +4 -5
  91. package/src/commands/steward.js +96 -47
  92. package/src/commands/tournament.js +46 -37
  93. package/src/commands/worktree.js +94 -25
  94. package/src/config/loader.js +34 -17
  95. package/src/config/overrides.js +2 -1
  96. package/src/config/secrets.js +36 -0
  97. package/src/config.js +1 -0
  98. package/src/environment/adr.js +16 -2
  99. package/src/environment/board-access.js +11 -9
  100. package/src/git/karajan-label.js +20 -8
  101. package/src/guards/main-guard.js +54 -0
  102. package/src/harden/branch-protection.js +36 -3
  103. package/src/harden/hook-templates.js +16 -1
  104. package/src/harden/sentinel/posttooluse.mjs +18 -6
  105. package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
  106. package/src/harden/sentinel/sentinel-lib.mjs +149 -23
  107. package/src/harden/sentinel/sentinel-shell.mjs +64 -0
  108. package/src/harden/sentinel/sessionstart.mjs +3 -2
  109. package/src/harden/sentinel/stop.mjs +5 -4
  110. package/src/harden/workflow-engine.js +12 -1
  111. package/src/harden/workflow-templates.js +1 -1
  112. package/src/hu/board-lookup.js +29 -0
  113. package/src/hu/gh-identity.js +23 -0
  114. package/src/hu/github-board.js +4 -2
  115. package/src/hu/lane-prune.js +15 -7
  116. package/src/hu/lane-setup.js +65 -0
  117. package/src/hu/lanes.js +66 -0
  118. package/src/hu/team-board-mirror.js +3 -2
  119. package/src/infrastructure/command-runner.js +1 -1
  120. package/src/infrastructure/file-system-service.js +1 -1
  121. package/src/mcp/handlers/direct-handlers.js +2 -292
  122. package/src/mcp/handlers/hu-handlers.js +44 -55
  123. package/src/mcp/handlers/management-handlers.js +2 -42
  124. package/src/mcp/server-handlers.js +16 -22
  125. package/src/mcp/tools.js +5 -200
  126. package/src/plan/lane-plans.js +54 -0
  127. package/src/plan/plan-store.js +7 -4
  128. package/src/policy/add.js +26 -12
  129. package/src/policy/adr-number-check.js +31 -0
  130. package/src/prompts/audit.js +299 -339
  131. package/src/prompts/card-context.js +10 -5
  132. package/src/prompts/reviewer.js +5 -2
  133. package/src/rag/auto-update.js +56 -43
  134. package/src/rag/bootstrap-index.js +28 -54
  135. package/src/rag/migrate.js +1 -1
  136. package/src/rag/onnx-fallback.js +2 -2
  137. package/src/rag/pid-lease.js +70 -0
  138. package/src/rag/project-store.js +2 -12
  139. package/src/review/card-first.js +57 -46
  140. package/src/review/dual-review.js +5 -4
  141. package/src/review/gate-gitignore.js +23 -4
  142. package/src/review/gate-hook.js +47 -0
  143. package/src/review/one-shot-review.js +51 -37
  144. package/src/review/publish-pr.js +18 -3
  145. package/src/review/repo-docs.js +73 -0
  146. package/src/review/repo-stack.js +59 -0
  147. package/src/review/reviewer-fallback.js +34 -3
  148. package/src/review/seal-commit.js +29 -0
  149. package/src/review/sonar-pregate.js +59 -44
  150. package/src/review/third-party-review.js +90 -16
  151. package/src/review/third-party-size.js +43 -0
  152. package/src/review/third-party-skills.js +54 -0
  153. package/src/review/verify-pr.js +2 -26
  154. package/src/roles/audit-role.js +106 -125
  155. package/src/skills/atril-skills.js +5 -4
  156. package/src/sonar/scanner.js +116 -101
  157. package/src/steward/invariants.js +5 -4
  158. package/src/steward/phantom-sweep.js +66 -0
  159. package/src/tournament/judge.js +60 -53
  160. package/src/utils/agent-home.js +33 -0
  161. package/src/utils/gh-account.js +37 -0
  162. package/src/utils/git.js +0 -13
  163. package/src/utils/home-migration.js +7 -1
  164. package/src/utils/main-checkout.js +53 -0
  165. package/src/utils/qmd-collection.js +3 -1
  166. package/src/utils/welcome.js +3 -3
  167. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  172. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  173. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  174. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  175. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  176. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  177. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  178. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  179. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  180. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  181. package/packages/hu-board/src/run-tracker.js +0 -121
  182. package/src/activity-log.js +0 -59
  183. package/src/agents/host-agent.js +0 -38
  184. package/src/agents/model-registry.js +0 -142
  185. package/src/audit/plan-adherence.js +0 -224
  186. package/src/autonomy/arbiter-role.js +0 -71
  187. package/src/autonomy/arbiter.js +0 -22
  188. package/src/autonomy/decider.js +0 -18
  189. package/src/autonomy/decision-resolver.js +0 -58
  190. package/src/autonomy/outcome-report.js +0 -55
  191. package/src/autonomy/stage-ask.js +0 -30
  192. package/src/brain/decision-tracker.js +0 -125
  193. package/src/brain/decisor.js +0 -243
  194. package/src/brain/solomon-consult.js +0 -171
  195. package/src/brain/standby-scheduler.js +0 -8
  196. package/src/budget/comparison.js +0 -96
  197. package/src/canvas/parse-md.js +0 -238
  198. package/src/canvas/schema.js +0 -101
  199. package/src/canvas/to-flat.js +0 -85
  200. package/src/canvas/validate.js +0 -163
  201. package/src/ci/dispatch.js +0 -99
  202. package/src/ci/index.js +0 -3
  203. package/src/ci/pr-diff.js +0 -26
  204. package/src/cli/register-standby.js +0 -26
  205. package/src/commands/architect.js +0 -111
  206. package/src/commands/autorun.js +0 -49
  207. package/src/commands/researcher.js +0 -54
  208. package/src/commands/resume.js +0 -72
  209. package/src/commands/review.js +0 -89
  210. package/src/commands/run.js +0 -185
  211. package/src/commands/standby.js +0 -117
  212. package/src/commands/status.js +0 -36
  213. package/src/commands/triage.js +0 -78
  214. package/src/commands/undo.js +0 -62
  215. package/src/domains/domain-loader.js +0 -245
  216. package/src/domains/domain-registry.js +0 -140
  217. package/src/domains/domain-synthesizer.js +0 -129
  218. package/src/git/automation.js +0 -433
  219. package/src/git/coder-commit-guard.js +0 -40
  220. package/src/git/hu-automation.js +0 -243
  221. package/src/git/hu-snapshot.js +0 -10
  222. package/src/git/symlink-targets.js +0 -57
  223. package/src/golden/asserter.js +0 -92
  224. package/src/golden/loader.js +0 -52
  225. package/src/golden/runner.js +0 -92
  226. package/src/golden/schema.js +0 -41
  227. package/src/guards/duplicate-members.js +0 -86
  228. package/src/guards/intent-guard.js +0 -161
  229. package/src/guards/perf-guard.js +0 -126
  230. package/src/guards/policy-guard.js +0 -90
  231. package/src/guards/policy-resolver.js +0 -85
  232. package/src/guards/secret-redactor.js +0 -71
  233. package/src/hu/acceptance-runner.js +0 -138
  234. package/src/hu/lazy-planner.js +0 -109
  235. package/src/hu/parallel-executor.js +0 -94
  236. package/src/hu/routing-metrics.js +0 -17
  237. package/src/hu/split-validator.js +0 -143
  238. package/src/hu/splitting-detector.js +0 -158
  239. package/src/hu/splitting-generator.js +0 -175
  240. package/src/hu/store.js +0 -394
  241. package/src/infrastructure/mocks.js +0 -182
  242. package/src/mcp/handlers/run-handler.js +0 -318
  243. package/src/mcp/sovereignty-guard.js +0 -113
  244. package/src/mcp/tool-arg-normalizers.js +0 -16
  245. package/src/mutate/reviewer-signal.js +0 -76
  246. package/src/orchestrator/agent-fallback.js +0 -81
  247. package/src/orchestrator/brain-coordinator.js +0 -186
  248. package/src/orchestrator/ci-integration.js +0 -139
  249. package/src/orchestrator/config-init.js +0 -426
  250. package/src/orchestrator/direct-actions.js +0 -217
  251. package/src/orchestrator/drivers/error-recovery.js +0 -287
  252. package/src/orchestrator/drivers/init-context.js +0 -238
  253. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  254. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  255. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  256. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  257. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  258. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  259. package/src/orchestrator/drivers/post-loop.js +0 -404
  260. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  261. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  262. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  263. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  264. package/src/orchestrator/drivers/pre-loop.js +0 -524
  265. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  266. package/src/orchestrator/feedback-enrichment.js +0 -140
  267. package/src/orchestrator/feedback-queue.js +0 -151
  268. package/src/orchestrator/flow-control.js +0 -170
  269. package/src/orchestrator/flow-runner.js +0 -365
  270. package/src/orchestrator/fs-leak-detector.js +0 -228
  271. package/src/orchestrator/hu-scheduler.js +0 -114
  272. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  273. package/src/orchestrator/iteration-gate.js +0 -73
  274. package/src/orchestrator/iteration-stages.js +0 -9
  275. package/src/orchestrator/parallel-limiter.js +0 -74
  276. package/src/orchestrator/pipeline-context.js +0 -72
  277. package/src/orchestrator/post-loop-stages.js +0 -468
  278. package/src/orchestrator/pre-loop-stages.js +0 -11
  279. package/src/orchestrator/preflight-checks.js +0 -487
  280. package/src/orchestrator/repair/repair-detector.js +0 -117
  281. package/src/orchestrator/repair/repair-runner.js +0 -142
  282. package/src/orchestrator/reviewer-fallback.js +0 -45
  283. package/src/orchestrator/role-output-compressor.js +0 -189
  284. package/src/orchestrator/session-journal.js +0 -308
  285. package/src/orchestrator/solomon-escalation.js +0 -331
  286. package/src/orchestrator/solomon-rules.js +0 -212
  287. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  288. package/src/orchestrator/stages/architect-stage.js +0 -172
  289. package/src/orchestrator/stages/coder-stage.js +0 -506
  290. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  291. package/src/orchestrator/stages/format-stage.js +0 -61
  292. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  293. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  294. package/src/orchestrator/stages/perf-stage.js +0 -140
  295. package/src/orchestrator/stages/planner-stage.js +0 -85
  296. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  297. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  298. package/src/orchestrator/stages/research-stage.js +0 -69
  299. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  300. package/src/orchestrator/stages/sonar-stage.js +0 -439
  301. package/src/orchestrator/stages/stage-classes.js +0 -84
  302. package/src/orchestrator/stages/stage-executor.js +0 -155
  303. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  304. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  305. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  306. package/src/orchestrator/stages/triage-stage.js +0 -172
  307. package/src/orchestrator/standby.js +0 -71
  308. package/src/orchestrator/verification-gate.js +0 -183
  309. package/src/orchestrator.js +0 -22
  310. package/src/plan/adr-generator.js +0 -170
  311. package/src/plan/adr-loader.js +0 -60
  312. package/src/plan/plan-executor.js +0 -100
  313. package/src/plan/plan-validation.js +0 -4
  314. package/src/prompts/acceptance-coverage.js +0 -32
  315. package/src/prompts/arbiter.js +0 -38
  316. package/src/prompts/architect.js +0 -103
  317. package/src/prompts/hu-reviewer.js +0 -244
  318. package/src/prompts/tool-correctness-judge.js +0 -31
  319. package/src/prompts/triage.js +0 -57
  320. package/src/rag/embedder.js +0 -2
  321. package/src/rag/embedders/_cloud-base.js +0 -2
  322. package/src/rag/embedders/cohere.js +0 -2
  323. package/src/rag/embedders/mistral.js +0 -2
  324. package/src/rag/embedders/onnx.js +0 -2
  325. package/src/rag/embedders/openai.js +0 -2
  326. package/src/rag/embedders/voyage.js +0 -2
  327. package/src/rag/rerank.js +0 -4
  328. package/src/rag/where-parser.js +0 -4
  329. package/src/repeat-detector.js +0 -88
  330. package/src/review/diff-generator.js +0 -112
  331. package/src/review/git-stash-helper.js +0 -104
  332. package/src/review/schema.js +0 -31
  333. package/src/review/scope-filter.js +0 -152
  334. package/src/review/snapshot-diff.js +0 -122
  335. package/src/review/tdd-discipline.js +0 -90
  336. package/src/review/tdd-policy.js +0 -69
  337. package/src/roles/acceptance-coverage-role.js +0 -78
  338. package/src/roles/architect-role.js +0 -77
  339. package/src/roles/coder-role.js +0 -113
  340. package/src/roles/commiter-role.js +0 -113
  341. package/src/roles/domain-curator-role.js +0 -134
  342. package/src/roles/hu-reviewer-role.js +0 -64
  343. package/src/roles/impeccable-role.js +0 -85
  344. package/src/roles/index.js +0 -18
  345. package/src/roles/karajan-brain-role.js +0 -134
  346. package/src/roles/perf-role.js +0 -122
  347. package/src/roles/planner-role.js +0 -151
  348. package/src/roles/refactorer-role.js +0 -30
  349. package/src/roles/repairer-role.js +0 -181
  350. package/src/roles/researcher-role.js +0 -70
  351. package/src/roles/reviewer-role.js +0 -115
  352. package/src/roles/security-role.js +0 -73
  353. package/src/roles/solomon-role.js +0 -271
  354. package/src/roles/sonar-role.js +0 -72
  355. package/src/roles/tester-role.js +0 -235
  356. package/src/roles/tool-correctness-judge-role.js +0 -78
  357. package/src/roles/triage-role.js +0 -99
  358. package/src/session/journal/decisions-writer.js +0 -200
  359. package/src/session/journal/iteration-logger.js +0 -194
  360. package/src/session/journal/summary-writer.js +0 -320
  361. package/src/session/journal/tree-writer.js +0 -164
  362. package/src/session/journal/write-all.js +0 -89
  363. package/src/session-cleanup.js +0 -116
  364. package/src/skills/semantic-detector.js +0 -167
  365. package/src/skills/skill-detector.js +0 -385
  366. package/src/sonar/cloud-scanner.js +0 -78
  367. package/src/tracker-bootstrap.js +0 -44
  368. package/src/types/index.js +0 -38
  369. package/src/types/policy.js +0 -43
  370. package/src/types/solomon.js +0 -87
  371. package/src/utils/async-lock.js +0 -31
  372. package/src/utils/budget.js +0 -229
  373. package/src/utils/cwd-confirm.js +0 -39
  374. package/src/utils/display/event-handlers.js +0 -403
  375. package/src/utils/display/formatters.js +0 -132
  376. package/src/utils/display/header.js +0 -47
  377. package/src/utils/display/session-summary.js +0 -118
  378. package/src/utils/display/solomon.js +0 -42
  379. package/src/utils/pricing.js +0 -29
  380. package/src/utils/quota-simulator.js +0 -56
  381. package/src/utils/role-assigner.js +0 -137
  382. package/src/utils/rtk-wrapper.js +0 -87
  383. package/src/utils/run-registry.js +0 -9
  384. package/src/utils/status-dashboard.js +0 -254
  385. package/src/utils/tool-call-extractor.js +0 -56
  386. package/src/webperf/devtools-detect.js +0 -112
  387. package/src/webperf/webperf-role-integration.js +0 -66
  388. 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
- }