@karajan-family/code 4.21.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/LICENSE +661 -0
- package/README.md +98 -0
- package/bin/karajan-mcp.js +2 -0
- package/bin/kj-rag-mcp.js +75 -0
- package/bin/kj-tail +361 -0
- package/bin/kj.js +2 -0
- package/docs/README.es.md +80 -0
- package/docs/karajan-code-logo-small.png +0 -0
- package/library/logical-clocks-lamport.md +40 -0
- package/package.json +140 -0
- package/packages/ai-trash/README.md +37 -0
- package/packages/ai-trash/bin/kj-trash.js +10 -0
- package/packages/ai-trash/package.json +43 -0
- package/packages/ai-trash/src/cli.js +200 -0
- package/packages/ai-trash/src/destructive-parser.js +74 -0
- package/packages/ai-trash/src/git-snapshot.js +128 -0
- package/packages/ai-trash/src/hook.js +137 -0
- package/packages/ai-trash/src/index.js +14 -0
- package/packages/ai-trash/src/install.js +73 -0
- package/packages/ai-trash/src/logger.js +60 -0
- package/packages/ai-trash/src/manifest.js +91 -0
- package/packages/ai-trash/src/permissions.js +26 -0
- package/packages/ai-trash/src/snapshot.js +66 -0
- package/packages/ai-trash/src/ulid.js +66 -0
- package/packages/hu-board/README.md +69 -0
- package/packages/hu-board/package.json +28 -0
- package/packages/hu-board/public/app.js +259 -0
- package/packages/hu-board/public/index.html +77 -0
- package/packages/hu-board/public/pipeline.css +132 -0
- package/packages/hu-board/public/pipeline.html +48 -0
- package/packages/hu-board/public/pipeline.js +200 -0
- package/packages/hu-board/public/rag.html +21 -0
- package/packages/hu-board/public/rag.js +39 -0
- package/packages/hu-board/public/styles.css +973 -0
- package/packages/hu-board/public/utils/api.js +139 -0
- package/packages/hu-board/public/utils/board-view.js +473 -0
- package/packages/hu-board/public/utils/command-launcher.js +213 -0
- package/packages/hu-board/public/utils/config-editor.js +181 -0
- package/packages/hu-board/public/utils/dashboard-view.js +103 -0
- package/packages/hu-board/public/utils/formatters.js +300 -0
- package/packages/hu-board/public/utils/graph-view.js +216 -0
- package/packages/hu-board/public/utils/hu-actions.js +224 -0
- package/packages/hu-board/public/utils/init-listeners.js +180 -0
- package/packages/hu-board/public/utils/log-panel.js +222 -0
- package/packages/hu-board/public/utils/modals.js +309 -0
- package/packages/hu-board/public/utils/plan-rollup-view.js +53 -0
- package/packages/hu-board/public/utils/preflight-view.js +89 -0
- package/packages/hu-board/public/utils/project-actions.js +143 -0
- package/packages/hu-board/public/utils/project-picker-view.js +139 -0
- package/packages/hu-board/public/utils/run-launcher.js +169 -0
- package/packages/hu-board/public/utils/server-push.js +252 -0
- package/packages/hu-board/public/utils/sessions-view.js +199 -0
- package/packages/hu-board/public/utils/story-detail-view.js +324 -0
- package/packages/hu-board/public/utils/story-edit-form.js +271 -0
- package/packages/hu-board/public/wiki.html +32 -0
- package/packages/hu-board/public/wiki.js +53 -0
- package/packages/hu-board/src/auth.js +92 -0
- package/packages/hu-board/src/boot-info.js +16 -0
- package/packages/hu-board/src/cleanup-zombies.js +145 -0
- package/packages/hu-board/src/command-runner.js +133 -0
- package/packages/hu-board/src/config-yaml.js +531 -0
- package/packages/hu-board/src/db.js +963 -0
- package/packages/hu-board/src/ephemeral-cleaner.js +196 -0
- package/packages/hu-board/src/event-bus.js +58 -0
- package/packages/hu-board/src/format.js +207 -0
- package/packages/hu-board/src/hu-zombie-reaper.js +103 -0
- package/packages/hu-board/src/journal-parser.js +180 -0
- package/packages/hu-board/src/plan-mutations.js +424 -0
- package/packages/hu-board/src/preflight.js +286 -0
- package/packages/hu-board/src/routes/api.js +1374 -0
- package/packages/hu-board/src/routes/pipeline.js +45 -0
- package/packages/hu-board/src/routes/rag.js +42 -0
- package/packages/hu-board/src/routes/wiki.js +43 -0
- package/packages/hu-board/src/run-tracker.js +121 -0
- package/packages/hu-board/src/server.js +438 -0
- package/packages/hu-board/src/sync.js +732 -0
- package/packages/hu-board/src/token-store.js +56 -0
- package/packages/hu-board/src/zombie-reaper.js +206 -0
- package/scripts/ai-attribution-guard.yml +84 -0
- package/scripts/audit-test-diet.mjs +151 -0
- package/scripts/build-sea.mjs +150 -0
- package/scripts/diet-baseline.mjs +170 -0
- package/scripts/dual-publish.mjs +67 -0
- package/scripts/esbuild-sea.config.mjs +273 -0
- package/scripts/git-hooks/post-merge +18 -0
- package/scripts/install-binary.ps1 +174 -0
- package/scripts/install-binary.sh +159 -0
- package/scripts/install-guard-all-repos.sh +85 -0
- package/scripts/install-kj.sh +193 -0
- package/scripts/install.js +901 -0
- package/scripts/install.sh +7 -0
- package/scripts/postinstall.js +117 -0
- package/scripts/protect-all-repos.sh +88 -0
- package/scripts/quickstart-gate.mjs +97 -0
- package/scripts/regen-arch-stats.sh +71 -0
- package/scripts/setup-multi-instance.sh +150 -0
- package/scripts/verify-pack.mjs +278 -0
- package/src/activity-log.js +59 -0
- package/src/agents/agy-agent.js +62 -0
- package/src/agents/aider-agent.js +78 -0
- package/src/agents/availability.js +52 -0
- package/src/agents/base-agent.js +134 -0
- package/src/agents/claude-agent.js +413 -0
- package/src/agents/codex-agent.js +112 -0
- package/src/agents/copilot-agent.js +65 -0
- package/src/agents/gemini-agent.js +85 -0
- package/src/agents/host-agent.js +38 -0
- package/src/agents/index.js +59 -0
- package/src/agents/kimi-agent.js +45 -0
- package/src/agents/model-registry.js +137 -0
- package/src/agents/opencode-agent.js +72 -0
- package/src/agents/qwen-agent.js +20 -0
- package/src/agents/resolve-bin.js +73 -0
- package/src/audit/agent-readiness.js +259 -0
- package/src/audit/ai-slop-findings.js +102 -0
- package/src/audit/audit-fallback.js +66 -0
- package/src/audit/audit-history-display.js +61 -0
- package/src/audit/audit-history.js +102 -0
- package/src/audit/basal-cost.js +281 -0
- package/src/audit/circular-deps.js +144 -0
- package/src/audit/dead-exports.js +186 -0
- package/src/audit/deterministic-summary.js +327 -0
- package/src/audit/harness-scorecard.js +100 -0
- package/src/audit/harness-section.js +81 -0
- package/src/audit/infra-findings.js +100 -0
- package/src/audit/injection-findings.js +114 -0
- package/src/audit/issue-filter.js +133 -0
- package/src/audit/osv-findings.js +167 -0
- package/src/audit/plan-adherence.js +224 -0
- package/src/audit/semgrep-findings.js +129 -0
- package/src/audit/sonar-findings.js +93 -0
- package/src/audit/webperf-input.js +133 -0
- package/src/autonomy/arbiter-role.js +71 -0
- package/src/autonomy/arbiter.js +22 -0
- package/src/autonomy/decider.js +18 -0
- package/src/autonomy/decision-resolver.js +58 -0
- package/src/autonomy/outcome-report.js +55 -0
- package/src/autonomy/policy.js +41 -0
- package/src/autonomy/stage-ask.js +30 -0
- package/src/bootstrap.js +276 -0
- package/src/brain/agent-error-classifier.js +116 -0
- package/src/brain/decision-tracker.js +125 -0
- package/src/brain/decisor.js +243 -0
- package/src/brain/solomon-consult.js +171 -0
- package/src/brain/standby-scheduler.js +8 -0
- package/src/brain/standby-store.js +12 -0
- package/src/brain/with-brain-recovery.js +235 -0
- package/src/budget/comparison.js +96 -0
- package/src/canvas/parse-md.js +238 -0
- package/src/canvas/schema.js +101 -0
- package/src/canvas/to-flat.js +85 -0
- package/src/canvas/validate.js +163 -0
- package/src/checks/ai-surface.js +79 -0
- package/src/checks/ai-trash.js +34 -0
- package/src/checks/binaries.js +207 -0
- package/src/checks/ci.js +105 -0
- package/src/checks/config-files.js +217 -0
- package/src/checks/dir-setup.js +103 -0
- package/src/checks/guarantee-level.js +38 -0
- package/src/checks/hardware.js +150 -0
- package/src/checks/harness-scorecard.js +41 -0
- package/src/checks/mcp-health.js +169 -0
- package/src/checks/method.js +73 -0
- package/src/checks/native-build.js +67 -0
- package/src/checks/node.js +70 -0
- package/src/checks/ollama.js +41 -0
- package/src/checks/orphans.js +77 -0
- package/src/checks/ports.js +188 -0
- package/src/checks/project-checks.js +245 -0
- package/src/checks/qmd.js +41 -0
- package/src/checks/rag-hooks.js +54 -0
- package/src/checks/release-check.js +102 -0
- package/src/checks/rtk.js +36 -0
- package/src/checks/runner.js +326 -0
- package/src/checks/skills.js +53 -0
- package/src/checks/sonar.js +67 -0
- package/src/checks/squeezr.js +36 -0
- package/src/checks/system.js +53 -0
- package/src/checks/tokens.js +172 -0
- package/src/checks/types.js +103 -0
- package/src/ci/dispatch.js +99 -0
- package/src/ci/index.js +3 -0
- package/src/ci/pr-diff.js +26 -0
- package/src/ci/repo.js +45 -0
- package/src/cli/_shared.js +30 -0
- package/src/cli/advanced-commands.js +61 -0
- package/src/cli/register-meta.js +772 -0
- package/src/cli/register-pipeline.js +335 -0
- package/src/cli/register-plan.js +224 -0
- package/src/cli/register-roles-skills.js +54 -0
- package/src/cli/register-sonar.js +28 -0
- package/src/cli/register-standby.js +26 -0
- package/src/cli.js +155 -0
- package/src/commands/advanced.js +31 -0
- package/src/commands/agent-run.js +63 -0
- package/src/commands/agents.js +105 -0
- package/src/commands/architect.js +123 -0
- package/src/commands/audit.js +430 -0
- package/src/commands/autorun.js +49 -0
- package/src/commands/board.js +458 -0
- package/src/commands/check.js +40 -0
- package/src/commands/clean.js +145 -0
- package/src/commands/code.js +45 -0
- package/src/commands/config.js +74 -0
- package/src/commands/discover.js +105 -0
- package/src/commands/doctor.js +251 -0
- package/src/commands/env.js +207 -0
- package/src/commands/harden.js +203 -0
- package/src/commands/hu.js +210 -0
- package/src/commands/identity.js +60 -0
- package/src/commands/init.js +950 -0
- package/src/commands/install-tools.js +432 -0
- package/src/commands/mutate.js +94 -0
- package/src/commands/ollama.js +44 -0
- package/src/commands/onboard.js +45 -0
- package/src/commands/plan/_shared.js +55 -0
- package/src/commands/plan/add-hu.js +23 -0
- package/src/commands/plan/delete.js +9 -0
- package/src/commands/plan/fix.js +99 -0
- package/src/commands/plan/generate.js +532 -0
- package/src/commands/plan/index.js +13 -0
- package/src/commands/plan/list.js +21 -0
- package/src/commands/plan/migrate-result.js +41 -0
- package/src/commands/plan/ready.js +46 -0
- package/src/commands/plan/remove-hu.js +17 -0
- package/src/commands/plan/share.js +85 -0
- package/src/commands/plan/show.js +81 -0
- package/src/commands/plan/unshare.js +41 -0
- package/src/commands/plan/validate.js +20 -0
- package/src/commands/plan.js +17 -0
- package/src/commands/policy.js +164 -0
- package/src/commands/privacy.js +45 -0
- package/src/commands/qmd.js +86 -0
- package/src/commands/rag-mcp.js +18 -0
- package/src/commands/rag.js +173 -0
- package/src/commands/report-issue.js +77 -0
- package/src/commands/report.js +469 -0
- package/src/commands/researcher.js +54 -0
- package/src/commands/resume.js +68 -0
- package/src/commands/review-gate.js +355 -0
- package/src/commands/review.js +89 -0
- package/src/commands/roles.js +116 -0
- package/src/commands/run.js +185 -0
- package/src/commands/scan.js +18 -0
- package/src/commands/skills.js +86 -0
- package/src/commands/sonar.js +53 -0
- package/src/commands/standby.js +117 -0
- package/src/commands/start.js +121 -0
- package/src/commands/status.js +36 -0
- package/src/commands/sync.js +103 -0
- package/src/commands/telemetry.js +70 -0
- package/src/commands/tournament.js +85 -0
- package/src/commands/triage.js +78 -0
- package/src/commands/undo.js +62 -0
- package/src/commands/watch.js +46 -0
- package/src/commands/webperf.js +162 -0
- package/src/commands/worktree.js +76 -0
- package/src/config/defaults.js +270 -0
- package/src/config/loader.js +204 -0
- package/src/config/overrides.js +220 -0
- package/src/config/role-resolver.js +171 -0
- package/src/config/schema.js +299 -0
- package/src/config/test-harness.js +78 -0
- package/src/config.js +34 -0
- package/src/domains/domain-loader.js +245 -0
- package/src/domains/domain-registry.js +140 -0
- package/src/domains/domain-synthesizer.js +129 -0
- package/src/environment/adr.js +45 -0
- package/src/environment/board-access.js +97 -0
- package/src/environment/board-select.js +59 -0
- package/src/environment/briefs.js +129 -0
- package/src/environment/issue-report.js +72 -0
- package/src/environment/mcp-wiring.js +44 -0
- package/src/environment/playbook.js +127 -0
- package/src/git/automation.js +334 -0
- package/src/git/hu-automation.js +171 -0
- package/src/git/hu-snapshot.js +10 -0
- package/src/golden/asserter.js +92 -0
- package/src/golden/loader.js +52 -0
- package/src/golden/runner.js +92 -0
- package/src/golden/schema.js +41 -0
- package/src/guards/intent-guard.js +161 -0
- package/src/guards/output-guard.js +149 -0
- package/src/guards/perf-guard.js +126 -0
- package/src/guards/policy-guard.js +90 -0
- package/src/guards/policy-resolver.js +85 -0
- package/src/guards/secret-redactor.js +71 -0
- package/src/harden/advisory.js +203 -0
- package/src/harden/alternatives.js +50 -0
- package/src/harden/check.js +81 -0
- package/src/harden/config-engine.js +128 -0
- package/src/harden/config-templates.js +122 -0
- package/src/harden/guidelines-engine.js +48 -0
- package/src/harden/guidelines-templates.js +36 -0
- package/src/harden/harden-engine.js +80 -0
- package/src/harden/harness-hooks.js +107 -0
- package/src/harden/hook-commands.js +25 -0
- package/src/harden/hook-templates.js +183 -0
- package/src/harden/interactive.js +76 -0
- package/src/harden/sentinel-hooks.js +721 -0
- package/src/harden/stack-roots.js +105 -0
- package/src/harden/test-on-push.js +38 -0
- package/src/harden/workflow-engine.js +116 -0
- package/src/harden/workflow-templates.js +285 -0
- package/src/hu/acceptance-runner.js +138 -0
- package/src/hu/auto-generator.js +358 -0
- package/src/hu/graph.js +71 -0
- package/src/hu/lazy-planner.js +109 -0
- package/src/hu/model-router.js +108 -0
- package/src/hu/parallel-executor.js +94 -0
- package/src/hu/split-validator.js +143 -0
- package/src/hu/splitting-detector.js +158 -0
- package/src/hu/splitting-generator.js +175 -0
- package/src/hu/store.js +392 -0
- package/src/hu/worktree-bootstrap.js +59 -0
- package/src/identity/bootstrap.js +48 -0
- package/src/identity/compare.js +38 -0
- package/src/identity/detect.js +51 -0
- package/src/identity/store.js +66 -0
- package/src/infrastructure/command-runner.js +44 -0
- package/src/infrastructure/environment.js +38 -0
- package/src/infrastructure/file-system-service.js +63 -0
- package/src/infrastructure/mocks.js +182 -0
- package/src/lang/chunk-go.js +94 -0
- package/src/lang/chunk-java.js +90 -0
- package/src/lang/chunk-python.js +88 -0
- package/src/lang/chunk-rust.js +102 -0
- package/src/lang/go.js +14 -0
- package/src/lang/java.js +16 -0
- package/src/lang/js.js +8 -0
- package/src/lang/python.js +14 -0
- package/src/lang/registry.js +79 -0
- package/src/lang/rust.js +14 -0
- package/src/lang/tree-sitter-loader.js +45 -0
- package/src/mcp/direct-role-runner.js +112 -0
- package/src/mcp/error-classifiers.js +66 -0
- package/src/mcp/handlers/direct-handlers.js +486 -0
- package/src/mcp/handlers/hu-handlers.js +93 -0
- package/src/mcp/handlers/management-handlers.js +265 -0
- package/src/mcp/handlers/rag-handler.js +52 -0
- package/src/mcp/handlers/run-handler.js +313 -0
- package/src/mcp/orphan-guard.js +131 -0
- package/src/mcp/preflight.js +47 -0
- package/src/mcp/progress.js +149 -0
- package/src/mcp/response-compressor.js +81 -0
- package/src/mcp/run-kj.js +135 -0
- package/src/mcp/server-handlers.js +79 -0
- package/src/mcp/server.js +66 -0
- package/src/mcp/shared-helpers.js +297 -0
- package/src/mcp/sovereignty-guard.js +112 -0
- package/src/mcp/suggest-handler.js +92 -0
- package/src/mcp/tool-arg-normalizers.js +16 -0
- package/src/mcp/tools.js +432 -0
- package/src/mutate/diff-scope.js +105 -0
- package/src/mutate/reviewer-signal.js +76 -0
- package/src/mutate/runner.js +72 -0
- package/src/mutate/tool-registry.js +90 -0
- package/src/onboarder/cache.js +24 -0
- package/src/onboarder/collectors/framework-multilang.js +64 -0
- package/src/onboarder/collectors/index.js +136 -0
- package/src/orchestrator/agent-fallback.js +81 -0
- package/src/orchestrator/brain-coordinator.js +186 -0
- package/src/orchestrator/ci-integration.js +139 -0
- package/src/orchestrator/config-init.js +510 -0
- package/src/orchestrator/direct-actions.js +217 -0
- package/src/orchestrator/drivers/error-recovery.js +287 -0
- package/src/orchestrator/drivers/init-context.js +227 -0
- package/src/orchestrator/drivers/iteration-loop.js +380 -0
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +69 -0
- package/src/orchestrator/drivers/iteration-phases/guards.js +84 -0
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +29 -0
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +114 -0
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +60 -0
- package/src/orchestrator/drivers/post-loop.js +383 -0
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +136 -0
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +47 -0
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +84 -0
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +391 -0
- package/src/orchestrator/drivers/pre-loop.js +507 -0
- package/src/orchestrator/drivers/run-hu-batch.js +427 -0
- package/src/orchestrator/feedback-enrichment.js +140 -0
- package/src/orchestrator/feedback-queue.js +151 -0
- package/src/orchestrator/flow-control.js +170 -0
- package/src/orchestrator/flow-runner.js +364 -0
- package/src/orchestrator/fs-leak-detector.js +210 -0
- package/src/orchestrator/hu-scheduler.js +114 -0
- package/src/orchestrator/hu-sub-pipeline.js +616 -0
- package/src/orchestrator/integrations.js +81 -0
- package/src/orchestrator/iteration-gate.js +73 -0
- package/src/orchestrator/iteration-stages.js +9 -0
- package/src/orchestrator/parallel-limiter.js +74 -0
- package/src/orchestrator/pipeline-context.js +72 -0
- package/src/orchestrator/post-loop-stages.js +468 -0
- package/src/orchestrator/pre-loop-stages.js +11 -0
- package/src/orchestrator/preflight-checks.js +462 -0
- package/src/orchestrator/repair/repair-detector.js +117 -0
- package/src/orchestrator/repair/repair-runner.js +142 -0
- package/src/orchestrator/reviewer-fallback.js +45 -0
- package/src/orchestrator/role-output-compressor.js +189 -0
- package/src/orchestrator/session-journal.js +308 -0
- package/src/orchestrator/solomon-escalation.js +305 -0
- package/src/orchestrator/solomon-rules.js +212 -0
- package/src/orchestrator/stages/architect-stage.js +172 -0
- package/src/orchestrator/stages/coder-stage.js +480 -0
- package/src/orchestrator/stages/domain-curator-stage.js +82 -0
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +127 -0
- package/src/orchestrator/stages/hu-reviewer-stage.js +394 -0
- package/src/orchestrator/stages/perf-stage.js +140 -0
- package/src/orchestrator/stages/planner-stage.js +85 -0
- package/src/orchestrator/stages/rag-context-stage.js +77 -0
- package/src/orchestrator/stages/rag-preload-decisor.js +58 -0
- package/src/orchestrator/stages/research-stage.js +69 -0
- package/src/orchestrator/stages/reviewer-stage.js +422 -0
- package/src/orchestrator/stages/sonar-stage.js +421 -0
- package/src/orchestrator/stages/stage-classes.js +84 -0
- package/src/orchestrator/stages/stage-executor.js +155 -0
- package/src/orchestrator/stages/tdd-discipline-stage.js +56 -0
- package/src/orchestrator/stages/tool-judge-stage.js +53 -0
- package/src/orchestrator/stages/triage-stage.js +172 -0
- package/src/orchestrator/standby.js +71 -0
- package/src/orchestrator/verification-gate.js +183 -0
- package/src/orchestrator.js +22 -0
- package/src/plan/adr-generator.js +170 -0
- package/src/plan/adr-loader.js +60 -0
- package/src/plan/plan-executor.js +100 -0
- package/src/plan/plan-fixer.js +192 -0
- package/src/plan/plan-hu-ops.js +16 -0
- package/src/plan/plan-id.js +4 -0
- package/src/plan/plan-migrate-result.js +24 -0
- package/src/plan/plan-reviewer.js +236 -0
- package/src/plan/plan-schema.js +334 -0
- package/src/plan/plan-store.js +260 -0
- package/src/plan/plan-structural-pass.js +122 -0
- package/src/plan/plan-validation.js +4 -0
- package/src/plan/preflight-hu.js +105 -0
- package/src/plan/spec-detector.js +61 -0
- package/src/plan/tests-synthesizer.js +131 -0
- package/src/planning-game/adapter.js +108 -0
- package/src/planning-game/architect-adrs.js +45 -0
- package/src/planning-game/client.js +108 -0
- package/src/planning-game/decomposition.js +87 -0
- package/src/planning-game/pipeline-adapter.js +251 -0
- package/src/plugins/loader.js +67 -0
- package/src/policy/add.js +111 -0
- package/src/policy/decisions.js +42 -0
- package/src/policy/engine.js +82 -0
- package/src/policy/exceptions.js +60 -0
- package/src/privacy/onboarding.js +35 -0
- package/src/privacy/scan.js +120 -0
- package/src/prompts/arbiter.js +38 -0
- package/src/prompts/architect.js +103 -0
- package/src/prompts/audit.js +474 -0
- package/src/prompts/coder.js +287 -0
- package/src/prompts/diff-clip.js +27 -0
- package/src/prompts/discover.js +222 -0
- package/src/prompts/hu-reviewer.js +219 -0
- package/src/prompts/planner.js +312 -0
- package/src/prompts/prompt-layout.js +80 -0
- package/src/prompts/prompt-resolver.js +120 -0
- package/src/prompts/reviewer.js +75 -0
- package/src/prompts/rtk-snippet.js +25 -0
- package/src/prompts/spec-reviewer.js +66 -0
- package/src/prompts/split-signal.js +82 -0
- package/src/prompts/start-decision.js +52 -0
- package/src/prompts/tool-correctness-judge.js +31 -0
- package/src/prompts/triage.js +57 -0
- package/src/rag/auto-update.js +72 -0
- package/src/rag/chunker-ast.js +56 -0
- package/src/rag/chunker.js +132 -0
- package/src/rag/embedder.js +2 -0
- package/src/rag/embedders/_cloud-base.js +2 -0
- package/src/rag/embedders/cohere.js +2 -0
- package/src/rag/embedders/factory.js +2 -0
- package/src/rag/embedders/mistral.js +2 -0
- package/src/rag/embedders/onnx.js +2 -0
- package/src/rag/embedders/openai.js +2 -0
- package/src/rag/embedders/voyage.js +2 -0
- package/src/rag/eval.js +61 -0
- package/src/rag/governed-embedder.js +39 -0
- package/src/rag/indexer.js +199 -0
- package/src/rag/library.js +62 -0
- package/src/rag/ollama-capability.js +59 -0
- package/src/rag/ollama-manager.js +98 -0
- package/src/rag/onnx-fallback.js +69 -0
- package/src/rag/rerank.js +4 -0
- package/src/rag/retriever.js +2 -0
- package/src/rag/vec-store.js +17 -0
- package/src/rag/watcher.js +62 -0
- package/src/rag/where-parser.js +4 -0
- package/src/repeat-detector.js +88 -0
- package/src/review/card-first.js +99 -0
- package/src/review/card-verify.js +83 -0
- package/src/review/diff-generator.js +112 -0
- package/src/review/gate-gitignore.js +77 -0
- package/src/review/git-stash-helper.js +104 -0
- package/src/review/mutation-pregate.js +48 -0
- package/src/review/one-shot-review.js +122 -0
- package/src/review/parser.js +80 -0
- package/src/review/policy-gate.js +26 -0
- package/src/review/profiles.js +66 -0
- package/src/review/reviewer-fallback.js +125 -0
- package/src/review/schema.js +31 -0
- package/src/review/scope-filter.js +152 -0
- package/src/review/snapshot-diff.js +122 -0
- package/src/review/solomon-arbitration.js +113 -0
- package/src/review/sonar-pregate.js +63 -0
- package/src/review/tdd-discipline.js +90 -0
- package/src/review/tdd-policy.js +69 -0
- package/src/review/tests-with-code.js +33 -0
- package/src/review/verdict-store.js +87 -0
- package/src/review/workspace.js +21 -0
- package/src/roles/agent-role.js +194 -0
- package/src/roles/architect-role.js +77 -0
- package/src/roles/audit-role.js +258 -0
- package/src/roles/base-role.js +165 -0
- package/src/roles/coder-role.js +107 -0
- package/src/roles/commiter-role.js +110 -0
- package/src/roles/discover-role.js +81 -0
- package/src/roles/domain-curator-role.js +141 -0
- package/src/roles/hu-reviewer-role.js +64 -0
- package/src/roles/impeccable-role.js +85 -0
- package/src/roles/index.js +18 -0
- package/src/roles/karajan-brain-role.js +134 -0
- package/src/roles/onboarder-role.js +61 -0
- package/src/roles/perf-role.js +122 -0
- package/src/roles/planner-role.js +151 -0
- package/src/roles/refactorer-role.js +30 -0
- package/src/roles/repairer-role.js +181 -0
- package/src/roles/researcher-role.js +70 -0
- package/src/roles/reviewer-role.js +104 -0
- package/src/roles/security-role.js +73 -0
- package/src/roles/solomon-role.js +265 -0
- package/src/roles/sonar-role.js +70 -0
- package/src/roles/spec-reviewer-role.js +106 -0
- package/src/roles/tester-role.js +235 -0
- package/src/roles/tool-correctness-judge-role.js +78 -0
- package/src/roles/triage-role.js +99 -0
- package/src/session/journal/decisions-writer.js +200 -0
- package/src/session/journal/iteration-logger.js +194 -0
- package/src/session/journal/summary-writer.js +320 -0
- package/src/session/journal/tree-writer.js +164 -0
- package/src/session/journal/write-all.js +89 -0
- package/src/session/mutators.js +339 -0
- package/src/session/runtime-overrides.js +59 -0
- package/src/session/store.js +106 -0
- package/src/session-cleanup.js +116 -0
- package/src/skills/addyosmani-catalog.js +315 -0
- package/src/skills/addyosmani-role-map.js +139 -0
- package/src/skills/openskills-client.js +157 -0
- package/src/skills/semantic-detector.js +167 -0
- package/src/skills/skill-detector.js +385 -0
- package/src/skills/skill-loader.js +219 -0
- package/src/skills/skills-cache.js +128 -0
- package/src/sonar/api.js +128 -0
- package/src/sonar/cloud-scanner.js +78 -0
- package/src/sonar/config-resolver.js +88 -0
- package/src/sonar/credentials.js +60 -0
- package/src/sonar/discovery.js +124 -0
- package/src/sonar/enforcer.js +19 -0
- package/src/sonar/issue-filter.js +12 -0
- package/src/sonar/manager.js +181 -0
- package/src/sonar/project-key.js +120 -0
- package/src/sonar/scanner.js +307 -0
- package/src/sonar/token-bootstrap.js +205 -0
- package/src/sonar/token-recovery.js +67 -0
- package/src/spec-review/refine-loop.js +58 -0
- package/src/spec-review/run-spec-review.js +119 -0
- package/src/start/assessment.js +74 -0
- package/src/start/maturity.js +73 -0
- package/src/start/start-decider-role.js +79 -0
- package/src/start/sweep.js +157 -0
- package/src/sync/apply-canvas-patch.js +55 -0
- package/src/sync/detect-drift.js +113 -0
- package/src/tournament/crown.js +88 -0
- package/src/tournament/judge.js +150 -0
- package/src/tournament/run.js +142 -0
- package/src/tournament/scoreboard.js +124 -0
- package/src/tracker-bootstrap.js +44 -0
- package/src/types/agent.js +55 -0
- package/src/types/config.js +114 -0
- package/src/types/hu.js +47 -0
- package/src/types/index.js +38 -0
- package/src/types/policy.js +43 -0
- package/src/types/session.js +75 -0
- package/src/types/solomon.js +87 -0
- package/src/types/stage.js +68 -0
- package/src/utils/agent-detect.js +93 -0
- package/src/utils/ai-trash.js +48 -0
- package/src/utils/async-lock.js +31 -0
- package/src/utils/atomic-write.js +6 -0
- package/src/utils/banner.js +66 -0
- package/src/utils/binary-sources.js +70 -0
- package/src/utils/board-prompt-bridge.js +108 -0
- package/src/utils/budget.js +229 -0
- package/src/utils/cli-ask-question.js +93 -0
- package/src/utils/cli-progress.js +220 -0
- package/src/utils/cli-run-log.js +83 -0
- package/src/utils/cwd-confirm.js +39 -0
- package/src/utils/derive-project-name-from-cwd.js +119 -0
- package/src/utils/display/event-handlers.js +403 -0
- package/src/utils/display/formatters.js +132 -0
- package/src/utils/display/header.js +47 -0
- package/src/utils/display/resume-hint.js +41 -0
- package/src/utils/display/session-summary.js +118 -0
- package/src/utils/display/solomon.js +42 -0
- package/src/utils/display/spec-findings.js +44 -0
- package/src/utils/doc-links.js +29 -0
- package/src/utils/docker-install.js +34 -0
- package/src/utils/escape-regexp.js +15 -0
- package/src/utils/events.js +35 -0
- package/src/utils/fs.js +19 -0
- package/src/utils/garbage-collector.js +481 -0
- package/src/utils/git.js +279 -0
- package/src/utils/home-migration.js +87 -0
- package/src/utils/injection-guard.js +186 -0
- package/src/utils/install-hints.js +180 -0
- package/src/utils/json-extract.js +64 -0
- package/src/utils/locale.js +59 -0
- package/src/utils/logger.js +96 -0
- package/src/utils/managed-markers.js +93 -0
- package/src/utils/manifest-sniff.js +82 -0
- package/src/utils/messages.js +61 -0
- package/src/utils/model-selector.js +107 -0
- package/src/utils/os-detect.js +79 -0
- package/src/utils/paths.js +13 -0
- package/src/utils/pending-user-action.js +95 -0
- package/src/utils/port-check.js +6 -0
- package/src/utils/port-occupant.js +96 -0
- package/src/utils/pricing.js +29 -0
- package/src/utils/process.js +4 -0
- package/src/utils/project-detect.js +160 -0
- package/src/utils/prompt-project-name.js +35 -0
- package/src/utils/provider-env.js +116 -0
- package/src/utils/qmd-collection.js +72 -0
- package/src/utils/qmd-detect.js +18 -0
- package/src/utils/qmd-install.js +37 -0
- package/src/utils/quota-simulator.js +56 -0
- package/src/utils/rate-limit-detector.js +181 -0
- package/src/utils/repo-cleaner.js +79 -0
- package/src/utils/retry.js +88 -0
- package/src/utils/role-assigner.js +137 -0
- package/src/utils/role-env.js +58 -0
- package/src/utils/rtk-detect.js +18 -0
- package/src/utils/rtk-install.js +38 -0
- package/src/utils/rtk-wrapper.js +87 -0
- package/src/utils/run-context.js +75 -0
- package/src/utils/run-log.js +217 -0
- package/src/utils/run-registry.js +9 -0
- package/src/utils/shared-paths.js +12 -0
- package/src/utils/squeezr-detect.js +21 -0
- package/src/utils/squeezr-install.js +37 -0
- package/src/utils/stack-detect.js +135 -0
- package/src/utils/stall-detector.js +159 -0
- package/src/utils/status-dashboard.js +254 -0
- package/src/utils/task-file.js +109 -0
- package/src/utils/telemetry.js +124 -0
- package/src/utils/templates-root.js +61 -0
- package/src/utils/tool-call-extractor.js +56 -0
- package/src/utils/tool-governor.js +116 -0
- package/src/utils/tool-installer.js +93 -0
- package/src/utils/update-check.js +280 -0
- package/src/utils/vector-store-orphans.js +89 -0
- package/src/utils/welcome.js +47 -0
- package/src/utils/with-timeout.js +42 -0
- package/src/utils/wizard.js +47 -0
- package/src/webperf/cwv-gate.js +94 -0
- package/src/webperf/devtools-detect.js +112 -0
- package/src/webperf/scanner.js +209 -0
- package/src/webperf/webperf-role-integration.js +66 -0
- package/templates/coder-rules.md +45 -0
- package/templates/docker-compose.sonar.yml +60 -0
- package/templates/domains/example-dental.md +57 -0
- package/templates/kj.config.yml +128 -0
- package/templates/review-rules.md +17 -0
- package/templates/roles/architect/anthropic.md +74 -0
- package/templates/roles/architect/default.md +72 -0
- package/templates/roles/architect/google.md +61 -0
- package/templates/roles/architect/openai.md +60 -0
- package/templates/roles/architect/opencode.md +59 -0
- package/templates/roles/architect.md +76 -0
- package/templates/roles/audit.md +68 -0
- package/templates/roles/coder/anthropic.md +81 -0
- package/templates/roles/coder/default.md +78 -0
- package/templates/roles/coder/google.md +87 -0
- package/templates/roles/coder/openai.md +68 -0
- package/templates/roles/coder/opencode.md +58 -0
- package/templates/roles/coder.md +152 -0
- package/templates/roles/commiter.md +44 -0
- package/templates/roles/discover.md +167 -0
- package/templates/roles/domain-curator.md +52 -0
- package/templates/roles/hu-reviewer.md +236 -0
- package/templates/roles/impeccable-design.md +87 -0
- package/templates/roles/impeccable.md +125 -0
- package/templates/roles/karajan-brain.md +95 -0
- package/templates/roles/onboarder.md +45 -0
- package/templates/roles/planner/anthropic.md +59 -0
- package/templates/roles/planner/default.md +57 -0
- package/templates/roles/planner/google.md +75 -0
- package/templates/roles/planner/openai.md +55 -0
- package/templates/roles/planner/opencode.md +62 -0
- package/templates/roles/planner.md +61 -0
- package/templates/roles/refactorer.md +48 -0
- package/templates/roles/repairer.md +103 -0
- package/templates/roles/researcher.md +41 -0
- package/templates/roles/reviewer/anthropic.md +61 -0
- package/templates/roles/reviewer/default.md +62 -0
- package/templates/roles/reviewer/google.md +63 -0
- package/templates/roles/reviewer/openai.md +57 -0
- package/templates/roles/reviewer/opencode.md +42 -0
- package/templates/roles/reviewer-paranoid.md +38 -0
- package/templates/roles/reviewer-relaxed.md +34 -0
- package/templates/roles/reviewer-strict.md +37 -0
- package/templates/roles/reviewer.md +62 -0
- package/templates/roles/security.md +54 -0
- package/templates/roles/solomon/anthropic.md +71 -0
- package/templates/roles/solomon/default.md +83 -0
- package/templates/roles/solomon/google.md +61 -0
- package/templates/roles/solomon/openai.md +53 -0
- package/templates/roles/solomon/opencode.md +55 -0
- package/templates/roles/solomon.md +83 -0
- package/templates/roles/sonar.md +49 -0
- package/templates/roles/spec-reviewer.md +47 -0
- package/templates/roles/tester.md +50 -0
- package/templates/roles/triage.md +69 -0
- package/templates/skills/kj-architect.md +45 -0
- package/templates/skills/kj-audit.md +63 -0
- package/templates/skills/kj-board.md +16 -0
- package/templates/skills/kj-code.md +51 -0
- package/templates/skills/kj-csv-transform.md +40 -0
- package/templates/skills/kj-data-report.md +44 -0
- package/templates/skills/kj-discover.md +24 -0
- package/templates/skills/kj-rag-query.md +50 -0
- package/templates/skills/kj-review.md +47 -0
- package/templates/skills/kj-run.md +73 -0
- package/templates/skills/kj-security.md +49 -0
- package/templates/skills/kj-sonar.md +41 -0
- package/templates/skills/kj-sql-analysis.md +40 -0
- package/templates/skills/kj-test.md +40 -0
- package/templates/workflows/automerge.yml +30 -0
- package/templates/workflows/houston-override.yml +46 -0
- package/templates/workflows/kj-ci-gateway.yml +58 -0
- package/vendor/tree-sitter-grammars/README.md +21 -0
- package/vendor/tree-sitter-grammars/go.wasm +0 -0
- package/vendor/tree-sitter-grammars/java.wasm +0 -0
- package/vendor/tree-sitter-grammars/python.wasm +0 -0
- package/vendor/tree-sitter-grammars/rust.wasm +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kj harden` — install the quality harness (git hooks) into any repo.
|
|
3
|
+
*
|
|
4
|
+
* Thin CLI layer over harden-engine (KJC-TSK-0555): resolves stack-aware
|
|
5
|
+
* lint/format/test commands, runs the installer and reports. Config files
|
|
6
|
+
* (eslint/prettier) and CI gates land in later slices (H-C / H-D).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
import { loadConfig } from "../config.js";
|
|
13
|
+
import { resolveTestOnPush } from "../harden/test-on-push.js";
|
|
14
|
+
import { compareHarden, formatAdvisoryReport } from "../harden/advisory.js";
|
|
15
|
+
import { interactiveHarden } from "../harden/interactive.js";
|
|
16
|
+
import { createWizard, isTTY } from "../utils/wizard.js";
|
|
17
|
+
import { installConfigsForRoots } from "../harden/config-engine.js";
|
|
18
|
+
import { installGuidelines } from "../harden/guidelines-engine.js";
|
|
19
|
+
import { commandsForLanguage } from "../harden/hook-commands.js";
|
|
20
|
+
import { installHooks } from "../harden/harden-engine.js";
|
|
21
|
+
import { installHarnessHooks } from "../harden/harness-hooks.js";
|
|
22
|
+
import { installSentinelHooks } from "../harden/sentinel-hooks.js";
|
|
23
|
+
import { detectStackRoots } from "../harden/stack-roots.js";
|
|
24
|
+
import { installWorkflows } from "../harden/workflow-engine.js";
|
|
25
|
+
import { detectTestFramework } from "../utils/project-detect.js";
|
|
26
|
+
import { ensureIdentity } from "../identity/bootstrap.js";
|
|
27
|
+
|
|
28
|
+
const JS_TEST_CMD = {
|
|
29
|
+
vitest: "npx vitest run",
|
|
30
|
+
jest: "npx jest",
|
|
31
|
+
mocha: "npx mocha",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Per-repo harden scope, persisted in package.json `kj.harden` so a repo with
|
|
36
|
+
* sub-tools (e.g. a python wrapper) excludes them once instead of on every
|
|
37
|
+
* invocation (KJC-TSK-0564). CLI flags are merged on top.
|
|
38
|
+
*/
|
|
39
|
+
function readHardenConfig(projectDir) {
|
|
40
|
+
const pkgPath = join(projectDir, "package.json");
|
|
41
|
+
if (!existsSync(pkgPath)) return {};
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(pkgPath, "utf8")).kj?.harden ?? {};
|
|
44
|
+
} catch {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the hook's lint/format/test commands for the primary language.
|
|
51
|
+
* Non-JS stacks use their native toolchain (go/ruff/…); JS/TS is built from
|
|
52
|
+
* the project's own package.json scripts so no npm command is ever assumed.
|
|
53
|
+
*/
|
|
54
|
+
export async function resolveCmds(projectDir, language) {
|
|
55
|
+
const lang = language ?? detectStackRoots(projectDir)[0]?.language ?? null;
|
|
56
|
+
const cmds = { ...commandsForLanguage(lang) };
|
|
57
|
+
if (lang !== "javascript" && lang !== "typescript") return cmds;
|
|
58
|
+
|
|
59
|
+
const pkgPath = join(projectDir, "package.json");
|
|
60
|
+
if (existsSync(pkgPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const scripts = JSON.parse(readFileSync(pkgPath, "utf8")).scripts ?? {};
|
|
63
|
+
if (scripts.lint) cmds.lint = "npm run -s lint";
|
|
64
|
+
if (scripts["format:check"]) cmds.format = "npm run -s format:check";
|
|
65
|
+
else if (scripts.format) cmds.format = "npm run -s format";
|
|
66
|
+
if (scripts.test) cmds.test = "npm test";
|
|
67
|
+
} catch {
|
|
68
|
+
/* unreadable package.json → fall back to framework detection */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!cmds.test) {
|
|
72
|
+
const { framework } = await detectTestFramework(projectDir);
|
|
73
|
+
if (framework && JS_TEST_CMD[framework]) cmds.test = JS_TEST_CMD[framework];
|
|
74
|
+
}
|
|
75
|
+
return cmds;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function hardenCommand({
|
|
79
|
+
projectDir = process.cwd(),
|
|
80
|
+
profile = "standard",
|
|
81
|
+
config = true,
|
|
82
|
+
ci = true,
|
|
83
|
+
guidelines = true,
|
|
84
|
+
mutation = false,
|
|
85
|
+
dryRun = false,
|
|
86
|
+
json = false,
|
|
87
|
+
report = false,
|
|
88
|
+
interactive = false,
|
|
89
|
+
only = [],
|
|
90
|
+
exclude = [],
|
|
91
|
+
logger = console,
|
|
92
|
+
} = {}) {
|
|
93
|
+
const repoCfg = readHardenConfig(projectDir);
|
|
94
|
+
const onlyDirs = [...(repoCfg.only ?? []), ...only];
|
|
95
|
+
const excludeDirs = [...(repoCfg.exclude ?? []), ...exclude];
|
|
96
|
+
|
|
97
|
+
// --report is read-only: compare against the kj standard and print/emit the
|
|
98
|
+
// advisory (Advisory B, KJC-TSK-0566), honouring the same scope as an install
|
|
99
|
+
// so it never proposes a root that `kj harden` would skip. Writes nothing.
|
|
100
|
+
if (report) {
|
|
101
|
+
const result = compareHarden({ projectDir, profile, only: onlyDirs, exclude: excludeDirs });
|
|
102
|
+
if (json) logger.info?.(JSON.stringify(result));
|
|
103
|
+
else for (const line of formatAdvisoryReport(result)) logger.info?.(line);
|
|
104
|
+
return { ok: true, report: true, ...result };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// --interactive: adopt the kj standard piece by piece, default-safe (keep the
|
|
108
|
+
// user's own). Only meaningful with a TTY — without one (CI, --json) we fall
|
|
109
|
+
// through to the normal seed-if-absent install so nothing breaks (KJC-TSK-0567).
|
|
110
|
+
if (interactive && isTTY() && !json) {
|
|
111
|
+
const wizard = createWizard();
|
|
112
|
+
try {
|
|
113
|
+
return await interactiveHarden({
|
|
114
|
+
projectDir,
|
|
115
|
+
profile,
|
|
116
|
+
only: onlyDirs,
|
|
117
|
+
exclude: excludeDirs,
|
|
118
|
+
ask: (prompt, def) => wizard.confirm(prompt, def),
|
|
119
|
+
logger,
|
|
120
|
+
});
|
|
121
|
+
} finally {
|
|
122
|
+
wizard.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const roots = detectStackRoots(projectDir, { only: onlyDirs, exclude: excludeDirs });
|
|
127
|
+
const cmds = await resolveCmds(projectDir, roots[0]?.language ?? null);
|
|
128
|
+
// KJC-TSK-0647: CI already running the suite per PR ⇒ pre-push drops its
|
|
129
|
+
// test command (false-red source under local parallelism); opt back in
|
|
130
|
+
// via package.json kj.harden.test_on_push.
|
|
131
|
+
const top = resolveTestOnPush({ projectDir, repoCfg, testCmd: cmds.test });
|
|
132
|
+
if (top.reason) {
|
|
133
|
+
logger.info?.(`kj harden: ${top.reason}`);
|
|
134
|
+
cmds.test = undefined;
|
|
135
|
+
}
|
|
136
|
+
// KJC-TSK-0648: branch-first guard — the base branch only moves via PR.
|
|
137
|
+
// Resolved from the project's kj config (default "main"); best-effort so
|
|
138
|
+
// harden keeps working on repos that never ran kj init.
|
|
139
|
+
let baseBranch = "main";
|
|
140
|
+
try {
|
|
141
|
+
baseBranch = (await loadConfig(projectDir))?.base_branch || "main";
|
|
142
|
+
} catch { /* no kj config — default stands */ }
|
|
143
|
+
let result;
|
|
144
|
+
try {
|
|
145
|
+
result = await installHooks({ projectDir, profile, cmds, dryRun, baseBranch });
|
|
146
|
+
// KJC-TSK-0710 — the TOOL gate: rules imposed at tool time (Claude Code
|
|
147
|
+
// PreToolUse). Standard+ only; minimal stays hooks-lite.
|
|
148
|
+
if (profile !== "minimal" && !dryRun) {
|
|
149
|
+
const hh = installHarnessHooks({ projectDir, logger });
|
|
150
|
+
result.harnessHooks = hh.wired ? "wired" : "script-only";
|
|
151
|
+
// KJC-TSK-0713 — the Sentinel: method state + Stop gate (turn cannot
|
|
152
|
+
// end red). Same Claude-only harness surface as the tool gate.
|
|
153
|
+
const sh = installSentinelHooks({ projectDir, logger });
|
|
154
|
+
result.sentinelHooks = sh.wired ? "wired" : "script-only";
|
|
155
|
+
}
|
|
156
|
+
} catch (err) {
|
|
157
|
+
if (json) logger.info?.(JSON.stringify({ ok: false, error: err.message }));
|
|
158
|
+
else logger.error?.(`kj harden: ${err.message}`);
|
|
159
|
+
return { ok: false, error: err.message };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Config (lint/format/commit) ships with standard+, per language root so a
|
|
163
|
+
// fullstack monorepo is hardened on every side, not just one.
|
|
164
|
+
const withConfig = config && profile !== "minimal";
|
|
165
|
+
const cfg = withConfig ? installConfigsForRoots({ projectDir, roots, dryRun }) : null;
|
|
166
|
+
const withCi = ci && profile !== "minimal";
|
|
167
|
+
const wf = withCi
|
|
168
|
+
? installWorkflows({ projectDir, language: roots[0]?.language ?? null, profile, mutation, dryRun })
|
|
169
|
+
: null;
|
|
170
|
+
const withGuidelines = guidelines && profile !== "minimal";
|
|
171
|
+
const gl = withGuidelines ? installGuidelines({ projectDir, dryRun }) : null;
|
|
172
|
+
const out = {
|
|
173
|
+
ok: true,
|
|
174
|
+
...result,
|
|
175
|
+
configs: cfg?.configs ?? [],
|
|
176
|
+
workflows: wf?.workflows ?? [],
|
|
177
|
+
guidelines: gl?.guidelines ?? [],
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if (json) {
|
|
181
|
+
logger.info?.(JSON.stringify(out));
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const verb = dryRun ? "would install" : "installed";
|
|
186
|
+
logger.info?.(`kj harden (${profile}) — ${verb} ${result.hooks.length} hook(s) → ${result.hooksPath}`);
|
|
187
|
+
for (const h of result.hooks) logger.info?.(` • ${h.hook}: ${h.action}`);
|
|
188
|
+
for (const c of out.configs) {
|
|
189
|
+
const note = c.note ? ` (${c.note})` : "";
|
|
190
|
+
logger.info?.(` • ${c.file}: ${c.action}${note}`);
|
|
191
|
+
}
|
|
192
|
+
for (const w of out.workflows) logger.info?.(` • ${w.file}: ${w.action}`);
|
|
193
|
+
for (const g of out.guidelines) logger.info?.(` • ${g.file}: ${g.action}`);
|
|
194
|
+
if (!dryRun) logger.info?.("core.hooksPath set. Verify later with `kj check`.");
|
|
195
|
+
// IDN-A (KJC-TSK-0762): a hardened clone declares who works it. Captured
|
|
196
|
+
// only with a human confirming; headless runs get the pending command.
|
|
197
|
+
if (!dryRun) {
|
|
198
|
+
const id = await ensureIdentity({ projectDir, logger });
|
|
199
|
+
out.identity = id.declared ? id.identity : null;
|
|
200
|
+
if (id.pending) out.identityPending = id.pending;
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kj hu add|move|list` (AB-H, KJC-TSK-0658) — board writes for the brain.
|
|
3
|
+
* The v4 playbook orders "card first", but until now only the headless
|
|
4
|
+
* planner could create HUs. These commands operate on a per-project
|
|
5
|
+
* "brain-backlog" plan (created on first use) so any host agent can track
|
|
6
|
+
* work in the HU Board without the subprocess pipeline.
|
|
7
|
+
*/
|
|
8
|
+
import { addHu, updateHuStatus } from "../plan/plan-hu-ops.js";
|
|
9
|
+
import { generatePlanId } from "../plan/plan-id.js";
|
|
10
|
+
import { savePlan, listPlans, loadPlan } from "../plan/plan-store.js";
|
|
11
|
+
import { detectHostAgent } from "../utils/agent-detect.js";
|
|
12
|
+
|
|
13
|
+
// KJC-TSK-0661 (Jorge's friction): every HU records WHO created it — the
|
|
14
|
+
// board must never show work nobody can trace. Host agent env → that agent;
|
|
15
|
+
// a human typing in a terminal → "human"; anything else headless → "agent".
|
|
16
|
+
export function creatorLabel() {
|
|
17
|
+
return detectHostAgent() || (process.stdin.isTTY ? "human" : "agent");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const HU_STATUSES = ["pending", "running", "done", "failed", "skipped"];
|
|
21
|
+
const BACKLOG_NAME = "brain-backlog";
|
|
22
|
+
|
|
23
|
+
// KJC-TSK-0675 (issue #1288): agents that skip `kj hu list` created twins of
|
|
24
|
+
// existing work — sometimes in a DIFFERENT plan. Titles are compared
|
|
25
|
+
// normalized (case/punctuation-insensitive) across every live HU of every
|
|
26
|
+
// plan: identical → refuse; mostly-overlapping tokens → warn with candidates.
|
|
27
|
+
const normTitle = (t) => String(t || "").toLowerCase().replaceAll(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
28
|
+
const titleTokens = (t) => new Set(normTitle(t).split(" ").filter((w) => w.length > 2));
|
|
29
|
+
|
|
30
|
+
export function findTitleMatches(title, allHus) {
|
|
31
|
+
const norm = normTitle(title);
|
|
32
|
+
const toks = titleTokens(title);
|
|
33
|
+
const identical = [];
|
|
34
|
+
const similar = [];
|
|
35
|
+
for (const h of allHus) {
|
|
36
|
+
if (h.status === "skipped") continue; // discarded cards don't reserve titles
|
|
37
|
+
if (normTitle(h.title) === norm) { identical.push(h); continue; }
|
|
38
|
+
const other = titleTokens(h.title);
|
|
39
|
+
const shared = [...toks].filter((w) => other.has(w)).length;
|
|
40
|
+
const smaller = Math.min(toks.size, other.size);
|
|
41
|
+
if (smaller > 0 && shared / smaller >= 0.8) similar.push(h);
|
|
42
|
+
}
|
|
43
|
+
return { identical, similar };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function backlogPlan(projectDir) {
|
|
47
|
+
const plans = await listPlans(projectDir);
|
|
48
|
+
const existing = plans.find((p) => p.alias === BACKLOG_NAME || p.name === BACKLOG_NAME);
|
|
49
|
+
if (existing) return loadPlan(projectDir, existing.planId);
|
|
50
|
+
const plan = {
|
|
51
|
+
version: 2, planId: generatePlanId(), name: BACKLOG_NAME,
|
|
52
|
+
task: "Host-agent tracked work (v4 environment)",
|
|
53
|
+
status: "ready", hus: [], createdAt: new Date().toISOString(),
|
|
54
|
+
};
|
|
55
|
+
const planId = await savePlan(projectDir, plan);
|
|
56
|
+
return loadPlan(projectDir, planId);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function huCommand({ config = null, action, args = [], flags = {} }) {
|
|
60
|
+
const projectDir = config?.projectDir || process.cwd();
|
|
61
|
+
const emit = (obj, human) => { console.log(flags.json ? JSON.stringify(obj) : human); return obj; };
|
|
62
|
+
|
|
63
|
+
// KJC-TSK-0684 (issue #1287): with an external board declared, kj never
|
|
64
|
+
// maintains a parallel HU Board — writes are refused with the pointer.
|
|
65
|
+
if (config?.state_backend === "external" && (action === "add" || action === "move")) {
|
|
66
|
+
const name = config?.board?.name || "an external board";
|
|
67
|
+
throw new Error(
|
|
68
|
+
`this project's board lives in ${name} (state_backend: external) — create and move cards there, `
|
|
69
|
+
+ `through your agent's MCP/tools. kj does not mirror external boards.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (action === "list") {
|
|
74
|
+
const plans = await listPlans(projectDir);
|
|
75
|
+
const rows = [];
|
|
76
|
+
for (const meta of plans) {
|
|
77
|
+
const plan = await loadPlan(projectDir, meta.planId);
|
|
78
|
+
for (const h of plan.hus || []) {
|
|
79
|
+
rows.push({
|
|
80
|
+
id: h.id, short_id: h.short_id, title: h.title, status: h.status,
|
|
81
|
+
plan: plan.alias || plan.planId,
|
|
82
|
+
// KJC-TSK-0661: provenance — where a card came from is part of
|
|
83
|
+
// the card. Older HUs predate the stamp: shown as "?".
|
|
84
|
+
created_by: h.created_by || null, created_at: h.createdAt || null,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (flags.json) { console.log(JSON.stringify(rows)); return rows; }
|
|
89
|
+
for (const r of rows) {
|
|
90
|
+
const origin = `${r.plan} · by ${r.created_by || "?"}${r.created_at ? ` · ${r.created_at.slice(0, 10)}` : ""}`;
|
|
91
|
+
console.log(`${(r.short_id || r.id).padEnd(28)} ${r.status.padEnd(8)} ${r.title} [${origin}]`);
|
|
92
|
+
}
|
|
93
|
+
if (rows.length === 0) console.log("no HUs yet — create one with: kj hu add \"<story>\"");
|
|
94
|
+
else console.log("→ work one: ask your agent, or kj run --plan <plan> · discard one: kj hu move <id> skipped");
|
|
95
|
+
return rows;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (action === "add") {
|
|
99
|
+
const title = args[0];
|
|
100
|
+
if (!title || !title.trim()) throw new Error("kj hu add requires a title: kj hu add \"<story>\"");
|
|
101
|
+
// Cross-plan title dedup (KJC-TSK-0675) — check BEFORE creating anything.
|
|
102
|
+
const allHus = [];
|
|
103
|
+
for (const meta of await listPlans(projectDir)) {
|
|
104
|
+
const p = await loadPlan(projectDir, meta.planId);
|
|
105
|
+
for (const h of p.hus || []) allHus.push({ ...h, plan: p.alias || p.name || p.planId });
|
|
106
|
+
}
|
|
107
|
+
const { identical, similar } = findTitleMatches(title, allHus);
|
|
108
|
+
if (identical.length > 0) {
|
|
109
|
+
const ref = identical[0];
|
|
110
|
+
throw new Error(
|
|
111
|
+
`An HU with this title already exists: ${ref.short_id || ref.id} (status: ${ref.status}, plan: ${ref.plan}). `
|
|
112
|
+
+ `HUs are never duplicated — work that card, move it with: kj hu move ${ref.short_id || ref.id} <status>, `
|
|
113
|
+
+ `or run kj hu list before adding.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (similar.length > 0) {
|
|
117
|
+
const plural = similar.length === 1 ? "" : "s";
|
|
118
|
+
const candidates = similar.map((h) => ` · ${h.short_id || h.id} (${h.status}, plan: ${h.plan}) "${h.title}"`).join("\n");
|
|
119
|
+
console.warn(`⚠ possible duplicate${plural} — check before working it:\n${candidates}`);
|
|
120
|
+
}
|
|
121
|
+
const plan = await backlogPlan(projectDir);
|
|
122
|
+
// KJC-TSK-0669 (absolute rule): cards are permanent. The delete-and-
|
|
123
|
+
// recreate "fix" an agent improvises loses history and duplicates ids —
|
|
124
|
+
// refuse it with the norm spelled out.
|
|
125
|
+
if (flags.id) {
|
|
126
|
+
const dup = (plan.hus || []).find((h) => h.short_id === flags.id);
|
|
127
|
+
if (dup) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`HU "${flags.id}" already exists (status: ${dup.status}). HUs are never deleted or recreated — `
|
|
130
|
+
+ `update its state with: kj hu move ${flags.id} <pending|running|done|failed|skipped>, `
|
|
131
|
+
+ `or discard it with: kj hu move ${flags.id} skipped`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// KJC-TSK-0678 (issue #1296): complete HUs in ONE call. --ac / --tests
|
|
136
|
+
// are repeatable AND accept multiline strings; --criteria stays as the
|
|
137
|
+
// legacy single-criterion alias.
|
|
138
|
+
const TASK_TYPES = ["sw", "infra", "doc", "add-tests", "refactor"];
|
|
139
|
+
if (flags.taskType && !TASK_TYPES.includes(flags.taskType)) {
|
|
140
|
+
throw new Error(`invalid --task-type "${flags.taskType}" — valid: ${TASK_TYPES.join(", ")}`);
|
|
141
|
+
}
|
|
142
|
+
const splitLines = (v) => (Array.isArray(v) ? v : v ? [v] : [])
|
|
143
|
+
.flatMap((s) => String(s).split("\n")).map((s) => s.trim()).filter(Boolean);
|
|
144
|
+
const hu = addHu(plan, {
|
|
145
|
+
title,
|
|
146
|
+
short_id: flags.id || null,
|
|
147
|
+
acceptance_criteria: [...splitLines(flags.ac), ...splitLines(flags.criteria)],
|
|
148
|
+
acceptance_tests: splitLines(flags.tests),
|
|
149
|
+
scope: flags.scope || null,
|
|
150
|
+
task_type: flags.taskType || undefined,
|
|
151
|
+
});
|
|
152
|
+
hu.created_by = creatorLabel();
|
|
153
|
+
await savePlan(projectDir, plan);
|
|
154
|
+
const missing = [];
|
|
155
|
+
if (hu.acceptance_criteria.length === 0) missing.push("acceptance criteria (--ac \"...\")");
|
|
156
|
+
if (hu.acceptance_tests.length === 0) missing.push("tests (--tests \"...\")");
|
|
157
|
+
if (missing.length > 0) {
|
|
158
|
+
console.warn(`⚠ incomplete spec — kj run's spec review will flag it. Missing: ${missing.join(", ")}`);
|
|
159
|
+
}
|
|
160
|
+
return emit({
|
|
161
|
+
id: hu.id, short_id: hu.short_id, status: hu.status, created_by: hu.created_by,
|
|
162
|
+
acceptance_criteria: hu.acceptance_criteria, acceptance_tests: hu.acceptance_tests,
|
|
163
|
+
scope: hu.scope, task_type: hu.task_type,
|
|
164
|
+
}, `✓ HU created: ${hu.short_id || hu.id} (pending, by ${hu.created_by}) — it shows up in \`kj board\``);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (action === "move") {
|
|
168
|
+
const [ref, status] = args;
|
|
169
|
+
if (!ref || !status) throw new Error("usage: kj hu move <id> <status>");
|
|
170
|
+
if (!HU_STATUSES.includes(status)) {
|
|
171
|
+
throw new Error(`invalid status "${status}" — valid: ${HU_STATUSES.join(", ")}`);
|
|
172
|
+
}
|
|
173
|
+
// Exact canonical id wins outright (it IS the disambiguator); only then
|
|
174
|
+
// fall back to short_id matches — which can repeat between plans, so
|
|
175
|
+
// silently moving the first hit could move the wrong card.
|
|
176
|
+
const byId = [];
|
|
177
|
+
const byShort = [];
|
|
178
|
+
const running = [];
|
|
179
|
+
for (const meta of await listPlans(projectDir)) {
|
|
180
|
+
const plan = await loadPlan(projectDir, meta.planId);
|
|
181
|
+
for (const hu of plan.hus || []) {
|
|
182
|
+
if (hu.id === ref) byId.push({ plan, hu });
|
|
183
|
+
else if (hu.short_id === ref) byShort.push({ plan, hu });
|
|
184
|
+
if (hu.status === "running") running.push(hu);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const matches = byId.length > 0 ? byId : byShort;
|
|
188
|
+
if (matches.length === 0) throw new Error(`HU "${ref}" not found — see kj hu list`);
|
|
189
|
+
if (matches.length > 1) {
|
|
190
|
+
const ids = matches.map((m) => m.hu.id).join(", ");
|
|
191
|
+
throw new Error(`"${ref}" is ambiguous (${matches.length} matches: ${ids}) — use the full id`);
|
|
192
|
+
}
|
|
193
|
+
const { plan, hu } = matches[0];
|
|
194
|
+
// KJC-TSK-0688 (MG-C): the nudge fires AT the deviation — a second
|
|
195
|
+
// concurrent task belongs in its own lane, not in the shared tree.
|
|
196
|
+
const others = running.filter((r) => r.id !== hu.id);
|
|
197
|
+
if (status === "running" && hu.status !== "running" && others.length > 0) {
|
|
198
|
+
const slug = String(hu.short_id || hu.id).toLowerCase();
|
|
199
|
+
console.warn(
|
|
200
|
+
`⚠ ${others.map((r) => r.short_id || r.id).join(", ")} ${others.length === 1 ? "is" : "are"} already running — `
|
|
201
|
+
+ `a second concurrent task should live in its own lane: kj worktree start ${slug}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
updateHuStatus(plan, hu.id, status);
|
|
205
|
+
await savePlan(projectDir, plan);
|
|
206
|
+
return emit({ id: hu.id, status }, `✓ ${hu.short_id || hu.id} → ${status}`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
throw new Error(`unknown action "${action}" — use: add | move | list`);
|
|
210
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kj identity show|set` (IDN-A, KJC-TSK-0762, epic KJC-PCS-0079).
|
|
3
|
+
*
|
|
4
|
+
* show — declared identity vs what is ACTIVE now; exit 2 on mismatch or
|
|
5
|
+
* when nothing is declared (scriptable: the gate and hooks reuse it).
|
|
6
|
+
* set — capture the effective gh account + git email (or --gh/--email),
|
|
7
|
+
* confirm on a TTY, write .karajan/identity.local.yml. Never invents:
|
|
8
|
+
* no session and no flags → exit 1.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readIdentity, writeIdentity } from "../identity/store.js";
|
|
12
|
+
import { activeGhUser, effectiveGitEmail } from "../identity/detect.js";
|
|
13
|
+
import { compareIdentity } from "../identity/compare.js";
|
|
14
|
+
import { createWizard, isTTY } from "../utils/wizard.js";
|
|
15
|
+
|
|
16
|
+
export async function identityCommand({ action = "show", config, flags = {}, deps = {} }) {
|
|
17
|
+
const projectDir = config?.projectDir || process.cwd();
|
|
18
|
+
const log = deps.log || console.log;
|
|
19
|
+
const tty = deps.isTTY || isTTY;
|
|
20
|
+
const detectOpts = { hostsPath: deps.hostsPath, gitFn: deps.gitFn };
|
|
21
|
+
const effective = {
|
|
22
|
+
gh_user: activeGhUser(detectOpts.hostsPath ? { hostsPath: detectOpts.hostsPath } : {}),
|
|
23
|
+
git_email: effectiveGitEmail(projectDir, detectOpts.gitFn ? { gitFn: detectOpts.gitFn } : {}),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (action === "set") {
|
|
27
|
+
const candidate = { gh_user: flags.gh || effective.gh_user, git_email: flags.email || effective.git_email };
|
|
28
|
+
if (!candidate.gh_user || !candidate.git_email) {
|
|
29
|
+
log(`kj identity: cannot declare — gh account: ${candidate.gh_user ?? "no session"}, git email: ${candidate.git_email ?? "none"}. Log in / set git config, or pass --gh <user> --email <email>.`);
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
if (tty() && !flags.yes) {
|
|
33
|
+
const wizard = (deps.makeWizard || createWizard)();
|
|
34
|
+
try {
|
|
35
|
+
const ok = await wizard.confirm(`Bind this clone to gh ${candidate.gh_user} / git ${candidate.git_email}?`, true);
|
|
36
|
+
if (!ok) { log("kj identity: not declared."); return 1; }
|
|
37
|
+
} finally { wizard.close(); }
|
|
38
|
+
} else if (!flags.gh || !flags.email) {
|
|
39
|
+
// Proven live on day one: the active gh session had been flipped by
|
|
40
|
+
// ANOTHER session, and --yes bound the clone to the wrong account.
|
|
41
|
+
// Binding without confirmation is allowed, but never silent.
|
|
42
|
+
log("kj identity: WARNING — binding the ACTIVE session as-is without confirmation (another session may have switched it); prefer --gh/--email explicitly and verify with `kj identity show`.");
|
|
43
|
+
}
|
|
44
|
+
writeIdentity(projectDir, candidate);
|
|
45
|
+
log(`kj identity: declared gh ${candidate.gh_user} / git ${candidate.git_email} → .karajan/identity.local.yml (ignored by git).`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const declared = readIdentity(projectDir);
|
|
50
|
+
const result = compareIdentity(declared, effective);
|
|
51
|
+
if (!declared) {
|
|
52
|
+
log("kj identity: no identity declared for this clone — run `kj identity set`.");
|
|
53
|
+
return 2;
|
|
54
|
+
}
|
|
55
|
+
const mark = (field) => (result.mismatches.some((m) => m.field === field) ? "DISTINTA" : "ACTIVA");
|
|
56
|
+
log(`gh_user ${declared.gh_user} [${mark("gh_user")}: ${effective.gh_user ?? "no session"}]`);
|
|
57
|
+
log(`git_email ${declared.git_email} [${mark("git_email")}: ${effective.git_email ?? "none"}]`);
|
|
58
|
+
for (const m of result.mismatches) log(` → ${m.remedy}`);
|
|
59
|
+
return result.ok ? 0 : 2;
|
|
60
|
+
}
|