@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
@@ -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;
@@ -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 {};
@@ -1,39 +1,65 @@
1
- import type { RunningServer } from "@habemus-papadum/aiui-claude-channel";
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>;