Feat/layout test#4
Open
tronicum wants to merge 16 commits into
Open
Conversation
added 16 commits
July 17, 2026 20:41
…d README for Notion + vault The Notion export subagent added a fetch() to api.notion.com but never declared it in manifest.json's host_permissions (same class of drift as the earlier SUPPORTED_HOSTS/supported-sites.json issue this session) — would likely be blocked under Firefox's stricter MV3 permission enforcement and is inconsistent with how api.github.com is already explicitly listed. PRIVACY.md and README.md's Privacy/Integrations sections still only mentioned Gist + webhook, making the privacy policy inaccurate now that Notion (a new external endpoint) and direct-to-vault (new local file writes) both exist. Updated both docs and the permissions table.
Live-investigated on a real logged-in ChatGPT account. Canvas code blocks
turned out to already extract clean code correctly (the existing 'pre'
handler's querySelector('code') happens to reach through the CodeMirror
markup) — the original TODO's assumption of a whole unhandled side-panel
UI didn't hold up. The one real gap: the language name lives as plain text
in a '.sticky' toolbar header (alongside Copy/Run buttons) inside the same
<pre>, which none of the three existing language-detection heuristics
catch, so every Canvas export shipped with no language tag on the fence.
Added a 4th heuristic, gated on an actual CodeMirror editor being present
(.cm-editor/.cm-content/#code-block-viewer) so it can't misfire on some
other platform's unrelated '.sticky' element.
Also confirmed real selectors for ChatGPT's history sidebar for Batch 8
(a[href^="/c/"], data-sidebarItem, scrollable nav container) — documented
in TODOs.md. Text-canvas variant and pagination/virtualization behavior at
scale remain unverified (free-tier canvas tool call misfired; account only
had ~28 conversations, too few to observe lazy-load).
4 new JSDOM tests, confirmed to fail pre-fix and pass post-fix. Full suite
267→271 passed, 0 failed, before and after.
…idebar (Batch 8) Live-investigated against a real logged-in Claude account (two artifacts created: Python + JS). Claude Artifacts: confirmed this genuinely needs the side-panel handling the original TODO assumed (unlike ChatGPT Canvas, which turned out in-line). extractClaude()'s current artifactSuffix logic queries for code/pre inside .artifact-block-cell, but that only ever contains a title+filetype preview card with zero code inside — so Claude Artifacts exports currently ship with NO artifact content at all. The real code lives in a separate #wiggle-file-content panel outside any message turn, with line-number-gutter text baked into textContent (needs per-line stripping), and only the most-recently-opened artifact's content is ever mounted — extracting all artifacts in a conversation needs click-through per card (confirmed a bare el.click() doesn't trigger the swap; only a real synthetic mouse click does). Not fixed this session — genuinely multi-session work as originally scoped, unlike Canvas. Claude sidebar (Batch 8): confirmed a[href^="/chat/"] selector, and that naive textContent doubles the title (a hidden .sr-only span + a visible aria-hidden duplicate) — use .sr-only for a clean title. Found Claude's dedicated /recents page (full searchable list + native multi-select) as a better Batch 8 enumeration target than the sidebar preview.
Instant scrollTop jump doesn't trigger lazy-load; confirmed via bulk-create test that genuine incremental scroll + dispatched scroll events does (28 -> 56 conversations, stabilizing at true max scrollTop). Corrects the earlier 'inconclusive' note and documents the implementation implication for Batch 8 orchestration code.
Adds src/content.js getConversationList() + {action:'getConversationList'}
message handler for ChatGPT/Claude, returning de-duplicated {title,url}
pairs from the current tab's history sidebar. Feature-detects by returning
[] on unsupported/logged-out pages, so the future popup UI can gate purely
on conversations.length without touching the existing single-conversation
extraction path.
7 new JSDOM tests (271 -> 278 passed, 0 failed). Selectors also re-verified
live against real open ChatGPT (28 convos) and Claude (8 convos) tabs.
Popup UI + background.js tab-cycling orchestration (steps 2-5) still TODO.
…ch 7) Re-tested live with a full pointerdown/mousedown/pointerup/mouseup/click sequence (bubbles, cancelable, real coordinates) against a real 2-artifact conversation - still no panel swap. Only genuine OS-level input (CDP/ chrome.debugger) works, and chrome.debugger is a heavy permission with a persistent browser-wide warning banner - poor trade for a read-only export feature. Downgrades this item from 'more engineering time needed' to effectively blocked pending a non-click extraction path.
Backfills one ## [x.y.z.w] section per existing git tag (v0.2.0 through v0.4.28.1) plus an Unreleased section for work since the last tag (Notion export, vault writes, Canvas fix, AI Mode dedup fix, footnote fix, etc). Entries are short and user-facing, matching what Batch 10's future automated store-publishing workflow will extract and submit as AMO's release_notes / the GitHub Release body. Adds a JSDOM regression suite (281 total, 0 failed) that fails if the current manifest version has no matching section, if Unreleased goes missing, or if a heading doesn't match a real git tag - guards against the file silently drifting out of sync with what's actually shipped. Also documents in TODOs.md Batch 10 exactly how the future workflow should consume this file (extract text between this tag's heading and the next).
Converts all 5 settings.html sections (Language, Export, Direct-to-vault, Integrations, Advanced) from <section><h2> to <details class="settings-section" open><summary><h2>, all starting open so the default view is unchanged - scannability only, not a way to hide settings. Custom rotating chevron marker replaces the native triangle. The vault section's existing Chrome-only hidden/display feature-detect toggle in settings.js is untouched and confirmed to still work correctly alongside the details/open attribute. 281 tests still pass, 0 failed - no test or JS file referenced the <section> tag name.
…ration popup.html/popup.js: a 'Batch export past conversations...' toggle appears only when content.js's getConversationList() (Batch 8 step 1) finds a history sidebar on the current tab - stays hidden/silent everywhere else, so the existing single-conversation export path is untouched. background.js: new runBatchExport() - sequential background-tab automation (create tab, wait for load, extract, collect markdown, remove tab, small delay) living in the service worker so it survives the popup closing. Aggregates one .md file per conversation into a single ZIP via the existing buildZip()/buildFilename()/safeDownload() helpers - no new export-building code, all reused from the existing extraction paths. 9 new i18n keys, real translations added to all 26 locales (25 via parallel subagents, spot-checked + full key-set diff verified - zero mismatches). One new Playwright e2e test asserting the toggle stays hidden with no chat page open (syntax-verified via node -c; couldn't execute in this sandbox - Chromium binary download blocked by network restrictions - needs a real CI/local run to confirm it passes). 281 JSDOM tests still pass, 0 failed. Per TODOs.md: this is implemented and internally consistent but NOT live-tested end-to-end yet, same status Batch 5 (Notion) and Batch 6 (vault) shipped in - needs a real small-N (3-5 conversations) run on Stefan's own accounts before being called done. Per-platform timeout tuning and safe-batch-size limits remain open questions, same as the original design sketch flagged.
Stefan compared the old 'ON' badge to uBlock/Bitwarden's much more visible
toolbar badges and wanted something bigger, passive (no click needed),
not a number. The native OS badge corner turned out to be a dead end -
its size is fixed by the browser, no API controls it - so the signal moves
into the icon bitmap instead, which we fully control.
Added icons/icon-{16,32,48,96,128}-active.png (generated via Pillow: a
white-ringed green checkmark circle, ~62% of icon width, bottom-right;
16px drops the checkmark detail, too small to survive downscaling).
background.js's existing updateBadge() now calls action.setIcon() per tab
instead of setBadgeText('ON'), and explicitly clears any stale badge text
a previous version may have left on an already-open tab.
5 new JSDOM tests: all 4 manifest icon sizes have a referenced -active
file, each file exists/is non-empty, each is confirmed to actually differ
from its default (byte comparison, catches a copy-paste no-op), each is a
structurally valid PNG at its declared size (parsed IHDR directly, no new
dependency), and the stale-badge-clear call is present. Also added the 4
active icons to CI's required-files check. 281 -> 286 passed, 0 failed.
Not verified: actual rendering in a real browser toolbar (DPI, dark/light
theme contrast, Firefox's icon padding) - image generation and JSDOM
checks only, no way to render a real toolbar in this sandbox.
Stefan looked at the real 32px rendering of the checkmark-badge version and flagged that it visibly overlapped/clipped the arrow logo - legible, but now covering the brand mark, a regression in a different direction. Replaced with a full-icon recolor: icon-*-active.png is the same logo art with its background hue-shifted from purple/blue to green (#16a34a's hue), nothing drawn on top. HSV hue-shift only touches pixels above a saturation threshold, cleanly separating the colorful background gradient (sat. ~146-148) from the pure-white glyph (sat. 0) - so the arrow/lines stay 100% intact and legible at every size down to 16px, and the gradient's original shading is preserved (just green instead of purple/blue). Same file names/paths, same background.js wiring, same 5 JSDOM tests - only the pixel content changed. 286 passed, 0 failed.
Stefan reloaded the unpacked extension while sitting on an already-open, already-focused supported tab and saw no green icon at all. Root cause: updateBadge() only ran from tabs.onUpdated (navigation) and tabs.onActivated (switching tabs) - reloading the extension fires neither for a tab that was already open and already focused, so nothing ever told that tab's icon to update. Added syncAllTabIcons(), wired to runtime.onInstalled (install/update/every unpacked-reload) and runtime.onStartup (browser restart restoring tabs) - queries every open tab and runs the existing updateBadge() logic on each. 2 new JSDOM tests (288 total, 0 failed).
Stefan flagged the popup as crowded (up to 11 buttons visible at once). Brainstormed 3 directions, landed on a GitHub-style split button: a primary face (remembers the most recently used format) + a caret that opens a menu with everything else, including Gist/Notion folded into the same menu instead of separate always-there buttons. Critically, the menu contains the exact same 11 button elements/ids (mdBtn, pdfBtn, ..., gistBtn, notionBtn) that used to sit in the grid - only their container/CSS changed - so every existing click handler (extraction, vault-write branching, Gist/Notion upload, webhook firing, history persistence) keeps running completely unmodified. New code is just a thin layer: FORMAT_TO_BTN maps format -> button, the primary face proxies its click to FORMAT_TO_BTN[preferredFormat], preferredFormat is seeded from the existing inkpour_last_export.format (no new storage key) falling back to the Settings default format, and setLoading() got one additive line mirroring state onto the primary face. 2 new i18n keys (More export options tooltip, short 'All' label), translated to all 26 locales. 8 new structural JSDOM tests (popup.js/html aren't executed by this harness, same as background.js - these parse/grep instead). Updated 5 stale e2e tests that referenced the old grid, added 5 new ones for menu open/close/pick behavior (not run in this sandbox - Chromium binary download blocked by network restrictions, same limitation as before - syntax-verified only). 296 passed, 0 failed. Not yet verified: actual visual rendering/spacing in a real 320px popup - CSS reuses existing variables/patterns and cascade order was verified by parsing, not rendering.
…-Execute for the rest Reworks the split-button popup from the previous commit per live usage feedback: Copy MD and ZIP move back out to always-visible quick buttons (they were the two most-used actions and got buried in the collapsed menu); everything else (MD/PDF/HTML/JSON/DOCX/Copy HTML/Export All/ Gist/Notion) is now picked from a menu that only updates the selection, with a separate Export button that actually fires it. Real handlers are unchanged, just relocated into a permanently-hidden container so a menu row click structurally cannot reach them — only the Export button's click proxies through. Fixes the specific complaint that picking Gist/ Notion from the old menu fired the upload instantly with no chance to back out. - popup.html: quick-actions row (copyBtn/zipBtn), new .export-picker (exportSelectBtn + exportGoBtn), inert data-format menu rows, hidden #realExportActions housing the original 9 buttons. - popup.js: FORMAT_TO_BTN drops copy-md/zip; setSelectedFormat() only updates UI; exportGoBtn is the sole .click() proxy; gist/notion token-gating retargeted to the menu stand-ins. - 1 new i18n key (popupExportGoBtn), translated to all 26 locales. - Rewrote the JSDOM structural suite + Playwright e2e spec to match (300 passed, 0 failed; e2e not run in this sandbox, Playwright Chromium download still blocked — node -c only). - TODOs.md Batch 4d + CHANGELOG.md Unreleased updated.
Feedback: Copy MD (quick button) vs Copy HTML (buried in an unrelated copy cluster in the dropdown) felt arbitrary with no visible reason for the split. Considered dropping Copy HTML outright, but it's kept as the clipboard alternative to the HTML file export. - popup.html: copy-html menu row moved to sit directly under the html row (dropped the old copy-cluster divider), styled .sub-item (indented, muted) so it reads as HTML's clipboard variant rather than a peer action. Label changed from "Copy HTML" to "Copy to clipboard" (same popupBtnCopyHtml i18n key, new message only). - Translated the new wording to all 26 locales. - Copy MD's quick-button position is unchanged. - 300 passed, 0 failed.
Two more rounds of live feedback on the popup export picker: - The selector's caret was too small to read as a toggle. Now bigger (10px -> 15px) and rotates 180 degrees while the menu is open. - Calling out "Copy to clipboard" by name made the other rows' silent destination (file download vs. external upload) feel unexplained by contrast. Added a small non-translated inline SVG icon to every quick button and menu row: download-arrow for file exports, copy-icon for clipboard-bound ones, upload-arrow for Gist/Notion -- matching the "up" cue Gist/Notion already implied. Icons are plain <svg> markup outside any data-i18n span, so future wording tweaks never touch translations again. Correspondingly stripped the symbols that used to be baked into translated strings themselves (popupBtnExportAll's leading arrow, popupBtnGist/popupBtnNotion's trailing arrow, popupBtnCopyHtml shortened to "Copy"), re-translated across all 26 locales. 300 passed, 0 failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.