Commit graph

396 commits

Author SHA1 Message Date
tux tucker
d7cc384fba untrack .gitignore 2026-05-18 22:41:52 -04:00
tux tucker
515474b8a2 Merge testing into main for v1.10.17 release 2026-05-18 22:33:09 -04:00
tux tucker
aec2906fb2 Import Backup: ask mode before opening file picker (v1.10.17)
Old flow: click Import Backup -> OS file picker opens -> select file
-> modal asks merge/replace. Awkward because the user was already
deep in a filesystem dialog before being asked the meaningful
question.

New flow: click Import Backup -> modal asks merge/replace + "Choose
File..." -> file picker opens -> import runs with the chosen mode.

Refactor:
- showImportBackupModal(backup, onConfirm) -> showImportModeModal(onConfirm).
  No longer takes a file/backup arg; no file-contents preview (snapshot
  /export counts, creation date) since the file isn't selected yet.
  Modal copy now reads "Choose how the imported data should be
  combined with your current data, then pick a backup file."
- importBackup(file, onComplete) -> importBackup(file, mode, onComplete).
  No internal modal call; just validates the file and applies the
  pre-chosen mode.
- options.js and browse.js each gained a pendingImportMode state
  variable that bridges the async modal-close -> file-picker-change
  boundary. Consumed and reset on file-picker change to prevent stale
  reuse.

Both browsers identical. Tests still pass (54/54).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 22:30:00 -04:00
tux tucker
e97cd37ea2 Export Selected: include checked chats hidden by filter (v1.10.16)
exportAllFiltered was intersecting selectedConversations with
filteredConversations, so any chat the user had checked but later
filtered out (e.g. via the funnel "New / Updated" filter or by typing
a search term) was silently excluded from the export. The "Export
Selected (N)" button text continued to show the full selection
count, so the user got fewer chats than they expected.

Now uses allConversations.filter() when selectedConversations.size > 0
so every checked chat ships, regardless of current view state. The
header select-all checkbox still only operates on visible rows
(unchanged) — that's the user's preferred behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 22:24:50 -04:00
tux tucker
a384177b95 Mark v1.9.5-v1.10.15 as published 2026-05-18 22:20:08 -04:00
tux tucker
c0990b8589 Merge testing into main for v1.10.15 release
Resolved conflicts:
- chrome/firefox manifest.json: kept main's name ("Claude Exporter"),
  testing's version (1.10.15)
- root CHANGELOG.md deleted (moved to docs/CHANGELOG.md per testing)
2026-05-18 22:17:49 -04:00
tux tucker
64bc4dc07f Bump manifests to 1.10.15 + changelog (follow-up to f125602)
Previous commit landed the code fix and tests but the manifest/changelog
edits failed (file-modified-since-read race) and weren't retried.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 22:08:16 -04:00
tux tucker
f125602d12 Fix artifact extraction for create_file MCP tool (v1.10.15)
When Anthropic's `enabled_artifacts_attachments` conversation setting
is false, Claude creates files via the skills-runner `create_file` MCP
tool instead of the legacy `artifacts` tool. The display_content shape
is identical (json_block with language / code / filename), only the
tool_use.name differs. The v1.9.1 strict allowlist was rejecting it,
silently dropping every artifact in those conversations.

Allowlist now accepts both 'artifacts' and 'create_file'. Other skills
tools that happen to share json_block display (view, list_directory,
etc.) stay filtered out by name.

Two regression tests added:
- positive: create_file with markdown json_block extracts correctly
- negative: view tool with similar json_block stays filtered

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 22:06:43 -04:00
tux tucker
bec92d687f Restore artifact count in unified export toast (v1.10.14)
After v1.10.13 deduplicated the export toast to a single emit per
call, the "with N artifact(s)" detail was lost. Restored it without
re-introducing the double-toast pattern:

- Added function-scope `let artifactCount = 0;` at the top of
  exportConversation.
- Set artifactCount = artifactFiles.length inside the artifact
  extraction branch when files are actually found.
- Unified post-save toast now reads:
    artifactCount > 0
      ? "Exported: X with N artifact(s)"
      : "Exported: X"

Both browsers identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:48:46 -04:00
tux tucker
8d0e998ea8 Fix duplicate export toast in chrome browse.js (v1.10.13)
exportConversation was emitting three toasts on a successful export
with artifacts:
  1. "Exporting X..." (line 656)
  2. "Exported: X with N artifact(s)" (line 741, branch-specific)
  3. "Exported: X" (line 794, unified post-save)

