@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/index.mjs CHANGED
@@ -4314,6 +4314,32 @@ function classifyHotChatSessionsForSubscriptionFlush(sessions, previousHotSessio
4314
4314
  init_logger();
4315
4315
  import WebSocket from "ws";
4316
4316
  import * as http from "http";
4317
+ function normalizeTitle(value) {
4318
+ return String(value || "").trim().replace(/\s+/g, " ").toLowerCase();
4319
+ }
4320
+ function titlesMatch(lhs, rhs) {
4321
+ const a = normalizeTitle(lhs);
4322
+ const b = normalizeTitle(rhs);
4323
+ if (!a || !b) return false;
4324
+ return a === b || a.includes(b) || b.includes(a);
4325
+ }
4326
+ function resolveCdpPageTarget(params) {
4327
+ const { pages, pinnedTargetId, previousPageTitle } = params;
4328
+ if (pages.length === 0) return { target: null, retargeted: false };
4329
+ if (!pinnedTargetId) {
4330
+ return { target: pages[0] || null, retargeted: false };
4331
+ }
4332
+ const exact = pages.find((page) => page.id === pinnedTargetId);
4333
+ if (exact) return { target: exact, retargeted: false };
4334
+ const titleMatchesList = pages.filter((page) => titlesMatch(page.title, previousPageTitle));
4335
+ if (titleMatchesList.length === 1) {
4336
+ return { target: titleMatchesList[0], retargeted: true };
4337
+ }
4338
+ if (pages.length === 1) {
4339
+ return { target: pages[0], retargeted: true };
4340
+ }
4341
+ return { target: null, retargeted: false };
4342
+ }
4317
4343
  var DaemonCdpManager = class {
4318
4344
  ws = null;
4319
4345
  browserWs = null;
@@ -4474,18 +4500,28 @@ var DaemonCdpManager = class {
4474
4500
  resolve11(targets.find((t) => t.webSocketDebuggerUrl) || null);
4475
4501
  return;
4476
4502
  }
4477
- const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
4478
- const list = mainPages.length > 0 ? mainPages : pages;
4503
+ const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
4504
+ const mainPages = titleFilteredPages.filter((t) => this.isMainPageUrl(t.url));
4505
+ const list = mainPages.length > 0 ? mainPages : titleFilteredPages.length > 0 ? titleFilteredPages : pages;
4479
4506
  this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
4480
- if (this._targetId) {
4481
- const specific = list.find((t) => t.id === this._targetId);
4482
- if (specific) {
4483
- this._pageTitle = specific.title || "";
4484
- resolve11(specific);
4485
- } else {
4486
- this.log(`[CDP] Target ${this._targetId} not found in page list`);
4487
- resolve11(null);
4507
+ const previousTargetId = this._targetId;
4508
+ const selected = resolveCdpPageTarget({
4509
+ pages: list,
4510
+ pinnedTargetId: previousTargetId,
4511
+ previousPageTitle: this._pageTitle
4512
+ });
4513
+ if (selected.target) {
4514
+ if (selected.retargeted && previousTargetId && previousTargetId !== selected.target.id) {
4515
+ this.log(`[CDP] Target ${previousTargetId} rekeyed to ${selected.target.id}`);
4516
+ this._targetId = selected.target.id;
4488
4517
  }
4518
+ this._pageTitle = selected.target.title || "";
4519
+ resolve11(selected.target);
4520
+ return;
4521
+ }
4522
+ if (previousTargetId) {
4523
+ this.log(`[CDP] Target ${previousTargetId} not found in page list`);
4524
+ resolve11(null);
4489
4525
  return;
4490
4526
  }
4491
4527
  this._pageTitle = list[0]?.title || "";
@@ -5925,7 +5961,17 @@ import * as path7 from "path";
5925
5961
  import * as os5 from "os";
5926
5962
  var HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
5927
5963
  var RETAIN_DAYS = 30;
5964
+ var SAVED_HISTORY_INDEX_VERSION = 1;
5965
+ var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
5966
+ var SAVED_HISTORY_INDEX_LOCK_SUFFIX = ".lock";
5967
+ var SAVED_HISTORY_INDEX_LOCK_WAIT_MS = 1500;
5968
+ var SAVED_HISTORY_INDEX_LOCK_STALE_MS = 15e3;
5969
+ var SAVED_HISTORY_INDEX_LOCK_POLL_MS = 25;
5970
+ var SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES = 16 * 1024 * 1024;
5928
5971
  var savedHistorySessionCache = /* @__PURE__ */ new Map();
5972
+ var savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
5973
+ var savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
5974
+ var savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
5929
5975
  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;
5930
5976
  function normalizeHistoryComparable(text) {
5931
5977
  return String(text || "").replace(/\s+/g, " ").trim();
@@ -5983,6 +6029,68 @@ function sanitizeHistoryMessage(agentType, message) {
5983
6029
  content
5984
6030
  };
5985
6031
  }
6032
+ function sortSavedHistorySessionSummaries(summaries) {
6033
+ return summaries.slice().sort((a, b) => b.lastMessageAt - a.lastMessageAt);
6034
+ }
6035
+ function buildSavedHistorySessionSummaryMapFromEntries(entries) {
6036
+ const summaries = /* @__PURE__ */ new Map();
6037
+ for (const entry of Array.from(entries.values())) {
6038
+ const fileSummary = entry.summary;
6039
+ if (!fileSummary || fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) continue;
6040
+ const existing = summaries.get(fileSummary.historySessionId);
6041
+ if (!existing) {
6042
+ summaries.set(fileSummary.historySessionId, {
6043
+ historySessionId: fileSummary.historySessionId,
6044
+ sessionTitle: fileSummary.sessionTitle,
6045
+ messageCount: fileSummary.messageCount,
6046
+ firstMessageAt: fileSummary.firstMessageAt,
6047
+ lastMessageAt: fileSummary.lastMessageAt,
6048
+ preview: fileSummary.preview,
6049
+ workspace: fileSummary.workspace
6050
+ });
6051
+ continue;
6052
+ }
6053
+ existing.messageCount += fileSummary.messageCount;
6054
+ if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
6055
+ existing.firstMessageAt = fileSummary.firstMessageAt;
6056
+ }
6057
+ if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
6058
+ existing.lastMessageAt = fileSummary.lastMessageAt;
6059
+ if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
6060
+ if (fileSummary.preview) existing.preview = fileSummary.preview;
6061
+ }
6062
+ if (!existing.workspace && fileSummary.workspace) {
6063
+ existing.workspace = fileSummary.workspace;
6064
+ }
6065
+ }
6066
+ return Object.fromEntries(sortSavedHistorySessionSummaries(Array.from(summaries.values())).map((summary) => [summary.historySessionId, summary]));
6067
+ }
6068
+ function readPersistedSavedHistorySessionSummaries(dir) {
6069
+ try {
6070
+ const filePath = getSavedHistoryIndexFilePath(dir);
6071
+ if (!fs3.existsSync(filePath)) return null;
6072
+ const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
6073
+ if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.sessions || typeof raw.sessions !== "object") {
6074
+ return null;
6075
+ }
6076
+ return sortSavedHistorySessionSummaries(
6077
+ Object.values(raw.sessions).filter((summary) => !!summary && typeof summary.historySessionId === "string" && summary.messageCount > 0 && summary.lastMessageAt > 0).map((summary) => ({
6078
+ historySessionId: summary.historySessionId,
6079
+ sessionTitle: summary.sessionTitle,
6080
+ messageCount: summary.messageCount,
6081
+ firstMessageAt: summary.firstMessageAt,
6082
+ lastMessageAt: summary.lastMessageAt,
6083
+ preview: summary.preview,
6084
+ workspace: summary.workspace
6085
+ }))
6086
+ );
6087
+ } catch {
6088
+ return null;
6089
+ }
6090
+ }
6091
+ function shouldScheduleSavedHistoryRollup(totalBytes) {
6092
+ return Number.isFinite(totalBytes) && totalBytes >= SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES;
6093
+ }
5986
6094
  function sanitizeHistoryFileSegment(value) {
5987
6095
  return String(value || "").replace(/[^a-zA-Z0-9_-]/g, "_");
5988
6096
  }
@@ -5996,71 +6104,386 @@ function listHistoryFiles(dir, historySessionId) {
5996
6104
  return true;
5997
6105
  }).sort().reverse();
