Commit Graph
71 Commits
Author SHA1 Message Date
tommy0103 78aacfac6c feat(session): animate total count with split flap 2026-07-12 20:00:07 +08:00
tommy0103 1742d73b32 fix(activity): align ledger typography 2026-07-12 15:24:28 +08:00
tommy0103 48f1a4c225 feat(activity): add contribution ledger 2026-07-12 15:15:48 +08:00
tommy0103 644942202e Complete Vue renderer migration 2026-07-12 02:26:01 +08:00
tommy0103 dbf3ea4b51 Fix activity session navigation 2026-07-12 01:47:32 +08:00
tommy0103 32a9b8d424 Merge branch 'refactor/migrate' into main
Phases 0–7 of the Obelisk engineering refactor: provider-adapter architecture
(ADR-0001), shared persist + tx module, TypeScript workspace (packages/core),
electron-vite app migration, writer-lease concurrency, and CI skill publish.
2026-07-12 01:12:32 +08:00
tommy0103andClaude Opus 4.8 410b0a8df3 docs(readme): rewrite for dual-surface product (skill + app) and workspace structure
Rewrite README to reflect the current state of the project:
- Describe both surfaces: skill (agent-first retrieval) and app (human browser).
- Add Codex support section (unified schema, source tagging, child-thread mapping).
- Update Structure tree to match the packages/core workspace layout with all
  TypeScript modules (providers, persist, tx, write-coordinator, writer-lease).
- Document generated build outputs (packages/core/dist, dist/obelisk-skill).
- License badge corrected to AGPL-3.0 (skill artifact is MIT; source is AGPL).
- Skill invocation examples updated to /obelisk-skill.
- Add recap flow documentation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:59:33 +08:00
tommy0103 8af0f9a31d refactor(core): type the persist database seam 2026-07-12 00:46:04 +08:00
tommy0103 c4c458fa8f refactor(core): share sqlite boundary types 2026-07-12 00:44:06 +08:00
tommy0103 3a6e3a00a7 fix(core): ship schema with package build 2026-07-12 00:39:57 +08:00
tommy0103 535d8edb4d refactor(core): finish TypeScript workspace migration 2026-07-12 00:37:32 +08:00
tommy0103 83d5703f7b refactor(core): move shared runtime into workspace package 2026-07-12 00:28:17 +08:00
tommy0103andClaude Opus 4.8 6edaf5231f ci: auto-publish skill artifact to tommy0103/obelisk-skill on push to main (Phase 7)
Add a GitHub Actions workflow that builds the readable, non-bundled skill
artifact (`npm run build:skill`) and force-pushes it to the dedicated
tommy0103/obelisk-skill public repo whenever the main branch is updated.
The skill repo is a pure derivative — no manual commits, no PRs; the source
of truth stays in tommy0103/obelisk.

- .github/workflows/publish-skill.yml: checkout → npm ci → build:skill →
  clone skill repo → replace content → commit + force push. Auth via
  SKILL_REPO_DEPLOY_KEY (SSH deploy key with write access to obelisk-skill).
- packaging/skill-README.md: the README placed in the skill repo (install
  instructions + link back to source + "auto-published, don't PR here").
- packaging/skill-LICENSE: MIT license for the skill artifact (relicensed
  from the AGPL-3.0 source by the copyright holder).
- packaging/publish-skill.sh: local convenience script for manual publish.
- packaging/skill-package.json: license field updated to MIT.
- README.md: install command updated to tommy0103/obelisk-skill.
- package.json: add publish:skill script.

The skill repo is MIT-licensed for zero adoption friction (local tool, no
library API, no derivative works expected); the source repo stays AGPL-3.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 16:18:43 +08:00
tommy0103andClaude Opus 4.8 e3e61cc7ab fix: coordinate sqlite index writers
Implement the full ADR-0006 plan: three-layer separation of transaction
correctness, retry policy, and cross-process writer coordination.

Layer 1 — scripts/tx.ts (transaction correctness):
- runWriteTransaction executes work exactly once; no internal retry.
- BEGIN IMMEDIATE takes the write lock up front (avoids SQLITE_BUSY_SNAPSHOT).
- Guarded rollback: checks inTransaction() via adapter before attempting
  ROLLBACK; never masks the primary exception.
- WriteTxDiagnostics attached to errors: phase, code, label,
  rollbackSucceeded, rollbackError, transactionActive.
- Binding adapters (betterSqliteTransactionAdapter, nodeSqliteTransactionAdapter)
  mapping better-sqlite3's `.inTransaction` and node:sqlite's `.isTransaction`.
