adhdev 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
@@ -1287,6 +1287,32 @@ var init_logger = __esm({
1287
1287
  });
1288
1288
 
1289
1289
  // ../../oss/packages/daemon-core/src/cdp/manager.ts
1290
+ function normalizeTitle(value) {
1291
+ return String(value || "").trim().replace(/\s+/g, " ").toLowerCase();
1292
+ }
1293
+ function titlesMatch(lhs, rhs) {
1294
+ const a = normalizeTitle(lhs);
1295
+ const b = normalizeTitle(rhs);
1296
+ if (!a || !b) return false;
1297
+ return a === b || a.includes(b) || b.includes(a);
1298
+ }
1299
+ function resolveCdpPageTarget(params) {
1300
+ const { pages, pinnedTargetId, previousPageTitle } = params;
1301
+ if (pages.length === 0) return { target: null, retargeted: false };
1302
+ if (!pinnedTargetId) {
1303
+ return { target: pages[0] || null, retargeted: false };
1304
+ }
1305
+ const exact = pages.find((page) => page.id === pinnedTargetId);
1306
+ if (exact) return { target: exact, retargeted: false };
1307
+ const titleMatchesList = pages.filter((page) => titlesMatch(page.title, previousPageTitle));
1308
+ if (titleMatchesList.length === 1) {
1309
+ return { target: titleMatchesList[0], retargeted: true };
1310
+ }
1311
+ if (pages.length === 1) {
1312
+ return { target: pages[0], retargeted: true };
1313
+ }
1314
+ return { target: null, retargeted: false };
1315
+ }
1290
1316
  var import_ws, http, DaemonCdpManager;
1291
1317
  var init_manager = __esm({
1292
1318
  "../../oss/packages/daemon-core/src/cdp/manager.ts"() {
@@ -1454,18 +1480,28 @@ var init_manager = __esm({
1454
1480
  resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
1455
1481
  return;
1456
1482
  }
1457
- const mainPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
1458
- const list = mainPages.length > 0 ? mainPages : pages;
1483
+ const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
1484
+ const mainPages = titleFilteredPages.filter((t) => this.isMainPageUrl(t.url));
1485
+ const list = mainPages.length > 0 ? mainPages : titleFilteredPages.length > 0 ? titleFilteredPages : pages;
1459
1486
  this.log(`[CDP] pages(${list.length}): ${list.map((t) => `"${t.title}"`).join(", ")}`);
1460
- if (this._targetId) {
1461
- const specific = list.find((t) => t.id === this._targetId);
1462
- if (specific) {
1463
- this._pageTitle = specific.title || "";
1464
- resolve15(specific);
1465
- } else {
1466
- this.log(`[CDP] Target ${this._targetId} not found in page list`);
1467
- resolve15(null);
1487
+ const previousTargetId = this._targetId;
1488
+ const selected = resolveCdpPageTarget({
1489
+ pages: list,
1490
+ pinnedTargetId: previousTargetId,
1491
+ previousPageTitle: this._pageTitle
1492
+ });
1493
+ if (selected.target) {
1494
+ if (selected.retargeted && previousTargetId && previousTargetId !== selected.target.id) {
1495
+ this.log(`[CDP] Target ${previousTargetId} rekeyed to ${selected.target.id}`);
1496
+ this._targetId = selected.target.id;
1468
1497
  }
1498
+ this._pageTitle = selected.target.title || "";
1499
+ resolve15(selected.target);
1500
+ return;
1501
+ }
1502
+ if (previousTargetId) {
1503
+ this.log(`[CDP] Target ${previousTargetId} not found in page list`);
1504
+ resolve15(null);
1469
1505
  return;
1470
1506
  }
1471
1507
  this._pageTitle = list[0]?.title || "";
@@ -3342,6 +3378,68 @@ function sanitizeHistoryMessage(agentType, message) {
3342
3378
  content
3343
3379
  };
3344
3380
  }
3381
+ function sortSavedHistorySessionSummaries(summaries) {
3382
+ return summaries.slice().sort((a, b) => b.lastMessageAt - a.lastMessageAt);
3383
+ }
3384
+ function buildSavedHistorySessionSummaryMapFromEntries(entries) {
3385
+ const summaries = /* @__PURE__ */ new Map();
3386
+ for (const entry of Array.from(entries.values())) {
3387
+ const fileSummary = entry.summary;
3388
+ if (!fileSummary || fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) continue;
3389
+ const existing = summaries.get(fileSummary.historySessionId);
3390
+ if (!existing) {
3391
+ summaries.set(fileSummary.historySessionId, {
3392
+ historySessionId: fileSummary.historySessionId,
3393
+ sessionTitle: fileSummary.sessionTitle,
3394
+ messageCount: fileSummary.messageCount,
3395
+ firstMessageAt: fileSummary.firstMessageAt,
3396
+ lastMessageAt: fileSummary.lastMessageAt,
3397
+ preview: fileSummary.preview,
3398
+ workspace: fileSummary.workspace
3399
+ });
3400
+ continue;
3401
+ }
3402
+ existing.messageCount += fileSummary.messageCount;
3403
+ if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
3404
+ existing.firstMessageAt = fileSummary.firstMessageAt;
3405
+ }
3406
+ if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
3407
+ existing.lastMessageAt = fileSummary.lastMessageAt;
3408
+ if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
3409
+ if (fileSummary.preview) existing.preview = fileSummary.preview;
3410
+ }
3411
+ if (!existing.workspace && fileSummary.workspace) {
3412
+ existing.workspace = fileSummary.workspace;
3413
+ }
3414
+ }
3415
+ return Object.fromEntries(sortSavedHistorySessionSummaries(Array.from(summaries.values())).map((summary) => [summary.historySessionId, summary]));
3416
+ }
3417
+ function readPersistedSavedHistorySessionSummaries(dir) {
3418
+ try {
3419
+ const filePath = getSavedHistoryIndexFilePath(dir);
3420
+ if (!fs3.existsSync(filePath)) return null;
3421
+ const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
3422
+ if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.sessions || typeof raw.sessions !== "object") {
3423
+ return null;
3424
+ }
3425
+ return sortSavedHistorySessionSummaries(
3426
+ Object.values(raw.sessions).filter((summary) => !!summary && typeof summary.historySessionId === "string" && summary.messageCount > 0 && summary.lastMessageAt > 0).map((summary) => ({
3427
+ historySessionId: summary.historySessionId,
3428
+ sessionTitle: summary.sessionTitle,
3429
+ messageCount: summary.messageCount,
3430
+ firstMessageAt: summary.firstMessageAt,
3431
+ lastMessageAt: summary.lastMessageAt,
3432
+ preview: summary.preview,
3433
+ workspace: summary.workspace
3434
+ }))
3435
+ );
3436
+ } catch {
3437
+ return null;
3438
+ }
3439
+ }
3440
+ function shouldScheduleSavedHistoryRollup(totalBytes) {
3441
+ return Number.isFinite(totalBytes) && totalBytes >= SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES;
3442
+ }
3345
3443
  function sanitizeHistoryFileSegment(value) {
3346
3444
  return String(value || "").replace(/[^a-zA-Z0-9_-]/g, "_");
3347
3445
  }
@@ -3355,71 +3453,386 @@ function listHistoryFiles(dir, historySessionId) {
3355
3453
  return true;
3356
3454
  }).sort().reverse();
3357
3455
  }
