@tutti-os/agent-gui 0.0.132 → 0.0.134
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/README.md +21 -4
- package/dist/{AgentRichTextReadonly-PEKCMRPE.js → AgentRichTextReadonly-HCKTNAYO.js} +7 -6
- package/dist/agent-conversation/index.d.ts +4 -6
- package/dist/agent-conversation/index.js +10 -10
- package/dist/agent-env/index.d.ts +10 -27
- package/dist/agent-env/index.js +14 -290
- package/dist/agent-env/index.js.map +1 -1
- package/dist/agent-gui.d.ts +1118 -20
- package/dist/agent-gui.js +18 -18
- package/dist/agent-message-center/index.d.ts +42 -7
- package/dist/agent-message-center/index.js +7 -7
- package/dist/{agentConversationVM-BD0-gg6C.d.ts → agentConversationVM-DWEy7jzx.d.ts} +41 -2
- package/dist/{agentFileMentionContracts-CWAeuL7S.d.ts → agentFileMentionContracts-B0yQizXB.d.ts} +5 -0
- package/dist/{agentGuiNodeTypes-5TL1hyCN.d.ts → agentGuiNodeTypes-DV7KvZRe.d.ts} +10 -26
- package/dist/agents.d.ts +1 -1
- package/dist/agents.js +1 -1
- package/dist/app/renderer/agentactivity.css +7 -0
- package/dist/app/renderer/assets/icons/@-lined.svg +1 -8
- package/dist/{chunk-PQJXWXTS.js → chunk-25VMCMAQ.js} +4 -4
- package/dist/{chunk-T2NICA5D.js → chunk-5WOCGIXJ.js} +7 -1
- package/dist/chunk-5WOCGIXJ.js.map +1 -0
- package/dist/chunk-DLCZJKCA.js +1 -0
- package/dist/chunk-DLCZJKCA.js.map +1 -0
- package/dist/{chunk-QQRTUHCH.js → chunk-EU7DCT4F.js} +2 -2
- package/dist/chunk-FM42UN2J.js +462 -0
- package/dist/chunk-FM42UN2J.js.map +1 -0
- package/dist/{chunk-SZOTLVH6.js → chunk-GIYGO2PB.js} +2 -2
- package/dist/{chunk-GCQYN7BR.js → chunk-IN3HXYOO.js} +4 -4
- package/dist/{chunk-YWHGCKMT.js → chunk-IYZ4GOSN.js} +10 -10
- package/dist/chunk-IYZ4GOSN.js.map +1 -0
- package/dist/{chunk-JZS4SWFJ.js → chunk-JI5KND3K.js} +60 -56
- package/dist/chunk-JI5KND3K.js.map +1 -0
- package/dist/{chunk-J4TTEMRW.js → chunk-KWGMK4IZ.js} +4 -4
- package/dist/{chunk-NE6H7S5Z.js → chunk-OFJNIQWR.js} +2 -2
- package/dist/{chunk-NE6H7S5Z.js.map → chunk-OFJNIQWR.js.map} +1 -1
- package/dist/{chunk-UARZZJJB.js → chunk-OI6BYC7P.js} +4 -4
- package/dist/{chunk-OBWM2RFE.js → chunk-QPEO4OQS.js} +308 -8
- package/dist/chunk-QPEO4OQS.js.map +1 -0
- package/dist/{chunk-XNE2ROCP.js → chunk-UA75CGAG.js} +3 -3
- package/dist/{chunk-PVTAFUDS.js → chunk-VGS7S7YT.js} +2 -2
- package/dist/{chunk-OQR3HXPF.js → chunk-VUNVGEQG.js} +7 -1
- package/dist/chunk-VUNVGEQG.js.map +1 -0
- package/dist/{chunk-G75CPIVV.js → chunk-Y5HD6XHP.js} +1040 -797
- package/dist/chunk-Y5HD6XHP.js.map +1 -0
- package/dist/{chunk-KPMQGPYU.js → chunk-ZVYUTXQJ.js} +1 -1
- package/dist/chunk-ZVYUTXQJ.js.map +1 -0
- package/dist/context-mention-palette/index.d.ts +1 -1
- package/dist/context-mention-palette/index.js +8 -7
- package/dist/{contribution-yc4CGJmy.d.ts → contribution-CDdwTppn.d.ts} +54 -1
- package/dist/custom-mention.d.ts +4 -2
- package/dist/custom-mention.js +1 -0
- package/dist/i18n/index.d.ts +17 -6
- package/dist/i18n/index.js +2 -2
- package/dist/index.d.ts +8026 -33
- package/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/mention-search.d.ts +1 -1
- package/dist/mention-search.js +6 -5
- package/dist/runtime-Dwf44VKc.d.ts +7 -0
- package/dist/{types-BicfRVrV.d.ts → types-ee3zJ6Cc.d.ts} +6 -5
- package/dist/workbench/browser-element-context/index.d.ts +37 -0
- package/dist/workbench/browser-element-context/index.js +750 -0
- package/dist/workbench/browser-element-context/index.js.map +1 -0
- package/dist/workbench/contribution.d.ts +1 -2
- package/dist/workbench/contribution.js +4 -4
- package/dist/workbench/index.d.ts +1 -2
- package/dist/workbench/index.js +4 -4
- package/dist/workbench/sessionTitle.js +2 -2
- package/dist/workbench/tool-sidebar/index.d.ts +189 -0
- package/dist/workbench/tool-sidebar/index.js +1492 -0
- package/dist/workbench/tool-sidebar/index.js.map +1 -0
- package/dist/workspace-agent-generated-files.d.ts +12 -1
- package/package.json +28 -13
- package/dist/AgentGUI-DxypmD7b.d.ts +0 -1080
- package/dist/agentPlanPromptDispatch-C7cCMjve.d.ts +0 -37
- package/dist/chunk-G75CPIVV.js.map +0 -1
- package/dist/chunk-JZS4SWFJ.js.map +0 -1
- package/dist/chunk-KPMQGPYU.js.map +0 -1
- package/dist/chunk-OBWM2RFE.js.map +0 -1
- package/dist/chunk-OQR3HXPF.js.map +0 -1
- package/dist/chunk-T2NICA5D.js.map +0 -1
- package/dist/chunk-VMQNG2KI.js +0 -178
- package/dist/chunk-VMQNG2KI.js.map +0 -1
- package/dist/chunk-YWHGCKMT.js.map +0 -1
- package/dist/pastedTextKinds-D-XuInaS.d.ts +0 -4
- package/dist/runtime-BBNdWgDU.d.ts +0 -10
- package/dist/workspaceAgentActivityListTypes-DZfS_HgG.d.ts +0 -48
- /package/dist/{AgentRichTextReadonly-PEKCMRPE.js.map → AgentRichTextReadonly-HCKTNAYO.js.map} +0 -0
- /package/dist/{chunk-PQJXWXTS.js.map → chunk-25VMCMAQ.js.map} +0 -0
- /package/dist/{chunk-QQRTUHCH.js.map → chunk-EU7DCT4F.js.map} +0 -0
- /package/dist/{chunk-SZOTLVH6.js.map → chunk-GIYGO2PB.js.map} +0 -0
- /package/dist/{chunk-GCQYN7BR.js.map → chunk-IN3HXYOO.js.map} +0 -0
- /package/dist/{chunk-J4TTEMRW.js.map → chunk-KWGMK4IZ.js.map} +0 -0
- /package/dist/{chunk-UARZZJJB.js.map → chunk-OI6BYC7P.js.map} +0 -0
- /package/dist/{chunk-XNE2ROCP.js.map → chunk-UA75CGAG.js.map} +0 -0
- /package/dist/{chunk-PVTAFUDS.js.map → chunk-VGS7S7YT.js.map} +0 -0
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
import "../../chunk-DLCZJKCA.js";
|
|
2
|
+
import "../../chunk-FGLQZ6I4.js";
|
|
3
|
+
import {
|
|
4
|
+
useEngineSelector
|
|
5
|
+
} from "../../chunk-2RQM7PJN.js";
|
|
6
|
+
import {
|
|
7
|
+
registerAgentCustomMentionKind
|
|
8
|
+
} from "../../chunk-D2JUDUYY.js";
|
|
9
|
+
|
|
10
|
+
// workbench/browser-element-context/BrowserElementContextAction.tsx
|
|
11
|
+
import { useCallback, useState } from "react";
|
|
12
|
+
import {
|
|
13
|
+
Button,
|
|
14
|
+
InspectIcon,
|
|
15
|
+
Tooltip,
|
|
16
|
+
TooltipContent,
|
|
17
|
+
TooltipTrigger,
|
|
18
|
+
cn
|
|
19
|
+
} from "@tutti-os/ui-system";
|
|
20
|
+
import { useActiveBrowserNodeWebview } from "@tutti-os/browser-node/react";
|
|
21
|
+
|
|
22
|
+
// workbench/browser-element-context/browserElementSnapshot.ts
|
|
23
|
+
var browserElementSnapshotFormat = "tutti.browser-element.v1";
|
|
24
|
+
var browserElementSnapshotMaxHtmlChars = 32e3;
|
|
25
|
+
var browserElementSnapshotMaxTextChars = 4e3;
|
|
26
|
+
function normalizeBrowserElementSelectionResult(value) {
|
|
27
|
+
if (!isRecord(value)) return null;
|
|
28
|
+
if (value.status === "cancelled") return { status: "cancelled" };
|
|
29
|
+
if (value.status !== "selected" || !isRecord(value.snapshot)) return null;
|
|
30
|
+
const snapshot = value.snapshot;
|
|
31
|
+
const page = isRecord(snapshot.page) ? snapshot.page : {};
|
|
32
|
+
const element = isRecord(snapshot.element) ? snapshot.element : {};
|
|
33
|
+
const bounds = isRecord(element.bounds) ? element.bounds : {};
|
|
34
|
+
const viewport = isRecord(snapshot.viewport) ? snapshot.viewport : {};
|
|
35
|
+
const normalized = {
|
|
36
|
+
format: browserElementSnapshotFormat,
|
|
37
|
+
capturedAt: boundedString(snapshot.capturedAt, 64) || (/* @__PURE__ */ new Date()).toISOString(),
|
|
38
|
+
page: {
|
|
39
|
+
title: boundedString(page.title, 500),
|
|
40
|
+
url: sanitizeSnapshotUrl(boundedString(page.url, 4e3))
|
|
41
|
+
},
|
|
42
|
+
element: {
|
|
43
|
+
ariaLabel: nullableBoundedString(element.ariaLabel, 1e3),
|
|
44
|
+
attributes: boundedStringRecord(element.attributes, 40, 200, 2e3),
|
|
45
|
+
bounds: {
|
|
46
|
+
height: finiteNumber(bounds.height),
|
|
47
|
+
width: finiteNumber(bounds.width),
|
|
48
|
+
x: finiteNumber(bounds.x),
|
|
49
|
+
y: finiteNumber(bounds.y)
|
|
50
|
+
},
|
|
51
|
+
classes: boundedStringArray(element.classes, 24, 200),
|
|
52
|
+
domPath: boundedString(element.domPath, 4e3) || boundedString(element.selector, 2e3),
|
|
53
|
+
html: boundedString(element.html, browserElementSnapshotMaxHtmlChars),
|
|
54
|
+
htmlTruncated: element.htmlTruncated === true || typeof element.html === "string" && element.html.length > browserElementSnapshotMaxHtmlChars,
|
|
55
|
+
id: nullableBoundedString(element.id, 500),
|
|
56
|
+
role: nullableBoundedString(element.role, 200),
|
|
57
|
+
selector: boundedString(element.selector, 2e3),
|
|
58
|
+
styles: boundedStringRecord(element.styles, 32, 100, 500),
|
|
59
|
+
tagName: boundedString(element.tagName, 100).toLowerCase(),
|
|
60
|
+
text: boundedString(element.text, browserElementSnapshotMaxTextChars),
|
|
61
|
+
textTruncated: element.textTruncated === true || typeof element.text === "string" && element.text.length > browserElementSnapshotMaxTextChars
|
|
62
|
+
},
|
|
63
|
+
ancestors: Array.isArray(snapshot.ancestors) ? snapshot.ancestors.slice(0, 8).flatMap(
|
|
64
|
+
(item) => isRecord(item) ? [
|
|
65
|
+
{
|
|
66
|
+
id: nullableBoundedString(item.id, 500),
|
|
67
|
+
role: nullableBoundedString(item.role, 200),
|
|
68
|
+
selector: boundedString(item.selector, 2e3),
|
|
69
|
+
tagName: boundedString(item.tagName, 100).toLowerCase()
|
|
70
|
+
}
|
|
71
|
+
] : []
|
|
72
|
+
) : [],
|
|
73
|
+
viewport: {
|
|
74
|
+
devicePixelRatio: finiteNumber(viewport.devicePixelRatio, 1),
|
|
75
|
+
height: finiteNumber(viewport.height),
|
|
76
|
+
scrollX: finiteNumber(viewport.scrollX),
|
|
77
|
+
scrollY: finiteNumber(viewport.scrollY),
|
|
78
|
+
width: finiteNumber(viewport.width)
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
if (!normalized.element.tagName || !normalized.element.domPath) return null;
|
|
82
|
+
return { snapshot: normalized, status: "selected" };
|
|
83
|
+
}
|
|
84
|
+
function serializeBrowserElementSnapshot(snapshot) {
|
|
85
|
+
const { bounds } = snapshot.element;
|
|
86
|
+
return [
|
|
87
|
+
`DOM Path: ${snapshot.element.domPath}`,
|
|
88
|
+
`Position: top=${formatPixel(bounds.y)}, left=${formatPixel(bounds.x)}, width=${formatPixel(bounds.width)}, height=${formatPixel(bounds.height)}`,
|
|
89
|
+
`HTML Element: ${compactHtmlFragment(snapshot.element.html)}`
|
|
90
|
+
].join("\n");
|
|
91
|
+
}
|
|
92
|
+
function formatPixel(value) {
|
|
93
|
+
const rounded = Math.round(value * 100) / 100;
|
|
94
|
+
return `${Object.is(rounded, -0) ? 0 : rounded}px`;
|
|
95
|
+
}
|
|
96
|
+
function compactHtmlFragment(value) {
|
|
97
|
+
return value.replace(/\r?\n/gu, " ").replace(/\s{2,}/gu, " ").trim();
|
|
98
|
+
}
|
|
99
|
+
function sanitizeSnapshotUrl(value) {
|
|
100
|
+
try {
|
|
101
|
+
const url = new URL(value);
|
|
102
|
+
url.username = "";
|
|
103
|
+
url.password = "";
|
|
104
|
+
url.hash = "";
|
|
105
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
106
|
+
if (/(?:token|auth|password|secret|session|cookie|key|signature)/iu.test(
|
|
107
|
+
key
|
|
108
|
+
)) {
|
|
109
|
+
url.searchParams.set(key, "[redacted]");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return url.toString();
|
|
113
|
+
} catch {
|
|
114
|
+
return boundedString(value, 4e3);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function boundedString(value, maxChars) {
|
|
118
|
+
return typeof value === "string" ? value.slice(0, maxChars) : "";
|
|
119
|
+
}
|
|
120
|
+
function nullableBoundedString(value, maxChars) {
|
|
121
|
+
const normalized = boundedString(value, maxChars).trim();
|
|
122
|
+
return normalized || null;
|
|
123
|
+
}
|
|
124
|
+
function boundedStringArray(value, maxItems, maxChars) {
|
|
125
|
+
return Array.isArray(value) ? value.slice(0, maxItems).filter((item) => typeof item === "string").map((item) => item.slice(0, maxChars)) : [];
|
|
126
|
+
}
|
|
127
|
+
function boundedStringRecord(value, maxItems, maxKeyChars, maxValueChars) {
|
|
128
|
+
if (!isRecord(value)) return {};
|
|
129
|
+
return Object.fromEntries(
|
|
130
|
+
Object.entries(value).slice(0, maxItems).flatMap(
|
|
131
|
+
([key, item]) => typeof item === "string" ? [[key.slice(0, maxKeyChars), item.slice(0, maxValueChars)]] : []
|
|
132
|
+
)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function finiteNumber(value, fallback = 0) {
|
|
136
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
137
|
+
}
|
|
138
|
+
function isRecord(value) {
|
|
139
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// workbench/browser-element-context/browserElementSelectorScript.ts
|
|
143
|
+
function runTuttiBrowserElementSelector() {
|
|
144
|
+
const selectorGlobal = globalThis;
|
|
145
|
+
selectorGlobal.__tuttiBrowserElementSelector?.cancel();
|
|
146
|
+
return new Promise((resolve) => {
|
|
147
|
+
const overlay = document.createElement("div");
|
|
148
|
+
overlay.setAttribute("data-tutti-browser-element-highlight", "true");
|
|
149
|
+
Object.assign(overlay.style, {
|
|
150
|
+
background: "rgba(86, 156, 214, 0.12)",
|
|
151
|
+
border: "2px solid rgb(86, 156, 214)",
|
|
152
|
+
borderRadius: "3px",
|
|
153
|
+
boxSizing: "border-box",
|
|
154
|
+
display: "none",
|
|
155
|
+
left: "0",
|
|
156
|
+
pointerEvents: "none",
|
|
157
|
+
position: "fixed",
|
|
158
|
+
top: "0",
|
|
159
|
+
zIndex: "2147483647"
|
|
160
|
+
});
|
|
161
|
+
document.documentElement.append(overlay);
|
|
162
|
+
const previousCursor = document.documentElement.style.cursor;
|
|
163
|
+
document.documentElement.style.cursor = "crosshair";
|
|
164
|
+
const finish = (value) => {
|
|
165
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
166
|
+
document.removeEventListener("click", handleClick, true);
|
|
167
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
168
|
+
document.documentElement.style.cursor = previousCursor;
|
|
169
|
+
overlay.remove();
|
|
170
|
+
delete selectorGlobal.__tuttiBrowserElementSelector;
|
|
171
|
+
resolve(value);
|
|
172
|
+
};
|
|
173
|
+
const cancel = () => finish({ status: "cancelled" });
|
|
174
|
+
selectorGlobal.__tuttiBrowserElementSelector = { cancel };
|
|
175
|
+
function handleMouseMove(event) {
|
|
176
|
+
const target = event.target;
|
|
177
|
+
if (!(target instanceof Element) || target === overlay) return;
|
|
178
|
+
const rect = target.getBoundingClientRect();
|
|
179
|
+
Object.assign(overlay.style, {
|
|
180
|
+
display: "block",
|
|
181
|
+
height: `${Math.max(0, rect.height)}px`,
|
|
182
|
+
transform: `translate(${rect.left}px, ${rect.top}px)`,
|
|
183
|
+
width: `${Math.max(0, rect.width)}px`
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function handleClick(event) {
|
|
187
|
+
const target = event.target;
|
|
188
|
+
if (!(target instanceof Element) || target === overlay) return;
|
|
189
|
+
event.preventDefault();
|
|
190
|
+
event.stopImmediatePropagation();
|
|
191
|
+
finish({ snapshot: captureSnapshot(target), status: "selected" });
|
|
192
|
+
}
|
|
193
|
+
function handleKeyDown(event) {
|
|
194
|
+
if (event.key !== "Escape") return;
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
event.stopImmediatePropagation();
|
|
197
|
+
cancel();
|
|
198
|
+
}
|
|
199
|
+
function captureSnapshot(target) {
|
|
200
|
+
const rect = target.getBoundingClientRect();
|
|
201
|
+
const rawText = isFormControl(target) ? "" : (target.textContent ?? "").replace(/\s+/gu, " ").trim();
|
|
202
|
+
const clone = target.cloneNode(true);
|
|
203
|
+
clone.querySelectorAll("script,style,noscript,template").forEach((item) => item.remove());
|
|
204
|
+
sanitizeElement(clone);
|
|
205
|
+
clone.querySelectorAll("*").forEach(sanitizeElement);
|
|
206
|
+
const rawHtml = clone.outerHTML;
|
|
207
|
+
const computed = getComputedStyle(target);
|
|
208
|
+
const styleNames = [
|
|
209
|
+
"display",
|
|
210
|
+
"position",
|
|
211
|
+
"color",
|
|
212
|
+
"background-color",
|
|
213
|
+
"font-family",
|
|
214
|
+
"font-size",
|
|
215
|
+
"font-weight",
|
|
216
|
+
"line-height",
|
|
217
|
+
"margin",
|
|
218
|
+
"padding",
|
|
219
|
+
"border",
|
|
220
|
+
"border-radius",
|
|
221
|
+
"width",
|
|
222
|
+
"height",
|
|
223
|
+
"flex",
|
|
224
|
+
"grid-template-columns",
|
|
225
|
+
"align-items",
|
|
226
|
+
"justify-content",
|
|
227
|
+
"overflow",
|
|
228
|
+
"opacity",
|
|
229
|
+
"visibility"
|
|
230
|
+
];
|
|
231
|
+
return {
|
|
232
|
+
format: "tutti.browser-element.v1",
|
|
233
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
234
|
+
page: {
|
|
235
|
+
title: document.title,
|
|
236
|
+
url: sanitizeUrl(location.href)
|
|
237
|
+
},
|
|
238
|
+
element: {
|
|
239
|
+
ariaLabel: target.getAttribute("aria-label"),
|
|
240
|
+
attributes: readAttributes(target),
|
|
241
|
+
bounds: {
|
|
242
|
+
height: rect.height,
|
|
243
|
+
width: rect.width,
|
|
244
|
+
x: rect.x,
|
|
245
|
+
y: rect.y
|
|
246
|
+
},
|
|
247
|
+
classes: [...target.classList].slice(0, 24),
|
|
248
|
+
domPath: domPathFor(target),
|
|
249
|
+
html: rawHtml.slice(0, 32e3),
|
|
250
|
+
htmlTruncated: rawHtml.length > 32e3,
|
|
251
|
+
id: target.id || null,
|
|
252
|
+
role: target.getAttribute("role"),
|
|
253
|
+
selector: selectorFor(target),
|
|
254
|
+
styles: Object.fromEntries(
|
|
255
|
+
styleNames.map((name) => [name, computed.getPropertyValue(name)])
|
|
256
|
+
),
|
|
257
|
+
tagName: target.tagName.toLowerCase(),
|
|
258
|
+
text: rawText.slice(0, 4e3),
|
|
259
|
+
textTruncated: rawText.length > 4e3
|
|
260
|
+
},
|
|
261
|
+
ancestors: readAncestors(target),
|
|
262
|
+
viewport: {
|
|
263
|
+
devicePixelRatio: globalThis.devicePixelRatio,
|
|
264
|
+
height: globalThis.innerHeight,
|
|
265
|
+
scrollX: globalThis.scrollX,
|
|
266
|
+
scrollY: globalThis.scrollY,
|
|
267
|
+
width: globalThis.innerWidth
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function sanitizeElement(element) {
|
|
272
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement || element instanceof HTMLOptionElement) {
|
|
273
|
+
element.removeAttribute("value");
|
|
274
|
+
if ("value" in element) element.value = "";
|
|
275
|
+
if (element instanceof HTMLTextAreaElement) element.textContent = "";
|
|
276
|
+
}
|
|
277
|
+
for (const attribute of [...element.attributes]) {
|
|
278
|
+
const name = attribute.name.toLowerCase();
|
|
279
|
+
if (name.startsWith("on") || name === "nonce" || name === "integrity" || name === "srcdoc" || /(?:token|auth|password|secret|session|cookie|api[-_]?key)/iu.test(
|
|
280
|
+
name
|
|
281
|
+
)) {
|
|
282
|
+
element.setAttribute(attribute.name, "[redacted]");
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (name === "href" || name === "src" || name === "action") {
|
|
286
|
+
element.setAttribute(attribute.name, sanitizeUrl(attribute.value));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function isFormControl(element) {
|
|
291
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
292
|
+
}
|
|
293
|
+
function readAttributes(element) {
|
|
294
|
+
const result = {};
|
|
295
|
+
for (const attribute of [...element.attributes].slice(0, 40)) {
|
|
296
|
+
const name = attribute.name.toLowerCase();
|
|
297
|
+
if (name.startsWith("on") || name === "value" || name === "srcdoc") {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
result[attribute.name] = /(?:token|auth|password|secret|session|cookie|api[-_]?key)/iu.test(
|
|
301
|
+
name
|
|
302
|
+
) ? "[redacted]" : name === "href" || name === "src" || name === "action" ? sanitizeUrl(attribute.value) : attribute.value.slice(0, 2e3);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
function sanitizeUrl(value) {
|
|
307
|
+
try {
|
|
308
|
+
const url = new URL(value, location.href);
|
|
309
|
+
url.username = "";
|
|
310
|
+
url.password = "";
|
|
311
|
+
url.hash = "";
|
|
312
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
313
|
+
if (/(?:token|auth|password|secret|session|cookie|key|signature)/iu.test(
|
|
314
|
+
key
|
|
315
|
+
)) {
|
|
316
|
+
url.searchParams.set(key, "[redacted]");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return url.toString();
|
|
320
|
+
} catch {
|
|
321
|
+
return value.slice(0, 4e3);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function selectorFor(element) {
|
|
325
|
+
if (element.id) return `#${escapeCss(element.id)}`;
|
|
326
|
+
const segments = [];
|
|
327
|
+
let current = element;
|
|
328
|
+
while (current && segments.length < 8) {
|
|
329
|
+
let segment = current.tagName.toLowerCase();
|
|
330
|
+
const parentElement = current.parentElement;
|
|
331
|
+
if (parentElement) {
|
|
332
|
+
const currentTagName = current.tagName;
|
|
333
|
+
const siblings = [...parentElement.children].filter(
|
|
334
|
+
(item) => item.tagName === currentTagName
|
|
335
|
+
);
|
|
336
|
+
if (siblings.length > 1) {
|
|
337
|
+
segment += `:nth-of-type(${siblings.indexOf(current) + 1})`;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
segments.unshift(segment);
|
|
341
|
+
current = parentElement;
|
|
342
|
+
}
|
|
343
|
+
return segments.join(" > ");
|
|
344
|
+
}
|
|
345
|
+
function domPathFor(element) {
|
|
346
|
+
const appRoot = document.querySelector("#app");
|
|
347
|
+
const root = appRoot?.contains(element) === true ? appRoot : document.body ?? document.documentElement;
|
|
348
|
+
const segments = [];
|
|
349
|
+
let current = element;
|
|
350
|
+
while (current) {
|
|
351
|
+
segments.unshift(domPathSegment(current, current === root));
|
|
352
|
+
if (current === root) break;
|
|
353
|
+
current = current.parentElement;
|
|
354
|
+
}
|
|
355
|
+
return segments.join(" > ").slice(0, 4e3);
|
|
356
|
+
}
|
|
357
|
+
function domPathSegment(element, isRoot) {
|
|
358
|
+
if (isRoot && element.id === "app") return "#app";
|
|
359
|
+
const tagName = element.tagName.toLowerCase();
|
|
360
|
+
const classNames = [...element.classList].filter(Boolean).slice(0, 6).map((name) => `.${name}`).join("");
|
|
361
|
+
if (classNames) return `${tagName}${classNames}`;
|
|
362
|
+
if (element.id) return `${tagName}#${element.id}`;
|
|
363
|
+
return tagName;
|
|
364
|
+
}
|
|
365
|
+
function escapeCss(value) {
|
|
366
|
+
return globalThis.CSS?.escape ? globalThis.CSS.escape(value) : value.replace(/[^a-zA-Z0-9_-]/gu, (character) => `\\${character}`);
|
|
367
|
+
}
|
|
368
|
+
function readAncestors(element) {
|
|
369
|
+
const result = [];
|
|
370
|
+
let current = element.parentElement;
|
|
371
|
+
while (current && result.length < 8) {
|
|
372
|
+
result.push({
|
|
373
|
+
id: current.id || null,
|
|
374
|
+
role: current.getAttribute("role"),
|
|
375
|
+
selector: selectorFor(current),
|
|
376
|
+
tagName: current.tagName.toLowerCase()
|
|
377
|
+
});
|
|
378
|
+
current = current.parentElement;
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
383
|
+
document.addEventListener("click", handleClick, true);
|
|
384
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
var browserElementSelectorScript = `(${runTuttiBrowserElementSelector.toString()})()`;
|
|
388
|
+
var cancelBrowserElementSelectorScript = "globalThis.__tuttiBrowserElementSelector?.cancel();";
|
|
389
|
+
|
|
390
|
+
// workbench/browser-element-context/browserElementWebview.ts
|
|
391
|
+
var browserElementWebviewReadyTimeoutMs = 2e3;
|
|
392
|
+
function isBrowserElementWebviewReady(webview) {
|
|
393
|
+
if (!webview.isConnected) return false;
|
|
394
|
+
try {
|
|
395
|
+
const webContentsId = webview.getWebContentsId?.();
|
|
396
|
+
return typeof webContentsId === "number" && Number.isFinite(webContentsId);
|
|
397
|
+
} catch {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
async function waitForBrowserElementWebviewReady(webview, timeoutMs = browserElementWebviewReadyTimeoutMs) {
|
|
402
|
+
if (isBrowserElementWebviewReady(webview)) return true;
|
|
403
|
+
if (!webview.isConnected) return false;
|
|
404
|
+
return new Promise((resolve) => {
|
|
405
|
+
let settled = false;
|
|
406
|
+
let timeoutSignal = null;
|
|
407
|
+
const finish = (ready) => {
|
|
408
|
+
if (settled) return;
|
|
409
|
+
settled = true;
|
|
410
|
+
timeoutSignal?.removeEventListener("abort", handleTimeout);
|
|
411
|
+
webview.removeEventListener("dom-ready", handleDomReady);
|
|
412
|
+
resolve(ready);
|
|
413
|
+
};
|
|
414
|
+
const handleDomReady = () => {
|
|
415
|
+
finish(isBrowserElementWebviewReady(webview));
|
|
416
|
+
};
|
|
417
|
+
timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
418
|
+
const handleTimeout = () => finish(false);
|
|
419
|
+
timeoutSignal.addEventListener("abort", handleTimeout, { once: true });
|
|
420
|
+
webview.addEventListener("dom-ready", handleDomReady, { once: true });
|
|
421
|
+
if (isBrowserElementWebviewReady(webview)) finish(true);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
async function executeBrowserElementWebviewScript(webview, script, userGesture = false) {
|
|
425
|
+
if (!webview.executeJavaScript) {
|
|
426
|
+
throw new Error("Browser webview JavaScript execution is unavailable");
|
|
427
|
+
}
|
|
428
|
+
if (!await waitForBrowserElementWebviewReady(webview)) {
|
|
429
|
+
throw new Error("Browser webview is not ready");
|
|
430
|
+
}
|
|
431
|
+
return webview.executeJavaScript(script, userGesture);
|
|
432
|
+
}
|
|
433
|
+
async function cancelBrowserElementWebviewSelection(webview, script, onError) {
|
|
434
|
+
if (!webview?.executeJavaScript || !webview.isConnected) return;
|
|
435
|
+
try {
|
|
436
|
+
await webview.executeJavaScript(script);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
if (onError) {
|
|
439
|
+
onError(error);
|
|
440
|
+
} else {
|
|
441
|
+
console.warn(
|
|
442
|
+
"[agent-gui] browser element selection cleanup failed",
|
|
443
|
+
error
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// workbench/browser-element-context/browserElementMention.ts
|
|
450
|
+
import { createRichTextMentionMarkdown } from "@tutti-os/ui-rich-text/core";
|
|
451
|
+
var browserElementMentionKind = "browser-element";
|
|
452
|
+
function createBrowserElementMentionMarkdown(reference) {
|
|
453
|
+
const tagName = normalizeBrowserElementTagName(reference.tagName);
|
|
454
|
+
const context = reference.context.trim();
|
|
455
|
+
const workspaceId = reference.workspaceId.trim();
|
|
456
|
+
if (!tagName || !context || !workspaceId) {
|
|
457
|
+
return "";
|
|
458
|
+
}
|
|
459
|
+
return createRichTextMentionMarkdown({
|
|
460
|
+
providerId: browserElementMentionKind,
|
|
461
|
+
entityId: reference.id,
|
|
462
|
+
label: tagName,
|
|
463
|
+
scope: { context, tag: tagName, workspaceId }
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
function browserElementMentionLabel(tagName) {
|
|
467
|
+
const normalized = normalizeBrowserElementTagName(tagName);
|
|
468
|
+
return normalized ? `<${normalized}>` : "";
|
|
469
|
+
}
|
|
470
|
+
function presentBrowserElementMention(mention) {
|
|
471
|
+
const label = browserElementMentionLabel(
|
|
472
|
+
mention.scope?.tag?.trim() || mention.label
|
|
473
|
+
);
|
|
474
|
+
if (!label) {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
const workspaceId = mention.scope?.workspaceId?.trim() ?? "";
|
|
478
|
+
return {
|
|
479
|
+
name: label,
|
|
480
|
+
...workspaceId ? { workspaceId } : {}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function normalizeBrowserElementTagName(value) {
|
|
484
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9:-]/gu, "").slice(0, 100);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// workbench/browser-element-context/browserElementContextSelectionController.ts
|
|
488
|
+
var BrowserElementContextSelectionController = class {
|
|
489
|
+
activeWebview = null;
|
|
490
|
+
detachFrame = null;
|
|
491
|
+
input;
|
|
492
|
+
listeners = /* @__PURE__ */ new Set();
|
|
493
|
+
session = null;
|
|
494
|
+
snapshot = { state: "idle" };
|
|
495
|
+
subscribedWebview = null;
|
|
496
|
+
constructor(input) {
|
|
497
|
+
this.input = input;
|
|
498
|
+
}
|
|
499
|
+
getSnapshot = () => this.snapshot;
|
|
500
|
+
subscribe = (listener) => {
|
|
501
|
+
this.listeners.add(listener);
|
|
502
|
+
return () => this.listeners.delete(listener);
|
|
503
|
+
};
|
|
504
|
+
configure(input) {
|
|
505
|
+
this.input = input;
|
|
506
|
+
}
|
|
507
|
+
bindAction(node, activeWebview) {
|
|
508
|
+
if (node) {
|
|
509
|
+
if (this.detachFrame !== null) {
|
|
510
|
+
cancelAnimationFrame(this.detachFrame);
|
|
511
|
+
this.detachFrame = null;
|
|
512
|
+
}
|
|
513
|
+
this.moveToActiveWebview(activeWebview);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (this.detachFrame !== null) cancelAnimationFrame(this.detachFrame);
|
|
517
|
+
this.detachFrame = requestAnimationFrame(() => {
|
|
518
|
+
this.detachFrame = null;
|
|
519
|
+
this.dispose();
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
toggle(activeWebview) {
|
|
523
|
+
if (this.session) {
|
|
524
|
+
this.endSelection(this.session);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (!activeWebview?.executeJavaScript) {
|
|
528
|
+
this.input.onError(this.input.failedCopy);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const session = {
|
|
532
|
+
attempt: 0,
|
|
533
|
+
navigationPending: false,
|
|
534
|
+
webview: null
|
|
535
|
+
};
|
|
536
|
+
this.session = session;
|
|
537
|
+
this.setState("selecting");
|
|
538
|
+
this.moveToActiveWebview(activeWebview);
|
|
539
|
+
}
|
|
540
|
+
handleStartLoading = () => {
|
|
541
|
+
if (this.session) this.session.navigationPending = true;
|
|
542
|
+
};
|
|
543
|
+
handleDomReady = () => {
|
|
544
|
+
const session = this.session;
|
|
545
|
+
const webview = this.activeWebview;
|
|
546
|
+
if (!session || !webview) return;
|
|
547
|
+
session.navigationPending = false;
|
|
548
|
+
void this.moveSelectionToWebview(session, webview, true);
|
|
549
|
+
};
|
|
550
|
+
moveToActiveWebview(webview) {
|
|
551
|
+
this.activeWebview = webview;
|
|
552
|
+
const session = this.session;
|
|
553
|
+
if (!session) return;
|
|
554
|
+
if (!webview) {
|
|
555
|
+
const previousWebview = session.webview;
|
|
556
|
+
session.webview = null;
|
|
557
|
+
session.attempt += 1;
|
|
558
|
+
this.unsubscribeFromWebview();
|
|
559
|
+
void cancelBrowserElementWebviewSelection(
|
|
560
|
+
previousWebview,
|
|
561
|
+
cancelBrowserElementSelectorScript
|
|
562
|
+
);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
this.subscribeToWebview(webview);
|
|
566
|
+
void this.moveSelectionToWebview(session, webview);
|
|
567
|
+
}
|
|
568
|
+
subscribeToWebview(webview) {
|
|
569
|
+
if (this.subscribedWebview === webview) return;
|
|
570
|
+
this.unsubscribeFromWebview();
|
|
571
|
+
this.subscribedWebview = webview;
|
|
572
|
+
webview.addEventListener("did-start-loading", this.handleStartLoading);
|
|
573
|
+
webview.addEventListener("dom-ready", this.handleDomReady);
|
|
574
|
+
}
|
|
575
|
+
unsubscribeFromWebview() {
|
|
576
|
+
this.subscribedWebview?.removeEventListener(
|
|
577
|
+
"did-start-loading",
|
|
578
|
+
this.handleStartLoading
|
|
579
|
+
);
|
|
580
|
+
this.subscribedWebview?.removeEventListener(
|
|
581
|
+
"dom-ready",
|
|
582
|
+
this.handleDomReady
|
|
583
|
+
);
|
|
584
|
+
this.subscribedWebview = null;
|
|
585
|
+
}
|
|
586
|
+
async moveSelectionToWebview(session, webview, force = false) {
|
|
587
|
+
if (this.session !== session) return;
|
|
588
|
+
if (!force && session.webview === webview && session.attempt > 0) return;
|
|
589
|
+
const previousWebview = session.webview;
|
|
590
|
+
session.webview = webview;
|
|
591
|
+
session.navigationPending = false;
|
|
592
|
+
const attempt = ++session.attempt;
|
|
593
|
+
await cancelBrowserElementWebviewSelection(
|
|
594
|
+
previousWebview && (force || previousWebview !== webview) ? previousWebview : null,
|
|
595
|
+
cancelBrowserElementSelectorScript
|
|
596
|
+
);
|
|
597
|
+
if (!this.isCurrentSelectionAttempt(session, attempt)) return;
|
|
598
|
+
void this.runSelectionAttempt(session, webview, attempt);
|
|
599
|
+
}
|
|
600
|
+
async runSelectionAttempt(session, webview, attempt) {
|
|
601
|
+
try {
|
|
602
|
+
const rawResult = await executeBrowserElementWebviewScript(
|
|
603
|
+
webview,
|
|
604
|
+
browserElementSelectorScript,
|
|
605
|
+
true
|
|
606
|
+
);
|
|
607
|
+
if (!this.isCurrentSelectionAttempt(session, attempt)) return;
|
|
608
|
+
const result = normalizeBrowserElementSelectionResult(rawResult);
|
|
609
|
+
if (!result || result.status === "cancelled") {
|
|
610
|
+
this.endSelection(session);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const content = serializeBrowserElementSnapshot(result.snapshot);
|
|
614
|
+
const mention = createBrowserElementMentionMarkdown({
|
|
615
|
+
context: content,
|
|
616
|
+
id: createBrowserElementReferenceId(),
|
|
617
|
+
tagName: result.snapshot.element.tagName,
|
|
618
|
+
workspaceId: this.input.workspaceId
|
|
619
|
+
});
|
|
620
|
+
if (!mention)
|
|
621
|
+
throw new Error("Browser element mention could not be created");
|
|
622
|
+
this.input.onAppendMention(mention);
|
|
623
|
+
this.endSelection(session);
|
|
624
|
+
} catch {
|
|
625
|
+
if (!this.isCurrentSelectionAttempt(session, attempt)) return;
|
|
626
|
+
if (session.navigationPending) return;
|
|
627
|
+
this.input.onError(this.input.failedCopy);
|
|
628
|
+
this.endSelection(session);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
isCurrentSelectionAttempt(session, attempt) {
|
|
632
|
+
return this.session === session && session.attempt === attempt;
|
|
633
|
+
}
|
|
634
|
+
endSelection(session) {
|
|
635
|
+
if (this.session !== session) return;
|
|
636
|
+
this.session = null;
|
|
637
|
+
session.attempt += 1;
|
|
638
|
+
const webview = session.webview;
|
|
639
|
+
session.webview = null;
|
|
640
|
+
this.unsubscribeFromWebview();
|
|
641
|
+
void cancelBrowserElementWebviewSelection(
|
|
642
|
+
webview,
|
|
643
|
+
cancelBrowserElementSelectorScript
|
|
644
|
+
);
|
|
645
|
+
this.setState("idle");
|
|
646
|
+
}
|
|
647
|
+
setState(state) {
|
|
648
|
+
if (this.snapshot.state === state) return;
|
|
649
|
+
this.snapshot = { state };
|
|
650
|
+
for (const listener of this.listeners) listener(this.snapshot);
|
|
651
|
+
}
|
|
652
|
+
dispose() {
|
|
653
|
+
const session = this.session;
|
|
654
|
+
if (session) this.endSelection(session);
|
|
655
|
+
this.unsubscribeFromWebview();
|
|
656
|
+
this.activeWebview = null;
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
function createBrowserElementReferenceId() {
|
|
660
|
+
return `browser-element:${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// workbench/browser-element-context/BrowserElementContextAction.tsx
|
|
664
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
665
|
+
function BrowserElementContextAction({
|
|
666
|
+
copy,
|
|
667
|
+
onAppendMention,
|
|
668
|
+
onError,
|
|
669
|
+
workspaceId
|
|
670
|
+
}) {
|
|
671
|
+
const activeWebview = useActiveBrowserNodeWebview();
|
|
672
|
+
const [controller] = useState(
|
|
673
|
+
() => new BrowserElementContextSelectionController({
|
|
674
|
+
failedCopy: copy.failed,
|
|
675
|
+
onAppendMention,
|
|
676
|
+
onError,
|
|
677
|
+
workspaceId
|
|
678
|
+
})
|
|
679
|
+
);
|
|
680
|
+
controller.configure({
|
|
681
|
+
failedCopy: copy.failed,
|
|
682
|
+
onAppendMention,
|
|
683
|
+
onError,
|
|
684
|
+
workspaceId
|
|
685
|
+
});
|
|
686
|
+
const state = useEngineSelector(controller, (snapshot) => snapshot.state);
|
|
687
|
+
const bindAction = useCallback(
|
|
688
|
+
(node) => controller.bindAction(node, activeWebview),
|
|
689
|
+
[activeWebview, controller]
|
|
690
|
+
);
|
|
691
|
+
const label = state === "selecting" ? copy.cancel : copy.select;
|
|
692
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
693
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
694
|
+
Button,
|
|
695
|
+
{
|
|
696
|
+
"aria-label": label,
|
|
697
|
+
"aria-pressed": state === "selecting",
|
|
698
|
+
className: cn(
|
|
699
|
+
"nodrag shrink-0 rounded-md",
|
|
700
|
+
state === "selecting" && "bg-[var(--transparency-block)] text-[var(--text-primary)]"
|
|
701
|
+
),
|
|
702
|
+
size: "icon-sm",
|
|
703
|
+
ref: bindAction,
|
|
704
|
+
type: "button",
|
|
705
|
+
variant: "chrome",
|
|
706
|
+
onClick: () => controller.toggle(activeWebview),
|
|
707
|
+
children: /* @__PURE__ */ jsx(InspectIcon, { className: "size-[15px]" })
|
|
708
|
+
}
|
|
709
|
+
) }),
|
|
710
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: label })
|
|
711
|
+
] });
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// workbench/browser-element-context/registerBrowserElementMention.tsx
|
|
715
|
+
import { Badge } from "@tutti-os/ui-system";
|
|
716
|
+
import { InspectIcon as InspectIcon2 } from "@tutti-os/ui-system/icons";
|
|
717
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
718
|
+
function registerBrowserElementMention() {
|
|
719
|
+
registerAgentCustomMentionKind({
|
|
720
|
+
kind: browserElementMentionKind,
|
|
721
|
+
materializePromptText: (mention) => {
|
|
722
|
+
const context = mention.scope?.context?.trim();
|
|
723
|
+
return context ? `
|
|
724
|
+
${context}
|
|
725
|
+
` : null;
|
|
726
|
+
},
|
|
727
|
+
present: presentBrowserElementMention,
|
|
728
|
+
renderChip: ({ name }) => /* @__PURE__ */ jsxs2(
|
|
729
|
+
Badge,
|
|
730
|
+
{
|
|
731
|
+
className: "h-5 max-w-full gap-1.5 rounded-[6px] px-2 py-0 font-[var(--font-mono)] text-[13px] font-semibold leading-5",
|
|
732
|
+
"data-agent-browser-element-chip": "true",
|
|
733
|
+
variant: "accent",
|
|
734
|
+
children: [
|
|
735
|
+
/* @__PURE__ */ jsx2(InspectIcon2, { "aria-hidden": "true", className: "size-3.5 shrink-0" }),
|
|
736
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: name })
|
|
737
|
+
]
|
|
738
|
+
}
|
|
739
|
+
)
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
export {
|
|
743
|
+
BrowserElementContextAction,
|
|
744
|
+
browserElementMentionKind,
|
|
745
|
+
browserElementMentionLabel,
|
|
746
|
+
createBrowserElementMentionMarkdown,
|
|
747
|
+
presentBrowserElementMention,
|
|
748
|
+
registerBrowserElementMention
|
|
749
|
+
};
|
|
750
|
+
//# sourceMappingURL=index.js.map
|