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