klypix-mcp 1.67.0 → 1.67.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": "klypix-mcp",
3
- "version": "1.67.0",
3
+ "version": "1.67.1",
4
4
  "description": "Shared project brain and MCP coordination server for multi-agent coding.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -83,7 +83,7 @@
83
83
  "bench": "node bin/klypix-mcp.mjs bench",
84
84
  "test:bench": "node test/bench.mjs",
85
85
  "pretest": "node test/publish-workflow.mjs",
86
- "test": "node test/publish-verdict.mjs && node test/remote-client.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/request-identity.mjs && node test/session-identity-core.mjs && node test/agent-presence.mjs && node test/message-delivery-v3.mjs && node test/claude-message-delivery-v3.mjs && node test/result-reconcile.mjs && node test/evidence-publication-gate.mjs && node test/release-evidence-cli.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/archived-visibility.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/install-version.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
86
+ "test": "node test/publish-verdict.mjs && node test/remote-client.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/request-identity.mjs && node test/session-identity-core.mjs && node test/agent-presence.mjs && node test/message-delivery-v3.mjs && node test/claude-message-delivery-v3.mjs && node test/result-reconcile.mjs && node test/evidence-publication-gate.mjs && node test/release-evidence-cli.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/archived-visibility.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/install-version.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-security.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
87
87
  "test:memory": "node test/memory-runtime.mjs",
88
88
  "test:memory:soak": "node --expose-gc test/memory-soak.mjs",
89
89
  "runtime": "node bin/klypix-runtime.mjs"
@@ -18,6 +18,7 @@ import fs from 'fs';
18
18
  import path from 'path';
19
19
  import os from 'os';
20
20
  import crypto from 'crypto';
21
+ import { createRequire } from 'module';
21
22
 
22
23
  const PB_DIR = path.join(os.homedir(), '.claude', 'project-brain');
23
24
  const EMB_DIR = path.join(PB_DIR, 'embeddings');
@@ -29,6 +30,46 @@ export const HOOK_EMBEDDING_MODEL_ID = 'Xenova/bge-small-en-v1.5';
29
30
  export const HOOK_EMBEDDING_QUERY_PREFIX = 'Represent this sentence for searching relevant passages: ';
30
31
  export const HOOK_EMBEDDING_POOLING = 'cls';
31
32
  export const HOOK_EMBEDDING_CACHE_KEY = `${HOOK_EMBEDDING_MODEL_ID}|q8|${HOOK_EMBEDDING_POOLING}|query-instruction-v1`;
33
+ const MIN_SAFE_SHARP_VERSION = [0, 35, 3];
34
+
35
+ function findPackageManifest(entryPath, expectedName) {
36
+ let dir = path.dirname(entryPath);
37
+ while (dir !== path.dirname(dir)) {
38
+ try {
39
+ const manifestPath = path.join(dir, 'package.json');
40
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
41
+ if (manifest?.name === expectedName) return { manifestPath, manifest };
42
+ } catch { /* keep walking */ }
43
+ dir = path.dirname(dir);
44
+ }
45
+ return null;
46
+ }
47
+
48
+ function isSafeSharpVersion(version) {
49
+ const parts = String(version || '').split('.').slice(0, 3).map(Number);
50
+ if (parts.length !== 3 || parts.some(part => !Number.isInteger(part) || part < 0)) return false;
51
+ for (let i = 0; i < MIN_SAFE_SHARP_VERSION.length; i++) {
52
+ if (parts[i] !== MIN_SAFE_SHARP_VERSION[i]) return parts[i] > MIN_SAFE_SHARP_VERSION[i];
53
+ }
54
+ return true;
55
+ }
56
+
57
+ export function semanticRuntimeEntryIfSafe(transformersEntry) {
58
+ try {
59
+ const transformers = findPackageManifest(transformersEntry, '@huggingface/transformers');
60
+ if (!transformers) return null;
61
+ const sharpEntry = createRequire(transformers.manifestPath).resolve('sharp');
62
+ const sharp = findPackageManifest(sharpEntry, 'sharp');
63
+ return sharp && isSafeSharpVersion(sharp.manifest.version) ? transformersEntry : null;
64
+ } catch { return null; }
65
+ }
66
+
67
+ function ambientTransformersEntryIfSafe() {
68
+ try {
69
+ const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
70
+ return semanticRuntimeEntryIfSafe(entry);
71
+ } catch { return null; }
72
+ }
32
73
 
33
74
  // Memoized within THIS process only (a one-shot hook run) — across prompts it
34
75
  // reloads cold, which is exactly why we only pay it on a lexical miss.
