@tutti-os/agent-gui 0.0.93 → 0.0.95

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 (164) hide show
  1. package/README.md +48 -32
  2. package/dist/AgentGUI-CwBLYtv-.d.ts +992 -0
  3. package/dist/agent-conversation/index.d.ts +5 -7
  4. package/dist/agent-conversation/index.js +13 -9
  5. package/dist/agent-conversation/index.js.map +1 -1
  6. package/dist/agent-env/index.d.ts +14 -38
  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 +145 -122
  12. package/dist/agent-message-center/index.js +1473 -1398
  13. package/dist/agent-message-center/index.js.map +1 -1
  14. package/dist/{agentConversationVM-CfXN_TQ2.d.ts → agentConversationVM-C335TR6S.d.ts} +112 -7
  15. package/dist/agentFileMentionContracts-Czvz6YMI.d.ts +107 -0
  16. package/dist/{agentGuiNodeTypes-rGaDqxVR.d.ts → agentGuiNodeTypes-DppADPHW.d.ts} +102 -149
  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 +431 -75
  21. package/dist/app/renderer/assets/icons/agent-vinyl-player-chassis.png +0 -0
  22. package/dist/app/renderer/assets/icons/agent-vinyl-tonearm.png +0 -0
  23. package/dist/app/renderer/assets/icons/agent-vinyls/claude-vinyl.png +0 -0
  24. package/dist/app/renderer/assets/icons/agent-vinyls/codex-vinyl.png +0 -0
  25. package/dist/app/renderer/assets/icons/agent-vinyls/cursor-vinyl.png +0 -0
  26. package/dist/app/renderer/assets/icons/agent-vinyls/hermes-vinyl.png +0 -0
  27. package/dist/app/renderer/assets/icons/agent-vinyls/openclaw-vinyl.png +0 -0
  28. package/dist/app/renderer/assets/icons/agent-vinyls/opencode-vinyl.png +0 -0
  29. package/dist/app/renderer/assets/icons/agent-vinyls/tutti-vinyl.png +0 -0
  30. package/dist/app/renderer/assets/icons/open-link-lined.svg +4 -0
  31. package/dist/{chunk-7QHBFRG5.js → chunk-3R2D4E57.js} +3137 -3396
  32. package/dist/chunk-3R2D4E57.js.map +1 -0
  33. package/dist/chunk-4YG7YK7S.js +23 -0
  34. package/dist/chunk-4YG7YK7S.js.map +1 -0
  35. package/dist/chunk-5X7YDOC6.js +42 -0
  36. package/dist/chunk-5X7YDOC6.js.map +1 -0
  37. package/dist/{chunk-IBIMGLCD.js → chunk-7J4K6WKB.js} +1 -1
  38. package/dist/chunk-7J4K6WKB.js.map +1 -0
  39. package/dist/{chunk-KQE5KV2V.js → chunk-7PFDA2HQ.js} +505 -504
  40. package/dist/chunk-7PFDA2HQ.js.map +1 -0
  41. package/dist/{chunk-M2LWH54R.js → chunk-7RDD3EWP.js} +557 -569
  42. package/dist/chunk-7RDD3EWP.js.map +1 -0
  43. package/dist/{chunk-VWXFFSIM.js → chunk-AOS2VWU6.js} +1357 -1301
  44. package/dist/chunk-AOS2VWU6.js.map +1 -0
  45. package/dist/{chunk-3HARXLAZ.js → chunk-BFNJKTDV.js} +295 -255
  46. package/dist/chunk-BFNJKTDV.js.map +1 -0
  47. package/dist/{chunk-U7D7G3UU.js → chunk-BIHBXWK5.js} +2 -2
  48. package/dist/{chunk-XQUUELKF.js → chunk-C5FV4UGI.js} +2921 -2944
  49. package/dist/chunk-C5FV4UGI.js.map +1 -0
  50. package/dist/{chunk-HOSX5C5V.js → chunk-CRO2MV2Y.js} +36 -46
  51. package/dist/chunk-CRO2MV2Y.js.map +1 -0
  52. package/dist/chunk-FGLQZ6I4.js +9 -0
  53. package/dist/chunk-FGLQZ6I4.js.map +1 -0
  54. package/dist/chunk-H6IQ63DQ.js +14 -0
  55. package/dist/chunk-H6IQ63DQ.js.map +1 -0
  56. package/dist/{chunk-4SQNOOJ3.js → chunk-JX2SIXNL.js} +1293 -1702
  57. package/dist/chunk-JX2SIXNL.js.map +1 -0
  58. package/dist/chunk-KAL4XZMA.js +231 -0
  59. package/dist/chunk-KAL4XZMA.js.map +1 -0
  60. package/dist/chunk-KJQERFKX.js +259 -0
  61. package/dist/chunk-KJQERFKX.js.map +1 -0
  62. package/dist/chunk-LQVXBT65.js +491 -0
  63. package/dist/chunk-LQVXBT65.js.map +1 -0
  64. package/dist/{chunk-AOVPGJBC.js → chunk-NITOD7WF.js} +2 -2
  65. package/dist/{chunk-7LMJXF4R.js → chunk-NJAZ7LQM.js} +20 -16
  66. package/dist/chunk-NJAZ7LQM.js.map +1 -0
  67. package/dist/chunk-NX3CZJXW.js +25 -0
  68. package/dist/chunk-NX3CZJXW.js.map +1 -0
  69. package/dist/chunk-O6W72SEP.js +93 -0
  70. package/dist/chunk-O6W72SEP.js.map +1 -0
  71. package/dist/{chunk-PSLAWU25.js → chunk-R2EWECUP.js} +7 -1
  72. package/dist/chunk-R2EWECUP.js.map +1 -0
  73. package/dist/chunk-RY6GIO3K.js +31700 -0
  74. package/dist/chunk-RY6GIO3K.js.map +1 -0
  75. package/dist/{chunk-XDV4ZRVK.js → chunk-UGVI47X6.js} +98 -37
  76. package/dist/chunk-UGVI47X6.js.map +1 -0
  77. package/dist/{chunk-XW4CVBUH.js → chunk-UQJPV6HP.js} +18 -11
  78. package/dist/chunk-UQJPV6HP.js.map +1 -0
  79. package/dist/{chunk-GAPTLVII.js → chunk-VF22EG3F.js} +1 -1
  80. package/dist/{chunk-GAPTLVII.js.map → chunk-VF22EG3F.js.map} +1 -1
  81. package/dist/{chunk-45FF4DQU.js → chunk-WEDMAVX2.js} +22 -24
  82. package/dist/chunk-WEDMAVX2.js.map +1 -0
  83. package/dist/{chunk-SXDLSEHO.js → chunk-XMO45GKA.js} +531 -401
  84. package/dist/chunk-XMO45GKA.js.map +1 -0
  85. package/dist/{chunk-UNO7CEAF.js → chunk-YE25HN6T.js} +6 -9
  86. package/dist/chunk-YE25HN6T.js.map +1 -0
  87. package/dist/context-mention-palette/index.d.ts +3 -2
  88. package/dist/context-mention-palette/index.js +19 -14
  89. package/dist/custom-mention.d.ts +44 -0
  90. package/dist/custom-mention.js +17 -0
  91. package/dist/custom-mention.js.map +1 -0
  92. package/dist/dock-icons.d.ts +6 -0
  93. package/dist/dock-icons.js +11 -0
  94. package/dist/dock-icons.js.map +1 -0
  95. package/dist/i18n/index.d.ts +852 -837
  96. package/dist/i18n/index.js +2 -2
  97. package/dist/index.d.ts +52 -1061
  98. package/dist/index.js +72 -35254
  99. package/dist/index.js.map +1 -1
  100. package/dist/mention-search.d.ts +226 -0
  101. package/dist/mention-search.js +29 -0
  102. package/dist/mention-search.js.map +1 -0
  103. package/dist/open-link-lined-JWEKUKME.svg +4 -0
  104. package/dist/provider-icons.d.ts +6 -0
  105. package/dist/provider-icons.js +12 -0
  106. package/dist/provider-icons.js.map +1 -0
  107. package/dist/provider-identity.d.ts +9 -0
  108. package/dist/provider-identity.js +21 -0
  109. package/dist/provider-identity.js.map +1 -0
  110. package/dist/runtime-BBNdWgDU.d.ts +10 -0
  111. package/dist/{types-PLFZ8SBX.d.ts → types-DX2bxgB8.d.ts} +28 -83
  112. package/dist/workbench/contribution.d.ts +32 -40
  113. package/dist/workbench/contribution.js +10 -6
  114. package/dist/workbench/index.d.ts +6 -2
  115. package/dist/workbench/index.js +24 -20
  116. package/dist/workbench/launch.d.ts +2 -5
  117. package/dist/workbench/launch.js +4 -3
  118. package/dist/workbench/providerCatalog.js +2 -1
  119. package/dist/workbench/sessionTitle.d.ts +4 -3
  120. package/dist/workbench/sessionTitle.js +4 -3
  121. package/dist/workbench/state.d.ts +1 -1
  122. package/dist/workbench/state.js +3 -2
  123. package/dist/workbench/types.d.ts +0 -3
  124. package/dist/workbench/types.js +1 -1
  125. package/dist/workspace-agent-generated-files.d.ts +20 -2
  126. package/dist/workspace-agent-generated-files.js +7 -6
  127. package/dist/workspaceAgentActivityListTypes-C7gPWYiA.d.ts +71 -0
  128. package/package.json +65 -28
  129. package/dist/AgentMentionSearchController-DD_WOred.d.ts +0 -241
  130. package/dist/AgentMessageMarkdown-DeYPURtF.d.ts +0 -7
  131. package/dist/chunk-3HARXLAZ.js.map +0 -1
  132. package/dist/chunk-45FF4DQU.js.map +0 -1
  133. package/dist/chunk-4HP6V2YA.js +0 -207
  134. package/dist/chunk-4HP6V2YA.js.map +0 -1
  135. package/dist/chunk-4SQNOOJ3.js.map +0 -1
  136. package/dist/chunk-7LMJXF4R.js.map +0 -1
  137. package/dist/chunk-7QHBFRG5.js.map +0 -1
  138. package/dist/chunk-HOSX5C5V.js.map +0 -1
  139. package/dist/chunk-IBIMGLCD.js.map +0 -1
  140. package/dist/chunk-KQE5KV2V.js.map +0 -1
  141. package/dist/chunk-LR4FA5X6.js +0 -368
  142. package/dist/chunk-LR4FA5X6.js.map +0 -1
  143. package/dist/chunk-M2LWH54R.js.map +0 -1
  144. package/dist/chunk-MKHDRIGN.js +0 -71
  145. package/dist/chunk-MKHDRIGN.js.map +0 -1
  146. package/dist/chunk-PSLAWU25.js.map +0 -1
  147. package/dist/chunk-SXDLSEHO.js.map +0 -1
  148. package/dist/chunk-UNO7CEAF.js.map +0 -1
  149. package/dist/chunk-VAKFNNKT.js +0 -410
  150. package/dist/chunk-VAKFNNKT.js.map +0 -1
  151. package/dist/chunk-VWXFFSIM.js.map +0 -1
  152. package/dist/chunk-XDV4ZRVK.js.map +0 -1
  153. package/dist/chunk-XQUUELKF.js.map +0 -1
  154. package/dist/chunk-XW4CVBUH.js.map +0 -1
  155. package/dist/plan-decision-ops.d.ts +0 -70
  156. package/dist/plan-decision-ops.js +0 -19
  157. package/dist/queued-prompt-runtime.d.ts +0 -115
  158. package/dist/queued-prompt-runtime.js +0 -9
  159. package/dist/workspaceAgentActivityListViewModel-TXH1VXrk.d.ts +0 -339
  160. package/dist/workspaceLinkActions-DS9LWqzI.d.ts +0 -74
  161. /package/dist/{plan-decision-ops.js.map → agent-gui.js.map} +0 -0
  162. /package/dist/{queued-prompt-runtime.js.map → agents.js.map} +0 -0
  163. /package/dist/{chunk-U7D7G3UU.js.map → chunk-BIHBXWK5.js.map} +0 -0
  164. /package/dist/{chunk-AOVPGJBC.js.map → chunk-NITOD7WF.js.map} +0 -0