5998
6106
  }
5999
- function buildSavedHistoryCacheSignature(dir, files) {
6000
- return files.map((file) => {
6107
+ function normalizeSavedHistorySessionId(agentType, historySessionId) {
6108
+ const normalizedId = String(historySessionId || "").trim();
6109
+ if (!normalizedId) return "";
6110
+ const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
6111
+ if (strictProviderId) return strictProviderId;
6112
+ return agentType === "hermes-cli" ? "" : normalizedId;
6113
+ }
6114
+ function extractSavedHistorySessionIdFromFile(agentType, file) {
6115
+ const match = file.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
6116
+ return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
6117
+ }
6118
+ function buildSavedHistoryFileSignatureMap(dir, files) {
6119
+ return new Map(files.map((file) => {
6001
6120
  try {
6002
6121
  const stat = fs3.statSync(path7.join(dir, file));
6003
- return `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
6122
+ return [file, `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`];
6004
6123
  } catch {
6005
- return `${file}:missing`;
6006
- }
6007
- }).join("|");
6008
- }
6009
- function computeSavedHistorySessionSummaries(agentType, dir, files) {
6010
- const groupedFiles = /* @__PURE__ */ new Map();
6011
- const filePattern = /^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/;
6012
- for (const file of files) {
6013
- const match = file.match(filePattern);
6014
- if (!match?.[1]) continue;
6015
- const historySessionId = match[1];
6016
- const grouped = groupedFiles.get(historySessionId) || [];
6017
- grouped.push(file);
6018
- groupedFiles.set(historySessionId, grouped);
6019
- }
6020
- const summaries = [];
6021
- for (const [historySessionId, grouped] of groupedFiles.entries()) {
6022
- let messageCount = 0;
6023
- let firstMessageAt = 0;
6024
- let lastMessageAt = 0;
6025
- let sessionTitle = "";
6026
- let preview = "";
6027
- let workspace = "";
6028
- for (const file of grouped.sort()) {
6029
- const filePath = path7.join(dir, file);
6030
- const content = fs3.readFileSync(filePath, "utf-8");
6031
- const lines = content.split("\n").filter(Boolean);
6032
- for (const line of lines) {
6033
- let parsed = null;
6124
+ return [file, `${file}:missing`];
6125
+ }
6126
+ }));
6127
+ }
6128
+ function buildSavedHistoryCacheSignature(files, fileSignatures) {
6129
+ return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
6130
+ }
6131
+ function getSavedHistoryIndexFilePath(dir) {
6132
+ return path7.join(dir, SAVED_HISTORY_INDEX_FILE);
6133
+ }
6134
+ function getSavedHistoryIndexLockPath(dir) {
6135
+ return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
6136
+ }
6137
+ function sleepBlocking(ms) {
6138
+ if (ms <= 0) return;
6139
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
6140
+ }
6141
+ function loadPersistedSavedHistoryIndexFromFile(dir) {
6142
+ try {
6143
+ const filePath = getSavedHistoryIndexFilePath(dir);
6144
+ if (!fs3.existsSync(filePath)) return /* @__PURE__ */ new Map();
6145
+ const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
6146
+ if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.files || typeof raw.files !== "object") {
6147
+ return /* @__PURE__ */ new Map();
6148
+ }
6149
+ return new Map(
6150
+ Object.entries(raw.files).filter(([file, entry]) => !!file && !!entry && typeof entry.signature === "string").map(([file, entry]) => [file, {
6151
+ signature: entry.signature,
6152
+ summary: entry.summary || null
6153
+ }])
6154
+ );
6155
+ } catch {
6156
+ return /* @__PURE__ */ new Map();
6157
+ }
6158
+ }
6159
+ function writePersistedSavedHistoryIndexFile(dir, entries) {
6160
+ const filePath = getSavedHistoryIndexFilePath(dir);
6161
+ const tempPath = `${filePath}.tmp`;
6162
+ const payload = {
6163
+ version: SAVED_HISTORY_INDEX_VERSION,
6164
+ files: Object.fromEntries(entries.entries()),
6165
+ sessions: buildSavedHistorySessionSummaryMapFromEntries(entries)
6166
+ };
6167
+ fs3.writeFileSync(tempPath, JSON.stringify(payload), "utf-8");
6168
+ fs3.renameSync(tempPath, filePath);
6169
+ }
6170
+ function acquireSavedHistoryIndexLock(dir) {
6171
+ const lockPath = getSavedHistoryIndexLockPath(dir);
6172
+ const deadline = Date.now() + SAVED_HISTORY_INDEX_LOCK_WAIT_MS;
6173
+ while (Date.now() <= deadline) {
6174
+ try {
6175
+ fs3.mkdirSync(lockPath);
6176
+ return () => {
6034
6177
  try {
6035
- parsed = JSON.parse(line);
6178
+ fs3.rmSync(lockPath, { recursive: true, force: true });
6036
6179
  } catch {
6037
- parsed = null;
6038
6180
  }
6039
- if (!parsed || parsed.historySessionId !== historySessionId) continue;
6040
- if (parsed.kind === "session_start") {
6041
- if (!workspace && parsed.workspace) workspace = parsed.workspace;
6181
+ };
6182
+ } catch (error) {
6183
+ if (error?.code !== "EEXIST") return null;
6184
+ try {
6185
+ const stat = fs3.statSync(lockPath);
6186
+ if (Date.now() - stat.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
6187
+ fs3.rmSync(lockPath, { recursive: true, force: true });
6042
6188
  continue;
6043
6189
  }
6044
- messageCount += 1;
6045
- if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
6046
- if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
6047
- if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
6048
- if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
6049
- }
6050
- }
6051
- if (messageCount === 0 || !lastMessageAt) continue;
6052
- summaries.push({
6053
- historySessionId,
6054
- sessionTitle: sessionTitle || void 0,
6055
- messageCount,
6056
- firstMessageAt,
6057
- lastMessageAt,
6058
- preview: preview || void 0,
6059
- workspace: workspace || void 0
6060
- });
6190
+ } catch {
6191
+ continue;
6192
+ }
6193
+ sleepBlocking(SAVED_HISTORY_INDEX_LOCK_POLL_MS);
6194
+ }
6195
+ }
6196
+ return null;
6197
+ }
6198
+ function withLockedPersistedSavedHistoryIndex(dir, callback) {
6199
+ const release2 = acquireSavedHistoryIndexLock(dir);
6200
+ if (!release2) return null;
6201
+ try {
6202
+ const entries = loadPersistedSavedHistoryIndexFromFile(dir);
6203
+ const result = callback(entries);
6204
+ writePersistedSavedHistoryIndexFile(dir, entries);
6205
+ return result;
6206
+ } catch {
6207
+ return null;
6208
+ } finally {
6209
+ release2();
6210
+ }
6211
+ }
6212
+ function loadPersistedSavedHistoryIndex(dir) {
6213
+ return loadPersistedSavedHistoryIndexFromFile(dir);
6214
+ }
6215
+ function savePersistedSavedHistoryIndex(dir, entries) {
6216
+ withLockedPersistedSavedHistoryIndex(dir, (currentEntries) => {
6217
+ const incomingFiles = new Set(Array.from(entries.keys()));
6218
+ for (const [file, entry] of Array.from(entries.entries())) {
6219
+ const liveSignature = buildSavedHistoryFileSignature(dir, file);
6220
+ const existingEntry = currentEntries.get(file);
6221
+ if (existingEntry && existingEntry.signature !== liveSignature && entry.signature !== liveSignature) {
6222
+ continue;
6223
+ }
6224
+ if (entry.signature !== liveSignature && (!existingEntry || existingEntry.signature !== liveSignature)) {
6225
+ continue;
6226
+ }
6227
+ currentEntries.set(file, entry.signature === liveSignature ? entry : {
6228
+ signature: liveSignature,
6229
+ summary: existingEntry?.summary || entry.summary
6230
+ });
6231
+ }
6232
+ for (const file of Array.from(currentEntries.keys())) {
6233
+ if (incomingFiles.has(file)) continue;
6234
+ if (!fs3.existsSync(path7.join(dir, file))) {
6235
+ currentEntries.delete(file);
6236
+ }
6237
+ }
6238
+ });
6239
+ }
6240
+ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
6241
+ try {
6242
+ fs3.rmSync(getSavedHistoryIndexFilePath(dir), { force: true });
6243
+ } catch {
6244
+ }
6245
+ savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
6246
+ }
6247
+ function buildSavedHistoryIndexFileSignature(dir) {
6248
+ try {
6249
+ const stat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
6250
+ return `index:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
6251
+ } catch {
6252
+ return "index:missing";
6253
+ }
6254
+ }
6255
+ function historyDirectoryHasFilesNewerThanIndex(dir) {
6256
+ try {
6257
+ const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
6258
+ const files = listHistoryFiles(dir);
6259
+ for (const file of files) {
6260
+ const stat = fs3.statSync(path7.join(dir, file));
6261
+ if (stat.mtimeMs > indexStat.mtimeMs) return true;
6262
+ }
6263
+ return false;
6264
+ } catch {
6265
+ return true;
6266
+ }
6267
+ }
6268
+ function buildSavedHistoryFileSignature(dir, file) {
6269
+ try {
6270
+ const stat = fs3.statSync(path7.join(dir, file));
6271
+ return `${file}:${stat.size}:${Math.trunc(stat.mtimeMs)}`;
6272
+ } catch {
6273
+ return `${file}:missing`;
6274
+ }
6275
+ }
6276
+ function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
6277
+ const filePath = path7.join(dir, file);
6278
+ const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
6279
+ const currentEntry = entries.get(file) || null;
6280
+ const nextSummary = updater(currentEntry?.summary || null);
6281
+ const nextEntry = {
6282
+ signature: buildSavedHistoryFileSignature(dir, file),
6283
+ summary: nextSummary
6284
+ };
6285
+ entries.set(file, nextEntry);
6286
+ savedHistoryFileSummaryCache.set(filePath, nextEntry);
6287
+ return nextEntry;
6288
+ });
6289
+ if (!result) return;
6290
+ if (result.summary?.historySessionId && shouldScheduleSavedHistoryRollupForSignature(result.signature)) {
6291
+ scheduleSavedHistoryRollup(agentType, result.summary.historySessionId);
6292
+ }
6293
+ }
6294
+ function updateSavedHistoryIndexForSessionStart(agentType, dir, file, historySessionId, workspace) {
6295
+ const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
6296
+ const normalizedWorkspace = String(workspace || "").trim();
6297
+ if (!normalizedSessionId || !normalizedWorkspace) return;
6298
+ persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => ({
6299
+ file,
6300
+ historySessionId: normalizedSessionId,
6301
+ messageCount: currentSummary?.messageCount || 0,
6302
+ firstMessageAt: currentSummary?.firstMessageAt || 0,
6303
+ lastMessageAt: currentSummary?.lastMessageAt || 0,
6304
+ sessionTitle: currentSummary?.sessionTitle,
6305
+ preview: currentSummary?.preview,
6306
+ workspace: normalizedWorkspace
6307
+ }));
6308
+ }
6309
+ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, historySessionId, messages) {
6310
+ const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
6311
+ if (!normalizedSessionId || messages.length === 0) return;
6312
+ persistSavedHistoryFileSummaryEntry(agentType, dir, file, (currentSummary) => {
6313
+ const nextSummary = {
6314
+ file,
6315
+ historySessionId: normalizedSessionId,
6316
+ messageCount: currentSummary?.messageCount || 0,
6317
+ firstMessageAt: currentSummary?.firstMessageAt || 0,
6318
+ lastMessageAt: currentSummary?.lastMessageAt || 0,
6319
+ sessionTitle: currentSummary?.sessionTitle,
6320
+ preview: currentSummary?.preview,
6321
+ workspace: currentSummary?.workspace
6322
+ };
6323
+ for (const message of messages) {
6324
+ if (!message || message.historySessionId !== historySessionId) continue;
6325
+ if (message.kind === "session_start") {
6326
+ if (message.workspace) nextSummary.workspace = message.workspace;
6327
+ continue;
6328
+ }
6329
+ nextSummary.messageCount += 1;
6330
+ if (!nextSummary.firstMessageAt || message.receivedAt < nextSummary.firstMessageAt) {
6331
+ nextSummary.firstMessageAt = message.receivedAt;
6332
+ }
6333
+ if (!nextSummary.lastMessageAt || message.receivedAt >= nextSummary.lastMessageAt) {
6334
+ nextSummary.lastMessageAt = message.receivedAt;
6335
+ if (message.sessionTitle) nextSummary.sessionTitle = message.sessionTitle;
6336
+ if (message.role !== "system" && message.content.trim()) nextSummary.preview = message.content.trim();
6337
+ } else if (message.sessionTitle) {
6338
+ nextSummary.sessionTitle = message.sessionTitle;
6339
+ }
6340
+ if (!nextSummary.preview && message.role !== "system" && message.content.trim()) {
6341
+ nextSummary.preview = message.content.trim();
6342
+ }
6343
+ }
6344
+ return nextSummary;
6345
+ });
6346
+ }
6347
+ function computeSavedHistoryFileSummary(agentType, dir, file) {
6348
+ const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file);
6349
+ if (!historySessionId) return null;
6350
+ const filePath = path7.join(dir, file);
6351
+ const content = fs3.readFileSync(filePath, "utf-8");
6352
+ const lines = content.split("\n").filter(Boolean);
6353
+ let messageCount = 0;
6354
+ let firstMessageAt = 0;
6355
+ let lastMessageAt = 0;
6356
+ let sessionTitle = "";
6357
+ let preview = "";
6358
+ let workspace = "";
6359
+ for (const line of lines) {
6360
+ let parsed = null;
6361
+ try {
6362
+ parsed = JSON.parse(line);
6363
+ } catch {
6364
+ parsed = null;
6365
+ }
6366
+ if (!parsed || parsed.historySessionId !== historySessionId) continue;
6367
+ if (parsed.kind === "session_start") {
6368
+ if (!workspace && parsed.workspace) workspace = parsed.workspace;
6369
+ continue;
6370
+ }
6371
+ messageCount += 1;
6372
+ if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
6373
+ if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
6374
+ if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
6375
+ if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
6376
+ }
6377
+ if (messageCount === 0 || !lastMessageAt) return null;
6378
+ return {
6379
+ file,
6380
+ historySessionId,
6381
+ messageCount,
6382
+ firstMessageAt,
6383
+ lastMessageAt,
6384
+ sessionTitle: sessionTitle || void 0,
6385
+ preview: preview || void 0,
6386
+ workspace: workspace || void 0
6387
+ };
6388
+ }
6389
+ function shouldScheduleSavedHistoryRollupForSignature(signature) {
6390
+ const parts = String(signature || "").split(":");
6391
+ const size = Number(parts[1] || 0);
6392
+ return shouldScheduleSavedHistoryRollup(size);
6393
+ }
6394
+ function scheduleSavedHistoryRollup(agentType, historySessionId) {
6395
+ const key = `${agentType}:${historySessionId}`;
6396
+ if (!historySessionId || savedHistoryRollupInFlight.has(key)) return;
6397
+ savedHistoryRollupInFlight.add(key);
6398
+ setTimeout(() => {
6399
+ try {
6400
+ new ChatHistoryWriter().compactHistorySession(agentType, historySessionId);
6401
+ } finally {
6402
+ savedHistoryRollupInFlight.delete(key);
6403
+ }
6404
+ }, 0);
6405
+ }
6406
+ function scheduleSavedHistoryBackgroundRefresh(agentType, dir) {
6407
+ const key = `${agentType}:${dir}`;
6408
+ if (savedHistoryBackgroundRefresh.has(key)) return;
6409
+ savedHistoryBackgroundRefresh.add(key);
6410
+ setTimeout(() => {
6411
+ try {
6412
+ if (!fs3.existsSync(dir)) return;
6413
+ const files = listHistoryFiles(dir);
6414
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
6415
+ const persistedEntries = loadPersistedSavedHistoryIndex(dir);
6416
+ const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
6417
+ savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
6418
+ const refreshedIndexSignature = buildSavedHistoryIndexFileSignature(dir);
6419
+ savedHistorySessionCache.set(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"), {
6420
+ signature: refreshedIndexSignature,
6421
+ summaries: computed.summaries || []
6422
+ });
6423
+ for (const [file, entry] of Array.from(computed.persistedEntries.entries())) {
6424
+ if (!entry?.summary || !shouldScheduleSavedHistoryRollupForSignature(entry.signature)) continue;
6425
+ scheduleSavedHistoryRollup(agentType, entry.summary.historySessionId);
6426
+ }
6427
+ } catch {
6428
+ } finally {
6429
+ savedHistoryBackgroundRefresh.delete(key);
6430
+ }
6431
+ }, 0);
6432
+ }
6433
+ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries) {
6434
+ const summaryBySessionId = /* @__PURE__ */ new Map();
6435
+ const nextPersistedEntries = /* @__PURE__ */ new Map();
6436
+ for (const file of files.slice().sort()) {
6437
+ const filePath = path7.join(dir, file);
6438
+ const signature = fileSignatures.get(file) || `${file}:missing`;
6439
+ const cached = savedHistoryFileSummaryCache.get(filePath);
6440
+ const persisted = persistedEntries.get(file);
6441
+ const reusableEntry = cached?.signature === signature ? cached : persisted?.signature === signature ? persisted : null;
6442
+ const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file);
6443
+ const nextEntry = reusableEntry || {
6444
+ signature,
6445
+ summary: fileSummary
6446
+ };
6447
+ if (!reusableEntry) {
6448
+ nextEntry.signature = signature;
6449
+ nextEntry.summary = fileSummary;
6450
+ }
6451
+ savedHistoryFileSummaryCache.set(filePath, nextEntry);
6452
+ nextPersistedEntries.set(file, nextEntry);
6453
+ if (!fileSummary) continue;
6454
+ const existing = summaryBySessionId.get(fileSummary.historySessionId);
6455
+ if (fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) {
6456
+ continue;
6457
+ }
6458
+ if (!existing) {
6459
+ summaryBySessionId.set(fileSummary.historySessionId, {
6460
+ historySessionId: fileSummary.historySessionId,
6461
+ sessionTitle: fileSummary.sessionTitle,
6462
+ messageCount: fileSummary.messageCount,
6463
+ firstMessageAt: fileSummary.firstMessageAt,
6464
+ lastMessageAt: fileSummary.lastMessageAt,
6465
+ preview: fileSummary.preview,
6466
+ workspace: fileSummary.workspace
6467
+ });
6468
+ continue;
6469
+ }
6470
+ existing.messageCount += fileSummary.messageCount;
6471
+ if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
6472
+ existing.firstMessageAt = fileSummary.firstMessageAt;
6473
+ }
6474
+ if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
6475
+ existing.lastMessageAt = fileSummary.lastMessageAt;
6476
+ if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
6477
+ if (fileSummary.preview) existing.preview = fileSummary.preview;
6478
+ }
6479
+ if (!existing.workspace && fileSummary.workspace) {
6480
+ existing.workspace = fileSummary.workspace;
6481
+ }
6061
6482
  }
