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.
Files changed (115) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/scripts/install.js +18 -15
  4. package/src/agents/aider-agent.js +0 -7
  5. package/src/agents/claude-agent.js +34 -6
  6. package/src/agents/codex-agent.js +2 -6
  7. package/src/agents/gemini-agent.js +0 -4
  8. package/src/agents/opencode-agent.js +0 -4
  9. package/src/{becaria → ci}/dispatch.js +13 -13
  10. package/src/{becaria → ci}/pr-diff.js +1 -1
  11. package/src/cli.js +3 -2
  12. package/src/commands/agents.js +0 -1
  13. package/src/commands/doctor.js +22 -40
  14. package/src/commands/init.js +8 -8
  15. package/src/commands/report.js +0 -13
  16. package/src/commands/review.js +17 -17
  17. package/src/commands/run.js +1 -2
  18. package/src/commands/status.js +1 -7
  19. package/src/config.js +10 -52
  20. package/src/domains/domain-loader.js +85 -4
  21. package/src/git/automation.js +9 -9
  22. package/src/guards/output-guard.js +0 -17
  23. package/src/mcp/handlers/direct-handlers.js +1 -1
  24. package/src/mcp/handlers/run-handler.js +1 -2
  25. package/src/mcp/sovereignty-guard.js +2 -2
  26. package/src/mcp/tools.js +3 -2
  27. package/src/orchestrator/brain-coordinator.js +165 -0
  28. package/src/orchestrator/ci-integration.js +139 -0
  29. package/src/orchestrator/config-init.js +435 -0
  30. package/src/orchestrator/direct-actions.js +186 -0
  31. package/src/orchestrator/feedback-enrichment.js +140 -0
  32. package/src/orchestrator/feedback-queue.js +152 -0
  33. package/src/orchestrator/flow-control.js +159 -0
  34. package/src/orchestrator/post-loop-stages.js +20 -15
  35. package/src/orchestrator/preflight-checks.js +7 -3
  36. package/src/orchestrator/role-output-compressor.js +190 -0
  37. package/src/orchestrator/session-journal.js +344 -0
  38. package/src/orchestrator/solomon-escalation.js +38 -5
  39. package/src/orchestrator/solomon-rules.js +32 -33
  40. package/src/orchestrator/stages/reviewer-stage.js +16 -5
  41. package/src/orchestrator/stages/sonar-stage.js +24 -1
  42. package/src/orchestrator/verification-gate.js +146 -0
  43. package/src/orchestrator.js +435 -661
  44. package/src/planning-game/client.js +2 -2
  45. package/src/planning-game/pipeline-adapter.js +1 -1
  46. package/src/prompts/coder.js +17 -3
  47. package/src/prompts/reviewer.js +2 -2
  48. package/src/prompts/rtk-snippet.js +3 -5
  49. package/src/review/diff-generator.js +66 -17
  50. package/src/review/snapshot-diff.js +122 -0
  51. package/src/review/tdd-policy.js +4 -2
  52. package/src/roles/agent-role.js +135 -0
  53. package/src/roles/architect-role.js +61 -108
  54. package/src/roles/audit-role.js +25 -71
  55. package/src/roles/coder-role.js +32 -57
  56. package/src/roles/discover-role.js +30 -71
  57. package/src/roles/hu-reviewer-role.js +51 -99
  58. package/src/roles/impeccable-role.js +34 -91
  59. package/src/roles/index.js +2 -0
  60. package/src/roles/karajan-brain-role.js +134 -0
  61. package/src/roles/planner-role.js +40 -75
  62. package/src/roles/refactorer-role.js +22 -64
  63. package/src/roles/researcher-role.js +52 -118
  64. package/src/roles/reviewer-role.js +69 -126
  65. package/src/roles/security-role.js +38 -102
  66. package/src/roles/solomon-role.js +71 -15
  67. package/src/roles/tester-role.js +121 -95
  68. package/src/roles/triage-role.js +50 -111
  69. package/src/session-store.js +1 -1
  70. package/src/skills/skill-detector.js +11 -0
  71. package/src/sonar/config-resolver.js +20 -1
  72. package/src/sonar/credentials.js +17 -0
  73. package/src/sonar/project-key.js +1 -1
  74. package/src/sonar/scanner.js +1 -1
  75. package/src/utils/banner.js +66 -0
  76. package/src/utils/display.js +35 -17
  77. package/src/utils/injection-guard.js +23 -8
  78. package/src/utils/logger.js +6 -1
  79. package/src/utils/process.js +3 -4
  80. package/src/utils/role-assigner.js +131 -0
  81. package/src/utils/update-check.js +5 -1
  82. package/src/utils/welcome.js +3 -8
  83. package/src/webperf/devtools-detect.js +70 -23
  84. package/templates/roles/coder.md +7 -0
  85. package/templates/roles/karajan-brain.md +95 -0
  86. package/templates/roles/solomon.md +67 -106
  87. package/templates/workflows/automerge.yml +4 -4
  88. package/templates/workflows/houston-override.yml +4 -4
  89. package/templates/workflows/{becaria-gateway.yml → kj-ci-gateway.yml} +12 -12
  90. package/src/proxy/adapters/anthropic.js +0 -131
  91. package/src/proxy/adapters/gemini.js +0 -106
  92. package/src/proxy/adapters/index.js +0 -51
  93. package/src/proxy/adapters/openai.js +0 -71
  94. package/src/proxy/compression/ai-compressor.js +0 -209
  95. package/src/proxy/compression/dedup-cache.js +0 -100
  96. package/src/proxy/compression/deterministic/bash-build.js +0 -60
  97. package/src/proxy/compression/deterministic/bash-git.js +0 -101
  98. package/src/proxy/compression/deterministic/bash-infra.js +0 -64
  99. package/src/proxy/compression/deterministic/bash-misc.js +0 -53
  100. package/src/proxy/compression/deterministic/bash-pkg.js +0 -49
  101. package/src/proxy/compression/deterministic/bash-test.js +0 -61
  102. package/src/proxy/compression/deterministic/glob.js +0 -26
  103. package/src/proxy/compression/deterministic/grep.js +0 -53
  104. package/src/proxy/compression/deterministic/index.js +0 -58
  105. package/src/proxy/compression/deterministic/read.js +0 -22
  106. package/src/proxy/compression/deterministic/utils.js +0 -33
  107. package/src/proxy/compression/pipeline.js +0 -270
  108. package/src/proxy/middleware/prompt-injector.js +0 -165
  109. package/src/proxy/middleware/response-interceptor.js +0 -223
  110. package/src/proxy/progress-monitor.js +0 -98
  111. package/src/proxy/proxy-lifecycle.js +0 -198
  112. package/src/proxy/proxy-server.js +0 -239
  113. package/src/proxy/security.js +0 -45
  114. /package/src/{becaria → ci}/index.js +0 -0
  115. /package/src/{becaria → ci}/repo.js +0 -0
