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.
- 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/ai-surface.js +9 -7
- package/src/checks/config-files.js +8 -7
- 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 -140
- package/src/cli/register-plan.js +9 -100
- 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 -148
- package/src/commands/go.js +76 -55
- package/src/commands/harden.js +105 -86
- 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 +75 -48
- package/src/commands/review-gate.js +422 -339
- 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 +94 -25
- package/src/config/loader.js +34 -17
- package/src/config/overrides.js +2 -1
- package/src/config/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/environment/board-access.js +11 -9
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/branch-protection.js +36 -3
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
- package/src/harden/sentinel/sentinel-lib.mjs +149 -23
- package/src/harden/sentinel/sentinel-shell.mjs +64 -0
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- package/src/harden/workflow-engine.js +12 -1
- 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 +15 -7
- 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 +44 -55
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +5 -200
- 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 +56 -43
- package/src/rag/bootstrap-index.js +28 -54
- package/src/rag/migrate.js +1 -1
- package/src/rag/onnx-fallback.js +2 -2
- package/src/rag/pid-lease.js +70 -0
- package/src/rag/project-store.js +2 -12
- package/src/review/card-first.js +57 -46
- package/src/review/dual-review.js +5 -4
- package/src/review/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +47 -0
- package/src/review/one-shot-review.js +51 -37
- package/src/review/publish-pr.js +18 -3
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +34 -3
- 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 +2 -26
- package/src/roles/audit-role.js +106 -125
- package/src/skills/atril-skills.js +5 -4
- 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/agent-home.js +33 -0
- 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
|
@@ -1,86 +1,75 @@
|
|
|
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
|
|
|
6
6
|
import { handleSuggestion } from "../suggest-handler.js";
|
|
7
|
+
import { runKjCommand } from "../run-kj.js";
|
|
7
8
|
import {
|
|
8
9
|
resolveProjectDir,
|
|
9
10
|
failPayload,
|
|
10
11
|
} from "../shared-helpers.js";
|
|
11
12
|
|
|
13
|
+
export const HU_STATUSES = ["pending", "running", "done", "failed", "skipped"];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* KJC-BUG-0452 (#2815): kj_hu used the old kj run store, so an agent saw an empty
|
|
17
|
+
* board while `kj hu list` showed every card. It runs the CLI's own `kj hu` in a
|
|
18
|
+
* subprocess: the same board (local, shared or a lane's), and stdout, which is
|
|
19
|
+
* this server's protocol channel, stays clean.
|
|
20
|
+
*/
|
|
21
|
+
async function kjHu(projectDir, args) {
|
|
22
|
+
const res = await runKjCommand({ command: "hu", commandArgs: [...args, "--json"], options: { projectDir } });
|
|
23
|
+
if (!res.ok) return { error: `kj hu ${args[0]} failed: ${res.errorSummary || res.stderr || "no output"}` };
|
|
24
|
+
const line = String(res.stdout || "").trim().split("\n").reverse().find((l) => /^[[{]/.test(l.trim()));
|
|
25
|
+
try { return { data: JSON.parse(line) }; } catch { return { error: `kj hu ${args[0]} answered no JSON: ${String(res.stdout || "").slice(0, 200)}` }; }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const notOnBoard = (id) => `HU ${id} is not on the board — kj_hu list shows its cards`;
|
|
29
|
+
|
|
30
|
+
async function createHu(projectDir, a) {
|
|
31
|
+
if (!a.title) return failPayload("Missing required field: title (required for create)");
|
|
32
|
+
const args = ["add", a.title, ...(a.acceptanceCriteria ? ["--ac", a.acceptanceCriteria] : []), ...(a.ref ? ["--ref", a.ref] : [])];
|
|
33
|
+
const added = await kjHu(projectDir, args);
|
|
34
|
+
if (added.error) return failPayload(added.error);
|
|
35
|
+
if (!a.status || a.status === "pending") return { ok: true, hu: added.data };
|
|
36
|
+
return moveHu(projectDir, added.data.short_id || added.data.id, a.status);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function moveHu(projectDir, huId, status) {
|
|
40
|
+
if (!HU_STATUSES.includes(status)) return failPayload(`Unknown status "${status}": use ${HU_STATUSES.join(", ")}`);
|
|
41
|
+
const moved = await kjHu(projectDir, ["move", huId, status]);
|
|
42
|
+
return moved.error ? failPayload(moved.error) : { ok: true, hu: moved.data };
|
|
43
|
+
}
|
|
44
|
+
|
|
12
45
|
export async function handleHu(a, server) {
|
|
13
46
|
const action = a.action;
|
|
14
47
|
if (!action) return failPayload("Missing required field: action");
|
|
15
|
-
|
|
16
48
|
const projectDir = await resolveProjectDir(server, a.projectDir);
|
|
17
|
-
const { createManualHu, listHus, getHu, updateHuStatus } = await import("../../hu/store.js");
|
|
18
49
|
|
|
19
50
|
switch (action) {
|
|
20
|
-
case "create":
|
|
21
|
-
|
|
22
|
-
const hu = await createManualHu(projectDir, {
|
|
23
|
-
title: a.title,
|
|
24
|
-
description: a.description,
|
|
25
|
-
status: a.status,
|
|
26
|
-
acceptanceCriteria: a.acceptanceCriteria
|
|
27
|
-
});
|
|
28
|
-
return { ok: true, hu };
|
|
29
|
-
}
|
|
51
|
+
case "create":
|
|
52
|
+
return createHu(projectDir, a);
|
|
30
53
|
case "list": {
|
|
31
|
-
const
|
|
32
|
-
return { ok: true, hus };
|
|
54
|
+
const listed = await kjHu(projectDir, ["list"]);
|
|
55
|
+
return listed.error ? failPayload(listed.error) : { ok: true, hus: listed.data };
|
|
33
56
|
}
|
|
34
57
|
case "get": {
|
|
35
58
|
if (!a.huId) return failPayload("Missing required field: huId (required for get)");
|
|
36
|
-
const
|
|
37
|
-
|
|
59
|
+
const listed = await kjHu(projectDir, ["list"]);
|
|
60
|
+
if (listed.error) return failPayload(listed.error);
|
|
61
|
+
const hu = listed.data.find((h) => h.id === a.huId || h.short_id === a.huId);
|
|
62
|
+
return hu ? { ok: true, hu } : failPayload(notOnBoard(a.huId));
|
|
38
63
|
}
|
|
39
|
-
case "update":
|
|
64
|
+
case "update":
|
|
40
65
|
if (!a.huId) return failPayload("Missing required field: huId (required for update)");
|
|
41
66
|
if (!a.status) return failPayload("Missing required field: status (required for update)");
|
|
42
|
-
|
|
43
|
-
return { ok: true, hu };
|
|
44
|
-
}
|
|
67
|
+
return moveHu(projectDir, a.huId, a.status);
|
|
45
68
|
default:
|
|
46
69
|
return failPayload(`Unknown hu action: ${action}`);
|
|
47
70
|
}
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
export async function handleSkills(a) {
|
|
51
|
-
const action = a.action;
|
|
52
|
-
if (!action) return failPayload("Missing required field: action");
|
|
53
|
-
|
|
54
|
-
const { isOpenSkillsAvailable, installSkill, removeSkill, listSkills, readSkill } =
|
|
55
|
-
await import("../../skills/openskills-client.js");
|
|
56
|
-
|
|
57
|
-
const opts = { projectDir: a.projectDir || null };
|
|
58
|
-
|
|
59
|
-
switch (action) {
|
|
60
|
-
case "install": {
|
|
61
|
-
if (!a.source) return failPayload("Missing required field: source (required for install)");
|
|
62
|
-
const available = await isOpenSkillsAvailable();
|
|
63
|
-
if (!available) {
|
|
64
|
-
return failPayload("OpenSkills CLI is not available. Install it with: npm install -g openskills");
|
|
65
|
-
}
|
|
66
|
-
return installSkill(a.source, { ...opts, global: a.global || false });
|
|
67
|
-
}
|
|
68
|
-
case "remove": {
|
|
69
|
-
if (!a.name) return failPayload("Missing required field: name (required for remove)");
|
|
70
|
-
return removeSkill(a.name, opts);
|
|
71
|
-
}
|
|
72
|
-
case "list": {
|
|
73
|
-
return listSkills(opts);
|
|
74
|
-
}
|
|
75
|
-
case "read": {
|
|
76
|
-
if (!a.name) return failPayload("Missing required field: name (required for read)");
|
|
77
|
-
return readSkill(a.name, opts);
|
|
78
|
-
}
|
|
79
|
-
default:
|
|
80
|
-
return failPayload(`Unknown skills action: ${action}`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
73
|
export async function handleSuggest(a) {
|
|
85
74
|
if (!a.suggestion) {
|
|
86
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
|
|
@@ -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),
|
package/src/mcp/tools.js
CHANGED
|
@@ -48,91 +48,6 @@ export const tools = [
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
-
{
|
|
52
|
-
name: "kj_run",
|
|
53
|
-
description:
|
|
54
|
-
"Run the full Karajan pipeline. IMPORTANT: Pass the user's task description exactly as they wrote it. Do NOT group, split, reorder, or modify tasks yourself. Karajan handles decomposition, role activation, iteration, and quality gates internally. Do NOT override pipeline parameters (enableHuReviewer, mode, methodology) unless the user explicitly requested it. If you have observations about the task, use kj_suggest instead.",
|
|
55
|
-
inputSchema: {
|
|
56
|
-
type: "object",
|
|
57
|
-
properties: {
|
|
58
|
-
task: { type: "string", description: "Task description for the coder (can include a Planning Game card ID like KJC-TSK-0042). Either `task` or `taskFile` is required." },
|
|
59
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md (or any text file) whose contents become the task description. Relative paths resolve against projectDir." },
|
|
60
|
-
plan: { type: "string", description: "Plan ID from kj_plan. Loads persisted plan context and skips researcher/architect/planner stages." },
|
|
61
|
-
projectDir: { type: "string", description: "Absolute path to the project directory. Required when KJ MCP server runs from a different directory than the target project." },
|
|
62
|
-
pgTask: { type: "string", description: "Planning Game card ID (e.g., KJC-TSK-0042). If provided, fetches full card details as task context and updates card status on completion." },
|
|
63
|
-
pgProject: { type: "string", description: "Planning Game project ID (e.g., 'Karajan Code'). Required when pgTask is used." },
|
|
64
|
-
planner: { type: "string" },
|
|
65
|
-
coder: { type: "string" },
|
|
66
|
-
reviewer: { type: "string" },
|
|
67
|
-
refactorer: { type: "string" },
|
|
68
|
-
plannerModel: { type: "string" },
|
|
69
|
-
coderModel: { type: "string" },
|
|
70
|
-
reviewerModel: { type: "string" },
|
|
71
|
-
refactorerModel: { type: "string" },
|
|
72
|
-
enablePlanner: { type: "boolean" },
|
|
73
|
-
enableReviewer: { type: "boolean" },
|
|
74
|
-
enableRefactorer: { type: "boolean" },
|
|
75
|
-
enableResearcher: { type: "boolean" },
|
|
76
|
-
enableTester: { type: "boolean" },
|
|
77
|
-
enableSecurity: { type: "boolean" },
|
|
78
|
-
enableImpeccable: { type: "boolean" },
|
|
79
|
-
enablePerf: { type: "boolean" },
|
|
80
|
-
enableTriage: { type: "boolean" },
|
|
81
|
-
enableDiscover: { type: "boolean" },
|
|
82
|
-
enableArchitect: { type: "boolean" },
|
|
83
|
-
enableHuReviewer: { type: "boolean" },
|
|
84
|
-
architectModel: { type: "string" },
|
|
85
|
-
huFile: { type: "string", description: "Path to YAML file with HU stories to certify before coding" },
|
|
86
|
-
enableSerena: { type: "boolean" },
|
|
87
|
-
enableCi: { type: "boolean", description: "Enable Karajan CI (early PR + dispatch comments/reviews)" },
|
|
88
|
-
reviewerFallback: { type: "string" },
|
|
89
|
-
reviewerRetries: { type: "number" },
|
|
90
|
-
mode: { type: "string" },
|
|
91
|
-
maxIterations: { type: "number" },
|
|
92
|
-
maxIterationMinutes: { type: "number" },
|
|
93
|
-
maxTotalMinutes: { type: "number" },
|
|
94
|
-
baseBranch: { type: "string" },
|
|
95
|
-
baseRef: { type: "string" },
|
|
96
|
-
methodology: { type: "string", enum: ["tdd", "standard"] },
|
|
97
|
-
autoCommit: { type: "boolean" },
|
|
98
|
-
autoPush: { type: "boolean" },
|
|
99
|
-
autoPr: { type: "boolean" },
|
|
100
|
-
autoRebase: { type: "boolean" },
|
|
101
|
-
branchPrefix: { type: "string" },
|
|
102
|
-
autoSimplify: { type: "boolean", description: "Auto-simplify pipeline for simple tasks (level trivial/simple). Disable with false to force full pipeline." },
|
|
103
|
-
smartModels: { type: "boolean", description: "Enable/disable smart model selection based on triage complexity" },
|
|
104
|
-
checkpointInterval: { type: "number", description: "Minutes between interactive checkpoints (default: 5). Set 0 to disable." },
|
|
105
|
-
taskType: { type: "string", enum: ["sw", "infra", "doc", "add-tests", "refactor"], description: "Explicit task type for policy resolution. Overrides triage classification." },
|
|
106
|
-
quiet: { type: "boolean", description: "Suppress raw agent output lines, show only stage status (default: true). Set false for verbose output." },
|
|
107
|
-
noSonar: { type: "boolean" },
|
|
108
|
-
design: { type: "boolean", description: "Activate design refactoring mode. Impeccable role applies design changes instead of just auditing." },
|
|
109
|
-
enableSonarcloud: { type: "boolean", description: "Enable SonarCloud scan (complementary to SonarQube)" },
|
|
110
|
-
kjHome: { type: "string" },
|
|
111
|
-
sonarToken: { type: "string" },
|
|
112
|
-
timeoutMs: { type: "number" },
|
|
113
|
-
domain: { type: "string", description: "Domain knowledge: inline text describing the project domain, or absolute path to a .md file. Auto-saved to .karajan/domains/ for the curator." },
|
|
114
|
-
brain: { type: "string", enum: ["on", "off"], description: "Brain decisor: on|off. Controls whether intent-driven routing overrides pipeline flags." },
|
|
115
|
-
forceRole: { type: "array", items: { type: "string" }, description: "Force roles ON regardless of triage (e.g. [\"security\"])" },
|
|
116
|
-
skipRole: { type: "array", items: { type: "string" }, description: "Force roles OFF regardless of triage (e.g. [\"tester\"])" },
|
|
117
|
-
specReviewMode: { type: "string", enum: ["auto", "skip"], description: "Pre-pipeline spec-reviewer behaviour (KJC-PCS-0048). `auto` (default): the role runs, findings stream to the client via progress events; the pipeline continues regardless. `skip`: bypass the reviewer entirely (mirrors the --skip-spec-review CLI flag)." }
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: "kj_resume",
|
|
123
|
-
description:
|
|
124
|
-
"Resume a paused, stopped, or failed session by ID. For paused sessions, provide an answer. For stopped/failed sessions, re-runs the flow from scratch. Sends real-time progress notifications via MCP logging.",
|
|
125
|
-
inputSchema: {
|
|
126
|
-
type: "object",
|
|
127
|
-
required: ["sessionId"],
|
|
128
|
-
properties: {
|
|
129
|
-
sessionId: { type: "string", description: "Session ID to resume" },
|
|
130
|
-
answer: { type: "string", description: "Answer to the question that caused the pause" },
|
|
131
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
132
|
-
kjHome: { type: "string" }
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
51
|
{
|
|
137
52
|
name: "kj_report",
|
|
138
53
|
description: "Read latest or list session reports. Use trace=true for chronological stage-by-stage breakdown with timing and token usage.",
|
|
@@ -176,7 +91,7 @@ export const tools = [
|
|
|
176
91
|
},
|
|
177
92
|
{
|
|
178
93
|
name: "kj_preflight",
|
|
179
|
-
description: "Confirm or adjust agent configuration before first
|
|
94
|
+
description: "Confirm or adjust agent configuration before first kj_code. REQUIRED before running any task via MCP. Show the config to the human, get their confirmation or adjustments, then call this tool with their response.",
|
|
180
95
|
inputSchema: {
|
|
181
96
|
type: "object",
|
|
182
97
|
required: ["humanResponse"],
|
|
@@ -207,50 +122,6 @@ export const tools = [
|
|
|
207
122
|
}
|
|
208
123
|
}
|
|
209
124
|
},
|
|
210
|
-
{
|
|
211
|
-
name: "kj_review",
|
|
212
|
-
description: "Run reviewer-only mode against current diff. Do NOT filter or pre-process the diff before passing it.",
|
|
213
|
-
inputSchema: {
|
|
214
|
-
type: "object",
|
|
215
|
-
properties: {
|
|
216
|
-
task: { type: "string", description: "Task description. Either `task` or `taskFile` is required." },
|
|
217
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
|
|
218
|
-
reviewer: { type: "string" },
|
|
219
|
-
reviewerModel: { type: "string" },
|
|
220
|
-
baseRef: { type: "string" },
|
|
221
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
222
|
-
kjHome: { type: "string" }
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
name: "kj_status",
|
|
228
|
-
description: "Show real-time status and log of the current or last Karajan run. Returns a parsed status (current stage, agent, iteration, errors) plus recent log lines. Use this to monitor progress while kj_run/kj_plan/kj_code is executing.",
|
|
229
|
-
inputSchema: {
|
|
230
|
-
type: "object",
|
|
231
|
-
properties: {
|
|
232
|
-
lines: { type: "number", description: "Number of log lines to show (default 50)" }
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
name: "kj_plan",
|
|
238
|
-
description: "Generate implementation plan for a task. Pass the task as the user described it. Karajan's planner decides the approach.",
|
|
239
|
-
inputSchema: {
|
|
240
|
-
type: "object",
|
|
241
|
-
properties: {
|
|
242
|
-
task: { type: "string", description: "Task description. Either `task` or `taskFile` is required." },
|
|
243
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
|
|
244
|
-
planner: { type: "string" },
|
|
245
|
-
plannerModel: { type: "string" },
|
|
246
|
-
coder: { type: "string", description: "Legacy alias for planner" },
|
|
247
|
-
coderModel: { type: "string", description: "Legacy alias for plannerModel" },
|
|
248
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
249
|
-
kjHome: { type: "string" },
|
|
250
|
-
specReviewMode: { type: "string", enum: ["auto", "skip"], description: "Pre-planner spec-reviewer behaviour (KJC-PCS-0048). `auto` (default): runs the reviewer, findings stream as progress, planner continues. `skip`: bypass entirely." }
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
125
|
{
|
|
255
126
|
name: "kj_discover",
|
|
256
127
|
description: "Analyze a task for gaps, ambiguities, and missing information before execution. Returns a verdict (ready/needs_validation) with structured gap list. Can read task details from Planning Game if pgTask is provided.",
|
|
@@ -268,46 +139,6 @@ export const tools = [
|
|
|
268
139
|
}
|
|
269
140
|
}
|
|
270
141
|
},
|
|
271
|
-
{
|
|
272
|
-
name: "kj_triage",
|
|
273
|
-
description: "Classify task complexity and recommend which pipeline roles to activate. Returns level (trivial/simple/medium/complex), taskType, recommended roles, and optional decomposition.",
|
|
274
|
-
inputSchema: {
|
|
275
|
-
type: "object",
|
|
276
|
-
properties: {
|
|
277
|
-
task: { type: "string", description: "Task description to classify. Either `task` or `taskFile` is required." },
|
|
278
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
|
|
279
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
280
|
-
kjHome: { type: "string" }
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
name: "kj_researcher",
|
|
286
|
-
description: "Research the codebase for a task. Identifies affected files, patterns, constraints, prior decisions, risks, and test coverage.",
|
|
287
|
-
inputSchema: {
|
|
288
|
-
type: "object",
|
|
289
|
-
properties: {
|
|
290
|
-
task: { type: "string", description: "Task description to research. Either `task` or `taskFile` is required." },
|
|
291
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
|
|
292
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
293
|
-
kjHome: { type: "string" }
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
name: "kj_architect",
|
|
299
|
-
description: "Design solution architecture for a task. Returns layers, patterns, data model, API contracts, tradeoffs, and a verdict (ready/needs_clarification).",
|
|
300
|
-
inputSchema: {
|
|
301
|
-
type: "object",
|
|
302
|
-
properties: {
|
|
303
|
-
task: { type: "string", description: "Task description to architect. Either `task` or `taskFile` is required." },
|
|
304
|
-
taskFile: { type: "string", description: "Alternative to `task`: path to a .md/text file." },
|
|
305
|
-
context: { type: "string", description: "Additional context (e.g., researcher output)" },
|
|
306
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" },
|
|
307
|
-
kjHome: { type: "string" }
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
142
|
{
|
|
312
143
|
name: "kj_audit",
|
|
313
144
|
description: "Analyze codebase health without modifying files. Returns findings across security, code quality, performance, architecture, and testing dimensions.",
|
|
@@ -335,17 +166,17 @@ export const tools = [
|
|
|
335
166
|
},
|
|
336
167
|
{
|
|
337
168
|
name: "kj_hu",
|
|
338
|
-
description: "Manage user stories (HUs) in the local
|
|
169
|
+
description: "Manage user stories (HUs) in the HU Board, the same board `kj hu` uses (local or shared)",
|
|
339
170
|
inputSchema: {
|
|
340
171
|
type: "object",
|
|
341
172
|
required: ["action"],
|
|
342
173
|
properties: {
|
|
343
174
|
action: { type: "string", enum: ["create", "update", "list", "get"], description: "Action to perform" },
|
|
344
175
|
title: { type: "string", description: "HU title (required for create)" },
|
|
345
|
-
|
|
346
|
-
|
|
176
|
+
acceptanceCriteria: { type: "string", description: "Acceptance criteria, one per line" },
|
|
177
|
+
ref: { type: "string", description: "Id of this card's replica in the external tracker (Planning Game, Jira, Linear...)" },
|
|
347
178
|
huId: { type: "string", description: "HU ID (required for update/get)" },
|
|
348
|
-
status: { type: "string", description: "HU status (for create/update)", enum: ["pending", "
|
|
179
|
+
status: { type: "string", description: "HU status (for create/update)", enum: ["pending", "running", "done", "failed", "skipped"] },
|
|
349
180
|
projectDir: { type: "string", description: "Project directory (defaults to cwd)" }
|
|
350
181
|
}
|
|
351
182
|
}
|
|
@@ -363,32 +194,6 @@ export const tools = [
|
|
|
363
194
|
}
|
|
364
195
|
}
|
|
365
196
|
},
|
|
366
|
-
{
|
|
367
|
-
name: "kj_skills",
|
|
368
|
-
description: "Manage OpenSkills for domain-specific agent knowledge. Install skills from the marketplace or GitHub repos to give coders domain expertise.",
|
|
369
|
-
inputSchema: {
|
|
370
|
-
type: "object",
|
|
371
|
-
properties: {
|
|
372
|
-
action: { type: "string", enum: ["install", "remove", "list", "read"], description: "Action to perform" },
|
|
373
|
-
source: { type: "string", description: "Skill source: marketplace name, GitHub URL, or local path (for install)" },
|
|
374
|
-
name: { type: "string", description: "Skill name (for remove/read)" },
|
|
375
|
-
global: { type: "boolean", description: "Install globally (~/.agent/skills/) instead of project-local" },
|
|
376
|
-
projectDir: { type: "string", description: "Project directory" }
|
|
377
|
-
},
|
|
378
|
-
required: ["action"]
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
name: "kj_undo",
|
|
383
|
-
description: "Revert the last pipeline run by resetting to the pre-pipeline commit. Default: soft reset (keeps changes staged). Use hard=true to discard all changes.",
|
|
384
|
-
inputSchema: {
|
|
385
|
-
type: "object",
|
|
386
|
-
properties: {
|
|
387
|
-
hard: { type: "boolean", description: "If true, discard all changes (git reset --hard). Default: false (soft reset, keeps changes staged)." },
|
|
388
|
-
projectDir: { type: "string", description: "Absolute path to the project directory" }
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
},
|
|
392
197
|
{
|
|
393
198
|
name: "kj_clean",
|
|
394
199
|
description: "Garbage-collect stale Karajan state: orphan plans (project dir no longer exists), finalised plans/sessions past their retention window, and HU story batches. Dry-run by default; pass yes=true to actually delete. Use nuke=true to wipe everything (retention=0 on every bucket + drop the HU board SQLite DB).",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #2566: a lane (<main>/.kj/worktrees/<x>, <main>/.claude/worktrees/<x>) kept plans under its own
|
|
3
|
+
* slug; `kj hu list` moves them to the main checkout's. A taken name is kept and reported.
|
|
4
|
+
*/
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { plansDir } from "./plan-store.js";
|
|
8
|
+
import { mainCheckout } from "../utils/main-checkout.js";
|
|
9
|
+
import { MIRROR_PLAN_ID } from "../hu/team-board-mirror.js";
|
|
10
|
+
|
|
11
|
+
const LANE_DIRS = [".kj_worktrees_", ".claude_worktrees_"];
|
|
12
|
+
|
|
13
|
+
// Never overwrites: "wx" and errorOnExist fail with EEXIST if another session wrote dest first.
|
|
14
|
+
async function moveEntry(from, dest, main) {
|
|
15
|
+
const plan = from.endsWith(".json") ? await fs.readFile(from, "utf8").then(JSON.parse, () => null) : null;
|
|
16
|
+
if (plan) {
|
|
17
|
+
// TSK-0341: the stamp must outlive the lane, or the GC sees the plan as orphan.
|
|
18
|
+
await fs.writeFile(dest, JSON.stringify({ ...plan, projectDir: main }, null, 2), { flag: "wx" });
|
|
19
|
+
return fs.unlink(from);
|
|
20
|
+
}
|
|
21
|
+
await fs.cp(from, dest, { recursive: true, force: false, errorOnExist: true });
|
|
22
|
+
return fs.rm(from, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function migrateLanePlans(projectDir) {
|
|
26
|
+
const [target, main] = [plansDir(projectDir), mainCheckout(projectDir)];
|
|
27
|
+
const root = path.dirname(target);
|
|
28
|
+
const prefixes = LANE_DIRS.map((d) => `${path.basename(target)}_${d}`); // the main checkout's slug
|
|
29
|
+
const moved = [];
|
|
30
|
+
const kept = [];
|
|
31
|
+
let entries;
|
|
32
|
+
try { entries = await fs.readdir(root, { withFileTypes: true }); } catch (err) {
|
|
33
|
+
if (err.code === "ENOENT") return { moved, kept };
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
const isLaneFolder = (e) => e.isDirectory() && prefixes.some((p) => e.name.startsWith(p));
|
|
37
|
+
for (const lane of entries.filter(isLaneFolder)) {
|
|
38
|
+
const from = path.join(root, lane.name);
|
|
39
|
+
await fs.mkdir(target, { recursive: true });
|
|
40
|
+
for (const file of await fs.readdir(from)) {
|
|
41
|
+
// The team board mirror is no plan: `kj hu list` rewrites it from GitHub, a lane's copy is stale.
|
|
42
|
+
if (file === `${MIRROR_PLAN_ID}.json`) { await fs.unlink(path.join(from, file)); continue; }
|
|
43
|
+
try {
|
|
44
|
+
await moveEntry(path.join(from, file), path.join(target, file), main);
|
|
45
|
+
moved.push(file);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err.code !== "EEXIST" && err.code !== "ERR_FS_CP_EEXIST") throw err;
|
|
48
|
+
kept.push(path.join(from, file));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
await fs.rmdir(from).catch((err) => { if (err.code !== "ENOTEMPTY") throw err; }); // a collision stays
|
|
52
|
+
}
|
|
53
|
+
return { moved, kept };
|
|
54
|
+
}
|
package/src/plan/plan-store.js
CHANGED
|
@@ -10,6 +10,7 @@ import { writeJsonAtomic } from "../utils/atomic-write.js";
|
|
|
10
10
|
import { resolveHome } from "../utils/paths.js";
|
|
11
11
|
import { getSharedPlansDir } from "../utils/shared-paths.js";
|
|
12
12
|
import { generatePlanId, normaliseAlias } from "./plan-id.js";
|
|
13
|
+
import { mainCheckout } from "../utils/main-checkout.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* A plan JSON file failed to parse — typically an interrupted write
|
|
@@ -51,7 +52,7 @@ export function getKjHome() {
|
|
|
51
52
|
/**
|
|
52
53
|
* Deterministic slug for a project path — stable across plan-store writes,
|
|
53
54
|
* HU-board syncs and board URL routing. Keep in lockstep with
|
|
54
|
-
* `packages/hu-board/src/sync.js::deriveProjectIdFromDir
|
|
55
|
+
* `packages/hu-board/src/sync.js::deriveProjectIdFromDir` (kj slugs the main checkout, #2566).
|
|
55
56
|
* @param {string} projectDir - absolute project path
|
|
56
57
|
* @returns {string}
|
|
57
58
|
*/
|
|
@@ -64,12 +65,13 @@ export function projectSlug(projectDir) {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
// KJC-TSK-1166: the board honours KJ_PLANS_DIR as its plans root; what kj writes must land
|
|
67
|
-
// in the same root, or the board shows none of it.
|
|
68
|
+
// in the same root, or the board shows none of it. #2566: one folder per main checkout, lanes included.
|
|
68
69
|
export function plansDir(projectDir) {
|
|
69
70
|
const root = process.env.KJ_PLANS_DIR || path.join(getKjHome(), "plans");
|
|
70
|
-
return path.join(root, projectSlug(projectDir));
|
|
71
|
+
return path.join(root, projectSlug(mainCheckout(projectDir)));
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
|
|
73
75
|
/**
|
|
74
76
|
* Save a plan to disk. Accepts both v1 and v2 schemas.
|
|
75
77
|
* @param {string} projectDir
|
|
@@ -88,7 +90,8 @@ export async function savePlan(projectDir, planResult) {
|
|
|
88
90
|
// plan so the GC can check `fs.exists(projectDir)` reliably. Reverse-
|
|
89
91
|
// engineering it from the slug is lossy (underscores in the original
|
|
90
92
|
// name collide with underscores introduced by slash-substitution).
|
|
91
|
-
|
|
93
|
+
// #2566: the main checkout, never a lane that is deleted after merge.
|
|
94
|
+
if (!planResult.projectDir && projectDir) planResult.projectDir = mainCheckout(projectDir);
|
|
92
95
|
// Humanización IDs: si el plan no tiene alias todavía, derívalo de
|
|
93
96
|
// plan.name (lo que el planner pidió al usuario). Resuelve
|
|
94
97
|
// colisiones con sufijo -2, -3… leyendo el dir antes.
|