@gmickel/gno 1.46.0 → 2.0.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 (230) hide show
  1. package/README.md +1 -1
  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.0.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.0.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 +21 -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/globals.built.css +1 -1
  100. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  101. package/src/serve/resident-admission.ts +36 -36
  102. package/src/serve/resident-background-work.ts +20 -2
  103. package/src/serve/resident-request.ts +11 -5
  104. package/src/serve/resident-runtime.ts +97 -61
  105. package/src/serve/resident-shutdown.ts +153 -0
  106. package/src/serve/routes/api.ts +3 -1
  107. package/src/serve/server.ts +47 -26
  108. package/src/store/migrations/028-vector-variants.ts +54 -0
  109. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  110. package/src/store/migrations/index.ts +4 -0
  111. package/src/store/sqlite/adapter.ts +251 -183
  112. package/src/store/sqlite/eligibility.ts +174 -0
  113. package/src/store/sqlite/graph-edge-application.ts +66 -0
  114. package/src/store/sqlite/graph-reference-state.ts +194 -0
  115. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  116. package/src/store/types.ts +80 -12
  117. package/src/store/vector/eligibility.ts +36 -0
  118. package/src/store/vector/freshness.ts +33 -6
  119. package/src/store/vector/lazy.ts +81 -0
  120. package/src/store/vector/sqlite-vec.ts +106 -54
  121. package/src/store/vector/stats.ts +14 -3
  122. package/src/store/vector/types.ts +35 -2
  123. package/src/store/vector/variant-search.ts +192 -0
  124. package/src/store/vector/variants.ts +451 -0
  125. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  126. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  127. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  128. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  129. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  130. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  131. package/vendor/converters/markitdown-ts/package.json +77 -0
  132. package/vendor/converters/officeparser/LICENSE +21 -0
  133. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  134. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  135. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  136. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  137. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  138. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  139. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  140. package/vendor/converters/officeparser/dist/cli.js +381 -0
  141. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  142. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  143. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  144. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  145. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  146. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  147. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  148. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  149. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  150. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  151. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  152. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  153. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  154. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  155. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  156. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  157. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  158. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  159. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  160. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  161. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  162. package/vendor/converters/officeparser/dist/index.js +72 -0
  163. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  164. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  165. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  166. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  167. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  168. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  170. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  171. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  172. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  173. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  174. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  175. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  176. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  177. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  178. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  179. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  180. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  181. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  182. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  183. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  184. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  185. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  186. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  187. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  188. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  189. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  190. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  191. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  192. package/vendor/converters/officeparser/dist/types.js +107 -0
  193. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  194. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  195. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  196. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  197. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  198. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  199. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  200. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  201. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  202. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  203. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  204. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  205. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  206. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  207. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  208. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  209. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  210. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  211. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  212. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  213. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  214. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  215. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  216. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  217. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  218. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  219. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  220. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  221. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  222. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  223. package/vendor/converters/officeparser/package.json +147 -0
  224. package/vendor/converters/upstream-manifest.json +124 -0
  225. package/vendor/dependency-fixes/README.md +77 -0
  226. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  227. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  228. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  229. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  230. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -3,9 +3,13 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
3
3
  "1c",
4
4
  "1c-query",
5
5
  "abap",
6
+ "actionscript",
6
7
  "actionscript-3",
7
8
  "ada",
8
9
  "adoc",
10
+ "ahk",
11
+ "ahk1",
12
+ "ahk2",
9
13
  "angular-html",
10
14
  "angular-ts",
11
15
  "apache",
@@ -13,6 +17,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
13
17
  "apl",
14
18
  "applescript",
15
19
  "ara",
20
+ "as3",
16
21
  "asciidoc",
17
22
  "asm",
18
23
  "astro",
@@ -37,6 +42,8 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
37
42
  "cadence",
38
43
  "cairo",
39
44
  "cdc",