3358
- function buildSavedHistoryCacheSignature(dir, files) {
3359
- return files.map((file2) => {
3456
+ function normalizeSavedHistorySessionId(agentType, historySessionId) {
3457
+ const normalizedId = String(historySessionId || "").trim();
3458
+ if (!normalizedId) return "";
3459
+ const strictProviderId = normalizeProviderSessionId(agentType, normalizedId);
3460
+ if (strictProviderId) return strictProviderId;
3461
+ return agentType === "hermes-cli" ? "" : normalizedId;
3462
+ }
3463
+ function extractSavedHistorySessionIdFromFile(agentType, file2) {
3464
+ const match = file2.match(/^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/);
3465
+ return normalizeSavedHistorySessionId(agentType, match?.[1] || "");
3466
+ }
3467
+ function buildSavedHistoryFileSignatureMap(dir, files) {
3468
+ return new Map(files.map((file2) => {
3360
3469
  try {
3361
3470
  const stat4 = fs3.statSync(path7.join(dir, file2));
3362
- return `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`;
3471
+ return [file2, `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`];
3363
3472
  } catch {
3364
- return `${file2}:missing`;
3365
- }
3366
- }).join("|");
3367
- }
3368
- function computeSavedHistorySessionSummaries(agentType, dir, files) {
3369
- const groupedFiles = /* @__PURE__ */ new Map();
3370
- const filePattern = /^([A-Za-z0-9_-]+)_\d{4}-\d{2}-\d{2}\.jsonl$/;
3371
- for (const file2 of files) {
3372
- const match = file2.match(filePattern);
3373
- if (!match?.[1]) continue;
3374
- const historySessionId = match[1];
3375
- const grouped = groupedFiles.get(historySessionId) || [];
3376
- grouped.push(file2);
3377
- groupedFiles.set(historySessionId, grouped);
3378
- }
3379
- const summaries = [];
3380
- for (const [historySessionId, grouped] of groupedFiles.entries()) {
3381
- let messageCount = 0;
3382
- let firstMessageAt = 0;
3383
- let lastMessageAt = 0;
3384
- let sessionTitle = "";
3385
- let preview = "";
3386
- let workspace = "";
3387
- for (const file2 of grouped.sort()) {
3388
- const filePath = path7.join(dir, file2);
3389
- const content = fs3.readFileSync(filePath, "utf-8");
3390
- const lines = content.split("\n").filter(Boolean);
3391
- for (const line of lines) {
3392
- let parsed = null;
3473
+ return [file2, `${file2}:missing`];
3474
+ }
3475
+ }));
3476
+ }
3477
+ function buildSavedHistoryCacheSignature(files, fileSignatures) {
3478
+ return files.map((file2) => fileSignatures.get(file2) || `${file2}:missing`).join("|");
3479
+ }
3480
+ function getSavedHistoryIndexFilePath(dir) {
3481
+ return path7.join(dir, SAVED_HISTORY_INDEX_FILE);
3482
+ }
3483
+ function getSavedHistoryIndexLockPath(dir) {
3484
+ return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
3485
+ }
3486
+ function sleepBlocking(ms) {
3487
+ if (ms <= 0) return;
3488
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
3489
+ }
3490
+ function loadPersistedSavedHistoryIndexFromFile(dir) {
3491
+ try {
3492
+ const filePath = getSavedHistoryIndexFilePath(dir);
3493
+ if (!fs3.existsSync(filePath)) return /* @__PURE__ */ new Map();
3494
+ const raw = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
3495
+ if (!raw || raw.version !== SAVED_HISTORY_INDEX_VERSION || !raw.files || typeof raw.files !== "object") {
3496
+ return /* @__PURE__ */ new Map();
3497
+ }
3498
+ return new Map(
3499
+ Object.entries(raw.files).filter(([file2, entry]) => !!file2 && !!entry && typeof entry.signature === "string").map(([file2, entry]) => [file2, {
3500
+ signature: entry.signature,
3501
+ summary: entry.summary || null
3502
+ }])
3503
+ );
3504
+ } catch {
3505
+ return /* @__PURE__ */ new Map();
3506
+ }
3507
+ }
3508
+ function writePersistedSavedHistoryIndexFile(dir, entries) {
3509
+ const filePath = getSavedHistoryIndexFilePath(dir);
3510
+ const tempPath = `${filePath}.tmp`;
3511
+ const payload = {
3512
+ version: SAVED_HISTORY_INDEX_VERSION,
3513
+ files: Object.fromEntries(entries.entries()),
3514
+ sessions: buildSavedHistorySessionSummaryMapFromEntries(entries)
3515
+ };
3516
+ fs3.writeFileSync(tempPath, JSON.stringify(payload), "utf-8");
3517
+ fs3.renameSync(tempPath, filePath);
3518
+ }
3519
+ function acquireSavedHistoryIndexLock(dir) {
3520
+ const lockPath = getSavedHistoryIndexLockPath(dir);
3521
+ const deadline = Date.now() + SAVED_HISTORY_INDEX_LOCK_WAIT_MS;
3522
+ while (Date.now() <= deadline) {
3523
+ try {
3524
+ fs3.mkdirSync(lockPath);
3525
+ return () => {
3393
3526
  try {
3394
- parsed = JSON.parse(line);
3527
+ fs3.rmSync(lockPath, { recursive: true, force: true });
3395
3528
  } catch {
3396
- parsed = null;
3397
3529
  }
3398
- if (!parsed || parsed.historySessionId !== historySessionId) continue;
3399
- if (parsed.kind === "session_start") {
3400
- if (!workspace && parsed.workspace) workspace = parsed.workspace;
3530
+ };
3531
+ } catch (error48) {
3532
+ if (error48?.code !== "EEXIST") return null;
3533
+ try {
3534
+ const stat4 = fs3.statSync(lockPath);
3535
+ if (Date.now() - stat4.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
3536
+ fs3.rmSync(lockPath, { recursive: true, force: true });
3401
3537
  continue;
3402
3538
  }
3403
- messageCount += 1;
3404
- if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
3405
- if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
3406
- if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
3407
- if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
3408
- }
3409
- }
3410
- if (messageCount === 0 || !lastMessageAt) continue;
3411
- summaries.push({
3412
- historySessionId,
3413
- sessionTitle: sessionTitle || void 0,
3414
- messageCount,
3415
- firstMessageAt,
3416
- lastMessageAt,
3417
- preview: preview || void 0,
3418
- workspace: workspace || void 0
3419
- });
3539
+ } catch {
3540
+ continue;
3541
+ }
3542
+ sleepBlocking(SAVED_HISTORY_INDEX_LOCK_POLL_MS);
3543
+ }
3544
+ }
3545
+ return null;
3546
+ }
3547
+ function withLockedPersistedSavedHistoryIndex(dir, callback) {
3548
+ const release2 = acquireSavedHistoryIndexLock(dir);
3549
+ if (!release2) return null;
3550
+ try {
3551
+ const entries = loadPersistedSavedHistoryIndexFromFile(dir);
3552
+ const result = callback(entries);
3553
+ writePersistedSavedHistoryIndexFile(dir, entries);
3554
+ return result;
3555
+ } catch {
3556
+ return null;
3557
+ } finally {
3558
+ release2();
3559
+ }
3560
+ }
3561
+ function loadPersistedSavedHistoryIndex(dir) {
3562
+ return loadPersistedSavedHistoryIndexFromFile(dir);
3563
+ }
3564
+ function savePersistedSavedHistoryIndex(dir, entries) {
3565
+ withLockedPersistedSavedHistoryIndex(dir, (currentEntries) => {
3566
+ const incomingFiles = new Set(Array.from(entries.keys()));
3567
+ for (const [file2, entry] of Array.from(entries.entries())) {
3568
+ const liveSignature = buildSavedHistoryFileSignature(dir, file2);
3569
+ const existingEntry = currentEntries.get(file2);
3570
+ if (existingEntry && existingEntry.signature !== liveSignature && entry.signature !== liveSignature) {
3571
+ continue;
3572
+ }
3573
+ if (entry.signature !== liveSignature && (!existingEntry || existingEntry.signature !== liveSignature)) {
3574
+ continue;
3575
+ }
3576
+ currentEntries.set(file2, entry.signature === liveSignature ? entry : {
3577
+ signature: liveSignature,
3578
+ summary: existingEntry?.summary || entry.summary
3579
+ });
3580
+ }
3581
+ for (const file2 of Array.from(currentEntries.keys())) {
3582
+ if (incomingFiles.has(file2)) continue;
3583
+ if (!fs3.existsSync(path7.join(dir, file2))) {
3584
+ currentEntries.delete(file2);
3585
+ }
3586
+ }
3587
+ });
3588
+ }
3589
+ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
3590
+ try {
3591
+ fs3.rmSync(getSavedHistoryIndexFilePath(dir), { force: true });
3592
+ } catch {
3593
+ }
3594
+ savedHistorySessionCache.delete(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"));
3595
+ }
3596
+ function buildSavedHistoryIndexFileSignature(dir) {
3597
+ try {
3598
+ const stat4 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
3599
+ return `index:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`;
3600
+ } catch {
3601
+ return "index:missing";
3602
+ }
3603
+ }
3604
+ function historyDirectoryHasFilesNewerThanIndex(dir) {
3605
+ try {
3606
+ const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
3607
+ const files = listHistoryFiles(dir);
3608
+ for (const file2 of files) {
3609
+ const stat4 = fs3.statSync(path7.join(dir, file2));
3610
+ if (stat4.mtimeMs > indexStat.mtimeMs) return true;
3611
+ }
3612
+ return false;
3613
+ } catch {
3614
+ return true;
3615
+ }
3616
+ }
3617
+ function buildSavedHistoryFileSignature(dir, file2) {
3618
+ try {
3619
+ const stat4 = fs3.statSync(path7.join(dir, file2));
3620
+ return `${file2}:${stat4.size}:${Math.trunc(stat4.mtimeMs)}`;
3621
+ } catch {
3622
+ return `${file2}:missing`;
3420
3623
  }
3421
- summaries.sort((a, b) => b.lastMessageAt - a.lastMessageAt);
3422
- return summaries;
3624
+ }
3625
+ function persistSavedHistoryFileSummaryEntry(agentType, dir, file2, updater) {
3626
+ const filePath = path7.join(dir, file2);
3627
+ const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
3628
+ const currentEntry = entries.get(file2) || null;
3629
+ const nextSummary = updater(currentEntry?.summary || null);
3630
+ const nextEntry = {
3631
+ signature: buildSavedHistoryFileSignature(dir, file2),
3632
+ summary: nextSummary
3633
+ };
3634
+ entries.set(file2, nextEntry);
3635
+ savedHistoryFileSummaryCache.set(filePath, nextEntry);
3636
+ return nextEntry;
3637
+ });
3638
+ if (!result) return;
3639
+ if (result.summary?.historySessionId && shouldScheduleSavedHistoryRollupForSignature(result.signature)) {
3640
+ scheduleSavedHistoryRollup(agentType, result.summary.historySessionId);
3641
+ }
3642
+ }
3643
+ function updateSavedHistoryIndexForSessionStart(agentType, dir, file2, historySessionId, workspace) {
3644
+ const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId);
3645
+ const normalizedWorkspace = String(workspace || "").trim();
3646
+ if (!normalizedSessionId || !normalizedWorkspace) return;
3647
+ persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => ({
3648
+ file: file2,
3649
+ historySessionId: normalizedSessionId,
3650
+ messageCount: currentSummary?.messageCount || 0,
3651
+ firstMessageAt: currentSummary?.firstMessageAt || 0,
3652
+ lastMessageAt: currentSummary?.lastMessageAt || 0,
3653
+ sessionTitle: currentSummary?.sessionTitle,
3654
+ preview: currentSummary?.preview,
3655
+ workspace: normalizedWorkspace
3656
+ }));
3657
+ }
3658
+ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file2, historySessionId, messages) {
3659
+ const normalizedSessionId = normalizeSavedHistorySessionId(agentType, historySessionId || "");
3660
+ if (!normalizedSessionId || messages.length === 0) return;
3661
+ persistSavedHistoryFileSummaryEntry(agentType, dir, file2, (currentSummary) => {
3662
+ const nextSummary = {
3663
+ file: file2,
3664
+ historySessionId: normalizedSessionId,
3665
+ messageCount: currentSummary?.messageCount || 0,
3666
+ firstMessageAt: currentSummary?.firstMessageAt || 0,
3667
+ lastMessageAt: currentSummary?.lastMessageAt || 0,
3668
+ sessionTitle: currentSummary?.sessionTitle,
3669
+ preview: currentSummary?.preview,
3670
+ workspace: currentSummary?.workspace
3671
+ };
3672
+ for (const message of messages) {
3673
+ if (!message || message.historySessionId !== historySessionId) continue;
3674
+ if (message.kind === "session_start") {
3675
+ if (message.workspace) nextSummary.workspace = message.workspace;
3676
+ continue;
3677
+ }
3678
+ nextSummary.messageCount += 1;
3679
+ if (!nextSummary.firstMessageAt || message.receivedAt < nextSummary.firstMessageAt) {
3680
+ nextSummary.firstMessageAt = message.receivedAt;
3681
+ }
3682
+ if (!nextSummary.lastMessageAt || message.receivedAt >= nextSummary.lastMessageAt) {
3683
+ nextSummary.lastMessageAt = message.receivedAt;
3684
+ if (message.sessionTitle) nextSummary.sessionTitle = message.sessionTitle;
3685
+ if (message.role !== "system" && message.content.trim()) nextSummary.preview = message.content.trim();
3686
+ } else if (message.sessionTitle) {
3687
+ nextSummary.sessionTitle = message.sessionTitle;
3688
+ }
3689
+ if (!nextSummary.preview && message.role !== "system" && message.content.trim()) {
3690
+ nextSummary.preview = message.content.trim();
3691
+ }
3692
+ }
3693
+ return nextSummary;
3694
+ });
3695
+ }
3696
+ function computeSavedHistoryFileSummary(agentType, dir, file2) {
3697
+ const historySessionId = extractSavedHistorySessionIdFromFile(agentType, file2);
3698
+ if (!historySessionId) return null;
3699
+ const filePath = path7.join(dir, file2);
3700
+ const content = fs3.readFileSync(filePath, "utf-8");
3701
+ const lines = content.split("\n").filter(Boolean);
3702
+ let messageCount = 0;
3703
+ let firstMessageAt = 0;
3704
+ let lastMessageAt = 0;
3705
+ let sessionTitle = "";
3706
+ let preview = "";
3707
+ let workspace = "";
3708
+ for (const line of lines) {
3709
+ let parsed = null;
3710
+ try {
3711
+ parsed = JSON.parse(line);
3712
+ } catch {
3713
+ parsed = null;
3714
+ }
3715
+ if (!parsed || parsed.historySessionId !== historySessionId) continue;
3716
+ if (parsed.kind === "session_start") {
3717
+ if (!workspace && parsed.workspace) workspace = parsed.workspace;
3718
+ continue;
3719
+ }
3720
+ messageCount += 1;
3721
+ if (!firstMessageAt || parsed.receivedAt < firstMessageAt) firstMessageAt = parsed.receivedAt;
3722
+ if (!lastMessageAt || parsed.receivedAt > lastMessageAt) lastMessageAt = parsed.receivedAt;
3723
+ if (parsed.sessionTitle) sessionTitle = parsed.sessionTitle;
3724
+ if (parsed.role !== "system" && parsed.content.trim()) preview = parsed.content.trim();
3725
+ }
3726
+ if (messageCount === 0 || !lastMessageAt) return null;
3727
+ return {
3728
+ file: file2,
3729
+ historySessionId,
3730
+ messageCount,
3731
+ firstMessageAt,
3732
+ lastMessageAt,
3733
+ sessionTitle: sessionTitle || void 0,
3734
+ preview: preview || void 0,
3735
+ workspace: workspace || void 0
3736
+ };
3737
+ }
3738
+ function shouldScheduleSavedHistoryRollupForSignature(signature) {
3739
+ const parts = String(signature || "").split(":");
3740
+ const size = Number(parts[1] || 0);
3741
+ return shouldScheduleSavedHistoryRollup(size);
3742
+ }
3743
+ function scheduleSavedHistoryRollup(agentType, historySessionId) {
3744
+ const key = `${agentType}:${historySessionId}`;
3745
+ if (!historySessionId || savedHistoryRollupInFlight.has(key)) return;
3746
+ savedHistoryRollupInFlight.add(key);
3747
+ setTimeout(() => {
3748
+ try {
3749
+ new ChatHistoryWriter().compactHistorySession(agentType, historySessionId);
3750
+ } finally {
3751
+ savedHistoryRollupInFlight.delete(key);
3752
+ }
3753
+ }, 0);
3754
+ }
3755
+ function scheduleSavedHistoryBackgroundRefresh(agentType, dir) {
3756
+ const key = `${agentType}:${dir}`;
3757
+ if (savedHistoryBackgroundRefresh.has(key)) return;
3758
+ savedHistoryBackgroundRefresh.add(key);
3759
+ setTimeout(() => {
3760
+ try {
3761
+ if (!fs3.existsSync(dir)) return;
3762
+ const files = listHistoryFiles(dir);
3763
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
3764
+ const persistedEntries = loadPersistedSavedHistoryIndex(dir);
3765
+ const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
3766
+ savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
3767
+ const refreshedIndexSignature = buildSavedHistoryIndexFileSignature(dir);
3768
+ savedHistorySessionCache.set(agentType.replace(/[^a-zA-Z0-9_-]/g, "_"), {
3769
+ signature: refreshedIndexSignature,
3770
+ summaries: computed.summaries || []
3771
+ });
3772
+ for (const [file2, entry] of Array.from(computed.persistedEntries.entries())) {
3773
+ if (!entry?.summary || !shouldScheduleSavedHistoryRollupForSignature(entry.signature)) continue;
3774
+ scheduleSavedHistoryRollup(agentType, entry.summary.historySessionId);
3775
+ }
3776
+ } catch {
3777
+ } finally {
3778
+ savedHistoryBackgroundRefresh.delete(key);
3779
+ }
3780
+ }, 0);
3781
+ }
3782
+ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries) {
3783
+ const summaryBySessionId = /* @__PURE__ */ new Map();
3784
+ const nextPersistedEntries = /* @__PURE__ */ new Map();
3785
+ for (const file2 of files.slice().sort()) {
3786
+ const filePath = path7.join(dir, file2);
3787
+ const signature = fileSignatures.get(file2) || `${file2}:missing`;
3788
+ const cached2 = savedHistoryFileSummaryCache.get(filePath);
3789
+ const persisted = persistedEntries.get(file2);
3790
+ const reusableEntry = cached2?.signature === signature ? cached2 : persisted?.signature === signature ? persisted : null;
3791
+ const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(agentType, dir, file2);
3792
+ const nextEntry = reusableEntry || {
3793
+ signature,
3794
+ summary: fileSummary
3795
+ };
3796
+ if (!reusableEntry) {
3797
+ nextEntry.signature = signature;
3798
+ nextEntry.summary = fileSummary;
3799
+ }
3800
+ savedHistoryFileSummaryCache.set(filePath, nextEntry);
3801
+ nextPersistedEntries.set(file2, nextEntry);
3802
+ if (!fileSummary) continue;
3803
+ const existing = summaryBySessionId.get(fileSummary.historySessionId);
3804
+ if (fileSummary.messageCount <= 0 || !fileSummary.lastMessageAt) {
3805
+ continue;
3806
+ }
3807
+ if (!existing) {
3808
+ summaryBySessionId.set(fileSummary.historySessionId, {
3809
+ historySessionId: fileSummary.historySessionId,
3810
+ sessionTitle: fileSummary.sessionTitle,
3811
+ messageCount: fileSummary.messageCount,
3812
+ firstMessageAt: fileSummary.firstMessageAt,
3813
+ lastMessageAt: fileSummary.lastMessageAt,
3814
+ preview: fileSummary.preview,
3815
+ workspace: fileSummary.workspace
3816
+ });
3817
+ continue;
3818
+ }
3819
+ existing.messageCount += fileSummary.messageCount;
3820
+ if (!existing.firstMessageAt || fileSummary.firstMessageAt < existing.firstMessageAt) {
3821
+ existing.firstMessageAt = fileSummary.firstMessageAt;
3822
+ }
3823
+ if (fileSummary.lastMessageAt >= existing.lastMessageAt) {
3824
+ existing.lastMessageAt = fileSummary.lastMessageAt;
3825
+ if (fileSummary.sessionTitle) existing.sessionTitle = fileSummary.sessionTitle;
3826
+ if (fileSummary.preview) existing.preview = fileSummary.preview;
3827
+ }
3828
+ if (!existing.workspace && fileSummary.workspace) {
3829
+ existing.workspace = fileSummary.workspace;
3830
+ }
3831
+ }
3832
+ return {
3833
+ summaries: Array.from(summaryBySessionId.values()).sort((a, b) => b.lastMessageAt - a.lastMessageAt),
3834
+ persistedEntries: nextPersistedEntries
3835
+ };
3423
3836
  }