- configureConnection centralizes WAL + synchronous + busy_timeout.

Layer 2 — scripts/write-coordinator.ts (retry policy):
- runRetryableWriteTransaction: bounded retry with total time budget.
- Only retries when the transaction confirmed ended (transactionActive=false)
  and the error is SQLITE_BUSY during work/commit phase.
- BEGIN-phase BUSY = abort entire build (isBeginBusyFailure); the caller
  returns `{ deferred: true, reason: 'writer_busy' }` instead of waiting.
- hasUnusableTransaction detects a still-active transaction after failure;
  aborts the build immediately, never retries.

Layer 3 — scripts/writer-lease.ts (cross-process coordination):
- acquireWriterLease: dedicated writer.lock.sqlite with busy_timeout=0 +
  BEGIN IMMEDIATE. Non-blocking attempt; bounded wait with retryDelayMs.
- writerLockPathFor derives lock path from the target DB path.
- Lease held for the entire build; released on completion or failure.
- Lock DB uses DELETE journal (not WAL); crash/close auto-releases.
- All consumers obey: skill acquires at build start (returns deferred if
  unavailable); app daemon (via worker) acquires for its build cycle.

Build semantics changes:
- affectedSessionIds updated only after successful commit.
- BuildIndexResult gains skipped/skippedFiles for observability.
- Skill finalize failure now fails the build (was silently warned).
- Checkpoint changed to PASSIVE (TRUNCATE reserved for maintenance/exit).
- Skill buildIndex returns { deferred, reason } on lease contention;
  indexer-service reschedules the build (deferredRetryMs) without publishing
  a heartbeat (so the build-deferred state is visible to cross-process
  arbitration).
- Service publishes heartbeat immediately on start() for correct arbitration.

Tests:
- tests/write-transaction.test.mjs: single-shot execution, diagnostics
  propagation, auto-rolled-back transaction detected, rollback failure
  captured as metadata, BEGIN IMMEDIATE semantics.
- tests/writer-lease.test.mjs: acquire/release, contention returns null,
  bounded wait with release during budget.
- tests/app-writer-lease.test.mjs: better-sqlite3 adapter integration.
- tests/app-rollback-guard.test.mjs: rewritten — transient BUSY recovered
  by coordinator, persistent BUSY skips file, begin-busy aborts build,
  live-transaction aborts build, phantom affectedSessionIds prevented.
- tests/daemon-arbitration.test.mjs: skill defers to fresh app heartbeat,
  builds when heartbeat is stale.
- tests/app-indexer-service.test.mjs: new cases for deferred-retry
  scheduling and immediate heartbeat on start.
- app/tests/electron-concurrency.mjs + child: dual-child IPC structure for
  real better-sqlite3 contention (holder acquires lock → build child starts
  → delayed release → result collected; persistent contention bounded).

ADR-0006 updated to reflect the implemented design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 00:42:43 +08:00
tommy0103andClaude Opus 4.8 44029676d4 fix(indexer): guard cleanup rollback so it never masks the real build error
Reported as "cannot rollback - no transaction is active" — a secondary error.
SQLite auto-rolls back certain failures (SQLITE_BUSY / SQLITE_BUSY_SNAPSHOT,
disk full), after which the per-file loop's unguarded ROLLBACK in its catch
threw over the real error and aborted the whole build instead of skipping just
the bad file.

Stopgap only (see docs/adr/0006 for the planned full fix):
- Add safeRollback(db) in both indexers: it swallows only the rollback's own
  error, so the true cause surfaces. Per-file failures are logged and the build
  continues; the finalize failure still propagates.
- Give the skill's node:sqlite connection an explicit PRAGMA busy_timeout=5000
  (it has no default). The app adds none: better-sqlite3 already defaults to
  5000ms, so busy_timeout is NOT the root-cause fix and is not treated as one.

Add tests/app-rollback-guard.test.mjs: injects a DB that faithfully reproduces
"a write auto-rolls back the txn, then ROLLBACK errors" and asserts the build
survives (bad file skipped, other file indexed). Revert-checked: without the
guard the test fails with the exact "cannot rollback - no transaction is active".

docs/adr/0006 records the real fix (shared runWriteTransaction, single-writer
coordination, BEGIN IMMEDIATE, whole-transaction retry, PASSIVE checkpointing)
as deferred, two-phase work — and why bumping busy_timeout is not it.

