karajan-code 3.15.1 → 3.15.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "3.15.1",
3
+ "version": "3.15.2",
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",
@@ -31,7 +31,11 @@ export const ERROR_CLASS = Object.freeze({
31
31
  const ONE_HOUR_MS = 60 * 60 * 1000;
32
32
  const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
33
33
 
34
- const AUTH_PATTERNS = /\b401\b|\b403\b|unauthorized|invalid\s+api\s+key|authentication\s+failed|expired\s+token/i;
34
+ // `error\s+authenticating` + `IneligibleTierError` (KJC-BUG-0113): the
35
+ // retired Gemini Code Assist CLI fails with "Error authenticating:
36
+ // IneligibleTierError … migrate to Antigravity" — it classified as
37
+ // UNKNOWN_FATAL and left the run without the AUTH escalation message.
38
+ const AUTH_PATTERNS = /\b401\b|\b403\b|unauthorized|invalid\s+api\s+key|authentication\s+failed|expired\s+token|error\s+authenticating|IneligibleTierError/i;
35
39
  const SILENCED_PATTERNS = /killed\s+after\s+\d+\s*ms|silence\s*timeout|no\s+output\s+for\s+\d+/i;
36
40
  // `session\s+limit` / `weekly\s+limit` cover Claude Code's usage caps
37
41
  // ("You've hit your session limit · resets 10:10pm"). Without them the
@@ -16,7 +16,8 @@ import {
16
16
  commitAll,
17
17
  pushBranch,
18
18
  createPullRequest,
19
- listPendingPaths
19
+ listPendingPaths,
20
+ hasRemote
20
21
  } from "../utils/git.js";
21
22
 
22
23
  /**
@@ -276,7 +277,19 @@ export async function finalizeGitAutomation({ config, gitCtx, task, logger, sess
276
277
  logger.info(committed ? "Committed changes" : "No changes to commit");
277
278
  }
278
279
 
279
- if (config.git.auto_push || config.git.auto_pr) {
280
+ // KJC-BUG-0112: without an `origin` remote (the quickstart scenario:
281
+ // fresh folder + git init) push/PR automation has nothing to talk to —
282
+ // fetchBase used to throw here and escalate to Solomon on EVERY
283
+ // iteration, burning the whole budget on an expected condition.
284
+ const remoteAvailable = (config.git.auto_push || config.git.auto_pr)
285
+ ? await hasRemote()
286
+ : false;
287
+ if ((config.git.auto_push || config.git.auto_pr) && !remoteAvailable) {
288
+ logger.info("No remote configured — skipping push/PR automation");
289
+ await addCheckpoint(session, { stage: "git-push", skipped: "no-remote" });
290
+ }
291
+
292
+ if (remoteAvailable && (config.git.auto_push || config.git.auto_pr)) {
280
293
  await fetchBase(gitCtx.baseBranch);
281
294
  await ensureBranchUpToDateWithBase({
282
295
  branch: gitCtx.branch,
@@ -286,14 +299,14 @@ export async function finalizeGitAutomation({ config, gitCtx, task, logger, sess
286
299
  await addCheckpoint(session, { stage: "git-rebase-check", branch: gitCtx.branch });
287
300
  }
288
301
 
289
- if (config.git.auto_push || config.git.auto_pr) {
302
+ if (remoteAvailable && (config.git.auto_push || config.git.auto_pr)) {
290
303
  await pushBranch(gitCtx.branch);
291
304
  await addCheckpoint(session, { stage: "git-push", branch: gitCtx.branch });
292
305
  logger.info(`Pushed branch: ${gitCtx.branch}`);
293
306
  }
294
307
 
295
308
  let prUrl = session.ci_pr_url || null;
296
- if (config.git.auto_pr && !prUrl) {
309
+ if (remoteAvailable && config.git.auto_pr && !prUrl) {
297
310
  const body = buildPrBody({ task, stageResults });
298
311
  prUrl = await createPullRequest({
299
312
  baseBranch: gitCtx.baseBranch,
@@ -123,7 +123,11 @@ export async function invokeSolomon({ config, logger, emitter, eventBase, stage,
123
123
  return escalateToHuman({ askQuestion, session, emitter, eventBase, stage, conflict, iteration });
124
124
  }
125
125
 
126
- const solomonProvider = config?.roles?.solomon?.provider || "gemini";
126
+ // KJC-BUG-0113: the fallback used to be "gemini" — Google retired the
127
+ // Gemini Code Assist CLI for individuals (IneligibleTierError), so an
128
+ // unconfigured Solomon died on every escalation. Claude matches the
129
+ // brain.provider default.
130
+ const solomonProvider = config?.roles?.solomon?.provider || "claude";
127
131
  emitProgress(
128
132
  emitter,
129
133
  makeEvent("solomon:start", { ...eventBase, stage: "solomon" }, {
@@ -8,7 +8,8 @@ import {
8
8
  commitAll,
9
9
  pushBranch,
10
10
  createPullRequest,
11
- revParse
11
+ revParse,
12
+ hasRemote
12
13
  } from "../utils/git.js";
13
14
 
14
15
  function buildCommitMessage(task) {
@@ -59,7 +60,13 @@ export class CommiterRole extends BaseRole {
59
60
  await commitAll(msg);
60
61
  const commitHash = await revParse("HEAD");
61
62
 
62
- if (push) {
63
+ // KJC-BUG-0112: no `origin` remote (quickstart scenario) → skip
64
+ // push/PR instead of throwing on fetch.
65
+ const remoteAvailable = push ? await hasRemote() : false;
66
+ if (push && !remoteAvailable) {
67
+ this.logger?.info?.("No remote configured — skipping push/PR");
68
+ }
69
+ if (push && remoteAvailable) {
63
70
  const baseBranch = this.config.base_branch || "main";
64
71
  await fetchBase(baseBranch);
65
72
  await ensureBranchUpToDateWithBase({
@@ -71,7 +78,7 @@ export class CommiterRole extends BaseRole {
71
78
  }
72
79
 
73
80
  let prUrl = null;
74
- if (push && createPr) {
81
+ if (push && createPr && remoteAvailable) {
75
82
  const baseBranch = this.config.base_branch || "main";
76
83
  prUrl = await createPullRequest({
77
84
  baseBranch,
@@ -12,7 +12,10 @@ const KNOWN_AGENTS = [
12
12
 
13
13
  export async function checkBinary(name, versionArg = "--version") {
14
14
  const resolved = resolveBin(name);
15
- const res = await runCommand(resolved, [versionArg]);
15
+ // KJC-BUG-0113: a zombie CLI that hangs on --version (seen with the
16
+ // retired Gemini Code Assist binary) must not hang init/preflight —
17
+ // 5s is generous for a version print.
18
+ const res = await runCommand(resolved, [versionArg], { timeout: 5000 });
16
19
  const version = (res.stdout || res.stderr || "").split("\n")[0].trim();
17
20
  return { ok: res.exitCode === 0, version, path: resolved };
18
21
  }
package/src/utils/git.js CHANGED
@@ -251,6 +251,16 @@ export async function commitAll(message, cwd = null) {
251
251
  return { committed: true, commit: { hash, message: commitMessage } };
252
252
  }
253
253
 
254
+ /**
255
+ * KJC-BUG-0112: whether the repo has an `origin` remote. The quickstart
256
+ * scenario (fresh folder + git init) has none — post-approval push/PR
257
+ * automation must skip instead of failing and escalating to Solomon.
258
+ */
259
+ export async function hasRemote(cwd = null) {
260
+ const res = await run("git", ["remote", "get-url", "origin"], cwd ? { cwd } : {});
261
+ return res.exitCode === 0;
262
+ }
263
+
254
264
  export async function pushBranch(branch, cwd = null) {
255
265
  await runGit(["push", "-u", "origin", branch], cwd ? { cwd } : {});
256
266
  }