gm-skill 2.0.1849 → 2.0.1850
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/gm-plugkit/bootstrap.js +18 -4
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +72 -9
- package/gm-plugkit/supervisor.js +19 -6
- package/gm.json +1 -1
- package/package.json +1 -1
package/gm-plugkit/bootstrap.js
CHANGED
|
@@ -1047,13 +1047,12 @@ function probeUnsupervisedWatcher(spoolDir) {
|
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
1049
|
function resolveNodeRuntime() {
|
|
1050
|
-
const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
|
|
1051
1050
|
const candidates = [];
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1051
|
+
if (process.env.PLUGKIT_RUNTIME) candidates.push(process.env.PLUGKIT_RUNTIME);
|
|
1052
|
+
candidates.push('bun');
|
|
1054
1053
|
try {
|
|
1055
1054
|
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
1056
|
-
const out = require('child_process').spawnSync(which, ['
|
|
1055
|
+
const out = require('child_process').spawnSync(which, ['bun'], { encoding: 'utf8', windowsHide: true });
|
|
1057
1056
|
if (out && out.stdout) {
|
|
1058
1057
|
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
1059
1058
|
if (first) candidates.push(first);
|
|
@@ -1062,6 +1061,21 @@ function resolveNodeRuntime() {
|
|
|
1062
1061
|
for (const c of candidates) {
|
|
1063
1062
|
try { const r = require('child_process').spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
1064
1063
|
}
|
|
1064
|
+
const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
|
|
1065
|
+
const nodeCandidates = [];
|
|
1066
|
+
if (isNodeExe(process.env.GM_NODE_PATH)) nodeCandidates.push(process.env.GM_NODE_PATH);
|
|
1067
|
+
if (isNodeExe(process.execPath)) nodeCandidates.push(process.execPath);
|
|
1068
|
+
try {
|
|
1069
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
1070
|
+
const out = require('child_process').spawnSync(which, ['node'], { encoding: 'utf8', windowsHide: true });
|
|
1071
|
+
if (out && out.stdout) {
|
|
1072
|
+
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
1073
|
+
if (first) nodeCandidates.push(first);
|
|
1074
|
+
}
|
|
1075
|
+
} catch (_) {}
|
|
1076
|
+
for (const c of nodeCandidates) {
|
|
1077
|
+
try { const r = require('child_process').spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
1078
|
+
}
|
|
1065
1079
|
return process.execPath;
|
|
1066
1080
|
}
|
|
1067
1081
|
|
package/gm-plugkit/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1850",
|
|
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": {
|
|
@@ -117,12 +117,14 @@ function clearVerbActive() {
|
|
|
117
117
|
|
|
118
118
|
process.on('uncaughtException', (err) => {
|
|
119
119
|
try { console.error('[plugkit-wasm] uncaught:', err && err.stack || err); } catch (_) {}
|
|
120
|
+
try { killAllTasks('crash:uncaughtException'); } catch (_) {}
|
|
120
121
|
emitShutdownReason('uncaughtException', err);
|
|
121
122
|
process.exit(1);
|
|
122
123
|
});
|
|
123
124
|
|
|
124
125
|
process.on('unhandledRejection', (reason) => {
|
|
125
126
|
try { console.error('[plugkit-wasm] unhandled rejection:', reason && reason.stack || reason); } catch (_) {}
|
|
127
|
+
try { killAllTasks('crash:unhandledRejection'); } catch (_) {}
|
|
126
128
|
emitShutdownReason('unhandledRejection', reason instanceof Error ? reason : new Error(String(reason)));
|
|
127
129
|
process.exit(1);
|
|
128
130
|
});
|
|
@@ -745,23 +747,23 @@ function aggregateCpuProfile(profile, topN) {
|
|
|
745
747
|
const BROWSER_RUNNER_BIN = process.env.GM_BROWSER_RUNNER_BIN || 'playwriter';
|
|
746
748
|
|
|
747
749
|
function findBrowserRunner() {
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
750
|
+
const bunGlobalRoots = [
|
|
751
|
+
path.join(os.homedir(), '.bun', 'install', 'global', 'node_modules', BROWSER_RUNNER_BIN, 'bin.js'),
|
|
752
|
+
];
|
|
753
|
+
for (const binJs of bunGlobalRoots) {
|
|
752
754
|
if (fs.existsSync(binJs)) return { cmd: process.execPath, baseArgs: [binJs], shell: false };
|
|
753
755
|
}
|
|
754
756
|
const whichCmd = process.platform === 'win32' ? 'where' : 'which';
|
|
757
|
+
const bunR = spawnSync(whichCmd, ['bun'], { encoding: 'utf-8', shell: true });
|
|
758
|
+
if (bunR.status === 0 && bunR.stdout.trim()) {
|
|
759
|
+
return { cmd: 'bun', baseArgs: ['x', `${BROWSER_RUNNER_BIN}@latest`], shell: true };
|
|
760
|
+
}
|
|
755
761
|
const r = spawnSync(whichCmd, [BROWSER_RUNNER_BIN], { encoding: 'utf-8', shell: true });
|
|
756
762
|
if (r.status === 0 && r.stdout.trim()) {
|
|
757
763
|
const candidates = r.stdout.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
758
764
|
const cmd = candidates.find(c => c.toLowerCase().endsWith('.cmd')) || candidates.find(c => !c.toLowerCase().endsWith('.ps1')) || candidates[0];
|
|
759
765
|
if (cmd) return { cmd, baseArgs: [], shell: process.platform === 'win32' };
|
|
760
766
|
}
|
|
761
|
-
const bunR = spawnSync(whichCmd, ['bun'], { encoding: 'utf-8', shell: true });
|
|
762
|
-
if (bunR.status === 0 && bunR.stdout.trim()) {
|
|
763
|
-
return { cmd: 'bun', baseArgs: ['x', `${BROWSER_RUNNER_BIN}@latest`], shell: true };
|
|
764
|
-
}
|
|
765
767
|
const npxR = spawnSync(whichCmd, ['npx'], { encoding: 'utf-8', shell: true });
|
|
766
768
|
if (npxR.status === 0 && npxR.stdout.trim()) {
|
|
767
769
|
return { cmd: 'npx', baseArgs: ['-y', BROWSER_RUNNER_BIN], shell: true };
|
|
@@ -2116,8 +2118,25 @@ function nextTaskId(cwd) {
|
|
|
2116
2118
|
return `t${n}`;
|
|
2117
2119
|
}
|
|
2118
2120
|
|
|
2121
|
+
let _jsRuntimeCmd = null;
|
|
2122
|
+
function resolveJsRuntimeCmd() {
|
|
2123
|
+
if (_jsRuntimeCmd) return _jsRuntimeCmd;
|
|
2124
|
+
if (!/(^|[\\/])node(\.exe)?$/i.test(String(process.execPath || ''))) {
|
|
2125
|
+
_jsRuntimeCmd = process.execPath;
|
|
2126
|
+
return _jsRuntimeCmd;
|
|
2127
|
+
}
|
|
2128
|
+
try {
|
|
2129
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
2130
|
+
const out = spawnSync(which, ['bun'], { encoding: 'utf-8', windowsHide: true });
|
|
2131
|
+
const first = (out && out.stdout || '').split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
2132
|
+
if (first) { _jsRuntimeCmd = first; return _jsRuntimeCmd; }
|
|
2133
|
+
} catch (_) {}
|
|
2134
|
+
_jsRuntimeCmd = process.execPath;
|
|
2135
|
+
return _jsRuntimeCmd;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2119
2138
|
function langToCmd(lang, code) {
|
|
2120
|
-
if (lang === 'nodejs' || lang === 'js' || lang === 'javascript' || lang === 'node') return { cmd:
|
|
2139
|
+
if (lang === 'nodejs' || lang === 'js' || lang === 'javascript' || lang === 'node') return { cmd: resolveJsRuntimeCmd(), args: ['-e', code], stdinCode: null };
|
|
2121
2140
|
if (lang === 'python' || lang === 'py') return { cmd: 'python', args: ['-c', code], stdinCode: null };
|
|
2122
2141
|
if (lang === 'bash' || lang === 'sh' || lang === 'shell' || lang === 'zsh') return { cmd: 'bash', args: ['-c', code], stdinCode: null };
|
|
2123
2142
|
if (lang === 'powershell' || lang === 'ps1') return { cmd: 'powershell', args: ['-NoProfile', '-NonInteractive', '-Command', code], stdinCode: null };
|
|
@@ -2125,10 +2144,15 @@ function langToCmd(lang, code) {
|
|
|
2125
2144
|
return null;
|
|
2126
2145
|
}
|
|
2127
2146
|
|
|
2147
|
+
const TASK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
|
|
2148
|
+
|
|
2128
2149
|
function spawnTask({ cwd, lang, code, timeoutMs }) {
|
|
2129
2150
|
const id = nextTaskId(cwd);
|
|
2130
2151
|
const built = langToCmd(lang, code);
|
|
2131
2152
|
if (!built) return { ok: false, error: `unsupported lang: ${lang}` };
|
|
2153
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > TASK_MAX_TIMEOUT_MS) {
|
|
2154
|
+
timeoutMs = TASK_MAX_TIMEOUT_MS;
|
|
2155
|
+
}
|
|
2132
2156
|
const outLog = taskOutPath(cwd, id, 'stdout');
|
|
2133
2157
|
const errLog = taskOutPath(cwd, id, 'stderr');
|
|
2134
2158
|
let outFd = null, errFd = null;
|
|
@@ -2261,6 +2285,43 @@ function killAllTasks(reason) {
|
|
|
2261
2285
|
return killed;
|
|
2262
2286
|
}
|
|
2263
2287
|
|
|
2288
|
+
function pidAliveLocal(pid) {
|
|
2289
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
2290
|
+
try { process.kill(pid, 0); return true; } catch (_) { return false; }
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
function sweepOrphanedTaskMetaOnBoot(cwd) {
|
|
2294
|
+
let swept = 0;
|
|
2295
|
+
try {
|
|
2296
|
+
const dir = tasksDir(cwd);
|
|
2297
|
+
const now = Date.now();
|
|
2298
|
+
for (const name of fs.readdirSync(dir)) {
|
|
2299
|
+
if (!/^t\d+\.json$/.test(name)) continue;
|
|
2300
|
+
const metaPath = path.join(dir, name);
|
|
2301
|
+
let meta = null;
|
|
2302
|
+
try { meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8')); } catch (_) { continue; }
|
|
2303
|
+
if (!meta || meta.status !== 'running') continue;
|
|
2304
|
+
const stale = !pidAliveLocal(meta.pid) || (meta.deadline_ms && now > meta.deadline_ms);
|
|
2305
|
+
if (!stale) continue;
|
|
2306
|
+
if (pidAliveLocal(meta.pid)) {
|
|
2307
|
+
try {
|
|
2308
|
+
if (process.platform === 'win32') {
|
|
2309
|
+
spawnSync('taskkill', ['/F', '/T', '/PID', String(meta.pid)], { stdio: 'ignore', windowsHide: true, timeout: 3000 });
|
|
2310
|
+
} else {
|
|
2311
|
+
try { process.kill(-meta.pid, 'SIGKILL'); } catch (_) { try { process.kill(meta.pid, 'SIGKILL'); } catch (_) {} }
|
|
2312
|
+
}
|
|
2313
|
+
} catch (_) {}
|
|
2314
|
+
}
|
|
2315
|
+
meta.status = 'reaped-on-boot';
|
|
2316
|
+
meta.ended_ms = now;
|
|
2317
|
+
try { fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2)); } catch (_) {}
|
|
2318
|
+
swept += 1;
|
|
2319
|
+
}
|
|
2320
|
+
} catch (_) {}
|
|
2321
|
+
if (swept > 0) logEvent('plugkit', 'task.bootSweepReaped', { cwd: cwd || process.cwd(), count: swept });
|
|
2322
|
+
return swept;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2264
2325
|
function hostTaskProc(action, params) {
|
|
2265
2326
|
switch (action) {
|
|
2266
2327
|
case 'spawn': return spawnTask(params);
|
|
@@ -3394,6 +3455,8 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
3394
3455
|
process.exit(0);
|
|
3395
3456
|
}
|
|
3396
3457
|
|
|
3458
|
+
try { sweepOrphanedTaskMetaOnBoot(process.cwd()); } catch (_) {}
|
|
3459
|
+
|
|
3397
3460
|
setInterval(() => {
|
|
3398
3461
|
try { reapTimedOutTasks(); } catch (_) {}
|
|
3399
3462
|
}, 5000);
|
package/gm-plugkit/supervisor.js
CHANGED
|
@@ -194,14 +194,13 @@ function spawnWatcher(bootReason) {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
|
|
197
|
-
const
|
|
197
|
+
const resolveRuntime = () => {
|
|
198
198
|
const candidates = [];
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
if (process.env.GM_NODE_PATH) candidates.push(process.env.GM_NODE_PATH);
|
|
199
|
+
if (process.env.PLUGKIT_RUNTIME) candidates.push(process.env.PLUGKIT_RUNTIME);
|
|
200
|
+
candidates.push('bun');
|
|
202
201
|
try {
|
|
203
202
|
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
204
|
-
const out = spawnSync(which, ['
|
|
203
|
+
const out = spawnSync(which, ['bun'], { encoding: 'utf8', windowsHide: true });
|
|
205
204
|
if (out && out.stdout) {
|
|
206
205
|
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
207
206
|
if (first) candidates.push(first);
|
|
@@ -210,9 +209,23 @@ function spawnWatcher(bootReason) {
|
|
|
210
209
|
for (const c of candidates) {
|
|
211
210
|
try { const r = spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
212
211
|
}
|
|
212
|
+
const nodeCandidates = [];
|
|
213
|
+
if (isNodeExe(process.execPath)) nodeCandidates.push(process.execPath);
|
|
214
|
+
if (process.env.GM_NODE_PATH) nodeCandidates.push(process.env.GM_NODE_PATH);
|
|
215
|
+
try {
|
|
216
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
217
|
+
const out = spawnSync(which, ['node'], { encoding: 'utf8', windowsHide: true });
|
|
218
|
+
if (out && out.stdout) {
|
|
219
|
+
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
220
|
+
if (first) nodeCandidates.push(first);
|
|
221
|
+
}
|
|
222
|
+
} catch (_) {}
|
|
223
|
+
for (const c of nodeCandidates) {
|
|
224
|
+
try { const r = spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
225
|
+
}
|
|
213
226
|
return process.execPath;
|
|
214
227
|
};
|
|
215
|
-
let cmd =
|
|
228
|
+
let cmd = resolveRuntime();
|
|
216
229
|
let args = [wrapper, 'spool'];
|
|
217
230
|
|
|
218
231
|
let logFd = null;
|
package/gm.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1850",
|
|
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",
|