@alexkroman1/aai-cli 0.9.3 → 0.10.1

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.
Files changed (65) hide show
  1. package/dist/{_build-Cf_bB5Vl.mjs → _build-aW_zyPpr.mjs} +57 -11
  2. package/dist/{_discover-DsorPpR_.mjs → _discover-D7HCLa_N.mjs} +62 -27
  3. package/dist/_init-CweK2mJJ.mjs +108 -0
  4. package/dist/{_link-BGXGFYWa.mjs → _link-D6mmDQ0B.mjs} +5 -3
  5. package/dist/_server-common-B6EXxxB2.mjs +105 -0
  6. package/dist/_ui-C9IvR7Fh.mjs +50 -0
  7. package/dist/cli.mjs +186 -31
  8. package/dist/delete-DxECFYOp.mjs +40 -0
  9. package/dist/{deploy-2OxZpIfj.mjs → deploy-DB0PeNtc.mjs} +11 -7
  10. package/dist/dev-DCtHG1pz.mjs +60 -0
  11. package/dist/doctor-bWuArZi6.mjs +215 -0
  12. package/dist/generate-D7zJtqoC.mjs +393 -0
  13. package/dist/{init-nHgDq3Om.mjs → init-COkINbH_.mjs} +13 -17
  14. package/dist/{rag-D0xqGIrS.mjs → rag-BNfrEr4A.mjs} +12 -7
  15. package/dist/{secret-BQl3zBOS.mjs → secret-Zzv7fJ_3.mjs} +2 -2
  16. package/dist/{start-Df8c2ciS.mjs → start-DQypQkOq.mjs} +5 -5
  17. package/dist/test-9fFn9DCf.mjs +40 -0
  18. package/package.json +18 -11
  19. package/dist/_init-l_uoyFCN.mjs +0 -82
  20. package/dist/_server-common-CpK4rWGs.mjs +0 -36
  21. package/dist/_ui-kJIua5L9.mjs +0 -44
  22. package/dist/dev-BIgNj8Dt.mjs +0 -39
  23. package/templates/_shared/.env.example +0 -5
  24. package/templates/_shared/CLAUDE.md +0 -1051
  25. package/templates/_shared/biome.json +0 -32
  26. package/templates/_shared/global.d.ts +0 -1
  27. package/templates/_shared/index.html +0 -16
  28. package/templates/_shared/package.json +0 -23
  29. package/templates/_shared/tsconfig.json +0 -15
  30. package/templates/code-interpreter/agent.ts +0 -27
  31. package/templates/code-interpreter/client.tsx +0 -3
  32. package/templates/css.d.ts +0 -1
  33. package/templates/dispatch-center/agent.ts +0 -1227
  34. package/templates/dispatch-center/client.tsx +0 -505
  35. package/templates/embedded-assets/agent.ts +0 -48
  36. package/templates/embedded-assets/client.tsx +0 -3
  37. package/templates/embedded-assets/knowledge.json +0 -20
  38. package/templates/health-assistant/agent.ts +0 -160
  39. package/templates/health-assistant/client.tsx +0 -3
  40. package/templates/infocom-adventure/agent.ts +0 -164
  41. package/templates/infocom-adventure/client.tsx +0 -300
  42. package/templates/math-buddy/agent.ts +0 -21
  43. package/templates/math-buddy/client.tsx +0 -3
  44. package/templates/memory-agent/agent.ts +0 -20
  45. package/templates/memory-agent/client.tsx +0 -3
  46. package/templates/night-owl/agent.ts +0 -98
  47. package/templates/night-owl/client.tsx +0 -12
  48. package/templates/personal-finance/agent.ts +0 -26
  49. package/templates/personal-finance/client.tsx +0 -3
  50. package/templates/pizza-ordering/agent.ts +0 -218
  51. package/templates/pizza-ordering/client.tsx +0 -264
  52. package/templates/simple/agent.ts +0 -6
  53. package/templates/simple/client.tsx +0 -3
  54. package/templates/smart-research/agent.ts +0 -164
  55. package/templates/smart-research/client.tsx +0 -3
  56. package/templates/solo-rpg/agent.ts +0 -1244
  57. package/templates/solo-rpg/client.tsx +0 -698
  58. package/templates/support/README.md +0 -62
  59. package/templates/support/agent.ts +0 -19
  60. package/templates/support/client.tsx +0 -3
  61. package/templates/travel-concierge/agent.ts +0 -29
  62. package/templates/travel-concierge/client.tsx +0 -3
  63. package/templates/tsconfig.json +0 -1
  64. package/templates/web-researcher/agent.ts +0 -17
  65. package/templates/web-researcher/client.tsx +0 -3
