gm-plugkit 2.0.1124 → 2.0.1126
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/bootstrap.js +183 -10
- package/package.json +1 -1
- package/plugkit.sha256 +1 -6
- package/plugkit.version +1 -1
package/bootstrap.js
CHANGED
|
@@ -190,6 +190,49 @@ async function extractNpmPackageWasm(destPath, version) {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
function httpGetBuffer(url, timeoutMs) {
|
|
194
|
+
const https = require('https');
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
const req = https.get(url, { timeout: timeoutMs || 30000, headers: { 'user-agent': 'gm-plugkit-bootstrap' } }, (res) => {
|
|
197
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
198
|
+
res.resume();
|
|
199
|
+
httpGetBuffer(res.headers.location, timeoutMs).then(resolve, reject);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (res.statusCode !== 200) {
|
|
203
|
+
res.resume();
|
|
204
|
+
reject(new Error(`HTTP ${res.statusCode} ${url}`));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const chunks = [];
|
|
208
|
+
res.on('data', c => chunks.push(c));
|
|
209
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
210
|
+
res.on('error', reject);
|
|
211
|
+
});
|
|
212
|
+
req.on('timeout', () => req.destroy(new Error(`timeout ${url}`)));
|
|
213
|
+
req.on('error', reject);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function downloadFromGithubReleases(destPath, version) {
|
|
218
|
+
const base = `https://github.com/AnEntrypoint/plugkit-bin/releases/download/v${version}`;
|
|
219
|
+
log(`gh-releases download: ${base}/plugkit.wasm`);
|
|
220
|
+
const buf = await httpGetBuffer(`${base}/plugkit.wasm`, 60000);
|
|
221
|
+
if (!buf || buf.length < 1024) throw new Error(`gh-releases download too small: ${buf ? buf.length : 0} bytes`);
|
|
222
|
+
let remoteSha = '';
|
|
223
|
+
try {
|
|
224
|
+
const shaBuf = await httpGetBuffer(`${base}/plugkit.wasm.sha256`, 10000);
|
|
225
|
+
remoteSha = shaBuf.toString('utf-8').trim().split(/\s+/)[0];
|
|
226
|
+
} catch (e) { log(`gh-releases sha fetch failed: ${e.message}`); }
|
|
227
|
+
if (remoteSha) {
|
|
228
|
+
const got = require('crypto').createHash('sha256').update(buf).digest('hex');
|
|
229
|
+
if (got !== remoteSha) throw new Error(`gh-releases sha mismatch: got ${got}, expected ${remoteSha}`);
|
|
230
|
+
log(`gh-releases sha verified ${got.slice(0, 16)}...`);
|
|
231
|
+
}
|
|
232
|
+
fs.writeFileSync(destPath, buf);
|
|
233
|
+
log(`gh-releases wrote ${buf.length} bytes to ${destPath}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
193
236
|
async function extractNpmPackageWithRetry(destPath, version) {
|
|
194
237
|
let lastErr;
|
|
195
238
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
@@ -547,12 +590,17 @@ async function bootstrap(opts) {
|
|
|
547
590
|
try {
|
|
548
591
|
await extractNpmPackageWithRetry(partialPath, version);
|
|
549
592
|
} catch (extractErr) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
593
|
+
log(`npm-extract failed (${extractErr.message || extractErr}); falling back to GitHub Releases`);
|
|
594
|
+
try {
|
|
595
|
+
await downloadFromGithubReleases(partialPath, version);
|
|
596
|
+
} catch (ghErr) {
|
|
597
|
+
writeBootstrapError({
|
|
598
|
+
expected_version: version, cached_version: null,
|
|
599
|
+
error_phase: 'npm-extract+gh-fallback',
|
|
600
|
+
error_message: `npm: ${extractErr.message}; gh: ${ghErr.message}`,
|
|
601
|
+
});
|
|
602
|
+
throw ghErr;
|
|
603
|
+
}
|
|
556
604
|
}
|
|
557
605
|
|
|
558
606
|
if (expectedSha) {
|
|
@@ -634,18 +682,143 @@ function isReady() {
|
|
|
634
682
|
return fs.existsSync(wasm);
|
|
635
683
|
}
|
|
636
684
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
685
|
+
function ensureWrapperFresh() {
|
|
686
|
+
try {
|
|
687
|
+
const wrapperSrc = path.join(__dirname, 'plugkit-wasm-wrapper.js');
|
|
688
|
+
const wrapperDst = path.join(gmToolsDir(), 'plugkit-wasm-wrapper.js');
|
|
689
|
+
if (!fs.existsSync(wrapperSrc)) return false;
|
|
690
|
+
let same = false;
|
|
691
|
+
if (fs.existsSync(wrapperDst)) {
|
|
692
|
+
try {
|
|
693
|
+
const a = sha256OfFileSync(wrapperSrc);
|
|
694
|
+
const b = sha256OfFileSync(wrapperDst);
|
|
695
|
+
if (a === b) same = true;
|
|
696
|
+
} catch (_) {}
|
|
697
|
+
}
|
|
698
|
+
if (!same) {
|
|
699
|
+
fs.mkdirSync(gmToolsDir(), { recursive: true });
|
|
700
|
+
fs.copyFileSync(wrapperSrc, wrapperDst);
|
|
701
|
+
return true;
|
|
702
|
+
}
|
|
703
|
+
return false;
|
|
704
|
+
} catch (_) { return false; }
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function installedVersionAtTools() {
|
|
708
|
+
try {
|
|
709
|
+
const p = path.join(gmToolsDir(), 'plugkit.version');
|
|
710
|
+
if (!fs.existsSync(p)) return null;
|
|
711
|
+
return fs.readFileSync(p, 'utf-8').trim();
|
|
712
|
+
} catch (_) { return null; }
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
async function resolveLatestRemoteVersion(timeoutMs) {
|
|
716
|
+
try {
|
|
717
|
+
const buf = await httpGetBuffer('https://api.github.com/repos/AnEntrypoint/plugkit-bin/releases?per_page=50', timeoutMs || 3000);
|
|
718
|
+
const releases = JSON.parse(buf.toString('utf-8'));
|
|
719
|
+
if (!Array.isArray(releases)) return null;
|
|
720
|
+
for (const rel of releases) {
|
|
721
|
+
const tag = rel && rel.tag_name;
|
|
722
|
+
if (!tag) continue;
|
|
723
|
+
const m = /^v(\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?)$/.exec(tag);
|
|
724
|
+
if (!m) continue;
|
|
725
|
+
const hasPlugkitWasm = Array.isArray(rel.assets) && rel.assets.some(a => a && a.name === 'plugkit.wasm');
|
|
726
|
+
if (hasPlugkitWasm) return m[1];
|
|
727
|
+
}
|
|
728
|
+
} catch (_) {}
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
async function ensureReady(opts) {
|
|
733
|
+
opts = opts || {};
|
|
734
|
+
const offline = opts.offline === true;
|
|
735
|
+
let pinnedVersion = null;
|
|
736
|
+
try { pinnedVersion = readVersionFile(); } catch (_) {}
|
|
737
|
+
let targetVersion = pinnedVersion;
|
|
738
|
+
if (!offline) {
|
|
739
|
+
const latest = await resolveLatestRemoteVersion(3000);
|
|
740
|
+
if (latest) targetVersion = latest;
|
|
741
|
+
}
|
|
742
|
+
if (!targetVersion) targetVersion = pinnedVersion;
|
|
743
|
+
|
|
744
|
+
const installed = installedVersionAtTools();
|
|
745
|
+
const versionDrift = targetVersion && installed && installed !== targetVersion;
|
|
746
|
+
|
|
747
|
+
if (isReady() && !versionDrift) {
|
|
748
|
+
const wasmPath = getWasmPath();
|
|
749
|
+
const wrapperUpdated = ensureWrapperFresh();
|
|
750
|
+
return { ok: true, wasmPath, binaryPath: wasmPath, status: wrapperUpdated ? 'wrapper-refreshed' : 'already-ready', version: installed };
|
|
751
|
+
}
|
|
752
|
+
if (versionDrift) {
|
|
753
|
+
try { killRunningDaemons(`version_drift:${installed}->${targetVersion}`); } catch (_) {}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (targetVersion && targetVersion !== pinnedVersion) {
|
|
757
|
+
try {
|
|
758
|
+
const verFilePath = path.join(wrapperDir, 'plugkit.version');
|
|
759
|
+
fs.writeFileSync(verFilePath, targetVersion + '\n');
|
|
760
|
+
log(`overrode bundled plugkit.version: ${pinnedVersion} -> ${targetVersion} (remote latest)`);
|
|
761
|
+
} catch (e) { log(`could not override plugkit.version: ${e.message}`); }
|
|
640
762
|
}
|
|
763
|
+
|
|
641
764
|
const wasmPath = await bootstrap();
|
|
642
|
-
|
|
765
|
+
ensureWrapperFresh();
|
|
766
|
+
return { ok: true, wasmPath, binaryPath: wasmPath, status: 'bootstrapped', version: targetVersion || installed };
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function getBinaryPath() {
|
|
770
|
+
return getWasmPath();
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function startSpoolDaemon() {
|
|
774
|
+
try {
|
|
775
|
+
const wrapper = path.join(gmToolsDir(), 'plugkit-wasm-wrapper.js');
|
|
776
|
+
if (!fs.existsSync(wrapper)) {
|
|
777
|
+
return { ok: false, error: `wrapper not at ${wrapper} — ensureReady() must run first` };
|
|
778
|
+
}
|
|
779
|
+
const runtime = process.platform === 'win32' ? 'bun.exe' : 'bun';
|
|
780
|
+
let cmd = runtime;
|
|
781
|
+
let args = [wrapper, 'spool'];
|
|
782
|
+
try {
|
|
783
|
+
require('child_process').execFileSync(runtime, ['--version'], { stdio: 'ignore' });
|
|
784
|
+
} catch (_) {
|
|
785
|
+
cmd = process.execPath;
|
|
786
|
+
args = [wrapper, 'spool'];
|
|
787
|
+
}
|
|
788
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
789
|
+
const spoolDir = path.join(projectDir, '.gm', 'exec-spool');
|
|
790
|
+
fs.mkdirSync(spoolDir, { recursive: true });
|
|
791
|
+
const logPath = path.join(spoolDir, '.watcher.log');
|
|
792
|
+
try {
|
|
793
|
+
const stat = fs.statSync(logPath);
|
|
794
|
+
if (stat.size > 10 * 1024 * 1024) {
|
|
795
|
+
try { fs.unlinkSync(path.join(spoolDir, '.watcher.log.1')); } catch (_) {}
|
|
796
|
+
fs.renameSync(logPath, path.join(spoolDir, '.watcher.log.1'));
|
|
797
|
+
}
|
|
798
|
+
} catch (_) {}
|
|
799
|
+
const logFd = fs.openSync(logPath, 'a');
|
|
800
|
+
try { fs.writeSync(logFd, `\n--- daemon spawn ${new Date().toISOString()} parent=${process.pid} ---\n`); } catch (_) {}
|
|
801
|
+
const child = require('child_process').spawn(cmd, args, {
|
|
802
|
+
detached: true,
|
|
803
|
+
stdio: ['ignore', logFd, logFd],
|
|
804
|
+
windowsHide: true,
|
|
805
|
+
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
806
|
+
});
|
|
807
|
+
try { fs.closeSync(logFd); } catch (_) {}
|
|
808
|
+
const pid = child.pid;
|
|
809
|
+
child.unref();
|
|
810
|
+
return { ok: true, pid, wrapper, runtime: cmd, logPath };
|
|
811
|
+
} catch (e) {
|
|
812
|
+
return { ok: false, error: e.message };
|
|
813
|
+
}
|
|
643
814
|
}
|
|
644
815
|
|
|
645
816
|
module.exports = {
|
|
646
817
|
bootstrap,
|
|
647
818
|
ensureReady,
|
|
648
819
|
getWasmPath,
|
|
820
|
+
getBinaryPath,
|
|
821
|
+
startSpoolDaemon,
|
|
649
822
|
isReady,
|
|
650
823
|
rtkBinaryName,
|
|
651
824
|
cacheRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1126",
|
|
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": {
|
package/plugkit.sha256
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
|
|
2
|
-
ce2f09f8ea0dd522345a9d9c3e5b04ba44bc37b2046d311d7ff1737f1b3fbf1a plugkit-win32-arm64.exe
|
|
3
|
-
a1a1d376986551828e5a39e4ae931accf66f00663aceac1439b2778cb4fffd27 plugkit-darwin-x64
|
|
4
|
-
7c36d730edab5cddf678211146ca670c9ce1def17d8b454234ce4bc04a4d7e85 plugkit-darwin-arm64
|
|
5
|
-
c9db60a399caf53c490dc08705713c7d83a1f62db057585a3950d64ab8fa449a plugkit-linux-x64
|
|
6
|
-
b9ebabaace995b1768d1d96ae13ca18a6dc5e2ca65b774fcdd457f069a7d115c plugkit-linux-arm64
|
|
1
|
+
{"plugkit.wasm":"874f5a3524d8a080a2880567cc3808ae727f4c2b4f35ad6fc33e932fd6c4c567"}
|
package/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.396
|