@warble/claude-agent-sdk 0.4.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/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_TARGET,
4
+ DispatchError,
5
+ DispatchSessionError,
6
+ ModelConfig,
7
+ buildManifest,
8
+ createChatSession,
9
+ discoverClaudeModels,
10
+ emitAgentModule,
11
+ parseRenderFlavor,
12
+ prepareDispatch,
13
+ prepareDisplayManifest,
14
+ runDispatch
15
+ } from "./chunk-F4QDKVP7.js";
16
+
17
+ // src/cli.ts
18
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
19
+ import { createRequire } from "module";
20
+ import { dirname, join, resolve } from "path";
21
+ import { createInterface } from "readline";
22
+ import { parseArgs } from "util";
23
+ import { fileURLToPath } from "url";
24
+ function fail(message) {
25
+ process.stderr.write(`error: ${message}
26
+ `);
27
+ process.exit(1);
28
+ }
29
+ var USAGE = 'usage: warble-agent-sdk <dispatch|emit|manifest|chat> <ir.json> ["<question>"] [options]\n warble-agent-sdk list-models [--project <dir>] [--timeout <ms>]';
30
+ var requireFromHere = createRequire(import.meta.url);
31
+ function packageVersion() {
32
+ return requireFromHere("../package.json").version;
33
+ }
34
+ function defaultWarbleBin() {
35
+ const here = dirname(fileURLToPath(import.meta.url));
36
+ const repoBuilt = resolve(here, "../../../target/release/warble");
37
+ return existsSync(repoBuilt) ? repoBuilt : "warble";
38
+ }
39
+ function printResolutionSummary(target, id, report) {
40
+ process.stderr.write(`warble-agent-sdk: capability resolution for '${target}' (component '${id}'):
41
+ `);
42
+ for (const e of report) {
43
+ const note = e.note ? ` \u2014 ${e.note}` : "";
44
+ process.stderr.write(
45
+ ` ${e.capability.padEnd(28)} ${e.outcome.padEnd(12)} (${e.provided_by}, ${e.criticality})${note}
46
+ `
47
+ );
48
+ }
49
+ }
50
+ function buildModels(values) {
51
+ const cfgPath = values["models-config"];
52
+ if (typeof cfgPath === "string") {
53
+ return ModelConfig.fromYaml(readFileSync(resolve(cfgPath), "utf8"));
54
+ }
55
+ return ModelConfig.fromFlags(
56
+ values.strong ?? "opus",
57
+ values.cheap ?? "haiku",
58
+ values.orchestrator ?? "sonnet"
59
+ );
60
+ }
61
+ async function main() {
62
+ const firstArg = process.argv[2];
63
+ if (firstArg === "--version" || firstArg === "-V") {
64
+ process.stdout.write(`${packageVersion()}
65
+ `);
66
+ return;
67
+ }
68
+ if (firstArg === "--help" || firstArg === "-h") {
69
+ process.stdout.write(`${USAGE}
70
+ `);
71
+ return;
72
+ }
73
+ const { values, positionals } = parseArgs({
74
+ allowPositionals: true,
75
+ options: {
76
+ target: { type: "string" },
77
+ out: { type: "string" },
78
+ "models-config": { type: "string" },
79
+ "render-flavor": { type: "string" },
80
+ strong: { type: "string" },
81
+ cheap: { type: "string" },
82
+ orchestrator: { type: "string" },
83
+ project: { type: "string" },
84
+ "warble-bin": { type: "string" },
85
+ "max-turns": { type: "string" },
86
+ title: { type: "string" },
87
+ "dry-run": { type: "boolean" },
88
+ standalone: { type: "boolean" },
89
+ component: { type: "string" },
90
+ "stream-json": { type: "boolean" },
91
+ resume: { type: "string" },
92
+ timeout: { type: "string" },
93
+ "include-unavailable": { type: "boolean" }
94
+ }
95
+ });
96
+ const [subcommand, irArg, question] = positionals;
97
+ if (subcommand !== "dispatch" && subcommand !== "emit" && subcommand !== "manifest" && subcommand !== "chat" && subcommand !== "list-models") {
98
+ fail(USAGE);
99
+ }
100
+ if (subcommand === "list-models") {
101
+ if (irArg !== void 0 || question !== void 0) fail("list-models does not take an <ir.json> or question");
102
+ const timeout = values.timeout === void 0 ? void 0 : Number(values.timeout);
103
+ if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout <= 0)) fail("--timeout must be a positive number");
104
+ const catalog = await discoverClaudeModels({
105
+ ...values.project ? { cwd: values.project } : {},
106
+ ...timeout !== void 0 ? { timeoutMs: timeout } : {}
107
+ });
108
+ process.stdout.write(`${JSON.stringify(catalog)}
109
+ `);
110
+ return;
111
+ }
112
+ if (values.timeout !== void 0) fail("--timeout is only supported by list-models");
113
+ if (values["include-unavailable"] && subcommand !== "manifest") fail("--include-unavailable is only supported by manifest");
114
+ if (!irArg) fail("missing <ir.json> argument");
115
+ const target = values.target ?? DEFAULT_TARGET;
116
+ const flavor = parseRenderFlavor(values["render-flavor"] ?? "programmatic");
117
+ const models = buildModels(values);
118
+ const raw = readFileSync(resolve(irArg), "utf8");
119
+ const common = { target, flavor, models, raw, irPath: irArg, project: values.project };
120
+ if (subcommand === "emit") {
121
+ return runEmit(common, values.out, Boolean(values.standalone));
122
+ }
123
+ if (subcommand === "manifest") {
124
+ return runManifest(common, values.out, Boolean(values["include-unavailable"]));
125
+ }
126
+ if (subcommand === "chat") {
127
+ return runChatCmd(common, values);
128
+ }
129
+ return runDispatchCmd(common, values, question);
130
+ }
131
+ function runEmit(common, outArg, standalone) {
132
+ const prepared = prepareDispatch({
133
+ ir: common.raw,
134
+ target: common.target,
135
+ flavor: common.flavor,
136
+ models: common.models,
137
+ irPath: common.irPath,
138
+ ...common.project !== void 0 ? { project: common.project } : {}
139
+ });
140
+ for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);
141
+ const outPath = resolve(outArg ?? "agent.ts");
142
+ mkdirSync(dirname(outPath), { recursive: true });
143
+ writeFileSync(outPath, emitAgentModule(prepared, { standalone }), "utf8");
144
+ process.stderr.write(
145
+ `warble-agent-sdk: emit \u2014 wrote ${outPath} (${prepared.components.length} component(s), ${standalone ? "standalone" : "thin"}).
146
+ `
147
+ );
148
+ }
149
+ function runManifest(common, outArg, includeUnavailable) {
150
+ const input = {
151
+ ir: common.raw,
152
+ target: common.target,
153
+ flavor: common.flavor,
154
+ models: common.models,
155
+ irPath: common.irPath,
156
+ ...common.project !== void 0 ? { project: common.project } : {}
157
+ };
158
+ const prepared = includeUnavailable ? prepareDisplayManifest(input) : prepareDispatch(input);
159
+ for (const c of prepared.components) {
160
+ if ("report" in c) printResolutionSummary(common.target, c.id, c.report);
161
+ }
162
+ const manifest = buildManifest(prepared, common.raw);
163
+ const json = `${JSON.stringify(manifest, null, 2)}
164
+ `;
165
+ if (outArg) {
166
+ const outPath = resolve(outArg);
167
+ mkdirSync(dirname(outPath), { recursive: true });
168
+ writeFileSync(outPath, json, "utf8");
169
+ process.stderr.write(
170
+ `warble-agent-sdk: manifest \u2014 wrote ${outPath} (${prepared.components.length} agent(s)).
171
+ `
172
+ );
173
+ } else {
174
+ process.stdout.write(json);
175
+ }
176
+ }
177
+ async function runDispatchCmd(common, values, question) {
178
+ const dryRun = Boolean(values["dry-run"]);
179
+ if (!question && !dryRun) fail('missing "<question>" argument (or pass --dry-run)');
180
+ const maxTurnsRaw = values["max-turns"];
181
+ const maxTurns = typeof maxTurnsRaw === "string" ? Number(maxTurnsRaw) : void 0;
182
+ if (maxTurns !== void 0 && !Number.isFinite(maxTurns)) fail("--max-turns must be a number");
183
+ const outDir = resolve(values.out ?? "./run");
184
+ const warbleBin = values["warble-bin"] ?? defaultWarbleBin();
185
+ const title = values.title;
186
+ const prepared = prepareDispatch({
187
+ ir: common.raw,
188
+ question: question ?? "",
189
+ target: common.target,
190
+ flavor: common.flavor,
191
+ models: common.models,
192
+ irPath: common.irPath,
193
+ ...common.project !== void 0 ? { project: common.project } : {},
194
+ ...maxTurns !== void 0 ? { maxTurns } : {}
195
+ });
196
+ mkdirSync(outDir, { recursive: true });
197
+ for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);
198
+ for (const c of prepared.components) {
199
+ if (dryRun) {
200
+ const planPath = join(outDir, `${c.node.verb}.plan.json`);
201
+ writeFileSync(
202
+ planPath,
203
+ JSON.stringify({ prompt: c.plan.prompt, options: c.plan.options, meta: c.plan.meta }, null, 2) + "\n",
204
+ "utf8"
205
+ );
206
+ process.stderr.write(
207
+ `warble-agent-sdk: dry-run \u2014 wrote plan ${planPath} (model=${c.plan.meta.model}, split=${c.plan.meta.split}, render=${c.plan.meta.render.kind}); query() not called.
208
+ `
209
+ );
210
+ continue;
211
+ }
212
+ const result = await runDispatch(c.plan, { outDir, warbleBin, ...title ? { title } : {} });
213
+ process.stderr.write(
214
+ `warble-agent-sdk: ran '${c.node.verb}' \u2192 ${result.htmlPath ?? "(no html)"}; ${result.denials.length} guardrail denial(s); trace at ${join(outDir, "trace.json")}
215
+ `
216
+ );
217
+ }
218
+ writeFileSync(
219
+ join(outDir, "capability-report.json"),
220
+ JSON.stringify(
221
+ { target: common.target, components: prepared.components.map((c) => ({ id: c.id, capabilities: c.report })) },
222
+ null,
223
+ 2
224
+ ) + "\n",
225
+ "utf8"
226
+ );
227
+ }
228
+ async function runChatCmd(common, values) {
229
+ const outDir = resolve(values.out ?? "./run");
230
+ const warbleBin = values["warble-bin"] ?? defaultWarbleBin();
231
+ const componentId = values.component ?? "answer_query";
232
+ const prepared = prepareDispatch({
233
+ ir: common.raw,
234
+ target: common.target,
235
+ flavor: common.flavor,
236
+ models: common.models,
237
+ irPath: common.irPath,
238
+ componentId,
239
+ ...common.project !== void 0 ? { project: common.project } : {}
240
+ });
241
+ const component = prepared.components[0];
242
+ if (!component) fail(`internal error: no component prepared for '${componentId}'`);
243
+ for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);
244
+ mkdirSync(outDir, { recursive: true });
245
+ const resumeSessionId = values.resume;
246
+ const session = createChatSession(component.plan, { outDir, warbleBin }, resumeSessionId);
247
+ process.stderr.write(
248
+ `warble-agent-sdk: chat \u2014 component '${componentId}'; type a question per line (Ctrl-D to end).
249
+ `
250
+ );
251
+ const streamJson = Boolean(values["stream-json"]);
252
+ const onEvent = streamJson ? (event) => {
253
+ process.stdout.write(`${JSON.stringify(event)}
254
+ `);
255
+ } : void 0;
256
+ const emitSession = (id) => {
257
+ if (!streamJson) return;
258
+ const sessionEvent = { t: "session", id };
259
+ process.stdout.write(`${JSON.stringify(sessionEvent)}
260
+ `);
261
+ };
262
+ const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
263
+ for await (const line of rl) {
264
+ const question = line.trim();
265
+ if (!question) continue;
266
+ let turn;
267
+ try {
268
+ turn = await session.ask(question, onEvent ? { onEvent } : {});
269
+ } catch (err) {
270
+ emitSession(err instanceof DispatchSessionError ? err.sessionId : null);
271
+ throw err;
272
+ }
273
+ emitSession(turn.sessionId);
274
+ if (streamJson) {
275
+ const answerEvent = { t: "answer", text: turn.finalText };
276
+ process.stdout.write(`${JSON.stringify(answerEvent)}
277
+ `);
278
+ } else {
279
+ process.stdout.write(`${turn.finalText}
280
+ `);
281
+ }
282
+ }
283
+ }
284
+ main().catch((e) => {
285
+ if (e instanceof DispatchError) fail(e.message);
286
+ fail(e instanceof Error ? e.stack ?? e.message : String(e));
287
+ });
288
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `warble-agent-sdk` — the Claude Agent SDK back-end CLI.\n *\n * warble-agent-sdk dispatch <ir.json> \"<question>\" [--target …] [--models-config m.yml]\n * [--render-flavor programmatic|prompt] [--out ./run] [--project <dir>]\n * [--strong opus] [--cheap haiku] [--orchestrator sonnet]\n * [--warble-bin <path>] [--max-turns N] [--title <t>] [--dry-run]\n *\n * warble-agent-sdk emit <ir.json> [--out agent.ts] [--standalone] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk manifest <ir.json> [--include-unavailable] [--out manifest.json] [--target …] [--models-config …]\n * [--render-flavor …] [--project <dir>] [--strong/--cheap/--orchestrator …]\n *\n * warble-agent-sdk chat <ir.json> [--project <dir>] [--component answer_query] [--out ./run]\n * [--target …] [--models-config m.yml] [--render-flavor programmatic|prompt] [--warble-bin <path>]\n * [--stream-json] [--resume <session-id>]\n *\n * `chat --stream-json` emits per-step/per-tool NDJSON events (one `WarbleChatEvent`, events.ts, per\n * line) to stdout as each turn runs, ending with a terminal `{\"t\":\"answer\",\"text\":…}` line, instead of\n * the default plain final-answer-text-per-turn output — for a consumer that wants to build a live,\n * expandable work log rather than just the finished text. Every turn also emits a\n * `{\"t\":\"session\",\"id\":…}` line (on success AND on a failed turn) carrying that turn's SDK session id.\n *\n * `--resume <session-id>` seeds a brand-new `chat` process's FIRST turn with a session id captured by\n * an earlier `chat` process (from its `{\"t\":\"session\",…}` line) — lets a caller resume a conversation\n * that a previous process started (e.g. one that ran out of turns), continuing the real SDK\n * conversation instead of re-dispatching a fresh prompt from scratch. Ignored after the first turn:\n * subsequent turns resume from this process's own prior turn, as usual.\n *\n * `dispatch` consumes the SAME `ir.json` a Rust `warble compile` emits and drives the SDK loop\n * in-process (`--dry-run` writes the assembled plan without calling `query()`). `emit` freezes the\n * resolved plan into an importable TS agent module (thin, or `--standalone`). `manifest` runs the\n * same preparation as `emit` (no `question`, no `query()` call) and instead serializes a display\n * manifest — the resolved agents/steps/tiers/capabilities/guardrails for THIS target, structurally\n * identical to the vercel back-end's bundle — so a consumer can source a display from whichever\n * back-end actually runs, instead of always reading the vercel bundle target's output. `chat` opens a\n * multi-turn session (session.ts, G1 — single profile, many turns) over one component, reading\n * questions from stdin line-by-line and resuming the SDK session turn over turn.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { parseArgs } from \"node:util\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { emitAgentModule } from \"./codegen.js\";\nimport { prepareDisplayManifest, prepareDispatch, type PreparedDispatch } from \"./dispatch.js\";\nimport { DispatchError } from \"./error.js\";\nimport type { WarbleChatEvent } from \"./events.js\";\nimport { buildManifest } from \"./manifest.js\";\nimport { ModelConfig } from \"./models.js\";\nimport { discoverClaudeModels } from \"./model_catalog.js\";\nimport { parseRenderFlavor, type RenderFlavor } from \"./options.js\";\nimport { DispatchSessionError, runDispatch } from \"./run.js\";\nimport { createChatSession } from \"./session.js\";\nimport { type ResolutionReport } from \"./resolve.js\";\nimport { DEFAULT_TARGET } from \"./targets.js\";\n\nfunction fail(message: string): never {\n process.stderr.write(`error: ${message}\\n`);\n process.exit(1);\n}\n\nconst USAGE =\n 'usage: warble-agent-sdk <dispatch|emit|manifest|chat> <ir.json> [\"<question>\"] [options]\\n' +\n \" warble-agent-sdk list-models [--project <dir>] [--timeout <ms>]\";\n\n// `require(\"../package.json\")` resolves relative to *this* file's own location, one directory up —\n// which is the package root in both the dev tree (src/cli.ts → ../package.json) and the published\n// layout (dist/cli.js → ../package.json; package.json ships in every npm package regardless of the\n// \"files\" allowlist). That keeps the reported version tied to the package's real `version` field\n// instead of a literal that could drift from it.\nconst requireFromHere = createRequire(import.meta.url);\n\nfunction packageVersion(): string {\n return (requireFromHere(\"../package.json\") as { version: string }).version;\n}\n\n/** Locate the reference `warble` binary: --warble-bin, else PATH, else this repo's release build. */\nfunction defaultWarbleBin(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n const repoBuilt = resolve(here, \"../../../target/release/warble\");\n return existsSync(repoBuilt) ? repoBuilt : \"warble\";\n}\n\nfunction printResolutionSummary(target: string, id: string, report: ResolutionReport): void {\n process.stderr.write(`warble-agent-sdk: capability resolution for '${target}' (component '${id}'):\\n`);\n for (const e of report) {\n const note = e.note ? ` — ${e.note}` : \"\";\n process.stderr.write(\n ` ${e.capability.padEnd(28)} ${e.outcome.padEnd(12)} (${e.provided_by}, ${e.criticality})${note}\\n`,\n );\n }\n}\n\ninterface CommonArgs {\n target: string;\n flavor: RenderFlavor;\n models: ModelConfig;\n raw: string;\n irPath: string;\n project: string | undefined;\n}\n\nfunction buildModels(values: Record<string, string | boolean | undefined>): ModelConfig {\n const cfgPath = values[\"models-config\"];\n if (typeof cfgPath === \"string\") {\n return ModelConfig.fromYaml(readFileSync(resolve(cfgPath), \"utf8\"));\n }\n return ModelConfig.fromFlags(\n (values.strong as string) ?? \"opus\",\n (values.cheap as string) ?? \"haiku\",\n (values.orchestrator as string) ?? \"sonnet\",\n );\n}\n\nasync function main(): Promise<void> {\n // Handle `--version`/`-V` and `--help`/`-h` up front, before the strict `parseArgs` below —\n // neither is a declared option there, so leaving them for `parseArgs` to see would throw\n // `ERR_PARSE_ARGS_UNKNOWN_OPTION` instead of doing what every other CLI does with them.\n const firstArg = process.argv[2];\n if (firstArg === \"--version\" || firstArg === \"-V\") {\n process.stdout.write(`${packageVersion()}\\n`);\n return;\n }\n if (firstArg === \"--help\" || firstArg === \"-h\") {\n process.stdout.write(`${USAGE}\\n`);\n return;\n }\n\n const { values, positionals } = parseArgs({\n allowPositionals: true,\n options: {\n target: { type: \"string\" },\n out: { type: \"string\" },\n \"models-config\": { type: \"string\" },\n \"render-flavor\": { type: \"string\" },\n strong: { type: \"string\" },\n cheap: { type: \"string\" },\n orchestrator: { type: \"string\" },\n project: { type: \"string\" },\n \"warble-bin\": { type: \"string\" },\n \"max-turns\": { type: \"string\" },\n title: { type: \"string\" },\n \"dry-run\": { type: \"boolean\" },\n standalone: { type: \"boolean\" },\n component: { type: \"string\" },\n \"stream-json\": { type: \"boolean\" },\n resume: { type: \"string\" },\n timeout: { type: \"string\" },\n \"include-unavailable\": { type: \"boolean\" },\n },\n });\n\n const [subcommand, irArg, question] = positionals;\n if (\n subcommand !== \"dispatch\" &&\n subcommand !== \"emit\" &&\n subcommand !== \"manifest\" &&\n subcommand !== \"chat\" &&\n subcommand !== \"list-models\"\n ) {\n fail(USAGE);\n }\n if (subcommand === \"list-models\") {\n if (irArg !== undefined || question !== undefined) fail(\"list-models does not take an <ir.json> or question\");\n const timeout = values.timeout === undefined ? undefined : Number(values.timeout);\n if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) fail(\"--timeout must be a positive number\");\n const catalog = await discoverClaudeModels({\n ...(values.project ? { cwd: values.project } : {}),\n ...(timeout !== undefined ? { timeoutMs: timeout } : {}),\n });\n process.stdout.write(`${JSON.stringify(catalog)}\\n`);\n return;\n }\n if (values.timeout !== undefined) fail(\"--timeout is only supported by list-models\");\n if (values[\"include-unavailable\"] && subcommand !== \"manifest\") fail(\"--include-unavailable is only supported by manifest\");\n if (!irArg) fail(\"missing <ir.json> argument\");\n\n const target = values.target ?? DEFAULT_TARGET;\n const flavor = parseRenderFlavor(values[\"render-flavor\"] ?? \"programmatic\");\n const models = buildModels(values);\n const raw = readFileSync(resolve(irArg), \"utf8\");\n\n const common: CommonArgs = { target, flavor, models, raw, irPath: irArg, project: values.project };\n\n if (subcommand === \"emit\") {\n return runEmit(common, values.out, Boolean(values.standalone));\n }\n if (subcommand === \"manifest\") {\n return runManifest(common, values.out, Boolean(values[\"include-unavailable\"]));\n }\n if (subcommand === \"chat\") {\n return runChatCmd(common, values);\n }\n return runDispatchCmd(common, values, question);\n}\n\nfunction runEmit(common: CommonArgs, outArg: string | undefined, standalone: boolean): void {\n const prepared: PreparedDispatch = prepareDispatch({\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n const outPath = resolve(outArg ?? \"agent.ts\");\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, emitAgentModule(prepared, { standalone }), \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: emit — wrote ${outPath} (${prepared.components.length} component(s), ${standalone ? \"standalone\" : \"thin\"}).\\n`,\n );\n}\n\n/**\n * `manifest` — same preparation as `emit` (no `question`, `query()` never called), but instead of\n * freezing an importable agent module, serializes the display manifest (see `manifest.ts`) to stdout\n * or `--out`. Capability resolution summaries still go to stderr so stdout stays pure JSON.\n */\nfunction runManifest(common: CommonArgs, outArg: string | undefined, includeUnavailable: boolean): void {\n const input = {\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n } as const;\n const prepared = includeUnavailable ? prepareDisplayManifest(input) : prepareDispatch(input);\n for (const c of prepared.components) {\n if (\"report\" in c) printResolutionSummary(common.target, c.id, c.report);\n }\n\n const manifest = buildManifest(prepared, common.raw);\n const json = `${JSON.stringify(manifest, null, 2)}\\n`;\n\n if (outArg) {\n const outPath = resolve(outArg);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, json, \"utf8\");\n process.stderr.write(\n `warble-agent-sdk: manifest — wrote ${outPath} (${prepared.components.length} agent(s)).\\n`,\n );\n } else {\n process.stdout.write(json);\n }\n}\n\nasync function runDispatchCmd(\n common: CommonArgs,\n values: Record<string, string | boolean | undefined>,\n question: string | undefined,\n): Promise<void> {\n const dryRun = Boolean(values[\"dry-run\"]);\n if (!question && !dryRun) fail('missing \"<question>\" argument (or pass --dry-run)');\n\n const maxTurnsRaw = values[\"max-turns\"];\n const maxTurns = typeof maxTurnsRaw === \"string\" ? Number(maxTurnsRaw) : undefined;\n if (maxTurns !== undefined && !Number.isFinite(maxTurns)) fail(\"--max-turns must be a number\");\n\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const title = values.title as string | undefined;\n\n const prepared = prepareDispatch({\n ir: common.raw,\n question: question ?? \"\",\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n ...(common.project !== undefined ? { project: common.project } : {}),\n ...(maxTurns !== undefined ? { maxTurns } : {}),\n });\n\n mkdirSync(outDir, { recursive: true });\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n for (const c of prepared.components) {\n if (dryRun) {\n const planPath = join(outDir, `${c.node.verb}.plan.json`);\n writeFileSync(\n planPath,\n JSON.stringify({ prompt: c.plan.prompt, options: c.plan.options, meta: c.plan.meta }, null, 2) + \"\\n\",\n \"utf8\",\n );\n process.stderr.write(\n `warble-agent-sdk: dry-run — wrote plan ${planPath} (model=${c.plan.meta.model}, split=${c.plan.meta.split}, render=${c.plan.meta.render.kind}); query() not called.\\n`,\n );\n continue;\n }\n const result = await runDispatch(c.plan, { outDir, warbleBin, ...(title ? { title } : {}) });\n process.stderr.write(\n `warble-agent-sdk: ran '${c.node.verb}' → ${result.htmlPath ?? \"(no html)\"}; ` +\n `${result.denials.length} guardrail denial(s); trace at ${join(outDir, \"trace.json\")}\\n`,\n );\n }\n\n writeFileSync(\n join(outDir, \"capability-report.json\"),\n JSON.stringify(\n { target: common.target, components: prepared.components.map((c) => ({ id: c.id, capabilities: c.report })) },\n null,\n 2,\n ) + \"\\n\",\n \"utf8\",\n );\n}\n\n/**\n * `chat` — a multi-turn session (session.ts, G1) over ONE prepared component, reading questions from\n * stdin line-by-line. Each turn's answer is printed to stdout; the SDK session is resumed turn over\n * turn (`ChatSession` handles the `resume: session_id` plumbing). Manual/live use only — not exercised\n * by the offline test suite.\n *\n * `--stream-json` (opt-in): instead of printing the turn's plain final-answer text, stream one\n * `WarbleChatEvent` NDJSON line per event as the turn runs (via `session.ask`'s `onEvent`), followed\n * by a terminal `{\"t\":\"answer\",\"text\":…}` line. Without the flag, behavior is byte-for-byte unchanged\n * from before this option existed.\n */\nasync function runChatCmd(\n common: CommonArgs,\n values: Record<string, string | boolean | undefined>,\n): Promise<void> {\n const outDir = resolve((values.out as string) ?? \"./run\");\n const warbleBin = (values[\"warble-bin\"] as string) ?? defaultWarbleBin();\n const componentId = (values.component as string) ?? \"answer_query\";\n\n // Scoped to `componentId`: only its own required capabilities are resolved, so a *different*\n // component's unmet requirements (e.g. a sibling gated-tool with no approval channel wired on\n // this target) can never block dispatching this one. See `DispatchInput.componentId`.\n const prepared = prepareDispatch({\n ir: common.raw,\n target: common.target,\n flavor: common.flavor,\n models: common.models,\n irPath: common.irPath,\n componentId,\n ...(common.project !== undefined ? { project: common.project } : {}),\n });\n\n // `prepareDispatch` with `componentId` set either returns exactly this one component or throws\n // (caught by `main().catch()` below) — this is a defensive invariant check, not a reachable\n // \"not found\" path; that path's error text now comes from `prepareDispatch` itself.\n const component = prepared.components[0];\n if (!component) fail(`internal error: no component prepared for '${componentId}'`);\n for (const c of prepared.components) printResolutionSummary(common.target, c.id, c.report);\n\n mkdirSync(outDir, { recursive: true });\n const resumeSessionId = values.resume as string | undefined;\n const session = createChatSession(component.plan, { outDir, warbleBin }, resumeSessionId);\n\n process.stderr.write(\n `warble-agent-sdk: chat — component '${componentId}'; type a question per line (Ctrl-D to end).\\n`,\n );\n\n const streamJson = Boolean(values[\"stream-json\"]);\n const onEvent = streamJson\n ? (event: WarbleChatEvent): void => {\n process.stdout.write(`${JSON.stringify(event)}\\n`);\n }\n : undefined;\n\n const emitSession = (id: string | null): void => {\n if (!streamJson) return;\n const sessionEvent: WarbleChatEvent = { t: \"session\", id };\n process.stdout.write(`${JSON.stringify(sessionEvent)}\\n`);\n };\n\n const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });\n for await (const line of rl) {\n const question = line.trim();\n if (!question) continue;\n let turn;\n try {\n turn = await session.ask(question, onEvent ? { onEvent } : {});\n } catch (err) {\n // A failed turn (e.g. error_max_turns) still surfaces its session id, when the SDK's result\n // message carried one, so a caller can resume this same conversation instead of starting over.\n emitSession(err instanceof DispatchSessionError ? err.sessionId : null);\n throw err;\n }\n emitSession(turn.sessionId);\n if (streamJson) {\n const answerEvent: WarbleChatEvent = { t: \"answer\", text: turn.finalText };\n process.stdout.write(`${JSON.stringify(answerEvent)}\\n`);\n } else {\n process.stdout.write(`${turn.finalText}\\n`);\n }\n }\n}\n\nmain().catch((e: unknown) => {\n if (e instanceof DispatchError) fail(e.message);\n fail(e instanceof Error ? (e.stack ?? e.message) : String(e));\n});\n"],"mappings":"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","names":[]}