@habemus-papadum/aiui 0.2.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.
Files changed (40) hide show
  1. package/README.md +6 -1
  2. package/dist/cli.js +1481 -832
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/browser.d.ts +50 -0
  5. package/dist/commands/clean.d.ts +49 -0
  6. package/dist/commands/config-tui.d.ts +1 -0
  7. package/dist/commands/config.d.ts +43 -0
  8. package/dist/commands/debug.d.ts +7 -0
  9. package/dist/commands/env.d.ts +36 -0
  10. package/dist/commands/extension.d.ts +46 -0
  11. package/dist/commands/mcp.d.ts +10 -0
  12. package/dist/commands/native-host.d.ts +16 -0
  13. package/dist/commands/pencil-url.d.ts +18 -0
  14. package/dist/commands/vite.d.ts +54 -28
  15. package/dist/config-Cis6kCik.js +293 -0
  16. package/dist/config-Cis6kCik.js.map +1 -0
  17. package/dist/index.d.ts +6 -0
  18. package/dist/index.js +6 -4
  19. package/dist/index.js.map +1 -1
  20. package/dist/util/aiui-args.d.ts +26 -0
  21. package/dist/util/channel-launch.d.ts +67 -0
  22. package/dist/util/channel-target.d.ts +33 -0
  23. package/dist/util/chrome.d.ts +48 -27
  24. package/dist/util/config-schema.d.ts +96 -0
  25. package/dist/util/config.d.ts +31 -59
  26. package/dist/util/first-run.d.ts +11 -8
  27. package/dist/util/gemini-preflight.d.ts +56 -0
  28. package/dist/util/openai-preflight.d.ts +4 -3
  29. package/dist/util/resolve-cli.d.ts +1 -11
  30. package/package.json +12 -8
  31. package/dist/commands/demo.d.ts +0 -28
  32. package/dist/util/browser.d.ts +0 -44
  33. package/templates/demo/CLAUDE.md +0 -16
  34. package/templates/demo/README.md +0 -36
  35. package/templates/demo/gitignore +0 -4
  36. package/templates/demo/index.html +0 -11
  37. package/templates/demo/package.json +0 -21
  38. package/templates/demo/src/main.ts +0 -51
  39. package/templates/demo/tsconfig.json +0 -11
  40. package/templates/demo/vite.config.ts +0 -17
@@ -19,10 +19,14 @@ type ChromeFlags = Pick<AiuiArgs, "chrome" | "noChrome" | "chromeProfile" | "chr
19
19
  * npx download + Chrome launch), with `--aiui-no-chrome`, or with
20
20
  * `chrome.enabled: false` in config. `--aiui-chrome` forces it on even under
21
21
  * CI; `chrome.enabled: true` merely restates the default and does not.
22
+ *
23
+ * Deliberately gated on CI alone, not the wider `isHeadless` check from
24
+ * aiui-util: on a headless-but-interactive box (SSH into a dev machine)
25
+ * the MCP still works — it just launches/attaches a headless-capable Chrome —
26
+ * whereas *opening a page for the user* would be pointless. Only commands that
27
+ * put a window in front of someone consult the broader signals.
22
28
  */
23
29
  export declare function chromeDevtoolsEnabled(args: Pick<ChromeFlags, "chrome" | "noChrome">, config?: ChromeConfig, env?: NodeJS.ProcessEnv): boolean;
24
- /** Truthy `CI` env var, with the conventional "false"/"0" escape hatches. */
25
- export declare function isCi(env?: NodeJS.ProcessEnv): boolean;
26
30
  /** The launch-relevant Chrome settings after flags and config are reconciled. */
