@habemus-papadum/aiui 0.3.0 → 0.5.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.
package/dist/cli.js CHANGED
@@ -1,310 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import { Command as gt } from "commander";
3
- import { join as f, dirname as R, resolve as P, delimiter as bt, relative as yt } from "node:path";
4
- import { CHROME_CHANNELS as vt, cacheDir as Y, packageRoot as L, runningFromSource as kt, isCi as ue, discoverSessionBrowser as F, openInSessionBrowser as H, sessionBrowserBinary as Fe, launchSessionBrowser as Ve, decideBrowserAction as Ct } from "@habemus-papadum/aiui-util";
5
- import { execa as k } from "execa";
6
- import { readFileSync as U, mkdirSync as W, writeFileSync as q, existsSync as v, realpathSync as He, readdirSync as G, accessSync as $t, constants as xt, rmSync as Tt, lstatSync as Pt, cpSync as Et, renameSync as Dt } from "node:fs";
7
- import { detectBrowserPlatform as Ke, resolveBuildId as Ye, Browser as I, getInstalledBrowsers as We, install as It, uninstall as St } from "@puppeteer/browsers";
8
- import { projectCacheDir as de, listMcpServers as J, selectMcpServer as qe } from "@habemus-papadum/aiui-claude-channel";
9
- import { createInterface as Ot } from "node:readline/promises";
10
- import l from "chalk";
11
- import { spawn as jt } from "node:child_process";
12
- import { r as Ut } from "./sidecars-BKlhUA0V.js";
13
- import { homedir as At, networkInterfaces as Nt } from "node:os";
14
- import { Separator as ie, select as K, input as _t } from "@inquirer/prompts";
15
- import { fileURLToPath as Ge } from "node:url";
16
- import { aiuiDevOverlay as Rt } from "@habemus-papadum/aiui-dev-overlay/vite";
17
- import { createServer as Lt } from "vite";
18
- const Mt = ["prompt", "auto", "off"], Bt = ["attach", "launch"], se = ["loopback", "host"], M = [
19
- {
20
- name: "claude",
21
- summary: "how `aiui claude` launches Claude Code",
22
- fields: [
23
- {
24
- key: "skipPermissions",
25
- type: "boolean",
26
- default: !0,
27
- defaultText: "true (unset: the first interactive launch asks, then persists the answer)",
28
- summary: "Launch Claude Code with --dangerously-skip-permissions.",
29
- doc: "A personal preference with real consequences (docs/guide/warning): every agent action — shell commands, file writes, network, the browser — runs without asking first. aiui works fine either way. The first interactive launch asks and persists the answer at the user level; when unset, non-interactive sessions fall back to true."
30
- },
31
- {
32
- key: "enterNudge",
33
- type: "boolean",
34
- default: !0,
35
- defaultText: "true (unset: the first interactive launch asks, then persists the answer)",
36
- summary: "Auto-dismiss Claude Code's development-channel acknowledgement prompt.",
37
- doc: "aiui loads a custom development channel, so Claude Code shows a one-key acknowledgement at every startup; this injects a single Enter keystroke into the terminal to dismiss it (best-effort TIOCSTI on /dev/tty — platforms that forbid it harmlessly do nothing). Saying no just means pressing Enter yourself each launch."
38
- }
39
- ]
40
- },
41
- {
42
- name: "channel",
43
- summary: "the channel server's web backend",
44
- fields: [
45
- {
46
- key: "bind",
47
- type: "enum",
48
- values: se,
49
- default: "loopback",
50
- defaultText: '"loopback" (unset: the first interactive launch asks, then persists the answer)',
51
- summary: "Which interface the channel web server binds: loopback, or host (LAN).",
52
- doc: '"host" (0.0.0.0) makes the session\'s whole web surface — the iPad paint page, but also prompt injection, /debug, and every sidecar — reachable by anyone on your network, UNAUTHENTICATED. That is the trusted-LAN posture (docs/guide/warning): right on a network that is yours alone, wrong on shared Wi-Fi. "loopback" keeps everything this-machine-only; reaching the paint page from an iPad is then up to you — tunnel the channel port however you like (Tailscale, `ssh -L`). The first interactive launch asks and persists the answer at the user level. Per-launch flag: --aiui-bind.'
53
- }
54
- ]
55
- },
56
- {
57
- name: "sidecars",
58
- summary: "which session sidecars `aiui claude` asks the channel to host",
59
- fields: [
60
- {
61
- key: "paint",
62
- type: "boolean",
63
- default: !0,
64
- summary: "Host the iPad paint sidecar (on the channel's own port).",
65
- doc: "The iPad paint stream (docs/guide/paint-stream) rides the channel's one port — no extra process, no extra listener — so it is on by default; false turns it off. Whether an iPad can actually reach it is channel.bind's call (host, or a tunnel you own). Per-launch flags win: --aiui-sidecar paint / --aiui-no-sidecar paint. `aiui paint url` prints the URL to open on the iPad."
66
- }
67
- ]
68
- },
69
- {
70
- name: "chrome",
71
- summary: "the agent's browser and the Chrome DevTools MCP",
72
- fields: [
73
- {
74
- key: "enabled",
75
- type: "boolean",
76
- default: !0,
77
- summary: "Attach the Chrome DevTools MCP.",
78
- doc: "false turns it off everywhere; true restates the default and does NOT override the CI default-off — only the --aiui-chrome flag forces it on under CI."
79
- },
80
- {
81
- key: "mode",
82
- type: "enum",
83
- values: Bt,
84
- default: "attach",
85
- summary: "How the MCP reaches a browser: shared session browser, or its own.",
86
- doc: `"attach" shares a user-visible session browser: an already-running one is discovered by profile, or an interactive launch starts one eagerly. "launch" is the hands-off mode: chrome-devtools-mcp launches its own private browser lazily, on the agent's first browser tool call.`
87
- },
88
- {
89
- key: "browserUrl",
90
- type: "string",
91
- defaultText: "unset (manage a browser locally)",
92
- summary: "Attach to this DevTools endpoint instead of managing a browser at all.",
93
- doc: 'The remote-development key (docs/guide/remote): the browser runs on another machine (started there with `aiui browser`) and its debug port is tunneled over. Setting it implies mode: "attach" and makes every local-browser setting (profile, executablePath, channel, forTesting…) irrelevant. Per-launch flag: --aiui-browser-url.',
94
- validate: (e) => Ft(String(e)) ? void 0 : 'expected an http(s) URL like "http://127.0.0.1:9222"'
95
- },
96
- {
97
- key: "debugPort",
98
- type: "number",
99
- default: 0,
100
- defaultText: "0 (an OS-assigned free port)",
101
- summary: "Fixed DevTools debug port for session browsers aiui launches.",
102
- doc: "Pin it (e.g. 9222) when something external must find the port — an ssh tunnel, a VS Code attach-to-Chrome launch config. 0 means an OS-assigned free port.",
103
- validate: (e) => Number.isInteger(e) && e >= 0 && e <= 65535 ? void 0 : "expected 0..65535"
104
- },
105
- {
106
- key: "profile",
107
- type: "string",
108
- default: "default",
109
- summary: "Named profile under .aiui-cache/chrome/.",
110
- doc: "Per-launch flag: --aiui-chrome-profile."
111
- },
112
- {
113
- key: "dataDir",
114
- type: "string",
115
- defaultText: "unset (derived from chrome.profile)",
116
- summary: "Explicit Chrome user data dir; takes precedence over chrome.profile.",
117
- doc: "Per-launch flag: --aiui-chrome-data-dir."
118
- },
119
- {
120
- key: "executablePath",
121
- type: "string",
122
- defaultText: "unset (managed Chrome for Testing when installed, else installed Chrome)",
123
- summary: "Chrome binary to launch — e.g. a Chrome for Testing install.",
124
- doc: "Chrome for Testing still honors --load-extension, so the aiui DevTools panel can auto-load. Mutually exclusive with chrome.channel."
125
- },
126
- {
127
- key: "channel",
128
- type: "enum",
129
- values: vt,
130
- defaultText: 'unset ("stable" when launching an installed Chrome)',
131
- summary: "Installed Chrome release channel to launch.",
132
- doc: "Mutually exclusive with chrome.executablePath."
133
- },
134
- {
135
- key: "forTesting",
136
- type: "enum",
137
- values: Mt,
138
- default: "prompt",
139
- summary: "How `aiui claude` manages the recommended Chrome for Testing install.",
140
- doc: '"prompt" asks before installing or updating it — interactive sessions only, never under CI; "auto" installs/updates without asking; "off" never checks. Prompt answers ("automatically", "never ask again") persist here at the user level. Skipped entirely when executablePath or channel picks a browser explicitly.'
141
- },
142
- {
143
- key: "headless",
144
- type: "boolean",
145
- default: !1,
146
- summary: "Launch Chrome with no UI."
147
- },
148
- {
149
- key: "buildExtension",
150
- type: "boolean",
151
- default: !0,
152
- summary: "Rebuild the aiui-devtools-extension whenever a browser starts in a dev checkout.",
153
- doc: "~0.3s of tsc so the auto-loaded DevTools panel is never stale. Only relevant in a dev checkout of pdum_aiui."
154
- }
155
- ]
156
- }
157
- ];
158
- function Je() {
159
- return M.flatMap(
160
- (e) => e.fields.map((t) => ({ section: e, field: t, path: `${e.name}.${t.key}` }))
161
- );
162
- }
163
- function ze(e) {
164
- return e.type === "enum" ? "string" : e.type;
165
- }
166
- function Xe(e, t) {
167
- var n;
168
- return e.type === "enum" && !(e.values ?? []).includes(String(t)) ? `expected one of: ${(e.values ?? []).join(", ")}` : (n = e.validate) == null ? void 0 : n.call(e, t);
169
- }
170
- function ae(e, t) {
171
- let n;
172
- switch (ze(e)) {
173
- case "boolean": {
174
- if (t !== "true" && t !== "false")
175
- return { error: "expected true or false" };
176
- n = t === "true";
177
- break;
178
- }
179
- case "number": {
180
- if (n = Number(t), t.trim() === "" || Number.isNaN(n))
181
- return { error: "expected a number" };
182
- break;
183
- }
184
- default:
185
- n = t;
186
- }
187
- const o = Xe(e, n);
188
- return o ? { error: o } : { value: n };
189
- }
190
- function $(e) {
191
- return typeof e == "string" ? JSON.stringify(e) : String(e);
192
- }
193
- function ce(e) {
194
- return e.defaultText ? e.defaultText : e.default === void 0 ? "unset" : $(e.default);
195
- }
196
- function Ft(e) {
197
- try {
198
- const t = new URL(e);
199
- return t.protocol === "http:" || t.protocol === "https:";
200
- } catch {
201
- return !1;
202
- }
203
- }
204
- const Ee = "config.json";
205
- function he(e = process.cwd()) {
206
- return {
207
- user: f(Y(void 0, { create: !1 }), Ee),
208
- project: f(de(e), Ee)
209
- };
210
- }
211
- function V(e = process.cwd()) {
212
- const t = he(e);
213
- return Qe(O(t.user) ?? {}, O(t.project) ?? {});
214
- }
215
- function Qe(e, t) {
216
- const n = {};
217
- for (const o of M)
218
- n[o.name] = {
219
- ...e[o.name],
220
- ...t[o.name]
221
- };
222
- return n;
223
- }
224
- function O(e) {
225
- let t;
226
- try {
227
- t = U(e, "utf8");
228
- } catch {
229
- return;
230
- }
231
- let n;
232
- try {
233
- n = JSON.parse(t);
234
- } catch (o) {
235
- throw new Error(
236
- `invalid JSON in ${e}: ${o instanceof Error ? o.message : String(o)}`
237
- );
238
- }
239
- return Vt(n, e);
240
- }
241
- function Vt(e, t) {
242
- const n = De(e, t, "the top level");
243
- Ie(
244
- n,
245
- M.map((r) => r.name),
246
- t,
247
- "the top level"
248
- );
249
- const o = {};
250
- for (const r of M) {
251
- if (n[r.name] === void 0)
252
- continue;
253
- const i = De(n[r.name], t, `"${r.name}"`);
254
- Ie(
255
- i,
256
- r.fields.map((a) => a.key),
257
- t,
258
- `"${r.name}"`
259
- );
260
- const s = {};
261
- for (const a of r.fields) {
262
- const c = i[a.key];
263
- if (c === void 0)
264
- continue;
265
- const d = `${r.name}.${a.key}`, p = ze(a);
266
- if (typeof c !== p)
267
- throw new Error(`expected a ${p} for ${d} in ${t}`);
268
- const h = Xe(a, c);
269
- if (h)
270
- throw new Error(
271
- `invalid ${d} ${$(c)} in ${t} — ${h}`
272
- );
273
- s[a.key] = c;
274
- }
275
- o[r.name] = s;
276
- }
277
- return o;
278
- }
279
- function B(e) {
280
- return fe(he().user, e);
281
- }
282
- function fe(e, t) {
283
- const n = O(e) ?? {};
284
- return t(n), W(R(e), { recursive: !0 }), q(e, `${JSON.stringify(n, null, 2)}
285
- `), e;
286
- }
287
- function De(e, t, n) {
288
- if (typeof e != "object" || e === null || Array.isArray(e))
289
- throw new Error(`expected an object at ${n} of ${t}`);
290
- return e;
291
- }
292
- function Ie(e, t, n, o) {
293
- for (const r of Object.keys(e))
294
- if (!t.includes(r))
295
- throw new Error(
296
- `unknown key "${r}" at ${o} of ${n} — known keys: ${t.join(", ")}`
297
- );
298
- }
299
- async function z(e, t, n) {
300
- const o = Ot({ input: process.stdin, output: process.stderr });
2
+ import { Command as wt } from "commander";
3
+ import { join as d, resolve as C, delimiter as gt, dirname as bt } from "node:path";
4
+ import { cacheDir as F, packageRoot as V, runningFromSource as yt, isCi as ie, discoverSessionBrowser as U, openInSessionBrowser as R, sessionBrowserBinary as Oe, launchSessionBrowser as je, decideBrowserAction as vt } from "@habemus-papadum/aiui-util";
5
+ import { execa as T } from "execa";
6
+ import { existsSync as v, mkdirSync as G, writeFileSync as K, readFileSync as L, realpathSync as $t, readdirSync as Y, chmodSync as Ct, accessSync as kt, constants as xt, rmSync as Tt, lstatSync as It } from "node:fs";
7
+ import { detectBrowserPlatform as Ne, resolveBuildId as Ue, Browser as E, getInstalledBrowsers as Le, install as Et, uninstall as Pt } from "@puppeteer/browsers";
8
+ import { u as _, l as S, C as ve, m as Dt, d as ee, p as te, c as St, r as ne, a as Me, f as k, b as Re, e as At } from "./config-Cis6kCik.js";
9
+ import { createInterface as _t } from "node:readline/promises";
10
+ import u from "chalk";
11
+ import { projectCacheDir as Be, listMcpServers as M, selectMcpServer as He, agentsByPid as Fe, listClaudeAgents as Ve } from "@habemus-papadum/aiui-claude-channel";
12
+ import { homedir as se, networkInterfaces as Ge } from "node:os";
13
+ import { spawn as Ot } from "node:child_process";
14
+ import { Separator as oe, select as O, input as jt } from "@inquirer/prompts";
15
+ async function W(e, t, n) {
16
+ const o = _t({ input: process.stdin, output: process.stderr });
301
17
  try {
302
18
  const r = t.map(
303
- (i) => ` ${l.bold(`[${i.key === n ? i.key.toUpperCase() : i.key}]`)} ${i.label}`
19
+ (i) => ` ${u.bold(`[${i.key === n ? i.key.toUpperCase() : i.key}]`)} ${i.label}`
304
20
  ).join(`
305
21
  `);
306
22
  for (; ; ) {
307
- const s = (await o.question(`${l.cyan(e)}
23
+ const s = (await o.question(`${u.cyan(e)}
308
24
  ${r}
309
25
  > `)).trim().toLowerCase();
310
26
  if (!s) {
@@ -312,41 +28,41 @@ ${r}
312
28
  return n;
313
29
  continue;
314
30
  }
315
- const a = t.find((c) => c.key === s) ?? t.find((c) => c.label.toLowerCase().startsWith(s));
316
- if (a)
317
- return a.key;
31
+ const c = t.find((a) => a.key === s) ?? t.find((a) => a.label.toLowerCase().startsWith(s));
32
+ if (c)
33
+ return c.key;
318
34
  }
319
35
  } finally {
320
36
  o.close();
321
37
  }
322
38
  }
323
- function g(e, t) {
324
- console.error(`${l.bgRed.white.bold(" ERROR ")} ${l.red.bold(e)}`), t && console.error(l.dim(t));
39
+ function b(e, t) {
40
+ console.error(`${u.bgRed.white.bold(" ERROR ")} ${u.red.bold(e)}`), t && console.error(u.dim(t));
325
41
  }
326
- function T(e, t) {
327
- console.error(`${l.bgYellow.black.bold(" WARN ")} ${l.yellow.bold(e)}`), t && console.error(l.dim(t));
42
+ function $(e, t) {
43
+ console.error(`${u.bgYellow.black.bold(" WARN ")} ${u.yellow.bold(e)}`), t && console.error(u.dim(t));
328
44
  }
329
- function y(e, t) {
330
- console.error(`${l.bgCyan.black.bold(" NOTE ")} ${l.cyan(e)}`), t && console.error(l.dim(t));
45
+ function w(e, t) {
46
+ console.error(`${u.bgCyan.black.bold(" NOTE ")} ${u.cyan(e)}`), t && console.error(u.dim(t));
331
47
  }
332
- const Ze = 1440 * 60 * 1e3, Ht = 4e3;
48
+ const Ke = 1440 * 60 * 1e3, Nt = 4e3;
333
49
  function A(e = !0) {
334
- return Y("chrome", { create: e });
50
+ return F("chrome", { create: e });
335
51
  }
336
- const et = "update-state.json";
337
- function X() {
52
+ const Ye = "update-state.json";
53
+ function q() {
338
54
  try {
339
- return JSON.parse(U(f(A(!1), et), "utf8"));
55
+ return JSON.parse(L(d(A(!1), Ye), "utf8"));
340
56
  } catch {
341
57
  return {};
342
58
  }
343
59
  }
344
- function Q(e) {
60
+ function z(e) {
345
61
  const t = A();
346
- W(t, { recursive: !0 }), q(f(t, et), `${JSON.stringify({ ...X(), ...e })}
62
+ G(t, { recursive: !0 }), K(d(t, Ye), `${JSON.stringify({ ...q(), ...e })}
347
63
  `);
348
64
  }
349
- function pe(e, t) {
65
+ function ae(e, t) {
350
66
  const n = e.split(".").map(Number), o = t.split(".").map(Number);
351
67
  for (let r = 0; r < Math.max(n.length, o.length); r++) {
352
68
  const i = (n[r] ?? 0) - (o[r] ?? 0);
@@ -355,76 +71,76 @@ function pe(e, t) {
355
71
  }
356
72
  return 0;
357
73
  }
358
- async function me() {
74
+ async function ce() {
359
75
  const e = A(!1);
360
76
  if (!v(e))
361
77
  return;
362
- const o = (await We({ cacheDir: e })).filter((r) => r.browser === I.CHROME).sort((r, i) => pe(r.buildId, i.buildId)).at(-1);
78
+ const o = (await Le({ cacheDir: e })).filter((r) => r.browser === E.CHROME).sort((r, i) => ae(r.buildId, i.buildId)).at(-1);
363
79
  return o && { buildId: o.buildId, executablePath: o.executablePath };
364
80
  }
365
- async function we(e = {}) {
366
- const { maxAgeMs: t = Ze, timeoutMs: n = Ht, now: o = Date.now() } = e, r = X();
81
+ async function le(e = {}) {
82
+ const { maxAgeMs: t = Ke, timeoutMs: n = Nt, now: o = Date.now() } = e, r = q();
367
83
  if (r.latestBuildId && r.checkedAt && o - r.checkedAt < t)
368
84
  return r.latestBuildId;
369
- const i = Ke();
85
+ const i = Ne();
370
86
  if (i)
371
87
  try {
372
- const s = await qt(
373
- Ye(I.CHROME, i, "stable"),
88
+ const s = await Rt(
89
+ Ue(E.CHROME, i, "stable"),
374
90
  n
375
91
  );
376
- return Q({ checkedAt: o, latestBuildId: s }), s;
92
+ return z({ checkedAt: o, latestBuildId: s }), s;
377
93
  } catch {
378
94
  return r.latestBuildId;
379
95
  }
380
96
  }
381
- async function S(e) {
382
- const t = A(), n = await It({
383
- browser: I.CHROME,
97
+ async function P(e) {
98
+ const t = A(), n = await Et({
99
+ browser: E.CHROME,
384
100
  buildId: e,
385
101
  cacheDir: t,
386
102
  downloadProgressCallback: "default"
387
- }), o = (await We({ cacheDir: t })).filter(
388
- (r) => r.browser === I.CHROME && r.buildId !== e
103
+ }), o = (await Le({ cacheDir: t })).filter(
104
+ (r) => r.browser === E.CHROME && r.buildId !== e
389
105
  );
390
106
  for (const r of o)
391
- await St({ browser: I.CHROME, buildId: r.buildId, cacheDir: t });
107
+ await Pt({ browser: E.CHROME, buildId: r.buildId, cacheDir: t });
392
108
  return { buildId: e, executablePath: n.executablePath };
393
109
  }
394
- async function Kt(e) {
395
- const t = Ke();
110
+ async function Ut(e) {
111
+ const t = Ne();
396
112
  if (!t)
397
113
  throw new Error("could not detect a supported platform for Chrome for Testing");
398
- const n = await Ye(I.CHROME, t, "stable");
399
- Q({ checkedAt: Date.now(), latestBuildId: n });
400
- const o = await me();
401
- if (o && pe(o.buildId, n) >= 0)
114
+ const n = await Ue(E.CHROME, t, "stable");
115
+ z({ checkedAt: Date.now(), latestBuildId: n });
116
+ const o = await ce();
117
+ if (o && ae(o.buildId, n) >= 0)
402
118
  return e(`Chrome for Testing ${o.buildId} is up to date`), { ...o, outcome: "current" };
403
119
  e(
404
120
  o ? `updating Chrome for Testing ${o.buildId} → ${n}…` : `installing Chrome for Testing ${n}…`
405
121
  );
406
- const r = await S(n);
122
+ const r = await P(n);
407
123
  return e(`Chrome for Testing ${n} installed at ${r.executablePath}`), { ...r, outcome: o ? "updated" : "installed" };
408
124
  }
409
- async function tt(e) {
410
- const { mode: t, interactive: n, now: o = Date.now() } = e, r = await me();
125
+ async function We(e) {
126
+ const { mode: t, interactive: n, now: o = Date.now() } = e, r = await ce();
411
127
  if (t === "off" || !n)
412
128
  return r == null ? void 0 : r.executablePath;
413
129
  if (!r)
414
- return Yt(t, o);
415
- const i = await we({ now: o });
416
- return !i || pe(i, r.buildId) <= 0 ? r.executablePath : Wt(t, r, i);
130
+ return Lt(t, o);
131
+ const i = await le({ now: o });
132
+ return !i || ae(i, r.buildId) <= 0 ? r.executablePath : Mt(t, r, i);
417
133
  }
418
- async function Yt(e, t) {
419
- const n = await we({ now: t });
134
+ async function Lt(e, t) {
135
+ const n = await le({ now: t });
420
136
  if (!n)
421
137
  return;
422
138
  if (e === "auto")
423
- return y(`installing Chrome for Testing ${n} (chrome.forTesting: "auto")…`), (await S(n)).executablePath;
424
- const o = X();
425
- if (o.installDeclinedAt && t - o.installDeclinedAt < Ze)
139
+ return w(`installing Chrome for Testing ${n} (chrome.forTesting: "auto")…`), (await P(n)).executablePath;
140
+ const o = q();
141
+ if (o.installDeclinedAt && t - o.installDeclinedAt < Ke)
426
142
  return;
427
- const r = await z(
143
+ const r = await W(
428
144
  `Chrome for Testing isn't installed. It's the recommended browser for aiui — version-pinned, separate from your real Chrome, and it auto-loads the aiui DevTools panel (branded Chrome can't). Download ${n} (~160 MB) to ${A(!1)}?`,
429
145
  [
430
146
  { key: "y", label: "yes, install it" },
@@ -434,23 +150,23 @@ async function Yt(e, t) {
434
150
  "y"
435
151
  );
436
152
  if (r === "y")
437
- return (await S(n)).executablePath;
153
+ return (await P(n)).executablePath;
438
154
  if (r === "never") {
439
- const i = B((s) => {
155
+ const i = _((s) => {
440
156
  s.chrome = { ...s.chrome, forTesting: "off" };
441
157
  });
442
- y(`wrote chrome.forTesting: "off" to ${i}`);
158
+ w(`wrote chrome.forTesting: "off" to ${i}`);
443
159
  } else
444
- Q({ installDeclinedAt: t });
160
+ z({ installDeclinedAt: t });
445
161
  }
446
- async function Wt(e, t, n) {
162
+ async function Mt(e, t, n) {
447
163
  if (e === "auto")
448
- return y(
164
+ return w(
449
165
  `updating Chrome for Testing ${t.buildId} → ${n} (chrome.forTesting: "auto")…`
450
- ), (await S(n)).executablePath;
451
- if (X().skippedBuildId === n)
166
+ ), (await P(n)).executablePath;
167
+ if (q().skippedBuildId === n)
452
168
  return t.executablePath;
453
- switch (await z(
169
+ switch (await W(
454
170
  `Your Chrome for Testing (${t.buildId}) is out of date — latest stable is ${n}. Update?`,
455
171
  [
456
172
  { key: "y", label: "yes, just this once" },
@@ -464,24 +180,24 @@ async function Wt(e, t, n) {
464
180
  "y"
465
181
  )) {
466
182
  case "y":
467
- return (await S(n)).executablePath;
183
+ return (await P(n)).executablePath;
468
184
  case "a": {
469
- const r = B((i) => {
185
+ const r = _((i) => {
470
186
  i.chrome = { ...i.chrome, forTesting: "auto" };
471
187
  });
472
- return y(`wrote chrome.forTesting: "auto" to ${r}`), (await S(n)).executablePath;
188
+ return w(`wrote chrome.forTesting: "auto" to ${r}`), (await P(n)).executablePath;
473
189
  }
474
190
  case "never": {
475
- const r = B((i) => {
191
+ const r = _((i) => {
476
192
  i.chrome = { ...i.chrome, forTesting: "off" };
477
193
  });
478
- return y(`wrote chrome.forTesting: "off" to ${r}`), t.executablePath;
194
+ return w(`wrote chrome.forTesting: "off" to ${r}`), t.executablePath;
479
195
  }
480
196
  default:
481
- return Q({ skippedBuildId: n }), t.executablePath;
197
+ return z({ skippedBuildId: n }), t.executablePath;
482
198
  }
483
199
  }
484
- async function qt(e, t) {
200
+ async function Rt(e, t) {
485
201
  let n;
486
202
  try {
487
203
  return await Promise.race([
@@ -494,123 +210,103 @@ async function qt(e, t) {
494
210
  clearTimeout(n);
495
211
  }
496
212
  }
497
- function ge(e, t) {
498
- const n = L(e), o = JSON.parse(U(f(n, "package.json"), "utf8")), r = typeof o.bin == "string" ? o.bin : Gt(o.bin);
213
+ function J(e, t) {
214
+ const n = V(e), o = JSON.parse(L(d(n, "package.json"), "utf8")), r = typeof o.bin == "string" ? o.bin : Bt(o.bin);
499
215
  if (!r)
500
216
  throw new Error(
501
217
  `package ${e} declares no bin`
502
218
  );
503
- if (kt(n)) {
219
+ if (yt(n)) {
504
220
  const i = r.replace(/^\.?\/?dist\//, "src/").replace(/\.js$/, ".ts");
505
- return { command: process.execPath, args: ["--import", "tsx", P(n, i)] };
221
+ return { command: process.execPath, args: ["--import", "tsx", C(n, i)] };
506
222
  }
507
- return { command: process.execPath, args: [P(n, r)] };
223
+ return { command: process.execPath, args: [C(n, r)] };
508
224
  }
509
- function Gt(e) {
225
+ function Bt(e) {
510
226
  return e ? Object.values(e)[0] : void 0;
511
227
  }
512
- const Jt = "chrome-devtools", nt = "@habemus-papadum/aiui-devtools-extension", zt = "default", Xt = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
513
- function ot(e, t = {}, n = process.env) {
514
- return e.noChrome ? !1 : e.chrome ? !0 : t.enabled === !1 ? !1 : !ue(n);
228
+ const Ht = "chrome-devtools", Ft = "@habemus-papadum/aiui-intent-client", Vt = "default", Gt = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
229
+ function qe(e, t = {}, n = process.env) {
230
+ return e.noChrome ? !1 : e.chrome ? !0 : t.enabled === !1 ? !1 : !ie(n);
515
231
  }
516
- function D(e, t = {}, n = process.cwd()) {
232
+ function x(e, t = {}, n = process.cwd()) {
517
233
  if (t.executablePath && t.channel)
518
234
  throw new Error(
519
235
  "config sets both chrome.executablePath and chrome.channel — they pick the browser two different ways; keep exactly one"
520
236
  );
521
237
  const o = e.chromeProfile !== void 0 || e.chromeDataDir !== void 0, r = e.chromeDataDir ?? (o ? void 0 : t.dataDir), i = e.chromeProfile ?? (o ? void 0 : t.profile);
522
238
  return {
523
- userDataDir: rt({ dataDir: r, profile: i }, n),
239
+ userDataDir: ze({ dataDir: r, profile: i }, n),
524
240
  // A configured endpoint means the browser is managed elsewhere (usually
525
241
  // another machine) — that's always attach, whatever `mode` says.
526
242
  mode: t.browserUrl ? "attach" : t.mode ?? "attach",
527
243
  browserUrl: t.browserUrl,
528
244
  debugPort: t.debugPort ?? 0,
529
- executablePath: t.executablePath && P(n, t.executablePath),
245
+ executablePath: t.executablePath && C(n, t.executablePath),
530
246
  channel: t.channel,
531
- headless: t.headless ?? !1,
532
- buildExtension: t.buildExtension ?? !0
247
+ headless: t.headless ?? !1
533
248
  };
534
249
  }
535
- function rt(e, t = process.cwd()) {
250
+ function ze(e, t = process.cwd()) {
536
251
  if (e.dataDir)
537
- return P(t, e.dataDir);
538
- const n = e.profile ?? zt;
539
- if (!Xt.test(n))
252
+ return C(t, e.dataDir);
253
+ const n = e.profile ?? Vt;
254
+ if (!Gt.test(n))
540
255
  throw new Error(
541
256
  `invalid chrome profile name "${n}" — use letters, digits, ".", "_", "-" (or --aiui-chrome-data-dir for an arbitrary path)`
542
257
  );
543
- return f(de(t), "chrome", n);
258
+ return d(Be(t), "chrome", n);
544
259
  }
545
- function Z() {
546
- let e;
260
+ const Kt = "dist-ext";
261
+ function Yt() {
547
262
  try {
548
- e = He(f(L(nt), "extension"));
263
+ const e = $t(V(Ft));
264
+ return { root: e, outDir: d(e, Kt) };
549
265
  } catch {
550
266
  return;
551
267
  }
552
- return v(f(e, "js")) ? e : void 0;
553
268
  }
554
- async function be() {
555
- let e, t;
556
- try {
557
- e = He(L(nt)), t = f(L("typescript"), "bin", "tsc");
558
- } catch {
559
- return;
560
- }
561
- if (!v(f(e, "src")))
562
- return;
563
- const n = await k(process.execPath, [t, "-p", f(e, "tsconfig.json")], {
564
- cwd: e,
565
- reject: !1,
566
- all: !0
567
- });
568
- if (n.exitCode) {
569
- T(
570
- "aiui-devtools-extension failed to compile — the DevTools panel will be stale or missing",
571
- n.all || n.message
572
- );
573
- return;
574
- }
575
- const o = f(e, "build-debug-ui.mjs");
576
- if (!v(o))
577
- return;
578
- const r = await k(process.execPath, [o], {
579
- cwd: e,
580
- reject: !1,
581
- all: !0
582
- });
583
- r.exitCode && T(
584
- "aiui-devtools-extension debug-ui bundle failed — the Intent pane will be degraded",
585
- r.all || r.message
269
+ function Wt(e) {
270
+ return e === void 0 ? { state: "absent" } : v(d(e.outDir, "manifest.json")) ? { state: "ready", dir: e.outDir } : { state: "unbuilt", root: e.root };
271
+ }
272
+ function j() {
273
+ return Wt(Yt());
274
+ }
275
+ function Je(e) {
276
+ e.state === "unbuilt" && w(
277
+ "the aiui intent client has no MV3 bundle yet, so this launch won't load it",
278
+ `Build it once: pnpm -C packages/aiui-intent-client build:ext
279
+ then relaunch — or load it into the RUNNING browser:
280
+ pnpm -C packages/aiui-intent-client ext`
586
281
  );
587
282
  }
588
- function it(e, t) {
589
- if (!t || e.executablePath)
283
+ function Xe(e, t) {
284
+ if (!t.length || e.executablePath)
590
285
  return;
591
- const n = f(e.userDataDir, "aiui-devtools-extension-hint");
286
+ const n = d(e.userDataDir, "aiui-extension-autoload-hint");
592
287
  if (!v(n)) {
593
- y(
594
- "the aiui DevTools panel can't auto-load into regular Chrome (≥ 137 ignores --load-extension)",
288
+ w(
289
+ "the aiui intent client can't auto-load into regular Chrome (≥ 137 ignores --load-extension)",
595
290
  `Load it once in the launched Chrome — chrome://extensions → Developer mode → Load unpacked →
596
- ${t}
291
+ ${t.join(`
292
+ `)}
597
293
  — and this profile remembers it. Or switch to Chrome for Testing (\`aiui chrome install\`),
598
294
  which auto-loads it. This note won't repeat for this profile.`
599
295
  );
600
296
  try {
601
- q(n, `${(/* @__PURE__ */ new Date()).toISOString()}
297
+ K(n, `${(/* @__PURE__ */ new Date()).toISOString()}
602
298
  `);
603
299
  } catch {
604
300
  }
605
301
  }
606
302
  }
607
- function te(e) {
303
+ function Z(e) {
608
304
  return {
609
305
  command: "npx",
610
306
  args: ["-y", "chrome-devtools-mcp@latest", "--browser-url", e]
611
307
  };
612
308
  }
613
- function Qt(e, t) {
309
+ function qt(e, t = []) {
614
310
  const n = [
615
311
  "-y",
616
312
  "chrome-devtools-mcp@latest",
@@ -618,13 +314,160 @@ function Qt(e, t) {
618
314
  e.userDataDir,
619
315
  "--ignoreDefaultChromeArg=--disable-extensions"
620
316
  ];
621
- return e.executablePath && n.push("--executablePath", e.executablePath), e.channel && n.push("--channel", e.channel), e.headless && n.push("--headless"), t && n.push(`--chromeArg=--load-extension=${t}`), { command: "npx", args: n };
317
+ return e.executablePath && n.push("--executablePath", e.executablePath), e.channel && n.push("--channel", e.channel), e.headless && n.push("--headless"), t.length && n.push(`--chromeArg=--load-extension=${t.join(",")}`), { command: "npx", args: n };
318
+ }
319
+ const N = "com.habemus_papadum.aiui", ue = "cdpbfpcelmifhagikjlfpgfipggcmdeg";
320
+ function Ze(e, t) {
321
+ if (e === "darwin") {
322
+ const n = d(t, "Library", "Application Support");
323
+ return [
324
+ d(n, "Google", "Chrome", "NativeMessagingHosts"),
325
+ d(n, "Chromium", "NativeMessagingHosts"),
326
+ d(n, "Microsoft Edge", "NativeMessagingHosts")
327
+ ];
328
+ }
329
+ if (e === "linux")
330
+ return [
331
+ d(t, ".config", "google-chrome", "NativeMessagingHosts"),
332
+ d(t, ".config", "chromium", "NativeMessagingHosts"),
333
+ d(t, ".config", "microsoft-edge", "NativeMessagingHosts")
334
+ ];
335
+ throw new Error(`aiui extension: unsupported platform ${e} (macOS/Linux only for now)`);
336
+ }
337
+ function zt(e, t, n) {
338
+ const o = (r) => `"${r.replace(/(["\\$`])/g, "\\$1")}"`;
339
+ return [
340
+ "#!/bin/sh",
341
+ "# aiui native-messaging host wrapper — generated by `aiui extension install-native-host`.",
342
+ "# Chrome spawns this with a minimal env and cwd /; everything below is absolute.",
343
+ `cd ${o(e)} || exit 1`,
344
+ `exec ${[t, ...n].map(o).join(" ")} native-host`,
345
+ ""
346
+ ].join(`
347
+ `);
348
+ }
349
+ const Jt = ["install-native-host", "status"];
350
+ async function Xt(e, t = {}) {
351
+ switch (e) {
352
+ case "install-native-host":
353
+ Qt(t);
354
+ return;
355
+ case "status":
356
+ en();
357
+ return;
358
+ case "dev":
359
+ case "reload":
360
+ b(
361
+ `aiui extension ${e} is gone — the frozen aiui-extension was deleted`,
362
+ `The intent client's extension is a static build:
363
+ pnpm -C packages/aiui-intent-client ext (build + load into the session browser)`
364
+ ), process.exitCode = 1;
365
+ return;
366
+ default:
367
+ throw new Error(`aiui extension: unknown action "${e}" (${Jt.join(" | ")})`);
368
+ }
622
369
  }
623
- const Zt = 9222;
624
- async function en(e) {
625
- const n = { ...V().chrome };
370
+ function Qe() {
371
+ return d(F("native-host", { create: !0 }), "aiui-native-host.sh");
372
+ }
373
+ function et(e) {
374
+ const t = J("@habemus-papadum/aiui"), n = V("@habemus-papadum/aiui"), o = Qe();
375
+ tt(o, zt(n, t.command, t.args)), Ct(o, 493);
376
+ const r = {
377
+ name: N,
378
+ description: "aiui native-messaging host: channel discovery for the aiui intent client",
379
+ path: o,
380
+ type: "stdio",
381
+ // The host answers one question — "which channels are up?" — for the
382
+ // intent client's cold start. An overridden id rides alongside the stable
383
+ // one so a custom build never locks the shipped client out.
384
+ allowed_origins: [
385
+ .../* @__PURE__ */ new Set([
386
+ `chrome-extension://${e}/`,
387
+ `chrome-extension://${ue}/`
388
+ ])
389
+ ]
390
+ };
391
+ return { wrapper: o, body: `${JSON.stringify(r, null, 2)}
392
+ ` };
393
+ }
394
+ function tt(e, t) {
395
+ try {
396
+ if (L(e, "utf8") === t)
397
+ return !1;
398
+ } catch {
399
+ }
400
+ return K(e, t), !0;
401
+ }
402
+ function Zt(e, t = {}) {
403
+ const { body: n } = et(t.extensionId ?? ue), o = d(e, "NativeMessagingHosts");
404
+ G(o, { recursive: !0 }), tt(d(o, `${N}.json`), n);
405
+ }
406
+ function B(e, t, n) {
407
+ if (t)
408
+ try {
409
+ Zt(e);
410
+ } catch (o) {
411
+ n(
412
+ "couldn't install the native-messaging host into the browser profile — the intent extension will need a manually typed port",
413
+ o instanceof Error ? o.message : String(o)
414
+ );
415
+ }
416
+ }
417
+ function Qt(e) {
418
+ const t = e.extensionId ?? ue, { wrapper: n, body: o } = et(t);
419
+ process.stdout.write(`wrote ${n}
420
+ `);
421
+ for (const r of Ze(process.platform, se())) {
422
+ G(r, { recursive: !0 });
423
+ const i = d(r, `${N}.json`);
424
+ K(i, o), process.stdout.write(`wrote ${i}
425
+ `);
426
+ }
427
+ process.stdout.write(
428
+ `native host installed for extension ${t}.
429
+ No browser restart needed; reload the extension if it was already running.
430
+ (Session browsers launched by aiui get the manifest in their own profile
431
+ automatically — this global install is for browsers aiui does not manage.)
432
+ `
433
+ );
434
+ }
435
+ function en() {
436
+ const e = Qe();
437
+ process.stdout.write(`wrapper: ${e} ${v(e) ? "(present)" : "(MISSING)"}
438
+ `);
439
+ for (const o of Ze(process.platform, se()))
440
+ $e(d(o, `${N}.json`));
441
+ const t = d(process.cwd(), ".aiui-cache", "chrome");
442
+ let n = [];
443
+ try {
444
+ n = Y(t, { withFileTypes: !0 }).filter((o) => o.isDirectory()).map((o) => o.name);
445
+ } catch {
446
+ }
447
+ for (const o of n)
448
+ $e(d(t, o, "NativeMessagingHosts", `${N}.json`));
449
+ }
450
+ function $e(e) {
451
+ var t;
452
+ if (!v(e)) {
453
+ process.stdout.write(`absent: ${e}
454
+ `);
455
+ return;
456
+ }
457
+ try {
458
+ const n = JSON.parse(L(e, "utf8"));
459
+ process.stdout.write(`present: ${e} → ${(t = n.allowed_origins) == null ? void 0 : t.join(", ")}
460
+ `);
461
+ } catch {
462
+ process.stdout.write(`present: ${e} (unparseable)
463
+ `);
464
+ }
465
+ }
466
+ const tn = 9222;
467
+ async function nn(e) {
468
+ const n = { ...S().chrome };
626
469
  if (n.browserUrl) {
627
- y(
470
+ w(
628
471
  `config pins chrome.browserUrl to ${n.browserUrl} — the browser is managed elsewhere`,
629
472
  "Run `aiui browser` on the machine that should host it (and drop browserUrl there)."
630
473
  );
@@ -632,86 +475,89 @@ async function en(e) {
632
475
  }
633
476
  let o, r;
634
477
  try {
635
- o = Se(e.remotePort, "--remote-port") ?? Zt, r = Se(e.port, "--port");
636
- } catch (c) {
637
- g(c instanceof Error ? c.message : String(c)), process.exitCode = 1;
478
+ o = Ce(e.remotePort, "--remote-port") ?? tn, r = Ce(e.port, "--port");
479
+ } catch (a) {
480
+ b(a instanceof Error ? a.message : String(a)), process.exitCode = 1;
638
481
  return;
639
482
  }
640
483
  const i = {
641
484
  chromeProfile: e.tunnel ? void 0 : e.profile,
642
- chromeDataDir: e.dataDir ?? (e.tunnel ? tn(e.tunnel, e.profile) : void 0)
485
+ chromeDataDir: e.dataDir ?? (e.tunnel ? on(e.tunnel, e.profile) : void 0)
643
486
  };
644
- let s = D(i, n);
487
+ let s = x(i, n);
645
488
  r !== void 0 && (s = { ...s, debugPort: r });
646
- let a = await F(s.userDataDir);
647
- if (a)
648
- Oe("session browser already running", s, a), e.open && (await H(a.browserUrl, e.open), console.log(`opened ${e.open}`));
489
+ let c = await U(s.userDataDir);
490
+ if (c)
491
+ B(
492
+ s.userDataDir,
493
+ j().state === "ready",
494
+ w
495
+ ), ke("session browser already running", s, c), e.open && (await R(c.browserUrl, e.open), console.log(`opened ${e.open}`));
649
496
  else {
650
- const c = !!process.stdin.isTTY && !!process.stdout.isTTY && !ue();
497
+ const a = !!process.stdin.isTTY && !!process.stdout.isTTY && !ie();
651
498
  try {
652
- const d = await st({
499
+ const l = await nt({
653
500
  flags: i,
654
501
  config: n,
655
- interactive: c,
502
+ interactive: a,
656
503
  debugPort: r,
657
504
  headless: e.headless,
658
505
  startUrl: e.open
659
506
  });
660
- a = d.session, s = d.settings;
661
- } catch (d) {
662
- g(
507
+ c = l.session, s = l.settings;
508
+ } catch (l) {
509
+ b(
663
510
  "the session browser failed to start",
664
- d instanceof Error ? d.message : String(d)
511
+ l instanceof Error ? l.message : String(l)
665
512
  ), process.exitCode = 1;
666
513
  return;
667
514
  }
668
- Oe("session browser started", s, a);
515
+ ke("session browser started", s, c);
669
516
  }
670
- e.tunnel ? await rn(e.tunnel, o, a.port) : sn(a, o);
517
+ e.tunnel ? await an(e.tunnel, o, c.port) : cn(c, o);
671
518
  }
672
- async function st(e) {
519
+ async function nt(e) {
673
520
  let t = e.config ?? {};
674
521
  const n = e.flags ?? {}, o = () => {
675
- const c = D(n, t);
676
- return e.debugPort === void 0 ? c : { ...c, debugPort: e.debugPort };
522
+ const l = x(n, t);
523
+ return e.debugPort === void 0 ? l : { ...l, debugPort: e.debugPort };
677
524
  };
678
525
  let r = o();
679
526
  if (!t.executablePath && !t.channel) {
680
- const c = await tt({
527
+ const l = await We({
681
528
  mode: t.forTesting ?? "prompt",
682
529
  interactive: e.interactive
683
530
  });
684
- c && (t = { ...t, executablePath: c }, r = o());
531
+ l && (t = { ...t, executablePath: l }, r = o());
685
532
  }
686
- r.buildExtension && await be();
687
- const i = Z();
688
- e.interactive && it(r, i);
689
- let s;
533
+ const i = j(), s = i.state === "ready" ? [i.dir] : [];
534
+ B(r.userDataDir, i.state === "ready", w), e.interactive && (Xe(r, s), Je(i));
535
+ let c;
690
536
  try {
691
- s = Fe(r);
692
- } catch (c) {
537
+ c = Oe(r);
538
+ } catch (l) {
693
539
  throw new Error(
694
- `${c instanceof Error ? c.message : String(c)}
540
+ `${l instanceof Error ? l.message : String(l)}
695
541
  Install Chrome for Testing with \`aiui chrome install\`, or set chrome.executablePath.`
696
542
  );
697
543
  }
698
- return { session: await Ve({
699
- binary: s,
544
+ return { session: await je({
545
+ binary: c,
700
546
  userDataDir: r.userDataDir,
701
547
  debugPort: r.debugPort,
702
- extensionDir: i,
548
+ extensionDirs: s,
703
549
  headless: r.headless || e.headless,
704
550
  startUrl: e.startUrl
705
551
  }), settings: r };
706
552
  }
707
- function tn(e, t) {
708
- const n = t ?? nn(e);
709
- return f(Y("browser-profiles", { create: !1 }), n);
553
+ function on(e, t) {
554
+ const n = t ?? rn(e);
555
+ return d(F("browser-profiles", { create: !1 }), n);
710
556
  }
711
- function nn(e) {
557
+ function rn(e) {
712
558
  return (e.includes("@") ? e.slice(e.indexOf("@") + 1) : e).replace(/[^A-Za-z0-9._-]/g, "-") || "remote";
713
559
  }
714
- function on(e, t, n) {
560
+ function sn(e, t, n) {
715
561
  return [
716
562
  // No remote command — the connection exists only to carry the forward...
717
563
  "-N",
@@ -724,28 +570,28 @@ function on(e, t, n) {
724
570
  e
725
571
  ];
726
572
  }
727
- function at(e) {
573
+ function ot(e) {
728
574
  return `aiui claude --aiui-browser-url http://127.0.0.1:${e}`;
729
575
  }
730
- async function rn(e, t, n) {
576
+ async function an(e, t, n) {
731
577
  console.log(
732
578
  `
733
579
  tunneling ${e}:${t} → localhost:${n} — on ${e}, run:
734
580
 
735
- ${at(t)}
581
+ ${ot(t)}
736
582
 
737
583
  (Ctrl-C closes the tunnel; the browser stays running.)`
738
584
  );
739
- const o = await k("ssh", on(e, t, n), {
585
+ const o = await T("ssh", sn(e, t, n), {
740
586
  stdio: "inherit",
741
587
  reject: !1
742
588
  });
743
- o.failed && !o.isTerminated && (g(
589
+ o.failed && !o.isTerminated && (b(
744
590
  `the ssh tunnel to ${e} exited (code ${o.exitCode})`,
745
591
  "A taken remote port exits immediately (ExitOnForwardFailure) — try another --remote-port. The browser is still running; rerun `aiui browser --tunnel …` to reconnect."
746
592
  ), process.exitCode = 1);
747
593
  }
748
- function Se(e, t) {
594
+ function Ce(e, t) {
749
595
  if (e === void 0)
750
596
  return;
751
597
  const n = Number(e);
@@ -753,77 +599,64 @@ function Se(e, t) {
753
599
  throw new Error(`invalid ${t} ${e} — expected 0..65535`);
754
600
  return n;
755
601
  }
756
- function Oe(e, t, n) {
602
+ function ke(e, t, n) {
757
603
  console.log(e), console.log(` profile: ${t.userDataDir}`), console.log(` debug endpoint: ${n.browserUrl}`);
758
604
  }
759
- function sn(e, t) {
605
+ function cn(e, t) {
760
606
  console.log(
761
607
  `
762
608
  An \`aiui claude\` in this profile's project attaches automatically. For a *remote*
763
609
  session, rerun with \`--tunnel <[user@]host>\` — or do it by hand:
764
610
  ssh -N -o ExitOnForwardFailure=yes -R ${t}:localhost:${e.port} <host>
765
- then, on the remote: ${at(t)}`
611
+ then, on the remote: ${ot(t)}`
766
612
  );
767
613
  }
768
- async function an(e, t) {
614
+ async function ln(e, t) {
769
615
  var i, s;
770
- const n = V(), o = D(
616
+ const n = S(), o = x(
771
617
  { chromeProfile: t.profile, chromeDataDir: t.dataDir },
772
618
  n.chrome ?? {}
773
- ), r = ((i = n.chrome) == null ? void 0 : i.browserUrl) ?? ((s = await F(o.userDataDir)) == null ? void 0 : s.browserUrl);
619
+ ), r = ((i = n.chrome) == null ? void 0 : i.browserUrl) ?? ((s = await U(o.userDataDir)) == null ? void 0 : s.browserUrl);
774
620
  if (!r) {
775
- g(
621
+ b(
776
622
  "no session browser is running for this profile",
777
623
  `Start one with \`aiui browser\` (profile: ${o.userDataDir}).`
778
624
  ), process.exitCode = 1;
779
625
  return;
780
626
  }
781
627
  try {
782
- await H(r, e), console.log(`opened ${e}`);
783
- } catch (a) {
784
- g(`couldn't open ${e}`, a instanceof Error ? a.message : String(a)), process.exitCode = 1;
628
+ await R(r, e), console.log(`opened ${e}`);
629
+ } catch (c) {
630
+ b(`couldn't open ${e}`, c instanceof Error ? c.message : String(c)), process.exitCode = 1;
785
631
  }
786
632
  }
787
- async function cn(e) {
633
+ async function un(e) {
788
634
  const [t] = e;
789
635
  switch (t) {
790
636
  case "install":
791
637
  case "update":
792
- await Kt((n) => console.log(n));
638
+ await Ut((n) => console.log(n));
793
639
  return;
794
640
  case "status":
795
- await ln();
641
+ await dn();
796
642
  return;
797
- case "extension": {
798
- await be();
799
- const n = Z();
800
- if (!n) {
801
- g(
802
- "the aiui-devtools-extension is not available in this install",
803
- "In a dev checkout, build it first: pnpm --filter @habemus-papadum/aiui-devtools-extension build"
804
- ), process.exitCode = 1;
805
- return;
806
- }
807
- console.log(n);
808
- return;
809
- }
810
643
  default:
811
- g(
644
+ b(
812
645
  t ? `unknown aiui chrome action: ${t}` : "aiui chrome needs an action",
813
- "Usage: aiui chrome <install | update | status | extension>"
646
+ "Usage: aiui chrome <install | update | status>"
814
647
  ), process.exitCode = 1;
815
648
  return;
816
649
  }
817
650
  }
818
- async function ln() {
819
- const t = V().chrome ?? {}, n = { chrome: !1, noChrome: !1 }, o = await me(), r = await we();
651
+ async function dn() {
652
+ const t = S().chrome ?? {}, n = { chrome: !1, noChrome: !1 }, o = await ce(), r = await le();
820
653
  if (console.log("Chrome for Testing (managed):"), o) {
821
654
  const m = r === void 0 ? "(latest stable unknown — offline?)" : r === o.buildId ? "(latest stable)" : `(latest stable is ${r} — run \`aiui chrome update\`)`;
822
655
  console.log(` installed ${o.buildId} ${m}`), console.log(` ${o.executablePath}`);
823
656
  } else
824
657
  console.log(" not installed — `aiui chrome install` (recommended; auto-loads the panel)");
825
658
  if (console.log(` startup checks (chrome.forTesting): ${t.forTesting ?? "prompt"}`), console.log(`
826
- This directory would launch:`), !ot(n, t)) {
659
+ This directory would launch:`), !qe(n, t)) {
827
660
  console.log(" nothing — the Chrome DevTools MCP is disabled here");
828
661
  return;
829
662
  }
@@ -833,130 +666,129 @@ This directory would launch:`), !ot(n, t)) {
833
666
  }
834
667
  const i = { ...t };
835
668
  !i.executablePath && !i.channel && o && (i.executablePath = o.executablePath);
836
- const s = D({}, i), a = await F(s.userDataDir), c = s.mode === "attach" ? a ? `attach to the running session browser at ${a.browserUrl}` : "attach — a session browser starts with the next interactive launch (or `aiui browser`)" : "launch — chrome-devtools-mcp starts a private browser on the agent's first tool use";
837
- console.log(` connection: ${c}`);
838
- const d = s.executablePath ? s.executablePath === (o == null ? void 0 : o.executablePath) ? `Chrome for Testing ${o.buildId}` : s.executablePath : s.channel ? `installed Chrome (${s.channel} channel)` : "installed Chrome (stable)";
839
- console.log(` browser: ${d}${s.headless ? " — headless" : ""}`), console.log(` user data dir: ${s.userDataDir}`);
840
- const p = f(rt({}, process.cwd()), "..");
669
+ const s = x({}, i), c = await U(s.userDataDir), a = s.mode === "attach" ? c ? `attach to the running session browser at ${c.browserUrl}` : "attach — a session browser starts with the next interactive launch (or `aiui browser`)" : "launch — chrome-devtools-mcp starts a private browser on the agent's first tool use";
670
+ console.log(` connection: ${a}`);
671
+ const l = s.executablePath ? s.executablePath === (o == null ? void 0 : o.executablePath) ? `Chrome for Testing ${o.buildId}` : s.executablePath : s.channel ? `installed Chrome (${s.channel} channel)` : "installed Chrome (stable)";
672
+ console.log(` browser: ${l}${s.headless ? " — headless" : ""}`), console.log(` user data dir: ${s.userDataDir}`);
673
+ const p = d(ze({}, process.cwd()), "..");
841
674
  if (v(p)) {
842
- const m = G(p, { withFileTypes: !0 }).filter((b) => b.isDirectory()).map((b) => b.name);
675
+ const m = Y(p, { withFileTypes: !0 }).filter((g) => g.isDirectory()).map((g) => g.name);
843
676
  m.length && console.log(` profiles here: ${m.join(", ")}`);
844
677
  }
845
678
  console.log(`
846
- aiui DevTools panel:`);
847
- const h = Z();
848
- if (!h) {
849
- console.log(" not available (unbuilt dev checkout? run `aiui chrome extension` for help)");
850
- return;
679
+ aiui intent client (the extension launches auto-load):`);
680
+ const f = j();
681
+ switch (f.state) {
682
+ case "absent":
683
+ console.log(" not available in this install (aiui-intent-client is not resolvable)");
684
+ break;
685
+ case "unbuilt":
686
+ console.log(
687
+ ` no MV3 bundle yet (${f.root})
688
+ build it: pnpm -C packages/aiui-intent-client build:ext
689
+ build + load into the running browser: pnpm -C packages/aiui-intent-client ext`
690
+ );
691
+ break;
692
+ case "ready":
693
+ console.log(` ${f.dir}`), hn(s.executablePath);
694
+ break;
851
695
  }
852
- console.log(` ${h}`), s.executablePath ? console.log(" auto-loads via --load-extension (honored by Chrome for Testing/Chromium)") : (console.log(" can NOT auto-load into branded Chrome ≥ 137 — load it unpacked once"), console.log(
696
+ }
697
+ function hn(e) {
698
+ e ? console.log(" auto-loads via --load-extension (honored by Chrome for Testing/Chromium)") : (console.log(" can NOT auto-load into branded Chrome ≥ 137 — load it unpacked once"), console.log(
853
699
  " (chrome://extensions → Developer mode → Load unpacked), or `aiui chrome install`"
854
700
  ));
855
701
  }
856
- const un = "--aiui-";
857
- function ct(e) {
702
+ const fn = "--aiui-";
703
+ function rt(e) {
858
704
  if (e.includes("--help") || e.includes("-h"))
859
705
  return "help";
860
706
  if (e.includes("--version") || e.includes("-v"))
861
707
  return "version";
862
708
  }
863
- function lt(e) {
864
- let t, n, o = !1, r = !1, i = !1, s = !1, a, c, d;
865
- const p = [], h = [];
866
- let m;
867
- const b = [];
868
- for (let w = 0; w < e.length; w++) {
869
- const C = e[w];
870
- if (!C.startsWith(un)) {
871
- b.push(C);
709
+ function de(e) {
710
+ let t, n, o = !1, r = !1, i = !1, s = !1, c, a, l, p;
711
+ const f = [];
712
+ for (let m = 0; m < e.length; m++) {
713
+ const g = e[m];
714
+ if (!g.startsWith(fn)) {
715
+ f.push(g);
872
716
  continue;
873
717
  }
874
- const x = C.indexOf("="), N = x === -1 ? C : C.slice(0, x);
875
- let u = x === -1 ? void 0 : C.slice(x + 1);
876
- switch (N) {
718
+ const y = g.indexOf("="), I = y === -1 ? g : g.slice(0, y);
719
+ let h = y === -1 ? void 0 : g.slice(y + 1);
720
+ switch (I) {
877
721
  case "--aiui-tag": {
878
- if (u === void 0 && (u = e[++w]), !u)
722
+ if (h === void 0 && (h = e[++m]), !h)
879
723
  throw new Error("--aiui-tag requires a non-empty value");
880
- t = u;
724
+ t = h;
881
725
  break;
882
726
  }
883
727
  case "--aiui-mcp": {
884
- if (u === void 0 && (u = e[++w]), !u)
728
+ if (h === void 0 && (h = e[++m]), !h)
885
729
  throw new Error("--aiui-mcp requires a non-empty value");
886
- n = u;
730
+ n = h;
887
731
  break;
888
732
  }
889
733
  case "--aiui-chrome": {
890
- if (u !== void 0)
734
+ if (h !== void 0)
891
735
  throw new Error("--aiui-chrome takes no value");
892
736
  o = !0;
893
737
  break;
894
738
  }
895
739
  case "--aiui-no-chrome": {
896
- if (u !== void 0)
740
+ if (h !== void 0)
897
741
  throw new Error("--aiui-no-chrome takes no value");
898
742
  r = !0;
899
743
  break;
900
744
  }
901
745
  case "--aiui-browser": {
902
- if (u !== void 0)
746
+ if (h !== void 0)
903
747
  throw new Error("--aiui-browser takes no value");
904
748
  i = !0;
905
749
  break;
906
750
  }
907
751
  case "--aiui-no-browser": {
908
- if (u !== void 0)
752
+ if (h !== void 0)
909
753
  throw new Error("--aiui-no-browser takes no value");
910
754
  s = !0;
911
755
  break;
912
756
  }
913
757
  case "--aiui-chrome-profile": {
914
- if (u === void 0 && (u = e[++w]), !u)
758
+ if (h === void 0 && (h = e[++m]), !h)
915
759
  throw new Error("--aiui-chrome-profile requires a non-empty value");
916
- a = u;
760
+ c = h;
917
761
  break;
918
762
  }
919
763
  case "--aiui-chrome-data-dir": {
920
- if (u === void 0 && (u = e[++w]), !u)
764
+ if (h === void 0 && (h = e[++m]), !h)
921
765
  throw new Error("--aiui-chrome-data-dir requires a non-empty value");
922
- c = u;
766
+ a = h;
923
767
  break;
924
768
  }
925
769
  case "--aiui-browser-url": {
926
- if (u === void 0 && (u = e[++w]), !u)
770
+ if (h === void 0 && (h = e[++m]), !h)
927
771
  throw new Error("--aiui-browser-url requires a non-empty value");
928
- d = u;
929
- break;
930
- }
931
- case "--aiui-sidecar": {
932
- if (u === void 0 && (u = e[++w]), !u)
933
- throw new Error("--aiui-sidecar requires a non-empty value");
934
- p.push(u);
935
- break;
936
- }
937
- case "--aiui-no-sidecar": {
938
- if (u === void 0 && (u = e[++w]), !u)
939
- throw new Error("--aiui-no-sidecar requires a non-empty value");
940
- h.push(u);
772
+ l = h;
941
773
  break;
942
774
  }
943
775
  case "--aiui-bind": {
944
- if (u === void 0 && (u = e[++w]), !u || !se.includes(u))
945
- throw new Error(`--aiui-bind requires one of: ${se.join(", ")}`);
946
- m = u;
776
+ if (h === void 0 && (h = e[++m]), !h || !ve.includes(h))
777
+ throw new Error(`--aiui-bind requires one of: ${ve.join(", ")}`);
778
+ p = h;
947
779
  break;
948
780
  }
949
781
  default:
950
- throw new Error(`unknown aiui option: ${N}`);
782
+ throw new Error(`unknown aiui option: ${I}`);
951
783
  }
952
784
  }
953
785
  if (o && r)
954
786
  throw new Error("--aiui-chrome and --aiui-no-chrome are mutually exclusive");
955
787
  if (i && s)
956
788
  throw new Error("--aiui-browser and --aiui-no-browser are mutually exclusive");
957
- if (a !== void 0 && c !== void 0)
789
+ if (c !== void 0 && a !== void 0)
958
790
  throw new Error("--aiui-chrome-profile and --aiui-chrome-data-dir are mutually exclusive");
959
- if (d !== void 0 && (a !== void 0 || c !== void 0))
791
+ if (l !== void 0 && (c !== void 0 || a !== void 0))
960
792
  throw new Error(
961
793
  "--aiui-browser-url means the browser is managed elsewhere — it can't be combined with --aiui-chrome-profile or --aiui-chrome-data-dir"
962
794
  );
@@ -967,114 +799,190 @@ function lt(e) {
967
799
  noChrome: r,
968
800
  browser: i,
969
801
  noBrowser: s,
970
- chromeProfile: a,
971
- chromeDataDir: c,
972
- browserUrl: d,
973
- sidecar: p,
974
- noSidecar: h,
975
- bind: m,
976
- passthrough: b
802
+ chromeProfile: c,
803
+ chromeDataDir: a,
804
+ browserUrl: l,
805
+ bind: p,
806
+ passthrough: f
977
807
  };
978
808
  }
979
- const dn = {
809
+ function it(e) {
810
+ var t;
811
+ return { bind: e.bind ?? ((t = e.config.channel) == null ? void 0 : t.bind) ?? "loopback" };
812
+ }
813
+ function st(e) {
814
+ return ["--bind", e.bind];
815
+ }
816
+ const pn = /* @__PURE__ */ new Set(["serve", "mcp"]);
817
+ function mn(e, t) {
818
+ return e.some((n) => n === t || n.startsWith(`${t}=`));
819
+ }
820
+ function at(e) {
821
+ const t = e.find((n) => !n.startsWith("-"));
822
+ return t !== void 0 && pn.has(t);
823
+ }
824
+ function wn(e, t) {
825
+ if (!at(e))
826
+ return e;
827
+ const n = st(t), o = [...e];
828
+ for (let r = 0; r < n.length; r += 2) {
829
+ const i = n[r], s = n[r + 1];
830
+ mn(e, i) || o.push(i, s);
831
+ }
832
+ return o;
833
+ }
834
+ const gn = {
980
835
  darwin: 2147578994,
981
836
  linux: 21522
982
- }, hn = 'open(my $t,"+<","/dev/tty") or exit 0; my $c="\\r"; ioctl($t,$ARGV[0]+0,$c);', fn = [250, 750];
983
- function pn(e = fn) {
984
- const t = dn[process.platform];
837
+ }, bn = 'open(my $t,"+<","/dev/tty") or exit 0; my $c="\\r"; ioctl($t,$ARGV[0]+0,$c);', yn = [250, 750];
838
+ function vn(e = yn) {
839
+ const t = gn[process.platform];
985
840
  if (t !== void 0)
986
841
  for (const n of e)
987
842
  setTimeout(() => {
988
843
  try {
989
- jt("perl", ["-e", hn, String(t)], { stdio: "ignore" }).on("error", () => {
844
+ Ot("perl", ["-e", bn, String(t)], { stdio: "ignore" }).on("error", () => {
990
845
  });
991
846
  } catch {
992
847
  }
993
848
  }, n).unref();
994
849
  }
995
- const mn = `One-time setup — how should aiui launch Claude Code?
850
+ const $n = `One-time setup — how should aiui launch Claude Code?
996
851
  With --dangerously-skip-permissions, every agent action (shell commands, file writes,
997
852
  network, the browser) runs without asking you first. Fast, and dangerous. It's a personal
998
853
  preference — aiui works fine either way. Saved as claude.skipPermissions in your user
999
- config; edit or delete it there to change your mind.`, wn = `One-time setup — where should the channel's web server bind?
854
+ config; edit or delete it there to change your mind.`, Cn = `One-time setup — where should the channel's web server bind?
1000
855
  Binding the HOST interface puts the session's whole web surface on your network,
1001
856
  UNAUTHENTICATED — the iPad paint page (\`aiui paint url\` prints its URL), but also prompt
1002
857
  injection, /debug, and every sidecar. That's the simple, single-port way to use the iPad —
1003
858
  on a network that is yours alone (a home LAN), not on café Wi-Fi. LOOPBACK keeps everything
1004
859
  this-machine-only; reaching it from an iPad is then up to you — tunnel the channel port
1005
860
  however you like (Tailscale, \`ssh -L\`). Saved as channel.bind in your user config;
1006
- --aiui-bind wins per launch.`, gn = `One-time setup — auto-dismiss Claude Code's channel prompt?
861
+ --aiui-bind wins per launch.`, kn = `One-time setup — auto-dismiss Claude Code's channel prompt?
1007
862
  aiui loads a custom development channel, so Claude Code shows a one-key acknowledgement
1008
863
  prompt at every startup. aiui can dismiss it for you: shortly after launch it injects a
1009
864
  single Enter keystroke into this terminal (a best-effort TIOCSTI ioctl on /dev/tty — it
1010
865
  literally "types" the Enter for you; on platforms that forbid that, nothing happens and
1011
866
  you press it yourself). Saying no just means pressing Enter once per launch. Saved as
1012
867
  claude.enterNudge in your user config.`;
1013
- async function bn(e, t = z) {
868
+ async function xn(e, t = W) {
1014
869
  var o, r, i;
1015
870
  let n = e;
1016
871
  if (((o = n.claude) == null ? void 0 : o.skipPermissions) === void 0) {
1017
- const s = await t(mn, [
872
+ const s = await t($n, [
1018
873
  { key: "y", label: "yes — skip permissions; nothing asks before acting" },
1019
874
  { key: "n", label: "no — keep Claude Code's own permission prompts" }
1020
875
  ]);
1021
- n = je(n, "skipPermissions", s === "y");
876
+ n = xe(n, "skipPermissions", s === "y");
1022
877
  }
1023
878
  if (((r = n.claude) == null ? void 0 : r.enterNudge) === void 0) {
1024
- const s = await t(gn, [
879
+ const s = await t(kn, [
1025
880
  { key: "y", label: "yes — press Enter for me at startup" },
1026
881
  { key: "n", label: "no — I'll press it myself each launch" }
1027
882
  ]);
1028
- n = je(n, "enterNudge", s === "y");
883
+ n = xe(n, "enterNudge", s === "y");
1029
884
  }
1030
885
  if (((i = n.channel) == null ? void 0 : i.bind) === void 0) {
1031
- const s = await t(wn, [
886
+ const s = await t(Cn, [
1032
887
  { key: "h", label: "host — reachable on my (trusted) network; the iPad just works" },
1033
888
  { key: "l", label: "loopback — this machine only; I'll tunnel when I want the iPad" }
1034
889
  ]);
1035
- n = yn(n, s === "h" ? "host" : "loopback");
890
+ n = Tn(n, s === "h" ? "host" : "loopback");
1036
891
  }
1037
892
  return n;
1038
893
  }
1039
- function je(e, t, n) {
1040
- const o = B((r) => {
894
+ function xe(e, t, n) {
895
+ const o = _((r) => {
1041
896
  r.claude = { ...r.claude, [t]: n };
1042
897
  });
1043
- return y(`wrote claude.${t}: ${n} to ${o}`), { ...e, claude: { ...e.claude, [t]: n } };
898
+ return w(`wrote claude.${t}: ${n} to ${o}`), { ...e, claude: { ...e.claude, [t]: n } };
1044
899
  }
1045
- function yn(e, t) {
1046
- const n = B((o) => {
900
+ function Tn(e, t) {
901
+ const n = _((o) => {
1047
902
  o.channel = { ...o.channel, bind: t };
1048
903
  });
1049
- return y(`wrote channel.bind: ${t} to ${n}`), { ...e, channel: { ...e.channel, bind: t } };
904
+ return w(`wrote channel.bind: ${t} to ${n}`), { ...e, channel: { ...e.channel, bind: t } };
1050
905
  }
1051
- const vn = "https://api.openai.com/v1/models", kn = 3e3;
1052
- async function Cn(e = {}) {
1053
- var c;
906
+ const In = "https://generativelanguage.googleapis.com/v1beta/models", En = 3e3;
907
+ async function Pn(e = {}) {
908
+ var a;
909
+ const {
910
+ verify: t = !0,
911
+ env: n = process.env,
912
+ fetchImpl: o = fetch,
913
+ timeoutMs: r = En
914
+ } = e, i = (a = n.GEMINI_API_KEY) == null ? void 0 : a.trim();
915
+ if (!i)
916
+ return "missing";
917
+ if (!t)
918
+ return "unverified";
919
+ const s = new AbortController(), c = setTimeout(() => s.abort(), r);
920
+ try {
921
+ const l = await o(`${In}?key=${encodeURIComponent(i)}`, {
922
+ signal: s.signal
923
+ });
924
+ return l.ok ? "valid" : l.status === 400 || l.status === 401 || l.status === 403 ? "invalid" : "unverified";
925
+ } catch {
926
+ return "unverified";
927
+ } finally {
928
+ clearTimeout(c);
929
+ }
930
+ }
931
+ function Dn(e) {
932
+ switch (e) {
933
+ case "valid":
934
+ return null;
935
+ case "missing":
936
+ return {
937
+ level: "note",
938
+ title: "GEMINI_API_KEY is not set — the realtime (Gemini Live) tier is unavailable",
939
+ detail: "Only the realtime conversational submode needs it; transcription tiers are unaffected. To enable it, export the key in the shell you run `aiui claude` from:\n export GEMINI_API_KEY=…\nIt flows through to the channel process, where the Gemini Live session runs."
940
+ };
941
+ case "invalid":
942
+ return {
943
+ level: "warn",
944
+ title: "GEMINI_API_KEY was rejected by Google — the realtime tier will fail",
945
+ detail: "The key in your environment isn't valid, so every Gemini Live session will close immediately. The usual cause is a stale shell export shadowing your real key — check what's actually set (this prints only a short prefix, not the whole secret):\n echo $GEMINI_API_KEY | head -c 8\nFix the export and relaunch `aiui claude`."
946
+ };
947
+ case "unverified":
948
+ return {
949
+ level: "note",
950
+ title: "couldn't verify GEMINI_API_KEY with Google — continuing",
951
+ detail: "The check didn't complete (offline, a timeout, or a transient error), so the key is unverified — not known-bad. Launch continues; if the realtime tier turns out unavailable, an unreachable or invalid key may be why."
952
+ };
953
+ }
954
+ }
955
+ function Sn(e) {
956
+ const t = Dn(e);
957
+ t && (t.level === "warn" ? $(t.title, t.detail) : w(t.title, t.detail));
958
+ }
959
+ const An = "https://api.openai.com/v1/models", _n = 3e3;
960
+ async function On(e = {}) {
961
+ var a;
1054
962
  const {
1055
963
  verify: t = !0,
1056
964
  env: n = process.env,
1057
965
  fetchImpl: o = fetch,
1058
- timeoutMs: r = kn
1059
- } = e, i = (c = n.OPENAI_API_KEY) == null ? void 0 : c.trim();
966
+ timeoutMs: r = _n
967
+ } = e, i = (a = n.OPENAI_API_KEY) == null ? void 0 : a.trim();
1060
968
  if (!i)
1061
969
  return "missing";
1062
970
  if (!t)
1063
971
  return "unverified";
1064
- const s = new AbortController(), a = setTimeout(() => s.abort(), r);
972
+ const s = new AbortController(), c = setTimeout(() => s.abort(), r);
1065
973
  try {
1066
- const d = await o(vn, {
974
+ const l = await o(An, {
1067
975
  headers: { authorization: `Bearer ${i}` },
1068
976
  signal: s.signal
1069
977
  });
1070
- return d.ok ? "valid" : d.status === 401 || d.status === 403 ? "invalid" : "unverified";
978
+ return l.ok ? "valid" : l.status === 401 || l.status === 403 ? "invalid" : "unverified";
1071
979
  } catch {
1072
980
  return "unverified";
1073
981
  } finally {
1074
- clearTimeout(a);
982
+ clearTimeout(c);
1075
983
  }
1076
984
  }
1077
- function $n(e) {
985
+ function jn(e) {
1078
986
  switch (e) {
1079
987
  case "valid":
1080
988
  return null;
@@ -1100,93 +1008,91 @@ and compare that against the start of your real key. Until it's fixed, transcrip
1100
1008
  };
1101
1009
  }
1102
1010
  }
1103
- function xn(e) {
1104
- const t = $n(e);
1105
- t && (t.level === "warn" ? T(t.title, t.detail) : y(t.title, t.detail));
1011
+ function Nn(e) {
1012
+ const t = jn(e);
1013
+ t && (t.level === "warn" ? $(t.title, t.detail) : w(t.title, t.detail));
1106
1014
  }
1107
- const ee = "0.3.0";
1108
- function ye(e) {
1109
- const t = (process.env.PATH ?? "").split(bt).filter(Boolean), n = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
1015
+ const he = "0.5.0";
1016
+ function Un(e) {
1017
+ const t = (process.env.PATH ?? "").split(gt).filter(Boolean), n = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
1110
1018
  for (const o of t)
1111
1019
  for (const r of n)
1112
1020
  try {
1113
- return $t(f(o, e + r), xt.X_OK), !0;
1021
+ return kt(d(o, e + r), xt.X_OK), !0;
1114
1022
  } catch {
1115
1023
  }
1116
1024
  return !1;
1117
1025
  }
1118
- const Tn = "@habemus-papadum/aiui-claude-channel", Pn = "@habemus-papadum/aiui-claude-plugin", Ue = "aiui";
1119
- async function En(e = []) {
1120
- var xe, Te, Pe;
1121
- const t = lt(e), { tag: n, passthrough: o } = t, r = ct(o);
1026
+ const Ln = "@habemus-papadum/aiui-claude-channel", Mn = "@habemus-papadum/aiui-claude-plugin", Te = "aiui";
1027
+ async function Rn(e = []) {
1028
+ var ge, be;
1029
+ const t = de(e), { tag: n, passthrough: o } = t, r = rt(o);
1122
1030
  if (r) {
1123
- r === "help" ? In() : console.log(`aiui ${ee}`), await Dn(o);
1031
+ r === "help" ? Hn() : console.log(`aiui ${he}`), await Bn(o);
1124
1032
  return;
1125
1033
  }
1126
- let i = V();
1127
- const s = On(o) && !ue();
1128
- s && (i = await bn(i));
1129
- const a = await Cn({ verify: s });
1130
- if (s && xn(a), !ut())
1034
+ let i = S();
1035
+ const s = Vn(o) && !ie();
1036
+ s && (i = await xn(i));
1037
+ const c = await On({ verify: s });
1038
+ s && Nn(c);
1039
+ const a = await Pn({ verify: s });
1040
+ if (s && Sn(a), !ct())
1131
1041
  return;
1132
- const c = P(L(Pn), "marketplace", "plugins"), d = ge(Tn), p = [...d.args, "mcp"];
1133
- n && p.push("--tag", n);
1134
- const h = t.bind ?? ((xe = i.channel) == null ? void 0 : xe.bind) ?? "loopback";
1135
- p.push("--bind", h);
1136
- const m = {
1137
- [Ue]: { command: d.command, args: p }
1042
+ const l = C(V(Mn), "marketplace", "plugins"), p = J(Ln), f = [...p.args, "mcp"];
1043
+ n && f.push("--tag", n);
1044
+ const m = it({ config: i, bind: t.bind });
1045
+ f.push(...st(m));
1046
+ const g = {
1047
+ [Te]: { command: p.command, args: f }
1138
1048
  };
1139
- let b = { enabled: !1 };
1140
- if (ot(t, i.chrome)) {
1141
- const E = {
1049
+ let y = { enabled: !1 };
1050
+ if (qe(t, i.chrome)) {
1051
+ const X = {
1142
1052
  ...i.chrome,
1143
1053
  ...t.browserUrl ? { browserUrl: t.browserUrl } : {}
1144
- }, _ = await Sn(t, E, s);
1145
- m[Jt] = _.entry, b = _.info;
1054
+ }, ye = await Fn(t, X, s);
1055
+ g[Ht] = ye.entry, y = ye.info;
1146
1056
  }
1147
- const w = {
1057
+ const I = {
1148
1058
  launcher: "aiui claude",
1149
- chromeDevtools: b,
1150
- openaiKey: a
1059
+ chromeDevtools: y,
1060
+ openaiKey: c,
1061
+ geminiKey: a
1151
1062
  };
1152
- p.push("--launch-info", JSON.stringify(w));
1153
- const C = [...t.sidecar], x = [...t.noSidecar];
1154
- for (const [E, _] of Object.entries(i.sidecars ?? {}))
1155
- _ === void 0 || C.includes(E) || x.includes(E) || (_ ? C : x).push(E);
1156
- const N = Ut(process.cwd(), { enable: C, disable: x });
1157
- N.length > 0 && p.push("--sidecars", JSON.stringify(N));
1158
- const u = JSON.stringify({ mcpServers: m }), Ce = [f(c, "aiui"), f(c, "frontend-design")];
1159
- b.enabled && Ce.push(f(c, "session-browser"));
1160
- const wt = [
1161
- ...((Te = i.claude) == null ? void 0 : Te.skipPermissions) ?? !0 ? ["--dangerously-skip-permissions"] : [],
1063
+ f.push("--launch-info", JSON.stringify(I));
1064
+ const h = JSON.stringify({ mcpServers: g }), me = [d(l, "aiui"), d(l, "frontend-design")];
1065
+ y.enabled && me.push(d(l, "session-browser"));
1066
+ const mt = [
1067
+ ...((ge = i.claude) == null ? void 0 : ge.skipPermissions) ?? !0 ? ["--dangerously-skip-permissions"] : [],
1162
1068
  "--mcp-config",
1163
- u,
1164
- ...Ce.flatMap((E) => ["--plugin-dir", E]),
1069
+ h,
1070
+ ...me.flatMap((X) => ["--plugin-dir", X]),
1165
1071
  // Custom channels are a research preview and not on the approved allowlist,
1166
1072
  // so opt this session into loading ours as a development channel.
1167
1073
  "--dangerously-load-development-channels",
1168
- `server:${Ue}`
1074
+ `server:${Te}`
1169
1075
  ];
1170
- s && (((Pe = i.claude) == null ? void 0 : Pe.enterNudge) ?? !0) && pn();
1171
- const $e = await k("claude", [...wt, ...o], {
1076
+ s && (((be = i.claude) == null ? void 0 : be.enterNudge) ?? !0) && vn();
1077
+ const we = await T("claude", [...mt, ...o], {
1172
1078
  stdio: "inherit",
1173
1079
  reject: !1
1174
1080
  });
1175
- $e.exitCode && (process.exitCode = $e.exitCode);
1081
+ we.exitCode && (process.exitCode = we.exitCode);
1176
1082
  }
1177
- function ut() {
1178
- return ye("claude") ? !0 : (g(
1083
+ function ct() {
1084
+ return Un("claude") ? !0 : (b(
1179
1085
  "`claude` was not found on your PATH",
1180
1086
  "Install Claude Code and make sure the `claude` command is available, then try again."
1181
1087
  ), process.exitCode = 1, !1);
1182
1088
  }
1183
- async function Dn(e) {
1184
- if (!ut())
1089
+ async function Bn(e) {
1090
+ if (!ct())
1185
1091
  return;
1186
- const t = await k("claude", e, { stdio: "inherit", reject: !1 });
1092
+ const t = await T("claude", e, { stdio: "inherit", reject: !1 });
1187
1093
  t.exitCode && (process.exitCode = t.exitCode);
1188
1094
  }
1189
- function In() {
1095
+ function Hn() {
1190
1096
  console.log(`aiui claude — launch Claude Code wired with the aiui channel, plugin, and browser MCP
1191
1097
 
1192
1098
  aiui's own flags (everything else forwards to claude verbatim):
@@ -1202,26 +1108,29 @@ aiui's own flags (everything else forwards to claude verbatim):
1202
1108
  whole network can reach the session's web
1203
1109
  surface — the iPad paint page included;
1204
1110
  trusted networks only)
1205
- --aiui-sidecar <name> host this session sidecar (repeatable);
1206
- \`paint\` (iPad ink) is always on
1207
- --aiui-no-sidecar <name> don't host this session sidecar (repeatable)
1208
1111
 
1112
+ Every channel hosts the same session sidecars — paint (iPad ink), the intent panel
1113
+ at /intent/, the remote bar, and the remote pencil — reachable per --aiui-bind.
1209
1114
  Durable settings live in config.json (project .aiui-cache/ + user cache) — see the
1210
1115
  Configuration guide. What follows is claude's own --help:
1211
1116
  `);
1212
1117
  }
1213
- async function Sn(e, t, n) {
1118
+ async function Fn(e, t, n) {
1214
1119
  if (t.browserUrl)
1215
1120
  return {
1216
- entry: te(t.browserUrl),
1121
+ entry: Z(t.browserUrl),
1217
1122
  info: { enabled: !0, connection: "attach", browserUrl: t.browserUrl }
1218
1123
  };
1219
- let o = { ...t }, r = D(e, o);
1124
+ let o = { ...t }, r = x(e, o);
1220
1125
  if (r.mode === "attach") {
1221
- const a = await F(r.userDataDir);
1126
+ const a = await U(r.userDataDir);
1222
1127
  if (a)
1223
- return {
1224
- entry: te(a.browserUrl),
1128
+ return B(
1129
+ r.userDataDir,
1130
+ j().state === "ready",
1131
+ $
1132
+ ), {
1133
+ entry: Z(a.browserUrl),
1225
1134
  info: {
1226
1135
  enabled: !0,
1227
1136
  connection: "attach",
@@ -1231,59 +1140,59 @@ async function Sn(e, t, n) {
1231
1140
  };
1232
1141
  }
1233
1142
  if (!o.executablePath && !o.channel) {
1234
- const a = await tt({ mode: o.forTesting ?? "prompt", interactive: n });
1235
- a && (o = { ...o, executablePath: a }, r = D(e, o));
1143
+ const a = await We({ mode: o.forTesting ?? "prompt", interactive: n });
1144
+ a && (o = { ...o, executablePath: a }, r = x(e, o));
1236
1145
  }
1237
- W(r.userDataDir, { recursive: !0 }), r.buildExtension && await be();
1238
- const i = Z();
1239
- n && it(r, i);
1240
- const s = {
1146
+ G(r.userDataDir, { recursive: !0 });
1147
+ const i = j(), s = i.state === "ready" ? [i.dir] : [];
1148
+ B(r.userDataDir, i.state === "ready", $), n && (Xe(r, s), Je(i));
1149
+ const c = {
1241
1150
  userDataDir: r.userDataDir,
1242
1151
  executablePath: r.executablePath,
1243
1152
  channel: r.channel,
1244
1153
  headless: r.headless,
1245
- extensionDir: i
1154
+ extensionDirs: s
1246
1155
  };
1247
1156
  if (r.mode === "attach" && n)
1248
1157
  try {
1249
- const a = await Ve({
1250
- binary: Fe(r),
1158
+ const a = await je({
1159
+ binary: Oe(r),
1251
1160
  userDataDir: r.userDataDir,
1252
1161
  debugPort: r.debugPort,
1253
- extensionDir: i,
1162
+ extensionDirs: s,
1254
1163
  headless: r.headless
1255
1164
  });
1256
1165
  return {
1257
- entry: te(a.browserUrl),
1166
+ entry: Z(a.browserUrl),
1258
1167
  info: {
1259
1168
  enabled: !0,
1260
1169
  connection: "attach",
1261
1170
  browserUrl: a.browserUrl,
1262
- ...s
1171
+ ...c
1263
1172
  }
1264
1173
  };
1265
1174
  } catch (a) {
1266
- T(
1175
+ $(
1267
1176
  "couldn't start the session browser — falling back to a browser private to the MCP",
1268
1177
  a instanceof Error ? a.message : String(a)
1269
1178
  );
1270
1179
  }
1271
1180
  return {
1272
- entry: Qt(r, i),
1273
- info: { enabled: !0, connection: "launch", ...s }
1181
+ entry: qt(r, s),
1182
+ info: { enabled: !0, connection: "launch", ...c }
1274
1183
  };
1275
1184
  }
1276
- function On(e) {
1185
+ function Vn(e) {
1277
1186
  return !process.stdin.isTTY || !process.stdout.isTTY ? !1 : !e.some((t) => t === "-p" || t === "--print");
1278
1187
  }
1279
- function jn(e = process.cwd()) {
1188
+ function Gn(e = process.cwd()) {
1280
1189
  return {
1281
- project: de(e),
1282
- user: Y(void 0, { create: !1 }),
1190
+ project: Be(e),
1191
+ user: F(void 0, { create: !1 }),
1283
1192
  browser: A(!1)
1284
1193
  };
1285
1194
  }
1286
- function Un(e, t) {
1195
+ function Kn(e, t) {
1287
1196
  const n = [];
1288
1197
  return e.userOnly || n.push({ label: "project cache", path: t.project }), e.projectOnly || n.push(
1289
1198
  e.keepBrowser ? {
@@ -1293,30 +1202,30 @@ function Un(e, t) {
1293
1202
  } : { label: "user cache", path: t.user }
1294
1203
  ), n;
1295
1204
  }
1296
- function An(e) {
1205
+ function Yn(e) {
1297
1206
  var o;
1298
1207
  if (!v(e.path))
1299
1208
  return [];
1300
1209
  if (!((o = e.keep) != null && o.length))
1301
1210
  return [e.path];
1302
- const t = new Set(e.keep.map((r) => P(r)));
1211
+ const t = new Set(e.keep.map((r) => C(r)));
1303
1212
  let n;
1304
1213
  try {
1305
- n = G(e.path);
1214
+ n = Y(e.path);
1306
1215
  } catch {
1307
1216
  return [];
1308
1217
  }
1309
- return n.map((r) => P(f(e.path, r))).filter((r) => !t.has(r));
1218
+ return n.map((r) => C(d(e.path, r))).filter((r) => !t.has(r));
1310
1219
  }
1311
- async function Nn(e = {}) {
1220
+ async function Wn(e = {}) {
1312
1221
  if (e.projectOnly && e.userOnly) {
1313
- g(
1222
+ b(
1314
1223
  "pass at most one of --project-only / --user-only",
1315
1224
  "with neither, `aiui clean` removes both"
1316
1225
  ), process.exitCode = 1;
1317
1226
  return;
1318
1227
  }
1319
- const t = process.cwd(), o = Un(e, jn(t)).map((h) => ({ target: h, paths: An(h) })).filter((h) => h.paths.length > 0);
1228
+ const t = process.cwd(), o = Kn(e, Gn(t)).map((f) => ({ target: f, paths: Yn(f) })).filter((f) => f.paths.length > 0);
1320
1229
  if (o.length === 0) {
1321
1230
  console.log("nothing to clean — no aiui state here or in the user cache.");
1322
1231
  return;
@@ -1324,39 +1233,39 @@ async function Nn(e = {}) {
1324
1233
  let r = 0;
1325
1234
  console.log(`aiui clean will remove:
1326
1235
  `);
1327
- for (const { target: h, paths: m } of o) {
1328
- const b = m.reduce((w, C) => w + le(C), 0);
1329
- r += b, console.log(` ${ne(b).padStart(9)} ${h.label}`), console.log(` ${" ".repeat(9)} ${l.dim(h.path)}`);
1236
+ for (const { target: f, paths: m } of o) {
1237
+ const g = m.reduce((y, I) => y + re(I), 0);
1238
+ r += g, console.log(` ${Q(g).padStart(9)} ${f.label}`), console.log(` ${" ".repeat(9)} ${u.dim(f.path)}`);
1330
1239
  }
1331
1240
  console.log(`
1332
- ${ne(r).padStart(9)} total
1241
+ ${Q(r).padStart(9)} total
1333
1242
  `);
1334
- const i = !e.projectOnly, s = i && !e.keepBrowser, a = [
1243
+ const i = !e.projectOnly, s = i && !e.keepBrowser, c = [
1335
1244
  "traces and session-browser logins are cleared",
1336
1245
  i && "the Claude permission prompt (claude.skipPermissions) returns on next launch",
1337
1246
  s && "Chrome for Testing re-downloads (~160 MB) on the next `aiui claude`"
1338
- ].filter((h) => !!h);
1247
+ ].filter((f) => !!f);
1339
1248
  console.log("This resets aiui toward a fresh install:");
1340
- for (const h of a)
1341
- console.log(` • ${h}`);
1249
+ for (const f of c)
1250
+ console.log(` • ${f}`);
1342
1251
  console.log("");
1343
- const c = J(t);
1344
- if (c.length && T(
1345
- `${c.length} aiui session${c.length === 1 ? "" : "s"} still running`,
1252
+ const a = M(t);
1253
+ if (a.length && $(
1254
+ `${a.length} aiui session${a.length === 1 ? "" : "s"} still running`,
1346
1255
  "stop them first — a live session rewrites its registry entry as it exits, and an open browser can lock files being deleted"
1347
1256
  ), e.dryRun) {
1348
- y("dry run — nothing was deleted");
1257
+ w("dry run — nothing was deleted");
1349
1258
  return;
1350
1259
  }
1351
1260
  if (!e.yes) {
1352
1261
  if (!process.stdin.isTTY) {
1353
- g(
1262
+ b(
1354
1263
  "refusing to delete without confirmation",
1355
1264
  "re-run with --yes for a non-interactive clean, or from a terminal"
1356
1265
  ), process.exitCode = 1;
1357
1266
  return;
1358
1267
  }
1359
- if (await z(
1268
+ if (await W(
1360
1269
  "Delete these now?",
1361
1270
  [
1362
1271
  { key: "y", label: "yes, delete" },
@@ -1368,28 +1277,28 @@ async function Nn(e = {}) {
1368
1277
  return;
1369
1278
  }
1370
1279
  }
1371
- let d = 0, p = 0;
1372
- for (const { paths: h } of o)
1373
- for (const m of h) {
1374
- const b = le(m);
1280
+ let l = 0, p = 0;
1281
+ for (const { paths: f } of o)
1282
+ for (const m of f) {
1283
+ const g = re(m);
1375
1284
  try {
1376
- Tt(m, { recursive: !0, force: !0 }), d += b;
1377
- } catch (w) {
1378
- p++, T(
1285
+ Tt(m, { recursive: !0, force: !0 }), l += g;
1286
+ } catch (y) {
1287
+ p++, $(
1379
1288
  `could not remove ${m}`,
1380
- w instanceof Error ? w.message : String(w)
1289
+ y instanceof Error ? y.message : String(y)
1381
1290
  );
1382
1291
  }
1383
1292
  }
1384
- p && T(
1293
+ p && $(
1385
1294
  `${p} path${p === 1 ? "" : "s"} could not be deleted`,
1386
1295
  "a running browser can lock its files — close the session browser and re-run"
1387
- ), console.log(`clean complete — freed ~${ne(d)}.`);
1296
+ ), console.log(`clean complete — freed ~${Q(l)}.`);
1388
1297
  }
1389
- function le(e) {
1298
+ function re(e) {
1390
1299
  let t;
1391
1300
  try {
1392
- t = Pt(e);
1301
+ t = It(e);
1393
1302
  } catch {
1394
1303
  return 0;
1395
1304
  }
@@ -1397,16 +1306,16 @@ function le(e) {
1397
1306
  return t.size;
1398
1307
  let n;
1399
1308
  try {
1400
- n = G(e);
1309
+ n = Y(e);
1401
1310
  } catch {
1402
1311
  return 0;
1403
1312
  }
1404
1313
  let o = 0;
1405
1314
  for (const r of n)
1406
- o += le(f(e, r));
1315
+ o += re(d(e, r));
1407
1316
  return o;
1408
1317
  }
1409
- function ne(e) {
1318
+ function Q(e) {
1410
1319
  if (e < 1024)
1411
1320
  return `${e} B`;
1412
1321
  const t = ["KB", "MB", "GB", "TB"];
@@ -1415,35 +1324,35 @@ function ne(e) {
1415
1324
  n /= 1024, o++;
1416
1325
  return `${n.toFixed(1)} ${t[o]}`;
1417
1326
  }
1418
- function j(e = process.cwd()) {
1419
- const t = he(e);
1327
+ function D(e = process.cwd()) {
1328
+ const t = St(e);
1420
1329
  return {
1421
1330
  paths: t,
1422
- user: O(t.user) ?? {},
1423
- project: O(t.project) ?? {}
1331
+ user: ne(t.user) ?? {},
1332
+ project: ne(t.project) ?? {}
1424
1333
  };
1425
1334
  }
1426
- function ve(e) {
1427
- return Je().map((t) => {
1428
- const n = Ae(e.user, t), o = Ae(e.project, t), r = o ?? n, i = o !== void 0 ? "project" : n !== void 0 ? "user" : t.field.default !== void 0 ? "default" : "unset";
1335
+ function fe(e) {
1336
+ return Me().map((t) => {
1337
+ const n = Ie(e.user, t), o = Ie(e.project, t), r = o ?? n, i = o !== void 0 ? "project" : n !== void 0 ? "user" : t.field.default !== void 0 ? "default" : "unset";
1429
1338
  return { ...t, userValue: n, projectValue: o, effective: r, source: i };
1430
1339
  });
1431
1340
  }
1432
- function Ae(e, t) {
1341
+ function Ie(e, t) {
1433
1342
  var o;
1434
1343
  return (o = e[t.section.name]) == null ? void 0 : o[t.field.key];
1435
1344
  }
1436
- function ke(e, t) {
1437
- const n = ve(t).find((o) => o.path === e);
1438
- return n || (g(
1345
+ function pe(e, t) {
1346
+ const n = fe(t).find((o) => o.path === e);
1347
+ return n || (b(
1439
1348
  `unknown config key: ${e}`,
1440
1349
  `Known keys:
1441
- ${Je().map((o) => o.path).join(`
1350
+ ${Me().map((o) => o.path).join(`
1442
1351
  `)}`
1443
1352
  ), process.exitCode = 1), n;
1444
1353
  }
1445
- function _n(e = {}, t = process.cwd()) {
1446
- const n = j(t), o = ve(n);
1354
+ function qn(e = {}, t = process.cwd()) {
1355
+ const n = D(t), o = fe(n);
1447
1356
  if (e.json) {
1448
1357
  console.log(
1449
1358
  JSON.stringify(
@@ -1454,7 +1363,7 @@ function _n(e = {}, t = process.cwd()) {
1454
1363
  },
1455
1364
  user: n.user,
1456
1365
  project: n.project,
1457
- effective: Qe(n.user, n.project)
1366
+ effective: Dt(n.user, n.project)
1458
1367
  },
1459
1368
  null,
1460
1369
  2
@@ -1462,95 +1371,95 @@ function _n(e = {}, t = process.cwd()) {
1462
1371
  );
1463
1372
  return;
1464
1373
  }
1465
- console.log(`user: ${n.paths.user}${Ne(n.paths.user)}`), console.log(`project: ${n.paths.project}${Ne(n.paths.project)}`);
1374
+ console.log(`user: ${n.paths.user}${Ee(n.paths.user)}`), console.log(`project: ${n.paths.project}${Ee(n.paths.project)}`);
1466
1375
  const r = Math.max(...o.map((s) => s.path.length));
1467
1376
  let i = "";
1468
1377
  for (const s of o)
1469
1378
  s.section.name !== i && (i = s.section.name, console.log(`
1470
- ${l.bold(i)} ${l.dim(`— ${s.section.summary}`)}`)), console.log(` ${s.path.padEnd(r + 2)}${dt(s)}`);
1379
+ ${u.bold(i)} ${u.dim(`— ${s.section.summary}`)}`)), console.log(` ${s.path.padEnd(r + 2)}${lt(s)}`);
1471
1380
  console.log(
1472
- l.dim(
1381
+ u.dim(
1473
1382
  "\nProject beats user per key; CLI flags beat both. `aiui config` browses the docs interactively."
1474
1383
  )
1475
1384
  );
1476
1385
  }
1477
- function Ne(e) {
1478
- return v(e) ? "" : l.dim(" (not present)");
1386
+ function Ee(e) {
1387
+ return v(e) ? "" : u.dim(" (not present)");
1479
1388
  }
1480
- function dt(e) {
1481
- return e.effective !== void 0 ? `${l.cyan($(e.effective))} ${l.dim(`(${e.source})`)}` : l.dim(
1482
- e.field.default !== void 0 ? `default: ${$(e.field.default)}` : "unset"
1389
+ function lt(e) {
1390
+ return e.effective !== void 0 ? `${u.cyan(k(e.effective))} ${u.dim(`(${e.source})`)}` : u.dim(
1391
+ e.field.default !== void 0 ? `default: ${k(e.field.default)}` : "unset"
1483
1392
  );
1484
1393
  }
1485
- function Rn(e, t = process.cwd()) {
1486
- const n = j(t), o = ke(e, n);
1394
+ function zn(e, t = process.cwd()) {
1395
+ const n = D(t), o = pe(e, n);
1487
1396
  if (o) {
1488
1397
  if (o.effective !== void 0) {
1489
1398
  console.log(String(o.effective));
1490
1399
  const r = o.source === "project" ? n.paths.project : n.paths.user;
1491
- console.error(l.dim(`# set in the ${o.source} config: ${r}`));
1400
+ console.error(u.dim(`# set in the ${o.source} config: ${r}`));
1492
1401
  return;
1493
1402
  }
1494
1403
  if (o.field.default !== void 0) {
1495
- console.log(String(o.field.default)), console.error(l.dim(`# built-in default — ${ce(o.field)}`));
1404
+ console.log(String(o.field.default)), console.error(u.dim(`# built-in default — ${ee(o.field)}`));
1496
1405
  return;
1497
1406
  }
1498
1407
  console.error(
1499
- l.dim(`# not set in any config file — default: ${ce(o.field)}`)
1408
+ u.dim(`# not set in any config file — default: ${ee(o.field)}`)
1500
1409
  );
1501
1410
  }
1502
1411
  }
1503
- function Ln(e, t, n = {}, o = process.cwd()) {
1504
- const r = j(o), i = ke(e, r);
1412
+ function Jn(e, t, n = {}, o = process.cwd()) {
1413
+ const r = D(o), i = pe(e, r);
1505
1414
  if (!i)
1506
1415
  return;
1507
- const s = ae(i.field, t);
1416
+ const s = te(i.field, t);
1508
1417
  if ("error" in s) {
1509
- g(`invalid value for ${i.path}: ${t}`, s.error), process.exitCode = 1;
1418
+ b(`invalid value for ${i.path}: ${t}`, s.error), process.exitCode = 1;
1510
1419
  return;
1511
1420
  }
1512
- ht(r, i, s.value, n.project ? "project" : "user");
1421
+ ut(r, i, s.value, n.project ? "project" : "user");
1513
1422
  }
1514
- function ht(e, t, n, o) {
1515
- const r = fe(e.paths[o], (i) => {
1423
+ function ut(e, t, n, o) {
1424
+ const r = Re(e.paths[o], (i) => {
1516
1425
  const s = i;
1517
1426
  s[t.section.name] = { ...s[t.section.name], [t.field.key]: n };
1518
1427
  });
1519
- y(`wrote ${t.path}: ${$(n)} to ${r}`);
1428
+ w(`wrote ${t.path}: ${k(n)} to ${r}`);
1520
1429
  }
1521
- function Mn(e, t = {}, n = process.cwd()) {
1522
- const o = j(n), r = ke(e, o);
1523
- r && ft(o, r, t.project ? "project" : "user");
1430
+ function Xn(e, t = {}, n = process.cwd()) {
1431
+ const o = D(n), r = pe(e, o);
1432
+ r && dt(o, r, t.project ? "project" : "user");
1524
1433
  }
1525
- function ft(e, t, n) {
1526
- var a;
1434
+ function dt(e, t, n) {
1435
+ var c;
1527
1436
  const o = e.paths[n];
1528
- if (((a = (O(o) ?? {})[t.section.name]) == null ? void 0 : a[t.field.key]) === void 0) {
1529
- y(`${t.path} is not set in the ${n} config (${o})`);
1437
+ if (((c = (ne(o) ?? {})[t.section.name]) == null ? void 0 : c[t.field.key]) === void 0) {
1438
+ w(`${t.path} is not set in the ${n} config (${o})`);
1530
1439
  return;
1531
1440
  }
1532
- const s = fe(o, (c) => {
1533
- const d = c, p = { ...d[t.section.name] };
1534
- delete p[t.field.key], Object.keys(p).length === 0 ? delete d[t.section.name] : d[t.section.name] = p;
1441
+ const s = Re(o, (a) => {
1442
+ const l = a, p = { ...l[t.section.name] };
1443
+ delete p[t.field.key], Object.keys(p).length === 0 ? delete l[t.section.name] : l[t.section.name] = p;
1535
1444
  });
1536
- y(`removed ${t.path} from ${s}`);
1445
+ w(`removed ${t.path} from ${s}`);
1537
1446
  }
1538
- async function _e(e = process.cwd()) {
1447
+ async function Pe(e = process.cwd()) {
1539
1448
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
1540
- g(
1449
+ b(
1541
1450
  "aiui config tui needs an interactive terminal",
1542
1451
  "In scripts and non-TTY sessions use `aiui config show` (or `show --json`)."
1543
1452
  ), process.exitCode = 1;
1544
1453
  return;
1545
1454
  }
1546
- const t = j(e).paths;
1547
- console.log(l.dim(`user: ${Le(t.user)}`)), console.log(l.dim(`project: ${Le(t.project)}`));
1455
+ const t = D(e).paths;
1456
+ console.log(u.dim(`user: ${Se(t.user)}`)), console.log(u.dim(`project: ${Se(t.project)}`));
1548
1457
  try {
1549
1458
  for (; ; ) {
1550
- const n = j(e), o = await Bn(n);
1459
+ const n = D(e), o = await Zn(n);
1551
1460
  if (!o)
1552
1461
  return;
1553
- await Vn(n, o);
1462
+ await eo(n, o);
1554
1463
  }
1555
1464
  } catch (n) {
1556
1465
  if (n instanceof Error && n.name === "ExitPromptError")
@@ -1558,35 +1467,35 @@ async function _e(e = process.cwd()) {
1558
1467
  throw n;
1559
1468
  }
1560
1469
  }
1561
- async function Bn(e) {
1562
- const t = ve(e), n = Math.max(...t.map((r) => r.path.length)) + 2, o = [];
1563
- for (const r of M) {
1564
- o.push(new ie(l.dim(`── ${r.name} — ${r.summary}`)));
1470
+ async function Zn(e) {
1471
+ const t = fe(e), n = Math.max(...t.map((r) => r.path.length)) + 2, o = [];
1472
+ for (const r of At) {
1473
+ o.push(new oe(u.dim(`── ${r.name} — ${r.summary}`)));
1565
1474
  for (const i of t.filter((s) => s.section.name === r.name))
1566
1475
  o.push({
1567
- name: `${i.path.padEnd(n)}${dt(i)}`,
1476
+ name: `${i.path.padEnd(n)}${lt(i)}`,
1568
1477
  value: i,
1569
- description: Fn(i)
1478
+ description: Qn(i)
1570
1479
  });
1571
1480
  }
1572
- return o.push(new ie(" ")), o.push({ name: "exit", value: void 0, description: "Leave the config browser." }), K({
1481
+ return o.push(new oe(" ")), o.push({ name: "exit", value: void 0, description: "Leave the config browser." }), O({
1573
1482
  message: "aiui config",
1574
1483
  choices: o,
1575
1484
  pageSize: o.length,
1576
1485
  loop: !1
1577
1486
  });
1578
1487
  }
1579
- function Fn(e) {
1580
- const t = [l.bold(e.field.summary)];
1581
- return e.field.doc && t.push(Kn(e.field.doc, 76)), t.push(""), e.field.type === "enum" && t.push(`allowed: ${(e.field.values ?? []).join(" | ")}`), t.push(`default: ${ce(e.field)}`), t.push(`user: ${Re(e.userValue)}`), t.push(`project: ${Re(e.projectValue)}`), t.push(
1582
- `effective: ${e.effective !== void 0 ? `${$(e.effective)} (from the ${e.source} config)` : "the built-in default"}`
1488
+ function Qn(e) {
1489
+ const t = [u.bold(e.field.summary)];
1490
+ return e.field.doc && t.push(no(e.field.doc, 76)), t.push(""), e.field.type === "enum" && t.push(`allowed: ${(e.field.values ?? []).join(" | ")}`), t.push(`default: ${ee(e.field)}`), t.push(`user: ${De(e.userValue)}`), t.push(`project: ${De(e.projectValue)}`), t.push(
1491
+ `effective: ${e.effective !== void 0 ? `${k(e.effective)} (from the ${e.source} config)` : "the built-in default"}`
1583
1492
  ), t.join(`
1584
1493
  `);
1585
1494
  }
1586
- function Re(e) {
1587
- return e === void 0 ? l.dim("(not set)") : $(e);
1495
+ function De(e) {
1496
+ return e === void 0 ? u.dim("(not set)") : k(e);
1588
1497
  }
1589
- async function Vn(e, t) {
1498
+ async function eo(e, t) {
1590
1499
  const n = [
1591
1500
  {
1592
1501
  name: "set in the user config",
@@ -1602,13 +1511,13 @@ This project only; the file may be shared or committed by a team.`
1602
1511
  }
1603
1512
  ];
1604
1513
  t.userValue !== void 0 && n.push({
1605
- name: `unset in the user config (currently ${$(t.userValue)})`,
1514
+ name: `unset in the user config (currently ${k(t.userValue)})`,
1606
1515
  value: "unset-user"
1607
1516
  }), t.projectValue !== void 0 && n.push({
1608
- name: `unset in the project config (currently ${$(t.projectValue)})`,
1517
+ name: `unset in the project config (currently ${k(t.projectValue)})`,
1609
1518
  value: "unset-project"
1610
- }), n.push(new ie()), n.push({ name: "back", value: "back" });
1611
- const o = await K({
1519
+ }), n.push(new oe()), n.push({ name: "back", value: "back" });
1520
+ const o = await O({
1612
1521
  message: `${t.path} — ${t.field.summary}`,
1613
1522
  choices: n
1614
1523
  });
@@ -1616,45 +1525,45 @@ This project only; the file may be shared or committed by a team.`
1616
1525
  return;
1617
1526
  const r = o.endsWith("project") ? "project" : "user";
1618
1527
  if (o.startsWith("unset")) {
1619
- ft(e, t, r);
1528
+ dt(e, t, r);
1620
1529
  return;
1621
1530
  }
1622
- const i = await Hn(t);
1623
- i !== void 0 && ht(e, t, i, r);
1531
+ const i = await to(t);
1532
+ i !== void 0 && ut(e, t, i, r);
1624
1533
  }
1625
- async function Hn(e) {
1534
+ async function to(e) {
1626
1535
  const t = (r) => r === e.effective ? " (current)" : r === e.field.default ? " (default)" : "";
1627
1536
  if (e.field.type === "boolean")
1628
- return K({
1537
+ return O({
1629
1538
  message: `${e.path} =`,
1630
1539
  choices: [!0, !1].map((r) => ({
1631
- name: `${r}${l.dim(t(r))}`,
1540
+ name: `${r}${u.dim(t(r))}`,
1632
1541
  value: r
1633
1542
  }))
1634
1543
  });
1635
1544
  if (e.field.type === "enum")
1636
- return K({
1545
+ return O({
1637
1546
  message: `${e.path} =`,
1638
1547
  choices: (e.field.values ?? []).map((r) => ({
1639
- name: `${r}${l.dim(t(r))}`,
1548
+ name: `${r}${u.dim(t(r))}`,
1640
1549
  value: r
1641
1550
  }))
1642
1551
  });
1643
- const n = await _t({
1552
+ const n = await jt({
1644
1553
  message: `${e.path} = `,
1645
1554
  default: e.effective !== void 0 ? String(e.effective) : void 0,
1646
1555
  validate: (r) => {
1647
- const i = ae(e.field, r);
1556
+ const i = te(e.field, r);
1648
1557
  return "error" in i ? i.error : !0;
1649
1558
  }
1650
- }), o = ae(e.field, n);
1559
+ }), o = te(e.field, n);
1651
1560
  return "error" in o ? void 0 : o.value;
1652
1561
  }
1653
- function Le(e) {
1654
- const t = At();
1562
+ function Se(e) {
1563
+ const t = se();
1655
1564
  return e.startsWith(t) ? `~${e.slice(t.length)}` : e;
1656
1565
  }
1657
- function Kn(e, t) {
1566
+ function no(e, t) {
1658
1567
  const n = [];
1659
1568
  let o = "";
1660
1569
  for (const r of e.split(/\s+/))
@@ -1662,8 +1571,7 @@ function Kn(e, t) {
1662
1571
  return o && n.push(o), n.join(`
1663
1572
  `);
1664
1573
  }
1665
- const Yn = "vite", oe = "VITE_AIUI_PORT";
1666
- function pt(e, t) {
1574
+ function oo(e, t) {
1667
1575
  if (t !== void 0) {
1668
1576
  const n = e.find((o) => o.tag === t);
1669
1577
  if (!n) {
@@ -1676,49 +1584,42 @@ function pt(e, t) {
1676
1584
  }
1677
1585
  return e.length > 0 ? { select: e } : {};
1678
1586
  }
1679
- async function Wn(e = []) {
1680
- const t = lt(e), { mcp: n, tag: o, passthrough: r } = t, i = ct(r);
1587
+ const ro = "vite";
1588
+ async function io(e = []) {
1589
+ const t = de(e), { mcp: n, tag: o, passthrough: r } = t, i = rt(r);
1681
1590
  if (i) {
1682
- i === "help" ? Qn() : console.log(`aiui ${ee}`), await Xn(r);
1683
- return;
1684
- }
1685
- const s = n ?? o, a = pt(J(), s);
1686
- if (a.error) {
1687
- g("Could not resolve an aiui channel", a.error), process.exitCode = 1;
1591
+ i === "help" ? uo() : console.log(`aiui ${he}`), await lo(r);
1688
1592
  return;
1689
1593
  }
1690
- const c = a.select ? await qe(a.select) : a.server;
1691
- let d;
1692
- c ? (d = String(c.port), console.error(
1693
- l.dim(
1694
- `aiui: connecting vite to channel "${c.tag}" (${c.cwd}) on port ${d} via ${oe}`
1695
- )
1696
- )) : console.error(l.dim(`aiui: no running channel found — ${oe} left unset`));
1697
- const p = mt();
1698
- if (!p)
1594
+ (n !== void 0 || o !== void 0) && $(
1595
+ "aiui vite no longer connects the app to a channel",
1596
+ "--aiui-mcp / --aiui-tag are ignored. The app reaches the channel through the intent client served at /intent/, not a build-time port. (The standalone panel's own `pnpm dev` still selects a channel — that page is served on Vite's origin, not the channel's.)"
1597
+ );
1598
+ const s = ft();
1599
+ if (!s)
1699
1600
  return;
1700
- const h = {};
1701
- d && (h[oe] = d), process.stdout.isTTY && !("FORCE_COLOR" in process.env) && !("NO_COLOR" in process.env) && (h.FORCE_COLOR = "1");
1702
- const m = k(p.command, [...p.args, ...r], {
1601
+ const c = {};
1602
+ process.stdout.isTTY && !("FORCE_COLOR" in process.env) && !("NO_COLOR" in process.env) && (c.FORCE_COLOR = "1");
1603
+ const a = T(s.command, [...s.args, ...r], {
1703
1604
  stdio: ["inherit", "pipe", "inherit"],
1704
1605
  buffer: !1,
1705
1606
  reject: !1,
1706
- env: h
1607
+ env: c
1707
1608
  });
1708
- m.stdout && Jn(m.stdout, process.stdout, (w) => {
1709
- zn(w, t);
1609
+ a.stdout && co(a.stdout, process.stdout, (p) => {
1610
+ ht(p, t);
1710
1611
  });
1711
- const b = await m;
1712
- b.exitCode && (process.exitCode = b.exitCode);
1612
+ const l = await a;
1613
+ l.exitCode && (process.exitCode = l.exitCode);
1713
1614
  }
1714
- const qn = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
1715
- function Gn(e) {
1716
- const n = e.replace(qn, "").match(
1615
+ const so = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
1616
+ function ao(e) {
1617
+ const n = e.replace(so, "").match(
1717
1618
  /\bLocal:\s+(https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?\/?\S*)/
1718
1619
  );
1719
1620
  return n == null ? void 0 : n[1];
1720
1621
  }
1721
- function Jn(e, t, n) {
1622
+ function co(e, t, n) {
1722
1623
  let o = "", r = !1;
1723
1624
  e.on("data", (i) => {
1724
1625
  if (t.write(i), !r) {
@@ -1727,11 +1628,11 @@ function Jn(e, t, n) {
1727
1628
  `);
1728
1629
  if (s === -1)
1729
1630
  break;
1730
- const a = o.slice(0, s);
1631
+ const c = o.slice(0, s);
1731
1632
  o = o.slice(s + 1);
1732
- const c = Gn(a);
1733
- if (c) {
1734
- r = !0, o = "", n(c);
1633
+ const a = ao(c);
1634
+ if (a) {
1635
+ r = !0, o = "", n(a);
1735
1636
  return;
1736
1637
  }
1737
1638
  }
@@ -1739,16 +1640,16 @@ function Jn(e, t, n) {
1739
1640
  }
1740
1641
  });
1741
1642
  }
1742
- async function zn(e, t) {
1643
+ async function ht(e, t) {
1743
1644
  try {
1744
1645
  const n = {
1745
- ...V().chrome,
1646
+ ...S().chrome,
1746
1647
  ...t.browserUrl ? { browserUrl: t.browserUrl } : {}
1747
- }, o = Ct(t, n);
1648
+ }, o = vt(t, n);
1748
1649
  if (o.kind === "skip")
1749
1650
  return;
1750
1651
  if (o.kind === "hint") {
1751
- y(
1652
+ w(
1752
1653
  `detected a headless environment (${o.reason}) — not opening a browser`,
1753
1654
  `Assuming the dev server's port is already forwarded, open ${e} in the browser
1754
1655
  on your local machine. (Pass --aiui-browser to open one here anyway.)`
@@ -1756,254 +1657,232 @@ on your local machine. (Pass --aiui-browser to open one here anyway.)`
1756
1657
  return;
1757
1658
  }
1758
1659
  if (n.browserUrl) {
1759
- await H(n.browserUrl, e), console.error(l.dim(`aiui: opened ${e} in the browser at ${n.browserUrl}`));
1660
+ await R(n.browserUrl, e), console.error(u.dim(`aiui: opened ${e} in the browser at ${n.browserUrl}`));
1760
1661
  return;
1761
1662
  }
1762
- const r = D(t, n), i = await F(r.userDataDir);
1763
- i ? (await H(i.browserUrl, e), console.error(l.dim(`aiui: opened ${e} in the session browser`))) : (await st({
1663
+ const r = x(t, n), i = await U(r.userDataDir);
1664
+ i ? (await R(i.browserUrl, e), console.error(u.dim(`aiui: opened ${e} in the session browser`))) : (await nt({
1764
1665
  flags: t,
1765
1666
  config: n,
1766
1667
  interactive: !1,
1767
1668
  startUrl: e
1768
- }), console.error(l.dim(`aiui: opened ${e} in a new session browser`)));
1669
+ }), console.error(u.dim(`aiui: opened ${e} in a new session browser`)));
1769
1670
  } catch (n) {
1770
- T(
1671
+ $(
1771
1672
  "couldn't open the app in the session browser — the dev server is unaffected",
1772
1673
  n instanceof Error ? n.message : String(n)
1773
1674
  );
1774
1675
  }
1775
1676
  }
1776
- function mt() {
1677
+ function ft() {
1777
1678
  try {
1778
- return ge(Yn);
1679
+ return J(ro);
1779
1680
  } catch {
1780
- g(
1681
+ b(
1781
1682
  "Vite is not available",
1782
1683
  "`vite` should be installed as a dependency of aiui — try reinstalling."
1783
1684
  ), process.exitCode = 1;
1784
1685
  return;
1785
1686
  }
1786
1687
  }
1787
- async function Xn(e) {
1788
- const t = mt();
1688
+ async function lo(e) {
1689
+ const t = ft();
1789
1690
  if (!t)
1790
1691
  return;
1791
- const n = await k(t.command, [...t.args, ...e], {
1692
+ const n = await T(t.command, [...t.args, ...e], {
1792
1693
  stdio: "inherit",
1793
1694
  reject: !1
1794
1695
  });
1795
1696
  n.exitCode && (process.exitCode = n.exitCode);
1796
1697
  }
1797
- function Qn() {
1798
- console.log(`aiui vite — launch Vite connected to the running aiui channel
1698
+ function uo() {
1699
+ console.log(`aiui vite — launch Vite and open the app in the session browser
1799
1700
 
1800
1701
  aiui's own flags (everything else forwards to vite verbatim):
1801
- --aiui-mcp <tag> connect to the channel server with this tag
1802
- --aiui-tag <tag> accepted alias for --aiui-mcp
1803
1702
  --aiui-browser open the app in the session browser even when
1804
1703
  the environment looks headless (CI, SSH, no display)
1805
1704
  --aiui-no-browser never open a browser for this run
1806
1705
  --aiui-chrome-profile <name> browser profile at .aiui-cache/chrome/<name>
1807
1706
  --aiui-chrome-data-dir <path> explicit browser user data dir
1808
1707
 
1809
- The chosen channel's port is exported as VITE_AIUI_PORT; the aiuiDevOverlay()
1810
- Vite plugin picks it up there and wires the intent tool to it. When Vite prints
1811
- its Local: URL, aiui opens it in the shared session browser (the one \`aiui
1812
- claude\` and \`aiui open\` use); in headless environments it prints the URL to
1813
- open on your own machine instead. What follows is vite's own --help:
1708
+ When Vite prints its Local: URL, aiui opens it in the shared session browser
1709
+ (the one \`aiui claude\` and \`aiui open\` use); in headless environments it
1710
+ prints the URL to open on your own machine instead.
1711
+
1712
+ The app reaches the aiui channel through the intent client served at /intent/,
1713
+ not through this command — so there is no channel to pick here. (The standalone
1714
+ intent panel, served on Vite's own origin, is the exception: its \`pnpm dev\`
1715
+ selects a channel itself.) What follows is vite's own --help:
1814
1716
  `);
1815
1717
  }
1816
- const re = "/__aiui/debug", Me = 4747;
1817
- function Zn() {
1818
- let e = R(Ge(import.meta.url));
1819
- for (let t = 0; t < 5; t++) {
1820
- const n = f(e, "package.json");
1821
- if (v(n))
1822
- try {
1823
- if (JSON.parse(U(n, "utf8")).name === "@habemus-papadum/aiui")
1824
- return e;
1825
- } catch {
1826
- }
1827
- e = R(e);
1828
- }
1829
- }
1830
- async function eo(e = {}) {
1831
- var d;
1832
- const t = pt(J(), e.mcp);
1718
+ async function ho(e = {}) {
1719
+ const t = oo(M(), e.mcp);
1833
1720
  if (t.error) {
1834
- g("Could not resolve an aiui channel", t.error), process.exitCode = 1;
1721
+ b("Could not resolve an aiui channel", t.error), process.exitCode = 1;
1835
1722
  return;
1836
1723
  }
1837
- const n = t.select ? await qe(t.select) : t.server;
1724
+ const n = t.select ? await He(t.select) : t.server;
1838
1725
  if (!n) {
1839
- console.log("No running aiui channel to debug — start one with `aiui claude`."), process.exitCode = 1;
1840
- return;
1841
- }
1842
- const o = Zn();
1843
- if (!o) {
1844
- g("Could not locate the aiui package root to serve the viewer from"), process.exitCode = 1;
1726
+ console.log("No running aiui channel to open — start one with `aiui claude`."), process.exitCode = 1;
1845
1727
  return;
1846
1728
  }
1847
- const r = {
1848
- name: "aiui:debug-home",
1849
- configureServer(p) {
1850
- p.middlewares.use((h, m, b) => {
1851
- if ((h.url ?? "/").split("?")[0] === "/") {
1852
- m.statusCode = 302, m.setHeader("location", re), m.end();
1853
- return;
1854
- }
1855
- b();
1856
- });
1857
- }
1858
- }, i = Number(e.port), s = await Lt({
1859
- root: o,
1860
- configFile: !1,
1861
- // `mount: false`: this server hosts the viewer, not an app — nothing to
1862
- // arm, so the intent tool stays out of it. The plugin still serves the
1863
- // DEBUG_ROUTE page and seeds the picked channel's port into it.
1864
- plugins: [r, Rt({ port: n.port, mount: !1 })],
1865
- server: {
1866
- port: Number.isInteger(i) && i > 0 ? i : Me,
1867
- open: e.open === !1 ? !1 : re
1868
- },
1869
- logLevel: "warn"
1870
- });
1871
- await s.listen();
1872
- const c = `${(((d = s.resolvedUrls) == null ? void 0 : d.local[0]) ?? `http://localhost:${Me}/`).replace(/\/$/, "")}${re}`;
1873
- console.log(`${l.cyan("aiui debug")} — the lowering-trace viewer`), console.log(` viewing ${l.bold(c)}`), console.log(
1874
- l.dim(` channel "${n.tag}" (${n.cwd}) on port ${n.port}`) + l.dim(" — switch channels from the page's header. Ctrl-C to stop.")
1875
- );
1876
- }
1877
- async function to(e, t = {}) {
1878
- const n = P(process.cwd(), e ?? "aiui-demo");
1879
- switch (no(n)) {
1880
- case "occupied":
1881
- g(
1882
- `${n} already exists and isn't an aiui demo`,
1883
- "Pick an empty (or new) directory — the scaffold never overwrites existing content."
1884
- ), process.exitCode = 1;
1885
- return;
1886
- case "existing-demo":
1887
- y(`existing demo found at ${n} — continuing where it left off`);
1888
- break;
1889
- case "new": {
1890
- const o = so();
1891
- if (!o) {
1892
- g("the demo template did not ship with this aiui install"), process.exitCode = 1;
1893
- return;
1894
- }
1895
- ro(o, n), console.log(`scaffolded the demo playground at ${n}`), await io(n);
1896
- break;
1897
- }
1898
- }
1899
- if (!t.skipInstall && !v(f(n, "node_modules")))
1900
- if (!ye("npm"))
1901
- y("npm not found on PATH — run your package manager's install in the demo yourself");
1902
- else {
1903
- console.log("installing dependencies (one time)…");
1904
- const o = await k("npm", ["install", "--no-audit", "--no-fund"], {
1905
- cwd: n,
1906
- stdio: "inherit",
1907
- reject: !1
1908
- });
1909
- if (o.exitCode) {
1910
- g("npm install failed — fix that, then re-run this command to continue"), process.exitCode = o.exitCode;
1911
- return;
1912
- }
1913
- }
1914
- ao(n);
1915
- }
1916
- function no(e) {
1917
- var n;
1918
- if (!v(e))
1919
- return "new";
1920
- let t;
1921
- try {
1922
- t = G(e);
1923
- } catch {
1924
- return "occupied";
1925
- }
1926
- if (t.length === 0)
1927
- return "new";
1928
- try {
1929
- if (((n = JSON.parse(U(f(e, "package.json"), "utf8")).aiui) == null ? void 0 : n.demo) === !0)
1930
- return "existing-demo";
1931
- } catch {
1729
+ const o = `http://127.0.0.1:${n.port}/`;
1730
+ console.log(`${u.cyan("aiui debug")} — the channel console`), console.log(` ${u.bold(o)}`), console.log(
1731
+ u.dim(` channel "${n.tag}" (${n.cwd}) on port ${n.port}`) + u.dim(" — the dashboard links to the trace debugger at /__aiui/debug.")
1732
+ ), e.open !== !1 && await ht(o, de([]));
1733
+ }
1734
+ const Ae = [".env", ".env.local", ".env.dev", ".env.dev.local"];
1735
+ function fo(e) {
1736
+ let t = e;
1737
+ for (; ; ) {
1738
+ if (v(d(t, "pnpm-workspace.yaml")) || v(d(t, ".git")))
1739
+ return t;
1740
+ const n = bt(t);
1741
+ if (n === t)
1742
+ return e;
1743
+ t = n;
1744
+ }
1745
+ }
1746
+ function po(e) {
1747
+ const t = /* @__PURE__ */ new Map();
1748
+ for (const n of e.split(`
1749
+ `)) {
1750
+ const o = n.trim();
1751
+ if (o === "" || o.startsWith("#"))
1752
+ continue;
1753
+ const r = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(o);
1754
+ if (!r)
1755
+ continue;
1756
+ let i = r[2].trim();
1757
+ i.length >= 2 && (i[0] === '"' || i[0] === "'") && i[i.length - 1] === i[0] && (i = i.slice(1, -1)), t.set(r[1], i);
1932
1758
  }
1933
- return "occupied";
1759
+ return t;
1934
1760
  }
1935
- function oo(e) {
1936
- return /^\d+\.\d+\.\d+$/.test(e) ? `^${e}` : "latest";
1761
+ function _e(e) {
1762
+ return `'${e.replace(/'/g, "'\\''")}'`;
1937
1763
  }
1938
- function ro(e, t) {
1939
- W(t, { recursive: !0 }), Et(e, t, { recursive: !0 }), v(f(t, "gitignore")) && Dt(f(t, "gitignore"), f(t, ".gitignore"));
1940
- const n = f(t, "package.json");
1941
- q(
1942
- n,
1943
- U(n, "utf8").replaceAll(
1944
- "__AIUI_VERSION_RANGE__",
1945
- oo(ee)
1764
+ function mo(e) {
1765
+ const t = [];
1766
+ t.push(
1767
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: shell parameter expansion, not a JS template
1768
+ 'if [ -z "${_AIUI_OLD_PATH:-}" ]; then _AIUI_OLD_PATH="$PATH"; export _AIUI_OLD_PATH; fi;'
1769
+ );
1770
+ for (const o of [...e.pathDirs].reverse()) {
1771
+ const r = _e(o);
1772
+ t.push(`case ":$PATH:" in *":"${r}":"*) : ;; *) PATH=${r}":$PATH"; export PATH ;; esac;`);
1773
+ }
1774
+ for (const [o, r] of e.vars)
1775
+ t.push(`export ${o}=${_e(r)};`);
1776
+ const n = e.vars.size > 0 ? ` unset ${[...e.vars.keys()].join(" ")};` : "";
1777
+ return t.push(
1778
+ `aiui_deactivate () { if [ -n "\${_AIUI_OLD_PATH:-}" ]; then PATH="$_AIUI_OLD_PATH"; export PATH; unset _AIUI_OLD_PATH; fi;${n} unset -f aiui_deactivate; };`
1779
+ ), `${t.join(`
1780
+ `)}
1781
+ `;
1782
+ }
1783
+ function wo() {
1784
+ const e = process.cwd(), t = fo(e), n = [d(t, "bin"), d(t, "node_modules", ".bin")];
1785
+ e !== t && n.push(d(e, "node_modules", ".bin"));
1786
+ const o = n.filter((c) => v(c)), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
1787
+ for (const c of Ae) {
1788
+ const a = d(t, c);
1789
+ if (v(a))
1790
+ for (const [l, p] of po(L(a, "utf8")))
1791
+ r.set(l, p), i.set(l, c);
1792
+ }
1793
+ process.stdout.write(mo({ pathDirs: o, vars: r }));
1794
+ const s = [...r.keys()].map((c) => `${c} (${i.get(c)})`);
1795
+ process.stderr.write(
1796
+ u.dim(
1797
+ `aiui env: root ${t}
1798
+ aiui env: PATH + ${o.length > 0 ? o.join(", ") : "(nothing found)"}
1799
+ aiui env: export ${s.length > 0 ? s.join(", ") : `(none — no ${Ae.join("/")} at root)`}
1800
+ aiui env: activate with eval "$(aiui env)" — undo with aiui_deactivate
1801
+ `
1946
1802
  )
1947
1803
  );
1948
1804
  }
1949
- async function io(e) {
1950
- !ye("git") || (await k("git", ["-C", e, "rev-parse", "--is-inside-work-tree"], {
1951
- reject: !1
1952
- })).exitCode === 0 || (await k("git", ["-C", e, "init", "--quiet"], { reject: !1 })).exitCode !== 0 || (await k("git", ["-C", e, "add", "-A"], { reject: !1 }), await k("git", ["-C", e, "commit", "--quiet", "-m", "aiui demo scaffold"], {
1953
- reject: !1
1954
- }));
1955
- }
1956
- function so() {
1957
- let e = R(Ge(import.meta.url));
1958
- for (let t = 0; t < 4; t++) {
1959
- const n = f(e, "templates", "demo");
1960
- if (v(f(n, "package.json")))
1961
- return n;
1962
- e = R(e);
1963
- }
1964
- }
1965
- function ao(e) {
1966
- const t = yt(process.cwd(), e) || ".", n = t === "aiui-demo" ? "aiui demo" : `aiui demo ${t}`;
1967
- console.log(`
1968
- demo ready. Run the loop:
1969
-
1970
- cd ${t}
1971
- npm run claude # terminal 1 — Claude Code with the aiui channel + session browser
1972
- npm run dev # terminal 2 — the demo app (Vite + the intent tool)
1973
-
1974
- then open the app in the session browser (the window you share with the agent):
1975
-
1976
- npx aiui open http://localhost:5173
1977
-
1978
- Click the ✳ aiui button on the page and type an intent — it lands in the session
1979
- as a prompt. Re-run \`${n}\` anytime to continue this sandbox.`);
1980
- }
1981
- const co = "@habemus-papadum/aiui-claude-channel";
1982
- async function lo(e = []) {
1805
+ const go = "@habemus-papadum/aiui-claude-channel";
1806
+ async function bo(e = []) {
1983
1807
  let t;
1984
1808
  try {
1985
- t = ge(co);
1809
+ t = J(go);
1986
1810
  } catch {
1987
- g(
1811
+ b(
1988
1812
  "The aiui Claude channel CLI is not available",
1989
1813
  "`@habemus-papadum/aiui-claude-channel` should be installed as a dependency of aiui — try reinstalling."
1990
1814
  ), process.exitCode = 1;
1991
1815
  return;
1992
1816
  }
1993
- const n = await k(t.command, [...t.args, ...e], {
1817
+ const n = at(e) ? wn(e, it({ config: S() })) : e, o = await T(t.command, [...t.args, ...n], {
1994
1818
  stdio: "inherit",
1995
1819
  reject: !1
1996
1820
  });
1997
- n.exitCode && (process.exitCode = n.exitCode);
1821
+ o.exitCode && (process.exitCode = o.exitCode);
1822
+ }
1823
+ function yo(e) {
1824
+ const t = Buffer.from(JSON.stringify(e), "utf8"), n = Buffer.allocUnsafe(4 + t.length);
1825
+ return pt() ? n.writeUInt32LE(t.length, 0) : n.writeUInt32BE(t.length, 0), t.copy(n, 4), n;
1826
+ }
1827
+ function vo(e) {
1828
+ const t = [];
1829
+ let n = 0;
1830
+ for (; e.length - n >= 4; ) {
1831
+ const o = pt() ? e.readUInt32LE(n) : e.readUInt32BE(n);
1832
+ if (e.length - n - 4 < o)
1833
+ break;
1834
+ const r = e.subarray(n + 4, n + 4 + o);
1835
+ n += 4 + o;
1836
+ try {
1837
+ t.push(JSON.parse(r.toString("utf8")));
1838
+ } catch {
1839
+ t.push(void 0);
1840
+ }
1841
+ }
1842
+ return { messages: t, rest: e.subarray(n) };
1843
+ }
1844
+ function pt() {
1845
+ return new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
1846
+ }
1847
+ function $o(e) {
1848
+ const t = e !== null && typeof e == "object" ? e.cmd : void 0;
1849
+ return t === "ping" ? { ok: !0, at: (/* @__PURE__ */ new Date()).toISOString() } : t === "version" ? { ok: !0, version: 1 } : t === "listChannels" ? { ok: !0, channels: M().map((o) => ({
1850
+ tag: o.tag,
1851
+ port: o.port,
1852
+ pid: o.pid,
1853
+ cwd: o.cwd,
1854
+ startedAt: o.startedAt,
1855
+ ...o.name !== void 0 ? { name: o.name } : {},
1856
+ ...o.debug === !0 ? { debug: !0 } : {}
1857
+ })) } : { ok: !1, error: `unknown cmd ${JSON.stringify(t)}` };
1858
+ }
1859
+ async function Co() {
1860
+ let e = Buffer.alloc(0);
1861
+ process.stdin.on("data", (t) => {
1862
+ e = Buffer.concat([e, t]);
1863
+ const { messages: n, rest: o } = vo(e);
1864
+ e = o;
1865
+ for (const r of n) {
1866
+ let i;
1867
+ try {
1868
+ i = $o(r);
1869
+ } catch (s) {
1870
+ i = { ok: !1, error: s instanceof Error ? s.message : String(s) };
1871
+ }
1872
+ process.stdout.write(yo(i));
1873
+ }
1874
+ }), await new Promise((t) => {
1875
+ process.stdin.on("end", t), process.stdin.on("close", t);
1876
+ });
1998
1877
  }
1999
- function uo() {
1878
+ function ko() {
2000
1879
  const e = [];
2001
- for (const t of Object.values(Nt()))
1880
+ for (const t of Object.values(Ge()))
2002
1881
  for (const n of t ?? [])
2003
1882
  n.family === "IPv4" && !n.internal && e.push(n.address);
2004
1883
  return e;
2005
1884
  }
2006
- async function Be(e, t) {
1885
+ async function H(e, t) {
2007
1886
  try {
2008
1887
  const n = await fetch(`http://127.0.0.1:${e}${t}`, {
2009
1888
  signal: AbortSignal.timeout(1500)
@@ -2013,53 +1892,101 @@ async function Be(e, t) {
2013
1892
  return;
2014
1893
  }
2015
1894
  }
2016
- async function ho(e) {
2017
- const t = await Be(
1895
+ async function xo(e, t) {
1896
+ const n = await H(
2018
1897
  e,
2019
- "/paint/info"
1898
+ `${t}/info`
2020
1899
  );
2021
- if (!(t != null && t.ok))
1900
+ if (!(n != null && n.ok))
2022
1901
  return;
2023
- const n = await Be(e, "/health"), o = (n == null ? void 0 : n.host) !== void 0 && n.host !== "127.0.0.1";
1902
+ const o = await H(e, "/health"), r = (o == null ? void 0 : o.host) !== void 0 && o.host !== "127.0.0.1";
2024
1903
  return {
2025
- lan: o,
2026
- urls: o ? uo().map((r) => `http://${r}:${e}/paint/`) : [`http://127.0.0.1:${e}/paint/`],
2027
- hosts: t.hosts ?? 0,
2028
- clients: t.clients ?? 0
1904
+ lan: r,
1905
+ urls: r ? ko().map((i) => `http://${i}:${e}${t}/`) : [`http://127.0.0.1:${e}${t}/`],
1906
+ hosts: n.hosts ?? 0,
1907
+ clients: n.clients ?? 0
2029
1908
  };
2030
1909
  }
2031
- async function fo(e = {}) {
2032
- const t = J(), n = [];
2033
- for (const o of t) {
2034
- const r = await ho(o.port);
2035
- r && n.push({ cwd: o.cwd, pid: o.pid, port: o.port, ...r });
1910
+ function To(e) {
1911
+ const t = { name: "loopback", address: "127.0.0.1" };
1912
+ if (e === void 0 || e === "127.0.0.1")
1913
+ return [t];
1914
+ const n = [];
1915
+ for (const [o, r] of Object.entries(Ge()))
1916
+ for (const i of r ?? [])
1917
+ i.family === "IPv4" && !i.internal && n.push({ name: o, address: i.address });
1918
+ return [...n, t];
1919
+ }
1920
+ async function Io(e) {
1921
+ if (process.platform !== "darwin")
1922
+ return !1;
1923
+ try {
1924
+ return await T("pbcopy", { input: e }), !0;
1925
+ } catch {
1926
+ return !1;
2036
1927
  }
2037
- if (e.json) {
2038
- console.log(JSON.stringify({ targets: n }, null, 2));
1928
+ }
1929
+ function Eo(e, t) {
1930
+ var n;
1931
+ return e.name ?? ((n = t.get(e.ppid)) == null ? void 0 : n.name) ?? e.cwd;
1932
+ }
1933
+ function Po(e = {}) {
1934
+ return e.json ? Ao("/pencil") : Do("/pencil", "pencil");
1935
+ }
1936
+ async function Do(e, t) {
1937
+ const n = M();
1938
+ if (n.length === 0) {
1939
+ So(t);
2039
1940
  return;
2040
1941
  }
2041
- if (n.length === 0) {
2042
- console.log("No running channel is hosting the paint surface."), console.log(""), console.log(
2043
- `It is on by default — start a session with ${l.cyan("aiui claude")}. If it's off here,`
2044
- ), console.log(
2045
- `check for ${l.cyan("sidecars.paint false")} in config or a --aiui-no-sidecar flag.`
1942
+ const o = await He(n), r = await H(o.port, `${e}/info`);
1943
+ if (!(r != null && r.ok)) {
1944
+ console.log(
1945
+ `${u.bold(Eo(o, Fe(Ve())))} is not hosting the ${t} surface.`
2046
1946
  ), process.exitCode = 1;
2047
1947
  return;
2048
1948
  }
2049
- for (const o of n) {
2050
- console.log(""), console.log(`${l.bold(o.cwd)} ${l.dim(`(channel :${o.port})`)}`);
2051
- for (const i of o.urls.length ? o.urls : ["(no LAN address found)"])
2052
- console.log(` ${l.cyan(i)}`);
2053
- const r = o.lan ? "open the URL on the iPad (same Wi-Fi)" : "loopback-only — the iPad needs a tunnel to this port (Tailscale, ssh -L), or relaunch with --aiui-bind host";
2054
- console.log(
2055
- l.dim(` ${o.hosts} browser host(s), ${o.clients} viewer(s) ${r}`)
2056
- );
1949
+ const i = await H(o.port, "/health"), s = To(i == null ? void 0 : i.host), c = (i == null ? void 0 : i.host) !== void 0 && i.host !== "127.0.0.1", l = `http://${(s.length === 1 ? s[0] : await O({
1950
+ message: "Which host interface should the iPad reach the channel on?",
1951
+ choices: s.map((f) => ({
1952
+ name: `${f.address} ${u.dim(`(${f.name})`)}`,
1953
+ value: f
1954
+ }))
1955
+ })).address}:${o.port}${e}/`, p = await Io(l);
1956
+ console.log(""), console.log(` ${u.cyan(l)}`), console.log(""), p ? (console.log(u.dim(" Copied to your clipboard.")), console.log(
1957
+ u.dim(" Use Universal Clipboard (⌘V on the iPad) to paste it into Safari there.")
1958
+ )) : console.log(u.dim(" (Copy it to the iPad however you like.)")), c || console.log(
1959
+ u.dim(
1960
+ " This channel is loopback-only: the iPad needs a tunnel to this port (Tailscale, ssh -L), or relaunch with --aiui-bind host."
1961
+ )
1962
+ ), console.log("");
1963
+ }
1964
+ function So(e) {
1965
+ console.log(`No running channel is hosting the ${e} surface.`), console.log(""), console.log(`Every channel hosts it — start a session with ${u.cyan("aiui claude")} (or a`), console.log(
1966
+ `standalone ${u.cyan("aiui mcp serve")}), then run this again to reach the ${e} surface.`
1967
+ ), process.exitCode = 1;
1968
+ }
1969
+ async function Ao(e, t) {
1970
+ var i;
1971
+ const n = M(), o = n.length > 0 ? Fe(Ve()) : /* @__PURE__ */ new Map(), r = [];
1972
+ for (const s of n) {
1973
+ const c = await xo(s.port, e);
1974
+ if (c) {
1975
+ const a = s.name ?? ((i = o.get(s.ppid)) == null ? void 0 : i.name);
1976
+ r.push({
1977
+ cwd: s.cwd,
1978
+ pid: s.pid,
1979
+ port: s.port,
1980
+ ...a !== void 0 ? { session: a } : {},
1981
+ ...c
1982
+ });
1983
+ }
2057
1984
  }
2058
- console.log("");
1985
+ console.log(JSON.stringify({ targets: r }, null, 2));
2059
1986
  }
2060
- function po() {
2061
- const e = new gt();
2062
- e.name("aiui").description("ai ui frontends — thin launchers for Claude, Vite, and the channel CLI").version(ee).enablePositionalOptions(), e.command("claude").description("launch Claude (extra args are forwarded, e.g. `aiui claude --resume`)").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to claude").action((o) => En(o)), e.command("vite").description("launch Vite (extra args are forwarded, e.g. `aiui vite dev`)").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to vite").action((o) => Wn(o)), e.command("debug").description("open the lowering-trace viewer for a running channel (switchable in-page)").option("--mcp <tag>", "target a channel by registry tag (skips the selector)").option("--port <port>", "UI port for the viewer's dev server (default 4747)").option("--no-open", "don't open the browser").action((o) => eo(o)), e.command("chrome").description("manage the agent's browser: install | update | status | extension").argument("<action>", "install | update | status | extension").action((o) => cn([o])), e.command("browser").description(
1987
+ function _o() {
1988
+ const e = new wt();
1989
+ e.name("aiui").description("ai ui frontends — thin launchers for Claude, Vite, and the channel CLI").version(he).enablePositionalOptions(), e.command("claude").description("launch Claude (extra args are forwarded, e.g. `aiui claude --resume`)").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to claude").action((o) => Rn(o)), e.command("vite").description("launch Vite (extra args are forwarded, e.g. `aiui vite dev`)").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to vite").action((o) => io(o)), e.command("debug").description("open the channel console (dashboard + trace debugger) in the session browser").option("--mcp <tag>", "target a channel by registry tag (skips the selector)").option("--no-open", "print the URL but don't open the browser").action((o) => ho(o)), e.command("chrome").description("manage the agent's browser: install | update | status").argument("<action>", "install | update | status").action((o) => un([o])), e.command("browser").description(
2063
1990
  "start (or find) the shared session browser; --tunnel does the whole remote-dev local half"
2064
1991
  ).option(
2065
1992
  "--profile <name>",
@@ -2067,13 +1994,13 @@ function po() {
2067
1994
  ).option("--data-dir <path>", "explicit Chrome user data dir").option("--port <port>", "fixed local DevTools debug port (default: OS-assigned)").option("--headless", "launch with no UI").option("--open <url>", "also open this URL in it").option(
2068
1995
  "--tunnel <[user@]host>",
2069
1996
  "reverse-tunnel the debug port to this host (Ctrl-C closes it)"
2070
- ).option("--remote-port <port>", "fixed port on the tunnel's remote side (default: 9222)").action((o) => en(o)), e.command("demo").description("scaffold a runnable demo playground (safe to re-run; default dir: aiui-demo)").argument("[dir]", "target directory (default: aiui-demo)").option("--skip-install", "scaffold only don't run npm install").action((o, r) => to(o, r)), e.command("clean").description(
1997
+ ).option("--remote-port <port>", "fixed port on the tunnel's remote side (default: 9222)").action((o) => nn(o)), e.command("extension").description("the intent client extension's native host: install-native-host | status").argument("<action>", "install-native-host | status").option("--extension-id <id>", "extension id for allowed_origins (default: the pinned id)").action((o, r) => Xt(o, r)), e.command("native-host", { hidden: !0 }).description("(internal) Chrome native-messaging host — spawned by the browser").action(() => Co()), e.command("clean").description(
2071
1998
  "reset aiui state (project + user cache, incl. Chrome for Testing) for a clean-slate demo"
2072
- ).option("--project-only", "only this repo's .aiui-cache/").option("--user-only", "only the user cache (~/.cache/aiui)").option("--keep-browser", "keep Chrome for Testing (skip the ~160 MB re-download)").option("-n, --dry-run", "print what would be deleted, then stop").option("-y, --yes", "delete without the confirmation prompt").action((o) => Nn(o)), e.command("open").description("open a URL in the session browser, e.g. `aiui open http://localhost:5173`").argument("<url>", "the URL to open").option("--profile <name>", "named profile under .aiui-cache/chrome/").option("--data-dir <path>", "explicit Chrome user data dir").action((o, r) => an(o, r));
2073
- const t = e.command("config").description("inspect and edit aiui's config.json — tui | show | get | set | unset").action(() => _e());
2074
- return t.command("tui").description("browse every setting interactively: docs, defaults, current values, editing").action(() => _e()), t.command("show").description("every key with its effective value and which file set it").option("--json", "machine-readable: file paths, per-level values, effective merge").action((o) => _n(o)), t.command("get").description("print a key's effective value (provenance goes to stderr)").argument("<key>", 'dotted key, e.g. "chrome.mode"').action((o) => Rn(o)), t.command("set").description("set a key in the user config (or the project's with --project)").argument("<key>", 'dotted key, e.g. "chrome.mode"').argument("<value>", "the new value, validated against the schema").option("--project", "write .aiui-cache/config.json here instead of the user config").action((o, r, i) => Ln(o, r, i)), t.command("unset").description("remove a key from the user config (or the project's with --project)").argument("<key>", 'dotted key, e.g. "claude.skipPermissions"').option("--project", "remove from .aiui-cache/config.json here instead of the user config").action((o, r) => Mn(o, r)), e.command("mcp").description("run a channel command (forwards to aiui-claude-channel), e.g. `aiui mcp quick`").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to the aiui-claude-channel CLI").action((o) => lo(o)), e.command("paint").description("the iPad paint stream — url (where the iPad should connect)").command("url").description("print the URL(s) an iPad should open, per running paint-enabled channel").option("--json", "machine-readable targets").action((o) => fo(o)), e;
1999
+ ).option("--project-only", "only this repo's .aiui-cache/").option("--user-only", "only the user cache (~/.cache/aiui)").option("--keep-browser", "keep Chrome for Testing (skip the ~160 MB re-download)").option("-n, --dry-run", "print what would be deleted, then stop").option("-y, --yes", "delete without the confirmation prompt").action((o) => Wn(o)), e.command("open").description("open a URL in the session browser, e.g. `aiui open http://localhost:5173`").argument("<url>", "the URL to open").option("--profile <name>", "named profile under .aiui-cache/chrome/").option("--data-dir <path>", "explicit Chrome user data dir").action((o, r) => ln(o, r)), e.command("env").description('print shell code to activate this checkout — use as: eval "$(aiui env)"').action(() => wo());
2000
+ const t = e.command("config").description("inspect and edit aiui's config.json — tui | show | get | set | unset").action(() => Pe());
2001
+ return t.command("tui").description("browse every setting interactively: docs, defaults, current values, editing").action(() => Pe()), t.command("show").description("every key with its effective value and which file set it").option("--json", "machine-readable: file paths, per-level values, effective merge").action((o) => qn(o)), t.command("get").description("print a key's effective value (provenance goes to stderr)").argument("<key>", 'dotted key, e.g. "chrome.mode"').action((o) => zn(o)), t.command("set").description("set a key in the user config (or the project's with --project)").argument("<key>", 'dotted key, e.g. "chrome.mode"').argument("<value>", "the new value, validated against the schema").option("--project", "write .aiui-cache/config.json here instead of the user config").action((o, r, i) => Jn(o, r, i)), t.command("unset").description("remove a key from the user config (or the project's with --project)").argument("<key>", 'dotted key, e.g. "claude.skipPermissions"').option("--project", "remove from .aiui-cache/config.json here instead of the user config").action((o, r) => Xn(o, r)), e.command("mcp").description("run a channel command (forwards to aiui-claude-channel), e.g. `aiui mcp quick`").allowUnknownOption().allowExcessArguments().helpOption(!1).argument("[args...]", "arguments forwarded to the aiui-claude-channel CLI").action((o) => bo(o)), e.command("pencil").description("the remote pencil — url (where the iPad should connect)").command("url").description("pick a channel + interface, print the iPad URL and copy it to the clipboard").option("--json", "machine-readable targets (every hosting channel, no prompts)").action((o) => Po(o)), e;
2075
2002
  }
2076
- po().parseAsync().catch((e) => {
2003
+ _o().parseAsync().catch((e) => {
2077
2004
  console.error(e instanceof Error ? e.message : e), process.exitCode = 1;
2078
2005
  });
2079
2006
  //# sourceMappingURL=cli.js.map