refactor(core): finish TypeScript workspace migration
This commit is contained in:
@@ -6,8 +6,9 @@
|
||||
> adapters* (driven by the multi-provider roadmap), and there is *one* shared
|
||||
> persist layer, not one per binding.
|
||||
|
||||
**Context.** Obelisk had two divergent full indexers — `scripts/indexer.mjs`
|
||||
(`node:sqlite`, skill/runtime) and `app/indexer.js` (`better-sqlite3`, Electron
|
||||
**Context.** Obelisk had two divergent full indexers — the former
|
||||
`scripts/indexer.mjs` (`node:sqlite`, skill/runtime) and `app/indexer.js`
|
||||
(`better-sqlite3`, Electron
|
||||
app) — that duplicated the same Claude and Codex JSONL parsing and had silently
|
||||
diverged in write semantics (`INSERT OR REPLACE` vs `ON CONFLICT DO UPDATE`,
|
||||
message-count accumulation). Two forces shape the fix: (1) the roadmap will add
|
||||
|
||||
@@ -7,7 +7,8 @@ the skill artifact must install with **zero build step** on the user's machine
|
||||
its checkable contracts, but raises how the compiled output is shipped and which
|
||||
module format it targets.
|
||||
|
||||
**Decision.** Author all of Core in TypeScript and compile it ahead-of-time to
|
||||
**Decision.** Author all of Core in the `@obelisk/core` npm workspace
|
||||
(`packages/core`) in TypeScript and compile it ahead-of-time to
|
||||
**ESM JavaScript plus `.d.ts`**. The skill/CLI runtime ships the *precompiled*
|
||||
ESM JS, so installing the skill never runs a build. Rather than have Core
|
||||
dual-publish CJS+ESM, the Electron main process migrates to ESM at Phase 5 so it
|
||||
@@ -20,3 +21,5 @@ in exchange for no dual-build maintenance and a single module format across skil
|
||||
CLI, and app. The shipped skill artifact contains compiled JS, not TS. The
|
||||
renderer (Vue) is out of scope and stays JavaScript. Phase 3's TS baseline only
|
||||
adds root tooling (package.json, tsconfig, ESLint); it does not touch the app.
|
||||
The app imports Core source so electron-vite can bundle it, while package and
|
||||
skill builds compile the same workspace source to JavaScript.
|
||||
|
||||
@@ -20,8 +20,9 @@ decisions within this:
|
||||
security) does not support ESM preload. Source stays ESM; only the preload
|
||||
output format is CJS. `main` loads `../preload/index.js`.
|
||||
- **The app consumes the Core from source**: electron-vite/rollup bundles
|
||||
`scripts/providers/*` + `scripts/persist` (and their `scripts/parsing.mjs`
|
||||
dependency) into the app's main/worker build, injecting `better-sqlite3`. This
|
||||
`packages/core/src/providers/*` + `packages/core/src/persist.ts` (and their
|
||||
`packages/core/src/parsing.ts` dependency) into the app's main/worker build,
|
||||
injecting `better-sqlite3`. This
|
||||
works because the provider→parsing import graph is node:sqlite-free (ADR-0001),
|
||||
so nothing drags `node:sqlite` into the app. The `dist/` from `build:core`
|
||||
(ADR-0003) remains for the skill artifact; the app does not need it.
|
||||
@@ -30,17 +31,17 @@ decisions within this:
|
||||
- **The app main + preload source is TypeScript with types at its seams**, but
|
||||
under a *deliberately more lenient* project than the runtime core. `app/tsconfig.json`
|
||||
keeps `strict` on yet sets `noImplicitAny: false`, because the app mostly
|
||||
orchestrates the already-strictly-typed core (`scripts/`), and annotating every
|
||||
orchestrates the already-strictly-typed core (`packages/core/src/`), and annotating every
|
||||
internal SQLite-handle helper would be high-cost, low-value churn. Types are
|
||||
added where they matter: the core-consumption seam (`BuildIndexOptions`/
|
||||
`BuildIndexResult`, `FileInfo`), the service/worker factories, and the IPC
|
||||
bridge. Module-to-module specifiers use the real `.ts` extension (mirroring
|
||||
`scripts/`, since Node's type-stripping does not rewrite `.js`→`.ts`), which
|
||||
Core source, since Node's type-stripping does not rewrite `.js`→`.ts`), which
|
||||
needs `allowImportingTsExtensions` (safe under the project's `noEmit`); the
|
||||
worker's *runtime* path stays `indexer-worker.js` because that is the built
|
||||
output. `@types/better-sqlite3` is a devDependency for the injected binding.
|
||||
|
||||
**Two-tier typechecking.** `npm run typecheck` runs the root project (`scripts/` +
|
||||
**Two-tier typechecking.** `npm run typecheck` runs the root project (`packages/core/src/` +
|
||||
`tests/`, fully strict including `noImplicitAny`) and then the app project. The
|
||||
root project **excludes the app-importing tests** (`tests/app-*.test.mjs`,
|
||||
`tests/recap-capture-query.test.mjs`): those tests import app source, which would
|
||||
|
||||
@@ -17,14 +17,15 @@ failed statement can replay part of a transaction.
|
||||
**Decision.** Use one transaction primitive plus two explicit coordination
|
||||
layers.
|
||||
|
||||
- `scripts/tx.ts` owns the binding-agnostic `runWriteTransaction(db, work)`.
|
||||
- `packages/core/src/tx.ts` owns the binding-agnostic
|
||||
`runWriteTransaction(db, work)`.
|
||||
Adapters expose transaction state from better-sqlite3's `inTransaction` and
|
||||
node:sqlite's `isTransaction`. The primitive performs `BEGIN IMMEDIATE`, runs
|
||||
`work` exactly once, commits, and attempts rollback only when the binding says
|
||||
a transaction is active or its state is unknown. Cleanup never masks the
|
||||
primary exception. Diagnostics record phase, SQLite code, rollback outcome,
|
||||
transaction state, label, and attempts.
|
||||
- Retry is an upper-layer policy in `scripts/write-coordinator.ts`, never hidden
|
||||
- Retry is an upper-layer policy in `packages/core/src/write-coordinator.ts`, never hidden
|
||||
inside the transaction primitive. Only an idempotent whole transaction that
|
||||
failed during work/commit with `SQLITE_BUSY*` and is confirmed inactive may be
|
||||
retried. The default is three attempts within a one-second budget with short
|
||||
|
||||
Reference in New Issue
Block a user