@@ -37,15 +78,20 @@ function getEmbedder() {
37
78
  if (_embedder !== undefined) return _embedder;
38
79
  _embedder = (async () => {
39
80
  let t;
40
- try { t = await import('@huggingface/transformers'); }
41
- catch {
81
+ const ambientEntry = ambientTransformersEntryIfSafe();
82
+ if (ambientEntry) {
83
+ try { t = await import('@huggingface/transformers'); } catch { /* try owned runtime */ }
84
+ }
85
+ if (!t) {
42
86
  const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
43
87
  let last;
44
88
  for (const f of ['transformers.node.mjs', 'transformers.mjs']) {
45
- try { t = await import(new URL('file:///' + path.join(base, f).replace(/\\/g, '/')).href); last = null; break; }
89
+ const entry = path.join(base, f);
90
+ if (!semanticRuntimeEntryIfSafe(entry)) continue;
91
+ try { t = await import(new URL('file:///' + entry.replace(/\\/g, '/')).href); last = null; break; }
46
92
  catch (e) { last = e; }
47
93
  }
48
- if (!t) throw last;
94
+ if (!t) throw last || new Error('semantic runtime rejected: sharp must be >=0.35.3');
49
95
  }
50
96
  t.env.cacheDir = path.join(PB_DIR, 'hf-cache');
51
97
  return await t.pipeline('feature-extraction', HOOK_EMBEDDING_MODEL_ID, { dtype: 'q8' });
@@ -13,6 +13,7 @@ import { createRequire } from 'module';
13
13
  const PB_DIR = path.join(os.homedir(), '.claude', 'project-brain');
14
14
  const EMB_DIR = path.join(PB_DIR, 'embeddings');
15
15
  const sha1 = (s) => crypto.createHash('sha1').update(String(s)).digest('hex');
16
+ const MIN_SAFE_SHARP_VERSION = [0, 35, 3];
16
17
  export const EMBEDDING_MODEL_ID = 'Xenova/bge-small-en-v1.5';
17
18
  export const EMBEDDING_QUERY_PREFIX = 'Represent this sentence for searching relevant passages: ';
18
19
  export const EMBEDDING_POOLING = 'cls';
@@ -236,16 +237,59 @@ function disposeTensorTree(value, seen = new Set()) {
236
237
  for (const item of Object.values(value)) disposeTensorTree(item, seen);
237
238
  }
238
239
 
240
+ function findPackageManifest(entryPath, expectedName) {
241
+ let dir = path.dirname(entryPath);
242
+ while (dir !== path.dirname(dir)) {
243
+ try {
244
+ const manifestPath = path.join(dir, 'package.json');
245
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
246
+ if (manifest?.name === expectedName) return { manifestPath, manifest };
247
+ } catch { /* keep walking */ }
248
+ dir = path.dirname(dir);
249
+ }
250
+ return null;
251
+ }
252
+
253
+ function isSafeSharpVersion(version) {
254
+ const parts = String(version || '').split('.').slice(0, 3).map(Number);
255
+ if (parts.length !== 3 || parts.some(part => !Number.isInteger(part) || part < 0)) return false;
256
+ for (let i = 0; i < MIN_SAFE_SHARP_VERSION.length; i++) {
257
+ if (parts[i] !== MIN_SAFE_SHARP_VERSION[i]) return parts[i] > MIN_SAFE_SHARP_VERSION[i];
258
+ }
259
+ return true;
260
+ }
261
+
262
+ export function semanticRuntimeEntryIfSafe(transformersEntry) {
263
+ try {
264
+ const transformers = findPackageManifest(transformersEntry, '@huggingface/transformers');
265
+ if (!transformers) return null;
266
+ const sharpEntry = createRequire(transformers.manifestPath).resolve('sharp');
267
+ const sharp = findPackageManifest(sharpEntry, 'sharp');
268
+ return sharp && isSafeSharpVersion(sharp.manifest.version) ? transformersEntry : null;
269
+ } catch { return null; }
270
+ }
271
+
272
+ function ambientTransformersEntryIfSafe() {
273
+ try {
274
+ const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
275
+ return semanticRuntimeEntryIfSafe(entry);
276
+ } catch { return null; }
277
+ }
278
+
239
279
  async function loadTransformers() {
240
- try { return await import('@huggingface/transformers'); }
241
- catch {
280
+ if (ambientTransformersEntryIfSafe()) {
281
+ try { return await import('@huggingface/transformers'); } catch { /* try owned runtime */ }
282
+ }
283
+ {
242
284
  const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
243
285
  let lastErr;
244
286
  for (const f of ['transformers.node.mjs', 'transformers.mjs']) {
245
- try { return await import(new URL('file:///' + path.join(base, f).replace(/\\/g, '/')).href); }
287
+ const entry = path.join(base, f);
288
+ if (!semanticRuntimeEntryIfSafe(entry)) continue;
289
+ try { return await import(new URL('file:///' + entry.replace(/\\/g, '/')).href); }
246
290
  catch (error) { lastErr = error; }
247
291
  }
248
- throw lastErr;
292
+ throw lastErr || new Error('semantic runtime rejected: sharp must be >=0.35.3');
249
293
  }
250
294
  }
251
295
 
@@ -267,13 +311,15 @@ export function semanticRuntimeInstalled() {
267
311
  if (runtimeInstalledCache !== null) return runtimeInstalledCache;
268
312
  let found = false;
269
313
  try {
270
- createRequire(import.meta.url).resolve('@huggingface/transformers');
271
- found = true;
314
+ const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
315
+ found = Boolean(semanticRuntimeEntryIfSafe(entry));
272
316
  } catch {
317
+ // Fall through to the owned runtime below.
318
+ }
319
+ if (!found) {
273
320
  const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
274
- found = ['transformers.node.mjs', 'transformers.mjs'].some(f => {
275
- try { return fs.existsSync(path.join(base, f)); } catch { return false; }
276
- });
321
+ found = ['transformers.node.mjs', 'transformers.mjs']
322
+ .some(f => Boolean(semanticRuntimeEntryIfSafe(path.join(base, f))));
277
323
  }
278
324
  runtimeInstalledCache = found;
279
325
  return found;