adhdev 0.8.75 → 0.8.77
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/cli/index.js +764 -182
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +742 -160
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1026,6 +1026,67 @@ var init_host_memory = __esm({
|
|
|
1026
1026
|
}
|
|
1027
1027
|
});
|
|
1028
1028
|
|
|
1029
|
+
// ../../oss/packages/daemon-core/src/session-host/runtime-surface.ts
|
|
1030
|
+
function isSessionHostLiveRuntime(record2) {
|
|
1031
|
+
const lifecycle = String(record2?.lifecycle || "").trim();
|
|
1032
|
+
return LIVE_LIFECYCLES.has(lifecycle);
|
|
1033
|
+
}
|
|
1034
|
+
function getSessionHostRecoveryLabel(meta3) {
|
|
1035
|
+
const recoveryState = typeof meta3?.runtimeRecoveryState === "string" ? String(meta3.runtimeRecoveryState).trim() : "";
|
|
1036
|
+
if (!recoveryState) return null;
|
|
1037
|
+
if (recoveryState === "auto_resumed") return "restored after restart";
|
|
1038
|
+
if (recoveryState === "resume_failed") return "restore failed";
|
|
1039
|
+
if (recoveryState === "host_restart_interrupted") return "host restart interrupted";
|
|
1040
|
+
if (recoveryState === "orphan_snapshot") return "snapshot recovered";
|
|
1041
|
+
return recoveryState.replace(/_/g, " ");
|
|
1042
|
+
}
|
|
1043
|
+
function isSessionHostRecoverySnapshot(record2) {
|
|
1044
|
+
if (!record2) return false;
|
|
1045
|
+
if (isSessionHostLiveRuntime(record2)) return false;
|
|
1046
|
+
const lifecycle = String(record2.lifecycle || "").trim();
|
|
1047
|
+
if (lifecycle && lifecycle !== "stopped" && lifecycle !== "failed") {
|
|
1048
|
+
return false;
|
|
1049
|
+
}
|
|
1050
|
+
const meta3 = record2.meta || void 0;
|
|
1051
|
+
if (meta3?.restoredFromStorage === true) return true;
|
|
1052
|
+
return getSessionHostRecoveryLabel(meta3) !== null;
|
|
1053
|
+
}
|
|
1054
|
+
function getSessionHostSurfaceKind(record2) {
|
|
1055
|
+
if (isSessionHostLiveRuntime(record2)) return "live_runtime";
|
|
1056
|
+
if (isSessionHostRecoverySnapshot(record2)) return "recovery_snapshot";
|
|
1057
|
+
return "inactive_record";
|
|
1058
|
+
}
|
|
1059
|
+
function partitionSessionHostRecords(records) {
|
|
1060
|
+
const liveRuntimes = [];
|
|
1061
|
+
const recoverySnapshots = [];
|
|
1062
|
+
const inactiveRecords = [];
|
|
1063
|
+
for (const record2 of records) {
|
|
1064
|
+
const kind = getSessionHostSurfaceKind(record2);
|
|
1065
|
+
if (kind === "live_runtime") {
|
|
1066
|
+
liveRuntimes.push(record2);
|
|
1067
|
+
} else if (kind === "recovery_snapshot") {
|
|
1068
|
+
recoverySnapshots.push(record2);
|
|
1069
|
+
} else {
|
|
1070
|
+
inactiveRecords.push(record2);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return {
|
|
1074
|
+
liveRuntimes,
|
|
1075
|
+
recoverySnapshots,
|
|
1076
|
+
inactiveRecords
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function partitionSessionHostDiagnosticsSessions(records) {
|
|
1080
|
+
return partitionSessionHostRecords(records || []);
|
|
1081
|
+
}
|
|
1082
|
+
var LIVE_LIFECYCLES;
|
|
1083
|
+
var init_runtime_surface = __esm({
|
|
1084
|
+
"../../oss/packages/daemon-core/src/session-host/runtime-surface.ts"() {
|
|
1085
|
+
"use strict";
|
|
1086
|
+
LIVE_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1029
1090
|
// ../../oss/packages/daemon-core/src/status/chat-tail-hot-sessions.ts
|
|
1030
1091
|
function parseMessageTimestamp(value) {
|
|
1031
1092
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -1035,6 +1096,23 @@ function parseMessageTimestamp(value) {
|
|
|
1035
1096
|
}
|
|
1036
1097
|
return 0;
|
|
1037
1098
|
}
|
|
1099
|
+
function isDefinitelyNonLiveRuntimeSession(session) {
|
|
1100
|
+
const surfaceKind = String(session?.runtimeSurfaceKind || "").trim();
|
|
1101
|
+
if (surfaceKind === "live_runtime") return false;
|
|
1102
|
+
if (surfaceKind === "recovery_snapshot") return true;
|
|
1103
|
+
if (surfaceKind === "inactive_record") return false;
|
|
1104
|
+
const lifecycle = String(session?.runtimeLifecycle || "").trim();
|
|
1105
|
+
if (lifecycle && LIVE_RUNTIME_LIFECYCLES.has(lifecycle)) return false;
|
|
1106
|
+
const inferredSurfaceKind = getSessionHostSurfaceKind({
|
|
1107
|
+
lifecycle: lifecycle || null,
|
|
1108
|
+
meta: {
|
|
1109
|
+
restoredFromStorage: session?.runtimeRestoredFromStorage === true,
|
|
1110
|
+
...session?.runtimeRecoveryState ? { runtimeRecoveryState: session.runtimeRecoveryState } : {}
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
if (inferredSurfaceKind === "recovery_snapshot") return true;
|
|
1114
|
+
return false;
|
|
1115
|
+
}
|
|
1038
1116
|
function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessionIds, options = {}) {
|
|
1039
1117
|
const now = options.now ?? Date.now();
|
|
1040
1118
|
const recentMessageGraceMs = Math.max(
|
|
@@ -1043,9 +1121,14 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
|
|
|
1043
1121
|
);
|
|
1044
1122
|
const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
|
|
1045
1123
|
const active = /* @__PURE__ */ new Set();
|
|
1124
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
1046
1125
|
for (const session of sessions) {
|
|
1047
1126
|
const sessionId = typeof session?.id === "string" ? session.id : "";
|
|
1048
1127
|
if (!sessionId) continue;
|
|
1128
|
+
if (isDefinitelyNonLiveRuntimeSession(session)) {
|
|
1129
|
+
excluded.add(sessionId);
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1049
1132
|
const status = String(session?.status || "").toLowerCase();
|
|
1050
1133
|
const lastMessageAt = parseMessageTimestamp(session?.lastMessageAt);
|
|
1051
1134
|
const recentlyUpdated = lastMessageAt > 0 && now - lastMessageAt <= recentMessageGraceMs;
|
|
@@ -1054,20 +1137,22 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
|
|
|
1054
1137
|
}
|
|
1055
1138
|
}
|
|
1056
1139
|
const finalizing = new Set(
|
|
1057
|
-
Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId))
|
|
1140
|
+
Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId) && !excluded.has(sessionId))
|
|
1058
1141
|
);
|
|
1059
1142
|
return { active, finalizing };
|
|
1060
1143
|
}
|
|
1061
|
-
var DEFAULT_ACTIVE_CHAT_POLL_STATUSES, DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS;
|
|
1144
|
+
var DEFAULT_ACTIVE_CHAT_POLL_STATUSES, DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS, LIVE_RUNTIME_LIFECYCLES;
|
|
1062
1145
|
var init_chat_tail_hot_sessions = __esm({
|
|
1063
1146
|
"../../oss/packages/daemon-core/src/status/chat-tail-hot-sessions.ts"() {
|
|
1064
1147
|
"use strict";
|
|
1148
|
+
init_runtime_surface();
|
|
1065
1149
|
DEFAULT_ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
|
|
1066
1150
|
"generating",
|
|
1067
1151
|
"waiting_approval",
|
|
1068
1152
|
"starting"
|
|
1069
1153
|
]);
|
|
1070
1154
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS = 8e3;
|
|
1155
|
+
LIVE_RUNTIME_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
1071
1156
|
}
|
|
1072
1157
|
});
|
|
1073
1158
|
|
|
@@ -1287,6 +1372,32 @@ var init_logger = __esm({
|
|
|
1287
1372
|
});
|
|
1288
1373
|
|
|
1289
1374
|
// ../../oss/packages/daemon-core/src/cdp/manager.ts
|
|
1375
|
+
function normalizeTitle(value) {
|
|
1376
|
+
return String(value || "").trim().replace(/\s+/g, " ").toLowerCase();
|
|
1377
|
+
}
|
|
1378
|
+
function titlesMatch(lhs, rhs) {
|
|
1379
|
+
const a = normalizeTitle(lhs);
|
|
1380
|
+
const b = normalizeTitle(rhs);
|
|
1381
|
+
if (!a || !b) return false;
|
|
1382
|
+
return a === b || a.includes(b) || b.includes(a);
|
|
1383
|
+
}
|
|
1384
|
+
function resolveCdpPageTarget(params) {
|
|
1385
|
+
const { pages, pinnedTargetId, previousPageTitle } = params;
|
|
1386
|
+
if (pages.length === 0) return { target: null, retargeted: false };
|
|
1387
|
+
if (!pinnedTargetId) {
|
|
1388
|
+
return { target: pages[0] || null, retargeted: false };
|
|
1389
|
+
}
|
|
1390
|
+
const exact = pages.find((page) => page.id === pinnedTargetId);
|
|
1391
|
+
if (exact) return { target: exact, retargeted: false };
|
|
1392
|
+
const titleMatchesList = pages.filter((page) => titlesMatch(page.title, previousPageTitle));
|
|
1393
|
+
if (titleMatchesList.length === 1) {
|
|
1394
|
+
return { target: titleMatchesList[0], retargeted: true };
|
|
1395
|
+
}
|
|
1396
|
+
if (pages.length === 1) {
|
|
1397
|
+
return { target: pages[0], retargeted: true };
|
|
1398
|
+
}
|
|
1399
|
+
return { target: null, retargeted: false };
|
|
1400
|
+
}
|
|
1290
1401
|
var import_ws, http, DaemonCdpManager;
|
|
1291
1402
|
var init_manager = __esm({
|
|
1292
1403
|
"../../oss/packages/daemon-core/src/cdp/manager.ts"() {
|
|
@@ -1454,18 +1565,28 @@ var init_manager = __esm({
|
|
|
1454
1565
|
resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
1455
1566
|
return;
|
|
1456
1567
|
}
|
|
1457
|
-
const
|
|
1458
|
-
const
|
|
1568
|
+
const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
1569
|
+
const mainPages = titleFilteredPages.filter((t) => this.isMainPageUrl(t.url));
|
|
1570
|
+
const list = mainPages.length > 0 ? mainPages : titleFilteredPages.length > 0 ? titleFilteredPages : pages;
|
|
1459
1571
|
this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1572
|
+
const previousTargetId = this._targetId;
|
|
1573
|
+
const selected = resolveCdpPageTarget({
|
|
1574
|
+
pages: list,
|
|
1575
|
+
pinnedTargetId: previousTargetId,
|
|
1576
|
+
previousPageTitle: this._pageTitle
|
|
1577
|
+
});
|
|
1578
|
+
if (selected.target) {
|
|
1579
|
+
if (selected.retargeted && previousTargetId && previousTargetId !== selected.target.id) {
|
|
1580
|
+
this.log(`[CDP] Target ${previousTargetId} rekeyed to ${selected.target.id}`);
|
|
1581
|
+
this._targetId = selected.target.id;
|
|
1468
1582
|
}
|
|
1583
|
+
this._pageTitle = selected.target.title || "";
|
|
1584
|
+
resolve15(selected.target);
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
if (previousTargetId) {
|
|
1588
|
+
this.log(`[CDP] Target ${previousTargetId} not found in page list`);
|
|
1589
|
+
resolve15(null);
|
|
1469
1590
|
return;
|
|
1470
1591
|
}
|
|
1471
1592
|
this._pageTitle = list[0]?.title || "";
|
|
@@ -3342,6 +3463,68 @@ function sanitizeHistoryMessage(agentType, message) {
|
|
|
3342
3463
|
content
|
|
3343
3464
|
};
|
|
3344
3465
|
}
|
|
3466
|
+
function sortSavedHistorySessionSummaries(summaries) {
|
|
3467
|
+
return summaries.slice().sort((a, b) => b.lastMessageAt - a.lastMessageAt);
|
|
3468
|
+
}
|
|
3469
|
+
function buildSavedHistorySessionSummaryMapFromEntries(entries) {
|
|
3470
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
3471
|
+
for (const entry of Array.from(entries.values())) {
|
|
3472
|
+
const fileSummary = entry.summary;
|
|
3473
|
+
if (!fileSummary || fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) continue;
|
|
3474
|
+
const existing = summaries.get(fileSummary.historySessionId);
|
|
3475
|
+
if (!existing) {
|
|
3476
|
+
summaries.set(fileSummary.historySessionId, {
|
|
3477
|
+
historySessionId: fileSummary.historySessionId,
|
|
3478
|
+
sessionTitle: fileSummary.sessionTitle,
|
|
3479
|
+
messageCount: fileSummary.messageCount,
|
|
3480
|
+
firstMessageAt: fileSummary.firstMessageAt,
|
|
3481
|
+
lastMessageAt: fileSummary.lastMessageAt,
|
|
3482
|
+
preview: fileSummary.preview,
|
|
3483
|
+
workspace: fileSummary.workspace
|
|
3484
|
+
});
|
|
3485
|
+
continue;
|
|
3486
|
+
}
|
|
3487
|
+
existing.messageCount += fileSummary.messageCount;
|
|
3488
|
+
if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
|
|
3489
|
+
existing.firstMessageAt = fileSummary.firstMessageAt;
|
|
3490
|
+
}
|
|
3491
|
+
if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
|
|
3492
|
+
existing.lastMessageAt = fileSummary.lastMessageAt;
|
|
3493
|
+
if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
|
|
3494
|
+
if (fileSummary.preview) existing.preview = fileSummary.preview;
|
|
3495
|
+
}
|
|
3496
|
+
if (!existing.workspace && fileSummary.workspace) {
|
|
3497
|
+
existing.workspace = fileSummary.workspace;
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
return Object.fromEntries(sortSavedHistorySessionSummaries(Array.from(summaries.values())).map((summary) => [summary.historySessionId, summary]));
|
|
3501
|
+
}
|
|
3502
|
+
function readPersistedSavedHistorySessionSummaries(dir) {
|
|
3503
|
+
try {
|
|
3504
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
3505
|
+
if (!fs3.existsSync(filePath)) return null;
|
|
3506
|
+
const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
3507
|
+
if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.sessions || typeof raw.sessions !== "object") {
|
|
3508
|
+
return null;
|
|
3509
|
+
}
|
|
3510
|
+
return sortSavedHistorySessionSummaries(
|
|
3511
|
+
Object.values(raw.sessions).filter((summary) => !!summary && typeof summary.historySessionId === "string" && summary.messageCount > 0 && summary.lastMessageAt > 0).map((summary) => ({
|
|
3512
|
+
historySessionId: summary.historySessionId,
|
|
3513
|
+
sessionTitle: summary.sessionTitle,
|
|
3514
|
+
messageCount: summary.messageCount,
|
|
3515
|
+
firstMessageAt: summary.firstMessageAt,
|
|
3516
|
+
lastMessageAt: summary.lastMessageAt,
|
|
3517
|
+
preview: summary.preview,
|
|
3518
|
+
workspace: summary.workspace
|
|
3519
|
+
}))
|
|
3520
|
+
);
|
|
3521
|
+
} catch {
|
|
3522
|
+
return null;
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
function shouldScheduleSavedHistoryRollup(totalBytes) {
|
|
3526
|
+
return Number.isFinite(totalBytes) && totalBytes >= SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES;
|
|
3527
|
+
}
|
|
3345
3528
|
function sanitizeHistoryFileSegment(value) {
|
|
3346
3529
|
return String(value || "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3347
3530
|
}
|
|
@@ -3355,71 +3538,386 @@ function listHistoryFiles(dir, historySessionId) {
|
|
|
3355
3538
|
return true;
|
|
3356
3539
|
}).sort().reverse();
|
|
3357
3540
|
}
|
|
3358
|
-
function
|
|
3359
|
-
|
|
3541
|
+
function normalizeSavedHistorySessionId(agentType, historySessionId) {
|
|
3542
|
+
const normalizedId = String(historySessionId || "").trim();
|
|
3543
|
+
if (!normalizedId) return "";
|
|
3544
|
+
const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
|
|
3545
|
+
if (strictProviderId) return strictProviderId;
|
|
3546
|
+
return agentType === "hermes-cli" ? "" : normalizedId;
|
|
3547
|
+
}
|
|
3548
|
+
function extractSavedHistorySessionIdFromFile(agentType, file2) {
|
|
3549
|
+
const match = file2.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
|
|
3550
|
+
return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
|
|
3551
|
+
}
|
|
3552
|
+
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
3553
|
+
return new Map(files.map((file2) => {
|
|
3360
3554
|
try {
|
|
3361
3555
|
const stat4 = fs3.statSync(path7.join(dir, file2));
|
|
3362
|
-
return `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}
|
|
3556
|
+
return [file2, `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`];
|
|
3363
3557
|
} catch {
|
|
3364
|
-
return `${file2}:missing
|
|
3365
|
-
}
|
|
3366
|
-
})
|
|
3367
|
-
}
|
|
3368
|
-
function
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3558
|
+
return [file2, `${file2}:missing`];
|
|
3559
|
+
}
|
|
3560
|
+
}));
|
|
3561
|
+
}
|
|
3562
|
+
function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
3563
|
+
return files.map((file2) => fileSignatures.get(file2) || `${file2}:missing`).join("|");
|
|
3564
|
+
}
|
|
3565
|
+
function getSavedHistoryIndexFilePath(dir) {
|
|
3566
|
+
return path7.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
3567
|
+
}
|
|
3568
|
+
function getSavedHistoryIndexLockPath(dir) {
|
|
3569
|
+
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
3570
|
+
}
|
|
3571
|
+
function sleepBlocking(ms) {
|
|
3572
|
+
if (ms <= 0) return;
|
|
3573
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
3574
|
+
}
|
|
3575
|
+
function loadPersistedSavedHistoryIndexFromFile(dir) {
|
|
3576
|
+
try {
|
|
3577
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
3578
|
+
if (!fs3.existsSync(filePath)) return /* @__PURE__ */ new Map();
|
|
3579
|
+
const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
3580
|
+
if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.files || typeof raw.files !== "object") {
|
|
3581
|
+
return /* @__PURE__ */ new Map();
|
|
3582
|
+
}
|
|
3583
|
+
return new Map(
|
|
3584
|
+
Object.entries(raw.files).filter(([file2, entry]) => !!file2 && !!entry && typeof entry.signature === "string").map(([file2, entry]) => [file2, {
|
|
3585
|
+
signature: entry.signature,
|
|
3586
|
+
summary: entry.summary || null
|
|
3587
|
+
}])
|
|
3588
|
+
);
|
|
3589
|
+
} catch {
|
|
3590
|
+
return /* @__PURE__ */ new Map();
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
function writePersistedSavedHistoryIndexFile(dir, entries) {
|
|
3594
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
3595
|
+
const tempPath = `${filePath}.tmp`;
|
|
3596
|
+
const payload = {
|
|
3597
|
+
version: SAVED_HISTORY_INDEX_VERSION,
|
|
3598
|
+
files: Object.fromEntries(entries.entries()),
|
|
3599
|
+
sessions: buildSavedHistorySessionSummaryMapFromEntries(entries)
|
|
3600
|
+
};
|
|
3601
|
+
fs3.writeFileSync(tempPath, JSON.stringify(payload), "utf-8");
|
|
3602
|
+
fs3.renameSync(tempPath, filePath);
|
|
3603
|
+
}
|
|
3604
|
+
function acquireSavedHistoryIndexLock(dir) {
|
|
3605
|
+
const lockPath = getSavedHistoryIndexLockPath(dir);
|
|
3606
|
+
const deadline = Date.now() + SAVED_HISTORY_INDEX_LOCK_WAIT_MS;
|
|
3607
|
+
while (Date.now() <= deadline) {
|
|
3608
|
+
try {
|
|
3609
|
+
fs3.mkdirSync(lockPath);
|
|
3610
|
+
return () => {
|
|
3393
3611
|
try {
|
|
3394
|
-
|
|
3612
|
+
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
3395
3613
|
} catch {
|
|
3396
|
-
parsed = null;
|
|
3397
3614
|
}
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3615
|
+
};
|
|
3616
|
+
} catch (error48) {
|
|
3617
|
+
if (error48?.code !== "EEXIST") return null;
|
|
3618
|
+
try {
|
|
3619
|
+
const stat4 = fs3.statSync(lockPath);
|
|
3620
|
+
if (Date.now() - stat4.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
|
|
3621
|
+
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
3401
3622
|
continue;
|
|
3402
3623
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3624
|
+
} catch {
|
|
3625
|
+
continue;
|
|
3626
|
+
}
|
|
3627
|
+
sleepBlocking(SAVED_HISTORY_INDEX_LOCK_POLL_MS);
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
return null;
|
|
3631
|
+
}
|
|
3632
|
+
function withLockedPersistedSavedHistoryIndex(dir, callback) {
|
|
3633
|
+
const release2 = acquireSavedHistoryIndexLock(dir);
|
|
3634
|
+
if (!release2) return null;
|
|
3635
|
+
try {
|
|
3636
|
+
const entries = loadPersistedSavedHistoryIndexFromFile(dir);
|
|
3637
|
+
const result = callback(entries);
|
|
3638
|
+
writePersistedSavedHistoryIndexFile(dir, entries);
|
|
3639
|
+
return result;
|
|
3640
|
+
} catch {
|
|
3641
|
+
return null;
|
|
3642
|
+
} finally {
|
|
3643
|
+
release2();
|
|
3420
3644
|
}
|
|
3421
|
-
|
|
3422
|
-
|
|
3645
|
+
}
|
|
3646
|
+
function loadPersistedSavedHistoryIndex(dir) {
|
|
3647
|
+
return loadPersistedSavedHistoryIndexFromFile(dir);
|
|
3648
|
+
}
|
|
3649
|
+
function savePersistedSavedHistoryIndex(dir, entries) {
|
|
3650
|
+
withLockedPersistedSavedHistoryIndex(dir, (currentEntries) => {
|
|
3651
|
+
const incomingFiles = new Set(Array.from(entries.keys()));
|
|
3652
|
+
for (const [file2, entry] of Array.from(entries.entries())) {
|
|
3653
|
+
const liveSignature = buildSavedHistoryFileSignature(dir, file2);
|
|
3654
|
+
const existingEntry = currentEntries.get(file2);
|
|
3655
|
+
if (existingEntry && existingEntry.signature !== liveSignature && entry.signature !== liveSignature) {
|
|
3656
|
+
continue;
|
|
3657
|
+
}
|
|
3658
|
+
if (entry.signature !== liveSignature && (!existingEntry || existingEntry.signature !== liveSignature)) {
|
|
3659
|
+
continue;
|
|
3660
|
+
}
|
|
3661
|
+
currentEntries.set(file2, entry.signature === liveSignature ? entry : {
|
|
3662
|
+
signature: liveSignature,
|
|
3663
|
+
summary: existingEntry?.summary || entry.summary
|
|
3664
|
+
});
|
|
3665
|
+
}
|
|
3666
|
+
for (const file2 of Array.from(currentEntries.keys())) {
|
|
3667
|
+
if (incomingFiles.has(file2)) continue;
|
|
3668
|
+
if (!fs3.existsSync(path7.join(dir, file2))) {
|
|
3669
|
+
currentEntries.delete(file2);
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
});
|
|
3673
|
+
}
|
|
3674
|
+
function invalidatePersistedSavedHistoryIndex(agentType, dir) {
|
|
3675
|
+
try {
|
|
3676
|
+
fs3.rmSync(getSavedHistoryIndexFilePath(dir), { force: true });
|
|
3677
|
+
} catch {
|
|
3678
|
+
}
|
|
3679
|
+
savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
|
|
3680
|
+
}
|
|
3681
|
+
function buildSavedHistoryIndexFileSignature(dir) {
|
|
3682
|
+
try {
|
|
3683
|
+
const stat4 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
3684
|
+
return `index:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`;
|
|
3685
|
+
} catch {
|
|
3686
|
+
return "index:missing";
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
3690
|
+
try {
|
|
3691
|
+
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
3692
|
+
const files = listHistoryFiles(dir);
|
|
3693
|
+
for (const file2 of files) {
|
|
3694
|
+
const stat4 = fs3.statSync(path7.join(dir, file2));
|
|
3695
|
+
if (stat4.mtimeMs > indexStat.mtimeMs) return true;
|
|
3696
|
+
}
|
|
3697
|
+
return false;
|
|
3698
|
+
} catch {
|
|
3699
|
+
return true;
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
function buildSavedHistoryFileSignature(dir, file2) {
|
|
3703
|
+
try {
|
|
3704
|
+
const stat4 = fs3.statSync(path7.join(dir, file2));
|
|
3705
|
+
return `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`;
|
|
3706
|
+
} catch {
|
|
3707
|
+
return `${file2}:missing`;
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
function persistSavedHistoryFileSummaryEntry(agentType, dir, file2, updater) {
|
|
3711
|
+
const filePath = path7.join(dir, file2);
|
|
3712
|
+
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
3713
|
+
const currentEntry = entries.get(file2) || null;
|
|
3714
|
+
const nextSummary = updater(currentEntry?.summary || null);
|
|
3715
|
+
const nextEntry = {
|
|
3716
|
+
signature: buildSavedHistoryFileSignature(dir, file2),
|
|
3717
|
+
summary: nextSummary
|
|
3718
|
+
};
|
|
3719
|
+
entries.set(file2, nextEntry);
|
|
3720
|
+
savedHistoryFileSummaryCache.set(filePath, nextEntry);
|
|
3721
|
+
return nextEntry;
|
|
3722
|
+
});
|
|
3723
|
+
if (!result) return;
|
|
3724
|
+
if (result.summary?.historySessionId && shouldScheduleSavedHistoryRollupForSignature(result.signature)) {
|
|
3725
|
+
scheduleSavedHistoryRollup(agentType, result.summary.historySessionId);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
function updateSavedHistoryIndexForSessionStart(agentType, dir, file2, historySessionId, workspace) {
|
|
3729
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
|
|
3730
|
+
const normalizedWorkspace = String(workspace || "").trim();
|
|
3731
|
+
if (!normalizedSessionId || !normalizedWorkspace) return;
|
|
3732
|
+
persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => ({
|
|
3733
|
+
file: file2,
|
|
3734
|
+
historySessionId: normalizedSessionId,
|
|
3735
|
+
messageCount: currentSummary?.messageCount || 0,
|
|
3736
|
+
firstMessageAt: currentSummary?.firstMessageAt || 0,
|
|
3737
|
+
lastMessageAt: currentSummary?.lastMessageAt || 0,
|
|
3738
|
+
sessionTitle: currentSummary?.sessionTitle,
|
|
3739
|
+
preview: currentSummary?.preview,
|
|
3740
|
+
workspace: normalizedWorkspace
|
|
3741
|
+
}));
|
|
3742
|
+
}
|
|
3743
|
+
function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file2, historySessionId, messages) {
|
|
3744
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
|
|
3745
|
+
if (!normalizedSessionId || messages.length === 0) return;
|
|
3746
|
+
persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => {
|
|
3747
|
+
const nextSummary = {
|
|
3748
|
+
file: file2,
|
|
3749
|
+
historySessionId: normalizedSessionId,
|
|
3750
|
+
messageCount: currentSummary?.messageCount || 0,
|
|
3751
|
+
firstMessageAt: currentSummary?.firstMessageAt || 0,
|
|
3752
|
+
lastMessageAt: currentSummary?.lastMessageAt || 0,
|
|
3753
|
+
sessionTitle: currentSummary?.sessionTitle,
|
|
3754
|
+
preview: currentSummary?.preview,
|
|
3755
|
+
workspace: currentSummary?.workspace
|
|
3756
|
+
};
|
|
3757
|
+
for (const message of messages) {
|
|
3758
|
+
if (!message || message.historySessionId !== historySessionId) continue;
|
|
3759
|
+
if (message.kind === "session_start") {
|
|
3760
|
+
if (message.workspace) nextSummary.workspace = message.workspace;
|
|
3761
|
+
continue;
|
|
3762
|
+
}
|
|
3763
|
+
nextSummary.messageCount += 1;
|
|
3764
|
+
if (!nextSummary.firstMessageAt || message.receivedAt < nextSummary.firstMessageAt) {
|
|
3765
|
+
nextSummary.firstMessageAt = message.receivedAt;
|
|
3766
|
+
}
|
|
3767
|
+
if (!nextSummary.lastMessageAt || message.receivedAt >= nextSummary.lastMessageAt) {
|
|
3768
|
+
nextSummary.lastMessageAt = message.receivedAt;
|
|
3769
|
+
if (message.sessionTitle) nextSummary.sessionTitle = message.sessionTitle;
|
|
3770
|
+
if (message.role !== "system" && message.content.trim()) nextSummary.preview = message.content.trim();
|
|
3771
|
+
} else if (message.sessionTitle) {
|
|
3772
|
+
nextSummary.sessionTitle = message.sessionTitle;
|
|
3773
|
+
}
|
|
3774
|
+
if (!nextSummary.preview && message.role !== "system" && message.content.trim()) {
|
|
3775
|
+
nextSummary.preview = message.content.trim();
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
return nextSummary;
|
|
3779
|
+
});
|
|
3780
|
+
}
|
|
3781
|
+
function computeSavedHistoryFileSummary(agentType, dir, file2) {
|
|
3782
|
+
const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file2);
|
|
3783
|
+
if (!historySessionId) return null;
|
|
3784
|
+
const filePath = path7.join(dir, file2);
|
|
3785
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
3786
|
+
const lines = content.split("\n").filter(Boolean);
|
|
3787
|
+
let messageCount = 0;
|
|
3788
|
+
let firstMessageAt = 0;
|
|
3789
|
+
let lastMessageAt = 0;
|
|
3790
|
+
let sessionTitle = "";
|
|
3791
|
+
let preview = "";
|
|
3792
|
+
let workspace = "";
|
|
3793
|
+
for (const line of lines) {
|
|
3794
|
+
let parsed = null;
|
|
3795
|
+
try {
|
|
3796
|
+
parsed = JSON.parse(line);
|
|
3797
|
+
} catch {
|
|
3798
|
+
parsed = null;
|
|
3799
|
+
}
|
|
3800
|
+
if (!parsed || parsed.historySessionId !== historySessionId) continue;
|
|
3801
|
+
if (parsed.kind === "session_start") {
|
|
3802
|
+
if (!workspace && parsed.workspace) workspace = parsed.workspace;
|
|
3803
|
+
continue;
|
|
3804
|
+
}
|
|
3805
|
+
messageCount += 1;
|
|
3806
|
+
if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
|
|
3807
|
+
if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
|
|
3808
|
+
if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
|
|
3809
|
+
if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
|
|
3810
|
+
}
|
|
3811
|
+
if (messageCount === 0 || !lastMessageAt) return null;
|
|
3812
|
+
return {
|
|
3813
|
+
file: file2,
|
|
3814
|
+
historySessionId,
|
|
3815
|
+
messageCount,
|
|
3816
|
+
firstMessageAt,
|
|
3817
|
+
lastMessageAt,
|
|
3818
|
+
sessionTitle: sessionTitle || void 0,
|
|
3819
|
+
preview: preview || void 0,
|
|
3820
|
+
workspace: workspace || void 0
|
|
3821
|
+
};
|
|
3822
|
+
}
|
|
3823
|
+
function shouldScheduleSavedHistoryRollupForSignature(signature) {
|
|
3824
|
+
const parts = String(signature || "").split(":");
|
|
3825
|
+
const size = Number(parts[1] || 0);
|
|
3826
|
+
return shouldScheduleSavedHistoryRollup(size);
|
|
3827
|
+
}
|
|
3828
|
+
function scheduleSavedHistoryRollup(agentType, historySessionId) {
|
|
3829
|
+
const key = `${agentType}:${historySessionId}`;
|
|
3830
|
+
if (!historySessionId || savedHistoryRollupInFlight.has(key)) return;
|
|
3831
|
+
savedHistoryRollupInFlight.add(key);
|
|
3832
|
+
setTimeout(() => {
|
|
3833
|
+
try {
|
|
3834
|
+
new ChatHistoryWriter().compactHistorySession(agentType, historySessionId);
|
|
3835
|
+
} finally {
|
|
3836
|
+
savedHistoryRollupInFlight.delete(key);
|
|
3837
|
+
}
|
|
3838
|
+
}, 0);
|
|
3839
|
+
}
|
|
3840
|
+
function scheduleSavedHistoryBackgroundRefresh(agentType, dir) {
|
|
3841
|
+
const key = `${agentType}:${dir}`;
|
|
3842
|
+
if (savedHistoryBackgroundRefresh.has(key)) return;
|
|
3843
|
+
savedHistoryBackgroundRefresh.add(key);
|
|
3844
|
+
setTimeout(() => {
|
|
3845
|
+
try {
|
|
3846
|
+
if (!fs3.existsSync(dir)) return;
|
|
3847
|
+
const files = listHistoryFiles(dir);
|
|
3848
|
+
const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
|
|
3849
|
+
const persistedEntries = loadPersistedSavedHistoryIndex(dir);
|
|
3850
|
+
const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
|
|
3851
|
+
savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
|
|
3852
|
+
const refreshedIndexSignature = buildSavedHistoryIndexFileSignature(dir);
|
|
3853
|
+
savedHistorySessionCache.set(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"), {
|
|
3854
|
+
signature: refreshedIndexSignature,
|
|
3855
|
+
summaries: computed.summaries || []
|
|
3856
|
+
});
|
|
3857
|
+
for (const [file2, entry] of Array.from(computed.persistedEntries.entries())) {
|
|
3858
|
+
if (!entry?.summary || !shouldScheduleSavedHistoryRollupForSignature(entry.signature)) continue;
|
|
3859
|
+
scheduleSavedHistoryRollup(agentType, entry.summary.historySessionId);
|
|
3860
|
+
}
|
|
3861
|
+
} catch {
|
|
3862
|
+
} finally {
|
|
3863
|
+
savedHistoryBackgroundRefresh.delete(key);
|
|
3864
|
+
}
|
|
3865
|
+
}, 0);
|
|
3866
|
+
}
|
|
3867
|
+
function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries) {
|
|
3868
|
+
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
3869
|
+
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
3870
|
+
for (const file2 of files.slice().sort()) {
|
|
3871
|
+
const filePath = path7.join(dir, file2);
|
|
3872
|
+
const signature = fileSignatures.get(file2) || `${file2}:missing`;
|
|
3873
|
+
const cached2 = savedHistoryFileSummaryCache.get(filePath);
|
|
3874
|
+
const persisted = persistedEntries.get(file2);
|
|
3875
|
+
const reusableEntry = cached2?.signature === signature ? cached2 : persisted?.signature === signature ? persisted : null;
|
|
3876
|
+
const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file2);
|
|
3877
|
+
const nextEntry = reusableEntry || {
|
|
3878
|
+
signature,
|
|
3879
|
+
summary: fileSummary
|
|
3880
|
+
};
|
|
3881
|
+
if (!reusableEntry) {
|
|
3882
|
+
nextEntry.signature = signature;
|
|
3883
|
+
nextEntry.summary = fileSummary;
|
|
3884
|
+
}
|
|
3885
|
+
savedHistoryFileSummaryCache.set(filePath, nextEntry);
|
|
3886
|
+
nextPersistedEntries.set(file2, nextEntry);
|
|
3887
|
+
if (!fileSummary) continue;
|
|
3888
|
+
const existing = summaryBySessionId.get(fileSummary.historySessionId);
|
|
3889
|
+
if (fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) {
|
|
3890
|
+
continue;
|
|
3891
|
+
}
|
|
3892
|
+
if (!existing) {
|
|
3893
|
+
summaryBySessionId.set(fileSummary.historySessionId, {
|
|
3894
|
+
historySessionId: fileSummary.historySessionId,
|
|
3895
|
+
sessionTitle: fileSummary.sessionTitle,
|
|
3896
|
+
messageCount: fileSummary.messageCount,
|
|
3897
|
+
firstMessageAt: fileSummary.firstMessageAt,
|
|
3898
|
+
lastMessageAt: fileSummary.lastMessageAt,
|
|
3899
|
+
preview: fileSummary.preview,
|
|
3900
|
+
workspace: fileSummary.workspace
|
|
3901
|
+
});
|
|
3902
|
+
continue;
|
|
3903
|
+
}
|
|
3904
|
+
existing.messageCount += fileSummary.messageCount;
|
|
3905
|
+
if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
|
|
3906
|
+
existing.firstMessageAt = fileSummary.firstMessageAt;
|
|
3907
|
+
}
|
|
3908
|
+
if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
|
|
3909
|
+
existing.lastMessageAt = fileSummary.lastMessageAt;
|
|
3910
|
+
if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
|
|
3911
|
+
if (fileSummary.preview) existing.preview = fileSummary.preview;
|
|
3912
|
+
}
|
|
3913
|
+
if (!existing.workspace && fileSummary.workspace) {
|
|
3914
|
+
existing.workspace = fileSummary.workspace;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
return {
|
|
3918
|
+
summaries: Array.from(summaryBySessionId.values()).sort((a, b) => b.lastMessageAt - a.lastMessageAt),
|
|
3919
|
+
persistedEntries: nextPersistedEntries
|
|
3920
|
+
};
|
|
3423
3921
|
}
|
|
3424
3922
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0) {
|
|
3425
3923
|
try {
|
|
@@ -3477,18 +3975,51 @@ function listSavedHistorySessions(agentType, options = {}) {
|
|
|
3477
3975
|
savedHistorySessionCache.delete(sanitized);
|
|
3478
3976
|
return { sessions: [], hasMore: false };
|
|
3479
3977
|
}
|
|
3480
|
-
const files = listHistoryFiles(dir);
|
|
3481
|
-
const signature = buildSavedHistoryCacheSignature(dir, files);
|
|
3482
3978
|
const cached2 = savedHistorySessionCache.get(sanitized);
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3979
|
+
const offset = Math.max(0, options.offset || 0);
|
|
3980
|
+
const limit = Math.max(1, options.limit || 30);
|
|
3981
|
+
const indexSignature = buildSavedHistoryIndexFileSignature(dir);
|
|
3982
|
+
let cacheWasInvalidated = false;
|
|
3983
|
+
if (cached2) {
|
|
3984
|
+
const cacheLooksPersisted = cached2.signature.startsWith("index:");
|
|
3985
|
+
const cacheStillValid = cacheLooksPersisted ? cached2.signature === indexSignature : (() => {
|
|
3986
|
+
const files2 = listHistoryFiles(dir);
|
|
3987
|
+
const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
|
|
3988
|
+
return cached2.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
|
|
3989
|
+
})();
|
|
3990
|
+
if (cacheStillValid) {
|
|
3991
|
+
const sliced2 = cached2.summaries.slice(offset, offset + limit);
|
|
3992
|
+
return {
|
|
3993
|
+
sessions: sliced2,
|
|
3994
|
+
hasMore: cached2.summaries.length > offset + limit
|
|
3995
|
+
};
|
|
3996
|
+
}
|
|
3997
|
+
cacheWasInvalidated = true;
|
|
3998
|
+
}
|
|
3999
|
+
const persistedSessions = readPersistedSavedHistorySessionSummaries(dir);
|
|
4000
|
+
if (!cacheWasInvalidated && persistedSessions?.length && !historyDirectoryHasFilesNewerThanIndex(dir)) {
|
|
3485
4001
|
savedHistorySessionCache.set(sanitized, {
|
|
3486
|
-
signature,
|
|
3487
|
-
summaries
|
|
4002
|
+
signature: indexSignature,
|
|
4003
|
+
summaries: persistedSessions
|
|
3488
4004
|
});
|
|
4005
|
+
scheduleSavedHistoryBackgroundRefresh(agentType, dir);
|
|
4006
|
+
const sliced2 = persistedSessions.slice(offset, offset + limit);
|
|
4007
|
+
return {
|
|
4008
|
+
sessions: sliced2,
|
|
4009
|
+
hasMore: persistedSessions.length > offset + limit
|
|
4010
|
+
};
|
|
3489
4011
|
}
|
|
3490
|
-
const
|
|
3491
|
-
const
|
|
4012
|
+
const files = listHistoryFiles(dir);
|
|
4013
|
+
const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
|
|
4014
|
+
const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
|
|
4015
|
+
const persistedEntries = loadPersistedSavedHistoryIndex(dir);
|
|
4016
|
+
const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
|
|
4017
|
+
const summaries = computed.summaries || [];
|
|
4018
|
+
savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
|
|
4019
|
+
savedHistorySessionCache.set(sanitized, {
|
|
4020
|
+
signature,
|
|
4021
|
+
summaries
|
|
4022
|
+
});
|
|
3492
4023
|
const sliced = summaries.slice(offset, offset + limit);
|
|
3493
4024
|
return {
|
|
3494
4025
|
sessions: sliced,
|
|
@@ -3498,7 +4029,7 @@ function listSavedHistorySessions(agentType, options = {}) {
|
|
|
3498
4029
|
return { sessions: [], hasMore: false };
|
|
3499
4030
|
}
|
|
3500
4031
|
}
|
|
3501
|
-
var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, savedHistorySessionCache, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
|
|
4032
|
+
var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
|
|
3502
4033
|
var init_chat_history = __esm({
|
|
3503
4034
|
"../../oss/packages/daemon-core/src/config/chat-history.ts"() {
|
|
3504
4035
|
"use strict";
|
|
@@ -3506,9 +4037,20 @@ var init_chat_history = __esm({
|
|
|
3506
4037
|
path7 = __toESM(require("path"));
|
|
3507
4038
|
os5 = __toESM(require("os"));
|
|
3508
4039
|
init_chat_message_normalization();
|
|
4040
|
+
init_provider_session_id();
|
|
3509
4041
|
HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
|
|
3510
4042
|
RETAIN_DAYS = 30;
|
|
4043
|
+
SAVED_HISTORY_INDEX_VERSION = 1;
|
|
4044
|
+
SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
4045
|
+
SAVED_HISTORY_INDEX_LOCK_SUFFIX = ".lock";
|
|
4046
|
+
SAVED_HISTORY_INDEX_LOCK_WAIT_MS = 1500;
|
|
4047
|
+
SAVED_HISTORY_INDEX_LOCK_STALE_MS = 15e3;
|
|
4048
|
+
SAVED_HISTORY_INDEX_LOCK_POLL_MS = 25;
|
|
4049
|
+
SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES = 16 * 1024 * 1024;
|
|
3511
4050
|
savedHistorySessionCache = /* @__PURE__ */ new Map();
|
|
4051
|
+
savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
|
|
4052
|
+
savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
|
|
4053
|
+
savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
|
|
3512
4054
|
CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
|
|
3513
4055
|
ChatHistoryWriter = class {
|
|
3514
4056
|
/** Last seen message count per agent (deduplication) */
|
|
@@ -3583,9 +4125,11 @@ var init_chat_history = __esm({
|
|
|
3583
4125
|
fs3.mkdirSync(dir, { recursive: true });
|
|
3584
4126
|
const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3585
4127
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
3586
|
-
const
|
|
4128
|
+
const fileName = `${filePrefix}${date5}.jsonl`;
|
|
4129
|
+
const filePath = path7.join(dir, fileName);
|
|
3587
4130
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
3588
4131
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
4132
|
+
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
3589
4133
|
const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
|
|
3590
4134
|
if (!historySessionId && messages.length < prevCount * 0.5 && prevCount > 3) {
|
|
3591
4135
|
seenHashes.clear();
|
|
@@ -3676,7 +4220,8 @@ var init_chat_history = __esm({
|
|
|
3676
4220
|
const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
|
|
3677
4221
|
fs3.mkdirSync(dir, { recursive: true });
|
|
3678
4222
|
const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3679
|
-
const
|
|
4223
|
+
const fileName = `${this.sanitize(id)}_${date5}.jsonl`;
|
|
4224
|
+
const filePath = path7.join(dir, fileName);
|
|
3680
4225
|
const record2 = {
|
|
3681
4226
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3682
4227
|
receivedAt: Date.now(),
|
|
@@ -3689,6 +4234,7 @@ var init_chat_history = __esm({
|
|
|
3689
4234
|
workspace: ws
|
|
3690
4235
|
};
|
|
3691
4236
|
fs3.appendFileSync(filePath, JSON.stringify(record2) + "\n", "utf-8");
|
|
4237
|
+
updateSavedHistoryIndexForSessionStart(agentType, dir, fileName, id, ws);
|
|
3692
4238
|
} catch {
|
|
3693
4239
|
}
|
|
3694
4240
|
}
|
|
@@ -3754,6 +4300,7 @@ var init_chat_history = __esm({
|
|
|
3754
4300
|
}
|
|
3755
4301
|
fs3.unlinkSync(sourcePath);
|
|
3756
4302
|
}
|
|
4303
|
+
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
3757
4304
|
} catch {
|
|
3758
4305
|
}
|
|
3759
4306
|
}
|
|
@@ -3803,6 +4350,7 @@ var init_chat_history = __esm({
|
|
|
3803
4350
|
fs3.writeFileSync(filePath, `${collapsed.map((entry) => JSON.stringify(entry)).join("\n")}
|
|
3804
4351
|
`, "utf-8");
|
|
3805
4352
|
}
|
|
4353
|
+
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
3806
4354
|
} catch {
|
|
3807
4355
|
}
|
|
3808
4356
|
}
|
|
@@ -3822,13 +4370,18 @@ var init_chat_history = __esm({
|
|
|
3822
4370
|
for (const dir of agentDirs) {
|
|
3823
4371
|
const dirPath = path7.join(HISTORY_DIR, dir.name);
|
|
3824
4372
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
4373
|
+
let removedAny = false;
|
|
3825
4374
|
for (const file2 of files) {
|
|
3826
4375
|
const filePath = path7.join(dirPath, file2);
|
|
3827
4376
|
const stat4 = fs3.statSync(filePath);
|
|
3828
4377
|
if (stat4.mtimeMs < cutoff) {
|
|
3829
4378
|
fs3.unlinkSync(filePath);
|
|
4379
|
+
removedAny = true;
|
|
3830
4380
|
}
|
|
3831
4381
|
}
|
|
4382
|
+
if (removedAny) {
|
|
4383
|
+
invalidatePersistedSavedHistoryIndex(dir.name, dirPath);
|
|
4384
|
+
}
|
|
3832
4385
|
}
|
|
3833
4386
|
} catch {
|
|
3834
4387
|
}
|
|
@@ -5663,7 +6216,7 @@ function shouldIncludeSessionMetadata(profile) {
|
|
|
5663
6216
|
return profile !== "live";
|
|
5664
6217
|
}
|
|
5665
6218
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
5666
|
-
return
|
|
6219
|
+
return true;
|
|
5667
6220
|
}
|
|
5668
6221
|
function findCdpManager(cdpManagers, key) {
|
|
5669
6222
|
const exact = cdpManagers.get(key);
|
|
@@ -5755,6 +6308,21 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
5755
6308
|
lastUpdated: ext.lastUpdated
|
|
5756
6309
|
};
|
|
5757
6310
|
}
|
|
6311
|
+
function shouldIncludeExtensionSession(ext) {
|
|
6312
|
+
const status = String(ext.status || "").trim().toLowerCase();
|
|
6313
|
+
const hasActiveChat = !!ext.activeChat;
|
|
6314
|
+
const hasMessages = Array.isArray(ext.activeChat?.messages) && ext.activeChat.messages.length > 0;
|
|
6315
|
+
const hasModal = !!ext.activeChat?.activeModal;
|
|
6316
|
+
const hasStreams = Array.isArray(ext.agentStreams) && ext.agentStreams.length > 0;
|
|
6317
|
+
const hasProviderSessionId = typeof ext.providerSessionId === "string" && ext.providerSessionId.trim().length > 0;
|
|
6318
|
+
const hasControlValues = !!(ext.controlValues && Object.keys(ext.controlValues).length > 0);
|
|
6319
|
+
const hasProviderControls = Array.isArray(ext.providerControls) && ext.providerControls.length > 0;
|
|
6320
|
+
const hasOpenPanelCapability = Array.isArray(ext.sessionCapabilities) && ext.sessionCapabilities.includes("open_panel");
|
|
6321
|
+
const hasSummaryMetadata = !!ext.summaryMetadata;
|
|
6322
|
+
const hasError = typeof ext.errorMessage === "string" && ext.errorMessage.trim().length > 0;
|
|
6323
|
+
const hasInterestingStatus = !!status && !["idle", "panel_hidden", "disconnected", "not_monitored"].includes(status);
|
|
6324
|
+
return hasActiveChat || hasMessages || hasModal || hasStreams || hasProviderSessionId || hasControlValues || hasProviderControls || hasOpenPanelCapability || hasSummaryMetadata || hasError || hasInterestingStatus;
|
|
6325
|
+
}
|
|
5758
6326
|
function buildCliSession(state, options) {
|
|
5759
6327
|
const profile = options.profile || "full";
|
|
5760
6328
|
const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
|
|
@@ -5780,8 +6348,12 @@ function buildCliSession(state, options) {
|
|
|
5780
6348
|
runtimeKey: state.runtime?.runtimeKey,
|
|
5781
6349
|
runtimeDisplayName: state.runtime?.displayName,
|
|
5782
6350
|
runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
|
|
6351
|
+
runtimeLifecycle: state.runtime?.lifecycle ?? null,
|
|
6352
|
+
runtimeSurfaceKind: state.runtime?.surfaceKind,
|
|
5783
6353
|
runtimeWriteOwner: state.runtime?.writeOwner || null,
|
|
5784
|
-
runtimeAttachedClients: state.runtime?.attachedClients || []
|
|
6354
|
+
runtimeAttachedClients: state.runtime?.attachedClients || [],
|
|
6355
|
+
runtimeRestoredFromStorage: state.runtime?.restoredFromStorage === true,
|
|
6356
|
+
runtimeRecoveryState: state.runtime?.recoveryState ?? null
|
|
5785
6357
|
},
|
|
5786
6358
|
mode: state.mode,
|
|
5787
6359
|
resume: state.resume,
|
|
@@ -5838,6 +6410,7 @@ function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
|
5838
6410
|
for (const state of ideStates) {
|
|
5839
6411
|
sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
|
|
5840
6412
|
for (const ext of state.extensions) {
|
|
6413
|
+
if (!shouldIncludeExtensionSession(ext)) continue;
|
|
5841
6414
|
sessions.push(buildExtensionAgentSession(state, ext, options));
|
|
5842
6415
|
}
|
|
5843
6416
|
}
|
|
@@ -8090,7 +8663,9 @@ function applyProviderPatch(h, args, payload) {
|
|
|
8090
8663
|
});
|
|
8091
8664
|
}
|
|
8092
8665
|
async function executeProviderScript(h, args, scriptName) {
|
|
8093
|
-
const
|
|
8666
|
+
const explicitTargetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
8667
|
+
const targetSession = explicitTargetSessionId ? h.ctx.sessionRegistry?.get(explicitTargetSessionId) : void 0;
|
|
8668
|
+
const resolvedProviderType = targetSession?.providerType || h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
|
|
8094
8669
|
if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
|
|
8095
8670
|
const loader = h.ctx.providerLoader;
|
|
8096
8671
|
if (!loader) return { success: false, error: "ProviderLoader not initialized" };
|
|
@@ -8133,16 +8708,16 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
8133
8708
|
const scriptFn = provider.scripts[actualScriptName];
|
|
8134
8709
|
const scriptCode = scriptFn(normalizedArgs);
|
|
8135
8710
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
8136
|
-
const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
|
|
8711
|
+
const cdpKey = provider.category === "ide" ? targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey;
|
|
8137
8712
|
LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
|
|
8138
8713
|
const cdp = h.getCdp(cdpKey);
|
|
8139
8714
|
if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
|
|
8140
8715
|
try {
|
|
8141
8716
|
let result;
|
|
8142
8717
|
if (provider.category === "extension") {
|
|
8143
|
-
const runtimeSessionId = h.currentSession?.sessionId
|
|
8718
|
+
const runtimeSessionId = explicitTargetSessionId || h.currentSession?.sessionId;
|
|
8144
8719
|
if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
|
|
8145
|
-
const parentSessionId = h.currentSession?.parentSessionId;
|
|
8720
|
+
const parentSessionId = targetSession?.parentSessionId || h.currentSession?.parentSessionId;
|
|
8146
8721
|
if (parentSessionId) {
|
|
8147
8722
|
await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
|
|
8148
8723
|
await h.agentStream?.syncActiveSession(cdp, parentSessionId);
|
|
@@ -12492,8 +13067,12 @@ var init_cli_provider_instance = __esm({
|
|
|
12492
13067
|
runtimeKey: runtime.runtimeKey,
|
|
12493
13068
|
displayName: runtime.displayName,
|
|
12494
13069
|
workspaceLabel: runtime.workspaceLabel,
|
|
13070
|
+
lifecycle: runtime.lifecycle ?? null,
|
|
13071
|
+
surfaceKind: runtime.surfaceKind,
|
|
12495
13072
|
writeOwner: runtime.writeOwner || null,
|
|
12496
|
-
attachedClients: runtime.attachedClients || []
|
|
13073
|
+
attachedClients: runtime.attachedClients || [],
|
|
13074
|
+
restoredFromStorage: runtime.restoredFromStorage === true,
|
|
13075
|
+
recoveryState: runtime.recoveryState ?? null
|
|
12497
13076
|
} : void 0,
|
|
12498
13077
|
resume: this.provider.resume,
|
|
12499
13078
|
controlValues: surface.controlValues,
|
|
@@ -34904,67 +35483,6 @@ var init_command_log = __esm({
|
|
|
34904
35483
|
}
|
|
34905
35484
|
});
|
|
34906
35485
|
|
|
34907
|
-
// ../../oss/packages/daemon-core/src/session-host/runtime-surface.ts
|
|
34908
|
-
function isSessionHostLiveRuntime(record2) {
|
|
34909
|
-
const lifecycle = String(record2?.lifecycle || "").trim();
|
|
34910
|
-
return LIVE_LIFECYCLES.has(lifecycle);
|
|
34911
|
-
}
|
|
34912
|
-
function getSessionHostRecoveryLabel(meta3) {
|
|
34913
|
-
const recoveryState = typeof meta3?.runtimeRecoveryState === "string" ? String(meta3.runtimeRecoveryState).trim() : "";
|
|
34914
|
-
if (!recoveryState) return null;
|
|
34915
|
-
if (recoveryState === "auto_resumed") return "restored after restart";
|
|
34916
|
-
if (recoveryState === "resume_failed") return "restore failed";
|
|
34917
|
-
if (recoveryState === "host_restart_interrupted") return "host restart interrupted";
|
|
34918
|
-
if (recoveryState === "orphan_snapshot") return "snapshot recovered";
|
|
34919
|
-
return recoveryState.replace(/_/g, " ");
|
|
34920
|
-
}
|
|
34921
|
-
function isSessionHostRecoverySnapshot(record2) {
|
|
34922
|
-
if (!record2) return false;
|
|
34923
|
-
if (isSessionHostLiveRuntime(record2)) return false;
|
|
34924
|
-
const lifecycle = String(record2.lifecycle || "").trim();
|
|
34925
|
-
if (lifecycle && lifecycle !== "stopped" && lifecycle !== "failed") {
|
|
34926
|
-
return false;
|
|
34927
|
-
}
|
|
34928
|
-
const meta3 = record2.meta || void 0;
|
|
34929
|
-
if (meta3?.restoredFromStorage === true) return true;
|
|
34930
|
-
return getSessionHostRecoveryLabel(meta3) !== null;
|
|
34931
|
-
}
|
|
34932
|
-
function getSessionHostSurfaceKind(record2) {
|
|
34933
|
-
if (isSessionHostLiveRuntime(record2)) return "live_runtime";
|
|
34934
|
-
if (isSessionHostRecoverySnapshot(record2)) return "recovery_snapshot";
|
|
34935
|
-
return "inactive_record";
|
|
34936
|
-
}
|
|
34937
|
-
function partitionSessionHostRecords(records) {
|
|
34938
|
-
const liveRuntimes = [];
|
|
34939
|
-
const recoverySnapshots = [];
|
|
34940
|
-
const inactiveRecords = [];
|
|
34941
|
-
for (const record2 of records) {
|
|
34942
|
-
const kind = getSessionHostSurfaceKind(record2);
|
|
34943
|
-
if (kind === "live_runtime") {
|
|
34944
|
-
liveRuntimes.push(record2);
|
|
34945
|
-
} else if (kind === "recovery_snapshot") {
|
|
34946
|
-
recoverySnapshots.push(record2);
|
|
34947
|
-
} else {
|
|
34948
|
-
inactiveRecords.push(record2);
|
|
34949
|
-
}
|
|
34950
|
-
}
|
|
34951
|
-
return {
|
|
34952
|
-
liveRuntimes,
|
|
34953
|
-
recoverySnapshots,
|
|
34954
|
-
inactiveRecords
|
|
34955
|
-
};
|
|
34956
|
-
}
|
|
34957
|
-
function partitionSessionHostDiagnosticsSessions(records) {
|
|
34958
|
-
return partitionSessionHostRecords(records || []);
|
|
34959
|
-
}
|
|
34960
|
-
var LIVE_LIFECYCLES;
|
|
34961
|
-
var init_runtime_surface = __esm({
|
|
34962
|
-
"../../oss/packages/daemon-core/src/session-host/runtime-surface.ts"() {
|
|
34963
|
-
"use strict";
|
|
34964
|
-
LIVE_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
34965
|
-
}
|
|
34966
|
-
});
|
|
34967
|
-
|
|
34968
35486
|
// ../../oss/packages/daemon-core/src/status/snapshot.ts
|
|
34969
35487
|
function buildRecentReadDebugSignature(snapshot) {
|
|
34970
35488
|
return [
|
|
@@ -36582,6 +37100,28 @@ var init_subscription_updates = __esm({
|
|
|
36582
37100
|
}
|
|
36583
37101
|
});
|
|
36584
37102
|
|
|
37103
|
+
// ../../oss/packages/daemon-core/src/chat/async-batch.ts
|
|
37104
|
+
async function runAsyncBatch(items, worker, options = {}) {
|
|
37105
|
+
const list = Array.from(items);
|
|
37106
|
+
if (list.length === 0) return;
|
|
37107
|
+
const concurrency = Math.max(1, Math.min(list.length, Math.floor(options.concurrency || 1)));
|
|
37108
|
+
let nextIndex = 0;
|
|
37109
|
+
const runners = Array.from({ length: concurrency }, async () => {
|
|
37110
|
+
while (true) {
|
|
37111
|
+
const currentIndex = nextIndex;
|
|
37112
|
+
nextIndex += 1;
|
|
37113
|
+
if (currentIndex >= list.length) return;
|
|
37114
|
+
await worker(list[currentIndex], currentIndex);
|
|
37115
|
+
}
|
|
37116
|
+
});
|
|
37117
|
+
await Promise.all(runners);
|
|
37118
|
+
}
|
|
37119
|
+
var init_async_batch = __esm({
|
|
37120
|
+
"../../oss/packages/daemon-core/src/chat/async-batch.ts"() {
|
|
37121
|
+
"use strict";
|
|
37122
|
+
}
|
|
37123
|
+
});
|
|
37124
|
+
|
|
36585
37125
|
// ../../oss/packages/daemon-core/src/agent-stream/provider-adapter.ts
|
|
36586
37126
|
var ProviderStreamAdapter;
|
|
36587
37127
|
var init_provider_adapter = __esm({
|
|
@@ -37063,10 +37603,12 @@ var init_manager2 = __esm({
|
|
|
37063
37603
|
}
|
|
37064
37604
|
}
|
|
37065
37605
|
/** Collect active extension session state */
|
|
37066
|
-
async collectActiveSession(cdp, parentSessionId) {
|
|
37606
|
+
async collectActiveSession(cdp, parentSessionId, attemptedSessionIds = /* @__PURE__ */ new Set(), originSessionId) {
|
|
37067
37607
|
if (!this.enabled) return null;
|
|
37068
37608
|
const activeSessionId = this.getActiveSessionId(parentSessionId);
|
|
37069
37609
|
if (!activeSessionId) return null;
|
|
37610
|
+
const resolvedOriginSessionId = originSessionId || activeSessionId;
|
|
37611
|
+
attemptedSessionIds.add(activeSessionId);
|
|
37070
37612
|
let agent = this.managedBySessionId.get(activeSessionId);
|
|
37071
37613
|
if (!agent) {
|
|
37072
37614
|
agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
|
|
@@ -37079,18 +37621,44 @@ var init_manager2 = __esm({
|
|
|
37079
37621
|
try {
|
|
37080
37622
|
const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
|
|
37081
37623
|
const state = await agent.adapter.readChat(evaluate);
|
|
37082
|
-
const
|
|
37083
|
-
const
|
|
37084
|
-
|
|
37085
|
-
|
|
37624
|
+
const resolvedProviderSessionId = typeof state.providerSessionId === "string" && state.providerSessionId.trim() ? state.providerSessionId.trim() : typeof state.sessionId === "string" && state.sessionId.trim() && state.sessionId !== agent.runtimeSessionId ? state.sessionId.trim() : void 0;
|
|
37625
|
+
const normalizedState = {
|
|
37626
|
+
...state,
|
|
37627
|
+
sessionId: agent.runtimeSessionId,
|
|
37628
|
+
...resolvedProviderSessionId ? { providerSessionId: resolvedProviderSessionId } : {}
|
|
37629
|
+
};
|
|
37630
|
+
const stateError = this.getStateError(normalizedState);
|
|
37631
|
+
const selectedModelValue = typeof normalizedState.controlValues?.model === "string" ? normalizedState.controlValues.model : "";
|
|
37632
|
+
LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${normalizedState.status} msgs=${normalizedState.messages?.length || 0} model=${selectedModelValue}${normalizedState.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
|
|
37633
|
+
if (normalizedState.status === "error" && this.isRecoverableSessionError(stateError)) {
|
|
37086
37634
|
throw new Error(stateError);
|
|
37087
37635
|
}
|
|
37088
|
-
agent.lastState =
|
|
37636
|
+
agent.lastState = normalizedState;
|
|
37089
37637
|
agent.lastError = null;
|
|
37090
|
-
if (
|
|
37638
|
+
if (normalizedState.status === "panel_hidden") {
|
|
37639
|
+
const discovered = await cdp.discoverAgentWebviews().catch(() => []);
|
|
37640
|
+
const fallbackTarget = discovered.find((entry) => {
|
|
37641
|
+
if (entry.agentType === type) return false;
|
|
37642
|
+
const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, entry.agentType);
|
|
37643
|
+
return !!fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId);
|
|
37644
|
+
});
|
|
37645
|
+
if (fallbackTarget) {
|
|
37646
|
+
const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, fallbackTarget.agentType);
|
|
37647
|
+
if (fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId)) {
|
|
37648
|
+
this.logFn(`[AgentStream] Active session ${type} is hidden; switching to visible agent ${fallbackTarget.agentType} (${parentSessionId})`);
|
|
37649
|
+
await this.setActiveSession(cdp, parentSessionId, fallbackSessionId);
|
|
37650
|
+
await this.syncActiveSession(cdp, parentSessionId);
|
|
37651
|
+
const fallbackState = await this.collectActiveSession(cdp, parentSessionId, attemptedSessionIds, resolvedOriginSessionId);
|
|
37652
|
+
if (fallbackState?.status === "panel_hidden" && resolvedOriginSessionId !== fallbackSessionId) {
|
|
37653
|
+
await this.setActiveSession(cdp, parentSessionId, resolvedOriginSessionId);
|
|
37654
|
+
await this.syncActiveSession(cdp, parentSessionId);
|
|
37655
|
+
}
|
|
37656
|
+
return fallbackState;
|
|
37657
|
+
}
|
|
37658
|
+
}
|
|
37091
37659
|
agent.lastHiddenCheckTime = Date.now();
|
|
37092
37660
|
}
|
|
37093
|
-
return
|
|
37661
|
+
return normalizedState;
|
|
37094
37662
|
} catch (e) {
|
|
37095
37663
|
const errorMsg = e?.message || String(e);
|
|
37096
37664
|
this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
|
|
@@ -37402,6 +37970,7 @@ var init_poller = __esm({
|
|
|
37402
37970
|
try {
|
|
37403
37971
|
await agentStreamManager.syncActiveSession(cdp, parentSessionId);
|
|
37404
37972
|
let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
|
|
37973
|
+
resolvedActiveSessionId = stream?.sessionId || agentStreamManager.getActiveSessionId(parentSessionId) || resolvedActiveSessionId;
|
|
37405
37974
|
if (stream?.status === "waiting_approval") {
|
|
37406
37975
|
const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
|
|
37407
37976
|
if (autoApprove && resolvedActiveSessionId) {
|
|
@@ -43444,6 +44013,8 @@ var init_session_host_transport = __esm({
|
|
|
43444
44013
|
runtimeKey: record2.runtimeKey,
|
|
43445
44014
|
displayName: record2.displayName,
|
|
43446
44015
|
workspaceLabel: record2.workspaceLabel,
|
|
44016
|
+
lifecycle: typeof record2.lifecycle === "string" ? record2.lifecycle : null,
|
|
44017
|
+
surfaceKind: record2.surfaceKind,
|
|
43447
44018
|
writeOwner: record2.writeOwner ? {
|
|
43448
44019
|
clientId: record2.writeOwner.clientId,
|
|
43449
44020
|
ownerType: record2.writeOwner.ownerType
|
|
@@ -44221,6 +44792,7 @@ __export(src_exports, {
|
|
|
44221
44792
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
44222
44793
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
44223
44794
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
44795
|
+
runAsyncBatch: () => runAsyncBatch,
|
|
44224
44796
|
saveConfig: () => saveConfig,
|
|
44225
44797
|
saveState: () => saveState,
|
|
44226
44798
|
setDebugRuntimeConfig: () => setDebugRuntimeConfig,
|
|
@@ -44268,6 +44840,7 @@ var init_src = __esm({
|
|
|
44268
44840
|
init_chat_history();
|
|
44269
44841
|
init_chat_signatures();
|
|
44270
44842
|
init_subscription_updates();
|
|
44843
|
+
init_async_batch();
|
|
44271
44844
|
init_agent_stream();
|
|
44272
44845
|
init_agent_stream();
|
|
44273
44846
|
init_forward();
|
|
@@ -45356,6 +45929,7 @@ var init_daemon_p2p = __esm({
|
|
|
45356
45929
|
fs15 = __toESM(require("fs"));
|
|
45357
45930
|
path23 = __toESM(require("path"));
|
|
45358
45931
|
import_node_module2 = require("module");
|
|
45932
|
+
init_src();
|
|
45359
45933
|
init_data_channel_router();
|
|
45360
45934
|
init_screenshot_sender();
|
|
45361
45935
|
init_peer_connection_manager();
|
|
@@ -45605,14 +46179,22 @@ ${e?.stack || ""}`);
|
|
|
45605
46179
|
return false;
|
|
45606
46180
|
}
|
|
45607
46181
|
async flushChatSubscriptions(builder) {
|
|
46182
|
+
const tasks = [];
|
|
45608
46183
|
for (const peer of this.peers.values()) {
|
|
45609
46184
|
if (peer.state !== "connected" || !peer.chatSubscriptions || peer.chatSubscriptions.size === 0) continue;
|
|
45610
46185
|
for (const subscription of peer.chatSubscriptions.values()) {
|
|
46186
|
+
tasks.push({ peer, subscription });
|
|
46187
|
+
}
|
|
46188
|
+
}
|
|
46189
|
+
await runAsyncBatch(tasks, async ({ peer, subscription }) => {
|
|
46190
|
+
try {
|
|
45611
46191
|
const update = await builder(subscription);
|
|
45612
|
-
if (!update)
|
|
46192
|
+
if (!update) return;
|
|
45613
46193
|
this.screenshotSender.sendTopicUpdateToPeer(peer, update);
|
|
46194
|
+
} catch (error48) {
|
|
46195
|
+
log(`chat_tail flush skipped: peer=${peer.peerId} session=${subscription.params.targetSessionId} error=${error48?.message || error48}`);
|
|
45614
46196
|
}
|
|
45615
|
-
}
|
|
46197
|
+
}, { concurrency: 4 });
|
|
45616
46198
|
}
|
|
45617
46199
|
async flushMachineRuntimeSubscriptions(builder) {
|
|
45618
46200
|
for (const peer of this.peers.values()) {
|
|
@@ -53563,7 +54145,7 @@ var init_adhdev_daemon = __esm({
|
|
|
53563
54145
|
init_source2();
|
|
53564
54146
|
init_version();
|
|
53565
54147
|
init_src();
|
|
53566
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.
|
|
54148
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.77" });
|
|
53567
54149
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
53568
54150
|
localHttpServer = null;
|
|
53569
54151
|
localWss = null;
|
|
@@ -53977,7 +54559,7 @@ ${err?.stack || ""}`);
|
|
|
53977
54559
|
}),
|
|
53978
54560
|
onStatusChange: () => {
|
|
53979
54561
|
this.statusReporter?.onStatusChange();
|
|
53980
|
-
void this.flushP2PChatSubscriptions({ onlyActive:
|
|
54562
|
+
void this.flushP2PChatSubscriptions({ onlyActive: true });
|
|
53981
54563
|
},
|
|
53982
54564
|
removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
|
|
53983
54565
|
hostedRuntimeManagerTag: "adhdev-cloud",
|
|
@@ -54006,7 +54588,7 @@ ${err?.stack || ""}`);
|
|
|
54006
54588
|
statusVersion: pkgVersion,
|
|
54007
54589
|
onStatusChange: () => {
|
|
54008
54590
|
this.statusReporter?.onStatusChange();
|
|
54009
|
-
void this.flushP2PChatSubscriptions({ onlyActive:
|
|
54591
|
+
void this.flushP2PChatSubscriptions({ onlyActive: true });
|
|
54010
54592
|
},
|
|
54011
54593
|
onPostChatCommand: () => {
|
|
54012
54594
|
setTimeout(() => this.statusReporter?.throttledReport(), 1e3);
|