package/README.md CHANGED
@@ -23,6 +23,8 @@
23
23
 
24
24
  ---
25
25
 
26
+ > **v2.0 released** — Karajan Brain architecture, smart init, session journal, and more. See [MIGRATION-v2.md](./MIGRATION-v2.md) for breaking changes (proxy removed, becaria→ci rename).
27
+
26
28
  You describe what you want to build. Karajan orchestrates multiple AI agents to plan it, implement it, test it, review it with SonarQube, and iterate. No babysitting required.
27
29
 
28
30
  ## What is Karajan?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "1.59.0",
3
+ "version": "2.0.0",
4
4
  "description": "Local multi-agent coding orchestrator with TDD, SonarQube, and code review pipeline",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -641,7 +641,7 @@ async function collectSettings(rootDir, parsedArgs, instanceContext, nonInteract
641
641
  sonarToken: "",
642
642
  coder: instanceContext.existing?.coder || "codex",
643
643
  reviewer: instanceContext.existing?.reviewer || "claude",
644
- reviewerFallback: instanceContext.existing?.reviewerFallback || "codex",
644
+ reviewerFallback: instanceContext.existing?.reviewerFallback || null,
645
645
  setupMcpClaude: true,
646
646
  setupMcpCodex: true,
647
647
  runDoctor: true,
@@ -649,7 +649,7 @@ async function collectSettings(rootDir, parsedArgs, instanceContext, nonInteract
649
649
  };
650
650
 
651
651
  if (nonInteractive) {
652
- return {
652
+ const settings = {
653
653
  linkGlobal: parseBool(pickSetting({ cli: parsedArgs, cliKey: "linkGlobal", envKey: "KJ_INSTALL_LINK_GLOBAL", fallback: defaults.linkGlobal }), defaults.linkGlobal),
654
654
  kjHome: pickSetting({ cli: parsedArgs, cliKey: "kjHome", envKey: "KJ_INSTALL_KJ_HOME", fallback: defaults.kjHome }),
655
655
  sonarHost: pickSetting({ cli: parsedArgs, cliKey: "sonarHost", envKey: "KJ_INSTALL_SONAR_HOST", fallback: defaults.sonarHost }),
@@ -660,13 +660,14 @@ async function collectSettings(rootDir, parsedArgs, instanceContext, nonInteract
660
660
  sonarToken: pickSetting({ cli: parsedArgs, cliKey: "sonarToken", envKey: "KJ_SONAR_TOKEN", fallback: defaults.sonarToken }),
661
661
  coder: pickSetting({ cli: parsedArgs, cliKey: "coder", envKey: "KJ_INSTALL_CODER", fallback: defaults.coder }),
662
662
  reviewer: pickSetting({ cli: parsedArgs, cliKey: "reviewer", envKey: "KJ_INSTALL_REVIEWER", fallback: defaults.reviewer }),
663
- reviewerFallback: pickSetting({ cli: parsedArgs, cliKey: "reviewerFallback", envKey: "KJ_INSTALL_REVIEWER_FALLBACK", fallback: defaults.reviewerFallback }),
664
- setupMcpClaude: parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupMcpClaude", envKey: "KJ_INSTALL_SETUP_MCP_CLAUDE", fallback: defaults.setupMcpClaude }), defaults.setupMcpClaude),
665
- setupMcpCodex: parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupMcpCodex", envKey: "KJ_INSTALL_SETUP_MCP_CODEX", fallback: defaults.setupMcpCodex }), defaults.setupMcpCodex),
666
- setupChromeDevtools: parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupChromeDevtools", envKey: "KJ_INSTALL_SETUP_CHROME_DEVTOOLS", fallback: true }), true),
667
- runDoctor: parseBool(pickSetting({ cli: parsedArgs, cliKey: "runDoctor", envKey: "KJ_INSTALL_RUN_DOCTOR", fallback: defaults.runDoctor }), defaults.runDoctor),
668
- runTests: parseBool(pickSetting({ cli: parsedArgs, cliKey: "runTests", envKey: "KJ_INSTALL_RUN_TESTS", fallback: defaults.runTests }), defaults.runTests)
669
663
  };
664
+ settings.reviewerFallback = pickSetting({ cli: parsedArgs, cliKey: "reviewerFallback", envKey: "KJ_INSTALL_REVIEWER_FALLBACK", fallback: settings.reviewer });
665
+ settings.setupMcpClaude = parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupMcpClaude", envKey: "KJ_INSTALL_SETUP_MCP_CLAUDE", fallback: defaults.setupMcpClaude }), defaults.setupMcpClaude);
666
+ settings.setupMcpCodex = parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupMcpCodex", envKey: "KJ_INSTALL_SETUP_MCP_CODEX", fallback: defaults.setupMcpCodex }), defaults.setupMcpCodex);
667
+ settings.setupChromeDevtools = parseBool(pickSetting({ cli: parsedArgs, cliKey: "setupChromeDevtools", envKey: "KJ_INSTALL_SETUP_CHROME_DEVTOOLS", fallback: true }), true);
668
+ settings.runDoctor = parseBool(pickSetting({ cli: parsedArgs, cliKey: "runDoctor", envKey: "KJ_INSTALL_RUN_DOCTOR", fallback: defaults.runDoctor }), defaults.runDoctor);
669
+ settings.runTests = parseBool(pickSetting({ cli: parsedArgs, cliKey: "runTests", envKey: "KJ_INSTALL_RUN_TESTS", fallback: defaults.runTests }), defaults.runTests);
670
+ return settings;
670
671
  }
671
672
 
672
673
  const linkGlobal = await askBool("Link karajan binaries globally with npm link", defaults.linkGlobal);
@@ -706,7 +707,7 @@ async function collectSettings(rootDir, parsedArgs, instanceContext, nonInteract
706
707
  }
707
708
  }
708
709
 
709
- return {
710
+ const settings = {
710
711
  linkGlobal,
711
712
  kjHome,
712
713
  sonarHost,
@@ -717,13 +718,15 @@ async function collectSettings(rootDir, parsedArgs, instanceContext, nonInteract
717
718
  sonarToken,
718
719
  coder: await ask("Default coder", defaults.coder),
719
720
  reviewer: await ask("Default reviewer", defaults.reviewer),
720
- reviewerFallback: await ask("Reviewer fallback", defaults.reviewerFallback),
721
- setupMcpClaude: await askBool("Configure Claude MCP automatically", defaults.setupMcpClaude),
722
- setupMcpCodex: await askBool("Configure Codex MCP automatically", defaults.setupMcpCodex),
723
- setupChromeDevtools: await askBool("Configure Chrome DevTools MCP", true),
724
- runDoctor: await askBool("Run kj doctor now", defaults.runDoctor),
725
- runTests: await askBool("Run tests now", defaults.runTests)
726
721
  };
722
+ settings.reviewerFallback = await ask("Reviewer fallback", settings.reviewer);
723
+ settings.setupMcpClaude = await askBool("Configure Claude MCP automatically", defaults.setupMcpClaude);
724
+ settings.setupMcpCodex = await askBool("Configure Codex MCP automatically", defaults.setupMcpCodex);
725
+ settings.setupChromeDevtools = await askBool("Configure Chrome DevTools MCP", true);
726
+ settings.runDoctor = await askBool("Run kj doctor now", defaults.runDoctor);
727
+ settings.runTests = await askBool("Run tests now", defaults.runTests);
728
+
729
+ return settings;
727
730
  }
728
731
 
729
732
  async function main() {
@@ -1,7 +1,6 @@
1
1
  import { BaseAgent } from "./base-agent.js";
2
2
  import { runCommand } from "../utils/process.js";
3
3
  import { resolveBin } from "./resolve-bin.js";
4
- import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
5
4
 
6
5
  export class AiderAgent extends BaseAgent {
7
6
  async runTask(task) {
@@ -29,13 +28,7 @@ export class AiderAgent extends BaseAgent {
29
28
  async _exec(task, model) {
30
29
  const args = ["--yes", "--message", task.prompt];
31
30
  if (model) args.push("--model", model);
32
- const proxyEnv = getProxyEnv();
33
- if (proxyEnv) {
34
- args.push("--api-base", proxyEnv.OPENAI_BASE_URL);
35
- }
36
- const env = proxyEnv ? { ...process.env, ...proxyEnv } : undefined;
37
31
  const res = await runCommand(resolveBin("aider"), args, {
38
- ...(env && { env }),
39
32
  onOutput: task.onOutput,
40
33
  silenceTimeoutMs: task.silenceTimeoutMs,
41
34
  timeout: task.timeoutMs
@@ -1,7 +1,6 @@
1
1
  import { BaseAgent } from "./base-agent.js";
2
2
  import { runCommand } from "../utils/process.js";
3
3
  import { resolveBin } from "./resolve-bin.js";
4
- import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
5
4
 
6
5
  /**
7
6
  * Safely parse a JSON line, returning null on failure.
@@ -12,6 +11,37 @@ function tryParseJson(line) {
12
11
  } catch { return null; }
13
12
  }
14
13
 
14
+ /**
15
+ * Extract a human-readable error message from Claude's raw NDJSON stderr output.
16
+ * Claude emits system init, api_retry, assistant error, and result lines.
17
+ * We extract just the meaningful error text, discarding the JSON noise.
18
+ */
19
+ export function sanitizeClaudeError(raw) {
20
+ if (!raw) return "Unknown error";
21
+ const lines = raw.split("\n").filter(Boolean);
22
+
23
+ // Look for a result line with the actual error
24
+ for (let i = lines.length - 1; i >= 0; i--) {
25
+ const obj = tryParseJson(lines[i]);
26
+ if (!obj) continue;
27
+ if (obj.type === "result" && obj.result) return String(obj.result);
28
+ if (obj.type === "assistant" && obj.message?.content) {
29
+ const text = obj.message.content
30
+ .filter(b => b.type === "text" && b.text)
31
+ .map(b => b.text)
32
+ .join(" ");
33
+ if (text) return text;
34
+ }
35
+ }
36
+
37
+ // If no JSON parsed, return first non-JSON line or truncated raw
38
+ for (const line of lines) {
39
+ if (!line.startsWith("{")) return line.slice(0, 200);
40
+ }
41
+
42
+ return raw.slice(0, 200);
43
+ }
44
+
15
45
  /**
16
46
  * Try to extract a result string from a parsed JSON object.
17
47
  * Returns the result string or null if the object is not a result message.
@@ -42,7 +72,7 @@ function collectAssistantText(obj) {
42
72
  * usage.input_tokens/output_tokens, and modelUsage.
43
73
  * Returns an object with tokens_in, tokens_out, cost_usd, model or null if not found.
44
74
  */
45
- export function extractUsageFromStreamJson(raw) {
75
+ function extractUsageFromStreamJson(raw) {
46
76
  const lines = (raw || "").split("\n").filter(Boolean);
47
77
  for (let i = lines.length - 1; i >= 0; i--) {
48
78
  const obj = tryParseJson(lines[i]);
@@ -135,8 +165,6 @@ function createStreamJsonFilter(onOutput) {
135
165
  */
136
166
  function cleanExecaOpts(extra = {}) {
137
167
  const { CLAUDECODE, ...env } = process.env;
138
- const proxyEnv = getProxyEnv();
139
- if (proxyEnv) Object.assign(env, proxyEnv);
140
168
  return { env, stdin: "ignore", ...extra };
141
169
  }
142
170
 
@@ -197,7 +225,7 @@ export class ClaudeAgent extends BaseAgent {
197
225
  const raw = pickOutput(res);
198
226
  const output = extractTextFromStreamJson(raw);
199
227
  const usage = extractUsageFromStreamJson(raw);
200
- return { ok: res.exitCode === 0, output, error: res.exitCode === 0 ? "" : raw, exitCode: res.exitCode, ...usage };
228
+ return { ok: res.exitCode === 0, output, error: res.exitCode === 0 ? "" : sanitizeClaudeError(raw), exitCode: res.exitCode, ...usage };
201
229
  }
202
230
 
203
231
  // Without streaming, use json output to get structured response via stderr
@@ -206,7 +234,7 @@ export class ClaudeAgent extends BaseAgent {
206
234
  const raw = pickOutput(res);
207
235
  const output = extractTextFromStreamJson(raw);
208
236
  const usage = extractUsageFromStreamJson(raw);
209
- return { ok: res.exitCode === 0, output, error: res.exitCode === 0 ? "" : raw, exitCode: res.exitCode, ...usage };
237
+ return { ok: res.exitCode === 0, output, error: res.exitCode === 0 ? "" : sanitizeClaudeError(raw), exitCode: res.exitCode, ...usage };
210
238
  }
211
239
 
212
240
  async _reviewTaskExec(task, model) {
@@ -1,7 +1,6 @@
1
1
  import { BaseAgent } from "./base-agent.js";
2
2
  import { runCommand } from "../utils/process.js";
3
3
  import { resolveBin } from "./resolve-bin.js";
4
- import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
5
4
 
6
5
  /**
7
6
  * Extract token usage from Codex CLI stdout.
@@ -10,7 +9,7 @@ import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
10
9
  * Since Codex doesn't split input/output, we assign the total to tokens_out
11
10
  * as a conservative estimate for cost calculation.
12
11
  */
13
- export function extractCodexTokens(stdout) {
12
+ function extractCodexTokens(stdout) {
14
13
  const match = (stdout || "").match(/tokens?\s+used\s*\n\s*([\d,]+)/i);
15
14
  if (!match) return null;
16
15
  const total = Number(match[1].replace(/,/g, ""));
@@ -42,14 +41,11 @@ export class CodexAgent extends BaseAgent {
42
41
  }
43
42
 
44
43
  async _exec(task, model, role) {
45
- const args = ["exec"];
44
+ const args = ["exec", "--skip-git-repo-check"];
46
45
  if (model) args.push("--model", model);
47
46
  if (role !== "reviewer" && this.isAutoApproveEnabled(role)) args.push("--full-auto");
48
47
  args.push("-");
49
- const proxyEnv = getProxyEnv();
50
- const env = proxyEnv ? { ...process.env, ...proxyEnv } : undefined;
51
48
  const res = await runCommand(resolveBin("codex"), args, {
52
- ...(env && { env }),
53
49
  onOutput: task.onOutput,
54
50
  silenceTimeoutMs: task.silenceTimeoutMs,
55
51
  timeout: task.timeoutMs,
@@ -1,7 +1,6 @@
1
1
  import { BaseAgent } from "./base-agent.js";
2
2
  import { runCommand } from "../utils/process.js";
3
3
  import { resolveBin } from "./resolve-bin.js";
4
- import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
5
4
 
6
5
  export class GeminiAgent extends BaseAgent {
7
6
  async runTask(task) {
@@ -30,10 +29,7 @@ export class GeminiAgent extends BaseAgent {
30
29
  const args = ["-p", task.prompt];
31
30
  if (mode === "review") args.push("--output-format", "json");
32
31
  if (model) args.push("--model", model);
33
- const proxyEnv = getProxyEnv();
34
- const env = proxyEnv ? { ...process.env, ...proxyEnv } : undefined;
35
32
  const res = await runCommand(resolveBin("gemini"), args, {
36
- ...(env && { env }),
37
33
  onOutput: task.onOutput,
38
34
  silenceTimeoutMs: task.silenceTimeoutMs,
39
35
  timeout: task.timeoutMs
@@ -1,7 +1,6 @@
1
1
  import { BaseAgent } from "./base-agent.js";
2
2
  import { runCommand } from "../utils/process.js";
3
3
  import { resolveBin } from "./resolve-bin.js";
4
- import { getProxyEnv } from "../proxy/proxy-lifecycle.js";
5
4
 
6
5
  export class OpenCodeAgent extends BaseAgent {
7
6
  async runTask(task) {
@@ -31,10 +30,7 @@ export class OpenCodeAgent extends BaseAgent {
31
30
  if (jsonFormat) args.push("--format", "json");
32
31
  if (model) args.push("--model", model);
33
32
  args.push(task.prompt);
34
- const proxyEnv = getProxyEnv();
35
- const env = proxyEnv ? { ...process.env, ...proxyEnv } : undefined;
36
33
  const res = await runCommand(resolveBin("opencode"), args, {
37
- ...(env && { env }),
38
34
  onOutput: task.onOutput,
39
35
  silenceTimeoutMs: task.silenceTimeoutMs,
40
36
  timeout: task.timeoutMs
@@ -1,12 +1,12 @@
1
1
  /**
2
- * BecarIA dispatch client — sends repository_dispatch events via gh CLI
3
- * so the BecarIA Gateway can publish comments and reviews on PRs.
2
+ * Karajan CI dispatch client — sends repository_dispatch events via gh CLI
3
+ * so the Karajan CI Gateway can publish comments and reviews on PRs.
4
4
  *
5
- * Event types are configurable via becaria config:
6
- * - comment_event (default: "becaria-comment")
7
- * - review_event (default: "becaria-review")
5
+ * Event types are configurable via ci config:
6
+ * - comment_event (default: "kj-comment")
7
+ * - review_event (default: "kj-review")
8
8
  *
9
- * Only active when becaria.enabled: true.
9
+ * Only active when ci.enabled: true.
10
10
  */
11
11
 
12
12
  import { runCommand } from "../utils/process.js";
@@ -59,15 +59,15 @@ async function sendDispatch(repo, payload) {
59
59
  /**
60
60
  * Send a comment event so the gateway posts a PR comment.
61
61
  * @param {object} opts
62
- * @param {object} [opts.becariaConfig] - becaria config section (optional)
62
+ * @param {object} [opts.ciConfig] - ci config section (optional)
63
63
  */
64
- export async function dispatchComment({ repo, prNumber, agent, body, becariaConfig }) {
64
+ export async function dispatchComment({ repo, prNumber, agent, body, ciConfig }) {
65
65
  validateCommon({ repo, prNumber });
66
66
  validateAgent(agent);
67
67
  if (!body) throw new Error("body is required (comment text)");
68
68
 
69
- const prefix = becariaConfig?.comment_prefix === false ? "" : `[${agent}] `;
70
- const eventType = becariaConfig?.comment_event || "becaria-comment";
69
+ const prefix = ciConfig?.comment_prefix === false ? "" : `[${agent}] `;
70
+ const eventType = ciConfig?.comment_event || "kj-comment";
71
71
 
72
72
  await sendDispatch(repo, {
73
73
  event_type: eventType,
@@ -78,9 +78,9 @@ export async function dispatchComment({ repo, prNumber, agent, body, becariaConf
78
78
  /**
79
79
  * Send a review event so the gateway submits a formal PR review.
80
80
  * @param {object} opts
81
- * @param {object} [opts.becariaConfig] - becaria config section (optional)
81
+ * @param {object} [opts.ciConfig] - ci config section (optional)
82
82
  */
83
- export async function dispatchReview({ repo, prNumber, event, body, agent, becariaConfig }) {
83
+ export async function dispatchReview({ repo, prNumber, event, body, agent, ciConfig }) {
84
84
  validateCommon({ repo, prNumber });
85
85
  validateAgent(agent);
86
86
  if (!VALID_REVIEW_EVENTS.includes(event)) {
@@ -90,7 +90,7 @@ export async function dispatchReview({ repo, prNumber, event, body, agent, becar
90
90
  }
91
91
  if (!body) throw new Error("body is required (review text)");
92
92
 
93
- const eventType = becariaConfig?.review_event || "becaria-review";
93
+ const eventType = ciConfig?.review_event || "kj-review";
94
94
 
95
95
  await sendDispatch(repo, {
96
96
  event_type: eventType,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Read PR diff via gh CLI for BecarIA Gateway flow.
2
+ * Read PR diff via gh CLI for Karajan CI flow.
3
3
  * The reviewer reads the PR diff instead of local git diff.
4
4
  */
5
5
 
package/src/cli.js CHANGED
@@ -57,7 +57,7 @@ program
57
57
  .command("init")
58
58
  .description("Initialize config, review rules and SonarQube")
59
59
  .option("--no-interactive", "Skip wizard, use defaults (for CI/scripts)")
60
- .option("--scaffold-becaria", "Scaffold BecarIA Gateway workflow files")
60
+ .option("--scaffold-ci", "Scaffold Karajan CI Gateway workflow files")
61
61
  .action(async (flags) => {
62
62
  await withConfig("init", flags, async ({ config, logger }) => {
63
63
  await initCommand({ logger, flags });
@@ -111,7 +111,7 @@ program
111
111
  .option("--auto-commit")
112
112
  .option("--auto-push")
113
113
  .option("--auto-pr")
114
- .option("--enable-becaria", "Enable BecarIA Gateway (early PR + dispatch comments/reviews)")
114
+ .option("--enable-ci", "Enable Karajan CI (early PR + dispatch comments/reviews)")
115
115
  .option("--branch-prefix <prefix>")
116
116
  .option("--task-type <type>", "Explicit task type: sw, infra, doc, add-tests, refactor")
117
117
  .option("--methodology <name>")
@@ -127,6 +127,7 @@ program
127
127
  .option("--smart-models", "Enable smart model selection based on triage complexity")
128
128
  .option("--no-smart-models", "Disable smart model selection")
129
129
  .option("--design", "Activate design refactoring mode (impeccable role applies design changes)")
130
+ .option("--domain <text-or-path>", "Domain knowledge: inline text or path to .md file")
130
131
  .option("--dry-run", "Show what would be executed without running anything")
131
132
  .option("--json", "Output JSON only (no styled display)")
132
133
  .option("-q, --quiet", "Show only stage status lines, suppress raw agent output (default)")
@@ -89,4 +89,3 @@ export async function agentsCommand({ config, subcommand, role, provider, global
89
89
  return agents;
90
90
  }
91
91
 
92
- export { ASSIGNABLE_ROLES, VALID_PROVIDERS };
@@ -12,7 +12,7 @@ import { ensureGitRepo } from "../utils/git.js";
12
12
  import { checkBinary, KNOWN_AGENTS } from "../utils/agent-detect.js";
13
13
  import { getInstallCommand } from "../utils/os-detect.js";
14
14
  import { withDocLink } from "../utils/doc-links.js";
15
- import { isProxyRunning } from "../proxy/proxy-lifecycle.js";
15
+
16
16
 
17
17
  function getPackageVersion() {
18
18
  const pkgPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../package.json");
@@ -144,27 +144,27 @@ async function checkSerena() {
144
144
  };
145
145
  }
146
146
 
147
- async function checkBecariaWorkflows(projectDir) {
147
+ async function checkCiWorkflows(projectDir) {
148
148
  const checks = [];
149
149
  const workflowDir = path.join(projectDir, ".github", "workflows");
150
- const requiredWorkflows = ["becaria-gateway.yml", "automerge.yml", "houston-override.yml"];
150
+ const requiredWorkflows = ["kj-ci-gateway.yml", "automerge.yml", "houston-override.yml"];
151
151
  for (const wf of requiredWorkflows) {
152
152
  const wfPath = path.join(workflowDir, wf);
153
153
  const wfExists = await exists(wfPath);
154
154
  checks.push({
155
- name: `becaria:workflow:${wf}`,
156
- label: `BecarIA workflow: ${wf}`,
155
+ name: `ci:workflow:${wf}`,
156
+ label: `CI workflow: ${wf}`,
157
157
  ok: wfExists,
158
158
  detail: wfExists ? "Found" : "Not found",
159
- fix: wfExists ? null : `Run 'kj init --scaffold-becaria' or copy from karajan-code/templates/workflows/${wf}`
159
+ fix: wfExists ? null : `Run 'kj init --scaffold-ci' or copy from karajan-code/templates/workflows/${wf}`
160
160
  });
161
161
  }
162
162
  return checks;
163
163
  }
164
164
 
165
- async function checkBecariaSecrets() {
165
+ async function checkCiSecrets() {
166
166
  try {
167
- const { detectRepo } = await import("../becaria/repo.js");
167
+ const { detectRepo } = await import("../ci/repo.js");
168
168
  const repo = await detectRepo();
169
169
  if (!repo) return null;
170
170
 
@@ -172,38 +172,38 @@ async function checkBecariaSecrets() {
172
172
  if (secretsRes.exitCode !== 0) return null;
173
173
 
174
174
  const names = new Set(secretsRes.stdout.split("\n").map((s) => s.trim()));
175
- const hasAppId = names.has("BECARIA_APP_ID");
176
- const hasKey = names.has("BECARIA_APP_PRIVATE_KEY");
175
+ const hasAppId = names.has("KJ_CI_APP_ID");
176
+ const hasKey = names.has("KJ_CI_PRIVATE_KEY");
177
177
  const secretsOk = hasAppId && hasKey;
178
- const missing = [!hasAppId && "BECARIA_APP_ID", !hasKey && "BECARIA_APP_PRIVATE_KEY"].filter(Boolean).join(" ");
178
+ const missing = [!hasAppId && "KJ_CI_APP_ID", !hasKey && "KJ_CI_PRIVATE_KEY"].filter(Boolean).join(" ");
179
179
  return {
180
- name: "becaria:secrets",
181
- label: "BecarIA: GitHub secrets",
180
+ name: "ci:secrets",
181
+ label: "CI: GitHub secrets",
182
182
  ok: secretsOk,
183
- detail: secretsOk ? "BECARIA_APP_ID + BECARIA_APP_PRIVATE_KEY found" : `Missing: ${missing}`,
184
- fix: secretsOk ? null : "Add BECARIA_APP_ID and BECARIA_APP_PRIVATE_KEY as GitHub repository secrets"
183
+ detail: secretsOk ? "KJ_CI_APP_ID + KJ_CI_PRIVATE_KEY found" : `Missing: ${missing}`,
184
+ fix: secretsOk ? null : "Add KJ_CI_APP_ID and KJ_CI_PRIVATE_KEY as GitHub repository secrets"
185
185
  };
186
186
  } catch { /* GitHub API error */
187
187
  return null;
188
188
  }
189
189
  }
190
190
 
191
- async function checkBecariaInfra(config) {
191
+ async function checkCiInfra(config) {
192
192
  const checks = [];
193
193
  const projectDir = config.projectDir || process.cwd();
194
194
 
195
- checks.push(...await checkBecariaWorkflows(projectDir));
195
+ checks.push(...await checkCiWorkflows(projectDir));
196
196
 
197
197
  const ghCheck = await checkBinary("gh");
198
198
  checks.push({
199
- name: "becaria:gh",
200
- label: "BecarIA: gh CLI",
199
+ name: "ci:gh",
200
+ label: "CI: gh CLI",
201
201
  ok: ghCheck.ok,
202
202
  detail: ghCheck.ok ? ghCheck.version : "Not found",
203
203
  fix: ghCheck.ok ? null : "Install GitHub CLI: https://cli.github.com/"
204
204
  });
205
205
 
206
- const secretsCheck = await checkBecariaSecrets();
206
+ const secretsCheck = await checkCiSecrets();
207
207
  if (secretsCheck) checks.push(secretsCheck);
208
208
 
209
209
  return checks;
@@ -343,23 +343,6 @@ async function checkAgentConfigs() {
343
343
  return checks;
344
344
  }
345
345
 
346
- async function checkProxy(config) {
347
- if (config.proxy?.enabled === false) {
348
- return { name: "proxy", label: "Proxy", ok: true, detail: "Disabled in config", fix: null };
349
- }
350
- let running = false;
351
- try {
352
- running = await isProxyRunning();
353
- } catch { /* proxy check failed */ }
354
- return {
355
- name: "proxy",
356
- label: "Proxy",
357
- ok: true,
358
- detail: running ? "Running" : "Available (starts on kj run)",
359
- fix: null
360
- };
361
- }
362
-
363
346
  export async function runChecks({ config }) {
364
347
  const checks = [];
365
348
 
@@ -377,14 +360,13 @@ export async function runChecks({ config }) {
377
360
  checks.push(await checkSerena());
378
361
  }
379
362
 
380
- if (config.becaria?.enabled) {
381
- checks.push(...await checkBecariaInfra(config));
363
+ if (config.ci?.enabled) {
364
+ checks.push(...await checkCiInfra(config));
382
365
  }
383
366
 
384
367
  checks.push(...await checkAgentConfigs());
385
368
  checks.push(...await checkRuleFiles(config));
386
369
  checks.push(await checkRtk());
387
- checks.push(await checkProxy(config));
388
370
 
389
371
  return checks;
390
372
  }
@@ -222,14 +222,14 @@ async function setupSonarQube(config, logger) {
222
222
  logger.info(' or export KJ_SONAR_TOKEN="<your-token>"');
223
223
  }
224
224
 
225
- async function scaffoldBecariaGateway(config, flags, logger) {
226
- if (!config.becaria?.enabled && !flags.scaffoldBecaria) return;
225
+ async function scaffoldCiGateway(config, flags, logger) {
226
+ if (!config.ci?.enabled && !flags.scaffoldCi) return;
227
227
  const projectDir = process.cwd();
228
228
  const workflowDir = path.join(projectDir, ".github", "workflows");
229
229
  await ensureDir(workflowDir);
230
230
 
231
231
  const templatesDir = path.resolve(import.meta.dirname, "../../templates/workflows");
232
- const workflows = ["becaria-gateway.yml", "automerge.yml", "houston-override.yml"];
232
+ const workflows = ["kj-ci-gateway.yml", "automerge.yml", "houston-override.yml"];
233
233
 
234
234
  for (const wf of workflows) {
235
235
  const destPath = path.join(workflowDir, wf);
@@ -248,11 +248,11 @@ async function scaffoldBecariaGateway(config, flags, logger) {
248
248
  }
249
249
 
250
250
  logger.info("");
251
- logger.info("BecarIA Gateway scaffolded. Next steps:");
252
- logger.info(" 1. Create a GitHub App named 'becaria-reviewer' with pull_request write permissions");
251
+ logger.info("Karajan CI Gateway scaffolded. Next steps:");
252
+ logger.info(" 1. Create a GitHub App named 'kj-reviewer' with pull_request write permissions");
253
253
  logger.info(" 2. Install the App on your repository");
254
- logger.info(" 3. Add secrets: BECARIA_APP_ID and BECARIA_APP_PRIVATE_KEY");
255
- logger.info(" 4. Push the workflow files and enable 'kj run --enable-becaria'");
254
+ logger.info(" 3. Add secrets: KJ_CI_APP_ID and KJ_CI_PRIVATE_KEY");
255
+ logger.info(" 4. Push the workflow files and enable 'kj run --enable-ci'");
256
256
  }
257
257
 
258
258
  async function installSkills(logger, interactive) {
@@ -403,7 +403,7 @@ export async function initCommand({ logger, flags = {} }) {
403
403
  }
404
404
 
405
405
  await setupSonarQube(config, logger);
406
- await scaffoldBecariaGateway(config, flags, logger);
406
+ await scaffoldCiGateway(config, flags, logger);
407
407
 
408
408
  // Telemetry: anonymous install event (non-blocking)
409
409
  const { sendTelemetryEvent } = await import("../utils/telemetry.js");
@@ -153,7 +153,6 @@ async function buildReport(dir, sessionId) {
153
153
  if (session.pg_task_id) report.pg_task_id = session.pg_task_id;
154
154
  if (session.pg_project_id) report.pg_project_id = session.pg_project_id;
155
155
  if (session.rtk_savings) report.rtk_savings = session.rtk_savings;
156
- if (session.proxy_stats) report.proxy_stats = session.proxy_stats;
157
156
  return report;
158
157
  }
159
158
 
@@ -200,7 +199,6 @@ function printTextReport(report) {
200
199
  console.log(formatBudgetText(report.budget_consumed));
201
200
  console.log("Commits Generated:");
202
201
  console.log(formatCommitsText(report.commits_generated));
203
- printProxyStats(report.proxy_stats);
204
202
  }
205
203
 
206
204
  function formatDuration(ms) {
@@ -329,16 +327,6 @@ async function resolveTraceOptions(currency) {
329
327
  return { cur, rate };
330
328
  }
331
329
 
332
- function printProxyStats(proxyStats) {
333
- if (!proxyStats) return;
334
- const orig = proxyStats.originalTokens ?? 0;
335
- const comp = proxyStats.compressedTokens ?? 0;
336
- const pct = orig > 0 ? ((1 - comp / orig) * 100).toFixed(1) : "0.0";
337
- const hits = proxyStats.cacheHits ?? 0;
338
- console.log("");
339
- console.log(`Proxy: ${orig} original tokens, ${comp} compressed tokens, ${pct}% savings, ${hits} cache hits`);
340
- }
341
-
342
330
  function printRtkSavings(rtkSavings) {
343
331
  if (!rtkSavings || !rtkSavings.callCount) return;
344
332
  const tokens = rtkSavings.estimatedTokensSaved ?? 0;
@@ -357,7 +345,6 @@ function printTraceReport(report, currency, exchangeRate) {
357
345
  console.log("");
358
346
  printTraceTable(report.budget_trace, { currency, exchangeRate });
359
347
  printRtkSavings(report.rtk_savings);
360
- printProxyStats(report.proxy_stats);
361
348
  }
362
349
 
363
350
  async function handlePgTaskReport({ dir, pgTask, list, sessionId, format, trace, currency }) {