kiri-mcp-server 0.9.6 → 0.10.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 (207) hide show
  1. package/README.md +144 -13
  2. package/dist/client/cli.js +68 -0
  3. package/dist/client/cli.js.map +1 -0
  4. package/dist/client/index.js +5 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/eval/metrics.js +47 -0
  7. package/dist/eval/metrics.js.map +1 -0
  8. package/dist/indexer/cli.js +362 -0
  9. package/dist/indexer/cli.js.map +1 -0
  10. package/dist/indexer/codeintel.js +182 -0
  11. package/dist/indexer/codeintel.js.map +1 -0
  12. package/dist/indexer/git.js +30 -0
  13. package/dist/indexer/git.js.map +1 -0
  14. package/dist/indexer/language.js +34 -0
  15. package/dist/indexer/language.js.map +1 -0
  16. package/dist/indexer/pipeline/filters/denylist.js +71 -0
  17. package/dist/indexer/pipeline/filters/denylist.js.map +1 -0
  18. package/dist/indexer/schema.js +101 -0
  19. package/dist/indexer/schema.js.map +1 -0
  20. package/dist/package.json +14 -1
  21. package/dist/server/bootstrap.js +19 -0
  22. package/dist/server/bootstrap.js.map +1 -0
  23. package/dist/server/context.js +1 -0
  24. package/dist/server/context.js.map +1 -0
  25. package/dist/server/fallbacks/degradeController.js +69 -0
  26. package/dist/server/fallbacks/degradeController.js.map +1 -0
  27. package/dist/server/handlers.js +1268 -0
  28. package/dist/server/handlers.js.map +1 -0
  29. package/dist/server/main.js +151 -0
  30. package/dist/server/main.js.map +1 -0
  31. package/dist/server/observability/metrics.js +56 -0
  32. package/dist/server/observability/metrics.js.map +1 -0
  33. package/dist/server/observability/tracing.js +58 -0
  34. package/dist/server/observability/tracing.js.map +1 -0
  35. package/dist/server/rpc.js +477 -0
  36. package/dist/server/rpc.js.map +1 -0
  37. package/dist/server/runtime.js +47 -0
  38. package/dist/server/runtime.js.map +1 -0
  39. package/dist/server/scoring.js +116 -0
  40. package/dist/server/scoring.js.map +1 -0
  41. package/dist/server/stdio.js +76 -0
  42. package/dist/server/stdio.js.map +1 -0
  43. package/dist/shared/duckdb.js +119 -0
  44. package/dist/shared/duckdb.js.map +1 -0
  45. package/dist/shared/embedding.js +98 -0
  46. package/dist/shared/embedding.js.map +1 -0
  47. package/dist/shared/index.js +9 -0
  48. package/dist/shared/index.js.map +1 -0
  49. package/dist/shared/security/config.js +64 -0
  50. package/dist/shared/security/config.js.map +1 -0
  51. package/dist/shared/security/masker.js +56 -0
  52. package/dist/shared/security/masker.js.map +1 -0
  53. package/dist/shared/tokenizer.js +4 -0
  54. package/dist/shared/tokenizer.js.map +1 -0
  55. package/dist/shared/utils/simpleYaml.js +89 -0
  56. package/dist/shared/utils/simpleYaml.js.map +1 -0
  57. package/dist/src/client/proxy.js +83 -13
  58. package/dist/src/client/proxy.js.map +1 -1
  59. package/dist/src/client/start-daemon.d.ts.map +1 -1
  60. package/dist/src/client/start-daemon.js +2 -1
  61. package/dist/src/client/start-daemon.js.map +1 -1
  62. package/dist/src/daemon/daemon.js +97 -18
  63. package/dist/src/daemon/daemon.js.map +1 -1
  64. package/dist/src/daemon/socket.d.ts +6 -4
  65. package/dist/src/daemon/socket.d.ts.map +1 -1
  66. package/dist/src/daemon/socket.js +62 -18
  67. package/dist/src/daemon/socket.js.map +1 -1
  68. package/dist/src/indexer/cli.d.ts +1 -0
  69. package/dist/src/indexer/cli.d.ts.map +1 -1
  70. package/dist/src/indexer/cli.js +503 -257
  71. package/dist/src/indexer/cli.js.map +1 -1
  72. package/dist/src/indexer/codeintel.d.ts +1 -1
  73. package/dist/src/indexer/codeintel.d.ts.map +1 -1
  74. package/dist/src/indexer/codeintel.js +296 -3
  75. package/dist/src/indexer/codeintel.js.map +1 -1
  76. package/dist/src/indexer/dart/analyze.d.ts +29 -0
  77. package/dist/src/indexer/dart/analyze.d.ts.map +1 -0
  78. package/dist/src/indexer/dart/analyze.js +452 -0
  79. package/dist/src/indexer/dart/analyze.js.map +1 -0
  80. package/dist/src/indexer/dart/client.d.ts +113 -0
  81. package/dist/src/indexer/dart/client.d.ts.map +1 -0
  82. package/dist/src/indexer/dart/client.js +444 -0
  83. package/dist/src/indexer/dart/client.js.map +1 -0
  84. package/dist/src/indexer/dart/config.d.ts +36 -0
  85. package/dist/src/indexer/dart/config.d.ts.map +1 -0
  86. package/dist/src/indexer/dart/config.js +62 -0
  87. package/dist/src/indexer/dart/config.js.map +1 -0
  88. package/dist/src/indexer/dart/dependencies.d.ts +17 -0
  89. package/dist/src/indexer/dart/dependencies.d.ts.map +1 -0
  90. package/dist/src/indexer/dart/dependencies.js +102 -0
  91. package/dist/src/indexer/dart/dependencies.js.map +1 -0
  92. package/dist/src/indexer/dart/pathKey.d.ts +40 -0
  93. package/dist/src/indexer/dart/pathKey.d.ts.map +1 -0
  94. package/dist/src/indexer/dart/pathKey.js +72 -0
  95. package/dist/src/indexer/dart/pathKey.js.map +1 -0
  96. package/dist/src/indexer/dart/poolGate.d.ts +57 -0
  97. package/dist/src/indexer/dart/poolGate.d.ts.map +1 -0
  98. package/dist/src/indexer/dart/poolGate.js +87 -0
  99. package/dist/src/indexer/dart/poolGate.js.map +1 -0
  100. package/dist/src/indexer/dart/sdk.d.ts +40 -0
  101. package/dist/src/indexer/dart/sdk.d.ts.map +1 -0
  102. package/dist/src/indexer/dart/sdk.js +167 -0
  103. package/dist/src/indexer/dart/sdk.js.map +1 -0
  104. package/dist/src/indexer/dart/transform.d.ts +17 -0
  105. package/dist/src/indexer/dart/transform.d.ts.map +1 -0
  106. package/dist/src/indexer/dart/transform.js +157 -0
  107. package/dist/src/indexer/dart/transform.js.map +1 -0
  108. package/dist/src/indexer/dart/types.d.ts +137 -0
  109. package/dist/src/indexer/dart/types.d.ts.map +1 -0
  110. package/dist/src/indexer/dart/types.js +5 -0
  111. package/dist/src/indexer/dart/types.js.map +1 -0
  112. package/dist/src/indexer/git.d.ts +1 -0
  113. package/dist/src/indexer/git.d.ts.map +1 -1
  114. package/dist/src/indexer/git.js +8 -0
  115. package/dist/src/indexer/git.js.map +1 -1
  116. package/dist/src/indexer/language.d.ts.map +1 -1
  117. package/dist/src/indexer/language.js +1 -0
  118. package/dist/src/indexer/language.js.map +1 -1
  119. package/dist/src/indexer/queue.d.ts +19 -0
  120. package/dist/src/indexer/queue.d.ts.map +1 -0
  121. package/dist/src/indexer/queue.js +50 -0
  122. package/dist/src/indexer/queue.js.map +1 -0
  123. package/dist/src/indexer/schema.d.ts +61 -1
  124. package/dist/src/indexer/schema.d.ts.map +1 -1
  125. package/dist/src/indexer/schema.js +253 -2
  126. package/dist/src/indexer/schema.js.map +1 -1
  127. package/dist/src/indexer/watch.d.ts +21 -0
  128. package/dist/src/indexer/watch.d.ts.map +1 -1
  129. package/dist/src/indexer/watch.js +189 -28
  130. package/dist/src/indexer/watch.js.map +1 -1
  131. package/dist/src/server/abbreviations.d.ts +47 -0
  132. package/dist/src/server/abbreviations.d.ts.map +1 -0
  133. package/dist/src/server/abbreviations.js +71 -0
  134. package/dist/src/server/abbreviations.js.map +1 -0
  135. package/dist/src/server/boost-profiles.d.ts +63 -0
  136. package/dist/src/server/boost-profiles.d.ts.map +1 -0
  137. package/dist/src/server/boost-profiles.js +86 -0
  138. package/dist/src/server/boost-profiles.js.map +1 -0
  139. package/dist/src/server/context.d.ts +7 -0
  140. package/dist/src/server/context.d.ts.map +1 -1
  141. package/dist/src/server/handlers.d.ts +3 -2
  142. package/dist/src/server/handlers.d.ts.map +1 -1
  143. package/dist/src/server/handlers.js +542 -96
  144. package/dist/src/server/handlers.js.map +1 -1
  145. package/dist/src/server/indexBootstrap.d.ts.map +1 -1
  146. package/dist/src/server/indexBootstrap.js +4 -1
  147. package/dist/src/server/indexBootstrap.js.map +1 -1
  148. package/dist/src/server/main.d.ts.map +1 -1
  149. package/dist/src/server/main.js +112 -30
  150. package/dist/src/server/main.js.map +1 -1
  151. package/dist/src/server/rpc.d.ts.map +1 -1
  152. package/dist/src/server/rpc.js +28 -9
  153. package/dist/src/server/rpc.js.map +1 -1
  154. package/dist/src/server/rrf.d.ts +86 -0
  155. package/dist/src/server/rrf.d.ts.map +1 -0
  156. package/dist/src/server/rrf.js +108 -0
  157. package/dist/src/server/rrf.js.map +1 -0
  158. package/dist/src/server/runtime.d.ts.map +1 -1
  159. package/dist/src/server/runtime.js +45 -6
  160. package/dist/src/server/runtime.js.map +1 -1
  161. package/dist/src/server/scoring.d.ts.map +1 -1
  162. package/dist/src/server/scoring.js +19 -0
  163. package/dist/src/server/scoring.js.map +1 -1
  164. package/dist/src/shared/cli/args.d.ts +70 -0
  165. package/dist/src/shared/cli/args.d.ts.map +1 -0
  166. package/dist/src/shared/cli/args.js +84 -0
  167. package/dist/src/shared/cli/args.js.map +1 -0
  168. package/dist/src/shared/duckdb.d.ts.map +1 -1
  169. package/dist/src/shared/duckdb.js +9 -0
  170. package/dist/src/shared/duckdb.js.map +1 -1
  171. package/dist/src/shared/embedding/engine.d.ts +38 -0
  172. package/dist/src/shared/embedding/engine.d.ts.map +1 -0
  173. package/dist/src/shared/embedding/engine.js +6 -0
  174. package/dist/src/shared/embedding/engine.js.map +1 -0
  175. package/dist/src/shared/embedding/lsh-engine.d.ts +11 -0
  176. package/dist/src/shared/embedding/lsh-engine.d.ts.map +1 -0
  177. package/dist/src/shared/embedding/lsh-engine.js +14 -0
  178. package/dist/src/shared/embedding/lsh-engine.js.map +1 -0
  179. package/dist/src/shared/embedding/registry.d.ts +25 -0
  180. package/dist/src/shared/embedding/registry.d.ts.map +1 -0
  181. package/dist/src/shared/embedding/registry.js +50 -0
  182. package/dist/src/shared/embedding/registry.js.map +1 -0
  183. package/dist/src/shared/embedding/semantic-engine.d.ts +14 -0
  184. package/dist/src/shared/embedding/semantic-engine.d.ts.map +1 -0
  185. package/dist/src/shared/embedding/semantic-engine.js +50 -0
  186. package/dist/src/shared/embedding/semantic-engine.js.map +1 -0
  187. package/dist/src/shared/models/model-manager.d.ts +38 -0
  188. package/dist/src/shared/models/model-manager.d.ts.map +1 -0
  189. package/dist/src/shared/models/model-manager.js +116 -0
  190. package/dist/src/shared/models/model-manager.js.map +1 -0
  191. package/dist/src/shared/models/model-manifest.d.ts +22 -0
  192. package/dist/src/shared/models/model-manifest.d.ts.map +1 -0
  193. package/dist/src/shared/models/model-manifest.js +24 -0
  194. package/dist/src/shared/models/model-manifest.js.map +1 -0
  195. package/dist/src/shared/utils/path.d.ts +46 -0
  196. package/dist/src/shared/utils/path.d.ts.map +1 -0
  197. package/dist/src/shared/utils/path.js +94 -0
  198. package/dist/src/shared/utils/path.js.map +1 -0
  199. package/dist/src/shared/utils/socket.d.ts +61 -0
  200. package/dist/src/shared/utils/socket.d.ts.map +1 -0
  201. package/dist/src/shared/utils/socket.js +156 -0
  202. package/dist/src/shared/utils/socket.js.map +1 -0
  203. package/dist/src/shared/utils/validation.d.ts +14 -0
  204. package/dist/src/shared/utils/validation.d.ts.map +1 -0
  205. package/dist/src/shared/utils/validation.js +22 -0
  206. package/dist/src/shared/utils/validation.js.map +1 -0
  207. package/package.json +14 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Intelligent code context extraction for LLMs via Model Context Protocol
