karajan-code 4.70.4 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -14
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/public/app.js +4 -18
  5. package/packages/hu-board/public/index.html +5 -2
  6. package/packages/hu-board/public/styles.css +26 -0
  7. package/packages/hu-board/public/utils/api.js +0 -74
  8. package/packages/hu-board/public/utils/board-tour.js +62 -0
  9. package/packages/hu-board/public/utils/board-view.js +49 -144
  10. package/packages/hu-board/public/utils/command-launcher.js +8 -70
  11. package/packages/hu-board/public/utils/formatters.js +10 -0
  12. package/packages/hu-board/public/utils/governance-view.js +13 -1
  13. package/packages/hu-board/public/utils/hu-actions.js +17 -68
  14. package/packages/hu-board/public/utils/init-listeners.js +7 -8
  15. package/packages/hu-board/public/utils/log-panel.js +3 -16
  16. package/packages/hu-board/public/utils/maggle-mode.js +2 -12
  17. package/packages/hu-board/public/utils/modals.js +7 -0
  18. package/packages/hu-board/public/utils/project-picker-view.js +1 -1
  19. package/packages/hu-board/public/utils/server-push.js +3 -22
  20. package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
  21. package/packages/hu-board/public/utils/story-detail-view.js +5 -19
  22. package/packages/hu-board/src/cleanup-zombies.js +0 -1
  23. package/packages/hu-board/src/command-runner.js +36 -25
  24. package/packages/hu-board/src/db-connection.js +282 -0
  25. package/packages/hu-board/src/db-paths.js +113 -0
  26. package/packages/hu-board/src/db-queries.js +188 -0
  27. package/packages/hu-board/src/db-tombstones.js +51 -0
  28. package/packages/hu-board/src/db.js +28 -619
  29. package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
  30. package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
  31. package/packages/hu-board/src/plan-mutations.js +3 -153
  32. package/packages/hu-board/src/plans-service.js +55 -0
  33. package/packages/hu-board/src/routes/api/commands.js +122 -0
  34. package/packages/hu-board/src/routes/api/plans.js +55 -0
  35. package/packages/hu-board/src/routes/api/projects.js +267 -0
  36. package/packages/hu-board/src/routes/api/prompts.js +135 -0
  37. package/packages/hu-board/src/routes/api/sessions.js +95 -0
  38. package/packages/hu-board/src/routes/api/stories.js +183 -0
  39. package/packages/hu-board/src/routes/api/system.js +241 -0
  40. package/packages/hu-board/src/routes/api/tombstones.js +38 -0
  41. package/packages/hu-board/src/routes/api.js +24 -1371
  42. package/packages/hu-board/src/routes/governance.js +23 -1
  43. package/packages/hu-board/src/routes/lanes.js +40 -0
  44. package/packages/hu-board/src/routes/rag.js +4 -3
  45. package/packages/hu-board/src/server.js +20 -34
  46. package/packages/hu-board/src/sync-files.js +318 -0
  47. package/packages/hu-board/src/sync-project.js +99 -0
  48. package/packages/hu-board/src/sync.js +22 -566
  49. package/packages/hu-board/src/zombie-reaper.js +1 -1
  50. package/scripts/dual-publish.mjs +19 -3
  51. package/scripts/postinstall.js +15 -2
  52. package/scripts/verify-pack-mcp.mjs +11 -7
  53. package/scripts/verify-pack.mjs +4 -4
  54. package/src/audit/audit-history.js +3 -2
  55. package/src/audit/dead-exports.js +68 -59
  56. package/src/audit/deterministic-summary.js +33 -13
  57. package/src/audit/npm-signatures.js +41 -0
  58. package/src/audit/sbom.js +35 -0
  59. package/src/checks/agent-token.js +112 -0
  60. package/src/checks/dir-setup.js +34 -1
  61. package/src/checks/native-build.js +21 -39
  62. package/src/checks/runner.js +128 -142
  63. package/src/cli/advanced-commands.js +6 -6
  64. package/src/cli/register-meta.js +42 -82
  65. package/src/cli/register-pipeline.js +8 -143
  66. package/src/cli/register-plan.js +9 -100
  67. package/src/cli/retired-commands.js +49 -0
  68. package/src/cli.js +18 -5
  69. package/src/commands/agent-run.js +40 -26
  70. package/src/commands/audit.js +127 -124
  71. package/src/commands/board.js +5 -9
  72. package/src/commands/check.js +29 -16
  73. package/src/commands/doctor.js +2 -0
  74. package/src/commands/env.js +176 -150
  75. package/src/commands/go.js +71 -53
  76. package/src/commands/harden.js +90 -81
  77. package/src/commands/hu-start.js +52 -0
  78. package/src/commands/hu.js +288 -221
  79. package/src/commands/identity.js +111 -78
  80. package/src/commands/init-atril.js +47 -0
  81. package/src/commands/init.js +11 -40
  82. package/src/commands/install-tools.js +70 -85
  83. package/src/commands/main-guard.js +78 -0
  84. package/src/commands/policy.js +226 -184
  85. package/src/commands/qmd.js +27 -21
  86. package/src/commands/rag.js +75 -48
  87. package/src/commands/review-gate.js +421 -341
  88. package/src/commands/start.js +4 -5
  89. package/src/commands/steward.js +96 -47
  90. package/src/commands/tournament.js +46 -37
  91. package/src/commands/worktree.js +94 -25
  92. package/src/config/loader.js +34 -17
  93. package/src/config/secrets.js +36 -0
  94. package/src/config.js +1 -0
  95. package/src/environment/adr.js +16 -2
  96. package/src/git/karajan-label.js +20 -8
  97. package/src/guards/main-guard.js +54 -0
  98. package/src/harden/hook-templates.js +16 -1
  99. package/src/harden/sentinel/posttooluse.mjs +18 -6
  100. package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
  101. package/src/harden/sentinel/sentinel-lib.mjs +129 -26
  102. package/src/harden/sentinel/sentinel-shell.mjs +5 -16
  103. package/src/harden/sentinel/sessionstart.mjs +3 -2
  104. package/src/harden/sentinel/stop.mjs +5 -4
  105. package/src/harden/workflow-templates.js +1 -1
  106. package/src/hu/board-lookup.js +29 -0
  107. package/src/hu/gh-identity.js +23 -0
  108. package/src/hu/github-board.js +4 -2
  109. package/src/hu/lane-prune.js +15 -7
  110. package/src/hu/lane-setup.js +65 -0
  111. package/src/hu/lanes.js +66 -0
  112. package/src/hu/team-board-mirror.js +3 -2
  113. package/src/infrastructure/command-runner.js +1 -1
  114. package/src/infrastructure/file-system-service.js +1 -1
  115. package/src/mcp/handlers/direct-handlers.js +2 -292
  116. package/src/mcp/handlers/hu-handlers.js +1 -35
  117. package/src/mcp/handlers/management-handlers.js +2 -42
  118. package/src/mcp/server-handlers.js +16 -22
  119. package/src/mcp/tools.js +1 -196
  120. package/src/plan/lane-plans.js +54 -0
  121. package/src/plan/plan-store.js +7 -4
  122. package/src/policy/add.js +26 -12
  123. package/src/policy/adr-number-check.js +31 -0
  124. package/src/prompts/audit.js +299 -339
  125. package/src/prompts/card-context.js +10 -5
  126. package/src/prompts/reviewer.js +5 -2
  127. package/src/rag/auto-update.js +56 -43
  128. package/src/rag/bootstrap-index.js +28 -54
  129. package/src/rag/migrate.js +1 -1
  130. package/src/rag/onnx-fallback.js +2 -2
  131. package/src/rag/pid-lease.js +70 -0
  132. package/src/rag/project-store.js +2 -12
  133. package/src/review/card-first.js +57 -46
  134. package/src/review/gate-gitignore.js +23 -4
  135. package/src/review/gate-hook.js +12 -4
  136. package/src/review/one-shot-review.js +45 -35
  137. package/src/review/publish-pr.js +14 -2
  138. package/src/review/repo-docs.js +73 -0
  139. package/src/review/repo-stack.js +59 -0
  140. package/src/review/reviewer-fallback.js +19 -4
  141. package/src/review/seal-commit.js +29 -0
  142. package/src/review/sonar-pregate.js +59 -44
  143. package/src/review/third-party-review.js +90 -16
  144. package/src/review/third-party-size.js +43 -0
  145. package/src/review/third-party-skills.js +54 -0
  146. package/src/review/verify-pr.js +1 -24
  147. package/src/roles/audit-role.js +106 -125
  148. package/src/skills/atril-skills.js +5 -4
  149. package/src/sonar/scanner.js +116 -101
  150. package/src/steward/invariants.js +5 -4
  151. package/src/steward/phantom-sweep.js +66 -0
  152. package/src/tournament/judge.js +60 -53
  153. package/src/utils/gh-account.js +37 -0
  154. package/src/utils/git.js +0 -13
  155. package/src/utils/home-migration.js +7 -1
  156. package/src/utils/main-checkout.js +53 -0
  157. package/src/utils/qmd-collection.js +3 -1
  158. package/src/utils/welcome.js +3 -3
  159. package/templates/{skills → atril/commands}/kj-architect.md +5 -0
  160. package/templates/{skills → atril/commands}/kj-audit.md +5 -0
  161. package/templates/{skills → atril/commands}/kj-board.md +5 -0
  162. package/templates/{skills → atril/commands}/kj-code.md +5 -0
  163. package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
  164. package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
  165. package/templates/{skills → atril/commands}/kj-discover.md +5 -0
  166. package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
  167. package/templates/{skills → atril/commands}/kj-review.md +5 -0
  168. package/templates/{skills → atril/commands}/kj-security.md +5 -0
  169. package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
  170. package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
  171. package/templates/{skills → atril/commands}/kj-test.md +5 -0
  172. package/packages/hu-board/public/utils/run-launcher.js +0 -169
  173. package/packages/hu-board/src/run-tracker.js +0 -121
  174. package/src/activity-log.js +0 -59
  175. package/src/agents/host-agent.js +0 -38
  176. package/src/agents/model-registry.js +0 -142
  177. package/src/audit/plan-adherence.js +0 -224
  178. package/src/autonomy/arbiter-role.js +0 -71
  179. package/src/autonomy/arbiter.js +0 -22
  180. package/src/autonomy/decider.js +0 -18
  181. package/src/autonomy/decision-resolver.js +0 -58
  182. package/src/autonomy/outcome-report.js +0 -55
  183. package/src/autonomy/stage-ask.js +0 -30
  184. package/src/brain/decision-tracker.js +0 -125
  185. package/src/brain/decisor.js +0 -243
  186. package/src/brain/solomon-consult.js +0 -171
  187. package/src/brain/standby-scheduler.js +0 -8
  188. package/src/budget/comparison.js +0 -96
  189. package/src/canvas/parse-md.js +0 -238
  190. package/src/canvas/schema.js +0 -101
  191. package/src/canvas/to-flat.js +0 -85
  192. package/src/canvas/validate.js +0 -163
  193. package/src/ci/dispatch.js +0 -99
  194. package/src/ci/index.js +0 -3
  195. package/src/ci/pr-diff.js +0 -26
  196. package/src/cli/register-standby.js +0 -26
  197. package/src/commands/architect.js +0 -111
  198. package/src/commands/autorun.js +0 -49
  199. package/src/commands/researcher.js +0 -54
  200. package/src/commands/resume.js +0 -72
  201. package/src/commands/review.js +0 -89
  202. package/src/commands/run.js +0 -185
  203. package/src/commands/standby.js +0 -117
  204. package/src/commands/status.js +0 -36
  205. package/src/commands/triage.js +0 -78
  206. package/src/commands/undo.js +0 -62
  207. package/src/domains/domain-loader.js +0 -245
  208. package/src/domains/domain-registry.js +0 -140
  209. package/src/domains/domain-synthesizer.js +0 -129
  210. package/src/git/automation.js +0 -433
  211. package/src/git/coder-commit-guard.js +0 -40
  212. package/src/git/hu-automation.js +0 -243
  213. package/src/git/hu-snapshot.js +0 -10
  214. package/src/git/symlink-targets.js +0 -57
  215. package/src/golden/asserter.js +0 -92
  216. package/src/golden/loader.js +0 -52
  217. package/src/golden/runner.js +0 -92
  218. package/src/golden/schema.js +0 -41
  219. package/src/guards/duplicate-members.js +0 -86
  220. package/src/guards/intent-guard.js +0 -161
  221. package/src/guards/perf-guard.js +0 -126
  222. package/src/guards/policy-guard.js +0 -90
  223. package/src/guards/policy-resolver.js +0 -85
  224. package/src/guards/secret-redactor.js +0 -71
  225. package/src/hu/acceptance-runner.js +0 -138
  226. package/src/hu/lazy-planner.js +0 -109
  227. package/src/hu/parallel-executor.js +0 -94
  228. package/src/hu/routing-metrics.js +0 -17
  229. package/src/hu/split-validator.js +0 -143
  230. package/src/hu/splitting-detector.js +0 -158
  231. package/src/hu/splitting-generator.js +0 -175
  232. package/src/hu/store.js +0 -394
  233. package/src/infrastructure/mocks.js +0 -182
  234. package/src/mcp/handlers/run-handler.js +0 -318
  235. package/src/mcp/sovereignty-guard.js +0 -113
  236. package/src/mcp/tool-arg-normalizers.js +0 -16
  237. package/src/mutate/reviewer-signal.js +0 -76
  238. package/src/orchestrator/agent-fallback.js +0 -81
  239. package/src/orchestrator/brain-coordinator.js +0 -186
  240. package/src/orchestrator/ci-integration.js +0 -139
  241. package/src/orchestrator/config-init.js +0 -426
  242. package/src/orchestrator/direct-actions.js +0 -217
  243. package/src/orchestrator/drivers/error-recovery.js +0 -287
  244. package/src/orchestrator/drivers/init-context.js +0 -238
  245. package/src/orchestrator/drivers/iteration-loop.js +0 -382
  246. package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
  247. package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
  248. package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
  249. package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
  250. package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
  251. package/src/orchestrator/drivers/post-loop.js +0 -404
  252. package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
  253. package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
  254. package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
  255. package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
  256. package/src/orchestrator/drivers/pre-loop.js +0 -524
  257. package/src/orchestrator/drivers/run-hu-batch.js +0 -468
  258. package/src/orchestrator/feedback-enrichment.js +0 -140
  259. package/src/orchestrator/feedback-queue.js +0 -151
  260. package/src/orchestrator/flow-control.js +0 -170
  261. package/src/orchestrator/flow-runner.js +0 -365
  262. package/src/orchestrator/fs-leak-detector.js +0 -228
  263. package/src/orchestrator/hu-scheduler.js +0 -114
  264. package/src/orchestrator/hu-sub-pipeline.js +0 -642
  265. package/src/orchestrator/iteration-gate.js +0 -73
  266. package/src/orchestrator/iteration-stages.js +0 -9
  267. package/src/orchestrator/parallel-limiter.js +0 -74
  268. package/src/orchestrator/pipeline-context.js +0 -72
  269. package/src/orchestrator/post-loop-stages.js +0 -468
  270. package/src/orchestrator/pre-loop-stages.js +0 -11
  271. package/src/orchestrator/preflight-checks.js +0 -487
  272. package/src/orchestrator/repair/repair-detector.js +0 -117
  273. package/src/orchestrator/repair/repair-runner.js +0 -142
  274. package/src/orchestrator/reviewer-fallback.js +0 -45
  275. package/src/orchestrator/role-output-compressor.js +0 -189
  276. package/src/orchestrator/session-journal.js +0 -308
  277. package/src/orchestrator/solomon-escalation.js +0 -331
  278. package/src/orchestrator/solomon-rules.js +0 -212
  279. package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
  280. package/src/orchestrator/stages/architect-stage.js +0 -172
  281. package/src/orchestrator/stages/coder-stage.js +0 -506
  282. package/src/orchestrator/stages/domain-curator-stage.js +0 -82
  283. package/src/orchestrator/stages/format-stage.js +0 -61
  284. package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
  285. package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
  286. package/src/orchestrator/stages/perf-stage.js +0 -140
  287. package/src/orchestrator/stages/planner-stage.js +0 -85
  288. package/src/orchestrator/stages/rag-context-stage.js +0 -80
  289. package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
  290. package/src/orchestrator/stages/research-stage.js +0 -69
  291. package/src/orchestrator/stages/reviewer-stage.js +0 -431
  292. package/src/orchestrator/stages/sonar-stage.js +0 -439
  293. package/src/orchestrator/stages/stage-classes.js +0 -84
  294. package/src/orchestrator/stages/stage-executor.js +0 -155
  295. package/src/orchestrator/stages/suite-green-stage.js +0 -62
  296. package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
  297. package/src/orchestrator/stages/tool-judge-stage.js +0 -53
  298. package/src/orchestrator/stages/triage-stage.js +0 -172
  299. package/src/orchestrator/standby.js +0 -71
  300. package/src/orchestrator/verification-gate.js +0 -183
  301. package/src/orchestrator.js +0 -22
  302. package/src/plan/adr-generator.js +0 -170
  303. package/src/plan/adr-loader.js +0 -60
  304. package/src/plan/plan-executor.js +0 -100
  305. package/src/plan/plan-validation.js +0 -4
  306. package/src/prompts/acceptance-coverage.js +0 -32
  307. package/src/prompts/arbiter.js +0 -38
  308. package/src/prompts/architect.js +0 -103
  309. package/src/prompts/hu-reviewer.js +0 -244
  310. package/src/prompts/tool-correctness-judge.js +0 -31
  311. package/src/prompts/triage.js +0 -57
  312. package/src/rag/embedder.js +0 -2
  313. package/src/rag/embedders/_cloud-base.js +0 -2
  314. package/src/rag/embedders/cohere.js +0 -2
  315. package/src/rag/embedders/mistral.js +0 -2
  316. package/src/rag/embedders/onnx.js +0 -2
  317. package/src/rag/embedders/openai.js +0 -2
  318. package/src/rag/embedders/voyage.js +0 -2
  319. package/src/rag/rerank.js +0 -4
  320. package/src/rag/where-parser.js +0 -4
  321. package/src/repeat-detector.js +0 -88
  322. package/src/review/diff-generator.js +0 -112
  323. package/src/review/git-stash-helper.js +0 -104
  324. package/src/review/schema.js +0 -31
  325. package/src/review/scope-filter.js +0 -152
  326. package/src/review/snapshot-diff.js +0 -122
  327. package/src/review/tdd-discipline.js +0 -90
  328. package/src/review/tdd-policy.js +0 -69
  329. package/src/roles/acceptance-coverage-role.js +0 -78
  330. package/src/roles/architect-role.js +0 -77
  331. package/src/roles/coder-role.js +0 -113
  332. package/src/roles/commiter-role.js +0 -113
  333. package/src/roles/domain-curator-role.js +0 -134
  334. package/src/roles/hu-reviewer-role.js +0 -64
  335. package/src/roles/impeccable-role.js +0 -85
  336. package/src/roles/index.js +0 -18
  337. package/src/roles/karajan-brain-role.js +0 -134
  338. package/src/roles/perf-role.js +0 -122
  339. package/src/roles/planner-role.js +0 -151
  340. package/src/roles/refactorer-role.js +0 -30
  341. package/src/roles/repairer-role.js +0 -181
  342. package/src/roles/researcher-role.js +0 -70
  343. package/src/roles/reviewer-role.js +0 -115
  344. package/src/roles/security-role.js +0 -73
  345. package/src/roles/solomon-role.js +0 -271
  346. package/src/roles/sonar-role.js +0 -72
  347. package/src/roles/tester-role.js +0 -235
  348. package/src/roles/tool-correctness-judge-role.js +0 -78
  349. package/src/roles/triage-role.js +0 -99
  350. package/src/session/journal/decisions-writer.js +0 -200
  351. package/src/session/journal/iteration-logger.js +0 -194
  352. package/src/session/journal/summary-writer.js +0 -320
  353. package/src/session/journal/tree-writer.js +0 -164
  354. package/src/session/journal/write-all.js +0 -89
  355. package/src/session-cleanup.js +0 -116
  356. package/src/skills/semantic-detector.js +0 -167
  357. package/src/skills/skill-detector.js +0 -385
  358. package/src/sonar/cloud-scanner.js +0 -78
  359. package/src/tracker-bootstrap.js +0 -44
  360. package/src/types/index.js +0 -38
  361. package/src/types/policy.js +0 -43
  362. package/src/types/solomon.js +0 -87
  363. package/src/utils/async-lock.js +0 -31
  364. package/src/utils/budget.js +0 -229
  365. package/src/utils/cwd-confirm.js +0 -39
  366. package/src/utils/display/event-handlers.js +0 -403
  367. package/src/utils/display/formatters.js +0 -132
  368. package/src/utils/display/header.js +0 -47
  369. package/src/utils/display/session-summary.js +0 -118
  370. package/src/utils/display/solomon.js +0 -42
  371. package/src/utils/pricing.js +0 -29
  372. package/src/utils/quota-simulator.js +0 -56
  373. package/src/utils/role-assigner.js +0 -137
  374. package/src/utils/rtk-wrapper.js +0 -87
  375. package/src/utils/run-registry.js +0 -9
  376. package/src/utils/status-dashboard.js +0 -254
  377. package/src/utils/tool-call-extractor.js +0 -56
  378. package/src/webperf/devtools-detect.js +0 -112
  379. package/src/webperf/webperf-role-integration.js +0 -66
  380. package/templates/skills/kj-run.md +0 -73
