@adhdev/daemon-core 0.8.74 → 0.8.76
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-stream/manager.d.ts +1 -1
- package/dist/cdp/manager.d.ts +9 -2
- package/dist/chat/async-batch.d.ts +4 -0
- package/dist/config/chat-history.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +621 -88
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +620 -88
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/agent-stream/manager.ts +47 -8
- package/src/agent-stream/poller.ts +1 -0
- package/src/cdp/manager.ts +65 -13
- package/src/chat/async-batch.ts +26 -0
- package/src/commands/stream-commands.ts +8 -5
- package/src/config/chat-history.ts +596 -63
- package/src/index.ts +2 -0
- package/src/status/builders.ts +28 -0
package/dist/index.js
CHANGED
|
@@ -3667,6 +3667,7 @@ __export(index_exports, {
|
|
|
3667
3667
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
3668
3668
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
3669
3669
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
3670
|
+
runAsyncBatch: () => runAsyncBatch,
|
|
3670
3671
|
saveConfig: () => saveConfig,
|
|
3671
3672
|
saveState: () => saveState,
|
|
3672
3673
|
setDebugRuntimeConfig: () => setDebugRuntimeConfig,
|
|
@@ -4451,6 +4452,32 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
|
|
|
4451
4452
|
var import_ws = __toESM(require("ws"));
|
|
4452
4453
|
var http = __toESM(require("http"));
|
|
4453
4454
|
init_logger();
|
|
4455
|
+
function normalizeTitle(value) {
|
|
4456
|
+
return String(value || "").trim().replace(/\s+/g, " ").toLowerCase();
|
|
4457
|
+
}
|
|
4458
|
+
function titlesMatch(lhs, rhs) {
|
|
4459
|
+
const a = normalizeTitle(lhs);
|
|
4460
|
+
const b = normalizeTitle(rhs);
|
|
4461
|
+
if (!a || !b) return false;
|
|
4462
|
+
return a === b || a.includes(b) || b.includes(a);
|
|
4463
|
+
}
|
|
4464
|
+
function resolveCdpPageTarget(params) {
|
|
4465
|
+
const { pages, pinnedTargetId, previousPageTitle } = params;
|
|
4466
|
+
if (pages.length === 0) return { target: null, retargeted: false };
|
|
4467
|
+
if (!pinnedTargetId) {
|
|
4468
|
+
return { target: pages[0] || null, retargeted: false };
|
|
4469
|
+
}
|
|
4470
|
+
const exact = pages.find((page) => page.id === pinnedTargetId);
|
|
4471
|
+
if (exact) return { target: exact, retargeted: false };
|
|
4472
|
+
const titleMatchesList = pages.filter((page) => titlesMatch(page.title, previousPageTitle));
|
|
4473
|
+
if (titleMatchesList.length === 1) {
|
|
4474
|
+
return { target: titleMatchesList[0], retargeted: true };
|
|
4475
|
+
}
|
|
4476
|
+
if (pages.length === 1) {
|
|
4477
|
+
return { target: pages[0], retargeted: true };
|
|
4478
|
+
}
|
|
4479
|
+
return { target: null, retargeted: false };
|
|
4480
|
+
}
|
|
4454
4481
|
var DaemonCdpManager = class {
|
|
4455
4482
|
ws = null;
|
|
4456
4483
|
browserWs = null;
|
|
@@ -4611,18 +4638,28 @@ var DaemonCdpManager = class {
|
|
|
4611
4638
|
resolve11(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
4612
4639
|
return;
|
|
4613
4640
|
}
|
|
4614
|
-
const
|
|
4615
|
-
const
|
|
4641
|
+
const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
4642
|
+
const mainPages = titleFilteredPages.filter((t) => this.isMainPageUrl(t.url));
|
|
4643
|
+
const list = mainPages.length > 0 ? mainPages : titleFilteredPages.length > 0 ? titleFilteredPages : pages;
|
|
4616
4644
|
this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4645
|
+
const previousTargetId = this._targetId;
|
|
4646
|
+
const selected = resolveCdpPageTarget({
|
|
4647
|
+
pages: list,
|
|
4648
|
+
pinnedTargetId: previousTargetId,
|
|
4649
|
+
previousPageTitle: this._pageTitle
|
|
4650
|
+
});
|
|
4651
|
+
if (selected.target) {
|
|
4652
|
+
if (selected.retargeted && previousTargetId && previousTargetId !== selected.target.id) {
|
|
4653
|
+
this.log(`[CDP] Target ${previousTargetId} rekeyed to ${selected.target.id}`);
|
|
4654
|
+
this._targetId = selected.target.id;
|
|
4625
4655
|
}
|
|
4656
|
+
this._pageTitle = selected.target.title || "";
|
|
4657
|
+
resolve11(selected.target);
|
|
4658
|
+
return;
|
|
4659
|
+
}
|
|
4660
|
+
if (previousTargetId) {
|
|
4661
|
+
this.log(`[CDP] Target ${previousTargetId} not found in page list`);
|
|
4662
|
+
resolve11(null);
|
|
4626
4663
|
return;
|
|
4627
4664
|
}
|
|
4628
4665
|
this._pageTitle = list[0]?.title || "";
|
|
@@ -6062,7 +6099,17 @@ var os5 = __toESM(require("os"));
|
|
|
6062
6099
|
init_chat_message_normalization();
|
|
6063
6100
|
var HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
|
|
6064
6101
|
var RETAIN_DAYS = 30;
|
|
6102
|
+
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
6103
|
+
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
6104
|
+
var SAVED_HISTORY_INDEX_LOCK_SUFFIX = ".lock";
|
|
6105
|
+
var SAVED_HISTORY_INDEX_LOCK_WAIT_MS = 1500;
|
|
6106
|
+
var SAVED_HISTORY_INDEX_LOCK_STALE_MS = 15e3;
|
|
6107
|
+
var SAVED_HISTORY_INDEX_LOCK_POLL_MS = 25;
|
|
6108
|
+
var SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES = 16 * 1024 * 1024;
|
|
6065
6109
|
var savedHistorySessionCache = /* @__PURE__ */ new Map();
|
|
6110
|
+
var savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
|
|
6111
|
+
var savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
|
|
6112
|
+
var savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
|
|
6066
6113
|
var 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;
|
|
6067
6114
|
function normalizeHistoryComparable(text) {
|
|
6068
6115
|
return String(text || "").replace(/\s+/g, " ").trim();
|
|
@@ -6120,6 +6167,68 @@ function sanitizeHistoryMessage(agentType, message) {
|
|
|
6120
6167
|
content
|
|
6121
6168
|
};
|
|
6122
6169
|
}
|
|
6170
|
+
function sortSavedHistorySessionSummaries(summaries) {
|
|
6171
|
+
return summaries.slice().sort((a, b) => b.lastMessageAt - a.lastMessageAt);
|
|
6172
|
+
}
|
|
6173
|
+
function buildSavedHistorySessionSummaryMapFromEntries(entries) {
|
|
6174
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
6175
|
+
for (const entry of Array.from(entries.values())) {
|
|
6176
|
+
const fileSummary = entry.summary;
|
|
6177
|
+
if (!fileSummary || fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) continue;
|
|
6178
|
+
const existing = summaries.get(fileSummary.historySessionId);
|
|
6179
|
+
if (!existing) {
|
|
6180
|
+
summaries.set(fileSummary.historySessionId, {
|
|
6181
|
+
historySessionId: fileSummary.historySessionId,
|
|
6182
|
+
sessionTitle: fileSummary.sessionTitle,
|
|
6183
|
+
messageCount: fileSummary.messageCount,
|
|
6184
|
+
firstMessageAt: fileSummary.firstMessageAt,
|
|
6185
|
+
lastMessageAt: fileSummary.lastMessageAt,
|
|
6186
|
+
preview: fileSummary.preview,
|
|
6187
|
+
workspace: fileSummary.workspace
|
|
6188
|
+
});
|
|
6189
|
+
continue;
|
|
6190
|
+
}
|
|
6191
|
+
existing.messageCount += fileSummary.messageCount;
|
|
6192
|
+
if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
|
|
6193
|
+
existing.firstMessageAt = fileSummary.firstMessageAt;
|
|
6194
|
+
}
|
|
6195
|
+
if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
|
|
6196
|
+
existing.lastMessageAt = fileSummary.lastMessageAt;
|
|
6197
|
+
if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
|
|
6198
|
+
if (fileSummary.preview) existing.preview = fileSummary.preview;
|
|
6199
|
+
}
|
|
6200
|
+
if (!existing.workspace && fileSummary.workspace) {
|
|
6201
|
+
existing.workspace = fileSummary.workspace;
|
|
6202
|
+
}
|
|
6203
|
+
}
|
|
6204
|
+
return Object.fromEntries(sortSavedHistorySessionSummaries(Array.from(summaries.values())).map((summary) => [summary.historySessionId, summary]));
|
|
6205
|
+
}
|
|
6206
|
+
function readPersistedSavedHistorySessionSummaries(dir) {
|
|
6207
|
+
try {
|
|
6208
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
6209
|
+
if (!fs3.existsSync(filePath)) return null;
|
|
6210
|
+
const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
6211
|
+
if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.sessions || typeof raw.sessions !== "object") {
|
|
6212
|
+
return null;
|
|
6213
|
+
}
|
|
6214
|
+
return sortSavedHistorySessionSummaries(
|
|
6215
|
+
Object.values(raw.sessions).filter((summary) => !!summary && typeof summary.historySessionId === "string" && summary.messageCount > 0 && summary.lastMessageAt > 0).map((summary) => ({
|
|
6216
|
+
historySessionId: summary.historySessionId,
|
|
6217
|
+
sessionTitle: summary.sessionTitle,
|
|
6218
|
+
messageCount: summary.messageCount,
|
|
6219
|
+
firstMessageAt: summary.firstMessageAt,
|
|
6220
|
+
lastMessageAt: summary.lastMessageAt,
|
|
6221
|
+
preview: summary.preview,
|
|
6222
|
+
workspace: summary.workspace
|
|
6223
|
+
}))
|
|
6224
|
+
);
|
|
6225
|
+
} catch {
|
|
6226
|
+
return null;
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
function shouldScheduleSavedHistoryRollup(totalBytes) {
|
|
6230
|
+
return Number.isFinite(totalBytes) && totalBytes >= SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES;
|
|
6231
|
+
}
|
|
6123
6232
|
function sanitizeHistoryFileSegment(value) {
|
|
6124
6233
|
return String(value || "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6125
6234
|
}
|
|
@@ -6133,71 +6242,386 @@ function listHistoryFiles(dir, historySessionId) {
|
|
|
6133
6242
|
return true;
|
|
6134
6243
|
}).sort().reverse();
|
|
6135
6244
|
}
|
|
6136
|
-
function
|
|
6137
|
-
|
|
6245
|
+
function normalizeSavedHistorySessionId(agentType, historySessionId) {
|
|
6246
|
+
const normalizedId = String(historySessionId || "").trim();
|
|
6247
|
+
if (!normalizedId) return "";
|
|
6248
|
+
const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
|
|
6249
|
+
if (strictProviderId) return strictProviderId;
|
|
6250
|
+
return agentType === "hermes-cli" ? "" : normalizedId;
|
|
6251
|
+
}
|
|
6252
|
+
function extractSavedHistorySessionIdFromFile(agentType, file) {
|
|
6253
|
+
const match = file.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
|
|
6254
|
+
return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
|
|
6255
|
+
}
|
|
6256
|
+
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
6257
|
+
return new Map(files.map((file) => {
|
|
6138
6258
|
try {
|
|
6139
6259
|
const stat = fs3.statSync(path7.join(dir, file));
|
|
6140
|
-
return `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}
|
|
6260
|
+
return [file, `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`];
|
|
6141
6261
|
} catch {
|
|
6142
|
-
return `${file}:missing
|
|
6143
|
-
}
|
|
6144
|
-
})
|
|
6145
|
-
}
|
|
6146
|
-
function
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6262
|
+
return [file, `${file}:missing`];
|
|
6263
|
+
}
|
|
6264
|
+
}));
|
|
6265
|
+
}
|
|
6266
|
+
function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
6267
|
+
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
6268
|
+
}
|
|
6269
|
+
function getSavedHistoryIndexFilePath(dir) {
|
|
6270
|
+
return path7.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
6271
|
+
}
|
|
6272
|
+
function getSavedHistoryIndexLockPath(dir) {
|
|
6273
|
+
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
6274
|
+
}
|
|
6275
|
+
function sleepBlocking(ms) {
|
|
6276
|
+
if (ms <= 0) return;
|
|
6277
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
6278
|
+
}
|
|
6279
|
+
function loadPersistedSavedHistoryIndexFromFile(dir) {
|
|
6280
|
+
try {
|
|
6281
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
6282
|
+
if (!fs3.existsSync(filePath)) return /* @__PURE__ */ new Map();
|
|
6283
|
+
const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
6284
|
+
if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.files || typeof raw.files !== "object") {
|
|
6285
|
+
return /* @__PURE__ */ new Map();
|
|
6286
|
+
}
|
|
6287
|
+
return new Map(
|
|
6288
|
+
Object.entries(raw.files).filter(([file, entry]) => !!file && !!entry && typeof entry.signature === "string").map(([file, entry]) => [file, {
|
|
6289
|
+
signature: entry.signature,
|
|
6290
|
+
summary: entry.summary || null
|
|
6291
|
+
}])
|
|
6292
|
+
);
|
|
6293
|
+
} catch {
|
|
6294
|
+
return /* @__PURE__ */ new Map();
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
function writePersistedSavedHistoryIndexFile(dir, entries) {
|
|
6298
|
+
const filePath = getSavedHistoryIndexFilePath(dir);
|
|
6299
|
+
const tempPath = `${filePath}.tmp`;
|
|
6300
|
+
const payload = {
|
|
6301
|
+
version: SAVED_HISTORY_INDEX_VERSION,
|
|
6302
|
+
files: Object.fromEntries(entries.entries()),
|
|
6303
|
+
sessions: buildSavedHistorySessionSummaryMapFromEntries(entries)
|
|
6304
|
+
};
|
|
6305
|
+
fs3.writeFileSync(tempPath, JSON.stringify(payload), "utf-8");
|
|
6306
|
+
fs3.renameSync(tempPath, filePath);
|
|
6307
|
+
}
|
|
6308
|
+
function acquireSavedHistoryIndexLock(dir) {
|
|
6309
|
+
const lockPath = getSavedHistoryIndexLockPath(dir);
|
|
6310
|
+
const deadline = Date.now() + SAVED_HISTORY_INDEX_LOCK_WAIT_MS;
|
|
6311
|
+
while (Date.now() <= deadline) {
|
|
6312
|
+
try {
|
|
6313
|
+
fs3.mkdirSync(lockPath);
|
|
6314
|
+
return () => {
|
|
6171
6315
|
try {
|
|
6172
|
-
|
|
6316
|
+
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
6173
6317
|
} catch {
|
|
6174
|
-
parsed = null;
|
|
6175
6318
|
}
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6319
|
+
};
|
|
6320
|
+
} catch (error) {
|
|
6321
|
+
if (error?.code !== "EEXIST") return null;
|
|
6322
|
+
try {
|
|
6323
|
+
const stat = fs3.statSync(lockPath);
|
|
6324
|
+
if (Date.now() - stat.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
|
|
6325
|
+
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
6179
6326
|
continue;
|
|
6180
6327
|
}
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6328
|
+
} catch {
|
|
6329
|
+
continue;
|
|
6330
|
+
}
|
|
6331
|
+
sleepBlocking(SAVED_HISTORY_INDEX_LOCK_POLL_MS);
|
|
6332
|
+
}
|
|
6333
|
+
}
|
|
6334
|
+
return null;
|
|
6335
|
+
}
|
|
6336
|
+
function withLockedPersistedSavedHistoryIndex(dir, callback) {
|
|
6337
|
+
const release2 = acquireSavedHistoryIndexLock(dir);
|
|
6338
|
+
if (!release2) return null;
|
|
6339
|
+
try {
|
|
6340
|
+
const entries = loadPersistedSavedHistoryIndexFromFile(dir);
|
|
6341
|
+
const result = callback(entries);
|
|
6342
|
+
writePersistedSavedHistoryIndexFile(dir, entries);
|
|
6343
|
+
return result;
|
|
6344
|
+
} catch {
|
|
6345
|
+
return null;
|
|
6346
|
+
} finally {
|
|
6347
|
+
release2();
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
6350
|
+
function loadPersistedSavedHistoryIndex(dir) {
|
|
6351
|
+
return loadPersistedSavedHistoryIndexFromFile(dir);
|
|
6352
|
+
}
|
|
6353
|
+
function savePersistedSavedHistoryIndex(dir, entries) {
|
|
6354
|
+
withLockedPersistedSavedHistoryIndex(dir, (currentEntries) => {
|
|
6355
|
+
const incomingFiles = new Set(Array.from(entries.keys()));
|
|
6356
|
+
for (const [file, entry] of Array.from(entries.entries())) {
|
|
6357
|
+
const liveSignature = buildSavedHistoryFileSignature(dir, file);
|
|
6358
|
+
const existingEntry = currentEntries.get(file);
|
|
6359
|
+
if (existingEntry && existingEntry.signature !== liveSignature && entry.signature !== liveSignature) {
|
|
6360
|
+
continue;
|
|
6361
|
+
}
|
|
6362
|
+
if (entry.signature !== liveSignature && (!existingEntry || existingEntry.signature !== liveSignature)) {
|
|
6363
|
+
continue;
|
|
6364
|
+
}
|
|
6365
|
+
currentEntries.set(file, entry.signature === liveSignature ? entry : {
|
|
6366
|
+
signature: liveSignature,
|
|
6367
|
+
summary: existingEntry?.summary || entry.summary
|
|
6368
|
+
});
|
|
6369
|
+
}
|
|
6370
|
+
for (const file of Array.from(currentEntries.keys())) {
|
|
6371
|
+
if (incomingFiles.has(file)) continue;
|
|
6372
|
+
if (!fs3.existsSync(path7.join(dir, file))) {
|
|
6373
|
+
currentEntries.delete(file);
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
});
|
|
6377
|
+
}
|
|
6378
|
+
function invalidatePersistedSavedHistoryIndex(agentType, dir) {
|
|
6379
|
+
try {
|
|
6380
|
+
fs3.rmSync(getSavedHistoryIndexFilePath(dir), { force: true });
|
|
6381
|
+
} catch {
|
|
6382
|
+
}
|
|
6383
|
+
savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
|
|
6384
|
+
}
|
|
6385
|
+
function buildSavedHistoryIndexFileSignature(dir) {
|
|
6386
|
+
try {
|
|
6387
|
+
const stat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
6388
|
+
return `index:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
|
|
6389
|
+
} catch {
|
|
6390
|
+
return "index:missing";
|
|
6391
|
+
}
|
|
6392
|
+
}
|
|
6393
|
+
function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
6394
|
+
try {
|
|
6395
|
+
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
6396
|
+
const files = listHistoryFiles(dir);
|
|
6397
|
+
for (const file of files) {
|
|
6398
|
+
const stat = fs3.statSync(path7.join(dir, file));
|
|
6399
|
+
if (stat.mtimeMs > indexStat.mtimeMs) return true;
|
|
6400
|
+
}
|
|
6401
|
+
return false;
|
|
6402
|
+
} catch {
|
|
6403
|
+
return true;
|
|
6404
|
+
}
|
|
6405
|
+
}
|
|
6406
|
+
function buildSavedHistoryFileSignature(dir, file) {
|
|
6407
|
+
try {
|
|
6408
|
+
const stat = fs3.statSync(path7.join(dir, file));
|
|
6409
|
+
return `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
|
|
6410
|
+
} catch {
|
|
6411
|
+
return `${file}:missing`;
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
6415
|
+
const filePath = path7.join(dir, file);
|
|
6416
|
+
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
6417
|
+
const currentEntry = entries.get(file) || null;
|
|
6418
|
+
const nextSummary = updater(currentEntry?.summary || null);
|
|
6419
|
+
const nextEntry = {
|
|
6420
|
+
signature: buildSavedHistoryFileSignature(dir, file),
|
|
6421
|
+
summary: nextSummary
|
|
6422
|
+
};
|
|
6423
|
+
entries.set(file, nextEntry);
|
|
6424
|
+
savedHistoryFileSummaryCache.set(filePath, nextEntry);
|
|
6425
|
+
return nextEntry;
|
|
6426
|
+
});
|
|
6427
|
+
if (!result) return;
|
|
6428
|
+
if (result.summary?.historySessionId && shouldScheduleSavedHistoryRollupForSignature(result.signature)) {
|
|
6429
|
+
scheduleSavedHistoryRollup(agentType, result.summary.historySessionId);
|
|
6430
|
+
}
|
|
6431
|
+
}
|
|
6432
|
+
function updateSavedHistoryIndexForSessionStart(agentType, dir, file, historySessionId, workspace) {
|
|
6433
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
|
|
6434
|
+
const normalizedWorkspace = String(workspace || "").trim();
|
|
6435
|
+
if (!normalizedSessionId || !normalizedWorkspace) return;
|
|
6436
|
+
persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => ({
|
|
6437
|
+
file,
|
|
6438
|
+
historySessionId: normalizedSessionId,
|
|
6439
|
+
messageCount: currentSummary?.messageCount || 0,
|
|
6440
|
+
firstMessageAt: currentSummary?.firstMessageAt || 0,
|
|
6441
|
+
lastMessageAt: currentSummary?.lastMessageAt || 0,
|
|
6442
|
+
sessionTitle: currentSummary?.sessionTitle,
|
|
6443
|
+
preview: currentSummary?.preview,
|
|
6444
|
+
workspace: normalizedWorkspace
|
|
6445
|
+
}));
|
|
6446
|
+
}
|
|
6447
|
+
function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, historySessionId, messages) {
|
|
6448
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
|
|
6449
|
+
if (!normalizedSessionId || messages.length === 0) return;
|
|
6450
|
+
persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => {
|
|
6451
|
+
const nextSummary = {
|
|
6452
|
+
file,
|
|
6453
|
+
historySessionId: normalizedSessionId,
|
|
6454
|
+
messageCount: currentSummary?.messageCount || 0,
|
|
6455
|
+
firstMessageAt: currentSummary?.firstMessageAt || 0,
|
|
6456
|
+
lastMessageAt: currentSummary?.lastMessageAt || 0,
|
|
6457
|
+
sessionTitle: currentSummary?.sessionTitle,
|
|
6458
|
+
preview: currentSummary?.preview,
|
|
6459
|
+
workspace: currentSummary?.workspace
|
|
6460
|
+
};
|
|
6461
|
+
for (const message of messages) {
|
|
6462
|
+
if (!message || message.historySessionId !== historySessionId) continue;
|
|
6463
|
+
if (message.kind === "session_start") {
|
|
6464
|
+
if (message.workspace) nextSummary.workspace = message.workspace;
|
|
6465
|
+
continue;
|
|
6466
|
+
}
|
|
6467
|
+
nextSummary.messageCount += 1;
|
|
6468
|
+
if (!nextSummary.firstMessageAt || message.receivedAt < nextSummary.firstMessageAt) {
|
|
6469
|
+
nextSummary.firstMessageAt = message.receivedAt;
|
|
6470
|
+
}
|
|
6471
|
+
if (!nextSummary.lastMessageAt || message.receivedAt >= nextSummary.lastMessageAt) {
|
|
6472
|
+
nextSummary.lastMessageAt = message.receivedAt;
|
|
6473
|
+
if (message.sessionTitle) nextSummary.sessionTitle = message.sessionTitle;
|
|
6474
|
+
if (message.role !== "system" && message.content.trim()) nextSummary.preview = message.content.trim();
|
|
6475
|
+
} else if (message.sessionTitle) {
|
|
6476
|
+
nextSummary.sessionTitle = message.sessionTitle;
|
|
6477
|
+
}
|
|
6478
|
+
if (!nextSummary.preview && message.role !== "system" && message.content.trim()) {
|
|
6479
|
+
nextSummary.preview = message.content.trim();
|
|
6480
|
+
}
|
|
6481
|
+
}
|
|
6482
|
+
return nextSummary;
|
|
6483
|
+
});
|
|
6484
|
+
}
|
|
6485
|
+
function computeSavedHistoryFileSummary(agentType, dir, file) {
|
|
6486
|
+
const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file);
|
|
6487
|
+
if (!historySessionId) return null;
|
|
6488
|
+
const filePath = path7.join(dir, file);
|
|
6489
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
6490
|
+
const lines = content.split("\n").filter(Boolean);
|
|
6491
|
+
let messageCount = 0;
|
|
6492
|
+
let firstMessageAt = 0;
|
|
6493
|
+
let lastMessageAt = 0;
|
|
6494
|
+
let sessionTitle = "";
|
|
6495
|
+
let preview = "";
|
|
6496
|
+
let workspace = "";
|
|
6497
|
+
for (const line of lines) {
|
|
6498
|
+
let parsed = null;
|
|
6499
|
+
try {
|
|
6500
|
+
parsed = JSON.parse(line);
|
|
6501
|
+
} catch {
|
|
6502
|
+
parsed = null;
|
|
6503
|
+
}
|
|
6504
|
+
if (!parsed || parsed.historySessionId !== historySessionId) continue;
|
|
6505
|
+
if (parsed.kind === "session_start") {
|
|
6506
|
+
if (!workspace && parsed.workspace) workspace = parsed.workspace;
|
|
6507
|
+
continue;
|
|
6508
|
+
}
|
|
6509
|
+
messageCount += 1;
|
|
6510
|
+
if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
|
|
6511
|
+
if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
|
|
6512
|
+
if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
|
|
6513
|
+
if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
|
|
6514
|
+
}
|
|
6515
|
+
if (messageCount === 0 || !lastMessageAt) return null;
|
|
6516
|
+
return {
|
|
6517
|
+
file,
|
|
6518
|
+
historySessionId,
|
|
6519
|
+
messageCount,
|
|
6520
|
+
firstMessageAt,
|
|
6521
|
+
lastMessageAt,
|
|
6522
|
+
sessionTitle: sessionTitle || void 0,
|
|
6523
|
+
preview: preview || void 0,
|
|
6524
|
+
workspace: workspace || void 0
|
|
6525
|
+
};
|
|
6526
|
+
}
|
|
6527
|
+
function shouldScheduleSavedHistoryRollupForSignature(signature) {
|
|
6528
|
+
const parts = String(signature || "").split(":");
|
|
6529
|
+
const size = Number(parts[1] || 0);
|
|
6530
|
+
return shouldScheduleSavedHistoryRollup(size);
|
|
6531
|
+
}
|
|
6532
|
+
function scheduleSavedHistoryRollup(agentType, historySessionId) {
|
|
6533
|
+
const key = `${agentType}:${historySessionId}`;
|
|
6534
|
+
if (!historySessionId || savedHistoryRollupInFlight.has(key)) return;
|
|
6535
|
+
savedHistoryRollupInFlight.add(key);
|
|
6536
|
+
setTimeout(() => {
|
|
6537
|
+
try {
|
|
6538
|
+
new ChatHistoryWriter().compactHistorySession(agentType, historySessionId);
|
|
6539
|
+
} finally {
|
|
6540
|
+
savedHistoryRollupInFlight.delete(key);
|
|
6541
|
+
}
|
|
6542
|
+
}, 0);
|
|
6543
|
+
}
|
|
6544
|
+
function scheduleSavedHistoryBackgroundRefresh(agentType, dir) {
|
|
6545
|
+
const key = `${agentType}:${dir}`;
|
|
6546
|
+
if (savedHistoryBackgroundRefresh.has(key)) return;
|
|
6547
|
+
savedHistoryBackgroundRefresh.add(key);
|
|
6548
|
+
setTimeout(() => {
|
|
6549
|
+
try {
|
|
6550
|
+
if (!fs3.existsSync(dir)) return;
|
|
6551
|
+
const files = listHistoryFiles(dir);
|
|
6552
|
+
const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
|
|
6553
|
+
const persistedEntries = loadPersistedSavedHistoryIndex(dir);
|
|
6554
|
+
const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
|
|
6555
|
+
savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
|
|
6556
|
+
const refreshedIndexSignature = buildSavedHistoryIndexFileSignature(dir);
|
|
6557
|
+
savedHistorySessionCache.set(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"), {
|
|
6558
|
+
signature: refreshedIndexSignature,
|
|
6559
|
+
summaries: computed.summaries || []
|
|
6560
|
+
});
|
|
6561
|
+
for (const [file, entry] of Array.from(computed.persistedEntries.entries())) {
|
|
6562
|
+
if (!entry?.summary || !shouldScheduleSavedHistoryRollupForSignature(entry.signature)) continue;
|
|
6563
|
+
scheduleSavedHistoryRollup(agentType, entry.summary.historySessionId);
|
|
6564
|
+
}
|
|
6565
|
+
} catch {
|
|
6566
|
+
} finally {
|
|
6567
|
+
savedHistoryBackgroundRefresh.delete(key);
|
|
6568
|
+
}
|
|
6569
|
+
}, 0);
|
|
6570
|
+
}
|
|
6571
|
+
function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries) {
|
|
6572
|
+
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
6573
|
+
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
6574
|
+
for (const file of files.slice().sort()) {
|
|
6575
|
+
const filePath = path7.join(dir, file);
|
|
6576
|
+
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
6577
|
+
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
6578
|
+
const persisted = persistedEntries.get(file);
|
|
6579
|
+
const reusableEntry = cached?.signature === signature ? cached : persisted?.signature === signature ? persisted : null;
|
|
6580
|
+
const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file);
|
|
6581
|
+
const nextEntry = reusableEntry || {
|
|
6582
|
+
signature,
|
|
6583
|
+
summary: fileSummary
|
|
6584
|
+
};
|
|
6585
|
+
if (!reusableEntry) {
|
|
6586
|
+
nextEntry.signature = signature;
|
|
6587
|
+
nextEntry.summary = fileSummary;
|
|
6588
|
+
}
|
|
6589
|
+
savedHistoryFileSummaryCache.set(filePath, nextEntry);
|
|
6590
|
+
nextPersistedEntries.set(file, nextEntry);
|
|
6591
|
+
if (!fileSummary) continue;
|
|
6592
|
+
const existing = summaryBySessionId.get(fileSummary.historySessionId);
|
|
6593
|
+
if (fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) {
|
|
6594
|
+
continue;
|
|
6595
|
+
}
|
|
6596
|
+
if (!existing) {
|
|
6597
|
+
summaryBySessionId.set(fileSummary.historySessionId, {
|
|
6598
|
+
historySessionId: fileSummary.historySessionId,
|
|
6599
|
+
sessionTitle: fileSummary.sessionTitle,
|
|
6600
|
+
messageCount: fileSummary.messageCount,
|
|
6601
|
+
firstMessageAt: fileSummary.firstMessageAt,
|
|
6602
|
+
lastMessageAt: fileSummary.lastMessageAt,
|
|
6603
|
+
preview: fileSummary.preview,
|
|
6604
|
+
workspace: fileSummary.workspace
|
|
6605
|
+
});
|
|
6606
|
+
continue;
|
|
6607
|
+
}
|
|
6608
|
+
existing.messageCount += fileSummary.messageCount;
|
|
6609
|
+
if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
|
|
6610
|
+
existing.firstMessageAt = fileSummary.firstMessageAt;
|
|
6611
|
+
}
|
|
6612
|
+
if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
|
|
6613
|
+
existing.lastMessageAt = fileSummary.lastMessageAt;
|
|
6614
|
+
if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
|
|
6615
|
+
if (fileSummary.preview) existing.preview = fileSummary.preview;
|
|
6616
|
+
}
|
|
6617
|
+
if (!existing.workspace && fileSummary.workspace) {
|
|
6618
|
+
existing.workspace = fileSummary.workspace;
|
|
6619
|
+
}
|
|
6198
6620
|
}
|
|
6199
|
-
|
|
6200
|
-
|
|
6621
|
+
return {
|
|
6622
|
+
summaries: Array.from(summaryBySessionId.values()).sort((a, b) => b.lastMessageAt - a.lastMessageAt),
|
|
6623
|
+
persistedEntries: nextPersistedEntries
|
|
6624
|
+
};
|
|
6201
6625
|
}
|
|
6202
6626
|
var ChatHistoryWriter = class {
|
|
6203
6627
|
/** Last seen message count per agent (deduplication) */
|
|
@@ -6272,9 +6696,11 @@ var ChatHistoryWriter = class {
|
|
|
6272
6696
|
fs3.mkdirSync(dir, { recursive: true });
|
|
6273
6697
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6274
6698
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
6275
|
-
const
|
|
6699
|
+
const fileName = `${filePrefix}${date}.jsonl`;
|
|
6700
|
+
const filePath = path7.join(dir, fileName);
|
|
6276
6701
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
6277
6702
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
6703
|
+
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
6278
6704
|
const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
|
|
6279
6705
|
if (!historySessionId && messages.length < prevCount * 0.5 && prevCount > 3) {
|
|
6280
6706
|
seenHashes.clear();
|
|
@@ -6365,7 +6791,8 @@ var ChatHistoryWriter = class {
|
|
|
6365
6791
|
const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
|
|
6366
6792
|
fs3.mkdirSync(dir, { recursive: true });
|
|
6367
6793
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6368
|
-
const
|
|
6794
|
+
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
6795
|
+
const filePath = path7.join(dir, fileName);
|
|
6369
6796
|
const record = {
|
|
6370
6797
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6371
6798
|
receivedAt: Date.now(),
|
|
@@ -6378,6 +6805,7 @@ var ChatHistoryWriter = class {
|
|
|
6378
6805
|
workspace: ws
|
|
6379
6806
|
};
|
|
6380
6807
|
fs3.appendFileSync(filePath, JSON.stringify(record) + "\n", "utf-8");
|
|
6808
|
+
updateSavedHistoryIndexForSessionStart(agentType, dir, fileName, id, ws);
|
|
6381
6809
|
} catch {
|
|
6382
6810
|
}
|
|
6383
6811
|
}
|
|
@@ -6443,6 +6871,7 @@ var ChatHistoryWriter = class {
|
|
|
6443
6871
|
}
|
|
6444
6872
|
fs3.unlinkSync(sourcePath);
|
|
6445
6873
|
}
|
|
6874
|
+
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
6446
6875
|
} catch {
|
|
6447
6876
|
}
|
|
6448
6877
|
}
|
|
@@ -6492,6 +6921,7 @@ var ChatHistoryWriter = class {
|
|
|
6492
6921
|
fs3.writeFileSync(filePath, `${collapsed.map((entry) => JSON.stringify(entry)).join("\n")}
|
|
6493
6922
|
`, "utf-8");
|
|
6494
6923
|
}
|
|
6924
|
+
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
6495
6925
|
} catch {
|
|
6496
6926
|
}
|
|
6497
6927
|
}
|
|
@@ -6511,13 +6941,18 @@ var ChatHistoryWriter = class {
|
|
|
6511
6941
|
for (const dir of agentDirs) {
|
|
6512
6942
|
const dirPath = path7.join(HISTORY_DIR, dir.name);
|
|
6513
6943
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
6944
|
+
let removedAny = false;
|
|
6514
6945
|
for (const file of files) {
|
|
6515
6946
|
const filePath = path7.join(dirPath, file);
|
|
6516
6947
|
const stat = fs3.statSync(filePath);
|
|
6517
6948
|
if (stat.mtimeMs < cutoff) {
|
|
6518
6949
|
fs3.unlinkSync(filePath);
|
|
6950
|
+
removedAny = true;
|
|
6519
6951
|
}
|
|
6520
6952
|
}
|
|
6953
|
+
if (removedAny) {
|
|
6954
|
+
invalidatePersistedSavedHistoryIndex(dir.name, dirPath);
|
|
6955
|
+
}
|
|
6521
6956
|
}
|
|
6522
6957
|
} catch {
|
|
6523
6958
|
}
|
|
@@ -6583,18 +7018,51 @@ function listSavedHistorySessions(agentType, options = {}) {
|
|
|
6583
7018
|
savedHistorySessionCache.delete(sanitized);
|
|
6584
7019
|
return { sessions: [], hasMore: false };
|
|
6585
7020
|
}
|
|
6586
|
-
const files = listHistoryFiles(dir);
|
|
6587
|
-
const signature = buildSavedHistoryCacheSignature(dir, files);
|
|
6588
7021
|
const cached = savedHistorySessionCache.get(sanitized);
|
|
6589
|
-
const
|
|
6590
|
-
|
|
7022
|
+
const offset = Math.max(0, options.offset || 0);
|
|
7023
|
+
const limit = Math.max(1, options.limit || 30);
|
|
7024
|
+
const indexSignature = buildSavedHistoryIndexFileSignature(dir);
|
|
7025
|
+
let cacheWasInvalidated = false;
|
|
7026
|
+
if (cached) {
|
|
7027
|
+
const cacheLooksPersisted = cached.signature.startsWith("index:");
|
|
7028
|
+
const cacheStillValid = cacheLooksPersisted ? cached.signature === indexSignature : (() => {
|
|
7029
|
+
const files2 = listHistoryFiles(dir);
|
|
7030
|
+
const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
|
|
7031
|
+
return cached.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
|
|
7032
|
+
})();
|
|
7033
|
+
if (cacheStillValid) {
|
|
7034
|
+
const sliced2 = cached.summaries.slice(offset, offset + limit);
|
|
7035
|
+
return {
|
|
7036
|
+
sessions: sliced2,
|
|
7037
|
+
hasMore: cached.summaries.length > offset + limit
|
|
7038
|
+
};
|
|
7039
|
+
}
|
|
7040
|
+
cacheWasInvalidated = true;
|
|
7041
|
+
}
|
|
7042
|
+
const persistedSessions = readPersistedSavedHistorySessionSummaries(dir);
|
|
7043
|
+
if (!cacheWasInvalidated && persistedSessions?.length && !historyDirectoryHasFilesNewerThanIndex(dir)) {
|
|
6591
7044
|
savedHistorySessionCache.set(sanitized, {
|
|
6592
|
-
signature,
|
|
6593
|
-
summaries
|
|
7045
|
+
signature: indexSignature,
|
|
7046
|
+
summaries: persistedSessions
|
|
6594
7047
|
});
|
|
7048
|
+
scheduleSavedHistoryBackgroundRefresh(agentType, dir);
|
|
7049
|
+
const sliced2 = persistedSessions.slice(offset, offset + limit);
|
|
7050
|
+
return {
|
|
7051
|
+
sessions: sliced2,
|
|
7052
|
+
hasMore: persistedSessions.length > offset + limit
|
|
7053
|
+
};
|
|
6595
7054
|
}
|
|
6596
|
-
const
|
|
6597
|
-
const
|
|
7055
|
+
const files = listHistoryFiles(dir);
|
|
7056
|
+
const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
|
|
7057
|
+
const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
|
|
7058
|
+
const persistedEntries = loadPersistedSavedHistoryIndex(dir);
|
|
7059
|
+
const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
|
|
7060
|
+
const summaries = computed.summaries || [];
|
|
7061
|
+
savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
|
|
7062
|
+
savedHistorySessionCache.set(sanitized, {
|
|
7063
|
+
signature,
|
|
7064
|
+
summaries
|
|
7065
|
+
});
|
|
6598
7066
|
const sliced = summaries.slice(offset, offset + limit);
|
|
6599
7067
|
return {
|
|
6600
7068
|
sessions: sliced,
|
|
@@ -8347,6 +8815,21 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
8347
8815
|
lastUpdated: ext.lastUpdated
|
|
8348
8816
|
};
|
|
8349
8817
|
}
|
|
8818
|
+
function shouldIncludeExtensionSession(ext) {
|
|
8819
|
+
const status = String(ext.status || "").trim().toLowerCase();
|
|
8820
|
+
const hasActiveChat = !!ext.activeChat;
|
|
8821
|
+
const hasMessages = Array.isArray(ext.activeChat?.messages) && ext.activeChat.messages.length > 0;
|
|
8822
|
+
const hasModal = !!ext.activeChat?.activeModal;
|
|
8823
|
+
const hasStreams = Array.isArray(ext.agentStreams) && ext.agentStreams.length > 0;
|
|
8824
|
+
const hasProviderSessionId = typeof ext.providerSessionId === "string" && ext.providerSessionId.trim().length > 0;
|
|
8825
|
+
const hasControlValues = !!(ext.controlValues && Object.keys(ext.controlValues).length > 0);
|
|
8826
|
+
const hasProviderControls = Array.isArray(ext.providerControls) && ext.providerControls.length > 0;
|
|
8827
|
+
const hasOpenPanelCapability = Array.isArray(ext.sessionCapabilities) && ext.sessionCapabilities.includes("open_panel");
|
|
8828
|
+
const hasSummaryMetadata = !!ext.summaryMetadata;
|
|
8829
|
+
const hasError = typeof ext.errorMessage === "string" && ext.errorMessage.trim().length > 0;
|
|
8830
|
+
const hasInterestingStatus = !!status && !["idle", "panel_hidden", "disconnected", "not_monitored"].includes(status);
|
|
8831
|
+
return hasActiveChat || hasMessages || hasModal || hasStreams || hasProviderSessionId || hasControlValues || hasProviderControls || hasOpenPanelCapability || hasSummaryMetadata || hasError || hasInterestingStatus;
|
|
8832
|
+
}
|
|
8350
8833
|
function buildCliSession(state, options) {
|
|
8351
8834
|
const profile = options.profile || "full";
|
|
8352
8835
|
const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
|
|
@@ -8430,6 +8913,7 @@ function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
|
8430
8913
|
for (const state of ideStates) {
|
|
8431
8914
|
sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
|
|
8432
8915
|
for (const ext of state.extensions) {
|
|
8916
|
+
if (!shouldIncludeExtensionSession(ext)) continue;
|
|
8433
8917
|
sessions.push(buildExtensionAgentSession(state, ext, options));
|
|
8434
8918
|
}
|
|
8435
8919
|
}
|
|
@@ -10600,7 +11084,9 @@ function applyProviderPatch(h, args, payload) {
|
|
|
10600
11084
|
});
|
|
10601
11085
|
}
|
|
10602
11086
|
async function executeProviderScript(h, args, scriptName) {
|
|
10603
|
-
const
|
|
11087
|
+
const explicitTargetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
11088
|
+
const targetSession = explicitTargetSessionId ? h.ctx.sessionRegistry?.get(explicitTargetSessionId) : void 0;
|
|
11089
|
+
const resolvedProviderType = targetSession?.providerType || h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
|
|
10604
11090
|
if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
|
|
10605
11091
|
const loader = h.ctx.providerLoader;
|
|
10606
11092
|
if (!loader) return { success: false, error: "ProviderLoader not initialized" };
|
|
@@ -10643,16 +11129,16 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
10643
11129
|
const scriptFn = provider.scripts[actualScriptName];
|
|
10644
11130
|
const scriptCode = scriptFn(normalizedArgs);
|
|
10645
11131
|
if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
|
|
10646
|
-
const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
|
|
11132
|
+
const cdpKey = provider.category === "ide" ? targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey;
|
|
10647
11133
|
LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
|
|
10648
11134
|
const cdp = h.getCdp(cdpKey);
|
|
10649
11135
|
if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
|
|
10650
11136
|
try {
|
|
10651
11137
|
let result;
|
|
10652
11138
|
if (provider.category === "extension") {
|
|
10653
|
-
const runtimeSessionId = h.currentSession?.sessionId
|
|
11139
|
+
const runtimeSessionId = explicitTargetSessionId || h.currentSession?.sessionId;
|
|
10654
11140
|
if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
|
|
10655
|
-
const parentSessionId = h.currentSession?.parentSessionId;
|
|
11141
|
+
const parentSessionId = targetSession?.parentSessionId || h.currentSession?.parentSessionId;
|
|
10656
11142
|
if (parentSessionId) {
|
|
10657
11143
|
await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
|
|
10658
11144
|
await h.agentStream?.syncActiveSession(cdp, parentSessionId);
|
|
@@ -17575,6 +18061,23 @@ function prepareSessionModalUpdate(input) {
|
|
|
17575
18061
|
};
|
|
17576
18062
|
}
|
|
17577
18063
|
|
|
18064
|
+
// src/chat/async-batch.ts
|
|
18065
|
+
async function runAsyncBatch(items, worker, options = {}) {
|
|
18066
|
+
const list = Array.from(items);
|
|
18067
|
+
if (list.length === 0) return;
|
|
18068
|
+
const concurrency = Math.max(1, Math.min(list.length, Math.floor(options.concurrency || 1)));
|
|
18069
|
+
let nextIndex = 0;
|
|
18070
|
+
const runners = Array.from({ length: concurrency }, async () => {
|
|
18071
|
+
while (true) {
|
|
18072
|
+
const currentIndex = nextIndex;
|
|
18073
|
+
nextIndex += 1;
|
|
18074
|
+
if (currentIndex >= list.length) return;
|
|
18075
|
+
await worker(list[currentIndex], currentIndex);
|
|
18076
|
+
}
|
|
18077
|
+
});
|
|
18078
|
+
await Promise.all(runners);
|
|
18079
|
+
}
|
|
18080
|
+
|
|
17578
18081
|
// src/agent-stream/provider-adapter.ts
|
|
17579
18082
|
init_read_chat_contract();
|
|
17580
18083
|
init_chat_message_normalization();
|
|
@@ -18043,10 +18546,12 @@ var DaemonAgentStreamManager = class {
|
|
|
18043
18546
|
}
|
|
18044
18547
|
}
|
|
18045
18548
|
/** Collect active extension session state */
|
|
18046
|
-
async collectActiveSession(cdp, parentSessionId) {
|
|
18549
|
+
async collectActiveSession(cdp, parentSessionId, attemptedSessionIds = /* @__PURE__ */ new Set(), originSessionId) {
|
|
18047
18550
|
if (!this.enabled) return null;
|
|
18048
18551
|
const activeSessionId = this.getActiveSessionId(parentSessionId);
|
|
18049
18552
|
if (!activeSessionId) return null;
|
|
18553
|
+
const resolvedOriginSessionId = originSessionId || activeSessionId;
|
|
18554
|
+
attemptedSessionIds.add(activeSessionId);
|
|
18050
18555
|
let agent = this.managedBySessionId.get(activeSessionId);
|
|
18051
18556
|
if (!agent) {
|
|
18052
18557
|
agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
|
|
@@ -18059,18 +18564,44 @@ var DaemonAgentStreamManager = class {
|
|
|
18059
18564
|
try {
|
|
18060
18565
|
const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
|
|
18061
18566
|
const state = await agent.adapter.readChat(evaluate);
|
|
18062
|
-
const
|
|
18063
|
-
const
|
|
18064
|
-
|
|
18065
|
-
|
|
18567
|
+
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;
|
|
18568
|
+
const normalizedState = {
|
|
18569
|
+
...state,
|
|
18570
|
+
sessionId: agent.runtimeSessionId,
|
|
18571
|
+
...resolvedProviderSessionId ? { providerSessionId: resolvedProviderSessionId } : {}
|
|
18572
|
+
};
|
|
18573
|
+
const stateError = this.getStateError(normalizedState);
|
|
18574
|
+
const selectedModelValue = typeof normalizedState.controlValues?.model === "string" ? normalizedState.controlValues.model : "";
|
|
18575
|
+
LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${normalizedState.status} msgs=${normalizedState.messages?.length || 0} model=${selectedModelValue}${normalizedState.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
|
|
18576
|
+
if (normalizedState.status === "error" && this.isRecoverableSessionError(stateError)) {
|
|
18066
18577
|
throw new Error(stateError);
|
|
18067
18578
|
}
|
|
18068
|
-
agent.lastState =
|
|
18579
|
+
agent.lastState = normalizedState;
|
|
18069
18580
|
agent.lastError = null;
|
|
18070
|
-
if (
|
|
18581
|
+
if (normalizedState.status === "panel_hidden") {
|
|
18582
|
+
const discovered = await cdp.discoverAgentWebviews().catch(() => []);
|
|
18583
|
+
const fallbackTarget = discovered.find((entry) => {
|
|
18584
|
+
if (entry.agentType === type) return false;
|
|
18585
|
+
const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, entry.agentType);
|
|
18586
|
+
return !!fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId);
|
|
18587
|
+
});
|
|
18588
|
+
if (fallbackTarget) {
|
|
18589
|
+
const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, fallbackTarget.agentType);
|
|
18590
|
+
if (fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId)) {
|
|
18591
|
+
this.logFn(`[AgentStream] Active session ${type} is hidden; switching to visible agent ${fallbackTarget.agentType} (${parentSessionId})`);
|
|
18592
|
+
await this.setActiveSession(cdp, parentSessionId, fallbackSessionId);
|
|
18593
|
+
await this.syncActiveSession(cdp, parentSessionId);
|
|
18594
|
+
const fallbackState = await this.collectActiveSession(cdp, parentSessionId, attemptedSessionIds, resolvedOriginSessionId);
|
|
18595
|
+
if (fallbackState?.status === "panel_hidden" && resolvedOriginSessionId !== fallbackSessionId) {
|
|
18596
|
+
await this.setActiveSession(cdp, parentSessionId, resolvedOriginSessionId);
|
|
18597
|
+
await this.syncActiveSession(cdp, parentSessionId);
|
|
18598
|
+
}
|
|
18599
|
+
return fallbackState;
|
|
18600
|
+
}
|
|
18601
|
+
}
|
|
18071
18602
|
agent.lastHiddenCheckTime = Date.now();
|
|
18072
18603
|
}
|
|
18073
|
-
return
|
|
18604
|
+
return normalizedState;
|
|
18074
18605
|
} catch (e) {
|
|
18075
18606
|
const errorMsg = e?.message || String(e);
|
|
18076
18607
|
this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
|
|
@@ -18366,6 +18897,7 @@ var AgentStreamPoller = class {
|
|
|
18366
18897
|
try {
|
|
18367
18898
|
await agentStreamManager.syncActiveSession(cdp, parentSessionId);
|
|
18368
18899
|
let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
|
|
18900
|
+
resolvedActiveSessionId = stream?.sessionId || agentStreamManager.getActiveSessionId(parentSessionId) || resolvedActiveSessionId;
|
|
18369
18901
|
if (stream?.status === "waiting_approval") {
|
|
18370
18902
|
const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
|
|
18371
18903
|
if (autoApprove && resolvedActiveSessionId) {
|
|
@@ -25071,6 +25603,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
25071
25603
|
resolveChatMessageKind,
|
|
25072
25604
|
resolveDebugRuntimeConfig,
|
|
25073
25605
|
resolveSessionHostAppName,
|
|
25606
|
+
runAsyncBatch,
|
|
25074
25607
|
saveConfig,
|
|
25075
25608
|
saveState,
|
|
25076
25609
|
setDebugRuntimeConfig,
|