acpx 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agent-registry-DU6mhZBL.js +785 -0
  2. package/dist/agent-registry-DU6mhZBL.js.map +1 -0
  3. package/dist/agent-registry.d.ts +70 -0
  4. package/dist/agent-registry.d.ts.map +1 -0
  5. package/dist/agent-registry.js +2 -0
  6. package/dist/{cli-Cen2Rb6S.js → cli-BkYIxj_N.js} +6 -14
  7. package/dist/cli-BkYIxj_N.js.map +1 -0
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +137 -333
  11. package/dist/cli.js.map +1 -1
  12. package/dist/{client-Cvz6msGc.d.ts → client-5levcBIs.d.ts} +11 -9
  13. package/dist/client-5levcBIs.d.ts.map +1 -0
  14. package/dist/{flows-D-F3Y2o9.js → flows-Bxs4udrs.js} +205 -277
  15. package/dist/flows-Bxs4udrs.js.map +1 -0
  16. package/dist/flows.d.ts +6 -17
  17. package/dist/flows.d.ts.map +1 -1
  18. package/dist/flows.js +1 -1
  19. package/dist/{flags-CRh8BJre.js → invocation-options-BY4lxkn3.js} +82 -58
  20. package/dist/invocation-options-BY4lxkn3.js.map +1 -0
  21. package/dist/{live-checkpoint-CYRs-D9t.js → live-checkpoint-BEfxBKCh.js} +1033 -1437
  22. package/dist/live-checkpoint-BEfxBKCh.js.map +1 -0
  23. package/dist/{output-CIVecnHU.js → output-uo5a27KB.js} +487 -490
  24. package/dist/output-uo5a27KB.js.map +1 -0
  25. package/dist/runtime.d.ts +105 -22
  26. package/dist/runtime.d.ts.map +1 -1
  27. package/dist/runtime.js +582 -366
  28. package/dist/runtime.js.map +1 -1
  29. package/dist/{session-options-DyIGRNfu.d.ts → session-options-t3d-F4dn.d.ts} +8 -6
  30. package/dist/session-options-t3d-F4dn.d.ts.map +1 -0
  31. package/package.json +27 -25
  32. package/skills/acpx/SKILL.md +19 -17
  33. package/dist/cli-Cen2Rb6S.js.map +0 -1
  34. package/dist/client-Cvz6msGc.d.ts.map +0 -1
  35. package/dist/flags-CRh8BJre.js.map +0 -1
  36. package/dist/flows-D-F3Y2o9.js.map +0 -1
  37. package/dist/live-checkpoint-CYRs-D9t.js.map +0 -1
  38. package/dist/output-CIVecnHU.js.map +0 -1
  39. package/dist/session-options-DyIGRNfu.d.ts.map +0 -1
@@ -1,13 +1,19 @@
1
+ import { A as resolveAgentCommandParts, C as asAbsoluteCwd, E as isoNow$2, F as waitForSpawn, M as runTimedExecFile, N as splitCommandLine, P as waitForChildExit, S as PROCESS_HELPER_TIMEOUT_MS, T as isChildProcessRunning, _ as buildSpawnCommandOptions, b as readWindowsEnvValue, f as resolveBuiltInAgentLaunch, g as buildAgentSpawnCommand, j as resolveAgentSessionCwd, k as requireAgentStdio, n as AGENT_REGISTRY, r as BUILT_IN_AGENT_PACKAGES, t as AGENT_ARGV_REGISTRY, v as buildTerminalShellSpawnCommand, w as basenameToken, x as resolveWindowsExecutablePath, y as buildTerminalSpawnCommand } from "./agent-registry-DU6mhZBL.js";
1
2
  import fs, { readFileSync, statSync } from "node:fs";
2
- import { fileURLToPath } from "node:url";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
4
  import path from "node:path";
5
+ import { spawn } from "node:child_process";
4
6
  import fs$1 from "node:fs/promises";
5
7
  import os from "node:os";
8
+ import { tempFile } from "@openclaw/fs-safe/advanced";
6
9
  import { randomUUID } from "node:crypto";
7
- import { execFile, spawn } from "node:child_process";
8
10
  import { Readable, Writable } from "node:stream";
9
- import { PROTOCOL_VERSION, client, methods } from "@agentclientprotocol/sdk";
11
+ import { PROTOCOL_VERSION, RequestError, client, methods } from "@agentclientprotocol/sdk";
12
+ import { FsSafeError } from "@openclaw/fs-safe/errors";
13
+ import { isPathInside } from "@openclaw/fs-safe/path";
14
+ import { root } from "@openclaw/fs-safe/root";
10
15
  import readline from "node:readline/promises";
16
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
11
17
  //#region src/errors.ts
