@wasao/kagemusha 0.2.0 → 0.3.5

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 (93) hide show
  1. package/README.md +103 -453
  2. package/dist/commands/capture.js +57 -35
  3. package/dist/commands/capture.js.map +1 -1
  4. package/dist/commands/edit.d.ts +1 -1
  5. package/dist/commands/edit.d.ts.map +1 -1
  6. package/dist/commands/edit.js +46 -8
  7. package/dist/commands/edit.js.map +1 -1
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +82 -83
  10. package/dist/commands/init.js.map +1 -1
  11. package/dist/commands/login.d.ts.map +1 -1
  12. package/dist/commands/login.js +14 -18
  13. package/dist/commands/login.js.map +1 -1
  14. package/dist/editor/inject-script/annotations.d.ts +11 -0
  15. package/dist/editor/inject-script/annotations.d.ts.map +1 -0
  16. package/dist/editor/inject-script/annotations.js +409 -0
  17. package/dist/editor/inject-script/annotations.js.map +1 -0
  18. package/dist/editor/inject-script/bridge.d.ts +13 -0
  19. package/dist/editor/inject-script/bridge.d.ts.map +1 -0
  20. package/dist/editor/inject-script/bridge.js +33 -0
  21. package/dist/editor/inject-script/bridge.js.map +1 -0
  22. package/dist/editor/inject-script/crop.d.ts +9 -0
  23. package/dist/editor/inject-script/crop.d.ts.map +1 -0
  24. package/dist/editor/inject-script/crop.js +236 -0
  25. package/dist/editor/inject-script/crop.js.map +1 -0
  26. package/dist/editor/inject-script/dom.d.ts +7 -0
  27. package/dist/editor/inject-script/dom.d.ts.map +1 -0
  28. package/dist/editor/inject-script/dom.js +32 -0
  29. package/dist/editor/inject-script/dom.js.map +1 -0
  30. package/dist/editor/inject-script/index.d.ts +2 -0
  31. package/dist/editor/inject-script/index.d.ts.map +1 -0
  32. package/dist/editor/inject-script/index.js +56 -0
  33. package/dist/editor/inject-script/index.js.map +1 -0
  34. package/dist/editor/inject-script/record.d.ts +5 -0
  35. package/dist/editor/inject-script/record.d.ts.map +1 -0
  36. package/dist/editor/inject-script/record.js +398 -0
  37. package/dist/editor/inject-script/record.js.map +1 -0
  38. package/dist/editor/inject-script/selector.d.ts +6 -0
  39. package/dist/editor/inject-script/selector.d.ts.map +1 -0
  40. package/dist/editor/inject-script/selector.js +112 -0
  41. package/dist/editor/inject-script/selector.js.map +1 -0
  42. package/dist/editor/inject-script/state.d.ts +27 -0
  43. package/dist/editor/inject-script/state.d.ts.map +1 -0
  44. package/dist/editor/inject-script/state.js +26 -0
  45. package/dist/editor/inject-script/state.js.map +1 -0
  46. package/dist/editor/inject-script/svg.d.ts +7 -0
  47. package/dist/editor/inject-script/svg.d.ts.map +1 -0
  48. package/dist/editor/inject-script/svg.js +39 -0
  49. package/dist/editor/inject-script/svg.js.map +1 -0
  50. package/dist/editor/inject-script/toolbar.d.ts +14 -0
  51. package/dist/editor/inject-script/toolbar.d.ts.map +1 -0
  52. package/dist/editor/inject-script/toolbar.js +240 -0
  53. package/dist/editor/inject-script/toolbar.js.map +1 -0
  54. package/dist/editor/inject-script/types.d.ts +102 -0
  55. package/dist/editor/inject-script/types.d.ts.map +1 -0
  56. package/dist/editor/inject-script/types.js +5 -0
  57. package/dist/editor/inject-script/types.js.map +1 -0
  58. package/dist/editor/inject-script.js +1248 -699
  59. package/dist/index.js +9 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/lib/canonical.d.ts +35 -3
  62. package/dist/lib/canonical.d.ts.map +1 -1
  63. package/dist/lib/canonical.js +85 -25
  64. package/dist/lib/canonical.js.map +1 -1
  65. package/dist/lib/crawl.js +1 -1
  66. package/dist/lib/crawl.js.map +1 -1
  67. package/dist/lib/diff.d.ts +23 -4
  68. package/dist/lib/diff.d.ts.map +1 -1
  69. package/dist/lib/diff.js +5 -6
  70. package/dist/lib/diff.js.map +1 -1
  71. package/dist/lib/page-ready.d.ts +18 -0
  72. package/dist/lib/page-ready.d.ts.map +1 -0
  73. package/dist/lib/page-ready.js +19 -0
  74. package/dist/lib/page-ready.js.map +1 -0
  75. package/dist/lib/playwright-launch.d.ts +4 -0
  76. package/dist/lib/playwright-launch.d.ts.map +1 -0
  77. package/dist/lib/playwright-launch.js +11 -0
  78. package/dist/lib/playwright-launch.js.map +1 -0
  79. package/dist/lib/screenshot.d.ts +4 -1
  80. package/dist/lib/screenshot.d.ts.map +1 -1
  81. package/dist/lib/screenshot.js +37 -7
  82. package/dist/lib/screenshot.js.map +1 -1
  83. package/dist/lib/staging.d.ts +0 -1
  84. package/dist/lib/staging.d.ts.map +1 -1
  85. package/dist/lib/staging.js +0 -3
  86. package/dist/lib/staging.js.map +1 -1
  87. package/dist/types.d.ts +5 -0
  88. package/dist/types.d.ts.map +1 -1
  89. package/package.json +22 -12
  90. package/templates/notify-slack.jq +30 -0
  91. package/dist/editor/inject-script.d.ts +0 -2
  92. package/dist/editor/inject-script.d.ts.map +0 -1
  93. package/dist/editor/inject-script.js.map +0 -1
