acpx 0.19.2 → 0.19.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/{agent-registry-DWlx5BQ4.js → agent-registry-kHdpsK9F.js} +35 -21
  2. package/dist/agent-registry-kHdpsK9F.js.map +1 -0
  3. package/dist/agent-registry.d.ts.map +1 -1
  4. package/dist/agent-registry.js +1 -1
  5. package/dist/{cli-D-s_eTUy.js → cli-DCtHeMEi.js} +34 -46
  6. package/dist/cli-DCtHeMEi.js.map +1 -0
  7. package/dist/cli.d.ts +1 -1
  8. package/dist/cli.js +57 -40
  9. package/dist/cli.js.map +1 -1
  10. package/dist/{client-BchvQRpz.d.ts → client-DqCXdF0Q.d.ts} +6 -18
  11. package/dist/client-DqCXdF0Q.d.ts.map +1 -0
  12. package/dist/{flows-DdxEaeZo.js → flows--1zpaEh9.js} +38 -14
  13. package/dist/flows--1zpaEh9.js.map +1 -0
  14. package/dist/flows.d.ts +2 -2
  15. package/dist/flows.js +1 -1
  16. package/dist/{invocation-options-HjxSBsK0.js → invocation-options-CvkenzCc.js} +6 -12
  17. package/dist/invocation-options-CvkenzCc.js.map +1 -0
  18. package/dist/{ipc-D0ZMQ0q9.js → ipc-D7zT86b9.js} +430 -307
  19. package/dist/ipc-D7zT86b9.js.map +1 -0
  20. package/dist/{output-GQnhkJMU.js → output-lylSoEBd.js} +12 -4
  21. package/dist/output-lylSoEBd.js.map +1 -0
  22. package/dist/{queue-owner-runtime-W0lly6ap.js → queue-owner-runtime-C0wIYowh.js} +766 -547
  23. package/dist/queue-owner-runtime-C0wIYowh.js.map +1 -0
  24. package/dist/runtime.d.ts +23 -3
  25. package/dist/runtime.d.ts.map +1 -1
  26. package/dist/runtime.js +52 -22
  27. package/dist/runtime.js.map +1 -1
  28. package/dist/{session-options-Dp6mzNSy.d.ts → session-options-X7LhX9BF.d.ts} +2 -1
  29. package/dist/{session-options-Dp6mzNSy.d.ts.map → session-options-X7LhX9BF.d.ts.map} +1 -1
  30. package/dist/{session-watch-_8yxQ6ba.js → session-watch-DPOwDRf8.js} +4 -4
  31. package/dist/{session-watch-_8yxQ6ba.js.map → session-watch-DPOwDRf8.js.map} +1 -1
  32. package/dist/{watch-C0mwpJcN.js → watch-H7rNOJtv.js} +2 -2
  33. package/dist/{watch-C0mwpJcN.js.map → watch-H7rNOJtv.js.map} +1 -1
  34. package/package.json +17 -16
  35. package/skills/acpx/SKILL.md +13 -3
  36. package/dist/agent-registry-DWlx5BQ4.js.map +0 -1
  37. package/dist/cli-D-s_eTUy.js.map +0 -1
  38. package/dist/client-BchvQRpz.d.ts.map +0 -1
  39. package/dist/flows-DdxEaeZo.js.map +0 -1
  40. package/dist/invocation-options-HjxSBsK0.js.map +0 -1
  41. package/dist/ipc-D0ZMQ0q9.js.map +0 -1
  42. package/dist/output-GQnhkJMU.js.map +0 -1
  43. package/dist/queue-owner-runtime-W0lly6ap.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { C as PROCESS_HELPER_TIMEOUT_MS, E as isChildProcessRunning, N as runTimedExecFile, S as PROCESS_HELPER_MAX_BUFFER_BYTES, n as AGENT_REGISTRY, r as BUILT_IN_AGENT_PACKAGES, t as AGENT_ARGV_REGISTRY } from "./agent-registry-DWlx5BQ4.js";
