@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
@@ -14,7 +14,6 @@ import type { NormalizedContentTypeRule } from "../config";
14
14
  import type { Collection } from "../config/types";
15
15
  import type {
16
16
  ChunkInput,
17
- DocEdgeInput,
18
17
  DocLinkInput,
19
18
  DocumentInput,
20
19
  DocumentRow,
@@ -49,16 +48,12 @@ import { DEFAULT_LIMITS, type RecordAdapter } from "../converters/types";
49
48
  import {
50
49
  diffDocumentStructure,
51
50
  extractDocumentStructure,
52
- isRelationMap,
53
- normalizeRelationEdgeType,
54
- normalizeRelationTarget,
55
51
  } from "../core/change-diff";
56
52
  import { enforceCollectionEgress } from "../core/egress-enforcement";
57
53
  import {
58
54
  normalizeMarkdownPath,
59
55
  normalizeWikiName,
60
56
  parseLinks,
61
- parseTargetParts,
62
57
  } from "../core/links";
63
58
  import { extractMemoryScopes } from "../core/memory-record";
64
59
  import { normalizeTag, validateTag } from "../core/tags";
@@ -68,6 +63,7 @@ import {
68
63
  parseFrontmatter,
69
64
  stripFrontmatter,
70
65
  } from "./frontmatter";
66
+ import { projectGraph } from "./graph-reconciliation";
71
67
  import { buildLineOffsets } from "./position";
72
68
  import { processRecordContainer } from "./record-container";
73
69
  import {
@@ -104,8 +100,6 @@ const MAX_CONCURRENCY = 16;
104
100
  export const INGEST_VERSION = 6;
105
101
  const EMPTY_CONTENT_TYPE_RULES_FINGERPRINT =
106
102
  fingerprintContentTypeMetadataRules([]);
107
- const RELATION_EDGE_TYPE_PATTERN = /^[a-z][a-z0-9_]*$/;
108
- const PROJECTION_YIELD_INTERVAL = 25;
109
103
  const NON_RETRYABLE_CONVERSION_ERROR_CODES = new Set([
110
104
  "CORRUPT",
111
105
  "PERMISSION",
@@ -113,98 +107,6 @@ const NON_RETRYABLE_CONVERSION_ERROR_CODES = new Set([
113
107
  "UNSUPPORTED",
114
108
  ]);
115
109
 
116
- function findDocByWikiRef(
117
- docs: DocumentRow[],
118
- targetRef: string,
119
- collection?: string
120
- ): DocumentRow | undefined {
121
- const normalized = normalizeWikiName(targetRef);
122
- const candidates = collection
123
- ? docs.filter((doc) => doc.collection === collection)
124
- : docs;
125
-
126
- return candidates.find((doc) => {
127
- const title = doc.title ?? doc.relPath.split("/").pop() ?? doc.relPath;
128
- const relStem = doc.relPath.replace(/\.[^/.]+$/, "");
129
- return (
130
- normalizeWikiName(title) === normalized ||
131
- normalizeWikiName(doc.relPath) === normalized ||
132
- normalizeWikiName(relStem) === normalized
133
- );
134
- });
135
- }
136
-
137
- function resolveRelationTarget(
138
- docs: DocumentRow[],
139
- sourceDoc: DocumentRow,
140
- rawTarget: string
141
- ): DocumentRow | undefined {
142
- const target = normalizeRelationTarget(rawTarget);
143
- if (!target) {
144
- return undefined;
145
- }
146
-
147
- if (target.startsWith("#")) {
148
- return docs.find((doc) => doc.docid === target);
149
- }
150
-
151
- if (target.startsWith("gno://")) {
152
- return docs.find((doc) => doc.uri === target);
153
- }
154
-
155
- const parts = parseTargetParts(target);
156
- const targetCollection = parts.collection;
157
- const targetRef = parts.ref;
158
- if (!targetRef) {
159
- return undefined;
160
- }
161
-
162
- if (targetCollection) {
163
- const exact = docs.find(
164
- (doc) => doc.collection === targetCollection && doc.relPath === targetRef
165
- );
166
- return exact ?? findDocByWikiRef(docs, targetRef, targetCollection);
167
- }
168
-
169
- const sameCollectionPath = normalizeMarkdownPath(
170
- targetRef,
171
- sourceDoc.relPath
172
- );
173
- if (sameCollectionPath) {
174
- const exact = docs.find(
175
- (doc) =>
176
- doc.collection === sourceDoc.collection &&
177
- doc.relPath === sameCollectionPath
178
- );
179
- if (exact) {
180
- return exact;
181
- }
182
- }
183
-
184
- const explicitCollPath = docs.find(
185
- (doc) => `${doc.collection}/${doc.relPath}` === targetRef
186
- );
187
- if (explicitCollPath) {
188
- return explicitCollPath;
189
- }
190
-
191
- return (
192
- findDocByWikiRef(docs, targetRef, sourceDoc.collection) ??
193
- findDocByWikiRef(docs, targetRef)
194
- );
195
- }
196
-
197
- function getPrimaryGraphHint(
198
- contentType: string | null | undefined,
199
- rules: NormalizedContentTypeRule[]
200
- ): string | undefined {
201
- if (!contentType) {
202
- return undefined;
203
- }
204
- const rule = rules.find((candidate) => candidate.id === contentType);
205
- return rule?.graphHints?.[0];
206
- }
207
-
208
110
  /**
209
111
  * Decide whether to process a file or skip it.
210
112
  * Handles repair cases where sourceHash matches but content is incomplete.
@@ -219,6 +121,11 @@ function decideAction(
219
121
  if (!existing) {
220
122
  return { kind: "process", reason: "new file" };
221
123
  }
124
+ // Identical bytes can reappear after deletion; restore through the normal
125
+ // conversion/upsert path so identity, derived data and journal agree.
126
+ if (!existing.active) {
127
+ return { kind: "repair", reason: "source restored" };
128
+ }
222
129
 
223
130
  // Source hash changed - must process
224
131
  if (existing.sourceHash !== sourceHash) {
@@ -1784,182 +1691,12 @@ export class SyncService {
1784
1691
  return null;
1785
1692
  }
1786
1693
 
1787
- private async projectTypedEdges(
1694
+ private projectTypedEdges(
1788
1695
  store: StorePort,
1789
1696
  options: SyncOptions,
1790
1697
  sourceDocumentIds?: Set<number>
1791
1698
  ): Promise<Array<{ relPath: string; code: string; message: string }>> {
1792
- const errors: Array<{ relPath: string; code: string; message: string }> =
1793
- [];
1794
-
1795
- const selectedSourceIds = sourceDocumentIds
1796
- ? [...sourceDocumentIds]
1797
- : undefined;
1798
- const backfillResult = await store.backfillDocEdges(selectedSourceIds);
1799
- if (!backfillResult.ok) {
1800
- return [
1801
- {
1802
- relPath: "(typed edge backfill)",
1803
- code: backfillResult.error.code,
1804
- message: backfillResult.error.message,
1805
- },
1806
- ];
1807
- }
1808
-
1809
- const docsResult = await store.listDocuments();
1810
- if (!docsResult.ok) {
1811
- return [
1812
- {
1813
- relPath: "(typed edge projection)",
1814
- code: docsResult.error.code,
1815
- message: docsResult.error.message,
1816
- },
1817
- ];
1818
- }
1819
-
1820
- const activeDocs = docsResult.value.filter((doc) => doc.active);
1821
- const activeIds = new Set(activeDocs.map((doc) => doc.id));
1822
- if (selectedSourceIds) {
1823
- for (const documentId of selectedSourceIds) {
1824
- if (!activeIds.has(documentId)) {
1825
- // Clear typed edges for inactivated projection sources.
1826
- const clearResult = await store.setDocEdges(
1827
- documentId,
1828
- [],
1829
- "frontmatter-relation"
1830
- );
1831
- if (!clearResult.ok) {
1832
- errors.push({
1833
- relPath: `(doc:${documentId})`,
1834
- code: clearResult.error.code,
1835
- message: clearResult.error.message,
1836
- });
1837
- }
1838
- }
1839
- }
1840
- }
1841
- const projectedDocs = sourceDocumentIds
1842
- ? activeDocs.filter((doc) => sourceDocumentIds.has(doc.id))
1843
- : activeDocs;
1844
-
1845
- for (const [docIndex, doc] of projectedDocs.entries()) {
1846
- if (docIndex > 0 && docIndex % PROJECTION_YIELD_INTERVAL === 0) {
1847
- await Bun.sleep(0);
1848
- }
1849
- if (!doc.mirrorHash) {
1850
- continue;
1851
- }
1852
-
1853
- const contentResult = await store.getContent(doc.mirrorHash);
1854
- if (!contentResult.ok || contentResult.value === null) {
1855
- continue;
1856
- }
1857
-
1858
- const relationsValue = parseFrontmatter(contentResult.value).metadata
1859
- .relations;
1860
- const relationEdges: DocEdgeInput[] = [];
1861
-
1862
- if (isRelationMap(relationsValue)) {
1863
- for (const [rawEdgeType, targets] of Object.entries(relationsValue)) {
1864
- const edgeType = normalizeRelationEdgeType(rawEdgeType);
1865
- if (!RELATION_EDGE_TYPE_PATTERN.test(edgeType)) {
1866
- continue;
1867
- }
1868
- for (const target of targets) {
1869
- const targetDoc = resolveRelationTarget(activeDocs, doc, target);
1870
- if (targetDoc) {
1871
- relationEdges.push({
1872
- targetDocId: targetDoc.id,
1873
- edgeType,
1874
- confidence: "manual",
1875
- });
1876
- }
1877
- }
1878
- }
1879
- }
1880
- const relationTargetIds = new Set(
1881
- relationEdges.map((edge) => edge.targetDocId)
1882
- );
1883
-
1884
- const relationsResult = await store.setDocEdges(
1885
- doc.id,
1886
- relationEdges,
1887
- "frontmatter-relation"
1888
- );
1889
- if (!relationsResult.ok) {
1890
- errors.push({
1891
- relPath: doc.relPath,
1892
- code: relationsResult.error.code,
1893
- message: relationsResult.error.message,
1894
- });
1895
- }
1896
-
1897
- const primaryHint = getPrimaryGraphHint(
1898
- doc.contentType,
1899
- options.contentTypeRules ?? []
1900
- );
1901
- if (!primaryHint || !RELATION_EDGE_TYPE_PATTERN.test(primaryHint)) {
1902
- continue;
1903
- }
1904
-
1905
- const linksResult = await store.getLinksForDoc(doc.id);
1906
- if (!linksResult.ok) {
1907
- errors.push({
1908
- relPath: doc.relPath,
1909
- code: linksResult.error.code,
1910
- message: linksResult.error.message,
1911
- });
1912
- continue;
1913
- }
1914
-
1915
- const wikiEdges: DocEdgeInput[] = [];
1916
- const markdownEdges: DocEdgeInput[] = [];
1917
- for (const link of linksResult.value) {
1918
- const targetRef =
1919
- link.linkType === "markdown"
1920
- ? `${doc.collection}/${link.targetRefNorm}`
1921
- : link.targetCollection
1922
- ? `${link.targetCollection}:${link.targetRef}`
1923
- : link.targetRefNorm;
1924
- const targetDoc = resolveRelationTarget(activeDocs, doc, targetRef);
1925
- if (!targetDoc || relationTargetIds.has(targetDoc.id)) {
1926
- continue;
1927
- }
1928
- const edge = {
1929
- targetDocId: targetDoc.id,
1930
- edgeType: primaryHint,
1931
- confidence: "configured" as const,
1932
- };
1933
- if (link.linkType === "wiki") {
1934
- wikiEdges.push(edge);
1935
- } else {
1936
- markdownEdges.push(edge);
1937
- }
1938
- }
1939
-
1940
- const wikiResult = await store.setDocEdges(doc.id, wikiEdges, "wikilink");
1941
- if (!wikiResult.ok) {
1942
- errors.push({
1943
- relPath: doc.relPath,
1944
- code: wikiResult.error.code,
1945
- message: wikiResult.error.message,
1946
- });
1947
- }
1948
- const markdownResult = await store.setDocEdges(
1949
- doc.id,
1950
- markdownEdges,
1951
- "markdown-link"
1952
- );
1953
- if (!markdownResult.ok) {
1954
- errors.push({
1955
- relPath: doc.relPath,
1956
- code: markdownResult.error.code,
1957
- message: markdownResult.error.message,
1958
- });
1959
- }
1960
- }
1961
-
1962
- return errors;
1699
+ return projectGraph(store, options, sourceDocumentIds);
1963
1700
  }
1964
1701
 
1965
1702
  /** Run an exact global typed-edge reconciliation with cooperative yields. */
@@ -1967,7 +1704,7 @@ export class SyncService {
1967
1704
  store: StorePort,
1968
1705
  options: SyncOptions = {}
1969
1706
  ): Promise<Array<{ relPath: string; code: string; message: string }>> {
1970
- return this.projectTypedEdges(store, options);
1707
+ return projectGraph(store, options, undefined, true);
1971
1708
  }
1972
1709
 
1973
1710
  /**
@@ -21,6 +21,8 @@ import { classifyHttpDestination, prepareHttpDestination } from "./http-policy";
21
21
  const REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
22
22
 
23
23
  export interface HttpInferenceOptions {
24
+ /** Resolved models.inferenceTimeout; measured across the complete HTTP call. */
25
+ inferenceTimeout?: number;
24
26
  collections: readonly Collection[];
25
27
  collectionNames: readonly string[];
26
28
  authenticated?: boolean;
@@ -64,6 +66,7 @@ export const requestHttpInference = async (
64
66
  init: BunFetchRequestInit,
65
67
  options: HttpInferenceOptions
66
68
  ): Promise<Response> => {
69
+ init.signal?.throwIfAborted();
67
70
  const states = scopedStates(options);
68
71
  if (states.length === 0) {
69
72
  enforce(states, "remote", options);
@@ -118,6 +121,7 @@ export const requestHttpInference = async (
118
121
 
119
122
  let currentUrl = url;
120
123
  for (;;) {
124
+ init.signal?.throwIfAborted();
121
125
  enforce(states, prepared.value.classification.zone, options);
122
126
  const connection = await prepared.value.acquireConnection();
123
127
  if (!connection.ok) {
@@ -134,7 +138,9 @@ export const requestHttpInference = async (
134
138
  })
135
139
  );
136
140
  }
141
+ init.signal?.throwIfAborted();
137
142
  const response = await connection.value.request(init, options.fetchFn);
143
+ init.signal?.throwIfAborted();
138
144
  if (!REDIRECT_STATUSES.has(response.status)) return response;
139
145
 
140
146
  const location = response.headers.get("location");
@@ -1,16 +1,17 @@
1
+ import type { HttpInferenceOptions } from "./http-inference";
2
+ import type { InferenceOptions } from "./types";
1
3
  /**
2
4
  * HTTP-based embedding port implementation.
3
5
  * Calls OpenAI-compatible embedding endpoints.
4
6
  *
5
7
  * @module src/llm/httpEmbedding
6
8
  */
7
-
8
- import type { HttpInferenceOptions } from "./http-inference";
9
9
  import type { EmbeddingPort, LlmResult } from "./types";
10
10
 
11
11
  import { EgressDeniedError } from "../core/egress-enforcement";
12
12
  import { egressDeniedInferenceError, inferenceFailedError } from "./errors";
13
13
  import { requestHttpInference } from "./http-inference";
14
+ import { runHttpInference } from "./inference-scope";
14
15
 
15
16
  // ─────────────────────────────────────────────────────────────────────────────
16
17
  // Types
@@ -58,20 +59,35 @@ export class HttpEmbedding implements EmbeddingPort {
58
59
  }
59
60
  }
60
61
 
61
- async init(): Promise<LlmResult<void>> {
62
+ async init(options?: InferenceOptions): Promise<LlmResult<void>> {
62
63
  // Test connection with a simple embedding
63
- const result = await this.embed("test");
64
+ const result = await this.embed("test", options);
64
65
  if (!result.ok) {
65
66
  return result;
66
67
  }
67
68
  return { ok: true, value: undefined };
68
69
  }
69
70
 
70
- async embed(text: string): Promise<LlmResult<number[]>> {
71
+ async embed(
72
+ text: string,
73
+ options?: InferenceOptions
74
+ ): Promise<LlmResult<number[]>> {
75
+ return runHttpInference(
76
+ options,
77
+ (operational) => this.embedRequest(text, operational),
78
+ this.requestOptions.inferenceTimeout
79
+ );
80
+ }
81
+
82
+ private async embedRequest(
83
+ text: string,
84
+ options: InferenceOptions
85
+ ): Promise<LlmResult<number[]>> {
71
86
  try {
72
87
  const response = await requestHttpInference(
73
88
  this.apiUrl,
74
89
  {
90
+ signal: options.signal,
75
91
  method: "POST",
76
92
  headers: {
77
93
  "Content-Type": "application/json",
@@ -128,11 +144,26 @@ export class HttpEmbedding implements EmbeddingPort {
128
144
  }
129
145
  }
130
146
 
131
- async embedBatch(texts: string[]): Promise<LlmResult<number[][]>> {
147
+ async embedBatch(
148
+ texts: string[],
149
+ options?: InferenceOptions
150
+ ): Promise<LlmResult<number[][]>> {
151
+ return runHttpInference(
152
+ options,
153
+ (operational) => this.embedBatchRequest(texts, operational),
154
+ this.requestOptions.inferenceTimeout
155
+ );
156
+ }
157
+
158
+ private async embedBatchRequest(
159
+ texts: string[],
160
+ options: InferenceOptions
161
+ ): Promise<LlmResult<number[][]>> {
132
162
  try {
133
163
  const response = await requestHttpInference(
134
164
  this.apiUrl,
135
165
  {
166
+ signal: options.signal,
136
167
  method: "POST",
137
168
  headers: {
138
169
  "Content-Type": "application/json",
@@ -1,11 +1,11 @@
1
+ import type { HttpInferenceOptions } from "./http-inference";
2
+ import type { InferenceOptions } from "./types";
1
3
  /**
2
4
  * HTTP-based generation port implementation.
3
5
  * Calls OpenAI-compatible chat completion endpoints.
4
6
  *
5
7
  * @module src/llm/httpGeneration
6
8
  */
7
-
8
- import type { HttpInferenceOptions } from "./http-inference";
9
9
  import type { GenerationPort, GenParams, LlmResult } from "./types";
10
10
 
11
11
  import { EgressDeniedError } from "../core/egress-enforcement";
@@ -15,6 +15,7 @@ import {
15
15
  structuredOutputUnavailableError,
16
16
  } from "./errors";
17
17
  import { requestHttpInference } from "./http-inference";
18
+ import { runHttpInference } from "./inference-scope";
18
19
 
19
20
  // ─────────────────────────────────────────────────────────────────────────────
20
21
  // Types
@@ -71,7 +72,20 @@ export class HttpGeneration implements GenerationPort {
71
72
 
72
73
  async generate(
73
74
  prompt: string,
74
- params?: GenParams
75
+ params?: GenParams,
76
+ options?: InferenceOptions
77
+ ): Promise<LlmResult<string>> {
78
+ return runHttpInference(
79
+ options,
80
+ (operational) => this.generateRequest(prompt, params, operational),
81
+ this.requestOptions.inferenceTimeout
82
+ );
83
+ }
84
+
85
+ private async generateRequest(
86
+ prompt: string,
87
+ params: GenParams | undefined,
88
+ options: InferenceOptions
75
89
  ): Promise<LlmResult<string>> {
76
90
  if (params?.jsonSchema) {
77
91
  return {
@@ -83,6 +97,7 @@ export class HttpGeneration implements GenerationPort {
83
97
  const response = await requestHttpInference(
84
98
  this.apiUrl,
85
99
  {
100
+ signal: options.signal,
86
101
  method: "POST",
87
102
  headers: {
88
103
  "Content-Type": "application/json",
@@ -1,16 +1,17 @@
1
+ import type { HttpInferenceOptions } from "./http-inference";
2
+ import type { InferenceOptions } from "./types";
1
3
  /**
2
4
  * HTTP-based rerank port implementation.
3
5
  * Calls OpenAI-compatible completions endpoints for reranking.
4
6
  *
5
7
  * @module src/llm/httpRerank
6
8
  */
7
-
8
- import type { HttpInferenceOptions } from "./http-inference";
9
9
  import type { LlmResult, RerankPort, RerankScore } from "./types";
10
10
 
11
11
  import { EgressDeniedError } from "../core/egress-enforcement";
12
12
  import { egressDeniedInferenceError, inferenceFailedError } from "./errors";
13
13
  import { requestHttpInference } from "./http-inference";
14
+ import { runHttpInference } from "./inference-scope";
14
15
 
15
16
  // ─────────────────────────────────────────────────────────────────────────────
16
17
  // Types
@@ -63,7 +64,20 @@ export class HttpRerank implements RerankPort {
63
64
 
64
65
  async rerank(
65
66
  query: string,
66
- documents: string[]
67
+ documents: string[],
68
+ options?: InferenceOptions
69
+ ): Promise<LlmResult<RerankScore[]>> {
70
+ return runHttpInference(
71
+ options,
72
+ (operational) => this.rerankRequest(query, documents, operational),
73
+ this.requestOptions.inferenceTimeout
74
+ );
75
+ }
76
+
77
+ private async rerankRequest(
78
+ query: string,
79
+ documents: string[],
80
+ options: InferenceOptions
67
81
  ): Promise<LlmResult<RerankScore[]>> {
68
82
  if (documents.length === 0) {
69
83
  return { ok: true, value: [] };
@@ -74,7 +88,7 @@ export class HttpRerank implements RerankPort {
74
88
  const prompts = documents.map((doc) => this.buildPrompt(query, doc));
75
89
 
76
90
  // Score all documents in a single batch request
77
- const scoresResult = await this.scoreBatch(prompts);
91
+ const scoresResult = await this.scoreBatch(prompts, options);
78
92
 
79
93
  if (!scoresResult.ok) {
80
94
  return { ok: false, error: scoresResult.error };
@@ -112,11 +126,15 @@ export class HttpRerank implements RerankPort {
112
126
  return `<Instruct>: ${this.instruction}\n<Query>: ${query}\n<Document>: ${document}\n<Score>:`;
113
127
  }
114
128
 
115
- private async scoreBatch(prompts: string[]): Promise<LlmResult<number[]>> {
129
+ private async scoreBatch(
130
+ prompts: string[],
131
+ options: InferenceOptions
132
+ ): Promise<LlmResult<number[]>> {
116
133
  try {
117
134
  const response = await requestHttpInference(
118
135
  this.apiUrl,
119
136
  {
137
+ signal: options.signal,
120
138
  method: "POST",
121
139
  headers: {
122
140
  "Content-Type": "application/json",