karajan-code 3.12.0 → 3.12.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.
Files changed (59) hide show
  1. package/package.json +2 -5
  2. package/packages/hu-board/package.json +1 -1
  3. package/packages/hu-board/src/plan-mutations.js +4 -4
  4. package/packages/hu-board/src/routes/api.js +1 -1
  5. package/packages/hu-board/src/routes/rag.js +1 -1
  6. package/packages/hu-board/src/routes/wiki.js +1 -1
  7. package/packages/hu-board/src/run-tracker.js +1 -1
  8. package/packages/hu-board/src/server.js +2 -2
  9. package/packages/hu-board/src/sync.js +1 -1
  10. package/scripts/verify-pack.mjs +38 -6
  11. package/src/brain/standby-scheduler.js +2 -2
  12. package/src/brain/standby-store.js +2 -2
  13. package/src/cli/register-meta.js +5 -20
  14. package/src/git/hu-snapshot.js +2 -2
  15. package/src/plan/plan-hu-ops.js +2 -2
  16. package/src/plan/plan-id.js +2 -2
  17. package/src/plan/plan-validation.js +2 -2
  18. package/src/rag/vec-store.js +2 -2
  19. package/src/utils/atomic-write.js +3 -3
  20. package/src/utils/paths.js +2 -2
  21. package/src/utils/port-check.js +3 -3
  22. package/src/utils/process.js +2 -2
  23. package/src/utils/run-registry.js +2 -2
  24. package/src/utils/shared-paths.js +3 -3
  25. package/src/utils/update-check.js +47 -0
  26. package/node_modules/@karajan/core/README.md +0 -42
  27. package/node_modules/@karajan/core/package.json +0 -49
  28. package/node_modules/@karajan/core/src/atomic-write.js +0 -43
  29. package/node_modules/@karajan/core/src/cost/index.js +0 -102
  30. package/node_modules/@karajan/core/src/hu-snapshot.js +0 -105
  31. package/node_modules/@karajan/core/src/index.js +0 -18
  32. package/node_modules/@karajan/core/src/paths.js +0 -123
  33. package/node_modules/@karajan/core/src/plan-hu-ops.js +0 -338
  34. package/node_modules/@karajan/core/src/plan-id.js +0 -45
  35. package/node_modules/@karajan/core/src/plan-validation.js +0 -82
  36. package/node_modules/@karajan/core/src/port-check.js +0 -45
  37. package/node_modules/@karajan/core/src/pricing/index.js +0 -64
  38. package/node_modules/@karajan/core/src/pricing/model-pricing.json +0 -28
  39. package/node_modules/@karajan/core/src/process.js +0 -188
  40. package/node_modules/@karajan/core/src/run-registry.js +0 -115
  41. package/node_modules/@karajan/core/src/shared-paths.js +0 -41
  42. package/node_modules/@karajan/core/src/standby-scheduler.js +0 -92
  43. package/node_modules/@karajan/core/src/standby-store.js +0 -168
  44. package/node_modules/@karajan/core/src/vec-store.js +0 -253
  45. package/node_modules/@karajan/core/tests/atomic-write.test.js +0 -30
  46. package/node_modules/@karajan/core/tests/cost/index.test.js +0 -89
  47. package/node_modules/@karajan/core/tests/hu-snapshot.test.js +0 -39
  48. package/node_modules/@karajan/core/tests/paths.test.js +0 -51
  49. package/node_modules/@karajan/core/tests/plan-hu-ops.test.js +0 -68
  50. package/node_modules/@karajan/core/tests/plan-id.test.js +0 -21
  51. package/node_modules/@karajan/core/tests/plan-validation.test.js +0 -39
  52. package/node_modules/@karajan/core/tests/port-check.test.js +0 -47
  53. package/node_modules/@karajan/core/tests/pricing/index.test.js +0 -95
  54. package/node_modules/@karajan/core/tests/process.test.js +0 -22
  55. package/node_modules/@karajan/core/tests/run-registry.test.js +0 -71
  56. package/node_modules/@karajan/core/tests/shared-paths.test.js +0 -30
  57. package/node_modules/@karajan/core/tests/standby.test.js +0 -66
  58. package/node_modules/@karajan/core/tests/vec-store.test.js +0 -98
  59. package/node_modules/@karajan/core/vitest.config.js +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "3.12.0",
