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.
- package/dist/{agent-registry-DWlx5BQ4.js → agent-registry-kHdpsK9F.js} +35 -21
- package/dist/agent-registry-kHdpsK9F.js.map +1 -0
- package/dist/agent-registry.d.ts.map +1 -1
- package/dist/agent-registry.js +1 -1
- package/dist/{cli-D-s_eTUy.js → cli-DCtHeMEi.js} +34 -46
- package/dist/cli-DCtHeMEi.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +57 -40
- package/dist/cli.js.map +1 -1
- package/dist/{client-BchvQRpz.d.ts → client-DqCXdF0Q.d.ts} +6 -18
- package/dist/client-DqCXdF0Q.d.ts.map +1 -0
- package/dist/{flows-DdxEaeZo.js → flows--1zpaEh9.js} +38 -14
- package/dist/flows--1zpaEh9.js.map +1 -0
- package/dist/flows.d.ts +2 -2
- package/dist/flows.js +1 -1
- package/dist/{invocation-options-HjxSBsK0.js → invocation-options-CvkenzCc.js} +6 -12
- package/dist/invocation-options-CvkenzCc.js.map +1 -0
- package/dist/{ipc-D0ZMQ0q9.js → ipc-D7zT86b9.js} +430 -307
- package/dist/ipc-D7zT86b9.js.map +1 -0
- package/dist/{output-GQnhkJMU.js → output-lylSoEBd.js} +12 -4
- package/dist/output-lylSoEBd.js.map +1 -0
- package/dist/{queue-owner-runtime-W0lly6ap.js → queue-owner-runtime-C0wIYowh.js} +766 -547
- package/dist/queue-owner-runtime-C0wIYowh.js.map +1 -0
- package/dist/runtime.d.ts +23 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +52 -22
- package/dist/runtime.js.map +1 -1
- package/dist/{session-options-Dp6mzNSy.d.ts → session-options-X7LhX9BF.d.ts} +2 -1
- package/dist/{session-options-Dp6mzNSy.d.ts.map → session-options-X7LhX9BF.d.ts.map} +1 -1
- package/dist/{session-watch-_8yxQ6ba.js → session-watch-DPOwDRf8.js} +4 -4
- package/dist/{session-watch-_8yxQ6ba.js.map → session-watch-DPOwDRf8.js.map} +1 -1
- package/dist/{watch-C0mwpJcN.js → watch-H7rNOJtv.js} +2 -2
- package/dist/{watch-C0mwpJcN.js.map → watch-H7rNOJtv.js.map} +1 -1
- package/package.json +17 -16
- package/skills/acpx/SKILL.md +13 -3
- package/dist/agent-registry-DWlx5BQ4.js.map +0 -1
- package/dist/cli-D-s_eTUy.js.map +0 -1
- package/dist/client-BchvQRpz.d.ts.map +0 -1
- package/dist/flows-DdxEaeZo.js.map +0 -1
- package/dist/invocation-options-HjxSBsK0.js.map +0 -1
- package/dist/ipc-D0ZMQ0q9.js.map +0 -1
- package/dist/output-GQnhkJMU.js.map +0 -1
- 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-
|
|
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
|
-
|
|
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
|
-
|
|
905
|
-
|
|
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
|
-
}
|
|
916
|
-
await this.closeSnapshot(segments);
|
|
917
|
-
}
|
|
936
|
+
});
|
|
918
937
|
}
|
|
919
938
|
async readTail() {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
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
|
-
}
|
|
942
|
-
await this.closeSnapshot(segments);
|
|
943
|
-
}
|
|
959
|
+
});
|
|
944
960
|
}
|
|
945
961
|
async read(signal, options) {
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
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 =
|
|
970
|
+
const state = { ...states.get(segment.identity) ?? emptySegment() };
|
|
955
971
|
await this.readSegment(segment.opened.handle, segment.opened.stat.size, state, page, signal);
|
|
956
|
-
|
|
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
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
-
}
|
|
981
|
-
|
|
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
|
|
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
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
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
|
|
1301
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
1659
|
-
agentArgv:
|
|
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
|
-
|
|
1830
|
-
|
|
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 (
|
|
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,
|
|
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,
|
|
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,
|
|
2004
|
-
return record.closed === true && (!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2696
|
-
|
|
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
|
|
2703
|
-
if (identity.birth.kind !== "linux-proc") return typeof cutoff === "number"
|
|
2704
|
-
if (typeof cutoff === "number" || identity.birth.timeNamespace !== cutoff.timeNamespace || !identity.clockTicksPerSecond) return
|
|
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
|
-
|
|
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
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
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,
|
|
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-
|
|
5296
|
+
//# sourceMappingURL=ipc-D7zT86b9.js.map
|