@agent-native/pinpoint 0.1.1 → 0.1.4
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 +4 -0
- package/dist/{agent-context-76ZW6ODH.js → agent-context-OICFLRJ7.js} +2 -2
- package/dist/{chunk-EPXBFDY6.js → chunk-C5OZ7ZT5.js} +1 -1
- package/dist/chunk-C5OZ7ZT5.js.map +1 -0
- package/dist/{chunk-5OW42OKO.js → chunk-PQIWC4FE.js} +44 -71
- package/dist/{chunk-5OW42OKO.js.map → chunk-PQIWC4FE.js.map} +1 -1
- package/dist/{index-5or67wLi.d.ts → index-NvFcZ4SO.d.ts} +8 -1
- package/dist/index.browser.d.ts +3 -7
- package/dist/index.browser.js +2 -2
- package/dist/index.d.ts +2 -6
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/types/index.d.ts +8 -1
- package/package.json +7 -3
- package/dist/chunk-EPXBFDY6.js.map +0 -1
- /package/dist/{agent-context-76ZW6ODH.js.map → agent-context-OICFLRJ7.js.map} +0 -0
package/README.md
CHANGED
|
@@ -234,6 +234,7 @@ All options can be passed as props to `<Pinpoint />` or as the config object to
|
|
|
234
234
|
| `outputFormat` | `'compact' \| 'standard' \| 'detailed'` | `'standard'` | Detail level in agent output |
|
|
235
235
|
| `autoSubmit` | `boolean` | `true` | Auto-submit annotations to agent chat |
|
|
236
236
|
| `clearOnSend` | `boolean` | `false` | Clear pins after sending |
|
|
237
|
+
| `sendToAgent` | `(output) => void \| Promise<void>` | — | Custom bridge for annotation delivery |
|
|
237
238
|
| `blockInteractions` | `boolean` | `false` | Block page clicks during selection |
|
|
238
239
|
| `compactPopup` | `boolean` | `true` | Hide technical details behind toggle |
|
|
239
240
|
| `freezeJSTimers` | `boolean` | `false` | Freeze JS timers during selection |
|
|
@@ -395,6 +396,9 @@ Inside [Builder.io's Fusion](https://builder.io), annotations are sent via `send
|
|
|
395
396
|
|
|
396
397
|
No additional configuration needed when running inside a Builder.io project.
|
|
397
398
|
|
|
399
|
+
Hosts with their own chat implementation can pass `sendToAgent` to reuse Pinpoint's pin,
|
|
400
|
+
draw, queue, and prompt UI while delivering `{ message, context, submit }` themselves.
|
|
401
|
+
|
|
398
402
|
## Architecture
|
|
399
403
|
|
|
400
404
|
- **SolidJS overlay** in **Shadow DOM** — zero interference with host app styles or React reconciliation
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
formatPinsForAgent,
|
|
4
4
|
formatQueueForAgent,
|
|
5
5
|
formatRichPinContext
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-C5OZ7ZT5.js";
|
|
7
7
|
import "./chunk-BB7X7W3H.js";
|
|
8
8
|
export {
|
|
9
9
|
formatPinsForAgent,
|
|
10
10
|
formatQueueForAgent,
|
|
11
11
|
formatRichPinContext
|
|
12
12
|
};
|
|
13
|
-
//# sourceMappingURL=agent-context-
|
|
13
|
+
//# sourceMappingURL=agent-context-OICFLRJ7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/output/agent-context.ts"],"sourcesContent":["// @agent-native/pinpoint — Split output for sendToAgentChat()\n// MIT License\n//\n// Splits annotation output into { message, context } for the agent chat bridge.\n// The message is shown in chat UI. The context is hidden, appended for the agent.\n\nimport type {\n AgentOutput,\n Pin,\n OutputFormat,\n QueuedAnnotation,\n} from \"../types/index.js\";\nimport { formatPins } from \"./formatter.js\";\n\nexport type { AgentOutput } from \"../types/index.js\";\n\n/**\n * Format a single pin into rich context for the agent.\n *\n * ```\n * [Annotation on <button class=\"primary\"> in <Header> component]\n * Comment: \"This button should be blue instead of gray\"\n * Element: button.primary at (120, 45)\n * Source: src/components/Header.tsx:42\n * ```\n */\nexport function formatRichPinContext(pin: Pin): string {\n const lines: string[] = [];\n\n // Build element descriptor\n const tagName = pin.element.tagName.toLowerCase();\n const classes =\n pin.element.classNames.length > 0\n ? ` class=\"${pin.element.classNames.join(\" \")}\"`\n : \"\";\n const component = pin.framework?.componentPath\n ? ` in ${pin.framework.componentPath} component`\n : \"\";\n\n lines.push(`[Annotation on <${tagName}${classes}>${component}]`);\n lines.push(`Comment: \"${pin.comment}\"`);\n\n const rect = pin.element.boundingRect;\n const classStr =\n pin.element.classNames.length > 0\n ? `.${pin.element.classNames.join(\".\")}`\n : \"\";\n lines.push(\n `Element: ${tagName}${classStr} at (${Math.round(rect.x)}, ${Math.round(rect.y)})`,\n );\n\n if (pin.framework?.sourceFile) {\n lines.push(`Source: ${pin.framework.sourceFile}`);\n }\n\n if (pin.element.textContent) {\n const truncated = pin.element.textContent.slice(0, 80);\n lines.push(\n `Text: \"${truncated}${pin.element.textContent.length > 80 ? \"...\" : \"\"}\"`,\n );\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format pins for agent chat.\n * The full formatted output goes into message (visible in chat UI) so the user\n * can see exactly what context the agent is working with.\n */\nexport function formatPinsForAgent(\n pins: Pin[],\n format: OutputFormat = \"standard\",\n): AgentOutput {\n if (pins.length === 0) {\n return { message: \"No annotations to send.\", context: \"\" };\n }\n\n // Use rich context format for each pin\n const richAnnotations = pins\n .map((pin) => formatRichPinContext(pin))\n .join(\"\\n\\n\");\n\n const instruction = `The user has annotated ${pins.length} element${pins.length === 1 ? \"\" : \"s\"} on the page with visual feedback. Review each annotation and make the requested changes.\\n\\n`;\n\n // Also include the structured format as context for the agent\n const details = formatPins(pins, format);\n const message = instruction + richAnnotations;\n\n return { message, context: details };\n}\n\n/**\n * Format queued annotations for batch sending.\n */\nexport function formatQueueForAgent(\n queue: QueuedAnnotation[],\n format: OutputFormat = \"standard\",\n): AgentOutput {\n if (queue.length === 0) {\n return { message: \"No queued annotations to send.\", context: \"\" };\n }\n\n const parts: string[] = [];\n const pins: Pin[] = [];\n\n parts.push(\n `The user has queued ${queue.length} annotation${queue.length === 1 ? \"\" : \"s\"} for batch review. Process each one:\\n`,\n );\n\n for (let i = 0; i < queue.length; i++) {\n const item = queue[i];\n parts.push(`--- Item ${i + 1} ---`);\n\n if (item.pin) {\n parts.push(formatRichPinContext(item.pin));\n pins.push(item.pin);\n }\n\n if (item.drawings && item.drawings.length > 0) {\n parts.push(`[Drawing: ${item.drawings.length} stroke(s) on the page]`);\n for (const stroke of item.drawings) {\n const startPt = stroke.points[0];\n const endPt = stroke.points[stroke.points.length - 1];\n parts.push(\n ` ${stroke.type} from (${Math.round(startPt.x)}, ${Math.round(startPt.y)}) to (${Math.round(endPt.x)}, ${Math.round(endPt.y)}) [${stroke.color}]`,\n );\n }\n }\n\n if (item.textNotes && item.textNotes.length > 0) {\n for (const note of item.textNotes) {\n parts.push(\n `[Text note at (${Math.round(note.x)}, ${Math.round(note.y)}): \"${note.text}\"]`,\n );\n }\n }\n\n parts.push(\"\");\n }\n\n const message = parts.join(\"\\n\");\n const context = pins.length > 0 ? formatPins(pins, format) : \"\";\n\n return { message, context };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4076,6 +4076,24 @@ var PinpointApp = (props) => {
|
|
|
4076
4076
|
const [blockInteractions, setBlockInteractions] = createSignal(props.config.blockInteractions ?? false);
|
|
4077
4077
|
const [autoSubmit, setAutoSubmit] = createSignal(props.config.autoSubmit ?? true);
|
|
4078
4078
|
const [compactPopup, setCompactPopup] = createSignal(props.config.compactPopup ?? true);
|
|
4079
|
+
async function deliverToAgent(output) {
|
|
4080
|
+
const agentOutput = {
|
|
4081
|
+
...output,
|
|
4082
|
+
submit: output.submit ?? autoSubmit()
|
|
4083
|
+
};
|
|
4084
|
+
if (props.config.sendToAgent) {
|
|
4085
|
+
await props.config.sendToAgent(agentOutput);
|
|
4086
|
+
return;
|
|
4087
|
+
}
|
|
4088
|
+
try {
|
|
4089
|
+
const {
|
|
4090
|
+
sendToAgentChat
|
|
4091
|
+
} = await import("@agent-native/core/client");
|
|
4092
|
+
sendToAgentChat(agentOutput);
|
|
4093
|
+
} catch {
|
|
4094
|
+
await navigator.clipboard.writeText([agentOutput.message, agentOutput.context].filter(Boolean).join("\n\n"));
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4079
4097
|
const storage = props.config.storage || (props.config.endpoint ? new RestClient(props.config.endpoint) : new MemoryStore());
|
|
4080
4098
|
const picker = new ElementPicker({
|
|
4081
4099
|
ignoreSelector: "#pinpoint-root, [data-pinpoint-marker]",
|
|
@@ -4353,25 +4371,15 @@ var PinpointApp = (props) => {
|
|
|
4353
4371
|
if (items.length === 0) return;
|
|
4354
4372
|
const {
|
|
4355
4373
|
formatQueueForAgent
|
|
4356
|
-
} = await import("./agent-context-
|
|
4374
|
+
} = await import("./agent-context-OICFLRJ7.js");
|
|
4357
4375
|
const {
|
|
4358
4376
|
message,
|
|
4359
4377
|
context
|
|
4360
4378
|
} = formatQueueForAgent(items, outputFormat());
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
sendToAgentChat({
|
|
4366
|
-
message,
|
|
4367
|
-
context,
|
|
4368
|
-
submit: autoSubmit()
|
|
4369
|
-
});
|
|
4370
|
-
} catch {
|
|
4371
|
-
await navigator.clipboard.writeText(`${message}
|
|
4372
|
-
|
|
4373
|
-
${context}`);
|
|
4374
|
-
}
|
|
4379
|
+
await deliverToAgent({
|
|
4380
|
+
message,
|
|
4381
|
+
context
|
|
4382
|
+
});
|
|
4375
4383
|
setQueue([]);
|
|
4376
4384
|
if (clearOnSend()) {
|
|
4377
4385
|
const pageUrl = window.location.pathname;
|
|
@@ -4399,25 +4407,15 @@ ${context}`);
|
|
|
4399
4407
|
const selected = pins().filter((p) => ids.has(p.id));
|
|
4400
4408
|
const {
|
|
4401
4409
|
formatPinsForAgent
|
|
4402
|
-
} = await import("./agent-context-
|
|
4410
|
+
} = await import("./agent-context-OICFLRJ7.js");
|
|
4403
4411
|
const {
|
|
4404
4412
|
message,
|
|
4405
4413
|
context
|
|
4406
4414
|
} = formatPinsForAgent(selected, outputFormat());
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
sendToAgentChat({
|
|
4412
|
-
message,
|
|
4413
|
-
context,
|
|
4414
|
-
submit: autoSubmit()
|
|
4415
|
-
});
|
|
4416
|
-
} catch {
|
|
4417
|
-
await navigator.clipboard.writeText(`${message}
|
|
4418
|
-
|
|
4419
|
-
${context}`);
|
|
4420
|
-
}
|
|
4415
|
+
await deliverToAgent({
|
|
4416
|
+
message,
|
|
4417
|
+
context
|
|
4418
|
+
});
|
|
4421
4419
|
setSelectedPinIds(/* @__PURE__ */ new Set());
|
|
4422
4420
|
}
|
|
4423
4421
|
function toggleActive() {
|
|
@@ -4501,20 +4499,12 @@ ${context}`);
|
|
|
4501
4499
|
const pin = addPin(el, comment);
|
|
4502
4500
|
const {
|
|
4503
4501
|
formatRichPinContext
|
|
4504
|
-
} = await import("./agent-context-
|
|
4502
|
+
} = await import("./agent-context-OICFLRJ7.js");
|
|
4505
4503
|
const richMessage = `Please fix: ${formatRichPinContext(pin)}`;
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
sendToAgentChat({
|
|
4511
|
-
message: richMessage,
|
|
4512
|
-
context: "",
|
|
4513
|
-
submit: autoSubmit()
|
|
4514
|
-
});
|
|
4515
|
-
} catch {
|
|
4516
|
-
await navigator.clipboard.writeText(richMessage);
|
|
4517
|
-
}
|
|
4504
|
+
await deliverToAgent({
|
|
4505
|
+
message: richMessage,
|
|
4506
|
+
context: ""
|
|
4507
|
+
});
|
|
4518
4508
|
}
|
|
4519
4509
|
function openEditPopup(pin) {
|
|
4520
4510
|
setShowPopup(false);
|
|
@@ -4552,25 +4542,15 @@ ${context}`);
|
|
|
4552
4542
|
async function sendPins() {
|
|
4553
4543
|
const {
|
|
4554
4544
|
formatPinsForAgent
|
|
4555
|
-
} = await import("./agent-context-
|
|
4545
|
+
} = await import("./agent-context-OICFLRJ7.js");
|
|
4556
4546
|
const {
|
|
4557
4547
|
message,
|
|
4558
4548
|
context
|
|
4559
4549
|
} = formatPinsForAgent(pins(), outputFormat());
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
sendToAgentChat({
|
|
4565
|
-
message,
|
|
4566
|
-
context,
|
|
4567
|
-
submit: autoSubmit()
|
|
4568
|
-
});
|
|
4569
|
-
} catch {
|
|
4570
|
-
await navigator.clipboard.writeText(`${message}
|
|
4571
|
-
|
|
4572
|
-
${context}`);
|
|
4573
|
-
}
|
|
4550
|
+
await deliverToAgent({
|
|
4551
|
+
message,
|
|
4552
|
+
context
|
|
4553
|
+
});
|
|
4574
4554
|
if (clearOnSend()) {
|
|
4575
4555
|
const pageUrl = window.location.pathname;
|
|
4576
4556
|
await storage.clear(pageUrl);
|
|
@@ -4807,18 +4787,11 @@ ${context}`);
|
|
|
4807
4787
|
return selectedElement();
|
|
4808
4788
|
},
|
|
4809
4789
|
onSend: async (instruction) => {
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
sendToAgentChat({
|
|
4816
|
-
message: instruction,
|
|
4817
|
-
context: JSON.stringify(context, null, 2),
|
|
4818
|
-
submit: autoSubmit()
|
|
4819
|
-
});
|
|
4820
|
-
} catch {
|
|
4821
|
-
}
|
|
4790
|
+
const context = buildElementContext(selectedElement());
|
|
4791
|
+
await deliverToAgent({
|
|
4792
|
+
message: instruction,
|
|
4793
|
+
context: JSON.stringify(context, null, 2)
|
|
4794
|
+
});
|
|
4822
4795
|
setShowPrompt(false);
|
|
4823
4796
|
},
|
|
4824
4797
|
onCancel: () => setShowPrompt(false)
|
|
@@ -4894,4 +4867,4 @@ export {
|
|
|
4894
4867
|
mountPinpoint,
|
|
4895
4868
|
unmountPinpoint
|
|
4896
4869
|
};
|
|
4897
|
-
//# sourceMappingURL=chunk-
|
|
4870
|
+
//# sourceMappingURL=chunk-PQIWC4FE.js.map
|