Verified: suite 124/124, typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:36:36 +08:00
tommy0103andClaude Opus 4.8 e44ab7a1da build(skill): add build:skill for a readable, non-bundled skill artifact (Phase 6)
`npm run build:skill` emits dist/obelisk-skill/: the whole scripts/ Core
compiled to readable JS (module structure + comments preserved, ~1:1 with
source, no bundling/minifying per ADR-0004), plus schema.sql, SKILL.md,
references/, and a package.json. It excludes app/, tests/, and release/, which
is what keeps the artifact small.

- tsconfig.skill.json compiles scripts/**/*.{ts,mjs} (allowJs) with
  rewriteRelativeImportExtensions, so the .ts specifiers inside the .mjs shells
  (runtime.mjs -> ./core.js, indexer.mjs -> ./providers/*.js, ./persist.js) are
  rewritten to .js. declaration:false — the skill needs no .d.ts.
- packaging/skill-package.json provides the artifact's package.json; it sets
  "type":"module" because the emitted .ts->.js files are ESM.
- build:skill runs tsc then copies schema.sql/SKILL.md/references/package.json.

Add tests/build-skill.test.mjs: runs the real build:skill, asserts the artifact
structure, that no emitted .js/.mjs still imports a .ts module, and that the
compiled artifact builds an index and answers a search end-to-end under plain
Node (no type-stripping) against a temp HOME.

Verified: suite 123/123, typecheck clean, artifact smoke run green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:36:01 +08:00
tommy0103andClaude Opus 4.8 c964653362 fix(indexer): force build purges stale sessions instead of only clearing index_state
The skill's `--build` (always a force build) cleared `index_state` and
re-indexed existing files, but never removed rows for transcripts that no
longer exist on disk, so deleted sessions accumulated forever (the dogfood
showed 328 indexed sessions vs 283 current files). A force build is meant to
be a clean rebuild, matching what the app already does.

Drop every derived table (messages, tool_calls, tool_results, sessions,
summaries, subagents, workflows, workflow_agents) in the force path, then
re-index from the current files. `memories` is the durable, human-approved
layer and is never cleared; messages_fts is repopulated by the existing
'rebuild' command in finalize.

Add a test that builds two sessions, deletes one transcript, force-rebuilds,
and asserts the stale session is purged while a seeded memory survives.
Verified the test is discriminating: without the fix it reports
['gone','keep'] instead of ['keep'].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 03:18:52 +08:00
tommy0103andClaude Opus 4.8 01a390fa10 refactor(app): migrate main + preload to TypeScript with typed seams (Phase 5d-3c-ii)
Convert the app's main and preload source from .js to .ts (git mv preserves
history), adding types where they carry value: the core-consumption seam
(BuildIndexOptions/BuildIndexResult, FileInfo), the indexer service/worker
factories, and the preload IPC bridge. Module-to-module specifiers use the
real .ts extension (mirroring scripts/, since Node type-stripping does not
rewrite .js->.ts); the worker's runtime path stays indexer-worker.js because
that is the built output.

Toolchain:
- Add app/tsconfig.json: strict but noImplicitAny:false (the app orchestrates
  the already-strict core; annotating every SQLite-handle helper is low-value
  churn) + allowImportingTsExtensions (safe under noEmit).
- Add @types/better-sqlite3 for the injected binding.
- electron.vite.config.ts inputs -> .ts; refresh the stale CommonJS comment.
- typecheck script runs root + app projects. Root tsconfig excludes the
  app-importing tests (app-*.test.mjs, recap-capture-query.test.mjs) so the
  lenient app files are not dragged into the strict root program; the app
  source is covered by app/tsconfig.json instead. See docs/adr/0005.

Verified: npm run typecheck (root + app) clean; suite 121/121; electron-vite
build emits all 6 main entries + preload with no .ts/node:sqlite residue in
the bundles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 16:25:59 +08:00
tommy0103andClaude Opus 4.8 60d47a852e refactor(app): consume shared indexing core, remove duplicated indexer (Phase 5d-3c-i)
The desktop app now indexes through the shared provider adapters + persist
layer (scripts/providers/{claude,codex}, scripts/persist, scripts/parsing)
instead of maintaining its own parallel indexer. buildIndex shrinks from
~1173 to ~592 lines, eliminating the skill<->app parse duplication that
Phase 5 set out to remove. electron-vite bundles the .ts core from source
with better-sqlite3 injected; the provider->parsing graph stays
node:sqlite-free so nothing drags node:sqlite into the app.

Also fix a misleading log: when a manual rebuild tears down the worker
mid-build, the cancelled background build is a deliberate stop, not a
failure. Guard the service's failure log with the stopped flag so it no
longer prints "Obelisk index build failed: Indexer worker stopped" on
every rebuild.

- CONTEXT.md: provider-adapter + single-persist + node:sqlite-free parsing.
- docs/adr/0005: app builds with electron-vite (TS+ESM), packages with
  electron-builder; preload CJS for sandbox; app consumes core from source.

Verified: full suite 121/121; a node:sqlite-adapter dogfood of the rebuild
path over real data (969 files, 285 sessions, FTS rebuilt) runs clean; app
Rebuild confirmed in real Electron/better-sqlite3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 12:46:02 +08:00
tommy0103 905c10789a refactor(app): migrate to ESM; preload emitted as CJS for sandbox (Phase 5d-3b)
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.
2026-07-09 11:05:00 +08:00
tommy0103 80c125a572 build(app): migrate to electron-vite (main/preload/renderer), keep electron-builder (Phase 5d-3a)
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.
2026-07-09 10:20:18 +08:00
tommy0103 e04c07de05 build: add build:core to compile the app-consumable core to dist/ (Phase 5d-2)
tsconfig.build.json emits providers/* + persist (+ their parsing.mjs/types deps)
to dist/ as ESM JS + .d.ts. Output is verified node:sqlite-free and functionally
runnable (parse+persist against an injected db). Foundation for the app importing
the shared core.
> obelisk@0.1.0 build:core
> rm -rf dist && tsc -p tsconfig.build.json; dist/ is gitignored.
2026-07-09 09:34:25 +08:00
tommy0103 1bda4da170 refactor: extract node:sqlite-free parsing.mjs so the core can be app-consumable (Phase 5d-1)
Move all pure parse/discover helpers (message extraction, project-path, codex
helpers, discovery) out of db.mjs/indexer.mjs into scripts/parsing.mjs, which
imports only node:fs/path/os. Providers now import from parsing.mjs, so the
provider import graph no longer transitively loads node:sqlite — a prerequisite
for the app (Electron/Node without node:sqlite) to consume the compiled core.
Verbatim move, no behavior change; indexer.mjs 840→209 lines. 119/119.
2026-07-09 09:20:37 +08:00
tommy0103 0598c29aad feat(providers): migrate codex indexing to adapter + persist, remove legacy indexers (Phase 5c)
Complete the skill-side provider migration: codex now goes through a pure adapter
and the shared persist layer, and the two original monolithic indexers are gone.

New:
- scripts/providers/codex.ts — pure codex adapter. Full-reparse (buffers the whole
  file) because the event_msg↔response_item dedup needs whole-file, bidirectional
  knowledge; emits SessionRecord with countMode 'total'. Handles guardian threads
  (→ delete-session), agent spawns/tool calls (→ tool_call/subagent), token_count
  (patched onto the message record) and task_complete (→ message-turn-duration).

Contract:
- SessionRecord.countMode ('total' | 'delta') tells persist whether to replace or
  accumulate message_count — claude is line-incremental (delta), codex full-reparse
  (total). SubagentRecord non-key fields are optional; persist merges them
  column-wise with COALESCE. MessageTurnDurationRecord.turn_duration_ms is nullable.

Orchestration:
- buildIndex's codex branch parses via the adapter and writes via persist. An
  unchanged file is skipped but still swept for stale guardian rows (routed through
  persist as a delete-session), preserving prior behavior.

Cleanup:
- Remove the now-unused indexJsonl, indexCodexJsonl, deleteCodexThreadRows and
  upsertCodexSubagent — their semantics now live in the adapters + persist.
  indexer.mjs drops from ~840 to 428 lines. Codex pure helpers stay exported for
  codex.ts and the guardian sweep (physical move deferred to the app-side reorg).
- Migrate the upsert drift test off indexJsonl to the claude.parse + persist path,
  keeping the rowid-stability and count-replace regression guards.

Tests: tests/codex-parse.test.mjs (record-stream golden: dedup, tools, token patch,
turn-duration, guardian→delete) and tests/codex-index.test.mjs (full buildIndex
path: fresh build + incremental full-reparse, total-count replace, no duplicates).

Verified equivalent on the real ~/.obelisk index: codex messages 82476 and
subagents 522 identical before/after, zero guardian leakage; real incremental
confirmed (touch a codex file → reparsed idempotently, unchanged files skipped).
lint + typecheck clean, 119/119.
2026-07-08 20:43:54 +08:00
tommy0103 1c346039f1 refactor(indexer): route claude indexing through adapter + persist (Phase 5b-2b)
buildIndex's claude branch now parses via providers/claude.ts and writes via
persist.ts instead of the inlined indexJsonl. Behavior is equivalent — the full
buildIndex integration suite (runtime.test.mjs) stays green, 116/116 — and a
force rebuild of the real ~/.obelisk index (327 sessions, 119k messages)
reproduced identical session counts with project_path fully populated.

codex, indexSubagentMeta, workflows, history and the project_path pass are
untouched. indexJsonl is now unused by buildIndex (kept for its drift test;
removed once codex is migrated).

Adds tests/incremental-index.test.mjs: verifies resume/accumulate through the
full buildIndex path (append new lines to an indexed session → incremental
build resumes from the cursor, message_count accumulates, no duplicates). The
30s shouldSkipBuild debounce is cleared in-test so the incremental run fires.
2026-07-08 19:46:34 +08:00
tommy0103 1d652d823f feat(persist): add shared record-stream persist layer (Phase 5b-2a)
Introduce scripts/persist.ts — the single, provider- and binding-agnostic
layer that consumes an adapter's IndexRecord stream and writes rows into an
injected SQLite handle (node:sqlite for skill/CLI, better-sqlite3 for the app).
It is the only layer that touches the database.

Write semantics are the canonical ones reconciled from the earlier drift:
- messages upsert via ON CONFLICT (turn_duration_ms not in the column list, so
  it is never clobbered)
- sessions merge with the existing row: started_at MIN, ended_at MAX,
  message_count reset-or-accumulate by resume state, fill-if-null for the rest;
  project_path is preserved and left to refreshSessionProjectPaths
- message-turn-duration applies as a targeted UPDATE
- delete-session cascades across all tables
- the generator's return cursor is written back to index_state (mtime:lines →
  the two existing columns; no schema migration yet)

Purely additive — buildIndex still uses the old indexJsonl path, so existing
behavior is unchanged. Rewiring happens in 5b-2b.

Adds tests/persist.test.mjs: all record kinds written, resume does not
double-count message_count, fresh re-scan resets it, delete-session cascades.
Full suite 115/115, lint + typecheck green.
2026-07-08 19:01:54 +08:00
tommy0103 2b30d9596d feat(providers): add pure claude adapter with record-stream golden tests (5b-1)
claude.parse mirrors indexJsonl line-for-line but yields IndexRecords (no db).
Adds MessageTurnDurationRecord op. Purely additive — buildIndex still uses the
old path. 111/111 green.
2026-07-08 18:27:28 +08:00
tommy0103 338dae413d feat(indexer): define source-agnostic Provider + IndexRecord contract (Phase 5a)
Provider adapters own discovery/change-detection/cursoring and emit records;
one shared binding-agnostic persist consumes them. Records map 1:1 to schema
tables. Revises ADR-0001 to the provider-registry model.
2026-07-08 18:10:04 +08:00
tommy0103 51597f42f0 fix(indexer): align claude message writes to canonical upsert semantics
scripts/indexer.mjs indexJsonl used INSERT OR REPLACE (rowid/FTS churn) and
carried message_count forward on full re-scan; align to app's ON CONFLICT upsert
+ count reset so the two indexers no longer silently diverge. Regression test added.
2026-07-08 17:23:55 +08:00
tommy0103 3391bf6ac3 refactor: extract runtime Core into scripts/core.ts; runtime.mjs becomes a thin shell
Core exposes buildIndex/searchText/executeQuery/executeAttune as the single shared
implementation for all transports. First TypeScript module, run via Node type
stripping in dev. Adds typescript-eslint. lint/typecheck green, test 107/107.
2026-07-08 16:59:30 +08:00
tommy0103 33ec238c0c build: add TypeScript + ESLint baseline (typecheck/lint/test scripts)
Root package.json (type: module), strict tsconfig with allowJs/checkJs:false for
gradual migration, flat ESLint config scoped to scripts/ + tests/. App untouched.
All three green: lint, typecheck, test 107/107.
2026-07-08 16:42:08 +08:00
tommy0103 a32461b2ab feat: make search() FTS-safe; complete Tier 2 helper-shape contract tests
search() falls back to safe per-token quoting on malformed FTS input instead of
crashing (documented in api-reference.md). Adds raw() to the doc-synced shape
contract. Full suite 107/107.
2026-07-08 16:35:10 +08:00
tommy0103 25537d3a53 test: lock runtime CLI I/O envelope; unify --build/--search error handling 2026-07-08 16:20:48 +08:00
tommy0103 1a34245618 chore: sanitize tests, add CONTEXT.md + ADRs, track tests/docs 2026-07-08 16:11:12 +08:00
tommy0103 942a08412a docs: split schema.md into focused references (api-reference.md + compact SQL map)
Extract helper API documentation into a standalone api-reference.md and
  reduce schema.md to a compact field/join/table map for raw SQL work.
  Add a Reference Map table to SKILL.md for quick routing by task type.
2026-06-18 01:54:10 +08:00
tommy0103 d5d5df46fa docs: split schema.md into focused references (api-reference.md + compact SQL map)
Extract helper API documentation into a standalone api-reference.md and
  reduce schema.md to a compact field/join/table map for raw SQL work.
  Add a Reference Map table to SKILL.md for quick routing by task type.
2026-06-18 01:52:44 +08:00
tommy0103 4f048bcd10 chore: update README.md 2026-06-18 00:13:11 +08:00
tommy0103 9ea5b8b5b4 feat: add Codex transcript indexing and dual-source retrieval
Obelisk now indexes ~/.codex/ sessions alongside Claude Code, storing
  both under a unified schema with a  column for provenance.
  Includes DB migration to ~/.obelisk/, guardian thread filtering, and
  source-aware query helpers.
2026-06-17 23:58:26 +08:00
tommy0103 12407227cc feat: index Codex sessions alongside Claude Code with source tagging
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.
2026-06-17 23:40:36 +08:00
tommy0103 e3ca1735b9 feat(app): link memory to source session with focus-scroll navigation
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.
2026-06-17 01:15:16 +08:00
tommy0103 b071cf7232 chore: switch license from MIT to AGPL-3.0 and add demo screenshot 2026-06-15 02:48:04 +08:00
tommy0103 c50706daef docs: rewrite README to cover both skill and app sides
Restructure the README around the dual nature of Obelisk: agent-first
  skill for querying session history, plus Electron desktop app for
  browsing sessions, memories, activity, and recap cards. Trim verbose
  implementation details and add app screenshot.
2026-06-15 02:38:04 +08:00
tommy0103 3822bda89e feat: evolve retrieval layer with content_type, memory FTS, forget(), and recap references
Extract schema DDL into scripts/schema.sql. Add content_type and is_meta
  columns to messages for transcript control-plane filtering. Introduce
  FTS5-backed memory recall with safe tokenization, memory soft-delete via
  forget() through the renamed --attune runtime, and anchors on memory
  records. Expand query helpers (includeMeta, thread opts, overview
  project-path awareness). Add per-card recap retrieval and writing
  references under references/recap/.
2026-06-15 02:25:21 +08:00
tommy0103 42c7c0da66 fix(app): suppress empty-state flash by gating on data-loaded flag
Add a  flag set after initial data fetch completes so
  SessionList and RecapList don't briefly show their empty/onboarding
  states before content arrives.
2026-06-15 02:07:13 +08:00
tommy0103 b7506ee765 feat(app): add Settings view, configurable claude dir, and recap docs refactor
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.
2026-06-15 01:44:32 +08:00
tommy0103 9fc7f202f0 feat(app): add weekly recap cards with swipeable story UI and export
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.
2026-06-14 03:16:49 +08:00
tommy0103 4eec6b38c9 feat(app): embed indexer in Electron with file-watching service and UI refinements
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.
2026-06-13 03:42:01 +08:00
tommy0103 b524339d85 feat(app): add Electron desktop UI and evolve memory/retrieval layer
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.
2026-06-12 22:20:29 +08:00
tommy0103 b52f57b538 feat(memory): enforce English-only memory indexing with CJK guardrail
Memory layer is now English-indexed: memories() query terms and
  remember() summaries must be English. Adds a runtime assertion that
  rejects CJK text in both paths, guiding the agent to translate
  non-English user requests before querying or writing memories.
  Ensures consistent retrieval regardless of conversation language.
2026-06-10 03:50:38 +08:00
tommy0103 89b53d4570 docs: establish helper-first retrieval as default entry point
Make overview() + memories() + search() the standard first pass for
  broad retrieval tasks, with sql() positioned as an escalation path for
  exact joins/aggregations. Add a Default First Pass section to SKILL.md,
  a copyable first-pass pattern to query-patterns.md, and update
  retrieval-semantics.md to reinforce the helper-before-sql principle.
2026-06-10 03:28:15 +08:00