@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
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { type SessionBrowser } from "@habemus-papadum/aiui-util";
|
|
2
|
+
import type { AiuiArgs } from "../util/aiui-args";
|
|
3
|
+
import { type ChromeSettings } from "../util/chrome";
|
|
4
|
+
import { type AiuiConfig } from "../util/config";
|
|
5
|
+
type ChromeConfig = NonNullable<AiuiConfig["chrome"]>;
|
|
1
6
|
/** The default *remote* port — the one worth keeping fixed (see module doc). */
|
|
2
7
|
export declare const DEFAULT_REMOTE_PORT = 9222;
|
|
3
8
|
export interface BrowserOptions {
|
|
@@ -12,6 +17,50 @@ export interface BrowserOptions {
|
|
|
12
17
|
remotePort?: string;
|
|
13
18
|
}
|
|
14
19
|
export declare function runBrowser(opts: BrowserOptions): Promise<void>;
|
|
20
|
+
/** Options for {@link startSessionBrowser}. */
|
|
21
|
+
export interface StartSessionBrowserOptions {
|
|
22
|
+
/** CLI identity flags (profile / data dir), reconciled against config. */
|
|
23
|
+
flags?: Pick<AiuiArgs, "chromeProfile" | "chromeDataDir">;
|
|
24
|
+
/** The `chrome` section of the loaded config. */
|
|
25
|
+
config?: ChromeConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Whether prompting is allowed. Interactive launches may offer to
|
|
28
|
+
* install/update Chrome for Testing and print the extension autoload hint;
|
|
29
|
+
* non-interactive ones (CI, or a sidecar whose terminal belongs to another
|
|
30
|
+
* process — `aiui vite`'s browser open) degrade to whatever browser is
|
|
31
|
+
* already installed, silently.
|
|
32
|
+
*/
|
|
33
|
+
interactive: boolean;
|
|
34
|
+
/** Override the resolved DevTools debug port (`aiui browser --port`). */
|
|
35
|
+
debugPort?: number;
|
|
36
|
+
/** Launch headless regardless of config (`aiui browser --headless`). */
|
|
37
|
+
headless?: boolean;
|
|
38
|
+
/** Open this URL as the first tab instead of about:blank. */
|
|
39
|
+
startUrl?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Launch the session browser the way `aiui browser` does — the shared
|
|
43
|
+
* "everything before the window exists" sequence, extracted so other commands
|
|
44
|
+
* (`aiui vite`'s browser sidecar) launch identically instead of re-deriving
|
|
45
|
+
* it:
|
|
46
|
+
*
|
|
47
|
+
* 1. Resolve settings from flags + config.
|
|
48
|
+
* 2. Prefer the managed Chrome for Testing unless config names a browser
|
|
49
|
+
* explicitly (the sync may prompt to install/update — only when
|
|
50
|
+
* `interactive`; otherwise it just reports what's installed).
|
|
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).
|
|
54
|
+
* 4. Launch on the profile's user data dir and wait for the debug endpoint.
|
|
55
|
+
*
|
|
56
|
+
* Throws with a remediation-bearing message when no browser can be found or
|
|
57
|
+
* the launch fails; callers decide whether that's fatal (`aiui browser`) or
|
|
58
|
+
* merely a warning (`aiui vite`, where the dev server must keep running).
|
|
59
|
+
*/
|
|
60
|
+
export declare function startSessionBrowser(opts: StartSessionBrowserOptions): Promise<{
|
|
61
|
+
session: SessionBrowser;
|
|
62
|
+
settings: ChromeSettings;
|
|
63
|
+
}>;
|
|
15
64
|
/**
|
|
16
65
|
* `~/.cache/aiui/browser-profiles/<key>` for a tunneled session browser.
|
|
17
66
|
* Path-only (no mkdir) — the browser launch creates it on first use.
|
|
@@ -25,3 +74,4 @@ export declare function sshTunnelArgs(target: string, remotePort: number, localP
|
|
|
25
74
|
export declare function remoteAttachCommand(remotePort: number): string;
|
|
26
75
|
/** `aiui open <url>` — open a page in the running session browser. */
|
|
27
76
|
export declare function runOpen(url: string, opts: Pick<BrowserOptions, "profile" | "dataDir">): Promise<void>;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface CleanOptions {
|
|
2
|
+
/** Limit the reset to this repo's `.aiui-cache/`. */
|
|
3
|
+
projectOnly?: boolean;
|
|
4
|
+
/** Limit the reset to the user cache (`~/.cache/aiui`). */
|
|
5
|
+
userOnly?: boolean;
|
|
6
|
+
/** Keep the managed Chrome for Testing install (skip the ~160 MB re-download). */
|
|
7
|
+
keepBrowser?: boolean;
|
|
8
|
+
/** Print what would be deleted, then stop. */
|
|
9
|
+
dryRun?: boolean;
|
|
10
|
+
/** Delete without the confirmation prompt. */
|
|
11
|
+
yes?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** The three cache roots `clean` reasons about (resolved, never created). */
|
|
14
|
+
export interface CleanRoots {
|
|
15
|
+
/** `<base>/.aiui-cache`. */
|
|
16
|
+
project: string;
|
|
17
|
+
/** `~/.cache/aiui` (respects `$AIUI_CACHE` / `$XDG_CACHE_HOME`). */
|
|
18
|
+
user: string;
|
|
19
|
+
/** The managed Chrome for Testing dir — a child of {@link CleanRoots.user}. */
|
|
20
|
+
browser: string;
|
|
21
|
+
}
|
|
22
|
+
/** One thing `clean` will delete: a root path, optionally sparing some children. */
|
|
23
|
+
export interface CleanTarget {
|
|
24
|
+
/** Short human label for the plan output. */
|
|
25
|
+
label: string;
|
|
26
|
+
/** The directory to remove. */
|
|
27
|
+
path: string;
|
|
28
|
+
/**
|
|
29
|
+
* Absolute child paths to preserve instead of deleting `path` wholesale. Used
|
|
30
|
+
* by `--keep-browser` to clear the user cache while keeping `chrome/`.
|
|
31
|
+
*/
|
|
32
|
+
keep?: string[];
|
|
33
|
+
}
|
|
34
|
+
/** Resolve the cache roots for a given base dir (defaults to cwd). */
|
|
35
|
+
export declare function cleanRoots(base?: string): CleanRoots;
|
|
36
|
+
/**
|
|
37
|
+
* Decide which roots to remove from the flags. Pure over `roots`: the fs is only
|
|
38
|
+
* touched later, when the targets are resolved to concrete deletions.
|
|
39
|
+
*/
|
|
40
|
+
export declare function planCleanTargets(opts: CleanOptions, roots: CleanRoots): CleanTarget[];
|
|
41
|
+
/**
|
|
42
|
+
* The concrete absolute paths a target will delete. `[path]` for a plain target,
|
|
43
|
+
* or its children minus the kept ones for a `--keep-browser` target; `[]` when
|
|
44
|
+
* nothing there exists (so an already-clean root drops out of the plan).
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveDeletions(target: CleanTarget): string[];
|
|
47
|
+
export declare function runClean(opts?: CleanOptions): Promise<void>;
|
|
48
|
+
/** Human-readable byte count (binary units), e.g. `346.0 MB`. */
|
|
49
|
+
export declare function formatBytes(n: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runConfigTui(base?: string): Promise<void>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type AiuiConfig } from "../util/config";
|
|
2
|
+
import { type ConfigValue, type ResolvedField } from "../util/config-schema";
|
|
3
|
+
/** Which config file a write targets. */
|
|
4
|
+
export type ConfigLevel = "user" | "project";
|
|
5
|
+
/** Both config files, read once — the raw material for every subcommand. */
|
|
6
|
+
export interface ConfigLevels {
|
|
7
|
+
paths: {
|
|
8
|
+
user: string;
|
|
9
|
+
project: string;
|
|
10
|
+
};
|
|
11
|
+
user: AiuiConfig;
|
|
12
|
+
project: AiuiConfig;
|
|
13
|
+
}
|
|
14
|
+
/** One field with its per-level values and resolved provenance. */
|
|
15
|
+
export interface FieldState extends ResolvedField {
|
|
16
|
+
userValue?: ConfigValue;
|
|
17
|
+
projectValue?: ConfigValue;
|
|
18
|
+
/** The value the launcher would see (project beats user); undefined = unset. */
|
|
19
|
+
effective?: ConfigValue;
|
|
20
|
+
/** Where {@link effective} comes from; "default"/"unset" mean no file sets it. */
|
|
21
|
+
source: ConfigLevel | "default" | "unset";
|
|
22
|
+
}
|
|
23
|
+
/** Read both config levels (missing files read as empty configs). */
|
|
24
|
+
export declare function readLevels(base?: string): ConfigLevels;
|
|
25
|
+
/** Resolve every schema field against the two levels. */
|
|
26
|
+
export declare function fieldStates(levels: ConfigLevels): FieldState[];
|
|
27
|
+
export interface ShowOptions {
|
|
28
|
+
json?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare function runConfigShow(options?: ShowOptions, base?: string): void;
|
|
31
|
+
/** The value column of one `show`/TUI row: set value + source, or the default. */
|
|
32
|
+
export declare function valueCell(state: FieldState): string;
|
|
33
|
+
export declare function runConfigGet(key: string, base?: string): void;
|
|
34
|
+
export interface WriteOptions {
|
|
35
|
+
/** Target the project file (.aiui-cache/config.json) instead of the user file. */
|
|
36
|
+
project?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare function runConfigSet(key: string, raw: string, options?: WriteOptions, base?: string): void;
|
|
39
|
+
/** The shared write path for `set` and the TUI. */
|
|
40
|
+
export declare function writeValue(levels: ConfigLevels, state: ResolvedField, value: ConfigValue, level: ConfigLevel): void;
|
|
41
|
+
export declare function runConfigUnset(key: string, options?: WriteOptions, base?: string): void;
|
|
42
|
+
/** The shared unset path for `unset` and the TUI. */
|
|
43
|
+
export declare function removeValue(levels: ConfigLevels, state: ResolvedField, level: ConfigLevel): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface DebugOptions {
|
|
2
|
+
/** Target a channel by its registry tag instead of the interactive selector. */
|
|
3
|
+
mcp?: string;
|
|
4
|
+
/** Open the browser at the console (default true; `--no-open` skips). */
|
|
5
|
+
open?: boolean;
|
|
6
|
+
}
|
|
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,39 +1,65 @@
|
|
|
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
|
|
36
9
|
* as the "is Vite available?" check: if it isn't installed, we fail loudly
|
|
37
10
|
* rather than shelling out to nothing. See {@link resolvePackageCli}.
|
|
11
|
+
*
|
|
12
|
+
* Once the dev server is up, a *sidecar* opens it in the session browser (the
|
|
13
|
+
* shared window `aiui claude` attaches the agent to). We never know up front
|
|
14
|
+
* which port Vite will bind — the user runs many dev servers and Vite walks up
|
|
15
|
+
* from 5173 — so instead of guessing, Vite's stdout is teed through us and
|
|
16
|
+
* scanned for its own ready banner (see {@link parseViteLocalUrl}). stdin and
|
|
17
|
+
* stderr stay inherited: Vite still owns the terminal, its interactive
|
|
18
|
+
* shortcuts and Ctrl-C behave exactly as before. The sidecar is fire-and-forget
|
|
19
|
+
* ({@link openAppInBrowser}): whatever the browser does, the dev server runs on.
|
|
38
20
|
*/
|
|
39
21
|
export declare function runVite(rawArgs?: string[]): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Parse one line of Vite's stdout for the local dev-server URL.
|
|
24
|
+
*
|
|
25
|
+
* Vite's ready banner looks like (colored in a real terminal):
|
|
26
|
+
*
|
|
27
|
+
* ➜ Local: http://localhost:5174/
|
|
28
|
+
* ➜ Network: use --host to expose
|
|
29
|
+
*
|
|
30
|
+
* Only the `Local:` line counts, and only with a loopback host (`localhost`,
|
|
31
|
+
* `127.0.0.1`, `[::1]`) — that's the URL meaningful to open in a browser on
|
|
32
|
+
* this machine, or to port-forward in the headless hint. ANSI codes are
|
|
33
|
+
* stripped *first*: Vite colors the host and the port separately, so escape
|
|
34
|
+
* sequences sit in the middle of the URL text and no pattern would survive
|
|
35
|
+
* matching against the raw bytes. Returns undefined for anything that isn't
|
|
36
|
+
* the ready line — the same shape the retired workbench lab used, the
|
|
37
|
+
* house pattern for these one-line protocols.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseViteLocalUrl(line: string): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Tee a child's stdout to ours verbatim while watching for the dev-server URL.
|
|
42
|
+
*
|
|
43
|
+
* Chunks are forwarded untouched (colors, spinners, screen clears all pass
|
|
44
|
+
* through); scanning happens on a parallel line-buffered copy so a URL split
|
|
45
|
+
* across chunk boundaries is still seen. Once found, `onUrl` fires exactly
|
|
46
|
+
* once and the scanner disengages — from then on this is a plain passthrough.
|
|
47
|
+
* Exported for tests, which drive it with in-memory streams (no child
|
|
48
|
+
* process).
|
|
49
|
+
*/
|
|
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>;
|