gm-qwen 2.0.980 → 2.0.982
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/bootstrap.js +42 -0
- package/bin/plugkit.js +35 -144
- package/bin/plugkit.sha256 +6 -6
- package/bin/rtk.sha256 +2 -2
- package/gm.json +1 -1
- package/package.json +1 -1
package/bin/bootstrap.js
CHANGED
|
@@ -99,6 +99,42 @@ function fallbackCacheRoot() {
|
|
|
99
99
|
return path.join(os.tmpdir(), 'plugkit-cache', 'bin');
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
function gmToolsDir() {
|
|
103
|
+
const home = process.env.USERPROFILE || process.env.HOME || os.homedir();
|
|
104
|
+
return path.join(home, '.claude', 'gm-tools');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Copy the freshly-resolved plugkit binary + its version+sha manifests to
|
|
108
|
+
// ~/.claude/gm-tools so hooks.json can invoke plugkit directly without going
|
|
109
|
+
// through node. Self-update inside the Rust binary keeps gm-tools fresh from
|
|
110
|
+
// here on. Skipped silently on any error — the next session-start hook will
|
|
111
|
+
// retry via ensure_tools_current.
|
|
112
|
+
function copyToGmTools(finalPath, wrapperDir, version) {
|
|
113
|
+
try {
|
|
114
|
+
const dst = gmToolsDir();
|
|
115
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
116
|
+
const exeName = process.platform === 'win32' ? 'plugkit.exe' : 'plugkit';
|
|
117
|
+
const target = path.join(dst, exeName);
|
|
118
|
+
const targetTmp = target + '.new';
|
|
119
|
+
fs.copyFileSync(finalPath, targetTmp);
|
|
120
|
+
try { fs.renameSync(targetTmp, target); }
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (err.code === 'EEXIST' || err.code === 'EPERM' || err.code === 'EBUSY') {
|
|
123
|
+
// target may be locked by a running plugkit; the .new file persists
|
|
124
|
+
// and the in-Rust self-update will eventually swap it. Leave it.
|
|
125
|
+
} else { throw err; }
|
|
126
|
+
}
|
|
127
|
+
if (process.platform !== 'win32') {
|
|
128
|
+
try { fs.chmodSync(target, 0o755); } catch (_) {}
|
|
129
|
+
}
|
|
130
|
+
fs.writeFileSync(path.join(dst, 'plugkit.version'), version);
|
|
131
|
+
try {
|
|
132
|
+
const srcSha = path.join(wrapperDir, 'plugkit.sha256');
|
|
133
|
+
if (fs.existsSync(srcSha)) fs.copyFileSync(srcSha, path.join(dst, 'plugkit.sha256'));
|
|
134
|
+
} catch (_) {}
|
|
135
|
+
} catch (_) {}
|
|
136
|
+
}
|
|
137
|
+
|
|
102
138
|
function ensureDir(dir) {
|
|
103
139
|
fs.mkdirSync(dir, { recursive: true });
|
|
104
140
|
}
|
|
@@ -349,6 +385,7 @@ async function bootstrap(opts) {
|
|
|
349
385
|
const actualSha = sha256OfFileSync(finalPath);
|
|
350
386
|
if (actualSha === expectedSha) {
|
|
351
387
|
if (!opts.silent) log(`decision: hit reason: sha-match v${version} (${finalPath})`);
|
|
388
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
352
389
|
return finalPath;
|
|
353
390
|
}
|
|
354
391
|
log(`decision: fetch reason: cache-hit-sha-mismatch (dir=v${version} expected ${expectedSha.slice(0,12)}… got ${(actualSha||'').slice(0,12)}…)`);
|
|
@@ -362,6 +399,7 @@ async function bootstrap(opts) {
|
|
|
362
399
|
try { fs.unlinkSync(okSentinel); } catch (_) {}
|
|
363
400
|
} else {
|
|
364
401
|
if (!opts.silent) log(`decision: hit reason: sentinel+no-sha-manifest (${finalPath})`);
|
|
402
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
365
403
|
return finalPath;
|
|
366
404
|
}
|
|
367
405
|
}
|
|
@@ -369,6 +407,7 @@ async function bootstrap(opts) {
|
|
|
369
407
|
if (healIfShaMatches(finalPath, expectedSha, okSentinel, partialPath, 'plugkit')) {
|
|
370
408
|
if (!opts.silent) log(`decision: heal reason: sha-match (${finalPath})`);
|
|
371
409
|
spawnDetachedRtkFetch(wrapperDir);
|
|
410
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
372
411
|
return finalPath;
|
|
373
412
|
}
|
|
374
413
|
|
|
@@ -377,11 +416,13 @@ async function bootstrap(opts) {
|
|
|
377
416
|
try {
|
|
378
417
|
if (fs.existsSync(finalPath) && fs.existsSync(okSentinel)) {
|
|
379
418
|
log(`decision: hit reason: lock-race-resolved (${finalPath})`);
|
|
419
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
380
420
|
return finalPath;
|
|
381
421
|
}
|
|
382
422
|
if (healIfShaMatches(finalPath, expectedSha, okSentinel, partialPath, 'plugkit')) {
|
|
383
423
|
log(`decision: heal reason: sha-match-under-lock (${finalPath})`);
|
|
384
424
|
spawnDetachedRtkFetch(wrapperDir);
|
|
425
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
385
426
|
return finalPath;
|
|
386
427
|
}
|
|
387
428
|
|
|
@@ -442,6 +483,7 @@ async function bootstrap(opts) {
|
|
|
442
483
|
proactiveKillForNewInstall(version, finalPath);
|
|
443
484
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
444
485
|
spawnDetachedRtkFetch(wrapperDir);
|
|
486
|
+
copyToGmTools(finalPath, wrapperDir, version);
|
|
445
487
|
return finalPath;
|
|
446
488
|
} finally {
|
|
447
489
|
releaseLock(lockPath);
|
package/bin/plugkit.js
CHANGED
|
@@ -1,159 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
|
|
3
|
+
// Minimal exec wrapper. ZERO bootstrap, ZERO version-probe, ZERO async work.
|
|
4
|
+
// Just shell out to ~/.claude/gm-tools/plugkit{.exe} with inherited stdio.
|
|
5
|
+
// The Rust binary handles its own self-update at startup (detached); first-time
|
|
6
|
+
// bootstrap is done by gm-cc postinstall.js. Hot path is one spawnSync, ~150ms
|
|
7
|
+
// of node startup overhead.
|
|
8
|
+
|
|
9
|
+
const { spawnSync } = require('child_process');
|
|
4
10
|
const path = require('path');
|
|
5
11
|
const fs = require('fs');
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const dir = __dirname;
|
|
9
|
-
|
|
10
|
-
function readPinnedVersion() {
|
|
11
|
-
try { return fs.readFileSync(path.join(dir, 'plugkit.version'), 'utf8').trim(); } catch (_) { return null; }
|
|
12
|
-
}
|
|
12
|
+
const os = require('os');
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const text = `${r.stdout || ''} ${r.stderr || ''}`.trim();
|
|
19
|
-
const m = text.match(/(\d+\.\d+\.\d+)/);
|
|
20
|
-
return m ? m[1] : null;
|
|
21
|
-
} catch (_) { return null; }
|
|
14
|
+
function toolsBin() {
|
|
15
|
+
const home = process.env.USERPROFILE || process.env.HOME || os.homedir();
|
|
16
|
+
const exe = process.platform === 'win32' ? 'plugkit.exe' : 'plugkit';
|
|
17
|
+
return path.join(home, '.claude', 'gm-tools', exe);
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
function envWithRtkOnPath() {
|
|
35
|
-
const rtkPath = resolveCachedRtk({ wrapperDir: dir });
|
|
36
|
-
if (!rtkPath) return process.env;
|
|
37
|
-
const rtkDir = path.dirname(rtkPath);
|
|
38
|
-
const sep = process.platform === 'win32' ? ';' : ':';
|
|
39
|
-
return { ...process.env, PATH: `${rtkDir}${sep}${process.env.PATH || ''}` };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async function resolveBinary() {
|
|
43
|
-
const cached = resolveCachedBinary({ wrapperDir: dir });
|
|
44
|
-
if (cached) return cached;
|
|
45
|
-
return await bootstrap({ wrapperDir: dir });
|
|
20
|
+
function legacyBesideWrapper() {
|
|
21
|
+
const dir = __dirname;
|
|
22
|
+
const p = os.platform();
|
|
23
|
+
const a = os.arch();
|
|
24
|
+
let candidates = [];
|
|
25
|
+
if (p === 'win32') candidates = [path.join(dir, a === 'arm64' ? 'plugkit-win32-arm64.exe' : 'plugkit-win32-x64.exe')];
|
|
26
|
+
else if (p === 'darwin') candidates = [path.join(dir, a === 'arm64' ? 'plugkit-darwin-arm64' : 'plugkit-darwin-x64')];
|
|
27
|
+
else candidates = [path.join(dir, (a === 'arm64' || a === 'aarch64') ? 'plugkit-linux-arm64' : 'plugkit-linux-x64')];
|
|
28
|
+
for (const c of candidates) if (fs.existsSync(c)) return c;
|
|
29
|
+
return null;
|
|
46
30
|
}
|
|
47
31
|
|
|
48
|
-
|
|
32
|
+
function main() {
|
|
49
33
|
const args = process.argv.slice(2);
|
|
50
|
-
// Detached bootstrap entry: just run bootstrap() and exit. Used by session-start
|
|
51
|
-
// to avoid blocking CC startup on a slow GitHub download.
|
|
52
|
-
if (args[0] === '__rtk_only__') {
|
|
53
|
-
try { await bootstrap({ wrapperDir: dir, silent: false }); }
|
|
54
|
-
catch (e) { try { process.stderr.write(`[plugkit-bootstrap-detached] ${e.message}\n`); } catch (_) {} }
|
|
55
|
-
process.exit(0);
|
|
56
|
-
}
|
|
57
34
|
const isHook = args[0] === 'hook';
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// session-start ALWAYS bootstraps: this is the once-per-session moment
|
|
68
|
-
// where we guarantee the cached binary matches the wrapper-pinned version.
|
|
69
|
-
// If the bootstrap fails (offline) we fall through to whatever the cache
|
|
70
|
-
// currently has — the hook itself isn't blocking, just refreshing.
|
|
71
|
-
if (isHook && hookSubcmd === 'session-start') {
|
|
72
|
-
obsEvent('plugkit_wrapper', 'hook_bootstrap_session_start', { argv: args.slice(0, 4) });
|
|
73
|
-
// Bootstrap can stall 60s+ on a slow GitHub mirror — never block CC startup
|
|
74
|
-
// on it. Detach into a background child; this hook returns immediately
|
|
75
|
-
// with whatever cached binary exists. Subsequent hooks pick up the new
|
|
76
|
-
// binary once the detached bootstrap completes.
|
|
77
|
-
bin = resolveCachedBinary({ wrapperDir: dir }) || legacyFallback();
|
|
78
|
-
try {
|
|
79
|
-
const child = spawn(process.execPath, [__filename, '__rtk_only__'], {
|
|
80
|
-
detached: true,
|
|
81
|
-
stdio: 'ignore',
|
|
82
|
-
windowsHide: true,
|
|
83
|
-
env: { ...process.env, PLUGKIT_BOOTSTRAP_DETACHED: '1' },
|
|
84
|
-
});
|
|
85
|
-
child.unref();
|
|
86
|
-
obsEvent('plugkit_wrapper', 'session_start_bootstrap_detached', { pid: child.pid });
|
|
87
|
-
} catch (e) {
|
|
88
|
-
process.stderr.write(`[plugkit] detached bootstrap spawn failed: ${e.message}\n`);
|
|
89
|
-
}
|
|
90
|
-
// If no cached binary yet (fresh install with bootstrap still downloading),
|
|
91
|
-
// skip running the session-start handler this turn — it will fire next
|
|
92
|
-
// session-start once binary is in place.
|
|
93
|
-
if (!bin) {
|
|
94
|
-
process.stderr.write(`[plugkit] session-start skipped: binary not yet installed (bootstrap running in background).\n`);
|
|
95
|
-
process.exit(0);
|
|
96
|
-
}
|
|
97
|
-
} else if (isHook) {
|
|
98
|
-
bin = (await resolveBinaryWithPinCheck()) || legacyFallback();
|
|
99
|
-
if (!bin) {
|
|
100
|
-
process.stderr.write(`[plugkit] hook ${hookSubcmd} skipped: binary not yet installed. Bootstrap will run on session-start.\n`);
|
|
101
|
-
obsEvent('plugkit_wrapper', 'hook_skip_uncached', { argv: args.slice(0, 4), dur_ms: Date.now() - startedAt });
|
|
102
|
-
process.exit(0);
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
bin = await resolveBinary();
|
|
35
|
+
let bin = toolsBin();
|
|
36
|
+
if (!fs.existsSync(bin)) {
|
|
37
|
+
bin = legacyBesideWrapper();
|
|
38
|
+
if (!bin) {
|
|
39
|
+
// Binary not yet installed. If this is a hook, exit cleanly so CC doesn't
|
|
40
|
+
// see an error; postinstall will populate gm-tools on /plugin install.
|
|
41
|
+
if (isHook) process.exit(0);
|
|
42
|
+
process.stderr.write('[plugkit] binary not found at ~/.claude/gm-tools/plugkit — run postinstall\n');
|
|
43
|
+
process.exit(1);
|
|
106
44
|
}
|
|
107
|
-
} catch (err) {
|
|
108
|
-
process.stderr.write(`[plugkit] bootstrap failed: ${err.message}\n`);
|
|
109
|
-
obsEvent('plugkit_wrapper', 'bootstrap_failed', { err: err.message, dur_ms: Date.now() - startedAt, argv: args.slice(0, 4), is_hook: isHook });
|
|
110
|
-
const legacy = legacyFallback();
|
|
111
|
-
if (legacy) { bin = legacy; }
|
|
112
|
-
else if (isHook) { process.exit(0); }
|
|
113
|
-
else process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const env = envWithRtkOnPath();
|
|
117
|
-
|
|
118
|
-
if (isHook && !process.stdin.isTTY) {
|
|
119
|
-
const chunks = [];
|
|
120
|
-
process.stdin.on('data', c => chunks.push(c));
|
|
121
|
-
process.stdin.on('end', () => {
|
|
122
|
-
const child = spawn(bin, args, { stdio: ['pipe', 'inherit', 'inherit'], windowsHide: true, env });
|
|
123
|
-
child.stdin.end(Buffer.concat(chunks));
|
|
124
|
-
child.on('close', code => process.exit(code ?? 1));
|
|
125
|
-
child.on('error', () => process.exit(1));
|
|
126
|
-
});
|
|
127
|
-
process.stdin.on('error', () => process.exit(1));
|
|
128
|
-
} else {
|
|
129
|
-
const result = spawnSync(bin, args, { stdio: 'inherit', windowsHide: true, env });
|
|
130
|
-
obsEvent('plugkit_wrapper', 'exit', { dur_ms: Date.now() - startedAt, code: result.status ?? -1 });
|
|
131
|
-
process.exit(result.status ?? 1);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// legacyFallback only returns a binary that lives next to the wrapper. We
|
|
136
|
-
// never reach across to ~/.claude/gm-tools/plugkit.exe or other ambient
|
|
137
|
-
// install dirs — those have proven to mask bootstrap failures by serving a
|
|
138
|
-
// stale version whose hooks silently mismatch the active wrapper code (see
|
|
139
|
-
// the v0.1.292-vs-v0.1.294 incident).
|
|
140
|
-
function legacyFallback() {
|
|
141
|
-
const os = require('os');
|
|
142
|
-
const p = os.platform();
|
|
143
|
-
const a = os.arch();
|
|
144
|
-
let candidates = [];
|
|
145
|
-
if (p === 'win32') {
|
|
146
|
-
candidates = [path.join(dir, a === 'arm64' ? 'plugkit-win32-arm64.exe' : 'plugkit-win32-x64.exe')];
|
|
147
|
-
} else if (p === 'darwin') {
|
|
148
|
-
candidates = [path.join(dir, a === 'arm64' ? 'plugkit-darwin-arm64' : 'plugkit-darwin-x64')];
|
|
149
|
-
} else {
|
|
150
|
-
candidates = [path.join(dir, (a === 'arm64' || a === 'aarch64') ? 'plugkit-linux-arm64' : 'plugkit-linux-x64')];
|
|
151
45
|
}
|
|
152
|
-
|
|
153
|
-
|
|
46
|
+
const r = spawnSync(bin, args, { stdio: 'inherit', windowsHide: true });
|
|
47
|
+
process.exit(r.status ?? 1);
|
|
154
48
|
}
|
|
155
49
|
|
|
156
|
-
main()
|
|
157
|
-
process.stderr.write(`[plugkit] fatal: ${err.message}\n`);
|
|
158
|
-
process.exit(1);
|
|
159
|
-
});
|
|
50
|
+
main();
|
package/bin/plugkit.sha256
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
8d0063971b24bb316258d997351e1d2f7873567efb2d5e5d67c0812b3aafa3b2 plugkit-win32-x64.exe
|
|
2
|
+
a3ae6e3dc06119779b6906d864aa5153a6b0263d02cd804256744ce87b418bd1 plugkit-win32-arm64.exe
|
|
3
|
+
0026e9c08fa50816f7c9c4574fc69177d982dd4c78195e7b9205d1f0a0cd0e4d plugkit-darwin-x64
|
|
4
|
+
6b953f803a0c07f5a8ff1d505158482e2feae8a062d8d16459ed52d4685feec6 plugkit-darwin-arm64
|
|
5
|
+
0dd17b76a720db81d7b8142b3783fcbeae8759b3741fe9ce37c776149b03ba6f plugkit-linux-x64
|
|
6
|
+
05d91f175c3a6ae78a11687b78aedcd0c5faeac6499b9f292848108a420c21c3 plugkit-linux-arm64
|
package/bin/rtk.sha256
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
ea121977fa8760f46a46a5eca0cdcd45dc1fe336586ab583a515bce5cd0737e6 rtk-win32-x64.exe
|
|
2
|
+
232f7342e365178ad0c3732c4ff0f746539f1f999f328164eb7307595305a8ba rtk-win32-arm64.exe
|
|
3
3
|
1b1e792767ed0e1e6ca0e2f0a8de02e77b06dea2f5ae667278b94baf239fcdc3 rtk-darwin-x64
|
|
4
4
|
9717978d9d6216ea50c94444e00e359479b6315a17bd48c16064b267c8b0b60d rtk-darwin-arm64
|
|
5
5
|
a100d3defac54194144e5723aec57e6f286b42298c67145c8428815246c9ee56 rtk-linux-x64
|
package/gm.json
CHANGED