diff --git a/.opencode/plans/dap-step-manipulation.md b/.opencode/plans/dap-step-manipulation.md index 1d6f973cf..7188a2e6e 100644 --- a/.opencode/plans/dap-step-manipulation.md +++ b/.opencode/plans/dap-step-manipulation.md @@ -7,15 +7,15 @@ ## Progress Checklist -- [ ] **Chunk 1:** Command Parser & Infrastructure -- [ ] **Chunk 2:** Step Serializer (ActionStep → YAML) -- [ ] **Chunk 3:** Step Factory (Create new steps) -- [ ] **Chunk 4:** Step Manipulator (Queue operations) -- [ ] **Chunk 5:** REPL Commands (!step list, !step add run, !step edit, !step remove, !step move) -- [ ] **Chunk 6:** Action Download Integration (!step add uses) -- [ ] **Chunk 7:** Export Command (!step export) -- [ ] **Chunk 8:** JSON API for Browser Extension -- [ ] **Chunk 9:** Browser Extension UI +- [x] **Chunk 1:** Command Parser & Infrastructure +- [x] **Chunk 2:** Step Serializer (ActionStep → YAML) +- [x] **Chunk 3:** Step Factory (Create new steps) +- [x] **Chunk 4:** Step Manipulator (Queue operations) +- [x] **Chunk 5:** REPL Commands (!step list, !step add run, !step edit, !step remove, !step move) +- [x] **Chunk 6:** Action Download Integration (!step add uses) +- [x] **Chunk 7:** Export Command (!step export) +- [x] **Chunk 8:** JSON API for Browser Extension +- [x] **Chunk 9:** Browser Extension UI ## Overview diff --git a/browser-ext/content/content.css b/browser-ext/content/content.css index ff347ac7e..b693341cd 100644 --- a/browser-ext/content/content.css +++ b/browser-ext/content/content.css @@ -613,3 +613,411 @@ html[data-color-mode="light"] .dap-debug-btn.selected { background-color: #ddf4ff; border-color: #54aeff; } + +/* ========================================================================== + Steps Panel + ========================================================================== */ + +.dap-steps-panel { + display: flex; + flex-direction: column; + border-right: 1px solid var(--borderColor-default, #30363d); + min-width: 200px; + max-width: 280px; + width: 25%; +} + +.dap-debugger-sidebar .dap-steps-panel { + border-right: none; + border-bottom: 1px solid var(--borderColor-default, #30363d); + max-width: none; + width: auto; + max-height: 35%; + min-height: 120px; +} + +.dap-steps-header { + background-color: var(--bgColor-muted, #161b22); + font-size: 12px; + font-weight: 600; + flex-shrink: 0; +} + +.dap-steps-list { + flex: 1; + overflow-y: auto; + padding: 4px 0; +} + +.dap-steps-empty { + font-size: 12px; +} + +.dap-steps-footer { + flex-shrink: 0; + background-color: var(--bgColor-muted, #161b22); +} + +.dap-add-step-btn, +.dap-export-btn { + display: inline-flex; + align-items: center; + gap: 4px; +} + +.dap-add-step-btn svg, +.dap-export-btn svg { + width: 14px; + height: 14px; +} + +.dap-add-step-btn:disabled, +.dap-export-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Step Items */ +.dap-step-item { + display: flex; + align-items: center; + padding: 4px 8px; + font-size: 12px; + cursor: default; + gap: 4px; + border-left: 3px solid transparent; +} + +.dap-step-item:hover { + background-color: var(--bgColor-muted, #161b22); +} + +.dap-step-item.completed { + opacity: 0.6; +} + +.dap-step-item.current { + background-color: var(--bgColor-accent-muted, #388bfd26); + border-left-color: var(--fgColor-accent, #58a6ff); +} + +.dap-step-item.pending[data-editable="true"] { + cursor: pointer; +} + +.dap-step-status-icon { + flex-shrink: 0; + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; +} + +.dap-step-status-icon svg { + width: 12px; + height: 12px; +} + +.dap-step-status-icon.completed { + color: var(--fgColor-success, #3fb950); +} + +.dap-step-status-icon.current { + color: var(--fgColor-accent, #58a6ff); +} + +.dap-step-status-icon.pending { + color: var(--fgColor-muted, #8b949e); +} + +.dap-step-index { + color: var(--fgColor-muted, #8b949e); + font-size: 11px; + min-width: 20px; +} + +.dap-step-name { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--fgColor-default, #e6edf3); +} + +.dap-step-badge { + font-size: 10px; + padding: 1px 4px; + border-radius: 3px; + font-weight: 500; + flex-shrink: 0; +} + +.dap-step-badge-added { + background-color: var(--bgColor-success-muted, #2ea04326); + color: var(--fgColor-success, #3fb950); +} + +.dap-step-badge-modified { + background-color: var(--bgColor-attention-muted, #bb800926); + color: var(--fgColor-attention, #d29922); +} + +.dap-step-type { + color: var(--fgColor-muted, #8b949e); + font-size: 10px; + flex-shrink: 0; + max-width: 80px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dap-step-menu-btn { + background: none; + border: none; + color: var(--fgColor-muted, #8b949e); + cursor: pointer; + padding: 2px 6px; + border-radius: 3px; + font-weight: bold; + letter-spacing: 1px; + opacity: 0; + transition: opacity 0.1s; +} + +.dap-step-item:hover .dap-step-menu-btn { + opacity: 1; +} + +.dap-step-menu-btn:hover { + background-color: var(--bgColor-neutral-muted, #6e768166); + color: var(--fgColor-default, #e6edf3); +} + +/* ========================================================================== + Context Menu + ========================================================================== */ + +.dap-context-menu { + background-color: var(--bgColor-default, #0d1117); + border: 1px solid var(--borderColor-default, #30363d); + border-radius: 6px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + z-index: 10000; + min-width: 140px; + padding: 4px 0; +} + +.dap-context-menu-item { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + font-size: 12px; + color: var(--fgColor-default, #e6edf3); + cursor: pointer; +} + +.dap-context-menu-item:hover { + background-color: var(--bgColor-accent-muted, #388bfd26); +} + +.dap-context-menu-item.danger { + color: var(--fgColor-danger, #f85149); +} + +.dap-context-menu-item.danger:hover { + background-color: var(--bgColor-danger-muted, #da363326); +} + +.dap-context-menu-item svg { + width: 14px; + height: 14px; +} + +.dap-context-menu-divider { + height: 1px; + background-color: var(--borderColor-default, #30363d); + margin: 4px 0; +} + +/* ========================================================================== + Modal + ========================================================================== */ + +.dap-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10001; +} + +.dap-modal { + background-color: var(--bgColor-default, #0d1117); + border: 1px solid var(--borderColor-default, #30363d); + border-radius: 8px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + width: 90%; + max-width: 500px; + max-height: 80vh; + display: flex; + flex-direction: column; +} + +.dap-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + border-bottom: 1px solid var(--borderColor-default, #30363d); +} + +.dap-modal-header .text-bold { + font-size: 14px; + color: var(--fgColor-default, #e6edf3); +} + +.dap-modal-close-btn { + background: none !important; + border: none !important; + color: var(--fgColor-muted, #8b949e) !important; + padding: 4px !important; + cursor: pointer; +} + +.dap-modal-close-btn:hover { + color: var(--fgColor-default, #e6edf3) !important; +} + +.dap-modal-close-btn svg { + width: 16px; + height: 16px; +} + +.dap-modal-content { + padding: 16px; + overflow-y: auto; + flex: 1; +} + +.dap-modal-footer { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 12px 16px; + border-top: 1px solid var(--borderColor-default, #30363d); +} + +/* Form elements */ +.dap-form-group { + margin-bottom: 12px; +} + +.dap-form-group:last-child { + margin-bottom: 0; +} + +.dap-label { + display: block; + font-size: 12px; + font-weight: 600; + color: var(--fgColor-default, #e6edf3); + margin-bottom: 4px; +} + +.dap-modal .form-control { + width: 100%; + background-color: var(--bgColor-inset, #010409) !important; + border-color: var(--borderColor-default, #30363d) !important; + color: var(--fgColor-default, #e6edf3) !important; + font-size: 12px; + padding: 6px 8px; + border-radius: 6px; +} + +.dap-modal .form-control:focus { + border-color: var(--focus-outlineColor, #1f6feb) !important; + outline: none; + box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.3); +} + +.dap-modal select.form-control { + appearance: auto; +} + +.dap-modal textarea.form-control { + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; + resize: vertical; +} + +/* Export Modal */ +.dap-export-stats { + font-size: 12px; +} + +.dap-export-yaml { + background-color: var(--bgColor-inset, #010409); + border: 1px solid var(--borderColor-default, #30363d); + border-radius: 6px; + overflow: auto; + max-height: 300px; +} + +.dap-yaml-content { + margin: 0; + padding: 12px; + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; + font-size: 11px; + line-height: 1.5; + color: var(--fgColor-default, #e6edf3); + white-space: pre; +} + +/* ========================================================================== + Light Mode Overrides for New Components + ========================================================================== */ + +[data-color-mode="light"] .dap-context-menu, +html[data-color-mode="light"] .dap-context-menu { + background-color: #ffffff; + border-color: #d0d7de; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); +} + +[data-color-mode="light"] .dap-context-menu-item, +html[data-color-mode="light"] .dap-context-menu-item { + color: #1f2328; +} + +[data-color-mode="light"] .dap-modal, +html[data-color-mode="light"] .dap-modal { + background-color: #ffffff; + border-color: #d0d7de; +} + +[data-color-mode="light"] .dap-modal-header .text-bold, +html[data-color-mode="light"] .dap-modal-header .text-bold { + color: #1f2328; +} + +[data-color-mode="light"] .dap-step-name, +html[data-color-mode="light"] .dap-step-name { + color: #1f2328; +} + +[data-color-mode="light"] .dap-export-yaml, +html[data-color-mode="light"] .dap-export-yaml { + background-color: #f6f8fa; +} + +[data-color-mode="light"] .dap-yaml-content, +html[data-color-mode="light"] .dap-yaml-content { + color: #1f2328; +} diff --git a/browser-ext/content/content.js b/browser-ext/content/content.js index 76cad32a1..8193fa2ac 100644 --- a/browser-ext/content/content.js +++ b/browser-ext/content/content.js @@ -13,6 +13,9 @@ let replHistory = []; let replHistoryIndex = -1; let currentLayout = 'bottom'; // 'bottom' | 'sidebar' let currentStepElement = null; // Track current step for breakpoint indicator +let stepsList = []; // Cached steps from DAP +let activeContextMenu = null; // Track open context menu +let activeModal = null; // Track open modal // Layout constants const BOTTOM_PANEL_HEIGHT = 350; @@ -132,6 +135,16 @@ const Icons = { stepBack: ``, continue: ``, stepForward: ``, + plus: ``, + download: ``, + check: ``, + play: ``, + clock: ``, + pencil: ``, + trash: ``, + arrowUp: ``, + arrowDown: ``, + copy: ``, }; /** @@ -155,6 +168,31 @@ function createControlButtonsHTML(compact = false) { `; } +/** + * Create the steps panel HTML + */ +function createStepsPanelHTML() { + return ` +
${escapeHtml(yaml)}
+