karajan-code 1.59.0 → 2.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 -0
- package/package.json +1 -1
- package/scripts/install.js +18 -15
- package/src/agents/aider-agent.js +0 -7
- package/src/agents/claude-agent.js +34 -6
- package/src/agents/codex-agent.js +2 -6
- package/src/agents/gemini-agent.js +0 -4
- package/src/agents/opencode-agent.js +0 -4
- package/src/{becaria → ci}/dispatch.js +13 -13
- package/src/{becaria → ci}/pr-diff.js +1 -1
- package/src/cli.js +3 -2
- package/src/commands/agents.js +0 -1
- package/src/commands/doctor.js +22 -40
- package/src/commands/init.js +8 -8
- package/src/commands/report.js +0 -13
- package/src/commands/review.js +17 -17
- package/src/commands/run.js +1 -2
- package/src/commands/status.js +1 -7
- package/src/config.js +10 -52
- package/src/domains/domain-loader.js +85 -4
- package/src/git/automation.js +9 -9
- package/src/guards/output-guard.js +0 -17
- package/src/mcp/handlers/direct-handlers.js +1 -1
- package/src/mcp/handlers/run-handler.js +1 -2
- package/src/mcp/sovereignty-guard.js +2 -2
- package/src/mcp/tools.js +3 -2
- package/src/orchestrator/brain-coordinator.js +165 -0
- package/src/orchestrator/ci-integration.js +139 -0
- package/src/orchestrator/config-init.js +435 -0
- package/src/orchestrator/direct-actions.js +186 -0
- package/src/orchestrator/feedback-enrichment.js +140 -0
- package/src/orchestrator/feedback-queue.js +152 -0
- package/src/orchestrator/flow-control.js +159 -0
- package/src/orchestrator/post-loop-stages.js +20 -15
- package/src/orchestrator/preflight-checks.js +7 -3
- package/src/orchestrator/role-output-compressor.js +190 -0
- package/src/orchestrator/session-journal.js +344 -0
- package/src/orchestrator/solomon-escalation.js +38 -5
- package/src/orchestrator/solomon-rules.js +32 -33
- package/src/orchestrator/stages/reviewer-stage.js +16 -5
- package/src/orchestrator/stages/sonar-stage.js +24 -1
- package/src/orchestrator/verification-gate.js +146 -0
- package/src/orchestrator.js +435 -661
- package/src/planning-game/client.js +2 -2
- package/src/planning-game/pipeline-adapter.js +1 -1
- package/src/prompts/coder.js +17 -3
- package/src/prompts/reviewer.js +2 -2
- package/src/prompts/rtk-snippet.js +3 -5
- package/src/review/diff-generator.js +66 -17
- package/src/review/snapshot-diff.js +122 -0
- package/src/review/tdd-policy.js +4 -2
- package/src/roles/agent-role.js +135 -0
- package/src/roles/architect-role.js +61 -108
- package/src/roles/audit-role.js +25 -71
- package/src/roles/coder-role.js +32 -57
- package/src/roles/discover-role.js +30 -71
- package/src/roles/hu-reviewer-role.js +51 -99
- package/src/roles/impeccable-role.js +34 -91
- package/src/roles/index.js +2 -0
- package/src/roles/karajan-brain-role.js +134 -0
- package/src/roles/planner-role.js +40 -75
- package/src/roles/refactorer-role.js +22 -64
- package/src/roles/researcher-role.js +52 -118
- package/src/roles/reviewer-role.js +69 -126
- package/src/roles/security-role.js +38 -102
- package/src/roles/solomon-role.js +71 -15
- package/src/roles/tester-role.js +121 -95
- package/src/roles/triage-role.js +50 -111
- package/src/session-store.js +1 -1
- package/src/skills/skill-detector.js +11 -0
- package/src/sonar/config-resolver.js +20 -1
- package/src/sonar/credentials.js +17 -0
- package/src/sonar/project-key.js +1 -1
- package/src/sonar/scanner.js +1 -1
- package/src/utils/banner.js +66 -0
- package/src/utils/display.js +35 -17
- package/src/utils/injection-guard.js +23 -8
- package/src/utils/logger.js +6 -1
- package/src/utils/process.js +3 -4
- package/src/utils/role-assigner.js +131 -0
- package/src/utils/update-check.js +5 -1
- package/src/utils/welcome.js +3 -8
- package/src/webperf/devtools-detect.js +70 -23
- package/templates/roles/coder.md +7 -0
- package/templates/roles/karajan-brain.md +95 -0
- package/templates/roles/solomon.md +67 -106
- package/templates/workflows/automerge.yml +4 -4
- package/templates/workflows/houston-override.yml +4 -4
- package/templates/workflows/{becaria-gateway.yml → kj-ci-gateway.yml} +12 -12
- package/src/proxy/adapters/anthropic.js +0 -131
- package/src/proxy/adapters/gemini.js +0 -106
- package/src/proxy/adapters/index.js +0 -51
- package/src/proxy/adapters/openai.js +0 -71
- package/src/proxy/compression/ai-compressor.js +0 -209
- package/src/proxy/compression/dedup-cache.js +0 -100
- package/src/proxy/compression/deterministic/bash-build.js +0 -60
- package/src/proxy/compression/deterministic/bash-git.js +0 -101
- package/src/proxy/compression/deterministic/bash-infra.js +0 -64
- package/src/proxy/compression/deterministic/bash-misc.js +0 -53
- package/src/proxy/compression/deterministic/bash-pkg.js +0 -49
- package/src/proxy/compression/deterministic/bash-test.js +0 -61
- package/src/proxy/compression/deterministic/glob.js +0 -26
- package/src/proxy/compression/deterministic/grep.js +0 -53
- package/src/proxy/compression/deterministic/index.js +0 -58
- package/src/proxy/compression/deterministic/read.js +0 -22
- package/src/proxy/compression/deterministic/utils.js +0 -33
- package/src/proxy/compression/pipeline.js +0 -270
- package/src/proxy/middleware/prompt-injector.js +0 -165
- package/src/proxy/middleware/response-interceptor.js +0 -223
- package/src/proxy/progress-monitor.js +0 -98
- package/src/proxy/proxy-lifecycle.js +0 -198
- package/src/proxy/proxy-server.js +0 -239
- package/src/proxy/security.js +0 -45
- /package/src/{becaria → ci}/index.js +0 -0
- /package/src/{becaria → ci}/repo.js +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Smart role assignment based on available AI agents.
|
|
2
|
+
// Used by both kj init (interactive) and auto-init (non-interactive).
|
|
3
|
+
|
|
4
|
+
import { detectAvailableAgents } from "./agent-detect.js";
|
|
5
|
+
|
|
6
|
+
// Agent capability tiers (higher = more capable for complex reasoning)
|
|
7
|
+
const CAPABILITY_TIERS = {
|
|
8
|
+
claude: 5, // Best for reasoning, orchestration, complex tasks
|
|
9
|
+
codex: 4, // Strong coder, good reviewer
|
|
10
|
+
gemini: 3, // Good general purpose
|
|
11
|
+
aider: 2, // Good coder, limited reasoning
|
|
12
|
+
opencode: 2 // Similar to aider
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Role requirements: what capability level is ideal for each role
|
|
16
|
+
const ROLE_PREFERENCES = {
|
|
17
|
+
brain: { minTier: 4, prefer: "claude", description: "Karajan Brain (orchestrator)" },
|
|
18
|
+
solomon: { minTier: 3, prefer: "gemini", description: "Solomon (judge/arbiter)" },
|
|
19
|
+
coder: { minTier: 2, prefer: "claude", description: "Coder" },
|
|
20
|
+
reviewer: { minTier: 3, prefer: "codex", description: "Reviewer" },
|
|
21
|
+
planner: { minTier: 4, prefer: "claude", description: "Planner" },
|
|
22
|
+
researcher: { minTier: 3, prefer: "claude", description: "Researcher" },
|
|
23
|
+
architect: { minTier: 4, prefer: "claude", description: "Architect" },
|
|
24
|
+
tester: { minTier: 3, prefer: "claude", description: "Tester" },
|
|
25
|
+
security: { minTier: 3, prefer: "claude", description: "Security" },
|
|
26
|
+
triage: { minTier: 3, prefer: "claude", description: "Triage" }
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Assign the best available agent to a role.
|
|
31
|
+
* Prefers the role's preferred agent if available, then falls back by capability tier.
|
|
32
|
+
*/
|
|
33
|
+
function assignRole(roleName, availableAgents) {
|
|
34
|
+
const pref = ROLE_PREFERENCES[roleName];
|
|
35
|
+
if (!pref) return availableAgents[0]?.name || "claude";
|
|
36
|
+
|
|
37
|
+
// Preferred agent available?
|
|
38
|
+
if (availableAgents.find(a => a.name === pref.prefer)) {
|
|
39
|
+
return pref.prefer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Sort by capability tier (descending) and pick the best available
|
|
43
|
+
const sorted = [...availableAgents].sort(
|
|
44
|
+
(a, b) => (CAPABILITY_TIERS[b.name] || 1) - (CAPABILITY_TIERS[a.name] || 1)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return sorted[0]?.name || "claude";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Try to diversify: if possible, use a different agent for reviewer than coder.
|
|
52
|
+
*/
|
|
53
|
+
function diversifyReviewer(coderAgent, availableAgents) {
|
|
54
|
+
const alternatives = availableAgents.filter(a => a.name !== coderAgent);
|
|
55
|
+
if (alternatives.length === 0) return coderAgent;
|
|
56
|
+
|
|
57
|
+
const sorted = [...alternatives].sort(
|
|
58
|
+
(a, b) => (CAPABILITY_TIERS[b.name] || 1) - (CAPABILITY_TIERS[a.name] || 1)
|
|
59
|
+
);
|
|
60
|
+
return sorted[0].name;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Auto-assign all roles based on detected agents. Non-interactive.
|
|
65
|
+
* Returns a config-ready object with role assignments.
|
|
66
|
+
*/
|
|
67
|
+
export async function autoAssignRoles(logger) {
|
|
68
|
+
const agents = await detectAvailableAgents();
|
|
69
|
+
const available = agents.filter(a => a.available);
|
|
70
|
+
|
|
71
|
+
if (available.length === 0) {
|
|
72
|
+
logger?.warn?.("No AI agents detected. Using claude as default for all roles.");
|
|
73
|
+
return { assignments: getDefaultAssignments("claude"), agents, available: [] };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
logger?.info?.(`Detected ${available.length} AI agent(s): ${available.map(a => `${a.name} (${a.version})`).join(", ")}`);
|
|
77
|
+
|
|
78
|
+
const coder = assignRole("coder", available);
|
|
79
|
+
const reviewer = available.length > 1 ? diversifyReviewer(coder, available) : coder;
|
|
80
|
+
const brain = assignRole("brain", available);
|
|
81
|
+
const solomon = available.length > 1 ? diversifyReviewer(brain, available) : brain;
|
|
82
|
+
|
|
83
|
+
const assignments = {
|
|
84
|
+
brain,
|
|
85
|
+
solomon,
|
|
86
|
+
coder,
|
|
87
|
+
reviewer,
|
|
88
|
+
planner: assignRole("planner", available),
|
|
89
|
+
researcher: assignRole("researcher", available),
|
|
90
|
+
architect: assignRole("architect", available),
|
|
91
|
+
tester: assignRole("tester", available),
|
|
92
|
+
security: assignRole("security", available),
|
|
93
|
+
triage: assignRole("triage", available)
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
logger?.info?.(`Role assignments: Brain=${brain}, Solomon=${solomon}, Coder=${coder}, Reviewer=${reviewer}`);
|
|
97
|
+
|
|
98
|
+
return { assignments, agents, available };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getDefaultAssignments(agent) {
|
|
102
|
+
return {
|
|
103
|
+
brain: agent, solomon: agent, coder: agent, reviewer: agent,
|
|
104
|
+
planner: agent, researcher: agent, architect: agent,
|
|
105
|
+
tester: agent, security: agent, triage: agent
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Apply role assignments to a Karajan config object.
|
|
111
|
+
*/
|
|
112
|
+
export function applyRoleAssignments(config, assignments) {
|
|
113
|
+
config.coder = assignments.coder;
|
|
114
|
+
config.reviewer = assignments.reviewer;
|
|
115
|
+
|
|
116
|
+
const roleNames = ["coder", "reviewer", "planner", "researcher", "architect",
|
|
117
|
+
"tester", "security", "triage", "solomon"];
|
|
118
|
+
|
|
119
|
+
for (const role of roleNames) {
|
|
120
|
+
config.roles = config.roles || {};
|
|
121
|
+
config.roles[role] = config.roles[role] || {};
|
|
122
|
+
config.roles[role].provider = assignments[role] || assignments.coder;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Brain is a new top-level config (not in roles yet — will be when KarajanBrainRole is implemented)
|
|
126
|
+
config.brain = { provider: assignments.brain };
|
|
127
|
+
|
|
128
|
+
return config;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { CAPABILITY_TIERS, ROLE_PREFERENCES };
|
|
@@ -20,7 +20,11 @@ export async function checkForUpdate(currentVersion) {
|
|
|
20
20
|
const cache = JSON.parse(raw);
|
|
21
21
|
if (cache.checkedAt && Date.now() - cache.checkedAt < CACHE_TTL_MS) {
|
|
22
22
|
if (!cache.latest || cache.latest === currentVersion) return null;
|
|
23
|
-
|
|
23
|
+
// Only show update if latest is actually NEWER than current
|
|
24
|
+
if (compareVersions(cache.latest, currentVersion) > 0) {
|
|
25
|
+
return { updateAvailable: true, latest: cache.latest, current: currentVersion };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
24
28
|
}
|
|
25
29
|
} catch { /* no cache or expired */ }
|
|
26
30
|
|
package/src/utils/welcome.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { printBanner } from "./banner.js";
|
|
2
|
+
|
|
1
3
|
const A = {
|
|
2
4
|
reset: "\x1b[0m",
|
|
3
5
|
bold: "\x1b[1m",
|
|
@@ -7,8 +9,6 @@ const A = {
|
|
|
7
9
|
yellow: "\x1b[33m",
|
|
8
10
|
};
|
|
9
11
|
|
|
10
|
-
const BAR = `${A.dim}${"─".repeat(44)}${A.reset}`;
|
|
11
|
-
|
|
12
12
|
const QUICK_START = [
|
|
13
13
|
["kj run <task>", "Run the full coder+reviewer pipeline"],
|
|
14
14
|
["kj init", "Initialize config and setup"],
|
|
@@ -24,12 +24,7 @@ const QUICK_START = [
|
|
|
24
24
|
* @param {object} [opts.config] - Loaded KJ config (optional, shows configured agents)
|
|
25
25
|
*/
|
|
26
26
|
export function printWelcomeScreen({ version, config = null }) {
|
|
27
|
-
|
|
28
|
-
console.log(BAR);
|
|
29
|
-
console.log(` ${A.bold}${A.cyan}▶ Karajan Code${A.reset} ${A.dim}v${version}${A.reset}`);
|
|
30
|
-
console.log(` ${A.dim}AI-powered coding pipeline${A.reset}`);
|
|
31
|
-
console.log(BAR);
|
|
32
|
-
console.log();
|
|
27
|
+
printBanner(version, { force: true });
|
|
33
28
|
|
|
34
29
|
if (config) {
|
|
35
30
|
const coder = config.roles?.coder?.provider || config.coder || "claude";
|
|
@@ -1,32 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
* Chrome DevTools MCP detection and WebPerf skill auto-installation.
|
|
3
|
-
*/
|
|
1
|
+
// Chrome DevTools MCP detection and WebPerf skill auto-installation.
|
|
4
2
|
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
5
6
|
import { isOpenSkillsAvailable, installSkill, listSkills } from "../skills/openskills-client.js";
|
|
6
7
|
|
|
7
|
-
/** Skill names
|
|
8
|
+
/** Skill names relevant for WebPerf analysis. Already installed globally via openskills. */
|
|
8
9
|
export const WEBPERF_SKILLS = [
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"optimize",
|
|
11
|
+
"audit",
|
|
12
|
+
"polish"
|
|
12
13
|
];
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Check whether Chrome DevTools MCP is configured and available.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @param {object} config — merged Karajan config
|
|
17
|
+
* Checks: (1) config flag, (2) Claude MCP config (~/.claude.json), (3) VS Code MCP settings.
|
|
18
|
+
* @param {object} config - merged Karajan config
|
|
19
19
|
* @returns {boolean}
|
|
20
20
|
*/
|
|
21
21
|
export function isDevToolsMcpAvailable(config) {
|
|
22
|
-
|
|
22
|
+
// Explicit config flag takes priority
|
|
23
|
+
if (config?.webperf?.devtools_mcp === true) return true;
|
|
24
|
+
if (config?.webperf?.devtools_mcp === false) return false;
|
|
25
|
+
|
|
26
|
+
// Check cached detection result
|
|
27
|
+
if (_devToolsDetected !== null) return _devToolsDetected;
|
|
28
|
+
|
|
29
|
+
// Not yet detected - return false (async detection runs at init)
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let _devToolsDetected = null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Auto-detect Chrome DevTools MCP from system configuration.
|
|
37
|
+
* Checks ~/.claude.json and VS Code MCP settings.
|
|
38
|
+
* Call once at pipeline init.
|
|
39
|
+
*/
|
|
40
|
+
export async function detectDevToolsMcp(logger) {
|
|
41
|
+
// Check Claude MCP config
|
|
42
|
+
const claudeConfigPath = path.join(os.homedir(), ".claude.json");
|
|
43
|
+
try {
|
|
44
|
+
const raw = await fs.readFile(claudeConfigPath, "utf8");
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
const mcpServers = parsed?.mcpServers || parsed?.mcp_servers || {};
|
|
47
|
+
if (mcpServers["chrome-devtools"] || mcpServers["chrome_devtools"]) {
|
|
48
|
+
_devToolsDetected = true;
|
|
49
|
+
logger?.info?.("Chrome DevTools MCP detected in ~/.claude.json");
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
} catch { /* file not found or parse error */ }
|
|
53
|
+
|
|
54
|
+
// Check VS Code MCP settings
|
|
55
|
+
const vscodePaths = [
|
|
56
|
+
path.join(os.homedir(), ".vscode", "settings.json"),
|
|
57
|
+
path.join(process.cwd(), ".vscode", "settings.json")
|
|
58
|
+
];
|
|
59
|
+
for (const vscPath of vscodePaths) {
|
|
60
|
+
try {
|
|
61
|
+
const raw = await fs.readFile(vscPath, "utf8");
|
|
62
|
+
if (raw.includes("chrome-devtools") || raw.includes("chrome_devtools")) {
|
|
63
|
+
_devToolsDetected = true;
|
|
64
|
+
logger?.info?.(`Chrome DevTools MCP detected in ${vscPath}`);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
} catch { /* not found */ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_devToolsDetected = false;
|
|
71
|
+
return false;
|
|
23
72
|
}
|
|
24
73
|
|
|
25
74
|
/**
|
|
26
75
|
* Ensure WebPerf skills are installed via OpenSkills.
|
|
27
76
|
* Installs any missing skills from WEBPERF_SKILLS.
|
|
28
|
-
* @param {string} projectDir
|
|
29
|
-
* @param {object} [logger]
|
|
77
|
+
* @param {string} projectDir - absolute path to the project root
|
|
78
|
+
* @param {object} [logger] - optional logger ({ info, warn })
|
|
30
79
|
* @returns {Promise<{ installed: string[], alreadyInstalled: string[], skipped: string[] }>}
|
|
31
80
|
*/
|
|
32
81
|
export async function ensureWebPerfSkills(projectDir, logger) {
|
|
@@ -34,12 +83,12 @@ export async function ensureWebPerfSkills(projectDir, logger) {
|
|
|
34
83
|
|
|
35
84
|
const available = await isOpenSkillsAvailable();
|
|
36
85
|
if (!available) {
|
|
37
|
-
logger?.
|
|
86
|
+
logger?.debug?.("OpenSkills CLI not available - WebPerf skills unavailable");
|
|
38
87
|
result.skipped = [...WEBPERF_SKILLS];
|
|
39
88
|
return result;
|
|
40
89
|
}
|
|
41
90
|
|
|
42
|
-
//
|
|
91
|
+
// List skills (includes global installs)
|
|
43
92
|
const listResult = await listSkills({ projectDir });
|
|
44
93
|
const installedNames = new Set(
|
|
45
94
|
(listResult.ok ? listResult.skills : []).map(s => s.name)
|
|
@@ -48,18 +97,16 @@ export async function ensureWebPerfSkills(projectDir, logger) {
|
|
|
48
97
|
for (const skill of WEBPERF_SKILLS) {
|
|
49
98
|
if (installedNames.has(skill)) {
|
|
50
99
|
result.alreadyInstalled.push(skill);
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const installResult = await installSkill(skill, { projectDir });
|
|
55
|
-
if (installResult.ok) {
|
|
56
|
-
result.installed.push(skill);
|
|
57
|
-
logger?.info?.(`Installed WebPerf skill: ${skill}`);
|
|
58
100
|
} else {
|
|
101
|
+
// Skills should be installed globally via `openskills install owner/repo`
|
|
102
|
+
// Don't attempt auto-install with bare names — just note they're missing
|
|
59
103
|
result.skipped.push(skill);
|
|
60
|
-
logger?.warn?.(`Failed to install WebPerf skill "${skill}": ${installResult.error}`);
|
|
61
104
|
}
|
|
62
105
|
}
|
|
63
106
|
|
|
107
|
+
if (result.alreadyInstalled.length > 0) {
|
|
108
|
+
logger?.info?.(`WebPerf skills available: ${result.alreadyInstalled.join(", ")}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
64
111
|
return result;
|
|
65
112
|
}
|
package/templates/roles/coder.md
CHANGED
|
@@ -45,6 +45,13 @@ Before reporting done, verify that ALL parts of the task are addressed:
|
|
|
45
45
|
- If unintended changes are detected, revert immediately with `git checkout -- <file>`.
|
|
46
46
|
- Pay special attention to CSS, HTML, and config files where full rewrites destroy prior work.
|
|
47
47
|
|
|
48
|
+
## Code Quality Rules
|
|
49
|
+
|
|
50
|
+
- Follow SOLID principles. Write small, focused functions (< 30 lines).
|
|
51
|
+
- Make atomic commits: 1 logical change = 1 commit. Keep PRs small and reviewable.
|
|
52
|
+
- Security: use httpOnly cookies for auth tokens, validate all input, parameterize queries, never expose secrets.
|
|
53
|
+
- No console.log in production code -- use a structured logger. No 'any' types -- use JSDoc annotations.
|
|
54
|
+
|
|
48
55
|
## Output format
|
|
49
56
|
|
|
50
57
|
Return a JSON object:
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Karajan Brain — Central Pipeline Orchestrator
|
|
2
|
+
|
|
3
|
+
You are the central intelligence of the Karajan pipeline. Every role output passes through you. You decide what happens next.
|
|
4
|
+
|
|
5
|
+
## Your responsibilities
|
|
6
|
+
|
|
7
|
+
1. **Route** — decide which role runs next based on current state
|
|
8
|
+
2. **Enrich** — transform vague feedback into concrete, actionable instructions
|
|
9
|
+
3. **Verify** — check that each role actually did its job before moving on
|
|
10
|
+
4. **Act directly** — execute commands when a full role invocation isn't needed
|
|
11
|
+
5. **Consult Solomon** — only when facing a genuine dilemma
|
|
12
|
+
|
|
13
|
+
## Skills
|
|
14
|
+
|
|
15
|
+
### 1. route-decision
|
|
16
|
+
Decide the next role based on pipeline state.
|
|
17
|
+
- If coder just finished successfully → reviewer
|
|
18
|
+
- If reviewer approved → next quality gate (tester/security/impeccable) or done
|
|
19
|
+
- If reviewer rejected with issues → coder (with enriched feedback)
|
|
20
|
+
- If tester/security failed → coder (with specific fix instructions)
|
|
21
|
+
- If max iterations reached and still failing → consult Solomon
|
|
22
|
+
- If approved and all gates pass → done
|
|
23
|
+
|
|
24
|
+
### 2. prompt-enrichment
|
|
25
|
+
When feedback is vague, make it actionable.
|
|
26
|
+
- Identify concrete file paths from the project structure
|
|
27
|
+
- Add line numbers when possible
|
|
28
|
+
- Suggest specific code changes
|
|
29
|
+
- Break complex feedback into numbered steps
|
|
30
|
+
- Include test commands to run
|
|
31
|
+
|
|
32
|
+
Example transformation:
|
|
33
|
+
- Vague: "auth test suite missing refresh token coverage"
|
|
34
|
+
- Enriched: "In packages/server/tests/auth/, create refresh-token.test.js. Test cases: (1) POST /auth/refresh with valid token returns new pair, (2) expired token returns 401, (3) invalid token returns 401. Reference packages/server/src/auth/jwt.js for the refresh logic."
|
|
35
|
+
|
|
36
|
+
### 3. output-verification
|
|
37
|
+
Check that coder produced real changes before advancing.
|
|
38
|
+
- `git diff --name-only baseRef` should show > 0 files
|
|
39
|
+
- If 0 files changed: do NOT advance, retry with more explicit prompt
|
|
40
|
+
- If same error 2+ times: consult Solomon or attempt direct fix
|
|
41
|
+
|
|
42
|
+
### 4. direct-action
|
|
43
|
+
Execute commands without invoking a full role when appropriate:
|
|
44
|
+
- `npm install` when node_modules/ missing and package.json exists
|
|
45
|
+
- `.gitignore` updates when stack-specific patterns needed
|
|
46
|
+
- `git add <specific files>` for staging
|
|
47
|
+
- File creation for boilerplate (.env.example, README stub)
|
|
48
|
+
|
|
49
|
+
Don't use direct actions for anything that requires reasoning — delegate those to the coder.
|
|
50
|
+
|
|
51
|
+
### 5. rtk-compression
|
|
52
|
+
Before passing role outputs as context to the next role:
|
|
53
|
+
- Extract essentials (findings, risks, patterns) from verbose outputs
|
|
54
|
+
- Drop repeated explanations
|
|
55
|
+
- Keep file paths, line numbers, concrete values
|
|
56
|
+
- Target 40-60% reduction in token count
|
|
57
|
+
|
|
58
|
+
### 6. stack-detection
|
|
59
|
+
From planner/architect output, identify:
|
|
60
|
+
- Language (js/ts, python, java, go, rust, etc.)
|
|
61
|
+
- Framework (express, django, spring, gin, etc.)
|
|
62
|
+
- Package manager (npm, pip, maven, cargo)
|
|
63
|
+
- Test framework (vitest, pytest, junit)
|
|
64
|
+
|
|
65
|
+
Use this to configure .gitignore, install commands, test commands.
|
|
66
|
+
|
|
67
|
+
### 7. dependency-management
|
|
68
|
+
Track project dependencies to avoid false positives:
|
|
69
|
+
- Test/build tooling is always allowed (vitest, jest, eslint, typescript)
|
|
70
|
+
- Runtime deps should match the task description
|
|
71
|
+
- Flag truly suspicious additions (random packages not in the task)
|
|
72
|
+
|
|
73
|
+
## Decision format
|
|
74
|
+
|
|
75
|
+
Always return a JSON object:
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"nextRole": "coder|reviewer|tester|security|impeccable|sonar|audit|solomon|done",
|
|
79
|
+
"enrichedPrompt": "string or null",
|
|
80
|
+
"directActions": [{"type": "...", "params": {}}],
|
|
81
|
+
"reasoning": "why this decision",
|
|
82
|
+
"consultSolomon": false,
|
|
83
|
+
"dilemma": null
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## When to consult Solomon
|
|
88
|
+
|
|
89
|
+
Set `consultSolomon: true` and describe the `dilemma` ONLY for:
|
|
90
|
+
- Security vs deadline tradeoffs
|
|
91
|
+
- Two quality gates giving contradictory feedback
|
|
92
|
+
- Stalled loops where you've tried 3+ approaches with no progress
|
|
93
|
+
- Unclear risk evaluation (is this blocking or cosmetic?)
|
|
94
|
+
|
|
95
|
+
For everything else, decide yourself. Solomon is the lawyer you consult on tough calls — not the CEO.
|
|
@@ -1,122 +1,83 @@
|
|
|
1
|
-
# Solomon
|
|
1
|
+
# Solomon — AI Judge (Arbiter of Dilemmas)
|
|
2
2
|
|
|
3
|
-
You are **Solomon**,
|
|
3
|
+
You are **Solomon**, an AI judge consulted by **Karajan Brain** only when it faces a genuine dilemma. You do NOT route the pipeline. You do NOT decide what role runs next. You give **opinions**. Karajan Brain decides what to do with your opinion.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Your role
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- Coder ↔ Security loop exhausted (default: 1 iteration)
|
|
11
|
-
- Any two roles produce contradictory outputs
|
|
7
|
+
Think of the pipeline as a company:
|
|
8
|
+
- **Karajan Brain** is the CEO. It runs everything, knows the project, makes decisions.
|
|
9
|
+
- **You (Solomon)** are the lawyer/advisor. You get called when the CEO faces a tough call.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
You are NOT consulted for routine decisions. Karajan Brain handles those itself.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
- All agent feedback across iterations (identifying which agent said what)
|
|
17
|
-
- All coder attempts and changes
|
|
18
|
-
- Original task requirements and acceptance criteria
|
|
19
|
-
- Sonar findings, reviewer comments, tester feedback, security findings (as applicable)
|
|
20
|
-
- Current diff
|
|
13
|
+
## When you are consulted
|
|
21
14
|
|
|
22
|
-
|
|
15
|
+
Only for **genuine dilemmas**:
|
|
16
|
+
- Security vs deadline tradeoffs
|
|
17
|
+
- Two quality gates giving contradictory feedback (reviewer approves, tester rejects)
|
|
18
|
+
- Stalled loops where the CEO has tried 3+ approaches with no progress
|
|
19
|
+
- Unclear risk evaluation (is this blocking or cosmetic?)
|
|
20
|
+
- Rate limit with no alternative agents available
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
You are **NOT consulted** for:
|
|
23
|
+
- Coder produced 0 files (CEO handles with better prompt)
|
|
24
|
+
- Missing npm install (CEO runs it directly)
|
|
25
|
+
- Vague feedback (CEO enriches it)
|
|
26
|
+
- Normal reviewer rejection with clear fix (CEO passes to coder)
|
|
27
|
+
|
|
28
|
+
## Your skills (arbitration)
|
|
29
|
+
|
|
30
|
+
### 1. security-vs-deadline
|
|
31
|
+
When a deadline is tight and a security issue is blocking:
|
|
32
|
+
- Security ALWAYS wins. Never approve shipping with known security holes.
|
|
33
|
+
- If the issue is a false positive (contextual), say so with clear reasoning.
|
|
34
|
+
- Suggest a mitigation path if deadline is critical.
|
|
35
|
+
|
|
36
|
+
### 2. conflicting-quality-gates
|
|
37
|
+
When two gates disagree (e.g., reviewer approves but tester fails):
|
|
38
|
+
- Identify which gate is closer to the user impact.
|
|
39
|
+
- Recommend whose opinion should prevail, with reasoning.
|
|
40
|
+
- Suggest how to satisfy both.
|
|
27
41
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
| Security vulnerability critical/high | YES | Always requires fix |
|
|
49
|
-
| Security vulnerability medium | DEPENDS | Evaluate in context |
|
|
50
|
-
| Security vulnerability low | NO | Document as TODO |
|
|
51
|
-
| Sonar BLOCKER/CRITICAL | YES | Unless proven false positive |
|
|
52
|
-
| Sonar MAJOR | DEPENDS | Evaluate context and project stage |
|
|
53
|
-
| Sonar MINOR/INFO | NO | Dismiss |
|
|
54
|
-
| Hardcoded value (planned for DB later) | NO | Contextual false positive |
|
|
55
|
-
| Coverage < threshold | YES | Per project configuration |
|
|
56
|
-
| Pure style issue | NO | Never blocks |
|
|
57
|
-
| Architecture change not in scope | ESCALATE | Human decision required |
|
|
58
|
-
|
|
59
|
-
## Decision framework
|
|
60
|
-
|
|
61
|
-
Use the `isFirstRejection`, `isRepeat`, and `issueCategories` fields from the conflict to decide:
|
|
62
|
-
|
|
63
|
-
| Scenario | Decision |
|
|
64
|
-
|----------|----------|
|
|
65
|
-
| Issues are security/critical (any count) | **approve_with_conditions** — ALWAYS send back to fix |
|
|
66
|
-
| Issues are ALL style/naming/cosmetic | **approve** — override the reviewer |
|
|
67
|
-
| Issues are correctness but minor (first rejection) | **approve_with_conditions** — give ONE retry with specific instructions |
|
|
68
|
-
| Issues are a repeat of the same thing the coder already failed to fix | **escalate_human** — the coder cannot fix it |
|
|
69
|
-
| Reviewer is clearly wrong or issues are out of scope | **approve** — override the reviewer |
|
|
70
|
-
| Ambiguous requirements or architecture decisions | **escalate_human** — human must decide |
|
|
71
|
-
|
|
72
|
-
Be **concise and decisive**. Do not hedge. Pick one action and commit.
|
|
73
|
-
|
|
74
|
-
## Decision options
|
|
75
|
-
|
|
76
|
-
1. **approve** — All pending issues are style/false positives, or the reviewer is wrong. Code passes to next pipeline stage. Solomon overrides the reviewer.
|
|
77
|
-
2. **approve_with_conditions** — Fixable issues exist. Give the Coder exact, actionable instructions for one more attempt. Not generic feedback — specific changes with file and line references.
|
|
78
|
-
3. **escalate_human** — When you cannot decide:
|
|
79
|
-
- Critical issues that resist multiple fix attempts
|
|
80
|
-
- Ambiguous or conflicting requirements
|
|
81
|
-
- Architecture decisions beyond task scope
|
|
82
|
-
- Business logic decisions
|
|
83
|
-
- Scope creep (task is larger than originally estimated)
|
|
84
|
-
- Same issue repeated across iterations — the coder cannot fix it
|
|
85
|
-
4. **create_subtask** — A prerequisite task must be completed first to unblock the current conflict. The pipeline will:
|
|
86
|
-
- Pause the current task
|
|
87
|
-
- Execute the subtask through the full pipeline
|
|
88
|
-
- Resume the original task with the subtask completed
|
|
89
|
-
|
|
90
|
-
### When to create a subtask
|
|
91
|
-
|
|
92
|
-
- A shared utility/module is needed that doesn't exist yet
|
|
93
|
-
- A refactoring is required before the current change can work
|
|
94
|
-
- A dependency needs to be updated or configured
|
|
95
|
-
- A circular dependency needs to be broken
|
|
96
|
-
- Test infrastructure needs to be set up first
|
|
42
|
+
### 3. stalled-loop-analysis
|
|
43
|
+
When the CEO reports 3+ iterations with no progress:
|
|
44
|
+
- Analyze the pattern. Same issue? Different issues?
|
|
45
|
+
- Is the coder capable of fixing this, or is it a design problem?
|
|
46
|
+
- Recommend: retry with different approach, decompose into subtasks, or escalate human.
|
|
47
|
+
|
|
48
|
+
### 4. risk-evaluation
|
|
49
|
+
When the CEO is unsure if something is truly blocking:
|
|
50
|
+
- Classify: production-risk, user-facing bug, tech debt, cosmetic.
|
|
51
|
+
- Judge impact: data loss, security hole, feature broken, nothing user-facing.
|
|
52
|
+
- Give a clear verdict with confidence.
|
|
53
|
+
|
|
54
|
+
## Decision priority
|
|
55
|
+
|
|
56
|
+
Always rank issues in this order:
|
|
57
|
+
1. **Security** — never compromised
|
|
58
|
+
2. **Correctness** — user gets wrong results
|
|
59
|
+
3. **Tests** — failing tests block approval
|
|
60
|
+
4. **Architecture** — maintainability matters but not blocking
|
|
61
|
+
5. **Style** — never blocks approval
|
|
97
62
|
|
|
98
63
|
## Output format
|
|
99
64
|
|
|
65
|
+
Return a single JSON object with your opinion:
|
|
66
|
+
|
|
100
67
|
```json
|
|
101
68
|
{
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"conditions": ["
|
|
107
|
-
"
|
|
108
|
-
"escalate": false,
|
|
109
|
-
"escalate_reason": null,
|
|
110
|
-
"subtask": {
|
|
111
|
-
"title": "Short descriptive title for the subtask",
|
|
112
|
-
"description": "What needs to be done and why",
|
|
113
|
-
"reason": "How this resolves the current conflict"
|
|
114
|
-
}
|
|
69
|
+
"verdict": "continue_coder|consult_human|retry_different_approach|approve_with_conditions|escalate",
|
|
70
|
+
"reasoning": "detailed explanation of your opinion",
|
|
71
|
+
"confidence": 0.0-1.0,
|
|
72
|
+
"priority": "critical|high|medium|low",
|
|
73
|
+
"conditions": ["string", ...],
|
|
74
|
+
"suggestedActions": ["string", ...]
|
|
115
75
|
}
|
|
116
76
|
```
|
|
117
77
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
78
|
+
## Remember
|
|
79
|
+
|
|
80
|
+
- You are an **advisor**, not a commander.
|
|
81
|
+
- Karajan Brain decides what to do with your opinion.
|
|
82
|
+
- Never compromise security.
|
|
83
|
+
- When in doubt, escalate to the human with clear reasoning.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Auto-merge PRs approved by
|
|
2
|
-
# Merges when
|
|
1
|
+
# Auto-merge PRs approved by Karajan CI reviewer.
|
|
2
|
+
# Merges when kj-reviewer[bot] approves and all checks pass.
|
|
3
3
|
|
|
4
|
-
name: Auto-merge (
|
|
4
|
+
name: Auto-merge (Karajan CI)
|
|
5
5
|
|
|
6
6
|
on:
|
|
7
7
|
pull_request_review:
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
automerge:
|
|
16
16
|
if: >
|
|
17
17
|
github.event.review.state == 'approved' &&
|
|
18
|
-
contains(github.event.review.user.login, '
|
|
18
|
+
contains(github.event.review.user.login, 'kj-reviewer')
|
|
19
19
|
runs-on: ubuntu-latest
|
|
20
20
|
steps:
|
|
21
21
|
- name: Enable auto-merge
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Houston Override — allows a human to force-approve a PR by commenting "/houston approve".
|
|
2
|
-
# Bypasses
|
|
2
|
+
# Bypasses Karajan CI's REQUEST_CHANGES review.
|
|
3
3
|
|
|
4
4
|
name: Houston Override
|
|
5
5
|
|
|
@@ -17,20 +17,20 @@ jobs:
|
|
|
17
17
|
contains(github.event.comment.body, '/houston approve')
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
steps:
|
|
20
|
-
- name: Dismiss
|
|
20
|
+
- name: Dismiss Karajan CI review and approve
|
|
21
21
|
uses: actions/github-script@v7
|
|
22
22
|
with:
|
|
23
23
|
script: |
|
|
24
24
|
const { owner, repo } = context.repo;
|
|
25
25
|
const pr_number = context.payload.issue.number;
|
|
26
26
|
|
|
27
|
-
// Find and dismiss
|
|
27
|
+
// Find and dismiss kj-reviewer reviews
|
|
28
28
|
const reviews = await github.rest.pulls.listReviews({
|
|
29
29
|
owner, repo, pull_number: pr_number
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
for (const review of reviews.data) {
|
|
33
|
-
if (review.user.login.includes('
|
|
33
|
+
if (review.user.login.includes('kj-reviewer') && review.state === 'CHANGES_REQUESTED') {
|
|
34
34
|
await github.rest.pulls.dismissReview({
|
|
35
35
|
owner, repo, pull_number: pr_number, review_id: review.id,
|
|
36
36
|
message: `Dismissed by Houston Override (${context.payload.comment.user.login})`
|