karajan-code 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +441 -0
- package/docs/karajan-code-logo-small.png +0 -0
- package/package.json +60 -0
- package/scripts/install.js +898 -0
- package/scripts/install.sh +7 -0
- package/scripts/postinstall.js +117 -0
- package/scripts/setup-multi-instance.sh +150 -0
- package/src/activity-log.js +59 -0
- package/src/agents/aider-agent.js +25 -0
- package/src/agents/availability.js +32 -0
- package/src/agents/base-agent.js +27 -0
- package/src/agents/claude-agent.js +24 -0
- package/src/agents/codex-agent.js +27 -0
- package/src/agents/gemini-agent.js +25 -0
- package/src/agents/index.js +19 -0
- package/src/agents/resolve-bin.js +60 -0
- package/src/cli.js +200 -0
- package/src/commands/code.js +32 -0
- package/src/commands/config.js +74 -0
- package/src/commands/doctor.js +155 -0
- package/src/commands/init.js +181 -0
- package/src/commands/plan.js +67 -0
- package/src/commands/report.js +340 -0
- package/src/commands/resume.js +39 -0
- package/src/commands/review.js +26 -0
- package/src/commands/roles.js +117 -0
- package/src/commands/run.js +91 -0
- package/src/commands/scan.js +18 -0
- package/src/commands/sonar.js +53 -0
- package/src/config.js +322 -0
- package/src/git/automation.js +100 -0
- package/src/mcp/progress.js +69 -0
- package/src/mcp/run-kj.js +87 -0
- package/src/mcp/server-handlers.js +259 -0
- package/src/mcp/server.js +37 -0
- package/src/mcp/tool-arg-normalizers.js +16 -0
- package/src/mcp/tools.js +184 -0
- package/src/orchestrator.js +1277 -0
- package/src/planning-game/adapter.js +105 -0
- package/src/planning-game/client.js +81 -0
- package/src/prompts/coder.js +60 -0
- package/src/prompts/planner.js +26 -0
- package/src/prompts/reviewer.js +45 -0
- package/src/repeat-detector.js +77 -0
- package/src/review/diff-generator.js +22 -0
- package/src/review/parser.js +93 -0
- package/src/review/profiles.js +66 -0
- package/src/review/schema.js +31 -0
- package/src/review/tdd-policy.js +57 -0
- package/src/roles/base-role.js +127 -0
- package/src/roles/coder-role.js +60 -0
- package/src/roles/commiter-role.js +94 -0
- package/src/roles/index.js +12 -0
- package/src/roles/planner-role.js +81 -0
- package/src/roles/refactorer-role.js +66 -0
- package/src/roles/researcher-role.js +134 -0
- package/src/roles/reviewer-role.js +132 -0
- package/src/roles/security-role.js +128 -0
- package/src/roles/solomon-role.js +199 -0
- package/src/roles/sonar-role.js +65 -0
- package/src/roles/tester-role.js +114 -0
- package/src/roles/triage-role.js +128 -0
- package/src/session-store.js +80 -0
- package/src/sonar/api.js +78 -0
- package/src/sonar/enforcer.js +19 -0
- package/src/sonar/manager.js +163 -0
- package/src/sonar/project-key.js +83 -0
- package/src/sonar/scanner.js +267 -0
- package/src/utils/agent-detect.js +32 -0
- package/src/utils/budget.js +123 -0
- package/src/utils/display.js +346 -0
- package/src/utils/events.js +23 -0
- package/src/utils/fs.js +19 -0
- package/src/utils/git.js +101 -0
- package/src/utils/logger.js +86 -0
- package/src/utils/paths.js +18 -0
- package/src/utils/pricing.js +28 -0
- package/src/utils/process.js +67 -0
- package/src/utils/wizard.js +41 -0
- package/templates/coder-rules.md +24 -0
- package/templates/docker-compose.sonar.yml +60 -0
- package/templates/kj.config.yml +82 -0
- package/templates/review-rules.md +11 -0
- package/templates/roles/coder.md +42 -0
- package/templates/roles/commiter.md +44 -0
- package/templates/roles/planner.md +45 -0
- package/templates/roles/refactorer.md +39 -0
- package/templates/roles/researcher.md +37 -0
- package/templates/roles/reviewer-paranoid.md +38 -0
- package/templates/roles/reviewer-relaxed.md +34 -0
- package/templates/roles/reviewer-strict.md +37 -0
- package/templates/roles/reviewer.md +55 -0
- package/templates/roles/security.md +54 -0
- package/templates/roles/solomon.md +106 -0
- package/templates/roles/sonar.md +49 -0
- package/templates/roles/tester.md +41 -0
- package/templates/roles/triage.md +25 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
|
|
3
|
+
const LEVELS = ["debug", "info", "warn", "error"];
|
|
4
|
+
|
|
5
|
+
const ANSI = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
dim: "\x1b[2m",
|
|
8
|
+
cyan: "\x1b[36m",
|
|
9
|
+
yellow: "\x1b[33m",
|
|
10
|
+
red: "\x1b[31m",
|
|
11
|
+
gray: "\x1b[90m"
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const LEVEL_COLORS = {
|
|
15
|
+
debug: ANSI.gray,
|
|
16
|
+
info: ANSI.cyan,
|
|
17
|
+
warn: ANSI.yellow,
|
|
18
|
+
error: ANSI.red
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function timestamp() {
|
|
22
|
+
return new Date().toISOString().slice(11, 23);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function formatContext(ctx) {
|
|
26
|
+
const parts = [];
|
|
27
|
+
if (ctx.iteration !== undefined) parts.push(`iter=${ctx.iteration}`);
|
|
28
|
+
if (ctx.stage) parts.push(`stage=${ctx.stage}`);
|
|
29
|
+
return parts.length ? `[${parts.join(" ")}] ` : "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createLogger(level = "info", mode = "cli") {
|
|
33
|
+
const min = LEVELS.indexOf(level);
|
|
34
|
+
const minIdx = min === -1 ? 1 : min;
|
|
35
|
+
const emitter = new EventEmitter();
|
|
36
|
+
let context = {};
|
|
37
|
+
|
|
38
|
+
function canLog(target) {
|
|
39
|
+
return LEVELS.indexOf(target) >= minIdx;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function emit(lvl, args) {
|
|
43
|
+
const entry = {
|
|
44
|
+
level: lvl,
|
|
45
|
+
timestamp: new Date().toISOString(),
|
|
46
|
+
context: { ...context },
|
|
47
|
+
message: args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")
|
|
48
|
+
};
|
|
49
|
+
emitter.emit("log", entry);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function log(lvl, ...args) {
|
|
53
|
+
if (!canLog(lvl)) return;
|
|
54
|
+
emit(lvl, args);
|
|
55
|
+
if (mode === "silent") return;
|
|
56
|
+
if (mode === "mcp") return;
|
|
57
|
+
const color = LEVEL_COLORS[lvl] || "";
|
|
58
|
+
const ts = `${ANSI.dim}${timestamp()}${ANSI.reset}`;
|
|
59
|
+
const prefix = `${color}[${lvl}]${ANSI.reset}`;
|
|
60
|
+
const ctx = formatContext(context);
|
|
61
|
+
const stream = lvl === "error" ? console.error : lvl === "warn" ? console.warn : console.log;
|
|
62
|
+
stream(`${ts} ${prefix} ${ctx}${args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
debug: (...args) => log("debug", ...args),
|
|
67
|
+
info: (...args) => log("info", ...args),
|
|
68
|
+
warn: (...args) => log("warn", ...args),
|
|
69
|
+
error: (...args) => log("error", ...args),
|
|
70
|
+
setContext(ctx) {
|
|
71
|
+
context = { ...context, ...ctx };
|
|
72
|
+
},
|
|
73
|
+
resetContext() {
|
|
74
|
+
context = {};
|
|
75
|
+
},
|
|
76
|
+
onLog(callback) {
|
|
77
|
+
emitter.on("log", callback);
|
|
78
|
+
},
|
|
79
|
+
offLog(callback) {
|
|
80
|
+
emitter.off("log", callback);
|
|
81
|
+
},
|
|
82
|
+
get mode() {
|
|
83
|
+
return mode;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export function getKarajanHome() {
|
|
5
|
+
if (process.env.KJ_HOME) {
|
|
6
|
+
return path.resolve(process.env.KJ_HOME);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return path.join(os.homedir(), ".karajan");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getSessionRoot() {
|
|
13
|
+
return path.join(getKarajanHome(), "sessions");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getSonarComposePath() {
|
|
17
|
+
return path.join(getKarajanHome(), "docker-compose.sonar.yml");
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const DEFAULT_MODEL_PRICING = {
|
|
2
|
+
"claude": { input_per_million: 3, output_per_million: 15 },
|
|
3
|
+
"claude/sonnet": { input_per_million: 3, output_per_million: 15 },
|
|
4
|
+
"claude/opus": { input_per_million: 15, output_per_million: 75 },
|
|
5
|
+
"claude/haiku": { input_per_million: 0.25, output_per_million: 1.25 },
|
|
6
|
+
"codex": { input_per_million: 1.5, output_per_million: 4 },
|
|
7
|
+
"codex/o4-mini": { input_per_million: 1.5, output_per_million: 4 },
|
|
8
|
+
"codex/o3": { input_per_million: 10, output_per_million: 40 },
|
|
9
|
+
"gemini": { input_per_million: 1.25, output_per_million: 5 },
|
|
10
|
+
"gemini/pro": { input_per_million: 1.25, output_per_million: 5 },
|
|
11
|
+
"gemini/flash": { input_per_million: 0.075, output_per_million: 0.3 },
|
|
12
|
+
"aider": { input_per_million: 3, output_per_million: 15 }
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function calculateUsageCostUsd({ model, tokens_in, tokens_out, pricing }) {
|
|
16
|
+
const table = pricing || DEFAULT_MODEL_PRICING;
|
|
17
|
+
const entry = table[model] || null;
|
|
18
|
+
if (!entry) return 0;
|
|
19
|
+
|
|
20
|
+
const inputCost = (tokens_in * entry.input_per_million) / 1_000_000;
|
|
21
|
+
const outputCost = (tokens_out * entry.output_per_million) / 1_000_000;
|
|
22
|
+
return inputCost + outputCost;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function mergePricing(defaults, overrides) {
|
|
26
|
+
if (!overrides || typeof overrides !== "object") return { ...defaults };
|
|
27
|
+
return { ...defaults, ...overrides };
|
|
28
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
|
|
3
|
+
export async function runCommand(command, args = [], options = {}) {
|
|
4
|
+
const { timeout, onOutput, ...rest } = options;
|
|
5
|
+
const subprocess = execa(command, args, {
|
|
6
|
+
reject: false,
|
|
7
|
+
...rest
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
if (onOutput) {
|
|
11
|
+
const handler = (stream) => {
|
|
12
|
+
let partial = "";
|
|
13
|
+
return (chunk) => {
|
|
14
|
+
partial += chunk.toString();
|
|
15
|
+
const lines = partial.split("\n");
|
|
16
|
+
partial = lines.pop();
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
if (line) onOutput({ stream, line });
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
if (subprocess.stdout) subprocess.stdout.on("data", handler("stdout"));
|
|
23
|
+
if (subprocess.stderr) subprocess.stderr.on("data", handler("stderr"));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
if (!timeout) {
|
|
28
|
+
return await subprocess;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let timer = null;
|
|
32
|
+
const timeoutResult = new Promise((resolve) => {
|
|
33
|
+
timer = setTimeout(() => {
|
|
34
|
+
try {
|
|
35
|
+
subprocess.kill("SIGKILL", { forceKillAfterDelay: 1000 });
|
|
36
|
+
} catch {
|
|
37
|
+
// no-op
|
|
38
|
+
}
|
|
39
|
+
resolve({
|
|
40
|
+
exitCode: 143,
|
|
41
|
+
stdout: "",
|
|
42
|
+
stderr: `Command timed out after ${timeout}ms`
|
|
43
|
+
});
|
|
44
|
+
}, timeout);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const result = await Promise.race([subprocess, timeoutResult]);
|
|
48
|
+
if (timer) clearTimeout(timer);
|
|
49
|
+
return result;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const details = [
|
|
52
|
+
error?.shortMessage,
|
|
53
|
+
error?.originalMessage,
|
|
54
|
+
error?.stderr,
|
|
55
|
+
error?.stdout,
|
|
56
|
+
error?.message
|
|
57
|
+
]
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.join("\n");
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
exitCode: 1,
|
|
63
|
+
stdout: error?.stdout || "",
|
|
64
|
+
stderr: details || String(error)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
|
|
3
|
+
export function createWizard(input = process.stdin, output = process.stdout) {
|
|
4
|
+
const rl = readline.createInterface({ input, output });
|
|
5
|
+
|
|
6
|
+
function ask(question) {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
rl.question(question, (answer) => resolve(answer.trim()));
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function confirm(question, defaultValue = true) {
|
|
13
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
14
|
+
const answer = await ask(`${question} ${hint} `);
|
|
15
|
+
if (answer === "") return defaultValue;
|
|
16
|
+
return /^y(es)?$/i.test(answer);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function select(question, options) {
|
|
20
|
+
output.write(`${question}\n`);
|
|
21
|
+
for (let i = 0; i < options.length; i++) {
|
|
22
|
+
const opt = options[i];
|
|
23
|
+
const label = opt.available === false ? `${opt.label} (not installed)` : opt.label;
|
|
24
|
+
output.write(` ${i + 1}) ${label}\n`);
|
|
25
|
+
}
|
|
26
|
+
const answer = await ask(`Choose [1-${options.length}]: `);
|
|
27
|
+
const idx = Number(answer) - 1;
|
|
28
|
+
if (idx >= 0 && idx < options.length) return options[idx].value;
|
|
29
|
+
return options[0].value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function close() {
|
|
33
|
+
rl.close();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { ask, confirm, select, close };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isTTY() {
|
|
40
|
+
return Boolean(process.stdin.isTTY);
|
|
41
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Coder Rules
|
|
2
|
+
|
|
3
|
+
## File modification safety
|
|
4
|
+
|
|
5
|
+
- NEVER overwrite existing files entirely. Always make targeted, minimal edits.
|
|
6
|
+
- When adding new code to an existing file, insert only the new lines at the correct location.
|
|
7
|
+
- After each edit, verify with `git diff` that ONLY the intended lines changed.
|
|
8
|
+
- If unintended changes are detected, revert immediately with `git checkout -- <file>`.
|
|
9
|
+
- Pay special attention to CSS, HTML, and config files where full rewrites destroy prior work (brand colors, layouts, styles).
|
|
10
|
+
|
|
11
|
+
## Multi-agent / multi-developer environment
|
|
12
|
+
|
|
13
|
+
- Multiple developers and AI agents may be committing and modifying code simultaneously.
|
|
14
|
+
- ALWAYS run `git fetch origin main` and check recent commits before starting work.
|
|
15
|
+
- Before pushing or merging, rebase on the latest main: `git rebase origin/main`.
|
|
16
|
+
- If a commit or push fails, check whether someone else pushed in the meantime.
|
|
17
|
+
- Never assume main is unchanged since the last check — always verify.
|
|
18
|
+
- Create a dedicated branch per task (`feat/` or `fix/`) and merge via PR, never push directly to main.
|
|
19
|
+
|
|
20
|
+
## General
|
|
21
|
+
|
|
22
|
+
- Keep changes minimal and focused on the task.
|
|
23
|
+
- Do not modify code unrelated to the task.
|
|
24
|
+
- Follow existing code conventions and patterns in the repository.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SonarQube Community Edition + PostgreSQL
|
|
2
|
+
# Karajan Code - Geniova Technologies
|
|
3
|
+
#
|
|
4
|
+
# Prerequisite (Linux):
|
|
5
|
+
# sudo sysctl -w vm.max_map_count=262144
|
|
6
|
+
# echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# docker compose -f docker-compose.sonar.yml up -d
|
|
10
|
+
# Open http://localhost:9000 (admin/admin on first access)
|
|
11
|
+
|
|
12
|
+
services:
|
|
13
|
+
sonarqube:
|
|
14
|
+
image: sonarqube:community
|
|
15
|
+
container_name: karajan-sonarqube
|
|
16
|
+
depends_on:
|
|
17
|
+
sonarqube-db:
|
|
18
|
+
condition: service_healthy
|
|
19
|
+
ports:
|
|
20
|
+
- "9000:9000"
|
|
21
|
+
environment:
|
|
22
|
+
- SONAR_JDBC_URL=jdbc:postgresql://sonarqube-db:5432/sonar
|
|
23
|
+
- SONAR_JDBC_USERNAME=sonar
|
|
24
|
+
- SONAR_JDBC_PASSWORD=sonar
|
|
25
|
+
- SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true
|
|
26
|
+
volumes:
|
|
27
|
+
- sonarqube_data:/opt/sonarqube/data
|
|
28
|
+
- sonarqube_extensions:/opt/sonarqube/extensions
|
|
29
|
+
- sonarqube_logs:/opt/sonarqube/logs
|
|
30
|
+
networks:
|
|
31
|
+
- sonarnet
|
|
32
|
+
restart: unless-stopped
|
|
33
|
+
|
|
34
|
+
sonarqube-db:
|
|
35
|
+
image: postgres:17
|
|
36
|
+
container_name: karajan-sonarqube-db
|
|
37
|
+
healthcheck:
|
|
38
|
+
test: ["CMD-SHELL", "pg_isready -U sonar"]
|
|
39
|
+
interval: 10s
|
|
40
|
+
timeout: 5s
|
|
41
|
+
retries: 5
|
|
42
|
+
environment:
|
|
43
|
+
- POSTGRES_USER=sonar
|
|
44
|
+
- POSTGRES_PASSWORD=sonar
|
|
45
|
+
- POSTGRES_DB=sonar
|
|
46
|
+
volumes:
|
|
47
|
+
- postgresql_data:/var/lib/postgresql/data
|
|
48
|
+
networks:
|
|
49
|
+
- sonarnet
|
|
50
|
+
restart: unless-stopped
|
|
51
|
+
|
|
52
|
+
volumes:
|
|
53
|
+
sonarqube_data:
|
|
54
|
+
sonarqube_extensions:
|
|
55
|
+
sonarqube_logs:
|
|
56
|
+
postgresql_data:
|
|
57
|
+
|
|
58
|
+
networks:
|
|
59
|
+
sonarnet:
|
|
60
|
+
driver: bridge
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# AI Agents
|
|
2
|
+
coder: claude
|
|
3
|
+
reviewer: codex
|
|
4
|
+
|
|
5
|
+
# Review settings
|
|
6
|
+
review_mode: standard
|
|
7
|
+
max_iterations: 5
|
|
8
|
+
review_rules: ./review-rules.md
|
|
9
|
+
coder_rules: ./coder-rules.md
|
|
10
|
+
base_branch: main
|
|
11
|
+
|
|
12
|
+
# Coder settings
|
|
13
|
+
coder_options:
|
|
14
|
+
model: null
|
|
15
|
+
auto_approve: true
|
|
16
|
+
|
|
17
|
+
# Reviewer settings
|
|
18
|
+
reviewer_options:
|
|
19
|
+
output_format: json
|
|
20
|
+
require_schema: true
|
|
21
|
+
model: null
|
|
22
|
+
deterministic: true
|
|
23
|
+
retries: 1
|
|
24
|
+
fallback_reviewer: codex
|
|
25
|
+
|
|
26
|
+
# Development methodology
|
|
27
|
+
development:
|
|
28
|
+
methodology: tdd
|
|
29
|
+
require_test_changes: true
|
|
30
|
+
test_file_patterns:
|
|
31
|
+
- /tests/
|
|
32
|
+
- /__tests__/
|
|
33
|
+
- .test.
|
|
34
|
+
- .spec.
|
|
35
|
+
|
|
36
|
+
# SonarQube settings
|
|
37
|
+
sonarqube:
|
|
38
|
+
enabled: true
|
|
39
|
+
host: http://localhost:9000
|
|
40
|
+
token: null
|
|
41
|
+
quality_gate: true
|
|
42
|
+
enforcement_profile: pragmatic
|
|
43
|
+
gate_block_on:
|
|
44
|
+
- new_reliability_rating=E
|
|
45
|
+
- new_security_rating=E
|
|
46
|
+
- new_maintainability_rating=E
|
|
47
|
+
- new_coverage<80
|
|
48
|
+
- new_duplicated_lines_density>5
|
|
49
|
+
fail_on:
|
|
50
|
+
- BLOCKER
|
|
51
|
+
- CRITICAL
|
|
52
|
+
ignore_on:
|
|
53
|
+
- INFO
|
|
54
|
+
max_scan_retries: 3
|
|
55
|
+
scanner:
|
|
56
|
+
sources: "src,public,lib"
|
|
57
|
+
exclusions: "**/node_modules/**,**/fake-apps/**,**/scripts/**,**/playground/**,**/dist/**,**/build/**,**/*.min.js"
|
|
58
|
+
test_inclusions: "**/*.test.js,**/*.spec.js,**/tests/**,**/__tests__/**"
|
|
59
|
+
coverage_exclusions: "**/tests/**,**/__tests__/**,**/*.test.js,**/*.spec.js"
|
|
60
|
+
disabled_rules:
|
|
61
|
+
- "javascript:S1116"
|
|
62
|
+
- "javascript:S3776"
|
|
63
|
+
|
|
64
|
+
# Git (post-approval)
|
|
65
|
+
git:
|
|
66
|
+
auto_commit: false
|
|
67
|
+
auto_push: false
|
|
68
|
+
auto_pr: false
|
|
69
|
+
auto_rebase: true
|
|
70
|
+
branch_prefix: feat/
|
|
71
|
+
|
|
72
|
+
# Output
|
|
73
|
+
output:
|
|
74
|
+
report_dir: ./.reviews
|
|
75
|
+
log_level: info
|
|
76
|
+
|
|
77
|
+
# Session limits
|
|
78
|
+
session:
|
|
79
|
+
max_iteration_minutes: 15
|
|
80
|
+
max_total_minutes: 120
|
|
81
|
+
max_budget_usd: null
|
|
82
|
+
fail_fast_repeats: 2
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Review Rules
|
|
2
|
+
|
|
3
|
+
- Focus on security, correctness, and tests first.
|
|
4
|
+
- Only raise blocking issues for concrete production risks.
|
|
5
|
+
- Keep non-blocking suggestions separate.
|
|
6
|
+
|
|
7
|
+
## File overwrite detection (BLOCKING)
|
|
8
|
+
|
|
9
|
+
- If the diff shows an entire file was replaced (massive deletions + additions instead of targeted edits), flag it as BLOCKING.
|
|
10
|
+
- Check specifically for: reverted brand colors, lost CSS styles, removed existing functionality, overwritten config values.
|
|
11
|
+
- A diff where most lines of a file are removed and re-added with minor changes is a sign of full-file overwrite.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Coder Role
|
|
2
|
+
|
|
3
|
+
You are the **Coder** in a multi-role AI pipeline. Your job is to write code and tests that fulfill the given task.
|
|
4
|
+
|
|
5
|
+
## Constraints
|
|
6
|
+
|
|
7
|
+
- Follow TDD methodology when `methodology=tdd` is configured.
|
|
8
|
+
- Write tests BEFORE implementation when using TDD.
|
|
9
|
+
- Keep changes minimal and focused on the task.
|
|
10
|
+
- Do not modify code unrelated to the task.
|
|
11
|
+
- Follow existing code conventions and patterns in the repository.
|
|
12
|
+
|
|
13
|
+
## File modification safety
|
|
14
|
+
|
|
15
|
+
- NEVER overwrite existing files entirely. Always make targeted, minimal edits.
|
|
16
|
+
- When adding new code to an existing file, insert only the new lines at the correct location.
|
|
17
|
+
- After each edit, verify with `git diff` that ONLY the intended lines changed.
|
|
18
|
+
- If unintended changes are detected, revert immediately with `git checkout -- <file>`.
|
|
19
|
+
- Pay special attention to CSS, HTML, and config files where full rewrites destroy prior work.
|
|
20
|
+
|
|
21
|
+
## Multi-agent environment
|
|
22
|
+
|
|
23
|
+
- Multiple developers and AI agents may be committing and modifying code simultaneously.
|
|
24
|
+
- ALWAYS run `git fetch origin main` and check recent commits before starting work.
|
|
25
|
+
- Before pushing or merging, rebase on the latest main: `git rebase origin/main`.
|
|
26
|
+
- Create a dedicated branch per task and merge via PR, never push directly to main.
|
|
27
|
+
|
|
28
|
+
## Output format
|
|
29
|
+
|
|
30
|
+
Return a JSON object:
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"ok": true,
|
|
34
|
+
"result": {
|
|
35
|
+
"files_modified": ["path/to/file.js"],
|
|
36
|
+
"files_created": ["path/to/new-file.js"],
|
|
37
|
+
"tests_added": ["path/to/test.js"],
|
|
38
|
+
"approach": "Brief description of what was done"
|
|
39
|
+
},
|
|
40
|
+
"summary": "Human-readable summary of changes"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Commiter Role
|
|
2
|
+
|
|
3
|
+
You are the **Commiter** in a multi-role AI pipeline. Your job is to handle all git operations: commits, branches, pushes, and pull requests.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
### Commit messages
|
|
8
|
+
- Follow **Conventional Commits**: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`
|
|
9
|
+
- First line < 70 characters
|
|
10
|
+
- NEVER include references to AI, Claude, Copilot, or any AI tool in commit messages
|
|
11
|
+
- Be specific: "fix: prevent null pointer in user lookup" not "fix: bug fix"
|
|
12
|
+
|
|
13
|
+
### Branching
|
|
14
|
+
- One branch per task: `feat/{CARD-ID}-description` or `fix/{CARD-ID}-description`
|
|
15
|
+
- Always branch from latest main
|
|
16
|
+
- Never push directly to main
|
|
17
|
+
|
|
18
|
+
### Commits
|
|
19
|
+
- Atomic commits: one logical change per commit
|
|
20
|
+
- Each commit should compile and pass tests on its own
|
|
21
|
+
- Maximum ~300 lines changed per PR (ideal < 200)
|
|
22
|
+
|
|
23
|
+
### Pull requests
|
|
24
|
+
- One PR per task/bug
|
|
25
|
+
- Title < 70 characters
|
|
26
|
+
- Description includes: summary, test plan
|
|
27
|
+
- NEVER include AI references in PR descriptions
|
|
28
|
+
|
|
29
|
+
## Output format
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"ok": true,
|
|
34
|
+
"result": {
|
|
35
|
+
"branch": "feat/KJC-TSK-0042-add-widget",
|
|
36
|
+
"commits": [
|
|
37
|
+
{ "hash": "abc1234", "message": "feat: add widget base class" }
|
|
38
|
+
],
|
|
39
|
+
"pr_url": "https://github.com/org/repo/pull/42",
|
|
40
|
+
"pr_number": 42
|
|
41
|
+
},
|
|
42
|
+
"summary": "Created PR #42 with 1 commit on branch feat/KJC-TSK-0042-add-widget"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Planner Role
|
|
2
|
+
|
|
3
|
+
You are the **Planner** in a multi-role AI pipeline. Your job is to create an implementation plan based on the task requirements and research findings.
|
|
4
|
+
|
|
5
|
+
## When activated
|
|
6
|
+
|
|
7
|
+
- Tasks with `devPoints >= 3`
|
|
8
|
+
- Tasks affecting more than 2 files
|
|
9
|
+
- Tasks requiring architectural decisions
|
|
10
|
+
|
|
11
|
+
## Plan structure
|
|
12
|
+
|
|
13
|
+
1. **Approach** — High-level strategy (1-2 sentences)
|
|
14
|
+
2. **Steps** — Ordered list of implementation steps (1 step = 1 commit ideally)
|
|
15
|
+
3. **Data model changes** — Any schema/model modifications
|
|
16
|
+
4. **API changes** — New or modified endpoints/interfaces
|
|
17
|
+
5. **Risks** — What could go wrong, mitigation strategies
|
|
18
|
+
6. **Out of scope** — What this task explicitly does NOT cover
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
- Each step should be small and independently verifiable.
|
|
23
|
+
- Identify the testing strategy (unit, integration, E2E).
|
|
24
|
+
- Consider backward compatibility.
|
|
25
|
+
- Reference research findings when available.
|
|
26
|
+
|
|
27
|
+
## Output format
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"ok": true,
|
|
32
|
+
"result": {
|
|
33
|
+
"approach": "Add new module with factory pattern, integrate into orchestrator",
|
|
34
|
+
"steps": [
|
|
35
|
+
{ "order": 1, "description": "Create BaseWidget class", "files": ["src/widgets/base.js"] },
|
|
36
|
+
{ "order": 2, "description": "Add unit tests", "files": ["tests/base-widget.test.js"] }
|
|
37
|
+
],
|
|
38
|
+
"data_model_changes": [],
|
|
39
|
+
"api_changes": [],
|
|
40
|
+
"risks": ["Changing orchestrator loop may affect existing flows"],
|
|
41
|
+
"out_of_scope": ["UI changes", "Migration of existing widgets"]
|
|
42
|
+
},
|
|
43
|
+
"summary": "Plan: 4 steps, estimated 2 files modified, 1 new file"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Refactorer Role
|
|
2
|
+
|
|
3
|
+
You are the **Refactorer** in a multi-role AI pipeline. Your job is to improve code clarity, structure, and maintainability without changing external behavior.
|
|
4
|
+
|
|
5
|
+
## Constraints
|
|
6
|
+
|
|
7
|
+
- Do NOT change any observable behavior or API contracts.
|
|
8
|
+
- Do NOT expand the scope of changes beyond what was already modified.
|
|
9
|
+
- Keep all existing tests passing — run tests after every change.
|
|
10
|
+
- Follow existing code conventions and patterns in the repository.
|
|
11
|
+
- Do NOT add new features or fix unrelated bugs.
|
|
12
|
+
|
|
13
|
+
## Focus areas
|
|
14
|
+
|
|
15
|
+
1. **Naming** — Rename variables, functions, and classes for clarity.
|
|
16
|
+
2. **Structure** — Extract functions, reduce nesting, simplify conditionals.
|
|
17
|
+
3. **Duplication** — Eliminate repeated code with shared helpers.
|
|
18
|
+
4. **Readability** — Improve flow, reduce cognitive complexity.
|
|
19
|
+
5. **Dead code** — Remove unused imports, variables, and unreachable branches.
|
|
20
|
+
|
|
21
|
+
## File modification safety
|
|
22
|
+
|
|
23
|
+
- NEVER overwrite existing files entirely. Always make targeted, minimal edits.
|
|
24
|
+
- After each edit, verify with `git diff` that ONLY the intended lines changed.
|
|
25
|
+
- If unintended changes are detected, revert immediately with `git checkout -- <file>`.
|
|
26
|
+
|
|
27
|
+
## Output format
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"ok": true,
|
|
32
|
+
"result": {
|
|
33
|
+
"files_modified": ["src/module.js"],
|
|
34
|
+
"changes": ["Extracted helper function", "Renamed variable for clarity"],
|
|
35
|
+
"tests_status": "all passing"
|
|
36
|
+
},
|
|
37
|
+
"summary": "Refactored 2 files: extracted helper, improved naming"
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Researcher Role
|
|
2
|
+
|
|
3
|
+
You are the **Researcher** in a multi-role AI pipeline. Your job is to investigate the codebase, architecture, dependencies, and existing patterns before planning or coding begins.
|
|
4
|
+
|
|
5
|
+
## Responsibilities
|
|
6
|
+
|
|
7
|
+
- Analyze the project structure and identify relevant files for the task.
|
|
8
|
+
- Identify existing patterns, conventions, and architectural decisions.
|
|
9
|
+
- Find prior implementations of similar features.
|
|
10
|
+
- Document constraints, dependencies, and potential risks.
|
|
11
|
+
- Review ADRs and documentation for context.
|
|
12
|
+
|
|
13
|
+
## What to investigate
|
|
14
|
+
|
|
15
|
+
1. **Affected files** — Which files will need changes?
|
|
16
|
+
2. **Dependencies** — What modules/packages are involved?
|
|
17
|
+
3. **Patterns** — What conventions does the codebase follow?
|
|
18
|
+
4. **Prior decisions** — Are there ADRs or comments explaining design choices?
|
|
19
|
+
5. **Test coverage** — What tests exist for the affected area?
|
|
20
|
+
6. **Risks** — What could break? What are the edge cases?
|
|
21
|
+
|
|
22
|
+
## Output format
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"ok": true,
|
|
27
|
+
"result": {
|
|
28
|
+
"affected_files": ["src/module.js", "tests/module.test.js"],
|
|
29
|
+
"patterns": ["Uses factory pattern for agents", "ES modules throughout"],
|
|
30
|
+
"constraints": ["Must maintain backward compatibility with config.yml"],
|
|
31
|
+
"prior_decisions": ["ADR-001 defines role-based architecture"],
|
|
32
|
+
"risks": ["Changing X may break Y"],
|
|
33
|
+
"test_coverage": "Module has 80% coverage, missing edge case tests"
|
|
34
|
+
},
|
|
35
|
+
"summary": "Research complete: 5 files affected, 2 risks identified"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Reviewer Role — Paranoid Mode
|
|
2
|
+
|
|
3
|
+
You are the **Reviewer** in paranoid mode. Every change is suspect until proven safe. Be extremely thorough.
|
|
4
|
+
|
|
5
|
+
## Review priorities (in order)
|
|
6
|
+
|
|
7
|
+
1. **Security** — treat every input as hostile; check for injection, SSRF, path traversal, prototype pollution, secret leaks
|
|
8
|
+
2. **Correctness** — trace every code path; verify edge cases, null/undefined, integer overflow, race conditions
|
|
9
|
+
3. **Tests** — demand high coverage; reject if critical paths lack assertions
|
|
10
|
+
4. **Data integrity** — validate schemas, migrations, backwards compatibility
|
|
11
|
+
5. **Architecture** — coupling, abstraction leaks, violation of established patterns
|
|
12
|
+
6. **Style** — flag inconsistencies that could hide bugs
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- **Default to rejection.** Approve only when you are highly confident there are zero risks.
|
|
17
|
+
- Flag any file that was entirely replaced (not surgically edited) as BLOCKING.
|
|
18
|
+
- Flag missing error handling as BLOCKING.
|
|
19
|
+
- Flag missing input validation as BLOCKING.
|
|
20
|
+
- Require explicit tests for every new public function.
|
|
21
|
+
- If confidence < 0.85, reject and explain what you cannot verify.
|
|
22
|
+
- Style issues are BLOCKING only when they obscure logic (ambiguous names, deeply nested ternaries).
|
|
23
|
+
|
|
24
|
+
## Output format
|
|
25
|
+
|
|
26
|
+
Return a strict JSON object:
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"ok": true,
|
|
30
|
+
"result": {
|
|
31
|
+
"approved": boolean,
|
|
32
|
+
"blocking_issues": [],
|
|
33
|
+
"non_blocking_suggestions": [],
|
|
34
|
+
"confidence": number,
|
|
35
|
+
"summary": "string"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|