@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.
- package/README.md +6 -1
- package/dist/cli.js +1481 -832
- package/dist/cli.js.map +1 -1
- package/dist/commands/browser.d.ts +50 -0
- package/dist/commands/clean.d.ts +49 -0
- package/dist/commands/config-tui.d.ts +1 -0
- package/dist/commands/config.d.ts +43 -0
- package/dist/commands/debug.d.ts +7 -0
- 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 +54 -28
- package/dist/config-Cis6kCik.js +293 -0
- package/dist/config-Cis6kCik.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/util/aiui-args.d.ts +26 -0
- package/dist/util/channel-launch.d.ts +67 -0
- package/dist/util/channel-target.d.ts +33 -0
- package/dist/util/chrome.d.ts +48 -27
- package/dist/util/config-schema.d.ts +96 -0
- package/dist/util/config.d.ts +31 -59
- package/dist/util/first-run.d.ts +11 -8
- package/dist/util/gemini-preflight.d.ts +56 -0
- package/dist/util/openai-preflight.d.ts +4 -3
- package/dist/util/resolve-cli.d.ts +1 -11
- package/package.json +12 -8
- package/dist/commands/demo.d.ts +0 -28
- package/dist/util/browser.d.ts +0 -44
- 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 -21
- package/templates/demo/src/main.ts +0 -51
- package/templates/demo/tsconfig.json +0 -11
- package/templates/demo/vite.config.ts +0 -17
package/dist/util/chrome.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
76
|
+
* What we found when looking for the intent client's extension — the one
|
|
77
|
+
* launches AUTO-LOAD.
|
|
70
78
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
90
|
-
* auto-load
|
|
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,
|
|
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
|
|
103
|
-
* anything installed manually into the profile — so it is always stripped.
|
|
104
|
-
* When
|
|
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,
|
|
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;
|
package/dist/util/config.d.ts
CHANGED
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
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
|
-
*
|
|
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;
|
package/dist/util/first-run.d.ts
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* First-run choices: settings that deserve a deliberate answer, not a silent
|
|
3
3
|
* default.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* consequences: whether to launch with `--dangerously-skip-permissions`,
|
|
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
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* the
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
|
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-
|
|
40
|
-
"@habemus-papadum/aiui-
|
|
41
|
-
"@habemus-papadum/aiui-claude-
|
|
42
|
-
"@habemus-papadum/aiui-
|
|
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",
|
package/dist/commands/demo.d.ts
DELETED
|
@@ -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;
|
package/dist/util/browser.d.ts
DELETED
|
@@ -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>;
|
package/templates/demo/CLAUDE.md
DELETED
|
@@ -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.
|
package/templates/demo/README.md
DELETED
|
@@ -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>
|
package/templates/demo/gitignore
DELETED
|
@@ -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>
|