45
+ "chapel",
46
+ "chpl",
40
47
  "cjs",
41
48
  "clarity",
42
49
  "clj",
@@ -151,6 +158,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
151
158
  "jsx",
152
159
  "julia",
153
160
  "just",
161
+ "justfile",
154
162
  "kdl",
155
163
  "kotlin",
156
164
  "kql",
@@ -197,6 +205,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
197
205
  "nginx",
198
206
  "nim",
199
207
  "nix",
208
+ "nsis",
200
209
  "nu",
201
210
  "nushell",
202
211
  "objc",
@@ -205,6 +214,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
205
214
  "ocaml",
206
215
  "odin",
207
216
  "openscad",
217
+ "org",
208
218
  "pascal",
209
219
  "perl",
210
220
  "perl6",
@@ -228,6 +238,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
228
238
  "pug",
229
239
  "puppet",
230
240
  "purescript",
241
+ "pwsh",
231
242
  "py",
232
243
  "python",
233
244
  "ql",
@@ -239,6 +250,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
239
250
  "raku",
240
251
  "razor",
241
252
  "rb",
253
+ "rbs",
242
254
  "reg",
243
255
  "regex",
244
256
  "regexp",
@@ -249,6 +261,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
249
261
  "rs",
250
262
  "rst",
251
263
  "ruby",
264
+ "ruby-signature",
252
265
  "rust",
253
266
  "sas",
254
267
  "sass",
@@ -264,6 +277,7 @@ export const BUNDLED_LANGUAGE_IDS: ReadonlySet<string> = new Set([
264
277
  "shellscript",
265
278
  "shellsession",
266
279
  "smalltalk",
280
+ "smithy",
267
281
  "solidity",
268
282
  "soy",
269
283
  "sparql",
@@ -2,6 +2,8 @@
2
2
 
3
3
  import type { ResidentRequestHandle } from "./resident-runtime";
4
4
 
5
+ import { settlesBy } from "../core/shutdown-budget";
6
+
5
7
  const DEFAULT_READER_LIMIT = 8;
6
8
  const DEFAULT_READER_QUEUE_LIMIT = 64;
7
9
 
@@ -63,21 +65,32 @@ export class ReaderGate {
63
65
  signal?.addEventListener("abort", entry.onAbort, { once: true });
64
66
  this.#queue.push(entry);
65
67
  });
68
+ // Release reserved capacity if cancellation won the handoff race.
69
+ if (signal?.aborted) {
70
+ this.#releaseSlot();
71
+ throw new Error("Resident request aborted");
72
+ }
73
+ } else {
74
+ this.#active += 1;
66
75
  }
67
- if (signal?.aborted) throw new Error("Resident request aborted");
68
- this.#active += 1;
69
76
  let released = false;
70
77
  return () => {
71
78
  if (released) return;
72
79
  released = true;
73
- this.#active -= 1;
74
- const next = this.#queue.shift();
75
- if (next) {
76
- next.signal?.removeEventListener("abort", next.onAbort!);
77
- next.resolve();
78
- }
80
+ this.#releaseSlot();
79
81
  };
80
82
  }
83
+
84
+ #releaseSlot(): void {
85
+ const next = this.#queue.shift();
86
+ if (next) {
87
+ // Transfer ownership synchronously, before any fresh acquire can run.
88
+ next.signal?.removeEventListener("abort", next.onAbort!);
89
+ next.resolve();
90
+ } else {
91
+ this.#active -= 1;
92
+ }
93
+ }
81
94
  }
82
95
 
