karajan-code 4.70.3 → 5.0.0

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