6062
- summaries.sort((a, b) => b.lastMessageAt - a.lastMessageAt);
6063
- return summaries;
6483
+ return {
6484
+ summaries: Array.from(summaryBySessionId.values()).sort((a, b) => b.lastMessageAt - a.lastMessageAt),
6485
+ persistedEntries: nextPersistedEntries
6486
+ };
6064
6487
  }
6065
6488
  var ChatHistoryWriter = class {
6066
6489
  /** Last seen message count per agent (deduplication) */
@@ -6135,9 +6558,11 @@ var ChatHistoryWriter = class {
6135
6558
  fs3.mkdirSync(dir, { recursive: true });
6136
6559
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6137
6560
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
6138
- const filePath = path7.join(dir, `${filePrefix}${date}.jsonl`);
6561
+ const fileName = `${filePrefix}${date}.jsonl`;
6562
+ const filePath = path7.join(dir, fileName);
6139
6563
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
6140
6564
  fs3.appendFileSync(filePath, lines, "utf-8");
6565
+ updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
6141
6566
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
6142
6567
  if (!historySessionId && messages.length < prevCount * 0.5 && prevCount > 3) {
6143
6568
  seenHashes.clear();
@@ -6228,7 +6653,8 @@ var ChatHistoryWriter = class {
6228
6653
  const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
6229
6654
  fs3.mkdirSync(dir, { recursive: true });
6230
6655
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6231
- const filePath = path7.join(dir, `${this.sanitize(id)}_${date}.jsonl`);
6656
+ const fileName = `${this.sanitize(id)}_${date}.jsonl`;
6657
+ const filePath = path7.join(dir, fileName);
6232
6658
  const record = {
6233
6659
  ts: (/* @__PURE__ */ new Date()).toISOString(),
6234
6660
  receivedAt: Date.now(),
@@ -6241,6 +6667,7 @@ var ChatHistoryWriter = class {
6241
6667
  workspace: ws
6242
6668
  };
6243
6669
  fs3.appendFileSync(filePath, JSON.stringify(record) + "\n", "utf-8");
6670
+ updateSavedHistoryIndexForSessionStart(agentType, dir, fileName, id, ws);
6244
6671
  } catch {
6245
6672
  }
6246
6673
  }
@@ -6306,6 +6733,7 @@ var ChatHistoryWriter = class {
6306
6733
  }
6307
6734
  fs3.unlinkSync(sourcePath);
6308
6735
  }
6736
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
6309
6737
  } catch {
6310
6738
  }
6311
6739
  }
