@yadsh/dsh-qa-surface 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/README.md +194 -9
  2. package/compatibility.json +10 -1
  3. package/cordis.patch.yml +9 -0
  4. package/lib/account-remotes.js +10 -0
  5. package/lib/account-remotes.js.map +1 -1
  6. package/lib/accounts/errors.js.map +1 -1
  7. package/lib/accounts/file.js.map +1 -1
  8. package/lib/accounts/store.js +22 -0
  9. package/lib/accounts/store.js.map +1 -1
  10. package/lib/client/QaAccountsController.js +29 -0
  11. package/lib/client/QaAccountsController.js.map +1 -1
  12. package/lib/client/QaSessionController.js +168 -48
  13. package/lib/client/QaSessionController.js.map +1 -1
  14. package/lib/client/QaSurface.js +125 -56
  15. package/lib/client/QaSurface.js.map +1 -1
  16. package/lib/client/QaSurfaceGuard.js +96 -0
  17. package/lib/client/QaSurfaceGuard.js.map +1 -0
  18. package/lib/client/QaTranscriptAdapter.js +11 -5
  19. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  20. package/lib/client/components/QaChangelog.js +31 -0
  21. package/lib/client/components/QaChangelog.js.map +1 -1
  22. package/lib/client/components/QaComposer.js +1 -1
  23. package/lib/client/components/QaComposer.js.map +1 -1
  24. package/lib/client/components/QaHeader.js +2 -8
  25. package/lib/client/components/QaHeader.js.map +1 -1
  26. package/lib/client/components/QaMessage.js +20 -7
  27. package/lib/client/components/QaMessage.js.map +1 -1
  28. package/lib/client/components/QaModal.js +24 -6
  29. package/lib/client/components/QaModal.js.map +1 -1
  30. package/lib/client/components/QaSidebar.js +2 -6
  31. package/lib/client/components/QaSidebar.js.map +1 -1
  32. package/lib/client/components/QaSourcesPanel.js +6 -5
  33. package/lib/client/components/QaSourcesPanel.js.map +1 -1
  34. package/lib/client/components/QaWidthHandle.js +21 -1
  35. package/lib/client/components/QaWidthHandle.js.map +1 -1
  36. package/lib/client/components/surface-utils.js +2 -0
  37. package/lib/client/components/surface-utils.js.map +1 -1
  38. package/lib/client/index.js +72 -24
  39. package/lib/client/index.js.map +1 -1
  40. package/lib/client/panels/PanelHost.js +209 -0
  41. package/lib/client/panels/PanelHost.js.map +1 -0
  42. package/lib/client/panels/PanelLauncher.js +39 -0
  43. package/lib/client/panels/PanelLauncher.js.map +1 -0
  44. package/lib/client/panels/contract.js +2 -0
  45. package/lib/client/panels/contract.js.map +1 -0
  46. package/lib/client/panels/index.js +2 -0
  47. package/lib/client/panels/index.js.map +1 -0
  48. package/lib/client/panels/registry.js +171 -0
  49. package/lib/client/panels/registry.js.map +1 -0
  50. package/lib/client/project-session-state.js +3 -0
  51. package/lib/client/project-session-state.js.map +1 -1
  52. package/lib/client/settings/card.js +2 -2
  53. package/lib/client/settings/card.js.map +1 -1
  54. package/lib/client/settings/sections/accounts.js +3 -1
  55. package/lib/client/settings/sections/accounts.js.map +1 -1
  56. package/lib/client/settings/sections/documents.js +88 -0
  57. package/lib/client/settings/sections/documents.js.map +1 -0
  58. package/lib/client/settings/sections/interface.js +2 -0
  59. package/lib/client/settings/sections/interface.js.map +1 -1
  60. package/lib/client/settings/sections.js +1 -0
  61. package/lib/client/settings/sections.js.map +1 -1
  62. package/lib/client/settings-extensions/contract.js +2 -0
  63. package/lib/client/settings-extensions/contract.js.map +1 -0
  64. package/lib/client/settings-extensions/index.js +2 -0
  65. package/lib/client/settings-extensions/index.js.map +1 -0
  66. package/lib/client/settings-extensions/registry.js +63 -0
  67. package/lib/client/settings-extensions/registry.js.map +1 -0
  68. package/lib/client/settlement.js +51 -5
  69. package/lib/client/settlement.js.map +1 -1
  70. package/lib/client/source-preview.js +24 -0
  71. package/lib/client/source-preview.js.map +1 -0
  72. package/lib/client/styles.js +157 -32
  73. package/lib/client/styles.js.map +1 -1
  74. package/lib/client/subagent-codenames.js +109 -0
  75. package/lib/client/subagent-codenames.js.map +1 -0
  76. package/lib/client/types.js +1 -0
  77. package/lib/client/types.js.map +1 -1
  78. package/lib/client/user-settings/GeneralSettingsPage.js +13 -0
  79. package/lib/client/user-settings/GeneralSettingsPage.js.map +1 -0
  80. package/lib/client/user-settings/ProfileSettingsPage.js +59 -0
  81. package/lib/client/user-settings/ProfileSettingsPage.js.map +1 -0
  82. package/lib/client/user-settings/SkillCatalog.js +23 -0
  83. package/lib/client/user-settings/SkillCatalog.js.map +1 -0
  84. package/lib/client/user-settings/SkillEditor.js +89 -0
  85. package/lib/client/user-settings/SkillEditor.js.map +1 -0
  86. package/lib/client/user-settings/SkillToolPicker.js +58 -0
  87. package/lib/client/user-settings/SkillToolPicker.js.map +1 -0
  88. package/lib/client/user-settings/SkillsSettingsPage.js +171 -0
  89. package/lib/client/user-settings/SkillsSettingsPage.js.map +1 -0
  90. package/lib/client/user-settings/StartersSettingsPage.js +78 -0
  91. package/lib/client/user-settings/StartersSettingsPage.js.map +1 -0
  92. package/lib/client/user-settings/UserSettingsDialog.js +50 -0
  93. package/lib/client/user-settings/UserSettingsDialog.js.map +1 -0
  94. package/lib/client/user-settings/copy.js +84 -0
  95. package/lib/client/user-settings/copy.js.map +1 -0
  96. package/lib/client/user-settings/draft.js +127 -0
  97. package/lib/client/user-settings/draft.js.map +1 -0
  98. package/lib/client/user-settings/fields.js +24 -0
  99. package/lib/client/user-settings/fields.js.map +1 -0
  100. package/lib/client.js +5467 -1379
  101. package/lib/client.js.map +1 -1
  102. package/lib/config-resolvers/accounts.js +30 -0
  103. package/lib/config-resolvers/accounts.js.map +1 -1
  104. package/lib/config-resolvers/defaults.js +23 -0
  105. package/lib/config-resolvers/defaults.js.map +1 -1
  106. package/lib/config-resolvers/tools.js +37 -0
  107. package/lib/config-resolvers/tools.js.map +1 -0
  108. package/lib/config-resolvers/ui.js +2 -0
  109. package/lib/config-resolvers/ui.js.map +1 -1
  110. package/lib/config.js +288 -0
  111. package/lib/config.js.map +1 -1
  112. package/lib/documents/artifacts/ids.js +43 -0
  113. package/lib/documents/artifacts/ids.js.map +1 -0
  114. package/lib/documents/artifacts/manifest.js +66 -0
  115. package/lib/documents/artifacts/manifest.js.map +1 -0
  116. package/lib/documents/artifacts/store.js +169 -0
  117. package/lib/documents/artifacts/store.js.map +1 -0
  118. package/lib/documents/capabilities.js +93 -0
  119. package/lib/documents/capabilities.js.map +1 -0
  120. package/lib/documents/config.js +302 -0
  121. package/lib/documents/config.js.map +1 -0
  122. package/lib/documents/defaults.js +78 -0
  123. package/lib/documents/defaults.js.map +1 -0
  124. package/lib/documents/errors.js +101 -0
  125. package/lib/documents/errors.js.map +1 -0
  126. package/lib/documents/index.js +80 -0
  127. package/lib/documents/index.js.map +1 -0
  128. package/lib/documents/inspect/facts.js +161 -0
  129. package/lib/documents/inspect/facts.js.map +1 -0
  130. package/lib/documents/inspect/zip.js +108 -0
  131. package/lib/documents/inspect/zip.js.map +1 -0
  132. package/lib/documents/markdown/directives.js +135 -0
  133. package/lib/documents/markdown/directives.js.map +1 -0
  134. package/lib/documents/markdown/frontmatter.js +35 -0
  135. package/lib/documents/markdown/frontmatter.js.map +1 -0
  136. package/lib/documents/markdown/normalize.js +113 -0
  137. package/lib/documents/markdown/normalize.js.map +1 -0
  138. package/lib/documents/orchestrator/assets.js +243 -0
  139. package/lib/documents/orchestrator/assets.js.map +1 -0
  140. package/lib/documents/orchestrator/convert-document.js +186 -0
  141. package/lib/documents/orchestrator/convert-document.js.map +1 -0
  142. package/lib/documents/orchestrator/create-document.js +292 -0
  143. package/lib/documents/orchestrator/create-document.js.map +1 -0
  144. package/lib/documents/orchestrator/extract-document.js +162 -0
  145. package/lib/documents/orchestrator/extract-document.js.map +1 -0
  146. package/lib/documents/orchestrator/inspect-document.js +89 -0
  147. package/lib/documents/orchestrator/inspect-document.js.map +1 -0
  148. package/lib/documents/orchestrator/runtime-deps.js +59 -0
  149. package/lib/documents/orchestrator/runtime-deps.js.map +1 -0
  150. package/lib/documents/orchestrator/scope.js +132 -0
  151. package/lib/documents/orchestrator/scope.js.map +1 -0
  152. package/lib/documents/providers/docling.js +247 -0
  153. package/lib/documents/providers/docling.js.map +1 -0
  154. package/lib/documents/providers/libreoffice.js +130 -0
  155. package/lib/documents/providers/libreoffice.js.map +1 -0
  156. package/lib/documents/providers/markitdown.js +89 -0
  157. package/lib/documents/providers/markitdown.js.map +1 -0
  158. package/lib/documents/providers/pandoc.js +161 -0
  159. package/lib/documents/providers/pandoc.js.map +1 -0
  160. package/lib/documents/providers/process.js +164 -0
  161. package/lib/documents/providers/process.js.map +1 -0
  162. package/lib/documents/providers/registry.js +152 -0
  163. package/lib/documents/providers/registry.js.map +1 -0
  164. package/lib/documents/providers/shared.js +75 -0
  165. package/lib/documents/providers/shared.js.map +1 -0
  166. package/lib/documents/runtime.js +114 -0
  167. package/lib/documents/runtime.js.map +1 -0
  168. package/lib/documents/security/file-types.js +188 -0
  169. package/lib/documents/security/file-types.js.map +1 -0
  170. package/lib/documents/security/limits.js +78 -0
  171. package/lib/documents/security/limits.js.map +1 -0
  172. package/lib/documents/security/mime.js +43 -0
  173. package/lib/documents/security/mime.js.map +1 -0
  174. package/lib/documents/security/paths.js +133 -0
  175. package/lib/documents/security/paths.js.map +1 -0
  176. package/lib/documents/templates/registry.js +147 -0
  177. package/lib/documents/templates/registry.js.map +1 -0
  178. package/lib/documents/templates/resolver.js +59 -0
  179. package/lib/documents/templates/resolver.js.map +1 -0
  180. package/lib/documents/tools/convert.js +125 -0
  181. package/lib/documents/tools/convert.js.map +1 -0
  182. package/lib/documents/tools/create.js +187 -0
  183. package/lib/documents/tools/create.js.map +1 -0
  184. package/lib/documents/tools/index.js +41 -0
  185. package/lib/documents/tools/index.js.map +1 -0
  186. package/lib/documents/tools/inspect.js +135 -0
  187. package/lib/documents/tools/inspect.js.map +1 -0
  188. package/lib/documents/tools/shared.js +88 -0
  189. package/lib/documents/tools/shared.js.map +1 -0
  190. package/lib/documents/tools/to-markdown.js +125 -0
  191. package/lib/documents/tools/to-markdown.js.map +1 -0
  192. package/lib/documents/types.js +12 -0
  193. package/lib/documents/types.js.map +1 -0
  194. package/lib/index.js +225 -20
  195. package/lib/index.js.map +1 -1
  196. package/lib/integration-principals.js +22 -0
  197. package/lib/integration-principals.js.map +1 -0
  198. package/lib/lockdown-policy.js +15 -3
  199. package/lib/lockdown-policy.js.map +1 -1
  200. package/lib/personal-skills/errors.js +9 -0
  201. package/lib/personal-skills/errors.js.map +1 -0
  202. package/lib/personal-skills/host.js +80 -0
  203. package/lib/personal-skills/host.js.map +1 -0
  204. package/lib/personal-skills/index.js +10 -0
  205. package/lib/personal-skills/index.js.map +1 -0
  206. package/lib/personal-skills/paths.js +127 -0
  207. package/lib/personal-skills/paths.js.map +1 -0
  208. package/lib/personal-skills/provider.js +109 -0
  209. package/lib/personal-skills/provider.js.map +1 -0
  210. package/lib/personal-skills/remotes.js +40 -0
  211. package/lib/personal-skills/remotes.js.map +1 -0
  212. package/lib/personal-skills/service.js +686 -0
  213. package/lib/personal-skills/service.js.map +1 -0
  214. package/lib/personal-skills/skill-file.js +278 -0
  215. package/lib/personal-skills/skill-file.js.map +1 -0
  216. package/lib/personal-skills/skill-format.js +202 -0
  217. package/lib/personal-skills/skill-format.js.map +1 -0
  218. package/lib/personal-skills/watcher.js +96 -0
  219. package/lib/personal-skills/watcher.js.map +1 -0
  220. package/lib/profile.js +6 -4
  221. package/lib/profile.js.map +1 -1
  222. package/lib/prompt-notes.js +19 -0
  223. package/lib/prompt-notes.js.map +1 -1
  224. package/lib/provenance/file-preview.js +68 -21
  225. package/lib/provenance/file-preview.js.map +1 -1
  226. package/lib/provenance/host-store.js +44 -11
  227. package/lib/provenance/host-store.js.map +1 -1
  228. package/lib/provenance/index.js +1 -0
  229. package/lib/provenance/index.js.map +1 -1
  230. package/lib/provenance/normalize.js +3 -1
  231. package/lib/provenance/normalize.js.map +1 -1
  232. package/lib/provenance/snapshot-store.js +154 -0
  233. package/lib/provenance/snapshot-store.js.map +1 -0
  234. package/lib/qa-tools/activation-detector.js +53 -0
  235. package/lib/qa-tools/activation-detector.js.map +1 -0
  236. package/lib/qa-tools/activation-manager.js +111 -0
  237. package/lib/qa-tools/activation-manager.js.map +1 -0
  238. package/lib/qa-tools/catalog.js +108 -0
  239. package/lib/qa-tools/catalog.js.map +1 -0
  240. package/lib/qa-tools/durable-marker.js +115 -0
  241. package/lib/qa-tools/durable-marker.js.map +1 -0
  242. package/lib/qa-tools/index.js +83 -0
  243. package/lib/qa-tools/index.js.map +1 -0
  244. package/lib/qa-tools/lifecycle.js +64 -0
  245. package/lib/qa-tools/lifecycle.js.map +1 -0
  246. package/lib/qa-tools/types.js +2 -0
  247. package/lib/qa-tools/types.js.map +1 -0
  248. package/lib/resolve-config.js +5 -0
  249. package/lib/resolve-config.js.map +1 -1
  250. package/lib/secure-session.js +35 -3
  251. package/lib/secure-session.js.map +1 -1
  252. package/lib/starters.js +117 -0
  253. package/lib/starters.js.map +1 -0
  254. package/lib/typert.host.js +767 -22
  255. package/lib/typert.remote-client.d.ts +17 -1
  256. package/lib/typert.remote-client.js +609 -17
  257. package/lib/types/account-remotes.d.ts +3 -1
  258. package/lib/types/accounts/errors.d.ts +1 -1
  259. package/lib/types/accounts/file.d.ts +10 -0
  260. package/lib/types/accounts/store.d.ts +7 -1
  261. package/lib/types/client/QaAccountsController.d.ts +7 -1
  262. package/lib/types/client/QaSessionController.d.ts +12 -0
  263. package/lib/types/client/QaSurface.d.ts +14 -4
  264. package/lib/types/client/QaSurfaceGuard.d.ts +27 -0
  265. package/lib/types/client/QaTranscriptAdapter.d.ts +7 -0
  266. package/lib/types/client/components/QaComposer.d.ts +3 -1
  267. package/lib/types/client/components/QaHeader.d.ts +3 -1
  268. package/lib/types/client/components/QaModal.d.ts +5 -4
  269. package/lib/types/client/components/QaSidebar.d.ts +8 -11
  270. package/lib/types/client/components/QaWidthHandle.d.ts +13 -0
  271. package/lib/types/client/index.d.ts +1 -0
  272. package/lib/types/client/panels/PanelHost.d.ts +18 -0
  273. package/lib/types/client/panels/PanelLauncher.d.ts +5 -0
  274. package/lib/types/client/panels/contract.d.ts +83 -0
  275. package/lib/types/client/panels/index.d.ts +3 -0
  276. package/lib/types/client/panels/registry.d.ts +40 -0
  277. package/lib/types/client/project-session-state.d.ts +5 -0
  278. package/lib/types/client/settings/sections/documents.d.ts +13 -0
  279. package/lib/types/client/settings/sections.d.ts +1 -0
  280. package/lib/types/client/settings-extensions/contract.d.ts +32 -0
  281. package/lib/types/client/settings-extensions/index.d.ts +3 -0
  282. package/lib/types/client/settings-extensions/registry.d.ts +15 -0
  283. package/lib/types/client/settlement.d.ts +41 -5
  284. package/lib/types/client/source-preview.d.ts +8 -0
  285. package/lib/types/client/styles.d.ts +2 -0
  286. package/lib/types/client/subagent-codenames.d.ts +18 -0
  287. package/lib/types/client/types.d.ts +35 -3
  288. package/lib/types/client/user-settings/GeneralSettingsPage.d.ts +14 -0
  289. package/lib/types/client/user-settings/ProfileSettingsPage.d.ts +18 -0
  290. package/lib/types/client/user-settings/SkillCatalog.d.ts +16 -0
  291. package/lib/types/client/user-settings/SkillEditor.d.ts +42 -0
  292. package/lib/types/client/user-settings/SkillToolPicker.d.ts +17 -0
  293. package/lib/types/client/user-settings/SkillsSettingsPage.d.ts +15 -0
  294. package/lib/types/client/user-settings/StartersSettingsPage.d.ts +14 -0
  295. package/lib/types/client/user-settings/UserSettingsDialog.d.ts +43 -0
  296. package/lib/types/client/user-settings/copy.d.ts +25 -0
  297. package/lib/types/client/user-settings/draft.d.ts +51 -0
  298. package/lib/types/client/user-settings/fields.d.ts +43 -0
  299. package/lib/types/config-resolvers/tools.d.ts +6 -0
  300. package/lib/types/documents/artifacts/ids.d.ts +14 -0
  301. package/lib/types/documents/artifacts/manifest.d.ts +32 -0
  302. package/lib/types/documents/artifacts/store.d.ts +67 -0
  303. package/lib/types/documents/capabilities.d.ts +32 -0
  304. package/lib/types/documents/config.d.ts +27 -0
  305. package/lib/types/documents/defaults.d.ts +161 -0
  306. package/lib/types/documents/errors.d.ts +42 -0
  307. package/lib/types/documents/index.d.ts +63 -0
  308. package/lib/types/documents/inspect/facts.d.ts +43 -0
  309. package/lib/types/documents/inspect/zip.d.ts +28 -0
  310. package/lib/types/documents/markdown/directives.d.ts +39 -0
  311. package/lib/types/documents/markdown/frontmatter.d.ts +15 -0
  312. package/lib/types/documents/markdown/normalize.d.ts +30 -0
  313. package/lib/types/documents/orchestrator/assets.d.ts +55 -0
  314. package/lib/types/documents/orchestrator/convert-document.d.ts +25 -0
  315. package/lib/types/documents/orchestrator/create-document.d.ts +18 -0
  316. package/lib/types/documents/orchestrator/extract-document.d.ts +24 -0
  317. package/lib/types/documents/orchestrator/inspect-document.d.ts +12 -0
  318. package/lib/types/documents/orchestrator/runtime-deps.d.ts +43 -0
  319. package/lib/types/documents/orchestrator/scope.d.ts +52 -0
  320. package/lib/types/documents/providers/docling.d.ts +54 -0
  321. package/lib/types/documents/providers/libreoffice.d.ts +40 -0
  322. package/lib/types/documents/providers/markitdown.d.ts +28 -0
  323. package/lib/types/documents/providers/pandoc.d.ts +42 -0
  324. package/lib/types/documents/providers/process.d.ts +54 -0
  325. package/lib/types/documents/providers/registry.d.ts +68 -0
  326. package/lib/types/documents/providers/shared.d.ts +27 -0
  327. package/lib/types/documents/runtime.d.ts +59 -0
  328. package/lib/types/documents/security/file-types.d.ts +39 -0
  329. package/lib/types/documents/security/limits.d.ts +24 -0
  330. package/lib/types/documents/security/mime.d.ts +13 -0
  331. package/lib/types/documents/security/paths.d.ts +38 -0
  332. package/lib/types/documents/templates/registry.d.ts +50 -0
  333. package/lib/types/documents/templates/resolver.d.ts +30 -0
  334. package/lib/types/documents/tools/convert.d.ts +9 -0
  335. package/lib/types/documents/tools/create.d.ts +14 -0
  336. package/lib/types/documents/tools/index.d.ts +33 -0
  337. package/lib/types/documents/tools/inspect.d.ts +9 -0
  338. package/lib/types/documents/tools/shared.d.ts +77 -0
  339. package/lib/types/documents/tools/to-markdown.d.ts +12 -0
  340. package/lib/types/documents/types.d.ts +294 -0
  341. package/lib/types/index.d.ts +75 -3
  342. package/lib/types/integration-principals.d.ts +9 -0
  343. package/lib/types/lockdown-policy.d.ts +12 -2
  344. package/lib/types/personal-skills/errors.d.ts +11 -0
  345. package/lib/types/personal-skills/host.d.ts +42 -0
  346. package/lib/types/personal-skills/index.d.ts +10 -0
  347. package/lib/types/personal-skills/paths.d.ts +39 -0
  348. package/lib/types/personal-skills/provider.d.ts +33 -0
  349. package/lib/types/personal-skills/remotes.d.ts +35 -0
  350. package/lib/types/personal-skills/service.d.ts +131 -0
  351. package/lib/types/personal-skills/skill-file.d.ts +64 -0
  352. package/lib/types/personal-skills/skill-format.d.ts +100 -0
  353. package/lib/types/personal-skills/watcher.d.ts +39 -0
  354. package/lib/types/profile.d.ts +13 -0
  355. package/lib/types/prompt-notes.d.ts +9 -0
  356. package/lib/types/provenance/file-preview.d.ts +47 -4
  357. package/lib/types/provenance/host-store.d.ts +7 -1
  358. package/lib/types/provenance/index.d.ts +1 -0
  359. package/lib/types/provenance/snapshot-store.d.ts +23 -0
  360. package/lib/types/qa-tools/activation-detector.d.ts +29 -0
  361. package/lib/types/qa-tools/activation-manager.d.ts +47 -0
  362. package/lib/types/qa-tools/catalog.d.ts +40 -0
  363. package/lib/types/qa-tools/durable-marker.d.ts +16 -0
  364. package/lib/types/qa-tools/index.d.ts +40 -0
  365. package/lib/types/qa-tools/lifecycle.d.ts +44 -0
  366. package/lib/types/qa-tools/types.d.ts +45 -0
  367. package/lib/types/secure-session.d.ts +24 -2
  368. package/lib/types/starters.d.ts +45 -0
  369. package/lib/types/types.d.ts +202 -3
  370. package/package.json +24 -11
  371. package/scripts/repair-session-events.mjs +260 -0
  372. package/lib/client/components/QaProfile.js +0 -64
  373. package/lib/client/components/QaProfile.js.map +0 -1
  374. package/lib/types/client/components/QaProfile.d.ts +0 -25
