@alexkroman1/aai-cli 9.1.0 → 10.0.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.
Files changed (81) hide show
  1. package/dist/{_bundler-CDuYl5Gb.mjs → _bundler-B31MqYaD.mjs} +7 -33
  2. package/dist/_bundler.d.ts +3 -41
  3. package/dist/{_dev-server-BAR8Ya43.mjs → _dev-server-Bo5dSBzQ.mjs} +140 -44
  4. package/dist/_dev-server.d.ts +1 -8
  5. package/dist/_dev-vite-config.d.ts +21 -0
  6. package/dist/{_init-BNotRgV1.mjs → _init-BURbdHNM.mjs} +1 -1
  7. package/dist/{_slug-api--ZBmIGH-.mjs → _slug-api-CfGQq1Tt.mjs} +1 -1
  8. package/dist/{_templates-4WcKOjS5.mjs → _templates-0Zr2z6yA.mjs} +37 -2
  9. package/dist/_templates.d.ts +29 -0
  10. package/dist/{build-DvDdSwAS.mjs → build-DKC2e9o_.mjs} +1 -2
  11. package/dist/cli.mjs +46 -22
  12. package/dist/{delete-8pjH8n8n.mjs → delete-X_CRgCf6.mjs} +1 -1
  13. package/dist/{deploy-CjU3e-3P.mjs → deploy-CchW5pmw.mjs} +2 -2
  14. package/dist/{dev-dFzdvwa7.mjs → dev-BfVl1uBA.mjs} +1 -1
  15. package/dist/{init-DK7GpIF9.mjs → init-BRfoc2EK.mjs} +2 -2
  16. package/dist/{logs-D2Yhqe2w.mjs → logs-hWnJ66Bl.mjs} +2 -2
  17. package/dist/scaffold/CLAUDE.md +162 -54
  18. package/dist/scaffold/package.json +4 -6
  19. package/dist/scaffold/server.mjs +12 -23
  20. package/dist/{secret-CwgDLpSy.mjs → secret-B-3T5tvr.mjs} +2 -2
  21. package/dist/{studio-D3-HWIfk.mjs → studio-wVWNLREn.mjs} +4 -3
  22. package/dist/templates/call-audit/agent.eval.test.ts +1 -1
  23. package/dist/templates/call-audit/agent.test.ts +80 -8
  24. package/dist/templates/call-audit/client.tsx +87 -3
  25. package/dist/templates/call-audit/workflows/audit.ts +52 -32
  26. package/dist/templates/call-audit/workflows/ingest.ts +15 -15
  27. package/dist/templates/call-audit/workflows/media.ts +1 -1
  28. package/dist/templates/call-audit/workflows/summarize.ts +0 -4
  29. package/dist/templates/link-digest/agent.eval.test.ts +4 -2
  30. package/dist/templates/link-digest/agent.test.ts +25 -5
  31. package/dist/templates/link-digest/client.tsx +65 -7
  32. package/dist/templates/link-digest/workflows/digest.ts +39 -29
  33. package/dist/templates/podcast-digest/agent.eval.test.ts +5 -5
  34. package/dist/templates/podcast-digest/agent.test.ts +108 -2
  35. package/dist/templates/podcast-digest/client.tsx +89 -8
  36. package/dist/templates/podcast-digest/workflows/digest.ts +67 -48
  37. package/dist/templates/podcast-digest/workflows/feeds.ts +1 -4
  38. package/dist/templates/podcast-digest/workflows/slack.ts +5 -6
  39. package/dist/templates/recap-workflow/agent.eval.test.ts +72 -8
  40. package/dist/templates/recap-workflow/agent.test.ts +323 -83
  41. package/dist/templates/recap-workflow/shared.ts +4 -3
  42. package/dist/templates/recap-workflow/workflows/recap.ts +322 -86
  43. package/dist/templates/recap-workflow/workflows/tokens.ts +21 -0
  44. package/dist/templates/redline/agent.eval.test.ts +1 -1
  45. package/dist/templates/redline/agent.test.ts +1 -1
  46. package/dist/templates/redline/client.tsx +83 -3
  47. package/dist/templates/redline/workflows/redline.ts +26 -23
  48. package/dist/templates/research-workflow/agent.eval.test.ts +9 -8
  49. package/dist/templates/research-workflow/agent.test.ts +32 -6
  50. package/dist/templates/research-workflow/agent.ts +4 -4
  51. package/dist/templates/research-workflow/shared.ts +4 -3
  52. package/dist/templates/research-workflow/workflows/prompts.ts +1 -1
  53. package/dist/templates/research-workflow/workflows/research.ts +35 -38
  54. package/dist/templates/spoken-summary/agent.eval.test.ts +3 -3
  55. package/dist/templates/spoken-summary/agent.test.ts +10 -8
  56. package/dist/templates/spoken-summary/client.tsx +72 -3
  57. package/dist/templates/spoken-summary/workflows/summarize.ts +25 -21
  58. package/dist/templates/spoken-summary/workflows/transcribe.ts +15 -18
  59. package/dist/templates/transcription-workflow/agent.eval.test.ts +1 -1
  60. package/dist/templates/transcription-workflow/agent.test.ts +720 -16
  61. package/dist/templates/transcription-workflow/agent.ts +6 -4
  62. package/dist/templates/transcription-workflow/client.tsx +106 -308
  63. package/dist/templates/transcription-workflow/recover.test.ts +141 -0
  64. package/dist/templates/transcription-workflow/recover.ts +130 -0
  65. package/dist/templates/transcription-workflow/run-panel.tsx +203 -0
  66. package/dist/templates/transcription-workflow/total-latency.tsx +144 -0
  67. package/dist/templates/transcription-workflow/workflows/batch.ts +21 -24
  68. package/dist/templates/transcription-workflow/workflows/downsample.ts +273 -0
  69. package/dist/templates/transcription-workflow/workflows/normalize.ts +17 -40
  70. package/dist/templates/transcription-workflow/workflows/stream.ts +311 -38
  71. package/dist/templates/transcription-workflow/workflows/transcribe.ts +69 -32
  72. package/dist/templates/transcription-workflow/workflows/wav.ts +15 -4
  73. package/dist/worker-bundler.d.ts +0 -14
  74. package/dist/worker-bundler.mjs +149 -1
  75. package/dist/{workflow-BflATMmU.mjs → workflow-BBu5oEDw.mjs} +84 -10
  76. package/dist/workflow.d.ts +1 -0
  77. package/package.json +4 -6
  78. package/dist/_workflow-scan.d.ts +0 -108
  79. package/dist/worker-bundler-CCVEDjm1.mjs +0 -650
  80. package/dist/workflow-bundler.d.ts +0 -138
  81. package/dist/{_studio-CKrsixd0.mjs → _studio-B1waXMuR.mjs} +1 -1
