annotask 0.0.3 → 0.0.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.
@@ -0,0 +1 @@
1
+ .control-row[data-v-548da941]{margin-bottom:10px}.control-label[data-v-548da941]{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.04em}.button-group[data-v-548da941]{display:flex;gap:2px}.seg-btn[data-v-548da941]{flex:1;padding:4px 6px;font-size:10px;background:var(--bg);border:1px solid var(--border);color:var(--text-muted);cursor:pointer;transition:all .1s;white-space:nowrap}.seg-btn[data-v-548da941]:first-child{border-radius:5px 0 0 5px}.seg-btn[data-v-548da941]:last-child{border-radius:0 5px 5px 0}.seg-btn[data-v-548da941]:hover{background:var(--surface-2);color:var(--text)}.seg-btn.active[data-v-548da941]{background:var(--accent);border-color:var(--accent);color:#fff}.icon-btn[data-v-548da941]{font-size:14px;padding:4px 8px}.num-input-group[data-v-548da941]{display:flex;align-items:center;gap:8px}.range-input[data-v-548da941]{flex:1;accent-color:var(--accent);height:4px}.num-value[data-v-548da941]{font-size:11px;color:var(--text);font-variant-numeric:tabular-nums;min-width:36px;text-align:right}.box-model[data-v-e06fb04c]{display:flex;justify-content:center}.margin-box[data-v-e06fb04c],.padding-box[data-v-e06fb04c]{position:relative;display:flex;align-items:center;justify-content:center}.margin-box[data-v-e06fb04c]{padding:20px 28px;background:#f9731614;border:1px dashed rgba(249,115,22,.3);border-radius:6px;min-width:220px}.padding-box[data-v-e06fb04c]{padding:18px 24px;background:#22c55e14;border:1px dashed rgba(34,197,94,.3);border-radius:4px;width:100%}.content-box[data-v-e06fb04c]{padding:8px 12px;background:var(--accent);border-radius:3px;color:#fff;font-size:10px;font-weight:600;text-align:center;white-space:nowrap}.box-label[data-v-e06fb04c]{position:absolute;font-size:9px;text-transform:uppercase;letter-spacing:.05em;opacity:.6}.margin-label[data-v-e06fb04c]{top:3px;left:6px;color:#f97316}.padding-label[data-v-e06fb04c]{top:2px;left:5px;color:#22c55e}.side-input[data-v-e06fb04c]{position:absolute;width:28px;padding:1px 2px;font-size:10px;text-align:center;background:transparent;border:1px solid transparent;border-radius:3px;color:var(--text);font-variant-numeric:tabular-nums;outline:none}.side-input[data-v-e06fb04c]:hover{border-color:var(--border);background:var(--bg)}.side-input[data-v-e06fb04c]:focus{border-color:var(--accent);background:var(--bg)}.margin-box>.side-input.top[data-v-e06fb04c]{top:2px;left:50%;transform:translate(-50%)}.margin-box>.side-input.bottom[data-v-e06fb04c]{bottom:2px;left:50%;transform:translate(-50%)}.margin-box>.side-input.left[data-v-e06fb04c]{left:2px;top:50%;transform:translateY(-50%)}.margin-box>.side-input.right[data-v-e06fb04c]{right:2px;top:50%;transform:translateY(-50%)}.padding-box>.side-input.top[data-v-e06fb04c]{top:1px;left:50%;transform:translate(-50%)}.padding-box>.side-input.bottom[data-v-e06fb04c]{bottom:1px;left:50%;transform:translate(-50%)}.padding-box>.side-input.left[data-v-e06fb04c]{left:2px;top:50%;transform:translateY(-50%)}.padding-box>.side-input.right[data-v-e06fb04c]{right:2px;top:50%;transform:translateY(-50%)}.size-row[data-v-c3ca7e31]{display:flex;gap:8px;margin-bottom:10px}.size-field[data-v-c3ca7e31]{flex:1}.control-row[data-v-c3ca7e31]{margin-bottom:10px}.control-label[data-v-c3ca7e31]{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.04em}.size-input-group[data-v-c3ca7e31]{display:flex;align-items:center}.size-input[data-v-c3ca7e31]{width:100%;padding:5px 6px;background:var(--bg);border:1px solid var(--border);border-radius:5px 0 0 5px;color:var(--text);font-size:12px;font-variant-numeric:tabular-nums;outline:none}.size-input[data-v-c3ca7e31]:focus{border-color:var(--accent)}.size-unit[data-v-c3ca7e31]{padding:5px 6px;background:var(--surface-2);border:1px solid var(--border);border-left:none;border-radius:0 5px 5px 0;font-size:10px;color:var(--text-muted)}.button-group[data-v-c3ca7e31]{display:flex;gap:2px}.seg-btn[data-v-c3ca7e31]{flex:1;padding:4px;font-size:10px;background:var(--bg);border:1px solid var(--border);color:var(--text-muted);cursor:pointer}.seg-btn[data-v-c3ca7e31]:first-child{border-radius:5px 0 0 5px}.seg-btn[data-v-c3ca7e31]:last-child{border-radius:0 5px 5px 0}.seg-btn[data-v-c3ca7e31]:hover{background:var(--surface-2);color:var(--text)}.seg-btn.active[data-v-c3ca7e31]{background:var(--accent);border-color:var(--accent);color:#fff}.color-palette-picker[data-v-b0ade670]{position:relative}.picker-trigger[data-v-b0ade670]{display:flex;align-items:center;gap:6px}.color-swatch[data-v-b0ade670]{width:28px;height:28px;border:2px solid var(--border);border-radius:6px;cursor:pointer;padding:0;background:none}.color-swatch[data-v-b0ade670]::-webkit-color-swatch-wrapper{padding:0}.color-swatch[data-v-b0ade670]::-webkit-color-swatch{border:none;border-radius:4px}.palette-btn[data-v-b0ade670]{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--surface-2);border:1px solid var(--border);border-radius:5px;color:var(--text-muted);cursor:pointer;transition:all .1s}.palette-btn[data-v-b0ade670]:hover,.palette-btn.active[data-v-b0ade670]{background:var(--border);color:var(--text)}.color-match[data-v-b0ade670]{font-size:9px;color:var(--accent);font-family:SF Mono,Fira Code,monospace}.palette-popover[data-v-b0ade670]{position:absolute;top:100%;left:0;margin-top:6px;width:280px;background:var(--surface);border:1px solid var(--border);border-radius:10px;box-shadow:0 8px 24px #00000080;z-index:200;overflow:hidden}.palette-tabs[data-v-b0ade670]{display:flex;border-bottom:1px solid var(--border)}.ptab[data-v-b0ade670]{flex:1;padding:6px 4px;font-size:10px;font-weight:500;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;transition:all .15s}.ptab[data-v-b0ade670]:hover{color:var(--text)}.ptab.active[data-v-b0ade670]{color:var(--accent);border-bottom-color:var(--accent)}.palette-body[data-v-b0ade670]{max-height:320px;overflow-y:auto;padding:8px}.color-family[data-v-b0ade670]{display:flex;align-items:center;gap:6px;margin-bottom:3px}.family-label[data-v-b0ade670]{font-size:8px;color:var(--text-muted);width:40px;flex-shrink:0;text-align:right;text-transform:lowercase}.swatch-row[data-v-b0ade670]{display:flex;gap:2px}.swatch[data-v-b0ade670]{width:18px;height:18px;border:1px solid rgba(255,255,255,.08);border-radius:3px;cursor:pointer;padding:0;transition:transform .1s}.swatch[data-v-b0ade670]:hover{transform:scale(1.25);z-index:1;border-color:var(--text)}.swatch.selected[data-v-b0ade670]{outline:2px solid var(--accent);outline-offset:1px}.swatch.large[data-v-b0ade670]{width:24px;height:24px;border-radius:4px}.var-grid[data-v-b0ade670]{display:flex;flex-direction:column;gap:2px}.var-swatch[data-v-b0ade670]{display:flex;align-items:center;gap:8px;padding:5px 6px;background:none;border:1px solid transparent;border-radius:6px;cursor:pointer;transition:all .1s}.var-swatch[data-v-b0ade670]:hover{background:var(--surface-2);border-color:var(--border)}.var-swatch.selected[data-v-b0ade670]{border-color:var(--accent)}.var-color[data-v-b0ade670]{width:18px;height:18px;border-radius:4px;flex-shrink:0;border:1px solid rgba(255,255,255,.08)}.var-name[data-v-b0ade670]{font-size:11px;color:var(--text);font-family:SF Mono,Fira Code,monospace;flex:1;text-align:left}.var-hex[data-v-b0ade670]{font-size:9px;color:var(--text-muted);font-family:SF Mono,Fira Code,monospace}.swatch-grid[data-v-b0ade670]{display:flex;flex-wrap:wrap;gap:4px}.empty-msg[data-v-b0ade670]{font-size:11px;color:var(--text-muted);text-align:center;padding:20px 0}.control-row[data-v-47449e0a]{margin-bottom:10px}.control-label[data-v-47449e0a]{display:block;font-size:11px;color:var(--text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.04em}.color-input-group[data-v-47449e0a]{display:flex;align-items:center;gap:8px}.color-value[data-v-47449e0a]{font-size:10px;color:var(--text-muted);font-family:SF Mono,Fira Code,monospace;overflow:hidden;text-overflow:ellipsis}.num-input-group[data-v-47449e0a]{display:flex;align-items:center;gap:8px}.range-input[data-v-47449e0a]{flex:1;accent-color:var(--accent);height:4px}.num-value[data-v-47449e0a]{font-size:11px;color:var(--text);font-variant-numeric:tabular-nums;min-width:36px;text-align:right}.button-group[data-v-47449e0a]{display:flex;gap:1px}.seg-btn[data-v-47449e0a]{flex:1;padding:4px 2px;font-size:9px;background:var(--bg);border:1px solid var(--border);color:var(--text-muted);cursor:pointer;transition:all .1s}.seg-btn[data-v-47449e0a]:first-child{border-radius:5px 0 0 5px}.seg-btn[data-v-47449e0a]:last-child{border-radius:0 5px 5px 0}.seg-btn[data-v-47449e0a]:hover{background:var(--surface-2);color:var(--text)}.seg-btn.active[data-v-47449e0a]{background:var(--accent);border-color:var(--accent);color:#fff}.mode-toolbar[data-v-90efa075]{display:flex;gap:2px;margin-left:4px;align-items:center}.mode-btn[data-v-90efa075]{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:5px;background:var(--surface-2);color:var(--text-muted);cursor:pointer;transition:all .1s}.mode-btn[data-v-90efa075]:hover{background:var(--border);color:var(--text)}.mode-btn.active[data-v-90efa075]{background:var(--accent);border-color:var(--accent);color:#fff}.mode-btn.mode-interact.active[data-v-90efa075]{background:#6366f1;border-color:#6366f1}.mode-btn.arrow.active[data-v-90efa075]{background:#ef4444;border-color:#ef4444}.mode-btn.draw.active[data-v-90efa075]{background:#22c55e;border-color:#22c55e}.mode-btn.mode-highlight.active[data-v-90efa075]{background:#f59e0b;border-color:#f59e0b}.mode-sep[data-v-90efa075]{width:1px;height:18px;background:var(--border);margin:0 2px;align-self:center}.context-menu[data-v-b4795b28]{position:fixed;z-index:20000;min-width:160px;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #00000080;padding:4px;overflow:hidden}.menu-item[data-v-b4795b28]{display:flex;align-items:center;justify-content:space-between;width:100%;padding:6px 12px;background:none;border:none;border-radius:5px;color:var(--text);font-size:12px;cursor:pointer;transition:background .1s}.menu-item[data-v-b4795b28]:hover:not(.disabled){background:var(--surface-2)}.menu-item.disabled[data-v-b4795b28]{color:var(--text-muted);cursor:not-allowed;opacity:.5}.item-shortcut[data-v-b4795b28]{font-size:10px;color:var(--text-muted);font-family:SF Mono,monospace}.separator[data-v-b4795b28]{height:1px;background:var(--border);margin:4px 8px}.pin[data-v-006ef709]{position:fixed;z-index:10003;width:22px;height:22px;border-radius:50%;background:#3b82f6;color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;transform:translate(-11px,-11px);box-shadow:0 2px 6px #0000004d;transition:all .15s;border:2px solid white}.pin[data-v-006ef709]:hover{transform:translate(-11px,-11px) scale(1.2)}.pin.selected[data-v-006ef709]{background:#2563eb;box-shadow:0 0 0 3px #3b82f64d,0 2px 6px #0000004d}.pin.has-action[data-v-006ef709]{background:#a855f7}.pin.has-note.has-action[data-v-006ef709]{background:#7c3aed}.pin-number[data-v-006ef709]{font-size:10px;font-weight:700}.pin-remove[data-v-006ef709]{position:absolute;top:-6px;right:-6px;width:14px;height:14px;border-radius:50%;background:var(--danger, #ef4444);color:#fff;border:1px solid white;font-size:10px;line-height:1;cursor:pointer;display:none;align-items:center;justify-content:center;padding:0}.pin:hover .pin-remove[data-v-006ef709]{display:flex}.arrow-svg[data-v-1d2c9ec9]{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:10003;pointer-events:none}.arrow-path[data-v-1d2c9ec9]{pointer-events:stroke;cursor:pointer}.arrow-label[data-v-1d2c9ec9]{font-size:10px;font-weight:600;fill:#ef4444;pointer-events:none;paint-order:stroke;stroke:#00000080;stroke-width:3px}.arrow-delete[data-v-1d2c9ec9]{cursor:pointer;pointer-events:auto}.section-preview[data-v-d10f1f9f]{position:fixed;z-index:10003;border:2px dashed #22c55e;background:#22c55e0f;border-radius:6px;pointer-events:none}.drawn-section[data-v-d10f1f9f]{position:fixed;z-index:10003;border:2px dashed #22c55e;background:#22c55e0a;border-radius:6px;display:flex;flex-direction:column;overflow:hidden;cursor:pointer;transition:border-color .15s}.drawn-section.selected[data-v-d10f1f9f]{border-color:#16a34a;box-shadow:0 0 0 2px #22c55e4d}.section-header[data-v-d10f1f9f]{display:flex;align-items:center;gap:6px;padding:4px 8px;background:#22c55e1a;border-bottom:1px solid rgba(34,197,94,.15)}.section-badge[data-v-d10f1f9f]{font-size:9px;font-weight:700;color:#16a34a}.section-placement[data-v-d10f1f9f]{font-size:8px;color:#22c55e;background:#22c55e1a;padding:1px 4px;border-radius:3px}.section-delete[data-v-d10f1f9f]{margin-left:auto;width:16px;height:16px;border:none;background:none;color:#22c55e;font-size:14px;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center}.section-delete[data-v-d10f1f9f]:hover{color:#ef4444}.section-prompt[data-v-d10f1f9f]{flex:1;padding:6px 8px;border:none;background:transparent;color:#166534;font-size:11px;line-height:1.4;resize:none;outline:none;font-family:inherit;min-height:40px}.section-prompt[data-v-d10f1f9f]::placeholder{color:#16653466}.section-dims[data-v-d10f1f9f]{padding:2px 8px 4px;font-size:8px;color:#16653466;text-align:right}.notes-tab[data-v-0b4424b4]{display:flex;flex-direction:column;gap:14px}.section-label[data-v-0b4424b4]{display:block;font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);margin-bottom:6px}.action-grid[data-v-0b4424b4]{display:flex;flex-wrap:wrap;gap:4px}.action-btn[data-v-0b4424b4]{padding:4px 10px;font-size:11px;font-weight:500;background:var(--surface-2);border:1px solid var(--border);border-radius:5px;color:var(--text);cursor:pointer;transition:all .1s}.action-btn[data-v-0b4424b4]:hover{background:var(--border);color:var(--accent);border-color:var(--accent)}.note-input[data-v-0b4424b4]{width:100%;padding:8px;font-size:12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);resize:vertical;outline:none;font-family:inherit}.note-input[data-v-0b4424b4]:focus{border-color:var(--accent)}.submit-btn[data-v-0b4424b4]{margin-top:4px;padding:5px 12px;font-size:11px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:5px;cursor:pointer;transition:opacity .1s}.submit-btn[data-v-0b4424b4]:disabled{opacity:.4;cursor:not-allowed}.submit-btn[data-v-0b4424b4]:hover:not(:disabled){opacity:.9}.task-toggles[data-v-0b4424b4]{display:flex;gap:10px;margin-top:4px}.note-actions[data-v-0b4424b4]{display:flex;align-items:center;gap:8px;margin-top:4px}.history-toggle[data-v-0b4424b4]{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-muted);cursor:pointer;white-space:nowrap}.history-toggle input[data-v-0b4424b4]{margin:0}.history-toggle span[data-v-0b4424b4]{-webkit-user-select:none;user-select:none}.screenshot-btn[data-v-0b4424b4]{width:100%;padding:5px;margin-top:4px;font-size:10px;font-weight:600;background:var(--surface-2);color:var(--text-muted);border:1px dashed var(--border);border-radius:5px;cursor:pointer}.screenshot-btn[data-v-0b4424b4]:hover{border-color:var(--accent);color:var(--accent)}.screenshot-preview[data-v-0b4424b4]{position:relative;margin-top:4px}.screenshot-thumb[data-v-0b4424b4]{width:100%;border-radius:4px;border:1px solid var(--border)}.screenshot-remove[data-v-0b4424b4]{position:absolute;top:4px;right:4px;width:18px;height:18px;border:none;border-radius:50%;background:#0009;color:#fff;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.screenshot-remove[data-v-0b4424b4]:hover{background:#ef4444}.pin-item[data-v-0b4424b4]{display:flex;align-items:flex-start;gap:8px;padding:6px 8px;border-radius:5px;cursor:pointer;transition:background .1s}.pin-item[data-v-0b4424b4]:hover{background:var(--surface-2)}.pin-item.selected[data-v-0b4424b4]{background:var(--surface-2);border:1px solid var(--accent)}.pin-badge[data-v-0b4424b4]{width:18px;height:18px;border-radius:50%;background:#3b82f6;color:#fff;font-size:9px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.pin-badge.action[data-v-0b4424b4]{background:#a855f7}.pin-content[data-v-0b4424b4]{flex:1;min-width:0}.pin-file[data-v-0b4424b4]{font-size:10px;color:var(--accent);display:block;margin-bottom:2px}.pin-action[data-v-0b4424b4]{font-size:10px;color:#a855f7;font-weight:600;display:block}.pin-note[data-v-0b4424b4]{font-size:11px;color:var(--text);display:block;word-break:break-word}.pin-empty[data-v-0b4424b4]{font-size:10px;color:var(--text-muted);font-style:italic}.pin-delete[data-v-0b4424b4]{width:16px;height:16px;border-radius:50%;background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:12px;display:none;align-items:center;justify-content:center;padding:0}.pin-item:hover .pin-delete[data-v-0b4424b4]{display:flex}.pin-delete[data-v-0b4424b4]:hover{color:var(--danger, #ef4444)}.empty-hint[data-v-0b4424b4]{font-size:11px;color:var(--text-muted);text-align:center;padding:12px 0}.task-review[data-v-0b4424b4]{border-top:1px solid var(--border, #2a2a2a);padding-top:10px}.task-item[data-v-0b4424b4]{padding:6px 8px;border-radius:5px;margin-bottom:4px;border:1px solid var(--border, #2a2a2a)}.task-item.review[data-v-0b4424b4]{border-color:#f59e0b;background:#f59e0b0d}.task-item.denied[data-v-0b4424b4]{border-color:#ef4444;background:#ef44440d}.task-item.pending[data-v-0b4424b4]{border-color:var(--border, #2a2a2a)}.task-header[data-v-0b4424b4]{display:flex;align-items:center;gap:6px;margin-bottom:3px}.task-status-badge[data-v-0b4424b4]{font-size:8px;font-weight:700;padding:1px 5px;border-radius:3px;text-transform:uppercase}.task-status-badge.pending[data-v-0b4424b4]{background:#71717a33;color:#71717a}.task-status-badge.review[data-v-0b4424b4]{background:#f59e0b33;color:#f59e0b}.task-status-badge.denied[data-v-0b4424b4]{background:#ef444433;color:#ef4444}.task-desc[data-v-0b4424b4]{font-size:11px;color:var(--text, #e4e4e7)}.task-file[data-v-0b4424b4]{font-size:9px;color:var(--text-muted, #71717a);display:block;margin-bottom:3px}.task-feedback[data-v-0b4424b4]{font-size:10px;color:#ef4444;font-style:italic;margin-bottom:3px}.task-actions[data-v-0b4424b4]{display:flex;gap:4px;align-items:center;margin-top:4px}.task-accept[data-v-0b4424b4]{padding:4px 10px;font-size:10px;font-weight:600;background:#22c55e26;color:#22c55e;border:none;border-radius:4px;cursor:pointer;transition:all .12s}.task-accept[data-v-0b4424b4]:hover{background:#22c55e;color:#fff}.task-deny[data-v-0b4424b4]{padding:4px 10px;font-size:10px;font-weight:600;background:#ef44441f;color:#ef4444;border:none;border-radius:4px;cursor:pointer;transition:all .12s}.task-deny[data-v-0b4424b4]:hover{background:#ef4444;color:#fff}.deny-input[data-v-0b4424b4]{flex:1;padding:2px 6px;font-size:10px;background:var(--bg, #0a0a0a);border:1px solid var(--border);border-radius:4px;color:var(--text);outline:none}.task-cancel[data-v-0b4424b4]{width:18px;height:18px;border:none;background:none;color:var(--text-muted, #71717a);font-size:14px;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center;margin-left:auto;border-radius:3px}.task-cancel[data-v-0b4424b4]:hover{color:#ef4444;background:#ef44441a}.highlight-prompt[data-v-b4a28a2c]{position:fixed;z-index:10005;background:var(--surface, #141414);border:1px solid #f59e0b;border-radius:8px;box-shadow:0 8px 24px #00000080;padding:8px;width:280px}.prompt-header[data-v-b4a28a2c]{margin-bottom:6px}.prompt-text-preview[data-v-b4a28a2c]{font-size:11px;color:#f59e0b;font-style:italic;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.prompt-input[data-v-b4a28a2c]{width:100%;padding:6px 8px;background:var(--bg, #0a0a0a);border:1px solid var(--border, #2a2a2a);border-radius:5px;color:var(--text, #e4e4e7);font-size:12px;outline:none}.prompt-input[data-v-b4a28a2c]:focus{border-color:#f59e0b}.prompt-hint[data-v-b4a28a2c]{font-size:9px;color:var(--text-muted, #71717a);margin-top:4px}.text-highlight-card[data-v-b4a28a2c]{position:relative;margin:4px 0;padding:6px 8px;background:#f59e0b14;border:1px solid rgba(245,158,11,.2);border-radius:6px;cursor:pointer}.text-highlight-card.selected[data-v-b4a28a2c]{border-color:#f59e0b}.hl-header[data-v-b4a28a2c]{display:flex;align-items:center;gap:6px;margin-bottom:3px}.hl-badge[data-v-b4a28a2c]{font-size:9px;font-weight:700;color:#f59e0b}.hl-file[data-v-b4a28a2c]{font-size:9px;color:var(--text-muted, #71717a)}.hl-delete[data-v-b4a28a2c]{margin-left:auto;width:14px;height:14px;border:none;background:none;color:var(--text-muted);font-size:12px;cursor:pointer;padding:0;display:none}.text-highlight-card:hover .hl-delete[data-v-b4a28a2c]{display:block}.hl-text[data-v-b4a28a2c]{font-size:11px;color:#f59e0b;font-style:italic;margin-bottom:2px}.hl-prompt[data-v-b4a28a2c]{font-size:11px;color:var(--text, #e4e4e7)}.hl-prompt-edit[data-v-b4a28a2c]{width:100%;margin-top:4px;padding:4px 6px;background:var(--bg, #0a0a0a);border:1px solid var(--border, #2a2a2a);border-radius:4px;color:var(--text);font-size:11px;outline:none}.hl-prompt-edit[data-v-b4a28a2c]:focus{border-color:#f59e0b}.layout-outline[data-v-ed4fb8a3]{position:fixed;pointer-events:none;z-index:9998;border-radius:3px}.layout-outline.flex[data-v-ed4fb8a3]{border:1.5px dashed rgba(168,85,247,.4);background:#a855f708}.layout-outline.grid[data-v-ed4fb8a3]{border:1.5px dashed rgba(34,197,94,.4);background:#22c55e08}.layout-label[data-v-ed4fb8a3]{position:absolute;top:-16px;left:4px;font-size:9px;font-weight:600;padding:1px 5px;border-radius:3px;white-space:nowrap;letter-spacing:.03em}.flex .layout-label[data-v-ed4fb8a3]{background:#a855f726;color:#a855f7}.grid .layout-label[data-v-ed4fb8a3]{background:#22c55e26;color:#22c55e}.grid-line[data-v-ed4fb8a3]{position:fixed;z-index:9999;pointer-events:auto}.grid-line.col[data-v-ed4fb8a3]{width:6px;margin-left:-3px;cursor:col-resize;background:transparent}.grid-line.col[data-v-ed4fb8a3]:hover,.grid-line.col[data-v-ed4fb8a3]:active{background:#22c55e4d}.grid-line.row[data-v-ed4fb8a3]{height:6px;margin-top:-3px;cursor:row-resize;background:transparent}.grid-line.row[data-v-ed4fb8a3]:hover,.grid-line.row[data-v-ed4fb8a3]:active{background:#22c55e4d}.add-track-btn[data-v-ed4fb8a3],.add-child-btn[data-v-ed4fb8a3]{position:fixed;z-index:9999;pointer-events:auto;border:none;border-radius:4px;font-size:9px;font-weight:700;padding:3px 6px;cursor:pointer;opacity:.7;transition:all .15s;white-space:nowrap}.add-track-btn[data-v-ed4fb8a3]:hover,.add-child-btn[data-v-ed4fb8a3]:hover{opacity:1;transform:scale(1.1)}.add-track-btn[data-v-ed4fb8a3]{background:#22c55e26;color:#22c55e;border:1px solid rgba(34,197,94,.3)}.add-track-btn[data-v-ed4fb8a3]:hover{background:#22c55e4d}.add-child-btn[data-v-ed4fb8a3]{background:#a855f726;color:#a855f7;border:1px solid rgba(168,85,247,.3);width:22px;height:22px;display:flex;align-items:center;justify-content:center;font-size:14px;padding:0}.add-child-btn[data-v-ed4fb8a3]:hover{background:#a855f74d}.theme-page[data-v-67b64182]{display:flex;flex-direction:column;height:100%;overflow:hidden}.theme-header[data-v-67b64182]{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--border);flex-shrink:0}.theme-title[data-v-67b64182]{font-size:13px;font-weight:600;color:var(--text)}.theme-actions[data-v-67b64182]{display:flex;align-items:center;gap:8px}.theme-change-count[data-v-67b64182]{font-size:11px;color:var(--text-muted)}.theme-btn[data-v-67b64182]{padding:4px 12px;font-size:11px;font-weight:600;border:none;border-radius:5px;cursor:pointer}.theme-btn.commit[data-v-67b64182]{background:var(--accent);color:#fff}.theme-btn.commit[data-v-67b64182]:hover{opacity:.9}.theme-btn.commit[data-v-67b64182]:disabled{opacity:.4;cursor:not-allowed}.theme-btn.discard[data-v-67b64182]{background:var(--surface-2);color:var(--text-muted);border:1px solid var(--border)}.theme-btn.discard[data-v-67b64182]:hover{color:var(--text);background:var(--border)}.theme-btn.small[data-v-67b64182]{padding:3px 10px;font-size:10px}.theme-empty[data-v-67b64182]{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--text-muted);text-align:center;padding:24px}.theme-empty p[data-v-67b64182]{font-size:13px}.theme-empty-hint[data-v-67b64182]{font-size:11px;opacity:.7}.theme-empty code[data-v-67b64182]{background:#3b82f626;padding:1px 6px;border-radius:3px;font-weight:600;color:#60a5fa}.theme-tabs[data-v-67b64182]{display:flex;border-bottom:1px solid var(--border);flex-shrink:0}.theme-tab[data-v-67b64182]{flex:1;padding:8px 4px;font-size:11px;font-weight:500;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;transition:all .15s}.theme-tab[data-v-67b64182]:hover{color:var(--text)}.theme-tab.active[data-v-67b64182]{color:var(--accent);border-bottom-color:var(--accent)}.theme-tab-badge[data-v-67b64182]{display:inline-flex;align-items:center;justify-content:center;min-width:14px;height:14px;padding:0 3px;font-size:9px;font-weight:700;background:var(--accent);color:#fff;border-radius:7px;margin-left:3px}.theme-content[data-v-67b64182]{flex:1;overflow-y:auto;padding:12px}.theme-section[data-v-67b64182]{display:flex;flex-direction:column;gap:2px}.theme-section-empty[data-v-67b64182]{padding:16px 0;text-align:center;font-size:11px;color:var(--text-muted);opacity:.6}.section-subtitle[data-v-67b64182]{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);padding:6px 0 4px}.token-row[data-v-67b64182]{display:flex;align-items:center;justify-content:space-between;padding:6px 8px;border-radius:6px;gap:8px;transition:background .1s}.token-row[data-v-67b64182]:hover{background:var(--surface-2)}.token-row.new[data-v-67b64182]{background:#3b82f60f}.token-info[data-v-67b64182]{display:flex;flex-direction:column;gap:1px;min-width:0;flex-shrink:1}.token-role[data-v-67b64182]{font-size:12px;font-weight:500;color:var(--text);white-space:nowrap}.token-role.edited[data-v-67b64182]{color:var(--accent)}.token-role.new-badge[data-v-67b64182]{color:#22c55e;font-weight:600}.token-source[data-v-67b64182]{font-size:9px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px}.token-controls[data-v-67b64182]{display:flex;align-items:center;gap:6px;flex-shrink:0}.token-value-input[data-v-67b64182]{width:80px;padding:3px 6px;font-size:11px;font-family:monospace;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);outline:none}.token-value-input[data-v-67b64182]:focus{border-color:var(--accent)}.token-value-input.wide[data-v-67b64182]{width:160px}.token-value-input.color-hex[data-v-67b64182]{width:72px}.token-value-ro[data-v-67b64182]{font-size:11px;color:var(--text-muted)}.token-remove[data-v-67b64182]{width:18px;height:18px;border:none;background:none;color:var(--text-muted);font-size:14px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:3px}.token-remove[data-v-67b64182]:hover{color:#ef4444;background:#ef44441a}.no-preview-badge[data-v-67b64182]{font-size:8px;color:var(--text-muted);opacity:.6;white-space:nowrap}.color-swatch-wrapper[data-v-67b64182]{flex-shrink:0}.color-swatch-inline[data-v-67b64182]{width:20px;height:20px;border-radius:4px;border:1px solid var(--border);flex-shrink:0}.font-size-preview[data-v-67b64182]{color:var(--text);line-height:1;white-space:nowrap}.weight-chips[data-v-67b64182]{display:flex;flex-wrap:wrap;gap:4px;padding:4px 0}.weight-chip[data-v-67b64182]{font-size:10px;padding:2px 8px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px;color:var(--text-muted)}.spacing-preview[data-v-67b64182]{width:60px;height:12px;background:var(--surface-2);border-radius:2px;overflow:hidden}.spacing-bar[data-v-67b64182]{height:100%;background:var(--accent);border-radius:2px;max-width:100%;transition:width .15s}.radius-preview[data-v-67b64182]{width:24px;height:24px;background:var(--accent);transition:border-radius .15s}.add-token-btn[data-v-67b64182]{padding:6px;margin-top:4px;font-size:11px;color:var(--text-muted);background:none;border:1px dashed var(--border);border-radius:6px;cursor:pointer;transition:all .1s}.add-token-btn[data-v-67b64182]:hover{color:var(--accent);border-color:var(--accent)}.add-token-form[data-v-67b64182]{display:flex;flex-direction:column;gap:4px;padding:8px;margin-top:4px;background:var(--surface-2);border:1px solid var(--border);border-radius:6px}.add-input[data-v-67b64182]{padding:4px 8px;font-size:11px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);outline:none;font-family:inherit}.add-input[data-v-67b64182]:focus{border-color:var(--accent)}.add-actions[data-v-67b64182]{display:flex;gap:4px;margin-top:2px}.library-card[data-v-67b64182]{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--surface-2);border:1px solid var(--border);border-radius:6px}.library-name[data-v-67b64182]{font-size:12px;font-weight:600;color:var(--text)}.library-version[data-v-67b64182]{font-size:10px;color:var(--text-muted)}.styling-chip[data-v-67b64182]{font-size:9px;padding:1px 6px;background:#3b82f61f;color:#60a5fa;border-radius:3px;font-weight:600}.library-components[data-v-67b64182]{display:flex;flex-wrap:wrap;gap:4px;padding:6px 0}.component-chip[data-v-67b64182]{font-size:10px;padding:2px 8px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px;color:var(--text-muted);font-family:monospace}.report-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50000;display:flex;justify-content:flex-end}.report-backdrop{position:absolute;top:0;right:0;bottom:0;left:0;background:#0006}.report-drawer{position:relative;width:min(720px,80vw);height:100%;background:#0d0d0d;border-left:1px solid var(--border);display:flex;flex-direction:column;animation:slide-in .15s ease-out}@keyframes slide-in{0%{transform:translate(100%)}to{transform:translate(0)}}.report-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--border);background:var(--surface);flex-shrink:0}.report-title{display:flex;align-items:center;gap:10px;font-size:14px;font-weight:600;color:var(--text)}.report-badge{font-size:11px;font-weight:500;color:var(--text-muted);background:var(--surface-2);padding:2px 8px;border-radius:4px;border:1px solid var(--border)}.report-controls{display:flex;align-items:center;gap:8px}.format-toggle{display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden}.fmt-btn{padding:4px 12px;font-size:11px;font-weight:600;color:var(--text-muted);background:transparent;border:none;cursor:pointer;transition:all .1s}.fmt-btn.active{background:var(--surface-2);color:var(--text)}.fmt-btn:hover:not(.active){color:var(--text)}.copy-btn{display:flex;align-items:center;gap:5px;padding:5px 12px;font-size:12px;font-weight:500;color:var(--text);background:var(--surface-2);border:1px solid var(--border);border-radius:6px;cursor:pointer;transition:all .1s}.copy-btn:hover{background:var(--border)}.copy-btn:disabled{opacity:.4;cursor:default}.close-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;color:var(--text-muted);background:transparent;border:none;border-radius:6px;cursor:pointer;transition:all .1s}.close-btn:hover{background:var(--surface-2);color:var(--text)}.report-body{flex:1;overflow:auto}.report-code{margin:0;padding:20px;font-size:12px;line-height:1.6;-moz-tab-size:2;tab-size:2;overflow:auto;background:transparent}.report-code code{font-family:SF Mono,Fira Code,Cascadia Code,JetBrains Mono,Consolas,monospace}.report-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:14px}.report-empty-hint{font-size:12px;margin-top:8px;opacity:.6}.report-code .token.property{color:#7dd3fc}.report-code .token.string{color:#86efac}.report-code .token.number{color:#fbbf24}.report-code .token.boolean{color:#c084fc}.report-code .token.null{color:#f87171}.report-code .token.operator{color:#71717a}.report-code .token.punctuation{color:#52525b}.report-code .token.key,.report-code .token.atrule,.report-code .token.tag{color:#7dd3fc}.report-code .token.scalar{color:#86efac}.report-code .token.important{color:#fbbf24}.viewport-selector[data-v-0f350755]{position:relative}.vp-trigger[data-v-0f350755]{display:flex;align-items:center;gap:4px;padding:3px 8px;border:1px solid var(--border);border-radius:5px;background:var(--surface-2);color:var(--text-muted);font-size:11px;cursor:pointer;transition:all .1s;white-space:nowrap}.vp-trigger[data-v-0f350755]:hover{background:var(--border);color:var(--text)}.vp-label[data-v-0f350755]{font-family:monospace;font-size:11px}.vp-dropdown[data-v-0f350755]{position:absolute;top:100%;left:50%;transform:translate(-50%);margin-top:4px;min-width:220px;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 24px #0006;padding:4px;z-index:100;max-height:400px;overflow-y:auto}.vp-group[data-v-0f350755]{margin-top:2px}.vp-group-title[data-v-0f350755]{padding:4px 8px 2px;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);opacity:.6}.vp-item[data-v-0f350755]{display:flex;align-items:center;justify-content:space-between;width:100%;padding:5px 8px;border:none;border-radius:4px;background:transparent;color:var(--text);font-size:11px;cursor:pointer;transition:background .1s}.vp-item[data-v-0f350755]:hover{background:var(--surface-2)}.vp-item.active[data-v-0f350755]{background:var(--accent);color:#fff}.vp-item-label[data-v-0f350755]{flex:1;text-align:left}.vp-item-dim[data-v-0f350755]{font-family:monospace;font-size:10px;color:var(--text-muted)}.vp-item.active .vp-item-dim[data-v-0f350755]{color:#ffffffb3}.vp-custom[data-v-0f350755]{margin-top:2px;border-top:1px solid var(--border);padding-top:4px}.vp-custom-row[data-v-0f350755]{display:flex;align-items:center;gap:4px;padding:4px 8px}.vp-input[data-v-0f350755]{width:56px;padding:3px 6px;border:1px solid var(--border);border-radius:4px;background:var(--surface-2);color:var(--text);font-size:11px;font-family:monospace;text-align:center}.vp-input[data-v-0f350755]:focus{outline:none;border-color:var(--accent)}.vp-x[data-v-0f350755]{color:var(--text-muted);font-size:10px}.vp-apply[data-v-0f350755]{padding:3px 8px;border:1px solid var(--accent);border-radius:4px;background:var(--accent);color:#fff;font-size:10px;font-weight:600;cursor:pointer}.vp-apply[data-v-0f350755]:hover{opacity:.9}.vp-rotate[data-v-0f350755]{margin-top:2px;border-top:1px solid var(--border);padding-top:4px;gap:6px}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg: #0a0a0a;--surface: #141414;--surface-2: #1e1e1e;--border: #2a2a2a;--text: #e4e4e7;--text-muted: #71717a;--accent: #3b82f6;--danger: #ef4444}html,body,#app{height:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:13px}.annotask-shell{display:flex;flex-direction:column;height:100%}.toolbar{display:flex;align-items:center;justify-content:space-between;height:40px;padding:0 12px;background:var(--surface);border-bottom:1px solid var(--border);flex-shrink:0}.toolbar-left,.toolbar-right{display:flex;align-items:center;gap:8px}.logo{height:20px;width:auto;margin-right:12px;color:var(--accent)}.tool-btn{display:flex;align-items:center;gap:4px;padding:4px 10px;border:1px solid var(--border);border-radius:6px;background:var(--surface-2);color:var(--text);font-size:12px;cursor:pointer}.tool-btn:hover{background:var(--border)}.tool-btn:disabled{opacity:.4;cursor:not-allowed}.tool-btn.active{background:var(--accent);border-color:var(--accent);color:#fff}.tool-btn.danger{color:var(--danger)}.panel-toggle{display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden}.toggle-btn{display:flex;align-items:center;gap:3px;padding:3px 8px;border:none;background:var(--surface-2);color:var(--text-muted);font-size:11px;cursor:pointer;transition:all .1s}.toggle-btn:first-child{border-right:1px solid var(--border)}.toggle-btn:hover{background:var(--border);color:var(--text)}.toggle-btn.active{background:var(--accent);color:#fff}.toggle-badge{display:inline-flex;align-items:center;justify-content:center;min-width:14px;height:14px;padding:0 3px;font-size:8px;font-weight:700;background:#ffffff40;color:#fff;border-radius:7px}.toggle-btn:not(.active) .toggle-badge{background:var(--accent);color:#fff}.view-toggle{display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden;margin-right:8px}.theme-panel{width:440px;background:var(--surface);border-left:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}.visibility-toggles{display:flex;gap:1px;margin-right:4px}.vis-btn{width:20px;height:20px;border:none;border-radius:3px;background:var(--surface-2);color:var(--text-muted);font-size:9px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .1s}.vis-btn:hover{background:var(--border);color:var(--text)}.vis-btn.off{opacity:.3;text-decoration:line-through}.change-count{font-size:11px;color:var(--text-muted)}.warning-banner{padding:8px 16px;background:#eab3081a;border-bottom:1px solid rgba(234,179,8,.3);color:#eab308;font-size:12px}.warning-banner code{background:#eab30826;padding:1px 4px;border-radius:3px}.setup-banner{padding:8px 16px;background:#3b82f614;border-bottom:1px solid rgba(59,130,246,.2);color:#60a5fa;font-size:12px}.setup-banner code{background:#3b82f626;padding:1px 6px;border-radius:3px;font-weight:600}.main{display:flex;flex:1;overflow:hidden}.toolbar-center{display:flex;align-items:center;gap:8px}.route-indicator{font-size:11px;color:var(--text-muted);background:var(--surface-2);padding:2px 8px;border-radius:4px;border:1px solid var(--border)}.canvas-area{flex:1;position:relative;overflow:hidden}.canvas-area.viewport-active{display:flex;align-items:flex-start;justify-content:center;overflow:auto;background:#0a0a0a;padding:16px}.app-iframe{width:100%;height:100%;border:none}.canvas-area.viewport-active .app-iframe{flex-shrink:0;border-radius:6px;box-shadow:0 0 0 1px var(--border),0 4px 24px #00000080}.drawing-shield{position:absolute;top:0;right:0;bottom:0;left:0;z-index:9999}.drawing-shield.arrow,.drawing-shield.draw{cursor:crosshair}.highlight{position:fixed;pointer-events:none;z-index:10000;border-radius:2px}.highlight.hover{background:#3b82f61a;border:1.5px solid rgba(59,130,246,.5)}.highlight.group{background:#a855f714;border:1.5px dashed rgba(168,85,247,.4)}.highlight.select{background:#3b82f614;border:2px solid var(--accent)}.hover-label,.select-label{position:absolute;bottom:100%;left:-1px;display:flex;align-items:center;gap:6px;padding:2px 8px;font-size:11px;font-weight:500;white-space:nowrap;border-radius:4px 4px 0 0}.hover-label{background:var(--accent);color:#fff}.hover-tag{font-family:monospace}.hover-comp{opacity:.7}.select-label{background:var(--accent);color:#fff;font-family:monospace;font-size:10px}.panel{width:320px;background:var(--surface);border-left:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}.panel.empty{justify-content:center;align-items:center}.panel-source{padding:10px 14px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;flex-wrap:wrap}.source-path{font-size:12px;color:var(--accent);word-break:break-all;font-family:monospace}.component-badge{font-size:10px;padding:2px 6px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px;color:var(--text-muted);white-space:nowrap}.role-badge{font-size:9px;padding:1px 5px;border-radius:3px;font-weight:600;text-transform:uppercase;letter-spacing:.03em}.role-badge.container{background:#22c55e26;color:#22c55e}.role-badge.content{background:#3b82f626;color:#3b82f6}.role-badge.component{background:#a855f726;color:#a855f7}.panel-group-bar{display:flex;align-items:center;justify-content:space-between;padding:6px 14px;border-bottom:1px solid var(--border);background:#a855f70f}.group-summary{font-size:11px;color:#a855f7}.group-toggle{display:flex;align-items:center;gap:5px;cursor:pointer}.group-toggle input{accent-color:#a855f7;width:14px;height:14px;cursor:pointer}.toggle-label{font-size:11px;color:var(--text-muted)}.panel-tabs{display:flex;border-bottom:1px solid var(--border);flex-shrink:0}.tab{flex:1;padding:8px 4px;font-size:11px;font-weight:500;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;transition:all .15s}.tab:hover{color:var(--text)}.tab.active{color:var(--accent);border-bottom-color:var(--accent)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:14px;height:14px;padding:0 3px;font-size:9px;font-weight:700;background:var(--accent);color:#fff;border-radius:7px;margin-left:3px}.tab-content{flex:1;overflow-y:auto;padding:14px}.class-editor{width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:monospace;font-size:12px;resize:vertical;outline:none}.class-editor:focus{border-color:var(--accent)}.hint{font-size:10px;color:var(--text-muted);margin-top:4px}.empty-content{text-align:center;color:var(--text-muted)}.empty-content p{margin-top:8px}.empty-hint{font-size:11px;opacity:.6}.changes-footer{border-top:1px solid var(--border);flex-shrink:0;padding:8px 14px}.changes-list{max-height:120px;overflow-y:auto;margin-bottom:6px}.change-item{display:flex;align-items:center;gap:6px;padding:2px 0;font-size:11px}.change-prop{color:var(--text-muted);font-family:monospace}.change-arrow{color:var(--text-muted);font-size:10px}.change-val{color:#22c55e;font-family:monospace}.changes-actions{display:flex;align-items:center;gap:6px}.changes-count{font-size:10px;color:var(--text-muted);flex:1}.changes-commit{padding:4px 12px;font-size:11px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:5px;cursor:pointer}.changes-commit:hover{opacity:.9}.changes-discard{padding:4px 12px;font-size:11px;background:var(--surface-2);color:var(--text-muted);border:1px solid var(--border);border-radius:5px;cursor:pointer}.changes-discard:hover{background:var(--border);color:var(--text)}.task-card{padding:8px;border:1px solid var(--border);border-radius:6px;margin-bottom:6px}.task-card.review{border-color:#f59e0b}.task-card.denied{border-color:#ef4444}.task-card-header{display:flex;align-items:center;gap:6px;margin-bottom:3px}.task-status-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.task-status-dot.pending{background:#71717a}.task-status-dot.review{background:#f59e0b}.task-status-dot.denied{background:#ef4444}.task-card-desc{font-size:11px;color:var(--text);flex:1}.task-card-close{width:16px;height:16px;border:none;background:none;color:var(--text-muted);font-size:13px;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center;border-radius:3px}.task-card-close:hover{color:#ef4444;background:#ef44441a}.task-card-meta{display:flex;align-items:center;gap:6px}.task-card-file{font-size:9px;color:var(--text-muted)}.task-route-badge{font-size:8px;padding:1px 5px;background:#3b82f61f;color:#60a5fa;border-radius:3px;font-weight:600}.task-card-feedback{font-size:10px;color:#ef4444;font-style:italic;margin-top:3px}.new-task-toggle{margin-left:auto;padding:2px 8px;font-size:10px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer}.new-task-toggle:hover{opacity:.9}.new-task-form{padding:8px 14px;border-bottom:1px solid var(--border)}.new-task-input{width:100%;padding:6px 8px;font-size:12px;background:var(--bg);border:1px solid var(--border);border-radius:5px;color:var(--text);resize:none;outline:none;font-family:inherit}.new-task-input:focus{border-color:var(--accent)}.new-task-actions{display:flex;gap:4px;margin-top:4px}.submit-btn{padding:4px 12px;font-size:11px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer}.submit-btn:disabled{opacity:.4;cursor:not-allowed}.cancel-btn{padding:4px 12px;font-size:11px;background:var(--surface-2);color:var(--text-muted);border:1px solid var(--border);border-radius:4px;cursor:pointer}.task-card-actions{display:flex;gap:4px;margin-top:6px;align-items:center}.deny-feedback-input{flex:1;padding:4px 8px;font-size:10px;background:var(--bg);border:1px solid #ef4444;border-radius:4px;color:var(--text);outline:none}.deny-feedback-input:focus{box-shadow:0 0 0 2px #ef444433}.task-card-actions .task-accept,.task-card-actions .task-deny{flex:1;padding:5px 0;font-size:11px;font-weight:600;border:none;border-radius:5px;cursor:pointer;transition:all .12s;display:flex;align-items:center;justify-content:center;gap:4px}.task-card-actions .task-accept{background:#22c55e26;color:#22c55e}.task-card-actions .task-accept:hover{background:#22c55e;color:#fff}.task-card-actions .task-deny{background:#ef44441f;color:#ef4444}.task-card-actions .task-deny:hover{background:#ef4444;color:#fff}.pending-task-panel{padding:14px;display:flex;flex-direction:column;gap:12px}.pending-task-context{display:flex;flex-direction:column;gap:6px}.pending-task-kind{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--text)}.pending-task-kind.pin{color:var(--accent)}.pending-task-kind.pin svg{stroke:var(--accent)}.pending-task-kind.arrow{color:#ef4444}.pending-task-kind.arrow svg{stroke:#ef4444}.pending-task-file{font-size:11px;color:var(--text-muted);font-family:monospace}.pending-task-input{width:100%;padding:8px 10px;font-size:12px;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:6px;resize:vertical;font-family:inherit;line-height:1.4}.pending-task-input:focus{border-color:var(--accent);outline:none}.pending-task-actions{display:flex;gap:6px}.pending-task-actions .submit-btn{flex:1;padding:6px 12px;font-size:11px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:5px;cursor:pointer}.pending-task-actions .submit-btn:disabled{opacity:.4;cursor:default}.pending-task-actions .cancel-btn{padding:6px 12px;font-size:11px;background:var(--surface-2);color:var(--text-muted);border:1px solid var(--border);border-radius:5px;cursor:pointer}.pending-task-actions .cancel-btn:hover{background:var(--border);color:var(--text)}.task-toggles{display:flex;gap:10px;margin-bottom:4px}.scan-btn{padding:3px 10px;font-size:10px;font-weight:600;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer}.scan-btn:disabled{opacity:.5;cursor:default}.scan-btn:hover:not(:disabled){opacity:.9}.a11y-error{font-size:11px;color:#ef4444;padding:6px 8px;background:#ef44441a;border-radius:5px;margin-bottom:6px}.a11y-pass{display:flex;align-items:center;gap:6px;padding:8px 10px;border-radius:6px;font-size:11px;font-weight:600;background:#22c55e1f;color:#22c55e;border:1px solid rgba(34,197,94,.25)}.a11y-empty{font-size:11px;color:var(--text-muted);padding:20px 0;text-align:center}.a11y-summary{font-size:11px;font-weight:600;color:#ef4444;padding:6px 8px;border-radius:5px;margin-bottom:4px;background:#ef444414;border:1px solid rgba(239,68,68,.2)}.a11y-card{padding:8px;border-radius:6px;margin-bottom:6px;background:var(--surface-2);border-left:3px solid var(--border)}.a11y-card.critical{border-left-color:#dc2626}.a11y-card.serious{border-left-color:#ef4444}.a11y-card.moderate{border-left-color:#f59e0b}.a11y-card.minor{border-left-color:#6b7280}.a11y-card-header{display:flex;align-items:center;gap:6px;font-size:11px}.a11y-impact{font-size:9px;font-weight:700;text-transform:uppercase;padding:1px 5px;border-radius:3px;color:#fff}.a11y-impact.critical{background:#dc2626}.a11y-impact.serious{background:#ef4444}.a11y-impact.moderate{background:#f59e0b}.a11y-impact.minor{background:#6b7280}.a11y-rule{font-weight:600;color:var(--text)}.a11y-count{margin-left:auto;color:var(--text-muted);font-size:10px}.a11y-help{margin:4px 0 6px;font-size:11px;color:var(--text-muted);line-height:1.4}.a11y-fix-btn{padding:3px 10px;font-size:10px;font-weight:600;background:#3b82f61f;color:#3b82f6;border:1px solid rgba(59,130,246,.25);border-radius:4px;cursor:pointer}.a11y-fix-btn:hover{background:#3b82f6;color:#fff}.a11y-tasked{font-size:10px;color:#22c55e;font-weight:600}.screenshot-btn{width:100%;padding:5px;margin-top:4px;font-size:10px;font-weight:600;background:var(--surface-2);color:var(--text-muted);border:1px dashed var(--border);border-radius:5px;cursor:pointer}.screenshot-btn:hover{border-color:var(--accent);color:var(--accent)}.screenshot-preview{position:relative;margin-top:4px}.screenshot-thumb{width:100%;border-radius:4px;border:1px solid var(--border)}.screenshot-remove{position:absolute;top:4px;right:4px;width:18px;height:18px;border:none;border-radius:50%;background:#0009;color:#fff;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.screenshot-remove:hover{background:#ef4444}.snip-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:20000;background:#0000004d;cursor:crosshair}.snip-hint{position:absolute;top:16px;left:50%;transform:translate(-50%);padding:6px 14px;border-radius:6px;font-size:12px;font-weight:600;background:#000000b3;color:#fff;pointer-events:none}.snip-selection{position:fixed;z-index:20001;pointer-events:none;border:2px dashed #06b6d4;background:#06b6d414;border-radius:4px}.task-screenshot-thumb{width:100%;border-radius:4px;margin-top:6px;border:1px solid var(--border)}.history-toggle{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-muted);cursor:pointer;white-space:nowrap}.history-toggle input{margin:0}.history-toggle span{-webkit-user-select:none;user-select:none}.shortcuts-panel{padding:14px;overflow-y:auto;flex:1}.shortcut-group{margin-bottom:16px}.shortcut-group-title{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid var(--border)}.shortcut-row{display:flex;align-items:center;gap:6px;padding:4px 0;font-size:12px;color:var(--text)}.shortcut-row span{margin-left:auto;color:var(--text-muted);font-size:11px}.shortcut-row kbd{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:20px;padding:0 5px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px;font-family:inherit;font-size:11px;font-weight:600;color:var(--text);box-shadow:0 1px 0 var(--border)}.shortcut-row kbd.mod{font-size:10px;color:var(--text-muted)}.shortcut-hint{font-size:11px;color:var(--text-muted);padding-top:8px;border-top:1px solid var(--border);display:flex;align-items:center;gap:4px;flex-wrap:wrap}.shortcut-hint kbd{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 4px;background:var(--surface-2);border:1px solid var(--border);border-radius:3px;font-family:inherit;font-size:10px;font-weight:600;color:var(--text-muted)}
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <link rel="icon" href="/__annotask/favicon.ico" />
7
7
  <title>Annotask</title>
8
- <script type="module" crossorigin src="/__annotask/assets/index-BcsdXOsJ.js"></script>
9
- <link rel="stylesheet" crossorigin href="/__annotask/assets/index-DwbhEo-C.css">
8
+ <script type="module" crossorigin src="/__annotask/assets/index-Dko9s8T0.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/__annotask/assets/index-En0AXNAK.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="app"></div>
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  startStandaloneServer
3
- } from "./chunk-JPNMDGZN.js";
3
+ } from "./chunk-4IZECCVO.js";
4
4
  import "./chunk-XLNGAH3S.js";
