@tutti-os/agent-gui 0.0.14 → 0.0.16

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.
Files changed (69) hide show
  1. package/dist/AgentMentionSearchController-DqssJ2-b.d.ts +218 -0
  2. package/dist/agent-conversation/index.d.ts +4 -2
  3. package/dist/agent-conversation/index.js +5 -4
  4. package/dist/agent-conversation/index.js.map +1 -1
  5. package/dist/agent-message-center/index.d.ts +3 -2
  6. package/dist/agent-message-center/index.js +547 -287
  7. package/dist/agent-message-center/index.js.map +1 -1
  8. package/dist/app/renderer/agentactivity.css +177 -17
  9. package/dist/{chunk-GZHQPPK2.js → chunk-267VY3EJ.js} +130 -43
  10. package/dist/chunk-267VY3EJ.js.map +1 -0
  11. package/dist/{chunk-KEKPOVQD.js → chunk-CABHBFYH.js} +2 -2
  12. package/dist/{chunk-HSXDSFKB.js → chunk-EKATXC3W.js} +2 -2
  13. package/dist/{chunk-RLPVFX7V.js → chunk-FJYH2ZPX.js} +196 -322
  14. package/dist/chunk-FJYH2ZPX.js.map +1 -0
  15. package/dist/{chunk-ASAZDEQE.js → chunk-GWR6WGZY.js} +72 -22
  16. package/dist/chunk-GWR6WGZY.js.map +1 -0
  17. package/dist/{chunk-YXSO4ITT.js → chunk-HIREVEZM.js} +1 -1
  18. package/dist/chunk-HIREVEZM.js.map +1 -0
  19. package/dist/{chunk-VDNMTW2E.js → chunk-IXIGWLQY.js} +1 -1
  20. package/dist/chunk-IXIGWLQY.js.map +1 -0
  21. package/dist/{chunk-ZO3SZCIX.js → chunk-JNGYJ7GM.js} +6 -3
  22. package/dist/chunk-JNGYJ7GM.js.map +1 -0
  23. package/dist/{chunk-MU2LODEV.js → chunk-KWPL3JYS.js} +131 -13
  24. package/dist/chunk-KWPL3JYS.js.map +1 -0
  25. package/dist/{chunk-WME2V26J.js → chunk-LW2S255I.js} +21 -36
  26. package/dist/chunk-LW2S255I.js.map +1 -0
  27. package/dist/{chunk-3YZX5EUC.js → chunk-LWRYYGPZ.js} +610 -480
  28. package/dist/chunk-LWRYYGPZ.js.map +1 -0
  29. package/dist/{chunk-GEXHKJK5.js → chunk-MUZMBEFO.js} +35 -17
  30. package/dist/chunk-MUZMBEFO.js.map +1 -0
  31. package/dist/chunk-O5TUTXHT.js +196 -0
  32. package/dist/chunk-O5TUTXHT.js.map +1 -0
  33. package/dist/{chunk-FSTZDNRM.js → chunk-SIDWRR5I.js} +281 -183
  34. package/dist/chunk-SIDWRR5I.js.map +1 -0
  35. package/dist/context-mention-palette/index.d.ts +11 -170
  36. package/dist/context-mention-palette/index.js +7 -6
  37. package/dist/context-mention-provider.d.ts +6 -1
  38. package/dist/context-mention-provider.js +1 -1
  39. package/dist/i18n/index.d.ts +277 -179
  40. package/dist/i18n/index.js +1 -1
  41. package/dist/index.d.ts +56 -3
  42. package/dist/index.js +2706 -1700
  43. package/dist/index.js.map +1 -1
  44. package/dist/workbench/contribution.d.ts +7 -1
  45. package/dist/workbench/contribution.js +6 -4
  46. package/dist/workbench/index.d.ts +5 -2
  47. package/dist/workbench/index.js +6 -4
  48. package/dist/workbench/launch.d.ts +2 -0
  49. package/dist/workbench/launch.js +2 -2
  50. package/dist/workbench/state.d.ts +3 -2
  51. package/dist/workbench/state.js +1 -1
  52. package/dist/workbench/types.d.ts +3 -0
  53. package/dist/workbench/types.js +1 -1
  54. package/dist/workspace-agent-generated-files.js +2 -2
  55. package/dist/{workspaceLinkActions-BlLN8Pvz.d.ts → workspaceLinkActions-Mjktl_Be.d.ts} +3 -0
  56. package/package.json +15 -13
  57. package/dist/chunk-3YZX5EUC.js.map +0 -1
  58. package/dist/chunk-ASAZDEQE.js.map +0 -1
  59. package/dist/chunk-FSTZDNRM.js.map +0 -1
  60. package/dist/chunk-GEXHKJK5.js.map +0 -1
  61. package/dist/chunk-GZHQPPK2.js.map +0 -1
  62. package/dist/chunk-MU2LODEV.js.map +0 -1
  63. package/dist/chunk-RLPVFX7V.js.map +0 -1
  64. package/dist/chunk-VDNMTW2E.js.map +0 -1
  65. package/dist/chunk-WME2V26J.js.map +0 -1
  66. package/dist/chunk-YXSO4ITT.js.map +0 -1
  67. package/dist/chunk-ZO3SZCIX.js.map +0 -1
  68. /package/dist/{chunk-KEKPOVQD.js.map → chunk-CABHBFYH.js.map} +0 -0
  69. /package/dist/{chunk-HSXDSFKB.js.map → chunk-EKATXC3W.js.map} +0 -0
