@tutti-os/agent-gui 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +56 -0
- package/dist/agent-message-center/index.d.ts +218 -0
- package/dist/agent-message-center/index.js +1962 -0
- package/dist/agent-message-center/index.js.map +1 -0
- package/dist/agent-rich-text-at-provider.d.ts +49 -0
- package/dist/agent-rich-text-at-provider.js +7 -0
- package/dist/agent-rich-text-at-provider.js.map +1 -0
- package/dist/agent-title-text.d.ts +3 -0
- package/dist/agent-title-text.js +7 -0
- package/dist/agent-title-text.js.map +1 -0
- package/dist/app/renderer/agentactivity.css +6773 -0
- package/dist/app/renderer/assets/icons/agent-sessions-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/agents/claude-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/codex-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/gemini-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/hermes-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-claude-code.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-codex.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-gemini.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-hermes.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-nextop.png +0 -0
- package/dist/app/renderer/assets/icons/agents/manage-agent-openclaw.png +0 -0
- package/dist/app/renderer/assets/icons/agents/nextop-doc-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/openclaw-rounded.png +0 -0
- package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-claude-code.png +0 -0
- package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-codex.png +0 -0
- package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-gemini.png +0 -0
- package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-nexight.png +0 -0
- package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-openclaw.png +0 -0
- package/dist/app/renderer/assets/icons/code-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/doc-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/folder-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/image-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/issue-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/product-filled.svg +1 -0
- package/dist/app/renderer/assets/icons/user-avatar-placeholder.png +0 -0
- package/dist/app/renderer/assets/icons/video-filled.svg +1 -0
- package/dist/chunk-22L4VWUR.js +70 -0
- package/dist/chunk-22L4VWUR.js.map +1 -0
- package/dist/chunk-3D5VTIKP.js +93 -0
- package/dist/chunk-3D5VTIKP.js.map +1 -0
- package/dist/chunk-AF5CXBJN.js +3075 -0
- package/dist/chunk-AF5CXBJN.js.map +1 -0
- package/dist/chunk-BABBC24I.js +28 -0
- package/dist/chunk-BABBC24I.js.map +1 -0
- package/dist/chunk-GCBDIQDX.js +22 -0
- package/dist/chunk-GCBDIQDX.js.map +1 -0
- package/dist/chunk-HSR5DI6O.js +4695 -0
- package/dist/chunk-HSR5DI6O.js.map +1 -0
- package/dist/chunk-IVPB4MLI.js +7 -0
- package/dist/chunk-IVPB4MLI.js.map +1 -0
- package/dist/chunk-KCC3GNPB.js +13 -0
- package/dist/chunk-KCC3GNPB.js.map +1 -0
- package/dist/chunk-PJP5BUU6.js +18 -0
- package/dist/chunk-PJP5BUU6.js.map +1 -0
- package/dist/chunk-RORLLV27.js +144 -0
- package/dist/chunk-RORLLV27.js.map +1 -0
- package/dist/chunk-UJWUGMWC.js +128 -0
- package/dist/chunk-UJWUGMWC.js.map +1 -0
- package/dist/chunk-UKQIGNN3.js +921 -0
- package/dist/chunk-UKQIGNN3.js.map +1 -0
- package/dist/chunk-ZP7P7DYO.js +270 -0
- package/dist/chunk-ZP7P7DYO.js.map +1 -0
- package/dist/chunk-ZX5PDYAS.js +346 -0
- package/dist/chunk-ZX5PDYAS.js.map +1 -0
- package/dist/claude-rounded-F6VPQETB.png +0 -0
- package/dist/codex-rounded-SC63MZAW.png +0 -0
- package/dist/gemini-rounded-O4KAJFIM.png +0 -0
- package/dist/hermes-rounded-QGDHBNRJ.png +0 -0
- package/dist/i18n/index.d.ts +4580 -0
- package/dist/i18n/index.js +19 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +775 -0
- package/dist/index.js +33699 -0
- package/dist/index.js.map +1 -0
- package/dist/manage-agent-claude-code-F6VPQETB.png +0 -0
- package/dist/manage-agent-codex-SC63MZAW.png +0 -0
- package/dist/manage-agent-gemini-O4KAJFIM.png +0 -0
- package/dist/manage-agent-hermes-QGDHBNRJ.png +0 -0
- package/dist/manage-agent-nextop-UFAQ22K2.png +0 -0
- package/dist/manage-agent-openclaw-24U7O6CA.png +0 -0
- package/dist/mention-file-presentation.d.ts +16 -0
- package/dist/mention-file-presentation.js +10 -0
- package/dist/mention-file-presentation.js.map +1 -0
- package/dist/nextop-doc-rounded-UFAQ22K2.png +0 -0
- package/dist/openclaw-rounded-24U7O6CA.png +0 -0
- package/dist/user-avatar-placeholder-WP2373TS.png +0 -0
- package/dist/workbench/contribution.d.ts +42 -0
- package/dist/workbench/contribution.js +24 -0
- package/dist/workbench/contribution.js.map +1 -0
- package/dist/workbench/index.d.ts +24 -0
- package/dist/workbench/index.js +82 -0
- package/dist/workbench/index.js.map +1 -0
- package/dist/workbench/launch.d.ts +49 -0
- package/dist/workbench/launch.js +23 -0
- package/dist/workbench/launch.js.map +1 -0
- package/dist/workbench/providerCatalog.d.ts +15 -0
- package/dist/workbench/providerCatalog.js +27 -0
- package/dist/workbench/providerCatalog.js.map +1 -0
- package/dist/workbench/state.d.ts +22 -0
- package/dist/workbench/state.js +22 -0
- package/dist/workbench/state.js.map +1 -0
- package/dist/workbench/types.d.ts +43 -0
- package/dist/workbench/types.js +7 -0
- package/dist/workbench/types.js.map +1 -0
- package/dist/workspace-agent-generated-files.d.ts +2 -0
- package/dist/workspace-agent-generated-files.js +21 -0
- package/dist/workspace-agent-generated-files.js.map +1 -0
- package/dist/workspaceAgentActivityListViewModel-PvLQDj60.d.ts +309 -0
- package/dist/workspaceLinkActions-Bwa-phu8.d.ts +51 -0
- package/package.json +166 -0
|
@@ -0,0 +1,3075 @@
|
|
|
1
|
+
import {
|
|
2
|
+
translate,
|
|
3
|
+
useTranslation
|
|
4
|
+
} from "./chunk-HSR5DI6O.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveAgentWorkspaceFileVisualKind
|
|
7
|
+
} from "./chunk-PJP5BUU6.js";
|
|
8
|
+
|
|
9
|
+
// agentActivityRuntime.tsx
|
|
10
|
+
import {
|
|
11
|
+
createContext,
|
|
12
|
+
useContext,
|
|
13
|
+
useSyncExternalStore
|
|
14
|
+
} from "react";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
var AgentActivityRuntimeContext = createContext(
|
|
17
|
+
null
|
|
18
|
+
);
|
|
19
|
+
var currentAgentActivityRuntime = null;
|
|
20
|
+
function AgentActivityRuntimeProvider({
|
|
21
|
+
children,
|
|
22
|
+
runtime
|
|
23
|
+
}) {
|
|
24
|
+
currentAgentActivityRuntime = runtime ?? null;
|
|
25
|
+
return /* @__PURE__ */ jsx(AgentActivityRuntimeContext.Provider, { value: runtime ?? null, children });
|
|
26
|
+
}
|
|
27
|
+
function useAgentActivityRuntime() {
|
|
28
|
+
const runtime = useContext(AgentActivityRuntimeContext) ?? getTestAgentActivityRuntime();
|
|
29
|
+
if (!runtime) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"AgentActivityRuntimeProvider is missing an AgentActivityRuntime instance."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return runtime;
|
|
35
|
+
}
|
|
36
|
+
function useOptionalAgentActivityRuntime() {
|
|
37
|
+
return useContext(AgentActivityRuntimeContext) ?? getTestAgentActivityRuntime();
|
|
38
|
+
}
|
|
39
|
+
function useAgentActivitySnapshot(workspaceId) {
|
|
40
|
+
const runtime = useAgentActivityRuntime();
|
|
41
|
+
const normalizedWorkspaceId = workspaceId.trim();
|
|
42
|
+
return useSyncExternalStore(
|
|
43
|
+
(listener) => runtime.subscribe(normalizedWorkspaceId, listener),
|
|
44
|
+
() => runtime.getSnapshot(normalizedWorkspaceId),
|
|
45
|
+
() => runtime.getSnapshot(normalizedWorkspaceId)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function getAgentActivityRuntime() {
|
|
49
|
+
const runtime = getExplicitWindowTestAgentActivityRuntime() ?? currentAgentActivityRuntime ?? getTestAgentActivityRuntime();
|
|
50
|
+
if (!runtime) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
"AgentActivityRuntimeProvider is missing an AgentActivityRuntime instance."
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return runtime;
|
|
56
|
+
}
|
|
57
|
+
function getOptionalAgentActivityRuntime() {
|
|
58
|
+
return getExplicitWindowTestAgentActivityRuntime() ?? currentAgentActivityRuntime ?? getTestAgentActivityRuntime();
|
|
59
|
+
}
|
|
60
|
+
function resetAgentActivityRuntimeForTests() {
|
|
61
|
+
if (process.env.NODE_ENV === "test") {
|
|
62
|
+
currentAgentActivityRuntime = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function setAgentActivityRuntimeForTests(runtime) {
|
|
66
|
+
if (process.env.NODE_ENV === "test") {
|
|
67
|
+
currentAgentActivityRuntime = runtime;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function getTestAgentActivityRuntime() {
|
|
71
|
+
if (process.env.NODE_ENV !== "test") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (typeof window === "undefined") {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const explicitRuntime = getExplicitWindowTestAgentActivityRuntime();
|
|
78
|
+
if (explicitRuntime) {
|
|
79
|
+
return explicitRuntime;
|
|
80
|
+
}
|
|
81
|
+
if (currentAgentActivityRuntime) {
|
|
82
|
+
return currentAgentActivityRuntime;
|
|
83
|
+
}
|
|
84
|
+
const testRuntime = window.agentActivityRuntime;
|
|
85
|
+
return testRuntime ?? null;
|
|
86
|
+
}
|
|
87
|
+
function getExplicitWindowTestAgentActivityRuntime() {
|
|
88
|
+
if (process.env.NODE_ENV !== "test" || typeof window === "undefined") {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const testDescriptor = Object.getOwnPropertyDescriptor(
|
|
92
|
+
window,
|
|
93
|
+
"agentActivityRuntime"
|
|
94
|
+
);
|
|
95
|
+
if (!testDescriptor || !("value" in testDescriptor)) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return testDescriptor.value ?? null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// agentActivityHost.tsx
|
|
102
|
+
import {
|
|
103
|
+
createContext as createContext2,
|
|
104
|
+
useContext as useContext2
|
|
105
|
+
} from "react";
|
|
106
|
+
|
|
107
|
+
// host/agentHostApi.ts
|
|
108
|
+
function toAgentHostRuntimeApi(hostApi) {
|
|
109
|
+
return {
|
|
110
|
+
account: hostApi.account,
|
|
111
|
+
agentGuiBatch: hostApi.agentGuiBatch ?? {},
|
|
112
|
+
clipboard: hostApi.clipboard,
|
|
113
|
+
debug: hostApi.debug,
|
|
114
|
+
filesystem: hostApi.filesystem,
|
|
115
|
+
meta: hostApi.meta,
|
|
116
|
+
onHostEvent: hostApi.onHostEvent,
|
|
117
|
+
runtime: hostApi.runtime,
|
|
118
|
+
userProjects: hostApi.userProjects,
|
|
119
|
+
workspace: hostApi.workspace,
|
|
120
|
+
workspaceAgentProbes: hostApi.workspaceAgentProbes
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// agentActivityHost.tsx
|
|
125
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
126
|
+
var AgentActivityHostContext = createContext2(
|
|
127
|
+
null
|
|
128
|
+
);
|
|
129
|
+
var currentAgentHostApi = null;
|
|
130
|
+
function AgentActivityHostProvider({
|
|
131
|
+
agentActivityRuntime,
|
|
132
|
+
agentHostApi,
|
|
133
|
+
children
|
|
134
|
+
}) {
|
|
135
|
+
const resolvedAgentHostApi = agentHostApi ? toAgentHostRuntimeApi(agentHostApi) : null;
|
|
136
|
+
currentAgentHostApi = resolvedAgentHostApi;
|
|
137
|
+
return /* @__PURE__ */ jsx2(AgentActivityRuntimeProvider, { runtime: agentActivityRuntime, children: /* @__PURE__ */ jsx2(AgentActivityHostContext.Provider, { value: resolvedAgentHostApi, children }) });
|
|
138
|
+
}
|
|
139
|
+
function useAgentHostApi() {
|
|
140
|
+
const agentHostApi = useContext2(AgentActivityHostContext) ?? getTestAgentHostApi();
|
|
141
|
+
if (!agentHostApi) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"AgentActivityHostProvider is missing an agentHostApi instance."
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return agentHostApi;
|
|
147
|
+
}
|
|
148
|
+
function useOptionalAgentHostApi() {
|
|
149
|
+
return useContext2(AgentActivityHostContext) ?? getTestAgentHostApi();
|
|
150
|
+
}
|
|
151
|
+
function getOptionalAgentHostApi() {
|
|
152
|
+
return getExplicitWindowTestAgentHostApi() ?? currentAgentHostApi ?? getTestAgentHostApi();
|
|
153
|
+
}
|
|
154
|
+
function getTestAgentHostApi() {
|
|
155
|
+
if (process.env.NODE_ENV !== "test") {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
if (typeof window === "undefined") {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const explicitAgentHostApi = getExplicitWindowTestAgentHostApi();
|
|
162
|
+
if (explicitAgentHostApi) {
|
|
163
|
+
return explicitAgentHostApi;
|
|
164
|
+
}
|
|
165
|
+
if (currentAgentHostApi) {
|
|
166
|
+
return currentAgentHostApi;
|
|
167
|
+
}
|
|
168
|
+
const testAgentHostApi = window.agentHostApi;
|
|
169
|
+
return testAgentHostApi ? toAgentHostRuntimeApi(testAgentHostApi) : null;
|
|
170
|
+
}
|
|
171
|
+
function getExplicitWindowTestAgentHostApi() {
|
|
172
|
+
if (process.env.NODE_ENV !== "test" || typeof window === "undefined") {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const testDescriptor = Object.getOwnPropertyDescriptor(
|
|
176
|
+
window,
|
|
177
|
+
"agentHostApi"
|
|
178
|
+
);
|
|
179
|
+
if (!testDescriptor || !("value" in testDescriptor)) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const testAgentHostApi = testDescriptor.value;
|
|
183
|
+
return testAgentHostApi ? toAgentHostRuntimeApi(testAgentHostApi) : null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// app/renderer/assets/icons/agents/manage-agent-claude-code.png
|
|
187
|
+
var manage_agent_claude_code_default = "./manage-agent-claude-code-F6VPQETB.png";
|
|
188
|
+
|
|
189
|
+
// app/renderer/assets/icons/agents/manage-agent-codex.png
|
|
190
|
+
var manage_agent_codex_default = "./manage-agent-codex-SC63MZAW.png";
|
|
191
|
+
|
|
192
|
+
// app/renderer/assets/icons/agents/manage-agent-gemini.png
|
|
193
|
+
var manage_agent_gemini_default = "./manage-agent-gemini-O4KAJFIM.png";
|
|
194
|
+
|
|
195
|
+
// app/renderer/assets/icons/agents/manage-agent-hermes.png
|
|
196
|
+
var manage_agent_hermes_default = "./manage-agent-hermes-QGDHBNRJ.png";
|
|
197
|
+
|
|
198
|
+
// app/renderer/assets/icons/agents/manage-agent-nextop.png
|
|
199
|
+
var manage_agent_nextop_default = "./manage-agent-nextop-UFAQ22K2.png";
|
|
200
|
+
|
|
201
|
+
// app/renderer/assets/icons/agents/manage-agent-openclaw.png
|
|
202
|
+
var manage_agent_openclaw_default = "./manage-agent-openclaw-24U7O6CA.png";
|
|
203
|
+
|
|
204
|
+
// app/renderer/assets/icons/agents/claude-rounded.png
|
|
205
|
+
var claude_rounded_default = "./claude-rounded-F6VPQETB.png";
|
|
206
|
+
|
|
207
|
+
// app/renderer/assets/icons/agents/codex-rounded.png
|
|
208
|
+
var codex_rounded_default = "./codex-rounded-SC63MZAW.png";
|
|
209
|
+
|
|
210
|
+
// app/renderer/assets/icons/agents/gemini-rounded.png
|
|
211
|
+
var gemini_rounded_default = "./gemini-rounded-O4KAJFIM.png";
|
|
212
|
+
|
|
213
|
+
// app/renderer/assets/icons/agents/hermes-rounded.png
|
|
214
|
+
var hermes_rounded_default = "./hermes-rounded-QGDHBNRJ.png";
|
|
215
|
+
|
|
216
|
+
// app/renderer/assets/icons/agents/nextop-doc-rounded.png
|
|
217
|
+
var nextop_doc_rounded_default = "./nextop-doc-rounded-UFAQ22K2.png";
|
|
218
|
+
|
|
219
|
+
// app/renderer/assets/icons/agents/openclaw-rounded.png
|
|
220
|
+
var openclaw_rounded_default = "./openclaw-rounded-24U7O6CA.png";
|
|
221
|
+
|
|
222
|
+
// shared/managedAgentProviders.ts
|
|
223
|
+
function normalizeManagedAgentProvider(provider) {
|
|
224
|
+
const normalized = provider?.trim().toLowerCase().replace(/[_\s]+/gu, "-") ?? "";
|
|
225
|
+
switch (normalized) {
|
|
226
|
+
case "claude":
|
|
227
|
+
case "claude-code":
|
|
228
|
+
return "claude-code";
|
|
229
|
+
case "nexight":
|
|
230
|
+
case "nextop-doc":
|
|
231
|
+
return "nextop";
|
|
232
|
+
default:
|
|
233
|
+
return normalized;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// shared/managedAgentIcons.ts
|
|
238
|
+
var MANAGED_AGENT_ICON_URLS = {
|
|
239
|
+
"claude-code": manage_agent_claude_code_default,
|
|
240
|
+
codex: manage_agent_codex_default,
|
|
241
|
+
gemini: manage_agent_gemini_default,
|
|
242
|
+
hermes: manage_agent_hermes_default,
|
|
243
|
+
nextop: manage_agent_nextop_default,
|
|
244
|
+
openclaw: manage_agent_openclaw_default
|
|
245
|
+
};
|
|
246
|
+
var MANAGED_AGENT_ICON_ROUNDED_URLS = {
|
|
247
|
+
"claude-code": claude_rounded_default,
|
|
248
|
+
codex: codex_rounded_default,
|
|
249
|
+
gemini: gemini_rounded_default,
|
|
250
|
+
hermes: hermes_rounded_default,
|
|
251
|
+
nextop: nextop_doc_rounded_default,
|
|
252
|
+
openclaw: openclaw_rounded_default
|
|
253
|
+
};
|
|
254
|
+
var MANAGED_AGENT_ROUNDED_ICON_FALLBACK_URL = nextop_doc_rounded_default;
|
|
255
|
+
var MANAGED_AGENT_ICON_FALLBACK_URL = manage_agent_nextop_default;
|
|
256
|
+
function managedAgentRoundedIconUrl(provider) {
|
|
257
|
+
return MANAGED_AGENT_ICON_ROUNDED_URLS[normalizeManagedAgentProvider(provider)] ?? MANAGED_AGENT_ROUNDED_ICON_FALLBACK_URL;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// shared/agentConversation/approvalOptionPresentation.ts
|
|
261
|
+
function approvalOptionDisplayLabel(option, intent = {}) {
|
|
262
|
+
const idToken = normalizeApprovalOptionToken(option.id);
|
|
263
|
+
const kindToken = normalizeApprovalOptionToken(option.kind);
|
|
264
|
+
const label = option.label.trim();
|
|
265
|
+
const specificTranslationKey = approvalOptionSpecificTranslationKey(
|
|
266
|
+
idToken,
|
|
267
|
+
label
|
|
268
|
+
);
|
|
269
|
+
if (specificTranslationKey) {
|
|
270
|
+
return translate(specificTranslationKey);
|
|
271
|
+
}
|
|
272
|
+
const providerLabelTranslation = approvalOptionProviderLabelTranslation(label);
|
|
273
|
+
if (providerLabelTranslation) {
|
|
274
|
+
return translate(
|
|
275
|
+
providerLabelTranslation.key,
|
|
276
|
+
providerLabelTranslation.params
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
if ((idToken === "allowonce" || kindToken === "allowonce") && isGenericAllowOnceLabel(label)) {
|
|
280
|
+
return translate("agentHost.agentGui.approvalOptions.allowOnce");
|
|
281
|
+
}
|
|
282
|
+
if ((idToken === "allowalways" || idToken === "allowall") && isGenericApprovalLabel(label)) {
|
|
283
|
+
return translate("agentHost.agentGui.approvalOptions.allowAlways");
|
|
284
|
+
}
|
|
285
|
+
if (idToken === "rejectalways" || kindToken === "rejectalways") {
|
|
286
|
+
return translate("agentHost.agentGui.approvalOptions.rejectAlways");
|
|
287
|
+
}
|
|
288
|
+
if (idToken === "rejectonce" || idToken === "reject" || idToken === "deny" || kindToken === "rejectonce" || kindToken === "reject" || kindToken === "deny") {
|
|
289
|
+
return intent.feedback ? translate("agentHost.agentGui.approvalOptions.rejectWithFollowUp") : translate("agentHost.agentGui.approvalOptions.rejectOnce");
|
|
290
|
+
}
|
|
291
|
+
return label || option.id;
|
|
292
|
+
}
|
|
293
|
+
function approvalOptionVisualPresentation(option, intent = {}) {
|
|
294
|
+
const commandPrefix = approvalOptionCommandPrefix(option.label);
|
|
295
|
+
if (commandPrefix) {
|
|
296
|
+
return {
|
|
297
|
+
label: translate(
|
|
298
|
+
"agentHost.agentGui.approvalOptions.allowAlwaysForCommandPrefixLead"
|
|
299
|
+
),
|
|
300
|
+
commandPrefix
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
label: approvalOptionDisplayLabel(option, intent)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function normalizeApprovalOptionToken(value) {
|
|
308
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
309
|
+
}
|
|
310
|
+
function approvalOptionSpecificTranslationKey(token, label) {
|
|
311
|
+
const labelToken = normalizeApprovalOptionToken(label);
|
|
312
|
+
switch (token) {
|
|
313
|
+
case "bypasspermissions":
|
|
314
|
+
return "agentHost.agentGui.approvalOptions.bypassPermissions";
|
|
315
|
+
case "auto":
|
|
316
|
+
return labelToken === "yesanduseautomode" ? "agentHost.agentGui.approvalOptions.autoMode" : null;
|
|
317
|
+
case "acceptedits":
|
|
318
|
+
return "agentHost.agentGui.approvalOptions.acceptEdits";
|
|
319
|
+
case "default":
|
|
320
|
+
return labelToken === "yesandmanuallyapproveedits" ? "agentHost.agentGui.approvalOptions.manualApproval" : null;
|
|
321
|
+
default:
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function approvalOptionProviderLabelTranslation(label) {
|
|
326
|
+
const commandPrefix = approvalOptionCommandPrefix(label);
|
|
327
|
+
if (commandPrefix) {
|
|
328
|
+
return {
|
|
329
|
+
key: "agentHost.agentGui.approvalOptions.allowAlwaysForCommandPrefix",
|
|
330
|
+
params: { command: commandPrefix }
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
const allowScopeMatch = label.match(/^Yes,\s*and don't ask again for (.+)$/i);
|
|
334
|
+
if (allowScopeMatch?.[1]) {
|
|
335
|
+
return {
|
|
336
|
+
key: "agentHost.agentGui.approvalOptions.allowAlwaysForScope",
|
|
337
|
+
params: { scope: allowScopeMatch[1] }
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const alwaysAllowMatch = label.match(/^Always Allow\s+(.+)$/i);
|
|
341
|
+
if (alwaysAllowMatch?.[1]) {
|
|
342
|
+
return {
|
|
343
|
+
key: "agentHost.agentGui.approvalOptions.alwaysAllowScope",
|
|
344
|
+
params: { scope: alwaysAllowMatch[1] }
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
function approvalOptionCommandPrefix(label) {
|
|
350
|
+
const commandPrefixMatch = label.match(
|
|
351
|
+
/^Yes,\s*and don't ask again for commands that start with `([^`]+)`$/i
|
|
352
|
+
);
|
|
353
|
+
return commandPrefixMatch?.[1]?.trim() || null;
|
|
354
|
+
}
|
|
355
|
+
function isGenericApprovalLabel(label) {
|
|
356
|
+
const token = normalizeApprovalOptionToken(label);
|
|
357
|
+
return token === "" || token === "allowalways" || token === "allowall" || token === "alwaysallow" || token === "yesanddontaskagain";
|
|
358
|
+
}
|
|
359
|
+
function isGenericAllowOnceLabel(label) {
|
|
360
|
+
const token = normalizeApprovalOptionToken(label);
|
|
361
|
+
return token === "" || token === "allow" || token === "allowonce" || token === "yes" || token === "yesproceed" || token === "yesandproceed";
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// shared/agentConversation/promptToolDetails.ts
|
|
365
|
+
function getPromptToolDetails(input) {
|
|
366
|
+
if (!input) {
|
|
367
|
+
return [];
|
|
368
|
+
}
|
|
369
|
+
const detailInput = resolveToolDetailInput(input);
|
|
370
|
+
const command = commandStringValue(detailInput.command) ?? commandStringValue(detailInput.cmd);
|
|
371
|
+
if (command) {
|
|
372
|
+
return [
|
|
373
|
+
{
|
|
374
|
+
kind: "command",
|
|
375
|
+
value: command,
|
|
376
|
+
...stringValue(detailInput.description) ? { meta: stringValue(detailInput.description) } : {}
|
|
377
|
+
}
|
|
378
|
+
];
|
|
379
|
+
}
|
|
380
|
+
const filePath = stringValue(detailInput.file_path) ?? stringValue(detailInput.filePath) ?? stringValue(detailInput.path) ?? stringValue(detailInput.notebook_path);
|
|
381
|
+
if (filePath) {
|
|
382
|
+
const lineRange = formatLineRange(detailInput);
|
|
383
|
+
return [
|
|
384
|
+
{
|
|
385
|
+
kind: "path",
|
|
386
|
+
value: filePath,
|
|
387
|
+
...lineRange ? { meta: lineRange } : {}
|
|
388
|
+
}
|
|
389
|
+
];
|
|
390
|
+
}
|
|
391
|
+
const query = stringValue(detailInput.query) ?? stringValue(detailInput.search_query) ?? stringValue(detailInput.searchQuery) ?? stringValue(detailInput.pattern);
|
|
392
|
+
if (query) {
|
|
393
|
+
return [
|
|
394
|
+
{
|
|
395
|
+
kind: "query",
|
|
396
|
+
value: query
|
|
397
|
+
}
|
|
398
|
+
];
|
|
399
|
+
}
|
|
400
|
+
return [];
|
|
401
|
+
}
|
|
402
|
+
function isPromptRequestIdTitle(value) {
|
|
403
|
+
return /^request(?:id|ID)\s*:/u.test(value.trim());
|
|
404
|
+
}
|
|
405
|
+
function resolveToolDetailInput(input) {
|
|
406
|
+
const toolCall = objectValue(input.toolCall);
|
|
407
|
+
return firstObjectValue(input, [
|
|
408
|
+
"command",
|
|
409
|
+
"cmd",
|
|
410
|
+
"file_path",
|
|
411
|
+
"filePath",
|
|
412
|
+
"path",
|
|
413
|
+
"notebook_path",
|
|
414
|
+
"query",
|
|
415
|
+
"search_query",
|
|
416
|
+
"searchQuery",
|
|
417
|
+
"pattern"
|
|
418
|
+
]) ?? firstObjectValue(toolCall, [
|
|
419
|
+
"input",
|
|
420
|
+
"rawInput",
|
|
421
|
+
"raw_input",
|
|
422
|
+
"arguments",
|
|
423
|
+
"args"
|
|
424
|
+
]) ?? toolCall ?? input;
|
|
425
|
+
}
|
|
426
|
+
function firstObjectValue(input, keys) {
|
|
427
|
+
if (!input) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
if (keys.some((key) => stringValue(input[key]))) {
|
|
431
|
+
return input;
|
|
432
|
+
}
|
|
433
|
+
for (const key of keys) {
|
|
434
|
+
const value = objectValue(input[key]);
|
|
435
|
+
if (value) {
|
|
436
|
+
return value;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
function formatLineRange(input) {
|
|
442
|
+
const start = numericValue(input.startLine) ?? numericValue(input.start_line);
|
|
443
|
+
const end = numericValue(input.endLine) ?? numericValue(input.end_line);
|
|
444
|
+
if (start === null || end === null) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
return start === end ? `L${start}` : `L${start}-${end}`;
|
|
448
|
+
}
|
|
449
|
+
function stringValue(value) {
|
|
450
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
451
|
+
}
|
|
452
|
+
function commandStringValue(value) {
|
|
453
|
+
if (typeof value === "string") {
|
|
454
|
+
return stringValue(value);
|
|
455
|
+
}
|
|
456
|
+
if (!Array.isArray(value)) {
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
const shellFlag = stringValue(value[value.length - 2]);
|
|
460
|
+
const shellCommand = stringValue(value[value.length - 1]);
|
|
461
|
+
if ((shellFlag === "-c" || shellFlag === "-lc") && shellCommand) {
|
|
462
|
+
return shellCommand;
|
|
463
|
+
}
|
|
464
|
+
const parts = value.flatMap((part) => {
|
|
465
|
+
const text = stringValue(part);
|
|
466
|
+
return text ? [text] : [];
|
|
467
|
+
});
|
|
468
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
469
|
+
}
|
|
470
|
+
function objectValue(value) {
|
|
471
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
472
|
+
}
|
|
473
|
+
function numericValue(value) {
|
|
474
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// shared/agentConversation/components/AgentInteractivePromptSurface.tsx
|
|
478
|
+
import {
|
|
479
|
+
useCallback as useCallback2,
|
|
480
|
+
useEffect as useEffect2,
|
|
481
|
+
useMemo,
|
|
482
|
+
useRef as useRef2,
|
|
483
|
+
useState
|
|
484
|
+
} from "react";
|
|
485
|
+
|
|
486
|
+
// app/renderer/components/icons/MessageSquareMoreIcon.tsx
|
|
487
|
+
import {
|
|
488
|
+
forwardRef,
|
|
489
|
+
useCallback,
|
|
490
|
+
useEffect,
|
|
491
|
+
useImperativeHandle,
|
|
492
|
+
useRef
|
|
493
|
+
} from "react";
|
|
494
|
+
import {
|
|
495
|
+
motion,
|
|
496
|
+
useAnimation,
|
|
497
|
+
useReducedMotion
|
|
498
|
+
} from "framer-motion";
|
|
499
|
+
|
|
500
|
+
// app/renderer/lib/utils.ts
|
|
501
|
+
import { clsx } from "clsx";
|
|
502
|
+
import { twMerge } from "tailwind-merge";
|
|
503
|
+
function cn(...inputs) {
|
|
504
|
+
return twMerge(clsx(inputs));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// app/renderer/components/icons/MessageSquareMoreIcon.tsx
|
|
508
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
509
|
+
var DOT_TRANSITION = {
|
|
510
|
+
times: [0, 0.1, 0.1, 0.2, 0.5, 0.6, 0.6, 0.7],
|
|
511
|
+
duration: 1.5
|
|
512
|
+
};
|
|
513
|
+
var DOT_VARIANTS = {
|
|
514
|
+
normal: {
|
|
515
|
+
opacity: 1
|
|
516
|
+
},
|
|
517
|
+
animate: (custom) => ({
|
|
518
|
+
opacity: [1, 0, 0, 1, 1, 0, 0, 1],
|
|
519
|
+
transition: {
|
|
520
|
+
opacity: {
|
|
521
|
+
...DOT_TRANSITION,
|
|
522
|
+
times: DOT_TRANSITION.times.map(
|
|
523
|
+
(time, index) => index === 2 || index === 3 || index === 6 || index === 7 ? time + custom * 0.1 : time
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}),
|
|
528
|
+
active: (custom) => ({
|
|
529
|
+
opacity: [1, 0, 0, 1, 1, 0, 0, 1],
|
|
530
|
+
transition: {
|
|
531
|
+
opacity: {
|
|
532
|
+
...DOT_TRANSITION,
|
|
533
|
+
repeat: Infinity,
|
|
534
|
+
times: DOT_TRANSITION.times.map(
|
|
535
|
+
(time, index) => index === 2 || index === 3 || index === 6 || index === 7 ? time + custom * 0.1 : time
|
|
536
|
+
)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
})
|
|
540
|
+
};
|
|
541
|
+
var MessageSquareMoreIcon = forwardRef(
|
|
542
|
+
({
|
|
543
|
+
active = false,
|
|
544
|
+
onMouseEnter,
|
|
545
|
+
onMouseLeave,
|
|
546
|
+
className,
|
|
547
|
+
size = 28,
|
|
548
|
+
...props
|
|
549
|
+
}, ref) => {
|
|
550
|
+
const controls = useAnimation();
|
|
551
|
+
const reduceMotion = useReducedMotion();
|
|
552
|
+
const isControlledRef = useRef(false);
|
|
553
|
+
const startAnimation = useCallback(() => {
|
|
554
|
+
if (reduceMotion) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
void controls.start(active ? "active" : "animate");
|
|
558
|
+
}, [active, controls, reduceMotion]);
|
|
559
|
+
const stopAnimation = useCallback(() => {
|
|
560
|
+
void controls.start("normal");
|
|
561
|
+
}, [controls]);
|
|
562
|
+
useImperativeHandle(ref, () => {
|
|
563
|
+
isControlledRef.current = true;
|
|
564
|
+
return {
|
|
565
|
+
startAnimation,
|
|
566
|
+
stopAnimation
|
|
567
|
+
};
|
|
568
|
+
});
|
|
569
|
+
useEffect(() => {
|
|
570
|
+
if (active) {
|
|
571
|
+
startAnimation();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
stopAnimation();
|
|
575
|
+
}, [active, startAnimation, stopAnimation]);
|
|
576
|
+
const handleMouseEnter = useCallback(
|
|
577
|
+
(event) => {
|
|
578
|
+
if (isControlledRef.current) {
|
|
579
|
+
onMouseEnter?.(event);
|
|
580
|
+
} else {
|
|
581
|
+
startAnimation();
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
[onMouseEnter, startAnimation]
|
|
585
|
+
);
|
|
586
|
+
const handleMouseLeave = useCallback(
|
|
587
|
+
(event) => {
|
|
588
|
+
if (isControlledRef.current) {
|
|
589
|
+
onMouseLeave?.(event);
|
|
590
|
+
} else {
|
|
591
|
+
stopAnimation();
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
[onMouseLeave, stopAnimation]
|
|
595
|
+
);
|
|
596
|
+
return /* @__PURE__ */ jsx3(
|
|
597
|
+
"div",
|
|
598
|
+
{
|
|
599
|
+
className: cn("inline-flex items-center justify-center", className),
|
|
600
|
+
onMouseEnter: handleMouseEnter,
|
|
601
|
+
onMouseLeave: handleMouseLeave,
|
|
602
|
+
...props,
|
|
603
|
+
children: /* @__PURE__ */ jsxs(
|
|
604
|
+
"svg",
|
|
605
|
+
{
|
|
606
|
+
fill: "none",
|
|
607
|
+
height: size,
|
|
608
|
+
stroke: "currentColor",
|
|
609
|
+
strokeLinecap: "round",
|
|
610
|
+
strokeLinejoin: "round",
|
|
611
|
+
strokeWidth: "2",
|
|
612
|
+
viewBox: "0 0 24 24",
|
|
613
|
+
width: size,
|
|
614
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }),
|
|
617
|
+
/* @__PURE__ */ jsx3(
|
|
618
|
+
motion.path,
|
|
619
|
+
{
|
|
620
|
+
animate: controls,
|
|
621
|
+
custom: 0,
|
|
622
|
+
d: "M8 10h.01",
|
|
623
|
+
variants: DOT_VARIANTS
|
|
624
|
+
}
|
|
625
|
+
),
|
|
626
|
+
/* @__PURE__ */ jsx3(
|
|
627
|
+
motion.path,
|
|
628
|
+
{
|
|
629
|
+
animate: controls,
|
|
630
|
+
custom: 1,
|
|
631
|
+
d: "M12 10h.01",
|
|
632
|
+
variants: DOT_VARIANTS
|
|
633
|
+
}
|
|
634
|
+
),
|
|
635
|
+
/* @__PURE__ */ jsx3(
|
|
636
|
+
motion.path,
|
|
637
|
+
{
|
|
638
|
+
animate: controls,
|
|
639
|
+
custom: 2,
|
|
640
|
+
d: "M16 10h.01",
|
|
641
|
+
variants: DOT_VARIANTS
|
|
642
|
+
}
|
|
643
|
+
)
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
);
|
|
651
|
+
MessageSquareMoreIcon.displayName = "MessageSquareMoreIcon";
|
|
652
|
+
|
|
653
|
+
// app/renderer/components/ui/spinner.tsx
|
|
654
|
+
import { Spinner } from "@tutti-os/ui-system";
|
|
655
|
+
|
|
656
|
+
// shared/agentConversation/components/AgentInteractivePromptSurface.tsx
|
|
657
|
+
import {
|
|
658
|
+
ShortcutBadge,
|
|
659
|
+
Tooltip,
|
|
660
|
+
TooltipContent,
|
|
661
|
+
TooltipProvider,
|
|
662
|
+
TooltipTrigger
|
|
663
|
+
} from "@tutti-os/ui-system";
|
|
664
|
+
|
|
665
|
+
// agent-gui/agentGuiNode/AgentGUIConversation.styles.ts
|
|
666
|
+
var styles = {
|
|
667
|
+
interactivePrompt: "agent-gui-conversation__interactive-prompt",
|
|
668
|
+
interactivePromptCard: "agent-gui-conversation__interactive-prompt-card",
|
|
669
|
+
interactivePromptHeader: "agent-gui-conversation__interactive-prompt-header",
|
|
670
|
+
interactivePromptLead: "agent-gui-conversation__interactive-prompt-lead",
|
|
671
|
+
interactivePromptMeta: "agent-gui-conversation__interactive-prompt-meta",
|
|
672
|
+
interactivePromptQuestion: "agent-gui-conversation__interactive-prompt-question",
|
|
673
|
+
interactivePromptOptions: "agent-gui-conversation__interactive-prompt-options",
|
|
674
|
+
interactiveOptionDisplay: "agent-gui-conversation__interactive-option-display",
|
|
675
|
+
interactiveOptionButton: "agent-gui-conversation__interactive-option-button",
|
|
676
|
+
interactiveOptionTitle: "agent-gui-conversation__interactive-option-title",
|
|
677
|
+
interactiveOptionDescription: "agent-gui-conversation__interactive-option-description",
|
|
678
|
+
interactiveOptionCommandDescription: "agent-gui-conversation__interactive-option-command-description",
|
|
679
|
+
interactiveOptionCommandTooltip: "agent-gui-conversation__interactive-option-command-tooltip",
|
|
680
|
+
interactiveOptionShortcut: "agent-gui-conversation__interactive-option-shortcut",
|
|
681
|
+
interactiveOptionSpinner: "agent-gui-conversation__interactive-option-spinner",
|
|
682
|
+
interactiveFeedbackComposer: "agent-gui-conversation__interactive-feedback-composer",
|
|
683
|
+
interactivePromptTextarea: "agent-gui-conversation__interactive-prompt-textarea",
|
|
684
|
+
interactiveFeedbackSendButton: "agent-gui-conversation__interactive-feedback-send-button",
|
|
685
|
+
interactivePromptFooter: "agent-gui-conversation__interactive-prompt-footer",
|
|
686
|
+
interactivePromptActions: "agent-gui-conversation__interactive-prompt-actions",
|
|
687
|
+
userMessageFlow: "agent-gui-conversation__user-message-flow",
|
|
688
|
+
assistantMessageFlow: "agent-gui-conversation__assistant-message-flow",
|
|
689
|
+
messageGroup: "agent-gui-conversation__message-group",
|
|
690
|
+
userMessageBubble: "agent-gui-conversation__user-message-bubble",
|
|
691
|
+
assistantMarkdown: "agent-gui-conversation__assistant-markdown"
|
|
692
|
+
};
|
|
693
|
+
var AgentGUIConversation_styles_default = styles;
|
|
694
|
+
|
|
695
|
+
// shared/agentConversation/components/AgentInteractivePromptSurface.tsx
|
|
696
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
697
|
+
var COMMAND_TOOLTIP_DELAY_MS = 1e3;
|
|
698
|
+
function AgentInteractivePromptSurface({
|
|
699
|
+
prompt,
|
|
700
|
+
edgeGlow = false,
|
|
701
|
+
embedded = false,
|
|
702
|
+
keyboardShortcuts = true,
|
|
703
|
+
isSubmitting,
|
|
704
|
+
onSubmit,
|
|
705
|
+
labels
|
|
706
|
+
}) {
|
|
707
|
+
"use memo";
|
|
708
|
+
if (prompt.kind === "approval") {
|
|
709
|
+
return /* @__PURE__ */ jsx4(
|
|
710
|
+
ApprovalPromptSurface,
|
|
711
|
+
{
|
|
712
|
+
prompt,
|
|
713
|
+
embedded,
|
|
714
|
+
edgeGlow,
|
|
715
|
+
keyboardShortcuts,
|
|
716
|
+
isSubmitting,
|
|
717
|
+
onSubmit,
|
|
718
|
+
labels
|
|
719
|
+
}
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
if (prompt.kind === "exit-plan") {
|
|
723
|
+
return /* @__PURE__ */ jsx4(
|
|
724
|
+
ExitPlanPromptSurface,
|
|
725
|
+
{
|
|
726
|
+
prompt,
|
|
727
|
+
embedded,
|
|
728
|
+
edgeGlow,
|
|
729
|
+
isSubmitting,
|
|
730
|
+
onSubmit,
|
|
731
|
+
labels
|
|
732
|
+
}
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
return /* @__PURE__ */ jsx4(
|
|
736
|
+
AskUserPromptSurface,
|
|
737
|
+
{
|
|
738
|
+
prompt,
|
|
739
|
+
embedded,
|
|
740
|
+
edgeGlow,
|
|
741
|
+
isSubmitting,
|
|
742
|
+
onSubmit,
|
|
743
|
+
labels
|
|
744
|
+
}
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
function ApprovalPromptSurface({
|
|
748
|
+
prompt,
|
|
749
|
+
embedded = false,
|
|
750
|
+
edgeGlow = false,
|
|
751
|
+
keyboardShortcuts = true,
|
|
752
|
+
isSubmitting,
|
|
753
|
+
onSubmit,
|
|
754
|
+
labels
|
|
755
|
+
}) {
|
|
756
|
+
"use memo";
|
|
757
|
+
const promptDetails = useMemo(
|
|
758
|
+
() => formatToolDetails(prompt.input ?? null),
|
|
759
|
+
[prompt.input]
|
|
760
|
+
);
|
|
761
|
+
const visiblePromptTitle = approvalPromptTitle(
|
|
762
|
+
prompt.title,
|
|
763
|
+
promptDetails.length
|
|
764
|
+
);
|
|
765
|
+
const details = useMemo(
|
|
766
|
+
() => filterDuplicatePromptTitleDetails(promptDetails, visiblePromptTitle),
|
|
767
|
+
[promptDetails, visiblePromptTitle]
|
|
768
|
+
);
|
|
769
|
+
const [submittingOptionId, setSubmittingOptionId] = useState(
|
|
770
|
+
null
|
|
771
|
+
);
|
|
772
|
+
const [pendingFeedbackOptionId, setPendingFeedbackOptionId] = useState(null);
|
|
773
|
+
const [feedback, setFeedback] = useState("");
|
|
774
|
+
const feedbackTextareaRef = useRef2(null);
|
|
775
|
+
const agentHostApi = useOptionalAgentHostApi() ?? getOptionalAgentHostApi();
|
|
776
|
+
const isDarwin = isDarwinPlatform(agentHostApi?.meta?.platform);
|
|
777
|
+
const feedbackOptionId = useMemo(
|
|
778
|
+
() => approvalFeedbackOptionId(prompt.options),
|
|
779
|
+
[prompt.options]
|
|
780
|
+
);
|
|
781
|
+
const feedbackValue = feedback.trim();
|
|
782
|
+
useEffect2(() => {
|
|
783
|
+
setSubmittingOptionId(null);
|
|
784
|
+
setPendingFeedbackOptionId(null);
|
|
785
|
+
setFeedback("");
|
|
786
|
+
}, [prompt.requestId]);
|
|
787
|
+
useEffect2(() => {
|
|
788
|
+
if (pendingFeedbackOptionId !== null) {
|
|
789
|
+
feedbackTextareaRef.current?.focus();
|
|
790
|
+
}
|
|
791
|
+
}, [pendingFeedbackOptionId]);
|
|
792
|
+
const submitOption = useCallback2(
|
|
793
|
+
(optionId) => {
|
|
794
|
+
const feedbackOption = feedbackOptionId === optionId;
|
|
795
|
+
if (feedbackOption && pendingFeedbackOptionId !== optionId) {
|
|
796
|
+
setFeedback("");
|
|
797
|
+
setPendingFeedbackOptionId(optionId);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
setSubmittingOptionId(optionId);
|
|
801
|
+
onSubmit({
|
|
802
|
+
requestId: prompt.requestId,
|
|
803
|
+
...feedbackOption ? { action: "deny" } : {},
|
|
804
|
+
optionId,
|
|
805
|
+
...feedbackOption && feedbackValue ? { payload: { denyMessage: feedbackValue } } : {}
|
|
806
|
+
});
|
|
807
|
+
},
|
|
808
|
+
[
|
|
809
|
+
feedbackOptionId,
|
|
810
|
+
feedbackValue,
|
|
811
|
+
onSubmit,
|
|
812
|
+
pendingFeedbackOptionId,
|
|
813
|
+
prompt.requestId
|
|
814
|
+
]
|
|
815
|
+
);
|
|
816
|
+
useEffect2(() => {
|
|
817
|
+
if (!keyboardShortcuts || isSubmitting || submittingOptionId !== null || prompt.options.length === 0) {
|
|
818
|
+
return void 0;
|
|
819
|
+
}
|
|
820
|
+
const handleKeyDown = (event) => {
|
|
821
|
+
if (!isEnterLikeKey(event) || isEditableKeyboardTarget(event.target) || event.isComposing || event.altKey || event.shiftKey) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
const optionIndex = event.metaKey || event.ctrlKey ? 1 : 0;
|
|
825
|
+
const option = prompt.options[optionIndex];
|
|
826
|
+
if (!option) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
event.preventDefault();
|
|
830
|
+
event.stopPropagation();
|
|
831
|
+
submitOption(option.id);
|
|
832
|
+
};
|
|
833
|
+
window.addEventListener("keydown", handleKeyDown, true);
|
|
834
|
+
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
835
|
+
}, [
|
|
836
|
+
isSubmitting,
|
|
837
|
+
keyboardShortcuts,
|
|
838
|
+
prompt.options,
|
|
839
|
+
submitOption,
|
|
840
|
+
submittingOptionId
|
|
841
|
+
]);
|
|
842
|
+
return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
|
|
843
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(labels.approvalLead) }),
|
|
844
|
+
visiblePromptTitle ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptQuestion, children: visiblePromptTitle }) : null,
|
|
845
|
+
details.length > 0 ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: details.map((detail) => /* @__PURE__ */ jsxs2(
|
|
846
|
+
"div",
|
|
847
|
+
{
|
|
848
|
+
className: AgentGUIConversation_styles_default.interactiveOptionDisplay,
|
|
849
|
+
children: [
|
|
850
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: detail.label }),
|
|
851
|
+
/* @__PURE__ */ jsx4(PromptDetailValue, { detail }),
|
|
852
|
+
detail.meta ? /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: detail.meta }) : null
|
|
853
|
+
]
|
|
854
|
+
},
|
|
855
|
+
`${detail.label}:${detail.value}`
|
|
856
|
+
)) }) : null,
|
|
857
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: prompt.options.map((option, optionIndex) => {
|
|
858
|
+
const showSpinner = submittingOptionId === option.id;
|
|
859
|
+
const optionSupportsFeedback = feedbackOptionId === option.id;
|
|
860
|
+
const optionLabel = approvalOptionDisplayLabel(option, {
|
|
861
|
+
feedback: optionSupportsFeedback
|
|
862
|
+
});
|
|
863
|
+
const optionPresentation = approvalOptionVisualPresentation(
|
|
864
|
+
option,
|
|
865
|
+
{ feedback: optionSupportsFeedback }
|
|
866
|
+
);
|
|
867
|
+
const shortcutLabel = approvalOptionShortcutLabel(
|
|
868
|
+
optionIndex,
|
|
869
|
+
isDarwin
|
|
870
|
+
);
|
|
871
|
+
const showFeedbackComposer = pendingFeedbackOptionId === option.id;
|
|
872
|
+
if (showFeedbackComposer) {
|
|
873
|
+
return /* @__PURE__ */ jsxs2(
|
|
874
|
+
"div",
|
|
875
|
+
{
|
|
876
|
+
className: AgentGUIConversation_styles_default.interactiveFeedbackComposer,
|
|
877
|
+
children: [
|
|
878
|
+
/* @__PURE__ */ jsx4(
|
|
879
|
+
"textarea",
|
|
880
|
+
{
|
|
881
|
+
ref: feedbackTextareaRef,
|
|
882
|
+
value: feedback,
|
|
883
|
+
placeholder: labels.feedbackPlaceholder,
|
|
884
|
+
disabled: isSubmitting || submittingOptionId !== null,
|
|
885
|
+
className: AgentGUIConversation_styles_default.interactivePromptTextarea,
|
|
886
|
+
"aria-label": interactiveOptionLabel(
|
|
887
|
+
optionLabel,
|
|
888
|
+
option.description
|
|
889
|
+
),
|
|
890
|
+
onChange: (event) => setFeedback(event.currentTarget.value),
|
|
891
|
+
onKeyDown: (event) => {
|
|
892
|
+
if (!keyboardShortcuts || event.key !== "Enter" || !event.metaKey && !event.ctrlKey || event.nativeEvent.isComposing) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
event.preventDefault();
|
|
896
|
+
if (!feedbackValue) {
|
|
897
|
+
feedbackTextareaRef.current?.focus();
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
submitOption(option.id);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
),
|
|
904
|
+
/* @__PURE__ */ jsx4(
|
|
905
|
+
"button",
|
|
906
|
+
{
|
|
907
|
+
type: "button",
|
|
908
|
+
className: AgentGUIConversation_styles_default.interactiveFeedbackSendButton,
|
|
909
|
+
disabled: isSubmitting || submittingOptionId !== null || !feedbackValue,
|
|
910
|
+
"aria-label": labels.sendFeedback,
|
|
911
|
+
title: labels.sendFeedback,
|
|
912
|
+
"aria-busy": showSpinner,
|
|
913
|
+
onClick: () => {
|
|
914
|
+
if (!feedbackValue) {
|
|
915
|
+
feedbackTextareaRef.current?.focus();
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
submitOption(option.id);
|
|
919
|
+
},
|
|
920
|
+
children: showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : /* @__PURE__ */ jsx4(SendFilledIcon, {})
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
]
|
|
924
|
+
},
|
|
925
|
+
option.id
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
return /* @__PURE__ */ jsxs2(
|
|
929
|
+
"button",
|
|
930
|
+
{
|
|
931
|
+
type: "button",
|
|
932
|
+
className: AgentGUIConversation_styles_default.interactiveOptionButton,
|
|
933
|
+
"aria-label": interactiveOptionLabel(
|
|
934
|
+
optionLabel,
|
|
935
|
+
option.description
|
|
936
|
+
),
|
|
937
|
+
disabled: isSubmitting || submittingOptionId !== null,
|
|
938
|
+
onClick: () => submitOption(option.id),
|
|
939
|
+
children: [
|
|
940
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: optionPresentation.label }),
|
|
941
|
+
optionPresentation.commandPrefix ? /* @__PURE__ */ jsx4(
|
|
942
|
+
CommandTextWithTooltip,
|
|
943
|
+
{
|
|
944
|
+
value: optionPresentation.commandPrefix,
|
|
945
|
+
testId: "agent-interactive-command-prefix-option"
|
|
946
|
+
}
|
|
947
|
+
) : null,
|
|
948
|
+
option.description ? /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: option.description }) : null,
|
|
949
|
+
keyboardShortcuts && shortcutLabel && !showSpinner ? /* @__PURE__ */ jsx4(
|
|
950
|
+
ShortcutBadge,
|
|
951
|
+
{
|
|
952
|
+
className: AgentGUIConversation_styles_default.interactiveOptionShortcut,
|
|
953
|
+
"aria-hidden": "true",
|
|
954
|
+
children: shortcutLabel
|
|
955
|
+
}
|
|
956
|
+
) : null,
|
|
957
|
+
showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : null
|
|
958
|
+
]
|
|
959
|
+
},
|
|
960
|
+
option.id
|
|
961
|
+
);
|
|
962
|
+
}) })
|
|
963
|
+
] }) });
|
|
964
|
+
}
|
|
965
|
+
function ExitPlanPromptSurface({
|
|
966
|
+
prompt,
|
|
967
|
+
embedded = false,
|
|
968
|
+
edgeGlow = false,
|
|
969
|
+
isSubmitting,
|
|
970
|
+
onSubmit,
|
|
971
|
+
labels
|
|
972
|
+
}) {
|
|
973
|
+
"use memo";
|
|
974
|
+
const [feedback, setFeedback] = useState("");
|
|
975
|
+
const [submittingOptionId, setSubmittingOptionId] = useState(
|
|
976
|
+
null
|
|
977
|
+
);
|
|
978
|
+
const trimmed = feedback.trim();
|
|
979
|
+
const continueLabel = trimmed === "" ? labels.stayInPlan : labels.sendFeedback;
|
|
980
|
+
useEffect2(() => {
|
|
981
|
+
setSubmittingOptionId(null);
|
|
982
|
+
}, [prompt.requestId]);
|
|
983
|
+
return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
|
|
984
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(labels.planLead) }),
|
|
985
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: labels.planModes.map((mode) => {
|
|
986
|
+
const showSpinner = submittingOptionId === mode.id;
|
|
987
|
+
return /* @__PURE__ */ jsxs2(
|
|
988
|
+
"button",
|
|
989
|
+
{
|
|
990
|
+
type: "button",
|
|
991
|
+
className: AgentGUIConversation_styles_default.interactiveOptionButton,
|
|
992
|
+
"aria-label": interactiveOptionLabel(
|
|
993
|
+
mode.label,
|
|
994
|
+
mode.description
|
|
995
|
+
),
|
|
996
|
+
disabled: isSubmitting || submittingOptionId !== null,
|
|
997
|
+
onClick: () => {
|
|
998
|
+
setSubmittingOptionId(mode.id);
|
|
999
|
+
onSubmit({
|
|
1000
|
+
requestId: prompt.requestId,
|
|
1001
|
+
action: "allow",
|
|
1002
|
+
optionId: mode.id
|
|
1003
|
+
});
|
|
1004
|
+
},
|
|
1005
|
+
children: [
|
|
1006
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: mode.label }),
|
|
1007
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: mode.description }),
|
|
1008
|
+
showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : null
|
|
1009
|
+
]
|
|
1010
|
+
},
|
|
1011
|
+
mode.id
|
|
1012
|
+
);
|
|
1013
|
+
}) }),
|
|
1014
|
+
/* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptFooter, children: [
|
|
1015
|
+
/* @__PURE__ */ jsx4(
|
|
1016
|
+
"textarea",
|
|
1017
|
+
{
|
|
1018
|
+
value: feedback,
|
|
1019
|
+
placeholder: labels.feedbackPlaceholder,
|
|
1020
|
+
disabled: isSubmitting,
|
|
1021
|
+
className: AgentGUIConversation_styles_default.interactivePromptTextarea,
|
|
1022
|
+
onChange: (event) => setFeedback(event.currentTarget.value)
|
|
1023
|
+
}
|
|
1024
|
+
),
|
|
1025
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptActions, children: /* @__PURE__ */ jsx4(
|
|
1026
|
+
"button",
|
|
1027
|
+
{
|
|
1028
|
+
type: "button",
|
|
1029
|
+
disabled: isSubmitting,
|
|
1030
|
+
onClick: () => onSubmit({
|
|
1031
|
+
requestId: prompt.requestId,
|
|
1032
|
+
action: "deny",
|
|
1033
|
+
payload: trimmed ? { denyMessage: trimmed } : void 0
|
|
1034
|
+
}),
|
|
1035
|
+
children: continueLabel
|
|
1036
|
+
}
|
|
1037
|
+
) })
|
|
1038
|
+
] })
|
|
1039
|
+
] }) });
|
|
1040
|
+
}
|
|
1041
|
+
function AskUserPromptSurface({
|
|
1042
|
+
prompt,
|
|
1043
|
+
embedded = false,
|
|
1044
|
+
edgeGlow = false,
|
|
1045
|
+
isSubmitting,
|
|
1046
|
+
onSubmit,
|
|
1047
|
+
labels
|
|
1048
|
+
}) {
|
|
1049
|
+
"use memo";
|
|
1050
|
+
const [index, setIndex] = useState(0);
|
|
1051
|
+
const [selectedByQuestionId, setSelectedByQuestionId] = useState({});
|
|
1052
|
+
const [freeTextByQuestionId, setFreeTextByQuestionId] = useState({});
|
|
1053
|
+
const question = prompt.questions[index] ?? null;
|
|
1054
|
+
const selected = question ? selectedByQuestionId[question.id] ?? [] : [];
|
|
1055
|
+
const freeText = question ? freeTextByQuestionId[question.id] ?? "" : "";
|
|
1056
|
+
const canAdvance = question !== null && (selected.length > 0 || freeText.trim() !== "" || question.options.length === 0);
|
|
1057
|
+
const isLast = index >= prompt.questions.length - 1;
|
|
1058
|
+
const payload = useMemo(() => {
|
|
1059
|
+
const answersByQuestionId = {};
|
|
1060
|
+
const answers = [];
|
|
1061
|
+
for (const current of prompt.questions) {
|
|
1062
|
+
const chosen = selectedByQuestionId[current.id] ?? [];
|
|
1063
|
+
const other = (freeTextByQuestionId[current.id] ?? "").trim();
|
|
1064
|
+
if (current.multiSelect) {
|
|
1065
|
+
const value2 = other ? [...chosen, other] : chosen;
|
|
1066
|
+
if (value2.length > 0) {
|
|
1067
|
+
answersByQuestionId[current.id] = value2;
|
|
1068
|
+
answers.push(value2.join(", "));
|
|
1069
|
+
}
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
const value = other || chosen[0];
|
|
1073
|
+
if (value) {
|
|
1074
|
+
answersByQuestionId[current.id] = value;
|
|
1075
|
+
answers.push(value);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
return { answers, answersByQuestionId };
|
|
1079
|
+
}, [freeTextByQuestionId, prompt.questions, selectedByQuestionId]);
|
|
1080
|
+
if (!question) {
|
|
1081
|
+
return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsx4("div", { className: interactivePromptCardClassName(edgeGlow), children: /* @__PURE__ */ jsxs2(
|
|
1082
|
+
"div",
|
|
1083
|
+
{
|
|
1084
|
+
className: `${AgentGUIConversation_styles_default.interactivePromptLead} inline-flex items-center gap-1.5`,
|
|
1085
|
+
children: [
|
|
1086
|
+
/* @__PURE__ */ jsx4(
|
|
1087
|
+
MessageSquareMoreIcon,
|
|
1088
|
+
{
|
|
1089
|
+
size: 15,
|
|
1090
|
+
active: true,
|
|
1091
|
+
"aria-hidden": "true",
|
|
1092
|
+
className: "shrink-0"
|
|
1093
|
+
}
|
|
1094
|
+
),
|
|
1095
|
+
stripPromptTitlePunctuation(labels.waitingForAnswer)
|
|
1096
|
+
]
|
|
1097
|
+
}
|
|
1098
|
+
) }) });
|
|
1099
|
+
}
|
|
1100
|
+
return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
|
|
1101
|
+
/* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptHeader, children: [
|
|
1102
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(question.header) }),
|
|
1103
|
+
/* @__PURE__ */ jsxs2("span", { className: AgentGUIConversation_styles_default.interactivePromptMeta, children: [
|
|
1104
|
+
index + 1,
|
|
1105
|
+
"/",
|
|
1106
|
+
prompt.questions.length
|
|
1107
|
+
] })
|
|
1108
|
+
] }),
|
|
1109
|
+
/* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptQuestion, children: question.question }),
|
|
1110
|
+
question.options.length > 0 ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: question.options.map((option) => {
|
|
1111
|
+
const active = selected.includes(option.label);
|
|
1112
|
+
return /* @__PURE__ */ jsxs2(
|
|
1113
|
+
"button",
|
|
1114
|
+
{
|
|
1115
|
+
type: "button",
|
|
1116
|
+
className: AgentGUIConversation_styles_default.interactiveOptionButton,
|
|
1117
|
+
"data-active": active,
|
|
1118
|
+
"aria-label": interactiveOptionLabel(
|
|
1119
|
+
option.label,
|
|
1120
|
+
option.description
|
|
1121
|
+
),
|
|
1122
|
+
disabled: isSubmitting,
|
|
1123
|
+
onClick: () => {
|
|
1124
|
+
setSelectedByQuestionId((current) => {
|
|
1125
|
+
const existing = current[question.id] ?? [];
|
|
1126
|
+
const next = question.multiSelect ? existing.includes(option.label) ? existing.filter((value) => value !== option.label) : [...existing, option.label] : existing.includes(option.label) ? [] : [option.label];
|
|
1127
|
+
return { ...current, [question.id]: next };
|
|
1128
|
+
});
|
|
1129
|
+
},
|
|
1130
|
+
children: [
|
|
1131
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: option.label }),
|
|
1132
|
+
/* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: option.description })
|
|
1133
|
+
]
|
|
1134
|
+
},
|
|
1135
|
+
option.label
|
|
1136
|
+
);
|
|
1137
|
+
}) }) : null,
|
|
1138
|
+
/* @__PURE__ */ jsx4(
|
|
1139
|
+
"textarea",
|
|
1140
|
+
{
|
|
1141
|
+
value: freeText,
|
|
1142
|
+
placeholder: labels.answerPlaceholder,
|
|
1143
|
+
disabled: isSubmitting,
|
|
1144
|
+
className: AgentGUIConversation_styles_default.interactivePromptTextarea,
|
|
1145
|
+
onChange: (event) => {
|
|
1146
|
+
const value = event.currentTarget.value;
|
|
1147
|
+
setFreeTextByQuestionId((current) => ({
|
|
1148
|
+
...current,
|
|
1149
|
+
[question.id]: value
|
|
1150
|
+
}));
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
),
|
|
1154
|
+
/* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptActions, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx4(
|
|
1156
|
+
"button",
|
|
1157
|
+
{
|
|
1158
|
+
type: "button",
|
|
1159
|
+
disabled: isSubmitting || index === 0,
|
|
1160
|
+
onClick: () => setIndex((current) => Math.max(current - 1, 0)),
|
|
1161
|
+
children: labels.previousQuestion
|
|
1162
|
+
}
|
|
1163
|
+
),
|
|
1164
|
+
isLast ? /* @__PURE__ */ jsx4(
|
|
1165
|
+
"button",
|
|
1166
|
+
{
|
|
1167
|
+
type: "button",
|
|
1168
|
+
disabled: isSubmitting || Object.keys(payload.answersByQuestionId).length === 0,
|
|
1169
|
+
onClick: () => onSubmit({
|
|
1170
|
+
requestId: prompt.requestId,
|
|
1171
|
+
action: "submit",
|
|
1172
|
+
payload
|
|
1173
|
+
}),
|
|
1174
|
+
children: labels.submitAnswers
|
|
1175
|
+
}
|
|
1176
|
+
) : /* @__PURE__ */ jsx4(
|
|
1177
|
+
"button",
|
|
1178
|
+
{
|
|
1179
|
+
type: "button",
|
|
1180
|
+
disabled: isSubmitting || !canAdvance,
|
|
1181
|
+
onClick: () => setIndex(
|
|
1182
|
+
(current) => Math.min(current + 1, prompt.questions.length - 1)
|
|
1183
|
+
),
|
|
1184
|
+
children: labels.nextQuestion
|
|
1185
|
+
}
|
|
1186
|
+
)
|
|
1187
|
+
] })
|
|
1188
|
+
] }) });
|
|
1189
|
+
}
|
|
1190
|
+
function isEnterLikeKey(event) {
|
|
1191
|
+
return event.key === "Enter" || event.code === "Enter" || event.code === "NumpadEnter";
|
|
1192
|
+
}
|
|
1193
|
+
function isEditableKeyboardTarget(target) {
|
|
1194
|
+
if (!(target instanceof HTMLElement)) {
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1197
|
+
const tagName = target.tagName.toLowerCase();
|
|
1198
|
+
return tagName === "input" || tagName === "textarea" || tagName === "select" || target.isContentEditable;
|
|
1199
|
+
}
|
|
1200
|
+
function approvalOptionShortcutLabel(optionIndex, isDarwin) {
|
|
1201
|
+
if (optionIndex === 0) {
|
|
1202
|
+
return translate("agentHost.agentGui.shortcutEnter");
|
|
1203
|
+
}
|
|
1204
|
+
if (optionIndex === 1) {
|
|
1205
|
+
return isDarwin ? translate("agentHost.agentGui.shortcutCmdEnter") : translate("agentHost.agentGui.shortcutCtrEnter");
|
|
1206
|
+
}
|
|
1207
|
+
return null;
|
|
1208
|
+
}
|
|
1209
|
+
function isDarwinPlatform(platform) {
|
|
1210
|
+
if (platform) {
|
|
1211
|
+
return platform === "darwin";
|
|
1212
|
+
}
|
|
1213
|
+
if (typeof navigator === "undefined") {
|
|
1214
|
+
return false;
|
|
1215
|
+
}
|
|
1216
|
+
const userAgentPlatform = "userAgentData" in navigator ? navigator.userAgentData?.platform : void 0;
|
|
1217
|
+
const navigatorPlatform = userAgentPlatform ?? navigator.platform ?? "";
|
|
1218
|
+
return /mac/i.test(navigatorPlatform);
|
|
1219
|
+
}
|
|
1220
|
+
function InteractiveOptionSpinner() {
|
|
1221
|
+
"use memo";
|
|
1222
|
+
return /* @__PURE__ */ jsx4(
|
|
1223
|
+
Spinner,
|
|
1224
|
+
{
|
|
1225
|
+
className: AgentGUIConversation_styles_default.interactiveOptionSpinner,
|
|
1226
|
+
testId: "agent-interactive-option-spinner"
|
|
1227
|
+
}
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
function SendFilledIcon() {
|
|
1231
|
+
"use memo";
|
|
1232
|
+
return /* @__PURE__ */ jsx4(
|
|
1233
|
+
"svg",
|
|
1234
|
+
{
|
|
1235
|
+
width: "24",
|
|
1236
|
+
height: "24",
|
|
1237
|
+
viewBox: "0 0 24 24",
|
|
1238
|
+
fill: "none",
|
|
1239
|
+
"aria-hidden": "true",
|
|
1240
|
+
children: /* @__PURE__ */ jsx4(
|
|
1241
|
+
"path",
|
|
1242
|
+
{
|
|
1243
|
+
d: "M2.74311 8.80587C2.84592 8.40096 3.14571 8.08844 3.54551 7.97033L18.5197 3.51569C18.9336 3.39383 19.3809 3.5054 19.6881 3.81262C19.9951 4.11984 20.1076 4.56798 19.9857 4.9817L15.5311 19.9559C15.413 20.3557 15.1005 20.6555 14.6956 20.7583C14.2895 20.8597 13.869 20.7438 13.5721 20.4469L10.455 15.1823C10.8585 14.6483 12.1563 12.9094 14.3475 9.96528C14.6086 9.70419 14.6382 9.31168 14.4138 9.08692C14.1891 8.86221 13.796 8.8913 13.5348 9.15252L8.31088 13.0423L3.05316 9.92799C2.7562 9.63104 2.64049 9.21071 2.74311 8.80587Z",
|
|
1244
|
+
fill: "currentColor"
|
|
1245
|
+
}
|
|
1246
|
+
)
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function interactivePromptClassName(embedded) {
|
|
1251
|
+
return embedded ? `${AgentGUIConversation_styles_default.interactivePrompt} agent-gui-conversation__interactive-prompt--embedded` : AgentGUIConversation_styles_default.interactivePrompt;
|
|
1252
|
+
}
|
|
1253
|
+
function interactivePromptCardClassName(edgeGlow) {
|
|
1254
|
+
return edgeGlow ? `${AgentGUIConversation_styles_default.interactivePromptCard} agent-gui-edge-glow` : AgentGUIConversation_styles_default.interactivePromptCard;
|
|
1255
|
+
}
|
|
1256
|
+
function formatToolDetails(input) {
|
|
1257
|
+
return getPromptToolDetails(input).map((detail) => ({
|
|
1258
|
+
kind: detail.kind,
|
|
1259
|
+
label: promptToolDetailLabel(detail.kind),
|
|
1260
|
+
value: detail.value,
|
|
1261
|
+
...detail.meta ? { meta: detail.meta } : {}
|
|
1262
|
+
}));
|
|
1263
|
+
}
|
|
1264
|
+
function PromptDetailValue({
|
|
1265
|
+
detail
|
|
1266
|
+
}) {
|
|
1267
|
+
"use memo";
|
|
1268
|
+
if (detail.kind !== "command") {
|
|
1269
|
+
return /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: detail.value });
|
|
1270
|
+
}
|
|
1271
|
+
return /* @__PURE__ */ jsx4(
|
|
1272
|
+
CommandTextWithTooltip,
|
|
1273
|
+
{
|
|
1274
|
+
value: detail.value,
|
|
1275
|
+
testId: "agent-interactive-command-detail"
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
function CommandTextWithTooltip({
|
|
1280
|
+
value,
|
|
1281
|
+
testId
|
|
1282
|
+
}) {
|
|
1283
|
+
"use memo";
|
|
1284
|
+
return /* @__PURE__ */ jsx4(TooltipProvider, { delayDuration: COMMAND_TOOLTIP_DELAY_MS, children: /* @__PURE__ */ jsxs2(Tooltip, { children: [
|
|
1285
|
+
/* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx4(
|
|
1286
|
+
"span",
|
|
1287
|
+
{
|
|
1288
|
+
className: `${AgentGUIConversation_styles_default.interactiveOptionDescription} ${AgentGUIConversation_styles_default.interactiveOptionCommandDescription}`,
|
|
1289
|
+
"data-agent-interactive-command-detail": testId === "agent-interactive-command-detail" ? "true" : void 0,
|
|
1290
|
+
"data-agent-interactive-command-prefix-option": testId === "agent-interactive-command-prefix-option" ? "true" : void 0,
|
|
1291
|
+
children: value
|
|
1292
|
+
}
|
|
1293
|
+
) }),
|
|
1294
|
+
/* @__PURE__ */ jsx4(TooltipContent, { className: AgentGUIConversation_styles_default.interactiveOptionCommandTooltip, children: value })
|
|
1295
|
+
] }) });
|
|
1296
|
+
}
|
|
1297
|
+
function promptToolDetailLabel(kind) {
|
|
1298
|
+
switch (kind) {
|
|
1299
|
+
case "command":
|
|
1300
|
+
return translate("agentHost.agentTool.details.command");
|
|
1301
|
+
case "path":
|
|
1302
|
+
return translate("agentHost.agentTool.details.path");
|
|
1303
|
+
case "query":
|
|
1304
|
+
return translate("agentHost.agentTool.details.query");
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function filterDuplicatePromptTitleDetails(details, title) {
|
|
1308
|
+
const normalizedTitle = normalizePromptDetailText(title);
|
|
1309
|
+
if (!normalizedTitle) {
|
|
1310
|
+
return details;
|
|
1311
|
+
}
|
|
1312
|
+
return details.filter(
|
|
1313
|
+
(detail) => normalizePromptDetailText(detail.value) !== normalizedTitle
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
function normalizePromptDetailText(value) {
|
|
1317
|
+
return value?.trim() ?? "";
|
|
1318
|
+
}
|
|
1319
|
+
function isApprovalFeedbackOption(option) {
|
|
1320
|
+
return isDenyApprovalOptionToken(option.id) || isDenyApprovalOptionToken(option.kind);
|
|
1321
|
+
}
|
|
1322
|
+
function approvalFeedbackOptionId(options) {
|
|
1323
|
+
const explicitFeedbackOption = options.find(
|
|
1324
|
+
(option) => isExplicitFeedbackDenyApprovalOption(option)
|
|
1325
|
+
);
|
|
1326
|
+
if (explicitFeedbackOption) {
|
|
1327
|
+
return explicitFeedbackOption.id;
|
|
1328
|
+
}
|
|
1329
|
+
return options.find(isApprovalFeedbackOption)?.id ?? null;
|
|
1330
|
+
}
|
|
1331
|
+
function isExplicitFeedbackDenyApprovalOption(option) {
|
|
1332
|
+
for (const value of [option.id, option.kind]) {
|
|
1333
|
+
switch (normalizeApprovalOptionToken(value ?? "")) {
|
|
1334
|
+
case "abort":
|
|
1335
|
+
case "cancel":
|
|
1336
|
+
case "cancelled":
|
|
1337
|
+
case "canceled":
|
|
1338
|
+
case "denywithfeedback":
|
|
1339
|
+
case "rejectwithfeedback":
|
|
1340
|
+
return true;
|
|
1341
|
+
default:
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return false;
|
|
1346
|
+
}
|
|
1347
|
+
function isDenyApprovalOptionToken(value) {
|
|
1348
|
+
switch (normalizeApprovalOptionToken(value ?? "")) {
|
|
1349
|
+
case "abort":
|
|
1350
|
+
case "cancel":
|
|
1351
|
+
case "cancelled":
|
|
1352
|
+
case "canceled":
|
|
1353
|
+
case "deny":
|
|
1354
|
+
case "denied":
|
|
1355
|
+
case "reject":
|
|
1356
|
+
case "rejected":
|
|
1357
|
+
case "rejectonce":
|
|
1358
|
+
case "disallow":
|
|
1359
|
+
case "decline":
|
|
1360
|
+
case "declined":
|
|
1361
|
+
case "no":
|
|
1362
|
+
return true;
|
|
1363
|
+
default:
|
|
1364
|
+
return false;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
function approvalPromptTitle(value, detailCount) {
|
|
1368
|
+
const title = value.trim();
|
|
1369
|
+
return title && detailCount === 0 && !isPromptRequestIdTitle(title) ? title : null;
|
|
1370
|
+
}
|
|
1371
|
+
function stripPromptTitlePunctuation(value) {
|
|
1372
|
+
return value.trim().replace(/[.。]+$/u, "");
|
|
1373
|
+
}
|
|
1374
|
+
function interactiveOptionLabel(label, description) {
|
|
1375
|
+
const trimmedDescription = description?.trim();
|
|
1376
|
+
return trimmedDescription ? `${label} ${trimmedDescription}` : label;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// shared/AgentMessageMarkdown.tsx
|
|
1380
|
+
import {
|
|
1381
|
+
createContext as createContext3,
|
|
1382
|
+
startTransition,
|
|
1383
|
+
useCallback as useCallback3,
|
|
1384
|
+
useEffect as useEffect3,
|
|
1385
|
+
useContext as useContext3,
|
|
1386
|
+
useMemo as useMemo2,
|
|
1387
|
+
useState as useState2
|
|
1388
|
+
} from "react";
|
|
1389
|
+
|
|
1390
|
+
// app/renderer/components/ZoomableImage.tsx
|
|
1391
|
+
import {
|
|
1392
|
+
cloneElement
|
|
1393
|
+
} from "react";
|
|
1394
|
+
import Zoom from "react-medium-image-zoom";
|
|
1395
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1396
|
+
function ZoomableImage({
|
|
1397
|
+
className,
|
|
1398
|
+
wrapElement = "div",
|
|
1399
|
+
...props
|
|
1400
|
+
}) {
|
|
1401
|
+
const { t } = useTranslation();
|
|
1402
|
+
const renderZoomContent = ({
|
|
1403
|
+
buttonUnzoom,
|
|
1404
|
+
img
|
|
1405
|
+
}) => /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1406
|
+
img,
|
|
1407
|
+
cloneElement(buttonUnzoom, {
|
|
1408
|
+
className: cn(
|
|
1409
|
+
buttonUnzoom.props.className,
|
|
1410
|
+
"nodrag tsh-desktop-no-drag"
|
|
1411
|
+
)
|
|
1412
|
+
})
|
|
1413
|
+
] });
|
|
1414
|
+
return /* @__PURE__ */ jsx5(
|
|
1415
|
+
Zoom,
|
|
1416
|
+
{
|
|
1417
|
+
a11yNameButtonZoom: t("common.expandImage"),
|
|
1418
|
+
a11yNameButtonUnzoom: t("common.minimizeImage"),
|
|
1419
|
+
classDialog: "tsh-zoom-dialog nodrag tsh-desktop-no-drag",
|
|
1420
|
+
wrapElement,
|
|
1421
|
+
zoomMargin: 24,
|
|
1422
|
+
ZoomContent: renderZoomContent,
|
|
1423
|
+
children: /* @__PURE__ */ jsx5(
|
|
1424
|
+
"img",
|
|
1425
|
+
{
|
|
1426
|
+
...props,
|
|
1427
|
+
className: cn("nodrag tsh-desktop-no-drag cursor-zoom-in", className)
|
|
1428
|
+
}
|
|
1429
|
+
)
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// shared/AgentMessageMarkdown.tsx
|
|
1435
|
+
import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
|
|
1436
|
+
import rehypeSanitize, {
|
|
1437
|
+
defaultSchema
|
|
1438
|
+
} from "rehype-sanitize";
|
|
1439
|
+
import remarkGfm from "remark-gfm";
|
|
1440
|
+
import {
|
|
1441
|
+
resolveWorkspaceFileExtension,
|
|
1442
|
+
resolveWorkspaceImageMimeType,
|
|
1443
|
+
workspaceFileName as basenameWorkspacePath
|
|
1444
|
+
} from "@tutti-os/workspace-file-manager/services";
|
|
1445
|
+
|
|
1446
|
+
// shared/utils/websiteUrl.ts
|
|
1447
|
+
var ALLOWED_WEBSITE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
1448
|
+
var LIKELY_HOST_PATTERN = /^(localhost|(\d{1,3}\.){3}\d{1,3}|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})(?::\d{1,5})?(?:[/?#][^\s]*)?$/i;
|
|
1449
|
+
var EXPLICIT_PROTOCOL_PATTERN = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//;
|
|
1450
|
+
var LOOPBACK_HOST_PATTERN = /^(localhost|127(?:\.\d{1,3}){3})(?::\d{1,5})?(?:[/?#][^\s]*)?$/i;
|
|
1451
|
+
function defaultSchemeForHostInput(value) {
|
|
1452
|
+
return LOOPBACK_HOST_PATTERN.test(value) ? "http" : "https";
|
|
1453
|
+
}
|
|
1454
|
+
function resolveWebsiteNavigationUrl(rawUrl) {
|
|
1455
|
+
const trimmed = rawUrl.trim();
|
|
1456
|
+
if (trimmed.length === 0) {
|
|
1457
|
+
return { url: null, error: null };
|
|
1458
|
+
}
|
|
1459
|
+
if (EXPLICIT_PROTOCOL_PATTERN.test(trimmed)) {
|
|
1460
|
+
try {
|
|
1461
|
+
const parsed = new URL(trimmed);
|
|
1462
|
+
if (!ALLOWED_WEBSITE_PROTOCOLS.has(parsed.protocol)) {
|
|
1463
|
+
return { url: null, error: `Unsupported protocol: ${parsed.protocol}` };
|
|
1464
|
+
}
|
|
1465
|
+
return { url: parsed.toString(), error: null };
|
|
1466
|
+
} catch {
|
|
1467
|
+
return { url: null, error: "Invalid URL" };
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
if (!LIKELY_HOST_PATTERN.test(trimmed)) {
|
|
1471
|
+
return { url: null, error: "Invalid URL" };
|
|
1472
|
+
}
|
|
1473
|
+
try {
|
|
1474
|
+
const parsed = new URL(
|
|
1475
|
+
`${defaultSchemeForHostInput(trimmed)}://${trimmed}`
|
|
1476
|
+
);
|
|
1477
|
+
return { url: parsed.toString(), error: null };
|
|
1478
|
+
} catch {
|
|
1479
|
+
return { url: null, error: "Invalid URL" };
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// actions/workspaceLinkActions.ts
|
|
1484
|
+
import {
|
|
1485
|
+
parseWorkspaceIssueMentionHref
|
|
1486
|
+
} from "@tutti-os/workspace-issue-manager/core";
|
|
1487
|
+
var URL_LIKE_LINK_PATTERN = /^[a-zA-Z][a-zA-Z\d+.-]*:|^#/;
|
|
1488
|
+
function resolveWorkspaceFilePathCandidate({
|
|
1489
|
+
path,
|
|
1490
|
+
workspaceRoot,
|
|
1491
|
+
basePath
|
|
1492
|
+
}) {
|
|
1493
|
+
const rawPath = decodeWorkspaceLinkPath(path.trim());
|
|
1494
|
+
const root = normalizeWorkspaceFilePath(workspaceRoot?.trim() ?? "");
|
|
1495
|
+
if (!rawPath || !root || isUrlLikeWorkspaceFilePath(rawPath)) {
|
|
1496
|
+
return null;
|
|
1497
|
+
}
|
|
1498
|
+
const normalizedPath = normalizeWorkspaceFilePath(rawPath);
|
|
1499
|
+
const base = normalizeWorkspaceFilePath(basePath?.trim() || root);
|
|
1500
|
+
const resolvedPath = isAbsoluteLocalPath(normalizedPath) ? normalizedPath : normalizeWorkspaceFilePath(`${base}/${normalizedPath}`);
|
|
1501
|
+
if (!isInsideOrEqual(resolvedPath, root) && !isDirectAgentGeneratedImagePath(resolvedPath)) {
|
|
1502
|
+
return null;
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
path: resolvedPath,
|
|
1506
|
+
directoryPath: resolvedPath === root ? root : dirname(resolvedPath),
|
|
1507
|
+
workspaceRoot: root
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
function resolveWorkspaceFileLinkAction({
|
|
1511
|
+
path,
|
|
1512
|
+
workspaceRoot,
|
|
1513
|
+
basePath,
|
|
1514
|
+
source
|
|
1515
|
+
}) {
|
|
1516
|
+
const candidate = resolveWorkspaceFilePathCandidate({
|
|
1517
|
+
path,
|
|
1518
|
+
workspaceRoot,
|
|
1519
|
+
basePath
|
|
1520
|
+
});
|
|
1521
|
+
if (!candidate) {
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
return {
|
|
1525
|
+
type: "open-workspace-file",
|
|
1526
|
+
path: candidate.path,
|
|
1527
|
+
directoryPath: candidate.directoryPath,
|
|
1528
|
+
workspaceRoot: candidate.workspaceRoot,
|
|
1529
|
+
source
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
function resolveWorkspaceUrlLinkAction({
|
|
1533
|
+
url,
|
|
1534
|
+
source
|
|
1535
|
+
}) {
|
|
1536
|
+
const resolved = resolveWebsiteNavigationUrl(url);
|
|
1537
|
+
if (!resolved.url || resolved.error) {
|
|
1538
|
+
return null;
|
|
1539
|
+
}
|
|
1540
|
+
return {
|
|
1541
|
+
type: "open-url",
|
|
1542
|
+
url: resolved.url,
|
|
1543
|
+
source
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
function resolveWorkspaceMentionLinkAction({
|
|
1547
|
+
href,
|
|
1548
|
+
source
|
|
1549
|
+
}) {
|
|
1550
|
+
const rawHref = href.trim();
|
|
1551
|
+
if (!rawHref.toLowerCase().startsWith("mention://")) {
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
let url;
|
|
1555
|
+
try {
|
|
1556
|
+
url = new URL(rawHref);
|
|
1557
|
+
} catch {
|
|
1558
|
+
return null;
|
|
1559
|
+
}
|
|
1560
|
+
const workspaceId = url.searchParams.get("workspaceId")?.trim() || "";
|
|
1561
|
+
const targetId = url.searchParams.get("id")?.trim() || "";
|
|
1562
|
+
if (!workspaceId || !targetId) {
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
if (url.hostname === "agent-session") {
|
|
1566
|
+
const provider = url.searchParams.get("provider")?.trim() || null;
|
|
1567
|
+
return {
|
|
1568
|
+
type: "open-agent-session",
|
|
1569
|
+
workspaceId,
|
|
1570
|
+
agentSessionId: targetId,
|
|
1571
|
+
...provider ? { provider } : {},
|
|
1572
|
+
source
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
if (url.hostname === "workspace-issue") {
|
|
1576
|
+
const parsedIssueMention = parseWorkspaceIssueMentionHref(rawHref);
|
|
1577
|
+
if (!parsedIssueMention) {
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
return {
|
|
1581
|
+
type: "open-workspace-issue",
|
|
1582
|
+
workspaceId: parsedIssueMention.workspaceId,
|
|
1583
|
+
issueId: parsedIssueMention.issueId,
|
|
1584
|
+
...parsedIssueMention.mode ? { mode: parsedIssueMention.mode } : {},
|
|
1585
|
+
...parsedIssueMention.outputDir ? { outputDir: parsedIssueMention.outputDir } : {},
|
|
1586
|
+
...parsedIssueMention.runId ? { runId: parsedIssueMention.runId } : {},
|
|
1587
|
+
...parsedIssueMention.taskId ? { taskId: parsedIssueMention.taskId } : {},
|
|
1588
|
+
...parsedIssueMention.topicId ? { topicId: parsedIssueMention.topicId } : {},
|
|
1589
|
+
source
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
return null;
|
|
1593
|
+
}
|
|
1594
|
+
function resolveWorkspaceLinkAction({
|
|
1595
|
+
href,
|
|
1596
|
+
workspaceRoot,
|
|
1597
|
+
basePath,
|
|
1598
|
+
source
|
|
1599
|
+
}) {
|
|
1600
|
+
return resolveWorkspaceMentionLinkAction({ href, source }) ?? resolveWorkspaceFileLinkAction({
|
|
1601
|
+
path: href,
|
|
1602
|
+
workspaceRoot,
|
|
1603
|
+
basePath,
|
|
1604
|
+
source
|
|
1605
|
+
}) ?? resolveWorkspaceUrlLinkAction({ url: href, source });
|
|
1606
|
+
}
|
|
1607
|
+
function normalizeWorkspaceFilePath(path) {
|
|
1608
|
+
const normalizedPath = path.trim().replaceAll("\\", "/");
|
|
1609
|
+
const drive = /^[A-Za-z]:/.exec(normalizedPath)?.[0] ?? "";
|
|
1610
|
+
const startsWithSlash = normalizedPath.startsWith("/");
|
|
1611
|
+
const pathBody = drive ? normalizedPath.slice(drive.length) : startsWithSlash ? normalizedPath.slice(1) : normalizedPath;
|
|
1612
|
+
const parts = [];
|
|
1613
|
+
for (const part of pathBody.split("/")) {
|
|
1614
|
+
if (!part || part === ".") {
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
if (part === "..") {
|
|
1618
|
+
parts.pop();
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
parts.push(part);
|
|
1622
|
+
}
|
|
1623
|
+
if (drive) {
|
|
1624
|
+
return parts.length > 0 ? `${drive}/${parts.join("/")}` : `${drive}/`;
|
|
1625
|
+
}
|
|
1626
|
+
if (startsWithSlash) {
|
|
1627
|
+
return parts.length > 0 ? `/${parts.join("/")}` : "/";
|
|
1628
|
+
}
|
|
1629
|
+
return parts.join("/");
|
|
1630
|
+
}
|
|
1631
|
+
function isUrlLikeWorkspaceFilePath(path) {
|
|
1632
|
+
if (path.startsWith("#")) {
|
|
1633
|
+
return true;
|
|
1634
|
+
}
|
|
1635
|
+
if (isWindowsAbsolutePath(path.trim().replaceAll("\\", "/"))) {
|
|
1636
|
+
return false;
|
|
1637
|
+
}
|
|
1638
|
+
return URL_LIKE_LINK_PATTERN.test(path);
|
|
1639
|
+
}
|
|
1640
|
+
function isAbsoluteLocalPath(path) {
|
|
1641
|
+
return path.startsWith("/") || isWindowsAbsolutePath(path);
|
|
1642
|
+
}
|
|
1643
|
+
function isWindowsAbsolutePath(path) {
|
|
1644
|
+
return /^[A-Za-z]:\//.test(path);
|
|
1645
|
+
}
|
|
1646
|
+
function decodeWorkspaceLinkPath(path) {
|
|
1647
|
+
if (!path.includes("%")) {
|
|
1648
|
+
return path;
|
|
1649
|
+
}
|
|
1650
|
+
try {
|
|
1651
|
+
return decodeURI(path);
|
|
1652
|
+
} catch {
|
|
1653
|
+
return path;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
function dirname(path) {
|
|
1657
|
+
const index = path.lastIndexOf("/");
|
|
1658
|
+
if (index <= 0) {
|
|
1659
|
+
return "/";
|
|
1660
|
+
}
|
|
1661
|
+
return path.slice(0, index);
|
|
1662
|
+
}
|
|
1663
|
+
function isInsideOrEqual(path, root) {
|
|
1664
|
+
if (root === "/") {
|
|
1665
|
+
return path.startsWith("/");
|
|
1666
|
+
}
|
|
1667
|
+
const comparison = isWindowsAbsolutePath(root) || isWindowsAbsolutePath(path) ? { path: path.toLowerCase(), root: root.toLowerCase() } : { path, root };
|
|
1668
|
+
return comparison.path === comparison.root || comparison.path.startsWith(`${comparison.root}/`);
|
|
1669
|
+
}
|
|
1670
|
+
function isDirectAgentGeneratedImagePath(path) {
|
|
1671
|
+
if (!isAbsoluteLocalPath(path)) {
|
|
1672
|
+
return false;
|
|
1673
|
+
}
|
|
1674
|
+
const segments = path.split("/").filter(Boolean);
|
|
1675
|
+
const stateRootIndex = segments.findIndex(
|
|
1676
|
+
(segment) => segment === ".nextop" || segment === ".nextop-dev"
|
|
1677
|
+
);
|
|
1678
|
+
if (stateRootIndex < 0) {
|
|
1679
|
+
return false;
|
|
1680
|
+
}
|
|
1681
|
+
const statePath = segments.slice(stateRootIndex);
|
|
1682
|
+
if (statePath[1] !== "agent" || statePath[2] !== "runs" || !statePath.includes("generated_images")) {
|
|
1683
|
+
return false;
|
|
1684
|
+
}
|
|
1685
|
+
return /\.(?:png|jpe?g|gif|webp|bmp)$/i.test(path);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// shared/AgentMessageMarkdown.tsx
|
|
1689
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1690
|
+
var COLLAPSED_LINE_LIMIT = 8;
|
|
1691
|
+
var APPROX_CHARS_PER_LINE = 34;
|
|
1692
|
+
var DEFERRED_LONG_MARKDOWN_CHAR_THRESHOLD = 4096;
|
|
1693
|
+
var DEFERRED_LONG_MARKDOWN_FALLBACK_DELAY_MS = 80;
|
|
1694
|
+
var DEFERRED_LONG_MARKDOWN_IDLE_TIMEOUT_MS = 700;
|
|
1695
|
+
var PLAIN_SESSION_MENTION_AGENT_LABELS = [
|
|
1696
|
+
"Claude Code",
|
|
1697
|
+
"Nexight",
|
|
1698
|
+
"Codex"
|
|
1699
|
+
];
|
|
1700
|
+
var MARKDOWN_SANITIZE_SCHEMA = {
|
|
1701
|
+
...defaultSchema,
|
|
1702
|
+
protocols: {
|
|
1703
|
+
...defaultSchema.protocols,
|
|
1704
|
+
href: [...defaultSchema.protocols?.href ?? [], "mention"]
|
|
1705
|
+
}
|
|
1706
|
+
};
|
|
1707
|
+
var EMPTY_WORKSPACE_APP_ICONS = [];
|
|
1708
|
+
var MarkdownLinkContext = createContext3(false);
|
|
1709
|
+
function AgentMessageMarkdown({
|
|
1710
|
+
content,
|
|
1711
|
+
onLinkClick,
|
|
1712
|
+
onLinkAction,
|
|
1713
|
+
workspaceLinkContext = null,
|
|
1714
|
+
workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS,
|
|
1715
|
+
collapsible = false,
|
|
1716
|
+
expandLabel,
|
|
1717
|
+
className,
|
|
1718
|
+
inline = false,
|
|
1719
|
+
normalizePlainIssueMentionTitle = false,
|
|
1720
|
+
deferLongContentRender = false,
|
|
1721
|
+
enableImageZoom = false
|
|
1722
|
+
}) {
|
|
1723
|
+
"use memo";
|
|
1724
|
+
const { t } = useTranslation();
|
|
1725
|
+
const workspaceRoot = workspaceLinkContext?.workspaceRoot ?? null;
|
|
1726
|
+
const basePath = workspaceLinkContext?.basePath ?? null;
|
|
1727
|
+
const workspaceLinkSource = workspaceLinkContext?.source ?? null;
|
|
1728
|
+
const [isExpanded, setIsExpanded] = useState2(false);
|
|
1729
|
+
const resolvedExpandLabel = expandLabel ?? t("agentHost.workspaceAgentMessageExpand");
|
|
1730
|
+
const shouldCollapse = collapsible && isLikelyLongerThanLineLimit(content);
|
|
1731
|
+
const isCollapsed = shouldCollapse && !isExpanded;
|
|
1732
|
+
const ContainerTag = inline ? "span" : "div";
|
|
1733
|
+
const contentSignature = useMemo2(
|
|
1734
|
+
() => hashMarkdownProfilerContent(content),
|
|
1735
|
+
[content]
|
|
1736
|
+
);
|
|
1737
|
+
const normalizedContent = useMemo2(
|
|
1738
|
+
() => linkBareLocalAbsolutePaths(
|
|
1739
|
+
normalizeMentionMarkdownLinks(
|
|
1740
|
+
normalizePlainIssueMentionTitle ? normalizePlainIssueMentionTitleContent(
|
|
1741
|
+
normalizePlainSessionMentionTitle(content)
|
|
1742
|
+
) : normalizePlainSessionMentionTitle(content)
|
|
1743
|
+
)
|
|
1744
|
+
),
|
|
1745
|
+
[content, normalizePlainIssueMentionTitle]
|
|
1746
|
+
);
|
|
1747
|
+
const isMentionOnly = isMentionOnlyMarkdownContent(normalizedContent);
|
|
1748
|
+
const shouldDeferMarkdownRender = deferLongContentRender && !inline && content.length >= DEFERRED_LONG_MARKDOWN_CHAR_THRESHOLD && !isExpanded;
|
|
1749
|
+
const markdownRenderReady = useDeferredMarkdownRenderReady(
|
|
1750
|
+
contentSignature,
|
|
1751
|
+
shouldDeferMarkdownRender
|
|
1752
|
+
);
|
|
1753
|
+
const handleLinkClick = useCallback3(
|
|
1754
|
+
(href) => {
|
|
1755
|
+
if (workspaceLinkSource && onLinkAction) {
|
|
1756
|
+
const action = resolveWorkspaceLinkAction({
|
|
1757
|
+
href,
|
|
1758
|
+
workspaceRoot,
|
|
1759
|
+
basePath,
|
|
1760
|
+
source: workspaceLinkSource
|
|
1761
|
+
});
|
|
1762
|
+
if (action) {
|
|
1763
|
+
onLinkAction(action);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
onLinkClick?.(href);
|
|
1768
|
+
},
|
|
1769
|
+
[basePath, onLinkAction, onLinkClick, workspaceLinkSource, workspaceRoot]
|
|
1770
|
+
);
|
|
1771
|
+
const handleAnchorClickCapture = useCallback3(
|
|
1772
|
+
(event) => {
|
|
1773
|
+
const href = resolveMarkdownAnchorHref(event.target);
|
|
1774
|
+
if (!href) {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
event.preventDefault();
|
|
1778
|
+
event.stopPropagation();
|
|
1779
|
+
handleLinkClick(href);
|
|
1780
|
+
},
|
|
1781
|
+
[handleLinkClick]
|
|
1782
|
+
);
|
|
1783
|
+
const markdownComponents = useMemo2(
|
|
1784
|
+
() => ({
|
|
1785
|
+
a: (props) => /* @__PURE__ */ jsx6(
|
|
1786
|
+
MarkdownLink,
|
|
1787
|
+
{
|
|
1788
|
+
...props,
|
|
1789
|
+
onLinkClick: handleLinkClick,
|
|
1790
|
+
workspaceAppIcons
|
|
1791
|
+
}
|
|
1792
|
+
),
|
|
1793
|
+
code: (props) => /* @__PURE__ */ jsx6(MarkdownCode, { ...props, onLinkClick: handleLinkClick }),
|
|
1794
|
+
img: (props) => /* @__PURE__ */ jsx6(MarkdownImage, { ...props, enableZoom: enableImageZoom }),
|
|
1795
|
+
p: (props) => /* @__PURE__ */ jsx6(MarkdownParagraph, { ...props, inline }),
|
|
1796
|
+
ul: MarkdownUnorderedList,
|
|
1797
|
+
ol: MarkdownOrderedList,
|
|
1798
|
+
li: MarkdownListItem
|
|
1799
|
+
}),
|
|
1800
|
+
[enableImageZoom, handleLinkClick, inline, workspaceAppIcons]
|
|
1801
|
+
);
|
|
1802
|
+
return /* @__PURE__ */ jsxs4(
|
|
1803
|
+
ContainerTag,
|
|
1804
|
+
{
|
|
1805
|
+
className: "flex w-full min-w-0 flex-col items-start gap-1",
|
|
1806
|
+
"data-workspace-agent-markdown-shell": "true",
|
|
1807
|
+
children: [
|
|
1808
|
+
/* @__PURE__ */ jsx6(
|
|
1809
|
+
ContainerTag,
|
|
1810
|
+
{
|
|
1811
|
+
className: cn(
|
|
1812
|
+
"relative w-full min-w-0 overflow-x-auto text-[13px] leading-[1.5] text-[var(--text-primary)] [overflow-wrap:anywhere]",
|
|
1813
|
+
"[&_>table:first-child]:mt-0 [&_p]:mb-2 [&_pre]:mb-2 [&_blockquote]:mb-2",
|
|
1814
|
+
"[&_hr]:my-4 [&_hr]:h-0 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-t-[color-mix(in_srgb,var(--text-primary)_14%,transparent)]",
|
|
1815
|
+
"[&_ul]:my-2 [&_ul]:max-w-full [&_ul]:rounded-[8px] [&_ul]:border [&_ul]:border-[var(--line-2)] [&_ul]:bg-[var(--background-panel)] [&_ul]:px-4 [&_ul]:py-2",
|
|
1816
|
+
"[&_ol]:my-2 [&_ol]:max-w-full [&_ol]:rounded-[8px] [&_ol]:border [&_ol]:border-[var(--line-2)] [&_ol]:bg-[var(--background-panel)] [&_ol]:px-4 [&_ol]:py-2",
|
|
1817
|
+
"[&_li>ul]:mt-1.5 [&_li>ul]:mb-0.5 [&_li>ul]:border-0 [&_li>ul]:px-0 [&_li>ul]:py-1",
|
|
1818
|
+
"[&_li>ol]:mt-1.5 [&_li>ol]:mb-0.5 [&_li>ol]:border-0 [&_li>ol]:px-0 [&_li>ol]:py-1",
|
|
1819
|
+
"[&_table]:my-2 [&_table]:w-max [&_table]:min-w-full [&_table]:max-w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:overflow-hidden [&_table]:rounded-[8px] [&_table]:border [&_table]:border-[var(--line-2)] [&_table]:text-[13px] [&_table]:leading-[1.45]",
|
|
1820
|
+
"[&_th]:max-w-[280px] [&_th]:border-r [&_th]:border-b [&_th]:border-[var(--line-2)] [&_th]:px-2 [&_th]:py-1.5 [&_th]:align-top [&_th]:font-semibold [&_th]:text-[var(--text-primary)] [&_th]:[overflow-wrap:anywhere] [&_th]:bg-[color-mix(in_srgb,var(--background-panel)_94%,var(--text-primary))]",
|
|
1821
|
+
"[&_td]:max-w-[280px] [&_td]:border-r [&_td]:border-b [&_td]:border-[var(--line-2)] [&_td]:px-2 [&_td]:py-1.5 [&_td]:align-top [&_td]:[overflow-wrap:anywhere]",
|
|
1822
|
+
"[&_tr:last-child_th]:border-b-0 [&_tr:last-child_td]:border-b-0 [&_th:last-child]:border-r-0 [&_td:last-child]:border-r-0",
|
|
1823
|
+
"[&_a]:cursor-pointer [&_a]:font-semibold [&_a]:text-[var(--tutti-purple)] [&_a]:no-underline [&_a:hover]:underline [&_a:focus-visible]:underline",
|
|
1824
|
+
"[&_strong]:font-semibold",
|
|
1825
|
+
"[&_code]:inline [&_code]:rounded-[2px] [&_code]:bg-[var(--transparency-block)] [&_code]:px-1 [&_code]:py-[1px] [&_code]:font-[var(--tsh-font-mono)] [&_code]:text-[11px] [&_code]:leading-[1.35] [&_code]:text-[var(--text-primary)] [&_code]:[box-decoration-break:clone] [&_code]:[-webkit-box-decoration-break:clone] [&_code]:[overflow-wrap:anywhere] [&_code]:[word-break:break-word]",
|
|
1826
|
+
"[&_pre]:box-border [&_pre]:overflow-auto [&_pre]:rounded-[6px] [&_pre]:bg-[var(--transparency-block)] [&_pre]:px-2.5 [&_pre]:py-2",
|
|
1827
|
+
"[&_pre_code]:inline [&_pre_code]:h-auto [&_pre_code]:items-normal [&_pre_code]:rounded-none [&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-[inherit] [&_pre_code]:leading-[inherit] [&_pre_code]:[white-space:pre-wrap] [&_pre_code]:[overflow-wrap:anywhere] [&_pre_code]:[word-break:break-word]",
|
|
1828
|
+
"[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
|
1829
|
+
inline && "inline min-w-0 overflow-hidden align-baseline [&_p]:inline [&_p]:m-0",
|
|
1830
|
+
shouldCollapse && "overflow-hidden transition-[max-height] duration-220 ease-out",
|
|
1831
|
+
isCollapsed && "max-h-[calc(13px*1.5*8)] overflow-hidden [mask-image:linear-gradient(180deg,black_0%,black_calc(100%_-_36px),transparent_100%)] [-webkit-mask-image:linear-gradient(180deg,black_0%,black_calc(100%_-_36px),transparent_100%)] [&_pre]:overflow-hidden",
|
|
1832
|
+
shouldCollapse && !isCollapsed && "max-h-[72rem]",
|
|
1833
|
+
className
|
|
1834
|
+
),
|
|
1835
|
+
"data-workspace-agent-markdown": "true",
|
|
1836
|
+
"data-agent-mention-only": isMentionOnly ? "true" : void 0,
|
|
1837
|
+
"data-collapsed": isCollapsed ? "true" : "false",
|
|
1838
|
+
onClickCapture: handleAnchorClickCapture,
|
|
1839
|
+
children: markdownRenderReady ? /* @__PURE__ */ jsx6(
|
|
1840
|
+
ReactMarkdown,
|
|
1841
|
+
{
|
|
1842
|
+
remarkPlugins: [remarkGfm],
|
|
1843
|
+
rehypePlugins: [[rehypeSanitize, MARKDOWN_SANITIZE_SCHEMA]],
|
|
1844
|
+
urlTransform: markdownUrlTransform,
|
|
1845
|
+
components: markdownComponents,
|
|
1846
|
+
children: normalizedContent
|
|
1847
|
+
}
|
|
1848
|
+
) : /* @__PURE__ */ jsx6(
|
|
1849
|
+
"div",
|
|
1850
|
+
{
|
|
1851
|
+
className: "whitespace-pre-wrap [overflow-wrap:anywhere]",
|
|
1852
|
+
"data-workspace-agent-markdown-deferred": "true",
|
|
1853
|
+
children: normalizedContent
|
|
1854
|
+
}
|
|
1855
|
+
)
|
|
1856
|
+
}
|
|
1857
|
+
),
|
|
1858
|
+
shouldCollapse && !isExpanded ? /* @__PURE__ */ jsx6(
|
|
1859
|
+
"button",
|
|
1860
|
+
{
|
|
1861
|
+
type: "button",
|
|
1862
|
+
className: "m-0 border-0 bg-transparent p-0 text-[11px] leading-[1.4] font-semibold text-[var(--tutti-purple)] hover:underline focus-visible:underline focus-visible:outline-none",
|
|
1863
|
+
onClick: () => setIsExpanded(true),
|
|
1864
|
+
children: resolvedExpandLabel
|
|
1865
|
+
}
|
|
1866
|
+
) : null
|
|
1867
|
+
]
|
|
1868
|
+
}
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
function resolveMarkdownAnchorHref(target) {
|
|
1872
|
+
if (!(target instanceof Element)) {
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
const link = target.closest("[data-agent-link-href],a[href]");
|
|
1876
|
+
if (!(link instanceof HTMLElement)) {
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
const dataHref = link.dataset.agentLinkHref?.trim();
|
|
1880
|
+
if (dataHref) {
|
|
1881
|
+
return dataHref;
|
|
1882
|
+
}
|
|
1883
|
+
if (link instanceof HTMLAnchorElement) {
|
|
1884
|
+
return link.getAttribute("href")?.trim() || null;
|
|
1885
|
+
}
|
|
1886
|
+
return null;
|
|
1887
|
+
}
|
|
1888
|
+
function activateMarkdownLink(event, href, onLinkClick) {
|
|
1889
|
+
const target = href.trim();
|
|
1890
|
+
if (!target) {
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
event.preventDefault();
|
|
1894
|
+
event.stopPropagation();
|
|
1895
|
+
onLinkClick?.(target);
|
|
1896
|
+
}
|
|
1897
|
+
function activateMarkdownLinkFromKey(event, href, onLinkClick) {
|
|
1898
|
+
if (event.key !== "Enter" && event.key !== " ") {
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
activateMarkdownLink(event, href, onLinkClick);
|
|
1902
|
+
}
|
|
1903
|
+
function activateMarkdownLinkFromPointer(event, href, onLinkClick) {
|
|
1904
|
+
if (event.button !== 0) {
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
activateMarkdownLink(event, href, onLinkClick);
|
|
1908
|
+
}
|
|
1909
|
+
function useDeferredMarkdownRenderReady(contentSignature, shouldDefer) {
|
|
1910
|
+
const [readySignature, setReadySignature] = useState2(
|
|
1911
|
+
shouldDefer ? null : contentSignature
|
|
1912
|
+
);
|
|
1913
|
+
const renderReady = !shouldDefer || readySignature === contentSignature;
|
|
1914
|
+
useEffect3(() => {
|
|
1915
|
+
if (!shouldDefer) {
|
|
1916
|
+
setReadySignature(contentSignature);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
let canceled = false;
|
|
1920
|
+
let timeoutId = null;
|
|
1921
|
+
let idleCallbackId = null;
|
|
1922
|
+
const markReady = () => {
|
|
1923
|
+
if (canceled) {
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
startTransition(() => {
|
|
1927
|
+
setReadySignature(contentSignature);
|
|
1928
|
+
});
|
|
1929
|
+
};
|
|
1930
|
+
if ("requestIdleCallback" in window) {
|
|
1931
|
+
idleCallbackId = window.requestIdleCallback(markReady, {
|
|
1932
|
+
timeout: DEFERRED_LONG_MARKDOWN_IDLE_TIMEOUT_MS
|
|
1933
|
+
});
|
|
1934
|
+
} else {
|
|
1935
|
+
timeoutId = setTimeout(
|
|
1936
|
+
markReady,
|
|
1937
|
+
DEFERRED_LONG_MARKDOWN_FALLBACK_DELAY_MS
|
|
1938
|
+
);
|
|
1939
|
+
}
|
|
1940
|
+
return () => {
|
|
1941
|
+
canceled = true;
|
|
1942
|
+
if (idleCallbackId !== null) {
|
|
1943
|
+
window.cancelIdleCallback(idleCallbackId);
|
|
1944
|
+
}
|
|
1945
|
+
if (timeoutId !== null) {
|
|
1946
|
+
clearTimeout(timeoutId);
|
|
1947
|
+
}
|
|
1948
|
+
};
|
|
1949
|
+
}, [contentSignature, shouldDefer]);
|
|
1950
|
+
return renderReady;
|
|
1951
|
+
}
|
|
1952
|
+
function hashMarkdownProfilerContent(content) {
|
|
1953
|
+
let hash = 0;
|
|
1954
|
+
for (let index = 0; index < content.length; index += 1) {
|
|
1955
|
+
hash = hash * 31 + content.charCodeAt(index) | 0;
|
|
1956
|
+
}
|
|
1957
|
+
return `${content.length}:${Math.abs(hash)}`;
|
|
1958
|
+
}
|
|
1959
|
+
function isLikelyLongerThanLineLimit(content) {
|
|
1960
|
+
const normalizedLines = content.replace(/\r\n?/g, "\n").split("\n");
|
|
1961
|
+
if (normalizedLines.length > COLLAPSED_LINE_LIMIT) {
|
|
1962
|
+
return true;
|
|
1963
|
+
}
|
|
1964
|
+
const estimatedLineCount = normalizedLines.reduce((total, line) => {
|
|
1965
|
+
const trimmed = line.trim();
|
|
1966
|
+
const blockSpacing = /^(#{1,6}\s|\s*[-*+]\s|\s*\d+\.\s|>)/.test(trimmed) ? 1 : 0;
|
|
1967
|
+
return total + Math.max(1, Math.ceil(trimmed.length / APPROX_CHARS_PER_LINE)) + blockSpacing;
|
|
1968
|
+
}, 0);
|
|
1969
|
+
return estimatedLineCount > COLLAPSED_LINE_LIMIT;
|
|
1970
|
+
}
|
|
1971
|
+
function MarkdownLink({
|
|
1972
|
+
node: _node,
|
|
1973
|
+
onClick: _onClick,
|
|
1974
|
+
onLinkClick,
|
|
1975
|
+
workspaceAppIcons,
|
|
1976
|
+
href,
|
|
1977
|
+
...props
|
|
1978
|
+
}) {
|
|
1979
|
+
"use memo";
|
|
1980
|
+
const { t } = useTranslation();
|
|
1981
|
+
const targetHref = href?.trim() ?? "";
|
|
1982
|
+
const mention = targetHref ? parseMentionLink(
|
|
1983
|
+
targetHref,
|
|
1984
|
+
textFromReactNode(props.children),
|
|
1985
|
+
workspaceAppIcons ?? [],
|
|
1986
|
+
t("agentHost.agentGui.workspaceAppFactoryMentionFallback")
|
|
1987
|
+
) : null;
|
|
1988
|
+
if (mention) {
|
|
1989
|
+
return /* @__PURE__ */ jsx6(
|
|
1990
|
+
MentionLink,
|
|
1991
|
+
{
|
|
1992
|
+
...props,
|
|
1993
|
+
href: targetHref,
|
|
1994
|
+
mention,
|
|
1995
|
+
onLinkClick
|
|
1996
|
+
}
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
const fileMention = targetHref ? parseWorkspaceFileMentionLink(
|
|
2000
|
+
targetHref,
|
|
2001
|
+
textFromReactNode(props.children)
|
|
2002
|
+
) : null;
|
|
2003
|
+
if (fileMention) {
|
|
2004
|
+
return /* @__PURE__ */ jsx6(
|
|
2005
|
+
WorkspaceFileMentionLink,
|
|
2006
|
+
{
|
|
2007
|
+
...props,
|
|
2008
|
+
href: targetHref,
|
|
2009
|
+
mention: fileMention,
|
|
2010
|
+
onLinkClick
|
|
2011
|
+
}
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
return /* @__PURE__ */ jsx6(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx6(
|
|
2015
|
+
"a",
|
|
2016
|
+
{
|
|
2017
|
+
...props,
|
|
2018
|
+
"data-agent-link-href": targetHref,
|
|
2019
|
+
role: "link",
|
|
2020
|
+
tabIndex: 0,
|
|
2021
|
+
onClick: (event) => {
|
|
2022
|
+
activateMarkdownLink(event, targetHref, onLinkClick);
|
|
2023
|
+
},
|
|
2024
|
+
onPointerDown: (event) => {
|
|
2025
|
+
activateMarkdownLinkFromPointer(event, targetHref, onLinkClick);
|
|
2026
|
+
},
|
|
2027
|
+
onKeyDown: (event) => {
|
|
2028
|
+
activateMarkdownLinkFromKey(event, targetHref, onLinkClick);
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
) });
|
|
2032
|
+
}
|
|
2033
|
+
function parseWorkspaceFileMentionTarget(href) {
|
|
2034
|
+
const target = href.trim();
|
|
2035
|
+
if (!isLocalAbsolutePath(target)) {
|
|
2036
|
+
return null;
|
|
2037
|
+
}
|
|
2038
|
+
let url;
|
|
2039
|
+
try {
|
|
2040
|
+
url = new URL(target, "https://tsh.local");
|
|
2041
|
+
} catch {
|
|
2042
|
+
return null;
|
|
2043
|
+
}
|
|
2044
|
+
const explicitKindValue = url.searchParams.get("kind") ?? url.searchParams.get("refType") ?? url.searchParams.get("entryKind") ?? "";
|
|
2045
|
+
const normalizedKind = explicitKindValue.trim().toLowerCase();
|
|
2046
|
+
const explicitKind = normalizedKind === "folder" || normalizedKind === "directory" ? "directory" : normalizedKind === "file" ? "file" : null;
|
|
2047
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
2048
|
+
if (!path || path === "/") {
|
|
2049
|
+
return null;
|
|
2050
|
+
}
|
|
2051
|
+
return {
|
|
2052
|
+
path,
|
|
2053
|
+
explicitKind: explicitKind ?? (url.pathname.endsWith("/") ? "directory" : null)
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function resolveWorkspaceFileMentionEntryKind(path, label, explicitKind) {
|
|
2057
|
+
if (explicitKind) {
|
|
2058
|
+
return explicitKind;
|
|
2059
|
+
}
|
|
2060
|
+
if (resolveWorkspaceFileExtension(path)) {
|
|
2061
|
+
return "file";
|
|
2062
|
+
}
|
|
2063
|
+
const basename = basenameWorkspacePath(path);
|
|
2064
|
+
return basename === label ? "directory" : "file";
|
|
2065
|
+
}
|
|
2066
|
+
function parseWorkspaceFileMentionLink(href, rawLabel) {
|
|
2067
|
+
const label = rawLabel.trim();
|
|
2068
|
+
const target = parseWorkspaceFileMentionTarget(href);
|
|
2069
|
+
if (!target || !label.startsWith("@")) {
|
|
2070
|
+
return null;
|
|
2071
|
+
}
|
|
2072
|
+
const fileLabel = label.replace(/^@+/, "").trim();
|
|
2073
|
+
if (!fileLabel) {
|
|
2074
|
+
return null;
|
|
2075
|
+
}
|
|
2076
|
+
const entryKind = resolveWorkspaceFileMentionEntryKind(
|
|
2077
|
+
target.path,
|
|
2078
|
+
fileLabel,
|
|
2079
|
+
target.explicitKind
|
|
2080
|
+
);
|
|
2081
|
+
return {
|
|
2082
|
+
label: fileLabel,
|
|
2083
|
+
href: target.path,
|
|
2084
|
+
entryKind,
|
|
2085
|
+
visualKind: resolveAgentWorkspaceFileVisualKind(target.path, {
|
|
2086
|
+
refType: entryKind === "directory" ? "folder" : "file"
|
|
2087
|
+
})
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
function WorkspaceFileMentionLink({
|
|
2091
|
+
onClick: _onClick,
|
|
2092
|
+
onLinkClick,
|
|
2093
|
+
href: _href,
|
|
2094
|
+
mention,
|
|
2095
|
+
...props
|
|
2096
|
+
}) {
|
|
2097
|
+
"use memo";
|
|
2098
|
+
return /* @__PURE__ */ jsxs4(
|
|
2099
|
+
"a",
|
|
2100
|
+
{
|
|
2101
|
+
...props,
|
|
2102
|
+
className: cn(
|
|
2103
|
+
"tsh-workspace-file-link tsh-agent-object-token tsh-agent-object-token--file",
|
|
2104
|
+
props.className
|
|
2105
|
+
),
|
|
2106
|
+
"data-agent-file-mention": "true",
|
|
2107
|
+
"data-agent-mention-kind": "file",
|
|
2108
|
+
"data-agent-file-entry-kind": mention.entryKind,
|
|
2109
|
+
"data-agent-file-visual-kind": mention.visualKind,
|
|
2110
|
+
"data-agent-link-href": mention.href,
|
|
2111
|
+
"data-agent-mention-href": mention.href,
|
|
2112
|
+
"aria-label": mention.label,
|
|
2113
|
+
role: "link",
|
|
2114
|
+
tabIndex: 0,
|
|
2115
|
+
onClick: (event) => {
|
|
2116
|
+
activateMarkdownLink(event, mention.href, onLinkClick);
|
|
2117
|
+
},
|
|
2118
|
+
onPointerDown: (event) => {
|
|
2119
|
+
activateMarkdownLinkFromPointer(event, mention.href, onLinkClick);
|
|
2120
|
+
},
|
|
2121
|
+
onKeyDown: (event) => {
|
|
2122
|
+
activateMarkdownLinkFromKey(event, mention.href, onLinkClick);
|
|
2123
|
+
},
|
|
2124
|
+
children: [
|
|
2125
|
+
/* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__icon", "aria-hidden": "true" }),
|
|
2126
|
+
/* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__main", children: mention.label })
|
|
2127
|
+
]
|
|
2128
|
+
}
|
|
2129
|
+
);
|
|
2130
|
+
}
|
|
2131
|
+
function MentionLink({
|
|
2132
|
+
onClick: _onClick,
|
|
2133
|
+
onLinkClick,
|
|
2134
|
+
href,
|
|
2135
|
+
mention,
|
|
2136
|
+
...props
|
|
2137
|
+
}) {
|
|
2138
|
+
"use memo";
|
|
2139
|
+
return /* @__PURE__ */ jsxs4(
|
|
2140
|
+
"a",
|
|
2141
|
+
{
|
|
2142
|
+
...props,
|
|
2143
|
+
className: cn(
|
|
2144
|
+
"tsh-agent-object-token tsh-agent-object-token--entity",
|
|
2145
|
+
props.className
|
|
2146
|
+
),
|
|
2147
|
+
"data-agent-file-mention": "true",
|
|
2148
|
+
"data-agent-link-href": href,
|
|
2149
|
+
"data-agent-mention-icon-url": mention.iconUrl,
|
|
2150
|
+
"data-agent-mention-href": href,
|
|
2151
|
+
"data-agent-mention-kind": mention.kind,
|
|
2152
|
+
"aria-label": mention.label,
|
|
2153
|
+
role: "link",
|
|
2154
|
+
tabIndex: 0,
|
|
2155
|
+
onClick: (event) => {
|
|
2156
|
+
activateMarkdownLink(event, href, onLinkClick);
|
|
2157
|
+
},
|
|
2158
|
+
onPointerDown: (event) => {
|
|
2159
|
+
activateMarkdownLinkFromPointer(event, href, onLinkClick);
|
|
2160
|
+
},
|
|
2161
|
+
onKeyDown: (event) => {
|
|
2162
|
+
activateMarkdownLinkFromKey(event, href, onLinkClick);
|
|
2163
|
+
},
|
|
2164
|
+
children: [
|
|
2165
|
+
mention.kind === "workspace-app" ? /* @__PURE__ */ jsx6(
|
|
2166
|
+
"span",
|
|
2167
|
+
{
|
|
2168
|
+
className: "grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px] bg-block",
|
|
2169
|
+
"aria-hidden": "true",
|
|
2170
|
+
"data-agent-mention-app-icon": "true",
|
|
2171
|
+
"data-workspace-app-icon": "true",
|
|
2172
|
+
children: mention.iconUrl ? /* @__PURE__ */ jsx6(
|
|
2173
|
+
"img",
|
|
2174
|
+
{
|
|
2175
|
+
src: mention.iconUrl,
|
|
2176
|
+
alt: "",
|
|
2177
|
+
className: "h-full w-full object-cover",
|
|
2178
|
+
decoding: "async",
|
|
2179
|
+
loading: "lazy",
|
|
2180
|
+
draggable: false
|
|
2181
|
+
}
|
|
2182
|
+
) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__kind-icon h-4 w-4" })
|
|
2183
|
+
}
|
|
2184
|
+
) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__kind", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(
|
|
2185
|
+
"span",
|
|
2186
|
+
{
|
|
2187
|
+
className: "tsh-agent-object-token__kind-icon",
|
|
2188
|
+
"aria-hidden": "true"
|
|
2189
|
+
}
|
|
2190
|
+
) }),
|
|
2191
|
+
mention.kind === "session" ? /* @__PURE__ */ jsxs4("span", { className: "tsh-agent-object-token__main", children: [
|
|
2192
|
+
/* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__participant", children: mention.participant }),
|
|
2193
|
+
mention.summary ? /* @__PURE__ */ jsxs4("span", { className: "tsh-agent-object-token__summary", children: [
|
|
2194
|
+
" ",
|
|
2195
|
+
mention.summary
|
|
2196
|
+
] }) : null
|
|
2197
|
+
] }) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__main", children: mention.label })
|
|
2198
|
+
]
|
|
2199
|
+
}
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
function MarkdownCode({
|
|
2203
|
+
node: _node,
|
|
2204
|
+
children,
|
|
2205
|
+
className,
|
|
2206
|
+
onLinkClick,
|
|
2207
|
+
...props
|
|
2208
|
+
}) {
|
|
2209
|
+
"use memo";
|
|
2210
|
+
const text = textFromReactNode(children).trim();
|
|
2211
|
+
if (!className && onLinkClick && (isLocalAbsolutePath(text) || isHttpUrl(text))) {
|
|
2212
|
+
return /* @__PURE__ */ jsx6("code", { ...props, className, children: /* @__PURE__ */ jsx6(PathLink, { href: text, onLinkClick, children }) });
|
|
2213
|
+
}
|
|
2214
|
+
return /* @__PURE__ */ jsx6("code", { ...props, className, children });
|
|
2215
|
+
}
|
|
2216
|
+
var cachedMarkdownImages = /* @__PURE__ */ new Map();
|
|
2217
|
+
var CACHED_MARKDOWN_IMAGE_REVOKE_DELAY_MS = 250;
|
|
2218
|
+
function MarkdownImage({
|
|
2219
|
+
node: _node,
|
|
2220
|
+
src,
|
|
2221
|
+
alt,
|
|
2222
|
+
className,
|
|
2223
|
+
enableZoom = false,
|
|
2224
|
+
...props
|
|
2225
|
+
}) {
|
|
2226
|
+
"use memo";
|
|
2227
|
+
const { t } = useTranslation();
|
|
2228
|
+
const isInsideLink = useContext3(MarkdownLinkContext);
|
|
2229
|
+
const agentHostApi = useOptionalAgentHostApi() ?? getOptionalAgentHostApi();
|
|
2230
|
+
const workspacePath = typeof src === "string" && isLocalAbsolutePath(src) ? src.trim() : null;
|
|
2231
|
+
const readWorkspaceImage = workspacePath ? agentHostApi?.workspace?.readFile : void 0;
|
|
2232
|
+
const canReadWorkspaceImage = Boolean(workspacePath && readWorkspaceImage);
|
|
2233
|
+
const shouldEnableZoom = enableZoom && !isInsideLink;
|
|
2234
|
+
const resolvedSrc = typeof src === "string" ? resolveRenderableMarkdownImageSrc(src) : src;
|
|
2235
|
+
const [state, setState] = useState2(
|
|
2236
|
+
() => canReadWorkspaceImage && workspacePath ? peekCachedMarkdownImageState(workspacePath) ?? { status: "loading" } : null
|
|
2237
|
+
);
|
|
2238
|
+
useEffect3(() => {
|
|
2239
|
+
if (!workspacePath || !readWorkspaceImage) {
|
|
2240
|
+
setState(null);
|
|
2241
|
+
return;
|
|
2242
|
+
}
|
|
2243
|
+
const resolvedWorkspacePath = workspacePath;
|
|
2244
|
+
const resolvedReadWorkspaceImage = readWorkspaceImage;
|
|
2245
|
+
const cachedSrc = retainCachedMarkdownImage(resolvedWorkspacePath);
|
|
2246
|
+
if (cachedSrc) {
|
|
2247
|
+
setState({ status: "ready", src: cachedSrc });
|
|
2248
|
+
return () => {
|
|
2249
|
+
releaseCachedMarkdownImage(resolvedWorkspacePath, cachedSrc);
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2252
|
+
const resolvedMimeType = resolveWorkspaceImageMimeType(
|
|
2253
|
+
resolvedWorkspacePath
|
|
2254
|
+
);
|
|
2255
|
+
if (!resolvedMimeType) {
|
|
2256
|
+
setState({
|
|
2257
|
+
status: "error",
|
|
2258
|
+
reason: "unsupported"
|
|
2259
|
+
});
|
|
2260
|
+
return;
|
|
2261
|
+
}
|
|
2262
|
+
const imageMimeType = resolvedMimeType;
|
|
2263
|
+
let canceled = false;
|
|
2264
|
+
let objectUrl = null;
|
|
2265
|
+
setState({ status: "loading" });
|
|
2266
|
+
async function loadWorkspaceImage() {
|
|
2267
|
+
try {
|
|
2268
|
+
const result = await resolvedReadWorkspaceImage({
|
|
2269
|
+
path: resolvedWorkspacePath
|
|
2270
|
+
});
|
|
2271
|
+
if (canceled) {
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
const bytes = result.bytes instanceof Uint8Array ? result.bytes : new Uint8Array(result.bytes);
|
|
2275
|
+
const arrayBuffer = bytes.buffer.slice(
|
|
2276
|
+
bytes.byteOffset,
|
|
2277
|
+
bytes.byteOffset + bytes.byteLength
|
|
2278
|
+
);
|
|
2279
|
+
objectUrl = cacheMarkdownImage(
|
|
2280
|
+
resolvedWorkspacePath,
|
|
2281
|
+
new Blob([arrayBuffer], { type: imageMimeType })
|
|
2282
|
+
);
|
|
2283
|
+
setState({ status: "ready", src: objectUrl });
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
if (!canceled) {
|
|
2286
|
+
setState({
|
|
2287
|
+
status: "error",
|
|
2288
|
+
reason: "read-failed",
|
|
2289
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
void loadWorkspaceImage();
|
|
2295
|
+
return () => {
|
|
2296
|
+
canceled = true;
|
|
2297
|
+
if (objectUrl) {
|
|
2298
|
+
releaseCachedMarkdownImage(resolvedWorkspacePath, objectUrl);
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
}, [canReadWorkspaceImage, workspacePath]);
|
|
2302
|
+
if (!workspacePath || !readWorkspaceImage) {
|
|
2303
|
+
if (!shouldEnableZoom) {
|
|
2304
|
+
return /* @__PURE__ */ jsx6("img", { ...props, src: resolvedSrc, alt, className });
|
|
2305
|
+
}
|
|
2306
|
+
return /* @__PURE__ */ jsx6(
|
|
2307
|
+
ZoomableImage,
|
|
2308
|
+
{
|
|
2309
|
+
...props,
|
|
2310
|
+
src: resolvedSrc,
|
|
2311
|
+
alt,
|
|
2312
|
+
className,
|
|
2313
|
+
wrapElement: "span"
|
|
2314
|
+
}
|
|
2315
|
+
);
|
|
2316
|
+
}
|
|
2317
|
+
if (state?.status === "ready") {
|
|
2318
|
+
if (!shouldEnableZoom) {
|
|
2319
|
+
return /* @__PURE__ */ jsx6(
|
|
2320
|
+
"img",
|
|
2321
|
+
{
|
|
2322
|
+
...props,
|
|
2323
|
+
src: state.src,
|
|
2324
|
+
alt,
|
|
2325
|
+
className: cn(
|
|
2326
|
+
"block max-h-[360px] max-w-full rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] object-contain",
|
|
2327
|
+
className
|
|
2328
|
+
)
|
|
2329
|
+
}
|
|
2330
|
+
);
|
|
2331
|
+
}
|
|
2332
|
+
return /* @__PURE__ */ jsx6(
|
|
2333
|
+
ZoomableImage,
|
|
2334
|
+
{
|
|
2335
|
+
...props,
|
|
2336
|
+
src: state.src,
|
|
2337
|
+
alt,
|
|
2338
|
+
className: cn(
|
|
2339
|
+
"block max-h-[360px] max-w-full rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] object-contain",
|
|
2340
|
+
className
|
|
2341
|
+
),
|
|
2342
|
+
wrapElement: "span"
|
|
2343
|
+
}
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
return /* @__PURE__ */ jsx6("span", { className: "flex min-h-[160px] w-full items-center justify-center rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: state?.status === "error" ? state.reason === "unsupported" ? t("agentHost.workspaceFileManager.previewUnsupported") : t("agentHost.workspaceFileManager.previewReadFailed", {
|
|
2347
|
+
message: state.detail ?? ""
|
|
2348
|
+
}) : t("agentHost.workspaceFileManager.previewLoading") });
|
|
2349
|
+
}
|
|
2350
|
+
var MARKDOWN_ORDERED_LIST_STYLE = {
|
|
2351
|
+
listStylePosition: "outside",
|
|
2352
|
+
margin: "12px 0 8px",
|
|
2353
|
+
paddingInlineStart: 34,
|
|
2354
|
+
paddingInlineEnd: 16
|
|
2355
|
+
};
|
|
2356
|
+
var MARKDOWN_UNORDERED_LIST_STYLE = {
|
|
2357
|
+
margin: "12px 0 8px",
|
|
2358
|
+
paddingInlineStart: 0
|
|
2359
|
+
};
|
|
2360
|
+
var MARKDOWN_LIST_ITEM_STYLE = {
|
|
2361
|
+
margin: "4px 0"
|
|
2362
|
+
};
|
|
2363
|
+
function MarkdownUnorderedList({
|
|
2364
|
+
node: _node,
|
|
2365
|
+
className,
|
|
2366
|
+
style,
|
|
2367
|
+
...props
|
|
2368
|
+
}) {
|
|
2369
|
+
"use memo";
|
|
2370
|
+
return /* @__PURE__ */ jsx6(
|
|
2371
|
+
"ul",
|
|
2372
|
+
{
|
|
2373
|
+
...props,
|
|
2374
|
+
className: cn(
|
|
2375
|
+
'[&_li]:relative [&_li]:list-none [&_li]:pl-[34px] [&_li::before]:absolute [&_li::before]:left-4 [&_li::before]:top-[0.78em] [&_li::before]:h-1.5 [&_li::before]:w-1.5 [&_li::before]:-translate-y-1/2 [&_li::before]:rounded-full [&_li::before]:bg-[var(--text-tertiary)] [&_li::before]:content-[""]',
|
|
2376
|
+
className
|
|
2377
|
+
),
|
|
2378
|
+
style: { ...MARKDOWN_UNORDERED_LIST_STYLE, ...style }
|
|
2379
|
+
}
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
function MarkdownOrderedList({
|
|
2383
|
+
node: _node,
|
|
2384
|
+
style,
|
|
2385
|
+
...props
|
|
2386
|
+
}) {
|
|
2387
|
+
"use memo";
|
|
2388
|
+
return /* @__PURE__ */ jsx6(
|
|
2389
|
+
"ol",
|
|
2390
|
+
{
|
|
2391
|
+
...props,
|
|
2392
|
+
style: {
|
|
2393
|
+
...MARKDOWN_ORDERED_LIST_STYLE,
|
|
2394
|
+
listStyleType: "decimal",
|
|
2395
|
+
...style
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
function MarkdownListItem({
|
|
2401
|
+
node: _node,
|
|
2402
|
+
style,
|
|
2403
|
+
...props
|
|
2404
|
+
}) {
|
|
2405
|
+
"use memo";
|
|
2406
|
+
return /* @__PURE__ */ jsx6("li", { ...props, style: { ...MARKDOWN_LIST_ITEM_STYLE, ...style } });
|
|
2407
|
+
}
|
|
2408
|
+
function MarkdownParagraph({
|
|
2409
|
+
node: _node,
|
|
2410
|
+
inline,
|
|
2411
|
+
...props
|
|
2412
|
+
}) {
|
|
2413
|
+
"use memo";
|
|
2414
|
+
if (inline) {
|
|
2415
|
+
return /* @__PURE__ */ jsx6("span", { ...props });
|
|
2416
|
+
}
|
|
2417
|
+
return /* @__PURE__ */ jsx6("p", { ...props });
|
|
2418
|
+
}
|
|
2419
|
+
function isLocalAbsolutePath(path) {
|
|
2420
|
+
const candidate = path.trim();
|
|
2421
|
+
return candidate.length > 1 && candidate.startsWith("/") && !candidate.startsWith("//") && !candidate.includes("://") && !/\s/.test(candidate);
|
|
2422
|
+
}
|
|
2423
|
+
function resolveRenderableMarkdownImageSrc(src) {
|
|
2424
|
+
const trimmed = src.trim();
|
|
2425
|
+
if (!trimmed) {
|
|
2426
|
+
return src;
|
|
2427
|
+
}
|
|
2428
|
+
if (!isLocalAbsolutePath(trimmed) || trimmed.startsWith("/workspace/")) {
|
|
2429
|
+
return src;
|
|
2430
|
+
}
|
|
2431
|
+
return new URL(trimmed, "file://").toString();
|
|
2432
|
+
}
|
|
2433
|
+
function peekCachedMarkdownImageState(path) {
|
|
2434
|
+
const src = cachedMarkdownImages.get(path)?.objectUrl ?? null;
|
|
2435
|
+
return src ? { status: "ready", src } : null;
|
|
2436
|
+
}
|
|
2437
|
+
function retainCachedMarkdownImage(path) {
|
|
2438
|
+
const entry = cachedMarkdownImages.get(path);
|
|
2439
|
+
if (!entry) {
|
|
2440
|
+
return null;
|
|
2441
|
+
}
|
|
2442
|
+
entry.refCount += 1;
|
|
2443
|
+
if (entry.revokeTimer) {
|
|
2444
|
+
clearTimeout(entry.revokeTimer);
|
|
2445
|
+
entry.revokeTimer = null;
|
|
2446
|
+
}
|
|
2447
|
+
return entry.objectUrl;
|
|
2448
|
+
}
|
|
2449
|
+
function cacheMarkdownImage(path, blob) {
|
|
2450
|
+
const entry = cachedMarkdownImages.get(path);
|
|
2451
|
+
if (entry) {
|
|
2452
|
+
entry.refCount += 1;
|
|
2453
|
+
if (entry.revokeTimer) {
|
|
2454
|
+
clearTimeout(entry.revokeTimer);
|
|
2455
|
+
entry.revokeTimer = null;
|
|
2456
|
+
}
|
|
2457
|
+
return entry.objectUrl;
|
|
2458
|
+
}
|
|
2459
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
2460
|
+
cachedMarkdownImages.set(path, {
|
|
2461
|
+
objectUrl,
|
|
2462
|
+
refCount: 1,
|
|
2463
|
+
revokeTimer: null
|
|
2464
|
+
});
|
|
2465
|
+
return objectUrl;
|
|
2466
|
+
}
|
|
2467
|
+
function releaseCachedMarkdownImage(path, objectUrl) {
|
|
2468
|
+
const entry = cachedMarkdownImages.get(path);
|
|
2469
|
+
if (!entry || entry.objectUrl !== objectUrl) {
|
|
2470
|
+
URL.revokeObjectURL(objectUrl);
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
entry.refCount = Math.max(0, entry.refCount - 1);
|
|
2474
|
+
if (entry.refCount > 0 || entry.revokeTimer) {
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2477
|
+
entry.revokeTimer = setTimeout(() => {
|
|
2478
|
+
const current = cachedMarkdownImages.get(path);
|
|
2479
|
+
if (!current || current.objectUrl !== objectUrl || current.refCount > 0) {
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
cachedMarkdownImages.delete(path);
|
|
2483
|
+
URL.revokeObjectURL(objectUrl);
|
|
2484
|
+
}, CACHED_MARKDOWN_IMAGE_REVOKE_DELAY_MS);
|
|
2485
|
+
}
|
|
2486
|
+
function isHttpUrl(value) {
|
|
2487
|
+
const candidate = value.trim();
|
|
2488
|
+
if (!candidate || /\s/.test(candidate)) {
|
|
2489
|
+
return false;
|
|
2490
|
+
}
|
|
2491
|
+
try {
|
|
2492
|
+
const url = new URL(candidate);
|
|
2493
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
2494
|
+
} catch {
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
function linkBareLocalAbsolutePaths(content) {
|
|
2499
|
+
let out = "";
|
|
2500
|
+
for (let index = 0; index < content.length; ) {
|
|
2501
|
+
const markdownLinkEnd = markdownLinkEndIndex(content, index);
|
|
2502
|
+
if (markdownLinkEnd > index) {
|
|
2503
|
+
out += content.slice(index, markdownLinkEnd);
|
|
2504
|
+
index = markdownLinkEnd;
|
|
2505
|
+
continue;
|
|
2506
|
+
}
|
|
2507
|
+
const codeSpanEnd = codeSpanEndIndex(content, index);
|
|
2508
|
+
if (codeSpanEnd > index) {
|
|
2509
|
+
out += content.slice(index, codeSpanEnd);
|
|
2510
|
+
index = codeSpanEnd;
|
|
2511
|
+
continue;
|
|
2512
|
+
}
|
|
2513
|
+
if (isLocalPathStart(content, index)) {
|
|
2514
|
+
const end = bareLocalPathEndIndex(content, index);
|
|
2515
|
+
const rawPath = trimTrailingPathPunctuation(content.slice(index, end));
|
|
2516
|
+
const trailing = content.slice(index + rawPath.length, end);
|
|
2517
|
+
if (isLocalAbsolutePath(rawPath)) {
|
|
2518
|
+
out += `[${escapeMarkdownLinkLabel(rawPath)}](${rawPath})${trailing}`;
|
|
2519
|
+
} else {
|
|
2520
|
+
out += content.slice(index, end);
|
|
2521
|
+
}
|
|
2522
|
+
index = end;
|
|
2523
|
+
continue;
|
|
2524
|
+
}
|
|
2525
|
+
out += content[index];
|
|
2526
|
+
index += 1;
|
|
2527
|
+
}
|
|
2528
|
+
return out;
|
|
2529
|
+
}
|
|
2530
|
+
function normalizePlainIssueMentionTitleContent(content) {
|
|
2531
|
+
const trimmed = content.trim();
|
|
2532
|
+
if (trimmed !== content || !trimmed.startsWith("@") || trimmed.includes("\n") || markdownLinkEndIndex(trimmed, 0) === trimmed.length) {
|
|
2533
|
+
return content;
|
|
2534
|
+
}
|
|
2535
|
+
const label = trimmed.replace(/^@+/, "").trim();
|
|
2536
|
+
if (!label) {
|
|
2537
|
+
return content;
|
|
2538
|
+
}
|
|
2539
|
+
return `[@${escapeMarkdownLinkLabel(label)}](mention://workspace-issue?source=plain-title)`;
|
|
2540
|
+
}
|
|
2541
|
+
function normalizeMentionMarkdownLinks(content) {
|
|
2542
|
+
return content.replace(/\]([\t ]*\r?\n[\t ]*)+\((mention:\/\/)/g, "]($2").replace(/\]\((mention:\/\/[A-Za-z0-9.-]+)\)\?([^\s)]+)/g, "]($1?$2)");
|
|
2543
|
+
}
|
|
2544
|
+
function isMentionOnlyMarkdownContent(content) {
|
|
2545
|
+
const trimmed = content.trim();
|
|
2546
|
+
if (trimmed.length === 0) {
|
|
2547
|
+
return false;
|
|
2548
|
+
}
|
|
2549
|
+
if (markdownLinkEndIndex(trimmed, 0) !== trimmed.length) {
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
const labelEnd = trimmed.indexOf("]");
|
|
2553
|
+
return trimmed.slice(labelEnd + 2).startsWith("mention://");
|
|
2554
|
+
}
|
|
2555
|
+
function normalizePlainSessionMentionTitle(content) {
|
|
2556
|
+
const trimmed = content.trim();
|
|
2557
|
+
if (trimmed !== content || !trimmed.startsWith("@") || trimmed.includes("\n")) {
|
|
2558
|
+
return content;
|
|
2559
|
+
}
|
|
2560
|
+
for (const agentLabel of PLAIN_SESSION_MENTION_AGENT_LABELS) {
|
|
2561
|
+
const separator = ` & ${agentLabel}`;
|
|
2562
|
+
const separatorIndex = trimmed.indexOf(separator);
|
|
2563
|
+
if (separatorIndex <= 1) {
|
|
2564
|
+
continue;
|
|
2565
|
+
}
|
|
2566
|
+
const userLabel = trimmed.slice(1, separatorIndex).trim();
|
|
2567
|
+
const summary = trimmed.slice(separatorIndex + separator.length).trim();
|
|
2568
|
+
if (!userLabel) {
|
|
2569
|
+
continue;
|
|
2570
|
+
}
|
|
2571
|
+
const mentionLabel = [userLabel, agentLabel, summary].filter(Boolean).join(" \xB7 ");
|
|
2572
|
+
return `[@${escapeMarkdownLinkLabel(mentionLabel)}](mention://agent-session?source=plain-title)`;
|
|
2573
|
+
}
|
|
2574
|
+
return content;
|
|
2575
|
+
}
|
|
2576
|
+
function markdownUrlTransform(value) {
|
|
2577
|
+
return value.startsWith("mention://") ? value : defaultUrlTransform(value);
|
|
2578
|
+
}
|
|
2579
|
+
function parseMentionLink(href, rawLabel, workspaceAppIcons = [], appFactoryFallbackLabel = "Create app") {
|
|
2580
|
+
let url;
|
|
2581
|
+
try {
|
|
2582
|
+
url = new URL(href);
|
|
2583
|
+
} catch {
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
if (url.protocol !== "mention:") {
|
|
2587
|
+
return null;
|
|
2588
|
+
}
|
|
2589
|
+
const resource = url.hostname.trim().toLowerCase();
|
|
2590
|
+
const kind = resource === "agent-session" ? "session" : resource === "workspace-app" ? "workspace-app" : resource === "workspace-app-factory" ? "workspace-app-factory" : resource === "workspace-issue" ? "workspace-issue" : resource;
|
|
2591
|
+
if (kind !== "session" && kind !== "workspace-app" && kind !== "workspace-app-factory" && kind !== "workspace-issue") {
|
|
2592
|
+
return null;
|
|
2593
|
+
}
|
|
2594
|
+
const label = rawLabel.trim().replace(/^@+/, "").trim() || (kind === "workspace-app-factory" ? appFactoryFallbackLabel : "");
|
|
2595
|
+
if (kind === "workspace-app" || kind === "workspace-app-factory") {
|
|
2596
|
+
const appId = url.searchParams.get("appId")?.trim() || "";
|
|
2597
|
+
const workspaceId = url.searchParams.get("workspaceId")?.trim() || "";
|
|
2598
|
+
return {
|
|
2599
|
+
kind,
|
|
2600
|
+
...kind === "workspace-app" ? { appId } : {},
|
|
2601
|
+
label,
|
|
2602
|
+
...kind === "workspace-app" ? {
|
|
2603
|
+
iconUrl: resolveWorkspaceAppMentionIconUrl({
|
|
2604
|
+
appId,
|
|
2605
|
+
workspaceAppIcons,
|
|
2606
|
+
workspaceId
|
|
2607
|
+
})
|
|
2608
|
+
} : {},
|
|
2609
|
+
participant: label,
|
|
2610
|
+
summary: ""
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2613
|
+
if (kind === "workspace-issue") {
|
|
2614
|
+
return {
|
|
2615
|
+
kind,
|
|
2616
|
+
label,
|
|
2617
|
+
participant: label,
|
|
2618
|
+
summary: ""
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2621
|
+
const sessionLabel = parseSessionMentionLabel(label);
|
|
2622
|
+
return {
|
|
2623
|
+
kind,
|
|
2624
|
+
label,
|
|
2625
|
+
participant: sessionLabel.participant,
|
|
2626
|
+
summary: sessionLabel.summary
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
2629
|
+
function resolveWorkspaceAppMentionIconUrl(input) {
|
|
2630
|
+
const appId = input.appId.trim();
|
|
2631
|
+
if (!appId) {
|
|
2632
|
+
return void 0;
|
|
2633
|
+
}
|
|
2634
|
+
const workspaceId = input.workspaceId.trim();
|
|
2635
|
+
const exactMatch = input.workspaceAppIcons.find(
|
|
2636
|
+
(icon) => icon.appId.trim() === appId && (icon.workspaceId?.trim() ?? "") === workspaceId && icon.iconUrl?.trim()
|
|
2637
|
+
);
|
|
2638
|
+
const fallbackMatch = input.workspaceAppIcons.find(
|
|
2639
|
+
(icon) => icon.appId.trim() === appId && icon.iconUrl?.trim()
|
|
2640
|
+
);
|
|
2641
|
+
return exactMatch?.iconUrl?.trim() || fallbackMatch?.iconUrl?.trim() || void 0;
|
|
2642
|
+
}
|
|
2643
|
+
function parseSessionMentionLabel(label) {
|
|
2644
|
+
const dottedParts = label.split("\xB7").map((part) => part.trim()).filter(Boolean);
|
|
2645
|
+
if (dottedParts.length >= 3) {
|
|
2646
|
+
return {
|
|
2647
|
+
participant: `${dottedParts[0]} & ${dottedParts[1]}`,
|
|
2648
|
+
summary: dottedParts.slice(2).join(" ")
|
|
2649
|
+
};
|
|
2650
|
+
}
|
|
2651
|
+
return {
|
|
2652
|
+
participant: label,
|
|
2653
|
+
summary: ""
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
function markdownLinkEndIndex(content, index) {
|
|
2657
|
+
if (content[index] !== "[") {
|
|
2658
|
+
return -1;
|
|
2659
|
+
}
|
|
2660
|
+
const labelEnd = content.indexOf("]", index + 1);
|
|
2661
|
+
if (labelEnd < 0 || content[labelEnd + 1] !== "(") {
|
|
2662
|
+
return -1;
|
|
2663
|
+
}
|
|
2664
|
+
const hrefEnd = content.indexOf(")", labelEnd + 2);
|
|
2665
|
+
return hrefEnd < 0 ? -1 : hrefEnd + 1;
|
|
2666
|
+
}
|
|
2667
|
+
function codeSpanEndIndex(content, index) {
|
|
2668
|
+
if (content[index] !== "`") {
|
|
2669
|
+
return -1;
|
|
2670
|
+
}
|
|
2671
|
+
let tickCount = 1;
|
|
2672
|
+
while (content[index + tickCount] === "`") {
|
|
2673
|
+
tickCount += 1;
|
|
2674
|
+
}
|
|
2675
|
+
const fence = "`".repeat(tickCount);
|
|
2676
|
+
const end = content.indexOf(fence, index + tickCount);
|
|
2677
|
+
return end < 0 ? -1 : end + tickCount;
|
|
2678
|
+
}
|
|
2679
|
+
function isLocalPathStart(content, index) {
|
|
2680
|
+
if (content[index] !== "/" || content[index + 1] === "/") {
|
|
2681
|
+
return false;
|
|
2682
|
+
}
|
|
2683
|
+
const previous = content[index - 1];
|
|
2684
|
+
return previous === void 0 || /\s/.test(previous) || previous === "(" || previous === "[";
|
|
2685
|
+
}
|
|
2686
|
+
function bareLocalPathEndIndex(content, index) {
|
|
2687
|
+
let end = index;
|
|
2688
|
+
while (end < content.length) {
|
|
2689
|
+
const char = content[end];
|
|
2690
|
+
if (!char || /[\s<>[\](){}"'`]/.test(char)) {
|
|
2691
|
+
break;
|
|
2692
|
+
}
|
|
2693
|
+
end += 1;
|
|
2694
|
+
}
|
|
2695
|
+
return end;
|
|
2696
|
+
}
|
|
2697
|
+
function trimTrailingPathPunctuation(path) {
|
|
2698
|
+
return path.replace(/[.,;:!?,。;:!?]+$/g, "");
|
|
2699
|
+
}
|
|
2700
|
+
function escapeMarkdownLinkLabel(label) {
|
|
2701
|
+
return label.replace(/([\\[\]])/g, "\\$1");
|
|
2702
|
+
}
|
|
2703
|
+
function PathLink({
|
|
2704
|
+
href,
|
|
2705
|
+
children,
|
|
2706
|
+
onLinkClick
|
|
2707
|
+
}) {
|
|
2708
|
+
"use memo";
|
|
2709
|
+
return /* @__PURE__ */ jsx6(
|
|
2710
|
+
"a",
|
|
2711
|
+
{
|
|
2712
|
+
className: "cursor-pointer",
|
|
2713
|
+
"data-agent-link-href": href,
|
|
2714
|
+
role: "link",
|
|
2715
|
+
tabIndex: 0,
|
|
2716
|
+
onClick: (event) => {
|
|
2717
|
+
activateMarkdownLink(event, href, onLinkClick);
|
|
2718
|
+
},
|
|
2719
|
+
onPointerDown: (event) => {
|
|
2720
|
+
activateMarkdownLinkFromPointer(event, href, onLinkClick);
|
|
2721
|
+
},
|
|
2722
|
+
onKeyDown: (event) => {
|
|
2723
|
+
activateMarkdownLinkFromKey(event, href, onLinkClick);
|
|
2724
|
+
},
|
|
2725
|
+
children
|
|
2726
|
+
}
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
function textFromReactNode(node) {
|
|
2730
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
2731
|
+
return String(node);
|
|
2732
|
+
}
|
|
2733
|
+
if (Array.isArray(node)) {
|
|
2734
|
+
return node.map(textFromReactNode).join("");
|
|
2735
|
+
}
|
|
2736
|
+
return "";
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
// app/renderer/assets/icons/user-avatar-placeholder.png
|
|
2740
|
+
var user_avatar_placeholder_default = "./user-avatar-placeholder-WP2373TS.png";
|
|
2741
|
+
|
|
2742
|
+
// shared/workspaceAgentActivityStatusLabel.ts
|
|
2743
|
+
function normalizeWorkspaceAgentActivityDisplayStatus(status) {
|
|
2744
|
+
switch ((status ?? "").trim().toLowerCase()) {
|
|
2745
|
+
case "working":
|
|
2746
|
+
return "working";
|
|
2747
|
+
case "waiting":
|
|
2748
|
+
return "waiting";
|
|
2749
|
+
case "idle":
|
|
2750
|
+
case "ready":
|
|
2751
|
+
return "completed";
|
|
2752
|
+
case "completed":
|
|
2753
|
+
case "end":
|
|
2754
|
+
return "completed";
|
|
2755
|
+
case "canceled":
|
|
2756
|
+
return "canceled";
|
|
2757
|
+
case "failed":
|
|
2758
|
+
return "failed";
|
|
2759
|
+
default:
|
|
2760
|
+
return "idle";
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
function workspaceAgentActivityStatusLabel(status, t) {
|
|
2764
|
+
const translateFn = t ?? translate;
|
|
2765
|
+
switch (normalizeWorkspaceAgentActivityDisplayStatus(status)) {
|
|
2766
|
+
case "working":
|
|
2767
|
+
return translateFn("agentHost.workspaceAgentActivityStatusWorking");
|
|
2768
|
+
case "waiting":
|
|
2769
|
+
return translateFn("agentHost.workspaceAgentActivityStatusWaiting");
|
|
2770
|
+
case "idle":
|
|
2771
|
+
return translateFn("agentHost.workspaceAgentActivityStatusIdle");
|
|
2772
|
+
case "completed":
|
|
2773
|
+
return translateFn("agentHost.workspaceAgentActivityStatusEnd");
|
|
2774
|
+
case "canceled":
|
|
2775
|
+
return translateFn("agentHost.workspaceAgentActivityStatusCanceled");
|
|
2776
|
+
case "failed":
|
|
2777
|
+
return translateFn("agentHost.workspaceAgentActivityStatusFailed");
|
|
2778
|
+
default:
|
|
2779
|
+
return String(status);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
// app/renderer/components/ui/custom-scroll-area.tsx
|
|
2784
|
+
import {
|
|
2785
|
+
forwardRef as forwardRef2,
|
|
2786
|
+
useCallback as useCallback4,
|
|
2787
|
+
useEffect as useEffect4,
|
|
2788
|
+
useRef as useRef3,
|
|
2789
|
+
useState as useState3
|
|
2790
|
+
} from "react";
|
|
2791
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2792
|
+
var MIN_THUMB_HEIGHT = 24;
|
|
2793
|
+
function CustomScrollbar({
|
|
2794
|
+
getViewport,
|
|
2795
|
+
className,
|
|
2796
|
+
thumbClassName,
|
|
2797
|
+
testId,
|
|
2798
|
+
thumbTestId,
|
|
2799
|
+
syncKey
|
|
2800
|
+
}) {
|
|
2801
|
+
"use memo";
|
|
2802
|
+
const trackRef = useRef3(null);
|
|
2803
|
+
const dragStateRef = useRef3(null);
|
|
2804
|
+
const [scrollbarState, setScrollbarState] = useState3({
|
|
2805
|
+
scrollable: false,
|
|
2806
|
+
thumbHeight: 0,
|
|
2807
|
+
thumbTop: 0
|
|
2808
|
+
});
|
|
2809
|
+
const [dragging, setDragging] = useState3(false);
|
|
2810
|
+
const syncScrollbarState = useCallback4(() => {
|
|
2811
|
+
const viewport = getViewport();
|
|
2812
|
+
if (!viewport) {
|
|
2813
|
+
setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
const { clientHeight, scrollHeight, scrollTop } = viewport;
|
|
2817
|
+
const trackHeight = trackRef.current?.clientHeight ?? clientHeight;
|
|
2818
|
+
const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
|
|
2819
|
+
if (clientHeight <= 0 || trackHeight <= 0 || maxScrollTop <= 0) {
|
|
2820
|
+
setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
|
|
2821
|
+
return;
|
|
2822
|
+
}
|
|
2823
|
+
const thumbHeight = Math.max(
|
|
2824
|
+
MIN_THUMB_HEIGHT,
|
|
2825
|
+
Math.round(clientHeight / scrollHeight * trackHeight)
|
|
2826
|
+
);
|
|
2827
|
+
const maxThumbTop = Math.max(0, trackHeight - thumbHeight);
|
|
2828
|
+
const thumbTop = Math.round(scrollTop / maxScrollTop * maxThumbTop);
|
|
2829
|
+
setScrollbarState(
|
|
2830
|
+
(previous) => previous.scrollable && previous.thumbHeight === thumbHeight && previous.thumbTop === thumbTop ? previous : { scrollable: true, thumbHeight, thumbTop }
|
|
2831
|
+
);
|
|
2832
|
+
}, [getViewport]);
|
|
2833
|
+
const scrollViewportToThumbTop = useCallback4(
|
|
2834
|
+
(thumbTop) => {
|
|
2835
|
+
const viewport = getViewport();
|
|
2836
|
+
const track = trackRef.current;
|
|
2837
|
+
if (!viewport || !track) {
|
|
2838
|
+
return;
|
|
2839
|
+
}
|
|
2840
|
+
const maxScrollTop = Math.max(
|
|
2841
|
+
0,
|
|
2842
|
+
viewport.scrollHeight - viewport.clientHeight
|
|
2843
|
+
);
|
|
2844
|
+
const maxThumbTop = Math.max(
|
|
2845
|
+
0,
|
|
2846
|
+
track.clientHeight - scrollbarState.thumbHeight
|
|
2847
|
+
);
|
|
2848
|
+
if (maxScrollTop <= 0 || maxThumbTop <= 0) {
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2851
|
+
viewport.scrollTop = clamp(thumbTop, 0, maxThumbTop) / maxThumbTop * maxScrollTop;
|
|
2852
|
+
syncScrollbarState();
|
|
2853
|
+
},
|
|
2854
|
+
[getViewport, scrollbarState.thumbHeight, syncScrollbarState]
|
|
2855
|
+
);
|
|
2856
|
+
const handleTrackMouseDown = useCallback4(
|
|
2857
|
+
(event) => {
|
|
2858
|
+
if (event.button !== 0 || !scrollbarState.scrollable) {
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2861
|
+
const track = trackRef.current;
|
|
2862
|
+
if (!track) {
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
event.preventDefault();
|
|
2866
|
+
event.stopPropagation();
|
|
2867
|
+
const trackRect = track.getBoundingClientRect();
|
|
2868
|
+
scrollViewportToThumbTop(
|
|
2869
|
+
event.clientY - trackRect.top - scrollbarState.thumbHeight / 2
|
|
2870
|
+
);
|
|
2871
|
+
},
|
|
2872
|
+
[
|
|
2873
|
+
scrollViewportToThumbTop,
|
|
2874
|
+
scrollbarState.scrollable,
|
|
2875
|
+
scrollbarState.thumbHeight
|
|
2876
|
+
]
|
|
2877
|
+
);
|
|
2878
|
+
const handleThumbMouseDown = useCallback4(
|
|
2879
|
+
(event) => {
|
|
2880
|
+
if (event.button !== 0 || !scrollbarState.scrollable) {
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
const viewport = getViewport();
|
|
2884
|
+
const track = trackRef.current;
|
|
2885
|
+
if (!viewport || !track) {
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
const maxScrollTop = Math.max(
|
|
2889
|
+
0,
|
|
2890
|
+
viewport.scrollHeight - viewport.clientHeight
|
|
2891
|
+
);
|
|
2892
|
+
const maxThumbTop = Math.max(
|
|
2893
|
+
0,
|
|
2894
|
+
track.clientHeight - scrollbarState.thumbHeight
|
|
2895
|
+
);
|
|
2896
|
+
if (maxScrollTop <= 0 || maxThumbTop <= 0) {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
event.preventDefault();
|
|
2900
|
+
event.stopPropagation();
|
|
2901
|
+
dragStateRef.current = {
|
|
2902
|
+
maxScrollTop,
|
|
2903
|
+
maxThumbTop,
|
|
2904
|
+
startClientY: event.clientY,
|
|
2905
|
+
startScrollTop: viewport.scrollTop
|
|
2906
|
+
};
|
|
2907
|
+
setDragging(true);
|
|
2908
|
+
},
|
|
2909
|
+
[getViewport, scrollbarState.scrollable, scrollbarState.thumbHeight]
|
|
2910
|
+
);
|
|
2911
|
+
useEffect4(() => {
|
|
2912
|
+
if (!dragging) {
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2915
|
+
const handleMouseMove = (event) => {
|
|
2916
|
+
const dragState = dragStateRef.current;
|
|
2917
|
+
const viewport = getViewport();
|
|
2918
|
+
if (!dragState || !viewport) {
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
const nextThumbTop = dragState.startScrollTop / dragState.maxScrollTop * dragState.maxThumbTop + (event.clientY - dragState.startClientY);
|
|
2922
|
+
viewport.scrollTop = clamp(nextThumbTop, 0, dragState.maxThumbTop) / dragState.maxThumbTop * dragState.maxScrollTop;
|
|
2923
|
+
syncScrollbarState();
|
|
2924
|
+
};
|
|
2925
|
+
const handleMouseUp = () => {
|
|
2926
|
+
dragStateRef.current = null;
|
|
2927
|
+
setDragging(false);
|
|
2928
|
+
};
|
|
2929
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
2930
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
2931
|
+
return () => {
|
|
2932
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
2933
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
2934
|
+
};
|
|
2935
|
+
}, [dragging, getViewport, syncScrollbarState]);
|
|
2936
|
+
useEffect4(() => {
|
|
2937
|
+
const viewport = getViewport();
|
|
2938
|
+
if (!viewport) {
|
|
2939
|
+
setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
|
|
2940
|
+
return;
|
|
2941
|
+
}
|
|
2942
|
+
syncScrollbarState();
|
|
2943
|
+
viewport.addEventListener("scroll", syncScrollbarState, { passive: true });
|
|
2944
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(syncScrollbarState) : null;
|
|
2945
|
+
resizeObserver?.observe(viewport);
|
|
2946
|
+
const animationFrameId = window.requestAnimationFrame(syncScrollbarState);
|
|
2947
|
+
return () => {
|
|
2948
|
+
window.cancelAnimationFrame(animationFrameId);
|
|
2949
|
+
viewport.removeEventListener("scroll", syncScrollbarState);
|
|
2950
|
+
resizeObserver?.disconnect();
|
|
2951
|
+
};
|
|
2952
|
+
}, [getViewport, syncKey, syncScrollbarState]);
|
|
2953
|
+
return /* @__PURE__ */ jsx7(
|
|
2954
|
+
"div",
|
|
2955
|
+
{
|
|
2956
|
+
ref: trackRef,
|
|
2957
|
+
className: cn("tsh-custom-scrollbar", className),
|
|
2958
|
+
"data-scrollable": scrollbarState.scrollable ? "true" : "false",
|
|
2959
|
+
"data-dragging": dragging ? "true" : "false",
|
|
2960
|
+
"data-testid": testId,
|
|
2961
|
+
"aria-hidden": "true",
|
|
2962
|
+
onMouseDown: handleTrackMouseDown,
|
|
2963
|
+
children: /* @__PURE__ */ jsx7(
|
|
2964
|
+
"div",
|
|
2965
|
+
{
|
|
2966
|
+
className: cn("tsh-custom-scrollbar__thumb", thumbClassName),
|
|
2967
|
+
"data-testid": thumbTestId,
|
|
2968
|
+
onMouseDown: handleThumbMouseDown,
|
|
2969
|
+
style: {
|
|
2970
|
+
height: `${scrollbarState.thumbHeight}px`,
|
|
2971
|
+
transform: `translateY(${scrollbarState.thumbTop}px)`
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
)
|
|
2975
|
+
}
|
|
2976
|
+
);
|
|
2977
|
+
}
|
|
2978
|
+
var CustomScrollArea = forwardRef2(function CustomScrollArea2({
|
|
2979
|
+
children,
|
|
2980
|
+
className,
|
|
2981
|
+
viewportClassName,
|
|
2982
|
+
scrollbarClassName,
|
|
2983
|
+
scrollbarThumbClassName,
|
|
2984
|
+
scrollbarTestId,
|
|
2985
|
+
scrollbarThumbTestId,
|
|
2986
|
+
syncKey,
|
|
2987
|
+
...viewportProps
|
|
2988
|
+
}, forwardedRef) {
|
|
2989
|
+
"use memo";
|
|
2990
|
+
const viewportRef = useRef3(null);
|
|
2991
|
+
const getViewport = useCallback4(() => viewportRef.current, []);
|
|
2992
|
+
return /* @__PURE__ */ jsxs5(
|
|
2993
|
+
"div",
|
|
2994
|
+
{
|
|
2995
|
+
className: cn(
|
|
2996
|
+
"tsh-custom-scroll-area relative min-h-0 min-w-0",
|
|
2997
|
+
className
|
|
2998
|
+
),
|
|
2999
|
+
children: [
|
|
3000
|
+
/* @__PURE__ */ jsx7(
|
|
3001
|
+
"div",
|
|
3002
|
+
{
|
|
3003
|
+
ref: setRefs(viewportRef, forwardedRef),
|
|
3004
|
+
className: cn(
|
|
3005
|
+
"overflow-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
3006
|
+
viewportClassName
|
|
3007
|
+
),
|
|
3008
|
+
...viewportProps,
|
|
3009
|
+
children
|
|
3010
|
+
}
|
|
3011
|
+
),
|
|
3012
|
+
/* @__PURE__ */ jsx7(
|
|
3013
|
+
CustomScrollbar,
|
|
3014
|
+
{
|
|
3015
|
+
getViewport,
|
|
3016
|
+
className: scrollbarClassName,
|
|
3017
|
+
thumbClassName: scrollbarThumbClassName,
|
|
3018
|
+
testId: scrollbarTestId,
|
|
3019
|
+
thumbTestId: scrollbarThumbTestId,
|
|
3020
|
+
syncKey: syncKey ?? children
|
|
3021
|
+
}
|
|
3022
|
+
)
|
|
3023
|
+
]
|
|
3024
|
+
}
|
|
3025
|
+
);
|
|
3026
|
+
});
|
|
3027
|
+
function setRefs(localRef, forwardedRef) {
|
|
3028
|
+
return (node) => {
|
|
3029
|
+
localRef.current = node;
|
|
3030
|
+
if (typeof forwardedRef === "function") {
|
|
3031
|
+
forwardedRef(node);
|
|
3032
|
+
} else if (forwardedRef) {
|
|
3033
|
+
forwardedRef.current = node;
|
|
3034
|
+
}
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
function clamp(value, min, max) {
|
|
3038
|
+
return Math.min(max, Math.max(min, value));
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
export {
|
|
3042
|
+
cn,
|
|
3043
|
+
AgentActivityRuntimeProvider,
|
|
3044
|
+
useAgentActivityRuntime,
|
|
3045
|
+
useOptionalAgentActivityRuntime,
|
|
3046
|
+
useAgentActivitySnapshot,
|
|
3047
|
+
getAgentActivityRuntime,
|
|
3048
|
+
getOptionalAgentActivityRuntime,
|
|
3049
|
+
resetAgentActivityRuntimeForTests,
|
|
3050
|
+
setAgentActivityRuntimeForTests,
|
|
3051
|
+
AgentActivityHostProvider,
|
|
3052
|
+
useAgentHostApi,
|
|
3053
|
+
useOptionalAgentHostApi,
|
|
3054
|
+
getOptionalAgentHostApi,
|
|
3055
|
+
resolveWebsiteNavigationUrl,
|
|
3056
|
+
ZoomableImage,
|
|
3057
|
+
resolveWorkspaceLinkAction,
|
|
3058
|
+
AgentMessageMarkdown,
|
|
3059
|
+
AgentGUIConversation_styles_default,
|
|
3060
|
+
CustomScrollArea,
|
|
3061
|
+
MessageSquareMoreIcon,
|
|
3062
|
+
normalizeManagedAgentProvider,
|
|
3063
|
+
MANAGED_AGENT_ICON_URLS,
|
|
3064
|
+
MANAGED_AGENT_ICON_FALLBACK_URL,
|
|
3065
|
+
managedAgentRoundedIconUrl,
|
|
3066
|
+
approvalOptionDisplayLabel,
|
|
3067
|
+
Spinner,
|
|
3068
|
+
getPromptToolDetails,
|
|
3069
|
+
isPromptRequestIdTitle,
|
|
3070
|
+
AgentInteractivePromptSurface,
|
|
3071
|
+
user_avatar_placeholder_default,
|
|
3072
|
+
normalizeWorkspaceAgentActivityDisplayStatus,
|
|
3073
|
+
workspaceAgentActivityStatusLabel
|
|
3074
|
+
};
|
|
3075
|
+
//# sourceMappingURL=chunk-AF5CXBJN.js.map
|