|
18 | 18 |
|
19 | 19 | - [save-all-chats] Save All Chats feature: FloatingDial speed-dial action calls listConversations() then fetchThread() with per-provider jittered delays. Threads sent in batches of 10 via SAVE_BULK_DATA message. Vault uses saveBulkThreads() for single-write batch upsert. Skips already-saved threads by comparing updatedAt. AbortController for cancellation. Gemini excluded (intercept-only). |
20 | 20 |
|
21 | | - |
22 | 21 | - [unlimited-storage-permission] The extension declares the unlimitedStorage permission in the manifest to support bulk-saving hundreds of threads without hitting the default 10 MB chrome.storage.local quota. Users upgrading from a version without this permission will be prompted to re-approve the extension. |
23 | 22 |
|
24 | 23 | - [gemini-exclusion-policy] Gemini is permanently excluded from any feature that requires background or bulk API fetching because its extraction relies solely on a MAIN-world fetch interceptor. Any new bulk or batch feature must document this exclusion explicitly. |
|
29 | 28 |
|
30 | 29 | - [save-all-minimize] Save All modal has a Minimize2 button (visible during listing/saving) that hides the modal while saving continues. FAB shows an SVG arc ring (58px, r=26, circumference=163.4, starts at 12-o'clock) + numeric badge (n/total or …) while minimized. Clicking the FAB reopens the modal. Phase done/cancelled auto-resurfaces the modal by setting saveAllMinimized=false. |
31 | 30 |
|
32 | | -- [save-all-fab-spec] While the Save All modal is minimized, the FAB displays an SVG arc progress ring (58px diameter, radius 26, circumference 163.4, origin at 12-o'clock) with a numeric badge showing completed/total or an ellipsis during indeterminate phases. Clicking the FAB reopens the modal. When the save phase reaches done or cancelled, the modal auto-resurfaces by setting saveAllMinimized to false. |
33 | | - |
34 | 31 | - [modal-minimize-behavior] The Save All modal exposes a Minimize button (Minimize2 icon) that is visible only during the listing and saving phases. Pressing it hides the modal visually while the save operation continues uninterrupted in the background. No other modal in the extension has a minimize affordance. |
35 | 32 |
|
36 | 33 | - [save-all-skip-policy] Save All must skip any thread whose updatedAt timestamp matches the value already stored in the Vault, avoiding redundant network fetches and storage writes for unchanged conversations. |
| 34 | + |
| 35 | +- [gemini-intercept-only] Gemini extraction relies exclusively on a MAIN-world fetch interceptor that captures responses in-page. No background API calls, no listConversations, and no fetchThread implementation exist or should be added for Gemini. Any extractor code for Gemini must be scoped entirely to the content script MAIN world. |
| 36 | + |
| 37 | +- [universal-json-schema] All extracted chat data must be normalised into the Universal JSON Schema before being sent to the background worker via SAVE_EXTRACTED_DATA or SAVE_BULK_DATA. No provider-specific shape may be written directly to chrome.storage.local. Transformation to the Universal schema is always the content script's responsibility. |
| 38 | + |
| 39 | +- [gemini-save-all-ui-exclusion] The Save All Chats UI must explicitly hide or disable the Save All action for Gemini sessions. If the active provider is detected as Gemini, the feature must be omitted from the FloatingDial and no listConversations or fetchThread call may be attempted for it. |
| 40 | + |
| 41 | +- [save-bulk-data-background-write] The background worker's handler for SAVE_BULK_DATA must call saveBulkThreads as a single atomic upsert per batch. It must never iterate the batch and write threads one at a time, and it must never pass raw provider data directly to storage without a prior Universal JSON transformation having been completed in the content script. |
| 42 | + |
| 43 | +- [export-import-feature] Export: EXPORT_VAULT message → vault.exportAll() → downloads aichatbackup-<date>.json. Import parsing runs in options page (Blob#text() + detectAndAdapt), then sends IMPORT_THREADS to background. Supports: own format, ChatGPT conversations.json, Claude export. Gemini/Perplexity/Grok stubs (isXxx always false). lastExportedAt stored at vault:meta:lastExportedAt, read directly via chrome.storage.local in options page. |
| 44 | + |
| 45 | +- [uninstall-safety] onInstalled listener in background sets setUninstallURL to https://vchan-in.github.io/migrate/uninstall. Options sidebar shows amber nudge if never exported or last export > 7 days ago. |
| 46 | + |
| 47 | +- [uninstall-url-registration] The background service worker must register the uninstall URL by calling chrome.runtime.setUninstallURL with the value https://vchan-in.github.io/migrate/uninstall inside a chrome.runtime.onInstalled listener. This must be done unconditionally on every install and update event. |
| 48 | + |
| 49 | +- [export-nudge-policy] The Options sidebar must display an amber nudge indicator whenever the user has never exported their Vault or the lastExportedAt timestamp is more than 7 days in the past. This nudge must be driven by reading vault:meta:lastExportedAt from chrome.storage.local at Options page load time. |
| 50 | + |
| 51 | +- [import-format-detection] Import parsing is the responsibility of the options page, not the background worker. The options page reads the uploaded file via Blob text, runs detectAndAdapt to normalise it into Universal JSON, and only then sends an IMPORT_THREADS message to the background. The background worker must never receive or parse raw third-party export formats. |
| 52 | + |
| 53 | +- [markdown-rendering] Messages in the dashboard render markdown via react-markdown + remark-gfm + @tailwindcss/typography. MarkdownContent component lives in src/components/MarkdownContent.tsx. Overflow is hard-capped: pre=overflow-x-auto, img=max-w-full, table wrapped in overflow-x-auto div, links=break-all. |
| 54 | + |
| 55 | +- [message-copy-share] Per-message actions: Copy (MD/TXT toggle, shared copyMode state) + Share (Web Share API with clipboard fallback). Action bar is hover-revealed via Tailwind group/group-hover pattern. stripMarkdown utility lives in src/utils/stripMarkdown.ts (regex-only, no deps). |
0 commit comments