klypix-mcp 1.67.0 → 1.67.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.
- package/package.json +2 -2
- package/src/brain-semantic.mjs +53 -4
- package/src/semantic-memory.mjs +58 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "klypix-mcp",
|
|
3
|
-
"version": "1.67.
|
|
3
|
+
"version": "1.67.2",
|
|
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"
|
package/src/brain-semantic.mjs
CHANGED
|
@@ -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,49 @@ 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
|
+
// Resolve from the exact executable bundle entry. Resolving from the
|
|
62
|
+
// package manifest misses a Sharp installation shadowed under dist/
|
|
63
|
+
// even though that is the copy the ESM bundle itself will import.
|
|
64
|
+
const sharpEntry = createRequire(transformersEntry).resolve('sharp');
|
|
65
|
+
const sharp = findPackageManifest(sharpEntry, 'sharp');
|
|
66
|
+
return sharp && isSafeSharpVersion(sharp.manifest.version) ? transformersEntry : null;
|
|
67
|
+
} catch { return null; }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function ambientTransformersEntryIfSafe() {
|
|
71
|
+
try {
|
|
72
|
+
const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
|
|
73
|
+
return semanticRuntimeEntryIfSafe(entry);
|
|
74
|
+
} catch { return null; }
|
|
75
|
+
}
|
|
32
76
|
|
|
33
77
|
// Memoized within THIS process only (a one-shot hook run) — across prompts it
|
|
34
78
|
// reloads cold, which is exactly why we only pay it on a lexical miss.
|
|
@@ -37,15 +81,20 @@ function getEmbedder() {
|
|
|
37
81
|
if (_embedder !== undefined) return _embedder;
|
|
38
82
|
_embedder = (async () => {
|
|
39
83
|
let t;
|
|
40
|
-
|
|
41
|
-
|
|
84
|
+
const ambientEntry = ambientTransformersEntryIfSafe();
|
|
85
|
+
if (ambientEntry) {
|
|
86
|
+
try { t = await import('@huggingface/transformers'); } catch { /* try owned runtime */ }
|
|
87
|
+
}
|
|
88
|
+
if (!t) {
|
|
42
89
|
const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
|
|
43
90
|
let last;
|
|
44
91
|
for (const f of ['transformers.node.mjs', 'transformers.mjs']) {
|
|
45
|
-
|
|
92
|
+
const entry = path.join(base, f);
|
|
93
|
+
if (!semanticRuntimeEntryIfSafe(entry)) continue;
|
|
94
|
+
try { t = await import(new URL('file:///' + entry.replace(/\\/g, '/')).href); last = null; break; }
|
|
46
95
|
catch (e) { last = e; }
|
|
47
96
|
}
|
|
48
|
-
if (!t) throw last;
|
|
97
|
+
if (!t) throw last || new Error('semantic runtime rejected: sharp must be >=0.35.3');
|
|
49
98
|
}
|
|
50
99
|
t.env.cacheDir = path.join(PB_DIR, 'hf-cache');
|
|
51
100
|
return await t.pipeline('feature-extraction', HOOK_EMBEDDING_MODEL_ID, { dtype: 'q8' });
|
package/src/semantic-memory.mjs
CHANGED
|
@@ -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,62 @@ 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
|
+
// Resolve from the exact executable bundle entry. Resolving from the
|
|
267
|
+
// package manifest misses a Sharp installation shadowed under dist/
|
|
268
|
+
// even though that is the copy the ESM bundle itself will import.
|
|
269
|
+
const sharpEntry = createRequire(transformersEntry).resolve('sharp');
|
|
270
|
+
const sharp = findPackageManifest(sharpEntry, 'sharp');
|
|
271
|
+
return sharp && isSafeSharpVersion(sharp.manifest.version) ? transformersEntry : null;
|
|
272
|
+
} catch { return null; }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function ambientTransformersEntryIfSafe() {
|
|
276
|
+
try {
|
|
277
|
+
const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
|
|
278
|
+
return semanticRuntimeEntryIfSafe(entry);
|
|
279
|
+
} catch { return null; }
|
|
280
|
+
}
|
|
281
|
+
|
|
239
282
|
async function loadTransformers() {
|
|
240
|
-
|
|
241
|
-
|
|
283
|
+
if (ambientTransformersEntryIfSafe()) {
|
|
284
|
+
try { return await import('@huggingface/transformers'); } catch { /* try owned runtime */ }
|
|
285
|
+
}
|
|
286
|
+
{
|
|
242
287
|
const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
|
|
243
288
|
let lastErr;
|
|
244
289
|
for (const f of ['transformers.node.mjs', 'transformers.mjs']) {
|
|
245
|
-
|
|
290
|
+
const entry = path.join(base, f);
|
|
291
|
+
if (!semanticRuntimeEntryIfSafe(entry)) continue;
|
|
292
|
+
try { return await import(new URL('file:///' + entry.replace(/\\/g, '/')).href); }
|
|
246
293
|
catch (error) { lastErr = error; }
|
|
247
294
|
}
|
|
248
|
-
throw lastErr;
|
|
295
|
+
throw lastErr || new Error('semantic runtime rejected: sharp must be >=0.35.3');
|
|
249
296
|
}
|
|
250
297
|
}
|
|
251
298
|
|
|
@@ -267,13 +314,15 @@ export function semanticRuntimeInstalled() {
|
|
|
267
314
|
if (runtimeInstalledCache !== null) return runtimeInstalledCache;
|
|
268
315
|
let found = false;
|
|
269
316
|
try {
|
|
270
|
-
createRequire(import.meta.url).resolve('@huggingface/transformers');
|
|
271
|
-
found =
|
|
317
|
+
const entry = createRequire(import.meta.url).resolve('@huggingface/transformers');
|
|
318
|
+
found = Boolean(semanticRuntimeEntryIfSafe(entry));
|
|
272
319
|
} catch {
|
|
320
|
+
// Fall through to the owned runtime below.
|
|
321
|
+
}
|
|
322
|
+
if (!found) {
|
|
273
323
|
const base = path.join(PB_DIR, 'semantic', 'node_modules', '@huggingface', 'transformers', 'dist');
|
|
274
|
-
found = ['transformers.node.mjs', 'transformers.mjs']
|
|
275
|
-
|
|
276
|
-
});
|
|
324
|
+
found = ['transformers.node.mjs', 'transformers.mjs']
|
|
325
|
+
.some(f => Boolean(semanticRuntimeEntryIfSafe(path.join(base, f))));
|
|
277
326
|
}
|
|
278
327
|
runtimeInstalledCache = found;
|
|
279
328
|
return found;
|