@@ -0,0 +1,398 @@
1
+ // Pre-capture step recording — record clicks / inputs / selects during a
2
+ // "Record" mode, plus explicit buttons for + Wait / + WaitForSelector /
3
+ // + Hover (= things you can't infer from passive observation).
4
+ //
5
+ // Design notes:
6
+ // - Record ON wipes existing recordedSteps after a confirmation. OFF just
7
+ // stops collecting; the panel keeps showing what was captured.
8
+ // - While recording, the SVG overlay is set to `pointer-events: none` so
9
+ // clicks reach the host page. Annotation / crop buttons are disabled.
10
+ // - Toolbar self-clicks and the steps panel itself are excluded from
11
+ // recording (= we don't record interactions with kagemusha's own UI).
12
+ // - The eventual hosted GUI will replace the click/input listeners with
13
+ // message-bus events but keep the same step shape.
14
+ import { computeSelector } from "./selector.js";
15
+ import { state } from "./state.js";
16
+ // Excluded selectors — any event whose target is inside one of these is
17
+ // not recorded (= kagemusha's own UI).
18
+ const KAGEMUSHA_UI_SELECTORS = [
19
+ "#kagemusha-toolbar",
20
+ "#kagemusha-svg-layer",
21
+ ".kagemusha-hint",
22
+ ".kagemusha-steps-panel",
23
+ ".kagemusha-prompt",
24
+ ];
25
+ const isOwnUi = (el) => {
26
+ if (!(el instanceof Element))
27
+ return false;
28
+ return KAGEMUSHA_UI_SELECTORS.some((s) => el.closest(s) !== null);
29
+ };
30
+ let svgRef = null;
31
+ let panelEl = null;
32
+ let pickerOutlineEl = null;
33
+ let panelOpen = false;
34
+ // --- Steps panel (read-only list) ---
35
+ const ensurePanel = () => {
36
+ if (panelEl)
37
+ return panelEl;
38
+ const div = document.createElement("div");
39
+ div.className = "kagemusha-steps-panel";
40
+ div.setAttribute("style",
41
+ // Anchored just below the toolbar (top: 60px) so it's visible without
42
+ // scrolling. Fills available vertical space minus a small bottom margin.
43
+ "position:fixed;top:60px;right:16px;width:340px;max-height:calc(100vh - 80px);" +
44
+ "overflow-y:auto;background:#1a1a2e;color:#fff;padding:12px 16px;" +
45
+ "border-radius:8px;font-family:-apple-system,sans-serif;font-size:12px;" +
46
+ "line-height:1.5;z-index:var(--kg-z-top);box-shadow:0 4px 16px rgba(0,0,0,0.4);" +
47
+ "display:none;");
48
+ document.documentElement.appendChild(div);
49
+ panelEl = div;
50
+ return div;
51
+ };
52
+ const renderPanel = () => {
53
+ const panel = ensurePanel();
54
+ updateToggleButton();
55
+ if (!panelOpen) {
56
+ panel.style.display = "none";
57
+ return;
58
+ }
59
+ panel.style.display = "block";
60
+ const header = state.recording
61
+ ? `<div style="color:#ef4444;font-weight:600;margin-bottom:6px;">📹 Recording... (${state.recordedSteps.length} steps)</div>`
62
+ : `<div style="color:#7a89b0;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px;">Steps (${state.recordedSteps.length})</div>`;
63
+ const rows = state.recordedSteps
64
+ .map((s, i) => `<div>${i + 1}. ${renderStepLine(s)}</div>`)
65
+ .join("");
66
+ panel.innerHTML = `${header}${rows || '<div style="color:#888;">(no steps)</div>'}`;
67
+ };
68
+ const updateToggleButton = () => {
69
+ const btn = document.getElementById("kg-steps-toggle");
70
+ if (!btn)
71
+ return;
72
+ const n = state.recordedSteps.length;
73
+ const recording = state.recording;
74
+ btn.textContent = recording
75
+ ? `📹 Steps (${n})`
76
+ : n > 0
77
+ ? `📋 Steps (${n})`
78
+ : "📋 Steps (0)";
79
+ btn.classList.toggle("has-steps", n > 0 && !panelOpen);
80
+ btn.classList.toggle("open", panelOpen);
81
+ };
82
+ const openPanel = () => {
83
+ panelOpen = true;
84
+ renderPanel();
85
+ };
86
+ const closePanel = () => {
87
+ panelOpen = false;
88
+ renderPanel();
89
+ };
90
+ const togglePanel = () => {
91
+ if (panelOpen)
92
+ closePanel();
93
+ else
94
+ openPanel();
95
+ };
96
+ const escapeHtml = (v) => v.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
97
+ const optBadge = (s) => s.optional
98
+ ? ' <span style="color:#7a89b0;font-size:10px;background:#2a2a4e;padding:1px 5px;border-radius:3px;margin-left:4px;">optional</span>'
99
+ : "";
100
+ const renderStepLine = (s) => {
101
+ switch (s.action) {
102
+ case "click":
103
+ return `<b>click</b> ${escapeHtml(s.selector)}${optBadge(s)}`;
104
+ case "type":
105
+ return `<b>type</b> ${escapeHtml(s.selector)} → "${escapeHtml(s.text)}"${optBadge(s)}`;
106
+ case "select":
107
+ return `<b>select</b> ${escapeHtml(s.selector)} → "${escapeHtml(s.value)}"${optBadge(s)}`;
108
+ case "hover":
109
+ return `<b>hover</b> ${escapeHtml(s.selector)}${optBadge(s)}`;
110
+ case "wait":
111
+ return `<b>wait</b> ${s.ms}ms`;
112
+ case "waitForSelector":
113
+ return `<b>waitForSelector</b> ${escapeHtml(s.selector)}${s.timeout ? ` (${s.timeout}ms)` : ""}${optBadge(s)}`;
114
+ default:
115
+ return `<b>${s.action}</b>`;
116
+ }
117
+ };
118
+ // --- Recording lifecycle ---
119
+ const updateToolbarLockState = () => {
120
+ // Annotation + capture-mode + delete buttons are disabled while recording
121
+ // so user can't draw rectangles into "the page they're recording on".
122
+ const lock = state.recording;
123
+ for (const id of [
124
+ "kg-tool-rect",
125
+ "kg-tool-arrow",
126
+ "kg-tool-label",
127
+ "kg-cap-full",
128
+ "kg-cap-crop",
129
+ "kg-delete",
130
+ ]) {
131
+ const btn = document.getElementById(id);
132
+ if (btn)
133
+ btn.disabled = lock;
134
+ }
135
+ // Step builder buttons are entirely hidden when not recording (= clearer
136
+ // than disabled-but-greyed-out; the buttons appear/disappear with Record).
137
+ const group = document.getElementById("kg-rec-group");
138
+ if (group)
139
+ group.classList.toggle("visible", lock);
140
+ // Record toggle reflects current state.
141
+ const recBtn = document.getElementById("kg-record");
142
+ if (recBtn) {
143
+ recBtn.textContent = state.recording ? "⏹ Stop" : "🔴 Record";
144
+ recBtn.classList.toggle("active", state.recording);
145
+ }
146
+ if (svgRef) {
147
+ // Block svg clicks while recording so the host page receives them.
148
+ svgRef.style.pointerEvents = state.recording ? "none" : "";
149
+ }
150
+ };
151
+ const setRecording = (on) => {
152
+ if (on) {
153
+ if (state.recordedSteps.length > 0) {
154
+ const ok = window.confirm(`Recording will replace the existing ${state.recordedSteps.length} step(s). Continue?`);
155
+ if (!ok)
156
+ return;
157
+ }
158
+ state.recordedSteps = [];
159
+ state.recording = true;
160
+ }
161
+ else {
162
+ state.recording = false;
163
+ cancelPicker();
164
+ }
165
+ updateToolbarLockState();
166
+ renderPanel();
167
+ };
168
+ // --- Picker mode (single-shot element selection for + Hover / + WaitForSelector) ---
169
+ const pickerButtonId = (kind) => kind === "hover" ? "kg-rec-hover" : "kg-rec-wfs";
170
+ const startPicker = (kind) => {
171
+ if (!state.recording)
172
+ return;
173
+ state.pickerKind = kind;
174
+ // Highlight the button that initiated picking so user can see they're in
175
+ // picker mode (and which kind).
176
+ document.getElementById(pickerButtonId(kind))?.classList.add("picking");
177
+ if (svgRef)
178
+ svgRef.style.cursor = "crosshair";
179
+ showPrompt(kind === "hover"
180
+ ? "Hover an element, click to confirm. ESC to cancel."
181
+ : "Hover an element, click to confirm. ESC to cancel.");
182
+ };
183
+ const cancelPicker = () => {
184
+ if (state.pickerKind) {
185
+ document
186
+ .getElementById(pickerButtonId(state.pickerKind))
187
+ ?.classList.remove("picking");
188
+ }
189
+ state.pickerKind = null;
190
+ if (svgRef)
191
+ svgRef.style.cursor = "";
192
+ hidePrompt();
193
+ hidePickerOutline();
194
+ };
195
+ const ensurePickerOutline = () => {
196
+ if (pickerOutlineEl)
197
+ return pickerOutlineEl;
198
+ const div = document.createElement("div");
199
+ div.className = "kagemusha-picker-outline";
200
+ div.style.display = "none";
201
+ document.documentElement.appendChild(div);
202
+ pickerOutlineEl = div;
203
+ return div;
204
+ };
205
+ const showPickerOutline = (rect) => {
206
+ const el = ensurePickerOutline();
207
+ el.style.display = "block";
208
+ el.style.left = `${rect.left}px`;
209
+ el.style.top = `${rect.top}px`;
210
+ el.style.width = `${rect.width}px`;
211
+ el.style.height = `${rect.height}px`;
212
+ };
213
+ const hidePickerOutline = () => {
214
+ if (pickerOutlineEl)
215
+ pickerOutlineEl.style.display = "none";
216
+ };
217
+ let promptEl = null;
218
+ const showPrompt = (message) => {
219
+ if (!promptEl) {
220
+ const div = document.createElement("div");
221
+ div.className = "kagemusha-prompt";
222
+ div.setAttribute("style", "position:fixed;top:60px;left:50%;transform:translateX(-50%);" +
223
+ "background:#0ea5e9;color:#fff;padding:10px 18px;border-radius:8px;" +
224
+ "font-family:-apple-system,sans-serif;font-size:13px;" +
225
+ "z-index:var(--kg-z-top);box-shadow:0 4px 12px rgba(0,0,0,0.3);");
226
+ document.documentElement.appendChild(div);
227
+ promptEl = div;
228
+ }
229
+ promptEl.textContent = message;
230
+ promptEl.style.display = "block";
231
+ };
232
+ const hidePrompt = () => {
233
+ if (promptEl)
234
+ promptEl.style.display = "none";
235
+ };
236
+ // --- Event listeners ---
237
+ const onClickCapture = (e) => {
238
+ if (!state.recording)
239
+ return;
240
+ if (isOwnUi(e.target))
241
+ return;
242
+ const el = e.target;
243
+ if (!el)
244
+ return;
245
+ // Picker mode: one-shot element selection
246
+ if (state.pickerKind) {
247
+ e.preventDefault();
248
+ e.stopPropagation();
249
+ const kind = state.pickerKind;
250
+ const sel = computeSelector(el);
251
+ if (kind === "hover") {
252
+ state.recordedSteps.push({ action: "hover", selector: sel.selector });
253
+ }
254
+ else {
255
+ state.recordedSteps.push({
256
+ action: "waitForSelector",
257
+ selector: sel.selector,
258
+ });
259
+ }
260
+ cancelPicker();
261
+ renderPanel();
262
+ return;
263
+ }
264
+ // Normal record: append a click step. The page still receives the click
265
+ // because we don't preventDefault — we only observe.
266
+ //
267
+ // `optional: true` so capture doesn't fail when the recorded element is
268
+ // absent on a re-run (= session-dependent modals, AB-test variants, etc).
269
+ // User can flip to false in definitions.json if the step must succeed.
270
+ const sel = computeSelector(el);
271
+ state.recordedSteps.push({
272
+ action: "click",
273
+ selector: sel.selector,
274
+ optional: true,
275
+ });
276
+ renderPanel();
277
+ };
278
+ const onChangeCapture = (e) => {
279
+ if (!state.recording)
280
+ return;
281
+ if (isOwnUi(e.target))
282
+ return;
283
+ const target = e.target;
284
+ if (!target)
285
+ return;
286
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
287
+ const input = target;
288
+ // Skip checkbox/radio — those are click semantics, not "type a value".
289
+ const type = input.type;
290
+ if (type === "checkbox" || type === "radio")
291
+ return;
292
+ const sel = computeSelector(input);
293
+ // optional:true — same reasoning as click. See onClickCapture.
294
+ state.recordedSteps.push({
295
+ action: "type",
296
+ selector: sel.selector,
297
+ text: input.value,
298
+ optional: true,
299
+ });
300
+ renderPanel();
301
+ return;
302
+ }
303
+ if (target.tagName === "SELECT") {
304
+ const select = target;
305
+ const sel = computeSelector(select);
306
+ state.recordedSteps.push({
307
+ action: "select",
308
+ selector: sel.selector,
309
+ value: select.value,
310
+ optional: true,
311
+ });
312
+ renderPanel();
313
+ }
314
+ };
315
+ const onKeyDownCapture = (e) => {
316
+ if (state.pickerKind && e.key === "Escape") {
317
+ cancelPicker();
318
+ }
319
+ };
320
+ const onMouseMoveCapture = (e) => {
321
+ if (!state.pickerKind)
322
+ return;
323
+ if (isOwnUi(e.target)) {
324
+ hidePickerOutline();
325
+ return;
326
+ }
327
+ const el = e.target;
328
+ if (!el)
329
+ return;
330
+ showPickerOutline(el.getBoundingClientRect());
331
+ };
332
+ // Close the steps popover when clicking outside it (or the toggle button).
333
+ // We listen in the bubble phase so the toggle's own stopPropagation can
334
+ // preempt this, and we bail if the click landed inside the panel.
335
+ const onOutsideClick = (e) => {
336
+ if (!panelOpen)
337
+ return;
338
+ const target = e.target;
339
+ if (!target)
340
+ return;
341
+ if (target.closest(".kagemusha-steps-panel"))
342
+ return;
343
+ if (target.closest("#kg-steps-toggle"))
344
+ return;
345
+ closePanel();
346
+ };
347
+ // --- Step builder buttons ---
348
+ const promptForWaitMs = () => {
349
+ const raw = window.prompt("Wait for how many milliseconds?", "3000");
350
+ if (raw === null)
351
+ return;
352
+ const ms = Number.parseInt(raw, 10);
353
+ if (Number.isNaN(ms) || ms <= 0)
354
+ return;
355
+ state.recordedSteps.push({ action: "wait", ms });
356
+ renderPanel();
357
+ };
358
+ // --- Init ---
359
+ export const initRecord = (svg) => {
360
+ svgRef = svg;
361
+ ensurePanel();
362
+ document
363
+ .getElementById("kg-record")
364
+ ?.addEventListener("click", () => setRecording(!state.recording));
365
+ document
366
+ .getElementById("kg-rec-wait")
367
+ ?.addEventListener("click", () => promptForWaitMs());
368
+ document
369
+ .getElementById("kg-rec-wfs")
370
+ ?.addEventListener("click", () => startPicker("waitForSelector"));
371
+ document
372
+ .getElementById("kg-rec-hover")
373
+ ?.addEventListener("click", () => startPicker("hover"));
374
+ document.getElementById("kg-steps-toggle")?.addEventListener("click", (e) => {
375
+ e.stopPropagation();
376
+ togglePanel();
377
+ });
378
+ // Capture-phase listeners on document — we want first dibs so we can
379
+ // observe events on elements that stopPropagation later.
380
+ document.addEventListener("click", onClickCapture, true);
381
+ document.addEventListener("change", onChangeCapture, true);
382
+ document.addEventListener("keydown", onKeyDownCapture, true);
383
+ document.addEventListener("mousemove", onMouseMoveCapture, true);
384
+ // Outside click closes the panel. Use bubble phase so that clicks on the
385
+ // toggle / inside the panel can suppress this via stopPropagation /
386
+ // closest checks before it reaches here.
387
+ document.addEventListener("click", onOutsideClick);
388
+ updateToolbarLockState();
389
+ renderPanel();
390
+ };
391
+ // Called by bridge on load to seed from existing definition.beforeCapture.
392
+ export const loadSteps = (steps) => {
393
+ state.recordedSteps = [...steps];
394
+ renderPanel();
395
+ };
396
+ // Called by bridge on save.
397
+ export const serializeSteps = () => [...state.recordedSteps];
398
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/editor/inject-script/record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface SelectorResult {
2
+ selector: string;
3
+ quality: "good" | "fallback";
4
+ }
5
+ export declare const computeSelector: (raw: Element) => SelectorResult;
6
+ //# sourceMappingURL=selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../../src/editor/inject-script/selector.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,cAAc;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;CAC7B;AAwED,eAAO,MAAM,eAAe,GAAI,KAAK,OAAO,KAAG,cAkC9C,CAAC"}
@@ -0,0 +1,112 @@
1
+ // Selector strategy — compute a Playwright-compatible selector string for a
2
+ // recorded element. Priority order targets stability:
3
+ //
4
+ // 1. data-testid — explicit test hook, the most stable signal
5
+ // 2. aria-label — semantic, survives layout/style changes
6
+ // 3. role + text (button/link with short text content)
7
+ // 4. text="..." — exact text match
8
+ // 5. minimal CSS path — fallback when nothing better is available
9
+ //
10
+ // Returns `{ selector, quality }`. `quality: "fallback"` means the result
11
+ // is a brittle CSS path; the steps panel surfaces this with a ⚠ icon so
12
+ // the user knows to add a data-testid to that element.
13
+ //
14
+ // Pure function — no DOM mutation, no editor state. Tested without a page.
15
+ const escapeQuotes = (s) => s.replace(/"/g, '\\"');
16
+ // Roughly mirrors Playwright's role inference for elements without an
17
+ // explicit `role` attribute. Limited to the cases the editor cares about.
18
+ const inferRole = (el) => {
19
+ const tag = el.tagName;
20
+ if (tag === "BUTTON")
21
+ return "button";
22
+ if (tag === "A" && el.hasAttribute("href"))
23
+ return "link";
24
+ if (tag === "INPUT") {
25
+ const type = el.type;
26
+ if (type === "button" || type === "submit")
27
+ return "button";
28
+ if (type === "checkbox")
29
+ return "checkbox";
30
+ if (type === "radio")
31
+ return "radio";
32
+ }
33
+ return null;
34
+ };
35
+ const isInteractiveAncestor = (el) => {
36
+ // Walk up to the nearest interactive ancestor — useful when the user
37
+ // clicks on an icon inside a <button>.
38
+ let cur = el;
39
+ while (cur) {
40
+ if (cur.tagName === "BUTTON" ||
41
+ cur.tagName === "A" ||
42
+ cur.getAttribute("role") === "button" ||
43
+ cur.getAttribute("role") === "link" ||
44
+ cur.hasAttribute("data-testid")) {
45
+ return cur;
46
+ }
47
+ cur = cur.parentElement;
48
+ }
49
+ return null;
50
+ };
51
+ // Build a stable-ish CSS selector by walking up to the first ancestor with
52
+ // a unique id/class, then using nth-child from there. We deliberately keep
53
+ // the result short (max 4 segments) — long paths are signal that nothing
54
+ // stable was available, and the user should add a data-testid.
55
+ const cssPath = (el) => {
56
+ const parts = [];
57
+ let cur = el;
58
+ let depth = 0;
59
+ while (cur && depth < 4 && cur !== document.body) {
60
+ const node = cur;
61
+ const tag = node.tagName;
62
+ let segment = tag.toLowerCase();
63
+ const id = node.id;
64
+ if (id && /^[a-zA-Z][\w-]*$/.test(id)) {
65
+ parts.unshift(`#${id}`);
66
+ break;
67
+ }
68
+ const parent = node.parentElement;
69
+ if (parent) {
70
+ const siblings = Array.from(parent.children).filter((c) => c.tagName === tag);
71
+ if (siblings.length > 1) {
72
+ const idx = siblings.indexOf(node) + 1;
73
+ segment += `:nth-of-type(${idx})`;
74
+ }
75
+ }
76
+ parts.unshift(segment);
77
+ cur = parent;
78
+ depth++;
79
+ }
80
+ return parts.join(" > ");
81
+ };
82
+ export const computeSelector = (raw) => {
83
+ // Prefer an interactive ancestor — clicks on icons inside buttons should
84
+ // select the button.
85
+ const el = isInteractiveAncestor(raw) ?? raw;
86
+ const testId = el.getAttribute("data-testid");
87
+ if (testId) {
88
+ return {
89
+ selector: `[data-testid="${escapeQuotes(testId)}"]`,
90
+ quality: "good",
91
+ };
92
+ }
93
+ const ariaLabel = el.getAttribute("aria-label");
94
+ if (ariaLabel) {
95
+ return {
96
+ selector: `[aria-label="${escapeQuotes(ariaLabel)}"]`,
97
+ quality: "good",
98
+ };
99
+ }
100
+ const role = el.getAttribute("role") ?? inferRole(el);
101
+ const text = el.textContent?.trim();
102
+ if (role && text && text.length > 0 && text.length < 50) {
103
+ // Playwright recognizes `text="..."` as an exact-match selector,
104
+ // which is more reliable than role= for kagemusha's use case.
105
+ return { selector: `text="${escapeQuotes(text)}"`, quality: "good" };
106
+ }
107
+ if (text && text.length > 0 && text.length < 50 && !/\n/.test(text)) {
108
+ return { selector: `text="${escapeQuotes(text)}"`, quality: "good" };
109
+ }
110
+ return { selector: cssPath(el), quality: "fallback" };
111
+ };
112
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../../../src/editor/inject-script/selector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Annotation, CaptureAction, CropDragState, DragState, Tool } from "./types.js";
2
+ export declare const SVG_NS = "http://www.w3.org/2000/svg";
3
+ export declare const HANDLE_SIZE = 10;
4
+ export declare const MIN_CROP = 10;
5
+ export type PickerKind = "hover" | "waitForSelector";
6
+ interface EditorState {
7
+ tool: Tool;
8
+ annotations: Annotation[];
9
+ selectedId: string | null;
10
+ dragState: DragState | null;
11
+ nextId: number;
12
+ captureMode: "fullPage" | "crop";
13
+ captureCrop: {
14
+ x: number;
15
+ y: number;
16
+ w: number;
17
+ h: number;
18
+ } | null;
19
+ cropDragState: CropDragState | null;
20
+ recordedSteps: CaptureAction[];
21
+ recording: boolean;
22
+ pickerKind: PickerKind | null;
23
+ }
24
+ export declare const state: EditorState;
25
+ export declare const allocateAnnotationId: () => string;
26
+ export {};
27
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/editor/inject-script/state.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,SAAS,EACT,IAAI,EACJ,MAAM,YAAY,CAAC;AAIpB,eAAO,MAAM,MAAM,+BAA+B,CAAC;AACnD,eAAO,MAAM,WAAW,KAAK,CAAC;AAC9B,eAAO,MAAM,QAAQ,KAAK,CAAC;AAU3B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,iBAAiB,CAAC;AAErD,UAAU,WAAW;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IAIf,WAAW,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnE,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAKpC,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CAC9B;AAED,eAAO,MAAM,KAAK,EAAE,WAYnB,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAO,MAA8B,CAAC"}
@@ -0,0 +1,26 @@
1
+ // Centralized editor state. Putting all mutable state in one place is the
2
+ // boundary we'll cross when porting to a hosted GUI: the React/Vue version
3
+ // will replace this with a reactive store while keeping the surface area
4
+ // (state shape + getters) identical.
5
+ //
6
+ // Don't read these fields directly from DOM modules — go through getters so
7
+ // the same module works against both this plain object and a future store.
8
+ // --- Constants ---
9
+ export const SVG_NS = "http://www.w3.org/2000/svg";
10
+ export const HANDLE_SIZE = 10;
11
+ export const MIN_CROP = 10;
12
+ export const state = {
13
+ tool: "rect",
14
+ annotations: [],
15
+ selectedId: null,
16
+ dragState: null,
17
+ nextId: 1,
18
+ captureMode: "fullPage",
19
+ captureCrop: null,
20
+ cropDragState: null,
21
+ recordedSteps: [],
22
+ recording: false,
23
+ pickerKind: null,
24
+ };
25
+ export const allocateAnnotationId = () => `a${state.nextId++}`;
26
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/editor/inject-script/state.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,2EAA2E;AAC3E,yEAAyE;AACzE,qCAAqC;AACrC,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAU3E,oBAAoB;AAEpB,MAAM,CAAC,MAAM,MAAM,GAAG,4BAA4B,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC9B,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAiC3B,MAAM,CAAC,MAAM,KAAK,GAAgB;IACjC,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,EAAE;IACf,UAAU,EAAE,IAAI;IAChB,SAAS,EAAE,IAAI;IACf,MAAM,EAAE,CAAC;IACT,WAAW,EAAE,UAAU;IACvB,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,KAAK;IAChB,UAAU,EAAE,IAAI;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAW,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const initSvgLayer: () => {
2
+ svg: SVGElement;
3
+ captureGroup: SVGGElement;
4
+ };
5
+ export declare const getSvg: () => SVGElement;
6
+ export declare const getCaptureGroup: () => SVGGElement;
7
+ //# sourceMappingURL=svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../../src/editor/inject-script/svg.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY,QAAO;IAC/B,GAAG,EAAE,UAAU,CAAC;IAChB,YAAY,EAAE,WAAW,CAAC;CA2B1B,CAAC;AAEF,eAAO,MAAM,MAAM,QAAO,UAGzB,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,WAGlC,CAAC"}