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
package/src/checks/mcp-health.js
CHANGED
|
@@ -102,8 +102,14 @@ export function createKarajanMcpCheck() {
|
|
|
102
102
|
return {
|
|
103
103
|
ok: result.ok,
|
|
104
104
|
severity: result.ok ? "info" : "warn",
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/commands/harden.js
CHANGED
|
@@ -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
|