@struktoai/mirage-cli 0.0.3-alpha.0 → 0.0.4
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/README.md +1 -1
- package/dist/bin/mirage.js +152 -14
- package/dist/bin/mirage.js.map +1 -1
- package/dist/{chunk-IMRNFGEA.js → chunk-TMXBYKRM.js} +186 -55
- package/dist/chunk-TMXBYKRM.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-IMRNFGEA.js.map +0 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ await ws.execute('cat /s3/events/2026-05-06.parquet | jq .user')
|
|
|
57
57
|
## About
|
|
58
58
|
|
|
59
59
|
- **One interface instead of N SDKs and M MCPs.** Every service speaks the same filesystem semantics, and pipelines compose across services as naturally as on a local disk.
|
|
60
|
-
- **Around 50 built-in backends:** RAM, Disk, Redis, S3 / R2 / OCI / Supabase / GCS, Gmail / GDrive / GDocs / GSheets / GSlides, GitHub / Linear / Notion / Trello, Slack / Discord /
|
|
60
|
+
- **Around 50 built-in backends:** RAM, Disk, Redis, S3 / R2 / OCI / Supabase / GCS, Gmail / GDrive / GDocs / GSheets / GSlides, GitHub / Linear / Notion / Trello, Slack / Discord / Email, MongoDB / Postgres / LanceDB, SSH, and more, mounted side-by-side under a single root.
|
|
61
61
|
- **Portable workspaces:** clone, snapshot, and version a workspace; agent runs move between machines without restarting or reconfiguring the system.
|
|
62
62
|
- **Embeddable:** the Python and TypeScript SDKs run in-process inside FastAPI, Express, browser apps, or any async runtime; no separate process required.
|
|
63
63
|
- **Agent integrations:** OpenAI Agents SDK, Vercel AI SDK, LangChain, Pydantic AI, CAMEL, and OpenHands via the SDKs; coding agents like Claude Code and Codex via the lightweight CLI + daemon.
|
package/dist/bin/mirage.js
CHANGED
|
@@ -5,21 +5,112 @@ import {
|
|
|
5
5
|
fail,
|
|
6
6
|
formatAge,
|
|
7
7
|
formatTable,
|
|
8
|
+
getConfig,
|
|
8
9
|
handleResponse,
|
|
10
|
+
listConfig,
|
|
9
11
|
loadDaemonSettings,
|
|
10
|
-
makeClient
|
|
11
|
-
|
|
12
|
+
makeClient,
|
|
13
|
+
resolvedConfig,
|
|
14
|
+
setConfig,
|
|
15
|
+
unsetConfig
|
|
16
|
+
} from "../chunk-TMXBYKRM.js";
|
|
17
|
+
|
|
18
|
+
// src/bin/mirage.ts
|
|
19
|
+
import { DaemonConfigError as DaemonConfigError2 } from "@struktoai/mirage-server";
|
|
12
20
|
|
|
13
21
|
// src/main.ts
|
|
14
22
|
import { readFileSync as readFileSync4 } from "fs";
|
|
15
|
-
import { dirname, join
|
|
23
|
+
import { dirname, join } from "path";
|
|
16
24
|
import { fileURLToPath } from "url";
|
|
17
25
|
import { Command } from "commander";
|
|
18
26
|
|
|
27
|
+
// src/config.ts
|
|
28
|
+
import { ALLOWED_KEYS, DaemonConfigError } from "@struktoai/mirage-server";
|
|
29
|
+
function mask(key, value) {
|
|
30
|
+
if (key === "auth_token" && value !== "") return "***";
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function humanTable(table) {
|
|
34
|
+
return Object.entries(table).map(([k, v]) => `${k} = ${v}`).join("\n");
|
|
35
|
+
}
|
|
36
|
+
function humanResolved(table) {
|
|
37
|
+
return Object.entries(table).map(([k, e]) => `${k} = ${e.value} (${e.origin})`).join("\n");
|
|
38
|
+
}
|
|
39
|
+
function listResolved() {
|
|
40
|
+
let resolved;
|
|
41
|
+
try {
|
|
42
|
+
resolved = resolvedConfig();
|
|
43
|
+
} catch (e) {
|
|
44
|
+
fail(e.message, 2);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const payload = {};
|
|
48
|
+
for (const [key, [value, origin]] of Object.entries(resolved)) {
|
|
49
|
+
payload[key] = { value: mask(key, value), origin };
|
|
50
|
+
}
|
|
51
|
+
emit(payload, humanResolved);
|
|
52
|
+
}
|
|
53
|
+
function listFile() {
|
|
54
|
+
let table;
|
|
55
|
+
try {
|
|
56
|
+
table = listConfig();
|
|
57
|
+
} catch (e) {
|
|
58
|
+
if (!(e instanceof DaemonConfigError)) throw e;
|
|
59
|
+
fail(e.message, 2);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const unknown = Object.keys(table).filter((k) => !ALLOWED_KEYS.has(k)).sort();
|
|
63
|
+
if (unknown.length > 0) {
|
|
64
|
+
process.stderr.write(
|
|
65
|
+
`warning: unknown [daemon] keys (daemon will refuse to start): ${unknown.join(", ")}
|
|
66
|
+
`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
emit(table, humanTable);
|
|
70
|
+
}
|
|
71
|
+
function registerConfigCommands(program) {
|
|
72
|
+
const config = program.command("config").description("Read and write daemon settings in config.toml.");
|
|
73
|
+
config.command("list").option("--resolved", "show effective values and their origins").description("Print the config.toml [daemon] table.").action((opts) => {
|
|
74
|
+
if (opts.resolved === true) listResolved();
|
|
75
|
+
else listFile();
|
|
76
|
+
});
|
|
77
|
+
config.command("get").argument("<key>").description("Print one [daemon] key.").action((key) => {
|
|
78
|
+
let value;
|
|
79
|
+
try {
|
|
80
|
+
value = getConfig(key);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
fail(e.message, 2);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (value === void 0) {
|
|
86
|
+
fail(`${key} is not set`, 1);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
emit({ [key]: value }, () => value);
|
|
90
|
+
});
|
|
91
|
+
config.command("set").argument("<key>").argument("<value>").description("Write a [daemon] key (path settings apply on next daemon restart).").action((key, value) => {
|
|
92
|
+
try {
|
|
93
|
+
setConfig(key, value);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
fail(e.message, 2);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
emit({ [key]: value, written: true }, () => `${key} = ${value}`);
|
|
99
|
+
});
|
|
100
|
+
config.command("unset").argument("<key>").description("Remove a [daemon] key.").action((key) => {
|
|
101
|
+
try {
|
|
102
|
+
unsetConfig(key);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
fail(e.message, 2);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
emit({ [key]: null, unset: true }, () => `unset ${key}`);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
19
111
|
// src/daemon.ts
|
|
20
112
|
import { existsSync, readFileSync } from "fs";
|
|
21
|
-
import {
|
|
22
|
-
import { join } from "path";
|
|
113
|
+
import { pidFilePath } from "@struktoai/mirage-server";
|
|
23
114
|
function formatStatus(d) {
|
|
24
115
|
if (!d.running) return `Daemon not running. URL: ${d.url}`;
|
|
25
116
|
const parts = [`Running. PID ${d.pid !== null ? String(d.pid) : "?"}`];
|
|
@@ -44,9 +135,6 @@ function formatKill(d) {
|
|
|
44
135
|
if (d.pid === null || d.pid === void 0) return "Daemon not running.";
|
|
45
136
|
return `Already gone (PID ${String(d.pid)}).`;
|
|
46
137
|
}
|
|
47
|
-
function pidFilePath() {
|
|
48
|
-
return join(homedir(), ".mirage", "daemon.pid");
|
|
49
|
-
}
|
|
50
138
|
function readPid() {
|
|
51
139
|
const p = pidFilePath();
|
|
52
140
|
if (!existsSync(p)) return null;
|
|
@@ -229,6 +317,35 @@ function registerJobCommands(program) {
|
|
|
229
317
|
});
|
|
230
318
|
}
|
|
231
319
|
|
|
320
|
+
// src/mcp.ts
|
|
321
|
+
import { serveMirageMcp } from "@struktoai/mirage-agents/mcp";
|
|
322
|
+
import { buildWorkspaceFromConfig, resolveWorkspaceConfig } from "@struktoai/mirage-server";
|
|
323
|
+
function resolveMcpConfig(config, options = {}) {
|
|
324
|
+
return resolveWorkspaceConfig(config, {
|
|
325
|
+
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
326
|
+
...options.env !== void 0 ? { env: options.env } : {},
|
|
327
|
+
envNames: ["MIRAGE_MCP_CONFIG", "MIRAGE_CONFIG"]
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
async function buildMcpWorkspace(configPath) {
|
|
331
|
+
return buildWorkspaceFromConfig(configPath);
|
|
332
|
+
}
|
|
333
|
+
async function runMcpServer(config, options) {
|
|
334
|
+
const configPath = resolveMcpConfig(config);
|
|
335
|
+
const workspace = await buildMcpWorkspace(configPath);
|
|
336
|
+
try {
|
|
337
|
+
await serveMirageMcp(workspace, {
|
|
338
|
+
staleWriteProtection: options.staleWriteProtection
|
|
339
|
+
});
|
|
340
|
+
} catch (error) {
|
|
341
|
+
await workspace.close();
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function registerMcpCommand(program) {
|
|
346
|
+
program.command("mcp").argument("[config]", "Mirage workspace YAML config").option("--no-stale-write-protection", "allow edits after a file changed since it was read").description("Serve a Mirage workspace as MCP tools over stdio.").action(runMcpServer);
|
|
347
|
+
}
|
|
348
|
+
|
|
232
349
|
// src/provision.ts
|
|
233
350
|
function registerProvisionCommand(program) {
|
|
234
351
|
program.command("provision").description("Estimate cost / preview a command without running it.").requiredOption("-w, --workspace <id>", "Workspace id").requiredOption("-c, --command <command>", "Shell command to estimate").option("-s, --session <id>", "Session id").action(async (opts) => {
|
|
@@ -250,11 +367,25 @@ function registerProvisionCommand(program) {
|
|
|
250
367
|
function buildClient3() {
|
|
251
368
|
return makeClient(loadDaemonSettings());
|
|
252
369
|
}
|
|
370
|
+
var MODES = /* @__PURE__ */ new Set(["read", "write", "exec", "r", "rw", "rwx"]);
|
|
371
|
+
function parseMountModes(mounts) {
|
|
372
|
+
const modes = {};
|
|
373
|
+
for (const item of mounts) {
|
|
374
|
+
const idx = item.lastIndexOf(":");
|
|
375
|
+
const mode = idx >= 0 ? item.slice(idx + 1) : "";
|
|
376
|
+
if (idx >= 0 && MODES.has(mode)) {
|
|
377
|
+
modes[item.slice(0, idx)] = mode;
|
|
378
|
+
} else {
|
|
379
|
+
modes[item] = "exec";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return modes;
|
|
383
|
+
}
|
|
253
384
|
function registerSessionCommands(program) {
|
|
254
385
|
const sess = program.command("session").description("Manage workspace sessions.");
|
|
255
386
|
sess.command("create").argument("<wsId>").option("--id <sessionId>").option(
|
|
256
387
|
"-m, --mount <prefix>",
|
|
257
|
-
"restrict session to
|
|
388
|
+
"restrict session to a mount, optionally capping its mode: '/data:read' (alias '/data:r'), '/scratch:rw', '/bin:rwx', or a bare '/data' to keep the mount's own mode; repeatable",
|
|
258
389
|
(value, prev) => prev.concat([value]),
|
|
259
390
|
[]
|
|
260
391
|
).action(async (wsId, opts) => {
|
|
@@ -263,7 +394,7 @@ function registerSessionCommands(program) {
|
|
|
263
394
|
const body = {};
|
|
264
395
|
if (opts.id !== void 0) body.sessionId = opts.id;
|
|
265
396
|
if (opts.mount !== void 0 && opts.mount.length > 0) {
|
|
266
|
-
body.
|
|
397
|
+
body.mounts = parseMountModes(opts.mount);
|
|
267
398
|
}
|
|
268
399
|
emit(
|
|
269
400
|
await handleResponse(
|
|
@@ -292,7 +423,7 @@ function registerSessionCommands(program) {
|
|
|
292
423
|
// src/workspace.ts
|
|
293
424
|
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
294
425
|
import { resolve } from "path";
|
|
295
|
-
import { interpolateEnv,
|
|
426
|
+
import { interpolateEnv, loadWorkspaceConfigFile } from "@struktoai/mirage-server";
|
|
296
427
|
import { parse as yamlParse } from "yaml";
|
|
297
428
|
function buildClient4() {
|
|
298
429
|
return makeClient(loadDaemonSettings());
|
|
@@ -347,7 +478,8 @@ function formatWorkspaceDetail(d) {
|
|
|
347
478
|
if (d.internals != null) {
|
|
348
479
|
lines.push("", "Internals:");
|
|
349
480
|
for (const k of ["cacheBytes", "cacheEntries", "historyLength", "inFlightJobs"]) {
|
|
350
|
-
|
|
481
|
+
const value = d.internals[k];
|
|
482
|
+
lines.push(` ${k.padEnd(16)} ${value === null ? "n/a (not tracked)" : String(value)}`);
|
|
351
483
|
}
|
|
352
484
|
}
|
|
353
485
|
return lines.join("\n");
|
|
@@ -369,7 +501,7 @@ function formatDiff(changes) {
|
|
|
369
501
|
function registerWorkspaceCommands(program) {
|
|
370
502
|
const ws = program.command("workspace").description("Manage workspaces.");
|
|
371
503
|
ws.command("create").description("Create a workspace; daemon auto-spawns if not running.").argument("<config>", "YAML/JSON workspace config").option("--id <id>", "Explicit workspace id").action(async (configPath, opts) => {
|
|
372
|
-
const cfg =
|
|
504
|
+
const cfg = loadWorkspaceConfigFile(configPath);
|
|
373
505
|
const body = { config: cfg };
|
|
374
506
|
if (opts.id !== void 0) body.id = opts.id;
|
|
375
507
|
const c = buildClient4();
|
|
@@ -486,7 +618,7 @@ function resolveVersion() {
|
|
|
486
618
|
let dir = dirname(fileURLToPath(import.meta.url));
|
|
487
619
|
for (let i = 0; i < 6; i++) {
|
|
488
620
|
try {
|
|
489
|
-
const pkg = JSON.parse(readFileSync4(
|
|
621
|
+
const pkg = JSON.parse(readFileSync4(join(dir, "package.json"), "utf8"));
|
|
490
622
|
if (pkg.name === "@struktoai/mirage-cli" && pkg.version) return pkg.version;
|
|
491
623
|
} catch {
|
|
492
624
|
}
|
|
@@ -501,8 +633,10 @@ function buildProgram() {
|
|
|
501
633
|
registerSessionCommands(program);
|
|
502
634
|
registerJobCommands(program);
|
|
503
635
|
registerExecuteCommand(program);
|
|
636
|
+
registerMcpCommand(program);
|
|
504
637
|
registerProvisionCommand(program);
|
|
505
638
|
registerDaemonCommands(program);
|
|
639
|
+
registerConfigCommands(program);
|
|
506
640
|
return program;
|
|
507
641
|
}
|
|
508
642
|
|
|
@@ -521,6 +655,10 @@ function rewriteArgv(argv) {
|
|
|
521
655
|
});
|
|
522
656
|
}
|
|
523
657
|
buildProgram().parseAsync(rewriteArgv(process.argv)).catch((err) => {
|
|
658
|
+
if (err instanceof DaemonConfigError2) {
|
|
659
|
+
console.error(err.message);
|
|
660
|
+
process.exit(2);
|
|
661
|
+
}
|
|
524
662
|
console.error(err);
|
|
525
663
|
process.exit(1);
|
|
526
664
|
});
|
package/dist/bin/mirage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/main.ts","../../src/daemon.ts","../../src/execute.ts","../../src/job.ts","../../src/provision.ts","../../src/session.ts","../../src/workspace.ts","../../src/bin/mirage.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { registerDaemonCommands } from './daemon.ts'\nimport { registerExecuteCommand } from './execute.ts'\nimport { registerJobCommands } from './job.ts'\nimport { registerProvisionCommand } from './provision.ts'\nimport { registerSessionCommands } from './session.ts'\nimport { registerWorkspaceCommands } from './workspace.ts'\n\nfunction resolveVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {\n name?: string\n version?: string\n }\n if (pkg.name === '@struktoai/mirage-cli' && pkg.version) return pkg.version\n } catch {\n // package.json absent at this level: keep walking up to the package root\n }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n program\n .name('mirage')\n .description('Mirage daemon CLI: manage workspaces and execute commands.')\n .version(resolveVersion())\n registerWorkspaceCommands(program)\n registerSessionCommands(program)\n registerJobCommands(program)\n registerExecuteCommand(program)\n registerProvisionCommand(program)\n registerDaemonCommands(program)\n return program\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\ninterface DaemonStatus {\n running: boolean\n pid: number | null\n url: string\n uptimeS?: number\n workspaces?: number\n}\n\nfunction formatStatus(d: DaemonStatus): string {\n if (!d.running) return `Daemon not running. URL: ${d.url}`\n const parts: string[] = [`Running. PID ${d.pid !== null ? String(d.pid) : '?'}`]\n if (d.uptimeS !== undefined) {\n parts.push(`uptime ${formatAge(Date.now() / 1000 - d.uptimeS)}`)\n }\n if (d.workspaces !== undefined) {\n parts.push(`${String(d.workspaces)} workspace${d.workspaces === 1 ? '' : 's'}`)\n }\n return parts.join(', ') + `. URL: ${d.url}`\n}\n\nfunction formatStop(d: { via?: string; pid?: number }): string {\n const via = d.via ?? '?'\n return `Stopped (via ${via}${d.pid !== undefined ? `, PID ${String(d.pid)}` : ''}).`\n}\n\nfunction formatRestart(d: { spawnedFresh?: boolean }): string {\n if (d.spawnedFresh === true) return 'Restarted (eager spawn).'\n return 'Restarted; next CLI command will auto-spawn.'\n}\n\nfunction formatKill(d: { killed: boolean; pid?: number | null }): string {\n if (d.killed) return `Killed PID ${String(d.pid ?? '?')}.`\n if (d.pid === null || d.pid === undefined) return 'Daemon not running.'\n return `Already gone (PID ${String(d.pid)}).`\n}\n\nfunction pidFilePath(): string {\n return join(homedir(), '.mirage', 'daemon.pid')\n}\n\nfunction readPid(): number | null {\n const p = pidFilePath()\n if (!existsSync(p)) return null\n const text = readFileSync(p, 'utf-8').trim()\n const pid = Number(text)\n return Number.isFinite(pid) && pid > 0 ? pid : null\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n return false\n }\n}\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nasync function waitForUnreachable(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const c = buildClient()\n if (!(await c.isReachable(300))) return true\n await new Promise((r) => setTimeout(r, 200))\n }\n return false\n}\n\nexport function registerDaemonCommands(program: Command): void {\n const d = program.command('daemon').description('Manage the daemon process lifecycle.')\n\n d.command('status')\n .description('Show daemon health, PID, uptime, workspace count.')\n .action(async () => {\n const pid = readPid()\n const c = buildClient()\n const url = c.settings.url\n try {\n const r = await c.request('GET', '/v1/health')\n if (r.status !== 200) {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n const body = (await r.json()) as Record<string, unknown>\n emit({ running: true, pid, url, ...body } as DaemonStatus, formatStatus)\n } catch {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n })\n\n d.command('stop')\n .description('Gracefully stop the daemon.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .action(async (opts: { timeout: string }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n const c = buildClient()\n let r: Response\n try {\n r = await c.request('POST', '/v1/shutdown')\n } catch (err: unknown) {\n fail(`daemon not reachable: ${String(err)}`)\n }\n if (r.status >= 400) fail(`shutdown failed: ${await r.text()}`, 2)\n if (await waitForUnreachable(timeoutMs)) {\n emit({ stopped: true, via: 'graceful' }, formatStop)\n return\n }\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n emit({ stopped: true, via: 'sigterm', pid }, formatStop)\n return\n } catch {\n // fall through to fail\n }\n }\n fail(`daemon did not exit within ${opts.timeout}s and no live PID found`, 2)\n })\n\n d.command('restart')\n .description('Stop the daemon. Next CLI command auto-spawns a fresh one.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .option('--eager', 'Spawn a fresh daemon immediately')\n .action(async (opts: { timeout: string; eager?: boolean }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n try {\n await buildClient().request('POST', '/v1/shutdown')\n } catch {\n // already unreachable; fall through to pid cleanup\n }\n if (!(await waitForUnreachable(timeoutMs))) {\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // process may have exited between checks\n }\n }\n }\n if (opts.eager === true) {\n await buildClient().ensureRunning({ allowSpawn: true })\n emit({ restarted: true, spawnedFresh: true }, formatRestart)\n return\n }\n emit(\n {\n restarted: true,\n spawnedFresh: false,\n note: 'next workspace create will auto-spawn',\n },\n formatRestart,\n )\n })\n\n d.command('kill')\n .description('SIGKILL the daemon. Last resort -- skips graceful shutdown.')\n .action(() => {\n const pid = readPid()\n if (pid === null) {\n emit({ killed: false, reason: 'no daemon running', pid: null }, formatKill)\n return\n }\n if (!processAlive(pid)) {\n emit({ killed: false, reason: 'process already gone', pid }, formatKill)\n return\n }\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n emit({ killed: false, reason: 'process gone', pid }, formatKill)\n return\n }\n emit({ killed: true, pid }, formatKill)\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { readFileSync } from 'node:fs'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerExecuteCommand(program: Command): void {\n program\n .command('execute')\n .description('Execute a command.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to execute')\n .option('-s, --session <id>', 'Session id')\n .option('--bg', 'Background; return job_id immediately')\n .action(\n async (opts: { workspace: string; command: string; session?: string; bg?: boolean }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: false }\n if (opts.session !== undefined) body.sessionId = opts.session\n if (opts.bg !== true && !process.stdin.isTTY) {\n body.stdinBase64 = readFileSync(0).toString('base64')\n }\n const path =\n `/v1/workspaces/${opts.workspace}/execute` + (opts.bg === true ? '?background=true' : '')\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(\n await c.request('POST', path, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n },\n )\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nexport function registerJobCommands(program: Command): void {\n const job = program.command('job').description('Manage daemon jobs.')\n\n job\n .command('list')\n .option('-w, --workspace <id>')\n .action(async (opts: { workspace?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path =\n '/v1/jobs' + (opts.workspace !== undefined ? `?workspaceId=${opts.workspace}` : '')\n emit(await handleResponse(await c.request('GET', path)))\n })\n\n job\n .command('get')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(await c.request('GET', `/v1/jobs/${id}`))\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('wait')\n .argument('<id>')\n .option('--timeout <s>')\n .action(async (id: string, opts: { timeout?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.timeout !== undefined) body.timeoutS = Number(opts.timeout)\n const response = await handleResponse(\n await c.request('POST', `/v1/jobs/${id}/wait`, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('cancel')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('DELETE', `/v1/jobs/${id}`)))\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerProvisionCommand(program: Command): void {\n program\n .command('provision')\n .description('Estimate cost / preview a command without running it.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to estimate')\n .option('-s, --session <id>', 'Session id')\n .action(async (opts: { workspace: string; command: string; session?: string }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: true }\n if (opts.session !== undefined) body.sessionId = opts.session\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${opts.workspace}/execute`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nexport function registerSessionCommands(program: Command): void {\n const sess = program.command('session').description('Manage workspace sessions.')\n\n sess\n .command('create')\n .argument('<wsId>')\n .option('--id <sessionId>')\n .option(\n '-m, --mount <prefix>',\n 'restrict session to this mount prefix; repeatable',\n (value: string, prev: string[]) => prev.concat([value]),\n [] as string[],\n )\n .action(async (wsId: string, opts: { id?: string; mount?: string[] }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.id !== undefined) body.sessionId = opts.id\n if (opts.mount !== undefined && opts.mount.length > 0) {\n body.allowedMounts = opts.mount\n }\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${wsId}/sessions`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n\n sess\n .command('list')\n .argument('<wsId>')\n .action(async (wsId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('GET', `/v1/workspaces/${wsId}/sessions`)))\n })\n\n sess\n .command('delete')\n .argument('<wsId>')\n .argument('<sessionId>')\n .action(async (wsId: string, sessionId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('DELETE', `/v1/workspaces/${wsId}/sessions/${sessionId}`),\n ),\n )\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { interpolateEnv, loadWorkspaceConfig } from '@struktoai/mirage-server'\nimport { parse as yamlParse } from 'yaml'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge, formatTable, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nfunction envRecord(): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') out[k] = v\n }\n return out\n}\n\nfunction loadConfigArgument(path: string): unknown {\n if (!existsSync(path)) fail(`config file not found: ${path}`, 2)\n const text = readFileSync(path, 'utf-8')\n try {\n return interpolateEnv(yamlParse(text), envRecord())\n } catch (err: unknown) {\n fail(`invalid config YAML/JSON at ${path}: ${String(err)}`, 2)\n }\n}\n\ninterface WorkspaceBrief {\n id: string\n mode: string\n mountCount: number\n sessionCount: number\n createdAt: number\n}\n\ninterface MountSummary {\n prefix: string\n resource: string\n mode: string\n}\n\ninterface SessionSummary {\n sessionId: string\n cwd: string\n}\n\ninterface Internals {\n cacheBytes: number\n cacheEntries: number\n historyLength: number\n inFlightJobs: number\n}\n\ninterface WorkspaceDetail {\n id: string\n mode: string\n createdAt: number\n mounts?: MountSummary[]\n sessions?: SessionSummary[]\n internals?: Internals | null\n}\n\nfunction formatWorkspaceList(items: WorkspaceBrief[]): string {\n if (items.length === 0) return 'No active workspaces.'\n const rows = items.map((w) => [\n w.id,\n w.mode,\n String(w.mountCount),\n String(w.sessionCount),\n formatAge(w.createdAt),\n ])\n return formatTable(['ID', 'MODE', 'MOUNTS', 'SESSIONS', 'AGE'], rows)\n}\n\nfunction formatWorkspaceDetail(d: WorkspaceDetail): string {\n const lines: string[] = [\n `ID: ${d.id}`,\n `Mode: ${d.mode}`,\n `Created: ${formatAge(d.createdAt)} ago`,\n ]\n if (d.mounts !== undefined && d.mounts.length > 0) {\n const rows = d.mounts.map((m) => [m.prefix, m.resource, m.mode])\n lines.push('', 'Mounts:')\n for (const ln of formatTable(['PREFIX', 'RESOURCE', 'MODE'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.sessions !== undefined && d.sessions.length > 0) {\n const rows = d.sessions.map((s) => [s.sessionId, s.cwd])\n lines.push('', 'Sessions:')\n for (const ln of formatTable(['SESSION', 'CWD'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.internals != null) {\n lines.push('', 'Internals:')\n for (const k of ['cacheBytes', 'cacheEntries', 'historyLength', 'inFlightJobs'] as const) {\n lines.push(` ${k.padEnd(16)} ${String(d.internals[k])}`)\n }\n }\n return lines.join('\\n')\n}\n\ninterface VersionLogItem {\n id: string\n message: string\n}\n\ninterface DiffResult {\n added: string[]\n modified: string[]\n deleted: string[]\n}\n\nfunction formatVersionLog(items: VersionLogItem[]): string {\n if (items.length === 0) return 'No versions.'\n return formatTable(\n ['VERSION', 'MESSAGE'],\n items.map((v) => [v.id.slice(0, 12), v.message]),\n )\n}\n\nfunction formatDiff(changes: DiffResult): string {\n const lines: string[] = []\n for (const kind of ['added', 'modified', 'deleted'] as const) {\n for (const path of changes[kind]) lines.push(`${kind.padEnd(9)} ${path}`)\n }\n return lines.length > 0 ? lines.join('\\n') : 'No changes.'\n}\n\nexport function registerWorkspaceCommands(program: Command): void {\n const ws = program.command('workspace').description('Manage workspaces.')\n\n ws.command('create')\n .description('Create a workspace; daemon auto-spawns if not running.')\n .argument('<config>', 'YAML/JSON workspace config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (configPath: string, opts: { id?: string }) => {\n const cfg = loadWorkspaceConfig(configPath)\n const body: { config: unknown; id?: string } = { config: cfg }\n if (opts.id !== undefined) body.id = opts.id\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('list')\n .description('List active workspaces.')\n .action(async () => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('GET', '/v1/workspaces'))) as WorkspaceBrief[],\n formatWorkspaceList,\n )\n })\n\n ws.command('get')\n .description('Show full details for one workspace.')\n .argument('<id>')\n .option('--verbose', 'Include cache/dirty/history internals')\n .action(async (id: string, opts: { verbose?: boolean }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path = `/v1/workspaces/${id}` + (opts.verbose === true ? '?verbose=true' : '')\n emit(\n (await handleResponse(await c.request('GET', path))) as WorkspaceDetail,\n formatWorkspaceDetail,\n )\n })\n\n ws.command('delete')\n .description('Stop and remove a workspace.')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('DELETE', `/v1/workspaces/${id}`))) as {\n id: string\n },\n (d) => `Deleted workspace ${d.id}.`,\n )\n })\n\n ws.command('clone')\n .description('Clone a workspace, optionally from one of its past versions.')\n .argument('<srcId>')\n .option('--id <id>', 'Explicit id for the clone')\n .option('--at <ref>', 'Clone from a past version (id or branch) not the live state')\n .action(async (srcId: string, opts: { id?: string; at?: string }) => {\n const body: Record<string, unknown> = { sourceId: srcId }\n if (opts.id !== undefined) body.id = opts.id\n if (opts.at !== undefined) body.at = opts.at\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', '/v1/workspaces/clone', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('commit')\n .description(\"Commit the workspace's current state as a version.\")\n .argument('<id>')\n .option('-m, --message <msg>', 'Version message', '')\n .option('-b, --branch <branch>', 'Branch to commit on', 'main')\n .action(async (id: string, opts: { message: string; branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/commit`, {\n body: JSON.stringify({ message: opts.message, branch: opts.branch }),\n })\n emit(\n (await handleResponse(r)) as { version: string; branch: string },\n (d) => `Committed ${d.version.slice(0, 12)} on ${d.branch}.`,\n )\n })\n\n ws.command('branch')\n .description(\"Create a branch at another branch's current version.\")\n .argument('<id>')\n .argument('<name>')\n .option('--from <branch>', 'Branch to fork from', 'main')\n .action(async (id: string, name: string, opts: { from: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/branch`, {\n body: JSON.stringify({ name, fromBranch: opts.from }),\n })\n emit(\n (await handleResponse(r)) as { branch: string; version: string },\n (d) => `Created branch ${d.branch} at ${d.version.slice(0, 12)}.`,\n )\n })\n\n ws.command('log')\n .description(\"List a workspace's versions (newest first).\")\n .argument('<id>')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(async (id: string, opts: { branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/versions?branch=${opts.branch}`)\n emit((await handleResponse(r)) as VersionLogItem[], formatVersionLog)\n })\n\n ws.command('diff')\n .description('Show changed files (git-style): live vs HEAD, live vs <a>, or <a> vs <b>.')\n .argument('<id>')\n .argument('[a]', 'Base ref; omit to use live state')\n .argument('[b]', 'Compare ref; omit to use live state')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(\n async (\n id: string,\n a: string | undefined,\n b: string | undefined,\n opts: { branch: string },\n ) => {\n const params = new URLSearchParams({ branch: opts.branch })\n if (a !== undefined) params.set('a', a)\n if (b !== undefined) params.set('b', b)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/diff?${params.toString()}`)\n emit((await handleResponse(r)) as DiffResult, formatDiff)\n },\n )\n\n ws.command('checkout')\n .description('Restore a workspace in place to one of its versions.')\n .argument('<id>')\n .argument('<ref>', 'Version id or branch to restore')\n .action(async (id: string, ref: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/checkout`, {\n body: JSON.stringify({ ref }),\n })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('snapshot')\n .description(\n 'Snapshot a workspace to a tar file. The path is resolved to an absolute path and the daemon writes the tar.',\n )\n .argument('<id>')\n .argument('<output>', 'Path to write the .tar to')\n .action(async (id: string, output: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/snapshot`, {\n body: JSON.stringify({ path: resolve(output) }),\n })\n const d = (await handleResponse(r)) as { id: string; path: string; size: number }\n emit(d, (x) => `Snapshot ${x.id} -> ${x.path} (${x.size.toLocaleString()} bytes).`)\n })\n\n ws.command('load')\n .description('Load a workspace from a tar file.')\n .argument('<tar>', 'Path to a .tar produced by `mirage workspace snapshot`')\n .argument('[config]', 'Workspace YAML/JSON config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (tarPath: string, configPath: string | undefined, opts: { id?: string }) => {\n if (!existsSync(tarPath)) fail(`tar file not found: ${tarPath}`, 2)\n const body: { path: string; id?: string; override?: unknown } = { path: resolve(tarPath) }\n if (opts.id !== undefined) body.id = opts.id\n if (configPath !== undefined) body.override = loadConfigArgument(configPath)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces/load', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n}\n","#!/usr/bin/env node\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { buildProgram } from '../main.ts'\n\nconst ALIASES: Record<string, string> = {\n '--workspace_id': '--workspace',\n '--session_id': '--session',\n}\n\nfunction rewriteArgv(argv: string[]): string[] {\n return argv.map((arg) => {\n for (const [from, to] of Object.entries(ALIASES)) {\n if (arg === from) return to\n if (arg.startsWith(from + '=')) return to + arg.slice(from.length)\n }\n return arg\n })\n}\n\nbuildProgram()\n .parseAsync(rewriteArgv(process.argv))\n .catch((err: unknown) => {\n console.error(err)\n process.exit(1)\n })\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAS,gBAAAA,qBAAoB;AAC7B,SAAS,SAAS,QAAAC,aAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,eAAe;;;ACHxB,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,YAAY;AAcrB,SAAS,aAAa,GAAyB;AAC7C,MAAI,CAAC,EAAE,QAAS,QAAO,4BAA4B,EAAE,GAAG;AACxD,QAAM,QAAkB,CAAC,gBAAgB,EAAE,QAAQ,OAAO,OAAO,EAAE,GAAG,IAAI,GAAG,EAAE;AAC/E,MAAI,EAAE,YAAY,QAAW;AAC3B,UAAM,KAAK,UAAU,UAAU,KAAK,IAAI,IAAI,MAAO,EAAE,OAAO,CAAC,EAAE;AAAA,EACjE;AACA,MAAI,EAAE,eAAe,QAAW;AAC9B,UAAM,KAAK,GAAG,OAAO,EAAE,UAAU,CAAC,aAAa,EAAE,eAAe,IAAI,KAAK,GAAG,EAAE;AAAA,EAChF;AACA,SAAO,MAAM,KAAK,IAAI,IAAI,UAAU,EAAE,GAAG;AAC3C;AAEA,SAAS,WAAW,GAA2C;AAC7D,QAAM,MAAM,EAAE,OAAO;AACrB,SAAO,gBAAgB,GAAG,GAAG,EAAE,QAAQ,SAAY,SAAS,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE;AAClF;AAEA,SAAS,cAAc,GAAuC;AAC5D,MAAI,EAAE,iBAAiB,KAAM,QAAO;AACpC,SAAO;AACT;AAEA,SAAS,WAAW,GAAqD;AACvE,MAAI,EAAE,OAAQ,QAAO,cAAc,OAAO,EAAE,OAAO,GAAG,CAAC;AACvD,MAAI,EAAE,QAAQ,QAAQ,EAAE,QAAQ,OAAW,QAAO;AAClD,SAAO,qBAAqB,OAAO,EAAE,GAAG,CAAC;AAC3C;AAEA,SAAS,cAAsB;AAC7B,SAAO,KAAK,QAAQ,GAAG,WAAW,YAAY;AAChD;AAEA,SAAS,UAAyB;AAChC,QAAM,IAAI,YAAY;AACtB,MAAI,CAAC,WAAW,CAAC,EAAG,QAAO;AAC3B,QAAM,OAAO,aAAa,GAAG,OAAO,EAAE,KAAK;AAC3C,QAAM,MAAM,OAAO,IAAI;AACvB,SAAO,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;AACjD;AAEA,SAAS,aAAa,KAAsB;AAC1C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,KAAc;AACrB,UAAM,OAAQ,IAA8B;AAC5C,QAAI,SAAS,QAAS,QAAO;AAC7B,QAAI,SAAS,QAAS,QAAO;AAC7B,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc;AACrB,SAAO,WAAW,mBAAmB,CAAC;AACxC;AAEA,eAAe,mBAAmB,WAAqC;AACrE,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,IAAI,YAAY;AACtB,QAAI,CAAE,MAAM,EAAE,YAAY,GAAG,EAAI,QAAO;AACxC,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,SAAwB;AAC7D,QAAM,IAAI,QAAQ,QAAQ,QAAQ,EAAE,YAAY,sCAAsC;AAEtF,IAAE,QAAQ,QAAQ,EACf,YAAY,mDAAmD,EAC/D,OAAO,YAAY;AAClB,UAAM,MAAM,QAAQ;AACpB,UAAM,IAAI,YAAY;AACtB,UAAM,MAAM,EAAE,SAAS;AACvB,QAAI;AACF,YAAM,IAAI,MAAM,EAAE,QAAQ,OAAO,YAAY;AAC7C,UAAI,EAAE,WAAW,KAAK;AACpB,aAAK,EAAE,SAAS,OAAO,KAAK,IAAI,GAAmB,YAAY;AAC/D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM,OAAQ,MAAM,EAAE,KAAK;AAC3B,WAAK,EAAE,SAAS,MAAM,KAAK,KAAK,GAAG,KAAK,GAAmB,YAAY;AAAA,IACzE,QAAQ;AACN,WAAK,EAAE,SAAS,OAAO,KAAK,IAAI,GAAmB,YAAY;AAC/D,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,IAAE,QAAQ,MAAM,EACb,YAAY,6BAA6B,EACzC,OAAO,iBAAiB,qCAAqC,GAAG,EAChE,OAAO,OAAO,SAA8B;AAC3C,UAAM,YAAY,OAAO,KAAK,OAAO,IAAI;AACzC,UAAM,IAAI,YAAY;AACtB,QAAI;AACJ,QAAI;AACF,UAAI,MAAM,EAAE,QAAQ,QAAQ,cAAc;AAAA,IAC5C,SAAS,KAAc;AACrB,WAAK,yBAAyB,OAAO,GAAG,CAAC,EAAE;AAAA,IAC7C;AACA,QAAI,EAAE,UAAU,IAAK,MAAK,oBAAoB,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC;AACjE,QAAI,MAAM,mBAAmB,SAAS,GAAG;AACvC,WAAK,EAAE,SAAS,MAAM,KAAK,WAAW,GAAG,UAAU;AACnD;AAAA,IACF;AACA,UAAM,MAAM,QAAQ;AACpB,QAAI,QAAQ,QAAQ,aAAa,GAAG,GAAG;AACrC,UAAI;AACF,gBAAQ,KAAK,KAAK,SAAS;AAC3B,aAAK,EAAE,SAAS,MAAM,KAAK,WAAW,IAAI,GAAG,UAAU;AACvD;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,8BAA8B,KAAK,OAAO,2BAA2B,CAAC;AAAA,EAC7E,CAAC;AAEH,IAAE,QAAQ,SAAS,EAChB,YAAY,4DAA4D,EACxE,OAAO,iBAAiB,qCAAqC,GAAG,EAChE,OAAO,WAAW,kCAAkC,EACpD,OAAO,OAAO,SAA+C;AAC5D,UAAM,YAAY,OAAO,KAAK,OAAO,IAAI;AACzC,QAAI;AACF,YAAM,YAAY,EAAE,QAAQ,QAAQ,cAAc;AAAA,IACpD,QAAQ;AAAA,IAER;AACA,QAAI,CAAE,MAAM,mBAAmB,SAAS,GAAI;AAC1C,YAAM,MAAM,QAAQ;AACpB,UAAI,QAAQ,QAAQ,aAAa,GAAG,GAAG;AACrC,YAAI;AACF,kBAAQ,KAAK,KAAK,SAAS;AAAA,QAC7B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,UAAU,MAAM;AACvB,YAAM,YAAY,EAAE,cAAc,EAAE,YAAY,KAAK,CAAC;AACtD,WAAK,EAAE,WAAW,MAAM,cAAc,KAAK,GAAG,aAAa;AAC3D;AAAA,IACF;AACA;AAAA,MACE;AAAA,QACE,WAAW;AAAA,QACX,cAAc;AAAA,QACd,MAAM;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAEH,IAAE,QAAQ,MAAM,EACb,YAAY,6DAA6D,EACzE,OAAO,MAAM;AACZ,UAAM,MAAM,QAAQ;AACpB,QAAI,QAAQ,MAAM;AAChB,WAAK,EAAE,QAAQ,OAAO,QAAQ,qBAAqB,KAAK,KAAK,GAAG,UAAU;AAC1E;AAAA,IACF;AACA,QAAI,CAAC,aAAa,GAAG,GAAG;AACtB,WAAK,EAAE,QAAQ,OAAO,QAAQ,wBAAwB,IAAI,GAAG,UAAU;AACvE;AAAA,IACF;AACA,QAAI;AACF,cAAQ,KAAK,KAAK,SAAS;AAAA,IAC7B,QAAQ;AACN,WAAK,EAAE,QAAQ,OAAO,QAAQ,gBAAgB,IAAI,GAAG,UAAU;AAC/D;AAAA,IACF;AACA,SAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,UAAU;AAAA,EACxC,CAAC;AACL;;;AC/LA,SAAS,gBAAAC,qBAAoB;AAMtB,SAAS,uBAAuB,SAAwB;AAC7D,UACG,QAAQ,SAAS,EACjB,YAAY,oBAAoB,EAChC,eAAe,wBAAwB,cAAc,EACrD,eAAe,2BAA2B,0BAA0B,EACpE,OAAO,sBAAsB,YAAY,EACzC,OAAO,QAAQ,uCAAuC,EACtD;AAAA,IACC,OAAO,SAAiF;AACtF,YAAM,OAAgC,EAAE,SAAS,KAAK,SAAS,WAAW,MAAM;AAChF,UAAI,KAAK,YAAY,OAAW,MAAK,YAAY,KAAK;AACtD,UAAI,KAAK,OAAO,QAAQ,CAAC,QAAQ,MAAM,OAAO;AAC5C,aAAK,cAAcC,cAAa,CAAC,EAAE,SAAS,QAAQ;AAAA,MACtD;AACA,YAAM,OACJ,kBAAkB,KAAK,SAAS,cAAc,KAAK,OAAO,OAAO,qBAAqB;AACxF,YAAM,IAAI,WAAW,mBAAmB,CAAC;AACzC,YAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,YAAM,WAAW,MAAM;AAAA,QACrB,MAAM,EAAE,QAAQ,QAAQ,MAAM,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC;AAAA,MAC9D;AACA,WAAK,QAAQ;AACb,cAAQ,KAAK,qBAAqB,QAAQ,CAAC;AAAA,IAC7C;AAAA,EACF;AACJ;;;AC3BA,SAASC,eAAc;AACrB,SAAO,WAAW,mBAAmB,CAAC;AACxC;AAEO,SAAS,oBAAoB,SAAwB;AAC1D,QAAM,MAAM,QAAQ,QAAQ,KAAK,EAAE,YAAY,qBAAqB;AAEpE,MACG,QAAQ,MAAM,EACd,OAAO,sBAAsB,EAC7B,OAAO,OAAO,SAAiC;AAC9C,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,OACJ,cAAc,KAAK,cAAc,SAAY,gBAAgB,KAAK,SAAS,KAAK;AAClF,SAAK,MAAM,eAAe,MAAM,EAAE,QAAQ,OAAO,IAAI,CAAC,CAAC;AAAA,EACzD,CAAC;AAEH,MACG,QAAQ,KAAK,EACb,SAAS,MAAM,EACf,OAAO,OAAO,OAAe;AAC5B,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,WAAW,MAAM,eAAe,MAAM,EAAE,QAAQ,OAAO,YAAY,EAAE,EAAE,CAAC;AAC9E,SAAK,QAAQ;AACb,YAAQ,KAAK,qBAAqB,QAAQ,CAAC;AAAA,EAC7C,CAAC;AAEH,MACG,QAAQ,MAAM,EACd,SAAS,MAAM,EACf,OAAO,eAAe,EACtB,OAAO,OAAO,IAAY,SAA+B;AACxD,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,OAAgC,CAAC;AACvC,QAAI,KAAK,YAAY,OAAW,MAAK,WAAW,OAAO,KAAK,OAAO;AACnE,UAAM,WAAW,MAAM;AAAA,MACrB,MAAM,EAAE,QAAQ,QAAQ,YAAY,EAAE,SAAS,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC;AAAA,IAC/E;AACA,SAAK,QAAQ;AACb,YAAQ,KAAK,qBAAqB,QAAQ,CAAC;AAAA,EAC7C,CAAC;AAEH,MACG,QAAQ,QAAQ,EAChB,SAAS,MAAM,EACf,OAAO,OAAO,OAAe;AAC5B,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,SAAK,MAAM,eAAe,MAAM,EAAE,QAAQ,UAAU,YAAY,EAAE,EAAE,CAAC,CAAC;AAAA,EACxE,CAAC;AACL;;;ACrDO,SAAS,yBAAyB,SAAwB;AAC/D,UACG,QAAQ,WAAW,EACnB,YAAY,uDAAuD,EACnE,eAAe,wBAAwB,cAAc,EACrD,eAAe,2BAA2B,2BAA2B,EACrE,OAAO,sBAAsB,YAAY,EACzC,OAAO,OAAO,SAAmE;AAChF,UAAM,OAAgC,EAAE,SAAS,KAAK,SAAS,WAAW,KAAK;AAC/E,QAAI,KAAK,YAAY,OAAW,MAAK,YAAY,KAAK;AACtD,UAAM,IAAI,WAAW,mBAAmB,CAAC;AACzC,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C;AAAA,MACE,MAAM;AAAA,QACJ,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,KAAK,SAAS,YAAY;AAAA,UAClE,MAAM,KAAK,UAAU,IAAI;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACL;;;ACpBA,SAASC,eAAc;AACrB,SAAO,WAAW,mBAAmB,CAAC;AACxC;AAEO,SAAS,wBAAwB,SAAwB;AAC9D,QAAM,OAAO,QAAQ,QAAQ,SAAS,EAAE,YAAY,4BAA4B;AAEhF,OACG,QAAQ,QAAQ,EAChB,SAAS,QAAQ,EACjB,OAAO,kBAAkB,EACzB;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,OAAe,SAAmB,KAAK,OAAO,CAAC,KAAK,CAAC;AAAA,IACtD,CAAC;AAAA,EACH,EACC,OAAO,OAAO,MAAc,SAA4C;AACvE,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,OAAgC,CAAC;AACvC,QAAI,KAAK,OAAO,OAAW,MAAK,YAAY,KAAK;AACjD,QAAI,KAAK,UAAU,UAAa,KAAK,MAAM,SAAS,GAAG;AACrD,WAAK,gBAAgB,KAAK;AAAA,IAC5B;AACA;AAAA,MACE,MAAM;AAAA,QACJ,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,IAAI,aAAa;AAAA,UACzD,MAAM,KAAK,UAAU,IAAI;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,MAAM,EACd,SAAS,QAAQ,EACjB,OAAO,OAAO,SAAiB;AAC9B,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,SAAK,MAAM,eAAe,MAAM,EAAE,QAAQ,OAAO,kBAAkB,IAAI,WAAW,CAAC,CAAC;AAAA,EACtF,CAAC;AAEH,OACG,QAAQ,QAAQ,EAChB,SAAS,QAAQ,EACjB,SAAS,aAAa,EACtB,OAAO,OAAO,MAAc,cAAsB;AACjD,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C;AAAA,MACE,MAAM;AAAA,QACJ,MAAM,EAAE,QAAQ,UAAU,kBAAkB,IAAI,aAAa,SAAS,EAAE;AAAA,MAC1E;AAAA,IACF;AAAA,EACF,CAAC;AACL;;;AC7DA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,eAAe;AAExB,SAAS,gBAAgB,2BAA2B;AACpD,SAAS,SAAS,iBAAiB;AAKnC,SAASC,eAAc;AACrB,SAAO,WAAW,mBAAmB,CAAC;AACxC;AAEA,SAAS,YAAoC;AAC3C,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,GAAG,GAAG;AAChD,QAAI,OAAO,MAAM,SAAU,KAAI,CAAC,IAAI;AAAA,EACtC;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,MAAuB;AACjD,MAAI,CAACC,YAAW,IAAI,EAAG,MAAK,0BAA0B,IAAI,IAAI,CAAC;AAC/D,QAAM,OAAOC,cAAa,MAAM,OAAO;AACvC,MAAI;AACF,WAAO,eAAe,UAAU,IAAI,GAAG,UAAU,CAAC;AAAA,EACpD,SAAS,KAAc;AACrB,SAAK,+BAA+B,IAAI,KAAK,OAAO,GAAG,CAAC,IAAI,CAAC;AAAA,EAC/D;AACF;AAqCA,SAAS,oBAAoB,OAAiC;AAC5D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,OAAO,MAAM,IAAI,CAAC,MAAM;AAAA,IAC5B,EAAE;AAAA,IACF,EAAE;AAAA,IACF,OAAO,EAAE,UAAU;AAAA,IACnB,OAAO,EAAE,YAAY;AAAA,IACrB,UAAU,EAAE,SAAS;AAAA,EACvB,CAAC;AACD,SAAO,YAAY,CAAC,MAAM,QAAQ,UAAU,YAAY,KAAK,GAAG,IAAI;AACtE;AAEA,SAAS,sBAAsB,GAA4B;AACzD,QAAM,QAAkB;AAAA,IACtB,cAAc,EAAE,EAAE;AAAA,IAClB,cAAc,EAAE,IAAI;AAAA,IACpB,cAAc,UAAU,EAAE,SAAS,CAAC;AAAA,EACtC;AACA,MAAI,EAAE,WAAW,UAAa,EAAE,OAAO,SAAS,GAAG;AACjD,UAAM,OAAO,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC;AAC/D,UAAM,KAAK,IAAI,SAAS;AACxB,eAAW,MAAM,YAAY,CAAC,UAAU,YAAY,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,GAAG;AAC9E,YAAM,KAAK,OAAO,EAAE;AAAA,IACtB;AAAA,EACF;AACA,MAAI,EAAE,aAAa,UAAa,EAAE,SAAS,SAAS,GAAG;AACrD,UAAM,OAAO,EAAE,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC;AACvD,UAAM,KAAK,IAAI,WAAW;AAC1B,eAAW,MAAM,YAAY,CAAC,WAAW,KAAK,GAAG,IAAI,EAAE,MAAM,IAAI,GAAG;AAClE,YAAM,KAAK,OAAO,EAAE;AAAA,IACtB;AAAA,EACF;AACA,MAAI,EAAE,aAAa,MAAM;AACvB,UAAM,KAAK,IAAI,YAAY;AAC3B,eAAW,KAAK,CAAC,cAAc,gBAAgB,iBAAiB,cAAc,GAAY;AACxF,YAAM,KAAK,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE;AAAA,IAC1D;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAaA,SAAS,iBAAiB,OAAiC;AACzD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO;AAAA,IACL,CAAC,WAAW,SAAS;AAAA,IACrB,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC;AAAA,EACjD;AACF;AAEA,SAAS,WAAW,SAA6B;AAC/C,QAAM,QAAkB,CAAC;AACzB,aAAW,QAAQ,CAAC,SAAS,YAAY,SAAS,GAAY;AAC5D,eAAW,QAAQ,QAAQ,IAAI,EAAG,OAAM,KAAK,GAAG,KAAK,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE;AAAA,EAC1E;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;AAEO,SAAS,0BAA0B,SAAwB;AAChE,QAAM,KAAK,QAAQ,QAAQ,WAAW,EAAE,YAAY,oBAAoB;AAExE,KAAG,QAAQ,QAAQ,EAChB,YAAY,wDAAwD,EACpE,SAAS,YAAY,4BAA4B,EACjD,OAAO,aAAa,uBAAuB,EAC3C,OAAO,OAAO,YAAoB,SAA0B;AAC3D,UAAM,MAAM,oBAAoB,UAAU;AAC1C,UAAM,OAAyC,EAAE,QAAQ,IAAI;AAC7D,QAAI,KAAK,OAAO,OAAW,MAAK,KAAK,KAAK;AAC1C,UAAM,IAAIF,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,KAAK,CAAC;AAC1C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC;AAClF,SAAM,MAAM,eAAe,CAAC,GAAuB,qBAAqB;AAAA,EAC1E,CAAC;AAEH,KAAG,QAAQ,MAAM,EACd,YAAY,yBAAyB,EACrC,OAAO,YAAY;AAClB,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C;AAAA,MACG,MAAM,eAAe,MAAM,EAAE,QAAQ,OAAO,gBAAgB,CAAC;AAAA,MAC9D;AAAA,IACF;AAAA,EACF,CAAC;AAEH,KAAG,QAAQ,KAAK,EACb,YAAY,sCAAsC,EAClD,SAAS,MAAM,EACf,OAAO,aAAa,uCAAuC,EAC3D,OAAO,OAAO,IAAY,SAAgC;AACzD,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,OAAO,kBAAkB,EAAE,MAAM,KAAK,YAAY,OAAO,kBAAkB;AACjF;AAAA,MACG,MAAM,eAAe,MAAM,EAAE,QAAQ,OAAO,IAAI,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,EACF,CAAC;AAEH,KAAG,QAAQ,QAAQ,EAChB,YAAY,8BAA8B,EAC1C,SAAS,MAAM,EACf,OAAO,OAAO,OAAe;AAC5B,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C;AAAA,MACG,MAAM,eAAe,MAAM,EAAE,QAAQ,UAAU,kBAAkB,EAAE,EAAE,CAAC;AAAA,MAGvE,CAAC,MAAM,qBAAqB,EAAE,EAAE;AAAA,IAClC;AAAA,EACF,CAAC;AAEH,KAAG,QAAQ,OAAO,EACf,YAAY,8DAA8D,EAC1E,SAAS,SAAS,EAClB,OAAO,aAAa,2BAA2B,EAC/C,OAAO,cAAc,6DAA6D,EAClF,OAAO,OAAO,OAAe,SAAuC;AACnE,UAAM,OAAgC,EAAE,UAAU,MAAM;AACxD,QAAI,KAAK,OAAO,OAAW,MAAK,KAAK,KAAK;AAC1C,QAAI,KAAK,OAAO,OAAW,MAAK,KAAK,KAAK;AAC1C,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,wBAAwB,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC;AACxF,SAAM,MAAM,eAAe,CAAC,GAAuB,qBAAqB;AAAA,EAC1E,CAAC;AAEH,KAAG,QAAQ,QAAQ,EAChB,YAAY,oDAAoD,EAChE,SAAS,MAAM,EACf,OAAO,uBAAuB,mBAAmB,EAAE,EACnD,OAAO,yBAAyB,uBAAuB,MAAM,EAC7D,OAAO,OAAO,IAAY,SAA8C;AACvE,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,WAAW;AAAA,MAC/D,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,SAAS,QAAQ,KAAK,OAAO,CAAC;AAAA,IACrE,CAAC;AACD;AAAA,MACG,MAAM,eAAe,CAAC;AAAA,MACvB,CAAC,MAAM,aAAa,EAAE,QAAQ,MAAM,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM;AAAA,IAC3D;AAAA,EACF,CAAC;AAEH,KAAG,QAAQ,QAAQ,EAChB,YAAY,sDAAsD,EAClE,SAAS,MAAM,EACf,SAAS,QAAQ,EACjB,OAAO,mBAAmB,uBAAuB,MAAM,EACvD,OAAO,OAAO,IAAY,MAAc,SAA2B;AAClE,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,WAAW;AAAA,MAC/D,MAAM,KAAK,UAAU,EAAE,MAAM,YAAY,KAAK,KAAK,CAAC;AAAA,IACtD,CAAC;AACD;AAAA,MACG,MAAM,eAAe,CAAC;AAAA,MACvB,CAAC,MAAM,kBAAkB,EAAE,MAAM,OAAO,EAAE,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAChE;AAAA,EACF,CAAC;AAEH,KAAG,QAAQ,KAAK,EACb,YAAY,6CAA6C,EACzD,SAAS,MAAM,EACf,OAAO,yBAAyB,UAAU,MAAM,EAChD,OAAO,OAAO,IAAY,SAA6B;AACtD,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,OAAO,kBAAkB,EAAE,oBAAoB,KAAK,MAAM,EAAE;AACtF,SAAM,MAAM,eAAe,CAAC,GAAwB,gBAAgB;AAAA,EACtE,CAAC;AAEH,KAAG,QAAQ,MAAM,EACd,YAAY,2EAA2E,EACvF,SAAS,MAAM,EACf,SAAS,OAAO,kCAAkC,EAClD,SAAS,OAAO,qCAAqC,EACrD,OAAO,yBAAyB,UAAU,MAAM,EAChD;AAAA,IACC,OACE,IACA,GACA,GACA,SACG;AACH,YAAM,SAAS,IAAI,gBAAgB,EAAE,QAAQ,KAAK,OAAO,CAAC;AAC1D,UAAI,MAAM,OAAW,QAAO,IAAI,KAAK,CAAC;AACtC,UAAI,MAAM,OAAW,QAAO,IAAI,KAAK,CAAC;AACtC,YAAM,IAAIA,aAAY;AACtB,YAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,YAAM,IAAI,MAAM,EAAE,QAAQ,OAAO,kBAAkB,EAAE,SAAS,OAAO,SAAS,CAAC,EAAE;AACjF,WAAM,MAAM,eAAe,CAAC,GAAkB,UAAU;AAAA,IAC1D;AAAA,EACF;AAEF,KAAG,QAAQ,UAAU,EAClB,YAAY,sDAAsD,EAClE,SAAS,MAAM,EACf,SAAS,SAAS,iCAAiC,EACnD,OAAO,OAAO,IAAY,QAAgB;AACzC,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,aAAa;AAAA,MACjE,MAAM,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,IAC9B,CAAC;AACD,SAAM,MAAM,eAAe,CAAC,GAAuB,qBAAqB;AAAA,EAC1E,CAAC;AAEH,KAAG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EACF,EACC,SAAS,MAAM,EACf,SAAS,YAAY,2BAA2B,EAChD,OAAO,OAAO,IAAY,WAAmB;AAC5C,UAAM,IAAIA,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,MAAM,CAAC;AAC3C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,kBAAkB,EAAE,aAAa;AAAA,MACjE,MAAM,KAAK,UAAU,EAAE,MAAM,QAAQ,MAAM,EAAE,CAAC;AAAA,IAChD,CAAC;AACD,UAAM,IAAK,MAAM,eAAe,CAAC;AACjC,SAAK,GAAG,CAAC,MAAM,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,KAAK,eAAe,CAAC,UAAU;AAAA,EACpF,CAAC;AAEH,KAAG,QAAQ,MAAM,EACd,YAAY,mCAAmC,EAC/C,SAAS,SAAS,wDAAwD,EAC1E,SAAS,YAAY,4BAA4B,EACjD,OAAO,aAAa,uBAAuB,EAC3C,OAAO,OAAO,SAAiB,YAAgC,SAA0B;AACxF,QAAI,CAACC,YAAW,OAAO,EAAG,MAAK,uBAAuB,OAAO,IAAI,CAAC;AAClE,UAAM,OAA0D,EAAE,MAAM,QAAQ,OAAO,EAAE;AACzF,QAAI,KAAK,OAAO,OAAW,MAAK,KAAK,KAAK;AAC1C,QAAI,eAAe,OAAW,MAAK,WAAW,mBAAmB,UAAU;AAC3E,UAAM,IAAID,aAAY;AACtB,UAAM,EAAE,cAAc,EAAE,YAAY,KAAK,CAAC;AAC1C,UAAM,IAAI,MAAM,EAAE,QAAQ,QAAQ,uBAAuB,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC;AACvF,SAAM,MAAM,eAAe,CAAC,GAAuB,qBAAqB;AAAA,EAC1E,CAAC;AACL;;;ANlTA,SAAS,iBAAyB;AAChC,MAAI,MAAM,QAAQ,cAAc,YAAY,GAAG,CAAC;AAChD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI;AACF,YAAM,MAAM,KAAK,MAAMG,cAAaC,MAAK,KAAK,cAAc,GAAG,MAAM,CAAC;AAItE,UAAI,IAAI,SAAS,2BAA2B,IAAI,QAAS,QAAO,IAAI;AAAA,IACtE,QAAQ;AAAA,IAER;AACA,UAAM,QAAQ,GAAG;AAAA,EACnB;AACA,SAAO;AACT;AAEO,SAAS,eAAwB;AACtC,QAAM,UAAU,IAAI,QAAQ;AAC5B,UACG,KAAK,QAAQ,EACb,YAAY,4DAA4D,EACxE,QAAQ,eAAe,CAAC;AAC3B,4BAA0B,OAAO;AACjC,0BAAwB,OAAO;AAC/B,sBAAoB,OAAO;AAC3B,yBAAuB,OAAO;AAC9B,2BAAyB,OAAO;AAChC,yBAAuB,OAAO;AAC9B,SAAO;AACT;;;AOtCA,IAAM,UAAkC;AAAA,EACtC,kBAAkB;AAAA,EAClB,gBAAgB;AAClB;AAEA,SAAS,YAAY,MAA0B;AAC7C,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,eAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,OAAO,GAAG;AAChD,UAAI,QAAQ,KAAM,QAAO;AACzB,UAAI,IAAI,WAAW,OAAO,GAAG,EAAG,QAAO,KAAK,IAAI,MAAM,KAAK,MAAM;AAAA,IACnE;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEA,aAAa,EACV,WAAW,YAAY,QAAQ,IAAI,CAAC,EACpC,MAAM,CAAC,QAAiB;AACvB,UAAQ,MAAM,GAAG;AACjB,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["readFileSync","join","readFileSync","readFileSync","buildClient","buildClient","existsSync","readFileSync","buildClient","existsSync","readFileSync","readFileSync","join"]}
|
|
1
|
+
{"version":3,"sources":["../../src/bin/mirage.ts","../../src/main.ts","../../src/config.ts","../../src/daemon.ts","../../src/execute.ts","../../src/job.ts","../../src/mcp.ts","../../src/provision.ts","../../src/session.ts","../../src/workspace.ts"],"sourcesContent":["#!/usr/bin/env node\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { DaemonConfigError } from '@struktoai/mirage-server'\nimport { buildProgram } from '../main.ts'\n\nconst ALIASES: Record<string, string> = {\n '--workspace_id': '--workspace',\n '--session_id': '--session',\n}\n\nfunction rewriteArgv(argv: string[]): string[] {\n return argv.map((arg) => {\n for (const [from, to] of Object.entries(ALIASES)) {\n if (arg === from) return to\n if (arg.startsWith(from + '=')) return to + arg.slice(from.length)\n }\n return arg\n })\n}\n\nbuildProgram()\n .parseAsync(rewriteArgv(process.argv))\n .catch((err: unknown) => {\n if (err instanceof DaemonConfigError) {\n console.error(err.message)\n process.exit(2)\n }\n console.error(err)\n process.exit(1)\n })\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { registerConfigCommands } from './config.ts'\nimport { registerDaemonCommands } from './daemon.ts'\nimport { registerExecuteCommand } from './execute.ts'\nimport { registerJobCommands } from './job.ts'\nimport { registerMcpCommand } from './mcp.ts'\nimport { registerProvisionCommand } from './provision.ts'\nimport { registerSessionCommands } from './session.ts'\nimport { registerWorkspaceCommands } from './workspace.ts'\n\nfunction resolveVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {\n name?: string\n version?: string\n }\n if (pkg.name === '@struktoai/mirage-cli' && pkg.version) return pkg.version\n } catch {\n // package.json absent at this level: keep walking up to the package root\n }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n program\n .name('mirage')\n .description('Mirage daemon CLI: manage workspaces and execute commands.')\n .version(resolveVersion())\n registerWorkspaceCommands(program)\n registerSessionCommands(program)\n registerJobCommands(program)\n registerExecuteCommand(program)\n registerMcpCommand(program)\n registerProvisionCommand(program)\n registerDaemonCommands(program)\n registerConfigCommands(program)\n return program\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { ALLOWED_KEYS, DaemonConfigError } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { emit, fail } from './output.ts'\nimport { getConfig, listConfig, resolvedConfig, setConfig, unsetConfig } from './settings.ts'\n\nfunction mask(key: string, value: string): string {\n if (key === 'auth_token' && value !== '') return '***'\n return value\n}\n\ninterface ResolvedEntry {\n value: string\n origin: string\n}\n\nfunction humanTable(table: Record<string, string>): string {\n return Object.entries(table)\n .map(([k, v]) => `${k} = ${v}`)\n .join('\\n')\n}\n\nfunction humanResolved(table: Record<string, ResolvedEntry>): string {\n return Object.entries(table)\n .map(([k, e]) => `${k} = ${e.value} (${e.origin})`)\n .join('\\n')\n}\n\nfunction listResolved(): void {\n let resolved: Record<string, [string, string]>\n try {\n resolved = resolvedConfig()\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n const payload: Record<string, ResolvedEntry> = {}\n for (const [key, [value, origin]] of Object.entries(resolved)) {\n payload[key] = { value: mask(key, value), origin }\n }\n emit(payload, humanResolved)\n}\n\nfunction listFile(): void {\n let table: Record<string, string>\n try {\n table = listConfig()\n } catch (e) {\n if (!(e instanceof DaemonConfigError)) throw e\n fail(e.message, 2)\n return\n }\n const unknown = Object.keys(table)\n .filter((k) => !ALLOWED_KEYS.has(k))\n .sort()\n if (unknown.length > 0) {\n process.stderr.write(\n 'warning: unknown [daemon] keys (daemon will refuse to ' + `start): ${unknown.join(', ')}\\n`,\n )\n }\n emit(table, humanTable)\n}\n\nexport function registerConfigCommands(program: Command): void {\n const config = program\n .command('config')\n .description('Read and write daemon settings in config.toml.')\n\n config\n .command('list')\n .option('--resolved', 'show effective values and their origins')\n .description('Print the config.toml [daemon] table.')\n .action((opts: { resolved?: boolean }) => {\n if (opts.resolved === true) listResolved()\n else listFile()\n })\n\n config\n .command('get')\n .argument('<key>')\n .description('Print one [daemon] key.')\n .action((key: string) => {\n let value: string | undefined\n try {\n value = getConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n if (value === undefined) {\n fail(`${key} is not set`, 1)\n return\n }\n emit({ [key]: value }, () => value)\n })\n\n config\n .command('set')\n .argument('<key>')\n .argument('<value>')\n .description('Write a [daemon] key (path settings apply on next daemon restart).')\n .action((key: string, value: string) => {\n try {\n setConfig(key, value)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: value, written: true }, () => `${key} = ${value}`)\n })\n\n config\n .command('unset')\n .argument('<key>')\n .description('Remove a [daemon] key.')\n .action((key: string) => {\n try {\n unsetConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: null, unset: true }, () => `unset ${key}`)\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { pidFilePath } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\ninterface DaemonStatus {\n running: boolean\n pid: number | null\n url: string\n uptimeS?: number\n workspaces?: number\n}\n\nfunction formatStatus(d: DaemonStatus): string {\n if (!d.running) return `Daemon not running. URL: ${d.url}`\n const parts: string[] = [`Running. PID ${d.pid !== null ? String(d.pid) : '?'}`]\n if (d.uptimeS !== undefined) {\n parts.push(`uptime ${formatAge(Date.now() / 1000 - d.uptimeS)}`)\n }\n if (d.workspaces !== undefined) {\n parts.push(`${String(d.workspaces)} workspace${d.workspaces === 1 ? '' : 's'}`)\n }\n return parts.join(', ') + `. URL: ${d.url}`\n}\n\nfunction formatStop(d: { via?: string; pid?: number }): string {\n const via = d.via ?? '?'\n return `Stopped (via ${via}${d.pid !== undefined ? `, PID ${String(d.pid)}` : ''}).`\n}\n\nfunction formatRestart(d: { spawnedFresh?: boolean }): string {\n if (d.spawnedFresh === true) return 'Restarted (eager spawn).'\n return 'Restarted; next CLI command will auto-spawn.'\n}\n\nfunction formatKill(d: { killed: boolean; pid?: number | null }): string {\n if (d.killed) return `Killed PID ${String(d.pid ?? '?')}.`\n if (d.pid === null || d.pid === undefined) return 'Daemon not running.'\n return `Already gone (PID ${String(d.pid)}).`\n}\n\nfunction readPid(): number | null {\n const p = pidFilePath()\n if (!existsSync(p)) return null\n const text = readFileSync(p, 'utf-8').trim()\n const pid = Number(text)\n return Number.isFinite(pid) && pid > 0 ? pid : null\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n return false\n }\n}\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nasync function waitForUnreachable(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const c = buildClient()\n if (!(await c.isReachable(300))) return true\n await new Promise((r) => setTimeout(r, 200))\n }\n return false\n}\n\nexport function registerDaemonCommands(program: Command): void {\n const d = program.command('daemon').description('Manage the daemon process lifecycle.')\n\n d.command('status')\n .description('Show daemon health, PID, uptime, workspace count.')\n .action(async () => {\n const pid = readPid()\n const c = buildClient()\n const url = c.settings.url\n try {\n const r = await c.request('GET', '/v1/health')\n if (r.status !== 200) {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n const body = (await r.json()) as Record<string, unknown>\n emit({ running: true, pid, url, ...body } as DaemonStatus, formatStatus)\n } catch {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n })\n\n d.command('stop')\n .description('Gracefully stop the daemon.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .action(async (opts: { timeout: string }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n const c = buildClient()\n let r: Response\n try {\n r = await c.request('POST', '/v1/shutdown')\n } catch (err: unknown) {\n fail(`daemon not reachable: ${String(err)}`)\n }\n if (r.status >= 400) fail(`shutdown failed: ${await r.text()}`, 2)\n if (await waitForUnreachable(timeoutMs)) {\n emit({ stopped: true, via: 'graceful' }, formatStop)\n return\n }\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n emit({ stopped: true, via: 'sigterm', pid }, formatStop)\n return\n } catch {\n // fall through to fail\n }\n }\n fail(`daemon did not exit within ${opts.timeout}s and no live PID found`, 2)\n })\n\n d.command('restart')\n .description('Stop the daemon. Next CLI command auto-spawns a fresh one.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .option('--eager', 'Spawn a fresh daemon immediately')\n .action(async (opts: { timeout: string; eager?: boolean }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n try {\n await buildClient().request('POST', '/v1/shutdown')\n } catch {\n // already unreachable; fall through to pid cleanup\n }\n if (!(await waitForUnreachable(timeoutMs))) {\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // process may have exited between checks\n }\n }\n }\n if (opts.eager === true) {\n await buildClient().ensureRunning({ allowSpawn: true })\n emit({ restarted: true, spawnedFresh: true }, formatRestart)\n return\n }\n emit(\n {\n restarted: true,\n spawnedFresh: false,\n note: 'next workspace create will auto-spawn',\n },\n formatRestart,\n )\n })\n\n d.command('kill')\n .description('SIGKILL the daemon. Last resort -- skips graceful shutdown.')\n .action(() => {\n const pid = readPid()\n if (pid === null) {\n emit({ killed: false, reason: 'no daemon running', pid: null }, formatKill)\n return\n }\n if (!processAlive(pid)) {\n emit({ killed: false, reason: 'process already gone', pid }, formatKill)\n return\n }\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n emit({ killed: false, reason: 'process gone', pid }, formatKill)\n return\n }\n emit({ killed: true, pid }, formatKill)\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { readFileSync } from 'node:fs'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerExecuteCommand(program: Command): void {\n program\n .command('execute')\n .description('Execute a command.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to execute')\n .option('-s, --session <id>', 'Session id')\n .option('--bg', 'Background; return job_id immediately')\n .action(\n async (opts: { workspace: string; command: string; session?: string; bg?: boolean }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: false }\n if (opts.session !== undefined) body.sessionId = opts.session\n if (opts.bg !== true && !process.stdin.isTTY) {\n body.stdinBase64 = readFileSync(0).toString('base64')\n }\n const path =\n `/v1/workspaces/${opts.workspace}/execute` + (opts.bg === true ? '?background=true' : '')\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(\n await c.request('POST', path, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n },\n )\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nexport function registerJobCommands(program: Command): void {\n const job = program.command('job').description('Manage daemon jobs.')\n\n job\n .command('list')\n .option('-w, --workspace <id>')\n .action(async (opts: { workspace?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path =\n '/v1/jobs' + (opts.workspace !== undefined ? `?workspaceId=${opts.workspace}` : '')\n emit(await handleResponse(await c.request('GET', path)))\n })\n\n job\n .command('get')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(await c.request('GET', `/v1/jobs/${id}`))\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('wait')\n .argument('<id>')\n .option('--timeout <s>')\n .action(async (id: string, opts: { timeout?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.timeout !== undefined) body.timeoutS = Number(opts.timeout)\n const response = await handleResponse(\n await c.request('POST', `/v1/jobs/${id}/wait`, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('cancel')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('DELETE', `/v1/jobs/${id}`)))\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { serveMirageMcp } from '@struktoai/mirage-agents/mcp'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { buildWorkspaceFromConfig, resolveWorkspaceConfig } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\n\nexport interface McpConfigResolutionOptions {\n cwd?: string\n env?: Record<string, string | undefined>\n}\n\ninterface McpCommandOptions {\n staleWriteProtection: boolean\n}\n\nexport function resolveMcpConfig(\n config: string | undefined,\n options: McpConfigResolutionOptions = {},\n): string {\n return resolveWorkspaceConfig(config, {\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n ...(options.env !== undefined ? { env: options.env } : {}),\n envNames: ['MIRAGE_MCP_CONFIG', 'MIRAGE_CONFIG'],\n })\n}\n\nexport async function buildMcpWorkspace(configPath: string): Promise<Workspace> {\n return buildWorkspaceFromConfig(configPath)\n}\n\nasync function runMcpServer(config: string | undefined, options: McpCommandOptions): Promise<void> {\n const configPath = resolveMcpConfig(config)\n const workspace = await buildMcpWorkspace(configPath)\n try {\n await serveMirageMcp(workspace, {\n staleWriteProtection: options.staleWriteProtection,\n })\n } catch (error) {\n await workspace.close()\n throw error\n }\n}\n\nexport function registerMcpCommand(program: Command): void {\n program\n .command('mcp')\n .argument('[config]', 'Mirage workspace YAML config')\n .option('--no-stale-write-protection', 'allow edits after a file changed since it was read')\n .description('Serve a Mirage workspace as MCP tools over stdio.')\n .action(runMcpServer)\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerProvisionCommand(program: Command): void {\n program\n .command('provision')\n .description('Estimate cost / preview a command without running it.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to estimate')\n .option('-s, --session <id>', 'Session id')\n .action(async (opts: { workspace: string; command: string; session?: string }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: true }\n if (opts.session !== undefined) body.sessionId = opts.session\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${opts.workspace}/execute`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nconst MODES = new Set(['read', 'write', 'exec', 'r', 'rw', 'rwx'])\n\n/**\n * Parse `-m` values like `/data:read` into a modes mapping. Modes are\n * the words ('read', 'write', 'exec') or their cumulative filesystem\n * aliases ('r', 'rw', 'rwx'). A bare prefix (no mode suffix) keeps\n * the mount's own configured mode. The mode is taken from the last\n * `:` so mount prefixes that contain colons still parse.\n */\nexport function parseMountModes(mounts: string[]): Record<string, string> {\n const modes: Record<string, string> = {}\n for (const item of mounts) {\n const idx = item.lastIndexOf(':')\n const mode = idx >= 0 ? item.slice(idx + 1) : ''\n if (idx >= 0 && MODES.has(mode)) {\n modes[item.slice(0, idx)] = mode\n } else {\n modes[item] = 'exec'\n }\n }\n return modes\n}\n\nexport function registerSessionCommands(program: Command): void {\n const sess = program.command('session').description('Manage workspace sessions.')\n\n sess\n .command('create')\n .argument('<wsId>')\n .option('--id <sessionId>')\n .option(\n '-m, --mount <prefix>',\n \"restrict session to a mount, optionally capping its mode: '/data:read' \" +\n \"(alias '/data:r'), '/scratch:rw', '/bin:rwx', or a bare '/data' to keep \" +\n \"the mount's own mode; repeatable\",\n (value: string, prev: string[]) => prev.concat([value]),\n [] as string[],\n )\n .action(async (wsId: string, opts: { id?: string; mount?: string[] }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.id !== undefined) body.sessionId = opts.id\n if (opts.mount !== undefined && opts.mount.length > 0) {\n body.mounts = parseMountModes(opts.mount)\n }\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${wsId}/sessions`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n\n sess\n .command('list')\n .argument('<wsId>')\n .action(async (wsId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('GET', `/v1/workspaces/${wsId}/sessions`)))\n })\n\n sess\n .command('delete')\n .argument('<wsId>')\n .argument('<sessionId>')\n .action(async (wsId: string, sessionId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('DELETE', `/v1/workspaces/${wsId}/sessions/${sessionId}`),\n ),\n )\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { interpolateEnv, loadWorkspaceConfigFile } from '@struktoai/mirage-server'\nimport { parse as yamlParse } from 'yaml'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge, formatTable, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nfunction envRecord(): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') out[k] = v\n }\n return out\n}\n\nfunction loadConfigArgument(path: string): unknown {\n if (!existsSync(path)) fail(`config file not found: ${path}`, 2)\n const text = readFileSync(path, 'utf-8')\n try {\n return interpolateEnv(yamlParse(text), envRecord())\n } catch (err: unknown) {\n fail(`invalid config YAML/JSON at ${path}: ${String(err)}`, 2)\n }\n}\n\ninterface WorkspaceBrief {\n id: string\n mode: string\n mountCount: number\n sessionCount: number\n createdAt: number\n}\n\ninterface MountSummary {\n prefix: string\n resource: string\n mode: string\n}\n\ninterface SessionSummary {\n sessionId: string\n cwd: string\n}\n\ninterface Internals {\n cacheBytes: number | null\n cacheEntries: number | null\n historyLength: number\n inFlightJobs: number\n}\n\ninterface WorkspaceDetail {\n id: string\n mode: string\n createdAt: number\n mounts?: MountSummary[]\n sessions?: SessionSummary[]\n internals?: Internals | null\n}\n\nfunction formatWorkspaceList(items: WorkspaceBrief[]): string {\n if (items.length === 0) return 'No active workspaces.'\n const rows = items.map((w) => [\n w.id,\n w.mode,\n String(w.mountCount),\n String(w.sessionCount),\n formatAge(w.createdAt),\n ])\n return formatTable(['ID', 'MODE', 'MOUNTS', 'SESSIONS', 'AGE'], rows)\n}\n\nfunction formatWorkspaceDetail(d: WorkspaceDetail): string {\n const lines: string[] = [\n `ID: ${d.id}`,\n `Mode: ${d.mode}`,\n `Created: ${formatAge(d.createdAt)} ago`,\n ]\n if (d.mounts !== undefined && d.mounts.length > 0) {\n const rows = d.mounts.map((m) => [m.prefix, m.resource, m.mode])\n lines.push('', 'Mounts:')\n for (const ln of formatTable(['PREFIX', 'RESOURCE', 'MODE'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.sessions !== undefined && d.sessions.length > 0) {\n const rows = d.sessions.map((s) => [s.sessionId, s.cwd])\n lines.push('', 'Sessions:')\n for (const ln of formatTable(['SESSION', 'CWD'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.internals != null) {\n lines.push('', 'Internals:')\n for (const k of ['cacheBytes', 'cacheEntries', 'historyLength', 'inFlightJobs'] as const) {\n const value = d.internals[k]\n lines.push(` ${k.padEnd(16)} ${value === null ? 'n/a (not tracked)' : String(value)}`)\n }\n }\n return lines.join('\\n')\n}\n\ninterface VersionLogItem {\n id: string\n message: string\n}\n\ninterface DiffResult {\n added: string[]\n modified: string[]\n deleted: string[]\n}\n\nfunction formatVersionLog(items: VersionLogItem[]): string {\n if (items.length === 0) return 'No versions.'\n return formatTable(\n ['VERSION', 'MESSAGE'],\n items.map((v) => [v.id.slice(0, 12), v.message]),\n )\n}\n\nfunction formatDiff(changes: DiffResult): string {\n const lines: string[] = []\n for (const kind of ['added', 'modified', 'deleted'] as const) {\n for (const path of changes[kind]) lines.push(`${kind.padEnd(9)} ${path}`)\n }\n return lines.length > 0 ? lines.join('\\n') : 'No changes.'\n}\n\nexport function registerWorkspaceCommands(program: Command): void {\n const ws = program.command('workspace').description('Manage workspaces.')\n\n ws.command('create')\n .description('Create a workspace; daemon auto-spawns if not running.')\n .argument('<config>', 'YAML/JSON workspace config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (configPath: string, opts: { id?: string }) => {\n const cfg = loadWorkspaceConfigFile(configPath)\n const body: { config: unknown; id?: string } = { config: cfg }\n if (opts.id !== undefined) body.id = opts.id\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('list')\n .description('List active workspaces.')\n .action(async () => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('GET', '/v1/workspaces'))) as WorkspaceBrief[],\n formatWorkspaceList,\n )\n })\n\n ws.command('get')\n .description('Show full details for one workspace.')\n .argument('<id>')\n .option('--verbose', 'Include cache/dirty/history internals')\n .action(async (id: string, opts: { verbose?: boolean }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path = `/v1/workspaces/${id}` + (opts.verbose === true ? '?verbose=true' : '')\n emit(\n (await handleResponse(await c.request('GET', path))) as WorkspaceDetail,\n formatWorkspaceDetail,\n )\n })\n\n ws.command('delete')\n .description('Stop and remove a workspace.')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('DELETE', `/v1/workspaces/${id}`))) as {\n id: string\n },\n (d) => `Deleted workspace ${d.id}.`,\n )\n })\n\n ws.command('clone')\n .description('Clone a workspace, optionally from one of its past versions.')\n .argument('<srcId>')\n .option('--id <id>', 'Explicit id for the clone')\n .option('--at <ref>', 'Clone from a past version (id or branch) not the live state')\n .action(async (srcId: string, opts: { id?: string; at?: string }) => {\n const body: Record<string, unknown> = { sourceId: srcId }\n if (opts.id !== undefined) body.id = opts.id\n if (opts.at !== undefined) body.at = opts.at\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', '/v1/workspaces/clone', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('commit')\n .description(\"Commit the workspace's current state as a version.\")\n .argument('<id>')\n .option('-m, --message <msg>', 'Version message', '')\n .option('-b, --branch <branch>', 'Branch to commit on', 'main')\n .action(async (id: string, opts: { message: string; branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/commit`, {\n body: JSON.stringify({ message: opts.message, branch: opts.branch }),\n })\n emit(\n (await handleResponse(r)) as { version: string; branch: string },\n (d) => `Committed ${d.version.slice(0, 12)} on ${d.branch}.`,\n )\n })\n\n ws.command('branch')\n .description(\"Create a branch at another branch's current version.\")\n .argument('<id>')\n .argument('<name>')\n .option('--from <branch>', 'Branch to fork from', 'main')\n .action(async (id: string, name: string, opts: { from: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/branch`, {\n body: JSON.stringify({ name, fromBranch: opts.from }),\n })\n emit(\n (await handleResponse(r)) as { branch: string; version: string },\n (d) => `Created branch ${d.branch} at ${d.version.slice(0, 12)}.`,\n )\n })\n\n ws.command('log')\n .description(\"List a workspace's versions (newest first).\")\n .argument('<id>')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(async (id: string, opts: { branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/versions?branch=${opts.branch}`)\n emit((await handleResponse(r)) as VersionLogItem[], formatVersionLog)\n })\n\n ws.command('diff')\n .description('Show changed files (git-style): live vs HEAD, live vs <a>, or <a> vs <b>.')\n .argument('<id>')\n .argument('[a]', 'Base ref; omit to use live state')\n .argument('[b]', 'Compare ref; omit to use live state')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(\n async (\n id: string,\n a: string | undefined,\n b: string | undefined,\n opts: { branch: string },\n ) => {\n const params = new URLSearchParams({ branch: opts.branch })\n if (a !== undefined) params.set('a', a)\n if (b !== undefined) params.set('b', b)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/diff?${params.toString()}`)\n emit((await handleResponse(r)) as DiffResult, formatDiff)\n },\n )\n\n ws.command('checkout')\n .description('Restore a workspace in place to one of its versions.')\n .argument('<id>')\n .argument('<ref>', 'Version id or branch to restore')\n .action(async (id: string, ref: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/checkout`, {\n body: JSON.stringify({ ref }),\n })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('snapshot')\n .description(\n 'Snapshot a workspace to a tar file. The path is resolved to an absolute path and the daemon writes the tar.',\n )\n .argument('<id>')\n .argument('<output>', 'Path to write the .tar to')\n .action(async (id: string, output: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/snapshot`, {\n body: JSON.stringify({ path: resolve(output) }),\n })\n const d = (await handleResponse(r)) as { id: string; path: string; size: number }\n emit(d, (x) => `Snapshot ${x.id} -> ${x.path} (${x.size.toLocaleString()} bytes).`)\n })\n\n ws.command('load')\n .description('Load a workspace from a tar file.')\n .argument('<tar>', 'Path to a .tar produced by `mirage workspace snapshot`')\n .argument('[config]', 'Workspace YAML/JSON config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (tarPath: string, configPath: string | undefined, opts: { id?: string }) => {\n if (!existsSync(tarPath)) fail(`tar file not found: ${tarPath}`, 2)\n const body: { path: string; id?: string; override?: unknown } = { path: resolve(tarPath) }\n if (opts.id !== undefined) body.id = opts.id\n if (configPath !== undefined) body.override = loadConfigArgument(configPath)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces/load', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n}\n"],"mappings":"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","names":["DaemonConfigError","readFileSync","readFileSync","readFileSync","buildClient","buildClient","existsSync","readFileSync","buildClient","existsSync","readFileSync","readFileSync","DaemonConfigError"]}
|
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, openSync } from "fs";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import { homedir } from "os";
|
|
6
5
|
import { join } from "path";
|
|
7
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
AuthMode,
|
|
8
|
+
defaultTokenFile,
|
|
9
|
+
ensureTokenFile,
|
|
10
|
+
mirageHome,
|
|
11
|
+
readDaemonTable,
|
|
12
|
+
validateDaemonTable
|
|
13
|
+
} from "@struktoai/mirage-server";
|
|
8
14
|
|
|
9
15
|
// src/env.ts
|
|
10
16
|
import {
|
|
11
17
|
ENV_AUTH_MODE,
|
|
12
18
|
ENV_AUTH_TOKEN,
|
|
13
19
|
ENV_DAEMON_PORT,
|
|
14
|
-
ENV_IDLE_GRACE_SECONDS
|
|
15
|
-
ENV_JWT_ALG,
|
|
16
|
-
ENV_JWT_AUDIENCE,
|
|
17
|
-
ENV_JWT_AUTHORIZED_PARTIES,
|
|
18
|
-
ENV_JWT_CLOCK_SKEW,
|
|
19
|
-
ENV_JWT_ISSUER,
|
|
20
|
-
ENV_JWT_PUBKEY,
|
|
21
|
-
ENV_JWT_PUBKEY_FILE
|
|
20
|
+
ENV_IDLE_GRACE_SECONDS
|
|
22
21
|
} from "@struktoai/mirage-server";
|
|
23
22
|
var ENV_DAEMON_URL = "MIRAGE_DAEMON_URL";
|
|
24
23
|
var ENV_TOKEN = "MIRAGE_TOKEN";
|
|
@@ -111,18 +110,22 @@ var DaemonClient = class {
|
|
|
111
110
|
throw new Error(`daemon spawned but did not answer /v1/health within ${String(timeoutMs)}ms`);
|
|
112
111
|
}
|
|
113
112
|
spawnDaemon() {
|
|
113
|
+
const table = readDaemonTable(mirageHome());
|
|
114
|
+
validateDaemonTable(table);
|
|
114
115
|
const env = {};
|
|
115
116
|
for (const [k, v] of Object.entries(process.env)) {
|
|
116
117
|
if (typeof v === "string") env[k] = v;
|
|
117
118
|
}
|
|
118
|
-
env[ENV_DAEMON_PORT] = String(this.
|
|
119
|
+
env[ENV_DAEMON_PORT] = String(this.resolvePort(table));
|
|
119
120
|
env[ENV_IDLE_GRACE_SECONDS] = String(this.settings.idleGraceSeconds);
|
|
120
121
|
if (this.settings.authToken === "") {
|
|
121
|
-
this.settings.authToken = ensureTokenFile(
|
|
122
|
+
this.settings.authToken = ensureTokenFile(defaultTokenFile());
|
|
122
123
|
}
|
|
123
124
|
env[ENV_AUTH_TOKEN] = this.settings.authToken;
|
|
124
|
-
env[ENV_AUTH_MODE]
|
|
125
|
-
|
|
125
|
+
if ((env[ENV_AUTH_MODE] ?? "") === "" && (table.auth_mode ?? "") === "") {
|
|
126
|
+
env[ENV_AUTH_MODE] = AuthMode.Local;
|
|
127
|
+
}
|
|
128
|
+
const logDir = mirageHome();
|
|
126
129
|
mkdirSync(logDir, { recursive: true });
|
|
127
130
|
const out = openSync(join(logDir, "daemon.log"), "a");
|
|
128
131
|
const daemonEntry = requireFromHere.resolve("@struktoai/mirage-server/bin/daemon");
|
|
@@ -141,6 +144,13 @@ var DaemonClient = class {
|
|
|
141
144
|
});
|
|
142
145
|
child.unref();
|
|
143
146
|
}
|
|
147
|
+
resolvePort(table) {
|
|
148
|
+
const envPort = process.env[ENV_DAEMON_PORT];
|
|
149
|
+
if (envPort !== void 0 && envPort !== "") return Number(envPort);
|
|
150
|
+
const configPort = table.port;
|
|
151
|
+
if (configPort !== void 0 && configPort !== "") return Number(configPort);
|
|
152
|
+
return this.portFromUrl();
|
|
153
|
+
}
|
|
144
154
|
portFromUrl() {
|
|
145
155
|
const u = new URL(this.settings.url);
|
|
146
156
|
return Number(u.port) || 8765;
|
|
@@ -151,46 +161,23 @@ function makeClient(settings) {
|
|
|
151
161
|
}
|
|
152
162
|
|
|
153
163
|
// src/settings.ts
|
|
154
|
-
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
155
|
-
import {
|
|
156
|
-
import {
|
|
157
|
-
|
|
164
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
165
|
+
import { dirname, join as join2 } from "path";
|
|
166
|
+
import {
|
|
167
|
+
ALLOWED_KEYS,
|
|
168
|
+
DaemonConfigError,
|
|
169
|
+
DEFAULT_ALLOWED_HOSTS,
|
|
170
|
+
NUMERIC_KEYS,
|
|
171
|
+
defaultTokenFile as defaultTokenFile2,
|
|
172
|
+
mirageHome as mirageHome2,
|
|
173
|
+
parseDaemonTable,
|
|
174
|
+
readDaemonTable as readDaemonTable2,
|
|
175
|
+
readTokenFile
|
|
176
|
+
} from "@struktoai/mirage-server";
|
|
158
177
|
var DEFAULT_DAEMON_URL = "http://127.0.0.1:8765";
|
|
159
|
-
function defaultConfigPath() {
|
|
160
|
-
return join2(homedir2(), ".mirage", "config.toml");
|
|
161
|
-
}
|
|
162
|
-
function parseValue(raw) {
|
|
163
|
-
if (raw.startsWith('"') && raw.endsWith('"')) return raw.slice(1, -1);
|
|
164
|
-
return raw;
|
|
165
|
-
}
|
|
166
|
-
function readDaemonTable(path) {
|
|
167
|
-
if (!existsSync2(path)) return {};
|
|
168
|
-
const text = readFileSync(path, "utf-8");
|
|
169
|
-
const out = {};
|
|
170
|
-
let inDaemon = false;
|
|
171
|
-
for (const line of text.split("\n")) {
|
|
172
|
-
const trimmed = line.trim();
|
|
173
|
-
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
174
|
-
if (trimmed === "[daemon]") {
|
|
175
|
-
inDaemon = true;
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (trimmed.startsWith("[")) {
|
|
179
|
-
inDaemon = false;
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
if (!inDaemon) continue;
|
|
183
|
-
const eq = trimmed.indexOf("=");
|
|
184
|
-
if (eq < 0) continue;
|
|
185
|
-
const key = trimmed.slice(0, eq).trim();
|
|
186
|
-
out[key] = parseValue(trimmed.slice(eq + 1).trim());
|
|
187
|
-
}
|
|
188
|
-
return out;
|
|
189
|
-
}
|
|
190
178
|
function loadDaemonSettings(options = {}) {
|
|
191
179
|
const env = options.env ?? process.env;
|
|
192
|
-
const
|
|
193
|
-
const table = readDaemonTable(path);
|
|
180
|
+
const table = options.configPath !== void 0 ? existsSync2(options.configPath) ? parseDaemonTable(readFileSync(options.configPath, "utf-8")) : {} : readDaemonTable2(mirageHome2(env));
|
|
194
181
|
const settings = {
|
|
195
182
|
url: table.url ?? DEFAULT_DAEMON_URL,
|
|
196
183
|
authToken: table.auth_token ?? "",
|
|
@@ -205,13 +192,152 @@ function loadDaemonSettings(options = {}) {
|
|
|
205
192
|
settings.authToken = envToken;
|
|
206
193
|
}
|
|
207
194
|
if (settings.authToken === "") {
|
|
208
|
-
const fileToken = readTokenFile(options.tokenFile ??
|
|
195
|
+
const fileToken = readTokenFile(options.tokenFile ?? defaultTokenFile2(env));
|
|
209
196
|
if (fileToken !== void 0 && fileToken !== "") {
|
|
210
197
|
settings.authToken = fileToken;
|
|
211
198
|
}
|
|
212
199
|
}
|
|
213
200
|
return settings;
|
|
214
201
|
}
|
|
202
|
+
function defaultConfigPath(env = process.env) {
|
|
203
|
+
return join2(mirageHome2(env), "config.toml");
|
|
204
|
+
}
|
|
205
|
+
var ENV_FOR_KEY = {
|
|
206
|
+
url: ENV_DAEMON_URL,
|
|
207
|
+
allowed_hosts: "MIRAGE_ALLOWED_HOSTS",
|
|
208
|
+
auth_mode: "MIRAGE_AUTH_MODE",
|
|
209
|
+
jwt_alg: "MIRAGE_JWT_ALG",
|
|
210
|
+
jwt_issuer: "MIRAGE_JWT_ISSUER",
|
|
211
|
+
jwt_audience: "MIRAGE_JWT_AUDIENCE",
|
|
212
|
+
jwt_pubkey_file: "MIRAGE_JWT_PUBKEY_FILE",
|
|
213
|
+
jwt_clock_skew: "MIRAGE_JWT_CLOCK_SKEW_SECONDS",
|
|
214
|
+
jwt_authorized_parties: "MIRAGE_JWT_AUTHORIZED_PARTIES",
|
|
215
|
+
auth_token: ENV_TOKEN,
|
|
216
|
+
idle_grace_seconds: "MIRAGE_IDLE_GRACE_SECONDS",
|
|
217
|
+
port: "MIRAGE_DAEMON_PORT"
|
|
218
|
+
};
|
|
219
|
+
function defaultForKey(key) {
|
|
220
|
+
const defaults = {
|
|
221
|
+
url: DEFAULT_DAEMON_URL,
|
|
222
|
+
allowed_hosts: DEFAULT_ALLOWED_HOSTS.join(","),
|
|
223
|
+
auth_mode: "local",
|
|
224
|
+
jwt_alg: "",
|
|
225
|
+
jwt_issuer: "",
|
|
226
|
+
jwt_audience: "",
|
|
227
|
+
jwt_pubkey_file: "",
|
|
228
|
+
jwt_clock_skew: "5",
|
|
229
|
+
jwt_authorized_parties: "",
|
|
230
|
+
socket: "",
|
|
231
|
+
auth_token: "",
|
|
232
|
+
idle_grace_seconds: "30",
|
|
233
|
+
port: "8765"
|
|
234
|
+
};
|
|
235
|
+
return defaults[key] ?? "";
|
|
236
|
+
}
|
|
237
|
+
function resolvedConfig(env = process.env) {
|
|
238
|
+
const home = mirageHome2(env);
|
|
239
|
+
const table = readDaemonTable2(home);
|
|
240
|
+
const out = {};
|
|
241
|
+
for (const key of [...ALLOWED_KEYS].sort()) {
|
|
242
|
+
const envName = ENV_FOR_KEY[key];
|
|
243
|
+
if (envName !== void 0) {
|
|
244
|
+
const envValue = env[envName];
|
|
245
|
+
if (envValue !== void 0 && envValue !== "") {
|
|
246
|
+
out[key] = [envValue, `env ${envName}`];
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const fileValue = table[key];
|
|
251
|
+
if (fileValue !== void 0 && fileValue !== "") {
|
|
252
|
+
out[key] = [fileValue, "file"];
|
|
253
|
+
} else {
|
|
254
|
+
out[key] = [defaultForKey(key), "default"];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
function checkKey(key) {
|
|
260
|
+
if (!ALLOWED_KEYS.has(key)) {
|
|
261
|
+
throw new DaemonConfigError(
|
|
262
|
+
`unknown config key: '${key}'; allowed: ${[...ALLOWED_KEYS].sort().join(", ")}`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function formatValue(key, value) {
|
|
267
|
+
if (NUMERIC_KEYS.has(key)) return value;
|
|
268
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
269
|
+
}
|
|
270
|
+
function listConfig(path) {
|
|
271
|
+
const p = path ?? defaultConfigPath(process.env);
|
|
272
|
+
if (!existsSync2(p)) return {};
|
|
273
|
+
return parseDaemonTable(readFileSync(p, "utf-8"));
|
|
274
|
+
}
|
|
275
|
+
function getConfig(key, path) {
|
|
276
|
+
checkKey(key);
|
|
277
|
+
return listConfig(path)[key];
|
|
278
|
+
}
|
|
279
|
+
function setConfig(key, value, path) {
|
|
280
|
+
checkKey(key);
|
|
281
|
+
const p = path ?? defaultConfigPath(process.env);
|
|
282
|
+
const lines = existsSync2(p) ? readFileSync(p, "utf-8").split("\n") : [];
|
|
283
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
284
|
+
const rendered = `${key} = ${formatValue(key, value)}`;
|
|
285
|
+
let headerIdx = -1;
|
|
286
|
+
for (let i = 0; i < lines.length; i++) {
|
|
287
|
+
if ((lines[i] ?? "").trim() === "[daemon]") {
|
|
288
|
+
headerIdx = i;
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (headerIdx < 0) {
|
|
293
|
+
if (lines.length > 0 && (lines[lines.length - 1] ?? "").trim() !== "") lines.push("");
|
|
294
|
+
lines.push("[daemon]", rendered);
|
|
295
|
+
} else {
|
|
296
|
+
let end = lines.length;
|
|
297
|
+
for (let i = headerIdx + 1; i < lines.length; i++) {
|
|
298
|
+
if ((lines[i] ?? "").trim().startsWith("[")) {
|
|
299
|
+
end = i;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
let replaced = false;
|
|
304
|
+
for (let i = headerIdx + 1; i < end; i++) {
|
|
305
|
+
const t = (lines[i] ?? "").trim();
|
|
306
|
+
if (t.startsWith("#") || !t.includes("=")) continue;
|
|
307
|
+
if (t.slice(0, t.indexOf("=")).trim() === key) {
|
|
308
|
+
lines[i] = rendered;
|
|
309
|
+
replaced = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (!replaced) lines.splice(end, 0, rendered);
|
|
314
|
+
}
|
|
315
|
+
mkdirSync2(dirname(p), { recursive: true });
|
|
316
|
+
writeFileSync(p, lines.join("\n") + "\n");
|
|
317
|
+
chmodSync(p, 384);
|
|
318
|
+
}
|
|
319
|
+
function unsetConfig(key, path) {
|
|
320
|
+
const p = path ?? defaultConfigPath(process.env);
|
|
321
|
+
if (!existsSync2(p)) return;
|
|
322
|
+
const lines = readFileSync(p, "utf-8").split("\n");
|
|
323
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
324
|
+
const kept = [];
|
|
325
|
+
let inDaemon = false;
|
|
326
|
+
for (const line of lines) {
|
|
327
|
+
const t = line.trim();
|
|
328
|
+
if (t === "[daemon]") {
|
|
329
|
+
inDaemon = true;
|
|
330
|
+
kept.push(line);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (t.startsWith("[")) inDaemon = false;
|
|
334
|
+
if (inDaemon && t.includes("=") && !t.startsWith("#") && t.slice(0, t.indexOf("=")).trim() === key)
|
|
335
|
+
continue;
|
|
336
|
+
kept.push(line);
|
|
337
|
+
}
|
|
338
|
+
writeFileSync(p, kept.join("\n") + "\n");
|
|
339
|
+
chmodSync(p, 384);
|
|
340
|
+
}
|
|
215
341
|
|
|
216
342
|
// src/output.ts
|
|
217
343
|
function emit(obj, human) {
|
|
@@ -271,11 +397,11 @@ function formatTable(headers, rows) {
|
|
|
271
397
|
const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
272
398
|
const out = [];
|
|
273
399
|
out.push(
|
|
274
|
-
headers.map((h, i) => pad(h, widths[i] ?? h.length)).join(" ").
|
|
400
|
+
headers.map((h, i) => pad(h, widths[i] ?? h.length)).join(" ").trimEnd()
|
|
275
401
|
);
|
|
276
402
|
for (const row of norm) {
|
|
277
403
|
out.push(
|
|
278
|
-
row.map((c, i) => pad(c, widths[i] ?? c.length)).join(" ").
|
|
404
|
+
row.map((c, i) => pad(c, widths[i] ?? c.length)).join(" ").trimEnd()
|
|
279
405
|
);
|
|
280
406
|
}
|
|
281
407
|
return out.join("\n");
|
|
@@ -286,6 +412,11 @@ export {
|
|
|
286
412
|
makeClient,
|
|
287
413
|
DEFAULT_DAEMON_URL,
|
|
288
414
|
loadDaemonSettings,
|
|
415
|
+
resolvedConfig,
|
|
416
|
+
listConfig,
|
|
417
|
+
getConfig,
|
|
418
|
+
setConfig,
|
|
419
|
+
unsetConfig,
|
|
289
420
|
emit,
|
|
290
421
|
fail,
|
|
291
422
|
exitCodeFromResponse,
|
|
@@ -293,4 +424,4 @@ export {
|
|
|
293
424
|
formatAge,
|
|
294
425
|
formatTable
|
|
295
426
|
};
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
427
|
+
//# sourceMappingURL=chunk-TMXBYKRM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/env.ts","../src/settings.ts","../src/output.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, openSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport {\n AuthMode,\n defaultTokenFile,\n ensureTokenFile,\n mirageHome,\n readDaemonTable,\n validateDaemonTable,\n} from '@struktoai/mirage-server'\n\nimport { ENV_AUTH_MODE, ENV_AUTH_TOKEN, ENV_DAEMON_PORT, ENV_IDLE_GRACE_SECONDS } from './env.ts'\nimport type { DaemonSettings } from './settings.ts'\n\nconst requireFromHere = createRequire(import.meta.url)\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\nexport class DaemonClient {\n readonly settings: DaemonSettings\n\n constructor(settings: DaemonSettings) {\n this.settings = settings\n }\n\n private headers(extra?: Record<string, string>): Record<string, string> {\n const h: Record<string, string> = { ...extra }\n if (this.settings.authToken !== '') h.Authorization = `Bearer ${this.settings.authToken}`\n return h\n }\n\n async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const { timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, ...rest } = init\n const headers: Record<string, string> = {\n ...this.headers(),\n ...((rest.headers ?? {}) as Record<string, string>),\n }\n if (rest.body !== undefined && headers['Content-Type'] === undefined) {\n headers['Content-Type'] = 'application/json'\n }\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n return await fetch(this.settings.url + path, {\n ...rest,\n method,\n headers,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async requestMultipart(method: string, path: string, form: FormData): Promise<Response> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, DEFAULT_REQUEST_TIMEOUT_MS)\n try {\n return await fetch(this.settings.url + path, {\n method,\n headers: this.headers(),\n body: form,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async isReachable(timeoutMs = 500): Promise<boolean> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n const r = await fetch(this.settings.url + '/v1/health', {\n headers: this.headers(),\n signal: ctrl.signal,\n })\n return r.status === 200\n } catch {\n return false\n } finally {\n clearTimeout(t)\n }\n }\n\n async ensureRunning(opts: { allowSpawn?: boolean; timeoutMs?: number } = {}): Promise<void> {\n const allowSpawn = opts.allowSpawn ?? true\n const timeoutMs = opts.timeoutMs ?? 5000\n if (await this.isReachable()) return\n if (!allowSpawn) {\n throw new Error(\n `daemon not reachable at ${this.settings.url}; run \\`mirage workspace create CONFIG.yaml\\``,\n )\n }\n this.spawnDaemon()\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (await this.isReachable(300)) return\n await new Promise((r) => setTimeout(r, 100))\n }\n throw new Error(`daemon spawned but did not answer /v1/health within ${String(timeoutMs)}ms`)\n }\n\n private spawnDaemon(): void {\n const table = readDaemonTable(mirageHome())\n validateDaemonTable(table)\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') env[k] = v\n }\n env[ENV_DAEMON_PORT] = String(this.resolvePort(table))\n env[ENV_IDLE_GRACE_SECONDS] = String(this.settings.idleGraceSeconds)\n if (this.settings.authToken === '') {\n this.settings.authToken = ensureTokenFile(defaultTokenFile())\n }\n env[ENV_AUTH_TOKEN] = this.settings.authToken\n if ((env[ENV_AUTH_MODE] ?? '') === '' && (table.auth_mode ?? '') === '') {\n env[ENV_AUTH_MODE] = AuthMode.Local\n }\n const logDir = mirageHome()\n mkdirSync(logDir, { recursive: true })\n const out = openSync(join(logDir, 'daemon.log'), 'a')\n const daemonEntry = requireFromHere.resolve('@struktoai/mirage-server/bin/daemon')\n if (!existsSync(daemonEntry)) {\n throw new Error(\n `daemon binary not found at ${daemonEntry}; reinstall @struktoai/mirage-server`,\n )\n }\n const child = spawn(process.execPath, [daemonEntry], {\n env,\n detached: true,\n stdio: ['ignore', out, out],\n })\n child.on('error', (err) => {\n console.error('failed to spawn daemon:', err)\n })\n child.unref()\n }\n\n private resolvePort(table: Record<string, string>): number {\n const envPort = process.env[ENV_DAEMON_PORT]\n if (envPort !== undefined && envPort !== '') return Number(envPort)\n const configPort = table.port\n if (configPort !== undefined && configPort !== '') return Number(configPort)\n return this.portFromUrl()\n }\n\n private portFromUrl(): number {\n const u = new URL(this.settings.url)\n return Number(u.port) || 8765\n }\n}\n\nexport function makeClient(settings: DaemonSettings): DaemonClient {\n return new DaemonClient(settings)\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport {\n ENV_AUTH_MODE,\n ENV_AUTH_TOKEN,\n ENV_DAEMON_PORT,\n ENV_IDLE_GRACE_SECONDS,\n} from '@struktoai/mirage-server'\n\nexport const ENV_DAEMON_URL = 'MIRAGE_DAEMON_URL'\nexport const ENV_TOKEN = 'MIRAGE_TOKEN'\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport {\n ALLOWED_KEYS,\n DaemonConfigError,\n DEFAULT_ALLOWED_HOSTS,\n NUMERIC_KEYS,\n defaultTokenFile,\n mirageHome,\n parseDaemonTable,\n readDaemonTable,\n readTokenFile,\n} from '@struktoai/mirage-server'\n\nimport { ENV_DAEMON_URL, ENV_TOKEN } from './env.ts'\n\nexport const DEFAULT_DAEMON_URL = 'http://127.0.0.1:8765'\n\nexport interface DaemonSettings {\n url: string\n authToken: string\n idleGraceSeconds: number\n}\n\nexport interface LoadOptions {\n env?: Record<string, string | undefined>\n configPath?: string\n tokenFile?: string\n}\n\nexport function loadDaemonSettings(options: LoadOptions = {}): DaemonSettings {\n const env = options.env ?? (process.env as Record<string, string | undefined>)\n const table =\n options.configPath !== undefined\n ? existsSync(options.configPath)\n ? parseDaemonTable(readFileSync(options.configPath, 'utf-8'))\n : {}\n : readDaemonTable(mirageHome(env))\n const settings: DaemonSettings = {\n url: table.url ?? DEFAULT_DAEMON_URL,\n authToken: table.auth_token ?? '',\n idleGraceSeconds: Number(table.idle_grace_seconds ?? '30'),\n }\n const envUrl = env[ENV_DAEMON_URL]\n if (envUrl !== undefined && envUrl !== '') {\n settings.url = envUrl\n }\n const envToken = env[ENV_TOKEN]\n if (envToken !== undefined && envToken !== '') {\n settings.authToken = envToken\n }\n if (settings.authToken === '') {\n const fileToken = readTokenFile(options.tokenFile ?? defaultTokenFile(env))\n if (fileToken !== undefined && fileToken !== '') {\n settings.authToken = fileToken\n }\n }\n return settings\n}\n\nfunction defaultConfigPath(env: Record<string, string | undefined> = process.env): string {\n return join(mirageHome(env), 'config.toml')\n}\n\nconst ENV_FOR_KEY: Record<string, string> = {\n url: ENV_DAEMON_URL,\n allowed_hosts: 'MIRAGE_ALLOWED_HOSTS',\n auth_mode: 'MIRAGE_AUTH_MODE',\n jwt_alg: 'MIRAGE_JWT_ALG',\n jwt_issuer: 'MIRAGE_JWT_ISSUER',\n jwt_audience: 'MIRAGE_JWT_AUDIENCE',\n jwt_pubkey_file: 'MIRAGE_JWT_PUBKEY_FILE',\n jwt_clock_skew: 'MIRAGE_JWT_CLOCK_SKEW_SECONDS',\n jwt_authorized_parties: 'MIRAGE_JWT_AUTHORIZED_PARTIES',\n auth_token: ENV_TOKEN,\n idle_grace_seconds: 'MIRAGE_IDLE_GRACE_SECONDS',\n port: 'MIRAGE_DAEMON_PORT',\n}\n\nfunction defaultForKey(key: string): string {\n const defaults: Record<string, string> = {\n url: DEFAULT_DAEMON_URL,\n allowed_hosts: DEFAULT_ALLOWED_HOSTS.join(','),\n auth_mode: 'local',\n jwt_alg: '',\n jwt_issuer: '',\n jwt_audience: '',\n jwt_pubkey_file: '',\n jwt_clock_skew: '5',\n jwt_authorized_parties: '',\n socket: '',\n auth_token: '',\n idle_grace_seconds: '30',\n port: '8765',\n }\n return defaults[key] ?? ''\n}\n\nexport function resolvedConfig(\n env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,\n): Record<string, [string, string]> {\n const home = mirageHome(env)\n const table = readDaemonTable(home)\n const out: Record<string, [string, string]> = {}\n for (const key of [...ALLOWED_KEYS].sort()) {\n const envName = ENV_FOR_KEY[key]\n if (envName !== undefined) {\n const envValue = env[envName]\n if (envValue !== undefined && envValue !== '') {\n out[key] = [envValue, `env ${envName}`]\n continue\n }\n }\n const fileValue = table[key]\n if (fileValue !== undefined && fileValue !== '') {\n out[key] = [fileValue, 'file']\n } else {\n out[key] = [defaultForKey(key), 'default']\n }\n }\n return out\n}\n\nfunction checkKey(key: string): void {\n if (!ALLOWED_KEYS.has(key)) {\n throw new DaemonConfigError(\n `unknown config key: '${key}'; allowed: ${[...ALLOWED_KEYS].sort().join(', ')}`,\n )\n }\n}\n\nfunction formatValue(key: string, value: string): string {\n if (NUMERIC_KEYS.has(key)) return value\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n}\n\nexport function listConfig(path?: string): Record<string, string> {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return {}\n return parseDaemonTable(readFileSync(p, 'utf-8'))\n}\n\nexport function getConfig(key: string, path?: string): string | undefined {\n checkKey(key)\n return listConfig(path)[key]\n}\n\nexport function setConfig(key: string, value: string, path?: string): void {\n checkKey(key)\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n const lines = existsSync(p) ? readFileSync(p, 'utf-8').split('\\n') : []\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const rendered = `${key} = ${formatValue(key, value)}`\n let headerIdx = -1\n for (let i = 0; i < lines.length; i++) {\n if ((lines[i] ?? '').trim() === '[daemon]') {\n headerIdx = i\n break\n }\n }\n if (headerIdx < 0) {\n if (lines.length > 0 && (lines[lines.length - 1] ?? '').trim() !== '') lines.push('')\n lines.push('[daemon]', rendered)\n } else {\n let end = lines.length\n for (let i = headerIdx + 1; i < lines.length; i++) {\n if ((lines[i] ?? '').trim().startsWith('[')) {\n end = i\n break\n }\n }\n let replaced = false\n for (let i = headerIdx + 1; i < end; i++) {\n const t = (lines[i] ?? '').trim()\n if (t.startsWith('#') || !t.includes('=')) continue\n if (t.slice(0, t.indexOf('=')).trim() === key) {\n lines[i] = rendered\n replaced = true\n break\n }\n }\n if (!replaced) lines.splice(end, 0, rendered)\n }\n mkdirSync(dirname(p), { recursive: true })\n writeFileSync(p, lines.join('\\n') + '\\n')\n chmodSync(p, 0o600)\n}\n\nexport function unsetConfig(key: string, path?: string): void {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return\n const lines = readFileSync(p, 'utf-8').split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const kept: string[] = []\n let inDaemon = false\n for (const line of lines) {\n const t = line.trim()\n if (t === '[daemon]') {\n inDaemon = true\n kept.push(line)\n continue\n }\n if (t.startsWith('[')) inDaemon = false\n if (\n inDaemon &&\n t.includes('=') &&\n !t.startsWith('#') &&\n t.slice(0, t.indexOf('=')).trim() === key\n )\n continue\n kept.push(line)\n }\n writeFileSync(p, kept.join('\\n') + '\\n')\n chmodSync(p, 0o600)\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport type Formatter<T = unknown> = (obj: T) => string\n\nexport function emit<T = unknown>(obj: T, human?: Formatter<T>): void {\n if (human !== undefined && process.stdout.isTTY) {\n process.stdout.write(human(obj) + '\\n')\n return\n }\n process.stdout.write(JSON.stringify(obj, null, 2) + '\\n')\n}\n\nexport function fail(message: string, exitCode = 1): never {\n process.stderr.write(message + '\\n')\n process.exit(exitCode)\n}\n\nexport function exitCodeFromResponse(r: unknown): number {\n if (typeof r !== 'object' || r === null) return 0\n const obj = r as Record<string, unknown>\n const inner =\n obj.kind === 'io' ? obj : ((obj.result as Record<string, unknown> | null | undefined) ?? null)\n if (\n inner !== null &&\n inner.kind === 'io' &&\n typeof inner.exitCode === 'number' &&\n Number.isFinite(inner.exitCode)\n ) {\n return Math.min(255, Math.max(0, Math.trunc(inner.exitCode)))\n }\n if (typeof obj.status === 'string' && (obj.status === 'failed' || obj.status === 'canceled')) {\n return 2\n }\n return 0\n}\n\nexport async function handleResponse(r: Response): Promise<unknown> {\n if (r.status >= 400) {\n let detail = await r.text()\n try {\n const parsed = JSON.parse(detail) as { detail?: string }\n if (parsed.detail !== undefined) detail = parsed.detail\n } catch {\n // body wasn't JSON; fall through with the raw text as detail\n }\n fail(`daemon error ${String(r.status)}: ${detail}`, 2)\n }\n if (r.status === 204) return {}\n const text = await r.text()\n if (text === '') return {}\n return JSON.parse(text) as unknown\n}\n\nexport function formatAge(epoch: number, now: number = Date.now() / 1000): string {\n const delta = Math.max(0, now - epoch)\n if (delta < 60) return `${String(Math.floor(delta))}s`\n if (delta < 3600) return `${String(Math.floor(delta / 60))}m`\n if (delta < 86400) return `${String(Math.floor(delta / 3600))}h`\n return `${String(Math.floor(delta / 86400))}d`\n}\n\nexport function formatTable(headers: string[], rows: (string | undefined)[][]): string {\n if (rows.length === 0) return headers.join(' ')\n const norm: string[][] = rows.map((row) => row.map((c) => c ?? ''))\n const widths = headers.map((h) => h.length)\n for (const row of norm) {\n for (let i = 0; i < row.length; i++) {\n widths[i] = Math.max(widths[i] ?? 0, row[i]?.length ?? 0)\n }\n }\n const pad = (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length))\n const out: string[] = []\n out.push(\n headers\n .map((h, i) => pad(h, widths[i] ?? h.length))\n .join(' ')\n .trimEnd(),\n )\n for (const row of norm) {\n out.push(\n row\n .map((c, i) => pad(c, widths[i] ?? c.length))\n .join(' ')\n .trimEnd(),\n )\n }\n return out.join('\\n')\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","join","defaultTokenFile","mirageHome","readDaemonTable","existsSync","readDaemonTable","mirageHome","defaultTokenFile","join","mkdirSync"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@struktoai/mirage-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "A Unified Virtual Filesystem For AI Agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bash",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"commander": "^14.0.0",
|
|
44
44
|
"yaml": "^2.6.0",
|
|
45
|
-
"@struktoai/mirage-
|
|
45
|
+
"@struktoai/mirage-node": "0.0.4",
|
|
46
|
+
"@struktoai/mirage-agents": "0.0.4",
|
|
47
|
+
"@struktoai/mirage-server": "0.0.4"
|
|
46
48
|
},
|
|
47
49
|
"optionalDependencies": {
|
|
48
50
|
"@zkochan/fuse-native": "^0.1.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/env.ts","../src/settings.ts","../src/output.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, openSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { AuthMode, DEFAULT_TOKEN_FILE, ensureTokenFile } from '@struktoai/mirage-server'\n\nimport { ENV_AUTH_MODE, ENV_AUTH_TOKEN, ENV_DAEMON_PORT, ENV_IDLE_GRACE_SECONDS } from './env.ts'\nimport type { DaemonSettings } from './settings.ts'\n\nconst requireFromHere = createRequire(import.meta.url)\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\nexport class DaemonClient {\n readonly settings: DaemonSettings\n\n constructor(settings: DaemonSettings) {\n this.settings = settings\n }\n\n private headers(extra?: Record<string, string>): Record<string, string> {\n const h: Record<string, string> = { ...extra }\n if (this.settings.authToken !== '') h.Authorization = `Bearer ${this.settings.authToken}`\n return h\n }\n\n async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const { timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, ...rest } = init\n const headers: Record<string, string> = {\n ...this.headers(),\n ...((rest.headers ?? {}) as Record<string, string>),\n }\n if (rest.body !== undefined && headers['Content-Type'] === undefined) {\n headers['Content-Type'] = 'application/json'\n }\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n return await fetch(this.settings.url + path, {\n ...rest,\n method,\n headers,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async requestMultipart(method: string, path: string, form: FormData): Promise<Response> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, DEFAULT_REQUEST_TIMEOUT_MS)\n try {\n return await fetch(this.settings.url + path, {\n method,\n headers: this.headers(),\n body: form,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async isReachable(timeoutMs = 500): Promise<boolean> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n const r = await fetch(this.settings.url + '/v1/health', {\n headers: this.headers(),\n signal: ctrl.signal,\n })\n return r.status === 200\n } catch {\n return false\n } finally {\n clearTimeout(t)\n }\n }\n\n async ensureRunning(opts: { allowSpawn?: boolean; timeoutMs?: number } = {}): Promise<void> {\n const allowSpawn = opts.allowSpawn ?? true\n const timeoutMs = opts.timeoutMs ?? 5000\n if (await this.isReachable()) return\n if (!allowSpawn) {\n throw new Error(\n `daemon not reachable at ${this.settings.url}; run \\`mirage workspace create CONFIG.yaml\\``,\n )\n }\n this.spawnDaemon()\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (await this.isReachable(300)) return\n await new Promise((r) => setTimeout(r, 100))\n }\n throw new Error(`daemon spawned but did not answer /v1/health within ${String(timeoutMs)}ms`)\n }\n\n private spawnDaemon(): void {\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') env[k] = v\n }\n env[ENV_DAEMON_PORT] = String(this.portFromUrl())\n env[ENV_IDLE_GRACE_SECONDS] = String(this.settings.idleGraceSeconds)\n if (this.settings.authToken === '') {\n this.settings.authToken = ensureTokenFile(DEFAULT_TOKEN_FILE)\n }\n env[ENV_AUTH_TOKEN] = this.settings.authToken\n env[ENV_AUTH_MODE] ??= AuthMode.Local\n const logDir = join(homedir(), '.mirage')\n mkdirSync(logDir, { recursive: true })\n const out = openSync(join(logDir, 'daemon.log'), 'a')\n const daemonEntry = requireFromHere.resolve('@struktoai/mirage-server/bin/daemon')\n if (!existsSync(daemonEntry)) {\n throw new Error(\n `daemon binary not found at ${daemonEntry}; reinstall @struktoai/mirage-server`,\n )\n }\n const child = spawn(process.execPath, [daemonEntry], {\n env,\n detached: true,\n stdio: ['ignore', out, out],\n })\n child.on('error', (err) => {\n console.error('failed to spawn daemon:', err)\n })\n child.unref()\n }\n\n private portFromUrl(): number {\n const u = new URL(this.settings.url)\n return Number(u.port) || 8765\n }\n}\n\nexport function makeClient(settings: DaemonSettings): DaemonClient {\n return new DaemonClient(settings)\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport {\n ENV_AUTH_MODE,\n ENV_AUTH_TOKEN,\n ENV_DAEMON_PORT,\n ENV_IDLE_GRACE_SECONDS,\n ENV_JWT_ALG,\n ENV_JWT_AUDIENCE,\n ENV_JWT_AUTHORIZED_PARTIES,\n ENV_JWT_CLOCK_SKEW,\n ENV_JWT_ISSUER,\n ENV_JWT_PUBKEY,\n ENV_JWT_PUBKEY_FILE,\n} from '@struktoai/mirage-server'\n\nexport const ENV_DAEMON_URL = 'MIRAGE_DAEMON_URL'\nexport const ENV_TOKEN = 'MIRAGE_TOKEN'\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { DEFAULT_TOKEN_FILE, readTokenFile } from '@struktoai/mirage-server'\n\nimport { ENV_DAEMON_URL, ENV_TOKEN } from './env.ts'\n\nexport const DEFAULT_DAEMON_URL = 'http://127.0.0.1:8765'\n\nexport interface DaemonSettings {\n url: string\n authToken: string\n idleGraceSeconds: number\n}\n\nexport interface LoadOptions {\n env?: Record<string, string | undefined>\n configPath?: string\n tokenFile?: string\n}\n\nfunction defaultConfigPath(): string {\n return join(homedir(), '.mirage', 'config.toml')\n}\n\nfunction parseValue(raw: string): string {\n if (raw.startsWith('\"') && raw.endsWith('\"')) return raw.slice(1, -1)\n return raw\n}\n\nfunction readDaemonTable(path: string): Record<string, string> {\n if (!existsSync(path)) return {}\n const text = readFileSync(path, 'utf-8')\n const out: Record<string, string> = {}\n let inDaemon = false\n for (const line of text.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed === '' || trimmed.startsWith('#')) continue\n if (trimmed === '[daemon]') {\n inDaemon = true\n continue\n }\n if (trimmed.startsWith('[')) {\n inDaemon = false\n continue\n }\n if (!inDaemon) continue\n const eq = trimmed.indexOf('=')\n if (eq < 0) continue\n const key = trimmed.slice(0, eq).trim()\n out[key] = parseValue(trimmed.slice(eq + 1).trim())\n }\n return out\n}\n\nexport function loadDaemonSettings(options: LoadOptions = {}): DaemonSettings {\n const env = options.env ?? (process.env as Record<string, string | undefined>)\n const path = options.configPath ?? defaultConfigPath()\n const table = readDaemonTable(path)\n const settings: DaemonSettings = {\n url: table.url ?? DEFAULT_DAEMON_URL,\n authToken: table.auth_token ?? '',\n idleGraceSeconds: Number(table.idle_grace_seconds ?? '30'),\n }\n const envUrl = env[ENV_DAEMON_URL]\n if (envUrl !== undefined && envUrl !== '') {\n settings.url = envUrl\n }\n const envToken = env[ENV_TOKEN]\n if (envToken !== undefined && envToken !== '') {\n settings.authToken = envToken\n }\n if (settings.authToken === '') {\n const fileToken = readTokenFile(options.tokenFile ?? DEFAULT_TOKEN_FILE)\n if (fileToken !== undefined && fileToken !== '') {\n settings.authToken = fileToken\n }\n }\n return settings\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport type Formatter<T = unknown> = (obj: T) => string\n\nexport function emit<T = unknown>(obj: T, human?: Formatter<T>): void {\n if (human !== undefined && process.stdout.isTTY) {\n process.stdout.write(human(obj) + '\\n')\n return\n }\n process.stdout.write(JSON.stringify(obj, null, 2) + '\\n')\n}\n\nexport function fail(message: string, exitCode = 1): never {\n process.stderr.write(message + '\\n')\n process.exit(exitCode)\n}\n\nexport function exitCodeFromResponse(r: unknown): number {\n if (typeof r !== 'object' || r === null) return 0\n const obj = r as Record<string, unknown>\n const inner =\n obj.kind === 'io' ? obj : ((obj.result as Record<string, unknown> | null | undefined) ?? null)\n if (\n inner !== null &&\n inner.kind === 'io' &&\n typeof inner.exitCode === 'number' &&\n Number.isFinite(inner.exitCode)\n ) {\n return Math.min(255, Math.max(0, Math.trunc(inner.exitCode)))\n }\n if (typeof obj.status === 'string' && (obj.status === 'failed' || obj.status === 'canceled')) {\n return 2\n }\n return 0\n}\n\nexport async function handleResponse(r: Response): Promise<unknown> {\n if (r.status >= 400) {\n let detail = await r.text()\n try {\n const parsed = JSON.parse(detail) as { detail?: string }\n if (parsed.detail !== undefined) detail = parsed.detail\n } catch {\n // body wasn't JSON; fall through with the raw text as detail\n }\n fail(`daemon error ${String(r.status)}: ${detail}`, 2)\n }\n if (r.status === 204) return {}\n const text = await r.text()\n if (text === '') return {}\n return JSON.parse(text) as unknown\n}\n\nexport function formatAge(epoch: number, now: number = Date.now() / 1000): string {\n const delta = Math.max(0, now - epoch)\n if (delta < 60) return `${String(Math.floor(delta))}s`\n if (delta < 3600) return `${String(Math.floor(delta / 60))}m`\n if (delta < 86400) return `${String(Math.floor(delta / 3600))}h`\n return `${String(Math.floor(delta / 86400))}d`\n}\n\nexport function formatTable(headers: string[], rows: (string | undefined)[][]): string {\n if (rows.length === 0) return headers.join(' ')\n const norm: string[][] = rows.map((row) => row.map((c) => c ?? ''))\n const widths = headers.map((h) => h.length)\n for (const row of norm) {\n for (let i = 0; i < row.length; i++) {\n widths[i] = Math.max(widths[i] ?? 0, row[i]?.length ?? 0)\n }\n }\n const pad = (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length))\n const out: string[] = []\n out.push(\n headers\n .map((h, i) => pad(h, widths[i] ?? h.length))\n .join(' ')\n .replace(/\\s+$/, ''),\n )\n for (const row of norm) {\n out.push(\n row\n .map((c, i) => pad(c, widths[i] ?? c.length))\n .join(' ')\n .replace(/\\s+$/, ''),\n )\n }\n return out.join('\\n')\n}\n"],"mappings":"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","names":["existsSync","homedir","join","DEFAULT_TOKEN_FILE","join","homedir","existsSync","DEFAULT_TOKEN_FILE"]}
|