83
96
  export class AdmissionController {
@@ -122,38 +135,25 @@ export class AdmissionController {
122
135
  deadlineMs: number,
123
136
  abortSettleMs = deadlineMs
124
137
  ): Promise<boolean> {
138
+ this.stop();
139
+ const deadline = performance.now() + deadlineMs;
140
+ if (await settlesBy(this.drain(), deadline)) return false;
141
+ this.cancel();
142
+ await settlesBy(this.drain(), deadline + abortSettleMs);
143
+ return true;
144
+ }
145
+
146
+ stop(): void {
125
147
  this.#accepting = false;
126
- if (this.#requests.size === 0) return false;
127
-
128
- let timeout: ReturnType<typeof setTimeout> | undefined;
129
- let deadlineReached = false;
130
- await Promise.race([
131
- new Promise<void>((resolve) => this.#drainWaiters.add(resolve)),
132
- new Promise<void>((resolve) => {
133
- timeout = setTimeout(
134
- () => {
135
- deadlineReached = true;
136
- resolve();
137
- },
138
- Math.max(0, deadlineMs)
139
- );
140
- }),
141
- ]);
142
- if (timeout) clearTimeout(timeout);
143
-
144
- if (!deadlineReached) return false;
148
+ }
145
149
 
150
+ cancel(): void {
146
151
  for (const controller of this.#requests.values())
147
152
  controller.abort(new Error("Resident runtime is shutting down"));
153
+ }
148
154
 
149
- if (this.#requests.size > 0) {
150
- await Promise.race([
151
- new Promise<void>((resolve) => this.#drainWaiters.add(resolve)),
152
- new Promise<void>((resolve) =>
153
- setTimeout(resolve, Math.max(0, abortSettleMs))
154
- ),
155
- ]);
156
- }
157
- return deadlineReached;
155
+ drain(): Promise<void> {
156
+ if (!this.#requests.size) return Promise.resolve();
157
+ return new Promise<void>((resolve) => this.#drainWaiters.add(resolve));
158
158
  }
159
159
  }
@@ -1,4 +1,8 @@
1
1
  /** Tracks cancellable work that intentionally outlives its initiating request. */
2
+ import {
3
+ withBackgroundInference,
4
+ withOwnedInferenceScope,
5
+ } from "../llm/inference-scope";
2
6
 
3
7
  interface BackgroundWorkEntry {
4
8
  controller: AbortController;
@@ -21,19 +25,33 @@ export class ResidentBackgroundWork {
21
25
  promise: Promise.resolve(),
22
26
  };
23
27
  entry.promise = Promise.resolve()
24
- .then(() => operation(controller.signal))
28
+ .then(() =>
29
+ withBackgroundInference(() =>
30
+ withOwnedInferenceScope({ signal: controller.signal }, () =>
31
+ operation(controller.signal)
32
+ )
33
+ )
34
+ )
25
35
  .catch(() => undefined)
26
36
  .finally(() => this.#entries.delete(entry));
27
37
  this.#entries.add(entry);
28
38
  return true;
29
39
  }
30
40
 
31
- async cancelAndDrain(): Promise<void> {
41
+ cancel(): void {
32
42
  for (const entry of this.#entries) {
33
43
  entry.controller.abort(new Error("Resident runtime is shutting down"));
34
44
  }
45
+ }
46
+
47
+ async drain(): Promise<void> {
35
48
  await Promise.allSettled(
36
49
  Array.from(this.#entries, (entry) => entry.promise)
37
50
  );
38
51
  }
52
+
53
+ async cancelAndDrain(): Promise<void> {
54
+ this.cancel();
55
+ await this.drain();
56
+ }
39
57
  }
@@ -1,6 +1,7 @@
1
- /** Admission, bounded-reader, and model-lease boundary for resident REST reads. */
2
-
3
1
  import type { ResidentRuntime } from "./resident-runtime";
2
+ /** Admission and bounded-reader boundary for resident REST reads. */
3
+
4
+ import { withInferenceScope } from "../llm/inference-scope";
4
5
 
5
6
  function unavailableResponse(): Response {
6
7
  return Response.json(
@@ -100,8 +101,9 @@ export async function handleResidentRead(
100
101
  try {
101
102
  releaseReader = await runtime.readerGate.acquire(admitted.signal);
102
103
  if (admitted.signal.aborted) return unavailableResponse();
103
- const response = await runtime.withModelLease(() =>
104
- Promise.resolve(operation(admitted.signal))
104
+ const response = await withInferenceScope(
105
+ { signal: admitted.signal },
106
+ async () => operation(admitted.signal)
105
107
  );
106
108
  if (admitted.signal.aborted) return unavailableResponse();
107
109
  if (!isAuthorizationEpochCurrent()) {
@@ -109,7 +111,11 @@ export async function handleResidentRead(
109
111
  }
110
112
  if (response.headers.get("content-type")?.includes("text/event-stream")) {
111
113
  deferredFinish = true;
112
- return wrapResidentStream(response, isAuthorizationEpochCurrent, finish);
114
+ return wrapResidentStream(
115
+ response,
116
+ () => !admitted.signal.aborted && isAuthorizationEpochCurrent(),
117
+ finish
118
+ );
113
119
  }
114
120
  return response;
115
121
  } catch (error) {
@@ -42,9 +42,13 @@ import {
42
42
  } from "../core/findings-run-state";
43
43
  import { JobManager } from "../core/job-manager";
44
44
  import { recordContentMutation } from "../core/mutation-generations";
45
+ import {
46
+ shutdownDuration,
47
+ SHUTDOWN_DRAIN_MS,
48
+ SHUTDOWN_ABORT_MS,
49
+ } from "../core/shutdown-budget";
45
50
  import { defaultSyncService, withContentTypeRules } from "../ingestion";
46
- import { getModelManager } from "../llm/nodeLlamaCpp/lifecycle";
47
- import { getModelConfig } from "../llm/registry";
51
+ import { withOwnedInferenceScope } from "../llm/inference-scope";
48
52
  import { getActivePreset } from "../llm/registry";
49
53
  import { createToolContext, Mutex } from "../mcp/context";
50
54
  import { SqliteAdapter } from "../store/sqlite/adapter";
@@ -58,10 +62,13 @@ import { createEmbedScheduler } from "./embed-scheduler";
58
62
  import { FindingsScheduler, type FindingsPassResult } from "./findings-pass";
59
63
  import { AdmissionController, ReaderGate } from "./resident-admission";
60
64
  import { ResidentBackgroundWork } from "./resident-background-work";
61
- import { buildResidentStatusSnapshot } from "./resident-status";
65
+ import { disposeResidentResources } from "./resident-shutdown";
66
+ import {
67
+ createStandaloneResidentStatus,
68
+ buildResidentStatusSnapshot,
69
+ } from "./resident-status";
62
70
  import { CollectionWatchService as DefaultCollectionWatchService } from "./watch-service";
63
71
 
64
- const DEFAULT_SHUTDOWN_DEADLINE_MS = 5_000;
65
72
  const OWNER_LOCK_TIMEOUT_MS = 0;
66
73
 
67
74
  export type ResidentMode = "serve" | "daemon";
@@ -110,7 +117,10 @@ export interface ResidentRuntime {
110
117
  readonly capsuleReverificationScheduler: SavedCapsuleReverificationScheduler;
111
118
  /** Present only when daemon mode runs with `findings.enabled`. */
112
119
  readonly findingsScheduler: FindingsScheduler | null;
113
- readonly modelManager: ModelManager;
120
+ readonly modelManager: Pick<
121
+ ModelManager,
122
+ "acquireLease" | "getLifecycleStats" | "disposeAll"
123
+ >;
114
124
  readonly mcpContext: ToolContext;
115
125
  readonly generations: ResidentGeneration;
116
126
  readonly activeRequests: number;
@@ -136,7 +146,7 @@ export interface ResidentRuntime {
136
146
  runUpdateCmd?: boolean;
137
147
  triggerEmbed?: boolean;
138
148
  }): Promise<{ syncResult: SyncResult; embedResult: EmbedResult | null }>;
139
- dispose(): Promise<void>;
149
+ dispose(closeSurface?: () => Promise<unknown>): Promise<void>;
140
150
  }
141
151
 
142
152
  export type ResidentRuntimeResult =
@@ -176,6 +186,8 @@ export async function startResidentRuntime(
176
186
  options: ResidentRuntimeOptions = {},
177
187
  deps: ResidentRuntimeDeps = {}
178
188
  ): Promise<ResidentRuntimeResult> {
189
+ shutdownDuration(options.shutdownDeadlineMs, SHUTDOWN_DRAIN_MS);
190
+ shutdownDuration(options.shutdownAbortSettleMs, SHUTDOWN_ABORT_MS);
179
191
  if (options.index !== undefined && !isValidIndexName(options.index)) {
180
192
  return {
181
193
  success: false,
@@ -274,9 +286,16 @@ export async function startResidentRuntime(
274
286
  eventBus: options.eventBus ?? null,
275
287
  watchService: null,
276
288
  };
277
- const modelManager =
278
- deps.modelManagerFactory?.(initialConfig) ??
279
- getModelManager(getModelConfig(initialConfig));
289
+ const modelManager = deps.modelManagerFactory?.(initialConfig) ?? {
290
+ acquireLease: () =>
291
+ ctxHolder.current.llm?.acquireModelLease() ?? { release() {} },
292
+ getLifecycleStats: () =>
293
+ ctxHolder.current.llm?.getLifecycleStats() ??
294
+ createStandaloneResidentStatus("stdio").models,
295
+ disposeAll: async () => {
296
+ await ctxHolder.current.llm?.dispose();
297
+ },
298
+ };
280
299
  const generations: ResidentGeneration = { content: 0, index: 0 };
281
300
  ctxHolder.markContentMutation = () => {
282
301
  generations.content += 1;
@@ -289,7 +308,6 @@ export async function startResidentRuntime(
289
308
  getEmbedPort: () => ctxHolder.current.embedPort,
290
309
  getVectorIndex: () => ctxHolder.current.vectorIndex,
291
310
  getModelUri: () => getActivePreset(ctxHolder.config).embed,
292
- acquireModelLease: () => modelManager.acquireLease(),
293
311
  onEmbedded: () => {
294
312
  generations.index += 1;
295
313
  },
@@ -350,6 +368,7 @@ export async function startResidentRuntime(
350
368
  let shutdownState: ResidentStatus["shutdown"]["state"] = "none";
351
369
  let admissionState: ResidentStatus["admission"]["state"] = "accepting";
352
370
  let disposed = false;
371
+ let disposal: Promise<void> | undefined;
353
372
  const backgroundWork = new ResidentBackgroundWork(
354
373
  () => !disposed && admission.accepting
355
374
  );
@@ -405,7 +424,8 @@ export async function startResidentRuntime(
405
424
  writeLockPath,
406
425
  enableWrite: false,
407
426
  isShuttingDown: () => disposed || !admission.accepting,
408
- acquireModelLease: () => modelManager.acquireLease(),
427
+ getModelAdapter: (config) =>
428
+ config === ctxHolder.current.config ? ctxHolder.current.llm : undefined,
409
429
  markContentMutation: () => {
410
430
  generations.content += 1;
411
431
  },
@@ -545,60 +565,76 @@ export async function startResidentRuntime(
545
565
  policySessionInvalidator = invalidator;
546
566
  },
547
567
  async syncAll(syncOptions = {}) {
548
- const config = ctxHolder.config;
549
- const syncAllService = deps.syncAllService
550
- ? (...args: Parameters<typeof defaultSyncService.syncAll>) =>
551
- deps.syncAllService!(...args)
552
- : defaultSyncService.syncAll.bind(defaultSyncService);
553
- const syncResult = await syncAllService(
554
- config.collections,
555
- store,
556
- withContentTypeRules(
557
- {
558
- gitPull: syncOptions.gitPull,
559
- runUpdateCmd: syncOptions.runUpdateCmd,
560
- },
561
- config
562
- )
563
- );
564
- recordContentMutation(syncResult, () => {
565
- generations.content += 1;
566
- });
567
- const embedResult =
568
- syncOptions.triggerEmbed === false
569
- ? null
570
- : await scheduler.triggerNow();
571
- capsuleReverificationScheduler.notifySyncSettled();
572
- return { syncResult, embedResult };
568
+ const request = admission.admit();
569
+ if (!request) throw new Error("Resident runtime is shutting down");
570
+ try {
571
+ return await withOwnedInferenceScope(
572
+ { signal: request.signal },
573
+ async () => {
574
+ const config = ctxHolder.config;
575
+ const syncAllService = deps.syncAllService
576
+ ? (...args: Parameters<typeof defaultSyncService.syncAll>) =>
577
+ deps.syncAllService!(...args)
578
+ : defaultSyncService.syncAll.bind(defaultSyncService);
579
+ const syncResult = await syncAllService(
580
+ config.collections,
581
+ store,
582
+ withContentTypeRules(
583
+ {
584
+ gitPull: syncOptions.gitPull,
585
+ runUpdateCmd: syncOptions.runUpdateCmd,
586
+ },
587
+ config
588
+ )
589
+ );
590
+ recordContentMutation(syncResult, () => {
591
+ generations.content += 1;
592
+ });
593
+ const embedResult =
594
+ syncOptions.triggerEmbed === false
595
+ ? null
596
+ : await scheduler.triggerNow();
597
+ capsuleReverificationScheduler.notifySyncSettled();
598
+ return { syncResult, embedResult };
599
+ }
600
+ );
601
+ } finally {
602
+ request.finish();
603
+ }
573
604
  },
574
- async dispose() {
575
- if (disposed) return;
605
+ dispose(closeSurface) {
606
+ if (disposal) return disposal;
576
607
  disposed = true;
608
+ admission.stop();
609
+ jobManager.stop();
577
610
  admissionState = "draining";
578
611
  shutdownState = "graceful";
579
- const deadlineReached = await admission.closeAndDrain(
580
- options.shutdownDeadlineMs ?? DEFAULT_SHUTDOWN_DEADLINE_MS,
581
- options.shutdownAbortSettleMs ?? DEFAULT_SHUTDOWN_DEADLINE_MS
582
- );
583
- if (deadlineReached) shutdownState = "deadline";
584
- findingsScheduler?.dispose();
585
- await backgroundWork.cancelAndDrain();
586
- await capsuleReverificationScheduler.dispose();
587
- await jobManager.shutdown().catch(() => undefined);
588
- await Promise.allSettled([
589
- Promise.resolve().then(() => watchService.dispose()),
590
- Promise.resolve().then(() => options.eventBus?.close()),
591
- ]);
592
- await Promise.allSettled([scheduler.dispose()]);
593
- await Promise.allSettled([
594
- (deps.disposeServerContext ?? disposeServerContext)(ctxHolder.current),
595
- ]);
596
- await Promise.allSettled([modelManager.disposeAll()]);
597
- await Promise.allSettled([store.close()]);
598
- await Promise.allSettled([ownerLock.release()]);
599
- admissionState = "closed";
600
- transportStatusProvider = null;
601
- listenerPort = null;
612
+ disposal = disposeResidentResources({
613
+ options,
614
+ admission,
615
+ backgroundWork,
616
+ jobManager,
617
+ scheduler,
618
+ store,
619
+ watchService,
620
+ context: ctxHolder.current,
621
+ mcpContext,
622
+ modelManager,
623
+ ownerLock,
624
+ stopFindings: () => findingsScheduler?.dispose(),
625
+ stopCapsules: () => capsuleReverificationScheduler.dispose(),
626
+ closeEvents: () => options.eventBus?.close(),
627
+ disposeContext: deps.disposeServerContext ?? disposeServerContext,
628
+ closeSurface,
629
+ onDeadline: () => {
630
+ shutdownState = "deadline";
631
+ },
632
+ }).then(() => {
633
+ admissionState = "closed";
634
+ transportStatusProvider = null;
635
+ listenerPort = null;
636
+ });
637
+ return disposal;
602
638
  },
603
639
  };
604
640
  ctxHolder.startBackgroundWork = (operation) =>
@@ -0,0 +1,153 @@
1
+ import type { WriteLockHandle } from "../core/file-lock";
2
+ /** One finite shutdown clock for the resources owned by a resident runtime. */
3
+ import type { JobManager } from "../core/job-manager";
4
+ import type { ToolContext } from "../mcp/context";
5
+ import type { SqliteAdapter } from "../store/sqlite/adapter";
6
+ import type { ServerContext } from "./context";
7
+ import type { EmbedScheduler } from "./embed-scheduler";
8
+ import type { AdmissionController } from "./resident-admission";
9
+ import type { ResidentBackgroundWork } from "./resident-background-work";
10
+ import type { ResidentRuntimeOptions } from "./resident-runtime";
11
+
12
+ import {
13
+ settlesBy,
14
+ shutdownDuration,
15
+ SHUTDOWN_DRAIN_MS,
16
+ SHUTDOWN_ABORT_MS,
17
+ SHUTDOWN_EXIT_MS,
18
+ } from "../core/shutdown-budget";
19
+
20
+ interface ResidentShutdownResources {
21
+ options: ResidentRuntimeOptions;
22
+ admission: AdmissionController;
23
+ backgroundWork: ResidentBackgroundWork;
24
+ jobManager: JobManager;
25
+ scheduler: EmbedScheduler;
26
+ store: SqliteAdapter;
27
+ watchService: { dispose(): void | Promise<void> };
28
+ context: ServerContext;
29
+ mcpContext: ToolContext;
30
+ modelManager: { disposeAll(): Promise<void> };
31
+ ownerLock: WriteLockHandle;
32
+ stopFindings: () => void;
33
+ stopCapsules: () => Promise<void>;
34
+ closeEvents: () => void | Promise<void>;
35
+ disposeContext: (context: ServerContext) => Promise<void>;
36
+ closeSurface?: () => Promise<unknown>;
37
+ onDeadline: () => void;
38
+ }
39
+
40
+ export async function disposeResidentResources(
41
+ resources: ResidentShutdownResources
42
+ ): Promise<void> {
43
+ const {
44
+ options,
45
+ admission,
46
+ backgroundWork,
47
+ jobManager,
48
+ scheduler,
49
+ store,
50
+ watchService,
51
+ context,
52
+ mcpContext,
53
+ modelManager,
54
+ ownerLock,
55
+ stopFindings,
56
+ stopCapsules,
57
+ closeEvents,
58
+ disposeContext,
59
+ closeSurface,
60
+ onDeadline,
61
+ } = resources;
62
+ let deadlineReached = false;
63
+ const drainDeadline =
64
+ performance.now() +
65
+ shutdownDuration(options.shutdownDeadlineMs, SHUTDOWN_DRAIN_MS);
66
+ const abortDeadline =
67
+ drainDeadline +
68
+ shutdownDuration(options.shutdownAbortSettleMs, SHUTDOWN_ABORT_MS);
69
+ const exitDeadline = abortDeadline + SHUTDOWN_EXIT_MS;
70
+ let unfinishedJobs: Promise<void> = Promise.resolve();
71
+ let writeFailure: unknown;
72
+ store.beginShutdown?.(abortDeadline);
73
+ const observe = (operation: () => unknown): Promise<void> =>
74
+ Promise.resolve()
75
+ .then(operation)
76
+ .then(
77
+ () => {},
78
+ (error: unknown) => console.error("Resident cleanup failed:", error)
79
+ );
80
+ stopFindings();
81
+ const schedulerDrain = observe(() =>
82
+ scheduler.stop ? scheduler.stop() : scheduler.dispose()
83
+ );
84
+ const work = Promise.all([
85
+ observe(() => closeSurface?.()),
86
+ admission.drain(),
87
+ backgroundWork.drain(),
88
+ jobManager.shutdown(),
89
+ schedulerDrain,
90
+ observe(() => stopCapsules()),
91
+ observe(() => watchService.dispose()),
92
+ observe(() => closeEvents()),
93
+ ]);
94
+ if (!(await settlesBy(work, drainDeadline))) {
95
+ deadlineReached = true;
96
+ onDeadline();
97
+ admission.cancel();
98
+ backgroundWork.cancel();
99
+ jobManager.cancel();
100
+ const canceledScheduler = observe(() => scheduler.dispose());
101
+ if (
102
+ !(await settlesBy(Promise.all([work, canceledScheduler]), abortDeadline))
103
+ ) {
104
+ // Revoke/rollback suspended parent writers before closing their DB.
105
+ // The ordinary store API also fences any late noncooperative callback.
106
+ try {
107
+ store.fenceForShutdown?.();
108
+ // Calling close synchronously closes cached raw handles before
109
+ // any late callback can resume in the native-exit wait.
110
+ const closing = store.close();
111
+ unfinishedJobs = jobManager.failUnfinished();
112
+ if (!(await settlesBy(closing, exitDeadline)))
113
+ throw new Error("Store close exceeded shutdown deadline");
114
+ } catch (error) {
115
+ writeFailure = error;
116
+ }
117
+ }
118
+ }
119
+ // Reach the single native owner directly; port disposal may itself wait
120
+ // for that owner. Never let such a wait hide the forced-exit deadline.
121
+ const nativeOptions = {
122
+ deadline: exitDeadline,
123
+ force: deadlineReached,
124
+ };
125
+ const native = Promise.all([
126
+ context.llm?.dispose(nativeOptions),
127
+ mcpContext.disposeModels?.(nativeOptions),
128
+ ]);
129
+ let nativeFailure: unknown;
130
+ try {
131
+ if (!(await settlesBy(native, exitDeadline)))
132
+ throw new Error(
133
+ "Native shutdown did not settle before owned-child exit deadline"
134
+ );
135
+ } catch (error) {
136
+ nativeFailure = error;
137
+ console.error("Resident native shutdown failed:", error);
138
+ }
139
+ const cleanup = Promise.all([
140
+ unfinishedJobs,
141
+ observe(() => disposeContext(context)),
142
+ observe(() => modelManager.disposeAll()),
143
+ ]);
144
+ if (!(await settlesBy(cleanup, exitDeadline)))
145
+ console.error("Resident resource cleanup exceeded shutdown deadline");
146
+ // close performs synchronous rollback/revocation before disconnecting.
147
+ if (writeFailure) throw writeFailure;
148
+ if (!(await settlesBy(store.close(), exitDeadline)))
149
+ throw new Error("Store close exceeded shutdown deadline");
150
+ if (!(await settlesBy(ownerLock.release(), exitDeadline)))
151
+ throw new Error("Resident owner lock release exceeded shutdown deadline");
152
+ if (nativeFailure) throw nativeFailure;
153
+ }
@@ -4244,7 +4244,9 @@ export async function handleSearch(
4244
4244
  req,
4245
4245
  trace.session,
4246
4246
  "failed",
4247
- errorResponse("RUNTIME", result.error.message, 500)
4247
+ result.error.code === "INVALID_INPUT"
4248
+ ? errorResponse("VALIDATION", result.error.message, 400)
4249
+ : errorResponse("RUNTIME", result.error.message, 500)
4248
4250
  );
4249
4251
  }
4250
4252