gm-skill 2.0.2195 → 2.0.2197

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.
@@ -1 +1 @@
1
- ef91e83c06de31e44796c9c2647666eec8dca32f718d6e56ae3ceb52b4a7bb09 plugkit-slim.wasm
1
+ 8d37533c3fe69ed6627551aeb8fbbbe092c9ffa223abe42c0610d2339aeac4d2 plugkit-slim.wasm
@@ -1 +1 @@
1
- 0.1.1040
1
+ 0.1.1041
@@ -1 +1 @@
1
- b4909d21e0d5a4f0810a8c83e338d4011013150df970a54203752295c6af0310 plugkit.wasm
1
+ d0186237f4e0d691bd5f983ff729ffd62075c1b1c46c62f8be0b2edb6865784a plugkit.wasm
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.2195",
3
+ "version": "2.0.2197",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1 +1 @@
1
- ef91e83c06de31e44796c9c2647666eec8dca32f718d6e56ae3ceb52b4a7bb09 plugkit-slim.wasm
1
+ 8d37533c3fe69ed6627551aeb8fbbbe092c9ffa223abe42c0610d2339aeac4d2 plugkit-slim.wasm
@@ -1 +1 @@
1
- 0.1.1040
1
+ 0.1.1041
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.2195",
3
+ "version": "2.0.2197",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -17,5 +17,5 @@
17
17
  "publishConfig": {
18
18
  "access": "public"
19
19
  },
20
- "plugkitVersion": "0.1.1040"
20
+ "plugkitVersion": "0.1.1041"
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.2195",
3
+ "version": "2.0.2197",
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",
@@ -5,16 +5,78 @@ import process from 'node:process';
5
5
  const root = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1')), '..');
6
6
  const bundleDir = path.join(root, 'gm-plugkit', 'instructions');
7
7
 
