@jay-framework/aiditor 0.16.2

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.
@@ -0,0 +1,759 @@
1
+ <html>
2
+ <head>
3
+ <meta charset="UTF-8" />
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
+ <title>AIditor</title>
6
+ <style>
7
+ *, *::before, *::after { box-sizing: border-box; }
8
+ html, body { margin: 0; padding: 0; height: 100%; background: #252526; color: #d4d4d4; font-family: 'Segoe UI', system-ui, sans-serif; }
9
+ .setup-screen { height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; background: #1e1e1e; gap: 10px; }
10
+ .setup-title { margin: 0 0 4px; font-size: 28px; color: #9cdcfe; }
11
+ .setup-desc { margin: 0 0 20px; font-size: 14px; color: #888; }
12
+ .setup-form { display: flex; flex-direction: column; gap: 6px; width: 360px; }
13
+ .setup-label { font-size: 12px; color: #aaa; margin-top: 8px; }
14
+ .setup-input { background: #252526; color: #d4d4d4; border: 1px solid #3e3e3e; border-radius: 6px; padding: 10px 14px; font-size: 13px; outline: none; font-family: monospace; width: 100%; }
15
+ .setup-input:focus { border-color: #0e639c; }
16
+ .setup-hint { margin: 2px 0 0; font-size: 11px; color: #555; }
17
+ .setup-btn { margin-top: 16px; background: #0e639c; color: #fff; border: none; border-radius: 6px; padding: 10px 24px; font-size: 14px; cursor: pointer; align-self: flex-start; }
18
+ .setup-btn:hover { background: #1177bb; }
19
+ .setup-btn:disabled { opacity: 0.45; cursor: not-allowed; }
20
+ .bootstrap-msg { max-width: 420px; text-align: center; line-height: 1.45; color: #f48771; }
21
+ .root { display: flex; height: 100vh; overflow: hidden; flex-direction: column; }
22
+ .main-panel { flex: 1; padding: 0; overflow: hidden; background: #252526; display: flex; flex-direction: column; min-height: 0; }
23
+ .main-top-bar { flex-shrink: 0; display: flex; align-items: center; gap: 10px; padding: 12px 20px 0; flex-wrap: wrap; }
24
+ .main-top-bar-spacer { flex: 1; min-width: 8px; }
25
+ .reset-btn { background: #2d2d30; border: 1px solid #3e3e3e; color: #ccc; cursor: pointer; font-size: 14px; padding: 8px 12px; border-radius: 6px; line-height: 1; }
26
+ .reset-btn:hover { color: #fff; border-color: #9cdcfe; }
27
+ .route-picker-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; width: 100%; }
28
+ .aiditor-dropdown { width: 100%; min-width: 240px; background: #1e1e1e; color: #d4d4d4; border: 1px solid #9cdcfe; border-radius: 6px; padding: 8px 32px 8px 12px; font-size: 13px; font-family: ui-monospace, monospace; cursor: pointer; outline: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%239cdcfe' d='M3 4.5L6 8l3-3.5H3z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; }
29
+ .aiditor-dropdown:focus { border-color: #3794ff; box-shadow: 0 0 0 1px rgba(55,148,255,0.35); }
30
+ .aiditor-dropdown option { background: #f3f3f3; color: #1e1e1e; }
31
+ .preview-stack { flex: 1; display: flex; flex-direction: column; min-height: 0; padding: 12px 20px 16px; gap: 10px; }
32
+ .preview-url-row { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
33
+ .url-bar-wrap { flex: 1; min-width: 200px; }
34
+ .url-bar { font-size: 12px; font-family: monospace; color: #9cdcfe; background: #1e1e1e; border: 1px solid #3e3e3e; border-radius: 6px; padding: 8px 12px; word-break: break-all; }
35
+ .preview-visual-tools { display: flex; flex-shrink: 0; gap: 4px; align-items: center; }
36
+ .visual-tool-btn { background: #2d2d30; color: #ccc; border: 1px solid #3e3e3e; border-radius: 6px; padding: 6px 10px; font-size: 12px; cursor: pointer; line-height: 1; }
37
+ .visual-tool-btn:hover { background: #3e3e42; color: #fff; }
38
+ .visual-tool-on { background: #37373d !important; border-color: #9cdcfe !important; color: #9cdcfe !important; }
39
+ .preview-loading { font-size: 13px; color: #888; }
40
+ .preview-error { font-size: 13px; color: #f48771; background: #3a1f1f; border-radius: 6px; padding: 10px 12px; }
41
+ .path-select-row { display: flex; align-items: center; gap: 8px; width: 100%; }
42
+ .preview-path-select { flex: 1; min-width: 0; max-width: 560px; }
43
+ .params-loading-hint { font-size: 11px; color: #888; white-space: nowrap; flex-shrink: 0; }
44
+ /* isolation: Chrome Element Capture requires a stacking context on the capture target */
45
+ .preview-frame-wrap { flex: 1; min-height: 0; border: 1px solid #3e3e3e; border-radius: 8px; overflow: visible; background: #1e1e1e; position: relative; isolation: isolate; }
46
+ .preview-frame { width: 100%; height: 100%; min-height: 360px; border: none; display: block; }
47
+ .visual-overlay { position: absolute; inset: 0; z-index: 2; }
48
+ .visual-overlay-none { pointer-events: none; }
49
+ .point-marker { position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%; background: #c586ff; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.5); }
50
+ .point-marker-idx { position: absolute; left: 10px; top: -18px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 4px; background: #c586ff; color: #1e1e1e; font-size: 10px; font-weight: 700; line-height: 16px; text-align: center; pointer-events: none; }
51
+ .area-rect { position: absolute; border: 2px dashed #c586ff; background: rgba(197, 134, 255, 0.12); pointer-events: none; }
52
+ .area-marker-idx { position: absolute; left: 4px; top: 4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 4px; background: #c586ff; color: #1e1e1e; font-size: 10px; font-weight: 700; line-height: 18px; text-align: center; pointer-events: none; z-index: 1; }
53
+ .area-rect-draft { border-style: solid; border-color: #9cdcfe; background: rgba(156, 220, 254, 0.08); }
54
+ .arrow-pending-dot { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; border-radius: 50%; background: #9cdcfe; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.5); pointer-events: none; }
55
+ .arrow-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
56
+ .arrow-svg line { stroke: #c586ff; stroke-width: 2; marker-end: url(#aiditor-arrowhead); }
57
+ .arrow-end-pin { position: absolute; width: 22px; height: 22px; margin: -11px 0 0 -11px; border-radius: 50%; background: #c586ff; color: #1e1e1e; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.5); font-size: 11px; font-weight: 700; display: flex; align-items: center; justify-content: center; pointer-events: none; z-index: 3; }
58
+ .visual-popovers { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
59
+ .visual-popover { position: absolute; width: 280px; max-width: min(280px, calc(100% - 16px)); display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; background: #252526; border: 1px solid #9cdcfe; border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.45); box-sizing: border-box; transform: translate(10px, 10px); pointer-events: auto; }
60
+ /* Keep card on-screen when anchor is near right/bottom (default opens down-right). */
61
+ .visual-popover-flip-x { transform: translate(calc(-100% - 14px), 10px); }
62
+ .visual-popover-flip-y { transform: translate(10px, calc(-100% - 14px)); }
63
+ .visual-popover-flip-x.visual-popover-flip-y { transform: translate(calc(-100% - 14px), calc(-100% - 14px)); }
64
+ .visual-annotation-row-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
65
+ .visual-annotation-kind { font-size: 11px; color: #9cdcfe; font-weight: 600; }
66
+ .visual-annotation-actions { display: flex; gap: 6px; flex-shrink: 0; }
67
+ .visual-annotation-remove { background: transparent; color: #888; border: 1px solid #3e3e3e; border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; }
68
+ .visual-annotation-remove:hover { color: #f48771; border-color: #f48771; }
69
+ .visual-annotation-run { background: #0e639c; color: #fff; border: none; border-radius: 4px; padding: 4px 10px; font-size: 11px; cursor: pointer; }
70
+ .visual-annotation-run:hover { background: #1177bb; }
71
+ .visual-annotation-run:disabled { opacity: 0.45; cursor: not-allowed; }
72
+ .visual-annotation-instruction { width: 100%; min-height: 48px; resize: vertical; background: #252526; color: #d4d4d4; border: 1px solid #3e3e3e; border-radius: 6px; padding: 6px 8px; font-size: 12px; font-family: inherit; outline: none; }
73
+ .visual-annotation-instruction:focus { border-color: #0e639c; }
74
+ .visual-annotation-files { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
75
+ .visual-attach-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
76
+ .visual-attach-btn { background: #2d2d30; color: #ccc; border: 1px solid #3e3e3e; border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; }
77
+ .visual-attach-btn:hover { border-color: #9cdcfe; color: #fff; }
78
+ .visual-attachment-chips { display: flex; flex-wrap: wrap; gap: 6px; }
79
+ .visual-attachment-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; background: #1e1e1e; border: 1px solid #3e3e3e; border-radius: 6px; padding: 4px 6px; font-size: 11px; color: #ccc; }
80
+ .visual-attachment-thumb { width: 36px; height: 36px; object-fit: cover; border-radius: 4px; flex-shrink: 0; background: #2d2d30; }
81
+ .visual-attachment-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
82
+ .visual-attachment-remove-file { background: transparent; border: none; color: #888; cursor: pointer; font-size: 14px; line-height: 1; padding: 0 4px; }
83
+ .visual-attachment-remove-file:hover { color: #f48771; }
84
+ .file-input-hidden { display: none; }
85
+ .visual-error { font-size: 12px; color: #f48771; }
86
+ .visual-submit-error { font-size: 12px; color: #f48771; margin: 0; padding: 0 2px; }
87
+ .visual-submit-progress { font-size: 12px; color: #9cdcfe; margin: 0; padding: 0 2px; }
88
+ .bottom-panel { flex-shrink: 0; display: flex; flex-direction: column; background: #1e1e1e; border-top: 1px solid #3e3e3e; min-height: 32px; max-height: 80vh; }
89
+ .bottom-panel-collapsed { max-height: 32px; overflow: hidden; }
90
+ .bottom-panel-resize { height: 4px; cursor: ns-resize; background: transparent; flex-shrink: 0; }
91
+ .bottom-panel-resize:hover, .bottom-panel-resize:active { background: #007acc; }
92
+ .bottom-panel-header { display: flex; align-items: center; gap: 8px; padding: 6px 12px; flex-shrink: 0; cursor: pointer; user-select: none; }
93
+ .bottom-panel-title { font-size: 11px; font-weight: 600; color: #ccc; text-transform: uppercase; letter-spacing: 0.5px; }
94
+ .bottom-panel-running { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #89d185; animation: pulse-dot 1.2s ease-in-out infinite; margin-left: 4px; }
95
+ @keyframes pulse-dot { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
96
+ .bottom-panel-toggle { background: none; border: none; color: #888; font-size: 14px; cursor: pointer; padding: 0 4px; line-height: 1; }
97
+ .bottom-panel-toggle:hover { color: #fff; }
98
+ .bottom-panel-spacer { flex: 1; }
99
+ .bottom-panel-clear { background: none; border: none; color: #666; font-size: 11px; cursor: pointer; padding: 2px 6px; }
100
+ .bottom-panel-clear:hover { color: #ccc; }
101
+ .output-panel { overflow-y: auto; padding: 8px 12px; font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 12px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; max-height: calc(5 * 1.5em + 16px); }
102
+ .chunk { color: #d4d4d4; }
103
+ .chunk-status { color: #888; font-style: italic; }
104
+ .chunk-tool { color: #569cd6; }
105
+ .chunk-error { color: #f48771; }
106
+ .chunk-thinking { color: #666; font-style: italic; }
107
+ .chunk-result { color: #89d185; }
108
+ .tool-group-sep { width: 1px; background: #3e3e3e; align-self: stretch; margin: 0 4px; flex-shrink: 0; }
109
+ .file-link { color: #569cd6; text-decoration: underline; cursor: pointer; }
110
+ .file-link:hover { color: #9cdcfe; }
111
+ .chunk-tool-prefix { color: #569cd6; }
112
+ .file-preview-overlay { position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,0.78); display: flex; align-items: center; justify-content: center; padding: 20px; box-sizing: border-box; }
113
+ .file-preview-panel { background: #1e1e1e; border: 1px solid #3e3e3e; border-radius: 10px; width: min(900px, 96vw); max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; }
114
+ .file-preview-header { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-bottom: 1px solid #3e3e3e; flex-shrink: 0; }
115
+ .file-preview-title { font-size: 12px; color: #ccc; font-family: 'Cascadia Code', 'Fira Code', monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
116
+ .file-preview-close { background: none; border: none; color: #888; font-size: 18px; cursor: pointer; padding: 0 4px; line-height: 1; flex-shrink: 0; }
117
+ .file-preview-close:hover { color: #fff; }
118
+ .file-preview-body { flex: 1; overflow: auto; padding: 16px; min-height: 0; }
119
+ .file-preview-text { font-family: 'Cascadia Code', 'Fira Code', monospace; font-size: 12px; line-height: 1.5; color: #d4d4d4; white-space: pre-wrap; word-break: break-word; margin: 0; }
120
+ .file-preview-image { max-width: 100%; max-height: 70vh; display: block; margin: 0 auto; }
121
+ .file-preview-loading { color: #888; font-style: italic; font-size: 12px; }
122
+ .aiditor-logo { font-size: 18px; font-weight: 700; letter-spacing: -0.5px; color: #d4d4d4; flex-shrink: 0; font-family: 'Segoe UI', system-ui, sans-serif; }
123
+ .aiditor-logo-ai { color: #f44747; }
124
+ .preview-frame-tablet { align-self: center; width: 768px; max-width: 100%; }
125
+ .preview-frame-mobile { align-self: center; width: 390px; max-width: 100%; }
126
+ .video-record-btn { border-color: #c586ff !important; color: #e0d0ff !important; }
127
+ .video-record-active { animation: pulse-rec 1.2s ease-in-out infinite; }
128
+ @keyframes pulse-rec { 0%,100% { opacity: 1; } 50% { opacity: 0.55; } }
129
+ .video-review-overlay { position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,0.78); display: flex; align-items: center; justify-content: center; padding: 20px; box-sizing: border-box; }
130
+ .video-review-panel { background: #252526; border: 1px solid #3e3e3e; border-radius: 10px; width: min(1100px, 96vw); max-height: 94vh; display: flex; flex-direction: column; gap: 10px; padding: 14px 16px; overflow: auto; }
131
+ .video-review-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
132
+ .video-review-title { font-size: 15px; font-weight: 600; color: #9cdcfe; margin: 0; }
133
+ .video-review-meta { font-size: 12px; color: #888; }
134
+ .video-review-tools { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
135
+ .video-review-transport { display: flex; align-items: center; gap: 10px; width: 100%; }
136
+ .video-play-pause-btn { flex-shrink: 0; width: 40px; height: 36px; border-radius: 6px; border: 1px solid #555; background: #3c3c3c; color: #eee; font-size: 16px; line-height: 1; cursor: pointer; }
137
+ .video-play-pause-btn:hover { background: #4a4a4a; border-color: #9cdcfe; }
138
+ .video-timeline-wrap { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
139
+ .video-timeline { width: 100%; accent-color: #0e639c; }
140
+ .video-timeline-markers { position: relative; height: 10px; margin: 0 2px; }
141
+ .video-timeline-marker { position: absolute; top: 0; width: 10px; margin-left: -5px; height: 10px; background: #c586ff; border-radius: 1px; transform: translateX(-50%); cursor: pointer; }
142
+ .video-review-overlay .arrow-svg line { marker-end: url(#aiditor-video-arrowhead); }
143
+ .video-review-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; margin-top: 4px; }
144
+ .video-review-secondary { background: #3c3c3c; color: #ddd; border: 1px solid #555; border-radius: 6px; padding: 8px 16px; font-size: 13px; cursor: pointer; }
145
+ .video-review-secondary:hover { background: #4a4a4a; }
146
+ .video-review-primary { background: #0e639c; color: #fff; border: none; border-radius: 6px; padding: 8px 18px; font-size: 13px; cursor: pointer; }
147
+ .video-review-primary:hover { background: #1177bb; }
148
+ .video-review-primary:disabled { opacity: 0.45; cursor: not-allowed; }
149
+ </style>
150
+ <script type="application/jay-data">
151
+ data:
152
+ isBootstrapping: boolean
153
+ showBootstrapError: boolean
154
+ bootstrapErrorText: string
155
+ canRetryBootstrap: boolean
156
+ isMainVisible: boolean
157
+ projectName: string
158
+ notes: string
159
+ hasImage: boolean
160
+ isRunning: boolean
161
+ chunks:
162
+ - text: string
163
+ cssClass: string
164
+ filePath: string
165
+ toolName: string
166
+ hasChunks: boolean
167
+ outputEmpty: boolean
168
+ pageSelectOptions:
169
+ - url: string
170
+ label: string
171
+ selectedRouteSelectValue: string
172
+ hasPages: boolean
173
+ isPreviewMode: boolean
174
+ previewUrlBar: string
175
+ previewLoading: boolean
176
+ paramsLoadingHint: string
177
+ previewError: string
178
+ showPathSelect: boolean
179
+ previewPathOptions:
180
+ - path: string
181
+ selectedPreviewPath: string
182
+ showPreviewIframe: boolean
183
+ previewSrc: string
184
+ showOutputChunks: boolean
185
+ showOutputEmpty: boolean
186
+ outputEmptyHint: string
187
+ bottomPanelClass: string
188
+ bottomPanelToggleGlyph: string
189
+ showBottomPanelRunning: boolean
190
+ showFilePreview: boolean
191
+ filePreviewPath: string
192
+ filePreviewContent: string
193
+ filePreviewIsImage: boolean
194
+ filePreviewImageSrc: string
195
+ filePreviewLoading: boolean
196
+ showVisualToolbar: boolean
197
+ visualToolNoneOn: boolean
198
+ visualToolPointOn: boolean
199
+ visualToolAreaOn: boolean
200
+ visualToolArrowOn: boolean
201
+ visualPointDisplayItems:
202
+ - id: string
203
+ leftPct: number
204
+ topPct: number
205
+ indexLabel: string
206
+ showVisualPointMarkers: boolean
207
+ visualAreaDisplayItems:
208
+ - id: string
209
+ leftPct: number
210
+ topPct: number
211
+ widthPct: number
212
+ heightPct: number
213
+ indexLabel: string
214
+ showVisualAreaItems: boolean
215
+ areaDraftLeftPct: number
216
+ areaDraftTopPct: number
217
+ areaDraftWidthPct: number
218
+ areaDraftHeightPct: number
219
+ showAreaDraftRect: boolean
220
+ visualArrowDisplayItems:
221
+ - id: string
222
+ x1Pct: number
223
+ y1Pct: number
224
+ x2Pct: number
225
+ y2Pct: number
226
+ visualArrowPinItems:
227
+ - id: string
228
+ leftPct: number
229
+ topPct: number
230
+ indexLabel: string
231
+ hasVisualArrowLines: boolean
232
+ showArrowPending: boolean
233
+ arrowPendingLeftPct: number
234
+ arrowPendingTopPct: number
235
+ visualAnnotationRows:
236
+ - id: string
237
+ kindLabel: string
238
+ instruction: string
239
+ runDisabled: boolean
240
+ leftPct: number
241
+ topPct: number
242
+ popoverFlipX: boolean
243
+ popoverFlipY: boolean
244
+ attachmentChips:
245
+ - key: string
246
+ name: string
247
+ thumbUrl: string
248
+ annotationId: string
249
+ recordingDraftUi:
250
+ id: string
251
+ kindLabel: string
252
+ instruction: string
253
+ leftPct: number
254
+ topPct: number
255
+ popoverFlipX: boolean
256
+ popoverFlipY: boolean
257
+ attachmentChips:
258
+ - key: string
259
+ name: string
260
+ thumbUrl: string
261
+ annotationId: string
262
+ recordingDraftAttachmentChips:
263
+ - key: string
264
+ name: string
265
+ thumbUrl: string
266
+ annotationId: string
267
+ showRecordingDraftPopover: boolean
268
+ showVisualAnnotationsPanel: boolean
269
+ showVisualSubmitError: boolean
270
+ visualSubmitError: string
271
+ visualOverlayPointerNone: boolean
272
+ showVideoRecordUi: boolean
273
+ isVideoRecording: boolean
274
+ videoRecordLabel: string
275
+ videoRecordDisabled: boolean
276
+ freezeDisabled: boolean
277
+ showVideoReviewModal: boolean
278
+ videoReviewPreparing: boolean
279
+ videoReviewReady: boolean
280
+ videoReviewError: boolean
281
+ videoReviewErrorText: string
282
+ videoReviewObjectUrl: string
283
+ videoModalToolNoneOn: boolean
284
+ videoModalToolPointOn: boolean
285
+ videoModalToolAreaOn: boolean
286
+ videoModalToolArrowOn: boolean
287
+ videoPointDisplayItems:
288
+ - id: string
289
+ leftPct: number
290
+ topPct: number
291
+ indexLabel: string
292
+ showVideoPointMarkers: boolean
293
+ videoAreaDisplayItems:
294
+ - id: string
295
+ leftPct: number
296
+ topPct: number
297
+ widthPct: number
298
+ heightPct: number
299
+ indexLabel: string
300
+ showVideoAreaItems: boolean
301
+ videoAreaDraftLeftPct: number
302
+ videoAreaDraftTopPct: number
303
+ videoAreaDraftWidthPct: number
304
+ videoAreaDraftHeightPct: number
305
+ showVideoAreaDraftRect: boolean
306
+ videoArrowDisplayItems:
307
+ - id: string
308
+ x1Pct: number
309
+ y1Pct: number
310
+ x2Pct: number
311
+ y2Pct: number
312
+ videoArrowPinItems:
313
+ - id: string
314
+ leftPct: number
315
+ topPct: number
316
+ indexLabel: string
317
+ hasVideoArrowLines: boolean
318
+ showVideoArrowPending: boolean
319
+ videoArrowPendingLeftPct: number
320
+ videoArrowPendingTopPct: number
321
+ videoAnnotationRows:
322
+ - id: string
323
+ kindLabel: string
324
+ instruction: string
325
+ runDisabled: boolean
326
+ leftPct: number
327
+ topPct: number
328
+ popoverFlipX: boolean
329
+ popoverFlipY: boolean
330
+ attachmentChips:
331
+ - key: string
332
+ name: string
333
+ thumbUrl: string
334
+ annotationId: string
335
+ showVideoAnnotationsPanel: boolean
336
+ videoModalOverlayPointerNone: boolean
337
+ videoSubmitError: string
338
+ showVideoSubmitError: boolean
339
+ videoSubmitProgress: string
340
+ showVideoSubmitProgress: boolean
341
+ videoTimelineMarkers:
342
+ - key: string
343
+ timeSec: number
344
+ leftPct: number
345
+ label: string
346
+ showVideoAnnotationPopoversAtPlayhead: boolean
347
+ videoTimeLabel: string
348
+ videoSendDisabled: boolean
349
+ videoPlayPauseGlyph: string
350
+ breakpointDesktopOn: boolean
351
+ breakpointTabletOn: boolean
352
+ breakpointMobileOn: boolean
353
+ </script>
354
+ </head>
355
+ <body>
356
+ <div class="app-root">
357
+
358
+ <div class="setup-screen" if="!isMainVisible">
359
+ <h2 class="setup-title">AIditor</h2>
360
+ <p class="setup-desc" if="isBootstrapping">Starting…</p>
361
+ <p class="setup-desc bootstrap-msg" if="showBootstrapError">{bootstrapErrorText}</p>
362
+ <button type="button" class="setup-btn" ref="retryBootstrapBtn" disabled="!canRetryBootstrap">Retry</button>
363
+ </div>
364
+
365
+ <!-- Main screen -->
366
+ <div class="root" if="isMainVisible">
367
+ <main class="main-panel">
368
+ <div class="main-top-bar" if="hasPages">
369
+ <div class="route-picker-stack">
370
+ <select
371
+ class="aiditor-dropdown"
372
+ ref="pageRouteSelect"
373
+ value="{selectedRouteSelectValue}"
374
+ aria-label="Page route"
375
+ >
376
+ <option value="" disabled>Select a route…</option>
377
+ <option forEach="pageSelectOptions" trackBy="url" value="{url}">{label}</option>
378
+ </select>
379
+ <div class="path-select-row">
380
+ <select
381
+ class="aiditor-dropdown preview-path-select"
382
+ if="showPathSelect"
383
+ ref="previewPathSelect"
384
+ value="{selectedPreviewPath}"
385
+ aria-label="URL instance"
386
+ >
387
+ <option forEach="previewPathOptions" trackBy="path" value="{path}">{path}</option>
388
+ </select>
389
+ <span class="params-loading-hint" if="paramsLoadingHint">{paramsLoadingHint}</span>
390
+ </div>
391
+ </div>
392
+ </div>
393
+
394
+ <div class="preview-stack" if="isPreviewMode">
395
+ <div class="preview-url-row">
396
+ <span class="aiditor-logo"><span class="aiditor-logo-ai">AI</span>ditor</span>
397
+ <div class="url-bar-wrap">
398
+ <div class="url-bar">{previewUrlBar}</div>
399
+ </div>
400
+ <div class="preview-visual-tools" if="showVisualToolbar">
401
+ <button type="button" class="{breakpointDesktopOn ? visual-tool-on} visual-tool-btn" ref="breakpointDesktopBtn" title="Desktop (1280px)"><svg width="16" height="13" viewBox="0 0 16 13" fill="none"><rect x="0.7" y="0.7" width="14.6" height="9.1" rx="1.1" stroke="currentColor" stroke-width="1.4"/><path d="M5.5 9.8v2M10.5 9.8v2M3.5 11.8h9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg></button>
402
+ <button type="button" class="{breakpointTabletOn ? visual-tool-on} visual-tool-btn" ref="breakpointTabletBtn" title="Tablet (768px)"><svg width="10" height="14" viewBox="0 0 10 14" fill="none"><rect x="0.7" y="0.7" width="8.6" height="12.6" rx="1.1" stroke="currentColor" stroke-width="1.4"/><circle cx="5" cy="11.5" r="0.8" fill="currentColor"/></svg></button>
403
+ <button type="button" class="{breakpointMobileOn ? visual-tool-on} visual-tool-btn" ref="breakpointMobileBtn" title="Mobile (390px)"><svg width="8" height="14" viewBox="0 0 8 14" fill="none"><rect x="0.7" y="0.7" width="6.6" height="12.6" rx="1.1" stroke="currentColor" stroke-width="1.4"/><line x1="2.5" y1="11.5" x2="5.5" y2="11.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg></button>
404
+ <span class="tool-group-sep"></span>
405
+ <button type="button" class="{visualToolNoneOn ? visual-tool-on} visual-tool-btn" ref="visualToolNoneBtn" title="Select">⤢</button>
406
+ <button type="button" class="{visualToolPointOn ? visual-tool-on} visual-tool-btn" ref="visualToolPointBtn" title="Point">⊙</button>
407
+ <button type="button" class="{visualToolAreaOn ? visual-tool-on} visual-tool-btn" ref="visualToolAreaBtn" title="Area">▢</button>
408
+ <button type="button" class="{visualToolArrowOn ? visual-tool-on} visual-tool-btn" ref="visualToolArrowBtn" title="Arrow">↗</button>
409
+ <button
410
+ type="button"
411
+ class="{isVideoRecording ? video-record-active} video-record-btn visual-tool-btn"
412
+ ref="videoRecordBtn"
413
+ disabled="videoRecordDisabled"
414
+ title="Record preview"
415
+ >{videoRecordLabel}</button>
416
+ <button
417
+ type="button"
418
+ class="visual-tool-btn freeze-btn"
419
+ ref="freezeBtn"
420
+ disabled="freezeDisabled"
421
+ title="Freeze page state"
422
+ >❄</button>
423
+ </div>
424
+ </div>
425
+ <div class="preview-loading" if="previewLoading">{paramsLoadingHint}</div>
426
+ <div class="preview-error" if="previewError">{previewError}</div>
427
+ <input
428
+ type="file"
429
+ class="file-input-hidden"
430
+ ref="visualAttachFileInput"
431
+ multiple
432
+ />
433
+ <div class="{breakpointTabletOn ? preview-frame-tablet} {breakpointMobileOn ? preview-frame-mobile} preview-frame-wrap" if="showPreviewIframe" ref="previewCaptureRoot">
434
+ <iframe class="preview-frame" ref="previewIframe" src="{previewSrc}" title="Page preview"></iframe>
435
+ <div class="{visualOverlayPointerNone ? visual-overlay-none} visual-overlay" ref="visualOverlay">
436
+ <div
437
+ class="point-marker"
438
+ forEach="visualPointDisplayItems"
439
+ trackBy="id"
440
+ style="left: {leftPct}%; top: {topPct}%;"
441
+ >
442
+ <span class="point-marker-idx">{indexLabel}</span>
443
+ </div>
444
+ <div
445
+ class="area-rect"
446
+ forEach="visualAreaDisplayItems"
447
+ trackBy="id"
448
+ style="left: {leftPct}%; top: {topPct}%; width: {widthPct}%; height: {heightPct}%;"
449
+ ><span class="area-marker-idx">{indexLabel}</span></div>
450
+ <div
451
+ class="area-rect area-rect-draft"
452
+ if="showAreaDraftRect"
453
+ style="left: {areaDraftLeftPct}%; top: {areaDraftTopPct}%; width: {areaDraftWidthPct}%; height: {areaDraftHeightPct}%;"
454
+ ></div>
455
+ <div
456
+ class="arrow-pending-dot"
457
+ if="showArrowPending"
458
+ style="left: {arrowPendingLeftPct}%; top: {arrowPendingTopPct}%;"
459
+ ></div>
460
+ <svg class="arrow-svg" if="hasVisualArrowLines" viewBox="0 0 100 100" preserveAspectRatio="none">
461
+ <defs>
462
+ <marker id="aiditor-arrowhead" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
463
+ <polygon points="0 0, 8 4, 0 8" fill="#c586ff" />
464
+ </marker>
465
+ </defs>
466
+ <line
467
+ forEach="visualArrowDisplayItems"
468
+ trackBy="id"
469
+ x1="{x1Pct}"
470
+ y1="{y1Pct}"
471
+ x2="{x2Pct}"
472
+ y2="{y2Pct}"
473
+ />
474
+ </svg>
475
+ <div
476
+ class="arrow-end-pin"
477
+ forEach="visualArrowPinItems"
478
+ trackBy="id"
479
+ style="left: {leftPct}%; top: {topPct}%;"
480
+ >{indexLabel}</div>
481
+ </div>
482
+ <div class="visual-popovers" if="showVisualAnnotationsPanel">
483
+ <div
484
+ if="showRecordingDraftPopover"
485
+ class="{recordingDraftUi.popoverFlipX ? visual-popover-flip-x} {recordingDraftUi.popoverFlipY ? visual-popover-flip-y} visual-popover"
486
+ ref="recordingDraftPopover"
487
+ data-annotation-id="{recordingDraftUi.id}"
488
+ style="left: {recordingDraftUi.leftPct}%; top: {recordingDraftUi.topPct}%;"
489
+ >
490
+ <div class="visual-annotation-row-head">
491
+ <span class="visual-annotation-kind">{recordingDraftUi.kindLabel}</span>
492
+ <div class="visual-annotation-actions">
493
+ <button type="button" class="recording-draft-cancel visual-annotation-remove" title="Cancel annotation">Cancel</button>
494
+ <button
495
+ type="button"
496
+ class="recording-draft-add visual-annotation-run"
497
+ title="Pin this moment on the recording timeline"
498
+ >Add to recording</button>
499
+ </div>
500
+ </div>
501
+ <textarea
502
+ class="visual-annotation-instruction"
503
+ placeholder="Instruction for this annotation…"
504
+ data-annotation-id="{recordingDraftUi.id}"
505
+ value="{recordingDraftUi.instruction}"
506
+ ></textarea>
507
+ <div class="visual-annotation-files">
508
+ <div class="visual-attach-row">
509
+ <button type="button" class="visual-attach-btn visual-annotation-attach" data-annotation-id="{recordingDraftUi.id}">
510
+ Attach file
511
+ </button>
512
+ </div>
513
+ <div class="visual-attachment-chips" forEach="recordingDraftAttachmentChips" trackBy="key">
514
+ <div class="visual-attachment-chip">
515
+ <img if="thumbUrl" class="visual-attachment-thumb" src="{thumbUrl}" alt="" />
516
+ <span class="visual-attachment-name">{name}</span>
517
+ <button
518
+ type="button"
519
+ class="visual-attachment-remove-file"
520
+ data-annotation-id="{annotationId}"
521
+ data-att-key="{key}"
522
+ aria-label="Remove attachment"
523
+ >×</button>
524
+ </div>
525
+ </div>
526
+ </div>
527
+ </div>
528
+ <div
529
+ class="{popoverFlipX ? visual-popover-flip-x} {popoverFlipY ? visual-popover-flip-y} visual-popover"
530
+ forEach="visualAnnotationRows"
531
+ trackBy="id"
532
+ ref="annotationRow"
533
+ data-annotation-id="{id}"
534
+ style="left: {leftPct}%; top: {topPct}%;"
535
+ >
536
+ <div class="visual-annotation-row-head">
537
+ <span class="visual-annotation-kind">{kindLabel}</span>
538
+ <div class="visual-annotation-actions">
539
+ <button type="button" class="visual-annotation-remove" title="Remove annotation">Remove</button>
540
+ <button
541
+ type="button"
542
+ class="visual-annotation-run"
543
+ disabled="runDisabled"
544
+ title="Capture preview and send all annotations"
545
+ >Run</button>
546
+ </div>
547
+ </div>
548
+ <textarea
549
+ class="visual-annotation-instruction"
550
+ placeholder="Instruction for this annotation…"
551
+ data-annotation-id="{id}"
552
+ value="{instruction}"
553
+ ></textarea>
554
+ <div class="visual-annotation-files">
555
+ <div class="visual-attach-row">
556
+ <button type="button" class="visual-attach-btn visual-annotation-attach" data-annotation-id="{id}">
557
+ Attach file
558
+ </button>
559
+ </div>
560
+ <div class="visual-attachment-chips" forEach="attachmentChips" trackBy="key">
561
+ <div class="visual-attachment-chip">
562
+ <img if="thumbUrl" class="visual-attachment-thumb" src="{thumbUrl}" alt="" />
563
+ <span class="visual-attachment-name">{name}</span>
564
+ <button
565
+ type="button"
566
+ class="visual-attachment-remove-file"
567
+ data-annotation-id="{annotationId}"
568
+ data-att-key="{key}"
569
+ aria-label="Remove attachment"
570
+ >×</button>
571
+ </div>
572
+ </div>
573
+ </div>
574
+ </div>
575
+ </div>
576
+ </div>
577
+ <p class="visual-submit-error" if="showVisualSubmitError">{visualSubmitError}</p>
578
+ </div>
579
+
580
+ </main>
581
+ <div class="{bottomPanelClass}">
582
+ <div class="bottom-panel-resize" ref="bottomPanelResize"></div>
583
+ <div class="bottom-panel-header" ref="bottomPanelHeader">
584
+ <span class="bottom-panel-title">Claude Code Output</span>
585
+ <span class="bottom-panel-running" if="showBottomPanelRunning"></span>
586
+ <span class="bottom-panel-spacer"></span>
587
+ <button type="button" class="bottom-panel-clear" ref="bottomPanelClearBtn">Clear</button>
588
+ <button type="button" class="bottom-panel-toggle" ref="bottomPanelToggleBtn">{bottomPanelToggleGlyph}</button>
589
+ </div>
590
+ <div class="output-panel" ref="outputScroll">
591
+ <div class="{cssClass}" forEach="chunks" trackBy="text"><span if="filePath" class="chunk-tool-prefix">&gt; {toolName} </span><a if="filePath" class="file-link" href="#" data-path="{filePath}">{filePath}</a><span if="!filePath">{text}</span></div>
592
+ </div>
593
+ </div>
594
+ </div>
595
+
596
+ <div class="file-preview-overlay" if="showFilePreview" ref="filePreviewBackdrop">
597
+ <div class="file-preview-panel">
598
+ <div class="file-preview-header">
599
+ <span class="file-preview-title">{filePreviewPath}</span>
600
+ <button type="button" class="file-preview-close" ref="filePreviewCloseBtn">✕</button>
601
+ </div>
602
+ <div class="file-preview-body">
603
+ <span class="file-preview-loading" if="filePreviewLoading">Loading…</span>
604
+ <pre class="file-preview-text" if="!filePreviewIsImage">{filePreviewContent}</pre>
605
+ <img class="file-preview-image" if="filePreviewIsImage" src="{filePreviewImageSrc}" alt="" />
606
+ </div>
607
+ </div>
608
+ </div>
609
+
610
+ <div class="video-review-overlay" if="showVideoReviewModal" ref="videoReviewBackdrop" tabindex="-1">
611
+ <div class="video-review-panel">
612
+ <div class="video-review-header">
613
+ <div>
614
+ <h2 class="video-review-title">Review recording</h2>
615
+ <p class="video-review-meta" if="videoReviewReady">{videoTimeLabel}</p>
616
+ </div>
617
+ <button type="button" class="video-review-secondary" ref="videoReviewCloseBtn">Close</button>
618
+ </div>
619
+ <p if="videoReviewPreparing">Preparing recording…</p>
620
+ <p class="preview-error" if="videoReviewError">{videoReviewErrorText}</p>
621
+ <!-- Must mount while preparing: refs.videoReviewPlayer must exist before videoReviewReady flips true. -->
622
+ <div if="videoReviewPreparing || videoReviewReady">
623
+ <div class="video-review-tools">
624
+ <button type="button" class="{videoModalToolNoneOn ? visual-tool-on} visual-tool-btn" ref="videoModalToolNoneBtn" title="Select">⤢</button>
625
+ <button type="button" class="{videoModalToolPointOn ? visual-tool-on} visual-tool-btn" ref="videoModalToolPointBtn" title="Point">⊙</button>
626
+ <button type="button" class="{videoModalToolAreaOn ? visual-tool-on} visual-tool-btn" ref="videoModalToolAreaBtn" title="Area">▢</button>
627
+ <button type="button" class="{videoModalToolArrowOn ? visual-tool-on} visual-tool-btn" ref="videoModalToolArrowBtn" title="Arrow">↗</button>
628
+ </div>
629
+ <input type="file" class="file-input-hidden" ref="videoReviewAttachFileInput" multiple />
630
+ <div class="preview-frame-wrap video-review-capture-root" ref="videoReviewCaptureRoot">
631
+ <video
632
+ class="preview-frame"
633
+ ref="videoReviewPlayer"
634
+ data-aiditor-video-review=""
635
+ src="{videoReviewObjectUrl}"
636
+ playsinline
637
+ preload="metadata"
638
+ ></video>
639
+ <div class="{videoModalOverlayPointerNone ? visual-overlay-none} visual-overlay" ref="videoReviewOverlay">
640
+ <div
641
+ class="point-marker"
642
+ forEach="videoPointDisplayItems"
643
+ trackBy="id"
644
+ style="left: {leftPct}%; top: {topPct}%;"
645
+ >
646
+ <span class="point-marker-idx">{indexLabel}</span>
647
+ </div>
648
+ <div
649
+ class="area-rect"
650
+ forEach="videoAreaDisplayItems"
651
+ trackBy="id"
652
+ style="left: {leftPct}%; top: {topPct}%; width: {widthPct}%; height: {heightPct}%;"
653
+ ><span class="area-marker-idx">{indexLabel}</span></div>
654
+ <div
655
+ class="area-rect area-rect-draft"
656
+ if="showVideoAreaDraftRect"
657
+ style="left: {videoAreaDraftLeftPct}%; top: {videoAreaDraftTopPct}%; width: {videoAreaDraftWidthPct}%; height: {videoAreaDraftHeightPct}%;"
658
+ ></div>
659
+ <div
660
+ class="arrow-pending-dot"
661
+ if="showVideoArrowPending"
662
+ style="left: {videoArrowPendingLeftPct}%; top: {videoArrowPendingTopPct}%;"
663
+ ></div>
664
+ <svg class="arrow-svg" if="hasVideoArrowLines" viewBox="0 0 100 100" preserveAspectRatio="none">
665
+ <defs>
666
+ <marker id="aiditor-video-arrowhead" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
667
+ <polygon points="0 0, 8 4, 0 8" fill="#c586ff" />
668
+ </marker>
669
+ </defs>
670
+ <line
671
+ forEach="videoArrowDisplayItems"
672
+ trackBy="id"
673
+ x1="{x1Pct}"
674
+ y1="{y1Pct}"
675
+ x2="{x2Pct}"
676
+ y2="{y2Pct}"
677
+ />
678
+ </svg>
679
+ <div
680
+ class="arrow-end-pin"
681
+ forEach="videoArrowPinItems"
682
+ trackBy="id"
683
+ style="left: {leftPct}%; top: {topPct}%;"
684
+ >{indexLabel}</div>
685
+ </div>
686
+ <div class="visual-popovers" if="showVideoAnnotationPopoversAtPlayhead">
687
+ <div
688
+ class="{popoverFlipX ? visual-popover-flip-x} {popoverFlipY ? visual-popover-flip-y} visual-popover"
689
+ forEach="videoAnnotationRows"
690
+ trackBy="id"
691
+ ref="videoAnnotationRow"
692
+ data-annotation-id="{id}"
693
+ style="left: {leftPct}%; top: {topPct}%;"
694
+ >
695
+ <div class="visual-annotation-row-head">
696
+ <span class="visual-annotation-kind">{kindLabel}</span>
697
+ <div class="visual-annotation-actions">
698
+ <button type="button" class="visual-annotation-remove" title="Remove annotation">Remove</button>
699
+ </div>
700
+ </div>
701
+ <textarea
702
+ class="visual-annotation-instruction"
703
+ placeholder="Instruction for this annotation…"
704
+ data-annotation-id="{id}"
705
+ value="{instruction}"
706
+ ></textarea>
707
+ <div class="visual-annotation-files">
708
+ <div class="visual-attach-row">
709
+ <button type="button" class="visual-attach-btn visual-video-annotation-attach" data-annotation-id="{id}">
710
+ Attach file
711
+ </button>
712
+ </div>
713
+ <div class="visual-attachment-chips" forEach="attachmentChips" trackBy="key">
714
+ <div class="visual-attachment-chip">
715
+ <img if="thumbUrl" class="visual-attachment-thumb" src="{thumbUrl}" alt="" />
716
+ <span class="visual-attachment-name">{name}</span>
717
+ <button
718
+ type="button"
719
+ class="visual-attachment-remove-file"
720
+ data-annotation-id="{annotationId}"
721
+ data-att-key="{key}"
722
+ aria-label="Remove attachment"
723
+ >×</button>
724
+ </div>
725
+ </div>
726
+ </div>
727
+ </div>
728
+ </div>
729
+ </div>
730
+ <div class="video-review-transport">
731
+ <button type="button" class="video-play-pause-btn" ref="videoPlayPauseBtn" title="Play or pause" aria-label="Play or pause">{videoPlayPauseGlyph}</button>
732
+ <div class="video-timeline-wrap" ref="videoReviewTimelineWrap">
733
+ <input type="range" class="video-timeline" ref="videoTimeline" min="0" max="1000" value="0" step="1" />
734
+ <div class="video-timeline-markers" if="showVideoAnnotationsPanel">
735
+ <span
736
+ class="video-timeline-marker"
737
+ forEach="videoTimelineMarkers"
738
+ trackBy="key"
739
+ data-aiditor-timeline-marker=""
740
+ data-time-sec="{timeSec}"
741
+ style="left: {leftPct}%;"
742
+ title="{label}"
743
+ ></span>
744
+ </div>
745
+ </div>
746
+ </div>
747
+ <p class="visual-submit-error" if="showVideoSubmitError">{videoSubmitError}</p>
748
+ <p class="visual-submit-progress" if="showVideoSubmitProgress">{videoSubmitProgress}</p>
749
+ <div class="video-review-actions">
750
+ <button type="button" class="video-review-secondary" ref="videoReviewDiscardBtn">Discard recording</button>
751
+ <button type="button" class="video-review-primary" ref="videoReviewSendBtn" disabled="videoSendDisabled">Send</button>
752
+ </div>
753
+ </div>
754
+ </div>
755
+ </div>
756
+
757
+ </div>
758
+ </body>
759
+ </html>