@agentproto/driver-agent-cli 0.2.0 → 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/{chunk-YQHVLX6O.mjs → chunk-L6BRNMVP.mjs} +552 -62
- package/dist/chunk-L6BRNMVP.mjs.map +1 -0
- package/dist/index.d.ts +203 -14
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/manifest/index.d.ts +2 -2
- package/dist/manifest/index.mjs +2 -2
- package/dist/{schema-CCSzIDMJ.d.ts → schema-L-2rEB1H.d.ts} +314 -2
- package/package.json +2 -2
- package/dist/chunk-YQHVLX6O.mjs.map +0 -1
|
@@ -2,8 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
import { Writable, Readable } from 'stream';
|
|
3
3
|
import { createAcpClient } from '@agentproto/acp/client';
|
|
4
4
|
import { spawn } from 'child_process';
|
|
5
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, rmdirSync, mkdtempSync } from 'fs';
|
|
5
6
|
import { createInterface } from 'readline';
|
|
7
|
+
import { join } from 'path';
|
|
6
8
|
import { randomUUID } from 'crypto';
|
|
9
|
+
import { tmpdir } from 'os';
|
|
7
10
|
import { createDoctype } from '@agentproto/define-doctype';
|
|
8
11
|
|
|
9
12
|
/**
|
|
@@ -150,12 +153,21 @@ var authSchema = z.object({
|
|
|
150
153
|
var sessionSchema = z.object({
|
|
151
154
|
mode: z.enum(["ephemeral", "persistent", "resumable"]).default("ephemeral"),
|
|
152
155
|
idle_timeout_ms: z.number().int().min(1e3).default(6e5),
|
|
156
|
+
// No default: undefined disables the per-turn watchdog entirely. Only
|
|
157
|
+
// adapters known to sometimes drop the final `prompt` response (e.g.
|
|
158
|
+
// hermes) should declare this — applying it broadly would risk
|
|
159
|
+
// false-positiving on another adapter's legitimately long turns.
|
|
160
|
+
turn_idle_timeout_ms: z.number().int().min(1e3).optional(),
|
|
153
161
|
max_turns: z.number().int().positive().optional(),
|
|
154
162
|
context_carryover: z.boolean().default(true)
|
|
155
163
|
}).strict();
|
|
156
164
|
var modelsSchema = z.object({
|
|
157
165
|
default: z.string().optional(),
|
|
158
166
|
allowed: z.array(z.string()).optional(),
|
|
167
|
+
// Model-id patterns the adapter must never route to (case-insensitive,
|
|
168
|
+
// trailing `*` = prefix match). Enforced at compose time — see
|
|
169
|
+
// AgentCliModels.deny. Reserves premium providers for dedicated adapters.
|
|
170
|
+
deny: z.array(z.string()).optional(),
|
|
159
171
|
env: z.record(z.string(), z.string()).optional(),
|
|
160
172
|
// How a model is selected at session start: "config" (ACP
|
|
161
173
|
// set_config_option, default) | "command" (a `/model <id>` control turn,
|
|
@@ -182,8 +194,21 @@ var capabilitiesSchema = z.object({
|
|
|
182
194
|
var modeSchema = z.object({
|
|
183
195
|
id: z.string().regex(MODE_ID_PATTERN),
|
|
184
196
|
description: z.string().optional(),
|
|
197
|
+
bin_args_prepend: z.array(z.string()).optional(),
|
|
185
198
|
bin_args_append: z.array(z.string()).optional(),
|
|
186
|
-
env: z.record(z.string(), z.string()).optional()
|
|
199
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
200
|
+
// Env keys to DELETE from the spawn env (auth hygiene for gateway
|
|
201
|
+
// modes — see AgentCliMode.env_unset). Applied at the runtime merge
|
|
202
|
+
// point, not as a static set.
|
|
203
|
+
env_unset: z.array(z.string()).optional(),
|
|
204
|
+
// Honest support status surfaced to clients. Absent ⇒ "active".
|
|
205
|
+
status: z.enum(["active", "noop", "planned"]).optional(),
|
|
206
|
+
status_note: z.string().optional(),
|
|
207
|
+
// How the host activates this mode: "bin_args" (default, argv/env
|
|
208
|
+
// composed at spawn) | "config" (no CLI surface — forwarded to the ACP
|
|
209
|
+
// arm's connect({mode}) and applied via session/set_config_option
|
|
210
|
+
// configId:"mode", e.g. opencode).
|
|
211
|
+
apply: z.enum(["bin_args", "config"]).optional()
|
|
187
212
|
}).strict();
|
|
188
213
|
var optionSchema = z.object({
|
|
189
214
|
id: z.string().regex(OPTION_ID_PATTERN),
|
|
@@ -193,9 +218,14 @@ var optionSchema = z.object({
|
|
|
193
218
|
default: z.union([z.boolean(), z.number(), z.string()]).optional(),
|
|
194
219
|
min: z.number().int().optional(),
|
|
195
220
|
max: z.number().int().optional(),
|
|
221
|
+
bin_args_prepend: z.array(z.string()).optional(),
|
|
196
222
|
bin_args_template: z.array(z.string()).optional(),
|
|
197
223
|
bin_args_append_when_true: z.array(z.string()).optional(),
|
|
198
|
-
env: z.record(z.string(), z.string()).optional()
|
|
224
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
225
|
+
// Env keys to DELETE from the spawn env when this option is active
|
|
226
|
+
// (auth hygiene for value-bearing gateway options — see
|
|
227
|
+
// AgentCliOption.env_unset). Symmetric with modeSchema.env_unset.
|
|
228
|
+
env_unset: z.array(z.string()).optional()
|
|
199
229
|
}).strict().refine(
|
|
200
230
|
// type === "enum" REQUIRES an `enum` array. The JSON Schema enforces
|
|
201
231
|
// this via `if/then`; the zod side mirrors with a refine so both
|
|
@@ -203,6 +233,17 @@ var optionSchema = z.object({
|
|
|
203
233
|
(o) => o.type !== "enum" || Array.isArray(o.enum) && o.enum.length > 0,
|
|
204
234
|
{ message: "option.type === 'enum' requires a non-empty `enum` array" }
|
|
205
235
|
);
|
|
236
|
+
var presetSchema = z.object({
|
|
237
|
+
id: z.string().min(1),
|
|
238
|
+
label: z.string().min(1),
|
|
239
|
+
description: z.string().optional(),
|
|
240
|
+
schemaFlavor: z.enum(["anthropic", "openai"]),
|
|
241
|
+
baseUrl: z.string().min(1),
|
|
242
|
+
keyEnv: z.string().min(1),
|
|
243
|
+
scrubEnv: z.array(z.string()).optional(),
|
|
244
|
+
defaultModel: z.string().optional(),
|
|
245
|
+
homepage: z.string().optional()
|
|
246
|
+
}).strict();
|
|
206
247
|
var continuationStrategyIdSchema = z.enum(CONTINUATION_STRATEGY_IDS);
|
|
207
248
|
var continuationSchema = z.object({
|
|
208
249
|
default: continuationStrategyIdSchema,
|
|
@@ -225,6 +266,16 @@ var mcpBlockSchema = z.object({
|
|
|
225
266
|
transport: z.enum(["stdio", "http", "sse"]),
|
|
226
267
|
url: z.string().url().optional()
|
|
227
268
|
}).strict();
|
|
269
|
+
var printConfigSchema = z.object({
|
|
270
|
+
prompt_flag: z.string().optional(),
|
|
271
|
+
output_format: z.array(z.string()).optional(),
|
|
272
|
+
pre_prompt: z.array(z.string()).optional(),
|
|
273
|
+
resume: z.object({
|
|
274
|
+
flag: z.string(),
|
|
275
|
+
kind: z.enum(["value", "boolean"])
|
|
276
|
+
}).strict().optional(),
|
|
277
|
+
event_schema: z.enum(["claude-stream-json", "mastra-jsonl"]).optional()
|
|
278
|
+
}).strict().optional();
|
|
228
279
|
var agentCliFrontmatterSchema = z.object({
|
|
229
280
|
name: z.string().min(1).max(80),
|
|
230
281
|
id: z.string().regex(ID_PATTERN),
|
|
@@ -242,11 +293,15 @@ var agentCliFrontmatterSchema = z.object({
|
|
|
242
293
|
acp: z.string().optional(),
|
|
243
294
|
mcp: mcpBlockSchema.optional(),
|
|
244
295
|
adapter: z.string().regex(ADAPTER_PATTERN).optional(),
|
|
296
|
+
print: printConfigSchema,
|
|
245
297
|
session: sessionSchema.optional(),
|
|
246
298
|
models: modelsSchema.optional(),
|
|
247
299
|
capabilities: capabilitiesSchema.optional(),
|
|
248
300
|
modes: z.array(modeSchema).optional(),
|
|
249
301
|
options: z.array(optionSchema).optional(),
|
|
302
|
+
// AIP-45 gateway presets this adapter can drive (merged into the
|
|
303
|
+
// provider-preset catalog; built-in wins on id collision).
|
|
304
|
+
presets: z.array(presetSchema).optional(),
|
|
250
305
|
continuation: continuationSchema.optional(),
|
|
251
306
|
requires: z.object({
|
|
252
307
|
os: z.array(z.enum(["darwin", "linux", "windows"])).optional(),
|
|
@@ -325,6 +380,21 @@ var autoAllowPermissionHandler = ({
|
|
|
325
380
|
const allow = options.find((o) => typeof o.kind === "string" && o.kind.startsWith("allow_")) ?? options[0];
|
|
326
381
|
return { outcome: { outcome: "selected", optionId: allow.optionId } };
|
|
327
382
|
};
|
|
383
|
+
var PLAN_MODE_EXIT_TOOL_CALL_KIND = "switch_mode";
|
|
384
|
+
var planModePermissionHandler = (params) => {
|
|
385
|
+
const { options, toolCall } = params;
|
|
386
|
+
if (!options || options.length === 0) {
|
|
387
|
+
return { outcome: { outcome: "cancelled" } };
|
|
388
|
+
}
|
|
389
|
+
if (toolCall?.kind === PLAN_MODE_EXIT_TOOL_CALL_KIND) {
|
|
390
|
+
const keepPlanning = options.find((o) => o.kind === "reject_once");
|
|
391
|
+
return keepPlanning ? { outcome: { outcome: "selected", optionId: keepPlanning.optionId } } : { outcome: { outcome: "cancelled" } };
|
|
392
|
+
}
|
|
393
|
+
return autoAllowPermissionHandler(params);
|
|
394
|
+
};
|
|
395
|
+
function defaultPermissionHandlerForMode(requestedMode) {
|
|
396
|
+
return requestedMode === "plan" ? planModePermissionHandler : autoAllowPermissionHandler;
|
|
397
|
+
}
|
|
328
398
|
function createAcpProtocolArm(options) {
|
|
329
399
|
const { child, cwd } = options;
|
|
330
400
|
if (!child.stdin || !child.stdout) {
|
|
@@ -342,7 +412,7 @@ function createAcpProtocolArm(options) {
|
|
|
342
412
|
return session?.sessionId;
|
|
343
413
|
},
|
|
344
414
|
async connect(opts) {
|
|
345
|
-
const permissionHandler = options.onPermissionRequest ??
|
|
415
|
+
const permissionHandler = options.onPermissionRequest ?? defaultPermissionHandlerForMode(options.requestedMode);
|
|
346
416
|
client = await createAcpClient({
|
|
347
417
|
output,
|
|
348
418
|
input,
|
|
@@ -350,6 +420,8 @@ function createAcpProtocolArm(options) {
|
|
|
350
420
|
capabilities: {
|
|
351
421
|
fs: { readTextFile: true, writeTextFile: true }
|
|
352
422
|
},
|
|
423
|
+
onActivity: opts.onActivity,
|
|
424
|
+
turnIdleTimeoutMs: opts.turnIdleTimeoutMs,
|
|
353
425
|
// Wire the permission handler so the agent's `session/request_permission`
|
|
354
426
|
// callbacks get a real answer instead of bubbling up as
|
|
355
427
|
// "AcpClient.requestPermission: no handler configured" → which
|
|
@@ -370,7 +442,8 @@ function createAcpProtocolArm(options) {
|
|
|
370
442
|
cwd,
|
|
371
443
|
mcpServers: opts.mcpServers,
|
|
372
444
|
...opts.model ? { model: opts.model } : {},
|
|
373
|
-
...opts.effort ? { effort: opts.effort } : {}
|
|
445
|
+
...opts.effort ? { effort: opts.effort } : {},
|
|
446
|
+
...opts.mode ? { mode: opts.mode } : {}
|
|
374
447
|
});
|
|
375
448
|
}
|
|
376
449
|
},
|
|
@@ -395,9 +468,29 @@ function createAcpProtocolArm(options) {
|
|
|
395
468
|
}
|
|
396
469
|
};
|
|
397
470
|
}
|
|
471
|
+
|
|
472
|
+
// src/mcp-servers.ts
|
|
473
|
+
function toFileBasedMcpServers(servers) {
|
|
474
|
+
if (!servers || servers.length === 0) return void 0;
|
|
475
|
+
const out = {};
|
|
476
|
+
for (const s of servers) {
|
|
477
|
+
out[s.name] = s.transport === "stdio" ? { command: s.ref ?? "" } : { url: s.ref ?? "" };
|
|
478
|
+
}
|
|
479
|
+
return out;
|
|
480
|
+
}
|
|
481
|
+
var DEFAULT_OUTPUT = ["--output-format", "stream-json"];
|
|
482
|
+
var DEFAULT_PRE_PROMPT = ["--no-interactive"];
|
|
483
|
+
var DEFAULT_RESUME = { flag: "--resume", kind: "value" };
|
|
398
484
|
function createPrintSession(opts) {
|
|
485
|
+
const config = opts.printConfig;
|
|
486
|
+
const outputFormat = config?.output_format ?? DEFAULT_OUTPUT;
|
|
487
|
+
const prePrompt = config?.pre_prompt ?? DEFAULT_PRE_PROMPT;
|
|
488
|
+
const promptFlag = config?.prompt_flag;
|
|
489
|
+
const resumeCfg = config?.resume ?? DEFAULT_RESUME;
|
|
490
|
+
const eventSchema = config?.event_schema ?? "claude-stream-json";
|
|
399
491
|
let sessionId = opts.resumeSessionId ?? "";
|
|
400
492
|
let activeChild = null;
|
|
493
|
+
const mcpRestore = setupMcpConfigFile(opts, eventSchema);
|
|
401
494
|
return {
|
|
402
495
|
get sessionId() {
|
|
403
496
|
return sessionId;
|
|
@@ -406,13 +499,18 @@ function createPrintSession(opts) {
|
|
|
406
499
|
const prompt = extractPromptText(message);
|
|
407
500
|
const args = [
|
|
408
501
|
...opts.baseArgs,
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
"stream-json",
|
|
412
|
-
"--no-interactive",
|
|
413
|
-
...sessionId ? ["--resume", sessionId] : [],
|
|
414
|
-
prompt
|
|
502
|
+
...outputFormat,
|
|
503
|
+
...prePrompt
|
|
415
504
|
];
|
|
505
|
+
if (sessionId) {
|
|
506
|
+
args.push(resumeCfg.flag);
|
|
507
|
+
if (resumeCfg.kind === "value") args.push(sessionId);
|
|
508
|
+
}
|
|
509
|
+
if (promptFlag) {
|
|
510
|
+
args.push(promptFlag, prompt);
|
|
511
|
+
} else {
|
|
512
|
+
args.push(prompt);
|
|
513
|
+
}
|
|
416
514
|
const child = spawn(opts.bin, args, {
|
|
417
515
|
cwd: opts.cwd,
|
|
418
516
|
env: opts.env,
|
|
@@ -430,32 +528,38 @@ function createPrintSession(opts) {
|
|
|
430
528
|
}
|
|
431
529
|
});
|
|
432
530
|
try {
|
|
433
|
-
if (!child.stdout)
|
|
434
|
-
|
|
531
|
+
if (!child.stdout)
|
|
532
|
+
throw new Error("print-arm: child has no stdout pipe");
|
|
435
533
|
let capturedSessionId = "";
|
|
436
|
-
|
|
437
|
-
|
|
534
|
+
const mastraState = eventSchema === "mastra-jsonl" ? createMastraMapperState() : void 0;
|
|
535
|
+
const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
536
|
+
const queue = new EventQueue();
|
|
537
|
+
rl.on("line", (line) => {
|
|
538
|
+
if (!line.trim()) return;
|
|
438
539
|
let evt;
|
|
439
540
|
try {
|
|
440
541
|
evt = JSON.parse(line);
|
|
441
542
|
} catch {
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
if (evt.type === "result" && typeof evt.session_id === "string" && evt.session_id) {
|
|
445
|
-
capturedSessionId = evt.session_id;
|
|
543
|
+
return;
|
|
446
544
|
}
|
|
545
|
+
const csid = captureSessionId(evt, eventSchema);
|
|
546
|
+
if (csid) capturedSessionId = csid;
|
|
447
547
|
const sid = capturedSessionId || sessionId || "";
|
|
448
|
-
const mapped = mapEvent(evt, sid, stderrLines);
|
|
449
|
-
if (
|
|
548
|
+
const mapped = mapEvent(evt, sid, stderrLines, eventSchema, mastraState);
|
|
549
|
+
if (mapped) queue.push(mapped);
|
|
550
|
+
});
|
|
551
|
+
rl.once("close", () => queue.end());
|
|
552
|
+
for await (const mapped of queue) {
|
|
450
553
|
yield mapped;
|
|
451
554
|
}
|
|
452
555
|
const exitCode = await waitForExit(child);
|
|
453
556
|
if (capturedSessionId) sessionId = capturedSessionId;
|
|
454
557
|
if (exitCode !== 0 && exitCode !== null) {
|
|
558
|
+
const binLabel = eventSchema === "mastra-jsonl" ? "mastracode" : "claude";
|
|
455
559
|
const errEvt = {
|
|
456
560
|
kind: "error",
|
|
457
561
|
error: {
|
|
458
|
-
message:
|
|
562
|
+
message: `${binLabel} exited with code ${exitCode}`,
|
|
459
563
|
...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
|
|
460
564
|
}
|
|
461
565
|
};
|
|
@@ -470,6 +574,75 @@ function createPrintSession(opts) {
|
|
|
470
574
|
},
|
|
471
575
|
async close() {
|
|
472
576
|
activeChild?.kill("SIGTERM");
|
|
577
|
+
mcpRestore?.();
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
function setupMcpConfigFile(opts, eventSchema) {
|
|
582
|
+
if (eventSchema !== "mastra-jsonl") return void 0;
|
|
583
|
+
if (!opts.mcpServers || opts.mcpServers.length === 0) return void 0;
|
|
584
|
+
const dir = join(opts.cwd, ".mastracode");
|
|
585
|
+
const file = join(dir, "mcp.json");
|
|
586
|
+
const injected = toFileBasedMcpServers(opts.mcpServers);
|
|
587
|
+
if (!injected) return void 0;
|
|
588
|
+
const fileExisted = existsSync(file);
|
|
589
|
+
let originalContent;
|
|
590
|
+
if (fileExisted) {
|
|
591
|
+
try {
|
|
592
|
+
originalContent = readFileSync(file, "utf8");
|
|
593
|
+
} catch {
|
|
594
|
+
originalContent = void 0;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const dirExisted = existsSync(dir);
|
|
598
|
+
if (!dirExisted) {
|
|
599
|
+
mkdirSync(dir, { recursive: true });
|
|
600
|
+
}
|
|
601
|
+
let existingServers = {};
|
|
602
|
+
if (originalContent !== void 0) {
|
|
603
|
+
try {
|
|
604
|
+
const parsed = JSON.parse(originalContent);
|
|
605
|
+
if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
|
|
606
|
+
existingServers = parsed.mcpServers;
|
|
607
|
+
}
|
|
608
|
+
} catch {
|
|
609
|
+
existingServers = {};
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const merged = { ...existingServers, ...injected };
|
|
613
|
+
const output = JSON.stringify({ mcpServers: merged }, null, 2);
|
|
614
|
+
writeFileSync(file, output, "utf8");
|
|
615
|
+
return () => {
|
|
616
|
+
try {
|
|
617
|
+
if (!fileExisted) {
|
|
618
|
+
rmSync(file, { force: true });
|
|
619
|
+
if (!dirExisted) {
|
|
620
|
+
try {
|
|
621
|
+
rmdirSync(dir);
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
} else if (originalContent !== void 0) {
|
|
626
|
+
let current = {};
|
|
627
|
+
try {
|
|
628
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
629
|
+
if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
|
|
630
|
+
current = parsed.mcpServers;
|
|
631
|
+
}
|
|
632
|
+
} catch {
|
|
633
|
+
writeFileSync(file, originalContent, "utf8");
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
for (const key of Object.keys(injected)) {
|
|
637
|
+
delete current[key];
|
|
638
|
+
}
|
|
639
|
+
if (Object.keys(current).length === 0) {
|
|
640
|
+
writeFileSync(file, originalContent, "utf8");
|
|
641
|
+
} else {
|
|
642
|
+
writeFileSync(file, JSON.stringify({ mcpServers: current }, null, 2), "utf8");
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
} catch {
|
|
473
646
|
}
|
|
474
647
|
};
|
|
475
648
|
}
|
|
@@ -484,7 +657,33 @@ function extractPromptText(message) {
|
|
|
484
657
|
}
|
|
485
658
|
return JSON.stringify(message);
|
|
486
659
|
}
|
|
487
|
-
function
|
|
660
|
+
function captureSessionId(evt, schema) {
|
|
661
|
+
switch (schema) {
|
|
662
|
+
case "claude-stream-json":
|
|
663
|
+
if (evt.type === "result" && typeof evt.session_id === "string" && evt.session_id)
|
|
664
|
+
return evt.session_id;
|
|
665
|
+
return null;
|
|
666
|
+
case "mastra-jsonl":
|
|
667
|
+
if (evt.type === "result" && typeof evt.threadId === "string" && evt.threadId)
|
|
668
|
+
return evt.threadId;
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
function mapEvent(evt, sessionId, stderrLines, schema, mastraState) {
|
|
673
|
+
switch (schema) {
|
|
674
|
+
case "claude-stream-json":
|
|
675
|
+
return mapClaudeEvent(evt, sessionId, stderrLines);
|
|
676
|
+
case "mastra-jsonl": {
|
|
677
|
+
if (!mastraState) {
|
|
678
|
+
return mapClaudeEvent(evt, sessionId, stderrLines);
|
|
679
|
+
}
|
|
680
|
+
return mapMastraEvent(evt, sessionId, stderrLines, mastraState);
|
|
681
|
+
}
|
|
682
|
+
default:
|
|
683
|
+
return mapClaudeEvent(evt, sessionId, stderrLines);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function mapClaudeEvent(evt, sessionId, stderrLines) {
|
|
488
687
|
switch (evt.type) {
|
|
489
688
|
case "text":
|
|
490
689
|
return typeof evt.text === "string" ? { kind: "text-delta", sessionId, text: evt.text } : null;
|
|
@@ -528,6 +727,197 @@ function mapEvent(evt, sessionId, stderrLines) {
|
|
|
528
727
|
return null;
|
|
529
728
|
}
|
|
530
729
|
}
|
|
730
|
+
function createMastraMapperState() {
|
|
731
|
+
return { lastTextLength: 0 };
|
|
732
|
+
}
|
|
733
|
+
function extractTextFromBlocks(content) {
|
|
734
|
+
if (!Array.isArray(content)) return "";
|
|
735
|
+
return content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
|
|
736
|
+
}
|
|
737
|
+
function mapMastraEvent(evt, sessionId, stderrLines, state) {
|
|
738
|
+
switch (evt.type) {
|
|
739
|
+
// ── Text streaming ──────────────────────────────────────────
|
|
740
|
+
case "message_update": {
|
|
741
|
+
const content = evt.message?.content;
|
|
742
|
+
const fullText = extractTextFromBlocks(content);
|
|
743
|
+
if (fullText.length > state.lastTextLength) {
|
|
744
|
+
const delta = fullText.slice(state.lastTextLength);
|
|
745
|
+
state.lastTextLength = fullText.length;
|
|
746
|
+
return delta ? { kind: "text-delta", sessionId, text: delta } : null;
|
|
747
|
+
}
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
750
|
+
case "message_end": {
|
|
751
|
+
const msg = evt.message;
|
|
752
|
+
if (msg?.role !== "assistant") return null;
|
|
753
|
+
const fullText = extractTextFromBlocks(msg?.content);
|
|
754
|
+
if (fullText.length > state.lastTextLength) {
|
|
755
|
+
const delta = fullText.slice(state.lastTextLength);
|
|
756
|
+
state.lastTextLength = fullText.length;
|
|
757
|
+
return delta ? { kind: "text-delta", sessionId, text: delta } : null;
|
|
758
|
+
}
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
// ── Tool calls ──────────────────────────────────────────────
|
|
762
|
+
case "tool_start":
|
|
763
|
+
return {
|
|
764
|
+
kind: "tool-call",
|
|
765
|
+
sessionId,
|
|
766
|
+
toolCallId: typeof evt.toolCallId === "string" ? evt.toolCallId : "",
|
|
767
|
+
toolName: typeof evt.toolName === "string" ? evt.toolName : "?",
|
|
768
|
+
// Mastra's controller event carries the tool call payload under
|
|
769
|
+
// `args`, not `input` (that's the Claude Code stream-json field
|
|
770
|
+
// name used by the sibling mapClaudeEvent tool_use case below).
|
|
771
|
+
arguments: evt.args ?? {}
|
|
772
|
+
};
|
|
773
|
+
case "tool_end":
|
|
774
|
+
return {
|
|
775
|
+
kind: "tool-result",
|
|
776
|
+
sessionId,
|
|
777
|
+
toolCallId: typeof evt.toolCallId === "string" ? evt.toolCallId : "",
|
|
778
|
+
result: evt.result ?? null,
|
|
779
|
+
isError: evt.isError === true
|
|
780
|
+
};
|
|
781
|
+
// ── Turn end ────────────────────────────────────────────────
|
|
782
|
+
case "agent_end": {
|
|
783
|
+
const rawReason = typeof evt.reason === "string" ? evt.reason : "complete";
|
|
784
|
+
const reason = mapMastraFinishReason(rawReason);
|
|
785
|
+
return { kind: "turn-end", sessionId, reason };
|
|
786
|
+
}
|
|
787
|
+
// ── Final result line ────────────────────────────────────────
|
|
788
|
+
// Always written last, once, whether or not `agent_end` fired —
|
|
789
|
+
// pre-flight failures (bad model, unresolvable thread, missing API
|
|
790
|
+
// key) call straight into this without ever streaming an
|
|
791
|
+
// `agent_end` or `error` event. `turn-end` already came from
|
|
792
|
+
// `agent_end` on the success path, so this only needs to surface
|
|
793
|
+
// an error for the pre-flight-failure path.
|
|
794
|
+
case "result": {
|
|
795
|
+
const err = evt.error;
|
|
796
|
+
if (!err) return null;
|
|
797
|
+
return {
|
|
798
|
+
kind: "error",
|
|
799
|
+
sessionId,
|
|
800
|
+
error: {
|
|
801
|
+
message: typeof err.message === "string" ? err.message : "Unknown error",
|
|
802
|
+
...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
// ── Errors ─────────────────────────────────────────────────
|
|
807
|
+
case "error": {
|
|
808
|
+
const err = evt.error;
|
|
809
|
+
return {
|
|
810
|
+
kind: "error",
|
|
811
|
+
sessionId,
|
|
812
|
+
error: {
|
|
813
|
+
message: typeof err?.message === "string" ? err.message : "Unknown error",
|
|
814
|
+
...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
// ── Token usage ─────────────────────────────────────────────
|
|
819
|
+
// Mastra Code DOES expose usage: its `AgentController` emits a native
|
|
820
|
+
// `usage_update` event ({ type: "usage_update", usage: TokenUsage })
|
|
821
|
+
// on every model step-finish — verified against @mastra/core 1.48.0's
|
|
822
|
+
// AgentControllerEvent union and its emit site
|
|
823
|
+
// (`this.#session.emit({ type: "usage_update", usage: stepUsage })`).
|
|
824
|
+
// `TokenUsage` carries `{ promptTokens, completionTokens, totalTokens }`.
|
|
825
|
+
// Map it to this repo's `usage_update` StreamEvent (the SAME shape
|
|
826
|
+
// claude-code emits over ACP) so mastracode sessions — both the print
|
|
827
|
+
// arm and the in-process arm, which share this mapper — carry token
|
|
828
|
+
// telemetry in the transcript. mastracode reports these cumulatively
|
|
829
|
+
// (its own headless `runMC` result-usage is last-write-wins over these
|
|
830
|
+
// events), and last-write-wins on the descriptor matches that. It
|
|
831
|
+
// carries no context-window size/used or per-turn cost here, so those
|
|
832
|
+
// stay 0 / absent (projectEvent guards on >0, never clobbering a real
|
|
833
|
+
// size).
|
|
834
|
+
case "usage_update": {
|
|
835
|
+
const usage = evt.usage;
|
|
836
|
+
const promptTokens = typeof usage?.promptTokens === "number" ? usage.promptTokens : void 0;
|
|
837
|
+
const completionTokens = typeof usage?.completionTokens === "number" ? usage.completionTokens : void 0;
|
|
838
|
+
if (promptTokens === void 0 && completionTokens === void 0)
|
|
839
|
+
return null;
|
|
840
|
+
return {
|
|
841
|
+
kind: "usage_update",
|
|
842
|
+
sessionId,
|
|
843
|
+
size: 0,
|
|
844
|
+
used: 0,
|
|
845
|
+
...promptTokens !== void 0 ? { tokensIn: promptTokens } : {},
|
|
846
|
+
...completionTokens !== void 0 ? { tokensOut: completionTokens } : {}
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
// ── Shell output (tool-like) ────────────────────────────────
|
|
850
|
+
case "shell_output":
|
|
851
|
+
return typeof evt.output === "string" ? {
|
|
852
|
+
kind: "tool-result",
|
|
853
|
+
sessionId,
|
|
854
|
+
toolCallId: "",
|
|
855
|
+
result: evt.output,
|
|
856
|
+
isError: false
|
|
857
|
+
} : null;
|
|
858
|
+
// ── Skipped events ─────────────────────────────────────────
|
|
859
|
+
case "agent_start":
|
|
860
|
+
case "subagent_start":
|
|
861
|
+
case "subagent_end":
|
|
862
|
+
case "tool_approval_required":
|
|
863
|
+
case "tool_suspended":
|
|
864
|
+
return null;
|
|
865
|
+
default:
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
var QUEUE_HIGH_WATER_MARK = 1e4;
|
|
870
|
+
var EventQueue = class {
|
|
871
|
+
buffer = [];
|
|
872
|
+
resolveNext = null;
|
|
873
|
+
ended = false;
|
|
874
|
+
highWaterWarned = false;
|
|
875
|
+
push(evt) {
|
|
876
|
+
this.buffer.push(evt);
|
|
877
|
+
if (this.buffer.length > QUEUE_HIGH_WATER_MARK && !this.highWaterWarned) {
|
|
878
|
+
this.highWaterWarned = true;
|
|
879
|
+
console.warn(
|
|
880
|
+
`print-arm: event backlog exceeded ${QUEUE_HIGH_WATER_MARK} buffered events \u2014 downstream consumer is not keeping up. The child's stdout is still being drained (no ENOBUFS), but memory will grow until the consumer catches up.`
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
const resolve = this.resolveNext;
|
|
884
|
+
this.resolveNext = null;
|
|
885
|
+
resolve?.();
|
|
886
|
+
}
|
|
887
|
+
/** Signal that no further events will be pushed. */
|
|
888
|
+
end() {
|
|
889
|
+
this.ended = true;
|
|
890
|
+
const resolve = this.resolveNext;
|
|
891
|
+
this.resolveNext = null;
|
|
892
|
+
resolve?.();
|
|
893
|
+
}
|
|
894
|
+
async *[Symbol.asyncIterator]() {
|
|
895
|
+
for (; ; ) {
|
|
896
|
+
const evt = this.buffer.shift();
|
|
897
|
+
if (evt !== void 0) {
|
|
898
|
+
yield evt;
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
if (this.ended) return;
|
|
902
|
+
await new Promise((resolve) => {
|
|
903
|
+
this.resolveNext = resolve;
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
function mapMastraFinishReason(raw) {
|
|
909
|
+
switch (raw) {
|
|
910
|
+
case "complete":
|
|
911
|
+
return "completed";
|
|
912
|
+
case "aborted":
|
|
913
|
+
case "suspended":
|
|
914
|
+
return "cancelled";
|
|
915
|
+
case "error":
|
|
916
|
+
return "error";
|
|
917
|
+
default:
|
|
918
|
+
return "completed";
|
|
919
|
+
}
|
|
920
|
+
}
|
|
531
921
|
function waitForExit(child) {
|
|
532
922
|
return new Promise((resolve) => {
|
|
533
923
|
child.once("exit", (code) => resolve(code));
|
|
@@ -535,6 +925,27 @@ function waitForExit(child) {
|
|
|
535
925
|
});
|
|
536
926
|
}
|
|
537
927
|
|
|
928
|
+
// src/protocol/proprietary.ts
|
|
929
|
+
async function createProprietaryProtocolArm(options) {
|
|
930
|
+
let mod;
|
|
931
|
+
try {
|
|
932
|
+
mod = await import(options.adapter);
|
|
933
|
+
} catch (err) {
|
|
934
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
935
|
+
throw new Error(
|
|
936
|
+
`createProprietaryProtocolArm: could not load adapter package '${options.adapter}'. Install it with: npm i ${options.adapter}
|
|
937
|
+
cause: ${cause}`
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
const candidate = "createAgentCliClient" in mod ? mod.createAgentCliClient : mod.default;
|
|
941
|
+
if (typeof candidate !== "function") {
|
|
942
|
+
throw new Error(
|
|
943
|
+
`createProprietaryProtocolArm: adapter package '${options.adapter}' does not export a 'createAgentCliClient' factory function (or a default export function). A protocol="proprietary" adapter must export createAgentCliClient(definition: AgentCliHandle): AgentCliClient | Promise<AgentCliClient>.`
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
return await candidate(options.definition);
|
|
947
|
+
}
|
|
948
|
+
|
|
538
949
|
// src/manifest/compose.ts
|
|
539
950
|
var RuntimeConfigError = class extends Error {
|
|
540
951
|
code;
|
|
@@ -547,9 +958,11 @@ var RuntimeConfigError = class extends Error {
|
|
|
547
958
|
}
|
|
548
959
|
};
|
|
549
960
|
function composeSpawn(handle, config) {
|
|
550
|
-
|
|
961
|
+
if (!config) return { binArgs: [...handle.bin_args ?? []], env: {}, envUnset: [] };
|
|
962
|
+
const prepend = [];
|
|
963
|
+
const append = [];
|
|
551
964
|
const env = {};
|
|
552
|
-
|
|
965
|
+
const envUnset = [];
|
|
553
966
|
if (config.mode !== void 0) {
|
|
554
967
|
const mode = (handle.modes ?? []).find((m) => m.id === config.mode);
|
|
555
968
|
if (!mode) {
|
|
@@ -560,8 +973,12 @@ function composeSpawn(handle, config) {
|
|
|
560
973
|
`Mode '${config.mode}' is not declared by manifest '${handle.id}'. Known modes: ${known}`
|
|
561
974
|
);
|
|
562
975
|
}
|
|
563
|
-
if (mode.
|
|
564
|
-
|
|
976
|
+
if ((mode.apply ?? "bin_args") === "bin_args") {
|
|
977
|
+
if (mode.bin_args_prepend) prepend.push(...mode.bin_args_prepend);
|
|
978
|
+
if (mode.bin_args_append) append.push(...mode.bin_args_append);
|
|
979
|
+
if (mode.env) Object.assign(env, mode.env);
|
|
980
|
+
if (mode.env_unset) envUnset.push(...mode.env_unset);
|
|
981
|
+
}
|
|
565
982
|
}
|
|
566
983
|
if (config.options && Object.keys(config.options).length > 0) {
|
|
567
984
|
const declared = handle.options ?? [];
|
|
@@ -581,8 +998,23 @@ function composeSpawn(handle, config) {
|
|
|
581
998
|
const value = config.options[option.id];
|
|
582
999
|
validateOptionValue(option, value);
|
|
583
1000
|
const patch = renderOptionPatch(option, value);
|
|
584
|
-
|
|
1001
|
+
prepend.push(...patch.prepend);
|
|
1002
|
+
append.push(...patch.append);
|
|
585
1003
|
Object.assign(env, patch.env);
|
|
1004
|
+
if (patch.envUnset.length) envUnset.push(...patch.envUnset);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
const requestedModel = config.options?.model;
|
|
1008
|
+
if (typeof requestedModel === "string" && handle.models?.deny?.length) {
|
|
1009
|
+
const denyHit = handle.models.deny.find(
|
|
1010
|
+
(pattern) => matchesModelPattern(pattern, requestedModel)
|
|
1011
|
+
);
|
|
1012
|
+
if (denyHit) {
|
|
1013
|
+
throw new RuntimeConfigError(
|
|
1014
|
+
"model_denied",
|
|
1015
|
+
"config.options.model",
|
|
1016
|
+
`Model '${requestedModel}' is denied by manifest '${handle.id}' (matches deny pattern '${denyHit}'). This adapter deliberately does not route to that provider \u2014 use a permitted model or a different adapter.`
|
|
1017
|
+
);
|
|
586
1018
|
}
|
|
587
1019
|
}
|
|
588
1020
|
if (config.continuation !== void 0 && handle.continuation) {
|
|
@@ -594,12 +1026,21 @@ function composeSpawn(handle, config) {
|
|
|
594
1026
|
);
|
|
595
1027
|
}
|
|
596
1028
|
}
|
|
597
|
-
return {
|
|
1029
|
+
return {
|
|
1030
|
+
binArgs: [...prepend, ...handle.bin_args ?? [], ...append],
|
|
1031
|
+
env,
|
|
1032
|
+
envUnset
|
|
1033
|
+
};
|
|
598
1034
|
}
|
|
599
1035
|
function resolveContinuationStrategy(handle, config) {
|
|
600
1036
|
if (config?.continuation) return config.continuation;
|
|
601
1037
|
return handle.continuation?.default ?? "none";
|
|
602
1038
|
}
|
|
1039
|
+
function matchesModelPattern(pattern, modelId) {
|
|
1040
|
+
const p = pattern.toLowerCase();
|
|
1041
|
+
const m = modelId.toLowerCase();
|
|
1042
|
+
return p.endsWith("*") ? m.startsWith(p.slice(0, -1)) : m === p;
|
|
1043
|
+
}
|
|
603
1044
|
function validateOptionValue(option, value) {
|
|
604
1045
|
const path = `config.options.${option.id}`;
|
|
605
1046
|
switch (option.type) {
|
|
@@ -665,17 +1106,23 @@ function validateOptionValue(option, value) {
|
|
|
665
1106
|
function renderOptionPatch(option, value) {
|
|
666
1107
|
const stringValue = String(value);
|
|
667
1108
|
if (option.type === "boolean") {
|
|
668
|
-
if (value !== true) return {
|
|
1109
|
+
if (value !== true) return { prepend: [], append: [], env: {}, envUnset: [] };
|
|
669
1110
|
return {
|
|
670
|
-
|
|
671
|
-
|
|
1111
|
+
prepend: [],
|
|
1112
|
+
append: option.bin_args_append_when_true ? [...option.bin_args_append_when_true] : [],
|
|
1113
|
+
env: option.env ? interpolateEnv(option.env, stringValue) : {},
|
|
1114
|
+
envUnset: option.env_unset ? [...option.env_unset] : []
|
|
672
1115
|
};
|
|
673
1116
|
}
|
|
674
1117
|
return {
|
|
675
|
-
|
|
1118
|
+
prepend: option.bin_args_prepend ? option.bin_args_prepend.map(
|
|
676
1119
|
(token) => token.replace(/\{value\}/g, stringValue)
|
|
677
1120
|
) : [],
|
|
678
|
-
|
|
1121
|
+
append: option.bin_args_template ? option.bin_args_template.map(
|
|
1122
|
+
(token) => token.replace(/\{value\}/g, stringValue)
|
|
1123
|
+
) : [],
|
|
1124
|
+
env: option.env ? interpolateEnv(option.env, stringValue) : {},
|
|
1125
|
+
envUnset: option.env_unset ? [...option.env_unset] : []
|
|
679
1126
|
};
|
|
680
1127
|
}
|
|
681
1128
|
function interpolateEnv(env, value) {
|
|
@@ -732,35 +1179,55 @@ function createAgentCliRuntime(definition) {
|
|
|
732
1179
|
const composed = composeSpawn(definition, opts?.config);
|
|
733
1180
|
const env = {
|
|
734
1181
|
...filterStringEnv(process.env),
|
|
735
|
-
...composed.env
|
|
736
|
-
...opts?.env ?? {}
|
|
1182
|
+
...composed.env
|
|
737
1183
|
};
|
|
1184
|
+
for (const k of composed.envUnset) delete env[k];
|
|
1185
|
+
Object.assign(env, opts?.env ?? {});
|
|
1186
|
+
const permissionMode = resolveClaudeCodePermissionMode(
|
|
1187
|
+
definition,
|
|
1188
|
+
opts?.config?.mode
|
|
1189
|
+
);
|
|
1190
|
+
if (permissionMode) {
|
|
1191
|
+
const configDir = mkdtempSync(
|
|
1192
|
+
join(tmpdir(), "agentproto-claude-config-")
|
|
1193
|
+
);
|
|
1194
|
+
writeFileSync(
|
|
1195
|
+
join(configDir, "settings.json"),
|
|
1196
|
+
JSON.stringify({ permissions: { defaultMode: permissionMode } })
|
|
1197
|
+
);
|
|
1198
|
+
env.CLAUDE_CONFIG_DIR = configDir;
|
|
1199
|
+
}
|
|
738
1200
|
if (definition.protocol === "print") {
|
|
739
1201
|
return createPrintSession({
|
|
740
1202
|
bin: definition.bin,
|
|
741
1203
|
baseArgs: composed.binArgs,
|
|
742
1204
|
cwd,
|
|
743
1205
|
env,
|
|
744
|
-
...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}
|
|
1206
|
+
...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {},
|
|
1207
|
+
...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
|
|
1208
|
+
printConfig: definition.print
|
|
745
1209
|
});
|
|
746
1210
|
}
|
|
747
|
-
|
|
748
|
-
cwd,
|
|
749
|
-
env,
|
|
750
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
751
|
-
signal: opts?.signal
|
|
752
|
-
});
|
|
1211
|
+
let child;
|
|
753
1212
|
const stderrBuf = [];
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1213
|
+
if (definition.protocol !== "proprietary") {
|
|
1214
|
+
child = spawn(definition.bin, composed.binArgs, {
|
|
1215
|
+
cwd,
|
|
1216
|
+
env,
|
|
1217
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1218
|
+
signal: opts?.signal
|
|
1219
|
+
});
|
|
1220
|
+
const STDERR_KEEP_LINES = 80;
|
|
1221
|
+
child.stderr?.setEncoding("utf8");
|
|
1222
|
+
child.stderr?.on("data", (chunk) => {
|
|
1223
|
+
for (const line of chunk.split(/\r?\n/)) {
|
|
1224
|
+
if (!line) continue;
|
|
1225
|
+
stderrBuf.push(line);
|
|
1226
|
+
if (stderrBuf.length > STDERR_KEEP_LINES) stderrBuf.shift();
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
const arm = await buildProtocolArm(definition, child, cwd, opts?.config?.mode);
|
|
764
1231
|
arm._stderrTail = () => stderrBuf.join("\n");
|
|
765
1232
|
const abortController = new AbortController();
|
|
766
1233
|
if (opts?.signal) {
|
|
@@ -772,6 +1239,10 @@ function createAgentCliRuntime(definition) {
|
|
|
772
1239
|
const optEffort = opts?.config?.options?.effort;
|
|
773
1240
|
const modelApply = definition.models?.apply ?? "config";
|
|
774
1241
|
const configModel = optModel && modelApply === "config" ? String(optModel) : void 0;
|
|
1242
|
+
const requestedModeId = opts?.config?.mode;
|
|
1243
|
+
const requestedModeDecl = requestedModeId ? (definition.modes ?? []).find((m) => m.id === requestedModeId) : void 0;
|
|
1244
|
+
const configMode = requestedModeDecl?.apply === "config" ? requestedModeId : void 0;
|
|
1245
|
+
const turnIdleTimeoutMs = opts?.turnIdleTimeoutMs ?? definition.session?.turn_idle_timeout_ms;
|
|
775
1246
|
await arm.connect({
|
|
776
1247
|
cwd,
|
|
777
1248
|
env,
|
|
@@ -779,7 +1250,10 @@ function createAgentCliRuntime(definition) {
|
|
|
779
1250
|
...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {},
|
|
780
1251
|
...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
|
|
781
1252
|
...configModel ? { model: configModel } : {},
|
|
782
|
-
...optEffort ? { effort: String(optEffort) } : {}
|
|
1253
|
+
...optEffort ? { effort: String(optEffort) } : {},
|
|
1254
|
+
...configMode ? { mode: configMode } : {},
|
|
1255
|
+
...opts?.onActivity ? { onActivity: opts.onActivity } : {},
|
|
1256
|
+
...turnIdleTimeoutMs !== void 0 ? { turnIdleTimeoutMs } : {}
|
|
783
1257
|
});
|
|
784
1258
|
if (optModel && modelApply === "command") {
|
|
785
1259
|
await applyModelCommand(arm, String(optModel));
|
|
@@ -787,6 +1261,7 @@ function createAgentCliRuntime(definition) {
|
|
|
787
1261
|
const sessionId = arm.sessionId ?? randomUUID();
|
|
788
1262
|
return {
|
|
789
1263
|
sessionId,
|
|
1264
|
+
pid: child?.pid,
|
|
790
1265
|
send(message) {
|
|
791
1266
|
const turnId = randomUUID();
|
|
792
1267
|
return promptTurn(arm, turnId, message);
|
|
@@ -796,7 +1271,7 @@ function createAgentCliRuntime(definition) {
|
|
|
796
1271
|
},
|
|
797
1272
|
async close() {
|
|
798
1273
|
await arm.close();
|
|
799
|
-
if (!child.killed) child.kill("SIGTERM");
|
|
1274
|
+
if (child && !child.killed) child.kill("SIGTERM");
|
|
800
1275
|
}
|
|
801
1276
|
};
|
|
802
1277
|
}
|
|
@@ -839,24 +1314,39 @@ async function* promptTurn(arm, turnId, message) {
|
|
|
839
1314
|
yield evt;
|
|
840
1315
|
}
|
|
841
1316
|
}
|
|
842
|
-
function buildProtocolArm(def, child, cwd) {
|
|
1317
|
+
async function buildProtocolArm(def, child, cwd, requestedMode) {
|
|
843
1318
|
switch (def.protocol) {
|
|
844
1319
|
case "acp":
|
|
1320
|
+
if (!child) {
|
|
1321
|
+
throw new Error("createAgentCliRuntime: acp protocol requires a spawned subprocess");
|
|
1322
|
+
}
|
|
845
1323
|
return createAcpProtocolArm({
|
|
846
1324
|
child,
|
|
847
1325
|
cwd,
|
|
848
|
-
clientInfo: { name: def.id, version: def.version }
|
|
1326
|
+
clientInfo: { name: def.id, version: def.version },
|
|
1327
|
+
requestedMode
|
|
849
1328
|
});
|
|
850
1329
|
case "mcp":
|
|
851
1330
|
throw new Error("createAgentCliRuntime: mcp protocol arm not yet implemented");
|
|
852
1331
|
case "proprietary":
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1332
|
+
if (!def.adapter) {
|
|
1333
|
+
throw new Error(
|
|
1334
|
+
"createAgentCliRuntime: proprietary protocol requires manifest.adapter"
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
return createProprietaryProtocolArm({ adapter: def.adapter, definition: def });
|
|
856
1338
|
case "print":
|
|
857
1339
|
throw new Error("createAgentCliRuntime: print arm bypasses buildProtocolArm");
|
|
858
1340
|
}
|
|
859
1341
|
}
|
|
1342
|
+
function resolveClaudeCodePermissionMode(definition, configMode) {
|
|
1343
|
+
if (definition.id !== "claude-code" || !configMode) return void 0;
|
|
1344
|
+
const mode = (definition.modes ?? []).find((m) => m.id === configMode);
|
|
1345
|
+
const args = mode?.bin_args_append ?? [];
|
|
1346
|
+
const flagIndex = args.indexOf("--permission-mode");
|
|
1347
|
+
if (flagIndex === -1 || flagIndex + 1 >= args.length) return void 0;
|
|
1348
|
+
return args[flagIndex + 1];
|
|
1349
|
+
}
|
|
860
1350
|
function filterStringEnv(env) {
|
|
861
1351
|
const out = {};
|
|
862
1352
|
for (const [k, v] of Object.entries(env)) {
|
|
@@ -865,6 +1355,6 @@ function filterStringEnv(env) {
|
|
|
865
1355
|
return out;
|
|
866
1356
|
}
|
|
867
1357
|
|
|
868
|
-
export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createPrintSession, defineAgentCli, resolveContinuationStrategy, runtimeConfigSchema };
|
|
869
|
-
//# sourceMappingURL=chunk-
|
|
870
|
-
//# sourceMappingURL=chunk-
|
|
1358
|
+
export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
|
|
1359
|
+
//# sourceMappingURL=chunk-L6BRNMVP.mjs.map
|
|
1360
|
+
//# sourceMappingURL=chunk-L6BRNMVP.mjs.map
|