@tutti-os/agent-gui 0.0.94 → 0.0.96

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 (163) hide show
  1. package/README.md +86 -38
  2. package/dist/AgentGUI-DWdvUV4x.d.ts +1038 -0
  3. package/dist/agent-conversation/index.d.ts +6 -7
  4. package/dist/agent-conversation/index.js +15 -10
  5. package/dist/agent-conversation/index.js.map +1 -1
  6. package/dist/agent-env/index.d.ts +10 -36
  7. package/dist/agent-env/index.js +2 -57
  8. package/dist/agent-env/index.js.map +1 -1
  9. package/dist/agent-gui.d.ts +21 -0
  10. package/dist/agent-gui.js +39 -0
  11. package/dist/agent-message-center/index.d.ts +156 -124
  12. package/dist/agent-message-center/index.js +1656 -1463
  13. package/dist/agent-message-center/index.js.map +1 -1
  14. package/dist/{agentConversationVM-Cl4G0Lln.d.ts → agentConversationVM-C335TR6S.d.ts} +112 -7
  15. package/dist/agentFileMentionContracts-58IjMU-u.d.ts +108 -0
  16. package/dist/{agentGuiNodeTypes-CAioPXK9.d.ts → agentGuiNodeTypes-B9X4aWfv.d.ts} +123 -163
  17. package/dist/agentPlanPromptDispatch-C7cCMjve.d.ts +37 -0
  18. package/dist/agents.d.ts +13 -0
  19. package/dist/agents.js +13 -0
  20. package/dist/app/renderer/agentactivity.css +276 -83
  21. package/dist/app/renderer/assets/icons/agent-vinyls/tutti-vinyl.png +0 -0
  22. package/dist/app/renderer/assets/icons/open-link-lined.svg +4 -0
  23. package/dist/{chunk-7BUYFVRI.js → chunk-2HJEOO7W.js} +2931 -2946
  24. package/dist/chunk-2HJEOO7W.js.map +1 -0
  25. package/dist/{chunk-E5FOXRUM.js → chunk-3XXBDYAI.js} +293 -258
  26. package/dist/chunk-3XXBDYAI.js.map +1 -0
  27. package/dist/{chunk-ZUW4B5AT.js → chunk-3Y3F7CS5.js} +21 -32
  28. package/dist/chunk-3Y3F7CS5.js.map +1 -0
  29. package/dist/{chunk-SCLLP5DO.js → chunk-4PQPJ5OY.js} +50 -155
  30. package/dist/chunk-4PQPJ5OY.js.map +1 -0
  31. package/dist/chunk-4YG7YK7S.js +23 -0
  32. package/dist/chunk-4YG7YK7S.js.map +1 -0
  33. package/dist/chunk-5X7YDOC6.js +42 -0
  34. package/dist/chunk-5X7YDOC6.js.map +1 -0
  35. package/dist/{chunk-R2EWECUP.js → chunk-7BXWPI4F.js} +17 -2
  36. package/dist/{chunk-R2EWECUP.js.map → chunk-7BXWPI4F.js.map} +1 -1
  37. package/dist/chunk-AGT7MUTV.js +491 -0
  38. package/dist/chunk-AGT7MUTV.js.map +1 -0
  39. package/dist/chunk-C35SNDVZ.js +96 -0
  40. package/dist/chunk-C35SNDVZ.js.map +1 -0
  41. package/dist/{chunk-5FE7M42A.js → chunk-E4HQUTM3.js} +2 -2
  42. package/dist/chunk-FGLQZ6I4.js +9 -0
  43. package/dist/chunk-FGLQZ6I4.js.map +1 -0
  44. package/dist/chunk-H5F3QSCF.js +25 -0
  45. package/dist/chunk-H5F3QSCF.js.map +1 -0
  46. package/dist/chunk-H6IQ63DQ.js +14 -0
  47. package/dist/chunk-H6IQ63DQ.js.map +1 -0
  48. package/dist/{chunk-45FF4DQU.js → chunk-IYEXLOUE.js} +22 -27
  49. package/dist/chunk-IYEXLOUE.js.map +1 -0
  50. package/dist/{chunk-P72YLKC6.js → chunk-JKIZA7EJ.js} +3573 -3755
  51. package/dist/chunk-JKIZA7EJ.js.map +1 -0
  52. package/dist/chunk-KJQERFKX.js +259 -0
  53. package/dist/chunk-KJQERFKX.js.map +1 -0
  54. package/dist/{chunk-XW4CVBUH.js → chunk-L3GMMGRS.js} +25 -16
  55. package/dist/chunk-L3GMMGRS.js.map +1 -0
  56. package/dist/chunk-MASXZENX.js +231 -0
  57. package/dist/chunk-MASXZENX.js.map +1 -0
  58. package/dist/{chunk-BXVPOGYK.js → chunk-O3Q5SIJH.js} +505 -504
  59. package/dist/chunk-O3Q5SIJH.js.map +1 -0
  60. package/dist/{chunk-554VG7ZW.js → chunk-QVBF5BN5.js} +2 -2
  61. package/dist/{chunk-AWAIUYG4.js → chunk-RE4AXS27.js} +532 -565
  62. package/dist/chunk-RE4AXS27.js.map +1 -0
  63. package/dist/{chunk-7LMJXF4R.js → chunk-TVIGLNNI.js} +20 -16
  64. package/dist/chunk-TVIGLNNI.js.map +1 -0
  65. package/dist/{chunk-XDV4ZRVK.js → chunk-UGVI47X6.js} +98 -37
  66. package/dist/chunk-UGVI47X6.js.map +1 -0
  67. package/dist/{chunk-GAPTLVII.js → chunk-UHBCM6RO.js} +1 -1
  68. package/dist/chunk-UHBCM6RO.js.map +1 -0
  69. package/dist/{chunk-UBDPV34P.js → chunk-W6WAGPMD.js} +1385 -1305
  70. package/dist/chunk-W6WAGPMD.js.map +1 -0
  71. package/dist/chunk-WKSFPJHZ.js +33054 -0
  72. package/dist/chunk-WKSFPJHZ.js.map +1 -0
  73. package/dist/{chunk-IGY4ASUF.js → chunk-WMNS4MAQ.js} +1288 -1696
  74. package/dist/chunk-WMNS4MAQ.js.map +1 -0
  75. package/dist/{chunk-MATIJPGF.js → chunk-XPFHJMZP.js} +541 -401
  76. package/dist/chunk-XPFHJMZP.js.map +1 -0
  77. package/dist/chunk-YMXYBG7U.js +12 -0
  78. package/dist/chunk-YMXYBG7U.js.map +1 -0
  79. package/dist/context-mention-palette/index.d.ts +3 -2
  80. package/dist/context-mention-palette/index.js +17 -12
  81. package/dist/custom-mention.d.ts +42 -0
  82. package/dist/custom-mention.js +17 -0
  83. package/dist/custom-mention.js.map +1 -0
  84. package/dist/dock-icons.d.ts +4 -0
  85. package/dist/dock-icons.js +11 -0
  86. package/dist/dock-icons.js.map +1 -0
  87. package/dist/i18n/index.d.ts +880 -841
  88. package/dist/i18n/index.js +2 -2
  89. package/dist/index.d.ts +56 -1063
  90. package/dist/index.js +78 -35532
  91. package/dist/index.js.map +1 -1
  92. package/dist/mention-search.d.ts +226 -0
  93. package/dist/mention-search.js +29 -0
  94. package/dist/mention-search.js.map +1 -0
  95. package/dist/open-link-lined-JWEKUKME.svg +4 -0
  96. package/dist/pastedTextKinds-D-XuInaS.d.ts +4 -0
  97. package/dist/provider-icons.d.ts +6 -0
  98. package/dist/provider-icons.js +12 -0
  99. package/dist/provider-icons.js.map +1 -0
  100. package/dist/provider-identity.d.ts +9 -0
  101. package/dist/provider-identity.js +21 -0
  102. package/dist/provider-identity.js.map +1 -0
  103. package/dist/runtime-BBNdWgDU.d.ts +10 -0
  104. package/dist/startup-shell.d.ts +8 -0
  105. package/dist/startup-shell.js +184 -0
  106. package/dist/startup-shell.js.map +1 -0
  107. package/dist/{types-PLFZ8SBX.d.ts → types-CnT8rNUI.d.ts} +43 -87
  108. package/dist/workbench/contribution.d.ts +34 -41
  109. package/dist/workbench/contribution.js +10 -6
  110. package/dist/workbench/index.d.ts +5 -4
  111. package/dist/workbench/index.js +27 -25
  112. package/dist/workbench/launch.d.ts +4 -7
  113. package/dist/workbench/launch.js +4 -3
  114. package/dist/workbench/providerCatalog.d.ts +2 -2
  115. package/dist/workbench/providerCatalog.js +2 -1
  116. package/dist/workbench/sessionTitle.d.ts +11 -14
  117. package/dist/workbench/sessionTitle.js +6 -7
  118. package/dist/workbench/state.d.ts +1 -1
  119. package/dist/workbench/state.js +3 -2
  120. package/dist/workbench/types.d.ts +2 -4
  121. package/dist/workbench/types.js +1 -1
  122. package/dist/workspace-agent-generated-files.d.ts +20 -2
  123. package/dist/workspace-agent-generated-files.js +6 -5
  124. package/dist/workspaceAgentActivityListTypes-C7gPWYiA.d.ts +71 -0
  125. package/package.json +70 -26
  126. package/dist/AgentMentionSearchController-DD_WOred.d.ts +0 -241
  127. package/dist/AgentMessageMarkdown-DeYPURtF.d.ts +0 -7
  128. package/dist/chunk-45FF4DQU.js.map +0 -1
  129. package/dist/chunk-4HP6V2YA.js +0 -207
  130. package/dist/chunk-4HP6V2YA.js.map +0 -1
  131. package/dist/chunk-7BUYFVRI.js.map +0 -1
  132. package/dist/chunk-7LMJXF4R.js.map +0 -1
  133. package/dist/chunk-AWAIUYG4.js.map +0 -1
  134. package/dist/chunk-BXVPOGYK.js.map +0 -1
  135. package/dist/chunk-E5FOXRUM.js.map +0 -1
  136. package/dist/chunk-GAPTLVII.js.map +0 -1
  137. package/dist/chunk-IBIMGLCD.js +0 -66
  138. package/dist/chunk-IBIMGLCD.js.map +0 -1
  139. package/dist/chunk-IGY4ASUF.js.map +0 -1
  140. package/dist/chunk-LR4FA5X6.js +0 -368
  141. package/dist/chunk-LR4FA5X6.js.map +0 -1
  142. package/dist/chunk-MATIJPGF.js.map +0 -1
  143. package/dist/chunk-MKHDRIGN.js +0 -71
  144. package/dist/chunk-MKHDRIGN.js.map +0 -1
  145. package/dist/chunk-P72YLKC6.js.map +0 -1
  146. package/dist/chunk-SCLLP5DO.js.map +0 -1
  147. package/dist/chunk-UBDPV34P.js.map +0 -1
  148. package/dist/chunk-VAKFNNKT.js +0 -410
  149. package/dist/chunk-VAKFNNKT.js.map +0 -1
  150. package/dist/chunk-XDV4ZRVK.js.map +0 -1
  151. package/dist/chunk-XW4CVBUH.js.map +0 -1
  152. package/dist/chunk-ZUW4B5AT.js.map +0 -1
  153. package/dist/plan-decision-ops.d.ts +0 -70
  154. package/dist/plan-decision-ops.js +0 -19
  155. package/dist/queued-prompt-runtime.d.ts +0 -115
  156. package/dist/queued-prompt-runtime.js +0 -9
  157. package/dist/uiSettings-BQS9r2eo.d.ts +0 -6
  158. package/dist/workspaceAgentActivityListViewModel-BzV-cf0D.d.ts +0 -340
  159. package/dist/workspaceLinkActions-DS9LWqzI.d.ts +0 -74
  160. /package/dist/{plan-decision-ops.js.map → agent-gui.js.map} +0 -0
  161. /package/dist/{queued-prompt-runtime.js.map → agents.js.map} +0 -0
  162. /package/dist/{chunk-5FE7M42A.js.map → chunk-E4HQUTM3.js.map} +0 -0
  163. /package/dist/{chunk-554VG7ZW.js.map → chunk-QVBF5BN5.js.map} +0 -0
@@ -1,24 +1,198 @@
1
- import {
2
- userAvatarPlaceholderUrl,
3
- workspaceAgentActivityStatusLabel
4
- } from "./chunk-554VG7ZW.js";
5
1
  import {
6
2
  normalizeAgentSessionMentionTitle
7
- } from "./chunk-BXVPOGYK.js";
3
+ } from "./chunk-O3Q5SIJH.js";
8
4
  import {
9
- resolveAgentMentionFileThumbnailUrl,
10
- resolveAgentMentionFileVisualKind
5
+ resolveAgentMentionFileThumbnailUrl
11
6
  } from "./chunk-LUGELG5V.js";
12
- import {
13
- getOptionalAgentHostApi,
14
- managedAgentRoundedIconUrl
15
- } from "./chunk-LR4FA5X6.js";
16
- import {
17
- translate
18
- } from "./chunk-5FE7M42A.js";
19
7
  import {
20
8
  AGENT_CONTEXT_MENTION_PROVIDER_IDS
21
9
  } from "./chunk-JM24HADP.js";
10
+ import {
11
+ getOptionalAgentHostApi
12
+ } from "./chunk-MASXZENX.js";
13
+ import {
14
+ translate
15
+ } from "./chunk-E4HQUTM3.js";
16
+
17
+ // agent-gui/agentGuiNode/AgentMentionLabels.ts
18
+ function agentMentionGroupLabel(groupId) {
19
+ switch (groupId) {
20
+ case "apps":
21
+ return translate("agentHost.agentGui.mentionGroupApps");
22
+ case "agents":
23
+ return translate("agentHost.agentGui.mentionGroupAgents");
24
+ case "files":
25
+ return translate("agentHost.agentGui.mentionGroupFiles");
26
+ case "opened_files":
27
+ return translate("agentHost.agentGui.mentionGroupOpenedFiles");
28
+ case "agent_generated_files":
29
+ return translate("agentHost.agentGui.mentionGroupAgentGeneratedFiles");
30
+ case "my_sessions":
31
+ return translate("agentHost.agentGui.mentionGroupMySessions");
32
+ case "collab_sessions":
33
+ return translate("agentHost.agentGui.mentionGroupCollabSessions");
34
+ case "issues":
35
+ return translate("agentHost.agentGui.mentionGroupIssues");
36
+ }
37
+ }
38
+ function agentMentionFilterLabel(filter) {
39
+ switch (filter) {
40
+ case "app":
41
+ return translate("agentHost.agentGui.mentionFilterApp");
42
+ case "agent":
43
+ return translate("agentHost.agentGui.mentionFilterAgent");
44
+ case "file":
45
+ return translate("agentHost.agentGui.mentionFilterFile");
46
+ case "session":
47
+ return translate("agentHost.agentGui.mentionFilterSession");
48
+ case "issue":
49
+ return translate("agentHost.agentGui.mentionFilterIssue");
50
+ }
51
+ }
52
+ function agentMentionEmptyGroupLabel(groupId, query) {
53
+ if (groupId === "files" || groupId === "opened_files") {
54
+ return query.trim() ? translate("agentHost.agentGui.mentionNoMatchingFiles") : translate("agentHost.agentGui.mentionEmptyDockFiles");
55
+ }
56
+ if (groupId === "agent_generated_files") {
57
+ return query.trim() ? translate("agentHost.agentGui.mentionNoMatchingFiles") : translate("agentHost.agentGui.mentionEmptyAgentGeneratedFiles");
58
+ }
59
+ if (groupId === "apps") {
60
+ return translate("agentHost.agentGui.mentionEmptyApps");
61
+ }
62
+ if (groupId === "agents") {
63
+ return translate("agentHost.agentGui.mentionEmptyAgents");
64
+ }
65
+ if (groupId === "my_sessions") {
66
+ return translate("agentHost.agentGui.mentionEmptyMySessions");
67
+ }
68
+ if (groupId === "collab_sessions") {
69
+ return translate("agentHost.agentGui.mentionEmptyCollabSessions");
70
+ }
71
+ return translate("agentHost.agentGui.mentionEmptyIssues");
72
+ }
73
+
74
+ // shared/richText/richTextDocument.ts
75
+ import { isRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
76
+
77
+ // agent-gui/agentGuiNode/agentMentionSearchHelpers.ts
78
+ import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
79
+ var AGENT_MENTION_FILTER_TAB_ORDER = [
80
+ "session",
81
+ "file",
82
+ "issue",
83
+ "agent",
84
+ "app"
85
+ ];
86
+ var DEFAULT_AGENT_MENTION_FILTER = "session";
87
+ var DEFAULT_MENTION_GROUP_PAGE_SIZE = 10;
88
+ function mentionGroupPageSize(_filter, _groupId) {
89
+ return DEFAULT_MENTION_GROUP_PAGE_SIZE;
90
+ }
91
+ function mentionGroupExpandCount(group, filter) {
92
+ const pageSize = mentionGroupPageSize(
93
+ filter,
94
+ group.id
95
+ );
96
+ const remaining = Math.max(0, group.totalCount - group.visibleCount);
97
+ return Math.min(pageSize, remaining);
98
+ }
99
+ function groupIdsForFilter(filter) {
100
+ switch (filter) {
101
+ case "agent":
102
+ return ["agents"];
103
+ case "app":
104
+ return ["apps"];
105
+ case "file":
106
+ return ["opened_files", "agent_generated_files"];
107
+ case "session":
108
+ return ["my_sessions"];
109
+ case "issue":
110
+ return ["issues"];
111
+ }
112
+ }
113
+ function shouldShowEmptyGroup(groupId, filter, query) {
114
+ const hasQuery = query.trim().length > 0;
115
+ if (groupId === "files") {
116
+ return false;
117
+ }
118
+ if (groupId === "opened_files" || groupId === "agent_generated_files") {
119
+ return filter === "file" && !hasQuery;
120
+ }
121
+ if (groupId === "apps") {
122
+ return filter === "app";
123
+ }
124
+ if (groupId === "agents") {
125
+ return filter === "agent";
126
+ }
127
+ if (groupId === "my_sessions") {
128
+ return filter === "session";
129
+ }
130
+ if (groupId === "collab_sessions") {
131
+ return false;
132
+ }
133
+ return filter === "issue";
134
+ }
135
+ function buildEmptyGroup(groupId, query) {
136
+ return {
137
+ id: groupId,
138
+ items: [],
139
+ totalCount: 0,
140
+ visibleCount: 0,
141
+ hasMore: false,
142
+ emptyLabel: emptyGroupLabel(groupId, query)
143
+ };
144
+ }
145
+ function emptyGroupLabel(groupId, query) {
146
+ return agentMentionEmptyGroupLabel(groupId, query);
147
+ }
148
+ function resolveMentionGroupItems(groupId, rawGroups) {
149
+ if (groupId === "files") {
150
+ return [...rawGroups.opened_files, ...rawGroups.agent_generated_files];
151
+ }
152
+ return rawGroups[groupId] ?? [];
153
+ }
154
+ function resolveMentionGroupTotalCount(groupId, totalCounts, itemCount) {
155
+ if (groupId === "files") {
156
+ return (totalCounts.opened_files ?? 0) + (totalCounts.agent_generated_files ?? 0);
157
+ }
158
+ if (groupId === "agent_generated_files") {
159
+ return itemCount;
160
+ }
161
+ return totalCounts[groupId] ?? itemCount;
162
+ }
163
+ function normalizeQuery(value) {
164
+ return value.replace(/\s+/g, " ").trim();
165
+ }
166
+ function compactText(value) {
167
+ return value?.replace(/\s+/g, " ").trim() ?? "";
168
+ }
169
+
170
+ // agent-gui/agentGuiNode/AgentMentionSearchContracts.ts
171
+ var DEFAULT_DEBOUNCE_MS = 120;
172
+ var DEFAULT_FILE_LIMIT = 30;
173
+ var DEFAULT_ISSUE_LIMIT = 25;
174
+ var DEFAULT_SESSION_LIMIT = 30;
175
+ var DEFAULT_PROVIDER_TIMEOUT_MS = 3500;
176
+ var DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS = 250;
177
+ var DEFAULT_BROWSE_CACHE_TTL_MS = 3e4;
178
+ var AGENT_MENTION_LIFECYCLE_LOG_PREFIX = "[agent-gui] mention-lifecycle";
179
+ function buildBrowseCategories() {
180
+ return AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({
181
+ id,
182
+ label: agentMentionFilterLabel(id)
183
+ }));
184
+ }
185
+ var {
186
+ agentGeneratedFile: AGENT_GENERATED_FILE_PROVIDER_ID,
187
+ agentSession: AGENT_SESSION_PROVIDER_ID,
188
+ agentTarget: AGENT_TARGET_PROVIDER_ID,
189
+ file: FILE_PROVIDER_ID,
190
+ workspaceApp: WORKSPACE_APP_PROVIDER_ID,
191
+ workspaceIssue: WORKSPACE_ISSUE_PROVIDER_ID
192
+ } = AGENT_CONTEXT_MENTION_PROVIDER_IDS;
193
+
194
+ // agent-gui/agentGuiNode/AgentMentionSearchModel.ts
195
+ import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
22
196
 
