gm-plugkit 2.0.1217 → 2.0.1219

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": "gm-plugkit",
3
- "version": "2.0.1217",
3
+ "version": "2.0.1219",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform binary, verifies SHA256, and starts the spool watcher daemon. Includes plugkit-wasm-wrapper for WASM-based spool watching.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -70,6 +70,32 @@ function isSpoolPollCommand(command) {
70
70
  return null;
71
71
  }
72
72
 
73
+ function isBrowserRunningFileLocal(rel) {
74
+ if (!rel) return false;
75
+ const norm = String(rel).replace(/\\\\/g, '/');
76
+ if (/\\.(html?|tsx|jsx|vue|svelte)$/i.test(norm)) return true;
77
+ if (/\\.(mjs|cjs|js|ts|css|scss|sass)$/i.test(norm) && /^(src|public|site|app|pages|components|client|web)\\//i.test(norm)) return true;
78
+ return false;
79
+ }
80
+
81
+ function recordBrowserEditLocal(cwd, filePath) {
82
+ try {
83
+ const fs = require('fs');
84
+ const path = require('path');
85
+ let rel = filePath;
86
+ try { rel = path.relative(cwd, filePath); } catch (_) {}
87
+ if (!isBrowserRunningFileLocal(rel)) return false;
88
+ const editsFile = path.join(cwd, '.gm', 'exec-spool', '.turn-browser-edits.json');
89
+ fs.mkdirSync(path.dirname(editsFile), { recursive: true });
90
+ let list = [];
91
+ try { list = JSON.parse(fs.readFileSync(editsFile, 'utf8')); if (!Array.isArray(list)) list = []; } catch (_) {}
92
+ const entry = { file: rel.replace(/\\\\/g, '/'), ts: Date.now() };
93
+ if (!list.some(e => e && e.file === entry.file)) list.push(entry);
94
+ fs.writeFileSync(editsFile, JSON.stringify(list));
95
+ return true;
96
+ } catch (_) { return false; }
97
+ }
98
+
73
99
  let raw = '';
74
100
  process.stdin.setEncoding('utf8');
75
101
  process.stdin.on('data', (chunk) => { raw += chunk; });
@@ -78,6 +104,17 @@ process.stdin.on('end', () => {
78
104
  try { event = JSON.parse(raw || '{}'); } catch (_) { event = {}; }
79
105
  const tool = event.tool_name || event.tool || '';
80
106
  const input = event.tool_input || event.input || {};
107
+ const cwd = event.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
108
+
109
+ if (tool === 'Write' || tool === 'Edit' || tool === 'MultiEdit') {
110
+ const fp = input.file_path || input.filePath || input.path || '';
111
+ if (fp) {
112
+ try { recordBrowserEditLocal(cwd, fp); } catch (_) {}
113
+ }
114
+ process.stdout.write(JSON.stringify({ continue: true }));
115
+ process.exit(0);
116
+ }
117
+
81
118
  if (tool !== 'Bash') {
82
119
  process.stdout.write(JSON.stringify({ continue: true }));
83
120
  process.exit(0);
@@ -165,15 +202,17 @@ function ensureSpoolPollGate(cwd) {
165
202
  if (!settings.hooks || typeof settings.hooks !== 'object') settings.hooks = {};
166
203
  if (!Array.isArray(settings.hooks.PreToolUse)) settings.hooks.PreToolUse = [];
167
204
  const wantCommand = `node "\${CLAUDE_PROJECT_DIR}/.gm/hooks/spool-poll-gate.js"`;
168
- let bashEntry = settings.hooks.PreToolUse.find(e => e && e.matcher === 'Bash');
169
- if (!bashEntry) {
170
- bashEntry = { matcher: 'Bash', hooks: [] };
171
- settings.hooks.PreToolUse.push(bashEntry);
172
- }
173
- if (!Array.isArray(bashEntry.hooks)) bashEntry.hooks = [];
174
- const already = bashEntry.hooks.some(h => h && typeof h.command === 'string' && h.command.includes('spool-poll-gate.js'));
175
- if (!already) {
176
- bashEntry.hooks.push({ type: 'command', command: wantCommand });
205
+ for (const matcher of ['Bash', 'Write', 'Edit', 'MultiEdit']) {
206
+ let entry = settings.hooks.PreToolUse.find(e => e && e.matcher === matcher);
207
+ if (!entry) {
208
+ entry = { matcher, hooks: [] };
209
+ settings.hooks.PreToolUse.push(entry);
210
+ }
211
+ if (!Array.isArray(entry.hooks)) entry.hooks = [];
212
+ const already = entry.hooks.some(h => h && typeof h.command === 'string' && h.command.includes('spool-poll-gate.js'));
213
+ if (!already) {
214
+ entry.hooks.push({ type: 'command', command: wantCommand });
215
+ }
177
216
  }
178
217
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
179
218
  } catch (_) {}
@@ -1184,7 +1223,17 @@ function makeHostFunctions(instanceRef) {
1184
1223
  const opts = optsStr ? JSON.parse(optsStr) : {};
1185
1224
  const lang = opts.lang || 'nodejs';
1186
1225
  const cwd = opts.cwd || process.cwd();
1187
- const timeoutMs = opts.timeoutMs || 30000;
1226
+ const rawTimeout = opts.timeoutMs;
1227
+ if (rawTimeout === undefined || rawTimeout === null || typeof rawTimeout !== 'number' || !Number.isFinite(rawTimeout) || rawTimeout <= 0 || !Number.isInteger(rawTimeout)) {
1228
+ return writeWasmJson(instanceRef.value, {
1229
+ ok: false,
1230
+ error: 'missing timeoutMs',
1231
+ required: 'positive integer milliseconds',
1232
+ paper_ref: '§20',
1233
+ received: rawTimeout === undefined ? null : rawTimeout,
1234
+ });
1235
+ }
1236
+ const timeoutMs = rawTimeout;
1188
1237
  let cmd, args;
1189
1238
  if (lang === 'nodejs' || lang === 'js') { cmd = process.execPath; args = ['-e', code]; }
1190
1239
  else if (lang === 'python') { cmd = 'python'; args = ['-c', code]; }
@@ -1716,6 +1765,13 @@ async function runSpoolWatcher(instance, spoolDir) {
1716
1765
  const sessForRecall = readCurrentSess();
1717
1766
  if (isInstructionTurnStart(sessForRecall)) {
1718
1767
  autoRecallPayload = tryAutoRecallForTurnEntry(instance, sessForRecall, process.cwd());
1768
+ try {
1769
+ const _spoolDir = path.join(process.cwd(), '.gm', 'exec-spool');
1770
+ for (const _f of ['.turn-browser-edits.json', '.turn-browser-witnessed']) {
1771
+ const _p = path.join(_spoolDir, _f);
1772
+ if (fs.existsSync(_p)) fs.unlinkSync(_p);
1773
+ }
1774
+ } catch (_) {}
1719
1775
  }
1720
1776
  }
1721
1777
 
@@ -1742,6 +1798,15 @@ async function runSpoolWatcher(instance, spoolDir) {
1742
1798
  logEvent('plugkit', 'dispatch.end', { verb, task: taskBase, dur_ms, out_bytes: resultStr.length });
1743
1799
  emitOrchestratorEvents(verb, taskBase, resultStr);
1744
1800
 
1801
+ if (verb === 'browser') {
1802
+ try {
1803
+ const witnessFile = path.join(process.cwd(), '.gm', 'exec-spool', '.turn-browser-witnessed');
1804
+ fs.mkdirSync(path.dirname(witnessFile), { recursive: true });
1805
+ fs.writeFileSync(witnessFile, JSON.stringify({ ts: Date.now(), task: taskBase, dur_ms }));
1806
+ logEvent('plugkit', 'browser.witness-marked', { task: taskBase });
1807
+ } catch (_) {}
1808
+ }
1809
+
1745
1810
  try { instance.exports.plugkit_free(verbPtr, verbBytes.length); } catch (_) {}
1746
1811
  try { instance.exports.plugkit_free(bodyPtr, bodyBytes.length); } catch (_) {}
1747
1812
  try { instance.exports.plugkit_free(ptr, len); } catch (_) {}
package/plugkit.sha256 CHANGED
@@ -1 +1 @@
1
- {"plugkit.wasm":"f47f68684b3860078e10698ca188c302968eb99fbc6608a2851eb3ded4b55df8"}
1
+ {"plugkit.wasm":"0ce920f00138b9524a0a1ad062dab691e4959497853644a7d06403c2b77ed480"}
package/plugkit.version CHANGED
@@ -1 +1 @@
1
- 0.1.446
1
+ 0.1.447