@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,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tournament/crown — TOR-C (KJC-TSK-0725, epic KJC-PCS-0073). The last act:
|
|
3
|
+
* the tournament winner enters main THROUGH THE NORMAL DOOR, not around it.
|
|
4
|
+
*
|
|
5
|
+
* In the winner's still-alive lane: stage everything, run the real cross-AI
|
|
6
|
+
* review over the EXACT staged diff (verdict bound to its sha256, stored by
|
|
7
|
+
* the same verdict-store every commit uses), then commit — where the
|
|
8
|
+
* pre-commit gate validates that verdict like any other commit's. A
|
|
9
|
+
* rejected review ABORTS the coronation with the reasons: winning the
|
|
10
|
+
* tournament earns you a candidacy, not a bypass. Losers keep their full
|
|
11
|
+
* dossier under the tournament dir; their lanes are never removed here.
|
|
12
|
+
*/
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { execFile } from "node:child_process";
|
|
16
|
+
import { promisify } from "node:util";
|
|
17
|
+
import { runOneShotReview } from "../review/one-shot-review.js";
|
|
18
|
+
|
|
19
|
+
const execFileAsync = promisify(execFile);
|
|
20
|
+
|
|
21
|
+
const defaultExec = async (cmd, args, { cwd }) => {
|
|
22
|
+
const res = await execFileAsync(cmd, args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
23
|
+
return { exitCode: 0, stdout: res.stdout || "" };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
async function defaultReview({ lane, task, config, logger }) {
|
|
27
|
+
const { stdout: diff } = await execFileAsync("git", ["diff", "--cached"], { cwd: lane, maxBuffer: 64 * 1024 * 1024 });
|
|
28
|
+
try {
|
|
29
|
+
const record = await runOneShotReview({
|
|
30
|
+
diff,
|
|
31
|
+
task: `Tournament winner review. Original task:\n${task}`,
|
|
32
|
+
config: { ...config, projectDir: lane },
|
|
33
|
+
logger,
|
|
34
|
+
projectDir: lane,
|
|
35
|
+
});
|
|
36
|
+
return { ok: record.verdict === "approved", ...record };
|
|
37
|
+
} catch (err) {
|
|
38
|
+
return { ok: false, verdict: "error", error: err.message };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Crown the judged winner: governed review + commit in its lane.
|
|
44
|
+
* @returns {Promise<{winner: string, branch: string, commit: string, verdict: object}>}
|
|
45
|
+
*/
|
|
46
|
+
export async function crownWinner({ tournamentDir, config = {}, logger = console, cardRef = null, deps = {} }) {
|
|
47
|
+
const { execFn = defaultExec, reviewFn = defaultReview } = deps;
|
|
48
|
+
|
|
49
|
+
const judgementPath = path.join(tournamentDir, "judgement.json");
|
|
50
|
+
if (!fs.existsSync(judgementPath)) {
|
|
51
|
+
throw new Error("tournament: no hay judgement.json — corre primero kj tournament --judge <id>");
|
|
52
|
+
}
|
|
53
|
+
const judgement = JSON.parse(fs.readFileSync(judgementPath, "utf8"));
|
|
54
|
+
const summary = JSON.parse(fs.readFileSync(path.join(tournamentDir, "summary.json"), "utf8"));
|
|
55
|
+
const winner = judgement.winner;
|
|
56
|
+
const meta = JSON.parse(fs.readFileSync(path.join(tournamentDir, winner, "meta.json"), "utf8"));
|
|
57
|
+
const lane = meta.lane;
|
|
58
|
+
if (!lane || !fs.existsSync(lane)) {
|
|
59
|
+
throw new Error(`tournament: el carril del ganador (${winner}) ya no existe — corona justo después de juzgar, antes de limpiar carriles`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logger?.info?.(`coronando a ${winner} en ${meta.branch} — por la puerta normal, no por un atajo`);
|
|
63
|
+
await execFn("git", ["add", "-A"], { cwd: lane });
|
|
64
|
+
|
|
65
|
+
const verdict = await reviewFn({ lane, task: summary.task, config, logger });
|
|
66
|
+
if (!verdict?.ok) {
|
|
67
|
+
const issues = (verdict?.issues || []).map((i) => ` - ${i.description}`).join("\n");
|
|
68
|
+
throw new Error(
|
|
69
|
+
`tournament: la review RECHAZÓ al ganador (${winner}) — ganar el torneo da candidatura, no bypass.\n${issues || verdict?.error || ""}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const ref = cardRef ? ` (${cardRef})` : "";
|
|
74
|
+
const msg = `feat(tournament): crown ${winner} — ${String(summary.task).slice(0, 50).toLowerCase()}${ref} [${summary.id}]`;
|
|
75
|
+
await execFn("git", ["commit", "-m", msg], { cwd: lane });
|
|
76
|
+
const { stdout } = await execFn("git", ["rev-parse", "HEAD"], { cwd: lane });
|
|
77
|
+
const commit = stdout.trim();
|
|
78
|
+
|
|
79
|
+
const crown = {
|
|
80
|
+
winner, branch: meta.branch, commit,
|
|
81
|
+
verdict: { verdict: verdict.verdict, reviewer: verdict.reviewer, diffHash: verdict.diffHash },
|
|
82
|
+
crowned_at: new Date().toISOString(),
|
|
83
|
+
};
|
|
84
|
+
fs.writeFileSync(path.join(tournamentDir, "crown.json"), JSON.stringify(crown, null, 2));
|
|
85
|
+
logger?.info?.(`✓ coronado: ${winner} · commit ${commit.slice(0, 9)} en ${meta.branch} — la rama queda lista para PR`);
|
|
86
|
+
logger?.info?.(" los perdedores conservan su expediente en el dir del torneo; limpia carriles con kj worktree done cuando quieras");
|
|
87
|
+
return { winner, branch: meta.branch, commit, verdict: crown.verdict };
|
|
88
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tournament/judge — TOR-C (KJC-TSK-0725, epic KJC-PCS-0073).
|
|
3
|
+
*
|
|
4
|
+
* The scoreboard (TOR-B) ELIMINATES; the judge CHOOSES among survivors —
|
|
5
|
+
* a cross-AI reviewer ranking the finalists with the deterministic table
|
|
6
|
+
* in sight, so the LLM judges what metrics cannot see (design, readability,
|
|
7
|
+
* over-engineering) without overruling what they can. Two hard rules:
|
|
8
|
+
* a participant coder never judges its own tournament (nor does the host),
|
|
9
|
+
* and a WINNER disagreement with the scoreboard — or a declared tie —
|
|
10
|
+
* escalates to solomon carrying BOTH positions. Only first place crowns:
|
|
11
|
+
* lower-order differences are informative and never escalate (the card's
|
|
12
|
+
* "discrepancia fuerte" — over-escalating would make solomon the judge). Diffs travel WHOLE or the limit is
|
|
13
|
+
* DECLARED in the prompt (the [TRUNCATED]-blamed-on-the-file lesson,
|
|
14
|
+
* BUG-0134): the judge must never mistake our clipping for the coder's code.
|
|
15
|
+
*/
|
|
16
|
+
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { createAgent } from "../agents/index.js";
|
|
19
|
+
import { resolveRole } from "../config/role-resolver.js";
|
|
20
|
+
import { detectHostAgent } from "../utils/agent-detect.js";
|
|
21
|
+
import { candidateStatus } from "../review/reviewer-fallback.js";
|
|
22
|
+
|
|
23
|
+
const MAX_DIFF_CHARS = 60_000;
|
|
24
|
+
|
|
25
|
+
/** The configured reviewer unless it competed or hosts; else the first clean candidate. */
|
|
26
|
+
export function pickJudge({ configured, participants = [], host = null, statuses = [] }) {
|
|
27
|
+
const dirty = new Set([...participants, host].filter(Boolean));
|
|
28
|
+
if (configured && !dirty.has(configured)) return configured;
|
|
29
|
+
const clean = statuses.find((s) => s.installed && s.authenticated && !s.adapterPending && !dirty.has(s.name));
|
|
30
|
+
return clean ? clean.name : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function defaultJudge({ config, participants }) {
|
|
34
|
+
const configured = resolveRole(config, "reviewer").provider;
|
|
35
|
+
const statuses = await candidateStatus();
|
|
36
|
+
return pickJudge({ configured, participants, host: detectHostAgent(), statuses });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function defaultAgent({ judge, prompt, config, logger }) {
|
|
40
|
+
return createAgent(judge, config, logger).reviewTask({ prompt, role: "reviewer" });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function finalistBlock(board, torDir, coder) {
|
|
44
|
+
const row = board.rows.find((r) => r.coder === coder);
|
|
45
|
+
let diff = fs.readFileSync(path.join(torDir, coder, "diff.patch"), "utf8");
|
|
46
|
+
let clipped = false;
|
|
47
|
+
if (diff.length > MAX_DIFF_CHARS) {
|
|
48
|
+
diff = diff.slice(0, MAX_DIFF_CHARS);
|
|
49
|
+
clipped = true;
|
|
50
|
+
}
|
|
51
|
+
return [
|
|
52
|
+
`### Finalista: ${coder}`,
|
|
53
|
+
`Scoreboard: ${JSON.stringify(row)}`,
|
|
54
|
+
clipped
|
|
55
|
+
? `NOTA DEL SISTEMA: el diff se muestra RECORTADO a ${MAX_DIFF_CHARS} caracteres por límite del prompt — el recorte es NUESTRO, no un defecto del código; júzgalo por lo visible y dilo en tus razones.`
|
|
56
|
+
: "",
|
|
57
|
+
"```diff", diff, "```",
|
|
58
|
+
].filter(Boolean).join("\n");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Judge a scored tournament: rank finalists, escalate on tie/disagreement.
|
|
63
|
+
* @returns {Promise<{winner: string, judge: string|null, escalated: boolean, walkover?: boolean}>}
|
|
64
|
+
*/
|
|
65
|
+
export async function judgeTournament({ tournamentDir, config = {}, logger = console, deps = {} }) {
|
|
66
|
+
const { judgeFn = defaultJudge, agentFn = defaultAgent, solomonFn = null } = deps;
|
|
67
|
+
const board = JSON.parse(fs.readFileSync(path.join(tournamentDir, "scoreboard.json"), "utf8"));
|
|
68
|
+
const finalists = board.rows.filter((r) => r.finalist).map((r) => r.coder);
|
|
69
|
+
const participants = board.rows.map((r) => r.coder);
|
|
70
|
+
|
|
71
|
+
if (finalists.length === 0) throw new Error("tournament: sin finalistas (todas las suites rojas) — no hay nada que juzgar");
|
|
72
|
+
if (finalists.length === 1) {
|
|
73
|
+
const judgement = { winner: finalists[0], judge: null, escalated: false, walkover: true, board_ranking: board.ranking };
|
|
74
|
+
fs.writeFileSync(path.join(tournamentDir, "judgement.json"), JSON.stringify(judgement, null, 2));
|
|
75
|
+
logger?.info?.(`torneo ${board.id}: ganador por walkover — ${finalists[0]} (único finalista)`);
|
|
76
|
+
return judgement;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const judge = await judgeFn({ config, participants });
|
|
80
|
+
if (!judge) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"tournament: sin juez limpio — todos los agentes disponibles compitieron o son el host. " +
|
|
83
|
+
"Un participante jamás juzga su propio torneo: quita un coder o añade un agente."
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const prompt = [
|
|
88
|
+
"Eres el JUEZ de un torneo de código: varios coders resolvieron la MISMA tarea de forma independiente.",
|
|
89
|
+
"La fase determinista ya eliminó a los que suspendieron la suite. Tu trabajo: ordenar a los finalistas",
|
|
90
|
+
"por calidad de solución (diseño, legibilidad, ausencia de sobre-ingeniería), con el scoreboard a la vista.",
|
|
91
|
+
`Regla del scoreboard: ${board.rule}`,
|
|
92
|
+
`Ranking del scoreboard: ${board.ranking.join(" > ")}`,
|
|
93
|
+
`TAREA ORIGINAL:\n${board.task}`,
|
|
94
|
+
...finalists.map((c) => finalistBlock(board, tournamentDir, c)),
|
|
95
|
+
'Responde SOLO con JSON: {"ranking": ["coder", ...], "reasons": {"coder": "por qué"}, "tie": false}',
|
|
96
|
+
"Declara tie:true únicamente si de verdad no puedes distinguirlos.",
|
|
97
|
+
].join("\n\n");
|
|
98
|
+
|
|
99
|
+
logger?.info?.(`torneo ${board.id}: juez=${judge} sobre ${finalists.length} finalistas`);
|
|
100
|
+
const res = await agentFn({ judge, prompt, config, logger });
|
|
101
|
+
if (!res?.ok) throw new Error(`tournament: el juez ${judge} falló: ${res?.error || "sin salida"}`);
|
|
102
|
+
let verdict;
|
|
103
|
+
try {
|
|
104
|
+
verdict = JSON.parse(String(res.output).replace(/^[^{]*/, "").replace(/[^}]*$/, ""));
|
|
105
|
+
} catch {
|
|
106
|
+
throw new Error(`tournament: el juez ${judge} no devolvió un veredicto parseable`);
|
|
107
|
+
}
|
|
108
|
+
// An LLM verdict is untrusted input: the ranking must name FINALISTS and
|
|
109
|
+
// nobody else — a hallucinated coder must fail loud, never get crowned.
|
|
110
|
+
const isFinalist = (c) => finalists.includes(c);
|
|
111
|
+
if (!Array.isArray(verdict.ranking) || verdict.ranking.length === 0 || !verdict.ranking.every(isFinalist)) {
|
|
112
|
+
throw new Error(`tournament: ranking del juez inválido (${JSON.stringify(verdict.ranking)}) — debe nombrar solo finalistas: ${finalists.join(", ")}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Only FIRST place crowns a winner: a judge that reorders lower positions
|
|
116
|
+
// but agrees on who wins is agreement, not a dispute for solomon.
|
|
117
|
+
const judgeTop = verdict.ranking?.[0];
|
|
118
|
+
const boardTop = board.ranking[0];
|
|
119
|
+
const disagreement = judgeTop !== boardTop;
|
|
120
|
+
const escalated = Boolean(verdict.tie || disagreement);
|
|
121
|
+
|
|
122
|
+
let winner = judgeTop;
|
|
123
|
+
let solomon = null;
|
|
124
|
+
if (escalated) {
|
|
125
|
+
if (!solomonFn) {
|
|
126
|
+
const why = verdict.tie ? "empate declarado" : `discrepancia juez(${judgeTop}) vs scoreboard(${boardTop})`;
|
|
127
|
+
throw new Error(`tournament: ${why} y sin árbitro configurado`);
|
|
128
|
+
}
|
|
129
|
+
solomon = await solomonFn({
|
|
130
|
+
judgeRanking: verdict.ranking,
|
|
131
|
+
boardRanking: board.ranking,
|
|
132
|
+
reasons: verdict.reasons,
|
|
133
|
+
tie: Boolean(verdict.tie),
|
|
134
|
+
});
|
|
135
|
+
if (!isFinalist(solomon?.winner)) {
|
|
136
|
+
throw new Error(`tournament: solomon devolvió un ganador inválido (${solomon?.winner}) — debe ser finalista`);
|
|
137
|
+
}
|
|
138
|
+
winner = solomon.winner;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const judgement = {
|
|
142
|
+
winner, judge, escalated,
|
|
143
|
+
judge_ranking: verdict.ranking, judge_reasons: verdict.reasons || {},
|
|
144
|
+
board_ranking: board.ranking, solomon,
|
|
145
|
+
judged_at: new Date().toISOString(),
|
|
146
|
+
};
|
|
147
|
+
fs.writeFileSync(path.join(tournamentDir, "judgement.json"), JSON.stringify(judgement, null, 2));
|
|
148
|
+
logger?.info?.(`torneo ${board.id}: ganador=${winner}${escalated ? " (vía solomon)" : " (juez y scoreboard de acuerdo)"}`);
|
|
149
|
+
return judgement;
|
|
150
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tournament/run — TOR-A (KJC-TSK-0723, epic KJC-PCS-0073).
|
|
3
|
+
*
|
|
4
|
+
* Orca's pitch is "fan one prompt across N agents, compare, merge the
|
|
5
|
+
* winner" — with a human eyeballing diffs. Karajan's tournament keeps the
|
|
6
|
+
* fan-out and replaces the eyeballing with the method: this module runs the
|
|
7
|
+
* SAME task through N coders, each in its own isolated worktree lane (the
|
|
8
|
+
* PAR machinery), and collects per-lane evidence (diff, suite result, agent
|
|
9
|
+
* log, metadata) for the deterministic scoreboard (TOR-B) and the governed
|
|
10
|
+
* judgement/merge (TOR-C). No commits here: lanes stay as working trees.
|
|
11
|
+
*
|
|
12
|
+
* A COMPOSER, not a new pipeline: lanes = `git worktree` under
|
|
13
|
+
* .kj/worktrees (same dir as kj worktree / headless lanes); agents = the
|
|
14
|
+
* registered adapters with the PAR idiom (laneConfig.projectDir = lane,
|
|
15
|
+
* task.cwd = lane); suite = the package manager the repo actually uses.
|
|
16
|
+
* Every dependency is injectable; one lane's failure never sinks another.
|
|
17
|
+
*/
|
|
18
|
+
import fs from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { execFile } from "node:child_process";
|
|
21
|
+
import { promisify } from "node:util";
|
|
22
|
+
import { createAgent } from "../agents/index.js";
|
|
23
|
+
import { bootstrapWorktree } from "../hu/worktree-bootstrap.js";
|
|
24
|
+
import { detectPackageManager } from "../harden/workflow-engine.js";
|
|
25
|
+
import { PM_COMMANDS } from "../harden/workflow-templates.js";
|
|
26
|
+
|
|
27
|
+
const execFileAsync = promisify(execFile);
|
|
28
|
+
const WORKTREE_DIR = ".kj/worktrees"; // shared with kj worktree + headless lanes
|
|
29
|
+
const TOURNAMENT_DIR = ".kj/tournaments";
|
|
30
|
+
const SUITE_TIMEOUT_MS = 15 * 60 * 1000;
|
|
31
|
+
|
|
32
|
+
const defaultGit = (args, cwd) => execFileAsync("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
33
|
+
|
|
34
|
+
async function defaultRunSuite({ lanePath }) {
|
|
35
|
+
const pm = detectPackageManager(lanePath);
|
|
36
|
+
const testCmd = (PM_COMMANDS[pm] || PM_COMMANDS.npm).test.split(" ");
|
|
37
|
+
try {
|
|
38
|
+
const res = await execFileAsync(testCmd[0], testCmd.slice(1), {
|
|
39
|
+
cwd: lanePath, timeout: SUITE_TIMEOUT_MS, maxBuffer: 64 * 1024 * 1024,
|
|
40
|
+
});
|
|
41
|
+
return { ok: true, exitCode: 0, output: res.stdout || "" };
|
|
42
|
+
} catch (err) {
|
|
43
|
+
return { ok: false, exitCode: err.code ?? 1, output: `${err.stdout || ""}\n${err.stderr || ""}` };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Fan the task out to every coder and collect per-lane results.
|
|
49
|
+
* @returns {Promise<{id: string, dir: string, lanes: Array<object>}>}
|
|
50
|
+
*/
|
|
51
|
+
export async function runTournament({ task, coders = [], config = {}, logger = console, deps = {} }) {
|
|
52
|
+
const {
|
|
53
|
+
createAgentFn = createAgent,
|
|
54
|
+
gitFn = defaultGit,
|
|
55
|
+
bootstrapFn = bootstrapWorktree,
|
|
56
|
+
runSuiteFn = defaultRunSuite,
|
|
57
|
+
} = deps;
|
|
58
|
+
if (!task || !String(task).trim()) throw new Error("tournament: falta la tarea");
|
|
59
|
+
if (!Array.isArray(coders) || coders.length < 2) {
|
|
60
|
+
throw new Error("tournament: hacen falta al menos 2 coders (--coders a,b) — con uno no hay torneo");
|
|
61
|
+
}
|
|
62
|
+
// Coder names feed lane/result PATHS: a strict slug (no separators, no
|
|
63
|
+
// leading dot, no traversal) before any filesystem use — codex's catch.
|
|
64
|
+
const CODER_RE = /^[a-z0-9][a-z0-9_-]{0,23}$/i;
|
|
65
|
+
for (const c of coders) {
|
|
66
|
+
if (!CODER_RE.test(String(c))) {
|
|
67
|
+
throw new Error(`tournament: nombre de coder inválido "${c}" — solo letras, dígitos, guiones (sin rutas)`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const projectDir = config.projectDir || process.cwd();
|
|
72
|
+
const id = `tor-${Date.now().toString(36)}`;
|
|
73
|
+
const resultsRoot = path.join(projectDir, TOURNAMENT_DIR, id);
|
|
74
|
+
fs.mkdirSync(resultsRoot, { recursive: true });
|
|
75
|
+
logger?.info?.(`kj tournament ${id}: ${coders.length} coders → ${coders.join(", ")}`);
|
|
76
|
+
|
|
77
|
+
const settled = await Promise.allSettled(coders.map((coder) => runLane({
|
|
78
|
+
coder, task, id, projectDir, resultsRoot, config, logger,
|
|
79
|
+
createAgentFn, gitFn, bootstrapFn, runSuiteFn,
|
|
80
|
+
})));
|
|
81
|
+
|
|
82
|
+
const lanes = settled.map((s, i) =>
|
|
83
|
+
s.status === "fulfilled"
|
|
84
|
+
? s.value
|
|
85
|
+
: { coder: coders[i], status: "failed", error: String(s.reason?.message || s.reason), dir: path.join(resultsRoot, coders[i]) },
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const summary = { id, task: String(task), created_at: new Date().toISOString(), lanes };
|
|
89
|
+
fs.writeFileSync(path.join(resultsRoot, "summary.json"), JSON.stringify(summary, null, 2));
|
|
90
|
+
for (const lane of lanes) {
|
|
91
|
+
let state = `FAILED: ${lane.error}`;
|
|
92
|
+
if (lane.status === "completed") state = lane.suite?.ok ? "suite verde" : "suite ROJA";
|
|
93
|
+
logger?.info?.(` ${lane.coder.padEnd(10)} ${lane.status.padEnd(10)} ${state}`);
|
|
94
|
+
}
|
|
95
|
+
return { id, dir: resultsRoot, lanes };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function runLane({ coder, task, id, projectDir, resultsRoot, config, logger, createAgentFn, gitFn, bootstrapFn, runSuiteFn }) {
|
|
99
|
+
const slug = `${id}-${coder}`;
|
|
100
|
+
const lanePath = path.join(projectDir, WORKTREE_DIR, slug);
|
|
101
|
+
const branch = `tor/${slug}`;
|
|
102
|
+
const laneDir = path.join(resultsRoot, coder);
|
|
103
|
+
fs.mkdirSync(laneDir, { recursive: true });
|
|
104
|
+
|
|
105
|
+
await gitFn(["worktree", "add", "-b", branch, lanePath], projectDir);
|
|
106
|
+
await bootstrapFn({ worktreePath: lanePath, setupCommand: config?.session?.worktree_setup || null });
|
|
107
|
+
|
|
108
|
+
// The PAR idiom: the lane IS the project for this agent. A tournament
|
|
109
|
+
// coder MUST be able to write files — found live in the first real run:
|
|
110
|
+
// codex without auto_approve produced an honest but useless EMPTY diff.
|
|
111
|
+
const laneConfig = {
|
|
112
|
+
...config,
|
|
113
|
+
projectDir: lanePath,
|
|
114
|
+
coder_options: { ...config?.coder_options, auto_approve: true },
|
|
115
|
+
};
|
|
116
|
+
const prompt =
|
|
117
|
+
`You are one of ${"several"} coders solving the SAME task independently. ` +
|
|
118
|
+
`Work ONLY inside this directory (your isolated worktree). Implement the task with tests. Do not commit.\n\nTASK:\n${task}`;
|
|
119
|
+
const started = Date.now();
|
|
120
|
+
const result = await createAgentFn(coder, laneConfig, logger).runTask({ prompt, role: "coder", cwd: lanePath });
|
|
121
|
+
fs.writeFileSync(path.join(laneDir, "agent.log"), String(result?.output ?? ""));
|
|
122
|
+
if (!result?.ok) throw new Error(`coder ${coder} failed: ${result?.error || "no output"}`);
|
|
123
|
+
|
|
124
|
+
// Intent-to-add first: plain `git diff` is blind to UNTRACKED files, and
|
|
125
|
+
// new files are the most common coder output — codex's catch.
|
|
126
|
+
await gitFn(["add", "-N", "."], lanePath);
|
|
127
|
+
const diff = await gitFn(["diff"], lanePath);
|
|
128
|
+
fs.writeFileSync(path.join(laneDir, "diff.patch"), diff.stdout || "");
|
|
129
|
+
|
|
130
|
+
const suite = await runSuiteFn({ lanePath });
|
|
131
|
+
fs.writeFileSync(path.join(laneDir, "suite.log"), suite.output || "");
|
|
132
|
+
|
|
133
|
+
const meta = {
|
|
134
|
+
coder, branch, lane: lanePath, tournament: id,
|
|
135
|
+
duration_ms: Date.now() - started,
|
|
136
|
+
diff_bytes: (diff.stdout || "").length,
|
|
137
|
+
suite: { ok: suite.ok, exitCode: suite.exitCode },
|
|
138
|
+
};
|
|
139
|
+
fs.writeFileSync(path.join(laneDir, "meta.json"), JSON.stringify(meta, null, 2));
|
|
140
|
+
|
|
141
|
+
return { coder, status: "completed", branch, lane: lanePath, dir: laneDir, suite: { ok: suite.ok, exitCode: suite.exitCode } };
|
|
142
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tournament/scoreboard — TOR-B (KJC-TSK-0724, epic KJC-PCS-0073).
|
|
3
|
+
*
|
|
4
|
+
* The deterministic half of "merge the winner": pure metrics computed from
|
|
5
|
+
* the artifacts TOR-A leaves under .kj/tournaments/<id>/ (suite verdict,
|
|
6
|
+
* net LOC, tests touched — parsed from diff.patch), plus injectable
|
|
7
|
+
* external metrics (mutation via `kj mutate` in the still-alive lane;
|
|
8
|
+
* sonar reserved) that degrade HONESTLY to null-with-note when their tool
|
|
9
|
+
* is unavailable — a fake zero would poison the ranking. Red suites are
|
|
10
|
+
* eliminated, never finalists. The ranking rule is lexicographic and
|
|
11
|
+
* PRINTED with the result: no opaque composite scores, no hidden weights.
|
|
12
|
+
* Zero LLM in this whole phase.
|
|
13
|
+
*/
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { execFile } from "node:child_process";
|
|
17
|
+
import { promisify } from "node:util";
|
|
18
|
+
|
|
19
|
+
const execFileAsync = promisify(execFile);
|
|
20
|
+
const TESTS_RE = /(?:(?:^|\/)(?:tests?|__tests__|spec)\/)|(?:\.(?:test|spec)\.[a-z]+$)/;
|
|
21
|
+
const MUTATE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
22
|
+
|
|
23
|
+
// EXACT unified-diff header forms — an added line whose content starts with
|
|
24
|
+
// "++" produces "+++<content>" and must still COUNT (codex's catch): only
|
|
25
|
+
// `+++ b/…`, `+++ /dev/null`, `--- a/…`, `--- /dev/null` are headers.
|
|
26
|
+
const ADD_HEADER_RE = /^\+\+\+ (b\/|\/dev\/null)/;
|
|
27
|
+
const DEL_HEADER_RE = /^--- (a\/|\/dev\/null)/;
|
|
28
|
+
|
|
29
|
+
/** Pure unified-diff stats: files, additions/deletions/net, tests touched. */
|
|
30
|
+
export function parseDiffStats(patch) {
|
|
31
|
+
const files = [];
|
|
32
|
+
let additions = 0;
|
|
33
|
+
let deletions = 0;
|
|
34
|
+
for (const line of String(patch || "").split("\n")) {
|
|
35
|
+
if (ADD_HEADER_RE.test(line)) {
|
|
36
|
+
if (line.startsWith("+++ b/")) files.push(line.slice(6).trim());
|
|
37
|
+
} else if (DEL_HEADER_RE.test(line)) {
|
|
38
|
+
// deletion-side header — never a counted line
|
|
39
|
+
} else if (line.startsWith("+")) additions++;
|
|
40
|
+
else if (line.startsWith("-")) deletions++;
|
|
41
|
+
}
|
|
42
|
+
const testsTouched = files.filter((f) => TESTS_RE.test(f)).length;
|
|
43
|
+
return { files, additions, deletions, net: additions - deletions, testsTouched };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function defaultMutate({ lane }) {
|
|
47
|
+
// Mutation runs IN the live worktree lane — codex's catch: guard the path
|
|
48
|
+
// explicitly so a gone/relative lane yields a DISTINCT note instead of
|
|
49
|
+
// silently degrading the ranking.
|
|
50
|
+
if (!lane || !path.isAbsolute(lane) || !fs.existsSync(lane)) {
|
|
51
|
+
return { score: null, note: "lane no longer exists — score after the fan-out, before cleaning lanes" };
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const res = await execFileAsync("kj", ["mutate", "--json"], { cwd: lane, timeout: MUTATE_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024 });
|
|
55
|
+
const parsed = JSON.parse(res.stdout);
|
|
56
|
+
return { score: parsed.score ?? null, killed: parsed.killed ?? null, survived: parsed.survived ?? null };
|
|
57
|
+
} catch {
|
|
58
|
+
return null; // kj unavailable / no mutants / timeout — honest n/a
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Sonar-per-lane needs the running-server collector; reserved as a future
|
|
63
|
+
// step (see card). Injectable so TOR-C or tests can supply real findings.
|
|
64
|
+
const defaultSonar = async () => null;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Score every lane of a tournament from its artifacts.
|
|
68
|
+
* @returns {Promise<{id: string, rows: Array<object>, ranking: string[], rule: string}>}
|
|
69
|
+
*/
|
|
70
|
+
export async function scoreTournament({ tournamentDir, deps = {} }) {
|
|
71
|
+
const { mutateFn = defaultMutate, sonarFn = defaultSonar } = deps;
|
|
72
|
+
const summary = JSON.parse(fs.readFileSync(path.join(tournamentDir, "summary.json"), "utf8"));
|
|
73
|
+
|
|
74
|
+
const rows = [];
|
|
75
|
+
for (const lane of summary.lanes) {
|
|
76
|
+
if (lane.status !== "completed") {
|
|
77
|
+
rows.push({ coder: lane.coder, finalist: false, eliminated_by: "failed", error: lane.error || null });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const laneDir = lane.dir || path.join(tournamentDir, lane.coder);
|
|
81
|
+
const meta = JSON.parse(fs.readFileSync(path.join(laneDir, "meta.json"), "utf8"));
|
|
82
|
+
const loc = parseDiffStats(fs.readFileSync(path.join(laneDir, "diff.patch"), "utf8"));
|
|
83
|
+
|
|
84
|
+
let mutation = { score: null, note: "not available" };
|
|
85
|
+
try {
|
|
86
|
+
const m = await mutateFn({ coder: lane.coder, lane: meta.lane, laneDir });
|
|
87
|
+
if (m && typeof m.score === "number") mutation = { ...m, note: null };
|
|
88
|
+
else if (m?.note) mutation = { score: null, note: m.note };
|
|
89
|
+
} catch { /* honest n/a — never a fake zero */ }
|
|
90
|
+
const sonar = await sonarFn({ coder: lane.coder, lane: meta.lane, files: loc.files }).catch(() => null);
|
|
91
|
+
|
|
92
|
+
const suiteOk = Boolean(meta.suite?.ok);
|
|
93
|
+
rows.push({
|
|
94
|
+
coder: lane.coder,
|
|
95
|
+
finalist: suiteOk,
|
|
96
|
+
eliminated_by: suiteOk ? null : "suite",
|
|
97
|
+
suite: meta.suite,
|
|
98
|
+
loc,
|
|
99
|
+
mutation,
|
|
100
|
+
sonar,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const anyMutation = rows.some((r) => typeof r.mutation?.score === "number");
|
|
105
|
+
const rule = anyMutation
|
|
106
|
+
? "finalistas = suite verde; orden: mutation desc SOLO entre carriles que la tienen (null jamás penaliza — codex's catch), luego LOC neto asc"
|
|
107
|
+
: "finalistas = suite verde; orden: LOC neto asc (mutation no disponible)";
|
|
108
|
+
|
|
109
|
+
const ranking = rows
|
|
110
|
+
.filter((r) => r.finalist)
|
|
111
|
+
.sort((a, b) => {
|
|
112
|
+
const ma = a.mutation?.score;
|
|
113
|
+
const mb = b.mutation?.score;
|
|
114
|
+
// Mutation only compares when BOTH lanes have a real score — a null
|
|
115
|
+
// (tool unavailable) must stay a note, never become a hidden penalty.
|
|
116
|
+
if (typeof ma === "number" && typeof mb === "number" && mb !== ma) return mb - ma;
|
|
117
|
+
return a.loc.net - b.loc.net;
|
|
118
|
+
})
|
|
119
|
+
.map((r) => r.coder);
|
|
120
|
+
|
|
121
|
+
const board = { id: summary.id, task: summary.task, rule, ranking, rows, scored_at: new Date().toISOString() };
|
|
122
|
+
fs.writeFileSync(path.join(tournamentDir, "scoreboard.json"), JSON.stringify(board, null, 2));
|
|
123
|
+
return board;
|
|
124
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracker bootstrap — registers the configured task-tracker adapter into
|
|
3
|
+
* the orchestrator's integrations registry at runtime.
|
|
4
|
+
*
|
|
5
|
+
* This module exists so that `src/orchestrator/` never imports
|
|
6
|
+
* `src/planning-game/` (or any other tracker) directly — the architecture
|
|
7
|
+
* invariant `tests/architecture/tracker-coupling.test.js` enforces that.
|
|
8
|
+
* `runFlow` calls `ensureTrackerRegistered(config)` from here; this
|
|
9
|
+
* module owns the conditional import of each adapter.
|
|
10
|
+
*
|
|
11
|
+
* Adding a new tracker:
|
|
12
|
+
* 1. Write `src/adapters/<name>/adapter.js` with the hook surface
|
|
13
|
+
* documented in `src/orchestrator/integrations.js`.
|
|
14
|
+
* 2. Add a branch below that imports and registers it when the relevant
|
|
15
|
+
* config flag is true.
|
|
16
|
+
*
|
|
17
|
+
* The function is idempotent: once registered, subsequent calls are
|
|
18
|
+
* no-ops (the registry already has an entry for the slot).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { getIntegration, registerIntegration } from "./orchestrator/integrations.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Ensure the tracker adapter configured by `config` is registered under
|
|
25
|
+
* the `"tracker"` slot. Safe to call on every `runFlow` invocation.
|
|
26
|
+
*
|
|
27
|
+
* @param {object|null} config
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
*/
|
|
30
|
+
export async function ensureTrackerRegistered(config) {
|
|
31
|
+
if (getIntegration("tracker")) return; // Already registered.
|
|
32
|
+
|
|
33
|
+
if (config?.planning_game?.enabled) {
|
|
34
|
+
try {
|
|
35
|
+
const { planningGameAdapter } = await import("./planning-game/pipeline-adapter.js");
|
|
36
|
+
registerIntegration("tracker", planningGameAdapter);
|
|
37
|
+
} catch { /* registration failed — non-blocking, adapter stays absent */ }
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// No tracker enabled — the orchestrator's `getIntegration("tracker")`
|
|
42
|
+
// calls will return undefined and every hook becomes an optional-chain
|
|
43
|
+
// no-op. That's the intended behavior for "tracker disabled" runs.
|
|
44
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent result / response typedefs. Every provider agent (claude, codex,
|
|
3
|
+
* gemini, opencode, aider) returns a shape that's a superset of AgentResult.
|
|
4
|
+
*
|
|
5
|
+
* AgentResponse<T> is the generic wrapper used when a caller has parsed
|
|
6
|
+
* the raw output into a structured payload of type T.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Raw agent result as returned by agent.runTask() / agent.reviewTask().
|
|
11
|
+
*
|
|
12
|
+
* @typedef {Object} AgentResult
|
|
13
|
+
* @property {boolean} ok - whether the call succeeded
|
|
14
|
+
* @property {string} [output] - raw stdout / response text
|
|
15
|
+
* @property {string} [summary] - short human summary
|
|
16
|
+
* @property {Object} [result] - structured result (stage-specific)
|
|
17
|
+
* @property {string} [error]
|
|
18
|
+
* @property {string} [stderr]
|
|
19
|
+
* @property {string} [stdout]
|
|
20
|
+
* @property {number} [exitCode]
|
|
21
|
+
* @property {AgentUsage} [usage]
|
|
22
|
+
* @property {string} [provider]
|
|
23
|
+
* @property {string} [model]
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Token/cost reporting shape. Fields optional because not all providers
|
|
28
|
+
* report all metrics.
|
|
29
|
+
*
|
|
30
|
+
* @typedef {Object} AgentUsage
|
|
31
|
+
* @property {number} [input_tokens]
|
|
32
|
+
* @property {number} [output_tokens]
|
|
33
|
+
* @property {number} [cached_tokens]
|
|
34
|
+
* @property {number} [total_tokens]
|
|
35
|
+
* @property {number} [cost_usd]
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generic agent response — AgentResult whose `result` field is typed.
|
|
40
|
+
*
|
|
41
|
+
* Example:
|
|
42
|
+
* /** @type {import("../types/agent.js").AgentResponse<import("./review-result.js").ReviewResult>} *\/
|
|
43
|
+
*
|
|
44
|
+
* @template T
|
|
45
|
+
* @typedef {Object} AgentResponse
|
|
46
|
+
* @property {boolean} ok
|
|
47
|
+
* @property {T} [result]
|
|
48
|
+
* @property {string} [output]
|
|
49
|
+
* @property {string} [summary]
|
|
50
|
+
* @property {string} [error]
|
|
51
|
+
* @property {AgentUsage} [usage]
|
|
52
|
+
* @property {string} [provider]
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
export {};
|