1
+ import { C as PROCESS_HELPER_TIMEOUT_MS, E as isChildProcessRunning, N as runTimedExecFile, P as splitCommandLine, S as PROCESS_HELPER_MAX_BUFFER_BYTES, n as AGENT_REGISTRY, r as BUILT_IN_AGENT_PACKAGES, t as AGENT_ARGV_REGISTRY } from "./agent-registry-kHdpsK9F.js";
2
2
  import fs, { statSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import fs$1 from "node:fs/promises";
@@ -857,9 +857,7 @@ var SessionJournalReader = class {
857
857
  const segments = [];
858
858
  try {
859
859
  const paths = await this.openPresentSegments(segments);
860
- const current = await Promise.all(paths.map(pathIdentity));
861
- const identities = new Map(segments.map((entry) => [entry.filePath, entry.identity]));
862
- if (paths.every((filePath, index) => current[index] === identities.get(filePath))) return segments;
860
+ if (await this.matchesSnapshot(paths, segments)) return segments;
863
861
  } catch (error) {
864
862
  if (!retryableSnapshotError(error)) {
865
863
  await this.closeSnapshot(segments);
@@ -900,10 +898,33 @@ var SessionJournalReader = class {
900
898
  async closeSnapshot(segments) {
901
899
  await Promise.all(segments.map(({ opened }) => opened[Symbol.asyncDispose]()));
902
900
  }
901
+ async matchesSnapshot(paths, segments) {
902
+ const current = await Promise.all(paths.map(pathIdentity));
903
+ const identities = new Map(segments.map((entry) => [entry.filePath, entry.identity]));
904
+ return paths.every((filePath, index) => current[index] === identities.get(filePath));
905
+ }
906
+ async withSnapshot(read, signal) {
907
+ for (;;) {
908
+ const segments = await this.openSnapshot(signal);
909
+ try {
910
+ const outcome = await read(segments).then((value) => ({ value }), (error) => {
911
+ if (!(error instanceof SessionWatchError) || error.code !== "WATCH_JOURNAL_CORRUPT") throw error;
912
+ return { error };
913
+ });
914
+ if (await this.matchesSnapshot(this.paths(), segments)) {
915
+ signal?.throwIfAborted();
916
+ if ("error" in outcome) throw outcome.error;
917
+ return outcome.value;
918
+ }
919
+ } finally {
920
+ await this.closeSnapshot(segments);
921
+ }
922
+ await setTimeout$1(5, void 0, { signal });
923
+ }
924
+ }
903
925
  async readAcpMessages() {
904
- const segments = await this.openSnapshot();
905
- const messages = [];
906
- try {
926
+ return await this.withSnapshot(async (segments) => {
927
+ const messages = [];
907
928
  for (const { opened } of segments) {
908
929
  const payload = await opened.handle.readFile("utf8");
909
930
  for (const line of payload.split("\n")) try {
@@ -912,15 +933,12 @@ var SessionJournalReader = class {
912
933
  } catch {}
913
934
  }
914
935
  return messages;
915
- } finally {
916
- await this.closeSnapshot(segments);
917
- }
936
+ });
918
937
  }
919
938
  async readTail() {
920
- const segments = await this.openSnapshot();
921
- let tail = emptySegment();
922
- let active = emptySegment();
923
- try {
939
+ return await this.withSnapshot(async (segments) => {
940
+ let tail = emptySegment();
941
+ let active = emptySegment();
924
942
  for (const segment of segments.toReversed()) {
925
943
  const state = emptySegment();
926
944
  await this.readSegment(segment.opened.handle, segment.opened.stat.size, state, void 0);
@@ -938,22 +956,20 @@ var SessionJournalReader = class {
938
956
  activeAnchored: active.firstSequence !== void 0,
939
957
  activePartial: active.pending.length > 0
940
958
  };
941
- } finally {
942
- await this.closeSnapshot(segments);
943
- }
959
+ });
944
960
  }
945
961
  async read(signal, options) {
946
- const page = createJournalPage(options);
947
- const segments = await this.openSnapshot(signal);
948
- let hasMore = false;
949
- let firstSequence;
950
- let tail = emptySegment();
951
- let active = emptySegment();
952
- try {
962
+ const { result, states } = await this.withSnapshot(async (segments) => {
963
+ const page = createJournalPage(options);
964
+ const states = new Map(this.states);
965
+ let hasMore = false;
966
+ let firstSequence;
967
+ let tail = emptySegment();
968
+ let active = emptySegment();
953
969
  for (const segment of segments) {
954
- const state = this.states.get(segment.identity) ?? emptySegment();
970
+ const state = { ...states.get(segment.identity) ?? emptySegment() };
955
971
  await this.readSegment(segment.opened.handle, segment.opened.stat.size, state, page, signal);
956
- this.states.set(segment.identity, state);
972
+ states.set(segment.identity, state);
957
973
  if (state.firstSequence !== void 0) {
958
974
  if (firstSequence === void 0) firstSequence = state.firstSequence;
959
975
  else if (state.firstSequence !== tail.sequence) corrupt("Session journal segments are not contiguous");
@@ -965,25 +981,29 @@ var SessionJournalReader = class {
965
981
  break;
966
982
  }
967
983
  }
968
- this.pruneStates(segments);
984
+ this.pruneStates(states, segments);
969
985
  return {
970
- events: page.events,
971
- hasMore,
972
- firstSequence,
973
- sequence: tail.sequence,
974
- messageSequence: tail.messageSequence,
975
- requestId: tail.requestId,
976
- activeSize: active.offset,
977
- activeAnchored: active.firstSequence !== void 0,
978
- activePartial: active.pending.length > 0
986
+ states,
987
+ result: {
988
+ events: page.events,
989
+ hasMore,
990
+ firstSequence,
991
+ sequence: tail.sequence,
992
+ messageSequence: tail.messageSequence,
993
+ requestId: tail.requestId,
994
+ activeSize: active.offset,
995
+ activeAnchored: active.firstSequence !== void 0,
996
+ activePartial: active.pending.length > 0
997
+ }
979
998
  };
980
- } finally {
981
- await this.closeSnapshot(segments);
982
- }
999
+ }, signal);
1000
+ signal?.throwIfAborted();
1001
+ this.states = states;
1002
+ return result;
983
1003
  }
984
- pruneStates(segments) {
1004
+ pruneStates(states, segments) {
985
1005
  const retained = new Set(segments.map((entry) => entry.identity));
986
- for (const identity of this.states.keys()) if (!retained.has(identity)) this.states.delete(identity);
1006
+ for (const identity of states.keys()) if (!retained.has(identity)) states.delete(identity);
987
1007
  }
988
1008
  async readSegment(handle, size, state, page, signal) {
989
1009
  if (size < state.offset) corrupt("Session journal was truncated while watching");
@@ -1244,7 +1264,8 @@ const LEGACY_AGENT_COMMANDS = {
1244
1264
  pi: [
1245
1265
  "npx pi-acp",
1246
1266
  "npx pi-acp@^0.0.22",
1247
- "npx pi-acp@^0.0.26"
1267
+ "npx pi-acp@^0.0.26",
1268
+ "npx pi-acp@^0.0.31"
1248
1269
  ],
1249
1270
  codex: [
1250
1271
  "npx @zed-industries/codex-acp",
@@ -1263,10 +1284,19 @@ const LEGACY_AGENT_COMMANDS = {
1263
1284
  "npx -y @zed-industries/claude-agent-acp@^0.24.2",
1264
1285
  "npx -y @zed-industries/claude-agent-acp@^0.25.0",
1265
1286
  "npx -y @zed-industries/claude-agent-acp@^0.31.0",
1287
+ "npx -y @agentclientprotocol/claude-agent-acp@^0.24.2",
1288
+ "npx -y @agentclientprotocol/claude-agent-acp@^0.25.0",
1289
+ "npx -y @agentclientprotocol/claude-agent-acp@^0.31.0",
1266
1290
  "npx -y @agentclientprotocol/claude-agent-acp@^0.36.1",
1267
1291
  "npx -y @agentclientprotocol/claude-agent-acp@^0.37.0",
1292
+ "npx -y @agentclientprotocol/claude-agent-acp@^0.60.0",
1293
+ "npx -y @agentclientprotocol/claude-agent-acp@^0.76.0",
1294
+ "npm exec @agentclientprotocol/claude-agent-acp@^0.25.0",
1295
+ "npm exec @agentclientprotocol/claude-agent-acp@^0.31.0",
1268
1296
  "npm exec @agentclientprotocol/claude-agent-acp@^0.36.1",
1269
- "npm exec @agentclientprotocol/claude-agent-acp@^0.37.0"
1297
+ "npm exec @agentclientprotocol/claude-agent-acp@^0.37.0",
1298
+ "npm exec @agentclientprotocol/claude-agent-acp@^0.60.0",
1299
+ "npm exec @agentclientprotocol/claude-agent-acp@^0.76.0"
1270
1300
  ],
1271
1301
  gemini: ["gemini", "gemini --experimental-acp"],
1272
1302
  kiro: ["kiro-cli acp"],
@@ -1277,10 +1307,52 @@ function currentArgv(name) {
1277
1307
  const argv = AGENT_ARGV_REGISTRY[name];
1278
1308
  return argv ? [...argv] : void 0;
1279
1309
  }
1310
+ function isFallbackCommand(name, agentCommand) {
1311
+ return (BUILT_IN_AGENT_PACKAGES[name]?.legacyFallbackCommands ?? []).includes(agentCommand);
1312
+ }
1313
+ /** Built-in agent whose current or earlier default command is exactly `agentCommand`. */
1314
+ function builtInAgentForCommand(agentCommand) {
1315
+ return Object.keys(AGENT_REGISTRY).find((name) => AGENT_REGISTRY[name] === agentCommand) ?? Object.keys(BUILT_IN_AGENT_PACKAGES).find((name) => isFallbackCommand(name, agentCommand)) ?? Object.keys(LEGACY_AGENT_COMMANDS).find((name) => LEGACY_AGENT_COMMANDS[name].includes(agentCommand));
1316
+ }
1280
1317
  function resolveAgentArgvForCommand(agentCommand) {
1281
- for (const [name, command] of Object.entries(AGENT_REGISTRY)) if (command === agentCommand) return currentArgv(name);
1282
- for (const [name, spec] of Object.entries(BUILT_IN_AGENT_PACKAGES)) if ((spec.legacyFallbackCommands ?? []).includes(agentCommand)) return currentArgv(name);
1283
- for (const [name, commands] of Object.entries(LEGACY_AGENT_COMMANDS)) if (commands.includes(agentCommand)) return currentArgv(name);
1318
+ const name = builtInAgentForCommand(agentCommand);
1319
+ return name ? currentArgv(name) : void 0;
1320
+ }
1321
+ function commandArgv(agentCommand) {
1322
+ const { command, args } = splitCommandLine(agentCommand);
1323
+ return [command, ...args];
1324
+ }
1325
+ function sameArgv(left, right) {
1326
+ return left.length === right.length && left.every((value, index) => value === right[index]);
1327
+ }
1328
+ function launchesBuiltIn(agentCommand, agentArgv, name) {
1329
+ return agentArgv === void 0 || sameArgv(agentArgv, commandArgv(agentCommand)) || sameArgv(agentArgv, AGENT_ARGV_REGISTRY[name] ?? []);
1330
+ }
1331
+ /**
1332
+ * Maps a saved launch identity from an earlier built-in default onto the current
1333
+ * built-in command and argv, so agent-scoped lookup keeps finding the session
1334
+ * after an adapter range change. Identities with a custom argv, and commands
1335
+ * acpx never shipped as a built-in default, are returned unchanged.
1336
+ */
1337
+ function migrateBuiltInAgentIdentity(agentCommand, agentArgv) {
1338
+ const name = builtInAgentForCommand(agentCommand);
1339
+ const current = name ? AGENT_REGISTRY[name] : void 0;
1340
+ if (!name || !current || current === agentCommand) return {
1341
+ agentCommand,
1342
+ agentArgv
1343
+ };
1344
+ if (!launchesBuiltIn(agentCommand, agentArgv, name)) return {
1345
+ agentCommand,
1346
+ agentArgv
1347
+ };
1348
+ return {
1349
+ agentCommand: current,
1350
+ agentArgv: currentArgv(name)
1351
+ };
1352
+ }
1353
+ /** The agent command a session saved under `agentCommand` is filed under after migration. */
1354
+ function canonicalAgentCommand(agentCommand) {
1355
+ return migrateBuiltInAgentIdentity(agentCommand).agentCommand;
1284
1356
  }
1285
1357
  //#endregion
1286
1358
  //#region src/session/persistence/parse.ts
@@ -1297,8 +1369,12 @@ function isStringArray(value) {
1297
1369
  function parseOptionalAgentArgv(value) {
1298
1370
  return isStringArray(value) && value.length > 0 && value[0]?.length > 0 ? value : void 0;
1299
1371
  }
1300
- function parsePersistedAgentArgv(record) {
1301
- return parseOptionalAgentArgv(record.agent_argv) ?? (typeof record.agent_command === "string" ? resolveAgentArgvForCommand(record.agent_command) : void 0);
1372
+ function parsePersistedAgentIdentity(agentCommand, rawArgv) {
1373
+ const identity = migrateBuiltInAgentIdentity(agentCommand, parseOptionalAgentArgv(rawArgv));
1374
+ return {
1375
+ agentCommand: identity.agentCommand,
1376
+ agentArgv: identity.agentArgv ?? resolveAgentArgvForCommand(identity.agentCommand)
1377
+ };
1302
1378
  }
1303
1379
  function hasModelConfigOption(options) {
1304
1380
  if (!Array.isArray(options)) return false;
@@ -1394,16 +1470,24 @@ function parseRequestTokenUsage(raw) {
1394
1470
  for (const [key, value] of Object.entries(record)) {
1395
1471
  const parsed = parseTokenUsage(value);
1396
1472
  if (parsed == null) return null;
1397
- usage[key] = parsed;
1473
+ Object.defineProperty(usage, key, {
1474
+ value: parsed,
1475
+ writable: true,
1476
+ enumerable: true,
1477
+ configurable: true
1478
+ });
1398
1479
  }
1399
1480
  return usage;
1400
1481
  }
1482
+ function isValidImageSize(size) {
1483
+ if (size === void 0 || size === null) return true;
1484
+ const record = asRecord$2(size);
1485
+ return !!record && isFiniteNumber(record.width) && isFiniteNumber(record.height);
1486
+ }
1401
1487
  function isSessionMessageImage(raw) {
1402
1488
  const record = asRecord$2(raw);
1403
- if (!record || typeof record.source !== "string") return false;
1404
- if (record.size === void 0 || record.size === null) return true;
1405
- const size = asRecord$2(record.size);
1406
- return !!size && isFiniteNumber(size.width) && isFiniteNumber(size.height);
1489
+ if (!record || typeof record.source !== "string" || !isOptionalString(record.mime_type)) return false;
1490
+ return isValidImageSize(record.size);
1407
1491
  }
1408
1492
  function isSessionMessageAudio(raw) {
1409
1493
  const record = asRecord$2(raw);
@@ -1650,13 +1734,14 @@ function parseSessionRecord(raw) {
1650
1734
  const eventLog = parseEventLog(record.event_log, record.acpx_record_id);
1651
1735
  const metadata = parseSessionRecordMetadata(record);
1652
1736
  if (!metadata) return null;
1737
+ const agent = parsePersistedAgentIdentity(record.agent_command, record.agent_argv);
1653
1738
  return {
1654
1739
  schema: SESSION_RECORD_SCHEMA,
1655
1740
  acpxRecordId: record.acpx_record_id,
1656
1741
  acpSessionId: record.acp_session_id,
1657
1742
  agentSessionId: normalizeAgentSessionId(record.agent_session_id),
1658
- agentCommand: record.agent_command,
1659
- agentArgv: parsePersistedAgentArgv(record),
1743
+ agentCommand: agent.agentCommand,
1744
+ agentArgv: agent.agentArgv,
1660
1745
  cwd: record.cwd,
1661
1746
  name: optionals.name,
1662
1747
  createdAt: record.created_at,
@@ -1826,8 +1911,16 @@ async function* sessionRecords(readOnly = false) {
1826
1911
  if (!readOnly) await ensureSessionDir();
1827
1912
  yield* scanSessionRecords(sessionBaseDir());
1828
1913
  }
1829
- function matchesSession(session, agentCommand, normalizedName, includeClosed = false) {
1830
- if (session.agentCommand !== agentCommand) return false;
1914
+ /**
1915
+ * Commands a scoped query matches: the query itself, plus the current built-in
1916
+ * command when the query is an earlier built-in default (records under it are
1917
+ * migrated on read unless they carry a custom launcher).
1918
+ */
1919
+ function agentScope(agentCommand) {
1920
+ return /* @__PURE__ */ new Set([agentCommand, canonicalAgentCommand(agentCommand)]);
1921
+ }
1922
+ function matchesSession(session, scope, normalizedName, includeClosed = false) {
1923
+ if (!scope.has(session.agentCommand)) return false;
1831
1924
  if (!includeClosed && session.closed) return false;
1832
1925
  if (normalizedName == null) return session.name == null;
1833
1926
  return session.name === normalizedName;
@@ -1929,25 +2022,28 @@ async function listSessionsForAgent(agentCommand) {
1929
2022
  return await collectSessionRecords(agentCommand);
1930
2023
  }
1931
2024
  async function collectSessionRecords(agentCommand) {
2025
+ const scope = agentCommand === void 0 ? void 0 : agentScope(agentCommand);
1932
2026
  const records = [];
1933
- for await (const record of sessionRecords()) if (agentCommand === void 0 || record.agentCommand === agentCommand) records.push(record);
2027
+ for await (const record of sessionRecords()) if (scope === void 0 || scope.has(record.agentCommand)) records.push(record);
1934
2028
  return records.toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt));
1935
2029
  }
1936
2030
  async function findSession(options) {
1937
2031
  const normalizedCwd = absolutePath(options.cwd);
1938
2032
  const normalizedName = normalizeName(options.name);
2033
+ const scope = agentScope(options.agentCommand);
1939
2034
  let match;
1940
- for await (const record of sessionRecords(options.readOnly)) if (record.cwd === normalizedCwd && matchesSession(record, options.agentCommand, normalizedName, options.includeClosed) && isNewer(record, match)) match = record;
2035
+ for await (const record of sessionRecords(options.readOnly)) if (record.cwd === normalizedCwd && matchesSession(record, scope, normalizedName, options.includeClosed) && isNewer(record, match)) match = record;
1941
2036
  return match;
1942
2037
  }
1943
2038
  async function findSessionByDirectoryWalk(options) {
1944
2039
  const normalizedName = normalizeName(options.name);
2040
+ const scope = agentScope(options.agentCommand);
1945
2041
  const directories = walkDirectories(options);
1946
2042
  let match;
1947
2043
  let distance = Infinity;
1948
2044
  for await (const record of sessionRecords()) {
1949
2045
  const candidateDistance = directories.get(record.cwd);
1950
- if (candidateDistance !== void 0 && matchesSession(record, options.agentCommand, normalizedName) && (candidateDistance < distance || candidateDistance === distance && isNewer(record, match))) {
2046
+ if (candidateDistance !== void 0 && matchesSession(record, scope, normalizedName) && (candidateDistance < distance || candidateDistance === distance && isNewer(record, match))) {
1951
2047
  match = record;
1952
2048
  distance = candidateDistance;
1953
2049
  }
@@ -2000,13 +2096,14 @@ async function pruneSessions(options = {}) {
2000
2096
  dryRun: false
2001
2097
  };
2002
2098
  }
2003
- function isPruneCandidate(record, agentCommand) {
2004
- return record.closed === true && (!agentCommand || record.agentCommand === agentCommand);
2099
+ function isPruneCandidate(record, scope) {
2100
+ return record.closed === true && (!scope || scope.has(record.agentCommand));
2005
2101
  }
2006
2102
  async function loadPrunableRecords(cutoff, agentCommand) {
2007
2103
  const records = [];
2008
2104
  const cutoffIso = cutoff?.toISOString();
2009
- for await (const record of sessionRecords()) if (isPruneCandidate(record, agentCommand) && isBeforeCutoff(record, cutoffIso)) records.push(record);
2105
+ const scope = agentCommand === void 0 ? void 0 : agentScope(agentCommand);
2106
+ for await (const record of sessionRecords()) if (isPruneCandidate(record, scope) && isBeforeCutoff(record, cutoffIso)) records.push(record);
2010
2107
  return records.toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt));
2011
2108
  }
2012
2109
  function isBeforeCutoff(record, cutoffIso) {
@@ -2027,182 +2124,6 @@ async function unlinkCountingBytes(filePath) {
2027
2124
  return bytes;
2028
2125
  }
2029
2126
  //#endregion
2030
- //#region src/prompt-content.ts
2031
- var PromptInputValidationError = class extends Error {
2032
- constructor(message) {
2033
- super(message);
2034
- this.name = "PromptInputValidationError";
2035
- }
2036
- };
2037
- function asRecord$1(value) {
2038
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
2039
- return value;
2040
- }
2041
- function isNonEmptyString(value) {
2042
- return typeof value === "string" && value.trim().length > 0;
2043
- }
2044
- function isBase64Data(value) {
2045
- if (value.length === 0 || value.length % 4 !== 0) return false;
2046
- return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
2047
- }
2048
- function isImageMimeType(value) {
2049
- return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
2050
- }
2051
- function isAudioMimeType(value) {
2052
- return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
2053
- }
2054
- function isTextBlock(value) {
2055
- const record = asRecord$1(value);
2056
- return record?.type === "text" && typeof record.text === "string";
2057
- }
2058
- function isImageBlock(value) {
2059
- const record = asRecord$1(value);
2060
- return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2061
- }
2062
- function isAudioBlock(value) {
2063
- const record = asRecord$1(value);
2064
- return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2065
- }
2066
- function isResourceLinkBlock(value) {
2067
- const record = asRecord$1(value);
2068
- return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title == null || typeof record.title === "string") && typeof record.name === "string";
2069
- }
2070
- function isResourcePayload(value) {
2071
- const record = asRecord$1(value);
2072
- if (!record || !isNonEmptyString(record.uri)) return false;
2073
- return typeof record.text === "string" || typeof record.blob === "string";
2074
- }
2075
- function isResourceBlock(value) {
2076
- const record = asRecord$1(value);
2077
- return record?.type === "resource" && isResourcePayload(record.resource);
2078
- }
2079
- const CONTENT_BLOCK_VALIDATORS = [
2080
- isTextBlock,
2081
- isImageBlock,
2082
- isAudioBlock,
2083
- isResourceLinkBlock,
2084
- isResourceBlock
2085
- ];
2086
- function isContentBlock(value) {
2087
- return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
2088
- }
2089
- const CONTENT_BLOCK_ERROR_VALIDATORS = {
2090
- text: validateTextContentBlock,
2091
- image: validateImageContentBlock,
2092
- audio: validateAudioContentBlock,
2093
- resource_link: validateResourceLinkContentBlock,
2094
- resource: validateResourceContentBlock
2095
- };
2096
- function contentBlockErrorValidator(type) {
2097
- return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
2098
- }
2099
- function validateTextContentBlock(record, index) {
2100
- return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
2101
- }
2102
- function validateImageContentBlock(record, index) {
2103
- if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
2104
- if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
2105
- if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
2106
- return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
2107
- }
2108
- function validateAudioContentBlock(record, index) {
2109
- if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
2110
- if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
2111
- if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
2112
- return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
2113
- }
2114
- function validateResourceLinkContentBlock(record, index) {
2115
- if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
2116
- if (record.title != null && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string or null when present`;
2117
- if (typeof record.name !== "string") return `prompt[${index}] resource_link block must include a string name`;
2118
- }
2119
- function validateResourceContentBlock(record, index) {
2120
- if (!asRecord$1(record.resource)) return `prompt[${index}] resource block must include a resource object`;
2121
- return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and a string text or blob field`;
2122
- }
2123
- function getContentBlockValidationError(value, index) {
2124
- const record = asRecord$1(value);
2125
- if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
2126
- const validator = contentBlockErrorValidator(record.type);
2127
- return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
2128
- }
2129
- function isPromptInput(value) {
2130
- return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
2131
- }
2132
- function promptCapabilityRequirement(block) {
2133
- switch (block.type) {
2134
- case "image": return {
2135
- blockType: "image",
2136
- capability: "image"
2137
- };
2138
- case "audio": return {
2139
- blockType: "audio",
2140
- capability: "audio"
2141
- };
2142
- case "resource": return {
2143
- blockType: "resource",
2144
- capability: "embeddedContext"
2145
- };
2146
- default: return;
2147
- }
2148
- }
2149
- function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
2150
- for (const [index, block] of prompt.entries()) {
2151
- const requirement = promptCapabilityRequirement(block);
2152
- if (!requirement) continue;
2153
- if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
2154
- return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
2155
- }
2156
- }
2157
- function textPrompt(text) {
2158
- return [{
2159
- type: "text",
2160
- text
2161
- }];
2162
- }
2163
- function parseStructuredPrompt(source) {
2164
- if (!source.startsWith("[")) return;
2165
- try {
2166
- const parsed = JSON.parse(source);
2167
- if (isPromptInput(parsed)) return parsed;
2168
- 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");
2169
- return;
2170
- } catch (error) {
2171
- if (error instanceof PromptInputValidationError) throw error;
2172
- return;
2173
- }
2174
- }
2175
- function parsePromptSource(source) {
2176
- const trimmed = source.trim();
2177
- const structured = parseStructuredPrompt(trimmed);
2178
- if (structured) return structured;
2179
- if (!trimmed) return [];
2180
- return textPrompt(trimmed);
2181
- }
2182
- function mergePromptSourceWithText(source, suffixText) {
2183
- const prompt = parsePromptSource(source);
2184
- const appended = suffixText.trim();
2185
- if (!appended) return prompt;
2186
- if (prompt.length === 0) return textPrompt(appended);
2187
- return [...prompt, ...textPrompt(appended)];
2188
- }
2189
- function promptToDisplayText(prompt) {
2190
- return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
2191
- }
2192
- function contentBlockDisplayText(block) {
2193
- switch (block.type) {
2194
- case "text": return block.text;
2195
- case "resource_link": return block.title ?? block.name ?? block.uri;
2196
- case "resource": return resourceBlockDisplayText(block);
2197
- case "image": return `[image] ${block.mimeType}`;
2198
- case "audio": return `[audio] ${block.mimeType}`;
2199
- default: return "";
2200
- }
2201
- }
2202
- function resourceBlockDisplayText(block) {
2203
- return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
2204
- }
2205
- //#endregion
2206
2127
  //#region src/process-identity.ts
2207
2128
  const IDENTITY_QUERY_TIMEOUT_MS$1 = 2e3;
2208
2129
  const LINUX_PROCESS_QUERY = `
@@ -2599,6 +2520,222 @@ async function getOwnProcessIdentity() {
2599
2520
  return await ownIdentityPending;
2600
2521
  }
2601
2522
  //#endregion
2523
+ //#region src/session/lock-owner.ts
2524
+ const OBSERVATION_REUSE_MS = 1e3;
2525
+ const IDENTITY_QUERY_TIMEOUT_MS = 1e3;
2526
+ function lockOwnerPid(value) {
2527
+ if (!value || typeof value !== "object" || !("pid" in value)) return;
2528
+ const pid = value.pid;
2529
+ return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
2530
+ }
2531
+ function canReuseObservation(preserved, pid, identity, fresh) {
2532
+ return !fresh && preserved?.pid === pid && compareProcessBirthIdentity(preserved.identity, identity) === "matching" && performance.now() - preserved.checkedAt < OBSERVATION_REUSE_MS;
2533
+ }
2534
+ async function createLockOwner(options = {}) {
2535
+ const { signal, capturedIdentity } = options;
2536
+ signal?.throwIfAborted();
2537
+ const processIdentity = capturedIdentity === void 0 ? await getOwnProcessIdentity() : capturedIdentity.processIdentity;
2538
+ signal?.throwIfAborted();
2539
+ let preserved;
2540
+ return {
2541
+ payload: {
2542
+ pid: process.pid,
2543
+ processIdentity
2544
+ },
2545
+ async hasExited(payload, fresh, signal) {
2546
+ signal?.throwIfAborted();
2547
+ const pid = lockOwnerPid(payload);
2548
+ if (!pid) return false;
2549
+ const identity = parseProcessBirthIdentity(payload.processIdentity);
2550
+ if (identity && canReuseObservation(preserved, pid, identity, fresh)) return false;
2551
+ const incarnation = await observeProcessIncarnation(pid, identity, IDENTITY_QUERY_TIMEOUT_MS);
2552
+ signal?.throwIfAborted();
2553
+ if (identity && incarnation !== "gone") preserved = {
2554
+ pid,
2555
+ identity,
2556
+ checkedAt: performance.now()
2557
+ };
2558
+ return incarnation === "gone";
2559
+ }
2560
+ };
2561
+ }
2562
+ //#endregion
2563
+ //#region src/prompt-content.ts
2564
+ var PromptInputValidationError = class extends Error {
2565
+ constructor(message) {
2566
+ super(message);
2567
+ this.name = "PromptInputValidationError";
2568
+ }
2569
+ };
2570
+ function asRecord$1(value) {
2571
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
2572
+ return value;
2573
+ }
2574
+ function isNonEmptyString(value) {
2575
+ return typeof value === "string" && value.trim().length > 0;
2576
+ }
2577
+ function isBase64Data(value) {
2578
+ if (value.length === 0 || value.length % 4 !== 0) return false;
2579
+ return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
2580
+ }
2581
+ function isImageMimeType(value) {
2582
+ return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
2583
+ }
2584
+ function isAudioMimeType(value) {
2585
+ return /^audio\/[A-Za-z0-9.+-]+$/i.test(value);
2586
+ }
2587
+ function isTextBlock(value) {
2588
+ const record = asRecord$1(value);
2589
+ return record?.type === "text" && typeof record.text === "string";
2590
+ }
2591
+ function isImageBlock(value) {
2592
+ const record = asRecord$1(value);
2593
+ return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2594
+ }
2595
+ function isAudioBlock(value) {
2596
+ const record = asRecord$1(value);
2597
+ return record?.type === "audio" && isNonEmptyString(record.mimeType) && isAudioMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
2598
+ }
2599
+ function isResourceLinkBlock(value) {
2600
+ const record = asRecord$1(value);
2601
+ return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title == null || typeof record.title === "string") && typeof record.name === "string";
2602
+ }
2603
+ function isResourcePayload(value) {
2604
+ const record = asRecord$1(value);
2605
+ if (!record || !isNonEmptyString(record.uri)) return false;
2606
+ return typeof record.text === "string" || typeof record.blob === "string";
2607
+ }
2608
+ function isResourceBlock(value) {
2609
+ const record = asRecord$1(value);
2610
+ return record?.type === "resource" && isResourcePayload(record.resource);
2611
+ }
2612
+ const CONTENT_BLOCK_VALIDATORS = [
2613
+ isTextBlock,
2614
+ isImageBlock,
2615
+ isAudioBlock,
2616
+ isResourceLinkBlock,
2617
+ isResourceBlock
2618
+ ];
2619
+ function isContentBlock(value) {
2620
+ return CONTENT_BLOCK_VALIDATORS.some((validator) => validator(value));
2621
+ }
2622
+ const CONTENT_BLOCK_ERROR_VALIDATORS = {
2623
+ text: validateTextContentBlock,
2624
+ image: validateImageContentBlock,
2625
+ audio: validateAudioContentBlock,
2626
+ resource_link: validateResourceLinkContentBlock,
2627
+ resource: validateResourceContentBlock
2628
+ };
2629
+ function contentBlockErrorValidator(type) {
2630
+ return Object.hasOwn(CONTENT_BLOCK_ERROR_VALIDATORS, type) ? CONTENT_BLOCK_ERROR_VALIDATORS[type] : void 0;
2631
+ }
2632
+ function validateTextContentBlock(record, index) {
2633
+ return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
2634
+ }
2635
+ function validateImageContentBlock(record, index) {
2636
+ if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
2637
+ if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
2638
+ if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
2639
+ return isBase64Data(record.data) ? void 0 : `prompt[${index}] image block data must be valid base64`;
2640
+ }
2641
+ function validateAudioContentBlock(record, index) {
2642
+ if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] audio block must include a non-empty mimeType`;
2643
+ if (!isAudioMimeType(record.mimeType)) return `prompt[${index}] audio block mimeType must start with audio/`;
2644
+ if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] audio block must include non-empty base64 data`;
2645
+ return isBase64Data(record.data) ? void 0 : `prompt[${index}] audio block data must be valid base64`;
2646
+ }
2647
+ function validateResourceLinkContentBlock(record, index) {
2648
+ if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
2649
+ if (record.title != null && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string or null when present`;
2650
+ if (typeof record.name !== "string") return `prompt[${index}] resource_link block must include a string name`;
2651
+ }
2652
+ function validateResourceContentBlock(record, index) {
2653
+ if (!asRecord$1(record.resource)) return `prompt[${index}] resource block must include a resource object`;
2654
+ return isResourcePayload(record.resource) ? void 0 : `prompt[${index}] resource block resource must include a non-empty uri and a string text or blob field`;
2655
+ }
2656
+ function getContentBlockValidationError(value, index) {
2657
+ const record = asRecord$1(value);
2658
+ if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
2659
+ const validator = contentBlockErrorValidator(record.type);
2660
+ return validator ? validator(record, index) : `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
2661
+ }
2662
+ function isPromptInput(value) {
2663
+ return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
2664
+ }
2665
+ function promptCapabilityRequirement(block) {
2666
+ switch (block.type) {
2667
+ case "image": return {
2668
+ blockType: "image",
2669
+ capability: "image"
2670
+ };
2671
+ case "audio": return {
2672
+ blockType: "audio",
2673
+ capability: "audio"
2674
+ };
2675
+ case "resource": return {
2676
+ blockType: "resource",
2677
+ capability: "embeddedContext"
2678
+ };
2679
+ default: return;
2680
+ }
2681
+ }
2682
+ function getUnsupportedPromptContentMessage(prompt, agentCapabilities) {
2683
+ for (const [index, block] of prompt.entries()) {
2684
+ const requirement = promptCapabilityRequirement(block);
2685
+ if (!requirement) continue;
2686
+ if (agentCapabilities?.promptCapabilities?.[requirement.capability] === true) continue;
2687
+ return `prompt[${index}] ${requirement.blockType} content requires agentCapabilities.promptCapabilities.${requirement.capability}`;
2688
+ }
2689
+ }
2690
+ function textPrompt(text) {
2691
+ return [{
2692
+ type: "text",
2693
+ text
2694
+ }];
2695
+ }
2696
+ function parseStructuredPrompt(source) {
2697
+ if (!source.startsWith("[")) return;
2698
+ try {
2699
+ const parsed = JSON.parse(source);
2700
+ if (isPromptInput(parsed)) return parsed;
2701
+ 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");
2702
+ return;
2703
+ } catch (error) {
2704
+ if (error instanceof PromptInputValidationError) throw error;
2705
+ return;
2706
+ }
2707
+ }
2708
+ function parsePromptSource(source) {
2709
+ const trimmed = source.trim();
2710
+ const structured = parseStructuredPrompt(trimmed);
2711
+ if (structured) return structured;
2712
+ if (!trimmed) return [];
2713
+ return textPrompt(trimmed);
2714
+ }
2715
+ function mergePromptSourceWithText(source, suffixText) {
2716
+ const prompt = parsePromptSource(source);
2717
+ const appended = suffixText.trim();
2718
+ if (!appended) return prompt;
2719
+ if (prompt.length === 0) return textPrompt(appended);
2720
+ return [...prompt, ...textPrompt(appended)];
2721
+ }
2722
+ function promptToDisplayText(prompt) {
2723
+ return prompt.map((block) => contentBlockDisplayText(block)).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
2724
+ }
2725
+ function contentBlockDisplayText(block) {
2726
+ switch (block.type) {
2727
+ case "text": return block.text;
2728
+ case "resource_link": return block.title ?? block.name ?? block.uri;
2729
+ case "resource": return resourceBlockDisplayText(block);
2730
+ case "image": return `[image] ${block.mimeType}`;
2731
+ case "audio": return `[audio] ${block.mimeType}`;
2732
+ default: return "";
2733
+ }
2734
+ }
2735
+ function resourceBlockDisplayText(block) {
2736
+ return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
2737
+ }
2738
+ //#endregion
2602
2739
  //#region src/acp/process-descendants.ts
2603
2740
  function hasStaleWindowsParent(identity, parent) {
2604
2741
  return identity.birth.kind === "windows-creation" && (parent?.birth.kind !== "windows-creation" || parent.birth.value > identity.birth.value);
@@ -2623,6 +2760,8 @@ var ProcessDescendants = class {
2623
2760
  rootBirth;
2624
2761
  pending;
2625
2762
  retired = false;
2763
+ failedRootObservation = false;
2764
+ unresolvedOwnership = false;
2626
2765
  ownProcessGroup;
2627
2766
  captureGroupAfterExit;
2628
2767
  groupExitedAt;
@@ -2657,10 +2796,18 @@ var ProcessDescendants = class {
2657
2796
  }
2658
2797
  return true;
2659
2798
  } catch {
2660
- if (!isChildProcessRunning(this.child)) this.captureGroupAfterExit = false;
2799
+ this.recordSnapshotFailure(captureRootGroup);
2661
2800
  return false;
2662
2801
  }
2663
2802
  }
2803
+ recordSnapshotFailure(captureRootGroup) {
2804
+ if (isChildProcessRunning(this.child)) {
2805
+ this.failedRootObservation = true;
2806
+ return;
2807
+ }
2808
+ if (captureRootGroup) this.unresolvedOwnership = true;
2809
+ this.captureGroupAfterExit = false;
2810
+ }
2664
2811
  requiredSnapshotPids(rootWasRunning) {
2665
2812
  return [...this.identities.keys(), ...rootWasRunning && this.child.pid ? [this.child.pid] : []];
2666
2813
  }
@@ -2672,6 +2819,10 @@ var ProcessDescendants = class {
2672
2819
  if (observed && compareProcessBirthIdentity(identity.birth, observed.birth) === "matching") owned.add(pid);
2673
2820
  }
2674
2821
  this.includeRoot(table, owned);
2822
+ if (owned.has(this.child.pid ?? 0)) {
2823
+ this.failedRootObservation = false;
2824
+ this.unresolvedOwnership = false;
2825
+ }
2675
2826
  if (this.ownProcessGroup) this.includeProcessGroup(table, owned, rootWasRunning);
2676
2827
  includeProcessDescendants(table, owned);
2677
2828
  owned.delete(this.child.pid ?? 0);
@@ -2692,29 +2843,40 @@ var ProcessDescendants = class {
2692
2843
  }
2693
2844
  includeProcessGroup(table, owned, rootWasRunning) {
2694
2845
  const root = this.child.pid;
2695
- if (root && (rootWasRunning || [...owned].some((pid) => table.get(pid)?.groupPid === root))) {
2696
- for (const identity of table.values()) if (identity.groupPid === root && this.startedBeforeRootExit(identity)) owned.add(identity.pid);
2846
+ if (!root || !(rootWasRunning || [...owned].some((pid) => table.get(pid)?.groupPid === root))) return;
2847
+ this.unresolvedOwnership = !this.admitGroupMembers(table, owned, root);
2848
+ if (!this.unresolvedOwnership) this.failedRootObservation = false;
2849
+ }
2850
+ admitGroupMembers(table, owned, groupPid) {
2851
+ let verified = true;
2852
+ for (const identity of table.values()) {
2853
+ if (identity.groupPid !== groupPid) continue;
2854
+ const beforeExit = this.startedBeforeRootExit(identity);
2855
+ if (beforeExit === void 0) verified = false;
2856
+ else if (beforeExit) owned.add(identity.pid);
2697
2857
  }
2858
+ return verified;
2698
2859
  }
2699
2860
  startedBeforeRootExit(identity) {
2700
2861
  const cutoff = this.groupExitedAt;
2701
2862
  if (cutoff === void 0) return true;
2702
- if (cutoff === null) return false;
2703
- if (identity.birth.kind !== "linux-proc") return typeof cutoff === "number" && Date.parse(identity.birth.value) <= cutoff;
2704
- if (typeof cutoff === "number" || identity.birth.timeNamespace !== cutoff.timeNamespace || !identity.clockTicksPerSecond) return false;
2863
+ if (cutoff === null) return;
2864
+ if (identity.birth.kind !== "linux-proc") return typeof cutoff === "number" ? Date.parse(identity.birth.value) <= cutoff : void 0;
2865
+ if (typeof cutoff === "number" || identity.birth.timeNamespace !== cutoff.timeNamespace || !identity.clockTicksPerSecond) return;
2705
2866
  return BigInt(identity.birth.startTicks) * 100n < (cutoff.centiseconds + 1n) * identity.clockTicksPerSecond;
2706
2867
  }
2707
2868
  async signal(signal, timeoutMs) {
2708
2869
  if (!await this.capture(timeoutMs) || this.retired) return;
2709
2870
  for (const pid of this.identities.keys()) try {
2710
2871
  process.kill(pid, signal);
2711
- } catch {
2712
- this.identities.delete(pid);
2713
- }
2872
+ } catch {}
2714
2873
  }
2715
2874
  hasTrackedProcesses() {
2716
2875
  return this.identities.size > 0;
2717
2876
  }
2877
+ hasUnresolvedOwnership() {
2878
+ return this.unresolvedOwnership || !this.ownProcessGroup && this.failedRootObservation && !isChildProcessRunning(this.child);
2879
+ }
2718
2880
  async waitForExit(timeoutMs) {
2719
2881
  const deadline = performance.now() + timeoutMs;
2720
2882
  do {
@@ -2731,46 +2893,6 @@ var ProcessDescendants = class {
2731
2893
  }
2732
2894
  };
2733
2895
  //#endregion
2734
- //#region src/session/lock-owner.ts
2735
- const OBSERVATION_REUSE_MS = 1e3;
2736
- const IDENTITY_QUERY_TIMEOUT_MS = 1e3;
2737
- function lockOwnerPid(value) {
2738
- if (!value || typeof value !== "object" || !("pid" in value)) return;
2739
- const pid = value.pid;
2740
- return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
2741
- }
2742
- function canReuseObservation(preserved, pid, identity, fresh) {
2743
- return !fresh && preserved?.pid === pid && compareProcessBirthIdentity(preserved.identity, identity) === "matching" && performance.now() - preserved.checkedAt < OBSERVATION_REUSE_MS;
2744
- }
2745
- async function createLockOwner(options = {}) {
2746
- const { signal, capturedIdentity } = options;
2747
- signal?.throwIfAborted();
2748
- const processIdentity = capturedIdentity === void 0 ? await getOwnProcessIdentity() : capturedIdentity.processIdentity;
2749
- signal?.throwIfAborted();
2750
- let preserved;
2751
- return {
2752
- payload: {
2753
- pid: process.pid,
2754
- processIdentity
2755
- },
2756
- async hasExited(payload, fresh, signal) {
2757
- signal?.throwIfAborted();
2758
- const pid = lockOwnerPid(payload);
2759
- if (!pid) return false;
2760
- const identity = parseProcessBirthIdentity(payload.processIdentity);
2761
- if (identity && canReuseObservation(preserved, pid, identity, fresh)) return false;
2762
- const incarnation = await observeProcessIncarnation(pid, identity, IDENTITY_QUERY_TIMEOUT_MS);
2763
- signal?.throwIfAborted();
2764
- if (identity && incarnation !== "gone") preserved = {
2765
- pid,
2766
- identity,
2767
- checkedAt: performance.now()
2768
- };
2769
- return incarnation === "gone";
2770
- }
2771
- };
2772
- }
2773
- //#endregion
2774
2896
  //#region src/session/queue/paths.ts
2775
2897
  function shortHash(value, length) {
2776
2898
  return createHash("sha256").update(value).digest("hex").slice(0, length);
@@ -4039,7 +4161,7 @@ function parseStringResultOwnerMessage(message, context, type, field) {
4039
4161
  function parseSetModelOwnerMessage(message, context) {
4040
4162
  if (typeof message.modelId !== "string") return null;
4041
4163
  const response = asRecord(message.response);
4042
- if (message.response !== void 0 && (!response || !Array.isArray(response.configOptions))) return null;
4164
+ if (message.response !== void 0 && (!response || response.configOptions !== void 0 && !Array.isArray(response.configOptions))) return null;
4043
4165
  return {
4044
4166
  type: "set_model_result",
4045
4167
  ...context,
@@ -4049,7 +4171,7 @@ function parseSetModelOwnerMessage(message, context) {
4049
4171
  }
4050
4172
  function parseSetConfigOptionOwnerMessage(message, context) {
4051
4173
  const response = asRecord(message.response);
4052
- if (!response || !Array.isArray(response.configOptions)) return null;
4174
+ if (!response || response.configOptions !== void 0 && !Array.isArray(response.configOptions)) return null;
4053
4175
  return {
4054
4176
  type: "set_config_option_result",
4055
4177
  ...context,
@@ -4699,7 +4821,6 @@ var SessionQueueOwner = class SessionQueueOwner {
4699
4821
  };
4700
4822
  //#endregion
4701
4823
  //#region src/session/queue/ipc.ts
4702
- const MAX_MESSAGE_BUFFER_SIZE = 10485760;
4703
4824
  function assertOwnerGeneration(owner, message) {
4704
4825
  if (owner.ownerGeneration !== void 0 && message.ownerGeneration !== void 0 && message.ownerGeneration !== owner.ownerGeneration) throw new QueueProtocolError("Queue owner returned mismatched generation", {
4705
4826
  detailCode: "QUEUE_OWNER_GENERATION_MISMATCH",
@@ -4785,7 +4906,7 @@ async function runQueueOwnerRequest(options) {
4785
4906
  socket.setEncoding("utf8");
4786
4907
  return await new Promise((resolve, reject) => {
4787
4908
  let settled = false;
4788
- let buffer = "";
4909
+ const responseFragments = [];
4789
4910
  const state = { acknowledged: false };
4790
4911
  const finishResolve = (result) => {
4791
4912
  if (settled) return;
@@ -4829,19 +4950,21 @@ async function runQueueOwnerRequest(options) {
4829
4950
  }
4830
4951
  };
4831
4952
  socket.on("data", (chunk) => {
4832
- buffer += chunk;
4833
- if (buffer.length > 10485760) {
4834
- socket.destroy();
4835
- finishReject(uncertainQueueOutcome(/* @__PURE__ */ new Error(`Message buffer exceeded ${MAX_MESSAGE_BUFFER_SIZE} bytes`)));
4836
- return;
4837
- }
4838
- let index = buffer.indexOf("\n");
4839
- while (index >= 0) {
4840
- if (settled) return;
4841
- const line = buffer.slice(0, index).trim();
4842
- buffer = buffer.slice(index + 1);
4843
- if (line.length > 0) processLine(line);
4844
- index = buffer.indexOf("\n");
4953
+ try {
4954
+ let offset = 0;
4955
+ let newline = chunk.indexOf("\n");
4956
+ while (newline >= 0) {
4957
+ if (settled) return;
4958
+ responseFragments.push(chunk.slice(offset, newline));
4959
+ const line = responseFragments.join("").trim();
4960
+ responseFragments.length = 0;
4961
+ if (line.length > 0) processLine(line);
4962
+ offset = newline + 1;
4963
+ newline = chunk.indexOf("\n", offset);
4964
+ }
4965
+ if (!settled && offset < chunk.length) responseFragments.push(chunk.slice(offset));
4966
+ } catch (error) {
4967
+ finishReject(uncertainQueueOutcome(error));
4845
4968
  }
4846
4969
  });
4847
4970
  socket.once("error", (error) => {
@@ -5168,6 +5291,6 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
5168
5291
  });
5169
5292
  }
5170
5293
  //#endregion
5171
- export { resetPerfMetrics as $, findSession as A, PERMISSION_POLICY_ACTIONS as At, assertPersistedKeyPolicy as B, PermissionDeniedError as Bt, mergePromptSourceWithText as C, extractAcpError as Ct, DEFAULT_HISTORY_LIMIT as D, NON_INTERACTIVE_PERMISSION_POLICIES as Dt, textPrompt as E, EXIT_CODES as Et, normalizeName as F, AgentStartupError as Ft, SESSION_JOURNAL_SCHEMA as G, SessionModelReplayError as Gt, serializeSessionRecordForDisk as H, QueueConnectionError as Ht, pruneSessions as I, AuthPolicyError as It, watchSession as J, UnsupportedPromptContentError as Jt, SessionJournalReader as K, SessionNotFoundError as Kt, readSessionRecord as L, ClaudeAcpSessionCreateTimeoutError as Lt, isoNow as M, AcpxOperationalError as Mt, listSessions as N, AgentDisconnectedError as Nt, absolutePath as O, OUTPUT_FORMATS as Ot, listSessionsForAgent as P, AgentSpawnError as Pt, measurePerf as Q, resolveSessionRecord as R, CopilotAcpUnsupportedError as Rt, getUnsupportedPromptContentMessage as S, normalizeOutputError as St, promptToDisplayText as T, AUTH_POLICIES as Tt, extractAgentSessionId as U, SessionConfigOptionReplayError as Ut, parseSessionRecord as V, PermissionPromptUnavailableError as Vt, normalizeAgentSessionId as W, SessionModeReplayError as Wt, getPerfMetricsSnapshot as X, formatPerfMetric as Y, incrementPerfCounter as Z, createLockOwner as _, isProcessAlive as _t, trySetModelOnRunningOwner as a, isSessionUpdateNotification as at, observeProcessIncarnation as b, isAcpQueryClosedBeforeResponseError as bt, probeQueueOwnerHealth as c, parsePromptStopReason as ct, releaseQueueOwnerLease as d, sessionBaseDir as dt, setPerfGauge as et, terminateProcess as f, sessionEventActivePath as ft, QueueLeaseGuardSettlementError as g, writePrivateJsonFile as gt, waitMs as h, writePrivateFile as ht, trySetModeOnRunningOwner as i, isAcpMessageObject as it, findSessionByDirectoryWalk as j, SESSION_RECORD_SCHEMA as jt, findGitRepositoryRoot as k, PERMISSION_MODES as kt, readQueueOwnerRecord as l, DEFAULT_EVENT_SEGMENT_MAX_BYTES as lt, tryAcquireQueueOwnerLease as m, sessionEventSegmentPath as mt, tryCloseSessionOnRunningOwner as n, extractSessionUpdateNotification as nt, trySubmitToRunningOwner as o, parseJsonRpcErrorMessage as ot, terminateQueueOwnerForSession as p, sessionEventLockPath as pt, SessionWatchError as q, SessionResumeRequiredError as qt, trySetConfigOptionOnRunningOwner as r, isAcpJsonRpcMessage as rt, SessionQueueOwner as s, parsePermissionNotice as st, tryCancelOnRunningOwner as t, startPerfTimer as tt, refreshQueueOwnerLease as u, defaultSessionEventLog as ut, lockOwnerPid as v, exitCodeForOutputErrorCode as vt, parsePromptSource as w, isAcpResourceNotFoundError as wt, PromptInputValidationError as x, isRetryablePromptError as xt, ProcessDescendants as y, formatErrorMessage as yt, writeSessionRecord as z, GeminiAcpStartupTimeoutError as zt };
5294
+ export { resetPerfMetrics as $, findSession as A, PERMISSION_MODES as At, assertPersistedKeyPolicy as B, GeminiAcpStartupTimeoutError as Bt, textPrompt as C, normalizeOutputError as Ct, DEFAULT_HISTORY_LIMIT as D, EXIT_CODES as Dt, observeProcessIncarnation as E, AUTH_POLICIES as Et, normalizeName as F, AgentSpawnError as Ft, SESSION_JOURNAL_SCHEMA as G, SessionModeReplayError as Gt, serializeSessionRecordForDisk as H, PermissionPromptUnavailableError as Ht, pruneSessions as I, AgentStartupError as It, watchSession as J, SessionResumeRequiredError as Jt, SessionJournalReader as K, SessionModelReplayError as Kt, readSessionRecord as L, AuthPolicyError as Lt, isoNow as M, SESSION_RECORD_SCHEMA as Mt, listSessions as N, AcpxOperationalError as Nt, absolutePath as O, NON_INTERACTIVE_PERMISSION_POLICIES as Ot, listSessionsForAgent as P, AgentDisconnectedError as Pt, measurePerf as Q, resolveSessionRecord as R, ClaudeAcpSessionCreateTimeoutError as Rt, promptToDisplayText as S, isRetryablePromptError as St, lockOwnerPid as T, isAcpResourceNotFoundError as Tt, extractAgentSessionId as U, QueueConnectionError as Ut, parseSessionRecord as V, PermissionDeniedError as Vt, normalizeAgentSessionId as W, SessionConfigOptionReplayError as Wt, getPerfMetricsSnapshot as X, formatPerfMetric as Y, UnsupportedPromptContentError as Yt, incrementPerfCounter as Z, ProcessDescendants as _, _usingCtx as _t, trySetModelOnRunningOwner as a, isSessionUpdateNotification as at, mergePromptSourceWithText as b, formatErrorMessage as bt, probeQueueOwnerHealth as c, parsePromptStopReason as ct, releaseQueueOwnerLease as d, sessionBaseDir as dt, setPerfGauge as et, terminateProcess as f, sessionEventActivePath as ft, QueueLeaseGuardSettlementError as g, writePrivateJsonFile as gt, waitMs as h, writePrivateFile as ht, trySetModeOnRunningOwner as i, isAcpMessageObject as it, findSessionByDirectoryWalk as j, PERMISSION_POLICY_ACTIONS as jt, findGitRepositoryRoot as k, OUTPUT_FORMATS as kt, readQueueOwnerRecord as l, DEFAULT_EVENT_SEGMENT_MAX_BYTES as lt, tryAcquireQueueOwnerLease as m, sessionEventSegmentPath as mt, tryCloseSessionOnRunningOwner as n, extractSessionUpdateNotification as nt, trySubmitToRunningOwner as o, parseJsonRpcErrorMessage as ot, terminateQueueOwnerForSession as p, sessionEventLockPath as pt, SessionWatchError as q, SessionNotFoundError as qt, trySetConfigOptionOnRunningOwner as r, isAcpJsonRpcMessage as rt, SessionQueueOwner as s, parsePermissionNotice as st, tryCancelOnRunningOwner as t, startPerfTimer as tt, refreshQueueOwnerLease as u, defaultSessionEventLog as ut, PromptInputValidationError as v, isProcessAlive as vt, createLockOwner as w, extractAcpError as wt, parsePromptSource as x, isAcpQueryClosedBeforeResponseError as xt, getUnsupportedPromptContentMessage as y, exitCodeForOutputErrorCode as yt, writeSessionRecord as z, CopilotAcpUnsupportedError as zt };
5172
5295
 
5173
- //# sourceMappingURL=ipc-D0ZMQ0q9.js.map
5296
+ //# sourceMappingURL=ipc-D7zT86b9.js.map