@zipbul/gildash 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -49,7 +49,7 @@ gildash는 TypeScript 코드베이스를 로컬 SQLite 데이터베이스에 인
49
49
  bun add @zipbul/gildash
50
50
  ```
51
51
 
52
- > **피어 의존성** — [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result) 필요합니다. 모든 public 메서드는 `Result<T, GildashError>`를 반환합니다.
52
+ > **선택적 피어 의존성** — `typescript` (>=5.0.0) `semantic: true` 사용 시에만 필요합니다.
53
53
 
54
54
  <br>
55
55
 
@@ -57,7 +57,6 @@ bun add @zipbul/gildash
57
57
 
58
58
  ```ts
59
59
  import { Gildash } from '@zipbul/gildash';
60
- import { isErr } from '@zipbul/result';
61
60
 
62
61
  // 1. 열기 — 최초 실행 시 전체 .ts 파일 인덱싱, 이후 파일 변경 감시
63
62
  const ledger = await Gildash.open({
@@ -65,10 +64,8 @@ const ledger = await Gildash.open({
65
64
  });
66
65
 
67
66
  // 2. 검색 — 이름으로 심볼 찾기
68
- const result = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
69
- if (!isErr(result)) {
70
- result.forEach(s => console.log(`${s.name} → ${s.filePath}`));
71
- }
67
+ const symbols = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
68
+ symbols.forEach(s => console.log(`${s.name} → ${s.filePath}`));
72
69
 
73
70
  // 3. 종료 — 리소스 해제
74
71
  await ledger.close();
@@ -201,16 +198,18 @@ await ledger.close({ cleanup: true }); // DB 파일까지 삭제
201
198
 
202
199
  ## ❌ 에러 처리
203
200
 
204
- 모든 public 메서드는 [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result)의 `Result<T, GildashError>`를 반환합니다. `isErr()`로 에러를 분기합니다:
201
+ public 메서드는 값을 직접 반환하고, 실패 시 `GildashError`를 throw합니다. `instanceof`로 분기합니다:
205
202
 
206
203
  ```ts
207
- import { isErr } from '@zipbul/result';
208
-
209
- const result = ledger.searchSymbols({ text: 'foo' });
210
- if (isErr(result)) {
211
- console.error(result.data.type, result.data.message);
212
- } else {
213
- console.log(`${result.length}개 심볼 발견`);
204
+ import { Gildash, GildashError } from '@zipbul/gildash';
205
+
206
+ try {
207
+ const symbols = ledger.searchSymbols({ text: 'foo' });
208
+ console.log(`${symbols.length}개 심볼 발견`);
209
+ } catch (e) {
210
+ if (e instanceof GildashError) {
211
+ console.error(`[${e.type}] ${e.message}`);
212
+ }
214
213
  }
215
214
  ```
216
215
 
@@ -230,9 +229,9 @@ if (isErr(result)) {
230
229
  | `watchMode` | `boolean` | `true` | `false`이면 파일 워처 비활성화 (스캔 전용 모드) |
231
230
  | `semantic` | `boolean` | `false` | tsc TypeChecker 기반 시맨틱 분석 활성화 |
232
231
 
233
- **반환**: `Promise<Gildash>` (`Result`로 래핑됨)
232
+ **반환**: `Promise<Gildash>`. 실패 시 `GildashError`를 throw합니다.
234
233
 
235
- > **참고:** `semantic: true`는 프로젝트 루트에 `tsconfig.json`이 필요합니다. 없으면 `Gildash.open()`이 `GildashError`를 반환합니다.
234
+ > **참고:** `semantic: true`는 프로젝트 루트에 `tsconfig.json`이 필요합니다. 없으면 `Gildash.open()`이 `GildashError`를 throw합니다.
236
235
 
237
236
  <br>
238
237
 
@@ -242,34 +241,34 @@ if (isErr(result)) {
242
241
 
243
242
  | 메서드 | 반환 타입 | 설명 |
244
243
  |--------|-----------|------|
245
- | `searchSymbols(query)` | `Result<SymbolSearchResult[]>` | FTS5 전문검색 + exact/regex/decorator 필터 |
246
- | `searchRelations(query)` | `Result<StoredCodeRelation[]>` | 파일, 심볼, 관계 유형 필터 |
247
- | `searchAllSymbols(query)` | `Result<SymbolSearchResult[]>` | 전체 프로젝트 심볼 검색 |
248
- | `searchAllRelations(query)` | `Result<StoredCodeRelation[]>` | 전체 프로젝트 관계 검색 |
249
- | `listIndexedFiles(project?)` | `Result<FileRecord[]>` | 인덱싱된 파일 목록 |
250
- | `getSymbolsByFile(filePath)` | `Result<SymbolSearchResult[]>` | 단일 파일의 모든 심볼 |
244
+ | `searchSymbols(query)` | `SymbolSearchResult[]` | FTS5 전문검색 + exact/regex/decorator 필터 |
245
+ | `searchRelations(query)` | `StoredCodeRelation[]` | 파일, 심볼, 관계 유형 필터 |
246
+ | `searchAllSymbols(query)` | `SymbolSearchResult[]` | 전체 프로젝트 심볼 검색 |
247
+ | `searchAllRelations(query)` | `StoredCodeRelation[]` | 전체 프로젝트 관계 검색 |
248
+ | `listIndexedFiles(project?)` | `FileRecord[]` | 인덱싱된 파일 목록 |
249
+ | `getSymbolsByFile(filePath)` | `SymbolSearchResult[]` | 단일 파일의 모든 심볼 |
251
250
 
252
251
  ### 의존성 그래프
253
252
 
254
253
  | 메서드 | 반환 타입 | 설명 |
255
254
  |--------|-----------|------|
256
- | `getDependencies(filePath)` | `Result<string[]>` | `filePath`가 import하는 파일 목록 |
257
- | `getDependents(filePath)` | `Result<string[]>` | `filePath`를 import하는 파일 목록 |
258
- | `getAffected(changedFiles)` | `Promise<Result<string[]>>` | 전이적 영향 범위 |
259
- | `hasCycle(project?)` | `Promise<Result<boolean>>` | 순환 의존성 감지 |
260
- | `getCyclePaths(project?, opts?)` | `Promise<Result<string[][]>>` | 모든 순환 경로 (Tarjan SCC + Johnson's). `opts.maxCycles`로 개수 제한 가능. |
261
- | `getImportGraph(project?)` | `Promise<Result<Map>>` | 전체 인접 리스트 |
262
- | `getTransitiveDependencies(filePath)` | `Promise<Result<string[]>>` | 전방 전이적 BFS |
255
+ | `getDependencies(filePath)` | `string[]` | `filePath`가 import하는 파일 목록 |
256
+ | `getDependents(filePath)` | `string[]` | `filePath`를 import하는 파일 목록 |
257
+ | `getAffected(changedFiles)` | `Promise<string[]>` | 전이적 영향 범위 |
258
+ | `hasCycle(project?)` | `Promise<boolean>` | 순환 의존성 감지 |
259
+ | `getCyclePaths(project?, opts?)` | `Promise<string[][]>` | 모든 순환 경로 (Tarjan SCC + Johnson's). `opts.maxCycles`로 개수 제한 가능. |
260
+ | `getImportGraph(project?)` | `Promise<Map>` | 전체 인접 리스트 |
261
+ | `getTransitiveDependencies(filePath)` | `Promise<string[]>` | 전방 전이적 BFS |
263
262
 
264
263
  ### 분석
265
264
 
266
265
  | 메서드 | 반환 타입 | 설명 |
267
266
  |--------|-----------|------|
268
- | `getFullSymbol(name, filePath)` | `Result<FullSymbol>` | 멤버, jsDoc, 데코레이터, 타입 정보 |
269
- | `getFileStats(filePath)` | `Result<FileStats>` | 라인 수, 심볼 수, 파일 크기 |
270
- | `getFanMetrics(filePath)` | `Promise<Result<FanMetrics>>` | fan-in/fan-out 결합도 |
271
- | `getModuleInterface(filePath)` | `Result<ModuleInterface>` | 공개 export와 메타데이터 |
272
- | `getInternalRelations(filePath)` | `Result<StoredCodeRelation[]>` | 파일 내부 관계 |
267
+ | `getFullSymbol(name, filePath)` | `FullSymbol \| null` | 멤버, jsDoc, 데코레이터, 타입 정보 |
268
+ | `getFileStats(filePath)` | `FileStats` | 라인 수, 심볼 수, 파일 크기 |
269
+ | `getFanMetrics(filePath)` | `Promise<FanMetrics>` | fan-in/fan-out 결합도 |
270
+ | `getModuleInterface(filePath)` | `ModuleInterface` | 공개 export와 메타데이터 |
271
+ | `getInternalRelations(filePath)` | `StoredCodeRelation[]` | 파일 내부 관계 |
273
272
  | `diffSymbols(before, after)` | `SymbolDiff` | 스냅샷 diff (추가/삭제/수정) |
274
273
 
275
274
  ### 시맨틱 (opt-in)
@@ -278,10 +277,10 @@ if (isErr(result)) {
278
277
 
279
278
  | 메서드 | 반환 타입 | 설명 |
280
279
  |--------|-----------|------|
281
- | `getResolvedType(name, filePath)` | `Result<ResolvedType \| null>` | tsc TypeChecker로 resolved type 조회 |
282
- | `getSemanticReferences(name, filePath)` | `Result<SemanticReference[]>` | 심볼의 모든 참조 위치 |
283
- | `getImplementations(name, filePath)` | `Result<Implementation[]>` | 인터페이스/추상 클래스 구현체 |
284
- | `getSemanticModuleInterface(filePath)` | `Result<SemanticModuleInterface>` | 모듈 export 목록 + resolved type |
280
+ | `getResolvedType(name, filePath)` | `ResolvedType \| null` | tsc TypeChecker로 resolved type 조회 |
281
+ | `getSemanticReferences(name, filePath)` | `SemanticReference[]` | 심볼의 모든 참조 위치 |
282
+ | `getImplementations(name, filePath)` | `Implementation[]` | 인터페이스/추상 클래스 구현체 |
283
+ | `getSemanticModuleInterface(filePath)` | `SemanticModuleInterface` | 모듈 export 목록 + resolved type |
285
284
 
286
285
  `getFullSymbol()`은 semantic 활성 시 자동으로 `resolvedType` 필드를 보강합니다.
287
286
  `searchSymbols({ resolvedType })`로 resolved type 문자열 기반 필터링이 가능합니다.
@@ -290,25 +289,28 @@ if (isErr(result)) {
290
289
 
291
290
  | 메서드 | 반환 타입 | 설명 |
292
291
  |--------|-----------|------|
293
- | `findPattern(pattern, opts?)` | `Promise<Result<PatternMatch[]>>` | AST 구조적 검색 (ast-grep) |
294
- | `resolveSymbol(name, filePath)` | `Result<ResolvedSymbol>` | re-export 체인을 따라 원본 추적 |
295
- | `getHeritageChain(name, filePath)` | `Promise<Result<HeritageNode>>` | extends/implements 트리 |
296
- | `batchParse(filePaths, opts?)` | `Promise<Result<Map>>` | 다중 파일 동시 파싱. `opts`: oxc-parser `ParserOptions`. |
292
+ | `findPattern(pattern, opts?)` | `Promise<PatternMatch[]>` | AST 구조적 검색 (ast-grep) |
293
+ | `resolveSymbol(name, filePath)` | `ResolvedSymbol` | re-export 체인을 따라 원본 추적 |
294
+ | `getHeritageChain(name, filePath)` | `Promise<HeritageNode>` | extends/implements 트리 |
295
+ | `batchParse(filePaths, opts?)` | `Promise<BatchParseResult>` | 다중 파일 동시 파싱. `{ parsed, failures }` 반환. `opts`: oxc-parser `ParserOptions`. |
297
296
 
298
297
  ### 라이프사이클 & 저수준
299
298
 
300
299
  | 메서드 | 반환 타입 | 설명 |
301
300
  |--------|-----------|------|
302
- | `reindex()` | `Promise<Result<IndexResult>>` | 강제 전체 재인덱싱 (owner만 가능) |
301
+ | `reindex()` | `Promise<IndexResult>` | 강제 전체 재인덱싱 (owner만 가능) |
303
302
  | `onIndexed(callback)` | `() => void` | 인덱싱 완료 이벤트 구독 |
304
- | `parseSource(filePath, src, opts?)` | `Result<ParsedFile>` | 단일 파일 파싱 & 캐시. `opts`: oxc-parser `ParserOptions`. |
305
- | `extractSymbols(parsed)` | `Result<ExtractedSymbol[]>` | 파싱된 AST에서 심볼 추출 |
306
- | `extractRelations(parsed)` | `Result<CodeRelation[]>` | 파싱된 AST에서 관계 추출 |
303
+ | `onFileChanged(callback)` | `() => void` | 파일 변경 이벤트 구독 |
304
+ | `onError(callback)` | `() => void` | 에러 이벤트 구독 |
305
+ | `onRoleChanged(callback)` | `() => void` | owner/reader 역할 변경 이벤트 구독 |
306
+ | `parseSource(filePath, src, opts?)` | `ParsedFile` | 단일 파일 파싱 & 캐시. `opts`: oxc-parser `ParserOptions`. |
307
+ | `extractSymbols(parsed)` | `ExtractedSymbol[]` | 파싱된 AST에서 심볼 추출 |
308
+ | `extractRelations(parsed)` | `CodeRelation[]` | 파싱된 AST에서 관계 추출 |
307
309
  | `getParsedAst(filePath)` | `ParsedFile \| undefined` | 캐시된 AST 조회 (읽기 전용) |
308
- | `getFileInfo(filePath)` | `Result<FileRecord \| null>` | 파일 메타데이터 (해시, mtime, 크기) |
309
- | `getStats(project?)` | `Result<SymbolStats>` | 심볼/파일 통계 |
310
+ | `getFileInfo(filePath)` | `FileRecord \| null` | 파일 메타데이터 (해시, mtime, 크기) |
311
+ | `getStats(project?)` | `SymbolStats` | 심볼/파일 통계 |
310
312
  | `projects` | `ProjectBoundary[]` | 탐지된 프로젝트 경계 |
311
- | `close(opts?)` | `Promise<Result<void>>` | 종료 (`{ cleanup: true }`로 DB 삭제 가능) |
313
+ | `close(opts?)` | `Promise<void>` | 종료 (`{ cleanup: true }`로 DB 삭제 가능) |
312
314
 
313
315
  <br>
314
316
 
@@ -362,10 +364,10 @@ interface IndexResult {
362
364
  };
363
365
  }
364
366
 
365
- interface GildashError {
366
- type: GildashErrorType;
367
- message: string;
368
- cause?: unknown;
367
+ class GildashError extends Error {
368
+ readonly type: GildashErrorType;
369
+ readonly message: string;
370
+ readonly cause?: unknown; // Error에서 상속
369
371
  }
370
372
  ```
371
373
 
@@ -408,11 +410,44 @@ Gildash (파사드)
408
410
  동일 SQLite DB를 여러 프로세스가 공유할 때, 단일 writer를 보장합니다:
409
411
 
410
412
  - **Owner** — 파일 워처 실행, 인덱싱 수행, 30초 간격으로 heartbeat 전송
411
- - **Reader** — 읽기 전용 접근; 60초 간격으로 owner 상태 확인, owner가 stale 상태가 되면 reader 중 하나가 owner로 승격
413
+ - **Reader** — 읽기 전용 접근; 15초 간격으로 owner 상태 확인, owner가 60초 이상 stale 상태이면 reader 중 하나가 owner로 승격
412
414
 
413
415
  <br>
414
416
 
415
- ## ⬆️ 0.5.0에서 업그레이드
417
+ ## ⬆️ 업그레이드
418
+
419
+ ### 0.7.x → 0.8.0
420
+
421
+ **Breaking:** `batchParse()`가 `Map<string, ParsedFile>` 대신 `BatchParseResult` (`parsed` + `failures` 필드)를 반환합니다.
422
+
423
+ ```diff
424
+ - const parsed = await ledger.batchParse(filePaths);
425
+ - const ast = parsed.get('src/app.ts');
426
+ + const { parsed, failures } = await ledger.batchParse(filePaths);
427
+ + const ast = parsed.get('src/app.ts');
428
+ + if (failures.length > 0) console.warn('실패:', failures);
429
+ ```
430
+
431
+ **새 이벤트 메서드:** `onFileChanged()`, `onError()`, `onRoleChanged()`가 `onIndexed()`와 함께 추가되었습니다.
432
+
433
+ ### 0.6.x → 0.7.0
434
+
435
+ **Breaking:** `@zipbul/result`가 더 이상 public API의 일부가 아닙니다. 모든 메서드가 값을 직접 반환하고, 실패 시 `GildashError`를 throw합니다.
436
+
437
+ ```diff
438
+ - import { isErr } from '@zipbul/result';
439
+ - const result = ledger.searchSymbols({ text: 'foo' });
440
+ - if (isErr(result)) { console.error(result.data.message); }
441
+ - else { console.log(result); }
442
+ + const symbols = ledger.searchSymbols({ text: 'foo' }); // 실패 시 GildashError throw
443
+ ```
444
+
445
+ - `@zipbul/result`를 의존성에서 제거하세요 (더 이상 피어 의존성이 아닙니다)
446
+ - `isErr()` 체크를 `try/catch` + `instanceof GildashError`로 교체하세요
447
+ - `getFullSymbol()`, `getFileInfo()`, `getResolvedType()`은 찾지 못하면 에러 대신 `null`을 반환합니다
448
+ - `resolveSymbol()`은 순환 re-export 시 throw 대신 `{ circular: true }`를 반환합니다
449
+
450
+ ### 0.4.x → 0.5.0
416
451
 
417
452
  데이터베이스 디렉토리가 `.zipbul/`에서 `.gildash/`로 변경되었습니다. 데이터베이스는 `<projectRoot>/.gildash/gildash.db`에 저장됩니다.
418
453
 
package/README.md CHANGED
@@ -50,7 +50,7 @@ gildash indexes your TypeScript codebase into a local SQLite database, then lets
50
50
  bun add @zipbul/gildash
51
51
  ```
52
52
 
53
- > **Peer dependency** — [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result) is required. All public methods return `Result<T, GildashError>`.
53
+ > **Optional peer** — `typescript` (>=5.0.0) is needed only when using `semantic: true`.
54
54
 
55
55
  <br>
56
56
 
@@ -58,7 +58,6 @@ bun add @zipbul/gildash
58
58
 
59
59
  ```ts
60
60
  import { Gildash } from '@zipbul/gildash';
61
- import { isErr } from '@zipbul/result';
62
61
 
63
62
  // 1. Open — indexes every .ts file on first run, then watches for changes
64
63
  const ledger = await Gildash.open({
@@ -66,10 +65,8 @@ const ledger = await Gildash.open({
66
65
  });
67
66
 
68
67
  // 2. Search — find symbols by name
69
- const result = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
70
- if (!isErr(result)) {
71
- result.forEach(s => console.log(`${s.name} → ${s.filePath}`));
72
- }
68
+ const symbols = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
69
+ symbols.forEach(s => console.log(`${s.name} → ${s.filePath}`));
73
70
 
74
71
  // 3. Close — release resources
75
72
  await ledger.close();
@@ -202,16 +199,18 @@ await ledger.close({ cleanup: true }); // delete DB files after use
202
199
 
203
200
  ## ❌ Error Handling
204
201
 
205
- Every public method returns `Result<T, GildashError>` from [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result). Use `isErr()` to branch:
202
+ Public methods return values directly and throw `GildashError` on failure. Use `instanceof` to branch:
206
203
 
207
204
  ```ts
208
- import { isErr } from '@zipbul/result';
209
-
210
- const result = ledger.searchSymbols({ text: 'foo' });
211
- if (isErr(result)) {
212
- console.error(result.data.type, result.data.message);
213
- } else {
214
- console.log(`Found ${result.length} symbols`);
205
+ import { Gildash, GildashError } from '@zipbul/gildash';
206
+
207
+ try {
208
+ const symbols = ledger.searchSymbols({ text: 'foo' });
209
+ console.log(`Found ${symbols.length} symbols`);
210
+ } catch (e) {
211
+ if (e instanceof GildashError) {
212
+ console.error(`[${e.type}] ${e.message}`);
213
+ }
215
214
  }
216
215
  ```
217
216
 
@@ -231,9 +230,9 @@ if (isErr(result)) {
231
230
  | `watchMode` | `boolean` | `true` | `false` disables the file watcher (scan-only mode) |
232
231
  | `semantic` | `boolean` | `false` | Enable tsc TypeChecker-backed semantic analysis |
233
232
 
234
- Returns `Promise<Gildash>` (wrapped in `Result`).
233
+ Returns `Promise<Gildash>`. Throws `GildashError` on failure.
235
234
 
236
- > **Note:** `semantic: true` requires a `tsconfig.json` in the project root. If not found, `Gildash.open()` returns a `GildashError`.
235
+ > **Note:** `semantic: true` requires a `tsconfig.json` in the project root. If not found, `Gildash.open()` throws a `GildashError`.
237
236
 
238
237
  <br>
239
238
 
@@ -243,34 +242,34 @@ Returns `Promise<Gildash>` (wrapped in `Result`).
243
242
 
244
243
  | Method | Returns | Description |
245
244
  |--------|---------|-------------|
246
- | `searchSymbols(query)` | `Result<SymbolSearchResult[]>` | FTS5 full-text + exact / regex / decorator filters |
247
- | `searchRelations(query)` | `Result<StoredCodeRelation[]>` | Filter by file, symbol, or relation type |
248
- | `searchAllSymbols(query)` | `Result<SymbolSearchResult[]>` | Cross-project symbol search |
249
- | `searchAllRelations(query)` | `Result<StoredCodeRelation[]>` | Cross-project relation search |
250
- | `listIndexedFiles(project?)` | `Result<FileRecord[]>` | All indexed files for a project |
251
- | `getSymbolsByFile(filePath)` | `Result<SymbolSearchResult[]>` | All symbols in a single file |
245
+ | `searchSymbols(query)` | `SymbolSearchResult[]` | FTS5 full-text + exact / regex / decorator filters |
246
+ | `searchRelations(query)` | `StoredCodeRelation[]` | Filter by file, symbol, or relation type |
247
+ | `searchAllSymbols(query)` | `SymbolSearchResult[]` | Cross-project symbol search |
248
+ | `searchAllRelations(query)` | `StoredCodeRelation[]` | Cross-project relation search |
249
+ | `listIndexedFiles(project?)` | `FileRecord[]` | All indexed files for a project |
250
+ | `getSymbolsByFile(filePath)` | `SymbolSearchResult[]` | All symbols in a single file |
252
251
 
253
252
  ### Dependency Graph
254
253
 
255
254
  | Method | Returns | Description |
256
255
  |--------|---------|-------------|
257
- | `getDependencies(filePath)` | `Result<string[]>` | Files imported by `filePath` |
258
- | `getDependents(filePath)` | `Result<string[]>` | Files that import `filePath` |
259
- | `getAffected(changedFiles)` | `Promise<Result<string[]>>` | Transitive impact set |
260
- | `hasCycle(project?)` | `Promise<Result<boolean>>` | Circular dependency check |
261
- | `getCyclePaths(project?, opts?)` | `Promise<Result<string[][]>>` | All cycle paths (Tarjan SCC + Johnson's). `opts.maxCycles` limits results. |
262
- | `getImportGraph(project?)` | `Promise<Result<Map>>` | Full adjacency list |
263
- | `getTransitiveDependencies(filePath)` | `Promise<Result<string[]>>` | Forward transitive BFS |
256
+ | `getDependencies(filePath)` | `string[]` | Files imported by `filePath` |
257
+ | `getDependents(filePath)` | `string[]` | Files that import `filePath` |
258
+ | `getAffected(changedFiles)` | `Promise<string[]>` | Transitive impact set |
259
+ | `hasCycle(project?)` | `Promise<boolean>` | Circular dependency check |
260
+ | `getCyclePaths(project?, opts?)` | `Promise<string[][]>` | All cycle paths (Tarjan SCC + Johnson's). `opts.maxCycles` limits results. |
261
+ | `getImportGraph(project?)` | `Promise<Map>` | Full adjacency list |
262
+ | `getTransitiveDependencies(filePath)` | `Promise<string[]>` | Forward transitive BFS |
264
263
 
265
264
  ### Analysis
266
265
 
267
266
  | Method | Returns | Description |
268
267
  |--------|---------|-------------|
269
- | `getFullSymbol(name, filePath)` | `Result<FullSymbol>` | Members, jsDoc, decorators, type info |
270
- | `getFileStats(filePath)` | `Result<FileStats>` | Line count, symbol count, size |
271
- | `getFanMetrics(filePath)` | `Promise<Result<FanMetrics>>` | Fan-in / fan-out coupling |
272
- | `getModuleInterface(filePath)` | `Result<ModuleInterface>` | Public exports with metadata |
273
- | `getInternalRelations(filePath)` | `Result<StoredCodeRelation[]>` | Intra-file relations |
268
+ | `getFullSymbol(name, filePath)` | `FullSymbol \| null` | Members, jsDoc, decorators, type info |
269
+ | `getFileStats(filePath)` | `FileStats` | Line count, symbol count, size |
270
+ | `getFanMetrics(filePath)` | `Promise<FanMetrics>` | Fan-in / fan-out coupling |
271
+ | `getModuleInterface(filePath)` | `ModuleInterface` | Public exports with metadata |
272
+ | `getInternalRelations(filePath)` | `StoredCodeRelation[]` | Intra-file relations |
274
273
  | `diffSymbols(before, after)` | `SymbolDiff` | Snapshot diff (added / removed / modified) |
275
274
 
276
275
  ### Semantic (opt-in)
@@ -279,10 +278,10 @@ Requires `semantic: true` at open time.
279
278
 
280
279
  | Method | Returns | Description |
281
280
  |--------|---------|-------------|
282
- | `getResolvedType(name, filePath)` | `Result<ResolvedType \| null>` | Resolved type via tsc TypeChecker |
283
- | `getSemanticReferences(name, filePath)` | `Result<SemanticReference[]>` | All references to a symbol |
284
- | `getImplementations(name, filePath)` | `Result<Implementation[]>` | Interface / abstract class implementations |
285
- | `getSemanticModuleInterface(filePath)` | `Result<SemanticModuleInterface>` | Module exports with resolved types |
281
+ | `getResolvedType(name, filePath)` | `ResolvedType \| null` | Resolved type via tsc TypeChecker |
282
+ | `getSemanticReferences(name, filePath)` | `SemanticReference[]` | All references to a symbol |
283
+ | `getImplementations(name, filePath)` | `Implementation[]` | Interface / abstract class implementations |
284
+ | `getSemanticModuleInterface(filePath)` | `SemanticModuleInterface` | Module exports with resolved types |
286
285
 
287
286
  `getFullSymbol()` automatically enriches the result with a `resolvedType` field when semantic is enabled.
288
287
  `searchSymbols({ resolvedType })` filters symbols by their resolved type string.
@@ -291,25 +290,28 @@ Requires `semantic: true` at open time.
291
290
 
292
291
  | Method | Returns | Description |
293
292
  |--------|---------|-------------|
294
- | `findPattern(pattern, opts?)` | `Promise<Result<PatternMatch[]>>` | AST structural search (ast-grep) |
295
- | `resolveSymbol(name, filePath)` | `Result<ResolvedSymbol>` | Follow re-export chain to original |
296
- | `getHeritageChain(name, filePath)` | `Promise<Result<HeritageNode>>` | extends / implements tree |
297
- | `batchParse(filePaths, opts?)` | `Promise<Result<Map>>` | Concurrent multi-file parsing. `opts`: oxc-parser `ParserOptions`. |
293
+ | `findPattern(pattern, opts?)` | `Promise<PatternMatch[]>` | AST structural search (ast-grep) |
294
+ | `resolveSymbol(name, filePath)` | `ResolvedSymbol` | Follow re-export chain to original |
295
+ | `getHeritageChain(name, filePath)` | `Promise<HeritageNode>` | extends / implements tree |
296
+ | `batchParse(filePaths, opts?)` | `Promise<BatchParseResult>` | Concurrent multi-file parsing. Returns `{ parsed, failures }`. `opts`: oxc-parser `ParserOptions`. |
298
297
 
299
298
  ### Lifecycle & Low-level
300
299
 
301
300
  | Method | Returns | Description |
302
301
  |--------|---------|-------------|
303
- | `reindex()` | `Promise<Result<IndexResult>>` | Force full re-index (owner only) |
302
+ | `reindex()` | `Promise<IndexResult>` | Force full re-index (owner only) |
304
303
  | `onIndexed(callback)` | `() => void` | Subscribe to index-complete events |
305
- | `parseSource(filePath, src, opts?)` | `Result<ParsedFile>` | Parse & cache a single file. `opts`: oxc-parser `ParserOptions`. |
306
- | `extractSymbols(parsed)` | `Result<ExtractedSymbol[]>` | Extract symbols from parsed AST |
307
- | `extractRelations(parsed)` | `Result<CodeRelation[]>` | Extract relations from parsed AST |
304
+ | `onFileChanged(callback)` | `() => void` | Subscribe to file-change events |
305
+ | `onError(callback)` | `() => void` | Subscribe to error events |
306
+ | `onRoleChanged(callback)` | `() => void` | Subscribe to owner/reader role-change events |
307
+ | `parseSource(filePath, src, opts?)` | `ParsedFile` | Parse & cache a single file. `opts`: oxc-parser `ParserOptions`. |
308
+ | `extractSymbols(parsed)` | `ExtractedSymbol[]` | Extract symbols from parsed AST |
309
+ | `extractRelations(parsed)` | `CodeRelation[]` | Extract relations from parsed AST |
308
310
  | `getParsedAst(filePath)` | `ParsedFile \| undefined` | Cached AST lookup (read-only) |
309
- | `getFileInfo(filePath)` | `Result<FileRecord \| null>` | File metadata (hash, mtime, size) |
310
- | `getStats(project?)` | `Result<SymbolStats>` | Symbol / file count statistics |
311
+ | `getFileInfo(filePath)` | `FileRecord \| null` | File metadata (hash, mtime, size) |
312
+ | `getStats(project?)` | `SymbolStats` | Symbol / file count statistics |
311
313
  | `projects` | `ProjectBoundary[]` | Discovered project boundaries |
312
- | `close(opts?)` | `Promise<Result<void>>` | Shutdown (pass `{ cleanup: true }` to delete DB) |
314
+ | `close(opts?)` | `Promise<void>` | Shutdown (pass `{ cleanup: true }` to delete DB) |
313
315
 
314
316
  <br>
315
317
 
@@ -433,6 +435,7 @@ interface ResolvedSymbol {
433
435
  originalName: string;
434
436
  originalFilePath: string;
435
437
  reExportChain: Array<{ filePath: string; exportedAs: string }>;
438
+ circular: boolean; // true when re-export chain contains a cycle
436
439
  }
437
440
 
438
441
  interface HeritageNode {
@@ -472,10 +475,10 @@ interface FileRecord {
472
475
 
473
476
  // ── Errors ──────────────────────────────────────────────────────────────
474
477
 
475
- interface GildashError {
476
- type: GildashErrorType; // see Error Types table below
477
- message: string;
478
- cause?: unknown;
478
+ class GildashError extends Error {
479
+ readonly type: GildashErrorType; // see Error Types table below
480
+ readonly message: string;
481
+ readonly cause?: unknown; // inherited from Error
479
482
  }
480
483
  ```
481
484
 
@@ -518,11 +521,44 @@ Gildash (Facade)
518
521
  When multiple processes share the same SQLite database, gildash enforces a single-writer guarantee:
519
522
 
520
523
  - **Owner** — Runs the file watcher, performs indexing, sends a heartbeat every 30 s
521
- - **Reader** — Read-only access; polls owner health every 60 s and self-promotes if the owner goes stale
524
+ - **Reader** — Read-only access; polls owner health every 15 s and self-promotes if the owner goes stale (60 s threshold)
522
525
 
523
526
  <br>
524
527
 
525
- ## ⬆️ Upgrading from 0.5.0
528
+ ## ⬆️ Upgrading
529
+
530
+ ### From 0.7.x to 0.8.0
531
+
532
+ **Breaking:** `batchParse()` now returns `BatchParseResult` (with `parsed` and `failures` fields) instead of `Map<string, ParsedFile>`.
533
+
534
+ ```diff
535
+ - const parsed = await ledger.batchParse(filePaths);
536
+ - const ast = parsed.get('src/app.ts');
537
+ + const { parsed, failures } = await ledger.batchParse(filePaths);
538
+ + const ast = parsed.get('src/app.ts');
539
+ + if (failures.length > 0) console.warn('Failed:', failures);
540
+ ```
541
+
542
+ **New event methods:** `onFileChanged()`, `onError()`, `onRoleChanged()` added alongside `onIndexed()`.
543
+
544
+ ### From 0.6.x to 0.7.0
545
+
546
+ **Breaking:** `@zipbul/result` is no longer part of the public API. All methods now return values directly and throw `GildashError` on failure.
547
+
548
+ ```diff
549
+ - import { isErr } from '@zipbul/result';
550
+ - const result = ledger.searchSymbols({ text: 'foo' });
551
+ - if (isErr(result)) { console.error(result.data.message); }
552
+ - else { console.log(result); }
553
+ + const symbols = ledger.searchSymbols({ text: 'foo' }); // throws GildashError
554
+ ```
555
+
556
+ - Remove `@zipbul/result` from your dependencies (no longer a peer dependency)
557
+ - Replace `isErr()` checks with `try/catch` using `instanceof GildashError`
558
+ - `getFullSymbol()`, `getFileInfo()`, `getResolvedType()` return `null` instead of an error when not found
559
+ - `resolveSymbol()` returns `{ circular: true }` for circular re-exports instead of throwing
560
+
561
+ ### From 0.4.x to 0.5.0
526
562
 
527
563
  The database directory was renamed from `.zipbul/` to `.gildash/`. The database is now stored at `<projectRoot>/.gildash/gildash.db`.
528
564