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.
- package/README.md +2 -2
- package/package.json +6 -14
- package/packages/hu-board/package.json +1 -1
- package/packages/hu-board/public/app.js +4 -18
- package/packages/hu-board/public/index.html +5 -2
- package/packages/hu-board/public/styles.css +26 -0
- package/packages/hu-board/public/utils/api.js +0 -74
- package/packages/hu-board/public/utils/board-tour.js +62 -0
- package/packages/hu-board/public/utils/board-view.js +49 -144
- package/packages/hu-board/public/utils/command-launcher.js +8 -70
- package/packages/hu-board/public/utils/formatters.js +10 -0
- package/packages/hu-board/public/utils/governance-view.js +13 -1
- package/packages/hu-board/public/utils/hu-actions.js +17 -68
- package/packages/hu-board/public/utils/init-listeners.js +7 -8
- package/packages/hu-board/public/utils/log-panel.js +3 -16
- package/packages/hu-board/public/utils/maggle-mode.js +2 -12
- package/packages/hu-board/public/utils/modals.js +7 -0
- package/packages/hu-board/public/utils/project-picker-view.js +1 -1
- package/packages/hu-board/public/utils/server-push.js +3 -22
- package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
- package/packages/hu-board/public/utils/story-detail-view.js +5 -19
- package/packages/hu-board/src/cleanup-zombies.js +0 -1
- package/packages/hu-board/src/command-runner.js +36 -25
- package/packages/hu-board/src/db-connection.js +282 -0
- package/packages/hu-board/src/db-paths.js +113 -0
- package/packages/hu-board/src/db-queries.js +188 -0
- package/packages/hu-board/src/db-tombstones.js +51 -0
- package/packages/hu-board/src/db.js +28 -619
- package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
- package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
- package/packages/hu-board/src/plan-mutations.js +3 -153
- package/packages/hu-board/src/plans-service.js +55 -0
- package/packages/hu-board/src/routes/api/commands.js +122 -0
- package/packages/hu-board/src/routes/api/plans.js +55 -0
- package/packages/hu-board/src/routes/api/projects.js +267 -0
- package/packages/hu-board/src/routes/api/prompts.js +135 -0
- package/packages/hu-board/src/routes/api/sessions.js +95 -0
- package/packages/hu-board/src/routes/api/stories.js +183 -0
- package/packages/hu-board/src/routes/api/system.js +241 -0
- package/packages/hu-board/src/routes/api/tombstones.js +38 -0
- package/packages/hu-board/src/routes/api.js +24 -1371
- package/packages/hu-board/src/routes/governance.js +23 -1
- package/packages/hu-board/src/routes/lanes.js +40 -0
- package/packages/hu-board/src/routes/rag.js +4 -3
- package/packages/hu-board/src/server.js +20 -34
- package/packages/hu-board/src/sync-files.js +318 -0
- package/packages/hu-board/src/sync-project.js +99 -0
- package/packages/hu-board/src/sync.js +22 -566
- package/packages/hu-board/src/zombie-reaper.js +1 -1
- package/scripts/dual-publish.mjs +19 -3
- package/scripts/postinstall.js +15 -2
- package/scripts/verify-pack-mcp.mjs +11 -7
- package/scripts/verify-pack.mjs +4 -4
- package/src/audit/audit-history.js +3 -2
- package/src/audit/dead-exports.js +68 -59
- package/src/audit/deterministic-summary.js +33 -13
- package/src/audit/npm-signatures.js +41 -0
- package/src/audit/sbom.js +35 -0
- package/src/checks/agent-token.js +112 -0
- package/src/checks/dir-setup.js +34 -1
- package/src/checks/native-build.js +21 -39
- package/src/checks/runner.js +128 -142
- package/src/cli/advanced-commands.js +6 -6
- package/src/cli/register-meta.js +42 -82
- package/src/cli/register-pipeline.js +8 -143
- package/src/cli/register-plan.js +9 -100
- package/src/cli/register-roles-skills.js +1 -1
- package/src/cli/retired-commands.js +49 -0
- package/src/cli.js +18 -5
- package/src/commands/agent-run.js +40 -26
- package/src/commands/audit.js +127 -124
- package/src/commands/board.js +5 -9
- package/src/commands/check.js +29 -16
- package/src/commands/doctor.js +2 -0
- package/src/commands/env.js +176 -150
- package/src/commands/go.js +71 -53
- package/src/commands/harden.js +90 -81
- package/src/commands/hu-start.js +52 -0
- package/src/commands/hu.js +288 -221
- package/src/commands/identity.js +111 -78
- package/src/commands/init-atril.js +47 -0
- package/src/commands/init.js +11 -40
- package/src/commands/install-tools.js +70 -85
- package/src/commands/main-guard.js +78 -0
- package/src/commands/policy.js +226 -184
- package/src/commands/qmd.js +27 -21
- package/src/commands/rag.js +121 -55
- package/src/commands/review-gate.js +421 -341
- package/src/commands/skills.js +4 -1
- package/src/commands/start.js +4 -5
- package/src/commands/steward.js +96 -47
- package/src/commands/tournament.js +46 -37
- package/src/commands/worktree.js +107 -26
- package/src/config/defaults.js +1 -0
- package/src/config/loader.js +34 -17
- package/src/config/role-resolver.js +1 -0
- package/src/config/schema.js +1 -0
- package/src/config/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +64 -36
- package/src/harden/sentinel/sentinel-lib.mjs +129 -26
- package/src/harden/sentinel/sentinel-shell.mjs +5 -16
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- package/src/harden/workflow-templates.js +1 -1
- package/src/hu/board-lookup.js +29 -0
- package/src/hu/gh-identity.js +23 -0
- package/src/hu/github-board.js +4 -2
- package/src/hu/lane-prune.js +83 -13
- package/src/hu/lane-setup.js +65 -0
- package/src/hu/lanes.js +66 -0
- package/src/hu/team-board-mirror.js +3 -2
- package/src/infrastructure/command-runner.js +1 -1
- package/src/infrastructure/file-system-service.js +1 -1
- package/src/mcp/handlers/direct-handlers.js +2 -292
- package/src/mcp/handlers/hu-handlers.js +1 -35
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/handlers/rag-handler.js +9 -1
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +1 -196
- package/src/plan/lane-plans.js +54 -0
- package/src/plan/plan-store.js +7 -4
- package/src/policy/add.js +26 -12
- package/src/policy/adr-number-check.js +31 -0
- package/src/prompts/audit.js +299 -339
- package/src/prompts/card-context.js +10 -5
- package/src/prompts/reviewer.js +5 -2
- package/src/rag/auto-update.js +71 -44
- package/src/rag/bootstrap-index.js +46 -54
- package/src/rag/indexer.js +9 -4
- package/src/rag/migrate.js +1 -1
- package/src/rag/onnx-fallback.js +2 -2
- package/src/rag/pid-lease.js +181 -0
- package/src/rag/project-store.js +2 -12
- package/src/review/card-first.js +57 -46
- package/src/review/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +12 -4
- package/src/review/one-shot-review.js +45 -35
- package/src/review/publish-pr.js +14 -2
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +19 -4
- package/src/review/seal-commit.js +29 -0
- package/src/review/sonar-pregate.js +59 -44
- package/src/review/third-party-review.js +90 -16
- package/src/review/third-party-size.js +43 -0
- package/src/review/third-party-skills.js +54 -0
- package/src/review/verify-pr.js +1 -24
- package/src/roles/audit-role.js +106 -125
- package/src/skills/atril-cli.js +19 -1
- package/src/skills/atril-skills.js +5 -4
- package/src/skills/skills-search.js +72 -0
- package/src/skills/translate.js +62 -0
- package/src/sonar/scanner.js +116 -101
- package/src/steward/invariants.js +5 -4
- package/src/steward/phantom-sweep.js +66 -0
- package/src/tournament/judge.js +60 -53
- package/src/utils/gh-account.js +37 -0
- package/src/utils/git.js +0 -13
- package/src/utils/home-migration.js +7 -1
- package/src/utils/main-checkout.js +53 -0
- package/src/utils/qmd-collection.js +3 -1
- package/src/utils/welcome.js +3 -3
- package/templates/{skills → atril/commands}/kj-architect.md +5 -0
- package/templates/{skills → atril/commands}/kj-audit.md +5 -0
- package/templates/{skills → atril/commands}/kj-board.md +5 -0
- package/templates/{skills → atril/commands}/kj-code.md +5 -0
- package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
- package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
- package/templates/{skills → atril/commands}/kj-discover.md +5 -0
- package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
- package/templates/{skills → atril/commands}/kj-review.md +5 -0
- package/templates/{skills → atril/commands}/kj-security.md +5 -0
- package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
- package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
- package/templates/{skills → atril/commands}/kj-test.md +5 -0
- package/packages/hu-board/public/utils/run-launcher.js +0 -169
- package/packages/hu-board/src/run-tracker.js +0 -121
- package/src/activity-log.js +0 -59
- package/src/agents/host-agent.js +0 -38
- package/src/agents/model-registry.js +0 -142
- package/src/audit/plan-adherence.js +0 -224
- package/src/autonomy/arbiter-role.js +0 -71
- package/src/autonomy/arbiter.js +0 -22
- package/src/autonomy/decider.js +0 -18
- package/src/autonomy/decision-resolver.js +0 -58
- package/src/autonomy/outcome-report.js +0 -55
- package/src/autonomy/stage-ask.js +0 -30
- package/src/brain/decision-tracker.js +0 -125
- package/src/brain/decisor.js +0 -243
- package/src/brain/solomon-consult.js +0 -171
- package/src/brain/standby-scheduler.js +0 -8
- package/src/budget/comparison.js +0 -96
- package/src/canvas/parse-md.js +0 -238
- package/src/canvas/schema.js +0 -101
- package/src/canvas/to-flat.js +0 -85
- package/src/canvas/validate.js +0 -163
- package/src/ci/dispatch.js +0 -99
- package/src/ci/index.js +0 -3
- package/src/ci/pr-diff.js +0 -26
- package/src/cli/register-standby.js +0 -26
- package/src/commands/architect.js +0 -111
- package/src/commands/autorun.js +0 -49
- package/src/commands/researcher.js +0 -54
- package/src/commands/resume.js +0 -72
- package/src/commands/review.js +0 -89
- package/src/commands/run.js +0 -185
- package/src/commands/standby.js +0 -117
- package/src/commands/status.js +0 -36
- package/src/commands/triage.js +0 -78
- package/src/commands/undo.js +0 -62
- package/src/domains/domain-loader.js +0 -245
- package/src/domains/domain-registry.js +0 -140
- package/src/domains/domain-synthesizer.js +0 -129
- package/src/git/automation.js +0 -433
- package/src/git/coder-commit-guard.js +0 -40
- package/src/git/hu-automation.js +0 -243
- package/src/git/hu-snapshot.js +0 -10
- package/src/git/symlink-targets.js +0 -57
- package/src/golden/asserter.js +0 -92
- package/src/golden/loader.js +0 -52
- package/src/golden/runner.js +0 -92
- package/src/golden/schema.js +0 -41
- package/src/guards/duplicate-members.js +0 -86
- package/src/guards/intent-guard.js +0 -161
- package/src/guards/perf-guard.js +0 -126
- package/src/guards/policy-guard.js +0 -90
- package/src/guards/policy-resolver.js +0 -85
- package/src/guards/secret-redactor.js +0 -71
- package/src/hu/acceptance-runner.js +0 -138
- package/src/hu/lazy-planner.js +0 -109
- package/src/hu/parallel-executor.js +0 -94
- package/src/hu/routing-metrics.js +0 -17
- package/src/hu/split-validator.js +0 -143
- package/src/hu/splitting-detector.js +0 -158
- package/src/hu/splitting-generator.js +0 -175
- package/src/hu/store.js +0 -394
- package/src/infrastructure/mocks.js +0 -182
- package/src/mcp/handlers/run-handler.js +0 -318
- package/src/mcp/sovereignty-guard.js +0 -113
- package/src/mcp/tool-arg-normalizers.js +0 -16
- package/src/mutate/reviewer-signal.js +0 -76
- package/src/orchestrator/agent-fallback.js +0 -81
- package/src/orchestrator/brain-coordinator.js +0 -186
- package/src/orchestrator/ci-integration.js +0 -139
- package/src/orchestrator/config-init.js +0 -426
- package/src/orchestrator/direct-actions.js +0 -217
- package/src/orchestrator/drivers/error-recovery.js +0 -287
- package/src/orchestrator/drivers/init-context.js +0 -238
- package/src/orchestrator/drivers/iteration-loop.js +0 -382
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
- package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
- package/src/orchestrator/drivers/post-loop.js +0 -404
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
- package/src/orchestrator/drivers/pre-loop.js +0 -524
- package/src/orchestrator/drivers/run-hu-batch.js +0 -468
- package/src/orchestrator/feedback-enrichment.js +0 -140
- package/src/orchestrator/feedback-queue.js +0 -151
- package/src/orchestrator/flow-control.js +0 -170
- package/src/orchestrator/flow-runner.js +0 -365
- package/src/orchestrator/fs-leak-detector.js +0 -228
- package/src/orchestrator/hu-scheduler.js +0 -114
- package/src/orchestrator/hu-sub-pipeline.js +0 -642
- package/src/orchestrator/iteration-gate.js +0 -73
- package/src/orchestrator/iteration-stages.js +0 -9
- package/src/orchestrator/parallel-limiter.js +0 -74
- package/src/orchestrator/pipeline-context.js +0 -72
- package/src/orchestrator/post-loop-stages.js +0 -468
- package/src/orchestrator/pre-loop-stages.js +0 -11
- package/src/orchestrator/preflight-checks.js +0 -487
- package/src/orchestrator/repair/repair-detector.js +0 -117
- package/src/orchestrator/repair/repair-runner.js +0 -142
- package/src/orchestrator/reviewer-fallback.js +0 -45
- package/src/orchestrator/role-output-compressor.js +0 -189
- package/src/orchestrator/session-journal.js +0 -308
- package/src/orchestrator/solomon-escalation.js +0 -331
- package/src/orchestrator/solomon-rules.js +0 -212
- package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
- package/src/orchestrator/stages/architect-stage.js +0 -172
- package/src/orchestrator/stages/coder-stage.js +0 -506
- package/src/orchestrator/stages/domain-curator-stage.js +0 -82
- package/src/orchestrator/stages/format-stage.js +0 -61
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
- package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
- package/src/orchestrator/stages/perf-stage.js +0 -140
- package/src/orchestrator/stages/planner-stage.js +0 -85
- package/src/orchestrator/stages/rag-context-stage.js +0 -80
- package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
- package/src/orchestrator/stages/research-stage.js +0 -69
- package/src/orchestrator/stages/reviewer-stage.js +0 -431
- package/src/orchestrator/stages/sonar-stage.js +0 -439
- package/src/orchestrator/stages/stage-classes.js +0 -84
- package/src/orchestrator/stages/stage-executor.js +0 -155
- package/src/orchestrator/stages/suite-green-stage.js +0 -62
- package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
- package/src/orchestrator/stages/tool-judge-stage.js +0 -53
- package/src/orchestrator/stages/triage-stage.js +0 -172
- package/src/orchestrator/standby.js +0 -71
- package/src/orchestrator/verification-gate.js +0 -183
- package/src/orchestrator.js +0 -22
- package/src/plan/adr-generator.js +0 -170
- package/src/plan/adr-loader.js +0 -60
- package/src/plan/plan-executor.js +0 -100
- package/src/plan/plan-validation.js +0 -4
- package/src/prompts/acceptance-coverage.js +0 -32
- package/src/prompts/arbiter.js +0 -38
- package/src/prompts/architect.js +0 -103
- package/src/prompts/hu-reviewer.js +0 -244
- package/src/prompts/tool-correctness-judge.js +0 -31
- package/src/prompts/triage.js +0 -57
- package/src/rag/embedder.js +0 -2
- package/src/rag/embedders/_cloud-base.js +0 -2
- package/src/rag/embedders/cohere.js +0 -2
- package/src/rag/embedders/mistral.js +0 -2
- package/src/rag/embedders/onnx.js +0 -2
- package/src/rag/embedders/openai.js +0 -2
- package/src/rag/embedders/voyage.js +0 -2
- package/src/rag/rerank.js +0 -4
- package/src/rag/where-parser.js +0 -4
- package/src/repeat-detector.js +0 -88
- package/src/review/diff-generator.js +0 -112
- package/src/review/git-stash-helper.js +0 -104
- package/src/review/schema.js +0 -31
- package/src/review/scope-filter.js +0 -152
- package/src/review/snapshot-diff.js +0 -122
- package/src/review/tdd-discipline.js +0 -90
- package/src/review/tdd-policy.js +0 -69
- package/src/roles/acceptance-coverage-role.js +0 -78
- package/src/roles/architect-role.js +0 -77
- package/src/roles/coder-role.js +0 -113
- package/src/roles/commiter-role.js +0 -113
- package/src/roles/domain-curator-role.js +0 -134
- package/src/roles/hu-reviewer-role.js +0 -64
- package/src/roles/impeccable-role.js +0 -85
- package/src/roles/index.js +0 -18
- package/src/roles/karajan-brain-role.js +0 -134
- package/src/roles/perf-role.js +0 -122
- package/src/roles/planner-role.js +0 -151
- package/src/roles/refactorer-role.js +0 -30
- package/src/roles/repairer-role.js +0 -181
- package/src/roles/researcher-role.js +0 -70
- package/src/roles/reviewer-role.js +0 -115
- package/src/roles/security-role.js +0 -73
- package/src/roles/solomon-role.js +0 -271
- package/src/roles/sonar-role.js +0 -72
- package/src/roles/tester-role.js +0 -235
- package/src/roles/tool-correctness-judge-role.js +0 -78
- package/src/roles/triage-role.js +0 -99
- package/src/session/journal/decisions-writer.js +0 -200
- package/src/session/journal/iteration-logger.js +0 -194
- package/src/session/journal/summary-writer.js +0 -320
- package/src/session/journal/tree-writer.js +0 -164
- package/src/session/journal/write-all.js +0 -89
- package/src/session-cleanup.js +0 -116
- package/src/skills/semantic-detector.js +0 -167
- package/src/skills/skill-detector.js +0 -385
- package/src/sonar/cloud-scanner.js +0 -78
- package/src/tracker-bootstrap.js +0 -44
- package/src/types/index.js +0 -38
- package/src/types/policy.js +0 -43
- package/src/types/solomon.js +0 -87
- package/src/utils/async-lock.js +0 -31
- package/src/utils/budget.js +0 -229
- package/src/utils/cwd-confirm.js +0 -39
- package/src/utils/display/event-handlers.js +0 -403
- package/src/utils/display/formatters.js +0 -132
- package/src/utils/display/header.js +0 -47
- package/src/utils/display/session-summary.js +0 -118
- package/src/utils/display/solomon.js +0 -42
- package/src/utils/pricing.js +0 -29
- package/src/utils/quota-simulator.js +0 -56
- package/src/utils/role-assigner.js +0 -137
- package/src/utils/rtk-wrapper.js +0 -87
- package/src/utils/run-registry.js +0 -9
- package/src/utils/status-dashboard.js +0 -254
- package/src/utils/tool-call-extractor.js +0 -56
- package/src/webperf/devtools-detect.js +0 -112
- package/src/webperf/webperf-role-integration.js +0 -66
- package/templates/skills/kj-run.md +0 -73
package/src/hu/lanes.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KJC-TSK-1313: which card each worktree lane works on. Read from git every time, never stored on
|
|
3
|
+
* the card, so a lane removed by hand never lingers on the board.
|
|
4
|
+
*/
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The worktrees with a branch in `git worktree list --porcelain`. The first entry is the main
|
|
9
|
+
* checkout and is left out, as are detached worktrees. With `root`, only the lanes under it.
|
|
10
|
+
* @returns {{slug: string, branch: string, path: string}[]}
|
|
11
|
+
*/
|
|
12
|
+
export function parseLanes(porcelain, { root = null } = {}) {
|
|
13
|
+
const lanes = [];
|
|
14
|
+
let current = null;
|
|
15
|
+
let seen = 0;
|
|
16
|
+
for (const line of porcelain.split("\n")) {
|
|
17
|
+
if (line.startsWith("worktree ")) {
|
|
18
|
+
current = seen++ === 0 ? null : { path: line.slice(9).trim() };
|
|
19
|
+
} else if (line.startsWith("branch ") && current) {
|
|
20
|
+
lanes.push({ slug: path.basename(current.path), branch: line.slice(7).trim().replace(/^refs\/heads\//, ""), path: current.path });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return root ? lanes.filter((l) => l.path.startsWith(root + path.sep)) : lanes;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The lanes of each card: those whose branch carries the card id as a whole token (so HU-2 never
|
|
30
|
+
* claims HU-27). Cards without a lane have no entry.
|
|
31
|
+
* @returns {Map<string, {slug: string, branch: string, path: string}[]>}
|
|
32
|
+
*/
|
|
33
|
+
export function lanesByCard(lanes, cardIds) {
|
|
34
|
+
const byCard = new Map();
|
|
35
|
+
for (const id of new Set(cardIds)) {
|
|
36
|
+
const token = new RegExp(`(^|[^a-z0-9])${escapeRe(id)}($|[^a-z0-9])`, "i");
|
|
37
|
+
const hits = lanes.filter((l) => token.test(l.branch));
|
|
38
|
+
if (hits.length > 0) byCard.set(id, hits);
|
|
39
|
+
}
|
|
40
|
+
return byCard;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The cards a lane works on: those whose id or any of whose references (a tracker card, an
|
|
45
|
+
* issue) its branch names. `cards` are `{id, refs}`.
|
|
46
|
+
* @returns {string[]}
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* KJC-TSK-1316: one PR per branch from `gh pr list --json number,url,state,headRefName`: an open
|
|
50
|
+
* one wins, else the newest (a merged lane is what KJC-TSK-1314 warns about).
|
|
51
|
+
* @returns {Map<string, {number: number, url: string, state: string}>}
|
|
52
|
+
*/
|
|
53
|
+
export function prsByBranch(prs) {
|
|
54
|
+
const byBranch = new Map();
|
|
55
|
+
const open = (p) => (p.state === "OPEN" ? 1 : 0);
|
|
56
|
+
for (const p of prs) {
|
|
57
|
+
const cur = byBranch.get(p.headRefName);
|
|
58
|
+
if (!cur || open(p) > open(cur) || (open(p) === open(cur) && p.number > cur.number)) {
|
|
59
|
+
byBranch.set(p.headRefName, { number: p.number, url: p.url, state: p.state });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return byBranch;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const cardsOfLane = (lane, cards) =>
|
|
66
|
+
cards.filter((c) => lanesByCard([lane], [c.id, ...c.refs]).size > 0).map((c) => c.id);
|
|
@@ -19,10 +19,11 @@ export async function writeTeamMirror(projectDir, rows, { repo }) {
|
|
|
19
19
|
const plan = {
|
|
20
20
|
version: 2, planId: MIRROR_PLAN_ID, name: "github", alias: "github", projectDir,
|
|
21
21
|
task: `Shared HU Board: GitHub Issues of ${repo}`,
|
|
22
|
-
status: "ready", readonly: "github", createdAt: now,
|
|
22
|
+
status: "ready", readonly: "github", repo, createdAt: now,
|
|
23
23
|
hus: rows.map((r) => ({
|
|
24
24
|
id: r.short_id, short_id: r.short_id, title: r.title, status: r.status,
|
|
25
|
-
|
|
25
|
+
// KJC-BUG-0443: the tracker card it replicates too, so the gates find it by that reference.
|
|
26
|
+
claimed_by: r.claimed_by ?? null, created_by: "github", external_ref: [`${repo}#${r.number}`, r.ref].filter(Boolean).join(" · "),
|
|
26
27
|
acceptance_criteria: [], acceptance_tests: [], createdAt: now, updatedAt: now,
|
|
27
28
|
})),
|
|
28
29
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* This adapter preserves the runCommand API exactly, so current consumers
|
|
10
10
|
* can opt-in to DI without behavioural changes. A matching MockCommandRunner
|
|
11
|
-
* lives in
|
|
11
|
+
* lives in tests/support/infrastructure-mocks.js and lets tests script outputs per
|
|
12
12
|
* invocation.
|
|
13
13
|
*
|
|
14
14
|
* @typedef {Object} CommandRunResult
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* This adapter preserves the exact native API shapes for the handful of
|
|
9
9
|
* operations actually used in the codebase, so consumers can opt-in to DI
|
|
10
10
|
* without rewriting call sites. A matching MockFileSystem lives in
|
|
11
|
-
*
|
|
11
|
+
* tests/support/infrastructure-mocks.js.
|
|
12
12
|
*
|
|
13
13
|
* Scope for TSK-0316: intentionally minimal. Only the operations already used
|
|
14
14
|
* by orchestrator + agents. Additional methods added on demand.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Direct role handler logic (code,
|
|
3
|
-
*
|
|
2
|
+
* Direct role handler logic (code, audit, discover). KJC-TSK-1318: review,
|
|
3
|
+
* plan, triage, researcher and architect left with the kj run pipeline.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import fs from "node:fs/promises";
|
|
@@ -8,12 +8,7 @@ import { resolveRole } from "../../config.js";
|
|
|
8
8
|
import { createLogger } from "../../utils/logger.js";
|
|
9
9
|
import { assertAgentsAvailable } from "../../agents/availability.js";
|
|
10
10
|
import { createAgent } from "../../agents/index.js";
|
|
11
|
-
import { buildPlannerPrompt } from "../../prompts/planner.js";
|
|
12
11
|
import { buildCoderPrompt } from "../../prompts/coder.js";
|
|
13
|
-
import { buildReviewerPrompt } from "../../prompts/reviewer.js";
|
|
14
|
-
import { parseMaybeJsonString, agentAnswerText } from "../../review/parser.js";
|
|
15
|
-
import { computeBaseRef, generateDiff } from "../../review/diff-generator.js";
|
|
16
|
-
import { resolveReviewProfile } from "../../review/profiles.js";
|
|
17
12
|
import { createRunLog } from "../../utils/run-log.js";
|
|
18
13
|
import { createStallDetector } from "../../utils/stall-detector.js";
|
|
19
14
|
import { sendTrackerLog } from "../progress.js";
|
|
@@ -66,165 +61,6 @@ function applySessionOverrides(a, roleKeys) {
|
|
|
66
61
|
}
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
export async function handlePlanDirect(a, server, extra) {
|
|
70
|
-
// KJC-PCS-0048 PR 3b: same `specReviewMode: skip` → skipSpecReview
|
|
71
|
-
// mapping as kj_run. Default "auto" keeps the reviewer enabled.
|
|
72
|
-
if (a.specReviewMode === "skip") a.skipSpecReview = true;
|
|
73
|
-
const { normalizePlanArgs } = await import("../tool-arg-normalizers.js");
|
|
74
|
-
const options = normalizePlanArgs(a);
|
|
75
|
-
const config = await buildConfig(options, "plan");
|
|
76
|
-
const logger = createLogger(config.output.log_level, "mcp");
|
|
77
|
-
|
|
78
|
-
const plannerRole = resolveRole(config, "planner");
|
|
79
|
-
await assertAgentsAvailable([plannerRole.provider]);
|
|
80
|
-
|
|
81
|
-
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
82
|
-
await ensureTaskFromFile(a, projectDir);
|
|
83
|
-
const runLog = createRunLog(projectDir);
|
|
84
|
-
const silenceTimeoutMs = Number(config?.session?.max_agent_silence_minutes) > 0
|
|
85
|
-
? Math.round(Number(config.session.max_agent_silence_minutes) * 60 * 1000)
|
|
86
|
-
: undefined;
|
|
87
|
-
const plannerTimeoutMs = Number(config?.session?.max_planner_minutes) > 0
|
|
88
|
-
? Math.round(Number(config.session.max_planner_minutes) * 60 * 1000)
|
|
89
|
-
: undefined;
|
|
90
|
-
const silenceLabel = silenceTimeoutMs ? `${Math.round(silenceTimeoutMs / 1000)}s` : "disabled";
|
|
91
|
-
const runtimeLabel = plannerTimeoutMs ? `${Math.round(plannerTimeoutMs / 1000)}s` : "disabled";
|
|
92
|
-
runLog.logText(
|
|
93
|
-
`[kj_plan] started — provider=${plannerRole.provider}, max_silence=${silenceLabel}, max_runtime=${runtimeLabel}`
|
|
94
|
-
);
|
|
95
|
-
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
96
|
-
const eventBase = { sessionId: null, iteration: 0, startedAt: Date.now() };
|
|
97
|
-
|
|
98
|
-
// --- Phase 1: Researcher (codebase context) ---
|
|
99
|
-
let researchContext = null;
|
|
100
|
-
try {
|
|
101
|
-
const { ResearcherRole } = await import("../../roles/researcher-role.js");
|
|
102
|
-
const researcherRole = resolveRole(config, "researcher");
|
|
103
|
-
const researcherOnOutput = ({ stream, line }) => {
|
|
104
|
-
emitter.emit("progress", { type: "agent:output", stage: "researcher", message: line, detail: { stream, agent: researcherRole.provider } });
|
|
105
|
-
};
|
|
106
|
-
const researcherStall = createStallDetector({
|
|
107
|
-
onOutput: researcherOnOutput, emitter, eventBase, stage: "researcher", provider: researcherRole.provider
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
sendTrackerLog(server, "researcher", "running", researcherRole.provider);
|
|
111
|
-
runLog.logText(`[researcher] agent launched for plan context...`);
|
|
112
|
-
const researcher = new ResearcherRole({ config, logger, emitter });
|
|
113
|
-
await researcher.init({ task: a.task });
|
|
114
|
-
let researchOutput;
|
|
115
|
-
try {
|
|
116
|
-
researchOutput = await researcher.run({ task: a.task, onOutput: researcherStall.onOutput });
|
|
117
|
-
} finally {
|
|
118
|
-
researcherStall.stop();
|
|
119
|
-
}
|
|
120
|
-
if (researchOutput.ok) {
|
|
121
|
-
researchContext = researchOutput.result;
|
|
122
|
-
sendTrackerLog(server, "researcher", "done");
|
|
123
|
-
runLog.logText(`[researcher] completed — context available`);
|
|
124
|
-
} else {
|
|
125
|
-
sendTrackerLog(server, "researcher", "failed");
|
|
126
|
-
runLog.logText(`[researcher] failed: ${researchOutput.summary || "unknown"}`);
|
|
127
|
-
}
|
|
128
|
-
} catch (err) {
|
|
129
|
-
logger.warn(`Researcher phase skipped: ${err.message}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// --- Phase 2: Architect (solution design) ---
|
|
133
|
-
let architectContext = null;
|
|
134
|
-
try {
|
|
135
|
-
const { ArchitectRole } = await import("../../roles/architect-role.js");
|
|
136
|
-
const architectRole = resolveRole(config, "architect");
|
|
137
|
-
const architectOnOutput = ({ stream, line }) => {
|
|
138
|
-
emitter.emit("progress", { type: "agent:output", stage: "architect", message: line, detail: { stream, agent: architectRole.provider } });
|
|
139
|
-
};
|
|
140
|
-
const architectStall = createStallDetector({
|
|
141
|
-
onOutput: architectOnOutput, emitter, eventBase, stage: "architect", provider: architectRole.provider
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
sendTrackerLog(server, "architect", "running", architectRole.provider);
|
|
145
|
-
runLog.logText(`[architect] agent launched for plan context...`);
|
|
146
|
-
const architect = new ArchitectRole({ config, logger, emitter });
|
|
147
|
-
await architect.init({ task: a.task });
|
|
148
|
-
let architectOutput;
|
|
149
|
-
try {
|
|
150
|
-
architectOutput = await architect.run({ task: a.task, researchContext, onOutput: architectStall.onOutput });
|
|
151
|
-
} finally {
|
|
152
|
-
architectStall.stop();
|
|
153
|
-
}
|
|
154
|
-
if (architectOutput.ok) {
|
|
155
|
-
architectContext = architectOutput.result;
|
|
156
|
-
sendTrackerLog(server, "architect", "done");
|
|
157
|
-
runLog.logText(`[architect] completed — context available`);
|
|
158
|
-
} else {
|
|
159
|
-
sendTrackerLog(server, "architect", "failed");
|
|
160
|
-
runLog.logText(`[architect] failed: ${architectOutput.summary || "unknown"}`);
|
|
161
|
-
}
|
|
162
|
-
} catch (err) {
|
|
163
|
-
logger.warn(`Architect phase skipped: ${err.message}`);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// --- Phase 3: Planner (with research + architecture context) ---
|
|
167
|
-
const onOutput = ({ stream, line }) => {
|
|
168
|
-
emitter.emit("progress", { type: "agent:output", stage: "planner", message: line, detail: { stream, agent: plannerRole.provider } });
|
|
169
|
-
};
|
|
170
|
-
const stallDetector = createStallDetector({
|
|
171
|
-
onOutput, emitter, eventBase, stage: "planner", provider: plannerRole.provider
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const planner = createAgent(plannerRole.provider, config, logger);
|
|
175
|
-
const prompt = buildPlannerPrompt({ task: a.task, context: a.context, architectContext });
|
|
176
|
-
sendTrackerLog(server, "planner", "running", plannerRole.provider);
|
|
177
|
-
runLog.logText(`[planner] agent launched, waiting for response...`);
|
|
178
|
-
let result;
|
|
179
|
-
let plannerStats;
|
|
180
|
-
try {
|
|
181
|
-
result = await planner.runTask({
|
|
182
|
-
prompt,
|
|
183
|
-
role: "planner",
|
|
184
|
-
onOutput: stallDetector.onOutput,
|
|
185
|
-
silenceTimeoutMs,
|
|
186
|
-
timeoutMs: plannerTimeoutMs
|
|
187
|
-
});
|
|
188
|
-
} finally {
|
|
189
|
-
stallDetector.stop();
|
|
190
|
-
plannerStats = stallDetector.stats();
|
|
191
|
-
runLog.logText(
|
|
192
|
-
`[planner] finished — lines=${plannerStats.lineCount}, bytes=${plannerStats.bytesReceived}, elapsed=${Math.round(plannerStats.elapsedMs / 1000)}s`
|
|
193
|
-
);
|
|
194
|
-
runLog.close();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (!result.ok) {
|
|
198
|
-
sendTrackerLog(server, "planner", "failed");
|
|
199
|
-
const baseError = result.error || result.output || "Planner failed";
|
|
200
|
-
const statsSuffix = plannerStats
|
|
201
|
-
? ` [lines=${plannerStats.lineCount}, bytes=${plannerStats.bytesReceived}, elapsed=${Math.round(plannerStats.elapsedMs / 1000)}s]`
|
|
202
|
-
: "";
|
|
203
|
-
throw new Error(`${baseError}${statsSuffix}`);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
sendTrackerLog(server, "planner", "done");
|
|
207
|
-
const parsed = parseMaybeJsonString(result.output);
|
|
208
|
-
|
|
209
|
-
// --- Persist plan ---
|
|
210
|
-
let planId = null;
|
|
211
|
-
try {
|
|
212
|
-
const { savePlan } = await import("../../plan/plan-store.js");
|
|
213
|
-
planId = await savePlan(projectDir, {
|
|
214
|
-
task: a.task,
|
|
215
|
-
researchContext,
|
|
216
|
-
architectContext,
|
|
217
|
-
plan: parsed || result.output,
|
|
218
|
-
raw: result.output
|
|
219
|
-
});
|
|
220
|
-
runLog.logText(`[kj_plan] plan persisted — planId=${planId}`);
|
|
221
|
-
} catch (err) {
|
|
222
|
-
logger.warn(`Plan persistence failed (non-blocking): ${err.message}`);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return { ok: true, plan: parsed || result.output, raw: result.output, planId, researchContext, architectContext };
|
|
226
|
-
}
|
|
227
|
-
|
|
228
64
|
export async function handleCodeDirect(a, server, extra) {
|
|
229
65
|
const config = await buildConfig(a, "code");
|
|
230
66
|
await assertNotOnBaseBranch(config);
|
|
@@ -277,55 +113,6 @@ export async function handleCodeDirect(a, server, extra) {
|
|
|
277
113
|
return { ok: true, output: result.output, exitCode: result.exitCode };
|
|
278
114
|
}
|
|
279
115
|
|
|
280
|
-
export async function handleReviewDirect(a, server, extra) {
|
|
281
|
-
const config = await buildConfig(a, "review");
|
|
282
|
-
await assertNotOnBaseBranch(config);
|
|
283
|
-
const logger = createLogger(config.output.log_level, "mcp");
|
|
284
|
-
|
|
285
|
-
const reviewerRole = resolveRole(config, "reviewer");
|
|
286
|
-
await assertAgentsAvailable([reviewerRole.provider]);
|
|
287
|
-
|
|
288
|
-
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
289
|
-
await ensureTaskFromFile(a, projectDir);
|
|
290
|
-
const runLog = createRunLog(projectDir);
|
|
291
|
-
runLog.logText(`[kj_review] started — provider=${reviewerRole.provider}`);
|
|
292
|
-
const emitter = buildDirectEmitter(server, runLog, extra);
|
|
293
|
-
const eventBase = { sessionId: null, iteration: 0, startedAt: Date.now() };
|
|
294
|
-
const onOutput = ({ stream, line }) => {
|
|
295
|
-
emitter.emit("progress", { type: "agent:output", stage: "reviewer", message: line, detail: { stream, agent: reviewerRole.provider } });
|
|
296
|
-
};
|
|
297
|
-
const stallDetector = createStallDetector({
|
|
298
|
-
onOutput, emitter, eventBase, stage: "reviewer", provider: reviewerRole.provider
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
const reviewer = createAgent(reviewerRole.provider, config, logger);
|
|
302
|
-
const resolvedBase = await computeBaseRef({ baseBranch: config.base_branch, baseRef: a.baseRef });
|
|
303
|
-
const diff = await generateDiff({ baseRef: resolvedBase });
|
|
304
|
-
const { rules } = await resolveReviewProfile({ mode: config.review_mode, projectDir: process.cwd() });
|
|
305
|
-
|
|
306
|
-
const prompt = await buildReviewerPrompt({ task: a.task, diff, reviewRules: rules, mode: config.review_mode });
|
|
307
|
-
sendTrackerLog(server, "reviewer", "running", reviewerRole.provider);
|
|
308
|
-
runLog.logText(`[reviewer] agent launched, waiting for response...`);
|
|
309
|
-
let result;
|
|
310
|
-
try {
|
|
311
|
-
result = await reviewer.reviewTask({ prompt, role: "reviewer", onOutput: stallDetector.onOutput });
|
|
312
|
-
} finally {
|
|
313
|
-
stallDetector.stop();
|
|
314
|
-
const stats = stallDetector.stats();
|
|
315
|
-
runLog.logText(`[reviewer] finished — lines=${stats.lineCount}, bytes=${stats.bytesReceived}, elapsed=${Math.round(stats.elapsedMs / 1000)}s`);
|
|
316
|
-
runLog.close();
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (!result.ok) {
|
|
320
|
-
sendTrackerLog(server, "reviewer", "failed");
|
|
321
|
-
throw new Error(result.error || result.output || `Reviewer failed (exit ${result.exitCode})`);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
sendTrackerLog(server, "reviewer", "done");
|
|
325
|
-
const parsed = parseMaybeJsonString(agentAnswerText(result.output));
|
|
326
|
-
return { ok: true, review: parsed || result.output, raw: result.output };
|
|
327
|
-
}
|
|
328
|
-
|
|
329
116
|
export async function handleDiscoverDirect(a, server, extra) {
|
|
330
117
|
// Build context from pgTask if provided
|
|
331
118
|
let context = a.context || null;
|
|
@@ -350,34 +137,6 @@ export async function handleDiscoverDirect(a, server, extra) {
|
|
|
350
137
|
});
|
|
351
138
|
}
|
|
352
139
|
|
|
353
|
-
export async function handleTriageDirect(a, server, extra) {
|
|
354
|
-
return runDirectRole({
|
|
355
|
-
roleName: "triage",
|
|
356
|
-
importRole: async () => {
|
|
357
|
-
const { TriageRole } = await import("../../roles/triage-role.js");
|
|
358
|
-
return { RoleClass: TriageRole };
|
|
359
|
-
},
|
|
360
|
-
initContext: { task: a.task },
|
|
361
|
-
runInput: { task: a.task },
|
|
362
|
-
args: a, server, extra,
|
|
363
|
-
resolveProjectDir, buildConfig, buildDirectEmitter
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export async function handleResearcherDirect(a, server, extra) {
|
|
368
|
-
return runDirectRole({
|
|
369
|
-
roleName: "researcher",
|
|
370
|
-
importRole: async () => {
|
|
371
|
-
const { ResearcherRole } = await import("../../roles/researcher-role.js");
|
|
372
|
-
return { RoleClass: ResearcherRole };
|
|
373
|
-
},
|
|
374
|
-
initContext: { task: a.task },
|
|
375
|
-
runInput: { task: a.task },
|
|
376
|
-
args: a, server, extra,
|
|
377
|
-
resolveProjectDir, buildConfig, buildDirectEmitter
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
|
|
381
140
|
export async function handleAuditDirect(a, server, extra) {
|
|
382
141
|
const task = a.task || "Analyze the full codebase";
|
|
383
142
|
return runDirectRole({
|
|
@@ -394,20 +153,6 @@ export async function handleAuditDirect(a, server, extra) {
|
|
|
394
153
|
});
|
|
395
154
|
}
|
|
396
155
|
|
|
397
|
-
export async function handleArchitectDirect(a, server, extra) {
|
|
398
|
-
return runDirectRole({
|
|
399
|
-
roleName: "architect",
|
|
400
|
-
importRole: async () => {
|
|
401
|
-
const { ArchitectRole } = await import("../../roles/architect-role.js");
|
|
402
|
-
return { RoleClass: ArchitectRole };
|
|
403
|
-
},
|
|
404
|
-
initContext: { task: a.task },
|
|
405
|
-
runInput: { task: a.task, researchContext: a.context || null },
|
|
406
|
-
args: a, server, extra,
|
|
407
|
-
resolveProjectDir, buildConfig, buildDirectEmitter
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
156
|
export async function handleCode(a, server, extra) {
|
|
412
157
|
const missingTask = await requireTask(a, server);
|
|
413
158
|
if (missingTask) return missingTask;
|
|
@@ -422,20 +167,6 @@ export async function handleCode(a, server, extra) {
|
|
|
422
167
|
return handleCodeDirect(a, server, extra);
|
|
423
168
|
}
|
|
424
169
|
|
|
425
|
-
export async function handleReview(a, server, extra) {
|
|
426
|
-
const missingTask = await requireTask(a, server);
|
|
427
|
-
if (missingTask) return missingTask;
|
|
428
|
-
await runBootstrapGate(server, a);
|
|
429
|
-
return handleReviewDirect(a, server, extra);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
export async function handlePlan(a, server, extra) {
|
|
433
|
-
const missingTask = await requireTask(a, server);
|
|
434
|
-
if (missingTask) return missingTask;
|
|
435
|
-
await runBootstrapGate(server, a);
|
|
436
|
-
return handlePlanDirect(a, server, extra);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
170
|
export async function handleDiscover(a, server, extra) {
|
|
440
171
|
const missingTask = await requireTask(a, server);
|
|
441
172
|
if (missingTask) return missingTask;
|
|
@@ -447,27 +178,6 @@ export async function handleDiscover(a, server, extra) {
|
|
|
447
178
|
return handleDiscoverDirect(a, server, extra);
|
|
448
179
|
}
|
|
449
180
|
|
|
450
|
-
export async function handleTriage(a, server, extra) {
|
|
451
|
-
const missingTask = await requireTask(a, server);
|
|
452
|
-
if (missingTask) return missingTask;
|
|
453
|
-
await runBootstrapGate(server, a);
|
|
454
|
-
return handleTriageDirect(a, server, extra);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export async function handleResearcher(a, server, extra) {
|
|
458
|
-
const missingTask = await requireTask(a, server);
|
|
459
|
-
if (missingTask) return missingTask;
|
|
460
|
-
await runBootstrapGate(server, a);
|
|
461
|
-
return handleResearcherDirect(a, server, extra);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
export async function handleArchitect(a, server, extra) {
|
|
465
|
-
const missingTask = await requireTask(a, server);
|
|
466
|
-
if (missingTask) return missingTask;
|
|
467
|
-
await runBootstrapGate(server, a);
|
|
468
|
-
return handleArchitectDirect(a, server, extra);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
181
|
export async function handleAudit(a, server, extra) {
|
|
472
182
|
await runBootstrapGate(server, a);
|
|
473
183
|
const result = await handleAuditDirect(a, server, extra);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HU
|
|
2
|
+
* HU and Suggest handler logic (skills moved to `atril mcp`, ADR 0021).
|
|
3
3
|
* Extracted from server-handlers.js for maintainability.
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -70,40 +70,6 @@ export async function handleHu(a, server) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
export async function handleSkills(a) {
|
|
74
|
-
const action = a.action;
|
|
75
|
-
if (!action) return failPayload("Missing required field: action");
|
|
76
|
-
|
|
77
|
-
const { isOpenSkillsAvailable, installSkill, removeSkill, listSkills, readSkill } =
|
|
78
|
-
await import("../../skills/openskills-client.js");
|
|
79
|
-
|
|
80
|
-
const opts = { projectDir: a.projectDir || null };
|
|
81
|
-
|
|
82
|
-
switch (action) {
|
|
83
|
-
case "install": {
|
|
84
|
-
if (!a.source) return failPayload("Missing required field: source (required for install)");
|
|
85
|
-
const available = await isOpenSkillsAvailable();
|
|
86
|
-
if (!available) {
|
|
87
|
-
return failPayload("OpenSkills CLI is not available. Install it with: npm install -g openskills");
|
|
88
|
-
}
|
|
89
|
-
return installSkill(a.source, { ...opts, global: a.global || false });
|
|
90
|
-
}
|
|
91
|
-
case "remove": {
|
|
92
|
-
if (!a.name) return failPayload("Missing required field: name (required for remove)");
|
|
93
|
-
return removeSkill(a.name, opts);
|
|
94
|
-
}
|
|
95
|
-
case "list": {
|
|
96
|
-
return listSkills(opts);
|
|
97
|
-
}
|
|
98
|
-
case "read": {
|
|
99
|
-
if (!a.name) return failPayload("Missing required field: name (required for read)");
|
|
100
|
-
return readSkill(a.name, opts);
|
|
101
|
-
}
|
|
102
|
-
default:
|
|
103
|
-
return failPayload(`Unknown skills action: ${action}`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
73
|
export async function handleSuggest(a) {
|
|
108
74
|
if (!a.suggestion) {
|
|
109
75
|
return failPayload("Missing required field: suggestion");
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Management handler logic (init, doctor, config, scan, report, roles, agents, preflight,
|
|
3
|
-
*
|
|
2
|
+
* Management handler logic (init, doctor, config, scan, report, roles, agents, preflight, board, clean).
|
|
3
|
+
* KJC-TSK-1318: status and undo left with the kj run pipeline.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { runKjCommand } from "../run-kj.js";
|
|
7
7
|
import { loadConfig } from "../../config.js";
|
|
8
|
-
import { readRunLog } from "../../utils/run-log.js";
|
|
9
8
|
import { ackPreflight, getSessionOverrides } from "../preflight.js";
|
|
10
9
|
import { ensureBootstrap } from "../../bootstrap.js";
|
|
11
10
|
import {
|
|
@@ -14,8 +13,6 @@ import {
|
|
|
14
13
|
responseText,
|
|
15
14
|
buildConfig,
|
|
16
15
|
} from "../shared-helpers.js";
|
|
17
|
-
import { buildDashboardJson } from "../../utils/status-dashboard.js";
|
|
18
|
-
import { loadMostRecentSession } from "../../session/store.js";
|
|
19
16
|
import { escapeRegExp } from "../../utils/escape-regexp.js";
|
|
20
17
|
|
|
21
18
|
const AGENT_ROLES = new Set(["coder", "reviewer", "tester", "security", "solomon"]);
|
|
@@ -29,31 +26,6 @@ async function runBootstrapGate(server, a) {
|
|
|
29
26
|
await ensureBootstrap(projectDir, config);
|
|
30
27
|
}
|
|
31
28
|
|
|
32
|
-
export async function handleStatus(a, server) {
|
|
33
|
-
const maxLines = a.lines || 50;
|
|
34
|
-
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
35
|
-
const logResult = readRunLog(projectDir, maxLines);
|
|
36
|
-
|
|
37
|
-
// Enrich with dashboard data when possible
|
|
38
|
-
try {
|
|
39
|
-
const session = await loadMostRecentSession();
|
|
40
|
-
const stories = [];
|
|
41
|
-
if (session) {
|
|
42
|
-
try {
|
|
43
|
-
const { loadHuBatch } = await import("../../hu/store.js");
|
|
44
|
-
const batch = await loadHuBatch(session.id);
|
|
45
|
-
if (batch?.stories) stories.push(...batch.stories);
|
|
46
|
-
} catch { /* no HU batch for this session */ }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const dashboard = buildDashboardJson(session, logResult.lines || [], { stories });
|
|
50
|
-
return { ...logResult, dashboard };
|
|
51
|
-
} catch {
|
|
52
|
-
// Fallback: return raw log without dashboard
|
|
53
|
-
return logResult;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
29
|
export async function handleAgents(a) {
|
|
58
30
|
const action = a.action || "list";
|
|
59
31
|
if (action === "set") {
|
|
@@ -190,18 +162,6 @@ export async function handleBoard(a) {
|
|
|
190
162
|
}
|
|
191
163
|
}
|
|
192
164
|
|
|
193
|
-
export async function handleUndo(a, server) {
|
|
194
|
-
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
195
|
-
const origCwd = process.cwd();
|
|
196
|
-
try {
|
|
197
|
-
process.chdir(projectDir);
|
|
198
|
-
const { undoCommand } = await import("../../commands/undo.js");
|
|
199
|
-
return undoCommand({ hard: !!a.hard });
|
|
200
|
-
} finally {
|
|
201
|
-
process.chdir(origCwd);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
165
|
/**
|
|
206
166
|
* Garbage-collect stale Karajan state. Routed here (not through the
|
|
207
167
|
* generic `runKjCommand`) because the user needs a structured result
|
|
@@ -10,6 +10,7 @@ import { indexProject } from "../../rag/indexer.js";
|
|
|
10
10
|
import { ragExclude } from "../../rag/indexable.js";
|
|
11
11
|
import { query } from "../../rag/retriever.js";
|
|
12
12
|
import { pathNamedHits, withPathNamedHits } from "../../rag/path-hits.js";
|
|
13
|
+
import { claimLease, indexLeasePath, releaseLease } from "../../rag/pid-lease.js";
|
|
13
14
|
import { getKarajanHome } from "../../utils/paths.js";
|
|
14
15
|
import { resolveProjectDir, buildConfig, responseText, failPayload } from "../shared-helpers.js";
|
|
15
16
|
|
|
@@ -56,7 +57,11 @@ export async function handleRagIndex(args, server) {
|
|
|
56
57
|
const projectDir = await resolveProjectDir(server, args?.projectDir);
|
|
57
58
|
const config = await buildConfig({ ...args, projectDir }, "rag-index");
|
|
58
59
|
const db = openProjectStore({ projectDir, dim: config?.rag?.embedder?.dim || 768 });
|
|
60
|
+
// HU-2907: the long-lived host holds the machine lease for the walk and releases it in the finally.
|
|
61
|
+
const lease = indexLeasePath();
|
|
62
|
+
let claim;
|
|
59
63
|
try {
|
|
64
|
+
claim = claimLease(lease, { projectDir, slug: projectSlug(projectDir) });
|
|
60
65
|
const totals = await indexProject(projectDir, {
|
|
61
66
|
db, embedder: makeGovernedEmbedder(config),
|
|
62
67
|
karajanHome: getKarajanHome(), logger: silentLogger,
|
|
@@ -64,7 +69,10 @@ export async function handleRagIndex(args, server) {
|
|
|
64
69
|
exclude: ragExclude(config), // KJC-TSK-0891
|
|
65
70
|
});
|
|
66
71
|
return responseText(totals);
|
|
67
|
-
} finally {
|
|
72
|
+
} finally {
|
|
73
|
+
if (claim?.claimed) releaseLease(lease);
|
|
74
|
+
db.close();
|
|
75
|
+
}
|
|
68
76
|
} catch (err) {
|
|
69
77
|
return failPayload(`kj_rag_index failed: ${err.message}`);
|
|
70
78
|
}
|
|
@@ -20,32 +20,35 @@ export {
|
|
|
20
20
|
} from "./shared-helpers.js";
|
|
21
21
|
|
|
22
22
|
// ── Sub-module re-exports ────────────────────────────────────────────
|
|
23
|
-
export {
|
|
24
|
-
export {
|
|
25
|
-
export {
|
|
26
|
-
export { handleHu, handleSkills, handleSuggest } from "./handlers/hu-handlers.js";
|
|
23
|
+
export { handleCodeDirect, handleDiscoverDirect, handleAuditDirect, handleCode, handleDiscover, handleAudit } from "./handlers/direct-handlers.js";
|
|
24
|
+
export { handleAgents, handlePreflight, handleRoles, handleReport, handleInit, handleDoctor, handleConfig, handleScan, handleBoard, handleClean, buildPreflightRequiredResponse } from "./handlers/management-handlers.js";
|
|
25
|
+
export { handleHu, handleSuggest } from "./handlers/hu-handlers.js";
|
|
27
26
|
|
|
28
27
|
// ── Handler dispatch ─────────────────────────────────────────────────
|
|
29
28
|
|
|
30
29
|
import { asObject, failPayload } from "./shared-helpers.js";
|
|
31
|
-
import {
|
|
30
|
+
import { handleCode, handleDiscover, handleAudit } from "./handlers/direct-handlers.js";
|
|
32
31
|
import {
|
|
33
|
-
|
|
34
|
-
handleTriage, handleResearcher, handleArchitect, handleAudit
|
|
35
|
-
} from "./handlers/direct-handlers.js";
|
|
36
|
-
import {
|
|
37
|
-
handleStatus, handleAgents, handlePreflight, handleRoles,
|
|
32
|
+
handleAgents, handlePreflight, handleRoles,
|
|
38
33
|
handleReport, handleInit, handleDoctor, handleConfig,
|
|
39
|
-
handleScan, handleBoard,
|
|
34
|
+
handleScan, handleBoard, handleClean
|
|
40
35
|
} from "./handlers/management-handlers.js";
|
|
41
|
-
import {
|
|
36
|
+
import { retiredMessage } from "../cli/retired-commands.js";
|
|
37
|
+
|
|
38
|
+
// KJC-TSK-1318: the tools of the kj run pipeline, retired in 5.0 with their
|
|
39
|
+
// commands; a call answers with the same notice and starts nothing.
|
|
40
|
+
const RETIRED_TOOLS = {
|
|
41
|
+
kj_run: "run", kj_resume: "resume", kj_plan: "plan generate", kj_status: "status", kj_undo: "undo",
|
|
42
|
+
kj_triage: "triage", kj_researcher: "researcher", kj_architect: "architect", kj_review: "review",
|
|
43
|
+
};
|
|
44
|
+
import { handleHu, handleSuggest } from "./handlers/hu-handlers.js";
|
|
42
45
|
import { handleRagQuery, handleRagIndex } from "./handlers/rag-handler.js";
|
|
43
46
|
import { withKarajanHome } from "../utils/paths.js";
|
|
44
47
|
|
|
45
48
|
export async function handleToolCall(name, args, server, extra) {
|
|
49
|
+
if (Object.hasOwn(RETIRED_TOOLS, name)) return failPayload(retiredMessage(RETIRED_TOOLS[name]));
|
|
46
50
|
const a = asObject(args);
|
|
47
51
|
const handler = {
|
|
48
|
-
kj_status: (a, server) => handleStatus(a, server),
|
|
49
52
|
kj_init: (a) => handleInit(a),
|
|
50
53
|
kj_doctor: (a) => handleDoctor(a),
|
|
51
54
|
kj_agents: (a) => handleAgents(a),
|
|
@@ -54,21 +57,12 @@ export async function handleToolCall(name, args, server, extra) {
|
|
|
54
57
|
kj_scan: (a, server) => handleScan(a, server),
|
|
55
58
|
kj_roles: (a) => handleRoles(a),
|
|
56
59
|
kj_report: (a) => handleReport(a),
|
|
57
|
-
kj_resume: (a, server, extra) => handleResume(a, server, extra),
|
|
58
|
-
kj_run: (a, server, extra) => handleRun(a, server, extra),
|
|
59
60
|
kj_code: (a, server, extra) => handleCode(a, server, extra),
|
|
60
|
-
kj_review: (a, server, extra) => handleReview(a, server, extra),
|
|
61
|
-
kj_plan: (a, server, extra) => handlePlan(a, server, extra),
|
|
62
61
|
kj_discover: (a, server, extra) => handleDiscover(a, server, extra),
|
|
63
|
-
kj_triage: (a, server, extra) => handleTriage(a, server, extra),
|
|
64
|
-
kj_researcher: (a, server, extra) => handleResearcher(a, server, extra),
|
|
65
|
-
kj_architect: (a, server, extra) => handleArchitect(a, server, extra),
|
|
66
62
|
kj_audit: (a, server, extra) => handleAudit(a, server, extra),
|
|
67
63
|
kj_board: (a) => handleBoard(a),
|
|
68
64
|
kj_hu: (a, server) => handleHu(a, server),
|
|
69
65
|
kj_suggest: (a) => handleSuggest(a),
|
|
70
|
-
kj_skills: (a) => handleSkills(a),
|
|
71
|
-
kj_undo: (a, server) => handleUndo(a, server),
|
|
72
66
|
kj_clean: (a) => handleClean(a),
|
|
73
67
|
kj_rag_query: (a, server) => handleRagQuery(a, server),
|
|
74
68
|
kj_rag_index: (a, server) => handleRagIndex(a, server),
|