gm-qwen 2.0.984 → 2.0.985
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/plugkit.js +82 -22
- package/gm.json +1 -1
- package/package.json +1 -1
package/bin/plugkit.js
CHANGED
|
@@ -1,48 +1,108 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// of node startup overhead.
|
|
3
|
+
// Hot path: spawnSync to ~/.claude/gm-tools/plugkit.exe with inherited stdio.
|
|
4
|
+
// Cold path (session-start / prompt-submit OR missing binary): synchronously
|
|
5
|
+
// ensure gm-tools/plugkit{.exe} matches the pinned version, then run hook.
|
|
6
|
+
// Cache-aware: when local matches the pin (sha-checked), zero network calls.
|
|
8
7
|
|
|
9
8
|
const { spawnSync } = require('child_process');
|
|
10
9
|
const path = require('path');
|
|
11
10
|
const fs = require('fs');
|
|
12
11
|
const os = require('os');
|
|
13
12
|
|
|
13
|
+
const wrapperDir = __dirname;
|
|
14
|
+
|
|
14
15
|
function toolsBin() {
|
|
15
16
|
const home = process.env.USERPROFILE || process.env.HOME || os.homedir();
|
|
16
17
|
const exe = process.platform === 'win32' ? 'plugkit.exe' : 'plugkit';
|
|
17
18
|
return path.join(home, '.claude', 'gm-tools', exe);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
function sha256OfFileSync(filePath) {
|
|
22
|
+
try {
|
|
23
|
+
const crypto = require('crypto');
|
|
24
|
+
const h = crypto.createHash('sha256');
|
|
25
|
+
const fd = fs.openSync(filePath, 'r');
|
|
26
|
+
try {
|
|
27
|
+
const buf = Buffer.alloc(1 << 20);
|
|
28
|
+
let n;
|
|
29
|
+
while ((n = fs.readSync(fd, buf, 0, buf.length, null)) > 0) h.update(buf.subarray(0, n));
|
|
30
|
+
} finally { fs.closeSync(fd); }
|
|
31
|
+
return h.digest('hex');
|
|
32
|
+
} catch (_) { return null; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function platformAsset() {
|
|
36
|
+
const p = process.platform;
|
|
37
|
+
const a = process.arch;
|
|
38
|
+
if (p === 'win32') return a === 'arm64' ? 'plugkit-win32-arm64.exe' : 'plugkit-win32-x64.exe';
|
|
39
|
+
if (p === 'darwin') return a === 'arm64' ? 'plugkit-darwin-arm64' : 'plugkit-darwin-x64';
|
|
40
|
+
return (a === 'arm64' || a === 'aarch64') ? 'plugkit-linux-arm64' : 'plugkit-linux-x64';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function readPinnedVersion() {
|
|
44
|
+
try { return fs.readFileSync(path.join(wrapperDir, 'plugkit.version'), 'utf8').trim(); } catch (_) { return null; }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readExpectedSha() {
|
|
48
|
+
try {
|
|
49
|
+
const manifest = fs.readFileSync(path.join(wrapperDir, 'plugkit.sha256'), 'utf8');
|
|
50
|
+
const asset = platformAsset();
|
|
51
|
+
for (const line of manifest.split(/\r?\n/)) {
|
|
52
|
+
const parts = line.trim().split(/\s+/);
|
|
53
|
+
if (parts.length >= 2 && parts[parts.length - 1].replace(/^\*/, '') === asset) {
|
|
54
|
+
return parts[0].toLowerCase();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch (_) {}
|
|
29
58
|
return null;
|
|
30
59
|
}
|
|
31
60
|
|
|
61
|
+
// Returns true if gm-tools binary matches pinned version by sha. Fast: no network.
|
|
62
|
+
function isReady() {
|
|
63
|
+
const bin = toolsBin();
|
|
64
|
+
if (!fs.existsSync(bin)) return false;
|
|
65
|
+
const expected = readExpectedSha();
|
|
66
|
+
if (!expected) return true; // no manifest to compare against — trust existence
|
|
67
|
+
const actual = sha256OfFileSync(bin);
|
|
68
|
+
return actual && actual.toLowerCase() === expected;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Synchronously run bootstrap.js in a child node. Blocks until install finishes
|
|
72
|
+
// (or fails). Bootstrap itself is cache-aware: re-download only when sha differs
|
|
73
|
+
// from manifest. Wraps stdio:inherit so the user sees progress.
|
|
74
|
+
function ensureReady(silent) {
|
|
75
|
+
if (isReady()) return true;
|
|
76
|
+
const bootstrap = path.join(wrapperDir, 'bootstrap.js');
|
|
77
|
+
const r = spawnSync(process.execPath, [bootstrap], {
|
|
78
|
+
stdio: silent ? ['ignore', 'pipe', 'pipe'] : ['ignore', 'inherit', 'inherit'],
|
|
79
|
+
windowsHide: true,
|
|
80
|
+
});
|
|
81
|
+
return r.status === 0 && isReady();
|
|
82
|
+
}
|
|
83
|
+
|
|
32
84
|
function main() {
|
|
33
85
|
const args = process.argv.slice(2);
|
|
34
86
|
const isHook = args[0] === 'hook';
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
87
|
+
const hookSubcmd = isHook ? (args[1] || '') : '';
|
|
88
|
+
|
|
89
|
+
// Synchronous readiness check on these hooks. Hot path: isReady() is sha-match
|
|
90
|
+
// against pinned manifest, returns true in <50ms with no network.
|
|
91
|
+
const blocksUntilReady = hookSubcmd === 'session-start' || hookSubcmd === 'prompt-submit';
|
|
92
|
+
|
|
93
|
+
if (blocksUntilReady) {
|
|
94
|
+
if (!ensureReady(false)) {
|
|
95
|
+
process.stderr.write('[plugkit] bootstrap failed; aborting hook\n');
|
|
43
96
|
process.exit(1);
|
|
44
97
|
}
|
|
98
|
+
} else if (!fs.existsSync(toolsBin())) {
|
|
99
|
+
// For non-blocking hooks (pre-tool-use, post-tool-use, stop, etc.): if the
|
|
100
|
+
// binary doesn't exist yet, exit cleanly — session-start will populate it.
|
|
101
|
+
if (isHook) process.exit(0);
|
|
102
|
+
process.exit(1);
|
|
45
103
|
}
|
|
104
|
+
|
|
105
|
+
const bin = toolsBin();
|
|
46
106
|
const r = spawnSync(bin, args, { stdio: 'inherit', windowsHide: true });
|
|
47
107
|
process.exit(r.status ?? 1);
|
|
48
108
|
}
|
package/gm.json
CHANGED