karajan-code 4.1.0 → 4.1.1

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": "4.1.0",
3
+ "version": "4.1.1",
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",
@@ -102,8 +102,14 @@ export function createKarajanMcpCheck() {
102
102
  return {
103
103
  ok: result.ok,
104
104
  severity: result.ok ? "info" : "warn",
105
- detail: result.ok ? result.detail : `karajan-mcp did not respond: ${result.detail}`,
106
- fix: result.ok ? undefined : "Re-run karajan-mcp via `node bin/karajan-mcp.js`",
105
+ // KJC-BUG-0118: the MCP is OPTIONAL in the v4 environment (the host
106
+ // agent drives kj via CLI) — a dead MCP must read as a degraded
107
+ // optional, never as a broken install. The standalone (curl) binary
108
+ // cannot run it at all (no bundled native modules).
109
+ detail: result.ok
110
+ ? result.detail
111
+ : `karajan-mcp did not respond: ${result.detail} — OPTIONAL in v4: your agent runs kj directly; only shell-less hosts need MCP`,
112
+ fix: result.ok ? undefined : "Only if you need MCP: install via npm (`npm i -g karajan-code`) — the standalone binary does not bundle it",
107
113
  extra: { binPath },
108
114
  };
109
115
  },
@@ -51,7 +51,10 @@ export function createNativeBuildCheck({ loadDb = defaultLoadDb, isPnpm = isPnpm
51
51
  return {
52
52
  ok: false,
53
53
  severity: "warn",
54
- detail: `better-sqlite3 failed to load: ${firstLine}`,
54
+ // KJC-BUG-0118: the standalone (curl) binary ships without native
55
+ // modules by design — name the consequence (RAG/board/MCP need the
56
+ // npm install) instead of implying the install is broken.
57
+ detail: `better-sqlite3 failed to load: ${firstLine} — DB-backed features (RAG, board, MCP) unavailable; the standalone binary does not bundle native modules`,
55
58
  fix: "Reinstall to rebuild native modules: `npm i -g karajan-code`",
56
59
  };
57
60
  }
@@ -10,6 +10,7 @@ import { existsSync, readFileSync } from "node:fs";
10
10
  import { join } from "node:path";
11
11
 
12
12
  import { loadConfig } from "../config.js";
13
+ import { resolveTestOnPush } from "../harden/test-on-push.js";
13
14
  import { compareHarden, formatAdvisoryReport } from "../harden/advisory.js";
14
15
  import { interactiveHarden } from "../harden/interactive.js";
15
16
  import { createWizard, isTTY } from "../utils/wizard.js";
@@ -121,6 +122,14 @@ export async function hardenCommand({
121
122
 
122
123
  const roots = detectStackRoots(projectDir, { only: onlyDirs, exclude: excludeDirs });
123
124
  const cmds = await resolveCmds(projectDir, roots[0]?.language ?? null);
125
+ // KJC-TSK-0647: CI already running the suite per PR ⇒ pre-push drops its
126
+ // test command (false-red source under local parallelism); opt back in
127
+ // via package.json kj.harden.test_on_push.
128
+ const top = resolveTestOnPush({ projectDir, repoCfg, testCmd: cmds.test });
129
+ if (top.reason) {
130
+ logger.info?.(`kj harden: ${top.reason}`);
131
+ cmds.test = undefined;
132
+ }
124
133
  // KJC-TSK-0648: branch-first guard — the base branch only moves via PR.
125
134
  // Resolved from the project's kj config (default "main"); best-effort so
126
135
  // harden keeps working on repos that never ran kj init.
@@ -9,6 +9,7 @@ import { runCommand } from "../utils/process.js";
9
9
  import { checkVerdict } from "../review/verdict-store.js";
10
10
  import { runOneShotReview } from "../review/one-shot-review.js";
11
11
  import { runSolomonArbitration } from "../review/solomon-arbitration.js";
12
+ import { ensureGateTrackable } from "../review/gate-gitignore.js";
12
13
 
13
14
  // Raw git always — never a wrapped/compressing runner (KJC-BUG-0115).
14
15
  async function rawDiff(range) {
@@ -64,6 +65,12 @@ export async function reviewGateCommand({ config, logger = null, flags = {} }) {
64
65
  await fs.mkdir(path.dirname(marker), { recursive: true });
65
66
  await fs.writeFile(marker, "# Cross-AI review gate enabled (ENV-C1). Commit this file so the whole team inherits the gate.\n");
66
67
  console.log("✓ review gate enabled — commits now require an approved cross-AI verdict (kj review --staged)");
68
+ // KJC-TSK-0646: a `.karajan/` dir-exclude would silently keep the
69
+ // contract out of git — rewrite it so the team actually inherits it.
70
+ const gi = await ensureGateTrackable(projectDir);
71
+ if (gi.changed) {
72
+ console.log("✓ .gitignore adjusted: the gate contract (.karajan/review-gate, hooks) is now trackable — commit it");
73
+ }
67
74
  const hookProbe = await runCommand("git", ["config", "core.hooksPath"]);
68
75
  if (!hookProbe.stdout?.trim()) {
69
76
  console.log("⚠ no core.hooksPath configured — run `kj harden` so the pre-commit hook enforces the gate");
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Test-on-push policy (KJC-TSK-0647) — the full suite on every push is
3
+ * redundant when CI already runs it per PR, and a source of false reds
4
+ * (suites unstable under local parallelism). Field-reproduced.
5
+ *
6
+ * Policy: a CI workflow that runs tests ⇒ pre-push drops its test command
7
+ * (identity guard and chaining stay). Repos can force it back with
8
+ * `"kj": { "harden": { "test_on_push": true } }` in package.json. Repos
9
+ * without CI keep tests on push — there it IS the last safety net.
10
+ */
11
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+
14
+ const TEST_STEP = /\b(npm (run )?test|vitest|jest|pytest|go test|phpunit|cargo test)\b/;
15
+
16
+ export function ciRunsTests(projectDir) {
17
+ const dir = join(projectDir, ".github", "workflows");
18
+ if (!existsSync(dir)) return false;
19
+ try {
20
+ return readdirSync(dir)
21
+ .filter((f) => /\.ya?ml$/.test(f))
22
+ .some((f) => TEST_STEP.test(readFileSync(join(dir, f), "utf8")));
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+
28
+ export function resolveTestOnPush({ projectDir, repoCfg = {}, testCmd = null }) {
29
+ if (!testCmd) return { testCmd: null, reason: null };
30
+ if (repoCfg.test_on_push === true) return { testCmd, reason: null };
31
+ if (ciRunsTests(projectDir)) {
32
+ return {
33
+ testCmd: null,
34
+ reason: "CI already runs the suite per PR — pre-push keeps only the identity guard (opt back in with kj.harden.test_on_push: true in package.json)",
35
+ };
36
+ }
37
+ return { testCmd, reason: null };
38
+ }
Binary file