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
|
@@ -1,72 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createAgent as defaultCreateAgent } from "../agents/index.js";
|
|
1
|
+
import { AgentRole } from "./agent-role.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
config?.roles?.coder?.provider ||
|
|
8
|
-
"claude"
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function buildPrompt({ task, instructions }) {
|
|
13
|
-
const sections = [];
|
|
14
|
-
|
|
15
|
-
if (instructions) {
|
|
16
|
-
sections.push(instructions, "");
|
|
3
|
+
export class RefactorerRole extends AgentRole {
|
|
4
|
+
constructor(opts) {
|
|
5
|
+
super({ ...opts, name: "refactorer" });
|
|
17
6
|
}
|
|
18
7
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"Do not expand scope and keep tests green.",
|
|
22
|
-
"",
|
|
23
|
-
"## Task context",
|
|
24
|
-
task
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return sections.join("\n");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class RefactorerRole extends BaseRole {
|
|
31
|
-
constructor({ config, logger, emitter = null, createAgentFn = null }) {
|
|
32
|
-
super({ name: "refactorer", config, logger, emitter });
|
|
33
|
-
this._createAgent = createAgentFn || defaultCreateAgent;
|
|
8
|
+
resolveProvider() {
|
|
9
|
+
return this.config?.roles?.refactorer?.provider || this.config?.roles?.coder?.provider || "claude";
|
|
34
10
|
}
|
|
35
11
|
|
|
36
|
-
async
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const result = await agent.runTask(runArgs);
|
|
49
|
-
|
|
50
|
-
if (!result.ok) {
|
|
51
|
-
return {
|
|
52
|
-
ok: false,
|
|
53
|
-
result: {
|
|
54
|
-
...result,
|
|
55
|
-
error: result.error || result.output || "Refactorer failed",
|
|
56
|
-
provider
|
|
57
|
-
},
|
|
58
|
-
summary: `Refactorer failed: ${result.error || "unknown error"}`
|
|
59
|
-
};
|
|
60
|
-
}
|
|
12
|
+
async buildPrompt({ task }) {
|
|
13
|
+
const sections = [];
|
|
14
|
+
if (this.instructions) sections.push(this.instructions, "");
|
|
15
|
+
sections.push(
|
|
16
|
+
"Refactor the current changes for clarity and maintainability without changing behavior.",
|
|
17
|
+
"Do not expand scope and keep tests green.",
|
|
18
|
+
"",
|
|
19
|
+
"## Task context",
|
|
20
|
+
task
|
|
21
|
+
);
|
|
22
|
+
return { prompt: sections.join("\n") };
|
|
23
|
+
}
|
|
61
24
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
result: {
|
|
65
|
-
...result,
|
|
66
|
-
output: result.output?.trim() || "",
|
|
67
|
-
provider
|
|
68
|
-
},
|
|
69
|
-
summary: "Refactoring applied"
|
|
70
|
-
};
|
|
25
|
+
buildSuccessResult(parsed, provider, agentResult) {
|
|
26
|
+
return { ...agentResult, output: (agentResult.output || "").trim(), provider };
|
|
71
27
|
}
|
|
28
|
+
|
|
29
|
+
buildSummary() { return "Refactoring applied"; }
|
|
72
30
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AgentRole } from "./agent-role.js";
|
|
2
|
+
import { extractFirstJson } from "../utils/json-extract.js";
|
|
3
3
|
|
|
4
4
|
const SUBAGENT_PREAMBLE = [
|
|
5
5
|
"IMPORTANT: You are running as a Karajan sub-agent.",
|
|
@@ -7,130 +7,64 @@ const SUBAGENT_PREAMBLE = [
|
|
|
7
7
|
"Do NOT use any MCP tools. Focus only on researching the codebase."
|
|
8
8
|
].join(" ");
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"claude"
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function buildPrompt({ task, instructions }) {
|
|
19
|
-
const sections = [SUBAGENT_PREAMBLE];
|
|
10
|
+
const EMPTY_RESEARCH = {
|
|
11
|
+
affected_files: [], patterns: [], constraints: [],
|
|
12
|
+
prior_decisions: [], risks: [], test_coverage: ""
|
|
13
|
+
};
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
export class ResearcherRole extends AgentRole {
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
super({ ...opts, name: "researcher" });
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
function parseResearchOutput(raw) {
|
|
37
|
-
const text = raw?.trim() || "";
|
|
38
|
-
const jsonMatch = /\{[\s\S]*\}/.exec(text);
|
|
39
|
-
if (!jsonMatch) return null;
|
|
40
|
-
return JSON.parse(jsonMatch[0]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function buildSummary(parsed) {
|
|
44
|
-
const files = parsed.affected_files?.length || 0;
|
|
45
|
-
const risks = parsed.risks?.length || 0;
|
|
46
|
-
const patterns = parsed.patterns?.length || 0;
|
|
47
|
-
const parts = [];
|
|
48
|
-
if (files) parts.push(`${files} file${files === 1 ? "" : "s"}`);
|
|
49
|
-
if (risks) parts.push(`${risks} risk${risks === 1 ? "" : "s"}`);
|
|
50
|
-
if (patterns) parts.push(`${patterns} pattern${patterns === 1 ? "" : "s"}`);
|
|
51
|
-
return parts.length
|
|
52
|
-
? `Research complete: ${parts.join(", ")} identified`
|
|
53
|
-
: "Research complete";
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export class ResearcherRole extends BaseRole {
|
|
57
|
-
constructor({ config, logger, emitter = null, createAgentFn = null }) {
|
|
58
|
-
super({ name: "researcher", config, logger, emitter });
|
|
59
|
-
this._createAgent = createAgentFn || defaultCreateAgent;
|
|
20
|
+
async buildPrompt({ task }) {
|
|
21
|
+
const sections = [SUBAGENT_PREAMBLE];
|
|
22
|
+
if (this.instructions) sections.push(this.instructions);
|
|
23
|
+
sections.push(
|
|
24
|
+
"Investigate the codebase for the following task.",
|
|
25
|
+
"Identify affected files, patterns, constraints, prior decisions, risks, and test coverage.",
|
|
26
|
+
"Return a single valid JSON object with your findings and nothing else.",
|
|
27
|
+
'{"affected_files":[string],"patterns":[string],"constraints":[string],"prior_decisions":[string],"risks":[string],"test_coverage":string}',
|
|
28
|
+
`## Task\n${task}`
|
|
29
|
+
);
|
|
30
|
+
return { prompt: sections.join("\n\n") };
|
|
60
31
|
}
|
|
61
32
|
|
|
62
|
-
|
|
63
|
-
const task = typeof input === "string"
|
|
64
|
-
? input
|
|
65
|
-
: input?.task || this.context?.task || "";
|
|
66
|
-
const onOutput = typeof input === "string" ? null : input?.onOutput || null;
|
|
67
|
-
|
|
68
|
-
const provider = resolveProvider(this.config);
|
|
69
|
-
const agent = this._createAgent(provider, this.config, this.logger);
|
|
33
|
+
parseOutput(raw) { return extractFirstJson(raw); }
|
|
70
34
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
35
|
+
buildSuccessResult(parsed, provider) {
|
|
36
|
+
return {
|
|
37
|
+
affected_files: parsed.affected_files || [],
|
|
38
|
+
patterns: parsed.patterns || [],
|
|
39
|
+
constraints: parsed.constraints || [],
|
|
40
|
+
prior_decisions: parsed.prior_decisions || [],
|
|
41
|
+
risks: parsed.risks || [],
|
|
42
|
+
test_coverage: parsed.test_coverage || "",
|
|
43
|
+
provider
|
|
44
|
+
};
|
|
45
|
+
}
|
|
75
46
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
47
|
+
buildSummary(parsed) {
|
|
48
|
+
const files = parsed.affected_files?.length || 0;
|
|
49
|
+
const risks = parsed.risks?.length || 0;
|
|
50
|
+
const patterns = parsed.patterns?.length || 0;
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (files) parts.push(`${files} file${files === 1 ? "" : "s"}`);
|
|
53
|
+
if (risks) parts.push(`${risks} risk${risks === 1 ? "" : "s"}`);
|
|
54
|
+
if (patterns) parts.push(`${patterns} pattern${patterns === 1 ? "" : "s"}`);
|
|
55
|
+
return parts.length ? `Research complete: ${parts.join(", ")} identified` : "Research complete";
|
|
56
|
+
}
|
|
86
57
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
constraints: [],
|
|
96
|
-
prior_decisions: [],
|
|
97
|
-
risks: [],
|
|
98
|
-
test_coverage: "",
|
|
99
|
-
raw: result.output,
|
|
100
|
-
provider
|
|
101
|
-
},
|
|
102
|
-
summary: "Research complete (unstructured output)"
|
|
103
|
-
};
|
|
104
|
-
}
|
|
58
|
+
handleParseNull(agentResult, provider) {
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
result: { ...EMPTY_RESEARCH, raw: agentResult.output, provider },
|
|
62
|
+
summary: "Research complete (unstructured output)",
|
|
63
|
+
usage: agentResult.usage
|
|
64
|
+
};
|
|
65
|
+
}
|
|
105
66
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
result: {
|
|
109
|
-
affected_files: parsed.affected_files || [],
|
|
110
|
-
patterns: parsed.patterns || [],
|
|
111
|
-
constraints: parsed.constraints || [],
|
|
112
|
-
prior_decisions: parsed.prior_decisions || [],
|
|
113
|
-
risks: parsed.risks || [],
|
|
114
|
-
test_coverage: parsed.test_coverage || "",
|
|
115
|
-
provider
|
|
116
|
-
},
|
|
117
|
-
summary: buildSummary(parsed)
|
|
118
|
-
};
|
|
119
|
-
} catch { /* agent output is not structured JSON */
|
|
120
|
-
return {
|
|
121
|
-
ok: true,
|
|
122
|
-
result: {
|
|
123
|
-
affected_files: [],
|
|
124
|
-
patterns: [],
|
|
125
|
-
constraints: [],
|
|
126
|
-
prior_decisions: [],
|
|
127
|
-
risks: [],
|
|
128
|
-
test_coverage: "",
|
|
129
|
-
raw: result.output,
|
|
130
|
-
provider
|
|
131
|
-
},
|
|
132
|
-
summary: "Research complete (unstructured output)"
|
|
133
|
-
};
|
|
134
|
-
}
|
|
67
|
+
handleParseError(_err, agentResult, provider) {
|
|
68
|
+
return this.handleParseNull(agentResult, provider);
|
|
135
69
|
}
|
|
136
70
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createAgent as defaultCreateAgent } from "../agents/index.js";
|
|
1
|
+
import { AgentRole } from "./agent-role.js";
|
|
3
2
|
import { buildRtkInstructions } from "../prompts/rtk-snippet.js";
|
|
3
|
+
import { extractFirstJson } from "../utils/json-extract.js";
|
|
4
4
|
|
|
5
5
|
const MAX_DIFF_LENGTH = 12000;
|
|
6
6
|
|
|
@@ -10,147 +10,90 @@ const SUBAGENT_PREAMBLE = [
|
|
|
10
10
|
"Do NOT use any MCP tools. Focus only on reviewing the code."
|
|
11
11
|
].join(" ");
|
|
12
12
|
|
|
13
|
-
function resolveProvider(config) {
|
|
14
|
-
return (
|
|
15
|
-
config?.roles?.reviewer?.provider ||
|
|
16
|
-
config?.roles?.coder?.provider ||
|
|
17
|
-
"claude"
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
13
|
function truncateDiff(diff) {
|
|
22
14
|
if (!diff) return "";
|
|
23
|
-
return diff.length > MAX_DIFF_LENGTH
|
|
24
|
-
? `${diff.slice(0, MAX_DIFF_LENGTH)}\n\n[TRUNCATED]`
|
|
25
|
-
: diff;
|
|
15
|
+
return diff.length > MAX_DIFF_LENGTH ? `${diff.slice(0, MAX_DIFF_LENGTH)}\n\n[TRUNCATED]` : diff;
|
|
26
16
|
}
|
|
27
17
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
sections.push(SUBAGENT_PREAMBLE);
|
|
32
|
-
|
|
33
|
-
if (instructions) {
|
|
34
|
-
sections.push(instructions);
|
|
18
|
+
export class ReviewerRole extends AgentRole {
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
super({ ...opts, name: "reviewer" });
|
|
35
21
|
}
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
`You are a code reviewer in ${reviewMode || "standard"} mode.`,
|
|
39
|
-
"Return only one valid JSON object and nothing else.",
|
|
40
|
-
'JSON schema:',
|
|
41
|
-
'{"approved":boolean,"blocking_issues":[{"id":string,"severity":"critical|high|medium|low","file":string,"line":number,"description":string,"suggested_fix":string}],"non_blocking_suggestions":[string],"summary":string,"confidence":number}',
|
|
42
|
-
`Task context:\n${task}`
|
|
43
|
-
);
|
|
23
|
+
get agentMethod() { return "reviewTask"; }
|
|
44
24
|
|
|
45
|
-
|
|
46
|
-
|
|
25
|
+
extractInput(input) {
|
|
26
|
+
if (typeof input === "string") return { task: input, diff: "", reviewRules: null, onOutput: null };
|
|
27
|
+
return {
|
|
28
|
+
task: input?.task || this.context?.task || "",
|
|
29
|
+
diff: input?.diff || "",
|
|
30
|
+
reviewRules: input?.reviewRules || null,
|
|
31
|
+
onOutput: input?.onOutput || null
|
|
32
|
+
};
|
|
47
33
|
}
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
sections
|
|
51
|
-
|
|
35
|
+
async buildPrompt({ task, diff, reviewRules }) {
|
|
36
|
+
const sections = [SUBAGENT_PREAMBLE];
|
|
37
|
+
if (this.instructions) sections.push(this.instructions);
|
|
38
|
+
sections.push(
|
|
39
|
+
`You are a code reviewer in ${this.config?.review_mode || "standard"} mode.`,
|
|
40
|
+
"Return only one valid JSON object and nothing else.",
|
|
41
|
+
"JSON schema:",
|
|
42
|
+
'{"approved":boolean,"blocking_issues":[{"id":string,"severity":"critical|high|medium|low","file":string,"line":number,"description":string,"suggested_fix":string}],"non_blocking_suggestions":[string],"summary":string,"confidence":number}',
|
|
43
|
+
`Task context:\n${task}`
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const pc = this.config?.productContext;
|
|
47
|
+
if (pc) sections.push(`## Product Context\n${pc}`);
|
|
48
|
+
const dc = this.config?.domainContext;
|
|
49
|
+
if (dc) sections.push(`## Domain Context\n${dc}`);
|
|
50
|
+
|
|
51
|
+
const rtkSnippet = buildRtkInstructions({
|
|
52
|
+
rtkAvailable: Boolean(this.config?.rtk?.available)
|
|
53
|
+
});
|
|
54
|
+
if (rtkSnippet) sections.push(rtkSnippet);
|
|
55
|
+
if (reviewRules) sections.push(`Review rules:\n${reviewRules}`);
|
|
56
|
+
sections.push(`Git diff:\n${truncateDiff(diff)}`);
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
if (rtkSnippet) {
|
|
55
|
-
sections.push(rtkSnippet);
|
|
58
|
+
return { prompt: sections.join("\n\n") };
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
parseOutput(raw) {
|
|
62
|
+
const parsed = extractFirstJson(raw);
|
|
63
|
+
if (!parsed) throw new Error("Failed to parse reviewer output: no JSON found");
|
|
64
|
+
return parsed;
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
throw new Error(`Failed to parse reviewer output: no JSON found`);
|
|
67
|
+
buildSuccessResult(parsed, provider, agentResult) {
|
|
68
|
+
return {
|
|
69
|
+
...agentResult,
|
|
70
|
+
approved: parsed.approved,
|
|
71
|
+
blocking_issues: parsed.blocking_issues || [],
|
|
72
|
+
non_blocking_suggestions: parsed.non_blocking_suggestions || [],
|
|
73
|
+
confidence: parsed.confidence ?? null,
|
|
74
|
+
raw_summary: parsed.summary || ""
|
|
75
|
+
};
|
|
72
76
|
}
|
|
73
|
-
return JSON.parse(jsonMatch[0]);
|
|
74
|
-
}
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
buildSummary(parsed) {
|
|
79
|
+
const blockingIssues = parsed.blocking_issues || [];
|
|
80
|
+
return parsed.approved
|
|
81
|
+
? `Approved: ${parsed.summary || "no issues found"}`
|
|
82
|
+
: `Rejected: ${blockingIssues.length} blocking issue(s) — ${parsed.summary || ""}`;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
instructions: this.instructions,
|
|
96
|
-
rtkAvailable: Boolean(this.config?.rtk?.available),
|
|
97
|
-
proxyEnabled: Boolean(this.config?.proxy?.enabled),
|
|
98
|
-
productContext: this.config?.productContext || null,
|
|
99
|
-
domainContext: this.config?.domainContext || null
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const reviewArgs = { prompt, role: "reviewer" };
|
|
103
|
-
if (onOutput) reviewArgs.onOutput = onOutput;
|
|
104
|
-
|
|
105
|
-
const result = await agent.reviewTask(reviewArgs);
|
|
106
|
-
|
|
107
|
-
if (!result.ok) {
|
|
108
|
-
return {
|
|
109
|
-
ok: false,
|
|
110
|
-
result: {
|
|
111
|
-
error: result.error || result.output || "Reviewer agent failed",
|
|
112
|
-
approved: false,
|
|
113
|
-
blocking_issues: []
|
|
114
|
-
},
|
|
115
|
-
summary: `Reviewer failed: ${result.error || "unknown error"}`
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const parsed = parseReviewOutput(result.output);
|
|
121
|
-
const blockingIssues = parsed.blocking_issues || [];
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
ok: true,
|
|
125
|
-
result: {
|
|
126
|
-
...result,
|
|
127
|
-
approved: parsed.approved,
|
|
128
|
-
blocking_issues: blockingIssues,
|
|
129
|
-
non_blocking_suggestions: parsed.non_blocking_suggestions || [],
|
|
130
|
-
confidence: parsed.confidence ?? null,
|
|
131
|
-
raw_summary: parsed.summary || ""
|
|
132
|
-
},
|
|
133
|
-
summary: parsed.approved
|
|
134
|
-
? `Approved: ${parsed.summary || "no issues found"}`
|
|
135
|
-
: `Rejected: ${blockingIssues.length} blocking issue(s) — ${parsed.summary || ""}`
|
|
136
|
-
};
|
|
137
|
-
} catch (err) {
|
|
138
|
-
return {
|
|
139
|
-
ok: true,
|
|
140
|
-
result: {
|
|
141
|
-
...result,
|
|
142
|
-
approved: false,
|
|
143
|
-
blocking_issues: [{
|
|
144
|
-
id: "PARSE_ERROR",
|
|
145
|
-
severity: "high",
|
|
146
|
-
description: `Reviewer output could not be parsed: ${err.message}`
|
|
147
|
-
}],
|
|
148
|
-
non_blocking_suggestions: [],
|
|
149
|
-
confidence: 0,
|
|
150
|
-
raw_summary: `Parse error: ${err.message}`
|
|
151
|
-
},
|
|
152
|
-
summary: `Reviewer output parse error: ${err.message}`
|
|
153
|
-
};
|
|
154
|
-
}
|
|
85
|
+
handleParseError(err, agentResult, _provider) {
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
result: {
|
|
89
|
+
...agentResult,
|
|
90
|
+
approved: false,
|
|
91
|
+
blocking_issues: [{ id: "PARSE_ERROR", severity: "high", description: `Reviewer output could not be parsed: ${err.message}` }],
|
|
92
|
+
non_blocking_suggestions: [],
|
|
93
|
+
confidence: 0,
|
|
94
|
+
raw_summary: `Parse error: ${err.message}`
|
|
95
|
+
},
|
|
96
|
+
summary: `Reviewer output parse error: ${err.message}`
|
|
97
|
+
};
|
|
155
98
|
}
|
|
156
99
|
}
|