cursor-buddy 0.0.8 → 0.0.9
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 +5 -6
- 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-D73KQZf8.mjs → client-CSVSY-KV.mjs} +92 -100
- package/dist/client-CSVSY-KV.mjs.map +1 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -2
- package/dist/point-tool-Cv39qylv.mjs +54 -0
- package/dist/point-tool-Cv39qylv.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 +2 -3
- package/dist/server/adapters/next.d.mts.map +1 -1
- package/dist/server/adapters/next.mjs +2 -5
- package/dist/server/adapters/next.mjs.map +1 -1
- package/dist/server/index.d.mts +4 -7
- package/dist/server/index.d.mts.map +1 -1
- package/dist/server/index.mjs +125 -36
- package/dist/server/index.mjs.map +1 -1
- package/dist/{types-BxBhjZju.d.mts → types-BJfkApb_.d.mts} +2 -1
- package/dist/types-BJfkApb_.d.mts.map +1 -0
- package/package.json +3 -2
- package/dist/client-Crn8tW7w.d.mts.map +0 -1
- package/dist/client-D73KQZf8.mjs.map +0 -1
- package/dist/types-BxBhjZju.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ export const cursorBuddy = createCursorBuddyHandler({
|
|
|
57
57
|
import { toNextJsHandler } from "cursor-buddy/server/next"
|
|
58
58
|
import { cursorBuddy } from "@/lib/cursor-buddy"
|
|
59
59
|
|
|
60
|
-
export const {
|
|
60
|
+
export const { POST } = toNextJsHandler(cursorBuddy)
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
### 2. Client Setup
|
|
@@ -371,13 +371,13 @@ client.stopListening()
|
|
|
371
371
|
4. An annotated screenshot of the viewport is captured, with numbered markers on visible interactive elements, based on [agent-browser](https://github.com/vercel-labs/agent-browser) implementation.
|
|
372
372
|
5. The client prefers the browser transcript; if it is unavailable or empty in `auto` mode, the recorded audio is transcribed on the server
|
|
373
373
|
6. Screenshot + marker context are sent to the AI model
|
|
374
|
-
7. AI responds with text
|
|
375
|
-
-
|
|
376
|
-
-
|
|
374
|
+
7. AI responds with text and can optionally call the `point` tool to indicate a location on screen:
|
|
375
|
+
- `type: "marker"` with `markerId` for numbered interactive elements (most accurate)
|
|
376
|
+
- `type: "coordinates"` with `x, y` pixel coordinates for anything without a marker
|
|
377
377
|
8. Response is spoken in the browser or on the server based on `speech.mode`,
|
|
378
378
|
and can either wait for the full response or stream sentence-by-sentence
|
|
379
379
|
based on `speech.allowStreaming`
|
|
380
|
-
9. If
|
|
380
|
+
9. If the AI calls the point tool, the cursor animates to the target location — markers resolve to live DOM elements, coordinates map to viewport positions
|
|
381
381
|
10. **If user presses hotkey again at any point, current response is interrupted**
|
|
382
382
|
|
|
383
383
|
## Security Best Practices
|
|
@@ -415,7 +415,6 @@ export const GET = POST
|
|
|
415
415
|
|
|
416
416
|
## TODOs
|
|
417
417
|
|
|
418
|
-
- [ ] High: Make tool calls first class: Pointing becomes tool call (once per turn) + re-use pointing bubble UI for tool calls
|
|
419
418
|
- [ ] Medium: Proper test structure without relying on `as any` for audio and voice capture
|
|
420
419
|
|
|
421
420
|
## License
|
|
@@ -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.
|
|
@@ -691,7 +617,7 @@ const DEFAULT_STYLE = {
|
|
|
691
617
|
labelBackground: "rgba(255, 0, 0, 0.9)",
|
|
692
618
|
labelColor: "#ffffff",
|
|
693
619
|
borderWidth: 2,
|
|
694
|
-
fontSize:
|
|
620
|
+
fontSize: 15,
|
|
695
621
|
labelPadding: 4
|
|
696
622
|
};
|
|
697
623
|
/**
|
|
@@ -1009,7 +935,7 @@ async function waitForClonedDocumentStyles(doc) {
|
|
|
1009
935
|
}
|
|
1010
936
|
function getHtml2CanvasOptions(captureMetrics) {
|
|
1011
937
|
return {
|
|
1012
|
-
scale:
|
|
938
|
+
scale: window.devicePixelRatio,
|
|
1013
939
|
useCORS: true,
|
|
1014
940
|
logging: false,
|
|
1015
941
|
width: captureMetrics.viewportWidth,
|
|
@@ -1584,6 +1510,47 @@ function createStateMachine(initial = "idle") {
|
|
|
1584
1510
|
};
|
|
1585
1511
|
}
|
|
1586
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
|
|
1587
1554
|
//#region src/core/utils/response-processor.ts
|
|
1588
1555
|
const COMMON_ABBREVIATIONS = [
|
|
1589
1556
|
"mr.",
|
|
@@ -1652,32 +1619,58 @@ function extractCompletedSegments(text) {
|
|
|
1652
1619
|
};
|
|
1653
1620
|
}
|
|
1654
1621
|
/**
|
|
1655
|
-
*
|
|
1656
|
-
*
|
|
1622
|
+
* Processes a streaming AI SDK UI message stream response.
|
|
1623
|
+
* Extracts text for display/TTS and captures point tool calls.
|
|
1657
1624
|
*/
|
|
1658
1625
|
var ProgressiveResponseProcessor = class {
|
|
1659
|
-
|
|
1626
|
+
consumedTextLength = 0;
|
|
1660
1627
|
pendingShortSegment = "";
|
|
1661
|
-
|
|
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
|
+
*/
|
|
1662
1635
|
push(chunk) {
|
|
1663
|
-
this.
|
|
1664
|
-
const
|
|
1665
|
-
|
|
1666
|
-
|
|
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;
|
|
1667
1651
|
return {
|
|
1668
|
-
visibleText,
|
|
1669
|
-
speechSegments: this.coalesceSegments(segments)
|
|
1652
|
+
visibleText: this.rawText,
|
|
1653
|
+
speechSegments: this.coalesceSegments(segments),
|
|
1654
|
+
pointToolCall: this.pointToolCall
|
|
1670
1655
|
};
|
|
1671
1656
|
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Finalize processing and return any remaining text/tool call.
|
|
1659
|
+
*/
|
|
1672
1660
|
finish() {
|
|
1673
|
-
|
|
1674
|
-
|
|
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();
|
|
1675
1668
|
const finalSegmentParts = [this.pendingShortSegment, trailingText].filter(Boolean);
|
|
1676
1669
|
this.pendingShortSegment = "";
|
|
1677
1670
|
return {
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1671
|
+
finalResponseText: this.rawText.trim(),
|
|
1672
|
+
speechSegments: finalSegmentParts.length ? [finalSegmentParts.join(" ").trim()] : [],
|
|
1673
|
+
pointToolCall: this.pointToolCall
|
|
1681
1674
|
};
|
|
1682
1675
|
}
|
|
1683
1676
|
coalesceSegments(segments) {
|
|
@@ -1839,7 +1832,7 @@ var CursorBuddyClient = class {
|
|
|
1839
1832
|
this.options.onTranscript?.(transcript);
|
|
1840
1833
|
this.notify();
|
|
1841
1834
|
this.prepareSpeechMode();
|
|
1842
|
-
const { cleanResponse,
|
|
1835
|
+
const { cleanResponse, pointToolCall, playbackQueue } = await this.chatAndSpeak(transcript, screenshot, signal, {
|
|
1843
1836
|
onFailure: failTurn,
|
|
1844
1837
|
onPlaybackStart: () => {
|
|
1845
1838
|
this.stateMachine.transition({ type: "RESPONSE_STARTED" });
|
|
@@ -1847,18 +1840,17 @@ var CursorBuddyClient = class {
|
|
|
1847
1840
|
});
|
|
1848
1841
|
if (turnFailure) throw turnFailure;
|
|
1849
1842
|
if (signal?.aborted) return;
|
|
1850
|
-
const parsed = parsePointingTagRaw(fullResponse);
|
|
1851
1843
|
this.options.onResponse?.(cleanResponse);
|
|
1852
1844
|
let pointTarget = null;
|
|
1853
|
-
if (
|
|
1854
|
-
const coords = resolveMarkerToCoordinates(screenshot.markerMap,
|
|
1845
|
+
if (pointToolCall) if (pointToolCall.type === "marker") {
|
|
1846
|
+
const coords = resolveMarkerToCoordinates(screenshot.markerMap, pointToolCall.markerId);
|
|
1855
1847
|
if (coords) pointTarget = {
|
|
1856
1848
|
...coords,
|
|
1857
|
-
label:
|
|
1849
|
+
label: pointToolCall.label
|
|
1858
1850
|
};
|
|
1859
1851
|
} else pointTarget = {
|
|
1860
|
-
...mapCoordinatesToViewport(
|
|
1861
|
-
label:
|
|
1852
|
+
...mapCoordinatesToViewport(pointToolCall.x, pointToolCall.y, screenshot),
|
|
1853
|
+
label: pointToolCall.label
|
|
1862
1854
|
};
|
|
1863
1855
|
if (pointTarget) {
|
|
1864
1856
|
this.options.onPoint?.(pointTarget);
|
|
@@ -2061,7 +2053,7 @@ var CursorBuddyClient = class {
|
|
|
2061
2053
|
this.updateResponse(finalizedResponse.finalResponseText);
|
|
2062
2054
|
return {
|
|
2063
2055
|
cleanResponse: finalizedResponse.finalResponseText,
|
|
2064
|
-
|
|
2056
|
+
pointToolCall: finalizedResponse.pointToolCall,
|
|
2065
2057
|
playbackQueue
|
|
2066
2058
|
};
|
|
2067
2059
|
}
|
|
@@ -2259,4 +2251,4 @@ var CursorBuddyClient = class {
|
|
|
2259
2251
|
//#endregion
|
|
2260
2252
|
export { $buddyScale as a, $buddyRotation as i, $audioLevel as n, $cursorPosition as o, $buddyPosition as r, $pointingTarget as s, CursorBuddyClient as t };
|
|
2261
2253
|
|
|
2262
|
-
//# sourceMappingURL=client-
|
|
2254
|
+
//# sourceMappingURL=client-CSVSY-KV.mjs.map
|