cursor-buddy 0.0.7 → 0.0.9-beta.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/{client-Crn8tW7w.d.mts → client-Ba6rv-du.d.mts} +2 -5
- package/dist/client-Ba6rv-du.d.mts.map +1 -0
- package/dist/{client-DZNTKnnD.mjs → client-CevxN9EX.mjs} +159 -105
- package/dist/client-CevxN9EX.mjs.map +1 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -2
- package/dist/point-tool-DtHgq6gQ.mjs +54 -0
- package/dist/point-tool-DtHgq6gQ.mjs.map +1 -0
- package/dist/point-tool-kIviMn1q.d.mts +46 -0
- package/dist/point-tool-kIviMn1q.d.mts.map +1 -0
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.mjs +1 -1
- package/dist/server/adapters/next.d.mts +1 -1
- package/dist/server/index.d.mts +4 -7
- package/dist/server/index.d.mts.map +1 -1
- package/dist/server/index.mjs +124 -36
- package/dist/server/index.mjs.map +1 -1
- package/dist/{types-BxBhjZju.d.mts → types-COQKMo5C.d.mts} +1 -1
- package/dist/{types-BxBhjZju.d.mts.map → types-COQKMo5C.d.mts.map} +1 -1
- package/package.json +3 -2
- package/dist/client-Crn8tW7w.d.mts.map +0 -1
- package/dist/client-DZNTKnnD.mjs.map +0 -1
|
@@ -42,10 +42,7 @@ type VoiceEvent = {
|
|
|
42
42
|
error: Error;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
|
-
* Point coordinates
|
|
46
|
-
* Supports two formats:
|
|
47
|
-
* - Marker-based: [POINT:5:label] - references a numbered marker
|
|
48
|
-
* - Coordinate-based: [POINT:640,360:label] - raw pixel coordinates
|
|
45
|
+
* Point coordinates for cursor pointing.
|
|
49
46
|
*/
|
|
50
47
|
interface PointingTarget {
|
|
51
48
|
/** X coordinate in viewport pixels (top-left origin) */
|
|
@@ -460,4 +457,4 @@ declare class CursorBuddyClient {
|
|
|
460
457
|
}
|
|
461
458
|
//#endregion
|
|
462
459
|
export { CursorBuddySnapshot as a, CursorRenderProps as c, SpeechBubbleRenderProps as d, VoiceEvent as f, CursorBuddyMediaMode as i, Point as l, WaveformRenderProps as m, BrowserSpeechPort as n, CursorBuddySpeechConfig as o, VoiceState as p, CursorBuddyClientOptions as r, CursorBuddyTranscriptionConfig as s, CursorBuddyClient as t, PointingTarget as u };
|
|
463
|
-
//# sourceMappingURL=client-
|
|
460
|
+
//# sourceMappingURL=client-Ba6rv-du.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-Ba6rv-du.d.mts","names":[],"sources":["../src/core/utils/elements.ts","../src/core/types.ts","../src/core/client.ts"],"mappings":"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"}
|
|
@@ -21,80 +21,6 @@ const $isEnabled = atom(true);
|
|
|
21
21
|
atom(false);
|
|
22
22
|
const $conversationHistory = atom([]);
|
|
23
23
|
//#endregion
|
|
24
|
-
//#region src/core/pointing.ts
|
|
25
|
-
/**
|
|
26
|
-
* Parses POINT tags from AI responses.
|
|
27
|
-
*
|
|
28
|
-
* Supports two formats:
|
|
29
|
-
* - Marker-based: [POINT:5:label] - 3 parts, references a numbered marker
|
|
30
|
-
* - Coordinate-based: [POINT:640,360:label] - 4 parts, raw pixel coordinates
|
|
31
|
-
*/
|
|
32
|
-
const POINTING_TAG_REGEX = /\[POINT:(\d+)(?:,(\d+))?:([^\]]+)\]\s*$/;
|
|
33
|
-
const PARTIAL_POINTING_PREFIXES = new Set([
|
|
34
|
-
"[",
|
|
35
|
-
"[P",
|
|
36
|
-
"[PO",
|
|
37
|
-
"[POI",
|
|
38
|
-
"[POIN",
|
|
39
|
-
"[POINT",
|
|
40
|
-
"[POINT:"
|
|
41
|
-
]);
|
|
42
|
-
function stripTrailingPointingTag(response, trimResult) {
|
|
43
|
-
const stripped = response.replace(POINTING_TAG_REGEX, "");
|
|
44
|
-
return trimResult ? stripped.trim() : stripped;
|
|
45
|
-
}
|
|
46
|
-
function getPartialPointingTagStart(response) {
|
|
47
|
-
const lastOpenBracket = response.lastIndexOf("[");
|
|
48
|
-
if (lastOpenBracket === -1) return -1;
|
|
49
|
-
const suffix = response.slice(lastOpenBracket).trimEnd();
|
|
50
|
-
if (suffix.includes("]")) return -1;
|
|
51
|
-
if (suffix.startsWith("[POINT:")) {
|
|
52
|
-
let start = lastOpenBracket;
|
|
53
|
-
while (start > 0 && /\s/.test(response[start - 1] ?? "")) start--;
|
|
54
|
-
return start;
|
|
55
|
-
}
|
|
56
|
-
return PARTIAL_POINTING_PREFIXES.has(suffix) ? lastOpenBracket : -1;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Parse pointing tag into structured result.
|
|
60
|
-
* Returns null if no valid POINT tag is found at the end.
|
|
61
|
-
*/
|
|
62
|
-
function parsePointingTagRaw(response) {
|
|
63
|
-
const match = response.match(POINTING_TAG_REGEX);
|
|
64
|
-
if (!match) return null;
|
|
65
|
-
const first = Number.parseInt(match[1], 10);
|
|
66
|
-
const second = match[2] ? Number.parseInt(match[2], 10) : null;
|
|
67
|
-
const label = match[3].trim();
|
|
68
|
-
if (second !== null) return {
|
|
69
|
-
type: "coordinates",
|
|
70
|
-
x: first,
|
|
71
|
-
y: second,
|
|
72
|
-
label
|
|
73
|
-
};
|
|
74
|
-
return {
|
|
75
|
-
type: "marker",
|
|
76
|
-
markerId: first,
|
|
77
|
-
label
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Remove POINT tag from response text for display/TTS.
|
|
82
|
-
*/
|
|
83
|
-
function stripPointingTag(response) {
|
|
84
|
-
return stripTrailingPointingTag(response, true);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Strip complete or partial trailing POINT syntax while the response streams.
|
|
88
|
-
* This keeps the visible text and TTS input stable even if the tag arrives
|
|
89
|
-
* incrementally over multiple chunks.
|
|
90
|
-
*/
|
|
91
|
-
function stripTrailingPointingSyntax(response) {
|
|
92
|
-
const withoutCompleteTag = stripTrailingPointingTag(response, false);
|
|
93
|
-
const partialTagStart = getPartialPointingTagStart(withoutCompleteTag);
|
|
94
|
-
if (partialTagStart === -1) return withoutCompleteTag.trimEnd();
|
|
95
|
-
return withoutCompleteTag.slice(0, partialTagStart).trimEnd();
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
24
|
//#region src/core/utils/error.ts
|
|
99
25
|
/**
|
|
100
26
|
* Normalize unknown thrown values into Error instances.
|
|
@@ -906,6 +832,48 @@ function resolveMarkerToCoordinates(markerMap, markerId) {
|
|
|
906
832
|
//#endregion
|
|
907
833
|
//#region src/core/utils/screenshot.ts
|
|
908
834
|
const CLONE_RESOURCE_TIMEOUT_MS = 3e3;
|
|
835
|
+
/** Maximum width for compressed screenshots (maintains aspect ratio) */
|
|
836
|
+
const MAX_SCREENSHOT_WIDTH = 1280;
|
|
837
|
+
/** JPEG quality for compressed screenshots (0-1) */
|
|
838
|
+
const JPEG_QUALITY = .8;
|
|
839
|
+
/**
|
|
840
|
+
* Compress a canvas image by downscaling and converting to JPEG.
|
|
841
|
+
* Maintains aspect ratio and falls back to original if compression fails.
|
|
842
|
+
*
|
|
843
|
+
* @param sourceCanvas - The source canvas to compress
|
|
844
|
+
* @param maxWidth - Maximum width for the compressed image (default: MAX_SCREENSHOT_WIDTH)
|
|
845
|
+
* @param quality - JPEG quality 0-1 (default: JPEG_QUALITY)
|
|
846
|
+
* @returns Compression result with compressed image data and dimensions
|
|
847
|
+
*/
|
|
848
|
+
function compressImage(sourceCanvas, maxWidth = MAX_SCREENSHOT_WIDTH, quality = JPEG_QUALITY) {
|
|
849
|
+
const sourceWidth = sourceCanvas.width;
|
|
850
|
+
const sourceHeight = sourceCanvas.height;
|
|
851
|
+
if (sourceWidth <= maxWidth) return {
|
|
852
|
+
imageData: sourceCanvas.toDataURL("image/jpeg", quality),
|
|
853
|
+
width: sourceWidth,
|
|
854
|
+
height: sourceHeight
|
|
855
|
+
};
|
|
856
|
+
const scale = maxWidth / sourceWidth;
|
|
857
|
+
const targetWidth = Math.round(maxWidth);
|
|
858
|
+
const targetHeight = Math.round(sourceHeight * scale);
|
|
859
|
+
const canvas = document.createElement("canvas");
|
|
860
|
+
canvas.width = targetWidth;
|
|
861
|
+
canvas.height = targetHeight;
|
|
862
|
+
const ctx = canvas.getContext("2d");
|
|
863
|
+
if (!ctx) return {
|
|
864
|
+
imageData: sourceCanvas.toDataURL("image/jpeg", quality),
|
|
865
|
+
width: sourceWidth,
|
|
866
|
+
height: sourceHeight
|
|
867
|
+
};
|
|
868
|
+
ctx.imageSmoothingEnabled = true;
|
|
869
|
+
ctx.imageSmoothingQuality = "high";
|
|
870
|
+
ctx.drawImage(sourceCanvas, 0, 0, targetWidth, targetHeight);
|
|
871
|
+
return {
|
|
872
|
+
imageData: canvas.toDataURL("image/jpeg", quality),
|
|
873
|
+
width: targetWidth,
|
|
874
|
+
height: targetHeight
|
|
875
|
+
};
|
|
876
|
+
}
|
|
909
877
|
function getCaptureMetrics() {
|
|
910
878
|
return {
|
|
911
879
|
viewportWidth: window.innerWidth,
|
|
@@ -1004,7 +972,7 @@ function createFallbackCanvas() {
|
|
|
1004
972
|
}
|
|
1005
973
|
/**
|
|
1006
974
|
* Capture a screenshot of the current viewport.
|
|
1007
|
-
* Uses html2canvas to render the DOM to a canvas, then
|
|
975
|
+
* Uses html2canvas to render the DOM to a canvas, then compresses to JPEG.
|
|
1008
976
|
* Falls back to a placeholder if capture fails (e.g., due to unsupported CSS).
|
|
1009
977
|
*/
|
|
1010
978
|
async function captureViewport() {
|
|
@@ -1015,10 +983,20 @@ async function captureViewport() {
|
|
|
1015
983
|
} catch {
|
|
1016
984
|
canvas = createFallbackCanvas();
|
|
1017
985
|
}
|
|
986
|
+
let compressed;
|
|
987
|
+
try {
|
|
988
|
+
compressed = compressImage(canvas);
|
|
989
|
+
} catch {
|
|
990
|
+
compressed = {
|
|
991
|
+
imageData: canvas.toDataURL("image/png"),
|
|
992
|
+
width: canvas.width,
|
|
993
|
+
height: canvas.height
|
|
994
|
+
};
|
|
995
|
+
}
|
|
1018
996
|
return {
|
|
1019
|
-
imageData:
|
|
1020
|
-
width:
|
|
1021
|
-
height:
|
|
997
|
+
imageData: compressed.imageData,
|
|
998
|
+
width: compressed.width,
|
|
999
|
+
height: compressed.height,
|
|
1022
1000
|
viewportWidth: captureMetrics.viewportWidth,
|
|
1023
1001
|
viewportHeight: captureMetrics.viewportHeight
|
|
1024
1002
|
};
|
|
@@ -1039,10 +1017,20 @@ async function captureAnnotatedViewport() {
|
|
|
1039
1017
|
}
|
|
1040
1018
|
const canvas = markerMap.size > 0 ? createAnnotatedCanvas(sourceCanvas, markerMap) : sourceCanvas;
|
|
1041
1019
|
const markerContext = generateMarkerContext(markerMap);
|
|
1020
|
+
let compressed;
|
|
1021
|
+
try {
|
|
1022
|
+
compressed = compressImage(canvas);
|
|
1023
|
+
} catch {
|
|
1024
|
+
compressed = {
|
|
1025
|
+
imageData: canvas.toDataURL("image/png"),
|
|
1026
|
+
width: canvas.width,
|
|
1027
|
+
height: canvas.height
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1042
1030
|
return {
|
|
1043
|
-
imageData:
|
|
1044
|
-
width:
|
|
1045
|
-
height:
|
|
1031
|
+
imageData: compressed.imageData,
|
|
1032
|
+
width: compressed.width,
|
|
1033
|
+
height: compressed.height,
|
|
1046
1034
|
viewportWidth: captureMetrics.viewportWidth,
|
|
1047
1035
|
viewportHeight: captureMetrics.viewportHeight,
|
|
1048
1036
|
markerMap,
|
|
@@ -1522,6 +1510,47 @@ function createStateMachine(initial = "idle") {
|
|
|
1522
1510
|
};
|
|
1523
1511
|
}
|
|
1524
1512
|
//#endregion
|
|
1513
|
+
//#region src/core/utils/ui-stream-parser.ts
|
|
1514
|
+
/**
|
|
1515
|
+
* Parse a single line from the UI message stream.
|
|
1516
|
+
* The stream format is SSE with "data: " prefix followed by JSON.
|
|
1517
|
+
*/
|
|
1518
|
+
function parseUIStreamLine(line) {
|
|
1519
|
+
const trimmed = line.trim();
|
|
1520
|
+
if (!trimmed) return null;
|
|
1521
|
+
let jsonStr = trimmed;
|
|
1522
|
+
if (trimmed.startsWith("data: ")) jsonStr = trimmed.slice(6);
|
|
1523
|
+
if (jsonStr === "[DONE]") return null;
|
|
1524
|
+
try {
|
|
1525
|
+
const chunk = JSON.parse(jsonStr);
|
|
1526
|
+
switch (chunk.type) {
|
|
1527
|
+
case "text-delta": return {
|
|
1528
|
+
type: "text-delta",
|
|
1529
|
+
delta: chunk.delta ?? ""
|
|
1530
|
+
};
|
|
1531
|
+
case "tool-input-available": return {
|
|
1532
|
+
type: "tool-input-available",
|
|
1533
|
+
toolName: chunk.toolName ?? "",
|
|
1534
|
+
input: chunk.input
|
|
1535
|
+
};
|
|
1536
|
+
case "finish": return { type: "finish" };
|
|
1537
|
+
case "error": return {
|
|
1538
|
+
type: "error",
|
|
1539
|
+
errorText: chunk.errorText ?? "Unknown error"
|
|
1540
|
+
};
|
|
1541
|
+
default: return { type: "unknown" };
|
|
1542
|
+
}
|
|
1543
|
+
} catch {
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Check if a tool call is a point tool call with valid input.
|
|
1549
|
+
*/
|
|
1550
|
+
function isPointToolCall(chunk) {
|
|
1551
|
+
return chunk.type === "tool-input-available" && chunk.toolName === "point" && chunk.input != null && typeof chunk.input === "object" && "type" in chunk.input && "label" in chunk.input;
|
|
1552
|
+
}
|
|
1553
|
+
//#endregion
|
|
1525
1554
|
//#region src/core/utils/response-processor.ts
|
|
1526
1555
|
const COMMON_ABBREVIATIONS = [
|
|
1527
1556
|
"mr.",
|
|
@@ -1590,32 +1619,58 @@ function extractCompletedSegments(text) {
|
|
|
1590
1619
|
};
|
|
1591
1620
|
}
|
|
1592
1621
|
/**
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1622
|
+
* Processes a streaming AI SDK UI message stream response.
|
|
1623
|
+
* Extracts text for display/TTS and captures point tool calls.
|
|
1595
1624
|
*/
|
|
1596
1625
|
var ProgressiveResponseProcessor = class {
|
|
1597
|
-
|
|
1626
|
+
consumedTextLength = 0;
|
|
1598
1627
|
pendingShortSegment = "";
|
|
1599
|
-
|
|
1628
|
+
rawText = "";
|
|
1629
|
+
buffer = "";
|
|
1630
|
+
pointToolCall = null;
|
|
1631
|
+
/**
|
|
1632
|
+
* Push raw stream data and extract text chunks and tool calls.
|
|
1633
|
+
* The UI message stream format is newline-delimited JSON.
|
|
1634
|
+
*/
|
|
1600
1635
|
push(chunk) {
|
|
1601
|
-
this.
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1604
|
-
|
|
1636
|
+
this.buffer += chunk;
|
|
1637
|
+
const lines = this.buffer.split("\n");
|
|
1638
|
+
this.buffer = lines.pop() ?? "";
|
|
1639
|
+
const newTextParts = [];
|
|
1640
|
+
for (const line of lines) {
|
|
1641
|
+
const parsed = parseUIStreamLine(line);
|
|
1642
|
+
if (!parsed) continue;
|
|
1643
|
+
if (parsed.type === "text-delta") newTextParts.push(parsed.delta);
|
|
1644
|
+
else if (isPointToolCall(parsed)) {
|
|
1645
|
+
if (!this.pointToolCall) this.pointToolCall = parsed.input;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
if (newTextParts.length > 0) this.rawText += newTextParts.join("");
|
|
1649
|
+
const { consumedLength, segments } = extractCompletedSegments(this.rawText.slice(this.consumedTextLength));
|
|
1650
|
+
this.consumedTextLength += consumedLength;
|
|
1605
1651
|
return {
|
|
1606
|
-
visibleText,
|
|
1607
|
-
speechSegments: this.coalesceSegments(segments)
|
|
1652
|
+
visibleText: this.rawText,
|
|
1653
|
+
speechSegments: this.coalesceSegments(segments),
|
|
1654
|
+
pointToolCall: this.pointToolCall
|
|
1608
1655
|
};
|
|
1609
1656
|
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Finalize processing and return any remaining text/tool call.
|
|
1659
|
+
*/
|
|
1610
1660
|
finish() {
|
|
1611
|
-
|
|
1612
|
-
|
|
1661
|
+
if (this.buffer) {
|
|
1662
|
+
const parsed = parseUIStreamLine(this.buffer);
|
|
1663
|
+
if (parsed?.type === "text-delta") this.rawText += parsed.delta;
|
|
1664
|
+
else if (parsed && isPointToolCall(parsed) && !this.pointToolCall) this.pointToolCall = parsed.input;
|
|
1665
|
+
this.buffer = "";
|
|
1666
|
+
}
|
|
1667
|
+
const trailingText = this.rawText.slice(this.consumedTextLength).trim();
|
|
1613
1668
|
const finalSegmentParts = [this.pendingShortSegment, trailingText].filter(Boolean);
|
|
1614
1669
|
this.pendingShortSegment = "";
|
|
1615
1670
|
return {
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1671
|
+
finalResponseText: this.rawText.trim(),
|
|
1672
|
+
speechSegments: finalSegmentParts.length ? [finalSegmentParts.join(" ").trim()] : [],
|
|
1673
|
+
pointToolCall: this.pointToolCall
|
|
1619
1674
|
};
|
|
1620
1675
|
}
|
|
1621
1676
|
coalesceSegments(segments) {
|
|
@@ -1777,7 +1832,7 @@ var CursorBuddyClient = class {
|
|
|
1777
1832
|
this.options.onTranscript?.(transcript);
|
|
1778
1833
|
this.notify();
|
|
1779
1834
|
this.prepareSpeechMode();
|
|
1780
|
-
const { cleanResponse,
|
|
1835
|
+
const { cleanResponse, pointToolCall, playbackQueue } = await this.chatAndSpeak(transcript, screenshot, signal, {
|
|
1781
1836
|
onFailure: failTurn,
|
|
1782
1837
|
onPlaybackStart: () => {
|
|
1783
1838
|
this.stateMachine.transition({ type: "RESPONSE_STARTED" });
|
|
@@ -1785,18 +1840,17 @@ var CursorBuddyClient = class {
|
|
|
1785
1840
|
});
|
|
1786
1841
|
if (turnFailure) throw turnFailure;
|
|
1787
1842
|
if (signal?.aborted) return;
|
|
1788
|
-
const parsed = parsePointingTagRaw(fullResponse);
|
|
1789
1843
|
this.options.onResponse?.(cleanResponse);
|
|
1790
1844
|
let pointTarget = null;
|
|
1791
|
-
if (
|
|
1792
|
-
const coords = resolveMarkerToCoordinates(screenshot.markerMap,
|
|
1845
|
+
if (pointToolCall) if (pointToolCall.type === "marker") {
|
|
1846
|
+
const coords = resolveMarkerToCoordinates(screenshot.markerMap, pointToolCall.markerId);
|
|
1793
1847
|
if (coords) pointTarget = {
|
|
1794
1848
|
...coords,
|
|
1795
|
-
label:
|
|
1849
|
+
label: pointToolCall.label
|
|
1796
1850
|
};
|
|
1797
1851
|
} else pointTarget = {
|
|
1798
|
-
...mapCoordinatesToViewport(
|
|
1799
|
-
label:
|
|
1852
|
+
...mapCoordinatesToViewport(pointToolCall.x, pointToolCall.y, screenshot),
|
|
1853
|
+
label: pointToolCall.label
|
|
1800
1854
|
};
|
|
1801
1855
|
if (pointTarget) {
|
|
1802
1856
|
this.options.onPoint?.(pointTarget);
|
|
@@ -1999,7 +2053,7 @@ var CursorBuddyClient = class {
|
|
|
1999
2053
|
this.updateResponse(finalizedResponse.finalResponseText);
|
|
2000
2054
|
return {
|
|
2001
2055
|
cleanResponse: finalizedResponse.finalResponseText,
|
|
2002
|
-
|
|
2056
|
+
pointToolCall: finalizedResponse.pointToolCall,
|
|
2003
2057
|
playbackQueue
|
|
2004
2058
|
};
|
|
2005
2059
|
}
|
|
@@ -2197,4 +2251,4 @@ var CursorBuddyClient = class {
|
|
|
2197
2251
|
//#endregion
|
|
2198
2252
|
export { $buddyScale as a, $buddyRotation as i, $audioLevel as n, $cursorPosition as o, $buddyPosition as r, $pointingTarget as s, CursorBuddyClient as t };
|
|
2199
2253
|
|
|
2200
|
-
//# sourceMappingURL=client-
|
|
2254
|
+
//# sourceMappingURL=client-CevxN9EX.mjs.map
|