karajan-code 2.7.3 → 2.8.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 +4 -4
- package/package.json +24 -4
- package/scripts/diet-baseline.mjs +170 -0
- package/scripts/regen-arch-stats.sh +71 -0
- package/src/agents/availability.js +15 -9
- package/src/agents/claude-agent.js +143 -45
- package/src/agents/model-registry.js +1 -1
- package/src/audit/agent-readiness.js +240 -0
- package/src/bootstrap.js +26 -1
- package/src/brain/decision-tracker.js +3 -1
- package/src/brain/decisor.js +1 -1
- 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/binaries.js +1 -1
- package/src/checks/ports.js +97 -27
- package/src/checks/runner.js +26 -10
- package/src/checks/sonar.js +1 -1
- package/src/checks/system.js +1 -1
- package/src/checks/tokens.js +77 -24
- package/src/cli/_shared.js +30 -0
- package/src/cli/register-meta.js +204 -0
- package/src/cli/register-pipeline.js +212 -0
- package/src/cli/register-plan.js +152 -0
- package/src/cli/register-roles-skills.js +38 -0
- package/src/cli/register-sonar.js +28 -0
- package/src/cli.js +83 -468
- package/src/commands/agents.js +18 -6
- package/src/commands/architect.js +29 -2
- package/src/commands/audit.js +27 -3
- package/src/commands/board.js +160 -30
- package/src/commands/clean.js +83 -0
- package/src/commands/code.js +7 -2
- package/src/commands/discover.js +7 -2
- package/src/commands/init.js +2 -2
- package/src/commands/plan/_shared.js +40 -0
- package/src/commands/plan/add-hu.js +21 -0
- package/src/commands/plan/delete.js +9 -0
- package/src/commands/plan/generate.js +284 -0
- package/src/commands/plan/index.js +14 -0
- package/src/commands/plan/list.js +21 -0
- package/src/commands/plan/ready.js +46 -0
- package/src/commands/plan/remove-hu.js +17 -0
- package/src/commands/plan/show.js +81 -0
- package/src/commands/plan/validate.js +20 -0
- package/src/commands/plan.js +14 -291
- package/src/commands/researcher.js +7 -2
- package/src/commands/resume.js +24 -1
- package/src/commands/review.js +7 -2
- package/src/commands/run.js +52 -1
- package/src/commands/status.js +1 -1
- package/src/commands/sync.js +75 -0
- package/src/commands/triage.js +7 -2
- package/src/commands/undo.js +1 -1
- package/src/config/defaults.js +213 -0
- package/src/config/loader.js +137 -0
- package/src/config/overrides.js +199 -0
- package/src/config/role-resolver.js +159 -0
- package/src/config/test-harness.js +79 -0
- package/src/config.js +30 -609
- package/src/git/automation.js +2 -2
- package/src/guards/output-guard.js +0 -2
- package/src/hu/acceptance-runner.js +52 -10
- package/src/hu/store.js +11 -0
- package/src/mcp/handlers/direct-handlers.js +2 -5
- package/src/mcp/handlers/management-handlers.js +48 -4
- package/src/mcp/handlers/run-handler.js +9 -8
- package/src/mcp/preflight.js +32 -13
- package/src/mcp/server-handlers.js +4 -3
- package/src/mcp/suggest-handler.js +3 -2
- package/src/mcp/tools.js +15 -0
- package/src/orchestrator/agent-fallback.js +1 -1
- package/src/orchestrator/ci-integration.js +10 -10
- package/src/orchestrator/config-init.js +25 -7
- package/src/orchestrator/direct-actions.js +6 -2
- package/src/orchestrator/drivers/error-recovery.js +287 -0
- package/src/orchestrator/drivers/init-context.js +222 -0
- package/src/orchestrator/drivers/iteration-loop.js +311 -0
- package/src/orchestrator/drivers/iteration-phases/coder-and-refactorer.js +48 -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 +76 -0
- package/src/orchestrator/drivers/iteration-phases/reviewer-gate.js +60 -0
- package/src/orchestrator/drivers/post-loop.js +370 -0
- package/src/orchestrator/drivers/pre-loop-phases/auto-hu-batch.js +116 -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 +268 -0
- package/src/orchestrator/drivers/pre-loop.js +434 -0
- package/src/orchestrator/drivers/run-hu-batch.js +367 -0
- package/src/orchestrator/flow-control.js +4 -3
- package/src/orchestrator/flow-runner.js +121 -2019
- package/src/orchestrator/fs-leak-detector.js +156 -0
- package/src/orchestrator/hu-sub-pipeline.js +197 -9
- package/src/orchestrator/integrations.js +88 -0
- package/src/orchestrator/post-loop-stages.js +35 -8
- package/src/orchestrator/preflight-checks.js +30 -3
- package/src/orchestrator/repair/repair-detector.js +117 -0
- package/src/orchestrator/repair/repair-runner.js +142 -0
- package/src/orchestrator/reviewer-fallback.js +1 -1
- package/src/orchestrator/solomon-escalation.js +3 -2
- package/src/orchestrator/solomon-rules.js +7 -3
- package/src/orchestrator/stages/architect-stage.js +12 -11
- package/src/orchestrator/stages/coder-stage.js +56 -7
- package/src/orchestrator/stages/hu-reviewer-phases/detect-and-apply-splits.js +127 -0
- package/src/orchestrator/stages/hu-reviewer-stage.js +6 -79
- package/src/orchestrator/stages/planner-stage.js +1 -1
- package/src/orchestrator/stages/research-stage.js +1 -1
- package/src/orchestrator/stages/reviewer-stage.js +7 -7
- package/src/orchestrator/stages/sonar-stage.js +94 -10
- package/src/orchestrator/stages/stage-classes.js +86 -0
- package/src/orchestrator/stages/stage-executor.js +1 -1
- package/src/orchestrator/stages/triage-stage.js +1 -1
- package/src/orchestrator/standby.js +3 -2
- package/src/orchestrator/verification-gate.js +20 -12
- package/src/plan/adr-generator.js +170 -0
- package/src/plan/adr-loader.js +60 -0
- package/src/plan/plan-executor.js +19 -1
- package/src/plan/plan-hu-ops.js +170 -1
- package/src/plan/plan-reviewer.js +199 -0
- package/src/plan/plan-schema.js +69 -1
- package/src/plan/plan-store.js +40 -3
- package/src/plan/spec-detector.js +61 -0
- package/src/plan/tests-synthesizer.js +116 -0
- package/src/planning-game/client.js +3 -14
- package/src/planning-game/decomposition.js +1 -1
- package/src/planning-game/pipeline-adapter.js +36 -5
- package/src/prompts/coder.js +172 -1
- package/src/prompts/hu-reviewer.js +0 -1
- package/src/prompts/planner.js +81 -4
- package/src/review/diff-generator.js +35 -22
- package/src/review/snapshot-diff.js +1 -1
- package/src/roles/coder-role.js +25 -3
- package/src/roles/planner-role.js +42 -1
- package/src/roles/repairer-role.js +181 -0
- package/src/roles/tester-role.js +70 -4
- package/src/session/mutators.js +304 -0
- package/src/session/runtime-overrides.js +59 -0
- package/src/{session-store.js → session/store.js} +8 -2
- package/src/skills/semantic-detector.js +10 -5
- package/src/skills/skill-detector.js +1 -1
- package/src/sonar/cloud-scanner.js +0 -1
- package/src/sonar/credentials.js +14 -6
- package/src/sonar/discovery.js +123 -0
- package/src/sonar/manager.js +18 -0
- package/src/sync/detect-drift.js +113 -0
- package/src/tracker-bootstrap.js +44 -0
- package/src/utils/agent-detect.js +15 -11
- package/src/utils/board-prompt-bridge.js +109 -0
- package/src/utils/cli-progress.js +161 -0
- package/src/utils/cwd-confirm.js +39 -0
- package/src/utils/derive-project-name-from-cwd.js +119 -0
- package/src/utils/garbage-collector.js +396 -0
- package/src/utils/git.js +16 -4
- package/src/utils/locale.js +1 -1
- package/src/utils/paths.js +21 -1
- package/src/utils/process.js +1 -1
- package/src/utils/prompt-project-name.js +35 -0
- package/src/utils/run-context.js +75 -0
- package/src/utils/run-log.js +12 -0
- package/src/utils/task-file.js +1 -1
- package/src/utils/telemetry.js +13 -1
- package/src/webperf/devtools-detect.js +1 -1
- package/templates/coder-rules.md +13 -0
- package/templates/roles/coder.md +34 -0
- package/templates/roles/repairer.md +94 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role provider/model resolution + config validation.
|
|
3
|
+
*
|
|
4
|
+
* `resolveRole(config, role)` returns `{ provider, model }` for a role
|
|
5
|
+
* given the fully-overridden config, respecting legacy single-provider
|
|
6
|
+
* shortcuts (`coder: "claude"`) and per-role overrides
|
|
7
|
+
* (`roles.coder.provider`). Handles model compatibility (gemini models
|
|
8
|
+
* are dropped from a claude provider, etc.) so the agent subprocess
|
|
9
|
+
* never sees an incompatible `--model` flag.
|
|
10
|
+
*
|
|
11
|
+
* `validateConfig(config, commandName)` is the run-time guard called by
|
|
12
|
+
* every CLI command before spawning agents: it asserts every required
|
|
13
|
+
* role has a provider, otherwise throws with an actionable message
|
|
14
|
+
* ("Set 'roles.planner.provider' or pass '--planner <name>'").
|
|
15
|
+
*
|
|
16
|
+
* Extracted from `src/config.js` in TSK-0332 (Oleada 2 of the v2.7.4
|
|
17
|
+
* audit refactor). Public API: `resolveRole`, `validateConfig`. The
|
|
18
|
+
* inference helpers are internal.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if a model string is compatible with an agent provider.
|
|
23
|
+
* Only returns false when the model clearly belongs to a DIFFERENT provider.
|
|
24
|
+
* Returns true if we can't determine or if the model is ambiguous.
|
|
25
|
+
*/
|
|
26
|
+
const AGENT_MODEL_SIGNATURES = {
|
|
27
|
+
claude: ["claude", "sonnet", "opus", "haiku"],
|
|
28
|
+
codex: ["o4-", "o3-", "gpt-", "codex"],
|
|
29
|
+
gemini: ["gemini", "flash-"]
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function isModelCompatible(agent, model) {
|
|
33
|
+
if (!model || !agent) return true;
|
|
34
|
+
const lower = model.toLowerCase();
|
|
35
|
+
|
|
36
|
+
// Check if model clearly belongs to a different provider
|
|
37
|
+
for (const [provider, signatures] of Object.entries(AGENT_MODEL_SIGNATURES)) {
|
|
38
|
+
if (provider === agent) continue;
|
|
39
|
+
if (signatures.some(s => lower.includes(s))) {
|
|
40
|
+
// Model belongs to a different provider — incompatible
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Model doesn't clearly belong to any other provider — allow it
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Roles that inherit provider/model from the coder when not explicitly configured
|
|
50
|
+
const CODER_INHERITED_ROLES = new Set([
|
|
51
|
+
"planner", "refactorer", "solomon", "researcher", "tester", "security",
|
|
52
|
+
"impeccable", "triage", "discover", "architect", "audit", "hu_reviewer", "hu-reviewer"
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
function resolveProvider(roleConfig, role, roles, legacyCoder, legacyReviewer) {
|
|
56
|
+
if (roleConfig.provider) return roleConfig.provider;
|
|
57
|
+
|
|
58
|
+
// If model has "provider/model" format (e.g. "gemini/pro"), extract the provider
|
|
59
|
+
if (roleConfig.model && roleConfig.model.includes("/")) {
|
|
60
|
+
const inferredProvider = roleConfig.model.split("/")[0].toLowerCase();
|
|
61
|
+
if (AGENT_MODEL_SIGNATURES[inferredProvider]) return inferredProvider;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (role === "coder") return legacyCoder;
|
|
65
|
+
if (role === "reviewer") return legacyReviewer;
|
|
66
|
+
if (CODER_INHERITED_ROLES.has(role)) return roles.coder?.provider || legacyCoder;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveModel(roleConfig, role, config) {
|
|
71
|
+
if (roleConfig.model) {
|
|
72
|
+
// Strip "provider/" prefix from models like "gemini/pro" → "pro"
|
|
73
|
+
const model = roleConfig.model.includes("/")
|
|
74
|
+
? roleConfig.model.split("/").slice(1).join("/")
|
|
75
|
+
: roleConfig.model;
|
|
76
|
+
return { model, inherited: false };
|
|
77
|
+
}
|
|
78
|
+
if (role === "coder") return { model: config?.coder_options?.model ?? null, inherited: false };
|
|
79
|
+
if (role === "reviewer") return { model: config?.reviewer_options?.model ?? null, inherited: false };
|
|
80
|
+
if (CODER_INHERITED_ROLES.has(role)) {
|
|
81
|
+
const model = config?.coder_options?.model ?? null;
|
|
82
|
+
return { model, inherited: !!model };
|
|
83
|
+
}
|
|
84
|
+
return { model: null, inherited: false };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function resolveRole(config, role) {
|
|
88
|
+
const roles = config?.roles || {};
|
|
89
|
+
const roleConfig = roles[role] || {};
|
|
90
|
+
const legacyCoder = config?.coder || null;
|
|
91
|
+
const legacyReviewer = config?.reviewer || null;
|
|
92
|
+
|
|
93
|
+
const provider = resolveProvider(roleConfig, role, roles, legacyCoder, legacyReviewer);
|
|
94
|
+
let { model } = resolveModel(roleConfig, role, config);
|
|
95
|
+
|
|
96
|
+
// Drop model if incompatible with the resolved provider (inherited or explicit)
|
|
97
|
+
if (provider && model && !isModelCompatible(provider, model)) {
|
|
98
|
+
model = null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { provider, model };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Pipeline roles checked when commandName is "run": [pipelineKey, roleName]
|
|
105
|
+
const RUN_PIPELINE_ROLES = [
|
|
106
|
+
["reviewer", "reviewer"], ["triage", "triage"], ["planner", "planner"],
|
|
107
|
+
["refactorer", "refactorer"], ["researcher", "researcher"],
|
|
108
|
+
["tester", "tester"], ["security", "security"], ["impeccable", "impeccable"]
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
// Direct command-to-role mapping for non-"run" commands
|
|
112
|
+
const COMMAND_ROLE_MAP = {
|
|
113
|
+
discover: ["discover"],
|
|
114
|
+
plan: ["planner"],
|
|
115
|
+
code: ["coder"],
|
|
116
|
+
review: ["reviewer"]
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
function requiredRolesFor(commandName, config) {
|
|
120
|
+
if (commandName !== "run") {
|
|
121
|
+
return COMMAND_ROLE_MAP[commandName] || [];
|
|
122
|
+
}
|
|
123
|
+
const required = ["coder"];
|
|
124
|
+
for (const [pipelineKey, roleName] of RUN_PIPELINE_ROLES) {
|
|
125
|
+
const pipelineEntry = config?.pipeline?.[pipelineKey];
|
|
126
|
+
// reviewer defaults to enabled (only excluded if explicitly false)
|
|
127
|
+
const isEnabled = pipelineKey === "reviewer"
|
|
128
|
+
? pipelineEntry?.enabled !== false
|
|
129
|
+
: Boolean(pipelineEntry?.enabled);
|
|
130
|
+
if (isEnabled) required.push(roleName);
|
|
131
|
+
}
|
|
132
|
+
return required;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function validateConfig(config, commandName = "run") {
|
|
136
|
+
const errors = [];
|
|
137
|
+
if (!new Set(["paranoid", "strict", "standard", "relaxed", "custom"]).has(config.review_mode)) {
|
|
138
|
+
errors.push(`Invalid review_mode: ${config.review_mode}`);
|
|
139
|
+
}
|
|
140
|
+
if (!new Set(["tdd", "standard"]).has(config.development?.methodology)) {
|
|
141
|
+
errors.push(`Invalid development.methodology: ${config.development?.methodology}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const requiredRoles = requiredRolesFor(commandName, config);
|
|
145
|
+
for (const role of requiredRoles) {
|
|
146
|
+
const { provider } = resolveRole(config, role);
|
|
147
|
+
if (!provider) {
|
|
148
|
+
errors.push(
|
|
149
|
+
`Missing provider for required role '${role}'. Set 'roles.${role}.provider' or pass '--${role} <name>'`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (errors.length > 0) {
|
|
155
|
+
throw new Error(errors.join("\n"));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return config;
|
|
159
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-harness-visible config knobs — resolved once per run, then read
|
|
3
|
+
* everywhere via `config.testHarness.*`.
|
|
4
|
+
*
|
|
5
|
+
* Pre-v2.7.5 these defaults were read from `globalThis.__KJ_*` directly
|
|
6
|
+
* in production code paths — `flow-runner.js` read
|
|
7
|
+
* `globalThis.__KJ_DEFAULT_BRAIN_DECISOR`, `preflight-checks.js` read
|
|
8
|
+
* `globalThis.__KJ_DISABLE_SONAR_STAGE`, etc. The audit flagged this as
|
|
9
|
+
* spooky-action-at-a-distance: a stray test-harness leftover could flip
|
|
10
|
+
* a production default, and tests did not exercise the same path
|
|
11
|
+
* production users would.
|
|
12
|
+
*
|
|
13
|
+
* TSK-0334 isolates the globalThis lookup to a single site (this module,
|
|
14
|
+
* run during config load) and exposes the resolved knobs under
|
|
15
|
+
* `config.testHarness`. Production code reads only from `config.*`,
|
|
16
|
+
* never from `globalThis`. Tests can set either `globalThis.__KJ_*`
|
|
17
|
+
* (back-compat for the ~10 existing test files that already do) or pass
|
|
18
|
+
* `config.testHarness = { ... }` explicitly.
|
|
19
|
+
*
|
|
20
|
+
* The `tests/architecture/no-globalThis-kj.test.js` invariant fails CI
|
|
21
|
+
* if a `globalThis.__KJ_` read reappears anywhere under `src/` outside
|
|
22
|
+
* this module.
|
|
23
|
+
*
|
|
24
|
+
* Resolution order (first defined wins):
|
|
25
|
+
* 1. `config.testHarness.<key>` (explicit test or user config)
|
|
26
|
+
* 2. `globalThis.__KJ_<MACRO>` (existing test-harness global, back-compat)
|
|
27
|
+
* 3. Documented default (second column below)
|
|
28
|
+
*
|
|
29
|
+
* | config.testHarness key | globalThis key | prod default |
|
|
30
|
+
* |--------------------------------|----------------------------------|--------------|
|
|
31
|
+
* | disableSonarStage | __KJ_DISABLE_SONAR_STAGE | false |
|
|
32
|
+
* | defaultSkillsMode | __KJ_DEFAULT_SKILLS_MODE | "auto" |
|
|
33
|
+
* | defaultPreflightExtended | __KJ_DEFAULT_PREFLIGHT_EXTENDED | true |
|
|
34
|
+
* | defaultBrainDecisor | __KJ_DEFAULT_BRAIN_DECISOR | true |
|
|
35
|
+
* | defaultAddyosmaniEnabled | __KJ_DEFAULT_ADDYOSMANI_ENABLED | true |
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
const GLOBAL_KEYS = {
|
|
39
|
+
disableSonarStage: "__KJ_DISABLE_SONAR_STAGE",
|
|
40
|
+
defaultSkillsMode: "__KJ_DEFAULT_SKILLS_MODE",
|
|
41
|
+
defaultPreflightExtended: "__KJ_DEFAULT_PREFLIGHT_EXTENDED",
|
|
42
|
+
defaultBrainDecisor: "__KJ_DEFAULT_BRAIN_DECISOR",
|
|
43
|
+
defaultAddyosmaniEnabled: "__KJ_DEFAULT_ADDYOSMANI_ENABLED",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const PROD_DEFAULTS = Object.freeze({
|
|
47
|
+
disableSonarStage: false,
|
|
48
|
+
defaultSkillsMode: "auto",
|
|
49
|
+
defaultPreflightExtended: true,
|
|
50
|
+
defaultBrainDecisor: true,
|
|
51
|
+
defaultAddyosmaniEnabled: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the testHarness slice of config. Safe to call multiple times;
|
|
56
|
+
* each call re-reads globalThis so test-harness overrides applied after
|
|
57
|
+
* config load still take effect on the next resolution.
|
|
58
|
+
*
|
|
59
|
+
* @param {Partial<typeof PROD_DEFAULTS>} [explicit] - typically `config.testHarness` passed in
|
|
60
|
+
* @returns {Readonly<typeof PROD_DEFAULTS>}
|
|
61
|
+
*/
|
|
62
|
+
export function resolveTestHarness(explicit = {}) {
|
|
63
|
+
const out = {};
|
|
64
|
+
for (const [key, globalName] of Object.entries(GLOBAL_KEYS)) {
|
|
65
|
+
if (explicit && Object.prototype.hasOwnProperty.call(explicit, key) && explicit[key] !== undefined) {
|
|
66
|
+
out[key] = explicit[key];
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const g = globalThis[globalName];
|
|
70
|
+
if (g !== undefined) {
|
|
71
|
+
out[key] = g;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
out[key] = PROD_DEFAULTS[key];
|
|
75
|
+
}
|
|
76
|
+
return Object.freeze(out);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { PROD_DEFAULTS, GLOBAL_KEYS };
|