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>
This commit is contained in:
tommy0103
2026-07-09 12:46:02 +08:00
co-authored by Claude Opus 4.8
parent 905c10789a
commit 60d47a852e
6 changed files with 152 additions and 644 deletions
+14 -10
View File
@@ -27,22 +27,26 @@ promoted to an external tool surface.
## Indexing
**Parse core**:
The pure `jsonl -> records` transform. Given a transcript file and a start line,
it yields normalized index records. It does not open, own, or write to a
database, and is shared verbatim by every indexing mode. This is the layer that
must never be duplicated.
_Avoid_: parser, ingest
**Provider adapter**:
A pure per-source module (claude, codex, later opencode, pi, …) that discovers a
source's transcript files and parses one into a stream of records. It never opens
or writes a database; adding a source means adding one adapter. The shared pure
parse/discover helpers live in `scripts/parsing.mjs`, which imports only
node:fs/path/os — deliberately node:sqlite-free so the compiled providers can be
consumed by the app (whose Electron runtime has no `node:sqlite`).
_Avoid_: parse core, parser, ingest
**Record**:
One normalized row destined for the index (session, message, tool call, tool
result, summary, subagent, workflow, …), emitted by the parse core before any
result, summary, subagent, workflow, …), emitted by a provider adapter before any
persistence happens.
**Persist layer**:
The thin, binding-specific writer that consumes records from the parse core and
writes them into SQLite inside a transaction. Two persist layers exist and differ
only in binding: `node:sqlite` (skill/CLI) and `better-sqlite3` (app).
The single shared, provider- and binding-agnostic writer that consumes records
from any adapter and writes them into an injected SQLite handle inside a
transaction. The binding is injected — `node:sqlite` (skill/CLI) or
`better-sqlite3` (app) — so there is one persist implementation, not one per
binding.
_Avoid_: writer, sink, DAO
**Daemon indexing mode**: