karajan-code 3.12.1 → 3.12.3

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.
Files changed (68) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -5
  3. package/packages/hu-board/package.json +1 -1
  4. package/packages/hu-board/src/plan-mutations.js +4 -4
  5. package/packages/hu-board/src/routes/api.js +1 -1
  6. package/packages/hu-board/src/routes/rag.js +1 -1
  7. package/packages/hu-board/src/routes/wiki.js +1 -1
  8. package/packages/hu-board/src/run-tracker.js +1 -1
  9. package/packages/hu-board/src/server.js +2 -2
  10. package/packages/hu-board/src/sync.js +1 -1
  11. package/scripts/build-sea.mjs +23 -1
  12. package/scripts/esbuild-sea.config.mjs +22 -1
  13. package/scripts/verify-pack.mjs +38 -6
  14. package/src/audit/osv-findings.js +1 -1
  15. package/src/brain/standby-scheduler.js +2 -2
  16. package/src/brain/standby-store.js +2 -2
  17. package/src/commands/init.js +4 -3
  18. package/src/commands/onboard.js +2 -1
  19. package/src/git/hu-snapshot.js +2 -2
  20. package/src/orchestrator/config-init.js +2 -1
  21. package/src/plan/plan-hu-ops.js +2 -2
  22. package/src/plan/plan-id.js +2 -2
  23. package/src/plan/plan-validation.js +2 -2
  24. package/src/prompts/prompt-resolver.js +2 -9
  25. package/src/rag/vec-store.js +2 -2
  26. package/src/utils/atomic-write.js +3 -3
  27. package/src/utils/install-hints.js +5 -1
  28. package/src/utils/paths.js +2 -2
  29. package/src/utils/port-check.js +3 -3
  30. package/src/utils/process.js +2 -2
  31. package/src/utils/run-registry.js +2 -2
  32. package/src/utils/shared-paths.js +3 -3
  33. package/src/utils/templates-root.js +61 -0
  34. package/src/utils/update-check.js +78 -15
  35. package/node_modules/@karajan/core/README.md +0 -42
  36. package/node_modules/@karajan/core/package.json +0 -49
  37. package/node_modules/@karajan/core/src/atomic-write.js +0 -43
  38. package/node_modules/@karajan/core/src/cost/index.js +0 -102
  39. package/node_modules/@karajan/core/src/hu-snapshot.js +0 -105
  40. package/node_modules/@karajan/core/src/index.js +0 -18
  41. package/node_modules/@karajan/core/src/paths.js +0 -123
  42. package/node_modules/@karajan/core/src/plan-hu-ops.js +0 -338
  43. package/node_modules/@karajan/core/src/plan-id.js +0 -45
  44. package/node_modules/@karajan/core/src/plan-validation.js +0 -82
  45. package/node_modules/@karajan/core/src/port-check.js +0 -45
  46. package/node_modules/@karajan/core/src/pricing/index.js +0 -64
  47. package/node_modules/@karajan/core/src/pricing/model-pricing.json +0 -28
  48. package/node_modules/@karajan/core/src/process.js +0 -188
  49. package/node_modules/@karajan/core/src/run-registry.js +0 -115
  50. package/node_modules/@karajan/core/src/shared-paths.js +0 -41
  51. package/node_modules/@karajan/core/src/standby-scheduler.js +0 -92
  52. package/node_modules/@karajan/core/src/standby-store.js +0 -168
  53. package/node_modules/@karajan/core/src/vec-store.js +0 -253
  54. package/node_modules/@karajan/core/tests/atomic-write.test.js +0 -30
  55. package/node_modules/@karajan/core/tests/cost/index.test.js +0 -89
  56. package/node_modules/@karajan/core/tests/hu-snapshot.test.js +0 -39
  57. package/node_modules/@karajan/core/tests/paths.test.js +0 -51
  58. package/node_modules/@karajan/core/tests/plan-hu-ops.test.js +0 -68
  59. package/node_modules/@karajan/core/tests/plan-id.test.js +0 -21
  60. package/node_modules/@karajan/core/tests/plan-validation.test.js +0 -39
  61. package/node_modules/@karajan/core/tests/port-check.test.js +0 -47
  62. package/node_modules/@karajan/core/tests/pricing/index.test.js +0 -95
  63. package/node_modules/@karajan/core/tests/process.test.js +0 -22
  64. package/node_modules/@karajan/core/tests/run-registry.test.js +0 -71
  65. package/node_modules/@karajan/core/tests/shared-paths.test.js +0 -30
  66. package/node_modules/@karajan/core/tests/standby.test.js +0 -66
  67. package/node_modules/@karajan/core/tests/vec-store.test.js +0 -98
  68. package/node_modules/@karajan/core/vitest.config.js +0 -12
package/README.md CHANGED
@@ -190,7 +190,7 @@ None of these are required. Karajan auto-skips any scanner that isn't installed,
190
190
  | Tool | Scope | Install | Installable from `kj init`? | What you get |
191
191
  |------|-------|---------|-----------------------------|--------------|
192
192
  | **SonarQube** | Any stack | `docker compose -f ~/sonarqube/docker-compose.yml up -d` | ✅ Yes (wizard configures Docker container + token) | Code quality + security rules with line-precision in `kj audit` |
193
- | **OSV-Scanner** | Any stack | `go install github.com/google/osv-scanner@latest` | ❌ No (install manually) | Dependency CVE coverage broader than `npm audit` |
193
+ | **OSV-Scanner** | Any stack | `go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest` | ❌ No (install manually) | Dependency CVE coverage broader than `npm audit` |
194
194
  | **Semgrep** | Any stack | `pipx install semgrep` | ❌ No (install manually) | SAST: XSS, SQLi, taint flow, secrets — equivalent to `snyk code`, free for OSS |
195
195
  | **Lighthouse** | **Frontend only** | `npm install -g lighthouse` | ❌ No (install manually) | Core Web Vitals + opportunities for `kj webperf` (auto-feeds `kj audit`) |
196
196
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "3.12.1",
3
+ "version": "3.12.3",
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",
@@ -98,7 +98,6 @@
98
98
  },
99
99
  "dependencies": {
100
100
  "@babel/parser": "^7.29.7",
101
- "@karajan/core": "*",
102
101
  "@modelcontextprotocol/sdk": "^1.29.0",
103
102
  "better-sqlite3": "^12.10.0",
104
103
  "chokidar": "^5.0.0",
@@ -108,15 +107,13 @@
108
107
  "express-rate-limit": "^8.5.0",
109
108
  "helmet": "^8.1.0",
110
109
  "js-yaml": "^4.2.0",
110
+ "karajan-core": "^1.0.0",
111
111
  "knip": "^6.15.0",
112
112
  "madge": "^8.0.0",
113
113
  "sqlite-vec": "^0.1.9",
114
114
  "valibot": "^1.4.1",
115
115
  "web-tree-sitter": "^0.26.9"
116
116
  },
117
- "bundleDependencies": [
118
- "@karajan/core"
119
- ],
120
117
  "devDependencies": {
121
118
  "@eslint/js": "^10.0.1",
122
119
  "@vitest/coverage-v8": "^4.1.8",
@@ -13,7 +13,7 @@
13
13
  "test": "vitest run"
14
14
  },
