@jami-studio/pinpoint 0.1.12

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.
Files changed (47) hide show
  1. package/.agents/skills/pinpoint/SKILL.md +77 -0
  2. package/README.md +412 -0
  3. package/dist/agent-context-HBCZ4MBN.js +13 -0
  4. package/dist/agent-context-HBCZ4MBN.js.map +1 -0
  5. package/dist/chunk-B7TY4FPP.js +569 -0
  6. package/dist/chunk-B7TY4FPP.js.map +1 -0
  7. package/dist/chunk-CGJZ7BOM.js +88 -0
  8. package/dist/chunk-CGJZ7BOM.js.map +1 -0
  9. package/dist/chunk-DGUM43GV.js +11 -0
  10. package/dist/chunk-DGUM43GV.js.map +1 -0
  11. package/dist/chunk-HAEYE6KB.js +25 -0
  12. package/dist/chunk-HAEYE6KB.js.map +1 -0
  13. package/dist/chunk-J5PXKVTM.js +53 -0
  14. package/dist/chunk-J5PXKVTM.js.map +1 -0
  15. package/dist/chunk-XBX2J7WU.js +94 -0
  16. package/dist/chunk-XBX2J7WU.js.map +1 -0
  17. package/dist/chunk-ZW7IO3EW.js +4927 -0
  18. package/dist/chunk-ZW7IO3EW.js.map +1 -0
  19. package/dist/cli.js +71 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/formatter-CR4COA5Z.js +8 -0
  22. package/dist/formatter-CR4COA5Z.js.map +1 -0
  23. package/dist/index-NvFcZ4SO.d.ts +200 -0
  24. package/dist/index.browser.d.ts +377 -0
  25. package/dist/index.browser.js +620 -0
  26. package/dist/index.browser.js.map +1 -0
  27. package/dist/index.js +936 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/open-file-WR2JHI4P.js +8 -0
  30. package/dist/open-file-WR2JHI4P.js.map +1 -0
  31. package/dist/primitives/index.js +28 -0
  32. package/dist/primitives/index.js.map +1 -0
  33. package/dist/react.d.ts +23 -0
  34. package/dist/react.js +20 -0
  35. package/dist/react.js.map +1 -0
  36. package/dist/server/index.js +457 -0
  37. package/dist/server/index.js.map +1 -0
  38. package/dist/types/index.js +1 -0
  39. package/dist/types/index.js.map +1 -0
  40. package/package.json +88 -0
  41. package/src/scripts/create-pin.ts +43 -0
  42. package/src/scripts/delete-pin.ts +16 -0
  43. package/src/scripts/get-pins.ts +36 -0
  44. package/src/scripts/list-sessions.ts +33 -0
  45. package/src/scripts/resolve-pin.ts +27 -0
  46. package/src/scripts/run.ts +8 -0
  47. package/src/scripts/update-pin.ts +32 -0
