karajan-code 4.66.0 → 4.66.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.66.0",
3
+ "version": "4.66.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",
@@ -50,15 +50,16 @@ export function guardCommand(guard, { blocking = false, viaKj = isSea() || !kjHo
50
50
  return `if command -v ${bin} >/dev/null 2>&1; then ${run}; else ${missing}${blocking ? "; exit 2" : ""}; fi`;
51
51
  }
52
52
 
53
- /** The wiring kj harden wrote before ADR 0030: node running the project's copy. */
54
- const withoutLegacy = (list, script) => {
55
- const legacy = `node ${join(".karajan", "harness", script)}`;
56
- return list.flatMap((e) => {
57
- if (!Array.isArray(e?.hooks) || !e.hooks.some((h) => h?.command === legacy)) return [e];
58
- const hooks = e.hooks.filter((h) => h?.command !== legacy);
59
- return hooks.length ? [{ ...e, hooks }] : [];
60
- });
61
- };
53
+ /**
54
+ * Drop the commands that ran this guard some other way: node on the project's copy
55
+ * (before ADR 0030) or the other runner (KJC-BUG-0403: switching runner must not
56
+ * leave the guard wired twice).
57
+ */
58
+ const withoutStale = (list, stale) => list.flatMap((e) => {
59
+ if (!Array.isArray(e?.hooks) || !e.hooks.some((h) => stale.includes(h?.command))) return [e];
60
+ const hooks = e.hooks.filter((h) => !stale.includes(h?.command));
61
+ return hooks.length ? [{ ...e, hooks }] : [];
62
+ });
62
63
 
63
64
  /**
64
65
  * KJC-TSK-1206 (ADR 0030): the wiring is what decides which guard runs, so it is
@@ -98,7 +99,7 @@ export function wiringState({ projectDir, entries }) {
98
99
  * basename; an entry is present when that script already appears under the
99
100
  * same event (and matcher, when given).
100
101
  */
101
- export function mergeClaudeHooks({ projectDir, logger = console, entries }) {
102
+ export function mergeClaudeHooks({ projectDir, logger = console, entries, viaKj = isSea() || !kjHookOnPath() }) {
102
103
  const settingsPath = join(projectDir, ".claude", "settings.json");
103
104
  let settings = {};
104
105
  if (existsSync(settingsPath)) {
@@ -116,10 +117,12 @@ export function mergeClaudeHooks({ projectDir, logger = console, entries }) {
116
117
  return { wired: false };
117
118
  }
118
119
  }
119
- const viaKj = isSea() || !kjHookOnPath();
120
120
  for (const { event, matcher, script } of entries) {
121
- const list = withoutLegacy(Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [], script);
122
- const command = guardCommand(script.replace(/\.mjs$/, ""), { blocking: event === "PreToolUse", viaKj });
121
+ const guard = script.replace(/\.mjs$/, "");
122
+ const blocking = event === "PreToolUse";
123
+ const stale = [`node ${join(".karajan", "harness", script)}`, guardCommand(guard, { blocking, viaKj: !viaKj })];
124
+ const list = withoutStale(Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [], stale);
125
+ const command = guardCommand(guard, { blocking, viaKj });
123
126
  const present = list.some(
124
127
  (e) => (e?.hooks || []).some((h) => h?.command === command) && (matcher === undefined || e?.matcher === matcher),
125
128
  );