@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,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HU Auto-Generator — converts triage subtasks (+ researcher/architect context)
|
|
3
|
+
* into a certified HU batch ready for hu-sub-pipeline execution.
|
|
4
|
+
*
|
|
5
|
+
* Input: original task, triage subtasks, detected stack, researcher/architect context.
|
|
6
|
+
* Output: HU batch with setup HU (when needed), task HUs with per-HU task_type,
|
|
7
|
+
* and a dependency graph (setup blocks everything; remaining linear by default).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Derive a human-readable project name from a task prompt.
|
|
12
|
+
* Strips common action verbs + stopwords, takes up to 6 meaningful words,
|
|
13
|
+
* and title-cases the result. Max 60 chars.
|
|
14
|
+
*/
|
|
15
|
+
export function deriveProjectName(originalTask) {
|
|
16
|
+
if (!originalTask || typeof originalTask !== "string") return "Untitled Project";
|
|
17
|
+
const STOPWORDS = new Set([
|
|
18
|
+
"a", "an", "the", "and", "or", "with", "for", "to", "of", "in", "on",
|
|
19
|
+
"is", "it", "its", "this", "that", "these", "those", "be", "been", "being",
|
|
20
|
+
"build", "create", "implement", "make", "develop", "add", "set", "up",
|
|
21
|
+
"setup", "write", "code", "new", "complete", "from", "scratch",
|
|
22
|
+
"application", "app", "tool", "system", "project", "using", "use",
|
|
23
|
+
"full", "full-stack", "fullstack", "stack", "based", "simple", "basic"
|
|
24
|
+
]);
|
|
25
|
+
const words = originalTask
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.replaceAll(/[^\p{L}\p{N}\s-]/gu, " ")
|
|
28
|
+
.split(/\s+/)
|
|
29
|
+
.filter(w => w && !STOPWORDS.has(w));
|
|
30
|
+
const meaningful = words.slice(0, 6);
|
|
31
|
+
if (meaningful.length === 0) {
|
|
32
|
+
return originalTask.slice(0, 60).trim() || "Untitled Project";
|
|
33
|
+
}
|
|
34
|
+
const titled = meaningful
|
|
35
|
+
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
|
|
36
|
+
.join(" ");
|
|
37
|
+
return titled.length > 60 ? titled.slice(0, 57) + "..." : titled;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Classify a subtask into a Karajan task_type.
|
|
42
|
+
* Maps free-text subtask descriptions to {infra|sw|add-tests|doc|refactor|nocode}.
|
|
43
|
+
*/
|
|
44
|
+
export function classifyTaskType(text) {
|
|
45
|
+
if (!text || typeof text !== "string") return "sw";
|
|
46
|
+
const t = text.toLowerCase();
|
|
47
|
+
// Order matters: no-code beats infra (Zapier/Notion setups are no-code, not infra)
|
|
48
|
+
if (/\b(no-code|nocode|zapier|make\.com|airtable|notion)\b/.test(t)) return "nocode";
|
|
49
|
+
if (/\b(setup|install|init(?:ialize|iate)?|configure|scaffold|bootstrap)\b/.test(t)) return "infra";
|
|
50
|
+
if (/\b(docker|ci\/cd|pipeline|deploy|workflow\.yml|github actions?)\b/.test(t)) return "infra";
|
|
51
|
+
if (/\b(tests?|coverage|spec|vitest|jest|mocha|playwright)\b/.test(t) && !/\b(component|feature|endpoint)\b/.test(t)) return "add-tests";
|
|
52
|
+
if (/\b(readme|docs?|documentation|guide|tutorial)\b/.test(t)) return "doc";
|
|
53
|
+
if (/\b(refactor|cleanup|reorganiz|restructure|extract)\b/.test(t)) return "refactor";
|
|
54
|
+
return "sw";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Decide whether a setup HU is needed.
|
|
59
|
+
* Needed when: project is new OR stack hints suggest new dependencies.
|
|
60
|
+
*/
|
|
61
|
+
export function needsSetupHu({ isNewProject = false, stackHints = [], subtasks = [] }) {
|
|
62
|
+
if (isNewProject) return true;
|
|
63
|
+
if (stackHints.length > 0) return true;
|
|
64
|
+
// Subtasks mentioning a framework/tool suggest fresh setup
|
|
65
|
+
const setupKeywords = /\b(npm init|package\.json|workspace|monorepo|vite|vitest|express|astro|next\.js|nestjs)\b/i;
|
|
66
|
+
return subtasks.some(s => setupKeywords.test(s));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Stack-hint keyword sets. Used by filterConflictingHints (drop hints
|
|
70
|
+
// from other ecosystems once one is detected) and by
|
|
71
|
+
// resolveLanguageFromHints (pick the canonical language for setup +
|
|
72
|
+
// acceptance_tests templates).
|
|
73
|
+
const HINT_NODE = new Set(["express", "vite", "vitest", "jest", "next", "astro", "react", "vue", "svelte", "nestjs", "monorepo", "workspaces"]);
|
|
74
|
+
const HINT_PYTHON = new Set(["pytest", "flask", "fastapi", "django", "numpy", "pandas"]);
|
|
75
|
+
const HINT_GO = new Set(["gin", "fiber", "go"]);
|
|
76
|
+
const HINT_RUST = new Set(["cargo", "rust"]);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Drop hints from OTHER ecosystems when one is clearly the project's.
|
|
80
|
+
* Symmetric: previously only node-vs-go was filtered, so a Python
|
|
81
|
+
* project that also had "vitest" in a stale gitignore would still
|
|
82
|
+
* receive vitest in its setup HU.
|
|
83
|
+
*/
|
|
84
|
+
function filterConflictingHints(hints) {
|
|
85
|
+
if (!hints || hints.length === 0) return hints;
|
|
86
|
+
const setForEachLang = [
|
|
87
|
+
["python", HINT_PYTHON],
|
|
88
|
+
["go", HINT_GO],
|
|
89
|
+
["rust", HINT_RUST],
|
|
90
|
+
["node", HINT_NODE],
|
|
91
|
+
];
|
|
92
|
+
const present = setForEachLang.filter(([, set]) => hints.some((h) => set.has(h)));
|
|
93
|
+
if (present.length <= 1) return hints;
|
|
94
|
+
// First ecosystem found in the original hints order wins. We keep
|
|
95
|
+
// ambiguous keywords (those not in any set) and the winner's own
|
|
96
|
+
// keywords; we drop the explicit losers from competing ecosystems.
|
|
97
|
+
const winnerSet = present[0][1];
|
|
98
|
+
const losers = present.slice(1).flatMap(([, s]) => [...s]);
|
|
99
|
+
return hints.filter((h) => winnerSet.has(h) || !losers.includes(h));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Pick the canonical language for setup + acceptance_test templates
|
|
104
|
+
* based on the (already filtered) stack hints. Falls back to
|
|
105
|
+
* javascript so existing Node-centric runs keep their previous shape.
|
|
106
|
+
* @param {string[]} hints
|
|
107
|
+
* @returns {"python"|"go"|"rust"|"javascript"}
|
|
108
|
+
*/
|
|
109
|
+
function resolveLanguageFromHints(hints) {
|
|
110
|
+
if (!hints || hints.length === 0) return "javascript";
|
|
111
|
+
if (hints.some((h) => HINT_PYTHON.has(h))) return "python";
|
|
112
|
+
if (hints.some((h) => HINT_GO.has(h))) return "go";
|
|
113
|
+
if (hints.some((h) => HINT_RUST.has(h))) return "rust";
|
|
114
|
+
return "javascript";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// HU templates per language. The JS template is the legacy default;
|
|
118
|
+
// the others were missing — every autogenerated HU got vitest /
|
|
119
|
+
// npm-install hardcoded acceptance_tests regardless of stack.
|
|
120
|
+
const HU_TEMPLATES = {
|
|
121
|
+
javascript: {
|
|
122
|
+
pkgManager: "npm",
|
|
123
|
+
setupBullets: [
|
|
124
|
+
"- Create package.json (with workspaces if monorepo detected from stack hints)",
|
|
125
|
+
"- Install all runtime + dev dependencies listed in stack hints",
|
|
126
|
+
"- Install test framework WITH coverage reporter (e.g. vitest + @vitest/coverage-v8)",
|
|
127
|
+
"- Configure vitest.config.js with coverage.enabled = true",
|
|
128
|
+
"- Create .env.example with placeholder variables",
|
|
129
|
+
],
|
|
130
|
+
setupCriteria: [
|
|
131
|
+
"npm install succeeds without errors",
|
|
132
|
+
"npm test runs without error",
|
|
133
|
+
"npm run test:coverage runs without error",
|
|
134
|
+
".env.example exists",
|
|
135
|
+
],
|
|
136
|
+
setupTests: [
|
|
137
|
+
"npm install --ignore-scripts 2>&1 && echo PASS || echo FAIL",
|
|
138
|
+
"npx vitest run 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
139
|
+
"npx vitest run --coverage 2>&1 | grep -q 'All files\\|% Stmts' && echo PASS || echo FAIL",
|
|
140
|
+
"test -f .env.example && echo PASS || echo FAIL",
|
|
141
|
+
],
|
|
142
|
+
taskTests: [
|
|
143
|
+
"npx vitest run 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
144
|
+
"npx vitest run --coverage 2>&1 | grep -q 'All files\\|% Stmts' && echo PASS || echo FAIL",
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
python: {
|
|
148
|
+
pkgManager: "pip",
|
|
149
|
+
setupBullets: [
|
|
150
|
+
"- Create pyproject.toml (preferred) or requirements.txt",
|
|
151
|
+
"- Create a virtual env: python -m venv .venv",
|
|
152
|
+
"- Install runtime + dev dependencies (pip install -e . or pip install -r requirements.txt)",
|
|
153
|
+
"- Install pytest with coverage (pip install pytest pytest-cov)",
|
|
154
|
+
"- Create .env.example with placeholder variables",
|
|
155
|
+
],
|
|
156
|
+
setupCriteria: [
|
|
157
|
+
"Project metadata file exists (pyproject.toml or requirements.txt)",
|
|
158
|
+
"pytest runs without error",
|
|
159
|
+
"pytest --cov reports a total",
|
|
160
|
+
".env.example exists",
|
|
161
|
+
],
|
|
162
|
+
setupTests: [
|
|
163
|
+
"(test -f pyproject.toml || test -f requirements.txt) && echo PASS || echo FAIL",
|
|
164
|
+
"python -m pytest 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
165
|
+
"python -m pytest --cov 2>&1 | grep -q 'TOTAL\\|coverage' && echo PASS || echo FAIL",
|
|
166
|
+
"test -f .env.example && echo PASS || echo FAIL",
|
|
167
|
+
],
|
|
168
|
+
taskTests: [
|
|
169
|
+
"python -m pytest 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
170
|
+
"python -m pytest --cov 2>&1 | grep -q 'TOTAL\\|coverage' && echo PASS || echo FAIL",
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
go: {
|
|
174
|
+
pkgManager: "go",
|
|
175
|
+
setupBullets: [
|
|
176
|
+
"- Create go.mod with `go mod init <module>`",
|
|
177
|
+
"- Install dependencies with `go get` per import",
|
|
178
|
+
"- Create .env.example with placeholder variables",
|
|
179
|
+
],
|
|
180
|
+
setupCriteria: [
|
|
181
|
+
"go.mod exists",
|
|
182
|
+
"go test ./... runs without error",
|
|
183
|
+
"go test -cover reports coverage",
|
|
184
|
+
".env.example exists",
|
|
185
|
+
],
|
|
186
|
+
setupTests: [
|
|
187
|
+
"test -f go.mod && echo PASS || echo FAIL",
|
|
188
|
+
"go test ./... 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
189
|
+
"go test -cover ./... 2>&1 | grep -q 'coverage:' && echo PASS || echo FAIL",
|
|
190
|
+
"test -f .env.example && echo PASS || echo FAIL",
|
|
191
|
+
],
|
|
192
|
+
taskTests: [
|
|
193
|
+
"go test ./... 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
rust: {
|
|
197
|
+
pkgManager: "cargo",
|
|
198
|
+
setupBullets: [
|
|
199
|
+
"- Initialise the crate with `cargo init`",
|
|
200
|
+
"- Add dependencies with `cargo add`",
|
|
201
|
+
"- Create .env.example with placeholder variables",
|
|
202
|
+
],
|
|
203
|
+
setupCriteria: [
|
|
204
|
+
"Cargo.toml exists",
|
|
205
|
+
"cargo test runs without error",
|
|
206
|
+
".env.example exists",
|
|
207
|
+
],
|
|
208
|
+
setupTests: [
|
|
209
|
+
"test -f Cargo.toml && echo PASS || echo FAIL",
|
|
210
|
+
"cargo test 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
211
|
+
"test -f .env.example && echo PASS || echo FAIL",
|
|
212
|
+
],
|
|
213
|
+
taskTests: [
|
|
214
|
+
"cargo test 2>&1; test $? -eq 0 && echo PASS || echo FAIL",
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
function templateFor(language) {
|
|
220
|
+
return HU_TEMPLATES[language] || HU_TEMPLATES.javascript;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Build a MINIMAL setup HU — project structure + deps only.
|
|
225
|
+
* NEVER includes the full original task. The coder must only do setup.
|
|
226
|
+
*/
|
|
227
|
+
function buildSetupHu({ stackHints, language = "javascript" }) {
|
|
228
|
+
const tpl = templateFor(language);
|
|
229
|
+
const deps = stackHints.length > 0
|
|
230
|
+
? stackHints.map(h => `- ${h}`).join("\n")
|
|
231
|
+
: "- (auto-detect from subsequent HUs)";
|
|
232
|
+
const certifiedText = [
|
|
233
|
+
`**Setup: initialise the ${language} project + install dependencies (package manager: ${tpl.pkgManager}).**`,
|
|
234
|
+
"",
|
|
235
|
+
"SCOPE (do ONLY this, nothing else):",
|
|
236
|
+
...tpl.setupBullets,
|
|
237
|
+
"- Verify by running each acceptance_test command below",
|
|
238
|
+
"",
|
|
239
|
+
"DO NOT implement any business logic, API routes, components, or features.",
|
|
240
|
+
"This HU is ONLY project scaffolding.",
|
|
241
|
+
"",
|
|
242
|
+
"Stack hints:",
|
|
243
|
+
deps,
|
|
244
|
+
].join("\n");
|
|
245
|
+
return {
|
|
246
|
+
id: "HU-01",
|
|
247
|
+
title: `Setup: ${language} project structure + dependencies`,
|
|
248
|
+
task_type: "infra",
|
|
249
|
+
status: "certified",
|
|
250
|
+
blocked_by: [],
|
|
251
|
+
certified: { text: certifiedText },
|
|
252
|
+
acceptance_criteria: tpl.setupCriteria,
|
|
253
|
+
acceptance_tests: tpl.setupTests,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Build a MINIMAL task HU — one specific, focused piece of work.
|
|
259
|
+
* Includes a short goal reference (max 80 chars) NOT the full task.
|
|
260
|
+
*/
|
|
261
|
+
function buildTaskHu({ id, subtask, projectName, blockedBy, language = "javascript" }) {
|
|
262
|
+
const taskType = classifyTaskType(subtask);
|
|
263
|
+
const tpl = templateFor(language);
|
|
264
|
+
const certifiedText = [
|
|
265
|
+
`**${subtask}**`,
|
|
266
|
+
"",
|
|
267
|
+
`Project: ${projectName}`,
|
|
268
|
+
"",
|
|
269
|
+
"SCOPE (do ONLY this, nothing else):",
|
|
270
|
+
`- Implement: ${subtask}`,
|
|
271
|
+
"- Add unit tests for the new code",
|
|
272
|
+
"- Run ALL acceptance_tests listed below and ensure they pass",
|
|
273
|
+
"- Do NOT touch code outside this subtask's scope",
|
|
274
|
+
"- Target: <200 lines changed (like an atomic PR)",
|
|
275
|
+
].join("\n");
|
|
276
|
+
return {
|
|
277
|
+
id,
|
|
278
|
+
title: subtask.length > 80 ? subtask.slice(0, 77) + "..." : subtask,
|
|
279
|
+
task_type: taskType,
|
|
280
|
+
status: "certified",
|
|
281
|
+
blocked_by: blockedBy,
|
|
282
|
+
certified: { text: certifiedText },
|
|
283
|
+
acceptance_criteria: [
|
|
284
|
+
`${subtask} is implemented and working`,
|
|
285
|
+
"Unit tests cover the new code",
|
|
286
|
+
"All acceptance_tests pass",
|
|
287
|
+
],
|
|
288
|
+
acceptance_tests: tpl.taskTests,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Main entry point: generate a certified HU batch from triage output.
|
|
294
|
+
*
|
|
295
|
+
* @param {object} input
|
|
296
|
+
* @param {string} input.originalTask - the user's raw task
|
|
297
|
+
* @param {string[]} input.subtasks - triage.subtasks array
|
|
298
|
+
* @param {string[]} [input.stackHints] - detected stack keywords (e.g. ["nodejs", "vitest"])
|
|
299
|
+
* @param {boolean} [input.isNewProject] - true when projectDir is empty/fresh
|
|
300
|
+
* @param {string} [input.researcherContext] - researcher output (optional, used for better HU text)
|
|
301
|
+
* @param {string} [input.architectContext] - architect output (optional, used for dep graph)
|
|
302
|
+
* @returns {{ stories: object[], total: number, certified: number, generated: true }}
|
|
303
|
+
*/
|
|
304
|
+
export function generateHuBatch({
|
|
305
|
+
originalTask,
|
|
306
|
+
subtasks = [],
|
|
307
|
+
stackHints = [],
|
|
308
|
+
isNewProject = false,
|
|
309
|
+
researcherContext = null,
|
|
310
|
+
architectContext = null,
|
|
311
|
+
language = null,
|
|
312
|
+
}) {
|
|
313
|
+
if (!originalTask || typeof originalTask !== "string") {
|
|
314
|
+
throw new Error("generateHuBatch: originalTask is required");
|
|
315
|
+
}
|
|
316
|
+
if (!Array.isArray(subtasks) || subtasks.length === 0) {
|
|
317
|
+
throw new Error("generateHuBatch: subtasks array is required");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const stories = [];
|
|
321
|
+
const filteredHints = filterConflictingHints(stackHints);
|
|
322
|
+
const needsSetup = needsSetupHu({ isNewProject, stackHints: filteredHints, subtasks });
|
|
323
|
+
// Caller may pass a language explicitly (when it has a real
|
|
324
|
+
// detectProjectStack result from the filesystem); otherwise fall
|
|
325
|
+
// back to inferring from the hint keywords. Default 'javascript'
|
|
326
|
+
// matches the previous behaviour for Node-centric runs.
|
|
327
|
+
const resolvedLanguage = language || resolveLanguageFromHints(filteredHints);
|
|
328
|
+
let nextId = 1;
|
|
329
|
+
|
|
330
|
+
const projectName = deriveProjectName(originalTask);
|
|
331
|
+
|
|
332
|
+
if (needsSetup) {
|
|
333
|
+
stories.push(buildSetupHu({ stackHints: filteredHints, language: resolvedLanguage }));
|
|
334
|
+
nextId = 2;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Task HUs: linear dependency chain after setup (conservative default).
|
|
338
|
+
const setupId = needsSetup ? "HU-01" : null;
|
|
339
|
+
let previousId = setupId;
|
|
340
|
+
for (const subtask of subtasks) {
|
|
341
|
+
const id = `HU-${String(nextId).padStart(2, "0")}`;
|
|
342
|
+
const blockedBy = [];
|
|
343
|
+
if (setupId) blockedBy.push(setupId);
|
|
344
|
+
if (previousId && previousId !== setupId) blockedBy.push(previousId);
|
|
345
|
+
stories.push(buildTaskHu({ id, subtask, projectName, blockedBy, language: resolvedLanguage }));
|
|
346
|
+
previousId = id;
|
|
347
|
+
nextId += 1;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
stories,
|
|
352
|
+
total: stories.length,
|
|
353
|
+
certified: stories.length,
|
|
354
|
+
projectName: deriveProjectName(originalTask),
|
|
355
|
+
generated: true,
|
|
356
|
+
source: { triage_subtasks: subtasks.length, researcher: Boolean(researcherContext), architect: Boolean(architectContext) }
|
|
357
|
+
};
|
|
358
|
+
}
|
package/src/hu/graph.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topological sort of HU stories respecting blocked_by dependencies.
|
|
3
|
+
* Returns ordered array of story IDs (dependencies first).
|
|
4
|
+
* Throws if circular dependency detected.
|
|
5
|
+
* @param {Array<{id: string, blocked_by?: string[]}>} stories
|
|
6
|
+
* @returns {string[]} Sorted story IDs.
|
|
7
|
+
*/
|
|
8
|
+
export function topologicalSort(stories) {
|
|
9
|
+
const ids = new Set(stories.map(s => s.id));
|
|
10
|
+
const adj = new Map(); // id -> [dependents]
|
|
11
|
+
const inDegree = new Map();
|
|
12
|
+
|
|
13
|
+
for (const s of stories) {
|
|
14
|
+
adj.set(s.id, []);
|
|
15
|
+
inDegree.set(s.id, 0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for (const s of stories) {
|
|
19
|
+
for (const dep of (s.blocked_by || [])) {
|
|
20
|
+
if (!ids.has(dep)) throw new Error(`Dependency ${dep} not found in batch`);
|
|
21
|
+
adj.get(dep).push(s.id);
|
|
22
|
+
inDegree.set(s.id, (inDegree.get(s.id) || 0) + 1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const queue = [];
|
|
27
|
+
for (const [id, degree] of inDegree) {
|
|
28
|
+
if (degree === 0) queue.push(id);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const sorted = [];
|
|
32
|
+
while (queue.length > 0) {
|
|
33
|
+
const id = queue.shift();
|
|
34
|
+
sorted.push(id);
|
|
35
|
+
for (const dependent of adj.get(id)) {
|
|
36
|
+
inDegree.set(dependent, inDegree.get(dependent) - 1);
|
|
37
|
+
if (inDegree.get(dependent) === 0) queue.push(dependent);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (sorted.length !== stories.length) {
|
|
42
|
+
throw new Error("Circular dependency detected in HU batch");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return sorted;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if a story is ready to execute (all its dependencies are done).
|
|
50
|
+
* @param {{blocked_by?: string[]}} story
|
|
51
|
+
* @param {{stories: Array<{id: string, status: string}>}} batch
|
|
52
|
+
* @returns {boolean}
|
|
53
|
+
*/
|
|
54
|
+
export function isStoryReady(story, batch) {
|
|
55
|
+
if (!story.blocked_by || story.blocked_by.length === 0) return true;
|
|
56
|
+
return story.blocked_by.every(depId => {
|
|
57
|
+
const dep = batch.stories.find(s => s.id === depId);
|
|
58
|
+
return dep && dep.status === "done";
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get next stories ready for execution (certified + all deps done).
|
|
64
|
+
* @param {{stories: Array<{id: string, status: string, blocked_by?: string[]}>}} batch
|
|
65
|
+
* @returns {Array<object>} Stories that are certified and whose deps are all done.
|
|
66
|
+
*/
|
|
67
|
+
export function getNextReadyStories(batch) {
|
|
68
|
+
return batch.stories.filter(s =>
|
|
69
|
+
s.status === "certified" && isStoryReady(s, batch)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy HU Planner — refines HUs one at a time using context from completed HUs.
|
|
3
|
+
*
|
|
4
|
+
* Instead of fully planning all HUs upfront, only the first HU is decomposed
|
|
5
|
+
* with full acceptance criteria. Subsequent HUs are refined lazily before
|
|
6
|
+
* execution, incorporating learnings from previously completed HUs.
|
|
7
|
+
*/
|
|
8
|
+
import { createAgent } from "../agents/index.js";
|
|
9
|
+
import { extractFirstJson } from "../utils/json-extract.js";
|
|
10
|
+
import { withBrainRecovery } from "../brain/with-brain-recovery.js";
|
|
11
|
+
|
|
12
|
+
const SUBAGENT_PREAMBLE = [
|
|
13
|
+
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
14
|
+
"Do NOT ask about using Karajan, do NOT mention Karajan, do NOT suggest orchestration.",
|
|
15
|
+
"Do NOT use any MCP tools. Focus only on refining the user story."
|
|
16
|
+
].join(" ");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Build a prompt asking the AI to refine an HU based on context from completed HUs.
|
|
20
|
+
* @param {object} hu - The HU to refine (with at least id, original.text or certified.text).
|
|
21
|
+
* @param {Array<object>} completedHus - Array of completed HU results with summaries.
|
|
22
|
+
* @returns {string} The assembled refinement prompt.
|
|
23
|
+
*/
|
|
24
|
+
export function buildRefinementPrompt(hu, completedHus) {
|
|
25
|
+
const sections = [SUBAGENT_PREAMBLE];
|
|
26
|
+
|
|
27
|
+
sections.push("## HU Refinement");
|
|
28
|
+
sections.push(
|
|
29
|
+
"You are a senior product owner. Refine the following user story by adding or updating its acceptance criteria.",
|
|
30
|
+
"Use the context from previously completed HUs to make the criteria more precise and avoid redundant work."
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (completedHus.length > 0) {
|
|
34
|
+
sections.push("## Previously Completed HUs");
|
|
35
|
+
for (const completed of completedHus) {
|
|
36
|
+
const title = completed.certified?.title || completed.id;
|
|
37
|
+
const summary = completed.resultSummary || completed.certified?.text || completed.original?.text || "No summary available";
|
|
38
|
+
sections.push(`### ${completed.id} — ${title}\nResult: ${summary}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const huText = hu.certified?.text || hu.original?.text || `Implement HU ${hu.id}`;
|
|
43
|
+
sections.push(`## HU to Refine\n### ${hu.id}\n${huText}`);
|
|
44
|
+
|
|
45
|
+
sections.push(
|
|
46
|
+
"Return a single valid JSON object and nothing else.",
|
|
47
|
+
`JSON schema: {"id":string,"title":string,"text":string,"acceptanceCriteria":[string]}`,
|
|
48
|
+
"Rules:",
|
|
49
|
+
"- Keep the same HU id",
|
|
50
|
+
"- Refine the description to be more specific based on what was learned",
|
|
51
|
+
"- Add concrete, testable acceptance criteria",
|
|
52
|
+
"- Avoid repeating work already done in completed HUs",
|
|
53
|
+
"- The text field should be the full story description ready for implementation"
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return sections.join("\n\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Refine an HU using AI, incorporating context from completed HUs.
|
|
61
|
+
* @param {object} hu - The HU story object to refine.
|
|
62
|
+
* @param {Array<object>} completedHus - Completed HU stories with results.
|
|
63
|
+
* @param {object} config - Pipeline configuration.
|
|
64
|
+
* @param {object} logger - Logger instance.
|
|
65
|
+
* @returns {Promise<object>} Updated HU object with refined description and AC.
|
|
66
|
+
*/
|
|
67
|
+
export async function refineHuWithContext(hu, completedHus, config, logger) {
|
|
68
|
+
const provider = config?.roles?.hu_reviewer?.provider || config?.roles?.coder?.provider || "claude";
|
|
69
|
+
const prompt = buildRefinementPrompt(hu, completedHus);
|
|
70
|
+
|
|
71
|
+
logger.info(`Lazy planner: refining HU ${hu.id} with context from ${completedHus.length} completed HU(s)`);
|
|
72
|
+
|
|
73
|
+
const agent = createAgent(provider, config, logger);
|
|
74
|
+
let result;
|
|
75
|
+
try {
|
|
76
|
+
// KJC-TSK-0413 step C
|
|
77
|
+
result = await withBrainRecovery({
|
|
78
|
+
agent, taskArgs: { prompt, role: "hu-reviewer" },
|
|
79
|
+
role: "lazy-planner", provider, logger,
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
logger.warn(`Lazy planner: refinement failed for HU ${hu.id}: ${err.message}`);
|
|
83
|
+
return hu;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
logger.warn(`Lazy planner: refinement returned not-ok for HU ${hu.id}`);
|
|
88
|
+
return hu;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const parsed = extractFirstJson(result.output);
|
|
92
|
+
if (!parsed || !parsed.text) {
|
|
93
|
+
logger.warn(`Lazy planner: could not parse refinement output for HU ${hu.id}`);
|
|
94
|
+
return hu;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Update the HU with refined content
|
|
98
|
+
const refined = { ...hu };
|
|
99
|
+
refined.certified = {
|
|
100
|
+
...(hu.certified || {}),
|
|
101
|
+
text: parsed.text,
|
|
102
|
+
title: parsed.title || hu.certified?.title || hu.id,
|
|
103
|
+
acceptanceCriteria: parsed.acceptanceCriteria || []
|
|
104
|
+
};
|
|
105
|
+
refined.needsRefinement = false;
|
|
106
|
+
|
|
107
|
+
logger.info(`Lazy planner: HU ${hu.id} refined successfully`);
|
|
108
|
+
return refined;
|
|
109
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// KJC-TSK-0405: dado un HU con complexity score, recomienda coder_model y
|
|
2
|
+
// reviewer_model. El reviewer por defecto usa el provider alternativo al
|
|
3
|
+
// coder (cross-provider review) para que dos cabezas distintas miren el
|
|
4
|
+
// código y se detecten más patrones.
|
|
5
|
+
|
|
6
|
+
const LEVELS = ["trivial", "simple", "medium", "complex"];
|
|
7
|
+
|
|
8
|
+
// Mapping complexity score numérico → nivel categórico.
|
|
9
|
+
// 1 → trivial, 2 → simple, 3/4 → medium, 5+ → complex.
|
|
10
|
+
const SCORE_TO_LEVEL = {
|
|
11
|
+
1: "trivial",
|
|
12
|
+
2: "simple",
|
|
13
|
+
3: "medium",
|
|
14
|
+
4: "medium",
|
|
15
|
+
5: "complex",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Defaults por provider — alineados con utils/model-selector.js DEFAULTS.
|
|
19
|
+
// opencode: usa "coder" como alias razonable; el usuario suele definir
|
|
20
|
+
// gemma-local/coder, ollama/coder o similar en opencode.json. Override
|
|
21
|
+
// per-tier vía config.model_routing.by_provider.opencode si quieres
|
|
22
|
+
// rutear distinto por complexity (ej. fast para trivial, coder para
|
|
23
|
+
// complex). aider: null porque aider envuelve a otros providers — no
|
|
24
|
+
// tiene "modelos propios". Si el usuario lo elige, debe configurarlo
|
|
25
|
+
// explícito en config.model_routing.by_provider.aider o vía override
|
|
26
|
+
// del modal por HU.
|
|
27
|
+
const DEFAULT_TIERS = {
|
|
28
|
+
claude: { trivial: "haiku", simple: "haiku", medium: "sonnet", complex: "opus" },
|
|
29
|
+
codex: { trivial: "o4-mini", simple: "o4-mini", medium: "o4-mini", complex: "o3" },
|
|
30
|
+
gemini: { trivial: "gemini-2.0-flash", simple: "gemini-2.0-flash", medium: "gemini-2.5-pro", complex: "gemini-2.5-pro" },
|
|
31
|
+
opencode: { trivial: "coder", simple: "coder", medium: "coder", complex: "coder" },
|
|
32
|
+
aider: { trivial: null, simple: null, medium: null, complex: null },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Cross-provider reviewer default: para cada coder provider, qué provider
|
|
36
|
+
// usa el reviewer por defecto. Dos cabezas distintas miran el código.
|
|
37
|
+
// opencode → claude: pattern "local barato escribe + cloud revisa".
|
|
38
|
+
// aider → claude: aider suele correr en un model pequeño, claude verifica.
|
|
39
|
+
const CROSS_PROVIDER_REVIEWER = {
|
|
40
|
+
claude: "codex",
|
|
41
|
+
codex: "claude",
|
|
42
|
+
gemini: "claude",
|
|
43
|
+
opencode: "claude",
|
|
44
|
+
aider: "claude",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// KJC-TSK-0405 step 2: heurística para inferir complexity desde
|
|
48
|
+
// task_type cuando el planner no emite un score explícito. Permite
|
|
49
|
+
// que el model-router asigne modelos razonables sin un triage explícito.
|
|
50
|
+
const TASK_TYPE_COMPLEXITY = {
|
|
51
|
+
sw: "medium",
|
|
52
|
+
refactor: "medium",
|
|
53
|
+
"add-tests": "simple",
|
|
54
|
+
infra: "trivial",
|
|
55
|
+
doc: "trivial",
|
|
56
|
+
spike: "complex",
|
|
57
|
+
research: "complex",
|
|
58
|
+
audit: "complex",
|
|
59
|
+
analysis: "medium",
|
|
60
|
+
"no-code": "trivial",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export function complexityFromTaskType(taskType) {
|
|
64
|
+
return TASK_TYPE_COMPLEXITY[taskType] || "medium";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function complexityToLevel(complexity) {
|
|
68
|
+
if (typeof complexity === "string" && LEVELS.includes(complexity)) return complexity;
|
|
69
|
+
if (typeof complexity === "number" && SCORE_TO_LEVEL[complexity]) return SCORE_TO_LEVEL[complexity];
|
|
70
|
+
return "medium";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {object} args
|
|
75
|
+
* @param {string|number} args.complexity - "trivial" | "simple" | "medium" | "complex" | score 1-5
|
|
76
|
+
* @param {string} args.coderProvider - "claude" | "codex" | "gemini"
|
|
77
|
+
* @param {object} args.config - karajan config (lee model_routing si existe)
|
|
78
|
+
* @returns {{ coder_model: string|null, coder_provider: string, reviewer_model: string|null, reviewer_provider: string }}
|
|
79
|
+
*/
|
|
80
|
+
export function recommendModelsForHu({ complexity, coderProvider, config = {} }) {
|
|
81
|
+
const level = complexityToLevel(complexity);
|
|
82
|
+
const routing = config.model_routing || {};
|
|
83
|
+
const fixed = routing.fixed || {};
|
|
84
|
+
|
|
85
|
+
// Merge tiers: defaults + user overrides per provider.
|
|
86
|
+
const tiers = { ...DEFAULT_TIERS };
|
|
87
|
+
if (routing.by_provider) {
|
|
88
|
+
for (const [prov, levels] of Object.entries(routing.by_provider)) {
|
|
89
|
+
tiers[prov] = { ...(tiers[prov] || {}), ...levels };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const coderTier = tiers[coderProvider];
|
|
94
|
+
const coderAuto = coderTier ? (coderTier[level] || null) : null;
|
|
95
|
+
const coder_model = fixed.coder || coderAuto;
|
|
96
|
+
|
|
97
|
+
const reviewer_provider = CROSS_PROVIDER_REVIEWER[coderProvider] || "claude";
|
|
98
|
+
const reviewerTier = tiers[reviewer_provider];
|
|
99
|
+
const reviewerAuto = reviewerTier ? (reviewerTier[level] || null) : null;
|
|
100
|
+
const reviewer_model = fixed.reviewer || reviewerAuto;
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
coder_model,
|
|
104
|
+
coder_provider: coderProvider,
|
|
105
|
+
reviewer_model,
|
|
106
|
+
reviewer_provider,
|
|
107
|
+
};
|
|
108
|
+
}
|