dsh-data-domain-knowledge 0.1.0-alpha.9 → 0.1.1-alpha.2

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 (438) hide show
  1. package/README.md +118 -567
  2. package/cordis.patch.yml +5 -418
  3. package/eval/README.md +19 -8
  4. package/eval/benchmark-extraction-format.mjs +20 -0
  5. package/eval/evaluate-retrieval.mjs +17 -8
  6. package/eval/queries.example.jsonl +1 -0
  7. package/lib/client.js +4181 -3239
  8. package/lib/contract-envelope.d.ts +91 -0
  9. package/lib/contract-envelope.js +106 -0
  10. package/lib/contract-layout.d.ts +130 -0
  11. package/lib/contract-layout.js +138 -0
  12. package/lib/contract-refs.d.ts +39 -0
  13. package/lib/contract-refs.js +9 -0
  14. package/lib/contract-version.d.ts +311 -0
  15. package/lib/contract-version.js +270 -0
  16. package/lib/contract-wire.d.ts +147 -0
  17. package/lib/contract-wire.js +99 -0
  18. package/lib/contracts.d.ts +12 -0
  19. package/lib/contracts.js +12 -0
  20. package/lib/doc-page.js +2 -2
  21. package/lib/pages.js +3329 -1296
  22. package/lib/types/agent-behavior-rules.d.ts +10 -0
  23. package/lib/types/agent-behavior-rules.d.ts.map +1 -0
  24. package/lib/types/agent-behavior-rules.js +28 -0
  25. package/lib/types/agent-behavior-rules.js.map +1 -0
  26. package/lib/types/axis-registry.d.ts +37 -5
  27. package/lib/types/axis-registry.d.ts.map +1 -1
  28. package/lib/types/axis-registry.js +234 -26
  29. package/lib/types/axis-registry.js.map +1 -1
  30. package/lib/types/card-organize.d.ts +27 -12
  31. package/lib/types/card-organize.d.ts.map +1 -1
  32. package/lib/types/card-organize.js +58 -73
  33. package/lib/types/card-organize.js.map +1 -1
  34. package/lib/types/compiler/embedding-identity.d.ts +3 -0
  35. package/lib/types/compiler/embedding-identity.d.ts.map +1 -0
  36. package/lib/types/compiler/embedding-identity.js +24 -0
  37. package/lib/types/compiler/embedding-identity.js.map +1 -0
  38. package/lib/types/compiler/snapshot.d.ts +16 -0
  39. package/lib/types/compiler/snapshot.d.ts.map +1 -0
  40. package/lib/types/compiler/snapshot.js +2 -0
  41. package/lib/types/compiler/snapshot.js.map +1 -0
  42. package/lib/types/config-schema.d.ts +6 -3
  43. package/lib/types/config-schema.d.ts.map +1 -1
  44. package/lib/types/config-schema.js +6 -2
  45. package/lib/types/config-schema.js.map +1 -1
  46. package/lib/types/convert/host.d.ts +6 -5
  47. package/lib/types/convert/host.d.ts.map +1 -1
  48. package/lib/types/convert/host.js +58 -18
  49. package/lib/types/convert/host.js.map +1 -1
  50. package/lib/types/convert/ingest.d.ts +10 -1
  51. package/lib/types/convert/ingest.d.ts.map +1 -1
  52. package/lib/types/convert/ingest.js +68 -9
  53. package/lib/types/convert/ingest.js.map +1 -1
  54. package/lib/types/derive-contract.d.ts +3 -0
  55. package/lib/types/derive-contract.d.ts.map +1 -0
  56. package/lib/types/derive-contract.js +15 -0
  57. package/lib/types/derive-contract.js.map +1 -0
  58. package/lib/types/diagnosis/cards.d.ts +7 -3
  59. package/lib/types/diagnosis/cards.d.ts.map +1 -1
  60. package/lib/types/diagnosis/cards.js +13 -8
  61. package/lib/types/diagnosis/cards.js.map +1 -1
  62. package/lib/types/diagnosis/run.d.ts +4 -13
  63. package/lib/types/diagnosis/run.d.ts.map +1 -1
  64. package/lib/types/diagnosis/run.js +26 -16
  65. package/lib/types/diagnosis/run.js.map +1 -1
  66. package/lib/types/diagnosis/schema.js +2 -2
  67. package/lib/types/diagnosis/schema.js.map +1 -1
  68. package/lib/types/diagnosis/seed-source.d.ts +1 -1
  69. package/lib/types/diagnosis/seed-source.d.ts.map +1 -1
  70. package/lib/types/diagnosis/seed-source.js +5 -4
  71. package/lib/types/diagnosis/seed-source.js.map +1 -1
  72. package/lib/types/diagnosis/seed.d.ts +4 -4
  73. package/lib/types/diagnosis/seed.d.ts.map +1 -1
  74. package/lib/types/diagnosis/seed.js +6 -8
  75. package/lib/types/diagnosis/seed.js.map +1 -1
  76. package/lib/types/diagnosis/store.d.ts +24 -18
  77. package/lib/types/diagnosis/store.d.ts.map +1 -1
  78. package/lib/types/diagnosis/store.js +130 -65
  79. package/lib/types/diagnosis/store.js.map +1 -1
  80. package/lib/types/diagnosis/types.d.ts +47 -15
  81. package/lib/types/diagnosis/types.d.ts.map +1 -1
  82. package/lib/types/diagnosis/types.js.map +1 -1
  83. package/lib/types/environment/dsh-python.d.ts +77 -0
  84. package/lib/types/environment/dsh-python.d.ts.map +1 -0
  85. package/lib/types/environment/dsh-python.js +139 -0
  86. package/lib/types/environment/dsh-python.js.map +1 -0
  87. package/lib/types/environment/install.d.ts +15 -0
  88. package/lib/types/environment/install.d.ts.map +1 -0
  89. package/lib/types/environment/install.js +297 -0
  90. package/lib/types/environment/install.js.map +1 -0
  91. package/lib/types/environment/manifest.d.ts +208 -0
  92. package/lib/types/environment/manifest.d.ts.map +1 -0
  93. package/lib/types/environment/manifest.js +26 -0
  94. package/lib/types/environment/manifest.js.map +1 -0
  95. package/lib/types/environment/model-catalog.d.ts +223 -0
  96. package/lib/types/environment/model-catalog.d.ts.map +1 -0
  97. package/lib/types/environment/model-catalog.js +129 -0
  98. package/lib/types/environment/model-catalog.js.map +1 -0
  99. package/lib/types/environment/process.d.ts +10 -0
  100. package/lib/types/environment/process.d.ts.map +1 -0
  101. package/lib/types/environment/process.js +54 -0
  102. package/lib/types/environment/process.js.map +1 -0
  103. package/lib/types/environment/selection.d.ts +9 -0
  104. package/lib/types/environment/selection.d.ts.map +1 -0
  105. package/lib/types/environment/selection.js +29 -0
  106. package/lib/types/environment/selection.js.map +1 -0
  107. package/lib/types/environment/service.d.ts +64 -0
  108. package/lib/types/environment/service.d.ts.map +1 -0
  109. package/lib/types/environment/service.js +424 -0
  110. package/lib/types/environment/service.js.map +1 -0
  111. package/lib/types/environment/types.d.ts +56 -0
  112. package/lib/types/environment/types.d.ts.map +1 -0
  113. package/lib/types/environment/types.js +2 -0
  114. package/lib/types/environment/types.js.map +1 -0
  115. package/lib/types/events.d.ts +76 -0
  116. package/lib/types/events.d.ts.map +1 -0
  117. package/lib/types/events.js +52 -0
  118. package/lib/types/events.js.map +1 -0
  119. package/lib/types/extract-contract.d.ts +3 -0
  120. package/lib/types/extract-contract.d.ts.map +1 -0
  121. package/lib/types/extract-contract.js +41 -0
  122. package/lib/types/extract-contract.js.map +1 -0
  123. package/lib/types/extract-model.d.ts +5 -0
  124. package/lib/types/extract-model.d.ts.map +1 -1
  125. package/lib/types/extract-model.js.map +1 -1
  126. package/lib/types/extract-table-contract.d.ts +3 -0
  127. package/lib/types/extract-table-contract.d.ts.map +1 -0
  128. package/lib/types/extract-table-contract.js +27 -0
  129. package/lib/types/extract-table-contract.js.map +1 -0
  130. package/lib/types/extract-table.d.ts +8 -0
  131. package/lib/types/extract-table.d.ts.map +1 -0
  132. package/lib/types/extract-table.js +158 -0
  133. package/lib/types/extract-table.js.map +1 -0
  134. package/lib/types/extraction-runs.d.ts +30 -6
  135. package/lib/types/extraction-runs.d.ts.map +1 -1
  136. package/lib/types/extraction-runs.js +69 -8
  137. package/lib/types/extraction-runs.js.map +1 -1
  138. package/lib/types/fs-atomic.d.ts +0 -7
  139. package/lib/types/fs-atomic.d.ts.map +1 -1
  140. package/lib/types/fs-atomic.js +17 -2
  141. package/lib/types/fs-atomic.js.map +1 -1
  142. package/lib/types/images.d.ts +26 -0
  143. package/lib/types/images.d.ts.map +1 -0
  144. package/lib/types/images.js +196 -0
  145. package/lib/types/images.js.map +1 -0
  146. package/lib/types/index.d.ts +2 -2
  147. package/lib/types/index.d.ts.map +1 -1
  148. package/lib/types/index.js +598 -209
  149. package/lib/types/index.js.map +1 -1
  150. package/lib/types/intent/engine.d.ts +12 -4
  151. package/lib/types/intent/engine.d.ts.map +1 -1
  152. package/lib/types/intent/engine.js +43 -5
  153. package/lib/types/intent/engine.js.map +1 -1
  154. package/lib/types/intent/host.d.ts +5 -8
  155. package/lib/types/intent/host.d.ts.map +1 -1
  156. package/lib/types/intent/host.js +56 -11
  157. package/lib/types/intent/host.js.map +1 -1
  158. package/lib/types/intent/scope.d.ts +25 -0
  159. package/lib/types/intent/scope.d.ts.map +1 -0
  160. package/lib/types/intent/scope.js +116 -0
  161. package/lib/types/intent/scope.js.map +1 -0
  162. package/lib/types/intent/tools.d.ts +24 -20
  163. package/lib/types/intent/tools.d.ts.map +1 -1
  164. package/lib/types/intent/tools.js +65 -23
  165. package/lib/types/intent/tools.js.map +1 -1
  166. package/lib/types/intent/types.d.ts +11 -4
  167. package/lib/types/intent/types.d.ts.map +1 -1
  168. package/lib/types/knowledge-bases.d.ts +11 -5
  169. package/lib/types/knowledge-bases.d.ts.map +1 -1
  170. package/lib/types/knowledge-bases.js +52 -20
  171. package/lib/types/knowledge-bases.js.map +1 -1
  172. package/lib/types/knowledge-contract.d.ts +32 -0
  173. package/lib/types/knowledge-contract.d.ts.map +1 -0
  174. package/lib/types/knowledge-contract.js +116 -0
  175. package/lib/types/knowledge-contract.js.map +1 -0
  176. package/lib/types/knowledge.d.ts +31 -9
  177. package/lib/types/knowledge.d.ts.map +1 -1
  178. package/lib/types/knowledge.js +137 -60
  179. package/lib/types/knowledge.js.map +1 -1
  180. package/lib/types/layout.d.ts +10 -29
  181. package/lib/types/layout.d.ts.map +1 -1
  182. package/lib/types/layout.js +17 -36
  183. package/lib/types/layout.js.map +1 -1
  184. package/lib/types/materialize-snapshot.d.ts +49 -0
  185. package/lib/types/materialize-snapshot.d.ts.map +1 -0
  186. package/lib/types/materialize-snapshot.js +2 -0
  187. package/lib/types/materialize-snapshot.js.map +1 -0
  188. package/lib/types/migrate.d.ts +11 -0
  189. package/lib/types/migrate.d.ts.map +1 -1
  190. package/lib/types/migrate.js +83 -2
  191. package/lib/types/migrate.js.map +1 -1
  192. package/lib/types/model-text.d.ts +58 -1
  193. package/lib/types/model-text.d.ts.map +1 -1
  194. package/lib/types/model-text.js +85 -30
  195. package/lib/types/model-text.js.map +1 -1
  196. package/lib/types/oplog.d.ts.map +1 -1
  197. package/lib/types/oplog.js +7 -0
  198. package/lib/types/oplog.js.map +1 -1
  199. package/lib/types/organize-contract.d.ts +18 -0
  200. package/lib/types/organize-contract.d.ts.map +1 -0
  201. package/lib/types/organize-contract.js +82 -0
  202. package/lib/types/organize-contract.js.map +1 -0
  203. package/lib/types/pipeline/engine.d.ts +66 -0
  204. package/lib/types/pipeline/engine.d.ts.map +1 -0
  205. package/lib/types/pipeline/engine.js +352 -0
  206. package/lib/types/pipeline/engine.js.map +1 -0
  207. package/lib/types/pipeline/store.d.ts +73 -0
  208. package/lib/types/pipeline/store.d.ts.map +1 -0
  209. package/lib/types/pipeline/store.js +143 -0
  210. package/lib/types/pipeline/store.js.map +1 -0
  211. package/lib/types/pipeline/types.d.ts +102 -0
  212. package/lib/types/pipeline/types.d.ts.map +1 -0
  213. package/lib/types/pipeline/types.js +5 -0
  214. package/lib/types/pipeline/types.js.map +1 -0
  215. package/lib/types/present.d.ts +2 -0
  216. package/lib/types/present.d.ts.map +1 -1
  217. package/lib/types/present.js +9 -4
  218. package/lib/types/present.js.map +1 -1
  219. package/lib/types/preset-ids.d.ts +4 -0
  220. package/lib/types/preset-ids.d.ts.map +1 -0
  221. package/lib/types/preset-ids.js +6 -0
  222. package/lib/types/preset-ids.js.map +1 -0
  223. package/lib/types/query-analysis.d.ts +13 -1
  224. package/lib/types/query-analysis.d.ts.map +1 -1
  225. package/lib/types/query-analysis.js +62 -6
  226. package/lib/types/query-analysis.js.map +1 -1
  227. package/lib/types/recall-rank.d.ts +3 -3
  228. package/lib/types/recall-rank.d.ts.map +1 -1
  229. package/lib/types/recall-rank.js +4 -4
  230. package/lib/types/recall-rank.js.map +1 -1
  231. package/lib/types/retention.d.ts +39 -0
  232. package/lib/types/retention.d.ts.map +1 -0
  233. package/lib/types/retention.js +42 -0
  234. package/lib/types/retention.js.map +1 -0
  235. package/lib/types/retrieval/vector-index.d.ts +32 -0
  236. package/lib/types/retrieval/vector-index.d.ts.map +1 -0
  237. package/lib/types/retrieval/vector-index.js +15 -0
  238. package/lib/types/retrieval/vector-index.js.map +1 -0
  239. package/lib/types/retrieval/visibility.d.ts +6 -0
  240. package/lib/types/retrieval/visibility.d.ts.map +1 -0
  241. package/lib/types/retrieval/visibility.js +11 -0
  242. package/lib/types/retrieval/visibility.js.map +1 -0
  243. package/lib/types/runtime.d.ts +272 -27
  244. package/lib/types/runtime.d.ts.map +1 -1
  245. package/lib/types/runtime.js +2751 -537
  246. package/lib/types/runtime.js.map +1 -1
  247. package/lib/types/settings-schema.d.ts +17 -15
  248. package/lib/types/settings-schema.d.ts.map +1 -1
  249. package/lib/types/settings-schema.js +50 -47
  250. package/lib/types/settings-schema.js.map +1 -1
  251. package/lib/types/settings-volatile.d.ts +4 -4
  252. package/lib/types/settings-volatile.js +4 -4
  253. package/lib/types/source-evidence.d.ts +14 -0
  254. package/lib/types/source-evidence.d.ts.map +1 -0
  255. package/lib/types/source-evidence.js +36 -0
  256. package/lib/types/source-evidence.js.map +1 -0
  257. package/lib/types/store/axis-references.d.ts +5 -0
  258. package/lib/types/store/axis-references.d.ts.map +1 -0
  259. package/lib/types/store/axis-references.js +106 -0
  260. package/lib/types/store/axis-references.js.map +1 -0
  261. package/lib/types/store/derived.d.ts +12 -1
  262. package/lib/types/store/derived.d.ts.map +1 -1
  263. package/lib/types/store/derived.js +71 -12
  264. package/lib/types/store/derived.js.map +1 -1
  265. package/lib/types/store/knowledge-db.d.ts +31 -1
  266. package/lib/types/store/knowledge-db.d.ts.map +1 -1
  267. package/lib/types/store/knowledge-db.js +252 -18
  268. package/lib/types/store/knowledge-db.js.map +1 -1
  269. package/lib/types/store/migrate.d.ts.map +1 -1
  270. package/lib/types/store/migrate.js +17 -6
  271. package/lib/types/store/migrate.js.map +1 -1
  272. package/lib/types/trajectory-types.d.ts +172 -0
  273. package/lib/types/trajectory-types.d.ts.map +1 -0
  274. package/lib/types/trajectory-types.js +36 -0
  275. package/lib/types/trajectory-types.js.map +1 -0
  276. package/lib/types/types.d.ts +59 -27
  277. package/lib/types/types.d.ts.map +1 -1
  278. package/lib/types/types.js +6 -15
  279. package/lib/types/types.js.map +1 -1
  280. package/lib/types/wiki-finalize.d.ts +16 -0
  281. package/lib/types/wiki-finalize.d.ts.map +1 -1
  282. package/lib/types/wiki-finalize.js +26 -0
  283. package/lib/types/wiki-finalize.js.map +1 -1
  284. package/lib/types/wiki-materialize.d.ts +4 -0
  285. package/lib/types/wiki-materialize.d.ts.map +1 -1
  286. package/lib/types/wiki-materialize.js +21 -7
  287. package/lib/types/wiki-materialize.js.map +1 -1
  288. package/lib/types/wiki-trial-types.d.ts +87 -0
  289. package/lib/types/wiki-trial-types.d.ts.map +1 -1
  290. package/lib/types/wiki-trial-types.js +0 -16
  291. package/lib/types/wiki-trial-types.js.map +1 -1
  292. package/lib/types/wiki-trial.d.ts +40 -16
  293. package/lib/types/wiki-trial.d.ts.map +1 -1
  294. package/lib/types/wiki-trial.js +337 -224
  295. package/lib/types/wiki-trial.js.map +1 -1
  296. package/package.json +29 -20
  297. package/python/prepare-models.py +19 -0
  298. package/python/requirements.txt +8 -6
  299. package/scripts/doctor.mjs +13 -19
  300. package/scripts/environment.mjs +29 -0
  301. package/scripts/setup-embedding.sh +15 -5
  302. package/src/agent-behavior-rules.ts +37 -0
  303. package/src/axis-registry.ts +234 -27
  304. package/src/card-organize.ts +69 -75
  305. package/src/client/AgentBehaviorRulesCard.tsx +65 -0
  306. package/src/client/AttributionEventGuide.tsx +41 -39
  307. package/src/client/AxisRegistrySection.tsx +204 -164
  308. package/src/client/CompileDialogs.tsx +44 -29
  309. package/src/client/DeleteDocumentDialog.tsx +36 -5
  310. package/src/client/DirectoryPicker.tsx +0 -10
  311. package/src/client/EnvironmentSetup.tsx +243 -0
  312. package/src/client/ExpansionGraph.tsx +13 -7
  313. package/src/client/ExtractionTasksPage.tsx +578 -0
  314. package/src/client/GuideArchitectureCanvas.tsx +470 -0
  315. package/src/client/ImportFilesDialog.tsx +2 -13
  316. package/src/client/IntentLogic.tsx +2 -2
  317. package/src/client/IntentTab.tsx +118 -47
  318. package/src/client/KnowledgeBaseTab.tsx +277 -197
  319. package/src/client/KnowledgeLayerSection.tsx +24 -6
  320. package/src/client/KnowledgePanel.tsx +58 -93
  321. package/src/client/KnowledgeSettingsDrawer.tsx +90 -0
  322. package/src/client/ListPager.tsx +15 -5
  323. package/src/client/MaterializeTrajectoryView.tsx +124 -0
  324. package/src/client/NodeSettings.tsx +210 -89
  325. package/src/client/NormalizeTrajectoryView.tsx +136 -0
  326. package/src/client/PipelineNotice.tsx +26 -0
  327. package/src/client/PreviewSections.tsx +118 -51
  328. package/src/client/RecallPanel.tsx +89 -85
  329. package/src/client/TabGuide.tsx +159 -184
  330. package/src/client/TrialReportView.tsx +391 -214
  331. package/src/client/TypeDefinitionDrawer.tsx +150 -23
  332. package/src/client/WikiCardPreview.tsx +62 -16
  333. package/src/client/WikiFlowPanel.tsx +4 -4
  334. package/src/client/arch/NodeLogicPanel.tsx +3 -4
  335. package/src/client/arch/model.ts +6 -9
  336. package/src/client/architecture.tsx +23 -33
  337. package/src/client/attribution/AttributionGraph.tsx +10 -6
  338. package/src/client/attribution/AttributionTab.tsx +136 -84
  339. package/src/client/attribution/CaseView.tsx +3 -1
  340. package/src/client/attribution/EventView.tsx +108 -0
  341. package/src/client/attribution/RunView.tsx +2 -2
  342. package/src/client/attribution/StageChrome.tsx +34 -3
  343. package/src/client/attribution/ViewSwitch.tsx +20 -5
  344. package/src/client/attribution/graph-options.ts +47 -39
  345. package/src/client/attribution/model.ts +17 -10
  346. package/src/client/config-scope.ts +3 -3
  347. package/src/client/graph/palette.ts +165 -0
  348. package/src/client/index.ts +49 -42
  349. package/src/client/pages.css +459 -135
  350. package/src/client/pages.tsx +37 -9
  351. package/src/client/problem-domains.ts +1 -1
  352. package/src/client/session-remote.ts +9 -0
  353. package/src/client/styles.css +205 -62
  354. package/src/client/wiki-trial.ts +44 -3
  355. package/src/compiler/embedding-identity.ts +21 -0
  356. package/src/compiler/snapshot.ts +17 -0
  357. package/src/config-schema.ts +8 -3
  358. package/src/convert/host.ts +56 -21
  359. package/src/convert/ingest.ts +74 -10
  360. package/src/derive-contract.ts +14 -0
  361. package/src/diagnosis/cards.ts +13 -8
  362. package/src/diagnosis/run.ts +27 -17
  363. package/src/diagnosis/schema.ts +2 -2
  364. package/src/diagnosis/seed-source.ts +5 -4
  365. package/src/diagnosis/seed.ts +6 -8
  366. package/src/diagnosis/store.ts +138 -69
  367. package/src/diagnosis/types.ts +34 -15
  368. package/src/environment/dsh-python.ts +156 -0
  369. package/src/environment/install.ts +244 -0
  370. package/src/environment/manifest.ts +28 -0
  371. package/src/environment/model-catalog.ts +147 -0
  372. package/src/environment/process.ts +54 -0
  373. package/src/environment/selection.ts +29 -0
  374. package/src/environment/service.ts +348 -0
  375. package/src/environment/types.ts +45 -0
  376. package/src/events.ts +108 -0
  377. package/src/extract-contract.ts +42 -0
  378. package/src/extract-model.ts +10 -1
  379. package/src/extract-table-contract.ts +26 -0
  380. package/src/extract-table.ts +132 -0
  381. package/src/extraction-runs.ts +70 -11
  382. package/src/fs-atomic.ts +19 -2
  383. package/src/images.ts +203 -0
  384. package/src/index.ts +553 -205
  385. package/src/intent/README.md +8 -6
  386. package/src/intent/engine.ts +44 -6
  387. package/src/intent/host.ts +59 -18
  388. package/src/intent/scope.ts +125 -0
  389. package/src/intent/tools.ts +70 -28
  390. package/src/intent/types.ts +11 -4
  391. package/src/knowledge-bases.ts +56 -20
  392. package/src/knowledge-contract.ts +114 -0
  393. package/src/knowledge.ts +138 -69
  394. package/src/layout.ts +17 -37
  395. package/src/materialize-snapshot.ts +46 -0
  396. package/src/migrate.ts +75 -2
  397. package/src/model-text.ts +109 -4
  398. package/src/oplog.ts +7 -0
  399. package/src/organize-contract.ts +83 -0
  400. package/src/pipeline/engine.ts +323 -0
  401. package/src/pipeline/store.ts +147 -0
  402. package/src/pipeline/types.ts +93 -0
  403. package/src/present.ts +10 -4
  404. package/src/preset-ids.ts +6 -0
  405. package/src/python/embedding_worker.py +66 -2
  406. package/src/query-analysis.ts +68 -8
  407. package/src/recall-rank.ts +5 -5
  408. package/src/retention.ts +76 -0
  409. package/src/retrieval/vector-index.ts +45 -0
  410. package/src/retrieval/visibility.ts +14 -0
  411. package/src/runtime.ts +2708 -567
  412. package/src/settings-schema.ts +11 -8
  413. package/src/settings-volatile.ts +4 -4
  414. package/src/source-evidence.ts +37 -0
  415. package/src/store/axis-references.ts +96 -0
  416. package/src/store/derived.ts +70 -12
  417. package/src/store/knowledge-db.ts +248 -17
  418. package/src/store/migrate.ts +16 -6
  419. package/src/trajectory-types.ts +142 -0
  420. package/src/types.ts +61 -35
  421. package/src/wiki-finalize.ts +28 -0
  422. package/src/wiki-materialize.ts +25 -6
  423. package/src/wiki-trial-types.ts +83 -1
  424. package/src/wiki-trial.ts +357 -185
  425. package/lib/types/intent/preset-tools.d.ts +0 -37
  426. package/lib/types/intent/preset-tools.d.ts.map +0 -1
  427. package/lib/types/intent/preset-tools.js +0 -45
  428. package/lib/types/intent/preset-tools.js.map +0 -1
  429. package/preset/tita-data-agent/agent.cordis.yml +0 -394
  430. package/preset/tita-data-agent/preset.yml +0 -3
  431. package/scripts/install-agent-preset.mjs +0 -92
  432. package/scripts/sync-agent-preset.mjs +0 -188
  433. package/src/client/AgentPresetCard.tsx +0 -247
  434. package/src/client/agent-preset.ts +0 -121
  435. package/src/client/convert/ConvertPanel.tsx +0 -583
  436. package/src/client/convert/styles.css +0 -138
  437. package/src/client/convert/styles.ts +0 -49
  438. package/src/intent/preset-tools.ts +0 -48
