@ai-ecoverse/slicc-jsh 0.1.0-8 → 0.2.1

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.
@@ -0,0 +1,893 @@
1
+ // src/host/main.mjs
2
+ import { spawn as spawnChild } from "node:child_process";
3
+ import { accessSync, constants as fsConstants, readFileSync, writeSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { constants as osConstants } from "node:os";
6
+ import { delimiter, join, resolve } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import vm from "node:vm";
9
+
10
+ // package.json
11
+ var package_default = {
12
+ name: "@ai-ecoverse/slicc-jsh",
13
+ version: "0.2.1",
14
+ description: "Node.js-compatible runtime for slicc-kernel: the node and jsh commands (abi: js)",
15
+ type: "module",
16
+ license: "Apache-2.0",
17
+ repository: {
18
+ type: "git",
19
+ url: "git+https://github.com/ai-ecoverse/slicc-jsh.git"
20
+ },
21
+ homepage: "https://github.com/ai-ecoverse/slicc-jsh",
22
+ bugs: {
23
+ url: "https://github.com/ai-ecoverse/slicc-jsh/issues"
24
+ },
25
+ bin: {
26
+ jsh: "dist/host/jsh.mjs"
27
+ },
28
+ engines: {
29
+ node: ">=22",
30
+ "slicc-kernel": ">=1.53.2"
31
+ },
32
+ publishConfig: {
33
+ access: "public",
34
+ provenance: true
35
+ },
36
+ fledgling: {
37
+ provider: "github",
38
+ workflow: "release.yml",
39
+ repo: "ai-ecoverse/slicc-jsh",
40
+ publish: true
41
+ },
42
+ files: [
43
+ "LICENSE",
44
+ "NOTICE",
45
+ "README.md",
46
+ "dist"
47
+ ],
48
+ slicc: {
49
+ commands: {
50
+ node: {
51
+ abi: "js",
52
+ module: "dist/node.mjs",
53
+ argv0: "node"
54
+ },
55
+ jsh: {
56
+ abi: "js",
57
+ module: "dist/jsh.mjs",
58
+ argv0: "jsh"
59
+ }
60
+ },
61
+ binfmt: {
62
+ ".jsh": "jsh"
63
+ }
64
+ },
65
+ scripts: {
66
+ build: "node scripts/build.mjs && node scripts/build-host.mjs",
67
+ prepack: "npm run build",
68
+ prepare: "npm run build",
69
+ lint: "node scripts/lint.mjs",
70
+ test: "npm run test:golden && npm run test:jsh && npm run test:integration",
71
+ "test:golden": "node --max-old-space-size=512 scripts/golden.mjs check",
72
+ "test:integration": "node --max-old-space-size=512 --test --test-timeout=120000 test/integration/*.test.mjs",
73
+ "test:cert": "node --max-old-space-size=512 test/integration/cert/run.mjs",
74
+ "test:node-parallel": "node --max-old-space-size=512 test/node-parallel/run.mjs",
75
+ "golden:record": "node --max-old-space-size=512 scripts/golden.mjs record",
76
+ "test:jsh": "node --max-old-space-size=512 scripts/jsh-golden.mjs check",
77
+ "jsh:record": "node --max-old-space-size=512 scripts/jsh-golden.mjs record",
78
+ release: "semantic-release",
79
+ trust: "npx fledgling sync -y --skip-publish",
80
+ "trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
81
+ },
82
+ devDependencies: {
83
+ "@ai-ecoverse/slicc-kernel": "1.59.0",
84
+ "@ai-ecoverse/wasi-pnpm": "12.9.1-8",
85
+ "abort-controller": "3.0.0",
86
+ acorn: "8.19.0",
87
+ esbuild: "0.28.2",
88
+ "node-inspect-extracted": "3.3.4",
89
+ process: "0.11.10",
90
+ "readable-stream": "4.8.0",
91
+ "semantic-release": "25.0.9",
92
+ string_decoder: "1.3.0",
93
+ ws: "8.22.0"
94
+ }
95
+ };
96
+
97
+ // src/jsh/parse-flags.mjs
98
+ function parseFlags(argv) {
99
+ const positional = [];
100
+ const flags = {};
101
+ const passthrough = [];
102
+ const set = (key, value) => {
103
+ if (key in flags) {
104
+ const prev = flags[key];
105
+ if (Array.isArray(prev)) prev.push(String(value));
106
+ else flags[key] = [String(prev), String(value)];
107
+ } else {
108
+ flags[key] = value;
109
+ }
110
+ };
111
+ let i = 2;
112
+ while (i < argv.length) {
113
+ const arg = argv[i];
114
+ if (arg === "--") {
115
+ passthrough.push(...argv.slice(i + 1));
116
+ break;
117
+ }
118
+ if (arg.startsWith("--")) {
119
+ const body = arg.slice(2);
120
+ const eq = body.indexOf("=");
121
+ if (eq !== -1) {
122
+ set(body.slice(0, eq), body.slice(eq + 1));
123
+ i++;
124
+ continue;
125
+ }
126
+ const next = argv[i + 1];
127
+ if (next !== void 0 && !next.startsWith("-")) {
128
+ set(body, next);
129
+ i += 2;
130
+ continue;
131
+ }
132
+ set(body, true);
133
+ i++;
134
+ continue;
135
+ }
136
+ if (arg.startsWith("-") && arg.length > 1) {
137
+ for (const ch of arg.slice(1)) set(ch, true);
138
+ i++;
139
+ continue;
140
+ }
141
+ positional.push(arg);
142
+ i++;
143
+ }
144
+ const subcommand = positional.length > 0 && /^[a-z][\w-]*$/i.test(positional[0]) ? positional[0] : null;
145
+ return { positional, flags, subcommand, passthrough };
146
+ }
147
+ function attachParseFlags(argv) {
148
+ if (Object.prototype.hasOwnProperty.call(argv, "parseFlags")) return argv;
149
+ Object.defineProperty(argv, "parseFlags", {
150
+ value: () => parseFlags(argv),
151
+ enumerable: false,
152
+ writable: false,
153
+ configurable: true
154
+ });
155
+ return argv;
156
+ }
157
+
158
+ // src/jsh/sliccy/exec.mjs
159
+ var SIGNALS = { SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15 };
160
+ function killExitCode(sig = "SIGTERM") {
161
+ const n = typeof sig === "number" ? sig : SIGNALS[sig] ?? 15;
162
+ return 128 + n;
163
+ }
164
+ function createExec(engine2) {
165
+ const shellArgv = (command, args = []) => [...engine2.shell, command, "jsh", ...args];
166
+ const run = (argv, stdin) => engine2.spawn(argv, { stdin }).done;
167
+ const exec = (command) => {
168
+ if (typeof command !== "string") throw new TypeError("exec(command): command must be a string");
169
+ return run(shellArgv(command));
170
+ };
171
+ exec.spawn = (argv) => {
172
+ if (!Array.isArray(argv) || argv.length === 0) {
173
+ throw new TypeError("exec.spawn(argv): argv must be a non-empty array");
174
+ }
175
+ return run(argv.map(String));
176
+ };
177
+ exec.start = (commandOrArgv, opts = {}) => {
178
+ const argv = Array.isArray(commandOrArgv) ? [...commandOrArgv.map(String), ...(opts.args ?? []).map(String)] : shellArgv(String(commandOrArgv), (opts.args ?? []).map(String));
179
+ const chunks = [];
180
+ let child = null;
181
+ let killed = false;
182
+ let resolveDone;
183
+ let rejectDone;
184
+ const done = new Promise((resolve2, reject) => {
185
+ resolveDone = resolve2;
186
+ rejectDone = reject;
187
+ });
188
+ const fire = () => {
189
+ if (child || killed) return;
190
+ const stdin = chunks.length > 0 ? chunks.join("") : opts.stdin;
191
+ child = engine2.spawn(argv, { stdin });
192
+ child.done.then(resolveDone, rejectDone);
193
+ };
194
+ return {
195
+ kill(sig) {
196
+ if (child) return Promise.resolve(child.kill(sig ?? "SIGTERM")).then(() => true);
197
+ killed = true;
198
+ resolveDone({ stdout: "", stderr: "", exitCode: killExitCode(sig) });
199
+ return Promise.resolve(true);
200
+ },
201
+ stdin: {
202
+ write(chunk) {
203
+ if (!child && !killed) chunks.push(String(chunk));
204
+ },
205
+ end: () => fire()
206
+ },
207
+ done
208
+ };
209
+ };
210
+ exec.exec = exec;
211
+ return exec;
212
+ }
213
+ function dirnameOf(path) {
214
+ if (!path) return "";
215
+ const idx = path.lastIndexOf("/");
216
+ if (idx < 0) return "";
217
+ if (idx === 0) return "/";
218
+ return path.slice(0, idx);
219
+ }
220
+ function joinChild(dir, name) {
221
+ if (dir === "") return name;
222
+ if (dir === "/") return `/${name}`;
223
+ return `${dir}/${name}`;
224
+ }
225
+ function createSkill({ argv, fs, exec }) {
226
+ const dir = dirnameOf(argv[1] ?? "");
227
+ const refs = joinChild(dir, "references");
228
+ const assets = joinChild(dir, "assets");
229
+ const configPath = joinChild(dir, ".config");
230
+ async function readConfig() {
231
+ let text;
232
+ try {
233
+ if (!fs.existsSync(configPath)) return null;
234
+ text = await fs.promises.readFile(configPath, "utf8");
235
+ } catch {
236
+ return null;
237
+ }
238
+ if (!String(text).trim()) return null;
239
+ let parsed;
240
+ try {
241
+ parsed = JSON.parse(text);
242
+ } catch (err) {
243
+ throw new Error(`skill.config(): failed to parse ${configPath}: ${err?.message ?? err}`);
244
+ }
245
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
246
+ throw new Error(`skill.config(): ${configPath} must contain a JSON object`);
247
+ }
248
+ async function config(updates) {
249
+ const existing = await readConfig();
250
+ if (updates === void 0) return existing;
251
+ if (updates === null || typeof updates !== "object" || Array.isArray(updates)) {
252
+ throw new TypeError("skill.config(updates): updates must be a plain object");
253
+ }
254
+ const merged = { ...existing ?? {}, ...updates };
255
+ await fs.promises.writeFile(configPath, `${JSON.stringify(merged, null, 2)}
256
+ `);
257
+ return merged;
258
+ }
259
+ async function token(providerId) {
260
+ if (typeof providerId !== "string" || !providerId.trim()) {
261
+ throw new TypeError("skill.token(providerId): providerId must be a non-empty string");
262
+ }
263
+ const { stdout, stderr, exitCode } = await exec.spawn(["oauth-token", providerId]);
264
+ if (exitCode !== 0) {
265
+ const msg = stderr.trim() || `oauth-token exited with code ${exitCode}`;
266
+ throw new Error(`skill.token('${providerId}'): ${msg}`);
267
+ }
268
+ return stdout.replace(/\r?\n+$/, "");
269
+ }
270
+ return Object.freeze({ dir, refs, assets, config, token });
271
+ }
272
+
273
+ // src/jsh/sliccy/http.mjs
274
+ var HttpError = class extends Error {
275
+ constructor(status, statusText, url, body) {
276
+ const detail = typeof body === "string" && body ? `: ${body.slice(0, 200)}` : body && typeof body === "object" ? `: ${safeJson(body).slice(0, 200)}` : "";
277
+ super(`HTTP ${status} ${statusText} ${url}${detail}`);
278
+ this.name = "HttpError";
279
+ this.status = status;
280
+ this.statusText = statusText;
281
+ this.url = url;
282
+ this.body = body;
283
+ }
284
+ };
285
+ function safeJson(value) {
286
+ try {
287
+ return JSON.stringify(value);
288
+ } catch {
289
+ return String(value);
290
+ }
291
+ }
292
+ var DEFAULT_BACKOFF_BASE_MS = 500;
293
+ function buildUrl(baseUrl, path, params) {
294
+ let url;
295
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(path)) url = path;
296
+ else if (baseUrl) {
297
+ const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
298
+ url = `${base}${path.startsWith("/") ? path : `/${path}`}`;
299
+ } else url = path;
300
+ if (!params) return url;
301
+ const qs = [];
302
+ const push = (k, v) => qs.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
303
+ for (const [k, v] of Object.entries(params)) {
304
+ if (v === void 0 || v === null) continue;
305
+ if (Array.isArray(v)) {
306
+ for (const item of v) if (item !== void 0 && item !== null) push(k, item);
307
+ } else push(k, v);
308
+ }
309
+ if (qs.length === 0) return url;
310
+ return url + (url.includes("?") ? "&" : "?") + qs.join("&");
311
+ }
312
+ function isJsonContentType(ct) {
313
+ if (!ct) return false;
314
+ const lower = ct.toLowerCase();
315
+ return lower.startsWith("application/json") || /[+/]json(;|$|\s)/.test(lower);
316
+ }
317
+ function parseRetryAfter(value) {
318
+ const trimmed = value?.trim();
319
+ if (!trimmed) return null;
320
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
321
+ const seconds = Number(trimmed);
322
+ if (Number.isFinite(seconds) && seconds >= 0) return Math.round(seconds * 1e3);
323
+ }
324
+ const date = Date.parse(trimmed);
325
+ if (Number.isFinite(date)) return Math.max(0, date - Date.now());
326
+ return null;
327
+ }
328
+ async function readBody(resp) {
329
+ if (isJsonContentType(resp.headers.get("content-type"))) {
330
+ const text = await resp.text();
331
+ if (!text) return null;
332
+ try {
333
+ return JSON.parse(text);
334
+ } catch {
335
+ return text;
336
+ }
337
+ }
338
+ return resp.text();
339
+ }
340
+ function serializeBody(body, headers) {
341
+ if (body === void 0 || body === null) return void 0;
342
+ if (typeof body === "string") return body;
343
+ if (body instanceof ArrayBuffer || ArrayBuffer.isView(body) || typeof Blob !== "undefined" && body instanceof Blob || typeof FormData !== "undefined" && body instanceof FormData || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || typeof ReadableStream !== "undefined" && body instanceof ReadableStream) {
344
+ return body;
345
+ }
346
+ if (typeof body === "object") {
347
+ if (!Object.keys(headers).some((k) => k.toLowerCase() === "content-type")) {
348
+ headers["Content-Type"] = "application/json";
349
+ }
350
+ return JSON.stringify(body);
351
+ }
352
+ return String(body);
353
+ }
354
+ function createHttp({ fetch, sleep = (ms) => new Promise((r) => setTimeout(r, ms)) }) {
355
+ function makeClient(config = {}) {
356
+ const retryOn = new Set(config.retry?.on ?? []);
357
+ const maxAttempts = Math.max(1, Math.trunc(config.retry?.maxAttempts ?? 1));
358
+ async function request(method, path, opts = {}) {
359
+ if (typeof fetch !== "function") throw new Error("sliccy:http: fetch is not available");
360
+ const url = buildUrl(config.baseUrl, path, opts.params);
361
+ const headers = { ...config.headers ?? {}, ...opts.headers ?? {} };
362
+ if (config.token) {
363
+ const tok = await config.token({ method, path, url });
364
+ if (tok && !Object.keys(headers).some((k) => k.toLowerCase() === "authorization")) {
365
+ headers.Authorization = `Bearer ${tok}`;
366
+ }
367
+ }
368
+ const body = serializeBody(opts.body, headers);
369
+ const init = { method, headers };
370
+ if (body !== void 0) init.body = body;
371
+ for (let attempt = 0; ; attempt++) {
372
+ const timeoutCtl = config.timeoutMs ? new AbortController() : null;
373
+ const timeoutId = timeoutCtl ? setTimeout(() => timeoutCtl.abort(new Error("timeout")), config.timeoutMs) : null;
374
+ const signal = opts.signal && timeoutCtl ? AbortSignal.any([opts.signal, timeoutCtl.signal]) : opts.signal ?? timeoutCtl?.signal;
375
+ let resp;
376
+ try {
377
+ resp = await fetch(url, signal ? { ...init, signal } : init);
378
+ } finally {
379
+ if (timeoutId !== null) clearTimeout(timeoutId);
380
+ }
381
+ if (resp.ok) {
382
+ const respBody = await readBody(resp);
383
+ if (opts.raw) {
384
+ return {
385
+ body: respBody,
386
+ headers: Object.fromEntries(resp.headers.entries()),
387
+ status: resp.status
388
+ };
389
+ }
390
+ return respBody;
391
+ }
392
+ if (attempt + 1 >= maxAttempts || !retryOn.has(resp.status)) {
393
+ const errBody = await readBody(resp).catch(() => null);
394
+ throw new HttpError(resp.status, resp.statusText, url, errBody);
395
+ }
396
+ const retryAfter = parseRetryAfter(resp.headers.get("retry-after"));
397
+ await sleep(retryAfter ?? DEFAULT_BACKOFF_BASE_MS * 2 ** attempt);
398
+ }
399
+ }
400
+ return Object.freeze({
401
+ get: (path, opts) => request("GET", path, opts),
402
+ post: (path, opts) => request("POST", path, opts),
403
+ put: (path, opts) => request("PUT", path, opts),
404
+ patch: (path, opts) => request("PATCH", path, opts),
405
+ delete: (path, opts) => request("DELETE", path, opts)
406
+ });
407
+ }
408
+ return Object.freeze({ client: makeClient, HttpError });
409
+ }
410
+
411
+ // src/jsh/sliccy/pure.mjs
412
+ var ANSI = {
413
+ reset: "\x1B[0m",
414
+ green: "\x1B[32m",
415
+ red: "\x1B[31m",
416
+ yellow: "\x1B[33m",
417
+ gray: "\x1B[90m",
418
+ bold: "\x1B[1m",
419
+ cyan: "\x1B[36m",
420
+ dim: "\x1B[2m"
421
+ };
422
+ function colorEnabled(env, stdoutIsTTY) {
423
+ const force = env?.FORCE_COLOR;
424
+ if (force !== void 0) return force !== "" && force !== "0" && force !== "false";
425
+ if (env?.NO_COLOR) return false;
426
+ return !!stdoutIsTTY;
427
+ }
428
+ function createColor(enabled) {
429
+ const wrap = (code) => (s) => enabled ? `${code}${s}${ANSI.reset}` : String(s);
430
+ return Object.freeze({
431
+ enabled,
432
+ green: wrap(ANSI.green),
433
+ red: wrap(ANSI.red),
434
+ yellow: wrap(ANSI.yellow),
435
+ gray: wrap(ANSI.gray),
436
+ bold: wrap(ANSI.bold),
437
+ cyan: wrap(ANSI.cyan),
438
+ dim: wrap(ANSI.dim)
439
+ });
440
+ }
441
+ function createCli({ writeStdout, writeStderr, exit, color }) {
442
+ const toLine = (v) => {
443
+ if (typeof v === "string") return v;
444
+ if (v instanceof Error) return v.message;
445
+ if (v === null || v === void 0) return String(v);
446
+ try {
447
+ return JSON.stringify(v);
448
+ } catch {
449
+ return String(v);
450
+ }
451
+ };
452
+ const prefixed = (paint, prefix, text, fallback) => {
453
+ if (prefix === void 0) return `${paint(`${fallback}:`)} ${text}
454
+ `;
455
+ if (prefix === "") return `${paint(text)}
456
+ `;
457
+ return `${paint(`${prefix}:`)} ${text}
458
+ `;
459
+ };
460
+ const prefixOf = (opts) => typeof opts === "object" && opts !== null && "prefix" in opts ? opts.prefix : void 0;
461
+ return Object.freeze({
462
+ die(msg, opts) {
463
+ const code = typeof opts === "number" ? opts : opts?.exitCode ?? 1;
464
+ writeStderr(prefixed(color.red, prefixOf(opts), toLine(msg), "Error"));
465
+ exit(code);
466
+ throw new Error("unreachable");
467
+ },
468
+ out(value) {
469
+ if (typeof value === "string") {
470
+ writeStdout(value.endsWith("\n") ? value : `${value}
471
+ `);
472
+ return;
473
+ }
474
+ try {
475
+ writeStdout(`${JSON.stringify(value, null, 2)}
476
+ `);
477
+ } catch {
478
+ writeStdout(`${String(value)}
479
+ `);
480
+ }
481
+ },
482
+ warn(msg, opts) {
483
+ writeStderr(prefixed(color.yellow, prefixOf(opts), toLine(msg), "Warning"));
484
+ },
485
+ help(text) {
486
+ writeStdout(text.endsWith("\n") ? text : `${text}
487
+ `);
488
+ exit(0);
489
+ throw new Error("unreachable");
490
+ }
491
+ });
492
+ }
493
+ var ANSI_RE = /\u001b\[[0-9;]*m/g;
494
+ var stripAnsi = (s) => s.replace(ANSI_RE, "");
495
+ var visibleLength = (s) => stripAnsi(s).length;
496
+ var pad2 = (n) => n < 10 ? `0${n}` : String(n);
497
+ function trunc(s, n) {
498
+ const text = String(s ?? "");
499
+ if (n <= 0) return "";
500
+ if (visibleLength(text) <= n) return text;
501
+ if (n <= 1) return text.slice(0, n);
502
+ return `${stripAnsi(text).slice(0, n - 1)}\u2026`;
503
+ }
504
+ function col(s, width) {
505
+ const text = String(s ?? "");
506
+ const vis = visibleLength(text);
507
+ if (vis === width) return text;
508
+ if (vis > width) return trunc(text, width);
509
+ return text + " ".repeat(width - vis);
510
+ }
511
+ function table(rows, widths) {
512
+ if (!rows.length) return "";
513
+ const colCount = Math.max(...rows.map((r) => r.length));
514
+ const computed = [];
515
+ for (let i = 0; i < colCount; i++) {
516
+ if (widths && widths[i] !== void 0) {
517
+ computed[i] = widths[i];
518
+ } else {
519
+ let max = 0;
520
+ for (const r of rows) max = Math.max(max, visibleLength(i < r.length ? String(r[i] ?? "") : ""));
521
+ computed[i] = max;
522
+ }
523
+ }
524
+ return rows.map(
525
+ (r) => computed.map((w, i) => col(i < r.length ? String(r[i] ?? "") : "", w)).join(" ").replace(/\s+$/, "")
526
+ ).join("\n");
527
+ }
528
+ function fmtDate(value, style = "short") {
529
+ const d = value instanceof Date ? value : new Date(value);
530
+ if (Number.isNaN(d.getTime())) return String(value);
531
+ if (style === "iso") return d.toISOString();
532
+ if (style === "locale") return new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(d);
533
+ if (style === "human") {
534
+ const diff = Date.now() - d.getTime();
535
+ const abs = Math.abs(diff);
536
+ if (abs < 6e4) return diff >= 0 ? "just now" : "in a moment";
537
+ const tense = (n, u) => diff >= 0 ? `${n} ${u}${n === 1 ? "" : "s"} ago` : `in ${n} ${u}${n === 1 ? "" : "s"}`;
538
+ if (abs < 36e5) return tense(Math.round(abs / 6e4), "minute");
539
+ if (abs < 864e5) return tense(Math.round(abs / 36e5), "hour");
540
+ if (abs < 26298e5) return tense(Math.round(abs / 864e5), "day");
541
+ if (abs < 315576e5) return tense(Math.round(abs / 26298e5), "month");
542
+ return tense(Math.round(abs / 315576e5), "year");
543
+ }
544
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
545
+ }
546
+ var fmt = Object.freeze({ trunc, col, table, date: fmtDate });
547
+ var DURATION_UNITS_MS = {
548
+ ms: 1,
549
+ s: 1e3,
550
+ m: 6e4,
551
+ h: 36e5,
552
+ d: 864e5,
553
+ w: 6048e5,
554
+ M: 26298e5,
555
+ y: 315576e5
556
+ };
557
+ function parseDuration(spec) {
558
+ if (typeof spec === "number" && Number.isFinite(spec)) return Math.trunc(spec);
559
+ if (typeof spec !== "string") throw new TypeError("time.parseDuration: spec must be string or number");
560
+ const m = /^([0-9]+(?:\.[0-9]+)?)\s*(ms|s|m|h|d|w|M|y)?$/.exec(spec.trim());
561
+ if (!m) throw new RangeError(`time.parseDuration: unrecognized spec "${spec}"`);
562
+ return Math.trunc(Number(m[1]) * DURATION_UNITS_MS[m[2] ?? "ms"]);
563
+ }
564
+ var time = Object.freeze({
565
+ parseDuration,
566
+ ago(spec, from = /* @__PURE__ */ new Date()) {
567
+ return new Date(from.getTime() - parseDuration(spec));
568
+ },
569
+ range(spec, from = /* @__PURE__ */ new Date()) {
570
+ const end = new Date(from.getTime());
571
+ return { start: new Date(end.getTime() - parseDuration(spec)), end };
572
+ },
573
+ future(spec, from = /* @__PURE__ */ new Date()) {
574
+ const start = new Date(from.getTime());
575
+ return { start, end: new Date(start.getTime() + parseDuration(spec)) };
576
+ },
577
+ gmailDate(spec, from = /* @__PURE__ */ new Date()) {
578
+ const d = new Date(from.getTime() - parseDuration(spec));
579
+ return `${d.getFullYear()}/${pad2(d.getMonth() + 1)}/${pad2(d.getDate())}`;
580
+ }
581
+ });
582
+ async function pool(concurrency, items, fn) {
583
+ const n = Math.max(1, Math.trunc(concurrency) || 1);
584
+ const results = new Array(items.length);
585
+ let next = 0;
586
+ const worker = async () => {
587
+ for (; ; ) {
588
+ const i = next++;
589
+ if (i >= items.length) return;
590
+ results[i] = await fn(items[i], i);
591
+ }
592
+ };
593
+ const workers = [];
594
+ for (let w = 0; w < Math.min(n, items.length); w++) workers.push(worker());
595
+ await Promise.all(workers);
596
+ return results;
597
+ }
598
+
599
+ // src/jsh/sliccy/index.mjs
600
+ var SLICC_ONLY = /* @__PURE__ */ new Set(["agent", "usb", "serial", "hid", "computer"]);
601
+ function isNotFound(err, request) {
602
+ return err?.code === "MODULE_NOT_FOUND" && String(err.message).includes(`'${request}'`);
603
+ }
604
+ function createSliccyResolver({ engine: engine2, process: process2, require: require2 }) {
605
+ let color;
606
+ let exec;
607
+ const getColor = () => {
608
+ color ??= createColor(colorEnabled(process2.env, engine2.stdoutIsTTY));
609
+ return color;
610
+ };
611
+ const getExec = () => {
612
+ exec ??= createExec(engine2);
613
+ return exec;
614
+ };
615
+ const factories = {
616
+ cli: () => createCli({
617
+ writeStdout: engine2.writeStdout,
618
+ writeStderr: engine2.writeStderr,
619
+ exit: (code) => process2.exit(code),
620
+ color: getColor()
621
+ }),
622
+ color: getColor,
623
+ exec: getExec,
624
+ fmt: () => fmt,
625
+ http: () => createHttp({ fetch: engine2.fetch }),
626
+ pool: () => pool,
627
+ skill: () => createSkill({ argv: process2.argv, fs: require2("fs"), exec: getExec() }),
628
+ time: () => time
629
+ };
630
+ const cache = /* @__PURE__ */ new Map();
631
+ const lookups = [require2, engine2.selfRequire].filter(Boolean);
632
+ return function requireSliccy(id) {
633
+ const name = id.slice("sliccy:".length);
634
+ if (name === "") throw new Error("require('sliccy:'): empty sliccy: module name");
635
+ if (cache.has(name)) return cache.get(name);
636
+ let value;
637
+ if (Object.prototype.hasOwnProperty.call(factories, name)) {
638
+ value = factories[name]();
639
+ } else {
640
+ value = findPackage(name, lookups);
641
+ }
642
+ if (value === void 0) {
643
+ if (SLICC_ONLY.has(name)) {
644
+ throw new Error(`require('${id}'): sliccy:${name} is only available inside SLICC`);
645
+ }
646
+ const known = Object.keys(factories).sort().join(", ");
647
+ throw new Error(
648
+ `require('${id}'): unknown sliccy: module '${name}'. Known names: ${known}. Install @ai-ecoverse/sliccy-${name} to provide it.`
649
+ );
650
+ }
651
+ cache.set(name, value);
652
+ return value;
653
+ };
654
+ }
655
+ function findPackage(name, lookups) {
656
+ for (const pkg of [`@ai-ecoverse/sliccy-${name}`, `sliccy-${name}`]) {
657
+ for (const req of lookups) {
658
+ try {
659
+ return req(pkg);
660
+ } catch (err) {
661
+ if (!isNotFound(err, pkg)) throw err;
662
+ }
663
+ }
664
+ }
665
+ return void 0;
666
+ }
667
+
668
+ // src/jsh/run.mjs
669
+ var JSH_VERSION = package_default.version;
670
+ var JSH_PARAMS = Object.freeze([
671
+ "process",
672
+ "console",
673
+ "require",
674
+ "module",
675
+ "exports",
676
+ "fetch",
677
+ "__dirname",
678
+ "__filename"
679
+ ]);
680
+ var JSH_USAGE = `Usage: jsh [--version | --help] <script.jsh> [args...]
681
+
682
+ Runs a .jsh script: the body of an async function with process, console,
683
+ require, module, exports, fetch, __dirname and __filename in scope.
684
+ `;
685
+ function parseJshArgv(args) {
686
+ let i = 0;
687
+ const first = args[0];
688
+ if (first === "--version" || first === "-v") return { action: "version" };
689
+ if (first === "--help" || first === "-h") return { action: "help" };
690
+ if (first === "--") i = 1;
691
+ else if (first?.startsWith("-") && first !== "-") {
692
+ return { action: "error", message: `jsh: bad option: ${first}`, status: 9 };
693
+ }
694
+ if (i >= args.length) return { action: "usage" };
695
+ return { action: "run", script: args[i], args: args.slice(i + 1) };
696
+ }
697
+ function prepareSource(source) {
698
+ let text = source.charCodeAt(0) === 65279 ? source.slice(1) : source;
699
+ if (text.startsWith("#!")) {
700
+ const nl = text.indexOf("\n");
701
+ text = nl === -1 ? "" : text.slice(nl);
702
+ }
703
+ return text;
704
+ }
705
+ function wrapSource(body) {
706
+ return `(async function (${JSH_PARAMS.join(", ")}) {${body}
707
+ })`;
708
+ }
709
+ function dirnameOf2(path) {
710
+ const idx = path.lastIndexOf("/");
711
+ if (idx <= 0) return "/";
712
+ return path.slice(0, idx);
713
+ }
714
+ function wrapRequire(baseRequire, requireSliccy, module) {
715
+ const require2 = (id) => typeof id === "string" && id.startsWith("sliccy:") ? requireSliccy(id) : baseRequire(id);
716
+ const resolve2 = (id, options) => typeof id === "string" && id.startsWith("sliccy:") ? id : baseRequire.resolve(id, options);
717
+ resolve2.paths = (id) => baseRequire.resolve.paths?.(id) ?? null;
718
+ require2.resolve = resolve2;
719
+ require2.cache = baseRequire.cache;
720
+ require2.main = module;
721
+ return require2;
722
+ }
723
+ async function runJsh({ filename, engine: engine2, process: process2, console: console2 }) {
724
+ let source;
725
+ try {
726
+ source = engine2.readSource(filename);
727
+ } catch (err) {
728
+ engine2.writeStderr(`jsh: cannot open ${filename}: ${err?.code ?? err?.message ?? err}
729
+ `);
730
+ return engine2.exit(1);
731
+ }
732
+ attachParseFlags(process2.argv);
733
+ try {
734
+ process2.versions.jsh = JSH_VERSION;
735
+ } catch {
736
+ }
737
+ const dirname = dirnameOf2(filename);
738
+ const module = {
739
+ id: ".",
740
+ filename,
741
+ path: dirname,
742
+ exports: {},
743
+ loaded: false,
744
+ children: [],
745
+ paths: []
746
+ };
747
+ const baseRequire = engine2.createRequire(filename);
748
+ const requireSliccy = createSliccyResolver({ engine: engine2, process: process2, require: baseRequire });
749
+ const require2 = wrapRequire(baseRequire, requireSliccy, module);
750
+ try {
751
+ const fn = engine2.compile(prepareSource(source), filename);
752
+ await fn(process2, console2, require2, module, module.exports, engine2.fetch, dirname, filename);
753
+ module.loaded = true;
754
+ } catch (err) {
755
+ if (engine2.isExit(err)) return engine2.exit(err.code);
756
+ engine2.writeStderr(`${err?.stack ?? err}
757
+ `);
758
+ return engine2.exit(1);
759
+ }
760
+ return void 0;
761
+ }
762
+
763
+ // src/host/main.mjs
764
+ var writeFd = (fd, text) => {
765
+ const bytes = Buffer.from(String(text));
766
+ let off = 0;
767
+ while (off < bytes.length) {
768
+ try {
769
+ off += writeSync(fd, bytes, off);
770
+ } catch (err) {
771
+ if (err?.code === "EAGAIN") continue;
772
+ throw err;
773
+ }
774
+ }
775
+ };
776
+ function findOnPath(name) {
777
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
778
+ if (!dir) continue;
779
+ const candidate = join(dir, name);
780
+ try {
781
+ accessSync(candidate, fsConstants.X_OK);
782
+ return candidate;
783
+ } catch {
784
+ }
785
+ }
786
+ return null;
787
+ }
788
+ function silenceLoaderWarning() {
789
+ const emitWarning = process.emitWarning;
790
+ process.emitWarning = function filtered(warning, ...rest) {
791
+ const text = typeof warning === "string" ? warning : warning?.message;
792
+ if (typeof text === "string" && text.includes("USE_MAIN_CONTEXT_DEFAULT_LOADER")) return;
793
+ return emitWarning.call(this, warning, ...rest);
794
+ };
795
+ }
796
+ function spawn(argv, { stdin } = {}) {
797
+ let child;
798
+ const done = new Promise((resolveDone) => {
799
+ let settled = false;
800
+ const finish = (result) => {
801
+ if (!settled) {
802
+ settled = true;
803
+ resolveDone(result);
804
+ }
805
+ };
806
+ const out = [];
807
+ const err = [];
808
+ child = spawnChild(argv[0], argv.slice(1), {
809
+ cwd: process.cwd(),
810
+ env: process.env,
811
+ stdio: [stdin === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
812
+ });
813
+ child.stdout.on("data", (c) => out.push(c));
814
+ child.stderr.on("data", (c) => err.push(c));
815
+ child.on("error", (e) => {
816
+ if (e?.code === "ENOENT") {
817
+ finish({ stdout: "", stderr: `${argv[0]}: command not found
818
+ `, exitCode: 127 });
819
+ } else {
820
+ finish({ stdout: "", stderr: `${argv[0]}: ${e?.message ?? e}
821
+ `, exitCode: 126 });
822
+ }
823
+ });
824
+ child.on("close", (code, signal) => {
825
+ finish({
826
+ stdout: Buffer.concat(out).toString("utf8"),
827
+ stderr: Buffer.concat(err).toString("utf8"),
828
+ exitCode: code ?? 128 + (osConstants.signals[signal] ?? 0)
829
+ });
830
+ });
831
+ if (stdin !== void 0) {
832
+ child.stdin.on("error", () => {
833
+ });
834
+ child.stdin.end(stdin);
835
+ }
836
+ });
837
+ return { kill: (sig = "SIGTERM") => child.kill(sig), done };
838
+ }
839
+ var selfRequire = null;
840
+ try {
841
+ selfRequire = createRequire(fileURLToPath(import.meta.url));
842
+ } catch {
843
+ selfRequire = null;
844
+ }
845
+ var engine = {
846
+ readSource: (filename) => readFileSync(filename, "utf8"),
847
+ compile: (body, filename) => vm.runInThisContext(wrapSource(body), {
848
+ filename,
849
+ importModuleDynamically: vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER
850
+ }),
851
+ createRequire: (filename) => createRequire(filename),
852
+ selfRequire,
853
+ writeStdout: (s) => writeFd(1, s),
854
+ writeStderr: (s) => writeFd(2, s),
855
+ get stdoutIsTTY() {
856
+ return !!process.stdout.isTTY;
857
+ },
858
+ spawn,
859
+ shell: [findOnPath("bash") ?? "sh", "-c"],
860
+ fetch: globalThis.fetch,
861
+ isExit: () => false,
862
+ exit: (code) => process.exit(code)
863
+ };
864
+ async function main() {
865
+ const parsed = parseJshArgv(process.argv.slice(2));
866
+ if (parsed.action === "version") {
867
+ writeFd(1, `${JSH_VERSION}
868
+ `);
869
+ return;
870
+ }
871
+ if (parsed.action === "help") {
872
+ writeFd(1, JSH_USAGE);
873
+ return;
874
+ }
875
+ if (parsed.action === "usage") {
876
+ writeFd(2, JSH_USAGE);
877
+ process.exit(2);
878
+ }
879
+ if (parsed.action === "error") {
880
+ writeFd(2, `${parsed.message}
881
+ ${JSH_USAGE}`);
882
+ process.exit(parsed.status);
883
+ }
884
+ const filename = resolve(parsed.script);
885
+ process.argv = [process.execPath, filename, ...parsed.args];
886
+ silenceLoaderWarning();
887
+ await runJsh({ filename, engine, process, console });
888
+ }
889
+ main().catch((err) => {
890
+ writeFd(2, `${err?.stack ?? err}
891
+ `);
892
+ process.exit(1);
893
+ });