@@ -1,24 +1,198 @@
1
1
  import {
2
- userAvatarPlaceholderUrl,
3
- workspaceAgentActivityStatusLabel
4
- } from "./chunk-AOVPGJBC.js";
2
+ AGENT_CONTEXT_MENTION_PROVIDER_IDS
3
+ } from "./chunk-JM24HADP.js";
5
4
  import {
6
5
  normalizeAgentSessionMentionTitle
7
- } from "./chunk-KQE5KV2V.js";
6
+ } from "./chunk-7PFDA2HQ.js";
8
7
  import {
9
- resolveAgentMentionFileThumbnailUrl,
10
- resolveAgentMentionFileVisualKind
8
+ resolveAgentMentionFileThumbnailUrl
11
9
  } from "./chunk-LUGELG5V.js";
12
10
  import {
13
- getOptionalAgentHostApi,
14
- managedAgentRoundedIconUrl
15
- } from "./chunk-LR4FA5X6.js";
11
+ getOptionalAgentHostApi
12
+ } from "./chunk-KAL4XZMA.js";
16
13
  import {
17
14
  translate
18
- } from "./chunk-U7D7G3UU.js";
19
- import {
20
- AGENT_CONTEXT_MENTION_PROVIDER_IDS
21
- } from "./chunk-JM24HADP.js";
15
+ } from "./chunk-BIHBXWK5.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,197 @@ 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
+ status: presentation.status?.trim() || void 0,
551
+ inputPreview: description || void 0,
552
+ summaryPreview
553
+ };
400
554
  }
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);
555
+ return null;
415
556
  }
416
- function resolveMentionGroupItems(groupId, rawGroups) {
417
- if (groupId === "files") {
418
- return [...rawGroups.opened_files, ...rawGroups.agent_generated_files];
419
- }
420
- return rawGroups[groupId] ?? [];
557
+ function normalizeMentionScope(scope) {
558
+ return Object.fromEntries(
559
+ Object.entries(scope ?? {}).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0)
560
+ );
421
561
  }
