@gmickel/gno 1.46.0 → 2.1.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 (235) hide show
  1. package/README.md +17 -5
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/spa-production.json.gz +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip.sha256 +1 -0
  7. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  8. package/browser-extension/dist/manifest.json +1 -1
  9. package/browser-extension/dist/preview.html +1 -1
  10. package/browser-extension/dist/service-worker.js +32 -33
  11. package/bunfig.toml +2 -0
  12. package/package.json +40 -26
  13. package/spec/cli.md +29 -4
  14. package/spec/db/schema.sql +146 -1
  15. package/spec/mcp.md +26 -0
  16. package/src/app/context-runtime-types.ts +3 -0
  17. package/src/app/context-runtime.ts +2 -0
  18. package/src/cli/commands/ask.ts +6 -1
  19. package/src/cli/commands/daemon.ts +21 -8
  20. package/src/cli/commands/embed.ts +77 -41
  21. package/src/cli/detach.ts +3 -2
  22. package/src/config/types.ts +3 -3
  23. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  24. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  25. package/src/converters/versions.ts +6 -8
  26. package/src/core/context-evidence.ts +8 -4
  27. package/src/core/job-manager.ts +95 -13
  28. package/src/core/network-boundary-inventory.ts +10 -0
  29. package/src/core/shutdown-budget.ts +45 -0
  30. package/src/embed/backlog.ts +107 -4
  31. package/src/embed/batch.ts +42 -2
  32. package/src/embed/fingerprint.ts +16 -0
  33. package/src/embed/retry.ts +113 -5
  34. package/src/embed/variant-backlog.ts +105 -0
  35. package/src/embed/variant-plan.ts +62 -0
  36. package/src/embed/variant-retry.ts +113 -0
  37. package/src/ingestion/graph-reconciliation.ts +327 -0
  38. package/src/ingestion/sync.ts +9 -272
  39. package/src/llm/http-inference.ts +6 -0
  40. package/src/llm/httpEmbedding.ts +37 -6
  41. package/src/llm/httpGeneration.ts +18 -3
  42. package/src/llm/httpRerank.ts +23 -5
  43. package/src/llm/inference-cancellation.ts +168 -0
  44. package/src/llm/inference-scope.ts +202 -0
  45. package/src/llm/lazy-ports.ts +115 -0
  46. package/src/llm/native-worker/client.ts +541 -0
  47. package/src/llm/native-worker/dispatcher.ts +228 -0
  48. package/src/llm/native-worker/embedding-identity.ts +33 -0
  49. package/src/llm/native-worker/entry.ts +173 -0
  50. package/src/llm/native-worker/errors.ts +32 -0
  51. package/src/llm/native-worker/evaluation.ts +16 -0
  52. package/src/llm/native-worker/owned-exit.ts +108 -0
  53. package/src/llm/native-worker/owner.ts +141 -0
  54. package/src/llm/native-worker/ports.ts +317 -0
  55. package/src/llm/native-worker/protocol.ts +442 -0
  56. package/src/llm/native-worker/runtime-config.ts +92 -0
  57. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  58. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  59. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  60. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  61. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  62. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  63. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  64. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  65. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  66. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  67. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  68. package/src/llm/types.ts +35 -5
  69. package/src/mcp/context.ts +27 -0
  70. package/src/mcp/http-transport.ts +12 -10
  71. package/src/mcp/server.ts +3 -0
  72. package/src/mcp/tool-profile.ts +30 -8
  73. package/src/mcp/tools/context.ts +8 -11
  74. package/src/mcp/tools/embed.ts +1 -1
  75. package/src/mcp/tools/index-cmd.ts +1 -1
  76. package/src/mcp/tools/index.ts +10 -8
  77. package/src/mcp/tools/query.ts +14 -30
  78. package/src/mcp/tools/vsearch.ts +1 -1
  79. package/src/pipeline/answer.ts +23 -3
  80. package/src/pipeline/claim-verifier.ts +6 -0
  81. package/src/pipeline/expansion.ts +43 -40
  82. package/src/pipeline/explain.ts +6 -2
  83. package/src/pipeline/filters.ts +63 -0
  84. package/src/pipeline/fusion.ts +29 -9
  85. package/src/pipeline/graph-retrieval.ts +29 -9
  86. package/src/pipeline/hybrid.ts +198 -55
  87. package/src/pipeline/hydration.ts +161 -0
  88. package/src/pipeline/owner-fusion.ts +87 -0
  89. package/src/pipeline/rerank.ts +35 -11
  90. package/src/pipeline/search.ts +13 -2
  91. package/src/pipeline/types.ts +5 -3
  92. package/src/pipeline/vsearch.ts +87 -7
  93. package/src/sdk/client.ts +47 -3
  94. package/src/sdk/embed.ts +63 -39
  95. package/src/serve/background-runtime.ts +1 -1
  96. package/src/serve/context.ts +41 -56
  97. package/src/serve/embed-scheduler.ts +58 -35
  98. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  99. package/src/serve/public/components/PublishExportDialog.tsx +266 -0
  100. package/src/serve/public/globals.built.css +1 -1
  101. package/src/serve/public/globals.css +35 -0
  102. package/src/serve/public/lib/publish-export.ts +81 -1
  103. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  104. package/src/serve/public/pages/Collections.tsx +12 -46
  105. package/src/serve/public/pages/DocView.tsx +14 -52
  106. package/src/serve/resident-admission.ts +36 -36
  107. package/src/serve/resident-background-work.ts +20 -2
  108. package/src/serve/resident-request.ts +11 -5
  109. package/src/serve/resident-runtime.ts +97 -61
  110. package/src/serve/resident-shutdown.ts +153 -0
  111. package/src/serve/routes/api.ts +3 -1
  112. package/src/serve/server.ts +47 -26
  113. package/src/store/migrations/028-vector-variants.ts +54 -0
  114. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  115. package/src/store/migrations/index.ts +4 -0
  116. package/src/store/sqlite/adapter.ts +251 -183
  117. package/src/store/sqlite/eligibility.ts +174 -0
  118. package/src/store/sqlite/graph-edge-application.ts +66 -0
  119. package/src/store/sqlite/graph-reference-state.ts +194 -0
  120. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  121. package/src/store/types.ts +80 -12
  122. package/src/store/vector/eligibility.ts +36 -0
  123. package/src/store/vector/freshness.ts +33 -6
  124. package/src/store/vector/lazy.ts +81 -0
  125. package/src/store/vector/sqlite-vec.ts +106 -54
  126. package/src/store/vector/stats.ts +14 -3
  127. package/src/store/vector/types.ts +35 -2
  128. package/src/store/vector/variant-search.ts +192 -0
  129. package/src/store/vector/variants.ts +451 -0
  130. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  131. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  132. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  136. package/vendor/converters/markitdown-ts/package.json +77 -0
  137. package/vendor/converters/officeparser/LICENSE +21 -0
  138. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  140. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  142. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  144. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  145. package/vendor/converters/officeparser/dist/cli.js +381 -0
  146. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  147. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  148. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  150. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  152. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  154. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  156. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  158. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  160. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  162. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  164. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  166. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  167. package/vendor/converters/officeparser/dist/index.js +72 -0
  168. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  175. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  177. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  179. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  181. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  183. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  185. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  187. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  189. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  191. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  193. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  195. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  196. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  197. package/vendor/converters/officeparser/dist/types.js +107 -0
  198. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  200. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  202. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  204. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  206. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  208. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  210. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  212. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  214. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  216. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  218. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  220. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  222. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  224. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  226. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  228. package/vendor/converters/officeparser/package.json +147 -0
  229. package/vendor/converters/upstream-manifest.json +124 -0
  230. package/vendor/dependency-fixes/README.md +77 -0
  231. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  232. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  234. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  235. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
