@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,305 @@
|
|
|
1
|
+
import { SolomonRole } from "../roles/solomon-role.js";
|
|
2
|
+
import { addCheckpoint, pauseSession, saveSession } from "../session/store.js";
|
|
3
|
+
import { setSuggestions } from "../session/mutators.js";
|
|
4
|
+
import { emitProgress, makeEvent } from "../utils/events.js";
|
|
5
|
+
import { msg, getLang } from "../utils/messages.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import("../types/solomon.js").Conflict} Conflict
|
|
9
|
+
* @typedef {import("../types/solomon.js").SolomonResult} SolomonResult
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Architectural invariant (DO NOT BREAK):
|
|
14
|
+
* `invokeSolomon` MUST NOT be called directly from stages, rules or agent
|
|
15
|
+
* code. The only callers should be:
|
|
16
|
+
* - Karajan Brain (via `src/brain/solomon-consult.js`)
|
|
17
|
+
* - The orchestrator's escalation path (`src/orchestrator/flow-runner.js`)
|
|
18
|
+
* on behalf of Brain.
|
|
19
|
+
* The v2.3.0 audit fixed 21 violations of this rule. Keeping Solomon behind
|
|
20
|
+
* Brain is what the "Brain-as-gateway, Solomon-as-judge" architecture
|
|
21
|
+
* depends on — see docs/ARCHITECTURE.md §Brain/Solomon.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build a human-readable escalation message from raw Solomon conflict data.
|
|
26
|
+
* Replaces the raw JSON dump with structured, plain-text output.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} solomonResult - The conflict object passed to escalateToHuman
|
|
29
|
+
* @param {object} [session] - Current session (optional, used for extra context)
|
|
30
|
+
* @returns {string} Formatted message suitable for display to the user
|
|
31
|
+
*/
|
|
32
|
+
export function formatEscalationMessage(solomonResult, session) {
|
|
33
|
+
const stage = solomonResult?.stage || "unknown";
|
|
34
|
+
const solomonReason = solomonResult?.solomonReason || null;
|
|
35
|
+
const history = solomonResult?.history || [];
|
|
36
|
+
const lang = getLang(session?.config_snapshot);
|
|
37
|
+
|
|
38
|
+
const lines = [];
|
|
39
|
+
lines.push(msg("solomon_conflict", lang, { stage }));
|
|
40
|
+
lines.push("");
|
|
41
|
+
|
|
42
|
+
// Extract reviewer/agent feedback from history
|
|
43
|
+
const feedbackEntries = history.filter(entry => entry && typeof entry === "object");
|
|
44
|
+
if (feedbackEntries.length > 0) {
|
|
45
|
+
lines.push(msg("solomon_feedback", lang));
|
|
46
|
+
for (const entry of feedbackEntries) {
|
|
47
|
+
const agent = entry.agent || "unknown";
|
|
48
|
+
const feedback = entry.feedback || "No feedback provided";
|
|
49
|
+
// Split multi-line feedback (e.g. "R-1: ...\nR-2: ...") into bullet points
|
|
50
|
+
const feedbackLines = String(feedback).split("\n").filter(l => l.trim());
|
|
51
|
+
if (feedbackLines.length === 1) {
|
|
52
|
+
lines.push(` [${agent}] ${feedbackLines[0]}`);
|
|
53
|
+
} else {
|
|
54
|
+
lines.push(` [${agent}]`);
|
|
55
|
+
for (const fl of feedbackLines) {
|
|
56
|
+
lines.push(` - ${fl}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
lines.push("");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Solomon's reason (if it tried and failed)
|
|
64
|
+
if (solomonReason) {
|
|
65
|
+
lines.push(`${msg("solomon_reason", lang)} ${solomonReason}`);
|
|
66
|
+
lines.push("");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Iteration context
|
|
70
|
+
const iterationCount = solomonResult?.iterationCount;
|
|
71
|
+
const maxIterations = solomonResult?.maxIterations;
|
|
72
|
+
if (iterationCount !== undefined && maxIterations !== undefined) {
|
|
73
|
+
lines.push(msg("pipeline_iteration", lang, { current: iterationCount, max: maxIterations }));
|
|
74
|
+
lines.push("");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
lines.push(msg("solomon_options", lang));
|
|
78
|
+
lines.push("");
|
|
79
|
+
lines.push(msg("solomon_proceed", lang));
|
|
80
|
+
|
|
81
|
+
return lines.join("\n");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Extract Solomon's previous rulings from session checkpoints.
|
|
86
|
+
* Gives Solomon memory of its own decisions to avoid repeating failed strategies.
|
|
87
|
+
*/
|
|
88
|
+
function extractSolomonHistory(session) {
|
|
89
|
+
const checkpoints = session?.checkpoints || [];
|
|
90
|
+
return checkpoints
|
|
91
|
+
.filter(cp => cp.stage === "solomon")
|
|
92
|
+
.map(cp => ({
|
|
93
|
+
conflictStage: cp.conflictStage,
|
|
94
|
+
ruling: cp.ruling,
|
|
95
|
+
alternativeAgent: cp.alternativeAgent,
|
|
96
|
+
waitUntil: cp.waitUntil,
|
|
97
|
+
conditions: cp.conditions,
|
|
98
|
+
error: cp.error || null
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Consult Solomon (or fall back to human escalation) for a given conflict.
|
|
104
|
+
* See the Conflict typedef for the shape of the `conflict` argument and
|
|
105
|
+
* the invariant above for who is allowed to call this.
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} params
|
|
108
|
+
* @param {Object} params.config
|
|
109
|
+
* @param {Object} params.logger
|
|
110
|
+
* @param {Object} [params.emitter]
|
|
111
|
+
* @param {Object} [params.eventBase]
|
|
112
|
+
* @param {string} params.stage
|
|
113
|
+
* @param {Conflict} params.conflict
|
|
114
|
+
* @param {Function} [params.askQuestion]
|
|
115
|
+
* @param {Object} [params.session]
|
|
116
|
+
* @param {number} [params.iteration]
|
|
117
|
+
* @returns {Promise<SolomonResult>}
|
|
118
|
+
*/
|
|
119
|
+
export async function invokeSolomon({ config, logger, emitter, eventBase, stage, conflict, askQuestion, session, iteration }) {
|
|
120
|
+
const solomonEnabled = Boolean(config.pipeline?.solomon?.enabled);
|
|
121
|
+
|
|
122
|
+
if (!solomonEnabled) {
|
|
123
|
+
return escalateToHuman({ askQuestion, session, emitter, eventBase, stage, conflict, iteration });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// KJC-BUG-0113: the fallback used to be "gemini" — Google retired the
|
|
127
|
+
// Gemini Code Assist CLI for individuals (IneligibleTierError), so an
|
|
128
|
+
// unconfigured Solomon died on every escalation. Claude matches the
|
|
129
|
+
// brain.provider default.
|
|
130
|
+
const solomonProvider = config?.roles?.solomon?.provider || "claude";
|
|
131
|
+
emitProgress(
|
|
132
|
+
emitter,
|
|
133
|
+
makeEvent("solomon:start", { ...eventBase, stage: "solomon" }, {
|
|
134
|
+
message: `Solomon arbitrating ${stage} conflict`,
|
|
135
|
+
detail: { conflictStage: stage, provider: solomonProvider, executorType: "agent" }
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// Collect pending suggestions from the session for Solomon's context
|
|
140
|
+
const pendingSuggestions = Array.isArray(session.suggestions) && session.suggestions.length > 0
|
|
141
|
+
? session.suggestions.slice()
|
|
142
|
+
: null;
|
|
143
|
+
|
|
144
|
+
const solomon = new SolomonRole({ config, logger, emitter });
|
|
145
|
+
await solomon.init({ task: conflict.task, iteration });
|
|
146
|
+
let ruling;
|
|
147
|
+
try {
|
|
148
|
+
// Inject Solomon's own history so it doesn't repeat failed strategies
|
|
149
|
+
const solomonHistory = extractSolomonHistory(session);
|
|
150
|
+
const enrichedConflict = {
|
|
151
|
+
...conflict,
|
|
152
|
+
...(pendingSuggestions && { hostSuggestions: pendingSuggestions }),
|
|
153
|
+
...(solomonHistory.length > 0 && { previousSolomonRulings: solomonHistory })
|
|
154
|
+
};
|
|
155
|
+
ruling = await solomon.run({ conflict: enrichedConflict });
|
|
156
|
+
} catch (err) {
|
|
157
|
+
logger.warn(`Solomon threw: ${err.message}`);
|
|
158
|
+
return escalateToHuman({
|
|
159
|
+
askQuestion, session, emitter, eventBase, stage, iteration,
|
|
160
|
+
conflict: { ...conflict, solomonReason: `Solomon error: ${err.message}` }
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Clear processed suggestions from session
|
|
165
|
+
if (pendingSuggestions) {
|
|
166
|
+
setSuggestions(session, []);
|
|
167
|
+
try { await saveSession(session); } catch { /* best-effort */ }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const solomonError = ruling.result?.error;
|
|
171
|
+
if (!ruling.ok && solomonError) {
|
|
172
|
+
logger.warn(`Solomon execution failed: ${solomonError}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
emitProgress(
|
|
176
|
+
emitter,
|
|
177
|
+
makeEvent("solomon:end", { ...eventBase, stage: "solomon" }, {
|
|
178
|
+
message: ruling.ok
|
|
179
|
+
? `Solomon ruling: ${ruling.result?.ruling || "unknown"}`
|
|
180
|
+
: `Solomon failed: ${(solomonError || ruling.summary || "unknown error").slice(0, 200)}`,
|
|
181
|
+
detail: { ...ruling.result, provider: solomonProvider, executorType: "agent" }
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
await addCheckpoint(session, {
|
|
186
|
+
stage: "solomon",
|
|
187
|
+
iteration,
|
|
188
|
+
conflictStage: conflict?.stage || stage,
|
|
189
|
+
ruling: ruling.result?.ruling,
|
|
190
|
+
alternativeAgent: ruling.result?.alternativeAgent || null,
|
|
191
|
+
waitUntil: ruling.result?.waitUntil || null,
|
|
192
|
+
conditions: ruling.result?.conditions || [],
|
|
193
|
+
escalate: ruling.result?.escalate,
|
|
194
|
+
error: solomonError ? solomonError.slice(0, 500) : undefined,
|
|
195
|
+
subtask: ruling.result?.subtask?.title || null
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Record the ruling for the session journal (decisions.md). Lazy-import so
|
|
199
|
+
// this module stays free of journal-specific deps for callers that don't
|
|
200
|
+
// need them.
|
|
201
|
+
try {
|
|
202
|
+
const { recordSolomonRuling } = await import("../session/journal/decisions-writer.js");
|
|
203
|
+
recordSolomonRuling(session, {
|
|
204
|
+
stage: conflict?.stage || stage,
|
|
205
|
+
trigger: conflict?.reason || conflict?.summary || "solomon invoked",
|
|
206
|
+
conflict: {
|
|
207
|
+
task: conflict?.task,
|
|
208
|
+
reason: conflict?.reason,
|
|
209
|
+
summary: conflict?.summary,
|
|
210
|
+
iterationCount: conflict?.iterationCount,
|
|
211
|
+
},
|
|
212
|
+
ruling: ruling.result?.ruling || (ruling.ok ? "continue" : "escalate_human"),
|
|
213
|
+
reasoning: ruling.result?.reasoning || ruling.summary || "",
|
|
214
|
+
conditions: ruling.result?.conditions || [],
|
|
215
|
+
alternativeAgent: ruling.result?.alternativeAgent || null,
|
|
216
|
+
});
|
|
217
|
+
} catch { /* best-effort, don't break the pipeline on a journal hiccup */ }
|
|
218
|
+
|
|
219
|
+
if (!ruling.ok) {
|
|
220
|
+
const reason = ruling.result?.escalate_reason || solomonError || ruling.summary;
|
|
221
|
+
return escalateToHuman({
|
|
222
|
+
askQuestion, session, emitter, eventBase, stage, iteration,
|
|
223
|
+
conflict: { ...conflict, solomonReason: reason }
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const r = ruling.result?.ruling;
|
|
228
|
+
if (r === "approve") {
|
|
229
|
+
return { action: "approve", conditions: [], ruling };
|
|
230
|
+
}
|
|
231
|
+
if (r === "approve_with_conditions") {
|
|
232
|
+
return {
|
|
233
|
+
action: "continue",
|
|
234
|
+
conditions: ruling.result?.conditions || [],
|
|
235
|
+
extraIterations: ruling.result?.extraIterations || null,
|
|
236
|
+
alternativeAgent: ruling.result?.alternativeAgent || null,
|
|
237
|
+
waitUntil: ruling.result?.waitUntil || null,
|
|
238
|
+
ruling
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (r === "escalate_human") {
|
|
243
|
+
return escalateToHuman({
|
|
244
|
+
askQuestion, session, emitter, eventBase, stage, iteration,
|
|
245
|
+
conflict: { ...conflict, solomonReason: ruling.result?.escalate_reason || "Solomon escalated to human" }
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (r === "create_subtask") {
|
|
250
|
+
return { action: "subtask", subtask: ruling.result?.subtask, ruling };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return { action: "continue", conditions: [], ruling };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function parseEscalationAnswer(answer) {
|
|
257
|
+
if (!answer) return null;
|
|
258
|
+
const trimmed = answer.trim().toLowerCase();
|
|
259
|
+
// Option 1: Accept coder's work as-is
|
|
260
|
+
if (trimmed === "1" || trimmed === "accept" || trimmed === "yes" || trimmed === "sí" || trimmed === "si") {
|
|
261
|
+
return { action: "continue", humanGuidance: "Accept coder's work as-is" };
|
|
262
|
+
}
|
|
263
|
+
// Option 2: Retry with reviewer's feedback
|
|
264
|
+
if (trimmed === "2" || trimmed === "retry") {
|
|
265
|
+
return { action: "continue", humanGuidance: "Retry with reviewer feedback" };
|
|
266
|
+
}
|
|
267
|
+
// Option 3: Stop the session
|
|
268
|
+
if (trimmed === "3" || trimmed.startsWith("stop") || trimmed.startsWith("pause")) {
|
|
269
|
+
return { action: "stop" };
|
|
270
|
+
}
|
|
271
|
+
// Free-text: treat as human guidance (backward compat)
|
|
272
|
+
return { action: "continue", humanGuidance: answer.trim() };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export async function escalateToHuman({ askQuestion, session, emitter, eventBase, stage, conflict, iteration }) {
|
|
276
|
+
const question = formatEscalationMessage({ ...conflict, stage }, session);
|
|
277
|
+
|
|
278
|
+
if (askQuestion) {
|
|
279
|
+
const answer = await askQuestion(question, { iteration, stage });
|
|
280
|
+
const parsed = parseEscalationAnswer(answer);
|
|
281
|
+
if (parsed && parsed.action === "continue") {
|
|
282
|
+
return { action: "continue", humanGuidance: parsed.humanGuidance };
|
|
283
|
+
}
|
|
284
|
+
if (parsed && parsed.action === "stop") {
|
|
285
|
+
// Fall through to pause session
|
|
286
|
+
} else if (answer) {
|
|
287
|
+
return { action: "continue", humanGuidance: answer };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
await pauseSession(session, {
|
|
292
|
+
question,
|
|
293
|
+
context: { iteration, stage, conflict }
|
|
294
|
+
});
|
|
295
|
+
emitProgress(
|
|
296
|
+
emitter,
|
|
297
|
+
makeEvent("question", { ...eventBase, stage }, {
|
|
298
|
+
status: "paused",
|
|
299
|
+
message: question,
|
|
300
|
+
detail: { question, sessionId: session.id }
|
|
301
|
+
})
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
return { action: "pause", question };
|
|
305
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solomon rules engine — detects anomalies during session execution.
|
|
3
|
+
* Each rule returns { triggered: boolean, severity: "warn"|"critical", message, detail }
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const DEFAULT_RULES = {
|
|
7
|
+
max_stale_iterations: 3,
|
|
8
|
+
no_new_dependencies_without_task: true,
|
|
9
|
+
scope_guard: true,
|
|
10
|
+
reviewer_overreach: true,
|
|
11
|
+
reviewer_style_block: true
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function evaluateRules(context, rulesConfig = {}) {
|
|
15
|
+
const rules = { ...DEFAULT_RULES, ...rulesConfig };
|
|
16
|
+
const alerts = [];
|
|
17
|
+
|
|
18
|
+
// Rule 1: Stale iterations (no progress)
|
|
19
|
+
if (rules.max_stale_iterations && context.staleIterations >= rules.max_stale_iterations) {
|
|
20
|
+
alerts.push({
|
|
21
|
+
rule: "max_stale_iterations",
|
|
22
|
+
severity: "critical",
|
|
23
|
+
message: `${context.staleIterations} iterations without progress. Same errors repeating.`,
|
|
24
|
+
detail: { staleIterations: context.staleIterations, limit: rules.max_stale_iterations }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Rule 3: New dependencies not in task (only flag suspicious runtime deps, not dev/test tooling)
|
|
29
|
+
if (rules.no_new_dependencies_without_task && context.newDependencies?.length > 0) {
|
|
30
|
+
const testTooling = /vitest|jest|mocha|coverage|eslint|prettier|typescript|@types\//i;
|
|
31
|
+
const buildTooling = /webpack|vite|rollup|esbuild|tsup|unbuild/i;
|
|
32
|
+
const depsNotInTask = context.newDependencies.filter(dep => {
|
|
33
|
+
if (testTooling.test(dep) || buildTooling.test(dep)) return false;
|
|
34
|
+
if (dep.startsWith("dev:") || dep.startsWith("@vitest/") || dep.startsWith("@types/")) return false;
|
|
35
|
+
return !context.task?.toLowerCase().includes(dep.toLowerCase());
|
|
36
|
+
});
|
|
37
|
+
if (depsNotInTask.length > 0) {
|
|
38
|
+
alerts.push({
|
|
39
|
+
rule: "no_new_dependencies_without_task",
|
|
40
|
+
severity: "warn",
|
|
41
|
+
message: `New dependencies added not mentioned in task: ${depsNotInTask.join(", ")}`,
|
|
42
|
+
detail: { dependencies: depsNotInTask }
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Rule 4: Scope guard — files outside expected scope
|
|
48
|
+
if (rules.scope_guard && context.outOfScopeFiles?.length > 0) {
|
|
49
|
+
alerts.push({
|
|
50
|
+
rule: "scope_guard",
|
|
51
|
+
severity: "warn",
|
|
52
|
+
message: `Files modified outside expected scope: ${context.outOfScopeFiles.join(", ")}`,
|
|
53
|
+
detail: { files: context.outOfScopeFiles }
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Rule 5: Reviewer overreach — reviewer consistently flags out-of-scope issues
|
|
58
|
+
if (rules.reviewer_overreach && context.reviewerDemotedCount > 0) {
|
|
59
|
+
const severity = context.reviewerDemotedCount >= 3 ? "critical" : "warn";
|
|
60
|
+
alerts.push({
|
|
61
|
+
rule: "reviewer_overreach",
|
|
62
|
+
severity,
|
|
63
|
+
message: `Reviewer flagged ${context.reviewerDemotedCount} out-of-scope issue(s) that were auto-demoted by scope filter.`,
|
|
64
|
+
detail: { demotedCount: context.reviewerDemotedCount, autoApproved: context.reviewerAutoApproved || false }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Rule 6: Reviewer style-only block — all blocking issues are style/naming/formatting, not security/correctness
|
|
69
|
+
if (rules.reviewer_style_block && context.blockingIssues?.length > 0) {
|
|
70
|
+
const styleKeywords = /\b(naming|name|rename|style|format|formatting|indent|spacing|camelCase|snake_case|convention|cosmetic|readability|comment|jsdoc|documentation|whitespace|semicolon|quotes|trailing)\b/i;
|
|
71
|
+
// Anti-style: if any of these match, the issue is NOT style — it's a real correctness/security concern.
|
|
72
|
+
// Fixes KJC-BUG-0026 (Solomon approving legitimate security blockers misclassified as "style").
|
|
73
|
+
// Decomposed by concern (S5843, complexity 71 → 7 named groups).
|
|
74
|
+
// The union of tokens is byte-identical to the original alternation.
|
|
75
|
+
const SECURITY_KEYWORD_GROUPS = [
|
|
76
|
+
/\b(sql\s*injection|xss|csrf|ssrf|rce|injection|vulnerab|exploit)\b/i,
|
|
77
|
+
/\b(sanitiz|escape\b|encod\b|cors|traversal|prototype[-_\s]*pollution|deserializ)\b/i,
|
|
78
|
+
/\b(auth|authn|authz|password|secret|credential|token|api[-_\s]*key|private[-_\s]*key)\b/i,
|
|
79
|
+
/\b(hash|cipher|crypto|encrypt|decrypt|tls|ssl|certificate)\b/i,
|
|
80
|
+
/\b(leak|sensitive|pii|privacy|insecure|unsafe)\b/i,
|
|
81
|
+
/\b(race[-_\s]*condition|deadlock|memory[-_\s]*leak|null[-_\s]*deref|uaf|overflow)\b/i,
|
|
82
|
+
/\b(eval\b|exec\b|spawn|shell|command[-_\s]*injection)\b/i,
|
|
83
|
+
];
|
|
84
|
+
const securityKeywords = { test: (text) => SECURITY_KEYWORD_GROUPS.some((re) => re.test(text)) };
|
|
85
|
+
const securityCategories = new Set(["security", "correctness", "bug", "vulnerability"]);
|
|
86
|
+
const styleSeverities = new Set(["low", "minor"]);
|
|
87
|
+
const blockingSeverities = new Set(["critical", "high", "blocker", "major"]);
|
|
88
|
+
const isSecurityIssue = issue => {
|
|
89
|
+
const desc = issue.description || "";
|
|
90
|
+
const sev = (issue.severity || "").toLowerCase();
|
|
91
|
+
const cat = (issue.category || issue.type || "").toLowerCase();
|
|
92
|
+
const tags = Array.isArray(issue.tags) ? issue.tags.map(t => String(t).toLowerCase()) : [];
|
|
93
|
+
if (blockingSeverities.has(sev)) return true;
|
|
94
|
+
if (securityCategories.has(cat)) return true;
|
|
95
|
+
if (tags.some(t => securityCategories.has(t))) return true;
|
|
96
|
+
return securityKeywords.test(desc);
|
|
97
|
+
};
|
|
98
|
+
const allStyle = context.blockingIssues.every(issue => {
|
|
99
|
+
if (isSecurityIssue(issue)) return false;
|
|
100
|
+
const desc = issue.description || "";
|
|
101
|
+
const sev = (issue.severity || "").toLowerCase();
|
|
102
|
+
return styleSeverities.has(sev) || styleKeywords.test(desc);
|
|
103
|
+
});
|
|
104
|
+
if (allStyle) {
|
|
105
|
+
alerts.push({
|
|
106
|
+
rule: "reviewer_style_block",
|
|
107
|
+
severity: "critical",
|
|
108
|
+
message: `Reviewer blocked on ${context.blockingIssues.length} style-only issue(s). Style preferences should not block approval — escalating to Solomon mediation.`,
|
|
109
|
+
detail: { issueCount: context.blockingIssues.length, issues: context.blockingIssues.map(i => i.description) }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
alerts,
|
|
116
|
+
hasCritical: alerts.some(a => a.severity === "critical"),
|
|
117
|
+
hasWarnings: alerts.some(a => a.severity === "warn")
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Build context for rules evaluation from git diff and session state.
|
|
123
|
+
*/
|
|
124
|
+
export async function buildRulesContext({ session, task, iteration, blockingIssues }) {
|
|
125
|
+
const context = {
|
|
126
|
+
task,
|
|
127
|
+
iteration,
|
|
128
|
+
filesChanged: 0,
|
|
129
|
+
staleIterations: 0,
|
|
130
|
+
newDependencies: [],
|
|
131
|
+
outOfScopeFiles: [],
|
|
132
|
+
reviewerDemotedCount: 0,
|
|
133
|
+
reviewerAutoApproved: false,
|
|
134
|
+
blockingIssues: blockingIssues || []
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Count reviewer scope-filter demotions from session checkpoints
|
|
138
|
+
const scopeFilterCheckpoints = (session.checkpoints || [])
|
|
139
|
+
.filter(cp => cp.stage === "reviewer-scope-filter");
|
|
140
|
+
if (scopeFilterCheckpoints.length > 0) {
|
|
141
|
+
const latest = scopeFilterCheckpoints.at(-1);
|
|
142
|
+
context.reviewerDemotedCount = latest.demoted_count || 0;
|
|
143
|
+
context.reviewerAutoApproved = latest.auto_approved || false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Count files changed via git
|
|
147
|
+
try {
|
|
148
|
+
// Audit follow-up: was using execaCommand with template-string
|
|
149
|
+
// interpolation of `baseRef`. baseRef comes from session state, not
|
|
150
|
+
// user input, but the shape is a known shell-injection vector.
|
|
151
|
+
// Switched to execa with arg arrays so no shell expansion happens.
|
|
152
|
+
const { execa } = await import("execa");
|
|
153
|
+
const baseRef = session.session_start_sha || "HEAD~1";
|
|
154
|
+
|
|
155
|
+
// Files changed
|
|
156
|
+
const diffResult = await execa("git", ["diff", "--name-only", String(baseRef)], { reject: false });
|
|
157
|
+
if (diffResult.stdout) {
|
|
158
|
+
const files = diffResult.stdout.split("\n").filter(Boolean);
|
|
159
|
+
context.filesChanged = files.length;
|
|
160
|
+
|
|
161
|
+
// Detect scope: config files, CI/CD, etc. that are often out of scope
|
|
162
|
+
// Exclude .env.example (legitimate for new projects) and files within projectDir
|
|
163
|
+
const scopePatterns = [".github/", ".gitlab-ci", "docker-compose", "firebase.json", "firestore.rules"];
|
|
164
|
+
const projectDir = session?.config_snapshot?.projectDir || null;
|
|
165
|
+
context.outOfScopeFiles = files.filter(f => {
|
|
166
|
+
// Files inside projectDir are always in scope
|
|
167
|
+
if (projectDir && f.startsWith(projectDir.replace(/^\.\//, ""))) return false;
|
|
168
|
+
// .env (but not .env.example) is out of scope
|
|
169
|
+
if (f.endsWith(".env") && !f.endsWith(".env.example")) return true;
|
|
170
|
+
return scopePatterns.some(pattern => f.includes(pattern));
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Detect new dependencies
|
|
174
|
+
if (files.includes("package.json")) {
|
|
175
|
+
try {
|
|
176
|
+
const pkgDiff = await execa("git", ["diff", String(baseRef), "--", "package.json"], { reject: false });
|
|
177
|
+
const addedDeps = (pkgDiff.stdout || "").split("\n")
|
|
178
|
+
.filter(line => line.startsWith("+") && line.includes('"') && !line.startsWith("+++"))
|
|
179
|
+
.map(line => {
|
|
180
|
+
const match = /"([^"]+)":\s*"/.exec(line);
|
|
181
|
+
return match ? match[1] : null;
|
|
182
|
+
})
|
|
183
|
+
.filter(Boolean)
|
|
184
|
+
.filter(name => !new Set(["name", "version", "description", "main", "scripts", "type", "license", "author"]).has(name));
|
|
185
|
+
context.newDependencies = addedDeps;
|
|
186
|
+
} catch { /* ignore */ }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch { /* git not available */ }
|
|
190
|
+
|
|
191
|
+
// Count stale iterations from session checkpoints
|
|
192
|
+
// "Stale" means TRULY no progress: same exact feedback AND zero files changed
|
|
193
|
+
const checkpoints = session.checkpoints || [];
|
|
194
|
+
const reviewerCps = checkpoints.filter(cp => cp.stage === "reviewer").slice(-3);
|
|
195
|
+
const coderCps = checkpoints.filter(cp => cp.stage === "coder").slice(-3);
|
|
196
|
+
|
|
197
|
+
if (reviewerCps.length >= 3) {
|
|
198
|
+
const feedbacks = reviewerCps.map(cp => cp.note || "");
|
|
199
|
+
const uniqueFeedbacks = new Set(feedbacks);
|
|
200
|
+
const filesChanged = coderCps.some(cp => (cp.filesChanged || 0) > 0);
|
|
201
|
+
|
|
202
|
+
// Only stale if feedback is identical AND no files changed
|
|
203
|
+
if (uniqueFeedbacks.size === 1 && !filesChanged) {
|
|
204
|
+
context.staleIterations = reviewerCps.length;
|
|
205
|
+
}
|
|
206
|
+
// If issues are changing between iterations, there IS progress
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return context;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export { DEFAULT_RULES };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architect stage logic.
|
|
3
|
+
* Extracted from pre-loop-stages.js for maintainability.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ArchitectRole } from "../../roles/architect-role.js";
|
|
7
|
+
import { createAgent } from "../../agents/index.js";
|
|
8
|
+
import { addCheckpoint } from "../../session/store.js";
|
|
9
|
+
import { emitProgress, makeEvent, emitAgentOutput } from "../../utils/events.js";
|
|
10
|
+
import { createStallDetector } from "../../utils/stall-detector.js";
|
|
11
|
+
import { getIntegration } from "../integrations.js";
|
|
12
|
+
|
|
13
|
+
async function handleArchitectClarification({ architectOutput, askQuestion, config, logger, emitter, eventBase, session, architectOnOutput, architectProvider, coderRole, researchContext, discoverResult, triageLevel, trackBudget }) {
|
|
14
|
+
if (!architectOutput.ok
|
|
15
|
+
|| architectOutput.result?.verdict !== "needs_clarification"
|
|
16
|
+
|| !architectOutput.result?.questions?.length) {
|
|
17
|
+
return architectOutput;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const questions = architectOutput.result.questions;
|
|
21
|
+
if (!askQuestion) {
|
|
22
|
+
logger.warn("Architect returned needs_clarification but no interactive input available — continuing with best-effort decisions");
|
|
23
|
+
return architectOutput;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const formatted = "The architect needs clarification before proceeding:\n\n"
|
|
27
|
+
+ questions.map((q, i) => `${i + 1}. ${q}`).join("\n")
|
|
28
|
+
+ "\n\nPlease provide your answers:";
|
|
29
|
+
|
|
30
|
+
emitProgress(
|
|
31
|
+
emitter,
|
|
32
|
+
makeEvent("architect:clarification", { ...eventBase, stage: "architect" }, {
|
|
33
|
+
message: "Architect needs clarification — pausing for human input",
|
|
34
|
+
detail: { questions }
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const answer = await askQuestion(formatted, { iteration: 0, stage: "architect" });
|
|
39
|
+
if (!answer) return architectOutput;
|
|
40
|
+
|
|
41
|
+
const architect2 = new ArchitectRole({ config, logger, emitter, createAgentFn: createAgent });
|
|
42
|
+
await architect2.init({ task: session.task, sessionId: session.id, iteration: 0 });
|
|
43
|
+
const rerunStart = Date.now();
|
|
44
|
+
const rerunStall = createStallDetector({
|
|
45
|
+
onOutput: architectOnOutput, emitter, eventBase, stage: "architect", provider: architectProvider
|
|
46
|
+
});
|
|
47
|
+
let result;
|
|
48
|
+
try {
|
|
49
|
+
result = await architect2.execute({
|
|
50
|
+
task: session.task,
|
|
51
|
+
onOutput: rerunStall.onOutput,
|
|
52
|
+
researchContext,
|
|
53
|
+
discoverResult,
|
|
54
|
+
triageLevel,
|
|
55
|
+
humanAnswers: answer
|
|
56
|
+
});
|
|
57
|
+
} finally {
|
|
58
|
+
rerunStall.stop();
|
|
59
|
+
}
|
|
60
|
+
trackBudget({
|
|
61
|
+
role: "architect",
|
|
62
|
+
provider: architectProvider,
|
|
63
|
+
model: config?.roles?.architect?.model || coderRole.model,
|
|
64
|
+
result,
|
|
65
|
+
duration_ms: Date.now() - rerunStart
|
|
66
|
+
});
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function runArchitectStage({ config, logger, emitter, eventBase, session, coderRole, trackBudget, researchContext = null, discoverResult = null, triageLevel = null, askQuestion = null }) {
|
|
71
|
+
logger.setContext({ iteration: 0, stage: "architect" });
|
|
72
|
+
const architectProvider = config?.roles?.architect?.provider || coderRole.provider;
|
|
73
|
+
emitProgress(
|
|
74
|
+
emitter,
|
|
75
|
+
makeEvent("architect:start", { ...eventBase, stage: "architect" }, {
|
|
76
|
+
message: "Architect designing solution architecture",
|
|
77
|
+
detail: { architect: architectProvider, provider: architectProvider, executorType: "agent" }
|
|
78
|
+
})
|
|
79
|
+
);
|
|
80
|
+
const architectOnOutput = (payload) => emitAgentOutput(emitter, eventBase, "architect", architectProvider, payload);
|
|
81
|
+
const architectStall = createStallDetector({
|
|
82
|
+
onOutput: architectOnOutput, emitter, eventBase, stage: "architect", provider: architectProvider
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const architect = new ArchitectRole({ config, logger, emitter, createAgentFn: createAgent });
|
|
86
|
+
await architect.init({ task: session.task, sessionId: session.id, iteration: 0 });
|
|
87
|
+
const architectStart = Date.now();
|
|
88
|
+
let architectOutput;
|
|
89
|
+
try {
|
|
90
|
+
architectOutput = await architect.execute({
|
|
91
|
+
task: session.task,
|
|
92
|
+
onOutput: architectStall.onOutput,
|
|
93
|
+
researchContext,
|
|
94
|
+
discoverResult,
|
|
95
|
+
triageLevel
|
|
96
|
+
});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
logger.warn(`Architect threw: ${err.message}`);
|
|
99
|
+
architectOutput = { ok: false, summary: `Architect error: ${err.message}`, result: { error: err.message } };
|
|
100
|
+
} finally {
|
|
101
|
+
architectStall.stop();
|
|
102
|
+
}
|
|
103
|
+
trackBudget({
|
|
104
|
+
role: "architect",
|
|
105
|
+
provider: architectProvider,
|
|
106
|
+
model: config?.roles?.architect?.model || coderRole.model,
|
|
107
|
+
result: architectOutput,
|
|
108
|
+
duration_ms: Date.now() - architectStart
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await addCheckpoint(session, {
|
|
112
|
+
stage: "architect",
|
|
113
|
+
iteration: 0,
|
|
114
|
+
ok: architectOutput.ok,
|
|
115
|
+
provider: architectProvider,
|
|
116
|
+
model: config?.roles?.architect?.model || coderRole.model || null
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// --- Interactive clarification loop ---
|
|
120
|
+
architectOutput = await handleArchitectClarification({
|
|
121
|
+
architectOutput, askQuestion, config, logger, emitter, eventBase, session,
|
|
122
|
+
architectOnOutput, architectProvider, coderRole, researchContext, discoverResult, triageLevel, trackBudget
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const stageResult = {
|
|
126
|
+
ok: architectOutput.ok,
|
|
127
|
+
verdict: architectOutput.result?.verdict || null,
|
|
128
|
+
architecture: architectOutput.result?.architecture || null,
|
|
129
|
+
questions: architectOutput.result?.questions || []
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
emitProgress(
|
|
133
|
+
emitter,
|
|
134
|
+
makeEvent("architect:end", { ...eventBase, stage: "architect" }, {
|
|
135
|
+
status: architectOutput.ok ? "ok" : "fail",
|
|
136
|
+
message: architectOutput.ok ? "Architecture completed" : `Architecture failed: ${architectOutput.summary}`,
|
|
137
|
+
detail: { ...stageResult, provider: architectProvider, executorType: "agent" }
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const architectContext = architectOutput.ok ? architectOutput.result : null;
|
|
142
|
+
|
|
143
|
+
// TSK-0339: ADR creation is now a tracker hook. The orchestrator ships the
|
|
144
|
+
// tradeoffs; the registered adapter decides whether/how to persist them
|
|
145
|
+
// (PG creates ADR cards, another tracker might create Jira issues, an
|
|
146
|
+
// unregistered tracker is a no-op).
|
|
147
|
+
const tradeoffs = architectOutput.result?.architecture?.tradeoffs;
|
|
148
|
+
if (architectOutput.ok
|
|
149
|
+
&& architectOutput.result?.verdict === "ready"
|
|
150
|
+
&& tradeoffs?.length > 0
|
|
151
|
+
&& session.pg_task_id
|
|
152
|
+
&& session.pg_project_id) {
|
|
153
|
+
try {
|
|
154
|
+
const adrResult = await getIntegration("tracker")?.createAdrsFromTradeoffs?.({
|
|
155
|
+
tradeoffs,
|
|
156
|
+
pgTaskId: session.pg_task_id,
|
|
157
|
+
pgProject: session.pg_project_id,
|
|
158
|
+
taskTitle: session.task,
|
|
159
|
+
});
|
|
160
|
+
if (adrResult) {
|
|
161
|
+
stageResult.adrs = adrResult;
|
|
162
|
+
if (adrResult.created > 0) {
|
|
163
|
+
logger.info(`Architect: created ${adrResult.created} ADR(s) in tracker`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
logger.warn(`Architect: failed to create ADRs: ${err.message}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { architectContext, stageResult };
|
|
172
|
+
}
|