23
197
  // agent-gui/agentGuiNode/agentMentionAgentGeneratedFilesPresentation.ts
24
198
  var AGENT_GENERATED_FOLDER_MIN_FILES = 2;
@@ -123,106 +297,91 @@ function agentGeneratedMentionItemKey(item) {
123
297
  return item.path;
124
298
  }
125
299
 
126
- // agent-gui/agentGuiNode/agentMentionSearchDiagnostics.ts
127
- var AGENT_MENTION_SEARCH_LOG_PREFIX = "[agent-gui] mention-search";
128
- var {
129
- agentGeneratedFile: AGENT_GENERATED_FILE_PROVIDER_ID,
130
- agentSession: AGENT_SESSION_PROVIDER_ID,
131
- file: FILE_PROVIDER_ID,
132
- workspaceApp: WORKSPACE_APP_PROVIDER_ID,
133
- workspaceIssue: WORKSPACE_ISSUE_PROVIDER_ID
134
- } = AGENT_CONTEXT_MENTION_PROVIDER_IDS;
135
- var AGENT_MENTION_PROVIDER_LOG_ORDER = [
136
- FILE_PROVIDER_ID,
137
- AGENT_GENERATED_FILE_PROVIDER_ID,
138
- WORKSPACE_APP_PROVIDER_ID,
139
- WORKSPACE_ISSUE_PROVIDER_ID,
140
- AGENT_SESSION_PROVIDER_ID
141
- ];
142
- function emitAgentMentionSearchDiagnostic(input) {
143
- const durationMs = elapsedAgentMentionSearchDiagnosticMs(
144
- input.diagnosticNow(),
145
- input.startedAt
146
- );
147
- const providerResults = orderAgentMentionProviderDiagnostics(
148
- input.providerDiagnostics
149
- );
150
- const hasProviderIssue = providerResults.some(
151
- (result) => result.status === "timeout" || result.status === "error"
152
- );
153
- if (input.status === "ready" && !hasProviderIssue && durationMs < input.diagnosticSlowThresholdMs) {
154
- return;
155
- }
156
- const payload = {
157
- debounceMs: input.debounceMs,
158
- durationMs,
159
- ...input.status === "error" ? { errorKind: agentMentionSearchErrorKind(input.error) } : {},
160
- event: "agent_gui.mention_search",
161
- filter: input.filter,
162
- groupCount: input.groups.length,
163
- itemCount: input.groups.reduce((sum, group) => sum + group.items.length, 0),
164
- mode: input.mode,
165
- providerResults,
166
- providerTimeoutMs: input.providerTimeoutMs,
167
- queryLength: [...input.query].length,
168
- requestId: input.requestId,
169
- status: input.status,
170
- workspaceId: input.workspaceId
300
+ // agent-gui/agentGuiNode/AgentMentionSearchModel.ts
301
+ function buildAgentMentionGroups(input) {
302
+ const orderedGroupIds = groupIdsForFilter(input.currentFilter);
303
+ return orderedGroupIds.map((groupId) => {
304
+ const rawItems = resolveMentionGroupItems(groupId, input.rawGroups);
305
+ const items = groupId === "agent_generated_files" ? presentAgentGeneratedFileMentionItems({
306
+ files: rawItems,
307
+ browsePath: input.agentGeneratedBrowsePath,
308
+ query: input.currentQuery
309
+ }) : rawItems;
310
+ if (items.length === 0) {
311
+ if (!shouldShowEmptyGroup(
312
+ groupId,
313
+ input.currentFilter,
314
+ input.currentQuery
315
+ )) {
316
+ return null;
317
+ }
318
+ return buildEmptyGroup(groupId, input.currentQuery);
319
+ }
320
+ const pageSize = mentionGroupPageSize(input.currentFilter, groupId);
321
+ const visibleCount = groupId === "apps" ? items.length : Math.min(items.length, input.expandedCounts[groupId] ?? pageSize);
322
+ const totalCount = resolveMentionGroupTotalCount(
323
+ groupId,
324
+ input.totalCounts,
325
+ items.length
326
+ );
327
+ return {
328
+ id: groupId,
329
+ items: items.slice(0, visibleCount),
330
+ totalCount,
331
+ visibleCount,
332
+ hasMore: groupId !== "apps" && (items.length > visibleCount || (groupId === "opened_files" || groupId === "files" || groupId === "agent_generated_files") && items.length >= input.currentFileSearchLimit || totalCount > visibleCount)
333
+ };
334
+ }).filter((group) => group !== null);
335
+ }
336
+ function emptyAgentMentionRawGroups() {
337
+ return {
338
+ apps: [],
339
+ agents: [],
340
+ opened_files: [],
341
+ agent_generated_files: [],
342
+ my_sessions: [],
343
+ collab_sessions: [],
344
+ issues: []
171
345
  };
172
- try {
173
- input.diagnosticInfoLogger(payload);
174
- } catch {
175
- }
176
346
  }
177
- async function queryAgentMentionProviderWithDiagnostics(input) {
178
- if (!input.query) {
179
- input.diagnostics.push({
180
- durationMs: 0,
181
- providerId: input.providerId,
182
- resultCount: 0,
183
- status: "missing"
184
- });
185
- return input.fallback;
186
- }
187
- const startedAt = input.diagnosticNow();
188
- try {
189
- const { result, timedOut } = await runAgentMentionProviderQuery({
190
- fallback: input.fallback,
191
- providerTimeoutMs: input.providerTimeoutMs,
192
- query: input.query
193
- });
194
- input.diagnostics.push({
195
- durationMs: elapsedAgentMentionSearchDiagnosticMs(
196
- input.diagnosticNow(),
197
- startedAt
198
- ),
199
- providerId: input.providerId,
200
- resultCount: input.resultCount(result),
201
- status: timedOut ? "timeout" : "success"
202
- });
203
- return result;
204
- } catch (error) {
205
- input.diagnostics.push({
206
- durationMs: elapsedAgentMentionSearchDiagnosticMs(
207
- input.diagnosticNow(),
208
- startedAt
209
- ),
210
- errorKind: agentMentionSearchErrorKind(error),
211
- providerId: input.providerId,
212
- resultCount: 0,
213
- status: "error"
214
- });
215
- throw error;
216
- }
347
+ function cloneAgentMentionRawGroups(rawGroups) {
348
+ return {
349
+ apps: [...rawGroups.apps],
350
+ agents: [...rawGroups.agents],
351
+ opened_files: [...rawGroups.opened_files],
352
+ agent_generated_files: [...rawGroups.agent_generated_files],
353
+ my_sessions: [...rawGroups.my_sessions],
354
+ collab_sessions: [...rawGroups.collab_sessions],
355
+ issues: [...rawGroups.issues]
356
+ };
217
357
  }
218
- function elapsedAgentMentionSearchDiagnosticMs(now, startedAt) {
358
+ function totalCountsFromRawGroups(rawGroups) {
359
+ return {
360
+ apps: rawGroups.apps.length,
361
+ agents: rawGroups.agents.length,
362
+ opened_files: rawGroups.opened_files.length,
363
+ agent_generated_files: rawGroups.agent_generated_files.length,
364
+ my_sessions: rawGroups.my_sessions.length,
365
+ collab_sessions: rawGroups.collab_sessions.length,
366
+ issues: rawGroups.issues.length
367
+ };
368
+ }
369
+ function rawGroupItemCount(rawGroups) {
370
+ return Object.values(rawGroups).reduce(
371
+ (count, items) => count + items.length,
372
+ 0
373
+ );
374
+ }
375
+ function providerDiagnosticsSummary(diagnostics) {
376
+ return diagnostics.map(
377
+ (diagnostic) => `${diagnostic.providerId}:${diagnostic.status}:${diagnostic.resultCount}:${diagnostic.durationMs}`
378
+ ).join(",");
379
+ }
380
+ function elapsedDiagnosticMs(now, startedAt) {
219
381
  const durationMs = now - startedAt;
220
- if (!Number.isFinite(durationMs)) {
221
- return 0;
222
- }
223
- return Math.max(0, Math.round(durationMs));
382
+ return Number.isFinite(durationMs) ? Math.max(0, Math.round(durationMs)) : 0;
224
383
  }
225
- function agentMentionSearchErrorKind(error) {
384
+ function diagnosticErrorKind(error) {
226
385
  if (error instanceof Error && error.name.trim()) {
227
386
  return error.name.trim();
228
387
  }
@@ -231,220 +390,198 @@ function agentMentionSearchErrorKind(error) {
231
390
  }
232
391
  return typeof error;
233
392
  }
234
- function logAgentMentionSearchInfo(payload) {
235
- console.info(AGENT_MENTION_SEARCH_LOG_PREFIX, JSON.stringify(payload));
236
- }
237
- function orderAgentMentionProviderDiagnostics(diagnostics) {
238
- return [...diagnostics].sort((left, right) => {
239
- const leftIndex = providerDiagnosticOrder(left.providerId);
240
- const rightIndex = providerDiagnosticOrder(right.providerId);
241
- return leftIndex - rightIndex || left.providerId.localeCompare(right.providerId);
242
- });
243
- }
244
- function providerDiagnosticOrder(providerId) {
245
- const index = AGENT_MENTION_PROVIDER_LOG_ORDER.indexOf(providerId);
246
- return index === -1 ? AGENT_MENTION_PROVIDER_LOG_ORDER.length : index;
247
- }
248
- async function runAgentMentionProviderQuery(input) {
249
- const abortController = new AbortController();
250
- let timedOut = false;
251
- const queryPromise = Promise.resolve().then(
252
- () => input.query(abortController.signal)
253
- );
254
- const queryResultPromise = queryPromise.then(
255
- (result) => ({ result, timedOut: false }),
256
- (error) => {
257
- if (timedOut && abortController.signal.aborted) {
258
- return { result: input.fallback, timedOut: true };
259
- }
260
- throw error;
261
- }
262
- );
263
- if (input.providerTimeoutMs <= 0 || !Number.isFinite(input.providerTimeoutMs)) {
264
- return queryResultPromise;
393
+ function logAgentMentionLifecycleDiagnostic(payload) {
394
+ try {
395
+ console.info(AGENT_MENTION_LIFECYCLE_LOG_PREFIX, JSON.stringify(payload));
396
+ } catch (logError) {
397
+ console.error(
398
+ "[agent-gui] logAgentMentionLifecycleDiagnostic console.info failed",
399
+ logError
400
+ );
265
401
  }
266
- let timeout = null;
267
- const timeoutPromise = new Promise(
268
- (resolve) => {
269
- timeout = setTimeout(() => {
270
- timedOut = true;
271
- abortController.abort();
272
- resolve({ result: input.fallback, timedOut: true });
273
- }, input.providerTimeoutMs);
274
- }
275
- );
276
402
  try {
277
- return await Promise.race([queryResultPromise, timeoutPromise]);
278
- } finally {
279
- if (timeout !== null) {
280
- clearTimeout(timeout);
281
- }
403
+ getOptionalAgentHostApi()?.debug?.logRuntimeDiagnostics?.({
404
+ source: "renderer-workspace-surface",
405
+ level: "info",
406
+ event: `agent-gui.mention.${payload.event}`,
407
+ // i18n-check-ignore: Internal diagnostic log message.
408
+ message: "Agent GUI mention search lifecycle event.",
409
+ details: payload.details
410
+ });
411
+ } catch (logError) {
412
+ console.error(
413
+ "[agent-gui] logAgentMentionLifecycleDiagnostic host diagnostics failed",
414
+ logError
415
+ );
282
416
  }
283
417
  }
284
-
285
- // agent-gui/agentGuiNode/AgentMentionLabels.ts
286
- function agentMentionGroupLabel(groupId) {
287
- switch (groupId) {
288
- case "apps":
289
- return translate("agentHost.agentGui.mentionGroupApps");
290
- case "agents":
291
- return translate("agentHost.agentGui.mentionGroupAgents");
292
- case "files":
293
- return translate("agentHost.agentGui.mentionGroupFiles");
294
- case "opened_files":
295
- return translate("agentHost.agentGui.mentionGroupOpenedFiles");
296
- case "agent_generated_files":
297
- return translate("agentHost.agentGui.mentionGroupAgentGeneratedFiles");
298
- case "my_sessions":
299
- return translate("agentHost.agentGui.mentionGroupMySessions");
300
- case "collab_sessions":
301
- return translate("agentHost.agentGui.mentionGroupCollabSessions");
302
- case "issues":
303
- return translate("agentHost.agentGui.mentionGroupIssues");
304
- }
418
+ function normalizeSessionMentionItemsForMySessions(input) {
419
+ return input.items.filter((item) => item.kind === "session").filter(
420
+ (item) => input.currentUserId ? item.scope === "my_sessions" : true
421
+ ).map(
422
+ (item) => item.scope === "my_sessions" ? item : { ...item, scope: "my_sessions" }
423
+ );
305
424
  }
306
- function agentMentionFilterLabel(filter) {
307
- switch (filter) {
308
- case "app":
309
- return translate("agentHost.agentGui.mentionFilterApp");
310
- case "agent":
311
- return translate("agentHost.agentGui.mentionFilterAgent");
312
- case "file":
313
- return translate("agentHost.agentGui.mentionFilterFile");
314
- case "session":
315
- return translate("agentHost.agentGui.mentionFilterSession");
316
- case "issue":
317
- return translate("agentHost.agentGui.mentionFilterIssue");
425
+ function providerItemToAgentMentionItem(input) {
426
+ const label = compactText(input.label);
427
+ if (!label) {
428
+ return null;
318
429
  }
319
- }
320
- function agentMentionEmptyGroupLabel(groupId, query) {
321
- if (groupId === "files" || groupId === "opened_files") {
322
- return query.trim() ? translate("agentHost.agentGui.mentionNoMatchingFiles") : translate("agentHost.agentGui.mentionEmptyDockFiles");
430
+ if (input.insertResult.kind === "markdown-link") {
431
+ const href = input.insertResult.href.trim();
432
+ return {
433
+ kind: "file",
434
+ href,
435
+ path: href,
436
+ name: label,
437
+ entryKind: href.endsWith("/") ? "directory" : "unknown",
438
+ directoryPath: dirnameFromProviderWorkspaceFileHref(href)
439
+ };
323
440
  }
324
- if (groupId === "agent_generated_files") {
325
- return query.trim() ? translate("agentHost.agentGui.mentionNoMatchingFiles") : translate("agentHost.agentGui.mentionEmptyAgentGeneratedFiles");
441
+ if (input.insertResult.kind !== "mention") {
442
+ return null;
326
443
  }
327
- if (groupId === "apps") {
328
- return translate("agentHost.agentGui.mentionEmptyApps");
444
+ const mention = input.insertResult.mention;
445
+ const targetId = mention.entityId.trim();
446
+ if (!targetId) {
447
+ return null;
329
448
  }
330
- if (groupId === "agents") {
331
- return translate("agentHost.agentGui.mentionEmptyAgents");
449
+ const scope = normalizeMentionScope(mention.scope);
450
+ const presentation = mention.presentation ?? {};
451
+ const workspaceId = scope.workspaceId || input.workspaceId;
452
+ if (input.providerId === FILE_PROVIDER_ID || input.providerId === AGENT_GENERATED_FILE_PROVIDER_ID) {
453
+ return {
454
+ kind: "file",
455
+ href: createRichTextMentionHref2({
456
+ providerId: input.providerId,
457
+ entityId: targetId,
458
+ label,
459
+ scope
460
+ }),
461
+ path: targetId,
462
+ name: label,
463
+ entryKind: targetId.endsWith("/") ? "directory" : "unknown",
464
+ directoryPath: dirnameFromProviderWorkspaceFileHref(targetId),
465
+ thumbnailUrl: presentation.thumbnailUrl?.trim() || void 0
466
+ };
332
467
  }
333
- if (groupId === "my_sessions") {
334
- return translate("agentHost.agentGui.mentionEmptyMySessions");
468
+ if (input.providerId === WORKSPACE_ISSUE_PROVIDER_ID) {
469
+ return {
470
+ kind: "workspace-issue",
471
+ href: createRichTextMentionHref2({
472
+ providerId: "workspace-issue",
473
+ entityId: targetId,
474
+ label,
475
+ scope: {
476
+ workspaceId,
477
+ ...scope.topicId ? { topicId: scope.topicId } : {}
478
+ }
479
+ }),
480
+ workspaceId,
481
+ targetId,
482
+ topicId: scope.topicId,
483
+ name: label,
484
+ title: label,
485
+ status: presentation.status?.trim() || void 0,
486
+ contentPreview: compactText(presentation.description) || compactText(input.subtitle) || void 0
487
+ };
335
488
  }
336
- if (groupId === "collab_sessions") {
337
- return translate("agentHost.agentGui.mentionEmptyCollabSessions");
489
+ if (input.providerId === WORKSPACE_APP_PROVIDER_ID) {
490
+ const appId = targetId;
491
+ return {
492
+ kind: "workspace-app",
493
+ href: createRichTextMentionHref2({
494
+ providerId: "workspace-app",
495
+ entityId: appId,
496
+ label,
497
+ scope: { workspaceId }
498
+ }),
499
+ workspaceId,
500
+ targetId: appId,
501
+ appId,
502
+ name: label,
503
+ description: compactText(presentation.description) || compactText(presentation.subtitle) || compactText(input.subtitle) || void 0,
504
+ iconUrl: presentation.iconUrl?.trim() || void 0,
505
+ referencesListSupported: presentation.referencesListSupported === "true"
506
+ };
338
507
  }
339
- return translate("agentHost.agentGui.mentionEmptyIssues");
340
- }
341
-
342
- // shared/richText/richTextDocument.ts
343
- import { isRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
344
-
345
- // agent-gui/agentGuiNode/agentMentionSearchHelpers.ts
346
- import { createRichTextMentionHref } from "@tutti-os/ui-rich-text/core";
347
- var AGENT_MENTION_FILTER_TAB_ORDER = [
348
- "session",
349
- "file",
350
- "issue",
351
- "agent",
352
- "app"
353
- ];
354
- var DEFAULT_AGENT_MENTION_FILTER = "session";
355
- var DEFAULT_MENTION_GROUP_PAGE_SIZE = 10;
356
- function mentionGroupPageSize(_filter, _groupId) {
357
- return DEFAULT_MENTION_GROUP_PAGE_SIZE;
358
- }
359
- function mentionGroupExpandCount(group, filter) {
360
- const pageSize = mentionGroupPageSize(
361
- filter,
362
- group.id
363
- );
364
- const remaining = Math.max(0, group.totalCount - group.visibleCount);
365
- return Math.min(pageSize, remaining);
366
- }
367
- function groupIdsForFilter(filter) {
368
- switch (filter) {
369
- case "agent":
370
- return ["agents"];
371
- case "app":
372
- return ["apps"];
373
- case "file":
374
- return ["opened_files", "agent_generated_files"];
375
- case "session":
376
- return ["my_sessions"];
377
- case "issue":
378
- return ["issues"];
379
- }
380
- }
381
- function shouldShowEmptyGroup(groupId, filter, query) {
382
- const hasQuery = query.trim().length > 0;
383
- if (groupId === "files") {
384
- return false;
385
- }
386
- if (groupId === "opened_files" || groupId === "agent_generated_files") {
387
- return filter === "file" && !hasQuery;
388
- }
389
- if (groupId === "apps") {
390
- return filter === "app";
391
- }
392
- if (groupId === "agents") {
393
- return filter === "agent";
394
- }
395
- if (groupId === "my_sessions") {
396
- return filter === "session";
508
+ if (input.providerId === AGENT_TARGET_PROVIDER_ID) {
509
+ const agentProviderId = presentation.agentProviderId?.trim() || void 0;
510
+ return {
511
+ kind: "agent-target",
512
+ href: createRichTextMentionHref2({
513
+ providerId: "agent-target",
514
+ entityId: targetId,
515
+ label,
516
+ scope: { workspaceId }
517
+ }),
518
+ workspaceId,
519
+ targetId,
520
+ name: label,
521
+ description: compactText(presentation.description) || compactText(presentation.subtitle) || compactText(input.subtitle) || void 0,
522
+ agentProviderId,
523
+ iconUrl: presentation.iconUrl?.trim() || void 0
524
+ };
397
525
  }
398
- if (groupId === "collab_sessions") {
399
- return false;
526
+ if (input.providerId === AGENT_SESSION_PROVIDER_ID) {
527
+ const agentName = presentation.subtitle?.trim() || "";
528
+ const title = normalizeAgentSessionMentionTitle(label) || label;
529
+ const description = compactText(presentation.description);
530
+ const summaryPreview = description || compactText(input.subtitle) || void 0;
531
+ return {
532
+ kind: "session",
533
+ href: createRichTextMentionHref2({
534
+ providerId: "agent-session",
535
+ entityId: targetId,
536
+ label,
537
+ scope: { workspaceId }
538
+ }),
539
+ workspaceId,
540
+ targetId,
541
+ name: label,
542
+ title,
543
+ scope: mentionSessionScope({
544
+ currentUserId: input.currentUserId,
545
+ rawScope: scope.scope,
546
+ userId: scope.userId
547
+ }),
548
+ initiatorName: "",
549
+ agentName,
550
+ agentIconUrl: presentation.agentIconUrl?.trim() || presentation.iconUrl?.trim() || void 0,
551
+ status: presentation.status?.trim() || void 0,
552
+ inputPreview: description || void 0,
553
+ summaryPreview
554
+ };
400
555
  }
401
- return filter === "issue";
402
- }
403
- function buildEmptyGroup(groupId, query) {
404
- return {
405
- id: groupId,
406
- items: [],
407
- totalCount: 0,
408
- visibleCount: 0,
409
- hasMore: false,
410
- emptyLabel: emptyGroupLabel(groupId, query)
411
- };
412
- }
413
- function emptyGroupLabel(groupId, query) {
414
- return agentMentionEmptyGroupLabel(groupId, query);
556
+ return null;
415
557
  }
416
- function resolveMentionGroupItems(groupId, rawGroups) {
417
- if (groupId === "files") {
418
- return [...rawGroups.opened_files, ...rawGroups.agent_generated_files];
419
- }
420
- return rawGroups[groupId] ?? [];
558
+ function normalizeMentionScope(scope) {
559
+ return Object.fromEntries(
560
+ Object.entries(scope ?? {}).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0)
561
+ );
421
562
  }
422
- function resolveMentionGroupTotalCount(groupId, totalCounts, itemCount) {
423
- if (groupId === "files") {
424
- return (totalCounts.opened_files ?? 0) + (totalCounts.agent_generated_files ?? 0);
563
+ function mentionSessionScope(input) {
564
+ const rawScope = input.rawScope?.trim() ?? "";
565
+ if (rawScope === "my_sessions" || rawScope === "collab_sessions") {
566
+ return rawScope;
425
567
  }
426
- if (groupId === "agent_generated_files") {
427
- return itemCount;
568
+ const userId = input.userId?.trim() ?? "";
569
+ const currentUserId = input.currentUserId.trim();
570
+ if (!userId || !currentUserId || userId === "local" || currentUserId === "local") {
571
+ return "my_sessions";
428
572
  }
429
- return totalCounts[groupId] ?? itemCount;
430
- }
431
- function normalizeQuery(value) {
432
- return value.replace(/\s+/g, " ").trim();
573
+ return userId === currentUserId ? "my_sessions" : "collab_sessions";
433
574
  }
434
- function compactText(value) {
435
- return value?.replace(/\s+/g, " ").trim() ?? "";
575
+ function dirnameFromProviderWorkspaceFileHref(href) {
576
+ const normalized = href.replace(/\/+$/, "");
577
+ const index = normalized.lastIndexOf("/");
578
+ if (index <= 0) {
579
+ return "/";
580
+ }
581
+ return normalized.slice(0, index);
436
582
  }
437
583
 
438
- // agent-gui/agentGuiNode/AgentMentionSearchController.ts
439
- import { createRichTextMentionHref as createRichTextMentionHref2 } from "@tutti-os/ui-rich-text/core";
440
- var DEFAULT_DEBOUNCE_MS = 120;
441
- var DEFAULT_FILE_LIMIT = 30;
442
- var DEFAULT_ISSUE_LIMIT = 25;
443
- var DEFAULT_SESSION_LIMIT = 30;
444
- var DEFAULT_PROVIDER_TIMEOUT_MS = 3500;
445
- var DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS = 250;
446
- var DEFAULT_BROWSE_CACHE_TTL_MS = 3e4;
447
- var AGENT_MENTION_LIFECYCLE_LOG_PREFIX = "[agent-gui] mention-lifecycle";
584
+ // agent-gui/agentGuiNode/AgentMentionSearchCache.ts
448
585
  var sharedAgentMentionBrowseCache = /* @__PURE__ */ new Map();
449
586
  var sharedAgentMentionBrowseFetches = /* @__PURE__ */ new Map();
450
587
  var MAX_BROWSE_CACHE_ENTRIES = 64;
@@ -459,7 +596,7 @@ function writeBrowseCacheEntry(cacheKey, entry) {
459
596
  sharedAgentMentionBrowseCache.delete(oldestKey);
460
597
  }
461
598
  }
462
- function scheduleIdleTask(task) {
599
+ function scheduleAgentMentionIdleTask(task) {
463
600
  const scope = globalThis;
464
601
  if (typeof scope.requestIdleCallback === "function") {
465
602
  const handle2 = scope.requestIdleCallback(() => task(), { timeout: 500 });
@@ -473,57 +610,436 @@ function resetAgentMentionSearchBrowseCacheForTests() {
473
610
  sharedAgentMentionBrowseFetches.clear();
474
611
  }
475
612
  globalThis.__tuttiResetAgentMentionSearchBrowseCacheForTests = resetAgentMentionSearchBrowseCacheForTests;
476
- function buildBrowseCategories() {
477
- return AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({
478
- id,
479
- label: agentMentionFilterLabel(id)
480
- }));
613
+ async function loadAgentMentionBrowseFetchResult(input) {
614
+ const { cacheKey, reason } = input;
615
+ const browseInput = input.input;
616
+ const existingFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
617
+ if (existingFetch) {
618
+ input.logLifecycle("browse.fetch.dedupe", {
619
+ filter: browseInput.filter,
620
+ reason,
621
+ workspaceId: browseInput.workspaceId
622
+ });
623
+ return existingFetch;
624
+ }
625
+ const startedAt = input.diagnosticNow();
626
+ input.logLifecycle("browse.fetch.start", {
627
+ filter: browseInput.filter,
628
+ providerIds: input.providerIds,
629
+ reason,
630
+ workspaceId: browseInput.workspaceId
631
+ });
632
+ const fetchPromise = input.fetchBrowseResult().then((result) => {
633
+ writeBrowseCacheEntry(cacheKey, {
634
+ ...result,
635
+ cachedAt: input.diagnosticNow()
636
+ });
637
+ input.logLifecycle("browse.fetch.success", {
638
+ durationMs: elapsedDiagnosticMs(input.diagnosticNow(), startedAt),
639
+ filter: browseInput.filter,
640
+ itemCount: rawGroupItemCount(result.rawGroups),
641
+ providerResults: providerDiagnosticsSummary(result.providerDiagnostics),
642
+ reason,
643
+ workspaceId: browseInput.workspaceId
644
+ });
645
+ return result;
646
+ }).finally(() => {
647
+ if (sharedAgentMentionBrowseFetches.get(cacheKey) === fetchPromise) {
648
+ sharedAgentMentionBrowseFetches.delete(cacheKey);
649
+ }
650
+ });
651
+ sharedAgentMentionBrowseFetches.set(cacheKey, fetchPromise);
652
+ return fetchPromise;
653
+ }
654
+ function readAgentMentionBrowseCache(input) {
655
+ const entry = sharedAgentMentionBrowseCache.get(input.cacheKey);
656
+ if (!entry) {
657
+ return { entry: null, isFresh: false };
658
+ }
659
+ sharedAgentMentionBrowseCache.delete(input.cacheKey);
660
+ sharedAgentMentionBrowseCache.set(input.cacheKey, entry);
661
+ const ageMs = input.diagnosticNow() - entry.cachedAt;
662
+ const isFresh = input.browseCacheTtlMs >= 0 && Number.isFinite(input.browseCacheTtlMs) && ageMs <= input.browseCacheTtlMs;
663
+ return { entry, isFresh };
664
+ }
665
+ function buildAgentMentionBrowseCacheKey(input) {
666
+ return JSON.stringify({
667
+ workspaceId: input.workspaceId,
668
+ currentUserId: input.currentUserId,
669
+ sessionCwd: input.sessionCwd,
670
+ filter: input.filter,
671
+ fileLimit: input.fileLimit,
672
+ issueLimit: input.issueLimit,
673
+ providerIds: input.providerIds
674
+ });
481
675
  }
676
+
677
+ // agent-gui/agentGuiNode/agentMentionSearchDiagnostics.ts
678
+ var AGENT_MENTION_SEARCH_LOG_PREFIX = "[agent-gui] mention-search";
482
679
  var {
483
680
  agentGeneratedFile: AGENT_GENERATED_FILE_PROVIDER_ID2,
484
681
  agentSession: AGENT_SESSION_PROVIDER_ID2,
485
- agentTarget: AGENT_TARGET_PROVIDER_ID,
486
682
  file: FILE_PROVIDER_ID2,
487
683
  workspaceApp: WORKSPACE_APP_PROVIDER_ID2,
488
684
  workspaceIssue: WORKSPACE_ISSUE_PROVIDER_ID2
489
685
  } = AGENT_CONTEXT_MENTION_PROVIDER_IDS;
490
- var AgentMentionSearchController = class {
491
- contextMentionProviders;
492
- debounceMs;
493
- fileLimit;
494
- issueLimit;
495
- browseCacheTtlMs;
496
- providerTimeoutMs;
497
- diagnosticInfoLogger;
498
- diagnosticNow;
499
- diagnosticSlowThresholdMs;
500
- listeners = /* @__PURE__ */ new Set();
501
- expandedCounts = {};
502
- totalCounts = {};
503
- timer = null;
504
- preloadCancel = null;
505
- pendingPreloadKey = null;
506
- requestId = 0;
507
- disposed = false;
508
- activeWorkspaceId = "";
509
- currentUserId = "";
510
- currentFilter = DEFAULT_AGENT_MENTION_FILTER;
511
- currentQuery = "";
512
- currentSessionCwd = "";
513
- currentFileSearchLimit;
514
- currentIssueSearchLimit;
515
- agentGeneratedBrowsePath = null;
516
- rawGroups = emptyAgentMentionRawGroups();
517
- state = {
518
- status: "idle",
519
- query: "",
520
- mode: "browse",
521
- filter: DEFAULT_AGENT_MENTION_FILTER,
522
- categories: buildBrowseCategories(),
523
- groups: [],
524
- error: null
686
+ var AGENT_MENTION_PROVIDER_LOG_ORDER = [
687
+ FILE_PROVIDER_ID2,
688
+ AGENT_GENERATED_FILE_PROVIDER_ID2,
689
+ WORKSPACE_APP_PROVIDER_ID2,
690
+ WORKSPACE_ISSUE_PROVIDER_ID2,
691
+ AGENT_SESSION_PROVIDER_ID2
692
+ ];
693
+ function emitAgentMentionSearchDiagnostic(input) {
694
+ const durationMs = elapsedAgentMentionSearchDiagnosticMs(
695
+ input.diagnosticNow(),
696
+ input.startedAt
697
+ );
698
+ const providerResults = orderAgentMentionProviderDiagnostics(
699
+ input.providerDiagnostics
700
+ );
701
+ const hasProviderIssue = providerResults.some(
702
+ (result) => result.status === "timeout" || result.status === "error"
703
+ );
704
+ if (input.status === "ready" && !hasProviderIssue && durationMs < input.diagnosticSlowThresholdMs) {
705
+ return;
706
+ }
707
+ const payload = {
708
+ debounceMs: input.debounceMs,
709
+ durationMs,
710
+ ...input.status === "error" ? { errorKind: agentMentionSearchErrorKind(input.error) } : {},
711
+ event: "agent_gui.mention_search",
712
+ filter: input.filter,
713
+ groupCount: input.groups.length,
714
+ itemCount: input.groups.reduce((sum, group) => sum + group.items.length, 0),
715
+ mode: input.mode,
716
+ providerResults,
717
+ providerTimeoutMs: input.providerTimeoutMs,
718
+ queryLength: [...input.query].length,
719
+ requestId: input.requestId,
720
+ status: input.status,
721
+ workspaceId: input.workspaceId
525
722
  };
526
- constructor(options) {
723
+ try {
724
+ input.diagnosticInfoLogger(payload);
725
+ } catch {
726
+ }
727
+ }
728
+ async function queryAgentMentionProviderWithDiagnostics(input) {
729
+ if (!input.query) {
730
+ input.diagnostics.push({
731
+ durationMs: 0,
732
+ providerId: input.providerId,
733
+ resultCount: 0,
734
+ status: "missing"
735
+ });
736
+ return input.fallback;
737
+ }
738
+ const startedAt = input.diagnosticNow();
739
+ try {
740
+ const { result, timedOut } = await runAgentMentionProviderQuery({
741
+ fallback: input.fallback,
742
+ providerTimeoutMs: input.providerTimeoutMs,
743
+ query: input.query
744
+ });
745
+ input.diagnostics.push({
746
+ durationMs: elapsedAgentMentionSearchDiagnosticMs(
747
+ input.diagnosticNow(),
748
+ startedAt
749
+ ),
750
+ providerId: input.providerId,
751
+ resultCount: input.resultCount(result),
752
+ status: timedOut ? "timeout" : "success"
753
+ });
754
+ return result;
755
+ } catch (error) {
756
+ input.diagnostics.push({
757
+ durationMs: elapsedAgentMentionSearchDiagnosticMs(
758
+ input.diagnosticNow(),
759
+ startedAt
760
+ ),
761
+ errorKind: agentMentionSearchErrorKind(error),
762
+ providerId: input.providerId,
763
+ resultCount: 0,
764
+ status: "error"
765
+ });
766
+ throw error;
767
+ }
768
+ }
769
+ function elapsedAgentMentionSearchDiagnosticMs(now, startedAt) {
770
+ const durationMs = now - startedAt;
771
+ if (!Number.isFinite(durationMs)) {
772
+ return 0;
773
+ }
774
+ return Math.max(0, Math.round(durationMs));
775
+ }
776
+ function agentMentionSearchErrorKind(error) {
777
+ if (error instanceof Error && error.name.trim()) {
778
+ return error.name.trim();
779
+ }
780
+ if (error === null) {
781
+ return "null";
782
+ }
783
+ return typeof error;
784
+ }
785
+ function logAgentMentionSearchInfo(payload) {
786
+ console.info(AGENT_MENTION_SEARCH_LOG_PREFIX, JSON.stringify(payload));
787
+ }
788
+ function orderAgentMentionProviderDiagnostics(diagnostics) {
789
+ return [...diagnostics].sort((left, right) => {
790
+ const leftIndex = providerDiagnosticOrder(left.providerId);
791
+ const rightIndex = providerDiagnosticOrder(right.providerId);
792
+ return leftIndex - rightIndex || left.providerId.localeCompare(right.providerId);
793
+ });
794
+ }
795
+ function providerDiagnosticOrder(providerId) {
796
+ const index = AGENT_MENTION_PROVIDER_LOG_ORDER.indexOf(providerId);
797
+ return index === -1 ? AGENT_MENTION_PROVIDER_LOG_ORDER.length : index;
798
+ }
799
+ async function runAgentMentionProviderQuery(input) {
800
+ const abortController = new AbortController();
801
+ let timedOut = false;
802
+ const queryPromise = Promise.resolve().then(
803
+ () => input.query(abortController.signal)
804
+ );
805
+ const queryResultPromise = queryPromise.then(
806
+ (result) => ({ result, timedOut: false }),
807
+ (error) => {
808
+ if (timedOut && abortController.signal.aborted) {
809
+ return { result: input.fallback, timedOut: true };
810
+ }
811
+ throw error;
812
+ }
813
+ );
814
+ if (input.providerTimeoutMs <= 0 || !Number.isFinite(input.providerTimeoutMs)) {
815
+ return queryResultPromise;
816
+ }
817
+ let timeout = null;
818
+ const timeoutPromise = new Promise(
819
+ (resolve) => {
820
+ timeout = setTimeout(() => {
821
+ timedOut = true;
822
+ abortController.abort();
823
+ resolve({ result: input.fallback, timedOut: true });
824
+ }, input.providerTimeoutMs);
825
+ }
826
+ );
827
+ try {
828
+ return await Promise.race([queryResultPromise, timeoutPromise]);
829
+ } finally {
830
+ if (timeout !== null) {
831
+ clearTimeout(timeout);
832
+ }
833
+ }
834
+ }
835
+
836
+ // agent-gui/agentGuiNode/AgentMentionSearchIndex.ts
837
+ async function fetchAgentMentionFilterResult(input) {
838
+ const providerDiagnostics = [];
839
+ switch (input.filter) {
840
+ case "file": {
841
+ const fileQuery = input.queryProviderMentionItemsById({
842
+ providerId: FILE_PROVIDER_ID,
843
+ workspaceId: input.workspaceId,
844
+ currentUserId: input.currentUserId,
845
+ query: input.query,
846
+ limit: input.query ? input.currentFileSearchLimit : input.fileLimit,
847
+ sessionCwd: input.sessionCwd,
848
+ diagnostics: providerDiagnostics
849
+ });
850
+ const agentGeneratedFileQuery = input.includeAgentGeneratedFiles ? input.queryProviderMentionItemsById({
851
+ providerId: AGENT_GENERATED_FILE_PROVIDER_ID,
852
+ workspaceId: input.workspaceId,
853
+ currentUserId: input.currentUserId,
854
+ query: input.query,
855
+ limit: input.fileLimit,
856
+ sessionCwd: input.sessionCwd,
857
+ diagnostics: providerDiagnostics
858
+ }) : Promise.resolve([]);
859
+ const [fileItems, agentGeneratedFileItems] = await Promise.all([
860
+ fileQuery,
861
+ agentGeneratedFileQuery
862
+ ]);
863
+ const rawGroups = emptyAgentMentionRawGroups();
864
+ rawGroups.opened_files = fileItems.filter((item) => item.kind === "file");
865
+ rawGroups.agent_generated_files = agentGeneratedFileItems.filter(
866
+ (item) => item.kind === "file"
867
+ );
868
+ return {
869
+ providerDiagnostics,
870
+ rawGroups,
871
+ totalCounts: totalCountsFromRawGroups(rawGroups)
872
+ };
873
+ }
874
+ case "session": {
875
+ const sessionItems = await input.queryProviderMentionItemsById({
876
+ providerId: AGENT_SESSION_PROVIDER_ID,
877
+ workspaceId: input.workspaceId,
878
+ currentUserId: input.currentUserId,
879
+ query: input.query,
880
+ limit: DEFAULT_SESSION_LIMIT,
881
+ sessionCwd: input.sessionCwd,
882
+ diagnostics: providerDiagnostics
883
+ });
884
+ const rawGroups = emptyAgentMentionRawGroups();
885
+ rawGroups.my_sessions = normalizeSessionMentionItemsForMySessions({
886
+ currentUserId: input.currentUserId,
887
+ items: sessionItems
888
+ });
889
+ return {
890
+ providerDiagnostics,
891
+ rawGroups,
892
+ totalCounts: totalCountsFromRawGroups(rawGroups)
893
+ };
894
+ }
895
+ case "issue": {
896
+ const issueItems = await input.queryProviderMentionItemsById({
897
+ providerId: WORKSPACE_ISSUE_PROVIDER_ID,
898
+ workspaceId: input.workspaceId,
899
+ currentUserId: input.currentUserId,
900
+ query: input.query,
901
+ limit: input.currentIssueSearchLimit,
902
+ sessionCwd: input.sessionCwd,
903
+ diagnostics: providerDiagnostics
904
+ });
905
+ const rawGroups = emptyAgentMentionRawGroups();
906
+ rawGroups.issues = issueItems.filter(
907
+ (item) => item.kind === "workspace-issue"
908
+ );
909
+ return {
910
+ providerDiagnostics,
911
+ rawGroups,
912
+ totalCounts: totalCountsFromRawGroups(rawGroups)
913
+ };
914
+ }
915
+ case "agent": {
916
+ const agentItems = await input.queryProviderMentionItemsById({
917
+ providerId: AGENT_TARGET_PROVIDER_ID,
918
+ workspaceId: input.workspaceId,
919
+ currentUserId: input.currentUserId,
920
+ query: input.query,
921
+ sessionCwd: input.sessionCwd,
922
+ diagnostics: providerDiagnostics
923
+ });
924
+ const rawGroups = emptyAgentMentionRawGroups();
925
+ rawGroups.agents = agentItems.filter(
926
+ (item) => item.kind === "agent-target"
927
+ );
928
+ return {
929
+ providerDiagnostics,
930
+ rawGroups,
931
+ totalCounts: totalCountsFromRawGroups(rawGroups)
932
+ };
933
+ }
934
+ case "app": {
935
+ const appItems = await input.queryProviderMentionItemsById({
936
+ providerId: WORKSPACE_APP_PROVIDER_ID,
937
+ workspaceId: input.workspaceId,
938
+ currentUserId: input.currentUserId,
939
+ query: input.query,
940
+ sessionCwd: input.sessionCwd,
941
+ diagnostics: providerDiagnostics
942
+ });
943
+ const rawGroups = emptyAgentMentionRawGroups();
944
+ rawGroups.apps = appItems.filter((item) => item.kind === "workspace-app");
945
+ return {
946
+ providerDiagnostics,
947
+ rawGroups,
948
+ totalCounts: totalCountsFromRawGroups(rawGroups)
949
+ };
950
+ }
951
+ }
952
+ }
953
+ async function queryAgentMentionProviderItems(input) {
954
+ const items = await input.provider.query({
955
+ keyword: input.query,
956
+ maxResults: input.limit,
957
+ abortSignal: input.abortSignal,
958
+ trigger: "@",
959
+ context: {
960
+ metadata: {
961
+ currentUserId: input.currentUserId,
962
+ sessionCwd: input.sessionCwd || void 0,
963
+ target: "agent-gui",
964
+ workspaceId: input.workspaceId
965
+ }
966
+ }
967
+ });
968
+ if (input.abortSignal.aborted) {
969
+ return [];
970
+ }
971
+ const mentionItems = await Promise.all(
972
+ items.map(async (item) => {
973
+ const mentionItem = providerItemToAgentMentionItem({
974
+ currentUserId: input.currentUserId,
975
+ insertResult: input.provider.toInsertResult(item),
976
+ label: input.provider.getItemLabel(item),
977
+ providerId: input.provider.id,
978
+ subtitle: input.provider.getItemSubtitle?.(item) ?? "",
979
+ workspaceId: input.workspaceId
980
+ });
981
+ if (!mentionItem || mentionItem.kind !== "file") {
982
+ return mentionItem;
983
+ }
984
+ const iconUrl = await Promise.resolve(
985
+ input.provider.getItemIconUrl?.(item) ?? null
986
+ ).catch(() => null);
987
+ const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
988
+ ...mentionItem,
989
+ thumbnailUrl: iconUrl
990
+ });
991
+ if (!resolvedThumbnailUrl) {
992
+ return mentionItem;
993
+ }
994
+ return {
995
+ ...mentionItem,
996
+ thumbnailUrl: resolvedThumbnailUrl
997
+ };
998
+ })
999
+ );
1000
+ return mentionItems.filter(
1001
+ (item) => item !== null
1002
+ );
1003
+ }
1004
+
1005
+ // agent-gui/agentGuiNode/AgentMentionSearchControllerBase.ts
1006
+ var AgentMentionSearchControllerBase = class {
1007
+ contextMentionProviders;
1008
+ debounceMs;
1009
+ fileLimit;
1010
+ issueLimit;
1011
+ browseCacheTtlMs;
1012
+ providerTimeoutMs;
1013
+ diagnosticInfoLogger;
1014
+ diagnosticNow;
1015
+ diagnosticSlowThresholdMs;
1016
+ listeners = /* @__PURE__ */ new Set();
1017
+ expandedCounts = {};
1018
+ totalCounts = {};
1019
+ timer = null;
1020
+ preloadCancel = null;
1021
+ pendingPreloadKey = null;
1022
+ requestId = 0;
1023
+ disposed = false;
1024
+ activeWorkspaceId = "";
1025
+ currentUserId = "";
1026
+ currentFilter = DEFAULT_AGENT_MENTION_FILTER;
1027
+ currentQuery = "";
1028
+ currentSessionCwd = "";
1029
+ currentFileSearchLimit;
1030
+ currentIssueSearchLimit;
1031
+ agentGeneratedBrowsePath = null;
1032
+ rawGroups = emptyAgentMentionRawGroups();
1033
+ state = {
1034
+ status: "idle",
1035
+ query: "",
1036
+ mode: "browse",
1037
+ filter: DEFAULT_AGENT_MENTION_FILTER,
1038
+ categories: buildBrowseCategories(),
1039
+ groups: [],
1040
+ error: null
1041
+ };
1042
+ constructor(options) {
527
1043
  this.contextMentionProviders = new Map(
528
1044
  (options.contextMentionProviders ?? []).map((provider) => [
529
1045
  provider.id,
@@ -541,418 +1057,92 @@ var AgentMentionSearchController = class {
541
1057
  this.currentFileSearchLimit = this.fileLimit;
542
1058
  this.currentIssueSearchLimit = this.issueLimit;
543
1059
  }
544
- subscribe(listener) {
545
- this.listeners.add(listener);
546
- listener(this.state);
547
- return () => {
548
- this.listeners.delete(listener);
549
- };
550
- }
551
- updateQuery(input) {
552
- if (this.disposed) {
1060
+ startBrowseModeFetch(filter) {
1061
+ if (!this.activeWorkspaceId) {
1062
+ this.resetRawGroups();
1063
+ this.emitBrowseState("ready");
553
1064
  return;
554
1065
  }
555
- this.activeWorkspaceId = input.workspaceId.trim();
556
- this.currentUserId = input.currentUserId?.trim() ?? "";
557
- this.currentSessionCwd = input.sessionCwd?.trim() ?? "";
558
- this.currentQuery = normalizeQuery(input.query);
559
1066
  this.clearTimer();
560
1067
  const requestId = ++this.requestId;
561
- this.resetAgentGeneratedBrowsePath();
562
- this.resetExpandedCounts();
563
- this.resetSearchLimits();
564
- this.resetRawGroups();
565
- if (!this.activeWorkspaceId) {
566
- this.setState({
567
- status: "idle",
568
- query: this.currentQuery,
569
- mode: "browse",
570
- filter: this.currentFilter,
571
- categories: buildBrowseCategories(),
572
- groups: [],
573
- error: null
574
- });
575
- return;
576
- }
577
- if (!this.currentQuery) {
578
- this.startBrowseModeFetch(this.currentFilter);
579
- return;
580
- }
581
- this.setState({
582
- status: "loading",
583
- query: this.currentQuery,
584
- mode: "results",
585
- filter: this.currentFilter,
586
- categories: buildBrowseCategories(),
587
- groups: this.groupsFromRawGroups(),
588
- error: null
589
- });
590
- this.timer = setTimeout(() => {
591
- void this.runSearch({
592
- workspaceId: this.activeWorkspaceId,
593
- currentUserId: this.currentUserId,
594
- query: this.currentQuery,
595
- requestId,
596
- filter: this.currentFilter
597
- });
598
- }, this.debounceMs);
599
- }
600
- setFilter(filter) {
601
- if (this.disposed) {
602
- return;
603
- }
604
- this.currentFilter = filter;
605
- this.clearTimer();
606
- const requestId = ++this.requestId;
607
- this.resetAgentGeneratedBrowsePath();
608
- this.resetExpandedCounts();
609
- this.resetSearchLimits();
610
- this.resetRawGroups();
611
- if (!this.currentQuery) {
612
- this.startBrowseModeFetch(filter);
613
- return;
614
- }
615
- if (!this.activeWorkspaceId) {
616
- this.setState({
617
- status: "ready",
618
- query: this.currentQuery,
619
- mode: "results",
620
- filter: this.currentFilter,
621
- categories: buildBrowseCategories(),
622
- groups: [],
623
- error: null
624
- });
625
- return;
626
- }
627
- this.setState({
628
- status: "loading",
629
- query: this.currentQuery,
630
- mode: "results",
631
- filter: this.currentFilter,
632
- categories: buildBrowseCategories(),
633
- groups: this.groupsFromRawGroups(),
634
- error: null
635
- });
636
- void this.runSearch({
637
- workspaceId: this.activeWorkspaceId,
638
- currentUserId: this.currentUserId,
639
- query: this.currentQuery,
640
- requestId,
641
- filter
642
- });
643
- }
644
- preloadBrowse(input) {
645
- if (this.disposed) {
646
- return;
647
- }
648
- const workspaceId = input.workspaceId.trim();
649
- if (!workspaceId) {
650
- return;
651
- }
652
- const filter = input.filter ?? DEFAULT_AGENT_MENTION_FILTER;
653
- const currentUserId = input.currentUserId?.trim() ?? "";
654
- const sessionCwd = input.sessionCwd?.trim() ?? "";
655
1068
  const cacheKey = this.browseCacheKey({
656
- currentUserId,
1069
+ currentUserId: this.currentUserId,
657
1070
  filter,
658
- sessionCwd,
659
- workspaceId
660
- });
661
- if (this.readBrowseCache(cacheKey).isFresh) {
662
- return;
663
- }
664
- if (this.pendingPreloadKey === cacheKey) {
665
- return;
666
- }
667
- this.cancelPendingPreload();
668
- this.pendingPreloadKey = cacheKey;
669
- this.preloadCancel = scheduleIdleTask(() => {
670
- this.preloadCancel = null;
671
- this.pendingPreloadKey = null;
672
- if (this.disposed) {
673
- return;
674
- }
675
- this.runBrowsePreload({
676
- cacheKey,
677
- currentUserId,
678
- filter,
679
- sessionCwd,
680
- workspaceId
681
- });
1071
+ sessionCwd: this.currentSessionCwd,
1072
+ workspaceId: this.activeWorkspaceId
682
1073
  });
683
- }
684
- runBrowsePreload(input) {
685
- const { cacheKey, currentUserId, filter, sessionCwd, workspaceId } = input;
686
- this.logLifecycle("browse.preload", {
1074
+ this.logLifecycle("browse.open", {
687
1075
  filter,
688
1076
  providerIds: this.providerIdsForDiagnostics(),
689
- sessionCwdPresent: Boolean(sessionCwd),
690
- workspaceId
1077
+ requestId,
1078
+ sessionCwdPresent: Boolean(this.currentSessionCwd),
1079
+ workspaceId: this.activeWorkspaceId
691
1080
  });
692
1081
  const cached = this.readBrowseCache(cacheKey);
693
1082
  this.logBrowseCacheState({
694
1083
  cacheKey,
695
1084
  cached,
696
1085
  filter,
697
- reason: "preload",
698
- workspaceId
699
- });
700
- if (cached.isFresh) {
701
- return;
702
- }
703
- void this.loadBrowseFetchResult(
704
- {
705
- workspaceId,
706
- currentUserId,
707
- filter,
708
- sessionCwd
709
- },
710
- cacheKey,
711
- "preload"
712
- ).catch((error) => {
713
- this.logLifecycle("browse.fetch.error", {
714
- errorKind: diagnosticErrorKind(error),
715
- filter,
716
- reason: "preload",
717
- workspaceId
718
- });
1086
+ reason: "open",
1087
+ workspaceId: this.activeWorkspaceId
719
1088
  });
720
- }
721
- cancelPendingPreload() {
722
- if (this.preloadCancel) {
723
- this.preloadCancel();
724
- this.preloadCancel = null;
725
- }
726
- this.pendingPreloadKey = null;
727
- }
728
- enterCategory(category) {
729
- this.setFilter(category);
730
- }
731
- selectAgentGeneratedMentionItem(item) {
732
- if (item.kind !== "file" || !item.mentionNavigation) {
733
- return false;
734
- }
735
- if (item.mentionNavigation === "agent-generated-folder") {
736
- this.agentGeneratedBrowsePath = item.path;
737
- this.expandedCounts.agent_generated_files = mentionGroupPageSize(
738
- this.currentFilter,
739
- "agent_generated_files"
740
- );
741
- this.setState({
742
- status: this.state.status === "loading" ? "loading" : "ready",
743
- query: this.currentQuery,
744
- mode: this.currentQuery ? "results" : "browse",
745
- filter: this.currentFilter,
746
- categories: buildBrowseCategories(),
747
- groups: this.groupsFromRawGroups(),
748
- error: null
749
- });
750
- return true;
751
- }
752
- if (item.mentionNavigation === "agent-generated-folder-back") {
753
- this.resetAgentGeneratedBrowsePath();
1089
+ if (cached.entry) {
1090
+ this.applyBrowseFetchResult(cached.entry);
754
1091
  this.setState({
755
- status: this.state.status === "loading" ? "loading" : "ready",
756
- query: this.currentQuery,
757
- mode: this.currentQuery ? "results" : "browse",
1092
+ status: "ready",
1093
+ query: "",
1094
+ mode: "browse",
758
1095
  filter: this.currentFilter,
759
1096
  categories: buildBrowseCategories(),
760
1097
  groups: this.groupsFromRawGroups(),
761
1098
  error: null
762
1099
  });
763
- return true;
764
- }
765
- return false;
766
- }
767
- exitAgentGeneratedBrowse() {
768
- if (!this.agentGeneratedBrowsePath) {
769
- return false;
1100
+ if (cached.isFresh) {
1101
+ return;
1102
+ }
1103
+ } else {
1104
+ this.rawGroups = emptyAgentMentionRawGroups();
1105
+ this.resetTotalCounts();
1106
+ this.emitBrowseState("loading");
770
1107
  }
771
- this.resetAgentGeneratedBrowsePath();
772
- this.setState({
773
- status: this.state.status === "loading" ? "loading" : "ready",
774
- query: this.currentQuery,
775
- mode: this.currentQuery ? "results" : "browse",
776
- filter: this.currentFilter,
777
- categories: buildBrowseCategories(),
778
- groups: this.groupsFromRawGroups(),
779
- error: null
1108
+ void this.runBrowseSearch({
1109
+ workspaceId: this.activeWorkspaceId,
1110
+ currentUserId: this.currentUserId,
1111
+ requestId,
1112
+ filter,
1113
+ sessionCwd: this.currentSessionCwd
780
1114
  });
781
- return true;
782
1115
  }
783
- expandGroup(groupId) {
784
- const pageSize = mentionGroupPageSize(this.currentFilter, groupId);
785
- const current = this.expandedCounts[groupId] ?? pageSize;
786
- this.expandedCounts[groupId] = current + pageSize;
787
- if (!this.currentQuery) {
1116
+ async runSearch(input) {
1117
+ const startedAt = this.diagnosticNow();
1118
+ let providerDiagnostics = [];
1119
+ try {
1120
+ const result = await this.fetchFilterResult({
1121
+ workspaceId: input.workspaceId,
1122
+ currentUserId: input.currentUserId,
1123
+ query: input.query,
1124
+ filter: input.filter,
1125
+ sessionCwd: this.currentSessionCwd,
1126
+ includeAgentGeneratedFiles: false
1127
+ });
1128
+ providerDiagnostics = result.providerDiagnostics;
1129
+ if (!this.canApply(
1130
+ input.requestId,
1131
+ input.workspaceId,
1132
+ input.query,
1133
+ input.filter
1134
+ )) {
1135
+ return;
1136
+ }
1137
+ this.applyBrowseFetchResult(result);
1138
+ const groups = this.groupsFromRawGroups();
788
1139
  this.setState({
789
1140
  status: "ready",
790
- query: "",
791
- mode: "browse",
1141
+ query: input.query,
1142
+ mode: "results",
792
1143
  filter: this.currentFilter,
793
1144
  categories: buildBrowseCategories(),
794
- groups: this.groupsFromRawGroups(),
795
- error: null
796
- });
797
- return;
798
- }
799
- const needsMoreFiles = (groupId === "opened_files" || groupId === "files" || groupId === "agent_generated_files") && (groupId === "agent_generated_files" ? this.rawGroups.agent_generated_files.length >= this.currentFileSearchLimit : this.rawGroups.opened_files.length >= this.currentFileSearchLimit);
800
- const needsMoreIssues = groupId === "issues" && (this.totalCounts.issues ?? this.rawGroups.issues.length) > this.rawGroups.issues.length;
801
- if (needsMoreFiles) {
802
- this.currentFileSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
803
- }
804
- if (needsMoreIssues) {
805
- this.currentIssueSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
806
- }
807
- if (needsMoreFiles || needsMoreIssues) {
808
- this.clearTimer();
809
- const requestId = ++this.requestId;
810
- this.setState({
811
- status: "loading",
812
- query: this.currentQuery,
813
- mode: "results",
814
- filter: this.currentFilter,
815
- categories: buildBrowseCategories(),
816
- groups: this.groupsFromRawGroups(),
817
- error: null
818
- });
819
- void this.runSearch({
820
- workspaceId: this.activeWorkspaceId,
821
- currentUserId: this.currentUserId,
822
- query: this.currentQuery,
823
- requestId,
824
- filter: this.currentFilter
825
- });
826
- return;
827
- }
828
- this.setState({
829
- status: "ready",
830
- query: this.currentQuery,
831
- mode: "results",
832
- filter: this.currentFilter,
833
- categories: buildBrowseCategories(),
834
- groups: this.groupsFromRawGroups(),
835
- error: null
836
- });
837
- }
838
- close() {
839
- this.clearTimer();
840
- this.requestId += 1;
841
- this.currentFilter = DEFAULT_AGENT_MENTION_FILTER;
842
- this.resetAgentGeneratedBrowsePath();
843
- this.resetExpandedCounts();
844
- this.resetSearchLimits();
845
- this.resetRawGroups();
846
- this.currentQuery = "";
847
- this.setState({
848
- status: "idle",
849
- query: "",
850
- mode: "browse",
851
- filter: DEFAULT_AGENT_MENTION_FILTER,
852
- categories: buildBrowseCategories(),
853
- groups: [],
854
- error: null
855
- });
856
- }
857
- dispose() {
858
- this.disposed = true;
859
- this.clearTimer();
860
- this.cancelPendingPreload();
861
- this.listeners.clear();
862
- this.requestId += 1;
863
- }
864
- startBrowseModeFetch(filter) {
865
- if (!this.activeWorkspaceId) {
866
- this.resetRawGroups();
867
- this.emitBrowseState("ready");
868
- return;
869
- }
870
- this.clearTimer();
871
- const requestId = ++this.requestId;
872
- const cacheKey = this.browseCacheKey({
873
- currentUserId: this.currentUserId,
874
- filter,
875
- sessionCwd: this.currentSessionCwd,
876
- workspaceId: this.activeWorkspaceId
877
- });
878
- this.logLifecycle("browse.open", {
879
- filter,
880
- providerIds: this.providerIdsForDiagnostics(),
881
- requestId,
882
- sessionCwdPresent: Boolean(this.currentSessionCwd),
883
- workspaceId: this.activeWorkspaceId
884
- });
885
- const cached = this.readBrowseCacheForBrowseInput({
886
- cacheKey,
887
- currentUserId: this.currentUserId,
888
- filter,
889
- sessionCwd: this.currentSessionCwd,
890
- workspaceId: this.activeWorkspaceId
891
- });
892
- this.logBrowseCacheState({
893
- cacheKey,
894
- cached,
895
- filter,
896
- reason: "open",
897
- workspaceId: this.activeWorkspaceId
898
- });
899
- if (cached.entry) {
900
- this.applyBrowseFetchResult(cached.entry);
901
- this.setState({
902
- status: "ready",
903
- query: "",
904
- mode: "browse",
905
- filter: this.currentFilter,
906
- categories: buildBrowseCategories(),
907
- groups: this.groupsFromRawGroups(),
908
- error: null
909
- });
910
- if (cached.isFresh) {
911
- return;
912
- }
913
- } else {
914
- this.rawGroups = emptyAgentMentionRawGroups();
915
- this.resetTotalCounts();
916
- this.emitBrowseState("loading");
917
- }
918
- void this.runBrowseSearch({
919
- workspaceId: this.activeWorkspaceId,
920
- currentUserId: this.currentUserId,
921
- requestId,
922
- filter,
923
- sessionCwd: this.currentSessionCwd
924
- });
925
- }
926
- async runSearch(input) {
927
- const startedAt = this.diagnosticNow();
928
- let providerDiagnostics = [];
929
- try {
930
- const result = await this.fetchFilterResult({
931
- workspaceId: input.workspaceId,
932
- currentUserId: input.currentUserId,
933
- query: input.query,
934
- filter: input.filter,
935
- sessionCwd: this.currentSessionCwd,
936
- includeAgentGeneratedFiles: false
937
- });
938
- providerDiagnostics = result.providerDiagnostics;
939
- if (!this.canApply(
940
- input.requestId,
941
- input.workspaceId,
942
- input.query,
943
- input.filter
944
- )) {
945
- return;
946
- }
947
- this.applyBrowseFetchResult(result);
948
- const groups = this.groupsFromRawGroups();
949
- this.setState({
950
- status: "ready",
951
- query: input.query,
952
- mode: "results",
953
- filter: this.currentFilter,
954
- categories: buildBrowseCategories(),
955
- groups,
1145
+ groups,
956
1146
  error: null
957
1147
  });
958
1148
  this.logSearchDiagnostic({
@@ -1063,47 +1253,6 @@ var AgentMentionSearchController = class {
1063
1253
  });
1064
1254
  }
1065
1255
  }
1066
- async loadBrowseFetchResult(input, cacheKey, reason) {
1067
- const existingFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
1068
- if (existingFetch) {
1069
- this.logLifecycle("browse.fetch.dedupe", {
1070
- filter: input.filter,
1071
- reason,
1072
- workspaceId: input.workspaceId
1073
- });
1074
- return existingFetch;
1075
- }
1076
- const startedAt = this.diagnosticNow();
1077
- this.logLifecycle("browse.fetch.start", {
1078
- filter: input.filter,
1079
- providerIds: this.providerIdsForDiagnostics(),
1080
- reason,
1081
- workspaceId: input.workspaceId
1082
- });
1083
- const fetchPromise = this.fetchBrowseResult(input).then((result) => {
1084
- writeBrowseCacheEntry(cacheKey, {
1085
- ...result,
1086
- cachedAt: this.diagnosticNow()
1087
- });
1088
- this.logLifecycle("browse.fetch.success", {
1089
- durationMs: elapsedDiagnosticMs(this.diagnosticNow(), startedAt),
1090
- filter: input.filter,
1091
- itemCount: rawGroupItemCount(result.rawGroups),
1092
- providerResults: providerDiagnosticsSummary(
1093
- result.providerDiagnostics
1094
- ),
1095
- reason,
1096
- workspaceId: input.workspaceId
1097
- });
1098
- return result;
1099
- }).finally(() => {
1100
- if (sharedAgentMentionBrowseFetches.get(cacheKey) === fetchPromise) {
1101
- sharedAgentMentionBrowseFetches.delete(cacheKey);
1102
- }
1103
- });
1104
- sharedAgentMentionBrowseFetches.set(cacheKey, fetchPromise);
1105
- return fetchPromise;
1106
- }
1107
1256
  async fetchBrowseResult(input) {
1108
1257
  return this.fetchFilterResult({
1109
1258
  ...input,
@@ -1111,177 +1260,6 @@ var AgentMentionSearchController = class {
1111
1260
  includeAgentGeneratedFiles: input.filter === "file"
1112
1261
  });
1113
1262
  }
1114
- async fetchFilterResult(input) {
1115
- const providerDiagnostics = [];
1116
- switch (input.filter) {
1117
- case "file": {
1118
- const fileQuery = this.queryProviderMentionItemsById({
1119
- providerId: FILE_PROVIDER_ID2,
1120
- workspaceId: input.workspaceId,
1121
- currentUserId: input.currentUserId,
1122
- query: input.query,
1123
- limit: input.query ? this.currentFileSearchLimit : this.fileLimit,
1124
- sessionCwd: input.sessionCwd,
1125
- diagnostics: providerDiagnostics
1126
- });
1127
- const agentGeneratedFileQuery = input.includeAgentGeneratedFiles ? this.queryProviderMentionItemsById({
1128
- providerId: AGENT_GENERATED_FILE_PROVIDER_ID2,
1129
- workspaceId: input.workspaceId,
1130
- currentUserId: input.currentUserId,
1131
- query: input.query,
1132
- limit: this.fileLimit,
1133
- sessionCwd: input.sessionCwd,
1134
- diagnostics: providerDiagnostics
1135
- }) : Promise.resolve([]);
1136
- const [fileItems, agentGeneratedFileItems] = await Promise.all([
1137
- fileQuery,
1138
- agentGeneratedFileQuery
1139
- ]);
1140
- const rawGroups = emptyAgentMentionRawGroups();
1141
- rawGroups.opened_files = fileItems.filter(
1142
- (item) => item.kind === "file"
1143
- );
1144
- rawGroups.agent_generated_files = agentGeneratedFileItems.filter(
1145
- (item) => item.kind === "file"
1146
- );
1147
- return {
1148
- providerDiagnostics,
1149
- rawGroups,
1150
- totalCounts: totalCountsFromRawGroups(rawGroups)
1151
- };
1152
- }
1153
- case "session": {
1154
- const sessionItems = await this.queryProviderMentionItemsById({
1155
- providerId: AGENT_SESSION_PROVIDER_ID2,
1156
- workspaceId: input.workspaceId,
1157
- currentUserId: input.currentUserId,
1158
- query: input.query,
1159
- limit: DEFAULT_SESSION_LIMIT,
1160
- sessionCwd: input.sessionCwd,
1161
- diagnostics: providerDiagnostics
1162
- });
1163
- const rawGroups = emptyAgentMentionRawGroups();
1164
- rawGroups.my_sessions = normalizeSessionMentionItemsForMySessions({
1165
- currentUserId: input.currentUserId,
1166
- items: sessionItems
1167
- });
1168
- return {
1169
- providerDiagnostics,
1170
- rawGroups,
1171
- totalCounts: totalCountsFromRawGroups(rawGroups)
1172
- };
1173
- }
1174
- case "issue": {
1175
- const issueItems = await this.queryProviderMentionItemsById({
1176
- providerId: WORKSPACE_ISSUE_PROVIDER_ID2,
1177
- workspaceId: input.workspaceId,
1178
- currentUserId: input.currentUserId,
1179
- query: input.query,
1180
- limit: this.currentIssueSearchLimit,
1181
- sessionCwd: input.sessionCwd,
1182
- diagnostics: providerDiagnostics
1183
- });
1184
- const rawGroups = emptyAgentMentionRawGroups();
1185
- rawGroups.issues = issueItems.filter(
1186
- (item) => item.kind === "workspace-issue"
1187
- );
1188
- return {
1189
- providerDiagnostics,
1190
- rawGroups,
1191
- totalCounts: totalCountsFromRawGroups(rawGroups)
1192
- };
1193
- }
1194
- case "agent": {
1195
- const agentItems = await this.queryProviderMentionItemsById({
1196
- providerId: AGENT_TARGET_PROVIDER_ID,
1197
- workspaceId: input.workspaceId,
1198
- currentUserId: input.currentUserId,
1199
- query: input.query,
1200
- sessionCwd: input.sessionCwd,
1201
- diagnostics: providerDiagnostics
1202
- });
1203
- const rawGroups = emptyAgentMentionRawGroups();
1204
- rawGroups.agents = agentItems.filter(
1205
- (item) => item.kind === "agent-target"
1206
- );
1207
- return {
1208
- providerDiagnostics,
1209
- rawGroups,
1210
- totalCounts: totalCountsFromRawGroups(rawGroups)
1211
- };
1212
- }
1213
- case "app": {
1214
- const appItems = await this.queryProviderMentionItemsById({
1215
- providerId: WORKSPACE_APP_PROVIDER_ID2,
1216
- workspaceId: input.workspaceId,
1217
- currentUserId: input.currentUserId,
1218
- query: input.query,
1219
- sessionCwd: input.sessionCwd,
1220
- diagnostics: providerDiagnostics
1221
- });
1222
- const rawGroups = emptyAgentMentionRawGroups();
1223
- rawGroups.apps = appItems.filter(
1224
- (item) => item.kind === "workspace-app"
1225
- );
1226
- return {
1227
- providerDiagnostics,
1228
- rawGroups,
1229
- totalCounts: totalCountsFromRawGroups(rawGroups)
1230
- };
1231
- }
1232
- }
1233
- }
1234
- async queryProviderMentionItems(input) {
1235
- const items = await input.provider.query({
1236
- keyword: input.query,
1237
- maxResults: input.limit,
1238
- abortSignal: input.abortSignal,
1239
- trigger: "@",
1240
- context: {
1241
- metadata: {
1242
- currentUserId: input.currentUserId,
1243
- sessionCwd: input.sessionCwd || void 0,
1244
- target: "agent-gui",
1245
- workspaceId: input.workspaceId
1246
- }
1247
- }
1248
- });
1249
- if (input.abortSignal.aborted) {
1250
- return [];
1251
- }
1252
- const mentionItems = await Promise.all(
1253
- items.map(async (item) => {
1254
- const mentionItem = providerItemToAgentMentionItem({
1255
- currentUserId: input.currentUserId,
1256
- insertResult: input.provider.toInsertResult(item),
1257
- label: input.provider.getItemLabel(item),
1258
- providerId: input.provider.id,
1259
- subtitle: input.provider.getItemSubtitle?.(item) ?? "",
1260
- workspaceId: input.workspaceId
1261
- });
1262
- if (!mentionItem || mentionItem.kind !== "file") {
1263
- return mentionItem;
1264
- }
1265
- const iconUrl = await Promise.resolve(
1266
- input.provider.getItemIconUrl?.(item) ?? null
1267
- ).catch(() => null);
1268
- const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
1269
- ...mentionItem,
1270
- thumbnailUrl: iconUrl
1271
- });
1272
- if (!resolvedThumbnailUrl) {
1273
- return mentionItem;
1274
- }
1275
- return {
1276
- ...mentionItem,
1277
- thumbnailUrl: resolvedThumbnailUrl
1278
- };
1279
- })
1280
- );
1281
- return mentionItems.filter(
1282
- (item) => item !== null
1283
- );
1284
- }
1285
1263
  applyBrowseFetchResult(result) {
1286
1264
  this.rawGroups = cloneAgentMentionRawGroups(result.rawGroups);
1287
1265
  this.resetTotalCounts();
@@ -1289,31 +1267,6 @@ var AgentMentionSearchController = class {
1289
1267
  this.totalCounts[groupId] = count;
1290
1268
  }
1291
1269
  }
1292
- readBrowseCache(cacheKey) {
1293
- const entry = sharedAgentMentionBrowseCache.get(cacheKey);
1294
- if (!entry) {
1295
- return { entry: null, isFresh: false };
1296
- }
1297
- sharedAgentMentionBrowseCache.delete(cacheKey);
1298
- sharedAgentMentionBrowseCache.set(cacheKey, entry);
1299
- const ageMs = this.diagnosticNow() - entry.cachedAt;
1300
- const isFresh = this.browseCacheTtlMs >= 0 && Number.isFinite(this.browseCacheTtlMs) && ageMs <= this.browseCacheTtlMs;
1301
- return { entry, isFresh };
1302
- }
1303
- readBrowseCacheForBrowseInput(input) {
1304
- return this.readBrowseCache(input.cacheKey);
1305
- }
1306
- browseCacheKey(input) {
1307
- return JSON.stringify({
1308
- workspaceId: input.workspaceId,
1309
- currentUserId: input.currentUserId,
1310
- sessionCwd: input.sessionCwd,
1311
- filter: input.filter,
1312
- fileLimit: this.fileLimit,
1313
- issueLimit: this.currentIssueSearchLimit,
1314
- providerIds: [...this.contextMentionProviders.keys()].sort()
1315
- });
1316
- }
1317
1270
  logBrowseCacheState(input) {
1318
1271
  this.logLifecycle("browse.cache", {
1319
1272
  ageMs: input.cached.entry ? elapsedDiagnosticMs(this.diagnosticNow(), input.cached.entry.cachedAt) : null,
@@ -1339,7 +1292,7 @@ var AgentMentionSearchController = class {
1339
1292
  fallback: [],
1340
1293
  providerId: input.providerId,
1341
1294
  providerTimeoutMs: this.providerTimeoutMs,
1342
- query: provider ? (abortSignal) => this.queryProviderMentionItems({
1295
+ query: provider ? (abortSignal) => queryAgentMentionProviderItems({
1343
1296
  provider,
1344
1297
  workspaceId: input.workspaceId,
1345
1298
  currentUserId: input.currentUserId,
@@ -1370,41 +1323,6 @@ var AgentMentionSearchController = class {
1370
1323
  workspaceId: input.workspaceId
1371
1324
  });
1372
1325
  }
1373
- groupsFromRawGroups() {
1374
- const orderedGroupIds = groupIdsForFilter(this.currentFilter);
1375
- return orderedGroupIds.map((groupId) => {
1376
- const rawItems = resolveMentionGroupItems(groupId, this.rawGroups);
1377
- const items = groupId === "agent_generated_files" ? presentAgentGeneratedFileMentionItems({
1378
- files: rawItems,
1379
- browsePath: this.agentGeneratedBrowsePath,
1380
- query: this.currentQuery
1381
- }) : rawItems;
1382
- if (items.length === 0) {
1383
- if (!shouldShowEmptyGroup(
1384
- groupId,
1385
- this.currentFilter,
1386
- this.currentQuery
1387
- )) {
1388
- return null;
1389
- }
1390
- return buildEmptyGroup(groupId, this.currentQuery);
1391
- }
1392
- const pageSize = mentionGroupPageSize(this.currentFilter, groupId);
1393
- const visibleCount = groupId === "apps" ? items.length : Math.min(items.length, this.expandedCounts[groupId] ?? pageSize);
1394
- const totalCount = resolveMentionGroupTotalCount(
1395
- groupId,
1396
- this.totalCounts,
1397
- items.length
1398
- );
1399
- return {
1400
- id: groupId,
1401
- items: items.slice(0, visibleCount),
1402
- totalCount,
1403
- visibleCount,
1404
- hasMore: groupId !== "apps" && (items.length > visibleCount || (groupId === "opened_files" || groupId === "files" || groupId === "agent_generated_files") && items.length >= this.currentFileSearchLimit || totalCount > visibleCount)
1405
- };
1406
- }).filter((group) => group !== null);
1407
- }
1408
1326
  emitBrowseState(status) {
1409
1327
  this.setState({
1410
1328
  status,
@@ -1473,726 +1391,400 @@ var AgentMentionSearchController = class {
1473
1391
  listener(state);
1474
1392
  }
1475
1393
  }
1394
+ groupsFromRawGroups() {
1395
+ return buildAgentMentionGroups({
1396
+ agentGeneratedBrowsePath: this.agentGeneratedBrowsePath,
1397
+ currentFileSearchLimit: this.currentFileSearchLimit,
1398
+ currentFilter: this.currentFilter,
1399
+ currentQuery: this.currentQuery,
1400
+ expandedCounts: this.expandedCounts,
1401
+ rawGroups: this.rawGroups,
1402
+ totalCounts: this.totalCounts
1403
+ });
1404
+ }
1405
+ browseCacheKey(input) {
1406
+ return buildAgentMentionBrowseCacheKey({
1407
+ ...input,
1408
+ fileLimit: this.fileLimit,
1409
+ issueLimit: this.currentIssueSearchLimit,
1410
+ providerIds: [...this.contextMentionProviders.keys()].sort()
1411
+ });
1412
+ }
1413
+ readBrowseCache(cacheKey) {
1414
+ return readAgentMentionBrowseCache({
1415
+ cacheKey,
1416
+ browseCacheTtlMs: this.browseCacheTtlMs,
1417
+ diagnosticNow: this.diagnosticNow
1418
+ });
1419
+ }
1420
+ loadBrowseFetchResult(input, cacheKey, reason) {
1421
+ return loadAgentMentionBrowseFetchResult({
1422
+ input,
1423
+ cacheKey,
1424
+ reason,
1425
+ diagnosticNow: this.diagnosticNow,
1426
+ providerIds: this.providerIdsForDiagnostics(),
1427
+ fetchBrowseResult: () => this.fetchBrowseResult(input),
1428
+ logLifecycle: (event, details) => this.logLifecycle(event, details)
1429
+ });
1430
+ }
1431
+ fetchFilterResult(input) {
1432
+ return fetchAgentMentionFilterResult({
1433
+ ...input,
1434
+ fileLimit: this.fileLimit,
1435
+ currentFileSearchLimit: this.currentFileSearchLimit,
1436
+ currentIssueSearchLimit: this.currentIssueSearchLimit,
1437
+ queryProviderMentionItemsById: (queryInput) => this.queryProviderMentionItemsById(queryInput)
1438
+ });
1439
+ }
1476
1440
  };
1477
- function preloadAgentMentionBrowse(input) {
1478
- const controller = new AgentMentionSearchController({
1479
- contextMentionProviders: input.contextMentionProviders
1480
- });
1481
- controller.preloadBrowse({
1482
- workspaceId: input.workspaceId,
1483
- currentUserId: input.currentUserId,
1484
- sessionCwd: input.sessionCwd,
1485
- filter: input.filter
1486
- });
1487
- }
1488
- function emptyAgentMentionRawGroups() {
1489
- return {
1490
- apps: [],
1491
- agents: [],
1492
- opened_files: [],
1493
- agent_generated_files: [],
1494
- my_sessions: [],
1495
- collab_sessions: [],
1496
- issues: []
1497
- };
1498
- }
1499
- function cloneAgentMentionRawGroups(rawGroups) {
1500
- return {
1501
- apps: [...rawGroups.apps],
1502
- agents: [...rawGroups.agents],
1503
- opened_files: [...rawGroups.opened_files],
1504
- agent_generated_files: [...rawGroups.agent_generated_files],
1505
- my_sessions: [...rawGroups.my_sessions],
1506
- collab_sessions: [...rawGroups.collab_sessions],
1507
- issues: [...rawGroups.issues]
1508
- };
1509
- }
1510
- function totalCountsFromRawGroups(rawGroups) {
1511
- return {
1512
- apps: rawGroups.apps.length,
1513
- agents: rawGroups.agents.length,
1514
- opened_files: rawGroups.opened_files.length,
1515
- agent_generated_files: rawGroups.agent_generated_files.length,
1516
- my_sessions: rawGroups.my_sessions.length,
1517
- collab_sessions: rawGroups.collab_sessions.length,
1518
- issues: rawGroups.issues.length
1519
- };
1520
- }
1521
- function rawGroupItemCount(rawGroups) {
1522
- return Object.values(rawGroups).reduce(
1523
- (count, items) => count + items.length,
1524
- 0
1525
- );
1526
- }
1527
- function providerDiagnosticsSummary(diagnostics) {
1528
- return diagnostics.map(
1529
- (diagnostic) => `${diagnostic.providerId}:${diagnostic.status}:${diagnostic.resultCount}:${diagnostic.durationMs}`
1530
- ).join(",");
1531
- }
1532
- function elapsedDiagnosticMs(now, startedAt) {
1533
- const durationMs = now - startedAt;
1534
- return Number.isFinite(durationMs) ? Math.max(0, Math.round(durationMs)) : 0;
1535
- }
1536
- function diagnosticErrorKind(error) {
1537
- if (error instanceof Error && error.name.trim()) {
1538
- return error.name.trim();
1539
- }
1540
- if (error === null) {
1541
- return "null";
1542
- }
1543
- return typeof error;
1544
- }
1545
- function logAgentMentionLifecycleDiagnostic(payload) {
1546
- try {
1547
- console.info(AGENT_MENTION_LIFECYCLE_LOG_PREFIX, JSON.stringify(payload));
1548
- } catch {
1549
- }
1550
- try {
1551
- getOptionalAgentHostApi()?.debug?.logRuntimeDiagnostics?.({
1552
- source: "renderer-workspace-surface",
1553
- level: "info",
1554
- event: `agent-gui.mention.${payload.event}`,
1555
- // i18n-check-ignore: Internal diagnostic log message.
1556
- message: "Agent GUI mention search lifecycle event.",
1557
- details: payload.details
1558
- });
1559
- } catch {
1560
- }
1561
- }
1562
- function normalizeSessionMentionItemsForMySessions(input) {
1563
- return input.items.filter((item) => item.kind === "session").filter(
1564
- (item) => input.currentUserId ? item.scope === "my_sessions" : true
1565
- ).map(
1566
- (item) => item.scope === "my_sessions" ? item : { ...item, scope: "my_sessions" }
1567
- );
1568
- }
1569
- function providerItemToAgentMentionItem(input) {
1570
- const label = compactText(input.label);
1571
- if (!label) {
1572
- return null;
1573
- }
1574
- if (input.insertResult.kind === "markdown-link") {
1575
- const href = input.insertResult.href.trim();
1576
- return {
1577
- kind: "file",
1578
- href,
1579
- path: href,
1580
- name: label,
1581
- entryKind: href.endsWith("/") ? "directory" : "unknown",
1582
- directoryPath: dirnameFromProviderWorkspaceFileHref(href)
1583
- };
1584
- }
1585
- if (input.insertResult.kind !== "mention") {
1586
- return null;
1587
- }
1588
- const mention = input.insertResult.mention;
1589
- const targetId = mention.entityId.trim();
1590
- if (!targetId) {
1591
- return null;
1592
- }
1593
- const scope = normalizeMentionScope(mention.scope);
1594
- const presentation = mention.presentation ?? {};
1595
- const workspaceId = scope.workspaceId || input.workspaceId;
1596
- if (input.providerId === FILE_PROVIDER_ID2 || input.providerId === AGENT_GENERATED_FILE_PROVIDER_ID2) {
1597
- return {
1598
- kind: "file",
1599
- href: createRichTextMentionHref2({
1600
- providerId: input.providerId,
1601
- entityId: targetId,
1602
- label,
1603
- scope
1604
- }),
1605
- path: targetId,
1606
- name: label,
1607
- entryKind: targetId.endsWith("/") ? "directory" : "unknown",
1608
- directoryPath: dirnameFromProviderWorkspaceFileHref(targetId),
1609
- thumbnailUrl: presentation.thumbnailUrl?.trim() || void 0
1610
- };
1611
- }
1612
- if (input.providerId === WORKSPACE_ISSUE_PROVIDER_ID2) {
1613
- return {
1614
- kind: "workspace-issue",
1615
- href: createRichTextMentionHref2({
1616
- providerId: "workspace-issue",
1617
- entityId: targetId,
1618
- label,
1619
- scope: {
1620
- workspaceId,
1621
- ...scope.topicId ? { topicId: scope.topicId } : {}
1622
- }
1623
- }),
1624
- workspaceId,
1625
- targetId,
1626
- topicId: scope.topicId,
1627
- name: label,
1628
- title: label,
1629
- status: presentation.status?.trim() || void 0,
1630
- contentPreview: compactText(presentation.description) || compactText(input.subtitle) || void 0
1631
- };
1632
- }
1633
- if (input.providerId === WORKSPACE_APP_PROVIDER_ID2) {
1634
- const appId = targetId;
1635
- return {
1636
- kind: "workspace-app",
1637
- href: createRichTextMentionHref2({
1638
- providerId: "workspace-app",
1639
- entityId: appId,
1640
- label,
1641
- scope: { workspaceId }
1642
- }),
1643
- workspaceId,
1644
- targetId: appId,
1645
- appId,
1646
- name: label,
1647
- description: compactText(presentation.description) || compactText(presentation.subtitle) || compactText(input.subtitle) || void 0,
1648
- iconUrl: presentation.iconUrl?.trim() || void 0,
1649
- referencesListSupported: presentation.referencesListSupported === "true"
1650
- };
1651
- }
1652
- if (input.providerId === AGENT_TARGET_PROVIDER_ID) {
1653
- const agentProviderId = presentation.agentProviderId?.trim() || void 0;
1654
- return {
1655
- kind: "agent-target",
1656
- href: createRichTextMentionHref2({
1657
- providerId: "agent-target",
1658
- entityId: targetId,
1659
- label,
1660
- scope: { workspaceId }
1661
- }),
1662
- workspaceId,
1663
- targetId,
1664
- name: label,
1665
- description: compactText(presentation.description) || compactText(presentation.subtitle) || compactText(input.subtitle) || void 0,
1666
- agentProviderId,
1667
- iconUrl: presentation.iconUrl?.trim() || void 0
1668
- };
1669
- }
1670
- if (input.providerId === AGENT_SESSION_PROVIDER_ID2) {
1671
- const agentName = presentation.subtitle?.trim() || "";
1672
- const title = normalizeAgentSessionMentionTitle(label) || label;
1673
- const description = compactText(presentation.description);
1674
- const summaryPreview = description || compactText(input.subtitle) || void 0;
1675
- return {
1676
- kind: "session",
1677
- href: createRichTextMentionHref2({
1678
- providerId: "agent-session",
1679
- entityId: targetId,
1680
- label,
1681
- scope: { workspaceId }
1682
- }),
1683
- workspaceId,
1684
- targetId,
1685
- name: label,
1686
- title,
1687
- scope: mentionSessionScope({
1688
- currentUserId: input.currentUserId,
1689
- rawScope: scope.scope,
1690
- userId: scope.userId
1691
- }),
1692
- initiatorName: "",
1693
- agentName,
1694
- status: presentation.status?.trim() || void 0,
1695
- inputPreview: description || void 0,
1696
- summaryPreview
1441
+
1442
+ // agent-gui/agentGuiNode/AgentMentionSearchController.ts
1443
+ var AgentMentionSearchController = class extends AgentMentionSearchControllerBase {
1444
+ subscribe(listener) {
1445
+ this.listeners.add(listener);
1446
+ listener(this.state);
1447
+ return () => {
1448
+ this.listeners.delete(listener);
1697
1449
  };
1698
1450
  }
1699
- return null;
1700
- }
1701
- function normalizeMentionScope(scope) {
1702
- return Object.fromEntries(
1703
- Object.entries(scope ?? {}).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0)
1704
- );
1705
- }
1706
- function mentionSessionScope(input) {
1707
- const rawScope = input.rawScope?.trim() ?? "";
1708
- if (rawScope === "my_sessions" || rawScope === "collab_sessions") {
1709
- return rawScope;
1710
- }
1711
- const userId = input.userId?.trim() ?? "";
1712
- const currentUserId = input.currentUserId.trim();
1713
- if (!userId || !currentUserId || userId === "local" || currentUserId === "local") {
1714
- return "my_sessions";
1715
- }
1716
- return userId === currentUserId ? "my_sessions" : "collab_sessions";
1717
- }
1718
- function dirnameFromProviderWorkspaceFileHref(href) {
1719
- const normalized = href.replace(/\/+$/, "");
1720
- const index = normalized.lastIndexOf("/");
1721
- if (index <= 0) {
1722
- return "/";
1451
+ updateQuery(input) {
1452
+ if (this.disposed) {
1453
+ return;
1454
+ }
1455
+ this.activeWorkspaceId = input.workspaceId.trim();
1456
+ this.currentUserId = input.currentUserId?.trim() ?? "";
1457
+ this.currentSessionCwd = input.sessionCwd?.trim() ?? "";
1458
+ this.currentQuery = normalizeQuery(input.query);
1459
+ this.clearTimer();
1460
+ const requestId = ++this.requestId;
1461
+ this.resetAgentGeneratedBrowsePath();
1462
+ this.resetExpandedCounts();
1463
+ this.resetSearchLimits();
1464
+ this.resetRawGroups();
1465
+ if (!this.activeWorkspaceId) {
1466
+ this.setState({
1467
+ status: "idle",
1468
+ query: this.currentQuery,
1469
+ mode: "browse",
1470
+ filter: this.currentFilter,
1471
+ categories: buildBrowseCategories(),
1472
+ groups: [],
1473
+ error: null
1474
+ });
1475
+ return;
1476
+ }
1477
+ if (!this.currentQuery) {
1478
+ this.startBrowseModeFetch(this.currentFilter);
1479
+ return;
1480
+ }
1481
+ this.setState({
1482
+ status: "loading",
1483
+ query: this.currentQuery,
1484
+ mode: "results",
1485
+ filter: this.currentFilter,
1486
+ categories: buildBrowseCategories(),
1487
+ groups: this.groupsFromRawGroups(),
1488
+ error: null
1489
+ });
1490
+ this.timer = setTimeout(() => {
1491
+ void this.runSearch({
1492
+ workspaceId: this.activeWorkspaceId,
1493
+ currentUserId: this.currentUserId,
1494
+ query: this.currentQuery,
1495
+ requestId,
1496
+ filter: this.currentFilter
1497
+ });
1498
+ }, this.debounceMs);
1723
1499
  }
1724
- return normalized.slice(0, index);
1725
- }
1726
-
1727
- // agent-gui/agentGuiNode/AgentFileMentionPalette.tsx
1728
- import {
1729
- normalizeAgentActivityDisplayStatus
1730
- } from "@tutti-os/agent-activity-core";
1731
- import {
1732
- MentionPaletteFromState,
1733
- flattenMentionPaletteEntries,
1734
- renderMentionRow
1735
- } from "@tutti-os/ui-rich-text/at-panel";
1736
- import { resolveIssueManagerStatusPresentation } from "@tutti-os/workspace-issue-manager/ui";
1737
-
1738
- // shared/roomIssueStatusLabel.ts
1739
- function roomIssueStatusLabel(status, t) {
1740
- const translateFn = t ?? translate;
1741
- switch (status) {
1742
- case "not_started":
1743
- return translateFn("agentHost.roomIssueNode.issueStatusNotStarted");
1744
- case "running":
1745
- return translateFn("agentHost.roomIssueNode.issueStatusRunning");
1746
- case "in_progress":
1747
- return translateFn("agentHost.roomIssueNode.issueStatusInProgress");
1748
- case "pending_acceptance":
1749
- return translateFn(
1750
- "agentHost.roomIssueNode.issueStatusPendingAcceptance"
1751
- );
1752
- case "completed":
1753
- return translateFn("agentHost.roomIssueNode.issueStatusCompleted");
1754
- case "failed":
1755
- return translateFn("agentHost.roomIssueNode.issueStatusFailed");
1756
- case "canceled":
1757
- return translateFn("agentHost.roomIssueNode.issueStatusCanceled");
1758
- default:
1759
- return status || translateFn("agentHost.roomIssueNode.issueStatusUnknown");
1500
+ setFilter(filter) {
1501
+ if (this.disposed) {
1502
+ return;
1503
+ }
1504
+ this.currentFilter = filter;
1505
+ this.clearTimer();
1506
+ const requestId = ++this.requestId;
1507
+ this.resetAgentGeneratedBrowsePath();
1508
+ this.resetExpandedCounts();
1509
+ this.resetSearchLimits();
1510
+ this.resetRawGroups();
1511
+ if (!this.currentQuery) {
1512
+ this.startBrowseModeFetch(filter);
1513
+ return;
1514
+ }
1515
+ if (!this.activeWorkspaceId) {
1516
+ this.setState({
1517
+ status: "ready",
1518
+ query: this.currentQuery,
1519
+ mode: "results",
1520
+ filter: this.currentFilter,
1521
+ categories: buildBrowseCategories(),
1522
+ groups: [],
1523
+ error: null
1524
+ });
1525
+ return;
1526
+ }
1527
+ this.setState({
1528
+ status: "loading",
1529
+ query: this.currentQuery,
1530
+ mode: "results",
1531
+ filter: this.currentFilter,
1532
+ categories: buildBrowseCategories(),
1533
+ groups: this.groupsFromRawGroups(),
1534
+ error: null
1535
+ });
1536
+ void this.runSearch({
1537
+ workspaceId: this.activeWorkspaceId,
1538
+ currentUserId: this.currentUserId,
1539
+ query: this.currentQuery,
1540
+ requestId,
1541
+ filter
1542
+ });
1760
1543
  }
1761
- }
1762
-
1763
- // agent-gui/agentGuiNode/AgentFileMentionPalette.tsx
1764
- import { jsx } from "react/jsx-runtime";
1765
- var AGENT_MENTION_PALETTE_THEME = {
1766
- classNames: {
1767
- palette: "agent-gui-node__mention-palette",
1768
- header: "agent-gui-node__mention-palette-header",
1769
- footer: "agent-gui-node__mention-palette-footer",
1770
- tabs: "agent-gui-node__mention-palette-tabs",
1771
- scrollRegion: "agent-gui-node__mention-palette-scroll-region",
1772
- scrollbar: "workspace-agents-status-panel__scrollbar agent-gui-node__mention-palette-scrollbar",
1773
- scrollbarThumb: "workspace-agents-status-panel__scrollbar-thumb",
1774
- hint: "agent-gui-node__mention-palette-hint",
1775
- hintItem: "agent-gui-node__mention-palette-hint-item",
1776
- hintButton: "agent-gui-node__mention-palette-hint-button",
1777
- hintSeparator: "agent-gui-node__mention-palette-hint-separator",
1778
- shortcut: "agent-gui-node__mention-palette-shortcut",
1779
- shortcutArrow: "agent-gui-node__mention-palette-shortcut--arrow",
1780
- shortcutButton: "agent-gui-node__mention-palette-shortcut-button",
1781
- shortcutGroup: "agent-gui-node__mention-palette-shortcut-group"
1782
- },
1783
- testIds: {
1784
- emptyState: "agent-gui-mention-palette-empty-state",
1785
- hint: "agent-gui-mention-palette-hint",
1786
- scrollbar: "agent-gui-mention-palette-scrollbar",
1787
- loadingSpinner: "agent-mention-loading-spinner"
1788
- },
1789
- groupDividerAttribute: "data-agent-mention-group-divider"
1790
- };
1791
- var AGENT_MENTION_ROW_CLASS_NAMES = {
1792
- fileIcon: "agent-gui-node__mention-file-icon",
1793
- fileThumb: "agent-gui-node__mention-file-thumb",
1794
- kindIcon: "tsh-agent-object-token__kind-icon",
1795
- avatarImgUserPlaceholder: "workspace-agents-status-panel__avatar-img--user-placeholder"
1796
- };
1797
- function agentMentionItemKey(item) {
1798
- return `${item.kind}:${item.kind === "file" ? agentGeneratedMentionItemKey(item) : item.targetId}`;
1799
- }
1800
- function flattenAgentMentionPaletteEntries(state) {
1801
- return flattenMentionPaletteEntries(
1802
- state,
1803
- (item) => agentMentionItemKey(item)
1804
- ).map((entry) => {
1805
- if (entry.type === "item") {
1806
- const item = entry.groupId !== void 0 && entry.itemIndex !== void 0 ? state.groups.find((group) => group.id === entry.groupId)?.items[entry.itemIndex] : void 0;
1807
- return {
1808
- key: entry.key,
1809
- type: "item",
1810
- groupId: entry.groupId,
1811
- item
1812
- };
1544
+ preloadBrowse(input) {
1545
+ if (this.disposed) {
1546
+ return;
1813
1547
  }
1814
- return {
1815
- key: entry.key,
1816
- type: entry.type,
1817
- categoryId: entry.categoryId,
1818
- groupId: entry.groupId
1819
- };
1820
- });
1821
- }
1822
- function groupStartKeys(state) {
1823
- if (state.mode === "browse") {
1824
- return state.categories.map((category) => `category:${category.id}`);
1825
- }
1826
- return state.groups.map((group) => {
1827
- const firstItem = group.items[0];
1828
- if (firstItem) {
1829
- return `${group.id}:${agentMentionItemKey(firstItem)}`;
1548
+ const workspaceId = input.workspaceId.trim();
1549
+ if (!workspaceId) {
1550
+ return;
1551
+ }
1552
+ const filter = input.filter ?? DEFAULT_AGENT_MENTION_FILTER;
1553
+ const currentUserId = input.currentUserId?.trim() ?? "";
1554
+ const sessionCwd = input.sessionCwd?.trim() ?? "";
1555
+ const cacheKey = this.browseCacheKey({
1556
+ currentUserId,
1557
+ filter,
1558
+ sessionCwd,
1559
+ workspaceId
1560
+ });
1561
+ if (this.readBrowseCache(cacheKey).isFresh) {
1562
+ return;
1563
+ }
1564
+ if (this.pendingPreloadKey === cacheKey) {
1565
+ return;
1830
1566
  }
1831
- if (group.hasMore) {
1832
- return `expand:${group.id}`;
1567
+ this.cancelPendingPreload();
1568
+ this.pendingPreloadKey = cacheKey;
1569
+ this.preloadCancel = scheduleAgentMentionIdleTask(() => {
1570
+ this.preloadCancel = null;
1571
+ this.pendingPreloadKey = null;
1572
+ if (this.disposed) {
1573
+ return;
1574
+ }
1575
+ this.runBrowsePreload({
1576
+ cacheKey,
1577
+ currentUserId,
1578
+ filter,
1579
+ sessionCwd,
1580
+ workspaceId
1581
+ });
1582
+ });
1583
+ }
1584
+ runBrowsePreload(input) {
1585
+ const { cacheKey, currentUserId, filter, sessionCwd, workspaceId } = input;
1586
+ this.logLifecycle("browse.preload", {
1587
+ filter,
1588
+ providerIds: this.providerIdsForDiagnostics(),
1589
+ sessionCwdPresent: Boolean(sessionCwd),
1590
+ workspaceId
1591
+ });
1592
+ const cached = this.readBrowseCache(cacheKey);
1593
+ this.logBrowseCacheState({
1594
+ cacheKey,
1595
+ cached,
1596
+ filter,
1597
+ reason: "preload",
1598
+ workspaceId
1599
+ });
1600
+ if (cached.isFresh) {
1601
+ return;
1833
1602
  }
1834
- return null;
1835
- }).filter((key) => key !== null);
1836
- }
1837
- function AgentFileMentionPalette({
1838
- state,
1839
- highlightedKey,
1840
- label,
1841
- loadingLabel,
1842
- emptyLabel,
1843
- errorLabel,
1844
- tabHintLabel,
1845
- maxHeightPx,
1846
- shouldCenterHighlightedItem = false,
1847
- onHighlightChange,
1848
- onSelectItem,
1849
- onSelectCategory,
1850
- onSelectFilter,
1851
- onExpandGroup,
1852
- onNavigateHierarchy,
1853
- onNavigateIntoItem,
1854
- onOpenReferences
1855
- }) {
1856
- "use memo";
1857
- const openReferencesLabel = translate(
1858
- "agentHost.agentGui.mentionOpenReferences"
1859
- );
1860
- const navigateIntoLabel = translate(
1861
- "agentHost.agentGui.fileMentionEnterFolder"
1862
- );
1863
- const filter = state.filter;
1864
- const highlightedBrowseCategory = highlightedKey?.startsWith("category:") ? highlightedKey.slice("category:".length) : null;
1865
- const showBrowseHint = shouldShowBrowseSearchHint({
1866
- browseFilter: filter,
1867
- groups: state.groups,
1868
- highlightedBrowseCategory,
1869
- mode: state.mode
1870
- });
1871
- const categories = state.mode === "browse" ? state.categories : AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({
1872
- id,
1873
- label: agentMentionFilterLabel(id)
1874
- }));
1875
- const shellState = showBrowseHint ? { ...state, categories, groups: [] } : {
1876
- ...state,
1877
- categories,
1878
- groups: state.groups.map(
1879
- (group, index) => decorateMentionGroup(
1880
- group,
1881
- index,
1882
- state.groups,
1603
+ void this.loadBrowseFetchResult(
1604
+ {
1605
+ workspaceId,
1606
+ currentUserId,
1883
1607
  filter,
1884
- state.query
1885
- )
1886
- )
1887
- };
1888
- const emptyLabelForShell = showBrowseHint ? browseHintForFilter(filter) : resolveMentionPaletteEmptyLabel({
1889
- emptyLabel,
1890
- filter,
1891
- mode: state.mode,
1892
- query: state.query
1893
- });
1894
- return /* @__PURE__ */ jsx(
1895
- MentionPaletteFromState,
1896
- {
1897
- state: shellState,
1898
- highlightedKey,
1899
- getItemKey: agentMentionItemKey,
1900
- renderItem: (item, { group }) => renderMentionRow(agentMentionItemToRowItem(item), {
1901
- classNames: AGENT_MENTION_ROW_CLASS_NAMES,
1902
- dataAttributeMode: "agent",
1903
- ...onNavigateIntoItem && canNavigateIntoMentionItem(item, group) ? {
1904
- onNavigateInto: () => onNavigateIntoItem(item),
1905
- navigateIntoLabel
1906
- } : {},
1907
- ...onOpenReferences && isReferenceableMentionItem(item) ? {
1908
- onOpenReferences: () => onOpenReferences(item),
1909
- openReferencesLabel
1910
- } : {}
1911
- }),
1912
- labels: {
1913
- loading: loadingLabel,
1914
- empty: emptyLabelForShell,
1915
- error: errorLabel,
1916
- tabHint: tabHintLabel,
1917
- listbox: label
1918
- },
1919
- hintLabels: {
1920
- cycleFilter: translate("agentHost.agentGui.fileMentionSwitchCategory"),
1921
- moveSelection: translate(
1922
- "agentHost.agentGui.fileMentionSwitchSelection"
1923
- ),
1924
- navigateHierarchy: translate(
1925
- "agentHost.agentGui.fileMentionNavigateHierarchy"
1926
- )
1927
- },
1928
- maxHeightPx,
1929
- scrollHighlightedIntoViewCentered: shouldCenterHighlightedItem,
1930
- theme: AGENT_MENTION_PALETTE_THEME,
1931
- callbacks: {
1932
- onHighlightChange,
1933
- onActiveCategoryIdChange: (categoryId) => {
1934
- onSelectCategory(categoryId);
1935
- onSelectFilter(categoryId);
1936
- },
1937
- onExpandGroup: (groupId) => onExpandGroup(groupId),
1938
- onSelectItem
1608
+ sessionCwd
1939
1609
  },
1940
- onNavigateHierarchy
1941
- }
1942
- );
1943
- }
1944
- var AgentContextMentionPalette = AgentFileMentionPalette;
1945
- function decorateMentionGroup(group, index, groups, filter, query) {
1946
- const groupId = group.id;
1947
- const suppressChrome = shouldSuppressFileSearchGroupChrome(filter, query);
1948
- const followsMySessions = groupId === "collab_sessions" && groups[index - 1]?.id === "my_sessions";
1949
- const showLabel = shouldRenderMentionGroupLabel({
1950
- filter,
1951
- groupCount: groups.length,
1952
- groupId,
1953
- query
1954
- });
1955
- return {
1956
- ...group,
1957
- label: showLabel ? agentMentionGroupLabel(groupId) : void 0,
1958
- emptyLabel: suppressChrome ? void 0 : agentMentionEmptyGroupLabel(groupId, query),
1959
- expandLabel: group.hasMore ? translate("agentHost.agentGui.contextPickerExpandMore", {
1960
- count: mentionGroupExpandCount(group, filter)
1961
- }) : void 0,
1962
- sectionClassName: followsMySessions ? "mt-2" : void 0,
1963
- hideTopDivider: suppressChrome
1964
- };
1965
- }
1966
- function shouldSuppressFileSearchGroupChrome(filter, query) {
1967
- return filter === "file" && query.trim().length > 0;
1968
- }
1969
- function resolveMentionPaletteEmptyLabel(input) {
1970
- if (input.mode === "results" && input.filter === "file" && input.query.trim().length > 0) {
1971
- return translate("agentHost.agentGui.mentionNoMatchingFiles");
1972
- }
1973
- if (input.filter === "session") {
1974
- return agentMentionEmptyGroupLabel("my_sessions", input.query);
1975
- }
1976
- if (input.filter === "app") {
1977
- return agentMentionEmptyGroupLabel("apps", input.query);
1610
+ cacheKey,
1611
+ "preload"
1612
+ ).catch((error) => {
1613
+ this.logLifecycle("browse.fetch.error", {
1614
+ errorKind: diagnosticErrorKind(error),
1615
+ filter,
1616
+ reason: "preload",
1617
+ workspaceId
1618
+ });
1619
+ });
1978
1620
  }
1979
- if (input.filter === "agent") {
1980
- return agentMentionEmptyGroupLabel("agents", input.query);
1621
+ cancelPendingPreload() {
1622
+ if (this.preloadCancel) {
1623
+ this.preloadCancel();
1624
+ this.preloadCancel = null;
1625
+ }
1626
+ this.pendingPreloadKey = null;
1981
1627
  }
1982
- if (input.filter === "issue") {
1983
- return agentMentionEmptyGroupLabel("issues", input.query);
1628
+ enterCategory(category) {
1629
+ this.setFilter(category);
1984
1630
  }
1985
- return input.emptyLabel;
1986
- }
1987
- function shouldRenderMentionGroupLabel(input) {
1988
- if (shouldSuppressFileSearchGroupChrome(input.filter, input.query)) {
1631
+ selectAgentGeneratedMentionItem(item) {
1632
+ if (item.kind !== "file" || !item.mentionNavigation) {
1633
+ return false;
1634
+ }
1635
+ if (item.mentionNavigation === "agent-generated-folder") {
1636
+ this.agentGeneratedBrowsePath = item.path;
1637
+ this.expandedCounts.agent_generated_files = mentionGroupPageSize(
1638
+ this.currentFilter,
1639
+ "agent_generated_files"
1640
+ );
1641
+ this.setState({
1642
+ status: this.state.status === "loading" ? "loading" : "ready",
1643
+ query: this.currentQuery,
1644
+ mode: this.currentQuery ? "results" : "browse",
1645
+ filter: this.currentFilter,
1646
+ categories: buildBrowseCategories(),
1647
+ groups: this.groupsFromRawGroups(),
1648
+ error: null
1649
+ });
1650
+ return true;
1651
+ }
1652
+ if (item.mentionNavigation === "agent-generated-folder-back") {
1653
+ this.resetAgentGeneratedBrowsePath();
1654
+ this.setState({
1655
+ status: this.state.status === "loading" ? "loading" : "ready",
1656
+ query: this.currentQuery,
1657
+ mode: this.currentQuery ? "results" : "browse",
1658
+ filter: this.currentFilter,
1659
+ categories: buildBrowseCategories(),
1660
+ groups: this.groupsFromRawGroups(),
1661
+ error: null
1662
+ });
1663
+ return true;
1664
+ }
1989
1665
  return false;
1990
1666
  }
1991
- if (input.groupCount !== 1) {
1992
- return true;
1993
- }
1994
- return agentMentionGroupLabel(input.groupId) !== agentMentionFilterLabel(input.filter);
1995
- }
1996
- function agentMentionItemToRowItem(item) {
1997
- if (item.kind === "file") {
1998
- const visualKind = resolveAgentMentionFileVisualKind({
1999
- entryKind: item.entryKind,
2000
- href: item.href,
2001
- mentionNavigation: item.mentionNavigation,
2002
- name: item.name,
2003
- path: item.path
1667
+ exitAgentGeneratedBrowse() {
1668
+ if (!this.agentGeneratedBrowsePath) {
1669
+ return false;
1670
+ }
1671
+ this.resetAgentGeneratedBrowsePath();
1672
+ this.setState({
1673
+ status: this.state.status === "loading" ? "loading" : "ready",
1674
+ query: this.currentQuery,
1675
+ mode: this.currentQuery ? "results" : "browse",
1676
+ filter: this.currentFilter,
1677
+ categories: buildBrowseCategories(),
1678
+ groups: this.groupsFromRawGroups(),
1679
+ error: null
2004
1680
  });
2005
- const childCountLabel = item.mentionNavigation === "agent-generated-folder" && typeof item.childCount === "number" && item.childCount > 0 ? translate("agentHost.agentGui.mentionAgentGeneratedFolderFileCount", {
2006
- count: item.childCount
2007
- }) : null;
2008
- return {
2009
- kind: "file",
2010
- name: item.name,
2011
- visualKind,
2012
- thumbnailUrl: resolveAgentMentionFileThumbnailUrl(item) ?? null,
2013
- childCountLabel,
2014
- entryKind: item.entryKind,
2015
- mentionNavigation: item.mentionNavigation
2016
- };
2017
- }
2018
- if (item.kind === "session") {
2019
- const isMySession = item.scope === "my_sessions";
2020
- return {
2021
- kind: "session",
2022
- participant: isMySession ? item.agentName : `${item.initiatorName} & ${item.agentName}`,
2023
- summary: item.title,
2024
- userAvatarUrl: isMySession ? null : item.initiatorAvatarUrl ?? null,
2025
- userAvatarPlaceholderUrl,
2026
- agentIconUrl: managedAgentRoundedIconUrl(
2027
- mentionSessionAgentProvider(item) ?? item.agentName
2028
- ),
2029
- showUserAvatar: !isMySession,
2030
- statusTag: agentSessionStatusTag(item.status)
2031
- };
2032
- }
2033
- if (item.kind === "workspace-app") {
2034
- return {
2035
- kind: "app",
2036
- name: item.name,
2037
- description: item.description ?? null,
2038
- iconUrl: item.iconUrl ?? null
2039
- };
2040
- }
2041
- if (item.kind === "agent-target") {
2042
- return {
2043
- kind: "app",
2044
- name: item.name,
2045
- description: item.description ?? null,
2046
- iconUrl: item.iconUrl ?? managedAgentRoundedIconUrl(item.agentProviderId),
2047
- statusTag: agentTargetAvailableStatusTag()
2048
- };
2049
- }
2050
- if (item.kind === "workspace-reference") {
2051
- return {
2052
- kind: "app",
2053
- name: item.name,
2054
- description: null,
2055
- iconUrl: item.iconUrl ?? null
2056
- };
2057
- }
2058
- if (item.kind === "workspace-app-factory") {
2059
- return {
2060
- kind: "app-factory",
2061
- name: item.name
2062
- };
2063
- }
2064
- if (item.kind === "custom") {
2065
- return {
2066
- kind: "issue",
2067
- title: item.name,
2068
- creatorName: null,
2069
- statusTag: null
2070
- };
2071
- }
2072
- return {
2073
- kind: "issue",
2074
- title: item.title,
2075
- creatorName: item.creatorName ?? null,
2076
- statusTag: agentIssueStatusTag(item.status)
2077
- };
2078
- }
2079
- function isReferenceableMentionItem(item) {
2080
- if (item.kind === "workspace-issue") {
2081
1681
  return true;
2082
1682
  }
2083
- if (item.kind === "workspace-app") {
2084
- return item.referencesListSupported === true;
2085
- }
2086
- return false;
2087
- }
2088
- function canNavigateIntoMentionItem(item, group) {
2089
- return group.id === "agent_generated_files" && item.kind === "file" && item.mentionNavigation === "agent-generated-folder";
2090
- }
2091
- function mentionSessionAgentProvider(item) {
2092
- const queryStart = item.href.indexOf("?");
2093
- if (queryStart < 0) {
2094
- return null;
2095
- }
2096
- return new URLSearchParams(item.href.slice(queryStart + 1)).get("provider");
2097
- }
2098
- function agentSessionStatusTag(status) {
2099
- if (!status) {
2100
- return null;
2101
- }
2102
- const activityStatus = normalizeAgentActivityDisplayStatus(status);
2103
- return {
2104
- label: workspaceAgentActivityStatusLabel(activityStatus),
2105
- tone: mentionStatusTone(activityStatus),
2106
- pulse: activityStatus === "working" || activityStatus === "waiting",
2107
- variant: "activity",
2108
- dataStatus: activityStatus
2109
- };
2110
- }
2111
- function agentTargetAvailableStatusTag() {
2112
- return {
2113
- label: translate("agentHost.agentGui.mentionAgentTargetAvailable"),
2114
- tone: "green",
2115
- variant: "activity",
2116
- dataStatus: "available"
2117
- };
2118
- }
2119
- function agentIssueStatusTag(status) {
2120
- if (!status) {
2121
- return null;
2122
- }
2123
- const presentation = resolveIssueManagerStatusPresentation(status);
2124
- return {
2125
- label: roomIssueStatusLabel(status),
2126
- tone: presentation.mentionTone,
2127
- variant: "issue",
2128
- dataStatus: presentation.dataStatus
2129
- };
2130
- }
2131
- function mentionStatusTone(status) {
2132
- if (status === "working") {
2133
- return "blue";
2134
- }
2135
- if (status === "waiting" || status === "canceled") {
2136
- return "amber";
2137
- }
2138
- if (status === "completed" || status === "idle") {
2139
- return "green";
2140
- }
2141
- if (status === "failed") {
2142
- return "red";
2143
- }
2144
- return "neutral";
2145
- }
2146
- function browseHintForFilter(filter) {
2147
- switch (filter) {
2148
- case "agent":
2149
- return translate("agentHost.agentGui.contextPickerBrowseAgentHint");
2150
- case "app":
2151
- return translate("agentHost.agentGui.contextPickerBrowseAppHint");
2152
- case "file":
2153
- return translate("agentHost.agentGui.contextPickerBrowseFileHint");
2154
- case "session":
2155
- return translate("agentHost.agentGui.contextPickerBrowseSessionHint");
2156
- case "issue":
2157
- return translate("agentHost.agentGui.contextPickerBrowseIssueHint");
2158
- }
2159
- }
2160
- function hasInteractiveGroupEntries(groups) {
2161
- return groups.some((group) => group.items.length > 0 || group.hasMore);
2162
- }
2163
- function isFileBrowseGroupsOnlyEmpty(groups) {
2164
- const fileGroups = groups.filter(
2165
- (group) => group.id === "opened_files" || group.id === "agent_generated_files"
2166
- );
2167
- if (fileGroups.length === 0) {
2168
- return false;
2169
- }
2170
- return fileGroups.every(
2171
- (group) => group.items.length === 0 && !group.hasMore
2172
- );
2173
- }
2174
- function shouldShowBrowseSearchHint(input) {
2175
- if (input.mode !== "browse" || hasInteractiveGroupEntries(input.groups)) {
2176
- return false;
1683
+ expandGroup(groupId) {
1684
+ const pageSize = mentionGroupPageSize(this.currentFilter, groupId);
1685
+ const current = this.expandedCounts[groupId] ?? pageSize;
1686
+ this.expandedCounts[groupId] = current + pageSize;
1687
+ if (!this.currentQuery) {
1688
+ this.setState({
1689
+ status: "ready",
1690
+ query: "",
1691
+ mode: "browse",
1692
+ filter: this.currentFilter,
1693
+ categories: buildBrowseCategories(),
1694
+ groups: this.groupsFromRawGroups(),
1695
+ error: null
1696
+ });
1697
+ return;
1698
+ }
1699
+ const needsMoreFiles = (groupId === "opened_files" || groupId === "files" || groupId === "agent_generated_files") && (groupId === "agent_generated_files" ? this.rawGroups.agent_generated_files.length >= this.currentFileSearchLimit : this.rawGroups.opened_files.length >= this.currentFileSearchLimit);
1700
+ const needsMoreIssues = groupId === "issues" && (this.totalCounts.issues ?? this.rawGroups.issues.length) > this.rawGroups.issues.length;
1701
+ if (needsMoreFiles) {
1702
+ this.currentFileSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
1703
+ }
1704
+ if (needsMoreIssues) {
1705
+ this.currentIssueSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
1706
+ }
1707
+ if (needsMoreFiles || needsMoreIssues) {
1708
+ this.clearTimer();
1709
+ const requestId = ++this.requestId;
1710
+ this.setState({
1711
+ status: "loading",
1712
+ query: this.currentQuery,
1713
+ mode: "results",
1714
+ filter: this.currentFilter,
1715
+ categories: buildBrowseCategories(),
1716
+ groups: this.groupsFromRawGroups(),
1717
+ error: null
1718
+ });
1719
+ void this.runSearch({
1720
+ workspaceId: this.activeWorkspaceId,
1721
+ currentUserId: this.currentUserId,
1722
+ query: this.currentQuery,
1723
+ requestId,
1724
+ filter: this.currentFilter
1725
+ });
1726
+ return;
1727
+ }
1728
+ this.setState({
1729
+ status: "ready",
1730
+ query: this.currentQuery,
1731
+ mode: "results",
1732
+ filter: this.currentFilter,
1733
+ categories: buildBrowseCategories(),
1734
+ groups: this.groupsFromRawGroups(),
1735
+ error: null
1736
+ });
2177
1737
  }
2178
- if (input.groups.length === 0) {
2179
- return true;
1738
+ close() {
1739
+ this.clearTimer();
1740
+ this.requestId += 1;
1741
+ this.currentFilter = DEFAULT_AGENT_MENTION_FILTER;
1742
+ this.resetAgentGeneratedBrowsePath();
1743
+ this.resetExpandedCounts();
1744
+ this.resetSearchLimits();
1745
+ this.resetRawGroups();
1746
+ this.currentQuery = "";
1747
+ this.setState({
1748
+ status: "idle",
1749
+ query: "",
1750
+ mode: "browse",
1751
+ filter: DEFAULT_AGENT_MENTION_FILTER,
1752
+ categories: buildBrowseCategories(),
1753
+ groups: [],
1754
+ error: null
1755
+ });
2180
1756
  }
2181
- if (input.highlightedBrowseCategory !== null && input.highlightedBrowseCategory !== input.browseFilter) {
2182
- return true;
1757
+ dispose() {
1758
+ this.disposed = true;
1759
+ this.clearTimer();
1760
+ this.cancelPendingPreload();
1761
+ this.listeners.clear();
1762
+ this.requestId += 1;
2183
1763
  }
2184
- return input.browseFilter === "file" && isFileBrowseGroupsOnlyEmpty(input.groups);
1764
+ };
1765
+ function preloadAgentMentionBrowse(input) {
1766
+ const controller = new AgentMentionSearchController({
1767
+ contextMentionProviders: input.contextMentionProviders
1768
+ });
1769
+ controller.preloadBrowse({
1770
+ workspaceId: input.workspaceId,
1771
+ currentUserId: input.currentUserId,
1772
+ sessionCwd: input.sessionCwd,
1773
+ filter: input.filter
1774
+ });
2185
1775
  }
2186
1776
 
2187
1777
  export {
1778
+ agentMentionGroupLabel,
1779
+ agentMentionFilterLabel,
1780
+ agentMentionEmptyGroupLabel,
2188
1781
  AGENT_MENTION_FILTER_TAB_ORDER,
2189
1782
  DEFAULT_AGENT_MENTION_FILTER,
1783
+ mentionGroupExpandCount,
1784
+ agentGeneratedMentionItemKey,
1785
+ MAX_BROWSE_CACHE_ENTRIES,
1786
+ resetAgentMentionSearchBrowseCacheForTests,
2190
1787
  AgentMentionSearchController,
2191
- preloadAgentMentionBrowse,
2192
- agentMentionItemKey,
2193
- flattenAgentMentionPaletteEntries,
2194
- groupStartKeys,
2195
- AgentFileMentionPalette,
2196
- AgentContextMentionPalette
1788
+ preloadAgentMentionBrowse
2197
1789
  };
2198
- //# sourceMappingURL=chunk-IGY4ASUF.js.map
1790
+ //# sourceMappingURL=chunk-WMNS4MAQ.js.map