@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
package/src/utils/git.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { runCommand } from "./process.js";
|
|
2
|
+
import { getRunContext } from "./run-context.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Module-scoped runner — legacy back-compat for callers outside a
|
|
6
|
+
* `withRunContext` scope (CLI bootstrap, checks/system.js). When running
|
|
7
|
+
* inside a pipeline, `getRunContext()?.runner` takes precedence and
|
|
8
|
+
* provides per-run isolation (TSK-0338). When neither is set we fall
|
|
9
|
+
* back to the bare `runCommand`.
|
|
10
|
+
*
|
|
11
|
+
* @type {((command: string, args?: string[], options?: object) => Promise<object>)|null}
|
|
12
|
+
*/
|
|
13
|
+
let _runner = null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Set the module-scope runner. Retained for back-compat: concurrent
|
|
17
|
+
* `runFlow` invocations should rely on `withRunContext` for isolation,
|
|
18
|
+
* not on this setter (the setter is process-wide and would cause the
|
|
19
|
+
* exact cross-run contamination TSK-0338 eliminates).
|
|
20
|
+
*/
|
|
21
|
+
export function setRunner(runner) {
|
|
22
|
+
_runner = runner;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function run(command, args, ...rest) {
|
|
26
|
+
const ctxRunner = getRunContext()?.runner;
|
|
27
|
+
return (ctxRunner || _runner || runCommand)(command, args, ...rest);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function slugifyTask(task) {
|
|
31
|
+
return String(task)
|
|
32
|
+
.toLowerCase()
|
|
33
|
+
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
34
|
+
.replaceAll(/(^-+)|(-+$)/g, "")
|
|
35
|
+
.slice(0, 40);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function runGit(args, options = {}) {
|
|
39
|
+
const res = await run("git", args, options);
|
|
40
|
+
if (res.exitCode !== 0) {
|
|
41
|
+
throw new Error(`git ${args.join(" ")} failed: ${res.stderr || res.stdout}`);
|
|
42
|
+
}
|
|
43
|
+
return res.stdout.trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function ensureGitRepo() {
|
|
47
|
+
const res = await run("git", ["rev-parse", "--is-inside-work-tree"]);
|
|
48
|
+
return res.exitCode === 0 && res.stdout.trim() === "true";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function currentBranch() {
|
|
52
|
+
return runGit(["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function hasCommits() {
|
|
56
|
+
const res = await run("git", ["rev-parse", "HEAD"]);
|
|
57
|
+
return res.exitCode === 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function fetchBase(baseBranch) {
|
|
61
|
+
await runGit(["fetch", "origin", baseBranch]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function revParse(ref) {
|
|
65
|
+
return runGit(["rev-parse", ref]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* List commits in the range `fromSha..toRef`. Used by the post-loop
|
|
70
|
+
* journal builder to enumerate every commit produced during a `kj run`
|
|
71
|
+
* — both the coder's own commits AND the post-loop scaffold commit —
|
|
72
|
+
* so the user-visible summary doesn't lose track of them. Pre-fix the
|
|
73
|
+
* summary only listed `gitResult.commits` (post-loop only), which made
|
|
74
|
+
* `kj run "..."` runs look like the coder hadn't committed.
|
|
75
|
+
*
|
|
76
|
+
* Returns oldest-first so the list reads in execution order.
|
|
77
|
+
*
|
|
78
|
+
* @param {string|null|undefined} fromSha The SHA right BEFORE the run started
|
|
79
|
+
* (typically `session.session_start_sha`). Empty/missing → returns [].
|
|
80
|
+
* @param {string} [toRef="HEAD"]
|
|
81
|
+
* @returns {Promise<Array<{hash: string, message: string}>>}
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* List the file paths changed in the range `fromSha..toRef`. Used by the
|
|
85
|
+
* plan-adherence metric (KJC-TSK-0376) to score whether the coder's
|
|
86
|
+
* file changes fall within any HU's declared scope.
|
|
87
|
+
*
|
|
88
|
+
* Returns a deduplicated array of file paths, oldest commit's files
|
|
89
|
+
* first. Defensive: returns [] on missing `fromSha`, non-zero git exit,
|
|
90
|
+
* or thrown error — consistent with `listCommitsBetween`'s contract.
|
|
91
|
+
*
|
|
92
|
+
* @param {string|null|undefined} fromSha
|
|
93
|
+
* @param {string} [toRef="HEAD"]
|
|
94
|
+
* @returns {Promise<string[]>}
|
|
95
|
+
*/
|
|
96
|
+
export async function listFilesChangedSince(fromSha, toRef = "HEAD") {
|
|
97
|
+
if (!fromSha) return [];
|
|
98
|
+
const result = await run(
|
|
99
|
+
"git",
|
|
100
|
+
["diff", "--name-only", `${fromSha}..${toRef}`],
|
|
101
|
+
).catch(() => null);
|
|
102
|
+
if (!result || result.exitCode !== 0) return [];
|
|
103
|
+
const lines = String(result.stdout || "")
|
|
104
|
+
.split("\n")
|
|
105
|
+
.map((line) => line.trim())
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
return Array.from(new Set(lines));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function listCommitsBetween(fromSha, toRef = "HEAD") {
|
|
111
|
+
if (!fromSha) return [];
|
|
112
|
+
const result = await run(
|
|
113
|
+
"git",
|
|
114
|
+
["log", "--reverse", "--format=%H%x09%s", `${fromSha}..${toRef}`],
|
|
115
|
+
).catch(() => null);
|
|
116
|
+
if (!result || result.exitCode !== 0) return [];
|
|
117
|
+
return String(result.stdout || "")
|
|
118
|
+
.split("\n")
|
|
119
|
+
.map((line) => line.trimEnd())
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.map((line) => {
|
|
122
|
+
const tabIdx = line.indexOf("\t");
|
|
123
|
+
// Defensive: if git emitted no tab (shouldn't happen with our format)
|
|
124
|
+
// treat the whole line as the hash and leave the message empty rather
|
|
125
|
+
// than throw — caller can still render the row.
|
|
126
|
+
if (tabIdx === -1) return { hash: line, message: "" };
|
|
127
|
+
return { hash: line.slice(0, tabIdx), message: line.slice(tabIdx + 1) };
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function syncBaseBranch({ baseBranch, autoRebase }) {
|
|
132
|
+
const local = await revParse(baseBranch);
|
|
133
|
+
const remote = await revParse(`origin/${baseBranch}`);
|
|
134
|
+
if (local === remote) return { synced: true, rebased: false };
|
|
135
|
+
|
|
136
|
+
if (!autoRebase) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Base branch '${baseBranch}' is behind origin/${baseBranch}. Re-run with auto-rebase enabled or rebase manually.`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await runGit(["rebase", `origin/${baseBranch}`]);
|
|
143
|
+
return { synced: true, rebased: true };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function ensureBranchUpToDateWithBase({ branch, baseBranch, autoRebase }) {
|
|
147
|
+
const mergeBase = await runGit(["merge-base", branch, `origin/${baseBranch}`]);
|
|
148
|
+
const remoteBase = await revParse(`origin/${baseBranch}`);
|
|
149
|
+
if (mergeBase === remoteBase) return { upToDate: true, rebased: false };
|
|
150
|
+
|
|
151
|
+
if (!autoRebase) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Base branch '${baseBranch}' advanced during run. Re-run with auto-rebase enabled or rebase '${branch}' manually.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await runGit(["rebase", `origin/${baseBranch}`]);
|
|
158
|
+
return { upToDate: true, rebased: true };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function createBranch(branchName) {
|
|
162
|
+
await runGit(["checkout", "-b", branchName]);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function buildBranchName(prefix, task) {
|
|
166
|
+
const stamp = new Date().toISOString().replaceAll(/[:.]/g, "-").slice(0, 16);
|
|
167
|
+
return `${prefix}${slugifyTask(task) || "task"}-${stamp}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function hasChanges(cwd = null) {
|
|
171
|
+
const status = await runGit(["status", "--porcelain"], cwd ? { cwd } : {});
|
|
172
|
+
return status.length > 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Return the relative paths of every uncommitted change (modified,
|
|
177
|
+
* untracked, staged, etc.) in the working tree. Each path is the
|
|
178
|
+
* filename as `git status --porcelain` reports it (after the 2-char
|
|
179
|
+
* status code + space). Returns an empty array when the tree is clean.
|
|
180
|
+
*
|
|
181
|
+
* Used by `finalizeGitAutomation` to decide whether the changes
|
|
182
|
+
* pending at the end of a pipeline are exclusively Karajan
|
|
183
|
+
* scaffolding (and thus deserve a `chore:` commit message instead
|
|
184
|
+
* of inheriting the user task's `feat:`).
|
|
185
|
+
*
|
|
186
|
+
* NOTE: bypasses `runGit()` because that helper trims stdout, which
|
|
187
|
+
* eats the leading space of porcelain lines whose first status char
|
|
188
|
+
* is " " (e.g. " M .gitignore" → "M .gitignore"). The leading space
|
|
189
|
+
* is structural here — without it the slice(3) below would crop one
|
|
190
|
+
* character off the first path.
|
|
191
|
+
*/
|
|
192
|
+
export async function listPendingPaths() {
|
|
193
|
+
const res = await run("git", ["status", "--porcelain"]);
|
|
194
|
+
if (res.exitCode !== 0) {
|
|
195
|
+
throw new Error(`git status --porcelain failed: ${res.stderr || res.stdout}`);
|
|
196
|
+
}
|
|
197
|
+
const stdout = res.stdout;
|
|
198
|
+
if (!stdout) return [];
|
|
199
|
+
const lines = stdout.split("\n").map((l) => l.replace(/\r$/, "")).filter(Boolean);
|
|
200
|
+
const out = [];
|
|
201
|
+
for (const line of lines) {
|
|
202
|
+
// Each line is "XY <path>" (XY = 2-char status, space, path).
|
|
203
|
+
// Renames look like "R old -> new"; we want the new path.
|
|
204
|
+
const after = line.slice(3);
|
|
205
|
+
const arrow = after.indexOf(" -> ");
|
|
206
|
+
out.push(arrow !== -1 ? after.slice(arrow + 4) : after);
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Locale-tolerant detection of "git commit refused because the working
|
|
212
|
+
// tree was already clean by the time we ran it". Observed in N4
|
|
213
|
+
// dogfooding (2026-05-07) — `hasChanges()` reported true after `add -A`
|
|
214
|
+
// but `git commit` then failed with the Spanish message "nada para hacer
|
|
215
|
+
// commit, el árbol de trabajo está limpio". The race window is real:
|
|
216
|
+
// post-loop journal writes can finish between hasChanges and commit, and
|
|
217
|
+
// some files come back from `add -A` with no diff vs HEAD even though
|
|
218
|
+
// they show up in `git status --porcelain`. We treat any of those as
|
|
219
|
+
// "no commit needed" rather than escalating to Solomon.
|
|
220
|
+
const NOTHING_TO_COMMIT_PATTERNS = [
|
|
221
|
+
/nothing to commit/i,
|
|
222
|
+
/nada para hacer commit/i, // git in es_ES locale
|
|
223
|
+
/no hay nada para confirmar/i, // git in es_ES alt phrasing
|
|
224
|
+
/aucune modification ajout[ée]e au commit/i, // fr_FR
|
|
225
|
+
/nichts zu committen/i, // de_DE
|
|
226
|
+
];
|
|
227
|
+
function isNothingToCommit(message) {
|
|
228
|
+
const m = String(message || "");
|
|
229
|
+
return NOTHING_TO_COMMIT_PATTERNS.some((re) => re.test(m));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export async function commitAll(message, cwd = null, { beforeCommit = null } = {}) {
|
|
233
|
+
const opts = cwd ? { cwd } : {};
|
|
234
|
+
await runGit(["add", "-A"], opts);
|
|
235
|
+
const changed = await hasChanges(cwd);
|
|
236
|
+
if (!changed) return { committed: false };
|
|
237
|
+
// ENV-F1 (KJC-TSK-0643): runs between staging and committing — the only
|
|
238
|
+
// window where the staged diff is exactly what the commit will contain
|
|
239
|
+
// (used to stamp the pipeline's review verdict for the v4 gate).
|
|
240
|
+
if (beforeCommit) await beforeCommit();
|
|
241
|
+
try {
|
|
242
|
+
await runGit(["commit", "-m", message], opts);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
// `git status --porcelain` and `git commit` disagreed about whether
|
|
245
|
+
// there was anything to commit. Don't escalate — the only outcome
|
|
246
|
+
// either way is "no new commit was created", which the caller
|
|
247
|
+
// already handles via committed=false.
|
|
248
|
+
if (isNothingToCommit(err?.message)) {
|
|
249
|
+
return { committed: false };
|
|
250
|
+
}
|
|
251
|
+
throw err;
|
|
252
|
+
}
|
|
253
|
+
const raw = await runGit(["log", "-1", "--pretty=format:%H%x1f%s"], opts);
|
|
254
|
+
const [hash, commitMessage] = raw.split("\x1f");
|
|
255
|
+
return { committed: true, commit: { hash, message: commitMessage } };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* KJC-BUG-0112: whether the repo has an `origin` remote. The quickstart
|
|
260
|
+
* scenario (fresh folder + git init) has none — post-approval push/PR
|
|
261
|
+
* automation must skip instead of failing and escalating to Solomon.
|
|
262
|
+
*/
|
|
263
|
+
export async function hasRemote(cwd = null) {
|
|
264
|
+
const res = await run("git", ["remote", "get-url", "origin"], cwd ? { cwd } : {});
|
|
265
|
+
return res.exitCode === 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export async function pushBranch(branch, cwd = null) {
|
|
269
|
+
await runGit(["push", "-u", "origin", branch], cwd ? { cwd } : {});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export async function createPullRequest({ baseBranch, branch, title, body, cwd = null }) {
|
|
273
|
+
const args = ["pr", "create", "--base", baseBranch, "--head", branch, "--title", title, "--body", body];
|
|
274
|
+
const res = await runCommand("gh", args, cwd ? { cwd } : {});
|
|
275
|
+
if (res.exitCode !== 0) {
|
|
276
|
+
throw new Error(`gh ${args.join(" ")} failed: ${res.stderr || res.stdout}`);
|
|
277
|
+
}
|
|
278
|
+
return res.stdout.trim();
|
|
279
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// One-shot ~/.kj/ → ~/.karajan/ home consolidation (PR 2 of KJC-PCS-0047).
|
|
2
|
+
// Idempotent via `<target>/.kj-migrated.json`. Tarball backup under
|
|
3
|
+
// `<target>/backup/`. `plans/`, `standby/`, `worktrees/` are moved
|
|
4
|
+
// wholesale; `runs/` is merged with `.karajan/` winning on conflict.
|
|
5
|
+
// Cross-device safe. Non-fatal: CLI bootstrap wraps in try/catch.
|
|
6
|
+
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import { execa } from "execa";
|
|
11
|
+
|
|
12
|
+
const MARKER = ".kj-migrated.json";
|
|
13
|
+
const MOVE_DIRS = ["plans", "standby", "worktrees"];
|
|
14
|
+
|
|
15
|
+
async function readdirOrNull(dir) {
|
|
16
|
+
try { return await fs.readdir(dir); } catch (err) {
|
|
17
|
+
if (err.code === "ENOENT") return null;
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function moveChildren(src, dst, { mergeMode = false } = {}) {
|
|
23
|
+
const children = await readdirOrNull(src);
|
|
24
|
+
if (!children?.length) return 0;
|
|
25
|
+
await fs.mkdir(dst, { recursive: true });
|
|
26
|
+
let n = 0;
|
|
27
|
+
for (const c of children) {
|
|
28
|
+
const dstChild = path.join(dst, c);
|
|
29
|
+
if (mergeMode) {
|
|
30
|
+
try { await fs.access(dstChild); continue; } catch { /* no conflict */ }
|
|
31
|
+
}
|
|
32
|
+
const srcChild = path.join(src, c);
|
|
33
|
+
try { await fs.rename(srcChild, dstChild); } catch (err) {
|
|
34
|
+
if (err.code !== "EXDEV") throw err;
|
|
35
|
+
await fs.cp(srcChild, dstChild, { recursive: true });
|
|
36
|
+
await fs.rm(srcChild, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
n += 1;
|
|
39
|
+
}
|
|
40
|
+
await fs.rm(src, { recursive: true, force: true }).catch(() => {});
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function migrateKjToKarajan({ dryRun = false, force = false } = {}) {
|
|
45
|
+
// VITEST guard — tests setting KJ_HOME would otherwise migrate against
|
|
46
|
+
// the developer's real HOME. Migrator's own tests pass `force: true`.
|
|
47
|
+
if (process.env.VITEST && !force) return { migrated: false, reason: "vitest-skip" };
|
|
48
|
+
|
|
49
|
+
const sourceDir = process.env.KJ_HOME || path.join(os.homedir(), ".kj");
|
|
50
|
+
const targetDir = process.env.KARAJAN_HOME || path.join(os.homedir(), ".karajan");
|
|
51
|
+
|
|
52
|
+
if (path.resolve(sourceDir) === path.resolve(targetDir)) {
|
|
53
|
+
return { migrated: false, reason: "same-path" };
|
|
54
|
+
}
|
|
55
|
+
const entries = await readdirOrNull(sourceDir);
|
|
56
|
+
if (!entries) return { migrated: false, reason: "source-missing" };
|
|
57
|
+
if (entries.length === 0) return { migrated: false, reason: "source-empty" };
|
|
58
|
+
|
|
59
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
60
|
+
const markerPath = path.join(targetDir, MARKER);
|
|
61
|
+
try { await fs.access(markerPath); return { migrated: false, reason: "already-migrated" }; }
|
|
62
|
+
catch { /* not present — proceed */ }
|
|
63
|
+
|
|
64
|
+
if (dryRun) return { migrated: false, reason: "dry-run", sourceDir, targetDir };
|
|
65
|
+
|
|
66
|
+
const backupDir = path.join(targetDir, "backup");
|
|
67
|
+
await fs.mkdir(backupDir, { recursive: true });
|
|
68
|
+
const ts = new Date().toISOString().replaceAll(/[:.]/g, "-");
|
|
69
|
+
const backupPath = path.join(backupDir, `kj-pre-migration-${ts}.tar.gz`);
|
|
70
|
+
await execa("tar", ["-czf", backupPath, "-C", path.dirname(sourceDir), path.basename(sourceDir)]);
|
|
71
|
+
|
|
72
|
+
const counts = {};
|
|
73
|
+
for (const sub of MOVE_DIRS) {
|
|
74
|
+
counts[sub] = await moveChildren(path.join(sourceDir, sub), path.join(targetDir, sub));
|
|
75
|
+
}
|
|
76
|
+
counts.runs = await moveChildren(path.join(sourceDir, "runs"), path.join(targetDir, "runs"), { mergeMode: true });
|
|
77
|
+
|
|
78
|
+
const marker = { version: 1, migrated_at: new Date().toISOString(), items_moved: counts, backup_path: backupPath, source_dir: sourceDir, target_dir: targetDir };
|
|
79
|
+
await fs.writeFile(markerPath, JSON.stringify(marker, null, 2));
|
|
80
|
+
|
|
81
|
+
const summary = Object.entries(counts).filter(([, n]) => n > 0).map(([k, n]) => `${n} ${k}`).join(" + ");
|
|
82
|
+
if (summary) {
|
|
83
|
+
// eslint-disable-next-line no-console
|
|
84
|
+
console.warn(`\x1b[33m[warn]\x1b[0m Migrated ${summary} from ${sourceDir} to ${targetDir} (backup: ${backupPath})`);
|
|
85
|
+
}
|
|
86
|
+
return { migrated: true, counts, backupPath, marker };
|
|
87
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt-injection guard for AI-reviewed diffs and PR content.
|
|
3
|
+
*
|
|
4
|
+
* Scans text for patterns commonly used to hijack LLM instructions:
|
|
5
|
+
* directive overrides, role reassignment, invisible Unicode, and
|
|
6
|
+
* suspiciously large comment blocks that could hide payloads.
|
|
7
|
+
*
|
|
8
|
+
* @module utils/injection-guard
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Phrases that attempt to override system/reviewer instructions. */
|
|
12
|
+
const DIRECTIVE_PATTERNS = [
|
|
13
|
+
/ignore\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|rules?|prompts?|guidelines?)/i,
|
|
14
|
+
/disregard\s+(all\s+)?(previous|prior|above|earlier)\s+(instructions?|rules?|prompts?)/i,
|
|
15
|
+
/forget\s+(all\s+)?(previous|prior|your)\s+(instructions?|rules?|context)/i,
|
|
16
|
+
/override\s+(the\s+)?(system|reviewer|review)\s+(prompt|instructions?|rules?)/i,
|
|
17
|
+
/do\s+not\s+follow\s+(the\s+)?(above|previous|system)\s+(instructions?|rules?)/i,
|
|
18
|
+
/new\s+instructions?\s*:/i,
|
|
19
|
+
/system\s*:\s*you\s+are/i,
|
|
20
|
+
/\bact\s+as\s+(a\s+)?(different|new|my|an?\s+)/i,
|
|
21
|
+
/you\s+are\s+now\s+(a\s+)?/i,
|
|
22
|
+
/from\s+now\s+on\s*(,|\s)?\s*you\s+(will|should|must|are)/i,
|
|
23
|
+
/pretend\s+(you\s+are|to\s+be)/i,
|
|
24
|
+
/respond\s+(only\s+)?with\s+["']?approved["']?/i,
|
|
25
|
+
/always\s+(return|respond|output)\s+.*approved/i,
|
|
26
|
+
/set\s+approved\s*[=:]\s*true/i,
|
|
27
|
+
/\bapproved["']?\s*:\s*true\b.*ignore/i,
|
|
28
|
+
/output\s+the\s+following\s+json/i,
|
|
29
|
+
/return\s+this\s+exact\s+(json|response|output)/i,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/** Unicode categories that can hide or disguise content. */
|
|
33
|
+
const UNICODE_PATTERNS = [
|
|
34
|
+
/[\u200B-\u200F]/, // zero-width spaces, LTR/RTL marks
|
|
35
|
+
/[\u202A-\u202E]/, // bidi embedding/override
|
|
36
|
+
/[\u2066-\u2069]/, // bidi isolate
|
|
37
|
+
/[\uFEFF]/, // BOM mid-text
|
|
38
|
+
/[\u00AD]{3,}/, // repeated soft hyphens
|
|
39
|
+
/[\u2060-\u2064]/, // invisible operators
|
|
40
|
+
/[\u{E0000}-\u{E007F}]/u, // tag characters
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/** Maximum comment block size (chars) before flagging. */
|
|
44
|
+
const MAX_COMMENT_BLOCK = 2000;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Comment block patterns for common languages.
|
|
48
|
+
* Each regex captures the full block content.
|
|
49
|
+
*/
|
|
50
|
+
const COMMENT_BLOCK_RE = [
|
|
51
|
+
/\/\*[\s\S]{0,20000}?\*\//g, // C-style /* ... */
|
|
52
|
+
/<!--[\s\S]{0,20000}?-->/g, // HTML <!-- ... -->
|
|
53
|
+
/"""\s*[\s\S]{0,20000}?\s*"""/g, // Python docstrings
|
|
54
|
+
/'''\s*[\s\S]{0,20000}?\s*'''/g, // Python docstrings (single)
|
|
55
|
+
/=begin[\s\S]{0,20000}?=end/g, // Ruby block comments
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @typedef {Object} InjectionFinding
|
|
60
|
+
* @property {"directive"|"unicode"|"comment_block"} type
|
|
61
|
+
* @property {string} pattern - short label of what matched
|
|
62
|
+
* @property {string} snippet - excerpt of the offending text (max 120 chars)
|
|
63
|
+
* @property {number} [line] - approximate line number (1-based)
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @typedef {Object} GuardResult
|
|
68
|
+
* @property {boolean} clean - true if no threats detected
|
|
69
|
+
* @property {InjectionFinding[]} findings
|
|
70
|
+
* @property {string} summary - human-readable one-liner
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Scan a text (diff, PR description, comment) for prompt-injection signals.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} text - content to scan
|
|
77
|
+
* @param {Object} [opts]
|
|
78
|
+
* @param {number} [opts.maxCommentBlock=2000] - flag comment blocks larger than this
|
|
79
|
+
* @returns {GuardResult}
|
|
80
|
+
*/
|
|
81
|
+
export function scanForInjection(text, opts = {}) {
|
|
82
|
+
if (!text || typeof text !== "string") {
|
|
83
|
+
return { clean: true, findings: [], summary: "Nothing to scan" };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const maxBlock = opts.maxCommentBlock ?? MAX_COMMENT_BLOCK;
|
|
87
|
+
/** @type {InjectionFinding[]} */
|
|
88
|
+
const findings = [];
|
|
89
|
+
|
|
90
|
+
// 1. Directive patterns
|
|
91
|
+
for (const re of DIRECTIVE_PATTERNS) {
|
|
92
|
+
const match = re.exec(text);
|
|
93
|
+
if (match) {
|
|
94
|
+
findings.push({
|
|
95
|
+
type: "directive",
|
|
96
|
+
pattern: re.source.slice(0, 60),
|
|
97
|
+
snippet: excerpt(text, match.index),
|
|
98
|
+
line: lineAt(text, match.index),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 2. Invisible Unicode
|
|
104
|
+
for (const re of UNICODE_PATTERNS) {
|
|
105
|
+
const match = re.exec(text);
|
|
106
|
+
if (match) {
|
|
107
|
+
const charCode = match[0].codePointAt(0).toString(16).toUpperCase();
|
|
108
|
+
findings.push({
|
|
109
|
+
type: "unicode",
|
|
110
|
+
pattern: `U+${charCode}`,
|
|
111
|
+
snippet: excerpt(text, match.index),
|
|
112
|
+
line: lineAt(text, match.index),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 3. Oversized comment blocks
|
|
118
|
+
for (const re of COMMENT_BLOCK_RE) {
|
|
119
|
+
let m;
|
|
120
|
+
while ((m = re.exec(text)) !== null) {
|
|
121
|
+
if (m[0].length > maxBlock) {
|
|
122
|
+
findings.push({
|
|
123
|
+
type: "comment_block",
|
|
124
|
+
pattern: `block ${m[0].length} chars (max ${maxBlock})`,
|
|
125
|
+
snippet: excerpt(text, m.index),
|
|
126
|
+
line: lineAt(text, m.index),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const clean = findings.length === 0;
|
|
133
|
+
const summary = clean
|
|
134
|
+
? "No injection patterns detected"
|
|
135
|
+
: `${findings.length} potential injection(s): ${[...new Set(findings.map((f) => f.type))].join(", ")}`;
|
|
136
|
+
|
|
137
|
+
return { clean, findings, summary };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Scan a git diff, focusing only on added lines (lines starting with +).
|
|
142
|
+
* Removed lines cannot inject into the AI prompt.
|
|
143
|
+
*
|
|
144
|
+
* @param {string} diff - unified diff content
|
|
145
|
+
* @param {Object} [opts]
|
|
146
|
+
* @returns {GuardResult}
|
|
147
|
+
*/
|
|
148
|
+
export function scanDiff(diff, opts = {}) {
|
|
149
|
+
if (!diff) return { clean: true, findings: [], summary: "Empty diff" };
|
|
150
|
+
|
|
151
|
+
// Split diff into per-file chunks to avoid false positives from
|
|
152
|
+
// concatenated added-lines across unrelated files.
|
|
153
|
+
const files = diff.split(/^diff --git /m).filter(Boolean);
|
|
154
|
+
|
|
155
|
+
const allFindings = [];
|
|
156
|
+
for (const fileChunk of files) {
|
|
157
|
+
const addedLines = fileChunk
|
|
158
|
+
.split("\n")
|
|
159
|
+
.filter((l) => l.startsWith("+") && !l.startsWith("+++"))
|
|
160
|
+
.map((l) => l.slice(1))
|
|
161
|
+
.join("\n");
|
|
162
|
+
|
|
163
|
+
if (!addedLines) continue;
|
|
164
|
+
const result = scanForInjection(addedLines, opts);
|
|
165
|
+
if (!result.clean) allFindings.push(...result.findings);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const clean = allFindings.length === 0;
|
|
169
|
+
return {
|
|
170
|
+
clean,
|
|
171
|
+
findings: allFindings,
|
|
172
|
+
summary: clean ? "No injection patterns detected" : `${allFindings.length} injection pattern(s) detected across diff`
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// --- Helpers ---
|
|
177
|
+
|
|
178
|
+
function excerpt(text, index) {
|
|
179
|
+
const start = Math.max(0, index - 20);
|
|
180
|
+
const end = Math.min(text.length, index + 100);
|
|
181
|
+
return text.slice(start, end).replaceAll(/\n/g, "\\n").slice(0, 120);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function lineAt(text, index) {
|
|
185
|
+
return text.slice(0, index).split("\n").length;
|
|
186
|
+
}
|