gm-copilot-cli 2.0.1073 → 2.0.1075

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,6 +1,6 @@
1
1
  ---
2
2
  name: gm
3
- version: 2.0.1073
3
+ version: 2.0.1075
4
4
  description: Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement
5
5
  author: AnEntrypoint
6
6
  repository: https://github.com/AnEntrypoint/gm-copilot-cli
package/index.html CHANGED
@@ -74,7 +74,7 @@ body { display: flex; flex-direction: column; min-height: 100vh; }
74
74
  <section>
75
75
  <div class="gm-section-label"><span class="slash">//</span>status</div>
76
76
  <div class="panel">
77
- <div class="panel-head"><span>release · v2.0.1073</span><span>probably emerging</span></div>
77
+ <div class="panel-head"><span>release · v2.0.1075</span><span>probably emerging</span></div>
78
78
  <div class="panel-body">
79
79
  <div class="row">
80
80
  <span class="code"><span style="color:var(--panel-accent)">●</span></span>
@@ -8,32 +8,17 @@ const spool = require('./spool.js');
8
8
 
9
9
  const PLUGKIT_TOOLS_DIR = path.join(os.homedir(), '.claude', 'gm-tools');
10
10
  const PLUGKIT_VERSION_FILE = path.join(PLUGKIT_TOOLS_DIR, 'plugkit.version');
11
+ const PLUGKIT_WASM_PATH = path.join(PLUGKIT_TOOLS_DIR, 'plugkit.wasm');
12
+ const PLUGKIT_WASM_WRAPPER = path.join(PLUGKIT_TOOLS_DIR, 'plugkit-wasm-wrapper.js');
11
13
  const BOOTSTRAP_STATUS_FILE = path.join(os.homedir(), '.gm', 'bootstrap-status.json');
12
14
  const BOOTSTRAP_ERROR_FILE = path.join(os.homedir(), '.gm', 'bootstrap-error.json');
13
15
  const LOG_DIR = path.join(os.homedir(), '.claude', 'gm-log');
14
- const PLATFORM_MAP = {
15
- win32: { suffix: '-win32-x64.exe', altSuffix: '-win32-arm64.exe' },
16
- darwin: { suffix: '-darwin-x64', altSuffix: '-darwin-arm64' },
17
- linux: { suffix: '-linux-x64', altSuffix: '-linux-arm64' },
18
- };
19
-
20
- function getPlatformKey() {
21
- const plat = process.platform;
22
- if (plat === 'win32') return plat;
23
- if (plat === 'darwin') return plat;
24
- if (plat === 'linux') return plat;
25
- throw new Error(`Unsupported platform: ${plat}`);
26
- }
27
-
28
- function getExpectedBinaryName() {
29
- const plat = getPlatformKey();
30
- const suffix = PLATFORM_MAP[plat].suffix;
31
- return `plugkit${suffix}`;
32
- }
33
16
 
34
17
  function getPlugkitPath() {
35
- const name = getExpectedBinaryName();
36
- return path.join(PLUGKIT_TOOLS_DIR, name);
18
+ if (fs.existsSync(PLUGKIT_WASM_WRAPPER) && fs.existsSync(PLUGKIT_WASM_PATH)) {
19
+ return PLUGKIT_WASM_WRAPPER;
20
+ }
21
+ throw new Error(`plugkit WASM not found at ${PLUGKIT_WASM_PATH}`);
37
22
  }
38
23
 
