@habemus-papadum/aiui 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/cli.js +994 -1067
- package/dist/cli.js.map +1 -1
- package/dist/commands/browser.d.ts +3 -1
- package/dist/commands/debug.d.ts +1 -9
- package/dist/commands/env.d.ts +36 -0
- package/dist/commands/extension.d.ts +46 -0
- package/dist/commands/mcp.d.ts +10 -0
- package/dist/commands/native-host.d.ts +16 -0
- package/dist/commands/pencil-url.d.ts +18 -0
- package/dist/commands/vite.d.ts +17 -29
- package/dist/config-Cis6kCik.js +293 -0
- package/dist/config-Cis6kCik.js.map +1 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/util/aiui-args.d.ts +0 -14
- package/dist/util/channel-launch.d.ts +67 -0
- package/dist/util/channel-target.d.ts +33 -0
- package/dist/util/chrome.d.ts +42 -25
- package/dist/util/config.d.ts +5 -5
- package/dist/util/gemini-preflight.d.ts +56 -0
- package/dist/util/openai-preflight.d.ts +1 -1
- package/package.json +9 -9
- package/dist/commands/demo.d.ts +0 -28
- package/dist/commands/paint.d.ts +0 -3
- package/dist/sidecars-BKlhUA0V.js +0 -48
- package/dist/sidecars-BKlhUA0V.js.map +0 -1
- package/dist/util/sidecars.d.ts +0 -62
- package/templates/demo/CLAUDE.md +0 -16
- package/templates/demo/README.md +0 -36
- package/templates/demo/gitignore +0 -4
- package/templates/demo/index.html +0 -11
- package/templates/demo/package.json +0 -23
- package/templates/demo/src/main.ts +0 -51
- package/templates/demo/tsconfig.json +0 -11
- package/templates/demo/vite.config.ts +0 -17
|
@@ -48,7 +48,9 @@ export interface StartSessionBrowserOptions {
|
|
|
48
48
|
* 2. Prefer the managed Chrome for Testing unless config names a browser
|
|
49
49
|
* explicitly (the sync may prompt to install/update — only when
|
|
50
50
|
* `interactive`; otherwise it just reports what's installed).
|
|
51
|
-
* 3. Rebuild and load the aiui devtools extension
|
|
51
|
+
* 3. Rebuild and load the aiui devtools extension, and pick up the
|
|
52
|
+
* intent-tool extension's dist/ if its dev loop has produced one
|
|
53
|
+
* (dev checkouts only).
|
|
52
54
|
* 4. Launch on the profile's user data dir and wait for the debug endpoint.
|
|
53
55
|
*
|
|
54
56
|
* Throws with a remediation-bearing message when no browser can be found or
|
package/dist/commands/debug.d.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
export interface DebugOptions {
|
|
2
2
|
/** Target a channel by its registry tag instead of the interactive selector. */
|
|
3
3
|
mcp?: string;
|
|
4
|
-
/**
|
|
5
|
-
port?: string;
|
|
6
|
-
/** Open the browser at the viewer (default true; `--no-open` skips). */
|
|
4
|
+
/** Open the browser at the console (default true; `--no-open` skips). */
|
|
7
5
|
open?: boolean;
|
|
8
6
|
}
|
|
9
|
-
/**
|
|
10
|
-
* This package's root — the Vite server root, found by walking up from this
|
|
11
|
-
* module to the `@habemus-papadum/aiui` package.json (two levels in the
|
|
12
|
-
* source tree, but the walk keeps it honest against dist layouts too).
|
|
13
|
-
*/
|
|
14
|
-
export declare function packageRoot(): string | undefined;
|
|
15
7
|
export declare function runDebug(opts?: DebugOptions): Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** The env files read from the workspace root, in load order (later wins). */
|
|
2
|
+
export declare const ENV_FILES: readonly [".env", ".env.local", ".env.dev", ".env.dev.local"];
|
|
3
|
+
/**
|
|
4
|
+
* Find the workspace root: the nearest ancestor of `start` carrying a
|
|
5
|
+
* `pnpm-workspace.yaml` or a `.git`. Falls back to `start` itself (a bare
|
|
6
|
+
* consumer project without either still gets its own ./node_modules/.bin).
|
|
7
|
+
*/
|
|
8
|
+
export declare function findWorkspaceRoot(start: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Parse one dotenv file's text into ordered KEY → value entries. Deliberately
|
|
11
|
+
* minimal (the files here hold API keys, not programs): `KEY=VALUE` lines, an
|
|
12
|
+
* optional `export ` prefix, `#` comment lines and blanks skipped, one pair of
|
|
13
|
+
* matching single or double outer quotes stripped. No escape processing, no
|
|
14
|
+
* multiline values, no inline comments after unquoted values.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseDotenv(text: string): Map<string, string>;
|
|
17
|
+
/** Single-quote `value` for POSIX shells (embedded `'` becomes `'\''`). */
|
|
18
|
+
export declare function shQuote(value: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Render the activation script. Pure — the command resolves dirs and reads
|
|
21
|
+
* files, this just writes shell. Every line ends in `;` (see the module
|
|
22
|
+
* header: unquoted `eval` survival), and each PATH prepend is wrapped in a
|
|
23
|
+
* containment check so activation is idempotent.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildEnvScript(input: {
|
|
26
|
+
/** Directories to prepend to PATH, highest priority first. */
|
|
27
|
+
pathDirs: string[];
|
|
28
|
+
/** Env entries to export (already merged across files, later-file wins). */
|
|
29
|
+
vars: Map<string, string>;
|
|
30
|
+
}): string;
|
|
31
|
+
/**
|
|
32
|
+
* The command: resolve the workspace root from the cwd, collect the PATH dirs
|
|
33
|
+
* that exist, merge the env files, and print the script (stdout) + a summary
|
|
34
|
+
* of what it does (stderr, names only — never a value).
|
|
35
|
+
*/
|
|
36
|
+
export declare function runEnv(): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** The NM host name (lowercase alphanumerics, dots, underscores only). */
|
|
2
|
+
export declare const NATIVE_HOST_NAME = "com.habemus_papadum.aiui";
|
|
3
|
+
/**
|
|
4
|
+
* The intent client's stable unpacked-extension id (see
|
|
5
|
+
* `packages/aiui-intent-client/src/ext/manifest.ts`, which owns the key this
|
|
6
|
+
* is derived from). Duplicated rather than imported: `aiui` does not depend on
|
|
7
|
+
* the intent client, and this is a 32-char constant that changes only if the
|
|
8
|
+
* key does.
|
|
9
|
+
*/
|
|
10
|
+
export declare const INTENT_CLIENT_EXTENSION_ID = "cdpbfpcelmifhagikjlfpgfipggcmdeg";
|
|
11
|
+
export interface ExtensionOptions {
|
|
12
|
+
extensionId?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Browser NM manifest directories, user-level, per platform.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately NO Chrome for Testing entry: CfT does not read a fixed
|
|
18
|
+
* user-level directory — it looks in `<user-data-dir>/NativeMessagingHosts`
|
|
19
|
+
* (measured on macOS; an earlier `Google/ChromeForTesting` guess here was
|
|
20
|
+
* never read by anything). aiui-launched browsers get the manifest written
|
|
21
|
+
* into their profile at launch instead ({@link installProfileNativeHost}).
|
|
22
|
+
*/
|
|
23
|
+
export declare function nativeHostManifestDirs(platform: NodeJS.Platform, home: string): string[];
|
|
24
|
+
/** The wrapper script body. Exported for tests. */
|
|
25
|
+
export declare function wrapperScript(cwd: string, command: string, args: string[]): string;
|
|
26
|
+
export declare function runExtension(action: string, options?: ExtensionOptions): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Install the NM manifest into a session-browser profile
|
|
29
|
+
* (`<user-data-dir>/NativeMessagingHosts/`) — the directory Chrome for
|
|
30
|
+
* Testing actually consults (measured; see the module doc). Called by the
|
|
31
|
+
* launchers whenever they load the intent client's extension: the profile
|
|
32
|
+
* lives in aiui's own project-local cache, so unlike the global install this
|
|
33
|
+
* needs no user decision — it is the same class of write as creating the
|
|
34
|
+
* profile. Quiet and idempotent; no browser restart needed (NM manifests are
|
|
35
|
+
* read per `connectNative`/`sendNativeMessage` call).
|
|
36
|
+
*/
|
|
37
|
+
export declare function installProfileNativeHost(userDataDir: string, options?: ExtensionOptions): void;
|
|
38
|
+
/**
|
|
39
|
+
* {@link installProfileNativeHost} as the launchers call it: only when the
|
|
40
|
+
* intent client's extension is actually loadable (no point granting a host to
|
|
41
|
+
* an extension that won't be there), and never fatal — a failed write
|
|
42
|
+
* degrades to the panel's type-a-port fallback, with a note saying so. Called
|
|
43
|
+
* on both the launch and the attach-to-running paths, so a profile whose
|
|
44
|
+
* browser outlives many sessions still converges on a current manifest.
|
|
45
|
+
*/
|
|
46
|
+
export declare function ensureProfileNativeHost(userDataDir: string, intentReady: boolean, warn: (title: string, detail: string) => void): void;
|
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
* user-facing channel commands under `aiui` without moving them out of the
|
|
8
8
|
* package that owns the MCP server Claude Code spawns.
|
|
9
9
|
*
|
|
10
|
+
* **One thing is not verbatim.** The subcommands that *are* a channel process —
|
|
11
|
+
* `serve` (standalone debug channel) and `mcp` (the stdio MCP server) — get the
|
|
12
|
+
* same config-derived `--bind` that `aiui claude` computes when it tells Claude
|
|
13
|
+
* Code how to spawn the channel (see util/channel-launch), so both ways of
|
|
14
|
+
* starting a channel honor `channel.bind` identically. (Sidecars need no such
|
|
15
|
+
* plumbing: the channel imports and mounts its own standard set — paint, intent,
|
|
16
|
+
* bar, pencil — so every channel hosts all four.) Flags you pass explicitly
|
|
17
|
+
* always win. Every other subcommand (`quick`, `config`) talks to a channel
|
|
18
|
+
* someone *else* is running and forwards untouched.
|
|
19
|
+
*
|
|
10
20
|
* Like `aiui vite`, the channel CLI is a declared dependency, so we resolve it
|
|
11
21
|
* from node_modules (tsx-from-source in a dev checkout, the built `dist` when
|
|
12
22
|
* installed; see {@link resolvePackageCli}) rather than looking on the PATH.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Encode one native-messaging frame (native-endian u32 length + JSON). Pure. */
|
|
2
|
+
export declare function encodeNativeFrame(message: unknown): Buffer;
|
|
3
|
+
/**
|
|
4
|
+
* Split complete frames off an accumulating buffer. Returns the parsed
|
|
5
|
+
* messages and the unconsumed remainder (a partial frame stays buffered).
|
|
6
|
+
* Unparseable JSON inside a complete frame yields `undefined` in its slot —
|
|
7
|
+
* the caller answers with an error rather than dying. Pure.
|
|
8
|
+
*/
|
|
9
|
+
export declare function decodeNativeFrames(buffer: Buffer): {
|
|
10
|
+
messages: unknown[];
|
|
11
|
+
rest: Buffer;
|
|
12
|
+
};
|
|
13
|
+
/** Answer one request. Exported for tests. */
|
|
14
|
+
export declare function handleNativeRequest(message: unknown): Record<string, unknown>;
|
|
15
|
+
/** The stdio loop. Never resolves until stdin ends (Chrome closes it). */
|
|
16
|
+
export declare function runNativeHost(): Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** A network interface the channel's bind makes reachable, as offered in the picker. */
|
|
2
|
+
interface HostInterface {
|
|
3
|
+
/** The OS interface name (`en0`, `lo0`) or a synthetic label (`loopback`). */
|
|
4
|
+
name: string;
|
|
5
|
+
address: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The interfaces the channel is actually reachable on, given its bind:
|
|
9
|
+
* - loopback (`127.0.0.1`) → only the loopback address; an iPad can't reach it
|
|
10
|
+
* without a tunnel, but we still offer it (the user may have one).
|
|
11
|
+
* - host (`0.0.0.0`) → every non-internal IPv4 the machine holds, named by its
|
|
12
|
+
* OS interface, plus loopback last for on-machine testing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function boundInterfaces(bindHost: string | undefined): HostInterface[];
|
|
15
|
+
export declare function runPencilUrl(opts?: {
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export {};
|
package/dist/commands/vite.d.ts
CHANGED
|
@@ -1,35 +1,8 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/** The channel server `runVite` should point Vite at, or why it couldn't. */
|
|
3
|
-
export interface ChannelTarget {
|
|
4
|
-
/** The server resolved without prompting (by tag). */
|
|
5
|
-
server?: RunningServer;
|
|
6
|
-
/** Servers to offer in the interactive selector (no tag given, ≥1 running). */
|
|
7
|
-
select?: RunningServer[];
|
|
8
|
-
/** A human-readable reason a requested server couldn't be resolved. */
|
|
9
|
-
error?: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Decide which running channel server Vite should connect to.
|
|
13
|
-
*
|
|
14
|
-
* Pure so it can be unit-tested without spawning anything:
|
|
15
|
-
* - With a `targetTag`, return the server whose `tag` matches exactly; if none
|
|
16
|
-
* matches, return an `error` naming the tag and the tags that *are* running.
|
|
17
|
-
* - Without a `targetTag`, don't guess: return `{}` when nothing is running, or
|
|
18
|
-
* `{ select }` so the caller runs the same selector as `quick` (which
|
|
19
|
-
* auto-picks a lone server and prompts when there are several).
|
|
20
|
-
*/
|
|
21
|
-
export declare function resolveChannelTarget(servers: RunningServer[], targetTag: string | undefined): ChannelTarget;
|
|
1
|
+
import { type AiuiArgs } from "../util/aiui-args";
|
|
22
2
|
/**
|
|
23
3
|
* Launch Vite, forwarding any extra args (e.g. `aiui vite dev`,
|
|
24
4
|
* `aiui vite --port 3000`, `aiui vite --version`).
|
|
25
5
|
*
|
|
26
|
-
* Before launching, resolve which running aiui channel server the dev server
|
|
27
|
-
* should talk to — either the one named by `--aiui-mcp <tag>` (or `--aiui-tag`),
|
|
28
|
-
* or, with no tag, the one you pick from the same selector `quick` uses (which
|
|
29
|
-
* auto-selects when only one is running) — and inject its port as
|
|
30
|
-
* {@link VITE_PORT_ENV} so the app can reach it. When a specific tag was asked
|
|
31
|
-
* for but isn't running, we fail loudly instead of connecting to the wrong one.
|
|
32
|
-
*
|
|
33
6
|
* Unlike `claude` — an external tool we look up on the PATH — Vite is a declared
|
|
34
7
|
* dependency of this package, so we resolve it straight out of node_modules and
|
|
35
8
|
* run it via the current Node with an absolute path. Resolving it also doubles
|
|
@@ -60,7 +33,7 @@ export declare function runVite(rawArgs?: string[]): Promise<void>;
|
|
|
60
33
|
* stripped *first*: Vite colors the host and the port separately, so escape
|
|
61
34
|
* sequences sit in the middle of the URL text and no pattern would survive
|
|
62
35
|
* matching against the raw bytes. Returns undefined for anything that isn't
|
|
63
|
-
* the ready line — the same shape
|
|
36
|
+
* the ready line — the same shape the retired workbench lab used, the
|
|
64
37
|
* house pattern for these one-line protocols.
|
|
65
38
|
*/
|
|
66
39
|
export declare function parseViteLocalUrl(line: string): string | undefined;
|
|
@@ -75,3 +48,18 @@ export declare function parseViteLocalUrl(line: string): string | undefined;
|
|
|
75
48
|
* process).
|
|
76
49
|
*/
|
|
77
50
|
export declare function teeAndDetectLocalUrl(source: NodeJS.ReadableStream, sink: NodeJS.WritableStream, onUrl: (url: string) => void): void;
|
|
51
|
+
/**
|
|
52
|
+
* The browser sidecar: once the dev server's URL is known, put it in front of
|
|
53
|
+
* the user — in the *session browser* (the shared window `aiui claude`
|
|
54
|
+
* attaches the agent to; see aiui-util's browser module and `aiui open`),
|
|
55
|
+
* never their default browser. A running session browser gets a new tab; none running
|
|
56
|
+
* means launching one exactly the way `aiui browser` does
|
|
57
|
+
* ({@link startSessionBrowser}), with the app as its first tab.
|
|
58
|
+
*
|
|
59
|
+
* Runs concurrently with Vite and must never interfere with it: everything is
|
|
60
|
+
* caught, failures print a warning, and the dev server keeps the terminal and
|
|
61
|
+
* keeps running either way. It is also deliberately non-interactive — Vite
|
|
62
|
+
* owns stdin — so the Chrome for Testing sync never prompts here; it just
|
|
63
|
+
* uses whatever browser is already available.
|
|
64
|
+
*/
|
|
65
|
+
export declare function openAppInBrowser(url: string, aiuiArgs: AiuiArgs): Promise<void>;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { readFileSync as C, mkdirSync as T, writeFileSync as x } from "node:fs";
|
|
2
|
+
import { join as p, dirname as S } from "node:path";
|
|
3
|
+
import { projectCacheDir as E } from "@habemus-papadum/aiui-claude-channel";
|
|
4
|
+
import { CHROME_CHANNELS as N, cacheDir as $ } from "@habemus-papadum/aiui-util";
|
|
5
|
+
const O = ["prompt", "auto", "off"], P = ["attach", "launch"], D = ["loopback", "host"], u = [
|
|
6
|
+
{
|
|
7
|
+
name: "claude",
|
|
8
|
+
summary: "how `aiui claude` launches Claude Code",
|
|
9
|
+
fields: [
|
|
10
|
+
{
|
|
11
|
+
key: "skipPermissions",
|
|
12
|
+
type: "boolean",
|
|
13
|
+
default: !0,
|
|
14
|
+
defaultText: "true (unset: the first interactive launch asks, then persists the answer)",
|
|
15
|
+
summary: "Launch Claude Code with --dangerously-skip-permissions.",
|
|
16
|
+
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."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
key: "enterNudge",
|
|
20
|
+
type: "boolean",
|
|
21
|
+
default: !0,
|
|
22
|
+
defaultText: "true (unset: the first interactive launch asks, then persists the answer)",
|
|
23
|
+
summary: "Auto-dismiss Claude Code's development-channel acknowledgement prompt.",
|
|
24
|
+
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."
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "channel",
|
|
30
|
+
summary: "the channel server's web backend",
|
|
31
|
+
fields: [
|
|
32
|
+
{
|
|
33
|
+
key: "bind",
|
|
34
|
+
type: "enum",
|
|
35
|
+
values: D,
|
|
36
|
+
default: "loopback",
|
|
37
|
+
defaultText: '"loopback" (unset: the first interactive launch asks, then persists the answer)',
|
|
38
|
+
summary: "Which interface the channel web server binds: loopback, or host (LAN).",
|
|
39
|
+
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.'
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "chrome",
|
|
45
|
+
summary: "the agent's browser and the Chrome DevTools MCP",
|
|
46
|
+
fields: [
|
|
47
|
+
{
|
|
48
|
+
key: "enabled",
|
|
49
|
+
type: "boolean",
|
|
50
|
+
default: !0,
|
|
51
|
+
summary: "Attach the Chrome DevTools MCP.",
|
|
52
|
+
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."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: "mode",
|
|
56
|
+
type: "enum",
|
|
57
|
+
values: P,
|
|
58
|
+
default: "attach",
|
|
59
|
+
summary: "How the MCP reaches a browser: shared session browser, or its own.",
|
|
60
|
+
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.`
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "browserUrl",
|
|
64
|
+
type: "string",
|
|
65
|
+
defaultText: "unset (manage a browser locally)",
|
|
66
|
+
summary: "Attach to this DevTools endpoint instead of managing a browser at all.",
|
|
67
|
+
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.',
|
|
68
|
+
validate: (e) => j(String(e)) ? void 0 : 'expected an http(s) URL like "http://127.0.0.1:9222"'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "debugPort",
|
|
72
|
+
type: "number",
|
|
73
|
+
default: 0,
|
|
74
|
+
defaultText: "0 (an OS-assigned free port)",
|
|
75
|
+
summary: "Fixed DevTools debug port for session browsers aiui launches.",
|
|
76
|
+
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.",
|
|
77
|
+
validate: (e) => Number.isInteger(e) && e >= 0 && e <= 65535 ? void 0 : "expected 0..65535"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: "profile",
|
|
81
|
+
type: "string",
|
|
82
|
+
default: "default",
|
|
83
|
+
summary: "Named profile under .aiui-cache/chrome/.",
|
|
84
|
+
doc: "Per-launch flag: --aiui-chrome-profile."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
key: "dataDir",
|
|
88
|
+
type: "string",
|
|
89
|
+
defaultText: "unset (derived from chrome.profile)",
|
|
90
|
+
summary: "Explicit Chrome user data dir; takes precedence over chrome.profile.",
|
|
91
|
+
doc: "Per-launch flag: --aiui-chrome-data-dir."
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
key: "executablePath",
|
|
95
|
+
type: "string",
|
|
96
|
+
defaultText: "unset (managed Chrome for Testing when installed, else installed Chrome)",
|
|
97
|
+
summary: "Chrome binary to launch — e.g. a Chrome for Testing install.",
|
|
98
|
+
doc: "Chrome for Testing still honors --load-extension, so the aiui DevTools panel can auto-load. Mutually exclusive with chrome.channel."
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
key: "channel",
|
|
102
|
+
type: "enum",
|
|
103
|
+
values: N,
|
|
104
|
+
defaultText: 'unset ("stable" when launching an installed Chrome)',
|
|
105
|
+
summary: "Installed Chrome release channel to launch.",
|
|
106
|
+
doc: "Mutually exclusive with chrome.executablePath."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: "forTesting",
|
|
110
|
+
type: "enum",
|
|
111
|
+
values: O,
|
|
112
|
+
default: "prompt",
|
|
113
|
+
summary: "How `aiui claude` manages the recommended Chrome for Testing install.",
|
|
114
|
+
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.'
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: "headless",
|
|
118
|
+
type: "boolean",
|
|
119
|
+
default: !1,
|
|
120
|
+
summary: "Launch Chrome with no UI."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
key: "buildExtension",
|
|
124
|
+
type: "boolean",
|
|
125
|
+
default: !0,
|
|
126
|
+
summary: "OBSOLETE — parsed and ignored (the DevTools extension is deleted).",
|
|
127
|
+
doc: "The only extension a launch auto-loads is the intent client, whose MV3 bundle is built deliberately (`pnpm -C packages/aiui-intent-client build:ext`). Kept in the schema so old configs stay valid."
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
key: "autoCapture",
|
|
131
|
+
type: "boolean",
|
|
132
|
+
default: !0,
|
|
133
|
+
summary: "OBSOLETE — parsed and ignored (page-side getDisplayMedia capture is gone).",
|
|
134
|
+
doc: "The intent client's hosts capture natively (CDP screenshots / the extension's tabCapture stream); nothing reads the page-side capture marker any more. Kept in the schema so old configs stay valid."
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
function J() {
|
|
140
|
+
return u.flatMap(
|
|
141
|
+
(e) => e.fields.map((t) => ({ section: e, field: t, path: `${e.name}.${t.key}` }))
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
function w(e) {
|
|
145
|
+
return e.type === "enum" ? "string" : e.type;
|
|
146
|
+
}
|
|
147
|
+
function b(e, t) {
|
|
148
|
+
var n;
|
|
149
|
+
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);
|
|
150
|
+
}
|
|
151
|
+
function V(e, t) {
|
|
152
|
+
let n;
|
|
153
|
+
switch (w(e)) {
|
|
154
|
+
case "boolean": {
|
|
155
|
+
if (t !== "true" && t !== "false")
|
|
156
|
+
return { error: "expected true or false" };
|
|
157
|
+
n = t === "true";
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case "number": {
|
|
161
|
+
if (n = Number(t), t.trim() === "" || Number.isNaN(n))
|
|
162
|
+
return { error: "expected a number" };
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
default:
|
|
166
|
+
n = t;
|
|
167
|
+
}
|
|
168
|
+
const a = b(e, n);
|
|
169
|
+
return a ? { error: a } : { value: n };
|
|
170
|
+
}
|
|
171
|
+
function k(e) {
|
|
172
|
+
return typeof e == "string" ? JSON.stringify(e) : String(e);
|
|
173
|
+
}
|
|
174
|
+
function B(e) {
|
|
175
|
+
return e.defaultText ? e.defaultText : e.default === void 0 ? "unset" : k(e.default);
|
|
176
|
+
}
|
|
177
|
+
function j(e) {
|
|
178
|
+
try {
|
|
179
|
+
const t = new URL(e);
|
|
180
|
+
return t.protocol === "http:" || t.protocol === "https:";
|
|
181
|
+
} catch {
|
|
182
|
+
return !1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const y = "config.json", A = /* @__PURE__ */ new Set(["sidecars"]);
|
|
186
|
+
function v(e = process.cwd()) {
|
|
187
|
+
return {
|
|
188
|
+
user: p($(void 0, { create: !1 }), y),
|
|
189
|
+
project: p(E(e), y)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function G(e = process.cwd()) {
|
|
193
|
+
const t = v(e);
|
|
194
|
+
return I(l(t.user) ?? {}, l(t.project) ?? {});
|
|
195
|
+
}
|
|
196
|
+
function I(e, t) {
|
|
197
|
+
const n = {};
|
|
198
|
+
for (const a of u)
|
|
199
|
+
n[a.name] = {
|
|
200
|
+
...e[a.name],
|
|
201
|
+
...t[a.name]
|
|
202
|
+
};
|
|
203
|
+
return n;
|
|
204
|
+
}
|
|
205
|
+
function l(e) {
|
|
206
|
+
let t;
|
|
207
|
+
try {
|
|
208
|
+
t = C(e, "utf8");
|
|
209
|
+
} catch {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
let n;
|
|
213
|
+
try {
|
|
214
|
+
n = JSON.parse(t);
|
|
215
|
+
} catch (a) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`invalid JSON in ${e}: ${a instanceof Error ? a.message : String(a)}`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return M(n, e);
|
|
221
|
+
}
|
|
222
|
+
function M(e, t) {
|
|
223
|
+
const n = g(e, t, "the top level"), a = u.map((r) => r.name);
|
|
224
|
+
for (const r of Object.keys(n))
|
|
225
|
+
if (!(a.includes(r) || A.has(r)))
|
|
226
|
+
throw new Error(
|
|
227
|
+
`unknown key "${r}" at the top level of ${t} — known keys: ${a.join(", ")}`
|
|
228
|
+
);
|
|
229
|
+
const s = {};
|
|
230
|
+
for (const r of u) {
|
|
231
|
+
if (n[r.name] === void 0)
|
|
232
|
+
continue;
|
|
233
|
+
const c = g(n[r.name], t, `"${r.name}"`);
|
|
234
|
+
L(
|
|
235
|
+
c,
|
|
236
|
+
r.fields.map((o) => o.key),
|
|
237
|
+
t,
|
|
238
|
+
`"${r.name}"`
|
|
239
|
+
);
|
|
240
|
+
const h = {};
|
|
241
|
+
for (const o of r.fields) {
|
|
242
|
+
const i = c[o.key];
|
|
243
|
+
if (i === void 0)
|
|
244
|
+
continue;
|
|
245
|
+
const d = `${r.name}.${o.key}`, m = w(o);
|
|
246
|
+
if (typeof i !== m)
|
|
247
|
+
throw new Error(`expected a ${m} for ${d} in ${t}`);
|
|
248
|
+
const f = b(o, i);
|
|
249
|
+
if (f)
|
|
250
|
+
throw new Error(
|
|
251
|
+
`invalid ${d} ${k(i)} in ${t} — ${f}`
|
|
252
|
+
);
|
|
253
|
+
h[o.key] = i;
|
|
254
|
+
}
|
|
255
|
+
s[r.name] = h;
|
|
256
|
+
}
|
|
257
|
+
return s;
|
|
258
|
+
}
|
|
259
|
+
function K(e) {
|
|
260
|
+
return F(v().user, e);
|
|
261
|
+
}
|
|
262
|
+
function F(e, t) {
|
|
263
|
+
const n = l(e) ?? {};
|
|
264
|
+
return t(n), T(S(e), { recursive: !0 }), x(e, `${JSON.stringify(n, null, 2)}
|
|
265
|
+
`), e;
|
|
266
|
+
}
|
|
267
|
+
function g(e, t, n) {
|
|
268
|
+
if (typeof e != "object" || e === null || Array.isArray(e))
|
|
269
|
+
throw new Error(`expected an object at ${n} of ${t}`);
|
|
270
|
+
return e;
|
|
271
|
+
}
|
|
272
|
+
function L(e, t, n, a) {
|
|
273
|
+
for (const s of Object.keys(e))
|
|
274
|
+
if (!t.includes(s))
|
|
275
|
+
throw new Error(
|
|
276
|
+
`unknown key "${s}" at ${a} of ${n} — known keys: ${t.join(", ")}`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
export {
|
|
280
|
+
D as C,
|
|
281
|
+
J as a,
|
|
282
|
+
F as b,
|
|
283
|
+
v as c,
|
|
284
|
+
B as d,
|
|
285
|
+
u as e,
|
|
286
|
+
k as f,
|
|
287
|
+
G as l,
|
|
288
|
+
I as m,
|
|
289
|
+
V as p,
|
|
290
|
+
l as r,
|
|
291
|
+
K as u
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=config-Cis6kCik.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-Cis6kCik.js","sources":["../src/util/config-schema.ts","../src/util/config.ts"],"sourcesContent":["/**\n * The declarative schema for aiui's `config.json` — one table that drives\n * everything config-shaped:\n *\n * - validation (util/config.ts walks these sections instead of hand-rolled\n * per-key checks),\n * - the `aiui config` commands (show/get/set/unset use it to resolve keys,\n * parse CLI values, and report defaults),\n * - the `aiui config tui` browser (docs, defaults, and enum choices all\n * render from here).\n *\n * Because docs, defaults, and validation come from the same rows, they cannot\n * drift apart. `docs/guide/config.md` remains the long-form narrative; the\n * `doc` strings here are the terminal-sized versions.\n *\n * **How a component participates.** `CONFIG_SECTIONS` is the registry: a\n * section is plain data, so a future component that grows file-backed settings\n * (say, an `intent` section for the pipeline) joins by contributing one\n * `ConfigSectionSchema` object here and a matching optional section on\n * `AiuiConfig`. Nothing else — validation, show/get/set, and the TUI pick it\n * up from the table. (The intent pipeline's current config is deliberately\n * *not* here: it is per-app, passed as `aiuiDevOverlay({ intent: { … } })` in\n * the app's Vite config — see docs/guide/intent-overlay.md.)\n */\n\n// The channel list lives with the launch code (aiui-util's browser module,\n// whose RELEASE_CHANNELS map must stay exhaustive over it); re-exported here\n// so the config table keeps being the one import surface for config shapes.\nimport { CHROME_CHANNELS } from \"@habemus-papadum/aiui-util\";\n\nexport { CHROME_CHANNELS, type ChromeChannel } from \"@habemus-papadum/aiui-util\";\n\nexport const FOR_TESTING_MODES = [\"prompt\", \"auto\", \"off\"] as const;\nexport type ForTestingMode = (typeof FOR_TESTING_MODES)[number];\n\nexport const CHROME_MODES = [\"attach\", \"launch\"] as const;\nexport type ChromeMode = (typeof CHROME_MODES)[number];\n\nexport const CHANNEL_BINDS = [\"loopback\", \"host\"] as const;\nexport type ChannelBind = (typeof CHANNEL_BINDS)[number];\n\n/** Every config leaf is a JSON scalar; sections never nest further. */\nexport type ConfigValue = boolean | number | string;\n\nexport interface ConfigFieldSchema {\n /** Leaf key within its section, e.g. `\"skipPermissions\"`. */\n key: string;\n /** `\"enum\"` is a string constrained to {@link values}. */\n type: \"boolean\" | \"number\" | \"string\" | \"enum\";\n /** The allowed values when {@link type} is `\"enum\"`. */\n values?: readonly string[];\n /** The built-in default, when the fallback is a plain value. */\n default?: ConfigValue;\n /**\n * Human phrasing of the default when a bare value would mislead (dynamic\n * fallbacks, first-run prompts). Shown instead of {@link default}.\n */\n defaultText?: string;\n /** One-line summary — the TUI's list row. */\n summary: string;\n /** The rest of the documentation (terminal-sized; optional). */\n doc?: string;\n /**\n * Constraint beyond type/enum. Returns the \"expected …\" tail of the error\n * message, or undefined when the value is fine.\n */\n validate?: (value: ConfigValue) => string | undefined;\n}\n\nexport interface ConfigSectionSchema {\n /** Top-level key in config.json, e.g. `\"chrome\"`. */\n name: string;\n /** One-line summary of what the section configures. */\n summary: string;\n fields: ConfigFieldSchema[];\n}\n\nexport const CONFIG_SECTIONS: ConfigSectionSchema[] = [\n {\n name: \"claude\",\n summary: \"how `aiui claude` launches Claude Code\",\n fields: [\n {\n key: \"skipPermissions\",\n type: \"boolean\",\n default: true,\n defaultText: \"true (unset: the first interactive launch asks, then persists the answer)\",\n summary: \"Launch Claude Code with --dangerously-skip-permissions.\",\n doc:\n \"A personal preference with real consequences (docs/guide/warning): every agent \" +\n \"action — shell commands, file writes, network, the browser — runs without asking \" +\n \"first. aiui works fine either way. The first interactive launch asks and persists \" +\n \"the answer at the user level; when unset, non-interactive sessions fall back to true.\",\n },\n {\n key: \"enterNudge\",\n type: \"boolean\",\n default: true,\n defaultText: \"true (unset: the first interactive launch asks, then persists the answer)\",\n summary: \"Auto-dismiss Claude Code's development-channel acknowledgement prompt.\",\n doc:\n \"aiui loads a custom development channel, so Claude Code shows a one-key \" +\n \"acknowledgement at every startup; this injects a single Enter keystroke into the \" +\n \"terminal to dismiss it (best-effort TIOCSTI on /dev/tty — platforms that forbid it \" +\n \"harmlessly do nothing). Saying no just means pressing Enter yourself each launch.\",\n },\n ],\n },\n {\n name: \"channel\",\n summary: \"the channel server's web backend\",\n fields: [\n {\n key: \"bind\",\n type: \"enum\",\n values: CHANNEL_BINDS,\n default: \"loopback\",\n defaultText:\n '\"loopback\" (unset: the first interactive launch asks, then persists the answer)',\n summary: \"Which interface the channel web server binds: loopback, or host (LAN).\",\n doc:\n '\"host\" (0.0.0.0) makes the session\\'s whole web surface — the iPad paint page, but ' +\n \"also prompt injection, /debug, and every sidecar — reachable by anyone on your \" +\n \"network, UNAUTHENTICATED. That is the trusted-LAN posture (docs/guide/warning): \" +\n 'right on a network that is yours alone, wrong on shared Wi-Fi. \"loopback\" keeps ' +\n \"everything this-machine-only; reaching the paint page from an iPad is then up to \" +\n \"you — tunnel the channel port however you like (Tailscale, `ssh -L`). The first \" +\n \"interactive launch asks and persists the answer at the user level. Per-launch \" +\n \"flag: --aiui-bind.\",\n },\n ],\n },\n {\n name: \"chrome\",\n summary: \"the agent's browser and the Chrome DevTools MCP\",\n fields: [\n {\n key: \"enabled\",\n type: \"boolean\",\n default: true,\n summary: \"Attach the Chrome DevTools MCP.\",\n doc:\n \"false turns it off everywhere; true restates the default and does NOT override the \" +\n \"CI default-off — only the --aiui-chrome flag forces it on under CI.\",\n },\n {\n key: \"mode\",\n type: \"enum\",\n values: CHROME_MODES,\n default: \"attach\",\n summary: \"How the MCP reaches a browser: shared session browser, or its own.\",\n doc:\n '\"attach\" shares a user-visible session browser: an already-running one is ' +\n 'discovered by profile, or an interactive launch starts one eagerly. \"launch\" is ' +\n \"the hands-off mode: chrome-devtools-mcp launches its own private browser lazily, on \" +\n \"the agent's first browser tool call.\",\n },\n {\n key: \"browserUrl\",\n type: \"string\",\n defaultText: \"unset (manage a browser locally)\",\n summary: \"Attach to this DevTools endpoint instead of managing a browser at all.\",\n doc:\n \"The remote-development key (docs/guide/remote): the browser runs on another machine \" +\n \"(started there with `aiui browser`) and its debug port is tunneled over. Setting it \" +\n 'implies mode: \"attach\" and makes every local-browser setting (profile, ' +\n \"executablePath, channel, forTesting…) irrelevant. Per-launch flag: --aiui-browser-url.\",\n validate: (value) =>\n isHttpUrl(String(value))\n ? undefined\n : 'expected an http(s) URL like \"http://127.0.0.1:9222\"',\n },\n {\n key: \"debugPort\",\n type: \"number\",\n default: 0,\n defaultText: \"0 (an OS-assigned free port)\",\n summary: \"Fixed DevTools debug port for session browsers aiui launches.\",\n doc:\n \"Pin it (e.g. 9222) when something external must find the port — an ssh tunnel, a \" +\n \"VS Code attach-to-Chrome launch config. 0 means an OS-assigned free port.\",\n validate: (value) =>\n Number.isInteger(value) && (value as number) >= 0 && (value as number) <= 65535\n ? undefined\n : \"expected 0..65535\",\n },\n {\n key: \"profile\",\n type: \"string\",\n default: \"default\",\n summary: \"Named profile under .aiui-cache/chrome/.\",\n doc: \"Per-launch flag: --aiui-chrome-profile.\",\n },\n {\n key: \"dataDir\",\n type: \"string\",\n defaultText: \"unset (derived from chrome.profile)\",\n summary: \"Explicit Chrome user data dir; takes precedence over chrome.profile.\",\n doc: \"Per-launch flag: --aiui-chrome-data-dir.\",\n },\n {\n key: \"executablePath\",\n type: \"string\",\n defaultText: \"unset (managed Chrome for Testing when installed, else installed Chrome)\",\n summary: \"Chrome binary to launch — e.g. a Chrome for Testing install.\",\n doc:\n \"Chrome for Testing still honors --load-extension, so the aiui DevTools panel can \" +\n \"auto-load. Mutually exclusive with chrome.channel.\",\n },\n {\n key: \"channel\",\n type: \"enum\",\n values: CHROME_CHANNELS,\n defaultText: 'unset (\"stable\" when launching an installed Chrome)',\n summary: \"Installed Chrome release channel to launch.\",\n doc: \"Mutually exclusive with chrome.executablePath.\",\n },\n {\n key: \"forTesting\",\n type: \"enum\",\n values: FOR_TESTING_MODES,\n default: \"prompt\",\n summary: \"How `aiui claude` manages the recommended Chrome for Testing install.\",\n doc:\n '\"prompt\" asks before installing or updating it — interactive sessions only, never ' +\n 'under CI; \"auto\" installs/updates without asking; \"off\" never checks. Prompt ' +\n 'answers (\"automatically\", \"never ask again\") persist here at the user level. ' +\n \"Skipped entirely when executablePath or channel picks a browser explicitly.\",\n },\n {\n key: \"headless\",\n type: \"boolean\",\n default: false,\n summary: \"Launch Chrome with no UI.\",\n },\n {\n key: \"buildExtension\",\n type: \"boolean\",\n default: true,\n summary: \"OBSOLETE — parsed and ignored (the DevTools extension is deleted).\",\n doc:\n \"The only extension a launch auto-loads is the intent client, whose MV3 bundle \" +\n \"is built deliberately (`pnpm -C packages/aiui-intent-client build:ext`). \" +\n \"Kept in the schema so old configs stay valid.\",\n },\n {\n key: \"autoCapture\",\n type: \"boolean\",\n default: true,\n summary: \"OBSOLETE — parsed and ignored (page-side getDisplayMedia capture is gone).\",\n doc:\n \"The intent client's hosts capture natively (CDP screenshots / the extension's \" +\n \"tabCapture stream); nothing reads the page-side capture marker any more. Kept in \" +\n \"the schema so old configs stay valid.\",\n },\n ],\n },\n];\n\n/** A field paired with its section — what key-resolution hands back. */\nexport interface ResolvedField {\n section: ConfigSectionSchema;\n field: ConfigFieldSchema;\n /** The dotted path, e.g. `\"chrome.mode\"`. */\n path: string;\n}\n\n/** Every field in schema order, with dotted paths. */\nexport function allConfigFields(): ResolvedField[] {\n return CONFIG_SECTIONS.flatMap((section) =>\n section.fields.map((field) => ({ section, field, path: `${section.name}.${field.key}` })),\n );\n}\n\n/** Resolve a dotted path like `\"chrome.mode\"`; undefined when unknown. */\nexport function findConfigField(path: string): ResolvedField | undefined {\n return allConfigFields().find((entry) => entry.path === path);\n}\n\n/** The `typeof` a field's values (enums are strings). */\nexport function fieldRuntimeType(field: ConfigFieldSchema): \"boolean\" | \"number\" | \"string\" {\n return field.type === \"enum\" ? \"string\" : field.type;\n}\n\n/**\n * Constraint check beyond the runtime type: enum membership, then the field's\n * own `validate`. Returns the \"expected …\" tail for the error, or undefined.\n */\nexport function invalidReason(field: ConfigFieldSchema, value: ConfigValue): string | undefined {\n if (field.type === \"enum\" && !(field.values ?? []).includes(String(value))) {\n return `expected one of: ${(field.values ?? []).join(\", \")}`;\n }\n return field.validate?.(value);\n}\n\n/**\n * Parse a CLI-provided string into the field's type and validate it — how\n * `aiui config set` and the TUI turn text into a config value.\n */\nexport function parseFieldValue(\n field: ConfigFieldSchema,\n raw: string,\n): { value: ConfigValue } | { error: string } {\n let value: ConfigValue;\n switch (fieldRuntimeType(field)) {\n case \"boolean\": {\n if (raw !== \"true\" && raw !== \"false\") {\n return { error: \"expected true or false\" };\n }\n value = raw === \"true\";\n break;\n }\n case \"number\": {\n value = Number(raw);\n if (raw.trim() === \"\" || Number.isNaN(value)) {\n return { error: \"expected a number\" };\n }\n break;\n }\n default:\n value = raw;\n }\n const reason = invalidReason(field, value);\n return reason ? { error: reason } : { value };\n}\n\n/** Render a value the way config.json would hold it (strings quoted). */\nexport function formatConfigValue(value: ConfigValue): string {\n return typeof value === \"string\" ? JSON.stringify(value) : String(value);\n}\n\n/** The default, phrased for humans: `defaultText` wins, then the value, then \"unset\". */\nexport function describeDefault(field: ConfigFieldSchema): string {\n if (field.defaultText) {\n return field.defaultText;\n }\n return field.default === undefined ? \"unset\" : formatConfigValue(field.default);\n}\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n","/**\n * aiui's two-level configuration file.\n *\n * Settings live in `config.json` at up to two places, merged per-key with the\n * more specific one winning:\n *\n * <user cache>/config.json e.g. ~/.cache/aiui/config.json (respects\n * AIUI_CACHE / XDG_CACHE_HOME)\n * <project>/.aiui-cache/config.json next to the traces and Chrome profiles\n *\n * CLI flags override both. Everything is optional; a missing file is an empty\n * config. A *malformed* file is a hard error, not a warning — these settings\n * gate security-relevant behavior (`claude.skipPermissions`), and a typo that\n * silently reverts to the dangerous default is worse than a failed launch. The\n * same reasoning rejects unknown keys.\n *\n * What the keys are — types, enums, defaults, and documentation — lives in one\n * declarative table, `config-schema.ts`. Validation here walks that schema, and\n * the `aiui config` commands (show/get/set/tui) render from it, so the checks\n * and the docs cannot drift apart.\n */\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { projectCacheDir } from \"@habemus-papadum/aiui-claude-channel\";\nimport { cacheDir } from \"@habemus-papadum/aiui-util\";\nimport {\n type ChannelBind,\n type ChromeChannel,\n type ChromeMode,\n CONFIG_SECTIONS,\n type ConfigValue,\n type ForTestingMode,\n fieldRuntimeType,\n formatConfigValue,\n invalidReason,\n} from \"./config-schema\";\n\nexport {\n CHANNEL_BINDS,\n CHROME_CHANNELS,\n CHROME_MODES,\n type ChannelBind,\n type ChromeChannel,\n type ChromeMode,\n FOR_TESTING_MODES,\n type ForTestingMode,\n} from \"./config-schema\";\n\nexport const CONFIG_FILENAME = \"config.json\";\n\n/**\n * The typed shape of a config file. Must mirror `CONFIG_SECTIONS` in\n * config-schema.ts — the schema rows carry the full per-key documentation and\n * defaults; the comments here are just orientation.\n */\nexport interface AiuiConfig {\n claude?: {\n /** Launch Claude Code with `--dangerously-skip-permissions`. */\n skipPermissions?: boolean;\n /** Auto-dismiss Claude Code's development-channel prompt (util/enter-nudge.ts). */\n enterNudge?: boolean;\n };\n channel?: {\n /** Which interface the channel web server binds: loopback (default) or host (LAN). */\n bind?: ChannelBind;\n };\n chrome?: {\n /** Attach the Chrome DevTools MCP (default: true). */\n enabled?: boolean;\n /** How the MCP reaches a browser: shared session browser, or its own. */\n mode?: ChromeMode;\n /** Attach to this DevTools endpoint instead of managing a browser at all. */\n browserUrl?: string;\n /** Fixed DevTools debug port for session browsers aiui launches (0 = OS-assigned). */\n debugPort?: number;\n /** Named profile under `.aiui-cache/chrome/` (default: \"default\"). */\n profile?: string;\n /** Explicit Chrome user data dir; takes precedence over `profile`. */\n dataDir?: string;\n /** Chrome binary to launch. Mutually exclusive with `channel`. */\n executablePath?: string;\n /** Installed Chrome release channel to launch. */\n channel?: ChromeChannel;\n /** How `aiui claude` manages the Chrome for Testing install. */\n forTesting?: ForTestingMode;\n /** Launch Chrome headless (default: false). */\n headless?: boolean;\n /** OBSOLETE (the devtools extension is deleted): parsed and ignored so old\n * configs stay valid. */\n buildExtension?: boolean;\n /** OBSOLETE (page-side getDisplayMedia capture is gone): parsed and\n * ignored so old configs stay valid. */\n autoCapture?: boolean;\n };\n}\n\n/** The untyped view validation and merging work in: section → leaf values. */\ntype SectionValues = Record<string, ConfigValue>;\n\n/**\n * Top-level sections that USED to be valid and are now gone. A config file that\n * still carries one must not hard-fail — that would break every existing\n * config on upgrade — so it is accepted and ignored, distinct from a\n * genuinely-unknown key (a typo), which still throws. `sidecars.*` retired when\n * the channel began hosting its whole standard set unconditionally (paint,\n * intent, bar, pencil): there is nothing left to toggle, so the key is inert and\n * safe to delete.\n */\nconst DEPRECATED_SECTIONS = new Set([\"sidecars\"]);\n\n/** The `config.json` paths consulted, user-level first (base: the project dir). */\nexport function configPaths(base: string = process.cwd()): { user: string; project: string } {\n return {\n user: join(cacheDir(undefined, { create: false }), CONFIG_FILENAME),\n project: join(projectCacheDir(base), CONFIG_FILENAME),\n };\n}\n\n/** Load and merge the user- and project-level configs (project wins per key). */\nexport function loadAiuiConfig(base: string = process.cwd()): AiuiConfig {\n const paths = configPaths(base);\n return mergeAiuiConfig(readConfigFile(paths.user) ?? {}, readConfigFile(paths.project) ?? {});\n}\n\n/** Merge two configs section-by-section; `override`'s keys win within a section. */\nexport function mergeAiuiConfig(base: AiuiConfig, override: AiuiConfig): AiuiConfig {\n const merged: Record<string, SectionValues> = {};\n for (const section of CONFIG_SECTIONS) {\n merged[section.name] = {\n ...(base as Record<string, SectionValues | undefined>)[section.name],\n ...(override as Record<string, SectionValues | undefined>)[section.name],\n };\n }\n return merged as AiuiConfig;\n}\n\n/**\n * Read one config file. Missing → undefined; unreadable JSON or an unexpected\n * shape → an error naming the file, so the fix is obvious.\n */\nexport function readConfigFile(file: string): AiuiConfig | undefined {\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return undefined;\n }\n let raw: unknown;\n try {\n raw = JSON.parse(text);\n } catch (error) {\n throw new Error(\n `invalid JSON in ${file}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n return validateConfig(raw, file);\n}\n\n/** Walk `CONFIG_SECTIONS`, rejecting unknown keys, wrong types, and bad values. */\nfunction validateConfig(raw: unknown, file: string): AiuiConfig {\n const root = asSection(raw, file, \"the top level\");\n const knownSections = CONFIG_SECTIONS.map((s) => s.name);\n for (const key of Object.keys(root)) {\n // A retired section is tolerated (accepted, then ignored below); a truly\n // unknown one is a typo and still throws — see DEPRECATED_SECTIONS.\n if (knownSections.includes(key) || DEPRECATED_SECTIONS.has(key)) {\n continue;\n }\n throw new Error(\n `unknown key \"${key}\" at the top level of ${file} — known keys: ${knownSections.join(\", \")}`,\n );\n }\n\n const config: Record<string, SectionValues> = {};\n for (const section of CONFIG_SECTIONS) {\n if (root[section.name] === undefined) {\n continue;\n }\n const values = asSection(root[section.name], file, `\"${section.name}\"`);\n rejectUnknownKeys(\n values,\n section.fields.map((f) => f.key),\n file,\n `\"${section.name}\"`,\n );\n // Absent keys stay absent (never `undefined`), or merging would let them\n // clobber a value from the other config level.\n const out: SectionValues = {};\n for (const field of section.fields) {\n const value = values[field.key];\n if (value === undefined) {\n continue;\n }\n const path = `${section.name}.${field.key}`;\n const type = fieldRuntimeType(field);\n if (typeof value !== type) {\n throw new Error(`expected a ${type} for ${path} in ${file}`);\n }\n const reason = invalidReason(field, value as ConfigValue);\n if (reason) {\n throw new Error(\n `invalid ${path} ${formatConfigValue(value as ConfigValue)} in ${file} — ${reason}`,\n );\n }\n out[field.key] = value as ConfigValue;\n }\n config[section.name] = out;\n }\n return config as AiuiConfig;\n}\n\n/**\n * Persist a change to the **user-level** config (creating the file if needed).\n *\n * This is how interactive prompt answers like \"never ask again\" become\n * durable: they are per-user decisions, so they land in the user cache — never\n * in the project file, which may be shared/committed by a team.\n */\nexport function updateUserConfig(mutate: (config: AiuiConfig) => void): string {\n return updateConfigFile(configPaths().user, mutate);\n}\n\n/**\n * Persist a change to a specific config file — the general form behind\n * {@link updateUserConfig}, and how `aiui config set --project` writes the\n * project level deliberately.\n */\nexport function updateConfigFile(file: string, mutate: (config: AiuiConfig) => void): string {\n const config = readConfigFile(file) ?? {};\n mutate(config);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, `${JSON.stringify(config, null, 2)}\\n`);\n return file;\n}\n\nfunction asSection(value: unknown, file: string, where: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(`expected an object at ${where} of ${file}`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction rejectUnknownKeys(\n section: Record<string, unknown>,\n known: string[],\n file: string,\n where: string,\n): void {\n for (const key of Object.keys(section)) {\n if (!known.includes(key)) {\n throw new Error(\n `unknown key \"${key}\" at ${where} of ${file} — known keys: ${known.join(\", \")}`,\n );\n }\n }\n}\n"],"names":["FOR_TESTING_MODES","CHROME_MODES","CHANNEL_BINDS","CONFIG_SECTIONS","value","isHttpUrl","CHROME_CHANNELS","allConfigFields","section","field","fieldRuntimeType","invalidReason","_a","parseFieldValue","raw","reason","formatConfigValue","describeDefault","url","CONFIG_FILENAME","DEPRECATED_SECTIONS","configPaths","base","join","cacheDir","projectCacheDir","loadAiuiConfig","paths","mergeAiuiConfig","readConfigFile","override","merged","file","text","readFileSync","error","validateConfig","root","asSection","knownSections","s","key","config","values","rejectUnknownKeys","f","out","path","type","updateUserConfig","mutate","updateConfigFile","mkdirSync","dirname","writeFileSync","where","known"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
* ai ui frontends
|
|
3
3
|
*
|
|
4
4
|
* The `aiui` CLI's library surface. Launch *policy* the CLI applies lives here
|
|
5
|
-
* too, so sibling supervisors can reuse it instead of re-deriving it — the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* project root. The workbench imports it to give its debug channel the same
|
|
9
|
-
* sidecar set a real session would get.
|
|
5
|
+
* too, so sibling supervisors can reuse it instead of re-deriving it — e.g. the
|
|
6
|
+
* layered config loader below, so a debug-channel supervisor binds the channel
|
|
7
|
+
* the same way a real `aiui claude` launch would.
|
|
10
8
|
*
|
|
11
9
|
* @packageDocumentation
|
|
12
10
|
*/
|
|
13
|
-
export { type
|
|
11
|
+
export { type AiuiConfig, loadAiuiConfig } from "./util/config";
|
|
14
12
|
/** The published package name — handy for smoke tests. */
|
|
15
13
|
export declare const name = "@habemus-papadum/aiui";
|
|
16
14
|
/** Greet someone. Replace with your library's real API. */
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const
|
|
1
|
+
import { l as r } from "./config-Cis6kCik.js";
|
|
2
|
+
const o = "@habemus-papadum/aiui";
|
|
3
3
|
function a(e) {
|
|
4
4
|
return `Hello, ${e}!`;
|
|
5
5
|
}
|
|
6
6
|
export {
|
|
7
7
|
a as greet,
|
|
8
|
-
r as
|
|
9
|
-
|
|
8
|
+
r as loadAiuiConfig,
|
|
9
|
+
o as name
|
|
10
10
|
};
|
|
11
11
|
//# sourceMappingURL=index.js.map
|