package/bunfig.toml CHANGED
@@ -3,3 +3,5 @@ plugins = ["bun-plugin-tailwind"]
3
3
 
4
4
  [test]
5
5
  preload = ["./test/preload/happy-dom.ts"]
6
+ # Frozen evidence and local experiments are not the executable regression suite.
7
+ pathIgnorePatterns = [".flow/artifacts/**", "notes/**"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "1.46.0",
3
+ "version": "2.1.0",
4
4
  "description": "Local semantic search for your documents. Index Markdown, PDF, and Office files with hybrid BM25 + vector search.",
5
5
  "keywords": [
6
6
  "embeddings",
@@ -78,6 +78,7 @@
78
78
  "test:fixtures": "bun scripts/generate-test-fixtures.ts",
79
79
  "evals": "bun scripts/update-eval-scores.ts",
80
80
  "eval": "bun --bun evalite",
81
+ "eval:acceptance": "bun scripts/retrieval-acceptance.ts",
81
82
  "eval:hybrid": "bun --bun evalite evals/hybrid.eval.ts",
82
83
  "eval:memory": "bun --bun evalite evals/memory.eval.ts --threshold 100",
83
84
  "eval:memory:fixtures": "bun scripts/memory-eval-fixtures.ts",
@@ -160,8 +161,9 @@
160
161
  "prepack": "bun run package:clipper"
161
162
  },
162
163
  "dependencies": {
163
- "@codemirror/lang-markdown": "6.5.1",
164
+ "@codemirror/lang-markdown": "6.5.2",
164
165
  "@codemirror/theme-one-dark": "6.1.3",
166
+ "@joplin/turndown-plugin-gfm": "1.0.67",
165
167
  "@modelcontextprotocol/client": "2.0.0",
166
168
  "@modelcontextprotocol/server": "2.0.0",
167
169
  "@radix-ui/react-collapsible": "1.1.20",
@@ -174,7 +176,8 @@
174
176
  "@radix-ui/react-separator": "1.1.15",
175
177
  "@radix-ui/react-slot": "1.3.3",
176
178
  "@radix-ui/react-tooltip": "1.2.16",
177
- "ai": "6.0.68",
179
+ "@xmldom/xmldom": "0.9.12",
180
+ "ai": "6.0.277",
178
181
  "bun-plugin-tailwind": "0.1.2",
179
182
  "class-variance-authority": "0.7.1",
180
183
  "clsx": "2.1.1",
@@ -182,19 +185,23 @@
182
185
  "codemirror": "6.0.2",
183
186
  "commander": "15.0.0",
184
187
  "embla-carousel-react": "8.6.0",
188
+ "fflate": "0.8.3",
189
+ "file-type": "22.0.2",
185
190
  "franc": "6.2.0",
191
+ "jsdom": "25.0.1",
186
192
  "jsonc-parser": "3.3.1",
187
193
  "less-pager-mini": "1.12.1",
188
- "lucide-react": "1.28.0",
189
- "markitdown-ts": "0.0.10",
194
+ "lucide-react": "1.41.0",
195
+ "mammoth": "1.12.2",
190
196
  "mdast-util-from-markdown": "2.0.3",
191
197
  "mdast-util-gfm": "3.1.0",
192
198
  "micromark-extension-gfm": "3.0.0",
199
+ "mime-types": "2.1.35",
193
200
  "minimatch": "10.2.6",
194
- "nanoid": "6.0.0",
195
- "node-llama-cpp": "3.19.1",
196
- "officeparser": "7.5.0",
197
- "pdfjs-dist": "6.2.108",
201
+ "nanoid": "6.0.1",
202
+ "node-llama-cpp": "3.20.0",
203
+ "pdf-parse": "2.4.5",
204
+ "pdfjs-dist": "6.3.289",
198
205
  "picocolors": "1.1.1",
199
206
  "react": "19.2.8",
200
207
  "react-dom": "19.2.8",
@@ -202,45 +209,52 @@
202
209
  "react-markdown": "10.1.0",
203
210
  "rehype-sanitize": "6.0.0",
204
211
  "remark-gfm": "4.0.1",
205
- "sharp": "0.35.3",
206
- "shiki": "4.3.1",
212
+ "sharp": "0.35.4",
213
+ "shiki": "4.4.3",
207
214
  "sqlite-vec": "0.1.9",
208
- "streamdown": "2.5.0",
215
+ "streamdown": "2.6.0",
209
216
  "tailwind-merge": "3.6.0",
210
217
  "tailwindcss": "4.3.3",
218
+ "tesseract.js": "7.0.0",
219
+ "turndown": "7.2.4",
211
220
  "use-stick-to-bottom": "1.1.6",
221
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
212
222
  "zod": "4.4.3"
213
223
  },
214
224
  "devDependencies": {
215
- "@ai-sdk/openai": "3.0.25",
216
- "@biomejs/biome": "2.5.6",
225
+ "@ai-sdk/openai": "3.0.108",
226
+ "@biomejs/biome": "2.5.12",
217
227
  "@tailwindcss/cli": "4.3.3",
218
- "@testing-library/react": "16.3.2",
219
- "@testing-library/user-event": "14.6.1",
220
- "@types/bun": "1.3.14",
221
- "@types/react": "19.2.17",
222
- "@types/react-dom": "19.2.3",
228
+ "@testing-library/react": "16.3.3",
229
+ "@testing-library/user-event": "14.6.7",
230
+ "@types/bun": "1.4.1",
231
+ "@types/react": "19.2.18",
232
+ "@types/react-dom": "19.2.7",
223
233
  "@vscode/tree-sitter-wasm": "0.3.1",
224
- "ajv": "8.17.1",
234
+ "ajv": "8.20.0",
225
235
  "ajv-formats": "3.0.1",
226
- "bun": "1.3.14",
236
+ "bun": "1.4.2",
227
237
  "docx": "9.7.1",
228
238
  "evalite": "1.0.0-beta.16",
229
239
  "exceljs": "4.4.0",
230
- "happy-dom": "20.11.1",
231
- "lefthook": "2.1.10",
240
+ "happy-dom": "20.14.0",
241
+ "lefthook": "2.1.12",
232
242
  "oxfmt": "0.28.0",
233
243
  "oxlint": "1.43.0",
234
244
  "oxlint-tsgolint": "0.11.5",
235
245
  "pdf-lib": "1.17.1",
236
- "playwright": "1.62.0",
246
+ "playwright": "1.63.0",
237
247
  "pptxgenjs": "4.0.1",
238
248
  "ultracite": "7.1.5",
239
249
  "vitest": "4.1.10",
240
- "web-tree-sitter": "0.26.11"
250
+ "web-tree-sitter": "0.26.13"
241
251
  },
242
252
  "peerDependencies": {
243
- "typescript": "^5"
253
+ "typescript": "^5.9.3"
254
+ },
255
+ "overrides": {
256
+ "@fastify/static": "10.1.3",
257
+ "file-type": "22.0.2"
244
258
  },
245
259
  "engines": {
246
260
  "bun": ">=1.3.0"
package/spec/cli.md CHANGED
@@ -1330,6 +1330,8 @@ gno search "contract" --json | jq '.[] | .uri'
1330
1330
 
1331
1331
  ---
1332
1332
 
1333
+ Keyword retrieval applies collection/path scope, caller allowlists, tags, modified-date bounds, category and author filters, managed-memory visibility, and whole-document exclusions before its ranked candidate limit. Higher-ranked ineligible documents cannot consume that window; fewer eligible matches still produce a short result. Existing BM25 weights, query syntax, recency/project-affinity reranking and minimum-score behavior are unchanged.
1334
+
1333
1335
  ### gno vsearch
1334
1336
 
1335
1337
  Vector semantic search over indexed documents.
@@ -1343,6 +1345,21 @@ gno vsearch <query> [-n <num>] [--min-score <num>] [-c <collection>] [--since <d
1343
1345
  **Options:** Same as `gno search` (including temporal/category/author, tag, and
1344
1346
  project-affinity controls).
1345
1347
 
1348
+ **Embedding ownership:** After an exact-input partition activates, vector hits
1349
+ resolve only to eligible current document owners of that formatted input.
1350
+ Same-body documents with different title-derived inputs retain separate vector
1351
+ ranks. Collection, path, tag, memory, metadata and language eligibility apply
1352
+ before the nearest-neighbor limit. Public document IDs, URIs and mirror hashes
1353
+ keep their existing meaning.
1354
+
1355
+ Incomplete shadow backfill retains the legacy retrieval path. Initial promotion
1356
+ requires complete active coverage and an atomic mutation-epoch check. Once
1357
+ promoted, later mutations never permit fallback to unproven legacy vectors:
1358
+ stale owners await embedding; missing runtime identity, an unactivated selected
1359
+ partition or an unavailable variant index reports semantic failure. Hybrid query
1360
+ may continue lexically with fallback diagnostics. Run `gno embed` to complete or
1361
+ repair coverage; no historical vector is treated as proof of its formatted input.
1362
+
1346
1363
  **Scoring:**
1347
1364
 
1348
1365
  Vector similarity scores are normalized to a 0-1 range:
@@ -2280,6 +2297,14 @@ gno publish export <target> \
2280
2297
  [--json]
2281
2298
  ```
2282
2299
 
2300
+ The CLI and `POST /api/publish/export` MUST preserve the existing `public`
2301
+ default when visibility is omitted. Local Web UI export dialogs MUST instead
2302
+ require an explicit mode. Both successful export results MUST report the
2303
+ selected mode in `artifact.spaces[].visibility`. Invalid modes and missing required encryption input
2304
+ MUST fail without an artifact. Encrypted CLI export requires `--passphrase`;
2305
+ the local API requires `encryptionPassphrase`. Neither sends that input to
2306
+ gno.sh. Export is a local operation, not hosted activation or deletion.
2307
+
2283
2308
  Public V1 spaces MUST carry a `manifest` conforming to
2284
2309
  [`publish-artifact.schema.json`](./output-schemas/publish-artifact.schema.json).
2285
2310
  The manifest contains schema version `1.0`, a deterministic projection
@@ -3788,7 +3813,7 @@ production default unless the parent was started with `--dev`.
3788
3813
  | `--pid-file <path>` | string | `{data}/serve.pid` | Override pid-file location (JSON metadata, absolute path) |
3789
3814
  | `--log-file <path>` | string | `{data}/serve.log` | Override log-file location (append mode) |
3790
3815
  | `--status` | boolean | false | Read pid-file, check liveness, print status (JSON with `--json`) |
3791
- | `--stop` | boolean | false | Graceful SIGTERM with 10s timeout → SIGKILL fallback |
3816
+ | `--stop` | boolean | false | Graceful SIGTERM with 12s timeout → SIGKILL fallback |
3792
3817
  | `--host <address>` | string | `127.0.0.1` | Loopback listen address (Web/REST remains local-only) |
3793
3818
  | `--mcp-token-file` | string | config | Restrictive bearer-token file |
3794
3819
  | `--mcp-allowed-host` | string | config/loopback defaults | Exact Host value; repeatable |
@@ -3847,7 +3872,7 @@ is blocked.
3847
3872
  without changing destination.
3848
3873
  - On `--detach`: forks a detached child with stdio redirected to `--log-file`, writes pid-file JSON (`{pid, port, cmd:"serve", version, started_at}`), prints `{pid, url}` on stdout, exits 0
3849
3874
  - On `--status`: output matches the [process-status schema](./output-schemas/process-status.schema.json). Liveness via `process.kill(pid, 0)`; stale pid-files (ESRCH) are reported as `running:false`. Live status best-effort reads the same redacted `resident-status@1.0` snapshot from the recorded listener.
3850
- - On `--stop`: sends SIGTERM, polls every 100ms for up to 10s, falls back to SIGKILL, polls 2s more, unlinks pid-file if the process cleaned up after itself
3875
+ - On `--stop`: sends SIGTERM, polls every 100ms for up to 12s, falls back to SIGKILL, polls 2s more, unlinks pid-file if the process cleaned up after itself
3851
3876
  - **Windows**: `--detach` is unsupported and returns a `VALIDATION` error pointing to WSL. `--status` / `--stop` / `--pid-file` / `--log-file` remain parseable but have nothing to manage.
3852
3877
 
3853
3878
  **Exit Codes:**
@@ -3901,7 +3926,7 @@ gno daemon --stop
3901
3926
  | `--pid-file <path>` | string | `{data}/daemon.pid` | Override pid-file location (JSON metadata, absolute path) |
3902
3927
  | `--log-file <path>` | string | `{data}/daemon.log` | Override log-file location (append mode) |
3903
3928
  | `--status` | boolean | false | Read pid-file, check liveness, print status (JSON with `--json`) |
3904
- | `--stop` | boolean | false | Graceful SIGTERM with 10s timeout → SIGKILL fallback |
3929
+ | `--stop` | boolean | false | Graceful SIGTERM with 12s timeout → SIGKILL fallback |
3905
3930
  | `--host <address>` | string | `127.0.0.1` | HTTP listen address |
3906
3931
  | `--mcp-token-file` | string | config | Restrictive bearer-token file |
3907
3932
  | `--mcp-allowed-host` | string | config/loopback defaults | Exact Host value; repeatable |
@@ -3943,7 +3968,7 @@ is blocked.
3943
3968
  peer zone and all participating collection policies before returning metadata
3944
3969
  - On `--detach`: forks a detached child with stdio redirected to `--log-file`, writes pid-file JSON including the MCP gateway `port`, prints `{pid}` on stdout, exits 0
3945
3970
  - On `--status`: output matches the [process-status schema](./output-schemas/process-status.schema.json), including the MCP gateway port and a best-effort copy of the live redacted resident snapshot
3946
- - On `--stop`: SIGTERM → 10s poll → SIGKILL → 2s poll; the daemon's own signal handler unlinks the pid-file, `--stop` unlinks as fallback
3971
+ - On `--stop`: SIGTERM → 12s poll → SIGKILL → 2s poll; the daemon's own signal handler unlinks the pid-file, `--stop` unlinks as fallback
3947
3972
  - **Windows**: `--detach` is unsupported and returns a `VALIDATION` error pointing to WSL.
3948
3973
 
3949
3974
  **Packaged conformance:** `bun run test:package` installs the generated npm
@@ -1,4 +1,35 @@
1
1
  -- GNO Database Schema v1
2
+ -- Graph reference inventory (migration 029). Parsed links remain in doc_links.
3
+ -- Snapshots deliberately survive document deletion: closure needs old identities.
4
+ -- Missing inventory, changed version/config, or dirty state requires full recovery.
5
+ -- Begin persists dirty before projection. Complete only after successful edge writes,
6
+ -- unchanged input epoch, and coverage of every active source; compose in a transaction.
7
+ CREATE TABLE graph_projection_state (
8
+ id INTEGER PRIMARY KEY CHECK (id = 1),
9
+ epoch INTEGER NOT NULL DEFAULT 0,
10
+ version INTEGER,
11
+ config_fingerprint TEXT,
12
+ in_progress INTEGER NOT NULL DEFAULT 0 CHECK (in_progress IN (0, 1)),
13
+ dirty INTEGER NOT NULL DEFAULT 1 CHECK (dirty IN (0, 1))
14
+ );
15
+ INSERT INTO graph_projection_state(id) VALUES (1);
16
+ CREATE TABLE graph_reference_documents (
17
+ document_id INTEGER PRIMARY KEY,
18
+ collection TEXT NOT NULL, rel_path TEXT NOT NULL, docid TEXT NOT NULL,
19
+ uri TEXT NOT NULL, title TEXT, mirror_hash TEXT, source_hash TEXT NOT NULL,
20
+ content_type TEXT
21
+ );
22
+ CREATE INDEX idx_graph_reference_uri ON graph_reference_documents(uri);
23
+ CREATE INDEX idx_graph_reference_path ON graph_reference_documents(collection, rel_path);
24
+ CREATE INDEX idx_graph_reference_title ON graph_reference_documents(title);
25
+ CREATE TABLE graph_frontmatter_references (
26
+ source_doc_id INTEGER NOT NULL REFERENCES graph_reference_documents(document_id) ON DELETE CASCADE,
27
+ ordinal INTEGER NOT NULL,
28
+ edge_type TEXT NOT NULL,
29
+ target TEXT NOT NULL,
30
+ PRIMARY KEY(source_doc_id, ordinal)
31
+ );
32
+ CREATE INDEX idx_graph_reference_target ON graph_frontmatter_references(target);
2
33
  -- SQLite with FTS5
3
34
  --
4
35
  -- Tables:
@@ -221,9 +252,109 @@ CREATE INDEX IF NOT EXISTS idx_vectors_freshness
221
252
  ON content_vectors(model, embed_fingerprint, mirror_hash, seq, embedded_at);
222
253
 
223
254
  -- ─────────────────────────────────────────────────────────────────────────────
224
- -- LLM Cache (EPIC 6+)
255
+ -- Exact embedding input variants (v1)
225
256
  -- ─────────────────────────────────────────────────────────────────────────────
226
257
 
258
+ -- Input variants v1 are additive shadow state. Legacy content_vectors remain
259
+ -- authoritative until a partition's complete active-owner coverage is checked
260
+ -- under BEGIN IMMEDIATE at the expected mutation epoch. Never infer exact
261
+ -- historical input from unique ownership. Pending work is current active
262
+ -- document/chunk pairs without a validated binding; it is resumable by owner.
263
+ CREATE TABLE IF NOT EXISTS vector_variant_epoch (
264
+ id INTEGER PRIMARY KEY CHECK (id = 1),
265
+ epoch INTEGER NOT NULL DEFAULT 0
266
+ );
267
+ INSERT OR IGNORE INTO vector_variant_epoch(id) VALUES (1);
268
+ CREATE TABLE IF NOT EXISTS vector_partitions (
269
+ partition_id TEXT PRIMARY KEY,
270
+ version INTEGER NOT NULL CHECK (version = 1),
271
+ model TEXT NOT NULL,
272
+ fingerprint TEXT NOT NULL,
273
+ dimensions INTEGER NOT NULL CHECK (dimensions > 0),
274
+ state TEXT NOT NULL DEFAULT 'shadow' CHECK (state IN ('shadow', 'active')),
275
+ activated_epoch INTEGER,
276
+ UNIQUE(model, fingerprint, dimensions)
277
+ );
278
+ CREATE TABLE IF NOT EXISTS vector_variants (
279
+ variant_id INTEGER PRIMARY KEY,
280
+ partition_id TEXT NOT NULL REFERENCES vector_partitions(partition_id),
281
+ input_hash TEXT NOT NULL CHECK (length(input_hash) = 64),
282
+ embedding BLOB NOT NULL,
283
+ UNIQUE(partition_id, input_hash),
284
+ UNIQUE(partition_id, variant_id)
285
+ );
286
+ CREATE TABLE IF NOT EXISTS vector_owners (
287
+ document_id INTEGER NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
288
+ mirror_hash TEXT NOT NULL,
289
+ seq INTEGER NOT NULL,
290
+ partition_id TEXT NOT NULL,
291
+ variant_id INTEGER NOT NULL,
292
+ PRIMARY KEY(document_id, seq, partition_id),
293
+ FOREIGN KEY(partition_id, variant_id)
294
+ REFERENCES vector_variants(partition_id, variant_id)
295
+ );
296
+ CREATE INDEX IF NOT EXISTS idx_vector_owners_variant ON vector_owners(variant_id);
297
+ -- No chunk FK: replacing shared canonical chunks must not cascade vector loss.
298
+ -- The writer validates bindings against current document/chunk/formatted input.
299
+ -- vec_v1_<partition SHA256> uses variant_id INTEGER PRIMARY KEY and FLOAT[dims].
300
+ -- Its writes/deletes share the authoritative variant transaction; no best effort.
301
+ -- Mutation epoch fences all old and new writers, including raw SQL. Active state
302
+ -- records durable variant authority after initial promotion. activated_epoch
303
+ -- proves current completeness only when it matches the mutation epoch.
304
+ -- Later mutations do not revoke authority: retrieval validates each owner and
305
+ -- continues serving unaffected variants; it must not fall back wholesale to
306
+ -- legacy rows. Recreating a missing vec0 table resets its partition to shadow.
307
+
308
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_documents_INSERT
309
+ AFTER INSERT ON documents BEGIN
310
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
311
+ END;
312
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_documents_UPDATE
313
+ AFTER UPDATE ON documents BEGIN
314
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
315
+ END;
316
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_documents_DELETE
317
+ AFTER DELETE ON documents BEGIN
318
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
319
+ END;
320
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_content_chunks_INSERT
321
+ AFTER INSERT ON content_chunks BEGIN
322
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
323
+ END;
324
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_content_chunks_UPDATE
325
+ AFTER UPDATE ON content_chunks BEGIN
326
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
327
+ END;
328
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_content_chunks_DELETE
329
+ AFTER DELETE ON content_chunks BEGIN
330
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
331
+ END;
332
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_owners_INSERT
333
+ AFTER INSERT ON vector_owners BEGIN
334
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
335
+ END;
336
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_owners_UPDATE
337
+ AFTER UPDATE ON vector_owners BEGIN
338
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
339
+ END;
340
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_owners_DELETE
341
+ AFTER DELETE ON vector_owners BEGIN
342
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
343
+ END;
344
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_variants_INSERT
345
+ AFTER INSERT ON vector_variants BEGIN
346
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
347
+ END;
348
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_variants_UPDATE
349
+ AFTER UPDATE ON vector_variants BEGIN
350
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
351
+ END;
352
+ CREATE TRIGGER IF NOT EXISTS variant_epoch_vector_variants_DELETE
353
+ AFTER DELETE ON vector_variants BEGIN
354
+ UPDATE vector_variant_epoch SET epoch = epoch + 1 WHERE id = 1;
355
+ END;
356
+
357
+ -- LLM Cache (EPIC 6+)
227
358
  CREATE TABLE IF NOT EXISTS llm_cache (
228
359
  key TEXT PRIMARY KEY,
229
360
  value TEXT NOT NULL,
@@ -814,3 +945,17 @@ CREATE INDEX IF NOT EXISTS idx_file_refactor_journal_plan_digest
814
945
 
815
946
  CREATE INDEX IF NOT EXISTS idx_file_refactor_journal_collection
816
947
  ON file_refactor_recovery_journal(collection, updated_at_ms DESC);
948
+
949
+ -- Graph input/inventory invalidation (029); begin also advances epoch to fence older passes.
950
+ CREATE TRIGGER graph_input_documents_insert AFTER INSERT ON documents BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
951
+ CREATE TRIGGER graph_input_documents_update AFTER UPDATE ON documents WHEN OLD.collection IS NOT NEW.collection OR OLD.rel_path IS NOT NEW.rel_path OR OLD.docid IS NOT NEW.docid OR OLD.uri IS NOT NEW.uri OR OLD.title IS NOT NEW.title OR OLD.mirror_hash IS NOT NEW.mirror_hash OR OLD.source_hash IS NOT NEW.source_hash OR OLD.content_type IS NOT NEW.content_type OR OLD.active IS NOT NEW.active BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
952
+ CREATE TRIGGER graph_input_documents_delete AFTER DELETE ON documents BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
953
+ CREATE TRIGGER graph_input_doc_links_insert AFTER INSERT ON doc_links BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
954
+ CREATE TRIGGER graph_input_doc_links_update AFTER UPDATE ON doc_links BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
955
+ CREATE TRIGGER graph_input_doc_links_delete AFTER DELETE ON doc_links BEGIN UPDATE graph_projection_state SET epoch = epoch + 1, dirty = 1 WHERE id = 1; END;
956
+ CREATE TRIGGER graph_inventory_graph_reference_documents_insert AFTER INSERT ON graph_reference_documents BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
957
+ CREATE TRIGGER graph_inventory_graph_reference_documents_update AFTER UPDATE ON graph_reference_documents BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
958
+ CREATE TRIGGER graph_inventory_graph_reference_documents_delete AFTER DELETE ON graph_reference_documents BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
959
+ CREATE TRIGGER graph_inventory_graph_frontmatter_references_insert AFTER INSERT ON graph_frontmatter_references BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
960
+ CREATE TRIGGER graph_inventory_graph_frontmatter_references_update AFTER UPDATE ON graph_frontmatter_references BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
961
+ CREATE TRIGGER graph_inventory_graph_frontmatter_references_delete AFTER DELETE ON graph_frontmatter_references BEGIN UPDATE graph_projection_state SET dirty = 1, in_progress = 1 WHERE id = 1; END;
package/spec/mcp.md CHANGED
@@ -11,6 +11,21 @@ name answers JSON-RPC `-32602`)
11
11
 
12
12
  This document specifies the MCP server interface for GNO.
13
13
 
14
+ ## Filtered retrieval limits
15
+
16
+ Search candidate budgets apply after supported owner filters (collection, path,
17
+ tags, dates, author, categories and exclusions). Semantic retrieval and hybrid
18
+ retrieval also select matching-language chunks before their budgets; standalone
19
+ lexical language remains reserved. A nearby out-of-scope vector cannot displace
20
+ an eligible hit. Caller scope intersects user filters; empty allowlists deny all.
21
+ Whole-document exclusions inspect every chunk, including other languages;
22
+ hybrid exclusions also inspect author and category metadata.
23
+
24
+ Results can remain shorter than the requested limit after score thresholds,
25
+ deduplication or limited eligible coverage. Ranking/fusion and output schemas
26
+ are unchanged. This correction does not change independent natural-language
27
+ memory recall matching.
28
+
14
29
  ## Server Information
15
30
 
16
31
  | Property | Value |
@@ -281,6 +296,17 @@ redacted statuses: 401 (authentication), 403 (peer/Host/Origin/write), 413
281
296
  POST body, 120 requests/minute per actual peer, 64 active requests, 16 queued
282
297
  requests, 32 sessions, and a five-minute idle session timeout.
283
298
 
299
+ ### Cancellation and accepted jobs
300
+
301
+ MCP request cancellation notifications and transport disconnect propagate to the
302
+ participating inference stages. Canceled calls cannot publish late results or
303
+ successful fallback. Noncooperative native operations retain their model lease
304
+ and shared queue capacity until actual settlement or controlled child exit; queued
305
+ operations are never replayed on a replacement child. Accepted asynchronous jobs
306
+ have an independent lifetime after job-ID delivery and survive normal initiating
307
+ transport closure. Explicit job cancellation and resident shutdown stop their
308
+ subsequent work. Existing error, job status and output schemas remain unchanged.
309
+
284
310
  ### Packaged gateway conformance
285
311
 
286
312
  `bun run test:package` installs the generated npm tarball into an isolated
@@ -4,6 +4,7 @@ import type { ContextEvidenceCompilerDeps } from "../core/context-evidence";
4
4
  import type { ContextVerifierDeps } from "../core/context-verifier";
5
5
  import type { RetrievalTraceSession } from "../core/retrieval-trace-session";
6
6
  import type { EmbeddingPort, RerankPort } from "../llm/types";
7
+ import type { RequestHydration } from "../pipeline/hydration";
7
8
  import type { ProjectAffinityScoringInput } from "../pipeline/project-affinity";
8
9
  import type { QueryModeInput } from "../pipeline/types";
9
10
  import type { StorePort } from "../store/types";
@@ -43,6 +44,8 @@ export interface ContextCapsuleRuntimeDeps {
43
44
  store: StorePort &
44
45
  ContextEvidenceCompilerDeps<ContextCapsuleV1>["store"] &
45
46
  ContextVerifierDeps["store"];
47
+ /** Internal owner supplied by Ask; verification always reads the live store. */
48
+ hydration?: RequestHydration;
46
49
  config: Config;
47
50
  indexName?: string;
48
51
  vectorIndex?: VectorIndexPort | null;
@@ -96,11 +96,13 @@ export const buildContextCapsule = async (
96
96
  },
97
97
  {
98
98
  store: deps.store,
99
+ hydration: deps.hydration,
99
100
  retrieve: async (request) => {
100
101
  const requestNoRerank = noRerank || request.noRerank === true;
101
102
  const result = await searchHybrid(
102
103
  {
103
104
  store: deps.store,
105
+ hydration: deps.hydration,
104
106
  config: deps.config,
105
107
  vectorIndex: deps.vectorIndex ?? null,
106
108
  embedPort: deps.embedPort ?? null,
@@ -31,6 +31,7 @@ import {
31
31
  processAnswerResultWithTrace,
32
32
  } from "../../pipeline/answer";
33
33
  import { type HybridSearchDeps, searchHybrid } from "../../pipeline/hybrid";
34
+ import { RequestHydration } from "../../pipeline/hydration";
34
35
  import {
35
36
  createVectorIndexPort,
36
37
  type VectorIndexPort,
@@ -106,6 +107,7 @@ export async function ask(
106
107
  }
107
108
 
108
109
  const { store, config } = initResult;
110
+ const hydration = new RequestHydration(store);
109
111
 
110
112
  let embedPort: EmbeddingPort | null = null;
111
113
  let expandPort: GenerationPort | null = null;
@@ -258,6 +260,7 @@ export async function ask(
258
260
 
259
261
  const deps: HybridSearchDeps = {
260
262
  store,
263
+ hydration,
261
264
  config,
262
265
  vectorIndex,
263
266
  embedPort,
@@ -292,6 +295,7 @@ export async function ask(
292
295
  embedPort,
293
296
  rerankPort,
294
297
  genPort: answerPort,
298
+ hydration,
295
299
  projectAffinity,
296
300
  traceSession,
297
301
  }
@@ -357,7 +361,7 @@ export async function ask(
357
361
  await traceSession?.recordCapability("answer_generation", "attempted");
358
362
  const maxTokens = options.maxAnswerTokens ?? 512;
359
363
  const rawResult = await generateGroundedAnswer(
360
- { genPort: answerPort, store },
364
+ { genPort: answerPort, store, hydration },
361
365
  query,
362
366
  results,
363
367
  maxTokens
@@ -441,6 +445,7 @@ export async function ask(
441
445
  error: cause instanceof Error ? cause.message : "Ask failed",
442
446
  };
443
447
  } finally {
448
+ hydration.release();
444
449
  if (embedPort) {
445
450
  await embedPort.dispose();
446
451
  }
@@ -211,6 +211,14 @@ export async function daemon(
211
211
  });
212
212
  let gateway: Awaited<ReturnType<typeof createMcpHttpGateway>> | undefined;
213
213
  let server: ReturnType<typeof Bun.serve> | undefined;
214
+ const stopSignals = new AbortController();
215
+ const shutdown = createSignalPromise(
216
+ options.signal
217
+ ? AbortSignal.any([options.signal, stopSignals.signal])
218
+ : stopSignals.signal,
219
+ logger,
220
+ options.quiet ?? false
221
+ );
214
222
  try {
215
223
  gateway = await (deps.createMcpHttpGateway ?? createMcpHttpGateway)(
216
224
  runtime as ResidentRuntime,
@@ -271,10 +279,12 @@ export async function daemon(
271
279
  if (!options.quiet) {
272
280
  logger.log("Running initial sync...");
273
281
  }
274
- const { syncResult, embedResult } = await runtime.syncAll({
275
- runUpdateCmd: true,
276
- triggerEmbed: true,
277
- });
282
+ const synced = await Promise.race([
283
+ runtime.syncAll({ runUpdateCmd: true, triggerEmbed: true }),
284
+ shutdown.then(() => null),
285
+ ]);
286
+ if (!synced) return { success: true };
287
+ const { syncResult, embedResult } = synced;
278
288
  if (!options.quiet) {
279
289
  logger.log(
280
290
  `sync totals: ${syncResult.totalFilesAdded} added, ${syncResult.totalFilesUpdated} updated, ${syncResult.totalFilesErrored} errors, ${syncResult.totalFilesSkipped} skipped`
@@ -289,7 +299,7 @@ export async function daemon(
289
299
  logger.log("Skipping initial sync (--no-sync-on-start).");
290
300
  }
291
301
 
292
- await createSignalPromise(options.signal, logger, options.quiet ?? false);
302
+ await shutdown;
293
303
  return { success: true };
294
304
  } catch (error) {
295
305
  return {
@@ -297,8 +307,11 @@ export async function daemon(
297
307
  error: error instanceof Error ? error.message : String(error),
298
308
  };
299
309
  } finally {
300
- await Promise.allSettled([server?.stop(true)]);
301
- await Promise.allSettled([gateway?.close()]);
302
- await Promise.allSettled([runtime.dispose()]);
310
+ stopSignals.abort();
311
+ const surfaceClose = Promise.all([
312
+ Promise.resolve().then(() => server?.stop(true)),
313
+ Promise.resolve().then(() => gateway?.close()),
314
+ ]);
315
+ await runtime.dispose(() => surfaceClose);
303
316
  }
304
317
  }