package/dist/cli.mjs CHANGED
@@ -1,10 +1,29 @@
1
1
  #!/usr/bin/env node
2
- import { c as resolveCwd, r as getApiKey, t as fileExists } from "./_discover-DsorPpR_.mjs";
2
+ import { l as resolveCwd, n as fileExists, t as ensureApiKeyInEnv } from "./_discover-D7HCLa_N.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { defineCommand, runMain } from "citty";
7
7
  //#region cli.ts
8
+ /** Shared arg definitions for citty commands. */
9
+ const sharedArgs = {
10
+ port: {
11
+ type: "string",
12
+ alias: "p",
13
+ description: "Port to listen on",
14
+ default: "3000"
15
+ },
16
+ server: {
17
+ type: "string",
18
+ alias: "s",
19
+ description: "Server URL"
20
+ },
21
+ yes: {
22
+ type: "boolean",
23
+ alias: "y",
24
+ description: "Accept defaults (no prompts)"
25
+ }
26
+ };
8
27
  const cliDir = path.dirname(fileURLToPath(import.meta.url));
9
28
  function findPkgJson(dir) {
10
29
  try {
@@ -16,7 +35,7 @@ function findPkgJson(dir) {
16
35
  const VERSION = JSON.parse(findPkgJson(cliDir)).version;
17
36
  async function ensureAgent(cwd, yes) {
18
37
  if (!await fileExists(path.join(cwd, "agent.ts"))) {
19
- const { runInitCommand } = await import("./init-nHgDq3Om.mjs");
38
+ const { runInitCommand } = await import("./init-COkINbH_.mjs");
20
39
  await runInitCommand({ yes }, { quiet: true });
21
40
  }
22
41
  }
@@ -41,11 +60,7 @@ const init = defineCommand({
41
60
  alias: "f",
42
61
  description: "Overwrite existing agent.ts"
43
62
  },
44
- yes: {
45
- type: "boolean",
46
- alias: "y",
47
- description: "Accept defaults (no prompts)"
48
- },
63
+ yes: sharedArgs.yes,
49
64
  skipApi: {
50
65
  type: "boolean",
51
66
  description: "Skip API key check"
@@ -56,7 +71,7 @@ const init = defineCommand({
56
71
  }
57
72
  },
58
73
  async run({ args }) {
59
- const { runInitCommand } = await import("./init-nHgDq3Om.mjs");
74
+ const { runInitCommand } = await import("./init-COkINbH_.mjs");
60
75
  await runInitCommand({
61
76
  dir: args.dir,
62
77
  template: args.template,
@@ -92,8 +107,8 @@ const dev = defineCommand({
92
107
  async run({ args }) {
93
108
  const cwd = resolveCwd();
94
109
  await ensureAgent(cwd, args.yes);
95
- await getApiKey();
96
- const { runDevCommand } = await import("./dev-BIgNj8Dt.mjs");
110
+ await ensureApiKeyInEnv();
111
+ const { runDevCommand } = await import("./dev-DCtHG1pz.mjs");
97
112
  await runDevCommand({
98
113
  cwd,
99
114
  port: args.port,
@@ -101,20 +116,41 @@ const dev = defineCommand({
101
116
  });
102
117
  }
103
118
  });
119
+ const test = defineCommand({
120
+ meta: {
121
+ name: "test",
122
+ description: "Run agent tests"
123
+ },
124
+ async run() {
125
+ const cwd = resolveCwd();
126
+ const { runTestCommand } = await import("./test-9fFn9DCf.mjs");
127
+ await runTestCommand(cwd);
128
+ }
129
+ });
104
130
  const build = defineCommand({
105
131
  meta: {
106
132
  name: "build",
107
133
  description: "Bundle and validate (no server or deploy)"
108
134
  },
109
- args: { yes: {
110
- type: "boolean",
111
- alias: "y",
112
- description: "Accept defaults (no prompts)"
113
- } },
135
+ args: {
136
+ yes: {
137
+ type: "boolean",
138
+ alias: "y",
139
+ description: "Accept defaults (no prompts)"
140
+ },
141
+ skipTests: {
142
+ type: "boolean",
143
+ description: "Skip running tests before build"
144
+ }
145
+ },
114
146
  async run({ args }) {
115
147
  const cwd = resolveCwd();
116
148
  await ensureAgent(cwd, args.yes);
117
- const { runBuildCommand } = await import("./_build-Cf_bB5Vl.mjs");
149
+ if (!args.skipTests) {
150
+ const { runVitest } = await import("./test-9fFn9DCf.mjs");
151
+ runVitest(cwd);
152
+ }
153
+ const { runBuildCommand } = await import("./_build-aW_zyPpr.mjs");
118
154
  await runBuildCommand(cwd);
119
155
  }
120
156
  });
@@ -142,7 +178,7 @@ const deploy = defineCommand({
142
178
  async run({ args }) {
143
179
  const cwd = resolveCwd();
144
180
  await ensureAgent(cwd, args.yes);
145
- const { runDeployCommand } = await import("./deploy-2OxZpIfj.mjs");
181
+ const { runDeployCommand } = await import("./deploy-DB0PeNtc.mjs");
146
182
  await runDeployCommand({
147
183
  cwd,
148
184
  ...args.server ? { server: args.server } : {},
@@ -150,6 +186,25 @@ const deploy = defineCommand({
150
186
  });
151
187
  }
152
188
  });
189
+ const del = defineCommand({
190
+ meta: {
191
+ name: "delete",
192
+ description: "Remove a deployed agent"
193
+ },
194
+ args: { server: {
195
+ type: "string",
196
+ alias: "s",
197
+ description: "Server URL"
198
+ } },
199
+ async run({ args }) {
200
+ const cwd = resolveCwd();
201
+ const { runDeleteCommand } = await import("./delete-DxECFYOp.mjs");
202
+ await runDeleteCommand({
203
+ cwd,
204
+ ...args.server ? { server: args.server } : {}
205
+ });
206
+ }
207
+ });
153
208
  const start = defineCommand({
154
209
  meta: {
155
210
  name: "start",
@@ -170,8 +225,8 @@ const start = defineCommand({
170
225
  },
171
226
  async run({ args }) {
172
227
  const cwd = resolveCwd();
173
- await getApiKey();
174
- const { runStartCommand } = await import("./start-Df8c2ciS.mjs");
228
+ await ensureApiKeyInEnv();
229
+ const { runStartCommand } = await import("./start-DQypQkOq.mjs");
175
230
  await runStartCommand({
176
231
  cwd,
177
232
  port: args.port
@@ -196,8 +251,8 @@ const secret = defineCommand({
196
251
  } },
197
252
  async run({ args }) {
198
253
  const cwd = resolveCwd();
199
- await getApiKey();
200
- const { runSecretPut } = await import("./secret-BQl3zBOS.mjs");
254
+ await ensureApiKeyInEnv();
255
+ const { runSecretPut } = await import("./secret-Zzv7fJ_3.mjs");
201
256
  await runSecretPut(cwd, args.name);
202
257
  }
203
258
  }),
@@ -213,8 +268,8 @@ const secret = defineCommand({
213
268
  } },
214
269
  async run({ args }) {
215
270
  const cwd = resolveCwd();
216
- await getApiKey();
217
- const { runSecretDelete } = await import("./secret-BQl3zBOS.mjs");
271
+ await ensureApiKeyInEnv();
272
+ const { runSecretDelete } = await import("./secret-Zzv7fJ_3.mjs");
218
273
  await runSecretDelete(cwd, args.name);
219
274
  }
220
275
  }),
@@ -225,8 +280,8 @@ const secret = defineCommand({
225
280
  },
226
281
  async run() {
227
282
  const cwd = resolveCwd();
228
- await getApiKey();
229
- const { runSecretList } = await import("./secret-BQl3zBOS.mjs");
283
+ await ensureApiKeyInEnv();
284
+ const { runSecretList } = await import("./secret-Zzv7fJ_3.mjs");
230
285
  await runSecretList(cwd);
231
286
  }
232
287
  })
@@ -261,8 +316,8 @@ const rag = defineCommand({
261
316
  },
262
317
  async run({ args }) {
263
318
  const cwd = resolveCwd();
264
- await getApiKey();
265
- const { runRagCommand } = await import("./rag-D0xqGIrS.mjs");
319
+ await ensureApiKeyInEnv();
320
+ const { runRagCommand } = await import("./rag-BNfrEr4A.mjs");
266
321
  await runRagCommand({
267
322
  url: args.url,
268
323
  cwd,
@@ -271,13 +326,86 @@ const rag = defineCommand({
271
326
  });
272
327
  }
273
328
  });
329
+ const doctor = defineCommand({
330
+ meta: {
331
+ name: "doctor",
332
+ description: "Check environment health and diagnose issues"
333
+ },
334
+ args: { port: {
335
+ type: "string",
336
+ alias: "p",
337
+ description: "Port to check availability",
338
+ default: "3000"
339
+ } },
340
+ async run({ args }) {
341
+ const cwd = resolveCwd();
342
+ const { runDoctorCommand } = await import("./doctor-bWuArZi6.mjs");
343
+ await runDoctorCommand({
344
+ cwd,
345
+ port: args.port
346
+ });
347
+ }
348
+ });
349
+ const generate = defineCommand({
350
+ meta: {
351
+ name: "generate",
352
+ description: "Generate or modify agent code using AI"
353
+ },
354
+ args: { prompt: {
355
+ type: "positional",
356
+ description: "What to generate",
357
+ required: true
358
+ } },
359
+ async run({ args }) {
360
+ const cwd = resolveCwd();
361
+ await ensureApiKeyInEnv();
362
+ const { runGenerateCommand } = await import("./generate-D7zJtqoC.mjs");
363
+ await runGenerateCommand({
364
+ cwd,
365
+ prompt: args.prompt
366
+ });
367
+ }
368
+ });
369
+ const run = defineCommand({
370
+ meta: {
371
+ name: "run",
372
+ description: "Init, generate, and deploy in one step"
373
+ },
374
+ args: {
375
+ prompt: {
376
+ type: "positional",
377
+ description: "What to build",
378
+ required: true
379
+ },
380
+ server: {
381
+ type: "string",
382
+ alias: "s",
383
+ description: "Server URL"
384
+ }
385
+ },
386
+ async run({ args }) {
387
+ await ensureAgent(resolveCwd(), true);
388
+ await ensureApiKeyInEnv();
389
+ const cwd = resolveCwd();
390
+ const { runGenerateCommand } = await import("./generate-D7zJtqoC.mjs");
391
+ await runGenerateCommand({
392
+ cwd,
393
+ prompt: args.prompt
394
+ });
395
+ const { runDeployCommand } = await import("./deploy-DB0PeNtc.mjs");
396
+ await runDeployCommand({
397
+ cwd,
398
+ ...args.server ? { server: args.server } : {}
399
+ });
400
+ }
401
+ });
274
402
  const link = defineCommand({
275
403
  meta: {
276
404
  name: "link",
277
405
  description: "Link local workspace packages into the current project (dev only)"
278
406
  },
279
407
  async run() {
280
- const { runLinkCommand } = await import("./_link-BGXGFYWa.mjs");
408
+ const { runLinkCommand } = await import("./_link-D6mmDQ0B.mjs");
281
409
  runLinkCommand(resolveCwd());
282
410
  }
283
411
  });
@@ -287,7 +415,7 @@ const unlink = defineCommand({
287
415
  description: "Restore published package versions (reverses aai link)"
288
416
  },
289
417
  async run() {
290
- const { runUnlinkCommand } = await import("./_link-BGXGFYWa.mjs");
418
+ const { runUnlinkCommand } = await import("./_link-D6mmDQ0B.mjs");
291
419
  runUnlinkCommand(resolveCwd());
292
420
  }
293
421
  });
@@ -300,18 +428,45 @@ const mainCommand = defineCommand({
300
428
  subCommands: {
301
429
  init,
302
430
  dev,
431
+ test,
303
432
  build,
304
433
  deploy,
434
+ delete: del,
305
435
  start,
306
436
  secret,
307
437
  rag,
438
+ generate,
439
+ run,
308
440
  link,
309
- unlink
441
+ unlink,
442
+ doctor
310
443
  }
311
444
  });
312
445
  if (process.env.VITEST !== "true") {
313
446
  const sub = process.argv[2];
314
- if (!sub || sub.startsWith("-")) process.argv.splice(2, 0, "init");
447
+ const knownCommands = new Set(Object.keys(mainCommand.subCommands ?? {}));
448
+ const helpFlags = new Set([
449
+ "--help",
450
+ "--version",
451
+ "-h",
452
+ "-V"
453
+ ]);
454
+ if (!sub || sub.startsWith("-") && !helpFlags.has(sub)) process.argv.splice(2, 0, "init");
455
+ else if (!(sub.startsWith("-") || knownCommands.has(sub))) {
456
+ const promptParts = [];
457
+ const flagArgs = [];
458
+ for (let i = 2; i < process.argv.length; i++) if (process.argv[i]?.startsWith("-")) {
459
+ flagArgs.push(process.argv[i]);
460
+ if (i + 1 < process.argv.length && !process.argv[i + 1]?.startsWith("-")) flagArgs.push(process.argv[++i]);
461
+ } else promptParts.push(process.argv[i]);
462
+ process.argv = [
463
+ process.argv[0],
464
+ process.argv[1],
465
+ "run",
466
+ promptParts.join(" "),
467
+ ...flagArgs
468
+ ];
469
+ }
315
470
  runMain(mainCommand);
316
471
  }
317
472
  //#endregion
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { a as getServerInfo } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, o as step } from "./_ui-C9IvR7Fh.mjs";
4
+ //#region _delete.ts
5
+ async function runDelete(opts) {
6
+ const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
7
+ let resp;
8
+ try {
9
+ resp = await fetchFn(`${opts.url}/${opts.slug}`, {
10
+ method: "DELETE",
11
+ headers: { Authorization: `Bearer ${opts.apiKey}` }
12
+ });
13
+ } catch (err) {
14
+ const hint = opts.url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
15
+ throw new Error(`delete failed: could not reach ${opts.url}\n ${hint}`, { cause: err });
16
+ }
17
+ if (resp.ok) return;
18
+ const text = await resp.text();
19
+ let hint = "";
20
+ if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
21
+ else if (resp.status === 404) hint = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
22
+ throw new Error(`delete failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
23
+ }
24
+ //#endregion
25
+ //#region delete.ts
26
+ async function runDeleteCommand(opts) {
27
+ const { cwd } = opts;
28
+ const { serverUrl, slug, apiKey } = await getServerInfo(cwd, opts.server);
29
+ await runCommand(async ({ log }) => {
30
+ log(step("Delete", slug));
31
+ await runDelete({
32
+ url: serverUrl,
33
+ slug,
34
+ apiKey
35
+ });
36
+ log(step("Deleted", `${serverUrl}/${slug}`));
37
+ });
38
+ }
39
+ //#endregion
40
+ export { runDeleteCommand };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { l as resolveServerUrl, n as generateSlug, r as getApiKey, s as readProjectConfig, u as writeProjectConfig } from "./_discover-DsorPpR_.mjs";
3
- import { a as step, i as runCommand, o as stepInfo } from "./_ui-kJIua5L9.mjs";
4
- import { buildAgentBundle } from "./_build-Cf_bB5Vl.mjs";
2
+ import { c as readProjectConfig, d as writeProjectConfig, i as getApiKey, r as generateSlug, u as resolveServerUrl } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, o as step, s as stepInfo } from "./_ui-C9IvR7Fh.mjs";
4
+ import { buildAgentBundle } from "./_build-aW_zyPpr.mjs";
5
5
  //#region _deploy.ts
6
6
  async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
7
7
  try {
@@ -17,8 +17,9 @@ async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFile
17
17
  clientFiles
18
18
  })
19
19
  });
20
- } catch {
21
- throw new Error(`deployment failed: could not reach ${url}`);
20
+ } catch (err) {
21
+ const hint = url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
22
+ throw new Error(`deployment failed: could not reach ${url}\n ${hint}`, { cause: err });
22
23
  }
23
24
  }
24
25
  const MAX_RETRIES = 20;
@@ -34,9 +35,12 @@ async function runDeploy(opts) {
34
35
  slug = generateSlug();
35
36
  continue;
36
37
  }
37
- throw new Error(`deploy failed (${resp.status}): ${text}`);
38
+ let hint = "";
39
+ if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
40
+ else if (resp.status === 413) hint = "Your bundle is too large. Try reducing dependencies or splitting your agent.";
41
+ throw new Error(`deploy failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
38
42
  }
39
- throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
43
+ throw new Error(`deploy failed: could not find an available agent slug after ${MAX_RETRIES} attempts. Try setting a custom slug in .aai/project.json.`);
40
44
  }
41
45
  //#endregion
42
46
  //#region deploy.ts
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ import { s as loadAgent } from "./_discover-D7HCLa_N.mjs";
3
+ import { a as runCommand, i as parsePort, n as info, o as step } from "./_ui-C9IvR7Fh.mjs";
4
+ import { buildAgentBundle, t as createClientDevServer } from "./_build-aW_zyPpr.mjs";
5
+ import { a as resolveServerEnv, i as loadAgentDef, n as bootServer, t as bootBackendServer } from "./_server-common-B6EXxxB2.mjs";
6
+ //#region dev.ts
7
+ /** Build, boot, and verify the server — used by `--check` mode. */
8
+ async function runCheckMode(cwd, port, log) {
9
+ const bundle = await buildAgentBundle(cwd, log);
10
+ const agentDef = await loadAgentDef(cwd);
11
+ const env = await resolveServerEnv(cwd);
12
+ const server = await bootServer(agentDef, bundle.clientDir, env, port);
13
+ log(step("Ready", `http://localhost:${port}`));
14
+ const base = `http://localhost:${port}`;
15
+ try {
16
+ const healthRes = await fetch(`${base}/health`);
17
+ if (!healthRes.ok) throw new Error(`GET /health returned ${healthRes.status}. The server started but the health endpoint failed.`);
18
+ const health = await healthRes.json();
19
+ if (health.status !== "ok") throw new Error(`GET /health returned unhealthy status: ${JSON.stringify(health)}. Check your agent.ts for errors.`);
20
+ log(step("Health", health.name ?? "ok"));
21
+ const pageRes = await fetch(`${base}/`);
22
+ if (!pageRes.ok) throw new Error(`GET / returned ${pageRes.status}. The client page failed to load.`);
23
+ const html = await pageRes.text();
24
+ if (!(html.includes("<") && html.includes("html"))) throw new Error("GET / did not return valid HTML. Check that client.tsx exists and builds correctly.");
25
+ log(step("Client", "ok"));
26
+ } catch (err) {
27
+ await server.close();
28
+ throw err;
29
+ }
30
+ await server.close();
31
+ }
32
+ async function _startDevServer(cwd, port, log, opts) {
33
+ if (opts?.check) {
34
+ await runCheckMode(cwd, port, log);
35
+ return;
36
+ }
37
+ const agent = await loadAgent(cwd);
38
+ if (!agent) throw new Error("No agent found — run `aai init` first");
39
+ const agentDef = await loadAgentDef(cwd);
40
+ const env = await resolveServerEnv();
41
+ const backendPort = port + 1;
42
+ await bootBackendServer(agentDef, env, backendPort);
43
+ if (agent.clientEntry) {
44
+ await (await createClientDevServer(cwd, backendPort, port)).listen();
45
+ log(step("Ready", `http://localhost:${port}`));
46
+ log(info("Client HMR enabled — edits to client.tsx update instantly"));
47
+ } else {
48
+ log(step("Ready", `http://localhost:${backendPort}`));
49
+ log(info("No client.tsx found — serving agent API only"));
50
+ }
51
+ log(info("Ctrl-C to quit"));
52
+ }
53
+ async function runDevCommand(opts) {
54
+ const port = parsePort(opts.port);
55
+ await runCommand(async ({ log }) => {
56
+ await _startDevServer(opts.cwd, port, log, opts.check ? { check: true } : void 0);
57
+ });
58
+ }
59
+ //#endregion
60
+ export { runDevCommand };