Same triple-emit on the "no artifacts found" sub-branch (lines 656,
762, 794). The "normal export without artifact extraction" branch
correctly only emitted two (initial + unified).

Removed the branch-specific toasts at 741 and 762 — the unified
post-save toast at line 794 already covers all three branches.
Firefox already had this pattern (commented "Toast handled below
after timestamp save"). Chrome had regressed.

Trade-off: lose the "with N artifact(s)" detail from the toast,
gain consistent single-emit UX across all export paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:46:24 -04:00
tux tucker
0bc0158f2e Chrome/Firefox parity sync pass (v1.10.12)
Multiple files had drifted out of sync over recent commits. Brought
Firefox in line with Chrome (canonical copy per CLAUDE.md):

- popup.html: removed Chrome typo "dd" after --error-text: #ff9999;
- popup.html: synced firefox label { margin: 6px 0 } -> 6px (chrome's value)
- browse.html: synced firefox td { padding: 15px } -> 15px 20px
- browse.html: removed stale .btn-view CSS from firefox (the v1.10.9
  cleanup only touched chrome)
- browse.html: bumped firefox body min-width 1140 -> 1200 and added
  min-width: 1200px to .container to match chrome's recent tweak
- browse.js: synced firefox tooltip label "Now using" -> "Currently"
- options.html: synced firefox width: 800px -> 810px
- content.js: removed firefox-only [Claude Exporter] debug console.log
  lines at top of file

Legitimate differences left alone:
- background.js: chrome MV3 scripting.executeScript vs firefox MV2
  tabs.executeScript loop (per CLAUDE.md API differences)
- popup.js: chrome.tabs.* (chrome) vs browser.tabs.* (firefox idiom)

Uncertain (left for direction):
- browse.js exportConversation toast handling differs (chrome emits
  inline showToast per branch; firefox has them removed with a
  "Toast handled below after timestamp save" comment, but no
  unified toast was found later in the function)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:44:11 -04:00
tux tucker
48c1e91e68 Sync firefox .checkbox-col with chrome (right-align + 25px padding)
Firefox had drifted to padding: 15px 10px and text-align: center.
Missed in the previous commit. Bringing both browsers back in sync
per the parallel-browsers rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:31:07 -04:00
tux tucker
d62d822118 Anchor checkbox right; keep header + sort icon on one line (v1.10.11)
- .checkbox-col now text-align: right (was center). With center +
  padding 15/25, the checkbox drifted toward the middle of the cell
  whenever the table grew wider than its min-width. Right-aligning
  pins the checkbox to the cell's right edge with the existing 25px
  right padding regardless of cell width.

- th: added white-space: nowrap and bumped padding-right from 15px
  to 25px. Headers can no longer wrap onto multiple lines on narrow
  columns, and the extra right padding guarantees room for the
  absolute-positioned sort-direction arrow without text collision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:30:31 -04:00
tux tucker
9e755e9ed6 Browse page: body min-width so table never shrinks (v1.10.10)
Previously, even with the table's min-width: 1100px, the
.conversations-table parent stayed at body width (= viewport width),
and its overflow: hidden was clipping the table's right side rather
than letting the page grow.

Set body { min-width: 1140px } (= 1100 table min-width + 2*20px
.container padding). Now the body is forced to at least 1140px, the
table sits inside at its full natural width, and when the viewport
is narrower than 1140 the PAGE scrolls horizontally. Single page
scrollbar, no internal table scroll, all columns always visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:11:46 -04:00
tux tucker
d52a280979 Drop View button + page-level horizontal scroll (v1.10.9)
- Removed the redundant "View" button from each conversation row in
  the browse table. The chat name in the Name column is already an
  <a> link to the conversation, so View was duplicating that action.
  Dropped the button markup, its click handler, and the .btn-view
  CSS rules. Narrower Actions column.

- Reverted the table-level horizontal scroll from v1.10.6/1.10.7:
  .conversations-table is back to overflow: hidden, so when the
  viewport is narrower than the table's min-width, the PAGE scrolls
  horizontally instead of the table getting its own scrollbar. User
  preferred this — single scrollbar rather than two.

- Table min-width: 1200px -> 1100px since the Actions column is
  narrower now.

The flex-wrap cascade from v1.10.7/1.10.8 stays so the header
controls still wrap and don't unnecessarily inflate page width.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:03:06 -04:00
tux tucker
c344ada75a Cascade flex-wrap through export controls (v1.10.8)
v1.10.7's .controls flex-wrap let the three outer groups (search,
filter, export controls) wrap, but the export-controls-wrapper was
itself a fixed-width row (Chat format + 3 checkboxes + divider +
Artifact format + 3 checkboxes + Export All button) at ~900px wide,
which kept forcing the body wider than the viewport.

Added flex-wrap: wrap to .export-controls-wrapper, .export-settings,
.export-row, and .export-section so individual checkbox labels can
wrap to multiple rows on narrow viewports. With the page no longer
overflowing horizontally, the table's overflow-x: auto + min-width:
1200px finally provides its own internal scrollbar without dual
page-level + table-level scrolling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:55:21 -04:00
tux tucker
cf6a063db1 Fix narrow-viewport layout: controls wrap, table min-width (v1.10.7)
v1.10.6's overflow-x: auto on .conversations-table didn't actually
help because (a) the table had width: 100% with no min-width, so it
shrank to fit the container instead of overflowing, and (b) the
header controls had no flex-wrap, so they forced the whole page
wider than the viewport, creating page-level horizontal scroll that
confused the cutoff visual.

Two changes:
- .controls { flex-wrap: wrap }: header items (search box, filter
  funnel, export controls wrapper) now stack to multiple rows on
  narrow viewports. No more page-level horizontal scroll.
- table { min-width: 1200px }: keeps columns usable AND triggers the
  .conversations-table overflow-x: auto when viewport is narrower
  than 1200px, giving the table its own horizontal scrollbar within
  the container.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:51:52 -04:00
tux tucker
e17314674c Fix browse table cutoff in narrow windows (v1.10.6)
.conversations-table had overflow: hidden, which clipped the right
side of the table when the browser window was narrower than the
table's natural width AND prevented any scrollbar from appearing.

Switched to overflow-x: auto so the table scrolls horizontally on
demand. Border-radius still clips the rounded corners; the existing
container max-width caps things on the upper end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:44:30 -04:00
tux tucker
aec1345dec Gitignore .markdownlint.json
Local markdownlint override (disables MD036) lives at src/.markdownlint.json
and shouldn't be tracked. The _Published_ markers in docs/CHANGELOG.md are
intentional convention but trigger no-emphasis-as-heading on every CHANGELOG
edit, which created persistent IDE diagnostic noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:42:40 -04:00
tux tucker
d76bd1042f Slim Contact & Diagnostics to inline links (v1.10.5)
Replaced the three Contact & Diagnostics buttons (Email developer,
Generate diagnostics, Clear log) with two inline anchors inside a
single sentence:

  Found a bug or have feedback? [Email the developer]. If reporting
  a bug, please [attach a diagnostics file] (extension/browser info,
  stored counts, recent errors -- all UUIDs redacted, no conversation
  content).

Reasoning: most users who actually file bug reports are technical
enough to recognize underlined links as actions, and a section with
three buttons + two paragraphs read as cluttered.

- Removed clearDiagnosticsBtn entirely and the clearDiagnosticsLog
  helper in utils.js (nothing calls it now).
- Added .section a link styling (--link-color / --primary-hover) so
  the new inline anchors look correct in both light and dark mode
  instead of using browser default link colors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:39:34 -04:00
tux tucker
c53ace8054 Bind UI listeners before conversations load (v1.10.4)
setupEventListeners() now runs immediately after initTheme() instead
of after the await chain for loadOrgId / load*Prefs / loadConversations.
The settings gear, filter funnel, search bar, and other UI controls
are interactive from the start of the loading screen instead of only
after the conversation list arrives.

Handlers that read conversation data either iterate empty arrays
harmlessly or already guard with `if (data)` checks, so attaching
them early is safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:32:24 -04:00
tux tucker
a55d0e7490 Add Contact & Diagnostics section to Options (v1.10.3)
New Options section with three buttons:
- Email developer: opens a mailto with pre-filled subject (incl. version)
  and a short body template
- Generate diagnostics: downloads a sanitized JSON bundle the user can
  attach to a bug report
- Clear log: wipes the captured error ring buffer

Error capture (utils.js):
- initErrorCapture(context) registers window.error +
  unhandledrejection listeners that push entries to a 50-entry FIFO
  ring buffer in chrome.storage.local (errorLog key)
- Sanitization runs at capture time: UUID-shaped substrings (chat /
  org / project IDs that may appear in fetch URLs or stack traces)
  replaced with "<id>" before they hit storage
- Re-entry guard prevents the listener from looping on its own writes
- Called from popup, browse, content, options. Skipped in background --
  it's tiny and would need importScripts overhead for marginal value.

Diagnostics bundle includes: extension/browser version, navigator UA
+ platform + language, counts of modelSnapshots / exportTimestamps /
errors, current preferences (dateFormat, timeFormat, modelDisplay),
orgIdConfigured boolean (NOT the value), and the error log. No
conversation content. No org ID. Nothing is sent anywhere -- user
downloads the file and chooses whether to attach.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 19:11:13 -04:00
tux tucker
85da733d62 Dropdown cleanup + bounce marker polish + auto popup title (v1.10.2)
- Removed "Test connection" item from the browse settings dropdown
  (chrome+firefox HTML + JS handler). Available in Advanced Options.

- Model column "*" bounce marker:
  - Color now matches the badge per family (sonnet/opus/haiku/default)
    instead of always rendering var(--badge-default) at 0.7 opacity.
  - Tooltip on the bounced cell now fires when hovering EITHER the
    badge or the asterisk: wrapped both in a .model-cell span that
    carries the title + cursor: help.

- Popup header (#header-title) is now populated from manifest.name in
  popup.js — testing branch's "Claude Exporter Beta" surfaces in the
  popup automatically without a separate HTML edit per branch.

- src/CLAUDE.md extended the existing manifest-name rule to note that
  popup.js reads manifest.name into #header-title. (Workspace-root
  CLAUDE.md was mirrored locally but isn't tracked in git.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:52:17 -04:00
tux tucker
02ade4b896 Add "Search projects" funnel option (v1.10.1)
New 4th option in the browse page filter dropdown, separated from the
existing status filters by a divider. When selected:

- Search bar placeholder switches to "Search projects by name..."
- applyFiltersAndSort branches: search term is matched against the
  conversation's project name (via getProjectName); conversations
  without a project ("-") are excluded
- Status filter logic (new/exported) is skipped in this mode — the
  funnel option is the active filter

Filter button still gets its "active" highlight since the selection is
not the default "all".

Version jumped 1.9.17 → 1.10.1 per request (skipping 1.10.0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:36:44 -04:00
tux tucker
4a6b7d6930 Revert Model Display 2-col grid; back to stacked layout (v1.9.17)
The two-column layout from v1.9.16 cramped the radio descriptions.
Stacked layout reads cleaner — restoring it and dropping the
.model-display-grid CSS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:32:49 -04:00
tux tucker
d7adf70446 Options opens in same tab; model display radios in 2 columns (v1.9.16)
- Browse dropdown's "Edit Org ID" and "Advanced Options" now navigate
  the current tab to options.html via window.location.href instead of
  chrome.runtime.openOptionsPage() (which spawns a new tab on both
  Chrome MV3 and Firefox with open_in_tab). The browser back button
  returns to the browse view, restoring its scroll position.

- Browse page listens for pageshow with event.persisted === true
  (bfcache restore) and reloads itself. Without this, hitting Back
  would restore the cached page with stale preferences and the user
  would have to refresh manually.

- Model Display radios wrapped in a .model-display-grid (2-column),
  matching the Date & Time Format section's two-column layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:31:40 -04:00
tux tucker
cb4b0d1ffc Backup filename: claude-exporter-backup-YYYYMMDD-HHMMSS.json (v1.9.15)
Reverts the v1.9.14 rename to claude-database-* and replaces the ISO-
with-dashes timestamp with the YYYYMMDD-HHMMSS format already used by
conversation/artifact export filenames (see getLocalDateTimeString in
content.js / browse.js).

Inlined the date formatting here rather than extracting a third copy
of the helper — utils.js doesn't currently expose one and pulling
content.js/browse.js's copy into utils.js is scope creep beyond the
filename fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:28:14 -04:00
tux tucker
51ceebb71d Default Model column to original; configurable in Options (v1.9.14)
- Backup filename prefix: claude-exporter-backup-* → claude-database-*
  (same timestamp format, still JSON)
- Browse Model column display is now controlled by a new modelDisplay
  preference saved in chrome.storage.local. Default is 'original'
  (revert of v1.9.12's flip-to-current), with 'current' available as
  an opt-in via a new "Model Display" section on the Options page.
- Bounced chats keep the "*" marker in either mode. Tooltip text
  adapts: "Originally X" when displaying current, "Now using X" when
  displaying original. Bounce signal is preserved regardless of which
  model the cell shows.
- getDisplayModel now returns { model, other, otherLabel, bounced }
  with the displayed value chosen by the preference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:22:34 -04:00
tux tucker
3ff9b89ee2 Rename Backup/Restore to Export/Import + add merge mode (v1.9.13)
Renames throughout the UI:
- Options page buttons: "Download Backup" → "Export Backup",
  "Restore from File" → "Import Backup"
- Browse dropdown items: "Backup" → "Export Backup",
  "Restore" → "Import Backup"

Import now opens a custom modal (built and styled from utils.js so it
works identically on both options and browse pages) showing the backup
file's contents (snapshot/export counts + creation date) and letting
the user choose:

- Merge (default): missing keys added from backup; for plain-object
  values (UUID-keyed records like exportTimestamps and modelSnapshots),
  sub-keys are merged with local winning on overlap. Scalar conflicts
  (org ID, date format, etc.) keep the local value.
- Replace all: prior behavior — overwrite local data with the backup.

Modal supports Esc to cancel, Enter to import, and click-outside to
cancel. Z-index 100000 to clear the browse-page sticky header.

Function rename: restoreExtensionData → importBackup. mergeStorageData
helper added (exported for future tests). Toast wording adjusted to
match the new vocab ("Backup exported", "Import complete (merge)" /
"(replace)", "Import cancelled").

Bundled the in-progress button padding tweak (5px → 8px) and mirrored
it to firefox/options.html for parity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:17:54 -04:00
tux tucker
e79bc7a7f3 Flip Model column to show current model with * marker (v1.9.12)
Model column previously displayed the original (first-seen) model since
v1.9.4. Flipped to show the **current** model so the cell reflects what
model the chat will actually use on reopen. Bounced chats (current
differs from first-seen) get a small "*" asterisk marker with an
"Originally X" tooltip — replaces the prior "→" arrow.

getDisplayModel now returns { model: current, original, bounced }.
Sorting follows the new display name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:58:38 -04:00
tux tucker
94ca3b1352 Options page layout polish (v1.9.11)
- Merged Test Connection into the Organization ID section next to
  Save Settings using a flex .button-row container. Dropped the
  standalone "Test Your Settings" section.
- Fixed button text vertical centering with inline-flex + line-height: 1
  (was inheriting body's 1.6 line-height, shifting the perceived
  baseline relative to the smaller 5px symmetric padding).
- Date/Time format selects now sit side-by-side in a two-column grid
  instead of stacked.
- Mirrored prior chrome/options.html CSS tweaks (800px width, button
  padding, .section h3 margins) into firefox/options.html — Firefox
  copy had fallen behind.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:54:09 -04:00
tux tucker
ed185c5968 Popup org-ID error wording + lowercase claude.ai (v1.9.10)
Popup error when org-ID detection fails now reads:
"Failed to obtain organization ID: Please set this value in Options."
"Options" is a clickable link that opens the options page (same DOM
pattern as the existing 403/404 hint).

Lowercased "Claude.ai" → "claude.ai" in all user-facing strings across
popup.js, browse.js, and options.js (chrome + firefox) to match the
actual domain. Comments and HTML titles left as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:48:18 -04:00
tux tucker
422e728291 Remove redundant org ID setup banner from popup (v1.9.9)
Org ID is auto-detected on every export action since v1.8.12, so the
upfront "Organization ID not configured" banner was dead weight. Dropped
the #setupNotice div, the load-time auto-detect-or-warn check, and the
options-page link handler. Updated the fallback export-button error
message to suggest opening the popup from a claude.ai tab instead of
pointing at the now-removed link. Manual override on the options page is
preserved as the fallback path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:34:01 -04:00
tux tucker
6560751294 Restore blank line between TODO.md title and Pending heading (MD022) 2026-05-15 00:23:32 -04:00
tux tucker
3066621889 Fix: v1.9.8 TODO entry was misplaced at top; move to Completed section 2026-05-15 00:21:23 -04:00
tux tucker
846f6557b9 Markdown export: add truncated flag and attachment metadata
The markdown export was missing the truncated flag and per-message
attachment metadata (file_name, file_size, file_type) that the JSON
export already includes. File attachments now render as:
  ### Attachment: <name> _(size, type)_
followed by extracted_content in a quadruple-backtick block. Pasted
content (no file_name) keeps the existing ### Pasted label.

Adopted from upstream commit 318d4a7. Skipped the manifest rename to
"Local" since the project uses the "Beta" suffix convention on testing.
2026-05-15 00:08:44 -04:00
tux tucker
54278ac6ce Gitignore .claude/ and .vscode/ 2026-05-14 23:20:07 -04:00
tux tucker
29239943f4 Move CHANGELOG, INSTALL, TODO into docs/
Reorganize repo root: the three doc files now live in docs/. README links
updated by user; CLAUDE.md path refs (Documentation Upkeep and Release
Process sections) updated to match. Rename detection preserves history.
2026-05-14 23:12:01 -04:00
tux tucker
1dea046f69 Move test harness to tests/; untrack package-lock.json
Tidy the repo root: package.json moves to src/tests/ (still tracked) so the
Vitest harness lives next to the tests it runs. package-lock.json is now
untracked (matches CLAUDE.md's stated intent) -- gitignored at the new path.
node_modules/ moved alongside (still gitignored).

Run npm test from src/tests/ now (not src/). CLAUDE.md Testing section
updated.
2026-05-14 22:56:45 -04:00
tux tucker
b1ade4c2aa Restructure browse dropdown: Backup/Restore submenu, Date/Time to options page
- Date and Time format toggles moved out of the browse dropdown into a new
  'Date & Time Format' section on the options page
- That dropdown slot now holds 'Backup/Restore Database' with a hover flyout
  submenu (Backup / Restore)
- Backup/Restore core logic extracted to shared utils.js (backupExtensionData,
  restoreExtensionData); options page and browse dropdown both call it
- Version bumped to 1.9.7
2026-05-14 22:27:14 -04:00
tux tucker
cb1c21f580 Add Advanced Options link to browse settings dropdown
New divider-bounded 'Advanced Options' item between Time and Test connection;
opens the options page via chrome.runtime.openOptionsPage(), same pattern as
Edit Org ID. Makes Backup & Restore reachable from the browse view.
2026-05-14 22:01:37 -04:00
tux tucker
c61d8c8d53 Add Backup & Restore for extension data in options page
Download all chrome.storage.local + chrome.storage.sync data to a structured
JSON file ({_meta, local, sync}) and restore it later. Solves uninstall/
reinstall data loss and migration between separate extension builds (store
vs. GitHub) that have separate storage. Restore validates _meta.app and
confirms before overwriting.
2026-05-14 21:55:33 -04:00
tux tucker
59280d058d Add TODO: revisit redundant org ID setup UI (keep manual override as fallback) 2026-05-14 17:59:12 -04:00
tux tucker
6842e37785 Mark v1.9.2-1.9.4 as published 2026-05-14 17:00:57 -04:00
tux tucker
3b9e722802 Mark v1.9.2-1.9.4 as published 2026-05-14 17:00:56 -04:00
tux tucker
93113209f2 Merge branch 'testing'
# Conflicts:
#	chrome/manifest.json
#	firefox/manifest.json
2026-05-14 16:55:32 -04:00
tux tucker
64fa60e9df Show original (first-seen) model in browse table Model column
getDisplayModel() resolves each conversation to its first-seen model from
the modelSnapshots map, falling back to the current/inferred model when no
snapshot exists. Bounced chats (original != current) get a → marker with an
'Originally X, now Y' tooltip. Model column sorting follows the displayed
model.
2026-05-14 16:44:00 -04:00
tux tucker
db597c709f Snapshot conversation models on list fetch to survive model retirement
recordModelSnapshots() persists each conversation's current API model to
chrome.storage.local whenever the conversation list is fetched (browse page
load or popup Export All). Stores first-seen, current, and change history
per UUID — raw API model only, never an inferred guess. Mirrors the existing
exportTimestamps tracking pattern.
2026-05-14 16:36:40 -04:00
tux tucker
1106083960 Merge branch 'testing'
# Conflicts:
#	chrome/manifest.json
#	firefox/manifest.json
2026-05-14 16:28:50 -04:00
tux tucker
c1dd3f31d5 Bump version to 1.9.2 2026-05-14 16:27:51 -04:00