12
18
  var AcpxOperationalError = class extends Error {
13
19
  outputCode;
@@ -412,15 +418,11 @@ function isRetryablePromptError(error) {
412
418
  if (isNonRetryablePromptError(error)) return false;
413
419
  const acp = extractAcpError(error);
414
420
  if (!acp) return false;
415
- if (isPermanentPromptAcpError(acp)) return false;
416
421
  return acp.code === -32603 || acp.code === -32700;
417
422
  }
418
423
  function isNonRetryablePromptError(error) {
419
424
  return error instanceof PermissionDeniedError || error instanceof PermissionPromptUnavailableError || isTimeoutLike(error) || isNoSessionLike(error) || isUsageLike(error);
420
425
  }
421
- function isPermanentPromptAcpError(acp) {
422
- return acp.code === -32001 || acp.code === -32002 || acp.code === -32601 || acp.code === -32602 || isAcpAuthRequiredPayload(acp);
423
- }
424
426
  function exitCodeForOutputErrorCode(code) {
425
427
  switch (code) {
426
428
  case "USAGE": return EXIT_CODES.USAGE;
@@ -432,254 +434,6 @@ function exitCodeForOutputErrorCode(code) {
432
434
  }
433
435
  }
434
436
  //#endregion
435
- //#region src/agent-registry.ts
436
- const ACP_ADAPTER_PACKAGE_RANGES = {
437
- pi: "^0.0.31",
438
- codex: "^1.1.5",
439
- claude: "^0.60.0",
440
- mux: "^0.28.0"
441
- };
442
- const AGENT_REGISTRY = {
443
- pi: `npx pi-acp@${ACP_ADAPTER_PACKAGE_RANGES.pi}`,
444
- openclaw: "openclaw acp",
445
- codex: `npx -y @agentclientprotocol/codex-acp@${ACP_ADAPTER_PACKAGE_RANGES.codex}`,
446
- claude: `npx -y @agentclientprotocol/claude-agent-acp@${ACP_ADAPTER_PACKAGE_RANGES.claude}`,
447
- gemini: "gemini --acp",
448
- cursor: "cursor-agent acp",
449
- copilot: "copilot --acp --stdio",
450
- droid: "droid exec --output-format acp",
451
- "fast-agent": "uvx fast-agent-mcp acp",
452
- "grok-build": "grok agent stdio",
453
- iflow: "iflow --experimental-acp",
454
- kilocode: "npx -y @kilocode/cli acp",
455
- kimi: "kimi acp",
456
- kiro: "kiro-cli-chat acp",
457
- mcode: "mcode acp",
458
- mux: `npx -y mux@${ACP_ADAPTER_PACKAGE_RANGES.mux} acp`,
459
- opencode: "npx -y opencode-ai acp",
460
- pool: "pool acp",
461
- qoder: "qodercli --acp",
462
- qwen: "qwen --acp",
463
- trae: "traecli acp serve",
464
- zeroclaw: "zeroclaw acp"
465
- };
466
- const AGENT_ARGV_REGISTRY = {
467
- pi: ["npx", `pi-acp@${ACP_ADAPTER_PACKAGE_RANGES.pi}`],
468
- openclaw: ["openclaw", "acp"],
469
- codex: [
470
- "npx",
471
- "-y",
472
- `@agentclientprotocol/codex-acp@${ACP_ADAPTER_PACKAGE_RANGES.codex}`
473
- ],
474
- claude: [
475
- "npx",
476
- "-y",
477
- `@agentclientprotocol/claude-agent-acp@${ACP_ADAPTER_PACKAGE_RANGES.claude}`
478
- ],
479
- gemini: ["gemini", "--acp"],
480
- cursor: ["cursor-agent", "acp"],
481
- copilot: [
482
- "copilot",
483
- "--acp",
484
- "--stdio"
485
- ],
486
- droid: [
487
- "droid",
488
- "exec",
489
- "--output-format",
490
- "acp"
491
- ],
492
- "fast-agent": [
493
- "uvx",
494
- "fast-agent-mcp",
495
- "acp"
496
- ],
497
- "grok-build": [
498
- "grok",
499
- "agent",
500
- "stdio"
501
- ],
502
- iflow: ["iflow", "--experimental-acp"],
503
- kilocode: [
504
- "npx",
505
- "-y",
506
- "@kilocode/cli",
507
- "acp"
508
- ],
509
- kimi: ["kimi", "acp"],
510
- kiro: ["kiro-cli-chat", "acp"],
511
- mcode: ["mcode", "acp"],
512
- mux: [
513
- "npx",
514
- "-y",
515
- `mux@${ACP_ADAPTER_PACKAGE_RANGES.mux}`,
516
- "acp"
517
- ],
518
- opencode: [
519
- "npx",
520
- "-y",
521
- "opencode-ai",
522
- "acp"
523
- ],
524
- pool: ["pool", "acp"],
525
- qoder: ["qodercli", "--acp"],
526
- qwen: ["qwen", "--acp"],
527
- trae: [
528
- "traecli",
529
- "acp",
530
- "serve"
531
- ],
532
- zeroclaw: ["zeroclaw", "acp"]
533
- };
534
- const BUILT_IN_AGENT_PACKAGES = {
535
- codex: {
536
- packageName: "@agentclientprotocol/codex-acp",
537
- packageRange: ACP_ADAPTER_PACKAGE_RANGES.codex,
538
- preferredBinName: "codex-acp",
539
- fallbackCommand: AGENT_REGISTRY.codex,
540
- legacyFallbackCommands: []
541
- },
542
- claude: {
543
- packageName: "@agentclientprotocol/claude-agent-acp",
544
- packageRange: ACP_ADAPTER_PACKAGE_RANGES.claude,
545
- preferredBinName: "claude-agent-acp",
546
- fallbackCommand: AGENT_REGISTRY.claude,
547
- legacyFallbackCommands: [`npm exec @agentclientprotocol/claude-agent-acp@${ACP_ADAPTER_PACKAGE_RANGES.claude}`]
548
- }
549
- };
550
- const AGENT_ALIASES = {
551
- "factory-droid": "droid",
552
- factorydroid: "droid"
553
- };
554
- const DEFAULT_AGENT_NAME = "codex";
555
- function normalizeAgentName$1(value) {
556
- return value.trim().toLowerCase();
557
- }
558
- function resolveCanonicalAgentName(value) {
559
- const normalized = normalizeAgentName$1(value);
560
- return AGENT_ALIASES[normalized] ?? normalized;
561
- }
562
- function mergeAgentRegistry(overrides) {
563
- if (!overrides) return { ...AGENT_REGISTRY };
564
- const merged = { ...AGENT_REGISTRY };
565
- for (const [name, command] of Object.entries(overrides)) {
566
- const normalized = normalizeAgentName$1(name);
567
- if (!normalized || !command.trim()) continue;
568
- merged[normalized] = command.trim();
569
- }
570
- return merged;
571
- }
572
- function resolveAgentCommand(agentName, overrides) {
573
- const normalized = normalizeAgentName$1(agentName);
574
- const registry = mergeAgentRegistry(overrides);
575
- return registry[normalized] ?? registry[AGENT_ALIASES[normalized] ?? normalized] ?? agentName;
576
- }
577
- function resolveAgentArgv(agentName) {
578
- const normalized = normalizeAgentName$1(agentName);
579
- const argv = AGENT_ARGV_REGISTRY[normalized] ?? AGENT_ARGV_REGISTRY[resolveCanonicalAgentName(agentName)];
580
- return argv ? [...argv] : void 0;
581
- }
582
- function findBuiltInAgentPackage(agentCommand) {
583
- const normalized = agentCommand.trim();
584
- return Object.values(BUILT_IN_AGENT_PACKAGES).find((spec) => spec.fallbackCommand === normalized || spec.legacyFallbackCommands?.includes(normalized));
585
- }
586
- function defaultResolvePackageRoot(packageName) {
587
- const segments = packageName.split("/");
588
- let cursor = path.dirname(fileURLToPath(import.meta.url));
589
- while (true) {
590
- const candidateRoot = path.join(cursor, "node_modules", ...segments);
591
- const manifestPath = path.join(candidateRoot, "package.json");
592
- if (fs.existsSync(manifestPath)) try {
593
- if (JSON.parse(fs.readFileSync(manifestPath, "utf8")).name === packageName) return candidateRoot;
594
- } catch {}
595
- const parent = path.dirname(cursor);
596
- if (parent === cursor) throw new Error(`Built-in agent package not found: ${packageName}`);
597
- cursor = parent;
598
- }
599
- }
600
- function resolvePackageBin(spec, manifest) {
601
- if (typeof manifest.bin === "string") return manifest.bin;
602
- if (!manifest.bin || typeof manifest.bin !== "object") return;
603
- return manifest.bin[spec.preferredBinName] ?? (Object.keys(manifest.bin).length === 1 ? Object.values(manifest.bin)[0] : void 0);
604
- }
605
- function defaultResolveNpmCliPath(execPath) {
606
- const candidate = path.resolve(path.dirname(execPath), "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
607
- if (!fs.existsSync(candidate)) throw new Error(`npm CLI not found for execPath: ${execPath}`);
608
- return candidate;
609
- }
610
- function resolveInstalledBuiltInAgentLaunch(agentCommand, options = {}) {
611
- const spec = findBuiltInAgentPackage(agentCommand);
612
- if (!spec) return;
613
- const readFileSync = options.readFileSync ?? fs.readFileSync;
614
- const existsSync = options.existsSync ?? fs.existsSync;
615
- const resolvePackageRoot = options.resolvePackageRoot ?? defaultResolvePackageRoot;
616
- try {
617
- const resolved = resolveInstalledBuiltInAgentPackage(spec, {
618
- readFileSync,
619
- existsSync,
620
- resolvePackageRoot
621
- });
622
- if (!resolved) return;
623
- return {
624
- source: "installed",
625
- command: process.execPath,
626
- args: [resolved.binPath],
627
- packageName: spec.packageName,
628
- packageRange: spec.packageRange,
629
- packageVersion: resolved.packageVersion,
630
- binPath: resolved.binPath
631
- };
632
- } catch {
633
- return;
634
- }
635
- }
636
- function resolveInstalledBuiltInAgentPackage(spec, options) {
637
- const packageRoot = options.resolvePackageRoot(spec.packageName);
638
- const manifest = JSON.parse(options.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
639
- if (manifest.name !== spec.packageName) return;
640
- const relativeBinPath = resolvePackageBin(spec, manifest);
641
- if (!relativeBinPath) return;
642
- const binPath = path.resolve(packageRoot, relativeBinPath);
643
- return options.existsSync(binPath) ? {
644
- packageVersion: manifest.version,
645
- binPath
646
- } : void 0;
647
- }
648
- function resolvePackageExecBuiltInAgentLaunch(agentCommand, options = {}) {
649
- const spec = findBuiltInAgentPackage(agentCommand);
650
- if (!spec) return;
651
- const existsSync = options.existsSync ?? fs.existsSync;
652
- const execPath = options.execPath ?? process.execPath;
653
- const resolveNpmCliPath = options.resolveNpmCliPath ?? defaultResolveNpmCliPath;
654
- try {
655
- const npmCliPath = resolveNpmCliPath(execPath);
656
- if (!existsSync(npmCliPath)) return;
657
- return {
658
- source: "package-exec",
659
- command: execPath,
660
- args: [
661
- npmCliPath,
662
- "exec",
663
- "--yes",
664
- `--package=${spec.packageName}@${spec.packageRange}`,
665
- "--",
666
- spec.preferredBinName
667
- ],
668
- packageName: spec.packageName,
669
- packageRange: spec.packageRange,
670
- npmCliPath
671
- };
672
- } catch {
673
- return;
674
- }
675
- }
676
- function resolveBuiltInAgentLaunch(agentCommand, options = {}) {
677
- return resolveInstalledBuiltInAgentLaunch(agentCommand, options) ?? resolvePackageExecBuiltInAgentLaunch(agentCommand, options);
678
- }
679
- function listBuiltInAgents(overrides) {
680
- return [.../* @__PURE__ */ new Set([...Object.keys(AGENT_REGISTRY), ...Object.keys(overrides ?? {})])];
681
- }
682
- //#endregion
683
437
  //#region src/async-control.ts
684
438
  var TimeoutError = class extends Error {
685
439
  constructor(timeoutMs) {
@@ -737,195 +491,38 @@ async function withInterrupt(run, onInterrupt) {
737
491
  });
738
492
  }
739
493
  //#endregion
740
- //#region src/prompt-content.ts
741
- var PromptInputValidationError = class extends Error {
742
- constructor(message) {
743
- super(message);
744
- this.name = "PromptInputValidationError";
745
- }
746
- };
747
- function asRecord$6(value) {
748
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
749
- return value;
750
- }
751
- function isNonEmptyString(value) {
752
- return typeof value === "string" && value.trim().length > 0;
753
- }
754
- function isBase64Data(value) {
755
- if (value.length === 0 || value.length % 4 !== 0) return false;
756
- return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
757
- }
758
- function isImageMimeType(value) {
759
- return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
760
- }
761
- function isAudioMimeType(value) {
762
- return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
763
- }
764
- function isTextBlock(value) {
765
- const record = asRecord$6(value);
766
- return record?.type === "text" && typeof record.text === "string";
767
- }
768
- function isImageBlock(value) {
769
- const record = asRecord$6(value);
770
- return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
771
- }
772
- function isAudioBlock(value) {
773
- const record = asRecord$6(value);
774
- return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
775
- }
776
- function isResourceLinkBlock(value) {
777
- const record = asRecord$6(value);
778
- return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title === void 0 || typeof record.title === "string") && (record.name === void 0 || typeof record.name === "string");
779
- }
780
- function isResourcePayload(value) {
781
- const record = asRecord$6(value);
782
- if (!record || !isNonEmptyString(record.uri)) return false;
783
- return record.text === void 0 || typeof record.text === "string";
784
- }
785
- function isResourceBlock(value) {
786
- const record = asRecord$6(value);
787
- return record?.type === "resource" && isResourcePayload(record.resource);
788
- }
789
- const CONTENT_BLOCK_VALIDATORS = [
790
- isTextBlock,
791
- isImageBlock,
792
- isAudioBlock,
793
- isResourceLinkBlock,
794
- isResourceBlock
795
- ];
796
- function isContentBlock(value) {
797
- return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
798
- }
799
- const CONTENT_BLOCK_ERROR_VALIDATORS = {
800
- text: validateTextContentBlock,
801
- image: validateImageContentBlock,
802
- audio: validateAudioContentBlock,
803
- resource_link: validateResourceLinkContentBlock,
804
- resource: validateResourceContentBlock
805
- };
806
- function contentBlockErrorValidator(type) {
807
- return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
808
- }
809
- function validateTextContentBlock(record, index) {
810
- return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
811
- }
812
- function validateImageContentBlock(record, index) {
813
- if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
814
- if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
815
- if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
816
- return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
817
- }
818
- function validateAudioContentBlock(record, index) {
819
- if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
820
- if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
821
- if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
822
- return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
823
- }
824
- function validateResourceLinkContentBlock(record, index) {
825
- if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
826
- if (record.title !== void 0 && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string when present`;
827
- if (record.name !== void 0 && typeof record.name !== "string") return `prompt[${index}] resource_link block name must be a string when present`;
828
- }
829
- function validateResourceContentBlock(record, index) {
830
- if (!asRecord$6(record.resource)) return `prompt[${index}] resource block must include a resource object`;
831
- return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and optional text`;
832
- }
833
- function getContentBlockValidationError(value, index) {
834
- const record = asRecord$6(value);
835
- if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
836
- const validator = contentBlockErrorValidator(record.type);
837
- return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
838
- }
839
- function isPromptInput(value) {
840
- return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
841
- }
842
- function promptCapabilityRequirement(block) {
843
- switch (block.type) {
844
- case "image": return {
845
- blockType: "image",
846
- capability: "image"
847
- };
848
- case "audio": return {
849
- blockType: "audio",
850
- capability: "audio"
851
- };
852
- case "resource": return {
853
- blockType: "resource",
854
- capability: "embeddedContext"
855
- };
856
- default: return;
857
- }
858
- }
859
- function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
860
- for (const [index, block] of prompt.entries()) {
861
- const requirement = promptCapabilityRequirement(block);
862
- if (!requirement) continue;
863
- if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
864
- return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
865
- }
866
- }
867
- function textPrompt(text) {
868
- return [{
869
- type: "text",
870
- text
871
- }];
872
- }
873
- function parseStructuredPrompt(source) {
874
- if (!source.startsWith("[")) return;
875
- try {
876
- const parsed = JSON.parse(source);
877
- if (isPromptInput(parsed)) return parsed;
878
- if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
879
- return;
880
- } catch (error) {
881
- if (error instanceof PromptInputValidationError) throw error;
882
- return;
883
- }
884
- }
885
- function parsePromptSource(source) {
886
- const trimmed = source.trim();
887
- const structured = parseStructuredPrompt(trimmed);
888
- if (structured) return structured;
889
- if (!trimmed) return [];
890
- return textPrompt(trimmed);
891
- }
892
- function mergePromptSourceWithText(source, suffixText) {
893
- const prompt = parsePromptSource(source);
894
- const appended = suffixText.trim();
895
- if (!appended) return prompt;
896
- if (prompt.length === 0) return textPrompt(appended);
897
- return [...prompt, ...textPrompt(appended)];
898
- }
899
- function promptToDisplayText(prompt) {
900
- return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
901
- }
902
- function contentBlockDisplayText(block) {
903
- switch (block.type) {
904
- case "text": return block.text;
905
- case "resource_link": return block.title ?? block.name ?? block.uri;
906
- case "resource": return resourceBlockDisplayText(block);
907
- case "image": return `[image] ${block.mimeType}`;
908
- case "audio": return `[audio] ${block.mimeType}`;
909
- default: return "";
910
- }
911
- }
912
- function resourceBlockDisplayText(block) {
913
- return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
494
+ //#region src/acp/codex-compat.ts
495
+ function isLegacyZedCodexAcpInvocation(agentCommand) {
496
+ return /@zed-industries\/codex-acp\b/u.test(agentCommand);
497
+ }
498
+ function preferCodexPermissionRefusal(request, agentName) {
499
+ if (agentName !== "@agentclientprotocol/codex-acp") return request;
500
+ const preferred = request.options.find((option) => option.kind === "reject_once" && ["decline", "reject_permissions"].includes(option.optionId));
501
+ return preferred ? {
502
+ ...request,
503
+ options: [preferred, ...request.options.filter((option) => option !== preferred)]
504
+ } : request;
505
+ }
506
+ function codexPermissionNotice(request, response, agentName) {
507
+ if (agentName !== "@agentclientprotocol/codex-acp") return;
508
+ if (response.outcome.outcome === "cancelled") return "No matching permission option was available. The request was safely cancelled; Codex may end the current turn.";
509
+ const selectedId = response.outcome.optionId;
510
+ return request.options.find((option) => option.optionId === selectedId)?.kind === "reject_once" && selectedId === "cancel" ? "Permission refused using Codex's cancellation option; this can end the current turn. The operation was not approved." : void 0;
914
511
  }
915
512
  //#endregion
916
513
  //#region src/acp/jsonrpc.ts
917
- function asRecord$5(value) {
514
+ function asRecord$6(value) {
918
515
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
919
516
  return value;
920
517
  }
921
518
  function isAcpMessageObject(value) {
922
- return asRecord$5(value) !== null;
519
+ return asRecord$6(value) !== null;
923
520
  }
924
521
  function hasValidId(value) {
925
522
  return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
926
523
  }
927
524
  function isErrorObject(value) {
928
- const record = asRecord$5(value);
525
+ const record = asRecord$6(value);
929
526
  return !!record && typeof record.code === "number" && Number.isFinite(record.code) && typeof record.message === "string";
930
527
  }
931
528
  function hasResultOrError(value) {
@@ -950,7 +547,7 @@ function isJsonRpcResponse(value) {
950
547
  return hasResultOrError(value);
951
548
  }
952
549
  function isAcpJsonRpcMessage(value) {
953
- const record = asRecord$5(value);
550
+ const record = asRecord$6(value);
954
551
  if (!record || record.jsonrpc !== "2.0") return false;
955
552
  return isJsonRpcNotificationRecord(record) || isJsonRpcRequest(record) || isJsonRpcResponse(record);
956
553
  }
@@ -962,11 +559,11 @@ function isSessionUpdateNotification(message) {
962
559
  }
963
560
  function extractSessionUpdateNotification(message) {
964
561
  if (!isSessionUpdateNotification(message)) return;
965
- const params = asRecord$5(message.params);
562
+ const params = asRecord$6(message.params);
966
563
  if (!params) return;
967
564
  const sessionId = typeof params.sessionId === "string" ? params.sessionId : null;
968
565
  if (!sessionId) return;
969
- const update = asRecord$5(params.update);
566
+ const update = asRecord$6(params.update);
970
567
  if (!update || typeof update.sessionUpdate !== "string") return;
971
568
  return {
972
569
  sessionId,
@@ -975,33 +572,139 @@ function extractSessionUpdateNotification(message) {
975
572
  }
976
573
  function parsePromptStopReason(message) {
977
574
  if (!Object.hasOwn(message, "id") || !Object.hasOwn(message, "result")) return;
978
- const record = asRecord$5(message.result);
575
+ const record = asRecord$6(message.result);
979
576
  if (!record) return;
980
577
  return typeof record.stopReason === "string" ? record.stopReason : void 0;
981
578
  }
579
+ function parsePermissionNotice(message) {
580
+ if (!Object.hasOwn(message, "id") || !Object.hasOwn(message, "result")) return;
581
+ const notice = asRecord$6(asRecord$6(asRecord$6(message.result)?._meta)?.acpx)?.permissionNotice;
582
+ return typeof notice === "string" ? notice : void 0;
583
+ }
982
584
  function parseJsonRpcErrorMessage(message) {
983
585
  if (!Object.hasOwn(message, "error")) return;
984
- const errorRecord = asRecord$5(message.error);
586
+ const errorRecord = asRecord$6(message.error);
985
587
  if (!errorRecord || typeof errorRecord.message !== "string") return;
986
588
  return errorRecord.message;
987
589
  }
988
590
  //#endregion
591
+ //#region src/process-liveness.ts
592
+ function isProcessAlive(pid) {
593
+ if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
594
+ try {
595
+ process.kill(pid, 0);
596
+ return true;
597
+ } catch {
598
+ return false;
599
+ }
600
+ }
601
+ //#endregion
602
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/usingCtx.js
603
+ function _usingCtx() {
604
+ var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
605
+ var n = Error();
606
+ return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
607
+ }, e = {}, n = [];
608
+ function using(r, e) {
609
+ if (null != e) {
610
+ if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
611
+ if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
612
+ if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
613
+ if ("function" != typeof o) throw new TypeError("Object is not disposable.");
614
+ t && (o = function o() {
615
+ try {
616
+ t.call(e);
617
+ } catch (r) {
618
+ return Promise.reject(r);
619
+ }
620
+ }), n.push({
621
+ v: e,
622
+ d: o,
623
+ a: r
624
+ });
625
+ } else r && n.push({
626
+ d: e,
627
+ a: r
628
+ });
629
+ return e;
630
+ }
631
+ return {
632
+ e,
633
+ u: using.bind(null, !1),
634
+ a: using.bind(null, !0),
635
+ d: function d() {
636
+ var o, t = this.e, s = 0;
637
+ function next() {
638
+ for (; o = n.pop();) try {
639
+ if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
640
+ if (o.d) {
641
+ var r = o.d.call(o.v);
642
+ if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
643
+ } else s |= 1;
644
+ } catch (r) {
645
+ return err(r);
646
+ }
647
+ if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
648
+ if (t !== e) throw t;
649
+ }
650
+ function err(n) {
651
+ return t = t !== e ? new r(n, t) : n, next();
652
+ }
653
+ return next();
654
+ }
655
+ };
656
+ }
657
+ //#endregion
658
+ //#region src/state-files.ts
659
+ async function writePrivateFile(filePath, content, options = {}) {
660
+ try {
661
+ var _usingCtx$1 = _usingCtx();
662
+ const privateDirectory = options.privateDirectory !== false;
663
+ await fs$1.mkdir(path.dirname(filePath), {
664
+ recursive: true,
665
+ mode: privateDirectory ? 448 : void 0
666
+ });
667
+ const directory = await fs$1.realpath(path.dirname(filePath));
668
+ if (privateDirectory && process.platform !== "win32") await fs$1.chmod(directory, 448);
669
+ const temporary = _usingCtx$1.a(await tempFile({
670
+ rootDir: directory,
671
+ prefix: "acpx-write",
672
+ fileName: "record.json"
673
+ }));
674
+ const handle = await fs$1.open(temporary.path, "wx", 384);
675
+ try {
676
+ await handle.writeFile(content, "utf8");
677
+ await handle.chmod(384);
678
+ } finally {
679
+ await handle.close();
680
+ }
681
+ await fs$1.rename(temporary.path, path.join(directory, path.basename(filePath)));
682
+ } catch (_) {
683
+ _usingCtx$1.e = _;
684
+ } finally {
685
+ await _usingCtx$1.d();
686
+ }
687
+ }
688
+ async function writePrivateJsonFile(filePath, value) {
689
+ await writePrivateFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
690
+ }
691
+ //#endregion
989
692
  //#region src/session/event-log.ts
990
693
  const DEFAULT_EVENT_SEGMENT_MAX_BYTES = 67108864;
991
- function sessionBaseDir$1() {
694
+ function sessionBaseDir() {
992
695
  return path.join(os.homedir(), ".acpx", "sessions");
993
696
  }
994
697
  function safeSessionId(sessionId) {
995
698
  return encodeURIComponent(sessionId);
996
699
  }
997
700
  function sessionEventActivePath(sessionId) {
998
- return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.ndjson`);
701
+ return path.join(sessionBaseDir(), `${safeSessionId(sessionId)}.stream.ndjson`);
999
702
  }
1000
703
  function sessionEventSegmentPath(sessionId, segment) {
1001
- return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.${segment}.ndjson`);
704
+ return path.join(sessionBaseDir(), `${safeSessionId(sessionId)}.stream.${segment}.ndjson`);
1002
705
  }
1003
706
  function sessionEventLockPath(sessionId) {
1004
- return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.lock`);
707
+ return path.join(sessionBaseDir(), `${safeSessionId(sessionId)}.stream.lock`);
1005
708
  }
1006
709
  function defaultSessionEventLog(sessionId) {
1007
710
  return {
@@ -1034,57 +737,45 @@ function extractAgentSessionId(meta) {
1034
737
  }
1035
738
  }
1036
739
  //#endregion
1037
- //#region src/session/runtime-session-id.ts
1038
- function normalizeRuntimeSessionId(value) {
1039
- return normalizeAgentSessionId(value);
1040
- }
1041
- function extractRuntimeSessionId(meta) {
1042
- return extractAgentSessionId(meta);
1043
- }
1044
- //#endregion
1045
740
  //#region src/session/persistence/serialize.ts
1046
741
  function serializeSessionRecordForDisk(record) {
1047
- const canonical = {
1048
- ...record,
1049
- schema: SESSION_RECORD_SCHEMA
1050
- };
1051
742
  return {
1052
- schema: canonical.schema,
1053
- acpx_record_id: canonical.acpxRecordId,
1054
- acp_session_id: canonical.acpSessionId,
1055
- agent_session_id: normalizeRuntimeSessionId(canonical.agentSessionId),
1056
- agent_command: canonical.agentCommand,
1057
- agent_argv: canonical.agentArgv,
1058
- cwd: canonical.cwd,
1059
- name: canonical.name,
1060
- created_at: canonical.createdAt,
1061
- last_used_at: canonical.lastUsedAt,
1062
- last_seq: canonical.lastSeq,
1063
- last_request_id: canonical.lastRequestId,
1064
- event_log: canonical.eventLog,
1065
- closed: canonical.closed,
1066
- closed_at: canonical.closedAt,
1067
- pid: canonical.pid,
1068
- agent_started_at: canonical.agentStartedAt,
1069
- last_prompt_at: canonical.lastPromptAt,
1070
- last_agent_exit_code: canonical.lastAgentExitCode,
1071
- last_agent_exit_signal: canonical.lastAgentExitSignal,
1072
- last_agent_exit_at: canonical.lastAgentExitAt,
1073
- last_agent_disconnect_reason: canonical.lastAgentDisconnectReason,
1074
- protocol_version: canonical.protocolVersion,
1075
- agent_capabilities: canonical.agentCapabilities,
1076
- title: canonical.title,
1077
- messages: canonical.messages,
1078
- updated_at: canonical.updated_at,
1079
- cumulative_token_usage: canonical.cumulative_token_usage,
1080
- cumulative_cost: canonical.cumulative_cost,
1081
- request_token_usage: canonical.request_token_usage,
1082
- acpx: canonical.acpx,
1083
- imported_from: canonical.importedFrom ? {
1084
- record_id: canonical.importedFrom.recordId,
1085
- cwd_original: canonical.importedFrom.cwdOriginal,
1086
- exported_by: canonical.importedFrom.exportedBy,
1087
- exported_at: canonical.importedFrom.exportedAt
743
+ schema: SESSION_RECORD_SCHEMA,
744
+ acpx_record_id: record.acpxRecordId,
745
+ acp_session_id: record.acpSessionId,
746
+ agent_session_id: normalizeAgentSessionId(record.agentSessionId),
747
+ agent_command: record.agentCommand,
748
+ agent_argv: record.agentArgv,
749
+ cwd: record.cwd,
750
+ name: record.name,
751
+ created_at: record.createdAt,
752
+ last_used_at: record.lastUsedAt,
753
+ last_seq: record.lastSeq,
754
+ last_request_id: record.lastRequestId,
755
+ event_log: record.eventLog,
756
+ closed: record.closed,
757
+ closed_at: record.closedAt,
758
+ pid: record.pid,
759
+ agent_started_at: record.agentStartedAt,
760
+ last_prompt_at: record.lastPromptAt,
761
+ last_agent_exit_code: record.lastAgentExitCode,
762
+ last_agent_exit_signal: record.lastAgentExitSignal,
763
+ last_agent_exit_at: record.lastAgentExitAt,
764
+ last_agent_disconnect_reason: record.lastAgentDisconnectReason,
765
+ protocol_version: record.protocolVersion,
766
+ agent_capabilities: record.agentCapabilities,
767
+ title: record.title,
768
+ messages: record.messages,
769
+ updated_at: record.updated_at,
770
+ cumulative_token_usage: record.cumulative_token_usage,
771
+ cumulative_cost: record.cumulative_cost,
772
+ request_token_usage: record.request_token_usage,
773
+ acpx: record.acpx,
774
+ imported_from: record.importedFrom ? {
775
+ record_id: record.importedFrom.recordId,
776
+ cwd_original: record.importedFrom.cwdOriginal,
777
+ exported_by: record.importedFrom.exportedBy,
778
+ exported_at: record.importedFrom.exportedAt
1088
779
  } : void 0
1089
780
  };
1090
781
  }
@@ -1134,7 +825,7 @@ function resolveAgentArgvForCommand(agentCommand) {
1134
825
  }
1135
826
  //#endregion
1136
827
  //#region src/session/persistence/parse.ts
1137
- function asRecord$4(value) {
828
+ function asRecord$5(value) {
1138
829
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
1139
830
  return value;
1140
831
  }
@@ -1153,12 +844,12 @@ function parsePersistedAgentArgv(record) {
1153
844
  function hasModelConfigOption(options) {
1154
845
  if (!Array.isArray(options)) return false;
1155
846
  return options.some((entry) => {
1156
- const option = asRecord$4(entry);
847
+ const option = asRecord$5(entry);
1157
848
  return option?.category === "model" || option?.id === "model";
1158
849
  });
1159
850
  }
1160
851
  function parseConfigOptions(raw) {
1161
- if (!Array.isArray(raw) || !raw.every((entry) => asRecord$4(entry) !== void 0)) return;
852
+ if (!Array.isArray(raw) || !raw.every((entry) => asRecord$5(entry) !== void 0)) return;
1162
853
  return raw;
1163
854
  }
1164
855
  function parseAvailableCommand(raw) {
@@ -1166,7 +857,7 @@ function parseAvailableCommand(raw) {
1166
857
  const name = raw.trim();
1167
858
  return name ? { name } : void 0;
1168
859
  }
1169
- const record = asRecord$4(raw);
860
+ const record = asRecord$5(raw);
1170
861
  if (!record) return;
1171
862
  const name = parseNonEmptyString(record.name);
1172
863
  if (!name) return;
@@ -1189,7 +880,7 @@ function parseNonEmptyString(value) {
1189
880
  }
1190
881
  function parseTokenUsage(raw) {
1191
882
  if (raw === void 0 || raw === null) return;
1192
- const record = asRecord$4(raw);
883
+ const record = asRecord$5(raw);
1193
884
  if (!record) return null;
1194
885
  const usage = {};
1195
886
  for (const field of [
@@ -1212,7 +903,7 @@ function isNonNegativeFiniteNumber(value) {
1212
903
  }
1213
904
  function parseUsageCost(raw) {
1214
905
  if (raw === void 0 || raw === null) return;
1215
- const record = asRecord$4(raw);
906
+ const record = asRecord$5(raw);
1216
907
  if (!record) return null;
1217
908
  return parseUsageCostRecord(record);
1218
909
  }
@@ -1238,7 +929,7 @@ function parseCostCurrency(value) {
1238
929
  }
1239
930
  function parseRequestTokenUsage(raw) {
1240
931
  if (raw === void 0 || raw === null) return;
1241
- const record = asRecord$4(raw);
932
+ const record = asRecord$5(raw);
1242
933
  if (!record) return null;
1243
934
  const usage = {};
1244
935
  for (const [key, value] of Object.entries(record)) {
@@ -1249,25 +940,25 @@ function parseRequestTokenUsage(raw) {
1249
940
  return usage;
1250
941
  }
1251
942
  function isSessionMessageImage(raw) {
1252
- const record = asRecord$4(raw);
943
+ const record = asRecord$5(raw);
1253
944
  if (!record || typeof record.source !== "string") return false;
1254
945
  if (record.size === void 0 || record.size === null) return true;
1255
- const size = asRecord$4(record.size);
946
+ const size = asRecord$5(record.size);
1256
947
  return !!size && isFiniteNumber(size.width) && isFiniteNumber(size.height);
1257
948
  }
1258
949
  function isSessionMessageAudio(raw) {
1259
- const record = asRecord$4(raw);
950
+ const record = asRecord$5(raw);
1260
951
  return !!record && typeof record.source === "string" && typeof record.mime_type === "string";
1261
952
  }
1262
953
  function isFiniteNumber(value) {
1263
954
  return typeof value === "number" && Number.isFinite(value);
1264
955
  }
1265
956
  function isUserContent(raw) {
1266
- const record = asRecord$4(raw);
957
+ const record = asRecord$5(raw);
1267
958
  if (!record) return false;
1268
959
  if (typeof record.Text === "string") return true;
1269
960
  if (record.Mention !== void 0) {
1270
- const mention = asRecord$4(record.Mention);
961
+ const mention = asRecord$5(record.Mention);
1271
962
  return !!mention && typeof mention.uri === "string" && typeof mention.content === "string";
1272
963
  }
1273
964
  if (record.Image !== void 0) return isSessionMessageImage(record.Image);
@@ -1275,7 +966,7 @@ function isUserContent(raw) {
1275
966
  return false;
1276
967
  }
1277
968
  function isToolUse(raw) {
1278
- const record = asRecord$4(raw);
969
+ const record = asRecord$5(raw);
1279
970
  return !!record && hasStringFields(record, [
1280
971
  "id",
1281
972
  "name",
@@ -1289,18 +980,18 @@ function isOptionalString(value) {
1289
980
  return value === void 0 || value === null || typeof value === "string";
1290
981
  }
1291
982
  function isToolResultContent(raw) {
1292
- const record = asRecord$4(raw);
983
+ const record = asRecord$5(raw);
1293
984
  if (!record) return false;
1294
985
  if (typeof record.Text === "string") return true;
1295
986
  if (record.Image !== void 0) return isSessionMessageImage(record.Image);
1296
987
  return false;
1297
988
  }
1298
989
  function isToolResult(raw) {
1299
- const record = asRecord$4(raw);
990
+ const record = asRecord$5(raw);
1300
991
  return !!record && typeof record.tool_use_id === "string" && typeof record.tool_name === "string" && typeof record.is_error === "boolean" && isToolResultContent(record.content);
1301
992
  }
1302
993
  function isAgentContent(raw) {
1303
- const record = asRecord$4(raw);
994
+ const record = asRecord$5(raw);
1304
995
  if (!record) return false;
1305
996
  if (typeof record.Text === "string") return true;
1306
997
  if (record.Thinking !== void 0) return isThinkingContent(record.Thinking);
@@ -1309,21 +1000,21 @@ function isAgentContent(raw) {
1309
1000
  return false;
1310
1001
  }
1311
1002
  function isThinkingContent(raw) {
1312
- const thinking = asRecord$4(raw);
1003
+ const thinking = asRecord$5(raw);
1313
1004
  return !!thinking && typeof thinking.text === "string" && isOptionalString(thinking.signature);
1314
1005
  }
1315
1006
  function isUserMessage$1(raw) {
1316
- const record = asRecord$4(raw);
1007
+ const record = asRecord$5(raw);
1317
1008
  if (!record || record.User === void 0) return false;
1318
- const user = asRecord$4(record.User);
1009
+ const user = asRecord$5(record.User);
1319
1010
  return !!user && typeof user.id === "string" && Array.isArray(user.content) && user.content.every((entry) => isUserContent(entry));
1320
1011
  }
1321
1012
  function isAgentMessage$1(raw) {
1322
- const record = asRecord$4(raw);
1013
+ const record = asRecord$5(raw);
1323
1014
  if (!record || record.Agent === void 0) return false;
1324
- const agent = asRecord$4(record.Agent);
1015
+ const agent = asRecord$5(record.Agent);
1325
1016
  if (!agent || !Array.isArray(agent.content) || !agent.content.every(isAgentContent)) return false;
1326
- const toolResults = asRecord$4(agent.tool_results);
1017
+ const toolResults = asRecord$5(agent.tool_results);
1327
1018
  if (!toolResults) return false;
1328
1019
  return Object.values(toolResults).every(isToolResult);
1329
1020
  }
@@ -1356,13 +1047,16 @@ function hasValidConversationCore(record) {
1356
1047
  return Array.isArray(record.messages) && record.messages.every(isConversationMessage) && typeof record.updated_at === "string";
1357
1048
  }
1358
1049
  function parseAcpxState(raw) {
1359
- const record = asRecord$4(raw);
1050
+ const record = asRecord$5(raw);
1360
1051
  if (!record) return;
1361
1052
  const state = {};
1362
- assignBooleanTrue(state, "reset_on_next_ensure", record.reset_on_next_ensure);
1053
+ if (record.reset_on_next_ensure === true) state.reset_on_next_ensure = true;
1363
1054
  assignStringState(state, "current_mode_id", record.current_mode_id);
1364
1055
  assignStringState(state, "desired_mode_id", record.desired_mode_id);
1365
- assignDesiredConfigOptions(state, record.desired_config_options);
1056
+ const desiredConfigOptions = parseStringMap(record.desired_config_options);
1057
+ if (desiredConfigOptions) state.desired_config_options = desiredConfigOptions;
1058
+ const modelNames = parseStringMap(record.available_model_names, true);
1059
+ if (modelNames) state.available_model_names = modelNames;
1366
1060
  assignParsedModelState(state, record);
1367
1061
  const availableCommands = parseAvailableCommands(record.available_commands);
1368
1062
  if (availableCommands) state.available_commands = availableCommands;
@@ -1377,60 +1071,37 @@ function assignParsedModelState(state, record) {
1377
1071
  if (configOptions) state.config_options = configOptions;
1378
1072
  if (state.model_control === void 0 && state.available_models !== void 0) state.model_control = hasModelConfigOption(state.config_options) ? "config_option" : "legacy_set_model";
1379
1073
  }
1380
- function assignBooleanTrue(state, key, value) {
1381
- if (value === true) state[key] = true;
1382
- }
1383
1074
  function assignStringState(state, key, value) {
1384
1075
  if (typeof value === "string") state[key] = value;
1385
1076
  }
1386
- function assignDesiredConfigOptions(state, raw) {
1387
- const desiredConfigOptions = asRecord$4(raw);
1388
- if (!desiredConfigOptions) return;
1389
- const parsed = Object.fromEntries(Object.entries(desiredConfigOptions).filter((entry) => {
1390
- const [, value] = entry;
1391
- return typeof value === "string";
1392
- }));
1393
- if (Object.keys(parsed).length > 0) state.desired_config_options = parsed;
1077
+ function parseStringMap(raw, preserveEmpty = false) {
1078
+ const record = asRecord$5(raw);
1079
+ if (!record) return;
1080
+ const parsed = Object.fromEntries(Object.entries(record).filter((entry) => typeof entry[1] === "string"));
1081
+ return Object.keys(parsed).length > 0 || preserveEmpty ? parsed : void 0;
1394
1082
  }
1395
1083
  function assignParsedSessionOptions(state, raw) {
1396
- const sessionOptions = asRecord$4(raw);
1084
+ const sessionOptions = asRecord$5(raw);
1397
1085
  if (!sessionOptions) return;
1398
1086
  const parsedSessionOptions = {};
1399
- assignSessionOptionModel(parsedSessionOptions, sessionOptions.model);
1400
- assignSessionOptionAllowedTools(parsedSessionOptions, sessionOptions.allowed_tools);
1401
- assignSessionOptionMaxTurns(parsedSessionOptions, sessionOptions.max_turns);
1087
+ if (typeof sessionOptions.model === "string") parsedSessionOptions.model = sessionOptions.model;
1088
+ if (isStringArray(sessionOptions.allowed_tools)) parsedSessionOptions.allowed_tools = [...sessionOptions.allowed_tools];
1089
+ if (isPositiveInteger(sessionOptions.max_turns)) parsedSessionOptions.max_turns = sessionOptions.max_turns;
1402
1090
  assignSessionOptionSystemPrompt(parsedSessionOptions, sessionOptions.system_prompt);
1403
- assignSessionOptionEnv(parsedSessionOptions, sessionOptions.env);
1091
+ const env = parseStringMap(sessionOptions.env);
1092
+ if (env) parsedSessionOptions.env = env;
1404
1093
  if (Object.keys(parsedSessionOptions).length > 0) state.session_options = parsedSessionOptions;
1405
1094
  }
1406
- function assignSessionOptionModel(options, value) {
1407
- if (typeof value === "string") options.model = value;
1408
- }
1409
- function assignSessionOptionAllowedTools(options, value) {
1410
- if (isStringArray(value)) options.allowed_tools = [...value];
1411
- }
1412
- function assignSessionOptionMaxTurns(options, value) {
1413
- if (typeof value === "number" && Number.isInteger(value) && value > 0) options.max_turns = value;
1414
- }
1415
1095
  function assignSessionOptionSystemPrompt(options, value) {
1416
1096
  if (typeof value === "string" && value.length > 0) {
1417
1097
  options.system_prompt = value;
1418
1098
  return;
1419
1099
  }
1420
- const appendRecord = asRecord$4(value);
1100
+ const appendRecord = asRecord$5(value);
1421
1101
  if (appendRecord && typeof appendRecord.append === "string" && appendRecord.append.length > 0) options.system_prompt = { append: appendRecord.append };
1422
1102
  }
1423
- function assignSessionOptionEnv(options, value) {
1424
- const env = asRecord$4(value);
1425
- if (!env) return;
1426
- const parsed = Object.fromEntries(Object.entries(env).filter((entry) => {
1427
- const [, raw] = entry;
1428
- return typeof raw === "string";
1429
- }));
1430
- if (Object.keys(parsed).length > 0) options.env = parsed;
1431
- }
1432
1103
  function parseEventLog(raw, sessionId) {
1433
- const record = asRecord$4(raw);
1104
+ const record = asRecord$5(raw);
1434
1105
  if (!record || !hasValidEventLogCore(record)) return defaultSessionEventLog(sessionId);
1435
1106
  return {
1436
1107
  active_path: record.active_path,
@@ -1449,7 +1120,7 @@ function isPositiveInteger(value) {
1449
1120
  }
1450
1121
  function parseImportedFrom(raw) {
1451
1122
  if (raw == null) return;
1452
- const record = asRecord$4(raw);
1123
+ const record = asRecord$5(raw);
1453
1124
  if (!record || typeof record.record_id !== "string" || typeof record.cwd_original !== "string" || typeof record.exported_by !== "string" || typeof record.exported_at !== "string") return null;
1454
1125
  return {
1455
1126
  recordId: record.record_id,
@@ -1476,8 +1147,7 @@ function normalizeOptionalName(value) {
1476
1147
  }
1477
1148
  function normalizeOptionalPid(value) {
1478
1149
  if (value == null) return;
1479
- if (!Number.isInteger(value) || value <= 0) return null;
1480
- return value;
1150
+ return isPositiveInteger(value) ? value : null;
1481
1151
  }
1482
1152
  function normalizeOptionalBoolean(value, fallback = false) {
1483
1153
  if (value == null) return fallback;
@@ -1500,7 +1170,7 @@ function normalizeOptionalSignal(value) {
1500
1170
  return Symbol("invalid");
1501
1171
  }
1502
1172
  function parseSessionRecord(raw) {
1503
- const record = asRecord$4(raw);
1173
+ const record = asRecord$5(raw);
1504
1174
  if (!record) return null;
1505
1175
  if (record.schema !== "acpx.session.v1") return null;
1506
1176
  const optionals = validSessionOptionals({
@@ -1525,7 +1195,7 @@ function parseSessionRecord(raw) {
1525
1195
  schema: SESSION_RECORD_SCHEMA,
1526
1196
  acpxRecordId: record.acpx_record_id,
1527
1197
  acpSessionId: record.acp_session_id,
1528
- agentSessionId: normalizeRuntimeSessionId(record.agent_session_id),
1198
+ agentSessionId: normalizeAgentSessionId(record.agent_session_id),
1529
1199
  agentCommand: record.agent_command,
1530
1200
  agentArgv: parsePersistedAgentArgv(record),
1531
1201
  cwd: record.cwd,
@@ -1545,7 +1215,7 @@ function parseSessionRecord(raw) {
1545
1215
  lastAgentExitAt: optionals.lastAgentExitAt,
1546
1216
  lastAgentDisconnectReason: optionals.lastAgentDisconnectReason,
1547
1217
  protocolVersion: typeof record.protocol_version === "number" ? record.protocol_version : void 0,
1548
- agentCapabilities: asRecord$4(record.agent_capabilities),
1218
+ agentCapabilities: asRecord$5(record.agent_capabilities),
1549
1219
  title: conversation.title,
1550
1220
  messages: conversation.messages,
1551
1221
  updated_at: conversation.updated_at,
@@ -1669,7 +1339,8 @@ const ZED_TAG_KEYS = /* @__PURE__ */ new Set([
1669
1339
  const MAP_OBJECT_PATHS = /* @__PURE__ */ new Set([
1670
1340
  "request_token_usage",
1671
1341
  "messages.Agent.tool_results",
1672
- "acpx.session_options.env"
1342
+ "acpx.session_options.env",
1343
+ "acpx.available_model_names"
1673
1344
  ]);
1674
1345
  const OPAQUE_VALUE_PATHS = /* @__PURE__ */ new Set([
1675
1346
  "agent_capabilities",
@@ -1683,10 +1354,6 @@ function isRecord(value) {
1683
1354
  function joinPath(path) {
1684
1355
  return path.join(".");
1685
1356
  }
1686
- function isAllowedKey(path, key) {
1687
- if (ZED_TAG_KEYS.has(key)) return true;
1688
- return false;
1689
- }
1690
1357
  function shouldSkipKeyRule(path) {
1691
1358
  return MAP_OBJECT_PATHS.has(joinPath(path));
1692
1359
  }
@@ -1712,7 +1379,7 @@ function collectViolations(value, path, violations) {
1712
1379
  for (const [key, child] of Object.entries(value)) collectKeyViolation(child, key, path, skipKeyRule, violations);
1713
1380
  }
1714
1381
  function collectKeyViolation(child, key, path, skipKeyRule, violations) {
1715
- if (!skipKeyRule && !SNAKE_CASE_KEY.test(key) && !isAllowedKey(path, key)) violations.push(`${joinPath(path)}.${key}`.replace(/^\./, ""));
1382
+ if (!skipKeyRule && !SNAKE_CASE_KEY.test(key) && !ZED_TAG_KEYS.has(key)) violations.push(`${joinPath(path)}.${key}`.replace(/^\./, ""));
1716
1383
  const childPath = [...path, key];
1717
1384
  if (!shouldSkipDescend(childPath)) collectViolations(child, childPath, violations);
1718
1385
  }
@@ -1727,20 +1394,14 @@ function assertPersistedKeyPolicy(value) {
1727
1394
  throw new Error(`Persisted key policy violation (expected snake_case keys): ${violations.join(", ")}`);
1728
1395
  }
1729
1396
  //#endregion
1730
- //#region src/session/persistence/atomic-write.ts
1731
- function createAtomicWriteTempPath(filePath, createUniqueId = randomUUID) {
1732
- const tempName = `.acpx-write.${process.pid}.${Date.now()}.${createUniqueId()}.tmp`;
1733
- return path.join(path.dirname(filePath), tempName);
1734
- }
1735
- //#endregion
1736
1397
  //#region src/session/persistence/index.ts
1737
1398
  const SESSION_INDEX_SCHEMA = "acpx.session-index.v1";
1738
- function asRecord$3(value) {
1399
+ function asRecord$4(value) {
1739
1400
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
1740
1401
  return value;
1741
1402
  }
1742
1403
  function parseIndexEntry(raw) {
1743
- const record = asRecord$3(raw);
1404
+ const record = asRecord$4(raw);
1744
1405
  if (!record) return;
1745
1406
  if (!hasRequiredIndexEntryFields(record)) return;
1746
1407
  if (record.name !== void 0 && typeof record.name !== "string") return;
@@ -1784,7 +1445,7 @@ async function readSessionIndex(sessionDir) {
1784
1445
  const filePath = sessionIndexPath(sessionDir);
1785
1446
  try {
1786
1447
  const payload = await fs$1.readFile(filePath, "utf8");
1787
- const record = asRecord$3(JSON.parse(payload));
1448
+ const record = asRecord$4(JSON.parse(payload));
1788
1449
  if (!record || record.schema !== SESSION_INDEX_SCHEMA || !Array.isArray(record.files)) return;
1789
1450
  const files = record.files.filter((entry) => typeof entry === "string");
1790
1451
  if (files.length !== record.files.length || !Array.isArray(record.entries)) return;
@@ -1800,18 +1461,14 @@ async function readSessionIndex(sessionDir) {
1800
1461
  }
1801
1462
  }
1802
1463
  async function writeSessionIndex(sessionDir, index) {
1803
- const filePath = sessionIndexPath(sessionDir);
1804
- const tempFile = createAtomicWriteTempPath(filePath);
1805
- const payload = JSON.stringify({
1464
+ await writePrivateJsonFile(sessionIndexPath(sessionDir), {
1806
1465
  schema: SESSION_INDEX_SCHEMA,
1807
- files: [...index.files].toSorted(),
1808
- entries: [...index.entries].toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt))
1809
- }, null, 2);
1810
- await fs$1.writeFile(tempFile, `${payload}\n`, "utf8");
1811
- await fs$1.rename(tempFile, filePath);
1466
+ files: index.files.toSorted(),
1467
+ entries: index.entries.toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt))
1468
+ });
1812
1469
  }
1813
1470
  async function rebuildSessionIndex(sessionDir) {
1814
- const files = (await fs$1.readdir(sessionDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && entry.name !== "index.json").map((entry) => entry.name).toSorted();
1471
+ const files = await listSessionFiles(sessionDir);
1815
1472
  const indexEntries = [];
1816
1473
  for (const file of files) try {
1817
1474
  const payload = await fs$1.readFile(path.join(sessionDir, file), "utf8");
@@ -1828,23 +1485,26 @@ async function rebuildSessionIndex(sessionDir) {
1828
1485
  return index;
1829
1486
  }
1830
1487
  async function loadOrRebuildSessionIndex(sessionDir) {
1831
- const files = (await fs$1.readdir(sessionDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && entry.name !== "index.json").map((entry) => entry.name).toSorted();
1488
+ const files = await listSessionFiles(sessionDir);
1832
1489
  const existing = await readSessionIndex(sessionDir);
1833
1490
  if (existing && existing.files.length === files.length && existing.files.every((file, index) => file === files[index])) return existing;
1834
1491
  return await rebuildSessionIndex(sessionDir);
1835
1492
  }
1493
+ async function listSessionFiles(sessionDir) {
1494
+ return (await fs$1.readdir(sessionDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && entry.name !== "index.json").map((entry) => entry.name).toSorted();
1495
+ }
1836
1496
  //#endregion
1837
1497
  //#region src/session/persistence/repository.ts
1838
1498
  const DEFAULT_HISTORY_LIMIT = 20;
1839
1499
  function sessionFilePath(acpxRecordId) {
1840
- const safeId = encodeURIComponent(acpxRecordId);
1500
+ const safeId = safeSessionId(acpxRecordId);
1841
1501
  return path.join(sessionBaseDir(), `${safeId}.json`);
1842
1502
  }
1843
- function sessionBaseDir() {
1844
- return path.join(os.homedir(), ".acpx", "sessions");
1845
- }
1846
1503
  async function ensureSessionDir() {
1847
- await fs$1.mkdir(sessionBaseDir(), { recursive: true });
1504
+ await fs$1.mkdir(sessionBaseDir(), {
1505
+ recursive: true,
1506
+ mode: 448
1507
+ });
1848
1508
  }
1849
1509
  async function loadRecordFromIndexEntry(entry) {
1850
1510
  try {
@@ -1868,14 +1528,10 @@ function matchesSessionEntry(session, normalizedCwd, normalizedName, includeClos
1868
1528
  }
1869
1529
  async function writeSessionRecord(record) {
1870
1530
  await measurePerf("session.write_record", async () => {
1871
- await ensureSessionDir();
1872
1531
  const persisted = serializeSessionRecordForDisk(record);
1873
1532
  assertPersistedKeyPolicy(persisted);
1874
1533
  const file = sessionFilePath(record.acpxRecordId);
1875
- const tempFile = createAtomicWriteTempPath(file);
1876
- const payload = JSON.stringify(persisted, null, 2);
1877
- await fs$1.writeFile(tempFile, `${payload}\n`, "utf8");
1878
- await fs$1.rename(tempFile, file);
1534
+ await writePrivateJsonFile(file, persisted);
1879
1535
  const sessionDir = sessionBaseDir();
1880
1536
  const index = await loadOrRebuildSessionIndex(sessionDir);
1881
1537
  const fileName = path.basename(file);
@@ -1940,7 +1596,7 @@ function normalizeName(value) {
1940
1596
  const trimmed = value.trim();
1941
1597
  return trimmed.length > 0 ? trimmed : void 0;
1942
1598
  }
1943
- function isoNow$2() {
1599
+ function isoNow$1() {
1944
1600
  return (/* @__PURE__ */ new Date()).toISOString();
1945
1601
  }
1946
1602
  async function listSessions() {
@@ -2031,7 +1687,7 @@ function isBeforeCutoff(record, cutoffIso) {
2031
1687
  return !cutoffIso || closedAtOrLastUsedAt(record) < cutoffIso;
2032
1688
  }
2033
1689
  async function pruneSessionFiles(record, sessionDir, dirEntries, includeHistory) {
2034
- const safeId = encodeURIComponent(record.acpxRecordId);
1690
+ const safeId = safeSessionId(record.acpxRecordId);
2035
1691
  let bytesFreed = await unlinkCountingBytes(path.join(sessionDir, `${safeId}.json`));
2036
1692
  if (includeHistory) for (const name of dirEntries.filter((entry) => isSessionStreamFile(entry, safeId))) bytesFreed += await unlinkCountingBytes(path.join(sessionDir, name));
2037
1693
  return bytesFreed;
@@ -2068,10 +1724,6 @@ const WRITE_PREVIEW_MAX_CHARS = 1200;
2068
1724
  function nowIso$1() {
2069
1725
  return (/* @__PURE__ */ new Date()).toISOString();
2070
1726
  }
2071
- function isWithinRoot(rootDir, targetPath) {
2072
- const relative = path.relative(rootDir, targetPath);
2073
- return relative.length === 0 || !relative.startsWith("..") && !path.isAbsolute(relative);
2074
- }
2075
1727
  function toWritePreview(content) {
2076
1728
  const lines = content.replace(/\r\n/g, "\n").split("\n");
2077
1729
  const visibleLines = lines.slice(0, WRITE_PREVIEW_MAX_LINES);
@@ -2092,6 +1744,7 @@ function canPromptForPermission$2() {
2092
1744
  }
2093
1745
  var FileSystemHandlers = class {
2094
1746
  rootDir;
1747
+ workspace;
2095
1748
  permissionMode;
2096
1749
  nonInteractivePermissions;
2097
1750
  onOperation;
@@ -2121,7 +1774,7 @@ var FileSystemHandlers = class {
2121
1774
  });
2122
1775
  try {
2123
1776
  if (this.permissionMode === "deny-all") throw new PermissionDeniedError("Permission denied for fs/read_text_file (--deny-all)");
2124
- const content = await fs$1.readFile(filePath, "utf8");
1777
+ const content = await (await this.getWorkspace()).readText(`.${path.sep}${path.relative(this.rootDir, filePath)}`);
2125
1778
  const sliced = this.sliceContent(content, params.line, params.limit);
2126
1779
  this.emitOperation({
2127
1780
  method: "fs/read_text_file",
@@ -2156,8 +1809,12 @@ var FileSystemHandlers = class {
2156
1809
  });
2157
1810
  try {
2158
1811
  if (!await this.isWriteApproved(filePath, preview)) throw new PermissionDeniedError("Permission denied for fs/write_text_file");
2159
- await fs$1.mkdir(path.dirname(filePath), { recursive: true });
2160
- await fs$1.writeFile(filePath, params.content, "utf8");
1812
+ const file = await (await this.getWorkspace()).openWritable(`.${path.sep}${path.relative(this.rootDir, filePath)}`, { mode: 438 });
1813
+ try {
1814
+ await file.handle.writeFile(params.content, "utf8");
1815
+ } finally {
1816
+ await file.handle.close();
1817
+ }
2161
1818
  this.emitOperation({
2162
1819
  method: "fs/write_text_file",
2163
1820
  status: "completed",
@@ -2187,9 +1844,16 @@ var FileSystemHandlers = class {
2187
1844
  resolvePathWithinRoot(rawPath) {
2188
1845
  if (!path.isAbsolute(rawPath)) throw new Error(`Path must be absolute: ${rawPath}`);
2189
1846
  const resolved = path.resolve(rawPath);
2190
- if (!isWithinRoot(this.rootDir, resolved)) throw new Error(`Path is outside allowed cwd subtree: ${resolved}`);
1847
+ if (!isPathInside(this.rootDir, resolved)) throw new Error(`Path is outside allowed cwd subtree: ${resolved}`);
2191
1848
  return resolved;
2192
1849
  }
1850
+ getWorkspace() {
1851
+ return this.workspace ??= root(this.rootDir, {
1852
+ symlinks: "follow-within-root",
1853
+ hardlinks: "allow",
1854
+ maxBytes: Infinity
1855
+ });
1856
+ }
2193
1857
  sliceContent(content, line, limit) {
2194
1858
  if (line == null && limit == null) return content;
2195
1859
  const lines = content.split("\n");
@@ -2223,14 +1887,14 @@ function selected(optionId) {
2223
1887
  function cancelled() {
2224
1888
  return { outcome: { outcome: "cancelled" } };
2225
1889
  }
2226
- function withEscalationMetadata(response, event) {
1890
+ function withPermissionMetadata(response, metadata) {
2227
1891
  return {
2228
1892
  ...response,
2229
1893
  _meta: {
2230
1894
  ...response._meta,
2231
1895
  acpx: {
2232
1896
  ...response._meta?.acpx && typeof response._meta.acpx === "object" && !Array.isArray(response._meta.acpx) ? response._meta.acpx : {},
2233
- permissionEscalation: event
1897
+ ...metadata
2234
1898
  }
2235
1899
  }
2236
1900
  };
@@ -2405,7 +2069,7 @@ async function resolveEscalatingPermissionRequest(params, policyMatch, allowOpti
2405
2069
  if (canPromptForPermission$1()) return resolveInteractivePromptResult(params, allowOption, rejectOption);
2406
2070
  const escalation = buildEscalationEvent(params, policyMatch.matchedRule);
2407
2071
  return {
2408
- response: withEscalationMetadata(rejectOption ? selected(rejectOption.optionId) : cancelled(), escalation),
2072
+ response: withPermissionMetadata(rejectOption ? selected(rejectOption.optionId) : cancelled(), { permissionEscalation: escalation }),
2409
2073
  escalation
2410
2074
  };
2411
2075
  }
@@ -2467,419 +2131,180 @@ function classifyPermissionDecision(params, response) {
2467
2131
  return "denied";
2468
2132
  }
2469
2133
  //#endregion
2470
- //#region src/spawn-command-options.ts
2471
- function readWindowsEnvValue(env, key) {
2472
- const matchedKey = Object.keys(env).find((entry) => entry.toUpperCase() === key);
2473
- return matchedKey ? env[matchedKey] : void 0;
2474
- }
2475
- function windowsExecutableExtensions(env) {
2476
- return (readWindowsEnvValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
2477
- }
2478
- function commandCandidates(command, env) {
2479
- if (path.extname(command).length > 0) return [command];
2480
- return windowsExecutableExtensions(env).map((extension) => `${command}${extension}`);
2481
- }
2482
- function commandHasPath(command) {
2483
- return command.includes("/") || command.includes("\\") || path.isAbsolute(command);
2484
- }
2485
- function resolveWindowsPathCommand(command, env) {
2486
- const candidates = commandCandidates(command, env);
2487
- const pathValue = readWindowsEnvValue(env, "PATH");
2488
- if (!pathValue) return;
2489
- for (const directory of pathValue.split(";")) {
2490
- const resolved = findExistingCommandInDirectory(directory, candidates);
2491
- if (resolved) return resolved;
2492
- }
2493
- }
2494
- function findExistingCommandInDirectory(directory, candidates) {
2495
- const trimmedDirectory = directory.trim();
2496
- if (trimmedDirectory.length === 0) return;
2497
- return candidates.map((candidate) => path.join(trimmedDirectory, candidate)).find((resolved) => fs.existsSync(resolved));
2498
- }
2499
- function resolveWindowsWrapperToken(token, wrapperPath) {
2500
- const relative = token.match(/%~?dp0%?\s*[\\/]*(.*)$/i)?.[1]?.trim();
2501
- if (!relative) return;
2502
- const candidate = path.resolve(path.dirname(wrapperPath), relative.replace(/[\\/]+/g, path.sep).replace(/^[\\/]+/, ""));
2503
- return path.extname(candidate).toLowerCase() === ".exe" && fs.existsSync(candidate) ? candidate : void 0;
2504
- }
2505
- function resolveWindowsWrapperExecutable(wrapperPath) {
2506
- if (!fs.existsSync(wrapperPath)) return;
2507
- try {
2508
- return [...fs.readFileSync(wrapperPath, "utf8").matchAll(/"([^"\r\n]*)"/g)].map((match) => resolveWindowsWrapperToken(match[1] ?? "", wrapperPath)).find((candidate) => candidate !== void 0);
2509
- } catch {
2510
- return;
2134
+ //#region src/prompt-content.ts
2135
+ var PromptInputValidationError = class extends Error {
2136
+ constructor(message) {
2137
+ super(message);
2138
+ this.name = "PromptInputValidationError";
2511
2139
  }
2140
+ };
2141
+ function asRecord$3(value) {
2142
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
2143
+ return value;
2512
2144
  }
2513
- function resolveWindowsCommand(command, env = process.env) {
2514
- const candidates = commandCandidates(command, env);
2515
- if (commandHasPath(command)) return candidates.find((candidate) => fs.existsSync(candidate));
2516
- return resolveWindowsPathCommand(command, env);
2517
- }
2518
- /**
2519
- * Resolve a Windows command to a native executable suitable for direct spawn.
2520
- *
2521
- * Batch and PowerShell shims are intentionally rejected unless they point at a
2522
- * real `.exe` entrypoint. Callers that need shell execution should use the
2523
- * command-specific shell policy instead.
2524
- */
2525
- function resolveWindowsExecutablePath(command, env = process.env) {
2526
- const resolved = resolveWindowsCommand(command, env);
2527
- if (!resolved) return;
2528
- const absolute = path.resolve(resolved);
2529
- const extension = path.extname(absolute).toLowerCase();
2530
- if (extension === ".exe") return absolute;
2531
- if (extension !== ".cmd" && extension !== ".bat" && extension !== ".ps1") return;
2532
- const siblingExecutable = `${absolute.slice(0, -extension.length)}.exe`;
2533
- return fs.existsSync(siblingExecutable) ? siblingExecutable : resolveWindowsWrapperExecutable(absolute);
2534
- }
2535
- function shouldUseWindowsBatchShell(command, platform = process.platform, env = process.env) {
2536
- if (platform !== "win32") return false;
2537
- const resolvedCommand = resolveWindowsCommand(command, env) ?? command;
2538
- const ext = path.extname(resolvedCommand).toLowerCase();
2539
- return ext === ".cmd" || ext === ".bat";
2540
- }
2541
- const CMD_META_CHAR_RE = /([()\][%!^"`<>&|;, *?])/gu;
2542
- const CMD_BACKSLASH_QUOTE_RE = /(?=(\\+?)?)\1"/gu;
2543
- const CMD_TRAILING_BACKSLASH_RE = /(?=(\\+?)?)\1$/gu;
2544
- const CMD_SHIM_RE = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/iu;
2545
- function escapeCmdCommand(value) {
2546
- return value.replace(CMD_META_CHAR_RE, "^$1");
2547
- }
2548
- function escapeCmdArgument(value, doubleEscapeMeta) {
2549
- const escaped = `"${value.replace(CMD_BACKSLASH_QUOTE_RE, "$1$1\\\"").replace(CMD_TRAILING_BACKSLASH_RE, "$1$1")}"`.replace(CMD_META_CHAR_RE, "^$1");
2550
- return doubleEscapeMeta ? escaped.replace(CMD_META_CHAR_RE, "^$1") : escaped;
2551
- }
2552
- function buildAgentSpawnCommand(command, args, platform = process.platform, env = process.env) {
2553
- if (!shouldUseWindowsBatchShell(command, platform, env)) return {
2554
- command,
2555
- args: [...args]
2556
- };
2557
- const resolvedCommand = path.win32.normalize(resolveWindowsCommand(command, env) ?? command);
2558
- const doubleEscapeMeta = CMD_SHIM_RE.test(resolvedCommand);
2559
- const shellCommand = [escapeCmdCommand(resolvedCommand), ...args.map((arg) => escapeCmdArgument(arg, doubleEscapeMeta))].join(" ");
2560
- return {
2561
- command: readWindowsEnvValue(env, "COMSPEC") ?? "cmd.exe",
2562
- args: [
2563
- "/d",
2564
- "/s",
2565
- "/c",
2566
- `"${shellCommand}"`
2567
- ],
2568
- windowsVerbatimArguments: true
2569
- };
2570
- }
2571
- function buildSpawnCommandOptions(command, options, platform = process.platform, env = process.env) {
2572
- if (!shouldUseWindowsBatchShell(command, platform, env)) return options;
2573
- return {
2574
- ...options,
2575
- shell: true
2576
- };
2577
- }
2578
- function buildTerminalSpawnCommand(command, args) {
2579
- return {
2580
- command,
2581
- args: args ?? [],
2582
- killProcessGroup: false
2583
- };
2145
+ function isNonEmptyString(value) {
2146
+ return typeof value === "string" && value.trim().length > 0;
2584
2147
  }
2585
- function buildTerminalShellSpawnCommand(command, platform = process.platform) {
2586
- if (platform === "win32") return {
2587
- command: "cmd.exe",
2588
- args: [
2589
- "/d",
2590
- "/s",
2591
- "/c",
2592
- command
2593
- ],
2594
- killProcessGroup: true
2595
- };
2596
- return {
2597
- command: "/bin/sh",
2598
- args: ["-c", command],
2599
- killProcessGroup: true
2600
- };
2148
+ function isBase64Data(value) {
2149
+ if (value.length === 0 || value.length % 4 !== 0) return false;
2150
+ return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
2601
2151
  }
2602
- //#endregion
2603
- //#region src/version.ts
2604
- const UNKNOWN_VERSION = "0.0.0-unknown";
2605
- const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
2606
- let cachedVersion = null;
2607
- function parseVersion(value) {
2608
- if (typeof value !== "string") return null;
2609
- const trimmed = value.trim();
2610
- return trimmed.length > 0 ? trimmed : null;
2152
+ function isImageMimeType(value) {
2153
+ return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
2611
2154
  }
2612
- function readPackageVersion(packageJsonPath) {
2613
- try {
2614
- return parseVersion(JSON.parse(readFileSync(packageJsonPath, "utf8")).version);
2615
- } catch {
2616
- return null;
2617
- }
2155
+ function isAudioMimeType(value) {
2156
+ return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
2618
2157
  }
2619
- function resolveVersionFromAncestors(startDir) {
2620
- let current = startDir;
2621
- while (true) {
2622
- const packageVersion = readPackageVersion(path.join(current, "package.json"));
2623
- if (packageVersion) return packageVersion;
2624
- const parent = path.dirname(current);
2625
- if (parent === current) return null;
2626
- current = parent;
2627
- }
2158
+ function isTextBlock(value) {
2159
+ const record = asRecord$3(value);
2160
+ return record?.type === "text" && typeof record.text === "string";
2628
2161
  }
2629
- function resolveAcpxVersion(params) {
2630
- const envVersion = resolvePackageEnvVersion(params?.env ?? process.env);
2631
- if (envVersion) return envVersion;
2632
- if (params?.packageJsonPath) return readPackageVersion(params.packageJsonPath) ?? UNKNOWN_VERSION;
2633
- return resolveVersionFromAncestors(MODULE_DIR) ?? UNKNOWN_VERSION;
2162
+ function isImageBlock(value) {
2163
+ const record = asRecord$3(value);
2164
+ return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2634
2165
  }
2635
- function resolvePackageEnvVersion(env) {
2636
- const envPackageName = parseVersion(env.npm_package_name);
2637
- const envVersion = parseVersion(env.npm_package_version);
2638
- return envPackageName === "acpx" ? envVersion : null;
2166
+ function isAudioBlock(value) {
2167
+ const record = asRecord$3(value);
2168
+ return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2639
2169
  }
2640
- function getAcpxVersion() {
2641
- if (cachedVersion) return cachedVersion;
2642
- cachedVersion = resolveAcpxVersion();
2643
- return cachedVersion;
2170
+ function isResourceLinkBlock(value) {
2171
+ const record = asRecord$3(value);
2172
+ return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title === void 0 || typeof record.title === "string") && (record.name === void 0 || typeof record.name === "string");
2644
2173
  }
2645
- //#endregion
2646
- //#region src/acp/client-process.ts
2647
- const PROCESS_HELPER_TIMEOUT_MS = 8e3;
2648
- async function runTimedExecFile(command, args, options = {}) {
2649
- const timeoutMs = Math.max(1, Math.round(options.timeoutMs ?? 8e3));
2650
- return await new Promise((resolve, reject) => {
2651
- let settled = false;
2652
- let timer;
2653
- const child = execFile(command, [...args], {
2654
- encoding: "utf8",
2655
- maxBuffer: options.maxBufferBytes ?? 33554432,
2656
- killSignal: "SIGKILL",
2657
- windowsHide: options.windowsHide
2658
- }, (error, stdout) => {
2659
- if (settled) return;
2660
- settled = true;
2661
- if (timer) clearTimeout(timer);
2662
- if (error) {
2663
- reject(error);
2664
- return;
2665
- }
2666
- resolve(stdout);
2667
- });
2668
- timer = setTimeout(() => {
2669
- if (settled) return;
2670
- settled = true;
2671
- const killed = child.kill("SIGKILL");
2672
- child.stdout?.destroy();
2673
- child.stderr?.destroy();
2674
- child.unref();
2675
- reject(Object.assign(/* @__PURE__ */ new Error(`${command} timed out after ${timeoutMs}ms`), {
2676
- code: "ETIMEDOUT",
2677
- killed,
2678
- signal: "SIGKILL"
2679
- }));
2680
- }, timeoutMs);
2681
- });
2174
+ function isResourcePayload(value) {
2175
+ const record = asRecord$3(value);
2176
+ if (!record || !isNonEmptyString(record.uri)) return false;
2177
+ return record.text === void 0 || typeof record.text === "string";
2682
2178
  }
2683
- function normalizeAgentCommandInput(value) {
2684
- if (typeof value === "string") return { agentCommand: value };
2685
- const parts = toCommandParts([...value]);
2686
- const argv = [parts.command, ...parts.args];
2687
- return {
2688
- agentCommand: renderArgvIdentity(argv),
2689
- agentArgv: argv
2690
- };
2179
+ function isResourceBlock(value) {
2180
+ const record = asRecord$3(value);
2181
+ return record?.type === "resource" && isResourcePayload(record.resource);
2691
2182
  }
2692
- const IDENTITY_SAFE_ARG_RE = /^[A-Za-z0-9_@%+=:,./^~-]+$/u;
2693
- function renderArgvIdentity(argv) {
2694
- return argv.map((arg) => IDENTITY_SAFE_ARG_RE.test(arg) ? arg : JSON.stringify(arg)).join(" ");
2183
+ const CONTENT_BLOCK_VALIDATORS = [
2184
+ isTextBlock,
2185
+ isImageBlock,
2186
+ isAudioBlock,
2187
+ isResourceLinkBlock,
2188
+ isResourceBlock
2189
+ ];
2190
+ function isContentBlock(value) {
2191
+ return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
2695
2192
  }
2696
- function isoNow$1() {
2697
- return (/* @__PURE__ */ new Date()).toISOString();
2193
+ const CONTENT_BLOCK_ERROR_VALIDATORS = {
2194
+ text: validateTextContentBlock,
2195
+ image: validateImageContentBlock,
2196
+ audio: validateAudioContentBlock,
2197
+ resource_link: validateResourceLinkContentBlock,
2198
+ resource: validateResourceContentBlock
2199
+ };
2200
+ function contentBlockErrorValidator(type) {
2201
+ return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
2698
2202
  }
2699
- function waitForSpawn$1(child) {
2700
- return new Promise((resolve, reject) => {
2701
- const onSpawn = () => {
2702
- child.off("error", onError);
2703
- resolve();
2704
- };
2705
- const onError = (error) => {
2706
- child.off("spawn", onSpawn);
2707
- reject(error);
2708
- };
2709
- child.once("spawn", onSpawn);
2710
- child.once("error", onError);
2711
- });
2203
+ function validateTextContentBlock(record, index) {
2204
+ return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
2712
2205
  }
2713
- function isChildProcessRunning(child) {
2714
- return child.exitCode == null && child.signalCode == null;
2206
+ function validateImageContentBlock(record, index) {
2207
+ if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
2208
+ if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
2209
+ if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
2210
+ return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
2715
2211
  }
2716
- function requireAgentStdio(child) {
2717
- if (!child.stdin || !child.stdout || !child.stderr) throw new Error("ACP agent must be spawned with piped stdin/stdout/stderr");
2718
- return child;
2212
+ function validateAudioContentBlock(record, index) {
2213
+ if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
2214
+ if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
2215
+ if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
2216
+ return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
2719
2217
  }
2720
- function waitForChildExit(child, timeoutMs) {
2721
- if (!isChildProcessRunning(child)) return Promise.resolve(true);
2722
- return new Promise((resolve) => {
2723
- let settled = false;
2724
- const timer = setTimeout(() => {
2725
- finish(false);
2726
- }, Math.max(0, timeoutMs));
2727
- const finish = (value) => {
2728
- if (settled) return;
2729
- settled = true;
2730
- child.off("close", onExitLike);
2731
- child.off("exit", onExitLike);
2732
- clearTimeout(timer);
2733
- resolve(value);
2734
- };
2735
- const onExitLike = () => {
2736
- finish(true);
2737
- };
2738
- child.once("close", onExitLike);
2739
- child.once("exit", onExitLike);
2740
- });
2218
+ function validateResourceLinkContentBlock(record, index) {
2219
+ if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
2220
+ if (record.title !== void 0 && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string when present`;
2221
+ if (record.name !== void 0 && typeof record.name !== "string") return `prompt[${index}] resource_link block name must be a string when present`;
2741
2222
  }
2742
- function resolveAgentCommandParts(value, argv, platform = process.platform) {
2743
- if (argv) {
2744
- const parts = toCommandParts([...argv]);
2745
- assertWindowsLaunchableCommand(parts.command, platform);
2746
- return parts;
2747
- }
2748
- if (platform === "win32") throw new Error("Raw agent command strings are not supported on Windows. Configure the agent with an argv array, for example: \"argv\": [\"agent.exe\", \"--acp\"]. Legacy agents.<name>.args arrays are migrated automatically. Existing sessions without saved argv must be closed and recreated.");
2749
- return splitCommandLine(value);
2750
- }
2751
- function assertWindowsLaunchableCommand(command, platform) {
2752
- if (platform === "win32" && path.extname(command).toLowerCase() === ".sh") throw new Error(`Windows cannot launch shell script executable "${command}" directly. Configure an explicit interpreter argv, for example: "argv": ["bash", "${command}"]. acpx does not infer interpreters.`);
2753
- }
2754
- function splitCommandLine(value) {
2755
- const parts = [];
2756
- let current = "";
2757
- let quote = null;
2758
- let escaping = false;
2759
- let hasPart = false;
2760
- for (const ch of value) {
2761
- const next = readCommandLineChar({
2762
- ch,
2763
- current,
2764
- quote,
2765
- escaping,
2766
- parts,
2767
- hasPart
2768
- });
2769
- current = next.current;
2770
- quote = next.quote;
2771
- escaping = next.escaping;
2772
- hasPart = next.hasPart;
2773
- }
2774
- if (escaping) {
2775
- current += "\\";
2776
- hasPart = true;
2777
- }
2778
- if (quote) throw new Error("Invalid --agent command: unterminated quote");
2779
- if (hasPart) parts.push(current);
2780
- return toCommandParts(parts);
2223
+ function validateResourceContentBlock(record, index) {
2224
+ if (!asRecord$3(record.resource)) return `prompt[${index}] resource block must include a resource object`;
2225
+ return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and optional text`;
2781
2226
  }
2782
- function toCommandParts(parts) {
2783
- if (parts.length === 0 || parts[0] === "") throw new Error("Invalid --agent command: empty command");
2784
- return {
2785
- command: parts[0],
2786
- args: parts.slice(1)
2787
- };
2227
+ function getContentBlockValidationError(value, index) {
2228
+ const record = asRecord$3(value);
2229
+ if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
2230
+ const validator = contentBlockErrorValidator(record.type);
2231
+ return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
2788
2232
  }
2789
- function readCommandLineChar(state) {
2790
- if (state.escaping) return {
2791
- current: state.current + state.ch,
2792
- quote: state.quote,
2793
- escaping: false,
2794
- hasPart: true
2795
- };
2796
- if (state.ch === "\\" && state.quote !== "'") return {
2797
- current: state.current,
2798
- quote: state.quote,
2799
- escaping: true,
2800
- hasPart: state.hasPart
2801
- };
2802
- if (state.quote) return readQuotedCommandLineChar({
2803
- ch: state.ch,
2804
- current: state.current,
2805
- quote: state.quote,
2806
- hasPart: state.hasPart
2807
- });
2808
- return readUnquotedCommandLineChar(state);
2809
- }
2810
- function readQuotedCommandLineChar(state) {
2811
- if (state.ch === state.quote) return {
2812
- current: state.current,
2813
- quote: null,
2814
- escaping: false,
2815
- hasPart: true
2816
- };
2817
- return {
2818
- current: state.current + state.ch,
2819
- quote: state.quote,
2820
- escaping: false,
2821
- hasPart: true
2822
- };
2233
+ function isPromptInput(value) {
2234
+ return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
2823
2235
  }
2824
- function readUnquotedCommandLineChar(state) {
2825
- if (state.ch === "'" || state.ch === "\"") return {
2826
- current: state.current,
2827
- quote: state.ch,
2828
- escaping: false,
2829
- hasPart: true
2830
- };
2831
- if (/\s/.test(state.ch)) {
2832
- flushCommandLinePart(state.parts, state.current, state.hasPart);
2833
- return {
2834
- current: "",
2835
- quote: null,
2836
- escaping: false,
2837
- hasPart: false
2236
+ function promptCapabilityRequirement(block) {
2237
+ switch (block.type) {
2238
+ case "image": return {
2239
+ blockType: "image",
2240
+ capability: "image"
2241
+ };
2242
+ case "audio": return {
2243
+ blockType: "audio",
2244
+ capability: "audio"
2245
+ };
2246
+ case "resource": return {
2247
+ blockType: "resource",
2248
+ capability: "embeddedContext"
2838
2249
  };
2250
+ default: return;
2839
2251
  }
2840
- return {
2841
- current: state.current + state.ch,
2842
- quote: null,
2843
- escaping: false,
2844
- hasPart: true
2845
- };
2846
- }
2847
- function flushCommandLinePart(parts, current, hasPart) {
2848
- if (hasPart) parts.push(current);
2849
2252
  }
2850
- function asAbsoluteCwd(cwd) {
2851
- return path.resolve(cwd);
2253
+ function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
2254
+ for (const [index, block] of prompt.entries()) {
2255
+ const requirement = promptCapabilityRequirement(block);
2256
+ if (!requirement) continue;
2257
+ if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
2258
+ return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
2259
+ }
2852
2260
  }
2853
- async function resolveAgentSessionCwd(cwd, agentCommand, options = {}) {
2854
- const resolved = asAbsoluteCwd(cwd);
2855
- if (!shouldTranslateWslWindowsCwd(agentCommand, options)) return resolved;
2856
- const translated = (await (options.runWslpath ?? runWslpath)(resolved)).trim();
2857
- if (!translated) throw new Error(`wslpath returned an empty Windows path for cwd: ${resolved}`);
2858
- return translated;
2261
+ function textPrompt(text) {
2262
+ return [{
2263
+ type: "text",
2264
+ text
2265
+ }];
2859
2266
  }
2860
- function shouldTranslateWslWindowsCwd(agentCommand, options) {
2861
- if (!isWsl(options)) return false;
2267
+ function parseStructuredPrompt(source) {
2268
+ if (!source.startsWith("[")) return;
2862
2269
  try {
2863
- const { command } = splitCommandLine(agentCommand);
2864
- return isWindowsExecutableCommand(command);
2865
- } catch {
2866
- return false;
2270
+ const parsed = JSON.parse(source);
2271
+ if (isPromptInput(parsed)) return parsed;
2272
+ if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
2273
+ return;
2274
+ } catch (error) {
2275
+ if (error instanceof PromptInputValidationError) throw error;
2276
+ return;
2867
2277
  }
2868
2278
  }
2869
- function isWsl(options) {
2870
- if ((options.platform ?? process.platform) !== "linux") return false;
2871
- return (options.existsSync ?? fs.existsSync)("/proc/sys/fs/binfmt_misc/WSLInterop");
2279
+ function parsePromptSource(source) {
2280
+ const trimmed = source.trim();
2281
+ const structured = parseStructuredPrompt(trimmed);
2282
+ if (structured) return structured;
2283
+ if (!trimmed) return [];
2284
+ return textPrompt(trimmed);
2285
+ }
2286
+ function mergePromptSourceWithText(source, suffixText) {
2287
+ const prompt = parsePromptSource(source);
2288
+ const appended = suffixText.trim();
2289
+ if (!appended) return prompt;
2290
+ if (prompt.length === 0) return textPrompt(appended);
2291
+ return [...prompt, ...textPrompt(appended)];
2872
2292
  }
2873
- const WINDOWS_EXECUTABLE_EXTENSION_RE = /\.(?:exe|cmd|bat)$/u;
2874
- function isWindowsExecutableCommand(command) {
2875
- const normalized = command.toLowerCase();
2876
- return WINDOWS_EXECUTABLE_EXTENSION_RE.test(normalized);
2293
+ function promptToDisplayText(prompt) {
2294
+ return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
2877
2295
  }
2878
- async function runWslpath(cwd) {
2879
- return await runTimedExecFile("wslpath", ["-w", cwd]);
2296
+ function contentBlockDisplayText(block) {
2297
+ switch (block.type) {
2298
+ case "text": return block.text;
2299
+ case "resource_link": return block.title ?? block.name ?? block.uri;
2300
+ case "resource": return resourceBlockDisplayText(block);
2301
+ case "image": return `[image] ${block.mimeType}`;
2302
+ case "audio": return `[audio] ${block.mimeType}`;
2303
+ default: return "";
2304
+ }
2880
2305
  }
2881
- function basenameToken(value) {
2882
- return path.basename(value).toLowerCase().replace(/\.(cmd|exe|bat)$/u, "");
2306
+ function resourceBlockDisplayText(block) {
2307
+ return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
2883
2308
  }
2884
2309
  //#endregion
2885
2310
  //#region src/acp/agent-command.ts
@@ -3178,32 +2603,108 @@ function addAuthCredentialEnvKeys(protectedKeys, methodId, credential) {
3178
2603
  protectEnvKey(protectedKeys, normalized);
3179
2604
  }
3180
2605
  }
3181
- function assignAuthCredentialEnv(env, methodId, credential) {
3182
- if (typeof credential !== "string" || credential.trim().length === 0) return;
3183
- if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
3184
- const normalized = toEnvToken(methodId);
3185
- if (normalized) {
3186
- assignIfMissing(env, `${AUTH_ENV_PREFIX}${normalized}`, credential);
3187
- assignIfMissing(env, normalized, credential);
2606
+ function assignAuthCredentialEnv(env, methodId, credential) {
2607
+ if (typeof credential !== "string" || credential.trim().length === 0) return;
2608
+ if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
2609
+ const normalized = toEnvToken(methodId);
2610
+ if (normalized) {
2611
+ assignIfMissing(env, `${AUTH_ENV_PREFIX}${normalized}`, credential);
2612
+ assignIfMissing(env, normalized, credential);
2613
+ }
2614
+ }
2615
+ function assignIfMissing(env, key, value) {
2616
+ if (env[key] == null) env[key] = value;
2617
+ }
2618
+ function resolveConfiguredAuthCredential(methodId, authCredentials) {
2619
+ const configCredentials = authCredentials ?? {};
2620
+ return configCredentials[methodId] ?? configCredentials[toEnvToken(methodId)];
2621
+ }
2622
+ function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv, agentProcessEnv) {
2623
+ return {
2624
+ cwd,
2625
+ env: buildAgentEnvironment(authCredentials, sessionEnv, agentProcessEnv),
2626
+ stdio: [
2627
+ "pipe",
2628
+ "pipe",
2629
+ "pipe"
2630
+ ],
2631
+ windowsHide: true
2632
+ };
2633
+ }
2634
+ //#endregion
2635
+ //#region src/version.ts
2636
+ const UNKNOWN_VERSION = "0.0.0-unknown";
2637
+ const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
2638
+ let cachedVersion = null;
2639
+ function parseVersion(value) {
2640
+ if (typeof value !== "string") return null;
2641
+ const trimmed = value.trim();
2642
+ return trimmed.length > 0 ? trimmed : null;
2643
+ }
2644
+ function readPackageVersion(packageJsonPath) {
2645
+ try {
2646
+ return parseVersion(JSON.parse(readFileSync(packageJsonPath, "utf8")).version);
2647
+ } catch {
2648
+ return null;
2649
+ }
2650
+ }
2651
+ function resolveVersionFromAncestors(startDir) {
2652
+ let current = startDir;
2653
+ while (true) {
2654
+ const packageVersion = readPackageVersion(path.join(current, "package.json"));
2655
+ if (packageVersion) return packageVersion;
2656
+ const parent = path.dirname(current);
2657
+ if (parent === current) return null;
2658
+ current = parent;
3188
2659
  }
3189
2660
  }
3190
- function assignIfMissing(env, key, value) {
3191
- if (env[key] == null) env[key] = value;
2661
+ function resolveAcpxVersion(params) {
2662
+ const envVersion = resolvePackageEnvVersion(params?.env ?? process.env);
2663
+ if (envVersion) return envVersion;
2664
+ if (params?.packageJsonPath) return readPackageVersion(params.packageJsonPath) ?? UNKNOWN_VERSION;
2665
+ return resolveVersionFromAncestors(MODULE_DIR) ?? UNKNOWN_VERSION;
3192
2666
  }
3193
- function resolveConfiguredAuthCredential(methodId, authCredentials) {
3194
- const configCredentials = authCredentials ?? {};
3195
- return configCredentials[methodId] ?? configCredentials[toEnvToken(methodId)];
2667
+ function resolvePackageEnvVersion(env) {
2668
+ const envPackageName = parseVersion(env.npm_package_name);
2669
+ const envVersion = parseVersion(env.npm_package_version);
2670
+ return envPackageName === "acpx" ? envVersion : null;
3196
2671
  }
3197
- function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv, agentProcessEnv) {
2672
+ function getAcpxVersion() {
2673
+ if (cachedVersion) return cachedVersion;
2674
+ cachedVersion = resolveAcpxVersion();
2675
+ return cachedVersion;
2676
+ }
2677
+ //#endregion
2678
+ //#region src/acp/client-protocol.ts
2679
+ const DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META = Object.freeze({ "cognition.ai/requestDiagnostics": true });
2680
+ const DEVIN_COMPATIBILITY_CLIENT_NAME = "windsurf";
2681
+ const DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION = "1.110.1";
2682
+ function resolveClientInfo(devinAcp) {
2683
+ if (!devinAcp) return {
2684
+ name: "acpx",
2685
+ version: getAcpxVersion()
2686
+ };
3198
2687
  return {
3199
- cwd,
3200
- env: buildAgentEnvironment(authCredentials, sessionEnv, agentProcessEnv),
3201
- stdio: [
3202
- "pipe",
3203
- "pipe",
3204
- "pipe"
3205
- ],
3206
- windowsHide: true
2688
+ name: DEVIN_COMPATIBILITY_CLIENT_NAME,
2689
+ version: process.env.ACPX_DEVIN_WINDSURF_VERSION ?? DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION
2690
+ };
2691
+ }
2692
+ function resolveClientCapabilities(params) {
2693
+ const baseCapabilities = {
2694
+ fs: {
2695
+ readTextFile: params.fs,
2696
+ writeTextFile: params.fs
2697
+ },
2698
+ terminal: params.terminal,
2699
+ ...params.elicitationModes.length > 0 ? { elicitation: {
2700
+ ...params.elicitationModes.includes("form") ? { form: {} } : {},
2701
+ ...params.elicitationModes.includes("url") ? { url: {} } : {}
2702
+ } } : {}
2703
+ };
2704
+ if (!params.devinAcp) return baseCapabilities;
2705
+ return {
2706
+ ...baseCapabilities,
2707
+ _meta: DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META
3207
2708
  };
3208
2709
  }
3209
2710
  //#endregion
@@ -3261,9 +2762,8 @@ function parseAvailableModels(value) {
3261
2762
  function isModelSelectOption(option) {
3262
2763
  return option.type === "select" && (option.category === "model" || option.id === "model");
3263
2764
  }
3264
- function parseModelConfigOption(value) {
3265
- const option = asRecord$2(value);
3266
- if (!option || !isModelSelectOption(option) || typeof option.id !== "string" || typeof option.currentValue !== "string") return;
2765
+ function parseModelConfigOption(option) {
2766
+ if (!isModelSelectOption(option) || typeof option.id !== "string" || typeof option.currentValue !== "string") return;
3267
2767
  const availableModels = parseAvailableModels(option.options);
3268
2768
  return availableModels ? {
3269
2769
  configId: option.id,
@@ -3271,12 +2771,26 @@ function parseModelConfigOption(value) {
3271
2771
  availableModels
3272
2772
  } : void 0;
3273
2773
  }
2774
+ function modelConfigPriority(option) {
2775
+ if (option.category !== "model") return 0;
2776
+ return option.id === "model" ? 2 : 1;
2777
+ }
3274
2778
  function modelStateFromConfigOptions(configOptions) {
3275
2779
  if (!Array.isArray(configOptions)) return;
2780
+ let selected;
2781
+ let selectedPriority = -1;
3276
2782
  for (const value of configOptions) {
3277
- const models = parseModelConfigOption(value);
3278
- if (models) return models;
2783
+ const option = asRecord$2(value);
2784
+ if (!option) continue;
2785
+ const models = parseModelConfigOption(option);
2786
+ if (!models) continue;
2787
+ const priority = modelConfigPriority(option);
2788
+ if (priority > selectedPriority) {
2789
+ selected = models;
2790
+ selectedPriority = priority;
2791
+ }
3279
2792
  }
2793
+ return selected;
3280
2794
  }
3281
2795
  function modelStateFromLegacyResponse(response) {
3282
2796
  if (!response || typeof response !== "object") return;
@@ -3327,9 +2841,10 @@ function assertRequestedModelSupported(params) {
3327
2841
  }
3328
2842
  //#endregion
3329
2843
  //#region src/acp/ndjson-stream.ts
2844
+ const DEFAULT_MAX_ACP_MESSAGE_BYTES = 67108864;
3330
2845
  var AcpMessageLimitError = class extends AcpxOperationalError {
3331
2846
  constructor(limit) {
3332
- super(`ACP message exceeded ACPX_MAX_ACP_MESSAGE_BYTES (${limit} bytes)`, {
2847
+ super(`ACP message exceeded ACPX_MAX_ACP_MESSAGE_BYTES (${limit} bytes). Increase the limit or set it to 0 for unlimited input.`, {
3333
2848
  outputCode: "RUNTIME",
3334
2849
  detailCode: "ACP_MESSAGE_TOO_LARGE",
3335
2850
  origin: "acp",
@@ -3339,7 +2854,7 @@ var AcpMessageLimitError = class extends AcpxOperationalError {
3339
2854
  };
3340
2855
  function readMaxAcpMessageBytes(raw = process.env.ACPX_MAX_ACP_MESSAGE_BYTES) {
3341
2856
  const value = raw?.trim();
3342
- if (!value) return;
2857
+ if (!value) return DEFAULT_MAX_ACP_MESSAGE_BYTES;
3343
2858
  const bytes = Number(value);
3344
2859
  if (!/^\d+$/.test(value) || !Number.isSafeInteger(bytes)) throw new Error("ACPX_MAX_ACP_MESSAGE_BYTES must be a non-negative safe integer; zero is unlimited");
3345
2860
  return bytes === 0 ? void 0 : bytes;
@@ -3413,6 +2928,156 @@ function createNdJsonMessageStream(agentCommand, output, input, maxMessageBytes,
3413
2928
  };
3414
2929
  }
3415
2930
  //#endregion
2931
+ //#region src/acp/observed-stream.ts
2932
+ function observeAcpStream(base, options) {
2933
+ const elicitationRequestIds = /* @__PURE__ */ new Set();
2934
+ const shouldSuppressInboundReplaySessionUpdate = (message) => {
2935
+ return options.suppressReplaySessionUpdates() && isSessionUpdateNotification(message);
2936
+ };
2937
+ const observeInbound = (message) => {
2938
+ const requestId = elicitationRequestId(message);
2939
+ if (requestId !== void 0) {
2940
+ elicitationRequestIds.add(requestId);
2941
+ return;
2942
+ }
2943
+ if (!shouldSuppressInboundReplaySessionUpdate(message)) options.onMessage("inbound", message);
2944
+ };
2945
+ return {
2946
+ readable: new ReadableStream({ async start(controller) {
2947
+ const reader = base.readable.getReader();
2948
+ try {
2949
+ while (true) {
2950
+ const { value, done } = await reader.read();
2951
+ if (done) break;
2952
+ if (!value) continue;
2953
+ observeInbound(value);
2954
+ if (isExtensionNotification(value)) continue;
2955
+ controller.enqueue(value);
2956
+ }
2957
+ } finally {
2958
+ reader.releaseLock();
2959
+ controller.close();
2960
+ }
2961
+ } }),
2962
+ writable: new WritableStream({ async write(message) {
2963
+ const promptOwner = promptRequestOwner(message);
2964
+ const activePrompt = promptOwner ? options.bindPromptOwner(promptOwner) : void 0;
2965
+ const id = responseId(message);
2966
+ if (!(id !== void 0 && elicitationRequestIds.delete(id))) options.onMessage("outbound", message);
2967
+ const writer = base.writable.getWriter();
2968
+ try {
2969
+ await writer.write(message);
2970
+ } finally {
2971
+ writer.releaseLock();
2972
+ }
2973
+ if (activePrompt && promptOwner) options.onPromptRequestWritten(activePrompt, promptOwner);
2974
+ } })
2975
+ };
2976
+ }
2977
+ function isExtensionNotification(message) {
2978
+ if (!("method" in message) || "id" in message || typeof message.method !== "string") return false;
2979
+ return message.method !== methods.client.session.update && message.method !== methods.client.elicitation.complete && message.method !== methods.protocol.cancelRequest;
2980
+ }
2981
+ function elicitationRequestId(message) {
2982
+ if (!("method" in message) || message.method !== methods.client.elicitation.create || !("id" in message)) return;
2983
+ return message.id;
2984
+ }
2985
+ function responseId(message) {
2986
+ if (!("id" in message) || "method" in message) return;
2987
+ return message.id;
2988
+ }
2989
+ function promptRequestOwner(message) {
2990
+ if (!("method" in message) || message.method !== methods.agent.session.prompt || !("id" in message)) return;
2991
+ const sessionId = message.params?.sessionId;
2992
+ return typeof sessionId === "string" ? {
2993
+ requestId: message.id,
2994
+ sessionId
2995
+ } : void 0;
2996
+ }
2997
+ //#endregion
2998
+ //#region src/acp/process-descendants.ts
2999
+ function parseProcessTable(output) {
3000
+ const table = /* @__PURE__ */ new Map();
3001
+ for (const line of output.split("\n")) {
3002
+ const match = /^\s*(\d+)\s+(\d+)\s+(\S+)\s+(.+?)\s*$/.exec(line);
3003
+ if (match && !match[3].startsWith("Z")) {
3004
+ const pid = Number(match[1]);
3005
+ if (Number.isSafeInteger(pid) && pid > 1 && pid !== process.pid) table.set(pid, {
3006
+ pid,
3007
+ parentPid: Number(match[2]),
3008
+ birth: match[4]
3009
+ });
3010
+ }
3011
+ }
3012
+ return table;
3013
+ }
3014
+ function includeDescendants(table, owned) {
3015
+ let expanded;
3016
+ do {
3017
+ expanded = false;
3018
+ for (const identity of table.values()) if (owned.has(identity.parentPid) && !owned.has(identity.pid)) {
3019
+ owned.add(identity.pid);
3020
+ expanded = true;
3021
+ }
3022
+ } while (expanded);
3023
+ }
3024
+ /** Best-effort POSIX cleanup for descendants witnessed during this child launch. */
3025
+ var ProcessDescendants = class {
3026
+ child;
3027
+ identities = /* @__PURE__ */ new Map();
3028
+ pending;
3029
+ retired = false;
3030
+ constructor(child) {
3031
+ this.child = child;
3032
+ }
3033
+ capture(timeoutMs = PROCESS_HELPER_TIMEOUT_MS) {
3034
+ if (this.retired || process.platform === "win32") return Promise.resolve(true);
3035
+ this.pending ??= this.readSnapshot(timeoutMs).finally(() => {
3036
+ this.pending = void 0;
3037
+ });
3038
+ return this.pending;
3039
+ }
3040
+ async readSnapshot(timeoutMs) {
3041
+ try {
3042
+ const output = await runTimedExecFile("ps", ["-eo", "pid=,ppid=,stat=,lstart="], { timeoutMs });
3043
+ if (!this.retired) this.refresh(parseProcessTable(output));
3044
+ return true;
3045
+ } catch {
3046
+ return false;
3047
+ }
3048
+ }
3049
+ refresh(table) {
3050
+ const owned = /* @__PURE__ */ new Set();
3051
+ for (const [pid, identity] of this.identities) if (table.get(pid)?.birth === identity.birth) owned.add(pid);
3052
+ const root = this.child.pid;
3053
+ if (root && isChildProcessRunning(this.child)) owned.add(root);
3054
+ includeDescendants(table, owned);
3055
+ owned.delete(root ?? 0);
3056
+ this.identities = new Map([...table].filter(([pid]) => owned.has(pid)));
3057
+ }
3058
+ async signal(signal, timeoutMs) {
3059
+ if (!await this.capture(timeoutMs) || this.retired) return;
3060
+ for (const pid of this.identities.keys()) try {
3061
+ process.kill(pid, signal);
3062
+ } catch {
3063
+ this.identities.delete(pid);
3064
+ }
3065
+ }
3066
+ async waitForExit(timeoutMs) {
3067
+ const deadline = Date.now() + timeoutMs;
3068
+ do {
3069
+ if (!await this.capture(Math.max(1, deadline - Date.now()))) return false;
3070
+ if (this.identities.size === 0) return true;
3071
+ await setTimeout$1(Math.min(100, Math.max(0, deadline - Date.now())));
3072
+ } while (Date.now() < deadline);
3073
+ return false;
3074
+ }
3075
+ retire() {
3076
+ this.retired = true;
3077
+ this.identities.clear();
3078
+ }
3079
+ };
3080
+ //#endregion
3416
3081
  //#region src/acp/session-control-errors.ts
3417
3082
  const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
3418
3083
  function asRecord$1(value) {
@@ -3469,6 +3134,13 @@ function buildTerminalSpawnOptions(command, cwd, env, platform = process.platfor
3469
3134
  windowsHide: true
3470
3135
  }, platform, resolvedEnv ?? process.env);
3471
3136
  }
3137
+ function readTerminalOutputCeiling() {
3138
+ const raw = process.env.ACPX_TERMINAL_MAX_OUTPUT_BYTES?.trim();
3139
+ if (!raw) return;
3140
+ const bytes = Number(raw);
3141
+ if (!/^\d+$/.test(raw) || !Number.isSafeInteger(bytes)) throw new Error("ACPX_TERMINAL_MAX_OUTPUT_BYTES must be a non-negative safe integer; zero disables the host ceiling");
3142
+ return bytes === 0 ? void 0 : bytes;
3143
+ }
3472
3144
  function trimToUtf8Boundary(buffer, limit) {
3473
3145
  if (limit <= 0) return Buffer.alloc(0);
3474
3146
  if (buffer.length <= limit) return buffer;
@@ -3477,20 +3149,6 @@ function trimToUtf8Boundary(buffer, limit) {
3477
3149
  if (start >= buffer.length) start = buffer.length - limit;
3478
3150
  return buffer.subarray(start);
3479
3151
  }
3480
- function waitForSpawn(process) {
3481
- return new Promise((resolve, reject) => {
3482
- const onSpawn = () => {
3483
- process.off("error", onError);
3484
- resolve();
3485
- };
3486
- const onError = (error) => {
3487
- process.off("spawn", onSpawn);
3488
- reject(error);
3489
- };
3490
- process.once("spawn", onSpawn);
3491
- process.once("error", onError);
3492
- });
3493
- }
3494
3152
  async function defaultConfirmExecute(commandLine) {
3495
3153
  return await promptForPermission({ prompt: `\n[permission] Allow terminal command "${commandLine}"? (y/N) ` });
3496
3154
  }
@@ -3512,8 +3170,10 @@ var TerminalManager = class {
3512
3170
  confirmExecute;
3513
3171
  killGraceMs;
3514
3172
  processHelperTimeoutMs;
3173
+ outputCeilingBytes;
3515
3174
  terminals = /* @__PURE__ */ new Map();
3516
3175
  constructor(options) {
3176
+ this.outputCeilingBytes = readTerminalOutputCeiling();
3517
3177
  this.cwd = options.cwd;
3518
3178
  this.permissionMode = options.permissionMode;
3519
3179
  this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
@@ -3538,7 +3198,8 @@ var TerminalManager = class {
3538
3198
  });
3539
3199
  try {
3540
3200
  if (!await this.isExecuteApproved(commandLine)) throw new PermissionDeniedError("Permission denied for terminal/create");
3541
- const outputByteLimit = Math.max(0, Math.round(params.outputByteLimit ?? DEFAULT_TERMINAL_OUTPUT_LIMIT_BYTES));
3201
+ const requestedLimit = Math.max(0, Math.round(params.outputByteLimit ?? DEFAULT_TERMINAL_OUTPUT_LIMIT_BYTES));
3202
+ const outputByteLimit = Math.min(requestedLimit, this.outputCeilingBytes ?? Number.POSITIVE_INFINITY);
3542
3203
  const { proc, spawnCommand } = await spawnTerminalProcess(params, this.cwd);
3543
3204
  let resolveExit = () => {};
3544
3205
  const exitPromise = new Promise((resolve) => {
@@ -3902,11 +3563,12 @@ async function runProcessGroupListCommand(timeoutMs) {
3902
3563
  return await runTimedExecFile("ps", ["-eo", "pid=,pgid="], { timeoutMs });
3903
3564
  }
3904
3565
  async function runWindowsProcessListCommand(timeoutMs) {
3566
+ const command = ["Get-CimInstance Win32_Process |", "ForEach-Object { \"$($_.ProcessId) $($_.ParentProcessId)\" }"].join(" ");
3905
3567
  return await runTimedExecFile("powershell.exe", [
3906
3568
  "-NoProfile",
3907
3569
  "-NonInteractive",
3908
3570
  "-Command",
3909
- ["Get-CimInstance Win32_Process |", "ForEach-Object { \"$($_.ProcessId) $($_.ParentProcessId)\" }"].join(" ")
3571
+ command
3910
3572
  ], {
3911
3573
  timeoutMs,
3912
3574
  windowsHide: true
@@ -3959,10 +3621,8 @@ const REPLAY_DRAIN_TIMEOUT_MS = 5e3;
3959
3621
  const DRAIN_POLL_INTERVAL_MS = 20;
3960
3622
  const AGENT_CLOSE_TERM_GRACE_MS = 1500;
3961
3623
  const AGENT_CLOSE_KILL_GRACE_MS = 1e3;
3624
+ const AGENT_CLEANUP_BUDGET_MS = 8e3;
3962
3625
  const STARTUP_STDERR_MAX_CHARS = 8192;
3963
- const DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META = Object.freeze({ "cognition.ai/requestDiagnostics": true });
3964
- const DEVIN_COMPATIBILITY_CLIENT_NAME = "windsurf";
3965
- const DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION = "1.110.1";
3966
3626
  const ELICITATION_CANCEL_MESSAGES = {
3967
3627
  inactive: "elicitation owner is no longer active",
3968
3628
  unavailable: "elicitation handler is unavailable",
@@ -3971,16 +3631,6 @@ const ELICITATION_CANCEL_MESSAGES = {
3971
3631
  cancelled: "elicitation request was cancelled",
3972
3632
  requestScoped: "request-scoped elicitation has no owner"
3973
3633
  };
3974
- function resolveClientInfo(devinAcp) {
3975
- if (!devinAcp) return {
3976
- name: "acpx",
3977
- version: getAcpxVersion()
3978
- };
3979
- return {
3980
- name: DEVIN_COMPATIBILITY_CLIENT_NAME,
3981
- version: process.env.ACPX_DEVIN_WINDSURF_VERSION ?? DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION
3982
- };
3983
- }
3984
3634
  function normalizeElicitationModes(modes) {
3985
3635
  return [...new Set((modes ?? []).filter((mode) => mode === "form" || mode === "url"))];
3986
3636
  }
@@ -4003,72 +3653,18 @@ function elicitationRequestScopeId(request) {
4003
3653
  const value = request.requestId;
4004
3654
  return value === null || typeof value === "string" || typeof value === "number" ? value : void 0;
4005
3655
  }
4006
- function waitForAbort(signal) {
4007
- if (signal.aborted) return Promise.resolve({ kind: "aborted" });
4008
- return new Promise((resolve) => {
4009
- signal.addEventListener("abort", () => resolve({ kind: "aborted" }), { once: true });
3656
+ async function raceWithAbort(signal, pending) {
3657
+ let onAbort;
3658
+ const aborted = new Promise((resolve) => {
3659
+ onAbort = () => resolve(void 0);
3660
+ if (signal.aborted) onAbort();
3661
+ else signal.addEventListener("abort", onAbort, { once: true });
4010
3662
  });
4011
- }
4012
- function isExtensionNotification(message) {
4013
- if (!("method" in message) || "id" in message || typeof message.method !== "string") return false;
4014
- return message.method !== methods.client.session.update && message.method !== methods.client.elicitation.complete && message.method !== methods.protocol.cancelRequest;
4015
- }
4016
- function elicitationRequestId(message) {
4017
- if (!("method" in message) || message.method !== methods.client.elicitation.create || !("id" in message)) return;
4018
- return message.id;
4019
- }
4020
- function responseId(message) {
4021
- if (!("id" in message) || "method" in message) return;
4022
- return message.id;
4023
- }
4024
- function promptRequestOwner(message) {
4025
- if (!("method" in message) || message.method !== methods.agent.session.prompt || !("id" in message)) return;
4026
- const sessionId = message.params?.sessionId;
4027
- return typeof sessionId === "string" ? {
4028
- requestId: message.id,
4029
- sessionId
4030
- } : void 0;
4031
- }
4032
- function createAgentConnectionFacade(connection) {
4033
- const agent = connection.agent;
4034
- return {
4035
- signal: connection.signal,
4036
- close: (error) => connection.close(error),
4037
- initialize: async (params) => await agent.request(methods.agent.initialize, params),
4038
- authenticate: async (params) => {
4039
- await agent.request(methods.agent.authenticate, params);
4040
- },
4041
- newSession: async (params) => await agent.request(methods.agent.session.new, params),
4042
- loadSession: async (params) => await agent.request(methods.agent.session.load, params),
4043
- resumeSession: async (params) => await agent.request(methods.agent.session.resume, params),
4044
- prompt: async (params) => await agent.request(methods.agent.session.prompt, params),
4045
- setSessionMode: async (params) => await agent.request(methods.agent.session.setMode, params),
4046
- setSessionConfigOption: async (params) => await agent.request(methods.agent.session.setConfigOption, params),
4047
- extMethod: async (method, params) => await agent.request(method, params),
4048
- cancel: async (params) => await agent.notify(methods.agent.session.cancel, params),
4049
- closeSession: async (params) => {
4050
- await agent.request(methods.agent.session.close, params);
4051
- },
4052
- listSessions: async (params) => await agent.request(methods.agent.session.list, params)
4053
- };
4054
- }
4055
- function resolveClientCapabilities(params) {
4056
- const baseCapabilities = {
4057
- fs: {
4058
- readTextFile: params.fs,
4059
- writeTextFile: params.fs
4060
- },
4061
- terminal: params.terminal,
4062
- ...params.elicitationModes.length > 0 ? { elicitation: {
4063
- ...params.elicitationModes.includes("form") ? { form: {} } : {},
4064
- ...params.elicitationModes.includes("url") ? { url: {} } : {}
4065
- } } : {}
4066
- };
4067
- if (!params.devinAcp) return baseCapabilities;
4068
- return {
4069
- ...baseCapabilities,
4070
- _meta: DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META
4071
- };
3663
+ try {
3664
+ return await Promise.race([pending, aborted]);
3665
+ } finally {
3666
+ signal.removeEventListener("abort", onAbort);
3667
+ }
4072
3668
  }
4073
3669
  function hasResponseField(response, field) {
4074
3670
  return !!response && typeof response === "object" && field in response;
@@ -4080,7 +3676,7 @@ function normalizeResponseConfigOptions(response) {
4080
3676
  function toReconnectedSessionResult(response) {
4081
3677
  const configOptions = normalizeResponseConfigOptions(response);
4082
3678
  return {
4083
- agentSessionId: extractRuntimeSessionId(response?._meta),
3679
+ agentSessionId: extractAgentSessionId(response?._meta),
4084
3680
  configOptions,
4085
3681
  models: modelStateFromSessionResponse({
4086
3682
  configOptions,
@@ -4135,6 +3731,8 @@ var AcpClient = class {
4135
3731
  options;
4136
3732
  connection;
4137
3733
  agent;
3734
+ agentDescendants = /* @__PURE__ */ new WeakMap();
3735
+ agentCleanups = /* @__PURE__ */ new WeakMap();
4138
3736
  initResult;
4139
3737
  loadedSessionId;
4140
3738
  eventHandlers;
@@ -4277,6 +3875,7 @@ var AcpClient = class {
4277
3875
  this.logAgentLaunch(launch);
4278
3876
  await this.ensureLaunchSupport(launch);
4279
3877
  const { child, process: startedProcess } = await this.spawnAgentProcess(launch);
3878
+ this.agent = child;
4280
3879
  this.closing = false;
4281
3880
  this.agentStartedAt = startedProcess.startedAt;
4282
3881
  this.lastAgentExit = void 0;
@@ -4301,11 +3900,11 @@ var AcpClient = class {
4301
3900
  let connection;
4302
3901
  const stream = this.createTappedStream(createNdJsonMessageStream(this.options.agentCommand, input, output, maxMessageBytes, (error) => {
4303
3902
  this.rejectPendingConnectionRequests(error);
4304
- connection?.close?.(error);
3903
+ connection?.close(error);
4305
3904
  }));
4306
3905
  connection = this.createConnection(stream, launch);
4307
3906
  connection.signal.addEventListener("abort", () => {
4308
- this.recordAgentExit("connection_close", child.exitCode ?? null, child.signalCode ?? null);
3907
+ this.recordAgentExit(child, "connection_close", child.exitCode ?? null, child.signalCode ?? null);
4309
3908
  }, { once: true });
4310
3909
  await this.initializeAgentConnection({
4311
3910
  child,
@@ -4370,13 +3969,14 @@ var AcpClient = class {
4370
3969
  ...plan.spawnOptions,
4371
3970
  windowsVerbatimArguments: spawnCommand.windowsVerbatimArguments
4372
3971
  });
4373
- await waitForSpawn$1(spawnedChild);
3972
+ await waitForSpawn(spawnedChild);
4374
3973
  } catch (error) {
4375
3974
  const spawnError = new AgentSpawnError(this.options.agentCommand, error);
4376
3975
  this.notifyProcessSpawnFailure(launch, spawnError);
4377
3976
  throw spawnError;
4378
3977
  }
4379
3978
  const child = requireAgentStdio(spawnedChild);
3979
+ this.agentDescendants.set(child, new ProcessDescendants(child));
4380
3980
  const pid = child.pid;
4381
3981
  if (pid === void 0) {
4382
3982
  const spawnError = new AgentSpawnError(this.options.agentCommand, /* @__PURE__ */ new Error("spawned agent process did not expose a PID"));
@@ -4389,7 +3989,7 @@ var AcpClient = class {
4389
3989
  process: Object.freeze({
4390
3990
  ...launch,
4391
3991
  pid,
4392
- startedAt: isoNow$1()
3992
+ startedAt: isoNow$2()
4393
3993
  })
4394
3994
  };
4395
3995
  }
@@ -4422,34 +4022,34 @@ var AcpClient = class {
4422
4022
  }).onRequest(methods.client.terminal.create, async ({ params }) => {
4423
4023
  return await this.handleCreateTerminal(params);
4424
4024
  }).onRequest(methods.client.terminal.output, async ({ params }) => {
4425
- return await this.handleTerminalOutput(params);
4025
+ return await this.terminalManager.terminalOutput(params);
4426
4026
  }).onRequest(methods.client.terminal.waitForExit, async ({ params }) => {
4427
- return await this.handleWaitForTerminalExit(params);
4027
+ return await this.terminalManager.waitForTerminalExit(params);
4428
4028
  }).onRequest(methods.client.terminal.kill, async ({ params }) => {
4429
- return await this.handleKillTerminal(params);
4029
+ return await this.terminalManager.killTerminal(params);
4430
4030
  }).onRequest(methods.client.terminal.release, async ({ params }) => {
4431
- return await this.handleReleaseTerminal(params);
4031
+ return await this.terminalManager.releaseTerminal(params);
4432
4032
  });
4433
4033
  if (launch.devinAcp) app.onRequest("_cognition.ai/request_diagnostics", (params) => {
4434
4034
  return params && typeof params === "object" && !Array.isArray(params) ? params : {};
4435
4035
  }, async () => ({}));
4436
- return createAgentConnectionFacade(app.connect(stream));
4036
+ return app.connect(stream);
4437
4037
  }
4438
4038
  async initializeAgentConnection(params) {
4439
4039
  try {
4440
4040
  const initResult = await Promise.race([this.initializeProtocolConnection(params.connection, params.launch), params.startupFailure.promise]);
4441
4041
  params.startupFailure.dispose();
4442
4042
  this.connection = params.connection;
4443
- this.agent = params.child;
4444
4043
  this.initResult = initResult;
4044
+ await this.captureAgentDescendants(params.child);
4445
4045
  this.log(`initialized protocol version ${initResult.protocolVersion}`);
4446
4046
  } catch (error) {
4447
- params.connection.close?.(error);
4047
+ params.connection.close(error);
4448
4048
  await this.handleInitializeFailure(params, error);
4449
4049
  }
4450
4050
  }
4451
4051
  async initializeProtocolConnection(connection, launch) {
4452
- const initializePromise = connection.initialize({
4052
+ const initializePromise = connection.agent.request(methods.agent.initialize, {
4453
4053
  protocolVersion: PROTOCOL_VERSION,
4454
4054
  clientCapabilities: resolveClientCapabilities({
4455
4055
  devinAcp: launch.devinAcp,
@@ -4465,10 +4065,9 @@ var AcpClient = class {
4465
4065
  }
4466
4066
  async handleInitializeFailure(params, error) {
4467
4067
  params.startupFailure.dispose();
4068
+ await this.captureAgentDescendants(params.child);
4468
4069
  const normalizedError = error instanceof AcpMessageLimitError ? error : await this.normalizeInitializeError(error, params.child, params.startupStderr);
4469
- try {
4470
- params.child.kill();
4471
- } catch {}
4070
+ await this.terminateAgentProcess(params.child);
4472
4071
  if (params.launch.geminiAcp && error instanceof TimeoutError) throw new GeminiAcpStartupTimeoutError(await buildGeminiAcpStartupTimeoutMessage(params.launch.spawnCommand), {
4473
4072
  cause: error,
4474
4073
  retryable: true
@@ -4476,59 +4075,15 @@ var AcpClient = class {
4476
4075
  throw normalizedError;
4477
4076
  }
4478
4077
  createTappedStream(base) {
4479
- const onAcpMessage = () => this.eventHandlers.onAcpMessage;
4480
- const onAcpOutputMessage = () => this.eventHandlers.onAcpOutputMessage;
4481
- const elicitationRequestIds = /* @__PURE__ */ new Set();
4482
- const bindPromptOwner = (owner) => this.bindPromptOwner(owner);
4483
- const onPromptRequestWritten = (active, owner) => this.onPromptRequestWritten(active, owner);
4484
- const shouldSuppressInboundReplaySessionUpdate = (message) => {
4485
- return this.suppressReplaySessionUpdateMessages && isSessionUpdateNotification(message);
4486
- };
4487
- const observeInbound = (message) => {
4488
- const requestId = elicitationRequestId(message);
4489
- if (requestId !== void 0) {
4490
- elicitationRequestIds.add(requestId);
4491
- return;
4492
- }
4493
- if (!shouldSuppressInboundReplaySessionUpdate(message)) {
4494
- onAcpOutputMessage()?.("inbound", message);
4495
- onAcpMessage()?.("inbound", message);
4496
- }
4497
- };
4498
- return {
4499
- readable: new ReadableStream({ async start(controller) {
4500
- const reader = base.readable.getReader();
4501
- try {
4502
- while (true) {
4503
- const { value, done } = await reader.read();
4504
- if (done) break;
4505
- if (!value) continue;
4506
- observeInbound(value);
4507
- if (isExtensionNotification(value)) continue;
4508
- controller.enqueue(value);
4509
- }
4510
- } finally {
4511
- reader.releaseLock();
4512
- controller.close();
4513
- }
4514
- } }),
4515
- writable: new WritableStream({ async write(message) {
4516
- const promptOwner = promptRequestOwner(message);
4517
- const activePrompt = promptOwner ? bindPromptOwner(promptOwner) : void 0;
4518
- const id = responseId(message);
4519
- if (!(id !== void 0 && elicitationRequestIds.delete(id))) {
4520
- onAcpOutputMessage()?.("outbound", message);
4521
- onAcpMessage()?.("outbound", message);
4522
- }
4523
- const writer = base.writable.getWriter();
4524
- try {
4525
- await writer.write(message);
4526
- } finally {
4527
- writer.releaseLock();
4528
- }
4529
- if (activePrompt && promptOwner) onPromptRequestWritten(activePrompt, promptOwner);
4530
- } })
4531
- };
4078
+ return observeAcpStream(base, {
4079
+ onMessage: (direction, message) => {
4080
+ this.eventHandlers.onAcpOutputMessage?.(direction, message);
4081
+ this.eventHandlers.onAcpMessage?.(direction, message);
4082
+ },
4083
+ suppressReplaySessionUpdates: () => this.suppressReplaySessionUpdateMessages,
4084
+ bindPromptOwner: (owner) => this.bindPromptOwner(owner),
4085
+ onPromptRequestWritten: (active, owner) => this.onPromptRequestWritten(active, owner)
4086
+ });
4532
4087
  }
4533
4088
  async createSession(cwd = this.options.cwd) {
4534
4089
  const connection = this.getConnection();
@@ -4537,7 +4092,7 @@ var AcpClient = class {
4537
4092
  const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
4538
4093
  let result;
4539
4094
  try {
4540
- const createPromise = this.runConnectionRequest(() => connection.newSession({
4095
+ const createPromise = this.runConnectionRequest(() => connection.agent.request(methods.agent.session.new, {
4541
4096
  cwd: sessionCwd,
4542
4097
  mcpServers: this.options.mcpServers ?? [],
4543
4098
  _meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions, claudeAcp)
@@ -4557,9 +4112,10 @@ var AcpClient = class {
4557
4112
  response: result
4558
4113
  });
4559
4114
  this.rememberSessionModels(result.sessionId, models);
4115
+ await this.captureAgentDescendants(this.agent);
4560
4116
  return {
4561
4117
  sessionId: result.sessionId,
4562
- agentSessionId: extractRuntimeSessionId(result._meta),
4118
+ agentSessionId: extractAgentSessionId(result._meta),
4563
4119
  configOptions,
4564
4120
  models,
4565
4121
  configOptionsPresent: hasResponseField(result, "configOptions"),
@@ -4576,7 +4132,7 @@ var AcpClient = class {
4576
4132
  const previousSuppression = this.applySessionUpdateSuppression(Boolean(options.suppressReplayUpdates));
4577
4133
  let response;
4578
4134
  try {
4579
- response = await this.runConnectionRequest(() => connection.loadSession({
4135
+ response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.load, {
4580
4136
  sessionId,
4581
4137
  cwd: sessionCwd,
4582
4138
  mcpServers: this.options.mcpServers ?? []
@@ -4588,12 +4144,13 @@ var AcpClient = class {
4588
4144
  this.loadedSessionId = sessionId;
4589
4145
  const result = toReconnectedSessionResult(response);
4590
4146
  this.updateRememberedSessionModels(sessionId, result);
4147
+ await this.captureAgentDescendants(this.agent);
4591
4148
  return result;
4592
4149
  }
4593
4150
  async resumeSession(sessionId, cwd = this.options.cwd) {
4594
4151
  const connection = this.getConnection();
4595
4152
  const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
4596
- const response = await this.runConnectionRequest(() => connection.resumeSession({
4153
+ const response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.resume, {
4597
4154
  sessionId,
4598
4155
  cwd: sessionCwd,
4599
4156
  mcpServers: this.options.mcpServers ?? []
@@ -4601,6 +4158,7 @@ var AcpClient = class {
4601
4158
  this.loadedSessionId = sessionId;
4602
4159
  const result = toReconnectedSessionResult(response);
4603
4160
  this.updateRememberedSessionModels(sessionId, result);
4161
+ await this.captureAgentDescendants(this.agent);
4604
4162
  return result;
4605
4163
  }
4606
4164
  applySessionUpdateSuppression(enabled) {
@@ -4616,14 +4174,15 @@ var AcpClient = class {
4616
4174
  this.suppressSessionUpdates = previous.suppressSessionUpdates;
4617
4175
  this.suppressReplaySessionUpdateMessages = previous.suppressReplaySessionUpdateMessages;
4618
4176
  }
4619
- async prompt(sessionId, prompt, onRequestWritten, onElicitation) {
4177
+ async prompt(sessionId, prompt, onRequestWritten, onElicitation, onPermissionRequest) {
4620
4178
  const connection = this.getConnection();
4621
4179
  const normalizedPrompt = this.normalizePromptForAgent(prompt);
4622
4180
  const restoreConsoleError = this.options.suppressSdkConsoleErrors ? installSdkConsoleErrorSuppression() : void 0;
4623
- const activePrompt = this.beginActivePrompt(sessionId, onRequestWritten, onElicitation);
4181
+ const previousActivePrompt = this.activePrompt;
4182
+ const activePrompt = this.beginActivePrompt(sessionId, onRequestWritten, onElicitation, onPermissionRequest);
4624
4183
  let promptPromise;
4625
4184
  try {
4626
- promptPromise = this.runConnectionRequest(() => connection.prompt({
4185
+ promptPromise = this.runConnectionRequest(() => connection.agent.request(methods.agent.session.prompt, {
4627
4186
  sessionId,
4628
4187
  prompt: normalizedPrompt
4629
4188
  }));
@@ -4634,6 +4193,7 @@ var AcpClient = class {
4634
4193
  }
4635
4194
  activePrompt.promise = promptPromise;
4636
4195
  try {
4196
+ previousActivePrompt?.elicitationController?.abort();
4637
4197
  return this.returnPromptResponseOrPermissionFailure(sessionId, await promptPromise);
4638
4198
  } catch (error) {
4639
4199
  this.throwPromptPermissionFailureIfPresent(sessionId);
@@ -4641,23 +4201,19 @@ var AcpClient = class {
4641
4201
  } finally {
4642
4202
  restoreConsoleError?.();
4643
4203
  this.clearActivePrompt(activePrompt);
4644
- this.cancellingSessionIds.delete(sessionId);
4645
- this.abortAndDropPermissionSignal(sessionId);
4646
- this.promptPermissionFailures.delete(sessionId);
4647
4204
  }
4648
4205
  }
4649
- beginActivePrompt(sessionId, onRequestWritten, elicitationHandler) {
4650
- const previous = this.activePrompt;
4206
+ beginActivePrompt(sessionId, onRequestWritten, elicitationHandler, permissionHandler) {
4651
4207
  this.cancellingSessionIds.delete(sessionId);
4652
4208
  const active = {
4653
4209
  sessionId,
4654
4210
  onRequestWritten,
4655
4211
  elicitationHandler,
4212
+ permissionHandler,
4656
4213
  elicitationController: new AbortController()
4657
4214
  };
4658
4215
  this.activePrompt = active;
4659
4216
  this.pendingPromptOwners.push(active);
4660
- previous?.elicitationController?.abort();
4661
4217
  return active;
4662
4218
  }
4663
4219
  bindPromptOwner(owner) {
@@ -4674,10 +4230,18 @@ var AcpClient = class {
4674
4230
  } catch {}
4675
4231
  }
4676
4232
  clearActivePrompt(active) {
4677
- if (this.activePrompt === active) this.activePrompt = void 0;
4678
4233
  const pendingIndex = this.pendingPromptOwners.indexOf(active);
4234
+ const clearSession = !this.pendingPromptOwners.some((candidate, index) => index > pendingIndex && candidate.sessionId === active.sessionId);
4235
+ if (this.activePrompt === active) this.activePrompt = void 0;
4679
4236
  if (pendingIndex >= 0) this.pendingPromptOwners.splice(pendingIndex, 1);
4237
+ let permissionController;
4238
+ if (clearSession) {
4239
+ this.cancellingSessionIds.delete(active.sessionId);
4240
+ permissionController = this.takePermissionAbortController(active.sessionId);
4241
+ this.promptPermissionFailures.delete(active.sessionId);
4242
+ }
4680
4243
  active.elicitationController.abort();
4244
+ permissionController?.abort();
4681
4245
  }
4682
4246
  normalizePromptForAgent(prompt) {
4683
4247
  const normalizedPrompt = typeof prompt === "string" ? textPrompt(prompt) : prompt;
@@ -4696,7 +4260,7 @@ var AcpClient = class {
4696
4260
  async setSessionMode(sessionId, modeId) {
4697
4261
  const connection = this.getConnection();
4698
4262
  try {
4699
- await this.runConnectionRequest(() => connection.setSessionMode({
4263
+ await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setMode, {
4700
4264
  sessionId,
4701
4265
  modeId
4702
4266
  }));
@@ -4707,7 +4271,7 @@ var AcpClient = class {
4707
4271
  async setSessionConfigOption(sessionId, configId, value) {
4708
4272
  const connection = this.getConnection();
4709
4273
  try {
4710
- return await this.runConnectionRequest(() => connection.setSessionConfigOption({
4274
+ return await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setConfigOption, {
4711
4275
  sessionId,
4712
4276
  configId,
4713
4277
  value
@@ -4729,7 +4293,7 @@ var AcpClient = class {
4729
4293
  async setSessionModelThroughConfig(sessionId, modelId, configId) {
4730
4294
  const connection = this.getConnection();
4731
4295
  try {
4732
- const response = await this.runConnectionRequest(() => connection.setSessionConfigOption({
4296
+ const response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setConfigOption, {
4733
4297
  sessionId,
4734
4298
  configId,
4735
4299
  value: modelId
@@ -4743,7 +4307,7 @@ var AcpClient = class {
4743
4307
  async setSessionModelThroughLegacyMethod(sessionId, modelId) {
4744
4308
  const connection = this.getConnection();
4745
4309
  try {
4746
- await this.runConnectionRequest(() => connection.extMethod("session/set_model", {
4310
+ await this.runConnectionRequest(() => connection.agent.request("session/set_model", {
4747
4311
  sessionId,
4748
4312
  modelId
4749
4313
  }));
@@ -4791,26 +4355,32 @@ var AcpClient = class {
4791
4355
  }
4792
4356
  async cancel(sessionId) {
4793
4357
  const connection = this.getConnection();
4794
- const active = this.activePrompt;
4795
- if (active?.sessionId === sessionId) {
4358
+ const active = this.activePrompt?.sessionId === sessionId ? this.activePrompt : void 0;
4359
+ const cancellation = active?.cancelPromise ?? this.runConnectionRequest(() => connection.agent.notify(methods.agent.session.cancel, { sessionId })).catch((error) => {
4360
+ if (active?.cancelPromise === cancellation) active.cancelPromise = void 0;
4361
+ throw error;
4362
+ });
4363
+ const permissionController = this.takePermissionAbortController(sessionId);
4364
+ if (active) {
4365
+ active.cancelPromise = cancellation;
4796
4366
  this.cancellingSessionIds.add(sessionId);
4797
4367
  active.elicitationController?.abort();
4798
4368
  } else this.cancellingSessionIds.delete(sessionId);
4799
- this.abortAndDropPermissionSignal(sessionId);
4800
- await this.runConnectionRequest(() => connection.cancel({ sessionId }));
4369
+ permissionController?.abort();
4370
+ await cancellation;
4801
4371
  }
4802
4372
  async closeSession(sessionId) {
4803
4373
  const connection = this.getConnection();
4804
4374
  this.cancellingSessionIds.add(sessionId);
4805
4375
  if (this.activePrompt?.sessionId === sessionId) this.activePrompt.elicitationController?.abort();
4806
- await this.runConnectionRequest(() => connection.closeSession({ sessionId }));
4376
+ await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.close, { sessionId }));
4807
4377
  if (this.loadedSessionId === sessionId) this.loadedSessionId = void 0;
4808
4378
  this.modelConfigIds.delete(sessionId);
4809
4379
  this.legacyModelSessionIds.delete(sessionId);
4810
4380
  }
4811
4381
  async listSessions(params = {}) {
4812
4382
  const connection = this.getConnection();
4813
- return await this.runConnectionRequest(() => connection.listSessions(params));
4383
+ return await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.list, params));
4814
4384
  }
4815
4385
  async requestCancelActivePrompt() {
4816
4386
  const active = this.activePrompt;
@@ -4870,18 +4440,36 @@ var AcpClient = class {
4870
4440
  this.activePrompt?.elicitationController?.abort();
4871
4441
  }
4872
4442
  closeConnection() {
4873
- this.connection?.close?.();
4443
+ this.connection?.close();
4444
+ }
4445
+ async captureAgentDescendants(child) {
4446
+ const descendants = child && this.agentDescendants.get(child);
4447
+ if (descendants && !await descendants.capture()) this.log("could not verify agent descendants; skipping unverified process cleanup");
4448
+ }
4449
+ terminateAgentProcess(child) {
4450
+ let cleanup = this.agentCleanups.get(child);
4451
+ if (!cleanup) {
4452
+ cleanup = Promise.resolve().then(() => this.cleanupAgentProcess(child));
4453
+ this.agentCleanups.set(child, cleanup);
4454
+ }
4455
+ return cleanup;
4874
4456
  }
4875
- async terminateAgentProcess(child) {
4457
+ async cleanupAgentProcess(child) {
4458
+ const descendants = this.agentDescendants.get(child);
4459
+ const deadline = Date.now() + AGENT_CLEANUP_BUDGET_MS;
4876
4460
  const stdinCloseGraceMs = resolveAgentCloseAfterStdinEndMs(this.options.agentCommand);
4877
- this.endAgentStdin(child);
4878
- let exited = await waitForChildExit(child, stdinCloseGraceMs);
4879
- exited = await this.killAgentIfRunning(child, exited, "SIGTERM", AGENT_CLOSE_TERM_GRACE_MS);
4880
- if (!exited) {
4881
- this.log(`agent did not exit after ${AGENT_CLOSE_TERM_GRACE_MS}ms; forcing SIGKILL`);
4882
- exited = await this.killAgentIfRunning(child, exited, "SIGKILL", AGENT_CLOSE_KILL_GRACE_MS);
4461
+ try {
4462
+ if (descendants) await descendants.capture(Math.max(1, deadline - Date.now()));
4463
+ this.endAgentStdin(child);
4464
+ await waitForChildExit(child, Math.min(stdinCloseGraceMs, Math.max(0, deadline - Date.now())));
4465
+ if (!await this.signalAgentAndDescendants(child, "SIGTERM", AGENT_CLOSE_TERM_GRACE_MS, deadline)) {
4466
+ this.log("agent processes did not exit after SIGTERM; forcing SIGKILL");
4467
+ await this.signalAgentAndDescendants(child, "SIGKILL", AGENT_CLOSE_KILL_GRACE_MS, deadline);
4468
+ }
4469
+ } finally {
4470
+ descendants?.retire();
4471
+ this.detachAgentHandles(child, isChildProcessRunning(child));
4883
4472
  }
4884
- this.detachAgentHandles(child, !exited);
4885
4473
  }
4886
4474
  endAgentStdin(child) {
4887
4475
  if (child.stdin.destroyed) return;
@@ -4889,12 +4477,15 @@ var AcpClient = class {
4889
4477
  child.stdin.end();
4890
4478
  } catch {}
4891
4479
  }
4892
- async killAgentIfRunning(child, alreadyExited, signal, waitMs) {
4893
- if (alreadyExited || !isChildProcessRunning(child)) return alreadyExited;
4894
- try {
4480
+ async signalAgentAndDescendants(child, signal, waitMs, deadline) {
4481
+ const descendants = this.agentDescendants.get(child);
4482
+ if (descendants && Date.now() < deadline) await descendants.signal(signal, deadline - Date.now());
4483
+ if (isChildProcessRunning(child)) try {
4895
4484
  child.kill(signal);
4896
4485
  } catch {}
4897
- return await waitForChildExit(child, waitMs);
4486
+ const remaining = Math.min(waitMs, Math.max(0, deadline - Date.now()));
4487
+ const [exited, descendantsExited] = await Promise.all([waitForChildExit(child, remaining), descendants ? descendants.waitForExit(remaining) : Promise.resolve(true)]);
4488
+ return exited && descendantsExited;
4898
4489
  }
4899
4490
  detachAgentHandles(agent, unref) {
4900
4491
  const stdin = agent.stdin;
@@ -5046,7 +4637,7 @@ var AcpClient = class {
5046
4637
  this.log(`agent advertised auth methods [${authMethods.map((m) => m.id).join(", ")}] but no matching credentials found — skipping (agent may handle auth internally)`);
5047
4638
  return;
5048
4639
  }
5049
- await connection.authenticate({ methodId: selected.methodId });
4640
+ await connection.agent.request(methods.agent.authenticate, { methodId: selected.methodId });
5050
4641
  this.log(`authenticated with method ${selected.methodId} (${selected.source})`);
5051
4642
  }
5052
4643
  async handlePermissionRequest(params) {
@@ -5065,7 +4656,7 @@ var AcpClient = class {
5065
4656
  if ("response" in resolved) return resolved.response;
5066
4657
  const { active, handler } = resolved.owner;
5067
4658
  const signal = AbortSignal.any([requestSignal, active.elicitationController.signal]);
5068
- const handlerAttempt = Promise.resolve().then(async () => await handler(request, {
4659
+ const outcome = await raceWithAbort(signal, Promise.resolve().then(async () => await handler(request, {
5069
4660
  requestId,
5070
4661
  signal
5071
4662
  })).then((response) => ({
@@ -5074,10 +4665,9 @@ var AcpClient = class {
5074
4665
  }), (error) => ({
5075
4666
  kind: "error",
5076
4667
  error
5077
- }));
5078
- const outcome = await Promise.race([handlerAttempt, waitForAbort(signal)]);
4668
+ })));
5079
4669
  if (this.activePrompt !== active) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.inactive);
5080
- if (outcome.kind === "aborted" || signal.aborted) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.cancelled);
4670
+ if (!outcome || signal.aborted) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.cancelled);
5081
4671
  if (outcome.kind === "error" || !isKnownElicitationResponse(outcome.response)) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.unavailable);
5082
4672
  return outcome.response;
5083
4673
  }
@@ -5104,15 +4694,31 @@ var AcpClient = class {
5104
4694
  isElicitationSessionCancelling(sessionId) {
5105
4695
  return this.closing || this.cancellingSessionIds.has(sessionId);
5106
4696
  }
4697
+ resolvePermissionOwner(sessionId) {
4698
+ const active = this.activePrompt;
4699
+ const handler = active?.permissionHandler ?? this.options.onPermissionRequest;
4700
+ if (!handler) return;
4701
+ const signal = this.cancellationSignalForSession(sessionId);
4702
+ if (!active?.permissionHandler) return {
4703
+ handler,
4704
+ signal
4705
+ };
4706
+ return {
4707
+ handler,
4708
+ signal: active.sessionId === sessionId ? AbortSignal.any([signal, active.elicitationController.signal]) : AbortSignal.abort()
4709
+ };
4710
+ }
5107
4711
  async tryHandlePermissionRequestWithHost(params) {
5108
- if (!this.options.onPermissionRequest) return;
5109
- const signal = this.cancellationSignalForSession(params.sessionId);
4712
+ const owner = this.resolvePermissionOwner(params.sessionId);
4713
+ if (!owner) return;
4714
+ const { handler, signal } = owner;
4715
+ if (signal.aborted) return this.hostPermissionDecisionResponse(params, signal, void 0);
5110
4716
  try {
5111
- const decision = await this.options.onPermissionRequest({
4717
+ const decision = await raceWithAbort(signal, handler({
5112
4718
  sessionId: params.sessionId,
5113
4719
  raw: params,
5114
4720
  inferredKind: inferToolKind(params)
5115
- }, { signal });
4721
+ }, { signal }));
5116
4722
  return this.hostPermissionDecisionResponse(params, signal, decision);
5117
4723
  } catch (error) {
5118
4724
  return this.hostPermissionErrorResponse(params, signal, error);
@@ -5124,9 +4730,9 @@ var AcpClient = class {
5124
4730
  return cancelledPermissionResponse();
5125
4731
  }
5126
4732
  if (!decision) return;
5127
- const response = decisionToResponse(params, decision);
4733
+ const response = decisionToResponse(preferCodexPermissionRefusal(params, this.initResult?.agentInfo?.name), decision);
5128
4734
  this.recordPermissionDecision(classifyPermissionDecision(params, response));
5129
- return response;
4735
+ return decision.outcome === "cancel" ? response : this.explainPermissionRefusal(params, response);
5130
4736
  }
5131
4737
  hostPermissionErrorResponse(params, signal, error) {
5132
4738
  if (signal.aborted || this.cancellingSessionIds.has(params.sessionId)) {
@@ -5137,16 +4743,29 @@ var AcpClient = class {
5137
4743
  }
5138
4744
  async resolvePermissionRequestFromMode(params) {
5139
4745
  try {
5140
- const result = await resolvePermissionRequestWithDetails(params, this.options.permissionMode, this.options.nonInteractivePermissions ?? "deny", this.options.permissionPolicy);
4746
+ const result = await resolvePermissionRequestWithDetails(preferCodexPermissionRefusal(params, this.initResult?.agentInfo?.name), this.options.permissionMode, this.options.nonInteractivePermissions ?? "deny", this.options.permissionPolicy);
5141
4747
  this.emitPermissionEscalation(result.escalation);
5142
4748
  return {
5143
- response: result.response,
4749
+ response: this.explainPermissionRefusal(params, result.response),
5144
4750
  recorded: false
5145
4751
  };
5146
4752
  } catch (error) {
5147
4753
  return this.handleModePermissionError(params.sessionId, error);
5148
4754
  }
5149
4755
  }
4756
+ explainPermissionRefusal(params, response) {
4757
+ const notice = codexPermissionNotice(params, response, this.initResult?.agentInfo?.name);
4758
+ if (!notice || this.cancellingSessionIds.has(params.sessionId)) return response;
4759
+ try {
4760
+ this.eventHandlers.onClientOperation?.({
4761
+ method: "session/request_permission",
4762
+ status: "completed",
4763
+ summary: notice,
4764
+ timestamp: isoNow$2()
4765
+ });
4766
+ } catch {}
4767
+ return withPermissionMetadata(response, { permissionNotice: notice });
4768
+ }
5150
4769
  emitPermissionEscalation(escalation) {
5151
4770
  if (escalation) this.eventHandlers.onPermissionEscalation?.(escalation);
5152
4771
  }
@@ -5161,8 +4780,9 @@ var AcpClient = class {
5161
4780
  }
5162
4781
  attachAgentLifecycleObservers(child, startedProcess, exitNotificationBarrier) {
5163
4782
  const onExit = (exitCode, signal) => {
5164
- const exitedAt = isoNow$1();
5165
- this.recordAgentExit("process_exit", exitCode, signal);
4783
+ const exitedAt = isoNow$2();
4784
+ this.recordAgentExit(child, "process_exit", exitCode, signal);
4785
+ this.terminateAgentProcess(child);
5166
4786
  exitNotificationBarrier.then(() => {
5167
4787
  this.notifyProcessExit(startedProcess, exitCode, signal, exitedAt);
5168
4788
  });
@@ -5173,10 +4793,10 @@ var AcpClient = class {
5173
4793
  onExit(child.exitCode, child.signalCode);
5174
4794
  }
5175
4795
  child.once("close", (exitCode, signal) => {
5176
- this.recordAgentExit("process_close", exitCode, signal);
4796
+ this.recordAgentExit(child, "process_close", exitCode, signal);
5177
4797
  });
5178
4798
  child.stdout.once("close", () => {
5179
- this.recordAgentExit("pipe_close", child.exitCode ?? null, child.signalCode ?? null);
4799
+ this.recordAgentExit(child, "pipe_close", child.exitCode ?? null, child.signalCode ?? null);
5180
4800
  });
5181
4801
  }
5182
4802
  notifyProcessSpawnFailure(launch, error) {
@@ -5185,7 +4805,7 @@ var AcpClient = class {
5185
4805
  const event = Object.freeze({
5186
4806
  ...launch,
5187
4807
  error,
5188
- failedAt: isoNow$1()
4808
+ failedAt: isoNow$2()
5189
4809
  });
5190
4810
  try {
5191
4811
  Promise.resolve(handler(event)).catch((observerError) => {
@@ -5216,12 +4836,12 @@ var AcpClient = class {
5216
4836
  const message = error instanceof Error ? error.message : String(error);
5217
4837
  this.log(`process lifecycle ${hook} hook failed: ${message}`);
5218
4838
  }
5219
- recordAgentExit(reason, exitCode, signal) {
5220
- if (this.lastAgentExit) return;
4839
+ recordAgentExit(child, reason, exitCode, signal) {
4840
+ if (this.agent !== child || this.lastAgentExit) return;
5221
4841
  this.lastAgentExit = {
5222
4842
  exitCode,
5223
4843
  signal,
5224
- exitedAt: isoNow$1(),
4844
+ exitedAt: isoNow$2(),
5225
4845
  reason,
5226
4846
  unexpectedDuringPrompt: !this.closing && Boolean(this.activePrompt)
5227
4847
  };
@@ -5275,6 +4895,7 @@ var AcpClient = class {
5275
4895
  return await this.filesystem.readTextFile(params);
5276
4896
  } catch (error) {
5277
4897
  this.recordPermissionError(params.sessionId, error);
4898
+ if (error instanceof FsSafeError && error.code === "not-found" || error instanceof Error && "code" in error && error.code === "ENOENT") throw RequestError.resourceNotFound(pathToFileURL(params.path).href);
5278
4899
  throw error;
5279
4900
  }
5280
4901
  }
@@ -5294,18 +4915,6 @@ var AcpClient = class {
5294
4915
  throw error;
5295
4916
  }
5296
4917
  }
5297
- async handleTerminalOutput(params) {
5298
- return await this.terminalManager.terminalOutput(params);
5299
- }
5300
- async handleWaitForTerminalExit(params) {
5301
- return await this.terminalManager.waitForTerminalExit(params);
5302
- }
5303
- async handleKillTerminal(params) {
5304
- return await this.terminalManager.killTerminal(params);
5305
- }
5306
- async handleReleaseTerminal(params) {
5307
- return await this.terminalManager.releaseTerminal(params);
5308
- }
5309
4918
  cancellationSignalForSession(sessionId) {
5310
4919
  let controller = this.permissionAbortControllers.get(sessionId);
5311
4920
  if (!controller) {
@@ -5314,12 +4923,10 @@ var AcpClient = class {
5314
4923
  }
5315
4924
  return controller.signal;
5316
4925
  }
5317
- abortAndDropPermissionSignal(sessionId) {
4926
+ takePermissionAbortController(sessionId) {
5318
4927
  const controller = this.permissionAbortControllers.get(sessionId);
5319
- if (controller) {
5320
- controller.abort();
5321
- this.permissionAbortControllers.delete(sessionId);
5322
- }
4928
+ this.permissionAbortControllers.delete(sessionId);
4929
+ return controller;
5323
4930
  }
5324
4931
  recordPermissionDecision(decision) {
5325
4932
  this.permissionStats.requested += 1;
@@ -5382,132 +4989,6 @@ var AcpClient = class {
5382
4989
  }
5383
4990
  };
5384
4991
  //#endregion
5385
- //#region src/runtime/engine/lifecycle.ts
5386
- function applyLifecycleSnapshotToRecord(record, snapshot) {
5387
- if (!snapshot) return;
5388
- record.pid = snapshot.running ? snapshot.pid : void 0;
5389
- record.agentStartedAt = snapshot.startedAt;
5390
- if (snapshot.lastExit) {
5391
- record.lastAgentExitCode = snapshot.lastExit.exitCode;
5392
- record.lastAgentExitSignal = snapshot.lastExit.signal;
5393
- record.lastAgentExitAt = snapshot.lastExit.exitedAt;
5394
- record.lastAgentDisconnectReason = snapshot.lastExit.reason;
5395
- return;
5396
- }
5397
- record.lastAgentExitCode = void 0;
5398
- record.lastAgentExitSignal = void 0;
5399
- record.lastAgentExitAt = void 0;
5400
- record.lastAgentDisconnectReason = void 0;
5401
- }
5402
- function reconcileAgentSessionId(record, agentSessionId) {
5403
- const normalized = normalizeRuntimeSessionId(agentSessionId);
5404
- if (!normalized) return;
5405
- record.agentSessionId = normalized;
5406
- }
5407
- function sessionHasAgentMessages(recordOrConversation) {
5408
- return recordOrConversation.messages.some((message) => typeof message === "object" && message !== null && "Agent" in message);
5409
- }
5410
- function applyConversation(record, conversation) {
5411
- record.title = conversation.title;
5412
- record.updated_at = conversation.updated_at;
5413
- record.messages = conversation.messages;
5414
- record.cumulative_token_usage = conversation.cumulative_token_usage;
5415
- record.cumulative_cost = conversation.cumulative_cost;
5416
- record.request_token_usage = conversation.request_token_usage;
5417
- }
5418
- //#endregion
5419
- //#region src/runtime/engine/session-options.ts
5420
- function mergeSessionOptions(preferred, fallback) {
5421
- const merged = { ...fallback };
5422
- assignDefinedOption(merged, "model", preferred?.model);
5423
- assignDefinedOption(merged, "allowedTools", preferred?.allowedTools);
5424
- assignDefinedOption(merged, "maxTurns", preferred?.maxTurns);
5425
- assignDefinedOption(merged, "systemPrompt", preferred?.systemPrompt);
5426
- assignDefinedOption(merged, "env", mergeEnvRecords(fallback?.env, preferred?.env));
5427
- return Object.keys(merged).length > 0 ? merged : void 0;
5428
- }
5429
- function mergeEnvRecords(fallback, preferred) {
5430
- if (!fallback && !preferred) return;
5431
- return {
5432
- ...fallback,
5433
- ...preferred
5434
- };
5435
- }
5436
- function assignDefinedOption(target, key, value) {
5437
- if (value !== void 0) target[key] = value;
5438
- }
5439
- function persistSessionOptions(record, options) {
5440
- const next = options === void 0 ? void 0 : persistedSessionOptions(options);
5441
- if (next !== void 0) {
5442
- record.acpx = {
5443
- ...record.acpx,
5444
- session_options: next
5445
- };
5446
- return;
5447
- }
5448
- if (!record.acpx) return;
5449
- delete record.acpx.session_options;
5450
- }
5451
- function sessionOptionsFromRecord(record) {
5452
- const stored = record.acpx?.session_options;
5453
- if (!stored) return;
5454
- const sessionOptions = {};
5455
- assignStoredOption(sessionOptions, "model", nonEmptyString(stored.model));
5456
- assignStoredOption(sessionOptions, "allowedTools", storedAllowedTools(stored.allowed_tools));
5457
- assignStoredOption(sessionOptions, "maxTurns", storedMaxTurns(stored.max_turns));
5458
- assignStoredOption(sessionOptions, "systemPrompt", storedSystemPromptOption(stored.system_prompt));
5459
- assignStoredOption(sessionOptions, "env", storedEnvRecord(stored.env));
5460
- return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
5461
- }
5462
- function persistedSessionOptions(options) {
5463
- const next = {
5464
- model: nonEmptyString(options.model),
5465
- allowed_tools: Array.isArray(options.allowedTools) ? [...options.allowedTools] : void 0,
5466
- max_turns: typeof options.maxTurns === "number" ? options.maxTurns : void 0,
5467
- system_prompt: normalizeSystemPromptOption(options.systemPrompt),
5468
- env: storedEnvRecord(options.env)
5469
- };
5470
- return hasPersistedSessionOptions(next) ? next : void 0;
5471
- }
5472
- function hasPersistedSessionOptions(options) {
5473
- return options.model !== void 0 || options.allowed_tools !== void 0 || options.max_turns !== void 0 || options.system_prompt !== void 0 || options.env !== void 0;
5474
- }
5475
- function storedEnvRecord(value) {
5476
- if (value === null || typeof value !== "object" || Array.isArray(value)) return;
5477
- const entries = Object.entries(value);
5478
- const result = {};
5479
- for (const [key, raw] of entries) {
5480
- if (typeof raw !== "string") continue;
5481
- result[key] = raw;
5482
- }
5483
- return Object.keys(result).length > 0 ? result : void 0;
5484
- }
5485
- function normalizeSystemPromptOption(value) {
5486
- const prompt = nonEmptyString(value);
5487
- if (prompt !== void 0) return prompt;
5488
- const append = appendedSystemPrompt(value);
5489
- return append === void 0 ? void 0 : { append };
5490
- }
5491
- function appendedSystemPrompt(value) {
5492
- if (typeof value !== "object" || value === null || Array.isArray(value)) return;
5493
- return nonEmptyString(value.append);
5494
- }
5495
- function assignStoredOption(target, key, value) {
5496
- assignDefinedOption(target, key, value);
5497
- }
5498
- function storedAllowedTools(value) {
5499
- return Array.isArray(value) && value.every((item) => typeof item === "string") ? [...value] : void 0;
5500
- }
5501
- function storedMaxTurns(value) {
5502
- return typeof value === "number" ? value : void 0;
5503
- }
5504
- function storedSystemPromptOption(value) {
5505
- return normalizeSystemPromptOption(value);
5506
- }
5507
- function nonEmptyString(value) {
5508
- return typeof value === "string" && value.trim().length > 0 ? value : void 0;
5509
- }
5510
- //#endregion
5511
4992
  //#region src/session/model-state.ts
5512
4993
  function configOptionsAreAuthoritative(state) {
5513
4994
  return state.model_control === "config_option";
@@ -5518,7 +4999,7 @@ function legacyModelState(state) {
5518
4999
  currentModelId: state.current_model_id ?? "",
5519
5000
  availableModels: state.available_models.map((modelId) => ({
5520
5001
  modelId,
5521
- name: modelId
5002
+ name: state.available_model_names && Object.hasOwn(state.available_model_names, modelId) ? state.available_model_names[modelId] : modelId
5522
5003
  }))
5523
5004
  };
5524
5005
  }
@@ -5532,11 +5013,13 @@ function advertisedModelState(state) {
5532
5013
  function applyAdvertisedModelState(state, models) {
5533
5014
  state.current_model_id = models.currentModelId;
5534
5015
  state.available_models = models.availableModels.map((model) => model.modelId);
5016
+ state.available_model_names = Object.fromEntries(models.availableModels.map((model) => [model.modelId, model.name]));
5535
5017
  state.model_control = models.configId ? "config_option" : "legacy_set_model";
5536
5018
  }
5537
5019
  function clearAdvertisedModelState(state) {
5538
5020
  delete state.current_model_id;
5539
5021
  delete state.available_models;
5022
+ delete state.available_model_names;
5540
5023
  delete state.model_control;
5541
5024
  }
5542
5025
  function removeModelConfigOptions(state) {
@@ -5890,6 +5373,7 @@ function cloneSessionAcpxState(state) {
5890
5373
  desired_config_options: state.desired_config_options ? { ...state.desired_config_options } : void 0,
5891
5374
  current_model_id: state.current_model_id,
5892
5375
  available_models: state.available_models ? [...state.available_models] : void 0,
5376
+ ...state.available_model_names ? { available_model_names: { ...state.available_model_names } } : {},
5893
5377
  model_control: state.model_control,
5894
5378
  available_commands: state.available_commands ? state.available_commands.map((command) => ({ ...command })) : void 0,
5895
5379
  config_options: state.config_options ? deepClone(state.config_options) : void 0,
@@ -5909,10 +5393,10 @@ function cloneSessionOptions(options) {
5909
5393
  function cloneSystemPromptOption(option) {
5910
5394
  return typeof option === "string" ? option : { append: option.append };
5911
5395
  }
5912
- function recordPromptSubmission(conversation, prompt, timestamp = isoNow()) {
5396
+ function recordPromptSubmission(conversation, prompt, timestamp = isoNow(), messageId) {
5913
5397
  const userContent = (typeof prompt === "string" ? textPrompt(prompt) : prompt).map((content) => contentToUserContent(content)).filter((content) => content !== void 0);
5914
5398
  if (userContent.length === 0) return;
5915
- const promptMessageId = nextUserMessageId();
5399
+ const promptMessageId = messageId ?? nextUserMessageId();
5916
5400
  conversation.messages.push({ User: {
5917
5401
  id: promptMessageId,
5918
5402
  content: userContent.map((content) => {
@@ -5938,10 +5422,10 @@ function hasAgentReplyAfterPrompt(conversation, promptMessageId) {
5938
5422
  }
5939
5423
  return false;
5940
5424
  }
5941
- function recordSessionUpdate(conversation, state, notification, timestamp = isoNow()) {
5425
+ function recordSessionUpdate(conversation, state, notification, timestamp = isoNow(), userMessageId) {
5942
5426
  const acpx = ensureAcpxState$1(state);
5943
5427
  const update = notification.update;
5944
- applySessionUpdate(conversation, acpx, update);
5428
+ applySessionUpdate(conversation, acpx, update, userMessageId);
5945
5429
  updateConversationTimestamp(conversation, timestamp);
5946
5430
  trimConversationForRuntime(conversation);
5947
5431
  return acpx;
@@ -5954,13 +5438,13 @@ function recordPromptResponseUsage(conversation, usage, promptMessageId, timesta
5954
5438
  trimConversationForRuntime(conversation);
5955
5439
  return true;
5956
5440
  }
5957
- function applySessionUpdate(conversation, acpx, update) {
5441
+ function applySessionUpdate(conversation, acpx, update, userMessageId) {
5958
5442
  const handler = SESSION_UPDATE_HANDLERS[update.sessionUpdate];
5959
- handler?.(conversation, acpx, update);
5443
+ handler?.(conversation, acpx, update, userMessageId);
5960
5444
  }
5961
5445
  const SESSION_UPDATE_HANDLERS = {
5962
- user_message_chunk: (conversation, _acpx, update) => {
5963
- if (update.sessionUpdate === "user_message_chunk") appendUserMessageChunk(conversation, update.content);
5446
+ user_message_chunk: (conversation, _acpx, update, userMessageId) => {
5447
+ if (update.sessionUpdate === "user_message_chunk") appendUserMessageChunk(conversation, update.content, userMessageId);
5964
5448
  },
5965
5449
  agent_message_chunk: (conversation, _acpx, update) => {
5966
5450
  if (update.sessionUpdate === "agent_message_chunk") appendAgentMessageChunk(conversation, update.content, appendAgentText);
@@ -5990,11 +5474,11 @@ const SESSION_UPDATE_HANDLERS = {
5990
5474
  if (update.sessionUpdate === "config_option_update") applyConfigOptionsModelState(acpx, deepClone(update.configOptions));
5991
5475
  }
5992
5476
  };
5993
- function appendUserMessageChunk(conversation, content) {
5477
+ function appendUserMessageChunk(conversation, content, messageId) {
5994
5478
  const userContent = contentToUserContent(content);
5995
5479
  if (!userContent) return;
5996
5480
  conversation.messages.push({ User: {
5997
- id: nextUserMessageId(),
5481
+ id: messageId ?? nextUserMessageId(),
5998
5482
  content: [userContent]
5999
5483
  } });
6000
5484
  }
@@ -6018,7 +5502,7 @@ function applySessionInfoUpdate(conversation, update) {
6018
5502
  if (hasOwn(update, "title")) conversation.title = update.title ?? null;
6019
5503
  if (hasOwn(update, "updatedAt")) conversation.updated_at = update.updatedAt ?? conversation.updated_at;
6020
5504
  }
6021
- function recordClientOperation(conversation, state, operation, timestamp = isoNow()) {
5505
+ function recordClientOperation(conversation, state, _operation, timestamp = isoNow()) {
6022
5506
  const acpx = ensureAcpxState$1(state);
6023
5507
  updateConversationTimestamp(conversation, timestamp);
6024
5508
  trimConversationForRuntime(conversation);
@@ -6057,6 +5541,147 @@ function trimRuntimeToolResult(result) {
6057
5541
  if (typeof result.output === "string") result.output = trimRuntimeText(result.output, MAX_RUNTIME_TOOL_IO_CHARS);
6058
5542
  }
6059
5543
  //#endregion
5544
+ //#region src/runtime/engine/lifecycle.ts
5545
+ function createInitialSessionRecord(params) {
5546
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5547
+ return {
5548
+ schema: "acpx.session.v1",
5549
+ acpxRecordId: params.recordId,
5550
+ acpSessionId: params.sessionId,
5551
+ agentSessionId: params.agentSessionId,
5552
+ agentCommand: params.agentCommand,
5553
+ agentArgv: params.agentArgv,
5554
+ cwd: params.cwd,
5555
+ name: params.name,
5556
+ createdAt: now,
5557
+ lastUsedAt: now,
5558
+ lastSeq: 0,
5559
+ eventLog: defaultSessionEventLog(params.recordId),
5560
+ closed: false,
5561
+ closedAt: void 0,
5562
+ ...createSessionConversation(now),
5563
+ acpx: {}
5564
+ };
5565
+ }
5566
+ function applyLifecycleSnapshotToRecord(record, snapshot) {
5567
+ if (!snapshot) return;
5568
+ record.pid = snapshot.running ? snapshot.pid : void 0;
5569
+ record.agentStartedAt = snapshot.startedAt;
5570
+ if (snapshot.lastExit) {
5571
+ record.lastAgentExitCode = snapshot.lastExit.exitCode;
5572
+ record.lastAgentExitSignal = snapshot.lastExit.signal;
5573
+ record.lastAgentExitAt = snapshot.lastExit.exitedAt;
5574
+ record.lastAgentDisconnectReason = snapshot.lastExit.reason;
5575
+ return;
5576
+ }
5577
+ record.lastAgentExitCode = void 0;
5578
+ record.lastAgentExitSignal = void 0;
5579
+ record.lastAgentExitAt = void 0;
5580
+ record.lastAgentDisconnectReason = void 0;
5581
+ }
5582
+ function reconcileAgentSessionId(record, agentSessionId) {
5583
+ const normalized = normalizeAgentSessionId(agentSessionId);
5584
+ if (!normalized) return;
5585
+ record.agentSessionId = normalized;
5586
+ }
5587
+ function sessionHasAgentMessages(recordOrConversation) {
5588
+ return recordOrConversation.messages.some((message) => typeof message === "object" && message !== null && "Agent" in message);
5589
+ }
5590
+ function applyConversation(record, conversation) {
5591
+ record.title = conversation.title;
5592
+ record.updated_at = conversation.updated_at;
5593
+ record.messages = conversation.messages;
5594
+ record.cumulative_token_usage = conversation.cumulative_token_usage;
5595
+ record.cumulative_cost = conversation.cumulative_cost;
5596
+ record.request_token_usage = conversation.request_token_usage;
5597
+ }
5598
+ //#endregion
5599
+ //#region src/runtime/engine/session-options.ts
5600
+ function mergeSessionOptions(preferred, fallback) {
5601
+ const merged = { ...fallback };
5602
+ assignDefinedOption(merged, "model", preferred?.model);
5603
+ assignDefinedOption(merged, "allowedTools", preferred?.allowedTools);
5604
+ assignDefinedOption(merged, "maxTurns", preferred?.maxTurns);
5605
+ assignDefinedOption(merged, "systemPrompt", preferred?.systemPrompt);
5606
+ assignDefinedOption(merged, "env", mergeEnvRecords(fallback?.env, preferred?.env));
5607
+ return Object.keys(merged).length > 0 ? merged : void 0;
5608
+ }
5609
+ function mergeEnvRecords(fallback, preferred) {
5610
+ if (!fallback && !preferred) return;
5611
+ return {
5612
+ ...fallback,
5613
+ ...preferred
5614
+ };
5615
+ }
5616
+ function assignDefinedOption(target, key, value) {
5617
+ if (value !== void 0) target[key] = value;
5618
+ }
5619
+ function persistSessionOptions(record, options) {
5620
+ const next = options === void 0 ? void 0 : persistedSessionOptions(options);
5621
+ if (next !== void 0) {
5622
+ record.acpx = {
5623
+ ...record.acpx,
5624
+ session_options: next
5625
+ };
5626
+ return;
5627
+ }
5628
+ if (!record.acpx) return;
5629
+ delete record.acpx.session_options;
5630
+ }
5631
+ function sessionOptionsFromRecord(record) {
5632
+ const stored = record.acpx?.session_options;
5633
+ if (!stored) return;
5634
+ const sessionOptions = {};
5635
+ assignDefinedOption(sessionOptions, "model", nonEmptyString(stored.model));
5636
+ assignDefinedOption(sessionOptions, "allowedTools", storedAllowedTools(stored.allowed_tools));
5637
+ assignDefinedOption(sessionOptions, "maxTurns", storedMaxTurns(stored.max_turns));
5638
+ assignDefinedOption(sessionOptions, "systemPrompt", normalizeSystemPromptOption(stored.system_prompt));
5639
+ assignDefinedOption(sessionOptions, "env", storedEnvRecord(stored.env));
5640
+ return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
5641
+ }
5642
+ function persistedSessionOptions(options) {
5643
+ const next = {
5644
+ model: nonEmptyString(options.model),
5645
+ allowed_tools: Array.isArray(options.allowedTools) ? [...options.allowedTools] : void 0,
5646
+ max_turns: typeof options.maxTurns === "number" ? options.maxTurns : void 0,
5647
+ system_prompt: normalizeSystemPromptOption(options.systemPrompt),
5648
+ env: storedEnvRecord(options.env)
5649
+ };
5650
+ return hasPersistedSessionOptions(next) ? next : void 0;
5651
+ }
5652
+ function hasPersistedSessionOptions(options) {
5653
+ return options.model !== void 0 || options.allowed_tools !== void 0 || options.max_turns !== void 0 || options.system_prompt !== void 0 || options.env !== void 0;
5654
+ }
5655
+ function storedEnvRecord(value) {
5656
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return;
5657
+ const entries = Object.entries(value);
5658
+ const result = {};
5659
+ for (const [key, raw] of entries) {
5660
+ if (typeof raw !== "string") continue;
5661
+ result[key] = raw;
5662
+ }
5663
+ return Object.keys(result).length > 0 ? result : void 0;
5664
+ }
5665
+ function normalizeSystemPromptOption(value) {
5666
+ const prompt = nonEmptyString(value);
5667
+ if (prompt !== void 0) return prompt;
5668
+ const append = appendedSystemPrompt(value);
5669
+ return append === void 0 ? void 0 : { append };
5670
+ }
5671
+ function appendedSystemPrompt(value) {
5672
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return;
5673
+ return nonEmptyString(value.append);
5674
+ }
5675
+ function storedAllowedTools(value) {
5676
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? [...value] : void 0;
5677
+ }
5678
+ function storedMaxTurns(value) {
5679
+ return typeof value === "number" ? value : void 0;
5680
+ }
5681
+ function nonEmptyString(value) {
5682
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
5683
+ }
5684
+ //#endregion
6060
5685
  //#region src/session/mode-preference.ts
6061
5686
  function ensureAcpxState(state) {
6062
5687
  return state ?? {};
@@ -6147,6 +5772,11 @@ function applyConfigOptionsToRecord(record, result) {
6147
5772
  if (!configOptions) return;
6148
5773
  record.acpx = applyConfigOptionsToState(record.acpx, configOptions);
6149
5774
  }
5775
+ function applyInitialModelSelection(record, originalModels, requestedModel, modelApplication) {
5776
+ applyConfigOptionsToRecord(record, modelApplication.response);
5777
+ syncAdvertisedModelState(record, modelApplication.response ? modelStateFromConfigOptions(modelApplication.response.configOptions) : originalModels);
5778
+ if (modelApplication.applied) setCurrentModelId(record, currentModelIdFromSetModelResponse(modelApplication.response, requestedModel));
5779
+ }
6150
5780
  function applyAcceptedConfigOptions(state, response) {
6151
5781
  const next = cloneSessionAcpxState(state) ?? {};
6152
5782
  if (!response) return next;
@@ -6181,15 +5811,6 @@ function applyConfigOptionSelection(state, configId, value, response, modelConfi
6181
5811
  }
6182
5812
  //#endregion
6183
5813
  //#region src/runtime/engine/reconnect.ts
6184
- function isProcessAlive(pid) {
6185
- if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
6186
- try {
6187
- process.kill(pid, 0);
6188
- return true;
6189
- } catch {
6190
- return false;
6191
- }
6192
- }
6193
5814
  const SESSION_LOAD_UNSUPPORTED_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
6194
5815
  function shouldFallbackToNewSession(error, record) {
6195
5816
  if (isHardReconnectFailure(error)) return false;
@@ -6307,12 +5928,6 @@ async function connectAndLoadSession(options) {
6307
5928
  record.closed = false;
6308
5929
  record.closedAt = void 0;
6309
5930
  options.onConnectedRecord?.(record);
6310
- let resumed = false;
6311
- let loadError;
6312
- let sessionId = record.acpSessionId;
6313
- let createdFreshSession = false;
6314
- let pendingAgentSessionId = record.agentSessionId;
6315
- let sessionModels;
6316
5931
  const loadState = await loadOrCreateRuntimeSession({
6317
5932
  client,
6318
5933
  record,
@@ -6320,12 +5935,7 @@ async function connectAndLoadSession(options) {
6320
5935
  sameSessionOnly,
6321
5936
  timeoutMs: options.timeoutMs
6322
5937
  });
6323
- resumed = loadState.resumed;
6324
- loadError = loadState.loadError;
6325
- sessionId = loadState.sessionId;
6326
- createdFreshSession = loadState.createdFreshSession;
6327
- pendingAgentSessionId = loadState.pendingAgentSessionId;
6328
- sessionModels = loadState.sessionModels;
5938
+ const { resumed, loadError, sessionId, createdFreshSession, pendingAgentSessionId, sessionModels } = loadState;
6329
5939
  const preferenceReplay = await replaySessionPreferences({
6330
5940
  client,
6331
5941
  record,
@@ -6463,35 +6073,17 @@ async function loadOrCreateRuntimeSession(params) {
6463
6073
  resumed: true,
6464
6074
  createdFreshSession: false
6465
6075
  };
6466
- if (params.client.supportsResumeSession()) return await resumeRuntimeSession(params);
6467
- if (params.client.supportsLoadSession()) return await loadRuntimeSession(params);
6076
+ if (params.client.supportsResumeSession()) return await loadRuntimeSession(params, true);
6077
+ if (params.client.supportsLoadSession()) return await loadRuntimeSession(params, false);
6468
6078
  if (params.sameSessionOnly) throw makeSessionResumeRequiredError({
6469
6079
  record: params.record,
6470
6080
  reason: "agent does not support session/resume or session/load"
6471
6081
  });
6472
6082
  return await createFreshRuntimeSession(params.client, params.record, params.timeoutMs);
6473
6083
  }
6474
- async function resumeRuntimeSession(params) {
6475
- try {
6476
- const resumeResult = await withTimeout(params.client.resumeSession(params.record.acpSessionId, params.record.cwd), params.timeoutMs);
6477
- reconcileAgentSessionId(params.record, resumeResult.agentSessionId);
6478
- applyConfigOptionsToRecord(params.record, resumeResult);
6479
- return {
6480
- sessionId: params.record.acpSessionId,
6481
- pendingAgentSessionId: params.record.agentSessionId,
6482
- sessionModels: resumeResult.models,
6483
- configOptionsPresent: resumeResult.configOptionsPresent,
6484
- legacyModelMetadataPresent: resumeResult.legacyModelMetadataPresent,
6485
- resumed: true,
6486
- createdFreshSession: false
6487
- };
6488
- } catch (error) {
6489
- return await recoverRuntimeSessionLoadFailure(params, error);
6490
- }
6491
- }
6492
- async function loadRuntimeSession(params) {
6084
+ async function loadRuntimeSession(params, resume) {
6493
6085
  try {
6494
- const loadResult = await withTimeout(params.client.loadSessionWithOptions(params.record.acpSessionId, params.record.cwd, { suppressReplayUpdates: true }), params.timeoutMs);
6086
+ const loadResult = await withTimeout(resume ? params.client.resumeSession(params.record.acpSessionId, params.record.cwd) : params.client.loadSessionWithOptions(params.record.acpSessionId, params.record.cwd, { suppressReplayUpdates: true }), params.timeoutMs);
6495
6087
  reconcileAgentSessionId(params.record, loadResult.agentSessionId);
6496
6088
  applyConfigOptionsToRecord(params.record, loadResult);
6497
6089
  return {
@@ -6608,7 +6200,7 @@ async function withConnectedSession(options) {
6608
6200
  resumed,
6609
6201
  loadError
6610
6202
  });
6611
- const now = isoNow$2();
6203
+ const now = isoNow$1();
6612
6204
  record.lastUsedAt = now;
6613
6205
  record.closed = false;
6614
6206
  record.closedAt = void 0;
@@ -6629,7 +6221,7 @@ async function withConnectedSession(options) {
6629
6221
  });
6630
6222
  else await client.cancelActivePrompt(2500);
6631
6223
  applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
6632
- record.lastUsedAt = isoNow$2();
6224
+ record.lastUsedAt = isoNow$1();
6633
6225
  await options.saveRecord(record).catch(() => {});
6634
6226
  await client.close();
6635
6227
  });
@@ -6655,10 +6247,13 @@ function recoveredSessionResult(response, conversation, promptMessageId) {
6655
6247
  ...responseMetaField(response?._meta)
6656
6248
  };
6657
6249
  }
6250
+ function abortTimedOutRequests(error, client, sessionId) {
6251
+ if (error instanceof TimeoutError) client.endPromptElicitation?.(sessionId);
6252
+ }
6658
6253
  async function runPromptTurn(params) {
6659
6254
  let settledResponse;
6660
6255
  try {
6661
- const promptPromise = params.client.prompt(params.sessionId, params.prompt, params.onPromptRequestWritten, params.onElicitation);
6256
+ const promptPromise = params.client.prompt(params.sessionId, params.prompt, params.onPromptRequestWritten, params.onElicitation, params.onPermissionRequest);
6662
6257
  promptPromise.then((response) => {
6663
6258
  settledResponse = response;
6664
6259
  }, () => {});
@@ -6675,6 +6270,7 @@ async function runPromptTurn(params) {
6675
6270
  ...responseMetaField(response._meta)
6676
6271
  };
6677
6272
  } catch (error) {
6273
+ abortTimedOutRequests(error, params.client, params.sessionId);
6678
6274
  if (!(error instanceof TimeoutError) || !params.promptMessageId) throw error;
6679
6275
  await params.client.waitForSessionUpdatesIdle?.({
6680
6276
  idleMs: SESSION_REPLY_IDLE_MS,
@@ -6738,6 +6334,6 @@ var LiveSessionCheckpoint = class {
6738
6334
  }
6739
6335
  };
6740
6336
  //#endregion
6741
- export { formatPerfMetric as $, AgentSpawnError as $t, RequestedModelUnsupportedError as A, DEFAULT_AGENT_NAME as At, absolutePath as B, extractAcpError as Bt, sessionOptionsFromRecord as C, parsePromptSource as Ct, AcpClient as D, TimeoutError as Dt, reconcileAgentSessionId as E, InterruptedError as Et, runTimedExecFile as F, resolveCanonicalAgentName as Ft, listSessions as G, NON_INTERACTIVE_PERMISSION_POLICIES as Gt, findSession as H, toAcpErrorPayload as Ht, splitCommandLine as I, exitCodeForOutputErrorCode as It, pruneSessions as J, OUTPUT_FORMATS as Jt, listSessionsForAgent as K, OUTPUT_ERROR_CODES as Kt, getAcpxVersion as L, formatErrorMessage as Lt, modelStateFromConfigOptions as M, normalizeAgentName$1 as Mt, normalizeAgentCommandInput as N, resolveAgentArgv as Nt, REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE as O, withInterrupt as Ot, renderArgvIdentity as P, resolveAgentCommand as Pt, assertPersistedKeyPolicy as Q, AcpxOperationalError as Qt, permissionModeSatisfies as R, isRetryablePromptError as Rt, persistSessionOptions as S, mergePromptSourceWithText as St, applyLifecycleSnapshotToRecord as T, textPrompt as Tt, findSessionByDirectoryWalk as U, AUTH_POLICIES as Ut, findGitRepositoryRoot as V, isAcpResourceNotFoundError as Vt, isoNow$2 as W, EXIT_CODES as Wt, writeSessionRecord as X, PERMISSION_POLICY_ACTIONS as Xt, resolveSessionRecord as Y, PERMISSION_MODES as Yt, createAtomicWriteTempPath as Z, SESSION_RECORD_SCHEMA as Zt, recordPromptSubmission as _, isAcpJsonRpcMessage as _t, applyConfigOptionSelection as a, setPerfGauge as at, advertisedModelState as b, PromptInputValidationError as bt, applyRequestedModelIfAdvertised as c, serializeSessionRecordForDisk as ct, setDesiredModeId as d, defaultSessionEventLog as dt, QueueConnectionError as en, getPerfMetricsSnapshot as et, syncAdvertisedModelState as f, sessionBaseDir$1 as ft, recordClientOperation as g, extractSessionUpdateNotification as gt, createSessionConversation as h, sessionEventSegmentPath as ht, connectAndLoadSession as i, resetPerfMetrics as it, isRequestedModelUnsupportedError as j, listBuiltInAgents as jt, REQUESTED_MODEL_UNSUPPORTED_REASONS as k, withTimeout as kt, currentModelIdFromSetModelResponse as l, normalizeRuntimeSessionId as lt, cloneSessionConversation as m, sessionEventLockPath as mt, runPromptTurn as n, measurePerf as nt, applyConfigOptionsToRecord as o, startPerfTimer as ot, cloneSessionAcpxState as p, sessionEventActivePath as pt, normalizeName as q, OUTPUT_ERROR_ORIGINS as qt, withConnectedSession as r, recordPerfDuration as rt, applyModelSelection as s, parseSessionRecord as st, LiveSessionCheckpoint as t, QueueProtocolError as tn, incrementPerfCounter as tt, setCurrentModelId as u, DEFAULT_EVENT_SEGMENT_MAX_BYTES as ut, recordSessionUpdate as v, parseJsonRpcErrorMessage as vt, applyConversation as w, promptToDisplayText as wt, mergeSessionOptions as x, isPromptInput as xt, trimConversationForRuntime as y, parsePromptStopReason as yt, DEFAULT_HISTORY_LIMIT as z, normalizeOutputError as zt };
6337
+ export { getPerfMetricsSnapshot as $, isRequestedModelUnsupportedError as A, isRetryablePromptError as At, absolutePath as B, OUTPUT_FORMATS as Bt, recordSessionUpdate as C, isLegacyZedCodexAcpInvocation as Ct, REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE as D, withTimeout as Dt, AcpClient as E, withInterrupt as Et, parsePromptSource as F, AUTH_POLICIES as Ft, listSessions as G, AgentSpawnError as Gt, findSession as H, PERMISSION_POLICY_ACTIONS as Ht, promptToDisplayText as I, EXIT_CODES as It, pruneSessions as J, listSessionsForAgent as K, QueueConnectionError as Kt, textPrompt as L, NON_INTERACTIVE_PERMISSION_POLICIES as Lt, PromptInputValidationError as M, extractAcpError as Mt, isPromptInput as N, isAcpResourceNotFoundError as Nt, REQUESTED_MODEL_UNSUPPORTED_REASONS as O, exitCodeForOutputErrorCode as Ot, mergePromptSourceWithText as P, toAcpErrorPayload as Pt, formatPerfMetric as Q, permissionModeSatisfies as R, OUTPUT_ERROR_CODES as Rt, recordPromptSubmission as S, parsePromptStopReason as St, advertisedModelState as T, TimeoutError as Tt, findSessionByDirectoryWalk as U, SESSION_RECORD_SCHEMA as Ut, findGitRepositoryRoot as V, PERMISSION_MODES as Vt, isoNow$1 as W, AcpxOperationalError as Wt, writeSessionRecord as X, resolveSessionRecord as Y, assertPersistedKeyPolicy as Z, reconcileAgentSessionId as _, isProcessAlive as _t, applyConfigOptionSelection as a, startPerfTimer as at, createSessionConversation as b, parseJsonRpcErrorMessage as bt, applyModelSelection as c, normalizeAgentSessionId as ct, mergeSessionOptions as d, sessionBaseDir as dt, incrementPerfCounter as et, persistSessionOptions as f, sessionEventActivePath as ft, createInitialSessionRecord as g, writePrivateJsonFile as gt, applyLifecycleSnapshotToRecord as h, writePrivateFile as ht, connectAndLoadSession as i, setPerfGauge as it, getAcpxVersion as j, normalizeOutputError as jt, RequestedModelUnsupportedError as k, formatErrorMessage as kt, applyRequestedModelIfAdvertised as l, DEFAULT_EVENT_SEGMENT_MAX_BYTES as lt, applyConversation as m, sessionEventSegmentPath as mt, runPromptTurn as n, recordPerfDuration as nt, applyConfigOptionsToRecord as o, parseSessionRecord as ot, sessionOptionsFromRecord as p, sessionEventLockPath as pt, normalizeName as q, QueueProtocolError as qt, withConnectedSession as r, resetPerfMetrics as rt, applyInitialModelSelection as s, serializeSessionRecordForDisk as st, LiveSessionCheckpoint as t, measurePerf as tt, setDesiredModeId as u, defaultSessionEventLog as ut, cloneSessionAcpxState as v, extractSessionUpdateNotification as vt, trimConversationForRuntime as w, InterruptedError as wt, recordClientOperation as x, parsePermissionNotice as xt, cloneSessionConversation as y, isAcpJsonRpcMessage as yt, DEFAULT_HISTORY_LIMIT as z, OUTPUT_ERROR_ORIGINS as zt };
6742
6338
 
6743
- //# sourceMappingURL=live-checkpoint-CYRs-D9t.js.map
6339
+ //# sourceMappingURL=live-checkpoint-BEfxBKCh.js.map