acpx 0.15.1 → 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.
- package/dist/agent-registry-DU6mhZBL.js +785 -0
- package/dist/agent-registry-DU6mhZBL.js.map +1 -0
- package/dist/agent-registry.d.ts +70 -0
- package/dist/agent-registry.d.ts.map +1 -0
- package/dist/agent-registry.js +2 -0
- package/dist/{cli-BHAT_D3V.js → cli-BkYIxj_N.js} +6 -14
- package/dist/cli-BkYIxj_N.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +137 -333
- package/dist/cli.js.map +1 -1
- package/dist/{client-Cvz6msGc.d.ts → client-5levcBIs.d.ts} +11 -9
- package/dist/client-5levcBIs.d.ts.map +1 -0
- package/dist/{flows-BOI1XkMp.js → flows-Bxs4udrs.js} +205 -277
- package/dist/flows-Bxs4udrs.js.map +1 -0
- package/dist/flows.d.ts +6 -17
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{flags-BHcZWTov.js → invocation-options-BY4lxkn3.js} +82 -58
- package/dist/invocation-options-BY4lxkn3.js.map +1 -0
- package/dist/{live-checkpoint-sB7dFOYR.js → live-checkpoint-BEfxBKCh.js} +997 -1412
- package/dist/live-checkpoint-BEfxBKCh.js.map +1 -0
- package/dist/{output-8-D6Gd4Z.js → output-uo5a27KB.js} +487 -490
- package/dist/output-uo5a27KB.js.map +1 -0
- package/dist/runtime.d.ts +105 -22
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +582 -366
- package/dist/runtime.js.map +1 -1
- package/dist/{session-options-DyIGRNfu.d.ts → session-options-t3d-F4dn.d.ts} +8 -6
- package/dist/session-options-t3d-F4dn.d.ts.map +1 -0
- package/package.json +27 -25
- package/skills/acpx/SKILL.md +19 -17
- package/dist/cli-BHAT_D3V.js.map +0 -1
- package/dist/client-Cvz6msGc.d.ts.map +0 -1
- package/dist/flags-BHcZWTov.js.map +0 -1
- package/dist/flows-BOI1XkMp.js.map +0 -1
- package/dist/live-checkpoint-sB7dFOYR.js.map +0 -1
- package/dist/output-8-D6Gd4Z.js.map +0 -1
- 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/
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
return
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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
|
|
701
|
+
return path.join(sessionBaseDir(), `${safeSessionId(sessionId)}.stream.ndjson`);
|
|
999
702
|
}
|
|
1000
703
|
function sessionEventSegmentPath(sessionId, segment) {
|
|
1001
|
-
return path.join(sessionBaseDir
|
|
704
|
+
return path.join(sessionBaseDir(), `${safeSessionId(sessionId)}.stream.${segment}.ndjson`);
|
|
1002
705
|
}
|
|
1003
706
|
function sessionEventLockPath(sessionId) {
|
|
1004
|
-
return path.join(sessionBaseDir
|
|
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:
|
|
1053
|
-
acpx_record_id:
|
|
1054
|
-
acp_session_id:
|
|
1055
|
-
agent_session_id:
|
|
1056
|
-
agent_command:
|
|
1057
|
-
agent_argv:
|
|
1058
|
-
cwd:
|
|
1059
|
-
name:
|
|
1060
|
-
created_at:
|
|
1061
|
-
last_used_at:
|
|
1062
|
-
last_seq:
|
|
1063
|
-
last_request_id:
|
|
1064
|
-
event_log:
|
|
1065
|
-
closed:
|
|
1066
|
-
closed_at:
|
|
1067
|
-
pid:
|
|
1068
|
-
agent_started_at:
|
|
1069
|
-
last_prompt_at:
|
|
1070
|
-
last_agent_exit_code:
|
|
1071
|
-
last_agent_exit_signal:
|
|
1072
|
-
last_agent_exit_at:
|
|
1073
|
-
last_agent_disconnect_reason:
|
|
1074
|
-
protocol_version:
|
|
1075
|
-
agent_capabilities:
|
|
1076
|
-
title:
|
|
1077
|
-
messages:
|
|
1078
|
-
updated_at:
|
|
1079
|
-
cumulative_token_usage:
|
|
1080
|
-
cumulative_cost:
|
|
1081
|
-
request_token_usage:
|
|
1082
|
-
acpx:
|
|
1083
|
-
imported_from:
|
|
1084
|
-
record_id:
|
|
1085
|
-
cwd_original:
|
|
1086
|
-
exported_by:
|
|
1087
|
-
exported_at:
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
1007
|
+
const record = asRecord$5(raw);
|
|
1317
1008
|
if (!record || record.User === void 0) return false;
|
|
1318
|
-
const user = asRecord$
|
|
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$
|
|
1013
|
+
const record = asRecord$5(raw);
|
|
1323
1014
|
if (!record || record.Agent === void 0) return false;
|
|
1324
|
-
const agent = asRecord$
|
|
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$
|
|
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$
|
|
1050
|
+
const record = asRecord$5(raw);
|
|
1360
1051
|
if (!record) return;
|
|
1361
1052
|
const state = {};
|
|
1362
|
-
|
|
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
|
-
|
|
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
|
|
1387
|
-
const
|
|
1388
|
-
if (!
|
|
1389
|
-
const parsed = Object.fromEntries(Object.entries(
|
|
1390
|
-
|
|
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$
|
|
1084
|
+
const sessionOptions = asRecord$5(raw);
|
|
1397
1085
|
if (!sessionOptions) return;
|
|
1398
1086
|
const parsedSessionOptions = {};
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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$
|
|
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:
|
|
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$
|
|
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) && !
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
1804
|
-
const tempFile = createAtomicWriteTempPath(filePath);
|
|
1805
|
-
const payload = JSON.stringify({
|
|
1464
|
+
await writePrivateJsonFile(sessionIndexPath(sessionDir), {
|
|
1806
1465
|
schema: SESSION_INDEX_SCHEMA,
|
|
1807
|
-
files:
|
|
1808
|
-
entries:
|
|
1809
|
-
}
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(), {
|
|
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
|
-
|
|
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$
|
|
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 =
|
|
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
|
|
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
|
|
2160
|
-
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
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:
|
|
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/
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
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
|
|
2514
|
-
|
|
2515
|
-
if (commandHasPath(command)) return candidates.find((candidate) => fs.existsSync(candidate));
|
|
2516
|
-
return resolveWindowsPathCommand(command, env);
|
|
2145
|
+
function isNonEmptyString(value) {
|
|
2146
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
2517
2147
|
}
|
|
2518
|
-
|
|
2519
|
-
|
|
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
|
-
};
|
|
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);
|
|
2570
2151
|
}
|
|
2571
|
-
function
|
|
2572
|
-
|
|
2573
|
-
return {
|
|
2574
|
-
...options,
|
|
2575
|
-
shell: true
|
|
2576
|
-
};
|
|
2152
|
+
function isImageMimeType(value) {
|
|
2153
|
+
return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
2577
2154
|
}
|
|
2578
|
-
function
|
|
2579
|
-
return
|
|
2580
|
-
command,
|
|
2581
|
-
args: args ?? [],
|
|
2582
|
-
killProcessGroup: false
|
|
2583
|
-
};
|
|
2155
|
+
function isAudioMimeType(value) {
|
|
2156
|
+
return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
2584
2157
|
}
|
|
2585
|
-
function
|
|
2586
|
-
|
|
2587
|
-
|
|
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
|
-
};
|
|
2158
|
+
function isTextBlock(value) {
|
|
2159
|
+
const record = asRecord$3(value);
|
|
2160
|
+
return record?.type === "text" && typeof record.text === "string";
|
|
2601
2161
|
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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;
|
|
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);
|
|
2611
2165
|
}
|
|
2612
|
-
function
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
} catch {
|
|
2616
|
-
return null;
|
|
2617
|
-
}
|
|
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);
|
|
2618
2169
|
}
|
|
2619
|
-
function
|
|
2620
|
-
|
|
2621
|
-
|
|
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
|
-
}
|
|
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");
|
|
2628
2173
|
}
|
|
2629
|
-
function
|
|
2630
|
-
const
|
|
2631
|
-
if (
|
|
2632
|
-
|
|
2633
|
-
return resolveVersionFromAncestors(MODULE_DIR) ?? UNKNOWN_VERSION;
|
|
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";
|
|
2634
2178
|
}
|
|
2635
|
-
function
|
|
2636
|
-
const
|
|
2637
|
-
|
|
2638
|
-
return envPackageName === "acpx" ? envVersion : null;
|
|
2179
|
+
function isResourceBlock(value) {
|
|
2180
|
+
const record = asRecord$3(value);
|
|
2181
|
+
return record?.type === "resource" && isResourcePayload(record.resource);
|
|
2639
2182
|
}
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
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));
|
|
2644
2192
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
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
|
-
});
|
|
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;
|
|
2682
2202
|
}
|
|
2683
|
-
function
|
|
2684
|
-
|
|
2685
|
-
const parts = toCommandParts([...value]);
|
|
2686
|
-
const argv = [parts.command, ...parts.args];
|
|
2687
|
-
return {
|
|
2688
|
-
agentCommand: renderArgvIdentity(argv),
|
|
2689
|
-
agentArgv: argv
|
|
2690
|
-
};
|
|
2203
|
+
function validateTextContentBlock(record, index) {
|
|
2204
|
+
return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
|
|
2691
2205
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
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`;
|
|
2695
2211
|
}
|
|
2696
|
-
function
|
|
2697
|
-
|
|
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`;
|
|
2698
2217
|
}
|
|
2699
|
-
function
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
reject(error);
|
|
2708
|
-
};
|
|
2709
|
-
child.once("spawn", onSpawn);
|
|
2710
|
-
child.once("error", onError);
|
|
2711
|
-
});
|
|
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`;
|
|
2222
|
+
}
|
|
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`;
|
|
2712
2226
|
}
|
|
2713
|
-
function
|
|
2714
|
-
|
|
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)}`;
|
|
2715
2232
|
}
|
|
2716
|
-
function
|
|
2717
|
-
|
|
2718
|
-
return child;
|
|
2233
|
+
function isPromptInput(value) {
|
|
2234
|
+
return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
|
|
2719
2235
|
}
|
|
2720
|
-
function
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
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);
|
|
2236
|
+
function promptCapabilityRequirement(block) {
|
|
2237
|
+
switch (block.type) {
|
|
2238
|
+
case "image": return {
|
|
2239
|
+
blockType: "image",
|
|
2240
|
+
capability: "image"
|
|
2734
2241
|
};
|
|
2735
|
-
|
|
2736
|
-
|
|
2242
|
+
case "audio": return {
|
|
2243
|
+
blockType: "audio",
|
|
2244
|
+
capability: "audio"
|
|
2737
2245
|
};
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
}
|
|
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);
|
|
2781
|
-
}
|
|
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
|
-
};
|
|
2788
|
-
}
|
|
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
|
-
};
|
|
2823
|
-
}
|
|
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
|
|
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
|
|
2851
|
-
|
|
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
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
return translated;
|
|
2261
|
+
function textPrompt(text) {
|
|
2262
|
+
return [{
|
|
2263
|
+
type: "text",
|
|
2264
|
+
text
|
|
2265
|
+
}];
|
|
2859
2266
|
}
|
|
2860
|
-
function
|
|
2861
|
-
if (!
|
|
2267
|
+
function parseStructuredPrompt(source) {
|
|
2268
|
+
if (!source.startsWith("[")) return;
|
|
2862
2269
|
try {
|
|
2863
|
-
const
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
return
|
|
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
|
|
2870
|
-
|
|
2871
|
-
|
|
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
|
-
|
|
2874
|
-
|
|
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
|
-
|
|
2879
|
-
|
|
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
|
|
2882
|
-
return
|
|
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
|
|
@@ -3207,6 +2632,82 @@ function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv, agentProcessEn
|
|
|
3207
2632
|
};
|
|
3208
2633
|
}
|
|
3209
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;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
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;
|
|
2666
|
+
}
|
|
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;
|
|
2671
|
+
}
|
|
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
|
+
};
|
|
2687
|
+
return {
|
|
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
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
//#endregion
|
|
3210
2711
|
//#region src/acp/model-support.ts
|
|
3211
2712
|
const REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE = "ACP_MODEL_UNSUPPORTED";
|
|
3212
2713
|
const REQUESTED_MODEL_UNSUPPORTED_REASONS = ["missing-capability", "unadvertised-model"];
|
|
@@ -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(
|
|
3265
|
-
|
|
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
|
|
3278
|
-
if (
|
|
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;
|
|
@@ -3414,6 +2928,156 @@ function createNdJsonMessageStream(agentCommand, output, input, maxMessageBytes,
|
|
|
3414
2928
|
};
|
|
3415
2929
|
}
|
|
3416
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
|
|
3417
3081
|
//#region src/acp/session-control-errors.ts
|
|
3418
3082
|
const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
|
|
3419
3083
|
function asRecord$1(value) {
|
|
@@ -3485,20 +3149,6 @@ function trimToUtf8Boundary(buffer, limit) {
|
|
|
3485
3149
|
if (start >= buffer.length) start = buffer.length - limit;
|
|
3486
3150
|
return buffer.subarray(start);
|
|
3487
3151
|
}
|
|
3488
|
-
function waitForSpawn(process) {
|
|
3489
|
-
return new Promise((resolve, reject) => {
|
|
3490
|
-
const onSpawn = () => {
|
|
3491
|
-
process.off("error", onError);
|
|
3492
|
-
resolve();
|
|
3493
|
-
};
|
|
3494
|
-
const onError = (error) => {
|
|
3495
|
-
process.off("spawn", onSpawn);
|
|
3496
|
-
reject(error);
|
|
3497
|
-
};
|
|
3498
|
-
process.once("spawn", onSpawn);
|
|
3499
|
-
process.once("error", onError);
|
|
3500
|
-
});
|
|
3501
|
-
}
|
|
3502
3152
|
async function defaultConfirmExecute(commandLine) {
|
|
3503
3153
|
return await promptForPermission({ prompt: `\n[permission] Allow terminal command "${commandLine}"? (y/N) ` });
|
|
3504
3154
|
}
|
|
@@ -3913,11 +3563,12 @@ async function runProcessGroupListCommand(timeoutMs) {
|
|
|
3913
3563
|
return await runTimedExecFile("ps", ["-eo", "pid=,pgid="], { timeoutMs });
|
|
3914
3564
|
}
|
|
3915
3565
|
async function runWindowsProcessListCommand(timeoutMs) {
|
|
3566
|
+
const command = ["Get-CimInstance Win32_Process |", "ForEach-Object { \"$($_.ProcessId) $($_.ParentProcessId)\" }"].join(" ");
|
|
3916
3567
|
return await runTimedExecFile("powershell.exe", [
|
|
3917
3568
|
"-NoProfile",
|
|
3918
3569
|
"-NonInteractive",
|
|
3919
3570
|
"-Command",
|
|
3920
|
-
|
|
3571
|
+
command
|
|
3921
3572
|
], {
|
|
3922
3573
|
timeoutMs,
|
|
3923
3574
|
windowsHide: true
|
|
@@ -3970,10 +3621,8 @@ const REPLAY_DRAIN_TIMEOUT_MS = 5e3;
|
|
|
3970
3621
|
const DRAIN_POLL_INTERVAL_MS = 20;
|
|
3971
3622
|
const AGENT_CLOSE_TERM_GRACE_MS = 1500;
|
|
3972
3623
|
const AGENT_CLOSE_KILL_GRACE_MS = 1e3;
|
|
3624
|
+
const AGENT_CLEANUP_BUDGET_MS = 8e3;
|
|
3973
3625
|
const STARTUP_STDERR_MAX_CHARS = 8192;
|
|
3974
|
-
const DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META = Object.freeze({ "cognition.ai/requestDiagnostics": true });
|
|
3975
|
-
const DEVIN_COMPATIBILITY_CLIENT_NAME = "windsurf";
|
|
3976
|
-
const DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION = "1.110.1";
|
|
3977
3626
|
const ELICITATION_CANCEL_MESSAGES = {
|
|
3978
3627
|
inactive: "elicitation owner is no longer active",
|
|
3979
3628
|
unavailable: "elicitation handler is unavailable",
|
|
@@ -3982,16 +3631,6 @@ const ELICITATION_CANCEL_MESSAGES = {
|
|
|
3982
3631
|
cancelled: "elicitation request was cancelled",
|
|
3983
3632
|
requestScoped: "request-scoped elicitation has no owner"
|
|
3984
3633
|
};
|
|
3985
|
-
function resolveClientInfo(devinAcp) {
|
|
3986
|
-
if (!devinAcp) return {
|
|
3987
|
-
name: "acpx",
|
|
3988
|
-
version: getAcpxVersion()
|
|
3989
|
-
};
|
|
3990
|
-
return {
|
|
3991
|
-
name: DEVIN_COMPATIBILITY_CLIENT_NAME,
|
|
3992
|
-
version: process.env.ACPX_DEVIN_WINDSURF_VERSION ?? DEFAULT_DEVIN_COMPATIBILITY_CLIENT_VERSION
|
|
3993
|
-
};
|
|
3994
|
-
}
|
|
3995
3634
|
function normalizeElicitationModes(modes) {
|
|
3996
3635
|
return [...new Set((modes ?? []).filter((mode) => mode === "form" || mode === "url"))];
|
|
3997
3636
|
}
|
|
@@ -4014,72 +3653,18 @@ function elicitationRequestScopeId(request) {
|
|
|
4014
3653
|
const value = request.requestId;
|
|
4015
3654
|
return value === null || typeof value === "string" || typeof value === "number" ? value : void 0;
|
|
4016
3655
|
}
|
|
4017
|
-
function
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
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 });
|
|
4021
3662
|
});
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
}
|
|
4027
|
-
function elicitationRequestId(message) {
|
|
4028
|
-
if (!("method" in message) || message.method !== methods.client.elicitation.create || !("id" in message)) return;
|
|
4029
|
-
return message.id;
|
|
4030
|
-
}
|
|
4031
|
-
function responseId(message) {
|
|
4032
|
-
if (!("id" in message) || "method" in message) return;
|
|
4033
|
-
return message.id;
|
|
4034
|
-
}
|
|
4035
|
-
function promptRequestOwner(message) {
|
|
4036
|
-
if (!("method" in message) || message.method !== methods.agent.session.prompt || !("id" in message)) return;
|
|
4037
|
-
const sessionId = message.params?.sessionId;
|
|
4038
|
-
return typeof sessionId === "string" ? {
|
|
4039
|
-
requestId: message.id,
|
|
4040
|
-
sessionId
|
|
4041
|
-
} : void 0;
|
|
4042
|
-
}
|
|
4043
|
-
function createAgentConnectionFacade(connection) {
|
|
4044
|
-
const agent = connection.agent;
|
|
4045
|
-
return {
|
|
4046
|
-
signal: connection.signal,
|
|
4047
|
-
close: (error) => connection.close(error),
|
|
4048
|
-
initialize: async (params) => await agent.request(methods.agent.initialize, params),
|
|
4049
|
-
authenticate: async (params) => {
|
|
4050
|
-
await agent.request(methods.agent.authenticate, params);
|
|
4051
|
-
},
|
|
4052
|
-
newSession: async (params) => await agent.request(methods.agent.session.new, params),
|
|
4053
|
-
loadSession: async (params) => await agent.request(methods.agent.session.load, params),
|
|
4054
|
-
resumeSession: async (params) => await agent.request(methods.agent.session.resume, params),
|
|
4055
|
-
prompt: async (params) => await agent.request(methods.agent.session.prompt, params),
|
|
4056
|
-
setSessionMode: async (params) => await agent.request(methods.agent.session.setMode, params),
|
|
4057
|
-
setSessionConfigOption: async (params) => await agent.request(methods.agent.session.setConfigOption, params),
|
|
4058
|
-
extMethod: async (method, params) => await agent.request(method, params),
|
|
4059
|
-
cancel: async (params) => await agent.notify(methods.agent.session.cancel, params),
|
|
4060
|
-
closeSession: async (params) => {
|
|
4061
|
-
await agent.request(methods.agent.session.close, params);
|
|
4062
|
-
},
|
|
4063
|
-
listSessions: async (params) => await agent.request(methods.agent.session.list, params)
|
|
4064
|
-
};
|
|
4065
|
-
}
|
|
4066
|
-
function resolveClientCapabilities(params) {
|
|
4067
|
-
const baseCapabilities = {
|
|
4068
|
-
fs: {
|
|
4069
|
-
readTextFile: params.fs,
|
|
4070
|
-
writeTextFile: params.fs
|
|
4071
|
-
},
|
|
4072
|
-
terminal: params.terminal,
|
|
4073
|
-
...params.elicitationModes.length > 0 ? { elicitation: {
|
|
4074
|
-
...params.elicitationModes.includes("form") ? { form: {} } : {},
|
|
4075
|
-
...params.elicitationModes.includes("url") ? { url: {} } : {}
|
|
4076
|
-
} } : {}
|
|
4077
|
-
};
|
|
4078
|
-
if (!params.devinAcp) return baseCapabilities;
|
|
4079
|
-
return {
|
|
4080
|
-
...baseCapabilities,
|
|
4081
|
-
_meta: DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META
|
|
4082
|
-
};
|
|
3663
|
+
try {
|
|
3664
|
+
return await Promise.race([pending, aborted]);
|
|
3665
|
+
} finally {
|
|
3666
|
+
signal.removeEventListener("abort", onAbort);
|
|
3667
|
+
}
|
|
4083
3668
|
}
|
|
4084
3669
|
function hasResponseField(response, field) {
|
|
4085
3670
|
return !!response && typeof response === "object" && field in response;
|
|
@@ -4091,7 +3676,7 @@ function normalizeResponseConfigOptions(response) {
|
|
|
4091
3676
|
function toReconnectedSessionResult(response) {
|
|
4092
3677
|
const configOptions = normalizeResponseConfigOptions(response);
|
|
4093
3678
|
return {
|
|
4094
|
-
agentSessionId:
|
|
3679
|
+
agentSessionId: extractAgentSessionId(response?._meta),
|
|
4095
3680
|
configOptions,
|
|
4096
3681
|
models: modelStateFromSessionResponse({
|
|
4097
3682
|
configOptions,
|
|
@@ -4146,6 +3731,8 @@ var AcpClient = class {
|
|
|
4146
3731
|
options;
|
|
4147
3732
|
connection;
|
|
4148
3733
|
agent;
|
|
3734
|
+
agentDescendants = /* @__PURE__ */ new WeakMap();
|
|
3735
|
+
agentCleanups = /* @__PURE__ */ new WeakMap();
|
|
4149
3736
|
initResult;
|
|
4150
3737
|
loadedSessionId;
|
|
4151
3738
|
eventHandlers;
|
|
@@ -4288,6 +3875,7 @@ var AcpClient = class {
|
|
|
4288
3875
|
this.logAgentLaunch(launch);
|
|
4289
3876
|
await this.ensureLaunchSupport(launch);
|
|
4290
3877
|
const { child, process: startedProcess } = await this.spawnAgentProcess(launch);
|
|
3878
|
+
this.agent = child;
|
|
4291
3879
|
this.closing = false;
|
|
4292
3880
|
this.agentStartedAt = startedProcess.startedAt;
|
|
4293
3881
|
this.lastAgentExit = void 0;
|
|
@@ -4312,11 +3900,11 @@ var AcpClient = class {
|
|
|
4312
3900
|
let connection;
|
|
4313
3901
|
const stream = this.createTappedStream(createNdJsonMessageStream(this.options.agentCommand, input, output, maxMessageBytes, (error) => {
|
|
4314
3902
|
this.rejectPendingConnectionRequests(error);
|
|
4315
|
-
connection?.close
|
|
3903
|
+
connection?.close(error);
|
|
4316
3904
|
}));
|
|
4317
3905
|
connection = this.createConnection(stream, launch);
|
|
4318
3906
|
connection.signal.addEventListener("abort", () => {
|
|
4319
|
-
this.recordAgentExit("connection_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
3907
|
+
this.recordAgentExit(child, "connection_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
4320
3908
|
}, { once: true });
|
|
4321
3909
|
await this.initializeAgentConnection({
|
|
4322
3910
|
child,
|
|
@@ -4381,13 +3969,14 @@ var AcpClient = class {
|
|
|
4381
3969
|
...plan.spawnOptions,
|
|
4382
3970
|
windowsVerbatimArguments: spawnCommand.windowsVerbatimArguments
|
|
4383
3971
|
});
|
|
4384
|
-
await waitForSpawn
|
|
3972
|
+
await waitForSpawn(spawnedChild);
|
|
4385
3973
|
} catch (error) {
|
|
4386
3974
|
const spawnError = new AgentSpawnError(this.options.agentCommand, error);
|
|
4387
3975
|
this.notifyProcessSpawnFailure(launch, spawnError);
|
|
4388
3976
|
throw spawnError;
|
|
4389
3977
|
}
|
|
4390
3978
|
const child = requireAgentStdio(spawnedChild);
|
|
3979
|
+
this.agentDescendants.set(child, new ProcessDescendants(child));
|
|
4391
3980
|
const pid = child.pid;
|
|
4392
3981
|
if (pid === void 0) {
|
|
4393
3982
|
const spawnError = new AgentSpawnError(this.options.agentCommand, /* @__PURE__ */ new Error("spawned agent process did not expose a PID"));
|
|
@@ -4400,7 +3989,7 @@ var AcpClient = class {
|
|
|
4400
3989
|
process: Object.freeze({
|
|
4401
3990
|
...launch,
|
|
4402
3991
|
pid,
|
|
4403
|
-
startedAt: isoNow$
|
|
3992
|
+
startedAt: isoNow$2()
|
|
4404
3993
|
})
|
|
4405
3994
|
};
|
|
4406
3995
|
}
|
|
@@ -4433,34 +4022,34 @@ var AcpClient = class {
|
|
|
4433
4022
|
}).onRequest(methods.client.terminal.create, async ({ params }) => {
|
|
4434
4023
|
return await this.handleCreateTerminal(params);
|
|
4435
4024
|
}).onRequest(methods.client.terminal.output, async ({ params }) => {
|
|
4436
|
-
return await this.
|
|
4025
|
+
return await this.terminalManager.terminalOutput(params);
|
|
4437
4026
|
}).onRequest(methods.client.terminal.waitForExit, async ({ params }) => {
|
|
4438
|
-
return await this.
|
|
4027
|
+
return await this.terminalManager.waitForTerminalExit(params);
|
|
4439
4028
|
}).onRequest(methods.client.terminal.kill, async ({ params }) => {
|
|
4440
|
-
return await this.
|
|
4029
|
+
return await this.terminalManager.killTerminal(params);
|
|
4441
4030
|
}).onRequest(methods.client.terminal.release, async ({ params }) => {
|
|
4442
|
-
return await this.
|
|
4031
|
+
return await this.terminalManager.releaseTerminal(params);
|
|
4443
4032
|
});
|
|
4444
4033
|
if (launch.devinAcp) app.onRequest("_cognition.ai/request_diagnostics", (params) => {
|
|
4445
4034
|
return params && typeof params === "object" && !Array.isArray(params) ? params : {};
|
|
4446
4035
|
}, async () => ({}));
|
|
4447
|
-
return
|
|
4036
|
+
return app.connect(stream);
|
|
4448
4037
|
}
|
|
4449
4038
|
async initializeAgentConnection(params) {
|
|
4450
4039
|
try {
|
|
4451
4040
|
const initResult = await Promise.race([this.initializeProtocolConnection(params.connection, params.launch), params.startupFailure.promise]);
|
|
4452
4041
|
params.startupFailure.dispose();
|
|
4453
4042
|
this.connection = params.connection;
|
|
4454
|
-
this.agent = params.child;
|
|
4455
4043
|
this.initResult = initResult;
|
|
4044
|
+
await this.captureAgentDescendants(params.child);
|
|
4456
4045
|
this.log(`initialized protocol version ${initResult.protocolVersion}`);
|
|
4457
4046
|
} catch (error) {
|
|
4458
|
-
params.connection.close
|
|
4047
|
+
params.connection.close(error);
|
|
4459
4048
|
await this.handleInitializeFailure(params, error);
|
|
4460
4049
|
}
|
|
4461
4050
|
}
|
|
4462
4051
|
async initializeProtocolConnection(connection, launch) {
|
|
4463
|
-
const initializePromise = connection.initialize
|
|
4052
|
+
const initializePromise = connection.agent.request(methods.agent.initialize, {
|
|
4464
4053
|
protocolVersion: PROTOCOL_VERSION,
|
|
4465
4054
|
clientCapabilities: resolveClientCapabilities({
|
|
4466
4055
|
devinAcp: launch.devinAcp,
|
|
@@ -4476,10 +4065,9 @@ var AcpClient = class {
|
|
|
4476
4065
|
}
|
|
4477
4066
|
async handleInitializeFailure(params, error) {
|
|
4478
4067
|
params.startupFailure.dispose();
|
|
4068
|
+
await this.captureAgentDescendants(params.child);
|
|
4479
4069
|
const normalizedError = error instanceof AcpMessageLimitError ? error : await this.normalizeInitializeError(error, params.child, params.startupStderr);
|
|
4480
|
-
|
|
4481
|
-
params.child.kill();
|
|
4482
|
-
} catch {}
|
|
4070
|
+
await this.terminateAgentProcess(params.child);
|
|
4483
4071
|
if (params.launch.geminiAcp && error instanceof TimeoutError) throw new GeminiAcpStartupTimeoutError(await buildGeminiAcpStartupTimeoutMessage(params.launch.spawnCommand), {
|
|
4484
4072
|
cause: error,
|
|
4485
4073
|
retryable: true
|
|
@@ -4487,59 +4075,15 @@ var AcpClient = class {
|
|
|
4487
4075
|
throw normalizedError;
|
|
4488
4076
|
}
|
|
4489
4077
|
createTappedStream(base) {
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
const requestId = elicitationRequestId(message);
|
|
4500
|
-
if (requestId !== void 0) {
|
|
4501
|
-
elicitationRequestIds.add(requestId);
|
|
4502
|
-
return;
|
|
4503
|
-
}
|
|
4504
|
-
if (!shouldSuppressInboundReplaySessionUpdate(message)) {
|
|
4505
|
-
onAcpOutputMessage()?.("inbound", message);
|
|
4506
|
-
onAcpMessage()?.("inbound", message);
|
|
4507
|
-
}
|
|
4508
|
-
};
|
|
4509
|
-
return {
|
|
4510
|
-
readable: new ReadableStream({ async start(controller) {
|
|
4511
|
-
const reader = base.readable.getReader();
|
|
4512
|
-
try {
|
|
4513
|
-
while (true) {
|
|
4514
|
-
const { value, done } = await reader.read();
|
|
4515
|
-
if (done) break;
|
|
4516
|
-
if (!value) continue;
|
|
4517
|
-
observeInbound(value);
|
|
4518
|
-
if (isExtensionNotification(value)) continue;
|
|
4519
|
-
controller.enqueue(value);
|
|
4520
|
-
}
|
|
4521
|
-
} finally {
|
|
4522
|
-
reader.releaseLock();
|
|
4523
|
-
controller.close();
|
|
4524
|
-
}
|
|
4525
|
-
} }),
|
|
4526
|
-
writable: new WritableStream({ async write(message) {
|
|
4527
|
-
const promptOwner = promptRequestOwner(message);
|
|
4528
|
-
const activePrompt = promptOwner ? bindPromptOwner(promptOwner) : void 0;
|
|
4529
|
-
const id = responseId(message);
|
|
4530
|
-
if (!(id !== void 0 && elicitationRequestIds.delete(id))) {
|
|
4531
|
-
onAcpOutputMessage()?.("outbound", message);
|
|
4532
|
-
onAcpMessage()?.("outbound", message);
|
|
4533
|
-
}
|
|
4534
|
-
const writer = base.writable.getWriter();
|
|
4535
|
-
try {
|
|
4536
|
-
await writer.write(message);
|
|
4537
|
-
} finally {
|
|
4538
|
-
writer.releaseLock();
|
|
4539
|
-
}
|
|
4540
|
-
if (activePrompt && promptOwner) onPromptRequestWritten(activePrompt, promptOwner);
|
|
4541
|
-
} })
|
|
4542
|
-
};
|
|
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
|
+
});
|
|
4543
4087
|
}
|
|
4544
4088
|
async createSession(cwd = this.options.cwd) {
|
|
4545
4089
|
const connection = this.getConnection();
|
|
@@ -4548,7 +4092,7 @@ var AcpClient = class {
|
|
|
4548
4092
|
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
|
4549
4093
|
let result;
|
|
4550
4094
|
try {
|
|
4551
|
-
const createPromise = this.runConnectionRequest(() => connection.
|
|
4095
|
+
const createPromise = this.runConnectionRequest(() => connection.agent.request(methods.agent.session.new, {
|
|
4552
4096
|
cwd: sessionCwd,
|
|
4553
4097
|
mcpServers: this.options.mcpServers ?? [],
|
|
4554
4098
|
_meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions, claudeAcp)
|
|
@@ -4568,9 +4112,10 @@ var AcpClient = class {
|
|
|
4568
4112
|
response: result
|
|
4569
4113
|
});
|
|
4570
4114
|
this.rememberSessionModels(result.sessionId, models);
|
|
4115
|
+
await this.captureAgentDescendants(this.agent);
|
|
4571
4116
|
return {
|
|
4572
4117
|
sessionId: result.sessionId,
|
|
4573
|
-
agentSessionId:
|
|
4118
|
+
agentSessionId: extractAgentSessionId(result._meta),
|
|
4574
4119
|
configOptions,
|
|
4575
4120
|
models,
|
|
4576
4121
|
configOptionsPresent: hasResponseField(result, "configOptions"),
|
|
@@ -4587,7 +4132,7 @@ var AcpClient = class {
|
|
|
4587
4132
|
const previousSuppression = this.applySessionUpdateSuppression(Boolean(options.suppressReplayUpdates));
|
|
4588
4133
|
let response;
|
|
4589
4134
|
try {
|
|
4590
|
-
response = await this.runConnectionRequest(() => connection.
|
|
4135
|
+
response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.load, {
|
|
4591
4136
|
sessionId,
|
|
4592
4137
|
cwd: sessionCwd,
|
|
4593
4138
|
mcpServers: this.options.mcpServers ?? []
|
|
@@ -4599,12 +4144,13 @@ var AcpClient = class {
|
|
|
4599
4144
|
this.loadedSessionId = sessionId;
|
|
4600
4145
|
const result = toReconnectedSessionResult(response);
|
|
4601
4146
|
this.updateRememberedSessionModels(sessionId, result);
|
|
4147
|
+
await this.captureAgentDescendants(this.agent);
|
|
4602
4148
|
return result;
|
|
4603
4149
|
}
|
|
4604
4150
|
async resumeSession(sessionId, cwd = this.options.cwd) {
|
|
4605
4151
|
const connection = this.getConnection();
|
|
4606
4152
|
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
|
4607
|
-
const response = await this.runConnectionRequest(() => connection.
|
|
4153
|
+
const response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.resume, {
|
|
4608
4154
|
sessionId,
|
|
4609
4155
|
cwd: sessionCwd,
|
|
4610
4156
|
mcpServers: this.options.mcpServers ?? []
|
|
@@ -4612,6 +4158,7 @@ var AcpClient = class {
|
|
|
4612
4158
|
this.loadedSessionId = sessionId;
|
|
4613
4159
|
const result = toReconnectedSessionResult(response);
|
|
4614
4160
|
this.updateRememberedSessionModels(sessionId, result);
|
|
4161
|
+
await this.captureAgentDescendants(this.agent);
|
|
4615
4162
|
return result;
|
|
4616
4163
|
}
|
|
4617
4164
|
applySessionUpdateSuppression(enabled) {
|
|
@@ -4627,14 +4174,15 @@ var AcpClient = class {
|
|
|
4627
4174
|
this.suppressSessionUpdates = previous.suppressSessionUpdates;
|
|
4628
4175
|
this.suppressReplaySessionUpdateMessages = previous.suppressReplaySessionUpdateMessages;
|
|
4629
4176
|
}
|
|
4630
|
-
async prompt(sessionId, prompt, onRequestWritten, onElicitation) {
|
|
4177
|
+
async prompt(sessionId, prompt, onRequestWritten, onElicitation, onPermissionRequest) {
|
|
4631
4178
|
const connection = this.getConnection();
|
|
4632
4179
|
const normalizedPrompt = this.normalizePromptForAgent(prompt);
|
|
4633
4180
|
const restoreConsoleError = this.options.suppressSdkConsoleErrors ? installSdkConsoleErrorSuppression() : void 0;
|
|
4634
|
-
const
|
|
4181
|
+
const previousActivePrompt = this.activePrompt;
|
|
4182
|
+
const activePrompt = this.beginActivePrompt(sessionId, onRequestWritten, onElicitation, onPermissionRequest);
|
|
4635
4183
|
let promptPromise;
|
|
4636
4184
|
try {
|
|
4637
|
-
promptPromise = this.runConnectionRequest(() => connection.prompt
|
|
4185
|
+
promptPromise = this.runConnectionRequest(() => connection.agent.request(methods.agent.session.prompt, {
|
|
4638
4186
|
sessionId,
|
|
4639
4187
|
prompt: normalizedPrompt
|
|
4640
4188
|
}));
|
|
@@ -4645,6 +4193,7 @@ var AcpClient = class {
|
|
|
4645
4193
|
}
|
|
4646
4194
|
activePrompt.promise = promptPromise;
|
|
4647
4195
|
try {
|
|
4196
|
+
previousActivePrompt?.elicitationController?.abort();
|
|
4648
4197
|
return this.returnPromptResponseOrPermissionFailure(sessionId, await promptPromise);
|
|
4649
4198
|
} catch (error) {
|
|
4650
4199
|
this.throwPromptPermissionFailureIfPresent(sessionId);
|
|
@@ -4652,23 +4201,19 @@ var AcpClient = class {
|
|
|
4652
4201
|
} finally {
|
|
4653
4202
|
restoreConsoleError?.();
|
|
4654
4203
|
this.clearActivePrompt(activePrompt);
|
|
4655
|
-
this.cancellingSessionIds.delete(sessionId);
|
|
4656
|
-
this.abortAndDropPermissionSignal(sessionId);
|
|
4657
|
-
this.promptPermissionFailures.delete(sessionId);
|
|
4658
4204
|
}
|
|
4659
4205
|
}
|
|
4660
|
-
beginActivePrompt(sessionId, onRequestWritten, elicitationHandler) {
|
|
4661
|
-
const previous = this.activePrompt;
|
|
4206
|
+
beginActivePrompt(sessionId, onRequestWritten, elicitationHandler, permissionHandler) {
|
|
4662
4207
|
this.cancellingSessionIds.delete(sessionId);
|
|
4663
4208
|
const active = {
|
|
4664
4209
|
sessionId,
|
|
4665
4210
|
onRequestWritten,
|
|
4666
4211
|
elicitationHandler,
|
|
4212
|
+
permissionHandler,
|
|
4667
4213
|
elicitationController: new AbortController()
|
|
4668
4214
|
};
|
|
4669
4215
|
this.activePrompt = active;
|
|
4670
4216
|
this.pendingPromptOwners.push(active);
|
|
4671
|
-
previous?.elicitationController?.abort();
|
|
4672
4217
|
return active;
|
|
4673
4218
|
}
|
|
4674
4219
|
bindPromptOwner(owner) {
|
|
@@ -4685,10 +4230,18 @@ var AcpClient = class {
|
|
|
4685
4230
|
} catch {}
|
|
4686
4231
|
}
|
|
4687
4232
|
clearActivePrompt(active) {
|
|
4688
|
-
if (this.activePrompt === active) this.activePrompt = void 0;
|
|
4689
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;
|
|
4690
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
|
+
}
|
|
4691
4243
|
active.elicitationController.abort();
|
|
4244
|
+
permissionController?.abort();
|
|
4692
4245
|
}
|
|
4693
4246
|
normalizePromptForAgent(prompt) {
|
|
4694
4247
|
const normalizedPrompt = typeof prompt === "string" ? textPrompt(prompt) : prompt;
|
|
@@ -4707,7 +4260,7 @@ var AcpClient = class {
|
|
|
4707
4260
|
async setSessionMode(sessionId, modeId) {
|
|
4708
4261
|
const connection = this.getConnection();
|
|
4709
4262
|
try {
|
|
4710
|
-
await this.runConnectionRequest(() => connection.
|
|
4263
|
+
await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setMode, {
|
|
4711
4264
|
sessionId,
|
|
4712
4265
|
modeId
|
|
4713
4266
|
}));
|
|
@@ -4718,7 +4271,7 @@ var AcpClient = class {
|
|
|
4718
4271
|
async setSessionConfigOption(sessionId, configId, value) {
|
|
4719
4272
|
const connection = this.getConnection();
|
|
4720
4273
|
try {
|
|
4721
|
-
return await this.runConnectionRequest(() => connection.
|
|
4274
|
+
return await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setConfigOption, {
|
|
4722
4275
|
sessionId,
|
|
4723
4276
|
configId,
|
|
4724
4277
|
value
|
|
@@ -4740,7 +4293,7 @@ var AcpClient = class {
|
|
|
4740
4293
|
async setSessionModelThroughConfig(sessionId, modelId, configId) {
|
|
4741
4294
|
const connection = this.getConnection();
|
|
4742
4295
|
try {
|
|
4743
|
-
const response = await this.runConnectionRequest(() => connection.
|
|
4296
|
+
const response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.setConfigOption, {
|
|
4744
4297
|
sessionId,
|
|
4745
4298
|
configId,
|
|
4746
4299
|
value: modelId
|
|
@@ -4754,7 +4307,7 @@ var AcpClient = class {
|
|
|
4754
4307
|
async setSessionModelThroughLegacyMethod(sessionId, modelId) {
|
|
4755
4308
|
const connection = this.getConnection();
|
|
4756
4309
|
try {
|
|
4757
|
-
await this.runConnectionRequest(() => connection.
|
|
4310
|
+
await this.runConnectionRequest(() => connection.agent.request("session/set_model", {
|
|
4758
4311
|
sessionId,
|
|
4759
4312
|
modelId
|
|
4760
4313
|
}));
|
|
@@ -4802,26 +4355,32 @@ var AcpClient = class {
|
|
|
4802
4355
|
}
|
|
4803
4356
|
async cancel(sessionId) {
|
|
4804
4357
|
const connection = this.getConnection();
|
|
4805
|
-
const active = this.activePrompt;
|
|
4806
|
-
|
|
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;
|
|
4807
4366
|
this.cancellingSessionIds.add(sessionId);
|
|
4808
4367
|
active.elicitationController?.abort();
|
|
4809
4368
|
} else this.cancellingSessionIds.delete(sessionId);
|
|
4810
|
-
|
|
4811
|
-
await
|
|
4369
|
+
permissionController?.abort();
|
|
4370
|
+
await cancellation;
|
|
4812
4371
|
}
|
|
4813
4372
|
async closeSession(sessionId) {
|
|
4814
4373
|
const connection = this.getConnection();
|
|
4815
4374
|
this.cancellingSessionIds.add(sessionId);
|
|
4816
4375
|
if (this.activePrompt?.sessionId === sessionId) this.activePrompt.elicitationController?.abort();
|
|
4817
|
-
await this.runConnectionRequest(() => connection.
|
|
4376
|
+
await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.close, { sessionId }));
|
|
4818
4377
|
if (this.loadedSessionId === sessionId) this.loadedSessionId = void 0;
|
|
4819
4378
|
this.modelConfigIds.delete(sessionId);
|
|
4820
4379
|
this.legacyModelSessionIds.delete(sessionId);
|
|
4821
4380
|
}
|
|
4822
4381
|
async listSessions(params = {}) {
|
|
4823
4382
|
const connection = this.getConnection();
|
|
4824
|
-
return await this.runConnectionRequest(() => connection.
|
|
4383
|
+
return await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.list, params));
|
|
4825
4384
|
}
|
|
4826
4385
|
async requestCancelActivePrompt() {
|
|
4827
4386
|
const active = this.activePrompt;
|
|
@@ -4881,18 +4440,36 @@ var AcpClient = class {
|
|
|
4881
4440
|
this.activePrompt?.elicitationController?.abort();
|
|
4882
4441
|
}
|
|
4883
4442
|
closeConnection() {
|
|
4884
|
-
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;
|
|
4885
4456
|
}
|
|
4886
|
-
async
|
|
4457
|
+
async cleanupAgentProcess(child) {
|
|
4458
|
+
const descendants = this.agentDescendants.get(child);
|
|
4459
|
+
const deadline = Date.now() + AGENT_CLEANUP_BUDGET_MS;
|
|
4887
4460
|
const stdinCloseGraceMs = resolveAgentCloseAfterStdinEndMs(this.options.agentCommand);
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
this.
|
|
4893
|
-
|
|
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));
|
|
4894
4472
|
}
|
|
4895
|
-
this.detachAgentHandles(child, !exited);
|
|
4896
4473
|
}
|
|
4897
4474
|
endAgentStdin(child) {
|
|
4898
4475
|
if (child.stdin.destroyed) return;
|
|
@@ -4900,12 +4477,15 @@ var AcpClient = class {
|
|
|
4900
4477
|
child.stdin.end();
|
|
4901
4478
|
} catch {}
|
|
4902
4479
|
}
|
|
4903
|
-
async
|
|
4904
|
-
|
|
4905
|
-
|
|
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 {
|
|
4906
4484
|
child.kill(signal);
|
|
4907
4485
|
} catch {}
|
|
4908
|
-
|
|
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;
|
|
4909
4489
|
}
|
|
4910
4490
|
detachAgentHandles(agent, unref) {
|
|
4911
4491
|
const stdin = agent.stdin;
|
|
@@ -5057,7 +4637,7 @@ var AcpClient = class {
|
|
|
5057
4637
|
this.log(`agent advertised auth methods [${authMethods.map((m) => m.id).join(", ")}] but no matching credentials found — skipping (agent may handle auth internally)`);
|
|
5058
4638
|
return;
|
|
5059
4639
|
}
|
|
5060
|
-
await connection.authenticate
|
|
4640
|
+
await connection.agent.request(methods.agent.authenticate, { methodId: selected.methodId });
|
|
5061
4641
|
this.log(`authenticated with method ${selected.methodId} (${selected.source})`);
|
|
5062
4642
|
}
|
|
5063
4643
|
async handlePermissionRequest(params) {
|
|
@@ -5076,7 +4656,7 @@ var AcpClient = class {
|
|
|
5076
4656
|
if ("response" in resolved) return resolved.response;
|
|
5077
4657
|
const { active, handler } = resolved.owner;
|
|
5078
4658
|
const signal = AbortSignal.any([requestSignal, active.elicitationController.signal]);
|
|
5079
|
-
const
|
|
4659
|
+
const outcome = await raceWithAbort(signal, Promise.resolve().then(async () => await handler(request, {
|
|
5080
4660
|
requestId,
|
|
5081
4661
|
signal
|
|
5082
4662
|
})).then((response) => ({
|
|
@@ -5085,10 +4665,9 @@ var AcpClient = class {
|
|
|
5085
4665
|
}), (error) => ({
|
|
5086
4666
|
kind: "error",
|
|
5087
4667
|
error
|
|
5088
|
-
}));
|
|
5089
|
-
const outcome = await Promise.race([handlerAttempt, waitForAbort(signal)]);
|
|
4668
|
+
})));
|
|
5090
4669
|
if (this.activePrompt !== active) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.inactive);
|
|
5091
|
-
if (outcome
|
|
4670
|
+
if (!outcome || signal.aborted) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.cancelled);
|
|
5092
4671
|
if (outcome.kind === "error" || !isKnownElicitationResponse(outcome.response)) return cancelledElicitationResponse(ELICITATION_CANCEL_MESSAGES.unavailable);
|
|
5093
4672
|
return outcome.response;
|
|
5094
4673
|
}
|
|
@@ -5115,15 +4694,31 @@ var AcpClient = class {
|
|
|
5115
4694
|
isElicitationSessionCancelling(sessionId) {
|
|
5116
4695
|
return this.closing || this.cancellingSessionIds.has(sessionId);
|
|
5117
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
|
+
}
|
|
5118
4711
|
async tryHandlePermissionRequestWithHost(params) {
|
|
5119
|
-
|
|
5120
|
-
|
|
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);
|
|
5121
4716
|
try {
|
|
5122
|
-
const decision = await
|
|
4717
|
+
const decision = await raceWithAbort(signal, handler({
|
|
5123
4718
|
sessionId: params.sessionId,
|
|
5124
4719
|
raw: params,
|
|
5125
4720
|
inferredKind: inferToolKind(params)
|
|
5126
|
-
}, { signal });
|
|
4721
|
+
}, { signal }));
|
|
5127
4722
|
return this.hostPermissionDecisionResponse(params, signal, decision);
|
|
5128
4723
|
} catch (error) {
|
|
5129
4724
|
return this.hostPermissionErrorResponse(params, signal, error);
|
|
@@ -5135,9 +4730,9 @@ var AcpClient = class {
|
|
|
5135
4730
|
return cancelledPermissionResponse();
|
|
5136
4731
|
}
|
|
5137
4732
|
if (!decision) return;
|
|
5138
|
-
const response = decisionToResponse(params, decision);
|
|
4733
|
+
const response = decisionToResponse(preferCodexPermissionRefusal(params, this.initResult?.agentInfo?.name), decision);
|
|
5139
4734
|
this.recordPermissionDecision(classifyPermissionDecision(params, response));
|
|
5140
|
-
return response;
|
|
4735
|
+
return decision.outcome === "cancel" ? response : this.explainPermissionRefusal(params, response);
|
|
5141
4736
|
}
|
|
5142
4737
|
hostPermissionErrorResponse(params, signal, error) {
|
|
5143
4738
|
if (signal.aborted || this.cancellingSessionIds.has(params.sessionId)) {
|
|
@@ -5148,16 +4743,29 @@ var AcpClient = class {
|
|
|
5148
4743
|
}
|
|
5149
4744
|
async resolvePermissionRequestFromMode(params) {
|
|
5150
4745
|
try {
|
|
5151
|
-
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);
|
|
5152
4747
|
this.emitPermissionEscalation(result.escalation);
|
|
5153
4748
|
return {
|
|
5154
|
-
response: result.response,
|
|
4749
|
+
response: this.explainPermissionRefusal(params, result.response),
|
|
5155
4750
|
recorded: false
|
|
5156
4751
|
};
|
|
5157
4752
|
} catch (error) {
|
|
5158
4753
|
return this.handleModePermissionError(params.sessionId, error);
|
|
5159
4754
|
}
|
|
5160
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
|
+
}
|
|
5161
4769
|
emitPermissionEscalation(escalation) {
|
|
5162
4770
|
if (escalation) this.eventHandlers.onPermissionEscalation?.(escalation);
|
|
5163
4771
|
}
|
|
@@ -5172,8 +4780,9 @@ var AcpClient = class {
|
|
|
5172
4780
|
}
|
|
5173
4781
|
attachAgentLifecycleObservers(child, startedProcess, exitNotificationBarrier) {
|
|
5174
4782
|
const onExit = (exitCode, signal) => {
|
|
5175
|
-
const exitedAt = isoNow$
|
|
5176
|
-
this.recordAgentExit("process_exit", exitCode, signal);
|
|
4783
|
+
const exitedAt = isoNow$2();
|
|
4784
|
+
this.recordAgentExit(child, "process_exit", exitCode, signal);
|
|
4785
|
+
this.terminateAgentProcess(child);
|
|
5177
4786
|
exitNotificationBarrier.then(() => {
|
|
5178
4787
|
this.notifyProcessExit(startedProcess, exitCode, signal, exitedAt);
|
|
5179
4788
|
});
|
|
@@ -5184,10 +4793,10 @@ var AcpClient = class {
|
|
|
5184
4793
|
onExit(child.exitCode, child.signalCode);
|
|
5185
4794
|
}
|
|
5186
4795
|
child.once("close", (exitCode, signal) => {
|
|
5187
|
-
this.recordAgentExit("process_close", exitCode, signal);
|
|
4796
|
+
this.recordAgentExit(child, "process_close", exitCode, signal);
|
|
5188
4797
|
});
|
|
5189
4798
|
child.stdout.once("close", () => {
|
|
5190
|
-
this.recordAgentExit("pipe_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
4799
|
+
this.recordAgentExit(child, "pipe_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
5191
4800
|
});
|
|
5192
4801
|
}
|
|
5193
4802
|
notifyProcessSpawnFailure(launch, error) {
|
|
@@ -5196,7 +4805,7 @@ var AcpClient = class {
|
|
|
5196
4805
|
const event = Object.freeze({
|
|
5197
4806
|
...launch,
|
|
5198
4807
|
error,
|
|
5199
|
-
failedAt: isoNow$
|
|
4808
|
+
failedAt: isoNow$2()
|
|
5200
4809
|
});
|
|
5201
4810
|
try {
|
|
5202
4811
|
Promise.resolve(handler(event)).catch((observerError) => {
|
|
@@ -5227,12 +4836,12 @@ var AcpClient = class {
|
|
|
5227
4836
|
const message = error instanceof Error ? error.message : String(error);
|
|
5228
4837
|
this.log(`process lifecycle ${hook} hook failed: ${message}`);
|
|
5229
4838
|
}
|
|
5230
|
-
recordAgentExit(reason, exitCode, signal) {
|
|
5231
|
-
if (this.lastAgentExit) return;
|
|
4839
|
+
recordAgentExit(child, reason, exitCode, signal) {
|
|
4840
|
+
if (this.agent !== child || this.lastAgentExit) return;
|
|
5232
4841
|
this.lastAgentExit = {
|
|
5233
4842
|
exitCode,
|
|
5234
4843
|
signal,
|
|
5235
|
-
exitedAt: isoNow$
|
|
4844
|
+
exitedAt: isoNow$2(),
|
|
5236
4845
|
reason,
|
|
5237
4846
|
unexpectedDuringPrompt: !this.closing && Boolean(this.activePrompt)
|
|
5238
4847
|
};
|
|
@@ -5286,6 +4895,7 @@ var AcpClient = class {
|
|
|
5286
4895
|
return await this.filesystem.readTextFile(params);
|
|
5287
4896
|
} catch (error) {
|
|
5288
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);
|
|
5289
4899
|
throw error;
|
|
5290
4900
|
}
|
|
5291
4901
|
}
|
|
@@ -5305,18 +4915,6 @@ var AcpClient = class {
|
|
|
5305
4915
|
throw error;
|
|
5306
4916
|
}
|
|
5307
4917
|
}
|
|
5308
|
-
async handleTerminalOutput(params) {
|
|
5309
|
-
return await this.terminalManager.terminalOutput(params);
|
|
5310
|
-
}
|
|
5311
|
-
async handleWaitForTerminalExit(params) {
|
|
5312
|
-
return await this.terminalManager.waitForTerminalExit(params);
|
|
5313
|
-
}
|
|
5314
|
-
async handleKillTerminal(params) {
|
|
5315
|
-
return await this.terminalManager.killTerminal(params);
|
|
5316
|
-
}
|
|
5317
|
-
async handleReleaseTerminal(params) {
|
|
5318
|
-
return await this.terminalManager.releaseTerminal(params);
|
|
5319
|
-
}
|
|
5320
4918
|
cancellationSignalForSession(sessionId) {
|
|
5321
4919
|
let controller = this.permissionAbortControllers.get(sessionId);
|
|
5322
4920
|
if (!controller) {
|
|
@@ -5325,12 +4923,10 @@ var AcpClient = class {
|
|
|
5325
4923
|
}
|
|
5326
4924
|
return controller.signal;
|
|
5327
4925
|
}
|
|
5328
|
-
|
|
4926
|
+
takePermissionAbortController(sessionId) {
|
|
5329
4927
|
const controller = this.permissionAbortControllers.get(sessionId);
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
this.permissionAbortControllers.delete(sessionId);
|
|
5333
|
-
}
|
|
4928
|
+
this.permissionAbortControllers.delete(sessionId);
|
|
4929
|
+
return controller;
|
|
5334
4930
|
}
|
|
5335
4931
|
recordPermissionDecision(decision) {
|
|
5336
4932
|
this.permissionStats.requested += 1;
|
|
@@ -5393,132 +4989,6 @@ var AcpClient = class {
|
|
|
5393
4989
|
}
|
|
5394
4990
|
};
|
|
5395
4991
|
//#endregion
|
|
5396
|
-
//#region src/runtime/engine/lifecycle.ts
|
|
5397
|
-
function applyLifecycleSnapshotToRecord(record, snapshot) {
|
|
5398
|
-
if (!snapshot) return;
|
|
5399
|
-
record.pid = snapshot.running ? snapshot.pid : void 0;
|
|
5400
|
-
record.agentStartedAt = snapshot.startedAt;
|
|
5401
|
-
if (snapshot.lastExit) {
|
|
5402
|
-
record.lastAgentExitCode = snapshot.lastExit.exitCode;
|
|
5403
|
-
record.lastAgentExitSignal = snapshot.lastExit.signal;
|
|
5404
|
-
record.lastAgentExitAt = snapshot.lastExit.exitedAt;
|
|
5405
|
-
record.lastAgentDisconnectReason = snapshot.lastExit.reason;
|
|
5406
|
-
return;
|
|
5407
|
-
}
|
|
5408
|
-
record.lastAgentExitCode = void 0;
|
|
5409
|
-
record.lastAgentExitSignal = void 0;
|
|
5410
|
-
record.lastAgentExitAt = void 0;
|
|
5411
|
-
record.lastAgentDisconnectReason = void 0;
|
|
5412
|
-
}
|
|
5413
|
-
function reconcileAgentSessionId(record, agentSessionId) {
|
|
5414
|
-
const normalized = normalizeRuntimeSessionId(agentSessionId);
|
|
5415
|
-
if (!normalized) return;
|
|
5416
|
-
record.agentSessionId = normalized;
|
|
5417
|
-
}
|
|
5418
|
-
function sessionHasAgentMessages(recordOrConversation) {
|
|
5419
|
-
return recordOrConversation.messages.some((message) => typeof message === "object" && message !== null && "Agent" in message);
|
|
5420
|
-
}
|
|
5421
|
-
function applyConversation(record, conversation) {
|
|
5422
|
-
record.title = conversation.title;
|
|
5423
|
-
record.updated_at = conversation.updated_at;
|
|
5424
|
-
record.messages = conversation.messages;
|
|
5425
|
-
record.cumulative_token_usage = conversation.cumulative_token_usage;
|
|
5426
|
-
record.cumulative_cost = conversation.cumulative_cost;
|
|
5427
|
-
record.request_token_usage = conversation.request_token_usage;
|
|
5428
|
-
}
|
|
5429
|
-
//#endregion
|
|
5430
|
-
//#region src/runtime/engine/session-options.ts
|
|
5431
|
-
function mergeSessionOptions(preferred, fallback) {
|
|
5432
|
-
const merged = { ...fallback };
|
|
5433
|
-
assignDefinedOption(merged, "model", preferred?.model);
|
|
5434
|
-
assignDefinedOption(merged, "allowedTools", preferred?.allowedTools);
|
|
5435
|
-
assignDefinedOption(merged, "maxTurns", preferred?.maxTurns);
|
|
5436
|
-
assignDefinedOption(merged, "systemPrompt", preferred?.systemPrompt);
|
|
5437
|
-
assignDefinedOption(merged, "env", mergeEnvRecords(fallback?.env, preferred?.env));
|
|
5438
|
-
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
5439
|
-
}
|
|
5440
|
-
function mergeEnvRecords(fallback, preferred) {
|
|
5441
|
-
if (!fallback && !preferred) return;
|
|
5442
|
-
return {
|
|
5443
|
-
...fallback,
|
|
5444
|
-
...preferred
|
|
5445
|
-
};
|
|
5446
|
-
}
|
|
5447
|
-
function assignDefinedOption(target, key, value) {
|
|
5448
|
-
if (value !== void 0) target[key] = value;
|
|
5449
|
-
}
|
|
5450
|
-
function persistSessionOptions(record, options) {
|
|
5451
|
-
const next = options === void 0 ? void 0 : persistedSessionOptions(options);
|
|
5452
|
-
if (next !== void 0) {
|
|
5453
|
-
record.acpx = {
|
|
5454
|
-
...record.acpx,
|
|
5455
|
-
session_options: next
|
|
5456
|
-
};
|
|
5457
|
-
return;
|
|
5458
|
-
}
|
|
5459
|
-
if (!record.acpx) return;
|
|
5460
|
-
delete record.acpx.session_options;
|
|
5461
|
-
}
|
|
5462
|
-
function sessionOptionsFromRecord(record) {
|
|
5463
|
-
const stored = record.acpx?.session_options;
|
|
5464
|
-
if (!stored) return;
|
|
5465
|
-
const sessionOptions = {};
|
|
5466
|
-
assignStoredOption(sessionOptions, "model", nonEmptyString(stored.model));
|
|
5467
|
-
assignStoredOption(sessionOptions, "allowedTools", storedAllowedTools(stored.allowed_tools));
|
|
5468
|
-
assignStoredOption(sessionOptions, "maxTurns", storedMaxTurns(stored.max_turns));
|
|
5469
|
-
assignStoredOption(sessionOptions, "systemPrompt", storedSystemPromptOption(stored.system_prompt));
|
|
5470
|
-
assignStoredOption(sessionOptions, "env", storedEnvRecord(stored.env));
|
|
5471
|
-
return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
|
|
5472
|
-
}
|
|
5473
|
-
function persistedSessionOptions(options) {
|
|
5474
|
-
const next = {
|
|
5475
|
-
model: nonEmptyString(options.model),
|
|
5476
|
-
allowed_tools: Array.isArray(options.allowedTools) ? [...options.allowedTools] : void 0,
|
|
5477
|
-
max_turns: typeof options.maxTurns === "number" ? options.maxTurns : void 0,
|
|
5478
|
-
system_prompt: normalizeSystemPromptOption(options.systemPrompt),
|
|
5479
|
-
env: storedEnvRecord(options.env)
|
|
5480
|
-
};
|
|
5481
|
-
return hasPersistedSessionOptions(next) ? next : void 0;
|
|
5482
|
-
}
|
|
5483
|
-
function hasPersistedSessionOptions(options) {
|
|
5484
|
-
return options.model !== void 0 || options.allowed_tools !== void 0 || options.max_turns !== void 0 || options.system_prompt !== void 0 || options.env !== void 0;
|
|
5485
|
-
}
|
|
5486
|
-
function storedEnvRecord(value) {
|
|
5487
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) return;
|
|
5488
|
-
const entries = Object.entries(value);
|
|
5489
|
-
const result = {};
|
|
5490
|
-
for (const [key, raw] of entries) {
|
|
5491
|
-
if (typeof raw !== "string") continue;
|
|
5492
|
-
result[key] = raw;
|
|
5493
|
-
}
|
|
5494
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
5495
|
-
}
|
|
5496
|
-
function normalizeSystemPromptOption(value) {
|
|
5497
|
-
const prompt = nonEmptyString(value);
|
|
5498
|
-
if (prompt !== void 0) return prompt;
|
|
5499
|
-
const append = appendedSystemPrompt(value);
|
|
5500
|
-
return append === void 0 ? void 0 : { append };
|
|
5501
|
-
}
|
|
5502
|
-
function appendedSystemPrompt(value) {
|
|
5503
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return;
|
|
5504
|
-
return nonEmptyString(value.append);
|
|
5505
|
-
}
|
|
5506
|
-
function assignStoredOption(target, key, value) {
|
|
5507
|
-
assignDefinedOption(target, key, value);
|
|
5508
|
-
}
|
|
5509
|
-
function storedAllowedTools(value) {
|
|
5510
|
-
return Array.isArray(value) && value.every((item) => typeof item === "string") ? [...value] : void 0;
|
|
5511
|
-
}
|
|
5512
|
-
function storedMaxTurns(value) {
|
|
5513
|
-
return typeof value === "number" ? value : void 0;
|
|
5514
|
-
}
|
|
5515
|
-
function storedSystemPromptOption(value) {
|
|
5516
|
-
return normalizeSystemPromptOption(value);
|
|
5517
|
-
}
|
|
5518
|
-
function nonEmptyString(value) {
|
|
5519
|
-
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
5520
|
-
}
|
|
5521
|
-
//#endregion
|
|
5522
4992
|
//#region src/session/model-state.ts
|
|
5523
4993
|
function configOptionsAreAuthoritative(state) {
|
|
5524
4994
|
return state.model_control === "config_option";
|
|
@@ -5529,7 +4999,7 @@ function legacyModelState(state) {
|
|
|
5529
4999
|
currentModelId: state.current_model_id ?? "",
|
|
5530
5000
|
availableModels: state.available_models.map((modelId) => ({
|
|
5531
5001
|
modelId,
|
|
5532
|
-
name: modelId
|
|
5002
|
+
name: state.available_model_names && Object.hasOwn(state.available_model_names, modelId) ? state.available_model_names[modelId] : modelId
|
|
5533
5003
|
}))
|
|
5534
5004
|
};
|
|
5535
5005
|
}
|
|
@@ -5543,11 +5013,13 @@ function advertisedModelState(state) {
|
|
|
5543
5013
|
function applyAdvertisedModelState(state, models) {
|
|
5544
5014
|
state.current_model_id = models.currentModelId;
|
|
5545
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]));
|
|
5546
5017
|
state.model_control = models.configId ? "config_option" : "legacy_set_model";
|
|
5547
5018
|
}
|
|
5548
5019
|
function clearAdvertisedModelState(state) {
|
|
5549
5020
|
delete state.current_model_id;
|
|
5550
5021
|
delete state.available_models;
|
|
5022
|
+
delete state.available_model_names;
|
|
5551
5023
|
delete state.model_control;
|
|
5552
5024
|
}
|
|
5553
5025
|
function removeModelConfigOptions(state) {
|
|
@@ -5901,6 +5373,7 @@ function cloneSessionAcpxState(state) {
|
|
|
5901
5373
|
desired_config_options: state.desired_config_options ? { ...state.desired_config_options } : void 0,
|
|
5902
5374
|
current_model_id: state.current_model_id,
|
|
5903
5375
|
available_models: state.available_models ? [...state.available_models] : void 0,
|
|
5376
|
+
...state.available_model_names ? { available_model_names: { ...state.available_model_names } } : {},
|
|
5904
5377
|
model_control: state.model_control,
|
|
5905
5378
|
available_commands: state.available_commands ? state.available_commands.map((command) => ({ ...command })) : void 0,
|
|
5906
5379
|
config_options: state.config_options ? deepClone(state.config_options) : void 0,
|
|
@@ -5920,10 +5393,10 @@ function cloneSessionOptions(options) {
|
|
|
5920
5393
|
function cloneSystemPromptOption(option) {
|
|
5921
5394
|
return typeof option === "string" ? option : { append: option.append };
|
|
5922
5395
|
}
|
|
5923
|
-
function recordPromptSubmission(conversation, prompt, timestamp = isoNow()) {
|
|
5396
|
+
function recordPromptSubmission(conversation, prompt, timestamp = isoNow(), messageId) {
|
|
5924
5397
|
const userContent = (typeof prompt === "string" ? textPrompt(prompt) : prompt).map((content) => contentToUserContent(content)).filter((content) => content !== void 0);
|
|
5925
5398
|
if (userContent.length === 0) return;
|
|
5926
|
-
const promptMessageId = nextUserMessageId();
|
|
5399
|
+
const promptMessageId = messageId ?? nextUserMessageId();
|
|
5927
5400
|
conversation.messages.push({ User: {
|
|
5928
5401
|
id: promptMessageId,
|
|
5929
5402
|
content: userContent.map((content) => {
|
|
@@ -5949,10 +5422,10 @@ function hasAgentReplyAfterPrompt(conversation, promptMessageId) {
|
|
|
5949
5422
|
}
|
|
5950
5423
|
return false;
|
|
5951
5424
|
}
|
|
5952
|
-
function recordSessionUpdate(conversation, state, notification, timestamp = isoNow()) {
|
|
5425
|
+
function recordSessionUpdate(conversation, state, notification, timestamp = isoNow(), userMessageId) {
|
|
5953
5426
|
const acpx = ensureAcpxState$1(state);
|
|
5954
5427
|
const update = notification.update;
|
|
5955
|
-
applySessionUpdate(conversation, acpx, update);
|
|
5428
|
+
applySessionUpdate(conversation, acpx, update, userMessageId);
|
|
5956
5429
|
updateConversationTimestamp(conversation, timestamp);
|
|
5957
5430
|
trimConversationForRuntime(conversation);
|
|
5958
5431
|
return acpx;
|
|
@@ -5965,13 +5438,13 @@ function recordPromptResponseUsage(conversation, usage, promptMessageId, timesta
|
|
|
5965
5438
|
trimConversationForRuntime(conversation);
|
|
5966
5439
|
return true;
|
|
5967
5440
|
}
|
|
5968
|
-
function applySessionUpdate(conversation, acpx, update) {
|
|
5441
|
+
function applySessionUpdate(conversation, acpx, update, userMessageId) {
|
|
5969
5442
|
const handler = SESSION_UPDATE_HANDLERS[update.sessionUpdate];
|
|
5970
|
-
handler?.(conversation, acpx, update);
|
|
5443
|
+
handler?.(conversation, acpx, update, userMessageId);
|
|
5971
5444
|
}
|
|
5972
5445
|
const SESSION_UPDATE_HANDLERS = {
|
|
5973
|
-
user_message_chunk: (conversation, _acpx, update) => {
|
|
5974
|
-
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);
|
|
5975
5448
|
},
|
|
5976
5449
|
agent_message_chunk: (conversation, _acpx, update) => {
|
|
5977
5450
|
if (update.sessionUpdate === "agent_message_chunk") appendAgentMessageChunk(conversation, update.content, appendAgentText);
|
|
@@ -6001,11 +5474,11 @@ const SESSION_UPDATE_HANDLERS = {
|
|
|
6001
5474
|
if (update.sessionUpdate === "config_option_update") applyConfigOptionsModelState(acpx, deepClone(update.configOptions));
|
|
6002
5475
|
}
|
|
6003
5476
|
};
|
|
6004
|
-
function appendUserMessageChunk(conversation, content) {
|
|
5477
|
+
function appendUserMessageChunk(conversation, content, messageId) {
|
|
6005
5478
|
const userContent = contentToUserContent(content);
|
|
6006
5479
|
if (!userContent) return;
|
|
6007
5480
|
conversation.messages.push({ User: {
|
|
6008
|
-
id: nextUserMessageId(),
|
|
5481
|
+
id: messageId ?? nextUserMessageId(),
|
|
6009
5482
|
content: [userContent]
|
|
6010
5483
|
} });
|
|
6011
5484
|
}
|
|
@@ -6029,7 +5502,7 @@ function applySessionInfoUpdate(conversation, update) {
|
|
|
6029
5502
|
if (hasOwn(update, "title")) conversation.title = update.title ?? null;
|
|
6030
5503
|
if (hasOwn(update, "updatedAt")) conversation.updated_at = update.updatedAt ?? conversation.updated_at;
|
|
6031
5504
|
}
|
|
6032
|
-
function recordClientOperation(conversation, state,
|
|
5505
|
+
function recordClientOperation(conversation, state, _operation, timestamp = isoNow()) {
|
|
6033
5506
|
const acpx = ensureAcpxState$1(state);
|
|
6034
5507
|
updateConversationTimestamp(conversation, timestamp);
|
|
6035
5508
|
trimConversationForRuntime(conversation);
|
|
@@ -6068,6 +5541,147 @@ function trimRuntimeToolResult(result) {
|
|
|
6068
5541
|
if (typeof result.output === "string") result.output = trimRuntimeText(result.output, MAX_RUNTIME_TOOL_IO_CHARS);
|
|
6069
5542
|
}
|
|
6070
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
|
|
6071
5685
|
//#region src/session/mode-preference.ts
|
|
6072
5686
|
function ensureAcpxState(state) {
|
|
6073
5687
|
return state ?? {};
|
|
@@ -6158,6 +5772,11 @@ function applyConfigOptionsToRecord(record, result) {
|
|
|
6158
5772
|
if (!configOptions) return;
|
|
6159
5773
|
record.acpx = applyConfigOptionsToState(record.acpx, configOptions);
|
|
6160
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
|
+
}
|
|
6161
5780
|
function applyAcceptedConfigOptions(state, response) {
|
|
6162
5781
|
const next = cloneSessionAcpxState(state) ?? {};
|
|
6163
5782
|
if (!response) return next;
|
|
@@ -6192,15 +5811,6 @@ function applyConfigOptionSelection(state, configId, value, response, modelConfi
|
|
|
6192
5811
|
}
|
|
6193
5812
|
//#endregion
|
|
6194
5813
|
//#region src/runtime/engine/reconnect.ts
|
|
6195
|
-
function isProcessAlive(pid) {
|
|
6196
|
-
if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
|
|
6197
|
-
try {
|
|
6198
|
-
process.kill(pid, 0);
|
|
6199
|
-
return true;
|
|
6200
|
-
} catch {
|
|
6201
|
-
return false;
|
|
6202
|
-
}
|
|
6203
|
-
}
|
|
6204
5814
|
const SESSION_LOAD_UNSUPPORTED_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
|
|
6205
5815
|
function shouldFallbackToNewSession(error, record) {
|
|
6206
5816
|
if (isHardReconnectFailure(error)) return false;
|
|
@@ -6318,12 +5928,6 @@ async function connectAndLoadSession(options) {
|
|
|
6318
5928
|
record.closed = false;
|
|
6319
5929
|
record.closedAt = void 0;
|
|
6320
5930
|
options.onConnectedRecord?.(record);
|
|
6321
|
-
let resumed = false;
|
|
6322
|
-
let loadError;
|
|
6323
|
-
let sessionId = record.acpSessionId;
|
|
6324
|
-
let createdFreshSession = false;
|
|
6325
|
-
let pendingAgentSessionId = record.agentSessionId;
|
|
6326
|
-
let sessionModels;
|
|
6327
5931
|
const loadState = await loadOrCreateRuntimeSession({
|
|
6328
5932
|
client,
|
|
6329
5933
|
record,
|
|
@@ -6331,12 +5935,7 @@ async function connectAndLoadSession(options) {
|
|
|
6331
5935
|
sameSessionOnly,
|
|
6332
5936
|
timeoutMs: options.timeoutMs
|
|
6333
5937
|
});
|
|
6334
|
-
resumed = loadState
|
|
6335
|
-
loadError = loadState.loadError;
|
|
6336
|
-
sessionId = loadState.sessionId;
|
|
6337
|
-
createdFreshSession = loadState.createdFreshSession;
|
|
6338
|
-
pendingAgentSessionId = loadState.pendingAgentSessionId;
|
|
6339
|
-
sessionModels = loadState.sessionModels;
|
|
5938
|
+
const { resumed, loadError, sessionId, createdFreshSession, pendingAgentSessionId, sessionModels } = loadState;
|
|
6340
5939
|
const preferenceReplay = await replaySessionPreferences({
|
|
6341
5940
|
client,
|
|
6342
5941
|
record,
|
|
@@ -6474,35 +6073,17 @@ async function loadOrCreateRuntimeSession(params) {
|
|
|
6474
6073
|
resumed: true,
|
|
6475
6074
|
createdFreshSession: false
|
|
6476
6075
|
};
|
|
6477
|
-
if (params.client.supportsResumeSession()) return await
|
|
6478
|
-
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);
|
|
6479
6078
|
if (params.sameSessionOnly) throw makeSessionResumeRequiredError({
|
|
6480
6079
|
record: params.record,
|
|
6481
6080
|
reason: "agent does not support session/resume or session/load"
|
|
6482
6081
|
});
|
|
6483
6082
|
return await createFreshRuntimeSession(params.client, params.record, params.timeoutMs);
|
|
6484
6083
|
}
|
|
6485
|
-
async function
|
|
6486
|
-
try {
|
|
6487
|
-
const resumeResult = await withTimeout(params.client.resumeSession(params.record.acpSessionId, params.record.cwd), params.timeoutMs);
|
|
6488
|
-
reconcileAgentSessionId(params.record, resumeResult.agentSessionId);
|
|
6489
|
-
applyConfigOptionsToRecord(params.record, resumeResult);
|
|
6490
|
-
return {
|
|
6491
|
-
sessionId: params.record.acpSessionId,
|
|
6492
|
-
pendingAgentSessionId: params.record.agentSessionId,
|
|
6493
|
-
sessionModels: resumeResult.models,
|
|
6494
|
-
configOptionsPresent: resumeResult.configOptionsPresent,
|
|
6495
|
-
legacyModelMetadataPresent: resumeResult.legacyModelMetadataPresent,
|
|
6496
|
-
resumed: true,
|
|
6497
|
-
createdFreshSession: false
|
|
6498
|
-
};
|
|
6499
|
-
} catch (error) {
|
|
6500
|
-
return await recoverRuntimeSessionLoadFailure(params, error);
|
|
6501
|
-
}
|
|
6502
|
-
}
|
|
6503
|
-
async function loadRuntimeSession(params) {
|
|
6084
|
+
async function loadRuntimeSession(params, resume) {
|
|
6504
6085
|
try {
|
|
6505
|
-
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);
|
|
6506
6087
|
reconcileAgentSessionId(params.record, loadResult.agentSessionId);
|
|
6507
6088
|
applyConfigOptionsToRecord(params.record, loadResult);
|
|
6508
6089
|
return {
|
|
@@ -6619,7 +6200,7 @@ async function withConnectedSession(options) {
|
|
|
6619
6200
|
resumed,
|
|
6620
6201
|
loadError
|
|
6621
6202
|
});
|
|
6622
|
-
const now = isoNow$
|
|
6203
|
+
const now = isoNow$1();
|
|
6623
6204
|
record.lastUsedAt = now;
|
|
6624
6205
|
record.closed = false;
|
|
6625
6206
|
record.closedAt = void 0;
|
|
@@ -6640,7 +6221,7 @@ async function withConnectedSession(options) {
|
|
|
6640
6221
|
});
|
|
6641
6222
|
else await client.cancelActivePrompt(2500);
|
|
6642
6223
|
applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
|
|
6643
|
-
record.lastUsedAt = isoNow$
|
|
6224
|
+
record.lastUsedAt = isoNow$1();
|
|
6644
6225
|
await options.saveRecord(record).catch(() => {});
|
|
6645
6226
|
await client.close();
|
|
6646
6227
|
});
|
|
@@ -6666,10 +6247,13 @@ function recoveredSessionResult(response, conversation, promptMessageId) {
|
|
|
6666
6247
|
...responseMetaField(response?._meta)
|
|
6667
6248
|
};
|
|
6668
6249
|
}
|
|
6250
|
+
function abortTimedOutRequests(error, client, sessionId) {
|
|
6251
|
+
if (error instanceof TimeoutError) client.endPromptElicitation?.(sessionId);
|
|
6252
|
+
}
|
|
6669
6253
|
async function runPromptTurn(params) {
|
|
6670
6254
|
let settledResponse;
|
|
6671
6255
|
try {
|
|
6672
|
-
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);
|
|
6673
6257
|
promptPromise.then((response) => {
|
|
6674
6258
|
settledResponse = response;
|
|
6675
6259
|
}, () => {});
|
|
@@ -6686,6 +6270,7 @@ async function runPromptTurn(params) {
|
|
|
6686
6270
|
...responseMetaField(response._meta)
|
|
6687
6271
|
};
|
|
6688
6272
|
} catch (error) {
|
|
6273
|
+
abortTimedOutRequests(error, params.client, params.sessionId);
|
|
6689
6274
|
if (!(error instanceof TimeoutError) || !params.promptMessageId) throw error;
|
|
6690
6275
|
await params.client.waitForSessionUpdatesIdle?.({
|
|
6691
6276
|
idleMs: SESSION_REPLY_IDLE_MS,
|
|
@@ -6749,6 +6334,6 @@ var LiveSessionCheckpoint = class {
|
|
|
6749
6334
|
}
|
|
6750
6335
|
};
|
|
6751
6336
|
//#endregion
|
|
6752
|
-
export {
|
|
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 };
|
|
6753
6338
|
|
|
6754
|
-
//# sourceMappingURL=live-checkpoint-
|
|
6339
|
+
//# sourceMappingURL=live-checkpoint-BEfxBKCh.js.map
|