27
31
  export interface ChromeSettings {
28
32
  /** Absolute user data dir for this launch. */
@@ -42,7 +46,6 @@ export interface ChromeSettings {
42
46
  /** Installed Chrome release channel to launch, if configured. */
43
47
  channel?: ChromeChannel;
44
48
  headless: boolean;
45
- buildExtension: boolean;
46
49
  }
47
50
  /**
48
51
  * Reconcile CLI flags with config into the settings for this launch.
@@ -65,43 +68,61 @@ export declare function chromeUserDataDir(ids: {
65
68
  dataDir?: string;
66
69
  profile?: string;
67
70
  }, base?: string): string;
71
+ /** The intent client's MV3 bundle directory name (see its build-ext.ts: a
72
+ * THIRD shape of that package — dist/ is the library, dist-ext/ the unpacked
73
+ * extension). */
74
+ export declare const INTENT_CLIENT_OUT_DIR = "dist-ext";
68
75
  /**
69
- * The built aiui-devtools-extension directory, if available.
76
+ * What we found when looking for the intent client's extension the one
77
+ * launches AUTO-LOAD.
70
78
  *
71
- * The package publishes `extension/` prebuilt, so this resolves both in a dev
72
- * workspace (where `extension/js` appears once built see
73
- * {@link buildDevtoolsExtension}) and installed from npm. Without `js/` the
74
- * extension is an empty shell, so an unbuilt dev checkout returns undefined.
79
+ * Deliberately simple: the bundle is a static build with no dev server and no
80
+ * dev/prod split the client's hot-iteration surface is the channel-served
81
+ * plain page, so the extension only ever needs to be BUILT.
75
82
  */
76
- export declare function devtoolsExtensionDir(): string | undefined;
77
- /**
78
- * Rebuild the aiui-devtools-extension package so the auto-loaded panel is never stale.
79
- *
80
- * A full tsc of the extension (plus the debug-ui esbuild bundle) is well
81
- * under a second — cheap enough to run on every launch rather than tracking
82
- * staleness. Best-effort by design: outside a dev
83
- * checkout (no devtools package, no typescript) it silently does nothing, and
84
- * a failing compile warns loudly but never blocks the launch — whatever
85
- * `extension/js` already holds is what gets loaded.
86
- */
87
- export declare function buildDevtoolsExtension(): Promise<void>;
83
+ export type IntentClientExtension = {
84
+ state: "absent";
85
+ } | {
86
+ state: "unbuilt";
87
+ root: string;
88
+ } | {
89
+ state: "ready";
90
+ dir: string;
91
+ };
92
+ /** Absolute paths for the intent client's bundle, in a checkout. */
93
+ export declare function intentClientExtensionPaths(): {
94
+ root: string;
95
+ outDir: string;
96
+ } | undefined;
97
+ /** {@link findIntentClientExtension}'s decision, against explicit paths. */
98
+ export declare function resolveIntentClientExtension(paths: {
99
+ root: string;
100
+ outDir: string;
101
+ } | undefined): IntentClientExtension;
102
+ /** The intent client extension, as this checkout can load it. No build-on-
103
+ * launch (the same rule as the frozen extension's ladder): the bundle is a
104
+ * deliberate act — `pnpm -C packages/aiui-intent-client build:ext`. */
105
+ export declare function findIntentClientExtension(): IntentClientExtension;
106
+ /** One launch-time note when the client is resolvable but unbuilt — printed
107
+ * every launch while true (actionable; it disappears once fixed). */
108
+ export declare function warnIntentClientState(intent: IntentClientExtension): void;
88
109
  /**
89
- * One-time tip when the extension exists but the chosen browser won't
90
- * auto-load it (no `executablePath` means a branded Chrome — installed
110
+ * One-time tip when extensions exist but the chosen browser won't
111
+ * auto-load them (no `executablePath` means a branded Chrome — installed
91
112
  * stable or a `channel` build — and branded builds ≥ 137 ignore
92
113
  * `--load-extension`). Printed once per profile: the marker file lives in the
93
114
  * user data dir, so it survives exactly as long as the profile whose manual
94
115
  * install it recommends.
95
116
  */
96
- export declare function maybeExtensionAutoloadHint(settings: ChromeSettings, extensionDir: string | undefined): void;
117
+ export declare function maybeExtensionAutoloadHint(settings: ChromeSettings, extensionDirs: string[]): void;
97
118
  /**
98
119
  * The `mcpServers` entry that launches chrome-devtools-mcp.
99
120
  *
100
121
  * Uses the documented `npx -y chrome-devtools-mcp@latest` invocation with the
101
122
  * user data dir pinned to ours. Puppeteer's default launch args include
102
- * `--disable-extensions`, which would neuter both the auto-loaded panel and
103
- * anything installed manually into the profile — so it is always stripped.
104
- * When an extension dir is given, additionally ask Chrome to load it.
123
+ * `--disable-extensions`, which would neuter both the auto-loaded extensions
124
+ * and anything installed manually into the profile — so it is always stripped.
125
+ * When extension dirs are given, additionally ask Chrome to load them.
105
126
  */
106
127
  /**
107
128
  * The `mcpServers` entry that *attaches* chrome-devtools-mcp to an existing
@@ -113,7 +134,7 @@ export declare function chromeMcpAttachServer(browserUrl: string): {
113
134
  command: string;
114
135
  args: string[];
115
136
  };
116
- export declare function chromeMcpServer(settings: ChromeSettings, extensionDir?: string): {
137
+ export declare function chromeMcpServer(settings: ChromeSettings, extensionDirs?: string[]): {
117
138
  command: string;
118
139
  args: string[];
119
140
  };
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The declarative schema for aiui's `config.json` — one table that drives
3
+ * everything config-shaped:
4
+ *
5
+ * - validation (util/config.ts walks these sections instead of hand-rolled
6
+ * per-key checks),
7
+ * - the `aiui config` commands (show/get/set/unset use it to resolve keys,
8
+ * parse CLI values, and report defaults),
9
+ * - the `aiui config tui` browser (docs, defaults, and enum choices all
10
+ * render from here).
11
+ *
12
+ * Because docs, defaults, and validation come from the same rows, they cannot
13
+ * drift apart. `docs/guide/config.md` remains the long-form narrative; the
14
+ * `doc` strings here are the terminal-sized versions.
15
+ *
16
+ * **How a component participates.** `CONFIG_SECTIONS` is the registry: a
17
+ * section is plain data, so a future component that grows file-backed settings
18
+ * (say, an `intent` section for the pipeline) joins by contributing one
19
+ * `ConfigSectionSchema` object here and a matching optional section on
20
+ * `AiuiConfig`. Nothing else — validation, show/get/set, and the TUI pick it
21
+ * up from the table. (The intent pipeline's current config is deliberately
22
+ * *not* here: it is per-app, passed as `aiuiDevOverlay({ intent: { … } })` in
23
+ * the app's Vite config — see docs/guide/intent-overlay.md.)
24
+ */
25
+ export { CHROME_CHANNELS, type ChromeChannel } from "@habemus-papadum/aiui-util";
26
+ export declare const FOR_TESTING_MODES: readonly ["prompt", "auto", "off"];
27
+ export type ForTestingMode = (typeof FOR_TESTING_MODES)[number];
28
+ export declare const CHROME_MODES: readonly ["attach", "launch"];
29
+ export type ChromeMode = (typeof CHROME_MODES)[number];
30
+ export declare const CHANNEL_BINDS: readonly ["loopback", "host"];
31
+ export type ChannelBind = (typeof CHANNEL_BINDS)[number];
32
+ /** Every config leaf is a JSON scalar; sections never nest further. */
33
+ export type ConfigValue = boolean | number | string;
34
+ export interface ConfigFieldSchema {
35
+ /** Leaf key within its section, e.g. `"skipPermissions"`. */
36
+ key: string;
37
+ /** `"enum"` is a string constrained to {@link values}. */
38
+ type: "boolean" | "number" | "string" | "enum";
39
+ /** The allowed values when {@link type} is `"enum"`. */
40
+ values?: readonly string[];
41
+ /** The built-in default, when the fallback is a plain value. */
42
+ default?: ConfigValue;
43
+ /**
44
+ * Human phrasing of the default when a bare value would mislead (dynamic
45
+ * fallbacks, first-run prompts). Shown instead of {@link default}.
46
+ */
47
+ defaultText?: string;
48
+ /** One-line summary — the TUI's list row. */
49
+ summary: string;
50
+ /** The rest of the documentation (terminal-sized; optional). */
51
+ doc?: string;
52
+ /**
53
+ * Constraint beyond type/enum. Returns the "expected …" tail of the error
54
+ * message, or undefined when the value is fine.
55
+ */
56
+ validate?: (value: ConfigValue) => string | undefined;
57
+ }
58
+ export interface ConfigSectionSchema {
59
+ /** Top-level key in config.json, e.g. `"chrome"`. */
60
+ name: string;
61
+ /** One-line summary of what the section configures. */
62
+ summary: string;
63
+ fields: ConfigFieldSchema[];
64
+ }
65
+ export declare const CONFIG_SECTIONS: ConfigSectionSchema[];
66
+ /** A field paired with its section — what key-resolution hands back. */
67
+ export interface ResolvedField {
68
+ section: ConfigSectionSchema;
69
+ field: ConfigFieldSchema;
70
+ /** The dotted path, e.g. `"chrome.mode"`. */
71
+ path: string;
72
+ }
73
+ /** Every field in schema order, with dotted paths. */
74
+ export declare function allConfigFields(): ResolvedField[];
75
+ /** Resolve a dotted path like `"chrome.mode"`; undefined when unknown. */
76
+ export declare function findConfigField(path: string): ResolvedField | undefined;
77
+ /** The `typeof` a field's values (enums are strings). */
78
+ export declare function fieldRuntimeType(field: ConfigFieldSchema): "boolean" | "number" | "string";
79
+ /**
80
+ * Constraint check beyond the runtime type: enum membership, then the field's
81
+ * own `validate`. Returns the "expected …" tail for the error, or undefined.
82
+ */
83
+ export declare function invalidReason(field: ConfigFieldSchema, value: ConfigValue): string | undefined;
84
+ /**
85
+ * Parse a CLI-provided string into the field's type and validate it — how
86
+ * `aiui config set` and the TUI turn text into a config value.
87
+ */
88
+ export declare function parseFieldValue(field: ConfigFieldSchema, raw: string): {
89
+ value: ConfigValue;
90
+ } | {
91
+ error: string;
92
+ };
93
+ /** Render a value the way config.json would hold it (strings quoted). */
94
+ export declare function formatConfigValue(value: ConfigValue): string;
95
+ /** The default, phrased for humans: `defaultText` wins, then the value, then "unset". */
96
+ export declare function describeDefault(field: ConfigFieldSchema): string;
@@ -1,83 +1,49 @@
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
+ };
25
20
  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
