karajan-code 4.70.4 → 5.0.1

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