App source (main/preload/worker/renderer) -> ESM; app is now type: module;
__dirname via import.meta.url; worker spawned with type module. Preload is built
as CJS (electron-vite output format) because the sandboxed renderer does not
support ESM preload; main loads ../preload/index.js. Removed dead imports
(nativeImage, readline) and the obsolete scripts/dev.js.
Tests: 4 app tests require->import; app-main-settings rewritten with node:test
mock.module + dynamic import (replacing CJS Module._load mocking); test script
adds --experimental-test-module-mocks. electron-vite build clean, 119/119, and
npm run dev verified: app launches, preload bridges IPC, data loads.
Restructure app into src/{main,preload,renderer}; electron.vite.config.ts builds
all three (each main module its own input so CJS requires + the indexer worker
resolve; better-sqlite3 externalized; Vue plugin for renderer). main/index.js
paths updated for the out/ layout + ELECTRON_RENDERER_URL. Still JS/CJS — TS+ESM
and core consumption are the next stages. Verified: npm run dev launches clean;
electron-vite build succeeds; root suite 119/119.
Add `source` column to sessions and messages ('claude' | 'codex').
Discover and parse Codex JSONL files from ~/.codex/sessions/, mapping
Codex thread/item structures to the same schema (messages, tool_calls,
tool_results, subagents). Move DB to ~/.obelisk/ with legacy migration.
Add rebuild-to-temp-then-swap for safe full rebuilds. On the app side:
source filter toggle, collapsible untitled session fold, configurable
codexDir in Settings, and a dev script. Update SKILL.md and query
helpers to expose source fields and accept source filter opt.
Add a clickable session link in MemoryList detail panel that navigates
to the source session and scrolls to the originating message. Refactor
SessionDetail focus logic into a reusable focusPendingMessage() that
reads ?focus=<uuid> from the route query, scrolls the target into view,
and applies a pulse animation that fades out.
Add a flag set after initial data fetch completes so
SessionList and RecapList don't briefly show their empty/onboarding
states before content arrives.
Introduce a Settings view for configuring the Claude data directory
(with WSL auto-detection on Windows), sidebar project grouping module,
and an empty-state onboarding screen for SessionList. Refactor
recap-patterns.md into per-card reference files under references/recap/
with separate retrieval and writing guides. Remove the legacy panel.html.
On the data layer: incremental indexing via changedPaths, per-session
live-update IPC (obelisk:session-updated), and session dirty-tracking
in the renderer.
Introduce a Spotify-Wrapped-style recap feature: five themed cards
(Cover, Path, Vibe, Workflow, Closing) rendered per archetype palette,
with keyboard/swipe navigation and image export via capture IPC. Add
RecapList, RecapDetail, RecapExport views and recap component library.
Wire recap:list/read/updated IPC channels through preload, document the
retrieval-to-card contract in references/recap-patterns.md, and bundle
dist-renderer for production use.
Extract schema DDL into scripts/schema.sql shared between CLI and app.
Add an in-process chokidar-based indexer-service that watches ~/.claude/projects
for JSONL changes, debounces, and triggers background rebuilds via a worker
thread. Rename Usage view to Activity, flesh out MemoryDetail and SubagentDetail
views, and refine App.vue layout/routing. The main process now starts/stops the
indexer lifecycle and notifies renderer windows on index updates.
Introduce an Electron app with session browser, memory list, and usage
views (vanilla JS + Vue scaffolding). On the data layer: add content_type
and is_meta to messages for transcript control-plane filtering, introduce
FTS5-backed memory recall with safe tokenization, support memory archival
via forget() through the renamed --attune runtime, and expose anchors on
memory records.