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
@@ -247,8 +247,8 @@ export function validateDiagnosis(graph: AttributionGraphData): DiagnosisIssue[]
247
247
  if (!node.verdict) issues.push(fieldIssue(node, 'verdict', '证据必须给出结论:supports / refutes / inconclusive'))
248
248
  if (!node.why?.trim()) issues.push(fieldIssue(node, 'why', '证据必须说明「为什么这个结果算数或不算数」—— 采信与剔除都得能说理由'))
249
249
  }
250
- // `case` 节点只是图上的桩:案例的正文与路径住在案例卡片里,由
251
- // DiagnosisSnapshot.cases 校验,不在节点上重复要求。
250
+ // `case` 节点只是兼容旧图的桩;当前排查视图由 SourceRaw 记录派生,
251
+ // 新排查不会再写 diagnosis/case WikiCard。
252
252
  }
253
253
 
254
254
  // ── 第二层:引用完整性 ────────────────────────────────────────────────────
@@ -6,11 +6,12 @@
6
6
  * 所以 seed 也走完整条动线:
7
7
  *
8
8
  * ```
9
- * 这些文本(SourceRaw) → 五类卡片 → 编译 → 图
9
+ * 原文(SourceRaw) → 抽取 Knowledge / Event → 归一
10
+ * 排查运行记录(SourceRaw) → 只读 Case 视图
10
11
  * ```
11
12
  *
12
- * 手册与复盘是**人写的散文**(就是下面这些字面量),卡片是从它们编译出来的结构化提取。
13
- * 两者内容会有重叠 —— 那是正常的:卡片是散文的投影,不是它的替代品。
13
+ * 手册与复盘是**人写的散文**(就是下面这些字面量)。载入示例只保存来源与可复用诊断卡;
14
+ * Case 从独立的排查运行记录派生,不生成第二张诊断卡。
14
15
  */
15
16
  import { SEED_CASES, SEED_RUNS } from './seed.js'
16
17
  import { renderRunSource } from './run.js'
@@ -83,7 +84,7 @@ export const SEED_HANDBOOK = `# 日报指标异常排查手册(内部版)
83
84
  同一批假设被反复验证,而永远不会被剪掉 —— 图上会长出一堆僵尸边。
84
85
  `
85
86
 
