@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.
@@ -1,82 +1,48 @@
1
+ import { type ChannelBind, type ChromeChannel, type ChromeMode, type ForTestingMode } from "./config-schema";
2
+ export { CHANNEL_BINDS, CHROME_CHANNELS, CHROME_MODES, type ChannelBind, type ChromeChannel, type ChromeMode, FOR_TESTING_MODES, type ForTestingMode, } from "./config-schema";
1
3
  export declare const CONFIG_FILENAME = "config.json";
2
- export declare const CHROME_CHANNELS: readonly ["stable", "beta", "dev", "canary"];
3
- export type ChromeChannel = (typeof CHROME_CHANNELS)[number];
4
- export declare const FOR_TESTING_MODES: readonly ["prompt", "auto", "off"];
5
- export type ForTestingMode = (typeof FOR_TESTING_MODES)[number];
6
- export declare const CHROME_MODES: readonly ["attach", "launch"];
7
- export type ChromeMode = (typeof CHROME_MODES)[number];
4
+ /**
5
+ * The typed shape of a config file. Must mirror `CONFIG_SECTIONS` in
6
+ * config-schema.ts the schema rows carry the full per-key documentation and
7
+ * defaults; the comments here are just orientation.
8
+ */
8
9
  export interface AiuiConfig {
9
10
  claude?: {
10
- /**
11
- * Launch Claude Code with `--dangerously-skip-permissions`. A personal
12
- * preference with real consequences (see docs/guide/warning) — the first
13
- * interactive launch asks and persists the answer here; when unset in a
14
- * non-interactive session it defaults to true.
15
- */
11
+ /** Launch Claude Code with `--dangerously-skip-permissions`. */
16
12
  skipPermissions?: boolean;
17
- /**
18
- * Auto-dismiss Claude Code's development-channel acknowledgement prompt
19
- * by injecting an Enter keypress into the terminal at startup (see
20
- * util/enter-nudge.ts). Chosen on first interactive run; defaults to true
21
- * when unset.
22
- */
13
+ /** Auto-dismiss Claude Code's development-channel prompt (util/enter-nudge.ts). */
23
14
  enterNudge?: boolean;
24
15
  };
16
+ channel?: {
17
+ /** Which interface the channel web server binds: loopback (default) or host (LAN). */
18
+ bind?: ChannelBind;
19
+ };
20
+ sidecars?: {
21
+ /** Host the iPad paint sidecar on the channel's port (default: true). */
22
+ paint?: boolean;
23
+ };
25
24
  chrome?: {
26
- /**
27
- * Attach the Chrome DevTools MCP (default: true). `false` turns it off
28
- * everywhere; `true` does not override the CI default-off — only the
29
- * `--aiui-chrome` flag forces it on under CI.
30
- */
25
+ /** Attach the Chrome DevTools MCP (default: true). */
31
26
  enabled?: boolean;
32
- /**
33
- * How the MCP reaches a browser (default: "attach"). `"attach"` shares a
34
- * user-visible session browser: an already-running one is discovered by
35
- * profile, or an interactive launch starts one eagerly. `"launch"` is the
36
- * hands-off mode: chrome-devtools-mcp launches its own private browser
37
- * lazily, on the agent's first browser tool call.
38
- */
27
+ /** How the MCP reaches a browser: shared session browser, or its own. */
39
28
  mode?: ChromeMode;
40
- /**
41
- * Attach to this Chrome DevTools endpoint (e.g. "http://127.0.0.1:9222")
42
- * instead of managing a browser at all — the remote-development key: the
43
- * browser runs on another machine (started there with `aiui browser`) and
44
- * its port is tunneled over. Setting it implies `mode: "attach"` and makes
45
- * every local-browser setting (profile, executablePath, channel,
46
- * forTesting…) irrelevant.
47
- */
29
+ /** Attach to this DevTools endpoint instead of managing a browser at all. */
48
30
  browserUrl?: string;
49
- /**
50
- * Fixed DevTools debug port for session browsers aiui launches
51
- * (default: 0 — an OS-assigned free port). Pin it (e.g. 9222) when
52
- * something else must find the port, like an ssh tunnel.
53
- */
31
+ /** Fixed DevTools debug port for session browsers aiui launches (0 = OS-assigned). */
54
32
  debugPort?: number;
55
33
  /** Named profile under `.aiui-cache/chrome/` (default: "default"). */
56
34
  profile?: string;
57
35
  /** Explicit Chrome user data dir; takes precedence over `profile`. */
58
36
  dataDir?: string;
59
- /**
60
- * Chrome binary to launch — e.g. a Chrome for Testing install, which
61
- * still honors `--load-extension`. Mutually exclusive with `channel`.
62
- */
37
+ /** Chrome binary to launch. Mutually exclusive with `channel`. */
63
38
  executablePath?: string;
64
- /** Installed Chrome release channel to launch (default: stable). */
39
+ /** Installed Chrome release channel to launch. */
65
40
  channel?: ChromeChannel;
66
- /**
67
- * How `aiui claude` manages Chrome for Testing, the recommended browser
68
- * (default: "prompt"). `"prompt"` asks before installing or updating it —
69
- * interactive sessions only, never under CI; `"auto"` installs/updates
70
- * without asking; `"off"` never checks. Skipped entirely when
71
- * `executablePath` or `channel` picks a browser explicitly.
72
- */
41
+ /** How `aiui claude` manages the Chrome for Testing install. */
73
42
  forTesting?: ForTestingMode;
74
43
  /** Launch Chrome headless (default: false). */
75
44
  headless?: boolean;
76
- /**
77
- * In a dev checkout, rebuild the aiui-devtools-extension package (~0.3s of tsc)
78
- * on every launch so the auto-loaded panel is never stale (default: true).
79
- */
45
+ /** Rebuild the aiui-devtools-extension on every launch in a dev checkout. */
80
46
  buildExtension?: boolean;
81
47
  };
82
48
  }
