@popmelt.com/core 0.2.0 → 0.3.0
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/dist/index.d.mts +2 -0
- package/dist/index.mjs +432 -382
- package/dist/server.mjs +101 -32
- package/package.json +2 -4
package/dist/index.mjs
CHANGED
|
@@ -71,13 +71,20 @@ async function checkBridgeHealth(bridgeUrl = DEFAULT_BRIDGE_URL) {
|
|
|
71
71
|
return null;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
async function sendToBridge(screenshotBlob, feedbackJson, bridgeUrl = DEFAULT_BRIDGE_URL, color, provider, model) {
|
|
74
|
+
async function sendToBridge(screenshotBlob, feedbackJson, bridgeUrl = DEFAULT_BRIDGE_URL, color, provider, model, pastedImages) {
|
|
75
75
|
const formData = new FormData();
|
|
76
76
|
formData.append("screenshot", screenshotBlob, "screenshot.png");
|
|
77
77
|
formData.append("feedback", feedbackJson);
|
|
78
78
|
if (color) formData.append("color", color);
|
|
79
79
|
if (provider) formData.append("provider", provider);
|
|
80
80
|
if (model) formData.append("model", model);
|
|
81
|
+
if (pastedImages) {
|
|
82
|
+
for (const [annotationId, blobs] of pastedImages) {
|
|
83
|
+
for (let i = 0; i < blobs.length; i++) {
|
|
84
|
+
formData.append(`image-${annotationId}-${i}`, blobs[i], `image-${annotationId}-${i}.png`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
81
88
|
const res = await fetch(`${bridgeUrl}/send`, {
|
|
82
89
|
method: "POST",
|
|
83
90
|
body: formData
|
|
@@ -153,12 +160,94 @@ async function sendPlanExecution(screenshotBlob, planId, tasks, bridgeUrl = DEFA
|
|
|
153
160
|
}
|
|
154
161
|
return res.json();
|
|
155
162
|
}
|
|
156
|
-
async function sendReplyToBridge(threadId, reply, bridgeUrl = DEFAULT_BRIDGE_URL, color, provider, model) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
async function sendReplyToBridge(threadId, reply, bridgeUrl = DEFAULT_BRIDGE_URL, color, provider, model, images) {
|
|
164
|
+
let res;
|
|
165
|
+
if (images && images.length > 0) {
|
|
166
|
+
const formData = new FormData();
|
|
167
|
+
const placeholder = new Blob([new Uint8Array([
|
|
168
|
+
137,
|
|
169
|
+
80,
|
|
170
|
+
78,
|
|
171
|
+
71,
|
|
172
|
+
13,
|
|
173
|
+
10,
|
|
174
|
+
26,
|
|
175
|
+
10,
|
|
176
|
+
0,
|
|
177
|
+
0,
|
|
178
|
+
0,
|
|
179
|
+
13,
|
|
180
|
+
73,
|
|
181
|
+
72,
|
|
182
|
+
68,
|
|
183
|
+
82,
|
|
184
|
+
0,
|
|
185
|
+
0,
|
|
186
|
+
0,
|
|
187
|
+
1,
|
|
188
|
+
0,
|
|
189
|
+
0,
|
|
190
|
+
0,
|
|
191
|
+
1,
|
|
192
|
+
8,
|
|
193
|
+
6,
|
|
194
|
+
0,
|
|
195
|
+
0,
|
|
196
|
+
0,
|
|
197
|
+
31,
|
|
198
|
+
21,
|
|
199
|
+
196,
|
|
200
|
+
137,
|
|
201
|
+
0,
|
|
202
|
+
0,
|
|
203
|
+
0,
|
|
204
|
+
10,
|
|
205
|
+
73,
|
|
206
|
+
68,
|
|
207
|
+
65,
|
|
208
|
+
84,
|
|
209
|
+
120,
|
|
210
|
+
156,
|
|
211
|
+
98,
|
|
212
|
+
0,
|
|
213
|
+
0,
|
|
214
|
+
0,
|
|
215
|
+
2,
|
|
216
|
+
0,
|
|
217
|
+
1,
|
|
218
|
+
229,
|
|
219
|
+
39,
|
|
220
|
+
222,
|
|
221
|
+
252,
|
|
222
|
+
0,
|
|
223
|
+
0,
|
|
224
|
+
0,
|
|
225
|
+
0,
|
|
226
|
+
73,
|
|
227
|
+
69,
|
|
228
|
+
78,
|
|
229
|
+
68,
|
|
230
|
+
174,
|
|
231
|
+
66,
|
|
232
|
+
96,
|
|
233
|
+
130
|
|
234
|
+
])], { type: "image/png" });
|
|
235
|
+
formData.append("screenshot", placeholder, "screenshot.png");
|
|
236
|
+
formData.append("feedback", JSON.stringify({ threadId, reply, color, provider, model }));
|
|
237
|
+
for (let i = 0; i < images.length; i++) {
|
|
238
|
+
formData.append(`image-reply-${i}`, images[i], `reply-image-${i}.png`);
|
|
239
|
+
}
|
|
240
|
+
res = await fetch(`${bridgeUrl}/reply`, {
|
|
241
|
+
method: "POST",
|
|
242
|
+
body: formData
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
res = await fetch(`${bridgeUrl}/reply`, {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: { "Content-Type": "application/json" },
|
|
248
|
+
body: JSON.stringify({ threadId, reply, color, provider, model })
|
|
249
|
+
});
|
|
250
|
+
}
|
|
162
251
|
if (!res.ok) {
|
|
163
252
|
const body = await res.text();
|
|
164
253
|
throw new Error(`Bridge returned ${res.status}: ${body}`);
|
|
@@ -526,8 +615,9 @@ function handleFinishPath(state, payload) {
|
|
|
526
615
|
});
|
|
527
616
|
}
|
|
528
617
|
function handleAddText(state, payload) {
|
|
529
|
-
|
|
530
|
-
|
|
618
|
+
var _a;
|
|
619
|
+
const textAnnotation = __spreadValues({
|
|
620
|
+
id: (_a = payload.id) != null ? _a : generateId(),
|
|
531
621
|
type: "text",
|
|
532
622
|
points: [payload.point],
|
|
533
623
|
text: payload.text,
|
|
@@ -540,7 +630,7 @@ function handleAddText(state, payload) {
|
|
|
540
630
|
linkedSelector: payload.linkedSelector,
|
|
541
631
|
linkedAnchor: payload.linkedAnchor,
|
|
542
632
|
elements: payload.elements
|
|
543
|
-
};
|
|
633
|
+
}, payload.imageCount ? { imageCount: payload.imageCount } : {});
|
|
544
634
|
const baseState = payload.groupId ? state : pushToUndoStack(state);
|
|
545
635
|
return __spreadProps(__spreadValues({}, baseState), {
|
|
546
636
|
annotations: [...state.annotations, textAnnotation]
|
|
@@ -550,7 +640,7 @@ function handleUpdateText(state, payload) {
|
|
|
550
640
|
const stateWithUndo = pushToUndoStack(state);
|
|
551
641
|
return __spreadProps(__spreadValues({}, stateWithUndo), {
|
|
552
642
|
annotations: state.annotations.map(
|
|
553
|
-
(a) => a.id === payload.id ? __spreadProps(__spreadValues({}, a), { text: payload.text }) : a
|
|
643
|
+
(a) => a.id === payload.id ? __spreadValues(__spreadProps(__spreadValues({}, a), { text: payload.text }), payload.imageCount != null ? { imageCount: payload.imageCount } : {}) : a
|
|
554
644
|
)
|
|
555
645
|
});
|
|
556
646
|
}
|
|
@@ -884,17 +974,25 @@ function handleSetAnnotationStatus(state, payload) {
|
|
|
884
974
|
}
|
|
885
975
|
function handleSetAnnotationThread(state, payload) {
|
|
886
976
|
const idSet = new Set(payload.ids);
|
|
977
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
978
|
+
for (const a of state.annotations) {
|
|
979
|
+
if (idSet.has(a.id) && a.groupId) groupIds.add(a.groupId);
|
|
980
|
+
}
|
|
887
981
|
return __spreadProps(__spreadValues({}, state), {
|
|
888
982
|
annotations: state.annotations.map(
|
|
889
|
-
(a) => idSet.has(a.id) ? __spreadProps(__spreadValues({}, a), { threadId: payload.threadId }) : a
|
|
983
|
+
(a) => idSet.has(a.id) || a.groupId && groupIds.has(a.groupId) ? __spreadProps(__spreadValues({}, a), { threadId: payload.threadId }) : a
|
|
890
984
|
)
|
|
891
985
|
});
|
|
892
986
|
}
|
|
893
987
|
function handleSetAnnotationQuestion(state, payload) {
|
|
894
988
|
const idSet = new Set(payload.ids);
|
|
989
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
990
|
+
for (const a of state.annotations) {
|
|
991
|
+
if (idSet.has(a.id) && a.groupId) groupIds.add(a.groupId);
|
|
992
|
+
}
|
|
895
993
|
return __spreadProps(__spreadValues({}, state), {
|
|
896
994
|
annotations: state.annotations.map(
|
|
897
|
-
(a) => idSet.has(a.id) ? __spreadProps(__spreadValues({}, a), { status: "waiting_input", question: payload.question, threadId: payload.threadId }) : a
|
|
995
|
+
(a) => idSet.has(a.id) || a.groupId && groupIds.has(a.groupId) ? __spreadProps(__spreadValues({}, a), { status: "waiting_input", question: payload.question, threadId: payload.threadId }) : a
|
|
898
996
|
)
|
|
899
997
|
});
|
|
900
998
|
}
|
|
@@ -1917,25 +2015,26 @@ function buildFeedbackData(annotations, styleModifications = [], inspectedElemen
|
|
|
1917
2015
|
const text = group.find((a) => a.type === "text");
|
|
1918
2016
|
if (shape) {
|
|
1919
2017
|
const linkedSelector = shape.linkedSelector || (text == null ? void 0 : text.linkedSelector);
|
|
1920
|
-
|
|
2018
|
+
const imageCount = (text == null ? void 0 : text.imageCount) || shape.imageCount;
|
|
2019
|
+
annotationDataList.push(__spreadValues(__spreadProps(__spreadValues({
|
|
1921
2020
|
id: shape.id,
|
|
1922
2021
|
type: shape.type,
|
|
1923
2022
|
instruction: text == null ? void 0 : text.text
|
|
1924
2023
|
}, linkedSelector ? { linkedSelector } : {}), {
|
|
1925
2024
|
// Use stored elements (captured at creation time) or empty array
|
|
1926
2025
|
elements: shape.elements || []
|
|
1927
|
-
}));
|
|
2026
|
+
}), imageCount ? { imageCount } : {}));
|
|
1928
2027
|
}
|
|
1929
2028
|
}
|
|
1930
2029
|
for (const annotation of standaloneAnnotations) {
|
|
1931
|
-
annotationDataList.push(__spreadProps(__spreadValues({
|
|
2030
|
+
annotationDataList.push(__spreadValues(__spreadProps(__spreadValues({
|
|
1932
2031
|
id: annotation.id,
|
|
1933
2032
|
type: annotation.type,
|
|
1934
2033
|
instruction: annotation.type === "text" ? annotation.text : void 0
|
|
1935
2034
|
}, annotation.linkedSelector ? { linkedSelector: annotation.linkedSelector } : {}), {
|
|
1936
2035
|
// Use stored elements (captured at creation time) or empty array
|
|
1937
2036
|
elements: annotation.elements || []
|
|
1938
|
-
}));
|
|
2037
|
+
}), annotation.imageCount ? { imageCount: annotation.imageCount } : {}));
|
|
1939
2038
|
}
|
|
1940
2039
|
return __spreadValues({
|
|
1941
2040
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2076,7 +2175,8 @@ function drawAnnotationsToCanvas(ctx, annotations, scrollY, dpr) {
|
|
|
2076
2175
|
const fontSize = annotation.fontSize || 16;
|
|
2077
2176
|
ctx.font = `${fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`;
|
|
2078
2177
|
ctx.fillStyle = annotation.color;
|
|
2079
|
-
const
|
|
2178
|
+
const displayText = annotation.imageCount && annotation.imageCount > 0 ? `[${annotation.imageCount} image${annotation.imageCount > 1 ? "s" : ""}] ${annotation.text}` : annotation.text;
|
|
2179
|
+
const lines = displayText.split("\n");
|
|
2080
2180
|
const lineHeight = fontSize * 1.2;
|
|
2081
2181
|
const padding = 4;
|
|
2082
2182
|
let maxWidth = 0;
|
|
@@ -7025,7 +7125,7 @@ function calculateLinkedPosition(rect, anchor, stackOffset = 0) {
|
|
|
7025
7125
|
const y = anchor === "top-left" ? rect.top + window.scrollY - BADGE_HEIGHT - stackOffset * BADGE_HEIGHT + PADDING : rect.bottom + window.scrollY + PADDING - 1 + stackOffset * BADGE_HEIGHT;
|
|
7026
7126
|
return { x, y };
|
|
7027
7127
|
}
|
|
7028
|
-
function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds, inFlightStyleSelectors, inFlightSelectorColors, onReply, onViewThread,
|
|
7128
|
+
function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds, inFlightStyleSelectors, inFlightSelectorColors, onAttachImages, onReply, onViewThread, activePlan }) {
|
|
7029
7129
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
7030
7130
|
const { canvasRef, redrawAll, resizeCanvas } = useCanvasDrawing();
|
|
7031
7131
|
const [isDrawing, setIsDrawing] = useState12(false);
|
|
@@ -7722,26 +7822,39 @@ function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds
|
|
|
7722
7822
|
return () => window.removeEventListener("mousemove", handleMouseMove);
|
|
7723
7823
|
}, [activeText, findTextAtPoint]);
|
|
7724
7824
|
const commitActiveText = useCallback5(() => {
|
|
7825
|
+
var _a2;
|
|
7725
7826
|
if (!activeText) return;
|
|
7726
|
-
|
|
7827
|
+
const imageCount = ((_a2 = activeText.images) == null ? void 0 : _a2.length) || 0;
|
|
7828
|
+
if (activeText.text.trim() || imageCount > 0) {
|
|
7727
7829
|
if (activeText.isNew) {
|
|
7830
|
+
const annotationId = generateId();
|
|
7728
7831
|
dispatch({
|
|
7729
7832
|
type: "ADD_TEXT",
|
|
7730
|
-
payload: {
|
|
7833
|
+
payload: __spreadValues({
|
|
7731
7834
|
point: activeText.point,
|
|
7732
|
-
text: activeText.text,
|
|
7835
|
+
text: activeText.text || (imageCount > 0 ? `[${imageCount} image${imageCount > 1 ? "s" : ""}]` : ""),
|
|
7733
7836
|
fontSize: activeText.fontSize,
|
|
7837
|
+
id: annotationId,
|
|
7734
7838
|
groupId: activeText.groupId,
|
|
7735
7839
|
linkedSelector: activeText.linkedSelector,
|
|
7736
7840
|
linkedAnchor: activeText.linkedAnchor,
|
|
7737
7841
|
elements: activeText.elements
|
|
7738
|
-
}
|
|
7842
|
+
}, imageCount > 0 ? { imageCount } : {})
|
|
7739
7843
|
});
|
|
7844
|
+
if (imageCount > 0 && activeText.images && onAttachImages) {
|
|
7845
|
+
onAttachImages(annotationId, activeText.images);
|
|
7846
|
+
}
|
|
7740
7847
|
} else {
|
|
7741
7848
|
dispatch({
|
|
7742
7849
|
type: "UPDATE_TEXT",
|
|
7743
|
-
payload: {
|
|
7850
|
+
payload: __spreadValues({
|
|
7851
|
+
id: activeText.id,
|
|
7852
|
+
text: activeText.text || (imageCount > 0 ? `[${imageCount} image${imageCount > 1 ? "s" : ""}]` : "")
|
|
7853
|
+
}, imageCount > 0 ? { imageCount } : {})
|
|
7744
7854
|
});
|
|
7855
|
+
if (imageCount > 0 && activeText.images && onAttachImages) {
|
|
7856
|
+
onAttachImages(activeText.id, activeText.images);
|
|
7857
|
+
}
|
|
7745
7858
|
}
|
|
7746
7859
|
} else if (!activeText.isNew) {
|
|
7747
7860
|
dispatch({
|
|
@@ -7750,7 +7863,7 @@ function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds
|
|
|
7750
7863
|
});
|
|
7751
7864
|
}
|
|
7752
7865
|
setActiveText(null);
|
|
7753
|
-
}, [activeText, dispatch]);
|
|
7866
|
+
}, [activeText, dispatch, onAttachImages]);
|
|
7754
7867
|
const snapPadding = useCallback5((value) => {
|
|
7755
7868
|
for (let i = 0; i < PADDING_SNAP_STEPS2.length - 1; i++) {
|
|
7756
7869
|
const lo = PADDING_SNAP_STEPS2[i];
|
|
@@ -8841,6 +8954,24 @@ function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds
|
|
|
8841
8954
|
commitActiveText();
|
|
8842
8955
|
}
|
|
8843
8956
|
}, [commitActiveText]);
|
|
8957
|
+
const handleTextPaste = useCallback5((e) => {
|
|
8958
|
+
if (!activeText) return;
|
|
8959
|
+
const items = e.clipboardData.items;
|
|
8960
|
+
const imageBlobs = [];
|
|
8961
|
+
for (let i = 0; i < items.length; i++) {
|
|
8962
|
+
const item = items[i];
|
|
8963
|
+
if (item.type.startsWith("image/")) {
|
|
8964
|
+
const file = item.getAsFile();
|
|
8965
|
+
if (file) imageBlobs.push(file);
|
|
8966
|
+
}
|
|
8967
|
+
}
|
|
8968
|
+
if (imageBlobs.length > 0) {
|
|
8969
|
+
e.preventDefault();
|
|
8970
|
+
setActiveText((prev) => prev ? __spreadProps(__spreadValues({}, prev), {
|
|
8971
|
+
images: [...prev.images || [], ...imageBlobs]
|
|
8972
|
+
}) : null);
|
|
8973
|
+
}
|
|
8974
|
+
}, [activeText]);
|
|
8844
8975
|
const handleContextMenu = useCallback5((e) => {
|
|
8845
8976
|
if (state.activeTool !== "hand" || !state.isAnnotating) return;
|
|
8846
8977
|
e.preventDefault();
|
|
@@ -9030,10 +9161,36 @@ function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds
|
|
|
9030
9161
|
value: activeText.text,
|
|
9031
9162
|
onChange: handleTextChange,
|
|
9032
9163
|
onKeyDown: handleTextKeyDown,
|
|
9164
|
+
onPaste: handleTextPaste,
|
|
9033
9165
|
onBlur: commitActiveText,
|
|
9034
9166
|
placeholder: "Type here...",
|
|
9035
9167
|
style: textInputStyle
|
|
9036
9168
|
}
|
|
9169
|
+
),
|
|
9170
|
+
activeText.images && activeText.images.length > 0 && /* @__PURE__ */ jsxs9(
|
|
9171
|
+
"div",
|
|
9172
|
+
{
|
|
9173
|
+
"data-devtools": true,
|
|
9174
|
+
style: {
|
|
9175
|
+
position: "fixed",
|
|
9176
|
+
left: activeText.point.x - PADDING - scroll.x,
|
|
9177
|
+
top: activeText.point.y - PADDING - scroll.y - 20,
|
|
9178
|
+
zIndex: 1e4,
|
|
9179
|
+
fontSize: 11,
|
|
9180
|
+
fontFamily: "system-ui, sans-serif",
|
|
9181
|
+
color: "#fff",
|
|
9182
|
+
backgroundColor: "rgba(0,0,0,0.7)",
|
|
9183
|
+
padding: "2px 6px",
|
|
9184
|
+
borderRadius: 3,
|
|
9185
|
+
whiteSpace: "nowrap"
|
|
9186
|
+
},
|
|
9187
|
+
children: [
|
|
9188
|
+
activeText.images.length,
|
|
9189
|
+
" image",
|
|
9190
|
+
activeText.images.length > 1 ? "s" : "",
|
|
9191
|
+
" attached"
|
|
9192
|
+
]
|
|
9193
|
+
}
|
|
9037
9194
|
)
|
|
9038
9195
|
] }),
|
|
9039
9196
|
state.isAnnotating && state.activeTool !== "hand" && state.styleModifications.length > 0 && /* @__PURE__ */ jsx10(
|
|
@@ -9054,29 +9211,16 @@ function AnnotationCanvas({ state, dispatch, onScreenshot, inFlightAnnotationIds
|
|
|
9054
9211
|
accentColor: state.activeColor
|
|
9055
9212
|
}
|
|
9056
9213
|
),
|
|
9057
|
-
state.isAnnotating && inFlightAnnotationIds && inFlightAnnotationIds.size > 0 && /* @__PURE__ */ jsx10(
|
|
9058
|
-
ThinkingSpinners,
|
|
9059
|
-
{
|
|
9060
|
-
annotations: state.annotations,
|
|
9061
|
-
inFlightIds: inFlightAnnotationIds,
|
|
9062
|
-
scrollX: scroll.x,
|
|
9063
|
-
scrollY: scroll.y,
|
|
9064
|
-
annotationGroupMap,
|
|
9065
|
-
onViewThread,
|
|
9066
|
-
onSelectAnnotation: selectAnnotation
|
|
9067
|
-
}
|
|
9068
|
-
),
|
|
9069
9214
|
state.isAnnotating && /* @__PURE__ */ jsx10(
|
|
9070
|
-
|
|
9215
|
+
AnnotationBadges,
|
|
9071
9216
|
{
|
|
9072
9217
|
annotations: state.annotations,
|
|
9073
9218
|
supersededAnnotations,
|
|
9219
|
+
inFlightIds: inFlightAnnotationIds,
|
|
9074
9220
|
scrollX: scroll.x,
|
|
9075
9221
|
scrollY: scroll.y,
|
|
9076
9222
|
annotationGroupMap,
|
|
9077
|
-
onReply,
|
|
9078
9223
|
onViewThread,
|
|
9079
|
-
isThreadPanelOpen,
|
|
9080
9224
|
onSelectAnnotation: selectAnnotation
|
|
9081
9225
|
}
|
|
9082
9226
|
),
|
|
@@ -9262,8 +9406,9 @@ var THINKING_WORDS2 = [
|
|
|
9262
9406
|
"riffing"
|
|
9263
9407
|
];
|
|
9264
9408
|
var WORD_INTERVAL2 = 3e3;
|
|
9265
|
-
function
|
|
9409
|
+
function AnnotationBadges({
|
|
9266
9410
|
annotations,
|
|
9411
|
+
supersededAnnotations,
|
|
9267
9412
|
inFlightIds,
|
|
9268
9413
|
scrollX,
|
|
9269
9414
|
scrollY,
|
|
@@ -9271,10 +9416,12 @@ function ThinkingSpinners({
|
|
|
9271
9416
|
onViewThread,
|
|
9272
9417
|
onSelectAnnotation
|
|
9273
9418
|
}) {
|
|
9274
|
-
var _a;
|
|
9419
|
+
var _a, _b;
|
|
9275
9420
|
const [charIndex, setCharIndex] = useState12(0);
|
|
9276
9421
|
const [wordIndex, setWordIndex] = useState12(() => Math.floor(Math.random() * THINKING_WORDS2.length));
|
|
9422
|
+
const hasInFlight = !!(inFlightIds && inFlightIds.size > 0);
|
|
9277
9423
|
useEffect15(() => {
|
|
9424
|
+
if (!hasInFlight) return;
|
|
9278
9425
|
const charTimer = setInterval(() => {
|
|
9279
9426
|
setCharIndex((i) => (i + 1) % SPINNER_FRAME_COUNT2);
|
|
9280
9427
|
}, SPINNER_INTERVAL2);
|
|
@@ -9285,14 +9432,25 @@ function ThinkingSpinners({
|
|
|
9285
9432
|
clearInterval(charTimer);
|
|
9286
9433
|
clearInterval(wordTimer);
|
|
9287
9434
|
};
|
|
9288
|
-
}, []);
|
|
9289
|
-
const
|
|
9435
|
+
}, [hasInFlight]);
|
|
9436
|
+
const badges = [];
|
|
9290
9437
|
for (const annotation of annotations) {
|
|
9291
9438
|
if (annotation.type !== "text" || !annotation.text || !annotation.points[0]) continue;
|
|
9292
|
-
|
|
9293
|
-
|
|
9439
|
+
if (supersededAnnotations.has(annotation)) continue;
|
|
9440
|
+
const groupAnns = annotation.groupId ? annotations.filter((a) => a.groupId === annotation.groupId) : [annotation];
|
|
9441
|
+
const isInFlight = !!(inFlightIds && (inFlightIds.has(annotation.id) || groupAnns.some((a) => inFlightIds.has(a.id))));
|
|
9442
|
+
const status = (_a = annotation.status) != null ? _a : "pending";
|
|
9443
|
+
const groupMateResolved = groupAnns.some(
|
|
9444
|
+
(a) => a.status === "resolved" || a.status === "needs_review"
|
|
9294
9445
|
);
|
|
9295
|
-
|
|
9446
|
+
const hasThread = groupAnns.some((a) => a.threadId);
|
|
9447
|
+
if (!isInFlight && status !== "resolved" && status !== "needs_review" && !groupMateResolved && !hasThread) continue;
|
|
9448
|
+
const threadId = annotation.threadId || ((_b = groupAnns.find((a) => a.threadId)) == null ? void 0 : _b.threadId);
|
|
9449
|
+
const isNeedsReview = status === "needs_review" || groupAnns.some((a) => a.status === "needs_review");
|
|
9450
|
+
const replyCount = groupAnns.reduce((n, a) => {
|
|
9451
|
+
var _a2;
|
|
9452
|
+
return n + ((_a2 = a.replyCount) != null ? _a2 : 0);
|
|
9453
|
+
}, 0) || 1;
|
|
9296
9454
|
const point = annotation.points[0];
|
|
9297
9455
|
const fontSize = annotation.fontSize || 12;
|
|
9298
9456
|
const lineHeightPx = fontSize * LINE_HEIGHT;
|
|
@@ -9305,26 +9463,24 @@ function ThinkingSpinners({
|
|
|
9305
9463
|
ctx.font = `${fontSize}px ${FONT_FAMILY}`;
|
|
9306
9464
|
const maxWidth = Math.min(MAX_DISPLAY_WIDTH, Math.max(...displayLines.map((line) => ctx.measureText(line).width)));
|
|
9307
9465
|
const totalHeight = displayLines.length * lineHeightPx;
|
|
9308
|
-
|
|
9309
|
-
const groupAnns = annotation.groupId ? annotations.filter((a) => a.groupId === annotation.groupId) : [annotation];
|
|
9310
|
-
const threadId = annotation.threadId || ((_a = groupAnns.find((a) => a.threadId)) == null ? void 0 : _a.threadId);
|
|
9311
|
-
spinnerPositions.push({
|
|
9466
|
+
badges.push({
|
|
9312
9467
|
id: annotation.id,
|
|
9313
9468
|
threadId,
|
|
9314
9469
|
x: point.x + maxWidth + PADDING,
|
|
9315
|
-
// right edge of text bg
|
|
9316
9470
|
y: point.y - PADDING,
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9471
|
+
size: totalHeight + PADDING * 2,
|
|
9472
|
+
color: annotation.color,
|
|
9473
|
+
isInFlight,
|
|
9474
|
+
isNeedsReview,
|
|
9475
|
+
replyCount
|
|
9320
9476
|
});
|
|
9321
9477
|
}
|
|
9322
|
-
if (
|
|
9478
|
+
if (badges.length === 0) return null;
|
|
9323
9479
|
const clickable = !!onViewThread;
|
|
9324
|
-
return /* @__PURE__ */ jsx10(Fragment6, { children:
|
|
9480
|
+
return /* @__PURE__ */ jsx10(Fragment6, { children: badges.map((pos) => /* @__PURE__ */ jsx10(
|
|
9325
9481
|
"div",
|
|
9326
9482
|
{
|
|
9327
|
-
"data-devtools":
|
|
9483
|
+
"data-devtools": "annotation-badge",
|
|
9328
9484
|
onClick: clickable && pos.threadId ? () => {
|
|
9329
9485
|
onSelectAnnotation == null ? void 0 : onSelectAnnotation(pos.id);
|
|
9330
9486
|
onViewThread(pos.threadId);
|
|
@@ -9337,7 +9493,7 @@ function ThinkingSpinners({
|
|
|
9337
9493
|
display: "flex",
|
|
9338
9494
|
alignItems: "center",
|
|
9339
9495
|
pointerEvents: clickable ? "auto" : "none",
|
|
9340
|
-
cursor: clickable ? "pointer" : void 0,
|
|
9496
|
+
cursor: clickable && pos.threadId ? "pointer" : void 0,
|
|
9341
9497
|
zIndex: 9999,
|
|
9342
9498
|
backgroundColor: pos.color,
|
|
9343
9499
|
fontFamily: FONT_FAMILY,
|
|
@@ -9348,7 +9504,7 @@ function ThinkingSpinners({
|
|
|
9348
9504
|
gap: 4,
|
|
9349
9505
|
whiteSpace: "nowrap"
|
|
9350
9506
|
},
|
|
9351
|
-
children: [
|
|
9507
|
+
children: pos.isInFlight ? /* @__PURE__ */ jsxs9(Fragment6, { children: [
|
|
9352
9508
|
/* @__PURE__ */ jsx10("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "currentColor", style: { verticalAlign: "middle" }, children: charIndex === 1 ? /* @__PURE__ */ jsxs9(Fragment6, { children: [
|
|
9353
9509
|
/* @__PURE__ */ jsx10("circle", { cx: "7", cy: "7", r: "2" }),
|
|
9354
9510
|
/* @__PURE__ */ jsx10("circle", { cx: "17", cy: "7", r: "2" }),
|
|
@@ -9361,287 +9517,23 @@ function ThinkingSpinners({
|
|
|
9361
9517
|
/* @__PURE__ */ jsx10("circle", { cx: "12", cy: "18", r: "2" })
|
|
9362
9518
|
] }) }),
|
|
9363
9519
|
/* @__PURE__ */ jsx10("span", { style: { opacity: 0.7 }, children: THINKING_WORDS2[wordIndex] })
|
|
9364
|
-
]
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
}
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
isThreadPanelOpen,
|
|
9378
|
-
onSelectAnnotation
|
|
9379
|
-
}) {
|
|
9380
|
-
var _a;
|
|
9381
|
-
const badgePositions = [];
|
|
9382
|
-
for (const annotation of annotations) {
|
|
9383
|
-
if (annotation.type !== "text" || !annotation.text || !annotation.points[0]) continue;
|
|
9384
|
-
if (supersededAnnotations.has(annotation)) continue;
|
|
9385
|
-
const status = (_a = annotation.status) != null ? _a : "pending";
|
|
9386
|
-
const groupAnns = annotation.groupId ? annotations.filter((a) => a.groupId === annotation.groupId) : [annotation];
|
|
9387
|
-
const groupMateResolved = groupAnns.some(
|
|
9388
|
-
(a) => a.status === "resolved" || a.status === "needs_review"
|
|
9389
|
-
);
|
|
9390
|
-
const hasThread = groupAnns.some((a) => a.threadId);
|
|
9391
|
-
if (status !== "resolved" && status !== "needs_review" && !groupMateResolved && !hasThread) continue;
|
|
9392
|
-
const isNeedsReview = status === "needs_review" || groupAnns.some((a) => a.status === "needs_review");
|
|
9393
|
-
const point = annotation.points[0];
|
|
9394
|
-
const fontSize = annotation.fontSize || 12;
|
|
9395
|
-
const lineHeightPx = fontSize * LINE_HEIGHT;
|
|
9396
|
-
const lines = annotation.text.split("\n");
|
|
9397
|
-
const groupNumber = annotationGroupMap.get(annotation.id);
|
|
9398
|
-
const displayLines = groupNumber !== void 0 ? [groupNumber + ". " + (lines[0] || ""), ...lines.slice(1)] : lines;
|
|
9399
|
-
const canvas = document.createElement("canvas");
|
|
9400
|
-
const ctx = canvas.getContext("2d");
|
|
9401
|
-
if (!ctx) continue;
|
|
9402
|
-
ctx.font = `${fontSize}px ${FONT_FAMILY}`;
|
|
9403
|
-
const maxWidth = Math.min(MAX_DISPLAY_WIDTH, Math.max(...displayLines.map((line) => ctx.measureText(line).width)));
|
|
9404
|
-
const totalHeight = displayLines.length * lineHeightPx;
|
|
9405
|
-
const annotationHeight = totalHeight + PADDING * 2;
|
|
9406
|
-
badgePositions.push({
|
|
9407
|
-
annotation,
|
|
9408
|
-
x: point.x + maxWidth + PADDING,
|
|
9409
|
-
y: point.y - PADDING,
|
|
9410
|
-
size: annotationHeight,
|
|
9411
|
-
isNeedsReview: !!isNeedsReview,
|
|
9412
|
-
groupNumber
|
|
9413
|
-
});
|
|
9414
|
-
}
|
|
9415
|
-
if (badgePositions.length === 0) return null;
|
|
9416
|
-
return /* @__PURE__ */ jsx10(Fragment6, { children: badgePositions.map(({ annotation, x, y, size, isNeedsReview, groupNumber }) => /* @__PURE__ */ jsx10(
|
|
9417
|
-
ResolutionBadge,
|
|
9418
|
-
{
|
|
9419
|
-
annotation,
|
|
9420
|
-
annotations,
|
|
9421
|
-
x: x - scrollX,
|
|
9422
|
-
y: y - scrollY,
|
|
9423
|
-
size,
|
|
9424
|
-
isNeedsReview: !!isNeedsReview,
|
|
9425
|
-
groupNumber,
|
|
9426
|
-
onReply,
|
|
9427
|
-
onViewThread,
|
|
9428
|
-
isThreadPanelOpen,
|
|
9429
|
-
onSelectAnnotation
|
|
9520
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment6, { children: [
|
|
9521
|
+
pos.isNeedsReview ? /* @__PURE__ */ jsx10("span", { style: { fontWeight: 700 }, children: "?" }) : /* @__PURE__ */ jsxs9("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [
|
|
9522
|
+
/* @__PURE__ */ jsx10("line", { x1: "12", y1: "3", x2: "12", y2: "9" }),
|
|
9523
|
+
/* @__PURE__ */ jsx10("line", { x1: "12", y1: "15", x2: "12", y2: "21" }),
|
|
9524
|
+
/* @__PURE__ */ jsx10("line", { x1: "3", y1: "12", x2: "9", y2: "12" }),
|
|
9525
|
+
/* @__PURE__ */ jsx10("line", { x1: "15", y1: "12", x2: "21", y2: "12" })
|
|
9526
|
+
] }),
|
|
9527
|
+
/* @__PURE__ */ jsxs9("span", { style: { opacity: 0.7 }, children: [
|
|
9528
|
+
pos.replyCount,
|
|
9529
|
+
" ",
|
|
9530
|
+
pos.replyCount === 1 ? "reply" : "replies"
|
|
9531
|
+
] })
|
|
9532
|
+
] })
|
|
9430
9533
|
},
|
|
9431
|
-
|
|
9534
|
+
pos.id
|
|
9432
9535
|
)) });
|
|
9433
9536
|
}
|
|
9434
|
-
function ResolutionBadge({
|
|
9435
|
-
annotation,
|
|
9436
|
-
annotations,
|
|
9437
|
-
x,
|
|
9438
|
-
y,
|
|
9439
|
-
size,
|
|
9440
|
-
isNeedsReview,
|
|
9441
|
-
groupNumber,
|
|
9442
|
-
onReply,
|
|
9443
|
-
onViewThread,
|
|
9444
|
-
isThreadPanelOpen,
|
|
9445
|
-
onSelectAnnotation
|
|
9446
|
-
}) {
|
|
9447
|
-
var _a, _b;
|
|
9448
|
-
const [expanded, setExpanded] = useState12(false);
|
|
9449
|
-
const [replyText, setReplyText] = useState12("");
|
|
9450
|
-
const textareaRef = useRef5(null);
|
|
9451
|
-
const panelRef = useRef5(null);
|
|
9452
|
-
useEffect15(() => {
|
|
9453
|
-
if (expanded && textareaRef.current) {
|
|
9454
|
-
textareaRef.current.focus();
|
|
9455
|
-
}
|
|
9456
|
-
}, [expanded]);
|
|
9457
|
-
useEffect15(() => {
|
|
9458
|
-
if (!expanded) return;
|
|
9459
|
-
const handleClickOutside = (e) => {
|
|
9460
|
-
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
9461
|
-
setExpanded(false);
|
|
9462
|
-
}
|
|
9463
|
-
};
|
|
9464
|
-
const handleEscape = (e) => {
|
|
9465
|
-
if (e.key === "Escape") setExpanded(false);
|
|
9466
|
-
};
|
|
9467
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
9468
|
-
document.addEventListener("keydown", handleEscape);
|
|
9469
|
-
return () => {
|
|
9470
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
9471
|
-
document.removeEventListener("keydown", handleEscape);
|
|
9472
|
-
};
|
|
9473
|
-
}, [expanded]);
|
|
9474
|
-
const groupAnnotations = annotation.groupId ? annotations.filter((a) => a.groupId === annotation.groupId) : [annotation];
|
|
9475
|
-
const textAnn = groupAnnotations.find((a) => a.type === "text");
|
|
9476
|
-
const userMessage = (textAnn == null ? void 0 : textAnn.text) || "(no text)";
|
|
9477
|
-
const summary = (_a = groupAnnotations.find((a) => a.resolutionSummary)) == null ? void 0 : _a.resolutionSummary;
|
|
9478
|
-
const threadId = (_b = groupAnnotations.find((a) => a.threadId)) == null ? void 0 : _b.threadId;
|
|
9479
|
-
const handleSubmit = useCallback5(() => {
|
|
9480
|
-
if (!replyText.trim() || !threadId || !onReply) return;
|
|
9481
|
-
onReply(threadId, replyText.trim());
|
|
9482
|
-
setReplyText("");
|
|
9483
|
-
setExpanded(false);
|
|
9484
|
-
}, [replyText, threadId, onReply]);
|
|
9485
|
-
const handleKeyDown = useCallback5((e) => {
|
|
9486
|
-
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
9487
|
-
e.preventDefault();
|
|
9488
|
-
handleSubmit();
|
|
9489
|
-
}
|
|
9490
|
-
}, [handleSubmit]);
|
|
9491
|
-
return /* @__PURE__ */ jsxs9(
|
|
9492
|
-
"div",
|
|
9493
|
-
{
|
|
9494
|
-
ref: panelRef,
|
|
9495
|
-
"data-devtools": "resolution-badge",
|
|
9496
|
-
style: {
|
|
9497
|
-
position: "fixed",
|
|
9498
|
-
left: x,
|
|
9499
|
-
top: y,
|
|
9500
|
-
zIndex: expanded ? 10002 : 9999,
|
|
9501
|
-
pointerEvents: "auto"
|
|
9502
|
-
},
|
|
9503
|
-
children: [
|
|
9504
|
-
!expanded && /* @__PURE__ */ jsxs9(
|
|
9505
|
-
"div",
|
|
9506
|
-
{
|
|
9507
|
-
onClick: () => {
|
|
9508
|
-
onSelectAnnotation == null ? void 0 : onSelectAnnotation(annotation.id);
|
|
9509
|
-
if (threadId && onViewThread) {
|
|
9510
|
-
onViewThread(threadId);
|
|
9511
|
-
}
|
|
9512
|
-
},
|
|
9513
|
-
style: {
|
|
9514
|
-
height: size,
|
|
9515
|
-
display: "flex",
|
|
9516
|
-
alignItems: "center",
|
|
9517
|
-
cursor: "pointer",
|
|
9518
|
-
backgroundColor: annotation.color,
|
|
9519
|
-
fontFamily: FONT_FAMILY,
|
|
9520
|
-
fontSize: 12,
|
|
9521
|
-
color: "#ffffff",
|
|
9522
|
-
userSelect: "none",
|
|
9523
|
-
padding: `0 ${PADDING}px`,
|
|
9524
|
-
gap: 4,
|
|
9525
|
-
whiteSpace: "nowrap"
|
|
9526
|
-
},
|
|
9527
|
-
children: [
|
|
9528
|
-
isNeedsReview ? /* @__PURE__ */ jsx10("span", { style: { fontWeight: 700 }, children: "?" }) : /* @__PURE__ */ jsxs9("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", children: [
|
|
9529
|
-
/* @__PURE__ */ jsx10("line", { x1: "12", y1: "3", x2: "12", y2: "9" }),
|
|
9530
|
-
/* @__PURE__ */ jsx10("line", { x1: "12", y1: "15", x2: "12", y2: "21" }),
|
|
9531
|
-
/* @__PURE__ */ jsx10("line", { x1: "3", y1: "12", x2: "9", y2: "12" }),
|
|
9532
|
-
/* @__PURE__ */ jsx10("line", { x1: "15", y1: "12", x2: "21", y2: "12" })
|
|
9533
|
-
] }),
|
|
9534
|
-
/* @__PURE__ */ jsx10("span", { style: { opacity: 0.7 }, children: (() => {
|
|
9535
|
-
const groupAnns = annotation.groupId ? annotations.filter((a) => a.groupId === annotation.groupId) : [annotation];
|
|
9536
|
-
const count = groupAnns.reduce((n, a) => {
|
|
9537
|
-
var _a2;
|
|
9538
|
-
return n + ((_a2 = a.replyCount) != null ? _a2 : 0);
|
|
9539
|
-
}, 0) || 1;
|
|
9540
|
-
return `${count} ${count === 1 ? "reply" : "replies"}`;
|
|
9541
|
-
})() })
|
|
9542
|
-
]
|
|
9543
|
-
}
|
|
9544
|
-
),
|
|
9545
|
-
expanded && /* @__PURE__ */ jsxs9(
|
|
9546
|
-
"div",
|
|
9547
|
-
{
|
|
9548
|
-
style: {
|
|
9549
|
-
minWidth: 280,
|
|
9550
|
-
maxWidth: 400,
|
|
9551
|
-
backgroundColor: "#ffffff",
|
|
9552
|
-
fontFamily: FONT_FAMILY,
|
|
9553
|
-
fontSize: 12,
|
|
9554
|
-
color: "#1f2937",
|
|
9555
|
-
border: "1px solid rgba(0, 0, 0, 0.1)"
|
|
9556
|
-
},
|
|
9557
|
-
children: [
|
|
9558
|
-
/* @__PURE__ */ jsx10("div", { style: {
|
|
9559
|
-
padding: `${PADDING + 2}px ${PADDING + 4}px`,
|
|
9560
|
-
backgroundColor: annotation.color,
|
|
9561
|
-
color: "#ffffff",
|
|
9562
|
-
lineHeight: 1.4
|
|
9563
|
-
}, children: userMessage }),
|
|
9564
|
-
summary && /* @__PURE__ */ jsx10("div", { style: {
|
|
9565
|
-
padding: `${PADDING + 2}px ${PADDING + 4}px`,
|
|
9566
|
-
lineHeight: 1.4,
|
|
9567
|
-
borderBottom: "1px solid rgba(0, 0, 0, 0.06)"
|
|
9568
|
-
}, children: summary }),
|
|
9569
|
-
threadId && /* @__PURE__ */ jsxs9("div", { style: { padding: PADDING }, children: [
|
|
9570
|
-
onReply && /* @__PURE__ */ jsxs9(Fragment6, { children: [
|
|
9571
|
-
/* @__PURE__ */ jsx10(
|
|
9572
|
-
"textarea",
|
|
9573
|
-
{
|
|
9574
|
-
ref: textareaRef,
|
|
9575
|
-
value: replyText,
|
|
9576
|
-
onChange: (e) => setReplyText(e.target.value),
|
|
9577
|
-
onKeyDown: handleKeyDown,
|
|
9578
|
-
placeholder: "Reply...",
|
|
9579
|
-
style: {
|
|
9580
|
-
width: "100%",
|
|
9581
|
-
minHeight: 40,
|
|
9582
|
-
padding: PADDING,
|
|
9583
|
-
fontSize: 12,
|
|
9584
|
-
fontFamily: FONT_FAMILY,
|
|
9585
|
-
backgroundColor: "rgba(0, 0, 0, 0.04)",
|
|
9586
|
-
color: "#1f2937",
|
|
9587
|
-
border: "1px solid rgba(0, 0, 0, 0.1)",
|
|
9588
|
-
borderRadius: 0,
|
|
9589
|
-
outline: "none",
|
|
9590
|
-
resize: "vertical",
|
|
9591
|
-
lineHeight: 1.4,
|
|
9592
|
-
boxSizing: "border-box"
|
|
9593
|
-
}
|
|
9594
|
-
}
|
|
9595
|
-
),
|
|
9596
|
-
/* @__PURE__ */ jsx10("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: 4 }, children: /* @__PURE__ */ jsx10(
|
|
9597
|
-
"button",
|
|
9598
|
-
{
|
|
9599
|
-
onClick: handleSubmit,
|
|
9600
|
-
disabled: !replyText.trim(),
|
|
9601
|
-
style: {
|
|
9602
|
-
padding: "4px 12px",
|
|
9603
|
-
fontSize: 11,
|
|
9604
|
-
fontFamily: FONT_FAMILY,
|
|
9605
|
-
fontWeight: 600,
|
|
9606
|
-
backgroundColor: replyText.trim() ? annotation.color : "rgba(0,0,0,0.1)",
|
|
9607
|
-
color: replyText.trim() ? "#ffffff" : "rgba(0,0,0,0.3)",
|
|
9608
|
-
border: "none",
|
|
9609
|
-
cursor: replyText.trim() ? "pointer" : "default"
|
|
9610
|
-
},
|
|
9611
|
-
children: "Send \u2318\u23CE"
|
|
9612
|
-
}
|
|
9613
|
-
) })
|
|
9614
|
-
] }),
|
|
9615
|
-
onViewThread && /* @__PURE__ */ jsx10(
|
|
9616
|
-
"button",
|
|
9617
|
-
{
|
|
9618
|
-
onClick: () => {
|
|
9619
|
-
onViewThread(threadId);
|
|
9620
|
-
setExpanded(false);
|
|
9621
|
-
},
|
|
9622
|
-
style: {
|
|
9623
|
-
width: "100%",
|
|
9624
|
-
padding: "5px 0",
|
|
9625
|
-
fontSize: 11,
|
|
9626
|
-
fontFamily: FONT_FAMILY,
|
|
9627
|
-
fontWeight: 500,
|
|
9628
|
-
backgroundColor: "transparent",
|
|
9629
|
-
color: "#6b7280",
|
|
9630
|
-
border: "1px solid rgba(0, 0, 0, 0.1)",
|
|
9631
|
-
cursor: "pointer",
|
|
9632
|
-
marginTop: onReply ? 8 : 0
|
|
9633
|
-
},
|
|
9634
|
-
children: "View conversation \u2192"
|
|
9635
|
-
}
|
|
9636
|
-
)
|
|
9637
|
-
] })
|
|
9638
|
-
]
|
|
9639
|
-
}
|
|
9640
|
-
)
|
|
9641
|
-
]
|
|
9642
|
-
}
|
|
9643
|
-
);
|
|
9644
|
-
}
|
|
9645
9537
|
function PlanWaitingBadges({
|
|
9646
9538
|
annotations,
|
|
9647
9539
|
supersededAnnotations,
|
|
@@ -10952,7 +10844,9 @@ function AnnotationToolbar({
|
|
|
10952
10844
|
"div",
|
|
10953
10845
|
{
|
|
10954
10846
|
id: "devtools-toolbar",
|
|
10955
|
-
style: __spreadProps(__spreadValues({}, toolbarStyle), { overflow: "visible" }),
|
|
10847
|
+
style: __spreadProps(__spreadValues({}, toolbarStyle), { overflow: "visible", opacity: 0.5, transition: "opacity 150ms ease" }),
|
|
10848
|
+
onMouseEnter: (e) => e.currentTarget.style.opacity = "1",
|
|
10849
|
+
onMouseLeave: (e) => e.currentTarget.style.opacity = "0.5",
|
|
10956
10850
|
children: /* @__PURE__ */ jsx12(
|
|
10957
10851
|
"button",
|
|
10958
10852
|
{
|
|
@@ -11837,13 +11731,10 @@ function ThinkingBadge({ color }) {
|
|
|
11837
11731
|
/* @__PURE__ */ jsx15("span", { style: { fontSize: 11, color: "#9ca3af", fontStyle: "italic" }, children: THINKING_WORDS3[wordIndex] })
|
|
11838
11732
|
] });
|
|
11839
11733
|
}
|
|
11840
|
-
function
|
|
11734
|
+
function formatToolEvent(event) {
|
|
11841
11735
|
var _a;
|
|
11842
|
-
const
|
|
11843
|
-
|
|
11844
|
-
const last = toolEvents[toolEvents.length - 1];
|
|
11845
|
-
const tool = String(last.data.tool || "");
|
|
11846
|
-
const file = last.data.file ? String(last.data.file) : null;
|
|
11736
|
+
const tool = String(event.data.tool || "");
|
|
11737
|
+
const file = event.data.file ? String(event.data.file) : null;
|
|
11847
11738
|
const basename = file ? (_a = file.split("/").pop()) != null ? _a : file : null;
|
|
11848
11739
|
switch (tool) {
|
|
11849
11740
|
case "Read":
|
|
@@ -11866,6 +11757,34 @@ function formatToolStep(events) {
|
|
|
11866
11757
|
return tool ? `Using ${tool}` : null;
|
|
11867
11758
|
}
|
|
11868
11759
|
}
|
|
11760
|
+
function buildStreamSegments(events) {
|
|
11761
|
+
const segments = [];
|
|
11762
|
+
for (const e of events) {
|
|
11763
|
+
if (e.type === "tool_use") {
|
|
11764
|
+
const label = formatToolEvent(e);
|
|
11765
|
+
if (label) segments.push({ kind: "tool", label });
|
|
11766
|
+
} else if (e.type === "delta") {
|
|
11767
|
+
const text = String(e.data.text || "");
|
|
11768
|
+
if (!text) continue;
|
|
11769
|
+
const last = segments[segments.length - 1];
|
|
11770
|
+
if (last && last.kind === "text") {
|
|
11771
|
+
last.text += text;
|
|
11772
|
+
} else {
|
|
11773
|
+
segments.push({ kind: "text", text });
|
|
11774
|
+
}
|
|
11775
|
+
} else if (e.type === "thinking") {
|
|
11776
|
+
const text = String(e.data.text || "");
|
|
11777
|
+
if (!text) continue;
|
|
11778
|
+
const last = segments[segments.length - 1];
|
|
11779
|
+
if (last && last.kind === "thinking") {
|
|
11780
|
+
last.text += text;
|
|
11781
|
+
} else {
|
|
11782
|
+
segments.push({ kind: "thinking", text });
|
|
11783
|
+
}
|
|
11784
|
+
}
|
|
11785
|
+
}
|
|
11786
|
+
return segments;
|
|
11787
|
+
}
|
|
11869
11788
|
function ThreadPanel({
|
|
11870
11789
|
threadId,
|
|
11871
11790
|
bridgeUrl,
|
|
@@ -11887,6 +11806,7 @@ function ThreadPanel({
|
|
|
11887
11806
|
const [messages, setMessages] = useState15([]);
|
|
11888
11807
|
const [loading, setLoading] = useState15(true);
|
|
11889
11808
|
const [replyText, setReplyText] = useState15("");
|
|
11809
|
+
const [replyImages, setReplyImages] = useState15([]);
|
|
11890
11810
|
const scrollRef = useRef9(null);
|
|
11891
11811
|
const panelRef = useRef9(null);
|
|
11892
11812
|
const prevStreamingRef = useRef9(isStreaming);
|
|
@@ -11907,11 +11827,12 @@ function ThreadPanel({
|
|
|
11907
11827
|
}
|
|
11908
11828
|
prevStreamingRef.current = isStreaming;
|
|
11909
11829
|
}, [isStreaming, fetchThread]);
|
|
11830
|
+
const streamSegments = streamingEvents ? buildStreamSegments(streamingEvents) : [];
|
|
11910
11831
|
useEffect19(() => {
|
|
11911
11832
|
if (scrollRef.current) {
|
|
11912
11833
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
11913
11834
|
}
|
|
11914
|
-
}, [messages,
|
|
11835
|
+
}, [messages, streamSegments.length, isStreaming]);
|
|
11915
11836
|
useEffect19(() => {
|
|
11916
11837
|
const handleEscape = (e) => {
|
|
11917
11838
|
if (e.key === "Escape") onClose();
|
|
@@ -11922,24 +11843,38 @@ function ThreadPanel({
|
|
|
11922
11843
|
const handleSubmit = useCallback8(() => {
|
|
11923
11844
|
if (!replyText.trim() || !onReply) return;
|
|
11924
11845
|
const text = replyText.trim();
|
|
11846
|
+
const images = replyImages.length > 0 ? replyImages : void 0;
|
|
11925
11847
|
setMessages((prev) => [...prev, {
|
|
11926
11848
|
role: "human",
|
|
11927
11849
|
timestamp: Date.now(),
|
|
11928
11850
|
jobId: "pending",
|
|
11929
|
-
replyToQuestion: text
|
|
11851
|
+
replyToQuestion: images ? `${text} [${images.length} image${images.length > 1 ? "s" : ""}]` : text
|
|
11930
11852
|
}]);
|
|
11931
|
-
onReply(threadId, text);
|
|
11853
|
+
onReply(threadId, text, images);
|
|
11932
11854
|
setReplyText("");
|
|
11933
|
-
|
|
11855
|
+
setReplyImages([]);
|
|
11856
|
+
}, [replyText, replyImages, threadId, onReply]);
|
|
11857
|
+
const handlePaste = useCallback8((e) => {
|
|
11858
|
+
const items = e.clipboardData.items;
|
|
11859
|
+
const imageBlobs = [];
|
|
11860
|
+
for (let i = 0; i < items.length; i++) {
|
|
11861
|
+
const item = items[i];
|
|
11862
|
+
if (item.type.startsWith("image/")) {
|
|
11863
|
+
const file = item.getAsFile();
|
|
11864
|
+
if (file) imageBlobs.push(file);
|
|
11865
|
+
}
|
|
11866
|
+
}
|
|
11867
|
+
if (imageBlobs.length > 0) {
|
|
11868
|
+
e.preventDefault();
|
|
11869
|
+
setReplyImages((prev) => [...prev, ...imageBlobs]);
|
|
11870
|
+
}
|
|
11871
|
+
}, []);
|
|
11934
11872
|
const handleKeyDown = useCallback8((e) => {
|
|
11935
11873
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
11936
11874
|
e.preventDefault();
|
|
11937
11875
|
handleSubmit();
|
|
11938
11876
|
}
|
|
11939
11877
|
}, [handleSubmit]);
|
|
11940
|
-
const toolStep = streamingEvents ? formatToolStep(streamingEvents) : null;
|
|
11941
|
-
const thinkingText = streamingThinking || "";
|
|
11942
|
-
const responseText = streamingResponse ? stripInternalTags(streamingResponse) : "";
|
|
11943
11878
|
return /* @__PURE__ */ jsxs12(Fragment10, { children: [
|
|
11944
11879
|
/* @__PURE__ */ jsx15(
|
|
11945
11880
|
"div",
|
|
@@ -11987,7 +11922,9 @@ function ThreadPanel({
|
|
|
11987
11922
|
const isHuman = msg.role === "human";
|
|
11988
11923
|
const text = isHuman ? msg.replyToQuestion || msg.feedbackSummary || "(annotation)" : stripInternalTags(msg.responseText || "");
|
|
11989
11924
|
const questionText = !isHuman ? msg.question : void 0;
|
|
11990
|
-
|
|
11925
|
+
const hasResolutions = !isHuman && msg.resolutions && msg.resolutions.length > 0;
|
|
11926
|
+
const hasToolsUsed = !isHuman && msg.toolsUsed && msg.toolsUsed.length > 0;
|
|
11927
|
+
if (!text && !questionText && !hasResolutions) return null;
|
|
11991
11928
|
const isLatest = i === messages.length - 1;
|
|
11992
11929
|
return /* @__PURE__ */ jsxs12(
|
|
11993
11930
|
"div",
|
|
@@ -12020,7 +11957,21 @@ function ThreadPanel({
|
|
|
12020
11957
|
marginTop: text ? 4 : 0,
|
|
12021
11958
|
lineHeight: 1.5,
|
|
12022
11959
|
wordBreak: "break-word"
|
|
12023
|
-
}, children: renderMarkdown(questionText) })
|
|
11960
|
+
}, children: renderMarkdown(questionText) }),
|
|
11961
|
+
(hasToolsUsed || hasResolutions) && /* @__PURE__ */ jsxs12("div", { style: {
|
|
11962
|
+
marginTop: text || questionText ? 6 : 0,
|
|
11963
|
+
padding: "4px 8px",
|
|
11964
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
11965
|
+
fontSize: 11,
|
|
11966
|
+
lineHeight: 1.5,
|
|
11967
|
+
color: "#6b7280"
|
|
11968
|
+
}, children: [
|
|
11969
|
+
hasToolsUsed && /* @__PURE__ */ jsx15("div", { style: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 10 }, children: msg.toolsUsed.map((t, j) => /* @__PURE__ */ jsx15("div", { children: t }, j)) }),
|
|
11970
|
+
hasResolutions && msg.resolutions.map((r, j) => /* @__PURE__ */ jsxs12("div", { style: { marginTop: hasToolsUsed ? 4 : 0 }, children: [
|
|
11971
|
+
/* @__PURE__ */ jsx15("span", { style: { color: r.status === "resolved" ? "#10b981" : "#f59e0b" }, children: r.status === "resolved" ? "Done" : "Needs review" }),
|
|
11972
|
+
r.summary ? ` \u2014 ${r.summary}` : ""
|
|
11973
|
+
] }, j))
|
|
11974
|
+
] })
|
|
12024
11975
|
]
|
|
12025
11976
|
},
|
|
12026
11977
|
`${msg.jobId}-${i}`
|
|
@@ -12117,39 +12068,102 @@ function ThreadPanel({
|
|
|
12117
12068
|
/* @__PURE__ */ jsx15("span", { style: { fontWeight: 600, fontSize: 11, color: "#6b7280" }, children: "Claude Code" }),
|
|
12118
12069
|
/* @__PURE__ */ jsx15("span", { style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsx15(ThinkingBadge, { color: accentColor }) })
|
|
12119
12070
|
] }),
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12071
|
+
streamSegments.map((seg, i) => {
|
|
12072
|
+
if (seg.kind === "tool") {
|
|
12073
|
+
return /* @__PURE__ */ jsx15(
|
|
12074
|
+
"div",
|
|
12075
|
+
{
|
|
12076
|
+
style: {
|
|
12077
|
+
paddingLeft: 12,
|
|
12078
|
+
fontSize: 11,
|
|
12079
|
+
color: "#9ca3af",
|
|
12080
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
12081
|
+
lineHeight: 1.6
|
|
12082
|
+
},
|
|
12083
|
+
children: seg.label
|
|
12084
|
+
},
|
|
12085
|
+
i
|
|
12086
|
+
);
|
|
12087
|
+
}
|
|
12088
|
+
if (seg.kind === "thinking") {
|
|
12089
|
+
return /* @__PURE__ */ jsx15(
|
|
12090
|
+
"div",
|
|
12091
|
+
{
|
|
12092
|
+
style: {
|
|
12093
|
+
paddingLeft: 12,
|
|
12094
|
+
marginTop: 2,
|
|
12095
|
+
marginBottom: 2,
|
|
12096
|
+
fontSize: 11,
|
|
12097
|
+
color: "#9ca3af",
|
|
12098
|
+
fontStyle: "italic",
|
|
12099
|
+
lineHeight: 1.4,
|
|
12100
|
+
whiteSpace: "pre-wrap",
|
|
12101
|
+
wordBreak: "break-word",
|
|
12102
|
+
maxHeight: 80,
|
|
12103
|
+
overflowY: "auto"
|
|
12104
|
+
},
|
|
12105
|
+
children: seg.text
|
|
12106
|
+
},
|
|
12107
|
+
i
|
|
12108
|
+
);
|
|
12109
|
+
}
|
|
12110
|
+
const stripped = stripInternalTags(seg.text);
|
|
12111
|
+
if (!stripped) return null;
|
|
12112
|
+
return /* @__PURE__ */ jsx15(
|
|
12113
|
+
"div",
|
|
12114
|
+
{
|
|
12115
|
+
style: {
|
|
12116
|
+
paddingLeft: 12,
|
|
12117
|
+
marginTop: 2,
|
|
12118
|
+
marginBottom: 2,
|
|
12119
|
+
lineHeight: 1.5,
|
|
12120
|
+
wordBreak: "break-word"
|
|
12121
|
+
},
|
|
12122
|
+
children: renderMarkdown(stripped)
|
|
12123
|
+
},
|
|
12124
|
+
i
|
|
12125
|
+
);
|
|
12126
|
+
})
|
|
12144
12127
|
] })
|
|
12145
12128
|
] }),
|
|
12146
12129
|
onReply && /* @__PURE__ */ jsxs12("div", { style: replyAreaStyle, children: [
|
|
12130
|
+
replyImages.length > 0 && /* @__PURE__ */ jsxs12("div", { style: {
|
|
12131
|
+
fontSize: 11,
|
|
12132
|
+
color: "#6b7280",
|
|
12133
|
+
marginBottom: 4,
|
|
12134
|
+
display: "flex",
|
|
12135
|
+
alignItems: "center",
|
|
12136
|
+
gap: 4
|
|
12137
|
+
}, children: [
|
|
12138
|
+
/* @__PURE__ */ jsxs12("span", { children: [
|
|
12139
|
+
replyImages.length,
|
|
12140
|
+
" image",
|
|
12141
|
+
replyImages.length > 1 ? "s" : "",
|
|
12142
|
+
" attached"
|
|
12143
|
+
] }),
|
|
12144
|
+
/* @__PURE__ */ jsx15(
|
|
12145
|
+
"button",
|
|
12146
|
+
{
|
|
12147
|
+
onClick: () => setReplyImages([]),
|
|
12148
|
+
style: {
|
|
12149
|
+
background: "none",
|
|
12150
|
+
border: "none",
|
|
12151
|
+
cursor: "pointer",
|
|
12152
|
+
fontSize: 11,
|
|
12153
|
+
color: "#9ca3af",
|
|
12154
|
+
padding: "0 2px"
|
|
12155
|
+
},
|
|
12156
|
+
children: "\xD7"
|
|
12157
|
+
}
|
|
12158
|
+
)
|
|
12159
|
+
] }),
|
|
12147
12160
|
/* @__PURE__ */ jsx15(
|
|
12148
12161
|
"textarea",
|
|
12149
12162
|
{
|
|
12150
12163
|
value: replyText,
|
|
12151
12164
|
onChange: (e) => setReplyText(e.target.value),
|
|
12152
12165
|
onKeyDown: handleKeyDown,
|
|
12166
|
+
onPaste: handlePaste,
|
|
12153
12167
|
placeholder: "Reply... (Cmd+Enter to send)",
|
|
12154
12168
|
style: {
|
|
12155
12169
|
width: "100%",
|
|
@@ -12223,6 +12237,7 @@ function PopmeltProvider({
|
|
|
12223
12237
|
var _a, _b, _c, _d, _e;
|
|
12224
12238
|
const [state, dispatch] = useAnnotationState();
|
|
12225
12239
|
const bridge = useBridgeConnection(bridgeUrl);
|
|
12240
|
+
const annotationImagesRef = useRef10(/* @__PURE__ */ new Map());
|
|
12226
12241
|
const [provider, setProvider] = useState16(() => {
|
|
12227
12242
|
if (typeof window === "undefined") return "claude";
|
|
12228
12243
|
return localStorage.getItem(PROVIDER_STORAGE_KEY) || "claude";
|
|
@@ -12556,6 +12571,10 @@ function PopmeltProvider({
|
|
|
12556
12571
|
}
|
|
12557
12572
|
}
|
|
12558
12573
|
}, [activePlan == null ? void 0 : activePlan.planId, state.activeColor, dispatch]);
|
|
12574
|
+
const handleAttachImages = useCallback9((annotationId, images) => {
|
|
12575
|
+
const existing = annotationImagesRef.current.get(annotationId) || [];
|
|
12576
|
+
annotationImagesRef.current.set(annotationId, [...existing, ...images]);
|
|
12577
|
+
}, []);
|
|
12559
12578
|
const handleSendToClaude = useCallback9(async () => {
|
|
12560
12579
|
const canvas = document.getElementById("devtools-canvas");
|
|
12561
12580
|
if (!canvas) return false;
|
|
@@ -12572,9 +12591,37 @@ function PopmeltProvider({
|
|
|
12572
12591
|
if (!stitchedBlob) return false;
|
|
12573
12592
|
const feedbackData = buildFeedbackData(activeAnnotations, state.styleModifications);
|
|
12574
12593
|
const feedbackJson = JSON.stringify(feedbackData);
|
|
12594
|
+
const pastedImages = /* @__PURE__ */ new Map();
|
|
12595
|
+
for (const ann of activeAnnotations) {
|
|
12596
|
+
const blobs2 = annotationImagesRef.current.get(ann.id);
|
|
12597
|
+
if (blobs2 && blobs2.length > 0) {
|
|
12598
|
+
pastedImages.set(ann.id, blobs2);
|
|
12599
|
+
}
|
|
12600
|
+
if (ann.groupId) {
|
|
12601
|
+
for (const mate of activeAnnotations) {
|
|
12602
|
+
if (mate.groupId === ann.groupId && mate.id !== ann.id) {
|
|
12603
|
+
const mateBlobs = annotationImagesRef.current.get(mate.id);
|
|
12604
|
+
if (mateBlobs && mateBlobs.length > 0) {
|
|
12605
|
+
pastedImages.set(mate.id, mateBlobs);
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
}
|
|
12610
|
+
}
|
|
12575
12611
|
try {
|
|
12576
12612
|
const hexColor = cssColorToHex(state.activeColor);
|
|
12577
|
-
const { jobId, threadId: assignedThreadId } = await sendToBridge(
|
|
12613
|
+
const { jobId, threadId: assignedThreadId } = await sendToBridge(
|
|
12614
|
+
stitchedBlob,
|
|
12615
|
+
feedbackJson,
|
|
12616
|
+
bridgeUrl,
|
|
12617
|
+
hexColor,
|
|
12618
|
+
provider,
|
|
12619
|
+
currentModel.id,
|
|
12620
|
+
pastedImages.size > 0 ? pastedImages : void 0
|
|
12621
|
+
);
|
|
12622
|
+
for (const annId of pastedImages.keys()) {
|
|
12623
|
+
annotationImagesRef.current.delete(annId);
|
|
12624
|
+
}
|
|
12578
12625
|
const sentAnnotationIds = activeAnnotations.map((a) => a.id);
|
|
12579
12626
|
const sentStyleSelectors = state.styleModifications.filter((m) => !m.captured).map((m) => m.selector);
|
|
12580
12627
|
setInFlightJobs((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
@@ -12586,6 +12633,9 @@ function PopmeltProvider({
|
|
|
12586
12633
|
}
|
|
12587
12634
|
}));
|
|
12588
12635
|
dispatch({ type: "MARK_CAPTURED" });
|
|
12636
|
+
if (assignedThreadId && sentAnnotationIds.length > 0) {
|
|
12637
|
+
dispatch({ type: "SET_ANNOTATION_THREAD", payload: { ids: sentAnnotationIds, threadId: assignedThreadId } });
|
|
12638
|
+
}
|
|
12589
12639
|
const hueMatch = state.activeColor.match(/oklch\([^)]*\s+([\d.]+)\s*\)/);
|
|
12590
12640
|
const currentHue = (hueMatch == null ? void 0 : hueMatch[1]) ? parseFloat(hueMatch[1]) : 29;
|
|
12591
12641
|
const nextHue = (currentHue + 60) % 360;
|
|
@@ -12596,10 +12646,10 @@ function PopmeltProvider({
|
|
|
12596
12646
|
return false;
|
|
12597
12647
|
}
|
|
12598
12648
|
}, [state.annotations, state.styleModifications, state.activeColor, dispatch, bridgeUrl, provider, currentModel.id]);
|
|
12599
|
-
const handleReply = useCallback9(async (threadId, reply) => {
|
|
12649
|
+
const handleReply = useCallback9(async (threadId, reply, images) => {
|
|
12600
12650
|
try {
|
|
12601
12651
|
const hexColor = cssColorToHex(state.activeColor);
|
|
12602
|
-
const { jobId } = await sendReplyToBridge(threadId, reply, bridgeUrl, hexColor, provider, currentModel.id);
|
|
12652
|
+
const { jobId } = await sendReplyToBridge(threadId, reply, bridgeUrl, hexColor, provider, currentModel.id, images);
|
|
12603
12653
|
setInFlightJobs((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
12604
12654
|
[jobId]: {
|
|
12605
12655
|
annotationIds: [],
|
|
@@ -12856,9 +12906,9 @@ function PopmeltProvider({
|
|
|
12856
12906
|
inFlightAnnotationIds,
|
|
12857
12907
|
inFlightStyleSelectors,
|
|
12858
12908
|
inFlightSelectorColors,
|
|
12909
|
+
onAttachImages: handleAttachImages,
|
|
12859
12910
|
onReply: bridge.isConnected ? handleReply : void 0,
|
|
12860
12911
|
onViewThread: bridge.isConnected ? handleViewThread : void 0,
|
|
12861
|
-
isThreadPanelOpen: openThreadId !== null,
|
|
12862
12912
|
activePlan
|
|
12863
12913
|
}
|
|
12864
12914
|
),
|