422
- function resolveMentionGroupTotalCount(groupId, totalCounts, itemCount) {
423
- if (groupId === "files") {
424
- return (totalCounts.opened_files ?? 0) + (totalCounts.agent_generated_files ?? 0);
562
+ function mentionSessionScope(input) {
563
+ const rawScope = input.rawScope?.trim() ?? "";
564
+ if (rawScope === "my_sessions" || rawScope === "collab_sessions") {
565
+ return rawScope;
425
566
  }
426
- if (groupId === "agent_generated_files") {
427
- return itemCount;
567
+ const userId = input.userId?.trim() ?? "";
568
+ const currentUserId = input.currentUserId.trim();
569
+ if (!userId || !currentUserId || userId === "local" || currentUserId === "local") {
570
+ return "my_sessions";
428
571
  }
429
- return totalCounts[groupId] ?? itemCount;
430
- }
431
- function normalizeQuery(value) {
432
- return value.replace(/\s+/g, " ").trim();
572
+ return userId === currentUserId ? "my_sessions" : "collab_sessions";
433
573
  }
434
- function compactText(value) {
435
- return value?.replace(/\s+/g, " ").trim() ?? "";
574
+ function dirnameFromProviderWorkspaceFileHref(href) {
575
+ const normalized = href.replace(/\/+$/, "");
576
+ const index = normalized.lastIndexOf("/");
577
+ if (index <= 0) {
578
+ return "/";
579
+ }
580
+ return normalized.slice(0, index);
436
581
  }
437
582
 
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";
583
+ // agent-gui/agentGuiNode/AgentMentionSearchCache.ts
448
584
  var sharedAgentMentionBrowseCache = /* @__PURE__ */ new Map();
449
585
  var sharedAgentMentionBrowseFetches = /* @__PURE__ */ new Map();
450
586
  var MAX_BROWSE_CACHE_ENTRIES = 64;
@@ -459,7 +595,7 @@ function writeBrowseCacheEntry(cacheKey, entry) {
459
595
  sharedAgentMentionBrowseCache.delete(oldestKey);
460
596
  }
461
597
  }
462
- function scheduleIdleTask(task) {
598
+ function scheduleAgentMentionIdleTask(task) {
463
599
  const scope = globalThis;
464
600
  if (typeof scope.requestIdleCallback === "function") {
465
601
  const handle2 = scope.requestIdleCallback(() => task(), { timeout: 500 });
@@ -473,486 +609,539 @@ function resetAgentMentionSearchBrowseCacheForTests() {
473
609
  sharedAgentMentionBrowseFetches.clear();
474
610
  }
475
611
  globalThis.__tuttiResetAgentMentionSearchBrowseCacheForTests = resetAgentMentionSearchBrowseCacheForTests;
476
- function buildBrowseCategories() {
477
- return AGENT_MENTION_FILTER_TAB_ORDER.map((id) => ({
478
- id,
479
- label: agentMentionFilterLabel(id)
480
- }));
612
+ async function loadAgentMentionBrowseFetchResult(input) {
613
+ const { cacheKey, reason } = input;
614
+ const browseInput = input.input;
615
+ const existingFetch = sharedAgentMentionBrowseFetches.get(cacheKey);
616
+ if (existingFetch) {
617
+ input.logLifecycle("browse.fetch.dedupe", {
618
+ filter: browseInput.filter,
619
+ reason,
620
+ workspaceId: browseInput.workspaceId
621
+ });
622
+ return existingFetch;
623
+ }
624
+ const startedAt = input.diagnosticNow();
625
+ input.logLifecycle("browse.fetch.start", {
626
+ filter: browseInput.filter,
627
+ providerIds: input.providerIds,
628
+ reason,
629
+ workspaceId: browseInput.workspaceId
630
+ });
631
+ const fetchPromise = input.fetchBrowseResult().then((result) => {
632
+ writeBrowseCacheEntry(cacheKey, {
633
+ ...result,
634
+ cachedAt: input.diagnosticNow()
635
+ });
636
+ input.logLifecycle("browse.fetch.success", {
637
+ durationMs: elapsedDiagnosticMs(input.diagnosticNow(), startedAt),
638
+ filter: browseInput.filter,
639
+ itemCount: rawGroupItemCount(result.rawGroups),
640
+ providerResults: providerDiagnosticsSummary(result.providerDiagnostics),
641
+ reason,
642
+ workspaceId: browseInput.workspaceId
643
+ });
644
+ return result;
645
+ }).finally(() => {
646
+ if (sharedAgentMentionBrowseFetches.get(cacheKey) === fetchPromise) {
647
+ sharedAgentMentionBrowseFetches.delete(cacheKey);
648
+ }
649
+ });
650
+ sharedAgentMentionBrowseFetches.set(cacheKey, fetchPromise);
651
+ return fetchPromise;
652
+ }
653
+ function readAgentMentionBrowseCache(input) {
654
+ const entry = sharedAgentMentionBrowseCache.get(input.cacheKey);
655
+ if (!entry) {
656
+ return { entry: null, isFresh: false };
657
+ }
658
+ sharedAgentMentionBrowseCache.delete(input.cacheKey);
659
+ sharedAgentMentionBrowseCache.set(input.cacheKey, entry);
660
+ const ageMs = input.diagnosticNow() - entry.cachedAt;
661
+ const isFresh = input.browseCacheTtlMs >= 0 && Number.isFinite(input.browseCacheTtlMs) && ageMs <= input.browseCacheTtlMs;
662
+ return { entry, isFresh };
663
+ }
664
+ function buildAgentMentionBrowseCacheKey(input) {
665
+ return JSON.stringify({
666
+ workspaceId: input.workspaceId,
667
+ currentUserId: input.currentUserId,
668
+ sessionCwd: input.sessionCwd,
669
+ filter: input.filter,
670
+ fileLimit: input.fileLimit,
671
+ issueLimit: input.issueLimit,
672
+ providerIds: input.providerIds
673
+ });
481
674
  }
675
+
676
+ // agent-gui/agentGuiNode/agentMentionSearchDiagnostics.ts
677
+ var AGENT_MENTION_SEARCH_LOG_PREFIX = "[agent-gui] mention-search";
482
678
  var {
483
679
  agentGeneratedFile: AGENT_GENERATED_FILE_PROVIDER_ID2,
484
680
  agentSession: AGENT_SESSION_PROVIDER_ID2,
485
- agentTarget: AGENT_TARGET_PROVIDER_ID,
486
681
  file: FILE_PROVIDER_ID2,
487
682
  workspaceApp: WORKSPACE_APP_PROVIDER_ID2,
488
683
  workspaceIssue: WORKSPACE_ISSUE_PROVIDER_ID2
489
684
  } = 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
525
- };
526
- constructor(options) {
527
- this.contextMentionProviders = new Map(
528
- (options.contextMentionProviders ?? []).map((provider) => [
529
- provider.id,
530
- provider
531
- ])
532
- );
533
- this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
534
- this.fileLimit = options.fileLimit ?? DEFAULT_FILE_LIMIT;
535
- this.issueLimit = options.issueLimit ?? DEFAULT_ISSUE_LIMIT;
536
- this.browseCacheTtlMs = options.browseCacheTtlMs ?? DEFAULT_BROWSE_CACHE_TTL_MS;
537
- this.providerTimeoutMs = options.providerTimeoutMs ?? DEFAULT_PROVIDER_TIMEOUT_MS;
538
- this.diagnosticInfoLogger = options.diagnosticInfoLogger ?? logAgentMentionSearchInfo;
539
- this.diagnosticNow = options.diagnosticNow ?? Date.now;
540
- this.diagnosticSlowThresholdMs = options.diagnosticSlowThresholdMs ?? DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS;
541
- this.currentFileSearchLimit = this.fileLimit;
542
- this.currentIssueSearchLimit = this.issueLimit;
685
+ var AGENT_MENTION_PROVIDER_LOG_ORDER = [
686
+ FILE_PROVIDER_ID2,
687
+ AGENT_GENERATED_FILE_PROVIDER_ID2,
688
+ WORKSPACE_APP_PROVIDER_ID2,
689
+ WORKSPACE_ISSUE_PROVIDER_ID2,
690
+ AGENT_SESSION_PROVIDER_ID2
691
+ ];
692
+ function emitAgentMentionSearchDiagnostic(input) {
693
+ const durationMs = elapsedAgentMentionSearchDiagnosticMs(
694
+ input.diagnosticNow(),
695
+ input.startedAt
696
+ );
697
+ const providerResults = orderAgentMentionProviderDiagnostics(
698
+ input.providerDiagnostics
699
+ );
700
+ const hasProviderIssue = providerResults.some(
701
+ (result) => result.status === "timeout" || result.status === "error"
702
+ );
703
+ if (input.status === "ready" && !hasProviderIssue && durationMs < input.diagnosticSlowThresholdMs) {
704
+ return;
543
705
  }
544
- subscribe(listener) {
545
- this.listeners.add(listener);
546
- listener(this.state);
547
- return () => {
548
- this.listeners.delete(listener);
549
- };
706
+ const payload = {
707
+ debounceMs: input.debounceMs,
708
+ durationMs,
709
+ ...input.status === "error" ? { errorKind: agentMentionSearchErrorKind(input.error) } : {},
710
+ event: "agent_gui.mention_search",
711
+ filter: input.filter,
712
+ groupCount: input.groups.length,
713
+ itemCount: input.groups.reduce((sum, group) => sum + group.items.length, 0),
714
+ mode: input.mode,
715
+ providerResults,
716
+ providerTimeoutMs: input.providerTimeoutMs,
717
+ queryLength: [...input.query].length,
718
+ requestId: input.requestId,
719
+ status: input.status,
720
+ workspaceId: input.workspaceId
721
+ };
722
+ try {
723
+ input.diagnosticInfoLogger(payload);
724
+ } catch {
550
725
  }
551
- updateQuery(input) {
552
- if (this.disposed) {
553
- return;
726
+ }
727
+ async function queryAgentMentionProviderWithDiagnostics(input) {
728
+ if (!input.query) {
729
+ input.diagnostics.push({
730
+ durationMs: 0,
731
+ providerId: input.providerId,
732
+ resultCount: 0,
733
+ status: "missing"
734
+ });
735
+ return input.fallback;
736
+ }
737
+ const startedAt = input.diagnosticNow();
738
+ try {
739
+ const { result, timedOut } = await runAgentMentionProviderQuery({
740
+ fallback: input.fallback,
741
+ providerTimeoutMs: input.providerTimeoutMs,
742
+ query: input.query
743
+ });
744
+ input.diagnostics.push({
745
+ durationMs: elapsedAgentMentionSearchDiagnosticMs(
746
+ input.diagnosticNow(),
747
+ startedAt
748
+ ),
749
+ providerId: input.providerId,
750
+ resultCount: input.resultCount(result),
751
+ status: timedOut ? "timeout" : "success"
752
+ });
753
+ return result;
754
+ } catch (error) {
755
+ input.diagnostics.push({
756
+ durationMs: elapsedAgentMentionSearchDiagnosticMs(
757
+ input.diagnosticNow(),
758
+ startedAt
759
+ ),
760
+ errorKind: agentMentionSearchErrorKind(error),
761
+ providerId: input.providerId,
762
+ resultCount: 0,
763
+ status: "error"
764
+ });
765
+ throw error;
766
+ }
767
+ }
768
+ function elapsedAgentMentionSearchDiagnosticMs(now, startedAt) {
769
+ const durationMs = now - startedAt;
770
+ if (!Number.isFinite(durationMs)) {
771
+ return 0;
772
+ }
773
+ return Math.max(0, Math.round(durationMs));
774
+ }
775
+ function agentMentionSearchErrorKind(error) {
776
+ if (error instanceof Error && error.name.trim()) {
777
+ return error.name.trim();
778
+ }
779
+ if (error === null) {
780
+ return "null";
781
+ }
782
+ return typeof error;
783
+ }
784
+ function logAgentMentionSearchInfo(payload) {
785
+ console.info(AGENT_MENTION_SEARCH_LOG_PREFIX, JSON.stringify(payload));
786
+ }
787
+ function orderAgentMentionProviderDiagnostics(diagnostics) {
788
+ return [...diagnostics].sort((left, right) => {
789
+ const leftIndex = providerDiagnosticOrder(left.providerId);
790
+ const rightIndex = providerDiagnosticOrder(right.providerId);
791
+ return leftIndex - rightIndex || left.providerId.localeCompare(right.providerId);
792
+ });
793
+ }
794
+ function providerDiagnosticOrder(providerId) {
795
+ const index = AGENT_MENTION_PROVIDER_LOG_ORDER.indexOf(providerId);
796
+ return index === -1 ? AGENT_MENTION_PROVIDER_LOG_ORDER.length : index;
797
+ }
798
+ async function runAgentMentionProviderQuery(input) {
799
+ const abortController = new AbortController();
800
+ let timedOut = false;
801
+ const queryPromise = Promise.resolve().then(
802
+ () => input.query(abortController.signal)
803
+ );
804
+ const queryResultPromise = queryPromise.then(
805
+ (result) => ({ result, timedOut: false }),
806
+ (error) => {
807
+ if (timedOut && abortController.signal.aborted) {
808
+ return { result: input.fallback, timedOut: true };
809
+ }
810
+ throw error;
554
811
  }
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
- this.clearTimer();
560
- 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
812
+ );
813
+ if (input.providerTimeoutMs <= 0 || !Number.isFinite(input.providerTimeoutMs)) {
814
+ return queryResultPromise;
815
+ }
816
+ let timeout = null;
817
+ const timeoutPromise = new Promise(
818
+ (resolve) => {
819
+ timeout = setTimeout(() => {
820
+ timedOut = true;
821
+ abortController.abort();
822
+ resolve({ result: input.fallback, timedOut: true });
823
+ }, input.providerTimeoutMs);
824
+ }
825
+ );
826
+ try {
827
+ return await Promise.race([queryResultPromise, timeoutPromise]);
828
+ } finally {
829
+ if (timeout !== null) {
830
+ clearTimeout(timeout);
831
+ }
832
+ }
833
+ }
834
+
835
+ // agent-gui/agentGuiNode/AgentMentionSearchIndex.ts
836
+ async function fetchAgentMentionFilterResult(input) {
837
+ const providerDiagnostics = [];
838
+ switch (input.filter) {
839
+ case "file": {
840
+ const fileQuery = input.queryProviderMentionItemsById({
841
+ providerId: FILE_PROVIDER_ID,
842
+ workspaceId: input.workspaceId,
843
+ currentUserId: input.currentUserId,
844
+ query: input.query,
845
+ limit: input.query ? input.currentFileSearchLimit : input.fileLimit,
846
+ sessionCwd: input.sessionCwd,
847
+ diagnostics: providerDiagnostics
574
848
  });
575
- return;
849
+ const agentGeneratedFileQuery = input.includeAgentGeneratedFiles ? input.queryProviderMentionItemsById({
850
+ providerId: AGENT_GENERATED_FILE_PROVIDER_ID,
851
+ workspaceId: input.workspaceId,
852
+ currentUserId: input.currentUserId,
853
+ query: input.query,
854
+ limit: input.fileLimit,
855
+ sessionCwd: input.sessionCwd,
856
+ diagnostics: providerDiagnostics
857
+ }) : Promise.resolve([]);
858
+ const [fileItems, agentGeneratedFileItems] = await Promise.all([
859
+ fileQuery,
860
+ agentGeneratedFileQuery
861
+ ]);
862
+ const rawGroups = emptyAgentMentionRawGroups();
863
+ rawGroups.opened_files = fileItems.filter((item) => item.kind === "file");
864
+ rawGroups.agent_generated_files = agentGeneratedFileItems.filter(
865
+ (item) => item.kind === "file"
866
+ );
867
+ return {
868
+ providerDiagnostics,
869
+ rawGroups,
870
+ totalCounts: totalCountsFromRawGroups(rawGroups)
871
+ };
576
872
  }
577
- if (!this.currentQuery) {
578
- this.startBrowseModeFetch(this.currentFilter);
579
- return;
873
+ case "session": {
874
+ const sessionItems = await input.queryProviderMentionItemsById({
875
+ providerId: AGENT_SESSION_PROVIDER_ID,
876
+ workspaceId: input.workspaceId,
877
+ currentUserId: input.currentUserId,
878
+ query: input.query,
879
+ limit: DEFAULT_SESSION_LIMIT,
880
+ sessionCwd: input.sessionCwd,
881
+ diagnostics: providerDiagnostics
882
+ });
883
+ const rawGroups = emptyAgentMentionRawGroups();
884
+ rawGroups.my_sessions = normalizeSessionMentionItemsForMySessions({
885
+ currentUserId: input.currentUserId,
886
+ items: sessionItems
887
+ });
888
+ return {
889
+ providerDiagnostics,
890
+ rawGroups,
891
+ totalCounts: totalCountsFromRawGroups(rawGroups)
892
+ };
580
893
  }
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
894
+ case "issue": {
895
+ const issueItems = await input.queryProviderMentionItemsById({
896
+ providerId: WORKSPACE_ISSUE_PROVIDER_ID,
897
+ workspaceId: input.workspaceId,
898
+ currentUserId: input.currentUserId,
899
+ query: input.query,
900
+ limit: input.currentIssueSearchLimit,
901
+ sessionCwd: input.sessionCwd,
902
+ diagnostics: providerDiagnostics
597
903
  });
598
- }, this.debounceMs);
599
- }
600
- setFilter(filter) {
601
- if (this.disposed) {
602
- return;
904
+ const rawGroups = emptyAgentMentionRawGroups();
905
+ rawGroups.issues = issueItems.filter(
906
+ (item) => item.kind === "workspace-issue"
907
+ );
908
+ return {
909
+ providerDiagnostics,
910
+ rawGroups,
911
+ totalCounts: totalCountsFromRawGroups(rawGroups)
912
+ };
603
913
  }
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;
914
+ case "agent": {
915
+ const agentItems = await input.queryProviderMentionItemsById({
916
+ providerId: AGENT_TARGET_PROVIDER_ID,
917
+ workspaceId: input.workspaceId,
918
+ currentUserId: input.currentUserId,
919
+ query: input.query,
920
+ sessionCwd: input.sessionCwd,
921
+ diagnostics: providerDiagnostics
922
+ });
923
+ const rawGroups = emptyAgentMentionRawGroups();
924
+ rawGroups.agents = agentItems.filter(
925
+ (item) => item.kind === "agent-target"
926
+ );
927
+ return {
928
+ providerDiagnostics,
929
+ rawGroups,
930
+ totalCounts: totalCountsFromRawGroups(rawGroups)
931
+ };
614
932
  }
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
933
+ case "app": {
934
+ const appItems = await input.queryProviderMentionItemsById({
935
+ providerId: WORKSPACE_APP_PROVIDER_ID,
936
+ workspaceId: input.workspaceId,
937
+ currentUserId: input.currentUserId,
938
+ query: input.query,
939
+ sessionCwd: input.sessionCwd,
940
+ diagnostics: providerDiagnostics
624
941
  });
625
- return;
942
+ const rawGroups = emptyAgentMentionRawGroups();
943
+ rawGroups.apps = appItems.filter((item) => item.kind === "workspace-app");
944
+ return {
945
+ providerDiagnostics,
946
+ rawGroups,
947
+ totalCounts: totalCountsFromRawGroups(rawGroups)
948
+ };
626
949
  }
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
950
  }
644
- preloadBrowse(input) {
645
- if (this.disposed) {
646
- return;
951
+ }
952
+ async function queryAgentMentionProviderItems(input) {
953
+ const items = await input.provider.query({
954
+ keyword: input.query,
955
+ maxResults: input.limit,
956
+ abortSignal: input.abortSignal,
957
+ trigger: "@",
958
+ context: {
959
+ metadata: {
960
+ currentUserId: input.currentUserId,
961
+ sessionCwd: input.sessionCwd || void 0,
962
+ target: "agent-gui",
963
+ workspaceId: input.workspaceId
964
+ }
647
965
  }
648
- const workspaceId = input.workspaceId.trim();
649
- if (!workspaceId) {
966
+ });
967
+ if (input.abortSignal.aborted) {
968
+ return [];
969
+ }
970
+ const mentionItems = await Promise.all(
971
+ items.map(async (item) => {
972
+ const mentionItem = providerItemToAgentMentionItem({
973
+ currentUserId: input.currentUserId,
974
+ insertResult: input.provider.toInsertResult(item),
975
+ label: input.provider.getItemLabel(item),
976
+ providerId: input.provider.id,
977
+ subtitle: input.provider.getItemSubtitle?.(item) ?? "",
978
+ workspaceId: input.workspaceId
979
+ });
980
+ if (!mentionItem || mentionItem.kind !== "file") {
981
+ return mentionItem;
982
+ }
983
+ const iconUrl = await Promise.resolve(
984
+ input.provider.getItemIconUrl?.(item) ?? null
985
+ ).catch(() => null);
986
+ const resolvedThumbnailUrl = resolveAgentMentionFileThumbnailUrl({
987
+ ...mentionItem,
988
+ thumbnailUrl: iconUrl
989
+ });
990
+ if (!resolvedThumbnailUrl) {
991
+ return mentionItem;
992
+ }
993
+ return {
994
+ ...mentionItem,
995
+ thumbnailUrl: resolvedThumbnailUrl
996
+ };
997
+ })
998
+ );
999
+ return mentionItems.filter(
1000
+ (item) => item !== null
1001
+ );
1002
+ }
1003
+
1004
+ // agent-gui/agentGuiNode/AgentMentionSearchControllerBase.ts
1005
+ var AgentMentionSearchControllerBase = class {
1006
+ contextMentionProviders;
1007
+ debounceMs;
1008
+ fileLimit;
1009
+ issueLimit;
1010
+ browseCacheTtlMs;
1011
+ providerTimeoutMs;
1012
+ diagnosticInfoLogger;
1013
+ diagnosticNow;
1014
+ diagnosticSlowThresholdMs;
1015
+ listeners = /* @__PURE__ */ new Set();
1016
+ expandedCounts = {};
1017
+ totalCounts = {};
1018
+ timer = null;
1019
+ preloadCancel = null;
1020
+ pendingPreloadKey = null;
1021
+ requestId = 0;
1022
+ disposed = false;
1023
+ activeWorkspaceId = "";
1024
+ currentUserId = "";
1025
+ currentFilter = DEFAULT_AGENT_MENTION_FILTER;
1026
+ currentQuery = "";
1027
+ currentSessionCwd = "";
1028
+ currentFileSearchLimit;
1029
+ currentIssueSearchLimit;
1030
+ agentGeneratedBrowsePath = null;
1031
+ rawGroups = emptyAgentMentionRawGroups();
1032
+ state = {
1033
+ status: "idle",
1034
+ query: "",
1035
+ mode: "browse",
1036
+ filter: DEFAULT_AGENT_MENTION_FILTER,
1037
+ categories: buildBrowseCategories(),
1038
+ groups: [],
1039
+ error: null
1040
+ };
1041
+ constructor(options) {
1042
+ this.contextMentionProviders = new Map(
1043
+ (options.contextMentionProviders ?? []).map((provider) => [
1044
+ provider.id,
1045
+ provider
1046
+ ])
1047
+ );
1048
+ this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
1049
+ this.fileLimit = options.fileLimit ?? DEFAULT_FILE_LIMIT;
1050
+ this.issueLimit = options.issueLimit ?? DEFAULT_ISSUE_LIMIT;
1051
+ this.browseCacheTtlMs = options.browseCacheTtlMs ?? DEFAULT_BROWSE_CACHE_TTL_MS;
1052
+ this.providerTimeoutMs = options.providerTimeoutMs ?? DEFAULT_PROVIDER_TIMEOUT_MS;
1053
+ this.diagnosticInfoLogger = options.diagnosticInfoLogger ?? logAgentMentionSearchInfo;
1054
+ this.diagnosticNow = options.diagnosticNow ?? Date.now;
1055
+ this.diagnosticSlowThresholdMs = options.diagnosticSlowThresholdMs ?? DEFAULT_DIAGNOSTIC_SLOW_THRESHOLD_MS;
1056
+ this.currentFileSearchLimit = this.fileLimit;
1057
+ this.currentIssueSearchLimit = this.issueLimit;
1058
+ }
1059
+ startBrowseModeFetch(filter) {
1060
+ if (!this.activeWorkspaceId) {
1061
+ this.resetRawGroups();
1062
+ this.emitBrowseState("ready");
650
1063
  return;
651
1064
  }
652
- const filter = input.filter ?? DEFAULT_AGENT_MENTION_FILTER;
653
- const currentUserId = input.currentUserId?.trim() ?? "";
654
- const sessionCwd = input.sessionCwd?.trim() ?? "";
1065
+ this.clearTimer();
1066
+ const requestId = ++this.requestId;
655
1067
  const cacheKey = this.browseCacheKey({
656
- currentUserId,
1068
+ currentUserId: this.currentUserId,
657
1069
  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
- });
1070
+ sessionCwd: this.currentSessionCwd,
1071
+ workspaceId: this.activeWorkspaceId
682
1072
  });
683
- }
684
- runBrowsePreload(input) {
685
- const { cacheKey, currentUserId, filter, sessionCwd, workspaceId } = input;
686
- this.logLifecycle("browse.preload", {
1073
+ this.logLifecycle("browse.open", {
687
1074
  filter,
688
1075
  providerIds: this.providerIdsForDiagnostics(),
689
- sessionCwdPresent: Boolean(sessionCwd),
690
- workspaceId
1076
+ requestId,
1077
+ sessionCwdPresent: Boolean(this.currentSessionCwd),
1078
+ workspaceId: this.activeWorkspaceId
691
1079
  });
692
1080
  const cached = this.readBrowseCache(cacheKey);
693
1081
  this.logBrowseCacheState({
694
1082
  cacheKey,
695
1083
  cached,
696
1084
  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
- });
1085
+ reason: "open",
1086
+ workspaceId: this.activeWorkspaceId
719
1087
  });
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();
1088
+ if (cached.entry) {
1089
+ this.applyBrowseFetchResult(cached.entry);
754
1090
  this.setState({
755
- status: this.state.status === "loading" ? "loading" : "ready",
756
- query: this.currentQuery,
757
- mode: this.currentQuery ? "results" : "browse",
1091
+ status: "ready",
1092
+ query: "",
1093
+ mode: "browse",
758
1094
  filter: this.currentFilter,
759
1095
  categories: buildBrowseCategories(),
760
1096
  groups: this.groupsFromRawGroups(),
761
1097
  error: null
762
1098
  });
763
- return true;
764
- }
765
- return false;
766
- }
767
- exitAgentGeneratedBrowse() {
768
- if (!this.agentGeneratedBrowsePath) {
769
- return false;
1099
+ if (cached.isFresh) {
1100
+ return;
1101
+ }
1102
+ } else {
1103
+ this.rawGroups = emptyAgentMentionRawGroups();
1104
+ this.resetTotalCounts();
1105
+ this.emitBrowseState("loading");
770
1106
  }
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
1107
+ void this.runBrowseSearch({
1108
+ workspaceId: this.activeWorkspaceId,
1109
+ currentUserId: this.currentUserId,
1110
+ requestId,
1111
+ filter,
1112
+ sessionCwd: this.currentSessionCwd
780
1113
  });
781
- return true;
782
1114
  }
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) {
1115
+ async runSearch(input) {
1116
+ const startedAt = this.diagnosticNow();
1117
+ let providerDiagnostics = [];
1118
+ try {
1119
+ const result = await this.fetchFilterResult({
1120
+ workspaceId: input.workspaceId,
1121
+ currentUserId: input.currentUserId,
1122
+ query: input.query,
1123
+ filter: input.filter,
1124
+ sessionCwd: this.currentSessionCwd,
1125
+ includeAgentGeneratedFiles: false
1126
+ });
1127
+ providerDiagnostics = result.providerDiagnostics;
1128
+ if (!this.canApply(
1129
+ input.requestId,
1130
+ input.workspaceId,
1131
+ input.query,
1132
+ input.filter
1133
+ )) {
1134
+ return;
1135
+ }
1136
+ this.applyBrowseFetchResult(result);
1137
+ const groups = this.groupsFromRawGroups();
788
1138
  this.setState({
789
1139
  status: "ready",
790
- query: "",
791
- mode: "browse",
1140
+ query: input.query,
1141
+ mode: "results",
792
1142
  filter: this.currentFilter,
793
1143
  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,
1144
+ groups,
956
1145
  error: null
957
1146
  });
958
1147
  this.logSearchDiagnostic({
@@ -1063,47 +1252,6 @@ var AgentMentionSearchController = class {
1063
1252
  });
1064
1253
  }
1065
1254
  }
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
1255
  async fetchBrowseResult(input) {
1108
1256
  return this.fetchFilterResult({
1109
1257
  ...input,
@@ -1111,177 +1259,6 @@ var AgentMentionSearchController = class {
1111
1259
  includeAgentGeneratedFiles: input.filter === "file"
1112
1260
  });
1113
1261
  }
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
1262
  applyBrowseFetchResult(result) {
1286
1263
  this.rawGroups = cloneAgentMentionRawGroups(result.rawGroups);
1287
1264
  this.resetTotalCounts();
@@ -1289,31 +1266,6 @@ var AgentMentionSearchController = class {
1289
1266
  this.totalCounts[groupId] = count;
1290
1267
  }
1291
1268
  }
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
1269
  logBrowseCacheState(input) {
1318
1270
  this.logLifecycle("browse.cache", {
1319
1271
  ageMs: input.cached.entry ? elapsedDiagnosticMs(this.diagnosticNow(), input.cached.entry.cachedAt) : null,
@@ -1339,7 +1291,7 @@ var AgentMentionSearchController = class {
1339
1291
  fallback: [],
1340
1292
  providerId: input.providerId,
1341
1293
  providerTimeoutMs: this.providerTimeoutMs,
1342
- query: provider ? (abortSignal) => this.queryProviderMentionItems({
1294
+ query: provider ? (abortSignal) => queryAgentMentionProviderItems({
1343
1295
  provider,
1344
1296
  workspaceId: input.workspaceId,
1345
1297
  currentUserId: input.currentUserId,
@@ -1370,41 +1322,6 @@ var AgentMentionSearchController = class {
1370
1322
  workspaceId: input.workspaceId
1371
1323
  });
1372
1324
  }
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
1325
  emitBrowseState(status) {
1409
1326
  this.setState({
1410
1327
  status,
@@ -1473,726 +1390,400 @@ var AgentMentionSearchController = class {
1473
1390
  listener(state);
1474
1391
  }
1475
1392
  }
1393
+ groupsFromRawGroups() {
1394
+ return buildAgentMentionGroups({
1395
+ agentGeneratedBrowsePath: this.agentGeneratedBrowsePath,
1396
+ currentFileSearchLimit: this.currentFileSearchLimit,
1397
+ currentFilter: this.currentFilter,
1398
+ currentQuery: this.currentQuery,
1399
+ expandedCounts: this.expandedCounts,
1400
+ rawGroups: this.rawGroups,
1401
+ totalCounts: this.totalCounts
1402
+ });
1403
+ }
1404
+ browseCacheKey(input) {
1405
+ return buildAgentMentionBrowseCacheKey({
1406
+ ...input,
1407
+ fileLimit: this.fileLimit,
1408
+ issueLimit: this.currentIssueSearchLimit,
1409
+ providerIds: [...this.contextMentionProviders.keys()].sort()
1410
+ });
1411
+ }
1412
+ readBrowseCache(cacheKey) {
1413
+ return readAgentMentionBrowseCache({
1414
+ cacheKey,
1415
+ browseCacheTtlMs: this.browseCacheTtlMs,
1416
+ diagnosticNow: this.diagnosticNow
1417
+ });
1418
+ }
1419
+ loadBrowseFetchResult(input, cacheKey, reason) {
1420
+ return loadAgentMentionBrowseFetchResult({
1421
+ input,
1422
+ cacheKey,
1423
+ reason,
1424
+ diagnosticNow: this.diagnosticNow,
1425
+ providerIds: this.providerIdsForDiagnostics(),
1426
+ fetchBrowseResult: () => this.fetchBrowseResult(input),
1427
+ logLifecycle: (event, details) => this.logLifecycle(event, details)
1428
+ });
1429
+ }
1430
+ fetchFilterResult(input) {
1431
+ return fetchAgentMentionFilterResult({
1432
+ ...input,
1433
+ fileLimit: this.fileLimit,
1434
+ currentFileSearchLimit: this.currentFileSearchLimit,
1435
+ currentIssueSearchLimit: this.currentIssueSearchLimit,
1436
+ queryProviderMentionItemsById: (queryInput) => this.queryProviderMentionItemsById(queryInput)
1437
+ });
1438
+ }
1476
1439
  };
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
1440
+
1441
+ // agent-gui/agentGuiNode/AgentMentionSearchController.ts
1442
+ var AgentMentionSearchController = class extends AgentMentionSearchControllerBase {
1443
+ subscribe(listener) {
1444
+ this.listeners.add(listener);
1445
+ listener(this.state);
1446
+ return () => {
1447
+ this.listeners.delete(listener);
1697
1448
  };
1698
1449
  }
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 "/";
1450
+ updateQuery(input) {
1451
+ if (this.disposed) {
1452
+ return;
1453
+ }
1454
+ this.activeWorkspaceId = input.workspaceId.trim();
1455
+ this.currentUserId = input.currentUserId?.trim() ?? "";
1456
+ this.currentSessionCwd = input.sessionCwd?.trim() ?? "";
1457
+ this.currentQuery = normalizeQuery(input.query);
1458
+ this.clearTimer();
1459
+ const requestId = ++this.requestId;
1460
+ this.resetAgentGeneratedBrowsePath();
1461
+ this.resetExpandedCounts();
1462
+ this.resetSearchLimits();
1463
+ this.resetRawGroups();
1464
+ if (!this.activeWorkspaceId) {
1465
+ this.setState({
1466
+ status: "idle",
1467
+ query: this.currentQuery,
1468
+ mode: "browse",
1469
+ filter: this.currentFilter,
1470
+ categories: buildBrowseCategories(),
1471
+ groups: [],
1472
+ error: null
1473
+ });
1474
+ return;
1475
+ }
1476
+ if (!this.currentQuery) {
1477
+ this.startBrowseModeFetch(this.currentFilter);
1478
+ return;
1479
+ }
1480
+ this.setState({
1481
+ status: "loading",
1482
+ query: this.currentQuery,
1483
+ mode: "results",
1484
+ filter: this.currentFilter,
1485
+ categories: buildBrowseCategories(),
1486
+ groups: this.groupsFromRawGroups(),
1487
+ error: null
1488
+ });
1489
+ this.timer = setTimeout(() => {
1490
+ void this.runSearch({
1491
+ workspaceId: this.activeWorkspaceId,
1492
+ currentUserId: this.currentUserId,
1493
+ query: this.currentQuery,
1494
+ requestId,
1495
+ filter: this.currentFilter
1496
+ });
1497
+ }, this.debounceMs);
1723
1498
  }
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");
1499
+ setFilter(filter) {
1500
+ if (this.disposed) {
1501
+ return;
1502
+ }
1503
+ this.currentFilter = filter;
1504
+ this.clearTimer();
1505
+ const requestId = ++this.requestId;
1506
+ this.resetAgentGeneratedBrowsePath();
1507
+ this.resetExpandedCounts();
1508
+ this.resetSearchLimits();
1509
+ this.resetRawGroups();
1510
+ if (!this.currentQuery) {
1511
+ this.startBrowseModeFetch(filter);
1512
+ return;
1513
+ }
1514
+ if (!this.activeWorkspaceId) {
1515
+ this.setState({
1516
+ status: "ready",
1517
+ query: this.currentQuery,
1518
+ mode: "results",
1519
+ filter: this.currentFilter,
1520
+ categories: buildBrowseCategories(),
1521
+ groups: [],
1522
+ error: null
1523
+ });
1524
+ return;
1525
+ }
1526
+ this.setState({
1527
+ status: "loading",
1528
+ query: this.currentQuery,
1529
+ mode: "results",
1530
+ filter: this.currentFilter,
1531
+ categories: buildBrowseCategories(),
1532
+ groups: this.groupsFromRawGroups(),
1533
+ error: null
1534
+ });
1535
+ void this.runSearch({
1536
+ workspaceId: this.activeWorkspaceId,
1537
+ currentUserId: this.currentUserId,
1538
+ query: this.currentQuery,
1539
+ requestId,
1540
+ filter
1541
+ });
1760
1542
  }
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
- };
1543
+ preloadBrowse(input) {
1544
+ if (this.disposed) {
1545
+ return;
1813
1546
  }
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)}`;
1547
+ const workspaceId = input.workspaceId.trim();
1548
+ if (!workspaceId) {
1549
+ return;
1830
1550
  }
1831
- if (group.hasMore) {
1832
- return `expand:${group.id}`;
1551
+ const filter = input.filter ?? DEFAULT_AGENT_MENTION_FILTER;
1552
+ const currentUserId = input.currentUserId?.trim() ?? "";
1553
+ const sessionCwd = input.sessionCwd?.trim() ?? "";
1554
+ const cacheKey = this.browseCacheKey({
1555
+ currentUserId,
1556
+ filter,
1557
+ sessionCwd,
1558
+ workspaceId
1559
+ });
1560
+ if (this.readBrowseCache(cacheKey).isFresh) {
1561
+ return;
1562
+ }
1563
+ if (this.pendingPreloadKey === cacheKey) {
1564
+ return;
1565
+ }
1566
+ this.cancelPendingPreload();
1567
+ this.pendingPreloadKey = cacheKey;
1568
+ this.preloadCancel = scheduleAgentMentionIdleTask(() => {
1569
+ this.preloadCancel = null;
1570
+ this.pendingPreloadKey = null;
1571
+ if (this.disposed) {
1572
+ return;
1573
+ }
1574
+ this.runBrowsePreload({
1575
+ cacheKey,
1576
+ currentUserId,
1577
+ filter,
1578
+ sessionCwd,
1579
+ workspaceId
1580
+ });
1581
+ });
1582
+ }
1583
+ runBrowsePreload(input) {
1584
+ const { cacheKey, currentUserId, filter, sessionCwd, workspaceId } = input;
1585
+ this.logLifecycle("browse.preload", {
1586
+ filter,
1587
+ providerIds: this.providerIdsForDiagnostics(),
1588
+ sessionCwdPresent: Boolean(sessionCwd),
1589
+ workspaceId
1590
+ });
1591
+ const cached = this.readBrowseCache(cacheKey);
1592
+ this.logBrowseCacheState({
1593
+ cacheKey,
1594
+ cached,
1595
+ filter,
1596
+ reason: "preload",
1597
+ workspaceId
1598
+ });
1599
+ if (cached.isFresh) {
1600
+ return;
1833
1601
  }
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,
1602
+ void this.loadBrowseFetchResult(
1603
+ {
1604
+ workspaceId,
1605
+ currentUserId,
1883
1606
  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
1607
+ sessionCwd
1939
1608
  },
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);
1609
+ cacheKey,
1610
+ "preload"
1611
+ ).catch((error) => {
1612
+ this.logLifecycle("browse.fetch.error", {
1613
+ errorKind: diagnosticErrorKind(error),
1614
+ filter,
1615
+ reason: "preload",
1616
+ workspaceId
1617
+ });
1618
+ });
1978
1619
  }
1979
- if (input.filter === "agent") {
1980
- return agentMentionEmptyGroupLabel("agents", input.query);
1620
+ cancelPendingPreload() {
1621
+ if (this.preloadCancel) {
1622
+ this.preloadCancel();
1623
+ this.preloadCancel = null;
1624
+ }
1625
+ this.pendingPreloadKey = null;
1981
1626
  }
1982
- if (input.filter === "issue") {
1983
- return agentMentionEmptyGroupLabel("issues", input.query);
1627
+ enterCategory(category) {
1628
+ this.setFilter(category);
1984
1629
  }
1985
- return input.emptyLabel;
1986
- }
1987
- function shouldRenderMentionGroupLabel(input) {
1988
- if (shouldSuppressFileSearchGroupChrome(input.filter, input.query)) {
1630
+ selectAgentGeneratedMentionItem(item) {
1631
+ if (item.kind !== "file" || !item.mentionNavigation) {
1632
+ return false;
1633
+ }
1634
+ if (item.mentionNavigation === "agent-generated-folder") {
1635
+ this.agentGeneratedBrowsePath = item.path;
1636
+ this.expandedCounts.agent_generated_files = mentionGroupPageSize(
1637
+ this.currentFilter,
1638
+ "agent_generated_files"
1639
+ );
1640
+ this.setState({
1641
+ status: this.state.status === "loading" ? "loading" : "ready",
1642
+ query: this.currentQuery,
1643
+ mode: this.currentQuery ? "results" : "browse",
1644
+ filter: this.currentFilter,
1645
+ categories: buildBrowseCategories(),
1646
+ groups: this.groupsFromRawGroups(),
1647
+ error: null
1648
+ });
1649
+ return true;
1650
+ }
1651
+ if (item.mentionNavigation === "agent-generated-folder-back") {
1652
+ this.resetAgentGeneratedBrowsePath();
1653
+ this.setState({
1654
+ status: this.state.status === "loading" ? "loading" : "ready",
1655
+ query: this.currentQuery,
1656
+ mode: this.currentQuery ? "results" : "browse",
1657
+ filter: this.currentFilter,
1658
+ categories: buildBrowseCategories(),
1659
+ groups: this.groupsFromRawGroups(),
1660
+ error: null
1661
+ });
1662
+ return true;
1663
+ }
1989
1664
  return false;
1990
1665
  }
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
1666
+ exitAgentGeneratedBrowse() {
1667
+ if (!this.agentGeneratedBrowsePath) {
1668
+ return false;
1669
+ }
1670
+ this.resetAgentGeneratedBrowsePath();
1671
+ this.setState({
1672
+ status: this.state.status === "loading" ? "loading" : "ready",
1673
+ query: this.currentQuery,
1674
+ mode: this.currentQuery ? "results" : "browse",
1675
+ filter: this.currentFilter,
1676
+ categories: buildBrowseCategories(),
1677
+ groups: this.groupsFromRawGroups(),
1678
+ error: null
2004
1679
  });
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
1680
  return true;
2082
1681
  }
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;
1682
+ expandGroup(groupId) {
1683
+ const pageSize = mentionGroupPageSize(this.currentFilter, groupId);
1684
+ const current = this.expandedCounts[groupId] ?? pageSize;
1685
+ this.expandedCounts[groupId] = current + pageSize;
1686
+ if (!this.currentQuery) {
1687
+ this.setState({
1688
+ status: "ready",
1689
+ query: "",
1690
+ mode: "browse",
1691
+ filter: this.currentFilter,
1692
+ categories: buildBrowseCategories(),
1693
+ groups: this.groupsFromRawGroups(),
1694
+ error: null
1695
+ });
1696
+ return;
1697
+ }
1698
+ 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);
1699
+ const needsMoreIssues = groupId === "issues" && (this.totalCounts.issues ?? this.rawGroups.issues.length) > this.rawGroups.issues.length;
1700
+ if (needsMoreFiles) {
1701
+ this.currentFileSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
1702
+ }
1703
+ if (needsMoreIssues) {
1704
+ this.currentIssueSearchLimit += DEFAULT_MENTION_GROUP_PAGE_SIZE;
1705
+ }
1706
+ if (needsMoreFiles || needsMoreIssues) {
1707
+ this.clearTimer();
1708
+ const requestId = ++this.requestId;
1709
+ this.setState({
1710
+ status: "loading",
1711
+ query: this.currentQuery,
1712
+ mode: "results",
1713
+ filter: this.currentFilter,
1714
+ categories: buildBrowseCategories(),
1715
+ groups: this.groupsFromRawGroups(),
1716
+ error: null
1717
+ });
1718
+ void this.runSearch({
1719
+ workspaceId: this.activeWorkspaceId,
1720
+ currentUserId: this.currentUserId,
1721
+ query: this.currentQuery,
1722
+ requestId,
1723
+ filter: this.currentFilter
1724
+ });
1725
+ return;
1726
+ }
1727
+ this.setState({
1728
+ status: "ready",
1729
+ query: this.currentQuery,
1730
+ mode: "results",
1731
+ filter: this.currentFilter,
1732
+ categories: buildBrowseCategories(),
1733
+ groups: this.groupsFromRawGroups(),
1734
+ error: null
1735
+ });
2177
1736
  }
2178
- if (input.groups.length === 0) {
2179
- return true;
1737
+ close() {
1738
+ this.clearTimer();
1739
+ this.requestId += 1;
1740
+ this.currentFilter = DEFAULT_AGENT_MENTION_FILTER;
1741
+ this.resetAgentGeneratedBrowsePath();
1742
+ this.resetExpandedCounts();
1743
+ this.resetSearchLimits();
1744
+ this.resetRawGroups();
1745
+ this.currentQuery = "";
1746
+ this.setState({
1747
+ status: "idle",
1748
+ query: "",
1749
+ mode: "browse",
1750
+ filter: DEFAULT_AGENT_MENTION_FILTER,
1751
+ categories: buildBrowseCategories(),
1752
+ groups: [],
1753
+ error: null
1754
+ });
2180
1755
  }
2181
- if (input.highlightedBrowseCategory !== null && input.highlightedBrowseCategory !== input.browseFilter) {
2182
- return true;
1756
+ dispose() {
1757
+ this.disposed = true;
1758
+ this.clearTimer();
1759
+ this.cancelPendingPreload();
1760
+ this.listeners.clear();
1761
+ this.requestId += 1;
2183
1762
  }
2184
- return input.browseFilter === "file" && isFileBrowseGroupsOnlyEmpty(input.groups);
1763
+ };
1764
+ function preloadAgentMentionBrowse(input) {
1765
+ const controller = new AgentMentionSearchController({
1766
+ contextMentionProviders: input.contextMentionProviders
1767
+ });
1768
+ controller.preloadBrowse({
1769
+ workspaceId: input.workspaceId,
1770
+ currentUserId: input.currentUserId,
1771
+ sessionCwd: input.sessionCwd,
1772
+ filter: input.filter
1773
+ });
2185
1774
  }
2186
1775
 
2187
1776
  export {
1777
+ agentMentionGroupLabel,
1778
+ agentMentionFilterLabel,
1779
+ agentMentionEmptyGroupLabel,
2188
1780
  AGENT_MENTION_FILTER_TAB_ORDER,
2189
1781
  DEFAULT_AGENT_MENTION_FILTER,
1782
+ mentionGroupExpandCount,
1783
+ agentGeneratedMentionItemKey,
1784
+ MAX_BROWSE_CACHE_ENTRIES,
1785
+ resetAgentMentionSearchBrowseCacheForTests,
2190
1786
  AgentMentionSearchController,
2191
- preloadAgentMentionBrowse,
2192
- agentMentionItemKey,
2193
- flattenAgentMentionPaletteEntries,
2194
- groupStartKeys,
2195
- AgentFileMentionPalette,
2196
- AgentContextMentionPalette
1787
+ preloadAgentMentionBrowse
2197
1788
  };
2198
- //# sourceMappingURL=chunk-4SQNOOJ3.js.map
1789
+ //# sourceMappingURL=chunk-JX2SIXNL.js.map