@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,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verdict store (ENV-B1, KJC-TSK-0637) — persists cross-AI review verdicts
|
|
3
|
+
* keyed by the sha256 of the RAW diff they reviewed.
|
|
4
|
+
*
|
|
5
|
+
* The hash is the contract: a verdict only counts for byte-identical
|
|
6
|
+
* content, so any change after the review voids it and forces a new one
|
|
7
|
+
* (resolve-until-pass by construction). The pre-commit hook (ENV-C)
|
|
8
|
+
* calls checkVerdict() with the staged diff to decide whether the
|
|
9
|
+
* commit may enter. Diffs must be raw git output — never rtk-compressed
|
|
10
|
+
* (KJC-BUG-0115).
|
|
11
|
+
*/
|
|
12
|
+
import crypto from "node:crypto";
|
|
13
|
+
import fs from "node:fs/promises";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { runCommand } from "../utils/process.js";
|
|
16
|
+
|
|
17
|
+
const STORE_DIR = path.join(".karajan", "reviews");
|
|
18
|
+
|
|
19
|
+
export function diffHash(diff) {
|
|
20
|
+
// trimEnd: runners differ on the final newline (execa strips it, raw
|
|
21
|
+
// git keeps it) — trailing whitespace must not void a verdict.
|
|
22
|
+
return crypto.createHash("sha256").update(diff.trimEnd(), "utf8").digest("hex");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function verdictPath(projectDir, hash) {
|
|
26
|
+
return path.join(projectDir, STORE_DIR, `${hash}.json`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function saveVerdict(projectDir, diff, verdict) {
|
|
30
|
+
const hash = diffHash(diff);
|
|
31
|
+
const record = {
|
|
32
|
+
...verdict,
|
|
33
|
+
diffHash: hash,
|
|
34
|
+
timestamp: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
const file = verdictPath(projectDir, hash);
|
|
37
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
38
|
+
await fs.writeFile(file, `${JSON.stringify(record, null, 2)}\n`);
|
|
39
|
+
return record;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function loadVerdict(projectDir, hash) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(await fs.readFile(verdictPath(projectDir, hash), "utf8"));
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* ENV-F1 (KJC-TSK-0643): headless pipeline sessions call this after staging
|
|
52
|
+
* and before committing. Their reviewer ALREADY cross-AI-reviewed the work,
|
|
53
|
+
* so the verdict is recorded for the staged diff and the v4 pre-commit gate
|
|
54
|
+
* accepts the pipeline's commit. No gate marker → no-op (zero overhead for
|
|
55
|
+
* repos that never opted in). Raw git only — never a wrapped runner
|
|
56
|
+
* (KJC-BUG-0115).
|
|
57
|
+
* @returns {Promise<{stamped: boolean}>}
|
|
58
|
+
*/
|
|
59
|
+
export async function stampStagedVerdict({ projectDir, reviewer, summary = "" }) {
|
|
60
|
+
const dir = projectDir || process.cwd();
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(path.join(dir, ".karajan", "review-gate"));
|
|
63
|
+
} catch {
|
|
64
|
+
return { stamped: false };
|
|
65
|
+
}
|
|
66
|
+
const res = await runCommand("git", ["diff", "--cached"], { cwd: dir });
|
|
67
|
+
if (res.exitCode !== 0 || !res.stdout?.trim()) return { stamped: false };
|
|
68
|
+
await saveVerdict(dir, res.stdout, {
|
|
69
|
+
verdict: "approved", reviewer, host: "kj-pipeline", issues: [], summary,
|
|
70
|
+
});
|
|
71
|
+
return { stamped: true };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Is there an APPROVED verdict for exactly this diff?
|
|
76
|
+
* @returns {Promise<{ok: boolean, verdict?: object, reason?: string}>}
|
|
77
|
+
*/
|
|
78
|
+
export async function checkVerdict(projectDir, diff) {
|
|
79
|
+
const verdict = await loadVerdict(projectDir, diffHash(diff));
|
|
80
|
+
if (!verdict) {
|
|
81
|
+
return { ok: false, reason: "no verdict recorded for the current diff — run `kj review`" };
|
|
82
|
+
}
|
|
83
|
+
if (verdict.verdict !== "approved") {
|
|
84
|
+
return { ok: false, verdict, reason: `review was rejected by ${verdict.reviewer} — fix the issues and run \`kj review\` again` };
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, verdict };
|
|
87
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace detection for the review gate (KJC-TSK-0680). Field case: an
|
|
3
|
+
* agent claimed worktree isolation while editing the project root. The
|
|
4
|
+
* verdict now stamps WHERE the review actually ran, using the same proof
|
|
5
|
+
* the playbook demands: in a linked worktree, `git rev-parse --git-dir`
|
|
6
|
+
* differs from `--git-common-dir`. "root" | "worktree:<name>" | null
|
|
7
|
+
* (not a git repo — the gate itself will fail later with its own error).
|
|
8
|
+
*/
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { runCommand } from "../utils/process.js";
|
|
11
|
+
|
|
12
|
+
export async function detectWorkspace(dir) {
|
|
13
|
+
const res = await runCommand("git", ["rev-parse", "--git-dir", "--git-common-dir", "--show-toplevel"], { cwd: dir });
|
|
14
|
+
if (res.exitCode !== 0) return null;
|
|
15
|
+
const [gitDir, commonDir, toplevel] = String(res.stdout).trim().split("\n").map((l) => l.trim());
|
|
16
|
+
if (!gitDir || !commonDir) return null;
|
|
17
|
+
const resolvedGit = path.resolve(dir, gitDir);
|
|
18
|
+
const resolvedCommon = path.resolve(dir, commonDir);
|
|
19
|
+
if (resolvedGit === resolvedCommon) return "root";
|
|
20
|
+
return `worktree:${path.basename(toplevel || dir)}`;
|
|
21
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for LLM-backed roles.
|
|
3
|
+
* Handles the common execute() flow: resolve provider → create agent → call LLM → parse output.
|
|
4
|
+
* Subclasses override hooks (buildPrompt, parseOutput, buildSuccessResult, buildSummary)
|
|
5
|
+
* instead of reimplementing the full execute() boilerplate.
|
|
6
|
+
*
|
|
7
|
+
* Conceptual mapping: `AgentRole` is a Karajan Role that delegates to an AI CLI
|
|
8
|
+
* subprocess (not to a provider HTTP API). From the outside it plays the same
|
|
9
|
+
* role as a Genkit Flow — named unit of work with a prompt and a parsed output —
|
|
10
|
+
* but every invocation spawns a fresh `execa` subprocess (claude, codex, gemini,
|
|
11
|
+
* aider, opencode) and the state lives in Karajan's session store, not in a
|
|
12
|
+
* provider-side conversation. See `docs/COMPARISON.md`.
|
|
13
|
+
*
|
|
14
|
+
* @alias Flow — similar to Genkit Flow but executed over subprocess CLIs, not API calls.
|
|
15
|
+
*/
|
|
16
|
+
import { BaseRole } from "./base-role.js";
|
|
17
|
+
import { createAgent as defaultCreateAgent } from "../agents/index.js";
|
|
18
|
+
import { withBrainRecovery } from "../brain/with-brain-recovery.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Silence timeout (ms) for an agent subprocess, from
|
|
22
|
+
* config.session.max_agent_silence_minutes. runCommand kills a child
|
|
23
|
+
* that produces no output for this long — without it a hung coder /
|
|
24
|
+
* reviewer leaves `kj run` waiting forever. Returns null when unset.
|
|
25
|
+
* @param {object} config
|
|
26
|
+
* @returns {number|null}
|
|
27
|
+
*/
|
|
28
|
+
function resolveAgentSilenceTimeoutMs(config) {
|
|
29
|
+
const minutes = Number(config?.session?.max_agent_silence_minutes);
|
|
30
|
+
return Number.isFinite(minutes) && minutes > 0 ? Math.round(minutes * 60 * 1000) : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AgentRole extends BaseRole {
|
|
34
|
+
constructor({ name, config, logger, emitter = null, createAgentFn = null }) {
|
|
35
|
+
super({ name, config, logger, emitter });
|
|
36
|
+
this._createAgent = createAgentFn || defaultCreateAgent;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Provider fallback chain. Override for roles with non-standard chains. */
|
|
40
|
+
resolveProvider() {
|
|
41
|
+
return (
|
|
42
|
+
this.config?.roles?.[this.name]?.provider ||
|
|
43
|
+
this.config?.roles?.coder?.provider ||
|
|
44
|
+
"claude"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Agent method to call. Override with "reviewTask" for reviewer. */
|
|
49
|
+
get agentMethod() { return "runTask"; }
|
|
50
|
+
|
|
51
|
+
/** Create the agent. Override for special logic (e.g. HostAgent in coder). */
|
|
52
|
+
createAgentInstance(provider) {
|
|
53
|
+
return this._createAgent(provider, this.config, this.logger);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build the prompt for this role. MUST be overridden.
|
|
58
|
+
* @param {*} input - raw input from pipeline
|
|
59
|
+
* @returns {Promise<{prompt: string, onOutput?: Function}>|{prompt: string, onOutput?: Function}|string}
|
|
60
|
+
*/
|
|
61
|
+
async buildPrompt(_input) {
|
|
62
|
+
throw new Error(`${this.name}: buildPrompt() not implemented`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse raw LLM output into structured data. Return null to trigger handleParseNull.
|
|
67
|
+
* @param {string} raw - raw agent output
|
|
68
|
+
* @returns {*} parsed result
|
|
69
|
+
*/
|
|
70
|
+
parseOutput(raw) { return raw; }
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build the result object for a successful parse.
|
|
74
|
+
* @param {*} parsed - output of parseOutput
|
|
75
|
+
* @param {string} provider
|
|
76
|
+
* @param {object} agentResult - full agent result (for accessing .usage, .output, etc.)
|
|
77
|
+
* @returns {object} result to include in { ok, result, summary, usage }
|
|
78
|
+
*/
|
|
79
|
+
buildSuccessResult(parsed, provider, _agentResult) { return { ...parsed, provider }; }
|
|
80
|
+
|
|
81
|
+
/** Build human-readable summary from parsed output. */
|
|
82
|
+
buildSummary(_parsed) { return `${this.name} completed`; }
|
|
83
|
+
|
|
84
|
+
/** Determine ok status from parsed result. Default: true. Override for verdict-based roles. */
|
|
85
|
+
isSuccessful(_parsed) { return true; }
|
|
86
|
+
|
|
87
|
+
/** Handle null parse (no JSON found). Default returns error. Override for lenient roles. */
|
|
88
|
+
handleParseNull(agentResult, provider) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
result: { error: `Failed to parse ${this.name} output: no JSON found`, provider },
|
|
92
|
+
summary: `${this.name} output parse error: no JSON found`,
|
|
93
|
+
usage: agentResult.usage
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Handle parse exception. Default returns error. Override for lenient roles. */
|
|
98
|
+
handleParseError(err, agentResult, provider) {
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
result: { error: `Failed to parse ${this.name} output: ${err.message}`, provider },
|
|
102
|
+
summary: `${this.name} output parse error: ${err.message}`,
|
|
103
|
+
usage: agentResult.usage
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Extract input fields from raw input. Default handles string-or-object.
|
|
109
|
+
* Override for roles needing extra fields.
|
|
110
|
+
*/
|
|
111
|
+
extractInput(input) {
|
|
112
|
+
if (typeof input === "string") return { task: input, onOutput: null };
|
|
113
|
+
return {
|
|
114
|
+
task: input?.task || this.context?.task || "",
|
|
115
|
+
onOutput: input?.onOutput || null,
|
|
116
|
+
...input
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async execute(input) {
|
|
121
|
+
const extracted = this.extractInput(input);
|
|
122
|
+
const provider = this.resolveProvider();
|
|
123
|
+
const agent = this.createAgentInstance(provider);
|
|
124
|
+
|
|
125
|
+
const promptResult = await this.buildPrompt(extracted);
|
|
126
|
+
const { prompt, onOutput, stablePrompt, volatilePrompt } = typeof promptResult === "string"
|
|
127
|
+
? { prompt: promptResult, onOutput: extracted.onOutput }
|
|
128
|
+
: { onOutput: extracted.onOutput, ...promptResult };
|
|
129
|
+
|
|
130
|
+
const runArgs = { prompt, role: this.name };
|
|
131
|
+
if (onOutput) runArgs.onOutput = onOutput;
|
|
132
|
+
// PAR-H (KJC-TSK-0631): per-call env additions for the agent
|
|
133
|
+
// subprocess (lane slot vars). Agents that ignore task.env simply
|
|
134
|
+
// run without them.
|
|
135
|
+
if (extracted.env) runArgs.env = extracted.env;
|
|
136
|
+
// Φ1-D (KJC-PCS-0057): roles that build their prompt as a
|
|
137
|
+
// stable/volatile layout forward both buckets so cache-aware agents
|
|
138
|
+
// (ClaudeAgent) can ship the stable block as system prompt. Agents
|
|
139
|
+
// that don't know the fields keep reading `prompt` as before.
|
|
140
|
+
if (stablePrompt && volatilePrompt) {
|
|
141
|
+
runArgs.stablePrompt = stablePrompt;
|
|
142
|
+
runArgs.volatilePrompt = volatilePrompt;
|
|
143
|
+
}
|
|
144
|
+
// Kill a hung agent: without a silence timeout a coder / reviewer
|
|
145
|
+
// that stalls with no output left `kj run` waiting indefinitely.
|
|
146
|
+
// PlannerRole set this itself; every other role was unprotected.
|
|
147
|
+
const silenceTimeoutMs = resolveAgentSilenceTimeoutMs(this.config);
|
|
148
|
+
if (silenceTimeoutMs) runArgs.silenceTimeoutMs = silenceTimeoutMs;
|
|
149
|
+
|
|
150
|
+
// KJC-TSK-0413 step B: TODAS las roles que heredan de AgentRole pasan
|
|
151
|
+
// por Brain Recovery aquí — cubre AuditRole, SecurityRole, HuReviewerRole,
|
|
152
|
+
// CoderRole, ArchitectRole, DiscoverRole, ImpeccableRole, RefactorerRole,
|
|
153
|
+
// ResearcherRole, TriageRole, etc. Roles con agentMethod custom (ej.
|
|
154
|
+
// reviewer usa reviewTask) también funcionan: el wrapper sólo necesita
|
|
155
|
+
// un objeto con la firma `runTask(args) → { ok, output, error, exitCode }`.
|
|
156
|
+
const result = await withBrainRecovery({
|
|
157
|
+
agent: { runTask: (args) => agent[this.agentMethod](args), provider },
|
|
158
|
+
taskArgs: runArgs,
|
|
159
|
+
role: this.name,
|
|
160
|
+
provider,
|
|
161
|
+
emitter: this.emitter,
|
|
162
|
+
logger: this.logger,
|
|
163
|
+
// KJC: sessionState lets withBrainRecovery persist a hibernating run
|
|
164
|
+
// to ~/.kj/standby/ so it can be resumed. Without it a quota-exhausted
|
|
165
|
+
// run had nothing to resume from. Caller (coder-stage etc.) passes it
|
|
166
|
+
// through the input object; extractInput forwards it via `...input`.
|
|
167
|
+
sessionState: extracted.sessionState || this.context?.sessionState || null,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (!result.ok) {
|
|
171
|
+
const recoveryNote = result.recovery?.class ? ` [${result.recovery.class}]` : "";
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
result: { error: result.error || result.output || `${this.name} failed${recoveryNote}`, provider, recovery: result.recovery, action: result.action, standbyFile: result.standbyFile || null },
|
|
175
|
+
summary: `${this.name} failed${recoveryNote}: ${result.recovery?.message || result.error || "unknown error"}`,
|
|
176
|
+
usage: result.usage
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const parsed = this.parseOutput(result.output);
|
|
182
|
+
if (parsed === null) return this.handleParseNull(result, provider);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
ok: this.isSuccessful(parsed),
|
|
186
|
+
result: this.buildSuccessResult(parsed, provider, result),
|
|
187
|
+
summary: this.buildSummary(parsed),
|
|
188
|
+
usage: result.usage
|
|
189
|
+
};
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return this.handleParseError(err, result, provider);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { AgentRole } from "./agent-role.js";
|
|
2
|
+
import { buildArchitectPrompt, parseArchitectOutput } from "../prompts/architect.js";
|
|
3
|
+
|
|
4
|
+
const EMPTY_ARCHITECTURE = {
|
|
5
|
+
type: "", layers: [], patterns: [], dataModel: { entities: [] },
|
|
6
|
+
apiContracts: [], dependencies: [], tradeoffs: []
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export class ArchitectRole extends AgentRole {
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
super({ ...opts, name: "architect" });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
extractInput(input) {
|
|
15
|
+
if (typeof input === "string") return { task: input, researchContext: null, onOutput: null };
|
|
16
|
+
return {
|
|
17
|
+
task: input?.task || this.context?.task || "",
|
|
18
|
+
researchContext: input?.researchContext || null,
|
|
19
|
+
onOutput: input?.onOutput || null
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async buildPrompt({ task, researchContext }) {
|
|
24
|
+
const prompt = await buildArchitectPrompt({
|
|
25
|
+
task, instructions: this.instructions, researchContext,
|
|
26
|
+
productContext: this.config?.productContext || null,
|
|
27
|
+
domainContext: this.config?.domainContext || null,
|
|
28
|
+
projectDir: this.config?.projectDir || null,
|
|
29
|
+
provider: this._resolvedProvider || (typeof this.resolveProvider === "function" ? this.resolveProvider() : null)
|
|
30
|
+
});
|
|
31
|
+
return { prompt };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
parseOutput(raw) { return parseArchitectOutput(raw); }
|
|
35
|
+
|
|
36
|
+
buildSuccessResult(parsed, provider) {
|
|
37
|
+
return {
|
|
38
|
+
verdict: parsed.verdict,
|
|
39
|
+
architecture: parsed.architecture,
|
|
40
|
+
questions: parsed.questions,
|
|
41
|
+
provider
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
buildSummary(parsed) {
|
|
46
|
+
const parts = [];
|
|
47
|
+
const arch = parsed.architecture;
|
|
48
|
+
if (arch.type) parts.push(arch.type);
|
|
49
|
+
const layers = arch.layers?.length || 0;
|
|
50
|
+
if (layers) parts.push(`${layers} layer${layers === 1 ? "" : "s"}`);
|
|
51
|
+
const patterns = arch.patterns?.length || 0;
|
|
52
|
+
if (patterns) parts.push(`${patterns} pattern${patterns === 1 ? "" : "s"}`);
|
|
53
|
+
const entities = arch.dataModel?.entities?.length || 0;
|
|
54
|
+
if (entities) parts.push(`${entities} entit${entities === 1 ? "y" : "ies"}`);
|
|
55
|
+
const questions = parsed.questions?.length || 0;
|
|
56
|
+
if (questions) parts.push(`${questions} question${questions === 1 ? "" : "s"}`);
|
|
57
|
+
return parts.length
|
|
58
|
+
? `Architecture complete: ${parts.join(", ")} (verdict: ${parsed.verdict})`
|
|
59
|
+
: "Architecture complete";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
handleParseNull(agentResult, provider) {
|
|
63
|
+
return {
|
|
64
|
+
ok: true,
|
|
65
|
+
result: {
|
|
66
|
+
verdict: "needs_clarification", architecture: { ...EMPTY_ARCHITECTURE },
|
|
67
|
+
questions: [], raw: agentResult.output, provider
|
|
68
|
+
},
|
|
69
|
+
summary: "Architecture complete (unstructured output)",
|
|
70
|
+
usage: agentResult.usage
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
handleParseError(_err, agentResult, provider) {
|
|
75
|
+
return this.handleParseNull(agentResult, provider);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { AgentRole } from "./agent-role.js";
|
|
2
|
+
import { buildAuditPrompt, parseAuditOutput, AUDIT_DIMENSIONS } from "../prompts/audit.js";
|
|
3
|
+
import { measureBasalCost, loadPreviousAudit, saveAuditSnapshot, computeGrowthDelta } from "../audit/basal-cost.js";
|
|
4
|
+
import { detectProjectStack } from "../utils/stack-detect.js";
|
|
5
|
+
import { collectSonarFindings } from "../audit/sonar-findings.js";
|
|
6
|
+
import { collectWebPerfInput } from "../audit/webperf-input.js";
|
|
7
|
+
import { collectOsvFindings } from "../audit/osv-findings.js";
|
|
8
|
+
import { collectSemgrepFindings } from "../audit/semgrep-findings.js";
|
|
9
|
+
import { collectInfraFindings } from "../audit/infra-findings.js";
|
|
10
|
+
import { collectCircularDeps } from "../audit/circular-deps.js";
|
|
11
|
+
import { collectDeadExports } from "../audit/dead-exports.js";
|
|
12
|
+
import { collectInjectionFindings } from "../audit/injection-findings.js";
|
|
13
|
+
import { collectAiSlop } from "../audit/ai-slop-findings.js";
|
|
14
|
+
|
|
15
|
+
function parseDimensions(dimensionsStr) {
|
|
16
|
+
if (!dimensionsStr || dimensionsStr === "all") return null;
|
|
17
|
+
const requested = dimensionsStr.split(",").map(d => d.trim().toLowerCase());
|
|
18
|
+
const mapped = requested.map(d => d === "quality" ? "codeQuality" : d);
|
|
19
|
+
const valid = mapped.filter(d => AUDIT_DIMENSIONS.includes(d));
|
|
20
|
+
return valid.length > 0 ? valid : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function buildSummary(parsed) {
|
|
24
|
+
const { summary } = parsed;
|
|
25
|
+
const parts = [];
|
|
26
|
+
if (summary.critical > 0) parts.push(`${summary.critical} critical`);
|
|
27
|
+
if (summary.high > 0) parts.push(`${summary.high} high`);
|
|
28
|
+
if (summary.medium > 0) parts.push(`${summary.medium} medium`);
|
|
29
|
+
if (summary.low > 0) parts.push(`${summary.low} low`);
|
|
30
|
+
const findingsStr = parts.length > 0 ? parts.join(", ") : "no issues";
|
|
31
|
+
return `Overall health: ${summary.overallHealth}. ${summary.totalFindings} findings (${findingsStr})`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class AuditRole extends AgentRole {
|
|
35
|
+
constructor(opts) {
|
|
36
|
+
super({ ...opts, name: "audit" });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Run the deterministic side of an audit — basalCost, stack detection,
|
|
41
|
+
* Sonar issues, WebPerf input — without invoking the LLM. Cheap (no
|
|
42
|
+
* tokens, no API call). KJC-TSK-0364 splits the original execute() into
|
|
43
|
+
* this collector + executeWithDeterministic() so the CLI can show
|
|
44
|
+
* deterministic findings first and ask the user before paying for the
|
|
45
|
+
* LLM phase.
|
|
46
|
+
*
|
|
47
|
+
* @param {object|string} input - same shape execute() accepts
|
|
48
|
+
* @returns {Promise<object>} deterministic context (the same data
|
|
49
|
+
* execute() would gather internally)
|
|
50
|
+
*/
|
|
51
|
+
async collectDeterministic(input) {
|
|
52
|
+
// KJC-TSK-0695: securityOnly = the focused pass an agent self-invokes
|
|
53
|
+
// when a task touches sensitive surface. Only the security collectors
|
|
54
|
+
// run (sonar, osv, semgrep, injection) — zero tokens, fast.
|
|
55
|
+
const securityOnly = typeof input === "object" ? Boolean(input?.securityOnly) : false;
|
|
56
|
+
const noSonar = typeof input === "object" ? Boolean(input?.noSonar) : false;
|
|
57
|
+
const noOsv = typeof input === "object" ? Boolean(input?.noOsv) : false;
|
|
58
|
+
const noSemgrep = typeof input === "object" ? Boolean(input?.noSemgrep) : false;
|
|
59
|
+
const noMadge = (typeof input === "object" ? Boolean(input?.noMadge) : false) || securityOnly;
|
|
60
|
+
const noKnip = (typeof input === "object" ? Boolean(input?.noKnip) : false) || securityOnly;
|
|
61
|
+
const noInjectionScan = typeof input === "object" ? Boolean(input?.noInjectionScan) : false;
|
|
62
|
+
const noInfraScan = typeof input === "object" ? Boolean(input?.noInfraScan) : false;
|
|
63
|
+
const noAiSlop = (typeof input === "object" ? Boolean(input?.noAiSlop) : false) || securityOnly;
|
|
64
|
+
const projectDir = this.config?.projectDir || process.cwd();
|
|
65
|
+
let basalCost = null;
|
|
66
|
+
let growthDelta = null;
|
|
67
|
+
let stack = null;
|
|
68
|
+
let sonarFindings = null;
|
|
69
|
+
let webperf = null;
|
|
70
|
+
let osvFindings = null;
|
|
71
|
+
let semgrepFindings = null;
|
|
72
|
+
let circularDeps = null;
|
|
73
|
+
let deadExports = null;
|
|
74
|
+
let injectionFindings = null;
|
|
75
|
+
let infraFindings = null;
|
|
76
|
+
let aiSlop = null;
|
|
77
|
+
if (!securityOnly) {
|
|
78
|
+
try {
|
|
79
|
+
basalCost = await measureBasalCost(projectDir);
|
|
80
|
+
const previous = await loadPreviousAudit(projectDir);
|
|
81
|
+
growthDelta = computeGrowthDelta(basalCost, previous);
|
|
82
|
+
} catch { /* basal cost is best-effort */ }
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
stack = await detectProjectStack(projectDir);
|
|
86
|
+
} catch { /* stack detect is best-effort */ }
|
|
87
|
+
if (!noSonar) {
|
|
88
|
+
try {
|
|
89
|
+
sonarFindings = await collectSonarFindings(this.config, this.logger);
|
|
90
|
+
} catch { /* sonar fetch is best-effort */ }
|
|
91
|
+
}
|
|
92
|
+
if (!securityOnly) {
|
|
93
|
+
try {
|
|
94
|
+
webperf = collectWebPerfInput(stack, this.config);
|
|
95
|
+
} catch { /* webperf input is best-effort */ }
|
|
96
|
+
}
|
|
97
|
+
// OSV vulnerabilities — KJC-TSK-0365. Best-effort: missing
|
|
98
|
+
// osv-scanner binary returns available:false and the audit
|
|
99
|
+
// continues without the section.
|
|
100
|
+
if (!noOsv) {
|
|
101
|
+
try {
|
|
102
|
+
osvFindings = await collectOsvFindings(projectDir, this.logger);
|
|
103
|
+
} catch { /* osv-scanner is best-effort */ }
|
|
104
|
+
}
|
|
105
|
+
// Semgrep SAST — KJC-TSK-0366. Best-effort: missing semgrep binary
|
|
106
|
+
// returns available:false and the audit continues without the section.
|
|
107
|
+
if (!noSemgrep) {
|
|
108
|
+
try {
|
|
109
|
+
semgrepFindings = await collectSemgrepFindings(projectDir, this.logger);
|
|
110
|
+
} catch { /* semgrep is best-effort */ }
|
|
111
|
+
}
|
|
112
|
+
// Madge circular-import deps — KJC-TSK v2.17. Stack-aware: skipped for
|
|
113
|
+
// non-JS/TS projects. Best-effort: any failure returns available:false
|
|
114
|
+
// and the audit continues without the section.
|
|
115
|
+
if (!noMadge) {
|
|
116
|
+
try {
|
|
117
|
+
circularDeps = await collectCircularDeps(projectDir, stack, this.config, this.logger);
|
|
118
|
+
} catch { /* madge is best-effort */ }
|
|
119
|
+
}
|
|
120
|
+
// Knip dead-exports — KJC-TSK v2.17. Stack-aware, JS/TS only, needs
|
|
121
|
+
// package.json. Best-effort: any failure returns available:false and
|
|
122
|
+
// the audit continues without the section.
|
|
123
|
+
if (!noKnip) {
|
|
124
|
+
try {
|
|
125
|
+
deadExports = await collectDeadExports(projectDir, stack, this.config, this.logger);
|
|
126
|
+
} catch { /* knip is best-effort */ }
|
|
127
|
+
}
|
|
128
|
+
if (!noInjectionScan) {
|
|
129
|
+
try {
|
|
130
|
+
injectionFindings = await collectInjectionFindings(projectDir, this.logger);
|
|
131
|
+
} catch { /* injection scan is best-effort (KJC-TSK-0498) */ }
|
|
132
|
+
}
|
|
133
|
+
// Checkov infra misconfigs — INF-C (KJC-TSK-0760). Security surface, so
|
|
134
|
+
// it ALSO runs in securityOnly. Best-effort: no infra markers or missing
|
|
135
|
+
// checkov return available:false declaring why.
|
|
136
|
+
if (!noInfraScan) {
|
|
137
|
+
try {
|
|
138
|
+
infraFindings = await collectInfraFindings(projectDir, this.logger);
|
|
139
|
+
} catch { /* checkov is best-effort */ }
|
|
140
|
+
}
|
|
141
|
+
// AI-slop tells (KJC-TSK-0503). Deterministic, offline, regex-based.
|
|
142
|
+
// Local equivalent of Deslopify-style review. Best-effort.
|
|
143
|
+
if (!noAiSlop) {
|
|
144
|
+
try {
|
|
145
|
+
aiSlop = await collectAiSlop(projectDir);
|
|
146
|
+
} catch { /* ai-slop scan is best-effort */ }
|
|
147
|
+
}
|
|
148
|
+
return { projectDir, basalCost, growthDelta, stack, sonarFindings, webperf, osvFindings, semgrepFindings, circularDeps, deadExports, injectionFindings, infraFindings, aiSlop };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Run the LLM phase of an audit using a pre-collected deterministic
|
|
153
|
+
* context. KJC-TSK-0364: separated from execute() so the CLI can run
|
|
154
|
+
* collectDeterministic() first, show findings, prompt, and only then
|
|
155
|
+
* call this if the user wants to spend tokens.
|
|
156
|
+
*/
|
|
157
|
+
async executeWithDeterministic(input, deterministicCtx) {
|
|
158
|
+
const task = typeof input === "string" ? input : input?.task || this.context?.task || "";
|
|
159
|
+
const onOutput = typeof input === "string" ? null : input?.onOutput || null;
|
|
160
|
+
const rawDimensions = typeof input === "object" ? input?.dimensions || null : null;
|
|
161
|
+
const context = typeof input === "object" ? input?.context || null : null;
|
|
162
|
+
const dimensions = typeof rawDimensions === "string" ? parseDimensions(rawDimensions) : rawDimensions;
|
|
163
|
+
|
|
164
|
+
const { projectDir, basalCost, growthDelta, stack, sonarFindings, webperf, osvFindings, semgrepFindings, circularDeps, deadExports } = deterministicCtx;
|
|
165
|
+
|
|
166
|
+
const provider = this.resolveProvider();
|
|
167
|
+
const agent = this.createAgentInstance(provider);
|
|
168
|
+
const prompt = buildAuditPrompt({ task, instructions: this.instructions, dimensions, context, basalCost, growthDelta, stack, sonarFindings, webperf, osvFindings, semgrepFindings, circularDeps, deadExports });
|
|
169
|
+
const runArgs = { prompt, role: "audit" };
|
|
170
|
+
if (onOutput) runArgs.onOutput = onOutput;
|
|
171
|
+
const startedAt = Date.now();
|
|
172
|
+
const result = await agent.runTask(runArgs);
|
|
173
|
+
const durationMs = Date.now() - startedAt;
|
|
174
|
+
|
|
175
|
+
const usage = extractUsage(result, { provider, durationMs });
|
|
176
|
+
|
|
177
|
+
if (!result.ok) {
|
|
178
|
+
return { ok: false, result: { error: result.error || result.output || "Audit failed", provider }, summary: `Audit failed: ${result.error || "unknown error"}`, usage };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const parsed = parseAuditOutput(result.output);
|
|
183
|
+
if (!parsed) {
|
|
184
|
+
return { ok: true, result: { raw: result.output, provider }, summary: "Audit complete (unstructured output)", usage };
|
|
185
|
+
}
|
|
186
|
+
if (basalCost) { try { await saveAuditSnapshot(projectDir, basalCost); } catch { /* best-effort */ } }
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
ok: true,
|
|
190
|
+
result: {
|
|
191
|
+
summary: parsed.summary, dimensions: parsed.dimensions,
|
|
192
|
+
topRecommendations: parsed.topRecommendations,
|
|
193
|
+
textSummary: parsed.textSummary || undefined,
|
|
194
|
+
basalCost: basalCost || undefined, growthDelta: growthDelta || undefined,
|
|
195
|
+
stack: stack || undefined,
|
|
196
|
+
sonarFindings: sonarFindings?.available ? sonarFindings : undefined,
|
|
197
|
+
webperf: webperf?.available ? webperf : undefined,
|
|
198
|
+
osvFindings: osvFindings?.available ? osvFindings : undefined,
|
|
199
|
+
semgrepFindings: semgrepFindings?.available ? semgrepFindings : undefined,
|
|
200
|
+
circularDeps: circularDeps?.available ? circularDeps : undefined,
|
|
201
|
+
deadExports: deadExports?.available ? deadExports : undefined,
|
|
202
|
+
provider
|
|
203
|
+
},
|
|
204
|
+
summary: buildSummary(parsed),
|
|
205
|
+
usage
|
|
206
|
+
};
|
|
207
|
+
} catch {
|
|
208
|
+
return { ok: true, result: { raw: result.output, provider }, summary: "Audit complete (unstructured output)", usage };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Convenience: run both phases in one call. Identical to the previous
|
|
214
|
+
* (single-phase) execute() so MCP and pipeline callers don't change.
|
|
215
|
+
*/
|
|
216
|
+
async execute(input) {
|
|
217
|
+
const deterministicCtx = await this.collectDeterministic(input);
|
|
218
|
+
return this.executeWithDeterministic(input, deterministicCtx);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Consolidate the usage telemetry the agent spreads across its top-level
|
|
224
|
+
* result fields. Returns a single object so consumers (CLI formatter,
|
|
225
|
+
* report-file writer, MCP) don't need to know about the spread shape.
|
|
226
|
+
*
|
|
227
|
+
* Consumed by tests via vi.importActual (knip blind spot) — keep exported.
|
|
228
|
+
* @public
|
|
229
|
+
* @param {object} result - raw agent.runTask() return
|
|
230
|
+
* @param {{provider: string, durationMs: number}} ctx
|
|
231
|
+
* @returns {{available: boolean, provider: string, model?: string, tokens_in?: number, tokens_out?: number, cached_tokens?: number, total_tokens?: number, cost_usd?: number, durationMs: number, reason?: string}}
|
|
232
|
+
*/
|
|
233
|
+
export function extractUsage(result, { provider, durationMs }) {
|
|
234
|
+
if (!result || typeof result !== "object") {
|
|
235
|
+
return { available: false, provider, durationMs, reason: "no agent result" };
|
|
236
|
+
}
|
|
237
|
+
const tokens_in = Number.isFinite(result.tokens_in) ? result.tokens_in : null;
|
|
238
|
+
const tokens_out = Number.isFinite(result.tokens_out) ? result.tokens_out : null;
|
|
239
|
+
if (tokens_in === null && tokens_out === null) {
|
|
240
|
+
return { available: false, provider, model: result.model, durationMs, reason: `provider "${provider}" did not report token usage` };
|
|
241
|
+
}
|
|
242
|
+
// KJC-BUG-0085: cached_tokens must survive this consolidation — the
|
|
243
|
+
// budget chain (computeUsage → BudgetTracker → summary.md Cache hits →
|
|
244
|
+
// telemetry) reads it from `usage` and the audit is the most expensive
|
|
245
|
+
// role of the session.
|
|
246
|
+
const cached_tokens = Number.isFinite(result.cached_tokens) ? result.cached_tokens : 0;
|
|
247
|
+
return {
|
|
248
|
+
available: true,
|
|
249
|
+
provider,
|
|
250
|
+
model: result.model,
|
|
251
|
+
tokens_in: tokens_in ?? 0,
|
|
252
|
+
tokens_out: tokens_out ?? 0,
|
|
253
|
+
cached_tokens,
|
|
254
|
+
total_tokens: (tokens_in ?? 0) + (tokens_out ?? 0),
|
|
255
|
+
cost_usd: typeof result.cost_usd === "number" ? result.cost_usd : null,
|
|
256
|
+
durationMs,
|
|
257
|
+
};
|
|
258
|
+
}
|