Initial commit: Share-as-QR Firefox extension with bun build

MV3 WebExtension that turns the active tab's URL into a scannable QR
code via a toolbar popup. The popup runs locally — no network requests.

Build pipeline: `bun build` bundles popup.js + the vendored
kazuhikoarase/qrcode-generator (MIT, pinned to 83b7e8f) into a single
~23 KB minified ESM file under dist/. web-ext operates on dist/, so
the packaged zip contains only what actually ships (~28 KB).

Scripts:
- bun run build    — bundle + copy assets into dist/
- bun run lint     — build + web-ext lint (0 errors / 0 warnings)
- bun run package  — build + produce a signable .zip
- bun run start    — build + launch Firefox with the extension loaded

Tracks dogcat epic firefox-share-as-qr-35mw and its 5 child tasks
(scaffold, vendor lib, popup UI, icons, README).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-05-11 16:04:22 +02:00
commit 8fa1809d9d
16 changed files with 2915 additions and 0 deletions

1
.dogcats/config.toml Normal file
View file

@ -0,0 +1 @@
namespace = "firefox-share-as-qr"

30
.dogcats/issues.jsonl Normal file
View file

@ -0,0 +1,30 @@
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"35mw","title":"Build Firefox QR share extension","description":"Firefox WebExtension (MV3) that adds a toolbar button. Clicking the button opens a popup that renders a QR code of the current tab's URL so the user can quickly share the page to a phone/another device.\n\nConstraints:\n- Manifest v3, Firefox 109+\n- No remote scripts (MV3 forbids); QR library is vendored\n- No build step required for MVP\n- Use kazuhikoarase qrcode-generator (MIT) as bundled JS\n\nTrigger: toolbar button only (no context menu in MVP).\n\nAcceptance: installing the extension via about:debugging shows a toolbar icon. Clicking it on any http(s) page opens a popup with a scannable QR code of that page's URL.","status":"open","priority":2,"issue_type":"epic","owner":"olemd@glemt.net","parent":null,"labels":[],"external_ref":null,"design":null,"acceptance":"- Load as temporary add-on via about:debugging works without errors\n- Clicking the toolbar icon on any normal page shows a scannable QR code\n- QR encodes the active tab's full URL\n- No network requests made by the extension\n- LICENSE/attribution for vendored QR library present","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:56:50.789766+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:56:50.789768+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-35mw","timestamp":"2026-05-11T14:56:50.789768+02:00","by":"olemd@glemt.net","changes":{"owner":{"old":null,"new":"olemd@glemt.net"},"title":{"old":null,"new":"Build Firefox QR share extension"},"priority":{"old":null,"new":2},"status":{"old":null,"new":"open"},"description":{"old":null,"new":"Firefox WebExtension (MV3) that adds a toolbar button. Clicking the button opens a popup that renders a QR code of the current tab's URL so the user can quickly share the page to a phone/another device.\n\nConstraints:\n- Manifest v3, Firefox 109+\n- No remote scripts (MV3 forbids); QR library is vendored\n- No build step required for MVP\n- Use kazuhikoarase qrcode-generator (MIT) as bundled JS\n\nTrigger: toolbar button only (no context menu in MVP).\n\nAcceptance: installing the extension via about:debugging shows a toolbar icon. Clicking it on any http(s) page opens a popup with a scannable QR code of that page's URL."},"issue_type":{"old":null,"new":"epic"},"acceptance":{"old":null,"new":"- Load as temporary add-on via about:debugging works without errors\n- Clicking the toolbar icon on any normal page shows a scannable QR code\n- QR encodes the active tab's full URL\n- No network requests made by the extension\n- LICENSE/attribution for vendored QR library present"}},"title":"Build Firefox QR share extension"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2mpm","title":"Scaffold MV3 manifest and project layout","description":"Create the WebExtension manifest.json (MV3) with:\n- name, version, description, manifest_version: 3\n- browser_specific_settings.gecko.id and strict_min_version (>= 109.0)\n- action with default_popup, default_title, default_icon\n- icons (16/32/48/96/128)\n- no host_permissions; tabs activeTab is enough\n\nAlso lay out the directory: popup/ for the popup HTML/CSS/JS, icons/, vendor/ for third-party JS, LICENSE, README.","status":"open","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- manifest.json validates (web-ext lint passes)\n- about:debugging → Load Temporary Add-on succeeds without warnings\n- Toolbar icon appears","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:56:56.711635+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:56:56.711637+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-2mpm","timestamp":"2026-05-11T14:56:56.711637+02:00","by":"olemd@glemt.net","changes":{"priority":{"old":null,"new":1},"status":{"old":null,"new":"open"},"owner":{"old":null,"new":"olemd@glemt.net"},"description":{"old":null,"new":"Create the WebExtension manifest.json (MV3) with:\n- name, version, description, manifest_version: 3\n- browser_specific_settings.gecko.id and strict_min_version (>= 109.0)\n- action with default_popup, default_title, default_icon\n- icons (16/32/48/96/128)\n- no host_permissions; tabs activeTab is enough\n\nAlso lay out the directory: popup/ for the popup HTML/CSS/JS, icons/, vendor/ for third-party JS, LICENSE, README."},"parent":{"old":null,"new":"firefox-share-as-qr-35mw"},"title":{"old":null,"new":"Scaffold MV3 manifest and project layout"},"issue_type":{"old":null,"new":"task"},"acceptance":{"old":null,"new":"- manifest.json validates (web-ext lint passes)\n- about:debugging → Load Temporary Add-on succeeds without warnings\n- Toolbar icon appears"}},"title":"Scaffold MV3 manifest and project layout"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2u7w","title":"Vendor qrcode-generator library and add attribution","description":"Vendor kazuhikoarase's qrcode-generator (MIT) into vendor/qrcode.js as a single self-contained file. Add the MIT LICENSE text in vendor/LICENSE.qrcode-generator. Reference upstream version/commit in a comment header for traceability.\n\nUpstream: https://github.com/kazuhikoarase/qrcode-generator (MIT)","status":"open","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- vendor/qrcode.js present and standalone (no imports)\n- vendor/LICENSE.qrcode-generator present\n- Top-of-file comment notes upstream and version","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:04.087305+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:57:04.087308+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-2u7w","timestamp":"2026-05-11T14:57:04.087308+02:00","by":"olemd@glemt.net","changes":{"acceptance":{"old":null,"new":"- vendor/qrcode.js present and standalone (no imports)\n- vendor/LICENSE.qrcode-generator present\n- Top-of-file comment notes upstream and version"},"title":{"old":null,"new":"Vendor qrcode-generator library and add attribution"},"status":{"old":null,"new":"open"},"parent":{"old":null,"new":"firefox-share-as-qr-35mw"},"description":{"old":null,"new":"Vendor kazuhikoarase's qrcode-generator (MIT) into vendor/qrcode.js as a single self-contained file. Add the MIT LICENSE text in vendor/LICENSE.qrcode-generator. Reference upstream version/commit in a comment header for traceability.\n\nUpstream: https://github.com/kazuhikoarase/qrcode-generator (MIT)"},"issue_type":{"old":null,"new":"task"},"priority":{"old":null,"new":1},"owner":{"old":null,"new":"olemd@glemt.net"}},"title":"Vendor qrcode-generator library and add attribution"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"4ph7","title":"Build popup UI and wire QR rendering","description":"Implement popup/popup.html + popup/popup.css + popup/popup.js:\n- Query active tab URL via browser.tabs.query({active: true, currentWindow: true})\n- Render QR using vendored qrcode-generator into an <img> (data: URL via canvas) or SVG\n- Show the URL underneath (truncated/elided) and a Copy button\n- Handle long URLs gracefully (auto-bump QR error correction / version)\n- Handle privileged pages (about:, view-source:) by showing a friendly message\n- Respect prefers-color-scheme (light/dark)","status":"open","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- Opening the popup on https://example.com shows a scannable QR\n- Long URLs (e.g. >1kB) still render or show a clear error\n- about:* page shows 'cannot share this page' message\n- Copy URL button copies to clipboard\n- Layout works at 360px popup width and is keyboard-accessible","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:10.501759+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:57:10.501761+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-4ph7","timestamp":"2026-05-11T14:57:10.501761+02:00","by":"olemd@glemt.net","changes":{"parent":{"old":null,"new":"firefox-share-as-qr-35mw"},"priority":{"old":null,"new":1},"issue_type":{"old":null,"new":"task"},"owner":{"old":null,"new":"olemd@glemt.net"},"title":{"old":null,"new":"Build popup UI and wire QR rendering"},"acceptance":{"old":null,"new":"- Opening the popup on https://example.com shows a scannable QR\n- Long URLs (e.g. >1kB) still render or show a clear error\n- about:* page shows 'cannot share this page' message\n- Copy URL button copies to clipboard\n- Layout works at 360px popup width and is keyboard-accessible"},"description":{"old":null,"new":"Implement popup/popup.html + popup/popup.css + popup/popup.js:\n- Query active tab URL via browser.tabs.query({active: true, currentWindow: true})\n- Render QR using vendored qrcode-generator into an <img> (data: URL via canvas) or SVG\n- Show the URL underneath (truncated/elided) and a Copy button\n- Handle long URLs gracefully (auto-bump QR error correction / version)\n- Handle privileged pages (about:, view-source:) by showing a friendly message\n- Respect prefers-color-scheme (light/dark)"},"status":{"old":null,"new":"open"}},"title":"Build popup UI and wire QR rendering"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"13gn","title":"Add extension icons","description":"Provide icons at 16, 32, 48, 96, 128 px (PNG). For MVP, a simple QR-glyph or 'QR' badge is fine. Source SVG should live in icons/source.svg; PNGs generated from it.\n\nIf image generation isn't possible in the agent environment, commit a placeholder PNG plus the SVG source and note in the README that icons are TODO.","status":"open","priority":2,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- icons/icon-{16,32,48,96,128}.png exist\n- manifest references them\n- about:debugging shows the icon, not the default puzzle piece","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:16.085120+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:57:16.085122+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-13gn","timestamp":"2026-05-11T14:57:16.085122+02:00","by":"olemd@glemt.net","changes":{"status":{"old":null,"new":"open"},"priority":{"old":null,"new":2},"issue_type":{"old":null,"new":"task"},"parent":{"old":null,"new":"firefox-share-as-qr-35mw"},"title":{"old":null,"new":"Add extension icons"},"description":{"old":null,"new":"Provide icons at 16, 32, 48, 96, 128 px (PNG). For MVP, a simple QR-glyph or 'QR' badge is fine. Source SVG should live in icons/source.svg; PNGs generated from it.\n\nIf image generation isn't possible in the agent environment, commit a placeholder PNG plus the SVG source and note in the README that icons are TODO."},"acceptance":{"old":null,"new":"- icons/icon-{16,32,48,96,128}.png exist\n- manifest references them\n- about:debugging shows the icon, not the default puzzle piece"},"owner":{"old":null,"new":"olemd@glemt.net"}},"title":"Add extension icons"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2slq","title":"README and packaging instructions","description":"Write a short README with:\n- What the extension does (one paragraph + screenshot placeholder)\n- Install for development: about:debugging → 'Load Temporary Add-on' → pick manifest.json\n- Packaging: 'bunx web-ext build' produces a signable .zip (web-ext is the standard Mozilla tool; bunx avoids global install)\n- License and attribution for vendored QR library\n- Privacy note: the extension makes no network requests","status":"open","priority":2,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- README.md explains install + dev workflow\n- Attribution for qrcode-generator present","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:21.849005+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T14:57:21.849007+02:00","updated_by":null,"closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"created","issue_id":"firefox-share-as-qr-2slq","timestamp":"2026-05-11T14:57:21.849007+02:00","by":"olemd@glemt.net","changes":{"status":{"old":null,"new":"open"},"owner":{"old":null,"new":"olemd@glemt.net"},"parent":{"old":null,"new":"firefox-share-as-qr-35mw"},"title":{"old":null,"new":"README and packaging instructions"},"issue_type":{"old":null,"new":"task"},"description":{"old":null,"new":"Write a short README with:\n- What the extension does (one paragraph + screenshot placeholder)\n- Install for development: about:debugging → 'Load Temporary Add-on' → pick manifest.json\n- Packaging: 'bunx web-ext build' produces a signable .zip (web-ext is the standard Mozilla tool; bunx avoids global install)\n- License and attribution for vendored QR library\n- Privacy note: the extension makes no network requests"},"priority":{"old":null,"new":2},"acceptance":{"old":null,"new":"- README.md explains install + dev workflow\n- Attribution for qrcode-generator present"}},"title":"README and packaging instructions"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2mpm","title":"Scaffold MV3 manifest and project layout","description":"Create the WebExtension manifest.json (MV3) with:\n- name, version, description, manifest_version: 3\n- browser_specific_settings.gecko.id and strict_min_version (>= 109.0)\n- action with default_popup, default_title, default_icon\n- icons (16/32/48/96/128)\n- no host_permissions; tabs activeTab is enough\n\nAlso lay out the directory: popup/ for the popup HTML/CSS/JS, icons/, vendor/ for third-party JS, LICENSE, README.","status":"in_progress","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- manifest.json validates (web-ext lint passes)\n- about:debugging → Load Temporary Add-on succeeds without warnings\n- Toolbar icon appears","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:56:56.711635+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:34:56.439975+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-2mpm","timestamp":"2026-05-11T15:34:56.439975+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"open","new":"in_progress"}},"title":"Scaffold MV3 manifest and project layout"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2mpm","title":"Scaffold MV3 manifest and project layout","description":"Create the WebExtension manifest.json (MV3) with:\n- name, version, description, manifest_version: 3\n- browser_specific_settings.gecko.id and strict_min_version (>= 109.0)\n- action with default_popup, default_title, default_icon\n- icons (16/32/48/96/128)\n- no host_permissions; tabs activeTab is enough\n\nAlso lay out the directory: popup/ for the popup HTML/CSS/JS, icons/, vendor/ for third-party JS, LICENSE, README.","status":"in_review","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- manifest.json validates (web-ext lint passes)\n- about:debugging → Load Temporary Add-on succeeds without warnings\n- Toolbar icon appears","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:56:56.711635+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:36:02.467838+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-2mpm","timestamp":"2026-05-11T15:36:02.467838+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"in_progress","new":"in_review"}},"title":"Scaffold MV3 manifest and project layout"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2u7w","title":"Vendor qrcode-generator library and add attribution","description":"Vendor kazuhikoarase's qrcode-generator (MIT) into vendor/qrcode.js as a single self-contained file. Add the MIT LICENSE text in vendor/LICENSE.qrcode-generator. Reference upstream version/commit in a comment header for traceability.\n\nUpstream: https://github.com/kazuhikoarase/qrcode-generator (MIT)","status":"in_progress","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- vendor/qrcode.js present and standalone (no imports)\n- vendor/LICENSE.qrcode-generator present\n- Top-of-file comment notes upstream and version","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:04.087305+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:36:02.683873+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-2u7w","timestamp":"2026-05-11T15:36:02.683873+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"open","new":"in_progress"}},"title":"Vendor qrcode-generator library and add attribution"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2u7w","title":"Vendor qrcode-generator library and add attribution","description":"Vendor kazuhikoarase's qrcode-generator (MIT) into vendor/qrcode.js as a single self-contained file. Add the MIT LICENSE text in vendor/LICENSE.qrcode-generator. Reference upstream version/commit in a comment header for traceability.\n\nUpstream: https://github.com/kazuhikoarase/qrcode-generator (MIT)","status":"in_review","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- vendor/qrcode.js present and standalone (no imports)\n- vendor/LICENSE.qrcode-generator present\n- Top-of-file comment notes upstream and version","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:04.087305+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:38:22.668206+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-2u7w","timestamp":"2026-05-11T15:38:22.668206+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"in_progress","new":"in_review"}},"title":"Vendor qrcode-generator library and add attribution"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"4ph7","title":"Build popup UI and wire QR rendering","description":"Implement popup/popup.html + popup/popup.css + popup/popup.js:\n- Query active tab URL via browser.tabs.query({active: true, currentWindow: true})\n- Render QR using vendored qrcode-generator into an <img> (data: URL via canvas) or SVG\n- Show the URL underneath (truncated/elided) and a Copy button\n- Handle long URLs gracefully (auto-bump QR error correction / version)\n- Handle privileged pages (about:, view-source:) by showing a friendly message\n- Respect prefers-color-scheme (light/dark)","status":"in_progress","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- Opening the popup on https://example.com shows a scannable QR\n- Long URLs (e.g. >1kB) still render or show a clear error\n- about:* page shows 'cannot share this page' message\n- Copy URL button copies to clipboard\n- Layout works at 360px popup width and is keyboard-accessible","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:10.501759+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:38:22.886002+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-4ph7","timestamp":"2026-05-11T15:38:22.886002+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"open","new":"in_progress"}},"title":"Build popup UI and wire QR rendering"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"13gn","title":"Add extension icons","description":"Provide icons at 16, 32, 48, 96, 128 px (PNG). For MVP, a simple QR-glyph or 'QR' badge is fine. Source SVG should live in icons/source.svg; PNGs generated from it.\n\nIf image generation isn't possible in the agent environment, commit a placeholder PNG plus the SVG source and note in the README that icons are TODO.","status":"in_progress","priority":2,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- icons/icon-{16,32,48,96,128}.png exist\n- manifest references them\n- about:debugging shows the icon, not the default puzzle piece","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:16.085120+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:38:23.118252+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-13gn","timestamp":"2026-05-11T15:38:23.118252+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"open","new":"in_progress"}},"title":"Add extension icons"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"4ph7","title":"Build popup UI and wire QR rendering","description":"Implement popup/popup.html + popup/popup.css + popup/popup.js:\n- Query active tab URL via browser.tabs.query({active: true, currentWindow: true})\n- Render QR using vendored qrcode-generator into an <img> (data: URL via canvas) or SVG\n- Show the URL underneath (truncated/elided) and a Copy button\n- Handle long URLs gracefully (auto-bump QR error correction / version)\n- Handle privileged pages (about:, view-source:) by showing a friendly message\n- Respect prefers-color-scheme (light/dark)","status":"in_review","priority":1,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- Opening the popup on https://example.com shows a scannable QR\n- Long URLs (e.g. >1kB) still render or show a clear error\n- about:* page shows 'cannot share this page' message\n- Copy URL button copies to clipboard\n- Layout works at 360px popup width and is keyboard-accessible","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:10.501759+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:45:47.721028+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-4ph7","timestamp":"2026-05-11T15:45:47.721028+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"in_progress","new":"in_review"}},"title":"Build popup UI and wire QR rendering"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"13gn","title":"Add extension icons","description":"Provide icons at 16, 32, 48, 96, 128 px (PNG). For MVP, a simple QR-glyph or 'QR' badge is fine. Source SVG should live in icons/source.svg; PNGs generated from it.\n\nIf image generation isn't possible in the agent environment, commit a placeholder PNG plus the SVG source and note in the README that icons are TODO.","status":"in_review","priority":2,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- icons/icon-{16,32,48,96,128}.png exist\n- manifest references them\n- about:debugging shows the icon, not the default puzzle piece","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:16.085120+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:45:47.981639+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-13gn","timestamp":"2026-05-11T15:45:47.981639+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"in_progress","new":"in_review"}},"title":"Add extension icons"}
{"record_type":"issue","dcat_version":"0.12.1","namespace":"firefox-share-as-qr","id":"2slq","title":"README and packaging instructions","description":"Write a short README with:\n- What the extension does (one paragraph + screenshot placeholder)\n- Install for development: about:debugging → 'Load Temporary Add-on' → pick manifest.json\n- Packaging: 'bunx web-ext build' produces a signable .zip (web-ext is the standard Mozilla tool; bunx avoids global install)\n- License and attribution for vendored QR library\n- Privacy note: the extension makes no network requests","status":"in_review","priority":2,"issue_type":"task","owner":"olemd@glemt.net","parent":"firefox-share-as-qr-35mw","labels":[],"external_ref":null,"design":null,"acceptance":"- README.md explains install + dev workflow\n- Attribution for qrcode-generator present","notes":null,"closed_reason":null,"created_at":"2026-05-11T14:57:21.849005+02:00","created_by":"olemd@glemt.net","updated_at":"2026-05-11T15:45:48.234906+02:00","updated_by":"olemd@glemt.net","closed_at":null,"closed_by":null,"deleted_at":null,"deleted_by":null,"deleted_reason":null,"original_type":null,"comments":[],"duplicate_of":null,"snoozed_until":null,"metadata":{}}
{"record_type":"event","dcat_version":"0.12.1","event_type":"updated","issue_id":"firefox-share-as-qr-2slq","timestamp":"2026-05-11T15:45:48.234906+02:00","by":"olemd@glemt.net","changes":{"status":{"old":"open","new":"in_review"}},"title":"README and packaging instructions"}

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Dogcat JSONL merge driver
.dogcats/*.jsonl merge=dcat-jsonl

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.dogcats/config.local.toml
.dogcats/.issues.lock
.claude/settings.local.json
web-ext-artifacts/
node_modules/
dist/
bun.lockb
bun.lock

157
AGENTS.md Normal file
View file

@ -0,0 +1,157 @@
DOGCAT WORKFLOW GUIDE
## Rules
Run `dcat prime` after compaction, clear, or new session
BEFORE writing any code for a new bug, feature, or change:
ask the user if you should create an issue first. No exceptions
for 'small' tasks — the rule exists for traceability, not
because the task is complex.
When creating or updating issues, write them so a fresh agent
with no prior context can pick them up. Include the why,
relevant file paths, error messages, and acceptance criteria —
don't assume shared knowledge.
When creating issues, set appropriate labels using `--labels`
based on the issue content (e.g. `cli`, `tui`, `api`, `docs`,
`testing`, `refactor`, `ux`, `performance`, etc.).
Do NOT batch-mark an entire backlog as `in_progress` upfront.
Mark each issue `in_progress` right when you start working on it.
When running multiple `dcat` commands, make separate parallel
tool calls instead of chaining with `&&` and `echo` separators.
Before setting in_review: verify your work and cite actual output.
## Quick Start
Allowed issue types, priorities, and statuses:
Types: bug, chore, epic, feature, question, story, task
Priorities: 0 (Critical), 1 (High), 2 (Medium, default), 3 (Low), 4 (Minimal)
Statuses: draft, open, in_progress, in_review, blocked, deferred, closed
`dcat create` and `dcat update` both support --title, --description,
--priority, --acceptance, --notes, --labels, --parent, --manual,
--design, --external-ref, --depends-on, --blocks, --duplicate-of, --editor
1. Create: $ dcat create "Title" --type bug --priority 1 -d "Description"
2. List issues:
$ dcat list - All open issues
$ dcat list <parent_id> - Children of a parent
$ dcat ready - Ready to work (no blockers)
$ dcat blocked - All blocked issues
Use --namespace <ns> or --all-namespaces to filter.
3. Update: $ dcat update <id> --status in_progress
4. Close: $ dcat close <id> --reason "Fixed"
## Essential Commands
dcat create <title> - Create a new issue
dcat create <title> --depends-on <id> - Create with dependency
dcat create <title> --blocks <id> - Create issue that blocks another
dcat update <id> --depends-on <other_id> - Add dependency
dcat update <id> --blocks <other_id> - Mark as blocking another
dcat update <id> --remove-depends-on <id> - Remove a dependency
dcat update <id> --remove-blocks <id> - Remove a blocks relationship
dcat show <id> [<id> ...] - View one or more issues
dcat random - Show one random issue (same filters)
dcat search <query> - Search issues (supports --type filter)
dcat close <id> - Mark issue as closed
dcat reopen <id> - Reopen a closed issue
dcat delete <id> - Delete an issue (tombstone)
dcat pr - Show in-progress/in-review issues
dcat history - Show change history timeline
dcat history -i <id> - History for a specific issue
dcat diff - Show uncommitted issue changes
dcat label <id> add -l <label> - Add a label
dcat label <id> remove -l <label> - Remove a label
dcat link <id> add --related <other_id> - Link two issues
dcat link <id> remove --related <other_id> - Remove a link
dcat graph [<id>] - Visualize dependency graph
dcat comment <id> add -t "text" - Add a comment
dcat comment <id> list - List comments
dcat comment <id> delete -c <comment_id> - Delete a comment
## Parent-Child vs Dependencies
Parent-child is **organizational** (grouping), not **blocking**.
Children appear in `dcat ready` even when parent is open.
- Can start independently? → parent-child only
- Must parent complete first? → add dependency:
dcat update <child_id> --depends-on <parent_id>
## Breaking Down Large Tasks
For large/complex tasks, create an epic with child tasks:
$ dcat create "Redesign auth system" --type epic
$ dcat create "Add OAuth provider" --type task --parent <epic_id>
$ dcat create "Migrate sessions" --type task --parent <epic_id>
$ dcat update <task_id> --depends-on <other_task_id> # if ordering matters
Prefer multiple small, focused issues over one large issue.
If unsure about scope, ask the user before creating the breakdown.
## Agent Integration
`--agent-only` filters in list/ready exclude issues marked `--manual`:
dcat ready --agent-only # autonomous-workable
dcat list --agent-only # autonomous-workable
Mark `--manual` when a step requires a human in the loop —
credentials, deploys, hardware, visual confirmation, GUI keystrokes:
dcat update <id> --manual
`--manual` means HITL, not "agent skips". The filter exists so
autonomous-batch runs (no human present to consult) move past these.
When you are in session with a user, drive manual issues like any
other: do the analysis, frame the hypothesis, hand the user one
concrete action at a time, take their result, iterate. The human is
your hands for steps you can't reach; the rest is still your job.
## Comment-based filtering
List-style commands (list, ready, blocked, pr, snoozed, search, stale,
recently-closed, recently-added, etc.) accept --has-comments and
--without-comments to filter by comment presence. The two flags are
mutually exclusive and combine with other filters.
dcat list --has-comments # only issues with at least one comment
dcat list --without-comments # only issues with no comments
dcat ready --agent-only --has-comments
## Status Workflow
draft -> open -> in_progress -> in_review -> closed
## Questions
Questions (type: question) track questions needing answers, not tasks to work on.
## Labels
Freeform tags shown in list/show, filter with --label.
## Snooze
Temporarily hide issues from list/ready without changing status:
dcat snooze <id> 7d - Snooze for 7 days
dcat snooze <id> 2w - Snooze for 2 weeks
dcat snooze <id> --until 2026-04-01 - Snooze until a date
dcat unsnooze <id> - Remove snooze early
dcat snoozed - List currently snoozed issues
dcat list --include-snoozed - Show snoozed issues in list
Snoozed issues keep their original status and reappear automatically
when the snooze period expires.
## dogcat health check
✓ Inside a git repository
✓ .gitignore covers .issues.lock
✓ .dogcats/ is shared with team via git
✓ JSONL merge driver is configured
✓ .gitattributes has JSONL merge driver entry

65
README.md Normal file
View file

@ -0,0 +1,65 @@
# Share as QR
A small Firefox extension that turns the current tab's URL into a scannable QR
code, so you can hand a page off to a phone (or another machine) without
typing.
Click the toolbar icon → a popup shows the QR code plus a "Copy URL" button.
Nothing leaves your browser.
## Develop
This project uses [bun](https://bun.sh) as both the script runner and the
bundler. `popup/popup.js` imports the vendored QR library; `bun build` inlines
it into a single ESM file under `dist/`. Firefox loads the extension from
`dist/`, never from the source tree directly.
```sh
bun run build # bundle popup.js + assets into dist/
bun run lint # build + web-ext lint
bun run package # build + produce a signable .zip in web-ext-artifacts/
bun run start # build + launch Firefox with the extension loaded
```
To load the extension manually after a build:
1. Open `about:debugging#/runtime/this-firefox` in Firefox 142 or newer.
2. Click **Load Temporary Add-on…** and pick `dist/manifest.json`.
The temporary install is wiped when Firefox restarts; reload it the same way
during dev.
## Privacy
The extension makes no network requests. The QR code is generated locally in
the popup using the bundled `vendor/qrcode.js` library. The
`browser_specific_settings.gecko.data_collection_permissions` field in the
manifest declares "none" accordingly.
Permissions used:
- `activeTab` — read the active tab's URL when the popup opens.
- `clipboardWrite` — used by the Copy URL button.
Browser-internal URLs (`about:`, `chrome:`, `view-source:`, `moz-extension:`,
`data:`, `javascript:`, `resource:`) are not QR-encoded — the popup shows a
friendly message instead.
## Third-party code
- `vendor/qrcode.js` — [kazuhikoarase/qrcode-generator](https://github.com/kazuhikoarase/qrcode-generator),
pinned to commit `83b7e8fe3fddd3b0368dbafd6ce56995bd25e3c8`. MIT licensed;
full license text in `vendor/LICENSE.qrcode-generator` (also copied into
`dist/` so it ships with every build).
## Project layout
```
manifest.json MV3 manifest
popup/ Toolbar popup source (HTML/CSS/JS)
vendor/qrcode.js Bundled QR encoder (MIT, vendored, imported by popup.js)
icons/icon.svg Toolbar icon (single SVG, used at every size)
scripts/build.mjs Bun build + asset copy → dist/
web-ext-config.cjs Tells web-ext to operate on dist/
dist/ Build output (gitignored). What ships.
```

30
icons/icon.svg Normal file
View file

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Share as QR">
<rect width="32" height="32" rx="6" fill="#1f2937"/>
<g fill="#f9fafb">
<!-- Top-left finder -->
<path d="M5 5h8v8H5zM7 7v4h4V7z"/>
<rect x="8" y="8" width="2" height="2"/>
<!-- Top-right finder -->
<path d="M19 5h8v8h-8zM21 7v4h4V7z"/>
<rect x="22" y="8" width="2" height="2"/>
<!-- Bottom-left finder -->
<path d="M5 19h8v8H5zM7 21v4h4v-4z"/>
<rect x="8" y="22" width="2" height="2"/>
<!-- Data dots -->
<rect x="15" y="6" width="2" height="2"/>
<rect x="15" y="10" width="2" height="2"/>
<rect x="6" y="15" width="2" height="2"/>
<rect x="10" y="15" width="2" height="2"/>
<rect x="14" y="15" width="2" height="2"/>
<rect x="18" y="15" width="2" height="2"/>
<rect x="22" y="15" width="2" height="2"/>
<rect x="26" y="15" width="2" height="2"/>
<rect x="15" y="20" width="2" height="2"/>
<rect x="19" y="19" width="2" height="2"/>
<rect x="23" y="19" width="2" height="2"/>
<rect x="19" y="23" width="2" height="2"/>
<rect x="25" y="23" width="2" height="2"/>
<rect x="15" y="25" width="2" height="2"/>
<rect x="23" y="25" width="2" height="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

34
manifest.json Normal file
View file

@ -0,0 +1,34 @@
{
"manifest_version": 3,
"name": "Share as QR",
"version": "0.1.0",
"description": "Share the current tab's URL as a scannable QR code.",
"browser_specific_settings": {
"gecko": {
"id": "share-as-qr@olemd.local",
"strict_min_version": "142.0",
"data_collection_permissions": {
"required": ["none"]
}
}
},
"permissions": ["activeTab", "clipboardWrite"],
"action": {
"default_title": "Share page as QR code",
"default_popup": "popup/popup.html",
"default_icon": {
"16": "icons/icon.svg",
"32": "icons/icon.svg",
"48": "icons/icon.svg",
"96": "icons/icon.svg",
"128": "icons/icon.svg"
}
},
"icons": {
"16": "icons/icon.svg",
"32": "icons/icon.svg",
"48": "icons/icon.svg",
"96": "icons/icon.svg",
"128": "icons/icon.svg"
}
}

12
package.json Normal file
View file

@ -0,0 +1,12 @@
{
"name": "share-as-qr",
"version": "0.1.0",
"private": true,
"description": "Firefox extension: share the current tab's URL as a QR code.",
"scripts": {
"build": "bun run scripts/build.mjs",
"lint": "bun run build && bunx --bun web-ext lint",
"package": "bun run build && bunx --bun web-ext build --overwrite-dest",
"start": "bun run build && bunx --bun web-ext run"
}
}

98
popup/popup.css Normal file
View file

@ -0,0 +1,98 @@
:root {
color-scheme: light dark;
--bg: #ffffff;
--fg: #1f2937;
--muted: #6b7280;
--accent: #2563eb;
--accent-fg: #ffffff;
--border: #e5e7eb;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--fg: #f9fafb;
--muted: #9ca3af;
--accent: #3b82f6;
--accent-fg: #ffffff;
--border: #374151;
}
}
html, body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--fg);
font: 13px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif;
}
main {
width: 320px;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.qr {
width: 288px;
height: 288px;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid var(--border);
border-radius: 8px;
padding: 8px;
box-sizing: border-box;
}
.qr svg {
width: 100%;
height: 100%;
display: block;
}
.qr[data-empty="true"] {
background: var(--bg);
}
.message {
margin: 0;
color: var(--muted);
text-align: center;
}
.url {
margin: 0;
width: 100%;
font-size: 12px;
color: var(--muted);
overflow-wrap: anywhere;
word-break: break-all;
text-align: center;
max-height: 3.6em;
overflow-y: auto;
}
button {
font: inherit;
padding: 8px 14px;
border-radius: 6px;
border: 1px solid var(--accent);
background: var(--accent);
color: var(--accent-fg);
cursor: pointer;
}
button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
button:disabled {
opacity: 0.5;
cursor: default;
}

17
popup/popup.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Share as QR</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<main>
<div id="qr" class="qr"></div>
<p id="message" class="message" role="status" hidden></p>
<p id="url-text" class="url"></p>
<button id="copy" type="button">Copy URL</button>
</main>
<script type="module" src="popup.js"></script>
</body>
</html>

104
popup/popup.js Normal file
View file

@ -0,0 +1,104 @@
import qrcode from "../vendor/qrcode.js";
// Schemes that either can't be QR-encoded usefully or are browser-internal.
const PRIVILEGED_PROTOCOLS = new Set([
"about:",
"moz-extension:",
"chrome:",
"view-source:",
"resource:",
"javascript:",
"data:",
]);
qrcode.stringToBytes = qrcode.stringToBytesFuncs["UTF-8"];
const qrEl = document.getElementById("qr");
const messageEl = document.getElementById("message");
const urlEl = document.getElementById("url-text");
const copyBtn = document.getElementById("copy");
let currentUrl = "";
let copyResetTimer = null;
function showMessage(text) {
qrEl.replaceChildren();
qrEl.dataset.empty = "true";
messageEl.textContent = text;
messageEl.hidden = false;
copyBtn.disabled = true;
}
function isPrivileged(url) {
try {
return PRIVILEGED_PROTOCOLS.has(new URL(url).protocol);
} catch {
return true;
}
}
function renderQr(url) {
// EC level 'M' (~15%) balances scan robustness against QR density for screen display.
const qr = qrcode(0, "M");
qr.addData(url, "Byte");
qr.make();
const svgString = qr.createSvgTag({ cellSize: 4, margin: 2, scalable: true });
// Parse to a real DOM node rather than assigning innerHTML, to keep the
// string→DOM boundary explicit even though the bytes come from a trusted library.
const doc = new DOMParser().parseFromString(svgString, "image/svg+xml");
const svg = doc.documentElement;
if (svg.nodeName.toLowerCase() !== "svg") {
throw new Error("QR library did not return SVG");
}
qrEl.replaceChildren(svg);
qrEl.dataset.empty = "false";
messageEl.hidden = true;
}
async function init() {
let tabs;
try {
tabs = await browser.tabs.query({ active: true, currentWindow: true });
} catch (err) {
showMessage("Could not read the active tab.");
return;
}
const url = tabs?.[0]?.url;
if (!url) {
showMessage("No URL available for this tab.");
return;
}
currentUrl = url;
urlEl.textContent = url;
if (isPrivileged(url)) {
showMessage("This page can't be shared (browser-internal URL).");
return;
}
try {
renderQr(url);
} catch (err) {
// qrcode-generator throws when the data exceeds the largest QR version (~2,953 bytes for L).
showMessage("URL is too long to encode as a QR code.");
}
}
copyBtn.addEventListener("click", async () => {
if (!currentUrl) return;
try {
await navigator.clipboard.writeText(currentUrl);
copyBtn.textContent = "Copied!";
} catch (err) {
copyBtn.textContent = "Copy failed";
}
clearTimeout(copyResetTimer);
copyResetTimer = setTimeout(() => {
copyBtn.textContent = "Copy URL";
}, 1200);
});
init();

29
scripts/build.mjs Normal file
View file

@ -0,0 +1,29 @@
import { rm, cp } from "node:fs/promises";
const DIST = "dist";
await rm(DIST, { recursive: true, force: true });
const result = await Bun.build({
entrypoints: ["popup/popup.js"],
outdir: `${DIST}/popup`,
target: "browser",
format: "esm",
minify: true,
});
if (!result.success) {
for (const log of result.logs) console.error(log);
process.exit(1);
}
await Promise.all([
cp("manifest.json", `${DIST}/manifest.json`),
cp("popup/popup.html", `${DIST}/popup/popup.html`),
cp("popup/popup.css", `${DIST}/popup/popup.css`),
cp("icons", `${DIST}/icons`, { recursive: true }),
cp("vendor/LICENSE.qrcode-generator", `${DIST}/LICENSE.qrcode-generator`),
]);
const size = (await Bun.file(`${DIST}/popup/popup.js`).arrayBuffer()).byteLength;
console.log(`Built ${DIST}/ (popup.js: ${(size / 1024).toFixed(1)} KB)`);

21
vendor/LICENSE.qrcode-generator vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2009 Kazuhiko Arase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2303
vendor/qrcode.js vendored Normal file

File diff suppressed because it is too large Load diff

4
web-ext-config.cjs Normal file
View file

@ -0,0 +1,4 @@
module.exports = {
sourceDir: "dist",
artifactsDir: "web-ext-artifacts",
};