@@ -3,9 +3,9 @@
3
3
  * The pure half of the transcription desk: reading a WAV header, deciding where
4
4
  * to cut, and writing a header back over each cut.
5
5
  *
6
- * No directive in this file, and that is legal — the Workflow DevKit's builder
7
- * scans `workflows/` and transforms only what carries a `"use workflow"` /
8
- * `"use step"` body, so an ordinary module can sit beside them. It is a separate
6
+ * Nothing in this file is a step or a body, and that is legal — a body is
7
+ * whatever is handed a `ctx`, so an ordinary module can sit beside one. It is a
8
+ * separate
9
9
  * file because everything here is a pure function of a journaled value, which is
10
10
  * what makes it testable without a run at all: `transcribe.ts`'s spec drives
11
11
  * these directly.
@@ -43,7 +43,18 @@
43
43
  * so they keep naming the `ffmpeg` line that fixes the file.
44
44
  */
45
45
 
46
- /** What the sync endpoint will accept in one request. */
46
+ /**
47
+ * What the sync endpoint will accept in one request.
48
+ *
49
+ * **Measured against the live endpoint, the binding limit is a 30-second WALL
50
+ * CLOCK budget rather than this**, and that budget covers the upload as well as
51
+ * the transcription: a 92-second segment that is 17.66 MB comes back
52
+ * `504 — request exceeded 30.0s` well inside the documented cap. The constant is
53
+ * left alone because it is what the service DOCUMENTS and the discrepancy is
54
+ * unconfirmed; what closes the gap today is `downsample.ts`, which makes each
55
+ * request six times lighter so the deadline stops binding. Revisit both together
56
+ * once the real cap is settled — this number is what `planSegments` cuts to.
57
+ */
47
58
  export const MAX_SEGMENT_SECONDS = 120;
