@openma/cli 0.3.2 → 0.4.0

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.
Files changed (2) hide show
  1. package/dist/index.js +3708 -270
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -47,30 +47,45 @@ function currentPlatform() {
47
47
  if (p === "darwin" || p === "linux" || p === "win32") return p;
48
48
  return "unknown";
49
49
  }
50
+ function currentProfile() {
51
+ const raw = (process.env.OMA_PROFILE ?? "").trim();
52
+ if (raw === "") return "";
53
+ if (!PROFILE_SLUG_RE.test(raw)) {
54
+ throw new Error(
55
+ `OMA_PROFILE="${raw}" is not a valid profile slug. Expected: lowercase letters/digits/dashes, starting with letter or digit, max 32 chars.`
56
+ );
57
+ }
58
+ return raw;
59
+ }
50
60
  function paths() {
51
61
  const home = homedir();
52
62
  const p = currentPlatform();
53
- const configDir = join(home, ".oma/bridge");
63
+ const profile = currentProfile();
64
+ const dirSuffix = profile ? `-${profile}` : "";
65
+ const labelSuffix = profile ? `.${profile}` : "";
66
+ const configDir = join(home, `.oma/bridge${dirSuffix}`);
54
67
  const credsFile = join(configDir, "credentials.json");
55
68
  const machineIdFile = join(configDir, "machine-id");
56
69
  const sessionsDir = join(configDir, "sessions");
57
70
  const logFile = join(configDir, "logs", "bridge.log");
71
+ const serviceLabel = `${SERVICE_LABEL_BASE}${labelSuffix}`;
58
72
  let serviceFile = null;
59
73
  if (p === "darwin") {
60
- serviceFile = join(home, "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
74
+ serviceFile = join(home, "Library", "LaunchAgents", `${serviceLabel}.plist`);
61
75
  } else if (p === "linux") {
62
- serviceFile = join(home, ".config", "systemd", "user", `${SERVICE_LABEL}.service`);
76
+ serviceFile = join(home, ".config", "systemd", "user", `${serviceLabel}.service`);
63
77
  }
64
- return { configDir, credsFile, machineIdFile, sessionsDir, logFile, serviceFile, serviceLabel: SERVICE_LABEL };
78
+ return { configDir, credsFile, machineIdFile, sessionsDir, logFile, serviceFile, serviceLabel };
65
79
  }
66
80
  function osTag() {
67
81
  return `${platform()}/${process.arch}`;
68
82
  }
69
- var SERVICE_LABEL;
83
+ var PROFILE_SLUG_RE, SERVICE_LABEL_BASE;
70
84
  var init_platform = __esm({
71
85
  "src/bridge/lib/platform.ts"() {
72
86
  "use strict";
73
- SERVICE_LABEL = "dev.openma.bridge";
87
+ PROFILE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$/;
88
+ SERVICE_LABEL_BASE = "dev.openma.bridge";
74
89
  }
75
90
  });
76
91
 
@@ -94,9 +109,9 @@ async function writeCreds(creds) {
94
109
  await chmod(file2, 384);
95
110
  }
96
111
  async function deleteCreds() {
97
- const { unlink: unlink2 } = await import("node:fs/promises");
112
+ const { unlink: unlink4 } = await import("node:fs/promises");
98
113
  try {
99
- await unlink2(paths().credsFile);
114
+ await unlink4(paths().credsFile);
100
115
  } catch (e) {
101
116
  if (e.code !== "ENOENT") throw e;
102
117
  }
@@ -121,15 +136,40 @@ var init_config = __esm({
121
136
  }
122
137
  });
123
138
 
124
- // src/bridge/lib/launchd.ts
125
- import { mkdir as mkdir2, writeFile as writeFile2, unlink, readFile as readFile2 } from "node:fs/promises";
139
+ // src/bridge/lib/service-templates.ts
126
140
  import { dirname as dirname2 } from "node:path";
127
- import { spawn } from "node:child_process";
141
+ function escapeXml(s) {
142
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
143
+ }
144
+ function dedupColon(p) {
145
+ const seen = /* @__PURE__ */ new Set();
146
+ return p.split(":").filter((part) => {
147
+ if (!part || seen.has(part)) return false;
148
+ seen.add(part);
149
+ return true;
150
+ }).join(":");
151
+ }
152
+ function dedupSemicolon(p) {
153
+ const seen = /* @__PURE__ */ new Set();
154
+ return p.split(";").filter((part) => {
155
+ if (!part || seen.has(part)) return false;
156
+ seen.add(part);
157
+ return true;
158
+ }).join(";");
159
+ }
128
160
  function buildPlist(opts) {
129
161
  const p = paths();
130
162
  const nodeDir = dirname2(opts.nodePath);
131
163
  const setupPath = process.env.PATH ?? "";
132
- const envPath = opts.envPath ?? dedupPath(setupPath ? `${nodeDir}:${setupPath}` : nodeDir);
164
+ const envPath = opts.envPath ?? dedupColon(setupPath ? `${nodeDir}:${setupPath}` : nodeDir);
165
+ const profile = currentProfile();
166
+ const envBlock = `<key>EnvironmentVariables</key>
167
+ <dict>
168
+ <key>PATH</key>
169
+ <string>${escapeXml(envPath)}</string>
170
+ ` + (profile ? ` <key>OMA_PROFILE</key>
171
+ <string>${escapeXml(profile)}</string>
172
+ ` : "") + ` </dict>`;
133
173
  return `<?xml version="1.0" encoding="UTF-8"?>
134
174
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
135
175
  <plist version="1.0">
@@ -153,26 +193,63 @@ function buildPlist(opts) {
153
193
  <string>${p.logFile}</string>
154
194
  <key>StandardErrorPath</key>
155
195
  <string>${p.logFile}</string>
156
- <key>EnvironmentVariables</key>
157
- <dict>
158
- <key>PATH</key>
159
- <string>${escapeXml(envPath)}</string>
160
- </dict>
196
+ ${envBlock}
161
197
  </dict>
162
198
  </plist>
163
199
  `;
164
200
  }
165
- function escapeXml(s) {
166
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
167
- }
168
- function dedupPath(p) {
169
- const seen = /* @__PURE__ */ new Set();
170
- return p.split(":").filter((part) => {
171
- if (!part || seen.has(part)) return false;
172
- seen.add(part);
173
- return true;
174
- }).join(":");
201
+ function buildUnit(opts) {
202
+ const p = paths();
203
+ const nodeDir = dirname2(opts.nodePath);
204
+ const setupPath = process.env.PATH ?? "";
205
+ const envPath = opts.envPath ?? dedupColon(setupPath ? `${nodeDir}:${setupPath}` : nodeDir);
206
+ const profile = currentProfile();
207
+ const profileLine = profile ? `
208
+ Environment=OMA_PROFILE=${profile}` : "";
209
+ return `[Unit]
210
+ Description=OMA Bridge Daemon
211
+ Documentation=https://github.com/open-ma/open-managed-agents
212
+ After=network-online.target
213
+ Wants=network-online.target
214
+
215
+ [Service]
216
+ Type=simple
217
+ ExecStart=${opts.nodePath} ${opts.cliEntry} bridge daemon
218
+ Restart=always
219
+ RestartSec=10
220
+ Environment=PATH=${envPath}${profileLine}
221
+ StandardOutput=append:${p.logFile}
222
+ StandardError=append:${p.logFile}
223
+
224
+ [Install]
225
+ WantedBy=default.target
226
+ `;
175
227
  }
228
+ function buildShim(opts) {
229
+ const nodeDir = dirname2(opts.nodePath);
230
+ const setupPath = process.env.PATH ?? "";
231
+ const envPath = opts.envPath ?? dedupSemicolon(setupPath ? `${nodeDir};${setupPath}` : nodeDir);
232
+ const logFile = paths().logFile;
233
+ const profile = currentProfile();
234
+ const lines = [
235
+ "@echo off",
236
+ `set "PATH=${envPath}"`,
237
+ profile ? `set "OMA_PROFILE=${profile}"` : "",
238
+ `"${opts.nodePath}" "${opts.cliEntry}" bridge daemon >> "${logFile}" 2>&1`
239
+ ].filter(Boolean);
240
+ return lines.join("\r\n") + "\r\n";
241
+ }
242
+ var init_service_templates = __esm({
243
+ "src/bridge/lib/service-templates.ts"() {
244
+ "use strict";
245
+ init_platform();
246
+ }
247
+ });
248
+
249
+ // src/bridge/lib/launchd.ts
250
+ import { mkdir as mkdir2, writeFile as writeFile2, unlink, readFile as readFile2 } from "node:fs/promises";
251
+ import { dirname as dirname3 } from "node:path";
252
+ import { spawn } from "node:child_process";
176
253
  async function install(opts) {
177
254
  if (currentPlatform() !== "darwin") {
178
255
  throw new Error(
@@ -181,8 +258,8 @@ async function install(opts) {
181
258
  }
182
259
  const p = paths();
183
260
  if (!p.serviceFile) throw new Error("no service file path on this platform");
184
- await mkdir2(dirname2(p.logFile), { recursive: true });
185
- await mkdir2(dirname2(p.serviceFile), { recursive: true });
261
+ await mkdir2(dirname3(p.logFile), { recursive: true });
262
+ await mkdir2(dirname3(p.serviceFile), { recursive: true });
186
263
  await writeFile2(p.serviceFile, buildPlist(opts), "utf-8");
187
264
  await runLaunchctl(["unload", p.serviceFile]).catch(() => void 0);
188
265
  await runLaunchctl(["load", "-w", p.serviceFile]);
@@ -232,83 +309,628 @@ var init_launchd = __esm({
232
309
  "src/bridge/lib/launchd.ts"() {
233
310
  "use strict";
234
311
  init_platform();
312
+ init_service_templates();
235
313
  }
236
314
  });
237
315
 
238
- // ../acp-runtime/src/registry.ts
316
+ // src/bridge/lib/systemd.ts
317
+ import { mkdir as mkdir3, writeFile as writeFile3, unlink as unlink2, readFile as readFile3 } from "node:fs/promises";
318
+ import { dirname as dirname4 } from "node:path";
239
319
  import { spawn as spawn2 } from "node:child_process";
240
- async function detect(id) {
241
- const entry = KNOWN_ACP_AGENTS.find((e) => e.id === id);
242
- if (!entry) return null;
243
- return await isOnPath(entry.spec.command) ? entry : null;
320
+ async function install2(opts) {
321
+ if (currentPlatform() !== "linux") {
322
+ throw new Error(
323
+ `systemd install only supported on Linux. Run \`oma bridge daemon\` in foreground or use the platform's service mechanism.`
324
+ );
325
+ }
326
+ const p = paths();
327
+ if (!p.serviceFile) throw new Error("no service file path on this platform");
328
+ await mkdir3(dirname4(p.logFile), { recursive: true });
329
+ await mkdir3(dirname4(p.serviceFile), { recursive: true });
330
+ await writeFile3(p.serviceFile, buildUnit(opts), "utf-8");
331
+ let warning;
332
+ let started = true;
333
+ try {
334
+ await runSystemctl(["--user", "daemon-reload"]);
335
+ await runSystemctl(["--user", "enable", "--now", `${p.serviceLabel}.service`]);
336
+ } catch (e) {
337
+ started = false;
338
+ warning = e.message;
339
+ }
340
+ const lingerEnabled = await isLingerEnabled().catch(() => false);
341
+ return { started, lingerEnabled, warning };
244
342
  }
245
- function isOnPath(cmd) {
343
+ async function uninstall2() {
344
+ if (currentPlatform() !== "linux") return { removed: false };
345
+ const p = paths();
346
+ if (!p.serviceFile) return { removed: false };
347
+ let warning;
348
+ await runSystemctl(["--user", "disable", "--now", `${p.serviceLabel}.service`]).catch((e) => {
349
+ warning = e.message;
350
+ });
351
+ try {
352
+ await unlink2(p.serviceFile);
353
+ await runSystemctl(["--user", "daemon-reload"]).catch(() => void 0);
354
+ return { removed: true, warning };
355
+ } catch (e) {
356
+ if (e.code === "ENOENT") return { removed: false };
357
+ throw e;
358
+ }
359
+ }
360
+ function runSystemctl(args) {
361
+ return new Promise((resolve, reject) => {
362
+ const p = spawn2("systemctl", args, { stdio: ["ignore", "pipe", "pipe"] });
363
+ let stderr = "";
364
+ p.stderr.on("data", (chunk) => stderr += chunk.toString());
365
+ p.once("error", (e) => reject(new Error(`systemctl spawn failed: ${e.message}`)));
366
+ p.once("exit", (code) => {
367
+ if (code === 0) resolve();
368
+ else reject(new Error(`systemctl ${args.join(" ")} exited ${code}: ${stderr.trim()}`));
369
+ });
370
+ });
371
+ }
372
+ async function isLingerEnabled() {
373
+ const user = process.env.USER ?? process.env.LOGNAME ?? "";
374
+ if (!user) return false;
246
375
  return new Promise((resolve) => {
247
- const probe = process.platform === "win32" ? "where" : "which";
248
- const p = spawn2(probe, [cmd], { stdio: "ignore" });
376
+ const p = spawn2("loginctl", ["show-user", user, "--property=Linger", "--value"], {
377
+ stdio: ["ignore", "pipe", "pipe"]
378
+ });
379
+ let out = "";
380
+ p.stdout.on("data", (c3) => out += c3.toString());
249
381
  p.once("error", () => resolve(false));
250
- p.once("exit", (code) => resolve(code === 0));
382
+ p.once("exit", () => resolve(out.trim().toLowerCase() === "yes"));
251
383
  });
252
384
  }
253
- async function detectAll() {
254
- const results = await Promise.all(KNOWN_ACP_AGENTS.map((e) => detect(e.id)));
255
- return results.filter((e) => e !== null);
385
+ function lingerHint() {
386
+ const user = process.env.USER ?? process.env.LOGNAME ?? "$USER";
387
+ return `sudo loginctl enable-linger ${user} # so daemon survives logout`;
256
388
  }
257
- var KNOWN_ACP_AGENTS;
258
- var init_registry = __esm({
259
- "../acp-runtime/src/registry.ts"() {
389
+ async function readInstalledCliEntry2() {
390
+ const p = paths();
391
+ if (!p.serviceFile) return null;
392
+ let unit;
393
+ try {
394
+ unit = await readFile3(p.serviceFile, "utf-8");
395
+ } catch {
396
+ return null;
397
+ }
398
+ const m = unit.match(/^ExecStart=([^\s]+)\s+([^\s]+)\s+bridge\s+daemon\s*$/m);
399
+ return m?.[2] ?? null;
400
+ }
401
+ var init_systemd = __esm({
402
+ "src/bridge/lib/systemd.ts"() {
403
+ "use strict";
404
+ init_platform();
405
+ init_service_templates();
406
+ }
407
+ });
408
+
409
+ // src/bridge/lib/windows-task.ts
410
+ import { mkdir as mkdir4, writeFile as writeFile4, unlink as unlink3, readFile as readFile4 } from "node:fs/promises";
411
+ import { dirname as dirname5, join as join2 } from "node:path";
412
+ import { spawn as spawn3 } from "node:child_process";
413
+ function shimPath() {
414
+ return join2(paths().configDir, "daemon.cmd");
415
+ }
416
+ async function install3(opts) {
417
+ if (currentPlatform() !== "win32") {
418
+ throw new Error(`Windows Task Scheduler install only supported on Windows.`);
419
+ }
420
+ const p = paths();
421
+ await mkdir4(dirname5(p.logFile), { recursive: true });
422
+ await mkdir4(p.configDir, { recursive: true });
423
+ const shim = shimPath();
424
+ await writeFile4(shim, buildShim(opts), "utf-8");
425
+ const taskName = p.serviceLabel;
426
+ const args = [
427
+ "/create",
428
+ "/tn",
429
+ taskName,
430
+ "/tr",
431
+ `"${shim}"`,
432
+ "/sc",
433
+ "onlogon",
434
+ "/it",
435
+ "/rl",
436
+ "limited",
437
+ "/f"
438
+ ];
439
+ let warning;
440
+ try {
441
+ await runSchtasks(args);
442
+ } catch (e) {
443
+ return { registered: false, startedNow: false, shimPath: shim, warning: e.message };
444
+ }
445
+ let startedNow = true;
446
+ try {
447
+ await runSchtasks(["/run", "/tn", taskName]);
448
+ } catch (e) {
449
+ startedNow = false;
450
+ warning = e.message;
451
+ }
452
+ return { registered: true, startedNow, shimPath: shim, warning };
453
+ }
454
+ async function uninstall3() {
455
+ if (currentPlatform() !== "win32") return { removed: false };
456
+ const p = paths();
457
+ const taskName = p.serviceLabel;
458
+ let warning;
459
+ await runSchtasks(["/end", "/tn", taskName]).catch(() => void 0);
460
+ let removed = false;
461
+ try {
462
+ await runSchtasks(["/delete", "/tn", taskName, "/f"]);
463
+ removed = true;
464
+ } catch (e) {
465
+ warning = e.message;
466
+ }
467
+ try {
468
+ await unlink3(shimPath());
469
+ } catch {
470
+ }
471
+ return { removed, warning };
472
+ }
473
+ function runSchtasks(args) {
474
+ return new Promise((resolve, reject) => {
475
+ const p = spawn3("schtasks.exe", args, { stdio: ["ignore", "pipe", "pipe"] });
476
+ let stderr = "";
477
+ let stdout = "";
478
+ p.stdout.on("data", (c3) => stdout += c3.toString());
479
+ p.stderr.on("data", (c3) => stderr += c3.toString());
480
+ p.once("error", (e) => reject(new Error(`schtasks spawn failed: ${e.message}`)));
481
+ p.once("exit", (code) => {
482
+ if (code === 0) resolve();
483
+ else reject(new Error(`schtasks ${args.join(" ")} exited ${code}: ${(stderr || stdout).trim()}`));
484
+ });
485
+ });
486
+ }
487
+ async function readInstalledCliEntry3() {
488
+ let shim;
489
+ try {
490
+ shim = await readFile4(shimPath(), "utf-8");
491
+ } catch {
492
+ return null;
493
+ }
494
+ const m = shim.match(/^"([^"]+)"\s+"([^"]+)"\s+bridge\s+daemon/m);
495
+ return m?.[2] ?? null;
496
+ }
497
+ var init_windows_task = __esm({
498
+ "src/bridge/lib/windows-task.ts"() {
499
+ "use strict";
500
+ init_platform();
501
+ init_service_templates();
502
+ }
503
+ });
504
+
505
+ // src/bridge/lib/service-manager.ts
506
+ function detectServiceKind() {
507
+ switch (currentPlatform()) {
508
+ case "darwin":
509
+ return "launchd";
510
+ case "linux":
511
+ return "systemd";
512
+ case "win32":
513
+ return "windows-task";
514
+ default:
515
+ return "unsupported";
516
+ }
517
+ }
518
+ async function install4(opts) {
519
+ const kind = detectServiceKind();
520
+ if (kind === "launchd") {
521
+ await install(opts);
522
+ return {
523
+ kind,
524
+ installedAt: paths().serviceFile,
525
+ started: true,
526
+ // launchctl load -w starts immediately
527
+ lingerEnabled: true
528
+ // n/a on macOS
529
+ };
530
+ }
531
+ if (kind === "systemd") {
532
+ const r = await install2(opts);
533
+ return {
534
+ kind,
535
+ installedAt: paths().serviceFile,
536
+ started: r.started,
537
+ warning: r.warning,
538
+ lingerEnabled: r.lingerEnabled
539
+ };
540
+ }
541
+ if (kind === "windows-task") {
542
+ const r = await install3(opts);
543
+ return {
544
+ kind,
545
+ installedAt: r.shimPath,
546
+ started: r.startedNow,
547
+ warning: r.warning,
548
+ lingerEnabled: true
549
+ // n/a on windows
550
+ };
551
+ }
552
+ return { kind, installedAt: null, started: false, lingerEnabled: true };
553
+ }
554
+ async function uninstall4() {
555
+ const kind = detectServiceKind();
556
+ if (kind === "launchd") {
557
+ const r = await uninstall();
558
+ return { kind, removed: r.removed };
559
+ }
560
+ if (kind === "systemd") {
561
+ const r = await uninstall2();
562
+ return { kind, removed: r.removed, warning: r.warning };
563
+ }
564
+ if (kind === "windows-task") {
565
+ const r = await uninstall3();
566
+ return { kind, removed: r.removed, warning: r.warning };
567
+ }
568
+ return { kind, removed: false };
569
+ }
570
+ async function readInstalledCliEntry4() {
571
+ const kind = detectServiceKind();
572
+ if (kind === "launchd") return readInstalledCliEntry();
573
+ if (kind === "systemd") return readInstalledCliEntry2();
574
+ if (kind === "windows-task") return readInstalledCliEntry3();
575
+ return null;
576
+ }
577
+ function lingerHint2() {
578
+ return detectServiceKind() === "systemd" ? lingerHint() : "";
579
+ }
580
+ var init_service_manager = __esm({
581
+ "src/bridge/lib/service-manager.ts"() {
582
+ "use strict";
583
+ init_platform();
584
+ init_launchd();
585
+ init_systemd();
586
+ init_windows_task();
587
+ }
588
+ });
589
+
590
+ // ../acp-runtime/src/known-agents.ts
591
+ var OMA_OVERLAY_AGENTS;
592
+ var init_known_agents = __esm({
593
+ "../acp-runtime/src/known-agents.ts"() {
260
594
  "use strict";
261
- KNOWN_ACP_AGENTS = [
595
+ OMA_OVERLAY_AGENTS = [
596
+ // claude-acp: ACP wrapper around the user's `claude` binary. setup
597
+ // and `bridge agents refresh` offer y/N install via npm. spec uses
598
+ // the bare binary (faster spawn than `npx -y` per turn); install
599
+ // tells the audit how to get the binary onto PATH.
262
600
  {
263
- id: "claude-agent-acp",
264
- label: "Claude Code",
601
+ id: "claude-acp",
602
+ label: "Claude Agent",
265
603
  spec: { command: "claude-agent-acp" },
604
+ aliases: ["claude-agent-acp", "claude-code-acp"],
605
+ featured: true,
606
+ wraps: "claude",
607
+ install: { kind: "npm", package: "@agentclientprotocol/claude-agent-acp" },
266
608
  installHint: "npm install -g @agentclientprotocol/claude-agent-acp",
267
609
  homepage: "https://github.com/agentclientprotocol/claude-agent-acp"
268
610
  },
611
+ // codex-acp: ACP wrapper around the user's `codex` binary. Zed
612
+ // Industries' Rust binary; distributed as GitHub release tarballs +
613
+ // an npm mirror. We leave `install` unset here so mergeOverlay picks
614
+ // up the per-platform archives from the live registry — keeps overlay
615
+ // a single source of truth (no version-pinned URLs to bit-rot).
269
616
  {
270
- id: "codex-cli",
617
+ id: "codex-acp",
271
618
  label: "Codex CLI",
272
- spec: { command: "codex", args: ["--acp"] },
273
- installHint: "npm install -g @openai/codex",
274
- homepage: "https://github.com/openai/codex"
619
+ spec: { command: "codex-acp" },
620
+ aliases: ["codex-cli", "codex-acp-bridge"],
621
+ featured: true,
622
+ wraps: "codex",
623
+ installHint: "download from https://github.com/zed-industries/codex-acp/releases and place on PATH",
624
+ homepage: "https://github.com/zed-industries/codex-acp"
275
625
  },
626
+ // gemini: official id is `gemini`. Pre-registry OMA had `gemini-cli`.
276
627
  {
277
- id: "gemini-cli",
628
+ id: "gemini",
278
629
  label: "Gemini CLI",
279
- spec: { command: "gemini", args: ["--experimental-acp"] },
630
+ spec: { command: "gemini", args: ["--acp"] },
631
+ aliases: ["gemini-cli"],
280
632
  installHint: "npm install -g @google/gemini-cli",
281
633
  homepage: "https://github.com/google-gemini/gemini-cli"
282
634
  },
635
+ // opencode: official id matches ours, no alias needed. Listed here
636
+ // anyway so the Console (overlay-only) still sees it without needing
637
+ // a CDN fetch.
283
638
  {
284
639
  id: "opencode",
285
640
  label: "OpenCode",
286
641
  spec: { command: "opencode", args: ["acp"] },
287
- installHint: "https://opencode.ai/docs/ \u2014 Go binary, install via the platform package or https://opencode.ai/install.sh",
642
+ installHint: "npm install -g opencode-ai@latest # or curl -fsSL https://opencode.ai/install | bash",
288
643
  homepage: "https://opencode.ai/"
289
644
  },
645
+ // hermes: NOT in official registry. Python-packaged; the official
646
+ // installer downloads + sets up the global `hermes` binary. We ship a
647
+ // full entry so it appears in install hints even though the registry
648
+ // doesn't know about it.
290
649
  {
291
650
  id: "hermes",
292
651
  label: "Hermes (Nous Research)",
293
652
  spec: { command: "hermes", args: ["acp"] },
294
- installHint: "see https://hermes-agent.nousresearch.com/docs/installation/",
653
+ featured: true,
654
+ installHint: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash",
295
655
  homepage: "https://github.com/NousResearch/hermes-agent"
296
656
  },
657
+ // openclaw: NOT in official registry. The `openclaw` cli's `acp`
658
+ // subcommand exposes an ACP bridge that forwards to the OpenClaw
659
+ // Gateway. Distinct from `acpx` (an ACP CLIENT, same GH org).
297
660
  {
298
- // Meta-CLI from openclaw that can wrap many non-native-ACP agents
299
- // (openclaw, cursor, pi, kiro, qwen). We ship one entry pointing at
300
- // openclaw because that's the most-asked-for; users can always pass
301
- // their own AgentSpec to wrap a different one.
302
661
  id: "openclaw",
303
- label: "OpenClaw (via acpx)",
304
- spec: { command: "acpx", args: ["openclaw"] },
305
- installHint: "npm install -g acpx",
306
- homepage: "https://github.com/openclaw/acpx"
662
+ label: "OpenClaw",
663
+ spec: { command: "openclaw", args: ["acp"] },
664
+ featured: true,
665
+ installHint: "npm install -g openclaw",
666
+ homepage: "https://github.com/openclaw/openclaw"
307
667
  }
308
668
  ];
309
669
  }
310
670
  });
311
671
 
672
+ // ../acp-runtime/src/registry-fetch.ts
673
+ import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "node:fs/promises";
674
+ import { dirname as dirname6 } from "node:path";
675
+ async function fetchOfficialRegistry(opts) {
676
+ const ttl = opts?.ttlMs ?? DEFAULT_TTL_MS;
677
+ const cachePath = opts?.cachePath;
678
+ if (cachePath) {
679
+ const cached2 = await readCache(cachePath);
680
+ if (cached2 && Date.now() - cached2.fetchedAt < ttl) {
681
+ return cached2.data;
682
+ }
683
+ if (cached2 && opts?.cacheOnly) return cached2.data;
684
+ }
685
+ if (opts?.cacheOnly) {
686
+ throw new Error("registry cacheOnly=true but no cache exists");
687
+ }
688
+ const controller = new AbortController();
689
+ const timer = setTimeout(() => controller.abort(), 5e3);
690
+ try {
691
+ const res = await fetch(REGISTRY_URL, { signal: controller.signal });
692
+ if (!res.ok) throw new Error(`registry fetch HTTP ${res.status}`);
693
+ const data = await res.json();
694
+ if (!Array.isArray(data?.agents)) {
695
+ throw new Error("registry JSON malformed (no .agents array)");
696
+ }
697
+ if (cachePath) {
698
+ await writeCache(cachePath, { fetchedAt: Date.now(), data }).catch(() => {
699
+ });
700
+ }
701
+ return data;
702
+ } catch (e) {
703
+ if (cachePath) {
704
+ const stale = await readCache(cachePath);
705
+ if (stale) return stale.data;
706
+ }
707
+ throw e;
708
+ } finally {
709
+ clearTimeout(timer);
710
+ }
711
+ }
712
+ async function readCache(path2) {
713
+ try {
714
+ const text = await readFile5(path2, "utf-8");
715
+ const obj = JSON.parse(text);
716
+ if (typeof obj?.fetchedAt !== "number" || !Array.isArray(obj?.data?.agents)) return null;
717
+ return obj;
718
+ } catch {
719
+ return null;
720
+ }
721
+ }
722
+ async function writeCache(path2, c3) {
723
+ await mkdir5(dirname6(path2), { recursive: true });
724
+ await writeFile5(path2, JSON.stringify(c3, null, 2), "utf-8");
725
+ }
726
+ function mapOfficialAgent(o) {
727
+ const platformKey2 = `${process.platform === "win32" ? "windows" : process.platform}-${process.arch === "arm64" ? "aarch64" : process.arch === "x64" ? "x86_64" : process.arch}`;
728
+ let spec = null;
729
+ let installHint;
730
+ let install5;
731
+ if (o.distribution.binary?.[platformKey2]) {
732
+ const b = o.distribution.binary[platformKey2];
733
+ const command = b.cmd.replace(/^\.\//, "").replace(/\.exe$/, "");
734
+ spec = { command, args: b.args };
735
+ installHint = `download ${b.archive} and place \`${command}\` on PATH`;
736
+ const archives = {};
737
+ for (const [k, v] of Object.entries(o.distribution.binary)) {
738
+ archives[k] = { url: v.archive, cmd: v.cmd };
739
+ }
740
+ install5 = { kind: "binary", archives, downloadUrl: o.repository };
741
+ } else if (o.distribution.npx) {
742
+ const n = o.distribution.npx;
743
+ spec = { command: "npx", args: ["-y", n.package, ...n.args ?? []], env: n.env };
744
+ installHint = `npx -y ${n.package}` + (n.args ? " " + n.args.join(" ") : "");
745
+ const lastAt = n.package.lastIndexOf("@");
746
+ const pkgName = lastAt > 0 ? n.package.slice(0, lastAt) : n.package;
747
+ install5 = { kind: "npm", package: pkgName };
748
+ } else if (o.distribution.uvx) {
749
+ const u = o.distribution.uvx;
750
+ spec = { command: "uvx", args: [u.package, ...u.args ?? []], env: u.env };
751
+ installHint = `uvx ${u.package}` + (u.args ? " " + u.args.join(" ") : "");
752
+ }
753
+ if (!spec) return null;
754
+ return {
755
+ id: o.id,
756
+ label: o.name,
757
+ spec,
758
+ installHint,
759
+ install: install5,
760
+ homepage: o.website ?? o.repository
761
+ };
762
+ }
763
+ var REGISTRY_URL, DEFAULT_TTL_MS;
764
+ var init_registry_fetch = __esm({
765
+ "../acp-runtime/src/registry-fetch.ts"() {
766
+ "use strict";
767
+ REGISTRY_URL = "https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json";
768
+ DEFAULT_TTL_MS = 60 * 60 * 1e3;
769
+ }
770
+ });
771
+
772
+ // ../acp-runtime/src/registry.ts
773
+ import { spawn as spawn4, spawnSync } from "node:child_process";
774
+ async function loadRegistry(opts) {
775
+ if (_mergedCache && !opts?.forceRefresh) return _mergedCache;
776
+ let officialMapped = [];
777
+ try {
778
+ const reg = await fetchOfficialRegistry({ cachePath: opts?.cachePath, ttlMs: opts?.ttlMs });
779
+ for (const o of reg.agents) {
780
+ const m = mapOfficialAgent(o);
781
+ if (m) officialMapped.push(m);
782
+ }
783
+ } catch (e) {
784
+ process.stderr.write(
785
+ `! ACP registry fetch failed (${e.message}); using OMA overlay only
786
+ `
787
+ );
788
+ officialMapped = [];
789
+ }
790
+ _mergedCache = mergeOverlay(officialMapped, OMA_OVERLAY_AGENTS);
791
+ _npmGlobalCache = snapshotNpmGlobal();
792
+ _uvToolCache = snapshotUvTool();
793
+ return _mergedCache;
794
+ }
795
+ function getKnownAgents() {
796
+ return _mergedCache ?? OMA_OVERLAY_AGENTS;
797
+ }
798
+ function resolveKnownAgent(id) {
799
+ const list = getKnownAgents();
800
+ for (const e of list) {
801
+ if (e.id === id) return e;
802
+ if (e.aliases?.includes(id)) return e;
803
+ }
804
+ return null;
805
+ }
806
+ function mergeOverlay(official, overlay) {
807
+ const overlayById = new Map(overlay.map((e) => [e.id, e]));
808
+ const seenOverlay = /* @__PURE__ */ new Set();
809
+ const merged = [];
810
+ for (const o of official) {
811
+ const ov = overlayById.get(o.id);
812
+ if (ov) {
813
+ seenOverlay.add(o.id);
814
+ merged.push({
815
+ id: o.id,
816
+ label: ov.label || o.label,
817
+ spec: ov.spec,
818
+ // overlay wins — usually carries our preferred binary
819
+ installHint: ov.installHint || o.installHint,
820
+ homepage: ov.homepage || o.homepage,
821
+ aliases: ov.aliases,
822
+ featured: ov.featured,
823
+ wraps: ov.wraps,
824
+ // Overlay's install wins when set (lets us pin a specific
825
+ // package). When unset, fall back to whatever mapOfficialAgent
826
+ // derived from the live registry — that's how codex-acp picks
827
+ // up its per-platform archives without overlay duplicating
828
+ // version-pinned URLs that bit-rot.
829
+ install: ov.install ?? o.install
830
+ });
831
+ } else {
832
+ merged.push(o);
833
+ }
834
+ }
835
+ for (const ov of overlay) {
836
+ if (!seenOverlay.has(ov.id)) merged.push(ov);
837
+ }
838
+ return merged;
839
+ }
840
+ async function detect(id) {
841
+ const entry = resolveKnownAgent(id);
842
+ if (!entry) return null;
843
+ if (!await isOnPath(entry.spec.command)) return null;
844
+ if (entry.spec.command === "npx" && !isNpxPackageInstalled(entry)) return null;
845
+ if (entry.spec.command === "uvx" && !isUvxPackageInstalled(entry)) return null;
846
+ return entry;
847
+ }
848
+ function isNpxPackageInstalled(entry) {
849
+ const pkgSpec = entry.spec.args?.[1];
850
+ if (!pkgSpec) return false;
851
+ const lastAt = pkgSpec.lastIndexOf("@");
852
+ const pkgName = lastAt > 0 ? pkgSpec.slice(0, lastAt) : pkgSpec;
853
+ const cache = _npmGlobalCache ?? (_npmGlobalCache = snapshotNpmGlobal());
854
+ return cache.has(pkgName);
855
+ }
856
+ function isUvxPackageInstalled(entry) {
857
+ const pkgSpec = entry.spec.args?.[0];
858
+ if (!pkgSpec) return false;
859
+ let pkgName = pkgSpec;
860
+ for (const sep of ["==", "@"]) {
861
+ const idx = pkgName.indexOf(sep, 1);
862
+ if (idx > 0) {
863
+ pkgName = pkgName.slice(0, idx);
864
+ break;
865
+ }
866
+ }
867
+ const cache = _uvToolCache ?? (_uvToolCache = snapshotUvTool());
868
+ return cache.has(pkgName);
869
+ }
870
+ function snapshotNpmGlobal() {
871
+ try {
872
+ const r = spawnSync("npm", ["ls", "-g", "--depth=0", "--parseable"], {
873
+ encoding: "utf-8",
874
+ timeout: 1e4
875
+ });
876
+ if (r.status !== 0 && !r.stdout) return /* @__PURE__ */ new Set();
877
+ const out = /* @__PURE__ */ new Set();
878
+ for (const line of (r.stdout ?? "").split("\n")) {
879
+ const trimmed = line.trim();
880
+ if (!trimmed) continue;
881
+ const idx = trimmed.lastIndexOf("/node_modules/");
882
+ if (idx < 0) continue;
883
+ const tail = trimmed.slice(idx + "/node_modules/".length);
884
+ if (!tail) continue;
885
+ out.add(tail);
886
+ }
887
+ return out;
888
+ } catch {
889
+ return /* @__PURE__ */ new Set();
890
+ }
891
+ }
892
+ function snapshotUvTool() {
893
+ try {
894
+ const r = spawnSync("uv", ["tool", "list"], { encoding: "utf-8", timeout: 1e4 });
895
+ if (r.status !== 0 && !r.stdout) return /* @__PURE__ */ new Set();
896
+ const out = /* @__PURE__ */ new Set();
897
+ for (const line of (r.stdout ?? "").split("\n")) {
898
+ if (!line || line.startsWith(" ") || line.startsWith("warning:")) continue;
899
+ const m = line.match(/^([a-zA-Z0-9._-]+)\s+v?\d/);
900
+ if (m) out.add(m[1]);
901
+ }
902
+ return out;
903
+ } catch {
904
+ return /* @__PURE__ */ new Set();
905
+ }
906
+ }
907
+ function isOnPath(cmd) {
908
+ return new Promise((resolve) => {
909
+ const probe = process.platform === "win32" ? "where" : "which";
910
+ const p = spawn4(probe, [cmd], { stdio: "ignore" });
911
+ p.once("error", () => resolve(false));
912
+ p.once("exit", (code) => resolve(code === 0));
913
+ });
914
+ }
915
+ async function detectAll() {
916
+ const list = getKnownAgents();
917
+ const results = await Promise.all(list.map((e) => detect(e.id)));
918
+ return results.filter((e) => e !== null);
919
+ }
920
+ var _mergedCache, _npmGlobalCache, _uvToolCache;
921
+ var init_registry = __esm({
922
+ "../acp-runtime/src/registry.ts"() {
923
+ "use strict";
924
+ init_known_agents();
925
+ init_registry_fetch();
926
+ init_known_agents();
927
+ init_known_agents();
928
+ _mergedCache = null;
929
+ _npmGlobalCache = null;
930
+ _uvToolCache = null;
931
+ }
932
+ });
933
+
312
934
  // src/bridge/lib/style.ts
313
935
  function wrap(open, close) {
314
936
  return (s) => isTty ? `\x1B[${open}m${s}\x1B[${close}m` : s;
@@ -387,9 +1009,9 @@ var init_version = __esm({
387
1009
  "use strict";
388
1010
  req = createRequire(import.meta.url);
389
1011
  PKG_VERSION = (() => {
390
- for (const path of ["../package.json", "../../package.json"]) {
1012
+ for (const path2 of ["../package.json", "../../package.json"]) {
391
1013
  try {
392
- return req(path).version;
1014
+ return req(path2).version;
393
1015
  } catch {
394
1016
  }
395
1017
  }
@@ -2693,8 +3315,8 @@ var require_websocket = __commonJS({
2693
3315
  var http = __require("http");
2694
3316
  var net = __require("net");
2695
3317
  var tls = __require("tls");
2696
- var { randomBytes: randomBytes3, createHash: createHash2 } = __require("crypto");
2697
- var { Duplex, Readable: Readable2 } = __require("stream");
3318
+ var { randomBytes: randomBytes4, createHash: createHash2 } = __require("crypto");
3319
+ var { Duplex, Readable: Readable3 } = __require("stream");
2698
3320
  var { URL: URL2 } = __require("url");
2699
3321
  var PerMessageDeflate = require_permessage_deflate();
2700
3322
  var Receiver2 = require_receiver();
@@ -3220,7 +3842,7 @@ var require_websocket = __commonJS({
3220
3842
  }
3221
3843
  }
3222
3844
  const defaultPort = isSecure ? 443 : 80;
3223
- const key = randomBytes3(16).toString("base64");
3845
+ const key = randomBytes4(16).toString("base64");
3224
3846
  const request = isSecure ? https.request : http.request;
3225
3847
  const protocolSet = /* @__PURE__ */ new Set();
3226
3848
  let perMessageDeflate;
@@ -4056,22 +4678,2410 @@ async function probeRuntimeToken(serverUrl, token, timeoutMs = 8e3) {
4056
4678
  if (status === 401 || status === 403 || status === 404) {
4057
4679
  settle({ ok: false, reason: "invalid", detail: `HTTP ${status}` });
4058
4680
  } else {
4059
- settle({ ok: true });
4681
+ settle({ ok: true });
4682
+ }
4683
+ });
4684
+ ws.once("error", (e) => {
4685
+ clearTimeout(timer);
4686
+ settle({
4687
+ ok: false,
4688
+ reason: "unreachable",
4689
+ detail: e instanceof Error ? e.message : String(e)
4690
+ });
4691
+ });
4692
+ });
4693
+ }
4694
+ var init_probe = __esm({
4695
+ "src/bridge/lib/probe.ts"() {
4696
+ "use strict";
4697
+ }
4698
+ });
4699
+
4700
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/key.js
4701
+ var isUpKey, isDownKey, isSpaceKey, isNumberKey, isEnterKey;
4702
+ var init_key = __esm({
4703
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/key.js"() {
4704
+ isUpKey = (key, keybindings = []) => (
4705
+ // The up key
4706
+ key.name === "up" || // Vim keybinding: hjkl keys map to left/down/up/right
4707
+ keybindings.includes("vim") && key.name === "k" || // Emacs keybinding: Ctrl+P means "previous" in Emacs navigation conventions
4708
+ keybindings.includes("emacs") && key.ctrl && key.name === "p"
4709
+ );
4710
+ isDownKey = (key, keybindings = []) => (
4711
+ // The down key
4712
+ key.name === "down" || // Vim keybinding: hjkl keys map to left/down/up/right
4713
+ keybindings.includes("vim") && key.name === "j" || // Emacs keybinding: Ctrl+N means "next" in Emacs navigation conventions
4714
+ keybindings.includes("emacs") && key.ctrl && key.name === "n"
4715
+ );
4716
+ isSpaceKey = (key) => key.name === "space";
4717
+ isNumberKey = (key) => "1234567890".includes(key.name);
4718
+ isEnterKey = (key) => key.name === "enter" || key.name === "return";
4719
+ }
4720
+ });
4721
+
4722
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/errors.js
4723
+ var AbortPromptError, CancelPromptError, ExitPromptError, HookError, ValidationError;
4724
+ var init_errors = __esm({
4725
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/errors.js"() {
4726
+ AbortPromptError = class extends Error {
4727
+ name = "AbortPromptError";
4728
+ message = "Prompt was aborted";
4729
+ constructor(options) {
4730
+ super();
4731
+ this.cause = options?.cause;
4732
+ }
4733
+ };
4734
+ CancelPromptError = class extends Error {
4735
+ name = "CancelPromptError";
4736
+ message = "Prompt was canceled";
4737
+ };
4738
+ ExitPromptError = class extends Error {
4739
+ name = "ExitPromptError";
4740
+ };
4741
+ HookError = class extends Error {
4742
+ name = "HookError";
4743
+ };
4744
+ ValidationError = class extends Error {
4745
+ name = "ValidationError";
4746
+ };
4747
+ }
4748
+ });
4749
+
4750
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/hook-engine.js
4751
+ import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
4752
+ function createStore(rl) {
4753
+ const store = {
4754
+ rl,
4755
+ hooks: [],
4756
+ hooksCleanup: [],
4757
+ hooksEffect: [],
4758
+ index: 0,
4759
+ handleChange() {
4760
+ }
4761
+ };
4762
+ return store;
4763
+ }
4764
+ function withHooks(rl, cb) {
4765
+ const store = createStore(rl);
4766
+ return hookStorage.run(store, () => {
4767
+ function cycle(render) {
4768
+ store.handleChange = () => {
4769
+ store.index = 0;
4770
+ render();
4771
+ };
4772
+ store.handleChange();
4773
+ }
4774
+ return cb(cycle);
4775
+ });
4776
+ }
4777
+ function getStore() {
4778
+ const store = hookStorage.getStore();
4779
+ if (!store) {
4780
+ throw new HookError("[Inquirer] Hook functions can only be called from within a prompt");
4781
+ }
4782
+ return store;
4783
+ }
4784
+ function readline() {
4785
+ return getStore().rl;
4786
+ }
4787
+ function withUpdates(fn) {
4788
+ const wrapped = (...args) => {
4789
+ const store = getStore();
4790
+ let shouldUpdate = false;
4791
+ const oldHandleChange = store.handleChange;
4792
+ store.handleChange = () => {
4793
+ shouldUpdate = true;
4794
+ };
4795
+ const returnValue = fn(...args);
4796
+ if (shouldUpdate) {
4797
+ oldHandleChange();
4798
+ }
4799
+ store.handleChange = oldHandleChange;
4800
+ return returnValue;
4801
+ };
4802
+ return AsyncResource.bind(wrapped);
4803
+ }
4804
+ function withPointer(cb) {
4805
+ const store = getStore();
4806
+ const { index } = store;
4807
+ const pointer = {
4808
+ get() {
4809
+ return store.hooks[index];
4810
+ },
4811
+ set(value) {
4812
+ store.hooks[index] = value;
4813
+ },
4814
+ initialized: index in store.hooks
4815
+ };
4816
+ const returnValue = cb(pointer);
4817
+ store.index++;
4818
+ return returnValue;
4819
+ }
4820
+ function handleChange() {
4821
+ getStore().handleChange();
4822
+ }
4823
+ var hookStorage, effectScheduler;
4824
+ var init_hook_engine = __esm({
4825
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/hook-engine.js"() {
4826
+ init_errors();
4827
+ hookStorage = new AsyncLocalStorage();
4828
+ effectScheduler = {
4829
+ queue(cb) {
4830
+ const store = getStore();
4831
+ const { index } = store;
4832
+ store.hooksEffect.push(() => {
4833
+ store.hooksCleanup[index]?.();
4834
+ const cleanFn = cb(readline());
4835
+ if (cleanFn != null && typeof cleanFn !== "function") {
4836
+ throw new ValidationError("useEffect return value must be a cleanup function or nothing.");
4837
+ }
4838
+ store.hooksCleanup[index] = cleanFn;
4839
+ });
4840
+ },
4841
+ run() {
4842
+ const store = getStore();
4843
+ withUpdates(() => {
4844
+ store.hooksEffect.forEach((effect) => {
4845
+ effect();
4846
+ });
4847
+ store.hooksEffect.length = 0;
4848
+ })();
4849
+ },
4850
+ clearAll() {
4851
+ const store = getStore();
4852
+ store.hooksCleanup.forEach((cleanFn) => {
4853
+ cleanFn?.();
4854
+ });
4855
+ store.hooksEffect.length = 0;
4856
+ store.hooksCleanup.length = 0;
4857
+ }
4858
+ };
4859
+ }
4860
+ });
4861
+
4862
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-state.js
4863
+ import { AsyncResource as AsyncResource2 } from "node:async_hooks";
4864
+ function isFactory(value) {
4865
+ return typeof value === "function";
4866
+ }
4867
+ function useState(defaultValue) {
4868
+ return withPointer((pointer) => {
4869
+ const setState = AsyncResource2.bind(function setState2(newValue) {
4870
+ if (pointer.get() !== newValue) {
4871
+ pointer.set(newValue);
4872
+ handleChange();
4873
+ }
4874
+ });
4875
+ if (pointer.initialized) {
4876
+ return [pointer.get(), setState];
4877
+ }
4878
+ const value = isFactory(defaultValue) ? defaultValue() : defaultValue;
4879
+ pointer.set(value);
4880
+ return [value, setState];
4881
+ });
4882
+ }
4883
+ var init_use_state = __esm({
4884
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-state.js"() {
4885
+ init_hook_engine();
4886
+ }
4887
+ });
4888
+
4889
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-effect.js
4890
+ function useEffect(cb, depArray) {
4891
+ withPointer((pointer) => {
4892
+ const oldDeps = pointer.get();
4893
+ const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
4894
+ if (hasChanged) {
4895
+ effectScheduler.queue(cb);
4896
+ }
4897
+ pointer.set(depArray);
4898
+ });
4899
+ }
4900
+ var init_use_effect = __esm({
4901
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-effect.js"() {
4902
+ init_hook_engine();
4903
+ }
4904
+ });
4905
+
4906
+ // ../../node_modules/.pnpm/@inquirer+figures@2.0.5/node_modules/@inquirer/figures/dist/index.js
4907
+ import process2 from "node:process";
4908
+ function isUnicodeSupported() {
4909
+ if (!process2.platform.startsWith("win")) {
4910
+ return process2.env["TERM"] !== "linux";
4911
+ }
4912
+ return Boolean(process2.env["CI"]) || // CI environments generally support unicode
4913
+ Boolean(process2.env["WT_SESSION"]) || // Windows Terminal
4914
+ Boolean(process2.env["TERMINUS_SUBLIME"]) || // Terminus (<0.2.27)
4915
+ process2.env["ConEmuTask"] === "{cmd::Cmder}" || // ConEmu and cmder
4916
+ process2.env["TERM_PROGRAM"] === "Terminus-Sublime" || process2.env["TERM_PROGRAM"] === "vscode" || process2.env["TERM"] === "xterm-256color" || process2.env["TERM"] === "alacritty" || process2.env["TERMINAL_EMULATOR"] === "JetBrains-JediTerm";
4917
+ }
4918
+ var common, specialMainSymbols, specialFallbackSymbols, mainSymbols, fallbackSymbols, shouldUseMain, figures, dist_default, replacements;
4919
+ var init_dist = __esm({
4920
+ "../../node_modules/.pnpm/@inquirer+figures@2.0.5/node_modules/@inquirer/figures/dist/index.js"() {
4921
+ common = {
4922
+ circleQuestionMark: "(?)",
4923
+ questionMarkPrefix: "(?)",
4924
+ square: "\u2588",
4925
+ squareDarkShade: "\u2593",
4926
+ squareMediumShade: "\u2592",
4927
+ squareLightShade: "\u2591",
4928
+ squareTop: "\u2580",
4929
+ squareBottom: "\u2584",
4930
+ squareLeft: "\u258C",
4931
+ squareRight: "\u2590",
4932
+ squareCenter: "\u25A0",
4933
+ bullet: "\u25CF",
4934
+ dot: "\u2024",
4935
+ ellipsis: "\u2026",
4936
+ pointerSmall: "\u203A",
4937
+ triangleUp: "\u25B2",
4938
+ triangleUpSmall: "\u25B4",
4939
+ triangleDown: "\u25BC",
4940
+ triangleDownSmall: "\u25BE",
4941
+ triangleLeftSmall: "\u25C2",
4942
+ triangleRightSmall: "\u25B8",
4943
+ home: "\u2302",
4944
+ heart: "\u2665",
4945
+ musicNote: "\u266A",
4946
+ musicNoteBeamed: "\u266B",
4947
+ arrowUp: "\u2191",
4948
+ arrowDown: "\u2193",
4949
+ arrowLeft: "\u2190",
4950
+ arrowRight: "\u2192",
4951
+ arrowLeftRight: "\u2194",
4952
+ arrowUpDown: "\u2195",
4953
+ almostEqual: "\u2248",
4954
+ notEqual: "\u2260",
4955
+ lessOrEqual: "\u2264",
4956
+ greaterOrEqual: "\u2265",
4957
+ identical: "\u2261",
4958
+ infinity: "\u221E",
4959
+ subscriptZero: "\u2080",
4960
+ subscriptOne: "\u2081",
4961
+ subscriptTwo: "\u2082",
4962
+ subscriptThree: "\u2083",
4963
+ subscriptFour: "\u2084",
4964
+ subscriptFive: "\u2085",
4965
+ subscriptSix: "\u2086",
4966
+ subscriptSeven: "\u2087",
4967
+ subscriptEight: "\u2088",
4968
+ subscriptNine: "\u2089",
4969
+ oneHalf: "\xBD",
4970
+ oneThird: "\u2153",
4971
+ oneQuarter: "\xBC",
4972
+ oneFifth: "\u2155",
4973
+ oneSixth: "\u2159",
4974
+ oneEighth: "\u215B",
4975
+ twoThirds: "\u2154",
4976
+ twoFifths: "\u2156",
4977
+ threeQuarters: "\xBE",
4978
+ threeFifths: "\u2157",
4979
+ threeEighths: "\u215C",
4980
+ fourFifths: "\u2158",
4981
+ fiveSixths: "\u215A",
4982
+ fiveEighths: "\u215D",
4983
+ sevenEighths: "\u215E",
4984
+ line: "\u2500",
4985
+ lineBold: "\u2501",
4986
+ lineDouble: "\u2550",
4987
+ lineDashed0: "\u2504",
4988
+ lineDashed1: "\u2505",
4989
+ lineDashed2: "\u2508",
4990
+ lineDashed3: "\u2509",
4991
+ lineDashed4: "\u254C",
4992
+ lineDashed5: "\u254D",
4993
+ lineDashed6: "\u2574",
4994
+ lineDashed7: "\u2576",
4995
+ lineDashed8: "\u2578",
4996
+ lineDashed9: "\u257A",
4997
+ lineDashed10: "\u257C",
4998
+ lineDashed11: "\u257E",
4999
+ lineDashed12: "\u2212",
5000
+ lineDashed13: "\u2013",
5001
+ lineDashed14: "\u2010",
5002
+ lineDashed15: "\u2043",
5003
+ lineVertical: "\u2502",
5004
+ lineVerticalBold: "\u2503",
5005
+ lineVerticalDouble: "\u2551",
5006
+ lineVerticalDashed0: "\u2506",
5007
+ lineVerticalDashed1: "\u2507",
5008
+ lineVerticalDashed2: "\u250A",
5009
+ lineVerticalDashed3: "\u250B",
5010
+ lineVerticalDashed4: "\u254E",
5011
+ lineVerticalDashed5: "\u254F",
5012
+ lineVerticalDashed6: "\u2575",
5013
+ lineVerticalDashed7: "\u2577",
5014
+ lineVerticalDashed8: "\u2579",
5015
+ lineVerticalDashed9: "\u257B",
5016
+ lineVerticalDashed10: "\u257D",
5017
+ lineVerticalDashed11: "\u257F",
5018
+ lineDownLeft: "\u2510",
5019
+ lineDownLeftArc: "\u256E",
5020
+ lineDownBoldLeftBold: "\u2513",
5021
+ lineDownBoldLeft: "\u2512",
5022
+ lineDownLeftBold: "\u2511",
5023
+ lineDownDoubleLeftDouble: "\u2557",
5024
+ lineDownDoubleLeft: "\u2556",
5025
+ lineDownLeftDouble: "\u2555",
5026
+ lineDownRight: "\u250C",
5027
+ lineDownRightArc: "\u256D",
5028
+ lineDownBoldRightBold: "\u250F",
5029
+ lineDownBoldRight: "\u250E",
5030
+ lineDownRightBold: "\u250D",
5031
+ lineDownDoubleRightDouble: "\u2554",
5032
+ lineDownDoubleRight: "\u2553",
5033
+ lineDownRightDouble: "\u2552",
5034
+ lineUpLeft: "\u2518",
5035
+ lineUpLeftArc: "\u256F",
5036
+ lineUpBoldLeftBold: "\u251B",
5037
+ lineUpBoldLeft: "\u251A",
5038
+ lineUpLeftBold: "\u2519",
5039
+ lineUpDoubleLeftDouble: "\u255D",
5040
+ lineUpDoubleLeft: "\u255C",
5041
+ lineUpLeftDouble: "\u255B",
5042
+ lineUpRight: "\u2514",
5043
+ lineUpRightArc: "\u2570",
5044
+ lineUpBoldRightBold: "\u2517",
5045
+ lineUpBoldRight: "\u2516",
5046
+ lineUpRightBold: "\u2515",
5047
+ lineUpDoubleRightDouble: "\u255A",
5048
+ lineUpDoubleRight: "\u2559",
5049
+ lineUpRightDouble: "\u2558",
5050
+ lineUpDownLeft: "\u2524",
5051
+ lineUpBoldDownBoldLeftBold: "\u252B",
5052
+ lineUpBoldDownBoldLeft: "\u2528",
5053
+ lineUpDownLeftBold: "\u2525",
5054
+ lineUpBoldDownLeftBold: "\u2529",
5055
+ lineUpDownBoldLeftBold: "\u252A",
5056
+ lineUpDownBoldLeft: "\u2527",
5057
+ lineUpBoldDownLeft: "\u2526",
5058
+ lineUpDoubleDownDoubleLeftDouble: "\u2563",
5059
+ lineUpDoubleDownDoubleLeft: "\u2562",
5060
+ lineUpDownLeftDouble: "\u2561",
5061
+ lineUpDownRight: "\u251C",
5062
+ lineUpBoldDownBoldRightBold: "\u2523",
5063
+ lineUpBoldDownBoldRight: "\u2520",
5064
+ lineUpDownRightBold: "\u251D",
5065
+ lineUpBoldDownRightBold: "\u2521",
5066
+ lineUpDownBoldRightBold: "\u2522",
5067
+ lineUpDownBoldRight: "\u251F",
5068
+ lineUpBoldDownRight: "\u251E",
5069
+ lineUpDoubleDownDoubleRightDouble: "\u2560",
5070
+ lineUpDoubleDownDoubleRight: "\u255F",
5071
+ lineUpDownRightDouble: "\u255E",
5072
+ lineDownLeftRight: "\u252C",
5073
+ lineDownBoldLeftBoldRightBold: "\u2533",
5074
+ lineDownLeftBoldRightBold: "\u252F",
5075
+ lineDownBoldLeftRight: "\u2530",
5076
+ lineDownBoldLeftBoldRight: "\u2531",
5077
+ lineDownBoldLeftRightBold: "\u2532",
5078
+ lineDownLeftRightBold: "\u252E",
5079
+ lineDownLeftBoldRight: "\u252D",
5080
+ lineDownDoubleLeftDoubleRightDouble: "\u2566",
5081
+ lineDownDoubleLeftRight: "\u2565",
5082
+ lineDownLeftDoubleRightDouble: "\u2564",
5083
+ lineUpLeftRight: "\u2534",
5084
+ lineUpBoldLeftBoldRightBold: "\u253B",
5085
+ lineUpLeftBoldRightBold: "\u2537",
5086
+ lineUpBoldLeftRight: "\u2538",
5087
+ lineUpBoldLeftBoldRight: "\u2539",
5088
+ lineUpBoldLeftRightBold: "\u253A",
5089
+ lineUpLeftRightBold: "\u2536",
5090
+ lineUpLeftBoldRight: "\u2535",
5091
+ lineUpDoubleLeftDoubleRightDouble: "\u2569",
5092
+ lineUpDoubleLeftRight: "\u2568",
5093
+ lineUpLeftDoubleRightDouble: "\u2567",
5094
+ lineUpDownLeftRight: "\u253C",
5095
+ lineUpBoldDownBoldLeftBoldRightBold: "\u254B",
5096
+ lineUpDownBoldLeftBoldRightBold: "\u2548",
5097
+ lineUpBoldDownLeftBoldRightBold: "\u2547",
5098
+ lineUpBoldDownBoldLeftRightBold: "\u254A",
5099
+ lineUpBoldDownBoldLeftBoldRight: "\u2549",
5100
+ lineUpBoldDownLeftRight: "\u2540",
5101
+ lineUpDownBoldLeftRight: "\u2541",
5102
+ lineUpDownLeftBoldRight: "\u253D",
5103
+ lineUpDownLeftRightBold: "\u253E",
5104
+ lineUpBoldDownBoldLeftRight: "\u2542",
5105
+ lineUpDownLeftBoldRightBold: "\u253F",
5106
+ lineUpBoldDownLeftBoldRight: "\u2543",
5107
+ lineUpBoldDownLeftRightBold: "\u2544",
5108
+ lineUpDownBoldLeftBoldRight: "\u2545",
5109
+ lineUpDownBoldLeftRightBold: "\u2546",
5110
+ lineUpDoubleDownDoubleLeftDoubleRightDouble: "\u256C",
5111
+ lineUpDoubleDownDoubleLeftRight: "\u256B",
5112
+ lineUpDownLeftDoubleRightDouble: "\u256A",
5113
+ lineCross: "\u2573",
5114
+ lineBackslash: "\u2572",
5115
+ lineSlash: "\u2571"
5116
+ };
5117
+ specialMainSymbols = {
5118
+ tick: "\u2714",
5119
+ info: "\u2139",
5120
+ warning: "\u26A0",
5121
+ cross: "\u2718",
5122
+ squareSmall: "\u25FB",
5123
+ squareSmallFilled: "\u25FC",
5124
+ circle: "\u25EF",
5125
+ circleFilled: "\u25C9",
5126
+ circleDotted: "\u25CC",
5127
+ circleDouble: "\u25CE",
5128
+ circleCircle: "\u24DE",
5129
+ circleCross: "\u24E7",
5130
+ circlePipe: "\u24BE",
5131
+ radioOn: "\u25C9",
5132
+ radioOff: "\u25EF",
5133
+ checkboxOn: "\u2612",
5134
+ checkboxOff: "\u2610",
5135
+ checkboxCircleOn: "\u24E7",
5136
+ checkboxCircleOff: "\u24BE",
5137
+ pointer: "\u276F",
5138
+ triangleUpOutline: "\u25B3",
5139
+ triangleLeft: "\u25C0",
5140
+ triangleRight: "\u25B6",
5141
+ lozenge: "\u25C6",
5142
+ lozengeOutline: "\u25C7",
5143
+ hamburger: "\u2630",
5144
+ smiley: "\u32E1",
5145
+ mustache: "\u0DF4",
5146
+ star: "\u2605",
5147
+ play: "\u25B6",
5148
+ nodejs: "\u2B22",
5149
+ oneSeventh: "\u2150",
5150
+ oneNinth: "\u2151",
5151
+ oneTenth: "\u2152"
5152
+ };
5153
+ specialFallbackSymbols = {
5154
+ tick: "\u221A",
5155
+ info: "i",
5156
+ warning: "\u203C",
5157
+ cross: "\xD7",
5158
+ squareSmall: "\u25A1",
5159
+ squareSmallFilled: "\u25A0",
5160
+ circle: "( )",
5161
+ circleFilled: "(*)",
5162
+ circleDotted: "( )",
5163
+ circleDouble: "( )",
5164
+ circleCircle: "(\u25CB)",
5165
+ circleCross: "(\xD7)",
5166
+ circlePipe: "(\u2502)",
5167
+ radioOn: "(*)",
5168
+ radioOff: "( )",
5169
+ checkboxOn: "[\xD7]",
5170
+ checkboxOff: "[ ]",
5171
+ checkboxCircleOn: "(\xD7)",
5172
+ checkboxCircleOff: "( )",
5173
+ pointer: ">",
5174
+ triangleUpOutline: "\u2206",
5175
+ triangleLeft: "\u25C4",
5176
+ triangleRight: "\u25BA",
5177
+ lozenge: "\u2666",
5178
+ lozengeOutline: "\u25CA",
5179
+ hamburger: "\u2261",
5180
+ smiley: "\u263A",
5181
+ mustache: "\u250C\u2500\u2510",
5182
+ star: "\u2736",
5183
+ play: "\u25BA",
5184
+ nodejs: "\u2666",
5185
+ oneSeventh: "1/7",
5186
+ oneNinth: "1/9",
5187
+ oneTenth: "1/10"
5188
+ };
5189
+ mainSymbols = {
5190
+ ...common,
5191
+ ...specialMainSymbols
5192
+ };
5193
+ fallbackSymbols = {
5194
+ ...common,
5195
+ ...specialFallbackSymbols
5196
+ };
5197
+ shouldUseMain = isUnicodeSupported();
5198
+ figures = shouldUseMain ? mainSymbols : fallbackSymbols;
5199
+ dist_default = figures;
5200
+ replacements = Object.entries(specialMainSymbols);
5201
+ }
5202
+ });
5203
+
5204
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/theme.js
5205
+ import { styleText } from "node:util";
5206
+ var defaultTheme;
5207
+ var init_theme = __esm({
5208
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/theme.js"() {
5209
+ init_dist();
5210
+ defaultTheme = {
5211
+ prefix: {
5212
+ idle: styleText("blue", "?"),
5213
+ done: styleText("green", dist_default.tick)
5214
+ },
5215
+ spinner: {
5216
+ interval: 80,
5217
+ frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"].map((frame) => styleText("yellow", frame))
5218
+ },
5219
+ style: {
5220
+ answer: (text) => styleText("cyan", text),
5221
+ message: (text) => styleText("bold", text),
5222
+ error: (text) => styleText("red", `> ${text}`),
5223
+ defaultAnswer: (text) => styleText("dim", `(${text})`),
5224
+ help: (text) => styleText("dim", text),
5225
+ highlight: (text) => styleText("cyan", text),
5226
+ key: (text) => styleText("cyan", styleText("bold", `<${text}>`))
5227
+ }
5228
+ };
5229
+ }
5230
+ });
5231
+
5232
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/make-theme.js
5233
+ function isPlainObject(value) {
5234
+ if (typeof value !== "object" || value === null)
5235
+ return false;
5236
+ let proto = value;
5237
+ while (Object.getPrototypeOf(proto) !== null) {
5238
+ proto = Object.getPrototypeOf(proto);
5239
+ }
5240
+ return Object.getPrototypeOf(value) === proto;
5241
+ }
5242
+ function deepMerge(...objects) {
5243
+ const output = {};
5244
+ for (const obj of objects) {
5245
+ for (const [key, value] of Object.entries(obj)) {
5246
+ const prevValue = output[key];
5247
+ output[key] = isPlainObject(prevValue) && isPlainObject(value) ? deepMerge(prevValue, value) : value;
5248
+ }
5249
+ }
5250
+ return output;
5251
+ }
5252
+ function makeTheme(...themes) {
5253
+ const themesToMerge = [
5254
+ defaultTheme,
5255
+ ...themes.filter((theme) => theme != null)
5256
+ ];
5257
+ return deepMerge(...themesToMerge);
5258
+ }
5259
+ var init_make_theme = __esm({
5260
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/make-theme.js"() {
5261
+ init_theme();
5262
+ }
5263
+ });
5264
+
5265
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-prefix.js
5266
+ function usePrefix({ status = "idle", theme }) {
5267
+ const [showLoader, setShowLoader] = useState(false);
5268
+ const [tick, setTick] = useState(0);
5269
+ const { prefix, spinner } = makeTheme(theme);
5270
+ useEffect(() => {
5271
+ if (status === "loading") {
5272
+ let tickInterval;
5273
+ let inc = -1;
5274
+ const delayTimeout = setTimeout(() => {
5275
+ setShowLoader(true);
5276
+ tickInterval = setInterval(() => {
5277
+ inc = inc + 1;
5278
+ setTick(inc % spinner.frames.length);
5279
+ }, spinner.interval);
5280
+ }, 300);
5281
+ return () => {
5282
+ clearTimeout(delayTimeout);
5283
+ clearInterval(tickInterval);
5284
+ };
5285
+ } else {
5286
+ setShowLoader(false);
5287
+ }
5288
+ }, [status]);
5289
+ if (showLoader) {
5290
+ return spinner.frames[tick];
5291
+ }
5292
+ const iconName = status === "loading" ? "idle" : status;
5293
+ return typeof prefix === "string" ? prefix : prefix[iconName] ?? prefix["idle"];
5294
+ }
5295
+ var init_use_prefix = __esm({
5296
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-prefix.js"() {
5297
+ init_use_state();
5298
+ init_use_effect();
5299
+ init_make_theme();
5300
+ }
5301
+ });
5302
+
5303
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-memo.js
5304
+ function useMemo(fn, dependencies) {
5305
+ return withPointer((pointer) => {
5306
+ const prev = pointer.get();
5307
+ if (!prev || prev.dependencies.length !== dependencies.length || prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
5308
+ const value = fn();
5309
+ pointer.set({ value, dependencies });
5310
+ return value;
5311
+ }
5312
+ return prev.value;
5313
+ });
5314
+ }
5315
+ var init_use_memo = __esm({
5316
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-memo.js"() {
5317
+ init_hook_engine();
5318
+ }
5319
+ });
5320
+
5321
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-ref.js
5322
+ function useRef(val) {
5323
+ return useState({ current: val })[0];
5324
+ }
5325
+ var init_use_ref = __esm({
5326
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-ref.js"() {
5327
+ init_use_state();
5328
+ }
5329
+ });
5330
+
5331
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-keypress.js
5332
+ function useKeypress(userHandler) {
5333
+ const signal = useRef(userHandler);
5334
+ signal.current = userHandler;
5335
+ useEffect((rl) => {
5336
+ let ignore = false;
5337
+ const handler = withUpdates((_input, event) => {
5338
+ if (ignore)
5339
+ return;
5340
+ void signal.current(event, rl);
5341
+ });
5342
+ rl.input.on("keypress", handler);
5343
+ return () => {
5344
+ ignore = true;
5345
+ rl.input.removeListener("keypress", handler);
5346
+ };
5347
+ }, []);
5348
+ }
5349
+ var init_use_keypress = __esm({
5350
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/use-keypress.js"() {
5351
+ init_use_ref();
5352
+ init_use_effect();
5353
+ init_hook_engine();
5354
+ }
5355
+ });
5356
+
5357
+ // ../../node_modules/.pnpm/cli-width@4.1.0/node_modules/cli-width/index.js
5358
+ var require_cli_width = __commonJS({
5359
+ "../../node_modules/.pnpm/cli-width@4.1.0/node_modules/cli-width/index.js"(exports, module) {
5360
+ "use strict";
5361
+ module.exports = cliWidth2;
5362
+ function normalizeOpts(options) {
5363
+ const defaultOpts = {
5364
+ defaultWidth: 0,
5365
+ output: process.stdout,
5366
+ tty: __require("tty")
5367
+ };
5368
+ if (!options) {
5369
+ return defaultOpts;
5370
+ }
5371
+ Object.keys(defaultOpts).forEach(function(key) {
5372
+ if (!options[key]) {
5373
+ options[key] = defaultOpts[key];
5374
+ }
5375
+ });
5376
+ return options;
5377
+ }
5378
+ function cliWidth2(options) {
5379
+ const opts = normalizeOpts(options);
5380
+ if (opts.output.getWindowSize) {
5381
+ return opts.output.getWindowSize()[0] || opts.defaultWidth;
5382
+ }
5383
+ if (opts.tty.getWindowSize) {
5384
+ return opts.tty.getWindowSize()[1] || opts.defaultWidth;
5385
+ }
5386
+ if (opts.output.columns) {
5387
+ return opts.output.columns;
5388
+ }
5389
+ if (process.env.CLI_WIDTH) {
5390
+ const width = parseInt(process.env.CLI_WIDTH, 10);
5391
+ if (!isNaN(width) && width !== 0) {
5392
+ return width;
5393
+ }
5394
+ }
5395
+ return opts.defaultWidth;
5396
+ }
5397
+ }
5398
+ });
5399
+
5400
+ // ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
5401
+ var getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji;
5402
+ var init_utils = __esm({
5403
+ "../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js"() {
5404
+ getCodePointsLength = /* @__PURE__ */ (() => {
5405
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
5406
+ return (input) => {
5407
+ let surrogatePairsNr = 0;
5408
+ SURROGATE_PAIR_RE.lastIndex = 0;
5409
+ while (SURROGATE_PAIR_RE.test(input)) {
5410
+ surrogatePairsNr += 1;
5411
+ }
5412
+ return input.length - surrogatePairsNr;
5413
+ };
5414
+ })();
5415
+ isFullWidth = (x) => {
5416
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
5417
+ };
5418
+ isWideNotCJKTNotEmoji = (x) => {
5419
+ return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
5420
+ };
5421
+ }
5422
+ });
5423
+
5424
+ // ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
5425
+ var ANSI_RE, CONTROL_RE, CJKT_WIDE_RE, TAB_RE, EMOJI_RE, LATIN_RE, MODIFIER_RE, NO_TRUNCATION, getStringTruncatedWidth, dist_default2;
5426
+ var init_dist2 = __esm({
5427
+ "../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js"() {
5428
+ init_utils();
5429
+ ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
5430
+ CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
5431
+ CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
5432
+ TAB_RE = /\t{1,1000}/y;
5433
+ EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
5434
+ LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
5435
+ MODIFIER_RE = /\p{M}+/gu;
5436
+ NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
5437
+ getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
5438
+ const LIMIT = truncationOptions.limit ?? Infinity;
5439
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
5440
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
5441
+ const ANSI_WIDTH = 0;
5442
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
5443
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
5444
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
5445
+ const FULL_WIDTH_WIDTH = 2;
5446
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
5447
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
5448
+ const PARSE_BLOCKS = [
5449
+ [LATIN_RE, REGULAR_WIDTH],
5450
+ [ANSI_RE, ANSI_WIDTH],
5451
+ [CONTROL_RE, CONTROL_WIDTH],
5452
+ [TAB_RE, TAB_WIDTH],
5453
+ [EMOJI_RE, EMOJI_WIDTH],
5454
+ [CJKT_WIDE_RE, WIDE_WIDTH]
5455
+ ];
5456
+ let indexPrev = 0;
5457
+ let index = 0;
5458
+ let length = input.length;
5459
+ let lengthExtra = 0;
5460
+ let truncationEnabled = false;
5461
+ let truncationIndex = length;
5462
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
5463
+ let unmatchedStart = 0;
5464
+ let unmatchedEnd = 0;
5465
+ let width = 0;
5466
+ let widthExtra = 0;
5467
+ outer: while (true) {
5468
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
5469
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
5470
+ lengthExtra = 0;
5471
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
5472
+ const codePoint = char.codePointAt(0) || 0;
5473
+ if (isFullWidth(codePoint)) {
5474
+ widthExtra = FULL_WIDTH_WIDTH;
5475
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
5476
+ widthExtra = WIDE_WIDTH;
5477
+ } else {
5478
+ widthExtra = REGULAR_WIDTH;
5479
+ }
5480
+ if (width + widthExtra > truncationLimit) {
5481
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
5482
+ }
5483
+ if (width + widthExtra > LIMIT) {
5484
+ truncationEnabled = true;
5485
+ break outer;
5486
+ }
5487
+ lengthExtra += char.length;
5488
+ width += widthExtra;
5489
+ }
5490
+ unmatchedStart = unmatchedEnd = 0;
5491
+ }
5492
+ if (index >= length) {
5493
+ break outer;
5494
+ }
5495
+ for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
5496
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
5497
+ BLOCK_RE.lastIndex = index;
5498
+ if (BLOCK_RE.test(input)) {
5499
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
5500
+ widthExtra = lengthExtra * BLOCK_WIDTH;
5501
+ if (width + widthExtra > truncationLimit) {
5502
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
5503
+ }
5504
+ if (width + widthExtra > LIMIT) {
5505
+ truncationEnabled = true;
5506
+ break outer;
5507
+ }
5508
+ width += widthExtra;
5509
+ unmatchedStart = indexPrev;
5510
+ unmatchedEnd = index;
5511
+ index = indexPrev = BLOCK_RE.lastIndex;
5512
+ continue outer;
5513
+ }
5514
+ }
5515
+ index += 1;
5516
+ }
5517
+ return {
5518
+ width: truncationEnabled ? truncationLimit : width,
5519
+ index: truncationEnabled ? truncationIndex : length,
5520
+ truncated: truncationEnabled,
5521
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
5522
+ };
5523
+ };
5524
+ dist_default2 = getStringTruncatedWidth;
5525
+ }
5526
+ });
5527
+
5528
+ // ../../node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
5529
+ var NO_TRUNCATION2, fastStringWidth, dist_default3;
5530
+ var init_dist3 = __esm({
5531
+ "../../node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js"() {
5532
+ init_dist2();
5533
+ NO_TRUNCATION2 = {
5534
+ limit: Infinity,
5535
+ ellipsis: "",
5536
+ ellipsisWidth: 0
5537
+ };
5538
+ fastStringWidth = (input, options = {}) => {
5539
+ return dist_default2(input, NO_TRUNCATION2, options).width;
5540
+ };
5541
+ dist_default3 = fastStringWidth;
5542
+ }
5543
+ });
5544
+
5545
+ // ../../node_modules/.pnpm/fast-wrap-ansi@0.2.0/node_modules/fast-wrap-ansi/lib/main.js
5546
+ function wrapAnsi(string4, columns, options) {
5547
+ return String(string4).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
5548
+ }
5549
+ var ESC, CSI, END_CODE, ANSI_ESCAPE_BELL, ANSI_CSI, ANSI_OSC, ANSI_SGR_TERMINATOR, ANSI_ESCAPE_LINK, GROUP_REGEX, getClosingCode, wrapAnsiCode, wrapAnsiHyperlink, wrapWord, stringVisibleTrimSpacesRight, exec, CRLF_OR_LF;
5550
+ var init_main = __esm({
5551
+ "../../node_modules/.pnpm/fast-wrap-ansi@0.2.0/node_modules/fast-wrap-ansi/lib/main.js"() {
5552
+ init_dist3();
5553
+ ESC = "\x1B";
5554
+ CSI = "\x9B";
5555
+ END_CODE = 39;
5556
+ ANSI_ESCAPE_BELL = "\x07";
5557
+ ANSI_CSI = "[";
5558
+ ANSI_OSC = "]";
5559
+ ANSI_SGR_TERMINATOR = "m";
5560
+ ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
5561
+ GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
5562
+ getClosingCode = (openingCode) => {
5563
+ if (openingCode >= 30 && openingCode <= 37)
5564
+ return 39;
5565
+ if (openingCode >= 90 && openingCode <= 97)
5566
+ return 39;
5567
+ if (openingCode >= 40 && openingCode <= 47)
5568
+ return 49;
5569
+ if (openingCode >= 100 && openingCode <= 107)
5570
+ return 49;
5571
+ if (openingCode === 1 || openingCode === 2)
5572
+ return 22;
5573
+ if (openingCode === 3)
5574
+ return 23;
5575
+ if (openingCode === 4)
5576
+ return 24;
5577
+ if (openingCode === 7)
5578
+ return 27;
5579
+ if (openingCode === 8)
5580
+ return 28;
5581
+ if (openingCode === 9)
5582
+ return 29;
5583
+ if (openingCode === 0)
5584
+ return 0;
5585
+ return void 0;
5586
+ };
5587
+ wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
5588
+ wrapAnsiHyperlink = (url2) => `${ESC}${ANSI_ESCAPE_LINK}${url2}${ANSI_ESCAPE_BELL}`;
5589
+ wrapWord = (rows, word, columns) => {
5590
+ const characters = word[Symbol.iterator]();
5591
+ let isInsideEscape = false;
5592
+ let isInsideLinkEscape = false;
5593
+ let lastRow = rows.at(-1);
5594
+ let visible = lastRow === void 0 ? 0 : dist_default3(lastRow);
5595
+ let currentCharacter = characters.next();
5596
+ let nextCharacter = characters.next();
5597
+ let rawCharacterIndex = 0;
5598
+ while (!currentCharacter.done) {
5599
+ const character = currentCharacter.value;
5600
+ const characterLength = dist_default3(character);
5601
+ if (visible + characterLength <= columns) {
5602
+ rows[rows.length - 1] += character;
5603
+ } else {
5604
+ rows.push(character);
5605
+ visible = 0;
5606
+ }
5607
+ if (character === ESC || character === CSI) {
5608
+ isInsideEscape = true;
5609
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
5610
+ }
5611
+ if (isInsideEscape) {
5612
+ if (isInsideLinkEscape) {
5613
+ if (character === ANSI_ESCAPE_BELL) {
5614
+ isInsideEscape = false;
5615
+ isInsideLinkEscape = false;
5616
+ }
5617
+ } else if (character === ANSI_SGR_TERMINATOR) {
5618
+ isInsideEscape = false;
5619
+ }
5620
+ } else {
5621
+ visible += characterLength;
5622
+ if (visible === columns && !nextCharacter.done) {
5623
+ rows.push("");
5624
+ visible = 0;
5625
+ }
5626
+ }
5627
+ currentCharacter = nextCharacter;
5628
+ nextCharacter = characters.next();
5629
+ rawCharacterIndex += character.length;
5630
+ }
5631
+ lastRow = rows.at(-1);
5632
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
5633
+ rows[rows.length - 2] += rows.pop();
5634
+ }
5635
+ };
5636
+ stringVisibleTrimSpacesRight = (string4) => {
5637
+ const words = string4.split(" ");
5638
+ let last = words.length;
5639
+ while (last) {
5640
+ if (dist_default3(words[last - 1])) {
5641
+ break;
5642
+ }
5643
+ last--;
5644
+ }
5645
+ if (last === words.length) {
5646
+ return string4;
5647
+ }
5648
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
5649
+ };
5650
+ exec = (string4, columns, options = {}) => {
5651
+ if (options.trim !== false && string4.trim() === "") {
5652
+ return "";
5653
+ }
5654
+ let returnValue = "";
5655
+ let escapeCode;
5656
+ let escapeUrl;
5657
+ const words = string4.split(" ");
5658
+ let rows = [""];
5659
+ let rowLength = 0;
5660
+ for (let index = 0; index < words.length; index++) {
5661
+ const word = words[index];
5662
+ if (options.trim !== false) {
5663
+ const row = rows.at(-1) ?? "";
5664
+ const trimmed = row.trimStart();
5665
+ if (row.length !== trimmed.length) {
5666
+ rows[rows.length - 1] = trimmed;
5667
+ rowLength = dist_default3(trimmed);
5668
+ }
5669
+ }
5670
+ if (index !== 0) {
5671
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
5672
+ rows.push("");
5673
+ rowLength = 0;
5674
+ }
5675
+ if (rowLength || options.trim === false) {
5676
+ rows[rows.length - 1] += " ";
5677
+ rowLength++;
5678
+ }
5679
+ }
5680
+ const wordLength = dist_default3(word);
5681
+ if (options.hard && wordLength > columns) {
5682
+ const remainingColumns = columns - rowLength;
5683
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
5684
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
5685
+ if (breaksStartingNextLine < breaksStartingThisLine) {
5686
+ rows.push("");
5687
+ }
5688
+ wrapWord(rows, word, columns);
5689
+ rowLength = dist_default3(rows.at(-1) ?? "");
5690
+ continue;
5691
+ }
5692
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
5693
+ if (options.wordWrap === false && rowLength < columns) {
5694
+ wrapWord(rows, word, columns);
5695
+ rowLength = dist_default3(rows.at(-1) ?? "");
5696
+ continue;
5697
+ }
5698
+ rows.push("");
5699
+ rowLength = 0;
5700
+ }
5701
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
5702
+ wrapWord(rows, word, columns);
5703
+ rowLength = dist_default3(rows.at(-1) ?? "");
5704
+ continue;
5705
+ }
5706
+ rows[rows.length - 1] += word;
5707
+ rowLength += wordLength;
5708
+ }
5709
+ if (options.trim !== false) {
5710
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
5711
+ }
5712
+ const preString = rows.join("\n");
5713
+ let inSurrogate = false;
5714
+ for (let i = 0; i < preString.length; i++) {
5715
+ const character = preString[i];
5716
+ returnValue += character;
5717
+ if (!inSurrogate) {
5718
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
5719
+ if (inSurrogate) {
5720
+ continue;
5721
+ }
5722
+ } else {
5723
+ inSurrogate = false;
5724
+ }
5725
+ if (character === ESC || character === CSI) {
5726
+ GROUP_REGEX.lastIndex = i + 1;
5727
+ const groupsResult = GROUP_REGEX.exec(preString);
5728
+ const groups = groupsResult?.groups;
5729
+ if (groups?.code !== void 0) {
5730
+ const code = Number.parseFloat(groups.code);
5731
+ escapeCode = code === END_CODE ? void 0 : code;
5732
+ } else if (groups?.uri !== void 0) {
5733
+ escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
5734
+ }
5735
+ }
5736
+ if (preString[i + 1] === "\n") {
5737
+ if (escapeUrl) {
5738
+ returnValue += wrapAnsiHyperlink("");
5739
+ }
5740
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
5741
+ if (escapeCode && closingCode) {
5742
+ returnValue += wrapAnsiCode(closingCode);
5743
+ }
5744
+ } else if (character === "\n") {
5745
+ if (escapeCode && getClosingCode(escapeCode)) {
5746
+ returnValue += wrapAnsiCode(escapeCode);
5747
+ }
5748
+ if (escapeUrl) {
5749
+ returnValue += wrapAnsiHyperlink(escapeUrl);
5750
+ }
5751
+ }
5752
+ }
5753
+ return returnValue;
5754
+ };
5755
+ CRLF_OR_LF = /\r?\n/;
5756
+ }
5757
+ });
5758
+
5759
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/utils.js
5760
+ function breakLines(content, width) {
5761
+ return content.split("\n").flatMap((line) => wrapAnsi(line, width, { trim: false, hard: true }).split("\n").map((str) => str.trimEnd())).join("\n");
5762
+ }
5763
+ function readlineWidth() {
5764
+ return (0, import_cli_width.default)({ defaultWidth: 80, output: readline().output });
5765
+ }
5766
+ var import_cli_width;
5767
+ var init_utils2 = __esm({
5768
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/utils.js"() {
5769
+ import_cli_width = __toESM(require_cli_width(), 1);
5770
+ init_main();
5771
+ init_hook_engine();
5772
+ }
5773
+ });
5774
+
5775
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
5776
+ function usePointerPosition({ active, renderedItems, pageSize, loop }) {
5777
+ const state = useRef({
5778
+ lastPointer: active,
5779
+ lastActive: void 0
5780
+ });
5781
+ const { lastPointer, lastActive } = state.current;
5782
+ const middle = Math.floor(pageSize / 2);
5783
+ const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
5784
+ const defaultPointerPosition = renderedItems.slice(0, active).reduce((acc, item) => acc + item.length, 0);
5785
+ let pointer = defaultPointerPosition;
5786
+ if (renderedLength > pageSize) {
5787
+ if (loop) {
5788
+ pointer = lastPointer;
5789
+ if (
5790
+ // First render, skip this logic.
5791
+ lastActive != null && // Only move the pointer down when the user moves down.
5792
+ lastActive < active && // Check user didn't move up across page boundary.
5793
+ active - lastActive < pageSize
5794
+ ) {
5795
+ pointer = Math.min(
5796
+ // Furthest allowed position for the pointer is the middle of the list
5797
+ middle,
5798
+ Math.abs(active - lastActive) === 1 ? Math.min(
5799
+ // Move the pointer at most the height of the last active item.
5800
+ lastPointer + (renderedItems[lastActive]?.length ?? 0),
5801
+ // If the user moved by one item, move the pointer to the natural position of the active item as
5802
+ // long as it doesn't move the cursor up.
5803
+ Math.max(defaultPointerPosition, lastPointer)
5804
+ ) : (
5805
+ // Otherwise, move the pointer down by the difference between the active and last active item.
5806
+ lastPointer + active - lastActive
5807
+ )
5808
+ );
5809
+ }
5810
+ } else {
5811
+ const spaceUnderActive = renderedItems.slice(active).reduce((acc, item) => acc + item.length, 0);
5812
+ pointer = spaceUnderActive < pageSize - middle ? (
5813
+ // If the active item is near the end of the list, progressively move the cursor towards the end.
5814
+ pageSize - spaceUnderActive
5815
+ ) : (
5816
+ // Otherwise, progressively move the pointer to the middle of the list.
5817
+ Math.min(defaultPointerPosition, middle)
5818
+ );
5819
+ }
5820
+ }
5821
+ state.current.lastPointer = pointer;
5822
+ state.current.lastActive = active;
5823
+ return pointer;
5824
+ }
5825
+ function usePagination({ items, active, renderItem, pageSize, loop = true }) {
5826
+ const width = readlineWidth();
5827
+ const bound = (num) => (num % items.length + items.length) % items.length;
5828
+ const renderedItems = items.map((item, index) => {
5829
+ if (item == null)
5830
+ return [];
5831
+ return breakLines(renderItem({ item, index, isActive: index === active }), width).split("\n");
5832
+ });
5833
+ const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
5834
+ const renderItemAtIndex = (index) => renderedItems[index] ?? [];
5835
+ const pointer = usePointerPosition({ active, renderedItems, pageSize, loop });
5836
+ const activeItem = renderItemAtIndex(active).slice(0, pageSize);
5837
+ const activeItemPosition = pointer + activeItem.length <= pageSize ? pointer : pageSize - activeItem.length;
5838
+ const pageBuffer = Array.from({ length: pageSize });
5839
+ pageBuffer.splice(activeItemPosition, activeItem.length, ...activeItem);
5840
+ const itemVisited = /* @__PURE__ */ new Set([active]);
5841
+ let bufferPointer = activeItemPosition + activeItem.length;
5842
+ let itemPointer = bound(active + 1);
5843
+ while (bufferPointer < pageSize && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer > active)) {
5844
+ const lines = renderItemAtIndex(itemPointer);
5845
+ const linesToAdd = lines.slice(0, pageSize - bufferPointer);
5846
+ pageBuffer.splice(bufferPointer, linesToAdd.length, ...linesToAdd);
5847
+ itemVisited.add(itemPointer);
5848
+ bufferPointer += linesToAdd.length;
5849
+ itemPointer = bound(itemPointer + 1);
5850
+ }
5851
+ bufferPointer = activeItemPosition - 1;
5852
+ itemPointer = bound(active - 1);
5853
+ while (bufferPointer >= 0 && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer < active)) {
5854
+ const lines = renderItemAtIndex(itemPointer);
5855
+ const linesToAdd = lines.slice(Math.max(0, lines.length - bufferPointer - 1));
5856
+ pageBuffer.splice(bufferPointer - linesToAdd.length + 1, linesToAdd.length, ...linesToAdd);
5857
+ itemVisited.add(itemPointer);
5858
+ bufferPointer -= linesToAdd.length;
5859
+ itemPointer = bound(itemPointer - 1);
5860
+ }
5861
+ return pageBuffer.filter((line) => typeof line === "string").join("\n");
5862
+ }
5863
+ var init_use_pagination = __esm({
5864
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js"() {
5865
+ init_use_ref();
5866
+ init_utils2();
5867
+ }
5868
+ });
5869
+
5870
+ // ../../node_modules/.pnpm/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js
5871
+ var require_lib = __commonJS({
5872
+ "../../node_modules/.pnpm/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js"(exports, module) {
5873
+ var Stream = __require("stream");
5874
+ var MuteStream2 = class extends Stream {
5875
+ #isTTY = null;
5876
+ constructor(opts = {}) {
5877
+ super(opts);
5878
+ this.writable = this.readable = true;
5879
+ this.muted = false;
5880
+ this.on("pipe", this._onpipe);
5881
+ this.replace = opts.replace;
5882
+ this._prompt = opts.prompt || null;
5883
+ this._hadControl = false;
5884
+ }
5885
+ #destSrc(key, def) {
5886
+ if (this._dest) {
5887
+ return this._dest[key];
5888
+ }
5889
+ if (this._src) {
5890
+ return this._src[key];
5891
+ }
5892
+ return def;
5893
+ }
5894
+ #proxy(method, ...args) {
5895
+ if (typeof this._dest?.[method] === "function") {
5896
+ this._dest[method](...args);
5897
+ }
5898
+ if (typeof this._src?.[method] === "function") {
5899
+ this._src[method](...args);
5900
+ }
5901
+ }
5902
+ get isTTY() {
5903
+ if (this.#isTTY !== null) {
5904
+ return this.#isTTY;
5905
+ }
5906
+ return this.#destSrc("isTTY", false);
5907
+ }
5908
+ // basically just get replace the getter/setter with a regular value
5909
+ set isTTY(val) {
5910
+ this.#isTTY = val;
5911
+ }
5912
+ get rows() {
5913
+ return this.#destSrc("rows");
5914
+ }
5915
+ get columns() {
5916
+ return this.#destSrc("columns");
5917
+ }
5918
+ mute() {
5919
+ this.muted = true;
5920
+ }
5921
+ unmute() {
5922
+ this.muted = false;
5923
+ }
5924
+ _onpipe(src) {
5925
+ this._src = src;
5926
+ }
5927
+ pipe(dest, options) {
5928
+ this._dest = dest;
5929
+ return super.pipe(dest, options);
5930
+ }
5931
+ pause() {
5932
+ if (this._src) {
5933
+ return this._src.pause();
5934
+ }
5935
+ }
5936
+ resume() {
5937
+ if (this._src) {
5938
+ return this._src.resume();
5939
+ }
5940
+ }
5941
+ write(c3) {
5942
+ if (this.muted) {
5943
+ if (!this.replace) {
5944
+ return true;
5945
+ }
5946
+ if (c3.match(/^\u001b/)) {
5947
+ if (c3.indexOf(this._prompt) === 0) {
5948
+ c3 = c3.slice(this._prompt.length);
5949
+ c3 = c3.replace(/./g, this.replace);
5950
+ c3 = this._prompt + c3;
5951
+ }
5952
+ this._hadControl = true;
5953
+ return this.emit("data", c3);
5954
+ } else {
5955
+ if (this._prompt && this._hadControl && c3.indexOf(this._prompt) === 0) {
5956
+ this._hadControl = false;
5957
+ this.emit("data", this._prompt);
5958
+ c3 = c3.slice(this._prompt.length);
5959
+ }
5960
+ c3 = c3.toString().replace(/./g, this.replace);
5961
+ }
5962
+ }
5963
+ this.emit("data", c3);
5964
+ }
5965
+ end(c3) {
5966
+ if (this.muted) {
5967
+ if (c3 && this.replace) {
5968
+ c3 = c3.toString().replace(/./g, this.replace);
5969
+ } else {
5970
+ c3 = null;
5971
+ }
5972
+ }
5973
+ if (c3) {
5974
+ this.emit("data", c3);
5975
+ }
5976
+ this.emit("end");
5977
+ }
5978
+ destroy(...args) {
5979
+ return this.#proxy("destroy", ...args);
5980
+ }
5981
+ destroySoon(...args) {
5982
+ return this.#proxy("destroySoon", ...args);
5983
+ }
5984
+ close(...args) {
5985
+ return this.#proxy("close", ...args);
5986
+ }
5987
+ };
5988
+ module.exports = MuteStream2;
5989
+ }
5990
+ });
5991
+
5992
+ // ../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js
5993
+ var signals;
5994
+ var init_signals = __esm({
5995
+ "../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js"() {
5996
+ signals = [];
5997
+ signals.push("SIGHUP", "SIGINT", "SIGTERM");
5998
+ if (process.platform !== "win32") {
5999
+ signals.push(
6000
+ "SIGALRM",
6001
+ "SIGABRT",
6002
+ "SIGVTALRM",
6003
+ "SIGXCPU",
6004
+ "SIGXFSZ",
6005
+ "SIGUSR2",
6006
+ "SIGTRAP",
6007
+ "SIGSYS",
6008
+ "SIGQUIT",
6009
+ "SIGIOT"
6010
+ // should detect profiler and enable/disable accordingly.
6011
+ // see #21
6012
+ // 'SIGPROF'
6013
+ );
6014
+ }
6015
+ if (process.platform === "linux") {
6016
+ signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
6017
+ }
6018
+ }
6019
+ });
6020
+
6021
+ // ../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
6022
+ var processOk, kExitEmitter, global, ObjectDefineProperty, Emitter, SignalExitBase, signalExitWrap, SignalExitFallback, SignalExit, process3, onExit, load, unload;
6023
+ var init_mjs = __esm({
6024
+ "../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js"() {
6025
+ init_signals();
6026
+ processOk = (process4) => !!process4 && typeof process4 === "object" && typeof process4.removeListener === "function" && typeof process4.emit === "function" && typeof process4.reallyExit === "function" && typeof process4.listeners === "function" && typeof process4.kill === "function" && typeof process4.pid === "number" && typeof process4.on === "function";
6027
+ kExitEmitter = Symbol.for("signal-exit emitter");
6028
+ global = globalThis;
6029
+ ObjectDefineProperty = Object.defineProperty.bind(Object);
6030
+ Emitter = class {
6031
+ emitted = {
6032
+ afterExit: false,
6033
+ exit: false
6034
+ };
6035
+ listeners = {
6036
+ afterExit: [],
6037
+ exit: []
6038
+ };
6039
+ count = 0;
6040
+ id = Math.random();
6041
+ constructor() {
6042
+ if (global[kExitEmitter]) {
6043
+ return global[kExitEmitter];
6044
+ }
6045
+ ObjectDefineProperty(global, kExitEmitter, {
6046
+ value: this,
6047
+ writable: false,
6048
+ enumerable: false,
6049
+ configurable: false
6050
+ });
6051
+ }
6052
+ on(ev, fn) {
6053
+ this.listeners[ev].push(fn);
6054
+ }
6055
+ removeListener(ev, fn) {
6056
+ const list = this.listeners[ev];
6057
+ const i = list.indexOf(fn);
6058
+ if (i === -1) {
6059
+ return;
6060
+ }
6061
+ if (i === 0 && list.length === 1) {
6062
+ list.length = 0;
6063
+ } else {
6064
+ list.splice(i, 1);
6065
+ }
6066
+ }
6067
+ emit(ev, code, signal) {
6068
+ if (this.emitted[ev]) {
6069
+ return false;
6070
+ }
6071
+ this.emitted[ev] = true;
6072
+ let ret = false;
6073
+ for (const fn of this.listeners[ev]) {
6074
+ ret = fn(code, signal) === true || ret;
6075
+ }
6076
+ if (ev === "exit") {
6077
+ ret = this.emit("afterExit", code, signal) || ret;
6078
+ }
6079
+ return ret;
6080
+ }
6081
+ };
6082
+ SignalExitBase = class {
6083
+ };
6084
+ signalExitWrap = (handler) => {
6085
+ return {
6086
+ onExit(cb, opts) {
6087
+ return handler.onExit(cb, opts);
6088
+ },
6089
+ load() {
6090
+ return handler.load();
6091
+ },
6092
+ unload() {
6093
+ return handler.unload();
6094
+ }
6095
+ };
6096
+ };
6097
+ SignalExitFallback = class extends SignalExitBase {
6098
+ onExit() {
6099
+ return () => {
6100
+ };
6101
+ }
6102
+ load() {
6103
+ }
6104
+ unload() {
6105
+ }
6106
+ };
6107
+ SignalExit = class extends SignalExitBase {
6108
+ // "SIGHUP" throws an `ENOSYS` error on Windows,
6109
+ // so use a supported signal instead
6110
+ /* c8 ignore start */
6111
+ #hupSig = process3.platform === "win32" ? "SIGINT" : "SIGHUP";
6112
+ /* c8 ignore stop */
6113
+ #emitter = new Emitter();
6114
+ #process;
6115
+ #originalProcessEmit;
6116
+ #originalProcessReallyExit;
6117
+ #sigListeners = {};
6118
+ #loaded = false;
6119
+ constructor(process4) {
6120
+ super();
6121
+ this.#process = process4;
6122
+ this.#sigListeners = {};
6123
+ for (const sig of signals) {
6124
+ this.#sigListeners[sig] = () => {
6125
+ const listeners = this.#process.listeners(sig);
6126
+ let { count } = this.#emitter;
6127
+ const p = process4;
6128
+ if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") {
6129
+ count += p.__signal_exit_emitter__.count;
6130
+ }
6131
+ if (listeners.length === count) {
6132
+ this.unload();
6133
+ const ret = this.#emitter.emit("exit", null, sig);
6134
+ const s = sig === "SIGHUP" ? this.#hupSig : sig;
6135
+ if (!ret)
6136
+ process4.kill(process4.pid, s);
6137
+ }
6138
+ };
6139
+ }
6140
+ this.#originalProcessReallyExit = process4.reallyExit;
6141
+ this.#originalProcessEmit = process4.emit;
6142
+ }
6143
+ onExit(cb, opts) {
6144
+ if (!processOk(this.#process)) {
6145
+ return () => {
6146
+ };
6147
+ }
6148
+ if (this.#loaded === false) {
6149
+ this.load();
6150
+ }
6151
+ const ev = opts?.alwaysLast ? "afterExit" : "exit";
6152
+ this.#emitter.on(ev, cb);
6153
+ return () => {
6154
+ this.#emitter.removeListener(ev, cb);
6155
+ if (this.#emitter.listeners["exit"].length === 0 && this.#emitter.listeners["afterExit"].length === 0) {
6156
+ this.unload();
6157
+ }
6158
+ };
6159
+ }
6160
+ load() {
6161
+ if (this.#loaded) {
6162
+ return;
6163
+ }
6164
+ this.#loaded = true;
6165
+ this.#emitter.count += 1;
6166
+ for (const sig of signals) {
6167
+ try {
6168
+ const fn = this.#sigListeners[sig];
6169
+ if (fn)
6170
+ this.#process.on(sig, fn);
6171
+ } catch (_) {
6172
+ }
6173
+ }
6174
+ this.#process.emit = (ev, ...a) => {
6175
+ return this.#processEmit(ev, ...a);
6176
+ };
6177
+ this.#process.reallyExit = (code) => {
6178
+ return this.#processReallyExit(code);
6179
+ };
6180
+ }
6181
+ unload() {
6182
+ if (!this.#loaded) {
6183
+ return;
6184
+ }
6185
+ this.#loaded = false;
6186
+ signals.forEach((sig) => {
6187
+ const listener = this.#sigListeners[sig];
6188
+ if (!listener) {
6189
+ throw new Error("Listener not defined for signal: " + sig);
6190
+ }
6191
+ try {
6192
+ this.#process.removeListener(sig, listener);
6193
+ } catch (_) {
6194
+ }
6195
+ });
6196
+ this.#process.emit = this.#originalProcessEmit;
6197
+ this.#process.reallyExit = this.#originalProcessReallyExit;
6198
+ this.#emitter.count -= 1;
6199
+ }
6200
+ #processReallyExit(code) {
6201
+ if (!processOk(this.#process)) {
6202
+ return 0;
6203
+ }
6204
+ this.#process.exitCode = code || 0;
6205
+ this.#emitter.emit("exit", this.#process.exitCode, null);
6206
+ return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
6207
+ }
6208
+ #processEmit(ev, ...args) {
6209
+ const og = this.#originalProcessEmit;
6210
+ if (ev === "exit" && processOk(this.#process)) {
6211
+ if (typeof args[0] === "number") {
6212
+ this.#process.exitCode = args[0];
6213
+ }
6214
+ const ret = og.call(this.#process, ev, ...args);
6215
+ this.#emitter.emit("exit", this.#process.exitCode, null);
6216
+ return ret;
6217
+ } else {
6218
+ return og.call(this.#process, ev, ...args);
6219
+ }
6220
+ }
6221
+ };
6222
+ process3 = globalThis.process;
6223
+ ({
6224
+ onExit: (
6225
+ /**
6226
+ * Called when the process is exiting, whether via signal, explicit
6227
+ * exit, or running out of stuff to do.
6228
+ *
6229
+ * If the global process object is not suitable for instrumentation,
6230
+ * then this will be a no-op.
6231
+ *
6232
+ * Returns a function that may be used to unload signal-exit.
6233
+ */
6234
+ onExit
6235
+ ),
6236
+ load: (
6237
+ /**
6238
+ * Load the listeners. Likely you never need to call this, unless
6239
+ * doing a rather deep integration with signal-exit functionality.
6240
+ * Mostly exposed for the benefit of testing.
6241
+ *
6242
+ * @internal
6243
+ */
6244
+ load
6245
+ ),
6246
+ unload: (
6247
+ /**
6248
+ * Unload the listeners. Likely you never need to call this, unless
6249
+ * doing a rather deep integration with signal-exit functionality.
6250
+ * Mostly exposed for the benefit of testing.
6251
+ *
6252
+ * @internal
6253
+ */
6254
+ unload
6255
+ )
6256
+ } = signalExitWrap(processOk(process3) ? new SignalExit(process3) : new SignalExitFallback()));
6257
+ }
6258
+ });
6259
+
6260
+ // ../../node_modules/.pnpm/@inquirer+ansi@2.0.5/node_modules/@inquirer/ansi/dist/index.js
6261
+ var ESC2, cursorLeft, cursorHide, cursorShow, cursorUp, cursorDown, cursorTo, eraseLine, eraseLines;
6262
+ var init_dist4 = __esm({
6263
+ "../../node_modules/.pnpm/@inquirer+ansi@2.0.5/node_modules/@inquirer/ansi/dist/index.js"() {
6264
+ ESC2 = "\x1B[";
6265
+ cursorLeft = ESC2 + "G";
6266
+ cursorHide = ESC2 + "?25l";
6267
+ cursorShow = ESC2 + "?25h";
6268
+ cursorUp = (rows = 1) => rows > 0 ? `${ESC2}${rows}A` : "";
6269
+ cursorDown = (rows = 1) => rows > 0 ? `${ESC2}${rows}B` : "";
6270
+ cursorTo = (x, y) => {
6271
+ if (typeof y === "number" && !Number.isNaN(y)) {
6272
+ return `${ESC2}${y + 1};${x + 1}H`;
6273
+ }
6274
+ return `${ESC2}${x + 1}G`;
6275
+ };
6276
+ eraseLine = ESC2 + "2K";
6277
+ eraseLines = (lines) => lines > 0 ? (eraseLine + cursorUp(1)).repeat(lines - 1) + eraseLine + cursorLeft : "";
6278
+ }
6279
+ });
6280
+
6281
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/screen-manager.js
6282
+ import { stripVTControlCharacters } from "node:util";
6283
+ var height, lastLine, ScreenManager;
6284
+ var init_screen_manager = __esm({
6285
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/screen-manager.js"() {
6286
+ init_utils2();
6287
+ init_dist4();
6288
+ height = (content) => content.split("\n").length;
6289
+ lastLine = (content) => content.split("\n").pop() ?? "";
6290
+ ScreenManager = class {
6291
+ // These variables are keeping information to allow correct prompt re-rendering
6292
+ height = 0;
6293
+ extraLinesUnderPrompt = 0;
6294
+ cursorPos;
6295
+ rl;
6296
+ constructor(rl) {
6297
+ this.rl = rl;
6298
+ this.cursorPos = rl.getCursorPos();
6299
+ }
6300
+ write(content) {
6301
+ this.rl.output.unmute();
6302
+ this.rl.output.write(content);
6303
+ this.rl.output.mute();
6304
+ }
6305
+ render(content, bottomContent = "") {
6306
+ const promptLine = lastLine(content);
6307
+ const rawPromptLine = stripVTControlCharacters(promptLine);
6308
+ let prompt = rawPromptLine;
6309
+ if (this.rl.line.length > 0) {
6310
+ prompt = prompt.slice(0, -this.rl.line.length);
6311
+ }
6312
+ this.rl.setPrompt(prompt);
6313
+ this.cursorPos = this.rl.getCursorPos();
6314
+ const width = readlineWidth();
6315
+ content = breakLines(content, width);
6316
+ bottomContent = breakLines(bottomContent, width);
6317
+ if (rawPromptLine.length % width === 0) {
6318
+ content += "\n";
6319
+ }
6320
+ let output = content + (bottomContent ? "\n" + bottomContent : "");
6321
+ const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
6322
+ const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
6323
+ if (bottomContentHeight > 0)
6324
+ output += cursorUp(bottomContentHeight);
6325
+ output += cursorTo(this.cursorPos.cols);
6326
+ this.write(cursorDown(this.extraLinesUnderPrompt) + eraseLines(this.height) + output);
6327
+ this.extraLinesUnderPrompt = bottomContentHeight;
6328
+ this.height = height(output);
6329
+ }
6330
+ checkCursorPos() {
6331
+ const cursorPos = this.rl.getCursorPos();
6332
+ if (cursorPos.cols !== this.cursorPos.cols) {
6333
+ this.write(cursorTo(cursorPos.cols));
6334
+ this.cursorPos = cursorPos;
6335
+ }
6336
+ }
6337
+ done({ clearContent }) {
6338
+ this.rl.setPrompt("");
6339
+ let output = cursorDown(this.extraLinesUnderPrompt);
6340
+ output += clearContent ? eraseLines(this.height) : "\n";
6341
+ output += cursorShow;
6342
+ this.write(output);
6343
+ this.rl.close();
6344
+ }
6345
+ };
6346
+ }
6347
+ });
6348
+
6349
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/promise-polyfill.js
6350
+ var PromisePolyfill;
6351
+ var init_promise_polyfill = __esm({
6352
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/promise-polyfill.js"() {
6353
+ PromisePolyfill = class extends Promise {
6354
+ // Available starting from Node 22
6355
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
6356
+ static withResolver() {
6357
+ let resolve;
6358
+ let reject;
6359
+ const promise2 = new Promise((res, rej) => {
6360
+ resolve = res;
6361
+ reject = rej;
6362
+ });
6363
+ return { promise: promise2, resolve, reject };
6364
+ }
6365
+ };
6366
+ }
6367
+ });
6368
+
6369
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/create-prompt.js
6370
+ import * as readline2 from "node:readline";
6371
+ import { AsyncResource as AsyncResource3 } from "node:async_hooks";
6372
+ import path from "node:path";
6373
+ function getCallSites() {
6374
+ const _prepareStackTrace = Error.prepareStackTrace;
6375
+ let result = [];
6376
+ try {
6377
+ Error.prepareStackTrace = (_, callSites) => {
6378
+ const callSitesWithoutCurrent = callSites.slice(1);
6379
+ result = callSitesWithoutCurrent;
6380
+ return callSitesWithoutCurrent;
6381
+ };
6382
+ new Error().stack;
6383
+ } catch {
6384
+ return result;
6385
+ }
6386
+ Error.prepareStackTrace = _prepareStackTrace;
6387
+ return result;
6388
+ }
6389
+ function createPrompt(view) {
6390
+ const callSites = getCallSites();
6391
+ const prompt = (config2, context = {}) => {
6392
+ const { input = process.stdin, signal } = context;
6393
+ const cleanups = /* @__PURE__ */ new Set();
6394
+ const output = new import_mute_stream.default();
6395
+ output.pipe(context.output ?? process.stdout);
6396
+ const rl = readline2.createInterface({
6397
+ terminal: true,
6398
+ input,
6399
+ output
6400
+ });
6401
+ output.mute();
6402
+ const screen = new ScreenManager(rl);
6403
+ const { promise: promise2, resolve, reject } = PromisePolyfill.withResolver();
6404
+ const cancel = () => reject(new CancelPromptError());
6405
+ if (signal) {
6406
+ const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
6407
+ if (signal.aborted) {
6408
+ abort();
6409
+ return Object.assign(promise2, { cancel });
6410
+ }
6411
+ signal.addEventListener("abort", abort);
6412
+ cleanups.add(() => signal.removeEventListener("abort", abort));
6413
+ }
6414
+ cleanups.add(onExit((code, signal2) => {
6415
+ reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal2}`));
6416
+ }));
6417
+ const sigint = () => reject(new ExitPromptError(`User force closed the prompt with SIGINT`));
6418
+ rl.on("SIGINT", sigint);
6419
+ cleanups.add(() => rl.removeListener("SIGINT", sigint));
6420
+ return withHooks(rl, (cycle) => {
6421
+ const hooksCleanup = AsyncResource3.bind(() => effectScheduler.clearAll());
6422
+ rl.on("close", hooksCleanup);
6423
+ cleanups.add(() => rl.removeListener("close", hooksCleanup));
6424
+ const startCycle = () => {
6425
+ const checkCursorPos = () => screen.checkCursorPos();
6426
+ rl.input.on("keypress", checkCursorPos);
6427
+ cleanups.add(() => rl.input.removeListener("keypress", checkCursorPos));
6428
+ let pendingDone = null;
6429
+ cycle(() => {
6430
+ let effectsSettled = false;
6431
+ try {
6432
+ const nextView = view(config2, (value) => {
6433
+ if (effectsSettled) {
6434
+ resolve(value);
6435
+ } else {
6436
+ pendingDone = { value };
6437
+ }
6438
+ });
6439
+ if (nextView === void 0) {
6440
+ let callerFilename = callSites[1]?.getFileName();
6441
+ if (callerFilename && !callerFilename.startsWith("file://")) {
6442
+ callerFilename = path.resolve(callerFilename);
6443
+ }
6444
+ throw new Error(`Prompt functions must return a string.
6445
+ at ${callerFilename}`);
6446
+ }
6447
+ const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
6448
+ screen.render(content, bottomContent);
6449
+ effectScheduler.run();
6450
+ } catch (error40) {
6451
+ reject(error40);
6452
+ }
6453
+ effectsSettled = true;
6454
+ if (pendingDone !== null) {
6455
+ const { value } = pendingDone;
6456
+ pendingDone = null;
6457
+ resolve(value);
6458
+ }
6459
+ });
6460
+ };
6461
+ if ("readableFlowing" in input) {
6462
+ nativeSetImmediate(startCycle);
6463
+ } else {
6464
+ startCycle();
6465
+ }
6466
+ return Object.assign(promise2.then((answer) => {
6467
+ effectScheduler.clearAll();
6468
+ return answer;
6469
+ }, (error40) => {
6470
+ effectScheduler.clearAll();
6471
+ throw error40;
6472
+ }).finally(() => {
6473
+ cleanups.forEach((cleanup) => cleanup());
6474
+ screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
6475
+ output.end();
6476
+ }).then(() => promise2), { cancel });
6477
+ });
6478
+ };
6479
+ return prompt;
6480
+ }
6481
+ var import_mute_stream, nativeSetImmediate;
6482
+ var init_create_prompt = __esm({
6483
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/create-prompt.js"() {
6484
+ import_mute_stream = __toESM(require_lib(), 1);
6485
+ init_mjs();
6486
+ init_screen_manager();
6487
+ init_promise_polyfill();
6488
+ init_hook_engine();
6489
+ init_errors();
6490
+ nativeSetImmediate = globalThis.setImmediate;
6491
+ }
6492
+ });
6493
+
6494
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/Separator.js
6495
+ import { styleText as styleText2 } from "node:util";
6496
+ var Separator;
6497
+ var init_Separator = __esm({
6498
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/lib/Separator.js"() {
6499
+ init_dist();
6500
+ Separator = class {
6501
+ separator = styleText2("dim", Array.from({ length: 15 }).join(dist_default.line));
6502
+ type = "separator";
6503
+ constructor(separator) {
6504
+ if (separator) {
6505
+ this.separator = separator;
6506
+ }
6507
+ }
6508
+ static isSeparator(choice) {
6509
+ return Boolean(choice && typeof choice === "object" && "type" in choice && choice.type === "separator");
6510
+ }
6511
+ };
6512
+ }
6513
+ });
6514
+
6515
+ // ../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/index.js
6516
+ var init_dist5 = __esm({
6517
+ "../../node_modules/.pnpm/@inquirer+core@11.1.9_@types+node@22.19.17/node_modules/@inquirer/core/dist/index.js"() {
6518
+ init_key();
6519
+ init_errors();
6520
+ init_use_prefix();
6521
+ init_use_state();
6522
+ init_use_memo();
6523
+ init_use_keypress();
6524
+ init_make_theme();
6525
+ init_use_pagination();
6526
+ init_create_prompt();
6527
+ init_Separator();
6528
+ }
6529
+ });
6530
+
6531
+ // ../../node_modules/.pnpm/@inquirer+checkbox@5.1.4_@types+node@22.19.17/node_modules/@inquirer/checkbox/dist/index.js
6532
+ import { styleText as styleText3 } from "node:util";
6533
+ function isSelectable(item) {
6534
+ return !Separator.isSeparator(item) && !item.disabled;
6535
+ }
6536
+ function isNavigable(item) {
6537
+ return !Separator.isSeparator(item);
6538
+ }
6539
+ function isChecked(item) {
6540
+ return !Separator.isSeparator(item) && item.checked;
6541
+ }
6542
+ function toggle(item) {
6543
+ return isSelectable(item) ? { ...item, checked: !item.checked } : item;
6544
+ }
6545
+ function check(checked) {
6546
+ return function(item) {
6547
+ return isSelectable(item) ? { ...item, checked } : item;
6548
+ };
6549
+ }
6550
+ function normalizeChoices(choices) {
6551
+ return choices.map((choice) => {
6552
+ if (Separator.isSeparator(choice))
6553
+ return choice;
6554
+ if (typeof choice !== "object" || choice === null || !("value" in choice)) {
6555
+ const name2 = String(choice);
6556
+ return {
6557
+ value: choice,
6558
+ name: name2,
6559
+ short: name2,
6560
+ checkedName: name2,
6561
+ disabled: false,
6562
+ checked: false
6563
+ };
6564
+ }
6565
+ const name = choice.name ?? String(choice.value);
6566
+ const normalizedChoice = {
6567
+ value: choice.value,
6568
+ name,
6569
+ short: choice.short ?? name,
6570
+ checkedName: choice.checkedName ?? name,
6571
+ disabled: choice.disabled ?? false,
6572
+ checked: choice.checked ?? false
6573
+ };
6574
+ if (choice.description) {
6575
+ normalizedChoice.description = choice.description;
6576
+ }
6577
+ return normalizedChoice;
6578
+ });
6579
+ }
6580
+ var checkboxTheme, dist_default4;
6581
+ var init_dist6 = __esm({
6582
+ "../../node_modules/.pnpm/@inquirer+checkbox@5.1.4_@types+node@22.19.17/node_modules/@inquirer/checkbox/dist/index.js"() {
6583
+ init_dist5();
6584
+ init_dist4();
6585
+ init_dist();
6586
+ init_dist5();
6587
+ checkboxTheme = {
6588
+ icon: {
6589
+ checked: styleText3("green", dist_default.circleFilled),
6590
+ unchecked: dist_default.circle,
6591
+ cursor: dist_default.pointer,
6592
+ disabledChecked: styleText3("green", dist_default.circleDouble),
6593
+ disabledUnchecked: "-"
6594
+ },
6595
+ style: {
6596
+ disabled: (text) => styleText3("dim", text),
6597
+ renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
6598
+ description: (text) => styleText3("cyan", text),
6599
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText3("bold", key)} ${styleText3("dim", action)}`).join(styleText3("dim", " \u2022 "))
6600
+ },
6601
+ i18n: { disabledError: "This option is disabled and cannot be toggled." },
6602
+ keybindings: []
6603
+ };
6604
+ dist_default4 = createPrompt((config2, done) => {
6605
+ const { pageSize = 7, loop = true, required: required2, validate = () => true } = config2;
6606
+ const shortcuts = { all: "a", invert: "i", ...config2.shortcuts };
6607
+ const theme = makeTheme(checkboxTheme, config2.theme);
6608
+ const { keybindings } = theme;
6609
+ const [status, setStatus] = useState("idle");
6610
+ const prefix = usePrefix({ status, theme });
6611
+ const [items, setItems] = useState(normalizeChoices(config2.choices));
6612
+ const bounds = useMemo(() => {
6613
+ const first = items.findIndex(isNavigable);
6614
+ const last = items.findLastIndex(isNavigable);
6615
+ if (first === -1) {
6616
+ throw new ValidationError("[checkbox prompt] No selectable choices. All choices are disabled.");
6617
+ }
6618
+ return { first, last };
6619
+ }, [items]);
6620
+ const [active, setActive] = useState(bounds.first);
6621
+ const [errorMsg, setError] = useState();
6622
+ useKeypress(async (key) => {
6623
+ if (isEnterKey(key)) {
6624
+ const selection = items.filter(isChecked);
6625
+ const isValid = await validate([...selection]);
6626
+ if (required2 && !selection.length) {
6627
+ setError("At least one choice must be selected");
6628
+ } else if (isValid === true) {
6629
+ setStatus("done");
6630
+ done(selection.map((choice) => choice.value));
6631
+ } else {
6632
+ setError(isValid || "You must select a valid value");
6633
+ }
6634
+ } else if (isUpKey(key, keybindings) || isDownKey(key, keybindings)) {
6635
+ if (errorMsg) {
6636
+ setError(void 0);
6637
+ }
6638
+ if (loop || isUpKey(key, keybindings) && active !== bounds.first || isDownKey(key, keybindings) && active !== bounds.last) {
6639
+ const offset = isUpKey(key, keybindings) ? -1 : 1;
6640
+ let next = active;
6641
+ do {
6642
+ next = (next + offset + items.length) % items.length;
6643
+ } while (!isNavigable(items[next]));
6644
+ setActive(next);
6645
+ }
6646
+ } else if (isSpaceKey(key)) {
6647
+ const activeItem = items[active];
6648
+ if (activeItem && !Separator.isSeparator(activeItem)) {
6649
+ if (activeItem.disabled) {
6650
+ setError(theme.i18n.disabledError);
6651
+ } else {
6652
+ setError(void 0);
6653
+ setItems(items.map((choice, i) => i === active ? toggle(choice) : choice));
6654
+ }
6655
+ }
6656
+ } else if (key.name === shortcuts.all) {
6657
+ const selectAll = items.some((choice) => isSelectable(choice) && !choice.checked);
6658
+ setItems(items.map(check(selectAll)));
6659
+ } else if (key.name === shortcuts.invert) {
6660
+ setItems(items.map(toggle));
6661
+ } else if (isNumberKey(key)) {
6662
+ const selectedIndex = Number(key.name) - 1;
6663
+ let selectableIndex = -1;
6664
+ const position = items.findIndex((item) => {
6665
+ if (Separator.isSeparator(item))
6666
+ return false;
6667
+ selectableIndex++;
6668
+ return selectableIndex === selectedIndex;
6669
+ });
6670
+ const selectedItem = items[position];
6671
+ if (selectedItem && isSelectable(selectedItem)) {
6672
+ setActive(position);
6673
+ setItems(items.map((choice, i) => i === position ? toggle(choice) : choice));
6674
+ }
6675
+ }
6676
+ });
6677
+ const message = theme.style.message(config2.message, status);
6678
+ let description;
6679
+ const page = usePagination({
6680
+ items,
6681
+ active,
6682
+ renderItem({ item, isActive }) {
6683
+ if (Separator.isSeparator(item)) {
6684
+ return ` ${item.separator}`;
6685
+ }
6686
+ const cursor = isActive ? theme.icon.cursor : " ";
6687
+ if (item.disabled) {
6688
+ const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
6689
+ const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
6690
+ return theme.style.disabled(`${cursor}${checkbox2} ${item.name} ${disabledLabel}`);
6691
+ }
6692
+ if (isActive) {
6693
+ description = item.description;
6694
+ }
6695
+ const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
6696
+ const name = item.checked ? item.checkedName : item.name;
6697
+ const color = isActive ? theme.style.highlight : (x) => x;
6698
+ return color(`${cursor}${checkbox} ${name}`);
6699
+ },
6700
+ pageSize,
6701
+ loop
6702
+ });
6703
+ if (status === "done") {
6704
+ const selection = items.filter(isChecked);
6705
+ const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
6706
+ return [prefix, message, answer].filter(Boolean).join(" ");
6707
+ }
6708
+ const keys = [
6709
+ ["\u2191\u2193", "navigate"],
6710
+ ["space", "select"]
6711
+ ];
6712
+ if (shortcuts.all)
6713
+ keys.push([shortcuts.all, "all"]);
6714
+ if (shortcuts.invert)
6715
+ keys.push([shortcuts.invert, "invert"]);
6716
+ keys.push(["\u23CE", "submit"]);
6717
+ const helpLine = theme.style.keysHelpTip(keys);
6718
+ const lines = [
6719
+ [prefix, message].filter(Boolean).join(" "),
6720
+ page,
6721
+ " ",
6722
+ description ? theme.style.description(description) : "",
6723
+ errorMsg ? theme.style.error(errorMsg) : "",
6724
+ helpLine
6725
+ ].filter(Boolean).join("\n").trimEnd();
6726
+ return `${lines}${cursorHide}`;
6727
+ });
6728
+ }
6729
+ });
6730
+
6731
+ // src/bridge/lib/binary-installer.ts
6732
+ import { spawn as spawn5 } from "node:child_process";
6733
+ import { homedir as homedir2, tmpdir } from "node:os";
6734
+ import { join as join3, basename } from "node:path";
6735
+ import { mkdirSync, rmSync, chmodSync, existsSync, symlinkSync, unlinkSync, createWriteStream } from "node:fs";
6736
+ import { randomBytes } from "node:crypto";
6737
+ import { Readable } from "node:stream";
6738
+ import { pipeline } from "node:stream/promises";
6739
+ function platformKey() {
6740
+ const os = process.platform === "win32" ? "windows" : process.platform;
6741
+ const arch = process.arch === "arm64" ? "aarch64" : process.arch === "x64" ? "x86_64" : process.arch;
6742
+ return `${os}-${arch}`;
6743
+ }
6744
+ async function installBinaryWrapper(opts) {
6745
+ const archive = opts.install.archives[platformKey()];
6746
+ if (!archive) {
6747
+ return {
6748
+ ok: false,
6749
+ error: `no archive for ${platformKey()}`,
6750
+ hint: opts.install.downloadUrl ? `manual install: ${opts.install.downloadUrl}` : void 0
6751
+ };
6752
+ }
6753
+ const cmdRel = archive.cmd.replace(/^\.\//, "");
6754
+ const binName = basename(cmdRel).replace(/\.exe$/, "");
6755
+ const wrapperDir = join3(WRAPPERS_DIR, opts.id);
6756
+ const cmdAbs = join3(wrapperDir, cmdRel);
6757
+ const linkPath = join3(BIN_DIR, binName);
6758
+ try {
6759
+ rmSync(wrapperDir, { recursive: true, force: true });
6760
+ } catch (e) {
6761
+ return { ok: false, error: `wipe stale wrapper dir failed: ${e.message}` };
6762
+ }
6763
+ mkdirSync(wrapperDir, { recursive: true });
6764
+ mkdirSync(BIN_DIR, { recursive: true });
6765
+ const ext = guessExtension(archive.url);
6766
+ const tmpFile = join3(tmpdir(), `oma-${opts.id}-${randomBytes(4).toString("hex")}${ext}`);
6767
+ try {
6768
+ opts.onProgress?.(`downloading ${archive.url}`);
6769
+ await downloadToFile(archive.url, tmpFile, opts.onProgress);
6770
+ opts.onProgress?.(`extracting to ${wrapperDir}`);
6771
+ await extractArchive(tmpFile, wrapperDir, ext);
6772
+ if (!existsSync(cmdAbs)) {
6773
+ return {
6774
+ ok: false,
6775
+ error: `extracted archive missing expected cmd: ${cmdRel}`
6776
+ };
6777
+ }
6778
+ chmodSync(cmdAbs, 493);
6779
+ try {
6780
+ unlinkSync(linkPath);
6781
+ } catch {
6782
+ }
6783
+ symlinkSync(cmdAbs, linkPath);
6784
+ const result = { ok: true, binPath: linkPath, installedAt: wrapperDir };
6785
+ if (!isOnPath2(BIN_DIR)) {
6786
+ result.hint = `add \`${BIN_DIR}\` to your PATH (it's where OMA installs wrappers)`;
6787
+ }
6788
+ return result;
6789
+ } catch (e) {
6790
+ return { ok: false, error: e.message };
6791
+ } finally {
6792
+ try {
6793
+ unlinkSync(tmpFile);
6794
+ } catch {
6795
+ }
6796
+ }
6797
+ }
6798
+ function guessExtension(url2) {
6799
+ const path2 = (() => {
6800
+ try {
6801
+ return new URL(url2).pathname;
6802
+ } catch {
6803
+ return url2;
6804
+ }
6805
+ })();
6806
+ for (const ext of [".tar.gz", ".tgz", ".tar.bz2", ".tbz2", ".tar.xz", ".txz", ".zip"]) {
6807
+ if (path2.toLowerCase().endsWith(ext)) return ext;
6808
+ }
6809
+ return "";
6810
+ }
6811
+ async function downloadToFile(url2, dest, onProgress) {
6812
+ const res = await fetch(url2, { redirect: "follow" });
6813
+ if (!res.ok) throw new Error(`download HTTP ${res.status}`);
6814
+ const total = Number(res.headers.get("content-length") ?? "0");
6815
+ if (!res.body) throw new Error("download returned empty body");
6816
+ let last = Date.now();
6817
+ let read = 0;
6818
+ const stream = res.body;
6819
+ const node = Readable.fromWeb(stream);
6820
+ node.on("data", (chunk) => {
6821
+ read += chunk.byteLength;
6822
+ if (Date.now() - last > 1e3 && onProgress) {
6823
+ last = Date.now();
6824
+ const pct = total ? `${Math.floor(read / total * 100)}%` : "";
6825
+ onProgress(` \u2026${formatBytes(read)}${total ? `/${formatBytes(total)} ${pct}` : ""}`);
6826
+ }
6827
+ });
6828
+ await pipeline(node, createWriteStream(dest));
6829
+ }
6830
+ function formatBytes(n) {
6831
+ if (n < 1024) return `${n}B`;
6832
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
6833
+ return `${(n / 1024 / 1024).toFixed(1)}MB`;
6834
+ }
6835
+ function extractArchive(archive, dest, ext) {
6836
+ const isWin = process.platform === "win32";
6837
+ let cmd;
6838
+ let args;
6839
+ if (ext === ".zip") {
6840
+ if (isWin) {
6841
+ cmd = "tar";
6842
+ args = ["-xf", archive, "-C", dest];
6843
+ } else {
6844
+ cmd = "unzip";
6845
+ args = ["-q", "-o", archive, "-d", dest];
6846
+ }
6847
+ } else if (ext === ".tar.gz" || ext === ".tgz") {
6848
+ cmd = "tar";
6849
+ args = ["-xzf", archive, "-C", dest];
6850
+ } else if (ext === ".tar.bz2" || ext === ".tbz2") {
6851
+ cmd = "tar";
6852
+ args = ["-xjf", archive, "-C", dest];
6853
+ } else if (ext === ".tar.xz" || ext === ".txz") {
6854
+ cmd = "tar";
6855
+ args = ["-xJf", archive, "-C", dest];
6856
+ } else {
6857
+ return Promise.reject(new Error(`unsupported archive extension '${ext || "?"}'`));
6858
+ }
6859
+ return new Promise((resolve, reject) => {
6860
+ const p = spawn5(cmd, args, { stdio: ["ignore", "ignore", "pipe"] });
6861
+ let err = "";
6862
+ p.stderr?.on("data", (d) => {
6863
+ err += d.toString();
6864
+ });
6865
+ p.once("error", (e) => reject(new Error(`${cmd} spawn failed: ${e.message}`)));
6866
+ p.once("exit", (code) => {
6867
+ if (code === 0) resolve();
6868
+ else reject(new Error(`${cmd} exited ${code}: ${err.trim().slice(0, 400)}`));
6869
+ });
6870
+ });
6871
+ }
6872
+ function isOnPath2(dir) {
6873
+ const sep = process.platform === "win32" ? ";" : ":";
6874
+ return (process.env.PATH ?? "").split(sep).includes(dir);
6875
+ }
6876
+ var WRAPPERS_DIR, BIN_DIR, binDir;
6877
+ var init_binary_installer = __esm({
6878
+ "src/bridge/lib/binary-installer.ts"() {
6879
+ "use strict";
6880
+ WRAPPERS_DIR = join3(homedir2(), ".local", "share", "oma", "wrappers");
6881
+ BIN_DIR = join3(homedir2(), ".local", "bin");
6882
+ binDir = BIN_DIR;
6883
+ }
6884
+ });
6885
+
6886
+ // src/bridge/lib/wrapper-audit.ts
6887
+ import { spawn as spawn6 } from "node:child_process";
6888
+ async function auditAndOfferWrappers(initialAgents, opts = {}) {
6889
+ let agents = initialAgents.map((a) => ({ id: a.id }));
6890
+ const detectedIds = new Set(agents.map((a) => a.id));
6891
+ const rows = [];
6892
+ for (const e of getKnownAgents()) {
6893
+ if (detectedIds.has(e.id)) {
6894
+ if (e.wraps) {
6895
+ rows.push({ id: e.id, label: e.label, status: { kind: "wrapper-detected", wraps: e.wraps } });
6896
+ } else {
6897
+ rows.push({ id: e.id, label: e.label, status: { kind: "builtin-detected" } });
6898
+ }
6899
+ continue;
6900
+ }
6901
+ if (e.wraps && e.install && await isOnPath3(e.wraps)) {
6902
+ rows.push({
6903
+ id: e.id,
6904
+ label: e.label,
6905
+ status: { kind: "wrapper-needs-install", wraps: e.wraps, install: e.install }
6906
+ });
6907
+ }
6908
+ }
6909
+ if (rows.length === 0) return agents;
6910
+ const tty2 = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
6911
+ if (opts.dryRun) {
6912
+ printAuditPlain(rows);
6913
+ return agents;
6914
+ }
6915
+ if (!tty2 && !opts.yes) {
6916
+ printAuditPlain(rows);
6917
+ log.hint("non-interactive context \u2014 skipping prompts. Re-run from a terminal to install.");
6918
+ return agents;
6919
+ }
6920
+ let toInstall;
6921
+ if (opts.yes) {
6922
+ toInstall = rows.filter((r) => {
6923
+ if (r.status.kind !== "wrapper-needs-install") return false;
6924
+ const inst = r.status.install;
6925
+ if (inst.kind === "npm") return true;
6926
+ if (inst.kind === "binary") return Boolean(inst.archives[platformKey()]);
6927
+ return false;
6928
+ });
6929
+ } else {
6930
+ const choices = buildChoices(rows);
6931
+ if (!choices.some((c3) => "value" in c3 && !("disabled" in c3 && c3.disabled))) {
6932
+ printAuditPlain(rows);
6933
+ log.hint("nothing to install \u2014 your ACP agents are already in sync");
6934
+ return agents;
6935
+ }
6936
+ const selected = await dist_default4({
6937
+ message: "Install ACP wrappers? (space to toggle, enter to confirm)",
6938
+ choices,
6939
+ pageSize: Math.min(20, choices.length + 2),
6940
+ loop: false
6941
+ }).catch(() => []);
6942
+ toInstall = rows.filter((r) => {
6943
+ if (r.status.kind !== "wrapper-needs-install") return false;
6944
+ if (!selected.includes(r.id)) return false;
6945
+ const inst = r.status.install;
6946
+ if (inst.kind === "npm") return true;
6947
+ if (inst.kind === "binary") return Boolean(inst.archives[platformKey()]);
6948
+ return false;
6949
+ });
6950
+ }
6951
+ if (toInstall.length === 0) {
6952
+ log.hint("nothing to install");
6953
+ return agents;
6954
+ }
6955
+ let installed = 0;
6956
+ for (const r of toInstall) {
6957
+ if (r.status.kind !== "wrapper-needs-install") continue;
6958
+ const inst = r.status.install;
6959
+ if (inst.kind === "npm") {
6960
+ log.step(`installing ${inst.package}`);
6961
+ const ok = await npmInstallGlobal(inst.package);
6962
+ if (ok) {
6963
+ log.ok(`${r.id} installed`);
6964
+ installed += 1;
6965
+ } else {
6966
+ log.warn(`install failed \u2014 try manually: npm i -g ${inst.package}`);
6967
+ }
6968
+ } else if (inst.kind === "binary") {
6969
+ log.step(`downloading ${r.id} (binary, ${platformKey()})`);
6970
+ const result = await installBinaryWrapper({
6971
+ id: r.id,
6972
+ install: inst,
6973
+ onProgress: (m) => process.stderr.write(` ${c.dim(m)}
6974
+ `)
6975
+ });
6976
+ if (result.ok) {
6977
+ log.ok(`${r.id} installed \u2192 ${c.dim(result.binPath ?? "")}`);
6978
+ if (result.hint) log.hint(result.hint);
6979
+ installed += 1;
6980
+ } else {
6981
+ log.warn(`${r.id} install failed: ${result.error ?? "unknown"}`);
6982
+ if (result.hint) log.hint(result.hint);
6983
+ if (inst.downloadUrl) log.hint(`manual: ${inst.downloadUrl}`);
4060
6984
  }
4061
- });
4062
- ws.once("error", (e) => {
4063
- clearTimeout(timer);
4064
- settle({
4065
- ok: false,
4066
- reason: "unreachable",
4067
- detail: e instanceof Error ? e.message : String(e)
6985
+ }
6986
+ }
6987
+ if (installed > 0) {
6988
+ agents = (await detectAll()).map((a) => ({ id: a.id, binary: a.spec.command }));
6989
+ }
6990
+ return agents;
6991
+ }
6992
+ function buildChoices(rows) {
6993
+ const detected = rows.filter((r) => r.status.kind !== "wrapper-needs-install");
6994
+ const missing = rows.filter((r) => r.status.kind === "wrapper-needs-install");
6995
+ const out = [];
6996
+ if (detected.length) {
6997
+ out.push(new Separator(c.dim("\u2500\u2500\u2500 already detected on this machine \u2500\u2500\u2500")));
6998
+ for (const r of detected) {
6999
+ const tag = r.status.kind === "wrapper-detected" ? `wrapper for \`${r.status.wraps}\`` : "built-in ACP";
7000
+ out.push({
7001
+ name: `${r.id.padEnd(18)}${c.dim(tag)}`,
7002
+ value: r.id,
7003
+ disabled: " (already installed)"
4068
7004
  });
4069
- });
7005
+ }
7006
+ }
7007
+ if (missing.length) {
7008
+ out.push(new Separator(c.dim("\u2500\u2500\u2500 ACP wrappers available to install \u2500\u2500\u2500")));
7009
+ const pk = platformKey();
7010
+ for (const r of missing) {
7011
+ if (r.status.kind !== "wrapper-needs-install") continue;
7012
+ const wrapsLabel = c.dim(`wraps \`${r.status.wraps}\``);
7013
+ const inst = r.status.install;
7014
+ if (inst.kind === "npm") {
7015
+ out.push({
7016
+ name: `${r.id.padEnd(18)}${wrapsLabel} ${c.dim(`\u2014 npm i -g ${inst.package}`)}`,
7017
+ value: r.id,
7018
+ checked: false
7019
+ });
7020
+ } else {
7021
+ const archive = inst.archives[pk];
7022
+ if (archive) {
7023
+ out.push({
7024
+ name: `${r.id.padEnd(18)}${wrapsLabel} ${c.dim(`\u2014 binary release (${pk}) \u2192 ~/.local/bin/`)}`,
7025
+ value: r.id,
7026
+ checked: false
7027
+ });
7028
+ } else {
7029
+ out.push({
7030
+ name: `${r.id.padEnd(18)}${wrapsLabel} ${c.dim(`\u2014 no ${pk} build` + (inst.downloadUrl ? `; see ${inst.downloadUrl}` : ""))}`,
7031
+ value: r.id,
7032
+ disabled: " (manual download required)"
7033
+ });
7034
+ }
7035
+ }
7036
+ }
7037
+ }
7038
+ return out;
7039
+ }
7040
+ function printAuditPlain(rows) {
7041
+ process.stderr.write("\n");
7042
+ log.step(`ACP audit (${rows.length} relevant on this machine):`);
7043
+ const pk = platformKey();
7044
+ for (const r of rows) {
7045
+ let line;
7046
+ if (r.status.kind === "builtin-detected") {
7047
+ line = ` ${c.green("\u2713")} ${r.id.padEnd(18)} ${c.dim("built-in ACP")}`;
7048
+ } else if (r.status.kind === "wrapper-detected") {
7049
+ line = ` ${c.green("\u2713")} ${r.id.padEnd(18)} ${c.dim(`wrapper for \`${r.status.wraps}\``)}`;
7050
+ } else {
7051
+ const inst = r.status.install;
7052
+ if (inst.kind === "npm") {
7053
+ line = ` ${c.yellow("\u25CB")} ${r.id.padEnd(18)} ${c.dim(`wraps \`${r.status.wraps}\` \u2014 npm i -g ${inst.package}`)}`;
7054
+ } else if (inst.archives[pk]) {
7055
+ line = ` ${c.yellow("\u25CB")} ${r.id.padEnd(18)} ${c.dim(`wraps \`${r.status.wraps}\` \u2014 binary release (${pk}) \u2192 ${binDir}`)}`;
7056
+ } else {
7057
+ line = ` ${c.yellow("\u25CB")} ${r.id.padEnd(18)} ${c.dim(`wraps \`${r.status.wraps}\` \u2014 no ${pk} build` + (inst.downloadUrl ? `, see ${inst.downloadUrl}` : ""))}`;
7058
+ }
7059
+ }
7060
+ process.stderr.write(line + "\n");
7061
+ }
7062
+ }
7063
+ function isOnPath3(cmd) {
7064
+ return new Promise((resolve) => {
7065
+ const probe = process.platform === "win32" ? "where" : "which";
7066
+ const p = spawn6(probe, [cmd], { stdio: "ignore" });
7067
+ p.once("error", () => resolve(false));
7068
+ p.once("exit", (code) => resolve(code === 0));
4070
7069
  });
4071
7070
  }
4072
- var init_probe = __esm({
4073
- "src/bridge/lib/probe.ts"() {
7071
+ function npmInstallGlobal(pkg) {
7072
+ return new Promise((resolve) => {
7073
+ const p = spawn6("npm", ["install", "-g", pkg], { stdio: "inherit" });
7074
+ p.once("error", () => resolve(false));
7075
+ p.once("exit", (code) => resolve(code === 0));
7076
+ });
7077
+ }
7078
+ var init_wrapper_audit = __esm({
7079
+ "src/bridge/lib/wrapper-audit.ts"() {
4074
7080
  "use strict";
7081
+ init_dist6();
7082
+ init_registry();
7083
+ init_style();
7084
+ init_binary_installer();
4075
7085
  }
4076
7086
  });
4077
7087
 
@@ -4081,18 +7091,22 @@ __export(setup_exports, {
4081
7091
  runSetup: () => runSetup
4082
7092
  });
4083
7093
  import { createServer } from "node:http";
4084
- import { spawn as spawn3 } from "node:child_process";
7094
+ import { spawn as spawn7 } from "node:child_process";
4085
7095
  import { hostname } from "node:os";
4086
- import { randomBytes } from "node:crypto";
7096
+ import { randomBytes as randomBytes2 } from "node:crypto";
4087
7097
  import { realpathSync } from "node:fs";
4088
- function launchdInstallOpts() {
7098
+ import { join as join4 } from "node:path";
7099
+ function serviceInstallOpts() {
4089
7100
  return {
4090
7101
  nodePath: process.execPath,
4091
7102
  cliEntry: realpathSync(process.argv[1])
4092
7103
  };
4093
7104
  }
4094
7105
  async function runSetup(opts) {
4095
- printBanner(`setup \u2014 register this machine with ${opts.serverUrl}`, PKG_VERSION);
7106
+ const profile = currentProfile();
7107
+ const profileTag = profile ? ` [profile=${profile}]` : "";
7108
+ printBanner(`setup \u2014 register this machine with ${opts.serverUrl}${profileTag}`, PKG_VERSION);
7109
+ await loadRegistry({ cachePath: join4(paths().configDir, "registry-cache.json") });
4096
7110
  if (!opts.force) {
4097
7111
  const existing = await readCreds();
4098
7112
  if (existing) {
@@ -4109,30 +7123,19 @@ async function runSetup(opts) {
4109
7123
  } else {
4110
7124
  log.hint(`runtime ${existing.runtimeId.slice(0, 8)}\u2026 (use --force to re-register)`);
4111
7125
  }
4112
- if (!opts.noService && currentPlatform() === "darwin") {
4113
- const installedEntry = await readInstalledCliEntry();
4114
- const currentEntry = launchdInstallOpts().cliEntry;
4115
- if (installedEntry && installedEntry !== currentEntry) {
4116
- log.warn(`plist was pointing at a different binary; updating`);
4117
- log.hint(`old: ${c.dim(installedEntry)}`);
4118
- log.hint(`new: ${c.dim(currentEntry)}`);
4119
- }
4120
- await install(launchdInstallOpts());
4121
- log.ok(`launchd plist refreshed ${c.dim(paths().serviceFile ?? "")}`);
4122
- log.ok(`daemon restarted ${c.dim("logs: " + paths().logFile)}`);
4123
- } else {
4124
- log.hint("run `oma bridge daemon` to start the bridge");
4125
- }
7126
+ const fastPathAgents = (await detectAll()).map((a) => ({ id: a.id, binary: a.spec.command }));
7127
+ await auditAndOfferWrappers(fastPathAgents, { yes: opts.yes });
4126
7128
  process.stderr.write(`
4127
7129
  ${c.bold("Up to date.")}
4128
7130
 
4129
7131
  `);
7132
+ await refreshServiceOrFallback(opts);
4130
7133
  return;
4131
7134
  }
4132
7135
  }
4133
7136
  }
4134
7137
  log.step("waiting for browser to authorize");
4135
- const state = randomBytes(16).toString("hex");
7138
+ const state = randomBytes2(16).toString("hex");
4136
7139
  const code = await waitForCallback(state, opts.browserOrigin);
4137
7140
  log.ok("received code from browser");
4138
7141
  const machineId = await getOrCreateMachineId();
@@ -4154,38 +7157,105 @@ ${c.bold("Up to date.")}
4154
7157
  createdAt: Math.floor(Date.now() / 1e3)
4155
7158
  });
4156
7159
  log.ok(`credentials written ${c.dim(paths().credsFile)}`);
4157
- let agents = await detectAll();
4158
- const hasClaudeAcp = agents.some((a) => a.id === "claude-agent-acp");
4159
- if (!hasClaudeAcp && await isOnPath2("claude")) {
4160
- log.step("found `claude` on PATH \u2014 installing ACP wrapper @agentclientprotocol/claude-agent-acp");
4161
- const ok = await npmInstallGlobal("@agentclientprotocol/claude-agent-acp");
4162
- if (ok) {
4163
- log.ok("claude-agent-acp installed");
4164
- agents = await detectAll();
4165
- } else {
4166
- log.warn("auto-install failed \u2014 install manually: npm i -g @agentclientprotocol/claude-agent-acp");
4167
- }
4168
- }
7160
+ let agents = (await detectAll()).map((a) => ({ id: a.id, binary: a.spec.command }));
7161
+ agents = await auditAndOfferWrappers(agents, { yes: opts.yes });
4169
7162
  if (agents.length > 0) {
4170
7163
  log.ok(`agents detected ${c.dim(agents.map((a) => a.id).join(", "))}`);
4171
7164
  } else {
4172
7165
  log.warn("no ACP agents on PATH yet");
4173
7166
  log.hint("install one, e.g. `npm i -g @agentclientprotocol/claude-agent-acp`");
4174
7167
  }
4175
- if (opts.noService || currentPlatform() !== "darwin") {
7168
+ await installServiceOrFallback(opts);
7169
+ }
7170
+ async function installServiceOrFallback(opts) {
7171
+ const kind = detectServiceKind();
7172
+ if (opts.noService || kind === "unsupported") {
7173
+ process.stderr.write("\n");
7174
+ if (kind === "unsupported") {
7175
+ log.warn(`platform service install not supported on ${process.platform}; running daemon in foreground`);
7176
+ } else {
7177
+ log.step("--no-service: starting daemon in foreground");
7178
+ }
7179
+ log.hint("Ctrl-C to stop. To run as a system service, re-run setup without --no-service.");
7180
+ process.stderr.write("\n");
7181
+ execIntoDaemon();
7182
+ return;
7183
+ }
7184
+ await installAndReport(opts);
7185
+ }
7186
+ async function refreshServiceOrFallback(opts) {
7187
+ const kind = detectServiceKind();
7188
+ if (opts.noService || kind === "unsupported") {
4176
7189
  process.stderr.write("\n");
4177
- log.step("service install skipped");
4178
- log.hint("run `oma bridge daemon` to start the bridge in the foreground");
7190
+ log.step(opts.noService ? "--no-service: starting daemon in foreground" : `service install not supported on ${process.platform}; running daemon in foreground`);
7191
+ log.hint("Ctrl-C to stop. To run as a system service, re-run setup without --no-service.");
7192
+ process.stderr.write("\n");
7193
+ execIntoDaemon();
4179
7194
  return;
4180
7195
  }
4181
- await install(launchdInstallOpts());
4182
- log.ok(`launchd plist installed ${c.dim(paths().serviceFile ?? "")}`);
4183
- log.ok(`daemon started ${c.dim("logs: " + paths().logFile)}`);
7196
+ const installedEntry = await readInstalledCliEntry4();
7197
+ const currentEntry = serviceInstallOpts().cliEntry;
7198
+ if (installedEntry && installedEntry !== currentEntry) {
7199
+ log.warn(`service was pointing at a different binary; updating`);
7200
+ log.hint(`old: ${c.dim(installedEntry)}`);
7201
+ log.hint(`new: ${c.dim(currentEntry)}`);
7202
+ }
7203
+ await installAndReport(opts);
7204
+ }
7205
+ async function installAndReport(opts) {
7206
+ void opts;
7207
+ const result = await install4(serviceInstallOpts());
7208
+ const where = result.installedAt ? c.dim(result.installedAt) : c.dim("(no install path)");
7209
+ switch (result.kind) {
7210
+ case "launchd":
7211
+ log.ok(`launchd plist installed ${where}`);
7212
+ log.ok(`daemon started ${c.dim("logs: " + paths().logFile)}`);
7213
+ break;
7214
+ case "systemd":
7215
+ log.ok(`systemd unit installed ${where}`);
7216
+ if (result.started) {
7217
+ log.ok(`daemon started ${c.dim("logs: " + paths().logFile)}`);
7218
+ } else {
7219
+ log.warn(`unit installed but failed to start: ${result.warning ?? "unknown"}`);
7220
+ log.hint(`try: systemctl --user status ${paths().serviceLabel}`);
7221
+ }
7222
+ if (!result.lingerEnabled) {
7223
+ log.hint(lingerHint2());
7224
+ }
7225
+ break;
7226
+ case "windows-task":
7227
+ log.ok(`Task Scheduler task registered ${where}`);
7228
+ if (result.started) {
7229
+ log.ok(`daemon started ${c.dim("logs: " + paths().logFile)}`);
7230
+ } else {
7231
+ log.warn(`task registered but failed to start now: ${result.warning ?? "unknown"}`);
7232
+ log.hint(`it will run at next logon. To start manually: schtasks /run /tn ${paths().serviceLabel}`);
7233
+ }
7234
+ break;
7235
+ case "unsupported":
7236
+ log.err(`platform unsupported`);
7237
+ return;
7238
+ }
4184
7239
  process.stderr.write("\n");
4185
7240
  process.stderr.write(`${c.bold("Done.")} the runtime should appear online at ${c.cyan(opts.browserOrigin)}
4186
7241
 
4187
7242
  `);
4188
7243
  }
7244
+ function execIntoDaemon() {
7245
+ const profile = currentProfile();
7246
+ const child = spawn7(process.execPath, [process.argv[1], "bridge", "daemon"], {
7247
+ stdio: "inherit",
7248
+ env: { ...process.env, ...profile ? { OMA_PROFILE: profile } : {} }
7249
+ });
7250
+ child.once("exit", (code, signal) => {
7251
+ if (signal) {
7252
+ process.kill(process.pid, signal);
7253
+ return;
7254
+ }
7255
+ process.exit(code ?? 0);
7256
+ });
7257
+ return new Promise(() => void 0);
7258
+ }
4189
7259
  function waitForCallback(state, browserOrigin) {
4190
7260
  return new Promise((resolve, reject) => {
4191
7261
  const timeoutMs = 5 * 60 * 1e3;
@@ -4269,37 +7339,23 @@ function openBrowser(url2) {
4269
7339
  return new Promise((resolve, reject) => {
4270
7340
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
4271
7341
  const args = process.platform === "win32" ? ["", url2] : [url2];
4272
- const p = spawn3(cmd, args, { stdio: "ignore", detached: true, shell: process.platform === "win32" });
7342
+ const p = spawn7(cmd, args, { stdio: "ignore", detached: true, shell: process.platform === "win32" });
4273
7343
  p.once("error", reject);
4274
7344
  p.unref();
4275
7345
  setTimeout(() => resolve(), 100);
4276
7346
  });
4277
7347
  }
4278
- function isOnPath2(cmd) {
4279
- return new Promise((resolve) => {
4280
- const probe = process.platform === "win32" ? "where" : "which";
4281
- const p = spawn3(probe, [cmd], { stdio: "ignore" });
4282
- p.once("error", () => resolve(false));
4283
- p.once("exit", (code) => resolve(code === 0));
4284
- });
4285
- }
4286
- function npmInstallGlobal(pkg) {
4287
- return new Promise((resolve) => {
4288
- const p = spawn3("npm", ["install", "-g", pkg], { stdio: "inherit" });
4289
- p.once("error", () => resolve(false));
4290
- p.once("exit", (code) => resolve(code === 0));
4291
- });
4292
- }
4293
7348
  var init_setup = __esm({
4294
7349
  "src/bridge/commands/setup.ts"() {
4295
7350
  "use strict";
4296
7351
  init_config();
4297
7352
  init_platform();
4298
- init_launchd();
7353
+ init_service_manager();
4299
7354
  init_registry();
4300
7355
  init_style();
4301
7356
  init_version();
4302
7357
  init_probe();
7358
+ init_wrapper_audit();
4303
7359
  }
4304
7360
  });
4305
7361
 
@@ -4400,7 +7456,7 @@ __export(util_exports, {
4400
7456
  getParsedType: () => getParsedType,
4401
7457
  getSizableOrigin: () => getSizableOrigin,
4402
7458
  isObject: () => isObject,
4403
- isPlainObject: () => isPlainObject,
7459
+ isPlainObject: () => isPlainObject2,
4404
7460
  issue: () => issue,
4405
7461
  joinValues: () => joinValues,
4406
7462
  jsonStringifyReplacer: () => jsonStringifyReplacer,
@@ -4504,10 +7560,10 @@ function assignProp(target, prop, value) {
4504
7560
  configurable: true
4505
7561
  });
4506
7562
  }
4507
- function getElementAtPath(obj, path) {
4508
- if (!path)
7563
+ function getElementAtPath(obj, path2) {
7564
+ if (!path2)
4509
7565
  return obj;
4510
- return path.reduce((acc, key) => acc?.[key], obj);
7566
+ return path2.reduce((acc, key) => acc?.[key], obj);
4511
7567
  }
4512
7568
  function promiseAllObject(promisesObj) {
4513
7569
  const keys = Object.keys(promisesObj);
@@ -4534,7 +7590,7 @@ function esc(str) {
4534
7590
  function isObject(data) {
4535
7591
  return typeof data === "object" && data !== null && !Array.isArray(data);
4536
7592
  }
4537
- function isPlainObject(o) {
7593
+ function isPlainObject2(o) {
4538
7594
  if (isObject(o) === false)
4539
7595
  return false;
4540
7596
  const ctor = o.constructor;
@@ -4662,7 +7718,7 @@ function omit(schema, mask) {
4662
7718
  });
4663
7719
  }
4664
7720
  function extend(schema, shape) {
4665
- if (!isPlainObject(shape)) {
7721
+ if (!isPlainObject2(shape)) {
4666
7722
  throw new Error("Invalid input to extend: expected a plain object");
4667
7723
  }
4668
7724
  const def = {
@@ -4756,11 +7812,11 @@ function aborted(x, startIndex = 0) {
4756
7812
  }
4757
7813
  return false;
4758
7814
  }
4759
- function prefixIssues(path, issues) {
7815
+ function prefixIssues(path2, issues) {
4760
7816
  return issues.map((iss) => {
4761
7817
  var _a;
4762
7818
  (_a = iss).path ?? (_a.path = []);
4763
- iss.path.unshift(path);
7819
+ iss.path.unshift(path2);
4764
7820
  return iss;
4765
7821
  });
4766
7822
  }
@@ -4949,7 +8005,7 @@ function treeifyError(error40, _mapper) {
4949
8005
  return issue2.message;
4950
8006
  };
4951
8007
  const result = { errors: [] };
4952
- const processError = (error41, path = []) => {
8008
+ const processError = (error41, path2 = []) => {
4953
8009
  var _a, _b;
4954
8010
  for (const issue2 of error41.issues) {
4955
8011
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -4959,7 +8015,7 @@ function treeifyError(error40, _mapper) {
4959
8015
  } else if (issue2.code === "invalid_element") {
4960
8016
  processError({ issues: issue2.issues }, issue2.path);
4961
8017
  } else {
4962
- const fullpath = [...path, ...issue2.path];
8018
+ const fullpath = [...path2, ...issue2.path];
4963
8019
  if (fullpath.length === 0) {
4964
8020
  result.errors.push(mapper(issue2));
4965
8021
  continue;
@@ -4989,9 +8045,9 @@ function treeifyError(error40, _mapper) {
4989
8045
  processError(error40);
4990
8046
  return result;
4991
8047
  }
4992
- function toDotPath(path) {
8048
+ function toDotPath(path2) {
4993
8049
  const segs = [];
4994
- for (const seg of path) {
8050
+ for (const seg of path2) {
4995
8051
  if (typeof seg === "number")
4996
8052
  segs.push(`[${seg}]`);
4997
8053
  else if (typeof seg === "symbol")
@@ -5017,7 +8073,7 @@ function prettifyError(error40) {
5017
8073
  return lines.join("\n");
5018
8074
  }
5019
8075
  var initializer, $ZodError, $ZodRealError;
5020
- var init_errors = __esm({
8076
+ var init_errors2 = __esm({
5021
8077
  "../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/errors.js"() {
5022
8078
  init_core();
5023
8079
  init_util();
@@ -5053,7 +8109,7 @@ var _parse, parse, _parseAsync, parseAsync, _safeParse, safeParse, _safeParseAsy
5053
8109
  var init_parse = __esm({
5054
8110
  "../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/parse.js"() {
5055
8111
  init_core();
5056
- init_errors();
8112
+ init_errors2();
5057
8113
  init_util();
5058
8114
  _parse = (_Err) => (schema, value, _ctx, _params) => {
5059
8115
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
@@ -5841,7 +8897,7 @@ function isValidBase64(data) {
5841
8897
  function isValidBase64URL(data) {
5842
8898
  if (!base64url.test(data))
5843
8899
  return false;
5844
- const base643 = data.replace(/[-_]/g, (c2) => c2 === "-" ? "+" : "/");
8900
+ const base643 = data.replace(/[-_]/g, (c3) => c3 === "-" ? "+" : "/");
5845
8901
  const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
5846
8902
  return isValidBase64(padded);
5847
8903
  }
@@ -5917,7 +8973,7 @@ function mergeValues(a, b) {
5917
8973
  if (a instanceof Date && b instanceof Date && +a === +b) {
5918
8974
  return { valid: true, data: a };
5919
8975
  }
5920
- if (isPlainObject(a) && isPlainObject(b)) {
8976
+ if (isPlainObject2(a) && isPlainObject2(b)) {
5921
8977
  const bKeys = Object.keys(b);
5922
8978
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
5923
8979
  const newObj = { ...a, ...b };
@@ -6994,7 +10050,7 @@ var init_schemas = __esm({
6994
10050
  $ZodType.init(inst, def);
6995
10051
  inst._zod.parse = (payload, ctx) => {
6996
10052
  const input = payload.value;
6997
- if (!isPlainObject(input)) {
10053
+ if (!isPlainObject2(input)) {
6998
10054
  payload.issues.push({
6999
10055
  expected: "record",
7000
10056
  code: "invalid_type",
@@ -14535,7 +17591,7 @@ var init_core2 = __esm({
14535
17591
  "../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/index.js"() {
14536
17592
  init_core();
14537
17593
  init_parse();
14538
- init_errors();
17594
+ init_errors2();
14539
17595
  init_schemas();
14540
17596
  init_checks();
14541
17597
  init_versions();
@@ -14608,7 +17664,7 @@ var init_iso = __esm({
14608
17664
 
14609
17665
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/errors.js
14610
17666
  var initializer2, ZodError, ZodRealError;
14611
- var init_errors2 = __esm({
17667
+ var init_errors3 = __esm({
14612
17668
  "../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/errors.js"() {
14613
17669
  init_core2();
14614
17670
  init_core2();
@@ -14652,7 +17708,7 @@ var parse2, parseAsync2, safeParse2, safeParseAsync2;
14652
17708
  var init_parse2 = __esm({
14653
17709
  "../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/parse.js"() {
14654
17710
  init_core2();
14655
- init_errors2();
17711
+ init_errors3();
14656
17712
  parse2 = /* @__PURE__ */ _parse(ZodRealError);
14657
17713
  parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
14658
17714
  safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -15011,7 +18067,7 @@ function promise(innerType) {
15011
18067
  innerType
15012
18068
  });
15013
18069
  }
15014
- function check(fn) {
18070
+ function check2(fn) {
15015
18071
  const ch = new $ZodCheck({
15016
18072
  check: "custom"
15017
18073
  // ...util.normalizeParams(params),
@@ -15026,7 +18082,7 @@ function refine(fn, _params = {}) {
15026
18082
  return _refine(ZodCustom, fn, _params);
15027
18083
  }
15028
18084
  function superRefine(fn) {
15029
- const ch = check((payload) => {
18085
+ const ch = check2((payload) => {
15030
18086
  payload.addIssue = (issue2) => {
15031
18087
  if (typeof issue2 === "string") {
15032
18088
  payload.issues.push(util_exports.issue(issue2, payload.value, ch._zod.def));
@@ -15102,7 +18158,7 @@ var init_schemas2 = __esm({
15102
18158
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
15103
18159
  inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
15104
18160
  inst.spa = inst.safeParseAsync;
15105
- inst.refine = (check2, params) => inst.check(refine(check2, params));
18161
+ inst.refine = (check3, params) => inst.check(refine(check3, params));
15106
18162
  inst.superRefine = (refinement) => inst.check(superRefine(refinement));
15107
18163
  inst.overwrite = (fn) => inst.check(_overwrite(fn));
15108
18164
  inst.optional = () => optional(inst);
@@ -15369,9 +18425,9 @@ var init_schemas2 = __esm({
15369
18425
  ZodType.init(inst, def);
15370
18426
  inst.min = (value, params) => inst.check(_gte(value, params));
15371
18427
  inst.max = (value, params) => inst.check(_lte(value, params));
15372
- const c2 = inst._zod.bag;
15373
- inst.minDate = c2.minimum ? new Date(c2.minimum) : null;
15374
- inst.maxDate = c2.maximum ? new Date(c2.maximum) : null;
18428
+ const c3 = inst._zod.bag;
18429
+ inst.minDate = c3.minimum ? new Date(c3.minimum) : null;
18430
+ inst.maxDate = c3.maximum ? new Date(c3.maximum) : null;
15375
18431
  });
15376
18432
  ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
15377
18433
  $ZodArray.init(inst, def);
@@ -15754,7 +18810,7 @@ __export(external_exports, {
15754
18810
  bigint: () => bigint2,
15755
18811
  boolean: () => boolean2,
15756
18812
  catch: () => _catch2,
15757
- check: () => check,
18813
+ check: () => check2,
15758
18814
  cidrv4: () => cidrv42,
15759
18815
  cidrv6: () => cidrv62,
15760
18816
  clone: () => clone,
@@ -15883,7 +18939,7 @@ var init_external = __esm({
15883
18939
  init_core2();
15884
18940
  init_schemas2();
15885
18941
  init_checks2();
15886
- init_errors2();
18942
+ init_errors3();
15887
18943
  init_parse2();
15888
18944
  init_compat();
15889
18945
  init_core2();
@@ -18415,7 +21471,7 @@ var init_src = __esm({
18415
21471
 
18416
21472
  // ../acp-runtime/src/spawners/node.ts
18417
21473
  import { spawn as nodeSpawn } from "node:child_process";
18418
- import { Readable, Writable } from "node:stream";
21474
+ import { Readable as Readable2, Writable } from "node:stream";
18419
21475
  var NodeSpawner;
18420
21476
  var init_node = __esm({
18421
21477
  "../acp-runtime/src/spawners/node.ts"() {
@@ -18436,8 +21492,8 @@ var init_node = __esm({
18436
21492
  stdio: ["pipe", "pipe", "pipe"]
18437
21493
  });
18438
21494
  const stdin = Writable.toWeb(child.stdin);
18439
- const stdout = Readable.toWeb(child.stdout);
18440
- const stderr = Readable.toWeb(child.stderr);
21495
+ const stdout = Readable2.toWeb(child.stdout);
21496
+ const stderr = Readable2.toWeb(child.stderr);
18441
21497
  const exited = new Promise((resolve) => {
18442
21498
  let settled = false;
18443
21499
  const settle = (code, signal) => {
@@ -18461,28 +21517,28 @@ var init_node = __esm({
18461
21517
  });
18462
21518
 
18463
21519
  // src/bridge/lib/session-cwd.ts
18464
- import { mkdir as mkdir3, rm, writeFile as writeFile3 } from "node:fs/promises";
21520
+ import { mkdir as mkdir6, rm, writeFile as writeFile6 } from "node:fs/promises";
18465
21521
  import { createHash } from "node:crypto";
18466
- import { dirname as dirname3, join as join2 } from "node:path";
21522
+ import { dirname as dirname8, join as join5 } from "node:path";
18467
21523
  function dirNameFor(sessionId) {
18468
21524
  if (/^[a-f0-9]{1,12}$/i.test(sessionId)) return sessionId.toLowerCase();
18469
21525
  return createHash("sha256").update(sessionId).digest("hex").slice(0, DIR_NAME_LEN);
18470
21526
  }
18471
21527
  async function ensureSessionCwd(sessionId) {
18472
- const cwd = join2(paths().sessionsDir, dirNameFor(sessionId));
18473
- await mkdir3(cwd, { recursive: true });
21528
+ const cwd = join5(paths().sessionsDir, dirNameFor(sessionId));
21529
+ await mkdir6(cwd, { recursive: true });
18474
21530
  return cwd;
18475
21531
  }
18476
21532
  async function writeBundle(cwd, files) {
18477
21533
  for (const f of files) {
18478
21534
  if (f.path.startsWith("/") || f.path.includes("..")) continue;
18479
- const dst = join2(cwd, f.path);
18480
- await mkdir3(dirname3(dst), { recursive: true });
18481
- await writeFile3(dst, f.content);
21535
+ const dst = join5(cwd, f.path);
21536
+ await mkdir6(dirname8(dst), { recursive: true });
21537
+ await writeFile6(dst, f.content);
18482
21538
  }
18483
21539
  }
18484
21540
  async function removeSessionCwd(sessionId) {
18485
- const cwd = join2(paths().sessionsDir, dirNameFor(sessionId));
21541
+ const cwd = join5(paths().sessionsDir, dirNameFor(sessionId));
18486
21542
  try {
18487
21543
  await rm(cwd, { recursive: true, force: true });
18488
21544
  } catch {
@@ -18498,12 +21554,12 @@ var init_session_cwd = __esm({
18498
21554
  });
18499
21555
 
18500
21556
  // src/bridge/lib/claude-config-dir.ts
18501
- import { mkdir as mkdir4, readdir, rm as rm2, symlink } from "node:fs/promises";
18502
- import { join as join3 } from "node:path";
18503
- import { homedir as homedir2 } from "node:os";
21557
+ import { mkdir as mkdir7, readdir, rm as rm2, symlink } from "node:fs/promises";
21558
+ import { join as join6 } from "node:path";
21559
+ import { homedir as homedir3 } from "node:os";
18504
21560
  async function setupClaudeConfigDir(cwd, blocklist) {
18505
- const cfgDir = join3(cwd, ".claude-config");
18506
- await mkdir4(cfgDir, { recursive: true });
21561
+ const cfgDir = join6(cwd, ".claude-config");
21562
+ await mkdir7(cfgDir, { recursive: true });
18507
21563
  await mirrorClaudeHome(cfgDir);
18508
21564
  await rebuildSkills(cfgDir, blocklist);
18509
21565
  return cfgDir;
@@ -18517,11 +21573,11 @@ async function mirrorClaudeHome(cfgDir) {
18517
21573
  }
18518
21574
  for (const entry of entries) {
18519
21575
  if (entry === "skills") continue;
18520
- const dst = join3(cfgDir, entry);
21576
+ const dst = join6(cfgDir, entry);
18521
21577
  await rm2(dst, { recursive: true, force: true }).catch(() => {
18522
21578
  });
18523
21579
  try {
18524
- await symlink(join3(CLAUDE_HOME, entry), dst);
21580
+ await symlink(join6(CLAUDE_HOME, entry), dst);
18525
21581
  } catch (e) {
18526
21582
  process.stderr.write(
18527
21583
  ` ! claude-config symlink ${entry} failed (non-fatal): ${e.message}
@@ -18531,11 +21587,11 @@ async function mirrorClaudeHome(cfgDir) {
18531
21587
  }
18532
21588
  }
18533
21589
  async function rebuildSkills(cfgDir, blocklist) {
18534
- const dst = join3(cfgDir, "skills");
21590
+ const dst = join6(cfgDir, "skills");
18535
21591
  await rm2(dst, { recursive: true, force: true }).catch(() => {
18536
21592
  });
18537
- await mkdir4(dst, { recursive: true });
18538
- const src = join3(CLAUDE_HOME, "skills");
21593
+ await mkdir7(dst, { recursive: true });
21594
+ const src = join6(CLAUDE_HOME, "skills");
18539
21595
  let ids = [];
18540
21596
  try {
18541
21597
  ids = await readdir(src);
@@ -18545,7 +21601,7 @@ async function rebuildSkills(cfgDir, blocklist) {
18545
21601
  for (const id of ids) {
18546
21602
  if (id.startsWith(".")) continue;
18547
21603
  if (blocklist.has(id)) continue;
18548
- await symlink(join3(src, id), join3(dst, id)).catch((e) => {
21604
+ await symlink(join6(src, id), join6(dst, id)).catch((e) => {
18549
21605
  process.stderr.write(
18550
21606
  ` ! claude-config skill symlink ${id} failed (non-fatal): ${e.message}
18551
21607
  `
@@ -18557,11 +21613,12 @@ var CLAUDE_HOME;
18557
21613
  var init_claude_config_dir = __esm({
18558
21614
  "src/bridge/lib/claude-config-dir.ts"() {
18559
21615
  "use strict";
18560
- CLAUDE_HOME = join3(homedir2(), ".claude");
21616
+ CLAUDE_HOME = join6(homedir3(), ".claude");
18561
21617
  }
18562
21618
  });
18563
21619
 
18564
21620
  // src/bridge/lib/session-manager.ts
21621
+ import { spawn as childSpawn } from "node:child_process";
18565
21622
  function scrubAcpSpawnEnv(base) {
18566
21623
  return {
18567
21624
  ...base,
@@ -18585,6 +21642,11 @@ var init_session_manager = __esm({
18585
21642
  #runtime = new AcpRuntimeImpl(this.#spawner);
18586
21643
  #sessions = /* @__PURE__ */ new Map();
18587
21644
  #env = { apiKey: "", apiUrl: "", runtimeToken: "" };
21645
+ /** Set by `drain()` to refuse new session.start while in-flight turns
21646
+ * finish. Existing sessions keep accepting prompts so a user mid-turn
21647
+ * doesn't hit "session not ready" mid-stream just because the daemon
21648
+ * is on its way out. */
21649
+ #draining = false;
18588
21650
  constructor(send) {
18589
21651
  this.#send = send;
18590
21652
  }
@@ -18597,6 +21659,18 @@ var init_session_manager = __esm({
18597
21659
  has(session_id) {
18598
21660
  return this.#sessions.has(session_id);
18599
21661
  }
21662
+ /** Sum of in-flight turns across all sessions. A turn registers itself
21663
+ * in `sess.turns` when `prompt()` starts and removes itself in the
21664
+ * finally block when the ACP child finishes streaming. drain() polls
21665
+ * this to know when it's safe to exit. */
21666
+ activeTurnCount() {
21667
+ let n = 0;
21668
+ for (const s of this.#sessions.values()) n += s.turns.size;
21669
+ return n;
21670
+ }
21671
+ sessionCount() {
21672
+ return this.#sessions.size;
21673
+ }
18600
21674
  /** Re-announce alive sessions to the server (used after WS reconnect). */
18601
21675
  announceAll() {
18602
21676
  for (const [session_id, sess] of this.#sessions) {
@@ -18604,6 +21678,15 @@ var init_session_manager = __esm({
18604
21678
  }
18605
21679
  }
18606
21680
  async start(p) {
21681
+ if (this.#draining) {
21682
+ this.#send({
21683
+ type: "session.error",
21684
+ session_id: p.session_id,
21685
+ turn_id: "",
21686
+ message: "daemon draining for restart \u2014 retry in a few seconds"
21687
+ });
21688
+ return;
21689
+ }
18607
21690
  const existing = this.#sessions.get(p.session_id);
18608
21691
  if (existing) {
18609
21692
  this.#send({
@@ -18613,7 +21696,7 @@ var init_session_manager = __esm({
18613
21696
  });
18614
21697
  return;
18615
21698
  }
18616
- const agent = KNOWN_ACP_AGENTS.find((a) => a.id === p.agent_id);
21699
+ const agent = resolveKnownAgent(p.agent_id);
18617
21700
  if (!agent) {
18618
21701
  this.#send({
18619
21702
  type: "session.error",
@@ -18622,12 +21705,32 @@ var init_session_manager = __esm({
18622
21705
  });
18623
21706
  return;
18624
21707
  }
21708
+ if (agent.id !== p.agent_id) {
21709
+ process.stderr.write(
21710
+ ` \u21AA canonicalized acp_agent_id ${p.agent_id} \u2192 ${agent.id} (legacy alias)
21711
+ `
21712
+ );
21713
+ }
21714
+ const onPath = await new Promise((resolve) => {
21715
+ const probe = process.platform === "win32" ? "where" : "which";
21716
+ const p2 = childSpawn(probe, [agent.spec.command], { stdio: "ignore" });
21717
+ p2.once("error", () => resolve(false));
21718
+ p2.once("exit", (code) => resolve(code === 0));
21719
+ });
21720
+ if (!onPath) {
21721
+ this.#send({
21722
+ type: "session.error",
21723
+ session_id: p.session_id,
21724
+ message: `binary not on PATH for ${agent.id}: \`${agent.spec.command}\`` + (agent.installHint ? `. Install: ${agent.installHint}` : "")
21725
+ });
21726
+ return;
21727
+ }
18625
21728
  const sessionCwd = await ensureSessionCwd(p.session_id);
18626
21729
  let blocklist = [];
18627
21730
  let bundleMcpServers = [];
18628
21731
  let bundleEnv = [];
18629
21732
  try {
18630
- const bundle = await this.#fetchBundle(p.session_id, p.agent_id);
21733
+ const bundle = await this.#fetchBundle(p.session_id, agent.id);
18631
21734
  if (bundle) {
18632
21735
  await writeBundle(sessionCwd, bundle.files);
18633
21736
  blocklist = bundle.local_skill_blocklist ?? [];
@@ -18639,7 +21742,7 @@ var init_session_manager = __esm({
18639
21742
  `);
18640
21743
  }
18641
21744
  const extraEnv = {};
18642
- if (p.agent_id === "claude-agent-acp") {
21745
+ if (agent.id === "claude-acp") {
18643
21746
  try {
18644
21747
  const cfgDir = await setupClaudeConfigDir(sessionCwd, new Set(blocklist));
18645
21748
  extraEnv.CLAUDE_CONFIG_DIR = cfgDir;
@@ -18760,6 +21863,66 @@ var init_session_manager = __esm({
18760
21863
  const ids = [...this.#sessions.keys()];
18761
21864
  await Promise.all(ids.map((id) => this.#killChild(id)));
18762
21865
  }
21866
+ /**
21867
+ * Graceful drain for upgrade/restart. Caller (daemon SIGTERM handler)
21868
+ * awaits this before exiting so in-flight ACP turns get to finish
21869
+ * naturally instead of being SIGTERM'd mid-stream.
21870
+ *
21871
+ * Recovery model — mirrors the cloud agent's DO-eviction recovery
21872
+ * (apps/agent/src/runtime/turn-runtime.ts:268 recoverAgentTurn):
21873
+ *
21874
+ * 1. Set #draining → start() rejects new sessions; server retries.
21875
+ * 2. Poll activeTurnCount every 200ms until either:
21876
+ * - all turns drained naturally (clean session.complete) → break
21877
+ * - deadline elapsed → abort remaining turns. Their prompt()
21878
+ * loops unwind, emit session.error, and the ACP children
21879
+ * checkpoint their conversation state to disk (each ACP
21880
+ * implementation owns its own persistence; e.g. claude-acp
21881
+ * stores into ~/.claude/projects/...).
21882
+ * 3. disposeAll() — KEEPS spawn cwds. Same shape as a clean
21883
+ * shutdown.
21884
+ *
21885
+ * The next time the server sends session.start for any of these ids
21886
+ * it includes `resume.acp_session_id`. The new daemon respawns a
21887
+ * fresh ACP child in the preserved cwd and calls session/load to
21888
+ * restore conversation history (session-manager.ts:311 →
21889
+ * session.ts:108). Worst case the user re-prompts the cut-off turn;
21890
+ * partial response on their screen is the only artifact.
21891
+ *
21892
+ * Idempotent: a second call while one is in progress no-ops past the
21893
+ * existing drain.
21894
+ */
21895
+ async drain(deadlineMs, opts) {
21896
+ if (this.#draining) {
21897
+ const t02 = Date.now();
21898
+ while (this.#sessions.size > 0 && Date.now() - t02 < deadlineMs) {
21899
+ await new Promise((r) => setTimeout(r, 200));
21900
+ }
21901
+ return { initialTurns: 0, abortedTurns: 0, sessions: 0 };
21902
+ }
21903
+ this.#draining = true;
21904
+ const initialTurns = this.activeTurnCount();
21905
+ const initialSessions = this.#sessions.size;
21906
+ const t0 = Date.now();
21907
+ while (this.activeTurnCount() > 0) {
21908
+ const elapsed = Date.now() - t0;
21909
+ if (elapsed >= deadlineMs) break;
21910
+ opts?.onProgress?.(this.activeTurnCount(), deadlineMs - elapsed);
21911
+ await new Promise((r) => setTimeout(r, 200));
21912
+ }
21913
+ let aborted2 = 0;
21914
+ for (const sess of this.#sessions.values()) {
21915
+ for (const ctrl of sess.turns.values()) {
21916
+ ctrl.abort();
21917
+ aborted2 += 1;
21918
+ }
21919
+ }
21920
+ if (aborted2 > 0) {
21921
+ await new Promise((r) => setTimeout(r, 2e3));
21922
+ }
21923
+ await this.disposeAll();
21924
+ return { initialTurns, abortedTurns: aborted2, sessions: initialSessions };
21925
+ }
18763
21926
  /** Kill the ACP child + drop in-memory state. Does NOT touch the spawn
18764
21927
  * cwd — caller decides whether the cwd should outlive this. */
18765
21928
  async #killChild(session_id) {
@@ -18788,27 +21951,34 @@ var init_session_manager = __esm({
18788
21951
  });
18789
21952
 
18790
21953
  // src/bridge/lib/local-skills.ts
18791
- import { readdir as readdir2, readFile as readFile3, stat } from "node:fs/promises";
18792
- import { join as join4 } from "node:path";
18793
- import { homedir as homedir3 } from "node:os";
21954
+ import { readdir as readdir2, readFile as readFile6, stat } from "node:fs/promises";
21955
+ import { join as join7 } from "node:path";
21956
+ import { homedir as homedir4 } from "node:os";
18794
21957
  async function detectLocalSkills() {
18795
- return {
18796
- "claude-agent-acp": await detectClaudeCodeSkills()
18797
- };
21958
+ const [claude, gemini, opencode] = await Promise.all([
21959
+ detectClaudeCodeSkills(),
21960
+ detectGeminiExtensions(),
21961
+ detectOpencodeAgents()
21962
+ ]);
21963
+ const out = {};
21964
+ if (claude.length) out["claude-acp"] = claude;
21965
+ if (gemini.length) out["gemini"] = gemini;
21966
+ if (opencode.length) out["opencode"] = opencode;
21967
+ return out;
18798
21968
  }
18799
21969
  async function detectClaudeCodeSkills() {
18800
21970
  const seen = /* @__PURE__ */ new Map();
18801
- for (const skill of await scanSkillsDir(join4(HOME, ".claude", "skills"), "global")) {
21971
+ for (const skill of await scanSkillsDir(join7(HOME, ".claude", "skills"), "global")) {
18802
21972
  seen.set(skill.id, skill);
18803
21973
  }
18804
- const pluginsRoot = join4(HOME, ".claude", "plugins");
21974
+ const pluginsRoot = join7(HOME, ".claude", "plugins");
18805
21975
  let plugins = [];
18806
21976
  try {
18807
21977
  plugins = await readdir2(pluginsRoot);
18808
21978
  } catch {
18809
21979
  }
18810
21980
  for (const plugin of plugins) {
18811
- const pluginSkillsDir = join4(pluginsRoot, plugin, "skills");
21981
+ const pluginSkillsDir = join7(pluginsRoot, plugin, "skills");
18812
21982
  for (const skill of await scanSkillsDir(pluginSkillsDir, "plugin", plugin)) {
18813
21983
  const key = `${plugin}/${skill.id}`;
18814
21984
  seen.set(key, skill);
@@ -18826,7 +21996,7 @@ async function scanSkillsDir(dir, source, source_label) {
18826
21996
  const out = [];
18827
21997
  for (const id of entries) {
18828
21998
  if (id.startsWith(".")) continue;
18829
- const skillDir = join4(dir, id);
21999
+ const skillDir = join7(dir, id);
18830
22000
  let st;
18831
22001
  try {
18832
22002
  st = await stat(skillDir);
@@ -18834,7 +22004,7 @@ async function scanSkillsDir(dir, source, source_label) {
18834
22004
  continue;
18835
22005
  }
18836
22006
  if (!st.isDirectory()) continue;
18837
- const meta = await readSkillMeta(join4(skillDir, "SKILL.md"));
22007
+ const meta = await readSkillMeta(join7(skillDir, "SKILL.md"));
18838
22008
  out.push({
18839
22009
  id,
18840
22010
  name: meta.name ?? id,
@@ -18849,7 +22019,7 @@ async function scanSkillsDir(dir, source, source_label) {
18849
22019
  async function readSkillMeta(file2) {
18850
22020
  let text;
18851
22021
  try {
18852
- text = await readFile3(file2, "utf-8");
22022
+ text = await readFile6(file2, "utf-8");
18853
22023
  } catch {
18854
22024
  return {};
18855
22025
  }
@@ -18873,11 +22043,89 @@ async function readSkillMeta(file2) {
18873
22043
  }
18874
22044
  return { name, description };
18875
22045
  }
22046
+ async function detectGeminiExtensions() {
22047
+ const root = join7(HOME, ".gemini", "extensions");
22048
+ let entries;
22049
+ try {
22050
+ entries = await readdir2(root);
22051
+ } catch {
22052
+ return [];
22053
+ }
22054
+ const out = [];
22055
+ for (const id of entries) {
22056
+ if (id.startsWith(".")) continue;
22057
+ const extDir = join7(root, id);
22058
+ let st;
22059
+ try {
22060
+ st = await stat(extDir);
22061
+ } catch {
22062
+ continue;
22063
+ }
22064
+ if (!st.isDirectory()) continue;
22065
+ let manifest = {};
22066
+ try {
22067
+ const raw = await readFile6(join7(extDir, "gemini-extension.json"), "utf-8");
22068
+ manifest = JSON.parse(raw);
22069
+ } catch {
22070
+ continue;
22071
+ }
22072
+ let description = manifest.description;
22073
+ if (!description) {
22074
+ const ctxName = manifest.contextFileName ?? "GEMINI.md";
22075
+ const meta = await readSkillMeta(join7(extDir, ctxName));
22076
+ description = meta.description;
22077
+ }
22078
+ out.push({
22079
+ id,
22080
+ name: manifest.name ?? id,
22081
+ description,
22082
+ source: "global",
22083
+ path: extDir
22084
+ });
22085
+ }
22086
+ return out;
22087
+ }
22088
+ async function detectOpencodeAgents() {
22089
+ const seen = /* @__PURE__ */ new Map();
22090
+ const dirs = [
22091
+ join7(HOME, ".opencode", "agents"),
22092
+ join7(HOME, ".config", "opencode", "agents")
22093
+ ];
22094
+ for (const dir of dirs) {
22095
+ let entries;
22096
+ try {
22097
+ entries = await readdir2(dir);
22098
+ } catch {
22099
+ continue;
22100
+ }
22101
+ for (const file2 of entries) {
22102
+ if (!file2.endsWith(".md") || file2.startsWith(".")) continue;
22103
+ const id = file2.slice(0, -3);
22104
+ const path2 = join7(dir, file2);
22105
+ let st;
22106
+ try {
22107
+ st = await stat(path2);
22108
+ } catch {
22109
+ continue;
22110
+ }
22111
+ if (!st.isFile()) continue;
22112
+ const meta = await readSkillMeta(path2);
22113
+ seen.set(id, {
22114
+ id,
22115
+ name: meta.name ?? id,
22116
+ description: meta.description,
22117
+ source: "global",
22118
+ path: path2
22119
+ });
22120
+ }
22121
+ }
22122
+ return [...seen.values()];
22123
+ }
18876
22124
  var HOME;
18877
22125
  var init_local_skills = __esm({
18878
22126
  "src/bridge/lib/local-skills.ts"() {
18879
22127
  "use strict";
18880
- HOME = homedir3();
22128
+ HOME = homedir4();
18881
22129
  }
18882
22130
  });
18883
22131
 
@@ -18887,6 +22135,8 @@ __export(daemon_exports, {
18887
22135
  runDaemon: () => runDaemon
18888
22136
  });
18889
22137
  import { hostname as hostname3 } from "node:os";
22138
+ import { join as join8 } from "node:path";
22139
+ import { mkdirSync as mkdirSync2, writeFileSync, unlinkSync as unlinkSync2 } from "node:fs";
18890
22140
  async function runDaemon() {
18891
22141
  const creds = await readCreds();
18892
22142
  if (!creds) {
@@ -18895,25 +22145,108 @@ async function runDaemon() {
18895
22145
  );
18896
22146
  process.exit(2);
18897
22147
  }
18898
- printBanner(`daemon \u2014 runtime ${creds.runtimeId.slice(0, 8)}\u2026 \u2192 ${creds.serverUrl}`, PKG_VERSION);
22148
+ const profile = currentProfile();
22149
+ const profileTag = profile ? ` [profile=${profile}]` : "";
22150
+ printBanner(`daemon \u2014 runtime ${creds.runtimeId.slice(0, 8)}\u2026 \u2192 ${creds.serverUrl}${profileTag}`, PKG_VERSION);
22151
+ const cachePath = join8(paths().configDir, "registry-cache.json");
22152
+ await loadRegistry({ cachePath });
18899
22153
  const wsBase = creds.serverUrl.replace(/^http(s?):\/\//, "ws$1://").replace(/\/$/, "");
18900
22154
  const wsUrl = `${wsBase}/agents/runtime/_attach`;
18901
22155
  let backoffMs = RECONNECT_BACKOFF_MIN_MS;
22156
+ const DRAIN_DEADLINE_MS = 1e4;
22157
+ let draining = false;
18902
22158
  let stopping = false;
18903
- const stop = (sig) => {
22159
+ const stop = (sig, force = false) => {
18904
22160
  if (stopping) return;
18905
- stopping = true;
18906
- log.step(`${sig} received, shutting down`);
18907
- void sessions.disposeAll();
18908
- if (currentWs) {
22161
+ if (draining && !force) {
22162
+ log.warn(`${sig} again \u2014 abandoning drain, exiting now`);
22163
+ stopping = true;
18909
22164
  try {
18910
- currentWs.close(1e3, "shutdown");
22165
+ unlinkSync2(join8(paths().configDir, "daemon.pid"));
18911
22166
  } catch {
18912
22167
  }
22168
+ void sessions.disposeAll();
22169
+ if (currentWs) {
22170
+ try {
22171
+ currentWs.close(1e3, "shutdown");
22172
+ } catch {
22173
+ }
22174
+ }
22175
+ return;
22176
+ }
22177
+ draining = true;
22178
+ log.step(`${sig} received, draining (${DRAIN_DEADLINE_MS / 1e3}s deadline; sessions recover via session/load on reconnect)`);
22179
+ try {
22180
+ unlinkSync2(join8(paths().configDir, "daemon.pid"));
22181
+ } catch {
18913
22182
  }
22183
+ void (async () => {
22184
+ const r = await sessions.drain(DRAIN_DEADLINE_MS, {
22185
+ onProgress: (active, msLeft) => {
22186
+ log.hint(`${active} turns active, ${Math.ceil(msLeft / 1e3)}s left`);
22187
+ }
22188
+ }).catch((e) => {
22189
+ log.err(`drain failed: ${e.message}`);
22190
+ return { initialTurns: 0, abortedTurns: 0, sessions: 0 };
22191
+ });
22192
+ const naturallyCompleted = r.initialTurns - r.abortedTurns;
22193
+ if (r.abortedTurns > 0) {
22194
+ log.warn(
22195
+ `deadline reached \u2014 aborted ${r.abortedTurns} in-flight turn(s); they'll resume via ACP session/load when the server reconnects`
22196
+ );
22197
+ }
22198
+ log.ok(
22199
+ `drained ${r.sessions} session(s) (${naturallyCompleted}/${r.initialTurns} turns completed cleanly)`
22200
+ );
22201
+ stopping = true;
22202
+ if (currentWs) {
22203
+ try {
22204
+ currentWs.close(1e3, "shutdown");
22205
+ } catch {
22206
+ }
22207
+ }
22208
+ })();
18914
22209
  };
18915
22210
  process.on("SIGTERM", () => stop("SIGTERM"));
18916
22211
  process.on("SIGINT", () => stop("SIGINT"));
22212
+ try {
22213
+ mkdirSync2(paths().configDir, { recursive: true });
22214
+ writeFileSync(join8(paths().configDir, "daemon.pid"), String(process.pid), "utf-8");
22215
+ } catch (e) {
22216
+ process.stderr.write(`! pid file write failed (non-fatal): ${e.message}
22217
+ `);
22218
+ }
22219
+ process.on("SIGHUP", () => {
22220
+ void (async () => {
22221
+ log.step("SIGHUP \u2014 refreshing agent detection");
22222
+ try {
22223
+ await loadRegistry({ cachePath, forceRefresh: true });
22224
+ const agents = (await detectAll()).map((a) => ({ id: a.id, binary: a.spec.command }));
22225
+ const localSkillsDetailed = await detectLocalSkills();
22226
+ const localSkills = {};
22227
+ for (const [agentId, skills] of Object.entries(localSkillsDetailed)) {
22228
+ if (!skills) continue;
22229
+ localSkills[agentId] = skills.map(({ path: _path, ...rest }) => rest);
22230
+ }
22231
+ if (currentWs && currentWs.readyState === wrapper_default.OPEN) {
22232
+ currentWs.send(JSON.stringify({
22233
+ type: "hello",
22234
+ machine_id: creds.machineId,
22235
+ hostname: hostname3(),
22236
+ os: osTag(),
22237
+ version: PKG_VERSION,
22238
+ agents,
22239
+ local_skills: localSkills
22240
+ }));
22241
+ log.ok(`re-published manifest (${agents.length} agents)`);
22242
+ } else {
22243
+ log.warn("WS not attached \u2014 manifest will be re-sent on next connect");
22244
+ }
22245
+ } catch (e) {
22246
+ log.warn(`refresh failed: ${e.message}`);
22247
+ }
22248
+ })();
22249
+ });
18917
22250
  let currentWs = null;
18918
22251
  const sessions = new SessionManager(() => {
18919
22252
  });
@@ -19060,7 +22393,9 @@ __export(status_exports, {
19060
22393
  runStatus: () => runStatus
19061
22394
  });
19062
22395
  async function runStatus() {
19063
- printBanner("status", PKG_VERSION);
22396
+ const profile = currentProfile();
22397
+ const profileTag = profile ? ` [profile=${profile}]` : "";
22398
+ printBanner(`status${profileTag}`, PKG_VERSION);
19064
22399
  const p = paths();
19065
22400
  const creds = await readCreds();
19066
22401
  if (!creds) {
@@ -19068,6 +22403,7 @@ async function runStatus() {
19068
22403
  log.hint(`looked for ${p.credsFile}`);
19069
22404
  process.exit(1);
19070
22405
  }
22406
+ const kind = detectServiceKind();
19071
22407
  const row = (k, v) => process.stderr.write(` ${c.dim(k.padEnd(11))} ${v}
19072
22408
  `);
19073
22409
  row("server", creds.serverUrl);
@@ -19076,7 +22412,7 @@ async function runStatus() {
19076
22412
  row("registered", new Date(creds.createdAt * 1e3).toISOString());
19077
22413
  row("creds file", c.dim(p.credsFile));
19078
22414
  row("log file", c.dim(p.logFile));
19079
- if (p.serviceFile) row("service", c.dim(p.serviceFile));
22415
+ row("service", c.dim(`${kind}${p.serviceFile ? ` \u2192 ${p.serviceFile}` : ""}`));
19080
22416
  process.stderr.write("\n");
19081
22417
  log.step("probing server");
19082
22418
  const probe = await probeRuntimeToken(creds.serverUrl, creds.token);
@@ -19101,6 +22437,7 @@ var init_status = __esm({
19101
22437
  "use strict";
19102
22438
  init_config();
19103
22439
  init_platform();
22440
+ init_service_manager();
19104
22441
  init_style();
19105
22442
  init_version();
19106
22443
  init_probe();
@@ -19114,15 +22451,15 @@ __export(uninstall_exports, {
19114
22451
  });
19115
22452
  async function runUninstall() {
19116
22453
  printBanner("uninstall \u2014 remove daemon + local credentials", PKG_VERSION);
19117
- if (currentPlatform() === "darwin") {
19118
- try {
19119
- const r = await uninstall();
19120
- if (r.removed) log.ok(`launchd plist removed ${c.dim(paths().serviceFile ?? "")}`);
19121
- else process.stderr.write(`${sym.dot()} ${c.dim("launchd plist not present")}
22454
+ try {
22455
+ const r = await uninstall4();
22456
+ const tag = r.kind === "launchd" ? "launchd plist" : r.kind === "systemd" ? "systemd unit" : r.kind === "windows-task" ? "Task Scheduler task" : "service";
22457
+ if (r.removed) log.ok(`${tag} removed ${c.dim(paths().serviceFile ?? paths().configDir)}`);
22458
+ else process.stderr.write(`${sym.dot()} ${c.dim(`${tag} not present`)}
19122
22459
  `);
19123
- } catch (e) {
19124
- log.warn(`launchd uninstall failed: ${e instanceof Error ? e.message : String(e)}`);
19125
- }
22460
+ if (r.warning) log.hint(c.dim(r.warning));
22461
+ } catch (e) {
22462
+ log.warn(`service uninstall failed: ${e instanceof Error ? e.message : String(e)}`);
19126
22463
  }
19127
22464
  const creds = await readCreds();
19128
22465
  if (creds) {
@@ -19157,7 +22494,7 @@ ${c.bold("Done.")}
19157
22494
  var init_uninstall = __esm({
19158
22495
  "src/bridge/commands/uninstall.ts"() {
19159
22496
  "use strict";
19160
- init_launchd();
22497
+ init_service_manager();
19161
22498
  init_config();
19162
22499
  init_platform();
19163
22500
  init_style();
@@ -19165,17 +22502,87 @@ var init_uninstall = __esm({
19165
22502
  }
19166
22503
  });
19167
22504
 
22505
+ // src/bridge/commands/agents.ts
22506
+ var agents_exports = {};
22507
+ __export(agents_exports, {
22508
+ runAgents: () => runAgents
22509
+ });
22510
+ import { readFileSync, statSync } from "node:fs";
22511
+ import { join as join9 } from "node:path";
22512
+ async function runAgents(args) {
22513
+ const sub = args[0] ?? "";
22514
+ switch (sub) {
22515
+ case "refresh":
22516
+ await refresh(args.slice(1));
22517
+ return;
22518
+ default:
22519
+ process.stderr.write(
22520
+ "oma bridge agents \u2014 manage local agent detection\n\n oma bridge agents refresh [--yes] re-scan + offer-install missing ACP wrappers + signal daemon\n"
22521
+ );
22522
+ process.exit(sub ? 1 : 0);
22523
+ }
22524
+ }
22525
+ async function refresh(args) {
22526
+ const profile = currentProfile();
22527
+ const profileTag = profile ? ` [profile=${profile}]` : "";
22528
+ const yes = args.includes("--yes") || args.includes("-y");
22529
+ const cachePath = join9(paths().configDir, "registry-cache.json");
22530
+ await loadRegistry({ cachePath, forceRefresh: true });
22531
+ const detected = (await detectAll()).map((a) => ({ id: a.id, binary: a.spec.command }));
22532
+ await auditAndOfferWrappers(detected, { yes });
22533
+ const pidFile = join9(paths().configDir, "daemon.pid");
22534
+ let pid = 0;
22535
+ try {
22536
+ pid = parseInt(readFileSync(pidFile, "utf-8").trim(), 10);
22537
+ if (!Number.isFinite(pid) || pid <= 0) pid = 0;
22538
+ if (pid) process.kill(pid, 0);
22539
+ } catch {
22540
+ pid = 0;
22541
+ }
22542
+ if (pid === 0) {
22543
+ log.hint(`no running daemon${profileTag}; manifest will reflect on next \`oma bridge daemon\``);
22544
+ return;
22545
+ }
22546
+ try {
22547
+ const ageMs = Date.now() - statSync(pidFile).mtimeMs;
22548
+ if (ageMs > 7 * 24 * 3600 * 1e3) {
22549
+ log.hint(`pid file is ${Math.floor(ageMs / 864e5)} days old`);
22550
+ }
22551
+ } catch {
22552
+ }
22553
+ try {
22554
+ process.kill(pid, "SIGHUP");
22555
+ log.ok(`daemon${profileTag} re-detecting (pid ${pid})`);
22556
+ log.hint("Console dropdown will reflect the new state in 1\u20132s");
22557
+ } catch (e) {
22558
+ log.warn(`signal failed: ${e.message}`);
22559
+ process.exit(2);
22560
+ }
22561
+ }
22562
+ var init_agents = __esm({
22563
+ "src/bridge/commands/agents.ts"() {
22564
+ "use strict";
22565
+ init_platform();
22566
+ init_registry();
22567
+ init_wrapper_audit();
22568
+ init_style();
22569
+ }
22570
+ });
22571
+
19168
22572
  // src/index.ts
22573
+ init_platform();
19169
22574
  import { createServer as createServer2 } from "node:http";
19170
22575
  import { execSync } from "node:child_process";
19171
- import { homedir as homedir4, hostname as hostname4 } from "node:os";
19172
- import { join as join5, dirname as dirname4 } from "node:path";
19173
- import { mkdirSync, readFileSync, writeFileSync, unlinkSync, existsSync, chmodSync } from "node:fs";
19174
- import { randomBytes as randomBytes2 } from "node:crypto";
22576
+ import { homedir as homedir5, hostname as hostname4 } from "node:os";
22577
+ import { join as join10, dirname as dirname9 } from "node:path";
22578
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync3, existsSync as existsSync2, chmodSync as chmodSync2 } from "node:fs";
22579
+ import { randomBytes as randomBytes3 } from "node:crypto";
19175
22580
  function credentialsPath() {
19176
22581
  const xdg = process.env.XDG_CONFIG_HOME;
19177
- const base = xdg && xdg.length > 0 ? xdg : join5(homedir4(), ".config");
19178
- return join5(base, "oma", "credentials.json");
22582
+ const base = xdg && xdg.length > 0 ? xdg : join10(homedir5(), ".config");
22583
+ const profile = currentProfile();
22584
+ const file2 = profile ? `credentials.${profile}.json` : "credentials.json";
22585
+ return join10(base, "oma", file2);
19179
22586
  }
19180
22587
  function migrateV1ToV2(v1) {
19181
22588
  return {
@@ -19195,10 +22602,10 @@ function migrateV1ToV2(v1) {
19195
22602
  };
19196
22603
  }
19197
22604
  function readCredentials() {
19198
- const path = credentialsPath();
22605
+ const path2 = credentialsPath();
19199
22606
  try {
19200
- if (!existsSync(path)) return null;
19201
- const raw = readFileSync(path, "utf8");
22607
+ if (!existsSync2(path2)) return null;
22608
+ const raw = readFileSync2(path2, "utf8");
19202
22609
  const parsed = JSON.parse(raw);
19203
22610
  if (parsed.version === 2) return parsed;
19204
22611
  if (parsed.version === 1) {
@@ -19215,18 +22622,18 @@ function readCredentials() {
19215
22622
  }
19216
22623
  }
19217
22624
  function writeCredentials(creds) {
19218
- const path = credentialsPath();
19219
- mkdirSync(dirname4(path), { recursive: true, mode: 448 });
19220
- writeFileSync(path, JSON.stringify(creds, null, 2), { mode: 384 });
22625
+ const path2 = credentialsPath();
22626
+ mkdirSync3(dirname9(path2), { recursive: true, mode: 448 });
22627
+ writeFileSync2(path2, JSON.stringify(creds, null, 2), { mode: 384 });
19221
22628
  try {
19222
- chmodSync(path, 384);
22629
+ chmodSync2(path2, 384);
19223
22630
  } catch {
19224
22631
  }
19225
22632
  }
19226
22633
  function clearCredentials() {
19227
- const path = credentialsPath();
19228
- if (!existsSync(path)) return false;
19229
- unlinkSync(path);
22634
+ const path2 = credentialsPath();
22635
+ if (!existsSync2(path2)) return false;
22636
+ unlinkSync3(path2);
19230
22637
  return true;
19231
22638
  }
19232
22639
  function loadConfig() {
@@ -19291,8 +22698,8 @@ async function fetchWithRetry(url2, init, maxRetries = 3) {
19291
22698
  attempt += 1;
19292
22699
  }
19293
22700
  }
19294
- async function apiFetch(config2, path, init) {
19295
- const url2 = `${config2.baseUrl}${path}`;
22701
+ async function apiFetch(config2, path2, init) {
22702
+ const url2 = `${config2.baseUrl}${path2}`;
19296
22703
  const res = await fetchWithRetry(url2, {
19297
22704
  ...init,
19298
22705
  headers: {
@@ -19312,8 +22719,8 @@ async function apiFetch(config2, path, init) {
19312
22719
  }
19313
22720
  return res.json();
19314
22721
  }
19315
- async function rawStream(config2, path, init) {
19316
- const res = await fetchWithRetry(`${config2.baseUrl}${path}`, {
22722
+ async function rawStream(config2, path2, init) {
22723
+ const res = await fetchWithRetry(`${config2.baseUrl}${path2}`, {
19317
22724
  ...init,
19318
22725
  headers: {
19319
22726
  "x-api-key": config2.apiKey,
@@ -19456,7 +22863,7 @@ function table(rows) {
19456
22863
  if (!rows.length) return;
19457
22864
  const widths = rows[0].map((_, i) => Math.max(...rows.map((r) => (r[i] || "").length)));
19458
22865
  for (const row of rows) {
19459
- console.log(row.map((c2, i) => (c2 || "").padEnd(widths[i])).join(" "));
22866
+ console.log(row.map((c3, i) => (c3 || "").padEnd(widths[i])).join(" "));
19460
22867
  }
19461
22868
  }
19462
22869
  function capsPreview(caps) {
@@ -19476,7 +22883,7 @@ function isPubliclyReachable(url2) {
19476
22883
  }
19477
22884
  }
19478
22885
  async function authLogin(baseUrl, requestedTenant) {
19479
- const state = randomBytes2(16).toString("hex");
22886
+ const state = randomBytes3(16).toString("hex");
19480
22887
  const port = 19500 + Math.floor(Math.random() * 500);
19481
22888
  const callback = `http://127.0.0.1:${port}/callback`;
19482
22889
  const params = new URLSearchParams({
@@ -20000,7 +23407,7 @@ Version: v${a.version}`);
20000
23407
  console.log("No model cards. Create one with: oma models create");
20001
23408
  return;
20002
23409
  }
20003
- table([["NAME", "PROVIDER", "MODEL", "KEY", "DEFAULT"], ...data.map((c2) => [c2.name, c2.provider, c2.model_id, `****${c2.api_key_preview || ""}`, c2.is_default ? "yes" : ""])]);
23410
+ table([["NAME", "PROVIDER", "MODEL", "KEY", "DEFAULT"], ...data.map((c3) => [c3.name, c3.provider, c3.model_id, `****${c3.api_key_preview || ""}`, c3.is_default ? "yes" : ""])]);
20004
23411
  }
20005
23412
  },
20006
23413
  {
@@ -20107,7 +23514,7 @@ Save this key \u2014 it won't be shown again.`);
20107
23514
  console.log("No credentials in this vault.");
20108
23515
  return;
20109
23516
  }
20110
- table([["NAME", "TYPE", "DETAIL"], ...data.map((c2) => [c2.display_name, c2.auth.type, c2.auth.mcp_server_url || c2.auth.command_prefixes?.join(", ") || ""])]);
23517
+ table([["NAME", "TYPE", "DETAIL"], ...data.map((c3) => [c3.display_name, c3.auth.type, c3.auth.mcp_server_url || c3.auth.command_prefixes?.join(", ") || ""])]);
20111
23518
  }
20112
23519
  },
20113
23520
  {
@@ -21257,14 +24664,14 @@ Expires in ${r.expiresInDays} days.`);
21257
24664
  http: "POST /v1/memory_stores/:id/memories {path, content, precondition?}",
21258
24665
  async run(config2, args) {
21259
24666
  const storeId = args[0];
21260
- const path = args[1];
24667
+ const path2 = args[1];
21261
24668
  const content = readContentArg(args);
21262
24669
  const sha = flag(args, "--precondition-sha256");
21263
- if (!storeId || !path || content === void 0) {
24670
+ if (!storeId || !path2 || content === void 0) {
21264
24671
  console.error("Usage: oma memory write <store-id> <path> (--content <c> | --from-file <f>) [--precondition-sha256 <h>]");
21265
24672
  process.exit(1);
21266
24673
  }
21267
- const body = { path, content };
24674
+ const body = { path: path2, content };
21268
24675
  if (sha) body.precondition = { type: "content_sha256", content_sha256: sha };
21269
24676
  const mem = await apiFetch(
21270
24677
  config2,
@@ -21345,19 +24752,19 @@ Expires in ${r.expiresInDays} days.`);
21345
24752
  async run(config2, args) {
21346
24753
  const storeId = args[0];
21347
24754
  const memId = args[1];
21348
- const path = flag(args, "--path");
24755
+ const path2 = flag(args, "--path");
21349
24756
  const content = readContentArg(args);
21350
24757
  const sha = flag(args, "--precondition-sha256");
21351
24758
  if (!storeId || !memId) {
21352
24759
  console.error("Usage: oma memory update <store-id> <memory-id> [--path <p>] [--content <c> | --from-file <f>] [--precondition-sha256 <h>]");
21353
24760
  process.exit(1);
21354
24761
  }
21355
- if (path === void 0 && content === void 0) {
24762
+ if (path2 === void 0 && content === void 0) {
21356
24763
  console.error("Pass at least --path or --content/--from-file.");
21357
24764
  process.exit(1);
21358
24765
  }
21359
24766
  const body = {};
21360
- if (path !== void 0) body.path = path;
24767
+ if (path2 !== void 0) body.path = path2;
21361
24768
  if (content !== void 0) body.content = content;
21362
24769
  if (sha) body.precondition = { type: "content_sha256", content_sha256: sha };
21363
24770
  const mem = await apiFetch(
@@ -21571,10 +24978,10 @@ async function connectMcp(config2, mcpServerUrl, vaultId) {
21571
24978
  }
21572
24979
  function apiRef(resource) {
21573
24980
  const groups = /* @__PURE__ */ new Map();
21574
- for (const c2 of commands) {
21575
- const list = groups.get(c2.group) || [];
21576
- list.push(` ${c2.http}`);
21577
- groups.set(c2.group, list);
24981
+ for (const c3 of commands) {
24982
+ const list = groups.get(c3.group) || [];
24983
+ list.push(` ${c3.http}`);
24984
+ groups.set(c3.group, list);
21578
24985
  }
21579
24986
  for (const e of extraEndpoints) {
21580
24987
  const list = groups.get(e.group) || [];
@@ -21631,20 +25038,21 @@ oma \u2014 Open Managed Agents CLI
21631
25038
 
21632
25039
  Usage:`);
21633
25040
  let lastGroup = "";
21634
- for (const c2 of commands) {
21635
- if (c2.group !== lastGroup) {
25041
+ for (const c3 of commands) {
25042
+ if (c3.group !== lastGroup) {
21636
25043
  console.log(`
21637
- ${c2.group}:`);
21638
- lastGroup = c2.group;
25044
+ ${c3.group}:`);
25045
+ lastGroup = c3.group;
21639
25046
  }
21640
- console.log(` ${c2.usage.padEnd(42)} ${c2.desc}`);
25047
+ console.log(` ${c3.usage.padEnd(42)} ${c3.desc}`);
21641
25048
  }
21642
25049
  console.log(`
21643
25050
  Bridge (local runtime):
21644
- oma bridge setup [--force] [--no-service] Pair this machine with OMA (one-time OAuth)
21645
- oma bridge daemon Run the bridge in foreground
25051
+ oma bridge setup [--force] [--no-service] Pair this machine with OMA + start daemon
21646
25052
  oma bridge status Show creds + probe server reachability
21647
- oma bridge uninstall Remove launchd service + creds
25053
+ oma bridge agents refresh Re-detect agents + offer wrapper installs
25054
+ oma bridge uninstall Stop service + remove creds
25055
+ (oma bridge daemon Internal: launched by service mgr / debugging)
21648
25056
 
21649
25057
  API Reference:
21650
25058
  oma api Show all HTTP endpoints
@@ -21669,17 +25077,42 @@ async function main() {
21669
25077
  apiRef(args[1]);
21670
25078
  return;
21671
25079
  }
25080
+ for (let i = 0; i < args.length; i++) {
25081
+ if (args[i] === "--profile" && i + 1 < args.length) {
25082
+ process.env.OMA_PROFILE = args[i + 1];
25083
+ args.splice(i, 2);
25084
+ const argvIdx = process.argv.indexOf("--profile");
25085
+ if (argvIdx !== -1) process.argv.splice(argvIdx, 2);
25086
+ break;
25087
+ }
25088
+ const eq = args[i].match(/^--profile=(.+)$/);
25089
+ if (eq) {
25090
+ process.env.OMA_PROFILE = eq[1];
25091
+ args.splice(i, 1);
25092
+ const argvIdx = process.argv.findIndex((a) => a.startsWith("--profile="));
25093
+ if (argvIdx !== -1) process.argv.splice(argvIdx, 1);
25094
+ break;
25095
+ }
25096
+ }
25097
+ try {
25098
+ currentProfile();
25099
+ } catch (e) {
25100
+ console.error(`Error: ${e.message}`);
25101
+ process.exit(2);
25102
+ }
21672
25103
  if (args[0] === "bridge") {
21673
25104
  const sub = args[1] ?? "";
21674
25105
  process.argv.splice(2, 2);
21675
25106
  switch (sub) {
21676
25107
  case "setup": {
25108
+ const serverUrl = flag(args, "--server-url") ?? "https://openma.dev";
21677
25109
  const { runSetup: runSetup2 } = await Promise.resolve().then(() => (init_setup(), setup_exports));
21678
25110
  await runSetup2({
21679
- serverUrl: flag(args, "--server-url") ?? "https://openma.dev",
21680
- browserOrigin: flag(args, "--browser-origin") ?? "https://openma.dev",
25111
+ serverUrl,
25112
+ browserOrigin: flag(args, "--browser-origin") ?? serverUrl,
21681
25113
  noService: args.includes("--no-service"),
21682
- force: args.includes("--force")
25114
+ force: args.includes("--force"),
25115
+ yes: args.includes("--yes") || args.includes("-y")
21683
25116
  });
21684
25117
  return;
21685
25118
  }
@@ -21698,9 +25131,14 @@ async function main() {
21698
25131
  await runUninstall2();
21699
25132
  return;
21700
25133
  }
25134
+ case "agents": {
25135
+ const { runAgents: runAgents2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
25136
+ await runAgents2(args.slice(2));
25137
+ return;
25138
+ }
21701
25139
  default:
21702
25140
  console.error(
21703
- "oma bridge \u2014 pair a local ACP agent with OMA\n\n oma bridge setup [--server-url=\u2026] [--no-service] [--force]\n oma bridge daemon\n oma bridge status\n oma bridge uninstall\n"
25141
+ "oma bridge \u2014 pair a local ACP agent with OMA\n\n oma bridge setup [--server-url=\u2026] [--no-service] [--force] [--yes]\n Pair + install service + start daemon\n oma bridge status Creds + service kind + probe server\n oma bridge agents refresh [--yes] Re-scan + offer-install wrappers + reload\n oma bridge uninstall Stop service + remove creds\n oma bridge daemon (internal \u2014 launched by service mgr / for debug)\n\n Use --profile <name> (or OMA_PROFILE=<name>) to run multiple\n daemons side-by-side (e.g. prod in launchd + staging foreground).\n"
21704
25142
  );
21705
25143
  process.exit(sub ? 1 : 0);
21706
25144
  }
@@ -21711,15 +25149,15 @@ async function main() {
21711
25149
  const config2 = isPreAuth ? loadConfigOptional() : loadConfig();
21712
25150
  config2.json = wantJson;
21713
25151
  let needsArgMatch = null;
21714
- for (const c2 of commands) {
21715
- const verbMatch = c2.match.every((tok, i) => args[i] === tok);
25152
+ for (const c3 of commands) {
25153
+ const verbMatch = c3.match.every((tok, i) => args[i] === tok);
21716
25154
  if (!verbMatch) continue;
21717
- if (c2.needsArg && !args[c2.match.length]) {
21718
- needsArgMatch = c2;
25155
+ if (c3.needsArg && !args[c3.match.length]) {
25156
+ needsArgMatch = c3;
21719
25157
  continue;
21720
25158
  }
21721
- const rest = args.slice(c2.match.length);
21722
- return c2.run(config2, rest);
25159
+ const rest = args.slice(c3.match.length);
25160
+ return c3.run(config2, rest);
21723
25161
  }
21724
25162
  if (needsArgMatch) {
21725
25163
  console.error(`${needsArgMatch.usage}