@@ -102,3 +68,9 @@ export declare function readConfigFile(file: string): AiuiConfig | undefined;
102
68
  * in the project file, which may be shared/committed by a team.
103
69
  */
104
70
  export declare function updateUserConfig(mutate: (config: AiuiConfig) => void): string;
71
+ /**
72
+ * Persist a change to a specific config file — the general form behind
73
+ * {@link updateUserConfig}, and how `aiui config set --project` writes the
74
+ * project level deliberately.
75
+ */
76
+ export declare function updateConfigFile(file: string, mutate: (config: AiuiConfig) => void): string;
@@ -2,15 +2,18 @@
2
2
  * First-run choices: settings that deserve a deliberate answer, not a silent
3
3
  * default.
4
4
  *
5
- * Two of `aiui claude`'s behaviors are pure personal preference with real
6
- * consequences: whether to launch with `--dangerously-skip-permissions`, and
5
+ * Three of `aiui claude`'s behaviors are pure personal preference with real
6
+ * consequences: whether to launch with `--dangerously-skip-permissions`,
7
7
  * whether to auto-dismiss the development-channel acknowledgement prompt by
8
- * typing into the user's terminal. Neither should be something the user
9
- * "tagged along" with because a default existed so the first interactive
10
- * launch asks (definitively: the prompts have no Enter-through default), and
11
- * the answers persist to the **user-level** config, after which nothing asks
12
- * again. Non-interactive sessions never prompt; unset values fall back to the
13
- * documented defaults (skip: true, nudge: true).
8
+ * typing into the user's terminal, and whether the channel's web server binds
9
+ * loopback-only or the host interface (the trusted-LAN posture that makes the
10
+ * whole unauthenticated surface iPad paint page included reachable from
11
+ * the network). None should be something the user "tagged along" with because
12
+ * a default existed so the first interactive launch asks (definitively: the
13
+ * prompts have no Enter-through default), and the answers persist to the
14
+ * **user-level** config, after which nothing asks again. Non-interactive
15
+ * sessions never prompt; unset values fall back to the documented defaults
16
+ * (skip: true, nudge: true, bind: loopback).
14
17
  */
15
18
  import { type AiuiConfig } from "./config";
16
19
  import { type Choice } from "./prompt";
@@ -11,8 +11,9 @@
11
11
  *
12
12
  * So the launcher's whole job is to *preflight* that env var and tell the user
13
13
  * what it found — degradation, not refusal. A missing or rejected key never
14
- * blocks the launch; the modality still mounts and transcription/correction
15
- * fall back to mock/off. The most valuable case this catches is the one that
14
+ * blocks the launch; the modality still mounts, but transcription/correction are
15
+ * unavailable until the key is set (the widget says so — `mock` is the explicit
16
+ * offline choice, not a silent fallback). The most valuable case this catches is the one that
16
17
  * bit the bench twice (see workbench field-notes, "Keys & config"): a **stale