48
59
 
49
60
  /**
@@ -1,5 +1,4 @@
1
1
  import { type PluginOption } from "vite";
2
- import { type WorkflowBundleOutput } from "./workflow-bundler.ts";
3
2
  /**
4
3
  * Options for worker bundling.
5
4
  *
@@ -25,19 +24,6 @@ export type BuildWorkerOptions = {
25
24
  * rebuild would turn the watch loop from sub-second into multi-second.
26
25
  */
27
26
  runtime?: boolean;
28
- /**
29
- * The project's compiled workflows, when it declares any.
30
- *
31
- * Embedded in the worker as two string exports rather than shipped as extra
32
- * files, because the guest's `bundle/load` contract is ONE ESM string. See
33
- * `wrapperEntrySource`.
34
- *
35
- * It also switches on the client transform (`workflowClientPlugin`), which is
36
- * what puts a `workflowId` on the agent's own copy of each body. Passing the
37
- * strings without it produces a bundle that serves every workflow route and
38
- * cannot start a run.
39
- */
40
- workflows?: WorkflowBundleOutput | undefined;
41
27
  };
42
28
  /**
43
29
  * Bundle agent.ts into a single ESM string for the sandbox worker.
@@ -1,3 +1,151 @@
1
1
  #!/usr/bin/env node
2
- import { t as buildWorker } from "./worker-bundler-CCVEDjm1.mjs";
2
+ import { i as errorCode } from "./_utils-B8QmtFhK.mjs";
3
+ import { n as withPreservedNodeEnv } from "./_vite-env-BNveawd1.mjs";
4
+ import path from "node:path";
5
+ import fs from "node:fs/promises";
6
+ import { invariant } from "@alexkroman1/aai/internal";
7
+ import { build } from "vite";
8
+ //#region worker-bundler.ts
9
+ /**
10
+ * Generated wrapper entry, written under `.aai/` for the duration of the
11
+ * build (the CLI's own scratch dir — dot-paths are ignored by the dev
12
+ * watcher, and the studio's workspace materialization never writes there).
13
+ */
14
+ const WRAPPER_ENTRY_REL = path.join(".aai", "worker-entry.ts");
15
+ /** Extensions a tool module may be authored in (mirrors the SDK's registry). */
16
+ const TOOL_MODULE_EXT_RE = /\.(?:m?ts|tsx)$/;
17
+ /** A co-located spec is not a tool. */
18
+ const TOOL_SPEC_RE = /\.(?:test|spec)\.[^.]+$/;
19
+ /**
20
+ * The project's `tools/` directory, as file names relative to it.
21
+ *
22
+ * **This is the whole of "discovery", and it happens HERE because the guest has
23
+ * no filesystem.** A sandbox is handed one ESM string, so the only place a
24
+ * directory can be turned into modules is where the bundle is assembled — the
25
+ * same lowering eve does (`readdir` → static import list, which the bundler then
26
+ * follows). The names are validated by `toolRegistry` at bundle-evaluation time
27
+ * rather than here, so one implementation owns the rules.
28
+ *
29
+ * Sorted, so the emitted entry is byte-stable for a given directory: an entry
30
+ * that reordered per readdir would change the bundle hash for no reason.
31
+ */
32
+ async function discoverToolFiles(cwd) {
33
+ const root = path.join(cwd, "tools");
34
+ let entries;
35
+ try {
36
+ entries = await fs.readdir(root, {
37
+ withFileTypes: true,
38
+ recursive: true
39
+ });
40
+ } catch (err) {
41
+ if (errorCode(err) === "ENOENT") return [];
42
+ throw err;
43
+ }
44
+ return entries.filter((e) => e.isFile() && TOOL_MODULE_EXT_RE.test(e.name) && !TOOL_SPEC_RE.test(e.name)).map((e) => path.relative(root, path.join(e.parentPath, e.name)).split(path.sep).join("/")).sort();
45
+ }
46
+ /** The prose slot: one file, beside `agent.ts`, named by convention. */
47
+ const SYSTEM_PROMPT_FILE = "system-prompt.md";
48
+ /**
49
+ * Whether the project keeps its system prompt in a file.
50
+ *
51
+ * The other half of "a file beside `agent.ts` can BE the thing", and it happens
52
+ * here for the same reason `discoverToolFiles` does — the guest has no
53
+ * filesystem, so the read belongs where the bundle is assembled. What the file
54
+ * MEANS is `withSystemPrompt`'s to decide (the author may have imported and
55
+ * composed it, in which case discovery must not apply it twice); this only
56
+ * answers whether there is one.
57
+ */
58
+ async function hasSystemPromptFile(cwd) {
59
+ const nested = path.join(cwd, "system-prompt");
60
+ if ((await fs.stat(nested).catch(() => void 0))?.isDirectory() === true) throw new Error(`${nested} is a directory. A system prompt is ONE file — rename it to ${SYSTEM_PROMPT_FILE}, or import the pieces yourself and compose them into \`systemPrompt\`. There is deliberately no concatenation order for a directory.`);
61
+ try {
62
+ return (await fs.stat(path.join(cwd, SYSTEM_PROMPT_FILE))).isFile();
63
+ } catch (err) {
64
+ if (errorCode(err) === "ENOENT") return false;
65
+ throw err;
66
+ }
67
+ }
68
+ function wrapperEntrySource(runtime, toolFiles, systemPromptFile) {
69
+ const toolImports = toolFiles.map((file, i) => `import * as __aaiTool${i} from "../tools/${file}";`).join("\n");
70
+ const toolEntries = toolFiles.map((file, i) => ` ${JSON.stringify(`tools/${file}`)}: __aaiTool${i},`).join("\n");
71
+ return `import def from "../agent.ts";
72
+ import { agentToolsToSchemas, toAgentConfig, toolRegistry, withSystemPrompt, withTools } from "@alexkroman1/aai/manifest";
73
+ ${runtime ? `import { createRuntime } from "@alexkroman1/aai-runtime";` : ""}
74
+ ${systemPromptFile ? `import __aaiSystemPrompt from "../${SYSTEM_PROMPT_FILE}?raw";` : ""}
75
+ ${toolImports}
76
+ // A tool's name is its file name. The map is built here rather than written in
77
+ // agent.ts, so a file that exists is a tool the model can call — there is no
78
+ // registration step to forget.
79
+ //
80
+ // \`system-prompt.md\` arrives the same way, and the \`?raw\` lives HERE rather
81
+ // than in the author's own \`agent.ts\`: it is a Vite convention, and the whole
82
+ // point of generating this entry is that a bundler feature never has to appear
83
+ // in user-authored space.
84
+ const __aaiAgent = ${systemPromptFile ? "withSystemPrompt(" : ""}withTools(
85
+ def,
86
+ toolRegistry({
87
+ ${toolEntries}
88
+ }),
89
+ )${systemPromptFile ? ", __aaiSystemPrompt)" : ""};
90
+ export default __aaiAgent;
91
+ export const __aaiConfig = {
92
+ ...toAgentConfig(__aaiAgent),
93
+ toolSchemas: agentToolsToSchemas(__aaiAgent.tools ?? {}),
94
+ };
95
+ ${runtime ? `export const __aaiCreateRuntime = (opts: Record<string, unknown>) =>
96
+ createRuntime({ ...opts, agent: __aaiAgent });
97
+ ` : ""}`;
98
+ }
99
+ /**
100
+ * Bundle agent.ts into a single ESM string for the sandbox worker.
101
+ *
102
+ * Zod is bundled in — zod 4's `Function()` usage is wrapped in try/catch
103
+ * and gracefully degrades in restricted environments like Deno.
104
+ *
105
+ * @internal — build hook for aai-server/the studio; not a supported public
106
+ * API and not covered by semver.
107
+ */
108
+ async function buildWorker(cwd, opts = {}) {
109
+ const wrapperPath = path.join(cwd, WRAPPER_ENTRY_REL);
110
+ const [, toolFiles, systemPromptFile] = await Promise.all([
111
+ fs.mkdir(path.dirname(wrapperPath), { recursive: true }),
112
+ discoverToolFiles(cwd),
113
+ hasSystemPromptFile(cwd)
114
+ ]);
115
+ await fs.writeFile(wrapperPath, wrapperEntrySource(opts.runtime !== false, toolFiles, systemPromptFile), "utf-8");
116
+ const plugins = opts.plugins ?? [];
117
+ let result;
118
+ try {
119
+ result = await withPreservedNodeEnv(() => build({
120
+ root: cwd,
121
+ logLevel: "silent",
122
+ ...opts.configFile === false && { configFile: false },
123
+ ...plugins.length > 0 && { plugins },
124
+ ssr: { noExternal: true },
125
+ build: {
126
+ ssr: true,
127
+ lib: {
128
+ entry: wrapperPath,
129
+ formats: ["es"],
130
+ fileName: "worker"
131
+ },
132
+ target: "node20",
133
+ minify: opts.minify ? "oxc" : false,
134
+ write: false,
135
+ rollupOptions: { output: {
136
+ entryFileNames: "[name].js",
137
+ codeSplitting: false
138
+ } }
139
+ }
140
+ }));
141
+ } finally {
142
+ await fs.rm(wrapperPath, { force: true }).catch(() => void 0);
143
+ }
144
+ const output = Array.isArray(result) ? result[0] : result;
145
+ invariant(output !== void 0, "bundle.worker.output");
146
+ const chunk = output.output.find((o) => o.type === "chunk" && o.isEntry);
147
+ invariant(chunk !== void 0, "bundle.worker.entry-chunk", () => ({ kinds: output.output.map((o) => o.type) }));
148
+ return chunk.code;
149
+ }
150
+ //#endregion
3
151
  export { buildWorker };
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { a as ok, n as fail } from "./_output-CKkmWs7i.mjs";
2
+ import { a as ok, n as fail, t as CliError } from "./_output-CKkmWs7i.mjs";
3
3
  import { n as log } from "./_ui-u7T4YooX.mjs";
