gm-skill 2.0.1596 → 2.0.1598
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/bin/gm-shell-validate.js +16 -3
- package/bin/gm-validate.js +12 -3
- package/bin/plugkit.version +1 -1
- package/bin/plugkit.wasm.sha256 +1 -1
- package/gm-plugkit/cli.js +1 -1
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +2 -2
- package/gm.json +2 -2
- package/lang/ssh.js +16 -10
- package/lib/skill-bootstrap.js +1 -1
- package/lib/spool.js +2 -1
- package/package.json +1 -1
package/bin/gm-shell-validate.js
CHANGED
|
@@ -5,6 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const os = require('os');
|
|
8
|
+
const { pathToFileURL } = require('url');
|
|
8
9
|
|
|
9
10
|
const ROOT = process.cwd();
|
|
10
11
|
const WITNESS_DIR = path.join(ROOT, '.gm', 'witness');
|
|
@@ -30,7 +31,7 @@ async function renderPreview() {
|
|
|
30
31
|
const renderScript = `
|
|
31
32
|
import { writeFileSync } from 'fs';
|
|
32
33
|
import { resolve } from 'path';
|
|
33
|
-
const mod = await import('
|
|
34
|
+
const mod = await import(${JSON.stringify(pathToFileURL(path.join(ROOT, 'site', 'theme.mjs')).href)});
|
|
34
35
|
const ctx = {
|
|
35
36
|
readGlobal: (k) => {
|
|
36
37
|
if (k === 'site') return { title: 'gm', tagline: "more coushin' for the pushin'", description: 'local browser OS surface', glyph: 'g', accent_from: '#7ee787', accent_to: '#56d364' };
|
|
@@ -53,11 +54,20 @@ async function renderPreview() {
|
|
|
53
54
|
const server = cp.spawn('python', ['-m', 'http.server', '4210', '--directory', preview], { cwd: ROOT, detached: true, stdio: 'ignore', windowsHide: true });
|
|
54
55
|
server.unref();
|
|
55
56
|
await sleep(1500);
|
|
56
|
-
return { preview, port: 4210 };
|
|
57
|
+
return { preview, port: 4210, serverPid: server.pid };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function killServer(pid) {
|
|
61
|
+
if (!pid) return;
|
|
62
|
+
try {
|
|
63
|
+
if (process.platform === 'win32') cp.execFileSync('taskkill', ['/F', '/T', '/PID', String(pid)], { stdio: 'ignore', windowsHide: true });
|
|
64
|
+
else process.kill(pid, 'SIGTERM');
|
|
65
|
+
} catch (_) {}
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
async function main() {
|
|
60
|
-
const { preview, port } = await renderPreview();
|
|
69
|
+
const { preview, port, serverPid } = await renderPreview();
|
|
70
|
+
try {
|
|
61
71
|
const witness = path.join(os.tmpdir(), `gm-shell-witness-${Date.now()}.js`);
|
|
62
72
|
const witnessOut = path.join(WITNESS_DIR, `gm-shell-${Date.now()}.json`);
|
|
63
73
|
write(witness, `
|
|
@@ -112,6 +122,9 @@ return JSON.stringify(result);
|
|
|
112
122
|
fs.writeFileSync(witnessOut, JSON.stringify({ preview, port, output: out.trim(), parsed }, null, 2));
|
|
113
123
|
try { fs.unlinkSync(witness); } catch (_) {}
|
|
114
124
|
rmrf(preview);
|
|
125
|
+
} finally {
|
|
126
|
+
killServer(serverPid);
|
|
127
|
+
}
|
|
115
128
|
}
|
|
116
129
|
|
|
117
130
|
main().catch((e) => {
|
package/bin/gm-validate.js
CHANGED
|
@@ -189,7 +189,7 @@ async function validateEmbed() {
|
|
|
189
189
|
}
|
|
190
190
|
const lats = v.calls.map(c => c.latency_ms).sort((a, b) => a - b);
|
|
191
191
|
v.p50_ms = lats[Math.floor(lats.length * 0.5)] || 0;
|
|
192
|
-
v.p95_ms = lats[Math.max(0, lats.length - 1)] || 0;
|
|
192
|
+
v.p95_ms = lats[Math.max(0, Math.ceil(lats.length * 0.95) - 1)] || 0;
|
|
193
193
|
|
|
194
194
|
const r = await dispatch('recall', { query: 'gm-validate witness', namespace: 'validate', limit: 3 }, 60000);
|
|
195
195
|
const rd = (r.response && (r.response.data || r.response)) || {};
|
|
@@ -238,6 +238,7 @@ async function validateBrowserEmbed() {
|
|
|
238
238
|
serveProc.unref();
|
|
239
239
|
} catch (e) { v.errors.push('serve spawn: ' + e.message); return v; }
|
|
240
240
|
|
|
241
|
+
try {
|
|
241
242
|
const t0 = Date.now();
|
|
242
243
|
let ready = false;
|
|
243
244
|
while (Date.now() - t0 < 20000) {
|
|
@@ -278,7 +279,7 @@ return out;
|
|
|
278
279
|
try {
|
|
279
280
|
const tmpScript = path.join(os.tmpdir(), 'gm-validate-' + Date.now() + '.js');
|
|
280
281
|
fs.writeFileSync(tmpScript, script);
|
|
281
|
-
const out = cp.
|
|
282
|
+
const out = cp.execFileSync(pw, ['-s', sessionId, '--timeout', '60000', '-f', tmpScript], { encoding: 'utf8', windowsHide: true, maxBuffer: 4 * 1024 * 1024 });
|
|
282
283
|
try { fs.unlinkSync(tmpScript); } catch (_) {}
|
|
283
284
|
const m = out.match(/\{[\s\S]*\}\s*$/);
|
|
284
285
|
if (m) { try { res = JSON.parse(m[0]); } catch (_) {} }
|
|
@@ -290,7 +291,7 @@ return out;
|
|
|
290
291
|
v.calls = res.mems;
|
|
291
292
|
const lats = res.mems.map(c => c.latency_ms).sort((a, b) => a - b);
|
|
292
293
|
v.p50_ms = Math.round(lats[Math.floor(lats.length * 0.5)] || 0);
|
|
293
|
-
v.p95_ms = Math.round(lats[Math.max(0, lats.length - 1)] || 0);
|
|
294
|
+
v.p95_ms = Math.round(lats[Math.max(0, Math.ceil(lats.length * 0.95) - 1)] || 0);
|
|
294
295
|
const rows = (res.recall && (res.recall.rows || res.recall.hits)) || [];
|
|
295
296
|
v.recall_top_text = (rows[0] && (rows[0].text || rows[0].content)) || '';
|
|
296
297
|
const allOk = v.calls.every(c => c.ok);
|
|
@@ -298,6 +299,14 @@ return out;
|
|
|
298
299
|
if (!allOk) v.errors.push('not all browser memorize calls ok');
|
|
299
300
|
}
|
|
300
301
|
return v;
|
|
302
|
+
} finally {
|
|
303
|
+
if (serveProc && serveProc.pid) {
|
|
304
|
+
try {
|
|
305
|
+
if (process.platform === 'win32') cp.execFileSync('taskkill', ['/F', '/T', '/PID', String(serveProc.pid)], { stdio: 'ignore', windowsHide: true });
|
|
306
|
+
else process.kill(serveProc.pid, 'SIGTERM');
|
|
307
|
+
} catch (_) {}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
301
310
|
}
|
|
302
311
|
|
|
303
312
|
(async () => {
|
package/bin/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.679
|
package/bin/plugkit.wasm.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
60b61cd5dd1a7b9116849805b7a7c75bda06b2319c580dfceee9c9e3297af141 plugkit.wasm
|
package/gm-plugkit/cli.js
CHANGED
|
@@ -101,7 +101,7 @@ function killStaleWatchers() {
|
|
|
101
101
|
for (const s of stale) {
|
|
102
102
|
try {
|
|
103
103
|
if (process.platform === 'win32') {
|
|
104
|
-
cp.execFileSync('taskkill', ['/F', '/PID', String(s.pid)], { stdio: 'ignore', windowsHide: true });
|
|
104
|
+
cp.execFileSync('taskkill', ['/F', '/T', '/PID', String(s.pid)], { stdio: 'ignore', windowsHide: true });
|
|
105
105
|
} else {
|
|
106
106
|
process.kill(s.pid, 'SIGTERM');
|
|
107
107
|
}
|
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.1598",
|
|
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": {
|
|
@@ -836,7 +836,7 @@ function isPortAliveSync(port) {
|
|
|
836
836
|
}
|
|
837
837
|
|
|
838
838
|
function sleepSync(ms) {
|
|
839
|
-
|
|
839
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.max(0, ms | 0));
|
|
840
840
|
}
|
|
841
841
|
|
|
842
842
|
function playwriterHomeFor(cwd, claudeSessionId) {
|
|
@@ -1049,7 +1049,7 @@ function purgeProfileLockFiles(profileDir) {
|
|
|
1049
1049
|
|
|
1050
1050
|
function sleepSyncMs(ms) {
|
|
1051
1051
|
if (ms <= 0) return;
|
|
1052
|
-
|
|
1052
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms | 0);
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
1055
|
function gracefulCloseBrowser(entry, reason) {
|
package/gm.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1598",
|
|
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.
|
|
20
|
+
"plugkitVersion": "0.1.679"
|
|
21
21
|
}
|
package/lang/ssh.js
CHANGED
|
@@ -75,19 +75,23 @@ function runSsh(target, cmd, onData) {
|
|
|
75
75
|
return new Promise((resolve, reject) => {
|
|
76
76
|
const { Client } = resolveSsh2();
|
|
77
77
|
const ssh = new Client();
|
|
78
|
-
let
|
|
78
|
+
let stdout = '';
|
|
79
|
+
let stderr = '';
|
|
79
80
|
let done = false;
|
|
80
81
|
|
|
81
|
-
const finish = (
|
|
82
|
-
if (!done) {
|
|
82
|
+
const finish = (extra) => {
|
|
83
|
+
if (!done) {
|
|
84
|
+
done = true;
|
|
85
|
+
ssh.end();
|
|
86
|
+
resolve({ stdout: stdout.trimEnd(), stderr: stderr.trimEnd(), timedOut: false, ...extra });
|
|
87
|
+
}
|
|
83
88
|
};
|
|
84
89
|
|
|
85
90
|
const timeout = setTimeout(() => {
|
|
86
91
|
if (!done) {
|
|
87
92
|
done = true;
|
|
88
93
|
try { ssh.end(); } catch (_) {}
|
|
89
|
-
|
|
90
|
-
resolve(partial ? `${partial}\n[ssh timed out after 55s; output above is partial]` : '[ssh timed out after 55s; no output]');
|
|
94
|
+
resolve({ stdout: stdout.trimEnd(), stderr: (stderr + '\n[ssh timed out after 55s; output is partial]').trimEnd(), timedOut: true });
|
|
91
95
|
}
|
|
92
96
|
}, 55000);
|
|
93
97
|
|
|
@@ -96,12 +100,12 @@ function runSsh(target, cmd, onData) {
|
|
|
96
100
|
if (err) { clearTimeout(timeout); ssh.end(); reject(err); return; }
|
|
97
101
|
stream.on('data', d => {
|
|
98
102
|
const s = d.toString();
|
|
99
|
-
|
|
103
|
+
stdout += s;
|
|
100
104
|
if (onData) onData(s, 'stdout');
|
|
101
105
|
});
|
|
102
106
|
stream.stderr.on('data', d => {
|
|
103
107
|
const s = d.toString();
|
|
104
|
-
|
|
108
|
+
stderr += s;
|
|
105
109
|
if (onData) onData(s, 'stderr');
|
|
106
110
|
});
|
|
107
111
|
stream.on('close', () => { clearTimeout(timeout); finish(); });
|
|
@@ -133,8 +137,8 @@ async function runBackground(target, cmd) {
|
|
|
133
137
|
rpcCall(port, 'appendOutput', { taskId, type, data }).catch(() => {});
|
|
134
138
|
};
|
|
135
139
|
|
|
136
|
-
runSsh(target, cmd, onData).then(
|
|
137
|
-
rpcCall(port, 'completeTask', { taskId, result: { success:
|
|
140
|
+
runSsh(target, cmd, onData).then(r => {
|
|
141
|
+
rpcCall(port, 'completeTask', { taskId, result: { success: !r.timedOut, exitCode: r.timedOut ? 124 : 0, stdout: r.stdout, stderr: r.stderr, error: r.timedOut ? 'ssh timed out after 55s' : null } }).catch(() => {});
|
|
138
142
|
}).catch(err => {
|
|
139
143
|
rpcCall(port, 'completeTask', { taskId, result: { success: false, exitCode: 1, stdout: '', stderr: err.message, error: err.message } }).catch(() => {});
|
|
140
144
|
});
|
|
@@ -163,7 +167,9 @@ module.exports = {
|
|
|
163
167
|
}
|
|
164
168
|
}
|
|
165
169
|
|
|
166
|
-
|
|
170
|
+
const r = await runSsh(target, cmd, null);
|
|
171
|
+
const combined = [r.stdout, r.stderr].filter(Boolean).join('\n');
|
|
172
|
+
return combined || (r.timedOut ? '[ssh timed out after 55s; no output]' : '');
|
|
167
173
|
}
|
|
168
174
|
},
|
|
169
175
|
context: `=== exec:ssh ===
|
package/lib/skill-bootstrap.js
CHANGED
|
@@ -423,7 +423,7 @@ function killExistingPlugkit() {
|
|
|
423
423
|
for (const pid of pids) {
|
|
424
424
|
try {
|
|
425
425
|
if (process.platform === 'win32') {
|
|
426
|
-
execSync(`taskkill /F /PID ${pid}`, { stdio: 'ignore' });
|
|
426
|
+
execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore' });
|
|
427
427
|
} else {
|
|
428
428
|
execSync(`kill -9 ${pid}`, { stdio: 'ignore' });
|
|
429
429
|
}
|
package/lib/spool.js
CHANGED
|
@@ -7,8 +7,9 @@ function getSpoolBaseDir() {
|
|
|
7
7
|
return path.join(cwd, '.gm', 'exec-spool');
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
let taskIdSeq = 0;
|
|
10
11
|
function generateTaskId() {
|
|
11
|
-
return `${Date.now()}-${
|
|
12
|
+
return `${process.pid}-${Date.now()}-${(taskIdSeq++).toString(36)}`;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
function validateLang(lang) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1598",
|
|
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",
|