karajan-code 4.70.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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 +75 -48
- package/src/commands/review-gate.js +421 -341
- 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/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 +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 +1 -35
- package/src/mcp/handlers/management-handlers.js +2 -42
- 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 +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/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-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/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/commands/env.js
CHANGED
|
@@ -51,15 +51,14 @@ export function briefCommand({ config = null, flags = {}, role = null }) {
|
|
|
51
51
|
return { role, brief: text };
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// choice persists so it is only ever asked once.
|
|
54
|
+
/**
|
|
55
|
+
* KJC-TSK-0709 — the board is chosen BEFORE the playbook renders (its
|
|
56
|
+
* tracking line depends on the backend): interactive installs ask when
|
|
57
|
+
* alternatives are reachable, headless installs name the default. The
|
|
58
|
+
* choice persists so it is only ever asked once.
|
|
59
|
+
* @returns {Promise<object>} the config with the effective backend
|
|
60
|
+
*/
|
|
61
|
+
async function withChosenBoard(config, projectDir) {
|
|
63
62
|
try {
|
|
64
63
|
const wizard = process.stdin.isTTY && process.stdout.isTTY ? createWizard() : null;
|
|
65
64
|
const sel = await pickStateBackend({ projectDir, wizard, isTTY: Boolean(wizard), logger: console });
|
|
@@ -67,10 +66,151 @@ export async function envInstallCommand({ config = null, logger = null, flags =
|
|
|
67
66
|
// The effective backend feeds the render on EVERY non-error path —
|
|
68
67
|
// chosen, declared-in-file or default — so the playbook never falls
|
|
69
68
|
// back to hu-board while the selection said otherwise.
|
|
70
|
-
|
|
69
|
+
return { ...config, state_backend: sel.backend, board: sel.boardName ? { ...config?.board, name: sel.boardName } : config?.board };
|
|
71
70
|
} catch (err) {
|
|
72
71
|
console.log(`⚠ board selection failed (${err.message}) — continuing with the configured default`);
|
|
72
|
+
return config;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Stops the install with a pending block (exit 3): the playbook stays installed. */
|
|
77
|
+
function pend(result, items, opts) {
|
|
78
|
+
result.exitCode = PENDING_EXIT_CODE;
|
|
79
|
+
const block = renderPendingBlock(items, opts);
|
|
80
|
+
console.log(block);
|
|
81
|
+
return block;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* KJC-TSK-0685 (user rule): Karajan does not run without a board — it is
|
|
86
|
+
* what guarantees ordered, card-first work. Verify an OPERATIONAL access
|
|
87
|
+
* path to the declared backend BEFORE anything else; no path → block
|
|
88
|
+
* (exit 3) with the exact steps. The playbook stays installed.
|
|
89
|
+
* @returns {boolean} true when the install must stop
|
|
90
|
+
*/
|
|
91
|
+
function boardBlocked(result, config, projectDir) {
|
|
92
|
+
const access = verifyBoardAccess({ config, projectDir });
|
|
93
|
+
if (access.ok) {
|
|
94
|
+
if (access.backend !== "hu-board") console.log(`✓ board access verified: ${access.via}`);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
result.boardError = access.needed.join(" | ");
|
|
98
|
+
pend(result,
|
|
99
|
+
[{ tool: `${access.name || access.backend} board`, action: "needs-user", reason: `Karajan does not run without a board. To use ${access.name || access.backend}: ${access.needed.join(" ")}` }],
|
|
100
|
+
{ retry: "kj env install" });
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* KJC-BUG-0133 — installing IS activating. The setup flow used to order
|
|
106
|
+
* harden + the verdict gate as TEXT steps the agent runs (or narrates);
|
|
107
|
+
* a session that skipped them got a decorative method — field case
|
|
108
|
+
* 2026-08-02: installed karajan, then wrote everything by hand with
|
|
109
|
+
* nothing to stop it. env install now does them itself, idempotently.
|
|
110
|
+
* @returns {Promise<boolean>} true when the install must stop
|
|
111
|
+
*/
|
|
112
|
+
async function enforcementBlocked(result, config, projectDir) {
|
|
113
|
+
if (!existsSync(join(projectDir, ".git"))) {
|
|
114
|
+
pend(result,
|
|
115
|
+
[{ tool: "git", action: "needs-user", reason: "the enforcement gates live in git hooks — run `git init` (Karajan's guarantees do not exist without git)" }],
|
|
116
|
+
{ retry: "kj env install" });
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const h = await hardenCommand({ projectDir, logger: console });
|
|
121
|
+
if (h?.ok === false) throw new Error(h.error || "kj harden failed");
|
|
122
|
+
// KJC-BUG-0188: a headless harden never binds an identity by itself, and
|
|
123
|
+
// it must not. Blocking here beats the Sentinel denying every git and gh
|
|
124
|
+
// call later, with nothing on screen tying that back to this install.
|
|
125
|
+
if (h?.identityPending) {
|
|
126
|
+
result.pendingBlock = pend(result,
|
|
127
|
+
[{ tool: "identity", action: "needs-user", reason: h.identityPending, command: h.identityCommand }],
|
|
128
|
+
{ retry: "kj env install", why: "this clone has no declared identity, and kj never binds one on its own" });
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
const gate = await reviewGateCommand({ config, flags: { installGate: true } });
|
|
132
|
+
// KJC-BUG-0447: a gate no hook runs is decorative; never call it active.
|
|
133
|
+
if (!gate?.enforced) throw new Error("the review gate is declared but no pre-commit hook runs it");
|
|
134
|
+
console.log("✓ enforcement active: git hooks + cross-AI verdict gate — a commit outside the method is rejected, not narrated");
|
|
135
|
+
return false;
|
|
136
|
+
} catch (err) {
|
|
137
|
+
pend(result,
|
|
138
|
+
[{ tool: "enforcement", action: "needs-user", reason: `hooks/gate could not be installed: ${err.message} — without them the method is narratable` }],
|
|
139
|
+
{ retry: "kj env install" });
|
|
140
|
+
return true;
|
|
73
141
|
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* KJC-TSK-0683: on limited machines (no Ollama, no Docker) the DEFAULT
|
|
146
|
+
* provider falls back to the built-in ONNX embedder instead of blocking.
|
|
147
|
+
* Only for the first index and only when the user didn't pick a provider
|
|
148
|
+
* explicitly — the election is persisted (dims differ, it must stick).
|
|
149
|
+
*/
|
|
150
|
+
async function tryOnnxFallback({ config, projectDir, logger, why }) {
|
|
151
|
+
if (config?.rag?.embedder?.provider) return false;
|
|
152
|
+
console.log(`⚠ default embedder unavailable (${why}) — trying the built-in ONNX embedder (no install needed)…`);
|
|
153
|
+
try {
|
|
154
|
+
// KJC-BUG-0128: an empty store may carry a vec table at the wrong
|
|
155
|
+
// dim (the old probe created it at 768) — reset it so ONNX (384)
|
|
156
|
+
// can index. A store with data is never touched.
|
|
157
|
+
if (!resetEmptyStore(projectDir)) {
|
|
158
|
+
console.log(" the vector store already has data at another dimension — not switching automatically");
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const totals = await ragIndexCommand({ config: onnxConfig(config), logger, flags: { withSources: true } });
|
|
162
|
+
if ((totals?.indexed ?? 0) > 0) {
|
|
163
|
+
const p = await persistOnnxChoice(projectDir);
|
|
164
|
+
console.log(`✓ RAG indexed with the built-in ONNX embedder — persisted in ${p}`);
|
|
165
|
+
console.log(" To move to Ollama later: install it, remove the rag.embedder block from .karajan/kj.config.yml,");
|
|
166
|
+
console.log(" delete the store (~/.karajan/rag.db) and run: kj rag index --with-sources");
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
} catch (fallbackErr) {
|
|
170
|
+
console.log(` ONNX fallback also failed: ${fallbackErr.message}`);
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* ENV-E1: RAG-first — the playbook orders "query the RAG before coding",
|
|
177
|
+
* so installing the environment guarantees the index exists. KJC-TSK-0659
|
|
178
|
+
* stop-on-sudo: an index that cannot be built is a BLOCKING condition —
|
|
179
|
+
* "success" with 0 chunks would leave every future session running the
|
|
180
|
+
* method against an empty RAG (field-reproduced: 0/727 without Ollama).
|
|
181
|
+
* The playbook stays installed; the command exits 3 so the driving agent
|
|
182
|
+
* stops, shows the block, and waits for the user.
|
|
183
|
+
*/
|
|
184
|
+
async function ensureRagIndex({ result, config, projectDir, logger }) {
|
|
185
|
+
const provider = config?.rag?.embedder?.provider || "ollama";
|
|
186
|
+
const blockRag = (why) => {
|
|
187
|
+
result.ragError = why;
|
|
188
|
+
const item = provider === "ollama"
|
|
189
|
+
? { tool: "ollama", action: "needs-user", reason: `the RAG cannot index: ${why}` }
|
|
190
|
+
: { tool: `${provider} embedder`, action: "needs-user", reason: `the RAG cannot index: ${why} — check rag.embedder in kj config`, manualUrl: "kj config" };
|
|
191
|
+
pend(result, [item], { retry: "kj rag index --with-sources (then re-run: kj env install)" });
|
|
192
|
+
};
|
|
193
|
+
const fallbackOrBlock = async (why) => {
|
|
194
|
+
if (!(await tryOnnxFallback({ config, projectDir, logger, why }))) blockRag(why);
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
if (hasRagIndex(config, projectDir)) {
|
|
198
|
+
console.log("✓ RAG index present");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log("⏳ no RAG index for this project — building it (first time only)…");
|
|
202
|
+
const totals = await ragIndexCommand({ config, logger, flags: { withSources: true } });
|
|
203
|
+
if ((totals?.indexed ?? 0) === 0 && (totals?.files ?? 0) > 0) await fallbackOrBlock(`0 of ${totals.files} files indexed — is the embedder running?`);
|
|
204
|
+
} catch (err) {
|
|
205
|
+
await fallbackOrBlock(err.message);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function envInstallCommand({ config = null, logger = null, flags = {} }) {
|
|
210
|
+
const projectDir = config?.projectDir || process.cwd();
|
|
211
|
+
// KJC-BUG-0273: what is dirty NOW is the person's; kj commits only what it generates below.
|
|
212
|
+
const dirtyBefore = contractChanges(projectDir);
|
|
213
|
+
config = await withChosenBoard(config, projectDir);
|
|
74
214
|
|
|
75
215
|
const result = await installPlaybook({
|
|
76
216
|
projectDir, target: flags.target || "all",
|
|
@@ -90,145 +230,31 @@ export async function envInstallCommand({ config = null, logger = null, flags =
|
|
|
90
230
|
console.log(`⚠ could not wire kj-rag-mcp into .mcp.json: ${err.message}`);
|
|
91
231
|
}
|
|
92
232
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const access = verifyBoardAccess({ config, projectDir });
|
|
98
|
-
if (!access.ok) {
|
|
99
|
-
result.boardError = access.needed.join(" | ");
|
|
100
|
-
result.exitCode = PENDING_EXIT_CODE;
|
|
101
|
-
console.log(renderPendingBlock(
|
|
102
|
-
[{ tool: `${access.name || access.backend} board`, action: "needs-user", reason: `Karajan does not run without a board. To use ${access.name || access.backend}: ${access.needed.join(" ")}` }],
|
|
103
|
-
{ retry: "kj env install" },
|
|
104
|
-
));
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
if (access.backend !== "hu-board") console.log(`✓ board access verified: ${access.via}`);
|
|
108
|
-
|
|
109
|
-
// KJC-BUG-0133 — installing IS activating. The setup flow used to order
|
|
110
|
-
// harden + the verdict gate as TEXT steps the agent runs (or narrates);
|
|
111
|
-
// a session that skipped them got a decorative method — field case
|
|
112
|
-
// 2026-08-02: installed karajan, then wrote everything by hand with
|
|
113
|
-
// nothing to stop it. env install now does them itself, idempotently.
|
|
114
|
-
if (flags.enforce !== false) {
|
|
115
|
-
if (!existsSync(join(projectDir, ".git"))) {
|
|
116
|
-
result.exitCode = PENDING_EXIT_CODE;
|
|
117
|
-
console.log(renderPendingBlock(
|
|
118
|
-
[{ tool: "git", action: "needs-user", reason: "the enforcement gates live in git hooks — run `git init` (Karajan's guarantees do not exist without git)" }],
|
|
119
|
-
{ retry: "kj env install" },
|
|
120
|
-
));
|
|
121
|
-
return result;
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
const h = await hardenCommand({ projectDir, logger: console });
|
|
125
|
-
if (h?.ok === false) throw new Error(h.error || "kj harden failed");
|
|
126
|
-
// KJC-BUG-0188: a headless harden never binds an identity by itself, and
|
|
127
|
-
// it must not. Blocking here beats the Sentinel denying every git and gh
|
|
128
|
-
// call later, with nothing on screen tying that back to this install.
|
|
129
|
-
if (h?.identityPending) {
|
|
130
|
-
result.exitCode = PENDING_EXIT_CODE;
|
|
131
|
-
result.pendingBlock = renderPendingBlock(
|
|
132
|
-
[{ tool: "identity", action: "needs-user", reason: h.identityPending, command: h.identityCommand }],
|
|
133
|
-
{ retry: "kj env install", why: "this clone has no declared identity, and kj never binds one on its own" },
|
|
134
|
-
);
|
|
135
|
-
console.log(result.pendingBlock);
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
const gate = await reviewGateCommand({ config, flags: { installGate: true } });
|
|
139
|
-
// KJC-BUG-0447: a gate no hook runs is decorative; never call it active.
|
|
140
|
-
if (!gate?.enforced) throw new Error("the review gate is declared but no pre-commit hook runs it");
|
|
141
|
-
console.log("✓ enforcement active: git hooks + cross-AI verdict gate — a commit outside the method is rejected, not narrated");
|
|
142
|
-
} catch (err) {
|
|
143
|
-
result.exitCode = PENDING_EXIT_CODE;
|
|
144
|
-
console.log(renderPendingBlock(
|
|
145
|
-
[{ tool: "enforcement", action: "needs-user", reason: `hooks/gate could not be installed: ${err.message} — without them the method is narratable` }],
|
|
146
|
-
{ retry: "kj env install" },
|
|
147
|
-
));
|
|
148
|
-
return result;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// ENV-E1: RAG-first — the playbook orders "query the RAG before coding",
|
|
153
|
-
// so installing the environment guarantees the index exists. KJC-TSK-0659
|
|
154
|
-
// stop-on-sudo: an index that cannot be built is a BLOCKING condition —
|
|
155
|
-
// "success" with 0 chunks would leave every future session running the
|
|
156
|
-
// method against an empty RAG (field-reproduced: 0/727 without Ollama).
|
|
157
|
-
// The playbook stays installed; the command exits 3 so the driving agent
|
|
158
|
-
// stops, shows the block, and waits for the user.
|
|
159
|
-
if (flags.rag !== false) {
|
|
160
|
-
const provider = config?.rag?.embedder?.provider || "ollama";
|
|
161
|
-
const blockRag = (why) => {
|
|
162
|
-
result.ragError = why;
|
|
163
|
-
result.exitCode = PENDING_EXIT_CODE;
|
|
164
|
-
const item = provider === "ollama"
|
|
165
|
-
? { tool: "ollama", action: "needs-user", reason: `the RAG cannot index: ${why}` }
|
|
166
|
-
: { tool: `${provider} embedder`, action: "needs-user", reason: `the RAG cannot index: ${why} — check rag.embedder in kj config`, manualUrl: "kj config" };
|
|
167
|
-
console.log(renderPendingBlock([item], { retry: "kj rag index --with-sources (then re-run: kj env install)" }));
|
|
168
|
-
};
|
|
169
|
-
// KJC-TSK-0683: on limited machines (no Ollama, no Docker) the DEFAULT
|
|
170
|
-
// provider falls back to the built-in ONNX embedder instead of blocking.
|
|
171
|
-
// Only for the first index and only when the user didn't pick a provider
|
|
172
|
-
// explicitly — the election is persisted (dims differ, it must stick).
|
|
173
|
-
const explicitProvider = Boolean(config?.rag?.embedder?.provider);
|
|
174
|
-
const tryOnnxFallback = async (why) => {
|
|
175
|
-
if (explicitProvider) return false;
|
|
176
|
-
console.log(`⚠ default embedder unavailable (${why}) — trying the built-in ONNX embedder (no install needed)…`);
|
|
177
|
-
try {
|
|
178
|
-
// KJC-BUG-0128: an empty store may carry a vec table at the wrong
|
|
179
|
-
// dim (the old probe created it at 768) — reset it so ONNX (384)
|
|
180
|
-
// can index. A store with data is never touched.
|
|
181
|
-
if (!resetEmptyStore(projectDir)) {
|
|
182
|
-
console.log(" the vector store already has data at another dimension — not switching automatically");
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
const totals = await ragIndexCommand({ config: onnxConfig(config), logger, flags: { withSources: true } });
|
|
186
|
-
if ((totals?.indexed ?? 0) > 0) {
|
|
187
|
-
const p = await persistOnnxChoice(projectDir);
|
|
188
|
-
console.log(`✓ RAG indexed with the built-in ONNX embedder — persisted in ${p}`);
|
|
189
|
-
console.log(" To move to Ollama later: install it, remove the rag.embedder block from .karajan/kj.config.yml,");
|
|
190
|
-
console.log(" delete the store (~/.karajan/rag.db) and run: kj rag index --with-sources");
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
} catch (fallbackErr) {
|
|
194
|
-
console.log(` ONNX fallback also failed: ${fallbackErr.message}`);
|
|
195
|
-
}
|
|
196
|
-
return false;
|
|
197
|
-
};
|
|
198
|
-
try {
|
|
199
|
-
if (hasRagIndex(config, projectDir)) {
|
|
200
|
-
console.log("✓ RAG index present");
|
|
201
|
-
} else {
|
|
202
|
-
console.log("⏳ no RAG index for this project — building it (first time only)…");
|
|
203
|
-
const totals = await ragIndexCommand({ config, logger, flags: { withSources: true } });
|
|
204
|
-
if ((totals?.indexed ?? 0) === 0 && (totals?.files ?? 0) > 0) {
|
|
205
|
-
const why = `0 of ${totals.files} files indexed — is the embedder running?`;
|
|
206
|
-
if (!(await tryOnnxFallback(why))) blockRag(why);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
} catch (err) {
|
|
210
|
-
if (!(await tryOnnxFallback(err.message))) blockRag(err.message);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (result.exitCode !== PENDING_EXIT_CODE) {
|
|
214
|
-
// KJC-TSK-0707 (PV-D) — privacy onboarding rides the install: kj asks,
|
|
215
|
-
// kj writes the denylist. Best-effort (stubbed in the SEA binary).
|
|
216
|
-
try {
|
|
217
|
-
const wizard = process.stdin.isTTY && process.stdout.isTTY ? createWizard() : null;
|
|
218
|
-
await ensurePrivacyList({ wizard, logger: console, isTTY: Boolean(wizard) });
|
|
219
|
-
wizard?.close();
|
|
220
|
-
} catch { /* privacy onboarding is best-effort */ }
|
|
221
|
-
console.log(" The host agent now follows the method: RAG first, TDD, cross-AI review before commit.");
|
|
222
|
-
// KJC-BUG-0273: the contract is kj's to commit. Left to the agent, its own
|
|
223
|
-
// PR-size rules forbid a 1200-line commit of generated files and it stops.
|
|
224
|
-
const contract = commitContract({ projectDir, before: dirtyBefore, baseBranch: config?.base_branch || "main" });
|
|
225
|
-
if (contract.committed) console.log(`✓ contract committed by kj: ${contract.files.length} generated file(s), nothing for the agent to commit`);
|
|
226
|
-
else if (!contract.reason.startsWith("nothing")) console.log(`⚠ the contract kj generated is NOT committed (${contract.reason}): run \`kj env install\` again once that is fixed`);
|
|
227
|
-
// KJC-BUG-0133 (part 2): a mid-session install lands the playbook in
|
|
228
|
-
// CLAUDE.md, but the running session loaded its context BEFORE — nobody
|
|
229
|
-
// re-reads it. Print the method so it enters THIS conversation now.
|
|
230
|
-
console.log("\n— The Karajan method below is IN EFFECT from this very message. If your session started before this install, apply it from now on:\n");
|
|
231
|
-
console.log(renderPlaybook({ stateBackend: config?.state_backend || "hu-board", boardName: config?.board?.name || null, config }));
|
|
232
|
-
}
|
|
233
|
+
if (boardBlocked(result, config, projectDir)) return result;
|
|
234
|
+
if (flags.enforce !== false && await enforcementBlocked(result, config, projectDir)) return result;
|
|
235
|
+
if (flags.rag !== false) await ensureRagIndex({ result, config, projectDir, logger });
|
|
236
|
+
if (result.exitCode !== PENDING_EXIT_CODE) await finishInstall({ config, projectDir, dirtyBefore });
|
|
233
237
|
return result;
|
|
234
238
|
}
|
|
239
|
+
|
|
240
|
+
/** Privacy onboarding, the contract commit and the method printed into the running session. */
|
|
241
|
+
async function finishInstall({ config, projectDir, dirtyBefore }) {
|
|
242
|
+
// KJC-TSK-0707 (PV-D) — privacy onboarding rides the install: kj asks,
|
|
243
|
+
// kj writes the denylist. Best-effort (stubbed in the SEA binary).
|
|
244
|
+
try {
|
|
245
|
+
const wizard = process.stdin.isTTY && process.stdout.isTTY ? createWizard() : null;
|
|
246
|
+
await ensurePrivacyList({ wizard, logger: console, isTTY: Boolean(wizard) });
|
|
247
|
+
wizard?.close();
|
|
248
|
+
} catch { /* privacy onboarding is best-effort */ }
|
|
249
|
+
console.log(" The host agent now follows the method: RAG first, TDD, cross-AI review before commit.");
|
|
250
|
+
// KJC-BUG-0273: the contract is kj's to commit. Left to the agent, its own
|
|
251
|
+
// PR-size rules forbid a 1200-line commit of generated files and it stops.
|
|
252
|
+
const contract = commitContract({ projectDir, before: dirtyBefore, baseBranch: config?.base_branch || "main" });
|
|
253
|
+
if (contract.committed) console.log(`✓ contract committed by kj: ${contract.files.length} generated file(s), nothing for the agent to commit`);
|
|
254
|
+
else if (!contract.reason.startsWith("nothing")) console.log(`⚠ the contract kj generated is NOT committed (${contract.reason}): run \`kj env install\` again once that is fixed`);
|
|
255
|
+
// KJC-BUG-0133 (part 2): a mid-session install lands the playbook in
|
|
256
|
+
// CLAUDE.md, but the running session loaded its context BEFORE — nobody
|
|
257
|
+
// re-reads it. Print the method so it enters THIS conversation now.
|
|
258
|
+
console.log("\n— The Karajan method below is IN EFFECT from this very message. If your session started before this install, apply it from now on:\n");
|
|
259
|
+
console.log(renderPlaybook({ stateBackend: config?.state_backend || "hu-board", boardName: config?.board?.name || null, config }));
|
|
260
|
+
}
|
package/src/commands/go.js
CHANGED
|
@@ -67,53 +67,83 @@ function defaultLaunch(agent, prompt) {
|
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
+
const failed = () => {
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return 1;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// No agent ready: say what only the person can do (log in, or install one).
|
|
76
|
+
function explainNoAgent(agents, logger) {
|
|
77
|
+
const needLogin = agents.filter((a) => a.installed && !a.authenticated);
|
|
78
|
+
if (needLogin.length > 0) {
|
|
79
|
+
logger.error?.("Tienes el agente instalado pero falta iniciar sesión — eso solo puedes hacerlo tú (la cuenta es tuya; Karajan nunca toca tus credenciales):");
|
|
80
|
+
for (const a of needLogin) logger.error?.(` ${a.label}: ${a.login}`);
|
|
81
|
+
logger.error?.("Cuando hayas iniciado sesión, vuelve a escribir: kj go");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
logger.error?.("Karajan trabaja con un agente de IA que aún no tienes instalado. Elige uno, instálalo con su comando, e inicia sesión con TU cuenta (la cuenta es tuya):");
|
|
85
|
+
for (const a of agents) logger.error?.(` ${a.label}: ${a.install}`);
|
|
86
|
+
logger.error?.("Después, vuelve a escribir: kj go");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// At most one question, and only when more than one agent is ready.
|
|
90
|
+
async function chooseAgent(ready, { flags, deps }) {
|
|
91
|
+
if (ready.length === 1) return ready[0];
|
|
92
|
+
const ask = deps.ask ?? createCliAskQuestion({ flags });
|
|
93
|
+
const answer = await ask("¿Con cuál de tus agentes quieres trabajar?", { options: ready.map((a) => a.name), default: ready[0].name });
|
|
94
|
+
return ready.find((a) => a.name === String(answer).trim()) ?? ready[0];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Prepare ONCE: decisions already taken are never re-asked. Resolves false
|
|
98
|
+
// when something is left for the person's hands (already said above).
|
|
99
|
+
async function prepareOnce({ projectDir, config, logger, deps }) {
|
|
100
|
+
if (existsSync(path.join(projectDir, ".karajan", "review-gate"))) return true;
|
|
101
|
+
logger.info?.("Preparando tu proyecto (solo la primera vez)…");
|
|
102
|
+
// BOOT-A paso 3 (KJC-TSK-0857): el orden vive en UN sitio, kj bootstrap.
|
|
103
|
+
// Antes esta puerta cableaba su propia secuencia (git init y env install),
|
|
104
|
+
// así que la puerta del maggle y la técnica podían separarse sin que nadie
|
|
105
|
+
// se diera cuenta. Ahora las dos hacen lo mismo.
|
|
106
|
+
const booted = await (deps.bootstrap ?? bootstrapCommand)({ config, logger, flags: {}, deps: {} });
|
|
107
|
+
if (!booted.ok) {
|
|
108
|
+
logger.error?.(`Falta una cosa que solo puedes hacer tú, la tienes justo arriba (${booted.pending}). Cuando la hagas, vuelve a escribir: kj go`);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const prepared = deps.prepare ? await deps.prepare({ config, logger }) : null;
|
|
112
|
+
// Algo depende de tus manos (arriba tienes el detalle). Sin eso el
|
|
113
|
+
// proyecto quedaría a medias, así que paramos aquí en vez de seguir.
|
|
114
|
+
if (prepared?.exitCode) {
|
|
115
|
+
logger.error?.("Falta una cosa que solo puedes hacer tú, la tienes justo arriba. Cuando la hagas, vuelve a escribir: kj go");
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// The board is the muggle's window — unless the project turned it off
|
|
122
|
+
// (hu_board.enabled false is respected: KJC-BUG-0152). A board failure is
|
|
123
|
+
// said and never stops the conversation from starting. Resolves whether it opened.
|
|
124
|
+
async function openBoard({ config, logger, deps, windowMode }) {
|
|
125
|
+
if (config.hu_board?.enabled === false) return false;
|
|
126
|
+
const openPath = windowMode ? "/?maggle=1&window=1" : "/?maggle=1";
|
|
127
|
+
try {
|
|
128
|
+
await (deps.board ?? defaultBoard)({ config, logger, openPath });
|
|
129
|
+
return true;
|
|
130
|
+
} catch (err) {
|
|
131
|
+
logger.warn?.(`El tablero no pudo abrirse (${err.message}) — la conversación arranca igual.`);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
70
136
|
export async function goCommand({ config = {}, logger = console, flags = {}, deps = {} } = {}) {
|
|
71
137
|
const projectDir = config.projectDir || process.cwd();
|
|
72
138
|
const agents = await (deps.detect ?? detectMaggleAgents)();
|
|
73
139
|
const ready = agents.filter((a) => a.installed && a.authenticated);
|
|
74
|
-
const needLogin = agents.filter((a) => a.installed && !a.authenticated);
|
|
75
140
|
if (ready.length === 0) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
for (const a of needLogin) logger.error?.(` ${a.label}: ${a.login}`);
|
|
79
|
-
logger.error?.("Cuando hayas iniciado sesión, vuelve a escribir: kj go");
|
|
80
|
-
} else {
|
|
81
|
-
logger.error?.("Karajan trabaja con un agente de IA que aún no tienes instalado. Elige uno, instálalo con su comando, e inicia sesión con TU cuenta (la cuenta es tuya):");
|
|
82
|
-
for (const a of agents) logger.error?.(` ${a.label}: ${a.install}`);
|
|
83
|
-
logger.error?.("Después, vuelve a escribir: kj go");
|
|
84
|
-
}
|
|
85
|
-
process.exitCode = 1;
|
|
86
|
-
return 1;
|
|
87
|
-
}
|
|
88
|
-
let chosen = ready[0];
|
|
89
|
-
if (ready.length > 1) {
|
|
90
|
-
const ask = deps.ask ?? createCliAskQuestion({ flags });
|
|
91
|
-
const answer = await ask("¿Con cuál de tus agentes quieres trabajar?", { options: ready.map((a) => a.name), default: ready[0].name });
|
|
92
|
-
chosen = ready.find((a) => a.name === String(answer).trim()) ?? ready[0];
|
|
141
|
+
explainNoAgent(agents, logger);
|
|
142
|
+
return failed();
|
|
93
143
|
}
|
|
144
|
+
const chosen = await chooseAgent(ready, { flags, deps });
|
|
94
145
|
logger.info?.(`Trabajarás con ${chosen.label}.`);
|
|
95
|
-
|
|
96
|
-
if (!existsSync(path.join(projectDir, ".karajan", "review-gate"))) {
|
|
97
|
-
logger.info?.("Preparando tu proyecto (solo la primera vez)…");
|
|
98
|
-
// BOOT-A paso 3 (KJC-TSK-0857): el orden vive en UN sitio, kj bootstrap.
|
|
99
|
-
// Antes esta puerta cableaba su propia secuencia (git init y env install),
|
|
100
|
-
// así que la puerta del maggle y la técnica podían separarse sin que nadie
|
|
101
|
-
// se diera cuenta. Ahora las dos hacen lo mismo.
|
|
102
|
-
const booted = await (deps.bootstrap ?? bootstrapCommand)({ config, logger, flags: {}, deps: {} });
|
|
103
|
-
if (!booted.ok) {
|
|
104
|
-
logger.error?.(`Falta una cosa que solo puedes hacer tú, la tienes justo arriba (${booted.pending}). Cuando la hagas, vuelve a escribir: kj go`);
|
|
105
|
-
process.exitCode = 1;
|
|
106
|
-
return 1;
|
|
107
|
-
}
|
|
108
|
-
const prepared = deps.prepare ? await deps.prepare({ config, logger }) : null;
|
|
109
|
-
// Algo depende de tus manos (arriba tienes el detalle). Sin eso el
|
|
110
|
-
// proyecto quedaría a medias, así que paramos aquí en vez de seguir.
|
|
111
|
-
if (prepared?.exitCode) {
|
|
112
|
-
logger.error?.("Falta una cosa que solo puedes hacer tú, la tienes justo arriba. Cuando la hagas, vuelve a escribir: kj go");
|
|
113
|
-
process.exitCode = 1;
|
|
114
|
-
return 1;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
146
|
+
if (!(await prepareOnce({ projectDir, config, logger, deps }))) return failed();
|
|
117
147
|
const prompt = (deps.prompt ?? buildGoPrompt)();
|
|
118
148
|
// --window (MGL-E, ADR 0008): la conversación vive DENTRO del board — el
|
|
119
149
|
// daemon hereda por env (HU_BOARD_TERMINAL_CWD/AGENT/PROMPT) el cwd, el
|
|
@@ -126,19 +156,7 @@ export async function goCommand({ config = {}, logger = console, flags = {}, dep
|
|
|
126
156
|
process.env.HU_BOARD_TERMINAL_AGENT = chosen.name;
|
|
127
157
|
process.env.HU_BOARD_TERMINAL_PROMPT = prompt;
|
|
128
158
|
}
|
|
129
|
-
|
|
130
|
-
// (hu_board.enabled false is respected: KJC-BUG-0152). A board failure is
|
|
131
|
-
// said and never stops the conversation from starting.
|
|
132
|
-
let boardOpened = false;
|
|
133
|
-
if (config.hu_board?.enabled !== false) {
|
|
134
|
-
const openPath = windowMode ? "/?maggle=1&window=1" : "/?maggle=1";
|
|
135
|
-
try {
|
|
136
|
-
await (deps.board ?? defaultBoard)({ config, logger, openPath });
|
|
137
|
-
boardOpened = true;
|
|
138
|
-
} catch (err) {
|
|
139
|
-
logger.warn?.(`El tablero no pudo abrirse (${err.message}) — la conversación arranca igual.`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
159
|
+
const boardOpened = await openBoard({ config, logger, deps, windowMode });
|
|
142
160
|
if (windowMode && boardOpened) {
|
|
143
161
|
logger.info?.("Tu conversación vive en la ventana del navegador que se acaba de abrir. Si el tablero ya estaba arrancado de antes, reinícialo con kj board stop && kj go --window para que recoja este proyecto.");
|
|
144
162
|
process.exitCode = 0;
|