@@ -0,0 +1,154 @@
1
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ const locationSchema = z
5
+ .object({
6
+ path: z.string().optional(),
7
+ lineStart: z.number().int().optional(),
8
+ lineEnd: z.number().int().optional(),
9
+ anchor: z.string().optional(),
10
+ jiraKey: z.string().optional(),
11
+ confluencePageId: z.string().optional(),
12
+ })
13
+ .strict();
14
+ const originSchema = z
15
+ .object({
16
+ sessionId: z.string(),
17
+ turn: z.number().int(),
18
+ step: z.number().int().optional(),
19
+ toolCallId: z.string().optional(),
20
+ toolName: z.string().optional(),
21
+ agentId: z.string().optional(),
22
+ role: z.enum(["parent", "subagent"]),
23
+ subagentRunId: z.string().optional(),
24
+ subagentSessionId: z.string().optional(),
25
+ })
26
+ .strict();
27
+ const sourceSchema = z
28
+ .object({
29
+ id: z.string(),
30
+ kind: z.enum([
31
+ "file",
32
+ "code",
33
+ "web",
34
+ "jira",
35
+ "confluence",
36
+ "knowledge",
37
+ "other",
38
+ ]),
39
+ title: z.string(),
40
+ uri: z.string().optional(),
41
+ path: z.string().optional(),
42
+ snippet: z.string().optional(),
43
+ locations: z.array(locationSchema),
44
+ evidence: z.enum([
45
+ "read",
46
+ "fetched",
47
+ "queried",
48
+ "reported",
49
+ "inherited",
50
+ "discovered",
51
+ ]),
52
+ origins: z.array(originSchema),
53
+ score: z.number(),
54
+ metadata: z.record(z.string(), z.json()).optional(),
55
+ })
56
+ .strict();
57
+ const bundleSchema = z
58
+ .object({
59
+ version: z.literal(1),
60
+ sessionId: z.string(),
61
+ turn: z.number().int().nonnegative(),
62
+ sources: z.array(sourceSchema),
63
+ discovered: z.array(sourceSchema).optional(),
64
+ complete: z.boolean(),
65
+ incompleteOrigins: z
66
+ .array(z
67
+ .object({
68
+ subagentRunId: z.string().optional(),
69
+ provider: z.string().optional(),
70
+ reason: z.string(),
71
+ })
72
+ .strict())
73
+ .optional(),
74
+ })
75
+ .strict();
76
+ const fileSchema = z
77
+ .object({
78
+ version: z.literal(1),
79
+ sessions: z.record(z.string(), z.record(z.string(), bundleSchema)),
80
+ })
81
+ .strict();
82
+ /** Process-local store used by tests and explicit ephemeral deployments. */
83
+ export class MemoryQaProvenanceSnapshotStore {
84
+ sessions = new Map();
85
+ list(sessionId) {
86
+ return [...(this.sessions.get(sessionId)?.values() ?? [])].sort((left, right) => left.turn - right.turn);
87
+ }
88
+ put(bundle) {
89
+ const turns = this.sessions.get(bundle.sessionId) ?? new Map();
90
+ turns.set(bundle.turn, structuredClone(bundle));
91
+ this.sessions.set(bundle.sessionId, turns);
92
+ }
93
+ }
94
+ /** Default durable provenance path, deliberately outside Harness journals. */
95
+ export function defaultQaProvenanceFilePath() {
96
+ const home = process.env.DSH_HOME?.trim();
97
+ return path.join(home !== undefined && home !== "" ? home : process.cwd(), "qa-sources.json");
98
+ }
99
+ /** Atomically persists per-turn QA source snapshots in plugin-owned storage. */
100
+ export class FileQaProvenanceSnapshotStore {
101
+ filePath;
102
+ constructor(filePath = defaultQaProvenanceFilePath()) {
103
+ this.filePath = filePath;
104
+ }
105
+ list(sessionId) {
106
+ const turns = this.load().sessions[sessionId] ?? {};
107
+ return Object.values(turns).sort((left, right) => left.turn - right.turn);
108
+ }
109
+ put(bundle) {
110
+ const current = this.load();
111
+ const next = {
112
+ version: 1,
113
+ sessions: {
114
+ ...current.sessions,
115
+ [bundle.sessionId]: {
116
+ ...(current.sessions[bundle.sessionId] ?? {}),
117
+ [String(bundle.turn)]: structuredClone(bundle),
118
+ },
119
+ },
120
+ };
121
+ this.persist(next);
122
+ }
123
+ load() {
124
+ let raw;
125
+ try {
126
+ raw = readFileSync(this.filePath, "utf8");
127
+ }
128
+ catch (error) {
129
+ if (error.code === "ENOENT") {
130
+ return { version: 1, sessions: {} };
131
+ }
132
+ throw error;
133
+ }
134
+ const parsed = fileSchema.safeParse(JSON.parse(raw));
135
+ if (!parsed.success) {
136
+ throw new Error(`qa-sources: ${this.filePath} is not a recognizable provenance file; refusing to overwrite it`, { cause: parsed.error });
137
+ }
138
+ for (const [sessionId, turns] of Object.entries(parsed.data.sessions)) {
139
+ for (const [turn, bundle] of Object.entries(turns)) {
140
+ if (bundle.sessionId !== sessionId || String(bundle.turn) !== turn) {
141
+ throw new Error(`qa-sources: ${this.filePath} contains a snapshot under the wrong session or turn; refusing to overwrite it`);
142
+ }
143
+ }
144
+ }
145
+ return parsed.data;
146
+ }
147
+ persist(file) {
148
+ mkdirSync(path.dirname(this.filePath), { recursive: true });
149
+ const temp = `${this.filePath}.${process.pid}.tmp`;
150
+ writeFileSync(temp, `${JSON.stringify(file, null, 2)}\n`, "utf8");
151
+ renameSync(temp, this.filePath);
152
+ }
153
+ }
154
+ //# sourceMappingURL=snapshot-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-store.js","sourceRoot":"","sources":["../../src/provenance/snapshot-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,cAAc,GAAG,CAAC;KACrB,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,CAAC;IACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACzC,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,CAAC;IACN,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;QACX,MAAM;QACN,MAAM;QACN,KAAK;QACL,MAAM;QACN,YAAY;QACZ,WAAW;QACX,OAAO;KACR,CAAC;IACF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;IAClC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC;QACf,MAAM;QACN,SAAS;QACT,SAAS;QACT,UAAU;QACV,WAAW;QACX,YAAY;KACb,CAAC;IACF,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;CACpD,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACpC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;IAC9B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE;IAC5C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;IACrB,iBAAiB,EAAE,CAAC;SACjB,KAAK,CACJ,CAAC;SACE,MAAM,CAAC;QACN,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACpC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;SACD,MAAM,EAAE,CACZ;SACA,QAAQ,EAAE;CACd,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,UAAU,GAAG,CAAC;KACjB,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC;CACnE,CAAC;KACD,MAAM,EAAE,CAAC;AAYZ,4EAA4E;AAC5E,MAAM,OAAO,+BAA+B;IACzB,QAAQ,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE1E,IAAI,CAAC,SAAiB;QACpB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAC7D,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CACxC,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,MAAqB;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QAC/D,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,UAAU,2BAA2B;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EACxD,iBAAiB,CAClB,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,OAAO,6BAA6B;IAErB,QAAQ;IAD3B,YACmB,QAAQ,GAAW,2BAA2B,EAAE;wBAAhD,QAAQ;IACxB,CAAC;IAEJ,IAAI,CAAC,SAAiB;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACpD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,GAAG,CAAC,MAAqB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAiB;YACzB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE;gBACR,GAAG,OAAO,CAAC,QAAQ;gBACnB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;oBAClB,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;oBAC7C,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC;iBAC/C;aACF;SACF,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAEO,IAAI;QACV,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;YACtC,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,eAAe,IAAI,CAAC,QAAQ,kEAAkE,EAC9F,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CACxB,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtE,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACnE,MAAM,IAAI,KAAK,CACb,eAAe,IAAI,CAAC,QAAQ,gFAAgF,CAC7G,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,IAAoB,CAAC;IACrC,CAAC;IAEO,OAAO,CAAC,IAAkB;QAChC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QACnD,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;CACF"}
@@ -0,0 +1,53 @@
1
+ /** The skill-loader tool whose successful result may unlock the QA tools. */
2
+ const SKILL_TOOL = "skill";
3
+ /** The canonical value `skill` returns: the loaded skill's identity. */
4
+ function loadedSkillName(value) {
5
+ if (typeof value !== "object" || value === null)
6
+ return undefined;
7
+ const name = value.name;
8
+ return typeof name === "string" ? name : undefined;
9
+ }
10
+ /**
11
+ * Turns a successful QA skill load into an activation request.
12
+ *
13
+ * The trigger is the authoritative `tools/result` of the built-in `skill` tool,
14
+ * not the model's attempt and not the rendered conversation text: a refused,
15
+ * unknown, or cancelled skill load reaches this listener as an error result and
16
+ * activates nothing.
17
+ */
18
+ export class QaToolActivationDetector {
19
+ ctx;
20
+ options;
21
+ dispose;
22
+ constructor(ctx, options) {
23
+ this.ctx = ctx;
24
+ this.options = options;
25
+ this.dispose = ctx.on("tools/result", (exec, result) => {
26
+ this.observe(exec, result);
27
+ }, { global: true });
28
+ }
29
+ observe(exec, result) {
30
+ if (exec.name !== SKILL_TOOL)
31
+ return;
32
+ if (result.isError)
33
+ return;
34
+ const agent = exec.agent;
35
+ if (agent === undefined)
36
+ return;
37
+ if (!this.options.isManagedAgent(agent))
38
+ return;
39
+ if (loadedSkillName(result.value) !== this.options.activationSkill)
40
+ return;
41
+ this.options.logger.info("qa-tools.activation-requested", {
42
+ agentId: String(agent.id),
43
+ skill: this.options.activationSkill,
44
+ });
45
+ // The skill result itself stays authoritative: a failed attachment is
46
+ // reported here and never rewritten into a skill failure.
47
+ this.options.manager.activate(agent, "skill");
48
+ }
49
+ disposeListeners() {
50
+ this.dispose();
51
+ }
52
+ }
53
+ //# sourceMappingURL=activation-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activation-detector.js","sourceRoot":"","sources":["../../src/qa-tools/activation-detector.ts"],"names":[],"mappings":"AAKA,6EAA6E;AAC7E,MAAM,UAAU,GAAG,OAAO,CAAC;AAE3B,wEAAwE;AACxE,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,IAAI,GAAI,KAAiC,CAAC,IAAI,CAAC;IACrD,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,OAAO,wBAAwB;IAIhB,GAAG;IACH,OAAO;IAJT,OAAO,CAAa;IAErC,YACmB,GAAY,EACZ,OAAwC;mBADxC,GAAG;uBACH,OAAO;QAExB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,EAAE,CACnB,cAAc,EACd,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YACf,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC,EACD,EAAE,MAAM,EAAE,IAAI,EAAE,CACjB,CAAC;IACJ,CAAC;IAEO,OAAO,CACb,IAAuD,EACvD,MAA+D;QAE/D,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO;QACrC,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC;YAAE,OAAO;QAChD,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,eAAe;YAAE,OAAO;QAE3E,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE;YACxD,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe;SACpC,CAAC,CAAC;QACH,sEAAsE;QACtE,0DAA0D;QAC1D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,111 @@
1
+ import { assertValidQaToolCatalog } from "./catalog.js";
2
+ /**
3
+ * Per-agent runtime ownership of the QA tool registrations.
4
+ *
5
+ * One agent's tools exist only while that agent is live: activation registers
6
+ * the whole catalog through the agent's own scoped context, and disposal
7
+ * unwinds the exact disposers `tools.register()` returned. State is a WeakMap
8
+ * keyed by the live agent, so nothing has to be keyed by id and a stale agent
9
+ * can never be mistaken for a resumed one.
10
+ */
11
+ export class QaToolActivationManager {
12
+ options;
13
+ states = new WeakMap();
14
+ constructor(options) {
15
+ this.options = options;
16
+ }
17
+ /**
18
+ * Register the whole catalog on one agent, all or nothing.
19
+ *
20
+ * A failed registration unwinds every tool this attempt registered and leaves
21
+ * the agent inactive: a partially attached QA surface would be worse than
22
+ * none, because the model would see a tool it cannot rely on.
23
+ * @param agent - the live agent receiving the tools.
24
+ * @param origin - why activation ran, for the operator log.
25
+ * @returns the outcome; `failed` carries the original error for the caller to report.
26
+ */
27
+ activate(agent, origin) {
28
+ const current = this.states.get(agent);
29
+ if (current !== undefined && current.status !== "inactive") {
30
+ return { status: "already-active" };
31
+ }
32
+ const state = {
33
+ status: "activating",
34
+ disposers: [],
35
+ };
36
+ this.states.set(agent, state);
37
+ const catalog = this.options.catalog;
38
+ let toolName = "(preflight)";
39
+ try {
40
+ assertValidQaToolCatalog(catalog);
41
+ // Called through the loaded tools object: the registry method uses
42
+ // `this` to pick the calling scope's layer.
43
+ const tools = agent.ctx.tools;
44
+ for (const descriptor of catalog) {
45
+ toolName = descriptor.definition.name;
46
+ state.disposers.push(tools.register(descriptor.definition));
47
+ }
48
+ state.status = "active";
49
+ state.catalogVersion = this.options.catalogVersion;
50
+ }
51
+ catch (error) {
52
+ this.rollback(state);
53
+ this.states.delete(agent);
54
+ this.options.logger.error("qa-tools.activation-failed", {
55
+ agentId: String(agent.id),
56
+ origin,
57
+ tool: toolName,
58
+ error: error instanceof Error ? error.message : String(error),
59
+ });
60
+ return { status: "failed", error };
61
+ }
62
+ this.options.logger.info("qa-tools.activated", {
63
+ agentId: String(agent.id),
64
+ origin,
65
+ tools: state.disposers.length,
66
+ catalog: this.options.catalogVersion,
67
+ });
68
+ return { status: "activated", count: state.disposers.length };
69
+ }
70
+ /** Whether this agent currently has the QA tools registered. */
71
+ isActive(agent) {
72
+ return this.states.get(agent)?.status === "active";
73
+ }
74
+ /** Names registered on this agent; the admission guard evaluates this per call. */
75
+ activeToolNames(agent) {
76
+ if (!this.isActive(agent))
77
+ return [];
78
+ return this.options.catalog.map((descriptor) => descriptor.definition.name);
79
+ }
80
+ /**
81
+ * Unregister one agent's QA tools and forget its state. Safe to call more
82
+ * than once, and safe for an agent that never activated.
83
+ * @param agent - the agent whose registrations must be unwound.
84
+ */
85
+ disposeAgent(agent) {
86
+ const state = this.states.get(agent);
87
+ if (state === undefined)
88
+ return;
89
+ this.rollback(state);
90
+ this.states.delete(agent);
91
+ this.options.logger.debug("qa-tools.disposed", {
92
+ agentId: String(agent.id),
93
+ });
94
+ }
95
+ /** Dispose in reverse registration order, containing individual failures. */
96
+ rollback(state) {
97
+ state.status = "inactive";
98
+ state.catalogVersion = undefined;
99
+ for (const dispose of state.disposers.splice(0).reverse()) {
100
+ try {
101
+ dispose();
102
+ }
103
+ catch (error) {
104
+ this.options.logger.warn("qa-tools.dispose-failed", {
105
+ error: error instanceof Error ? error.message : String(error),
106
+ });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ //# sourceMappingURL=activation-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activation-manager.js","sourceRoot":"","sources":["../../src/qa-tools/activation-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { defineTool } from "@deepseek-ai/dsh-tools";
2
+ /**
3
+ * Deterministic catalog identity. The durable activation marker is derived from
4
+ * the session log rather than stored, so this version is not compared against a
5
+ * persisted record; it is reported by `qa_tools_selfcheck` and by the operator
6
+ * log so a catalog change is visible in a running deployment.
7
+ *
8
+ * Bump it whenever the catalog's tool set or their schemas change.
9
+ */
10
+ export const QA_TOOL_CATALOG_VERSION = "1";
11
+ function createSelfcheckTool(deps) {
12
+ return defineTool({
13
+ name: "qa_tools_selfcheck",
14
+ description: "Report whether the QA tool set is active for this agent and which QA tools are registered. Use it to diagnose a task that seems to be missing a QA capability.",
15
+ parameters: {
16
+ action: {
17
+ type: "string",
18
+ required: true,
19
+ enum: ["status", "catalog"],
20
+ description: "`status` reports this agent's activation state; `catalog` describes the shipped QA tool catalog.",
21
+ },
22
+ },
23
+ output: {
24
+ schema: {
25
+ type: "object",
26
+ additionalProperties: false,
27
+ properties: {
28
+ catalogVersion: { type: "string", required: true },
29
+ activationMode: { type: "string", required: true },
30
+ catalogTools: {
31
+ type: "array",
32
+ required: true,
33
+ items: { type: "string" },
34
+ },
35
+ activeTools: {
36
+ type: "array",
37
+ required: true,
38
+ items: { type: "string" },
39
+ },
40
+ active: { type: "boolean", required: true },
41
+ skillLoaded: { type: "boolean", required: true },
42
+ },
43
+ },
44
+ render: (args, value) => {
45
+ const active = value.active === true;
46
+ const tools = Array.isArray(value.activeTools) ? value.activeTools : [];
47
+ const text = args.action === "catalog"
48
+ ? `QA tool catalog ${String(value.catalogVersion)} (mode ${String(value.activationMode)}): ${tools.join(", ") || "(empty)"}.`
49
+ : active
50
+ ? `QA tools are active (catalog ${String(value.catalogVersion)}): ${tools.join(", ") || "(empty)"}.`
51
+ : `QA tools are inactive (catalog ${String(value.catalogVersion)}, skill loaded: ${String(value.skillLoaded)}).`;
52
+ return [{ type: "text", text }];
53
+ },
54
+ },
55
+ execute: async (args, exec) => {
56
+ const agent = exec.agent;
57
+ const activeTools = agent === undefined ? [] : deps.activeTools(agent);
58
+ return {
59
+ catalogVersion: deps.catalogVersion,
60
+ activationMode: deps.activationMode,
61
+ catalogTools: [...deps.catalogTools()],
62
+ activeTools: [...activeTools],
63
+ active: activeTools.length > 0,
64
+ skillLoaded: agent === undefined ? false : deps.skillLoaded(agent),
65
+ };
66
+ },
67
+ });
68
+ }
69
+ /**
70
+ * Build the shipped QA tool catalog.
71
+ *
72
+ * Side-effect free: constructing it registers nothing with `ctx.tools`. The
73
+ * activation manager owns every registration.
74
+ */
75
+ export function createQaToolCatalog(deps) {
76
+ return [
77
+ {
78
+ definition: createSelfcheckTool(deps),
79
+ group: "diagnostics",
80
+ tags: ["activation", "diagnostics"],
81
+ },
82
+ ];
83
+ }
84
+ /** QA tool names, in catalog order; the admission gate treats them as dynamic. */
85
+ export function qaToolNames(catalog) {
86
+ return catalog.map((descriptor) => descriptor.definition.name);
87
+ }
88
+ /**
89
+ * Validate the catalog before it is registered anywhere: names must be unique
90
+ * and non-empty. Called once at activation preflight so a broken catalog fails
91
+ * before the first registration rather than halfway through.
92
+ * @param catalog - descriptors to validate.
93
+ * @throws when two descriptors share a name or a name is empty.
94
+ */
95
+ export function assertValidQaToolCatalog(catalog) {
96
+ const seen = new Set();
97
+ for (const descriptor of catalog) {
98
+ const name = descriptor.definition.name;
99
+ if (typeof name !== "string" || name.length === 0) {
100
+ throw new Error("QA tool catalog contains a tool without a name");
101
+ }
102
+ if (seen.has(name)) {
103
+ throw new Error(`QA tool catalog contains duplicate tool name "${name}"`);
104
+ }
105
+ seen.add(name);
106
+ }
107
+ }
108
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/qa-tools/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * The durable activation marker, read back from the session log.
3
+ *
4
+ * The marker is not an event of its own. `qa-surface` deliberately appends no
5
+ * custom session type: a reader that does not mount this plugin refuses a log
6
+ * containing an unknown non-`ignorable` type, which would make every activated
7
+ * session unreadable in a plain DSH deployment. Instead the activation is
8
+ * derived from the `skill` tool call the model already made — a standard
9
+ * `tool/call` paired with a successful `tool/result`, both of which every
10
+ * harness build understands and neither of which this plugin writes.
11
+ *
12
+ * Consequence: restoration trusts the same fact the live detector does, and a
13
+ * deployment that drops the `skill` tool cannot restore. That is the correct
14
+ * trade — the tool is an operator's deliberate grant, and the log stays
15
+ * portable.
16
+ */
17
+ /** Rendered `skill` result prefix emitted by `@deepseek-ai/dsh-tool-skill`. */
18
+ const SKILL_CONTENT = /<skill_content name="([^"]*)">/u;
19
+ /** The skill-loader tool whose successful result is the activation marker. */
20
+ const SKILL_TOOL = "skill";
21
+ /** `tool/call` data: the tool name and the call id its result will carry. */
22
+ function toolCallData(data) {
23
+ if (typeof data !== "object" || data === null)
24
+ return undefined;
25
+ const record = data;
26
+ return record.name === SKILL_TOOL && typeof record.callId === "string"
27
+ ? { callId: record.callId }
28
+ : undefined;
29
+ }
30
+ /** Every text fragment nested under a model content value, at any depth. */
31
+ function collectTexts(value, into) {
32
+ if (typeof value === "string") {
33
+ into.push(value);
34
+ return;
35
+ }
36
+ if (Array.isArray(value)) {
37
+ for (const item of value)
38
+ collectTexts(item, into);
39
+ return;
40
+ }
41
+ if (typeof value !== "object" || value === null)
42
+ return;
43
+ const record = value;
44
+ if (typeof record.text === "string")
45
+ into.push(record.text);
46
+ if (Array.isArray(record.content))
47
+ collectTexts(record.content, into);
48
+ }
49
+ /**
50
+ * Read one `tool/result` event: the call it answers, the text it carried, and
51
+ * whether it failed. Text is collected recursively because a tool result wraps
52
+ * its blocks in a `tool_result` block whose own `content` holds the text the
53
+ * model saw.
54
+ */
55
+ function resultBlocks(data) {
56
+ if (typeof data !== "object" || data === null)
57
+ return undefined;
58
+ const message = data.message;
59
+ if (typeof message !== "object" || message === null)
60
+ return undefined;
61
+ const content = message.content;
62
+ if (!Array.isArray(content))
63
+ return undefined;
64
+ const callIds = [];
65
+ const texts = [];
66
+ let isError = false;
67
+ for (const block of content) {
68
+ if (typeof block !== "object" || block === null)
69
+ continue;
70
+ const record = block;
71
+ if (typeof record.callId === "string")
72
+ callIds.push(record.callId);
73
+ if (record.isError === true)
74
+ isError = true;
75
+ collectTexts(record.content, texts);
76
+ }
77
+ return { callIds, texts, isError };
78
+ }
79
+ /**
80
+ * Whether one session's log shows the configured skill was successfully loaded.
81
+ *
82
+ * Pairs each `tool/call` for the `skill` tool with its `tool/result`, then reads
83
+ * the loaded skill's name from the canonical rendered content. The rendered
84
+ * block is the only record of the returned skill identity that survives to the
85
+ * log — `tool/result` stores the model-facing message, not the tool's canonical
86
+ * value — and the pair closes only on a non-error result, so a refused or
87
+ * failed load never counts.
88
+ * @param session - the live session to inspect.
89
+ * @param skillName - the configured activation skill name.
90
+ * @returns whether that skill was loaded and its result succeeded.
91
+ */
92
+ export function sessionLoadedSkill(session, skillName) {
93
+ const skillCalls = new Set();
94
+ for (const event of session.snapshotEvents()) {
95
+ if (event.type === "tool/call") {
96
+ const call = toolCallData(event.data);
97
+ if (call !== undefined)
98
+ skillCalls.add(call.callId);
99
+ continue;
100
+ }
101
+ if (event.type !== "tool/result")
102
+ continue;
103
+ const blocks = resultBlocks(event.data);
104
+ if (blocks === undefined || blocks.isError)
105
+ continue;
106
+ if (!blocks.callIds.some((callId) => skillCalls.has(callId)))
107
+ continue;
108
+ for (const text of blocks.texts) {
109
+ if (SKILL_CONTENT.exec(text)?.[1] === skillName)
110
+ return true;
111
+ }
112
+ }
113
+ return false;
114
+ }
115
+ //# sourceMappingURL=durable-marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-marker.js","sourceRoot":"","sources":["../../src/qa-tools/durable-marker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { QaToolActivationManager } from "./activation-manager.js";
2
+ import { QaToolActivationDetector } from "./activation-detector.js";
3
+ import { createQaToolCatalog, QA_TOOL_CATALOG_VERSION } from "./catalog.js";
4
+ import { sessionLoadedSkill } from "./durable-marker.js";
5
+ import { QaToolActivationLifecycle } from "./lifecycle.js";
6
+ /**
7
+ * The QA tool subsystem: one catalog, one per-agent activation manager, and the
8
+ * two edges that drive it — the skill-result detector and the agent lifecycle.
9
+ *
10
+ * `dsh-qa-surface` owns the tools but never registers them at boot. Nothing in
11
+ * the catalog reaches the model until an agent it belongs to loads the
12
+ * activation skill, so the initial request of a session carries only the
13
+ * composition's own schemas.
14
+ */
15
+ export class QaTools {
16
+ ctx;
17
+ options;
18
+ manager;
19
+ detector;
20
+ lifecycle;
21
+ catalogTools;
22
+ constructor(ctx, options) {
23
+ this.ctx = ctx;
24
+ this.options = options;
25
+ // The self-check tool answers about whichever agent calls it, so the
26
+ // catalog is built before any agent exists and resolves `exec.agent` at
27
+ // execution time.
28
+ const catalog = createQaToolCatalog({
29
+ catalogVersion: QA_TOOL_CATALOG_VERSION,
30
+ activationMode: options.activationMode,
31
+ catalogTools: () => this.catalogTools,
32
+ activeTools: (agent) => this.manager.activeToolNames(agent),
33
+ skillLoaded: (agent) => sessionLoadedSkill(agent.session, options.activationSkill),
34
+ });
35
+ this.catalogTools = catalog.map((entry) => entry.definition.name);
36
+ this.manager = new QaToolActivationManager({
37
+ catalog,
38
+ catalogVersion: QA_TOOL_CATALOG_VERSION,
39
+ logger: options.logger,
40
+ });
41
+ this.detector = new QaToolActivationDetector(ctx, {
42
+ manager: this.manager,
43
+ logger: options.logger,
44
+ activationSkill: options.activationSkill,
45
+ isManagedAgent: (agent) => this.isManagedAgent(agent),
46
+ });
47
+ this.lifecycle = new QaToolActivationLifecycle(ctx, {
48
+ manager: this.manager,
49
+ logger: options.logger,
50
+ isManagedAgent: (agent) => this.isManagedAgent(agent),
51
+ dynamicActivation: options.dynamicActivation,
52
+ activationSkill: options.activationSkill,
53
+ });
54
+ if (options.activationPresets.length === 0 &&
55
+ this.catalogTools.length > 0) {
56
+ options.logger.warn("qa-tools.unscoped", {
57
+ hint: "tools.activationPresets is empty: any composed agent can unlock the QA tools",
58
+ });
59
+ }
60
+ }
61
+ /** Names currently registered on one agent; the admission guard reads this per call. */
62
+ activeToolNames(agent) {
63
+ return this.manager.activeToolNames(agent);
64
+ }
65
+ dispose() {
66
+ this.detector.disposeListeners();
67
+ this.lifecycle.dispose();
68
+ }
69
+ /**
70
+ * The preset gate. An empty `activationPresets` leaves it open, which is only
71
+ * coherent when this plugin serves a single agent composition; naming the QA
72
+ * preset keeps an unrelated DSH agent from unlocking the same catalog by
73
+ * loading a skill of the same name.
74
+ */
75
+ isManagedAgent(agent) {
76
+ const presets = this.options.activationPresets;
77
+ if (presets.length === 0)
78
+ return true;
79
+ const preset = agent.session?.header?.agentPreset;
80
+ return preset !== undefined && presets.includes(preset);
81
+ }
82
+ }
83
+ //# sourceMappingURL=index.js.map