@@ -6355,6 +6783,7 @@ var ChatHistoryWriter = class {
6355
6783
  fs3.writeFileSync(filePath, `${collapsed.map((entry) => JSON.stringify(entry)).join("\n")}
6356
6784
  `, "utf-8");
6357
6785
  }
6786
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
6358
6787
  } catch {
6359
6788
  }
6360
6789
  }
@@ -6374,13 +6803,18 @@ var ChatHistoryWriter = class {
6374
6803
  for (const dir of agentDirs) {
6375
6804
  const dirPath = path7.join(HISTORY_DIR, dir.name);
6376
6805
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
6806
+ let removedAny = false;
6377
6807
  for (const file of files) {
6378
6808
  const filePath = path7.join(dirPath, file);
6379
6809
  const stat = fs3.statSync(filePath);
6380
6810
  if (stat.mtimeMs < cutoff) {
6381
6811
  fs3.unlinkSync(filePath);
6812
+ removedAny = true;
6382
6813
  }
6383
6814
  }
6815
+ if (removedAny) {
6816
+ invalidatePersistedSavedHistoryIndex(dir.name, dirPath);
6817
+ }
6384
6818
  }
6385
6819
  } catch {
6386
6820
  }
@@ -6446,18 +6880,51 @@ function listSavedHistorySessions(agentType, options = {}) {
6446
6880
  savedHistorySessionCache.delete(sanitized);
6447
6881
  return { sessions: [], hasMore: false };
6448
6882
  }
