@alexkroman1/aai-cli 0.12.1 → 0.12.3
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/{_bundler-2yKukgnU.mjs → _bundler-DQtFVeww.mjs} +2 -2
- package/dist/{_discover-a8yIuqEp.mjs → _discover-DzsMlg3G.mjs} +14 -16
- package/dist/{_init-VzVTpJFZ.mjs → _init-CbMs9S2O.mjs} +1 -1
- package/dist/{_templates-CtZBILce.mjs → _templates-BDkbj3TM.mjs} +1 -1
- package/dist/cli.mjs +95 -67
- package/dist/{delete-BvRel3Tw.mjs → delete-CalIL6Pg.mjs} +1 -1
- package/dist/deploy-CLs8gLHV.mjs +53 -0
- package/dist/{init-DTfpWUv8.mjs → init-CNuntiij.mjs} +22 -21
- package/dist/secret-xmLQ96Yz.mjs +46 -0
- package/dist/{test-CYoqKJP0.mjs → test-yqHGZPF3.mjs} +8 -2
- package/package.json +12 -7
- package/dist/deploy-CnscqVZv.mjs +0 -92
- package/dist/secret-DLosn47q.mjs +0 -47
|
@@ -78,7 +78,7 @@ async function bundleAgent(agent, opts) {
|
|
|
78
78
|
} catch (err) {
|
|
79
79
|
throw new BundleError(errorMessage(err), { cause: err });
|
|
80
80
|
}
|
|
81
|
-
if (!
|
|
81
|
+
if (!opts?.skipClient && agent.clientEntry) try {
|
|
82
82
|
await build({
|
|
83
83
|
root: agent.dir,
|
|
84
84
|
base: "./",
|
|
@@ -102,7 +102,7 @@ async function bundleAgent(agent, opts) {
|
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
104
|
async function buildAgentBundle(cwd) {
|
|
105
|
-
const { loadAgent } = await import("./_discover-
|
|
105
|
+
const { loadAgent } = await import("./_discover-DzsMlg3G.mjs").then((n) => n.t);
|
|
106
106
|
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
107
107
|
const agent = await loadAgent(cwd);
|
|
108
108
|
if (!agent) throw new Error("No agent found — run `aai init` first");
|
|
@@ -3,8 +3,9 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import ci from "ci-info";
|
|
6
8
|
import { consola } from "consola";
|
|
7
|
-
import { humanId } from "human-id";
|
|
8
9
|
import { z } from "zod";
|
|
9
10
|
import { createInterface } from "node:readline";
|
|
10
11
|
//#region \0rolldown/runtime.js
|
|
@@ -22,9 +23,10 @@ var __exportAll = (all, no_symbols) => {
|
|
|
22
23
|
//#region _prompts.ts
|
|
23
24
|
/**
|
|
24
25
|
* Prompt the user for a password (masked input).
|
|
25
|
-
*
|
|
26
|
+
* Throws in CI or non-TTY environments instead of hanging.
|
|
26
27
|
*/
|
|
27
28
|
async function askPassword(message) {
|
|
29
|
+
if (ci.isCI || !process.stdin.isTTY) throw new Error(`Interactive prompt requires a terminal. Set ${message} as an environment variable in CI.`);
|
|
28
30
|
const rl = createInterface({
|
|
29
31
|
input: process.stdin,
|
|
30
32
|
output: process.stdout
|
|
@@ -32,11 +34,11 @@ async function askPassword(message) {
|
|
|
32
34
|
process.stdout.write(`${message}: `);
|
|
33
35
|
const stdin = process.stdin;
|
|
34
36
|
const wasRaw = stdin.isRaw;
|
|
35
|
-
|
|
37
|
+
stdin.setRawMode(true);
|
|
36
38
|
try {
|
|
37
39
|
return await readMasked(stdin);
|
|
38
40
|
} finally {
|
|
39
|
-
|
|
41
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
40
42
|
rl.close();
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -65,8 +67,8 @@ var _discover_exports = /* @__PURE__ */ __exportAll({
|
|
|
65
67
|
DEFAULT_SERVER: () => DEFAULT_SERVER,
|
|
66
68
|
ensureApiKeyInEnv: () => ensureApiKeyInEnv,
|
|
67
69
|
fileExists: () => fileExists,
|
|
68
|
-
generateSlug: () => generateSlug,
|
|
69
70
|
getApiKey: () => getApiKey,
|
|
71
|
+
getConfigDir: () => getConfigDir,
|
|
70
72
|
getServerInfo: () => getServerInfo,
|
|
71
73
|
isDevMode: () => isDevMode,
|
|
72
74
|
loadAgent: () => loadAgent,
|
|
@@ -85,16 +87,11 @@ const ProjectConfigSchema = z.object({
|
|
|
85
87
|
function resolveCwd() {
|
|
86
88
|
return process.env.INIT_CWD || process.cwd();
|
|
87
89
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
function generateSlug() {
|
|
92
|
-
return humanId({
|
|
93
|
-
separator: "-",
|
|
94
|
-
capitalize: false
|
|
95
|
-
});
|
|
90
|
+
function getConfigDir() {
|
|
91
|
+
if (process.platform === "win32") return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "aai");
|
|
92
|
+
return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"), "aai");
|
|
96
93
|
}
|
|
97
|
-
const CONFIG_DIR =
|
|
94
|
+
const CONFIG_DIR = getConfigDir();
|
|
98
95
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
99
96
|
async function readAuthConfig() {
|
|
100
97
|
try {
|
|
@@ -120,6 +117,7 @@ async function getApiKey() {
|
|
|
120
117
|
if (process.env.ASSEMBLYAI_API_KEY) return process.env.ASSEMBLYAI_API_KEY;
|
|
121
118
|
const config = await readAuthConfig();
|
|
122
119
|
if (config.assemblyai_api_key) return config.assemblyai_api_key;
|
|
120
|
+
if (ci.isCI || !process.stdin.isTTY) throw new Error("No ASSEMBLYAI_API_KEY found. Set the ASSEMBLYAI_API_KEY environment variable in CI or non-interactive environments.");
|
|
123
121
|
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
124
122
|
log.info("Get your API key at https://www.assemblyai.com/dashboard/signup");
|
|
125
123
|
log.info("Or set the ASSEMBLYAI_API_KEY environment variable to skip this prompt.");
|
|
@@ -207,7 +205,7 @@ async function fileExists(p) {
|
|
|
207
205
|
*/
|
|
208
206
|
async function loadAgent(dir) {
|
|
209
207
|
if (!await fileExists(path.join(dir, "agent.ts"))) return null;
|
|
210
|
-
const slug = (await readProjectConfig(dir))?.slug ??
|
|
208
|
+
const slug = (await readProjectConfig(dir))?.slug ?? "";
|
|
211
209
|
const clientEntry = await fileExists(path.join(dir, "client.tsx")) ? path.join(dir, "client.tsx") : "";
|
|
212
210
|
return {
|
|
213
211
|
slug,
|
|
@@ -217,4 +215,4 @@ async function loadAgent(dir) {
|
|
|
217
215
|
};
|
|
218
216
|
}
|
|
219
217
|
//#endregion
|
|
220
|
-
export {
|
|
218
|
+
export { getServerInfo as a, resolveCwd as c, askPassword as d, getApiKey as i, resolveServerUrl as l, ensureApiKeyInEnv as n, isDevMode as o, fileExists as r, readProjectConfig as s, _discover_exports as t, writeProjectConfig as u };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { c as resolveCwd, n as ensureApiKeyInEnv, r as fileExists } from "./_discover-DzsMlg3G.mjs";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -35,7 +35,7 @@ function findPkgJson(dir) {
|
|
|
35
35
|
const VERSION = JSON.parse(findPkgJson(cliDir)).version;
|
|
36
36
|
async function ensureAgent(cwd, yes) {
|
|
37
37
|
if (!await fileExists(path.join(cwd, "agent.ts"))) {
|
|
38
|
-
const { runInitCommand } = await import("./init-
|
|
38
|
+
const { runInitCommand } = await import("./init-CNuntiij.mjs");
|
|
39
39
|
return runInitCommand({ yes }, { quiet: true });
|
|
40
40
|
}
|
|
41
41
|
return cwd;
|
|
@@ -47,6 +47,16 @@ async function setup(args, opts) {
|
|
|
47
47
|
if (opts?.apiKey) await ensureApiKeyInEnv();
|
|
48
48
|
return cwd;
|
|
49
49
|
}
|
|
50
|
+
/** Catch command errors and display a clean message instead of a raw stack trace. */
|
|
51
|
+
async function handleErrors(fn) {
|
|
52
|
+
try {
|
|
53
|
+
await fn();
|
|
54
|
+
} catch (err) {
|
|
55
|
+
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
56
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
50
60
|
const init = defineCommand({
|
|
51
61
|
meta: {
|
|
52
62
|
name: "init",
|
|
@@ -68,6 +78,7 @@ const init = defineCommand({
|
|
|
68
78
|
alias: "f",
|
|
69
79
|
description: "Overwrite existing files"
|
|
70
80
|
},
|
|
81
|
+
server: sharedArgs.server,
|
|
71
82
|
yes: sharedArgs.yes,
|
|
72
83
|
skipApi: {
|
|
73
84
|
type: "boolean",
|
|
@@ -79,14 +90,17 @@ const init = defineCommand({
|
|
|
79
90
|
}
|
|
80
91
|
},
|
|
81
92
|
async run({ args }) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
await handleErrors(async () => {
|
|
94
|
+
const { runInitCommand } = await import("./init-CNuntiij.mjs");
|
|
95
|
+
await runInitCommand({
|
|
96
|
+
dir: args.dir,
|
|
97
|
+
template: args.template,
|
|
98
|
+
force: args.force,
|
|
99
|
+
yes: args.yes,
|
|
100
|
+
skipApi: args.skipApi,
|
|
101
|
+
skipDeploy: args.skipDeploy,
|
|
102
|
+
server: args.server
|
|
103
|
+
});
|
|
90
104
|
});
|
|
91
105
|
}
|
|
92
106
|
});
|
|
@@ -97,17 +111,20 @@ const dev = defineCommand({
|
|
|
97
111
|
},
|
|
98
112
|
args: {
|
|
99
113
|
port: sharedArgs.port,
|
|
114
|
+
server: sharedArgs.server,
|
|
100
115
|
yes: sharedArgs.yes
|
|
101
116
|
},
|
|
102
117
|
async run({ args }) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
await handleErrors(async () => {
|
|
119
|
+
const cwd = await setup(args, {
|
|
120
|
+
agent: true,
|
|
121
|
+
apiKey: true
|
|
122
|
+
});
|
|
123
|
+
const { runDevCommand } = await import("./dev-DEZKrw8v.mjs");
|
|
124
|
+
await runDevCommand({
|
|
125
|
+
cwd,
|
|
126
|
+
port: args.port
|
|
127
|
+
});
|
|
111
128
|
});
|
|
112
129
|
}
|
|
113
130
|
});
|
|
@@ -117,9 +134,11 @@ const test = defineCommand({
|
|
|
117
134
|
description: "Run agent tests"
|
|
118
135
|
},
|
|
119
136
|
async run() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
await handleErrors(async () => {
|
|
138
|
+
const cwd = await setup();
|
|
139
|
+
const { runTestCommand } = await import("./test-yqHGZPF3.mjs");
|
|
140
|
+
await runTestCommand(cwd);
|
|
141
|
+
});
|
|
123
142
|
}
|
|
124
143
|
});
|
|
125
144
|
const build = defineCommand({
|
|
@@ -128,6 +147,7 @@ const build = defineCommand({
|
|
|
128
147
|
description: "Bundle agent without deploying"
|
|
129
148
|
},
|
|
130
149
|
args: {
|
|
150
|
+
server: sharedArgs.server,
|
|
131
151
|
yes: sharedArgs.yes,
|
|
132
152
|
skipTests: {
|
|
133
153
|
type: "boolean",
|
|
@@ -135,13 +155,15 @@ const build = defineCommand({
|
|
|
135
155
|
}
|
|
136
156
|
},
|
|
137
157
|
async run({ args }) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
158
|
+
await handleErrors(async () => {
|
|
159
|
+
const cwd = await setup(args, { agent: true });
|
|
160
|
+
if (!args.skipTests) {
|
|
161
|
+
const { runVitest } = await import("./test-yqHGZPF3.mjs");
|
|
162
|
+
runVitest(cwd);
|
|
163
|
+
}
|
|
164
|
+
const { runBuildCommand } = await import("./_bundler-DQtFVeww.mjs");
|
|
165
|
+
await runBuildCommand(cwd);
|
|
166
|
+
});
|
|
145
167
|
}
|
|
146
168
|
});
|
|
147
169
|
const deploy = defineCommand({
|
|
@@ -151,26 +173,17 @@ const deploy = defineCommand({
|
|
|
151
173
|
},
|
|
152
174
|
args: {
|
|
153
175
|
server: sharedArgs.server,
|
|
154
|
-
dryRun: {
|
|
155
|
-
type: "boolean",
|
|
156
|
-
description: "Validate and bundle without deploying"
|
|
157
|
-
},
|
|
158
176
|
yes: sharedArgs.yes
|
|
159
177
|
},
|
|
160
178
|
async run({ args }) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
179
|
+
await handleErrors(async () => {
|
|
180
|
+
const cwd = await setup(args, { agent: true });
|
|
181
|
+
const { runDeployCommand } = await import("./deploy-CLs8gLHV.mjs");
|
|
164
182
|
await runDeployCommand({
|
|
165
183
|
cwd,
|
|
166
|
-
...args.server ? { server: args.server } : {}
|
|
167
|
-
...args.dryRun ? { dryRun: args.dryRun } : {}
|
|
184
|
+
...args.server ? { server: args.server } : {}
|
|
168
185
|
});
|
|
169
|
-
}
|
|
170
|
-
const { log } = await import("./_ui-DWGXImbO.mjs");
|
|
171
|
-
log.error(err instanceof Error ? err.message : String(err));
|
|
172
|
-
process.exit(1);
|
|
173
|
-
}
|
|
186
|
+
});
|
|
174
187
|
}
|
|
175
188
|
});
|
|
176
189
|
const del = defineCommand({
|
|
@@ -180,11 +193,13 @@ const del = defineCommand({
|
|
|
180
193
|
},
|
|
181
194
|
args: { server: sharedArgs.server },
|
|
182
195
|
async run({ args }) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
await handleErrors(async () => {
|
|
197
|
+
const cwd = await setup();
|
|
198
|
+
const { runDeleteCommand } = await import("./delete-CalIL6Pg.mjs");
|
|
199
|
+
await runDeleteCommand({
|
|
200
|
+
cwd,
|
|
201
|
+
...args.server ? { server: args.server } : {}
|
|
202
|
+
});
|
|
188
203
|
});
|
|
189
204
|
}
|
|
190
205
|
});
|
|
@@ -199,15 +214,20 @@ const secret = defineCommand({
|
|
|
199
214
|
name: "put",
|
|
200
215
|
description: "Create or update a secret"
|
|
201
216
|
},
|
|
202
|
-
args: {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
args: {
|
|
218
|
+
name: {
|
|
219
|
+
type: "positional",
|
|
220
|
+
description: "Secret name",
|
|
221
|
+
required: true
|
|
222
|
+
},
|
|
223
|
+
server: sharedArgs.server
|
|
224
|
+
},
|
|
207
225
|
async run({ args }) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
226
|
+
await handleErrors(async () => {
|
|
227
|
+
const cwd = await setup(void 0, { apiKey: true });
|
|
228
|
+
const { runSecretPut } = await import("./secret-xmLQ96Yz.mjs");
|
|
229
|
+
await runSecretPut(cwd, args.name, args.server);
|
|
230
|
+
});
|
|
211
231
|
}
|
|
212
232
|
}),
|
|
213
233
|
delete: defineCommand({
|
|
@@ -215,15 +235,20 @@ const secret = defineCommand({
|
|
|
215
235
|
name: "delete",
|
|
216
236
|
description: "Delete a secret"
|
|
217
237
|
},
|
|
218
|
-
args: {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
238
|
+
args: {
|
|
239
|
+
name: {
|
|
240
|
+
type: "positional",
|
|
241
|
+
description: "Secret name",
|
|
242
|
+
required: true
|
|
243
|
+
},
|
|
244
|
+
server: sharedArgs.server
|
|
245
|
+
},
|
|
223
246
|
async run({ args }) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
247
|
+
await handleErrors(async () => {
|
|
248
|
+
const cwd = await setup(void 0, { apiKey: true });
|
|
249
|
+
const { runSecretDelete } = await import("./secret-xmLQ96Yz.mjs");
|
|
250
|
+
await runSecretDelete(cwd, args.name, args.server);
|
|
251
|
+
});
|
|
227
252
|
}
|
|
228
253
|
}),
|
|
229
254
|
list: defineCommand({
|
|
@@ -231,10 +256,13 @@ const secret = defineCommand({
|
|
|
231
256
|
name: "list",
|
|
232
257
|
description: "List all secrets"
|
|
233
258
|
},
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
259
|
+
args: { server: sharedArgs.server },
|
|
260
|
+
async run({ args }) {
|
|
261
|
+
await handleErrors(async () => {
|
|
262
|
+
const cwd = await setup(void 0, { apiKey: true });
|
|
263
|
+
const { runSecretList } = await import("./secret-xmLQ96Yz.mjs");
|
|
264
|
+
await runSecretList(cwd, args.server);
|
|
265
|
+
});
|
|
238
266
|
}
|
|
239
267
|
})
|
|
240
268
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { a as getServerInfo } from "./_discover-DzsMlg3G.mjs";
|
|
3
3
|
import { log } from "./_ui-DWGXImbO.mjs";
|
|
4
4
|
import { n as apiError, r as apiRequest, t as HINT_INVALID_API_KEY } from "./_api-client-H4MFOr8j.mjs";
|
|
5
5
|
//#region _delete.ts
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as getApiKey, l as resolveServerUrl, s as readProjectConfig, u as writeProjectConfig } from "./_discover-DzsMlg3G.mjs";
|
|
3
|
+
import { buildAgentBundle } from "./_bundler-DQtFVeww.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
|
+
async function runDeploy(opts) {
|
|
8
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
9
|
+
const body = JSON.stringify({
|
|
10
|
+
...opts.slug ? { slug: opts.slug } : {},
|
|
11
|
+
env: opts.env,
|
|
12
|
+
worker: opts.bundle.worker,
|
|
13
|
+
clientFiles: opts.bundle.clientFiles
|
|
14
|
+
});
|
|
15
|
+
const resp = await apiRequest(`${opts.url}/deploy`, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
body,
|
|
18
|
+
apiKey: opts.apiKey,
|
|
19
|
+
action: "deploy"
|
|
20
|
+
}, fetchFn);
|
|
21
|
+
if (resp.ok) return { slug: (await resp.json()).slug };
|
|
22
|
+
const text = await resp.text();
|
|
23
|
+
let hint;
|
|
24
|
+
if (resp.status === 401) hint = HINT_INVALID_API_KEY;
|
|
25
|
+
else if (resp.status === 413) hint = "Your bundle is too large. Try reducing dependencies or splitting your agent.";
|
|
26
|
+
throw new Error(apiError("deploy", resp.status, text, hint).message);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region deploy.ts
|
|
30
|
+
async function runDeployCommand(opts) {
|
|
31
|
+
const { cwd } = opts;
|
|
32
|
+
const apiKey = await getApiKey();
|
|
33
|
+
const projectConfig = await readProjectConfig(cwd);
|
|
34
|
+
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
35
|
+
const bundle = await buildAgentBundle(cwd);
|
|
36
|
+
const slug = projectConfig?.slug;
|
|
37
|
+
log.step(`Deploying${slug ? ` ${slug}` : ""}…`);
|
|
38
|
+
const deployed = await runDeploy({
|
|
39
|
+
url: serverUrl,
|
|
40
|
+
bundle,
|
|
41
|
+
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
42
|
+
...slug ? { slug } : {},
|
|
43
|
+
apiKey
|
|
44
|
+
});
|
|
45
|
+
await writeProjectConfig(cwd, {
|
|
46
|
+
slug: deployed.slug,
|
|
47
|
+
serverUrl
|
|
48
|
+
});
|
|
49
|
+
const agentUrl = `${serverUrl}/${deployed.slug}`;
|
|
50
|
+
log.success(`Deployed ${fmtUrl(agentUrl)}`);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { runDeployCommand };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as listTemplates } from "./_templates-
|
|
2
|
+
import { c as resolveCwd, n as ensureApiKeyInEnv, r as fileExists } from "./_discover-DzsMlg3G.mjs";
|
|
3
|
+
import { n as listTemplates } from "./_templates-BDkbj3TM.mjs";
|
|
4
4
|
import { log } from "./_ui-DWGXImbO.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import fs from "node:fs/promises";
|
|
@@ -13,14 +13,6 @@ import { promisify } from "node:util";
|
|
|
13
13
|
const execFileAsync = promisify(execFile);
|
|
14
14
|
const DEFAULT_PROJECT_NAME = "my-voice-agent";
|
|
15
15
|
const DEFAULT_TEMPLATE = "simple";
|
|
16
|
-
/** Detect the package manager from the environment. */
|
|
17
|
-
function detectPackageManager() {
|
|
18
|
-
const ua = process.env.npm_config_user_agent ?? "";
|
|
19
|
-
if (ua.startsWith("pnpm")) return "pnpm";
|
|
20
|
-
if (ua.startsWith("yarn")) return "yarn";
|
|
21
|
-
if (ua.startsWith("bun")) return "bun";
|
|
22
|
-
return "npm";
|
|
23
|
-
}
|
|
24
16
|
/** Prompt for project name or return default when --yes is set. */
|
|
25
17
|
async function promptProjectName(yes) {
|
|
26
18
|
if (yes) return DEFAULT_PROJECT_NAME;
|
|
@@ -54,8 +46,14 @@ async function promptTemplate(yes) {
|
|
|
54
46
|
}
|
|
55
47
|
return result;
|
|
56
48
|
}
|
|
57
|
-
/**
|
|
58
|
-
async function
|
|
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) {
|
|
59
57
|
if (await fileExists(path.join(cwd, "node_modules"))) return;
|
|
60
58
|
let pkgJson;
|
|
61
59
|
try {
|
|
@@ -66,16 +64,17 @@ async function installDeps(cwd, pm) {
|
|
|
66
64
|
const deps = Object.keys(pkgJson.dependencies ?? {});
|
|
67
65
|
const devDeps = Object.keys(pkgJson.devDependencies ?? {});
|
|
68
66
|
if (deps.length === 0 && devDeps.length === 0) return;
|
|
67
|
+
await ensurePnpm();
|
|
69
68
|
const s = p.spinner();
|
|
70
|
-
s.start(
|
|
69
|
+
s.start("Installing dependencies with pnpm");
|
|
71
70
|
try {
|
|
72
|
-
await execFileAsync(
|
|
71
|
+
await execFileAsync("pnpm", ["install", "--ignore-workspace"], { cwd });
|
|
73
72
|
s.stop("Dependencies installed");
|
|
74
73
|
} catch (err) {
|
|
75
74
|
const msg = errorMessage(err);
|
|
76
75
|
s.stop("Dependency install failed");
|
|
77
|
-
log.warn(
|
|
78
|
-
log.warn(
|
|
76
|
+
log.warn(`pnpm install failed: ${msg}`);
|
|
77
|
+
log.warn("Run `corepack enable && pnpm install` manually in the project directory.");
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
/** Format the dev command for the "Next steps" note. */
|
|
@@ -83,7 +82,6 @@ function devCommand() {
|
|
|
83
82
|
return "aai dev";
|
|
84
83
|
}
|
|
85
84
|
async function runInitCommand(opts, extra) {
|
|
86
|
-
const pm = detectPackageManager();
|
|
87
85
|
if (!extra?.quiet) p.intro(colorize("cyanBright", "Create a new voice agent"));
|
|
88
86
|
if (!opts.skipApi) await ensureApiKeyInEnv();
|
|
89
87
|
const dir = opts.dir ?? await promptProjectName(opts.yes);
|
|
@@ -92,16 +90,19 @@ async function runInitCommand(opts, extra) {
|
|
|
92
90
|
const template = opts.template ?? await promptTemplate(opts.yes);
|
|
93
91
|
const s = p.spinner();
|
|
94
92
|
s.start(`Creating ${dir} from ${template} template`);
|
|
95
|
-
const { runInit } = await import("./_init-
|
|
93
|
+
const { runInit } = await import("./_init-CbMs9S2O.mjs");
|
|
96
94
|
await runInit({
|
|
97
95
|
targetDir: cwd,
|
|
98
96
|
template
|
|
99
97
|
});
|
|
100
98
|
s.stop("Project created");
|
|
101
|
-
await installDeps(cwd
|
|
99
|
+
await installDeps(cwd);
|
|
102
100
|
if (!(opts.skipDeploy || extra?.quiet)) {
|
|
103
|
-
const { runDeployCommand } = await import("./deploy-
|
|
104
|
-
await runDeployCommand({
|
|
101
|
+
const { runDeployCommand } = await import("./deploy-CLs8gLHV.mjs");
|
|
102
|
+
await runDeployCommand({
|
|
103
|
+
cwd,
|
|
104
|
+
...opts.server ? { server: opts.server } : {}
|
|
105
|
+
});
|
|
105
106
|
}
|
|
106
107
|
if (!extra?.quiet) {
|
|
107
108
|
log.success(`Created ${dir}`);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as getServerInfo, d as askPassword } from "./_discover-DzsMlg3G.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 secret.ts
|
|
6
|
+
async function secretRequest(cwd, pathSuffix, init, server) {
|
|
7
|
+
const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
|
|
8
|
+
const resp = await apiRequest(`${serverUrl}/${slug}/secret${pathSuffix}`, {
|
|
9
|
+
...init,
|
|
10
|
+
apiKey,
|
|
11
|
+
action: "secret"
|
|
12
|
+
});
|
|
13
|
+
if (!resp.ok) {
|
|
14
|
+
const text = await resp.text();
|
|
15
|
+
const hint = resp.status === 401 ? HINT_INVALID_API_KEY : void 0;
|
|
16
|
+
throw apiError("secret", resp.status, text, hint);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
resp,
|
|
20
|
+
slug
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function runSecretPut(cwd, name, server) {
|
|
24
|
+
const value = await askPassword(`Enter value for ${name}`);
|
|
25
|
+
if (!value) throw new Error("No value provided");
|
|
26
|
+
const { slug } = await secretRequest(cwd, "", {
|
|
27
|
+
method: "PUT",
|
|
28
|
+
body: JSON.stringify({ [name]: value })
|
|
29
|
+
}, server);
|
|
30
|
+
log.success(`Set ${name} for ${slug}`);
|
|
31
|
+
}
|
|
32
|
+
async function runSecretDelete(cwd, name, server) {
|
|
33
|
+
const { slug } = await secretRequest(cwd, `/${name}`, { method: "DELETE" }, server);
|
|
34
|
+
log.success(`Deleted ${name} from ${slug}`);
|
|
35
|
+
}
|
|
36
|
+
async function runSecretList(cwd, server) {
|
|
37
|
+
const { resp } = await secretRequest(cwd, "", void 0, server);
|
|
38
|
+
const { vars } = await resp.json();
|
|
39
|
+
if (vars.length === 0) log.info("No secrets set. Use `aai secret put <name>` to add one.");
|
|
40
|
+
else {
|
|
41
|
+
log.message(`${vars.length} secret${vars.length === 1 ? "" : "s"}:`);
|
|
42
|
+
for (const name of vars) log.message(` ${name}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { runSecretDelete, runSecretList, runSecretPut };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { log } from "./_ui-DWGXImbO.mjs";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
6
|
//#region test.ts
|
|
7
7
|
/**
|
|
8
8
|
* `aai test` — run agent tests via vitest.
|
|
@@ -15,7 +15,13 @@ import { execSync } from "node:child_process";
|
|
|
15
15
|
*/
|
|
16
16
|
function runVitest(cwd) {
|
|
17
17
|
if (!(existsSync(path.join(cwd, "agent.test.ts")) || existsSync(path.join(cwd, "agent.test.js")))) return false;
|
|
18
|
-
|
|
18
|
+
execFileSync("npx", [
|
|
19
|
+
"vitest",
|
|
20
|
+
"run",
|
|
21
|
+
"--root",
|
|
22
|
+
".",
|
|
23
|
+
existsSync(path.join(cwd, "agent.test.ts")) ? "agent.test.ts" : "agent.test.js"
|
|
24
|
+
], {
|
|
19
25
|
cwd,
|
|
20
26
|
stdio: "inherit",
|
|
21
27
|
env: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aai": "dist/cli.mjs"
|
|
@@ -9,19 +9,22 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@clack/prompts": "^1.
|
|
12
|
+
"@clack/prompts": "^1.2.0",
|
|
13
|
+
"ci-info": "^4.4.0",
|
|
13
14
|
"citty": "^0.2.1",
|
|
14
15
|
"consola": "^3.4.2",
|
|
15
16
|
"giget": "^2.0.0",
|
|
16
|
-
"human-id": "^4.1.3",
|
|
17
17
|
"vite": "^8.0.3",
|
|
18
18
|
"zod": "^4.3.6",
|
|
19
|
-
"@alexkroman1/aai": "0.12.
|
|
19
|
+
"@alexkroman1/aai": "0.12.3"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
22
|
+
"get-port": "^7.2.0",
|
|
23
|
+
"playwright": "^1.59.0",
|
|
24
|
+
"tree-kill": "^1.2.2",
|
|
25
|
+
"tsdown": "^0.21.7",
|
|
26
|
+
"verdaccio": "^6.3.2",
|
|
27
|
+
"vitest": "^4.1.2"
|
|
25
28
|
},
|
|
26
29
|
"engines": {
|
|
27
30
|
"node": ">=22.6"
|
|
@@ -32,6 +35,8 @@
|
|
|
32
35
|
"directory": "packages/aai-cli"
|
|
33
36
|
},
|
|
34
37
|
"scripts": {
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:coverage": "vitest run --coverage",
|
|
35
40
|
"build": "tsdown",
|
|
36
41
|
"typecheck": "tsc --noEmit",
|
|
37
42
|
"lint": "biome check .",
|
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/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 };
|