17
18
  * shell export** shadowing the real key, which surfaces as a confusing 401 deep
18
19
  * in the pipeline rather than a clear message up front.
@@ -1,14 +1,4 @@
1
- /**
2
- * Absolute root directory of an installed (or workspace-linked) dependency.
3
- *
4
- * Rather than resolve the package *through* the module system — which would hit
5
- * its `exports` map (forcing a built `dist/`, and normally blocking access to
6
- * `package.json`) — we ask Node for the `node_modules` dirs it would search and
7
- * read `package.json` straight off disk. This needs nothing special from the
8
- * target package (no `exports` entry) and works even when it has not been
9
- * built, so dev iteration requires no compile step.
10
- */
11
- export declare function packageRoot(packageName: string): string;
1
+ export { packageRoot } from "@habemus-papadum/aiui-util";
12
2
  /** How to spawn a CLI: a program plus the args that precede any subcommand. */
13
3
  export interface CliInvocation {
14
4
  command: string;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Deciding which **session sidecars** the channel should host for a launch.
3
+ *
4
+ * A sidecar is an extra backend the channel mounts alongside the intent
5
+ * pipeline — the concrete one today is the iPad paint stream. The channel takes
6
+ * no dependency on any sidecar: `aiui claude` hands it a JSON array of
7
+ * {@link SidecarDescriptor}s on `--sidecars`, and the channel dynamic-imports
8
+ * each `module`, calls `mod[export ?? "default"](options)`, and mounts the
9
+ * result (a bad descriptor is logged + skipped there).
10
+ *
11
+ * This module is the CLI's half: a small registry of the sidecars the launcher
12
+ * knows how to construct, plus a pure resolver that decides which are on for a
13
+ * given project root and set of `--aiui-sidecar` / `--aiui-no-sidecar` flags.
14
+ */
15
+ /**
16
+ * The contract the channel's `--sidecars` argument expects, mirrored here so
17
+ * the CLI can emit it. The channel imports `module`, calls its `export` (or
18
+ * `default`) with `options`, and mounts the returned sidecar.
19
+ */
20
+ export interface SidecarDescriptor {
21
+ /** Stable identifier, used for `--aiui-sidecar`/`--aiui-no-sidecar` and logs. */
22
+ name: string;
23
+ /** Importable specifier the channel `import()`s (e.g. a package subpath). */
24
+ module: string;
25
+ /** Named export to call as the factory. Defaults to `"default"`. */
26
+ export?: string;
27
+ /** Passed opaquely to the factory (e.g. `{ root: "/proj" }`). */
28
+ options?: unknown;
29
+ }
30
+ /** Resolves a package specifier to an absolute path the channel can `import()`. */
31
+ type ResolveModule = (specifier: string) => string;
32
+ /** Injectable seams, so the resolver is unit-testable without on-disk state. */
33
+ export interface ResolveSidecarsDeps {
34
+ /**
35
+ * Resolves a sidecar's package specifier to an ABSOLUTE path. Defaults to
36
+ * `createRequire(import.meta.url).resolve`. This matters: the channel
37
+ * dynamic-imports the descriptor's `module`, but it does NOT depend on any
38
+ * sidecar package — so a bare specifier resolves from the channel's own
39
+ * node_modules and fails (pnpm's isolated layout). Resolving here (from the
40
+ * `aiui` CLI, which DOES depend on the sidecar package) to an absolute path
41
+ * makes the import work in both the source-first workspace and an install.
42
+ */
43
+ resolveModule?: ResolveModule;
44
+ /** Warning sink for a sidecar that had to be dropped (defaults to stderr). */
45
+ log?: (message: string) => void;
46
+ }
47
+ /**
48
+ * Decide which session sidecars to host for `root`.
49
+ *
50
+ * Starts from the auto-detected set (each known sidecar whose `autoEnable`
51
+ * predicate is truthy for this root), then applies the flags: `opts.enable`
52
+ * force-adds a known sidecar by name even when it wouldn't auto-detect, and
53
+ * `opts.disable` removes one. Disable wins over enable. Enable names the CLI
54
+ * doesn't know how to construct are ignored (the launcher can only build the
55
+ * sidecars in {@link KNOWN_SIDECARS}). Descriptors come back in the registry's
56
+ * stable order.
57
+ */
58
+ export declare function resolveSidecars(root: string, opts: {
59
+ enable: string[];
60
+ disable: string[];
61
+ }, deps?: ResolveSidecarsDeps): SidecarDescriptor[];
62
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habemus-papadum/aiui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "ai ui frontends",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,8 @@
14
14
  "exports": {
15
15
  ".": {
16
16
  "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js"
17
+ "import": "./dist/index.js",
18
+ "default": "./dist/index.js"
18
19
  }
19
20
  },
20
21
  "main": "./dist/index.js",
@@ -31,15 +32,18 @@
31
32
  "access": "public"
32
33
  },