15
15
  "dependencies": {
16
- "@karajan/core": "*",
16
+ "karajan-core": "*",
17
17
  "better-sqlite3": "^12.10.0",
18
18
  "chokidar": "^5.0.0",
19
19
  "express": "^5.1.0",
@@ -17,13 +17,13 @@
17
17
  import { readFileSync, existsSync, readdirSync, mkdirSync, openSync } from 'node:fs';
18
18
  import { join, dirname } from 'node:path';
19
19
  import { homedir } from 'node:os';
20
- import { writeJsonAtomicSync } from '@karajan/core/atomic-write';
20
+ import { writeJsonAtomicSync } from 'karajan-core/atomic-write';
21
21
  import { spawn } from 'node:child_process';
22
22
  import { trackRun, untrack } from './run-tracker.js';
23
23
  import { getHuBoardRunsDir } from './db.js';
24
24
  import { fileURLToPath } from 'node:url';
25
- import { updateHuStatus, certifyAllHus, updateHu } from '@karajan/core/plan-hu-ops';
26
- import { validateBlockedByChange } from '@karajan/core/plan-validation';
25
+ import { updateHuStatus, certifyAllHus, updateHu } from 'karajan-core/plan-hu-ops';
26
+ import { validateBlockedByChange } from 'karajan-core/plan-validation';
27
27
  import { syncPlanFile } from './sync.js';
28
28
  import { getDb } from './db.js';
29
29
 
@@ -230,7 +230,7 @@ export async function revertHuFromSnapshot({ planId, huId, projectId }) {
230
230
  const projectDir = plan.projectDir;
231
231
  if (!projectDir) return { ok: false, error: 'plan sin projectDir' };
232
232
 
233
- const { restoreHuSnapshot } = await import('@karajan/core/hu-snapshot');
233
+ const { restoreHuSnapshot } = await import('karajan-core/hu-snapshot');
234
234
  const restore = await restoreHuSnapshot({ projectDir, huId });
235
235
  if (!restore.ok) return { ok: false, error: `restore falló: ${restore.error}` };
236
236
 
@@ -1361,7 +1361,7 @@ router.post('/rag/query', async (req, res) => {
1361
1361
  return res.status(400).json({ error: "'text' is required (non-empty string)" });
1362
1362
  }
1363
1363
  try {
1364
- const { openVecStore, countChunks } = await import('@karajan/core/vec-store');
1364
+ const { openVecStore, countChunks } = await import('karajan-core/vec-store');
1365
1365
  const { makeEmbedder } = await import('../../../../src/rag/embedders/factory.js');
1366
1366
  const { query } = await import('../../../../src/rag/retriever.js');
1367
1367
  const db = openVecStore({ dim: 768 });
@@ -5,7 +5,7 @@
5
5
  import { Router } from "express";
6
6
  import { existsSync, statSync } from "node:fs";
7
7
  import Database from "better-sqlite3";
8
- import { dbPath } from "@karajan/core/vec-store";
8
+ import { dbPath } from "karajan-core/vec-store";
9
9
  import { readConfig } from "../config-yaml.js";
10
10
 
11
11
  const router = Router();
@@ -4,7 +4,7 @@
4
4
  // 503 with installable:true so the front renders an "Install QMD" CTA
5
5
  // instead of a generic error when the binary is missing.
6
6
  import { Router } from "express";
7
- import { runCommand } from "@karajan/core/process";
7
+ import { runCommand } from "karajan-core/process";
8
8
 
9
9
  const router = Router();
10
10
  const QMD_NOT_INSTALLED = /command not found|ENOENT|not recognized as/i;
@@ -16,7 +16,7 @@
16
16
  * se borran como cleanup (responsabilidad de run-registry).
17
17
  */
18
18
 
19
- import { listActiveRuns as fsList } from "@karajan/core/run-registry";
19
+ import { listActiveRuns as fsList } from "karajan-core/run-registry";
20
20
 
21
21
  const runs = new Map();
22
22
  let reaperTimer = null;
@@ -17,7 +17,7 @@ import { reapZombieSessions } from './zombie-reaper.js';
17
17
  import { reapZombieHus } from './hu-zombie-reaper.js';
18
18
  import { setHuStatus as setHuStatusPlanMutation, setHuFailResult as setHuFailResultPlanMutation } from './plan-mutations.js';
19
19
  import { cleanupEphemeralProjects } from './ephemeral-cleaner.js';
20
- import { findAvailablePort as findAvailablePortBase } from '@karajan/core/port-check';
20
+ import { findAvailablePort as findAvailablePortBase } from 'karajan-core/port-check';
21
21
 
22
22
  /**
23
23
  * Path to the PID file the CLI's `kj board start` / `kj board stop`
@@ -238,7 +238,7 @@ async function main() {
238
238
  // - cooldownUntil > now → re-programa setTimeout que dispara en cooldown
239
239
  // Idempotente (lockfile per session). Cero polling.
240
240
  try {
241
- const { reconcileAll } = await import('@karajan/core/standby-scheduler');
241
+ const { reconcileAll } = await import('karajan-core/standby-scheduler');
242
242
  const { spawn } = await import('node:child_process');
243
243
  const { join, dirname } = await import('node:path');
244
244
  const { fileURLToPath } = await import('node:url');
@@ -14,7 +14,7 @@ import {
14
14
  removeTombstone,
15
15
  } from './db.js';
16
16
  import { publish as publishEvent } from './event-bus.js';
17
- import { getSharedPlansDir, SHARED_DIR_NAME, isSharedPath } from '@karajan/core/shared-paths';
17
+ import { getSharedPlansDir, SHARED_DIR_NAME, isSharedPath } from 'karajan-core/shared-paths';
18
18
  import { readConfig } from './config-yaml.js';
19
19
 
20
20
  /**
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  import { execSync } from "node:child_process";
22
- import { cpSync, mkdirSync, writeFileSync, statSync } from "node:fs";
22
+ import { cpSync, mkdirSync, writeFileSync, statSync, readFileSync } from "node:fs";
23
23
  import path from "node:path";
24
24
  import { fileURLToPath } from "node:url";
25
25
 
@@ -59,10 +59,32 @@ async function main() {
59
59
 
60
60
  // ── Step 2: Generate SEA blob ───────────────────────────────────
61
61
  console.log("[2/5] Generating SEA preparation blob...");
62
+ // Templates travel as SEA assets (KJC-BUG-0104): the binary ships no
63
+ // templates/ directory, so kj init / role prompts / onboard resolved
64
+ // paths like $HOME/templates/skills and hit ENOENT. The runtime
65
+ // (src/utils/templates-root.js) reads the index asset and extracts
66
+ // the files to ~/.karajan/embedded-templates/<version>/ on first use.
67
+ const { collectTemplateFiles } = await import("./esbuild-sea.config.mjs");
68
+ const pkgVersion = JSON.parse(
69
+ readFileSync(path.join(ROOT, "package.json"), "utf8"),
70
+ ).version;
71
+ const templateFiles = collectTemplateFiles();
72
+ writeFileSync(
73
+ path.join(DIST, "templates-index.json"),
74
+ JSON.stringify({ version: pkgVersion, files: templateFiles }),
75
+ );
76
+ // Absolute paths: node resolves asset paths against the CWD (not the
77
+ // config file), so anything relative is ambiguous.
78
+ const assets = { "templates-index.json": path.join(DIST, "templates-index.json") };
79
+ for (const rel of templateFiles) {
80
+ assets[`templates/${rel}`] = path.join(ROOT, "templates", rel);
81
+ }
82
+ console.log(` -> ${templateFiles.length} template assets embedded.`);
62
83
  const seaConfig = {
63
84
  main: "dist/kj-bundle.cjs",
64
85
  output: "dist/sea-prep.blob",
65
86
  disableExperimentalSEAWarning: true,
87
+ assets,
66
88
  };
67
89
  writeFileSync(
68
90
  path.join(DIST, "sea-config.json"),
@@ -10,7 +10,7 @@
10
10
 
11
11
  import path from "node:path";
12
12
  import fs from "node:fs/promises";
13
- import { readFileSync } from "node:fs";
13
+ import { readFileSync, readdirSync } from "node:fs";
14
14
  import { fileURLToPath } from "node:url";
15
15
 
16
16
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
@@ -213,6 +213,27 @@ const auditHistoryStubPlugin = {
213
213
  };
214
214
 
215
215
  /** @type {import('esbuild').BuildOptions} */
216
+ /**
217
+ * List every built-in template file, as paths relative to templates/
218
+ * (KJC-BUG-0104). The SEA binary ships them as SEA assets — build-sea.mjs
219
+ * turns this list into the sea-config `assets` map plus an index the
220
+ * runtime (src/utils/templates-root.js) uses to extract them on first use.
221
+ * Exported (instead of living in build-sea.mjs, which runs main() on
222
+ * import) so tests can exercise it.
223
+ */
224
+ export function collectTemplateFiles(rootDir = path.join(ROOT, "templates")) {
225
+ const files = [];
226
+ const walk = (dir) => {
227
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
228
+ const p = path.join(dir, entry.name);
229
+ if (entry.isDirectory()) walk(p);
230
+ else files.push(path.relative(rootDir, p));
231
+ }
232
+ };
233
+ walk(rootDir);
234
+ return files.sort();
235
+ }
236
+
216
237
  export const seaBuildOptions = {
217
238
  entryPoints: ["src/cli.js"],
218
239
  outfile: "dist/kj-bundle.cjs",
@@ -3,7 +3,7 @@
3
3
  * Pre-publish tarball smoke gate (KJC-TSK-0553).
4
4
  *
5
5
  * WHY: the test suite runs against the linked workspace, where
6
- * `@karajan/core` and its deps resolve via symlink — so a broken
6
+ * `karajan-core` and its deps resolve via symlink — so a broken
7
7
  * PUBLISHED artifact (bundleDependencies dragging in sqlite-vec without
8
8
  * its entry point, KJC-BUG-0082 / 0086) passed CI yet failed on every
9
9
  * clean `npm install`. v3.2.0, v3.3.0 and v3.4.1 all shipped unable to
@@ -50,6 +50,7 @@ function fail(msg, detail) {
50
50
 
51
51
  let tgzPath = null;
52
52
  let tmpDir = null;
53
+ let gTmp = null;
53
54
  let pnpmTmp = null;
54
55
  try {
55
56
  console.log(`verify-pack: packing karajan-code@${expectedVersion}…`);
@@ -92,15 +93,16 @@ try {
92
93
  console.log("verify-pack: kj --help ✓");
93
94
 
94
95
  // 3. The deps that broke before must resolve in the installed tree.
95
- const installedRoot = path.join(tmpDir, "node_modules", "karajan-code");
96
+ // karajan-core is a registry dep since KJC-BUG-0103 (no bundling), so it
97
+ // hoists to the consumer's top-level node_modules like everything else.
96
98
  const checks = [
97
99
  path.join(tmpDir, "node_modules", "sqlite-vec", "index.mjs"),
98
- path.join(installedRoot, "node_modules", "@karajan", "core", "src", "vec-store.js"),
100
+ path.join(tmpDir, "node_modules", "karajan-core", "src", "vec-store.js"),
99
101
  ];
100
102
  for (const p of checks) {
101
103
  if (!fs.existsSync(p)) fail(`expected resolved path missing in install: ${p}`);
102
104
  }
103
- console.log("verify-pack: sqlite-vec + @karajan/core resolve ✓");
105
+ console.log("verify-pack: sqlite-vec + karajan-core resolve ✓");
104
106
 
105
107
  // 4. kj-trash (ai-trash safety binary) must ship + link onto PATH and boot
106
108
  // without a module-resolution crash. It was silently absent from the tarball
@@ -115,9 +117,38 @@ try {
115
117
  }
116
118
  console.log("verify-pack: kj-trash ships + boots ✓");
117
119
 
118
- // 5. pnpm install smoke (KJC-TSK-0580). pnpm's layout differs from npm's
120
+ // 5. GLOBAL install smoke (KJC-BUG-0103). `npm install -g` nests every dep
121
+ // under karajan-code/node_modules; with bundleDependencies present, npm
122
+ // treated that whole subtree as "already in the tarball" and skipped
123
+ // fetching better-sqlite3 & friends — EMPTY dirs whose install scripts then
124
+ // crashed. Local installs hoist and never hit it, which is exactly why the
125
+ // check above stayed green for ~15 broken releases. A fresh global install
126
+ // must succeed and kj must boot.
127
+ gTmp = fs.mkdtempSync(path.join(os.tmpdir(), "kj-verify-g-"));
128
+ console.log(`verify-pack: installing the tarball GLOBALLY into ${gTmp}…`);
129
+ try {
130
+ run("npm", ["install", "-g", tgzPath, "--no-audit", "--no-fund", "--silent", "--prefix", gTmp]);
131
+ } catch (err) {
132
+ fail("`npm install -g` of the tarball failed (KJC-BUG-0103 class)", err.stderr || err.message);
133
+ }
134
+ const gBin = process.platform === "win32"
135
+ ? path.join(gTmp, "kj.cmd")
136
+ : path.join(gTmp, "bin", "kj");
137
+ if (!fs.existsSync(gBin)) fail(`kj binary missing after global install: ${gBin}`);
138
+ let gVersion;
139
+ try {
140
+ gVersion = run(gBin, ["--version"]).trim();
141
+ } catch (err) {
142
+ fail("`kj --version` crashed on a fresh GLOBAL install", err.stderr || err.message);
143
+ }
144
+ if (!gVersion.includes(expectedVersion)) {
145
+ fail(`kj --version (global) returned "${gVersion}", expected ${expectedVersion}`);
146
+ }
147
+ console.log(`verify-pack: global install + kj --version → ${gVersion} ✓`);
148
+
149
+ // 6. pnpm install smoke (KJC-TSK-0580). pnpm's layout differs from npm's
119
150
  // (a symlinked virtual store), so it can break resolution of the bundled
120
- // @karajan/core the way npm packaging breakage did before (KJC-BUG-0082/0086).
151
+ // karajan-core the way npm packaging breakage did before (KJC-BUG-0082/0086).
121
152
  // Verify a pnpm install resolves the JS tree and `kj --version` boots — every
122
153
  // release catches a pnpm packaging regression. (pnpm also blocks
123
154
  // better-sqlite3's native build by default, so DB-backed commands need
@@ -158,5 +189,6 @@ try {
158
189
  } finally {
159
190
  if (tgzPath && fs.existsSync(tgzPath)) fs.rmSync(tgzPath, { force: true });
160
191
  if (tmpDir && fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true, force: true });
192
+ if (gTmp && fs.existsSync(gTmp)) fs.rmSync(gTmp, { recursive: true, force: true });
161
193
  if (pnpmTmp && fs.existsSync(pnpmTmp)) fs.rmSync(pnpmTmp, { recursive: true, force: true });
162
194
  }
@@ -48,7 +48,7 @@ export async function collectOsvFindings(projectDir, logger = null) {
48
48
  // err.code 1 is NORMAL — we still want the stdout. Real failures are
49
49
  // ENOENT (binary missing) or stdout empty.
50
50
  if (err.code === "ENOENT") {
51
- if (logger?.warn) logger.warn("osv-scanner not found in PATH — install via 'go install github.com/google/osv-scanner@latest'");
51
+ if (logger?.warn) logger.warn("osv-scanner not found in PATH — install via 'go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest'");
52
52
  return { available: false, reason: "osv-scanner not installed" };
53
53
  }
54
54
  if (err.killed) {
@@ -1,8 +1,8 @@
1
- // Shim de compatibilidad: standby-scheduler vive ahora en @karajan/core.
1
+ // Shim de compatibilidad: standby-scheduler vive ahora en karajan-core.
2
2
  // Mantiene la ruta para callers internos del CLI.
3
3
  export {
4
4
  _resetScheduledForTests,
5
5
  scheduleResume,
6
6
  cancelScheduled,
7
7
  reconcileAll,
8
- } from "@karajan/core/standby-scheduler";
8
+ } from "karajan-core/standby-scheduler";
@@ -1,4 +1,4 @@
1
- // Shim de compatibilidad: standby-store vive ahora en @karajan/core.
1
+ // Shim de compatibilidad: standby-store vive ahora en karajan-core.
2
2
  // Mantiene la ruta para callers internos del CLI.
3
3
  export {
4
4
  standbyDir,
@@ -9,4 +9,4 @@ export {
9
9
  listPendingStandby,
10
10
  markStandbyDone,
11
11
  acquireStandbyLock,
12
- } from "@karajan/core/standby-store";
12
+ } from "karajan-core/standby-store";
@@ -7,6 +7,7 @@ import { ollamaUp, waitForOllamaReady, normalizeOllamaConfig } from "../rag/olla
7
7
  import { checkOllamaCapability, pullOllamaModel } from "../rag/ollama-capability.js";
8
8
  import { exists, ensureDir } from "../utils/fs.js";
9
9
  import { getKarajanHome } from "../utils/paths.js";
10
+ import { getTemplatesRoot } from "../utils/templates-root.js";
10
11
  import { detectAvailableAgents } from "../utils/agent-detect.js";
11
12
  import { createWizard, isTTY } from "../utils/wizard.js";
12
13
  import { runCommand } from "../utils/process.js";
@@ -441,7 +442,7 @@ async function ensureReviewRules(reviewRulesPath, logger) {
441
442
 
442
443
  async function ensureCoderRules(coderRulesPath, logger) {
443
444
  if (await exists(coderRulesPath)) return;
444
- const templatePath = path.resolve(import.meta.dirname, "../../templates/coder-rules.md");
445
+ const templatePath = path.join(getTemplatesRoot(), "coder-rules.md");
445
446
  let content;
446
447
  try {
447
448
  content = await fs.readFile(templatePath, "utf8");
@@ -537,7 +538,7 @@ async function scaffoldCiGateway(config, flags, logger) {
537
538
  const workflowDir = path.join(projectDir, ".github", "workflows");
538
539
  await ensureDir(workflowDir);
539
540
 
540
- const templatesDir = path.resolve(import.meta.dirname, "../../templates/workflows");
541
+ const templatesDir = path.join(getTemplatesRoot(), "workflows");
541
542
  const workflows = ["kj-ci-gateway.yml", "automerge.yml", "houston-override.yml"];
542
543
 
543
544
  for (const wf of workflows) {
@@ -611,7 +612,7 @@ async function bootstrapOllama({ flags, config, logger, interactive }) {
611
612
  async function installSkills(logger, interactive) {
612
613
  const projectDir = process.cwd();
613
614
  const commandsDir = path.join(projectDir, ".claude", "commands");
614
- const skillsTemplateDir = path.resolve(import.meta.dirname, "../../templates/skills");
615
+ const skillsTemplateDir = path.join(getTemplatesRoot(), "skills");
615
616
 
616
617
  let doInstall = true;
617
618
  if (interactive) {
@@ -6,6 +6,7 @@ import { collectAll } from "../onboarder/collectors/index.js";
6
6
  import { OnboarderRole } from "../roles/onboarder-role.js";
7
7
  import { resolveRole } from "../config.js";
8
8
  import { getKarajanHome } from "../utils/paths.js";
9
+ import { getTemplatesRoot } from "../utils/templates-root.js";
9
10
 
10
11
  export function briefPath(projectDir) {
11
12
  const slug = path.basename(projectDir).replace(/[^a-zA-Z0-9._-]/g, "-").toLowerCase() || "project";
@@ -28,7 +29,7 @@ export async function onboardCommand({ config, logger, flags = {} }) {
28
29
  return { path: out, bundle, brief: null };
29
30
  }
30
31
  const roleCfg = resolveRole(config, "onboarder") || resolveRole(config, "architect");
31
- const templatePath = new URL("../../templates/roles/onboarder.md", import.meta.url).pathname;
32
+ const templatePath = path.join(getTemplatesRoot(), "roles", "onboarder.md");
32
33
  const instructions = existsSync(templatePath) ? await readFile(templatePath, "utf8") : "";
33
34
  const role = new OnboarderRole({ instructions, config, ...roleCfg });
34
35
  // KJC-BUG-0061 Bug B: BaseRole.run() refuses to execute unless init()
@@ -1,4 +1,4 @@
1
- // Shim de compatibilidad: hu-snapshot vive ahora en @karajan/core.
1
+ // Shim de compatibilidad: hu-snapshot vive ahora en karajan-core.
2
2
  // Mantenemos esta ruta para que callers internos del CLI (orchestrator,
3
3
  // runners) sigan funcionando sin tocar imports.
4
4
  export {
@@ -7,4 +7,4 @@ export {
7
7
  hasHuSnapshot,
8
8
  restoreHuSnapshot,
9
9
  removeHuSnapshot,
10
- } from "@karajan/core/hu-snapshot";
10
+ } from "karajan-core/hu-snapshot";
@@ -10,6 +10,7 @@ import { buildCoderPrompt } from "../prompts/coder.js";
10
10
  import { buildReviewerPrompt } from "../prompts/reviewer.js";
11
11
  import { resolveRole } from "../config.js";
12
12
  import { emitProgress, makeEvent } from "../utils/events.js";
13
+ import { getTemplatesRoot } from "../utils/templates-root.js";
13
14
  import { BudgetTracker, extractUsageMetrics } from "../utils/budget.js";
14
15
  import { computeKjComparison } from "../budget/comparison.js";
15
16
  import { resolveRoleMdPath, loadFirstExisting } from "../roles/base-role.js";
@@ -76,7 +77,7 @@ export async function autoInit(projectDir, logger) {
76
77
  logger.info("No .karajan/ found — auto-initializing project scaffolding");
77
78
  await ensureDir(karajanDir);
78
79
 
79
- const templatesDir = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..", "..", "templates");
80
+ const templatesDir = getTemplatesRoot();
80
81
 
81
82
  const filesToCopy = [
82
83
  { src: "coder-rules.md", dest: "coder-rules.md" },
@@ -1,4 +1,4 @@
1
- // Shim: plan-hu-ops now lives in @karajan/core/plan-hu-ops so the
1
+ // Shim: plan-hu-ops now lives in karajan-core/plan-hu-ops so the
2
2
  // hu-board workspace can consume it without a relative dep on the CLI
3
3
  // src tree. KJC-TSK-0511 PR5.
4
4
  export {
@@ -13,4 +13,4 @@ export {
13
13
  computePlanOutcome,
14
14
  certifyAllHus,
15
15
  reorderHus,
16
- } from "@karajan/core/plan-hu-ops";
16
+ } from "karajan-core/plan-hu-ops";
@@ -1,4 +1,4 @@
1
- // Shim: plan-id primitives now live in @karajan/core/plan-id so the
1
+ // Shim: plan-id primitives now live in karajan-core/plan-id so the
2
2
  // hu-board workspace can consume them without a relative dep on the
3
3
  // CLI src tree. KJC-TSK-0511 PR5.
4
- export { generatePlanId, generateHuId, normaliseAlias } from "@karajan/core/plan-id";
4
+ export { generatePlanId, generateHuId, normaliseAlias } from "karajan-core/plan-id";
@@ -1,4 +1,4 @@
1
- // Shim: plan-validation now lives in @karajan/core/plan-validation so
1
+ // Shim: plan-validation now lives in karajan-core/plan-validation so
2
2
  // the hu-board workspace can consume it without a relative dep on the
3
3
  // CLI src tree. KJC-TSK-0511 PR6.
4
- export { validateBlockedByChange } from "@karajan/core/plan-validation";
4
+ export { validateBlockedByChange } from "karajan-core/plan-validation";
@@ -26,8 +26,8 @@
26
26
 
27
27
  import fs from "node:fs/promises";
28
28
  import path from "node:path";
29
- import { fileURLToPath } from "node:url";
30
29
  import { getKarajanHome } from "../utils/paths.js";
30
+ import { getTemplatesRoot } from "../utils/templates-root.js";
31
31
  import { normalizeProvider } from "../utils/provider-env.js";
32
32
 
33
33
  /**
@@ -50,14 +50,7 @@ export function resolveRolePromptPaths(role, provider, projectDir) {
50
50
  if (projectDir) homes.push(path.join(projectDir, ".karajan", "roles"));
51
51
  homes.push(path.join(getKarajanHome(), "roles"));
52
52
 
53
- const builtInRoot = path.resolve(
54
- path.dirname(fileURLToPath(import.meta.url)),
55
- "..",
56
- "..",
57
- "templates",
58
- "roles"
59
- );
60
- homes.push(builtInRoot);
53
+ homes.push(path.join(getTemplatesRoot(), "roles"));
61
54
 
62
55
  const perProvider = [];
63
56
  const defaults = [];
@@ -1,4 +1,4 @@
1
- // Shim: vec-store primitives now live in @karajan/core/vec-store so
1
+ // Shim: vec-store primitives now live in karajan-core/vec-store so
2
2
  // the hu-board workspace can consume them without a relative dep on the
3
3
  // CLI src tree. KJC-TSK-0511 PR4.
4
4
  export {
@@ -14,4 +14,4 @@ export {
14
14
  findChunkByHash,
15
15
  countChunks,
16
16
  searchBM25,
17
- } from "@karajan/core/vec-store";
17
+ } from "karajan-core/vec-store";
@@ -1,6 +1,6 @@
1
- // Shim — the real implementation now lives in @karajan/core/atomic-write.
1
+ // Shim — the real implementation now lives in karajan-core/atomic-write.
2
2
  // Kept here so CLI callers (src/**/*.js) keep importing
3
3
  // "#utils/atomic-write.js" without churn during KJC-TSK-0511 (decouple
4
4
  // @karajan/hu-board). Will be retired once every consumer migrates to
5
- // the @karajan/core import.
6
- export { writeJsonAtomic, writeJsonAtomicSync } from "@karajan/core/atomic-write";
5
+ // the karajan-core import.
6
+ export { writeJsonAtomic, writeJsonAtomicSync } from "karajan-core/atomic-write";
@@ -97,7 +97,11 @@ const INSTALL_CANDIDATES = {
97
97
  { manager: "pip", command: "pip install semgrep" },
98
98
  ],
99
99
  "osv-scanner": [
100
- { manager: "go", command: "go install github.com/google/osv-scanner@latest" },
100
+ // The module root has no main package — the binary lives in the cmd/
101
+ // subpackage, and since v2 the module path carries the /v2 suffix.
102
+ // `go install github.com/google/osv-scanner@latest` resolves the module
103
+ // (v1.x) but fails with "does not contain package" (KJC-BUG-0105).
104
+ { manager: "go", command: "go install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest" },
101
105
  { manager: "brew", command: "brew install osv-scanner" },
102
106
  ],
103
107
  lighthouse: [
@@ -1,4 +1,4 @@
1
- // Shim: paths primitives now live in @karajan/core/paths so the
1
+ // Shim: paths primitives now live in karajan-core/paths so the
2
2
  // hu-board workspace can consume them without a relative dep on the
3
3
  // CLI src tree. KJC-TSK-0511 PR3.
4
4
  export {
@@ -10,4 +10,4 @@ export {
10
10
  getOllamaComposePath,
11
11
  getWebperfDir,
12
12
  getPromptsDir,
13
- } from "@karajan/core/paths";
13
+ } from "karajan-core/paths";
@@ -1,6 +1,6 @@
1
- // Shim — the real implementation now lives in @karajan/core/port-check.
1
+ // Shim — the real implementation now lives in karajan-core/port-check.
2
2
  // Kept here so CLI callers (src/**/*.js) keep importing
3
3
  // "../utils/port-check.js" without churn during KJC-TSK-0511 (decouple
4
4
  // @karajan/hu-board). Will be retired once every consumer migrates to
5
- // the @karajan/core import.
6
- export { isPortAvailable, findAvailablePort } from "@karajan/core/port-check";
5
+ // the karajan-core import.
6
+ export { isPortAvailable, findAvailablePort } from "karajan-core/port-check";
@@ -1,4 +1,4 @@
1
- // Shim: process runner now lives in @karajan/core/process so the
1
+ // Shim: process runner now lives in karajan-core/process so the
2
2
  // hu-board workspace can consume it without a relative dep on the CLI
3
3
  // src tree. KJC-TSK-0511 PR6.
4
- export { runCommand } from "@karajan/core/process";
4
+ export { runCommand } from "karajan-core/process";
@@ -1,4 +1,4 @@
1
- // Shim: run-registry now lives in @karajan/core/run-registry so the
1
+ // Shim: run-registry now lives in karajan-core/run-registry so the
2
2
  // hu-board workspace can consume it without a relative dep on the CLI
3
3
  // src tree. KJC-TSK-0511 PR3.
4
4
  export {
@@ -6,4 +6,4 @@ export {
6
6
  registerRun,
7
7
  unregisterRun,
8
8
  listActiveRuns,
9
- } from "@karajan/core/run-registry";
9
+ } from "karajan-core/run-registry";
@@ -1,12 +1,12 @@
1
- // Shim — the real implementation now lives in @karajan/core/shared-paths.
1
+ // Shim — the real implementation now lives in karajan-core/shared-paths.
2
2
  // Kept here so CLI callers (src/**/*.js) keep importing
3
3
  // "../utils/shared-paths.js" without churn during KJC-TSK-0511 (decouple
4
4
  // @karajan/hu-board). Will be retired once every consumer migrates to
5
- // the @karajan/core import.
5
+ // the karajan-core import.
6
6
  export {
7
7
  SHARED_DIR_NAME,
8
8
  getSharedRoot,
9
9
  getSharedPlansDir,
10
10
  getSharedHuStoriesDir,
11
11
  isSharedPath,
12
- } from "@karajan/core/shared-paths";
12
+ } from "karajan-core/shared-paths";