8
- const GATE_AND_RESIDUAL_KEYS = [
8
+ const FALLBACK_GATE_AND_RESIDUAL_KEYS = [
9
9
  'gates/long-gap-no-instruction',
10
10
  'residual/prd-open', 'residual/browser-open', 'residual/tasks-running',
11
11
  'residual/dirty-tree', 'residual/imperative',
12
12
  ];
13
13
 
14
- function validateBundleCompleteness() {
14
+ const coreSrcDir = path.join(root, 'rs-plugkit', 'crates', 'plugkit-core', 'src');
15
+ const fsmVendorPath = path.join(coreSrcDir, 'orchestrator', 'fsm_vendor.rs');
16
+ const gatesRsPath = path.join(coreSrcDir, 'gates.rs');
17
+ const residualRsPath = path.join(coreSrcDir, 'orchestrator', 'residual.rs');
18
+
19
+ function readIfPresent(p) {
20
+ return fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null;
21
+ }
22
+
23
+ function extractDefaultsTable(fsmVendorRs, tableName) {
24
+ const re = new RegExp(`const ${tableName}:\\s*&\\[\\(&str,\\s*&str\\)\\]\\s*=\\s*&\\[([\\s\\S]*?)\\];`);
25
+ const m = fsmVendorRs.match(re);
26
+ if (!m) return null;
27
+ const entries = [];
28
+ const rowRe = /\(\s*"([^"]+)"\s*,\s*([A-Za-z_][A-Za-z0-9_:]*)\s*\)/g;
29
+ let row;
30
+ while ((row = rowRe.exec(m[1])) !== null) {
31
+ entries.push({ key: row[1], constPath: row[2] });
32
+ }
33
+ return entries;
34
+ }
35
+
36
+ function extractConstText(sourceText, constName) {
37
+ const re = new RegExp(`const ${constName}:\\s*&str\\s*=\\s*"((?:[^"\\\\]|\\\\.)*)"\\s*;`);
38
+ const m = sourceText.match(re);
39
+ return m ? m[1] : null;
40
+ }
41
+
42
+ function placeholdersIn(text) {
43
+ const found = new Set();
44
+ const re = /\{([a-z_]+)\}/g;
45
+ let m;
46
+ while ((m = re.exec(text)) !== null) found.add(`{${m[1]}}`);
47
+ return found;
48
+ }
49
+
50
+ function deriveKeySpecs() {
51
+ const fsmVendorRs = readIfPresent(fsmVendorPath);
52
+ const gatesRs = readIfPresent(gatesRsPath);
53
+ const residualRs = readIfPresent(residualRsPath);
54
+ if (!fsmVendorRs || !gatesRs || !residualRs) return null;
55
+
56
+ const gateRows = extractDefaultsTable(fsmVendorRs, 'GATE_DEFAULTS');
57
+ const residualRows = extractDefaultsTable(fsmVendorRs, 'RESIDUAL_DEFAULTS');
58
+ if (!gateRows || !residualRows || gateRows.length === 0 || residualRows.length === 0) return null;
59
+
60
+ const specs = [];
61
+ for (const { key, constPath } of gateRows) {
62
+ const constName = constPath.split('::').pop();
63
+ const text = extractConstText(gatesRs, constName) ?? extractConstText(residualRs, constName);
64
+ if (text === null) return null;
65
+ specs.push({ key: `gates/${key}`, constName, placeholders: placeholdersIn(text) });
66
+ }
67
+ for (const { key, constPath } of residualRows) {
68
+ const constName = constPath.split('::').pop();
69
+ const text = extractConstText(residualRs, constName) ?? extractConstText(gatesRs, constName);
70
+ if (text === null) return null;
71
+ specs.push({ key: `residual/${key}`, constName, placeholders: placeholdersIn(text) });
72
+ }
73
+ return specs;
74
+ }
75
+
76
+ function validateBundleCompleteness(keys) {
15
77
  const missing = [];
16
78
  const empty = [];
17
- for (const key of GATE_AND_RESIDUAL_KEYS) {
79
+ for (const key of keys) {
18
80
  const fp = path.join(bundleDir, `${key}.md`);
19
81
  if (!fs.existsSync(fp)) { missing.push(key); continue; }
20
82
  if (fs.readFileSync(fp, 'utf8').trim() === '') empty.push(key);
@@ -24,10 +86,37 @@ function validateBundleCompleteness() {
24
86
  if (empty.length) console.error(`prose bundle empty entries: ${empty.join(', ')}`);
25
87
  return false;
26
88
  }
27
- console.log(`prose bundle complete: ${GATE_AND_RESIDUAL_KEYS.length} keys present and non-empty`);
89
+ console.log(`prose bundle complete: ${keys.length} keys present and non-empty`);
28
90
  return true;
29
91
  }
30
92
 
93
+ function validatePlaceholderParity(specs) {
94
+ const findings = [];
95
+ for (const { key, constName, placeholders } of specs) {
96
+ const fp = path.join(bundleDir, `${key}.md`);
97
+ if (!fs.existsSync(fp)) continue;
98
+ const mdPlaceholders = placeholdersIn(fs.readFileSync(fp, 'utf8'));
99
+ for (const tok of placeholders) {
100
+ if (!mdPlaceholders.has(tok)) {
101
+ findings.push(`${key}.md is missing placeholder ${tok} carried by the canonical Rust const ${constName}; the substituted value would be silently dropped at render time`);
102
+ }
103
+ }
104
+ for (const tok of mdPlaceholders) {
105
+ if (!placeholders.has(tok)) {
106
+ findings.push(`${key}.md carries placeholder ${tok} that the canonical Rust const ${constName} never substitutes; it would render literally`);
107
+ }
108
+ }
109
+ }
110
+ if (findings.length) {
111
+ console.error('prose-placeholder-parity FAILED -- .md overrides drifted from the substituting Rust consts:');
112
+ for (const f of findings) console.error(` - ${f}`);
113
+ return true;
114
+ }
115
+ const withTokens = specs.filter((s) => s.placeholders.size > 0).length;
116
+ console.log(`prose-placeholder-parity: ${specs.length} keys checked, ${withTokens} carrying placeholders, all matching their Rust consts`);
117
+ return false;
118
+ }
119
+
31
120
  function resolveConformancePaths() {
32
121
  const proseSourceDir = path.join(root, 'rs-plugkit', 'crates', 'plugkit-core', 'src', 'orchestrator', 'instructions', 'prose');
33
122
  return {
@@ -135,9 +224,23 @@ function runConformanceCheck() {
135
224
  return false;
136
225
  }
137
226
 
138
- const bundleFailed = !validateBundleCompleteness();
227
+ const derivedSpecs = deriveKeySpecs();
228
+ const keys = derivedSpecs ? derivedSpecs.map((s) => s.key) : FALLBACK_GATE_AND_RESIDUAL_KEYS;
229
+
230
+ if (derivedSpecs) {
231
+ const missingFromDerived = FALLBACK_GATE_AND_RESIDUAL_KEYS.filter((k) => !keys.includes(k));
232
+ console.log(`prose bundle keys derived from fsm_vendor GATE_DEFAULTS + RESIDUAL_DEFAULTS: ${keys.length}`);
233
+ if (missingFromDerived.length) {
234
+ console.log(`note: previously-hardcoded keys no longer in the Rust tables: ${missingFromDerived.join(', ')}`);
235
+ }
236
+ } else {
237
+ console.log('prose bundle keys: falling back to the hardcoded list -- rs-plugkit sources unavailable (submodule not populated, or a partial/shallow checkout)');
238
+ }
239
+
240
+ const bundleFailed = !validateBundleCompleteness(keys);
241
+ const placeholderFailed = derivedSpecs ? validatePlaceholderParity(derivedSpecs) : false;
139
242
  const conformanceFailed = runConformanceCheck();
140
243
 
141
- if (bundleFailed || conformanceFailed) {
244
+ if (bundleFailed || placeholderFailed || conformanceFailed) {
142
245
  process.exit(1);
143
246
  }