karajan-code 4.70.3 → 5.0.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/README.md +2 -2
- package/package.json +6 -14
- package/packages/hu-board/package.json +1 -1
- package/packages/hu-board/public/app.js +4 -18
- package/packages/hu-board/public/index.html +5 -2
- package/packages/hu-board/public/styles.css +26 -0
- package/packages/hu-board/public/utils/api.js +0 -74
- package/packages/hu-board/public/utils/board-tour.js +62 -0
- package/packages/hu-board/public/utils/board-view.js +49 -144
- package/packages/hu-board/public/utils/command-launcher.js +8 -70
- package/packages/hu-board/public/utils/formatters.js +10 -0
- package/packages/hu-board/public/utils/governance-view.js +13 -1
- package/packages/hu-board/public/utils/hu-actions.js +17 -68
- package/packages/hu-board/public/utils/init-listeners.js +7 -8
- package/packages/hu-board/public/utils/log-panel.js +3 -16
- package/packages/hu-board/public/utils/maggle-mode.js +2 -12
- package/packages/hu-board/public/utils/modals.js +7 -0
- package/packages/hu-board/public/utils/project-picker-view.js +1 -1
- package/packages/hu-board/public/utils/server-push.js +3 -22
- package/packages/hu-board/public/utils/shared-board-notice.js +33 -0
- package/packages/hu-board/public/utils/story-detail-view.js +5 -19
- package/packages/hu-board/src/cleanup-zombies.js +0 -1
- package/packages/hu-board/src/command-runner.js +36 -25
- package/packages/hu-board/src/db-connection.js +282 -0
- package/packages/hu-board/src/db-paths.js +113 -0
- package/packages/hu-board/src/db-queries.js +188 -0
- package/packages/hu-board/src/db-tombstones.js +51 -0
- package/packages/hu-board/src/db.js +28 -619
- package/packages/hu-board/src/ephemeral-cleaner.js +2 -3
- package/packages/hu-board/src/hu-zombie-reaper.js +5 -1
- package/packages/hu-board/src/plan-mutations.js +3 -153
- package/packages/hu-board/src/plans-service.js +55 -0
- package/packages/hu-board/src/routes/api/commands.js +122 -0
- package/packages/hu-board/src/routes/api/plans.js +55 -0
- package/packages/hu-board/src/routes/api/projects.js +267 -0
- package/packages/hu-board/src/routes/api/prompts.js +135 -0
- package/packages/hu-board/src/routes/api/sessions.js +95 -0
- package/packages/hu-board/src/routes/api/stories.js +183 -0
- package/packages/hu-board/src/routes/api/system.js +241 -0
- package/packages/hu-board/src/routes/api/tombstones.js +38 -0
- package/packages/hu-board/src/routes/api.js +24 -1371
- package/packages/hu-board/src/routes/governance.js +23 -1
- package/packages/hu-board/src/routes/lanes.js +40 -0
- package/packages/hu-board/src/routes/rag.js +4 -3
- package/packages/hu-board/src/server.js +20 -34
- package/packages/hu-board/src/sync-files.js +318 -0
- package/packages/hu-board/src/sync-project.js +99 -0
- package/packages/hu-board/src/sync.js +22 -566
- package/packages/hu-board/src/zombie-reaper.js +1 -1
- package/scripts/dual-publish.mjs +19 -3
- package/scripts/postinstall.js +15 -2
- package/scripts/verify-pack-mcp.mjs +11 -7
- package/scripts/verify-pack.mjs +4 -4
- package/src/audit/audit-history.js +3 -2
- package/src/audit/dead-exports.js +68 -59
- package/src/audit/deterministic-summary.js +33 -13
- package/src/audit/npm-signatures.js +41 -0
- package/src/audit/sbom.js +35 -0
- package/src/checks/agent-token.js +112 -0
- package/src/checks/ai-surface.js +9 -7
- package/src/checks/config-files.js +8 -7
- package/src/checks/dir-setup.js +34 -1
- package/src/checks/native-build.js +21 -39
- package/src/checks/runner.js +128 -142
- package/src/cli/advanced-commands.js +6 -6
- package/src/cli/register-meta.js +42 -82
- package/src/cli/register-pipeline.js +8 -140
- package/src/cli/register-plan.js +9 -100
- package/src/cli/retired-commands.js +49 -0
- package/src/cli.js +18 -5
- package/src/commands/agent-run.js +40 -26
- package/src/commands/audit.js +127 -124
- package/src/commands/board.js +5 -9
- package/src/commands/check.js +29 -16
- package/src/commands/doctor.js +2 -0
- package/src/commands/env.js +176 -148
- package/src/commands/go.js +76 -55
- package/src/commands/harden.js +105 -86
- package/src/commands/hu-start.js +52 -0
- package/src/commands/hu.js +288 -221
- package/src/commands/identity.js +111 -78
- package/src/commands/init-atril.js +47 -0
- package/src/commands/init.js +11 -40
- package/src/commands/install-tools.js +70 -85
- package/src/commands/main-guard.js +78 -0
- package/src/commands/policy.js +226 -184
- package/src/commands/qmd.js +27 -21
- package/src/commands/rag.js +75 -48
- package/src/commands/review-gate.js +422 -339
- package/src/commands/start.js +4 -5
- package/src/commands/steward.js +96 -47
- package/src/commands/tournament.js +46 -37
- package/src/commands/worktree.js +94 -25
- package/src/config/loader.js +34 -17
- package/src/config/overrides.js +2 -1
- package/src/config/secrets.js +36 -0
- package/src/config.js +1 -0
- package/src/environment/adr.js +16 -2
- package/src/environment/board-access.js +11 -9
- package/src/git/karajan-label.js +20 -8
- package/src/guards/main-guard.js +54 -0
- package/src/harden/branch-protection.js +36 -3
- package/src/harden/hook-templates.js +16 -1
- package/src/harden/sentinel/posttooluse.mjs +18 -6
- package/src/harden/sentinel/pretooluse-sentinel.mjs +81 -35
- package/src/harden/sentinel/sentinel-lib.mjs +149 -23
- package/src/harden/sentinel/sentinel-shell.mjs +64 -0
- package/src/harden/sentinel/sessionstart.mjs +3 -2
- package/src/harden/sentinel/stop.mjs +5 -4
- package/src/harden/workflow-engine.js +12 -1
- package/src/harden/workflow-templates.js +1 -1
- package/src/hu/board-lookup.js +29 -0
- package/src/hu/gh-identity.js +23 -0
- package/src/hu/github-board.js +4 -2
- package/src/hu/lane-prune.js +15 -7
- package/src/hu/lane-setup.js +65 -0
- package/src/hu/lanes.js +66 -0
- package/src/hu/team-board-mirror.js +3 -2
- package/src/infrastructure/command-runner.js +1 -1
- package/src/infrastructure/file-system-service.js +1 -1
- package/src/mcp/handlers/direct-handlers.js +2 -292
- package/src/mcp/handlers/hu-handlers.js +44 -55
- package/src/mcp/handlers/management-handlers.js +2 -42
- package/src/mcp/server-handlers.js +16 -22
- package/src/mcp/tools.js +5 -200
- package/src/plan/lane-plans.js +54 -0
- package/src/plan/plan-store.js +7 -4
- package/src/policy/add.js +26 -12
- package/src/policy/adr-number-check.js +31 -0
- package/src/prompts/audit.js +299 -339
- package/src/prompts/card-context.js +10 -5
- package/src/prompts/reviewer.js +5 -2
- package/src/rag/auto-update.js +56 -43
- package/src/rag/bootstrap-index.js +28 -54
- package/src/rag/migrate.js +1 -1
- package/src/rag/onnx-fallback.js +2 -2
- package/src/rag/pid-lease.js +70 -0
- package/src/rag/project-store.js +2 -12
- package/src/review/card-first.js +57 -46
- package/src/review/dual-review.js +5 -4
- package/src/review/gate-gitignore.js +23 -4
- package/src/review/gate-hook.js +47 -0
- package/src/review/one-shot-review.js +51 -37
- package/src/review/publish-pr.js +18 -3
- package/src/review/repo-docs.js +73 -0
- package/src/review/repo-stack.js +59 -0
- package/src/review/reviewer-fallback.js +34 -3
- package/src/review/seal-commit.js +29 -0
- package/src/review/sonar-pregate.js +59 -44
- package/src/review/third-party-review.js +90 -16
- package/src/review/third-party-size.js +43 -0
- package/src/review/third-party-skills.js +54 -0
- package/src/review/verify-pr.js +2 -26
- package/src/roles/audit-role.js +106 -125
- package/src/skills/atril-skills.js +5 -4
- package/src/sonar/scanner.js +116 -101
- package/src/steward/invariants.js +5 -4
- package/src/steward/phantom-sweep.js +66 -0
- package/src/tournament/judge.js +60 -53
- package/src/utils/agent-home.js +33 -0
- package/src/utils/gh-account.js +37 -0
- package/src/utils/git.js +0 -13
- package/src/utils/home-migration.js +7 -1
- package/src/utils/main-checkout.js +53 -0
- package/src/utils/qmd-collection.js +3 -1
- package/src/utils/welcome.js +3 -3
- package/templates/{skills → atril/commands}/kj-architect.md +5 -0
- package/templates/{skills → atril/commands}/kj-audit.md +5 -0
- package/templates/{skills → atril/commands}/kj-board.md +5 -0
- package/templates/{skills → atril/commands}/kj-code.md +5 -0
- package/templates/{skills → atril/commands}/kj-csv-transform.md +5 -0
- package/templates/{skills → atril/commands}/kj-data-report.md +5 -0
- package/templates/{skills → atril/commands}/kj-discover.md +5 -0
- package/templates/{skills → atril/commands}/kj-rag-query.md +5 -0
- package/templates/{skills → atril/commands}/kj-review.md +5 -0
- package/templates/{skills → atril/commands}/kj-security.md +5 -0
- package/templates/{skills → atril/commands}/kj-sonar.md +5 -0
- package/templates/{skills → atril/commands}/kj-sql-analysis.md +5 -0
- package/templates/{skills → atril/commands}/kj-test.md +5 -0
- package/packages/hu-board/public/utils/run-launcher.js +0 -169
- package/packages/hu-board/src/run-tracker.js +0 -121
- package/src/activity-log.js +0 -59
- package/src/agents/host-agent.js +0 -38
- package/src/agents/model-registry.js +0 -142
- package/src/audit/plan-adherence.js +0 -224
- package/src/autonomy/arbiter-role.js +0 -71
- package/src/autonomy/arbiter.js +0 -22
- package/src/autonomy/decider.js +0 -18
- package/src/autonomy/decision-resolver.js +0 -58
- package/src/autonomy/outcome-report.js +0 -55
- package/src/autonomy/stage-ask.js +0 -30
- package/src/brain/decision-tracker.js +0 -125
- package/src/brain/decisor.js +0 -243
- package/src/brain/solomon-consult.js +0 -171
- package/src/brain/standby-scheduler.js +0 -8
- package/src/budget/comparison.js +0 -96
- package/src/canvas/parse-md.js +0 -238
- package/src/canvas/schema.js +0 -101
- package/src/canvas/to-flat.js +0 -85
- package/src/canvas/validate.js +0 -163
- package/src/ci/dispatch.js +0 -99
- package/src/ci/index.js +0 -3
- package/src/ci/pr-diff.js +0 -26
- package/src/cli/register-standby.js +0 -26
- package/src/commands/architect.js +0 -111
- package/src/commands/autorun.js +0 -49
- package/src/commands/researcher.js +0 -54
- package/src/commands/resume.js +0 -72
- package/src/commands/review.js +0 -89
- package/src/commands/run.js +0 -185
- package/src/commands/standby.js +0 -117
- package/src/commands/status.js +0 -36
- package/src/commands/triage.js +0 -78
- package/src/commands/undo.js +0 -62
- package/src/domains/domain-loader.js +0 -245
- package/src/domains/domain-registry.js +0 -140
- package/src/domains/domain-synthesizer.js +0 -129
- package/src/git/automation.js +0 -433
- package/src/git/coder-commit-guard.js +0 -40
- package/src/git/hu-automation.js +0 -243
- package/src/git/hu-snapshot.js +0 -10
- package/src/git/symlink-targets.js +0 -57
- package/src/golden/asserter.js +0 -92
- package/src/golden/loader.js +0 -52
- package/src/golden/runner.js +0 -92
- package/src/golden/schema.js +0 -41
- package/src/guards/duplicate-members.js +0 -86
- package/src/guards/intent-guard.js +0 -161
- package/src/guards/perf-guard.js +0 -126
- package/src/guards/policy-guard.js +0 -90
- package/src/guards/policy-resolver.js +0 -85
- package/src/guards/secret-redactor.js +0 -71
- package/src/hu/acceptance-runner.js +0 -138
- package/src/hu/lazy-planner.js +0 -109
- package/src/hu/parallel-executor.js +0 -94
- package/src/hu/routing-metrics.js +0 -17
- package/src/hu/split-validator.js +0 -143
- package/src/hu/splitting-detector.js +0 -158
- package/src/hu/splitting-generator.js +0 -175
- package/src/hu/store.js +0 -394
- package/src/infrastructure/mocks.js +0 -182
- package/src/mcp/handlers/run-handler.js +0 -318
- package/src/mcp/sovereignty-guard.js +0 -113
- package/src/mcp/tool-arg-normalizers.js +0 -16
- package/src/mutate/reviewer-signal.js +0 -76
- package/src/orchestrator/agent-fallback.js +0 -81
- package/src/orchestrator/brain-coordinator.js +0 -186
- package/src/orchestrator/ci-integration.js +0 -139
- package/src/orchestrator/config-init.js +0 -426
- package/src/orchestrator/direct-actions.js +0 -217
- package/src/orchestrator/drivers/error-recovery.js +0 -287
- package/src/orchestrator/drivers/init-context.js +0 -238
- package/src/orchestrator/drivers/iteration-loop.js +0 -382
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +0 -69
- package/src/orchestrator/drivers/iteration-phases/guards.js +0 -91
- package/src/orchestrator/drivers/iteration-phases/handle-approved.js +0 -29
- package/src/orchestrator/drivers/iteration-phases/quality-gates.js +0 -125
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +0 -62
- package/src/orchestrator/drivers/post-loop.js +0 -404
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +0 -137
- package/src/orchestrator/drivers/pre-loop-phases/config-deprecations.js +0 -47
- package/src/orchestrator/drivers/pre-loop-phases/ensure-addyosmani-skills.js +0 -84
- package/src/orchestrator/drivers/pre-loop-phases/inject-loaded-plan.js +0 -393
- package/src/orchestrator/drivers/pre-loop.js +0 -524
- package/src/orchestrator/drivers/run-hu-batch.js +0 -468
- package/src/orchestrator/feedback-enrichment.js +0 -140
- package/src/orchestrator/feedback-queue.js +0 -151
- package/src/orchestrator/flow-control.js +0 -170
- package/src/orchestrator/flow-runner.js +0 -365
- package/src/orchestrator/fs-leak-detector.js +0 -228
- package/src/orchestrator/hu-scheduler.js +0 -114
- package/src/orchestrator/hu-sub-pipeline.js +0 -642
- package/src/orchestrator/iteration-gate.js +0 -73
- package/src/orchestrator/iteration-stages.js +0 -9
- package/src/orchestrator/parallel-limiter.js +0 -74
- package/src/orchestrator/pipeline-context.js +0 -72
- package/src/orchestrator/post-loop-stages.js +0 -468
- package/src/orchestrator/pre-loop-stages.js +0 -11
- package/src/orchestrator/preflight-checks.js +0 -487
- package/src/orchestrator/repair/repair-detector.js +0 -117
- package/src/orchestrator/repair/repair-runner.js +0 -142
- package/src/orchestrator/reviewer-fallback.js +0 -45
- package/src/orchestrator/role-output-compressor.js +0 -189
- package/src/orchestrator/session-journal.js +0 -308
- package/src/orchestrator/solomon-escalation.js +0 -331
- package/src/orchestrator/solomon-rules.js +0 -212
- package/src/orchestrator/stages/acceptance-coverage-stage.js +0 -47
- package/src/orchestrator/stages/architect-stage.js +0 -172
- package/src/orchestrator/stages/coder-stage.js +0 -506
- package/src/orchestrator/stages/domain-curator-stage.js +0 -82
- package/src/orchestrator/stages/format-stage.js +0 -61
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +0 -127
- package/src/orchestrator/stages/hu-reviewer-stage.js +0 -419
- package/src/orchestrator/stages/perf-stage.js +0 -140
- package/src/orchestrator/stages/planner-stage.js +0 -85
- package/src/orchestrator/stages/rag-context-stage.js +0 -80
- package/src/orchestrator/stages/rag-preload-decisor.js +0 -58
- package/src/orchestrator/stages/research-stage.js +0 -69
- package/src/orchestrator/stages/reviewer-stage.js +0 -431
- package/src/orchestrator/stages/sonar-stage.js +0 -439
- package/src/orchestrator/stages/stage-classes.js +0 -84
- package/src/orchestrator/stages/stage-executor.js +0 -155
- package/src/orchestrator/stages/suite-green-stage.js +0 -62
- package/src/orchestrator/stages/tdd-discipline-stage.js +0 -56
- package/src/orchestrator/stages/tool-judge-stage.js +0 -53
- package/src/orchestrator/stages/triage-stage.js +0 -172
- package/src/orchestrator/standby.js +0 -71
- package/src/orchestrator/verification-gate.js +0 -183
- package/src/orchestrator.js +0 -22
- package/src/plan/adr-generator.js +0 -170
- package/src/plan/adr-loader.js +0 -60
- package/src/plan/plan-executor.js +0 -100
- package/src/plan/plan-validation.js +0 -4
- package/src/prompts/acceptance-coverage.js +0 -32
- package/src/prompts/arbiter.js +0 -38
- package/src/prompts/architect.js +0 -103
- package/src/prompts/hu-reviewer.js +0 -244
- package/src/prompts/tool-correctness-judge.js +0 -31
- package/src/prompts/triage.js +0 -57
- package/src/rag/embedder.js +0 -2
- package/src/rag/embedders/_cloud-base.js +0 -2
- package/src/rag/embedders/cohere.js +0 -2
- package/src/rag/embedders/mistral.js +0 -2
- package/src/rag/embedders/onnx.js +0 -2
- package/src/rag/embedders/openai.js +0 -2
- package/src/rag/embedders/voyage.js +0 -2
- package/src/rag/rerank.js +0 -4
- package/src/rag/where-parser.js +0 -4
- package/src/repeat-detector.js +0 -88
- package/src/review/diff-generator.js +0 -112
- package/src/review/git-stash-helper.js +0 -104
- package/src/review/schema.js +0 -31
- package/src/review/scope-filter.js +0 -152
- package/src/review/snapshot-diff.js +0 -122
- package/src/review/tdd-discipline.js +0 -90
- package/src/review/tdd-policy.js +0 -69
- package/src/roles/acceptance-coverage-role.js +0 -78
- package/src/roles/architect-role.js +0 -77
- package/src/roles/coder-role.js +0 -113
- package/src/roles/commiter-role.js +0 -113
- package/src/roles/domain-curator-role.js +0 -134
- package/src/roles/hu-reviewer-role.js +0 -64
- package/src/roles/impeccable-role.js +0 -85
- package/src/roles/index.js +0 -18
- package/src/roles/karajan-brain-role.js +0 -134
- package/src/roles/perf-role.js +0 -122
- package/src/roles/planner-role.js +0 -151
- package/src/roles/refactorer-role.js +0 -30
- package/src/roles/repairer-role.js +0 -181
- package/src/roles/researcher-role.js +0 -70
- package/src/roles/reviewer-role.js +0 -115
- package/src/roles/security-role.js +0 -73
- package/src/roles/solomon-role.js +0 -271
- package/src/roles/sonar-role.js +0 -72
- package/src/roles/tester-role.js +0 -235
- package/src/roles/tool-correctness-judge-role.js +0 -78
- package/src/roles/triage-role.js +0 -99
- package/src/session/journal/decisions-writer.js +0 -200
- package/src/session/journal/iteration-logger.js +0 -194
- package/src/session/journal/summary-writer.js +0 -320
- package/src/session/journal/tree-writer.js +0 -164
- package/src/session/journal/write-all.js +0 -89
- package/src/session-cleanup.js +0 -116
- package/src/skills/semantic-detector.js +0 -167
- package/src/skills/skill-detector.js +0 -385
- package/src/sonar/cloud-scanner.js +0 -78
- package/src/tracker-bootstrap.js +0 -44
- package/src/types/index.js +0 -38
- package/src/types/policy.js +0 -43
- package/src/types/solomon.js +0 -87
- package/src/utils/async-lock.js +0 -31
- package/src/utils/budget.js +0 -229
- package/src/utils/cwd-confirm.js +0 -39
- package/src/utils/display/event-handlers.js +0 -403
- package/src/utils/display/formatters.js +0 -132
- package/src/utils/display/header.js +0 -47
- package/src/utils/display/session-summary.js +0 -118
- package/src/utils/display/solomon.js +0 -42
- package/src/utils/pricing.js +0 -29
- package/src/utils/quota-simulator.js +0 -56
- package/src/utils/role-assigner.js +0 -137
- package/src/utils/rtk-wrapper.js +0 -87
- package/src/utils/run-registry.js +0 -9
- package/src/utils/status-dashboard.js +0 -254
- package/src/utils/tool-call-extractor.js +0 -56
- package/src/webperf/devtools-detect.js +0 -112
- package/src/webperf/webperf-role-integration.js +0 -66
- package/templates/skills/kj-run.md +0 -73
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
const modelRegistry = new Map();
|
|
2
|
-
|
|
3
|
-
export function registerModel(name, { provider, pricing, deprecated } = {}) {
|
|
4
|
-
if (!name || typeof name !== "string") {
|
|
5
|
-
throw new Error("Model name must be a non-empty string");
|
|
6
|
-
}
|
|
7
|
-
if (!pricing || typeof pricing.input_per_million !== "number" || typeof pricing.output_per_million !== "number") {
|
|
8
|
-
throw new Error(`Model "${name}" requires pricing with input_per_million and output_per_million`);
|
|
9
|
-
}
|
|
10
|
-
modelRegistry.set(name, {
|
|
11
|
-
name,
|
|
12
|
-
provider: provider || name.split("/")[0],
|
|
13
|
-
pricing: { input_per_million: pricing.input_per_million, output_per_million: pricing.output_per_million },
|
|
14
|
-
deprecated: deprecated || null,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function registerModelAlias(alias, target, { provider } = {}) {
|
|
19
|
-
const entry = modelRegistry.get(target);
|
|
20
|
-
if (!entry) {
|
|
21
|
-
throw new Error(`Target model "${target}" for alias "${alias}" not found`);
|
|
22
|
-
}
|
|
23
|
-
modelRegistry.set(alias, {
|
|
24
|
-
...entry,
|
|
25
|
-
name: alias,
|
|
26
|
-
provider: provider || entry.provider
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getModelPricing(name) {
|
|
31
|
-
const entry = modelRegistry.get(name);
|
|
32
|
-
return entry ? { ...entry.pricing } : null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function isModelDeprecated(name) {
|
|
36
|
-
const entry = modelRegistry.get(name);
|
|
37
|
-
if (!entry?.deprecated) return false;
|
|
38
|
-
return new Date(entry.deprecated) <= new Date();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function getModelInfo(name) {
|
|
42
|
-
const entry = modelRegistry.get(name);
|
|
43
|
-
if (!entry) return null;
|
|
44
|
-
return { name: entry.name, provider: entry.provider, pricing: { ...entry.pricing }, deprecated: entry.deprecated };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function getRegisteredModels() {
|
|
48
|
-
return [...modelRegistry.entries()].map(([_name, entry]) => ({
|
|
49
|
-
name: entry.name,
|
|
50
|
-
provider: entry.provider,
|
|
51
|
-
pricing: { ...entry.pricing },
|
|
52
|
-
deprecated: entry.deprecated,
|
|
53
|
-
}));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function buildDefaultPricingTable() {
|
|
57
|
-
const table = {};
|
|
58
|
-
for (const [name, entry] of modelRegistry) {
|
|
59
|
-
table[name] = { ...entry.pricing };
|
|
60
|
-
}
|
|
61
|
-
return table;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Anthropic Claude Family
|
|
66
|
-
* Pricing & Info: https://platform.claude.com/docs/en/about-claude/pricing
|
|
67
|
-
*/
|
|
68
|
-
registerModel("claude-opus-4.6", { provider: "anthropic", pricing: { input_per_million: 5.0, output_per_million: 25.0 } });
|
|
69
|
-
registerModel("claude-sonnet-4.6", { provider: "anthropic", pricing: { input_per_million: 3.0, output_per_million: 15.0 } });
|
|
70
|
-
registerModel("claude-haiku-4.5", { provider: "anthropic", pricing: { input_per_million: 1.0, output_per_million: 5.0 } });
|
|
71
|
-
|
|
72
|
-
// Default models & General aliases
|
|
73
|
-
registerModel("claude", { provider: "anthropic", pricing: { input_per_million: 3, output_per_million: 15 } });
|
|
74
|
-
registerModel("sonnet", { provider: "anthropic", pricing: { input_per_million: 3, output_per_million: 15 } });
|
|
75
|
-
registerModel("opus", { provider: "anthropic", pricing: { input_per_million: 15, output_per_million: 75 } });
|
|
76
|
-
registerModel("haiku", { provider: "anthropic", pricing: { input_per_million: 0.25, output_per_million: 1.25 } });
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* OpenAI GPT Family
|
|
80
|
-
* Pricing: https://developers.openai.com/api/docs/pricing
|
|
81
|
-
*/
|
|
82
|
-
registerModel("gpt-5.4-standard", { provider: "openai", pricing: { input_per_million: 2.5, output_per_million: 15.0 } });
|
|
83
|
-
registerModel("gpt-5.4-thinking", { provider: "openai", pricing: { input_per_million: 2.5, output_per_million: 15.0 } });
|
|
84
|
-
registerModel("gpt-5.4-pro", { provider: "openai", pricing: { input_per_million: 30.0, output_per_million: 180.0 } });
|
|
85
|
-
registerModel("gpt-5.4-mini", { provider: "openai", pricing: { input_per_million: 0.75, output_per_million: 4.5 } });
|
|
86
|
-
|
|
87
|
-
// Default models & General aliases
|
|
88
|
-
registerModel("codex", { provider: "openai", pricing: { input_per_million: 1.5, output_per_million: 4 } });
|
|
89
|
-
// KJC-TSK-0699: the models the codex CLI lists (0.146.1). List prices after the
|
|
90
|
-
// 2026-07-30 cut; Sol at its base rate, not the temporary promotion.
|
|
91
|
-
registerModel("gpt-5.6-sol", { provider: "openai", pricing: { input_per_million: 5.0, output_per_million: 30.0 } });
|
|
92
|
-
registerModel("gpt-5.6-terra", { provider: "openai", pricing: { input_per_million: 2.0, output_per_million: 12.0 } });
|
|
93
|
-
registerModel("gpt-5.6-luna", { provider: "openai", pricing: { input_per_million: 0.2, output_per_million: 1.2 } });
|
|
94
|
-
registerModel("o4-mini", { provider: "openai", pricing: { input_per_million: 1.5, output_per_million: 4 } });
|
|
95
|
-
registerModel("o3", { provider: "openai", pricing: { input_per_million: 10, output_per_million: 40 } });
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Google Gemini Family
|
|
99
|
-
* Pricing: https://ai.google.dev/gemini-api/docs/pricing
|
|
100
|
-
*/
|
|
101
|
-
registerModel("gemini-3.1-pro-preview", { provider: "google", pricing: { input_per_million: 2.0, output_per_million: 12.0 } });
|
|
102
|
-
registerModel("gemini-3.1-flash-lite", { provider: "google", pricing: { input_per_million: 0.25, output_per_million: 1.5 } });
|
|
103
|
-
registerModel("gemini-3-flash-preview", { provider: "google", pricing: { input_per_million: 0.5, output_per_million: 3.0 } });
|
|
104
|
-
registerModel("gemini-2.5-pro", { provider: "google", pricing: { input_per_million: 1.25, output_per_million: 5 } });
|
|
105
|
-
registerModel("gemini-2.0-flash", { provider: "google", pricing: { input_per_million: 0.075, output_per_million: 0.3 } });
|
|
106
|
-
|
|
107
|
-
// Default models & General aliases
|
|
108
|
-
registerModelAlias("gemini", "gemini-2.5-pro");
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Other Providers & CLI Aliases
|
|
112
|
-
*/
|
|
113
|
-
registerModel("aider", { provider: "aider", pricing: { input_per_million: 3, output_per_million: 15 } });
|
|
114
|
-
registerModel("opencode", { provider: "opencode", pricing: { input_per_million: 0, output_per_million: 0 } });
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Moonshot Kimi Family (KJC-TSK-0633) — consumed through OpenCode as an
|
|
118
|
-
* OpenAI-compatible provider (docs/providers-via-opencode.md).
|
|
119
|
-
* Pricing: https://platform.moonshot.ai/docs/pricing — verify before
|
|
120
|
-
* trusting for billing decisions; ids/prices move fast.
|
|
121
|
-
*/
|
|
122
|
-
registerModel("kimi-k2", { provider: "moonshot", pricing: { input_per_million: 0.6, output_per_million: 2.5 } });
|
|
123
|
-
registerModel("kimi-k2-thinking", { provider: "moonshot", pricing: { input_per_million: 0.6, output_per_million: 2.5 } });
|
|
124
|
-
registerModelAlias("kimi", "kimi-k2");
|
|
125
|
-
// Prefixed ids as the documented opencode.json snippet produces them.
|
|
126
|
-
registerModelAlias("kimi/kimi-k2", "kimi-k2");
|
|
127
|
-
registerModelAlias("kimi/kimi-k2-thinking", "kimi-k2-thinking");
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* DeepSeek Family (KJC-TSK-0633) — same OpenCode route.
|
|
131
|
-
* Pricing: https://api-docs.deepseek.com/quick_start/pricing
|
|
132
|
-
*/
|
|
133
|
-
registerModel("deepseek-chat", { provider: "deepseek", pricing: { input_per_million: 0.28, output_per_million: 0.42 } });
|
|
134
|
-
registerModel("deepseek-reasoner", { provider: "deepseek", pricing: { input_per_million: 0.28, output_per_million: 0.42 } });
|
|
135
|
-
registerModelAlias("deepseek", "deepseek-chat");
|
|
136
|
-
registerModelAlias("deepseek/deepseek-chat", "deepseek-chat");
|
|
137
|
-
registerModelAlias("deepseek/deepseek-reasoner", "deepseek-reasoner");
|
|
138
|
-
|
|
139
|
-
// Common CLI Aliases (with provider overrides)
|
|
140
|
-
registerModelAlias("aider/claude-3-7-sonnet", "claude-sonnet-4.6", { provider: "aider" });
|
|
141
|
-
registerModelAlias("aider/gpt-4o", "gpt-5.4-standard", { provider: "aider" });
|
|
142
|
-
registerModelAlias("opencode/minimax-m2.5", "opencode", { provider: "opencode" });
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan adherence metric — KJC-TSK-0376 (deepeval-inspired).
|
|
3
|
-
* Pure offline 0-100 score: how faithfully did the coder follow the plan?
|
|
4
|
-
* Components (weighted): commit_attribution 40%, acceptance_tests 30%,
|
|
5
|
-
* scope_discipline 20%, dependency_order 10%. Components return null
|
|
6
|
-
* when no data; aggregator redistributes the weight.
|
|
7
|
-
* See docs/plan-adherence.md (PR-C) for the full spec.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { escapeRegExp } from "../utils/escape-regexp.js";
|
|
11
|
-
|
|
12
|
-
const WEIGHTS = {
|
|
13
|
-
commit_attribution: 40,
|
|
14
|
-
acceptance_tests: 30,
|
|
15
|
-
scope_discipline: 20,
|
|
16
|
-
dependency_order: 10,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Build a regex that matches the HU id anywhere in a commit message
|
|
21
|
-
* (case-insensitive, word-boundary friendly). The `_` and `-` characters
|
|
22
|
-
* appear inside HU ids so we anchor on whole-token rather than \b.
|
|
23
|
-
*/
|
|
24
|
-
function huIdMatcher(huId) {
|
|
25
|
-
const escaped = escapeRegExp(huId);
|
|
26
|
-
return new RegExp(`(^|[^a-z0-9])${escaped}([^a-z0-9]|$)`, "i");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Slugify an HU title for branch-name / scope matching. Mirrors the
|
|
31
|
-
* `buildHuBranchName` slug rule (lowercase, non-alnum → "-").
|
|
32
|
-
*/
|
|
33
|
-
function slugify(text) {
|
|
34
|
-
return String(text || "")
|
|
35
|
-
.toLowerCase()
|
|
36
|
-
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
37
|
-
.replaceAll(/(^-+)|(-+$)/g, "");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Try to attribute a single commit to one of the plan's HUs.
|
|
42
|
-
*
|
|
43
|
-
* Order of evidence, strongest first:
|
|
44
|
-
* 1. The HU id appears in the commit message.
|
|
45
|
-
* 2. The HU id appears in the branch name where the commit lives
|
|
46
|
-
* (commit.branch is supplied by listCommitsBetween's caller when
|
|
47
|
-
* it knows the per-HU branches).
|
|
48
|
-
* 3. The HU title slug matches the commit message.
|
|
49
|
-
*
|
|
50
|
-
* Returns the matched huId, or null when none of the above fires.
|
|
51
|
-
*/
|
|
52
|
-
export function attributeCommitToHu(commit, hus) {
|
|
53
|
-
if (!commit || !Array.isArray(hus) || hus.length === 0) return null;
|
|
54
|
-
const msg = String(commit.message || "");
|
|
55
|
-
const branch = String(commit.branch || "");
|
|
56
|
-
for (const hu of hus) {
|
|
57
|
-
if (!hu?.id) continue;
|
|
58
|
-
const matcher = huIdMatcher(hu.id);
|
|
59
|
-
if (matcher.test(msg)) return hu.id;
|
|
60
|
-
if (branch && matcher.test(branch)) return hu.id;
|
|
61
|
-
}
|
|
62
|
-
// Fallback: title slug
|
|
63
|
-
for (const hu of hus) {
|
|
64
|
-
const slug = slugify(hu.title);
|
|
65
|
-
if (!slug || slug.length < 6) continue;
|
|
66
|
-
if (slugify(msg).includes(slug)) return hu.id;
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Component 1: commit attribution. Returns null when the run produced
|
|
73
|
-
* no commits at all (avoids penalising analysis-only or doc-only runs).
|
|
74
|
-
*/
|
|
75
|
-
export function computeCommitAttribution(commits, plan) {
|
|
76
|
-
if (!Array.isArray(commits) || commits.length === 0) return null;
|
|
77
|
-
if (!plan?.hus || plan.hus.length === 0) return null;
|
|
78
|
-
let attributed = 0;
|
|
79
|
-
for (const commit of commits) {
|
|
80
|
-
if (attributeCommitToHu(commit, plan.hus)) attributed += 1;
|
|
81
|
-
}
|
|
82
|
-
return Math.round((attributed / commits.length) * 100);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Component 2: acceptance test coverage. Heuristic: each HU declares
|
|
87
|
-
* `acceptance_tests`. We check whether at least one commit from that
|
|
88
|
-
* HU's pool has a `test:`-prefixed message. Per-HU score (1 or 0),
|
|
89
|
-
* averaged across HUs that DO declare tests. Returns null when no HU
|
|
90
|
-
* declares acceptance tests.
|
|
91
|
-
*/
|
|
92
|
-
export function computeAcceptanceTestCoverage(commits, plan) {
|
|
93
|
-
if (!plan?.hus || plan.hus.length === 0) return null;
|
|
94
|
-
if (!Array.isArray(commits) || commits.length === 0) return null;
|
|
95
|
-
const husWithTests = plan.hus.filter(
|
|
96
|
-
(hu) => Array.isArray(hu?.acceptance_tests) && hu.acceptance_tests.length > 0,
|
|
97
|
-
);
|
|
98
|
-
if (husWithTests.length === 0) return null;
|
|
99
|
-
|
|
100
|
-
let covered = 0;
|
|
101
|
-
for (const hu of husWithTests) {
|
|
102
|
-
const huCommits = (commits || []).filter(
|
|
103
|
-
(c) => attributeCommitToHu(c, [hu]) === hu.id,
|
|
104
|
-
);
|
|
105
|
-
const hasTestCommit = huCommits.some((c) =>
|
|
106
|
-
/^test[:(]/i.test(String(c.message || "").trim()),
|
|
107
|
-
);
|
|
108
|
-
if (hasTestCommit) covered += 1;
|
|
109
|
-
}
|
|
110
|
-
return Math.round((covered / husWithTests.length) * 100);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Component 3: scope discipline. For each file changed by the run, we
|
|
115
|
-
* try to match it against at least one HU's id slug, title slug, or
|
|
116
|
-
* `scope` text. A file that matches no HU is flagged as out-of-scope.
|
|
117
|
-
* Returns null when the run changed no files.
|
|
118
|
-
*/
|
|
119
|
-
export function computeScopeDiscipline(filesChanged, plan) {
|
|
120
|
-
if (!Array.isArray(filesChanged) || filesChanged.length === 0) return null;
|
|
121
|
-
if (!plan?.hus || plan.hus.length === 0) return null;
|
|
122
|
-
const huKeywords = plan.hus.map((hu) => ({
|
|
123
|
-
id: hu.id,
|
|
124
|
-
matchers: [
|
|
125
|
-
slugify(hu.id),
|
|
126
|
-
slugify(hu.title),
|
|
127
|
-
// Pull alpha-rich words from `scope` text (length >= 4).
|
|
128
|
-
...String(hu.scope || "")
|
|
129
|
-
.toLowerCase()
|
|
130
|
-
.split(/[^a-z]+/)
|
|
131
|
-
.filter((w) => w.length >= 4),
|
|
132
|
-
].filter(Boolean),
|
|
133
|
-
}));
|
|
134
|
-
let inScope = 0;
|
|
135
|
-
for (const file of filesChanged) {
|
|
136
|
-
const slug = slugify(file);
|
|
137
|
-
const matched = huKeywords.some((hk) =>
|
|
138
|
-
hk.matchers.some((m) => slug.includes(m) || file.includes(m)),
|
|
139
|
-
);
|
|
140
|
-
if (matched) inScope += 1;
|
|
141
|
-
}
|
|
142
|
-
return Math.round((inScope / filesChanged.length) * 100);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Component 4: dependency order. For every `(parent, child)` edge
|
|
147
|
-
* declared via `child.blocked_by`, check that the EARLIEST commit
|
|
148
|
-
* attributed to `parent` is older than the EARLIEST commit attributed
|
|
149
|
-
* to `child`. Returns null when no dependency edges exist.
|
|
150
|
-
*
|
|
151
|
-
* `commits` are expected oldest-first (the shape `listCommitsBetween`
|
|
152
|
-
* returns). When that's not the case the score still makes sense — we
|
|
153
|
-
* just compare relative positions in the array.
|
|
154
|
-
*/
|
|
155
|
-
export function computeDependencyOrder(commits, plan) {
|
|
156
|
-
if (!plan?.hus || plan.hus.length === 0) return null;
|
|
157
|
-
const edges = [];
|
|
158
|
-
for (const hu of plan.hus) {
|
|
159
|
-
for (const parentId of hu.blocked_by || []) {
|
|
160
|
-
edges.push([parentId, hu.id]);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (edges.length === 0) return null;
|
|
164
|
-
if (!Array.isArray(commits) || commits.length === 0) return null;
|
|
165
|
-
|
|
166
|
-
// Build huId → first commit index (oldest first attribution).
|
|
167
|
-
const firstIndex = new Map();
|
|
168
|
-
commits.forEach((commit, idx) => {
|
|
169
|
-
const huId = attributeCommitToHu(commit, plan.hus);
|
|
170
|
-
if (huId && !firstIndex.has(huId)) firstIndex.set(huId, idx);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
let respected = 0;
|
|
174
|
-
let evaluable = 0;
|
|
175
|
-
for (const [parentId, childId] of edges) {
|
|
176
|
-
const p = firstIndex.get(parentId);
|
|
177
|
-
const c = firstIndex.get(childId);
|
|
178
|
-
if (p === undefined || c === undefined) continue; // can't evaluate
|
|
179
|
-
evaluable += 1;
|
|
180
|
-
if (p < c) respected += 1;
|
|
181
|
-
}
|
|
182
|
-
if (evaluable === 0) return null;
|
|
183
|
-
return Math.round((respected / evaluable) * 100);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Aggregator: compute every component and weight them. Components
|
|
188
|
-
* that return `null` are excluded and their weight redistributed
|
|
189
|
-
* proportionally across the rest, so a run that legitimately has no
|
|
190
|
-
* acceptance tests or no dependencies isn't penalised.
|
|
191
|
-
*
|
|
192
|
-
* Returns the full structured result (see file header for shape).
|
|
193
|
-
*/
|
|
194
|
-
export function computePlanAdherenceScore({ commits, plan, filesChanged }) {
|
|
195
|
-
const breakdown = {
|
|
196
|
-
commit_attribution: computeCommitAttribution(commits, plan),
|
|
197
|
-
acceptance_tests: computeAcceptanceTestCoverage(commits, plan),
|
|
198
|
-
scope_discipline: computeScopeDiscipline(filesChanged, plan),
|
|
199
|
-
dependency_order: computeDependencyOrder(commits, plan),
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// Weighted average over non-null components only.
|
|
203
|
-
let totalWeight = 0;
|
|
204
|
-
let weightedSum = 0;
|
|
205
|
-
for (const [key, weight] of Object.entries(WEIGHTS)) {
|
|
206
|
-
const value = breakdown[key];
|
|
207
|
-
if (value === null || value === undefined) continue;
|
|
208
|
-
totalWeight += weight;
|
|
209
|
-
weightedSum += value * weight;
|
|
210
|
-
}
|
|
211
|
-
const score = totalWeight === 0 ? null : Math.round(weightedSum / totalWeight);
|
|
212
|
-
|
|
213
|
-
// Per-HU detail: was the HU "touched" (attributed at least one commit)?
|
|
214
|
-
const hu_scores = (plan?.hus || []).map((hu) => {
|
|
215
|
-
const huCommits = (commits || []).filter(
|
|
216
|
-
(c) => attributeCommitToHu(c, [hu]) === hu.id,
|
|
217
|
-
);
|
|
218
|
-
const issues = [];
|
|
219
|
-
if (huCommits.length === 0) issues.push("no commit attributed");
|
|
220
|
-
return { huId: hu.id, attributed: huCommits.length > 0, issues };
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
return { score, breakdown, hu_scores };
|
|
224
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ArbiterRole — the autonomous decision authority that resolves agent conflicts
|
|
3
|
-
* by picking the least-bad verdict (KJC-TSK-0573, épica KJC-PCS-0062).
|
|
4
|
-
*
|
|
5
|
-
* Extends AgentRole (so it inherits Brain recovery / standby) following the
|
|
6
|
-
* TriageRole pattern: a cheap decisor model emits a closed-set verdict, and any
|
|
7
|
-
* parse failure degrades to BLOCK_AND_CONTINUE — the pipeline never crashes and
|
|
8
|
-
* never blocks on the Arbiter.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { AgentRole } from "../roles/agent-role.js";
|
|
12
|
-
import { extractFirstJson } from "../utils/json-extract.js";
|
|
13
|
-
import { buildArbiterPrompt, VERDICTS } from "../prompts/arbiter.js";
|
|
14
|
-
|
|
15
|
-
const CONSERVATIVE = "BLOCK_AND_CONTINUE";
|
|
16
|
-
const VERDICT_SET = new Set(VERDICTS);
|
|
17
|
-
|
|
18
|
-
function clampConfidence(value) {
|
|
19
|
-
const n = Number(value);
|
|
20
|
-
return Number.isFinite(n) ? Math.min(1, Math.max(0, n)) : 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class ArbiterRole extends AgentRole {
|
|
24
|
-
constructor(opts) {
|
|
25
|
-
super({ ...opts, name: "arbiter" });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async buildPrompt(input) {
|
|
29
|
-
return { prompt: buildArbiterPrompt(input) };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
parseOutput(raw) {
|
|
33
|
-
return extractFirstJson(raw);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
buildSuccessResult(parsed, provider) {
|
|
37
|
-
const verdict = VERDICT_SET.has(parsed?.verdict) ? parsed.verdict : CONSERVATIVE;
|
|
38
|
-
return {
|
|
39
|
-
verdict,
|
|
40
|
-
confidence: clampConfidence(parsed?.confidence),
|
|
41
|
-
rationale: String(parsed?.rationale || "").trim() || "no rationale",
|
|
42
|
-
defect: parsed?.defect ? String(parsed.defect).trim() : null,
|
|
43
|
-
directive: parsed?.directive ? String(parsed.directive).trim() : null,
|
|
44
|
-
provider,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
buildSummary(parsed) {
|
|
49
|
-
return `Arbiter: ${VERDICT_SET.has(parsed?.verdict) ? parsed.verdict : CONSERVATIVE}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Never crash on garbage: degrade to the conservative verdict so the pipeline
|
|
53
|
-
// moves on instead of aborting (ok:true keeps the run alive).
|
|
54
|
-
handleParseNull(agentResult, provider) {
|
|
55
|
-
return this.degraded(agentResult, provider, "unstructured output");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
handleParseError(err, agentResult, provider) {
|
|
59
|
-
return this.degraded(agentResult, provider, err?.message || "parse error");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
degraded(agentResult, provider, why) {
|
|
63
|
-
this.logger?.warn?.(`[arbiter] ${why} → ${CONSERVATIVE} (conservative)`);
|
|
64
|
-
return {
|
|
65
|
-
ok: true,
|
|
66
|
-
result: { verdict: CONSERVATIVE, confidence: 0, rationale: `degraded: ${why}`, defect: null, directive: null, provider },
|
|
67
|
-
summary: `Arbiter: ${CONSERVATIVE} (degraded)`,
|
|
68
|
-
usage: agentResult.usage,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
package/src/autonomy/arbiter.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createArbiter — adapt ArbiterRole to the function the decision-resolver
|
|
3
|
-
* injects (KJC-TSK-0573). The resolver calls `arbiter(req)` and expects
|
|
4
|
-
* `{ choice, rationale, ... }`; here `choice` is the Arbiter's verdict, which
|
|
5
|
-
* the resolver then validates against the caller's options (AUTO-A).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { ArbiterRole } from "./arbiter-role.js";
|
|
9
|
-
|
|
10
|
-
export function createArbiter({ config = {}, logger = console, createAgentFn = null } = {}) {
|
|
11
|
-
return async function arbiter(req) {
|
|
12
|
-
const role = new ArbiterRole({ config, logger, createAgentFn });
|
|
13
|
-
const { result } = await role.execute(req);
|
|
14
|
-
return {
|
|
15
|
-
choice: result.verdict,
|
|
16
|
-
rationale: result.rationale,
|
|
17
|
-
confidence: result.confidence,
|
|
18
|
-
defect: result.defect,
|
|
19
|
-
directive: result.directive,
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
}
|
package/src/autonomy/decider.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* buildDecider — wire the active autonomy level to a ready decision resolver
|
|
3
|
-
* (KJC-TSK-0572, design in docs/specs/autonomous-delivery.md §5).
|
|
4
|
-
*
|
|
5
|
-
* interactive → the human `ask`; assisted/autonomous → the Arbiter (AUTO-B).
|
|
6
|
-
* Consumers (spec-review, reviewer, checkpoint…) call `resolve(...)` instead of
|
|
7
|
-
* prompting directly, so the autonomy level decides who answers in one place.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { createDecisionResolver } from "./decision-resolver.js";
|
|
11
|
-
import { resolveAutonomy } from "./policy.js";
|
|
12
|
-
import { createArbiter } from "./arbiter.js";
|
|
13
|
-
|
|
14
|
-
export function buildDecider({ config = {}, flags = {}, ask = null, env = process.env, logger = console, createAgentFn = null } = {}) {
|
|
15
|
-
const autonomy = resolveAutonomy({ config, flags, env });
|
|
16
|
-
const arbiter = autonomy === "interactive" ? null : createArbiter({ config, logger, createAgentFn });
|
|
17
|
-
return { autonomy, resolve: createDecisionResolver({ autonomy, ask, arbiter, logger }) };
|
|
18
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* autonomy/decision-resolver — the single choke point for every pipeline
|
|
3
|
-
* question (KJC-TSK-0572, design in docs/specs/autonomous-delivery.md §5).
|
|
4
|
-
*
|
|
5
|
-
* Today the "ask a human" logic is scattered (spec-review, checkpoint,
|
|
6
|
-
* reviewer, board-bridge). This unifies it: callers ask `resolveDecision`
|
|
7
|
-
* instead of prompting directly, and the autonomy level decides who answers —
|
|
8
|
-
* the human (`ask`) or the Arbiter (`arbiter`, injected by AUTO-B).
|
|
9
|
-
*
|
|
10
|
-
* INVARIANT: in `autonomous` mode the resolver NEVER returns a null choice and
|
|
11
|
-
* NEVER blocks — if the Arbiter can't decide it degrades to the option flagged
|
|
12
|
-
* `conservative` (or the first option). Decisions are always traced.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { RISK, usesArbiter } from "./policy.js";
|
|
16
|
-
|
|
17
|
-
/** Pick the safe fallback: the option flagged conservative, else the first. */
|
|
18
|
-
function conservativeOf(options) {
|
|
19
|
-
return options.find((o) => o.conservative) ?? options[0] ?? null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function decision(choice, rationale, source) {
|
|
23
|
-
return { choice: choice ?? null, rationale, source };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Build a resolver bound to an autonomy level and its two answer sources.
|
|
28
|
-
*
|
|
29
|
-
* @param {object} opts
|
|
30
|
-
* @param {string} opts.autonomy - interactive | assisted | autonomous
|
|
31
|
-
* @param {(question: string, context?: object) => Promise<string|null>} [opts.ask] - human prompt
|
|
32
|
-
* @param {(input: object) => Promise<{choice: string, rationale?: string}>} [opts.arbiter] - AUTO-B
|
|
33
|
-
* @returns {(req: object) => Promise<{choice, rationale, source}>}
|
|
34
|
-
*/
|
|
35
|
-
export function createDecisionResolver({ autonomy = "interactive", ask = null, arbiter = null, logger = console } = {}) {
|
|
36
|
-
return async function resolveDecision({ question, options = [], context = null, risk = RISK.LOW } = {}) {
|
|
37
|
-
const fallback = conservativeOf(options);
|
|
38
|
-
|
|
39
|
-
// Human path: interactive, or assisted with a high-risk decision.
|
|
40
|
-
if (!usesArbiter(autonomy, risk)) {
|
|
41
|
-
const answer = ask ? await ask(question, context) : null;
|
|
42
|
-
return decision(answer, "human", "human");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Arbiter path: must always yield a valid choice, never block.
|
|
46
|
-
if (!arbiter) return decision(fallback?.value, "no arbiter available → conservative", "fallback");
|
|
47
|
-
let verdict;
|
|
48
|
-
try {
|
|
49
|
-
verdict = await arbiter({ question, options, context, risk });
|
|
50
|
-
} catch (err) {
|
|
51
|
-
logger.warn?.(`decision-resolver: arbiter failed (${err.message}) → conservative`);
|
|
52
|
-
return decision(fallback?.value, "arbiter error → conservative", "fallback");
|
|
53
|
-
}
|
|
54
|
-
const valid = verdict && options.some((o) => o.value === verdict.choice);
|
|
55
|
-
if (!valid) return decision(fallback?.value, "arbiter gave no valid choice → conservative", "fallback");
|
|
56
|
-
return decision(verdict.choice, verdict.rationale ?? "arbiter", "arbiter");
|
|
57
|
-
};
|
|
58
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* outcome-report — the auditable "meets the ask, with known defects" report
|
|
3
|
-
* for an autonomous run (KJC-TSK-0577, design in docs/specs/autonomous-delivery.md §10).
|
|
4
|
-
*
|
|
5
|
-
* Pure: builds a serializable outcome from the run results + Arbiter decisions,
|
|
6
|
-
* and renders it as lines (or the structure is emitted as --json). The point is
|
|
7
|
-
* that an imperfect-but-delivered result is explicit and auditable: which HUs
|
|
8
|
-
* met the ask, what the Arbiter decided, and what debt remains.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {object} opts
|
|
13
|
-
* @param {string} [opts.planRef]
|
|
14
|
-
* @param {boolean} opts.delivered - the run met the minimum ask
|
|
15
|
-
* @param {Array<{id, title?, met: boolean, note?}>} [opts.hus]
|
|
16
|
-
* @param {Array<{verdict, rationale, hu?, defect?}>} [opts.decisions] - Arbiter log
|
|
17
|
-
*/
|
|
18
|
-
export function buildOutcome({ planRef = null, delivered = false, hus = [], decisions = [] } = {}) {
|
|
19
|
-
const met = hus.filter((h) => h.met).length;
|
|
20
|
-
const residualDefects = [
|
|
21
|
-
...hus.filter((h) => !h.met).map((h) => ({ hu: h.id, detail: h.note || "acceptance criteria not fully met" })),
|
|
22
|
-
...decisions.filter((d) => d.defect).map((d) => ({ hu: d.hu ?? null, detail: d.defect })),
|
|
23
|
-
];
|
|
24
|
-
return {
|
|
25
|
-
verdict: delivered ? "DELIVERED" : "INCOMPLETE",
|
|
26
|
-
planRef,
|
|
27
|
-
hus: { total: hus.length, met, unmet: hus.length - met },
|
|
28
|
-
decisions,
|
|
29
|
-
residualDefects,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Render an outcome (from buildOutcome) as human-readable lines. */
|
|
34
|
-
export function formatOutcomeReport(outcome) {
|
|
35
|
-
const lines = [
|
|
36
|
-
`kj autorun — outcome: ${outcome.verdict}`,
|
|
37
|
-
` plan: ${outcome.planRef ?? "?"}`,
|
|
38
|
-
` HUs: ${outcome.hus.met}/${outcome.hus.total} met the ask`,
|
|
39
|
-
];
|
|
40
|
-
if (outcome.decisions?.length) {
|
|
41
|
-
lines.push(" Decisions (Arbiter — least-bad calls):");
|
|
42
|
-
for (const d of outcome.decisions) {
|
|
43
|
-
lines.push(` • ${d.verdict}${d.hu ? ` [${d.hu}]` : ""} — ${d.rationale}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (outcome.residualDefects?.length) {
|
|
47
|
-
lines.push(" Known defects (delivered with debt):");
|
|
48
|
-
for (const def of outcome.residualDefects) {
|
|
49
|
-
lines.push(` • ${def.hu ? `[${def.hu}] ` : ""}${def.detail}`);
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
lines.push(" No residual defects recorded.");
|
|
53
|
-
}
|
|
54
|
-
return lines;
|
|
55
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createAutonomyAskQuestion — make the stages' question function non-blocking in
|
|
3
|
-
* autonomous mode (KJC-TSK-0576, AUTO-E, design in docs/specs/autonomous-delivery.md §9).
|
|
4
|
-
*
|
|
5
|
-
* In `autonomous` no stage asks a human or routes to the HU Board: the wrapper
|
|
6
|
-
* answers in-process with the least-bad "keep going" choice, so the run never
|
|
7
|
-
* pauses or aborts mid-loop. interactive and assisted keep the human prompts
|
|
8
|
-
* (baseAsk) unchanged.
|
|
9
|
-
*
|
|
10
|
-
* The answer is chosen per stage so the EXISTING branches proceed (verified
|
|
11
|
-
* against the stage code — no stage logic is touched):
|
|
12
|
-
* - architect clarification: null → the stage continues best-effort (a truthy
|
|
13
|
-
* answer would force a wasteful architect re-run).
|
|
14
|
-
* - everything else (Solomon escalation, checkpoint, …): "continue" → parsed
|
|
15
|
-
* as free-text guidance → the stage continues instead of pausing/aborting.
|
|
16
|
-
*/
|
|
17
|
-
export function createAutonomyAskQuestion({ baseAsk = null, autonomy = "interactive", logger = console } = {}) {
|
|
18
|
-
if (autonomy !== "autonomous") return baseAsk;
|
|
19
|
-
const auto = async (_question, context = {}) => {
|
|
20
|
-
const stage = context?.stage ?? null;
|
|
21
|
-
logger?.info?.(`[autonomy] ${stage ? `${stage}: ` : ""}auto-continue (no human in the loop)`);
|
|
22
|
-
return stage === "architect" ? null : "continue";
|
|
23
|
-
};
|
|
24
|
-
auto.interactive = false;
|
|
25
|
-
// Marker so the orchestrator can tell an autonomous (unattended) run from an
|
|
26
|
-
// interactive one even though both carry a truthy askQuestion — the wall-clock
|
|
27
|
-
// backstop relies on it (KJC-TSK-0575, AUTO-D).
|
|
28
|
-
auto.unattended = true;
|
|
29
|
-
return auto;
|
|
30
|
-
}
|