@@ -0,0 +1,88 @@
1
+ "use client";
2
+ import {
3
+ formatPins
4
+ } from "./chunk-XBX2J7WU.js";
5
+
6
+ // src/output/agent-context.ts
7
+ function formatRichPinContext(pin) {
8
+ const lines = [];
9
+ const tagName = pin.element.tagName.toLowerCase();
10
+ const classes = pin.element.classNames.length > 0 ? ` class="${pin.element.classNames.join(" ")}"` : "";
11
+ const component = pin.framework?.componentPath ? ` in ${pin.framework.componentPath} component` : "";
12
+ lines.push(`[Annotation on <${tagName}${classes}>${component}]`);
13
+ lines.push(`Comment: "${pin.comment}"`);
14
+ const rect = pin.element.boundingRect;
15
+ const classStr = pin.element.classNames.length > 0 ? `.${pin.element.classNames.join(".")}` : "";
16
+ lines.push(
17
+ `Element: ${tagName}${classStr} at (${Math.round(rect.x)}, ${Math.round(rect.y)})`
18
+ );
19
+ if (pin.framework?.sourceFile) {
20
+ lines.push(`Source: ${pin.framework.sourceFile}`);
21
+ }
22
+ if (pin.element.textContent) {
23
+ const truncated = pin.element.textContent.slice(0, 80);
24
+ lines.push(
25
+ `Text: "${truncated}${pin.element.textContent.length > 80 ? "..." : ""}"`
26
+ );
27
+ }
28
+ return lines.join("\n");
29
+ }
30
+ function formatPinsForAgent(pins, format = "standard") {
31
+ if (pins.length === 0) {
32
+ return { message: "No annotations to send.", context: "" };
33
+ }
34
+ const richAnnotations = pins.map((pin) => formatRichPinContext(pin)).join("\n\n");
35
+ 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.
36
+
37
+ `;
38
+ const details = formatPins(pins, format);
39
+ const message = instruction + richAnnotations;
40
+ return { message, context: details };
41
+ }
42
+ function formatQueueForAgent(queue, format = "standard") {
43
+ if (queue.length === 0) {
44
+ return { message: "No queued annotations to send.", context: "" };
45
+ }
46
+ const parts = [];
47
+ const pins = [];
48
+ parts.push(
49
+ `The user has queued ${queue.length} annotation${queue.length === 1 ? "" : "s"} for batch review. Process each one:
50
+ `
51
+ );
52
+ for (let i = 0; i < queue.length; i++) {
53
+ const item = queue[i];
54
+ parts.push(`--- Item ${i + 1} ---`);
55
+ if (item.pin) {
56
+ parts.push(formatRichPinContext(item.pin));
57
+ pins.push(item.pin);
58
+ }
59
+ if (item.drawings && item.drawings.length > 0) {
60
+ parts.push(`[Drawing: ${item.drawings.length} stroke(s) on the page]`);
61
+ for (const stroke of item.drawings) {
62
+ const startPt = stroke.points[0];
63
+ const endPt = stroke.points[stroke.points.length - 1];
64
+ parts.push(
65
+ ` ${stroke.type} from (${Math.round(startPt.x)}, ${Math.round(startPt.y)}) to (${Math.round(endPt.x)}, ${Math.round(endPt.y)}) [${stroke.color}]`
66
+ );
67
+ }
68
+ }
69
+ if (item.textNotes && item.textNotes.length > 0) {
70
+ for (const note of item.textNotes) {
71
+ parts.push(
72
+ `[Text note at (${Math.round(note.x)}, ${Math.round(note.y)}): "${note.text}"]`
73
+ );
74
+ }
75
+ }
76
+ parts.push("");
77
+ }
78
+ const message = parts.join("\n");
79
+ const context = pins.length > 0 ? formatPins(pins, format) : "";
80
+ return { message, context };
81
+ }
82
+
83
+ export {
84
+ formatRichPinContext,
85
+ formatPinsForAgent,
86
+ formatQueueForAgent
87
+ };
88
+ //# sourceMappingURL=chunk-CGJZ7BOM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/output/agent-context.ts"],"sourcesContent":["// @agent-native/pinpoint — Split output for sendToAgentChat()\r\n// MIT License\r\n//\r\n// Splits annotation output into { message, context } for the agent chat bridge.\r\n// The message is shown in chat UI. The context is hidden, appended for the agent.\r\n\r\nimport type {\r\n AgentOutput,\r\n Pin,\r\n OutputFormat,\r\n QueuedAnnotation,\r\n} from \"../types/index.js\";\r\nimport { formatPins } from \"./formatter.js\";\r\n\r\nexport type { AgentOutput } from \"../types/index.js\";\r\n\r\n/**\r\n * Format a single pin into rich context for the agent.\r\n *\r\n * ```\r\n * [Annotation on <button class=\"primary\"> in <Header> component]\r\n * Comment: \"This button should be blue instead of gray\"\r\n * Element: button.primary at (120, 45)\r\n * Source: src/components/Header.tsx:42\r\n * ```\r\n */\r\nexport function formatRichPinContext(pin: Pin): string {\r\n const lines: string[] = [];\r\n\r\n // Build element descriptor\r\n const tagName = pin.element.tagName.toLowerCase();\r\n const classes =\r\n pin.element.classNames.length > 0\r\n ? ` class=\"${pin.element.classNames.join(\" \")}\"`\r\n : \"\";\r\n const component = pin.framework?.componentPath\r\n ? ` in ${pin.framework.componentPath} component`\r\n : \"\";\r\n\r\n lines.push(`[Annotation on <${tagName}${classes}>${component}]`);\r\n lines.push(`Comment: \"${pin.comment}\"`);\r\n\r\n const rect = pin.element.boundingRect;\r\n const classStr =\r\n pin.element.classNames.length > 0\r\n ? `.${pin.element.classNames.join(\".\")}`\r\n : \"\";\r\n lines.push(\r\n `Element: ${tagName}${classStr} at (${Math.round(rect.x)}, ${Math.round(rect.y)})`,\r\n );\r\n\r\n if (pin.framework?.sourceFile) {\r\n lines.push(`Source: ${pin.framework.sourceFile}`);\r\n }\r\n\r\n if (pin.element.textContent) {\r\n const truncated = pin.element.textContent.slice(0, 80);\r\n lines.push(\r\n `Text: \"${truncated}${pin.element.textContent.length > 80 ? \"...\" : \"\"}\"`,\r\n );\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Format pins for agent chat.\r\n * The full formatted output goes into message (visible in chat UI) so the user\r\n * can see exactly what context the agent is working with.\r\n */\r\nexport function formatPinsForAgent(\r\n pins: Pin[],\r\n format: OutputFormat = \"standard\",\r\n): AgentOutput {\r\n if (pins.length === 0) {\r\n return { message: \"No annotations to send.\", context: \"\" };\r\n }\r\n\r\n // Use rich context format for each pin\r\n const richAnnotations = pins\r\n .map((pin) => formatRichPinContext(pin))\r\n .join(\"\\n\\n\");\r\n\r\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`;\r\n\r\n // Also include the structured format as context for the agent\r\n const details = formatPins(pins, format);\r\n const message = instruction + richAnnotations;\r\n\r\n return { message, context: details };\r\n}\r\n\r\n/**\r\n * Format queued annotations for batch sending.\r\n */\r\nexport function formatQueueForAgent(\r\n queue: QueuedAnnotation[],\r\n format: OutputFormat = \"standard\",\r\n): AgentOutput {\r\n if (queue.length === 0) {\r\n return { message: \"No queued annotations to send.\", context: \"\" };\r\n }\r\n\r\n const parts: string[] = [];\r\n const pins: Pin[] = [];\r\n\r\n parts.push(\r\n `The user has queued ${queue.length} annotation${queue.length === 1 ? \"\" : \"s\"} for batch review. Process each one:\\n`,\r\n );\r\n\r\n for (let i = 0; i < queue.length; i++) {\r\n const item = queue[i];\r\n parts.push(`--- Item ${i + 1} ---`);\r\n\r\n if (item.pin) {\r\n parts.push(formatRichPinContext(item.pin));\r\n pins.push(item.pin);\r\n }\r\n\r\n if (item.drawings && item.drawings.length > 0) {\r\n parts.push(`[Drawing: ${item.drawings.length} stroke(s) on the page]`);\r\n for (const stroke of item.drawings) {\r\n const startPt = stroke.points[0];\r\n const endPt = stroke.points[stroke.points.length - 1];\r\n parts.push(\r\n ` ${stroke.type} from (${Math.round(startPt.x)}, ${Math.round(startPt.y)}) to (${Math.round(endPt.x)}, ${Math.round(endPt.y)}) [${stroke.color}]`,\r\n );\r\n }\r\n }\r\n\r\n if (item.textNotes && item.textNotes.length > 0) {\r\n for (const note of item.textNotes) {\r\n parts.push(\r\n `[Text note at (${Math.round(note.x)}, ${Math.round(note.y)}): \"${note.text}\"]`,\r\n );\r\n }\r\n }\r\n\r\n parts.push(\"\");\r\n }\r\n\r\n const message = parts.join(\"\\n\");\r\n const context = pins.length > 0 ? formatPins(pins, format) : \"\";\r\n\r\n return { message, context };\r\n}\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
11
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ // src/utils/open-file.ts
4
+ async function openFile(filePath, lineNumber) {
5
+ const vsCodeUrl = lineNumber ? `vscode://file/${filePath}:${lineNumber}` : `vscode://file/${filePath}`;
6
+ try {
7
+ window.open(vsCodeUrl, "_blank");
8
+ return;
9
+ } catch {
10
+ }
11
+ try {
12
+ await fetch("/api/open-file", {
13
+ method: "POST",
14
+ headers: { "Content-Type": "application/json" },
15
+ body: JSON.stringify({ filePath, lineNumber })
16
+ });
17
+ } catch {
18
+ console.warn("[pinpoint] Could not open file:", filePath);
19
+ }
20
+ }
21
+
22
+ export {
23
+ openFile
24
+ };
25
+ //# sourceMappingURL=chunk-HAEYE6KB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/open-file.ts"],"sourcesContent":["// @agent-native/pinpoint — Open file in editor\r\n// MIT License\r\n\r\n/**\r\n * Open a file in the user's editor. Tries vscode:// protocol first,\r\n * falls back to a fetch to /api/open-file.\r\n */\r\nexport async function openFile(\r\n filePath: string,\r\n lineNumber?: number,\r\n): Promise<void> {\r\n // Try VS Code protocol\r\n const vsCodeUrl = lineNumber\r\n ? `vscode://file/${filePath}:${lineNumber}`\r\n : `vscode://file/${filePath}`;\r\n\r\n try {\r\n window.open(vsCodeUrl, \"_blank\");\r\n return;\r\n } catch {\r\n // VS Code not available\r\n }\r\n\r\n // Fallback: POST to server endpoint\r\n try {\r\n await fetch(\"/api/open-file\", {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ filePath, lineNumber }),\r\n });\r\n } catch {\r\n // Server endpoint not available\r\n console.warn(\"[pinpoint] Could not open file:\", filePath);\r\n }\r\n}\r\n"],"mappings":";;;AAOA,eAAsB,SACpB,UACA,YACe;AAEf,QAAM,YAAY,aACd,iBAAiB,QAAQ,IAAI,UAAU,KACvC,iBAAiB,QAAQ;AAE7B,MAAI;AACF,WAAO,KAAK,WAAW,QAAQ;AAC/B;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI;AACF,UAAM,MAAM,kBAAkB;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,WAAW,CAAC;AAAA,IAC/C,CAAC;AAAA,EACH,QAAQ;AAEN,YAAQ,KAAK,mCAAmC,QAAQ;AAAA,EAC1D;AACF;","names":[]}
@@ -0,0 +1,53 @@
1
+ // src/storage/schemas.ts
2
+ import { z } from "zod";
3
+ var ElementInfoSchema = z.object({
4
+ tagName: z.string(),
5
+ id: z.string().optional(),
6
+ classNames: z.array(z.string()),
7
+ selector: z.string(),
8
+ textContent: z.string().optional(),
9
+ boundingRect: z.object({
10
+ x: z.number(),
11
+ y: z.number(),
12
+ width: z.number(),
13
+ height: z.number()
14
+ }),
15
+ computedStyles: z.record(z.string(), z.string()).optional(),
16
+ ariaAttributes: z.record(z.string(), z.string()).optional(),
17
+ dataAttributes: z.record(z.string(), z.string()).optional(),
18
+ domPath: z.string().optional()
19
+ });
20
+ var FrameworkInfoSchema = z.object({
21
+ framework: z.string(),
22
+ componentPath: z.string(),
23
+ sourceFile: z.string().optional(),
24
+ frameworkVersion: z.string().optional()
25
+ });
26
+ var PinStatusSchema = z.enum([
27
+ "open",
28
+ "acknowledged",
29
+ "resolved",
30
+ "dismissed"
31
+ ]);
32
+ var PinSchema = z.object({
33
+ id: z.string().uuid(),
34
+ pageUrl: z.string(),
35
+ createdAt: z.string().datetime(),
36
+ updatedAt: z.string().datetime(),
37
+ author: z.string().optional(),
38
+ comment: z.string(),
39
+ element: ElementInfoSchema,
40
+ framework: FrameworkInfoSchema.optional(),
41
+ status: z.object({
42
+ state: PinStatusSchema,
43
+ changedAt: z.string().datetime(),
44
+ changedBy: z.string().optional()
45
+ })
46
+ });
47
+
48
+ export {
49
+ ElementInfoSchema,
50
+ FrameworkInfoSchema,
51
+ PinSchema
52
+ };
53
+ //# sourceMappingURL=chunk-J5PXKVTM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/schemas.ts"],"sourcesContent":["// @agent-native/pinpoint — Zod schemas for runtime validation\r\n// MIT License\r\n\r\nimport { z } from \"zod\";\r\n\r\nexport const ElementInfoSchema = z.object({\r\n tagName: z.string(),\r\n id: z.string().optional(),\r\n classNames: z.array(z.string()),\r\n selector: z.string(),\r\n textContent: z.string().optional(),\r\n boundingRect: z.object({\r\n x: z.number(),\r\n y: z.number(),\r\n width: z.number(),\r\n height: z.number(),\r\n }),\r\n computedStyles: z.record(z.string(), z.string()).optional(),\r\n ariaAttributes: z.record(z.string(), z.string()).optional(),\r\n dataAttributes: z.record(z.string(), z.string()).optional(),\r\n domPath: z.string().optional(),\r\n});\r\n\r\nexport const FrameworkInfoSchema = z.object({\r\n framework: z.string(),\r\n componentPath: z.string(),\r\n sourceFile: z.string().optional(),\r\n frameworkVersion: z.string().optional(),\r\n});\r\n\r\nexport const PinStatusSchema = z.enum([\r\n \"open\",\r\n \"acknowledged\",\r\n \"resolved\",\r\n \"dismissed\",\r\n]);\r\n\r\nexport const PinSchema = z.object({\r\n id: z.string().uuid(),\r\n pageUrl: z.string(),\r\n createdAt: z.string().datetime(),\r\n updatedAt: z.string().datetime(),\r\n author: z.string().optional(),\r\n comment: z.string(),\r\n element: ElementInfoSchema,\r\n framework: FrameworkInfoSchema.optional(),\r\n status: z.object({\r\n state: PinStatusSchema,\r\n changedAt: z.string().datetime(),\r\n changedBy: z.string().optional(),\r\n }),\r\n});\r\n\r\nexport type PinSchemaType = z.infer<typeof PinSchema>;\r\n"],"mappings":";AAGA,SAAS,SAAS;AAEX,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,SAAS,EAAE,OAAO;AAAA,EAClB,IAAI,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAC9B,UAAU,EAAE,OAAO;AAAA,EACnB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,cAAc,EAAE,OAAO;AAAA,IACrB,GAAG,EAAE,OAAO;AAAA,IACZ,GAAG,EAAE,OAAO;AAAA,IACZ,OAAO,EAAE,OAAO;AAAA,IAChB,QAAQ,EAAE,OAAO;AAAA,EACnB,CAAC;AAAA,EACD,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC1D,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC1D,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC1D,SAAS,EAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EAAE,OAAO;AAAA,EACpB,eAAe,EAAE,OAAO;AAAA,EACxB,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AACxC,CAAC;AAEM,IAAM,kBAAkB,EAAE,KAAK;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,YAAY,EAAE,OAAO;AAAA,EAChC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,SAAS,EAAE,OAAO;AAAA,EAClB,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,SAAS,EAAE,OAAO;AAAA,EAClB,SAAS;AAAA,EACT,WAAW,oBAAoB,SAAS;AAAA,EACxC,QAAQ,EAAE,OAAO;AAAA,IACf,OAAO;AAAA,IACP,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,CAAC;AACH,CAAC;","names":[]}
@@ -0,0 +1,94 @@
1
+ "use client";
2
+
3
+ // src/output/formatter.ts
4
+ function formatPins(pins, format = "standard") {
5
+ if (pins.length === 0) return "No annotations.";
6
+ const pageUrl = pins[0].pageUrl;
7
+ switch (format) {
8
+ case "compact":
9
+ return formatCompact(pins, pageUrl);
10
+ case "standard":
11
+ return formatStandard(pins, pageUrl);
12
+ case "detailed":
13
+ return formatDetailed(pins, pageUrl);
14
+ default:
15
+ return formatStandard(pins, pageUrl);
16
+ }
17
+ }
18
+ function formatCompact(pins, pageUrl) {
19
+ const lines = [`## Page Feedback: ${pageUrl} (${pins.length} annotations)`];
20
+ for (let i = 0; i < pins.length; i++) {
21
+ const pin = pins[i];
22
+ lines.push(`${i + 1}. \`${pin.element.selector}\` \u2014 "${pin.comment}"`);
23
+ }
24
+ return lines.join("\n");
25
+ }
26
+ function formatStandard(pins, pageUrl) {
27
+ const lines = [
28
+ `## Page Feedback: ${pageUrl}`,
29
+ `${pins.length} annotation${pins.length === 1 ? "" : "s"} | ${(/* @__PURE__ */ new Date()).toISOString()}`,
30
+ ""
31
+ ];
32
+ for (let i = 0; i < pins.length; i++) {
33
+ const pin = pins[i];
34
+ lines.push(`### ${i + 1}: \`${pin.element.selector}\``);
35
+ lines.push(`**Comment:** ${pin.comment}`);
36
+ lines.push(
37
+ `**Element:** \`<${pin.element.tagName}>\`${pin.element.classNames.length > 0 ? ` with classes \`.${pin.element.classNames.join(" .")}\`` : ""}`
38
+ );
39
+ if (pin.framework) {
40
+ lines.push(
41
+ `**Component:** ${pin.framework.componentPath} (${pin.framework.framework})`
42
+ );
43
+ if (pin.framework.sourceFile) {
44
+ lines.push(`**Source:** \`${pin.framework.sourceFile}\``);
45
+ }
46
+ }
47
+ const rect = pin.element.boundingRect;
48
+ lines.push(
49
+ `**Position:** (${rect.x}, ${rect.y}) ${rect.width}x${rect.height}`
50
+ );
51
+ lines.push(`**Status:** ${pin.status.state}`);
52
+ if (pin.author) {
53
+ lines.push(`**Author:** ${pin.author}`);
54
+ }
55
+ lines.push("");
56
+ }
57
+ return lines.join("\n");
58
+ }
59
+ function formatDetailed(pins, pageUrl) {
60
+ const lines = [formatStandard(pins, pageUrl)];
61
+ for (let i = 0; i < pins.length; i++) {
62
+ const pin = pins[i];
63
+ const detailLines = [];
64
+ if (pin.element.domPath) {
65
+ detailLines.push(`**DOM Path:** ${pin.element.domPath}`);
66
+ }
67
+ if (pin.element.computedStyles && Object.keys(pin.element.computedStyles).length > 0) {
68
+ const styles = Object.entries(pin.element.computedStyles).map(([key, value]) => `${key}: ${value}`).join(", ");
69
+ detailLines.push(`**Computed Styles:** ${styles}`);
70
+ }
71
+ if (pin.element.ariaAttributes && Object.keys(pin.element.ariaAttributes).length > 0) {
72
+ const aria = Object.entries(pin.element.ariaAttributes).map(([key, value]) => `${key}="${value}"`).join(", ");
73
+ detailLines.push(`**Accessibility:** ${aria}`);
74
+ }
75
+ if (pin.element.textContent) {
76
+ detailLines.push(`**Text Content:** "${pin.element.textContent}"`);
77
+ }
78
+ if (pin.element.dataAttributes && Object.keys(pin.element.dataAttributes).length > 0) {
79
+ const data = Object.entries(pin.element.dataAttributes).map(([key, value]) => `${key}="${value}"`).join(", ");
80
+ detailLines.push(`**Data Attributes:** ${data}`);
81
+ }
82
+ if (detailLines.length > 0) {
83
+ lines.push(`#### Details for #${i + 1}:`);
84
+ lines.push(detailLines.join("\n"));
85
+ lines.push("");
86
+ }
87
+ }
88
+ return lines.join("\n");
89
+ }
90
+
91
+ export {
92
+ formatPins
93
+ };
94
+ //# sourceMappingURL=chunk-XBX2J7WU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/output/formatter.ts"],"sourcesContent":["// @agent-native/pinpoint — Output formatting (compact/standard/detailed)\r\n// MIT License\r\n\r\nimport type { Pin, OutputFormat } from \"../types/index.js\";\r\n\r\n/**\r\n * Format pins into a human/agent-readable markdown string.\r\n */\r\nexport function formatPins(\r\n pins: Pin[],\r\n format: OutputFormat = \"standard\",\r\n): string {\r\n if (pins.length === 0) return \"No annotations.\";\r\n\r\n const pageUrl = pins[0].pageUrl;\r\n\r\n switch (format) {\r\n case \"compact\":\r\n return formatCompact(pins, pageUrl);\r\n case \"standard\":\r\n return formatStandard(pins, pageUrl);\r\n case \"detailed\":\r\n return formatDetailed(pins, pageUrl);\r\n default:\r\n return formatStandard(pins, pageUrl);\r\n }\r\n}\r\n\r\nfunction formatCompact(pins: Pin[], pageUrl: string): string {\r\n const lines = [`## Page Feedback: ${pageUrl} (${pins.length} annotations)`];\r\n for (let i = 0; i < pins.length; i++) {\r\n const pin = pins[i];\r\n lines.push(`${i + 1}. \\`${pin.element.selector}\\` — \"${pin.comment}\"`);\r\n }\r\n return lines.join(\"\\n\");\r\n}\r\n\r\nfunction formatStandard(pins: Pin[], pageUrl: string): string {\r\n const lines = [\r\n `## Page Feedback: ${pageUrl}`,\r\n `${pins.length} annotation${pins.length === 1 ? \"\" : \"s\"} | ${new Date().toISOString()}`,\r\n \"\",\r\n ];\r\n\r\n for (let i = 0; i < pins.length; i++) {\r\n const pin = pins[i];\r\n lines.push(`### ${i + 1}: \\`${pin.element.selector}\\``);\r\n lines.push(`**Comment:** ${pin.comment}`);\r\n lines.push(\r\n `**Element:** \\`<${pin.element.tagName}>\\`${pin.element.classNames.length > 0 ? ` with classes \\`.${pin.element.classNames.join(\" .\")}\\`` : \"\"}`,\r\n );\r\n\r\n if (pin.framework) {\r\n lines.push(\r\n `**Component:** ${pin.framework.componentPath} (${pin.framework.framework})`,\r\n );\r\n if (pin.framework.sourceFile) {\r\n lines.push(`**Source:** \\`${pin.framework.sourceFile}\\``);\r\n }\r\n }\r\n\r\n const rect = pin.element.boundingRect;\r\n lines.push(\r\n `**Position:** (${rect.x}, ${rect.y}) ${rect.width}x${rect.height}`,\r\n );\r\n lines.push(`**Status:** ${pin.status.state}`);\r\n\r\n if (pin.author) {\r\n lines.push(`**Author:** ${pin.author}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\nfunction formatDetailed(pins: Pin[], pageUrl: string): string {\r\n const lines = [formatStandard(pins, pageUrl)];\r\n\r\n // Append detailed info for each pin\r\n for (let i = 0; i < pins.length; i++) {\r\n const pin = pins[i];\r\n const detailLines: string[] = [];\r\n\r\n if (pin.element.domPath) {\r\n detailLines.push(`**DOM Path:** ${pin.element.domPath}`);\r\n }\r\n\r\n if (\r\n pin.element.computedStyles &&\r\n Object.keys(pin.element.computedStyles).length > 0\r\n ) {\r\n const styles = Object.entries(pin.element.computedStyles)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join(\", \");\r\n detailLines.push(`**Computed Styles:** ${styles}`);\r\n }\r\n\r\n if (\r\n pin.element.ariaAttributes &&\r\n Object.keys(pin.element.ariaAttributes).length > 0\r\n ) {\r\n const aria = Object.entries(pin.element.ariaAttributes)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(\", \");\r\n detailLines.push(`**Accessibility:** ${aria}`);\r\n }\r\n\r\n if (pin.element.textContent) {\r\n detailLines.push(`**Text Content:** \"${pin.element.textContent}\"`);\r\n }\r\n\r\n if (\r\n pin.element.dataAttributes &&\r\n Object.keys(pin.element.dataAttributes).length > 0\r\n ) {\r\n const data = Object.entries(pin.element.dataAttributes)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(\", \");\r\n detailLines.push(`**Data Attributes:** ${data}`);\r\n }\r\n\r\n if (detailLines.length > 0) {\r\n lines.push(`#### Details for #${i + 1}:`);\r\n lines.push(detailLines.join(\"\\n\"));\r\n lines.push(\"\");\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n"],"mappings":"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","names":[]}