karajan-code 1.59.1 → 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 (112) 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 +1 -4
  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 +2 -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/git/automation.js +9 -9
  21. package/src/guards/output-guard.js +0 -17
  22. package/src/mcp/handlers/direct-handlers.js +1 -1
  23. package/src/mcp/handlers/run-handler.js +1 -2
  24. package/src/mcp/sovereignty-guard.js +1 -1
  25. package/src/mcp/tools.js +1 -1
  26. package/src/orchestrator/brain-coordinator.js +165 -0
  27. package/src/orchestrator/ci-integration.js +139 -0
  28. package/src/orchestrator/config-init.js +435 -0
  29. package/src/orchestrator/direct-actions.js +186 -0
  30. package/src/orchestrator/feedback-enrichment.js +140 -0
  31. package/src/orchestrator/feedback-queue.js +152 -0
  32. package/src/orchestrator/flow-control.js +159 -0
  33. package/src/orchestrator/post-loop-stages.js +20 -15
  34. package/src/orchestrator/preflight-checks.js +7 -3
  35. package/src/orchestrator/role-output-compressor.js +190 -0
  36. package/src/orchestrator/session-journal.js +344 -0
  37. package/src/orchestrator/solomon-escalation.js +38 -5
  38. package/src/orchestrator/solomon-rules.js +32 -33
  39. package/src/orchestrator/stages/reviewer-stage.js +16 -5
  40. package/src/orchestrator/stages/sonar-stage.js +24 -1
  41. package/src/orchestrator/verification-gate.js +146 -0
  42. package/src/orchestrator.js +428 -664
  43. package/src/planning-game/client.js +2 -2
  44. package/src/planning-game/pipeline-adapter.js +1 -1
  45. package/src/prompts/coder.js +17 -3
  46. package/src/prompts/reviewer.js +2 -2
  47. package/src/prompts/rtk-snippet.js +3 -5
  48. package/src/review/diff-generator.js +66 -17
  49. package/src/review/snapshot-diff.js +122 -0
  50. package/src/review/tdd-policy.js +4 -2
  51. package/src/roles/agent-role.js +135 -0
  52. package/src/roles/architect-role.js +61 -108
  53. package/src/roles/audit-role.js +25 -71
  54. package/src/roles/coder-role.js +32 -57
  55. package/src/roles/discover-role.js +30 -71
  56. package/src/roles/hu-reviewer-role.js +51 -99
  57. package/src/roles/impeccable-role.js +33 -88
  58. package/src/roles/index.js +2 -0
  59. package/src/roles/karajan-brain-role.js +134 -0
  60. package/src/roles/planner-role.js +40 -75
  61. package/src/roles/refactorer-role.js +22 -64
  62. package/src/roles/researcher-role.js +51 -115
  63. package/src/roles/reviewer-role.js +68 -125
  64. package/src/roles/security-role.js +38 -102
  65. package/src/roles/solomon-role.js +69 -11
  66. package/src/roles/tester-role.js +121 -95
  67. package/src/roles/triage-role.js +50 -111
  68. package/src/session-store.js +1 -1
  69. package/src/skills/skill-detector.js +11 -0
  70. package/src/sonar/config-resolver.js +20 -1
  71. package/src/sonar/credentials.js +17 -0
  72. package/src/sonar/project-key.js +1 -1
  73. package/src/sonar/scanner.js +1 -1
  74. package/src/utils/display.js +33 -14
  75. package/src/utils/injection-guard.js +23 -8
  76. package/src/utils/logger.js +6 -1
  77. package/src/utils/process.js +3 -4
  78. package/src/utils/role-assigner.js +131 -0
  79. package/src/utils/update-check.js +5 -1
  80. package/src/webperf/devtools-detect.js +70 -23
  81. package/templates/roles/coder.md +7 -0
  82. package/templates/roles/karajan-brain.md +95 -0
  83. package/templates/roles/solomon.md +67 -106
  84. package/templates/workflows/automerge.yml +4 -4
  85. package/templates/workflows/houston-override.yml +4 -4
  86. package/templates/workflows/{becaria-gateway.yml → kj-ci-gateway.yml} +12 -12
  87. package/src/proxy/adapters/anthropic.js +0 -131
  88. package/src/proxy/adapters/gemini.js +0 -106
  89. package/src/proxy/adapters/index.js +0 -51
  90. package/src/proxy/adapters/openai.js +0 -71
  91. package/src/proxy/compression/ai-compressor.js +0 -209
  92. package/src/proxy/compression/dedup-cache.js +0 -100
  93. package/src/proxy/compression/deterministic/bash-build.js +0 -60
  94. package/src/proxy/compression/deterministic/bash-git.js +0 -101
  95. package/src/proxy/compression/deterministic/bash-infra.js +0 -64
  96. package/src/proxy/compression/deterministic/bash-misc.js +0 -53
  97. package/src/proxy/compression/deterministic/bash-pkg.js +0 -49
  98. package/src/proxy/compression/deterministic/bash-test.js +0 -61
  99. package/src/proxy/compression/deterministic/glob.js +0 -26
  100. package/src/proxy/compression/deterministic/grep.js +0 -53
  101. package/src/proxy/compression/deterministic/index.js +0 -58
  102. package/src/proxy/compression/deterministic/read.js +0 -22
  103. package/src/proxy/compression/deterministic/utils.js +0 -33
  104. package/src/proxy/compression/pipeline.js +0 -270
  105. package/src/proxy/middleware/prompt-injector.js +0 -165
  106. package/src/proxy/middleware/response-interceptor.js +0 -223
  107. package/src/proxy/progress-monitor.js +0 -98
  108. package/src/proxy/proxy-lifecycle.js +0 -201
  109. package/src/proxy/proxy-server.js +0 -239
  110. package/src/proxy/security.js +0 -45
  111. /package/src/{becaria → ci}/index.js +0 -0
  112. /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.1",
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
@@ -72,7 +72,7 @@ function collectAssistantText(obj) {
72
72
  * usage.input_tokens/output_tokens, and modelUsage.
73
73
  * Returns an object with tokens_in, tokens_out, cost_usd, model or null if not found.
74
74
  */
75
- export function extractUsageFromStreamJson(raw) {
75
+ function extractUsageFromStreamJson(raw) {
76
76
  const lines = (raw || "").split("\n").filter(Boolean);
77
77
  for (let i = lines.length - 1; i >= 0; i--) {
78
78
  const obj = tryParseJson(lines[i]);
@@ -165,9 +165,6 @@ function createStreamJsonFilter(onOutput) {
165
165
  */
166
166
  function cleanExecaOpts(extra = {}) {
167
167
  const { CLAUDECODE, ...env } = process.env;
168
- // NOTE: Claude Code CLI does not respect ANTHROPIC_BASE_URL — proxy env
169
- // injection is skipped for claude to avoid ECONNREFUSED errors.
170
- // Other agents (codex, gemini, aider) use SDKs that do respect base URL vars.
171
168
  return { env, stdin: "ignore", ...extra };
172
169
  }
173
170
 
@@ -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>")
@@ -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 }) {
@@ -7,24 +7,24 @@ import { resolveReviewProfile } from "../review/profiles.js";
7
7
 
8
8
  export async function reviewCommand({ task, config, logger, baseRef }) {
9
9
  const reviewerRole = resolveRole(config, "reviewer");
10
- await assertAgentsAvailable([reviewerRole.provider, config.reviewer_options?.fallback_reviewer]);
10
+ await assertAgentsAvailable([reviewerRole.provider]);
11
11
  logger.info(`Reviewer (${reviewerRole.provider}) starting...`);
12
12
  const reviewer = createAgent(reviewerRole.provider, config, logger);
13
13
 
14
14
  let diff;
15
- if (config.becaria?.enabled) {
16
- // BecarIA mode: read diff from open PR
17
- const { detectRepo, detectPrNumber } = await import("../becaria/repo.js");
18
- const { getPrDiff } = await import("../becaria/pr-diff.js");
15
+ if (config.ci?.enabled) {
16
+ // CI mode: read diff from open PR
17
+ const { detectRepo, detectPrNumber } = await import("../ci/repo.js");
18
+ const { getPrDiff } = await import("../ci/pr-diff.js");
19
19
  const repo = await detectRepo();
20
20
  const prNumber = await detectPrNumber();
21
21
  if (!prNumber) {
22
- throw new Error("BecarIA enabled but no open PR found for current branch. Create a PR first or disable BecarIA.");
22
+ throw new Error("CI enabled but no open PR found for current branch. Create a PR first or disable CI.");
23
23
  }
24
- logger.info(`BecarIA: reading PR diff #${prNumber}`);
24
+ logger.info(`CI: reading PR diff #${prNumber}`);
25
25
  diff = await getPrDiff(prNumber);
26
26
  // Store for dispatch later
27
- config._becaria_pr = { repo, prNumber };
27
+ config._ci_pr = { repo, prNumber };
28
28
  } else {
29
29
  const resolvedBase = await computeBaseRef({ baseBranch: config.base_branch, baseRef });
30
30
  diff = await generateDiff({ baseRef: resolvedBase });
@@ -42,12 +42,12 @@ export async function reviewCommand({ task, config, logger, baseRef }) {
42
42
  console.log(result.output);
43
43
  logger.info(`Reviewer completed (exit ${result.exitCode})`);
44
44
 
45
- // BecarIA: dispatch review result
46
- if (config.becaria?.enabled && config._becaria_pr) {
45
+ // CI: dispatch review result
46
+ if (config.ci?.enabled && config._ci_pr) {
47
47
  try {
48
- const { dispatchReview, dispatchComment } = await import("../becaria/dispatch.js");
49
- const { repo, prNumber } = config._becaria_pr;
50
- const bc = config.becaria;
48
+ const { dispatchReview, dispatchComment } = await import("../ci/dispatch.js");
49
+ const { repo, prNumber } = config._ci_pr;
50
+ const bc = config.ci;
51
51
 
52
52
  // Try to parse structured review from output
53
53
  let review;
@@ -61,18 +61,18 @@ export async function reviewCommand({ task, config, logger, baseRef }) {
61
61
  await dispatchReview({
62
62
  repo, prNumber, event,
63
63
  body: review.summary || result.output.slice(0, 500),
64
- agent: "Reviewer", becariaConfig: bc
64
+ agent: "Reviewer", ciConfig: bc
65
65
  });
66
66
 
67
67
  await dispatchComment({
68
68
  repo, prNumber, agent: "Reviewer",
69
69
  body: `Standalone review: ${event}\n\n${review.summary || result.output.slice(0, 1000)}`,
70
- becariaConfig: bc
70
+ ciConfig: bc
71
71
  });
72
72
 
73
- logger.info(`BecarIA: dispatched review for PR #${prNumber}`);
73
+ logger.info(`CI: dispatched review for PR #${prNumber}`);
74
74
  } catch (err) {
75
- logger.warn(`BecarIA dispatch failed (non-blocking): ${err.message}`);
75
+ logger.warn(`CI dispatch failed (non-blocking): ${err.message}`);
76
76
  }
77
77
  }
78
78
  }
@@ -35,8 +35,7 @@ export async function runCommandHandler({ task, config, logger, flags }) {
35
35
  } catch { /* non-blocking */ }
36
36
 
37
37
  const requiredProviders = [
38
- resolveRole(config, "coder").provider,
39
- config.reviewer_options?.fallback_reviewer
38
+ resolveRole(config, "coder").provider
40
39
  ];
41
40
  if (config.pipeline?.reviewer?.enabled !== false) {
42
41
  requiredProviders.push(resolveRole(config, "reviewer").provider);
@@ -5,7 +5,7 @@
5
5
  import { readRunLog } from "../utils/run-log.js";
6
6
  import { loadMostRecentSession } from "../session-store.js";
7
7
  import { buildDashboard } from "../utils/status-dashboard.js";
8
- import { getProxyStats } from "../proxy/proxy-lifecycle.js";
8
+
9
9
 
10
10
  /**
11
11
  * Run the `kj status` command: print a human-readable dashboard to stdout.
@@ -33,10 +33,4 @@ export async function statusCommand({ lines = 50, projectDir } = {}) {
33
33
 
34
34
  const dashboard = buildDashboard(session, logResult.lines || [], { stories });
35
35
  console.log(dashboard);
36
-
37
- const proxyStats = getProxyStats();
38
- if (proxyStats) {
39
- console.log("");
40
- console.log(`Proxy: port ${proxyStats.port}, ${proxyStats.requests} requests, ${proxyStats.bytes_in} bytes in, ${proxyStats.bytes_out} bytes out`);
41
- }
42
36
  }