gm-plugkit 2.0.1090 → 2.0.1092

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1090",
3
+ "version": "2.0.1092",
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": {
@@ -2,44 +2,329 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
4
  import { watch } from 'fs';
5
+ import { spawn, spawnSync } from 'child_process';
6
+
7
+ const KV_DIR = path.join(os.homedir(), '.claude', 'gm-tools', 'kv');
8
+ fs.mkdirSync(KV_DIR, { recursive: true });
9
+
10
+ const RS_LEARN_URL = process.env.RS_LEARN_URL || 'http://127.0.0.1:8000';
11
+ const VEC_K_DEFAULT = 10;
12
+
13
+ const browserSessions = new Map();
14
+ let nextBrowserSessionId = 1;
5
15
 
6
16
  function createWasiShim() {
7
- const shim = new Proxy({}, {
17
+ return new Proxy({}, {
8
18
  get(target, prop) {
9
19
  if (prop === 'proc_exit') return (code) => process.exit(code);
20
+ if (prop === 'fd_write') return () => 0;
21
+ if (prop === 'environ_get') return () => 0;
22
+ if (prop === 'environ_sizes_get') return () => 0;
10
23
  return () => 0;
11
24
  }
12
25
  });
13
- return shim;
14
26
  }
15
27
 
16
- function memWriteStr(memory, ptr, len, str) {
17
- const bytes = new TextEncoder().encode(str);
18
- const buf = new Uint8Array(memory.buffer, ptr, len);
19
- buf.set(bytes.slice(0, len));
20
- return Math.min(bytes.length, len);
28
+ function readWasmBytes(instance, ptr, len) {
29
+ if (ptr === 0 || len === 0) return new Uint8Array(0);
30
+ return new Uint8Array(instance.exports.memory.buffer, ptr, len).slice();
21
31
  }
22
32
 
23
- function memReadStr(memory, ptr, len) {
24
- const buf = new Uint8Array(memory.buffer, ptr, len);
25
- return new TextDecoder().decode(buf);
33
+ function readWasmStr(instance, ptr, len) {
34
+ if (ptr === 0 || len === 0) return '';
35
+ const bytes = new Uint8Array(instance.exports.memory.buffer, ptr, len);
36
+ return new TextDecoder('utf-8').decode(bytes);
26
37
  }
27
38
 
28
- let nextMemPtr = 0x10000;
29
- function allocInMemory(memory, data) {
30
- const ptr = nextMemPtr;
31
- const buf = new Uint8Array(memory.buffer, ptr, data.length);
32
- buf.set(data);
33
- nextMemPtr += data.length;
34
- if (nextMemPtr > memory.buffer.byteLength - 4096) nextMemPtr = 0x10000;
35
- return { ptr, len: data.length };
39
+ function writeWasmBytes(instance, bytes) {
40
+ if (bytes.length === 0) return 0n;
41
+ const ptr = instance.exports.plugkit_alloc(bytes.length);
42
+ if (ptr === 0) return 0n;
43
+ new Uint8Array(instance.exports.memory.buffer, ptr, bytes.length).set(bytes);
44
+ return (BigInt(ptr) & 0xffffffffn) | (BigInt(bytes.length) << 32n);
36
45
  }
37
46
 
38
- function packResult(str) {
39
- const bytes = new TextEncoder().encode(str);
40
- const ptr = Math.random() * 0x100000 | 0;
41
- const len = bytes.length;
42
- return (BigInt(ptr) & 0xffffffffn) | (BigInt(len) << 32n);
47
+ function writeWasmStr(instance, str) {
48
+ if (!str) return 0n;
49
+ return writeWasmBytes(instance, new TextEncoder().encode(str));
50
+ }
51
+
52
+ function writeWasmJson(instance, value) {
53
+ return writeWasmStr(instance, JSON.stringify(value));
54
+ }
55
+
56
+ function kvFilePath(ns, key) {
57
+ const safeNs = String(ns).replace(/[^A-Za-z0-9._-]/g, '_');
58
+ const safeKey = String(key).replace(/[^A-Za-z0-9._-]/g, '_');
59
+ const dir = path.join(KV_DIR, safeNs);
60
+ fs.mkdirSync(dir, { recursive: true });
61
+ return path.join(dir, safeKey + '.json');
62
+ }
63
+
64
+ function makeHostFunctions(instanceRef) {
65
+ return {
66
+ host_fs_read: (pathPtr, pathLen) => {
67
+ try {
68
+ const filePath = readWasmStr(instanceRef.value, pathPtr, pathLen);
69
+ if (!filePath) return 0n;
70
+ const data = fs.readFileSync(filePath, 'utf-8');
71
+ return writeWasmStr(instanceRef.value, data);
72
+ } catch (e) {
73
+ return 0n;
74
+ }
75
+ },
76
+
77
+ host_fs_write: (pathPtr, pathLen, dataPtr, dataLen) => {
78
+ try {
79
+ const filePath = readWasmStr(instanceRef.value, pathPtr, pathLen);
80
+ const data = readWasmStr(instanceRef.value, dataPtr, dataLen);
81
+ if (!filePath) return 0;
82
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
83
+ fs.writeFileSync(filePath, data);
84
+ return 1;
85
+ } catch (e) {
86
+ return 0;
87
+ }
88
+ },
89
+
90
+ host_fs_readdir: (pathPtr, pathLen) => {
91
+ try {
92
+ const dirPath = readWasmStr(instanceRef.value, pathPtr, pathLen);
93
+ if (!dirPath) return 0n;
94
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true }).map(e => ({
95
+ name: e.name,
96
+ is_dir: e.isDirectory(),
97
+ is_file: e.isFile(),
98
+ }));
99
+ return writeWasmJson(instanceRef.value, entries);
100
+ } catch (e) {
101
+ return 0n;
102
+ }
103
+ },
104
+
105
+ host_fs_stat: (pathPtr, pathLen) => {
106
+ try {
107
+ const filePath = readWasmStr(instanceRef.value, pathPtr, pathLen);
108
+ if (!filePath) return 0n;
109
+ const s = fs.statSync(filePath);
110
+ return writeWasmJson(instanceRef.value, {
111
+ is_dir: s.isDirectory(),
112
+ is_file: s.isFile(),
113
+ size: s.size,
114
+ mtime_ms: s.mtimeMs,
115
+ });
116
+ } catch (e) {
117
+ return 0n;
118
+ }
119
+ },
120
+
121
+ host_fetch: (urlPtr, urlLen, optsPtr, optsLen) => {
122
+ try {
123
+ const url = readWasmStr(instanceRef.value, urlPtr, urlLen);
124
+ const optsStr = readWasmStr(instanceRef.value, optsPtr, optsLen);
125
+ const opts = optsStr ? JSON.parse(optsStr) : {};
126
+ const result = spawnSync(process.execPath, ['-e', `
127
+ const url = ${JSON.stringify(url)};
128
+ const opts = ${JSON.stringify(opts)};
129
+ fetch(url, opts).then(r => r.text().then(body => {
130
+ process.stdout.write(JSON.stringify({ status: r.status, body }));
131
+ })).catch(e => process.stdout.write(JSON.stringify({ status: 0, error: e.message })));
132
+ `], { encoding: 'utf-8', timeout: 10000 });
133
+ if (result.status !== 0) return writeWasmJson(instanceRef.value, { status: 0, error: result.stderr || 'fetch failed' });
134
+ return writeWasmStr(instanceRef.value, result.stdout || '{}');
135
+ } catch (e) {
136
+ return writeWasmJson(instanceRef.value, { status: 0, error: e.message });
137
+ }
138
+ },
139
+
140
+ host_kv_get: (nsPtr, nsLen, keyPtr, keyLen) => {
141
+ try {
142
+ const ns = readWasmStr(instanceRef.value, nsPtr, nsLen);
143
+ const key = readWasmStr(instanceRef.value, keyPtr, keyLen);
144
+ if (!ns || !key) return 0n;
145
+ const fp = kvFilePath(ns, key);
146
+ if (!fs.existsSync(fp)) return 0n;
147
+ const data = fs.readFileSync(fp, 'utf-8');
148
+ return writeWasmStr(instanceRef.value, data);
149
+ } catch (e) {
150
+ return 0n;
151
+ }
152
+ },
153
+
154
+ host_kv_put: (nsPtr, nsLen, keyPtr, keyLen, valPtr, valLen) => {
155
+ try {
156
+ const ns = readWasmStr(instanceRef.value, nsPtr, nsLen);
157
+ const key = readWasmStr(instanceRef.value, keyPtr, keyLen);
158
+ const val = readWasmStr(instanceRef.value, valPtr, valLen);
159
+ if (!ns || !key) return 0;
160
+ fs.writeFileSync(kvFilePath(ns, key), val);
161
+ return 1;
162
+ } catch (e) {
163
+ return 0;
164
+ }
165
+ },
166
+
167
+ host_kv_query: (nsPtr, nsLen, qPtr, qLen) => {
168
+ try {
169
+ const ns = readWasmStr(instanceRef.value, nsPtr, nsLen);
170
+ const q = readWasmStr(instanceRef.value, qPtr, qLen);
171
+ if (!ns) return 0n;
172
+ const dir = path.join(KV_DIR, String(ns).replace(/[^A-Za-z0-9._-]/g, '_'));
173
+ if (!fs.existsSync(dir)) return writeWasmJson(instanceRef.value, []);
174
+ const ql = q ? String(q).toLowerCase() : '';
175
+ const results = [];
176
+ for (const f of fs.readdirSync(dir)) {
177
+ if (!f.endsWith('.json')) continue;
178
+ const value = fs.readFileSync(path.join(dir, f), 'utf-8');
179
+ if (ql && !value.toLowerCase().includes(ql) && !f.toLowerCase().includes(ql)) continue;
180
+ results.push({ key: f.replace(/\.json$/, ''), value });
181
+ }
182
+ return writeWasmJson(instanceRef.value, results);
183
+ } catch (e) {
184
+ return 0n;
185
+ }
186
+ },
187
+
188
+ host_vec_search: (qPtr, qLen, k) => {
189
+ try {
190
+ const q = readWasmStr(instanceRef.value, qPtr, qLen);
191
+ if (!q) return writeWasmJson(instanceRef.value, []);
192
+ const k_ = k > 0 ? k : VEC_K_DEFAULT;
193
+ const body = JSON.stringify({ query: q, limit: k_, scope: 'episodes' });
194
+ const result = spawnSync(process.execPath, ['-e', `
195
+ fetch('${RS_LEARN_URL}/search', { method: 'POST', headers: { 'content-type': 'application/json' }, body: ${JSON.stringify(body)} })
196
+ .then(r => r.text().then(t => process.stdout.write(t)))
197
+ .catch(e => process.stdout.write(JSON.stringify({ error: e.message, results: [] })));
198
+ `], { encoding: 'utf-8', timeout: 5000 });
199
+ if (result.status !== 0 || !result.stdout) return writeWasmJson(instanceRef.value, []);
200
+ try {
201
+ const parsed = JSON.parse(result.stdout);
202
+ return writeWasmJson(instanceRef.value, parsed.results || parsed);
203
+ } catch (_) {
204
+ return writeWasmJson(instanceRef.value, []);
205
+ }
206
+ } catch (e) {
207
+ return writeWasmJson(instanceRef.value, []);
208
+ }
209
+ },
210
+
211
+ host_vec_embed: (textPtr, textLen) => {
212
+ try {
213
+ const text = readWasmStr(instanceRef.value, textPtr, textLen);
214
+ if (!text) return 0n;
215
+ const body = JSON.stringify({ text });
216
+ const result = spawnSync(process.execPath, ['-e', `
217
+ fetch('${RS_LEARN_URL}/embed', { method: 'POST', headers: { 'content-type': 'application/json' }, body: ${JSON.stringify(body)} })
218
+ .then(r => r.text().then(t => process.stdout.write(t)))
219
+ .catch(e => process.stdout.write(''));
220
+ `], { encoding: 'utf-8', timeout: 5000 });
221
+ if (result.status !== 0 || !result.stdout) return 0n;
222
+ return writeWasmStr(instanceRef.value, result.stdout);
223
+ } catch (e) {
224
+ return 0n;
225
+ }
226
+ },
227
+
228
+ host_browser_spawn: (urlPtr, urlLen) => {
229
+ try {
230
+ const url = readWasmStr(instanceRef.value, urlPtr, urlLen);
231
+ const id = BigInt(nextBrowserSessionId++);
232
+ browserSessions.set(id, { url, opened_at: Date.now() });
233
+ return id;
234
+ } catch (e) {
235
+ return 0n;
236
+ }
237
+ },
238
+
239
+ host_browser_eval: (sessionId, codePtr, codeLen) => {
240
+ try {
241
+ const code = readWasmStr(instanceRef.value, codePtr, codeLen);
242
+ const session = browserSessions.get(BigInt(sessionId));
243
+ if (!session) return writeWasmJson(instanceRef.value, { error: 'session not found' });
244
+ return writeWasmJson(instanceRef.value, { ok: false, error: 'browser eval not implemented in JS host; route via spool browser verb' });
245
+ } catch (e) {
246
+ return writeWasmJson(instanceRef.value, { error: e.message });
247
+ }
248
+ },
249
+
250
+ host_browser_close: (sessionId) => {
251
+ try {
252
+ return browserSessions.delete(BigInt(sessionId)) ? 1 : 0;
253
+ } catch (e) {
254
+ return 0;
255
+ }
256
+ },
257
+
258
+ host_exec_js: (codePtr, codeLen, optsPtr, optsLen) => {
259
+ try {
260
+ const code = readWasmStr(instanceRef.value, codePtr, codeLen);
261
+ const optsStr = readWasmStr(instanceRef.value, optsPtr, optsLen);
262
+ const opts = optsStr ? JSON.parse(optsStr) : {};
263
+ const lang = opts.lang || 'nodejs';
264
+ const cwd = opts.cwd || process.cwd();
265
+ const timeoutMs = opts.timeoutMs || 30000;
266
+ let cmd, args;
267
+ if (lang === 'nodejs' || lang === 'js') { cmd = process.execPath; args = ['-e', code]; }
268
+ else if (lang === 'python') { cmd = 'python'; args = ['-c', code]; }
269
+ else if (lang === 'bash') { cmd = 'bash'; args = ['-c', code]; }
270
+ else if (lang === 'deno') { cmd = 'deno'; args = ['eval', code]; }
271
+ else { return writeWasmJson(instanceRef.value, { ok: false, error: `unsupported lang: ${lang}` }); }
272
+ const result = spawnSync(cmd, args, { encoding: 'utf-8', timeout: timeoutMs, cwd, env: process.env });
273
+ return writeWasmJson(instanceRef.value, {
274
+ ok: result.status === 0,
275
+ stdout: result.stdout || '',
276
+ stderr: result.stderr || '',
277
+ exit_code: result.status === null ? -1 : result.status,
278
+ timed_out: result.signal === 'SIGTERM',
279
+ });
280
+ } catch (e) {
281
+ return writeWasmJson(instanceRef.value, { ok: false, error: e.message });
282
+ }
283
+ },
284
+
285
+ host_log: (level, msgPtr, msgLen) => {
286
+ try {
287
+ const msg = readWasmStr(instanceRef.value, msgPtr, msgLen);
288
+ const prefix = level >= 3 ? '[plugkit-wasm:err]' : level >= 2 ? '[plugkit-wasm:warn]' : '[plugkit-wasm]';
289
+ if (level >= 2) console.error(`${prefix} ${msg}`);
290
+ else console.log(`${prefix} ${msg}`);
291
+ return 0;
292
+ } catch (e) {
293
+ return 0;
294
+ }
295
+ },
296
+
297
+ host_now_ms: () => BigInt(Date.now()),
298
+
299
+ host_env_get: (keyPtr, keyLen) => {
300
+ try {
301
+ const key = readWasmStr(instanceRef.value, keyPtr, keyLen);
302
+ if (!key) return 0n;
303
+ const v = process.env[key];
304
+ if (v === undefined) return 0n;
305
+ return writeWasmStr(instanceRef.value, v);
306
+ } catch (e) {
307
+ return 0n;
308
+ }
309
+ },
310
+ };
311
+ }
312
+
313
+ function resolveVersion(instance) {
314
+ try {
315
+ return fs.readFileSync(path.join(os.homedir(), '.claude', 'gm-tools', 'plugkit.version'), 'utf8').trim();
316
+ } catch (_) {}
317
+ try {
318
+ const fn = instance && instance.exports && instance.exports.plugkit_version;
319
+ if (typeof fn === 'function') {
320
+ const result = fn();
321
+ const ptr = Number(result & 0xffffffffn);
322
+ const len = Number(result >> 32n);
323
+ const bytes = new Uint8Array(instance.exports.memory.buffer, ptr, len);
324
+ return new TextDecoder().decode(bytes).trim();
325
+ }
326
+ } catch (_) {}
327
+ return 'unknown';
43
328
  }
44
329
 
45
330
  async function runSpoolWatcher(instance, spoolDir) {
@@ -48,6 +333,7 @@ async function runSpoolWatcher(instance, spoolDir) {
48
333
  fs.mkdirSync(inDir, { recursive: true });
49
334
  fs.mkdirSync(outDir, { recursive: true });
50
335
 
336
+ console.log(`[plugkit-wasm] plugkit v${resolveVersion(instance)} (wasm)`);
51
337
  console.log(`[plugkit-wasm] watching ${inDir}`);
52
338
 
53
339
  const processed = new Set();
@@ -69,22 +355,38 @@ async function runSpoolWatcher(instance, spoolDir) {
69
355
  const verbBytes = new TextEncoder().encode(verb);
70
356
  const bodyBytes = new TextEncoder().encode(body);
71
357
 
72
- const { ptr: verbPtr, len: verbLen } = allocInMemory(instance.exports.memory, verbBytes);
73
- const { ptr: bodyPtr, len: bodyLen } = allocInMemory(instance.exports.memory, bodyBytes);
358
+ const verbPtr = instance.exports.plugkit_alloc(verbBytes.length);
359
+ const bodyPtr = instance.exports.plugkit_alloc(bodyBytes.length);
360
+ new Uint8Array(instance.exports.memory.buffer, verbPtr, verbBytes.length).set(verbBytes);
361
+ new Uint8Array(instance.exports.memory.buffer, bodyPtr, bodyBytes.length).set(bodyBytes);
74
362
 
75
- const result = dispatch(verbPtr, verbLen, bodyPtr, bodyLen);
363
+ const result = dispatch(verbPtr, verbBytes.length, bodyPtr, bodyBytes.length);
76
364
 
77
365
  const ptr = Number(result & 0xffffffffn);
78
366
  const len = Number(result >> 32n);
79
- const resultStr = memReadStr(instance.exports.memory, ptr, len);
367
+ const resultBytes = new Uint8Array(instance.exports.memory.buffer, ptr, len);
368
+ const resultStr = new TextDecoder().decode(resultBytes);
369
+
370
+ const taskBase = path.basename(filePath, path.extname(filePath));
371
+ const outName = dir === '.' ? `${taskBase}.json` : `${verb}-${taskBase}.json`;
372
+ fs.writeFileSync(path.join(outDir, outName), resultStr);
80
373
 
81
- const taskId = Math.random().toString(36).slice(2);
82
- fs.writeFileSync(path.join(outDir, `${taskId}.json`), resultStr);
374
+ try { instance.exports.plugkit_free(verbPtr, verbBytes.length); } catch (_) {}
375
+ try { instance.exports.plugkit_free(bodyPtr, bodyBytes.length); } catch (_) {}
376
+ try { instance.exports.plugkit_free(ptr, len); } catch (_) {}
83
377
 
84
378
  fs.unlinkSync(filePath);
85
379
  processed.delete(key);
86
380
  } catch (e) {
87
381
  console.error(`[plugkit-wasm] error processing ${key}: ${e.message}`);
382
+ const taskBase = path.basename(filePath, path.extname(filePath));
383
+ const relPath = path.relative(inDir, filePath);
384
+ const dir = path.dirname(relPath);
385
+ const verb = dir === '.' ? taskBase : dir;
386
+ const outName = dir === '.' ? `${taskBase}.json` : `${verb}-${taskBase}.json`;
387
+ try {
388
+ fs.writeFileSync(path.join(outDir, outName), JSON.stringify({ ok: false, error: e.message }));
389
+ } catch (_) {}
88
390
  try { fs.unlinkSync(filePath); } catch (_) {}
89
391
  processed.delete(key);
90
392
  }
@@ -108,6 +410,18 @@ async function runSpoolWatcher(instance, spoolDir) {
108
410
  return files;
109
411
  }
110
412
 
413
+ const heartbeatPath = path.join(spoolDir, '.watcher.heartbeat');
414
+ setInterval(() => {
415
+ try { fs.writeFileSync(heartbeatPath, String(Date.now())); } catch (_) {}
416
+ }, 5000);
417
+
418
+ const pollDeadline = setInterval(async () => {
419
+ const existing = walkDir(inDir);
420
+ for (const fullPath of existing) {
421
+ await processFile(fullPath);
422
+ }
423
+ }, 250);
424
+
111
425
  const existing = walkDir(inDir);
112
426
  for (const fullPath of existing) {
113
427
  await processFile(fullPath);
@@ -139,38 +453,20 @@ async function runSpoolWatcher(instance, spoolDir) {
139
453
  const wasmBuffer = fs.readFileSync(wasmPath);
140
454
  const wasmModule = new WebAssembly.Module(wasmBuffer);
141
455
 
142
- const memory = new WebAssembly.Memory({ initial: 256, maximum: 512 });
143
-
144
- const hostFunctions = {
145
- host_fs_read: () => 0,
146
- host_fs_write: () => 0,
147
- host_fs_readdir: () => 0,
148
- host_fs_stat: () => 0,
149
- host_kv_get: () => 0,
150
- host_kv_put: () => 0,
151
- host_kv_query: () => 0,
152
- host_fetch: () => 0,
153
- host_vec_search: () => 0,
154
- host_vec_embed: () => 0,
155
- host_browser_spawn: () => 0,
156
- host_browser_eval: () => 0,
157
- host_browser_close: () => 0,
158
- host_exec_js: () => 0,
159
- host_log: (ptr, len) => { console.log('[host_log]'); return 0; },
160
- host_now_ms: () => BigInt(Date.now()),
161
- host_env_get: () => 0,
162
- };
456
+ const instanceRef = { value: null };
457
+ const hostFunctions = makeHostFunctions(instanceRef);
163
458
 
164
459
  const importObject = {
165
- env: { memory, ...hostFunctions },
460
+ env: hostFunctions,
166
461
  wasi_snapshot_preview1: createWasiShim(),
167
462
  };
168
463
 
169
464
  const instance = new WebAssembly.Instance(wasmModule, importObject);
465
+ instanceRef.value = instance;
170
466
 
171
467
  const args = process.argv.slice(2);
172
468
  if (args.includes('--version')) {
173
- console.log('plugkit v0.1.366 (wasm)');
469
+ console.log(`plugkit v${resolveVersion(instance)} (wasm)`);
174
470
  process.exit(0);
175
471
  }
176
472
 
@@ -178,6 +474,22 @@ async function runSpoolWatcher(instance, spoolDir) {
178
474
  const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
179
475
  const spoolDir = path.join(projectDir, '.gm', 'exec-spool');
180
476
  await runSpoolWatcher(instance, spoolDir);
477
+ } else if (args[0] === 'dispatch') {
478
+ const verb = args[1] || '';
479
+ const body = args[2] || '{}';
480
+ const dispatch = instance.exports.dispatch_verb;
481
+ const verbBytes = new TextEncoder().encode(verb);
482
+ const bodyBytes = new TextEncoder().encode(body);
483
+ const verbPtr = instance.exports.plugkit_alloc(verbBytes.length);
484
+ const bodyPtr = instance.exports.plugkit_alloc(bodyBytes.length);
485
+ new Uint8Array(instance.exports.memory.buffer, verbPtr, verbBytes.length).set(verbBytes);
486
+ new Uint8Array(instance.exports.memory.buffer, bodyPtr, bodyBytes.length).set(bodyBytes);
487
+ const result = dispatch(verbPtr, verbBytes.length, bodyPtr, bodyBytes.length);
488
+ const ptr = Number(result & 0xffffffffn);
489
+ const len = Number(result >> 32n);
490
+ const out = new TextDecoder().decode(new Uint8Array(instance.exports.memory.buffer, ptr, len));
491
+ process.stdout.write(out);
492
+ process.exit(0);
181
493
  } else {
182
494
  console.log('[plugkit-wasm] args:', args.join(' '));
183
495
  process.exit(0);