- */
21
+ /** Attach the Chrome DevTools MCP (default: true). */
31
22
  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
- */
23
+ /** How the MCP reaches a browser: shared session browser, or its own. */
39
24
  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
- */
25
+ /** Attach to this DevTools endpoint instead of managing a browser at all. */
48
26
  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
- */
27
+ /** Fixed DevTools debug port for session browsers aiui launches (0 = OS-assigned). */
54
28
  debugPort?: number;
55
29
  /** Named profile under `.aiui-cache/chrome/` (default: "default"). */
56
30
  profile?: string;
57
31
  /** Explicit Chrome user data dir; takes precedence over `profile`. */
58
32
  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
- */
33
+ /** Chrome binary to launch. Mutually exclusive with `channel`. */
63
34
  executablePath?: string;
64
- /** Installed Chrome release channel to launch (default: stable). */
35
+ /** Installed Chrome release channel to launch. */
65
36
  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
- */
37
+ /** How `aiui claude` manages the Chrome for Testing install. */
73
38
  forTesting?: ForTestingMode;
74
39
  /** Launch Chrome headless (default: false). */
75
40
  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
- */
41
+ /** OBSOLETE (the devtools extension is deleted): parsed and ignored so old
42
+ * configs stay valid. */
80
43
  buildExtension?: boolean;
