karajan-code 2.7.4 → 2.9.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 +1 -1
- 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/audit/basal-cost.js +92 -9
- package/src/audit/deterministic-summary.js +200 -0
- package/src/audit/osv-findings.js +162 -0
- package/src/audit/semgrep-findings.js +117 -0
- package/src/audit/sonar-findings.js +81 -0
- package/src/audit/webperf-input.js +90 -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 +3 -3
- package/src/checks/ci.js +2 -2
- package/src/checks/config-files.js +6 -6
- package/src/checks/dir-setup.js +4 -0
- package/src/checks/mcp-health.js +6 -0
- package/src/checks/ports.js +91 -29
- package/src/checks/rtk.js +1 -1
- package/src/checks/skills.js +5 -1
- package/src/checks/sonar.js +2 -2
- package/src/checks/system.js +3 -3
- package/src/checks/tokens.js +1 -1
- package/src/checks/types.js +0 -12
- package/src/cli/_shared.js +30 -0
- package/src/cli/register-meta.js +218 -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 +265 -30
- 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/doctor.js +1 -1
- 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 +78 -0
- package/src/config.js +30 -632
- 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 +11 -11
- package/src/orchestrator/config-init.js +25 -7
- package/src/orchestrator/direct-actions.js +7 -3
- 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 +301 -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 +431 -0
- package/src/orchestrator/drivers/run-hu-batch.js +367 -0
- package/src/orchestrator/feedback-queue.js +0 -1
- package/src/orchestrator/flow-control.js +4 -3
- package/src/orchestrator/flow-runner.js +121 -2077
- package/src/orchestrator/fs-leak-detector.js +156 -0
- package/src/orchestrator/hu-sub-pipeline.js +197 -9
- package/src/orchestrator/integrations.js +81 -0
- package/src/orchestrator/post-loop-stages.js +35 -8
- package/src/orchestrator/preflight-checks.js +20 -7
- 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/role-output-compressor.js +0 -1
- package/src/orchestrator/session-journal.js +4 -41
- 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 +84 -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 -17
- package/src/plan/spec-detector.js +61 -0
- package/src/plan/tests-synthesizer.js +116 -0
- package/src/planning-game/client.js +3 -28
- package/src/planning-game/decomposition.js +1 -1
- package/src/planning-game/pipeline-adapter.js +37 -6
- package/src/prompts/audit.js +206 -6
- package/src/prompts/coder.js +172 -1
- package/src/prompts/hu-reviewer.js +0 -1
- package/src/prompts/planner.js +81 -4
- package/src/prompts/rtk-snippet.js +1 -1
- package/src/review/diff-generator.js +35 -22
- package/src/review/snapshot-diff.js +1 -1
- package/src/roles/audit-role.js +125 -13
- 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} +2 -2
- package/src/skills/semantic-detector.js +10 -5
- package/src/skills/skill-detector.js +1 -1
- package/src/sonar/api.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/display/event-handlers.js +1 -1
- package/src/utils/display/header.js +1 -1
- package/src/utils/display/session-summary.js +3 -3
- package/src/utils/display/solomon.js +1 -1
- 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/role-assigner.js +1 -1
- 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,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR-H: ask the user "Nombre del proyecto?" before saving a plan.
|
|
3
|
+
*
|
|
4
|
+
* The user's words: "El nombre del board debería de deducirse del
|
|
5
|
+
* cwd o del nombre del plan, pero no darlo por hecho, preguntar al
|
|
6
|
+
* usuario siempre, por si quiere cambiarlo."
|
|
7
|
+
*
|
|
8
|
+
* Pre-fills the prompt with the suggested name (derived from the
|
|
9
|
+
* task / cwd) so accepting the default is one ENTER away. Returns
|
|
10
|
+
* the trimmed answer; falls back to the default when the user just
|
|
11
|
+
* hits ENTER (empty input).
|
|
12
|
+
*
|
|
13
|
+
* Caller is responsible for skipping this when stdin/stdout are not
|
|
14
|
+
* a TTY, when --yes is set, or when --json is set.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import readline from "node:readline";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} defaultName — pre-filled suggestion shown in [brackets]
|
|
21
|
+
* @returns {Promise<string>} the user's answer (defaults to defaultName)
|
|
22
|
+
*/
|
|
23
|
+
export async function promptProjectName(defaultName) {
|
|
24
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
25
|
+
const fallback = String(defaultName || "").trim();
|
|
26
|
+
const hint = fallback ? ` [${fallback}]` : "";
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
rl.question(`Nombre del proyecto${hint}: `, (answer) => {
|
|
29
|
+
rl.close();
|
|
30
|
+
const trimmed = String(answer || "").trim();
|
|
31
|
+
resolve(trimmed || fallback);
|
|
32
|
+
});
|
|
33
|
+
rl.on("SIGINT", () => { rl.close(); resolve(fallback); });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-run context store — makes module-level state in `utils/git.js`,
|
|
3
|
+
* `review/diff-generator.js`, etc. safe under concurrent `runFlow` calls.
|
|
4
|
+
*
|
|
5
|
+
* Pre-v2.7.5 the orchestrator mutated module-scope variables at pipeline
|
|
6
|
+
* start:
|
|
7
|
+
* setDiffRunner(rtkRunner); setDiffProjectDir(diffScope);
|
|
8
|
+
* setGitRunner(rtkRunner);
|
|
9
|
+
* // …later…
|
|
10
|
+
* // every git/diff op reads those globals
|
|
11
|
+
*
|
|
12
|
+
* That is fine for a single-threaded CLI invocation but corrupts when the
|
|
13
|
+
* MCP server fields two `kj_run` tool calls in parallel: each run would
|
|
14
|
+
* overwrite the others' runner/projectDir during setup, and subsequent
|
|
15
|
+
* reads would see a mix.
|
|
16
|
+
*
|
|
17
|
+
* TSK-0338 isolates that state to a per-run AsyncLocalStorage scope.
|
|
18
|
+
* `runFlow` wraps its execution in `withRunContext(ctx, fn)`, and the
|
|
19
|
+
* read paths in git.js / diff-generator.js look up
|
|
20
|
+
* `getRunContext()?.runner` before falling back to the module-level
|
|
21
|
+
* `_runner` (kept as a back-compat entry for callers outside a
|
|
22
|
+
* `runFlow` — CLI helpers, tests — that set state directly).
|
|
23
|
+
*
|
|
24
|
+
* What lives here vs. elsewhere:
|
|
25
|
+
* - `runContext` (this module) — runner, projectDir, snapshot — the
|
|
26
|
+
* pieces git/diff touches synchronously on every op.
|
|
27
|
+
* - `PipelineContext` (src/orchestrator/pipeline-context.js) — the
|
|
28
|
+
* richer structure ferried between stages. The two could merge
|
|
29
|
+
* eventually, but PipelineContext is created after preflight, and
|
|
30
|
+
* the runner/projectDir must be in scope BEFORE preflight runs
|
|
31
|
+
* (which itself calls git commands).
|
|
32
|
+
*
|
|
33
|
+
* The invariant `tests/orchestrator/concurrent-runs.test.js` exercises
|
|
34
|
+
* the isolation: two parallel `withRunContext(A, …)` and
|
|
35
|
+
* `withRunContext(B, …)` see their own runner, not each other's.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} RunContext
|
|
42
|
+
* @property {((command: string, args?: string[], options?: object) => Promise<object>)|null} [runner]
|
|
43
|
+
* Pipeline-scoped command runner. When present, git.js + diff-generator.js
|
|
44
|
+
* route commands through it instead of the default `runCommand`.
|
|
45
|
+
* @property {string|null} [projectDir]
|
|
46
|
+
* Directory scope for `git diff`. Prevents leaking unrelated subdir
|
|
47
|
+
* changes when `kj run` is invoked from a subpath of a monorepo.
|
|
48
|
+
* @property {Map<string, string>|null} [snapshot]
|
|
49
|
+
* Pre-coder filesystem snapshot for snapshot-based diff when git is
|
|
50
|
+
* unavailable (greenfield projects with no initial commit).
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
const runStore = new AsyncLocalStorage();
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Run `fn` with `ctx` as the active RunContext. All reads of
|
|
57
|
+
* `getRunContext()` inside (including from awaited callees) see `ctx`.
|
|
58
|
+
* Concurrent `withRunContext` invocations are fully isolated from each
|
|
59
|
+
* other — that's what AsyncLocalStorage guarantees.
|
|
60
|
+
*
|
|
61
|
+
* @param {RunContext} ctx
|
|
62
|
+
* @param {() => Promise<any>} fn
|
|
63
|
+
* @returns {Promise<any>}
|
|
64
|
+
*/
|
|
65
|
+
export function withRunContext(ctx, fn) {
|
|
66
|
+
return runStore.run(ctx ?? {}, fn);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @returns {RunContext|undefined} the active RunContext, or undefined when
|
|
71
|
+
* called outside any `withRunContext` scope (legacy CLI paths, tests).
|
|
72
|
+
*/
|
|
73
|
+
export function getRunContext() {
|
|
74
|
+
return runStore.getStore();
|
|
75
|
+
}
|
package/src/utils/run-log.js
CHANGED
|
@@ -57,6 +57,18 @@ export function createRunLog(projectDir) {
|
|
|
57
57
|
// Truncate/create the log file
|
|
58
58
|
fs.writeFileSync(logPath, `--- Karajan run started at ${new Date().toISOString()} ---\n`);
|
|
59
59
|
|
|
60
|
+
// Audit recommendation (perf-LOW): suggested createWriteStream + queue.
|
|
61
|
+
// Tried it; broke the contract. `readRunLog` (used by `kj_status`,
|
|
62
|
+
// `kj-tail`, and the HU board's chokidar tick) reads the file with
|
|
63
|
+
// `fs.readFileSync` and expects every prior write to be visible the
|
|
64
|
+
// moment the writer's `logEvent()` returns — which is what
|
|
65
|
+
// `fs.writeSync(fd, ...)` guarantees and `stream.write()` does NOT.
|
|
66
|
+
//
|
|
67
|
+
// The current shape is already opened-once: `fs.openSync(logPath, "a")`
|
|
68
|
+
// returns an fd that every subsequent `fs.writeSync` reuses (no extra
|
|
69
|
+
// open/close per call). The hot-path complaint was about the FALLBACK
|
|
70
|
+
// `fs.appendFileSync` line, which only fires when openSync itself
|
|
71
|
+
// fails (rare; FS error or RO mount).
|
|
60
72
|
let fd = null;
|
|
61
73
|
try {
|
|
62
74
|
fd = fs.openSync(logPath, "a");
|
package/src/utils/task-file.js
CHANGED
|
@@ -49,7 +49,7 @@ export async function readTaskFile(filePath, opts = {}) {
|
|
|
49
49
|
try {
|
|
50
50
|
stat = await fs.stat(resolved);
|
|
51
51
|
} catch (err) {
|
|
52
|
-
throw new Error(`Task file not found: ${resolved} (${err.code || err.message})
|
|
52
|
+
throw new Error(`Task file not found: ${resolved} (${err.code || err.message})`, { cause: err });
|
|
53
53
|
}
|
|
54
54
|
if (!stat.isFile()) {
|
|
55
55
|
throw new Error(`Task file is not a regular file: ${resolved}`);
|
package/src/utils/telemetry.js
CHANGED
|
@@ -32,7 +32,19 @@ export async function sendTelemetryEvent(eventName, data, config) {
|
|
|
32
32
|
} finally {
|
|
33
33
|
clearTimeout(timeout);
|
|
34
34
|
}
|
|
35
|
-
} catch {
|
|
35
|
+
} catch (err) {
|
|
36
|
+
// Audit follow-up: was a silent catch{}. Telemetry MUST stay
|
|
37
|
+
// fire-and-forget (never block the user's pipeline, never throw),
|
|
38
|
+
// but completely silent failures hide DNS/network bugs that matter
|
|
39
|
+
// when debugging the telemetry pipeline itself. Surface the error
|
|
40
|
+
// to stderr only when KJ_DEBUG=1 is explicitly set, so normal runs
|
|
41
|
+
// are still silent.
|
|
42
|
+
if (process.env.KJ_DEBUG === "1") {
|
|
43
|
+
// Stderr (not console — telemetry runs from CLI commands and is
|
|
44
|
+
// legitimate user-visible diagnostic output under KJ_DEBUG).
|
|
45
|
+
process.stderr.write(`[telemetry-debug] ${eventName}: ${err.message}\n`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import os from "node:os";
|
|
6
|
-
import { isOpenSkillsAvailable,
|
|
6
|
+
import { isOpenSkillsAvailable, listSkills } from "../skills/openskills-client.js";
|
|
7
7
|
|
|
8
8
|
/** Skill names relevant for WebPerf analysis. Already installed globally via openskills. */
|
|
9
9
|
export const WEBPERF_SKILLS = [
|
package/templates/coder-rules.md
CHANGED
|
@@ -22,3 +22,16 @@
|
|
|
22
22
|
- Keep changes minimal and focused on the task.
|
|
23
23
|
- Do not modify code unrelated to the task.
|
|
24
24
|
- Follow existing code conventions and patterns in the repository.
|
|
25
|
+
|
|
26
|
+
## Tests location (MANDATORY)
|
|
27
|
+
|
|
28
|
+
- Tests live in a top-level `tests/` directory mirroring `src/` (e.g. a function in
|
|
29
|
+
`src/services/foo.js` is tested by `tests/services/foo.test.js`).
|
|
30
|
+
- DO NOT scatter `*.test.js` files inside `src/` unless the project's local
|
|
31
|
+
`.karajan/coder-rules.md` explicitly overrides this.
|
|
32
|
+
- When generating a project from scratch:
|
|
33
|
+
- Create `tests/` and point the test runner at it (`include: ['tests/**/*.test.{js,ts}']`).
|
|
34
|
+
- Exclude `tests/` from the production bundle.
|
|
35
|
+
- If you write `sonar-project.properties`, set `sonar.tests=tests` AND make sure
|
|
36
|
+
that directory exists. Never declare a path that doesn't exist — Sonar will
|
|
37
|
+
refuse to scan and the run will fail every iteration with the same error.
|
package/templates/roles/coder.md
CHANGED
|
@@ -28,6 +28,40 @@ Before reporting done, verify that ALL parts of the task are addressed:
|
|
|
28
28
|
- If you write tests first (TDD), the implementation MUST make those tests pass.
|
|
29
29
|
- Do NOT commit code that doesn't compile or doesn't pass tests.
|
|
30
30
|
|
|
31
|
+
## Test file location (MANDATORY convention)
|
|
32
|
+
|
|
33
|
+
Tests live in a top-level `tests/` directory (or `test/` if the project already
|
|
34
|
+
established that convention). Mirror the source tree under it: a function in
|
|
35
|
+
`src/services/foo.js` is tested by `tests/services/foo.test.js`, NOT by a
|
|
36
|
+
sibling file inside `src/`. This is the default Karajan convention; the only
|
|
37
|
+
exception is when a `.karajan/coder-rules.md` in the project repo explicitly
|
|
38
|
+
overrides it.
|
|
39
|
+
|
|
40
|
+
Why this matters:
|
|
41
|
+
- Reviewers and humans look in `tests/`, not next to source. Buried tests get
|
|
42
|
+
treated as "no tests exist" even when they do.
|
|
43
|
+
- Sonar's default `sonar.tests=tests` (and equivalents in other scanners) only
|
|
44
|
+
finds tests there. Putting tests under `src/` produces empty coverage and
|
|
45
|
+
scanner errors.
|
|
46
|
+
- Bundlers (Vite, esbuild, Astro, etc.) skip a `tests/` tree by default;
|
|
47
|
+
in-source tests can leak into production bundles unless every config
|
|
48
|
+
explicitly excludes them.
|
|
49
|
+
|
|
50
|
+
When generating a project from scratch:
|
|
51
|
+
- Create the `tests/` directory.
|
|
52
|
+
- Configure the test runner to look there (`include: ['tests/**/*.test.{js,ts}']`
|
|
53
|
+
in vitest, `testMatch` in jest, etc.).
|
|
54
|
+
- Configure the build tool to ignore it (`vite.config` excludes, etc.).
|
|
55
|
+
- Configure Sonar (if `sonar-project.properties` is generated) with
|
|
56
|
+
`sonar.sources=src`, `sonar.tests=tests`, and verify both directories exist
|
|
57
|
+
before writing the file. NEVER write `sonar.tests=tests` without a `tests/`
|
|
58
|
+
folder — Sonar will refuse to scan and the run will burn iterations.
|
|
59
|
+
|
|
60
|
+
When modifying an existing project:
|
|
61
|
+
- Match whatever convention is already in place; do NOT introduce a second
|
|
62
|
+
one. If `tests/` exists, put new tests there. If only `src/**/*.test.js`
|
|
63
|
+
exists, follow that.
|
|
64
|
+
|
|
31
65
|
## Secrets and environment variables
|
|
32
66
|
|
|
33
67
|
- NEVER hardcode API keys, tokens, passwords, secrets, or credentials in source code. No exceptions, not even for public keys or test keys.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Repairer Role
|
|
2
|
+
|
|
3
|
+
You are the **Repairer** in a multi-role AI pipeline. Your single job is
|
|
4
|
+
to look at a **failing acceptance test** that the coder has tried and
|
|
5
|
+
failed to satisfy across multiple iterations, decide whether the test
|
|
6
|
+
**itself** is broken (vs. the code), and — if it is — return a corrected
|
|
7
|
+
test that preserves the original intent.
|
|
8
|
+
|
|
9
|
+
## When you are invoked
|
|
10
|
+
|
|
11
|
+
The Brain calls you when an HU's acceptance test has failed N
|
|
12
|
+
consecutive iterations with the same error signature, and the coder
|
|
13
|
+
cannot make it pass. The Brain has classified the failure as
|
|
14
|
+
*possibly infeasible* (the test may itself be the problem, not the
|
|
15
|
+
implementation under test).
|
|
16
|
+
|
|
17
|
+
## Your task
|
|
18
|
+
|
|
19
|
+
You receive:
|
|
20
|
+
|
|
21
|
+
- The failing acceptance test (string or `{ type, content }`).
|
|
22
|
+
- The most recent error output from running it.
|
|
23
|
+
- The HU's title and scope so you understand intent.
|
|
24
|
+
- A list of all of the HU's other acceptance tests (so any rewrite
|
|
25
|
+
stays consistent with them).
|
|
26
|
+
|
|
27
|
+
Decide:
|
|
28
|
+
|
|
29
|
+
1. **fixable**: the test has a syntactic / structural bug you can
|
|
30
|
+
correct (e.g. invalid `jq` query, wrong shell quoting, unreachable
|
|
31
|
+
path assumed to exist, command name typo). Return the corrected
|
|
32
|
+
test content.
|
|
33
|
+
2. **unfixable**: the test is fundamentally impossible (asks for a
|
|
34
|
+
contradiction, depends on an external service that's unreachable,
|
|
35
|
+
the HU's intent itself is wrong). Escalate.
|
|
36
|
+
|
|
37
|
+
## Diagnostic checklist (apply in order)
|
|
38
|
+
|
|
39
|
+
For shell tests:
|
|
40
|
+
- Does `bash -n -c '<cmd>'` parse? If not → syntax fix.
|
|
41
|
+
- Does the test invoke `jq`? Run `echo '{}' | jq <query>` to check
|
|
42
|
+
the jq query parses. If "Cannot index array with string", the test
|
|
43
|
+
likely uses `as $n | .field` after a transform — restructure with
|
|
44
|
+
`as $r` binding the root.
|
|
45
|
+
- Does the test reference a file path that the HU explicitly creates?
|
|
46
|
+
If the path doesn't match what the HU actually produces, fix the
|
|
47
|
+
path.
|
|
48
|
+
- Does the test depend on a tool not in the project's runtime
|
|
49
|
+
(`pnpm` vs `npm` vs `yarn`, `python3` vs `python`)? Match what's
|
|
50
|
+
actually used.
|
|
51
|
+
|
|
52
|
+
For Gherkin tests:
|
|
53
|
+
- Are Given/When/Then well-formed? If a step is ambiguous, narrow it.
|
|
54
|
+
- Does the test rely on state set up by another scenario? Inline the
|
|
55
|
+
setup or mark the scenario as needing the upstream HU.
|
|
56
|
+
|
|
57
|
+
## When NOT to "fix"
|
|
58
|
+
|
|
59
|
+
- The test is correct and the code is wrong → return `unfixable` with
|
|
60
|
+
reason `"test is correct; coder must fix the implementation"`. The
|
|
61
|
+
Brain will treat this as a normal failure, not as a repair.
|
|
62
|
+
- The HU's intent contradicts the test (the HU asks to do A, the test
|
|
63
|
+
checks B) → return `unfixable` with reason `"intent mismatch"`.
|
|
64
|
+
This is an FDE problem, not a Repairer problem.
|
|
65
|
+
|
|
66
|
+
## Output format
|
|
67
|
+
|
|
68
|
+
Return ONLY a single valid JSON object:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"verdict": "fixable" | "unfixable",
|
|
73
|
+
"fixed_test": { "type": "shell" | "gherkin", "content": "..." } | null,
|
|
74
|
+
"reason": "one-sentence explanation of what was wrong (or why unfixable)",
|
|
75
|
+
"diagnostics": ["any tool-output snippets you used to diagnose"]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- When `verdict: "fixable"`, `fixed_test` is REQUIRED and `reason`
|
|
80
|
+
describes the bug class (e.g. `"jq query had 'as $n | .field' on
|
|
81
|
+
the array tail"`).
|
|
82
|
+
- When `verdict: "unfixable"`, `fixed_test` is `null` and `reason`
|
|
83
|
+
explains why (`"test depends on Sonar 9000 reachable, network
|
|
84
|
+
isolated"`, `"intent mismatch — HU asks X, test checks Y"`).
|
|
85
|
+
|
|
86
|
+
## Constraints
|
|
87
|
+
|
|
88
|
+
- NEVER soften an assertion just to make it pass. If the test was
|
|
89
|
+
asking the right question, your job is to make it ask it correctly,
|
|
90
|
+
not weakly.
|
|
91
|
+
- NEVER rewrite a test to pass against the CURRENT code. The test
|
|
92
|
+
defines the contract; the code is what's measured against it.
|
|
93
|
+
- Keep changes minimal. One bug at a time. If the test has multiple
|
|
94
|
+
problems, fix the most blocking one first.
|