@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,278 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-publish tarball smoke gate (KJC-TSK-0553).
|
|
4
|
+
*
|
|
5
|
+
* WHY: the test suite runs against the linked workspace, where
|
|
6
|
+
* `karajan-core` and its deps resolve via symlink — so a broken
|
|
7
|
+
* PUBLISHED artifact (bundleDependencies dragging in sqlite-vec without
|
|
8
|
+
* its entry point, KJC-BUG-0082 / 0086) passed CI yet failed on every
|
|
9
|
+
* clean `npm install`. v3.2.0, v3.3.0 and v3.4.1 all shipped unable to
|
|
10
|
+
* run even `kj --version`.
|
|
11
|
+
*
|
|
12
|
+
* WHAT: pack the real tarball, install it into an isolated tmpdir
|
|
13
|
+
* (outside the repo, with CLAUDECODE stripped), and assert the binary
|
|
14
|
+
* actually starts and its native-ish deps resolve. Exit non-zero on any
|
|
15
|
+
* failure so `prepublishOnly` aborts the publish and CI blocks the PR.
|
|
16
|
+
*
|
|
17
|
+
* `npm pack` fires prepack/postpack, NOT prepublishOnly — so invoking
|
|
18
|
+
* this from prepublishOnly does not recurse.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
22
|
+
import fs from "node:fs";
|
|
23
|
+
import os from "node:os";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
|
|
27
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8"));
|
|
29
|
+
const expectedVersion = pkg.version;
|
|
30
|
+
// MIG-A (KJC-TSK-0751): el nombre sale del manifest — el MISMO verify-pack
|
|
31
|
+
// valida el tarball unscoped y el @karajan-family/* del dual-publish.
|
|
32
|
+
const pkgName = pkg.name;
|
|
33
|
+
|
|
34
|
+
// Subprocess env: strip CLAUDECODE (Claude Code blocks nested non-interactive
|
|
35
|
+
// runs otherwise) and force a non-interactive, quiet npm.
|
|
36
|
+
const { CLAUDECODE: _omit, ...cleanEnv } = process.env;
|
|
37
|
+
const childEnv = { ...cleanEnv, npm_config_yes: "true", CI: "1" };
|
|
38
|
+
|
|
39
|
+
function run(cmd, args, opts = {}) {
|
|
40
|
+
return execFileSync(cmd, args, {
|
|
41
|
+
encoding: "utf8",
|
|
42
|
+
env: childEnv,
|
|
43
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
44
|
+
...opts,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function fail(msg, detail) {
|
|
49
|
+
console.error(`\n✗ verify-pack: ${msg}`);
|
|
50
|
+
if (detail) console.error(String(detail).split("\n").slice(0, 20).join("\n"));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let tgzPath = null;
|
|
55
|
+
let tmpDir = null;
|
|
56
|
+
let gTmp = null;
|
|
57
|
+
let pnpmTmp = null;
|
|
58
|
+
let qsTmp = null;
|
|
59
|
+
try {
|
|
60
|
+
console.log(`verify-pack: packing ${pkgName}@${expectedVersion}…`);
|
|
61
|
+
// --json gives us the exact filename without parsing human output.
|
|
62
|
+
const packOut = run("npm", ["pack", "--json", "--silent"], { cwd: repoRoot });
|
|
63
|
+
const filename = JSON.parse(packOut)[0]?.filename;
|
|
64
|
+
if (!filename) fail("npm pack did not report a filename", packOut);
|
|
65
|
+
// npm --json reports the exact filename (scoped names normalized to
|
|
66
|
+
// scope-name-x.y.z.tgz); the file lands in cwd under that name.
|
|
67
|
+
tgzPath = path.join(repoRoot, filename);
|
|
68
|
+
if (!fs.existsSync(tgzPath)) fail(`packed tarball not found at ${tgzPath}`);
|
|
69
|
+
|
|
70
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kj-verify-pack-"));
|
|
71
|
+
console.log(`verify-pack: installing the tarball into ${tmpDir} (clean, isolated)…`);
|
|
72
|
+
run("npm", ["install", tgzPath, "--no-audit", "--no-fund", "--silent", "--prefix", tmpDir], {
|
|
73
|
+
cwd: tmpDir,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const binPath = path.join(tmpDir, "node_modules", ".bin", "kj");
|
|
77
|
+
if (!fs.existsSync(binPath)) fail(`kj binary missing after install: ${binPath}`);
|
|
78
|
+
|
|
79
|
+
// 1. kj --version must start AND report the version we just packed.
|
|
80
|
+
let versionOut;
|
|
81
|
+
try {
|
|
82
|
+
versionOut = run(binPath, ["--version"]).trim();
|
|
83
|
+
} catch (err) {
|
|
84
|
+
fail("`kj --version` crashed on a clean install", err.stderr || err.message);
|
|
85
|
+
}
|
|
86
|
+
if (!versionOut.includes(expectedVersion)) {
|
|
87
|
+
fail(`kj --version returned "${versionOut}", expected ${expectedVersion}`);
|
|
88
|
+
}
|
|
89
|
+
console.log(`verify-pack: kj --version → ${versionOut} ✓`);
|
|
90
|
+
|
|
91
|
+
// 1.5 Privacy boundary (KJC-TSK-0706): nothing personal or secret-shaped
|
|
92
|
+
// ships inside the tarball. Scans the INSTALLED package with the same
|
|
93
|
+
// engine as the pre-commit gate: denylist + token shapes abort the
|
|
94
|
+
// publish; generic PII only counts (code trees always carry a few
|
|
95
|
+
// pattern lookalikes).
|
|
96
|
+
const { scanPaths, loadPrivacyList } = await import(
|
|
97
|
+
path.join(repoRoot, "src", "privacy", "scan.js")
|
|
98
|
+
);
|
|
99
|
+
const shippedDir = path.join(tmpDir, "node_modules", ...pkgName.split("/"));
|
|
100
|
+
const pFindings = scanPaths([shippedDir], { list: loadPrivacyList() });
|
|
101
|
+
const pBlocks = pFindings.filter((f) => f.severity === "block");
|
|
102
|
+
if (pBlocks.length > 0) {
|
|
103
|
+
for (const f of pBlocks) console.error(`✗ [${f.type}] ${path.relative(shippedDir, f.source)}:${f.line} → ${f.masked}`);
|
|
104
|
+
fail(`${pBlocks.length} personal-data/secret hit(s) INSIDE the tarball — this must not publish`);
|
|
105
|
+
}
|
|
106
|
+
console.log(`verify-pack: tarball privacy scan ✓ (${pFindings.length} generic warning(s))`);
|
|
107
|
+
|
|
108
|
+
// 2. kj --help must exit 0 (exercises the command tree wiring).
|
|
109
|
+
try {
|
|
110
|
+
run(binPath, ["--help"]);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
fail("`kj --help` failed on a clean install", err.stderr || err.message);
|
|
113
|
+
}
|
|
114
|
+
console.log("verify-pack: kj --help ✓");
|
|
115
|
+
|
|
116
|
+
// 3. The deps that broke before must resolve in the installed tree.
|
|
117
|
+
// karajan-core is a registry dep since KJC-BUG-0103 (no bundling), so it
|
|
118
|
+
// hoists to the consumer's top-level node_modules like everything else.
|
|
119
|
+
const checks = [
|
|
120
|
+
path.join(tmpDir, "node_modules", "sqlite-vec", "index.mjs"),
|
|
121
|
+
path.join(tmpDir, "node_modules", "karajan-core", "src", "vec-store.js"),
|
|
122
|
+
];
|
|
123
|
+
for (const p of checks) {
|
|
124
|
+
if (!fs.existsSync(p)) fail(`expected resolved path missing in install: ${p}`);
|
|
125
|
+
}
|
|
126
|
+
console.log("verify-pack: sqlite-vec + karajan-core resolve ✓");
|
|
127
|
+
|
|
128
|
+
// 4. kj-trash (ai-trash safety binary) must ship + link onto PATH and boot
|
|
129
|
+
// without a module-resolution crash. It was silently absent from the tarball
|
|
130
|
+
// until KJC-BUG-0089 — every npm user got "kj-trash not found".
|
|
131
|
+
const trashBin = path.join(tmpDir, "node_modules", ".bin", "kj-trash");
|
|
132
|
+
if (!fs.existsSync(trashBin)) fail(`kj-trash binary missing after install: ${trashBin}`);
|
|
133
|
+
const trash = spawnSync(trashBin, ["--help"], { encoding: "utf8", env: childEnv });
|
|
134
|
+
// The CLI exits 2 on --help (usage); only a real crash (module not found, or
|
|
135
|
+
// an unexpected non-0/2 exit) is a failure.
|
|
136
|
+
if (![0, 2].includes(trash.status) || /ERR_MODULE_NOT_FOUND|Cannot find/.test(trash.stderr || "")) {
|
|
137
|
+
fail("`kj-trash --help` crashed on a clean install", trash.stderr || `exit ${trash.status}`);
|
|
138
|
+
}
|
|
139
|
+
console.log("verify-pack: kj-trash ships + boots ✓");
|
|
140
|
+
|
|
141
|
+
// 5. GLOBAL install smoke (KJC-BUG-0103). `npm install -g` nests every dep
|
|
142
|
+
// under karajan-code/node_modules; with bundleDependencies present, npm
|
|
143
|
+
// treated that whole subtree as "already in the tarball" and skipped
|
|
144
|
+
// fetching better-sqlite3 & friends — EMPTY dirs whose install scripts then
|
|
145
|
+
// crashed. Local installs hoist and never hit it, which is exactly why the
|
|
146
|
+
// check above stayed green for ~15 broken releases. A fresh global install
|
|
147
|
+
// must succeed and kj must boot.
|
|
148
|
+
gTmp = fs.mkdtempSync(path.join(os.tmpdir(), "kj-verify-g-"));
|
|
149
|
+
console.log(`verify-pack: installing the tarball GLOBALLY into ${gTmp}…`);
|
|
150
|
+
try {
|
|
151
|
+
run("npm", ["install", "-g", tgzPath, "--no-audit", "--no-fund", "--silent", "--prefix", gTmp]);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
fail("`npm install -g` of the tarball failed (KJC-BUG-0103 class)", err.stderr || err.message);
|
|
154
|
+
}
|
|
155
|
+
const gBin = process.platform === "win32"
|
|
156
|
+
? path.join(gTmp, "kj.cmd")
|
|
157
|
+
: path.join(gTmp, "bin", "kj");
|
|
158
|
+
if (!fs.existsSync(gBin)) fail(`kj binary missing after global install: ${gBin}`);
|
|
159
|
+
let gVersion;
|
|
160
|
+
try {
|
|
161
|
+
gVersion = run(gBin, ["--version"]).trim();
|
|
162
|
+
} catch (err) {
|
|
163
|
+
fail("`kj --version` crashed on a fresh GLOBAL install", err.stderr || err.message);
|
|
164
|
+
}
|
|
165
|
+
if (!gVersion.includes(expectedVersion)) {
|
|
166
|
+
fail(`kj --version (global) returned "${gVersion}", expected ${expectedVersion}`);
|
|
167
|
+
}
|
|
168
|
+
console.log(`verify-pack: global install + kj --version → ${gVersion} ✓`);
|
|
169
|
+
|
|
170
|
+
// 5.5 Quickstart smoke (KJC-TSK-0635) — the landing's Getting Started
|
|
171
|
+
// sequence against the INSTALLED tarball, no LLM involved. Born from
|
|
172
|
+
// 2026-07-19: following the docs to the letter caught 3 field bugs
|
|
173
|
+
// (silent 2.34.0 install, Solomon loop on no-remote repos, retired
|
|
174
|
+
// gemini CLI) that 6000 unit tests never saw. Aux bootstraps (ollama,
|
|
175
|
+
// rtk, squeezr, qmd, harden) are skipped — this validates kj's own
|
|
176
|
+
// init + config on the canonical no-remote scenario, not the network.
|
|
177
|
+
qsTmp = fs.mkdtempSync(path.join(os.tmpdir(), "kj-verify-qs-"));
|
|
178
|
+
console.log(`verify-pack: quickstart smoke (init on a no-remote repo) in ${qsTmp}…`);
|
|
179
|
+
run("git", ["init", "-q", "-b", "main"], { cwd: qsTmp });
|
|
180
|
+
// KARAJAN_HOME points at an isolated dir: faithful to a brand-new user
|
|
181
|
+
// (no pre-existing global config — `--local` without one is rejected by
|
|
182
|
+
// design, which is exactly what this smoke caught on its first CI run)
|
|
183
|
+
// AND hermetic (never touches the real ~/.karajan).
|
|
184
|
+
const qsEnv = { ...childEnv, KARAJAN_HOME: path.join(qsTmp, "karajan-home") };
|
|
185
|
+
delete qsEnv.CLAUDECODE;
|
|
186
|
+
const initRes = spawnSync(gBin, ["init", "--no-interactive", "--no-ollama", "--no-rtk", "--no-squeezr", "--no-qmd", "--no-harden"], {
|
|
187
|
+
encoding: "utf8", cwd: qsTmp, env: qsEnv, timeout: 180000,
|
|
188
|
+
});
|
|
189
|
+
if (initRes.status !== 0) {
|
|
190
|
+
fail("`kj init --no-interactive` failed on a fresh no-remote repo", (initRes.stderr || initRes.stdout || "").slice(-800));
|
|
191
|
+
}
|
|
192
|
+
const qsCfgLocal = path.join(qsTmp, ".karajan", "kj.config.yml");
|
|
193
|
+
const qsCfgGlobal = path.join(qsTmp, "karajan-home", "kj.config.yml");
|
|
194
|
+
const qsCfg = fs.existsSync(qsCfgLocal) ? qsCfgLocal : qsCfgGlobal;
|
|
195
|
+
if (!fs.existsSync(qsCfg)) fail(`kj init did not write ${qsCfg}`);
|
|
196
|
+
if (!/coder:\s*\S+/.test(fs.readFileSync(qsCfg, "utf8"))) {
|
|
197
|
+
fail("generated kj.config.yml has no coder assignment");
|
|
198
|
+
}
|
|
199
|
+
const reportRes = spawnSync(gBin, ["report"], { encoding: "utf8", cwd: qsTmp, env: qsEnv, timeout: 60000 });
|
|
200
|
+
const reportOut = `${reportRes.stdout || ""}${reportRes.stderr || ""}`;
|
|
201
|
+
if (reportRes.status !== 0 && !/no session|sin sesi|not found/i.test(reportOut)) {
|
|
202
|
+
fail("`kj report` crashed on a project with no sessions", reportOut.slice(-400));
|
|
203
|
+
}
|
|
204
|
+
console.log("verify-pack: quickstart smoke (init + report, no-remote repo) ✓");
|
|
205
|
+
|
|
206
|
+
// 6. pnpm install smoke (KJC-TSK-0580). pnpm's layout differs from npm's
|
|
207
|
+
// (a symlinked virtual store), so it can break resolution of the bundled
|
|
208
|
+
// karajan-core the way npm packaging breakage did before (KJC-BUG-0082/0086).
|
|
209
|
+
// Verify a pnpm install resolves the JS tree and `kj --version` boots — every
|
|
210
|
+
// release catches a pnpm packaging regression. (pnpm also blocks
|
|
211
|
+
// better-sqlite3's native build by default, so DB-backed commands need
|
|
212
|
+
// `pnpm approve-builds`; that's surfaced as a doctor warning, KJC-BUG-0092 —
|
|
213
|
+
// not a gate failure, since it's inherent to pnpm.) Auto-skips without pnpm.
|
|
214
|
+
// KJC-BUG-0135: `npm run` leaks npm_config_* into the child env, and pnpm
|
|
215
|
+
// maps those variables onto its own config — which can re-anchor it to THIS
|
|
216
|
+
// repo (7-aug incident: the repo's node_modules converted to pnpm layout,
|
|
217
|
+
// native bindings wiped, and simple-git-hooks' hook overwrote
|
|
218
|
+
// .karajan/hooks). The smoke runs with a scrubbed env and a pinned --dir,
|
|
219
|
+
// and the tripwire below turns any host contamination into a loud gate
|
|
220
|
+
// failure instead of a silent green.
|
|
221
|
+
const pnpmEnv = Object.fromEntries(Object.entries(childEnv).filter(([k]) => !/^npm_config_/i.test(k)));
|
|
222
|
+
const HOST_MARKERS = ["pnpm-lock.yaml", "pnpm-workspace.yaml", path.join("node_modules", ".pnpm")];
|
|
223
|
+
const hostMarkersBefore = new Set(HOST_MARKERS.filter((m) => fs.existsSync(path.join(repoRoot, m))));
|
|
224
|
+
const hasPnpm = spawnSync("pnpm", ["--version"], { encoding: "utf8", env: pnpmEnv }).status === 0;
|
|
225
|
+
if (!hasPnpm) {
|
|
226
|
+
console.log("verify-pack: pnpm not installed — skipping pnpm smoke (npm path covered above) ⚠");
|
|
227
|
+
} else {
|
|
228
|
+
pnpmTmp = fs.mkdtempSync(path.join(os.tmpdir(), "kj-verify-pnpm-"));
|
|
229
|
+
fs.writeFileSync(
|
|
230
|
+
path.join(pnpmTmp, "package.json"),
|
|
231
|
+
JSON.stringify({ name: "kj-verify-pnpm", private: true }),
|
|
232
|
+
);
|
|
233
|
+
console.log(`verify-pack: installing the tarball with pnpm into ${pnpmTmp}…`);
|
|
234
|
+
// pnpm exits non-zero on ERR_PNPM_IGNORED_BUILDS (it skips native build
|
|
235
|
+
// scripts by default) — expected here, so don't treat the exit as failure.
|
|
236
|
+
// minimum-release-age=0: modern pnpm quarantines freshly published
|
|
237
|
+
// versions (supply-chain protection), so right after publishing
|
|
238
|
+
// karajan-core it silently resolves an OLD one and this smoke fails on
|
|
239
|
+
// missing subpaths. The gate verifies packaging, not release-age policy.
|
|
240
|
+
spawnSync(
|
|
241
|
+
"pnpm",
|
|
242
|
+
["add", tgzPath, "--dir", pnpmTmp, "--ignore-workspace", "--store-dir", path.join(pnpmTmp, ".store"), "--config.minimum-release-age=0"],
|
|
243
|
+
{ encoding: "utf8", env: pnpmEnv, cwd: pnpmTmp },
|
|
244
|
+
);
|
|
245
|
+
const pnpmBin = path.join(pnpmTmp, "node_modules", ".bin", "kj");
|
|
246
|
+
if (!fs.existsSync(pnpmBin)) fail(`kj binary missing after pnpm install: ${pnpmBin}`);
|
|
247
|
+
let pnpmVersion;
|
|
248
|
+
try {
|
|
249
|
+
pnpmVersion = run(pnpmBin, ["--version"], { cwd: pnpmTmp }).trim();
|
|
250
|
+
} catch (err) {
|
|
251
|
+
fail("`kj --version` crashed under a pnpm install (packaging regression)", err.stderr || err.message);
|
|
252
|
+
}
|
|
253
|
+
if (!pnpmVersion.includes(expectedVersion)) {
|
|
254
|
+
fail(`kj --version under pnpm returned "${pnpmVersion}", expected ${expectedVersion}`);
|
|
255
|
+
}
|
|
256
|
+
console.log(`verify-pack: pnpm install + kj --version → ${pnpmVersion} ✓ (DB build needs \`pnpm approve-builds\`)`);
|
|
257
|
+
}
|
|
258
|
+
// Tripwire (KJC-BUG-0135): the smoke must NEVER touch the host repo. If a
|
|
259
|
+
// pnpm artifact appeared at the repo root during this run, the gate fails
|
|
260
|
+
// naming it — never a green over a contaminated tree.
|
|
261
|
+
const contaminated = HOST_MARKERS.filter(
|
|
262
|
+
(m) => !hostMarkersBefore.has(m) && fs.existsSync(path.join(repoRoot, m)),
|
|
263
|
+
);
|
|
264
|
+
if (contaminated.length > 0) {
|
|
265
|
+
fail(
|
|
266
|
+
`pnpm smoke contaminated the host repo: ${contaminated.join(", ")} appeared at the repo root`,
|
|
267
|
+
"remove the listed files and run `npm ci` to restore the npm layout; then verify .karajan/hooks with `git status`",
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log(`\n✓ verify-pack: ${pkgName}@${expectedVersion} installs clean and runs.`);
|
|
272
|
+
} finally {
|
|
273
|
+
if (tgzPath && fs.existsSync(tgzPath)) fs.rmSync(tgzPath, { force: true });
|
|
274
|
+
if (tmpDir && fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
275
|
+
if (gTmp && fs.existsSync(gTmp)) fs.rmSync(gTmp, { recursive: true, force: true });
|
|
276
|
+
if (pnpmTmp && fs.existsSync(pnpmTmp)) fs.rmSync(pnpmTmp, { recursive: true, force: true });
|
|
277
|
+
if (qsTmp && fs.existsSync(qsTmp)) fs.rmSync(qsTmp, { recursive: true, force: true });
|
|
278
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getSessionRoot } from "./utils/paths.js";
|
|
4
|
+
import { ensureDir } from "./utils/fs.js";
|
|
5
|
+
|
|
6
|
+
function formatLine(entry) {
|
|
7
|
+
const ts = entry.timestamp || new Date().toISOString();
|
|
8
|
+
const lvl = (entry.level || "info").toUpperCase().padEnd(5);
|
|
9
|
+
const ctx = entry.context
|
|
10
|
+
? Object.entries(entry.context)
|
|
11
|
+
.filter(([, v]) => v !== undefined)
|
|
12
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
13
|
+
.join(" ")
|
|
14
|
+
: "";
|
|
15
|
+
const ctxStr = ctx ? ` ${ctx}` : "";
|
|
16
|
+
return `${ts} [${lvl}]${ctxStr} ${entry.message || ""}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createActivityLog(sessionId) {
|
|
20
|
+
const logPath = path.join(getSessionRoot(), sessionId, "activity.log");
|
|
21
|
+
let buffer = [];
|
|
22
|
+
let flushing = false;
|
|
23
|
+
|
|
24
|
+
async function flush() {
|
|
25
|
+
if (flushing || buffer.length === 0) return;
|
|
26
|
+
flushing = true;
|
|
27
|
+
const lines = buffer.splice(0);
|
|
28
|
+
try {
|
|
29
|
+
await ensureDir(path.dirname(logPath));
|
|
30
|
+
await fs.appendFile(logPath, lines.join("\n") + "\n", "utf8");
|
|
31
|
+
} catch {
|
|
32
|
+
// best-effort: I/O errors do not crash the flow
|
|
33
|
+
}
|
|
34
|
+
flushing = false;
|
|
35
|
+
if (buffer.length > 0) flush();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
write(logEntry) {
|
|
40
|
+
buffer.push(formatLine(logEntry));
|
|
41
|
+
flush();
|
|
42
|
+
},
|
|
43
|
+
writeEvent(progressEvent) {
|
|
44
|
+
const entry = {
|
|
45
|
+
timestamp: progressEvent.timestamp,
|
|
46
|
+
level: progressEvent.status === "fail" ? "error" : "info",
|
|
47
|
+
context: {
|
|
48
|
+
iteration: progressEvent.iteration,
|
|
49
|
+
stage: progressEvent.stage
|
|
50
|
+
},
|
|
51
|
+
message: progressEvent.message || progressEvent.type
|
|
52
|
+
};
|
|
53
|
+
this.write(entry);
|
|
54
|
+
},
|
|
55
|
+
get path() {
|
|
56
|
+
return logPath;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { BaseAgent } from "./base-agent.js";
|
|
2
|
+
import { resolveBin } from "./resolve-bin.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Antigravity CLI (`agy`) — KJC-TSK-0729 fase 2b: the ninth built-in agent.
|
|
6
|
+
* Google's official successor to the retired gemini CLI (dead 2026-06-18),
|
|
7
|
+
* covered by the user's Google AI Pro/Ultra subscription — the natural
|
|
8
|
+
* third AI for solomon arbitration, back at last.
|
|
9
|
+
*
|
|
10
|
+
* Verified live against agy 1.1.10:
|
|
11
|
+
* - `-p <prompt>` runs print mode; `--output-format json` emits ONE JSON
|
|
12
|
+
* object: {status: "SUCCESS", response, usage}. Non-SUCCESS status can
|
|
13
|
+
* arrive with exit 0, so ok checks BOTH.
|
|
14
|
+
* - `--disable-slash-commands` keeps prompt content (diffs can contain
|
|
15
|
+
* "/lines") from expanding as slash commands in print mode.
|
|
16
|
+
* - Permission prompts are denied in print mode unless
|
|
17
|
+
* `--dangerously-skip-permissions` (coder mode only).
|
|
18
|
+
* - Auth lives under ~/.gemini/antigravity-cli (device/browser login).
|
|
19
|
+
*/
|
|
20
|
+
export class AgyAgent extends BaseAgent {
|
|
21
|
+
async runTask(task) {
|
|
22
|
+
return this._exec(task, this.getRoleModel(task.role || "coder"), ["--dangerously-skip-permissions"]);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async reviewTask(task) {
|
|
26
|
+
return this._exec(
|
|
27
|
+
{ ...task, prompt: `Do NOT use any tools. Answer directly from this prompt only.\n\n${task.prompt}` },
|
|
28
|
+
this.getRoleModel(task.role || "reviewer"),
|
|
29
|
+
[],
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async _exec(task, model, extraArgs) {
|
|
34
|
+
const args = ["-p", task.prompt, "--output-format", "json", "--disable-slash-commands", ...extraArgs];
|
|
35
|
+
if (model) args.push("--model", model);
|
|
36
|
+
const res = await this.runCommand(resolveBin("agy"), args, {
|
|
37
|
+
onOutput: task.onOutput,
|
|
38
|
+
silenceTimeoutMs: task.silenceTimeoutMs,
|
|
39
|
+
timeout: task.timeoutMs,
|
|
40
|
+
cwd: task.cwd,
|
|
41
|
+
});
|
|
42
|
+
const parsed = extractAgyOutput(res.stdout);
|
|
43
|
+
const ok = res.exitCode === 0 && parsed?.status === "SUCCESS";
|
|
44
|
+
return {
|
|
45
|
+
ok,
|
|
46
|
+
output: parsed?.response ?? res.stdout,
|
|
47
|
+
error: ok ? res.stderr : parsed?.error || res.stderr || `agy status: ${parsed?.status || "unparseable"}`,
|
|
48
|
+
exitCode: res.exitCode,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Parse agy's single-object JSON print output ({status, response}), null if not JSON. */
|
|
54
|
+
export function extractAgyOutput(stdout) {
|
|
55
|
+
if (!stdout) return null;
|
|
56
|
+
try {
|
|
57
|
+
const obj = JSON.parse(stdout.trim());
|
|
58
|
+
return typeof obj === "object" && obj !== null ? obj : null;
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BaseAgent } from "./base-agent.js";
|
|
2
|
+
import { resolveBin } from "./resolve-bin.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Extract token usage from Aider's stdout. Two shapes are supported:
|
|
6
|
+
*
|
|
7
|
+
* 1. LiteLLM passthrough — an OpenAI-style JSON `usage` block surfaces
|
|
8
|
+
* `prompt_tokens_details.cached_tokens` for prompt-cache hits.
|
|
9
|
+
* 2. Aider's native footer "Tokens: <sent> sent, <received> received
|
|
10
|
+
* [, <cached> cache hit]." (supports comma-separated and `k` suffix).
|
|
11
|
+
*
|
|
12
|
+
* Returns `{tokens_in, tokens_out, cached_tokens}` or null when no usage
|
|
13
|
+
* is found (= unmeasured; callers leave the fields undefined).
|
|
14
|
+
*/
|
|
15
|
+
function extractAiderUsage(text) {
|
|
16
|
+
if (!text) return null;
|
|
17
|
+
for (const line of text.split("\n")) {
|
|
18
|
+
const t = line.trim();
|
|
19
|
+
if (!t.startsWith("{")) continue;
|
|
20
|
+
let obj;
|
|
21
|
+
try { obj = JSON.parse(t); } catch { continue; }
|
|
22
|
+
const u = obj?.usage ?? (typeof obj?.prompt_tokens === "number" ? obj : null);
|
|
23
|
+
if (!u || typeof u.prompt_tokens !== "number") continue;
|
|
24
|
+
return {
|
|
25
|
+
tokens_in: u.prompt_tokens,
|
|
26
|
+
tokens_out: u.completion_tokens ?? 0,
|
|
27
|
+
cached_tokens: u.prompt_tokens_details?.cached_tokens ?? 0
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const m = text.match(/Tokens:\s*([\d.,]+k?)\s*sent,\s*([\d.,]+k?)\s*received(?:,\s*([\d.,]+k?)\s*cache\s*hit)?/i);
|
|
31
|
+
if (!m) return null;
|
|
32
|
+
const parse = (s) => {
|
|
33
|
+
const c = s.replaceAll(",", "");
|
|
34
|
+
return c.toLowerCase().endsWith("k")
|
|
35
|
+
? Math.round(parseFloat(c.slice(0, -1)) * 1000)
|
|
36
|
+
: Number(c);
|
|
37
|
+
};
|
|
38
|
+
const sent = parse(m[1]);
|
|
39
|
+
const recv = parse(m[2]);
|
|
40
|
+
if (!Number.isFinite(sent) || !Number.isFinite(recv)) return null;
|
|
41
|
+
return { tokens_in: sent, tokens_out: recv, cached_tokens: m[3] ? parse(m[3]) : 0 };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class AiderAgent extends BaseAgent {
|
|
45
|
+
async runTask(task) {
|
|
46
|
+
const role = task.role || "coder";
|
|
47
|
+
const model = this.getRoleModel(role);
|
|
48
|
+
const result = await this._exec(task, model);
|
|
49
|
+
if (!result.ok && model && this.isModelNotSupportedError(result)) {
|
|
50
|
+
this.logger?.warn(`Aider model "${model}" not supported — retrying with agent default`);
|
|
51
|
+
return this._exec(task, null);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async reviewTask(task) {
|
|
57
|
+
const role = task.role || "reviewer";
|
|
58
|
+
const model = this.getRoleModel(role);
|
|
59
|
+
const result = await this._exec(task, model);
|
|
60
|
+
if (!result.ok && model && this.isModelNotSupportedError(result)) {
|
|
61
|
+
this.logger?.warn(`Aider model "${model}" not supported — retrying with agent default`);
|
|
62
|
+
return this._exec(task, null);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async _exec(task, model) {
|
|
68
|
+
const args = ["--yes", "--message", task.prompt];
|
|
69
|
+
if (model) args.push("--model", model);
|
|
70
|
+
const res = await this.runCommand(resolveBin("aider"), args, {
|
|
71
|
+
onOutput: task.onOutput,
|
|
72
|
+
silenceTimeoutMs: task.silenceTimeoutMs,
|
|
73
|
+
timeout: task.timeoutMs
|
|
74
|
+
});
|
|
75
|
+
const usage = extractAiderUsage(res.stdout) ?? extractAiderUsage(res.stderr);
|
|
76
|
+
return { ok: res.exitCode === 0, output: res.stdout, error: res.stderr, exitCode: res.exitCode, ...usage };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { runCommand } from "../utils/process.js";
|
|
2
|
+
import { resolveBin } from "./resolve-bin.js";
|
|
3
|
+
import { getAgentMeta } from "./index.js";
|
|
4
|
+
|
|
5
|
+
export async function assertAgentsAvailable(agentNames = []) {
|
|
6
|
+
const unique = [...new Set(agentNames.filter(Boolean))];
|
|
7
|
+
|
|
8
|
+
// PR-J (audit quick win): probe every agent CLI in parallel via
|
|
9
|
+
// Promise.all instead of awaiting in a for-of loop. Each probe is
|
|
10
|
+
// an independent fork+exec with no shared state, so serialising
|
|
11
|
+
// them was wasted preflight latency: O(n) shell-outs becomes O(1)
|
|
12
|
+
// (max of all probes). On 4 agents at ~80ms each this drops the
|
|
13
|
+
// wait from ~320ms to ~80ms.
|
|
14
|
+
const probes = await Promise.all(
|
|
15
|
+
unique.map(async (name) => {
|
|
16
|
+
const meta = getAgentMeta(name);
|
|
17
|
+
if (!meta?.bin) return null;
|
|
18
|
+
const res = await runCommand(resolveBin(meta.bin), ["--version"]);
|
|
19
|
+
return res.exitCode !== 0 ? { name, ...meta } : null;
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
const missing = probes.filter(Boolean);
|
|
23
|
+
|
|
24
|
+
if (missing.length === 0) return;
|
|
25
|
+
|
|
26
|
+
const lines = ["Missing required AI CLIs for this command:"];
|
|
27
|
+
for (const m of missing) {
|
|
28
|
+
lines.push(`- ${m.name}: command '${m.bin}' not found`, ` Install: ${m.installUrl}`);
|
|
29
|
+
}
|
|
30
|
+
throw new Error(lines.join("\n"));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Non-throwing counterpart to assertAgentsAvailable: probe each agent CLI in
|
|
35
|
+
* parallel and return the subset whose `--version` succeeds. Used by the
|
|
36
|
+
* audit fallback (KJC-BUG-0094) to skip uninstalled providers instead of
|
|
37
|
+
* aborting the whole command when any one is missing.
|
|
38
|
+
* @param {string[]} agentNames
|
|
39
|
+
* @returns {Promise<string[]>}
|
|
40
|
+
*/
|
|
41
|
+
export async function filterAvailableAgents(agentNames = []) {
|
|
42
|
+
const unique = [...new Set(agentNames.filter(Boolean))];
|
|
43
|
+
const probes = await Promise.all(
|
|
44
|
+
unique.map(async (name) => {
|
|
45
|
+
const meta = getAgentMeta(name);
|
|
46
|
+
if (!meta?.bin) return null;
|
|
47
|
+
const res = await runCommand(resolveBin(meta.bin), ["--version"]);
|
|
48
|
+
return res.exitCode === 0 ? name : null;
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
return probes.filter(Boolean);
|
|
52
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for provider-specific agent adapters (claude, codex, gemini, ...).
|
|
3
|
+
* Every concrete agent must implement runTask() and may override reviewTask().
|
|
4
|
+
*
|
|
5
|
+
* @typedef {import("../types/config.js").KarajanConfig} KarajanConfig
|
|
6
|
+
* @typedef {import("../types/stage.js").Logger} Logger
|
|
7
|
+
* @typedef {import("../types/agent.js").AgentResult} AgentResult
|
|
8
|
+
* @typedef {import("../infrastructure/environment.js").Environment} Environment
|
|
9
|
+
* @typedef {import("../infrastructure/command-runner.js").CommandRunResult} CommandRunResult
|
|
10
|
+
* @typedef {import("../infrastructure/command-runner.js").CommandRunOptions} CommandRunOptions
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { defaultEnvironment } from "../infrastructure/environment.js";
|
|
14
|
+
import { buildAgentEnv } from "../utils/role-env.js";
|
|
15
|
+
import { isModelCompatible } from "../config/role-resolver.js";
|
|
16
|
+
|
|
17
|
+
const MODEL_NOT_SUPPORTED_PATTERNS = [
|
|
18
|
+
/model.{0,30}is not supported/i,
|
|
19
|
+
/model.{0,30}not available/i,
|
|
20
|
+
/model.{0,30}does not exist/i,
|
|
21
|
+
/unsupported model/i,
|
|
22
|
+
/invalid model/i,
|
|
23
|
+
/model_not_found/i
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export class BaseAgent {
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} name - agent slug (claude|codex|gemini|aider|opencode)
|
|
29
|
+
* @param {KarajanConfig} config
|
|
30
|
+
* @param {Logger} logger
|
|
31
|
+
* @param {Environment} [environment] - DI-friendly fs + runner bundle. Defaults
|
|
32
|
+
* to the native filesystem and execa-based
|
|
33
|
+
* command runner. Tests pass a mock env to
|
|
34
|
+
* unit-test agent paths without spawning
|
|
35
|
+
* real processes.
|
|
36
|
+
*/
|
|
37
|
+
constructor(name, config, logger, environment = defaultEnvironment) {
|
|
38
|
+
this.name = name;
|
|
39
|
+
this.config = config;
|
|
40
|
+
this.logger = logger;
|
|
41
|
+
this.environment = environment;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run a shell command through the injected CommandRunner. Subclasses should
|
|
46
|
+
* call this instead of importing runCommand directly so tests can swap in
|
|
47
|
+
* MockCommandRunner.
|
|
48
|
+
* @param {string} command
|
|
49
|
+
* @param {string[]} [args]
|
|
50
|
+
* @param {CommandRunOptions} [options]
|
|
51
|
+
* @returns {Promise<CommandRunResult>}
|
|
52
|
+
*/
|
|
53
|
+
async runCommand(command, args = [], options = {}) {
|
|
54
|
+
// KJC-TSK-0693: the subprocess gets an env allowlist, never the user's
|
|
55
|
+
// whole environment. security.env_allowlist:false opts out.
|
|
56
|
+
if (this.config?.security?.env_allowlist !== false) {
|
|
57
|
+
// Solomon-arbitrated contract (KJC-TSK-0693): an explicit env WITH a
|
|
58
|
+
// PATH is a COMPLETE child env (agents build those from process.env and
|
|
59
|
+
// deliberately strip vars — cleanExecaOpts drops CLAUDECODE, qwen
|
|
60
|
+
// unsets gemini's trust var) and is filtered AS GIVEN. An env WITHOUT
|
|
61
|
+
// a PATH is a partial overlay and merges over the inherited env first,
|
|
62
|
+
// so an overlay caller can never cost the child PATH/HOME.
|
|
63
|
+
const complete = options.env && ("PATH" in options.env || "Path" in options.env);
|
|
64
|
+
const base = complete ? options.env : { ...process.env, ...options.env };
|
|
65
|
+
options = {
|
|
66
|
+
...options,
|
|
67
|
+
env: buildAgentEnv(base, {
|
|
68
|
+
agent: this.name,
|
|
69
|
+
passthrough: this.config?.security?.env_passthrough || [],
|
|
70
|
+
}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return this.environment.runner.run(command, args, options);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Execute a coding/agentic task. Subclasses MUST override.
|
|
78
|
+
* @param {string|Object} _task
|
|
79
|
+
* @returns {Promise<AgentResult>}
|
|
80
|
+
*/
|
|
81
|
+
async runTask(_task) {
|
|
82
|
+
throw new Error("runTask not implemented");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Execute a review task. Subclasses MAY override for different behaviour.
|
|
87
|
+
* @param {string|Object} _task
|
|
88
|
+
* @returns {Promise<AgentResult>}
|
|
89
|
+
*/
|
|
90
|
+
async reviewTask(_task) {
|
|
91
|
+
throw new Error("reviewTask not implemented");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} role
|
|
96
|
+
* @returns {string|null}
|
|
97
|
+
*/
|
|
98
|
+
getRoleModel(role) {
|
|
99
|
+
const roleModel =
|
|
100
|
+
this.config?.roles?.[role]?.model ||
|
|
101
|
+
(role === "reviewer" ? this.config?.reviewer_options?.model : this.config?.coder_options?.model) ||
|
|
102
|
+
null;
|
|
103
|
+
// KJC-BUG-0144 (campo, issue #1465): un default por-rol (start: haiku)
|
|
104
|
+
// puede caer sobre un provider de OTRA familia (agy, codex...) — el
|
|
105
|
+
// modelo se descarta con aviso y el agente usa su propio default,
|
|
106
|
+
// nunca se le pasa un --model ajeno.
|
|
107
|
+
if (roleModel && !isModelCompatible(this.name, roleModel)) {
|
|
108
|
+
this.logger?.warn?.(`model "${roleModel}" belongs to another family — dropping it for ${this.name} (role ${role})`);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
return roleModel;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {string} role
|
|
116
|
+
* @returns {boolean}
|
|
117
|
+
*/
|
|
118
|
+
isAutoApproveEnabled(role) {
|
|
119
|
+
if (role === "reviewer") return false;
|
|
120
|
+
return Boolean(this.config?.coder_options?.auto_approve);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Heuristic: does the agent's error look like "model not supported"?
|
|
125
|
+
* Used by the retry/fallback path.
|
|
126
|
+
* @param {Partial<AgentResult>} result
|
|
127
|
+
* @returns {boolean}
|
|
128
|
+
*/
|
|
129
|
+
isModelNotSupportedError(result) {
|
|
130
|
+
const text = [result?.error, result?.output, result?.stderr, result?.stdout]
|
|
131
|
+
.filter(Boolean).join("\n");
|
|
132
|
+
return MODEL_NOT_SUPPORTED_PATTERNS.some(re => re.test(text));
|
|
133
|
+
}
|
|
134
|
+
}
|