4
+ import { i as readProjectConfig } from "./_config-CmJOFsAP.mjs";
4
5
  import { n as getServerInfo } from "./_agent-BTwZJu4P.mjs";
5
6
  import { errorMessage, omitUndefined } from "@alexkroman1/aai/utils";
6
7
  import { createWorkflowApiClient } from "@alexkroman1/aai/workflow-api";
@@ -35,32 +36,105 @@ import { createWorkflowApiClient } from "@alexkroman1/aai/workflow-api";
35
36
  /** Runs listed when the caller names no limit — a terminal is not a dashboard. */
36
37
  const DEFAULT_RUN_LIMIT = 20;
37
38
  /**
39
+ * The base URL {@link createWorkflowApiClient} is given for `--agent`.
40
+ *
41
+ * A dev server has no slug: `createServer` mounts the workflow API at
42
+ * `WORKFLOW_API_PREFIX` on the ORIGIN, where the platform serves it under
43
+ * `/:slug`. So targeting one is not a matter of a different origin — it is the
44
+ * absence of the path segment, which nothing in this command could express.
45
+ *
46
+ * Validated rather than interpolated. This value is joined into a request path,
47
+ * and the CLI's standing rule is that anything reaching a URL is checked at the
48
+ * one point it becomes a target (`resolveDeployTarget`'s slug guard is the same
49
+ * rule). It is also the only origin here that `resolveServerUrl` does not
50
+ * produce, so stripping the trailing slash is this function's job — the join
51
+ * site deliberately carries no copy of that.
52
+ *
53
+ * No trust check, deliberately, and the asymmetry with `--server` is the point:
54
+ * `--server` pairs an origin with the user's PLATFORM API KEY, which is why a
55
+ * repo-supplied loopback URL is refused there. Nothing credentialed goes to
56
+ * `--agent` — the workflow API takes the agent's own bearer or none — so there
57
+ * is nothing for a hostile origin to collect, and requiring `aai login` to read
58
+ * runs off a server on your own laptop is the defect this flag exists for.
59
+ */
60
+ function agentBaseUrl(raw) {
61
+ const url = URL.parse(raw);
62
+ if (url === null) throw new CliError("bad_agent_url", `--agent is not a URL: ${JSON.stringify(raw)}`, HINT_URL);
63
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw new CliError("bad_agent_url", `--agent must be http or https, not ${url.protocol.replace(":", "")}`, HINT_URL);
64
+ return raw.replace(/\/+$/, "");
65
+ }
66
+ /**
38
67
  * A client for the agent's workflow API, plus the bearer when one was given.
39
68
  *
40
- * `getServerInfo` is what turns "this directory" into an origin and a published
41
- * slug, and it already refuses a project that has never been deployed with the
42
- * sentence naming `aai publish`. The client is handed the AGENT's base URL and
43
- * appends the route prefix itself, so the `/workflows` literal is not spelled
44
- * here it is the same constant the server matches on.
69
+ * Two ways in. `--agent <url>` names a server the caller is running themselves
70
+ * `aai dev`, or the scaffold's `npm start` and takes that URL as the base:
71
+ * no project config, no published slug, and no `ensureApiKey`, none of which
72
+ * such a server has or wants. Otherwise `getServerInfo` turns "this directory"
73
+ * into a platform origin and a published slug.
74
+ *
75
+ * The client is handed the AGENT's base URL and appends the route prefix itself,
76
+ * so the `/workflows` literal is not spelled here — it is the same constant the
77
+ * server matches on.
45
78
  *
46
79
  * `serverUrl` is joined as-is: `resolveServerUrl` is the single producer of
47
- * every origin that reaches here and strips trailing slashes once, at
80
+ * every origin that reaches THAT branch and strips trailing slashes once, at
48
81
  * resolution time, precisely so join sites do not each carry a copy. The copy
49
82
  * this used to hold also DISAGREED with it — `/\/$/` takes one slash where the
50
83
  * upstream `/\/+$/` takes all — so the two would have differed on the only
51
84
  * input either was written for.
85
+ *
86
+ * **The no-deployment failure is raised HERE rather than by
87
+ * `requireDeployedSlug`, and the ordering is why.** `getServerInfo` resolves the
88
+ * API key BEFORE it looks for a slug, so in an undeployed project the first
89
+ * thing a developer running `aai dev` saw was `not_logged_in` — pointing at
90
+ * `aai login` for a command that never sends the key it was asking for, with
91
+ * the real cause two errors away. Reading the project config first puts the
92
+ * cause first and lets the sentence name every way out: publish it, or point at
93
+ * the server already running.
52
94
  */
