@zipbul/gildash 0.5.1 → 0.7.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.
Files changed (40) hide show
  1. package/README.ko.md +92 -52
  2. package/README.md +94 -51
  3. package/dist/index.js +7 -5
  4. package/dist/index.js.map +42 -28
  5. package/dist/migrations/0003_majestic_mongu.sql +1 -0
  6. package/dist/migrations/0004_cool_firestar.sql +23 -0
  7. package/dist/migrations/meta/0003_snapshot.json +422 -0
  8. package/dist/migrations/meta/0004_snapshot.json +429 -0
  9. package/dist/migrations/meta/_journal.json +14 -0
  10. package/dist/src/errors.d.ts +9 -7
  11. package/dist/src/extractor/relation-extractor.d.ts +2 -1
  12. package/dist/src/gildash/context.d.ts +91 -0
  13. package/dist/src/gildash/extract-api.d.ts +7 -0
  14. package/dist/src/gildash/graph-api.d.ts +28 -0
  15. package/dist/src/gildash/index.d.ts +91 -0
  16. package/dist/src/gildash/lifecycle.d.ts +60 -0
  17. package/dist/src/gildash/misc-api.d.ts +20 -0
  18. package/dist/src/gildash/parse-api.d.ts +9 -0
  19. package/dist/src/gildash/query-api.d.ts +33 -0
  20. package/dist/src/gildash/semantic-api.d.ts +20 -0
  21. package/dist/src/gildash/types.d.ts +162 -0
  22. package/dist/src/index.d.ts +4 -3
  23. package/dist/src/indexer/index-coordinator.d.ts +8 -2
  24. package/dist/src/indexer/relation-indexer.d.ts +6 -0
  25. package/dist/src/search/dependency-graph.d.ts +1 -0
  26. package/dist/src/search/relation-search.d.ts +11 -1
  27. package/dist/src/search/symbol-search.d.ts +6 -0
  28. package/dist/src/semantic/ast-node-utils.d.ts +9 -0
  29. package/dist/src/semantic/implementation-finder.d.ts +22 -0
  30. package/dist/src/semantic/index.d.ts +68 -0
  31. package/dist/src/semantic/reference-resolver.d.ts +19 -0
  32. package/dist/src/semantic/symbol-graph.d.ts +36 -0
  33. package/dist/src/semantic/tsc-program.d.ts +67 -0
  34. package/dist/src/semantic/type-collector.d.ts +27 -0
  35. package/dist/src/semantic/types.d.ts +103 -0
  36. package/dist/src/store/repositories/relation.repository.d.ts +14 -2
  37. package/dist/src/store/repositories/symbol.repository.d.ts +2 -0
  38. package/dist/src/store/schema.d.ts +38 -0
  39. package/package.json +10 -4
  40. package/dist/src/gildash.d.ts +0 -821
package/README.ko.md CHANGED
@@ -32,9 +32,8 @@ gildash는 TypeScript 코드베이스를 로컬 SQLite 데이터베이스에 인
32
32
  - **심볼 레벨 diff** — `IndexResult`의 `changedSymbols`로 인덱싱 사이클 당 추가/수정/삭제된 심볼 추적
33
33
  - **멀티 프로세스 안전** — owner/reader 역할 분리로 단일 writer 보장
34
34
  - **스캔 전용 모드** — `watchMode: false`로 파일 워처 없이 1회성 인덱싱
35
- - **외부 패키지 인덱싱** — `node_modules`의 `.d.ts` 타입 선언 인덱싱
36
35
  - **tsconfig.json JSONC** — `tsconfig.json`의 주석(`//`, `/* */`)과 트레일링 콤마를 지원하는 경로 별칭 파싱
37
-
36
+ - **시맨틱 레이어 (opt-in)** — tsc TypeChecker 통합으로 resolved type, 참조, 구현체, 모듈 인터페이스 분석
38
37
  <br>
39
38
 
40
39
  ## 📋 요구사항
@@ -50,7 +49,7 @@ gildash는 TypeScript 코드베이스를 로컬 SQLite 데이터베이스에 인
50
49
  bun add @zipbul/gildash