@@ -24,7 +24,7 @@
24
24
  * **注册命名空间**那一步就抛异常(`register` 先 `resolve` 再登记):
25
25
  *
26
26
  * - 命名空间从未注册 → 面板上整个知识库设置显示「设置服务不可用」;
27
- * - `swap()` 永远不被调用 → `migrateLegacyResources` 从不执行(家当一直留在旧位置);
27
+ * - `swap()` 永远不被调用 → 资源路径不会被运行时自动改写;
28
28
  * - `settings.yaml` 里存的值一个都不生效。
29
29
  *
30
30
  * 而且是**全量**失效,不是只有这三个字段 —— 所以这三个字段只约束「是字符串」,
@@ -42,15 +42,18 @@ import { DIAGNOSIS_ENTITY_TYPES } from './diagnosis/schema.js'
42
42
  /** 设置命名空间。命名规则是 `^[a-z][a-z0-9-]*$`(dsh-settings 的 `parseSettingsNamespace`)。 */
43
43
  export const SETTINGS_NAMESPACE = 'tita-data-agent-knowledge'
44
44
 
45
- export const KNOWLEDGE_SETTINGS_SCHEMA = z.object(volatileFields({
45
+ export const KNOWLEDGE_SETTINGS_SCHEMA = z.object({
46
46
  /**
47
- * **用户唯一要设的路径**(0029)。四段布局由它推出来,见 `layout.ts`。
47
+ * **固定的 Agent 根路径**。它不标记为 volatile,因此不会出现在设置弹层里;旧配置
48
+ * 仍保留在 schema 中,供旧配置平滑解析;运行时只使用新的默认根路径。
48
49
  */
49
50
  agentRoot: z.string().min(1).default(defaultAgentRoot()),
51
+ /** 固定多路径融合。保留旧路线值以平滑读取旧配置,但不标成可编辑设置。 */
52
+ recallMode: z.union(['fts', 'vector', 'hybrid'] as const).default(DEFAULT_KNOWLEDGE_CONFIG.recallMode),
53
+ ...volatileFields({
50
54
  /**
51
- * @deprecated 0029:旧布局的知识树根。**只作为一次性迁移的来源**保留 ——
52
- * 它不再出现在设置面板里,也不再决定任何路径。留一个宽松的字符串默认值,
53
- * 是为了让老用户的 settings JSON 还能被解析出来,从而知道旧树在哪。
55
+ * @deprecated 0029:旧布局的知识树根。仅保留字段形状以兼容旧配置;
56
+ * 新逻辑忽略它,也不会读取或迁移旧树。
54
57
  */
55
58
  rootDir: z.string().default(''),
56
59
  schemaTypes: z.array(z.union(['concept', 'metric', 'table', 'event', 'playbook', 'case', ...DIAGNOSIS_ENTITY_TYPES] as const)).default(DEFAULT_KNOWLEDGE_CONFIG.schemaTypes),
@@ -76,7 +79,6 @@ export const KNOWLEDGE_SETTINGS_SCHEMA = z.object(volatileFields({
76
79
  // 0031:候选池与最终条数彻底分开。上限 200 是因为再深也只是把噪声往后排,
77
80
  // 而重排的代价随候选数线性增长。
78
81
  recallCandidatePool: z.number().step(1).min(1).max(200).default(DEFAULT_KNOWLEDGE_CONFIG.recallCandidatePool),
79
- recallMode: z.union(['fts', 'vector', 'hybrid'] as const).default(DEFAULT_KNOWLEDGE_CONFIG.recallMode),
80
82
  // 阈值区间都开满:初值取 WeKnora 的出厂值,但校准要能自由调。
81
83
  // 关键词是归一化 BM25(0..1,相对),向量是原始余弦(−1..1,绝对)。
82
84
  keywordThreshold: z.number().min(0).max(1).default(DEFAULT_KNOWLEDGE_CONFIG.keywordThreshold),
@@ -91,4 +93,5 @@ export const KNOWLEDGE_SETTINGS_SCHEMA = z.object(volatileFields({
91
93
  rerankProvider: z.union(['bert-python', 'none'] as const).default(DEFAULT_KNOWLEDGE_CONFIG.rerankProvider),
92
94
  rerankModel: z.string().default(DEFAULT_KNOWLEDGE_CONFIG.rerankModel),
93
95
  rerankTimeoutMs: z.number().step(1).min(1000).max(600000).default(DEFAULT_KNOWLEDGE_CONFIG.rerankTimeoutMs),
94
- }))
96
+ }),
97
+ })
@@ -24,14 +24,14 @@
24
24
  * if (form === void 0) return []; // ← 一个字段都投影不出来,整条 entry 不会进 describe()
25
25
  * ```
26
26
  *
27
- * 我们的字段全是普通的 `.default(...)`,既不是 object 也不是 volatile,于是全部落到
27
+ * 可编辑业务字段如果只用普通的 `.default(...)`,既不是 object 也不是 volatile,就会落到
28
28
  * 出口 ③,整条 entry 被丢掉,客户端就只剩下 `unavailable`。核心插件的写法都带
29
29
  * `.volatile()`(`z.string().volatile()`、`z.number().default(10).volatile()`),
30
30
  * 这就是那条约定。
31
31
  *
32
32
  * ## 为什么这里统一标,而不是逐个手写
33
33
  *
34
- * 三个设置 schema 一共 40 多个字段;逐个加 `.volatile()` 既啰嗦,又会漏 —— 而**漏一个
34
+ * 可编辑设置字段有 40 多个;逐个加 `.volatile()` 既啰嗦,又会漏 —— 而**漏一个
35
35
  * 字段的后果是那个设置项在界面上直接消失**,属于沉默的失败。统一包一层让「新增字段
36
36
  * 默认可见」成为默认行为,想让它不可见才需要显式说明。
37
37
  *
@@ -66,7 +66,7 @@ export function volatileFields<T extends Record<string, Schemastery>>(fields: T)
66
66
  /**
67
67
  * volatile 字段解包。
68
68
  *
69
- * 0.1.7 的设置字段**全部标了 `.volatile()`**(理由见 `settings-volatile.ts`),而
69
+ * 0.1.7 起可编辑的业务设置字段标为 `.volatile()`;固定配置字段不标。
70
70
  * schemastery 对 volatile 字段解析出来的**不是值,是一个引用** —— `{ get(), set() }`。
71
71
  * 核心插件也是这么用的:`dsh-agent-default-model` 读的是 `this.config.provider.get()`。
72
72
  *
@@ -90,7 +90,7 @@ export function unwrapVolatile<T>(value: unknown): T | undefined {
90
90
  * ## 为什么需要两层
91
91
  *
92
92
  * entry config 的形状是固定的 `{ 组名: { 字段: 引用 } }`(见 `config-schema.ts` 的
93
- * `knowledge` / `intent` / `convert` 三组),而只解一层的结果是「组本身还是原始对象、
93
+ * `knowledge` / `convert` / `behaviorRules` 三组),而只解一层的结果是「组本身还是原始对象、
94
94
  * 组里的字段还是引用」。
95
95
  *
96
96
  * 0029 实测到的故障就是这样来的:`intent` 组被原样交给 `applyIntent`,于是
@@ -0,0 +1,37 @@
1
+ import type { Knowledge, KnowledgeSource } from './knowledge.js'
2
+ import type { KnowledgeDb } from './store/knowledge-db.js'
3
+
4
+ /** Checking an evidence anchor does not establish whether a claim is true. */
5
+ /**
6
+ * `bodies` 是可选的**来源正文预读**(documentId → 当前版本与正文)。批量路径(物化快照)
7
+ * 一次读完全部来源再传进来,于是每条知识不再各自 join 一次 blob、各做一次整份文档的
8
+ * flatten 与子串匹配 —— 那是 O(知识条数 × 文档大小)。不传时退回按需读取(单条判定)。
9
+ */
10
+ export function assessKnowledgeEvidence(knowledge: Knowledge, db: KnowledgeDb, bodies?: ReadonlyMap<string, { version: number; content: string }>): Knowledge {
11
+ return {
12
+ ...knowledge,
13
+ sources: knowledge.sources.map(source => assessSource(source, db, bodies)),
14
+ }
15
+ }
16
+
17
+ function assessSource(source: KnowledgeSource, db: KnowledgeDb, bodies?: ReadonlyMap<string, { version: number; content: string }>): KnowledgeSource {
18
+ if (source.withdrawn) return { ...source, evidenceStatus: 'historical', quoteInCurrentVersion: false }
19
+ if (!source.documentId) return { ...source, evidenceStatus: 'human' }
20
+ const head = bodies?.get(source.documentId) ?? db.source(source.documentId)
21
+ if (!head) return { ...source, evidenceStatus: 'missing', quoteInCurrentVersion: false }
22
+ const content = 'record' in head ? head.record.content : head.content
23
+ const flatten = (text: string): string => text.replace(/\s+/g, '')
24
+ const quote = flatten(source.quote)
25
+ return {
26
+ ...source,
27
+ currentVersion: head.version,
28
+ evidenceStatus: source.toVersion === undefined ? 'unversioned'
29
+ : source.toVersion === head.version ? 'current' : 'historical',
30
+ quoteInCurrentVersion: quote !== '' && flatten(content).includes(quote),
31
+ }
32
+ }
33
+
34
+ export function hasCurrentSupport(knowledge: Knowledge): boolean {
35
+ return knowledge.sources.some(source => source.evidenceStatus === 'human'
36
+ || (source.evidenceStatus === 'current' && source.quoteInCurrentVersion === true))
37
+ }
@@ -0,0 +1,96 @@
1
+ import { createHash } from 'node:crypto'
2
+ import type { AxisKind } from '../axis-registry.js'
3
+ import { compositeEventIdentity, eventEntityFromRecords, stripEventReferenceSection, type EventEntity } from '../events.js'
4
+ import { cardCoordinateKey, type CardCoordinate } from '../types.js'
5
+ import type { KnowledgeDb, CardKnowledgeRow } from './knowledge-db.js'
6
+
7
+ /** Runs inside the axis merge transaction on the same validated connection. */
8
+ export function redirectAxisReferences(db: KnowledgeDb, kind: AxisKind, fromId: string, intoId: string): void {
9
+ const column = { object: 'object_id', action: 'action_id', scene: 'scene_id' }[kind]
10
+ const field = { object: 'objectId', action: 'actionId', scene: 'sceneId' }[kind] as keyof CardCoordinate
11
+ const redirect = (coordinate: CardCoordinate): CardCoordinate => ({
12
+ ...coordinate, [field]: coordinate[field] === fromId ? intoId : coordinate[field],
13
+ })
14
+ const hasKnowledge = db.raw("SELECT 1 FROM sqlite_master WHERE name = 'knowledge'").get()
15
+ if (hasKnowledge) db.raw(`UPDATE knowledge SET ${column} = ?, updated_at = ? WHERE ${column} = ?`).run(intoId, new Date().toISOString(), fromId)
16
+ const placements = db.placements()
17
+ const cards = db.cards()
18
+ const byCoordinate = new Map(cards.filter(row => row.card.coordinate).map(row => [cardCoordinateKey(row.card.coordinate!), row]))
19
+ db.transact({ opId: `axis-merge:${fromId}:${intoId}:${Date.now()}`, actor: 'user', summary: '合并轴实体并迁移知识、卡片与事件引用' }, tx => {
20
+ for (const row of cards) {
21
+ const coordinate = row.card.coordinate
22
+ if (!coordinate || coordinate[field] !== fromId) continue
23
+ const next = redirect(coordinate)
24
+ const key = cardCoordinateKey(next)
25
+ const target = byCoordinate.get(key)
26
+ const base = target && target.card.entityId !== row.card.entityId ? target : row
27
+ const merged = base !== row
28
+ const eventRefs = [...new Set([...db.cardEventIds(base.card.entityId), ...db.cardEventIds(row.card.entityId)])]
29
+ const card = {
30
+ ...base.card, coordinate: next,
31
+ content: stripEventReferenceSection(merged ? `${base.card.content}\n\n${row.card.content}` : row.card.content),
32
+ sourceRefs: [...new Set([...base.card.sourceRefs, ...row.card.sourceRefs])],
33
+ annotations: [...new Map([...(base.card.annotations ?? []), ...(row.card.annotations ?? [])].map(annotation => [annotation.id, annotation])).values()],
34
+ metadata: { ...base.card.metadata, layout: undefined, citations: undefined,
35
+ aliases: [...new Set([...(Array.isArray(base.card.metadata.aliases) ? base.card.metadata.aliases : []), ...(Array.isArray(row.card.metadata.aliases) ? row.card.metadata.aliases : []), base.card.title, row.card.title])],
36
+ ...(eventRefs.length ? { event_refs: JSON.stringify(eventRefs) } : {}) },
37
+ }
38
+ const rows = [...(placements.get(base.card.entityId) ?? []), ...(merged ? placements.get(row.card.entityId) ?? [] : [])]
39
+ const combined: CardKnowledgeRow[] = [...new Map(rows.map(placement => [placement.knowledgeId, placement])).values()]
40
+ if (merged) tx.removeEntity('card', row.card.entityId)
41
+ const frontmatter = { ...base.frontmatter, coordinate: { object: next.objectId, action: next.actionId, scene: next.sceneId }, source_refs: card.sourceRefs, metadata: card.metadata, annotations: card.annotations }
42
+ tx.putCard(card, frontmatter, { actor: 'user', kind: 'named', summary: '轴合并后的卡片引用' }, combined, true)
43
+ db.setCardEvents(card.entityId, eventRefs)
44
+ byCoordinate.delete(cardCoordinateKey(coordinate))
45
+ byCoordinate.set(key, { ...base, card, frontmatter })
46
+ placements.set(card.entityId, combined)
47
+ }
48
+ const changed = new Set<string>()
49
+ const events = db.events().map(event => {
50
+ if (event.coordinateIds[field] !== fromId && !event.records.some(record => record.coordinateIds[field] === fromId)) return event
51
+ changed.add(event.id)
52
+ return { ...event, coordinateIds: redirect(event.coordinateIds), records: event.records.map(record => ({ ...record, coordinateIds: redirect(record.coordinateIds) })), updatedAt: new Date().toISOString() }
53
+ })
54
+ const externalBases = new Map(events.filter(event => event.identityType === 'external_id' && !event.identityKey.includes(':coordinate:')).map(event => [event.identityKey, event]))
55
+ const groups = new Map<string, EventEntity[]>()
56
+ for (const event of events) {
57
+ let key = event.identityKey
58
+ if (changed.has(event.id) && event.identityType === 'composite') key = compositeEventIdentity(event.occurredAt, event.coordinateIds, event.symptom)
59
+ if (event.identityType === 'external_id' && key.includes(':coordinate:')) {
60
+ const baseKey = key.slice(0, key.indexOf(':coordinate:'))
61
+ const base = externalBases.get(baseKey)
62
+ if (base && cardCoordinateKey(base.coordinateIds) === cardCoordinateKey(event.coordinateIds)) key = baseKey
63
+ else if (changed.has(event.id)) key = baseKey + ':coordinate:' + createHash('sha256').update(JSON.stringify(event.coordinateIds)).digest('hex').slice(0, 24)
64
+ }
65
+ const group = groups.get(key) ?? []
66
+ group.push(event)
67
+ groups.set(key, group)
68
+ }
69
+ const redirects = new Map<string, string>()
70
+ const affectedCards = new Set<string>()
71
+ for (const [key, group] of groups) {
72
+ if (group.length === 1 && !changed.has(group[0]!.id) && key === group[0]!.identityKey) continue
73
+ const target = group.find(event => event.identityKey === key) ?? group[0]!
74
+ const records = [...new Map(group.flatMap(event => event.records).map(record => [`${record.sourceId}\u0001${record.localId}`, record])).values()]
75
+ for (const event of group) {
76
+ if (event.id === target.id) continue
77
+ redirects.set(event.id, target.id)
78
+ for (const row of db.raw('SELECT card_id FROM card_event WHERE event_id = ?').all(event.id) as Array<{ card_id: string }>) affectedCards.add(row.card_id)
79
+ db.raw(`INSERT OR IGNORE INTO card_event(card_id, event_id, ordinal)
80
+ SELECT card_id, ?, ordinal FROM card_event WHERE event_id = ?`).run(target.id, event.id)
81
+ db.removeEvent(event.id)
82
+ }
83
+ db.writeEvent(group.length === 1 ? { ...target, identityKey: key } : eventEntityFromRecords({ ...target, identityKey: key, records }))
84
+ }
85
+ if (redirects.size) {
86
+ for (const row of db.cards()) {
87
+ let content = stripEventReferenceSection(row.card.content)
88
+ for (const [from, into] of redirects) content = content.replaceAll(from, into)
89
+ if (content === row.card.content && !affectedCards.has(row.card.entityId)) continue
90
+ const metadata = { ...row.card.metadata, event_refs: JSON.stringify(db.cardEventIds(row.card.entityId)) }
91
+ const frontmatter = { ...row.frontmatter, metadata }
92
+ tx.putCard({ ...row.card, content, metadata }, frontmatter, { actor: 'user', kind: 'named', summary: '轴合并后的 Event 引用' })
93
+ }
94
+ }
95
+ })
96
+ }
@@ -76,6 +76,12 @@ export interface FtsDocument {
76
76
  content: string
77
77
  }
78
78
 
79
+ export interface DerivedPublication {
80
+ artifacts: Map<string, string>
81
+ fts?: FtsDocument[]
82
+ vectors?: { manifest: unknown; binary: Buffer; int8: Buffer } | null
83
+ }
84
+
79
85
  export type DerivedOpenResult =
80
86
  | { ok: true; db: DerivedDb; /** 这次开库是否把旧结构整体重建了。 */ rebuilt: boolean }
81
87
  | { ok: false; code: 'NOT_A_DERIVED_DB' | 'OPEN_FAILED'; message: string }
@@ -150,19 +156,37 @@ export class DerivedDb {
150
156
  return { ok: false, code: 'OPEN_FAILED', message: `打开失败:${cause instanceof Error ? cause.message : String(cause)}` }
151
157
  }
152
158
  try {
153
- db.exec('PRAGMA journal_mode = WAL')
154
159
  const owner = readPragma(db, 'application_id')
155
160
  const version = readPragma(db, 'user_version')
156
- if (userTableCount(db) === 0) {
161
+ /**
162
+ * 属主标记为 0 = 这份文件从来没有被我们的初始化**写完过**。两种来源都要按「无主」处理:
163
+ *
164
+ * 1. 全新/空的文件(一张表都没有);
165
+ * 2. `schemaSql()` 已经建好表、`PRAGMA application_id` 还没写就被杀掉的那一次
166
+ * (崩溃、kill、磁盘满)。第二种原来会落到下面的「属主不对」分支,返回
167
+ * `NOT_A_DERIVED_DB` —— 而 `derivedHandle()` 会把这个结论缓存住,于是编译与召回
168
+ * **永久**失败,尽管这个文件按定义是可重建的。
169
+ *
170
+ * 但不能因此误伤别人的库:只有「文件里所有表都是我们自己建的」才认领重建,
171
+ * 出现陌生表就仍然拒绝打开(认错库比打不开糟)。
172
+ */
173
+ const tables = userTables(db)
174
+ const foreign = tables.filter(name => !['artifact', 'vector_index', 'fts'].includes(name))
175
+ if (owner === 0 && foreign.length === 0) {
176
+ db.exec('DROP TABLE IF EXISTS fts')
177
+ db.exec('DROP TABLE IF EXISTS artifact')
178
+ db.exec('DROP TABLE IF EXISTS vector_index')
179
+ db.exec('PRAGMA journal_mode = WAL')
157
180
  db.exec(schemaSql())
158
181
  db.exec(`PRAGMA application_id = ${DERIVED_DB_APPLICATION_ID}`)
159
182
  db.exec(`PRAGMA user_version = ${DERIVED_DB_SCHEMA}`)
160
- return { ok: true, db: new DerivedDb(db, file), rebuilt: false }
183
+ return { ok: true, db: new DerivedDb(db, file), rebuilt: tables.length > 0 }
161
184
  }
162
185
  if (owner !== DERIVED_DB_APPLICATION_ID) {
163
186
  db.close()
164
187
  return { ok: false, code: 'NOT_A_DERIVED_DB', message: `这个文件不是知识库的派生库(属主标记 ${owner}):${file}` }
165
188
  }
189
+ db.exec('PRAGMA journal_mode = WAL')
166
190
  if (version !== DERIVED_DB_SCHEMA) {
167
191
  // 整体重建。**没有迁移分支是刻意的**(见模块头)。
168
192
  db.exec('DROP TABLE IF EXISTS fts')
@@ -207,6 +231,24 @@ export class DerivedDb {
207
231
  .run(name, body, hashOf(body), Buffer.byteLength(body, 'utf8'), new Date().toISOString())
208
232
  }
209
233
 
234
+ /** Model calls finish before this short transaction starts. */
235
+ publish(publication: DerivedPublication): void {
236
+ this.db.exec('BEGIN IMMEDIATE')
237
+ try {
238
+ for (const [name, body] of publication.artifacts) this.putArtifact(name, body)
239
+ if (publication.fts !== undefined) this.rebuildFts(publication.fts)
240
+ if (publication.vectors === null) this.raw('DELETE FROM vector_index').run()
241
+ else if (publication.vectors !== undefined) {
242
+ const { manifest, binary, int8 } = publication.vectors
243
+ this.putVectorIndex(manifest, binary, int8)
244
+ }
245
+ this.db.exec('COMMIT')
246
+ } catch (cause) {
247
+ try { this.db.exec('ROLLBACK') } catch { /* preserve the original failure */ }
248
+ throw cause
249
+ }
250
+ }
251
+
210
252
  removeArtifact(name: string): void {
211
253
  this.raw('DELETE FROM artifact WHERE name = ?').run(name)
212
254
  }
@@ -239,14 +281,14 @@ export class DerivedDb {
239
281
  */
240
282
  rebuildFts(documents: FtsDocument[]): void {
241
283
  /*
242
- * `BEGIN` 在 DDL **之前**:SQLite 的 DDL 是事务性的(实测 `CREATE VIRTUAL TABLE` 与它
284
+ * `SAVEPOINT` 在 DDL **之前**:SQLite 的 DDL 是事务性的(实测 `CREATE VIRTUAL TABLE` 与它
243
285
  * 的 shadow 表一起回滚),而放在事务外就变成自动提交 —— 于是构建中途失败会留下一张
244
286
  * **空的** `fts` 表,`hasFts()` 还说它在,查询却一条也回不来。
245
287
  *
246
288
  * 放进同一个事务之后的实际行为:**上一版索引原样留着**(还能查),或者(本来就还没有
247
289
  * 索引时)仍然没有索引。两种都比「空表」好 —— 空表是一种既不报错也不可用的状态。
248
290
  */
249
- this.db.exec('BEGIN')
291
+ this.db.exec('SAVEPOINT rebuild_fts')
250
292
  try {
251
293
  this.db.exec('DROP TABLE IF EXISTS fts')
252
294
  this.db.exec(ftsSql())
@@ -256,9 +298,9 @@ export class DerivedDb {
256
298
  const tokens = [...segment(document.title), ...segment(document.title), ...segment(document.content)]
257
299
  insert.run(document.unitId, tokens.join(' '))
258
300
  }
259
- this.db.exec('COMMIT')
301
+ this.db.exec('RELEASE rebuild_fts')
260
302
  } catch (cause) {
261
- try { this.db.exec('ROLLBACK') } catch { /* rollback of a dead tx */ }
303
+ try { this.db.exec('ROLLBACK TO rebuild_fts; RELEASE rebuild_fts') } catch { /* rollback of a dead tx */ }
262
304
  throw cause
263
305
  }
264
306
  // `optimize` 在事务外:它是一次纯内部整理,失败不该把已经建好的索引回滚掉。
@@ -277,11 +319,19 @@ export class DerivedDb {
277
319
  * 查询语法错误或索引损坏时**返回空数组而不抛**:关键词路是三条召回路线之一,
278
320
  * 它挂了不该把整次召回带走 —— 调用方在诊断里如实说明这一路没结果。
279
321
  */
280
- searchFts(query: string, limit: number): FtsHit[] {
322
+ searchFts(query: string, limit: number, eligible?: ReadonlySet<string>): FtsHit[] {
281
323
  const expression = matchExpression(query)
282
324
  if (expression === null || !this.hasFts()) return []
283
325
  try {
284
- const rows = this.raw('SELECT unit_id, bm25(fts) AS rank FROM fts WHERE fts MATCH ? ORDER BY rank LIMIT ?').all(expression, limit) as Array<{ unit_id?: unknown; rank?: unknown }>
326
+ /*
327
+ * `eligible` 必须进 SQL。先 LIMIT 再在 JS 里过滤,会让已删除/停用卡片的死
328
+ * unitId 占满候选窗口(索引只在编译时重建,删除不会立刻反映到 fts 表)。
329
+ * 用 `json_each` 传一个 JSON 数组而不是拼参数列表:一个绑定参数,不受
330
+ * SQLITE_MAX_VARIABLE_NUMBER 限制。
331
+ */
332
+ const rows = (eligible === undefined
333
+ ? this.raw('SELECT unit_id, bm25(fts) AS rank FROM fts WHERE fts MATCH ? ORDER BY rank LIMIT ?').all(expression, limit)
334
+ : this.raw('SELECT unit_id, bm25(fts) AS rank FROM fts WHERE fts MATCH ? AND unit_id IN (SELECT value FROM json_each(?)) ORDER BY rank LIMIT ?').all(expression, JSON.stringify([...eligible]), limit)) as Array<{ unit_id?: unknown; rank?: unknown }>
285
335
  const parsed = rows
286
336
  .map(row => ({ unitId: String(row.unit_id ?? ''), raw: Number(row.rank ?? 0) }))
287
337
  .filter(row => row.unitId !== '' && Number.isFinite(row.raw))
@@ -291,6 +341,14 @@ export class DerivedDb {
291
341
  const scale = best > 0 ? best : 1
292
342
  return parsed.map(row => ({ ...row, score: Math.max(0, Math.min(1, -row.raw / scale)) }))
293
343
  } catch {
344
+ /**
345
+ * `json_each` 不可用(SQLite 没编 JSON)或索引损坏时,**不能直接返回空**。
346
+ *
347
+ * 空数组会被上游读成「这一路没命中」,而实际是「这一路坏了」—— 正是这次要消灭的
348
+ * 那种静默降级。退回不带资格过滤的两参数查询:结果仍然正确(调用方还会过滤一遍),
349
+ * 只是候选窗口可能被已删除的条目占掉。真的连那条也失败,才认「没有结果」。
350
+ */
351
+ if (eligible !== undefined) return this.searchFts(query, limit)
294
352
  return []
295
353
  }
296
354
  }
@@ -310,7 +368,7 @@ function readPragma(db: SqliteDatabase, name: string): number {
310
368
  return typeof first === 'number' ? first : Number(first ?? 0)
311
369
  }
312
370
 
313
- function userTableCount(db: SqliteDatabase): number {
314
- const rows = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all() as Array<{ name?: unknown }>
315
- return rows.length
371
+ /** 文件里现有的表名。用来判断「这份文件是不是我们建的」。 */
372
+ function userTables(db: SqliteDatabase): string[] {
373
+ return (db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").all() as Array<{ name?: unknown }>).map(row => String(row.name ?? ''))
316
374
  }