86
- /** 三篇复盘:案例卡片的出处。正文就是案例的散文段(现象 / 影响面 / 排查过程 / 根因 / 修复)。 */
87
+ /** 三篇复盘:供后续抽取 Knowledge / Event 的来源文档。 */
87
88
  export function seedCaseSources(): SeedSource[] {
88
89
  return SEED_CASES.map(item => ({
89
90
  id: item.id,
@@ -19,7 +19,7 @@ import type { AttributionCase, AttributionGraphData, DiagnosisRunRecord } from '
19
19
  * | `question` | 人 | 手册与复盘 —— 卡片 `source_refs` 指向这里 |
20
20
  * | `agent_diagnosis_case` | Agent | 一次排查的过程记录(`SEED_RUNS`) |
21
21
  *
22
- * `SEED_GRAPH` 里**只有卡片定义得了的东西**:类型层、引用层资产、案例桩,以及六种卡片边。
22
+ * `SEED_GRAPH` 里有可复用诊断 Knowledge 与引用层资产;历史案例桩只用于旧格式兼容夹具。
23
23
  * `evidence` / `cause` 与四条执行边由 `SEED_RUNS` 读时解析出来 —— 把「上次查到什么」
24
24
  * 写进卡片,等于让一份可复用的知识绑死在一次执行上。
25
25
  */
@@ -122,10 +122,8 @@ export const SEED_GRAPH: AttributionGraphData = {
122
122
  { id: 'metric_daily_gmv', kind: 'asset', layer: 'reference', title: 'metric_daily_gmv', assetType: 'metric' },
123
123
  { id: 'bi_daily_dashboard', kind: 'asset', layer: 'reference', title: 'bi_daily_dashboard', assetType: 'linkage' },
124
124
 
125
- // ── 实例层:案例节点是**图上的桩**(正文与有序路径住在案例卡片里) ──────
126
- // 标题必须与 `SEED_CASES[].title` 是同一个字符串,否则同一份知识会有两份标题
127
- // (而且还真的不一致过:「只剩」vs「只有」)。画布要在标签前显示案例 id,
128
- // 那是渲染层的事(见 `nodeStyleFor` 的 labelText)。
125
+ // ── 兼容层:旧格式里的案例节点桩。新样例的排查记录由 SEED_RUNS 派生为只读视图。 ──
126
+ // 保留稳定 ID,供旧卡片编解码与历史图迁移夹具使用。
129
127
  { id: 'CASE-001', kind: 'case', layer: 'instance', title: '日报 GMV 为 0' },
130
128
  { id: 'CASE-002', kind: 'case', layer: 'instance', title: '订单数只有昨日 12%' },
131
129
  { id: 'CASE-003', kind: 'case', layer: 'instance', title: 'DAU 突增 3.1 倍' },
@@ -197,7 +195,7 @@ export const SEED_GRAPH: AttributionGraphData = {
197
195
  ],
198
196
  }
199
197
 
200
- /** 三个 seed 案例卡片,与上面图谱里的节点 id 对齐(0021 §11)。 */
198
+ /** 旧版示例 Case 投影夹具;仅供历史卡片编解码与来源文案使用,当前载入流程不落盘。 */
201
199
  export const SEED_CASES: AttributionCase[] = [
202
200
  {
203
201
  id: 'CASE-001',
@@ -280,8 +278,8 @@ export const SEED_CASES: AttributionCase[] = [
280
278
  * 三次排查的**过程记录**(`agent_diagnosis_case`)。
281
279
  *
282
280
  * 它们与 `SEED_CASES` 一一对应,但**不是同一份东西**:这里是 Agent 跑出来的原始记录
283
- * (每条检查点真跑了什么、看到什么、这个结果算不算数),`SEED_CASES` 是之后归纳出来的
284
- * 案例卡片(要经人确认才生效)。一个回答「当时怎么走的」,一个回答「结论是什么」。
281
+ * (每条检查点真跑了什么、看到什么、这个结果算不算数);当前 Case 视图从运行记录派生,
282
+ * `SEED_CASES` 仅保留作旧卡片格式夹具。
285
283
  *
286
284
  * `E7` 是 CASE-001 里那次**贵的否定**:T7.2 直连明细对账推翻了 H7。它不在案例的
287
285
  * 主路径上(主路径早就确认了 H1),但它是这次排查最贵的一条知识 —— 40 分钟的误导段
@@ -7,9 +7,9 @@ import {
7
7
  cardFromRecord, cardsToGraph, CARD_EDGE_KINDS, graphToCards, parseCard, serializeCard,
8
8
  RUN_EDGE_KINDS, type DiagnosisCard,
9
9
  } from './cards.js'
10
- import { caseCardOf, parseRunSource, renderRunSource, runReferenceProblems, runToGraph } from './run.js'
10
+ import { caseViewOfRun, parseRunSource, renderRunSource, runReferenceProblems, runToGraph } from './run.js'
11
11
  import type {
12
- AttributionCase, AttributionEdge, AttributionGraphData, AttributionNode, AttributionNodeKind, DiagnosisRunRecord,
12
+ AttributionCase, AttributionEdge, AttributionEvent, AttributionGraphData, AttributionNode, AttributionNodeKind, DiagnosisRunRecord,
13
13
  } from './types.js'
14
14
  import type { KnowledgeRuntime } from '../runtime.js'
15
15
  import type { SchemaType } from '../types.js'
@@ -22,7 +22,7 @@ import type { SchemaType } from '../types.js'
22
22
  * | 目录 | 内容 | 谁是真相 |
23
23
  * | --- | --- | --- |
24
24
  * | `01_source_raw/` | 手册、复盘与排查原文 | SourceRaw 的唯一真相 |
25
- * | `02_wiki/diagnosis/` | 五类卡片(三段式) | **知识侧的唯一真相**,由一次排查 / 载入示例 / 迁移直接写入(0044 起不经人确认) |
25
+ * | `02_wiki/diagnosis/` | 历史诊断卡片 | 仅为旧数据兼容读取;新排查不再写 diagnosis/case 卡片 |
26
26
  *
27
27
  * `05_diagnosis/` 在 v1.1 撤销了(0021 §0.3)。它同时装着两类东西 —— 「一次排查的产物」
28
28
  * (源头)与「五类模板卡」(配置)—— 一个编号段混装两种性质,`rebuild --only` 的语义
@@ -58,12 +58,13 @@ const LEGACY_RUN_SHARDS: Record<string, AttributionNodeKind> = {
58
58
  'causes.jsonl': 'cause',
59
59
  }
60
60
 
61
- /** 读取顺序的显式来源,界面据此说明「现在看到的是哪一份」。 */
62
- export type DiagnosisSource = 'cards' | 'jsonl' | 'empty'
61
+ /** 读取来源,界面据此说明当前展示的是卡片、记录、旧快照还是空库。 */
62
+ export type DiagnosisSource = 'cards' | 'records' | 'jsonl' | 'empty'
63
63
 
64
64
  export interface DiagnosisSnapshot {
65
65
  graph: AttributionGraphData
66
66
  cases: AttributionCase[]
67
+ events: AttributionEvent[]
67
68
  issues: DiagnosisIssue[]
68
69
  /** 数据是不是本次调用从内置示例写进去的(只有 `loadSample()` 会把它变成 true)。 */
69
70
  seeded: boolean
@@ -86,7 +87,7 @@ export interface DiagnosisSnapshot {
86
87
  * `loadSources` 是 v1.1 新增的:一次排查的产物现在是一条 `agent_diagnosis_case`
87
88
  * 的 SourceRaw,归因图读的是它,而不是自造的 jsonl。
88
89
  */
89
- type DiagnosisHost = Pick<KnowledgeRuntime, 'rootDir' | 'addSource' | 'writeCard' | 'loadSources' | 'loadCards' | 'readCard'>
90
+ type DiagnosisHost = Pick<KnowledgeRuntime, 'rootDir' | 'addSource' | 'writeCard' | 'loadSources' | 'loadCards' | 'loadEvents' | 'readCard' | 'knowledgeStoreAvailable'>
90
91
 
91
92
  export class DiagnosisStore {
92
93
  constructor(private readonly host: DiagnosisHost) {}
@@ -112,65 +113,111 @@ export class DiagnosisStore {
112
113
  * 造出「设置里改了、磁盘上那份没改」的第二真源。
113
114
  */
114
115
  async ensure(): Promise<{ seeded: boolean; migrated: boolean; problems: string[] }> {
116
+ /**
117
+ * **「读不到」不等于「空」**(0070)。
118
+ *
119
+ * `readCards()` 在存储不可用时返回空数组,于是「node:sqlite 连不上 / 属主标记不符 /
120
+ * 权限不对」会被读成「这个库什么都还没有」,接着走下面的旧格式迁移 —— 那是一次
121
+ * **写**(会写入内置种子来源与几十张卡)。一次可恢复的读故障就这样变成不可逆的污染。
122
+ * 所以先问一句存储到底在不在,不在就什么都不做,并如实报出来。
123
+ */
124
+ if (!await this.host.knowledgeStoreAvailable()) {
125
+ return { seeded: false, migrated: false, problems: ['知识存储当前不可用,已跳过内置示例与旧格式迁移;请先解决存储问题再打开本页。'] }
126
+ }
115
127
  if ((await this.readCards()).length > 0) return { seeded: false, migrated: false, problems: [] }
116
128
  if ((await this.legacyShardFiles()).length > 0) return await this.migrate()
117
129
  return { seeded: false, migrated: false, problems: [] }
118
130
  }
119
131
 
120
132
  /**
121
- * 载入**内置示例**:一份排查手册 + 三篇复盘 + 三次排查日志 → SourceRaw → 卡片 → 图。
133
+ * 载入**内置示例**:一份排查手册 + 三篇复盘 + 三次排查日志 → SourceRaw、可复用诊断卡与只读排查视图。
122
134
  *
123
135
  * 只有用户明确点了「载入内置示例」才走这里(`ensure()` 不再自动调用)。幂等:
124
136
  * `addSource` 按 `externalId`、`writeCard` 按 entityId,点两次不会写出第二份。
125
137
  *
126
- * **它走的是「提议 → 确认」那条门,不是绕过它**(0021 §6.1)。区别只在确认者是谁:
127
- * 用户点「载入内置示例」这个动作本身就是**对整批示例的确认**,所以这里给每条提议记下
128
- * `confirmedBy = user:load-sample`,然后照常走 `writeCard`。这样做的两个好处:
129
- * 待办区里能看到这批卡片是怎么来的;而「未确认不落 `02_wiki/`」这条规则没有被开一个
130
- * 后门 —— 例外是**确认者的身份**,不是门的缺失。
138
+ * 示例里的可复用诊断 Knowledge 是预先整理好的演示数据,直接写入当前知识库。
139
+ * 三条排查记录作为 SourceRaw 写入,并由读取层派生只读 Case 视图;不创建 `diagnosis/case` WikiCard。
131
140
  */
132
141
  async loadSample(): Promise<{ seeded: boolean; migrated: boolean; problems: string[] }> {
142
+ /**
143
+ * 载入示例是一次**写**,所以门要在服务端,不能只在界面上。
144
+ *
145
+ * `canLoadSample` 原来只出现在 `snapshot()` 的返回值里,用来决定那枚按钮显不显示 ——
146
+ * 而 `POST /diagnosis/sample` 直接调这里。任何非界面的调用方(脚本、旧标签页、
147
+ * 以后的 runbook)打一次,就能在一个已经有真实知识的库上注入一整套演示数据,
148
+ * 库里于是有两份互相矛盾的知识,而这正是本文件开头要防的事。
149
+ *
150
+ * **不给覆盖开关**:曾经加过一个 `force`,但它没有任何调用方(路由按无参调用),
151
+ * 而且「往有真实知识的库里再塞一套演示」本来就不该是一个可选项 —— 那正是这条门要防的。
152
+ */
153
+ const allowed = await this.sampleAllowed()
154
+ if (!allowed.ok) {
155
+ return { seeded: false, migrated: false, problems: [`这个知识库里已经有内容(${allowed.reason}),不再载入内置示例。`] }
156
+ }
133
157
  const { problems: sourceProblems, refs } = await this.writeSources(seedSources())
134
- const cards = withSourceRefs(graphToCards(SEED_GRAPH, SEED_CASES), refs, SEED_CASES)
158
+ const cards = withSourceRefs(
159
+ graphToCards(SEED_GRAPH),
160
+ refs,
161
+ SEED_CASES,
162
+ )
135
163
  const problems = [...sourceProblems, ...await this.writeCards(cards, 'user:load-sample')]
136
164
  return { seeded: true, migrated: false, problems }
137
165
  }
138
166
 
167
+ /** Read Event entities for the Knowledge & Event view without building the diagnosis graph. */
168
+ async listEvents(): Promise<AttributionEvent[]> {
169
+ return this.readEvents()
170
+ }
171
+
172
+ /**
173
+ * 「能不能载入内置示例」的**唯一**判据 —— 只看四个计数。
174
+ *
175
+ * 抽出来是因为它有两个消费者(`snapshot()` 的 `canLoadSample` 与 `loadSample()` 的门),
176
+ * 各写一份的话,界面说「可以」而服务端说「不行」只是时间问题。判据与**读取**分开:
177
+ * 两边各自的读取是必要的(一个已经拿到了卡片/Event,一个还没读),规则不必要各写一遍。
178
+ */
179
+ private static sampleGate(state: { cards: number; events: number; runs: number; shards: number }): { ok: boolean; reason?: string } {
180
+ if (state.cards > 0) return { ok: false, reason: '已经有卡片' }
181
+ if (state.events > 0) return { ok: false, reason: '已经有 Event' }
182
+ if (state.runs > 0) return { ok: false, reason: '已经有排查记录' }
183
+ if (state.shards > 0) return { ok: false, reason: '还有旧格式的 05_diagnosis 分片等待迁移' }
184
+ return { ok: true }
185
+ }
186
+
187
+ private async sampleAllowed(): Promise<{ ok: boolean; reason?: string }> {
188
+ return DiagnosisStore.sampleGate({
189
+ cards: (await this.readCards()).length,
190
+ events: (await this.readEvents()).length,
191
+ runs: (await this.readRuns()).records.length,
192
+ shards: (await this.legacyShardFiles()).length,
193
+ })
194
+ }
195
+
139
196
  async snapshot(): Promise<DiagnosisSnapshot> {
140
197
  const { seeded, migrated, problems } = await this.ensure()
141
198
  const cards = await this.readCards()
199
+ const events = await this.readEvents()
200
+ const baseGraph = cards.length > 0 ? { nodes: [], edges: [] } : await this.readLegacyGraph()
201
+ const baseCases = cards.length > 0 ? [] : await this.readLegacyCases()
202
+ const built = await this.buildGraph(cards, baseGraph, baseCases)
203
+ const runRecords = (await this.readRuns()).records
142
204
  /**
143
- * 「什么都没有」= 没有卡片、也没有旧 jsonl。它是**可以载入内置示例**的唯一条件:
205
+ * 「什么都没有」= 没有卡片、Event、排查日志和旧 jsonl。它是**可以载入内置示例**的唯一条件:
144
206
  * 已经有知识(不管哪一代形态)时不该再往里塞示例 —— 那会变成第二份互相矛盾的知识。
145
207
  */
146
- const canLoadSample = cards.length === 0 && (await this.legacyShardFiles()).length === 0
147
-
148
- if (cards.length > 0) {
149
- const built = await this.buildGraph(cards)
150
- return {
151
- graph: built.graph,
152
- cases: built.cases,
153
- issues: validateDiagnosis(built.graph),
154
- seeded,
155
- migrated,
156
- source: 'cards',
157
- canLoadSample: false,
158
- problems: [...problems, ...built.problems],
159
- }
160
- }
161
-
162
- // 还没有卡片:旧 jsonl 就是当前可读的来源;两份都没有就是一个空库。
163
- const graph = await this.readLegacyGraph()
164
- const cases = await this.readLegacyCases()
208
+ const canLoadSample = DiagnosisStore.sampleGate({
209
+ cards: cards.length, events: events.length, runs: runRecords.length, shards: (await this.legacyShardFiles()).length,
210
+ }).ok
165
211
  return {
166
- graph,
167
- cases,
168
- issues: validateDiagnosis(graph),
212
+ graph: built.graph,
213
+ cases: built.cases,
214
+ events,
215
+ issues: validateDiagnosis(built.graph),
169
216
  seeded,
170
217
  migrated,
171
- source: canLoadSample ? 'empty' : 'jsonl',
218
+ source: canLoadSample ? 'empty' : cards.length > 0 ? 'cards' : events.length > 0 || runRecords.length > 0 ? 'records' : 'jsonl',
172
219
  canLoadSample,
173
- problems,
220
+ problems: [...problems, ...built.problems],
174
221
  }
175
222
  }
176
223
 
@@ -181,21 +228,27 @@ export class DiagnosisStore {
181
228
  * 与四条执行边全部来自 `agent_diagnosis_case` 的 SourceRaw。合成一张图是**读**的时候
182
229
  * 做的,不是写的时候 —— 写的时候合成,等于让一次执行的结果变成可复用的知识。
183
230
  */
184
- private async buildGraph(cards: DiagnosisCard[]): Promise<{ graph: AttributionGraphData; cases: AttributionCase[]; problems: string[] }> {
231
+ private async buildGraph(cards: DiagnosisCard[], baseGraph: AttributionGraphData = { nodes: [], edges: [] }, baseCases: AttributionCase[] = []): Promise<{ graph: AttributionGraphData; cases: AttributionCase[]; problems: string[] }> {
185
232
  const compiled = cardsToGraph(cards)
186
233
  const problems = [...compiled.problems]
187
- const nodes: AttributionNode[] = [...compiled.graph.nodes]
188
- const edges: AttributionEdge[] = [...compiled.graph.edges]
234
+ const nodes: AttributionNode[] = [...baseGraph.nodes, ...compiled.graph.nodes]
235
+ const edges: AttributionEdge[] = [...baseGraph.edges, ...compiled.graph.edges]
236
+ const knownCardNodes = [...baseGraph.nodes, ...compiled.graph.nodes]
237
+ const cases = new Map<string, AttributionCase>()
238
+ for (const item of [...baseCases, ...compiled.cases]) cases.set(item.id, item)
189
239
 
190
240
  const runs = await this.readRuns()
191
241
  problems.push(...runs.problems)
192
242
  for (const record of runs.records) {
193
243
  const run = runToGraph(record)
194
244
  // 引用完整性要**连这次排查自己产出的 id 一起算**:路径里的 `E1` / `C1` 正是它写下的。
195
- const known = new Set([...compiled.graph.nodes.map(node => node.id), ...run.nodes.map(node => node.id)])
245
+ const known = new Set([...knownCardNodes.map(node => node.id), ...run.nodes.map(node => node.id)])
196
246
  problems.push(...run.problems, ...runReferenceProblems(record, known))
197
247
  nodes.push(...run.nodes)
198
248
  edges.push(...run.edges)
249
+ const symptomTitle = knownCardNodes.find(node => node.id === record.symptomId)?.title ?? record.symptomId
250
+ const view = caseViewOfRun(record, symptomTitle)
251
+ cases.set(view.id, view)
199
252
  }
200
253
 
201
254
  /**
@@ -210,7 +263,7 @@ export class DiagnosisStore {
210
263
  nodes.push(...legacyRun.nodes)
211
264
  edges.push(...legacyRun.edges)
212
265
 
213
- return { graph: dedupe({ nodes, edges }, problems), cases: compiled.cases, problems }
266
+ return { graph: dedupe({ nodes, edges }, problems), cases: [...cases.values()], problems }
214
267
  }
215
268
 
216
269
  /**
@@ -238,14 +291,15 @@ export class DiagnosisStore {
238
291
 
239
292
  async readGraph(): Promise<AttributionGraphData> {
240
293
  const cards = await this.readCards()
241
- if (cards.length > 0) return (await this.buildGraph(cards)).graph
242
- return await this.readLegacyGraph()
294
+ const baseGraph = cards.length > 0 ? { nodes: [], edges: [] } : await this.readLegacyGraph()
295
+ return (await this.buildGraph(cards, baseGraph)).graph
243
296
  }
244
297
 
245
298
  async readCases(): Promise<AttributionCase[]> {
246
299
  const cards = await this.readCards()
247
- if (cards.length > 0) return cardsToGraph(cards).cases
248
- return await this.readLegacyCases()
300
+ const baseGraph = cards.length > 0 ? { nodes: [], edges: [] } : await this.readLegacyGraph()
301
+ const baseCases = cards.length > 0 ? [] : await this.readLegacyCases()
302
+ return (await this.buildGraph(cards, baseGraph, baseCases)).cases
249
303
  }
250
304
 
251
305
  /* ────────────────────────────────────────────── 卡片:读写 ── */
@@ -267,6 +321,35 @@ export class DiagnosisStore {
267
321
  return cards
268
322
  }
269
323
 
324
+ /** Event 与 Knowledge 同层,读取独立的 event 实体表。 */
325
+ private async readEvents(): Promise<AttributionEvent[]> {
326
+ const events = await this.host.loadEvents()
327
+ return events.map(event => ({
328
+ id: event.id,
329
+ title: event.title,
330
+ summary: event.summary,
331
+ identityType: event.identityType,
332
+ ...(event.externalId ? { externalId: event.externalId } : {}),
333
+ ...(event.occurredAt ? { occurredAt: event.occurredAt } : {}),
334
+ ...(event.symptom ? { symptom: event.symptom } : {}),
335
+ coordinate: event.coordinate,
336
+ timeline: event.timeline.map((step, index) => ({
337
+ id: step.id || `timeline-${index + 1}`,
338
+ type: step.type,
339
+ description: step.description,
340
+ ...(step.result ? { result: step.result } : {}),
341
+ ...(step.at ? { at: step.at } : {}),
342
+ sourceId: step.sourceId,
343
+ })),
344
+ rootCauses: event.rootCauses,
345
+ outcomes: event.outcomes,
346
+ missing: event.missing,
347
+ sources: event.sources.filter(source => source.found && source.documentId && source.quote)
348
+ .map(source => ({ documentId: source.documentId, quote: source.quote })),
349
+ recordCount: event.records.length,
350
+ })).sort((left, right) => (right.occurredAt ?? '').localeCompare(left.occurredAt ?? '') || left.title.localeCompare(right.title))
351
+ }
352
+
270
353
  /* ────────────────────────────────────────────── 一次排查的记录 ── */
271
354
 
272
355
  /**
@@ -279,6 +362,7 @@ export class DiagnosisStore {
279
362
  const records: DiagnosisRunRecord[] = []
280
363
  const problems: string[] = []
281
364
  for (const source of await this.host.loadSources()) {
365
+ if (!source.sourceId.startsWith('diagnosis:') && !source.content.includes('```json diagnosis-run')) continue
282
366
  const record = parseRunSource(source.content)
283
367
  if (record) records.push(record)
284
368
  else problems.push(`诊断日志 ${source.sourceId} 里没有可解析的 \`json diagnosis-run\` 块,已跳过`)
@@ -287,15 +371,11 @@ export class DiagnosisStore {
287
371
  }
288
372
 
289
373
  /**
290
- * 一次排查结束:写一条 SourceRaw,并**直接写入**一张案例卡片。
291
- *
292
- * 0044:案例卡片原来只提议、等人确认。与编译那条链路一样改成直接入库 ——
293
- * 一次排查的价值就在于「当时是怎么走的」,让它停在待办队列里等于把经验丢掉。
294
- * 卡片会被标成 `unreviewed`,人在「知识库 → Wiki」里 review 它。
295
- *
296
- * 幂等:`externalId` = runId,同一次排查重跑不会写出第二条来源;卡片按 entityId 写入。
374
+ * 一次排查结束只写一条 SourceRaw。案例视图从这条记录派生;Knowledge / Event 的抽取与归一
375
+ * 仍由知识处理阶段执行,避免把同一份排查过程再写成另一张 WikiCard。
376
+ * 幂等:`externalId` = runId,同一次排查重跑不会写出第二条来源。
297
377
  */
298
- async recordRun(record: DiagnosisRunRecord): Promise<{ sourceId?: string; entityId?: string; problems: string[] }> {
378
+ async recordRun(record: DiagnosisRunRecord): Promise<{ sourceId?: string; problems: string[] }> {
299
379
  const problems: string[] = []
300
380
  const added = await this.host.addSource({
301
381
  title: `AI 诊断日志 · ${record.symptomId} · ${record.runId}`,
@@ -306,18 +386,7 @@ export class DiagnosisStore {
306
386
  if (added.ok === false) return { problems: [`诊断日志 ${record.runId} 写入失败:${added.error.code} ${added.error.message}`] }
307
387
  const sourceId = added.data.sourceId
308
388
 
309
- const symptomTitle = (await this.readCards()).find(card => card.entityId === record.symptomId)?.title ?? record.symptomId
310
- const draft = caseCardOf(record, symptomTitle)
311
- const written = await this.host.writeCard({
312
- entityType: draft.entityType as SchemaType,
313
- entityId: draft.entityId,
314
- title: draft.title,
315
- content: renderCardBody(draft),
316
- sourceRefs: [sourceId],
317
- status: 'unreviewed',
318
- })
319
- if (written.ok === false) problems.push(`案例卡片 ${draft.entityId} 写入失败:${written.error.code} ${written.error.message}`)
320
- return { sourceId, ...(written.ok === false ? {} : { entityId: draft.entityId }), problems }
389
+ return { sourceId, problems }
321
390
  }
322
391
 
323
392
  /* ────────────────────────────────────────────── 旧知识根迁移 ── */
@@ -460,8 +529,8 @@ export function renderCardBody(card: DiagnosisCard): string {
460
529
  /**
461
530
  * 给卡片挂出处。
462
531
  *
463
- * 规则是**数据驱动的**,不是凭印象分的:案例卡片与它自己的复盘原文一一对应;
464
- * 其它卡片取「第一篇走过它的复盘」,没有走过它的就挂那本手册。
532
+ * 规则是**数据驱动的**,不是凭印象分的:可复用诊断卡优先引用第一篇走过该节点的复盘;
533
+ * 没有经过复盘的节点引用手册。历史 Case 卡仍由旧数据读取,不在新示例里生成。
465
534
  */
466
535
  function withSourceRefs(
467
536
  cards: DiagnosisCard[],
@@ -15,7 +15,8 @@ import type { ProblemClassId } from './problem-classes.js'
15
15
  export type NodeLayer = 'type' | 'reference' | 'instance'
16
16
 
17
17
  /**
18
- * 九类归因节点。与 wiki 卡片的 `entity_type` 一一对应(`asset` 与三类执行产物除外)。
18
+ * 九类归因图节点。当前 Knowledge 节点可对应 WikiCard;`case` 是排查记录视图,
19
+ * `asset` 与执行产物也不对应 WikiCard。历史 Case WikiCard 仅为兼容数据。
19
20
  *
20
21
  * **两个名字用的是下划线**(`check_point` / `failure_reason`),卡片类型用连字符
21
22
  * (`diagnosis/check-point` / `diagnosis/failure-reason`):kind 是代码里的标识符,
@@ -187,18 +188,9 @@ export interface AttributionGraphData {
187
188
  }
188
189
 
189
190
  /**
190
- * 案例 = **一篇 wiki 定义 + 一条有序排查路径**。
191
- *
192
- * 它住在领域层而不是示例里(原来是 `seed.ts`):案例是编译产物的一种
193
- * (`cardsToGraph()` 从卡片把它算出来,`/diagnosis/graph` 把它发给界面),
194
- * 而示例只是**一份**案例的取值来源。视图要渲染「服务端给的案例」,
195
- * 那它 import 的形状就不该从示例模块里拿。
196
- *
197
- * 两段各有明确消费者,不能合并:
198
- * - `sections` 是给人读、给向量召回的散文(可 diff、可评审、可追溯);
199
- * - `path` 是给图和剪枝用的结构(有序、可判真假、带被否定的分支)。
200
- *
201
- * 序和枚举一旦写进散文,归并算法就再也读不到它们了 —— 所以路径单独成段。
191
+ * Case 是一次排查记录的只读展示投影,不是持久化实体。
192
+ * `sections` 供人阅读,`path` 保留检查顺序与被否定的分支;来源是 SourceRaw 运行记录。
193
+ * 历史 `diagnosis/case` WikiCard 仍可读取,但新的运行与示例载入不再生成它。
202
194
  */
203
195
  export interface CaseSection {
204
196
  heading: string
@@ -223,6 +215,33 @@ export interface AttributionCase {
223
215
  /** 误导段:最贵的那条知识。没有它,下次还会有人在同一个假设上烧掉四十分钟。 */
224
216
  misleading?: { nodeId: string; label: string; wastedMinutes: number; why: string }
225
217
  rootCause: string
218
+ /** 排查记录里的根因确认状态;旧案例卡片缺省时按已有内容展示。 */
219
+ rootCauseStatus?: 'confirmed' | 'unconfirmed'
220
+ }
221
+
222
+ /** 从独立 Event 实体读取的一次具体发生,供智能归因的事件视图展示。 */
223
+ export interface AttributionEvent {
224
+ id: string
225
+ title: string
226
+ summary: string
227
+ identityType: 'external_id' | 'composite' | 'source'
228
+ externalId?: string
229
+ occurredAt?: string
230
+ symptom?: string
231
+ coordinate: { object: string | null; action: string | null; scene: string | null }
232
+ timeline: Array<{
233
+ id: string
234
+ type: string
235
+ description: string
236
+ result?: string
237
+ at?: string
238
+ sourceId: string
239
+ }>
240
+ rootCauses: Array<{ text: string; status: 'confirmed' | 'suspected' | null; sourceId: string }>
241
+ outcomes: Array<{ text: string; sourceId: string }>
242
+ missing: string[]
243
+ sources: Array<{ documentId: string; quote: string }>
244
+ recordCount: number
226
245
  }
227
246
 
228
247
  export interface AttributionStats {
@@ -298,8 +317,8 @@ export interface DiagnosisRunCause {
298
317
  /**
299
318
  * 一次排查的完整记录。落到 SourceRaw 正文里的 ```json diagnosis-run 块。
300
319
  *
301
- * 它与案例卡片的区别是**谁写的、有没有被归纳过**:这里是 Agent 跑完一圈留下的
302
- * 原始记录,案例卡片是**之后**归纳出来的知识(而且必须经人确认才生效)。
320
+ * 它是 Agent 跑完一圈留下的原始记录。Case 视图从这条记录派生;可复用 Knowledge 与 Event
321
+ * 由独立抽取和归一阶段生成,不在这条记录写成第二张卡片。
303
322
  */
304
323
  export interface DiagnosisRunRecord {
305
324
  /** 本次排查的 runId。同时用作 SourceRaw 的 `externalId`,重跑不产生第二条记录。 */
@@ -0,0 +1,156 @@
1
+ /**
2
+ * DSH 自带 Python 的落点(2026-10-18)。
3
+ *
4
+ * 桌面端把 Python 3.12 **打在自己的运行时里**:
5
+ * `<App>/Contents/Resources/runtime/primary-runtime/dependencies/python`(清单见同目录
6
+ * `runtime.json` 的 `python` 字段)。但这一层没把位置告诉插件 —— 宿主不导出 `DSH_PYTHON`,
7
+ * 于是「一键准备」的默认值 `python3` 落到了系统那个 3.9(macOS 命令行工具自带的正是 3.9),
8
+ * 第一步就报「Python 版本不受支持」,而机器上明明有 3.12。
9
+ *
10
+ * 所以这里自己找,顺序是:
11
+ *
12
+ * 1. **`DSH_PYTHON`** —— 显式覆盖永远是第一位的(文档里承诺的自定义入口)。
13
+ * 2. **DSH 自带的那一个** —— 从宿主告诉我们的两个锚点推:Electron 的 `resourcesPath`,
14
+ * 以及 `process.execPath`(桌面端是 `Contents/MacOS/<App>`,`ELECTRON_RUN_AS_NODE` 下
15
+ * 它就是运行时用的那个可执行文件)。两者都会向上找几级,因为包装脚本与真实二进制的
16
+ * 层级不一定一样。
17
+ * 3. **PATH 上的 `python3`** —— 都没有才退回。
18
+ *
19
+ * ## 这里只回答「哪个路径最可能是它」,不回答「它是哪个版本」
20
+ *
21
+ * 版本判断必须由准备阶段做(它要跑一次 `sys.version_info`,并把结论写进安装日志)。
22
+ * 在这里再探测一遍等于把同步可判的事情做成两次异步调用,而且拿到版本也不知道该报给谁。
23
+ */
24
+
25
+ import { existsSync } from 'node:fs'
26
+ import { posix, win32 } from 'node:path'
27
+ import { runProcess } from './process.js'
28
+
29
+ /**
30
+ * 按**目标平台**拼路径,不按跑这段代码的机器。
31
+ *
32
+ * 生产里两者永远一致(Windows 上 `process.platform` 就是 `win32`),但这里允许注入平台 ——
33
+ * 而 POSIX 上的 `dirname('C:\\x\\node.exe')` 会给出 `'.'`,于是那条 Windows 断言在 mac 上
34
+ * 跑不通。用平台自己的路径工具,注入才是真的能测。
35
+ */
36
+ const pathsFor = (platform: NodeJS.Platform): typeof posix => platform === 'win32' ? win32 : posix
37
+
38
+ /** 相对 App 资源根的落点。`runtime.json` 就在它的上一级。 */
39
+ const BUNDLE_RELATIVE = ['runtime/primary-runtime/dependencies/python']
40
+
41
+ /** 一个解释器可能叫的几个名字。Windows 的独立发行版把 `python.exe` 放在根上。 */
42
+ function interpreterNames(root: string, platform: NodeJS.Platform): string[] {
43
+ const { join } = pathsFor(platform)
44
+ return platform === 'win32'
45
+ ? [join(root, 'python.exe'), join(root, 'python3.exe')]
46
+ : [join(root, 'bin', 'python3'), join(root, 'bin', 'python')]
47
+ }
48
+
49
+ /** 从锚点向上走几级,每一级都试「本体」和「本体/Resources」两种排法。 */
50
+ function bundleCandidates(anchor: string, platform: NodeJS.Platform): string[] {
51
+ const { dirname, join } = pathsFor(platform)
52
+ const found: string[] = []
53
+ let dir = anchor
54
+ for (let depth = 0; depth < 6; depth += 1) {
55
+ for (const relative of BUNDLE_RELATIVE) {
56
+ for (const name of interpreterNames(join(dir, relative), platform)) found.push(name)
57
+ // macOS / Windows 的 `.app`:真实资源在 `Contents/Resources`,而锚点是 `Contents/MacOS`。
58
+ for (const name of interpreterNames(join(dir, 'Resources', relative), platform)) found.push(name)
59
+ }
60
+ const parent = dirname(dir)
61
+ if (parent === dir) break
62
+ dir = parent
63
+ }
64
+ return found
65
+ }
66
+
67
+ export interface PythonPick {
68
+ /** 要拿去建虚拟环境的解释器。 */
69
+ path: string
70
+ /** 它从哪来 —— 报错时要能说清「我没找到自带的那个」。 */
71
+ source: 'override' | 'bundled' | 'path'
72
+ }
73
+
74
+ export interface PythonProbe {
75
+ env?: Record<string, string | undefined>
76
+ /** Electron 的 `process.resourcesPath`;不在 Electron 里时省略。 */
77
+ resourcesPath?: string
78
+ /** 宿主的可执行文件路径;默认取 `process.execPath`。 */
79
+ execPath?: string
80
+ platform?: NodeJS.Platform
81
+ /** 存在性判断,测试里换成假的。 */
82
+ exists?: (path: string) => boolean
83
+ }
84
+
85
+ /**
86
+ * 挑一个基础解释器。**纯函数**(存在性判断可注入),所以「自带优先于 PATH」这条能被单独断言。
87
+ */
88
+ export function pickBasePython(probe: PythonProbe = {}): PythonPick {
89
+ const env = probe.env ?? process.env
90
+ const override = env.DSH_PYTHON?.trim()
91
+ if (override) return { path: override, source: 'override' }
92
+ const platform = probe.platform ?? process.platform
93
+ const exists = probe.exists ?? existsSync
94
+ const anchors: string[] = []
95
+ if (probe.resourcesPath) anchors.push(probe.resourcesPath)
96
+ const { dirname } = pathsFor(platform)
97
+ const executables = [env.DSH_DESKTOP_NODE_EXECUTABLE, probe.execPath ?? process.execPath]
98
+ for (const executable of executables) {
99
+ const value = executable?.trim()
100
+ if (value) anchors.push(dirname(value))
101
+ }
102
+ for (const anchor of anchors) {
103
+ for (const candidate of bundleCandidates(anchor, platform)) {
104
+ if (exists(candidate)) return { path: candidate, source: 'bundled' }
105
+ }
106
+ }
107
+ return { path: 'python3', source: 'path' }
108
+ }
109
+
110
+ /** 报错里那句「没找到自带的那一个」用得上。 */
111
+ export function pythonSourceLabel(source: PythonPick['source']): string {
112
+ return source === 'override' ? 'DSH_PYTHON' : source === 'bundled' ? 'DSH 自带运行时' : 'PATH 上的 python3'
113
+ }
114
+
115
+ /**
116
+ * 这个解释器能不能加载**第三方原生扩展**(torch 这类 pip 装的 dylib)。
117
+ *
118
+ * macOS 上不行的一种情况是真实存在过的(2026-10-18 实测):DSH 桌面端把 Python 3.12
119
+ * 打在自己的运行时里,并给它签了 Developer ID + **hardened runtime**
120
+ * (`flags=0x10000(runtime)`),又没有 `com.apple.security.cs.disable-library-validation`。
121
+ * 库校验因此生效 —— 它只肯加载**同一 Team ID** 签的 dylib。pip 上的 torch 是 ad-hoc 签名
122
+ * (Team ID 为空),于是:
123
+ *
124
+ * ```
125
+ * OSError: dlopen(.../libtorch_global_deps.dylib, 0x000A):
126
+ * code signature ... not valid for use in process:
127
+ * mapping process and mapped file (non-platform) have different Team IDs
128
+ * ```
129
+ *
130
+ * 同一个 dylib 换成 uv 管的独立 CPython(`adhoc, linker-signed`,没有 runtime 标记)
131
+ * 就能加载 —— 这一条在同一台机器上验过。
132
+ *
133
+ * 判据读的是 `codesign` 的 flags,不看路径:运行时目录在某些安装形态下不在 `.app` 里,
134
+ * 而「带不带 hardened runtime」才是真正决定库校验的那件事。没有 `codesign`(Linux/Windows)
135
+ * 或读不到(没签名)时一律当「能加载」—— 不因为探测失败就改道去下载解释器。
136
+ */
137
+ export async function hasHardenedRuntime(path: string, run: typeof runProcess = runProcess): Promise<boolean> {
138
+ if (process.platform !== 'darwin') return false
139
+ try {
140
+ const output = await run('/usr/bin/codesign', ['-dv', '--verbose=2', path], { timeoutMs: 10_000 })
141
+ const flags = /flags=0x[0-9a-f]+\(([^)]*)\)/i.exec(output)?.[1] ?? ''
142
+ return flags.split(',').some(flag => flag.trim() === 'runtime')
143
+ } catch {
144
+ return false
145
+ }
146
+ }
147
+
148
+ /**
149
+ * 这个解释器要不要换成 uv 管的那一个。
150
+ *
151
+ * 判据只有一条:**带 hardened runtime 就用不了第三方原生扩展**(见 `hasHardenedRuntime`)。
152
+ * `DSH_PYTHON` 显式给的不改道 —— 那是用户的选择;插件只把风险写进日志。
153
+ */
154
+ export function needsManagedInterpreter(pick: PythonPick, hardened: boolean): boolean {
155
+ return hardened && pick.source !== 'override'
156
+ }