@@ -3,20 +3,23 @@ import {
3
3
  managedAgentRoundedIconUrl,
4
4
  userAvatarPlaceholderUrl,
5
5
  workspaceAgentActivityStatusLabel
6
- } from "./chunk-HSXDSFKB.js";
6
+ } from "./chunk-EKATXC3W.js";
7
7
  import {
8
8
  buildAgentGenericMentionHref,
9
9
  buildAgentSessionMentionHref,
10
10
  buildAgentWorkspaceAppMentionHref,
11
11
  buildAgentWorkspaceIssueMentionHref,
12
12
  normalizeAgentSessionMentionTitle
13
- } from "./chunk-MU2LODEV.js";
13
+ } from "./chunk-KWPL3JYS.js";
14
+ import {
15
+ getOptionalAgentHostApi
16
+ } from "./chunk-O5TUTXHT.js";
14
17
  import {
15
18
  AGENT_CONTEXT_MENTION_PROVIDER_IDS
16
- } from "./chunk-YXSO4ITT.js";
19
+ } from "./chunk-HIREVEZM.js";
17
20
  import {
18
21
  translate
19
- } from "./chunk-FSTZDNRM.js";
22
+ } from "./chunk-SIDWRR5I.js";
20
23
  import {
21
24
  resolveAgentMentionFileThumbnailUrl,
22
25
  resolveAgentMentionFileVisualKind
@@ -305,8 +308,6 @@ function agentMentionGroupLabel(groupId) {
305
308
  }
306
309
  function agentMentionFilterLabel(filter) {
307
310
  switch (filter) {
308
- case "all":
309
- return translate("agentHost.agentGui.mentionFilterAll");
310
311
  case "app":
311
312
  return translate("agentHost.agentGui.mentionFilterApp");
312
313
  case "file":
@@ -338,16 +339,15 @@ function agentMentionEmptyGroupLabel(groupId, query) {
338
339
 
339
340
  // agent-gui/agentGuiNode/agentMentionSearchHelpers.ts
340
341
  var AGENT_MENTION_FILTER_TAB_ORDER = [
341
- "all",
342
342
  "session",
343
343
  "file",
344
344
  "issue",
345
345
  "app"
346
346
  ];
347
- var DEFAULT_MENTION_ALL_TAB_PAGE_SIZE = 5;
347
+ var DEFAULT_AGENT_MENTION_FILTER = "session";
348
348
  var DEFAULT_MENTION_GROUP_PAGE_SIZE = 10;
349
- function mentionGroupPageSize(filter, _groupId) {
350
- return filter === "all" ? DEFAULT_MENTION_ALL_TAB_PAGE_SIZE : DEFAULT_MENTION_GROUP_PAGE_SIZE;
349
+ function mentionGroupPageSize(_filter, _groupId) {
350
+ return DEFAULT_MENTION_GROUP_PAGE_SIZE;
351
351
  }
352
352
  function mentionGroupExpandCount(group, filter) {
353
353
  const pageSize = mentionGroupPageSize(
@@ -367,29 +367,26 @@ function groupIdsForFilter(filter) {
367
367
  return ["my_sessions"];
368
368
  case "issue":
369
369
  return ["issues"];
370
- case "all":
371
- default:
372
- return ["my_sessions", "files", "issues", "apps"];
373
370
  }
374
371
  }
375
372
  function shouldShowEmptyGroup(groupId, filter, query) {
376
373
  const hasQuery = query.trim().length > 0;
377
374
  if (groupId === "files") {
378
- return filter === "all";
375
+ return false;
379
376
  }
380
377
  if (groupId === "opened_files" || groupId === "agent_generated_files") {
381
378
  return filter === "file" && !hasQuery;
382
379
  }
383
380
  if (groupId === "apps") {
384
- return filter === "all" || filter === "app";
381
+ return filter === "app";
385
382
  }
386
383
  if (groupId === "my_sessions") {
387
- return filter === "all" || filter === "session";
384
+ return filter === "session";
388
385
  }
389
386
  if (groupId === "collab_sessions") {
390
387
  return false;
391
388
  }
392
- return filter === "all" || filter === "issue";
389
+ return filter === "issue";
393
390
  }
394
391
  function buildEmptyGroup(groupId, query) {
395
392
  return {
@@ -404,25 +401,6 @@ function buildEmptyGroup(groupId, query) {
404
401
  function emptyGroupLabel(groupId, query) {
405
402
  return agentMentionEmptyGroupLabel(groupId, query);
406
403
  }
407
- function shouldPrefetchBrowseFilter(filter) {
408
- return filter === "all" || filter === "app" || filter === "file" || filter === "session" || filter === "issue";
409
- }
410
- function filterForGroup(groupId) {
411
- switch (groupId) {
412
- case "apps":
413
- return "app";
414
- case "files":
415
- case "opened_files":
416
- case "agent_generated_files":
417
- return "file";
418
- case "my_sessions":
419
- return "session";
420
- case "collab_sessions":
421
- return "session";
422
- case "issues":
423
- return "issue";
424
- }
425
- }
426
404
  function resolveMentionGroupItems(groupId, rawGroups) {
427
405
  if (groupId === "files") {
428
406
  return [...rawGroups.opened_files, ...rawGroups.agent_generated_files];
@@ -452,6 +430,36 @@ var DEFAULT_ISSUE_LIMIT = 25;
452
430
  var DEFAULT_SESSION_LIMIT = 30;
453
431
  var DEFAULT_PROVIDER_TIMEOUT_MS = 3500;
454
432
  var DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS = 250;
433
+ var DEFAULT_BROWSE_CACHE_TTL_MS = 3e4;
434
+ var AGENT_MENTION_LIFECYCLE_LOG_PREFIX = "[agent-gui] mention-lifecycle";
435
+ var sharedAgentMentionBrowseCache = /* @__PURE__ */ new Map();
436
+ var sharedAgentMentionBrowseFetches = /* @__PURE__ */ new Map();
437
+ var MAX_BROWSE_CACHE_ENTRIES = 64;
438
+ function writeBrowseCacheEntry(cacheKey, entry) {
439
+ sharedAgentMentionBrowseCache.delete(cacheKey);
440
+ sharedAgentMentionBrowseCache.set(cacheKey, entry);
441
+ while (sharedAgentMentionBrowseCache.size > MAX_BROWSE_CACHE_ENTRIES) {
442
+ const oldestKey = sharedAgentMentionBrowseCache.keys().next().value;
443
+ if (oldestKey === void 0) {
444
+ break;
445
+ }
446
+ sharedAgentMentionBrowseCache.delete(oldestKey);
447
+ }
448
+ }
449
+ function scheduleIdleTask(task) {
450
+ const scope = globalThis;
451
+ if (typeof scope.requestIdleCallback === "function") {
452
+ const handle2 = scope.requestIdleCallback(() => task(), { timeout: 500 });
453
+ return () => scope.cancelIdleCallback?.(handle2);
454
+ }
455
+ const handle = setTimeout(task, 0);
456
+ return () => clearTimeout(handle);
457
+ }
458
+ function resetAgentMentionSearchBrowseCacheForTests() {
459
+ sharedAgentMentionBrowseCache.clear();
460
+ sharedAgentMentionBrowseFetches.clear();
461
+ }
462
+ globalThis.__tuttiResetAgentMentionSearchBrowseCacheForTests = resetAgentMentionSearchBrowseCacheForTests;
455
463
  function buildBrowseCategories() {
456
464
  return AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({
457
465
  id,
@@ -470,6 +478,7 @@ var AgentMentionSearchController = class {
470
478
  debounceMs;
471
479
  fileLimit;
472
480
  issueLimit;
481
+ browseCacheTtlMs;
473
482
  providerTimeoutMs;
474
483
  diagnosticInfoLogger;
475
484
  diagnosticNow;
@@ -478,29 +487,24 @@ var AgentMentionSearchController = class {
478
487
  expandedCounts = {};
479
488
  totalCounts = {};
480
489
  timer = null;
490
+ preloadCancel = null;
491
+ pendingPreloadKey = null;
481
492
  requestId = 0;
482
493
  disposed = false;
483
494
  activeWorkspaceId = "";
484
495
  currentUserId = "";
485
- currentFilter = "all";
496
+ currentFilter = DEFAULT_AGENT_MENTION_FILTER;
486
497
  currentQuery = "";
487
498
  currentSessionCwd = "";
488
499
  currentFileSearchLimit;
489
500
  currentIssueSearchLimit;
490
501
  agentGeneratedBrowsePath = null;
491
- rawGroups = {
492
- apps: [],
493
- opened_files: [],
494
- agent_generated_files: [],
495
- my_sessions: [],
496
- collab_sessions: [],
497
- issues: []
498
- };
502
+ rawGroups = emptyAgentMentionRawGroups();
499
503
  state = {
500
504
  status: "idle",
501
505
  query: "",
502
506
  mode: "browse",
503
- filter: "all",
507
+ filter: DEFAULT_AGENT_MENTION_FILTER,
504
508
  categories: buildBrowseCategories(),
505
509
  groups: [],
506
510
  error: null
@@ -515,12 +519,17 @@ var AgentMentionSearchController = class {
515
519
  this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
516
520
  this.fileLimit = options.fileLimit ?? DEFAULT_FILE_LIMIT;
517
521
  this.issueLimit = options.issueLimit ?? DEFAULT_ISSUE_LIMIT;
522
+ this.browseCacheTtlMs = options.browseCacheTtlMs ?? DEFAULT_BROWSE_CACHE_TTL_MS;
518
523
  this.providerTimeoutMs = options.providerTimeoutMs ?? DEFAULT_PROVIDER_TIMEOUT_MS;
519
524
  this.diagnosticInfoLogger = options.diagnosticInfoLogger ?? logAgentMentionSearchInfo;
520
525
  this.diagnosticNow = options.diagnosticNow ?? Date.now;
521
526
  this.diagnosticSlowThresholdMs = options.diagnosticSlowThresholdMs ?? DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS;
522
527
  this.currentFileSearchLimit = this.fileLimit;
523
528
  this.currentIssueSearchLimit = this.issueLimit;
529
+ this.logLifecycle("controller.construct", {
530
+ providerIds: this.providerIdsForDiagnostics(),
531
+ providerCount: this.contextMentionProviders.size
532
+ });
524
533
  }
525
534
  subscribe(listener) {
526
535
  this.listeners.add(listener);
@@ -542,6 +551,7 @@ var AgentMentionSearchController = class {
542
551
  this.resetAgentGeneratedBrowsePath();
543
552
  this.resetExpandedCounts();
544
553
  this.resetSearchLimits();
554
+ this.resetRawGroups();
545
555
  if (!this.activeWorkspaceId) {
546
556
  this.setState({
547
557
  status: "idle",
@@ -572,7 +582,8 @@ var AgentMentionSearchController = class {
572
582
  workspaceId: this.activeWorkspaceId,
573
583
  currentUserId: this.currentUserId,
574
584
  query: this.currentQuery,
575
- requestId
585
+ requestId,
586
+ filter: this.currentFilter
576
587
  });
577
588
  }, this.debounceMs);
578
589
  }
@@ -581,14 +592,30 @@ var AgentMentionSearchController = class {
581
592
  return;
582
593
  }
583
594
  this.currentFilter = filter;
595
+ this.clearTimer();
596
+ const requestId = ++this.requestId;
584
597
  this.resetAgentGeneratedBrowsePath();
585
598
  this.resetExpandedCounts();
599
+ this.resetSearchLimits();
600
+ this.resetRawGroups();
586
601
  if (!this.currentQuery) {
587
602
  this.startBrowseModeFetch(filter);
588
603
  return;
589
604
  }
605
+ if (!this.activeWorkspaceId) {
606
+ this.setState({
607
+ status: "ready",
608
+ query: this.currentQuery,
609
+ mode: "results",
610
+ filter: this.currentFilter,
611
+ categories: buildBrowseCategories(),
612
+ groups: [],
613
+ error: null
614
+ });
615
+ return;
616
+ }
590
617
  this.setState({
591
- status: "ready",
618
+ status: "loading",
592
619
  query: this.currentQuery,
593
620
  mode: "results",
594
621
  filter: this.currentFilter,
@@ -596,39 +623,101 @@ var AgentMentionSearchController = class {
596
623
  groups: this.groupsFromRawGroups(),
597
624
  error: null
598
625
  });
626
+ void this.runSearch({
627
+ workspaceId: this.activeWorkspaceId,
628
+ currentUserId: this.currentUserId,
629
+ query: this.currentQuery,
630
+ requestId,
631
+ filter
632
+ });
599
633
  }
600
- enterCategory(category) {
634
+ preloadBrowse(input) {
601
635
  if (this.disposed) {
602
636
  return;
603
637
  }
604
- this.currentFilter = category;
605
- this.resetExpandedCounts();
606
- this.clearTimer();
607
- if (!this.currentQuery) {
608
- this.startBrowseModeFetch(category);
638
+ const workspaceId = input.workspaceId.trim();
639
+ if (!workspaceId) {
609
640
  return;
610
641
  }
611
- if (!this.activeWorkspaceId) {
612
- this.emitBrowseState("ready");
642
+ const filter = input.filter ?? DEFAULT_AGENT_MENTION_FILTER;
643
+ const currentUserId = input.currentUserId?.trim() ?? "";
644
+ const sessionCwd = input.sessionCwd?.trim() ?? "";
645
+ const cacheKey = this.browseCacheKey({
646
+ currentUserId,
647
+ filter,
648
+ sessionCwd,
649
+ workspaceId
650
+ });
651
+ if (this.readBrowseCache(cacheKey).isFresh) {
613
652
  return;
614
653
  }
615
- const requestId = ++this.requestId;
616
- this.setState({
617
- status: "loading",
618
- query: this.currentQuery,
619
- mode: "results",
620
- filter: this.currentFilter,
621
- categories: buildBrowseCategories(),
622
- groups: this.groupsFromRawGroups(),
623
- error: null
654
+ if (this.pendingPreloadKey === cacheKey) {
655
+ return;
656
+ }
657
+ this.cancelPendingPreload();
658
+ this.pendingPreloadKey = cacheKey;
659
+ this.preloadCancel = scheduleIdleTask(() => {
660
+ this.preloadCancel = null;
661
+ this.pendingPreloadKey = null;
662
+ if (this.disposed) {
663
+ return;
664
+ }
665
+ this.runBrowsePreload({
666
+ cacheKey,
667
+ currentUserId,
668
+ filter,
669
+ sessionCwd,
670
+ workspaceId
671
+ });
624
672
  });
625
- void this.runSearch({
626
- workspaceId: this.activeWorkspaceId,
627
- currentUserId: this.currentUserId,
628
- query: this.currentQuery,
629
- requestId
673
+ }
674
+ runBrowsePreload(input) {
675
+ const { cacheKey, currentUserId, filter, sessionCwd, workspaceId } = input;
676
+ this.logLifecycle("browse.preload", {
677
+ filter,
678
+ providerIds: this.providerIdsForDiagnostics(),
679
+ sessionCwdPresent: Boolean(sessionCwd),
680
+ workspaceId
681
+ });
682
+ const cached = this.readBrowseCache(cacheKey);
683
+ this.logBrowseCacheState({
684
+ cacheKey,
685
+ cached,
686
+ filter,
687
+ reason: "preload",
688
+ workspaceId
689
+ });
690
+ if (cached.isFresh) {
691
+ return;
692
+ }
693
+ void this.loadBrowseFetchResult(
694
+ {
695
+ workspaceId,
696
+ currentUserId,
697
+ filter,
698
+ sessionCwd
699
+ },
700
+ cacheKey,
701
+ "preload"
702
+ ).catch((error) => {
703
+ this.logLifecycle("browse.fetch.error", {
704
+ errorKind: diagnosticErrorKind(error),
705
+ filter,
706
+ reason: "preload",
707
+ workspaceId
708
+ });
630
709
  });
631
710
  }
711
+ cancelPendingPreload() {
712
+ if (this.preloadCancel) {
713
+ this.preloadCancel();
714
+ this.preloadCancel = null;
715
+ }
716
+ this.pendingPreloadKey = null;
717
+ }
718
+ enterCategory(category) {
719
+ this.setFilter(category);
720
+ }
632
721
  selectAgentGeneratedMentionItem(item) {
633
722
  if (item.kind !== "file" || !item.mentionNavigation) {
634
723
  return false;
@@ -670,10 +759,6 @@ var AgentMentionSearchController = class {
670
759
  const current = this.expandedCounts[groupId] ?? pageSize;
671
760
  this.expandedCounts[groupId] = current + pageSize;
672
761
  if (!this.currentQuery) {
673
- const nextFilter = filterForGroup(groupId);
674
- if (this.currentFilter === "all") {
675
- this.currentFilter = nextFilter;
676
- }
677
762
  this.setState({
678
763
  status: "ready",
679
764
  query: "",
@@ -709,7 +794,8 @@ var AgentMentionSearchController = class {
709
794
  workspaceId: this.activeWorkspaceId,
710
795
  currentUserId: this.currentUserId,
711
796
  query: this.currentQuery,
712
- requestId
797
+ requestId,
798
+ filter: this.currentFilter
713
799
  });
714
800
  return;
715
801
  }
@@ -726,30 +812,17 @@ var AgentMentionSearchController = class {
726
812
  close() {
727
813
  this.clearTimer();
728
814
  this.requestId += 1;
729
- this.currentFilter = "all";
815
+ this.currentFilter = DEFAULT_AGENT_MENTION_FILTER;
730
816
  this.resetAgentGeneratedBrowsePath();
731
817
  this.resetExpandedCounts();
732
818
  this.resetSearchLimits();
733
- this.rawGroups = {
734
- apps: [],
735
- opened_files: [],
736
- agent_generated_files: [],
737
- my_sessions: [],
738
- collab_sessions: [],
739
- issues: []
740
- };
741
- this.totalCounts.apps = 0;
742
- this.totalCounts.opened_files = 0;
743
- this.totalCounts.agent_generated_files = 0;
744
- this.totalCounts.my_sessions = 0;
745
- this.totalCounts.collab_sessions = 0;
746
- this.totalCounts.issues = 0;
819
+ this.resetRawGroups();
747
820
  this.currentQuery = "";
748
821
  this.setState({
749
822
  status: "idle",
750
823
  query: "",
751
824
  mode: "browse",
752
- filter: "all",
825
+ filter: DEFAULT_AGENT_MENTION_FILTER,
753
826
  categories: buildBrowseCategories(),
754
827
  groups: [],
755
828
  error: null
@@ -758,101 +831,98 @@ var AgentMentionSearchController = class {
758
831
  dispose() {
759
832
  this.disposed = true;
760
833
  this.clearTimer();
834
+ this.cancelPendingPreload();
761
835
  this.listeners.clear();
762
836
  this.requestId += 1;
837
+ this.logLifecycle("controller.dispose", {
838
+ requestId: this.requestId,
839
+ workspaceId: this.activeWorkspaceId
840
+ });
763
841
  }
764
842
  startBrowseModeFetch(filter) {
765
- if (!this.activeWorkspaceId || !shouldPrefetchBrowseFilter(filter)) {
766
- this.rawGroups = {
767
- apps: [],
768
- opened_files: [],
769
- agent_generated_files: [],
770
- my_sessions: [],
771
- collab_sessions: [],
772
- issues: []
773
- };
843
+ if (!this.activeWorkspaceId) {
844
+ this.resetRawGroups();
774
845
  this.emitBrowseState("ready");
775
846
  return;
776
847
  }
777
848
  this.clearTimer();
778
849
  const requestId = ++this.requestId;
779
- this.rawGroups = {
780
- apps: [],
781
- opened_files: [],
782
- agent_generated_files: [],
783
- my_sessions: [],
784
- collab_sessions: [],
785
- issues: []
786
- };
787
- this.emitBrowseState("loading");
850
+ const cacheKey = this.browseCacheKey({
851
+ currentUserId: this.currentUserId,
852
+ filter,
853
+ sessionCwd: this.currentSessionCwd,
854
+ workspaceId: this.activeWorkspaceId
855
+ });
856
+ this.logLifecycle("browse.open", {
857
+ filter,
858
+ providerIds: this.providerIdsForDiagnostics(),
859
+ requestId,
860
+ sessionCwdPresent: Boolean(this.currentSessionCwd),
861
+ workspaceId: this.activeWorkspaceId
862
+ });
863
+ const cached = this.readBrowseCacheForBrowseInput({
864
+ cacheKey,
865
+ currentUserId: this.currentUserId,
866
+ filter,
867
+ sessionCwd: this.currentSessionCwd,
868
+ workspaceId: this.activeWorkspaceId
869
+ });
870
+ this.logBrowseCacheState({
871
+ cacheKey,
872
+ cached,
873
+ filter,
874
+ reason: "open",
875
+ workspaceId: this.activeWorkspaceId
876
+ });
877
+ if (cached.entry) {
878
+ this.applyBrowseFetchResult(cached.entry);
879
+ this.setState({
880
+ status: "ready",
881
+ query: "",
882
+ mode: "browse",
883
+ filter: this.currentFilter,
884
+ categories: buildBrowseCategories(),
885
+ groups: this.groupsFromRawGroups(),
886
+ error: null
887
+ });
888
+ if (cached.isFresh) {
889
+ return;
890
+ }
891
+ } else {
892
+ this.rawGroups = emptyAgentMentionRawGroups();
893
+ this.resetTotalCounts();
894
+ this.emitBrowseState("loading");
895
+ }
788
896
  void this.runBrowseSearch({
789
897
  workspaceId: this.activeWorkspaceId,
790
898
  currentUserId: this.currentUserId,
791
899
  requestId,
792
- filter
900
+ filter,
901
+ sessionCwd: this.currentSessionCwd
793
902
  });
794
903
  }
795
904
  async runSearch(input) {
796
905
  const startedAt = this.diagnosticNow();
797
- const providerDiagnostics = [];
906
+ let providerDiagnostics = [];
798
907
  try {
799
- const [fileItems, appItems, issueItems, sessionItems] = await Promise.all(
800
- [
801
- this.queryProviderMentionItemsById({
802
- providerId: FILE_PROVIDER_ID2,
803
- workspaceId: input.workspaceId,
804
- currentUserId: input.currentUserId,
805
- query: input.query,
806
- limit: this.currentFileSearchLimit,
807
- diagnostics: providerDiagnostics
808
- }),
809
- this.queryProviderMentionItemsById({
810
- providerId: WORKSPACE_APP_PROVIDER_ID2,
811
- workspaceId: input.workspaceId,
812
- currentUserId: input.currentUserId,
813
- query: input.query,
814
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
815
- diagnostics: providerDiagnostics
816
- }),
817
- this.queryProviderMentionItemsById({
818
- providerId: WORKSPACE_ISSUE_PROVIDER_ID2,
819
- workspaceId: input.workspaceId,
820
- currentUserId: input.currentUserId,
821
- query: input.query,
822
- limit: this.currentIssueSearchLimit,
823
- diagnostics: providerDiagnostics
824
- }),
825
- this.queryProviderMentionItemsById({
826
- providerId: AGENT_SESSION_PROVIDER_ID2,
827
- workspaceId: input.workspaceId,
828
- currentUserId: input.currentUserId,
829
- query: input.query,
830
- limit: DEFAULT_SESSION_LIMIT,
831
- diagnostics: providerDiagnostics
832
- })
833
- ]
834
- );
835
- if (!this.canApply(input.requestId, input.workspaceId, input.query)) {
908
+ const result = await this.fetchFilterResult({
909
+ workspaceId: input.workspaceId,
910
+ currentUserId: input.currentUserId,
911
+ query: input.query,
912
+ filter: input.filter,
913
+ sessionCwd: this.currentSessionCwd,
914
+ includeAgentGeneratedFiles: false
915
+ });
916
+ providerDiagnostics = result.providerDiagnostics;
917
+ if (!this.canApply(
918
+ input.requestId,
919
+ input.workspaceId,
920
+ input.query,
921
+ input.filter
922
+ )) {
836
923
  return;
837
924
  }
838
- this.rawGroups = {
839
- apps: appItems.filter((item) => item.kind === "workspace-app"),
840
- opened_files: fileItems.filter((item) => item.kind === "file"),
841
- agent_generated_files: [],
842
- my_sessions: sessionItems.filter(
843
- (item) => item.kind === "session" && item.scope === "my_sessions"
844
- ),
845
- collab_sessions: sessionItems.filter(
846
- (item) => item.kind === "session" && item.scope === "collab_sessions"
847
- ),
848
- issues: issueItems.filter((item) => item.kind === "workspace-issue")
849
- };
850
- this.totalCounts.apps = this.rawGroups.apps.length;
851
- this.totalCounts.opened_files = this.rawGroups.opened_files.length;
852
- this.totalCounts.agent_generated_files = 0;
853
- this.totalCounts.my_sessions = this.rawGroups.my_sessions.length;
854
- this.totalCounts.collab_sessions = this.rawGroups.collab_sessions.length;
855
- this.totalCounts.issues = this.rawGroups.issues.length;
925
+ this.applyBrowseFetchResult(result);
856
926
  const groups = this.groupsFromRawGroups();
857
927
  this.setState({
858
928
  status: "ready",
@@ -864,7 +934,7 @@ var AgentMentionSearchController = class {
864
934
  error: null
865
935
  });
866
936
  this.logSearchDiagnostic({
867
- filter: this.currentFilter,
937
+ filter: input.filter,
868
938
  groups,
869
939
  mode: "results",
870
940
  providerDiagnostics,
@@ -875,7 +945,12 @@ var AgentMentionSearchController = class {
875
945
  workspaceId: input.workspaceId
876
946
  });
877
947
  } catch (error) {
878
- if (!this.canApply(input.requestId, input.workspaceId, input.query)) {
948
+ if (!this.canApply(
949
+ input.requestId,
950
+ input.workspaceId,
951
+ input.query,
952
+ input.filter
953
+ )) {
879
954
  return;
880
955
  }
881
956
  this.setState({
@@ -889,7 +964,7 @@ var AgentMentionSearchController = class {
889
964
  });
890
965
  this.logSearchDiagnostic({
891
966
  error,
892
- filter: this.currentFilter,
967
+ filter: input.filter,
893
968
  groups: [],
894
969
  mode: "results",
895
970
  providerDiagnostics,
@@ -903,205 +978,21 @@ var AgentMentionSearchController = class {
903
978
  }
904
979
  async runBrowseSearch(input) {
905
980
  const startedAt = this.diagnosticNow();
906
- const providerDiagnostics = [];
981
+ let providerDiagnostics = [];
982
+ const cacheKey = this.browseCacheKey(input);
907
983
  try {
908
- if (input.filter === "file") {
909
- const [fileItems, agentGeneratedFileItems] = await Promise.all([
910
- this.queryProviderMentionItemsById({
911
- providerId: FILE_PROVIDER_ID2,
912
- workspaceId: input.workspaceId,
913
- currentUserId: input.currentUserId,
914
- query: "",
915
- limit: this.fileLimit,
916
- diagnostics: providerDiagnostics
917
- }),
918
- this.queryProviderMentionItemsById({
919
- providerId: AGENT_GENERATED_FILE_PROVIDER_ID2,
920
- workspaceId: input.workspaceId,
921
- currentUserId: input.currentUserId,
922
- query: "",
923
- limit: this.fileLimit,
924
- diagnostics: providerDiagnostics
925
- })
926
- ]);
927
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
928
- return;
929
- }
930
- this.rawGroups = {
931
- apps: [],
932
- opened_files: fileItems.filter((item) => item.kind === "file"),
933
- agent_generated_files: agentGeneratedFileItems.filter(
934
- (item) => item.kind === "file"
935
- ),
936
- my_sessions: [],
937
- collab_sessions: [],
938
- issues: []
939
- };
940
- this.totalCounts.apps = 0;
941
- this.totalCounts.opened_files = this.rawGroups.opened_files.length;
942
- this.totalCounts.agent_generated_files = this.rawGroups.agent_generated_files.length;
943
- this.totalCounts.my_sessions = 0;
944
- this.totalCounts.collab_sessions = 0;
945
- this.totalCounts.issues = 0;
946
- } else if (input.filter === "app") {
947
- const appItems = await this.queryProviderMentionItemsById({
948
- providerId: WORKSPACE_APP_PROVIDER_ID2,
949
- workspaceId: input.workspaceId,
950
- currentUserId: input.currentUserId,
951
- query: "",
952
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
953
- diagnostics: providerDiagnostics
954
- });
955
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
956
- return;
957
- }
958
- this.rawGroups = {
959
- apps: appItems.filter((item) => item.kind === "workspace-app"),
960
- opened_files: [],
961
- agent_generated_files: [],
962
- my_sessions: [],
963
- collab_sessions: [],
964
- issues: []
965
- };
966
- this.totalCounts.apps = this.rawGroups.apps.length;
967
- this.totalCounts.opened_files = 0;
968
- this.totalCounts.agent_generated_files = 0;
969
- this.totalCounts.my_sessions = 0;
970
- this.totalCounts.collab_sessions = 0;
971
- this.totalCounts.issues = 0;
972
- } else if (input.filter === "issue") {
973
- const issueItems = await this.queryProviderMentionItemsById({
974
- providerId: WORKSPACE_ISSUE_PROVIDER_ID2,
975
- workspaceId: input.workspaceId,
976
- currentUserId: input.currentUserId,
977
- query: "",
978
- limit: this.currentIssueSearchLimit,
979
- diagnostics: providerDiagnostics
980
- });
981
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
982
- return;
983
- }
984
- this.rawGroups = {
985
- apps: [],
986
- opened_files: [],
987
- agent_generated_files: [],
988
- my_sessions: [],
989
- collab_sessions: [],
990
- issues: issueItems.filter((item) => item.kind === "workspace-issue")
991
- };
992
- this.totalCounts.apps = 0;
993
- this.totalCounts.opened_files = 0;
994
- this.totalCounts.agent_generated_files = 0;
995
- this.totalCounts.my_sessions = 0;
996
- this.totalCounts.collab_sessions = 0;
997
- this.totalCounts.issues = this.rawGroups.issues.length;
998
- } else if (input.filter === "session") {
999
- const sessionItems = await this.queryProviderMentionItemsById({
1000
- providerId: AGENT_SESSION_PROVIDER_ID2,
1001
- workspaceId: input.workspaceId,
1002
- currentUserId: input.currentUserId,
1003
- query: "",
1004
- limit: DEFAULT_SESSION_LIMIT,
1005
- diagnostics: providerDiagnostics
984
+ const result = await this.loadBrowseFetchResult(input, cacheKey, "open");
985
+ providerDiagnostics = result.providerDiagnostics;
986
+ if (!this.canApply(input.requestId, input.workspaceId, "", input.filter)) {
987
+ this.logLifecycle("browse.apply.skipped", {
988
+ filter: input.filter,
989
+ requestId: input.requestId,
990
+ reason: "open",
991
+ workspaceId: input.workspaceId
1006
992
  });
1007
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
1008
- return;
1009
- }
1010
- const sessionMentionItems = sessionItems.filter(
1011
- (item) => item.kind === "session"
1012
- );
1013
- const mySessionItems = sessionMentionItems.filter(
1014
- (item) => input.currentUserId ? item.scope === "my_sessions" : true
1015
- ).map(
1016
- (item) => item.scope === "my_sessions" ? item : { ...item, scope: "my_sessions" }
1017
- );
1018
- this.rawGroups = {
1019
- apps: [],
1020
- opened_files: [],
1021
- agent_generated_files: [],
1022
- my_sessions: mySessionItems,
1023
- collab_sessions: [],
1024
- issues: []
1025
- };
1026
- this.totalCounts.apps = 0;
1027
- this.totalCounts.opened_files = 0;
1028
- this.totalCounts.agent_generated_files = 0;
1029
- this.totalCounts.my_sessions = this.rawGroups.my_sessions.length;
1030
- this.totalCounts.collab_sessions = this.rawGroups.collab_sessions.length;
1031
- this.totalCounts.issues = 0;
1032
- } else {
1033
- const [
1034
- appItems,
1035
- fileItems,
1036
- agentGeneratedFileItems,
1037
- issueItems,
1038
- sessionItems
1039
- ] = await Promise.all([
1040
- this.queryProviderMentionItemsById({
1041
- providerId: WORKSPACE_APP_PROVIDER_ID2,
1042
- workspaceId: input.workspaceId,
1043
- currentUserId: input.currentUserId,
1044
- query: "",
1045
- limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
1046
- diagnostics: providerDiagnostics
1047
- }),
1048
- this.queryProviderMentionItemsById({
1049
- providerId: FILE_PROVIDER_ID2,
1050
- workspaceId: input.workspaceId,
1051
- currentUserId: input.currentUserId,
1052
- query: "",
1053
- limit: this.fileLimit,
1054
- diagnostics: providerDiagnostics
1055
- }),
1056
- this.queryProviderMentionItemsById({
1057
- providerId: AGENT_GENERATED_FILE_PROVIDER_ID2,
1058
- workspaceId: input.workspaceId,
1059
- currentUserId: input.currentUserId,
1060
- query: "",
1061
- limit: this.fileLimit,
1062
- diagnostics: providerDiagnostics
1063
- }),
1064
- this.queryProviderMentionItemsById({
1065
- providerId: WORKSPACE_ISSUE_PROVIDER_ID2,
1066
- workspaceId: input.workspaceId,
1067
- currentUserId: input.currentUserId,
1068
- query: "",
1069
- limit: this.currentIssueSearchLimit,
1070
- diagnostics: providerDiagnostics
1071
- }),
1072
- this.queryProviderMentionItemsById({
1073
- providerId: AGENT_SESSION_PROVIDER_ID2,
1074
- workspaceId: input.workspaceId,
1075
- currentUserId: input.currentUserId,
1076
- query: "",
1077
- limit: DEFAULT_SESSION_LIMIT,
1078
- diagnostics: providerDiagnostics
1079
- })
1080
- ]);
1081
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
1082
- return;
1083
- }
1084
- this.rawGroups = {
1085
- apps: appItems.filter((item) => item.kind === "workspace-app"),
1086
- opened_files: fileItems.filter((item) => item.kind === "file"),
1087
- agent_generated_files: agentGeneratedFileItems.filter(
1088
- (item) => item.kind === "file"
1089
- ),
1090
- my_sessions: sessionItems.filter(
1091
- (item) => item.kind === "session" && item.scope === "my_sessions"
1092
- ),
1093
- collab_sessions: sessionItems.filter(
1094
- (item) => item.kind === "session" && item.scope === "collab_sessions"
1095
- ),
1096
- issues: issueItems.filter((item) => item.kind === "workspace-issue")
1097
- };
1098
- this.totalCounts.apps = this.rawGroups.apps.length;
1099
- this.totalCounts.opened_files = this.rawGroups.opened_files.length;
1100
- this.totalCounts.agent_generated_files = this.rawGroups.agent_generated_files.length;
1101
- this.totalCounts.my_sessions = this.rawGroups.my_sessions.length;
1102
- this.totalCounts.collab_sessions = this.rawGroups.collab_sessions.length;
1103
- this.totalCounts.issues = this.rawGroups.issues.length;
993
+ return;
1104
994
  }
995
+ this.applyBrowseFetchResult(result);
1105
996
  const groups = this.groupsFromRawGroups();
1106
997
  this.setState({
1107
998
  status: "ready",
@@ -1113,7 +1004,7 @@ var AgentMentionSearchController = class {
1113
1004
  error: null
1114
1005
  });
1115
1006
  this.logSearchDiagnostic({
1116
- filter: this.currentFilter,
1007
+ filter: input.filter,
1117
1008
  groups,
1118
1009
  mode: "browse",
1119
1010
  providerDiagnostics,
@@ -1124,7 +1015,7 @@ var AgentMentionSearchController = class {
1124
1015
  workspaceId: input.workspaceId
1125
1016
  });
1126
1017
  } catch (error) {
1127
- if (!this.canApply(input.requestId, input.workspaceId, "")) {
1018
+ if (!this.canApply(input.requestId, input.workspaceId, "", input.filter)) {
1128
1019
  return;
1129
1020
  }
1130
1021
  this.setState({
@@ -1138,7 +1029,7 @@ var AgentMentionSearchController = class {
1138
1029
  });
1139
1030
  this.logSearchDiagnostic({
1140
1031
  error,
1141
- filter: this.currentFilter,
1032
+ filter: input.filter,
1142
1033
  groups: [],
1143
1034
  mode: "browse",
1144
1035
  providerDiagnostics,
@@ -1150,6 +1041,156 @@ var AgentMentionSearchController = class {
1150
1041
  });
1151
1042
  }
1152
1043
  }
1044
+ async loadBrowseFetchResult(input, cacheKey, reason) {
1045
+ const existingFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
1046
+ if (existingFetch) {
1047
+ this.logLifecycle("browse.fetch.dedupe", {
1048
+ filter: input.filter,
1049
+ reason,
1050
+ workspaceId: input.workspaceId
1051
+ });
1052
+ return existingFetch;
1053
+ }
1054
+ const startedAt = this.diagnosticNow();
1055
+ this.logLifecycle("browse.fetch.start", {
1056
+ filter: input.filter,
1057
+ providerIds: this.providerIdsForDiagnostics(),
1058
+ reason,
1059
+ workspaceId: input.workspaceId
1060
+ });
1061
+ const fetchPromise = this.fetchBrowseResult(input).then((result) => {
1062
+ writeBrowseCacheEntry(cacheKey, {
1063
+ ...result,
1064
+ cachedAt: this.diagnosticNow()
1065
+ });
1066
+ this.logLifecycle("browse.fetch.success", {
1067
+ durationMs: elapsedDiagnosticMs(this.diagnosticNow(), startedAt),
1068
+ filter: input.filter,
1069
+ itemCount: rawGroupItemCount(result.rawGroups),
1070
+ providerResults: providerDiagnosticsSummary(
1071
+ result.providerDiagnostics
1072
+ ),
1073
+ reason,
1074
+ workspaceId: input.workspaceId
1075
+ });
1076
+ return result;
1077
+ }).finally(() => {
1078
+ if (sharedAgentMentionBrowseFetches.get(cacheKey) === fetchPromise) {
1079
+ sharedAgentMentionBrowseFetches.delete(cacheKey);
1080
+ }
1081
+ });
1082
+ sharedAgentMentionBrowseFetches.set(cacheKey, fetchPromise);
1083
+ return fetchPromise;
1084
+ }
1085
+ async fetchBrowseResult(input) {
1086
+ return this.fetchFilterResult({
1087
+ ...input,
1088
+ query: "",
1089
+ includeAgentGeneratedFiles: input.filter === "file"
1090
+ });
1091
+ }
1092
+ async fetchFilterResult(input) {
1093
+ const providerDiagnostics = [];
1094
+ switch (input.filter) {
1095
+ case "file": {
1096
+ const fileQuery = this.queryProviderMentionItemsById({
1097
+ providerId: FILE_PROVIDER_ID2,
1098
+ workspaceId: input.workspaceId,
1099
+ currentUserId: input.currentUserId,
1100
+ query: input.query,
1101
+ limit: input.query ? this.currentFileSearchLimit : this.fileLimit,
1102
+ sessionCwd: input.sessionCwd,
1103
+ diagnostics: providerDiagnostics
1104
+ });
1105
+ const agentGeneratedFileQuery = input.includeAgentGeneratedFiles ? this.queryProviderMentionItemsById({
1106
+ providerId: AGENT_GENERATED_FILE_PROVIDER_ID2,
1107
+ workspaceId: input.workspaceId,
1108
+ currentUserId: input.currentUserId,
1109
+ query: input.query,
1110
+ limit: this.fileLimit,
1111
+ sessionCwd: input.sessionCwd,
1112
+ diagnostics: providerDiagnostics
1113
+ }) : Promise.resolve([]);
1114
+ const [fileItems, agentGeneratedFileItems] = await Promise.all([
1115
+ fileQuery,
1116
+ agentGeneratedFileQuery
1117
+ ]);
1118
+ const rawGroups = emptyAgentMentionRawGroups();
1119
+ rawGroups.opened_files = fileItems.filter(
1120
+ (item) => item.kind === "file"
1121
+ );
1122
+ rawGroups.agent_generated_files = agentGeneratedFileItems.filter(
1123
+ (item) => item.kind === "file"
1124
+ );
1125
+ return {
1126
+ providerDiagnostics,
1127
+ rawGroups,
1128
+ totalCounts: totalCountsFromRawGroups(rawGroups)
1129
+ };
1130
+ }
1131
+ case "session": {
1132
+ const sessionItems = await this.queryProviderMentionItemsById({
1133
+ providerId: AGENT_SESSION_PROVIDER_ID2,
1134
+ workspaceId: input.workspaceId,
1135
+ currentUserId: input.currentUserId,
1136
+ query: input.query,
1137
+ limit: DEFAULT_SESSION_LIMIT,
1138
+ sessionCwd: input.sessionCwd,
1139
+ diagnostics: providerDiagnostics
1140
+ });
1141
+ const rawGroups = emptyAgentMentionRawGroups();
1142
+ rawGroups.my_sessions = normalizeSessionMentionItemsForMySessions({
1143
+ currentUserId: input.currentUserId,
1144
+ items: sessionItems
1145
+ });
1146
+ return {
1147
+ providerDiagnostics,
1148
+ rawGroups,
1149
+ totalCounts: totalCountsFromRawGroups(rawGroups)
1150
+ };
1151
+ }
1152
+ case "issue": {
1153
+ const issueItems = await this.queryProviderMentionItemsById({
1154
+ providerId: WORKSPACE_ISSUE_PROVIDER_ID2,
1155
+ workspaceId: input.workspaceId,
1156
+ currentUserId: input.currentUserId,
1157
+ query: input.query,
1158
+ limit: this.currentIssueSearchLimit,
1159
+ sessionCwd: input.sessionCwd,
1160
+ diagnostics: providerDiagnostics
1161
+ });
1162
+ const rawGroups = emptyAgentMentionRawGroups();
1163
+ rawGroups.issues = issueItems.filter(
1164
+ (item) => item.kind === "workspace-issue"
1165
+ );
1166
+ return {
1167
+ providerDiagnostics,
1168
+ rawGroups,
1169
+ totalCounts: totalCountsFromRawGroups(rawGroups)
1170
+ };
1171
+ }
1172
+ case "app": {
1173
+ const appItems = await this.queryProviderMentionItemsById({
1174
+ providerId: WORKSPACE_APP_PROVIDER_ID2,
1175
+ workspaceId: input.workspaceId,
1176
+ currentUserId: input.currentUserId,
1177
+ query: input.query,
1178
+ limit: DEFAULT_MENTION_GROUP_PAGE_SIZE,
1179
+ sessionCwd: input.sessionCwd,
1180
+ diagnostics: providerDiagnostics
1181
+ });
1182
+ const rawGroups = emptyAgentMentionRawGroups();
1183
+ rawGroups.apps = appItems.filter(
1184
+ (item) => item.kind === "workspace-app"
1185
+ );
1186
+ return {
1187
+ providerDiagnostics,
1188
+ rawGroups,
1189
+ totalCounts: totalCountsFromRawGroups(rawGroups)
1190
+ };
1191
+ }
1192
+ }
1193
+ }
1153
1194
  async queryProviderMentionItems(input) {
1154
1195
  const items = await input.provider.query({
1155
1196
  keyword: input.query,
@@ -1159,7 +1200,7 @@ var AgentMentionSearchController = class {
1159
1200
  context: {
1160
1201
  metadata: {
1161
1202
  currentUserId: input.currentUserId,
1162
- sessionCwd: this.currentSessionCwd || void 0,
1203
+ sessionCwd: input.sessionCwd || void 0,
1163
1204
  target: "agent-gui",
1164
1205
  workspaceId: input.workspaceId
1165
1206
  }
@@ -1181,12 +1222,12 @@ var AgentMentionSearchController = class {
1181
1222
  if (!mentionItem || mentionItem.kind !== "file") {
1182
1223
  return mentionItem;
1183
1224
  }
1184
- const thumbnailUrl = await Promise.resolve(
1185
- input.provider.getItemThumbnailUrl?.(item) ?? null
1225
+ const iconUrl = await Promise.resolve(
1226
+ input.provider.getItemIconUrl?.(item) ?? null
1186
1227
  ).catch(() => null);
1187
1228
  const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
1188
1229
  ...mentionItem,
1189
- thumbnailUrl
1230
+ thumbnailUrl: iconUrl
1190
1231
  });
1191
1232
  if (!resolvedThumbnailUrl) {
1192
1233
  return mentionItem;
@@ -1201,6 +1242,55 @@ var AgentMentionSearchController = class {
1201
1242
  (item) => item !== null
1202
1243
  );
1203
1244
  }
1245
+ applyBrowseFetchResult(result) {
1246
+ this.rawGroups = cloneAgentMentionRawGroups(result.rawGroups);
1247
+ this.resetTotalCounts();
1248
+ for (const [groupId, count] of Object.entries(result.totalCounts)) {
1249
+ this.totalCounts[groupId] = count;
1250
+ }
1251
+ }
1252
+ readBrowseCache(cacheKey) {
1253
+ const entry = sharedAgentMentionBrowseCache.get(cacheKey);
1254
+ if (!entry) {
1255
+ return { entry: null, isFresh: false };
1256
+ }
1257
+ sharedAgentMentionBrowseCache.delete(cacheKey);
1258
+ sharedAgentMentionBrowseCache.set(cacheKey, entry);
1259
+ const ageMs = this.diagnosticNow() - entry.cachedAt;
1260
+ const isFresh = this.browseCacheTtlMs >= 0 && Number.isFinite(this.browseCacheTtlMs) && ageMs <= this.browseCacheTtlMs;
1261
+ return { entry, isFresh };
1262
+ }
1263
+ readBrowseCacheForBrowseInput(input) {
1264
+ return this.readBrowseCache(input.cacheKey);
1265
+ }
1266
+ browseCacheKey(input) {
1267
+ return JSON.stringify({
1268
+ workspaceId: input.workspaceId,
1269
+ currentUserId: input.currentUserId,
1270
+ sessionCwd: input.sessionCwd,
1271
+ filter: input.filter,
1272
+ fileLimit: this.fileLimit,
1273
+ issueLimit: this.currentIssueSearchLimit,
1274
+ providerIds: [...this.contextMentionProviders.keys()].sort()
1275
+ });
1276
+ }
1277
+ logBrowseCacheState(input) {
1278
+ this.logLifecycle("browse.cache", {
1279
+ ageMs: input.cached.entry ? elapsedDiagnosticMs(this.diagnosticNow(), input.cached.entry.cachedAt) : null,
1280
+ cacheKeyLength: input.cacheKey.length,
1281
+ cacheState: input.cached.entry ? input.cached.isFresh ? "fresh" : "stale" : "miss",
1282
+ filter: input.filter,
1283
+ itemCount: input.cached.entry ? rawGroupItemCount(input.cached.entry.rawGroups) : 0,
1284
+ reason: input.reason,
1285
+ workspaceId: input.workspaceId
1286
+ });
1287
+ }
1288
+ logLifecycle(event, details) {
1289
+ logAgentMentionLifecycleDiagnostic({ event, details });
1290
+ }
1291
+ providerIdsForDiagnostics() {
1292
+ return [...this.contextMentionProviders.keys()].sort().join(",");
1293
+ }
1204
1294
  async queryProviderMentionItemsById(input) {
1205
1295
  const provider = this.contextMentionProviders.get(input.providerId);
1206
1296
  return queryAgentMentionProviderWithDiagnostics({
@@ -1215,6 +1305,7 @@ var AgentMentionSearchController = class {
1215
1305
  currentUserId: input.currentUserId,
1216
1306
  query: input.query,
1217
1307
  limit: input.limit,
1308
+ sessionCwd: input.sessionCwd ?? this.currentSessionCwd,
1218
1309
  abortSignal
1219
1310
  }) : null,
1220
1311
  resultCount: (result) => result.length
@@ -1241,7 +1332,7 @@ var AgentMentionSearchController = class {
1241
1332
  }
1242
1333
  groupsFromRawGroups() {
1243
1334
  const orderedGroupIds = groupIdsForFilter(this.currentFilter);
1244
- const groups = orderedGroupIds.map((groupId) => {
1335
+ return orderedGroupIds.map((groupId) => {
1245
1336
  const rawItems = resolveMentionGroupItems(groupId, this.rawGroups);
1246
1337
  const items = groupId === "agent_generated_files" ? presentAgentGeneratedFileMentionItems({
1247
1338
  files: rawItems,
@@ -1276,11 +1367,6 @@ var AgentMentionSearchController = class {
1276
1367
  hasMore: items.length > visibleCount || (groupId === "opened_files" || groupId === "files" || groupId === "agent_generated_files") && items.length >= this.currentFileSearchLimit || totalCount > visibleCount
1277
1368
  };
1278
1369
  }).filter((group) => group !== null);
1279
- return orderMentionGroupsForFilter({
1280
- filter: this.currentFilter,
1281
- groups,
1282
- query: this.currentQuery
1283
- });
1284
1370
  }
1285
1371
  emitBrowseState(status) {
1286
1372
  this.setState({
@@ -1293,8 +1379,8 @@ var AgentMentionSearchController = class {
1293
1379
  error: null
1294
1380
  });
1295
1381
  }
1296
- canApply(requestId, workspaceId, query) {
1297
- return !this.disposed && requestId === this.requestId && workspaceId === this.activeWorkspaceId && query === this.currentQuery;
1382
+ canApply(requestId, workspaceId, query, filter) {
1383
+ return !this.disposed && requestId === this.requestId && workspaceId === this.activeWorkspaceId && query === this.currentQuery && filter === this.currentFilter;
1298
1384
  }
1299
1385
  clearTimer() {
1300
1386
  if (this.timer !== null) {
@@ -1322,9 +1408,26 @@ var AgentMentionSearchController = class {
1322
1408
  this.currentFileSearchLimit = this.fileLimit;
1323
1409
  this.currentIssueSearchLimit = this.issueLimit;
1324
1410
  }
1411
+ resetRawGroups() {
1412
+ this.rawGroups = emptyAgentMentionRawGroups();
1413
+ this.resetTotalCounts();
1414
+ }
1325
1415
  resetAgentGeneratedBrowsePath() {
1326
1416
  this.agentGeneratedBrowsePath = null;
1327
1417
  }
1418
+ resetTotalCounts() {
1419
+ for (const groupId of [
1420
+ "files",
1421
+ "opened_files",
1422
+ "agent_generated_files",
1423
+ "my_sessions",
1424
+ "collab_sessions",
1425
+ "apps",
1426
+ "issues"
1427
+ ]) {
1428
+ delete this.totalCounts[groupId];
1429
+ }
1430
+ }
1328
1431
  setState(state) {
1329
1432
  this.state = state;
1330
1433
  for (const listener of this.listeners) {
@@ -1332,102 +1435,94 @@ var AgentMentionSearchController = class {
1332
1435
  }
1333
1436
  }
1334
1437
  };
1335
- function orderMentionGroupsForFilter(input) {
1336
- if (input.filter !== "all") {
1337
- return input.groups;
1338
- }
1339
- const query = normalizeQuery(input.query).toLowerCase();
1340
- return input.groups.map((group, index) => ({
1341
- group,
1342
- hasItems: group.items.length > 0,
1343
- index,
1344
- score: mentionGroupBestMatchScore(group, query)
1345
- })).sort((left, right) => {
1346
- if (left.hasItems !== right.hasItems) {
1347
- return left.hasItems ? -1 : 1;
1348
- }
1349
- if (query && left.score !== right.score) {
1350
- return right.score - left.score;
1351
- }
1352
- return left.index - right.index;
1353
- }).map((entry) => entry.group);
1354
- }
1355
- function mentionGroupBestMatchScore(group, query) {
1356
- if (!query) {
1357
- return 0;
1358
- }
1359
- return group.items.reduce(
1360
- (bestScore, item) => Math.max(bestScore, mentionItemMatchScore(item, query)),
1361
- 0
1362
- );
1363
- }
1364
- function mentionItemMatchScore(item, query) {
1365
- const primary = [];
1366
- const secondary = [];
1367
- let kindBoost = 0;
1368
- if (item.kind === "workspace-app") {
1369
- kindBoost = 8;
1370
- primary.push(item.name, item.appId, item.targetId);
1371
- secondary.push(item.description ?? "");
1372
- } else if (item.kind === "file") {
1373
- primary.push(item.name);
1374
- secondary.push(item.path, item.directoryPath);
1375
- } else if (item.kind === "session") {
1376
- primary.push(item.title);
1377
- secondary.push(
1378
- item.name,
1379
- item.initiatorName,
1380
- item.agentName,
1381
- item.inputPreview ?? "",
1382
- item.summaryPreview ?? ""
1383
- );
1384
- } else if (item.kind === "workspace-issue") {
1385
- primary.push(item.title, item.name);
1386
- secondary.push(
1387
- item.creatorName ?? "",
1388
- item.status ?? "",
1389
- item.contentPreview ?? ""
1390
- );
1391
- } else if (item.kind === "workspace-app-factory") {
1392
- primary.push(item.name, item.jobId, item.targetId);
1393
- secondary.push(item.action ?? "", item.contextPath ?? "");
1394
- }
1395
- const primaryScore = maxTextMatchScore(primary, query, {
1396
- contains: 60,
1397
- exact: 100,
1398
- prefix: 90,
1399
- wordPrefix: 80
1438
+ function preloadAgentMentionBrowse(input) {
1439
+ const controller = new AgentMentionSearchController({
1440
+ contextMentionProviders: input.contextMentionProviders
1400
1441
  });
1401
- const secondaryScore = maxTextMatchScore(secondary, query, {
1402
- contains: 25,
1403
- exact: 60,
1404
- prefix: 50,
1405
- wordPrefix: 40
1442
+ controller.preloadBrowse({
1443
+ workspaceId: input.workspaceId,
1444
+ currentUserId: input.currentUserId,
1445
+ sessionCwd: input.sessionCwd,
1446
+ filter: input.filter
1406
1447
  });
1407
- const score = Math.max(primaryScore, secondaryScore);
1408
- return score > 0 ? score + kindBoost : 0;
1409
1448
  }
1410
- function maxTextMatchScore(values, query, scores) {
1411
- return values.reduce(
1412
- (bestScore, value) => Math.max(bestScore, textMatchScore(value, query, scores)),
1449
+ function emptyAgentMentionRawGroups() {
1450
+ return {
1451
+ apps: [],
1452
+ opened_files: [],
1453
+ agent_generated_files: [],
1454
+ my_sessions: [],
1455
+ collab_sessions: [],
1456
+ issues: []
1457
+ };
1458
+ }
1459
+ function cloneAgentMentionRawGroups(rawGroups) {
1460
+ return {
1461
+ apps: [...rawGroups.apps],
1462
+ opened_files: [...rawGroups.opened_files],
1463
+ agent_generated_files: [...rawGroups.agent_generated_files],
1464
+ my_sessions: [...rawGroups.my_sessions],
1465
+ collab_sessions: [...rawGroups.collab_sessions],
1466
+ issues: [...rawGroups.issues]
1467
+ };
1468
+ }
1469
+ function totalCountsFromRawGroups(rawGroups) {
1470
+ return {
1471
+ apps: rawGroups.apps.length,
1472
+ opened_files: rawGroups.opened_files.length,
1473
+ agent_generated_files: rawGroups.agent_generated_files.length,
1474
+ my_sessions: rawGroups.my_sessions.length,
1475
+ collab_sessions: rawGroups.collab_sessions.length,
1476
+ issues: rawGroups.issues.length
1477
+ };
1478
+ }
1479
+ function rawGroupItemCount(rawGroups) {
1480
+ return Object.values(rawGroups).reduce(
1481
+ (count, items) => count + items.length,
1413
1482
  0
1414
1483
  );
1415
1484
  }
1416
- function textMatchScore(value, query, scores) {
1417
- const normalized = normalizeQuery(value).toLowerCase();
1418
- if (!normalized) {
1419
- return 0;
1485
+ function providerDiagnosticsSummary(diagnostics) {
1486
+ return diagnostics.map(
1487
+ (diagnostic) => `${diagnostic.providerId}:${diagnostic.status}:${diagnostic.resultCount}:${diagnostic.durationMs}`
1488
+ ).join(",");
1489
+ }
1490
+ function elapsedDiagnosticMs(now, startedAt) {
1491
+ const durationMs = now - startedAt;
1492
+ return Number.isFinite(durationMs) ? Math.max(0, Math.round(durationMs)) : 0;
1493
+ }
1494
+ function diagnosticErrorKind(error) {
1495
+ if (error instanceof Error && error.name.trim()) {
1496
+ return error.name.trim();
1420
1497
  }
1421
- if (normalized === query) {
1422
- return scores.exact;
1498
+ if (error === null) {
1499
+ return "null";
1423
1500
  }
1424
- if (normalized.startsWith(query)) {
1425
- return scores.prefix;
1501
+ return typeof error;
1502
+ }
1503
+ function logAgentMentionLifecycleDiagnostic(payload) {
1504
+ try {
1505
+ console.info(AGENT_MENTION_LIFECYCLE_LOG_PREFIX, JSON.stringify(payload));
1506
+ } catch {
1426
1507
  }
1427
- if (normalized.split(/[^a-z0-9]+/i).some((word) => word.startsWith(query))) {
1428
- return scores.wordPrefix;
1508
+ try {
1509
+ getOptionalAgentHostApi()?.debug?.logRuntimeDiagnostics?.({
1510
+ source: "renderer-workspace-surface",
1511
+ level: "info",
1512
+ event: `agent-gui.mention.${payload.event}`,
1513
+ // i18n-check-ignore: Internal diagnostic log message.
1514
+ message: "Agent GUI mention search lifecycle event.",
1515
+ details: payload.details
1516
+ });
1517
+ } catch {
1429
1518
  }
1430
- return normalized.includes(query) ? scores.contains : 0;
1519
+ }
1520
+ function normalizeSessionMentionItemsForMySessions(input) {
1521
+ return input.items.filter((item) => item.kind === "session").filter(
1522
+ (item) => input.currentUserId ? item.scope === "my_sessions" : true
1523
+ ).map(
1524
+ (item) => item.scope === "my_sessions" ? item : { ...item, scope: "my_sessions" }
1525
+ );
1431
1526
  }
1432
1527
  function providerItemToAgentMentionItem(input) {
1433
1528
  const label = compactText(input.label);
@@ -1492,7 +1587,8 @@ function providerItemToAgentMentionItem(input) {
1492
1587
  appId,
1493
1588
  name: label,
1494
1589
  description: compactText(presentation.description) || compactText(presentation.subtitle) || compactText(input.subtitle) || void 0,
1495
- iconUrl: presentation.iconUrl?.trim() || void 0
1590
+ iconUrl: presentation.iconUrl?.trim() || void 0,
1591
+ referencesListSupported: presentation.referencesListSupported === "true"
1496
1592
  };
1497
1593
  }
1498
1594
  if (input.providerId === AGENT_SESSION_PROVIDER_ID2) {
@@ -1531,7 +1627,12 @@ function mentionSessionScope(input) {
1531
1627
  if (rawScope === "my_sessions" || rawScope === "collab_sessions") {
1532
1628
  return rawScope;
1533
1629
  }
1534
- return input.userId && input.userId === input.currentUserId ? "my_sessions" : "collab_sessions";
1630
+ const userId = input.userId?.trim() ?? "";
1631
+ const currentUserId = input.currentUserId.trim();
1632
+ if (!userId || !currentUserId || userId === "local" || currentUserId === "local") {
1633
+ return "my_sessions";
1634
+ }
1635
+ return userId === currentUserId ? "my_sessions" : "collab_sessions";
1535
1636
  }
1536
1637
  function dirnameFromProviderWorkspaceFileHref(href) {
1537
1638
  const normalized = href.replace(/\/+$/, "");
@@ -1668,12 +1769,15 @@ function AgentFileMentionPalette({
1668
1769
  onSelectFilter,
1669
1770
  onExpandGroup,
1670
1771
  onCycleFilter,
1671
- onMoveSelection
1772
+ onMoveSelection,
1773
+ onOpenReferences
1672
1774
  }) {
1673
1775
  "use memo";
1776
+ const openReferencesLabel = translate(
1777
+ "agentHost.agentGui.mentionOpenReferences"
1778
+ );
1674
1779
  const filter = state.filter;
1675
1780
  const highlightedBrowseCategory = highlightedKey?.startsWith("category:") ? highlightedKey.slice("category:".length) : null;
1676
- const browseDisplayFilter = isBrowseCategoryId(highlightedBrowseCategory) ? highlightedBrowseCategory : filter;
1677
1781
  const showBrowseHint = shouldShowBrowseSearchHint({
1678
1782
  browseFilter: filter,
1679
1783
  groups: state.groups,
@@ -1697,7 +1801,7 @@ function AgentFileMentionPalette({
1697
1801
  )
1698
1802
  )
1699
1803
  };
1700
- const emptyLabelForShell = showBrowseHint ? browseHintForFilter(browseDisplayFilter) : resolveMentionPaletteEmptyLabel({
1804
+ const emptyLabelForShell = showBrowseHint ? browseHintForFilter(filter) : resolveMentionPaletteEmptyLabel({
1701
1805
  emptyLabel,
1702
1806
  filter,
1703
1807
  mode: state.mode,
@@ -1717,7 +1821,11 @@ function AgentFileMentionPalette({
1717
1821
  getItemKey: agentMentionItemKey,
1718
1822
  renderItem: (item) => renderMentionRow(agentMentionItemToRowItem(item), {
1719
1823
  classNames: AGENT_MENTION_ROW_CLASS_NAMES,
1720
- dataAttributeMode: "agent"
1824
+ dataAttributeMode: "agent",
1825
+ ...onOpenReferences && isReferenceableMentionItem(item) ? {
1826
+ onOpenReferences: () => onOpenReferences(item),
1827
+ openReferencesLabel
1828
+ } : {}
1721
1829
  }),
1722
1830
  labels: {
1723
1831
  loading: loadingLabel,
@@ -1810,13 +1918,22 @@ function resolveMentionPaletteEmptyLabel(input) {
1810
1918
  if (input.mode === "results" && input.filter === "file" && input.query.trim().length > 0) {
1811
1919
  return translate("agentHost.agentGui.mentionNoMatchingFiles");
1812
1920
  }
1921
+ if (input.filter === "session") {
1922
+ return agentMentionEmptyGroupLabel("my_sessions", input.query);
1923
+ }
1924
+ if (input.filter === "app") {
1925
+ return agentMentionEmptyGroupLabel("apps", input.query);
1926
+ }
1927
+ if (input.filter === "issue") {
1928
+ return agentMentionEmptyGroupLabel("issues", input.query);
1929
+ }
1813
1930
  return input.emptyLabel;
1814
1931
  }
1815
1932
  function shouldRenderMentionGroupLabel(input) {
1816
1933
  if (shouldSuppressFileSearchGroupChrome(input.filter, input.query)) {
1817
1934
  return false;
1818
1935
  }
1819
- if (input.filter === "all" || input.groupCount !== 1) {
1936
+ if (input.groupCount !== 1) {
1820
1937
  return true;
1821
1938
  }
1822
1939
  return agentMentionGroupLabel(input.groupId) !== agentMentionFilterLabel(input.filter);
@@ -1864,6 +1981,14 @@ function agentMentionItemToRowItem(item) {
1864
1981
  iconUrl: item.iconUrl ?? null
1865
1982
  };
1866
1983
  }
1984
+ if (item.kind === "workspace-reference") {
1985
+ return {
1986
+ kind: "app",
1987
+ name: item.name,
1988
+ description: null,
1989
+ iconUrl: item.iconUrl ?? null
1990
+ };
1991
+ }
1867
1992
  if (item.kind === "workspace-app-factory") {
1868
1993
  return {
1869
1994
  kind: "app-factory",
@@ -1877,6 +2002,15 @@ function agentMentionItemToRowItem(item) {
1877
2002
  statusTag: agentIssueStatusTag(item.status)
1878
2003
  };
1879
2004
  }
2005
+ function isReferenceableMentionItem(item) {
2006
+ if (item.kind === "workspace-issue") {
2007
+ return true;
2008
+ }
2009
+ if (item.kind === "workspace-app") {
2010
+ return item.referencesListSupported === true;
2011
+ }
2012
+ return false;
2013
+ }
1880
2014
  function mentionSessionAgentProvider(item) {
1881
2015
  const queryStart = item.href.indexOf("?");
1882
2016
  if (queryStart < 0) {
@@ -1924,9 +2058,6 @@ function mentionStatusTone(status) {
1924
2058
  return "neutral";
1925
2059
  }
1926
2060
  function browseHintForFilter(filter) {
1927
- if (filter === "all") {
1928
- return translate("agentHost.agentGui.contextPickerBrowseAllHint");
1929
- }
1930
2061
  switch (filter) {
1931
2062
  case "app":
1932
2063
  return translate("agentHost.agentGui.contextPickerBrowseAppHint");
@@ -1938,9 +2069,6 @@ function browseHintForFilter(filter) {
1938
2069
  return translate("agentHost.agentGui.contextPickerBrowseIssueHint");
1939
2070
  }
1940
2071
  }
1941
- function isBrowseCategoryId(value) {
1942
- return value === "all" || value === "app" || value === "file" || value === "session" || value === "issue";
1943
- }
1944
2072
  function hasInteractiveGroupEntries(groups) {
1945
2073
  return groups.some((group) => group.items.length > 0 || group.hasMore);
1946
2074
  }
@@ -1984,10 +2112,12 @@ function shouldShowBrowseSearchHint(input) {
1984
2112
 
1985
2113
  export {
1986
2114
  AGENT_MENTION_FILTER_TAB_ORDER,
2115
+ DEFAULT_AGENT_MENTION_FILTER,
1987
2116
  AgentMentionSearchController,
2117
+ preloadAgentMentionBrowse,
1988
2118
  flattenAgentMentionPaletteEntries,
1989
2119
  groupStartKeys,
1990
2120
  AgentFileMentionPalette,
1991
2121
  AgentContextMentionPalette
1992
2122
  };
1993
- //# sourceMappingURL=chunk-3YZX5EUC.js.map
2123
+ //# sourceMappingURL=chunk-LWRYYGPZ.js.map