51
50
  ```
52
51
 
53
- > **피어 의존성** — [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result) 필요합니다. 모든 public 메서드는 `Result<T, GildashError>`를 반환합니다.
52
+ > **선택적 피어 의존성** — `typescript` (>=5.0.0) `semantic: true` 사용 시에만 필요합니다.
54
53
 
55
54
  <br>
56
55
 
@@ -58,7 +57,6 @@ bun add @zipbul/gildash
58
57
 
59
58
  ```ts
60
59
  import { Gildash } from '@zipbul/gildash';
61
- import { isErr } from '@zipbul/result';
62
60
 
63
61
  // 1. 열기 — 최초 실행 시 전체 .ts 파일 인덱싱, 이후 파일 변경 감시
64
62
  const ledger = await Gildash.open({
@@ -66,10 +64,8 @@ const ledger = await Gildash.open({
66
64
  });
67
65
 
68
66
  // 2. 검색 — 이름으로 심볼 찾기
69
- const result = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
70
- if (!isErr(result)) {
71
- result.forEach(s => console.log(`${s.name} → ${s.filePath}`));
72
- }
67
+ const symbols = ledger.searchSymbols({ text: 'UserService', kind: 'class' });
68
+ symbols.forEach(s => console.log(`${s.name} → ${s.filePath}`));
73
69
 
74
70
  // 3. 종료 — 리소스 해제
75
71
  await ledger.close();
@@ -202,16 +198,18 @@ await ledger.close({ cleanup: true }); // DB 파일까지 삭제
202
198
 
203
199
  ## ❌ 에러 처리
204
200
 
205
- 모든 public 메서드는 [`@zipbul/result`](https://www.npmjs.com/package/@zipbul/result)의 `Result<T, GildashError>`를 반환합니다. `isErr()`로 에러를 분기합니다:
201
+ public 메서드는 값을 직접 반환하고, 실패 시 `GildashError`를 throw합니다. `instanceof`로 분기합니다:
206
202
 
207
203
  ```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(`${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
+ }
215
213
  }
216
214
  ```
217
215
 
@@ -229,8 +227,11 @@ if (isErr(result)) {
229
227
  | `parseCacheCapacity` | `number` | `500` | LRU 파싱 캐시 최대 크기 |
230
228
  | `logger` | `Logger` | `console` | 커스텀 로거 (`{ error(...args): void }`) |
231
229
  | `watchMode` | `boolean` | `true` | `false`이면 파일 워처 비활성화 (스캔 전용 모드) |
230
+ | `semantic` | `boolean` | `false` | tsc TypeChecker 기반 시맨틱 분석 활성화 |
232
231
 
233
- **반환**: `Promise<Gildash>` (`Result`로 래핑됨)
232
+ **반환**: `Promise<Gildash>`. 실패 시 `GildashError`를 throw합니다.
233
+
234
+ > **참고:** `semantic: true`는 프로젝트 루트에 `tsconfig.json`이 필요합니다. 없으면 `Gildash.open()`이 `GildashError`를 throw합니다.
234
235
 
235
236
  <br>
236
237
 
@@ -240,60 +241,73 @@ if (isErr(result)) {
240
241
 
241
242
  | 메서드 | 반환 타입 | 설명 |
242
243
  |--------|-----------|------|
243
- | `searchSymbols(query)` | `Result<SymbolSearchResult[]>` | FTS5 전문검색 + exact/regex/decorator 필터 |
244
- | `searchRelations(query)` | `Result<CodeRelation[]>` | 파일, 심볼, 관계 유형 필터 |
245
- | `searchAllSymbols(query)` | `Result<SymbolSearchResult[]>` | 전체 프로젝트 심볼 검색 |
246
- | `searchAllRelations(query)` | `Result<CodeRelation[]>` | 전체 프로젝트 관계 검색 |
247
- | `listIndexedFiles(project?)` | `Result<FileRecord[]>` | 인덱싱된 파일 목록 |
248
- | `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[]` | 단일 파일의 모든 심볼 |
249
250
 
250
251
  ### 의존성 그래프
251
252
 
252
253
  | 메서드 | 반환 타입 | 설명 |
253
254
  |--------|-----------|------|
254
- | `getDependencies(filePath)` | `Result<string[]>` | `filePath`가 import하는 파일 목록 |
255
- | `getDependents(filePath)` | `Result<string[]>` | `filePath`를 import하는 파일 목록 |
256
- | `getAffected(changedFiles)` | `Promise<Result<string[]>>` | 전이적 영향 범위 |
257
- | `hasCycle(project?)` | `Promise<Result<boolean>>` | 순환 의존성 감지 |
258
- | `getCyclePaths(project?, opts?)` | `Promise<Result<string[][]>>` | 모든 순환 경로 (Tarjan SCC + Johnson's). `opts.maxCycles`로 개수 제한 가능. |
259
- | `getImportGraph(project?)` | `Promise<Result<Map>>` | 전체 인접 리스트 |
260
- | `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 |
261
262
 
262
263
  ### 분석
263
264
 
264
265
  | 메서드 | 반환 타입 | 설명 |
265
266
  |--------|-----------|------|
266
- | `getFullSymbol(name, filePath)` | `Result<FullSymbol>` | 멤버, jsDoc, 데코레이터, 타입 정보 |
267
- | `getFileStats(filePath)` | `Result<FileStats>` | 라인 수, 심볼 수, 파일 크기 |
268
- | `getFanMetrics(filePath)` | `Promise<Result<FanMetrics>>` | fan-in/fan-out 결합도 |
269
- | `getModuleInterface(filePath)` | `Result<ModuleInterface>` | 공개 export와 메타데이터 |
270
- | `getInternalRelations(filePath)` | `Result<CodeRelation[]>` | 파일 내부 관계 |
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[]` | 파일 내부 관계 |
271
272
  | `diffSymbols(before, after)` | `SymbolDiff` | 스냅샷 diff (추가/삭제/수정) |
272
273
 
274
+ ### 시맨틱 (opt-in)
275
+
276
+ `semantic: true`로 열어야 사용 가능.
277
+
278
+ | 메서드 | 반환 타입 | 설명 |
279
+ |--------|-----------|------|
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 |
284
+
285
+ `getFullSymbol()`은 semantic 활성 시 자동으로 `resolvedType` 필드를 보강합니다.
286
+ `searchSymbols({ resolvedType })`로 resolved type 문자열 기반 필터링이 가능합니다.
287
+
273
288
  ### 고급
274
289
 
275
290
  | 메서드 | 반환 타입 | 설명 |
276
291
  |--------|-----------|------|
277
- | `findPattern(pattern, opts?)` | `Promise<Result<PatternMatch[]>>` | AST 구조적 검색 (ast-grep) |
278
- | `resolveSymbol(name, filePath)` | `Result<ResolvedSymbol>` | re-export 체인을 따라 원본 추적 |
279
- | `getHeritageChain(name, filePath)` | `Promise<Result<HeritageNode>>` | extends/implements 트리 |
280
- | `indexExternalPackages(packages)` | `Promise<Result<IndexResult[]>>` | `node_modules`의 `.d.ts` 인덱싱 |
281
- | `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<Map>` | 다중 파일 동시 파싱. `opts`: oxc-parser `ParserOptions`. |
282
296
 
283
297
  ### 라이프사이클 & 저수준
284
298
 
285
299
  | 메서드 | 반환 타입 | 설명 |
286
300
  |--------|-----------|------|
287
- | `reindex()` | `Promise<Result<IndexResult>>` | 강제 전체 재인덱싱 (owner만 가능) |
301
+ | `reindex()` | `Promise<IndexResult>` | 강제 전체 재인덱싱 (owner만 가능) |
288
302
  | `onIndexed(callback)` | `() => void` | 인덱싱 완료 이벤트 구독 |
289
- | `parseSource(filePath, src, opts?)` | `Result<ParsedFile>` | 단일 파일 파싱 & 캐시. `opts`: oxc-parser `ParserOptions`. |
290
- | `extractSymbols(parsed)` | `Result<ExtractedSymbol[]>` | 파싱된 AST에서 심볼 추출 |
291
- | `extractRelations(parsed)` | `Result<CodeRelation[]>` | 파싱된 AST에서 관계 추출 |
303
+ | `parseSource(filePath, src, opts?)` | `ParsedFile` | 단일 파일 파싱 & 캐시. `opts`: oxc-parser `ParserOptions`. |
304
+ | `extractSymbols(parsed)` | `ExtractedSymbol[]` | 파싱된 AST에서 심볼 추출 |
305
+ | `extractRelations(parsed)` | `CodeRelation[]` | 파싱된 AST에서 관계 추출 |
292
306
  | `getParsedAst(filePath)` | `ParsedFile \| undefined` | 캐시된 AST 조회 (읽기 전용) |
293
- | `getFileInfo(filePath)` | `Result<FileRecord \| null>` | 파일 메타데이터 (해시, mtime, 크기) |
294
- | `getStats(project?)` | `Result<SymbolStats>` | 심볼/파일 통계 |
307
+ | `getFileInfo(filePath)` | `FileRecord \| null` | 파일 메타데이터 (해시, mtime, 크기) |
308
+ | `getStats(project?)` | `SymbolStats` | 심볼/파일 통계 |
295
309
  | `projects` | `ProjectBoundary[]` | 탐지된 프로젝트 경계 |
296
- | `close(opts?)` | `Promise<Result<void>>` | 종료 (`{ cleanup: true }`로 DB 삭제 가능) |
310
+ | `close(opts?)` | `Promise<void>` | 종료 (`{ cleanup: true }`로 DB 삭제 가능) |
297
311
 
298
312
  <br>
299
313
 
@@ -326,6 +340,11 @@ interface CodeRelation {
326
340
  meta?: Record<string, unknown>;
327
341
  }
328
342
 
343
+ /** 목적지 프로젝트 식별자가 추가된 CodeRelation */
344
+ interface StoredCodeRelation extends CodeRelation {
345
+ dstProject: string;
346
+ }
347
+
329
348
  interface IndexResult {
330
349
  indexedFiles: number;
331
350
  removedFiles: number;
@@ -342,10 +361,10 @@ interface IndexResult {
342
361
  };
343
362
  }
344
363
 
345
- interface GildashError {
346
- type: GildashErrorType;
347
- message: string;
348
- cause?: unknown;
364
+ class GildashError extends Error {
365
+ readonly type: GildashErrorType;
366
+ readonly message: string;
367
+ readonly cause?: unknown; // Error에서 상속
349
368
  }
350
369
  ```
351
370
 
@@ -364,6 +383,7 @@ interface GildashError {
364
383
  | `store` | DB 연산 실패 |
365
384
  | `search` | 검색 쿼리 실패 |
366
385
  | `closed` | 종료된 인스턴스에서 연산 시도 |
386
+ | `semantic` | 시맨틱 레이어 미활성화 또는 tsc 에러 |
367
387
  | `validation` | 잘못된 입력 (e.g. `node_modules`에 패키지 없음) |
368
388
  | `close` | 종료 중 에러 |
369
389
 
@@ -378,6 +398,7 @@ Gildash (파사드)
378
398
  ├── Store — bun:sqlite + drizzle-orm (files · symbols · relations · FTS5), `.gildash/gildash.db`에 저장
379
399
  ├── Indexer — 파일 변경 → 파싱 → 추출 → 저장 파이프라인, 심볼 레벨 diff
380
400
  ├── Search — FTS + regex + decorator 검색, 관계 쿼리, 의존성 그래프, ast-grep
401
+ ├── Semantic — tsc TypeChecker 통합 (opt-in): 타입, 참조, 구현체
381
402
  └── Watcher — @parcel/watcher + owner/reader 역할 관리
382
403
  ```
383
404
 
@@ -390,7 +411,26 @@ Gildash (파사드)
390
411
 
391
412
  <br>
392
413
 
393
- ## ⬆️ 0.5.0에서 업그레이드
414
+ ## ⬆️ 업그레이드
415
+
416
+ ### 0.5.x → 0.6.0
417
+
418
+ **Breaking:** `@zipbul/result`가 더 이상 public API의 일부가 아닙니다. 모든 메서드가 값을 직접 반환하고, 실패 시 `GildashError`를 throw합니다.
419
+
420
+ ```diff
421
+ - import { isErr } from '@zipbul/result';
422
+ - const result = ledger.searchSymbols({ text: 'foo' });
423
+ - if (isErr(result)) { console.error(result.data.message); }
424
+ - else { console.log(result); }
425
+ + const symbols = ledger.searchSymbols({ text: 'foo' }); // 실패 시 GildashError throw
426
+ ```
427
+
428
+ - `@zipbul/result`를 의존성에서 제거하세요 (더 이상 피어 의존성이 아닙니다)
429
+ - `isErr()` 체크를 `try/catch` + `instanceof GildashError`로 교체하세요
430
+ - `getFullSymbol()`, `getFileInfo()`, `getResolvedType()`은 찾지 못하면 에러 대신 `null`을 반환합니다
431
+ - `resolveSymbol()`은 순환 re-export 시 throw 대신 `{ circular: true }`를 반환합니다
432
+
433
+ ### 0.4.x → 0.5.0
394
434
 
395
435
  데이터베이스 디렉토리가 `.zipbul/`에서 `.gildash/`로 변경되었습니다. 데이터베이스는 `<projectRoot>/.gildash/gildash.db`에 저장됩니다.
396
436
 
package/README.md CHANGED
@@ -32,8 +32,8 @@ gildash indexes your TypeScript codebase into a local SQLite database, then lets
32
32
  - **Symbol-level diff** — `changedSymbols` in `IndexResult` tracks added/modified/removed symbols per index cycle
33
33
  - **Multi-process safe** — Owner/reader role separation guarantees a single writer per database
34
34
  - **Scan-only mode** — `watchMode: false` for one-shot indexing without file watcher overhead
35
- - **External package indexing** — Index `.d.ts` type declarations from `node_modules`
36
35
  - **tsconfig.json JSONC** — Path alias resolution parses comments and trailing commas in `tsconfig.json`
36
+ - **Semantic layer (opt-in)** — tsc TypeChecker integration for resolved types, references, implementations, and module interface analysis
37
37
 
38
38
  <br>
39
39
 
@@ -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
 
@@ -229,8 +228,11 @@ if (isErr(result)) {
229
228
  | `parseCacheCapacity` | `number` | `500` | LRU parse-cache capacity |
230
229
  | `logger` | `Logger` | `console` | Custom logger (`{ error(...args): void }`) |
231
230
  | `watchMode` | `boolean` | `true` | `false` disables the file watcher (scan-only mode) |
231
+ | `semantic` | `boolean` | `false` | Enable tsc TypeChecker-backed semantic analysis |
232
+
233
+ Returns `Promise<Gildash>`. Throws `GildashError` on failure.
232
234
 
233
- Returns `Promise<Gildash>` (wrapped in `Result`).
235
+ > **Note:** `semantic: true` requires a `tsconfig.json` in the project root. If not found, `Gildash.open()` throws a `GildashError`.
234
236
 
235
237
  <br>
236
238
 
@@ -240,60 +242,73 @@ Returns `Promise<Gildash>` (wrapped in `Result`).
240
242
 
241
243
  | Method | Returns | Description |
242
244
  |--------|---------|-------------|
243
- | `searchSymbols(query)` | `Result<SymbolSearchResult[]>` | FTS5 full-text + exact / regex / decorator filters |
244
- | `searchRelations(query)` | `Result<CodeRelation[]>` | Filter by file, symbol, or relation type |
245
- | `searchAllSymbols(query)` | `Result<SymbolSearchResult[]>` | Cross-project symbol search |
246
- | `searchAllRelations(query)` | `Result<CodeRelation[]>` | Cross-project relation search |
247
- | `listIndexedFiles(project?)` | `Result<FileRecord[]>` | All indexed files for a project |
248
- | `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 |
249
251
 
250
252
  ### Dependency Graph
251
253
 
252
254
  | Method | Returns | Description |
253
255
  |--------|---------|-------------|
254
- | `getDependencies(filePath)` | `Result<string[]>` | Files imported by `filePath` |
255
- | `getDependents(filePath)` | `Result<string[]>` | Files that import `filePath` |
256
- | `getAffected(changedFiles)` | `Promise<Result<string[]>>` | Transitive impact set |
257
- | `hasCycle(project?)` | `Promise<Result<boolean>>` | Circular dependency check |
258
- | `getCyclePaths(project?, opts?)` | `Promise<Result<string[][]>>` | All cycle paths (Tarjan SCC + Johnson's). `opts.maxCycles` limits results. |
259
- | `getImportGraph(project?)` | `Promise<Result<Map>>` | Full adjacency list |
260
- | `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 |
261
263
 
262
264
  ### Analysis
263
265
 
264
266
  | Method | Returns | Description |
265
267
  |--------|---------|-------------|
266
- | `getFullSymbol(name, filePath)` | `Result<FullSymbol>` | Members, jsDoc, decorators, type info |
267
- | `getFileStats(filePath)` | `Result<FileStats>` | Line count, symbol count, size |
268
- | `getFanMetrics(filePath)` | `Promise<Result<FanMetrics>>` | Fan-in / fan-out coupling |
269
- | `getModuleInterface(filePath)` | `Result<ModuleInterface>` | Public exports with metadata |
270
- | `getInternalRelations(filePath)` | `Result<CodeRelation[]>` | 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 |
271
273
  | `diffSymbols(before, after)` | `SymbolDiff` | Snapshot diff (added / removed / modified) |
272
274
 
275
+ ### Semantic (opt-in)
276
+
277
+ Requires `semantic: true` at open time.
278
+
279
+ | Method | Returns | Description |
280
+ |--------|---------|-------------|
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 |
285
+
286
+ `getFullSymbol()` automatically enriches the result with a `resolvedType` field when semantic is enabled.
287
+ `searchSymbols({ resolvedType })` filters symbols by their resolved type string.
288
+
273
289
  ### Advanced
274
290
 
275
291
  | Method | Returns | Description |
276
292
  |--------|---------|-------------|
277
- | `findPattern(pattern, opts?)` | `Promise<Result<PatternMatch[]>>` | AST structural search (ast-grep) |
278
- | `resolveSymbol(name, filePath)` | `Result<ResolvedSymbol>` | Follow re-export chain to original |
279
- | `getHeritageChain(name, filePath)` | `Promise<Result<HeritageNode>>` | extends / implements tree |
280
- | `indexExternalPackages(packages)` | `Promise<Result<IndexResult[]>>` | Index `.d.ts` from `node_modules` |
281
- | `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<Map>` | Concurrent multi-file parsing. `opts`: oxc-parser `ParserOptions`. |
282
297
 
283
298
  ### Lifecycle & Low-level
284
299
 
285
300
  | Method | Returns | Description |
286
301
  |--------|---------|-------------|
287
- | `reindex()` | `Promise<Result<IndexResult>>` | Force full re-index (owner only) |
302
+ | `reindex()` | `Promise<IndexResult>` | Force full re-index (owner only) |
288
303
  | `onIndexed(callback)` | `() => void` | Subscribe to index-complete events |
289
- | `parseSource(filePath, src, opts?)` | `Result<ParsedFile>` | Parse & cache a single file. `opts`: oxc-parser `ParserOptions`. |
290
- | `extractSymbols(parsed)` | `Result<ExtractedSymbol[]>` | Extract symbols from parsed AST |
291
- | `extractRelations(parsed)` | `Result<CodeRelation[]>` | Extract relations from parsed AST |
304
+ | `parseSource(filePath, src, opts?)` | `ParsedFile` | Parse & cache a single file. `opts`: oxc-parser `ParserOptions`. |
305
+ | `extractSymbols(parsed)` | `ExtractedSymbol[]` | Extract symbols from parsed AST |
306
+ | `extractRelations(parsed)` | `CodeRelation[]` | Extract relations from parsed AST |
292
307
  | `getParsedAst(filePath)` | `ParsedFile \| undefined` | Cached AST lookup (read-only) |
293
- | `getFileInfo(filePath)` | `Result<FileRecord \| null>` | File metadata (hash, mtime, size) |
294
- | `getStats(project?)` | `Result<SymbolStats>` | Symbol / file count statistics |
308
+ | `getFileInfo(filePath)` | `FileRecord \| null` | File metadata (hash, mtime, size) |
309
+ | `getStats(project?)` | `SymbolStats` | Symbol / file count statistics |
295
310
  | `projects` | `ProjectBoundary[]` | Discovered project boundaries |
296
- | `close(opts?)` | `Promise<Result<void>>` | Shutdown (pass `{ cleanup: true }` to delete DB) |
311
+ | `close(opts?)` | `Promise<void>` | Shutdown (pass `{ cleanup: true }` to delete DB) |
297
312
 
298
313
  <br>
299
314
 
@@ -332,6 +347,7 @@ interface RelationSearchQuery {
332
347
  srcSymbolName?: string;
333
348
  dstFilePath?: string;
334
349
  dstSymbolName?: string;
350
+ dstProject?: string; // filter by destination project
335
351
  type?: 'imports' | 'type-references' | 're-exports' | 'calls' | 'extends' | 'implements';
336
352
  project?: string;
337
353
  limit?: number; // default: 500
@@ -347,6 +363,11 @@ interface CodeRelation {
347
363
  meta?: Record<string, unknown>; // auto-parsed from metaJson
348
364
  }
349
365
 
366
+ /** CodeRelation enriched with the destination project identifier. */
367
+ interface StoredCodeRelation extends CodeRelation {
368
+ dstProject: string;
369
+ }
370
+
350
371
  // ── Analysis ────────────────────────────────────────────────────────────
351
372
 
352
373
  interface FullSymbol extends SymbolSearchResult {
@@ -411,6 +432,7 @@ interface ResolvedSymbol {
411
432
  originalName: string;
412
433
  originalFilePath: string;
413
434
  reExportChain: Array<{ filePath: string; exportedAs: string }>;
435
+ circular: boolean; // true when re-export chain contains a cycle
414
436
  }
415
437
 
416
438
  interface HeritageNode {
@@ -450,10 +472,10 @@ interface FileRecord {
450
472
 
451
473
  // ── Errors ──────────────────────────────────────────────────────────────
452
474
 
453
- interface GildashError {
454
- type: GildashErrorType; // see Error Types table below
455
- message: string;
456
- cause?: unknown;
475
+ class GildashError extends Error {
476
+ readonly type: GildashErrorType; // see Error Types table below
477
+ readonly message: string;
478
+ readonly cause?: unknown; // inherited from Error
457
479
  }
458
480
  ```
459
481
 
@@ -472,6 +494,7 @@ interface GildashError {
472
494
  | `store` | Database operation failure |
473
495
  | `search` | Search query failure |
474
496
  | `closed` | Operation on a closed instance |
497
+ | `semantic` | Semantic layer not enabled or tsc error |
475
498
  | `validation` | Invalid input (e.g. missing `node_modules` package) |
476
499
  | `close` | Error during shutdown |
477
500
 
@@ -486,6 +509,7 @@ Gildash (Facade)
486
509
  ├── Store — bun:sqlite + drizzle-orm (files · symbols · relations · FTS5) at `.gildash/gildash.db`
487
510
  ├── Indexer — File change → parse → extract → store pipeline, symbol-level diff
488
511
  ├── Search — FTS + regex + decorator search, relation queries, dependency graph, ast-grep
512
+ ├── Semantic — tsc TypeChecker integration (opt-in): types, references, implementations
489
513
  └── Watcher — @parcel/watcher + owner/reader role management
490
514
  ```
491
515
 
@@ -498,7 +522,26 @@ When multiple processes share the same SQLite database, gildash enforces a singl
498
522
 
499
523
  <br>
500
524
 
501
- ## ⬆️ Upgrading from 0.5.0
525
+ ## ⬆️ Upgrading
526
+
527
+ ### From 0.5.x to 0.6.0
528
+
529
+ **Breaking:** `@zipbul/result` is no longer part of the public API. All methods now return values directly and throw `GildashError` on failure.
530
+
531
+ ```diff
532
+ - import { isErr } from '@zipbul/result';
533
+ - const result = ledger.searchSymbols({ text: 'foo' });
534
+ - if (isErr(result)) { console.error(result.data.message); }
535
+ - else { console.log(result); }
536
+ + const symbols = ledger.searchSymbols({ text: 'foo' }); // throws GildashError
537
+ ```
538
+
539
+ - Remove `@zipbul/result` from your dependencies (no longer a peer dependency)
540
+ - Replace `isErr()` checks with `try/catch` using `instanceof GildashError`
541
+ - `getFullSymbol()`, `getFileInfo()`, `getResolvedType()` return `null` instead of an error when not found
542
+ - `resolveSymbol()` returns `{ circular: true }` for circular re-exports instead of throwing
543
+
544
+ ### From 0.4.x to 0.5.0
502
545
 
503
546
  The database directory was renamed from `.zipbul/` to `.gildash/`. The database is now stored at `<projectRoot>/.gildash/gildash.db`.
504
547