@alexkroman1/aai-cli 0.10.3 → 0.11.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.
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env node
2
- import { colorize } from "consola/utils";
3
- //#region _ui.ts
4
- /** Interactive/info color wrapper (blue). */
5
- function interactive(s) {
6
- return colorize("blueBright", s);
7
- }
8
- /** Colored step message: bold action label + message. */
9
- function step(action, msg) {
10
- return `${colorize("bold", colorize("cyanBright", action))} ${msg}`;
11
- }
12
- /** Informational step message: bold blue action + message. */
13
- function stepInfo(action, msg) {
14
- return `${colorize("bold", colorize("blueBright", action))} ${msg}`;
15
- }
16
- /** Dimmed info sub-line (indented). */
17
- function info(msg) {
18
- return colorize("dim", ` ${msg}`);
19
- }
20
- /** Detail sub-line (indented). */
21
- function detail(msg) {
22
- return ` ${msg}`;
23
- }
24
- /** Warning message. */
25
- function warn(msg) {
26
- return `${colorize("yellowBright", "!")} ${msg}`;
27
- }
28
- /** Parse and validate a port string. Returns the numeric port or throws. */
29
- function parsePort(raw) {
30
- const port = Number.parseInt(raw, 10);
31
- if (Number.isNaN(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
32
- return port;
33
- }
34
- /**
35
- * Run an async command function, logging each step to stdout.
36
- * Replaces the Ink `runWithInk` pattern.
37
- */
38
- async function runCommand(fn) {
39
- const log = (msg) => console.log(msg);
40
- const setStatus = (msg) => {
41
- if (msg) process.stdout.write(`\r${colorize("dim", msg)}`);
42
- else process.stdout.write("\r\x1B[K");
43
- };
44
- await fn({
45
- log,
46
- setStatus
47
- });
48
- }
49
- //#endregion
50
- export { runCommand as a, warn as c, parsePort as i, info as n, step as o, interactive as r, stepInfo as s, detail as t };
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
- import { a as getServerInfo } from "./_discover-CbHCotwB.mjs";
3
- import { a as runCommand, o as step } from "./_ui-C9IvR7Fh.mjs";
4
- //#region _delete.ts
5
- async function runDelete(opts) {
6
- const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
7
- let resp;
8
- try {
9
- resp = await fetchFn(`${opts.url}/${opts.slug}`, {
10
- method: "DELETE",
11
- headers: { Authorization: `Bearer ${opts.apiKey}` }
12
- });
13
- } catch (err) {
14
- const hint = opts.url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
15
- throw new Error(`delete failed: could not reach ${opts.url}\n ${hint}`, { cause: err });
16
- }
17
- if (resp.ok) return;
18
- const text = await resp.text();
19
- let hint = "";
20
- if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
21
- else if (resp.status === 404) hint = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
22
- throw new Error(`delete failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
23
- }
24
- //#endregion
25
- //#region delete.ts
26
- async function runDeleteCommand(opts) {
27
- const { cwd } = opts;
28
- const { serverUrl, slug, apiKey } = await getServerInfo(cwd, opts.server);
29
- await runCommand(async ({ log }) => {
30
- log(step("Delete", slug));
31
- await runDelete({
32
- url: serverUrl,
33
- slug,
34
- apiKey
35
- });
36
- log(step("Deleted", `${serverUrl}/${slug}`));
37
- });
38
- }
39
- //#endregion
40
- export { runDeleteCommand };
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
- import { c as readProjectConfig, d as writeProjectConfig, i as getApiKey, r as generateSlug, u as resolveServerUrl } from "./_discover-CbHCotwB.mjs";
3
- import { a as runCommand, o as step, s as stepInfo } from "./_ui-C9IvR7Fh.mjs";
4
- import { buildAgentBundle } from "./_build-CElA0PJB.mjs";
5
- //#region _deploy.ts
6
- async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
7
- try {
8
- return await fetchFn(`${url}/${slug}/deploy`, {
9
- method: "POST",
10
- headers: {
11
- "Content-Type": "application/json",
12
- Authorization: `Bearer ${apiKey}`
13
- },
14
- body: JSON.stringify({
15
- env,
16
- worker,
17
- clientFiles
18
- })
19
- });
20
- } catch (err) {
21
- const hint = url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
22
- throw new Error(`deployment failed: could not reach ${url}\n ${hint}`, { cause: err });
23
- }
24
- }
25
- const MAX_RETRIES = 20;
26
- async function runDeploy(opts) {
27
- const { worker, clientFiles } = opts.bundle;
28
- const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
29
- let slug = opts.slug;
30
- for (let i = 0; i < MAX_RETRIES; i++) {
31
- const resp = await attemptDeploy(fetchFn, opts.url, slug, opts.apiKey, opts.env, worker, clientFiles);
32
- if (resp.ok) return { slug };
33
- const text = await resp.text();
34
- if (resp.status === 403 && text.includes("Slug")) {
35
- slug = generateSlug();
36
- continue;
37
- }
38
- let hint = "";
39
- if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
40
- else if (resp.status === 413) hint = "Your bundle is too large. Try reducing dependencies or splitting your agent.";
41
- throw new Error(`deploy failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
42
- }
43
- throw new Error(`deploy failed: could not find an available agent slug after ${MAX_RETRIES} attempts. Try setting a custom slug in .aai/project.json.`);
44
- }
45
- //#endregion
46
- //#region deploy.ts
47
- async function deployBundle(opts) {
48
- const { bundle, serverUrl, apiKey, cwd, log } = opts;
49
- let { slug } = opts;
50
- log(step("Deploy", slug));
51
- slug = (await runDeploy({
52
- url: serverUrl,
53
- bundle,
54
- env: { ASSEMBLYAI_API_KEY: apiKey },
55
- slug,
56
- apiKey
57
- })).slug;
58
- await writeProjectConfig(cwd, {
59
- slug,
60
- serverUrl
61
- });
62
- const agentUrl = `${serverUrl}/${slug}`;
63
- log(step("Ready", agentUrl));
64
- return agentUrl;
65
- }
66
- async function runDeployCommand(opts) {
67
- const { cwd } = opts;
68
- const dryRun = opts.dryRun ?? false;
69
- const apiKey = dryRun ? "" : await getApiKey();
70
- const projectConfig = await readProjectConfig(cwd);
71
- const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
72
- const slug = projectConfig?.slug ?? generateSlug();
73
- await runCommand(async ({ log }) => {
74
- const bundle = await buildAgentBundle(cwd, log);
75
- if (dryRun) {
76
- log(stepInfo("Dry run", `would deploy as ${slug}`));
77
- return;
78
- }
79
- await deployBundle({
80
- bundle,
81
- serverUrl,
82
- apiKey,
83
- slug,
84
- cwd,
85
- log
86
- });
87
- });
88
- }
89
- //#endregion
90
- export { runDeployCommand };
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env node
2
- import { s as loadAgent } from "./_discover-CbHCotwB.mjs";
3
- import { a as runCommand, i as parsePort, n as info, o as step } from "./_ui-C9IvR7Fh.mjs";
4
- import { buildAgentBundle, t as createClientDevServer } from "./_build-CElA0PJB.mjs";
5
- import { a as resolveServerEnv, i as loadAgentDef, n as bootServer, t as bootBackendServer } from "./_server-common-DekUfYGG.mjs";
6
- //#region dev.ts
7
- /** Build, boot, and verify the server — used by `--check` mode. */
8
- async function runCheckMode(cwd, port, log) {
9
- const bundle = await buildAgentBundle(cwd, log);
10
- const agentDef = await loadAgentDef(cwd);
11
- const env = await resolveServerEnv(cwd);
12
- const server = await bootServer(agentDef, bundle.clientDir, env, port);
13
- log(step("Ready", `http://localhost:${port}`));
14
- const base = `http://localhost:${port}`;
15
- try {
16
- const healthRes = await fetch(`${base}/health`);
17
- if (!healthRes.ok) throw new Error(`GET /health returned ${healthRes.status}. The server started but the health endpoint failed.`);
18
- const health = await healthRes.json();
19
- if (health.status !== "ok") throw new Error(`GET /health returned unhealthy status: ${JSON.stringify(health)}. Check your agent.ts for errors.`);
20
- log(step("Health", health.name ?? "ok"));
21
- const pageRes = await fetch(`${base}/`);
22
- if (!pageRes.ok) throw new Error(`GET / returned ${pageRes.status}. The client page failed to load.`);
23
- const html = await pageRes.text();
24
- if (!(html.includes("<") && html.includes("html"))) throw new Error("GET / did not return valid HTML. Check that client.tsx exists and builds correctly.");
25
- log(step("Client", "ok"));
26
- } catch (err) {
27
- await server.close();
28
- throw err;
29
- }
30
- await server.close();
31
- }
32
- async function _startDevServer(cwd, port, log, opts) {
33
- if (opts?.check) {
34
- await runCheckMode(cwd, port, log);
35
- return;
36
- }
37
- const agent = await loadAgent(cwd);
38
- if (!agent) throw new Error("No agent found — run `aai init` first");
39
- const agentDef = await loadAgentDef(cwd);
40
- const env = await resolveServerEnv();
41
- const backendPort = port + 1;
42
- await bootBackendServer(agentDef, env, backendPort);
43
- if (agent.clientEntry) {
44
- await (await createClientDevServer(cwd, backendPort, port)).listen();
45
- log(step("Ready", `http://localhost:${port}`));
46
- log(info("Client HMR enabled — edits to client.tsx update instantly"));
47
- } else {
48
- log(step("Ready", `http://localhost:${backendPort}`));
49
- log(info("No client.tsx found — serving agent API only"));
50
- }
51
- log(info("Ctrl-C to quit"));
52
- }
53
- async function runDevCommand(opts) {
54
- const port = parsePort(opts.port);
55
- await runCommand(async ({ log }) => {
56
- await _startDevServer(opts.cwd, port, log, opts.check ? { check: true } : void 0);
57
- });
58
- }
59
- //#endregion
60
- export { runDevCommand };
@@ -1,215 +0,0 @@
1
- #!/usr/bin/env node
2
- import { n as fileExists } from "./_discover-CbHCotwB.mjs";
3
- import { a as runCommand, i as parsePort, o as step } from "./_ui-C9IvR7Fh.mjs";
4
- import { i as loadAgentDef, r as envFileKeys } from "./_server-common-DekUfYGG.mjs";
5
- import path from "node:path";
6
- import fs from "node:fs/promises";
7
- import { colorize } from "consola/utils";
8
- import net from "node:net";
9
- //#region doctor.ts
10
- const PASS = colorize("greenBright", "✓");
11
- const WARN = colorize("yellowBright", "!");
12
- const FAIL = colorize("redBright", "✗");
13
- function statusIcon(status) {
14
- if (status === "pass") return PASS;
15
- if (status === "warn") return WARN;
16
- return FAIL;
17
- }
18
- async function checkNodeVersion() {
19
- const version = process.version;
20
- const match = version.match(/^v(\d+)\.(\d+)/);
21
- if (!match) return {
22
- name: "Node.js",
23
- status: "fail",
24
- message: `Unknown version: ${version}`
25
- };
26
- const [major, minor] = [Number(match[1]), Number(match[2])];
27
- if (major > 22 || major === 22 && minor >= 6) return {
28
- name: "Node.js",
29
- status: "pass",
30
- message: `${version} (>=22.6 required)`
31
- };
32
- return {
33
- name: "Node.js",
34
- status: "fail",
35
- message: `${version} — Node >=22.6 is required`,
36
- fix: "Install Node.js 22.6+ from https://nodejs.org or via nvm: nvm install 22"
37
- };
38
- }
39
- async function checkApiKey() {
40
- const key = process.env.ASSEMBLYAI_API_KEY || await (async () => {
41
- try {
42
- const configPath = path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".config", "aai", "config.json");
43
- return JSON.parse(await fs.readFile(configPath, "utf-8")).assemblyai_api_key;
44
- } catch {}
45
- })();
46
- if (!key) return {
47
- name: "API key",
48
- status: "fail",
49
- message: "ASSEMBLYAI_API_KEY not found",
50
- fix: "Run `aai init` to set up your API key, or set the ASSEMBLYAI_API_KEY environment variable"
51
- };
52
- if (key.length < 10) return {
53
- name: "API key",
54
- status: "warn",
55
- message: "ASSEMBLYAI_API_KEY looks too short — may be invalid",
56
- fix: "Get a valid key from https://www.assemblyai.com/dashboard/signup"
57
- };
58
- return {
59
- name: "API key",
60
- status: "pass",
61
- message: "ASSEMBLYAI_API_KEY is set"
62
- };
63
- }
64
- async function checkDependencies(cwd) {
65
- if (!await fileExists(path.join(cwd, "package.json"))) return {
66
- name: "Dependencies",
67
- status: "warn",
68
- message: "No package.json found",
69
- fix: "Run `aai init` to scaffold a project, or `npm init` to create package.json"
70
- };
71
- const nodeModules = path.join(cwd, "node_modules");
72
- if (!await fileExists(nodeModules)) return {
73
- name: "Dependencies",
74
- status: "fail",
75
- message: "node_modules/ not found — dependencies not installed",
76
- fix: "Run `npm install` to install dependencies"
77
- };
78
- if (!await fileExists(path.join(nodeModules, "@alexkroman1", "aai"))) return {
79
- name: "Dependencies",
80
- status: "fail",
81
- message: "@alexkroman1/aai package not found in node_modules",
82
- fix: "Run `npm install @alexkroman1/aai` to add the SDK"
83
- };
84
- return {
85
- name: "Dependencies",
86
- status: "pass",
87
- message: "node_modules/ present, SDK installed"
88
- };
89
- }
90
- async function checkEnvFile(cwd) {
91
- const envPath = path.join(cwd, ".env");
92
- if (!await fileExists(envPath)) {
93
- if (await fileExists(path.join(cwd, ".env.example"))) return {
94
- name: ".env file",
95
- status: "warn",
96
- message: ".env not found, but .env.example exists",
97
- fix: "Copy .env.example to .env and fill in the values: cp .env.example .env"
98
- };
99
- return {
100
- name: ".env file",
101
- status: "pass",
102
- message: "No .env file (using environment variables or aai config)"
103
- };
104
- }
105
- try {
106
- const content = await fs.readFile(envPath, "utf-8");
107
- const keys = envFileKeys(content);
108
- if (keys.length === 0) return {
109
- name: ".env file",
110
- status: "warn",
111
- message: ".env file is empty (no keys declared)"
112
- };
113
- const emptyKeys = [];
114
- for (const line of content.split("\n")) {
115
- const trimmed = line.trim();
116
- if (!trimmed || trimmed.startsWith("#")) continue;
117
- const eq = trimmed.indexOf("=");
118
- if (eq === -1) continue;
119
- const val = trimmed.slice(eq + 1).trim();
120
- if (!val || val === "\"\"" || val === "''") emptyKeys.push(trimmed.slice(0, eq).trim());
121
- }
122
- if (emptyKeys.length > 0) return {
123
- name: ".env file",
124
- status: "warn",
125
- message: `${keys.length} key(s) declared, ${emptyKeys.length} empty: ${emptyKeys.join(", ")}`,
126
- fix: "Fill in the empty values in your .env file"
127
- };
128
- return {
129
- name: ".env file",
130
- status: "pass",
131
- message: `${keys.length} key(s) declared`
132
- };
133
- } catch {
134
- return {
135
- name: ".env file",
136
- status: "fail",
137
- message: "Failed to read .env file"
138
- };
139
- }
140
- }
141
- async function checkPortAvailable(port) {
142
- if (await new Promise((resolve) => {
143
- const server = net.createServer();
144
- server.once("error", () => resolve(false));
145
- server.once("listening", () => {
146
- server.close(() => resolve(true));
147
- });
148
- server.listen(port, "127.0.0.1");
149
- })) return {
150
- name: "Port",
151
- status: "pass",
152
- message: `Port ${port} is available`
153
- };
154
- return {
155
- name: "Port",
156
- status: "warn",
157
- message: `Port ${port} is in use`,
158
- fix: `Use a different port: aai dev --port <number>, or stop the process using port ${port}`
159
- };
160
- }
161
- async function checkAgentSyntax(cwd) {
162
- if (!await fileExists(path.join(cwd, "agent.ts"))) return {
163
- name: "agent.ts",
164
- status: "fail",
165
- message: "agent.ts not found",
166
- fix: "Run `aai init` to scaffold a new agent project"
167
- };
168
- try {
169
- await loadAgentDef(cwd);
170
- return {
171
- name: "agent.ts",
172
- status: "pass",
173
- message: "Valid agent definition"
174
- };
175
- } catch (err) {
176
- return {
177
- name: "agent.ts",
178
- status: "fail",
179
- message: `Invalid: ${err instanceof Error ? err.message : String(err)}`,
180
- fix: "Check agent.ts — ensure it exports a default defineAgent() call with name, instructions, greeting, maxSteps, and tools"
181
- };
182
- }
183
- }
184
- async function _runDoctor(cwd, port, log) {
185
- log("");
186
- log(step("Doctor", "Checking environment health..."));
187
- log("");
188
- const results = [];
189
- results.push(await checkNodeVersion());
190
- results.push(await checkApiKey());
191
- results.push(await checkDependencies(cwd));
192
- results.push(await checkEnvFile(cwd));
193
- results.push(await checkPortAvailable(port));
194
- results.push(await checkAgentSyntax(cwd));
195
- for (const r of results) {
196
- log(` ${statusIcon(r.status)} ${colorize("bold", r.name)}: ${r.message}`);
197
- if (r.fix) log(colorize("dim", ` → ${r.fix}`));
198
- }
199
- log("");
200
- const fails = results.filter((r) => r.status === "fail").length;
201
- const warns = results.filter((r) => r.status === "warn").length;
202
- if (fails > 0) log(` ${FAIL} ${fails} issue(s) found. Fix them to proceed.`);
203
- else if (warns > 0) log(` ${WARN} All clear with ${warns} warning(s).`);
204
- else log(` ${PASS} Everything looks good!`);
205
- log("");
206
- if (fails > 0) process.exitCode = 1;
207
- }
208
- async function runDoctorCommand(opts) {
209
- const port = parsePort(opts.port);
210
- await runCommand(async ({ log }) => {
211
- await _runDoctor(opts.cwd, port, log);
212
- });
213
- }
214
- //#endregion
215
- export { runDoctorCommand };