@alexkroman1/aai-cli 5.1.1 → 5.2.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 (99) hide show
  1. package/dist/_agent.d.ts +39 -0
  2. package/dist/_api-client.d.ts +37 -0
  3. package/dist/_bundler.d.ts +46 -0
  4. package/dist/_config.d.ts +57 -0
  5. package/dist/_default-html.d.ts +12 -0
  6. package/dist/_deploy.d.ts +28 -0
  7. package/dist/_dev-server.d.ts +74 -0
  8. package/dist/{_init-B-LEVTHx.mjs → _init-DU-sXH6S.mjs} +44 -65
  9. package/dist/_init.d.ts +7 -0
  10. package/dist/_mock-api.d.ts +22 -0
  11. package/dist/_mock-registry.d.ts +17 -0
  12. package/dist/_output.d.ts +50 -0
  13. package/dist/_server-common.d.ts +17 -0
  14. package/dist/_slug-api.d.ts +15 -0
  15. package/dist/_templates.d.ts +21 -0
  16. package/dist/_typecheck-gate.d.ts +7 -0
  17. package/dist/_ui.d.ts +22 -0
  18. package/dist/_utils.d.ts +48 -0
  19. package/dist/_vite-env.d.ts +8 -0
  20. package/dist/build.d.ts +16 -0
  21. package/dist/cli.d.ts +1 -0
  22. package/dist/cli.mjs +1 -1
  23. package/dist/client-bundler.d.ts +21 -0
  24. package/dist/delete.d.ts +18 -0
  25. package/dist/deploy.d.ts +15 -0
  26. package/dist/dev.d.ts +13 -0
  27. package/dist/{init-tc3Rbgrf.mjs → init-BjeK8crW.mjs} +1 -1
  28. package/dist/init.d.ts +24 -0
  29. package/dist/scaffold/.env.example +11 -0
  30. package/dist/scaffold/CLAUDE.md +919 -0
  31. package/dist/scaffold/global.d.ts +1 -0
  32. package/dist/scaffold/package.json +32 -0
  33. package/dist/scaffold/pnpm-workspace.yaml +13 -0
  34. package/dist/scaffold/tsconfig.json +19 -0
  35. package/dist/scaffold/vite.config.ts +14 -0
  36. package/dist/scaffold/vitest.config.ts +24 -0
  37. package/dist/secret.d.ts +25 -0
  38. package/dist/storage.d.ts +22 -0
  39. package/dist/templates/code-interpreter/agent.ts +11 -0
  40. package/dist/templates/code-interpreter/system-prompt.md +18 -0
  41. package/dist/templates/dispatch-center/agent.test.ts +153 -0
  42. package/dist/templates/dispatch-center/agent.ts +50 -0
  43. package/dist/templates/dispatch-center/client.tsx +378 -0
  44. package/dist/templates/dispatch-center/shared.ts +631 -0
  45. package/dist/templates/dispatch-center/system-prompt.md +39 -0
  46. package/dist/templates/dispatch-center/tools/incident_add_note.ts +27 -0
  47. package/dist/templates/dispatch-center/tools/incident_create.ts +79 -0
  48. package/dist/templates/dispatch-center/tools/incident_escalate.ts +88 -0
  49. package/dist/templates/dispatch-center/tools/incident_get.ts +36 -0
  50. package/dist/templates/dispatch-center/tools/incident_triage.ts +78 -0
  51. package/dist/templates/dispatch-center/tools/incident_update_status.ts +68 -0
  52. package/dist/templates/dispatch-center/tools/ops_dashboard.ts +52 -0
  53. package/dist/templates/dispatch-center/tools/ops_protocols.ts +27 -0
  54. package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +149 -0
  55. package/dist/templates/dispatch-center/tools/resources_dispatch.ts +97 -0
  56. package/dist/templates/dispatch-center/tools/resources_get_available.ts +36 -0
  57. package/dist/templates/dispatch-center/tools/resources_update_status.ts +62 -0
  58. package/dist/templates/embedded-assets/agent.ts +55 -0
  59. package/dist/templates/embedded-assets/knowledge.json +20 -0
  60. package/dist/templates/health-assistant/agent.ts +174 -0
  61. package/dist/templates/health-assistant/system-prompt.md +17 -0
  62. package/dist/templates/infocom-adventure/agent.ts +119 -0
  63. package/dist/templates/infocom-adventure/client.tsx +279 -0
  64. package/dist/templates/infocom-adventure/shared.ts +38 -0
  65. package/dist/templates/infocom-adventure/system-prompt.md +43 -0
  66. package/dist/templates/math-buddy/agent.ts +16 -0
  67. package/dist/templates/math-buddy/system-prompt.md +12 -0
  68. package/dist/templates/night-owl/agent.ts +76 -0
  69. package/dist/templates/night-owl/client.tsx +130 -0
  70. package/dist/templates/night-owl/shared.ts +5 -0
  71. package/dist/templates/personal-finance/agent.ts +11 -0
  72. package/dist/templates/personal-finance/system-prompt.md +17 -0
  73. package/dist/templates/pipeline-simple/agent.test.ts +32 -0
  74. package/dist/templates/pipeline-simple/agent.ts +13 -0
  75. package/dist/templates/pizza-ordering/agent.test.ts +235 -0
  76. package/dist/templates/pizza-ordering/agent.ts +174 -0
  77. package/dist/templates/pizza-ordering/client.tsx +120 -0
  78. package/dist/templates/pizza-ordering/shared.ts +142 -0
  79. package/dist/templates/pizza-ordering/system-prompt.md +17 -0
  80. package/dist/templates/simple/agent.ts +5 -0
  81. package/dist/templates/solo-rpg/agent.test.ts +477 -0
  82. package/dist/templates/solo-rpg/agent.ts +37 -0
  83. package/dist/templates/solo-rpg/client.tsx +809 -0
  84. package/dist/templates/solo-rpg/shared.ts +747 -0
  85. package/dist/templates/solo-rpg/system-prompt.md +115 -0
  86. package/dist/templates/solo-rpg/tools/action_roll.ts +98 -0
  87. package/dist/templates/solo-rpg/tools/burn_momentum.ts +69 -0
  88. package/dist/templates/solo-rpg/tools/check_state.ts +11 -0
  89. package/dist/templates/solo-rpg/tools/load_game.ts +25 -0
  90. package/dist/templates/solo-rpg/tools/oracle.ts +248 -0
  91. package/dist/templates/solo-rpg/tools/save_game.ts +20 -0
  92. package/dist/templates/solo-rpg/tools/setup_character.ts +208 -0
  93. package/dist/templates/solo-rpg/tools/update_state.ts +170 -0
  94. package/dist/templates/web-researcher/agent.ts +11 -0
  95. package/dist/test.d.ts +39 -0
  96. package/dist/tsdown.config.d.ts +2 -0
  97. package/dist/typecheck.d.ts +26 -0
  98. package/dist/worker-bundler.d.ts +29 -0
  99. package/package.json +9 -6