33
34
  "dependencies": {
35
+ "@inquirer/prompts": "^7.2.0",
34
36
  "@puppeteer/browsers": "^2.10.5",
35
37
  "chalk": "^5.3.0",
36
38
  "commander": "^15.0.0",
37
39
  "execa": "^9.6.1",
38
40
  "vite": "^6.4.3",
39
- "@habemus-papadum/aiui-claude-plugin": "^0.2.0",
40
- "@habemus-papadum/aiui-util": "^0.2.0",
41
- "@habemus-papadum/aiui-claude-channel": "^0.2.0",
42
- "@habemus-papadum/aiui-devtools-extension": "^0.2.0"
41
+ "@habemus-papadum/aiui-claude-plugin": "^0.3.0",
42
+ "@habemus-papadum/aiui-devtools-extension": "^0.3.0",
43
+ "@habemus-papadum/aiui-dev-overlay": "^0.3.0",
44
+ "@habemus-papadum/aiui-paint": "^0.3.0",
45
+ "@habemus-papadum/aiui-claude-channel": "^0.3.0",
46
+ "@habemus-papadum/aiui-util": "^0.3.0"
43
47
  },
44
48
  "scripts": {
45
49
  "build": "tsc --emitDeclarationOnly -p tsconfig.json && vite build",
@@ -16,6 +16,8 @@
16
16
  "devDependencies": {
17
17
  "@babel/core": "^7.29.7",
18
18
  "@habemus-papadum/aiui": "__AIUI_VERSION_RANGE__",
19
+ "typescript": "^5.6.0",
20
+ "typescript-language-server": "^5.3.0",
19
21
  "vite": "^6.4.1"
20
22
  }
21
23
  }
@@ -1,44 +0,0 @@
1
- import type { ChromeChannel } from "./config";
2
- export interface SessionBrowser {
3
- /** The DevTools endpoint chrome-devtools-mcp attaches to. */
4
- browserUrl: string;
5
- port: number;
6
- }
7
- /**
8
- * A live session browser for this profile, if one is running.
9
- * Never launches anything; safe to call from non-interactive paths.
10
- */
11
- export declare function discoverSessionBrowser(userDataDir: string): Promise<SessionBrowser | undefined>;
12
- /**
13
- * Which binary a session-browser launch should run: an explicit
14
- * executablePath (usually the managed Chrome for Testing) wins; otherwise the
15
- * system install of the requested channel (default stable). Throws when no
16
- * such browser is installed.
17
- */
18
- export declare function sessionBrowserBinary(settings: {
19
- executablePath?: string;
20
- channel?: ChromeChannel;
21
- }): string;
22
- /**
23
- * Launch the session browser detached (it deliberately outlives the aiui
24
- * process — it's the user's window too) and wait for its debug endpoint.
25
- *
26
- * `debugPort` 0 lets the OS pick a free port; Chrome reports the choice via
27
- * `DevToolsActivePort`, which is removed first so a stale file from a previous
28
- * run can't win the poll. Fails fast if the process exits early — the classic
29
- * cause being an already-running Chrome on the same profile *without* a debug
30
- * port, which swallows the new invocation as a URL-handoff and exits.
31
- */
32
- export declare function launchSessionBrowser(opts: {
33
- binary: string;
34
- userDataDir: string;
35
- debugPort?: number;
36
- extensionDir?: string;
37
- headless?: boolean;
38
- startUrl?: string;
39
- }): Promise<SessionBrowser>;
40
- /**
41
- * Open a URL as a new tab in a session browser, via the DevTools HTTP API
42
- * (`PUT /json/new` — PUT is required by current Chrome).
43
- */
44
- export declare function openInSessionBrowser(browserUrl: string, url: string): Promise<void>;