@agentproto/driver-agent-cli 0.2.0 → 0.3.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.
@@ -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,6 +153,11 @@ 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();
@@ -225,6 +233,16 @@ var mcpBlockSchema = z.object({
225
233
  transport: z.enum(["stdio", "http", "sse"]),
226
234
  url: z.string().url().optional()
227
235
  }).strict();
236
+ var printConfigSchema = z.object({
237
+ prompt_flag: z.string().optional(),
238
+ output_format: z.array(z.string()).optional(),
239
+ pre_prompt: z.array(z.string()).optional(),
240
+ resume: z.object({
241
+ flag: z.string(),
242
+ kind: z.enum(["value", "boolean"])
243
+ }).strict().optional(),
244
+ event_schema: z.enum(["claude-stream-json", "mastra-jsonl"]).optional()
245
+ }).strict().optional();
228
246
  var agentCliFrontmatterSchema = z.object({
229
247
  name: z.string().min(1).max(80),
230
248
  id: z.string().regex(ID_PATTERN),
@@ -242,6 +260,7 @@ var agentCliFrontmatterSchema = z.object({
242
260
  acp: z.string().optional(),
243
261
  mcp: mcpBlockSchema.optional(),
244
262
  adapter: z.string().regex(ADAPTER_PATTERN).optional(),
263
+ print: printConfigSchema,
245
264
  session: sessionSchema.optional(),
246
265
  models: modelsSchema.optional(),
247
266
  capabilities: capabilitiesSchema.optional(),
@@ -325,6 +344,21 @@ var autoAllowPermissionHandler = ({
325
344
  const allow = options.find((o) => typeof o.kind === "string" && o.kind.startsWith("allow_")) ?? options[0];
326
345
  return { outcome: { outcome: "selected", optionId: allow.optionId } };
327
346
  };
347
+ var PLAN_MODE_EXIT_TOOL_CALL_KIND = "switch_mode";
348
+ var planModePermissionHandler = (params) => {
349
+ const { options, toolCall } = params;
350
+ if (!options || options.length === 0) {
351
+ return { outcome: { outcome: "cancelled" } };
352
+ }
353
+ if (toolCall?.kind === PLAN_MODE_EXIT_TOOL_CALL_KIND) {
354
+ const keepPlanning = options.find((o) => o.kind === "reject_once");
355
+ return keepPlanning ? { outcome: { outcome: "selected", optionId: keepPlanning.optionId } } : { outcome: { outcome: "cancelled" } };
356
+ }
357
+ return autoAllowPermissionHandler(params);
358
+ };
359
+ function defaultPermissionHandlerForMode(requestedMode) {
360
+ return requestedMode === "plan" ? planModePermissionHandler : autoAllowPermissionHandler;
361
+ }
328
362
  function createAcpProtocolArm(options) {
329
363
  const { child, cwd } = options;
330
364
  if (!child.stdin || !child.stdout) {
@@ -342,7 +376,7 @@ function createAcpProtocolArm(options) {
342
376
  return session?.sessionId;
343
377
  },
344
378
  async connect(opts) {
345
- const permissionHandler = options.onPermissionRequest ?? autoAllowPermissionHandler;
379
+ const permissionHandler = options.onPermissionRequest ?? defaultPermissionHandlerForMode(options.requestedMode);
346
380
  client = await createAcpClient({
347
381
  output,
348
382
  input,
@@ -350,6 +384,8 @@ function createAcpProtocolArm(options) {
350
384
  capabilities: {
351
385
  fs: { readTextFile: true, writeTextFile: true }
352
386
  },
387
+ onActivity: opts.onActivity,
388
+ turnIdleTimeoutMs: opts.turnIdleTimeoutMs,
353
389
  // Wire the permission handler so the agent's `session/request_permission`
354
390
  // callbacks get a real answer instead of bubbling up as
355
391
  // "AcpClient.requestPermission: no handler configured" → which
@@ -395,9 +431,29 @@ function createAcpProtocolArm(options) {
395
431
  }
396
432
  };
397
433
  }
434
+
435
+ // src/mcp-servers.ts
436
+ function toFileBasedMcpServers(servers) {
437
+ if (!servers || servers.length === 0) return void 0;
438
+ const out = {};
439
+ for (const s of servers) {
440
+ out[s.name] = s.transport === "stdio" ? { command: s.ref ?? "" } : { url: s.ref ?? "" };
441
+ }
442
+ return out;
443
+ }
444
+ var DEFAULT_OUTPUT = ["--output-format", "stream-json"];
445
+ var DEFAULT_PRE_PROMPT = ["--no-interactive"];
446
+ var DEFAULT_RESUME = { flag: "--resume", kind: "value" };
398
447
  function createPrintSession(opts) {
448
+ const config = opts.printConfig;
449
+ const outputFormat = config?.output_format ?? DEFAULT_OUTPUT;
450
+ const prePrompt = config?.pre_prompt ?? DEFAULT_PRE_PROMPT;
451
+ const promptFlag = config?.prompt_flag;
452
+ const resumeCfg = config?.resume ?? DEFAULT_RESUME;
453
+ const eventSchema = config?.event_schema ?? "claude-stream-json";
399
454
  let sessionId = opts.resumeSessionId ?? "";
400
455
  let activeChild = null;
456
+ const mcpRestore = setupMcpConfigFile(opts, eventSchema);
401
457
  return {
402
458
  get sessionId() {
403
459
  return sessionId;
@@ -406,13 +462,18 @@ function createPrintSession(opts) {
406
462
  const prompt = extractPromptText(message);
407
463
  const args = [
408
464
  ...opts.baseArgs,
409
- "--print",
410
- "--output-format",
411
- "stream-json",
412
- "--no-interactive",
413
- ...sessionId ? ["--resume", sessionId] : [],
414
- prompt
465
+ ...outputFormat,
466
+ ...prePrompt
415
467
  ];
468
+ if (sessionId) {
469
+ args.push(resumeCfg.flag);
470
+ if (resumeCfg.kind === "value") args.push(sessionId);
471
+ }
472
+ if (promptFlag) {
473
+ args.push(promptFlag, prompt);
474
+ } else {
475
+ args.push(prompt);
476
+ }
416
477
  const child = spawn(opts.bin, args, {
417
478
  cwd: opts.cwd,
418
479
  env: opts.env,
@@ -430,9 +491,11 @@ function createPrintSession(opts) {
430
491
  }
431
492
  });
432
493
  try {
433
- if (!child.stdout) throw new Error("print-arm: child has no stdout pipe");
494
+ if (!child.stdout)
495
+ throw new Error("print-arm: child has no stdout pipe");
434
496
  const rl = createInterface({ input: child.stdout, crlfDelay: Infinity });
435
497
  let capturedSessionId = "";
498
+ const mastraState = eventSchema === "mastra-jsonl" ? createMastraMapperState() : void 0;
436
499
  for await (const line of rl) {
437
500
  if (!line.trim()) continue;
438
501
  let evt;
@@ -441,21 +504,21 @@ function createPrintSession(opts) {
441
504
  } catch {
442
505
  continue;
443
506
  }
444
- if (evt.type === "result" && typeof evt.session_id === "string" && evt.session_id) {
445
- capturedSessionId = evt.session_id;
446
- }
507
+ const csid = captureSessionId(evt, eventSchema);
508
+ if (csid) capturedSessionId = csid;
447
509
  const sid = capturedSessionId || sessionId || "";
448
- const mapped = mapEvent(evt, sid, stderrLines);
510
+ const mapped = mapEvent(evt, sid, stderrLines, eventSchema, mastraState);
449
511
  if (!mapped) continue;
450
512
  yield mapped;
451
513
  }
452
514
  const exitCode = await waitForExit(child);
453
515
  if (capturedSessionId) sessionId = capturedSessionId;
454
516
  if (exitCode !== 0 && exitCode !== null) {
517
+ const binLabel = eventSchema === "mastra-jsonl" ? "mastracode" : "claude";
455
518
  const errEvt = {
456
519
  kind: "error",
457
520
  error: {
458
- message: `claude exited with code ${exitCode}`,
521
+ message: `${binLabel} exited with code ${exitCode}`,
459
522
  ...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
460
523
  }
461
524
  };
@@ -470,6 +533,75 @@ function createPrintSession(opts) {
470
533
  },
471
534
  async close() {
472
535
  activeChild?.kill("SIGTERM");
536
+ mcpRestore?.();
537
+ }
538
+ };
539
+ }
540
+ function setupMcpConfigFile(opts, eventSchema) {
541
+ if (eventSchema !== "mastra-jsonl") return void 0;
542
+ if (!opts.mcpServers || opts.mcpServers.length === 0) return void 0;
543
+ const dir = join(opts.cwd, ".mastracode");
544
+ const file = join(dir, "mcp.json");
545
+ const injected = toFileBasedMcpServers(opts.mcpServers);
546
+ if (!injected) return void 0;
547
+ const fileExisted = existsSync(file);
548
+ let originalContent;
549
+ if (fileExisted) {
550
+ try {
551
+ originalContent = readFileSync(file, "utf8");
552
+ } catch {
553
+ originalContent = void 0;
554
+ }
555
+ }
556
+ const dirExisted = existsSync(dir);
557
+ if (!dirExisted) {
558
+ mkdirSync(dir, { recursive: true });
559
+ }
560
+ let existingServers = {};
561
+ if (originalContent !== void 0) {
562
+ try {
563
+ const parsed = JSON.parse(originalContent);
564
+ if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
565
+ existingServers = parsed.mcpServers;
566
+ }
567
+ } catch {
568
+ existingServers = {};
569
+ }
570
+ }
571
+ const merged = { ...existingServers, ...injected };
572
+ const output = JSON.stringify({ mcpServers: merged }, null, 2);
573
+ writeFileSync(file, output, "utf8");
574
+ return () => {
575
+ try {
576
+ if (!fileExisted) {
577
+ rmSync(file, { force: true });
578
+ if (!dirExisted) {
579
+ try {
580
+ rmdirSync(dir);
581
+ } catch {
582
+ }
583
+ }
584
+ } else if (originalContent !== void 0) {
585
+ let current = {};
586
+ try {
587
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
588
+ if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
589
+ current = parsed.mcpServers;
590
+ }
591
+ } catch {
592
+ writeFileSync(file, originalContent, "utf8");
593
+ return;
594
+ }
595
+ for (const key of Object.keys(injected)) {
596
+ delete current[key];
597
+ }
598
+ if (Object.keys(current).length === 0) {
599
+ writeFileSync(file, originalContent, "utf8");
600
+ } else {
601
+ writeFileSync(file, JSON.stringify({ mcpServers: current }, null, 2), "utf8");
602
+ }
603
+ }
604
+ } catch {
473
605
  }
474
606
  };
475
607
  }
@@ -484,7 +616,33 @@ function extractPromptText(message) {
484
616
  }
485
617
  return JSON.stringify(message);
486
618
  }
487
- function mapEvent(evt, sessionId, stderrLines) {
619
+ function captureSessionId(evt, schema) {
620
+ switch (schema) {
621
+ case "claude-stream-json":
622
+ if (evt.type === "result" && typeof evt.session_id === "string" && evt.session_id)
623
+ return evt.session_id;
624
+ return null;
625
+ case "mastra-jsonl":
626
+ if (evt.type === "result" && typeof evt.threadId === "string" && evt.threadId)
627
+ return evt.threadId;
628
+ return null;
629
+ }
630
+ }
631
+ function mapEvent(evt, sessionId, stderrLines, schema, mastraState) {
632
+ switch (schema) {
633
+ case "claude-stream-json":
634
+ return mapClaudeEvent(evt, sessionId, stderrLines);
635
+ case "mastra-jsonl": {
636
+ if (!mastraState) {
637
+ return mapClaudeEvent(evt, sessionId, stderrLines);
638
+ }
639
+ return mapMastraEvent(evt, sessionId, stderrLines, mastraState);
640
+ }
641
+ default:
642
+ return mapClaudeEvent(evt, sessionId, stderrLines);
643
+ }
644
+ }
645
+ function mapClaudeEvent(evt, sessionId, stderrLines) {
488
646
  switch (evt.type) {
489
647
  case "text":
490
648
  return typeof evt.text === "string" ? { kind: "text-delta", sessionId, text: evt.text } : null;
@@ -528,6 +686,127 @@ function mapEvent(evt, sessionId, stderrLines) {
528
686
  return null;
529
687
  }
530
688
  }
689
+ function createMastraMapperState() {
690
+ return { lastTextLength: 0 };
691
+ }
692
+ function extractTextFromBlocks(content) {
693
+ if (!Array.isArray(content)) return "";
694
+ return content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
695
+ }
696
+ function mapMastraEvent(evt, sessionId, stderrLines, state) {
697
+ switch (evt.type) {
698
+ // ── Text streaming ──────────────────────────────────────────
699
+ case "message_update": {
700
+ const content = evt.message?.content;
701
+ const fullText = extractTextFromBlocks(content);
702
+ if (fullText.length > state.lastTextLength) {
703
+ const delta = fullText.slice(state.lastTextLength);
704
+ state.lastTextLength = fullText.length;
705
+ return delta ? { kind: "text-delta", sessionId, text: delta } : null;
706
+ }
707
+ return null;
708
+ }
709
+ case "message_end": {
710
+ const msg = evt.message;
711
+ if (msg?.role !== "assistant") return null;
712
+ const fullText = extractTextFromBlocks(msg?.content);
713
+ if (fullText.length > state.lastTextLength) {
714
+ const delta = fullText.slice(state.lastTextLength);
715
+ state.lastTextLength = fullText.length;
716
+ return delta ? { kind: "text-delta", sessionId, text: delta } : null;
717
+ }
718
+ return null;
719
+ }
720
+ // ── Tool calls ──────────────────────────────────────────────
721
+ case "tool_start":
722
+ return {
723
+ kind: "tool-call",
724
+ sessionId,
725
+ toolCallId: typeof evt.toolCallId === "string" ? evt.toolCallId : "",
726
+ toolName: typeof evt.toolName === "string" ? evt.toolName : "?",
727
+ // Mastra's controller event carries the tool call payload under
728
+ // `args`, not `input` (that's the Claude Code stream-json field
729
+ // name used by the sibling mapClaudeEvent tool_use case below).
730
+ arguments: evt.args ?? {}
731
+ };
732
+ case "tool_end":
733
+ return {
734
+ kind: "tool-result",
735
+ sessionId,
736
+ toolCallId: typeof evt.toolCallId === "string" ? evt.toolCallId : "",
737
+ result: evt.result ?? null,
738
+ isError: evt.isError === true
739
+ };
740
+ // ── Turn end ────────────────────────────────────────────────
741
+ case "agent_end": {
742
+ const rawReason = typeof evt.reason === "string" ? evt.reason : "complete";
743
+ const reason = mapMastraFinishReason(rawReason);
744
+ return { kind: "turn-end", sessionId, reason };
745
+ }
746
+ // ── Final result line ────────────────────────────────────────
747
+ // Always written last, once, whether or not `agent_end` fired —
748
+ // pre-flight failures (bad model, unresolvable thread, missing API
749
+ // key) call straight into this without ever streaming an
750
+ // `agent_end` or `error` event. `turn-end` already came from
751
+ // `agent_end` on the success path, so this only needs to surface
752
+ // an error for the pre-flight-failure path.
753
+ case "result": {
754
+ const err = evt.error;
755
+ if (!err) return null;
756
+ return {
757
+ kind: "error",
758
+ sessionId,
759
+ error: {
760
+ message: typeof err.message === "string" ? err.message : "Unknown error",
761
+ ...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
762
+ }
763
+ };
764
+ }
765
+ // ── Errors ─────────────────────────────────────────────────
766
+ case "error": {
767
+ const err = evt.error;
768
+ return {
769
+ kind: "error",
770
+ sessionId,
771
+ error: {
772
+ message: typeof err?.message === "string" ? err.message : "Unknown error",
773
+ ...stderrLines.length ? { data: { stderr: stderrLines.join("\n") } } : {}
774
+ }
775
+ };
776
+ }
777
+ // ── Shell output (tool-like) ────────────────────────────────
778
+ case "shell_output":
779
+ return typeof evt.output === "string" ? {
780
+ kind: "tool-result",
781
+ sessionId,
782
+ toolCallId: "",
783
+ result: evt.output,
784
+ isError: false
785
+ } : null;
786
+ // ── Skipped events ─────────────────────────────────────────
787
+ case "agent_start":
788
+ case "subagent_start":
789
+ case "subagent_end":
790
+ case "tool_approval_required":
791
+ case "tool_suspended":
792
+ return null;
793
+ default:
794
+ return null;
795
+ }
796
+ }
797
+ function mapMastraFinishReason(raw) {
798
+ switch (raw) {
799
+ case "complete":
800
+ return "completed";
801
+ case "aborted":
802
+ case "suspended":
803
+ return "cancelled";
804
+ case "error":
805
+ return "error";
806
+ default:
807
+ return "completed";
808
+ }
809
+ }
531
810
  function waitForExit(child) {
532
811
  return new Promise((resolve) => {
533
812
  child.once("exit", (code) => resolve(code));
@@ -535,6 +814,27 @@ function waitForExit(child) {
535
814
  });
536
815
  }
537
816
 
817
+ // src/protocol/proprietary.ts
818
+ async function createProprietaryProtocolArm(options) {
819
+ let mod;
820
+ try {
821
+ mod = await import(options.adapter);
822
+ } catch (err) {
823
+ const cause = err instanceof Error ? err.message : String(err);
824
+ throw new Error(
825
+ `createProprietaryProtocolArm: could not load adapter package '${options.adapter}'. Install it with: npm i ${options.adapter}
826
+ cause: ${cause}`
827
+ );
828
+ }
829
+ const candidate = "createAgentCliClient" in mod ? mod.createAgentCliClient : mod.default;
830
+ if (typeof candidate !== "function") {
831
+ throw new Error(
832
+ `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>.`
833
+ );
834
+ }
835
+ return await candidate(options.definition);
836
+ }
837
+
538
838
  // src/manifest/compose.ts
539
839
  var RuntimeConfigError = class extends Error {
540
840
  code;
@@ -735,32 +1035,51 @@ function createAgentCliRuntime(definition) {
735
1035
  ...composed.env,
736
1036
  ...opts?.env ?? {}
737
1037
  };
1038
+ const permissionMode = resolveClaudeCodePermissionMode(
1039
+ definition,
1040
+ opts?.config?.mode
1041
+ );
1042
+ if (permissionMode) {
1043
+ const configDir = mkdtempSync(
1044
+ join(tmpdir(), "agentproto-claude-config-")
1045
+ );
1046
+ writeFileSync(
1047
+ join(configDir, "settings.json"),
1048
+ JSON.stringify({ permissions: { defaultMode: permissionMode } })
1049
+ );
1050
+ env.CLAUDE_CONFIG_DIR = configDir;
1051
+ }
738
1052
  if (definition.protocol === "print") {
739
1053
  return createPrintSession({
740
1054
  bin: definition.bin,
741
1055
  baseArgs: composed.binArgs,
742
1056
  cwd,
743
1057
  env,
744
- ...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}
1058
+ ...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {},
1059
+ ...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
1060
+ printConfig: definition.print
745
1061
  });
746
1062
  }
747
- const child = spawn(definition.bin, composed.binArgs, {
748
- cwd,
749
- env,
750
- stdio: ["pipe", "pipe", "pipe"],
751
- signal: opts?.signal
752
- });
1063
+ let child;
753
1064
  const stderrBuf = [];
754
- const STDERR_KEEP_LINES = 80;
755
- child.stderr?.setEncoding("utf8");
756
- child.stderr?.on("data", (chunk) => {
757
- for (const line of chunk.split(/\r?\n/)) {
758
- if (!line) continue;
759
- stderrBuf.push(line);
760
- if (stderrBuf.length > STDERR_KEEP_LINES) stderrBuf.shift();
761
- }
762
- });
763
- const arm = buildProtocolArm(definition, child, cwd);
1065
+ if (definition.protocol !== "proprietary") {
1066
+ child = spawn(definition.bin, composed.binArgs, {
1067
+ cwd,
1068
+ env,
1069
+ stdio: ["pipe", "pipe", "pipe"],
1070
+ signal: opts?.signal
1071
+ });
1072
+ const STDERR_KEEP_LINES = 80;
1073
+ child.stderr?.setEncoding("utf8");
1074
+ child.stderr?.on("data", (chunk) => {
1075
+ for (const line of chunk.split(/\r?\n/)) {
1076
+ if (!line) continue;
1077
+ stderrBuf.push(line);
1078
+ if (stderrBuf.length > STDERR_KEEP_LINES) stderrBuf.shift();
1079
+ }
1080
+ });
1081
+ }
1082
+ const arm = await buildProtocolArm(definition, child, cwd, opts?.config?.mode);
764
1083
  arm._stderrTail = () => stderrBuf.join("\n");
765
1084
  const abortController = new AbortController();
766
1085
  if (opts?.signal) {
@@ -772,6 +1091,7 @@ function createAgentCliRuntime(definition) {
772
1091
  const optEffort = opts?.config?.options?.effort;
773
1092
  const modelApply = definition.models?.apply ?? "config";
774
1093
  const configModel = optModel && modelApply === "config" ? String(optModel) : void 0;
1094
+ const turnIdleTimeoutMs = opts?.turnIdleTimeoutMs ?? definition.session?.turn_idle_timeout_ms;
775
1095
  await arm.connect({
776
1096
  cwd,
777
1097
  env,
@@ -779,7 +1099,9 @@ function createAgentCliRuntime(definition) {
779
1099
  ...opts?.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {},
780
1100
  ...opts?.mcpServers ? { mcpServers: opts.mcpServers } : {},
781
1101
  ...configModel ? { model: configModel } : {},
782
- ...optEffort ? { effort: String(optEffort) } : {}
1102
+ ...optEffort ? { effort: String(optEffort) } : {},
1103
+ ...opts?.onActivity ? { onActivity: opts.onActivity } : {},
1104
+ ...turnIdleTimeoutMs !== void 0 ? { turnIdleTimeoutMs } : {}
783
1105
  });
784
1106
  if (optModel && modelApply === "command") {
785
1107
  await applyModelCommand(arm, String(optModel));
@@ -787,6 +1109,7 @@ function createAgentCliRuntime(definition) {
787
1109
  const sessionId = arm.sessionId ?? randomUUID();
788
1110
  return {
789
1111
  sessionId,
1112
+ pid: child?.pid,
790
1113
  send(message) {
791
1114
  const turnId = randomUUID();
792
1115
  return promptTurn(arm, turnId, message);
@@ -796,7 +1119,7 @@ function createAgentCliRuntime(definition) {
796
1119
  },
797
1120
  async close() {
798
1121
  await arm.close();
799
- if (!child.killed) child.kill("SIGTERM");
1122
+ if (child && !child.killed) child.kill("SIGTERM");
800
1123
  }
801
1124
  };
802
1125
  }
@@ -839,24 +1162,39 @@ async function* promptTurn(arm, turnId, message) {
839
1162
  yield evt;
840
1163
  }
841
1164
  }
842
- function buildProtocolArm(def, child, cwd) {
1165
+ async function buildProtocolArm(def, child, cwd, requestedMode) {
843
1166
  switch (def.protocol) {
844
1167
  case "acp":
1168
+ if (!child) {
1169
+ throw new Error("createAgentCliRuntime: acp protocol requires a spawned subprocess");
1170
+ }
845
1171
  return createAcpProtocolArm({
846
1172
  child,
847
1173
  cwd,
848
- clientInfo: { name: def.id, version: def.version }
1174
+ clientInfo: { name: def.id, version: def.version },
1175
+ requestedMode
849
1176
  });
850
1177
  case "mcp":
851
1178
  throw new Error("createAgentCliRuntime: mcp protocol arm not yet implemented");
852
1179
  case "proprietary":
853
- throw new Error(
854
- "createAgentCliRuntime: proprietary protocol arm not yet implemented"
855
- );
1180
+ if (!def.adapter) {
1181
+ throw new Error(
1182
+ "createAgentCliRuntime: proprietary protocol requires manifest.adapter"
1183
+ );
1184
+ }
1185
+ return createProprietaryProtocolArm({ adapter: def.adapter, definition: def });
856
1186
  case "print":
857
1187
  throw new Error("createAgentCliRuntime: print arm bypasses buildProtocolArm");
858
1188
  }
859
1189
  }
1190
+ function resolveClaudeCodePermissionMode(definition, configMode) {
1191
+ if (definition.id !== "claude-code" || !configMode) return void 0;
1192
+ const mode = (definition.modes ?? []).find((m) => m.id === configMode);
1193
+ const args = mode?.bin_args_append ?? [];
1194
+ const flagIndex = args.indexOf("--permission-mode");
1195
+ if (flagIndex === -1 || flagIndex + 1 >= args.length) return void 0;
1196
+ return args[flagIndex + 1];
1197
+ }
860
1198
  function filterStringEnv(env) {
861
1199
  const out = {};
862
1200
  for (const [k, v] of Object.entries(env)) {
@@ -865,6 +1203,6 @@ function filterStringEnv(env) {
865
1203
  return out;
866
1204
  }
867
1205
 
868
- export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createPrintSession, defineAgentCli, resolveContinuationStrategy, runtimeConfigSchema };
869
- //# sourceMappingURL=chunk-YQHVLX6O.mjs.map
870
- //# sourceMappingURL=chunk-YQHVLX6O.mjs.map
1206
+ export { RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers };
1207
+ //# sourceMappingURL=chunk-KHHRPQ2Q.mjs.map
1208
+ //# sourceMappingURL=chunk-KHHRPQ2Q.mjs.map