@alexkroman1/aai-cli 0.12.2 → 1.0.2
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-CzbSa09n.mjs +38 -0
- package/dist/{_api-client-H4MFOr8j.mjs → _api-client-CFfjWfNa.mjs} +13 -2
- package/dist/_bundler-DgRDzBzD.mjs +137 -0
- package/dist/_config-Dv-T6uRj.mjs +77 -0
- package/dist/_dev-server-Cag4LlkI.mjs +133 -0
- package/dist/_init-DhX1a2Zb.mjs +153 -0
- package/dist/_output-BKdAJaM5.mjs +70 -0
- package/dist/_server-common-Pdb-KUSK.mjs +36 -0
- package/dist/_ui-r2t6_2eP.mjs +40 -0
- package/dist/_utils-DZo3_J_v.mjs +23 -0
- package/dist/cli.mjs +131 -88
- package/dist/delete-CaiAsY1S.mjs +33 -0
- package/dist/deploy-CmY2AtML.mjs +61 -0
- package/dist/dev-Wmola4F6.mjs +30 -0
- package/dist/init-DJQVk0Gw.mjs +154 -0
- package/dist/rolldown-runtime-DacLjcLf.mjs +14 -0
- package/dist/secret-lSaf6Uax.mjs +60 -0
- package/dist/test-DhQ4aznR.mjs +56 -0
- package/package.json +31 -11
- package/dist/_bundler-2yKukgnU.mjs +0 -125
- package/dist/_discover-a8yIuqEp.mjs +0 -220
- package/dist/_init-VzVTpJFZ.mjs +0 -56
- package/dist/_templates-CtZBILce.mjs +0 -72
- package/dist/_ui-DWGXImbO.mjs +0 -30
- package/dist/delete-BvRel3Tw.mjs +0 -34
- package/dist/deploy-CnscqVZv.mjs +0 -92
- package/dist/dev-DEZKrw8v.mjs +0 -18
- package/dist/init-BYX6pxjd.mjs +0 -114
- package/dist/secret-DLosn47q.mjs +0 -47
- package/dist/test-CYoqKJP0.mjs +0 -38
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import fs from "node:fs/promises";
|
|
6
|
-
import { consola } from "consola";
|
|
7
|
-
import { humanId } from "human-id";
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
import { createInterface } from "node:readline";
|
|
10
|
-
//#region \0rolldown/runtime.js
|
|
11
|
-
var __defProp = Object.defineProperty;
|
|
12
|
-
var __exportAll = (all, no_symbols) => {
|
|
13
|
-
let target = {};
|
|
14
|
-
for (var name in all) __defProp(target, name, {
|
|
15
|
-
get: all[name],
|
|
16
|
-
enumerable: true
|
|
17
|
-
});
|
|
18
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
19
|
-
return target;
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region _prompts.ts
|
|
23
|
-
/**
|
|
24
|
-
* Prompt the user for a password (masked input).
|
|
25
|
-
* Returns the entered string.
|
|
26
|
-
*/
|
|
27
|
-
async function askPassword(message) {
|
|
28
|
-
const rl = createInterface({
|
|
29
|
-
input: process.stdin,
|
|
30
|
-
output: process.stdout
|
|
31
|
-
});
|
|
32
|
-
process.stdout.write(`${message}: `);
|
|
33
|
-
const stdin = process.stdin;
|
|
34
|
-
const wasRaw = stdin.isRaw;
|
|
35
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
36
|
-
try {
|
|
37
|
-
return await readMasked(stdin);
|
|
38
|
-
} finally {
|
|
39
|
-
if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
|
|
40
|
-
rl.close();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function readMasked(stdin) {
|
|
44
|
-
return new Promise((resolve) => {
|
|
45
|
-
let buf = "";
|
|
46
|
-
const onData = (ch) => {
|
|
47
|
-
const c = ch.toString();
|
|
48
|
-
if (c === "\n" || c === "\r") {
|
|
49
|
-
stdin.removeListener("data", onData);
|
|
50
|
-
process.stdout.write("\n");
|
|
51
|
-
resolve(buf);
|
|
52
|
-
} else if (c === "") {
|
|
53
|
-
stdin.removeListener("data", onData);
|
|
54
|
-
process.exit(0);
|
|
55
|
-
} else if (c === "" || c === "\b") buf = buf.slice(0, -1);
|
|
56
|
-
else buf += c;
|
|
57
|
-
};
|
|
58
|
-
stdin.on("data", onData);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region _discover.ts
|
|
63
|
-
var _discover_exports = /* @__PURE__ */ __exportAll({
|
|
64
|
-
DEFAULT_DEV_SERVER: () => DEFAULT_DEV_SERVER,
|
|
65
|
-
DEFAULT_SERVER: () => DEFAULT_SERVER,
|
|
66
|
-
ensureApiKeyInEnv: () => ensureApiKeyInEnv,
|
|
67
|
-
fileExists: () => fileExists,
|
|
68
|
-
generateSlug: () => generateSlug,
|
|
69
|
-
getApiKey: () => getApiKey,
|
|
70
|
-
getServerInfo: () => getServerInfo,
|
|
71
|
-
isDevMode: () => isDevMode,
|
|
72
|
-
loadAgent: () => loadAgent,
|
|
73
|
-
readProjectConfig: () => readProjectConfig,
|
|
74
|
-
resolveCwd: () => resolveCwd,
|
|
75
|
-
resolveServerUrl: () => resolveServerUrl,
|
|
76
|
-
writeProjectConfig: () => writeProjectConfig
|
|
77
|
-
});
|
|
78
|
-
const AuthConfigSchema = z.object({ assemblyai_api_key: z.string().optional() });
|
|
79
|
-
const ProjectConfigSchema = z.object({
|
|
80
|
-
slug: z.string(),
|
|
81
|
-
serverUrl: z.string(),
|
|
82
|
-
sessionId: z.string().optional()
|
|
83
|
-
});
|
|
84
|
-
/** Resolve the working directory from INIT_CWD or process.cwd(). */
|
|
85
|
-
function resolveCwd() {
|
|
86
|
-
return process.env.INIT_CWD || process.cwd();
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Generates a human-readable slug using human-id.
|
|
90
|
-
*/
|
|
91
|
-
function generateSlug() {
|
|
92
|
-
return humanId({
|
|
93
|
-
separator: "-",
|
|
94
|
-
capitalize: false
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
const CONFIG_DIR = path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".config", "aai");
|
|
98
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
99
|
-
async function readAuthConfig() {
|
|
100
|
-
try {
|
|
101
|
-
return AuthConfigSchema.parse(JSON.parse(await fs.readFile(CONFIG_FILE, "utf-8")));
|
|
102
|
-
} catch (error) {
|
|
103
|
-
consola.debug(`Failed to read auth config from ${CONFIG_FILE}:`, error);
|
|
104
|
-
return {};
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async function writeAuthConfig(config) {
|
|
108
|
-
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
109
|
-
await fs.writeFile(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\n`);
|
|
110
|
-
if (process.platform !== "win32") await fs.chmod(CONFIG_FILE, 384);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Retrieves the AssemblyAI API key from `process.env`, `~/.config/aai/config.json`,
|
|
114
|
-
* or by interactively prompting the user (persisting it to config).
|
|
115
|
-
*
|
|
116
|
-
* Does NOT mutate `process.env`. Callers that need the key available in the
|
|
117
|
-
* environment for child processes should use {@link ensureApiKeyInEnv} instead.
|
|
118
|
-
*/
|
|
119
|
-
async function getApiKey() {
|
|
120
|
-
if (process.env.ASSEMBLYAI_API_KEY) return process.env.ASSEMBLYAI_API_KEY;
|
|
121
|
-
const config = await readAuthConfig();
|
|
122
|
-
if (config.assemblyai_api_key) return config.assemblyai_api_key;
|
|
123
|
-
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
124
|
-
log.info("Get your API key at https://www.assemblyai.com/dashboard/signup");
|
|
125
|
-
log.info("Or set the ASSEMBLYAI_API_KEY environment variable to skip this prompt.");
|
|
126
|
-
let key;
|
|
127
|
-
while (!key) key = await askPassword("ASSEMBLYAI_API_KEY");
|
|
128
|
-
config.assemblyai_api_key = key;
|
|
129
|
-
await writeAuthConfig(config);
|
|
130
|
-
return key;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Resolves the API key via {@link getApiKey} and sets it on `process.env.ASSEMBLYAI_API_KEY`
|
|
134
|
-
* so that child processes and downstream code can read it from the environment.
|
|
135
|
-
*/
|
|
136
|
-
async function ensureApiKeyInEnv() {
|
|
137
|
-
const key = await getApiKey();
|
|
138
|
-
process.env.ASSEMBLYAI_API_KEY = key;
|
|
139
|
-
return key;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Reads `.aai/project.json` from an agent directory.
|
|
143
|
-
* Returns null if the file doesn't exist.
|
|
144
|
-
*/
|
|
145
|
-
async function readProjectConfig(agentDir) {
|
|
146
|
-
try {
|
|
147
|
-
return ProjectConfigSchema.parse(JSON.parse(await fs.readFile(path.join(agentDir, ".aai", "project.json"), "utf-8")));
|
|
148
|
-
} catch (error) {
|
|
149
|
-
consola.debug(`Failed to read project config from ${path.join(agentDir, ".aai", "project.json")}:`, error);
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Writes `.aai/project.json` to an agent directory.
|
|
155
|
-
*/
|
|
156
|
-
async function writeProjectConfig(agentDir, data) {
|
|
157
|
-
const aaiDir = path.join(agentDir, ".aai");
|
|
158
|
-
await fs.mkdir(aaiDir, { recursive: true });
|
|
159
|
-
await fs.writeFile(path.join(aaiDir, "project.json"), `${JSON.stringify(data, null, 2)}\n`);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Read project config (throws if missing), resolve API key and server URL.
|
|
163
|
-
* Shared by secret commands.
|
|
164
|
-
*/
|
|
165
|
-
async function getServerInfo(cwd, explicitServer, explicitApiKey) {
|
|
166
|
-
const config = await readProjectConfig(cwd);
|
|
167
|
-
if (!config) throw new Error("No .aai/project.json found — run `aai deploy` first");
|
|
168
|
-
const apiKey = explicitApiKey ?? await getApiKey();
|
|
169
|
-
return {
|
|
170
|
-
serverUrl: resolveServerUrl(explicitServer, config.serverUrl),
|
|
171
|
-
slug: config.slug,
|
|
172
|
-
apiKey
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
/** Default production server URL for agent deployments. */
|
|
176
|
-
const DEFAULT_SERVER = "https://aai-agent.fly.dev";
|
|
177
|
-
/** Default local dev server URL. */
|
|
178
|
-
const DEFAULT_DEV_SERVER = "http://localhost:8787";
|
|
179
|
-
/** Check if the CLI is running from the monorepo (dev mode). */
|
|
180
|
-
function isDevMode() {
|
|
181
|
-
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
182
|
-
const root1 = path.resolve(cliDir, "../..");
|
|
183
|
-
const root2 = path.resolve(cliDir, "../../..");
|
|
184
|
-
return existsSync(path.join(root1, "pnpm-workspace.yaml")) || existsSync(path.join(root2, "pnpm-workspace.yaml"));
|
|
185
|
-
}
|
|
186
|
-
/** Resolve the server URL from an explicit value, project config, or default. */
|
|
187
|
-
function resolveServerUrl(explicit, configUrl) {
|
|
188
|
-
if (explicit) return explicit;
|
|
189
|
-
if (isDevMode()) return DEFAULT_DEV_SERVER;
|
|
190
|
-
return configUrl ?? "https://aai-agent.fly.dev";
|
|
191
|
-
}
|
|
192
|
-
async function fileExists(p) {
|
|
193
|
-
try {
|
|
194
|
-
await fs.access(p);
|
|
195
|
-
return true;
|
|
196
|
-
} catch (error) {
|
|
197
|
-
consola.debug(`File access check failed for ${p}:`, error);
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Loads agent metadata from a directory by checking for `agent.ts` and
|
|
203
|
-
* resolving the client entry point.
|
|
204
|
-
*
|
|
205
|
-
* Env vars for deployed agents are managed on the server via
|
|
206
|
-
* `aai secret put`. For local dev, `.env` is loaded by `resolveServerEnv`.
|
|
207
|
-
*/
|
|
208
|
-
async function loadAgent(dir) {
|
|
209
|
-
if (!await fileExists(path.join(dir, "agent.ts"))) return null;
|
|
210
|
-
const slug = (await readProjectConfig(dir))?.slug ?? generateSlug();
|
|
211
|
-
const clientEntry = await fileExists(path.join(dir, "client.tsx")) ? path.join(dir, "client.tsx") : "";
|
|
212
|
-
return {
|
|
213
|
-
slug,
|
|
214
|
-
dir,
|
|
215
|
-
entryPoint: path.join(dir, "agent.ts"),
|
|
216
|
-
clientEntry
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
//#endregion
|
|
220
|
-
export { getApiKey as a, readProjectConfig as c, writeProjectConfig as d, askPassword as f, generateSlug as i, resolveCwd as l, ensureApiKeyInEnv as n, getServerInfo as o, fileExists as r, isDevMode as s, _discover_exports as t, resolveServerUrl as u };
|
package/dist/_init-VzVTpJFZ.mjs
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { t as downloadAndMergeTemplate } from "./_templates-CtZBILce.mjs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
|
-
//#region _init.ts
|
|
6
|
-
async function runInit(opts) {
|
|
7
|
-
const { targetDir, template } = opts;
|
|
8
|
-
await downloadAndMergeTemplate(template, targetDir);
|
|
9
|
-
try {
|
|
10
|
-
await fs.copyFile(path.join(targetDir, ".env.example"), path.join(targetDir, ".env"));
|
|
11
|
-
} catch {}
|
|
12
|
-
const readmePath = path.join(targetDir, "README.md");
|
|
13
|
-
const readme = `# ${path.basename(path.resolve(targetDir))}
|
|
14
|
-
|
|
15
|
-
A voice agent built with [aai](https://github.com/anthropics/aai).
|
|
16
|
-
|
|
17
|
-
## Getting started
|
|
18
|
-
|
|
19
|
-
\`\`\`sh
|
|
20
|
-
npm install # Install dependencies
|
|
21
|
-
aai dev # Run locally (opens browser)
|
|
22
|
-
aai deploy # Deploy to production
|
|
23
|
-
\`\`\`
|
|
24
|
-
|
|
25
|
-
## Secrets
|
|
26
|
-
|
|
27
|
-
Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
28
|
-
|
|
29
|
-
**Local development** — add secrets to \`.env\` (auto-loaded by \`aai dev\`):
|
|
30
|
-
|
|
31
|
-
\`\`\`sh
|
|
32
|
-
ALPHA_VANTAGE_KEY=sk-abc123
|
|
33
|
-
MY_API_KEY=secret-value
|
|
34
|
-
\`\`\`
|
|
35
|
-
|
|
36
|
-
**Production** — set secrets on the server:
|
|
37
|
-
|
|
38
|
-
\`\`\`sh
|
|
39
|
-
aai secret put MY_KEY # Set a secret (prompts for value)
|
|
40
|
-
aai secret list # List secret names
|
|
41
|
-
aai secret delete MY_KEY # Remove a secret
|
|
42
|
-
\`\`\`
|
|
43
|
-
|
|
44
|
-
## Learn more
|
|
45
|
-
|
|
46
|
-
See \`CLAUDE.md\` for the full agent API reference.
|
|
47
|
-
`;
|
|
48
|
-
try {
|
|
49
|
-
await fs.writeFile(readmePath, readme, { flag: "wx" });
|
|
50
|
-
} catch (err) {
|
|
51
|
-
if (!(err instanceof Error && "code" in err && err.code === "EEXIST")) throw err;
|
|
52
|
-
}
|
|
53
|
-
return targetDir;
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
|
-
export { runInit };
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { s as isDevMode } from "./_discover-a8yIuqEp.mjs";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import fs from "node:fs/promises";
|
|
7
|
-
import { downloadTemplate } from "giget";
|
|
8
|
-
//#region _templates.ts
|
|
9
|
-
const GIGET_SOURCE = "github:alexkroman/agent/packages/aai-templates";
|
|
10
|
-
const GIGET_REF = process.env.AAI_TEMPLATES_REF ?? "main";
|
|
11
|
-
/** Resolve the local aai-templates package directory (dev mode only). */
|
|
12
|
-
function resolveLocalTemplatesDir() {
|
|
13
|
-
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
const fromSrc = path.resolve(cliDir, "../aai-templates");
|
|
15
|
-
const fromDist = path.resolve(cliDir, "../../aai-templates");
|
|
16
|
-
if (existsSync(fromSrc)) return fromSrc;
|
|
17
|
-
if (existsSync(fromDist)) return fromDist;
|
|
18
|
-
throw new Error("Cannot find local aai-templates package");
|
|
19
|
-
}
|
|
20
|
-
/** Resolve the templates directory — local in dev, giget download in prod. */
|
|
21
|
-
async function resolveTemplatesDir() {
|
|
22
|
-
if (isDevMode()) return resolveLocalTemplatesDir();
|
|
23
|
-
const { dir } = await downloadTemplate(`${GIGET_SOURCE}#${GIGET_REF}`, { force: true });
|
|
24
|
-
return dir;
|
|
25
|
-
}
|
|
26
|
-
/** List available templates with descriptions. */
|
|
27
|
-
async function listTemplates() {
|
|
28
|
-
const root = await resolveTemplatesDir();
|
|
29
|
-
const dir = path.join(root, "templates");
|
|
30
|
-
const names = (await fs.readdir(dir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort((a, b) => a.localeCompare(b));
|
|
31
|
-
let descriptions = {};
|
|
32
|
-
try {
|
|
33
|
-
descriptions = JSON.parse(await fs.readFile(path.join(root, "templates.json"), "utf-8"));
|
|
34
|
-
} catch {}
|
|
35
|
-
return names.map((name) => ({
|
|
36
|
-
name,
|
|
37
|
-
description: descriptions[name] ?? ""
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Download a template into targetDir, merging scaffold files underneath.
|
|
42
|
-
*/
|
|
43
|
-
async function downloadAndMergeTemplate(template, targetDir) {
|
|
44
|
-
const root = await resolveTemplatesDir();
|
|
45
|
-
const templatesDir = path.join(root, "templates");
|
|
46
|
-
const names = (await fs.readdir(templatesDir, { withFileTypes: true })).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)) {
|
|
54
|
-
const entries = await fs.readdir(scaffoldDir, {
|
|
55
|
-
recursive: true,
|
|
56
|
-
withFileTypes: true
|
|
57
|
-
});
|
|
58
|
-
for (const entry of entries) {
|
|
59
|
-
if (!entry.isFile()) continue;
|
|
60
|
-
const rel = path.relative(scaffoldDir, path.join(entry.parentPath, entry.name));
|
|
61
|
-
const destPath = path.join(targetDir, rel);
|
|
62
|
-
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
63
|
-
try {
|
|
64
|
-
await fs.copyFile(path.join(scaffoldDir, rel), destPath, fs.constants.COPYFILE_EXCL);
|
|
65
|
-
} catch (err) {
|
|
66
|
-
if (!(err instanceof Error && "code" in err && err.code === "EEXIST")) throw err;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
export { listTemplates as n, downloadAndMergeTemplate as t };
|
package/dist/_ui-DWGXImbO.mjs
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import * as p from "@clack/prompts";
|
|
3
|
-
import { colorize } from "consola/utils";
|
|
4
|
-
//#region _ui.ts
|
|
5
|
-
/**
|
|
6
|
-
* Unified CLI output using @clack/prompts style (◐ ◇ │).
|
|
7
|
-
*
|
|
8
|
-
* All commands should use these helpers instead of consola directly
|
|
9
|
-
* so the output is visually consistent.
|
|
10
|
-
*/
|
|
11
|
-
const log = {
|
|
12
|
-
step: (msg) => p.log.step(msg),
|
|
13
|
-
success: (msg) => p.log.success(msg),
|
|
14
|
-
info: (msg) => p.log.info(msg),
|
|
15
|
-
warn: (msg) => p.log.warn(msg),
|
|
16
|
-
error: (msg) => p.log.error(msg),
|
|
17
|
-
message: (msg) => p.log.message(msg)
|
|
18
|
-
};
|
|
19
|
-
/** Format a URL for display. */
|
|
20
|
-
function fmtUrl(url) {
|
|
21
|
-
return colorize("cyanBright", url);
|
|
22
|
-
}
|
|
23
|
-
/** Parse and validate a port string. Returns the numeric port or throws. */
|
|
24
|
-
function parsePort(raw) {
|
|
25
|
-
const port = Number.parseInt(raw, 10);
|
|
26
|
-
if (Number.isNaN(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
|
|
27
|
-
return port;
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { fmtUrl, log, parsePort };
|
package/dist/delete-BvRel3Tw.mjs
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { o as getServerInfo } from "./_discover-a8yIuqEp.mjs";
|
|
3
|
-
import { log } from "./_ui-DWGXImbO.mjs";
|
|
4
|
-
import { n as apiError, r as apiRequest, t as HINT_INVALID_API_KEY } from "./_api-client-H4MFOr8j.mjs";
|
|
5
|
-
//#region _delete.ts
|
|
6
|
-
async function runDelete(opts) {
|
|
7
|
-
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
8
|
-
const resp = await apiRequest(`${opts.url}/${opts.slug}`, {
|
|
9
|
-
method: "DELETE",
|
|
10
|
-
apiKey: opts.apiKey,
|
|
11
|
-
action: "delete"
|
|
12
|
-
}, fetchFn);
|
|
13
|
-
if (resp.ok) return;
|
|
14
|
-
const text = await resp.text();
|
|
15
|
-
let hint;
|
|
16
|
-
if (resp.status === 401) hint = HINT_INVALID_API_KEY;
|
|
17
|
-
else if (resp.status === 404) hint = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
|
|
18
|
-
throw apiError("delete", resp.status, text, hint);
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
|
-
//#region delete.ts
|
|
22
|
-
async function runDeleteCommand(opts) {
|
|
23
|
-
const { cwd } = opts;
|
|
24
|
-
const { serverUrl, slug, apiKey } = await getServerInfo(cwd, opts.server);
|
|
25
|
-
log.step(`Deleting ${slug}`);
|
|
26
|
-
await runDelete({
|
|
27
|
-
url: serverUrl,
|
|
28
|
-
slug,
|
|
29
|
-
apiKey
|
|
30
|
-
});
|
|
31
|
-
log.success(`Deleted ${serverUrl}/${slug}`);
|
|
32
|
-
}
|
|
33
|
-
//#endregion
|
|
34
|
-
export { runDeleteCommand };
|
package/dist/deploy-CnscqVZv.mjs
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { a as getApiKey, c as readProjectConfig, d as writeProjectConfig, i as generateSlug, u as resolveServerUrl } from "./_discover-a8yIuqEp.mjs";
|
|
3
|
-
import { buildAgentBundle } from "./_bundler-2yKukgnU.mjs";
|
|
4
|
-
import { fmtUrl, log } from "./_ui-DWGXImbO.mjs";
|
|
5
|
-
import { n as apiError, r as apiRequest, t as HINT_INVALID_API_KEY } from "./_api-client-H4MFOr8j.mjs";
|
|
6
|
-
//#region _deploy.ts
|
|
7
|
-
const MAX_SLUG_RETRIES = 20;
|
|
8
|
-
async function attempt(fetchFn, url, slug, body, apiKey) {
|
|
9
|
-
const resp = await apiRequest(`${url}/${slug}/deploy`, {
|
|
10
|
-
method: "POST",
|
|
11
|
-
body,
|
|
12
|
-
apiKey,
|
|
13
|
-
action: "deploy"
|
|
14
|
-
}, fetchFn);
|
|
15
|
-
if (resp.ok) return {
|
|
16
|
-
ok: true,
|
|
17
|
-
slug
|
|
18
|
-
};
|
|
19
|
-
const text = await resp.text();
|
|
20
|
-
if (resp.status === 403 && text.includes("owned by another")) return {
|
|
21
|
-
ok: false,
|
|
22
|
-
retry: true
|
|
23
|
-
};
|
|
24
|
-
let hint;
|
|
25
|
-
if (resp.status === 401) hint = HINT_INVALID_API_KEY;
|
|
26
|
-
else if (resp.status === 403 && text.includes("Slug")) hint = "This slug is already taken. Set a different slug in .aai/project.json.";
|
|
27
|
-
else if (resp.status === 413) hint = "Your bundle is too large. Try reducing dependencies or splitting your agent.";
|
|
28
|
-
return {
|
|
29
|
-
ok: false,
|
|
30
|
-
retry: false,
|
|
31
|
-
error: apiError("deploy", resp.status, text, hint).message
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
async function runDeploy(opts) {
|
|
35
|
-
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
36
|
-
const body = JSON.stringify({
|
|
37
|
-
env: opts.env,
|
|
38
|
-
worker: opts.bundle.worker,
|
|
39
|
-
clientFiles: opts.bundle.clientFiles
|
|
40
|
-
});
|
|
41
|
-
let slug = opts.slug;
|
|
42
|
-
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
43
|
-
const result = await attempt(fetchFn, opts.url, slug, body, opts.apiKey);
|
|
44
|
-
if (result.ok) return { slug: result.slug };
|
|
45
|
-
if (!result.retry) throw new Error(result.error);
|
|
46
|
-
slug = generateSlug();
|
|
47
|
-
}
|
|
48
|
-
throw new Error(`Could not find an available slug after ${MAX_SLUG_RETRIES} attempts. Set one manually in .aai/project.json.`);
|
|
49
|
-
}
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region deploy.ts
|
|
52
|
-
async function deployBundle(opts) {
|
|
53
|
-
const { bundle, serverUrl, apiKey, cwd } = opts;
|
|
54
|
-
let { slug } = opts;
|
|
55
|
-
log.step(`Deploying ${slug}`);
|
|
56
|
-
slug = (await runDeploy({
|
|
57
|
-
url: serverUrl,
|
|
58
|
-
bundle,
|
|
59
|
-
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
60
|
-
slug,
|
|
61
|
-
apiKey
|
|
62
|
-
})).slug;
|
|
63
|
-
await writeProjectConfig(cwd, {
|
|
64
|
-
slug,
|
|
65
|
-
serverUrl
|
|
66
|
-
});
|
|
67
|
-
const agentUrl = `${serverUrl}/${slug}`;
|
|
68
|
-
log.success(`Deployed ${fmtUrl(agentUrl)}`);
|
|
69
|
-
return agentUrl;
|
|
70
|
-
}
|
|
71
|
-
async function runDeployCommand(opts) {
|
|
72
|
-
const { cwd } = opts;
|
|
73
|
-
const dryRun = opts.dryRun ?? false;
|
|
74
|
-
const apiKey = dryRun ? "" : await getApiKey();
|
|
75
|
-
const projectConfig = await readProjectConfig(cwd);
|
|
76
|
-
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
77
|
-
const bundle = await buildAgentBundle(cwd);
|
|
78
|
-
const slug = projectConfig?.slug ?? bundle.slug;
|
|
79
|
-
if (dryRun) {
|
|
80
|
-
log.info(`Dry run complete — would deploy as ${slug}`);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
await deployBundle({
|
|
84
|
-
bundle,
|
|
85
|
-
serverUrl,
|
|
86
|
-
apiKey,
|
|
87
|
-
slug,
|
|
88
|
-
cwd
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
//#endregion
|
|
92
|
-
export { runDeployCommand };
|
package/dist/dev-DEZKrw8v.mjs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { fmtUrl, log, parsePort } from "./_ui-DWGXImbO.mjs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { createServer } from "vite";
|
|
5
|
-
import { colorize } from "consola/utils";
|
|
6
|
-
//#region dev.ts
|
|
7
|
-
async function runDevCommand(opts) {
|
|
8
|
-
const port = parsePort(opts.port);
|
|
9
|
-
const agentName = path.basename(path.resolve(opts.cwd));
|
|
10
|
-
await (await createServer({
|
|
11
|
-
root: opts.cwd,
|
|
12
|
-
server: { port }
|
|
13
|
-
})).listen();
|
|
14
|
-
log.success(`${colorize("bold", agentName)} running at ${fmtUrl(`http://localhost:${port}`)}`);
|
|
15
|
-
log.info("Press Ctrl-C to stop");
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { runDevCommand };
|
package/dist/init-BYX6pxjd.mjs
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { l as resolveCwd, n as ensureApiKeyInEnv, r as fileExists } from "./_discover-a8yIuqEp.mjs";
|
|
3
|
-
import { n as listTemplates } from "./_templates-CtZBILce.mjs";
|
|
4
|
-
import { log } from "./_ui-DWGXImbO.mjs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import fs from "node:fs/promises";
|
|
7
|
-
import { errorMessage } from "@alexkroman1/aai/utils";
|
|
8
|
-
import * as p from "@clack/prompts";
|
|
9
|
-
import { colorize } from "consola/utils";
|
|
10
|
-
import { execFile } from "node:child_process";
|
|
11
|
-
import { promisify } from "node:util";
|
|
12
|
-
//#region init.ts
|
|
13
|
-
const execFileAsync = promisify(execFile);
|
|
14
|
-
const DEFAULT_PROJECT_NAME = "my-voice-agent";
|
|
15
|
-
const DEFAULT_TEMPLATE = "simple";
|
|
16
|
-
/** Prompt for project name or return default when --yes is set. */
|
|
17
|
-
async function promptProjectName(yes) {
|
|
18
|
-
if (yes) return DEFAULT_PROJECT_NAME;
|
|
19
|
-
const result = await p.text({
|
|
20
|
-
message: "What is your project named?",
|
|
21
|
-
placeholder: DEFAULT_PROJECT_NAME,
|
|
22
|
-
defaultValue: DEFAULT_PROJECT_NAME
|
|
23
|
-
});
|
|
24
|
-
if (p.isCancel(result)) {
|
|
25
|
-
p.cancel("Setup cancelled");
|
|
26
|
-
process.exit(0);
|
|
27
|
-
}
|
|
28
|
-
return result || DEFAULT_PROJECT_NAME;
|
|
29
|
-
}
|
|
30
|
-
/** Prompt for template selection or return default when --yes is set. */
|
|
31
|
-
async function promptTemplate(yes) {
|
|
32
|
-
if (yes) return DEFAULT_TEMPLATE;
|
|
33
|
-
const templates = await listTemplates();
|
|
34
|
-
const result = await p.select({
|
|
35
|
-
message: "Which template would you like to use?",
|
|
36
|
-
options: templates.map((t) => ({
|
|
37
|
-
value: t.name,
|
|
38
|
-
label: t.name,
|
|
39
|
-
hint: t.description
|
|
40
|
-
})),
|
|
41
|
-
initialValue: DEFAULT_TEMPLATE
|
|
42
|
-
});
|
|
43
|
-
if (p.isCancel(result)) {
|
|
44
|
-
p.cancel("Setup cancelled");
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
/** Enable corepack so pnpm is available (scaffold declares packageManager: pnpm). */
|
|
50
|
-
async function ensurePnpm() {
|
|
51
|
-
try {
|
|
52
|
-
await execFileAsync("corepack", ["enable"]);
|
|
53
|
-
} catch {}
|
|
54
|
-
}
|
|
55
|
-
/** Install deps with pnpm (scaffold declares packageManager: pnpm). */
|
|
56
|
-
async function installDeps(cwd) {
|
|
57
|
-
if (await fileExists(path.join(cwd, "node_modules"))) return;
|
|
58
|
-
let pkgJson;
|
|
59
|
-
try {
|
|
60
|
-
pkgJson = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8"));
|
|
61
|
-
} catch {
|
|
62
|
-
pkgJson = {};
|
|
63
|
-
}
|
|
64
|
-
const deps = Object.keys(pkgJson.dependencies ?? {});
|
|
65
|
-
const devDeps = Object.keys(pkgJson.devDependencies ?? {});
|
|
66
|
-
if (deps.length === 0 && devDeps.length === 0) return;
|
|
67
|
-
await ensurePnpm();
|
|
68
|
-
const s = p.spinner();
|
|
69
|
-
s.start("Installing dependencies with pnpm");
|
|
70
|
-
try {
|
|
71
|
-
await execFileAsync("pnpm", ["install", "--ignore-workspace"], { cwd });
|
|
72
|
-
s.stop("Dependencies installed");
|
|
73
|
-
} catch (err) {
|
|
74
|
-
const msg = errorMessage(err);
|
|
75
|
-
s.stop("Dependency install failed");
|
|
76
|
-
log.warn(`pnpm install failed: ${msg}`);
|
|
77
|
-
log.warn("Run `corepack enable && pnpm install` manually in the project directory.");
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/** Format the dev command for the "Next steps" note. */
|
|
81
|
-
function devCommand() {
|
|
82
|
-
return "aai dev";
|
|
83
|
-
}
|
|
84
|
-
async function runInitCommand(opts, extra) {
|
|
85
|
-
if (!extra?.quiet) p.intro(colorize("cyanBright", "Create a new voice agent"));
|
|
86
|
-
if (!opts.skipApi) await ensureApiKeyInEnv();
|
|
87
|
-
const dir = opts.dir ?? await promptProjectName(opts.yes);
|
|
88
|
-
const cwd = path.resolve(resolveCwd(), dir);
|
|
89
|
-
if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`agent.ts already exists in this directory. Use ${colorize("cyanBright", "--force")} to overwrite.`);
|
|
90
|
-
const template = opts.template ?? await promptTemplate(opts.yes);
|
|
91
|
-
const s = p.spinner();
|
|
92
|
-
s.start(`Creating ${dir} from ${template} template`);
|
|
93
|
-
const { runInit } = await import("./_init-VzVTpJFZ.mjs");
|
|
94
|
-
await runInit({
|
|
95
|
-
targetDir: cwd,
|
|
96
|
-
template
|
|
97
|
-
});
|
|
98
|
-
s.stop("Project created");
|
|
99
|
-
await installDeps(cwd);
|
|
100
|
-
if (!(opts.skipDeploy || extra?.quiet)) {
|
|
101
|
-
const { runDeployCommand } = await import("./deploy-CnscqVZv.mjs");
|
|
102
|
-
await runDeployCommand({
|
|
103
|
-
cwd,
|
|
104
|
-
...opts.server ? { server: opts.server } : {}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
if (!extra?.quiet) {
|
|
108
|
-
log.success(`Created ${dir}`);
|
|
109
|
-
log.info(`Next: cd ${dir} && ${devCommand()}`);
|
|
110
|
-
}
|
|
111
|
-
return cwd;
|
|
112
|
-
}
|
|
113
|
-
//#endregion
|
|
114
|
-
export { runInitCommand };
|
package/dist/secret-DLosn47q.mjs
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { f as askPassword, o as getServerInfo } from "./_discover-a8yIuqEp.mjs";
|
|
3
|
-
import { log } from "./_ui-DWGXImbO.mjs";
|
|
4
|
-
//#region secret.ts
|
|
5
|
-
async function apiFetch(cwd, pathSuffix, init) {
|
|
6
|
-
const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
|
|
7
|
-
const resp = await fetch(`${serverUrl}/${slug}/secret${pathSuffix}`, {
|
|
8
|
-
...init,
|
|
9
|
-
headers: {
|
|
10
|
-
Authorization: `Bearer ${apiKey}`,
|
|
11
|
-
...init?.headers
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
if (!resp.ok) {
|
|
15
|
-
const text = await resp.text();
|
|
16
|
-
throw new Error(`Secret operation failed: ${text}`);
|
|
17
|
-
}
|
|
18
|
-
return {
|
|
19
|
-
resp,
|
|
20
|
-
slug
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
async function runSecretPut(cwd, name) {
|
|
24
|
-
const value = await askPassword(`Enter value for ${name}`);
|
|
25
|
-
if (!value) throw new Error("No value provided");
|
|
26
|
-
const { slug } = await apiFetch(cwd, "", {
|
|
27
|
-
method: "PUT",
|
|
28
|
-
headers: { "Content-Type": "application/json" },
|
|
29
|
-
body: JSON.stringify({ [name]: value })
|
|
30
|
-
});
|
|
31
|
-
log.success(`Set ${name} for ${slug}`);
|
|
32
|
-
}
|
|
33
|
-
async function runSecretDelete(cwd, name) {
|
|
34
|
-
const { slug } = await apiFetch(cwd, `/${name}`, { method: "DELETE" });
|
|
35
|
-
log.success(`Deleted ${name} from ${slug}`);
|
|
36
|
-
}
|
|
37
|
-
async function runSecretList(cwd) {
|
|
38
|
-
const { resp } = await apiFetch(cwd, "");
|
|
39
|
-
const { vars } = await resp.json();
|
|
40
|
-
if (vars.length === 0) log.info("No secrets set. Use `aai secret put <name>` to add one.");
|
|
41
|
-
else {
|
|
42
|
-
log.message(`${vars.length} secret${vars.length === 1 ? "" : "s"}:`);
|
|
43
|
-
for (const name of vars) log.message(` ${name}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
export { runSecretDelete, runSecretList, runSecretPut };
|