3
+ "version": "3.12.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",
@@ -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
  /**
@@ -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
  }
@@ -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";
@@ -304,26 +304,11 @@ export function registerMeta(program, { pkgVersion }) {
304
304
  .command("update")
305
305
  .description("Update karajan-code to the latest version from npm")
306
306
  .action(async () => {
307
- // Audit follow-up: was execaCommand (shell parsing). Inputs are
308
- // constants today, but the project standard since #555 is execa
309
- // with arg arrays (no shell). Migrated for consistency.
310
- const { execa } = await import("execa");
311
- console.log(`Current version: ${pkgVersion}`);
312
- console.log("Checking for updates...");
313
- try {
314
- const { stdout } = await execa("npm", ["view", "karajan-code", "version"]);
315
- const latest = stdout.trim();
316
- if (latest === pkgVersion) {
317
- console.log(`Already on the latest version (${pkgVersion}).`);
318
- return;
319
- }
320
- console.log(`Updating ${pkgVersion} → ${latest}...`);
321
- await execa("npm", ["install", "-g", "karajan-code@latest"], { stdio: "inherit" });
322
- console.log(`Updated to ${latest}. Restart Claude to pick up the new MCP server.`);
323
- } catch (err) {
324
- console.error(`Update failed: ${err.message}`);
325
- process.exit(1);
326
- }
307
+ // Output-capturing self-update: npm's deprecation/allow-scripts/funding
308
+ // warnings are hidden on success and only surfaced when the install fails.
309
+ const { performSelfUpdate } = await import("../utils/update-check.js");
310
+ const result = await performSelfUpdate({ currentVersion: pkgVersion });
311
+ if (!result.ok) process.exit(1);
327
312
  });
328
313
 
329
314
  program
@@ -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";
@@ -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";
@@ -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";
@@ -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";
@@ -103,6 +103,53 @@ export async function printUpdateNotice(currentVersion) {
103
103
  }
104
104
  }
105
105
 
106
+ /**
107
+ * Run the npm-channel self-update (`kj update`). Captures npm's output instead
108
+ * of streaming it: a successful update shows only the progress + result line,
109
+ * so npm's deprecation / allow-scripts / funding noise — build plumbing, not
110
+ * actionable for whoever runs the command — never reaches the user. On failure
111
+ * the captured stdout/stderr IS surfaced, so real errors (native build,
112
+ * permissions) stay diagnosable — never a silent failure.
113
+ *
114
+ * @param {Object} opts
115
+ * @param {string} opts.currentVersion - version of the running kj
116
+ * @param {(cmd: string, args: string[]) => Promise<{stdout: string, stderr: string}>} [opts.exec] - injectable runner (defaults to execa)
117
+ * @param {Console} [opts.logger]
118
+ * @returns {Promise<{ ok: boolean, alreadyLatest?: boolean, latest?: string }>}
119
+ */
120
+ export async function performSelfUpdate({ currentVersion, exec, logger = console } = {}) {
121
+ const run = exec || (async (cmd, args) => (await import("execa")).execa(cmd, args));
122
+ logger.log(`Current version: ${currentVersion}`);
123
+ logger.log("Checking for updates...");
124
+
125
+ let latest;
126
+ try {
127
+ const { stdout } = await run("npm", ["view", PACKAGE_NAME, "version"]);
128
+ latest = stdout.trim();
129
+ } catch (err) {
130
+ logger.error(`Update failed: ${err.shortMessage || err.message}`);
131
+ return { ok: false };
132
+ }
133
+
134
+ if (latest === currentVersion) {
135
+ logger.log(`Already on the latest version (${currentVersion}).`);
136
+ return { ok: true, alreadyLatest: true, latest };
137
+ }
138
+
139
+ logger.log(`Updating ${currentVersion} → ${latest}... (this can take a few minutes)`);
140
+ try {
141
+ // No stdio:inherit — capture and drop npm's warnings on the success path.
142
+ await run("npm", ["install", "-g", `${PACKAGE_NAME}@latest`]);
143
+ logger.log(`Updated to ${latest}. Restart Claude to pick up the new MCP server.`);
144
+ return { ok: true, latest };
145
+ } catch (err) {
146
+ if (err.stdout) logger.error(err.stdout);
147
+ if (err.stderr) logger.error(err.stderr);
148
+ logger.error(`Update failed: ${err.shortMessage || err.message}`);
149
+ return { ok: false };
150
+ }
151
+ }
152
+
106
153
  /** Simple semver compare: returns >0 if a > b, <0 if a < b, 0 if equal */
