@alexkroman1/aai-cli 5.5.1 → 5.6.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/README.md +16 -7
- package/dist/{_agent-DMyOab9_.mjs → _agent-BB1ZaZsX.mjs} +3 -3
- package/dist/_agent.d.ts +3 -1
- package/dist/{_api-client-MenP4-O7.mjs → _api-client-B6_uvuLs.mjs} +1 -0
- package/dist/_api-client.d.ts +6 -0
- package/dist/_cli-common.d.ts +38 -0
- package/dist/{_config-5AEqhh-O.mjs → _config-PIC0nzRu.mjs} +29 -3
- package/dist/_config.d.ts +9 -1
- package/dist/_deploy.d.ts +7 -0
- package/dist/{_dev-server-vV05Fnki.mjs → _dev-server-CGptLIAm.mjs} +2 -2
- package/dist/{_init-BZ9t_Kz-.mjs → _init-BPFM4uBH.mjs} +3 -3
- package/dist/{_slug-api-DaqQJHk8.mjs → _slug-api-dcaQ_Uho.mjs} +2 -2
- package/dist/_studio-commands.d.ts +73 -0
- package/dist/_studio.d.ts +55 -0
- package/dist/{_templates-Bv8CR800.mjs → _templates-jmjgdgcd.mjs} +19 -8
- package/dist/_templates.d.ts +9 -0
- package/dist/{_typecheck-gate-9IHWDnl1.mjs → _typecheck-gate-DvE8S3aQ.mjs} +1 -1
- package/dist/{build-D_PgQOD4.mjs → build-BXwDB78d.mjs} +1 -1
- package/dist/cli.mjs +163 -34
- package/dist/delete-BaHgd9cN.mjs +51 -0
- package/dist/delete.d.ts +9 -2
- package/dist/{deploy-1eaXcfUw.mjs → deploy-D-O-Q_mW.mjs} +7 -5
- package/dist/deploy.d.ts +2 -0
- package/dist/{dev-gVNdGFYY.mjs → dev-C5P8amSg.mjs} +1 -1
- package/dist/{init-DoU4_txp.mjs → init-BGlOhIOl.mjs} +15 -14
- package/dist/login-B6IhXski.mjs +117 -0
- package/dist/login.d.ts +33 -20
- package/dist/scaffold/package.json +4 -4
- package/dist/{secret-CGAIAbUx.mjs → secret-_bHo4rqt.mjs} +1 -1
- package/dist/{storage-CnhOayhm.mjs → storage-MWiVx_mV.mjs} +1 -1
- package/dist/studio-CsRn2J1a.mjs +284 -0
- package/dist/studio.d.ts +52 -0
- package/package.json +4 -4
- package/dist/delete-DXilFBb1.mjs +0 -29
- package/dist/login-C59ZHzuO.mjs +0 -109
package/dist/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { defineCommand, runMain } from "citty";
|
|
8
|
-
//#region
|
|
8
|
+
//#region _cli-common.ts
|
|
9
9
|
/** Shared arg definitions for citty commands. */
|
|
10
10
|
const sharedArgs = {
|
|
11
11
|
server: {
|
|
@@ -23,21 +23,6 @@ const sharedArgs = {
|
|
|
23
23
|
description: "Output JSON (auto-detected in non-TTY)"
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
-
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
27
|
-
/**
|
|
28
|
-
* Read this CLI's own version from its package.json (source layout keeps it
|
|
29
|
-
* next to cli.ts; dist layout one level up). A missing or corrupt file must
|
|
30
|
-
* not brick every command over a cosmetic string — warn and fall back.
|
|
31
|
-
*/
|
|
32
|
-
function readCliVersion(dir) {
|
|
33
|
-
for (const candidate of [path.join(dir, "package.json"), path.join(dir, "..", "package.json")]) try {
|
|
34
|
-
const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
35
|
-
if (typeof parsed.version === "string") return parsed.version;
|
|
36
|
-
} catch {}
|
|
37
|
-
process.stderr.write("warning: could not read aai's package.json — reporting version unknown\n");
|
|
38
|
-
return "unknown";
|
|
39
|
-
}
|
|
40
|
-
const VERSION = readCliVersion(cliDir);
|
|
41
26
|
/** Shared command setup: resolve cwd, optionally require agent.ts. */
|
|
42
27
|
async function setup(opts) {
|
|
43
28
|
const cwd = resolveCwd();
|
|
@@ -77,6 +62,140 @@ async function runCommand(args, fn) {
|
|
|
77
62
|
if (mode === "json") await writeLine(`${JSON.stringify(result)}\n`);
|
|
78
63
|
if (!result.ok) process.exit(1);
|
|
79
64
|
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region _studio-commands.ts
|
|
67
|
+
const list = defineCommand({
|
|
68
|
+
meta: {
|
|
69
|
+
name: "list",
|
|
70
|
+
description: "List your studio projects"
|
|
71
|
+
},
|
|
72
|
+
args: {
|
|
73
|
+
server: sharedArgs.server,
|
|
74
|
+
json: sharedArgs.json
|
|
75
|
+
},
|
|
76
|
+
async run({ args }) {
|
|
77
|
+
await runCommand(args, async () => {
|
|
78
|
+
const cwd = resolveCwd();
|
|
79
|
+
const { executeList } = await import("./studio-CsRn2J1a.mjs");
|
|
80
|
+
return executeList({
|
|
81
|
+
cwd,
|
|
82
|
+
server: args.server
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const pull = defineCommand({
|
|
88
|
+
meta: {
|
|
89
|
+
name: "pull",
|
|
90
|
+
description: "Pull a studio project into a local directory"
|
|
91
|
+
},
|
|
92
|
+
args: {
|
|
93
|
+
project: {
|
|
94
|
+
type: "positional",
|
|
95
|
+
description: "Studio project name (see `aai list`)",
|
|
96
|
+
required: true
|
|
97
|
+
},
|
|
98
|
+
dir: {
|
|
99
|
+
type: "positional",
|
|
100
|
+
description: "Target directory (default: the project name)",
|
|
101
|
+
required: false
|
|
102
|
+
},
|
|
103
|
+
force: {
|
|
104
|
+
type: "boolean",
|
|
105
|
+
alias: "f",
|
|
106
|
+
description: "Overwrite files in a non-empty directory"
|
|
107
|
+
},
|
|
108
|
+
server: sharedArgs.server,
|
|
109
|
+
json: sharedArgs.json
|
|
110
|
+
},
|
|
111
|
+
async run({ args }) {
|
|
112
|
+
await runCommand(args, async () => {
|
|
113
|
+
const cwd = resolveCwd();
|
|
114
|
+
const { executePull } = await import("./studio-CsRn2J1a.mjs");
|
|
115
|
+
return executePull({
|
|
116
|
+
cwd,
|
|
117
|
+
project: args.project,
|
|
118
|
+
dir: args.dir,
|
|
119
|
+
force: args.force,
|
|
120
|
+
server: args.server
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const push = defineCommand({
|
|
126
|
+
meta: {
|
|
127
|
+
name: "push",
|
|
128
|
+
description: "Sync this project's source to its studio workspace"
|
|
129
|
+
},
|
|
130
|
+
args: {
|
|
131
|
+
force: {
|
|
132
|
+
type: "boolean",
|
|
133
|
+
alias: "f",
|
|
134
|
+
description: "Overwrite studio-side changes instead of failing the fast-forward check"
|
|
135
|
+
},
|
|
136
|
+
server: sharedArgs.server,
|
|
137
|
+
json: sharedArgs.json
|
|
138
|
+
},
|
|
139
|
+
async run({ args }) {
|
|
140
|
+
await runCommand(args, async () => {
|
|
141
|
+
const cwd = await setup({ agent: true });
|
|
142
|
+
const { executePush } = await import("./studio-CsRn2J1a.mjs");
|
|
143
|
+
return executePush({
|
|
144
|
+
cwd,
|
|
145
|
+
server: args.server,
|
|
146
|
+
force: args.force
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const publish = defineCommand({
|
|
152
|
+
meta: {
|
|
153
|
+
name: "publish",
|
|
154
|
+
description: "Push to the studio and deploy to production (the studio's Publish button)"
|
|
155
|
+
},
|
|
156
|
+
args: {
|
|
157
|
+
force: {
|
|
158
|
+
type: "boolean",
|
|
159
|
+
alias: "f",
|
|
160
|
+
description: "Overwrite studio-side changes instead of failing the fast-forward check"
|
|
161
|
+
},
|
|
162
|
+
server: sharedArgs.server,
|
|
163
|
+
json: sharedArgs.json,
|
|
164
|
+
skipTypecheck: {
|
|
165
|
+
type: "boolean",
|
|
166
|
+
description: "Skip type checking before publishing"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
async run({ args }) {
|
|
170
|
+
await runCommand(args, async () => {
|
|
171
|
+
const cwd = await setup({ agent: true });
|
|
172
|
+
const { executePublish } = await import("./studio-CsRn2J1a.mjs");
|
|
173
|
+
return executePublish({
|
|
174
|
+
cwd,
|
|
175
|
+
server: args.server,
|
|
176
|
+
force: args.force,
|
|
177
|
+
skipTypecheck: args.skipTypecheck
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region cli.ts
|
|
184
|
+
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
185
|
+
/**
|
|
186
|
+
* Read this CLI's own version from its package.json (source layout keeps it
|
|
187
|
+
* next to cli.ts; dist layout one level up). A missing or corrupt file must
|
|
188
|
+
* not brick every command over a cosmetic string — warn and fall back.
|
|
189
|
+
*/
|
|
190
|
+
function readCliVersion(dir) {
|
|
191
|
+
for (const candidate of [path.join(dir, "package.json"), path.join(dir, "..", "package.json")]) try {
|
|
192
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
193
|
+
if (typeof parsed.version === "string") return parsed.version;
|
|
194
|
+
} catch {}
|
|
195
|
+
process.stderr.write("warning: could not read aai's package.json — reporting version unknown\n");
|
|
196
|
+
return "unknown";
|
|
197
|
+
}
|
|
198
|
+
const VERSION = readCliVersion(cliDir);
|
|
80
199
|
const init = defineCommand({
|
|
81
200
|
meta: {
|
|
82
201
|
name: "init",
|
|
@@ -108,7 +227,7 @@ const init = defineCommand({
|
|
|
108
227
|
},
|
|
109
228
|
async run({ args }) {
|
|
110
229
|
await runCommand(args, async (mode) => {
|
|
111
|
-
const { executeInit } = await import("./init-
|
|
230
|
+
const { executeInit } = await import("./init-BGlOhIOl.mjs");
|
|
112
231
|
return executeInit({
|
|
113
232
|
dir: args.dir,
|
|
114
233
|
force: args.force,
|
|
@@ -137,7 +256,7 @@ const dev = defineCommand({
|
|
|
137
256
|
async run({ args }) {
|
|
138
257
|
await runCommand(args, async () => {
|
|
139
258
|
const cwd = await setup({ agent: true });
|
|
140
|
-
const { executeDev } = await import("./dev-
|
|
259
|
+
const { executeDev } = await import("./dev-C5P8amSg.mjs");
|
|
141
260
|
return executeDev({
|
|
142
261
|
cwd,
|
|
143
262
|
port: args.port
|
|
@@ -178,7 +297,7 @@ const build = defineCommand({
|
|
|
178
297
|
async run({ args }) {
|
|
179
298
|
await runCommand(args, async () => {
|
|
180
299
|
const cwd = await setup({ agent: true });
|
|
181
|
-
const { executeBuild } = await import("./build-
|
|
300
|
+
const { executeBuild } = await import("./build-BXwDB78d.mjs");
|
|
182
301
|
return executeBuild({
|
|
183
302
|
cwd,
|
|
184
303
|
skipTests: args.skipTests,
|
|
@@ -190,7 +309,8 @@ const build = defineCommand({
|
|
|
190
309
|
const deploy = defineCommand({
|
|
191
310
|
meta: {
|
|
192
311
|
name: "deploy",
|
|
193
|
-
description: "
|
|
312
|
+
description: "(internal) used by studio Publish",
|
|
313
|
+
hidden: true
|
|
194
314
|
},
|
|
195
315
|
args: {
|
|
196
316
|
server: sharedArgs.server,
|
|
@@ -199,6 +319,10 @@ const deploy = defineCommand({
|
|
|
199
319
|
type: "boolean",
|
|
200
320
|
description: "Deploy even when the agent's providers are missing credentials (the server warns instead of rejecting; set them afterwards with `aai secret put`)"
|
|
201
321
|
},
|
|
322
|
+
allowPreviewSlug: {
|
|
323
|
+
type: "boolean",
|
|
324
|
+
description: "Permit a `-preview`-suffixed slug (reserved for studio auto-previews; studio-internal — a slug you claim this way is subject to the preview reaper)"
|
|
325
|
+
},
|
|
202
326
|
skipTypecheck: {
|
|
203
327
|
type: "boolean",
|
|
204
328
|
description: "Skip type checking before deploy"
|
|
@@ -207,11 +331,12 @@ const deploy = defineCommand({
|
|
|
207
331
|
async run({ args }) {
|
|
208
332
|
await runCommand(args, async () => {
|
|
209
333
|
const cwd = await setup({ agent: true });
|
|
210
|
-
const { executeDeploy } = await import("./deploy-
|
|
334
|
+
const { executeDeploy } = await import("./deploy-D-O-Q_mW.mjs");
|
|
211
335
|
return executeDeploy({
|
|
212
336
|
cwd,
|
|
213
337
|
server: args.server,
|
|
214
338
|
allowMissingSecrets: args.allowMissingSecrets,
|
|
339
|
+
allowPreviewSlug: args.allowPreviewSlug,
|
|
215
340
|
skipTypecheck: args.skipTypecheck
|
|
216
341
|
});
|
|
217
342
|
});
|
|
@@ -220,7 +345,7 @@ const deploy = defineCommand({
|
|
|
220
345
|
const del = defineCommand({
|
|
221
346
|
meta: {
|
|
222
347
|
name: "delete",
|
|
223
|
-
description: "
|
|
348
|
+
description: "Delete the studio project and its deployed agents"
|
|
224
349
|
},
|
|
225
350
|
args: {
|
|
226
351
|
server: sharedArgs.server,
|
|
@@ -229,7 +354,7 @@ const del = defineCommand({
|
|
|
229
354
|
async run({ args }) {
|
|
230
355
|
await runCommand(args, async () => {
|
|
231
356
|
const cwd = await setup();
|
|
232
|
-
const { executeDelete } = await import("./delete-
|
|
357
|
+
const { executeDelete } = await import("./delete-BaHgd9cN.mjs");
|
|
233
358
|
return executeDelete({
|
|
234
359
|
cwd,
|
|
235
360
|
server: args.server
|
|
@@ -260,7 +385,7 @@ const secret = defineCommand({
|
|
|
260
385
|
async run({ args }) {
|
|
261
386
|
await runCommand(args, async (mode) => {
|
|
262
387
|
const cwd = await setup();
|
|
263
|
-
const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-
|
|
388
|
+
const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-_bHo4rqt.mjs");
|
|
264
389
|
const value = mode === "json" ? await readStdin() : void 0;
|
|
265
390
|
if (mode === "json" && !value) throw new CliError(...NO_INPUT);
|
|
266
391
|
return executeSecretPut(cwd, args.name, value, args.server);
|
|
@@ -284,7 +409,7 @@ const secret = defineCommand({
|
|
|
284
409
|
async run({ args }) {
|
|
285
410
|
await runCommand(args, async () => {
|
|
286
411
|
const cwd = await setup();
|
|
287
|
-
const { executeSecretDelete } = await import("./secret-
|
|
412
|
+
const { executeSecretDelete } = await import("./secret-_bHo4rqt.mjs");
|
|
288
413
|
return executeSecretDelete(cwd, args.name, args.server);
|
|
289
414
|
});
|
|
290
415
|
}
|
|
@@ -301,7 +426,7 @@ const secret = defineCommand({
|
|
|
301
426
|
async run({ args }) {
|
|
302
427
|
await runCommand(args, async () => {
|
|
303
428
|
const cwd = await setup();
|
|
304
|
-
const { executeSecretList } = await import("./secret-
|
|
429
|
+
const { executeSecretList } = await import("./secret-_bHo4rqt.mjs");
|
|
305
430
|
return executeSecretList(cwd, args.server);
|
|
306
431
|
});
|
|
307
432
|
}
|
|
@@ -336,7 +461,7 @@ const storage = defineCommand({
|
|
|
336
461
|
},
|
|
337
462
|
async run({ args }) {
|
|
338
463
|
await runCommand(args, async () => {
|
|
339
|
-
const { executeStorageStatus } = await import("./storage-
|
|
464
|
+
const { executeStorageStatus } = await import("./storage-MWiVx_mV.mjs");
|
|
340
465
|
return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
|
|
341
466
|
});
|
|
342
467
|
}
|
|
@@ -353,7 +478,7 @@ const storage = defineCommand({
|
|
|
353
478
|
},
|
|
354
479
|
async run({ args }) {
|
|
355
480
|
await runCommand(args, async () => {
|
|
356
|
-
const { executeStorageEnable } = await import("./storage-
|
|
481
|
+
const { executeStorageEnable } = await import("./storage-MWiVx_mV.mjs");
|
|
357
482
|
return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
|
|
358
483
|
});
|
|
359
484
|
}
|
|
@@ -375,7 +500,7 @@ const storage = defineCommand({
|
|
|
375
500
|
},
|
|
376
501
|
async run({ args }) {
|
|
377
502
|
await runCommand(args, async () => {
|
|
378
|
-
const { executeStorageDisable } = await import("./storage-
|
|
503
|
+
const { executeStorageDisable } = await import("./storage-MWiVx_mV.mjs");
|
|
379
504
|
return executeStorageDisable(resolveStorageCwd(args.dir), {
|
|
380
505
|
server: args.server,
|
|
381
506
|
force: args.force
|
|
@@ -388,7 +513,7 @@ const storage = defineCommand({
|
|
|
388
513
|
const login = defineCommand({
|
|
389
514
|
meta: {
|
|
390
515
|
name: "login",
|
|
391
|
-
description: "
|
|
516
|
+
description: "Link your signed-in browser account and save your API key"
|
|
392
517
|
},
|
|
393
518
|
args: {
|
|
394
519
|
server: sharedArgs.server,
|
|
@@ -396,7 +521,7 @@ const login = defineCommand({
|
|
|
396
521
|
},
|
|
397
522
|
async run({ args }) {
|
|
398
523
|
await runCommand(args, async () => {
|
|
399
|
-
const { executeLogin } = await import("./login-
|
|
524
|
+
const { executeLogin } = await import("./login-B6IhXski.mjs");
|
|
400
525
|
return executeLogin({ server: args.server });
|
|
401
526
|
});
|
|
402
527
|
}
|
|
@@ -409,7 +534,7 @@ const templates = defineCommand({
|
|
|
409
534
|
args: { json: sharedArgs.json },
|
|
410
535
|
async run({ args }) {
|
|
411
536
|
await runCommand(args, async (mode) => {
|
|
412
|
-
const { listTemplates } = await import("./_templates-
|
|
537
|
+
const { listTemplates } = await import("./_templates-jmjgdgcd.mjs");
|
|
413
538
|
const names = await listTemplates();
|
|
414
539
|
if (mode === "human") {
|
|
415
540
|
for (const name of names) log.message(name);
|
|
@@ -433,6 +558,10 @@ const mainCommand = defineCommand({
|
|
|
433
558
|
dev,
|
|
434
559
|
test,
|
|
435
560
|
build,
|
|
561
|
+
list,
|
|
562
|
+
pull,
|
|
563
|
+
push,
|
|
564
|
+
publish,
|
|
436
565
|
deploy,
|
|
437
566
|
delete: del,
|
|
438
567
|
login,
|
|
@@ -450,12 +579,12 @@ if (process.env.VITEST !== "true") {
|
|
|
450
579
|
return;
|
|
451
580
|
}
|
|
452
581
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
453
|
-
if (await (await import("@clack/prompts")).confirm({ message: "
|
|
582
|
+
if (await (await import("@clack/prompts")).confirm({ message: "Publish this agent to production?" }) !== true) {
|
|
454
583
|
log.info("Cancelled. Run `aai --help` to see all commands.");
|
|
455
584
|
process.exit(0);
|
|
456
585
|
}
|
|
457
586
|
}
|
|
458
|
-
process.argv.splice(2, 0, "
|
|
587
|
+
process.argv.splice(2, 0, "publish");
|
|
459
588
|
};
|
|
460
589
|
runDefault().then(() => runMain(mainCommand)).catch((err) => {
|
|
461
590
|
log.error(errorMessage(err));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
+
import { i as resolveDeployTarget, n as getServerInfo } from "./_agent-BB1ZaZsX.mjs";
|
|
4
|
+
import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-B6_uvuLs.mjs";
|
|
5
|
+
//#region delete.ts
|
|
6
|
+
async function runDelete(opts) {
|
|
7
|
+
await apiRequest(`${opts.url}/${opts.slug}`, {
|
|
8
|
+
method: "DELETE",
|
|
9
|
+
apiKey: opts.apiKey,
|
|
10
|
+
action: "delete",
|
|
11
|
+
hints: { 404: HINT_NOT_DEPLOYED },
|
|
12
|
+
...opts.fetch ? { fetch: opts.fetch } : {}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Delete THE PROJECT. A studio-linked directory deletes its studio project
|
|
17
|
+
* (`DELETE /studio/projects/:project`), which cascades server-side to the
|
|
18
|
+
* workspace, chat, and the project's deployed + preview agents — the exact
|
|
19
|
+
* delete the studio's own Delete button runs. A directory that only knows a
|
|
20
|
+
* slug (no studio link) deletes that deployed agent directly.
|
|
21
|
+
*/
|
|
22
|
+
async function executeDelete(opts) {
|
|
23
|
+
const { cwd } = opts;
|
|
24
|
+
const { config, serverUrl, apiKey } = await resolveDeployTarget(cwd, opts.server);
|
|
25
|
+
if (config?.studioProject) {
|
|
26
|
+
const project = config.studioProject;
|
|
27
|
+
log.step(`Deleting studio project ${project} (and its deployed agents)`);
|
|
28
|
+
await apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}`, {
|
|
29
|
+
method: "DELETE",
|
|
30
|
+
apiKey,
|
|
31
|
+
action: "delete",
|
|
32
|
+
hints: { 404: "Run `aai list` to see your projects." }
|
|
33
|
+
});
|
|
34
|
+
log.success(`Deleted ${project}`);
|
|
35
|
+
return ok({
|
|
36
|
+
project,
|
|
37
|
+
...config.slug ? { slug: config.slug } : {}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const { slug } = await getServerInfo(cwd, opts.server);
|
|
41
|
+
log.step(`Deleting ${slug}`);
|
|
42
|
+
await runDelete({
|
|
43
|
+
url: serverUrl,
|
|
44
|
+
slug,
|
|
45
|
+
apiKey
|
|
46
|
+
});
|
|
47
|
+
log.success(`Deleted ${serverUrl}/${slug}`);
|
|
48
|
+
return ok({ slug });
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { executeDelete };
|
package/dist/delete.d.ts
CHANGED
|
@@ -8,9 +8,16 @@ export type DeleteOpts = {
|
|
|
8
8
|
};
|
|
9
9
|
export declare function runDelete(opts: DeleteOpts): Promise<void>;
|
|
10
10
|
type DeleteData = {
|
|
11
|
-
slug
|
|
11
|
+
slug?: string;
|
|
12
|
+
project?: string;
|
|
12
13
|
};
|
|
13
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Delete THE PROJECT. A studio-linked directory deletes its studio project
|
|
16
|
+
* (`DELETE /studio/projects/:project`), which cascades server-side to the
|
|
17
|
+
* workspace, chat, and the project's deployed + preview agents — the exact
|
|
18
|
+
* delete the studio's own Delete button runs. A directory that only knows a
|
|
19
|
+
* slug (no studio link) deletes that deployed agent directly.
|
|
20
|
+
*/
|
|
14
21
|
export declare function executeDelete(opts: {
|
|
15
22
|
cwd: string;
|
|
16
23
|
server?: string | undefined;
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
import { n as log, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
3
|
import { a as errorMessage } from "./_utils-Ch0J4s6a.mjs";
|
|
4
4
|
import { t as buildAgentBundle } from "./_bundler-Cjaxa2wi.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { s as updateProjectConfig } from "./_config-PIC0nzRu.mjs";
|
|
6
6
|
import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
|
|
7
|
-
import { i as resolveDeployTarget } from "./_agent-
|
|
8
|
-
import {
|
|
9
|
-
import { n as apiRequest } from "./_api-client-
|
|
7
|
+
import { i as resolveDeployTarget } from "./_agent-BB1ZaZsX.mjs";
|
|
8
|
+
import { assertTypechecks } from "./_typecheck-gate-DvE8S3aQ.mjs";
|
|
9
|
+
import { n as apiRequest } from "./_api-client-B6_uvuLs.mjs";
|
|
10
10
|
import { gzipSync } from "node:zlib";
|
|
11
11
|
//#region _deploy.ts
|
|
12
12
|
async function runDeploy(opts) {
|
|
13
13
|
const body = gzipSync(JSON.stringify({
|
|
14
14
|
...opts.slug ? { slug: opts.slug } : {},
|
|
15
15
|
...opts.allowMissingSecrets ? { credentialPolicy: "warn" } : {},
|
|
16
|
+
...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
|
|
16
17
|
env: opts.env,
|
|
17
18
|
worker: opts.bundle.worker,
|
|
18
19
|
clientFiles: opts.bundle.clientFiles
|
|
@@ -55,11 +56,12 @@ async function executeDeploy(opts) {
|
|
|
55
56
|
},
|
|
56
57
|
...slug ? { slug } : {},
|
|
57
58
|
...opts.allowMissingSecrets ? { allowMissingSecrets: true } : {},
|
|
59
|
+
...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
|
|
58
60
|
apiKey
|
|
59
61
|
});
|
|
60
62
|
const agentUrl = `${serverUrl}/${deployed.slug}`;
|
|
61
63
|
try {
|
|
62
|
-
await
|
|
64
|
+
await updateProjectConfig(cwd, {
|
|
63
65
|
slug: deployed.slug,
|
|
64
66
|
serverUrl
|
|
65
67
|
});
|
package/dist/deploy.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare function executeDeploy(opts: {
|
|
|
9
9
|
server?: string | undefined;
|
|
10
10
|
/** See DeployOpts.allowMissingSecrets (`--allow-missing-secrets`). */
|
|
11
11
|
allowMissingSecrets?: boolean | undefined;
|
|
12
|
+
/** See DeployOpts.allowPreviewSlug (`--allow-preview-slug`; studio-internal). */
|
|
13
|
+
allowPreviewSlug?: boolean | undefined;
|
|
12
14
|
/** `--skipTypecheck`: deploy without the tsc gate. */
|
|
13
15
|
skipTypecheck?: boolean | undefined;
|
|
14
16
|
}): Promise<CommandResult<DeployData>>;
|
|
@@ -11,7 +11,7 @@ import { styleText } from "node:util";
|
|
|
11
11
|
async function executeDev(opts) {
|
|
12
12
|
const port = parsePort(opts.port);
|
|
13
13
|
const agentName = path.basename(path.resolve(opts.cwd));
|
|
14
|
-
const { startDevServer } = await import("./_dev-server-
|
|
14
|
+
const { startDevServer } = await import("./_dev-server-CGptLIAm.mjs");
|
|
15
15
|
let cleanup;
|
|
16
16
|
let shuttingDown = false;
|
|
17
17
|
const onSignal = () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as unwrapCancel, n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
3
|
import { a as errorMessage, c as readJson, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-Ch0J4s6a.mjs";
|
|
4
|
-
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-
|
|
4
|
+
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-BB1ZaZsX.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
import * as p from "@clack/prompts";
|
|
@@ -72,27 +72,28 @@ async function installDeps(cwd, silent) {
|
|
|
72
72
|
function resolveTargetDir(dir) {
|
|
73
73
|
return path.resolve(resolveCwd(), dir);
|
|
74
74
|
}
|
|
75
|
-
/**
|
|
76
|
-
async function
|
|
77
|
-
const {
|
|
75
|
+
/** Publish after init and return deploy metadata if successful. */
|
|
76
|
+
async function tryPublish(cwd, server) {
|
|
77
|
+
const { executePublish } = await import("./studio-CsRn2J1a.mjs");
|
|
78
78
|
try {
|
|
79
|
-
const result = await
|
|
79
|
+
const result = await executePublish({
|
|
80
80
|
cwd,
|
|
81
81
|
...server ? { server } : {}
|
|
82
82
|
});
|
|
83
83
|
return result.ok ? {
|
|
84
84
|
slug: result.data.slug,
|
|
85
|
-
url: result.data.url
|
|
85
|
+
url: result.data.url,
|
|
86
|
+
studioUrl: result.data.studioUrl
|
|
86
87
|
} : null;
|
|
87
88
|
} catch (err) {
|
|
88
|
-
log.warn(`
|
|
89
|
-
log.warn("Your project was still created — run `aai
|
|
89
|
+
log.warn(`Publish failed: ${errorMessage(err)}`);
|
|
90
|
+
log.warn("Your project was still created — run `aai publish` in it to retry.");
|
|
90
91
|
return null;
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
/** Scaffold the project, optionally showing a spinner. */
|
|
94
95
|
async function scaffoldProject(dir, cwd, template, silent) {
|
|
95
|
-
const { runInit } = await import("./_init-
|
|
96
|
+
const { runInit } = await import("./_init-BPFM4uBH.mjs");
|
|
96
97
|
const s = silent ? void 0 : p.spinner();
|
|
97
98
|
s?.start(`Creating ${dir}`);
|
|
98
99
|
await runInit({
|
|
@@ -120,13 +121,13 @@ async function executeInit(opts, extra) {
|
|
|
120
121
|
let deployed = false;
|
|
121
122
|
let slug;
|
|
122
123
|
let url;
|
|
123
|
-
if (!installed) log.warn("Skipping
|
|
124
|
+
if (!installed) log.warn("Skipping publish because dependencies were not installed.");
|
|
124
125
|
else if (!opts.skipDeploy) {
|
|
125
|
-
const
|
|
126
|
-
if (
|
|
126
|
+
const published = await tryPublish(cwd, opts.server);
|
|
127
|
+
if (published) {
|
|
127
128
|
deployed = true;
|
|
128
|
-
slug =
|
|
129
|
-
url =
|
|
129
|
+
slug = published.slug;
|
|
130
|
+
url = published.url;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
if (!suppressUi) printPostInitInfo(cwd, monorepoRoot);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
+
import { c as writeGlobalConfig, i as readGlobalConfig, r as getConfigDir, t as approveServer } from "./_config-PIC0nzRu.mjs";
|
|
4
|
+
import { a as resolveServerUrl } from "./_agent-BB1ZaZsX.mjs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { setTimeout } from "node:timers/promises";
|
|
7
|
+
import { randomBytes } from "node:crypto";
|
|
8
|
+
//#region login.ts
|
|
9
|
+
/**
|
|
10
|
+
* `aai login` — link the CLI to an account that is ALREADY signed in to the
|
|
11
|
+
* browser studio, ending with the account's AssemblyAI API key stored in
|
|
12
|
+
* the global config (the same slot `ensureApiKey` reads), so every other
|
|
13
|
+
* command is untouched by how the key was acquired.
|
|
14
|
+
*
|
|
15
|
+
* The CLI deliberately performs no sign-in of its own — it cannot create an
|
|
16
|
+
* account, and it never sees a session token. Device-link flow:
|
|
17
|
+
* 1. `GET /studio/auth` — fail fast when the server has no browser login
|
|
18
|
+
* configured (nobody could ever approve the link).
|
|
19
|
+
* 2. Mint an unguessable one-shot code (32 random bytes, base64url) and
|
|
20
|
+
* open the browser at `<server>/?cli-link=<code>`. The studio — where
|
|
21
|
+
* the user signs in with GitHub (or the local-dev login) if they aren't
|
|
22
|
+
* already — shows a "link the CLI to this account?" approval displaying
|
|
23
|
+
* the same short confirmation code this terminal printed, so a phished
|
|
24
|
+
* approval link has a visible mismatch (no terminal to match against).
|
|
25
|
+
* 3. Poll `POST /studio/cli-link/exchange` with the code. Approval grants
|
|
26
|
+
* the code ONE exchange for the account's stored API key, which is
|
|
27
|
+
* saved locally. An account with no stored key can't approve — the
|
|
28
|
+
* studio's own onboarding gate runs first — so the CLI never sets keys.
|
|
29
|
+
*/
|
|
30
|
+
const LINK_POLL_INTERVAL_MS = 2e3;
|
|
31
|
+
const LINK_TIMEOUT_MS = 3e5;
|
|
32
|
+
async function jsonBody(res, what) {
|
|
33
|
+
const body = await res.json().catch(() => null);
|
|
34
|
+
if (!res.ok) throw new CliError("login_failed", `${what} failed: ${body?.error ?? body?.msg ?? `HTTP ${res.status}`}`);
|
|
35
|
+
if (body === null) throw new CliError("login_failed", `${what} returned an invalid response`);
|
|
36
|
+
return body;
|
|
37
|
+
}
|
|
38
|
+
function requireTty() {
|
|
39
|
+
if (!process.stdin.isTTY) throw new CliError("login_interactive", "`aai login` is interactive and needs a TTY.", "Non-interactive setups can set the ASSEMBLYAI_API_KEY environment variable instead.");
|
|
40
|
+
}
|
|
41
|
+
function openerFor(platform) {
|
|
42
|
+
if (platform === "darwin") return ["open", []];
|
|
43
|
+
if (platform === "win32") return ["cmd", [
|
|
44
|
+
"/c",
|
|
45
|
+
"start",
|
|
46
|
+
""
|
|
47
|
+
]];
|
|
48
|
+
return ["xdg-open", []];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Human-matchable confirmation derived from the link code — printed in the
|
|
52
|
+
* terminal AND shown on the browser approval gate (aai-studio-client's
|
|
53
|
+
* cli-link.ts derives the same value; keep the two in lockstep). Not a
|
|
54
|
+
* secret: both ends already hold the full code. It exists so someone who
|
|
55
|
+
* lands on an approval page they didn't cause has a concrete mismatch to
|
|
56
|
+
* notice ("what terminal?") instead of a bare Approve button.
|
|
57
|
+
*/
|
|
58
|
+
function linkConfirmationCode(code) {
|
|
59
|
+
const head = code.slice(0, 8).toUpperCase();
|
|
60
|
+
return `${head.slice(0, 4)}-${head.slice(4)}`;
|
|
61
|
+
}
|
|
62
|
+
/** Best-effort: the link URL is always printed, so a failure is fine. */
|
|
63
|
+
function defaultOpenBrowser(url) {
|
|
64
|
+
const [cmd, args] = openerFor(process.platform);
|
|
65
|
+
try {
|
|
66
|
+
const child = spawn(cmd, [...args, url], {
|
|
67
|
+
stdio: "ignore",
|
|
68
|
+
detached: true
|
|
69
|
+
});
|
|
70
|
+
child.on("error", () => {});
|
|
71
|
+
child.unref();
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
async function executeLogin(opts, deps = {}) {
|
|
75
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
76
|
+
requireTty();
|
|
77
|
+
const globalConfig = await readGlobalConfig();
|
|
78
|
+
const serverUrl = resolveServerUrl(opts.server, void 0, globalConfig.approvedServers ?? []);
|
|
79
|
+
if (opts.server) await approveServer(serverUrl);
|
|
80
|
+
if ((await jsonBody(await fetchFn(`${serverUrl}/studio/auth`), "Reading the server's login configuration")).mode === "none") throw new CliError("login_unavailable", "This server has no browser login configured, so there is no account to link.", "Set the ASSEMBLYAI_API_KEY environment variable, or run any platform command to be prompted for a key.");
|
|
81
|
+
const code = randomBytes(32).toString("base64url");
|
|
82
|
+
const linkUrl = `${serverUrl}/?cli-link=${code}`;
|
|
83
|
+
log.info(`Opening the browser to link your account…\n ${linkUrl}`);
|
|
84
|
+
log.info(`Confirmation code: ${linkConfirmationCode(code)}`);
|
|
85
|
+
log.info("Approve the link in the browser (sign in there first if you need to) — the approval page shows the same code.");
|
|
86
|
+
(deps.openBrowser ?? defaultOpenBrowser)(linkUrl);
|
|
87
|
+
const pollInterval = deps.pollIntervalMs ?? LINK_POLL_INTERVAL_MS;
|
|
88
|
+
const deadline = Date.now() + (deps.timeoutMs ?? LINK_TIMEOUT_MS);
|
|
89
|
+
let granted;
|
|
90
|
+
for (;;) {
|
|
91
|
+
const res = await fetchFn(`${serverUrl}/studio/cli-link/exchange`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: { "Content-Type": "application/json" },
|
|
94
|
+
body: JSON.stringify({ code })
|
|
95
|
+
});
|
|
96
|
+
if (res.status !== 404) {
|
|
97
|
+
granted = await jsonBody(res, "Linking your account");
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (Date.now() >= deadline) throw new CliError("login_timeout", "Timed out waiting for the link to be approved in the browser.", "Run `aai login` again and approve the link within five minutes.");
|
|
101
|
+
await setTimeout(pollInterval);
|
|
102
|
+
}
|
|
103
|
+
if (!granted.apiKey) throw new CliError("login_failed", "Linking your account did not return an API key.");
|
|
104
|
+
const dir = getConfigDir();
|
|
105
|
+
await writeGlobalConfig(dir, {
|
|
106
|
+
...await readGlobalConfig(dir),
|
|
107
|
+
apiKey: granted.apiKey
|
|
108
|
+
});
|
|
109
|
+
const email = granted.email ?? "your account";
|
|
110
|
+
log.success(`Linked ${email} — your API key is saved for future commands.`);
|
|
111
|
+
return ok({
|
|
112
|
+
email,
|
|
113
|
+
server: serverUrl
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { executeLogin };
|