5
- import "./chunk-JLOSPIJ4.js";
5
+ import "./chunk-KB74TUGE.js";
6
6
  export {
7
7
  startStandaloneServer
8
8
  };
@@ -7,6 +7,7 @@ function annotaskLoader(source) {
7
7
  const options = this.getOptions?.() || {};
8
8
  const filePath = this.resourcePath;
9
9
  const projectRoot = options.projectRoot || process.cwd();
10
+ const mfe = options.mfe;
10
11
  if (filePath.endsWith("/main.ts") || filePath.endsWith("/main.js") || filePath.endsWith("/main.tsx") || filePath.endsWith("/main.jsx")) {
11
12
  if (source.includes("from 'vue'") || source.includes('from "vue"')) {
12
13
  return source + `
@@ -29,7 +30,7 @@ window.__ANNOTASK_SVELTE__ = { mount: __uf_mount, unmount: __uf_unmount };
29
30
  }
30
31
  }
31
32
  if (!filePath.endsWith(".vue") && !filePath.endsWith(".svelte") && !/\.[jt]sx$/.test(filePath)) return source;
32
- const result = transformFile(source, filePath, projectRoot);
33
+ const result = transformFile(source, filePath, projectRoot, mfe);
33
34
  if (!result) return source;
34
35
  let output = result;
35
36
  const importRegex = /import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/webpack/loader.ts"],"sourcesContent":["/**\n * Webpack loader for Annotask source file transform.\n * Injects data-annotask-* attributes into Vue, React, and Svelte templates.\n * Must run BEFORE framework-specific loaders (enforce: 'pre').\n */\nimport { transformFile } from '../plugin/transform.js'\n\nexport default function annotaskLoader(this: any, source: string): string {\n const options = this.getOptions?.() || {}\n const filePath = this.resourcePath\n const projectRoot = options.projectRoot || process.cwd()\n\n // Expose framework runtime on main entry files\n if (filePath.endsWith('/main.ts') || filePath.endsWith('/main.js') || filePath.endsWith('/main.tsx') || filePath.endsWith('/main.jsx')) {\n if (source.includes(\"from 'vue'\") || source.includes('from \"vue\"')) {\n return source + `\\n;import { createApp as __uf_createApp, h as __uf_h } from 'vue';\\nwindow.__ANNOTASK_VUE__ = { createApp: __uf_createApp, h: __uf_h };\\n`\n }\n if (source.includes(\"from 'react'\") || source.includes('from \"react\"')) {\n return source + `\\n;import { createElement as __uf_createElement } from 'react';\\nimport { createRoot as __uf_createRoot } from 'react-dom/client';\\nwindow.__ANNOTASK_REACT__ = { createElement: __uf_createElement, createRoot: __uf_createRoot };\\n`\n }\n if (source.includes(\"from 'svelte'\") || source.includes('from \"svelte\"')) {\n return source + `\\n;import { mount as __uf_mount, unmount as __uf_unmount } from 'svelte';\\nwindow.__ANNOTASK_SVELTE__ = { mount: __uf_mount, unmount: __uf_unmount };\\n`\n }\n }\n\n // Transform source files\n if (!filePath.endsWith('.vue') && !filePath.endsWith('.svelte') && !/\\.[jt]sx$/.test(filePath)) return source\n\n const result = transformFile(source, filePath, projectRoot)\n if (!result) return source\n\n // Register imported PascalCase components globally\n let output = result\n const importRegex = /import\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]/g\n let match\n const registrations: string[] = []\n while ((match = importRegex.exec(result)) !== null) {\n const [, name, src] = match\n if (name[0] === name[0].toUpperCase() && name[0] !== name[0].toLowerCase() && !src.startsWith('.')) {\n registrations.push(`window.__ANNOTASK_COMPONENTS__['${name}'] = ${name}`)\n }\n }\n if (registrations.length > 0) {\n const regCode = `\\nif (typeof window !== 'undefined') { window.__ANNOTASK_COMPONENTS__ = window.__ANNOTASK_COMPONENTS__ || {}; ${registrations.join('; ')} }\\n`\n if (filePath.endsWith('.vue') && output.includes('</script>')) {\n output = output.replace(/<\\/script>/, regCode + '</script>')\n } else {\n output += regCode\n }\n }\n\n return output\n}\n"],"mappings":";;;;;AAOe,SAAR,eAA2C,QAAwB;AACxE,QAAM,UAAU,KAAK,aAAa,KAAK,CAAC;AACxC,QAAM,WAAW,KAAK;AACtB,QAAM,cAAc,QAAQ,eAAe,QAAQ,IAAI;AAGvD,MAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,KAAK,SAAS,SAAS,WAAW,GAAG;AACtI,QAAI,OAAO,SAAS,YAAY,KAAK,OAAO,SAAS,YAAY,GAAG;AAClE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA,IAClB;AACA,QAAI,OAAO,SAAS,cAAc,KAAK,OAAO,SAAS,cAAc,GAAG;AACtE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAClB;AACA,QAAI,OAAO,SAAS,eAAe,KAAK,OAAO,SAAS,eAAe,GAAG;AACxE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA,IAClB;AAAA,EACF;AAGA,MAAI,CAAC,SAAS,SAAS,MAAM,KAAK,CAAC,SAAS,SAAS,SAAS,KAAK,CAAC,YAAY,KAAK,QAAQ,EAAG,QAAO;AAEvG,QAAM,SAAS,cAAc,QAAQ,UAAU,WAAW;AAC1D,MAAI,CAAC,OAAQ,QAAO;AAGpB,MAAI,SAAS;AACb,QAAM,cAAc;AACpB,MAAI;AACJ,QAAM,gBAA0B,CAAC;AACjC,UAAQ,QAAQ,YAAY,KAAK,MAAM,OAAO,MAAM;AAClD,UAAM,CAAC,EAAE,MAAM,GAAG,IAAI;AACtB,QAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,YAAY,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,YAAY,KAAK,CAAC,IAAI,WAAW,GAAG,GAAG;AAClG,oBAAc,KAAK,mCAAmC,IAAI,QAAQ,IAAI,EAAE;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,UAAU;AAAA,8GAAiH,cAAc,KAAK,IAAI,CAAC;AAAA;AACzJ,QAAI,SAAS,SAAS,MAAM,KAAK,OAAO,SAAS,WAAW,GAAG;AAC7D,eAAS,OAAO,QAAQ,cAAc,UAAU,WAAW;AAAA,IAC7D,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/webpack/loader.ts"],"sourcesContent":["/**\n * Webpack loader for Annotask source file transform.\n * Injects data-annotask-* attributes into Vue, React, and Svelte templates.\n * Must run BEFORE framework-specific loaders (enforce: 'pre').\n */\nimport { transformFile } from '../plugin/transform.js'\n\nexport default function annotaskLoader(this: any, source: string): string {\n const options = this.getOptions?.() || {}\n const filePath = this.resourcePath\n const projectRoot = options.projectRoot || process.cwd()\n const mfe: string | undefined = options.mfe\n\n // Expose framework runtime on main entry files\n if (filePath.endsWith('/main.ts') || filePath.endsWith('/main.js') || filePath.endsWith('/main.tsx') || filePath.endsWith('/main.jsx')) {\n if (source.includes(\"from 'vue'\") || source.includes('from \"vue\"')) {\n return source + `\\n;import { createApp as __uf_createApp, h as __uf_h } from 'vue';\\nwindow.__ANNOTASK_VUE__ = { createApp: __uf_createApp, h: __uf_h };\\n`\n }\n if (source.includes(\"from 'react'\") || source.includes('from \"react\"')) {\n return source + `\\n;import { createElement as __uf_createElement } from 'react';\\nimport { createRoot as __uf_createRoot } from 'react-dom/client';\\nwindow.__ANNOTASK_REACT__ = { createElement: __uf_createElement, createRoot: __uf_createRoot };\\n`\n }\n if (source.includes(\"from 'svelte'\") || source.includes('from \"svelte\"')) {\n return source + `\\n;import { mount as __uf_mount, unmount as __uf_unmount } from 'svelte';\\nwindow.__ANNOTASK_SVELTE__ = { mount: __uf_mount, unmount: __uf_unmount };\\n`\n }\n }\n\n // Transform source files\n if (!filePath.endsWith('.vue') && !filePath.endsWith('.svelte') && !/\\.[jt]sx$/.test(filePath)) return source\n\n const result = transformFile(source, filePath, projectRoot, mfe)\n if (!result) return source\n\n // Register imported PascalCase components globally\n let output = result\n const importRegex = /import\\s+(\\w+)\\s+from\\s+['\"]([^'\"]+)['\"]/g\n let match\n const registrations: string[] = []\n while ((match = importRegex.exec(result)) !== null) {\n const [, name, src] = match\n if (name[0] === name[0].toUpperCase() && name[0] !== name[0].toLowerCase() && !src.startsWith('.')) {\n registrations.push(`window.__ANNOTASK_COMPONENTS__['${name}'] = ${name}`)\n }\n }\n if (registrations.length > 0) {\n const regCode = `\\nif (typeof window !== 'undefined') { window.__ANNOTASK_COMPONENTS__ = window.__ANNOTASK_COMPONENTS__ || {}; ${registrations.join('; ')} }\\n`\n if (filePath.endsWith('.vue') && output.includes('</script>')) {\n output = output.replace(/<\\/script>/, regCode + '</script>')\n } else {\n output += regCode\n }\n }\n\n return output\n}\n"],"mappings":";;;;;AAOe,SAAR,eAA2C,QAAwB;AACxE,QAAM,UAAU,KAAK,aAAa,KAAK,CAAC;AACxC,QAAM,WAAW,KAAK;AACtB,QAAM,cAAc,QAAQ,eAAe,QAAQ,IAAI;AACvD,QAAM,MAA0B,QAAQ;AAGxC,MAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,KAAK,SAAS,SAAS,WAAW,GAAG;AACtI,QAAI,OAAO,SAAS,YAAY,KAAK,OAAO,SAAS,YAAY,GAAG;AAClE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA,IAClB;AACA,QAAI,OAAO,SAAS,cAAc,KAAK,OAAO,SAAS,cAAc,GAAG;AACtE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAClB;AACA,QAAI,OAAO,SAAS,eAAe,KAAK,OAAO,SAAS,eAAe,GAAG;AACxE,aAAO,SAAS;AAAA;AAAA;AAAA;AAAA,IAClB;AAAA,EACF;AAGA,MAAI,CAAC,SAAS,SAAS,MAAM,KAAK,CAAC,SAAS,SAAS,SAAS,KAAK,CAAC,YAAY,KAAK,QAAQ,EAAG,QAAO;AAEvG,QAAM,SAAS,cAAc,QAAQ,UAAU,aAAa,GAAG;AAC/D,MAAI,CAAC,OAAQ,QAAO;AAGpB,MAAI,SAAS;AACb,QAAM,cAAc;AACpB,MAAI;AACJ,QAAM,gBAA0B,CAAC;AACjC,UAAQ,QAAQ,YAAY,KAAK,MAAM,OAAO,MAAM;AAClD,UAAM,CAAC,EAAE,MAAM,GAAG,IAAI;AACtB,QAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,YAAY,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,YAAY,KAAK,CAAC,IAAI,WAAW,GAAG,GAAG;AAClG,oBAAc,KAAK,mCAAmC,IAAI,QAAQ,IAAI,EAAE;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,UAAU;AAAA,8GAAiH,cAAc,KAAK,IAAI,CAAC;AAAA;AACzJ,QAAI,SAAS,SAAS,MAAM,KAAK,OAAO,SAAS,WAAW,GAAG;AAC7D,eAAS,OAAO,QAAQ,cAAc,UAAU,WAAW;AAAA,IAC7D,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
package/dist/webpack.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  interface AnnotaskWebpackOptions {
2
2
  port?: number;
3
+ mfe?: string;
4
+ server?: string;
3
5
  }
4
6
  declare class AnnotaskWebpackPlugin {
5
7
  private options;
package/dist/webpack.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  bridgeClientScript
3
- } from "./chunk-X72ZX6VB.js";
3
+ } from "./chunk-YZ7UIZNB.js";
4
4
  import {
5
5
  startStandaloneServer
6
- } from "./chunk-JPNMDGZN.js";
7
- import "./chunk-XLNGAH3S.js";
8
- import "./chunk-JLOSPIJ4.js";
6
+ } from "./chunk-4IZECCVO.js";
7
+ import {
8
+ writeMfeServerInfo
9
+ } from "./chunk-XLNGAH3S.js";
10
+ import "./chunk-KB74TUGE.js";
9
11
 
10
12
  // src/webpack/plugin.ts
11
13
  import path from "path";
@@ -27,21 +29,32 @@ var AnnotaskWebpackPlugin = class {
27
29
  exclude: /node_modules/,
28
30
  use: [{
29
31
  loader: loaderPath,
30
- options: { projectRoot }
32
+ options: { projectRoot, mfe: this.options.mfe }
31
33
  }]
32
34
  });
33
35
  let serverStarted = false;
34
36
  compiler.hooks.beforeCompile.tapPromise("AnnotaskWebpackPlugin", async () => {
35
37
  if (serverStarted) return;
36
38
  serverStarted = true;
37
- try {
38
- const { port } = await startStandaloneServer({ projectRoot, port: this.options.port });
39
- this.serverUrl = `http://localhost:${port}`;
40
- console.log(`[Annotask] Server running at ${this.serverUrl}/__annotask/`);
41
- } catch (err) {
42
- console.error("[Annotask] Failed to start server:", err);
39
+ if (this.options.server) {
40
+ if (this.options.mfe) {
41
+ writeMfeServerInfo(projectRoot, this.options.server, this.options.mfe);
42
+ console.log(`[Annotask] MFE '${this.options.mfe}' \u2014 using remote server at ${this.options.server}/__annotask/`);
43
+ } else {
44
+ console.log(`[Annotask] Using remote server at ${this.options.server}/__annotask/`);
45
+ }
46
+ this.serverUrl = this.options.server;
47
+ } else {
48
+ try {
49
+ const { port } = await startStandaloneServer({ projectRoot, port: this.options.port });
50
+ this.serverUrl = `http://localhost:${port}`;
51
+ console.log(`[Annotask] Server running at ${this.serverUrl}/__annotask/`);
52
+ } catch (err) {
53
+ console.error("[Annotask] Failed to start server:", err);
54
+ }
43
55
  }
44
56
  });
57
+ if (this.options.server) return;
45
58
  compiler.hooks.compilation.tap("AnnotaskWebpackPlugin", (compilation) => {
46
59
  const htmlPluginConstructor = compiler.options.plugins?.map((p) => p.constructor).find((c) => c && typeof c.getHooks === "function");
47
60
  if (!htmlPluginConstructor) return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/webpack/plugin.ts"],"sourcesContent":["/**\n * Webpack plugin for Annotask.\n * Starts a standalone server, adds the SFC transform loader,\n * and injects bridge + toggle scripts into HTML.\n */\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { startStandaloneServer } from '../server/standalone.js'\nimport { bridgeClientScript } from '../plugin/bridge-client.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nexport interface AnnotaskWebpackOptions {\n port?: number\n}\n\nexport class AnnotaskWebpackPlugin {\n private options: AnnotaskWebpackOptions\n private serverUrl: string = ''\n\n constructor(options: AnnotaskWebpackOptions = {}) {\n this.options = options\n }\n\n apply(compiler: any) {\n // Only activate in development\n if (compiler.options.mode !== 'development') return\n\n const projectRoot = compiler.context\n const loaderPath = path.resolve(__dirname, 'webpack-loader.js')\n\n // Add the SFC transform loader (enforce: pre, before vue-loader)\n compiler.options.module.rules.unshift({\n test: /\\.(vue|svelte|[jt]sx?|ts|js)$/,\n enforce: 'pre',\n exclude: /node_modules/,\n use: [{\n loader: loaderPath,\n options: { projectRoot },\n }],\n })\n\n // Start standalone server\n let serverStarted = false\n compiler.hooks.beforeCompile.tapPromise('AnnotaskWebpackPlugin', async () => {\n if (serverStarted) return\n serverStarted = true\n try {\n const { port } = await startStandaloneServer({ projectRoot, port: this.options.port })\n this.serverUrl = `http://localhost:${port}`\n console.log(`[Annotask] Server running at ${this.serverUrl}/__annotask/`)\n } catch (err) {\n console.error('[Annotask] Failed to start server:', err)\n }\n })\n\n // Inject scripts into HTML (works with html-webpack-plugin)\n compiler.hooks.compilation.tap('AnnotaskWebpackPlugin', (compilation: any) => {\n // Find HtmlWebpackPlugin from registered plugins\n const htmlPluginConstructor = compiler.options.plugins\n ?.map((p: any) => p.constructor)\n .find((c: any) => c && typeof c.getHooks === 'function')\n\n if (!htmlPluginConstructor) return\n\n const hooks = htmlPluginConstructor.getHooks(compilation)\n hooks.beforeEmit.tapAsync('AnnotaskWebpackPlugin', (data: any, cb: any) => {\n const scripts = `\\n<script>${bridgeClientScript()}</script>`\n data.html = data.html.replace('</body>', scripts + '\\n</body>')\n cb(null, data)\n })\n })\n }\n}\n"],"mappings":";;;;;;;;;;AAKA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAI9B,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAMtD,IAAM,wBAAN,MAA4B;AAAA,EACzB;AAAA,EACA,YAAoB;AAAA,EAE5B,YAAY,UAAkC,CAAC,GAAG;AAChD,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,UAAe;AAEnB,QAAI,SAAS,QAAQ,SAAS,cAAe;AAE7C,UAAM,cAAc,SAAS;AAC7B,UAAM,aAAa,KAAK,QAAQ,WAAW,mBAAmB;AAG9D,aAAS,QAAQ,OAAO,MAAM,QAAQ;AAAA,MACpC,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,KAAK,CAAC;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS,EAAE,YAAY;AAAA,MACzB,CAAC;AAAA,IACH,CAAC;AAGD,QAAI,gBAAgB;AACpB,aAAS,MAAM,cAAc,WAAW,yBAAyB,YAAY;AAC3E,UAAI,cAAe;AACnB,sBAAgB;AAChB,UAAI;AACF,cAAM,EAAE,KAAK,IAAI,MAAM,sBAAsB,EAAE,aAAa,MAAM,KAAK,QAAQ,KAAK,CAAC;AACrF,aAAK,YAAY,oBAAoB,IAAI;AACzC,gBAAQ,IAAI,gCAAgC,KAAK,SAAS,cAAc;AAAA,MAC1E,SAAS,KAAK;AACZ,gBAAQ,MAAM,sCAAsC,GAAG;AAAA,MACzD;AAAA,IACF,CAAC;AAGD,aAAS,MAAM,YAAY,IAAI,yBAAyB,CAAC,gBAAqB;AAE5E,YAAM,wBAAwB,SAAS,QAAQ,SAC3C,IAAI,CAAC,MAAW,EAAE,WAAW,EAC9B,KAAK,CAAC,MAAW,KAAK,OAAO,EAAE,aAAa,UAAU;AAEzD,UAAI,CAAC,sBAAuB;AAE5B,YAAM,QAAQ,sBAAsB,SAAS,WAAW;AACxD,YAAM,WAAW,SAAS,yBAAyB,CAAC,MAAW,OAAY;AACzE,cAAM,UAAU;AAAA,UAAa,mBAAmB,CAAC;AACjD,aAAK,OAAO,KAAK,KAAK,QAAQ,WAAW,UAAU,WAAW;AAC9D,WAAG,MAAM,IAAI;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/webpack/plugin.ts"],"sourcesContent":["/**\n * Webpack plugin for Annotask.\n * Starts a standalone server, adds the SFC transform loader,\n * and injects bridge + toggle scripts into HTML.\n */\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { startStandaloneServer } from '../server/standalone.js'\nimport { writeMfeServerInfo } from '../server/discovery.js'\nimport { bridgeClientScript } from '../plugin/bridge-client.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nexport interface AnnotaskWebpackOptions {\n port?: number\n mfe?: string\n server?: string\n}\n\nexport class AnnotaskWebpackPlugin {\n private options: AnnotaskWebpackOptions\n private serverUrl: string = ''\n\n constructor(options: AnnotaskWebpackOptions = {}) {\n this.options = options\n }\n\n apply(compiler: any) {\n // Only activate in development\n if (compiler.options.mode !== 'development') return\n\n const projectRoot = compiler.context\n const loaderPath = path.resolve(__dirname, 'webpack-loader.js')\n\n // Add the SFC transform loader (enforce: pre, before vue-loader)\n compiler.options.module.rules.unshift({\n test: /\\.(vue|svelte|[jt]sx?|ts|js)$/,\n enforce: 'pre',\n exclude: /node_modules/,\n use: [{\n loader: loaderPath,\n options: { projectRoot, mfe: this.options.mfe },\n }],\n })\n\n // Start standalone server, or point to remote server when server option is set\n let serverStarted = false\n compiler.hooks.beforeCompile.tapPromise('AnnotaskWebpackPlugin', async () => {\n if (serverStarted) return\n serverStarted = true\n if (this.options.server) {\n // Skip local server, point to remote server (root shell)\n if (this.options.mfe) {\n writeMfeServerInfo(projectRoot, this.options.server, this.options.mfe)\n console.log(`[Annotask] MFE '${this.options.mfe}' — using remote server at ${this.options.server}/__annotask/`)\n } else {\n console.log(`[Annotask] Using remote server at ${this.options.server}/__annotask/`)\n }\n this.serverUrl = this.options.server\n } else {\n try {\n const { port } = await startStandaloneServer({ projectRoot, port: this.options.port })\n this.serverUrl = `http://localhost:${port}`\n console.log(`[Annotask] Server running at ${this.serverUrl}/__annotask/`)\n } catch (err) {\n console.error('[Annotask] Failed to start server:', err)\n }\n }\n })\n\n // Inject scripts into HTML (works with html-webpack-plugin)\n // Skip injection when server option is set — the root shell handles bridge/toggle\n if (this.options.server) return\n\n compiler.hooks.compilation.tap('AnnotaskWebpackPlugin', (compilation: any) => {\n // Find HtmlWebpackPlugin from registered plugins\n const htmlPluginConstructor = compiler.options.plugins\n ?.map((p: any) => p.constructor)\n .find((c: any) => c && typeof c.getHooks === 'function')\n\n if (!htmlPluginConstructor) return\n\n const hooks = htmlPluginConstructor.getHooks(compilation)\n hooks.beforeEmit.tapAsync('AnnotaskWebpackPlugin', (data: any, cb: any) => {\n const scripts = `\\n<script>${bridgeClientScript()}</script>`\n data.html = data.html.replace('</body>', scripts + '\\n</body>')\n cb(null, data)\n })\n })\n }\n}\n"],"mappings":";;;;;;;;;;;;AAKA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAK9B,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAQtD,IAAM,wBAAN,MAA4B;AAAA,EACzB;AAAA,EACA,YAAoB;AAAA,EAE5B,YAAY,UAAkC,CAAC,GAAG;AAChD,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,UAAe;AAEnB,QAAI,SAAS,QAAQ,SAAS,cAAe;AAE7C,UAAM,cAAc,SAAS;AAC7B,UAAM,aAAa,KAAK,QAAQ,WAAW,mBAAmB;AAG9D,aAAS,QAAQ,OAAO,MAAM,QAAQ;AAAA,MACpC,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,KAAK,CAAC;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS,EAAE,aAAa,KAAK,KAAK,QAAQ,IAAI;AAAA,MAChD,CAAC;AAAA,IACH,CAAC;AAGD,QAAI,gBAAgB;AACpB,aAAS,MAAM,cAAc,WAAW,yBAAyB,YAAY;AAC3E,UAAI,cAAe;AACnB,sBAAgB;AAChB,UAAI,KAAK,QAAQ,QAAQ;AAEvB,YAAI,KAAK,QAAQ,KAAK;AACpB,6BAAmB,aAAa,KAAK,QAAQ,QAAQ,KAAK,QAAQ,GAAG;AACrE,kBAAQ,IAAI,mBAAmB,KAAK,QAAQ,GAAG,mCAA8B,KAAK,QAAQ,MAAM,cAAc;AAAA,QAChH,OAAO;AACL,kBAAQ,IAAI,qCAAqC,KAAK,QAAQ,MAAM,cAAc;AAAA,QACpF;AACA,aAAK,YAAY,KAAK,QAAQ;AAAA,MAChC,OAAO;AACL,YAAI;AACF,gBAAM,EAAE,KAAK,IAAI,MAAM,sBAAsB,EAAE,aAAa,MAAM,KAAK,QAAQ,KAAK,CAAC;AACrF,eAAK,YAAY,oBAAoB,IAAI;AACzC,kBAAQ,IAAI,gCAAgC,KAAK,SAAS,cAAc;AAAA,QAC1E,SAAS,KAAK;AACZ,kBAAQ,MAAM,sCAAsC,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC;AAID,QAAI,KAAK,QAAQ,OAAQ;AAEzB,aAAS,MAAM,YAAY,IAAI,yBAAyB,CAAC,gBAAqB;AAE5E,YAAM,wBAAwB,SAAS,QAAQ,SAC3C,IAAI,CAAC,MAAW,EAAE,WAAW,EAC9B,KAAK,CAAC,MAAW,KAAK,OAAO,EAAE,aAAa,UAAU;AAEzD,UAAI,CAAC,sBAAuB;AAE5B,YAAM,QAAQ,sBAAsB,SAAS,WAAW;AACxD,YAAM,WAAW,SAAS,yBAAyB,CAAC,MAAW,OAAY;AACzE,cAAM,UAAU;AAAA,UAAa,mBAAmB,CAAC;AACjD,aAAK,OAAO,KAAK,KAAK,QAAQ,WAAW,UAAU,WAAW;AAC9D,WAAG,MAAM,IAAI;AAAA,MACf,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "annotask",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/api.ts","../src/server/ws-server.ts","../src/server/serve-shell.ts","../src/server/state.ts","../src/server/index.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\n\nexport interface APIOptions {\n getReport: () => unknown\n getConfig: () => unknown\n getDesignSpec: () => unknown\n getTasks: () => { version: string; tasks: any[] }\n updateTask: (id: string, updates: Record<string, unknown>) => unknown\n addTask: (task: Record<string, unknown>) => unknown\n}\n\nconst MAX_BODY_SIZE = 1_048_576\nconst VALID_TASK_STATUSES = new Set(['pending', 'applied', 'review', 'accepted', 'denied'])\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = ''\n let size = 0\n req.on('data', (chunk: Buffer) => {\n size += chunk.length\n if (size > MAX_BODY_SIZE) { req.destroy(); reject(new Error('Request body too large')); return }\n body += chunk.toString()\n })\n req.on('end', () => resolve(body))\n req.on('error', reject)\n })\n}\n\nfunction parseJSON(raw: string): { ok: true; data: unknown } | { ok: false } {\n try { return { ok: true, data: JSON.parse(raw) } } catch { return { ok: false } }\n}\n\nfunction sendError(res: ServerResponse, status: number, message: string) {\n res.statusCode = status\n res.end(JSON.stringify({ error: message }))\n}\n\nexport function createAPIMiddleware(options: APIOptions) {\n return async (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n if (!req.url?.startsWith('/__annotask/api/')) return next()\n\n const path = req.url.replace('/__annotask/api/', '')\n\n res.setHeader('Content-Type', 'application/json')\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n res.setHeader('Cache-Control', 'no-cache')\n\n if (req.method === 'OPTIONS') { res.statusCode = 200; res.end(); return }\n\n if (path === 'report' && req.method === 'GET') {\n res.end(JSON.stringify(options.getReport() ?? { version: '1.0', changes: [] }, null, 2))\n return\n }\n\n if (path === 'config' && req.method === 'GET') {\n res.end(JSON.stringify(options.getConfig(), null, 2))\n return\n }\n\n if (path === 'design-spec' && req.method === 'GET') {\n res.end(JSON.stringify(options.getDesignSpec(), null, 2))\n return\n }\n\n if (path.startsWith('tasks') && !path.startsWith('tasks/') && req.method === 'GET') {\n const urlObj = new URL(req.url!, `http://${req.headers.host || 'localhost'}`)\n const mfeFilter = urlObj.searchParams.get('mfe')\n const taskData = options.getTasks()\n if (mfeFilter) {\n const filtered = { ...taskData, tasks: taskData.tasks.filter((t: any) => t.mfe === mfeFilter) }\n res.end(JSON.stringify(filtered, null, 2))\n } else {\n res.end(JSON.stringify(taskData, null, 2))\n }\n return\n }\n\n if (path === 'tasks' && req.method === 'POST') {\n let raw: string\n try { raw = await readBody(req) } catch { return sendError(res, 413, 'Request body too large') }\n const parsed = parseJSON(raw)\n if (!parsed.ok) return sendError(res, 400, 'Invalid JSON body')\n const body = parsed.data as Record<string, unknown>\n if (!body || typeof body !== 'object' || Array.isArray(body)) return sendError(res, 400, 'Request body must be a JSON object')\n if (typeof body.type !== 'string' || !body.type) return sendError(res, 400, 'Missing required field: type (string)')\n if (typeof body.description !== 'string') return sendError(res, 400, 'Missing required field: description (string)')\n res.end(JSON.stringify(options.addTask(body), null, 2))\n return\n }\n\n if (path.startsWith('tasks/') && req.method === 'PATCH') {\n const id = path.replace('tasks/', '')\n let raw: string\n try { raw = await readBody(req) } catch { return sendError(res, 413, 'Request body too large') }\n const parsed = parseJSON(raw)\n if (!parsed.ok) return sendError(res, 400, 'Invalid JSON body')\n const body = parsed.data as Record<string, unknown>\n if (!body || typeof body !== 'object' || Array.isArray(body)) return sendError(res, 400, 'Request body must be a JSON object')\n if (body.status !== undefined && !VALID_TASK_STATUSES.has(body.status as string)) {\n return sendError(res, 400, `Invalid status. Must be one of: ${[...VALID_TASK_STATUSES].join(', ')}`)\n }\n res.end(JSON.stringify(options.updateTask(id, body), null, 2))\n return\n }\n\n if (path === 'status' && req.method === 'GET') {\n res.end(JSON.stringify({ status: 'ok', tool: 'annotask' }))\n return\n }\n\n res.statusCode = 404\n res.end(JSON.stringify({ error: 'Not found' }))\n }\n}\n","import { WebSocketServer, WebSocket } from 'ws'\nimport type { IncomingMessage } from 'node:http'\nimport type { Duplex } from 'node:stream'\n\nexport interface AnnotaskWSServer {\n handleUpgrade: (req: IncomingMessage, socket: Duplex, head: Buffer) => void\n broadcast: (event: string, data: unknown) => void\n getReport: () => unknown\n clients: Set<WebSocket>\n}\n\nexport function createWSServer(): AnnotaskWSServer {\n let currentReport: unknown = null\n const clients = new Set<WebSocket>()\n const wss = new WebSocketServer({ noServer: true })\n\n wss.on('connection', (ws) => {\n clients.add(ws)\n if (currentReport) {\n ws.send(JSON.stringify({ event: 'report:current', data: currentReport, timestamp: Date.now() }))\n }\n\n ws.on('message', (raw) => {\n try {\n const msg = JSON.parse(raw.toString())\n if (msg.event === 'report:updated') {\n currentReport = msg.data\n for (const client of clients) {\n if (client !== ws && client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify({ event: 'report:updated', data: msg.data, timestamp: Date.now() }))\n }\n }\n }\n if (msg.event === 'changes:cleared') {\n currentReport = null\n for (const client of clients) {\n if (client !== ws && client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify({ event: 'changes:cleared', data: null, timestamp: Date.now() }))\n }\n }\n }\n if (msg.event === 'get:report') {\n ws.send(JSON.stringify({ event: 'report:current', data: currentReport, timestamp: Date.now() }))\n }\n } catch {}\n })\n\n ws.on('close', () => { clients.delete(ws) })\n })\n\n return {\n handleUpgrade(req, socket, head) {\n wss.handleUpgrade(req, socket, head, (ws) => { wss.emit('connection', ws, req) })\n },\n broadcast(event, data) {\n const msg = JSON.stringify({ event, data, timestamp: Date.now() })\n for (const client of clients) {\n if (client.readyState === WebSocket.OPEN) client.send(msg)\n }\n },\n getReport() { return currentReport },\n clients,\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nfunction findShellDist(): string {\n return path.resolve(__dirname, 'shell')\n}\n\nexport function createShellMiddleware() {\n const shellDist = findShellDist()\n\n return (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n if (!req.url?.startsWith('/__annotask')) return next()\n\n // CORS for cross-port access (Webpack standalone server)\n res.setHeader('Access-Control-Allow-Origin', '*')\n\n let filePath = req.url.replace('/__annotask', '') || '/'\n const queryIndex = filePath.indexOf('?')\n if (queryIndex !== -1) filePath = filePath.slice(0, queryIndex)\n if (filePath === '/' || filePath === '') filePath = '/index.html'\n\n // Skip API and WS paths\n if (filePath.startsWith('/api/') || filePath === '/ws') return next()\n\n const fullPath = path.join(shellDist, filePath)\n\n if (!fullPath.startsWith(shellDist)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {\n const indexPath = path.join(shellDist, 'index.html')\n if (fs.existsSync(indexPath)) {\n res.setHeader('Content-Type', 'text/html')\n res.end(fs.readFileSync(indexPath, 'utf-8'))\n return\n }\n res.statusCode = 404\n res.end('Annotask shell not built. Run: pnpm build:shell')\n return\n }\n\n const ext = path.extname(fullPath)\n const contentTypes: Record<string, string> = {\n '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css',\n '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.ico': 'image/x-icon',\n }\n res.setHeader('Content-Type', contentTypes[ext] || 'application/octet-stream')\n res.end(fs.readFileSync(fullPath))\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nconst DEFAULT_DESIGN_SPEC = {\n initialized: false,\n version: '1.0' as const,\n framework: null,\n colors: [],\n typography: { families: [], scale: [], weights: [] },\n spacing: [],\n borders: { radius: [] },\n icons: null,\n components: null,\n}\n\nexport interface ProjectState {\n getDesignSpec: () => unknown\n getConfig: () => unknown\n getTasks: () => { version: string; tasks: any[] }\n addTask: (task: Record<string, unknown>) => unknown\n updateTask: (id: string, updates: Record<string, unknown>) => unknown\n dispose: () => void\n}\n\nexport function createProjectState(projectRoot: string, broadcast: (event: string, data: unknown) => void): ProjectState {\n let cachedDesignSpec: unknown = null\n let specWatcher: fs.FSWatcher | null = null\n const tasksPath = path.join(projectRoot, '.annotask', 'tasks.json')\n\n function getDesignSpec(): unknown {\n if (cachedDesignSpec !== null) return cachedDesignSpec\n const specPath = path.join(projectRoot, '.annotask', 'design-spec.json')\n try {\n cachedDesignSpec = { initialized: true, ...JSON.parse(fs.readFileSync(specPath, 'utf-8')) }\n } catch {\n cachedDesignSpec = DEFAULT_DESIGN_SPEC\n }\n if (!specWatcher) {\n const configDir = path.join(projectRoot, '.annotask')\n try {\n if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true })\n specWatcher = fs.watch(configDir, (_, filename) => {\n cachedDesignSpec = null\n if (filename === 'design-spec.json') broadcast('designspec:updated', null)\n })\n } catch { cachedDesignSpec = null }\n }\n return cachedDesignSpec ?? DEFAULT_DESIGN_SPEC\n }\n\n function getConfig(): unknown {\n const spec = getDesignSpec() as any\n return { initialized: !!spec?.initialized, ...spec }\n }\n\n function readTasks(): { version: string; tasks: any[] } {\n try { return JSON.parse(fs.readFileSync(tasksPath, 'utf-8')) } catch { return { version: '1.0', tasks: [] } }\n }\n\n function writeTasks(data: { version: string; tasks: any[] }) {\n const dir = path.dirname(tasksPath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(tasksPath, JSON.stringify(data, null, 2))\n }\n\n function addTask(task: Record<string, unknown>) {\n const data = readTasks()\n const id = `task-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`\n const newTask = { id, status: 'pending', createdAt: Date.now(), updatedAt: Date.now(), ...task }\n data.tasks.push(newTask)\n writeTasks(data)\n broadcast('tasks:updated', data)\n return newTask\n }\n\n function updateTask(id: string, updates: Record<string, unknown>) {\n const data = readTasks()\n const task = data.tasks.find((t: any) => t.id === id)\n if (!task) return { error: 'Task not found' }\n Object.assign(task, updates, { updatedAt: Date.now() })\n if (updates.status === 'accepted') data.tasks = data.tasks.filter((t: any) => t.id !== id)\n writeTasks(data)\n broadcast('tasks:updated', data)\n return task\n }\n\n function dispose() {\n if (specWatcher) { specWatcher.close(); specWatcher = null }\n }\n\n return { getDesignSpec, getConfig, getTasks: readTasks, addTask, updateTask, dispose }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport { createAPIMiddleware } from './api.js'\nimport { createWSServer, type AnnotaskWSServer } from './ws-server.js'\nimport { createShellMiddleware } from './serve-shell.js'\nimport { createProjectState, type ProjectState } from './state.js'\n\nexport interface AnnotaskServer {\n middleware: (req: IncomingMessage, res: ServerResponse, next: () => void) => void\n handleUpgrade: (req: IncomingMessage, socket: Duplex, head: Buffer) => void\n broadcast: (event: string, data: unknown) => void\n getReport: () => unknown\n dispose: () => void\n}\n\nexport interface AnnotaskServerOptions {\n projectRoot: string\n}\n\nexport function createAnnotaskServer(options: AnnotaskServerOptions): AnnotaskServer {\n const wsServer = createWSServer()\n const state = createProjectState(options.projectRoot, wsServer.broadcast)\n\n const apiMiddleware = createAPIMiddleware({\n getReport: () => wsServer.getReport(),\n getConfig: () => state.getConfig(),\n getDesignSpec: () => state.getDesignSpec(),\n getTasks: () => state.getTasks(),\n addTask: (task) => state.addTask(task),\n updateTask: (id, updates) => state.updateTask(id, updates),\n })\n\n const shellMiddleware = createShellMiddleware()\n\n const middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n // API first, then shell (shell is SPA fallback)\n apiMiddleware(req, res, () => {\n shellMiddleware(req, res, next)\n })\n }\n\n return {\n middleware,\n handleUpgrade: (req, socket, head) => wsServer.handleUpgrade(req, socket, head),\n broadcast: (event, data) => wsServer.broadcast(event, data),\n getReport: () => wsServer.getReport(),\n dispose: () => state.dispose(),\n }\n}\n\nexport { createProjectState, type ProjectState } from './state.js'\nexport { createWSServer, type AnnotaskWSServer } from './ws-server.js'\nexport { createAPIMiddleware, type APIOptions } from './api.js'\nexport { createShellMiddleware } from './serve-shell.js'\n"],"mappings":"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","names":["path","fs","path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/plugin/bridge-client.ts"],"sourcesContent":["/**\n * Client bridge script injected into the user's app.\n * Communicates with the Annotask shell via postMessage.\n * Handles all DOM interactions: hover, click, style reads/writes,\n * element resolution, layout scanning, etc.\n *\n * Returned as an inline string (same pattern as toggle-button.ts).\n */\nexport function bridgeClientScript(): string {\n return `\n(function() {\n // Don't run inside the Annotask shell\n if (window.location.pathname.startsWith('/__annotask')) return;\n // Don't run if already initialized\n if (window.__ANNOTASK_BRIDGE__) return;\n window.__ANNOTASK_BRIDGE__ = true;\n\n // ── Element Registry ──────────────────────────────────\n var eidCounter = 0;\n var eidMap = new Map(); // eid string → WeakRef<Element>\n var elToEid = new WeakMap(); // Element → eid string\n\n function getEid(el) {\n if (!el) return null;\n var existing = elToEid.get(el);\n if (existing) return existing;\n eidCounter++;\n var eid = 'e-' + eidCounter;\n eidMap.set(eid, new WeakRef(el));\n elToEid.set(el, eid);\n return eid;\n }\n\n function getEl(eid) {\n var ref = eidMap.get(eid);\n return ref ? ref.deref() || null : null;\n }\n\n // ── PostMessage Helpers ───────────────────────────────\n var shellOrigin = '*'; // Will be tightened on first shell message\n\n function sendToShell(type, payload, id) {\n var msg = { type: type, payload: payload || {}, source: 'annotask-client' };\n if (id) msg.id = id;\n window.parent.postMessage(msg, shellOrigin);\n }\n\n function respond(id, payload) {\n sendToShell(null, payload, id);\n // type is not needed for responses — shell matches by id\n }\n\n // ── Source Element Resolution ─────────────────────────\n function hasSourceAttr(el) {\n return el.hasAttribute && (el.hasAttribute('data-annotask-file') || el.hasAttribute('data-astro-source-file'));\n }\n\n function findSourceElement(el) {\n var c = el;\n while (c) {\n if (hasSourceAttr(c)) return { sourceEl: c, targetEl: el };\n c = c.parentElement;\n }\n return { sourceEl: el, targetEl: el };\n }\n\n function getSourceData(el) {\n // Prefer data-annotask-* attributes, fall back to data-astro-source-* (Astro framework)\n var file = el.getAttribute('data-annotask-file') || '';\n var line = el.getAttribute('data-annotask-line') || '';\n var component = el.getAttribute('data-annotask-component') || '';\n\n if (!file && el.getAttribute('data-astro-source-file')) {\n var astroFile = el.getAttribute('data-astro-source-file') || '';\n // Convert absolute path to project-relative by finding src/ prefix\n var srcIdx = astroFile.indexOf('/src/');\n file = srcIdx !== -1 ? astroFile.slice(srcIdx + 1) : astroFile;\n }\n if ((!line || line === '0') && el.getAttribute('data-astro-source-loc')) {\n // data-astro-source-loc format: \"line:col\"\n line = (el.getAttribute('data-astro-source-loc') || '').split(':')[0];\n }\n if (!component && file) {\n // Derive component name from file path\n var parts = file.split('/');\n var fileName = parts[parts.length - 1] || '';\n component = fileName.replace(/\\.[^.]+$/, '');\n }\n\n var mfe = el.getAttribute('data-annotask-mfe') || '';\n\n return { file: file, line: line, component: component, mfe: mfe };\n }\n\n function getRect(el) {\n var r = el.getBoundingClientRect();\n return { x: r.x, y: r.y, width: r.width, height: r.height };\n }\n\n // ── Interaction Mode ──────────────────────────────────\n var storedMode = '';\n try { storedMode = localStorage.getItem('annotask:mode') || ''; } catch(e) {}\n var currentMode = storedMode || 'select';\n var inspectModes = { select: true, pin: true };\n\n // ── Event Handlers ────────────────────────────────────\n var lastHoverEid = null;\n var rafPending = false;\n var pendingHoverData = null;\n\n function onMouseOver(e) {\n if (!inspectModes[currentMode]) return;\n var el = e.target;\n if (!el || el === document.documentElement || el === document.body) return;\n var eid = getEid(el);\n if (eid === lastHoverEid) return;\n lastHoverEid = eid;\n\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n\n pendingHoverData = {\n eid: eid,\n tag: el.tagName.toLowerCase(),\n file: data.file,\n component: data.component,\n rect: getRect(el)\n };\n\n if (!rafPending) {\n rafPending = true;\n requestAnimationFrame(function() {\n rafPending = false;\n if (pendingHoverData) sendToShell('hover:enter', pendingHoverData);\n });\n }\n }\n\n function onMouseOut(e) {\n if (!inspectModes[currentMode]) return;\n // Only fire leave when truly leaving all elements\n if (e.relatedTarget && e.relatedTarget !== document.documentElement) return;\n lastHoverEid = null;\n pendingHoverData = null;\n sendToShell('hover:leave', {});\n }\n\n function onClick(e) {\n if (!inspectModes[currentMode]) return;\n e.preventDefault();\n e.stopPropagation();\n\n var el = e.target;\n if (!el) return;\n\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n var targetEl = source.targetEl;\n var classes = typeof targetEl.className === 'string' ? targetEl.className : '';\n\n sendToShell('click:element', {\n eid: getEid(targetEl),\n sourceEid: getEid(source.sourceEl),\n file: data.file,\n line: data.line,\n component: data.component,\n mfe: data.mfe,\n tag: targetEl.tagName.toLowerCase(),\n classes: classes,\n rect: getRect(targetEl),\n shiftKey: e.shiftKey,\n clientX: e.clientX,\n clientY: e.clientY\n });\n }\n\n function onMouseDown(e) {\n if (!inspectModes[currentMode]) return;\n e.stopPropagation();\n }\n\n function onMouseUp(e) {\n if (currentMode !== 'highlight') return;\n var sel = document.getSelection();\n var text = sel ? sel.toString().trim() : '';\n if (!text || text.length < 2) return;\n var anchorEl = sel.anchorNode ? sel.anchorNode.parentElement : null;\n if (!anchorEl) return;\n var source = findSourceElement(anchorEl);\n var data = getSourceData(source.sourceEl);\n\n sendToShell('selection:text', {\n text: text,\n eid: getEid(anchorEl),\n file: data.file,\n line: parseInt(data.line) || 0,\n component: data.component,\n mfe: data.mfe,\n tag: anchorEl.tagName.toLowerCase()\n });\n }\n\n function onContextMenu(e) {\n if (currentMode === 'interact') return;\n e.preventDefault();\n var el = e.target;\n if (!el) return;\n var source = findSourceElement(el);\n var data = getSourceData(source.sourceEl);\n var targetEl = source.targetEl;\n var classes = typeof targetEl.className === 'string' ? targetEl.className : '';\n\n sendToShell('contextmenu:element', {\n eid: getEid(targetEl),\n sourceEid: getEid(source.sourceEl),\n file: data.file,\n line: data.line,\n component: data.component,\n mfe: data.mfe,\n tag: targetEl.tagName.toLowerCase(),\n classes: classes,\n rect: getRect(targetEl),\n shiftKey: false,\n clientX: e.clientX,\n clientY: e.clientY\n });\n }\n\n function onKeyDown(e) {\n if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n sendToShell('keydown', { key: e.key, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });\n }\n }\n\n // Install event listeners\n document.addEventListener('mouseover', onMouseOver, { capture: true });\n document.addEventListener('mouseout', onMouseOut, { capture: true });\n document.addEventListener('mousedown', onMouseDown, { capture: true });\n document.addEventListener('click', onClick, { capture: true });\n document.addEventListener('mouseup', onMouseUp, { capture: true });\n document.addEventListener('keydown', onKeyDown, { capture: true });\n document.addEventListener('contextmenu', onContextMenu, { capture: true });\n\n // ── Route Tracking ────────────────────────────────────\n var lastRoute = window.location.pathname;\n\n function checkRoute() {\n var path = window.location.pathname;\n if (path !== lastRoute) {\n lastRoute = path;\n sendToShell('route:changed', { path: path });\n }\n }\n\n window.addEventListener('popstate', checkRoute);\n window.addEventListener('hashchange', checkRoute);\n setInterval(checkRoute, 2000); // safety net for pushState\n\n // ── Message Handler ───────────────────────────────────\n window.addEventListener('message', function(event) {\n var msg = event.data;\n if (!msg || msg.source !== 'annotask-shell') return;\n // Tighten origin on first shell message\n if (shellOrigin === '*' && event.origin) shellOrigin = event.origin;\n\n var type = msg.type;\n var payload = msg.payload || {};\n var id = msg.id;\n\n // ── Mode ──\n if (type === 'mode:set') {\n currentMode = payload.mode || 'select';\n try { localStorage.setItem('annotask:mode', currentMode); } catch(e) {}\n return;\n }\n\n // ── Ping ──\n if (type === 'bridge:ping') {\n respond(id, {});\n return;\n }\n\n // ── Element Resolution ──\n if (type === 'resolve:at-point') {\n var el = document.elementFromPoint(payload.x, payload.y);\n if (!el || el === document.documentElement || el === document.body) {\n respond(id, null);\n return;\n }\n var src = findSourceElement(el);\n var srcData = getSourceData(src.sourceEl);\n respond(id, {\n eid: getEid(src.targetEl),\n file: srcData.file,\n line: srcData.line,\n component: srcData.component,\n mfe: srcData.mfe,\n tag: src.sourceEl.tagName.toLowerCase(),\n rect: getRect(src.sourceEl),\n classes: typeof src.targetEl.className === 'string' ? src.targetEl.className : ''\n });\n return;\n }\n\n if (type === 'resolve:template-group') {\n var all = document.querySelectorAll(\n '[data-annotask-file=\"' + payload.file + '\"][data-annotask-line=\"' + payload.line + '\"]'\n );\n // Also check Astro source attributes\n if (all.length === 0 && payload.file && payload.line) {\n // Try matching by astro source attributes (absolute path ends with file, loc starts with line)\n var astroAll = document.querySelectorAll('[data-astro-source-file]');\n var matched = [];\n for (var ai = 0; ai < astroAll.length; ai++) {\n var af = astroAll[ai].getAttribute('data-astro-source-file') || '';\n var al = (astroAll[ai].getAttribute('data-astro-source-loc') || '').split(':')[0];\n if (af.endsWith('/' + payload.file) && al === payload.line) matched.push(astroAll[ai]);\n }\n if (matched.length > 0) all = matched;\n }\n var eids = [];\n var rects = [];\n for (var i = 0; i < all.length; i++) {\n if (all[i].tagName.toLowerCase() === payload.tagName) {\n eids.push(getEid(all[i]));\n rects.push(getRect(all[i]));\n }\n }\n respond(id, { eids: eids, rects: rects });\n return;\n }\n\n if (type === 'resolve:rect') {\n var rEl = getEl(payload.eid);\n respond(id, rEl ? { rect: getRect(rEl) } : null);\n return;\n }\n\n if (type === 'resolve:rects') {\n var results = [];\n for (var j = 0; j < payload.eids.length; j++) {\n var re = getEl(payload.eids[j]);\n results.push(re ? getRect(re) : null);\n }\n respond(id, { rects: results });\n return;\n }\n\n // ── Style Operations ──\n if (type === 'style:get-computed') {\n var sEl = getEl(payload.eid);\n if (!sEl) { respond(id, { styles: {} }); return; }\n var cs = window.getComputedStyle(sEl);\n var styles = {};\n for (var k = 0; k < payload.properties.length; k++) {\n styles[payload.properties[k]] = cs.getPropertyValue(payload.properties[k]);\n }\n respond(id, { styles: styles });\n return;\n }\n\n if (type === 'style:apply') {\n var aEl = getEl(payload.eid);\n if (!aEl) { respond(id, { before: '' }); return; }\n var before = window.getComputedStyle(aEl).getPropertyValue(payload.property);\n aEl.style.setProperty(payload.property, payload.value);\n respond(id, { before: before });\n return;\n }\n\n if (type === 'style:apply-batch') {\n var befores = [];\n for (var m = 0; m < payload.eids.length; m++) {\n var bEl = getEl(payload.eids[m]);\n if (bEl) {\n befores.push(window.getComputedStyle(bEl).getPropertyValue(payload.property));\n bEl.style.setProperty(payload.property, payload.value);\n } else {\n befores.push('');\n }\n }\n respond(id, { befores: befores });\n return;\n }\n\n if (type === 'style:undo') {\n var uEl = getEl(payload.eid);\n if (uEl) {\n if (payload.value) uEl.style.setProperty(payload.property, payload.value);\n else uEl.style.removeProperty(payload.property);\n }\n respond(id, {});\n return;\n }\n\n if (type === 'class:get') {\n var cEl = getEl(payload.eid);\n respond(id, { classes: cEl ? (typeof cEl.className === 'string' ? cEl.className : '') : '' });\n return;\n }\n\n if (type === 'class:set') {\n var csEl = getEl(payload.eid);\n if (!csEl) { respond(id, { before: '' }); return; }\n var classBefore = typeof csEl.className === 'string' ? csEl.className : '';\n csEl.className = payload.classes;\n respond(id, { before: classBefore });\n return;\n }\n\n if (type === 'class:set-batch') {\n var classBefores = [];\n for (var n = 0; n < payload.eids.length; n++) {\n var cbEl = getEl(payload.eids[n]);\n if (cbEl) {\n classBefores.push(typeof cbEl.className === 'string' ? cbEl.className : '');\n cbEl.className = payload.classes;\n } else {\n classBefores.push('');\n }\n }\n respond(id, { befores: classBefores });\n return;\n }\n\n if (type === 'class:undo') {\n var cuEl = getEl(payload.eid);\n if (cuEl) cuEl.className = payload.classes;\n respond(id, {});\n return;\n }\n\n // ── Classification ──\n if (type === 'classify:element') {\n var clEl = getEl(payload.eid);\n if (!clEl) { respond(id, null); return; }\n var tag = clEl.tagName.toLowerCase();\n var clCs = window.getComputedStyle(clEl);\n var display = clCs.display;\n var childCount = clEl.children.length;\n var isFlex = display.includes('flex');\n var isGrid = display.includes('grid');\n var semanticContainers = ['section','main','aside','nav','header','footer','article'];\n var role = 'content';\n if (clEl.hasAttribute('data-annotask-component')) {\n var comp = clEl.getAttribute('data-annotask-component') || '';\n if (comp && comp[0] === comp[0].toUpperCase() && comp[0] !== comp[0].toLowerCase()) {\n role = 'component';\n }\n }\n if (role !== 'component' && (isFlex || isGrid) && childCount > 0) role = 'container';\n if (role !== 'component' && role !== 'container' && semanticContainers.indexOf(tag) >= 0 && childCount > 0) role = 'container';\n\n respond(id, {\n role: role,\n display: display,\n isFlexContainer: isFlex,\n isGridContainer: isGrid,\n flexDirection: isFlex ? clCs.flexDirection : undefined,\n childCount: childCount,\n isComponentUnit: role === 'component'\n });\n return;\n }\n\n // ── Layout Scan ──\n if (type === 'layout:scan') {\n var layoutResults = [];\n var allEls = document.querySelectorAll('*');\n for (var li = 0; li < allEls.length; li++) {\n var lEl = allEls[li];\n if (lEl.nodeType !== 1) continue;\n var lCs = window.getComputedStyle(lEl);\n var lDisplay = lCs.display;\n if (!lDisplay.includes('flex') && !lDisplay.includes('grid')) continue;\n var lRect = lEl.getBoundingClientRect();\n if (lRect.width < 20 || lRect.height < 20) continue;\n var lIsGrid = lDisplay.includes('grid');\n var entry = {\n eid: getEid(lEl),\n display: lIsGrid ? 'grid' : 'flex',\n direction: lIsGrid ? 'grid' : lCs.flexDirection,\n rect: { x: lRect.x, y: lRect.y, width: lRect.width, height: lRect.height },\n columnGap: parseFloat(lCs.columnGap) || 0,\n rowGap: parseFloat(lCs.rowGap) || 0\n };\n if (lIsGrid) {\n var cols = lCs.gridTemplateColumns;\n var rows = lCs.gridTemplateRows;\n entry.templateColumns = cols;\n entry.templateRows = rows;\n if (cols && cols !== 'none') {\n entry.columns = cols.split(/\\\\s+/).map(function(s) { return parseFloat(s) || 0; }).filter(function(v) { return v > 0; });\n }\n if (rows && rows !== 'none') {\n entry.rows = rows.split(/\\\\s+/).map(function(s) { return parseFloat(s) || 0; }).filter(function(v) { return v > 0; });\n }\n }\n layoutResults.push(entry);\n }\n respond(id, { containers: layoutResults });\n return;\n }\n\n if (type === 'layout:add-track') {\n var ltEl = getEl(payload.eid);\n if (!ltEl) { respond(id, { property: '', before: '', after: '' }); return; }\n var ltCs = window.getComputedStyle(ltEl);\n var cssProp = payload.axis === 'col' ? 'grid-template-columns' : 'grid-template-rows';\n var ltBefore = ltCs.getPropertyValue(cssProp) || '';\n var ltAfter = ltBefore && ltBefore !== 'none' ? ltBefore + ' 1fr' : '1fr';\n ltEl.style.setProperty(cssProp, ltAfter);\n respond(id, { property: cssProp, before: ltBefore, after: ltAfter });\n return;\n }\n\n if (type === 'layout:add-child') {\n var lcEl = getEl(payload.eid);\n if (!lcEl) { respond(id, { childEid: '' }); return; }\n var child = document.createElement('div');\n child.style.minWidth = '60px';\n child.style.minHeight = '40px';\n child.style.border = '2px dashed #a855f7';\n child.style.borderRadius = '4px';\n child.style.background = 'rgba(168,85,247,0.05)';\n child.setAttribute('data-annotask-placeholder', 'true');\n lcEl.appendChild(child);\n respond(id, { childEid: getEid(child) });\n return;\n }\n\n // ── Theme ──\n if (type === 'theme:inject-css') {\n var existing = document.getElementById(payload.styleId);\n if (existing) {\n existing.textContent = payload.css;\n } else {\n var style = document.createElement('style');\n style.id = payload.styleId;\n style.textContent = payload.css;\n document.head.appendChild(style);\n }\n respond(id, {});\n return;\n }\n\n if (type === 'theme:remove-css') {\n var toRemove = document.getElementById(payload.styleId);\n if (toRemove) toRemove.remove();\n respond(id, {});\n return;\n }\n\n // ── Color Palette ──\n if (type === 'palette:scan-vars') {\n var swatches = [];\n try {\n var rootStyles = window.getComputedStyle(document.documentElement);\n var sheets = document.styleSheets;\n for (var si = 0; si < sheets.length; si++) {\n try {\n var rules = sheets[si].cssRules;\n for (var ri = 0; ri < rules.length; ri++) {\n var rule = rules[ri];\n if (rule.selectorText === ':root' || rule.selectorText === ':root, :host') {\n for (var pi = 0; pi < rule.style.length; pi++) {\n var prop = rule.style[pi];\n if (prop.startsWith('--')) {\n var val = rootStyles.getPropertyValue(prop).trim();\n if (val && isColor(val)) {\n swatches.push({ name: prop, value: val });\n }\n }\n }\n }\n }\n } catch(e) { /* cross-origin stylesheet */ }\n }\n } catch(e) {}\n respond(id, { swatches: swatches });\n return;\n }\n\n // ── Source Mapping Check ──\n if (type === 'check:source-mapping') {\n respond(id, { hasMapping: !!(document.querySelector('[data-annotask-file]') || document.querySelector('[data-astro-source-file]')) });\n return;\n }\n\n // ── Insert Placeholder ──\n if (type === 'insert:placeholder') {\n var ipTarget = getEl(payload.targetEid);\n if (!ipTarget) { respond(id, { placeholderEid: '' }); return; }\n var ipEl = createPlaceholder(payload);\n var ipRef = ipTarget;\n switch (payload.position) {\n case 'before': ipRef.parentElement && ipRef.parentElement.insertBefore(ipEl, ipRef); break;\n case 'after': ipRef.parentElement && ipRef.parentElement.insertBefore(ipEl, ipRef.nextSibling); break;\n case 'append': ipRef.appendChild(ipEl); break;\n case 'prepend': ipRef.insertBefore(ipEl, ipRef.firstChild); break;\n }\n // Match sibling sizes in flex/grid\n var insertParent = (payload.position === 'append' || payload.position === 'prepend') ? ipRef : ipRef.parentElement;\n if (insertParent) {\n var pCs = window.getComputedStyle(insertParent);\n if (pCs.display.includes('flex') || pCs.display.includes('grid')) {\n if (!ipEl.style.width) {\n var isRow = pCs.flexDirection === 'row' || pCs.flexDirection === 'row-reverse' || pCs.display.includes('grid');\n if (isRow) ipEl.style.flex = '1';\n }\n }\n }\n respond(id, { placeholderEid: getEid(ipEl) });\n return;\n }\n\n if (type === 'insert:remove') {\n var irEl = getEl(payload.eid);\n if (irEl) {\n var unmount = irEl.__annotask_unmount;\n if (unmount) unmount();\n irEl.remove();\n }\n respond(id, {});\n return;\n }\n\n if (type === 'move:element') {\n var meEl = getEl(payload.eid);\n var meTarget = getEl(payload.targetEid);\n if (meEl && meTarget) {\n switch (payload.position) {\n case 'before': meTarget.parentElement && meTarget.parentElement.insertBefore(meEl, meTarget); break;\n case 'after': meTarget.parentElement && meTarget.parentElement.insertBefore(meEl, meTarget.nextSibling); break;\n case 'append': meTarget.appendChild(meEl); break;\n case 'prepend': meTarget.insertBefore(meEl, meTarget.firstChild); break;\n }\n }\n respond(id, {});\n return;\n }\n\n if (type === 'insert:vue-component' || type === 'insert:component') {\n var vcTarget = getEl(payload.targetEid);\n if (!vcTarget) { respond(id, { eid: '', mounted: false }); return; }\n var vcContainer = document.createElement('div');\n vcContainer.setAttribute('data-annotask-placeholder', 'true');\n switch (payload.position) {\n case 'before': vcTarget.parentElement && vcTarget.parentElement.insertBefore(vcContainer, vcTarget); break;\n case 'after': vcTarget.parentElement && vcTarget.parentElement.insertBefore(vcContainer, vcTarget.nextSibling); break;\n case 'append': vcTarget.appendChild(vcContainer); break;\n case 'prepend': vcTarget.insertBefore(vcContainer, vcTarget.firstChild); break;\n }\n var mounted = tryMountComponent(vcContainer, payload.componentName, payload.props);\n respond(id, { eid: getEid(vcContainer), mounted: mounted });\n return;\n }\n\n // ── Get source data for an eid ──\n if (type === 'resolve:source') {\n var rsEl = getEl(payload.eid);\n if (!rsEl) { respond(id, null); return; }\n var rsSrc = findSourceElement(rsEl);\n var rsData = getSourceData(rsSrc.sourceEl);\n respond(id, {\n sourceEid: getEid(rsSrc.sourceEl),\n file: rsData.file,\n line: rsData.line,\n component: rsData.component,\n tag: rsSrc.sourceEl.tagName.toLowerCase()\n });\n return;\n }\n\n // ── Route ──\n if (type === 'route:current') {\n respond(id, { path: window.location.pathname });\n return;\n }\n });\n\n // ── Helpers ───────────────────────────────────────────\n function isColor(val) {\n if (val.startsWith('#') || val.startsWith('rgb') || val.startsWith('hsl')) return true;\n // Named colors — quick check with canvas\n try {\n var ctx = document.createElement('canvas').getContext('2d');\n ctx.fillStyle = '#000000';\n ctx.fillStyle = val;\n return ctx.fillStyle !== '#000000' || val === 'black' || val === '#000000';\n } catch(e) { return false; }\n }\n\n function createPlaceholder(payload) {\n var el = document.createElement(payload.tag);\n el.setAttribute('data-annotask-placeholder', 'true');\n if (payload.classes) el.className = payload.classes;\n var tag = payload.tag.toLowerCase();\n var isComponent = payload.tag.includes('-') || (payload.tag[0] === payload.tag[0].toUpperCase() && payload.tag[0] !== payload.tag[0].toLowerCase());\n\n if (tag === 'button') {\n el.textContent = payload.textContent || 'Button';\n el.style.cssText = 'padding:8px 16px;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;border:1px solid currentColor;background:var(--accent,#3b82f6);color:white;';\n } else if (tag === 'input') {\n el.type = 'text'; el.placeholder = 'Input field...';\n el.style.cssText = 'padding:8px 12px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;max-width:300px;background:white;color:#333;';\n } else if (tag === 'textarea') {\n el.placeholder = 'Text area...';\n el.style.cssText = 'padding:8px 12px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;min-height:60px;background:white;color:#333;resize:vertical;';\n } else if (tag === 'img') {\n el.style.cssText = 'width:200px;height:120px;background:#e5e7eb;border-radius:8px;display:flex;align-items:center;justify-content:center;';\n } else if (['h1','h2','h3','h4','h5','h6'].indexOf(tag) >= 0) {\n el.textContent = payload.textContent || 'Heading';\n var sizes = { h1:'2em', h2:'1.5em', h3:'1.25em', h4:'1.1em', h5:'1em', h6:'0.9em' };\n el.style.cssText = 'font-size:' + (sizes[tag]||'1em') + ';font-weight:700;margin:0.5em 0;';\n } else if (tag === 'p') {\n el.textContent = payload.textContent || 'Paragraph text goes here.';\n el.style.cssText = 'margin:0.5em 0;line-height:1.5;';\n } else if (tag === 'a') {\n el.textContent = payload.textContent || 'Link';\n el.style.cssText = 'color:var(--accent,#3b82f6);text-decoration:underline;cursor:pointer;';\n } else if (tag === 'section' || tag === 'div' || tag === 'nav' || tag === 'header' || tag === 'footer' || tag === 'aside' || tag === 'main') {\n if (!payload.classes && !payload.textContent) {\n el.style.cssText = 'min-height:40px;padding:12px;border:1.5px dashed rgba(59,130,246,0.3);border-radius:6px;background:rgba(59,130,246,0.03);';\n } else if (payload.textContent) {\n el.textContent = payload.textContent;\n }\n if (payload.category === 'layout-preset') {\n el.style.minHeight = '60px';\n el.style.padding = el.style.padding || '12px';\n el.style.border = '1.5px dashed rgba(34,197,94,0.3)';\n el.style.borderRadius = '6px';\n el.style.background = 'rgba(34,197,94,0.03)';\n }\n } else if (isComponent) {\n var vcMounted = tryMountComponent(el, payload.tag, payload.defaultProps);\n if (!vcMounted) {\n el.style.cssText = 'min-height:80px;padding:16px;border:1px solid rgba(168,85,247,0.2);border-radius:8px;background:rgba(168,85,247,0.03);display:flex;flex-direction:column;gap:8px;overflow:hidden;';\n var hdr = document.createElement('div');\n hdr.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:4px;';\n var dot = document.createElement('span');\n dot.style.cssText = 'width:6px;height:6px;border-radius:50%;background:#a855f7;';\n hdr.appendChild(dot);\n var tagLabel = document.createElement('span');\n tagLabel.style.cssText = 'font-size:11px;font-weight:600;color:#a855f7;';\n tagLabel.textContent = payload.tag;\n hdr.appendChild(tagLabel);\n el.appendChild(hdr);\n }\n } else {\n el.textContent = payload.textContent || '';\n }\n return el;\n }\n\n function tryMountComponent(container, componentName, props) {\n // Try Vue\n if (window.__ANNOTASK_VUE__) {\n var mounted = tryMountVueComponent(container, componentName, props);\n if (mounted) return true;\n }\n // Try React\n if (window.__ANNOTASK_REACT__) {\n var mounted = tryMountReactComponent(container, componentName, props);\n if (mounted) return true;\n }\n // Try Svelte\n if (window.__ANNOTASK_SVELTE__) {\n var mounted = tryMountSvelteComponent(container, componentName, props);\n if (mounted) return true;\n }\n return false;\n }\n\n function tryMountVueComponent(container, componentName, props) {\n try {\n var appEl = document.querySelector('#app');\n var vueApp = appEl && appEl.__vue_app__;\n if (!vueApp) return false;\n var annotaskVue = window.__ANNOTASK_VUE__;\n if (!annotaskVue || !annotaskVue.createApp || !annotaskVue.h) return false;\n var component = vueApp._context.components[componentName] || (window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName]);\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var miniApp = annotaskVue.createApp({\n render: function() { return annotaskVue.h(component, props || {}); }\n });\n miniApp._context = vueApp._context;\n miniApp.mount(mountPoint);\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() { try { miniApp.unmount(); } catch(e) {} };\n return true;\n } catch(e) { return false; }\n }\n\n function tryMountReactComponent(container, componentName, props) {\n try {\n var annotaskReact = window.__ANNOTASK_REACT__;\n if (!annotaskReact || !annotaskReact.createElement || !annotaskReact.createRoot) return false;\n var component = window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName];\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var root = annotaskReact.createRoot(mountPoint);\n root.render(annotaskReact.createElement(component, props || {}));\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() { try { root.unmount(); } catch(e) {} };\n return true;\n } catch(e) { return false; }\n }\n\n function tryMountSvelteComponent(container, componentName, props) {\n try {\n var annotaskSvelte = window.__ANNOTASK_SVELTE__;\n if (!annotaskSvelte || !annotaskSvelte.mount) return false;\n var component = window.__ANNOTASK_COMPONENTS__ && window.__ANNOTASK_COMPONENTS__[componentName];\n if (!component) return false;\n var mountPoint = document.createElement('div');\n container.appendChild(mountPoint);\n var instance = annotaskSvelte.mount(component, { target: mountPoint, props: props || {} });\n container.setAttribute('data-annotask-mounted', 'true');\n container.__annotask_unmount = function() {\n try {\n if (annotaskSvelte.unmount) annotaskSvelte.unmount(instance);\n } catch(e) {}\n };\n return true;\n } catch(e) { return false; }\n }\n\n // ── Ready ─────────────────────────────────────────────\n sendToShell('bridge:ready', { version: '1.0' });\n})();\n`.trim()\n}\n"],"mappings":";AAQO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0zBP,KAAK;AACP;","names":[]}