53
95
  async function target(cwd, opts) {
96
+ if (opts.agent !== void 0) {
97
+ const baseUrl = agentBaseUrl(opts.agent);
98
+ return {
99
+ api: createWorkflowApiClient({
100
+ baseUrl,
101
+ ...omitUndefined({ token: opts.token })
102
+ }),
103
+ name: baseUrl
104
+ };
105
+ }
106
+ if (!(await readProjectConfig(cwd))?.slug) throw new CliError("no_deployment", NO_DEPLOYMENT, HINT_AGENT);
54
107
  const { serverUrl, slug } = await getServerInfo(cwd, opts.server);
55
108
  return {
56
109
  api: createWorkflowApiClient({
57
110
  baseUrl: `${serverUrl}/${slug}`,
58
111
  ...omitUndefined({ token: opts.token })
59
112
  }),
60
- slug
113
+ name: slug
61
114
  };
62
115
  }
63
116
  /**
117
+ * What a project with no deployment is told, and why it names two ways out.
118
+ *
119
+ * `requireDeployedSlug`'s sentence — "run `aai publish` first" — is right for
120
+ * `aai secret` and `aai delete`, which have nothing to talk to until the agent
121
+ * is on the platform. It is wrong here often enough to be a defect: a workflow
122
+ * API is the one agent surface that is fully live under `aai dev`, so the
123
+ * developer being told to publish frequently has the thing they asked about
124
+ * answering on localhost already.
125
+ */
126
+ const NO_DEPLOYMENT = "This project has no deployed agent, and no --agent URL was given — so there is nothing for `aai workflow` to ask.";
127
+ /**
128
+ * What a malformed `--agent` is told.
129
+ *
130
+ * Its own hint rather than {@link HINT_AGENT}: the caller already knows about
131
+ * the flag — they typed it — so repeating "run `aai publish`" answers a
132
+ * question they did not ask.
133
+ */
134
+ const HINT_URL = "Pass a full origin, e.g. --agent http://localhost:3000";
135
+ /** How to reach a server you are running yourself. Paired with {@link NO_DEPLOYMENT}. */
136
+ const HINT_AGENT = "Run `aai publish` to deploy it, or pass --agent <url> to target a server you are already running — `--agent http://localhost:3000` for `aai dev`, which needs no login and no slug.";
137
+ /**
64
138
  * Run one call, turning a rejection into this command's failure result.
65
139
  *
66
140
  * The client throws with the AGENT'S own sentence — an unknown workflow names
@@ -93,11 +167,11 @@ async function attempt(code, call) {
93
167
  }
94
168
  /** `aai workflow list` — what this agent declares. */
