Ship Chrome extension v2.4.0 hardening and local history - #2
Closed
anhtahaylove wants to merge 12 commits into
Closed
Ship Chrome extension v2.4.0 hardening and local history#2anhtahaylove wants to merge 12 commits into
anhtahaylove wants to merge 12 commits into
Conversation
Reattach the latest recovered extension implementation to the main history so the upgraded MV3 runtime, popup, settings, fixtures, and tests become the canonical repository state again. Keep IDE metadata untracked and drop tool-state directories from the restored tree. Constraint: Recovery source is unreachable stash commit ac325a0, not a live branch Constraint: Master must stay recoverable from pre-restore commit 9e434c9 Rejected: Apply stash in the active worktree | untracked .omx paths would collide Rejected: Restore tool-state directories | not part of the product deliverable Confidence: high Scope-risk: broad Reversibility: clean Directive: Treat this commit as the recovered Antigravity baseline before further cleanup Tested: node --test; node --check menu.js options.js background.js popup.js shared.js Tested: npx --yes web-ext lint --source-dir .; HTTP 200 for three fixture pages Not-tested: Full interactive browser run with the unpacked extension loaded
…ization Capture the current working tree as a stable baseline before the source moves into src modules and the release pipeline expands. This preserves the current Chrome-only runtime hardening and build contract so later refactors can be compared against a known-good state. Constraint: The working tree is the source of truth and must be preserved before deep refactors Rejected: Refactor in-place without a baseline commit | would make regression isolation harder Confidence: high Scope-risk: moderate Reversibility: clean Directive: Use this commit as the comparison point for any behavior regressions during modularization Tested: npm run validate; npm run pack:chrome; fixture HTTP 200 checks Not-tested: Full manual Chrome extension walkthrough against the checklist Co-Authored-By: Claude <noreply@anthropic.com>
Move the authored extension logic into src modules, build the shipped artifact exclusively from that source tree, and add browser automation so Chrome release verification exercises the unpacked extension instead of only unit-level helpers. This removes the split-brain risk of editing runtime files at the repo root while shipping something different. Constraint: Dist artifacts stay generated and must not become a second source of truth Constraint: Chrome-only support remains the product contract for this repository Rejected: Keep root runtime JS as active source | future edits would drift away from the build pipeline Rejected: Add only unit tests without browser automation | would miss extension lifecycle regressions Confidence: medium Scope-risk: broad Reversibility: clean Directive: Continue editing source under src and load unpacked from dist/chrome only Tested: npm run verify:release Not-tested: Manual exploratory walkthrough beyond the documented Chrome checklist Co-Authored-By: Claude <noreply@anthropic.com>
…dules Move the remaining hot-path logic out of the oversized content and options entrypoints so src/content/bootstrap.js and src/options/index.js become orchestration layers instead of carrying extraction, overlay, history, and settings internals directly. This keeps behavior locked by existing release verification while lowering the cost of future changes. Constraint: Behavior must continue to match the frozen baseline commit c911c73 Rejected: Leave bootstrap and options index as monoliths | future changes would keep compounding maintenance cost Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Continue new work in the extracted src/content and src/options modules rather than rebuilding logic in the entrypoints Tested: npm run verify:release Not-tested: Extra exploratory scenarios outside the automated smoke suite Co-Authored-By: Claude <noreply@anthropic.com>
The content helper had become the last broad runtime bucket after the Chrome-only release work. This keeps the createContentHelpers facade stable for bootstrap and events while moving targeting, extraction, overlay, persistence, and clipboard concerns into focused modules. The pass also locks the behavior that matters for this split with Playwright coverage around rich target extraction, table TSV export, selection priority, shortcut copy, excluded domains, and reload recovery. Constraint: Chrome-only contract and dist/chrome remain the release surface Constraint: No product scope expansion or root-authored runtime JS Rejected: Rewrite bootstrap/events around new imports | higher blast radius with no user-facing value Rejected: Keep helpers.js as a large bucket | future edits would keep mixing unrelated runtime responsibilities Confidence: high Scope-risk: moderate Directive: Keep createContentHelpers as the content facade unless bootstrap/events are refactored in the same verified pass Tested: npm run verify:release Not-tested: Human manual acceptance in visible Chrome
Some pages handle form-button clicks before document bubble listeners can observe them. Google Search is one visible case: the primary search button can run page click behavior while the extension is still waiting for the bubble-phase content listener. The content click listener now runs in capture phase and claims only recognized copy gestures, so normal clicks and excluded/editable-skip cases retain existing behavior while Alt-click copy bypasses page handlers and form submission. Constraint: Chrome-only content script behavior must keep dist/chrome as the release surface Rejected: Add a google.com-specific selector workaround | brittle and misses the underlying propagation issue Rejected: Stop propagation for all clicks | would break host-page behavior outside copy gestures Confidence: high Scope-risk: moderate Directive: Keep propagation blocking scoped to confirmed copy gestures only Tested: npm run verify:release Not-tested: Manual visible Chrome test on live google.com
The extension can now treat the local Companion as the source of truth when the native host is connected, while keeping a local fallback and IndexedDB-backed outbox for offline work. The companion adds the Wails desktop MVP, local JSON history, schema v3 conflict timestamps and tombstones, smart previews, tray/hotkey/autostart support, Windows native-host install scripts, release docs, and native/e2e smoke coverage. The final review pass also tightened the native messaging transport contract: host responses are capped under Chrome's 1 MiB host-to-extension limit, extension request text is truncated by UTF-8 bytes, and offline pinning now fails open without trimming fallback history if sync settings cannot be read. Constraint: No cloud sync, account, telemetry, or network transport; clipboard data stays local. Constraint: Native host name remains com.copy_text_without_selecting.companion and protocol version remains 1. Constraint: Chrome native messaging host-to-extension responses must stay under 1 MiB. Rejected: chrome.storage.local as the primary outbox | quota and data-loss risk for large pending payloads. Rejected: embedding companion/build/appicon.png | fresh workspaces do not contain generated build output. Confidence: high Scope-risk: broad Reversibility: messy Directive: Do not remove pending outbox operations until Companion ACKs the corresponding native message. Directive: Keep source assets under companion/assets and companion/frontend/dist; companion/build stays generated output. Directive: Keep native messaging request and response byte budgets separate; extension text truncation must remain UTF-8 byte-based, not JavaScript string-length-based. Tested: npm run validate; npm run test:e2e; npm run native:build; npm run native:test-host; npm run native:test-tray; npm run test:e2e:native; npm run pack:chrome; targeted node --test tests/native-messaging.test.js tests/local-history.test.js; targeted go test ./internal/companion; fresh workspace npm ci + validate + native:build; Wails desktop launch screenshot smoke; git diff --check Not-tested: macOS/Linux native hosts; Chrome Web Store submission; real end-user migration beyond synthetic schema/outbox fixtures.
Chrome already owns Alt+Shift+C as the extension command, so the shortcut flow now waits for a content-script copy acknowledgement and then opens the native Companion through the existing OPEN_APP bridge. The Companion still stores the preferred hotkey, but failed Windows global registration no longer rolls settings back; the UI reports that the saved hotkey is not active when Windows rejects the duplicate. The same pass keeps the installed Companion aligned with release expectations by allowing 9999 history items, syncing the Wails app icon from the extension icon during native builds, and documenting the manual icon/hotkey smoke points. Constraint: Windows RegisterHotKey rejects duplicate process-global shortcuts when Chrome owns Alt+Shift+C Constraint: Wails v2.12 only regenerates build/windows/icon.ico when the stale file is missing Rejected: Register Alt+Shift+C in both Chrome and Companion | duplicate global hotkeys fail and make settings look unstable Rejected: Leave Wails build/appicon.png as an ignored manual artifact | fresh builds could silently return to the default Wails icon Confidence: high Scope-risk: moderate Directive: Keep Alt+Shift+C owned by the extension command path; Companion hotkey activation remains best-effort when Windows reports a conflict Tested: npm run validate Tested: npm run test:e2e Tested: npm run native:build Tested: npm run native:test-host Tested: npm run test:e2e:native Tested: Playwright unpacked popup Open app smoke against extension pahmaphhgccgealefimmgjcfmobgofpp Not-tested: npm run native:test-tray in this turn
The release branch now ships a Windows-native companion, so browser-only Linux CI left the highest-risk packaging and Native Messaging path unguarded. This adds a Windows runner lane that installs the matching Wails CLI, builds the companion, smokes the native host protocol, and runs the native extension E2E flow. Constraint: GitHub Actions JavaScript action runtime is moving to Node 24, so the workflow uses current v6 setup actions instead of relying on the deprecated Node 20 action runtime. Rejected: Run tray visual smoke in hosted CI | the notification area path needs an interactive Windows desktop and is still better covered by manual release smoke. Confidence: high Scope-risk: narrow Directive: Keep tray visual validation manual unless the CI environment provides a real interactive desktop session. Tested: npm run validate; npm run test:e2e; npm run native:build; npm run native:test-host; npm run test:e2e:native; git diff --check Not-tested: GitHub-hosted Windows runner execution before push
The companion was release-ready functionally, but users still needed npm scripts to register the Native Messaging host. This adds a per-user Go setup executable that embeds the built companion, writes the Chrome/Chromium Native Messaging manifest and HKCU registry entries, creates a Windows uninstall entry, and supports silent install/uninstall for CI and release smoke. Constraint: Installer must work without Node.js, npm, Go, Wails, admin rights, cloud services, or telemetry on the user's machine. Rejected: Use Wails NSIS packaging first | Wails can emit NSIS installers, but Native Messaging registration still needs custom lifecycle hooks and an extra installer toolchain. Rejected: Keep npm install-host as the release path | it requires a developer toolchain on user machines. Confidence: high Scope-risk: moderate Directive: Keep user history/settings preserved by default; only delete APPDATA data when --purge-data is explicitly provided. Tested: npm run validate; npm run test:e2e; npm run native:build; npm run native:test-host; npm run native:package-installer; npm run native:test-installer; npm run test:e2e:native; git diff --check Not-tested: Double-click GUI installer experience and code signing
Remove the optional Wails companion, native messaging bridge, Windows installer, native CI lane, popup controls, documentation, and tests. Keep copy history local-only and delete obsolete sync outbox data during extension startup. Constraint: Preserve Chrome copy, shortcut, local history, analytics, and smart-action behavior without deleting saved user history. Rejected: Keep dormant companion code behind flags; it would retain permissions and maintenance burden. Tested: npm run verify:release; npm run validate; npm run test:e2e; git diff --check; active source and built artifact reference scans. Not-tested: Chrome Web Store in-place upgrade and manual migration on an existing browser profile.
Final release review found lifecycle, domain-validation, clipboard, local-history, and test-isolation edge cases that could break copy behavior or lose local history. This hardens dynamic MV3 registration, keeps the background service worker as the only history writer, bounds stored history by UTF-8 bytes, and always resolves Alt-click from the current event target. Constraint: Preserve the extension-only architecture, existing settings/history, Alt+Shift+C behavior, and local-only data model without adding dependencies or permissions. Rejected: Keep unregister-before-register content scripts | an invalid match pattern could leave the extension with no registered content script. Rejected: Keep content-script history fallback writes | concurrent tabs could overwrite each other's local history. Confidence: high Scope-risk: narrow Directive: Keep background initialization serialized and local history writes owned by the background service worker. Tested: npm run verify:release; npm run test:e2e twice consecutively; targeted node tests; git diff --check; independent code-review and architecture passes with no remaining P0/P1/P2. Not-tested: Manual in-place upgrade on the current Chrome profile because the ChatGPT Chrome control backend was unavailable despite local bridge diagnostics passing.
anhtahaylove
marked this pull request as ready for review
July 30, 2026 07:57
Author
|
Closing this PR because development will continue independently in https://github.com/anhtahaylove/copy-text-without-selecting. Thank you for the original MIT-licensed project. |
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.
Summary
Alt+Shift+Cshortcut support.Tests
npm run verify:release— PASSnpm run validate— 56/56 unit tests; syntax, manifest, and Chrome build PASSnpm run test:e2e— 9/9 PASS; final regression run repeated twice consecutivelygit diff --check— PASSChrome CIrun 30515495707 — PASSRisks
esbuildaudit advisory remains; no high/critical production dependency finding was detected.Release notes
copy-text-with-alt-click-chrome-v2.4.0.zip1a4674871d670e3e98dea30d17747f0a39b84da07e9915e2478c19bd2407afe34c32b8ad632e645840ddfe226397f278c8503c58