# Changelog All notable changes to this project will be documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [0.4.0] - Unreleased ### Added - Rich content support: messages now carry an ordered `blocks` list (text, code, thinking, tool_use, tool_result, citation, image_placeholder, file_placeholder, unknown) - ChatGPT voice mode: `audio_transcription` parts render as text blocks; `audio_asset_pointer` and `real_time_user_audio_video_asset_pointer` render as `📎 File attached` placeholders with size and duration metadata - ChatGPT Custom Instructions: `user_editable_context` and `model_editable_context` messages now appear in exports (were silently dropped — pre-existing bug fixed); rendered with a `> â„šī¸ Hidden context` marker driven by the `is_visually_hidden_from_conversation` flag - Image placeholders for `image_asset_pointer` parts (uploads + DALL-E) inside `multimodal_text` and at message level - Defensive Claude block extraction: `text`, `thinking`, `tool_use`, `tool_result` (including nested-block flattening), `image` blocks (untested against real data; will fix-forward in v0.4.1 if real shapes diverge) - `LossReport` summary table emitted at end of every `export` run, breaking down `unknown blocks` and `extraction failures` by raw type so silently-dropped data becomes visible - `_safe_fence` helper picks a fence longer than any backtick run in extracted content, preventing embedded triple-backticks from corrupting downstream rendering (verified live in Joplin during planning) - `unknown` blocks render as `> âš ī¸ Unsupported content` with the raw type, observed top-level keys, and reason — so future API additions are visible rather than silent ### Changed - ChatGPT role filter (previously dropped `tool` and `system` messages) is **lifted**: all roles now route through normal extraction; truly empty messages skip via the existing empty-content guard - Markdown rendering moves from provider-time to exporter-write-time. Providers produce blocks; exporters call `render_blocks_to_markdown` at write time. This unblocks future Obsidian/HTML exporters - `BaseProvider.normalize_conversation` signature now accepts an optional `LossReport` parameter (breaking change for any future custom subclass; FileProvider hasn't shipped yet) - `o1`/`o3` reasoning subparts inside `text` content_type messages remain rendered as plain text (defensive; reclassification to `thinking` block deferred until live shape is captured) ### Fixed - `user_editable_context` / `model_editable_context` extraction (parts-vs-direct-fields mismatch) — Custom Instructions are no longer silently dropped from every conversation ### Migration - Existing exports are not re-rendered automatically. To pick up v0.4.0 rendering for previously exported conversations: ``` python -m src.main cache --clear python -m src.main export --provider all ``` - JSON exports: messages now contain `blocks` (typed structured content) and may omit the legacy `content` field. External consumers reading JSON should prefer `blocks`. - Per-conversation message counts may increase: previously-dropped Custom Instructions, image-only user turns, and tool-only assistant turns now appear. ### Out of scope (deferred to v0.5.0+) - Binary downloads of images and audio assets (placeholders show metadata only; `content not preserved in this export`) - Joplin resource upload for embedded media - Filename resolution for `file-XYZ` / `sediment://` references - Speculative ChatGPT types (`tether_browsing_display`, `tether_quote`) and DALL-E assistant images — fall through to `unknown` blocks if encountered ## [0.2.0] - Unreleased ### Added - Joplin import automation: `joplin` command syncs exported Markdown files to Joplin as notes - Notebooks created automatically per provider+project (`ChatGPT - My Project`, etc.) - Re-running is safe: notes are updated, not duplicated (Joplin note ID stored in manifest) - `JOPLIN_API_TOKEN`, `JOPLIN_API_URL`, `JOPLIN_REQUEST_TIMEOUT` config variables - Configurable request timeout with clear error messages and actionable hints on timeout - `--project` filter on `export` and `list` commands (case-insensitive substring or `none`) - ChatGPT Projects support via `CHATGPT_PROJECT_IDS` env var ## [0.1.0] - Unreleased ### Added - Initial implementation: ChatGPT and Claude export via internal web APIs - Markdown and JSON exporters - Local cache/manifest for incremental sync - CLI with export, list, cache, doctor, and auth commands