@alexkroman1/aai-cli 14.0.0 → 15.1.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/dist/_artifacts-BJOYGQPp.mjs +21 -0
- package/dist/_artifacts.d.ts +16 -0
- package/dist/_build-target.d.ts +172 -0
- package/dist/{_bundler-DolUCMxu.mjs → _bundler-DM0d0M7m.mjs} +1 -1
- package/dist/{_dev-server-CSMqF8PN.mjs → _dev-server-BzWB6-4y.mjs} +9 -6
- package/dist/_e2e-test-utils.d.ts +1 -1
- package/dist/{_init-CQ8idAwo.mjs → _init-Bsi3DZNJ.mjs} +1 -1
- package/dist/_server-common-De0haHr9.mjs +70 -0
- package/dist/_server-common.d.ts +20 -1
- package/dist/{_templates-CK4oKoeX.mjs → _templates-CIlJ3Vay.mjs} +1 -1
- package/dist/_templates.d.ts +1 -1
- package/dist/_vercel-output.d.ts +63 -0
- package/dist/build-BhEaxBPu.mjs +481 -0
- package/dist/build.d.ts +18 -10
- package/dist/cli.mjs +51 -23
- package/dist/{client-bundler-BJgREAh6.mjs → client-bundler-6mTLs6ny.mjs} +4 -4
- package/dist/client-bundler.d.ts +1 -1
- package/dist/client-bundler.mjs +1 -1
- package/dist/{deploy-uAJ4NukN.mjs → deploy-CGqPU5U-.mjs} +2 -2
- package/dist/{dev-DApPSaE_.mjs → dev-Bx9gYBHM.mjs} +1 -1
- package/dist/{eval-BK47A_K5.mjs → eval-B3I7FqN9.mjs} +1 -1
- package/dist/{init-DukDxECd.mjs → init-CQbj3ycf.mjs} +49 -39
- package/dist/init.d.ts +19 -10
- package/dist/scaffold/CLAUDE.md +73 -22
- package/dist/scaffold/package.json +6 -6
- package/dist/start.d.ts +112 -0
- package/dist/start.mjs +156 -0
- package/dist/{studio-CpHlNHUZ.mjs → studio-C_zuRC_z.mjs} +2 -2
- package/dist/templates/briefing-desk/agent.eval.test.ts +156 -0
- package/dist/templates/code-interpreter/agent.test.ts +103 -0
- package/dist/templates/link-digest/client.tsx +55 -3
- package/dist/templates/math-buddy/agent.test.ts +126 -0
- package/dist/templates/personal-finance/agent.test.ts +127 -0
- package/dist/templates/support-line/agent.ts +8 -0
- package/dist/templates/travel-concierge/routing.ts +64 -55
- package/dist/templates/travel-concierge/tools/cancel_action.ts +3 -1
- package/dist/templates/travel-concierge/tools/complete_or_escalate.ts +3 -1
- package/dist/templates/travel-concierge/tools/confirm_action.ts +3 -1
- package/dist/templates/web-researcher/agent.test.ts +130 -0
- package/dist/worker-bundler.d.ts +1 -1
- package/dist/worker-bundler.mjs +7 -7
- package/package.json +9 -4
- package/dist/_server-common-vILJp3it.mjs +0 -43
- package/dist/build-Mxk8gWvX.mjs +0 -108
- package/dist/scaffold/server.mjs +0 -308
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { i as installStdoutGuard, n as fail, o as writeLine, r as getOutputMode, t as CliError } from "./_output-DBP9Op_d.mjs";
|
|
3
|
-
import { n as log, o as silenceOutput } from "./_ui-DCt4qZrk.mjs";
|
|
3
|
+
import { a as parsePort, n as log, o as silenceOutput } from "./_ui-DCt4qZrk.mjs";
|
|
4
4
|
import { c as fileExists, f as readPackageJson, p as resolveCwd, s as errorMessage$1, t as AGENT_ENTRY } from "./_utils-D5JGcjiW.mjs";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { isRecord, plural } from "@alexkroman1/aai/utils";
|
|
8
|
+
import { isRecord, omitUndefined, plural } from "@alexkroman1/aai/utils";
|
|
9
9
|
import { defineCommand, runMain, showUsage } from "citty";
|
|
10
10
|
//#region src/_cli-common.ts
|
|
11
11
|
/** Shared arg definitions for citty commands. */
|
|
@@ -395,7 +395,7 @@ const list = defineExec({
|
|
|
395
395
|
args: { ...platformArgs },
|
|
396
396
|
cwd: "any",
|
|
397
397
|
async run({ args, cwd }) {
|
|
398
|
-
const { executeList } = await import("./studio-
|
|
398
|
+
const { executeList } = await import("./studio-C_zuRC_z.mjs");
|
|
399
399
|
return executeList({
|
|
400
400
|
cwd,
|
|
401
401
|
server: args.server
|
|
@@ -427,7 +427,7 @@ const pull = defineExec({
|
|
|
427
427
|
},
|
|
428
428
|
cwd: "any",
|
|
429
429
|
async run({ args, cwd }) {
|
|
430
|
-
const { executePull } = await import("./studio-
|
|
430
|
+
const { executePull } = await import("./studio-C_zuRC_z.mjs");
|
|
431
431
|
return executePull({
|
|
432
432
|
cwd,
|
|
433
433
|
project: args.project,
|
|
@@ -448,7 +448,7 @@ const push = defineExec({
|
|
|
448
448
|
},
|
|
449
449
|
cwd: "agent",
|
|
450
450
|
async run({ args, cwd }) {
|
|
451
|
-
const { executePush } = await import("./studio-
|
|
451
|
+
const { executePush } = await import("./studio-C_zuRC_z.mjs");
|
|
452
452
|
return executePush({
|
|
453
453
|
cwd,
|
|
454
454
|
server: args.server,
|
|
@@ -471,7 +471,7 @@ const publish = defineExec({
|
|
|
471
471
|
},
|
|
472
472
|
cwd: "agent",
|
|
473
473
|
async run({ args, cwd }) {
|
|
474
|
-
const { executePublish } = await import("./studio-
|
|
474
|
+
const { executePublish } = await import("./studio-C_zuRC_z.mjs");
|
|
475
475
|
return executePublish({
|
|
476
476
|
cwd,
|
|
477
477
|
server: args.server,
|
|
@@ -693,26 +693,19 @@ const init = defineExec({
|
|
|
693
693
|
template: {
|
|
694
694
|
type: "string",
|
|
695
695
|
alias: "t",
|
|
696
|
-
description: "Template to use (
|
|
696
|
+
description: "Template to use (prompted when omitted)"
|
|
697
697
|
},
|
|
698
|
-
server: sharedArgs.server,
|
|
699
698
|
yes: sharedArgs.yes,
|
|
700
|
-
json: sharedArgs.json
|
|
701
|
-
skipDeploy: {
|
|
702
|
-
type: "boolean",
|
|
703
|
-
description: "Skip deploy after scaffolding"
|
|
704
|
-
}
|
|
699
|
+
json: sharedArgs.json
|
|
705
700
|
},
|
|
706
701
|
cwd: "none",
|
|
707
702
|
async run({ args, mode }) {
|
|
708
|
-
const { executeInit } = await import("./init-
|
|
703
|
+
const { executeInit } = await import("./init-CQbj3ycf.mjs");
|
|
709
704
|
return executeInit({
|
|
710
705
|
dir: args.dir,
|
|
711
706
|
force: args.force,
|
|
712
707
|
template: args.template,
|
|
713
|
-
yes: mode === "json" ? true : args.yes
|
|
714
|
-
skipDeploy: args.skipDeploy,
|
|
715
|
-
server: args.server
|
|
708
|
+
yes: mode === "json" ? true : args.yes
|
|
716
709
|
}, mode === "json" ? { silent: true } : void 0);
|
|
717
710
|
}
|
|
718
711
|
});
|
|
@@ -736,7 +729,7 @@ const dev = defineExec({
|
|
|
736
729
|
},
|
|
737
730
|
cwd: "agent",
|
|
738
731
|
async run({ args, cwd }) {
|
|
739
|
-
const { executeDev } = await import("./dev-
|
|
732
|
+
const { executeDev } = await import("./dev-Bx9gYBHM.mjs");
|
|
740
733
|
return executeDev({
|
|
741
734
|
cwd,
|
|
742
735
|
port: args.port,
|
|
@@ -744,6 +737,35 @@ const dev = defineExec({
|
|
|
744
737
|
});
|
|
745
738
|
}
|
|
746
739
|
});
|
|
740
|
+
const start = defineExec({
|
|
741
|
+
meta: {
|
|
742
|
+
name: "start",
|
|
743
|
+
description: "Serve the built agent (production)"
|
|
744
|
+
},
|
|
745
|
+
args: {
|
|
746
|
+
port: {
|
|
747
|
+
type: "string",
|
|
748
|
+
alias: "p",
|
|
749
|
+
description: "Port to listen on"
|
|
750
|
+
},
|
|
751
|
+
host: {
|
|
752
|
+
type: "string",
|
|
753
|
+
description: "Address to bind (default: loopback)"
|
|
754
|
+
},
|
|
755
|
+
json: sharedArgs.json
|
|
756
|
+
},
|
|
757
|
+
cwd: "agent",
|
|
758
|
+
async run({ args, cwd }) {
|
|
759
|
+
const { executeStart } = await import("./start.mjs");
|
|
760
|
+
return executeStart({
|
|
761
|
+
cwd,
|
|
762
|
+
...omitUndefined({
|
|
763
|
+
port: args.port === void 0 ? void 0 : parsePort(args.port),
|
|
764
|
+
host: args.host?.trim() || void 0
|
|
765
|
+
})
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
});
|
|
747
769
|
const test = defineExec({
|
|
748
770
|
meta: {
|
|
749
771
|
name: "test",
|
|
@@ -770,7 +792,7 @@ const evalCommand = defineExec({
|
|
|
770
792
|
args: { json: sharedArgs.json },
|
|
771
793
|
cwd: "agent",
|
|
772
794
|
async run({ cwd }) {
|
|
773
|
-
const { executeEval } = await import("./eval-
|
|
795
|
+
const { executeEval } = await import("./eval-B3I7FqN9.mjs");
|
|
774
796
|
return executeEval(cwd);
|
|
775
797
|
}
|
|
776
798
|
});
|
|
@@ -788,15 +810,20 @@ const build = defineExec({
|
|
|
788
810
|
skipTypecheck: {
|
|
789
811
|
type: "boolean",
|
|
790
812
|
description: "Skip type checking before build"
|
|
813
|
+
},
|
|
814
|
+
target: {
|
|
815
|
+
type: "string",
|
|
816
|
+
description: "Deployment shape to emit (node, vercel; default: detected)"
|
|
791
817
|
}
|
|
792
818
|
},
|
|
793
819
|
cwd: "agent",
|
|
794
820
|
async run({ args, cwd }) {
|
|
795
|
-
const { executeBuild } = await import("./build-
|
|
821
|
+
const { executeBuild } = await import("./build-BhEaxBPu.mjs");
|
|
796
822
|
return executeBuild({
|
|
797
823
|
cwd,
|
|
798
824
|
skipTests: args.skipTests,
|
|
799
|
-
skipTypecheck: args.skipTypecheck
|
|
825
|
+
skipTypecheck: args.skipTypecheck,
|
|
826
|
+
target: args.target
|
|
800
827
|
});
|
|
801
828
|
}
|
|
802
829
|
});
|
|
@@ -819,7 +846,7 @@ const deploy = defineExec({
|
|
|
819
846
|
},
|
|
820
847
|
cwd: "agent",
|
|
821
848
|
async run({ args, cwd }) {
|
|
822
|
-
const { executeDeploy } = await import("./deploy-
|
|
849
|
+
const { executeDeploy } = await import("./deploy-CGqPU5U-.mjs");
|
|
823
850
|
return executeDeploy({
|
|
824
851
|
cwd,
|
|
825
852
|
server: args.server,
|
|
@@ -863,7 +890,7 @@ const templates = defineExec({
|
|
|
863
890
|
args: { json: sharedArgs.json },
|
|
864
891
|
cwd: "none",
|
|
865
892
|
async run({ mode }) {
|
|
866
|
-
const { listTemplates } = await import("./_templates-
|
|
893
|
+
const { listTemplates } = await import("./_templates-CIlJ3Vay.mjs");
|
|
867
894
|
const names = await listTemplates();
|
|
868
895
|
if (mode === "human") {
|
|
869
896
|
for (const name of names) log.message(name);
|
|
@@ -880,6 +907,7 @@ const mainCommand = defineCommand({
|
|
|
880
907
|
subCommands: {
|
|
881
908
|
init,
|
|
882
909
|
dev,
|
|
910
|
+
start,
|
|
883
911
|
test,
|
|
884
912
|
eval: evalCommand,
|
|
885
913
|
build,
|
|
@@ -81,10 +81,10 @@ const DEFAULT_OUT_DIR = ".aai/client";
|
|
|
81
81
|
* @internal — build hook for aai-server/the studio; not a supported public
|
|
82
82
|
* API and not covered by semver.
|
|
83
83
|
*/
|
|
84
|
-
async function buildClient(cwd,
|
|
84
|
+
async function buildClient(cwd, options = {}) {
|
|
85
85
|
const clientEntry = path.join(cwd, "client.tsx");
|
|
86
86
|
if (!await fileExists(clientEntry)) return {};
|
|
87
|
-
const outDir =
|
|
87
|
+
const outDir = options.outDir ?? DEFAULT_OUT_DIR;
|
|
88
88
|
const clientDir = path.join(cwd, outDir);
|
|
89
89
|
let cleanupHtml = () => {};
|
|
90
90
|
try {
|
|
@@ -93,8 +93,8 @@ async function buildClient(cwd, opts = {}) {
|
|
|
93
93
|
root: cwd,
|
|
94
94
|
base: "./",
|
|
95
95
|
logLevel: "silent",
|
|
96
|
-
...
|
|
97
|
-
...omitUndefined({ plugins:
|
|
96
|
+
...options.configFile === false && { configFile: false },
|
|
97
|
+
...omitUndefined({ plugins: options.plugins }),
|
|
98
98
|
resolve: { dedupe: DEDUPED_PEERS },
|
|
99
99
|
build: {
|
|
100
100
|
outDir,
|
package/dist/client-bundler.d.ts
CHANGED
|
@@ -27,4 +27,4 @@ export type BuildClientOptions = {
|
|
|
27
27
|
* @internal — build hook for aai-server/the studio; not a supported public
|
|
28
28
|
* API and not covered by semver.
|
|
29
29
|
*/
|
|
30
|
-
export declare function buildClient(cwd: string,
|
|
30
|
+
export declare function buildClient(cwd: string, options?: BuildClientOptions): Promise<Record<string, string>>;
|
package/dist/client-bundler.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import { a as ok } from "./_output-DBP9Op_d.mjs";
|
|
|
3
3
|
import { n as log, r as notify, t as fmtUrl } from "./_ui-DCt4qZrk.mjs";
|
|
4
4
|
import { s as errorMessage$1 } from "./_utils-D5JGcjiW.mjs";
|
|
5
5
|
import { s as updateProjectConfig } from "./_config-DYzC6WMD.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import { t as
|
|
6
|
+
import { n as resolveServerEnv } from "./_server-common-De0haHr9.mjs";
|
|
7
|
+
import { i as evalWorkerConfig, t as buildAgentBundle } from "./_bundler-DM0d0M7m.mjs";
|
|
8
8
|
import { o as resolveDeployTarget } from "./_agent-BzUeqOdj.mjs";
|
|
9
9
|
import { assertTypechecks } from "./_typecheck-gate-U3jcil8L.mjs";
|
|
10
10
|
import { n as scanWorkflowDeterminism, t as determinismWarnings } from "./_workflow-determinism-CvpqMpdh.mjs";
|
|
@@ -12,7 +12,7 @@ import { styleText } from "node:util";
|
|
|
12
12
|
async function executeDev(opts) {
|
|
13
13
|
const port = parsePort(opts.port);
|
|
14
14
|
const agentName = path.basename(path.resolve(opts.cwd));
|
|
15
|
-
const { startDevServer } = await import("./_dev-server-
|
|
15
|
+
const { startDevServer } = await import("./_dev-server-BzWB6-4y.mjs");
|
|
16
16
|
let cleanup;
|
|
17
17
|
let shuttingDown = false;
|
|
18
18
|
const onSignal = () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as ok, n as fail } from "./_output-DBP9Op_d.mjs";
|
|
3
3
|
import { n as log } from "./_ui-DCt4qZrk.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { n as resolveServerEnv } from "./_server-common-De0haHr9.mjs";
|
|
5
5
|
import { classifyVitestError, runVitest } from "./test-D032V2cA.mjs";
|
|
6
6
|
//#region src/eval.ts
|
|
7
7
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as ok } from "./_output-DBP9Op_d.mjs";
|
|
3
3
|
import { n as log, s as unwrapCancel } from "./_ui-DCt4qZrk.mjs";
|
|
4
|
-
import { c as fileExists, d as readJson, p as resolveCwd, s as errorMessage
|
|
4
|
+
import { c as fileExists, d as readJson, p as resolveCwd, s as errorMessage, t as AGENT_ENTRY } from "./_utils-D5JGcjiW.mjs";
|
|
5
5
|
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-BzUeqOdj.mjs";
|
|
6
|
+
import { listTemplates } from "./_templates-CIlJ3Vay.mjs";
|
|
6
7
|
import path from "node:path";
|
|
7
|
-
import { omitUndefined } from "@alexkroman1/aai/utils";
|
|
8
8
|
import { styleText } from "node:util";
|
|
9
9
|
import * as p from "@clack/prompts";
|
|
10
10
|
import { execa } from "execa";
|
|
@@ -39,6 +39,41 @@ async function promptProjectName(yes) {
|
|
|
39
39
|
defaultValue: DEFAULT_PROJECT_NAME
|
|
40
40
|
}), "Setup cancelled") || DEFAULT_PROJECT_NAME;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The template a non-interactive `init` gets, and the entry the selector opens
|
|
44
|
+
* on — so an author who just presses Enter lands where they used to.
|
|
45
|
+
*/
|
|
46
|
+
const DEFAULT_TEMPLATE = "simple";
|
|
47
|
+
/**
|
|
48
|
+
* Ask which template to scaffold, listing what this CLI actually ships.
|
|
49
|
+
*
|
|
50
|
+
* The options are derived from {@link listTemplates} rather than a roster kept
|
|
51
|
+
* here: that function already backs `aai templates` AND the unknown-template
|
|
52
|
+
* error, so a template added to the package shows up in the picker with no
|
|
53
|
+
* second list to update. {@link DEFAULT_TEMPLATE} is hoisted to the top and
|
|
54
|
+
* pre-selected, which is what keeps a bare `aai init` a single Enter away from
|
|
55
|
+
* the project it produced before there was a picker.
|
|
56
|
+
*
|
|
57
|
+
* Callers must not reach here when there is nobody to answer — `--yes` and
|
|
58
|
+
* JSON mode (auto-detected on a pipe) resolve the default without prompting.
|
|
59
|
+
*/
|
|
60
|
+
async function promptTemplate(list = listTemplates) {
|
|
61
|
+
const [first, ...rest] = await list();
|
|
62
|
+
if (first === void 0) return DEFAULT_TEMPLATE;
|
|
63
|
+
if (rest.length === 0) return first;
|
|
64
|
+
const names = [first, ...rest];
|
|
65
|
+
const hasDefault = names.includes(DEFAULT_TEMPLATE);
|
|
66
|
+
const ordered = hasDefault ? [DEFAULT_TEMPLATE, ...names.filter((name) => name !== DEFAULT_TEMPLATE)] : names;
|
|
67
|
+
return unwrapCancel(await p.select({
|
|
68
|
+
message: "Which template?",
|
|
69
|
+
maxItems: 12,
|
|
70
|
+
initialValue: hasDefault ? DEFAULT_TEMPLATE : first,
|
|
71
|
+
options: ordered.map((name) => name === DEFAULT_TEMPLATE ? {
|
|
72
|
+
value: name,
|
|
73
|
+
hint: "the default starting point"
|
|
74
|
+
} : { value: name })
|
|
75
|
+
}), "Setup cancelled");
|
|
76
|
+
}
|
|
42
77
|
/** Best-effort corepack enable so pnpm is available (scaffold declares packageManager: pnpm). */
|
|
43
78
|
async function ensurePnpm() {
|
|
44
79
|
await execa("corepack", ["enable"], { reject: false });
|
|
@@ -73,9 +108,14 @@ async function runPnpmInstall(cwd) {
|
|
|
73
108
|
const pnpmArgs = isDevMode() ? ["install"] : ["install", "--ignore-workspace"];
|
|
74
109
|
await execa(cmd, [...args, ...pnpmArgs], { cwd });
|
|
75
110
|
}
|
|
76
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Install deps with pnpm, reporting a failure through `warn` rather than
|
|
113
|
+
* throwing: the project is scaffolded either way, and the two warnings say how
|
|
114
|
+
* to finish the install by hand. Nothing downstream branches on the outcome —
|
|
115
|
+
* `init` stops here — so it returns nothing.
|
|
116
|
+
*/
|
|
77
117
|
async function installDeps(cwd, warn, silent) {
|
|
78
|
-
if (!await hasDeps(cwd)) return
|
|
118
|
+
if (!await hasDeps(cwd)) return;
|
|
79
119
|
await ensurePnpm();
|
|
80
120
|
try {
|
|
81
121
|
await withSpinner(silent, {
|
|
@@ -83,11 +123,9 @@ async function installDeps(cwd, warn, silent) {
|
|
|
83
123
|
done: "Dependencies installed",
|
|
84
124
|
failed: "Dependency install failed"
|
|
85
125
|
}, () => runPnpmInstall(cwd));
|
|
86
|
-
return true;
|
|
87
126
|
} catch (err) {
|
|
88
|
-
warn(`pnpm install failed: ${errorMessage
|
|
127
|
+
warn(`pnpm install failed: ${errorMessage(err)}`);
|
|
89
128
|
warn("Install pnpm (`npm install -g pnpm`), then run `pnpm install` in the project.");
|
|
90
|
-
return false;
|
|
91
129
|
}
|
|
92
130
|
}
|
|
93
131
|
/** Resolve target directory relative to the user's current directory. */
|
|
@@ -104,30 +142,9 @@ function collectWarnings() {
|
|
|
104
142
|
}
|
|
105
143
|
};
|
|
106
144
|
}
|
|
107
|
-
/** Publish after init and return deploy metadata if successful. */
|
|
108
|
-
async function tryPublish(cwd, server, warn) {
|
|
109
|
-
const { executePublish } = await import("./studio-CpHlNHUZ.mjs");
|
|
110
|
-
try {
|
|
111
|
-
const result = await executePublish({
|
|
112
|
-
cwd,
|
|
113
|
-
...omitUndefined({ server })
|
|
114
|
-
});
|
|
115
|
-
if (result.ok) return {
|
|
116
|
-
slug: result.data.slug,
|
|
117
|
-
url: result.data.url,
|
|
118
|
-
studioUrl: result.data.studioUrl
|
|
119
|
-
};
|
|
120
|
-
warn(`Publish failed: ${result.error}`);
|
|
121
|
-
return null;
|
|
122
|
-
} catch (err) {
|
|
123
|
-
warn(`Publish failed: ${errorMessage$1(err)}`);
|
|
124
|
-
warn("Your project was still created — run `aai publish` in it to retry.");
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
145
|
/** Scaffold the project, optionally showing a spinner. */
|
|
129
146
|
async function scaffoldProject(dir, cwd, template, silent) {
|
|
130
|
-
const { runInit } = await import("./_init-
|
|
147
|
+
const { runInit } = await import("./_init-Bsi3DZNJ.mjs");
|
|
131
148
|
await withSpinner(silent, {
|
|
132
149
|
start: `Creating ${dir}`,
|
|
133
150
|
done: "Project created",
|
|
@@ -150,22 +167,15 @@ async function executeInit(opts, extra) {
|
|
|
150
167
|
const monorepoRoot = getMonorepoRoot();
|
|
151
168
|
const cwd = resolveTargetDir(dir);
|
|
152
169
|
if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`${AGENT_ENTRY} already exists in this directory. Use ${styleText("cyanBright", "--force")} to overwrite.`);
|
|
153
|
-
const template = opts.template ??
|
|
170
|
+
const template = opts.template ?? (opts.yes || suppressUi ? DEFAULT_TEMPLATE : await promptTemplate());
|
|
154
171
|
const { warn, warnings } = collectWarnings();
|
|
155
172
|
await scaffoldProject(dir, cwd, template, suppressUi);
|
|
156
|
-
|
|
157
|
-
if (!installed) warn("Skipping publish because dependencies were not installed.");
|
|
158
|
-
const published = installed && !opts.skipDeploy ? await tryPublish(cwd, opts.server, warn) : null;
|
|
173
|
+
await installDeps(cwd, warn, suppressUi);
|
|
159
174
|
if (!suppressUi) printPostInitInfo(cwd, monorepoRoot);
|
|
160
175
|
const data = {
|
|
161
176
|
dir: cwd,
|
|
162
|
-
template
|
|
163
|
-
deployed: published !== null
|
|
177
|
+
template
|
|
164
178
|
};
|
|
165
|
-
if (published) {
|
|
166
|
-
data.slug = published.slug;
|
|
167
|
-
data.url = published.url;
|
|
168
|
-
}
|
|
169
179
|
if (warnings.length > 0) data.warnings = warnings;
|
|
170
180
|
return ok(data);
|
|
171
181
|
}
|
package/dist/init.d.ts
CHANGED
|
@@ -2,21 +2,32 @@ import { type CommandResult } from "./_output.ts";
|
|
|
2
2
|
type InitData = {
|
|
3
3
|
dir: string;
|
|
4
4
|
template: string;
|
|
5
|
-
deployed: boolean;
|
|
6
|
-
slug?: string;
|
|
7
|
-
url?: string;
|
|
8
5
|
/**
|
|
9
|
-
* Diagnostics a human sees as `log.warn` lines
|
|
10
|
-
*
|
|
6
|
+
* Diagnostics a human sees as `log.warn` lines — today only a failed
|
|
7
|
+
* `pnpm install`.
|
|
11
8
|
*
|
|
12
9
|
* They have to ride the result for the same reason `PushOutcome.warnings`
|
|
13
10
|
* does — `log.warn` is silenced in JSON mode and JSON mode is AUTO-DETECTED
|
|
14
|
-
* on a pipe, so a scripted `aai init` was told `{ ok: true
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
* on a pipe, so a scripted `aai init` was told `{ ok: true }` for a project
|
|
12
|
+
* whose dependencies never installed and could not tell that apart from a
|
|
13
|
+
* clean run.
|
|
17
14
|
*/
|
|
18
15
|
warnings?: string[];
|
|
19
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Ask which template to scaffold, listing what this CLI actually ships.
|
|
19
|
+
*
|
|
20
|
+
* The options are derived from {@link listTemplates} rather than a roster kept
|
|
21
|
+
* here: that function already backs `aai templates` AND the unknown-template
|
|
22
|
+
* error, so a template added to the package shows up in the picker with no
|
|
23
|
+
* second list to update. {@link DEFAULT_TEMPLATE} is hoisted to the top and
|
|
24
|
+
* pre-selected, which is what keeps a bare `aai init` a single Enter away from
|
|
25
|
+
* the project it produced before there was a picker.
|
|
26
|
+
*
|
|
27
|
+
* Callers must not reach here when there is nobody to answer — `--yes` and
|
|
28
|
+
* JSON mode (auto-detected on a pipe) resolve the default without prompting.
|
|
29
|
+
*/
|
|
30
|
+
export declare function promptTemplate(list?: () => Promise<string[]>): Promise<string>;
|
|
20
31
|
/** Build the command + args for running pnpm, routing through safe-chain when available. */
|
|
21
32
|
export declare function resolvePnpmCommand(checkSafeChain?: () => Promise<boolean>): Promise<{
|
|
22
33
|
cmd: string;
|
|
@@ -27,8 +38,6 @@ export declare function executeInit(opts: {
|
|
|
27
38
|
force?: boolean | undefined;
|
|
28
39
|
template?: string | undefined;
|
|
29
40
|
yes?: boolean | undefined;
|
|
30
|
-
skipDeploy?: boolean | undefined;
|
|
31
|
-
server?: string | undefined;
|
|
32
41
|
}, extra?: {
|
|
33
42
|
silent?: boolean | undefined;
|
|
34
43
|
}): Promise<CommandResult<InitData>>;
|
package/dist/scaffold/CLAUDE.md
CHANGED
|
@@ -133,8 +133,8 @@ gate in front of `aai build`.
|
|
|
133
133
|
|
|
134
134
|
## Running it yourself (`npm start`)
|
|
135
135
|
|
|
136
|
-
`
|
|
137
|
-
|
|
136
|
+
`aai start` serves this agent from a plain Node process — no platform account,
|
|
137
|
+
nothing managed. It is the deployment counterpart of `aai dev`:
|
|
138
138
|
|
|
139
139
|
```sh
|
|
140
140
|
npm start # http://127.0.0.1:3000
|
|
@@ -142,11 +142,18 @@ PORT=8080 HOST=0.0.0.0 npm start # bind every interface, e.g. in a container
|
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
`npm start` **builds first** (that is the `prestart` script) and then serves
|
|
145
|
-
the result: `
|
|
145
|
+
the result: `aai start` boots `.aai/worker.mjs`, the same artifact
|
|
146
146
|
`aai publish` uploads. It serves your own `client.tsx` build when there is one
|
|
147
|
-
and falls back to
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
and falls back to the prebuilt default UI shipped inside `@alexkroman1/aai-ui`.
|
|
148
|
+
|
|
149
|
+
There is no server file in your project, and that is deliberate — the boot
|
|
150
|
+
belongs to the framework, so it improves when you update rather than being
|
|
151
|
+
frozen at the moment you scaffolded. When you need to own it, import
|
|
152
|
+
`createProjectServer` from `@alexkroman1/aai-cli/start`: it builds the server
|
|
153
|
+
and binds nothing, so you decide how it is served. Building one from scratch
|
|
154
|
+
instead, `defaultClientDir()` (`@alexkroman1/aai-ui/client-dir`) is where that
|
|
155
|
+
prebuilt UI lives — the only export of `aai-ui` that runs on Node rather than
|
|
156
|
+
in the browser.
|
|
150
157
|
|
|
151
158
|
The build is what makes `tools/` work — a tool is registered by existing, and
|
|
152
159
|
the enumeration happens where the bundle is assembled, so a server that loaded
|
|
@@ -161,9 +168,31 @@ One thing to know: it binds **loopback by default**, because this server has
|
|
|
161
168
|
no request authentication of its own; set `HOST=0.0.0.0` only behind your own
|
|
162
169
|
proxy or auth.
|
|
163
170
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
`run_code` is the one feature that does not follow — it needs the platform's
|
|
172
|
+
sandbox and refuses outside one.
|
|
173
|
+
|
|
174
|
+
### Deploying to a host that wants its own entry file
|
|
175
|
+
|
|
176
|
+
`aai build --target <host>` writes the deployment that host expects into the
|
|
177
|
+
build output. Nothing host-specific lives in your project: the files are
|
|
178
|
+
generated, gitignored, and rewritten by the host's own build.
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
aai build --target vercel # writes .vercel/output/ (Build Output API v3)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
You rarely type it. The target is detected from the host's own build
|
|
185
|
+
environment, so `vercel deploy` (or a git push) picks it up with nothing
|
|
186
|
+
configured; `--target node`, the default everywhere else, emits nothing extra
|
|
187
|
+
and is what `npm start` runs.
|
|
188
|
+
|
|
189
|
+
One thing to know before deploying a VOICE agent to a serverless host: the
|
|
190
|
+
session is a WebSocket, so the host has to support one. Vercel does — it hands
|
|
191
|
+
the function the raw upgrade, and the emitted entry passes it to the same
|
|
192
|
+
server `aai dev` runs. A host that serves only request/response still runs the
|
|
193
|
+
HTTP surface — `/health`, `/client-config`,
|
|
194
|
+
`/workflows/*` and your static assets — which is everything a workflow app
|
|
195
|
+
needs and none of what a voice agent needs.
|
|
167
196
|
|
|
168
197
|
## Project structure
|
|
169
198
|
|
|
@@ -1199,11 +1228,23 @@ statement about pipeline mode, not about the SDK.
|
|
|
1199
1228
|
|
|
1200
1229
|
### Answering a phone call
|
|
1201
1230
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1231
|
+
**Say which carriers may call, and `WS /phone` is served for exactly those.**
|
|
1232
|
+
`telephony` is an allow-list on `agent()`, and it is the whole of the wiring:
|
|
1233
|
+
|
|
1234
|
+
```ts
|
|
1235
|
+
import { agent } from "@alexkroman1/aai";
|
|
1236
|
+
|
|
1237
|
+
export default agent({
|
|
1238
|
+
name: "Support",
|
|
1239
|
+
greeting: "Support line — what's happened?",
|
|
1240
|
+
// The carrier this agent's number is with. `true` admits every carrier this
|
|
1241
|
+
// build decodes; omit the field and `/phone` is not served at all.
|
|
1242
|
+
telephony: ["twilio"],
|
|
1243
|
+
});
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
Point the carrier at the deployed agent with a `carrier` query parameter naming
|
|
1247
|
+
who is dialling:
|
|
1207
1248
|
|
|
1208
1249
|
```text
|
|
1209
1250
|
wss://<your-agent-url>/phone?carrier=twilio
|
|
@@ -1211,15 +1252,25 @@ wss://<your-agent-url>/phone?carrier=telnyx
|
|
|
1211
1252
|
```
|
|
1212
1253
|
|
|
1213
1254
|
Twilio and Telnyx are the two carriers this build decodes (`CARRIER_CODECS`);
|
|
1214
|
-
an unknown `carrier` is declined at the upgrade
|
|
1215
|
-
|
|
1255
|
+
an unknown `carrier` is declined at the upgrade with a `400`, and a real one
|
|
1256
|
+
this agent did not declare with a `404`. Both speak 8 kHz mu-law, which the
|
|
1257
|
+
bridge transcodes in both directions, so the agent, its tools and its slots
|
|
1216
1258
|
behave exactly as they do in the browser — a phone call is a transport, not a
|
|
1217
|
-
mode. Nothing about `agent.ts` changes to support one.
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1259
|
+
mode. Nothing else about `agent.ts` changes to support one.
|
|
1260
|
+
|
|
1261
|
+
**An agent that declares nothing answers no carrier**, which is a change from
|
|
1262
|
+
earlier releases: every voice agent used to serve both carriers' framing from
|
|
1263
|
+
the moment it booted, whether or not it had a phone number. `/phone` is the one
|
|
1264
|
+
door dialled from OUTSIDE your deployment, by a carrier following a number, so
|
|
1265
|
+
it is opened by a sentence in `agent.ts` rather than inherited. `aai dev` and a
|
|
1266
|
+
deployed sandbox honour the same declaration, so a call refused after a deploy
|
|
1267
|
+
is refused on your laptop too.
|
|
1268
|
+
|
|
1269
|
+
`telephony: false` is the same refusal stated out loud, and an operator can pass
|
|
1270
|
+
`telephony` to `createAgentServer` to override one deployment of an agent that
|
|
1271
|
+
does declare a carrier. If you are embedding the runtime yourself rather than
|
|
1272
|
+
deploying, the pieces are `createTelephonyBridge`, `startTelephonySession`,
|
|
1273
|
+
`TELEPHONY_PATH` and `carrierByName`, all on `@alexkroman1/aai-runtime`.
|
|
1223
1274
|
|
|
1224
1275
|
**Silence nudge (pipeline only):** set `silenceTimeoutMs` to make the
|
|
1225
1276
|
assistant proactively take a turn after that much user silence (e.g.
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "aai dev",
|
|
9
9
|
"prestart": "aai build --skip-tests",
|
|
10
|
-
"start": "
|
|
10
|
+
"start": "aai start",
|
|
11
11
|
"build": "aai build",
|
|
12
12
|
"test": "vitest run --exclude \"**/*.eval.test.*\"",
|
|
13
13
|
"test:agent": "aai test",
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
"publish:agent": "aai publish"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@alexkroman1/aai": "^
|
|
19
|
-
"@alexkroman1/aai-
|
|
20
|
-
"@alexkroman1/aai-
|
|
18
|
+
"@alexkroman1/aai": "^15.1.0",
|
|
19
|
+
"@alexkroman1/aai-cli": "^15.1.0",
|
|
20
|
+
"@alexkroman1/aai-runtime": "^15.1.0",
|
|
21
|
+
"@alexkroman1/aai-ui": "^15.1.0",
|
|
21
22
|
"react": "^19.2.8",
|
|
22
23
|
"react-dom": "^19.2.8",
|
|
23
24
|
"tailwindcss": "^4.0.0",
|
|
@@ -25,9 +26,8 @@
|
|
|
25
26
|
"zod": "^4.5.4"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@alexkroman1/aai-cli": "^14.0.0",
|
|
29
29
|
"@tailwindcss/vite": "^4.3.3",
|
|
30
|
-
"@types/node": "^
|
|
30
|
+
"@types/node": "^24.10.1",
|
|
31
31
|
"@types/react": "^19.2.18",
|
|
32
32
|
"@types/react-dom": "^19.2.5",
|
|
33
33
|
"@vitejs/plugin-react": "^6.1.1",
|