@adhdev/daemon-core 0.8.75 → 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/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 mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
4615
- const list = mainPages.length > 0 ? mainPages : pages;
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
- if (this._targetId) {
4618
- const specific = list.find((t) => t.id === this._targetId);
4619
- if (specific) {
4620
- this._pageTitle = specific.title || "";
4621
- resolve11(specific);
4622
- } else {
4623
- this.log(`[CDP] Target ${this._targetId} not found in page list`);
4624
- resolve11(null);
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 buildSavedHistoryCacheSignature(dir, files) {
6137
- return files.map((file) => {
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
- }).join("|");
6145
- }
6146
- function computeSavedHistorySessionSummaries(agentType, dir, files) {
6147
- const groupedFiles = /* @__PURE__ */ new Map();
6148
- const filePattern = /^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/;
6149
- for (const file of files) {
6150
- const match = file.match(filePattern);
6151
- if (!match?.[1]) continue;
6152
- const historySessionId = match[1];
6153
- const grouped = groupedFiles.get(historySessionId) || [];
6154
- grouped.push(file);
6155
- groupedFiles.set(historySessionId, grouped);
6156
- }
6157
- const summaries = [];
6158
- for (const [historySessionId, grouped] of groupedFiles.entries()) {
6159
- let messageCount = 0;
6160
- let firstMessageAt = 0;
6161
- let lastMessageAt = 0;
6162
- let sessionTitle = "";
6163
- let preview = "";
6164
- let workspace = "";
6165
- for (const file of grouped.sort()) {
6166
- const filePath = path7.join(dir, file);
6167
- const content = fs3.readFileSync(filePath, "utf-8");
6168
- const lines = content.split("\n").filter(Boolean);
6169
- for (const line of lines) {
6170
- let parsed = null;
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
- parsed = JSON.parse(line);
6316
+ fs3.rmSync(lockPath, { recursive: true, force: true });
6173
6317
  } catch {
6174
- parsed = null;
6175
6318
  }
6176
- if (!parsed || parsed.historySessionId !== historySessionId) continue;
6177
- if (parsed.kind === "session_start") {
6178
- if (!workspace && parsed.workspace) workspace = parsed.workspace;
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
- messageCount += 1;
6182
- if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
6183
- if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
6184
- if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
6185
- if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
6186
- }
6187
- }
6188
- if (messageCount === 0 || !lastMessageAt) continue;
6189
- summaries.push({
6190
- historySessionId,
6191
- sessionTitle: sessionTitle || void 0,
6192
- messageCount,
6193
- firstMessageAt,
6194
- lastMessageAt,
6195
- preview: preview || void 0,
6196
- workspace: workspace || void 0
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
- summaries.sort((a, b) => b.lastMessageAt - a.lastMessageAt);
6200
- return summaries;
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 filePath = path7.join(dir, `${filePrefix}${date}.jsonl`);
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 filePath = path7.join(dir, `${this.sanitize(id)}_${date}.jsonl`);
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 summaries = cached?.signature === signature ? cached.summaries : computeSavedHistorySessionSummaries(agentType, dir, files);
6590
- if (!cached || cached.signature !== signature) {
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 offset = Math.max(0, options.offset || 0);
6597
- const limit = Math.max(1, options.limit || 30);
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 resolvedProviderType = h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
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 || args?.targetSessionId;
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 stateError = this.getStateError(state);
18063
- const selectedModelValue = typeof state.controlValues?.model === "string" ? state.controlValues.model : "";
18064
- LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${selectedModelValue}${state.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
18065
- if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
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 = state;
18579
+ agent.lastState = normalizedState;
18069
18580
  agent.lastError = null;
18070
- if (state.status === "panel_hidden") {
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 state;
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,