95
169
  async function executeWorkflowList(cwd, opts) {
96
- const { api, slug } = await target(cwd, opts);
170
+ const { api, name } = await target(cwd, opts);
97
171
  const res = await attempt("workflow_list_failed", () => api.list());
98
172
  if (!res.ok) return res;
99
173
  const workflows = res.value;
100
- if (workflows.length === 0) log.info(`${slug} declares no workflows`);
174
+ if (workflows.length === 0) log.info(`${name} declares no workflows`);
101
175
  else for (const w of workflows) log.info(`${w.name}${w.description ? ` — ${w.description}` : ""}`);
102
176
  return ok({ workflows });
103
177
  }
@@ -39,6 +39,7 @@ type Run = WorkflowRunSnapshot;
39
39
  type WorkflowOptions = {
40
40
  server?: string | undefined;
41
41
  token?: string | undefined;
42
+ agent?: string | undefined;
42
43
  };
43
44
  /** `aai workflow list` — what this agent declares. */
44
45
  export declare function executeWorkflowList(cwd: string, opts: WorkflowOptions): Promise<CommandResult<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-cli",
3
- "version": "9.1.0",
3
+ "version": "10.0.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aai": "bin.mjs"
@@ -33,7 +33,6 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "@clack/prompts": "^1.7.0",
36
- "@workflow/builders": "4.1.7",
37
36
  "chokidar": "^5.0.0",
