gm-skill 2.0.1979 → 2.0.1980
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/package.json +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +49 -749
- package/gm.json +1 -1
- package/package.json +1 -1
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.1980",
|
|
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": {
|
|
@@ -17,6 +17,20 @@ const _sharedLogEvent = _gmLog.logEvent;
|
|
|
17
17
|
const _sharedGmLogRoot = _gmLog.GM_LOG_ROOT;
|
|
18
18
|
import _gmProcess from './gm-process.js';
|
|
19
19
|
const _sharedPidCommandLine = _gmProcess.pidCommandLineForKillGuard;
|
|
20
|
+
import { wasiFilesystemRootFor, createWasiShim } from './wrapper/wasi-shim.js';
|
|
21
|
+
import {
|
|
22
|
+
guardWasmRange,
|
|
23
|
+
decodeWasmResult,
|
|
24
|
+
writeWasmInput,
|
|
25
|
+
readWasmBytes,
|
|
26
|
+
readWasmStr,
|
|
27
|
+
writeWasmBytes,
|
|
28
|
+
writeWasmStr,
|
|
29
|
+
writeWasmJson,
|
|
30
|
+
} from './wrapper/wasm-bridge.js';
|
|
31
|
+
import { atomicWriteRaw, atomicWriteJson, readJsonFile, writeJsonFile } from './wrapper/fs-atomic.js';
|
|
32
|
+
import { safeName, projectKvDir, enabledDisciplineNamespaces, jaccardOverlap, makeKvHelpers } from './wrapper/kv-store.js';
|
|
33
|
+
import { makeTaskManager } from './wrapper/task-manager.js';
|
|
20
34
|
|
|
21
35
|
let _writeStatusBusy = () => {};
|
|
22
36
|
let _lastBusyUntil = 0;
|
|
@@ -612,21 +626,6 @@ function stampBrowserLastUse(cwd, claudeSessionId) {
|
|
|
612
626
|
} catch (_) {}
|
|
613
627
|
}
|
|
614
628
|
|
|
615
|
-
function atomicWriteRaw(filePath, data) {
|
|
616
|
-
const tmp = filePath + '.tmp.' + process.pid + '.' + Date.now() + '.' + Math.random().toString(36).slice(2, 8);
|
|
617
|
-
fs.writeFileSync(tmp, data);
|
|
618
|
-
try {
|
|
619
|
-
fs.renameSync(tmp, filePath);
|
|
620
|
-
} catch (err) {
|
|
621
|
-
try { fs.unlinkSync(tmp); } catch (_) {}
|
|
622
|
-
throw err;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
function atomicWriteJson(filePath, obj) {
|
|
627
|
-
atomicWriteRaw(filePath, JSON.stringify(obj, null, 2));
|
|
628
|
-
}
|
|
629
|
-
|
|
630
629
|
function migrateLegacyBrowserState(cwd) {
|
|
631
630
|
const dst1 = browserPortsFile(cwd);
|
|
632
631
|
const dst2 = browserSessionsFile(cwd);
|
|
@@ -653,13 +652,6 @@ function migrateLegacyBrowserState(cwd) {
|
|
|
653
652
|
} catch (_) {}
|
|
654
653
|
}
|
|
655
654
|
|
|
656
|
-
function readJsonFile(fp, fallback) {
|
|
657
|
-
try { return JSON.parse(fs.readFileSync(fp, 'utf-8')); } catch (_) { return fallback; }
|
|
658
|
-
}
|
|
659
|
-
function writeJsonFile(fp, value) {
|
|
660
|
-
try { atomicWriteJson(fp, value); } catch (_) {}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
655
|
const AGGREGATE_CPU_PROFILE_SRC = `function aggregateCpuProfile(profile, topN, isBrowserCtx) {
|
|
664
656
|
const N = topN || 20;
|
|
665
657
|
if (!profile || !Array.isArray(profile.nodes) || !Array.isArray(profile.samples)) {
|
|
@@ -1772,737 +1764,45 @@ function cosineSim(a, b) {
|
|
|
1772
1764
|
}
|
|
1773
1765
|
|
|
1774
1766
|
let __wasmAbortFlag = { aborted: false, code: 0 };
|
|
1775
|
-
const
|
|
1776
|
-
const WASI_FILESYSTEM_ROOT = path.join(GM_TOOLS_ROOT, 'wasi-fs', WASI_PROJECT_SLUG);
|
|
1767
|
+
const WASI_FILESYSTEM_ROOT = wasiFilesystemRootFor(GM_TOOLS_ROOT);
|
|
1777
1768
|
const wasiOpenFiles = new Map();
|
|
1778
1769
|
let wasiNextFd = 100;
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
function createWasiShim(instanceRef) {
|
|
1791
|
-
const getMemory = () => instanceRef.value.exports.memory.buffer;
|
|
1792
|
-
const shim = {
|
|
1793
|
-
proc_exit: (code) => {
|
|
1794
|
-
__wasmAbortFlag.aborted = true;
|
|
1795
|
-
__wasmAbortFlag.code = code;
|
|
1796
|
-
try {
|
|
1797
|
-
const spoolDir = spoolDirForSentinel();
|
|
1798
|
-
fs.mkdirSync(spoolDir, { recursive: true });
|
|
1799
|
-
fs.writeFileSync(path.join(spoolDir, '.wasm-abort.json'), JSON.stringify({
|
|
1800
|
-
ts: Date.now(),
|
|
1801
|
-
exit_code: code,
|
|
1802
|
-
verb_in_flight: __currentVerbContext,
|
|
1803
|
-
}));
|
|
1804
|
-
} catch (_) {}
|
|
1805
|
-
try { console.error(`[plugkit-wasm] wasm proc_exit(${code}) intercepted; throwing to abort current verb without killing watcher`); } catch (_) {}
|
|
1806
|
-
throw new Error(`wasm proc_exit(${code}) during verb ${__currentVerbContext && __currentVerbContext.verb}`);
|
|
1807
|
-
},
|
|
1808
|
-
fd_write: (fd, iovs_ptr, iovs_len, nwritten_ptr) => {
|
|
1809
|
-
try {
|
|
1810
|
-
const buf = getMemory();
|
|
1811
|
-
const dv = new DataView(buf);
|
|
1812
|
-
const chunks = [];
|
|
1813
|
-
let total = 0;
|
|
1814
|
-
const iovsBase = iovs_ptr >>> 0; // >>>0: high-bit iovs pointer is negative in JS -> getUint32 would throw
|
|
1815
|
-
for (let i = 0; i < iovs_len; i++) {
|
|
1816
|
-
const base = iovsBase + i * 8;
|
|
1817
|
-
const ptr = dv.getUint32(base, true);
|
|
1818
|
-
const len = dv.getUint32(base + 4, true);
|
|
1819
|
-
if (len > 0 && ptr + len <= buf.byteLength) {
|
|
1820
|
-
chunks.push(new Uint8Array(buf, ptr, len).slice());
|
|
1821
|
-
total += len;
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
const merged = new Uint8Array(total);
|
|
1825
|
-
let off = 0;
|
|
1826
|
-
for (const c of chunks) { merged.set(c, off); off += c.length; }
|
|
1827
|
-
const text = new TextDecoder('utf-8').decode(merged);
|
|
1828
|
-
if (fd === 2) process.stderr.write(text);
|
|
1829
|
-
else process.stdout.write(text);
|
|
1830
|
-
new DataView(getMemory()).setUint32(nwritten_ptr, total, true);
|
|
1831
|
-
return 0;
|
|
1832
|
-
} catch (e) {
|
|
1833
|
-
return 28;
|
|
1834
|
-
}
|
|
1835
|
-
},
|
|
1836
|
-
random_get: (buf_ptr, buf_len) => {
|
|
1837
|
-
try {
|
|
1838
|
-
crypto.randomFillSync(new Uint8Array(getMemory(), buf_ptr >>> 0, buf_len >>> 0)); // >>>0: high-bit ptr is negative in JS
|
|
1839
|
-
return 0;
|
|
1840
|
-
} catch (e) {
|
|
1841
|
-
return 28;
|
|
1842
|
-
}
|
|
1843
|
-
},
|
|
1844
|
-
clock_time_get: (clock_id, precision, time_ptr) => {
|
|
1845
|
-
try {
|
|
1846
|
-
const ns = BigInt(Date.now()) * 1000000n;
|
|
1847
|
-
new DataView(getMemory()).setBigUint64(time_ptr >>> 0, ns, true); // >>>0: high-bit ptr is negative in JS
|
|
1848
|
-
return 0;
|
|
1849
|
-
} catch (e) {
|
|
1850
|
-
return 28;
|
|
1851
|
-
}
|
|
1852
|
-
},
|
|
1853
|
-
environ_get: () => 0,
|
|
1854
|
-
environ_sizes_get: () => 0,
|
|
1855
|
-
fd_prestat_get: (fd, buf_ptr) => {
|
|
1856
|
-
if (fd !== 3) return 8;
|
|
1857
|
-
try {
|
|
1858
|
-
const dv = new DataView(getMemory());
|
|
1859
|
-
dv.setUint8(buf_ptr, 0);
|
|
1860
|
-
dv.setUint32(buf_ptr + 4, 1, true);
|
|
1861
|
-
return 0;
|
|
1862
|
-
} catch (e) { return 8; }
|
|
1863
|
-
},
|
|
1864
|
-
fd_prestat_dir_name: (fd, path_ptr, path_len) => {
|
|
1865
|
-
if (fd !== 3) return 8;
|
|
1866
|
-
try {
|
|
1867
|
-
const buf = getMemory();
|
|
1868
|
-
new Uint8Array(buf, path_ptr >>> 0, Math.min(path_len, 1)).set([0x2e]);
|
|
1869
|
-
return 0;
|
|
1870
|
-
} catch (e) { return 8; }
|
|
1871
|
-
},
|
|
1872
|
-
fd_close: (fd) => {
|
|
1873
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1874
|
-
if (!entry) return 0;
|
|
1875
|
-
try { fs.closeSync(entry.nodeFd); } catch (_) {}
|
|
1876
|
-
wasiOpenFiles.delete(fd);
|
|
1877
|
-
return 0;
|
|
1878
|
-
},
|
|
1879
|
-
fd_fdstat_get: (fd, stat_ptr) => {
|
|
1880
|
-
try {
|
|
1881
|
-
const dv = new DataView(getMemory());
|
|
1882
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1883
|
-
dv.setUint8(stat_ptr, entry ? 4 : 0);
|
|
1884
|
-
dv.setUint8(stat_ptr + 1, 0);
|
|
1885
|
-
dv.setBigUint64(stat_ptr + 8, 0xffffffffffffffffn, true);
|
|
1886
|
-
dv.setBigUint64(stat_ptr + 16, 0xffffffffffffffffn, true);
|
|
1887
|
-
return 0;
|
|
1888
|
-
} catch (e) { return 8; }
|
|
1889
|
-
},
|
|
1890
|
-
fd_fdstat_set_flags: () => 0,
|
|
1891
|
-
fd_filestat_get: (fd, buf_ptr) => {
|
|
1892
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1893
|
-
if (!entry) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_filestat_get FAILED: no entry for fd=${fd}`); return 8; }
|
|
1894
|
-
try {
|
|
1895
|
-
const st = fs.fstatSync(entry.nodeFd);
|
|
1896
|
-
const dv = new DataView(getMemory());
|
|
1897
|
-
dv.setBigUint64(buf_ptr, 0n, true);
|
|
1898
|
-
dv.setBigUint64(buf_ptr + 8, 0n, true);
|
|
1899
|
-
dv.setUint8(buf_ptr + 16, 4);
|
|
1900
|
-
dv.setBigUint64(buf_ptr + 24, 1n, true);
|
|
1901
|
-
dv.setBigUint64(buf_ptr + 32, BigInt(st.size), true);
|
|
1902
|
-
dv.setBigUint64(buf_ptr + 40, BigInt(Math.floor(st.atimeMs * 1e6)), true);
|
|
1903
|
-
dv.setBigUint64(buf_ptr + 48, BigInt(Math.floor(st.mtimeMs * 1e6)), true);
|
|
1904
|
-
dv.setBigUint64(buf_ptr + 56, BigInt(Math.floor(st.ctimeMs * 1e6)), true);
|
|
1905
|
-
return 0;
|
|
1906
|
-
} catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_filestat_get FAILED: ${e && e.message}`); return 8; }
|
|
1907
|
-
},
|
|
1908
|
-
fd_seek: (fd, offset64, whence, newoffset_ptr) => {
|
|
1909
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1910
|
-
if (!entry) { try { new DataView(getMemory()).setBigUint64(newoffset_ptr, 0n, true); } catch (_) {} return 8; }
|
|
1911
|
-
try {
|
|
1912
|
-
const offset = BigInt.asIntN(64, BigInt(offset64));
|
|
1913
|
-
let base;
|
|
1914
|
-
if (whence === 0) base = 0n;
|
|
1915
|
-
else if (whence === 1) base = BigInt(entry.pos);
|
|
1916
|
-
else base = BigInt(fs.fstatSync(entry.nodeFd).size);
|
|
1917
|
-
const next = base + offset;
|
|
1918
|
-
entry.pos = Number(next < 0n ? 0n : next);
|
|
1919
|
-
new DataView(getMemory()).setBigUint64(newoffset_ptr, BigInt(entry.pos), true);
|
|
1920
|
-
return 0;
|
|
1921
|
-
} catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_seek FAILED: ${e && e.message}`); return 8; }
|
|
1922
|
-
},
|
|
1923
|
-
fd_read: (fd, iovs_ptr, iovs_len, nread_ptr) => {
|
|
1924
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1925
|
-
if (!entry) { try { new DataView(getMemory()).setUint32(nread_ptr, 0, true); } catch (_) {} return 8; }
|
|
1926
|
-
try {
|
|
1927
|
-
const buf = getMemory();
|
|
1928
|
-
const dv = new DataView(buf);
|
|
1929
|
-
let total = 0;
|
|
1930
|
-
const iovsBase = iovs_ptr >>> 0;
|
|
1931
|
-
for (let i = 0; i < iovs_len; i++) {
|
|
1932
|
-
const base = iovsBase + i * 8;
|
|
1933
|
-
const ptr = dv.getUint32(base, true) >>> 0;
|
|
1934
|
-
const len = dv.getUint32(base + 4, true) >>> 0;
|
|
1935
|
-
if (len === 0) continue;
|
|
1936
|
-
const dest = Buffer.from(buf, ptr, len);
|
|
1937
|
-
const n = fs.readSync(entry.nodeFd, dest, 0, len, entry.pos);
|
|
1938
|
-
entry.pos += n;
|
|
1939
|
-
total += n;
|
|
1940
|
-
if (n < len) break;
|
|
1941
|
-
}
|
|
1942
|
-
dv.setUint32(nread_ptr, total, true);
|
|
1943
|
-
return 0;
|
|
1944
|
-
} catch (e) { return 8; }
|
|
1945
|
-
},
|
|
1946
|
-
fd_pread: (fd, iovs_ptr, iovs_len, offset64, nread_ptr) => {
|
|
1947
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1948
|
-
if (!entry) { try { new DataView(getMemory()).setUint32(nread_ptr, 0, true); } catch (_) {} return 8; }
|
|
1949
|
-
try {
|
|
1950
|
-
const offset = Number(BigInt.asUintN(64, BigInt(offset64)));
|
|
1951
|
-
const buf = getMemory();
|
|
1952
|
-
const dv = new DataView(buf);
|
|
1953
|
-
let total = 0;
|
|
1954
|
-
const iovsBase = iovs_ptr >>> 0;
|
|
1955
|
-
let pos = offset;
|
|
1956
|
-
for (let i = 0; i < iovs_len; i++) {
|
|
1957
|
-
const base = iovsBase + i * 8;
|
|
1958
|
-
const ptr = dv.getUint32(base, true) >>> 0;
|
|
1959
|
-
const len = dv.getUint32(base + 4, true) >>> 0;
|
|
1960
|
-
if (len === 0) continue;
|
|
1961
|
-
const dest = Buffer.from(buf, ptr, len);
|
|
1962
|
-
const n = fs.readSync(entry.nodeFd, dest, 0, len, pos);
|
|
1963
|
-
pos += n;
|
|
1964
|
-
total += n;
|
|
1965
|
-
if (n < len) break;
|
|
1966
|
-
}
|
|
1967
|
-
dv.setUint32(nread_ptr, total, true);
|
|
1968
|
-
return 0;
|
|
1969
|
-
} catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_pread FAILED: ${e && e.message}`); return 8; }
|
|
1970
|
-
},
|
|
1971
|
-
fd_pwrite: (fd, iovs_ptr, iovs_len, offset64, nwritten_ptr) => {
|
|
1972
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1973
|
-
if (!entry) { try { new DataView(getMemory()).setUint32(nwritten_ptr, 0, true); } catch (_) {} return 8; }
|
|
1974
|
-
try {
|
|
1975
|
-
const offset = Number(BigInt.asUintN(64, BigInt(offset64)));
|
|
1976
|
-
const buf = getMemory();
|
|
1977
|
-
const dv = new DataView(buf);
|
|
1978
|
-
let total = 0;
|
|
1979
|
-
const iovsBase = iovs_ptr >>> 0;
|
|
1980
|
-
let pos = offset;
|
|
1981
|
-
for (let i = 0; i < iovs_len; i++) {
|
|
1982
|
-
const base = iovsBase + i * 8;
|
|
1983
|
-
const ptr = dv.getUint32(base, true) >>> 0;
|
|
1984
|
-
const len = dv.getUint32(base + 4, true) >>> 0;
|
|
1985
|
-
if (len === 0) continue;
|
|
1986
|
-
const src = Buffer.from(buf, ptr, len);
|
|
1987
|
-
const n = fs.writeSync(entry.nodeFd, src, 0, len, pos);
|
|
1988
|
-
pos += n;
|
|
1989
|
-
total += n;
|
|
1990
|
-
}
|
|
1991
|
-
dv.setUint32(nwritten_ptr, total, true);
|
|
1992
|
-
return 0;
|
|
1993
|
-
} catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_pwrite FAILED: ${e && e.message}`); return 8; }
|
|
1994
|
-
},
|
|
1995
|
-
fd_sync: (fd) => {
|
|
1996
|
-
const entry = wasiOpenFiles.get(fd);
|
|
1997
|
-
if (!entry) return 8;
|
|
1998
|
-
try { fs.fsyncSync(entry.nodeFd); return 0; } catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_sync FAILED: ${e && e.message}`); return 8; }
|
|
1999
|
-
},
|
|
2000
|
-
fd_datasync: (fd) => {
|
|
2001
|
-
const entry = wasiOpenFiles.get(fd);
|
|
2002
|
-
if (!entry) return 8;
|
|
2003
|
-
try { fs.fdatasyncSync(entry.nodeFd); return 0; } catch (e) { return 8; }
|
|
2004
|
-
},
|
|
2005
|
-
fd_filestat_set_size: (fd, size64) => {
|
|
2006
|
-
const entry = wasiOpenFiles.get(fd);
|
|
2007
|
-
if (!entry) return 8;
|
|
2008
|
-
try {
|
|
2009
|
-
const size = Number(BigInt.asUintN(64, BigInt(size64)));
|
|
2010
|
-
fs.ftruncateSync(entry.nodeFd, size);
|
|
2011
|
-
return 0;
|
|
2012
|
-
} catch (e) { if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] fd_filestat_set_size FAILED: ${e && e.message}`); return 8; }
|
|
2013
|
-
},
|
|
2014
|
-
path_create_directory: (_dirfd, path_ptr, path_len) => {
|
|
2015
|
-
try {
|
|
2016
|
-
const buf = getMemory();
|
|
2017
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2018
|
-
const absPath = wasiResolvePath(relPath);
|
|
2019
|
-
fs.mkdirSync(absPath, { recursive: true });
|
|
2020
|
-
return 0;
|
|
2021
|
-
} catch (e) {
|
|
2022
|
-
if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] path_create_directory FAILED: ${e && e.message}`);
|
|
2023
|
-
return e && e.code === 'EEXIST' ? 0 : 8;
|
|
2024
|
-
}
|
|
2025
|
-
},
|
|
2026
|
-
path_unlink_file: (_dirfd, path_ptr, path_len) => {
|
|
2027
|
-
try {
|
|
2028
|
-
const buf = getMemory();
|
|
2029
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2030
|
-
const absPath = wasiResolvePath(relPath);
|
|
2031
|
-
fs.unlinkSync(absPath);
|
|
2032
|
-
return 0;
|
|
2033
|
-
} catch (e) {
|
|
2034
|
-
return e && e.code === 'ENOENT' ? 44 : 8;
|
|
2035
|
-
}
|
|
2036
|
-
},
|
|
2037
|
-
path_remove_directory: (_dirfd, path_ptr, path_len) => {
|
|
2038
|
-
try {
|
|
2039
|
-
const buf = getMemory();
|
|
2040
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2041
|
-
const absPath = wasiResolvePath(relPath);
|
|
2042
|
-
fs.rmdirSync(absPath);
|
|
2043
|
-
return 0;
|
|
2044
|
-
} catch (e) {
|
|
2045
|
-
if (e && e.code === 'ENOENT') return 44;
|
|
2046
|
-
if (e && e.code === 'ENOTEMPTY') return 55;
|
|
2047
|
-
return 8;
|
|
2048
|
-
}
|
|
2049
|
-
},
|
|
2050
|
-
path_filestat_set_times: (_dirfd, _flags, path_ptr, path_len, atim64, mtim64, fst_flags) => {
|
|
2051
|
-
try {
|
|
2052
|
-
const buf = getMemory();
|
|
2053
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2054
|
-
const absPath = wasiResolvePath(relPath);
|
|
2055
|
-
const FILESTAT_SET_ATIM = 0x1, FILESTAT_SET_ATIM_NOW = 0x2, FILESTAT_SET_MTIM = 0x4, FILESTAT_SET_MTIM_NOW = 0x8;
|
|
2056
|
-
const st = fs.statSync(absPath);
|
|
2057
|
-
const nowMs = Date.now();
|
|
2058
|
-
let atimeMs = st.atimeMs;
|
|
2059
|
-
let mtimeMs = st.mtimeMs;
|
|
2060
|
-
if (fst_flags & FILESTAT_SET_ATIM_NOW) atimeMs = nowMs;
|
|
2061
|
-
else if (fst_flags & FILESTAT_SET_ATIM) atimeMs = Number(BigInt.asUintN(64, BigInt(atim64))) / 1e6;
|
|
2062
|
-
if (fst_flags & FILESTAT_SET_MTIM_NOW) mtimeMs = nowMs;
|
|
2063
|
-
else if (fst_flags & FILESTAT_SET_MTIM) mtimeMs = Number(BigInt.asUintN(64, BigInt(mtim64))) / 1e6;
|
|
2064
|
-
fs.utimesSync(absPath, atimeMs / 1000, mtimeMs / 1000);
|
|
2065
|
-
return 0;
|
|
2066
|
-
} catch (e) {
|
|
2067
|
-
if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] path_filestat_set_times FAILED: ${e && e.message}`);
|
|
2068
|
-
return e && e.code === 'ENOENT' ? 44 : 8;
|
|
2069
|
-
}
|
|
2070
|
-
},
|
|
2071
|
-
path_open: (_dirfd, _dirflags, path_ptr, path_len, oflags, _rights_base, _rights_inherit, fdflags, opened_fd_ptr) => {
|
|
2072
|
-
try {
|
|
2073
|
-
const buf = getMemory();
|
|
2074
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2075
|
-
const absPath = wasiResolvePath(relPath);
|
|
2076
|
-
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
2077
|
-
const OFLAGS_CREAT = 1, OFLAGS_EXCL = 2, OFLAGS_TRUNC = 8;
|
|
2078
|
-
let nodeFlags = 'r+';
|
|
2079
|
-
const creat = (oflags & OFLAGS_CREAT) !== 0;
|
|
2080
|
-
const excl = (oflags & OFLAGS_EXCL) !== 0;
|
|
2081
|
-
const trunc = (oflags & OFLAGS_TRUNC) !== 0;
|
|
2082
|
-
if (excl && creat) nodeFlags = 'wx+';
|
|
2083
|
-
else if (trunc) nodeFlags = 'w+';
|
|
2084
|
-
else if (creat) nodeFlags = fs.existsSync(absPath) ? 'r+' : 'w+';
|
|
2085
|
-
else nodeFlags = 'r+';
|
|
2086
|
-
if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] path_open: rel=${relPath} abs=${absPath} oflags=${oflags} nodeFlags=${nodeFlags}`);
|
|
2087
|
-
const nodeFd = fs.openSync(absPath, nodeFlags);
|
|
2088
|
-
const wasiFd = wasiNextFd++;
|
|
2089
|
-
wasiOpenFiles.set(wasiFd, { nodeFd, pos: 0, path: absPath });
|
|
2090
|
-
new DataView(buf).setUint32(opened_fd_ptr, wasiFd, true);
|
|
2091
|
-
return 0;
|
|
2092
|
-
} catch (e) {
|
|
2093
|
-
if (process.env.PLUGKIT_DEBUG) console.error(`[plugkit-wasm] path_open FAILED: ${e && e.message}`);
|
|
2094
|
-
return e && /ENOENT/.test(e.code || '') ? 44 : 8;
|
|
2095
|
-
}
|
|
2096
|
-
},
|
|
2097
|
-
path_filestat_get: (_dirfd, _flags, path_ptr, path_len, buf_ptr) => {
|
|
2098
|
-
try {
|
|
2099
|
-
const buf = getMemory();
|
|
2100
|
-
const relPath = new TextDecoder('utf-8').decode(new Uint8Array(buf, path_ptr >>> 0, path_len >>> 0));
|
|
2101
|
-
const absPath = wasiResolvePath(relPath);
|
|
2102
|
-
const st = fs.statSync(absPath);
|
|
2103
|
-
const dv = new DataView(buf);
|
|
2104
|
-
dv.setBigUint64(buf_ptr, 0n, true);
|
|
2105
|
-
dv.setBigUint64(buf_ptr + 8, 0n, true);
|
|
2106
|
-
dv.setUint8(buf_ptr + 16, st.isDirectory() ? 3 : 4);
|
|
2107
|
-
dv.setBigUint64(buf_ptr + 24, 1n, true);
|
|
2108
|
-
dv.setBigUint64(buf_ptr + 32, BigInt(st.size), true);
|
|
2109
|
-
dv.setBigUint64(buf_ptr + 40, BigInt(Math.floor(st.atimeMs * 1e6)), true);
|
|
2110
|
-
dv.setBigUint64(buf_ptr + 48, BigInt(Math.floor(st.mtimeMs * 1e6)), true);
|
|
2111
|
-
dv.setBigUint64(buf_ptr + 56, BigInt(Math.floor(st.ctimeMs * 1e6)), true);
|
|
2112
|
-
return 0;
|
|
2113
|
-
} catch (e) {
|
|
2114
|
-
return e && /ENOENT/.test(e.code || '') ? 44 : 8;
|
|
2115
|
-
}
|
|
2116
|
-
},
|
|
2117
|
-
poll_oneoff: () => 0,
|
|
2118
|
-
sched_yield: () => 0,
|
|
2119
|
-
};
|
|
2120
|
-
if (process.env.PLUGKIT_DEBUG_WASI) {
|
|
2121
|
-
for (const k of Object.keys(shim)) {
|
|
2122
|
-
const orig = shim[k];
|
|
2123
|
-
shim[k] = (...args) => {
|
|
2124
|
-
const r = orig(...args);
|
|
2125
|
-
try { console.error(`[plugkit-wasm] wasi.${k}(${args.map(a => typeof a === 'bigint' ? a.toString() : a).join(',')}) -> ${r}`); } catch (_) {}
|
|
2126
|
-
return r;
|
|
2127
|
-
};
|
|
2128
|
-
}
|
|
2129
|
-
}
|
|
2130
|
-
return new Proxy(shim, {
|
|
2131
|
-
get(target, prop) {
|
|
2132
|
-
if (prop in target) return target[prop];
|
|
2133
|
-
return (...args) => {
|
|
2134
|
-
console.error(`[plugkit-wasm] unimplemented WASI call: ${String(prop)} args=${args.length}`);
|
|
2135
|
-
return 8;
|
|
2136
|
-
};
|
|
2137
|
-
}
|
|
2138
|
-
});
|
|
2139
|
-
}
|
|
2140
|
-
|
|
2141
|
-
function guardWasmRange(buffer, ptr, len, where) {
|
|
2142
|
-
const total = buffer.byteLength;
|
|
2143
|
-
if (!Number.isInteger(ptr) || !Number.isInteger(len) || ptr < 0 || len < 0 || ptr + len > total) {
|
|
2144
|
-
throw new Error(`wasm-memory-read-out-of-bounds at ${where}: ptr=${ptr} len=${len} buffer=${total} -- corrupt (ptr,len) from wasm, refusing the read instead of crashing the dispatch loop`);
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
function decodeWasmResult(instance, result, where) {
|
|
2149
|
-
const u = BigInt.asUintN(64, BigInt(result));
|
|
2150
|
-
const ptr = Number(u & 0xffffffffn);
|
|
2151
|
-
const len = Number(u >> 32n);
|
|
2152
|
-
if (ptr === 0 || len === 0) return '';
|
|
2153
|
-
const buffer = instance.exports.memory.buffer;
|
|
2154
|
-
guardWasmRange(buffer, ptr, len, where);
|
|
2155
|
-
const out = new TextDecoder().decode(new Uint8Array(buffer, ptr, len));
|
|
2156
|
-
try { instance.exports.plugkit_free(ptr, len); } catch (_) {}
|
|
2157
|
-
return out;
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2160
|
-
function writeWasmInput(instance, bytes, where) {
|
|
2161
|
-
if (bytes.length === 0) return 0;
|
|
2162
|
-
const ptr = instance.exports.plugkit_alloc(bytes.length) >>> 0;
|
|
2163
|
-
if (ptr === 0) throw new Error(`wasm-alloc-failed at ${where}: plugkit_alloc returned 0 (wasm OOM)`);
|
|
2164
|
-
guardWasmRange(instance.exports.memory.buffer, ptr, bytes.length, `${where}:writeWasmInput`);
|
|
2165
|
-
new Uint8Array(instance.exports.memory.buffer, ptr, bytes.length).set(bytes);
|
|
2166
|
-
return ptr;
|
|
2167
|
-
}
|
|
2168
|
-
|
|
2169
|
-
function readWasmBytes(instance, ptr, len) {
|
|
2170
|
-
if (ptr === 0 || len === 0) return new Uint8Array(0);
|
|
2171
|
-
const buffer = instance.exports.memory.buffer;
|
|
2172
|
-
guardWasmRange(buffer, ptr, len, 'readWasmBytes');
|
|
2173
|
-
return new Uint8Array(buffer, ptr, len).slice();
|
|
2174
|
-
}
|
|
2175
|
-
|
|
2176
|
-
function readWasmStr(instance, ptr, len) {
|
|
2177
|
-
if (ptr === 0 || len === 0) return '';
|
|
2178
|
-
const buffer = instance.exports.memory.buffer;
|
|
2179
|
-
guardWasmRange(buffer, ptr, len, 'readWasmStr');
|
|
2180
|
-
const bytes = new Uint8Array(buffer, ptr, len);
|
|
2181
|
-
return new TextDecoder('utf-8').decode(bytes);
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
function writeWasmBytes(instance, bytes) {
|
|
2185
|
-
if (bytes.length === 0) return 0n;
|
|
2186
|
-
const ptr = instance.exports.plugkit_alloc(bytes.length) >>> 0;
|
|
2187
|
-
if (ptr === 0) return 0n;
|
|
2188
|
-
guardWasmRange(instance.exports.memory.buffer, ptr, bytes.length, 'writeWasmBytes');
|
|
2189
|
-
new Uint8Array(instance.exports.memory.buffer, ptr, bytes.length).set(bytes);
|
|
2190
|
-
return (BigInt(ptr) & 0xffffffffn) | (BigInt(bytes.length) << 32n);
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
function writeWasmStr(instance, str) {
|
|
2194
|
-
if (!str) return 0n;
|
|
2195
|
-
return writeWasmBytes(instance, new TextEncoder().encode(str));
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
function writeWasmJson(instance, value) {
|
|
2199
|
-
return writeWasmStr(instance, JSON.stringify(value));
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
function safeName(s) { return String(s).replace(/[^A-Za-z0-9._-]/g, '_'); }
|
|
2203
|
-
|
|
2204
|
-
function projectKvDir(ns) {
|
|
2205
|
-
const projectRoot = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
2206
|
-
return path.join(projectRoot, '.gm', 'disciplines', safeName(ns));
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
function legacyKvDir(ns) {
|
|
2210
|
-
return path.join(KV_DIR, safeName(ns));
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
function kvFilePath(ns, key, ensureDir) {
|
|
2214
|
-
const dir = projectKvDir(ns);
|
|
2215
|
-
if (ensureDir) fs.mkdirSync(dir, { recursive: true });
|
|
2216
|
-
return path.join(dir, safeName(key) + '.json');
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
function kvReadResolve(ns, key) {
|
|
2220
|
-
const fp = kvFilePath(ns, key);
|
|
2221
|
-
if (fs.existsSync(fp)) return fp;
|
|
2222
|
-
const legacy = path.join(legacyKvDir(ns), safeName(key) + '.json');
|
|
2223
|
-
if (fs.existsSync(legacy)) return legacy;
|
|
2224
|
-
return null;
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
function kvNamespaceDirs(ns) {
|
|
2228
|
-
const out = [];
|
|
2229
|
-
const proj = projectKvDir(ns);
|
|
2230
|
-
if (fs.existsSync(proj)) out.push(proj);
|
|
2231
|
-
const legacy = legacyKvDir(ns);
|
|
2232
|
-
if (fs.existsSync(legacy)) out.push(legacy);
|
|
2233
|
-
return out;
|
|
2234
|
-
}
|
|
2235
|
-
|
|
2236
|
-
function enabledDisciplineNamespaces(baseNs) {
|
|
2237
|
-
const projectRoot = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
2238
|
-
const set = new Set([baseNs]);
|
|
2239
|
-
try {
|
|
2240
|
-
const enabledPath = path.join(projectRoot, '.gm', 'disciplines', 'enabled.txt');
|
|
2241
|
-
if (fs.existsSync(enabledPath)) {
|
|
2242
|
-
const lines = fs.readFileSync(enabledPath, 'utf-8').split(/\r?\n/);
|
|
2243
|
-
for (const ln of lines) {
|
|
2244
|
-
const name = ln.trim();
|
|
2245
|
-
if (name && !name.startsWith('#')) set.add(name);
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
} catch (_) {}
|
|
2249
|
-
return Array.from(set);
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
function jaccardOverlap(a, b) {
|
|
2253
|
-
if (!a || !b) return 0;
|
|
2254
|
-
const tokenize = (s) => new Set(String(s).toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length >= 3));
|
|
2255
|
-
const A = tokenize(a), B = tokenize(b);
|
|
2256
|
-
if (A.size === 0 || B.size === 0) return 0;
|
|
2257
|
-
let inter = 0;
|
|
2258
|
-
for (const t of A) if (B.has(t)) inter++;
|
|
2259
|
-
return inter / (A.size + B.size - inter);
|
|
2260
|
-
}
|
|
2261
|
-
|
|
2262
|
-
const __tasks = new Map();
|
|
2263
|
-
|
|
2264
|
-
function tasksDir(cwd) {
|
|
2265
|
-
const d = path.join(cwd || process.cwd(), '.gm', 'exec-spool', 'tasks');
|
|
2266
|
-
try { fs.mkdirSync(d, { recursive: true }); } catch (_) {}
|
|
2267
|
-
return d;
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
function taskMetaPath(cwd, id) { return path.join(tasksDir(cwd), `${id}.json`); }
|
|
2271
|
-
function taskOutPath(cwd, id, which) { return path.join(tasksDir(cwd), `${id}.${which}.log`); }
|
|
2272
|
-
|
|
2273
|
-
function writeTaskMeta(cwd, id, meta) {
|
|
2274
|
-
try { fs.writeFileSync(taskMetaPath(cwd, id), JSON.stringify(meta, null, 2)); } catch (_) {}
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
function nextTaskId(cwd) {
|
|
2278
|
-
const counterPath = path.join(tasksDir(cwd), '.counter');
|
|
2279
|
-
let n = 0;
|
|
2280
|
-
try { n = parseInt(fs.readFileSync(counterPath, 'utf-8'), 10) || 0; } catch (_) {}
|
|
2281
|
-
n += 1;
|
|
2282
|
-
try { fs.writeFileSync(counterPath, String(n)); } catch (_) {}
|
|
2283
|
-
return `t${n}`;
|
|
2284
|
-
}
|
|
2285
|
-
|
|
2286
|
-
let _jsRuntimeCmd = null;
|
|
2287
|
-
function resolveJsRuntimeCmd() {
|
|
2288
|
-
if (_jsRuntimeCmd) return _jsRuntimeCmd;
|
|
2289
|
-
if (!/(^|[\\/])node(\.exe)?$/i.test(String(process.execPath || ''))) {
|
|
2290
|
-
_jsRuntimeCmd = process.execPath;
|
|
2291
|
-
return _jsRuntimeCmd;
|
|
2292
|
-
}
|
|
2293
|
-
try {
|
|
2294
|
-
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
2295
|
-
const out = spawnSync(which, ['bun'], { encoding: 'utf-8', windowsHide: true });
|
|
2296
|
-
const first = (out && out.stdout || '').split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
2297
|
-
if (first) { _jsRuntimeCmd = first; return _jsRuntimeCmd; }
|
|
2298
|
-
} catch (_) {}
|
|
2299
|
-
_jsRuntimeCmd = process.execPath;
|
|
2300
|
-
return _jsRuntimeCmd;
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
function langToCmd(lang, code) {
|
|
2304
|
-
if (lang === 'nodejs' || lang === 'js' || lang === 'javascript' || lang === 'node') return { cmd: resolveJsRuntimeCmd(), args: ['-e', code], stdinCode: null };
|
|
2305
|
-
if (lang === 'python' || lang === 'py') return { cmd: 'python', args: ['-c', code], stdinCode: null };
|
|
2306
|
-
if (lang === 'bash' || lang === 'sh' || lang === 'shell' || lang === 'zsh') return { cmd: 'bash', args: ['-c', code], stdinCode: null };
|
|
2307
|
-
if (lang === 'powershell' || lang === 'ps1') return { cmd: 'powershell', args: ['-NoProfile', '-NonInteractive', '-Command', code], stdinCode: null };
|
|
2308
|
-
if (lang === 'deno') return { cmd: 'deno', args: ['eval', code], stdinCode: null };
|
|
2309
|
-
return null;
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
|
-
const TASK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
|
|
2313
|
-
|
|
2314
|
-
function spawnTask({ cwd, lang, code, timeoutMs }) {
|
|
2315
|
-
const id = nextTaskId(cwd);
|
|
2316
|
-
const built = langToCmd(lang, code);
|
|
2317
|
-
if (!built) return { ok: false, error: `unsupported lang: ${lang}` };
|
|
2318
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > TASK_MAX_TIMEOUT_MS) {
|
|
2319
|
-
timeoutMs = TASK_MAX_TIMEOUT_MS;
|
|
2320
|
-
}
|
|
2321
|
-
const outLog = taskOutPath(cwd, id, 'stdout');
|
|
2322
|
-
const errLog = taskOutPath(cwd, id, 'stderr');
|
|
2323
|
-
let outFd = null, errFd = null;
|
|
2324
|
-
try { outFd = fs.openSync(outLog, 'a'); } catch (_) {}
|
|
2325
|
-
try { errFd = fs.openSync(errLog, 'a'); } catch (_) {}
|
|
2326
|
-
const startedMs = Date.now();
|
|
2327
|
-
const isPosix = process.platform !== 'win32';
|
|
2328
|
-
const child = spawn(built.cmd, built.args, {
|
|
2329
|
-
cwd: cwd || process.cwd(),
|
|
2330
|
-
detached: isPosix,
|
|
2331
|
-
stdio: ['ignore', outFd || 'ignore', errFd || 'ignore'],
|
|
2332
|
-
windowsHide: true,
|
|
2333
|
-
env: process.env,
|
|
1770
|
+
const __wasiNextFdRef = { get value() { return wasiNextFd; }, set value(v) { wasiNextFd = v; } };
|
|
1771
|
+
const __currentVerbContextRef = { get value() { return __currentVerbContext; } };
|
|
1772
|
+
function __createWasiShimBound(instanceRef) {
|
|
1773
|
+
return createWasiShim(instanceRef, {
|
|
1774
|
+
wasiFilesystemRoot: WASI_FILESYSTEM_ROOT,
|
|
1775
|
+
wasiOpenFiles,
|
|
1776
|
+
wasiNextFdRef: __wasiNextFdRef,
|
|
1777
|
+
wasmAbortFlag: __wasmAbortFlag,
|
|
1778
|
+
spoolDirForSentinel,
|
|
1779
|
+
currentVerbContextRef: __currentVerbContextRef,
|
|
2334
1780
|
});
|
|
2335
|
-
try { if (outFd !== null) fs.closeSync(outFd); } catch (_) {}
|
|
2336
|
-
try { if (errFd !== null) fs.closeSync(errFd); } catch (_) {}
|
|
2337
|
-
const meta = {
|
|
2338
|
-
id,
|
|
2339
|
-
pid: child.pid,
|
|
2340
|
-
pgid: isPosix ? child.pid : null,
|
|
2341
|
-
lang,
|
|
2342
|
-
cmd: built.cmd,
|
|
2343
|
-
cwd: cwd || process.cwd(),
|
|
2344
|
-
started_ms: startedMs,
|
|
2345
|
-
timeout_ms: timeoutMs,
|
|
2346
|
-
deadline_ms: startedMs + timeoutMs,
|
|
2347
|
-
status: 'running',
|
|
2348
|
-
exit_code: null,
|
|
2349
|
-
stdout_log: outLog,
|
|
2350
|
-
stderr_log: errLog,
|
|
2351
|
-
};
|
|
2352
|
-
__tasks.set(id, { child, meta });
|
|
2353
|
-
writeTaskMeta(cwd, id, meta);
|
|
2354
|
-
child.on('exit', (code, signal) => {
|
|
2355
|
-
meta.status = signal ? 'killed' : (code === 0 ? 'completed' : 'failed');
|
|
2356
|
-
meta.exit_code = code;
|
|
2357
|
-
meta.signal = signal;
|
|
2358
|
-
meta.ended_ms = Date.now();
|
|
2359
|
-
writeTaskMeta(meta.cwd, id, meta);
|
|
2360
|
-
});
|
|
2361
|
-
child.on('error', (err) => {
|
|
2362
|
-
meta.status = 'error';
|
|
2363
|
-
meta.error = err.message;
|
|
2364
|
-
meta.ended_ms = Date.now();
|
|
2365
|
-
writeTaskMeta(meta.cwd, id, meta);
|
|
2366
|
-
});
|
|
2367
|
-
logEvent('plugkit', 'task.spawn', { task_id: id, pid: child.pid, lang, timeout_ms: timeoutMs });
|
|
2368
|
-
return { ok: true, task_id: id, pid: child.pid, started_ms: startedMs };
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
function stopTaskById(id) {
|
|
2372
|
-
const entry = __tasks.get(id);
|
|
2373
|
-
if (!entry) {
|
|
2374
|
-
return { ok: false, error: 'unknown task_id', task_id: id };
|
|
2375
|
-
}
|
|
2376
|
-
const { child, meta } = entry;
|
|
2377
|
-
if (meta.status !== 'running') return { ok: true, already: meta.status, task_id: id };
|
|
2378
|
-
const pid = meta.pid;
|
|
2379
|
-
const isPosix = process.platform !== 'win32';
|
|
2380
|
-
try {
|
|
2381
|
-
if (isPosix && meta.pgid) {
|
|
2382
|
-
try { process.kill(-meta.pgid, 'SIGTERM'); } catch (_) {}
|
|
2383
|
-
} else {
|
|
2384
|
-
try { child.kill('SIGTERM'); } catch (_) {}
|
|
2385
|
-
}
|
|
2386
|
-
} catch (_) {}
|
|
2387
|
-
const graceTimer = setTimeout(() => {
|
|
2388
|
-
if (meta.status !== 'running') return;
|
|
2389
|
-
if (isPosix && meta.pgid) {
|
|
2390
|
-
try { process.kill(-meta.pgid, 'SIGKILL'); } catch (_) {}
|
|
2391
|
-
} else if (process.platform === 'win32') {
|
|
2392
|
-
try { spawnSync('taskkill', ['/F', '/T', '/PID', String(pid)], { stdio: 'ignore', timeout: 3000 }); } catch (_) {}
|
|
2393
|
-
} else {
|
|
2394
|
-
try { child.kill('SIGKILL'); } catch (_) {}
|
|
2395
|
-
}
|
|
2396
|
-
}, 2000);
|
|
2397
|
-
graceTimer.unref && graceTimer.unref();
|
|
2398
|
-
logEvent('plugkit', 'task.stop', { task_id: id, pid });
|
|
2399
|
-
return { ok: true, task_id: id, pid };
|
|
2400
|
-
}
|
|
2401
|
-
|
|
2402
|
-
function tailFile(filePath, maxBytes) {
|
|
2403
|
-
try {
|
|
2404
|
-
const stat = fs.statSync(filePath);
|
|
2405
|
-
if (stat.size <= maxBytes) return fs.readFileSync(filePath, 'utf-8');
|
|
2406
|
-
const fd = fs.openSync(filePath, 'r');
|
|
2407
|
-
try {
|
|
2408
|
-
const buf = Buffer.alloc(maxBytes);
|
|
2409
|
-
fs.readSync(fd, buf, 0, maxBytes, stat.size - maxBytes);
|
|
2410
|
-
return buf.toString('utf-8');
|
|
2411
|
-
} finally { try { fs.closeSync(fd); } catch (_) {} }
|
|
2412
|
-
} catch (_) { return ''; }
|
|
2413
1781
|
}
|
|
2414
1782
|
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
|
|
2441
|
-
function killAllTasks(reason) {
|
|
2442
|
-
let killed = 0;
|
|
2443
|
-
for (const [id, entry] of __tasks) {
|
|
2444
|
-
if (entry.meta.status === 'running') {
|
|
2445
|
-
stopTaskById(id);
|
|
2446
|
-
killed += 1;
|
|
2447
|
-
}
|
|
2448
|
-
}
|
|
2449
|
-
if (killed > 0) logEvent('plugkit', 'task.killAll', { reason, count: killed });
|
|
2450
|
-
return killed;
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
function pidAliveLocal(pid) {
|
|
2454
|
-
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
2455
|
-
try { process.kill(pid, 0); return true; } catch (_) { return false; }
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
|
-
function sweepOrphanedTaskMetaOnBoot(cwd) {
|
|
2459
|
-
let swept = 0;
|
|
2460
|
-
try {
|
|
2461
|
-
const dir = tasksDir(cwd);
|
|
2462
|
-
const now = Date.now();
|
|
2463
|
-
for (const name of fs.readdirSync(dir)) {
|
|
2464
|
-
if (!/^t\d+\.json$/.test(name)) continue;
|
|
2465
|
-
const metaPath = path.join(dir, name);
|
|
2466
|
-
let meta = null;
|
|
2467
|
-
try { meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8')); } catch (_) { continue; }
|
|
2468
|
-
if (!meta || meta.status !== 'running') continue;
|
|
2469
|
-
const stale = !pidAliveLocal(meta.pid) || (meta.deadline_ms && now > meta.deadline_ms);
|
|
2470
|
-
if (!stale) continue;
|
|
2471
|
-
if (pidAliveLocal(meta.pid)) {
|
|
2472
|
-
try {
|
|
2473
|
-
if (process.platform === 'win32') {
|
|
2474
|
-
spawnSync('taskkill', ['/F', '/T', '/PID', String(meta.pid)], { stdio: 'ignore', windowsHide: true, timeout: 3000 });
|
|
2475
|
-
} else {
|
|
2476
|
-
try { process.kill(-meta.pid, 'SIGKILL'); } catch (_) { try { process.kill(meta.pid, 'SIGKILL'); } catch (_) {} }
|
|
2477
|
-
}
|
|
2478
|
-
} catch (_) {}
|
|
2479
|
-
}
|
|
2480
|
-
meta.status = 'reaped-on-boot';
|
|
2481
|
-
meta.ended_ms = now;
|
|
2482
|
-
try { fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2)); } catch (_) {}
|
|
2483
|
-
swept += 1;
|
|
2484
|
-
}
|
|
2485
|
-
} catch (_) {}
|
|
2486
|
-
if (swept > 0) logEvent('plugkit', 'task.bootSweepReaped', { cwd: cwd || process.cwd(), count: swept });
|
|
2487
|
-
return swept;
|
|
2488
|
-
}
|
|
2489
|
-
|
|
2490
|
-
function hostTaskProc(action, params) {
|
|
2491
|
-
switch (action) {
|
|
2492
|
-
case 'spawn': return spawnTask(params);
|
|
2493
|
-
case 'stop': return stopTaskById(params.id || params.task_id);
|
|
2494
|
-
case 'list': return { ok: true, tasks: listTasks(params.cwd) };
|
|
2495
|
-
case 'output': return {
|
|
2496
|
-
ok: true,
|
|
2497
|
-
task_id: params.id || params.task_id,
|
|
2498
|
-
stdout: tailFile(taskOutPath(params.cwd, params.id || params.task_id, 'stdout'), params.max_bytes || 65536),
|
|
2499
|
-
stderr: tailFile(taskOutPath(params.cwd, params.id || params.task_id, 'stderr'), params.max_bytes || 65536),
|
|
2500
|
-
};
|
|
2501
|
-
case 'reap': { reapTimedOutTasks(); return { ok: true }; }
|
|
2502
|
-
case 'killAll': { const n = killAllTasks(params.reason || 'host_task_proc'); return { ok: true, killed: n }; }
|
|
2503
|
-
default: return { ok: false, error: `unknown action: ${action}` };
|
|
2504
|
-
}
|
|
2505
|
-
}
|
|
1783
|
+
const { kvFilePath, kvReadResolve, kvNamespaceDirs } = makeKvHelpers(KV_DIR);
|
|
1784
|
+
|
|
1785
|
+
const __taskManager = makeTaskManager({ spawn, spawnSync, logEvent: (sub, event, fields) => logEvent(sub, event, fields) });
|
|
1786
|
+
const {
|
|
1787
|
+
__tasks,
|
|
1788
|
+
tasksDir,
|
|
1789
|
+
taskMetaPath,
|
|
1790
|
+
taskOutPath,
|
|
1791
|
+
writeTaskMeta,
|
|
1792
|
+
nextTaskId,
|
|
1793
|
+
resolveJsRuntimeCmd,
|
|
1794
|
+
langToCmd,
|
|
1795
|
+
TASK_MAX_TIMEOUT_MS,
|
|
1796
|
+
spawnTask,
|
|
1797
|
+
stopTaskById,
|
|
1798
|
+
tailFile,
|
|
1799
|
+
listTasks,
|
|
1800
|
+
reapTimedOutTasks,
|
|
1801
|
+
killAllTasks,
|
|
1802
|
+
pidAliveLocal,
|
|
1803
|
+
sweepOrphanedTaskMetaOnBoot,
|
|
1804
|
+
hostTaskProc,
|
|
1805
|
+
} = __taskManager;
|
|
2506
1806
|
|
|
2507
1807
|
let _gmRunnerEmbedBinPath;
|
|
2508
1808
|
function resolveGmRunnerEmbedBin() {
|
|
@@ -5436,7 +4736,7 @@ async function tryInstantiate(wasmPath) {
|
|
|
5436
4736
|
const hostFunctions = makeHostFunctions(instanceRef);
|
|
5437
4737
|
const importObject = {
|
|
5438
4738
|
env: hostFunctions,
|
|
5439
|
-
wasi_snapshot_preview1:
|
|
4739
|
+
wasi_snapshot_preview1: __createWasiShimBound(instanceRef),
|
|
5440
4740
|
};
|
|
5441
4741
|
const instance = await WebAssembly.instantiate(wasmModule, importObject);
|
|
5442
4742
|
instanceRef.value = instance;
|
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.1980",
|
|
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",
|