gm-skill 2.0.1189 → 2.0.1191

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/README.md CHANGED
@@ -35,7 +35,7 @@ An earlier generation fanned out fifteen per-platform downstream repos (gm-cc, g
35
35
 
36
36
  ## Version
37
37
 
38
- `2.0.1189` — auto-bumped from the canonical `gm` repo. Every push to `AnEntrypoint/gm` (or any cascading sibling crate) republishes this package.
38
+ `2.0.1191` — auto-bumped from the canonical `gm` repo. Every push to `AnEntrypoint/gm` (or any cascading sibling crate) republishes this package.
39
39
 
40
40
  ## Source of truth
41
41
 
@@ -27,6 +27,23 @@ const ORCHESTRATOR_VERBS = new Set(['instruction', 'transition', 'phase-status',
27
27
  const TURN_IDLE_MS = 30_000;
28
28
  const _turns = new Map();
29
29
 
30
+ function applyDisciplineSigil(rawBody) {
31
+ let parsed;
32
+ try { parsed = JSON.parse(rawBody); } catch (_) { return rawBody; }
33
+ if (!parsed || typeof parsed !== 'object') return rawBody;
34
+ const SIGIL = /^@([A-Za-z0-9][A-Za-z0-9_-]{0,63})\s+/;
35
+ for (const key of ['query', 'text']) {
36
+ const v = parsed[key];
37
+ if (typeof v !== 'string') continue;
38
+ const m = v.match(SIGIL);
39
+ if (!m) continue;
40
+ if (!parsed.namespace) parsed.namespace = m[1];
41
+ parsed[key] = v.slice(m[0].length);
42
+ break;
43
+ }
44
+ return JSON.stringify(parsed);
45
+ }
46
+
30
47
  function turnTick(sess, verb, taskBase, phase) {
31
48
  const key = sess || '(no-session)';
32
49
  const now = Date.now();
@@ -459,12 +476,38 @@ function writeWasmJson(instance, value) {
459
476
  return writeWasmStr(instance, JSON.stringify(value));
460
477
  }
461
478
 
479
+ function safeName(s) { return String(s).replace(/[^A-Za-z0-9._-]/g, '_'); }
480
+
481
+ function projectKvDir(ns) {
482
+ const projectRoot = process.env.CLAUDE_PROJECT_DIR || process.cwd();
483
+ return path.join(projectRoot, '.gm', 'disciplines', safeName(ns));
484
+ }
485
+
486
+ function legacyKvDir(ns) {
487
+ return path.join(KV_DIR, safeName(ns));
488
+ }
489
+
462
490
  function kvFilePath(ns, key) {
463
- const safeNs = String(ns).replace(/[^A-Za-z0-9._-]/g, '_');
464
- const safeKey = String(key).replace(/[^A-Za-z0-9._-]/g, '_');
465
- const dir = path.join(KV_DIR, safeNs);
491
+ const dir = projectKvDir(ns);
466
492
  fs.mkdirSync(dir, { recursive: true });
467
- return path.join(dir, safeKey + '.json');
493
+ return path.join(dir, safeName(key) + '.json');
494
+ }
495
+
496
+ function kvReadResolve(ns, key) {
497
+ const fp = kvFilePath(ns, key);
498
+ if (fs.existsSync(fp)) return fp;
499
+ const legacy = path.join(legacyKvDir(ns), safeName(key) + '.json');
500
+ if (fs.existsSync(legacy)) return legacy;
501
+ return null;
502
+ }
503
+
504
+ function kvNamespaceDirs(ns) {
505
+ const out = [];
506
+ const proj = projectKvDir(ns);
507
+ if (fs.existsSync(proj)) out.push(proj);
508
+ const legacy = legacyKvDir(ns);
509
+ if (fs.existsSync(legacy)) out.push(legacy);
510
+ return out;
468
511
  }
469
512
 
470
513
  const __tasks = new Map();
@@ -734,8 +777,8 @@ function makeHostFunctions(instanceRef) {
734
777
  const ns = readWasmStr(instanceRef.value, nsPtr, nsLen);
735
778
  const key = readWasmStr(instanceRef.value, keyPtr, keyLen);
736
779
  if (!ns || !key) return 0n;
737
- const fp = kvFilePath(ns, key);
738
- if (!fs.existsSync(fp)) return 0n;
780
+ const fp = kvReadResolve(ns, key);
781
+ if (!fp) return 0n;
739
782
  const data = fs.readFileSync(fp, 'utf-8');
740
783
  return writeWasmStr(instanceRef.value, data);
741
784
  } catch (e) {
@@ -761,15 +804,21 @@ function makeHostFunctions(instanceRef) {
761
804
  const ns = readWasmStr(instanceRef.value, nsPtr, nsLen);
762
805
  const q = readWasmStr(instanceRef.value, qPtr, qLen);
763
806
  if (!ns) return 0n;
764
- const dir = path.join(KV_DIR, String(ns).replace(/[^A-Za-z0-9._-]/g, '_'));
765
- if (!fs.existsSync(dir)) return writeWasmJson(instanceRef.value, []);
807
+ const dirs = kvNamespaceDirs(ns);
808
+ if (dirs.length === 0) return writeWasmJson(instanceRef.value, []);
766
809
  const ql = q ? String(q).toLowerCase() : '';
810
+ const seen = new Set();
767
811
  const results = [];
768
- for (const f of fs.readdirSync(dir)) {
769
- if (!f.endsWith('.json')) continue;
770
- const value = fs.readFileSync(path.join(dir, f), 'utf-8');
771
- if (ql && !value.toLowerCase().includes(ql) && !f.toLowerCase().includes(ql)) continue;
772
- results.push({ key: f.replace(/\.json$/, ''), value });
812
+ for (const dir of dirs) {
813
+ for (const f of fs.readdirSync(dir)) {
814
+ if (!f.endsWith('.json')) continue;
815
+ const key = f.replace(/\.json$/, '');
816
+ if (seen.has(key)) continue;
817
+ seen.add(key);
818
+ const value = fs.readFileSync(path.join(dir, f), 'utf-8');
819
+ if (ql && !value.toLowerCase().includes(ql) && !f.toLowerCase().includes(ql)) continue;
820
+ results.push({ key, value });
821
+ }
773
822
  }
774
823
  return writeWasmJson(instanceRef.value, results);
775
824
  } catch (e) {
@@ -797,26 +846,34 @@ function makeHostFunctions(instanceRef) {
797
846
  if (process.env.PLUGKIT_DEBUG) console.error('[plugkit-wasm] host_vec_search: no embedding in query, raw=', raw.slice(0, 200));
798
847
  return writeWasmJson(instanceRef.value, []);
799
848
  }
800
- const vecDir = path.join(KV_DIR, `${namespace}-vec`.replace(/[^A-Za-z0-9._-]/g, '_'));
801
- const dataDir = path.join(KV_DIR, namespace.replace(/[^A-Za-z0-9._-]/g, '_'));
802
- if (!fs.existsSync(vecDir) || !fs.existsSync(dataDir)) {
849
+ const vecDirs = kvNamespaceDirs(`${namespace}-vec`);
850
+ const dataDirs = kvNamespaceDirs(namespace);
851
+ if (vecDirs.length === 0 || dataDirs.length === 0) {
803
852
  return writeWasmJson(instanceRef.value, []);
804
853
  }
805
854
  const scored = [];
806
- for (const f of fs.readdirSync(vecDir)) {
807
- if (!f.endsWith('.json')) continue;
808
- let emb;
809
- try { emb = JSON.parse(fs.readFileSync(path.join(vecDir, f), 'utf-8')); }
810
- catch (_) { continue; }
811
- const vector = Array.isArray(emb?.data?.[0]?.embedding) ? emb.data[0].embedding
812
- : Array.isArray(emb?.embedding) ? emb.embedding
813
- : Array.isArray(emb) ? emb : null;
814
- if (!vector) continue;
815
- const score = cosineSim(queryEmbedding, vector);
816
- const key = f.replace(/\.json$/, '');
817
- const valuePath = path.join(dataDir, `${key}.json`);
818
- const text = fs.existsSync(valuePath) ? fs.readFileSync(valuePath, 'utf-8') : '';
819
- scored.push({ key, text, score });
855
+ const seen = new Set();
856
+ for (const vecDir of vecDirs) {
857
+ for (const f of fs.readdirSync(vecDir)) {
858
+ if (!f.endsWith('.json')) continue;
859
+ const key = f.replace(/\.json$/, '');
860
+ if (seen.has(key)) continue;
861
+ seen.add(key);
862
+ let emb;
863
+ try { emb = JSON.parse(fs.readFileSync(path.join(vecDir, f), 'utf-8')); }
864
+ catch (_) { continue; }
865
+ const vector = Array.isArray(emb?.data?.[0]?.embedding) ? emb.data[0].embedding
866
+ : Array.isArray(emb?.embedding) ? emb.embedding
867
+ : Array.isArray(emb) ? emb : null;
868
+ if (!vector) continue;
869
+ const score = cosineSim(queryEmbedding, vector);
870
+ let text = '';
871
+ for (const dataDir of dataDirs) {
872
+ const valuePath = path.join(dataDir, `${key}.json`);
873
+ if (fs.existsSync(valuePath)) { text = fs.readFileSync(valuePath, 'utf-8'); break; }
874
+ }
875
+ scored.push({ key, text, score });
876
+ }
820
877
  }
821
878
  scored.sort((a, b) => b.score - a.score);
822
879
  return writeWasmJson(instanceRef.value, scored.slice(0, k_));
@@ -1344,9 +1401,13 @@ async function runSpoolWatcher(instance, spoolDir) {
1344
1401
  const relPath = path.relative(inDir, filePath);
1345
1402
  const dir = path.dirname(relPath);
1346
1403
  const verb = dir === '.' ? path.basename(filePath, path.extname(filePath)) : dir;
1347
- const body = content.trim() || '{}';
1404
+ let body = content.trim() || '{}';
1348
1405
  const taskBase = path.basename(filePath, path.extname(filePath));
1349
1406
 
1407
+ if (verb === 'recall' || verb === 'memorize' || verb === 'codesearch' || verb === 'memorize-fire') {
1408
+ body = applyDisciplineSigil(body);
1409
+ }
1410
+
1350
1411
  const verbBytes = new TextEncoder().encode(verb);
1351
1412
  const bodyBytes = new TextEncoder().encode(body);
1352
1413
 
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1189",
3
+ "version": "2.0.1191",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1189",
3
+ "version": "2.0.1191",
4
4
  "description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "gm.json"
40
40
  ],
41
41
  "dependencies": {
42
- "gm-plugkit": "^2.0.1189"
42
+ "gm-plugkit": "^2.0.1191"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=16.0.0"