@alexkroman1/aai-cli 5.1.0 → 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.
- package/dist/{_agent-D39qatZJ.mjs → _agent-D8zBb3M5.mjs} +2 -3
- package/dist/_agent.d.ts +39 -0
- package/dist/{_api-client-a6cPMebU.mjs → _api-client-MenP4-O7.mjs} +3 -1
- package/dist/_api-client.d.ts +37 -0
- package/dist/{_bundler-DdmuZzeR.mjs → _bundler-DFS4xxqE.mjs} +3 -13
- package/dist/_bundler.d.ts +46 -0
- package/dist/{_config-Czjhvaax.mjs → _config-D3F9km8X.mjs} +3 -3
- package/dist/_config.d.ts +57 -0
- package/dist/_default-html.d.ts +12 -0
- package/dist/_deploy.d.ts +28 -0
- package/dist/{_dev-server-BCbEUhmv.mjs → _dev-server-BBUWo0sb.mjs} +12 -14
- package/dist/_dev-server.d.ts +74 -0
- package/dist/{_init-H-lw7czL.mjs → _init-DU-sXH6S.mjs} +47 -65
- package/dist/_init.d.ts +7 -0
- package/dist/_mock-api.d.ts +22 -0
- package/dist/_mock-registry.d.ts +17 -0
- package/dist/_output.d.ts +50 -0
- package/dist/{_server-common-B75oco06.mjs → _server-common-CnaP_Urf.mjs} +2 -1
- package/dist/_server-common.d.ts +17 -0
- package/dist/_slug-api-19R5kZ0U.mjs +27 -0
- package/dist/_slug-api.d.ts +15 -0
- package/dist/_templates.d.ts +21 -0
- package/dist/{_typecheck-gate-B1GcKZX-.mjs → _typecheck-gate-9IHWDnl1.mjs} +2 -2
- package/dist/_typecheck-gate.d.ts +7 -0
- package/dist/{_ui-DXZ9prrM.mjs → _ui-8kOEB-JH.mjs} +6 -3
- package/dist/_ui.d.ts +22 -0
- package/dist/{_utils-C502jKo8.mjs → _utils-Ch0J4s6a.mjs} +17 -1
- package/dist/_utils.d.ts +48 -0
- package/dist/_vite-env.d.ts +8 -0
- package/dist/build-Xq1xxoSg.mjs +38 -0
- package/dist/build.d.ts +16 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +35 -52
- package/dist/{client-bundler-DO3GgO6p.mjs → client-bundler-BWDkUeEP.mjs} +5 -6
- package/dist/client-bundler.d.ts +21 -0
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-K24hW1ab.mjs → delete-kSXFLxek.mjs} +4 -4
- package/dist/delete.d.ts +18 -0
- package/dist/{deploy-D-dnt9L8.mjs → deploy-Ci0X1gp2.mjs} +8 -8
- package/dist/deploy.d.ts +15 -0
- package/dist/{dev-C8o-p13B.mjs → dev-g7sGt8qX.mjs} +3 -3
- package/dist/dev.d.ts +13 -0
- package/dist/{init-B53rR3yD.mjs → init-BjeK8crW.mjs} +10 -17
- package/dist/init.d.ts +24 -0
- package/dist/scaffold/.env.example +11 -0
- package/dist/scaffold/CLAUDE.md +919 -0
- package/dist/scaffold/global.d.ts +1 -0
- package/dist/scaffold/package.json +32 -0
- package/dist/scaffold/pnpm-workspace.yaml +13 -0
- package/dist/scaffold/tsconfig.json +19 -0
- package/dist/scaffold/vite.config.ts +14 -0
- package/dist/scaffold/vitest.config.ts +24 -0
- package/dist/{secret-C4unwCEw.mjs → secret-DOva9OGk.mjs} +21 -20
- package/dist/secret.d.ts +25 -0
- package/dist/{storage-tZM1J8qj.mjs → storage-vM6HjDZZ.mjs} +6 -13
- package/dist/storage.d.ts +22 -0
- package/dist/templates/code-interpreter/agent.ts +11 -0
- package/dist/templates/code-interpreter/system-prompt.md +18 -0
- package/dist/templates/dispatch-center/agent.test.ts +153 -0
- package/dist/templates/dispatch-center/agent.ts +50 -0
- package/dist/templates/dispatch-center/client.tsx +378 -0
- package/dist/templates/dispatch-center/shared.ts +631 -0
- package/dist/templates/dispatch-center/system-prompt.md +39 -0
- package/dist/templates/dispatch-center/tools/incident_add_note.ts +27 -0
- package/dist/templates/dispatch-center/tools/incident_create.ts +79 -0
- package/dist/templates/dispatch-center/tools/incident_escalate.ts +88 -0
- package/dist/templates/dispatch-center/tools/incident_get.ts +36 -0
- package/dist/templates/dispatch-center/tools/incident_triage.ts +78 -0
- package/dist/templates/dispatch-center/tools/incident_update_status.ts +68 -0
- package/dist/templates/dispatch-center/tools/ops_dashboard.ts +52 -0
- package/dist/templates/dispatch-center/tools/ops_protocols.ts +27 -0
- package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +149 -0
- package/dist/templates/dispatch-center/tools/resources_dispatch.ts +97 -0
- package/dist/templates/dispatch-center/tools/resources_get_available.ts +36 -0
- package/dist/templates/dispatch-center/tools/resources_update_status.ts +62 -0
- package/dist/templates/embedded-assets/agent.ts +55 -0
- package/dist/templates/embedded-assets/knowledge.json +20 -0
- package/dist/templates/health-assistant/agent.ts +174 -0
- package/dist/templates/health-assistant/system-prompt.md +17 -0
- package/dist/templates/infocom-adventure/agent.ts +119 -0
- package/dist/templates/infocom-adventure/client.tsx +279 -0
- package/dist/templates/infocom-adventure/shared.ts +38 -0
- package/dist/templates/infocom-adventure/system-prompt.md +43 -0
- package/dist/templates/math-buddy/agent.ts +16 -0
- package/dist/templates/math-buddy/system-prompt.md +12 -0
- package/dist/templates/night-owl/agent.ts +76 -0
- package/dist/templates/night-owl/client.tsx +130 -0
- package/dist/templates/night-owl/shared.ts +5 -0
- package/dist/templates/personal-finance/agent.ts +11 -0
- package/dist/templates/personal-finance/system-prompt.md +17 -0
- package/dist/templates/pipeline-simple/agent.test.ts +32 -0
- package/dist/templates/pipeline-simple/agent.ts +13 -0
- package/dist/templates/pizza-ordering/agent.test.ts +235 -0
- package/dist/templates/pizza-ordering/agent.ts +174 -0
- package/dist/templates/pizza-ordering/client.tsx +120 -0
- package/dist/templates/pizza-ordering/shared.ts +142 -0
- package/dist/templates/pizza-ordering/system-prompt.md +17 -0
- package/dist/templates/simple/agent.ts +5 -0
- package/dist/templates/solo-rpg/agent.test.ts +477 -0
- package/dist/templates/solo-rpg/agent.ts +37 -0
- package/dist/templates/solo-rpg/client.tsx +809 -0
- package/dist/templates/solo-rpg/shared.ts +747 -0
- package/dist/templates/solo-rpg/system-prompt.md +115 -0
- package/dist/templates/solo-rpg/tools/action_roll.ts +98 -0
- package/dist/templates/solo-rpg/tools/burn_momentum.ts +69 -0
- package/dist/templates/solo-rpg/tools/check_state.ts +11 -0
- package/dist/templates/solo-rpg/tools/load_game.ts +25 -0
- package/dist/templates/solo-rpg/tools/oracle.ts +248 -0
- package/dist/templates/solo-rpg/tools/save_game.ts +20 -0
- package/dist/templates/solo-rpg/tools/setup_character.ts +208 -0
- package/dist/templates/solo-rpg/tools/update_state.ts +170 -0
- package/dist/templates/web-researcher/agent.ts +11 -0
- package/dist/{test-CgWhus_Z.mjs → test-3Gq4pqH_.mjs} +5 -7
- package/dist/test.d.ts +39 -0
- package/dist/tsdown.config.d.ts +2 -0
- package/dist/typecheck.d.ts +26 -0
- package/dist/typecheck.mjs +6 -10
- package/dist/worker-bundler.d.ts +29 -0
- package/package.json +9 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as serverOrigin, i as readProjectConfig, n as ensureApiKey, r as readGlobalConfig, t as approveServer } from "./_config-
|
|
2
|
+
import { a as serverOrigin, i as readProjectConfig, n as ensureApiKey, r as readGlobalConfig, t as approveServer } from "./_config-D3F9km8X.mjs";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -71,8 +71,7 @@ function resolveServerUrl(explicit, configUrl, approvedOrigins = []) {
|
|
|
71
71
|
* the project has never been deployed), server URL, and API key.
|
|
72
72
|
*/
|
|
73
73
|
async function resolveDeployTarget(cwd, explicitServer) {
|
|
74
|
-
const config = await readProjectConfig(cwd);
|
|
75
|
-
const globalConfig = await readGlobalConfig();
|
|
74
|
+
const [config, globalConfig] = await Promise.all([readProjectConfig(cwd), readGlobalConfig()]);
|
|
76
75
|
const serverUrl = resolveServerUrl(explicitServer, config?.serverUrl, globalConfig.approvedServers ?? []);
|
|
77
76
|
if (explicitServer) await approveServer(serverUrl);
|
|
78
77
|
return {
|
package/dist/_agent.d.ts
ADDED
|
@@ -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
|
+
}>;
|
|
@@ -9,6 +9,8 @@ import { FetchError, ofetch } from "ofetch";
|
|
|
9
9
|
* 5xx/429) are retried before surfacing an error.
|
|
10
10
|
*/
|
|
11
11
|
const HINT_INVALID_API_KEY = "Your API key may be invalid. Run `aai` to re-enter your AssemblyAI API key.";
|
|
12
|
+
/** 404 hint for requests scoped to a deployed agent's slug. */
|
|
13
|
+
const HINT_NOT_DEPLOYED = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
|
|
12
14
|
/**
|
|
13
15
|
* Send an authenticated request to the platform API and return the parsed
|
|
14
16
|
* JSON response. Throws a descriptive error with status-specific hints on
|
|
@@ -44,4 +46,4 @@ function toApiError(err, url, opts) {
|
|
|
44
46
|
return new Error(`${opts.action} failed: could not reach ${url}\n ${hint}`, { cause });
|
|
45
47
|
}
|
|
46
48
|
//#endregion
|
|
47
|
-
export { apiRequest as t };
|
|
49
|
+
export { apiRequest as n, HINT_NOT_DEPLOYED as t };
|
|
@@ -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>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as buildClient } from "./client-bundler-DO3GgO6p.mjs";
|
|
2
|
+
import { u as validateAgentExport } from "./_utils-Ch0J4s6a.mjs";
|
|
3
|
+
import { t as buildClient } from "./client-bundler-BWDkUeEP.mjs";
|
|
5
4
|
import { buildWorker } from "./worker-bundler.mjs";
|
|
6
5
|
import path from "node:path";
|
|
7
6
|
import { pathToFileURL } from "node:url";
|
|
@@ -79,14 +78,5 @@ function createWorkerEvaluator() {
|
|
|
79
78
|
return agentDef;
|
|
80
79
|
};
|
|
81
80
|
}
|
|
82
|
-
async function executeBuild(cwd) {
|
|
83
|
-
const bundle = await buildAgentBundle(cwd, { minify: true });
|
|
84
|
-
const agentDef = await evalWorkerBundle(bundle.worker);
|
|
85
|
-
log.success("Build complete");
|
|
86
|
-
return ok({
|
|
87
|
-
name: agentDef.name,
|
|
88
|
-
workerBytes: bundle.worker.length
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
81
|
//#endregion
|
|
92
|
-
export {
|
|
82
|
+
export { createWorkerEvaluator as n, evalWorkerBundle as r, buildAgentBundle as 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>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as unwrapCancel, n as log, o as CliError } from "./_ui-
|
|
3
|
-
import {
|
|
2
|
+
import { a as unwrapCancel, n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
+
import { a as errorMessage, c as readJson, d as writeJson } from "./_utils-Ch0J4s6a.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import * as p from "@clack/prompts";
|
|
6
6
|
import envPaths from "env-paths";
|
|
@@ -116,7 +116,7 @@ async function ensureApiKey(configDir) {
|
|
|
116
116
|
return envKey;
|
|
117
117
|
}
|
|
118
118
|
if (!process.stdin.isTTY) throw new CliError("no_api_key", "No API key configured and no TTY to prompt for one.", "Set the ASSEMBLYAI_API_KEY environment variable, or run `aai` interactively once to save a key.");
|
|
119
|
-
const apiKey = unwrapCancel(await p.password({ message: "Enter your AssemblyAI API key" }));
|
|
119
|
+
const apiKey = unwrapCancel(await p.password({ message: "Enter your AssemblyAI API key" }), "Setup cancelled");
|
|
120
120
|
await trySaveApiKey(dir, config, apiKey);
|
|
121
121
|
return apiKey;
|
|
122
122
|
}
|
|
@@ -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>;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as log } from "./_ui-
|
|
3
|
-
import {
|
|
4
|
-
import { n as fallbackHtmlPlugin } from "./client-bundler-
|
|
2
|
+
import { n as log } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
+
import { a as errorMessage, r as errorCode } from "./_utils-Ch0J4s6a.mjs";
|
|
4
|
+
import { n as fallbackHtmlPlugin } from "./client-bundler-BWDkUeEP.mjs";
|
|
5
5
|
import { buildWorker } from "./worker-bundler.mjs";
|
|
6
|
-
import { createWorkerEvaluator } from "./_bundler-
|
|
7
|
-
import { n as ensureApiKey } from "./_config-
|
|
8
|
-
import { t as resolveServerEnv } from "./_server-common-
|
|
6
|
+
import { n as createWorkerEvaluator } from "./_bundler-DFS4xxqE.mjs";
|
|
7
|
+
import { n as ensureApiKey } from "./_config-D3F9km8X.mjs";
|
|
8
|
+
import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import { setTimeout } from "node:timers/promises";
|
|
13
|
-
import { requiredProviderEnvVars, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
|
|
13
|
+
import { createRuntime, createServer, requiredProviderEnvVars, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
|
|
14
14
|
import { watch } from "chokidar";
|
|
15
15
|
import getPort, { portNumbers } from "get-port";
|
|
16
16
|
import pDebounce from "p-debounce";
|
|
@@ -183,7 +183,6 @@ function viteDevConfig(cwd, vitePort, backendPort) {
|
|
|
183
183
|
*/
|
|
184
184
|
async function startDevServer(opts) {
|
|
185
185
|
const { cwd, port } = opts;
|
|
186
|
-
const { createRuntime, createServer } = await import("@alexkroman1/aai/runtime");
|
|
187
186
|
const hasClient = existsSync(path.join(cwd, "client.tsx"));
|
|
188
187
|
const backendPort = hasClient ? await getPort({ port: portNumbers(port + 1, port + 100) }) : port;
|
|
189
188
|
const vitePort = port;
|
|
@@ -194,13 +193,12 @@ async function startDevServer(opts) {
|
|
|
194
193
|
const agentDef = await loadAgentDef(cwd, evaluateWorker);
|
|
195
194
|
const env = await resolveAgentEnv(cwd, agentDef);
|
|
196
195
|
const providerEnv = withHostCredentialFallback(env);
|
|
197
|
-
const runtime = createRuntime({
|
|
198
|
-
agent: agentDef,
|
|
199
|
-
env,
|
|
200
|
-
providerEnv
|
|
201
|
-
});
|
|
202
196
|
return createServer({
|
|
203
|
-
runtime
|
|
197
|
+
runtime: createRuntime({
|
|
198
|
+
agent: agentDef,
|
|
199
|
+
env,
|
|
200
|
+
providerEnv
|
|
201
|
+
}),
|
|
204
202
|
name: agentDef.name,
|
|
205
203
|
env: hostModeEnv(providerEnv),
|
|
206
204
|
hostBaseAgent: agentDef,
|
|
@@ -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>>;
|
|
@@ -1,85 +1,67 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
3
|
-
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-
|
|
2
|
+
import { a as errorMessage, c as readJson, d as writeJson, s as isEexist } from "./_utils-Ch0J4s6a.mjs";
|
|
3
|
+
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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;
|
|
20
30
|
const monorepoRoot = getMonorepoRoot();
|
|
21
|
-
if (monorepoRoot) return
|
|
22
|
-
|
|
23
|
-
cleanup: noCleanup
|
|
24
|
-
};
|
|
25
|
-
if (!VALID_REF_RE.test(GIGET_REF)) throw new Error(`Invalid AAI_TEMPLATES_REF: ${JSON.stringify(GIGET_REF)} is not a git ref.`);
|
|
26
|
-
const extractDir = await fs.mkdtemp(path.join(os.tmpdir(), "aai-templates-"));
|
|
27
|
-
const cleanup = async () => {
|
|
28
|
-
await fs.rm(extractDir, {
|
|
29
|
-
recursive: true,
|
|
30
|
-
force: true
|
|
31
|
-
}).catch(() => void 0);
|
|
32
|
-
};
|
|
33
|
-
try {
|
|
34
|
-
const { dir } = await downloadTemplate(`${GIGET_SOURCE}#${GIGET_REF}`, {
|
|
35
|
-
dir: extractDir,
|
|
36
|
-
force: true,
|
|
37
|
-
forceClean: true
|
|
38
|
-
});
|
|
39
|
-
return {
|
|
40
|
-
root: dir,
|
|
41
|
-
cleanup
|
|
42
|
-
};
|
|
43
|
-
} catch (err) {
|
|
44
|
-
await cleanup();
|
|
45
|
-
throw new Error(`Failed to download templates from ${GIGET_SOURCE}#${GIGET_REF}: ${errorMessage(err)}`, { cause: err });
|
|
46
|
-
}
|
|
31
|
+
if (monorepoRoot) return path.join(monorepoRoot, "packages", "aai-templates");
|
|
32
|
+
return bundledTemplatesDir();
|
|
47
33
|
}
|
|
48
34
|
/**
|
|
49
|
-
*
|
|
35
|
+
* Copy a template into targetDir, merging scaffold files underneath.
|
|
50
36
|
*/
|
|
51
37
|
async function downloadAndMergeTemplate(template, targetDir) {
|
|
52
|
-
const
|
|
38
|
+
const root = resolveTemplatesDir();
|
|
39
|
+
const templatesDir = path.join(root, "templates");
|
|
40
|
+
let available;
|
|
53
41
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
available = await fs.readdir(templatesDir, { withFileTypes: true });
|
|
58
|
-
} catch (err) {
|
|
59
|
-
throw new Error(`Templates directory is missing or unreadable at ${templatesDir} (corrupt or incomplete template download?): ${errorMessage(err)}`, { cause: err });
|
|
60
|
-
}
|
|
61
|
-
const names = available.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
62
|
-
if (!names.includes(template)) throw new Error(`Unknown template "${template}". Available templates: ${names.join(", ")}`);
|
|
63
|
-
await fs.cp(path.join(templatesDir, template), targetDir, {
|
|
64
|
-
recursive: true,
|
|
65
|
-
force: true
|
|
66
|
-
});
|
|
67
|
-
const scaffoldDir = path.join(root, "scaffold");
|
|
68
|
-
if (existsSync(scaffoldDir)) await fs.cp(scaffoldDir, targetDir, {
|
|
69
|
-
recursive: true,
|
|
70
|
-
force: false,
|
|
71
|
-
errorOnExist: false
|
|
72
|
-
});
|
|
73
|
-
} finally {
|
|
74
|
-
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 });
|
|
75
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
|
+
});
|
|
76
58
|
}
|
|
77
59
|
//#endregion
|
|
78
60
|
//#region _init.ts
|
|
79
61
|
function readmeContent(slug) {
|
|
80
62
|
return `# ${slug}
|
|
81
63
|
|
|
82
|
-
A voice agent built with [aai](
|
|
64
|
+
A voice agent built with [aai](${REPO_URL}).
|
|
83
65
|
|
|
84
66
|
## Getting started
|
|
85
67
|
|
package/dist/_init.d.ts
ADDED
|
@@ -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>;
|