38
37
  "citty": "^0.2.2",
39
38
  "env-paths": "^4.0.0",
@@ -44,16 +43,15 @@
44
43
  "p-timeout": "^7.0.1",
45
44
  "vite": "^8.2.1",
46
45
  "zod": "^4.4.3",
47
- "@alexkroman1/aai": "9.1.0",
48
- "@alexkroman1/aai-runtime": "9.1.0",
49
- "@alexkroman1/aai-ui": "9.1.0"
46
+ "@alexkroman1/aai": "10.0.0",
47
+ "@alexkroman1/aai-runtime": "10.0.0",
48
+ "@alexkroman1/aai-ui": "10.0.0"
50
49
  },
51
50
  "devDependencies": {
52
51
  "playwright": "^1.62.1",
53
52
  "tsdown": "^0.22.14",
54
53
  "verdaccio": "^6.9.2",
55
54
  "vitest": "^4.1.10",
56
- "workflow": "4.8.2",
57
55
  "aai-templates": "0.3.8"
58
56
  },
59
57
  "peerDependencies": {
@@ -1,108 +0,0 @@
1
- /**
2
- * What the BUILT flow bundle carries — the two scans that read it, and the
3
- * checks over them.
4
- *
5
- * Split out of `workflow-bundler.ts` when that file crossed the 500-line cap,
6
- * along the seam the two scans already share: both read the same artifact after
7
- * the builder has written it, both attribute a line to a module through
8
- * esbuild's `// <path>` headers, and neither has anything to do with
9
- * CONFIGURING the build. One of them fails the build (a `require` the workflow
10
- * VM cannot answer) and the other warns (a call that replays differently), which
11
- * is the only real difference between them.
12
- *
13
- * Internal: `workflow-bundler.ts` is the surface the studio and the CLI's own
14
- * build call, and it re-exports nothing from here that they need.
15
- *
16
- * @module _workflow-scan
17
- */
18
- /** One `require` the workflow VM cannot answer, and the module it was written for. */
19
- export type VmRequireSite = {
20
- /** The module specifier — `node:child_process`. */
21
- specifier: string;
22
- /** The bundled file esbuild attributed it to, or `undefined` when it said none. */
23
- module: string | undefined;
24
- };
25
- /**
26
- * Find the Node builtins a flow bundle would `require` at load.
27
- *
28
- * The flow bundle is compiled in a `node:vm` `Script` whose context has
29
- * `module` and `exports` and **no `require`**, so one of these is a run that
30
- * dies at replay with `ReferenceError: require is not defined` — never a build
31
- * failure, and never a symptom before the first run. The WDK's own builder
32
- * bundles everything for exactly this reason and carries
33
- * `createNodeModuleErrorPlugin` to reject a builtin import at build time.
34
- *
35
- * That plugin has two blind spots this scan covers, and both are the DEPLOYED
36
- * shape rather than an exotic one:
37
- *
38
- * - It reports a violation only when it can point at the import LINE in a
39
- * first-party file, matched with a single-line regex — so a multi-line
40
- * `import {\n x,\n} from "pkg"` finds nothing and the builtin is marked
41
- * external in silence.
42
- * - It resolves that file against `process.cwd()`, which is not the project
43
- * being built when the studio builds a workspace, so the read fails and the
44
- * same silent path is taken.
45
- *
46
- * Both were reproduced. What reaches the VM either way is
47
- * `var import_node_child_process = require("node:child_process");` at the top
48
- * of the bundle, i.e. every run of every workflow in the project fails, and the
49
- * stack names a line of generated code inside a dependency.
50
- *
51
- * Restricted to builtin specifiers deliberately: those are the only ones this
52
- * builder leaves external (it marks nothing else so, precisely so nothing can
53
- * need a `require`), and a narrow set is what keeps the scan from reading the
54
- * text of a prompt as a violation.
55
- *
56
- * @internal
57
- */
58
- export declare function findVmRequires(workflowCode: string): VmRequireSite[];
59
- /** One replay-unsafe call the flow bundle carries, and where it came from. */
60
- export type ReplayUnsafeSite = {
61
- /** The call, as written — `Date.now(`. */
62
- call: string;
63
- /** What it does on a replay, and what to do instead. */
64
- fix: string;
65
- /** The project file esbuild attributed it to. */
66
- module: string;
67
- };
68
- /**
69
- * Replay-unsafe calls the flow bundle carries, attributed to the project's OWN
70
- * `workflows/` files.
71
- *
72
- * Attribution is the whole design. The bundle inlines every non-external
73
- * dependency a workflow module imports — zod, a markdown parser, whatever — and
74
- * third-party code is full of `Date.now()` on paths a workflow never reaches, so
75
- * a scan of the bundle's text reports a library and blocks a correct project.
76
- * esbuild writes a `// <path>` header per module (the same one
77
- * {@link findVmRequires} reads), so lines can be charged to the file they were
78
- * written in, and only the project's own workflow sources are read.
79
- *
80
- * Scanning the BUNDLE rather than the sources is what makes a `"use step"` body
81
- * exempt for free: the workflow-mode transform has already removed them, so
82
- * what is left is the part that really does replay.
83
- *
84
- * @internal
85
- */
86
- export declare function findReplayUnsafeCalls(workflowCode: string): ReplayUnsafeSite[];
87
- /**
88
- * The warning `aai build` and `aai dev` print for a replay-unsafe call.
89
- *
90
- * A WARNING and not a build failure, deliberately. The attribution above makes
91
- * the scan accurate about which FILE a call is in, and it cannot know whether a
92
- * plain function in a `workflows/` module is reached from a body (where the
93
- * rule bites) or only from a step (where it does not) — so the one thing it
94
- * must not do is refuse a correct project. A silent build was the actual
95
- * problem; a line naming the file solves it without that risk.
96
- */
97
- export declare function replayWarnings(workflowCode: string): string[];
98
- /**
99
- * Fail the build when the flow bundle carries a `require` — see
100
- * {@link findVmRequires} for what that means and why nothing upstream catches it.
101
- *
102
- * The message has to name the MODULE as well as the specifier, because the
103
- * import that caused it is not in the file an author is looking at: only a
104
- * `"use step"` body is stripped from this bundle, so a value a `workflows/`
105
- * module holds at module scope — an exported helper, a constant — keeps its
106
- * import, and that import's whole graph rides into the VM.
107
- */
108
- export declare function assertNoVmRequires(workflowCode: string): void;