3424
3837
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0) {
3425
3838
  try {
@@ -3477,18 +3890,51 @@ function listSavedHistorySessions(agentType, options = {}) {
3477
3890
  savedHistorySessionCache.delete(sanitized);
3478
3891
  return { sessions: [], hasMore: false };
3479
3892
  }
3480
- const files = listHistoryFiles(dir);
3481
- const signature = buildSavedHistoryCacheSignature(dir, files);
3482
3893
  const cached2 = savedHistorySessionCache.get(sanitized);
3483
- const summaries = cached2?.signature === signature ? cached2.summaries : computeSavedHistorySessionSummaries(agentType, dir, files);
3484
- if (!cached2 || cached2.signature !== signature) {
3894
+ const offset = Math.max(0, options.offset || 0);
3895
+ const limit = Math.max(1, options.limit || 30);
3896
+ const indexSignature = buildSavedHistoryIndexFileSignature(dir);
3897
+ let cacheWasInvalidated = false;
3898
+ if (cached2) {
3899
+ const cacheLooksPersisted = cached2.signature.startsWith("index:");
3900
+ const cacheStillValid = cacheLooksPersisted ? cached2.signature === indexSignature : (() => {
3901
+ const files2 = listHistoryFiles(dir);
3902
+ const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
3903
+ return cached2.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
3904
+ })();
3905
+ if (cacheStillValid) {
3906
+ const sliced2 = cached2.summaries.slice(offset, offset + limit);
3907
+ return {
3908
+ sessions: sliced2,
3909
+ hasMore: cached2.summaries.length > offset + limit
3910
+ };
3911
+ }
3912
+ cacheWasInvalidated = true;
3913
+ }
3914
+ const persistedSessions = readPersistedSavedHistorySessionSummaries(dir);
3915
+ if (!cacheWasInvalidated && persistedSessions?.length && !historyDirectoryHasFilesNewerThanIndex(dir)) {
3485
3916
  savedHistorySessionCache.set(sanitized, {
3486
- signature,
3487
- summaries
3917
+ signature: indexSignature,
3918
+ summaries: persistedSessions
3488
3919
  });
3920
+ scheduleSavedHistoryBackgroundRefresh(agentType, dir);
3921
+ const sliced2 = persistedSessions.slice(offset, offset + limit);
3922
+ return {
3923
+ sessions: sliced2,
3924
+ hasMore: persistedSessions.length > offset + limit
3925
+ };
3489
3926
  }
3490
- const offset = Math.max(0, options.offset || 0);
3491
- const limit = Math.max(1, options.limit || 30);
3927
+ const files = listHistoryFiles(dir);
3928
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
3929
+ const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
3930
+ const persistedEntries = loadPersistedSavedHistoryIndex(dir);
3931
+ const computed = computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatures, persistedEntries);
3932
+ const summaries = computed.summaries || [];
3933
+ savePersistedSavedHistoryIndex(dir, computed.persistedEntries || /* @__PURE__ */ new Map());
3934
+ savedHistorySessionCache.set(sanitized, {
3935
+ signature,
3936
+ summaries
3937
+ });
3492
3938
  const sliced = summaries.slice(offset, offset + limit);
3493
3939
  return {
3494
3940
  sessions: sliced,
@@ -3498,7 +3944,7 @@ function listSavedHistorySessions(agentType, options = {}) {
3498
3944
  return { sessions: [], hasMore: false };
3499
3945
  }
3500
3946
  }
3501
- var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, savedHistorySessionCache, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
3947
+ var fs3, path7, os5, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, CODEX_STARTER_PROMPT_RE, ChatHistoryWriter;
3502
3948
  var init_chat_history = __esm({
3503
3949
  "../../oss/packages/daemon-core/src/config/chat-history.ts"() {
3504
3950
  "use strict";
@@ -3506,9 +3952,20 @@ var init_chat_history = __esm({
3506
3952
  path7 = __toESM(require("path"));
3507
3953
  os5 = __toESM(require("os"));
3508
3954
  init_chat_message_normalization();
3955
+ init_provider_session_id();
3509
3956
  HISTORY_DIR = path7.join(os5.homedir(), ".adhdev", "history");
3510
3957
  RETAIN_DAYS = 30;
3958
+ SAVED_HISTORY_INDEX_VERSION = 1;
3959
+ SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
3960
+ SAVED_HISTORY_INDEX_LOCK_SUFFIX = ".lock";
3961
+ SAVED_HISTORY_INDEX_LOCK_WAIT_MS = 1500;
3962
+ SAVED_HISTORY_INDEX_LOCK_STALE_MS = 15e3;
3963
+ SAVED_HISTORY_INDEX_LOCK_POLL_MS = 25;
3964
+ SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES = 16 * 1024 * 1024;
3511
3965
  savedHistorySessionCache = /* @__PURE__ */ new Map();
3966
+ savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
3967
+ savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
3968
+ savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
3512
3969
  CODEX_STARTER_PROMPT_RE = /^(?:[›❯]\s*)?(?:Find and fix a bug in @filename|Improve documentation in @filename|Write tests for @filename|Explain this codebase|Summarize recent commits|Implement \{feature\}|Use \/skills(?: to list available skills)?|Run \/review on my current changes)$/i;
3513
3970
  ChatHistoryWriter = class {
3514
3971
  /** Last seen message count per agent (deduplication) */
@@ -3583,9 +4040,11 @@ var init_chat_history = __esm({
3583
4040
  fs3.mkdirSync(dir, { recursive: true });
3584
4041
  const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3585
4042
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
3586
- const filePath = path7.join(dir, `${filePrefix}${date5}.jsonl`);
4043
+ const fileName = `${filePrefix}${date5}.jsonl`;
4044
+ const filePath = path7.join(dir, fileName);
3587
4045
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
3588
4046
  fs3.appendFileSync(filePath, lines, "utf-8");
4047
+ updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
3589
4048
  const prevCount = this.lastSeenCounts.get(dedupKey) || 0;
3590
4049
  if (!historySessionId && messages.length < prevCount * 0.5 && prevCount > 3) {
3591
4050
  seenHashes.clear();
@@ -3676,7 +4135,8 @@ var init_chat_history = __esm({
3676
4135
  const dir = path7.join(HISTORY_DIR, this.sanitize(agentType));
3677
4136
  fs3.mkdirSync(dir, { recursive: true });
3678
4137
  const date5 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3679
- const filePath = path7.join(dir, `${this.sanitize(id)}_${date5}.jsonl`);
4138
+ const fileName = `${this.sanitize(id)}_${date5}.jsonl`;
4139
+ const filePath = path7.join(dir, fileName);
3680
4140
  const record2 = {
3681
4141
  ts: (/* @__PURE__ */ new Date()).toISOString(),
3682
4142
  receivedAt: Date.now(),
@@ -3689,6 +4149,7 @@ var init_chat_history = __esm({
3689
4149
  workspace: ws
3690
4150
  };
3691
4151
  fs3.appendFileSync(filePath, JSON.stringify(record2) + "\n", "utf-8");
4152
+ updateSavedHistoryIndexForSessionStart(agentType, dir, fileName, id, ws);
3692
4153
  } catch {
3693
4154
  }
3694
4155
  }
@@ -3754,6 +4215,7 @@ var init_chat_history = __esm({
3754
4215
  }
3755
4216
  fs3.unlinkSync(sourcePath);
3756
4217
  }
4218
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
3757
4219
  } catch {
3758
4220
  }
3759
4221
  }
@@ -3803,6 +4265,7 @@ var init_chat_history = __esm({
3803
4265
  fs3.writeFileSync(filePath, `${collapsed.map((entry) => JSON.stringify(entry)).join("\n")}
3804
4266
  `, "utf-8");
3805
4267
  }
4268
+ invalidatePersistedSavedHistoryIndex(agentType, dir);
3806
4269
  } catch {
3807
4270
  }
3808
4271
  }
@@ -3822,13 +4285,18 @@ var init_chat_history = __esm({
3822
4285
  for (const dir of agentDirs) {
3823
4286
  const dirPath = path7.join(HISTORY_DIR, dir.name);
3824
4287
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
4288
+ let removedAny = false;
3825
4289
  for (const file2 of files) {
3826
4290
  const filePath = path7.join(dirPath, file2);
3827
4291
  const stat4 = fs3.statSync(filePath);
3828
4292
  if (stat4.mtimeMs < cutoff) {
3829
4293
  fs3.unlinkSync(filePath);
4294
+ removedAny = true;
3830
4295
  }
3831
4296
  }
4297
+ if (removedAny) {
4298
+ invalidatePersistedSavedHistoryIndex(dir.name, dirPath);
4299
+ }
3832
4300
  }
3833
4301
  } catch {
3834
4302
  }
@@ -5755,6 +6223,21 @@ function buildExtensionAgentSession(parent, ext, options) {
5755
6223
  lastUpdated: ext.lastUpdated
5756
6224
  };
5757
6225
  }
6226
+ function shouldIncludeExtensionSession(ext) {
6227
+ const status = String(ext.status || "").trim().toLowerCase();
6228
+ const hasActiveChat = !!ext.activeChat;
6229
+ const hasMessages = Array.isArray(ext.activeChat?.messages) && ext.activeChat.messages.length > 0;
6230
+ const hasModal = !!ext.activeChat?.activeModal;
6231
+ const hasStreams = Array.isArray(ext.agentStreams) && ext.agentStreams.length > 0;
6232
+ const hasProviderSessionId = typeof ext.providerSessionId === "string" && ext.providerSessionId.trim().length > 0;
6233
+ const hasControlValues = !!(ext.controlValues && Object.keys(ext.controlValues).length > 0);
6234
+ const hasProviderControls = Array.isArray(ext.providerControls) && ext.providerControls.length > 0;
6235
+ const hasOpenPanelCapability = Array.isArray(ext.sessionCapabilities) && ext.sessionCapabilities.includes("open_panel");
6236
+ const hasSummaryMetadata = !!ext.summaryMetadata;
6237
+ const hasError = typeof ext.errorMessage === "string" && ext.errorMessage.trim().length > 0;
6238
+ const hasInterestingStatus = !!status && !["idle", "panel_hidden", "disconnected", "not_monitored"].includes(status);
6239
+ return hasActiveChat || hasMessages || hasModal || hasStreams || hasProviderSessionId || hasControlValues || hasProviderControls || hasOpenPanelCapability || hasSummaryMetadata || hasError || hasInterestingStatus;
6240
+ }
5758
6241
  function buildCliSession(state, options) {
5759
6242
  const profile = options.profile || "full";
5760
6243
  const activeChat = normalizeActiveChatData(state.activeChat, getActiveChatOptions(profile));
@@ -5838,6 +6321,7 @@ function buildSessionEntries(allStates, cdpManagers, options = {}) {
5838
6321
  for (const state of ideStates) {
5839
6322
  sessions.push(buildIdeWorkspaceSession(state, cdpManagers, options));
5840
6323
  for (const ext of state.extensions) {
6324
+ if (!shouldIncludeExtensionSession(ext)) continue;
5841
6325
  sessions.push(buildExtensionAgentSession(state, ext, options));
5842
6326
  }
5843
6327
  }
@@ -8090,7 +8574,9 @@ function applyProviderPatch(h, args, payload) {
8090
8574
  });
8091
8575
  }
8092
8576
  async function executeProviderScript(h, args, scriptName) {
8093
- const resolvedProviderType = h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
8577
+ const explicitTargetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
8578
+ const targetSession = explicitTargetSessionId ? h.ctx.sessionRegistry?.get(explicitTargetSessionId) : void 0;
8579
+ const resolvedProviderType = targetSession?.providerType || h.currentSession?.providerType || h.currentProviderType || args?.agentType || args?.providerType;
8094
8580
  if (!resolvedProviderType) return { success: false, error: "targetSessionId or providerType is required" };
8095
8581
  const loader = h.ctx.providerLoader;
8096
8582
  if (!loader) return { success: false, error: "ProviderLoader not initialized" };
@@ -8133,16 +8619,16 @@ async function executeProviderScript(h, args, scriptName) {
8133
8619
  const scriptFn = provider.scripts[actualScriptName];
8134
8620
  const scriptCode = scriptFn(normalizedArgs);
8135
8621
  if (!scriptCode) return { success: false, error: `Script '${actualScriptName}' returned null` };
8136
- const cdpKey = provider.category === "ide" ? h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : h.currentSession?.cdpManagerKey || h.currentManagerKey;
8622
+ const cdpKey = provider.category === "ide" ? targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey || resolvedProviderType : targetSession?.cdpManagerKey || h.currentSession?.cdpManagerKey || h.currentManagerKey;
8137
8623
  LOG.info("Command", `[ExtScript] provider=${provider.type} category=${provider.category} cdpKey=${cdpKey}`);
8138
8624
  const cdp = h.getCdp(cdpKey);
8139
8625
  if (!cdp?.isConnected) return { success: false, error: `No CDP connection for ${cdpKey || "any"}` };
8140
8626
  try {
8141
8627
  let result;
8142
8628
  if (provider.category === "extension") {
8143
- const runtimeSessionId = h.currentSession?.sessionId || args?.targetSessionId;
8629
+ const runtimeSessionId = explicitTargetSessionId || h.currentSession?.sessionId;
8144
8630
  if (!runtimeSessionId) return { success: false, error: `No target session found for ${resolvedProviderType}` };
8145
- const parentSessionId = h.currentSession?.parentSessionId;
8631
+ const parentSessionId = targetSession?.parentSessionId || h.currentSession?.parentSessionId;
8146
8632
  if (parentSessionId) {
8147
8633
  await h.agentStream?.setActiveSession(cdp, parentSessionId, runtimeSessionId);
8148
8634
  await h.agentStream?.syncActiveSession(cdp, parentSessionId);
@@ -36582,6 +37068,28 @@ var init_subscription_updates = __esm({
36582
37068
  }
36583
37069
  });
36584
37070
 
37071
+ // ../../oss/packages/daemon-core/src/chat/async-batch.ts
37072
+ async function runAsyncBatch(items, worker, options = {}) {
37073
+ const list = Array.from(items);
37074
+ if (list.length === 0) return;
37075
+ const concurrency = Math.max(1, Math.min(list.length, Math.floor(options.concurrency || 1)));
37076
+ let nextIndex = 0;
37077
+ const runners = Array.from({ length: concurrency }, async () => {
37078
+ while (true) {
37079
+ const currentIndex = nextIndex;
37080
+ nextIndex += 1;
37081
+ if (currentIndex >= list.length) return;
37082
+ await worker(list[currentIndex], currentIndex);
37083
+ }
37084
+ });
37085
+ await Promise.all(runners);
37086
+ }
37087
+ var init_async_batch = __esm({
37088
+ "../../oss/packages/daemon-core/src/chat/async-batch.ts"() {
37089
+ "use strict";
37090
+ }
37091
+ });
37092
+
36585
37093
  // ../../oss/packages/daemon-core/src/agent-stream/provider-adapter.ts
36586
37094
  var ProviderStreamAdapter;
36587
37095
  var init_provider_adapter = __esm({
@@ -37063,10 +37571,12 @@ var init_manager2 = __esm({
37063
37571
  }
37064
37572
  }
37065
37573
  /** Collect active extension session state */
37066
- async collectActiveSession(cdp, parentSessionId) {
37574
+ async collectActiveSession(cdp, parentSessionId, attemptedSessionIds = /* @__PURE__ */ new Set(), originSessionId) {
37067
37575
  if (!this.enabled) return null;
37068
37576
  const activeSessionId = this.getActiveSessionId(parentSessionId);
37069
37577
  if (!activeSessionId) return null;
37578
+ const resolvedOriginSessionId = originSessionId || activeSessionId;
37579
+ attemptedSessionIds.add(activeSessionId);
37070
37580
  let agent = this.managedBySessionId.get(activeSessionId);
37071
37581
  if (!agent) {
37072
37582
  agent = await this.connectManagedSession(cdp, parentSessionId, activeSessionId) || void 0;
@@ -37079,18 +37589,44 @@ var init_manager2 = __esm({
37079
37589
  try {
37080
37590
  const evaluate = (expr, timeout) => cdp.evaluateInSessionFrame(agent.cdpSessionId, expr, timeout);
37081
37591
  const state = await agent.adapter.readChat(evaluate);
37082
- const stateError = this.getStateError(state);
37083
- const selectedModelValue = typeof state.controlValues?.model === "string" ? state.controlValues.model : "";
37084
- LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${state.status} msgs=${state.messages?.length || 0} model=${selectedModelValue}${state.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
37085
- if (state.status === "error" && this.isRecoverableSessionError(stateError)) {
37592
+ 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;
37593
+ const normalizedState = {
37594
+ ...state,
37595
+ sessionId: agent.runtimeSessionId,
37596
+ ...resolvedProviderSessionId ? { providerSessionId: resolvedProviderSessionId } : {}
37597
+ };
37598
+ const stateError = this.getStateError(normalizedState);
37599
+ const selectedModelValue = typeof normalizedState.controlValues?.model === "string" ? normalizedState.controlValues.model : "";
37600
+ LOG.debug("AgentStream", `[AgentStream] readChat(${type}) result: status=${normalizedState.status} msgs=${normalizedState.messages?.length || 0} model=${selectedModelValue}${normalizedState.status === "error" ? " error=" + JSON.stringify(stateError) : ""}`);
37601
+ if (normalizedState.status === "error" && this.isRecoverableSessionError(stateError)) {
37086
37602
  throw new Error(stateError);
37087
37603
  }
37088
- agent.lastState = state;
37604
+ agent.lastState = normalizedState;
37089
37605
  agent.lastError = null;
37090
- if (state.status === "panel_hidden") {
37606
+ if (normalizedState.status === "panel_hidden") {
37607
+ const discovered = await cdp.discoverAgentWebviews().catch(() => []);
37608
+ const fallbackTarget = discovered.find((entry) => {
37609
+ if (entry.agentType === type) return false;
37610
+ const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, entry.agentType);
37611
+ return !!fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId);
37612
+ });
37613
+ if (fallbackTarget) {
37614
+ const fallbackSessionId = this.resolveSessionIdForTarget(parentSessionId, fallbackTarget.agentType);
37615
+ if (fallbackSessionId && fallbackSessionId !== activeSessionId && !attemptedSessionIds.has(fallbackSessionId)) {
37616
+ this.logFn(`[AgentStream] Active session ${type} is hidden; switching to visible agent ${fallbackTarget.agentType} (${parentSessionId})`);
37617
+ await this.setActiveSession(cdp, parentSessionId, fallbackSessionId);
37618
+ await this.syncActiveSession(cdp, parentSessionId);
37619
+ const fallbackState = await this.collectActiveSession(cdp, parentSessionId, attemptedSessionIds, resolvedOriginSessionId);
37620
+ if (fallbackState?.status === "panel_hidden" && resolvedOriginSessionId !== fallbackSessionId) {
37621
+ await this.setActiveSession(cdp, parentSessionId, resolvedOriginSessionId);
37622
+ await this.syncActiveSession(cdp, parentSessionId);
37623
+ }
37624
+ return fallbackState;
37625
+ }
37626
+ }
37091
37627
  agent.lastHiddenCheckTime = Date.now();
37092
37628
  }
37093
- return state;
37629
+ return normalizedState;
37094
37630
  } catch (e) {
37095
37631
  const errorMsg = e?.message || String(e);
37096
37632
  this.logFn(`[AgentStream] readChat(${type}) error: ${errorMsg.slice(0, 200)}`);
@@ -37402,6 +37938,7 @@ var init_poller = __esm({
37402
37938
  try {
37403
37939
  await agentStreamManager.syncActiveSession(cdp, parentSessionId);
37404
37940
  let stream = await agentStreamManager.collectActiveSession(cdp, parentSessionId);
37941
+ resolvedActiveSessionId = stream?.sessionId || agentStreamManager.getActiveSessionId(parentSessionId) || resolvedActiveSessionId;
37405
37942
  if (stream?.status === "waiting_approval") {
37406
37943
  const autoApprove = providerLoader.getSettings(stream.agentType).autoApprove !== false;
37407
37944
  if (autoApprove && resolvedActiveSessionId) {
@@ -44221,6 +44758,7 @@ __export(src_exports, {
44221
44758
  resolveChatMessageKind: () => resolveChatMessageKind,
44222
44759
  resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
44223
44760
  resolveSessionHostAppName: () => resolveSessionHostAppName,
44761
+ runAsyncBatch: () => runAsyncBatch,
44224
44762
  saveConfig: () => saveConfig,
44225
44763
  saveState: () => saveState,
44226
44764
  setDebugRuntimeConfig: () => setDebugRuntimeConfig,
@@ -44268,6 +44806,7 @@ var init_src = __esm({
44268
44806
  init_chat_history();
44269
44807
  init_chat_signatures();
44270
44808
  init_subscription_updates();
44809
+ init_async_batch();
44271
44810
  init_agent_stream();
44272
44811
  init_agent_stream();
44273
44812
  init_forward();
@@ -45356,6 +45895,7 @@ var init_daemon_p2p = __esm({
45356
45895
  fs15 = __toESM(require("fs"));
45357
45896
  path23 = __toESM(require("path"));
45358
45897
  import_node_module2 = require("module");
45898
+ init_src();
45359
45899
  init_data_channel_router();
45360
45900
  init_screenshot_sender();
45361
45901
  init_peer_connection_manager();
@@ -45605,14 +46145,22 @@ ${e?.stack || ""}`);
45605
46145
  return false;
45606
46146
  }
45607
46147
  async flushChatSubscriptions(builder) {
46148
+ const tasks = [];
45608
46149
  for (const peer of this.peers.values()) {
45609
46150
  if (peer.state !== "connected" || !peer.chatSubscriptions || peer.chatSubscriptions.size === 0) continue;
45610
46151
  for (const subscription of peer.chatSubscriptions.values()) {
46152
+ tasks.push({ peer, subscription });
46153
+ }
46154
+ }
46155
+ await runAsyncBatch(tasks, async ({ peer, subscription }) => {
46156
+ try {
45611
46157
  const update = await builder(subscription);
45612
- if (!update) continue;
46158
+ if (!update) return;
45613
46159
  this.screenshotSender.sendTopicUpdateToPeer(peer, update);
46160
+ } catch (error48) {
46161
+ log(`chat_tail flush skipped: peer=${peer.peerId} session=${subscription.params.targetSessionId} error=${error48?.message || error48}`);
45614
46162
  }
45615
- }
46163
+ }, { concurrency: 4 });
45616
46164
  }
45617
46165
  async flushMachineRuntimeSubscriptions(builder) {
45618
46166
  for (const peer of this.peers.values()) {
@@ -53563,7 +54111,7 @@ var init_adhdev_daemon = __esm({
53563
54111
  init_source2();
53564
54112
  init_version();
53565
54113
  init_src();
53566
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.75" });
54114
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.8.76" });
53567
54115
  AdhdevDaemon = class _AdhdevDaemon {
53568
54116
  localHttpServer = null;
53569
54117
  localWss = null;
@@ -53977,7 +54525,7 @@ ${err?.stack || ""}`);
53977
54525
  }),
53978
54526
  onStatusChange: () => {
53979
54527
  this.statusReporter?.onStatusChange();
53980
- void this.flushP2PChatSubscriptions({ onlyActive: false });
54528
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
53981
54529
  },
53982
54530
  removeAgentTracking: (key) => this.statusReporter?.removeAgentTracking(key),
53983
54531
  hostedRuntimeManagerTag: "adhdev-cloud",
@@ -54006,7 +54554,7 @@ ${err?.stack || ""}`);
54006
54554
  statusVersion: pkgVersion,
54007
54555
  onStatusChange: () => {
54008
54556
  this.statusReporter?.onStatusChange();
54009
- void this.flushP2PChatSubscriptions({ onlyActive: false });
54557
+ void this.flushP2PChatSubscriptions({ onlyActive: true });
54010
54558
  },
54011
54559
  onPostChatCommand: () => {
54012
54560
  setTimeout(() => this.statusReporter?.throttledReport(), 1e3);