107
154
  function compareVersions(a, b) {
108
155
  const pa = a.split(".").map(Number);
@@ -1,42 +0,0 @@
1
- # @karajan/core
2
-
3
- Shared modules for the Karajan Code CLI and `@karajan/hu-board`. Private
4
- workspace package — not published to npm.
5
-
6
- ## Scope
7
-
8
- `@karajan/core` is the extraction destination for code that both the CLI
9
- package (`karajan-code`) and the HU Board package (`@karajan/hu-board`)
10
- need. Today it ships the atomic JSON writer; subsequent commits of
11
- KJC-TSK-0511 will land the shared paths, port-check, run-registry,
12
- process runner, plan validation, vector store, and plan/HU ops modules
13
- here.
14
-
15
- ## Exports
16
-
17
- | Subpath | Module |
18
- | --- | --- |
19
- | `@karajan/core/atomic-write` | `writeJsonAtomic`, `writeJsonAtomicSync` |
20
- | `@karajan/core/shared-paths` | `SHARED_DIR_NAME`, `getSharedRoot`, `getSharedPlansDir`, `getSharedHuStoriesDir`, `isSharedPath` |
21
- | `@karajan/core/port-check` | `isPortAvailable`, `findAvailablePort` |
22
- | `@karajan/core/paths` | `resolveHome`, `getKarajanHome`, `getSessionRoot`, `getSonarComposePath`, `getOllamaComposePath`, `getWebperfDir`, `getRunsDir`, `getPromptsDir`, `__resetKjHomeWarningForTests` |
23
- | `@karajan/core/run-registry` | `runsDir`, `registerRun`, `unregisterRun`, `listActiveRuns` |
24
- | `@karajan/core/vec-store` | `dbPath`, `openVecStore`, `insertChunk`, `searchSimilar`, `searchBM25`, `projectSlug`, `deleteChunksBySource`, `findChunkByHash`, `getEmbeddingsByIds`, `getLastIndexedCommit`, `setLastIndexedCommit`, `countChunks` |
25
- | `@karajan/core/plan-id` | `generatePlanId`, `generateHuId`, `normaliseAlias` |
26
- | `@karajan/core/plan-hu-ops` | `addHu`, `removeHu`, `updateHu`, `updateHuStatus`, `setHuOutcome`, `setPlanOutcome`, `autoCertifyPendingHus`, `assertPlanRunnable`, `computePlanOutcome`, `certifyAllHus`, `reorderHus` |
27
- | `@karajan/core/plan-validation` | `validateBlockedByChange` |
28
- | `@karajan/core/process` | `runCommand` (execa wrapper with output streaming, silence/total timeouts, ENOENT enrichment) |
29
- | `@karajan/core/hu-snapshot` | `snapshotRefForHu`, `createHuSnapshot`, `hasHuSnapshot`, `restoreHuSnapshot`, `removeHuSnapshot` |
30
- | `@karajan/core/standby-store` | `persistStandby`, `loadStandby`, `listPendingStandby`, `markStandbyDone`, `acquireStandbyLock`, `buildStandbyState`, `standbyDir`, `standbyDoneDir` |
31
- | `@karajan/core/standby-scheduler` | `scheduleResume`, `cancelScheduled`, `reconcileAll`, `acquireStandbyLock`, `markStandbyDone`, `_resetScheduledForTests` |
32
-
33
- The root export (`@karajan/core`) re-exports everything via the barrel
34
- in `src/index.js`, but prefer the subpath form so the bundler can
35
- tree-shake unused modules.
36
-
37
- ## Status
38
-
39
- KJC-TSK-0511 PR8 — `standby-store` + `standby-scheduler` extracted.
40
- With this PR `@karajan/hu-board` no longer reaches into `../../../src`
41
- from any static **or dynamic** import. PR9 will re-add
42
- `packages/hu-board` to the root `workspaces` array.
@@ -1,49 +0,0 @@
1
- {
2
- "name": "@karajan/core",
3
- "version": "0.1.0",
4
- "description": "Shared modules for Karajan Code CLI and @karajan/hu-board (atomic-write, paths, RAG store, plan ops, process runner).",
5
- "type": "module",
6
- "private": true,
7
- "engines": {
8
- "node": ">=22.22.1"
9
- },
10
- "exports": {
11
- "./atomic-write": "./src/atomic-write.js",
12
- "./shared-paths": "./src/shared-paths.js",
13
- "./port-check": "./src/port-check.js",
14
- "./paths": "./src/paths.js",
15
- "./run-registry": "./src/run-registry.js",
16
- "./vec-store": "./src/vec-store.js",
17
- "./plan-id": "./src/plan-id.js",
18
- "./plan-hu-ops": "./src/plan-hu-ops.js",
19
- "./plan-validation": "./src/plan-validation.js",
20
- "./process": "./src/process.js",
21
- "./hu-snapshot": "./src/hu-snapshot.js",
22
- "./standby-store": "./src/standby-store.js",
23
- "./standby-scheduler": "./src/standby-scheduler.js",
24
- "./pricing": "./src/pricing/index.js",
25
- "./cost": "./src/cost/index.js"
26
- },
27
- "scripts": {
28
- "test": "vitest run"
29
- },
30
- "peerDependencies": {
31
- "better-sqlite3": "^12.10.0",
32
- "execa": "^9.6.0",
33
- "sqlite-vec": "^0.1.9"
34
- },
35
- "peerDependenciesMeta": {
36
- "better-sqlite3": {
37
- "optional": true
38
- },
39
- "execa": {
40
- "optional": true
41
- },
42
- "sqlite-vec": {
43
- "optional": true
44
- }
45
- },
46
- "devDependencies": {
47
- "vitest": "^4.0.0"
48
- }
49
- }
@@ -1,43 +0,0 @@
1
- // Atomic JSON writes for persistent state (resilience audit, Phase 2).
2
- //
3
- // A plain `writeFile(path, JSON.stringify(...))` truncates the live file
4
- // before the new content lands. If the process is killed mid-write
5
- // (SIGKILL, crash, power loss) the file is left truncated and the only
6
- // good copy is already gone — the plan / session / standby JSON
7
- // silently corrupts.
8
- //
9
- // write-temp + rename fixes it: `rename` is atomic on the same
10
- // filesystem, so a reader sees either the old file or the complete new
11
- // one, never a half-written one. The temp file sits next to the target
12
- // (same dir → same FS) and is uniquely named so concurrent writers do
13
- // not clobber each other's temp. A crash before the rename leaves an
14
- // orphan `.tmp` but never a corrupt target.
15
-
16
- import { writeFileSync, renameSync } from "node:fs";
17
- import { writeFile, rename } from "node:fs/promises";
18
-
19
- function tempPath(target) {
20
- return `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
21
- }
22
-
23
- /**
24
- * Atomically write `obj` as pretty JSON to `target` (synchronous).
25
- * @param {string} target - destination path; its directory must exist
26
- * @param {unknown} obj
27
- */
28
- export function writeJsonAtomicSync(target, obj) {
29
- const tmp = tempPath(target);
30
- writeFileSync(tmp, JSON.stringify(obj, null, 2), "utf-8");
31
- renameSync(tmp, target);
32
- }
33
-
34
- /**
35
- * Atomically write `obj` as pretty JSON to `target` (async).
36
- * @param {string} target - destination path; its directory must exist
37
- * @param {unknown} obj
38
- */
39
- export async function writeJsonAtomic(target, obj) {
40
- const tmp = tempPath(target);
41
- await writeFile(tmp, JSON.stringify(obj, null, 2), "utf-8");
42
- await rename(tmp, target);
43
- }