@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,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration phase: deterministic output / perf guards on the diff.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
|
|
5
|
+
* the v2.7.x audit follow-up to keep the iteration-loop driver under the
|
|
6
|
+
* 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
|
|
7
|
+
* version.
|
|
8
|
+
*
|
|
9
|
+
* Returns { action: "ok" | "return", result? }.
|
|
10
|
+
* - "ok" → caller continues to the next phase.
|
|
11
|
+
* - "return" → caller returns `result` (output guard blocked on critical
|
|
12
|
+
* violations).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { emitProgress, makeEvent } from "../../../utils/events.js";
|
|
16
|
+
import { markSessionStatus, addCheckpoint } from "../../../session/store.js";
|
|
17
|
+
import { generateDiff, computeBaseRef } from "../../../review/diff-generator.js";
|
|
18
|
+
import { scanDiff } from "../../../guards/output-guard.js";
|
|
19
|
+
import { scanPerfDiff } from "../../../guards/perf-guard.js";
|
|
20
|
+
|
|
21
|
+
export async function runGuardStages({ config, logger, emitter, eventBase, session, iteration }) {
|
|
22
|
+
const outputEnabled = config.guards?.output?.enabled !== false;
|
|
23
|
+
const perfEnabled = config.guards?.perf?.enabled !== false;
|
|
24
|
+
|
|
25
|
+
if (!outputEnabled && !perfEnabled) return { action: "ok" };
|
|
26
|
+
|
|
27
|
+
const baseBranch = config.base_branch || "main";
|
|
28
|
+
let diff;
|
|
29
|
+
try {
|
|
30
|
+
const baseRef = await computeBaseRef({ baseBranch });
|
|
31
|
+
diff = await generateDiff({ baseRef, projectDir: config?.projectDir || null });
|
|
32
|
+
} catch {
|
|
33
|
+
logger.warn("Guards: could not generate diff, skipping");
|
|
34
|
+
return { action: "ok" };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!diff) return { action: "ok" };
|
|
38
|
+
|
|
39
|
+
if (outputEnabled) {
|
|
40
|
+
const outputResult = scanDiff(diff, config);
|
|
41
|
+
if (outputResult.violations.length > 0) {
|
|
42
|
+
const critical = outputResult.violations.filter(v => v.severity === "critical");
|
|
43
|
+
const warnings = outputResult.violations.filter(v => v.severity === "warning");
|
|
44
|
+
emitProgress(emitter, makeEvent("guard:output", { ...eventBase, stage: "guard" }, {
|
|
45
|
+
message: `Output guard: ${critical.length} critical, ${warnings.length} warnings`,
|
|
46
|
+
detail: { violations: outputResult.violations, executorType: "local" }
|
|
47
|
+
}));
|
|
48
|
+
logger.info(`Output guard: ${outputResult.violations.length} violation(s) found`);
|
|
49
|
+
for (const v of outputResult.violations) {
|
|
50
|
+
logger.info(` [${v.severity}] ${v.file}:${v.line} — ${v.message}`);
|
|
51
|
+
}
|
|
52
|
+
await addCheckpoint(session, { stage: "guard-output", iteration, pass: outputResult.pass, violations: outputResult.violations.length });
|
|
53
|
+
|
|
54
|
+
if (!outputResult.pass && config.guards.output.on_violation === "block") {
|
|
55
|
+
await markSessionStatus(session, "failed");
|
|
56
|
+
emitProgress(emitter, makeEvent("guard:blocked", { ...eventBase, stage: "guard" }, {
|
|
57
|
+
message: "Output guard blocked: critical violations detected",
|
|
58
|
+
detail: { violations: critical }
|
|
59
|
+
}));
|
|
60
|
+
return {
|
|
61
|
+
action: "return",
|
|
62
|
+
result: { approved: false, sessionId: session.id, reason: "guard_blocked", violations: critical }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (perfEnabled) {
|
|
69
|
+
const perfResult = scanPerfDiff(diff, config);
|
|
70
|
+
if (!perfResult.skipped && perfResult.violations.length > 0) {
|
|
71
|
+
emitProgress(emitter, makeEvent("guard:perf", { ...eventBase, stage: "guard" }, {
|
|
72
|
+
message: `Perf guard: ${perfResult.violations.length} issue(s)`,
|
|
73
|
+
detail: { violations: perfResult.violations, executorType: "local" }
|
|
74
|
+
}));
|
|
75
|
+
logger.info(`Perf guard: ${perfResult.violations.length} issue(s) found`);
|
|
76
|
+
for (const v of perfResult.violations) {
|
|
77
|
+
logger.info(` [${v.severity}] ${v.file}:${v.line} — ${v.message}`);
|
|
78
|
+
}
|
|
79
|
+
await addCheckpoint(session, { stage: "guard-perf", iteration, pass: perfResult.pass, violations: perfResult.violations.length });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { action: "ok" };
|
|
84
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration phase: post-loop wiring + session finalization when the
|
|
3
|
+
* reviewer approves.
|
|
4
|
+
*
|
|
5
|
+
* Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
|
|
6
|
+
* the v2.7.x audit follow-up to keep the iteration-loop driver under the
|
|
7
|
+
* 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
|
|
8
|
+
* version.
|
|
9
|
+
*
|
|
10
|
+
* Returns { action: "return" | "continue", result? }.
|
|
11
|
+
* - "return" → caller returns `result` (final approved session).
|
|
12
|
+
* - "continue" → caller continues the iteration loop.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { resetRetryCount } from "../../../session/mutators.js";
|
|
16
|
+
import { handlePostLoopStages, finalizeApprovedSession } from "../post-loop.js";
|
|
17
|
+
|
|
18
|
+
export async function handleApprovedReview({ config, session, emitter, eventBase, coderRole, trackBudget, i, task, stageResults, pipelineFlags, askQuestion, logger, gitCtx, budgetSummary, pgCard, pgProject, review, rtkTracker, brainCtx }) {
|
|
19
|
+
resetRetryCount(session, "reviewer");
|
|
20
|
+
const postLoopResult = await handlePostLoopStages({
|
|
21
|
+
config, session, emitter, eventBase, coderRole, trackBudget, i, task, stageResults,
|
|
22
|
+
ciEnabled: Boolean(config.ci?.enabled), testerEnabled: pipelineFlags.testerEnabled, securityEnabled: pipelineFlags.securityEnabled, askQuestion, logger, brainCtx
|
|
23
|
+
});
|
|
24
|
+
if (postLoopResult.action === "return") return { action: "return", result: postLoopResult.result };
|
|
25
|
+
if (postLoopResult.action === "continue") return { action: "continue" };
|
|
26
|
+
|
|
27
|
+
const result = await finalizeApprovedSession({ config, gitCtx, task, logger, session, stageResults, emitter, eventBase, budgetSummary, pgCard, pgProject, review, i, rtkTracker });
|
|
28
|
+
return { action: "return", result };
|
|
29
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration phase: quality gates (TDD check, SonarQube local + cloud,
|
|
3
|
+
* Impeccable design audit).
|
|
4
|
+
*
|
|
5
|
+
* Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
|
|
6
|
+
* the v2.7.x audit follow-up to keep the iteration-loop driver under the
|
|
7
|
+
* 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
|
|
8
|
+
* version.
|
|
9
|
+
*
|
|
10
|
+
* Returns { action: "ok" | "return" | "continue", result? }.
|
|
11
|
+
* - "ok" → caller continues to the next phase.
|
|
12
|
+
* - "return" → caller returns `result` (pause / stalled / blocked).
|
|
13
|
+
* - "continue" → caller continues the iteration loop (next iteration).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { generateDiff } from "../../../review/diff-generator.js";
|
|
17
|
+
import { withLock } from "../../../utils/async-lock.js";
|
|
18
|
+
import {
|
|
19
|
+
runTddCheckStage, runSonarStage, runSonarCloudStage,
|
|
20
|
+
} from "../../iteration-stages.js";
|
|
21
|
+
import { runImpeccableStage } from "../../post-loop-stages.js";
|
|
22
|
+
import { runPerfStage } from "../../stages/perf-stage.js";
|
|
23
|
+
import { runTddDisciplineStage } from "../../stages/tdd-discipline-stage.js";
|
|
24
|
+
import { runToolJudgeStage } from "../../stages/tool-judge-stage.js";
|
|
25
|
+
import { tryCiComment } from "../../ci-integration.js";
|
|
26
|
+
|
|
27
|
+
export async function runQualityGateStages({ config, logger, emitter, eventBase, session, trackBudget, i, askQuestion, repeatDetector, budgetSummary, sonarState, task, stageResults, coderRole, pipelineFlags, brainCtx }) {
|
|
28
|
+
const tddResult = await runTddCheckStage({ config, logger, emitter, eventBase, session, trackBudget, iteration: i, askQuestion, task, brainCtx });
|
|
29
|
+
if (tddResult.action === "pause") return { action: "return", result: tddResult.result };
|
|
30
|
+
if (tddResult.action === "continue") return { action: "continue" };
|
|
31
|
+
|
|
32
|
+
// KJC-TSK-0398 PR3: opt-in red-then-green check.
|
|
33
|
+
if (config.development?.require_red_then_green) {
|
|
34
|
+
const disc = await runTddDisciplineStage({
|
|
35
|
+
config, logger, emitter, eventBase,
|
|
36
|
+
sourceFiles: tddResult.sourceFiles || [],
|
|
37
|
+
testFiles: tddResult.testFiles || [],
|
|
38
|
+
});
|
|
39
|
+
if (disc.action === "continue") return { action: "continue" };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Sonar runs for code tasks per policy. Since v2.7.4 it is NOT
|
|
43
|
+
// toggleable via config — that's intrinsic to Karajan. The taskType
|
|
44
|
+
// policy (resolved_policies.sonar) is the single source of truth.
|
|
45
|
+
// Solomon may skip a single iteration via rule alerts; that's a
|
|
46
|
+
// runtime decision, not a config option.
|
|
47
|
+
//
|
|
48
|
+
// Test-harness escape hatch via config.testHarness.disableSonarStage
|
|
49
|
+
// — production code reads `config?.testHarness?.disableSonarStage`,
|
|
50
|
+
// never `globalThis.*`. The legacy override surface is documented
|
|
51
|
+
// (and exclusively read) in src/config/test-harness.js. ESLint rule
|
|
52
|
+
// (#557) blocks any re-introduction of `globalThis.__KJ_*` outside
|
|
53
|
+
// that one file.
|
|
54
|
+
const sonarStageDisabledForTest = config?.testHarness?.disableSonarStage === true;
|
|
55
|
+
if (!sonarStageDisabledForTest && session.resolved_policies?.sonar !== false) {
|
|
56
|
+
// Serialize across parallel HU lanes (KJC-TSK-0625): the SonarQube
|
|
57
|
+
// server scans one project key at a time. No-op on sequential runs.
|
|
58
|
+
const sonarResult = await withLock("sonar-scan", () => runSonarStage({
|
|
59
|
+
config, logger, emitter, eventBase, session, trackBudget, iteration: i,
|
|
60
|
+
repeatDetector, budgetSummary, sonarState, askQuestion, task, brainCtx
|
|
61
|
+
}));
|
|
62
|
+
if (sonarResult.action === "stalled" || sonarResult.action === "pause") return { action: "return", result: sonarResult.result };
|
|
63
|
+
if (sonarResult.action === "continue") return { action: "continue" };
|
|
64
|
+
if (sonarResult.stageResult) {
|
|
65
|
+
stageResults.sonar = sonarResult.stageResult;
|
|
66
|
+
await tryCiComment({ config, session, logger, agent: "Sonar", body: `SonarQube scan: ${sonarResult.stageResult.summary || "completed"}` });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (config.sonarcloud?.enabled) {
|
|
71
|
+
const cloudResult = await runSonarCloudStage({
|
|
72
|
+
config, logger, emitter, eventBase, session, trackBudget, iteration: i
|
|
73
|
+
});
|
|
74
|
+
if (cloudResult.stageResult) {
|
|
75
|
+
stageResults.sonarcloud = cloudResult.stageResult;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (pipelineFlags?.impeccableEnabled) {
|
|
80
|
+
const diff = await generateDiff({ baseRef: session.session_start_sha, projectDir: config?.projectDir || null });
|
|
81
|
+
const impeccableMode = pipelineFlags?.impeccableMode || "audit";
|
|
82
|
+
const impeccableResult = await runImpeccableStage({
|
|
83
|
+
config, logger, emitter, eventBase, session, coderRole, trackBudget,
|
|
84
|
+
iteration: i, task, diff, mode: impeccableMode
|
|
85
|
+
});
|
|
86
|
+
if (impeccableResult.stageResult) {
|
|
87
|
+
stageResults.impeccable = impeccableResult.stageResult;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (pipelineFlags?.perfEnabled) {
|
|
92
|
+
const perfResult = await runPerfStage({
|
|
93
|
+
config, logger, emitter, eventBase, session, trackBudget,
|
|
94
|
+
iteration: i, task, brainCtx
|
|
95
|
+
});
|
|
96
|
+
if (perfResult.stageResult) {
|
|
97
|
+
stageResults.perf = perfResult.stageResult;
|
|
98
|
+
}
|
|
99
|
+
if (perfResult.action === "continue") return { action: "continue" };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// KJC-TSK-0375 PR3: opt-in tool-call quality judge. Non-blocking.
|
|
103
|
+
if (pipelineFlags?.toolJudgeEnabled) {
|
|
104
|
+
const judgeResult = await runToolJudgeStage({
|
|
105
|
+
config, logger, emitter, eventBase, session, coderRole, trackBudget,
|
|
106
|
+
iteration: i, task,
|
|
107
|
+
});
|
|
108
|
+
if (judgeResult.stageResult) {
|
|
109
|
+
stageResults.toolJudge = judgeResult.stageResult;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { action: "ok" };
|
|
114
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration phase: reviewer stage with standby handling.
|
|
3
|
+
*
|
|
4
|
+
* Extracted verbatim from `src/orchestrator/drivers/iteration-loop.js` in
|
|
5
|
+
* the v2.7.x audit follow-up to keep the iteration-loop driver under the
|
|
6
|
+
* 600-LOC ceiling. Behaviour is byte-for-byte identical to the inlined
|
|
7
|
+
* version.
|
|
8
|
+
*
|
|
9
|
+
* Returns { action: "ok" | "return" | "retry", review?, result? }.
|
|
10
|
+
* - "ok" → caller proceeds with `review` (approved or with blocking
|
|
11
|
+
* issues).
|
|
12
|
+
* - "return" → caller returns `result` (pause / stalled).
|
|
13
|
+
* - "retry" → caller decrements its iteration counter and retries.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { stageRegistry } from "../../stages/stage-classes.js";
|
|
17
|
+
import { runStage } from "../../stages/stage-executor.js";
|
|
18
|
+
import { handleStandbyResult } from "../error-recovery.js";
|
|
19
|
+
|
|
20
|
+
export async function runReviewerGateStage({ pipelineFlags, reviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion, brainCtx }) {
|
|
21
|
+
// Reviewer via StageRegistry (TSK-0336). ReviewerStage.canRun returns
|
|
22
|
+
// `reviewerEnabled !== false`; when false, runStage returns null and we
|
|
23
|
+
// synthesize the "disabled-by-pipeline" stub (same shape as the previous
|
|
24
|
+
// early-return). Otherwise execute() runs runReviewerStage.
|
|
25
|
+
const reviewerCtx = {
|
|
26
|
+
reviewerRole, config, logger, emitter, eventBase, session, trackBudget,
|
|
27
|
+
iteration: i, reviewRules, task, repeatDetector, budgetSummary, askQuestion,
|
|
28
|
+
brainCtx, pipelineFlags,
|
|
29
|
+
};
|
|
30
|
+
const reviewerResult = await runStage(stageRegistry.get("reviewer"), reviewerCtx);
|
|
31
|
+
if (reviewerResult === null) {
|
|
32
|
+
return {
|
|
33
|
+
action: "ok",
|
|
34
|
+
review: { approved: true, blocking_issues: [], non_blocking_suggestions: [], summary: "Reviewer disabled by pipeline", confidence: 1 }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (reviewerResult.action === "pause") return { action: "return", result: reviewerResult.result };
|
|
38
|
+
const revStandby = await handleStandbyResult({ stageResult: reviewerResult, session, emitter, eventBase, i, stage: "reviewer", logger, config, askQuestion });
|
|
39
|
+
if (revStandby.handled) {
|
|
40
|
+
if (revStandby.action === "return") return { action: "return", result: revStandby.result };
|
|
41
|
+
if (revStandby.action === "skip") {
|
|
42
|
+
// Solomon said skip review — treat as approved
|
|
43
|
+
return { action: "ok", review: { approved: true, blocking_issues: [], non_blocking_suggestions: [], summary: "Review skipped (agent rate-limited, Solomon approved)", confidence: 0.7 } };
|
|
44
|
+
}
|
|
45
|
+
if (revStandby.action === "retry_reviewer_only") {
|
|
46
|
+
// Retry just the reviewer — use alternative agent if Solomon recommended one
|
|
47
|
+
let retryReviewerRole = reviewerRole;
|
|
48
|
+
const alt = session._alternative_agent;
|
|
49
|
+
if (alt?.stage === "reviewer" && alt?.provider) {
|
|
50
|
+
retryReviewerRole = { provider: alt.provider, model: null };
|
|
51
|
+
logger.info(`Retrying reviewer with alternative agent: ${alt.provider}`);
|
|
52
|
+
delete session._alternative_agent;
|
|
53
|
+
}
|
|
54
|
+
return runReviewerGateStage({ pipelineFlags: { reviewerEnabled: true }, reviewerRole: retryReviewerRole, config, logger, emitter, eventBase, session, trackBudget, i, reviewRules, task, repeatDetector, budgetSummary, askQuestion });
|
|
55
|
+
}
|
|
56
|
+
return { action: "retry" };
|
|
57
|
+
}
|
|
58
|
+
if (reviewerResult.stalled) return { action: "return", result: reviewerResult.stalledResult };
|
|
59
|
+
return { action: "ok", review: reviewerResult.review };
|
|
60
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-loop driver — extracted from src/orchestrator/flow-runner.js in
|
|
3
|
+
* TSK-0335 (Oleada 3 of the v2.7.4 audit refactor).
|
|
4
|
+
*
|
|
5
|
+
* Handlers for everything that happens AFTER the iteration loop decides
|
|
6
|
+
* an outcome (approved, max-iterations, or simple finalization):
|
|
7
|
+
*
|
|
8
|
+
* - handlePostLoopStages: run tester → security → final audit
|
|
9
|
+
* after the reviewer has approved; any of
|
|
10
|
+
* them can demand one more coder pass.
|
|
11
|
+
* - finalizeApprovedSession: commit/push/PR + PG card transition +
|
|
12
|
+
* full session journal + session:end event.
|
|
13
|
+
* - handleMaxIterationsReached: Brain-owned decision at the iteration
|
|
14
|
+
* cap (extend vs finalize vs escalate).
|
|
15
|
+
* Legacy path delegates to Solomon.
|
|
16
|
+
* - tryAutoStartBoard: auto-launch HU Board when config opts in.
|
|
17
|
+
* - writeHistoryRecord: non-blocking HU history write on session end.
|
|
18
|
+
*
|
|
19
|
+
* Extracted verbatim; no behavior change. flow-runner.js now imports these
|
|
20
|
+
* instead of defining them. Part of breaking up the 2254-LOC god-module —
|
|
21
|
+
* see docs/ARCHITECTURE.md and the TSK-0335 acceptance criteria.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { generateDiff } from "../../review/diff-generator.js";
|
|
25
|
+
import { finalizeGitAutomation } from "../../git/automation.js";
|
|
26
|
+
import { listCommitsBetween, listFilesChangedSince } from "../../utils/git.js";
|
|
27
|
+
import { loadPlan, projectSlug as slugFor } from "../../plan/plan-store.js";
|
|
28
|
+
import { computePlanAdherenceScore } from "../../audit/plan-adherence.js";
|
|
29
|
+
import { saveSession, markSessionStatus } from "../../session/store.js";
|
|
30
|
+
import {
|
|
31
|
+
setReviewerFeedback, setBudget, setRtkSavings, resetRetryCount,
|
|
32
|
+
} from "../../session/mutators.js";
|
|
33
|
+
import { emitProgress, makeEvent } from "../../utils/events.js";
|
|
34
|
+
import { runTesterStage, runSecurityStage, runFinalAuditStage } from "../post-loop-stages.js";
|
|
35
|
+
import { invokeSolomon } from "../solomon-escalation.js";
|
|
36
|
+
import { tryCiComment } from "../ci-integration.js";
|
|
37
|
+
import { getIntegration } from "../integrations.js";
|
|
38
|
+
|
|
39
|
+
export async function handlePostLoopStages({ config, session, emitter, eventBase, coderRole, trackBudget, i, task, stageResults, ciEnabled: _ciEnabled, testerEnabled, securityEnabled, askQuestion, logger, brainCtx }) {
|
|
40
|
+
const postLoopDiff = await generateDiff({ baseRef: session.session_start_sha });
|
|
41
|
+
|
|
42
|
+
if (testerEnabled) {
|
|
43
|
+
const testerResult = await runTesterStage({
|
|
44
|
+
config, logger, emitter, eventBase, session, coderRole, trackBudget,
|
|
45
|
+
iteration: i, task, diff: postLoopDiff, askQuestion
|
|
46
|
+
});
|
|
47
|
+
if (testerResult.action === "pause") return { action: "return", result: testerResult.result };
|
|
48
|
+
if (testerResult.action === "continue") {
|
|
49
|
+
const summary = testerResult.stageResult?.summary || "Tester found issues";
|
|
50
|
+
setReviewerFeedback(session, `Tester FAILED — fix these issues:\n${summary}`);
|
|
51
|
+
await saveSession(session);
|
|
52
|
+
if (testerResult.stageResult) stageResults.tester = testerResult.stageResult;
|
|
53
|
+
// Brain: push tester failure into feedback queue + compress for next coder iteration
|
|
54
|
+
if (brainCtx?.enabled) {
|
|
55
|
+
const { processRoleOutput } = await import("../brain-coordinator.js");
|
|
56
|
+
processRoleOutput(brainCtx, { roleName: "tester", output: testerResult.stageResult, iteration: i });
|
|
57
|
+
}
|
|
58
|
+
return { action: "continue" };
|
|
59
|
+
}
|
|
60
|
+
if (testerResult.stageResult) {
|
|
61
|
+
stageResults.tester = testerResult.stageResult;
|
|
62
|
+
await tryCiComment({ config, session, logger, agent: "Tester", body: `Tests: ${testerResult.stageResult.summary || "completed"}` });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (securityEnabled) {
|
|
67
|
+
const securityResult = await runSecurityStage({
|
|
68
|
+
config, logger, emitter, eventBase, session, coderRole, trackBudget,
|
|
69
|
+
iteration: i, task, diff: postLoopDiff, askQuestion, brainCtx
|
|
70
|
+
});
|
|
71
|
+
if (securityResult.action === "pause") return { action: "return", result: securityResult.result };
|
|
72
|
+
if (securityResult.action === "continue") {
|
|
73
|
+
const summary = securityResult.stageResult?.summary || "Security found issues";
|
|
74
|
+
setReviewerFeedback(session, `Security FAILED — fix these issues:\n${summary}`);
|
|
75
|
+
await saveSession(session);
|
|
76
|
+
if (securityResult.stageResult) stageResults.security = securityResult.stageResult;
|
|
77
|
+
// Brain: push security findings into feedback queue + compress for next coder iteration
|
|
78
|
+
if (brainCtx?.enabled) {
|
|
79
|
+
const { processRoleOutput } = await import("../brain-coordinator.js");
|
|
80
|
+
processRoleOutput(brainCtx, { roleName: "security", output: securityResult.stageResult, iteration: i });
|
|
81
|
+
}
|
|
82
|
+
return { action: "continue" };
|
|
83
|
+
}
|
|
84
|
+
if (securityResult.stageResult) {
|
|
85
|
+
stageResults.security = securityResult.stageResult;
|
|
86
|
+
await tryCiComment({ config, session, logger, agent: "Security", body: `Security scan: ${securityResult.stageResult.summary || "completed"}` });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Final audit — last quality gate before declaring success
|
|
91
|
+
const auditResult = await runFinalAuditStage({
|
|
92
|
+
config, logger, emitter, eventBase, session, coderRole, trackBudget,
|
|
93
|
+
iteration: i, task, diff: postLoopDiff
|
|
94
|
+
});
|
|
95
|
+
if (auditResult.stageResult) {
|
|
96
|
+
stageResults.audit = auditResult.stageResult;
|
|
97
|
+
await tryCiComment({ config, session, logger, agent: "Audit", body: `Final audit: ${auditResult.stageResult.summary || "completed"}` });
|
|
98
|
+
}
|
|
99
|
+
if (auditResult.action === "retry") {
|
|
100
|
+
// Audit found actionable issues — loop back to coder
|
|
101
|
+
setReviewerFeedback(session, auditResult.feedback);
|
|
102
|
+
await saveSession(session);
|
|
103
|
+
return { action: "continue" };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { action: "proceed" };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function finalizeApprovedSession({ config, gitCtx, task, logger, session, stageResults, emitter, eventBase, budgetSummary, pgCard, pgProject, review, i, rtkTracker }) {
|
|
110
|
+
const gitResult = await finalizeGitAutomation({ config, gitCtx, task, logger, session, stageResults });
|
|
111
|
+
|
|
112
|
+
// Accumulate final commits for PG card lifecycle tracking
|
|
113
|
+
if (gitResult?.commits?.length) {
|
|
114
|
+
const tracker = getIntegration("tracker");
|
|
115
|
+
for (const c of gitResult.commits) tracker?.onCommit?.(session, c);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (stageResults.planner?.ok) {
|
|
119
|
+
stageResults.planner.completedSteps = [...(stageResults.planner.steps ?? [])];
|
|
120
|
+
}
|
|
121
|
+
setBudget(session, budgetSummary());
|
|
122
|
+
await markSessionStatus(session, "approved");
|
|
123
|
+
|
|
124
|
+
await getIntegration("tracker")?.onSessionApproved?.({ pgCard, pgProject, config, session, gitResult, logger });
|
|
125
|
+
|
|
126
|
+
const deferredIssues = session.deferred_issues || [];
|
|
127
|
+
const rtkSavings = rtkTracker?.hasData() ? rtkTracker.summary() : undefined;
|
|
128
|
+
if (rtkSavings) setRtkSavings(session, rtkSavings);
|
|
129
|
+
await saveSession(session);
|
|
130
|
+
|
|
131
|
+
// --- Journal: write final files (shared writer, KJC-BUG-0084) ---
|
|
132
|
+
const journalDir = session._journalDir;
|
|
133
|
+
if (journalDir) {
|
|
134
|
+
// 2026-05-07 dogfooding: gitResult.commits only carries the post-loop
|
|
135
|
+
// commit (scaffold). Compute the full range from session_start_sha so
|
|
136
|
+
// every commit the run produced shows up in execution order.
|
|
137
|
+
let allCommits;
|
|
138
|
+
try { allCommits = (await listCommitsBetween(session.head_at_start || session.session_start_sha)) || []; }
|
|
139
|
+
catch { allCommits = gitResult?.commits || []; }
|
|
140
|
+
const summaryCommits = allCommits.length > 0 ? allCommits : (gitResult?.commits || []);
|
|
141
|
+
|
|
142
|
+
// KJC-TSK-0376 — plan adherence metric (deepeval-inspired). When the
|
|
143
|
+
// run executed against a known plan (`kj run --plan <id>`), score how
|
|
144
|
+
// faithfully the coder followed it. Pure offline; safe-by-default
|
|
145
|
+
// (try/catch swallows missing helper or unreadable plan).
|
|
146
|
+
let planAdherence = null;
|
|
147
|
+
try {
|
|
148
|
+
const planId = session._planRef?.planId
|
|
149
|
+
|| stageResults?.huReviewer?.planId
|
|
150
|
+
|| null;
|
|
151
|
+
if (planId) {
|
|
152
|
+
const projectDir = config?.projectDir
|
|
153
|
+
|| session.config_snapshot?.projectDir
|
|
154
|
+
|| process.cwd();
|
|
155
|
+
const plan = await loadPlan(projectDir, planId).catch(() => null);
|
|
156
|
+
if (plan && Array.isArray(plan.hus) && plan.hus.length > 0) {
|
|
157
|
+
const filesChanged = await listFilesChangedSince(
|
|
158
|
+
session.head_at_start || session.session_start_sha,
|
|
159
|
+
).catch(() => []);
|
|
160
|
+
planAdherence = computePlanAdherenceScore({
|
|
161
|
+
commits: summaryCommits,
|
|
162
|
+
plan,
|
|
163
|
+
filesChanged,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
logger?.warn?.(`Plan adherence calculation skipped: ${err.message}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const { writeSessionJournal } = await import("../../session/journal/write-all.js");
|
|
172
|
+
await writeSessionJournal({
|
|
173
|
+
session, logger,
|
|
174
|
+
result: "APPROVED",
|
|
175
|
+
iterations: i,
|
|
176
|
+
budget: budgetSummary(),
|
|
177
|
+
stages: stageResults,
|
|
178
|
+
commits: summaryCommits,
|
|
179
|
+
planAdherence,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Mirror the same enriched commit list into the session:end event so the
|
|
184
|
+
// terminal `🏁 Result` banner (printSessionGit) shows every commit the
|
|
185
|
+
// run produced, not just the post-loop scaffold one. We compute again
|
|
186
|
+
// (cheap: one git log call) rather than threading a variable through
|
|
187
|
+
// because the journal block is wrapped in try/catch and may have set
|
|
188
|
+
// `summaryCommits` to a fallback we don't want for the event detail.
|
|
189
|
+
// try/catch tolerates both promise rejection and sync undefined returns
|
|
190
|
+
// (see the journal block above for the detailed rationale).
|
|
191
|
+
let eventCommits = null;
|
|
192
|
+
try { eventCommits = await listCommitsBetween(session.head_at_start || session.session_start_sha); }
|
|
193
|
+
catch { /* leave null — we'll use gitResult unchanged */ }
|
|
194
|
+
const gitForEvent = (Array.isArray(eventCommits) && eventCommits.length > 0)
|
|
195
|
+
? { ...gitResult, commits: eventCommits }
|
|
196
|
+
: gitResult;
|
|
197
|
+
const endDetail = { approved: true, iterations: i, stages: stageResults, git: gitForEvent, budget: budgetSummary(), deferredIssues };
|
|
198
|
+
if (rtkSavings) endDetail.rtk_savings = rtkSavings;
|
|
199
|
+
emitProgress(
|
|
200
|
+
emitter,
|
|
201
|
+
makeEvent("session:end", { ...eventBase, stage: "done" }, {
|
|
202
|
+
message: deferredIssues.length > 0
|
|
203
|
+
? `Session approved (${deferredIssues.length} deferred issue(s) tracked as tech debt)`
|
|
204
|
+
: "Session approved",
|
|
205
|
+
detail: endDetail
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
const result = { approved: true, sessionId: session.id, review, git: gitResult, deferredIssues };
|
|
209
|
+
if (rtkSavings) result.rtk_savings = rtkSavings;
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export async function handleMaxIterationsReached({ session, budgetSummary, emitter, eventBase, config, stageResults, logger, askQuestion, task, rtkTracker, brainCtx }) {
|
|
214
|
+
const budget = budgetSummary();
|
|
215
|
+
|
|
216
|
+
// Brain-owned decision: max_iterations is guidance, not a hard rule.
|
|
217
|
+
// Brain evaluates the feedback queue state to decide extend / finalize / escalate.
|
|
218
|
+
// Solomon is only consulted if Brain cannot decide on its own.
|
|
219
|
+
if (brainCtx?.enabled) {
|
|
220
|
+
const entries = brainCtx.feedbackQueue?.entries || [];
|
|
221
|
+
const pending = entries.map(e => ({ source: e.source, category: e.category, severity: e.severity, description: e.description }));
|
|
222
|
+
const hasSecurity = entries.some(e => e.category === "security" || e.source === "security");
|
|
223
|
+
const hasCorrectness = entries.some(e => ["correctness", "tests"].includes(e.category));
|
|
224
|
+
|
|
225
|
+
if (hasSecurity) {
|
|
226
|
+
// Brain: security issues unresolved → cannot finalize, escalate
|
|
227
|
+
logger.warn(`Brain: max_iterations reached with ${entries.filter(e => e.category === "security" || e.source === "security").length} unresolved security issue(s) — cannot finalize`);
|
|
228
|
+
return { paused: true, sessionId: session.id, question: "Brain: unresolved security issues at max_iterations. Review manually or extend pipeline.", context: "brain_security_block", pending };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (hasCorrectness) {
|
|
232
|
+
// Brain: correctness/test issues pending. Cap at MAX_EXTENSIONS to avoid infinite extensions.
|
|
233
|
+
const MAX_EXTENSIONS = 2;
|
|
234
|
+
if (brainCtx.extensionCount >= MAX_EXTENSIONS) {
|
|
235
|
+
logger.warn(`Brain: ${brainCtx.extensionCount} extensions exhausted with correctness issues still pending — escalating to human`);
|
|
236
|
+
return { paused: true, sessionId: session.id, question: `Brain exhausted ${MAX_EXTENSIONS} extensions with correctness/tests still pending. Manual intervention needed.`, context: "brain_extension_cap", pending };
|
|
237
|
+
}
|
|
238
|
+
brainCtx.extensionCount += 1;
|
|
239
|
+
logger.info(`Brain: max_iterations reached with ${entries.filter(e => ["correctness", "tests"].includes(e.category)).length} correctness issue(s) pending — extending iterations (extension ${brainCtx.extensionCount}/${MAX_EXTENSIONS})`);
|
|
240
|
+
resetRetryCount(session, "reviewer");
|
|
241
|
+
await saveSession(session);
|
|
242
|
+
return { approved: false, sessionId: session.id, reason: "max_iterations_extended", extraIterations: Math.ceil(config.max_iterations / 2) };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (entries.length === 0) {
|
|
246
|
+
// Brain: no pending feedback → last reviewer approved, finalize
|
|
247
|
+
logger.info("Brain: max_iterations reached with clean feedback queue — finalizing as approved");
|
|
248
|
+
return { approved: true, sessionId: session.id, reason: "brain_approved" };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// hasStyleOnly: genuine dilemma → Brain consults Solomon
|
|
252
|
+
logger.info(`Brain: max_iterations with ${entries.length} style-only issue(s) — consulting Solomon on dilemma`);
|
|
253
|
+
const solomonResult = await invokeSolomon({
|
|
254
|
+
config, logger, emitter, eventBase, stage: "max_iterations", askQuestion, session,
|
|
255
|
+
iteration: config.max_iterations,
|
|
256
|
+
conflict: {
|
|
257
|
+
stage: "brain-max-iterations",
|
|
258
|
+
task,
|
|
259
|
+
iterationCount: config.max_iterations,
|
|
260
|
+
maxIterations: config.max_iterations,
|
|
261
|
+
budget_usd: budget?.total_cost_usd || 0,
|
|
262
|
+
dilemma: `Max iterations reached with ${entries.length} style-only issue(s) pending. Accept as-is or request more work?`,
|
|
263
|
+
pendingIssues: pending,
|
|
264
|
+
history: [{ agent: "pipeline", feedback: session.last_reviewer_feedback || "Max iterations reached" }]
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
// Brain applies Solomon's decision
|
|
268
|
+
if (solomonResult.action === "approve") {
|
|
269
|
+
logger.info("Brain: Solomon advised approve for style-only pending — finalizing");
|
|
270
|
+
return { approved: true, sessionId: session.id, reason: "brain_solomon_approved" };
|
|
271
|
+
}
|
|
272
|
+
if (solomonResult.action === "continue") {
|
|
273
|
+
return { approved: false, sessionId: session.id, reason: "max_iterations_extended", extraIterations: solomonResult.extraIterations || Math.ceil(config.max_iterations / 2) };
|
|
274
|
+
}
|
|
275
|
+
if (solomonResult.action === "pause") {
|
|
276
|
+
return { paused: true, sessionId: session.id, question: solomonResult.question, context: "brain_solomon_dilemma" };
|
|
277
|
+
}
|
|
278
|
+
// Fallback: escalate to human
|
|
279
|
+
return { paused: true, sessionId: session.id, question: `Brain+Solomon cannot resolve: ${entries.length} pending issue(s) at max_iterations`, context: "max_iterations" };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Legacy path (Brain disabled): original Solomon-driven flow
|
|
283
|
+
const solomonResult = await invokeSolomon({
|
|
284
|
+
config, logger, emitter, eventBase, stage: "max_iterations", askQuestion, session,
|
|
285
|
+
iteration: config.max_iterations,
|
|
286
|
+
conflict: {
|
|
287
|
+
stage: "max_iterations",
|
|
288
|
+
task,
|
|
289
|
+
iterationCount: config.max_iterations,
|
|
290
|
+
maxIterations: config.max_iterations,
|
|
291
|
+
budget_usd: budget?.total_cost_usd || 0,
|
|
292
|
+
history: [{ agent: "pipeline", feedback: session.last_reviewer_feedback || "Max iterations reached without reviewer approval" }]
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if (solomonResult.action === "approve") {
|
|
297
|
+
logger.info("Solomon approved coder's work at max_iterations checkpoint");
|
|
298
|
+
return { approved: true, sessionId: session.id, reason: "solomon_approved" };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (solomonResult.action === "continue") {
|
|
302
|
+
if (solomonResult.humanGuidance) {
|
|
303
|
+
setReviewerFeedback(session, `Solomon guidance: ${solomonResult.humanGuidance}`);
|
|
304
|
+
}
|
|
305
|
+
resetRetryCount(session, "reviewer");
|
|
306
|
+
await saveSession(session);
|
|
307
|
+
const extraIterations = solomonResult.extraIterations || config.max_iterations;
|
|
308
|
+
return { approved: false, sessionId: session.id, reason: "max_iterations_extended", humanGuidance: solomonResult.humanGuidance, extraIterations };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (solomonResult.action === "pause") {
|
|
312
|
+
return { paused: true, sessionId: session.id, question: solomonResult.question, context: "max_iterations" };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (solomonResult.action === "subtask") {
|
|
316
|
+
return { paused: true, sessionId: session.id, subtask: solomonResult.subtask, context: "max_iterations_subtask" };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Solomon couldn't resolve — fail
|
|
320
|
+
setBudget(session, budgetSummary());
|
|
321
|
+
const rtkSavings = rtkTracker?.hasData() ? rtkTracker.summary() : undefined;
|
|
322
|
+
if (rtkSavings) setRtkSavings(session, rtkSavings);
|
|
323
|
+
await markSessionStatus(session, "failed");
|
|
324
|
+
const failDetail = { approved: false, reason: "max_iterations", iterations: config.max_iterations, stages: stageResults, budget: budgetSummary() };
|
|
325
|
+
if (rtkSavings) failDetail.rtk_savings = rtkSavings;
|
|
326
|
+
emitProgress(
|
|
327
|
+
emitter,
|
|
328
|
+
makeEvent("session:end", { ...eventBase, stage: "done" }, {
|
|
329
|
+
status: "fail",
|
|
330
|
+
message: "Max iterations reached (Solomon could not resolve)",
|
|
331
|
+
detail: failDetail
|
|
332
|
+
})
|
|
333
|
+
);
|
|
334
|
+
return { approved: false, sessionId: session.id, reason: "max_iterations" };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function tryAutoStartBoard(config, logger, emitter, eventBase) {
|
|
338
|
+
// TSK-0273: gate on hu_board.auto_start alone. The previous double-gate
|
|
339
|
+
// (enabled && auto_start) was confusing because `enabled` was never the
|
|
340
|
+
// user-facing switch — only auto_start was. This matches the AC: "kj run
|
|
341
|
+
// auto-inicia el board server si hu_board.auto_start es true".
|
|
342
|
+
if (!config.hu_board?.auto_start) return;
|
|
343
|
+
// Never auto-start during vitest: races the PID file and starts a detached
|
|
344
|
+
// process that outlives the test run.
|
|
345
|
+
if (process.env.VITEST || process.env.NODE_ENV === "test") return;
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
const { startBoard, renderBoardBanner } = await import("../../commands/board.js");
|
|
349
|
+
const boardPort = config.hu_board.port || 4000;
|
|
350
|
+
// Scope the board URL to the current run's project (`#board/<slug>`)
|
|
351
|
+
// so the user lands on a filtered view, not the global dashboard.
|
|
352
|
+
const slug = config.projectDir ? slugFor(config.projectDir) : null;
|
|
353
|
+
const boardResult = await startBoard(boardPort, { projectSlug: slug });
|
|
354
|
+
const status = boardResult.alreadyRunning ? "already running" : "started";
|
|
355
|
+
// Highlighted URL box — visible regardless of log level (matches the
|
|
356
|
+
// post-planner auto-HU banner so the user gets the same signal either
|
|
357
|
+
// way the board got started).
|
|
358
|
+
console.log(renderBoardBanner({ url: boardResult.url, status }));
|
|
359
|
+
logger.info(`HU Board ${status} at ${boardResult.url}`);
|
|
360
|
+
emitProgress(emitter, makeEvent("board:started", eventBase, {
|
|
361
|
+
message: `HU Board running at ${boardResult.url}`,
|
|
362
|
+
detail: { pid: boardResult.pid, port: boardPort, url: boardResult.url }
|
|
363
|
+
}));
|
|
364
|
+
} catch (err) {
|
|
365
|
+
logger.warn(`HU Board auto-start failed (non-blocking): ${err.message}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export async function writeHistoryRecord({ sessionId, task, result, logger }) {
|
|
370
|
+
try {
|
|
371
|
+
const { createHistoryRecord } = await import("../../hu/store.js");
|
|
372
|
+
const approved = Boolean(result?.approved);
|
|
373
|
+
const summary = result?.review?.summary || result?.reason || null;
|
|
374
|
+
await createHistoryRecord(sessionId, {
|
|
375
|
+
task,
|
|
376
|
+
result: JSON.stringify(result),
|
|
377
|
+
approved,
|
|
378
|
+
summary
|
|
379
|
+
});
|
|
380
|
+
} catch (err) {
|
|
381
|
+
logger.warn(`HU history record failed (non-blocking): ${err.message}`);
|
|
382
|
+
}
|
|
383
|
+
}
|