39
24
  function emitBootstrapEvent(severity, message, details) {
@@ -65,17 +50,12 @@ function readManifest() {
65
50
  const gm = JSON.parse(fs.readFileSync(gmJsonPath, 'utf8'));
66
51
  const version = gm.plugkitVersion;
67
52
 
68
- const sha256Path = path.join(process.cwd(), 'gm-starter', 'bin', 'plugkit.sha256');
53
+ const sha256Path = path.join(process.cwd(), 'gm-starter', 'bin', 'plugkit.wasm.sha256');
69
54
  if (!fs.existsSync(sha256Path)) {
70
- throw new Error('gm-starter/bin/plugkit.sha256 not found');
55
+ throw new Error('gm-starter/bin/plugkit.wasm.sha256 not found');
71
56
  }
72
- const sha256Lines = fs.readFileSync(sha256Path, 'utf8').split('\n').filter(Boolean);
73
- const binaryName = getExpectedBinaryName();
74
- const hashLine = sha256Lines.find(line => line.includes(binaryName));
75
- if (!hashLine) {
76
- throw new Error(`No hash found for ${binaryName}`);
77
- }
78
- const expectedHash = hashLine.split(/\s+/)[0];
57
+ const sha256Content = fs.readFileSync(sha256Path, 'utf8').trim();
58
+ const expectedHash = sha256Content.split(/\s+/)[0];
79
59
 
80
60
  return { version, expectedHash };
81
61
  } catch (e) {
@@ -101,20 +81,20 @@ function computeFileHash(filePath) {
101
81
  }
102
82
 
103
83
  async function downloadPlugkitBinary(version) {
104
- const binaryName = getExpectedBinaryName();
105
- const url = `https://github.com/AnEntrypoint/plugkit-bin/releases/download/${version}/${binaryName}`;
84
+ const binaryName = 'plugkit.wasm';
85
+ const url = `https://github.com/AnEntrypoint/plugkit-bin/releases/download/v${version}/${binaryName}`;
106
86
 
107
- emitBootstrapEvent('info', 'Starting binary download', { version, binaryName, url });
87
+ emitBootstrapEvent('info', 'Starting WASM download', { version, url });
108
88
 
109
89
  return new Promise((resolve, reject) => {
110
90
  https
111
91
  .get(url, { timeout: 30000 }, (res) => {
112
92
  if (res.statusCode === 404) {
113
- reject(new Error(`Binary not found: ${binaryName} v${version}`));
93
+ reject(new Error(`WASM not found: v${version}`));
114
94
  return;
115
95
  }
116
96
  if (res.statusCode !== 200) {
117
- reject(new Error(`HTTP ${res.statusCode} downloading ${binaryName}`));
97
+ reject(new Error(`HTTP ${res.statusCode} downloading plugkit.wasm`));
118
98
  return;
119
99
  }
120
100
 
@@ -122,7 +102,7 @@ async function downloadPlugkitBinary(version) {
122
102
  res.on('data', (chunk) => chunks.push(chunk));
123
103
  res.on('end', () => {
124
104
  const data = Buffer.concat(chunks);
125
- emitBootstrapEvent('info', 'Binary download complete', { bytes: data.length });
105
+ emitBootstrapEvent('info', 'WASM download complete', { bytes: data.length });
126
106
  resolve(data);
127
107
  });
128
108
  })
@@ -204,12 +184,14 @@ async function writeBinaryWithRetry(filePath, data, maxRetries = 3) {
204
184
 
205
185
  async function verifyBinaryHealth(filePath) {
206
186
  try {
207
- if (process.platform === 'win32') {
208
- execSync(`"${filePath}" health > nul 2>&1`, { timeout: 5000, shell: true });
209
- } else {
210
- execSync(`"${filePath}" health > /dev/null 2>&1`, { timeout: 5000 });
187
+ if (!fs.existsSync(filePath)) {
188
+ throw new Error(`File not found: ${filePath}`);
211
189
  }
212
- emitBootstrapEvent('info', 'Binary health check passed');
190
+ const stat = fs.statSync(filePath);
191
+ if (stat.size < 1024) {
192
+ throw new Error(`File too small: ${stat.size} bytes`);
193
+ }
194
+ emitBootstrapEvent('info', 'Binary health check passed', { size: stat.size });
213
195
  return true;
214
196
  } catch (e) {
215
197
  emitBootstrapEvent('warn', 'Binary health check failed', { error: e.message });
@@ -217,24 +199,38 @@ async function verifyBinaryHealth(filePath) {
217
199
  }
218
200
  }
219
201
 
220
- async function spawnPlugkitWatcher(filePath) {
202
+ async function spawnPlugkitWatcher(wasmPath) {
221
203
  try {
222
- emitBootstrapEvent('info', 'Spawning plugkit watcher daemon');
204
+ emitBootstrapEvent('info', 'Spawning plugkit WASM watcher daemon');
205
+
206
+ let wrapperPath;
207
+ try {
208
+ const gmPlugkit = require('gm-plugkit');
209
+ wrapperPath = path.join(path.dirname(gmPlugkit.getPath ? gmPlugkit.getPath() : require.resolve('gm-plugkit')), 'plugkit-wasm-wrapper.js');
210
+ } catch (e) {
211
+ emitBootstrapEvent('warn', 'gm-plugkit npm not available, using bundled wrapper', { error: e.message });
212
+ wrapperPath = path.join(path.dirname(wasmPath), 'plugkit-wasm-wrapper.js');
213
+ }
214
+
215
+ if (!fs.existsSync(wrapperPath)) {
216
+ throw new Error(`WASM wrapper not found at ${wrapperPath}`);
217
+ }
223
218
 
224
- const cmd = process.platform === 'win32' ? filePath : filePath;
225
- const proc = spawn(cmd, ['watch', '--once=false'], {
219
+ const runtime = process.platform === 'win32' ? 'bun.exe' : 'bun';
220
+ const proc = spawn(runtime, [wrapperPath, 'spool'], {
226
221
  detached: true,
227
222
  stdio: 'ignore',
228
223
  windowsHide: true,
224
+ env: { ...process.env, CLAUDE_PROJECT_DIR: process.cwd() },
229
225
  });
230
226
 
231
227
  const pid = proc.pid;
232
228
  proc.unref();
233
229
 
234
- emitBootstrapEvent('info', 'Plugkit watcher spawned', { pid });
230
+ emitBootstrapEvent('info', 'Plugkit WASM watcher spawned', { pid });
235
231
  return pid;
236
232
  } catch (e) {
237
- emitBootstrapEvent('error', 'Failed to spawn plugkit watcher', { error: e.message });
233
+ emitBootstrapEvent('error', 'Failed to spawn plugkit WASM watcher', { error: e.message });
238
234
  throw e;
239
235
  }
240
236
  }
@@ -72,4 +72,29 @@ async function pollForCompletion(jsonFile, timeoutMs, taskId) {
72
72
  };
73
73
  }
74
74
 
75
- module.exports = { dispatchSpool };
75
+ function checkDispatchGates(sessionId, operation) {
76
+ const gm = path.join(process.cwd(), '.gm');
77
+ const prdPath = path.join(gm, 'prd.yml');
78
+ const mutsPath = path.join(gm, 'mutables.yml');
79
+ const needsGmPath = path.join(gm, 'needs-gm');
80
+ const gmFiredPath = path.join(gm, `gm-fired-${sessionId}`);
81
+
82
+ if (!['write', 'edit', 'git'].includes(operation)) return { allowed: true };
83
+
84
+ if (fs.existsSync(prdPath) && fs.existsSync(needsGmPath) && !fs.existsSync(gmFiredPath)) {
85
+ return { allowed: false, reason: 'gm orchestration in progress; skills must complete work before tools execute' };
86
+ }
87
+
88
+ if (fs.existsSync(mutsPath)) {
89
+ try {
90
+ const content = fs.readFileSync(mutsPath, 'utf8');
91
+ if (content.includes('status: unknown')) {
92
+ return { allowed: false, reason: 'unresolved mutables block tool execution; resolve all mutables before proceeding' };
93
+ }
94
+ } catch (_) {}
95
+ }
96
+
97
+ return { allowed: true };
98
+ }
99
+
100
+ module.exports = { dispatchSpool, checkDispatchGates };
package/manifest.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: gm
2
- version: 2.0.1073
2
+ version: 2.0.1075
3
3
  description: Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement
4
4
  author: AnEntrypoint
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-copilot-cli",
3
- "version": "2.0.1073",
3
+ "version": "2.0.1075",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -58,3 +58,15 @@ Platform adapters (vscode, cursor, zed, jetbrains) that support `end-to-end: tru
58
58
  4. Repeat until `nextSkill` is null
59
59
 
60
60
  This collapses 5 manual skill invocations into 1 user invocation + 4 transparent auto-dispatches, achieving perceived single-flow parity with gm-cc's subagent orchestration.
61
+
62
+ ## Skill Transition Protocol
63
+
64
+ Skill-to-skill transitions NEVER stop for approval or ask the user. Each skill completes its phase and invokes the next skill via `Skill()` tool call directly. Platform adapters auto-detect the transition from stdout JSON and fire the next skill without user interaction. Tool-use approvals are pre-authorized by the initial user request — re-asking defeats the cascade and breaks autonomy. Skills must assume subsequent tools are approved once the PRD is written by PLAN.
65
+
66
+ ## Gate enforcement (spool-dispatch layer)
67
+
68
+ The file-spool (`lib/spool-dispatch.js::checkDispatchGates()`) blocks Write/Edit/git operations when:
69
+ 1. `.gm/prd.yml` exists AND `.gm/needs-gm` exists AND `.gm/gm-fired-<sessionId>` does NOT exist → reason: "gm orchestration in progress; skills must complete work before tools execute"
70
+ 2. `.gm/mutables.yml` has entries with `status: unknown` → reason: "unresolved mutables block tool execution; resolve all mutables before proceeding"
71
+
72
+ Gate 1 auto-clears: PLAN writes THREE markers (`.gm/prd.yml`, `.gm/needs-gm`, `.gm/gm-fired-<sessionId>`) at session start BEFORE transitioning to EXECUTE. The marker proves planning has run and authorized tool use. Gate 2 auto-clears: EXECUTE resolves mutables by updating `.gm/mutables.yml` entries to `status: witnessed`, or the file is deleted when empty by gm-complete. Tool denials surface the reason text to the agent, which adjusts behavior (e.g., resolve remaining mutables before retrying). Tool denials never mutate command arguments — they surface policy as imperative instruction.
@@ -104,3 +104,18 @@ After `git push`, poll `gh run list --branch main --limit 5 --json status,name,d
104
104
  ## Completion
105
105
 
106
106
  All true at once: witnessed e2e | browser_validated when client work touched | failure paths exercised | test.js passes | `.prd` deleted | git clean and pushed | CI green | hygiene sweep clean | TODO.md gone | CHANGELOG.md updated.
107
+
108
+ ## Marker file protocol
109
+
110
+ On transition to `update-docs`, delete all gm orchestration markers for the next cycle:
111
+ ```
112
+ const fs = require('fs');
113
+ const path = require('path');
114
+ const sessionId = process.env.SESSION_ID || 'default';
115
+ const gm = path.join(process.cwd(), '.gm');
116
+ ['.gm/prd.yml', '.gm/mutables.yml', '.gm/needs-gm', `.gm/gm-fired-${sessionId}`].forEach(m => {
117
+ try { fs.unlinkSync(path.join(gm, m.split('/')[1])); } catch (_) {}
118
+ });
119
+ ```
120
+
121
+ The `.gm/gm-fired-<sessionId>` marker was written by PLAN at session start and proves gm orchestration has completed. Cleanup before next cycle resets gates so the next PLAN run can write fresh markers.
@@ -5,16 +5,18 @@ description: EMIT phase. Pre-emit debug, write files, post-emit verify from disk
5
5
 
6
6
  # GM EMIT — Write and verify from disk
7
7
 
8
- Entry: every mutable KNOWN, from `gm-execute` or re-entered from VERIFY. Exit: gates clear → `gm-complete`.
8
+ Entry: every mutable KNOWN, from `gm-execute` or re-entered from VERIFY. Exit: gates clear → `gm-complete` (automatic, no approval).
9
9
 
10
10
  Cross-cutting dispositions live in `gm` SKILL.md.
11
11
 
12
+ **Skill Transition Guarantee**: When this skill completes, invoke `gm-complete` directly via `Skill()` — do not ask the user. Tool denials from gates (checkDispatchGates) surface as imperative reason text; the agent adjusts behavior and retries, never re-asks the user.
13
+
12
14
  ## Transitions
13
15
 
14
- - All gates clear → `gm-complete`
15
- - Post-emit variance with known cause → fix in-band, re-verify, stay in EMIT
16
- - Pre-emit reveals known logic error → `gm-execute`
17
- - Pre-emit reveals new unknown OR post-emit variance with unknown cause OR scope changed → `planning`
16
+ - All gates clear → `gm-complete` (invoke via `Skill(skill="gm:gm-complete")` immediately, no stop)
17
+ - Post-emit variance with known cause → fix in-band, re-verify, stay in EMIT (self-loop, no transition)
18
+ - Pre-emit reveals known logic error → `gm-execute` (invoke via `Skill(skill="gm:gm-execute")` immediately, no stop)
19
+ - Pre-emit reveals new unknown OR post-emit variance with unknown cause OR scope changed → `planning` (invoke via `Skill(skill="planning")` immediately, no stop)
18
20
 
19
21
  ## Legitimacy gate (before pre-emit run)
20
22
 
@@ -68,3 +70,7 @@ Before pre-emit run, read `.gm/mutables.yml`. Any entry with `status: unknown`
68
70
  - Structure: no if/else where dispatch suffices; no one-liners that obscure; no reinvented APIs
69
71
  - Every fact resolved this phase memorized via background `Agent(memorize)`
70
72
  - CHANGELOG.md updated; TODO.md cleared or deleted
73
+
74
+ ## Marker file protocol
75
+
76
+ EMIT phase operates after EXECUTE resolves all mutables. `.gm/prd.yml` and `.gm/mutables.yml` remain live (deleted by gm-complete when work finishes). Gate enforcement does not block EMIT — the `.gm/gm-fired-<sessionId>` marker was already written by PLAN at session start, so tool use (Write/Edit) is fully authorized. EMIT does not write or read markers; it only invokes Write/Edit on files and runs post-emit verifications. On transition to gm-complete (all gates clear), invoke the skill immediately (no marker write needed by EMIT).
@@ -5,17 +5,19 @@ description: EXECUTE phase AND the foundational execution contract for every ski
5
5
 
6
6
  # GM EXECUTE — Resolve every unknown by witness
7
7
 
8
- Entry: `.prd` with named unknowns. Exit: every mutable KNOWN → invoke `gm-emit`.
8
+ Entry: `.prd` with named unknowns. Exit: every mutable KNOWN → invoke `gm-emit` (automatic, no approval).
9
9
 
10
10
  A `@<discipline>` sigil propagates from PLAN through every recall, codesearch, and memorize call; reads without one fan across default plus enabled disciplines, writes without one go to default only.
11
11
 
12
12
  This skill is the execution contract for ALL phases — pre-emit witnesses, post-emit verifies, e2e checks all run on this discipline. Cross-cutting dispositions live in `gm` SKILL.md.
13
13
 
14
+ **Skill Transition Guarantee**: Tool use is pre-authorized by the initial user request. When this skill completes, invoke `gm-emit` directly via `Skill()` — do not ask the user. Tool denials from gates (checkDispatchGates) surface as imperative reason text; the agent adjusts behavior and retries, never re-asks the user.
15
+
14
16
  ## Transitions
15
17
 
16
- - All mutables KNOWN → `gm-emit`
18
+ - All mutables KNOWN → `gm-emit` (invoke via `Skill(skill="gm:emit")` immediately, no stop)
17
19
  - Still UNKNOWN → re-run from a different angle (max 2 passes)
18
- - New unknown OR unresolvable after 2 passes → `planning`
20
+ - New unknown OR unresolvable after 2 passes → `planning` (invoke via `Skill(skill="planning")` immediately, no stop)
19
21
 
20
22
  ## Mutable discipline
21
23
 
@@ -81,3 +83,7 @@ Up to 3 `gm:gm` subagents for independent items in one message. Browser escalati
81
83
  ## CI is automated
82
84
 
83
85
  After `git push`, poll `gh run list --branch main --limit 5 --json status,name,databaseId` until all runs reach a terminal state. Green → continue; failure → investigate via `gh run view <id> --log-failed`, fix, push again. Deadline 180s (override `GM_CI_WATCH_SECS`). Poll every 10s via a nodejs spool file with a `setInterval` loop writing results to stdout.
86
+
87
+ ## Marker file protocol
88
+
89
+ EXECUTE phase works against `.gm/prd.yml` and `.gm/mutables.yml` written by PLAN. Both files live for the duration of work and are deleted by gm-complete when work finishes. Gate enforcement (spool-dispatch layer) checks: if `.gm/prd.yml` + `.gm/needs-gm` exist BUT `.gm/gm-fired-<sessionId>` marker is missing, tool use blocks. PLAN writes all three markers at session start before transitioning to EXECUTE, so the gate is already clear when EXECUTE runs. EXECUTE does not write or read markers — it only reads and updates mutables. On transition to gm-emit, invoke the skill immediately (no marker write needed by EXECUTE).
@@ -31,7 +31,7 @@ const { spawn, spawnSync } = require('child_process');
31
31
  const fs = require('fs');
32
32
  const path = require('path');
33
33
  const os = require('os');
34
- const bin = path.join(os.homedir(), '.claude', 'gm-tools', process.platform === 'win32' ? 'plugkit.exe' : 'plugkit');
34
+ const bin = path.join(os.homedir(), '.claude', 'gm-tools', 'plugkit.wasm');
35
35
  const root = process.cwd();
36
36
  const spoolIn = path.join(root, '.gm', 'exec-spool', 'in');
37
37
  const spoolOut = path.join(root, '.gm', 'exec-spool', 'out');
@@ -42,13 +42,13 @@ if (fs.existsSync(pidFile)) {
42
42
  try { fs.unlinkSync(pidFile); } catch (_) {}
43
43
  }
44
44
  if (process.platform === 'win32') {
45
- try { spawnSync('taskkill', ['/F', '/IM', 'plugkit.exe'], { windowsHide: true, timeout: 3000, stdio: 'ignore' }); } catch (_) {}
45
+ try { spawnSync('taskkill', ['/F', '/IM', 'node.exe'], { windowsHide: true, timeout: 3000, stdio: 'ignore' }); } catch (_) {}
46
46
  } else {
47
47
  try { spawnSync('pkill', ['-f', 'plugkit'], { timeout: 3000, stdio: 'ignore' }); } catch (_) {}
48
48
  }
49
49
  fs.mkdirSync(spoolIn, { recursive: true });
50
50
  fs.mkdirSync(spoolOut, { recursive: true });
51
- const proc = spawn(bin, ['runner', '--watch', spoolIn, '--out', spoolOut], {
51
+ const proc = spawn('node', [bin, 'runner', '--watch', spoolIn, '--out', spoolOut], {
52
52
  detached: true, stdio: 'ignore', windowsHide: true, cwd: root,
53
53
  });
54
54
  proc.unref();
@@ -152,3 +152,24 @@ Pack runs use `Promise.allSettled`, each idea its own try/catch, under 12s per c
152
152
  No comments. 200-line per-file cap. Fail loud. No duplication. Scan before edit. AGENTS.md edits route through the memorize sub-agent only. CHANGELOG.md gets one entry per commit.
153
153
 
154
154
  Minimal-code process, stop at the first that resolves: native → library → structure (map / pipeline) → write.
155
+
156
+ ## Marker File Protocol
157
+
158
+ PLAN phase writes THREE marker files before transitioning to EXECUTE:
159
+ 1. `.gm/prd.yml` — the work items (already written per PRD format above)
160
+ 2. `.gm/needs-gm` — empty marker file signaling PRD is ready for orchestration
161
+ 3. `.gm/gm-fired-<sessionId>` — signals that gm orchestration (planning) has run and cleared the gate
162
+
163
+ When `.gm/prd.yml` and `.gm/needs-gm` both exist, downstream tools check `.gm/gm-fired-<sessionId>` marker. If missing, tool execution blocks with reason: "gm orchestration in progress; skills must complete work before tools execute." This gate prevents tool use from tools that run BEFORE the orchestration phase is complete. Writing the marker clears this gate.
164
+
165
+ Write all three markers as final step of PLAN:
166
+ ```
167
+ const fs = require('fs');
168
+ const path = require('path');
169
+ const sessionId = process.env.SESSION_ID || 'default';
170
+ fs.mkdirSync(path.join(process.cwd(), '.gm'), { recursive: true });
171
+ fs.writeFileSync(path.join(process.cwd(), '.gm', 'needs-gm'), '');
172
+ fs.writeFileSync(path.join(process.cwd(), '.gm', `gm-fired-${sessionId}`), '');
173
+ ```
174
+
175
+ Transition to `gm-execute` (or `gm-gm` subagent) immediately after writing all files. No stop-for-approval; the transition is automatic.
package/tools.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1073",
3
+ "version": "2.0.1075",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "tools": [
6
6
  {