44
+ /** OBSOLETE (page-side getDisplayMedia capture is gone): parsed and
45
+ * ignored so old configs stay valid. */
46
+ autoCapture?: boolean;
81
47
  };
82
48
  }
83
49
  /** The `config.json` paths consulted, user-level first (base: the project dir). */
@@ -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";
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Gemini key preflight for `aiui claude` — the GEMINI_API_KEY twin of
3
+ * {@link ./openai-preflight}.
4
+ *
5
+ * The realtime submode's reference engine is Gemini Live, and it runs in the
6
+ * *channel* process, which inherits the environment `aiui claude` launches in.
7
+ * Same key story as OpenAI: **`GEMINI_API_KEY` in the environment**, never
8
+ * config, never a flag. And the same failure this catches: a missing or stale
9
+ * key that would otherwise surface as an opaque closed WebSocket deep in a
10
+ * live session ("gemini live session closed") rather than a clear message up
11
+ * front. Degradation, not refusal — a bad key never blocks the launch; the
12
+ * realtime tier is simply unavailable until it's fixed.
13
+ *
14
+ * We record only a status — never the key or any prefix of it — so the
15
+ * launch-info summary can explain a degraded pipeline without seeing the
16
+ * secret.
17
+ */
18
+ import type { OpenAiKeyStatus } from "@habemus-papadum/aiui-claude-channel";
19
+ export interface GeminiPreflightOptions {
20
+ /**
21
+ * Perform the authenticated network check. True only for interactive,
22
+ * non-CI launches. When false the check is skipped silently and a present
23
+ * key is reported as "unverified", never contacted.
24
+ */
25
+ verify?: boolean;
26
+ /** Injectable for tests; defaults to the process environment. */
27
+ env?: NodeJS.ProcessEnv;
28
+ /** Injectable for tests; defaults to global `fetch`. */
29
+ fetchImpl?: typeof fetch;
30
+ /** Network budget for the status check (default {@link DEFAULT_TIMEOUT_MS}). */
31
+ timeoutMs?: number;
32
+ }
33
+ /**
34
+ * Determine the status of `GEMINI_API_KEY` for this launch. Same contract as
35
+ * `preflightOpenAiKey`: never throws, never prints, never returns the key.
36
+ * The key rides the query string (Gemini's auth shape — no bearer header) and
37
+ * a rejected key answers 400/401/403 depending on how it's malformed, so all
38
+ * three read as "invalid".
39
+ */
40
+ export declare function preflightGeminiKey(opts?: GeminiPreflightOptions): Promise<OpenAiKeyStatus>;
41
+ interface PreflightMessage {
42
+ level: "warn" | "note";
43
+ title: string;
44
+ detail: string;
45
+ }
46
+ /**
47
+ * The user-facing message for a preflight status, or `null` when there's
48
+ * nothing to say. Unlike the OpenAI twin, a **missing** Gemini key is a quiet
49
+ * `note`, not a warning: the default transcription tiers don't need it — only
50
+ * the realtime (Gemini Live) submode does — so its absence degrades one
51
+ * opt-in tier, not the pipeline's default path.
52
+ */
53
+ export declare function geminiPreflightMessage(status: OpenAiKeyStatus): PreflightMessage | null;
54
+ /** Print the preflight message for `status` (nothing, for a valid key). */
55
+ export declare function reportGeminiPreflight(status: OpenAiKeyStatus): void;
56
+ export {};
@@ -11,9 +11,10 @@
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
16
- * bit the bench twice (see workbench field-notes, "Keys & config"): a **stale
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
17
+ * bit the bench twice (archive/workbench/field-notes.md, "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.
19
20
  *
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habemus-papadum/aiui",
3
- "version": "0.2.0",
3
+ "version": "0.5.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",
@@ -24,22 +25,25 @@
24
25
  "aiui": "./dist/cli.js"
25
26
  },