6449
- const files = listHistoryFiles(dir);
6450
- const signature = buildSavedHistoryCacheSignature(dir, files);
6451
6883
  const cached = savedHistorySessionCache.get(sanitized);
6452
- const summaries = cached?.signature === signature ? cached.summaries : computeSavedHistorySessionSummaries(agentType, dir, files);
6453
- if (!cached || cached.signature !== signature) {
6884
+ const offset = Math.max(0, options.offset || 0);
6885
+ const limit = Math.max(1, options.limit || 30);
6886
+ const indexSignature = buildSavedHistoryIndexFileSignature(dir);
6887
+ let cacheWasInvalidated = false;
6888
+ if (cached) {
6889
+ const cacheLooksPersisted = cached.signature.startsWith("index:");
6890
+ const cacheStillValid = cacheLooksPersisted ? cached.signature === indexSignature : (() => {
6891
+ const files2 = listHistoryFiles(dir);
6892
+ const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
6893
+ return cached.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
6894
+ })();
6895
+ if (cacheStillValid) {
6896
+ const sliced2 = cached.summaries.slice(offset, offset + limit);
6897
+ return {
6898
+ sessions: sliced2,
6899
+ hasMore: cached.summaries.length > offset + limit
6900
+ };
6901
+ }
6902
+ cacheWasInvalidated = true;
6903
+ }
6904
+ const persistedSessions = readPersistedSavedHistorySessionSummaries(dir);
6905
+ if (!cacheWasInvalidated && persistedSessions?.length && !historyDirectoryHasFilesNewerThanIndex(dir)) {
6454
6906
  savedHistorySessionCache.set(sanitized, {
6455
- signature,
6456
- summaries
6907
+ signature: indexSignature,
6908
+ summaries: persistedSessions
6457
6909
  });
6910
+ scheduleSavedHistoryBackgroundRefresh(agentType, dir);
6911
+ const sliced2 = persistedSessions.slice(offset, offset + limit);
6912
+ return {
6913
+ sessions: sliced2,
6914
+ hasMore: persistedSessions.length > offset + limit
6915
+ };
6458
6916
  }
6459
- const offset = Math.max(0, options.offset || 0);
6460
- const limit = Math.max(1, options.limit || 30);
6917
+ const files = listHistoryFiles(dir);
6918
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
6919
+ const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
6920
+ const persistedEntries = loadPersistedSavedHistoryIndex(dir);
6921
+ const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
6922
+ const summaries = computed.summaries || [];
6923
+ savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
6924
+ savedHistorySessionCache.set(sanitized, {
6925
+ signature,
6926
+ summaries
6927
+ });
6461
6928
  const sliced = summaries.slice(offset, offset + limit);
6462
6929
  return {
6463
6930
  sessions: sliced,
@@ -8210,6 +8677,21 @@ function buildExtensionAgentSession(parent, ext, options) {
8210
8677
  lastUpdated: ext.lastUpdated
8211
8678
  };
8212
8679
  }
8680
+ function shouldIncludeExtensionSession(ext) {
8681
+ const status = String(ext.status || "").trim().toLowerCase();
8682
+ const hasActiveChat = !!ext.activeChat;
8683
+ const hasMessages = Array.isArray(ext.activeChat?.messages) && ext.activeChat.messages.length > 0;
8684
+ const hasModal = !!ext.activeChat?.activeModal;
8685
+ const hasStreams = Array.isArray(ext.agentStreams) && ext.agentStreams.length > 0;
8686
+ const hasProviderSessionId = typeof ext.providerSessionId === "string" && ext.providerSessionId.trim().length > 0;
8687
+ const hasControlValues = !!(ext.controlValues && Object.keys(ext.controlValues).length > 0);
8688
+ const hasProviderControls = Array.isArray(ext.providerControls) && ext.providerControls.length > 0;
8689
+ const hasOpenPanelCapability = Array.isArray(ext.sessionCapabilities) && ext.sessionCapabilities.includes("open_panel");
8690
+ const hasSummaryMetadata = !!ext.summaryMetadata;
8691
+ const hasError = typeof ext.errorMessage === "string" && ext.errorMessage.trim().length > 0;
8692
+ const hasInterestingStatus = !!status && !["idle", "panel_hidden", "disconnected", "not_monitored"].includes(status);
8693
+ return hasActiveChat || hasMessages || hasModal || hasStreams || hasProviderSessionId || hasControlValues || hasProviderControls || hasOpenPanelCapability || hasSummaryMetadata || hasError || hasInterestingStatus;
8694
+ }
8213
8695
  function buildCliSession(state, options) {
8214
8696
  const profile = options.profile || "full";
8215
8697
  const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
@@ -8293,6 +8775,7 @@ function buildSessionEntries(allStates, cdpManagers, options = {}) {
8293
8775
  for (const state of ideStates) {
8294
8776
  sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
8295
8777
  for (const ext of state.extensions) {
8778
+ if (!shouldIncludeExtensionSession(ext)) continue;
8296
8779
  sessions.push(buildExtensionAgentSession(state, ext, options));
8297
8780
  }
8298
8781
  }
@@ -10463,7 +10946,9 @@ function applyProviderPatch(h, args, payload) {
10463
10946
  });
10464
10947
  }
10465
10948
  async function executeProviderScript(h, args, scriptName) {
10466
- const resolvedProviderType = h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
10949
+ const explicitTargetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
10950
+ const targetSession = explicitTargetSessionId ? h.ctx.sessionRegistry?.get(explicitTargetSessionId) : void 0;
10951
+ const resolvedProviderType = targetSession?.providerType || h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
10467
10952
  if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
10468
10953
  const loader = h.ctx.providerLoader;
10469
10954
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
@@ -10506,16 +10991,16 @@ async function executeProviderScript(h, args, scriptName) {
10506
10991
  const scriptFn = provider.scripts[actualScriptName];
10507
10992
  const scriptCode = scriptFn(normalizedArgs);
10508
10993
  if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
10509
- const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
10994
+ const cdpKey = provider.category === "ide" ? targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey;
10510
10995
  LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
10511
10996
  const cdp = h.getCdp(cdpKey);
10512
10997
  if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
10513
10998
  try {
10514
10999
  let result;
10515
11000
  if (provider.category === "extension") {
10516
- const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
11001
+ const runtimeSessionId = explicitTargetSessionId || h.currentSession?.sessionId;
10517
11002
  if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
10518
- const parentSessionId = h.currentSession?.parentSessionId;
11003
+ const parentSessionId = targetSession?.parentSessionId || h.currentSession?.parentSessionId;
10519
11004
  if (parentSessionId) {
10520
11005
  await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
10521
11006
  await h.agentStream?.syncActiveSession(cdp, parentSessionId);
@@ -17443,6 +17928,23 @@ function prepareSessionModalUpdate(input) {
17443
17928
  };
17444
17929
  }
17445
17930
 
17931
+ // src/chat/async-batch.ts
17932
+ async function runAsyncBatch(items, worker, options = {}) {
17933
+ const list = Array.from(items);
17934
+ if (list.length === 0) return;
17935
+ const concurrency = Math.max(1, Math.min(list.length, Math.floor(options.concurrency || 1)));
17936
+ let nextIndex = 0;
17937
+ const runners = Array.from({ length: concurrency }, async () => {
17938
+ while (true) {
17939
+ const currentIndex = nextIndex;
17940
+ nextIndex += 1;
17941
+ if (currentIndex >= list.length) return;
17942
+ await worker(list[currentIndex], currentIndex);
17943
+ }
17944
+ });
17945
+ await Promise.all(runners);
17946
+ }
17947
+
17446
17948
  // src/agent-stream/provider-adapter.ts
17447
17949
  init_read_chat_contract();
17448
17950
  init_chat_message_normalization();
@@ -17911,10 +18413,12 @@ var DaemonAgentStreamManager = class {
17911
18413
  }
17912
18414
  }
17913
18415
  /** Collect active extension session state */
17914
- async collectActiveSession(cdp, parentSessionId) {
18416
+ async collectActiveSession(cdp, parentSessionId, attemptedSessionIds = /* @__PURE__ */ new Set(), originSessionId) {
17915
18417
  if (!this.enabled) return null;
17916
18418
  const activeSessionId = this.getActiveSessionId(parentSessionId);
17917
18419
  if (!activeSessionId) return null;
18420
+ const resolvedOriginSessionId = originSessionId || activeSessionId;
18421
+ attemptedSessionIds.add(activeSessionId);
17918
18422
  let agent = this.managedBySessionId.get(activeSessionId);
17919
18423
  if (!agent) {
17920
18424
  agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
@@ -17927,18 +18431,44 @@ var DaemonAgentStreamManager = class {
17927
18431
  try {
17928
18432
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
17929
18433
  const state = await agent.adapter.readChat(evaluate);
17930
- const stateError = this.getStateError(state);
17931
- const selectedModelValue = typeof state.controlValues?.model === "string" ? state.controlValues.model : "";
17932
- LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${selectedModelValue}${state.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
17933
- if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
18434
+ 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;
18435
+ const normalizedState = {
18436
+ ...state,
18437
+ sessionId: agent.runtimeSessionId,
18438
+ ...resolvedProviderSessionId ? { providerSessionId: resolvedProviderSessionId } : {}
18439
+ };
18440
+ const stateError = this.getStateError(normalizedState);
18441
+ const selectedModelValue = typeof normalizedState.controlValues?.model === "string" ? normalizedState.controlValues.model : "";
18442
+ LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${normalizedState.status} msgs=${normalizedState.messages?.length || 0} model=${selectedModelValue}${normalizedState.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
18443
+ if (normalizedState.status === "error" && this.isRecoverableSessionError(stateError)) {
17934
18444
  throw new Error(stateError);
17935
18445
  }
17936
- agent.lastState = state;
18446
+ agent.lastState = normalizedState;
17937
18447
  agent.lastError = null;
17938
- if (state.status === "panel_hidden") {
18448
+ if (normalizedState.status === "panel_hidden") {
18449
+ const discovered = await cdp.discoverAgentWebviews().catch(() => []);
18450
+ const fallbackTarget = discovered.find((entry) => {
18451
+ if (entry.agentType === type) return false;
18452
+ const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, entry.agentType);
18453
+ return !!fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId);
18454
+ });
18455
+ if (fallbackTarget) {
18456
+ const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, fallbackTarget.agentType);
18457
+ if (fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId)) {
18458
+ this.logFn(`[AgentStream] Active session ${type} is hidden; switching to visible agent ${fallbackTarget.agentType} (${parentSessionId})`);
18459
+ await this.setActiveSession(cdp, parentSessionId, fallbackSessionId);
18460
+ await this.syncActiveSession(cdp, parentSessionId);
18461
+ const fallbackState = await this.collectActiveSession(cdp, parentSessionId, attemptedSessionIds, resolvedOriginSessionId);
18462
+ if (fallbackState?.status === "panel_hidden" && resolvedOriginSessionId !== fallbackSessionId) {
18463
+ await this.setActiveSession(cdp, parentSessionId, resolvedOriginSessionId);
18464
+ await this.syncActiveSession(cdp, parentSessionId);
18465
+ }
18466
+ return fallbackState;
18467
+ }
18468
+ }
17939
18469
  agent.lastHiddenCheckTime = Date.now();
17940
18470
  }
17941
- return state;
18471
+ return normalizedState;
17942
18472
  } catch (e) {
17943
18473
  const errorMsg = e?.message || String(e);
17944
18474
  this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
@@ -18234,6 +18764,7 @@ var AgentStreamPoller = class {
18234
18764
  try {
18235
18765
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
18236
18766
  let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
18767
+ resolvedActiveSessionId = stream?.sessionId || agentStreamManager.getActiveSessionId(parentSessionId) || resolvedActiveSessionId;
18237
18768
  if (stream?.status === "waiting_approval") {
18238
18769
  const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
18239
18770
  if (autoApprove && resolvedActiveSessionId) {
@@ -24943,6 +25474,7 @@ export {
24943
25474
  resolveChatMessageKind,
24944
25475
  resolveDebugRuntimeConfig,
24945
25476
  resolveSessionHostAppName,
25477
+ runAsyncBatch,
24946
25478
  saveConfig,
24947
25479
  saveState,
24948
25480
  setDebugRuntimeConfig,