@@ -1,117 +0,0 @@
1
- // KJC-TSK-0414 PR2: comandos kj standby list / kj resume.
2
- //
3
- // `kj resume <sessionId>` valida cooldownUntil y, si llegó la hora, re-spawn
4
- // el comando original capturado en argv. Si cooldown todavía está en el
5
- // futuro, muestra countdown y aborta. `kj standby list` solo enumera.
6
- //
7
- // Estrategia de resume: cada sessionState persiste su argv original (los
8
- // argumentos con los que se lanzó el `kj` que hibernó). El resume re-spawn
9
- // EXACTAMENTE ese mismo comando con env preservado. El run reanuda como si
10
- // fuera un retry — el state interno (HU pendiente, snapshot_sha, etc.) está
11
- // en el JSON persistido en disco por TSK-0408 + TSK-0414 PR1.
12
-
13
- import { spawn } from "node:child_process";
14
- import path from "node:path";
15
- import { fileURLToPath } from "node:url";
16
- import { loadStandby, listPendingStandby, markStandbyDone, acquireStandbyLock } from "../brain/standby-store.js";
17
-
18
- const REPO_KJ_CLI = (() => {
19
- try {
20
- const here = path.dirname(fileURLToPath(import.meta.url));
21
- return path.join(here, "..", "cli.js");
22
- } catch {
23
- return null;
24
- }
25
- })();
26
-
27
- function formatCountdown(ms) {
28
- if (ms <= 0) return "ahora";
29
- const s = Math.round(ms / 1000);
30
- const h = Math.floor(s / 3600);
31
- const m = Math.floor((s % 3600) / 60);
32
- const sec = s % 60;
33
- return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
34
- }
35
-
36
- export async function standbyListCommand({ json } = {}) {
37
- const sessions = listPendingStandby();
38
- if (json) {
39
- console.log(JSON.stringify(sessions, null, 2));
40
- return;
41
- }
42
- if (sessions.length === 0) {
43
- console.log("No hay sesiones hibernadas.");
44
- return;
45
- }
46
- console.log(`Sesiones hibernadas (${sessions.length}):`);
47
- const now = Date.now();
48
- for (const s of sessions) {
49
- const ms = new Date(s.cooldownUntil).getTime() - now;
50
- const status = ms <= 0 ? "✓ lista para resume" : `⏳ resume en ${formatCountdown(ms)}`;
51
- console.log(` ${s.sessionId} · ${s.reason || "?"} · ${status}`);
52
- if (s.planId) {
53
- const huSuffix = s.huId ? `, HU: ${s.huId}` : "";
54
- console.log(` plan: ${s.planId}${huSuffix}`);
55
- }
56
- }
57
- }
58
-
59
- /**
60
- * Re-spawn el comando original capturado en sessionState.argv.
61
- * Si cooldownUntil > now y force=false → aborta con mensaje.
62
- */
63
- export async function resumeCommand({ sessionId, force } = {}) {
64
- if (!sessionId) {
65
- console.error("kj resume requiere <sessionId>. Usa `kj standby list` para ver pendientes.");
66
- process.exitCode = 1;
67
- return;
68
- }
69
- const state = loadStandby(sessionId);
70
- if (!state) {
71
- console.error(`Sesión no encontrada: ${sessionId}`);
72
- process.exitCode = 1;
73
- return;
74
- }
75
- const cooldownMs = new Date(state.cooldownUntil).getTime() - Date.now();
76
- if (cooldownMs > 0 && !force) {
77
- console.log(`Sesión ${sessionId} todavía en cooldown ${formatCountdown(cooldownMs)} (hasta ${state.cooldownUntil}).`);
78
- console.log("Espera o usa `kj resume <sessionId> --force` (no recomendado — la API seguramente seguirá rechazando).");
79
- process.exitCode = 0;
80
- return;
81
- }
82
-
83
- const lock = acquireStandbyLock(sessionId);
84
- if (!lock.acquired) {
85
- console.log(`Sesión ${sessionId} ya está siendo reanudada por otro proceso.`);
86
- process.exitCode = 0;
87
- return;
88
- }
89
-
90
- try {
91
- if (!Array.isArray(state.argv) || state.argv.length === 0) {
92
- console.error(`Sesión ${sessionId} sin argv — no se puede re-spawn. Borra manual y relanza.`);
93
- process.exitCode = 1;
94
- return;
95
- }
96
- if (!REPO_KJ_CLI) {
97
- console.error("No se pudo localizar cli.js. ¿Karajan instalado correctamente?");
98
- process.exitCode = 1;
99
- return;
100
- }
101
- console.log(`Reanudando ${sessionId}: kj ${state.argv.join(" ")}`);
102
- const child = spawn(process.execPath, [REPO_KJ_CLI, ...state.argv], {
103
- cwd: state.cwd || process.cwd(),
104
- env: { ...process.env, ...(state.env || {}), KJ_RESUME_FROM: sessionId },
105
- stdio: "inherit",
106
- });
107
- await new Promise((resolve) => {
108
- child.on("exit", (code) => {
109
- if (code === 0) markStandbyDone(sessionId);
110
- process.exitCode = code ?? 0;
111
- resolve();
112
- });
113
- });
114
- } finally {
115
- lock.release?.();
116
- }
117
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * CLI status command — shows a terminal dashboard of the current pipeline state.
3
- */
4
-
5
- import { readRunLog } from "../utils/run-log.js";
6
- import { loadMostRecentSession } from "../session/store.js";
7
- import { buildDashboard } from "../utils/status-dashboard.js";
8
-
9
-
10
- /**
11
- * Run the `kj status` command: print a human-readable dashboard to stdout.
12
- * @param {object} options
13
- * @param {number} [options.lines=50] - Max log lines to read.
14
- * @param {string} [options.projectDir] - Project directory override.
15
- */
16
- export async function statusCommand({ lines = 50, projectDir } = {}) {
17
- const dir = projectDir || process.cwd();
18
- const logResult = readRunLog(dir, lines);
19
-
20
- let session = null;
21
- try {
22
- session = await loadMostRecentSession();
23
- } catch { /* no session available */ }
24
-
25
- let stories = [];
26
- if (session) {
27
- try {
28
- const { loadHuBatch } = await import("../hu/store.js");
29
- const batch = await loadHuBatch(session.id);
30
- if (batch?.stories) stories = batch.stories;
31
- } catch { /* no HU batch */ }
32
- }
33
-
34
- const dashboard = buildDashboard(session, logResult.lines || [], { stories });
35
- console.log(dashboard);
36
- }
@@ -1,78 +0,0 @@
1
- import { createAgent } from "../agents/index.js";
2
- import { assertAgentsAvailable } from "../agents/availability.js";
3
- import { resolveRole } from "../config.js";
4
- import { createCliProgressReporter } from "../utils/cli-progress.js";
5
- import { buildTriagePrompt } from "../prompts/triage.js";
6
- import { parseMaybeJsonString } from "../review/parser.js";
7
- import { withBrainRecovery } from "../brain/with-brain-recovery.js";
8
-
9
- function formatTriage(result) {
10
- const lines = [];
11
- lines.push(`## Triage Result`);
12
- lines.push(`- **Level:** ${result.level || "unknown"}`);
13
- if (result.taskType) lines.push(`- **Task type:** ${result.taskType}`);
14
- if (result.reasoning) lines.push(`- **Reasoning:** ${result.reasoning}`);
15
- lines.push("");
16
-
17
- if (result.roles?.length) {
18
- lines.push("### Recommended Roles");
19
- for (const r of result.roles) {
20
- lines.push(`- ${r}`);
21
- }
22
- lines.push("");
23
- }
24
-
25
- if (result.shouldDecompose) {
26
- lines.push("### Decomposition Suggested");
27
- if (result.subtasks?.length) {
28
- for (const s of result.subtasks) {
29
- lines.push(`- ${typeof s === "string" ? s : s.title || s}`);
30
- }
31
- }
32
- lines.push("");
33
- }
34
-
35
- return lines.join("\n");
36
- }
37
-
38
- export async function triageCommand({ task, config, logger, json }) {
39
- const { withCliRunLog } = await import("../utils/cli-run-log.js");
40
- return withCliRunLog("triage", { projectDir: config?.projectDir, logger }, async ({ runLog }) => {
41
- const triageRole = resolveRole(config, "triage");
42
- await assertAgentsAvailable([triageRole.provider]);
43
- logger.info(`Triage (${triageRole.provider}) starting...`);
44
- runLog.logText(`[triage] provider=${triageRole.provider}`);
45
-
46
- const agent = createAgent(triageRole.provider, config, logger);
47
- const prompt = buildTriagePrompt({ task });
48
- const progress = createCliProgressReporter({ role: "triage" });
49
- let result;
50
- try {
51
- result = await withBrainRecovery({
52
- agent, taskArgs: { prompt, onOutput: progress.onOutput, role: "triage" },
53
- role: "triage", provider: triageRole.provider, logger,
54
- });
55
- progress.finish(result.ok ? "done" : (result.action || "failed"));
56
- } catch (err) { progress.finish("failed"); throw err; }
57
-
58
- if (!result.ok) {
59
- throw new Error(result.error || result.output || "Triage failed");
60
- }
61
-
62
- const parsed = parseMaybeJsonString(result.output);
63
- if (parsed?.level) runLog.logText(`[triage] level=${parsed.level} roles=${(parsed.roles || []).join(",")}`);
64
-
65
- if (json) {
66
- console.log(JSON.stringify(parsed || result.output, null, 2));
67
- return { ok: true };
68
- }
69
-
70
- if (parsed?.level) {
71
- console.log(formatTriage(parsed));
72
- } else {
73
- console.log(result.output);
74
- }
75
- logger.info("Triage completed.");
76
- return { ok: true };
77
- });
78
- }
@@ -1,62 +0,0 @@
1
- import { loadMostRecentSession } from "../session/store.js";
2
- import { runCommand } from "../utils/process.js";
3
-
4
- /**
5
- * Revert the last pipeline run by resetting to the pre-pipeline commit.
6
- * Default: soft reset (keeps changes staged). With --hard: discards all changes.
7
- */
8
- export async function undoCommand({ hard = false, logger } = {}) {
9
- const session = await loadMostRecentSession();
10
- if (!session) {
11
- const msg = "No session to undo. No sessions found in the sessions directory.";
12
- if (logger) logger.error(msg);
13
- return { ok: false, error: msg };
14
- }
15
-
16
- const sha = session.session_start_sha;
17
- if (!sha) {
18
- const msg = `Session ${session.id} has no session_start_sha. Cannot determine the pre-pipeline commit.`;
19
- if (logger) logger.error(msg);
20
- return { ok: false, error: msg };
21
- }
22
-
23
- // Verify the SHA exists in git history
24
- const verifyRes = await runCommand("git", ["cat-file", "-t", sha]);
25
- if (verifyRes.exitCode !== 0 || verifyRes.stdout.trim() !== "commit") {
26
- const msg = `Commit ${sha} not found in git history. It may have been garbage-collected or belong to a different repository.`;
27
- if (logger) logger.error(msg);
28
- return { ok: false, error: msg };
29
- }
30
-
31
- // Check there are commits after the SHA (HEAD is ahead)
32
- const logRes = await runCommand("git", ["log", "--oneline", `${sha}..HEAD`]);
33
- if (logRes.exitCode !== 0 || !logRes.stdout.trim()) {
34
- const msg = `No commits to undo. HEAD is already at or before ${sha.slice(0, 8)}.`;
35
- if (logger) logger.warn(msg);
36
- return { ok: false, error: msg };
37
- }
38
-
39
- const mode = hard ? "--hard" : "--soft";
40
- const resetRes = await runCommand("git", ["reset", mode, sha]);
41
- if (resetRes.exitCode !== 0) {
42
- const msg = `git reset ${mode} ${sha} failed: ${resetRes.stderr || resetRes.stdout}`;
43
- if (logger) logger.error(msg);
44
- return { ok: false, error: msg };
45
- }
46
-
47
- const shortSha = sha.slice(0, 8);
48
- const message = hard
49
- ? `Reverted to pre-pipeline state (commit ${shortSha}). All changes discarded.`
50
- : `Reverted to pre-pipeline state (commit ${shortSha}). Changes are staged. Use \`git diff --cached\` to review.`;
51
-
52
- if (logger) logger.info(message);
53
- console.log(message);
54
-
55
- return {
56
- ok: true,
57
- message,
58
- sessionId: session.id,
59
- sha,
60
- mode: hard ? "hard" : "soft"
61
- };
62
- }
@@ -1,245 +0,0 @@
1
- /**
2
- * Domain Knowledge loader.
3
- * Scans .karajan/domains/ (project-local) and ~/.karajan/domains/ (user-global)
4
- * for DOMAIN.md files with YAML frontmatter.
5
- * Project-local domains override user-global domains by directory name.
6
- */
7
-
8
- import { readdir, readFile, mkdir, writeFile, stat } from "node:fs/promises";
9
- import { join, isAbsolute } from "node:path";
10
- import yaml from "js-yaml";
11
- import { getKarajanHome } from "../utils/paths.js";
12
-
13
- const DOMAIN_FILE = "DOMAIN.md";
14
- const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
15
-
16
- /**
17
- * Parse a DOMAIN.md file into a structured DomainFile object.
18
- * @param {string} filePath — absolute path to the DOMAIN.md file
19
- * @returns {Promise<DomainFile|null>} parsed domain or null on error
20
- *
21
- * @typedef {Object} DomainSection
22
- * @property {string} heading — section heading (e.g. "Core Concepts")
23
- * @property {string} content — section body (markdown)
24
- *
25
- * @typedef {Object} DomainFile
26
- * @property {string} name
27
- * @property {string} description
28
- * @property {string[]} tags
29
- * @property {string} version
30
- * @property {string} author
31
- * @property {string} visibility — "private" | "public"
32
- * @property {Array<{type: string, note?: string}>} sources
33
- * @property {string} content — full markdown body (after frontmatter)
34
- * @property {DomainSection[]} sections — parsed markdown sections
35
- * @property {string} filePath — original file path
36
- * @property {string} [origin] — "project" | "user" (set by loadDomains)
37
- */
38
- export async function parseDomainFile(filePath) {
39
- let raw;
40
- try {
41
- raw = await readFile(filePath, "utf-8");
42
- } catch {
43
- return null;
44
- }
45
-
46
- const match = raw.match(FRONTMATTER_RE);
47
- if (!match) return null;
48
-
49
- let meta;
50
- try {
51
- meta = yaml.load(match[1]);
52
- } catch {
53
- return null;
54
- }
55
-
56
- if (!meta || typeof meta !== "object" || !meta.name) return null;
57
-
58
- const content = match[2].trim();
59
- const sections = parseSections(content);
60
-
61
- return {
62
- name: meta.name,
63
- description: meta.description || "",
64
- tags: Array.isArray(meta.tags) ? meta.tags : [],
65
- version: meta.version || "0.0.0",
66
- author: meta.author || "",
67
- visibility: meta.visibility || "private",
68
- sources: Array.isArray(meta.sources) ? meta.sources : [],
69
- content,
70
- sections,
71
- filePath
72
- };
73
- }
74
-
75
- /**
76
- * Split markdown content into sections by ## headings.
77
- * @param {string} content
78
- * @returns {DomainSection[]}
79
- */
80
- function parseSections(content) {
81
- const sections = [];
82
- const lines = content.split("\n");
83
- let current = null;
84
-
85
- for (const line of lines) {
86
- const headingMatch = line.match(/^##\s+(.+)/);
87
- if (headingMatch) {
88
- if (current) {
89
- current.content = current.content.trim();
90
- sections.push(current);
91
- }
92
- current = { heading: headingMatch[1].trim(), content: "" };
93
- } else if (current) {
94
- current.content += line + "\n";
95
- }
96
- }
97
-
98
- if (current) {
99
- current.content = current.content.trim();
100
- sections.push(current);
101
- }
102
-
103
- return sections;
104
- }
105
-
106
- /**
107
- * Auto-detect project context files (README.md, CLAUDE.md) as lightweight domains.
108
- * Used as fallback when no explicit .karajan/domains/ are configured.
109
- *
110
- * @param {string} projectDir — absolute path to project root
111
- * @returns {Promise<DomainFile[]>}
112
- */
113
- export async function autoDetectDomains(projectDir) {
114
- if (!projectDir) return [];
115
-
116
- const candidates = ["README.md", "CLAUDE.md", "docs/README.md"];
117
- const detected = [];
118
-
119
- for (const rel of candidates) {
120
- const filePath = join(projectDir, rel);
121
- let content;
122
- try {
123
- content = await readFile(filePath, "utf-8");
124
- } catch { continue; }
125
-
126
- if (!content || content.trim().length < 20) continue;
127
-
128
- // Truncate to first 4000 chars to avoid bloating context
129
- const trimmed = content.length > 4000 ? content.slice(0, 4000) + "\n\n[...truncated]" : content;
130
-
131
- detected.push({
132
- name: `auto:${rel}`,
133
- description: `Auto-detected from ${rel}`,
134
- tags: [],
135
- version: "0.0.0",
136
- author: "",
137
- visibility: "private",
138
- sources: [{ type: "auto-detect", note: rel }],
139
- content: trimmed,
140
- sections: parseSections(trimmed),
141
- filePath,
142
- origin: "auto-detect"
143
- });
144
- }
145
-
146
- return detected;
147
- }
148
-
149
- /**
150
- * Load all domains from project-local and user-global directories.
151
- * Falls back to auto-detecting README.md/CLAUDE.md when no explicit domains found.
152
- * Project-local domains override user-global domains when directory names match.
153
- *
154
- * @param {string|null} projectDir — absolute path to project root (null = user-global only)
155
- * @returns {Promise<DomainFile[]>}
156
- */
157
- export async function loadDomains(projectDir) {
158
- const userDir = join(getKarajanHome(), "domains");
159
- const projectDomainDir = projectDir ? join(projectDir, ".karajan", "domains") : null;
160
-
161
- // Load user-global first, then project-local overrides
162
- const userDomains = await scanDomainDir(userDir, "user");
163
- const projectDomains = projectDomainDir ? await scanDomainDir(projectDomainDir, "project") : [];
164
-
165
- // Build a map keyed by directory name for merge.
166
- const merged = new Map();
167
-
168
- for (const { dirName, domain } of userDomains) {
169
- merged.set(dirName, domain);
170
- }
171
- for (const { dirName, domain } of projectDomains) {
172
- merged.set(dirName, domain); // project overrides user
173
- }
174
-
175
- const explicit = Array.from(merged.values());
176
-
177
- // Fallback: auto-detect README.md, CLAUDE.md when no explicit domains found
178
- if (explicit.length === 0 && projectDir) {
179
- return autoDetectDomains(projectDir);
180
- }
181
-
182
- return explicit;
183
- }
184
-
185
- /**
186
- * Scan a single domains directory for DOMAIN.md files.
187
- * @param {string} dir — absolute path to a domains/ directory
188
- * @param {string} origin — "project" | "user"
189
- * @returns {Promise<Array<{dirName: string, domain: DomainFile}>>}
190
- */
191
- async function scanDomainDir(dir, origin) {
192
- let entries;
193
- try {
194
- entries = await readdir(dir, { withFileTypes: true });
195
- } catch {
196
- return [];
197
- }
198
-
199
- const results = [];
200
-
201
- for (const entry of entries) {
202
- if (!entry.isDirectory()) continue;
203
-
204
- const domainPath = join(dir, entry.name, DOMAIN_FILE);
205
- const domain = await parseDomainFile(domainPath);
206
-
207
- if (domain) {
208
- domain.origin = origin;
209
- results.push({ dirName: entry.name, domain });
210
- }
211
- }
212
-
213
- return results;
214
- }
215
-
216
- /**
217
- * Persist an inline domain (text or file path) to .karajan/domains/inline/DOMAIN.md.
218
- * If domainInput is a path to an existing .md file, reads its content.
219
- * Otherwise treats it as inline text.
220
- *
221
- * @param {string} domainInput — inline text or absolute path to a .md file
222
- * @param {string} projectDir — project root
223
- */
224
- export async function persistInlineDomain(domainInput, projectDir) {
225
- if (!domainInput || !projectDir) return;
226
-
227
- let content = domainInput;
228
-
229
- // If it looks like a file path, try to read it
230
- if (isAbsolute(domainInput) && domainInput.endsWith(".md")) {
231
- try {
232
- const s = await stat(domainInput);
233
- if (s.isFile()) {
234
- content = await readFile(domainInput, "utf-8");
235
- }
236
- } catch { /* treat as inline text */ }
237
- }
238
-
239
- const domainDir = join(projectDir, ".karajan", "domains", "inline");
240
- await mkdir(domainDir, { recursive: true });
241
-
242
- const domainFile = join(domainDir, DOMAIN_FILE);
243
- const wrapped = `---\nname: inline-domain\ndescription: Domain knowledge provided via --domain parameter\ntags: []\nversion: "0.0.0"\n---\n\n${content}\n`;
244
- await writeFile(domainFile, wrapped, "utf-8");
245
- }
@@ -1,140 +0,0 @@
1
- /**
2
- * Local domain registry.
3
- * Tracks installed domains in ~/.karajan/domain-registry.json.
4
- * Provides search and filtering by tags/hints.
5
- * Interface prepared for future remote registry extension.
6
- */
7
-
8
- import { readFile, writeFile, mkdir } from "node:fs/promises";
9
- import { join } from "node:path";
10
- import { getKarajanHome } from "../utils/paths.js";
11
-
12
- const REGISTRY_FILE = "domain-registry.json";
13
- const SCHEMA_VERSION = 1;
14
-
15
- /**
16
- * @typedef {Object} RegistryEntry
17
- * @property {string} name
18
- * @property {string} [description]
19
- * @property {string} version
20
- * @property {string} source — "local" (future: "remote")
21
- * @property {string} installedAt — ISO timestamp
22
- * @property {string} filePath — absolute path to DOMAIN.md
23
- * @property {string[]} tags
24
- */
25
-
26
- export class DomainRegistry {
27
- /**
28
- * @param {Record<string, RegistryEntry>} domains
29
- */
30
- constructor(domains = {}) {
31
- this._domains = domains;
32
- }
33
-
34
- /**
35
- * Load registry from disk. Creates empty registry if file is missing or corrupt.
36
- * @returns {Promise<DomainRegistry>}
37
- */
38
- static async load() {
39
- const filePath = join(getKarajanHome(), REGISTRY_FILE);
40
- try {
41
- const raw = await readFile(filePath, "utf-8");
42
- const data = JSON.parse(raw);
43
- if (data?.schemaVersion === SCHEMA_VERSION && data.domains) {
44
- return new DomainRegistry(data.domains);
45
- }
46
- } catch { /* file missing, corrupt, or wrong schema */ }
47
- return new DomainRegistry();
48
- }
49
-
50
- /**
51
- * Persist registry to disk.
52
- */
53
- async save() {
54
- const home = getKarajanHome();
55
- await mkdir(home, { recursive: true });
56
- const filePath = join(home, REGISTRY_FILE);
57
- const data = {
58
- schemaVersion: SCHEMA_VERSION,
59
- domains: this._domains
60
- };
61
- await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
62
- }
63
-
64
- /**
65
- * Register or update a domain in the registry.
66
- * @param {{name: string, version?: string, tags?: string[], filePath?: string, description?: string}} domainFile
67
- */
68
- register(domainFile) {
69
- this._domains[domainFile.name] = {
70
- name: domainFile.name,
71
- description: domainFile.description || "",
72
- version: domainFile.version || "0.0.0",
73
- source: "local",
74
- installedAt: new Date().toISOString(),
75
- filePath: domainFile.filePath || "",
76
- tags: domainFile.tags || []
77
- };
78
- }
79
-
80
- /**
81
- * List domains, optionally filtered by tags and/or free-text query.
82
- * @param {{tags?: string[], query?: string}} [filters]
83
- * @returns {RegistryEntry[]}
84
- */
85
- list(filters = {}) {
86
- let entries = Object.values(this._domains);
87
-
88
- if (filters.tags?.length) {
89
- const tagSet = new Set(filters.tags.map(t => t.toLowerCase()));
90
- entries = entries.filter(e =>
91
- e.tags?.some(t => tagSet.has(t.toLowerCase()))
92
- );
93
- }
94
-
95
- if (filters.query) {
96
- const q = filters.query.toLowerCase();
97
- entries = entries.filter(e =>
98
- (e.name || "").toLowerCase().includes(q) ||
99
- (e.description || "").toLowerCase().includes(q)
100
- );
101
- }
102
-
103
- return entries;
104
- }
105
-
106
- /**
107
- * Search domains by triage hints.
108
- * Matches hints against tags, name and description.
109
- * Returns results ranked by number of matching hints.
110
- * @param {string[]} hints — keywords from triage domainHints
111
- * @returns {RegistryEntry[]}
112
- */
113
- search(hints) {
114
- if (!hints?.length) return [];
115
-
116
- const lowerHints = hints.map(h => h.toLowerCase());
117
- const entries = Object.values(this._domains);
118
- const scored = [];
119
-
120
- for (const entry of entries) {
121
- const searchable = [
122
- entry.name || "",
123
- entry.description || "",
124
- ...(entry.tags || [])
125
- ].join(" ").toLowerCase();
126
-
127
- let score = 0;
128
- for (const hint of lowerHints) {
129
- if (searchable.includes(hint)) score++;
130
- }
131
-
132
- if (score > 0) {
133
- scored.push({ entry, score });
134
- }
135
- }
136
-
137
- scored.sort((a, b) => b.score - a.score);
138
- return scored.map(s => s.entry);
139
- }
140
- }