26
27
  "files": [
27
- "dist",
28
- "templates"
28
+ "dist"
29
29
  ],
30
30
  "publishConfig": {
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
+ "@inquirer/prompts": "^7.2.0",
34
35
  "@puppeteer/browsers": "^2.10.5",
35
36
  "chalk": "^5.3.0",
36
37
  "commander": "^15.0.0",
37
38
  "execa": "^9.6.1",
38
39
  "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"
40
+ "@habemus-papadum/aiui-claude-channel": "^0.5.0",
41
+ "@habemus-papadum/aiui-trace-ui": "^0.5.0",
42
+ "@habemus-papadum/aiui-claude-plugin": "^0.5.0",
43
+ "@habemus-papadum/aiui-util": "^0.5.0"
44
+ },
45
+ "devDependencies": {
46
+ "@habemus-papadum/aiui-lowering-pipeline": "^0.5.0"
43
47
  },
44
48
  "scripts": {
45
49
  "build": "tsc --emitDeclarationOnly -p tsconfig.json && vite build",
@@ -1,28 +0,0 @@
1
- export interface DemoOptions {
2
- /** Scaffold only — skip `npm install` (used by the packaging test/CI). */
3
- skipInstall?: boolean;
4
- }
5
- /** What `aiui demo` finds at the target path. */
6
- export type DemoTargetState = "new" | "existing-demo" | "occupied";
7
- export declare function runDemo(dir: string | undefined, opts?: DemoOptions): Promise<void>;
8
- /**
9
- * Decide what to do with the target: `new` (missing or empty), an
10
- * `existing-demo` (package.json carries the scaffold marker — continue), or
11
- * `occupied` (anything else — refuse; never clobber unknown content).
12
- */
13
- export declare function classifyDemoTarget(target: string): DemoTargetState;
14
- /**
15
- * The dependency range the scaffold pins aiui packages to: this build's exact
16
- * release line when it has one, `latest` from a dev build (whose `0.0.0+dev`
17
- * doesn't exist on the registry).
18
- */
19
- export declare function demoDependencyRange(version: string): string;
20
- /** Copy the template, restore `.gitignore`, and pin dependency ranges. */
21
- export declare function scaffoldDemo(template: string, target: string): void;
22
- /**
23
- * The template directory shipped with this install. Probed upward from this
24
- * module because the relative depth differs between layouts: `dist/cli.js`
25
- * (bundled, installed) sits one level below the package root; the tsx-run
26
- * `src/commands/demo.ts` sits two below.
27
- */
28
- export declare function templateRoot(): string | undefined;
@@ -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>;
@@ -1,16 +0,0 @@
1
- # aiui demo playground
2
-
3
- This directory is a scaffolded, disposable aiui demo — a sandbox the user is exploring the aiui
4
- workflow in. Ground rules for working here:
5
-
6
- - **The app is scenery.** `src/main.ts` renders a fake "spectra" viewer purely so there's
7
- something to point at and modify. Redesign it, extend it, replace it — that's the point of the
8
- demo. Prefer small, visible changes the user can watch land.
9
- - **Don't remove the integration.** The `aiuiDevOverlay()` plugin in `vite.config.ts` is what
10
- mounts the intent tool and connects it to this session's channel. The demo stops working
11
- without it.
12
- - The dev server runs via `npm run dev` (which is `aiui vite dev` — it injects the channel port
13
- as `VITE_AIUI_PORT`). Plain `vite` also serves the app, but the intent tool won't find the
14
- channel.
15
- - This is a standalone git repo scaffolded by `aiui demo`; commit freely — history here belongs
16
- to the user's sandbox and goes nowhere else.
@@ -1,36 +0,0 @@
1
- # aiui demo playground
2
-
3
- A disposable sandbox for trying [aiui](https://habemus-papadum.github.io/pdum_aiui/): a Claude
4
- Code session with a custom channel, a shared agent+human browser, and a web intent tool floating
5
- over a demo app. It's a local git repo of its own — let the agent redesign, break, and rebuild
6
- the app; nothing flows back anywhere.
7
-
8
- > ⚠️ First read *Read before running* in the aiui docs: `aiui claude` can skip permissions and
9
- > gives the agent a browser. This sandbox assumes you've decided to trust it.
10
-
11
- ## Run it
12
-
13
- ```sh
14
- npm run claude # terminal 1 — Claude Code with the aiui channel + session browser
15
- npm run dev # terminal 2 — the demo app (Vite + the intent tool overlay)
16
- ```
17
-
18
- Then open the app **in the session browser** (the window you share with the agent):
19
-
20
- ```sh
21
- npx aiui open http://localhost:5173
22
- ```
23
-
24
- Click the floating **✳ aiui** button, type an intent — *"make the baseline curve red"* — and
25
- watch it land in the Claude session as a prompt. The 🔍 button shows how your input was lowered
26
- into that prompt.
27
-
28
- ## What's what
29
-
30
- - `vite.config.ts` — the **entire** aiui integration: one `aiuiDevOverlay()` plugin. This is the
31
- part you'd copy into your own app.
32
- - `src/main.ts` — throwaway scenery (a fake spectrum viewer). No aiui code in it.
33
- - Re-running the scaffold command in this directory just picks up where you left off — it never
34
- overwrites your (or the agent's) changes.
35
-
36
- Docs: <https://habemus-papadum.github.io/pdum_aiui/guide/getting-started>
@@ -1,4 +0,0 @@
1
- node_modules/
2
- dist/
3
- .aiui-cache/
4
- *.log
@@ -1,11 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>spectra — aiui demo playground</title>
7
- </head>
8
- <body>
9
- <script type="module" src="/src/main.ts"></script>
10
- </body>
11
- </html>