@@ -0,0 +1,39 @@
1
+ export declare const DEFAULT_SERVER = "https://alexkroman--aai-server-web-server.modal.run";
2
+ export declare const DEFAULT_DEV_SERVER = "http://localhost:8080";
3
+ export declare function getMonorepoRoot(): string | null;
4
+ export declare function isDevMode(): boolean;
5
+ /**
6
+ * Resolve which platform server to talk to.
7
+ *
8
+ * Precedence: an explicit `--server` flag, then dev mode, then the project
9
+ * config, then the shipped default.
10
+ *
11
+ * `configUrl` comes from `.aai/project.json` — a file in the working tree, so
12
+ * a cloned repo controls it. Because callers pair this URL with the user's API
13
+ * key (and, for `aai secret`, with secret values), a config-supplied origin is
14
+ * only honored when it is implicitly trusted or previously approved by the
15
+ * user via `--server`. Otherwise a repo could redirect a credentialed request
16
+ * to a host of its choosing simply by shipping a `project.json`, and
17
+ * `aai deploy` would hand over the developer's key on first run.
18
+ *
19
+ * @param approvedOrigins - Origins from the user-owned global config.
20
+ */
21
+ export declare function resolveServerUrl(explicit?: string, configUrl?: string, approvedOrigins?: readonly string[]): string;
22
+ /**
23
+ * Resolve everything needed to talk to the platform: project config (null if
24
+ * the project has never been deployed), server URL, and API key.
25
+ */
26
+ export declare function resolveDeployTarget(cwd: string, explicitServer?: string): Promise<{
27
+ config: {
28
+ slug: string;
29
+ serverUrl: string;
30
+ } | null;
31
+ serverUrl: string;
32
+ apiKey: string;
33
+ }>;
34
+ /** Like resolveDeployTarget, but requires an existing deployment (project config). */
35
+ export declare function getServerInfo(cwd: string, explicitServer?: string): Promise<{
36
+ serverUrl: string;
37
+ slug: string;
38
+ apiKey: string;
39
+ }>;
@@ -0,0 +1,37 @@
1
+ export declare const HINT_INVALID_API_KEY = "Your API key may be invalid. Run `aai` to re-enter your AssemblyAI API key.";
2
+ /** 404 hint for requests scoped to a deployed agent's slug. */
3
+ export declare const HINT_NOT_DEPLOYED = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
4
+ export type ApiRequestOptions = {
5
+ apiKey: string;
6
+ /** Verb used in error messages, e.g. "deploy". */
7
+ action: string;
8
+ method?: "GET" | "POST" | "PUT" | "DELETE";
9
+ /**
10
+ * Request body. Plain objects are JSON-serialized by ofetch (with
11
+ * Content-Type set); binary bodies (e.g. a pre-gzipped Buffer) pass
12
+ * through untouched — set Content-Type/Content-Encoding via `headers`.
13
+ */
14
+ body?: unknown;
15
+ /** Extra request headers, merged with the built-in Authorization header. */
16
+ headers?: Record<string, string>;
17
+ /** Extra error hints keyed by HTTP status. The 401 hint is built in. */
18
+ hints?: Record<number, string>;
19
+ /**
20
+ * Transient-failure retry count (default 2). Pass 0 for requests that are
21
+ * not idempotent server-side — a retry of a request that succeeded but lost
22
+ * its response would perform the action twice (e.g. a first deploy with no
23
+ * slug creates a fresh agent per attempt).
24
+ */
25
+ retry?: number;
26
+ /** Delay between retries in ms (default 300). Tests pass 0 so retry-path
27
+ * assertions don't sleep real wall-clock time. */
28
+ retryDelay?: number;
29
+ /** Optional fetch implementation for testing. Defaults to globalThis.fetch. */
30
+ fetch?: typeof globalThis.fetch;
31
+ };
32
+ /**
33
+ * Send an authenticated request to the platform API and return the parsed
34
+ * JSON response. Throws a descriptive error with status-specific hints on
35
+ * failure (the 401 hint is always included; pass more via `hints`).
36
+ */
37
+ export declare function apiRequest<T = unknown>(url: string, opts: ApiRequestOptions): Promise<T>;
@@ -0,0 +1,46 @@
1
+ import type { AgentDef } from "@alexkroman1/aai";
2
+ import { type BuildWorkerOptions } from "./worker-bundler.ts";
3
+ /** Output from the bundler: worker ESM + client files. */
4
+ export type DirectoryBundleOutput = {
5
+ /** ESM bundle of agent.ts (tool execute functions + hook handlers). */
6
+ worker: string;
7
+ /** Static client files from Vite build. Empty if no client.tsx. */
8
+ clientFiles: Record<string, string>;
9
+ };
10
+ /**
11
+ * Bundle an agent directory: build agent.ts into worker ESM + client files.
12
+ *
13
+ * agent.ts is the single entry point: `export default agent({...})`. The
14
+ * worker self-describes (it exports `__aaiConfig` — see `worker-bundler.ts`),
15
+ * so nothing here evaluates the bundle: the server extracts the config inside
16
+ * a guest sandbox at deploy time.
17
+ */
18
+ export declare function buildAgentBundle(cwd: string, opts?: BuildWorkerOptions): Promise<DirectoryBundleOutput>;
19
+ /**
20
+ * Import the worker ESM from a uniquely named temp file and return the
21
+ * AgentDef default export. A real `file:` URL, not a `data:` URL: deploy
22
+ * bundles ship the SDK runtime, whose CJS interop calls
23
+ * `createRequire(import.meta.url)` — which rejects anything that isn't a
24
+ * file URL or absolute path. (The guest harness imports bundles the same
25
+ * way, for the same reason.) The file is removed after import; the module
26
+ * lives on in memory.
27
+ *
28
+ * Each call imports a unique URL, and Node's ESM registry never evicts — so
29
+ * every call retains one bundle for the process lifetime. That is fine for
30
+ * one-shot commands (`aai build`); long-lived callers must go through
31
+ * `createWorkerEvaluator` to at least dedupe identical builds. Evaluating in
32
+ * a discardable context is not an option: tool `execute` functions from the
33
+ * returned AgentDef are called in-process by the dev runtime, which rules
34
+ * out worker threads, and `node:vm` ESM evaluation is still flagged
35
+ * experimental.
36
+ */
37
+ export declare function evalWorkerBundle(code: string): Promise<AgentDef>;
38
+ /**
39
+ * Memoizing wrapper around `evalWorkerBundle` for long-lived callers (the
40
+ * dev server): byte-identical worker code returns the previously evaluated
41
+ * AgentDef without touching the ESM registry. No-op saves and formatter
42
+ * churn are the common watcher events, so this caps the registry leak (see
43
+ * `evalWorkerBundle`) to genuinely-new bundles — the residual one-module-per-
44
+ * distinct-build leak is accepted for the reasons documented there.
45
+ */
46
+ export declare function createWorkerEvaluator(): (code: string) => Promise<AgentDef>;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * `.aai/project.json` lives in the working tree, so everything in it is
4
+ * untrusted input — a cloned repo can supply any value.
5
+ *
6
+ * `serverUrl` is deliberately NOT validated here. A failed field makes
7
+ * `readProjectConfig` return null for the whole file, which discards the
8
+ * `slug` too — and a deploy with no slug generates a fresh one, silently
9
+ * creating a duplicate agent and overwriting the config. The URL is instead
10
+ * validated where it is used, by `resolveServerUrl`, which rejects anything
11
+ * that isn't an approved http(s) origin.
12
+ */
13
+ declare const ProjectConfigSchema: z.ZodObject<{
14
+ slug: z.ZodString;
15
+ serverUrl: z.ZodString;
16
+ }, z.core.$strip>;
17
+ /**
18
+ * Resolve the global config directory (the platform-conventional env-paths
19
+ * location).
20
+ *
21
+ * `AAI_CONFIG_DIR` overrides everything — it exists so tests (and unusual
22
+ * setups) can redirect ALL global-config reads and writes away from the
23
+ * user's real config. The test suite's `approveServer` calls used to
24
+ * permanently pollute `~/.config/aai/config.json` with approved origins.
25
+ */
26
+ export declare function getConfigDir(): string;
27
+ export type ProjectConfig = z.infer<typeof ProjectConfigSchema>;
28
+ export declare function readProjectConfig(agentDir: string): Promise<ProjectConfig | null>;
29
+ export declare function writeProjectConfig(agentDir: string, data: ProjectConfig): Promise<void>;
30
+ export type GlobalConfig = {
31
+ apiKey?: string;
32
+ /**
33
+ * Origins the user has explicitly pointed the CLI at with `--server`.
34
+ *
35
+ * Lives in the user-owned global config, never in the repo: it is what makes
36
+ * a `serverUrl` from `.aai/project.json` trustworthy enough to receive an
37
+ * API key. See `resolveServerUrl`.
38
+ */
39
+ approvedServers?: string[];
40
+ };
41
+ /**
42
+ * Origin of `url`, or `null` when it is not an absolute http(s) URL.
43
+ *
44
+ * Non-HTTP schemes are rejected rather than returned: `new URL()` yields the
45
+ * opaque origin `"null"` for them, which would otherwise flow on as if it
46
+ * were a real origin.
47
+ */
48
+ export declare function serverOrigin(url: string): string | null;
49
+ /**
50
+ * Record `url`'s origin as user-approved, so later commands in this project
51
+ * may send credentials there without re-passing `--server`.
52
+ */
53
+ export declare function approveServer(url: string, configDir?: string): Promise<void>;
54
+ export declare function readGlobalConfig(configDir?: string): Promise<GlobalConfig>;
55
+ export declare function writeGlobalConfig(configDir: string, data: GlobalConfig): Promise<void>;
56
+ export declare function ensureApiKey(configDir?: string): Promise<string>;
57
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { Plugin } from "vite";
2
+ export declare const DEFAULT_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, viewport-fit=cover\" />\n <title>aai</title>\n <link rel=\"icon\" href=\"./favicon.ico\" />\n <style>html, body { background: #FBF8F2; margin: 0; }</style>\n </head>\n <body>\n <main id=\"app\"></main>\n <script type=\"module\" src=\"./client.tsx\"></script>\n </body>\n</html>";
3
+ /**
4
+ * Vite plugin that serves a fallback index.html in dev mode when one doesn't
5
+ * exist on disk. No-op if index.html exists (user override).
6
+ */
7
+ export declare function fallbackHtmlPlugin(root: string): Plugin;
8
+ /**
9
+ * Write a temporary index.html for Vite build (HTML must be on disk for build).
10
+ * Returns a cleanup function to remove it. No-op if index.html already exists.
11
+ */
12
+ export declare function writeTempHtml(root: string): () => void;
@@ -0,0 +1,28 @@
1
+ import type { DirectoryBundleOutput } from "./_bundler.ts";
2
+ export type DeployOpts = {
3
+ url: string;
4
+ bundle: DirectoryBundleOutput;
5
+ /** Env var values from .env to send to the server. */
6
+ env: Record<string, string>;
7
+ /** Existing slug for redeployment. Omit for first deploy — server generates one. */
8
+ slug?: string;
9
+ apiKey: string;
10
+ /**
11
+ * Ask the server to WARN (in `warnings`) instead of rejecting when the
12
+ * agent's providers are missing credentials — `aai deploy
13
+ * --allow-missing-secrets`, for setting them post-deploy with
14
+ * `aai secret put` (the studio's publish flow relies on this: its Secrets
15
+ * panel needs a deployed slug to attach secrets to).
16
+ */
17
+ allowMissingSecrets?: boolean;
18
+ /** Retry delay override for tests (0 = no real sleeps on retry paths). */
19
+ retryDelay?: number;
20
+ /** Optional fetch implementation for testing. Defaults to globalThis.fetch. */
21
+ fetch?: typeof globalThis.fetch;
22
+ };
23
+ export type DeployResult = {
24
+ slug: string;
25
+ /** Server-side deploy warnings (e.g. the missing-credential preflight). */
26
+ warnings?: string[];
27
+ };
28
+ export declare function runDeploy(opts: DeployOpts): Promise<DeployResult>;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Dev server for directory-based agents.
3
+ *
4
+ * Imports agent.ts directly for the full agent definition,
5
+ * builds a runtime, and starts an HTTP+WebSocket server. Watches for
6
+ * file changes and restarts automatically. Optionally runs Vite for
7
+ * client SPA HMR.
8
+ */
9
+ import type { AgentDef } from "@alexkroman1/aai";
10
+ import { type FSWatcher } from "chokidar";
11
+ /**
12
+ * Warnings about the agent's credentials, computed against the `.env`-derived
13
+ * env and the shell. Pure so it is directly testable; `resolveAgentEnv` logs
14
+ * each entry. Three cases, in increasing subtlety:
15
+ *
16
+ * - a provider key found nowhere → the first session will fail auth;
17
+ * - a provider key found only in the shell → works here (the
18
+ * `withHostCredentialFallback` ergonomic) but is invisible to `aai deploy`,
19
+ * which uploads `.env` — the classic "works locally, dead on deploy";
20
+ * - a declared `requiredEnv` key absent from `.env` → `ctx.env` won't contain
21
+ * it at all: custom keys never fall back to the shell, so a shell export
22
+ * can't mask one that would be missing both here and after deploy.
23
+ */
24
+ export declare function agentEnvWarnings(agentDef: Pick<AgentDef, "stt" | "llm" | "tts" | "s2s" | "requiredEnv">, env: Record<string, string>, shellEnv?: Record<string, string | undefined>): string[];
25
+ /**
26
+ * Load the agent definition by bundling agent.ts (and all its local imports)
27
+ * into a single ESM file, then importing that. A raw `import(agent.ts?t=...)`
28
+ * only cache-busts agent.ts itself — transitive imports (./tools.ts, etc.)
29
+ * stay in Node's ESM registry, so edits to them are ignored on reload.
30
+ * Bundling picks them up.
31
+ *
32
+ * The bundle comes from the same Vite pass deploy runs (`buildWorker`), so
33
+ * dev and deploy can't drift; a warm rebuild is well under 100ms. Compile
34
+ * errors in the agent's code propagate — the restart loop reports them and
35
+ * keeps the old server. Evaluation goes through the memoizing evaluator so
36
+ * a no-op save doesn't leak another module into the ESM registry.
37
+ */
38
+ export declare function loadAgentDef(cwd: string, evaluate: (code: string) => Promise<AgentDef>): Promise<AgentDef>;
39
+ /**
40
+ * True for paths that should never trigger a restart: anything inside
41
+ * `node_modules/` and any dot-entry (`.git/`, `.aai/`, `.DS_Store`, …).
42
+ * `.git/` especially matters — commits and status checks churn the index
43
+ * and would otherwise cause spurious full backend restarts.
44
+ *
45
+ * Exception: `.env` / `.env.*` files stay watched — env edits should
46
+ * restart the server with the new values.
47
+ */
48
+ export declare function isIgnoredPath(dir: string, filePath: string): boolean;
49
+ /**
50
+ * Watch the agent directory for changes and call `onChange` when detected.
51
+ * Debounces to avoid rapid restarts. Uses chokidar for reliable recursive
52
+ * watching across platforms (raw `fs.watch` misses events on Linux).
53
+ */
54
+ export declare function watchDirectory(dir: string, onChange: () => void): FSWatcher;
55
+ export type DevServerOptions = {
56
+ cwd: string;
57
+ port: number;
58
+ };
59
+ /**
60
+ * Vite dev-server config for the client SPA. Extracted so the proxy wiring
61
+ * is unit-testable: `/websocket` MUST proxy with `ws: true` or `aai dev`
62
+ * with a `client.tsx` serves a page whose WebSocket never connects.
63
+ *
64
+ * `strictPort` because the reported URL is `http://localhost:<port>` —
65
+ * without it, Vite silently binds port+N when the port is busy and the
66
+ * printed/JSON-returned URL points at whatever else was listening.
67
+ */
68
+ export declare function viteDevConfig(cwd: string, vitePort: number, backendPort: number): import("vite").InlineConfig;
69
+ /**
70
+ * Start the dev server for a directory-based agent.
71
+ *
72
+ * Returns a cleanup function to shut down the server and watchers.
73
+ */
74
+ export declare function startDevServer(opts: DevServerOptions): Promise<() => Promise<void>>;
@@ -4,78 +4,57 @@ import { r as isDevMode, t as getMonorepoRoot } from "./_agent-D8zBb3M5.mjs";
4
4
  import { existsSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
- import os from "node:os";
8
- import { downloadTemplate } from "giget";
9
- //#region _templates.ts
10
- /** The GitHub repo (owner/name) that hosts this project and its templates. */
11
- const REPO = "alexkroman/agent";
12
- const REPO_URL = `https://github.com/${REPO}`;
13
- const GIGET_SOURCE = `github:${REPO}/packages/aai-templates`;
14
- const GIGET_REF = process.env.AAI_TEMPLATES_REF ?? "main";
15
- const VALID_REF_RE = /^[\w./-]+$/;
16
- const noCleanup = async () => void 0;
17
- /** Resolve the templates directory local in dev, giget download in prod. */
18
- async function resolveTemplatesDir() {
19
- if (process.env.AAI_TEMPLATES_DIR) return {
20
- root: process.env.AAI_TEMPLATES_DIR,
21
- cleanup: noCleanup
22
- };
7
+ const REPO_URL = `https://github.com/alexkroman/agent`;
8
+ /**
9
+ * Templates as shipped inside the published tarball, copied into `dist/` by
10
+ * `bundle-templates.mjs` at build time so this resolves to `dist/` for a
11
+ * published CLI and to the (template-less) package root when running source
12
+ * in the monorepo, where the branch above wins.
13
+ *
14
+ * They used to be fetched at `init` time with giget from
15
+ * `github:alexkroman/agent/packages/aai-templates#main`. That required a
16
+ * network for every `init`, and pinned templates to `main` regardless of the
17
+ * CLI version the user had installed, so a template written against a newer
18
+ * SDK could land in a project resolving an older one. Bundling pins the two
19
+ * together by construction. It also puts the templates inside the studio's
20
+ * guest sandbox, which has the CLI in its baked toolchain but no way to fetch
21
+ * anything from GitHub.
22
+ */
23
+ function bundledTemplatesDir() {
24
+ return import.meta.dirname;
25
+ }
26
+ /** Resolve the templates root — env override, then monorepo, then bundled. */
27
+ function resolveTemplatesDir() {
28
+ const override = process.env.AAI_TEMPLATES_DIR;
29
+ if (override) return override;
23
30
  const monorepoRoot = getMonorepoRoot();
24
- if (monorepoRoot) return {
25
- root: path.join(monorepoRoot, "packages", "aai-templates"),
26
- cleanup: noCleanup
27
- };
28
- if (!VALID_REF_RE.test(GIGET_REF)) throw new Error(`Invalid AAI_TEMPLATES_REF: ${JSON.stringify(GIGET_REF)} is not a git ref.`);
29
- const extractDir = await fs.mkdtemp(path.join(os.tmpdir(), "aai-templates-"));
30
- const cleanup = async () => {
31
- await fs.rm(extractDir, {
32
- recursive: true,
33
- force: true
34
- }).catch(() => void 0);
35
- };
36
- try {
37
- const { dir } = await downloadTemplate(`${GIGET_SOURCE}#${GIGET_REF}`, {
38
- dir: extractDir,
39
- force: true,
40
- forceClean: true
41
- });
42
- return {
43
- root: dir,
44
- cleanup
45
- };
46
- } catch (err) {
47
- await cleanup();
48
- throw new Error(`Failed to download templates from ${GIGET_SOURCE}#${GIGET_REF}: ${errorMessage(err)}`, { cause: err });
49
- }
31
+ if (monorepoRoot) return path.join(monorepoRoot, "packages", "aai-templates");
32
+ return bundledTemplatesDir();
50
33
  }
51
34
  /**
52
- * Download a template into targetDir, merging scaffold files underneath.
35
+ * Copy a template into targetDir, merging scaffold files underneath.
53
36
  */
54
37
  async function downloadAndMergeTemplate(template, targetDir) {
55
- const { root, cleanup } = await resolveTemplatesDir();
38
+ const root = resolveTemplatesDir();
39
+ const templatesDir = path.join(root, "templates");
40
+ let available;
56
41
  try {
57
- const templatesDir = path.join(root, "templates");
58
- let available;
59
- try {
60
- available = await fs.readdir(templatesDir, { withFileTypes: true });
61
- } catch (err) {
62
- throw new Error(`Templates directory is missing or unreadable at ${templatesDir} (corrupt or incomplete template download?): ${errorMessage(err)}`, { cause: err });
63
- }
64
- const names = available.filter((e) => e.isDirectory()).map((e) => e.name);
65
- if (!names.includes(template)) throw new Error(`Unknown template "${template}". Available templates: ${names.join(", ")}`);
66
- await fs.cp(path.join(templatesDir, template), targetDir, {
67
- recursive: true,
68
- force: true
69
- });
70
- const scaffoldDir = path.join(root, "scaffold");
71
- if (existsSync(scaffoldDir)) await fs.cp(scaffoldDir, targetDir, {
72
- recursive: true,
73
- force: false,
74
- errorOnExist: false
75
- });
76
- } finally {
77
- await cleanup();
42
+ available = await fs.readdir(templatesDir, { withFileTypes: true });
43
+ } catch (err) {
44
+ throw new Error(`Templates directory is missing or unreadable at ${templatesDir} (incomplete @alexkroman1/aai-cli install?): ${errorMessage(err)}`, { cause: err });
78
45
  }
46
+ const names = available.filter((e) => e.isDirectory()).map((e) => e.name);
47
+ if (!names.includes(template)) throw new Error(`Unknown template "${template}". Available templates: ${names.join(", ")}`);
48
+ await fs.cp(path.join(templatesDir, template), targetDir, {
49
+ recursive: true,
50
+ force: true
51
+ });
52
+ const scaffoldDir = path.join(root, "scaffold");
53
+ if (existsSync(scaffoldDir)) await fs.cp(scaffoldDir, targetDir, {
54
+ recursive: true,
55
+ force: false,
56
+ errorOnExist: false
57
+ });
79
58
  }
80
59
  //#endregion
81
60
  //#region _init.ts
@@ -0,0 +1,7 @@
1
+ export type InitOptions = {
2
+ targetDir: string;
3
+ template: string;
4
+ };
5
+ /** Rewrite workspace deps to link: paths so pnpm links to local source. */
6
+ export declare function patchPackageJsonForWorkspace(targetDir: string): Promise<void>;
7
+ export declare function runInit(opts: InitOptions): Promise<void>;
@@ -0,0 +1,22 @@
1
+ export interface RecordedRequest {
2
+ method: string;
3
+ path: string;
4
+ headers: Record<string, string | string[] | undefined>;
5
+ /** Decoded body text (inflated first when sent with Content-Encoding: gzip). */
6
+ body: string;
7
+ }
8
+ export interface MockApi {
9
+ /** Base URL of the mock server (http://localhost:<port>) */
10
+ url: string;
11
+ /** All recorded requests */
12
+ requests: RecordedRequest[];
13
+ /** Secrets currently stored */
14
+ secrets: Record<string, string>;
15
+ /** Override response for a specific method+path pattern */
16
+ override(method: string, pathPattern: string, status: number, body?: string): void;
17
+ /** Clear recorded requests */
18
+ clear(): void;
19
+ /** Stop the server */
20
+ stop(): Promise<void>;
21
+ }
22
+ export declare function startMockApi(): Promise<MockApi>;
@@ -0,0 +1,17 @@
1
+ export interface MockRegistry {
2
+ /** Local registry URL (http://localhost:<port>) */
3
+ registryUrl: string;
4
+ /** The unique version string used for published workspace packages */
5
+ testVersion: string;
6
+ /** Environment variables to set for child processes using this registry */
7
+ env: Record<string, string>;
8
+ /** Stop the registry and clean up */
9
+ stop: () => Promise<void>;
10
+ }
11
+ /**
12
+ * Start a mock npm registry, build and publish workspace packages to it.
13
+ *
14
+ * @param packagesDir - Path to the `packages/` directory in the monorepo
15
+ * @param packageNames - Directory names under `packages/` to publish (e.g. ["aai", "aai-ui", "aai-cli"])
16
+ */
17
+ export declare function startMockRegistry(packagesDir: string, packageNames: string[]): Promise<MockRegistry>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Structured output support for CLI commands.
3
+ *
4
+ * In JSON mode (non-TTY or --json), commands emit exactly one JSON line to
5
+ * stdout. In human mode (TTY, default), commands use @clack/prompts as before.
6
+ */
7
+ export type OutputMode = "json" | "human";
8
+ export type CommandResult<T> = {
9
+ ok: true;
10
+ data: T;
11
+ } | {
12
+ ok: false;
13
+ error: string;
14
+ code: string;
15
+ hint?: string;
16
+ };
17
+ /**
18
+ * Determine output mode from CLI flags and TTY state.
19
+ *
20
+ * Priority: --json flag > --no-json flag > TTY auto-detection.
21
+ */
22
+ export declare function getOutputMode(args: {
23
+ json?: boolean | undefined;
24
+ }, isTTY?: boolean): OutputMode;
25
+ /**
26
+ * Write a line to stdout, resolving only once it has been flushed.
27
+ *
28
+ * Resolves (never rejects) even when the write fails: the common failure is
29
+ * EPIPE — the consumer closed the pipe (`aai … --json | head -1`) — and there
30
+ * is nothing useful to do about a broken stdout except carry on and exit.
31
+ * Stream-level `'error'` events are handled by {@link installStdoutGuard}.
32
+ */
33
+ export declare function writeLine(line: string): Promise<void>;
34
+ /**
35
+ * Install an `'error'` listener on stdout so a broken pipe doesn't crash the
36
+ * CLI with an unhandled `'error'` event. EPIPE (consumer went away, e.g.
37
+ * `aai … --json | head -1`) exits quietly; anything else is reported on
38
+ * stderr and exits non-zero.
39
+ */
40
+ export declare function installStdoutGuard(stream?: NodeJS.WriteStream): void;
41
+ /** Create an ok result. */
42
+ export declare function ok<T>(data: T): CommandResult<T>;
43
+ /** Create an error result. */
44
+ export declare function fail<T>(code: string, error: string, hint?: string): CommandResult<T>;
45
+ /** Typed CLI error that carries a structured error code and optional hint. */
46
+ export declare class CliError extends Error {
47
+ readonly code: string;
48
+ readonly hint?: string | undefined;
49
+ constructor(code: string, message: string, hint?: string, options?: ErrorOptions);
50
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Build the `ctx.env` record that agent tools will see at runtime.
3
+ *
4
+ * Only variables explicitly declared in `.env` are included — matching
5
+ * the platform sandbox behavior where `ctx.env`
6
+ * contains only secrets set via `aai secret put`. This prevents agents
7
+ * from accidentally depending on shell-level vars (PATH, HOME, etc.) that
8
+ * won't exist in production.
9
+ *
10
+ * Values are resolved by merging the `.env` file with the current
11
+ * environment — existing shell exports take precedence over `.env`
12
+ * defaults, without mutating `process.env`.
13
+ *
14
+ * @param cwd - Project directory containing `.env` (optional).
15
+ * @param baseEnv - Override the environment to read values from (tests only).
16
+ */
17
+ export declare function resolveServerEnv(cwd?: string, baseEnv?: Record<string, string | undefined>): Promise<Record<string, string>>;
@@ -0,0 +1,15 @@
1
+ import { type ApiRequestOptions } from "./_api-client.ts";
2
+ /**
3
+ * Authenticated request against a deployed agent's slug-scoped resource
4
+ * (`${serverUrl}/${slug}${resourcePath}`) — the one shape every per-agent
5
+ * command (secret, storage) shares, including the standard "not deployed"
6
+ * 404 hint.
7
+ *
8
+ * Its own module (rather than living beside `getServerInfo` in `_agent.ts`)
9
+ * so tests can mock `_agent.ts`/`_api-client.ts` while this composition
10
+ * stays real — an intra-module call would bypass those mocks.
11
+ */
12
+ export declare function slugRequest<T = unknown>(cwd: string, resourcePath: string, init: Pick<ApiRequestOptions, "method" | "body" | "action">, server?: string): Promise<{
13
+ data: T;
14
+ slug: string;
15
+ }>;
@@ -0,0 +1,21 @@
1
+ export declare const REPO_URL = "https://github.com/alexkroman/agent";
2
+ /**
3
+ * Templates as shipped inside the published tarball, copied into `dist/` by
4
+ * `bundle-templates.mjs` at build time — so this resolves to `dist/` for a
5
+ * published CLI and to the (template-less) package root when running source
6
+ * in the monorepo, where the branch above wins.
7
+ *
8
+ * They used to be fetched at `init` time with giget from
9
+ * `github:alexkroman/agent/packages/aai-templates#main`. That required a
10
+ * network for every `init`, and pinned templates to `main` regardless of the
11
+ * CLI version the user had installed, so a template written against a newer
12
+ * SDK could land in a project resolving an older one. Bundling pins the two
13
+ * together by construction. It also puts the templates inside the studio's
14
+ * guest sandbox, which has the CLI in its baked toolchain but no way to fetch
15
+ * anything from GitHub.
16
+ */
17
+ export declare function bundledTemplatesDir(): string;
18
+ /**
19
+ * Copy a template into targetDir, merging scaffold files underneath.
20
+ */
21
+ export declare function downloadAndMergeTemplate(template: string, targetDir: string): Promise<void>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The build/deploy typecheck gate: run the project's own `tsc --noEmit`
3
+ * (see `typecheck.ts`) and turn a failure into a structured CliError. The
4
+ * bundlers strip types unchecked, so without this a type-broken agent
5
+ * ships and misbehaves at runtime instead of failing here.
6
+ */
7
+ export declare function assertTypechecks(cwd: string): Promise<void>;
package/dist/_ui.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import * as p from "@clack/prompts";
2
+ type Log = typeof p.log;
3
+ /** Log instance that delegates to clack (human mode) or no-ops (JSON mode). */
4
+ export declare const log: Log;
5
+ /** Replace all log methods with no-ops. Call once in JSON mode. */
6
+ export declare function silenceOutput(): void;
7
+ /**
8
+ * Unwrap a clack prompt result, exiting cleanly if the user cancelled.
9
+ * `message` lets the caller name what was cancelled (e.g. "Setup cancelled").
10
+ */
11
+ export declare function unwrapCancel<T>(result: T | symbol, message?: string): T;
12
+ /** Format a URL for display. */
13
+ export declare function fmtUrl(url: string): string;
14
+ /**
15
+ * Parse and validate a port string. Returns the numeric port or throws.
16
+ *
17
+ * Deliberately zod-free: this module loads on every CLI invocation
18
+ * (including `aai --help`), and keeping zod off that path is the same
19
+ * startup-cost invariant `_utils.ts` documents for its error helpers.
20
+ */
21
+ export declare function parsePort(raw: string): number;
22
+ export {};