karajan-code 3.15.0 → 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/README.md CHANGED
@@ -234,7 +234,7 @@ Karajan ships as **layers you opt into**. The base CLI is tiny (~5 MB). Heavier
234
234
  - **Pipeline RAM peak**: 1–2 GB per `kj run` (one orchestrator + one coder + one reviewer subprocess at a time).
235
235
  - **SQLite is in-process.** No separate DB daemon. `~/.karajan/` is a folder, not a service.
236
236
  - **First-run Ollama pull**: ~5 min in the background; you can keep working — `kj` falls back to a cloud embedder if Ollama isn't ready yet.
237
- - **Runtime**: Node.js ≥ 22.22.1 (Active LTS). v3.0.0 dropped Node 20 support. Use `kj doctor` to verify your environment.
237
+ - **Runtime**: Node.js ≥ 22.12.0 (Active LTS). v3.0.0 dropped Node 20 support. Use `kj doctor` to verify your environment.
238
238
 
239
239
  ## Two ways to use Karajan
240
240
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "3.15.0",
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",
@@ -24,7 +24,7 @@
24
24
  "cli"
25
25
  ],
26
26
  "engines": {
27
- "node": ">=22.22.1"
27
+ "node": ">=22.12.0"
28
28
  },
29
29
  "kj": {
30
30
  "harden": {
@@ -25,7 +25,7 @@
25
25
  "aider"
26
26
  ],
27
27
  "engines": {
28
- "node": ">=22.22.1"
28
+ "node": ">=22.12.0"
29
29
  },
30
30
  "bin": {
31
31
  "kj-trash": "bin/kj-trash.js"
@@ -5,7 +5,7 @@
5
5
  "type": "module",
6
6
  "private": true,
7
7
  "engines": {
8
- "node": ">=22.22.1"
8
+ "node": ">=22.12.0"
9
9
  },
10
10
  "scripts": {
11
11
  "start": "node src/server.js",
@@ -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
@@ -2,8 +2,12 @@
2
2
  * Node.js runtime version check. Requires Node >= 22 — the Active LTS
3
3
  * baseline since Karajan v3.0.0 (KJC-TSK-0500, 2026-06-03). Node 20 was
4
4
  * dropped because (a) Node 20 reaches EOL on 2026-04-30 and (b) three
5
- * dependencies forced the bump: lint-staged 17 needs ≥22.22.1, commander
6
- * 15 needs ≥22.12.0, and better-sqlite3 v12.10+ dropped Node 20 prebuilds.
5
+ * dependencies forced the bump: commander 15 needs ≥22.12.0 and
6
+ * better-sqlite3 v12.10+ dropped Node 20 prebuilds. engines.node is
7
+ * ">=22.12.0" — the highest RUNTIME floor. KJC-BUG-0111: it briefly sat
8
+ * at 22.22.1 (lint-staged 17's floor — a devDependency end users never
9
+ * run) and npm silently served karajan-code@2.34.0 to every Node
10
+ * 22.0-22.21 install; keep dev-tool floors out of engines.
7
11
  * Strategy: manual — we cannot auto-upgrade the runtime. Users on older
8
12
  * Node get a clear upgrade instruction with nvm + brew hints instead of a
9
13
  * silent runtime crash.
@@ -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
  }