gm-skill 2.0.1157 → 2.0.1159
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/README.md +1 -1
- package/bin/plugkit.version +1 -1
- package/bin/plugkit.wasm +0 -0
- package/bin/plugkit.wasm.sha256 +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +212 -0
- package/gm.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ An earlier generation fanned out fifteen per-platform downstream repos (gm-cc, g
|
|
|
35
35
|
|
|
36
36
|
## Version
|
|
37
37
|
|
|
38
|
-
`2.0.
|
|
38
|
+
`2.0.1159` — auto-bumped from the canonical `gm` repo. Every push to `AnEntrypoint/gm` (or any cascading sibling crate) republishes this package.
|
|
39
39
|
|
|
40
40
|
## Source of truth
|
|
41
41
|
|
package/bin/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.418
|
package/bin/plugkit.wasm
CHANGED
|
Binary file
|
package/bin/plugkit.wasm.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ffb68924055bffd275db6a174fb5d286c1fcaf5a135f968345bf221b9976544f plugkit.wasm
|
|
@@ -435,6 +435,192 @@ function kvFilePath(ns, key) {
|
|
|
435
435
|
return path.join(dir, safeKey + '.json');
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
+
const __tasks = new Map();
|
|
439
|
+
|
|
440
|
+
function tasksDir(cwd) {
|
|
441
|
+
const d = path.join(cwd || process.cwd(), '.gm', 'exec-spool', 'tasks');
|
|
442
|
+
try { fs.mkdirSync(d, { recursive: true }); } catch (_) {}
|
|
443
|
+
return d;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function taskMetaPath(cwd, id) { return path.join(tasksDir(cwd), `${id}.json`); }
|
|
447
|
+
function taskOutPath(cwd, id, which) { return path.join(tasksDir(cwd), `${id}.${which}.log`); }
|
|
448
|
+
|
|
449
|
+
function writeTaskMeta(cwd, id, meta) {
|
|
450
|
+
try { fs.writeFileSync(taskMetaPath(cwd, id), JSON.stringify(meta, null, 2)); } catch (_) {}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function nextTaskId(cwd) {
|
|
454
|
+
const counterPath = path.join(tasksDir(cwd), '.counter');
|
|
455
|
+
let n = 0;
|
|
456
|
+
try { n = parseInt(fs.readFileSync(counterPath, 'utf-8'), 10) || 0; } catch (_) {}
|
|
457
|
+
n += 1;
|
|
458
|
+
try { fs.writeFileSync(counterPath, String(n)); } catch (_) {}
|
|
459
|
+
return `t${n}`;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function langToCmd(lang, code) {
|
|
463
|
+
if (lang === 'nodejs' || lang === 'js' || lang === 'javascript' || lang === 'node') return { cmd: process.execPath, args: ['-e', code], stdinCode: null };
|
|
464
|
+
if (lang === 'python' || lang === 'py') return { cmd: 'python', args: ['-c', code], stdinCode: null };
|
|
465
|
+
if (lang === 'bash' || lang === 'sh' || lang === 'shell' || lang === 'zsh') return { cmd: 'bash', args: ['-c', code], stdinCode: null };
|
|
466
|
+
if (lang === 'powershell' || lang === 'ps1') return { cmd: 'powershell', args: ['-NoProfile', '-NonInteractive', '-Command', code], stdinCode: null };
|
|
467
|
+
if (lang === 'deno') return { cmd: 'deno', args: ['eval', code], stdinCode: null };
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function spawnTask({ cwd, lang, code, timeoutMs }) {
|
|
472
|
+
const id = nextTaskId(cwd);
|
|
473
|
+
const built = langToCmd(lang, code);
|
|
474
|
+
if (!built) return { ok: false, error: `unsupported lang: ${lang}` };
|
|
475
|
+
const outLog = taskOutPath(cwd, id, 'stdout');
|
|
476
|
+
const errLog = taskOutPath(cwd, id, 'stderr');
|
|
477
|
+
let outFd = null, errFd = null;
|
|
478
|
+
try { outFd = fs.openSync(outLog, 'a'); } catch (_) {}
|
|
479
|
+
try { errFd = fs.openSync(errLog, 'a'); } catch (_) {}
|
|
480
|
+
const startedMs = Date.now();
|
|
481
|
+
const isPosix = process.platform !== 'win32';
|
|
482
|
+
const child = spawn(built.cmd, built.args, {
|
|
483
|
+
cwd: cwd || process.cwd(),
|
|
484
|
+
detached: isPosix,
|
|
485
|
+
stdio: ['ignore', outFd || 'ignore', errFd || 'ignore'],
|
|
486
|
+
windowsHide: true,
|
|
487
|
+
env: process.env,
|
|
488
|
+
});
|
|
489
|
+
try { if (outFd !== null) fs.closeSync(outFd); } catch (_) {}
|
|
490
|
+
try { if (errFd !== null) fs.closeSync(errFd); } catch (_) {}
|
|
491
|
+
const meta = {
|
|
492
|
+
id,
|
|
493
|
+
pid: child.pid,
|
|
494
|
+
pgid: isPosix ? child.pid : null,
|
|
495
|
+
lang,
|
|
496
|
+
cmd: built.cmd,
|
|
497
|
+
cwd: cwd || process.cwd(),
|
|
498
|
+
started_ms: startedMs,
|
|
499
|
+
timeout_ms: timeoutMs,
|
|
500
|
+
deadline_ms: startedMs + timeoutMs,
|
|
501
|
+
status: 'running',
|
|
502
|
+
exit_code: null,
|
|
503
|
+
stdout_log: outLog,
|
|
504
|
+
stderr_log: errLog,
|
|
505
|
+
};
|
|
506
|
+
__tasks.set(id, { child, meta });
|
|
507
|
+
writeTaskMeta(cwd, id, meta);
|
|
508
|
+
child.on('exit', (code, signal) => {
|
|
509
|
+
meta.status = signal ? 'killed' : (code === 0 ? 'completed' : 'failed');
|
|
510
|
+
meta.exit_code = code;
|
|
511
|
+
meta.signal = signal;
|
|
512
|
+
meta.ended_ms = Date.now();
|
|
513
|
+
writeTaskMeta(meta.cwd, id, meta);
|
|
514
|
+
});
|
|
515
|
+
child.on('error', (err) => {
|
|
516
|
+
meta.status = 'error';
|
|
517
|
+
meta.error = err.message;
|
|
518
|
+
meta.ended_ms = Date.now();
|
|
519
|
+
writeTaskMeta(meta.cwd, id, meta);
|
|
520
|
+
});
|
|
521
|
+
logEvent('plugkit', 'task.spawn', { task_id: id, pid: child.pid, lang, timeout_ms: timeoutMs });
|
|
522
|
+
return { ok: true, task_id: id, pid: child.pid, started_ms: startedMs };
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function stopTaskById(id) {
|
|
526
|
+
const entry = __tasks.get(id);
|
|
527
|
+
if (!entry) {
|
|
528
|
+
return { ok: false, error: 'unknown task_id', task_id: id };
|
|
529
|
+
}
|
|
530
|
+
const { child, meta } = entry;
|
|
531
|
+
if (meta.status !== 'running') return { ok: true, already: meta.status, task_id: id };
|
|
532
|
+
const pid = meta.pid;
|
|
533
|
+
const isPosix = process.platform !== 'win32';
|
|
534
|
+
try {
|
|
535
|
+
if (isPosix && meta.pgid) {
|
|
536
|
+
try { process.kill(-meta.pgid, 'SIGTERM'); } catch (_) {}
|
|
537
|
+
} else {
|
|
538
|
+
try { child.kill('SIGTERM'); } catch (_) {}
|
|
539
|
+
}
|
|
540
|
+
} catch (_) {}
|
|
541
|
+
const graceTimer = setTimeout(() => {
|
|
542
|
+
if (meta.status !== 'running') return;
|
|
543
|
+
if (isPosix && meta.pgid) {
|
|
544
|
+
try { process.kill(-meta.pgid, 'SIGKILL'); } catch (_) {}
|
|
545
|
+
} else if (process.platform === 'win32') {
|
|
546
|
+
try { spawnSync('taskkill', ['/F', '/T', '/PID', String(pid)], { stdio: 'ignore', timeout: 3000 }); } catch (_) {}
|
|
547
|
+
} else {
|
|
548
|
+
try { child.kill('SIGKILL'); } catch (_) {}
|
|
549
|
+
}
|
|
550
|
+
}, 2000);
|
|
551
|
+
graceTimer.unref && graceTimer.unref();
|
|
552
|
+
logEvent('plugkit', 'task.stop', { task_id: id, pid });
|
|
553
|
+
return { ok: true, task_id: id, pid };
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function tailFile(filePath, maxBytes) {
|
|
557
|
+
try {
|
|
558
|
+
const stat = fs.statSync(filePath);
|
|
559
|
+
if (stat.size <= maxBytes) return fs.readFileSync(filePath, 'utf-8');
|
|
560
|
+
const fd = fs.openSync(filePath, 'r');
|
|
561
|
+
try {
|
|
562
|
+
const buf = Buffer.alloc(maxBytes);
|
|
563
|
+
fs.readSync(fd, buf, 0, maxBytes, stat.size - maxBytes);
|
|
564
|
+
return buf.toString('utf-8');
|
|
565
|
+
} finally { try { fs.closeSync(fd); } catch (_) {} }
|
|
566
|
+
} catch (_) { return ''; }
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function listTasks(cwd) {
|
|
570
|
+
const d = tasksDir(cwd);
|
|
571
|
+
const out = [];
|
|
572
|
+
try {
|
|
573
|
+
for (const entry of fs.readdirSync(d)) {
|
|
574
|
+
if (!entry.endsWith('.json') || entry.startsWith('.')) continue;
|
|
575
|
+
try {
|
|
576
|
+
const meta = JSON.parse(fs.readFileSync(path.join(d, entry), 'utf-8'));
|
|
577
|
+
out.push(meta);
|
|
578
|
+
} catch (_) {}
|
|
579
|
+
}
|
|
580
|
+
} catch (_) {}
|
|
581
|
+
return out;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function reapTimedOutTasks() {
|
|
585
|
+
const now = Date.now();
|
|
586
|
+
for (const [id, entry] of __tasks) {
|
|
587
|
+
const m = entry.meta;
|
|
588
|
+
if (m.status === 'running' && m.deadline_ms && now > m.deadline_ms) {
|
|
589
|
+
logEvent('plugkit', 'task.timeout', { task_id: id, pid: m.pid, deadline_ms: m.deadline_ms, now_ms: now });
|
|
590
|
+
stopTaskById(id);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function killAllTasks(reason) {
|
|
596
|
+
let killed = 0;
|
|
597
|
+
for (const [id, entry] of __tasks) {
|
|
598
|
+
if (entry.meta.status === 'running') {
|
|
599
|
+
stopTaskById(id);
|
|
600
|
+
killed += 1;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (killed > 0) logEvent('plugkit', 'task.killAll', { reason, count: killed });
|
|
604
|
+
return killed;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function hostTaskProc(action, params) {
|
|
608
|
+
switch (action) {
|
|
609
|
+
case 'spawn': return spawnTask(params);
|
|
610
|
+
case 'stop': return stopTaskById(params.id || params.task_id);
|
|
611
|
+
case 'list': return { ok: true, tasks: listTasks(params.cwd) };
|
|
612
|
+
case 'output': return {
|
|
613
|
+
ok: true,
|
|
614
|
+
task_id: params.id || params.task_id,
|
|
615
|
+
stdout: tailFile(taskOutPath(params.cwd, params.id || params.task_id, 'stdout'), params.max_bytes || 65536),
|
|
616
|
+
stderr: tailFile(taskOutPath(params.cwd, params.id || params.task_id, 'stderr'), params.max_bytes || 65536),
|
|
617
|
+
};
|
|
618
|
+
case 'reap': { reapTimedOutTasks(); return { ok: true }; }
|
|
619
|
+
case 'killAll': { const n = killAllTasks(params.reason || 'host_task_proc'); return { ok: true, killed: n }; }
|
|
620
|
+
default: return { ok: false, error: `unknown action: ${action}` };
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
438
624
|
function makeHostFunctions(instanceRef) {
|
|
439
625
|
return {
|
|
440
626
|
host_fs_read: (pathPtr, pathLen) => {
|
|
@@ -713,6 +899,19 @@ function makeHostFunctions(instanceRef) {
|
|
|
713
899
|
return 0n;
|
|
714
900
|
}
|
|
715
901
|
},
|
|
902
|
+
|
|
903
|
+
host_task_proc: (actionPtr, actionLen, paramsPtr, paramsLen) => {
|
|
904
|
+
try {
|
|
905
|
+
const action = readWasmStr(instanceRef.value, actionPtr, actionLen);
|
|
906
|
+
const paramsStr = readWasmStr(instanceRef.value, paramsPtr, paramsLen);
|
|
907
|
+
const params = paramsStr ? JSON.parse(paramsStr) : {};
|
|
908
|
+
if (!params.cwd) params.cwd = process.cwd();
|
|
909
|
+
const result = hostTaskProc(action, params);
|
|
910
|
+
return writeWasmJson(instanceRef.value, result);
|
|
911
|
+
} catch (e) {
|
|
912
|
+
return writeWasmJson(instanceRef.value, { ok: false, error: e.message });
|
|
913
|
+
}
|
|
914
|
+
},
|
|
716
915
|
};
|
|
717
916
|
}
|
|
718
917
|
|
|
@@ -797,6 +996,8 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
797
996
|
console.log(`[plugkit-wasm] teardown reason=${reason}`);
|
|
798
997
|
} catch (_) {}
|
|
799
998
|
|
|
999
|
+
try { killAllTasks(`teardown:${reason}`); } catch (_) {}
|
|
1000
|
+
|
|
800
1001
|
try {
|
|
801
1002
|
if (fs.existsSync(ACPTOAPI_STATUS_PATH)) {
|
|
802
1003
|
const status = JSON.parse(fs.readFileSync(ACPTOAPI_STATUS_PATH, 'utf-8'));
|
|
@@ -830,6 +1031,10 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
830
1031
|
process.exit(0);
|
|
831
1032
|
}
|
|
832
1033
|
|
|
1034
|
+
setInterval(() => {
|
|
1035
|
+
try { reapTimedOutTasks(); } catch (_) {}
|
|
1036
|
+
}, 5000);
|
|
1037
|
+
|
|
833
1038
|
setInterval(() => {
|
|
834
1039
|
try {
|
|
835
1040
|
const idleMs = Date.now() - lastActivityMs;
|
|
@@ -842,6 +1047,13 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
842
1047
|
}
|
|
843
1048
|
if (browserAlive) { markActivity('browser-port-alive'); return; }
|
|
844
1049
|
} catch (_) {}
|
|
1050
|
+
try {
|
|
1051
|
+
let anyRunning = false;
|
|
1052
|
+
for (const entry of __tasks.values()) {
|
|
1053
|
+
if (entry.meta.status === 'running') { anyRunning = true; break; }
|
|
1054
|
+
}
|
|
1055
|
+
if (anyRunning) { markActivity('task-running'); return; }
|
|
1056
|
+
} catch (_) {}
|
|
845
1057
|
teardownAll('idle');
|
|
846
1058
|
} catch (e) {
|
|
847
1059
|
console.error(`[idle-check] error: ${e.message}`);
|
package/gm.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1159",
|
|
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.418"
|
|
21
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1159",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"gm.json"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"gm-plugkit": "^2.0.
|
|
42
|
+
"gm-plugkit": "^2.0.1159"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=16.0.0"
|