4
4
 
5
- [![Version](https://img.shields.io/badge/version-0.9.6-blue.svg)](package.json)
5
+ [![Version](https://img.shields.io/badge/version-0.10.0-blue.svg)](package.json)
6
6
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![MCP](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://modelcontextprotocol.io/)
@@ -18,6 +18,13 @@
18
18
  - **👁️ Auto-Sync**: Watch mode automatically re-indexes when files change
19
19
  - **🛡️ Reliable**: Degrade-first architecture works without optional extensions
20
20
  - **📝 Phrase-Aware**: Recognizes compound terms (kebab-case, snake_case) for precise matching
21
+ - **🔒 Concurrency-Safe** _(v0.9.7+)_: Per-database queues, canonicalized DuckDB paths, and bootstrap-safe locking prevent FTS rebuild conflicts and keep locks consistent across symlinks—even on first run
22
+
23
+ ## 🆕 What’s New in v0.9.8
24
+
25
+ - First-time bootstrap now skips redundant DuckDB locking, so `kiri` / `kiri-server` can index fresh repositories without deadlocking on their own locks.
26
+ - Added regression coverage (`tests/server/indexBootstrap.spec.ts`) to ensure repeated `ensureDatabaseIndexed` calls reuse the lock cleanly.
27
+ - All reliability upgrades from v0.9.7 (automatic ILIKE degrade during FTS rebuilds, canonicalized DB paths, expanded verify suite) remain in effect.
21
28
 
22
29
  ## ⚙️ Prerequisites
23
30
 
@@ -104,9 +111,31 @@ For very large repositories (10,000+ files), you may need to increase the timeou
104
111
 
105
112
  > **Note**: The example shows `480` seconds (8 minutes) for very large repositories (>20,000 files). The default `240` seconds (4 minutes) is sufficient for most projects with <10,000 files.
106
113
 
107
- | Variable | Default | Description |
108
- | --------------------------- | ------- | ------------------------------------------------------------------------------ |
109
- | `KIRI_DAEMON_READY_TIMEOUT` | `240` | Daemon initialization timeout in seconds. Increase for very large repositories |
114
+ | Variable | Default | Description |
115
+ | --------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------- |
116
+ | `KIRI_DAEMON_READY_TIMEOUT` | `240` | Daemon initialization timeout in seconds. Increase for very large repositories |
117
+ | `KIRI_SOCKET_DIR` | OS tmp directory | Directory for Unix socket fallback when repo paths are too long (e.g., `/var/run/kiri`). Keeps worktree sockets short |
118
+
119
+ > **Tip**: If you encounter `listen EINVAL` on deep worktrees, set `export KIRI_SOCKET_DIR=/var/run/kiri` (or any short 0700 directory) before launching `kiri`. This fallback ships in v0.9.9+, and an explicit path keeps logs and cleanup predictable.
120
+
121
+ **Dart Analysis Server Configuration:**
122
+
123
+ For projects containing Dart code, KIRI uses the Dart Analysis Server to extract accurate symbol information. The following environment variables control the Dart analyzer behavior:
124
+
125
+ | Variable | Default | Description |
126
+ | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------- |
127
+ | `DART_SDK_DETECT_TIMEOUT_MS` | `5000` | Timeout in milliseconds for SDK detection (prevents hanging on network issues) |
128
+ | `DART_ANALYSIS_MAX_CLIENTS` | `8` | Maximum concurrent Dart Analysis Server processes (prevents memory exhaustion on large monorepos) |
129
+ | `DART_ANALYSIS_CLIENT_WAIT_MS` | `10000` | Max wait time in milliseconds for available analysis server slot |
130
+ | `DART_ANALYSIS_IDLE_MS` | `60000` | Idle time in milliseconds before disposing unused analysis server (60s default) |
131
+ | `DART_FILE_QUEUE_TTL_MS` | `30000` | TTL in milliseconds for file-level request queues (prevents memory leaks) |
132
+
133
+ **When to adjust these values:**
134
+
135
+ - **Large Dart projects (>500 files)**: Increase `DART_ANALYSIS_MAX_CLIENTS` to 16 or 32
136
+ - **Network/UNC path issues**: Decrease `DART_SDK_DETECT_TIMEOUT_MS` to 2000 for faster failure
137
+ - **Memory constraints**: Decrease `DART_ANALYSIS_MAX_CLIENTS` to 4 and increase `DART_ANALYSIS_IDLE_MS` to 30000
138
+ - **Monorepo with many workspaces**: Increase `DART_ANALYSIS_CLIENT_WAIT_MS` to 30000
110
139
 
111
140
  #### For Codex CLI
112
141
 
@@ -194,12 +223,12 @@ Tip: Avoid leading command words like `find` or `show`; instead list concrete mo
194
223
 
195
224
  **Parameters:**
196
225
 
197
- | Parameter | Type | Required | Description |
198
- | --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
199
- | `goal` | string | Yes | Task description or question about the code |
200
- | `limit` | number | No | Max snippets to return (default: 12, max: 20) |
201
- | `compact` | boolean | No | Return only metadata without preview (default: **true** in v0.8.0+, false in v0.7) |
202
- | `boost_profile` | string | No | File type boosting: `"default"` (prioritizes src/, blacklists docs/), `"docs"` **(prioritizes .md/.yaml, includes docs/ directory)**, `"none"` (no boosting) |
226
+ | Parameter | Type | Required | Description |
227
+ | --------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
228
+ | `goal` | string | Yes | Task description or question about the code |
229
+ | `limit` | number | No | Max snippets to return (default: 12, max: 20) |
230
+ | `compact` | boolean | No | Return only metadata without preview (default: **true** in v0.8.0+, false in v0.7) |
231
+ | `boost_profile` | string | No | File type boosting: `"default"` (prioritizes src/, blacklists docs/), `"docs"` (prioritizes .md/.yaml, includes docs/ directory), `"balanced"` (equal weight for docs and impl, NEW in v0.9.10), `"none"` (no boosting) |
203
232
 
204
233
  ### 2. files_search
205
234
 
@@ -478,7 +507,17 @@ const db = await DuckDBClient.connect({
478
507
  Control search ranking behavior with the `boost_profile` parameter:
479
508
 
480
509
  - **`"default"`** (default): Prioritizes implementation files (`src/*.ts`) over documentation
510
+ - Implementation files get 30% boost, documentation files get 50% penalty
511
+ - Config files heavily penalized (95% reduction)
512
+ - `docs/` directory is blacklisted
481
513
  - **`"docs"`**: Prioritizes documentation files (`*.md`) over implementation
514
+ - Documentation files get 50% boost, implementation files get 50% penalty
515
+ - `docs/` directory is included in search results
516
+ - **`"balanced"`** (NEW in v0.9.10): Equal weight for docs and implementation
517
+ - Both documentation and implementation files: no penalty/boost (1.0x)
518
+ - Config files: relaxed penalty (0.3x, compared to 0.05x in default)
519
+ - `docs/` directory is included in search results
520
+ - No path-specific multipliers (treats all `src/` equally)
482
521
  - **`"none"`**: Pure BM25 scoring without file type adjustments
483
522
 
484
523
  ```typescript
@@ -488,6 +527,9 @@ files_search({ query: "authentication", boost_profile: "default" });
488
527
  // Find documentation
489
528
  files_search({ query: "setup guide", boost_profile: "docs" });
490
529
 
530
+ // Balanced search (docs and code equally weighted)
531
+ files_search({ query: "authentication design", boost_profile: "balanced" });
532
+
491
533
  // Pure BM25 ranking without boosting
492
534
  files_search({ query: "API", boost_profile: "none" });
493
535
  ```
@@ -594,6 +636,45 @@ KIRI automatically filters sensitive files and masks sensitive values:
594
636
  - Medium project (1,000-10,000 files): 10-100 MB
595
637
  - Large project (>10,000 files): 100-500 MB
596
638
 
639
+ #### DuckDB Native Binding Errors
640
+
641
+ **Problem**: Error message like `Cannot find module '.../duckdb.node'` when running from a cloned repository
642
+
643
+ **Root Cause**: Using `npm link` with pnpm-installed packages causes native module path resolution issues
644
+
645
+ **Solutions**:
646
+
647
+ 1. **Use pnpm link instead of npm link**:
648
+
649
+ ```bash
650
+ # Remove existing npm link (if any)
651
+ npm unlink -g kiri-mcp-server 2>/dev/null || true
652
+
653
+ # Clean and reinstall
654
+ rm -rf node_modules pnpm-lock.yaml
655
+ pnpm install --frozen-lockfile
656
+
657
+ # Verify native binding exists
658
+ ls -la node_modules/.pnpm/duckdb@*/node_modules/duckdb/lib/binding/duckdb.node
659
+
660
+ # If missing, rebuild DuckDB
661
+ pnpm rebuild duckdb
662
+
663
+ # Build and link (use pnpm, not npm!)
664
+ pnpm run build
665
+ pnpm link --global
666
+ ```
667
+
668
+ 2. **Prerequisites for building DuckDB**:
669
+ - **macOS**: Install Xcode Command Line Tools: `xcode-select --install`
670
+ - **Node.js**: Version 20 or higher: `node -v`
671
+ - **Network**: Access to `npm.duckdb.org` for prebuilt binaries
672
+
673
+ 3. **Unlink when done**:
674
+ ```bash
675
+ pnpm unlink --global kiri-mcp-server
676
+ ```
677
+
597
678
  ### Getting Help
598
679
 
599
680
  If you encounter issues not covered here:
@@ -612,8 +693,18 @@ KIRI provides AST-based symbol extraction for the following languages:
612
693
  | **TypeScript** | `.ts`, `.tsx` | `class`, `interface`, `enum`, `function`, `method` | TypeScript Compiler API |
613
694
  | **Swift** | `.swift` | `class`, `struct`, `protocol`, `enum`, `extension`, `func`, `init`, `property` | tree-sitter-swift |
614
695
  | **PHP** | `.php` | `class`, `interface`, `trait`, `function`, `method`, `property`, `constant`, `namespace` | tree-sitter-php (pure & HTML-mixed) |
696
+ | **Java** | `.java` | `class`, `interface`, `enum`, `annotation`, `method`, `constructor`, `field` | tree-sitter-java |
697
+ | **Dart** | `.dart` | `class`, `mixin`, `enum`, `extension`, `function`, `method`, `getter`, `setter` | Dart Analysis Server |
615
698
 
616
- Other languages are detected and indexed but use full-file snippets instead of symbol-level extraction. Support for additional languages (Rust, Go, Python, Java, etc.) is planned.
699
+ **Dart Integration Features:**
700
+
701
+ - Full IDE-quality symbol extraction via official Dart Analysis Server
702
+ - Automatic SDK detection from PATH or `DART_SDK` environment variable
703
+ - Memory-efficient client pooling with configurable limits
704
+ - Windows path normalization for case-insensitive filesystems
705
+ - Graceful degradation when Dart SDK is unavailable
706
+
707
+ Other languages are detected and indexed but use full-file snippets instead of symbol-level extraction. Support for additional languages (Rust, Go, Python, etc.) is planned.
617
708
 
618
709
  ## 🏗️ How It Works
619
710
 
@@ -666,6 +757,37 @@ See [docs/architecture.md](docs/architecture.md) for detailed technical informat
666
757
  | **Precision @ 10** | ≥ 0.7 | ✅ 0.75 |
667
758
  | **Token Reduction (compact)** | ≥ 90% | ✅ 95% (v0.8) |
668
759
 
760
+ ### Evaluation & Quality Assurance
761
+
762
+ KIRI includes a **Golden Set Evaluation System** for tracking search accuracy over time using representative queries.
763
+
764
+ **Metrics:**
765
+
766
+ - **P@10** (Precision at K=10): Fraction of relevant results in top 10 (target: ≥0.70)
767
+ - **TFFU** (Time To First Useful): Time until first relevant result appears (target: ≤1000ms)
768
+
769
+ **For Developers:**
770
+
771
+ ```bash
772
+ # Run benchmark evaluation (local only)
773
+ pnpm run eval:golden
774
+
775
+ # Verbose output
776
+ pnpm run eval:golden:verbose
777
+ ```
778
+
779
+ The benchmark system evaluates 5+ representative queries across categories (bugfix, feature, refactor, infra, docs) and outputs:
780
+
781
+ - JSON: Detailed per-query results (`var/eval/latest.json`)
782
+ - Markdown: Summary table (`var/eval/latest.md`)
783
+
784
+ **Documentation:**
785
+
786
+ - [Golden Set Guide](tests/eval/goldens/README.md) - Query format, categories, adding queries
787
+ - [Results Recording](tests/eval/results/README.md) - Tracking improvements over time
788
+
789
+ See [docs/testing.md](docs/testing.md) for complete testing and evaluation guidelines.
790
+
669
791
  ### Community
670
792
 
671
793
  - [GitHub Issues](https://github.com/CAPHTECH/kiri/issues) - Bug reports and feature requests
@@ -685,14 +807,23 @@ pnpm install
685
807
  # Build
686
808
  pnpm run build
687
809
 
688
- # Link globally for testing
689
- npm link
810
+ # Link globally for testing (IMPORTANT: use pnpm link, not npm link)
811
+ pnpm link --global
812
+
813
+ # Verify DuckDB native binding is installed
814
+ ls -la node_modules/.pnpm/duckdb@*/node_modules/duckdb/lib/binding/duckdb.node
815
+
816
+ # If duckdb.node is missing, rebuild it
817
+ pnpm rebuild duckdb
690
818
 
691
819
  # Run tests
692
820
  pnpm run test
693
821
 
694
822
  # Start in development mode (HTTP server on :8765)
695
823
  pnpm run dev
824
+
825
+ # Unlink when done
826
+ pnpm unlink --global kiri-mcp-server
696
827
  ```
697
828
 
698
829
  ### Commands Reference
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ import process from "node:process";
3
+ import { bootstrapServer } from "../server/bootstrap.js";
4
+ import { evaluateSecurityStatus, updateSecurityLock } from "../shared/security/config.js";
5
+ function printUsage() {
6
+ console.info(`Usage: pnpm exec tsx src/client/cli.ts <command> [options]\n`);
7
+ console.info(`Commands:`);
8
+ console.info(` security verify [--write-lock] Verify security baseline matches lock file`);
9
+ }
10
+ function formatStatus() {
11
+ const status = evaluateSecurityStatus();
12
+ const lockInfo = status.lockHash ? `hash=${status.lockHash}` : "missing";
13
+ const matchState = status.matches ? "MATCH" : "MISMATCH";
14
+ return [
15
+ `config: ${status.configPath}`,
16
+ `lock: ${status.lockPath} (${lockInfo})`,
17
+ `state: ${matchState}`,
18
+ ].join("\n");
19
+ }
20
+ function handleSecurityVerify(argv) {
21
+ const writeLock = argv.includes("--write-lock");
22
+ const status = evaluateSecurityStatus();
23
+ if (!status.lockHash && writeLock) {
24
+ updateSecurityLock(status.hash);
25
+ console.info("Security lock created.");
26
+ const refreshed = evaluateSecurityStatus();
27
+ console.info([
28
+ `config: ${refreshed.configPath}`,
29
+ `lock: ${refreshed.lockPath} (hash=${refreshed.lockHash})`,
30
+ "state: MATCH",
31
+ ].join("\n"));
32
+ return 0;
33
+ }
34
+ try {
35
+ bootstrapServer({ allowWriteLock: writeLock });
36
+ console.info("Security baseline verified.");
37
+ console.info(formatStatus());
38
+ return 0;
39
+ }
40
+ catch (error) {
41
+ console.error(error instanceof Error ? error.message : String(error));
42
+ console.info(formatStatus());
43
+ return 1;
44
+ }
45
+ }
46
+ export function main(argv = process.argv.slice(2)) {
47
+ const [command, ...rest] = argv;
48
+ switch (command) {
49
+ case "security": {
50
+ const [subcommand, ...subArgs] = rest;
51
+ if (subcommand === "verify") {
52
+ return handleSecurityVerify(subArgs);
53
+ }
54
+ break;
55
+ }
56
+ case undefined:
57
+ printUsage();
58
+ return 1;
59
+ default:
60
+ break;
61
+ }
62
+ printUsage();
63
+ return 1;
64
+ }
65
+ if (process.argv[1] && new URL(import.meta.url).pathname === process.argv[1]) {
66
+ process.exitCode = main();
67
+ }
68
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/client/cli.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAE1F,SAAS,UAAU;IACjB,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IACzD,OAAO;QACL,WAAW,MAAM,CAAC,UAAU,EAAE;QAC9B,SAAS,MAAM,CAAC,QAAQ,KAAK,QAAQ,GAAG;QACxC,UAAU,UAAU,EAAE;KACvB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAc;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,SAAS,EAAE,CAAC;QAClC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,sBAAsB,EAAE,CAAC;QAC3C,OAAO,CAAC,IAAI,CACV;YACE,WAAW,SAAS,CAAC,UAAU,EAAE;YACjC,SAAS,SAAS,CAAC,QAAQ,UAAU,SAAS,CAAC,QAAQ,GAAG;YAC1D,cAAc;SACf,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC;QACH,eAAe,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;YACtC,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;gBAC5B,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,SAAS;YACZ,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,CAAC;QACX;YACE,MAAM;IACV,CAAC;IACD,UAAU,EAAE,CAAC;IACb,OAAO,CAAC,CAAC;AACX,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,OAAO,CAAC,QAAQ,GAAG,IAAI,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export function buildContextBundleRequest(snippets) {
2
+ // TODO: align with MCP client schema
3
+ return JSON.stringify({ snippets }, null, 2);
4
+ }
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,yBAAyB,CACvC,QAAkD;IAElD,qCAAqC;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,47 @@
1
+ export function precisionAtK(retrievedIds, relevantIds, k) {
2
+ if (k <= 0 || retrievedIds.length === 0) {
3
+ return 0;
4
+ }
5
+ const relevantSet = new Set(relevantIds);
6
+ if (relevantSet.size === 0) {
7
+ return 0;
8
+ }
9
+ const limit = Math.min(k, retrievedIds.length);
10
+ let hits = 0;
11
+ for (let index = 0; index < limit; index += 1) {
12
+ const id = retrievedIds[index];
13
+ if (id !== undefined && relevantSet.has(id)) {
14
+ hits += 1;
15
+ }
16
+ }
17
+ return hits / limit;
18
+ }
19
+ export function timeToFirstUseful(events, options = {}) {
20
+ if (events.length === 0) {
21
+ return Number.POSITIVE_INFINITY;
22
+ }
23
+ const sorted = [...events].sort((a, b) => a.timestampMs - b.timestampMs);
24
+ const baseline = typeof options.startTimestampMs === "number"
25
+ ? options.startTimestampMs
26
+ : (sorted[0]?.timestampMs ?? 0);
27
+ for (const event of sorted) {
28
+ if (event.relevant) {
29
+ const deltaMs = event.timestampMs - baseline;
30
+ return Math.max(0, deltaMs) / 1000;
31
+ }
32
+ }
33
+ return Number.POSITIVE_INFINITY;
34
+ }
35
+ export function evaluateRetrieval(options) {
36
+ const { items, relevant, k } = options;
37
+ const ids = items.map((item) => item.id);
38
+ const precision = precisionAtK(ids, relevant, k);
39
+ const relevantSet = new Set(relevant);
40
+ const latencyEvents = items.map((item) => ({
41
+ timestampMs: item.timestampMs,
42
+ relevant: relevantSet.has(item.id),
43
+ }));
44
+ const ttff = timeToFirstUseful(latencyEvents);
45
+ return { precisionAtK: precision, timeToFirstUseful: ttff };
46
+ }
47
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/eval/metrics.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,YAAY,CAC1B,YAAsB,EACtB,WAA6B,EAC7B,CAAS;IAET,IAAI,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,SAAS,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,GAAG,KAAK,CAAC;AACtB,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAC/B,MAAsB,EACtB,UAAyC,EAAE;IAE3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;IACzE,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,gBAAgB,KAAK,QAAQ;QAC1C,CAAC,CAAC,OAAO,CAAC,gBAAgB;QAC1B,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,CAAC;IACpC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC;YAC7C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QACrC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,iBAAiB,CAAC;AAClC,CAAC;AAaD,MAAM,UAAU,iBAAiB,CAAC,OAAiC;IACjE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC;IACvC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,aAAa,GAAmB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACzD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;KACnC,CAAC,CAAC,CAAC;IACJ,MAAM,IAAI,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAC9C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}