dsh-agent-plugins-market 0.9.0 → 0.9.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 (358) hide show
  1. package/README.md +64 -154
  2. package/README.zh.md +74 -164
  3. package/assets/dsh-agent-plugins.png +0 -0
  4. package/client/client.js +5371 -1085
  5. package/client/client.js.map +1 -1
  6. package/lib/index.js +2 -257
  7. package/lib/{application → packages/market-bundle/src/application}/catalog.js +207 -41
  8. package/lib/{application → packages/market-bundle/src/application}/details.js +73 -29
  9. package/lib/packages/market-bundle/src/application/extension-inventory.js +408 -0
  10. package/lib/packages/market-bundle/src/application/extension-project.js +64 -0
  11. package/lib/packages/market-bundle/src/application/resource-inventory.js +96 -0
  12. package/lib/packages/market-bundle/src/application/server-config.js +9 -0
  13. package/lib/packages/market-bundle/src/application/suite-queries.js +86 -0
  14. package/lib/packages/market-bundle/src/index.js +372 -0
  15. package/lib/{runtime/host → packages/market-bundle/src/platform}/feedback-tool.js +2 -2
  16. package/lib/{runtime/host → packages/market-bundle/src/platform}/settings-namespace.js +55 -7
  17. package/lib/packages/market-bundle/src/platform/settings-schema.js +25 -0
  18. package/lib/packages/market-bundle/src/routes-extension-presets.js +161 -0
  19. package/lib/packages/market-bundle/src/routes-resources.js +127 -0
  20. package/lib/{routes.js → packages/market-bundle/src/routes.js} +225 -21
  21. package/lib/packages/market-bundle/src/runtime-adapters.js +57 -0
  22. package/lib/packages/market-bundle/src/session-extension.js +337 -0
  23. package/lib/{application → packages/market-catalog/src/application}/catalog-context.js +7 -4
  24. package/lib/{application → packages/market-catalog/src/application}/install-store.js +3 -3
  25. package/lib/{application → packages/market-catalog/src/application}/snapshot-cache.js +100 -11
  26. package/lib/{application → packages/market-catalog/src/application}/source-store.js +24 -11
  27. package/lib/{application → packages/market-catalog/src/application}/state/state-store.js +1 -1
  28. package/lib/{application → packages/market-catalog/src/application}/state/storage-migration.js +1 -1
  29. package/lib/packages/market-catalog/src/index.js +19 -0
  30. package/lib/{catalog → packages/market-catalog/src/scanning}/archive.js +1 -1
  31. package/lib/{catalog → packages/market-catalog/src/scanning}/codex-mcp.js +1 -1
  32. package/lib/{catalog → packages/market-catalog/src/scanning}/component-files.js +2 -2
  33. package/lib/{catalog → packages/market-catalog/src/scanning}/manifests.js +2 -2
  34. package/lib/{catalog → packages/market-catalog/src/scanning}/native-project.js +1 -1
  35. package/lib/{catalog → packages/market-catalog/src/scanning}/paths.js +1 -1
  36. package/lib/{catalog → packages/market-catalog/src/scanning}/plugin-variables.js +21 -1
  37. package/lib/{catalog → packages/market-catalog/src/scanning}/scan-resolvers.js +35 -2
  38. package/lib/{catalog → packages/market-catalog/src/scanning}/skills-parse.js +40 -10
  39. package/lib/{catalog → packages/market-catalog/src/scanning}/validate.js +15 -2
  40. package/lib/packages/market-contracts/src/contracts/extension-presets.js +125 -0
  41. package/lib/{contracts → packages/market-contracts/src/contracts}/market.js +33 -5
  42. package/lib/packages/market-contracts/src/contracts/mcp-overrides.js +2 -0
  43. package/lib/packages/market-contracts/src/contracts/resource-window.js +29 -0
  44. package/lib/packages/market-contracts/src/contracts/settings.js +130 -0
  45. package/lib/packages/market-contracts/src/contracts/surface-toggles.js +29 -0
  46. package/lib/packages/market-contracts/src/contracts/translation.js +28 -0
  47. package/lib/packages/market-contracts/src/index.js +4 -0
  48. package/lib/{model → packages/market-contracts/src/model}/layouts.js +11 -0
  49. package/lib/{application → packages/market-contracts/src/ports}/ports.js +3 -0
  50. package/lib/{application/mcp/mcp-redaction.js → packages/market-contracts/src/redaction.js} +17 -1
  51. package/lib/{application → packages/market-lsp/src/application}/lsp/lsp-direct-config.js +2 -2
  52. package/lib/{application → packages/market-lsp/src/application}/lsp/lsp-server-state.js +1 -1
  53. package/lib/{application → packages/market-lsp/src/application}/lsp/lsp-status.js +20 -3
  54. package/lib/{application → packages/market-lsp/src/application}/lsp/profile-seam.js +1 -1
  55. package/lib/packages/market-lsp/src/application/lsp/validation.js +46 -0
  56. package/lib/{application → packages/market-lsp/src/application}/lsp-service.js +61 -3
  57. package/lib/packages/market-lsp/src/index.js +8 -0
  58. package/lib/{runtime → packages/market-lsp/src/runtime}/lsp/lsp-mounts.js +79 -40
  59. package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-backend.js +0 -16
  60. package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-config.js +104 -21
  61. package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-direct-config.js +12 -4
  62. package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-overrides.js +4 -4
  63. package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-status.js +49 -10
  64. package/lib/packages/market-mcp/src/application/mcp/validation.js +63 -0
  65. package/lib/{application → packages/market-mcp/src/application}/mcp-service.js +111 -91
  66. package/lib/packages/market-mcp/src/index.js +10 -0
  67. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/bridge.js +12 -9
  68. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/connection.js +1 -1
  69. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/oauth.js +1 -1
  70. package/lib/packages/market-mcp/src/runtime/mcp/bridge/tool-ownership.js +26 -0
  71. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/tools.js +1 -1
  72. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-auth-record.js +35 -4
  73. package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-mounts.js +35 -4
  74. package/lib/packages/market-runtime/src/adapter-contracts.js +1 -0
  75. package/lib/packages/market-runtime/src/application/command-resources.js +74 -0
  76. package/lib/packages/market-runtime/src/application/extension-authorization.js +27 -0
  77. package/lib/packages/market-runtime/src/application/extension-hook-selection.js +56 -0
  78. package/lib/packages/market-runtime/src/application/extension-suite-declarations.js +57 -0
  79. package/lib/packages/market-runtime/src/application/extension-suite-selection.js +84 -0
  80. package/lib/packages/market-runtime/src/application/fs-probe.js +43 -0
  81. package/lib/packages/market-runtime/src/application/panel-resources.js +370 -0
  82. package/lib/{application → packages/market-runtime/src/application}/panels/user-hooks.js +2 -2
  83. package/lib/{application → packages/market-runtime/src/application}/panels/user-store.js +53 -13
  84. package/lib/{application → packages/market-runtime/src/application}/project-agent-roles.js +20 -11
  85. package/lib/packages/market-runtime/src/application/state/extension-presets.js +144 -0
  86. package/lib/packages/market-runtime/src/application/state/resource-favorites.js +90 -0
  87. package/lib/packages/market-runtime/src/application/state/resource-filters.js +2 -0
  88. package/lib/packages/market-runtime/src/application/state/surface-toggles.js +10 -0
  89. package/lib/packages/market-runtime/src/application/state/workspace-policy.js +56 -0
  90. package/lib/packages/market-runtime/src/catalog-port.js +1 -0
  91. package/lib/packages/market-runtime/src/extension-service.js +1 -0
  92. package/lib/packages/market-runtime/src/index.js +31 -0
  93. package/lib/{runtime → packages/market-runtime/src/runtime}/agents/agent-role-router.js +74 -79
  94. package/lib/packages/market-runtime/src/runtime/agents/agent-teams-seat.js +58 -0
  95. package/lib/{runtime → packages/market-runtime/src/runtime}/agents/subagent-catalog.js +89 -21
  96. package/lib/packages/market-runtime/src/runtime/agents/team-coordination.js +51 -0
  97. package/lib/packages/market-runtime/src/runtime/agents/teammate-role-runtime.js +241 -0
  98. package/lib/packages/market-runtime/src/runtime/agents/teammate-role-tool.js +130 -0
  99. package/lib/{runtime → packages/market-runtime/src/runtime}/core/reconcile-scheduler.js +2 -2
  100. package/lib/packages/market-runtime/src/runtime/core/reconciler.js +457 -0
  101. package/lib/packages/market-runtime/src/runtime/host/command-name-allocator.js +168 -0
  102. package/lib/packages/market-runtime/src/runtime/host/extension-progress.js +120 -0
  103. package/lib/packages/market-runtime/src/runtime/host/extension-runtime.js +405 -0
  104. package/lib/packages/market-runtime/src/runtime/host/extension-session-state.js +839 -0
  105. package/lib/packages/market-runtime/src/runtime/host/extension-tool-gates.js +96 -0
  106. package/lib/{runtime → packages/market-runtime/src/runtime}/host/failure-detail.js +1 -1
  107. package/lib/{runtime → packages/market-runtime/src/runtime}/host/host-locale.js +2 -0
  108. package/lib/packages/market-runtime/src/runtime/host/menu-row-identities.js +38 -0
  109. package/lib/packages/market-runtime/src/runtime/host/resource-filter-service.js +81 -0
  110. package/lib/packages/market-runtime/src/runtime/host/scoped-contributors.js +304 -0
  111. package/lib/packages/market-runtime/src/runtime/host/surface-toggle-service.js +15 -0
  112. package/lib/packages/market-runtime/src/runtime/panels/user-commands.js +211 -0
  113. package/lib/{runtime → packages/market-runtime/src/runtime}/panels/user-panels.js +34 -14
  114. package/lib/packages/market-runtime/src/runtime/surfaces/commands-mounts.js +256 -0
  115. package/lib/packages/market-runtime/src/runtime/surfaces/extension-hooks.js +294 -0
  116. package/lib/packages/market-runtime/src/runtime/surfaces/hook-dry-run.js +122 -0
  117. package/lib/{runtime → packages/market-runtime/src/runtime}/surfaces/hooks-mounts.js +1 -1
  118. package/lib/{runtime → packages/market-runtime/src/runtime}/surfaces/project-runtime.js +23 -13
  119. package/lib/packages/market-runtime/src/runtime/surfaces/skills-provider.js +241 -0
  120. package/lib/packages/market-translation/src/application/state/translation-cache.js +122 -0
  121. package/lib/packages/market-translation/src/application/translation/chain.js +99 -0
  122. package/lib/packages/market-translation/src/application/translation/document.js +384 -0
  123. package/lib/packages/market-translation/src/application/translation/localizer.js +642 -0
  124. package/lib/packages/market-translation/src/application/translation/service.js +113 -0
  125. package/lib/packages/market-translation/src/application/translation/unit.js +19 -0
  126. package/lib/packages/market-translation/src/index.js +4 -0
  127. package/lib/packages/market-translation/src/runtime/host/llm-translator.js +278 -0
  128. package/lib/packages/market-translation/src/runtime/host/machine-translator.js +152 -0
  129. package/lib/packages/market-translation/src/runtime/host/text-masking.js +96 -0
  130. package/lib/packages/market-translation/src/runtime/host/translation-providers.js +116 -0
  131. package/lib/types/index.d.ts +2 -130
  132. package/lib/types/{application → packages/market-bundle/src/application}/catalog.d.ts +117 -22
  133. package/lib/types/packages/market-bundle/src/application/details.d.ts +24 -0
  134. package/lib/types/packages/market-bundle/src/application/extension-inventory.d.ts +45 -0
  135. package/lib/types/packages/market-bundle/src/application/extension-project.d.ts +26 -0
  136. package/lib/types/packages/market-bundle/src/application/resource-inventory.d.ts +42 -0
  137. package/lib/types/packages/market-bundle/src/application/server-config.d.ts +9 -0
  138. package/lib/types/packages/market-bundle/src/application/suite-queries.d.ts +84 -0
  139. package/lib/types/packages/market-bundle/src/index.d.ts +125 -0
  140. package/lib/types/{runtime/host → packages/market-bundle/src/platform}/settings-namespace.d.ts +44 -9
  141. package/lib/types/{application/mcp/mcp-backend.d.ts → packages/market-bundle/src/platform/settings-schema.d.ts} +13 -28
  142. package/lib/types/packages/market-bundle/src/routes-extension-presets.d.ts +15 -0
  143. package/lib/types/packages/market-bundle/src/routes-resources.d.ts +17 -0
  144. package/lib/types/packages/market-bundle/src/routes.d.ts +32 -0
  145. package/lib/types/packages/market-bundle/src/runtime-adapters.d.ts +42 -0
  146. package/lib/types/packages/market-bundle/src/session-extension.d.ts +62 -0
  147. package/lib/types/{application → packages/market-catalog/src/application}/catalog-context.d.ts +11 -3
  148. package/lib/types/{application → packages/market-catalog/src/application}/install-store.d.ts +1 -1
  149. package/lib/types/{application → packages/market-catalog/src/application}/regions.d.ts +1 -1
  150. package/lib/types/{application → packages/market-catalog/src/application}/snapshot-cache.d.ts +44 -2
  151. package/lib/types/{application → packages/market-catalog/src/application}/source-store.d.ts +12 -3
  152. package/lib/types/{application → packages/market-catalog/src/application}/state/state-store.d.ts +1 -1
  153. package/lib/types/packages/market-catalog/src/index.d.ts +22 -0
  154. package/lib/types/{catalog → packages/market-catalog/src/scanning}/archive.d.ts +1 -1
  155. package/lib/types/{catalog → packages/market-catalog/src/scanning}/codex-mcp.d.ts +1 -1
  156. package/lib/types/{catalog → packages/market-catalog/src/scanning}/component-files.d.ts +1 -1
  157. package/lib/types/{catalog → packages/market-catalog/src/scanning}/lsp-spec.d.ts +1 -1
  158. package/lib/types/{catalog → packages/market-catalog/src/scanning}/manifests.d.ts +3 -3
  159. package/lib/types/{catalog → packages/market-catalog/src/scanning}/native-project.d.ts +2 -2
  160. package/lib/types/{catalog → packages/market-catalog/src/scanning}/plugin-variables.d.ts +12 -1
  161. package/lib/types/{catalog → packages/market-catalog/src/scanning}/project-config.d.ts +2 -2
  162. package/lib/types/{catalog → packages/market-catalog/src/scanning}/project-hooks.d.ts +2 -2
  163. package/lib/types/{catalog → packages/market-catalog/src/scanning}/scan-pipeline.d.ts +1 -1
  164. package/lib/types/{catalog → packages/market-catalog/src/scanning}/scan-resolvers.d.ts +3 -3
  165. package/lib/types/{catalog → packages/market-catalog/src/scanning}/source-catalog.d.ts +1 -1
  166. package/lib/types/{catalog → packages/market-catalog/src/scanning}/suite-components.d.ts +1 -1
  167. package/lib/types/{catalog → packages/market-catalog/src/scanning}/suite-scanner.d.ts +1 -1
  168. package/lib/types/{catalog → packages/market-catalog/src/scanning}/surfaces.d.ts +1 -1
  169. package/lib/types/{catalog → packages/market-catalog/src/scanning}/validate.d.ts +1 -1
  170. package/lib/types/packages/market-contracts/src/contracts/extension-presets.d.ts +237 -0
  171. package/lib/types/{contracts → packages/market-contracts/src/contracts}/market.d.ts +87 -16
  172. package/lib/types/packages/market-contracts/src/contracts/mcp-overrides.d.ts +39 -0
  173. package/lib/types/{contracts → packages/market-contracts/src/contracts}/mcp-status.d.ts +9 -0
  174. package/lib/types/packages/market-contracts/src/contracts/resource-window.d.ts +70 -0
  175. package/lib/types/packages/market-contracts/src/contracts/settings.d.ts +121 -0
  176. package/lib/types/packages/market-contracts/src/contracts/surface-toggles.d.ts +28 -0
  177. package/lib/types/packages/market-contracts/src/contracts/translation.d.ts +81 -0
  178. package/lib/types/{runtime → packages/market-contracts/src}/host/plugin-message-source.d.ts +1 -1
  179. package/lib/types/packages/market-contracts/src/index.d.ts +5 -0
  180. package/lib/types/{model → packages/market-contracts/src/model}/layouts.d.ts +7 -0
  181. package/lib/types/{model → packages/market-contracts/src/model}/types.d.ts +2 -2
  182. package/lib/types/packages/market-contracts/src/ports/ports.d.ts +183 -0
  183. package/lib/types/{application → packages/market-contracts/src/ports}/queries.d.ts +27 -6
  184. package/lib/types/{application/mcp/mcp-redaction.d.ts → packages/market-contracts/src/redaction.d.ts} +2 -0
  185. package/lib/types/{application → packages/market-lsp/src/application}/lsp/lsp-direct-config.d.ts +1 -1
  186. package/lib/types/{application → packages/market-lsp/src/application}/lsp/lsp-status.d.ts +21 -5
  187. package/lib/types/packages/market-lsp/src/application/lsp/validation.d.ts +8 -0
  188. package/lib/types/{application → packages/market-lsp/src/application}/lsp-service.d.ts +19 -6
  189. package/lib/types/packages/market-lsp/src/index.d.ts +8 -0
  190. package/lib/types/{runtime → packages/market-lsp/src/runtime}/lsp/lsp-mounts.d.ts +26 -6
  191. package/lib/types/packages/market-mcp/src/application/mcp/mcp-backend.d.ts +28 -0
  192. package/lib/types/{application → packages/market-mcp/src/application}/mcp/mcp-bridge-config.d.ts +1 -1
  193. package/lib/types/{application → packages/market-mcp/src/application}/mcp/mcp-config.d.ts +2 -2
  194. package/lib/types/{application → packages/market-mcp/src/application}/mcp/mcp-direct-config.d.ts +6 -1
  195. package/lib/types/{application → packages/market-mcp/src/application}/mcp/mcp-overrides.d.ts +4 -38
  196. package/lib/types/packages/market-mcp/src/application/mcp/mcp-status.d.ts +40 -0
  197. package/lib/types/{application/server-config.d.ts → packages/market-mcp/src/application/mcp/validation.d.ts} +2 -10
  198. package/lib/types/{application → packages/market-mcp/src/application}/mcp-service.d.ts +22 -16
  199. package/lib/types/packages/market-mcp/src/index.d.ts +12 -0
  200. package/lib/types/packages/market-mcp/src/runtime/mcp/bridge/tool-ownership.d.ts +14 -0
  201. package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-auth-record.d.ts +4 -0
  202. package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-mounts.d.ts +19 -3
  203. package/lib/types/packages/market-runtime/src/adapter-contracts.d.ts +89 -0
  204. package/lib/types/{application → packages/market-runtime/src/application}/agent-roles.d.ts +2 -0
  205. package/lib/types/packages/market-runtime/src/application/command-resources.d.ts +26 -0
  206. package/lib/types/packages/market-runtime/src/application/extension-authorization.d.ts +12 -0
  207. package/lib/types/packages/market-runtime/src/application/extension-hook-selection.d.ts +23 -0
  208. package/lib/types/packages/market-runtime/src/application/extension-suite-declarations.d.ts +10 -0
  209. package/lib/types/packages/market-runtime/src/application/extension-suite-selection.d.ts +30 -0
  210. package/lib/types/packages/market-runtime/src/application/fs-probe.d.ts +12 -0
  211. package/lib/types/packages/market-runtime/src/application/panel-resources.d.ts +100 -0
  212. package/lib/types/{application → packages/market-runtime/src/application}/panels/user-hooks.d.ts +1 -1
  213. package/lib/types/packages/market-runtime/src/application/project-agent-roles.d.ts +10 -0
  214. package/lib/types/packages/market-runtime/src/application/state/extension-presets.d.ts +24 -0
  215. package/lib/types/packages/market-runtime/src/application/state/resource-favorites.d.ts +9 -0
  216. package/lib/types/packages/market-runtime/src/application/state/resource-filters.d.ts +2 -0
  217. package/lib/types/packages/market-runtime/src/application/state/surface-toggles.d.ts +6 -0
  218. package/lib/types/packages/market-runtime/src/application/state/workspace-policy.d.ts +19 -0
  219. package/lib/types/packages/market-runtime/src/catalog-port.d.ts +30 -0
  220. package/lib/types/packages/market-runtime/src/extension-service.d.ts +14 -0
  221. package/lib/types/packages/market-runtime/src/index.d.ts +41 -0
  222. package/lib/types/{runtime → packages/market-runtime/src/runtime}/agents/agent-role-router.d.ts +66 -31
  223. package/lib/types/packages/market-runtime/src/runtime/agents/agent-teams-seat.d.ts +41 -0
  224. package/lib/types/{runtime → packages/market-runtime/src/runtime}/agents/subagent-catalog.d.ts +34 -2
  225. package/lib/types/packages/market-runtime/src/runtime/agents/team-coordination.d.ts +8 -0
  226. package/lib/types/packages/market-runtime/src/runtime/agents/teammate-role-runtime.d.ts +74 -0
  227. package/lib/types/packages/market-runtime/src/runtime/agents/teammate-role-tool.d.ts +6 -0
  228. package/lib/types/{runtime → packages/market-runtime/src/runtime}/core/reconcile-scheduler.d.ts +5 -2
  229. package/lib/types/packages/market-runtime/src/runtime/core/reconciler.d.ts +141 -0
  230. package/lib/types/packages/market-runtime/src/runtime/host/command-name-allocator.d.ts +132 -0
  231. package/lib/types/packages/market-runtime/src/runtime/host/extension-progress.d.ts +91 -0
  232. package/lib/types/packages/market-runtime/src/runtime/host/extension-runtime.d.ts +77 -0
  233. package/lib/types/packages/market-runtime/src/runtime/host/extension-session-state.d.ts +242 -0
  234. package/lib/types/packages/market-runtime/src/runtime/host/extension-tool-gates.d.ts +38 -0
  235. package/lib/types/{runtime → packages/market-runtime/src/runtime}/host/host-locale.d.ts +1 -1
  236. package/lib/types/packages/market-runtime/src/runtime/host/menu-row-identities.d.ts +50 -0
  237. package/lib/types/{runtime → packages/market-runtime/src/runtime}/host/model-catalog.d.ts +1 -1
  238. package/lib/types/packages/market-runtime/src/runtime/host/resource-filter-service.d.ts +34 -0
  239. package/lib/types/packages/market-runtime/src/runtime/host/scoped-contributors.d.ts +58 -0
  240. package/lib/types/packages/market-runtime/src/runtime/host/surface-toggle-service.d.ts +10 -0
  241. package/lib/types/packages/market-runtime/src/runtime/panels/user-commands.d.ts +74 -0
  242. package/lib/types/{runtime → packages/market-runtime/src/runtime}/panels/user-panels.d.ts +7 -1
  243. package/lib/types/packages/market-runtime/src/runtime/surfaces/commands-mounts.d.ts +81 -0
  244. package/lib/types/packages/market-runtime/src/runtime/surfaces/extension-hooks.d.ts +59 -0
  245. package/lib/types/packages/market-runtime/src/runtime/surfaces/hook-dry-run.d.ts +91 -0
  246. package/lib/types/{runtime → packages/market-runtime/src/runtime}/surfaces/hooks-mounts.d.ts +1 -1
  247. package/lib/types/{runtime → packages/market-runtime/src/runtime}/surfaces/project-runtime.d.ts +8 -5
  248. package/lib/types/packages/market-runtime/src/runtime/surfaces/skills-provider.d.ts +71 -0
  249. package/lib/types/packages/market-translation/src/application/state/translation-cache.d.ts +56 -0
  250. package/lib/types/packages/market-translation/src/application/translation/chain.d.ts +47 -0
  251. package/lib/types/packages/market-translation/src/application/translation/document.d.ts +54 -0
  252. package/lib/types/packages/market-translation/src/application/translation/localizer.d.ts +325 -0
  253. package/lib/types/packages/market-translation/src/application/translation/service.d.ts +89 -0
  254. package/lib/types/packages/market-translation/src/application/translation/unit.d.ts +35 -0
  255. package/lib/types/packages/market-translation/src/index.d.ts +4 -0
  256. package/lib/types/packages/market-translation/src/runtime/host/llm-translator.d.ts +30 -0
  257. package/lib/types/packages/market-translation/src/runtime/host/machine-translator.d.ts +52 -0
  258. package/lib/types/packages/market-translation/src/runtime/host/text-masking.d.ts +42 -0
  259. package/lib/types/packages/market-translation/src/runtime/host/translation-providers.d.ts +42 -0
  260. package/locale/en.json +6 -0
  261. package/locale/zh.json +6 -0
  262. package/package.json +47 -10
  263. package/schemas/README.md +4 -4
  264. package/schemas/agent-plugins/spec.md +2 -2
  265. package/schemas/com.deepseek.harness/spec.md +1 -1
  266. package/schemas/skill-collection/spec.md +10 -2
  267. package/lib/application/panel-resources.js +0 -161
  268. package/lib/application/server-config.js +0 -109
  269. package/lib/contracts/settings.js +0 -63
  270. package/lib/runtime/core/reconciler.js +0 -100
  271. package/lib/runtime/panels/user-commands.js +0 -105
  272. package/lib/runtime/surfaces/commands-mounts.js +0 -186
  273. package/lib/runtime/surfaces/skills-provider.js +0 -160
  274. package/lib/types/application/details.d.ts +0 -7
  275. package/lib/types/application/mcp/mcp-status.d.ts +0 -24
  276. package/lib/types/application/panel-resources.d.ts +0 -28
  277. package/lib/types/application/ports.d.ts +0 -86
  278. package/lib/types/application/project-agent-roles.d.ts +0 -3
  279. package/lib/types/contracts/settings.d.ts +0 -59
  280. package/lib/types/routes.d.ts +0 -16
  281. package/lib/types/runtime/core/reconciler.d.ts +0 -58
  282. package/lib/types/runtime/panels/user-commands.d.ts +0 -27
  283. package/lib/types/runtime/surfaces/commands-mounts.d.ts +0 -48
  284. package/lib/types/runtime/surfaces/skills-provider.d.ts +0 -23
  285. /package/lib/{application → packages/market-catalog/src/application}/deadline.js +0 -0
  286. /package/lib/{application → packages/market-catalog/src/application}/json-file.js +0 -0
  287. /package/lib/{application → packages/market-catalog/src/application}/regions.js +0 -0
  288. /package/lib/{catalog → packages/market-catalog/src/scanning}/fs-probes.js +0 -0
  289. /package/lib/{catalog → packages/market-catalog/src/scanning}/git.js +0 -0
  290. /package/lib/{catalog → packages/market-catalog/src/scanning}/lsp-spec.js +0 -0
  291. /package/lib/{catalog → packages/market-catalog/src/scanning}/project-config.js +0 -0
  292. /package/lib/{catalog → packages/market-catalog/src/scanning}/project-hooks.js +0 -0
  293. /package/lib/{catalog → packages/market-catalog/src/scanning}/scan-pipeline.js +0 -0
  294. /package/lib/{catalog → packages/market-catalog/src/scanning}/source-catalog.js +0 -0
  295. /package/lib/{catalog → packages/market-catalog/src/scanning}/suite-components.js +0 -0
  296. /package/lib/{catalog → packages/market-catalog/src/scanning}/suite-scanner.js +0 -0
  297. /package/lib/{catalog → packages/market-catalog/src/scanning}/surfaces.js +0 -0
  298. /package/lib/{contracts → packages/market-contracts/src/contracts}/lsp-status.js +0 -0
  299. /package/lib/{contracts → packages/market-contracts/src/contracts}/lsp.js +0 -0
  300. /package/lib/{contracts → packages/market-contracts/src/contracts}/mcp-status.js +0 -0
  301. /package/lib/{contracts → packages/market-contracts/src/contracts}/mcp.js +0 -0
  302. /package/lib/{runtime → packages/market-contracts/src}/host/plugin-message-source.js +0 -0
  303. /package/lib/{model → packages/market-contracts/src/model}/command-names.js +0 -0
  304. /package/lib/{model → packages/market-contracts/src/model}/preset-source.js +0 -0
  305. /package/lib/{model → packages/market-contracts/src/model}/types.js +0 -0
  306. /package/lib/{application → packages/market-contracts/src/ports}/queries.js +0 -0
  307. /package/lib/{application → packages/market-mcp/src/application}/mcp/mcp-bridge-config.js +0 -0
  308. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/host-contract.js +0 -0
  309. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/host-seams.js +0 -0
  310. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/plugin-identity.js +0 -0
  311. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/projection.js +0 -0
  312. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/transport.js +0 -0
  313. /package/lib/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-credentials.js +0 -0
  314. /package/lib/{application → packages/market-runtime/src/application}/agent-roles.js +0 -0
  315. /package/lib/{runtime → packages/market-runtime/src/runtime}/agents/agent-role-names.js +0 -0
  316. /package/lib/{runtime → packages/market-runtime/src/runtime}/core/context.js +0 -0
  317. /package/lib/{runtime → packages/market-runtime/src/runtime}/core/mount-lifecycle.js +0 -0
  318. /package/lib/{runtime → packages/market-runtime/src/runtime}/core/source-auto-update.js +0 -0
  319. /package/lib/{runtime → packages/market-runtime/src/runtime}/core/timer-seat.js +0 -0
  320. /package/lib/{runtime → packages/market-runtime/src/runtime}/host/model-catalog.js +0 -0
  321. /package/lib/{runtime → packages/market-runtime/src/runtime}/host/shell-path.js +0 -0
  322. /package/lib/{runtime → packages/market-runtime/src/runtime}/host/tool-registry-observer.js +0 -0
  323. /package/lib/{runtime → packages/market-runtime/src/runtime}/surfaces/dynamic-context.js +0 -0
  324. /package/lib/types/{runtime/host → packages/market-bundle/src/platform}/feedback-tool.d.ts +0 -0
  325. /package/lib/types/{application → packages/market-catalog/src/application}/deadline.d.ts +0 -0
  326. /package/lib/types/{application → packages/market-catalog/src/application}/json-file.d.ts +0 -0
  327. /package/lib/types/{application → packages/market-catalog/src/application}/state/storage-migration.d.ts +0 -0
  328. /package/lib/types/{catalog → packages/market-catalog/src/scanning}/fs-probes.d.ts +0 -0
  329. /package/lib/types/{catalog → packages/market-catalog/src/scanning}/git.d.ts +0 -0
  330. /package/lib/types/{catalog → packages/market-catalog/src/scanning}/paths.d.ts +0 -0
  331. /package/lib/types/{catalog → packages/market-catalog/src/scanning}/skills-parse.d.ts +0 -0
  332. /package/lib/types/{contracts → packages/market-contracts/src/contracts}/lsp-status.d.ts +0 -0
  333. /package/lib/types/{contracts → packages/market-contracts/src/contracts}/lsp.d.ts +0 -0
  334. /package/lib/types/{contracts → packages/market-contracts/src/contracts}/mcp.d.ts +0 -0
  335. /package/lib/types/{model → packages/market-contracts/src/model}/command-names.d.ts +0 -0
  336. /package/lib/types/{model → packages/market-contracts/src/model}/preset-source.d.ts +0 -0
  337. /package/lib/types/{application → packages/market-lsp/src/application}/lsp/lsp-server-state.d.ts +0 -0
  338. /package/lib/types/{application → packages/market-lsp/src/application}/lsp/profile-seam.d.ts +0 -0
  339. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/bridge.d.ts +0 -0
  340. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/connection.d.ts +0 -0
  341. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/host-contract.d.ts +0 -0
  342. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/host-seams.d.ts +0 -0
  343. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/oauth.d.ts +0 -0
  344. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/plugin-identity.d.ts +0 -0
  345. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/projection.d.ts +0 -0
  346. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/tools.d.ts +0 -0
  347. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/bridge/transport.d.ts +0 -0
  348. /package/lib/types/{runtime → packages/market-mcp/src/runtime}/mcp/mcp-credentials.d.ts +0 -0
  349. /package/lib/types/{application → packages/market-runtime/src/application}/panels/user-store.d.ts +0 -0
  350. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/agents/agent-role-names.d.ts +0 -0
  351. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/core/context.d.ts +0 -0
  352. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/core/mount-lifecycle.d.ts +0 -0
  353. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/core/source-auto-update.d.ts +0 -0
  354. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/core/timer-seat.d.ts +0 -0
  355. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/host/failure-detail.d.ts +0 -0
  356. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/host/shell-path.d.ts +0 -0
  357. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/host/tool-registry-observer.d.ts +0 -0
  358. /package/lib/types/{runtime → packages/market-runtime/src/runtime}/surfaces/dynamic-context.d.ts +0 -0
@@ -0,0 +1,337 @@
1
+ /** Session-owned selection, cached project readers, tool gates and scoped registration. */
2
+ import { homedir } from 'node:os';
3
+ import { isAbsolute } from 'node:path';
4
+ import { SessionId } from '@deepseek-ai/dsh-session';
5
+ import { pluginPathEnvironment, pluginRootOf, suiteDataDir } from '../../market-catalog/src/index.js';
6
+ import { loadDisabledLspServers } from '../../market-lsp/src/index.js';
7
+ import { HOOK_RUN_NO_COMMAND, HOOK_RUN_SHELL_UNAVAILABLE, HOOK_RUN_UNKNOWN_DECLARATION, ExtensionRuntime, ScopedExtensionContributors, attachExtensionToolGates, extensionWorkspace, hookRunFailure, hookRunShellOf, projectExtensionSuites, readExtensionSuiteDeclarations, runHookDryRun, shellSeamOf, projectAgentRoles } from '../../market-runtime/src/index.js';
8
+ import { createProjectExtensionResources } from './application/extension-project.js';
9
+ import { readExtensionInventory } from './application/extension-inventory.js';
10
+ import { mountExtensionPresetRoutes } from './routes-extension-presets.js';
11
+ import { createMcpMount } from './runtime-adapters.js';
12
+ /** One suite per owner: a second copy would publish the same hook id twice. */
13
+ function dedupeSuites(suites) {
14
+ const byOwner = new Map();
15
+ for (const suite of suites)
16
+ byOwner.set(suite.sourceId + '/' + suite.id, suite);
17
+ return [...byOwner.values()];
18
+ }
19
+ /**
20
+ * The settings Hooks page's read: one row per declared command hook.
21
+ *
22
+ * `enabledUserSuites()` already carries the Agent layout root's synthetic hook
23
+ * suite whenever it declares events, so this read lists that result as it
24
+ * stands: the suite enters once and each declaration publishes one id.
25
+ */
26
+ async function readHookRows(catalog, suites) {
27
+ const rows = await readExtensionInventory({
28
+ catalog: { overview: () => catalog.overview(), mcpStatus: async () => catalog.mcpStatus(), lspStatus: async () => catalog.lspStatus() },
29
+ panels: { skills: { list: async () => [] }, commands: { list: async () => [] }, agents: { list: async () => [] } }
30
+ }, { projectSuites: suites });
31
+ return rows.filter(row => row.face === 'hooks');
32
+ }
33
+ export async function readHooksOverview(catalog) {
34
+ return { rows: await readHookRows(catalog, await catalog.enabledUserSuites()) };
35
+ }
36
+ /**
37
+ * Resolve one dry run's declaration from the same rows the Hooks overview
38
+ * publishes.
39
+ *
40
+ * The caller passes the suites to search, so a session's project hooks join
41
+ * user and installed rows without changing how identity is built. The command
42
+ * comes from the scanned declaration; the request carries identity only.
43
+ * @param catalog - the catalog status reads the overview uses.
44
+ * @param suites - the suites whose hook rows the lookup may match.
45
+ * @param input - the declaration address from the client.
46
+ * @returns the resolved command with its suite, or a stable error code.
47
+ */
48
+ export async function resolveHookDeclaration(catalog, suites, input) {
49
+ const row = (await readHookRows(catalog, suites)).find(candidate => {
50
+ const detail = candidate.detail;
51
+ return detail.kind === 'hook' && detail.sourceId === input.sourceId && detail.suiteId === input.suiteId && detail.event === input.event && detail.hookIndex === input.hookIndex;
52
+ });
53
+ if (row === undefined)
54
+ return { error: HOOK_RUN_UNKNOWN_DECLARATION };
55
+ const detail = row.detail;
56
+ if (detail.kind !== 'hook' || detail.command === undefined || detail.hookIndex === undefined)
57
+ return { error: HOOK_RUN_NO_COMMAND };
58
+ const suite = suites.find(candidate => candidate.sourceId === input.sourceId && candidate.id === input.suiteId);
59
+ if (suite === undefined)
60
+ return { error: HOOK_RUN_UNKNOWN_DECLARATION };
61
+ return { command: detail.command, ...(detail.timeoutSec === undefined ? {} : { timeoutSec: detail.timeoutSec }), suite };
62
+ }
63
+ /**
64
+ * Create the stable readers before catalog initialization. Mount only after its sources are loaded.
65
+ * Call mount once. Host injection owns start and disposal; construction registers nothing.
66
+ */
67
+ export function createSessionExtensions({ ctx, dataRoot, runtime, hostLocale }) {
68
+ let extensionPresets;
69
+ let scopedContributors;
70
+ let selectedRoleSuites;
71
+ let suiteSession;
72
+ let listRoles = async () => ({
73
+ entries: [],
74
+ complete: false
75
+ });
76
+ const mount = ({ catalog, panels, resources, readUserDeclarations }) => {
77
+ ctx.inject(['agents', 'sessions', 'sessionQuery', 'tools'], hostCtx => {
78
+ const eligible = (agent) => {
79
+ const cwd = agent.session.header.cwd;
80
+ return typeof cwd === 'string' && isAbsolute(cwd);
81
+ };
82
+ const gates = new Map();
83
+ const attachGate = (agent) => {
84
+ // An ineligible agent is never gated: the service does not own an agent
85
+ // whose workspace it cannot even read.
86
+ if (!eligible(agent))
87
+ return undefined;
88
+ const mounted = gates.get(agent);
89
+ if (mounted)
90
+ return mounted;
91
+ const gate = attachExtensionToolGates(agent, {
92
+ mcpTools: () => [...runtime.mcpToolOwnership(), ...(scopedContributors?.toolOwnership(agent) ?? [])],
93
+ lspProviders: () => runtime.lsp.providerOwnership(),
94
+ ownsLspTool: () => runtime.lsp.ownsTool()
95
+ }, {
96
+ ready: candidate => extensionRuntime.ready(candidate),
97
+ allows: (candidate, resourceId, suiteId) => extensionRuntime.allows(candidate, resourceId, suiteId)
98
+ });
99
+ gates.set(agent, gate);
100
+ return gate;
101
+ };
102
+ const projectReaders = new Map();
103
+ const getProjectReader = (agent) => {
104
+ const existing = projectReaders.get(agent);
105
+ if (existing !== undefined)
106
+ return existing;
107
+ const created = createProjectExtensionResources(catalog, panels, extensionWorkspace(agent));
108
+ projectReaders.set(agent, created);
109
+ return created;
110
+ };
111
+ const pendingSelections = new Map();
112
+ const readCandidates = async (agent) => {
113
+ const [user, project] = await Promise.all([readUserDeclarations(), catalog.readProjectCatalog(extensionWorkspace(agent))]);
114
+ return [...user, ...(await readExtensionSuiteDeclarations(project.enabledSuites))];
115
+ };
116
+ const selectedSuites = async (agent, selection) => {
117
+ const chosen = selection ?? pendingSelections.get(agent) ?? extensionRuntime.state.read(agent)?.selection;
118
+ if (!chosen)
119
+ return [];
120
+ const enabledIds = [...chosen.enabledIds];
121
+ if (enabledIds.some(id => id.startsWith('mcp:plugin:@user-mcp/user-mcp/')))
122
+ enabledIds.push('market:@user-mcp/user-mcp');
123
+ return projectExtensionSuites(await readCandidates(agent), { ...chosen, enabledIds }).map(row => row.suite);
124
+ };
125
+ const extensionRuntime = new ExtensionRuntime(hostCtx, {
126
+ dataRoot,
127
+ // Only an agent with a real absolute workspace is governed. Every other
128
+ // agent keeps the host's own lifecycle: no selection, no gate, no delay.
129
+ eligible,
130
+ // One reader per agent: it owns panel stores whose row caches must survive
131
+ // across reads, so every caller shares the same instance.
132
+ inventory: async (agent) => {
133
+ const project = getProjectReader(agent);
134
+ const [projectSuites, candidates, backend, lspDisabledIds] = await Promise.all([
135
+ project.suites(),
136
+ readCandidates(agent),
137
+ catalog.mcpBackend(),
138
+ loadDisabledLspServers(dataRoot)
139
+ ]);
140
+ const listedSuites = [...projectSuites, ...candidates.map(row => row.suite).filter(suite => suite.sourceId === '@user-hooks')];
141
+ // Hook rows search one more list than the suite rows: an installed
142
+ // user-dimension suite publishes no hook row of its own, so the
143
+ // manager lists its declarations beside the project and @user-hooks
144
+ // ones. The list stays separate from projectSuites, so project owner
145
+ // addressing is unaffected.
146
+ const hookSuites = dedupeSuites([...projectSuites, ...candidates.map(row => row.suite).filter(suite => suite.dimension === 'user')]);
147
+ const mcpOverrides = await catalog.allMcpOverrides(candidates.map(row => row.suite));
148
+ return readExtensionInventory({
149
+ catalog: {
150
+ overview: () => catalog.overview(),
151
+ mcpStatus: async () => {
152
+ const [global, local] = await Promise.all([catalog.mcpStatus(), project.mcpStatus()]);
153
+ return { ...global, entries: [...global.entries, ...local.entries] };
154
+ },
155
+ lspStatus: async () => {
156
+ const [global, local] = await Promise.all([catalog.lspStatus(), project.lspStatus()]);
157
+ return { ...global, entries: [...global.entries, ...local.entries] };
158
+ }
159
+ },
160
+ panels: Object.fromEntries(['skills', 'commands', 'agents'].map(kind => [
161
+ kind,
162
+ { list: async () => [...(await resources[kind].list(true)), ...(await project.panels[kind].list(true))] }
163
+ ]))
164
+ }, { projectSuites: listedSuites, hookSuites, candidates, mcpOverrides, lspDisabledIds, sessionId: agent.id, mcpSessionControl: backend === 'builtin' });
165
+ },
166
+ // The settings Hooks tab: hook declarations belong to the user Agent
167
+ // layout root. Installed suites' declared hooks join them: the page
168
+ // shows both sources, provenance on every row. The same
169
+ // readExtensionInventory fan-out produces the rows the manager's Hooks
170
+ // tab renders, so both surfaces agree on identity and support verdicts.
171
+ hooksOverview: () => readHooksOverview(catalog),
172
+ // The dry run resolves the declaration from the catalog, then runs it in the
173
+ // home directory. A named session only widens the lookup to that workspace's
174
+ // project hooks; it never supplies the run directory.
175
+ hookRun: async (input) => {
176
+ const suites = [...(await catalog.enabledUserSuites())];
177
+ if (input.sessionId !== undefined) {
178
+ const agent = hostCtx.agents.get(SessionId(input.sessionId));
179
+ const cwd = agent?.session.header.cwd;
180
+ if (typeof cwd === 'string' && isAbsolute(cwd))
181
+ suites.push(...(await catalog.readProjectCatalog(cwd)).suites);
182
+ }
183
+ const resolved = await resolveHookDeclaration(catalog, suites, input);
184
+ if ('error' in resolved)
185
+ return hookRunFailure(resolved.error);
186
+ const shell = hookRunShellOf(shellSeamOf(hostCtx));
187
+ if (shell === undefined)
188
+ return hookRunFailure(HOOK_RUN_SHELL_UNAVAILABLE);
189
+ const root = pluginRootOf(resolved.suite);
190
+ const data = root === undefined ? undefined : suiteDataDir(dataRoot, resolved.suite.sourceId, resolved.suite.id);
191
+ const env = pluginPathEnvironment({
192
+ ...(root === undefined ? {} : { root }),
193
+ ...(data === undefined ? {} : { data }),
194
+ projectDir: homedir()
195
+ });
196
+ return runHookDryRun(shell, resolved.command, {
197
+ event: input.event,
198
+ ...(resolved.timeoutSec === undefined ? {} : { timeoutSec: resolved.timeoutSec }),
199
+ ...(Object.keys(env).length === 0 ? {} : { env })
200
+ });
201
+ },
202
+ // A session change touches that session only: its own contributions and its
203
+ // own gate. The global pipeline belongs to catalog changes, which the change
204
+ // hook drives for every agent.
205
+ applySelection: async (agent, selection) => {
206
+ pendingSelections.set(agent, selection);
207
+ let receipt;
208
+ try {
209
+ const [candidates, globalSuites, suites, backend] = await Promise.all([
210
+ readUserDeclarations(),
211
+ catalog.enabledUserSuites(),
212
+ selectedSuites(agent, selection),
213
+ catalog.mcpBackend()
214
+ ]);
215
+ runtime.setCatalogAuthority(candidates, globalSuites);
216
+ const shared = suites
217
+ .filter(suite => suite.dimension === 'user')
218
+ .map(suite => (backend === 'builtin' ? suite : { ...suite, mcp: undefined, activeSurfaces: { ...suite.activeSurfaces, mcp: false } }));
219
+ receipt = await runtime.stageSessionDemand(agent, shared, selection.enabledIds.filter(id => id.startsWith('lsp:direct/')).map(id => id.slice(4)));
220
+ attachGate(agent)?.refresh();
221
+ await contributors.reconcile(agent, selection);
222
+ return receipt;
223
+ }
224
+ catch (error) {
225
+ try {
226
+ await receipt?.rollback();
227
+ }
228
+ catch (cleanupError) {
229
+ ctx.logger.warn(String(cleanupError));
230
+ }
231
+ throw error;
232
+ }
233
+ finally {
234
+ pendingSelections.delete(agent);
235
+ }
236
+ },
237
+ committed: agent => {
238
+ contributors.committed(agent);
239
+ attachGate(agent)?.refresh();
240
+ },
241
+ ready: async (agent, source) => {
242
+ if (!eligible(agent))
243
+ return;
244
+ attachGate(agent)?.refresh();
245
+ if (!extensionRuntime.ready(agent))
246
+ return;
247
+ await contributors.ready(agent, source);
248
+ }
249
+ });
250
+ const contributors = new ScopedExtensionContributors({
251
+ mcpMounts: createMcpMount,
252
+ dataRoot,
253
+ catalog,
254
+ // Resolved lazily: the seam reader below is declared later in this scope,
255
+ // and the agents fiber can activate before that declaration runs.
256
+ shell: () => shellSeamOf(ctx),
257
+ allows: (agent, resourceId, suiteId) => extensionRuntime.allows(agent, resourceId, suiteId),
258
+ registrationAllows: (agent, resourceId) => extensionRuntime.registrationAllows(agent, resourceId),
259
+ panels,
260
+ suites: agent => selectedSuites(agent),
261
+ hostContext: hostCtx,
262
+ t: key => hostLocale.t(key)
263
+ });
264
+ scopedContributors = contributors;
265
+ selectedRoleSuites = agent => selectedSuites(agent);
266
+ hostCtx.on('agent/disposed', ({ agent }) => {
267
+ gates.get(agent)?.dispose();
268
+ gates.delete(agent);
269
+ projectReaders.delete(agent);
270
+ pendingSelections.delete(agent);
271
+ void runtime.releaseSessionDemand(agent).catch(error => ctx.logger.warn(String(error)));
272
+ void contributors.dispose(agent).catch(error => ctx.logger.warn('extension disposal: ' + String(error)));
273
+ });
274
+ // The route resolver shares the very same per-agent reader as the inventory,
275
+ // so a detail read and an inventory read never build two panel caches.
276
+ suiteSession = {
277
+ agent: sessionId => hostCtx.agents.get(SessionId(sessionId)),
278
+ project: getProjectReader
279
+ };
280
+ hostCtx.effect(() => () => {
281
+ projectReaders.clear();
282
+ }, 'dsh-agent-plugins-market: project readers');
283
+ hostCtx.inject(['webServer', 'loader'], webCtx => {
284
+ webCtx.effect(() => mountExtensionPresetRoutes(webCtx, extensionRuntime), 'dsh-agent-plugins-market: extension preset routes');
285
+ });
286
+ hostCtx.effect(() => {
287
+ extensionPresets = extensionRuntime;
288
+ for (const agent of hostCtx.agents.list())
289
+ attachGate(agent);
290
+ void extensionRuntime.start().catch(error => {
291
+ ctx.logger?.warn?.('[dsh-agent-plugins-market] extension presets: ' + (error instanceof Error ? error.message : String(error)));
292
+ });
293
+ return async () => {
294
+ if (extensionPresets === extensionRuntime)
295
+ extensionPresets = undefined;
296
+ if (scopedContributors === contributors)
297
+ scopedContributors = undefined;
298
+ await extensionRuntime.dispose();
299
+ await contributors.disposeAll();
300
+ for (const gate of gates.values())
301
+ gate.dispose();
302
+ gates.clear();
303
+ };
304
+ }, 'dsh-agent-plugins-market: extension presets');
305
+ });
306
+ listRoles = async (parent) => {
307
+ const agent = parent;
308
+ // "Not ready" is not "no roles": the extension runtime may still be
309
+ // initializing or recovering, so an empty answer must not replace the
310
+ // published catalog. A read failure propagates for the same reason, and
311
+ // the catalog publisher turns both into "no new information".
312
+ if (!agent || !extensionPresets?.ready(agent))
313
+ return { entries: [], complete: false };
314
+ const user = (await resources.agents.list(true))
315
+ .filter(entry => entry.origin === 'user' && extensionPresets?.allows(agent, 'agents:' + (entry.id ?? entry.name)))
316
+ .map(entry => ({ ...entry, title: entry.name, name: entry.id ?? entry.name, selectionEnabled: true }));
317
+ const project = await projectAgentRoles(catalog, parent, {
318
+ suites: () => selectedRoleSuites?.(agent) ?? Promise.resolve([]),
319
+ selected: role => extensionPresets?.allows(agent, 'agents:' + role.name) === true
320
+ });
321
+ return { entries: [...user, ...project], complete: true };
322
+ };
323
+ };
324
+ return {
325
+ mount,
326
+ /** Preserve revocation before default-provider invalidation and contributor refresh. */
327
+ invalidate(invalidateDefaultSkills) {
328
+ extensionPresets?.invalidate();
329
+ invalidateDefaultSkills();
330
+ scopedContributors?.invalidateAll();
331
+ },
332
+ refresh: () => extensionPresets?.refreshAll(),
333
+ commandRegistrations: () => scopedContributors?.registrations() ?? [],
334
+ roles: (parent) => listRoles(parent),
335
+ session: () => suiteSession
336
+ };
337
+ }
@@ -8,11 +8,11 @@
8
8
  * notification path — have a single owner.
9
9
  */
10
10
  import { join } from 'node:path';
11
- import { MARKET_SETTINGS_DEFAULTS } from '../contracts/settings.js';
12
- import { STATE_FILE_NAME } from '../catalog/paths.js';
11
+ import { MARKET_SETTINGS_DEFAULTS } from '../../../market-contracts/src/contracts/settings.js';
12
+ import { STATE_FILE_NAME } from '../scanning/paths.js';
13
13
  import { settlesWithin } from './deadline.js';
14
14
  import { EMPTY_STATE, loadState, saveState } from './state/state-store.js';
15
- import { effectiveSurfaces } from '../model/types.js';
15
+ import { effectiveSurfaces } from '../../../market-contracts/src/model/types.js';
16
16
  import { SCAN_CACHE_TTL_MS, SnapshotCache } from './snapshot-cache.js';
17
17
  /** Key of one install entry in the persisted `installed` record. */
18
18
  export function installKey(sourceId, suiteId) {
@@ -46,6 +46,8 @@ export class CatalogContext {
46
46
  git;
47
47
  /** Discovery scans and dimension snapshots derived from {@link state}. */
48
48
  snapshots;
49
+ /** The clock every TTL and window in this context is measured against. */
50
+ now;
49
51
  onChanged;
50
52
  constructor(options) {
51
53
  this.statePath = join(options.userRoot, STATE_FILE_NAME);
@@ -54,10 +56,11 @@ export class CatalogContext {
54
56
  this.agentsRoot = options.agentsRoot;
55
57
  this.git = options.git ?? {};
56
58
  this.onChanged = options.onChanged;
59
+ this.now = options.now ?? Date.now;
57
60
  this.snapshots = new SnapshotCache(this, {
58
61
  user: options.userSnapshotTtlMs ?? SCAN_CACHE_TTL_MS,
59
62
  project: options.projectSnapshotTtlMs ?? 5_000
60
- });
63
+ }, this.now);
61
64
  }
62
65
  get state() {
63
66
  return this.currentState;
@@ -6,9 +6,9 @@
6
6
  * The checkout a suite is read from stays source-owned: installing writes an
7
7
  * entry, never a file inside the source.
8
8
  */
9
- import { isDirectory } from '../catalog/fs-probes.js';
10
- import { discoverSuitesInSource } from '../catalog/suite-scanner.js';
11
- import { SUITE_SURFACE_KEYS } from '../model/types.js';
9
+ import { isDirectory } from '../scanning/fs-probes.js';
10
+ import { discoverSuitesInSource } from '../scanning/suite-scanner.js';
11
+ import { SUITE_SURFACE_KEYS } from '../../../market-contracts/src/model/types.js';
12
12
  import { installKey } from './catalog-context.js';
13
13
  import { tryHead } from './source-store.js';
14
14
  export class InstallStore {
@@ -10,25 +10,53 @@
10
10
  * for in-place working-tree edits of local sources.
11
11
  */
12
12
  import { join, resolve } from 'node:path';
13
- import { resolveProjectRoot, STATE_FILE_NAME } from '../catalog/paths.js';
14
- import { discoverSourceListWithNotes } from '../catalog/source-catalog.js';
13
+ import { resolveProjectRoot, STATE_FILE_NAME } from '../scanning/paths.js';
14
+ import { discoverSourceListWithNotes } from '../scanning/source-catalog.js';
15
15
  import { loadState } from './state/state-store.js';
16
16
  export const SCAN_CACHE_TTL_MS = 30_000;
17
17
  const SCAN_CACHE_MAX_ENTRIES = 8;
18
+ /**
19
+ * When the background refresh of the user snapshot runs, as a fraction of its
20
+ * TTL. Refreshing before the snapshot expires is what keeps the TTL a
21
+ * *staleness* bound rather than a cost every read pays: a read arriving after
22
+ * the refresh lands is served from the cache, where it used to trigger the
23
+ * whole discovery scan itself.
24
+ */
25
+ const USER_REFRESH_LEAD_RATIO = 0.8;
26
+ /**
27
+ * How long the background refresh keeps running after the last user-dimension
28
+ * read, in TTLs. The TTL exists to bound how long an out-of-band working-tree
29
+ * edit stays invisible, so the refresh has to stay frequent while the catalog
30
+ * is in use; this multiple is what stops it from scanning a 2,500-suite
31
+ * catalog forever once nobody is reading. A read after the window pays exactly
32
+ * one scan — the cost every read paid before the window existed — and warms
33
+ * the cache up again.
34
+ */
35
+ const USER_KEEP_WARM_TTL_MULTIPLE = 10;
18
36
  export class SnapshotCache {
19
37
  host;
20
38
  ttls;
39
+ now;
21
40
  scanCache = new Map();
22
41
  scanPromises = new Map();
23
42
  userSnapshot;
24
43
  userSnapshotExpiresAt = 0;
25
44
  userSnapshotPromise;
45
+ /** The armed keep-warm refresh, or undefined when none is scheduled. */
46
+ userRefreshTimer;
47
+ /** Set by {@link dispose}: the keep-warm chain is over and never re-arms. */
48
+ disposed = false;
49
+ /** When the user dimension was last read; the keep-warm window closes from here. */
50
+ lastUserReadAt = 0;
26
51
  /** Project-dimension snapshots keyed by project root, with TTL freshness. */
27
52
  projectSnapshots = new Map();
28
53
  projectSnapshotPromises = new Map();
29
- constructor(host, ttls) {
54
+ constructor(host, ttls,
55
+ /** Clock seam; tests drive TTL expiry, the scan cache, and the idle window through it. */
56
+ now = Date.now) {
30
57
  this.host = host;
31
58
  this.ttls = ttls;
59
+ this.now = now;
32
60
  }
33
61
  /** Read one coherent user-dimension snapshot, reusing in-flight discovery. */
34
62
  async readUserCatalog() {
@@ -36,17 +64,31 @@ export class SnapshotCache {
36
64
  // mirroring the project dimension's caching-disabled semantics.
37
65
  if (this.ttls.user <= 0)
38
66
  return this.build(this.host.state, 'user', this.host.userRoot);
39
- if (this.userSnapshot !== undefined && Date.now() < this.userSnapshotExpiresAt)
40
- return this.userSnapshot;
67
+ this.lastUserReadAt = this.now();
68
+ const snapshot = await this.loadUserSnapshot(false);
69
+ this.armUserRefresh();
70
+ return snapshot;
71
+ }
72
+ /**
73
+ * Build the user snapshot, or join the build already in flight.
74
+ *
75
+ * `forceRescan` is the keep-warm refresh's entry point: it re-reads the
76
+ * working tree even while the discovery cache would still answer, because
77
+ * replaying that cache would let one scan outlive the freshness bound the
78
+ * TTL states.
79
+ */
80
+ loadUserSnapshot(forceRescan) {
81
+ if (!forceRescan && this.userSnapshot !== undefined && this.now() < this.userSnapshotExpiresAt)
82
+ return Promise.resolve(this.userSnapshot);
41
83
  if (this.userSnapshotPromise !== undefined)
42
84
  return this.userSnapshotPromise;
43
85
  const revision = this.host.revision;
44
86
  const generation = this.host.scanGeneration;
45
- const promise = this.build(this.host.state, 'user', this.host.userRoot)
87
+ const promise = this.build(this.host.state, 'user', this.host.userRoot, forceRescan)
46
88
  .then(snapshot => {
47
89
  if (revision === this.host.revision && generation === this.host.scanGeneration) {
48
90
  this.userSnapshot = snapshot;
49
- this.userSnapshotExpiresAt = Date.now() + this.ttls.user;
91
+ this.userSnapshotExpiresAt = this.now() + this.ttls.user;
50
92
  }
51
93
  return snapshot;
52
94
  })
@@ -57,6 +99,36 @@ export class SnapshotCache {
57
99
  this.userSnapshotPromise = promise;
58
100
  return promise;
59
101
  }
102
+ /**
103
+ * Keep the user snapshot warm while the catalog is in use.
104
+ *
105
+ * Without this, the first read after the TTL lapses pays the full discovery
106
+ * scan — the normal case for a panel opened minutes apart. The refresh runs
107
+ * {@link USER_REFRESH_LEAD_RATIO} of the TTL before the snapshot expires, so
108
+ * a read never waits for it, and it is armed by reads: the chain ends
109
+ * {@link USER_KEEP_WARM_TTL_MULTIPLE} TTLs after the last one.
110
+ */
111
+ armUserRefresh() {
112
+ if (this.disposed || this.ttls.user <= 0 || this.userRefreshTimer !== undefined)
113
+ return;
114
+ const delay = Math.max(1, Math.round(this.ttls.user * USER_REFRESH_LEAD_RATIO));
115
+ const timer = setTimeout(() => {
116
+ if (this.userRefreshTimer === timer)
117
+ this.userRefreshTimer = undefined;
118
+ this.refreshUserSnapshot();
119
+ }, delay);
120
+ // A waiting refresh must not hold the host process open.
121
+ timer.unref?.();
122
+ this.userRefreshTimer = timer;
123
+ }
124
+ /** Run one background refresh unless the catalog has been idle past its window. */
125
+ refreshUserSnapshot() {
126
+ if (this.disposed || this.now() - this.lastUserReadAt > this.ttls.user * USER_KEEP_WARM_TTL_MULTIPLE)
127
+ return;
128
+ void this.loadUserSnapshot(true)
129
+ .catch(() => undefined)
130
+ .finally(() => this.armUserRefresh());
131
+ }
60
132
  /** Read one coherent project-dimension snapshot for a workspace cwd. */
61
133
  async readProjectCatalog(cwd) {
62
134
  const projectRoot = await resolveProjectRoot(cwd);
@@ -70,7 +142,7 @@ export class SnapshotCache {
70
142
  if (this.ttls.project <= 0)
71
143
  return this.buildProjectSnapshot(projectRoot);
72
144
  const cached = this.projectSnapshots.get(projectRoot);
73
- if (cached !== undefined && cached.expiresAt > Date.now())
145
+ if (cached !== undefined && cached.expiresAt > this.now())
74
146
  return cached.snapshot;
75
147
  const inFlight = this.projectSnapshotPromises.get(projectRoot);
76
148
  if (inFlight !== undefined)
@@ -80,7 +152,7 @@ export class SnapshotCache {
80
152
  const promise = this.buildProjectSnapshot(projectRoot)
81
153
  .then(snapshot => {
82
154
  if (revision === this.host.revision && generation === this.host.scanGeneration) {
83
- this.projectSnapshots.set(projectRoot, { snapshot, expiresAt: Date.now() + this.ttls.project });
155
+ this.projectSnapshots.set(projectRoot, { snapshot, expiresAt: this.now() + this.ttls.project });
84
156
  }
85
157
  return snapshot;
86
158
  })
@@ -98,7 +170,7 @@ export class SnapshotCache {
98
170
  // The user snapshot's TTL also bounds scan reuse: a snapshot rebuild that
99
171
  // replays a 30s scan cache would silently outlive its own staleness bound.
100
172
  const scanCacheTtl = dimension === 'user' ? Math.min(this.ttls.user, SCAN_CACHE_TTL_MS) : SCAN_CACHE_TTL_MS;
101
- const cacheFresh = !skipScanCache && cached !== undefined && Date.now() - cached.at < scanCacheTtl;
173
+ const cacheFresh = !skipScanCache && cached !== undefined && this.now() - cached.at < scanCacheTtl;
102
174
  let discovered;
103
175
  let scanNotes;
104
176
  if (cacheFresh && cached !== undefined) {
@@ -126,7 +198,7 @@ export class SnapshotCache {
126
198
  if (generation === this.host.scanGeneration) {
127
199
  if (this.scanCache.size >= SCAN_CACHE_MAX_ENTRIES)
128
200
  this.scanCache.clear();
129
- this.scanCache.set(fingerprint, { at: Date.now(), discovered, scanNotes });
201
+ this.scanCache.set(fingerprint, { at: this.now(), discovered, scanNotes });
130
202
  }
131
203
  }
132
204
  const suites = this.host.project(discovered, state, dimension);
@@ -146,6 +218,23 @@ export class SnapshotCache {
146
218
  this.projectSnapshots.clear();
147
219
  this.projectSnapshotPromises.clear();
148
220
  }
221
+ /**
222
+ * End the keep-warm refresh for good.
223
+ *
224
+ * Clearing the armed timer is not enough on its own: a refresh already in
225
+ * flight re-arms through its own `.finally()`, so a teardown landing while
226
+ * one runs would leave the chain scanning the whole catalog every 0.8 TTL
227
+ * with nobody reading it. Disposal is therefore terminal — the chain end is
228
+ * checked before it arms and before it runs — and reads after it still answer
229
+ * from the cache or rebuild one, they just no longer keep it warm.
230
+ */
231
+ dispose() {
232
+ this.disposed = true;
233
+ if (this.userRefreshTimer !== undefined) {
234
+ clearTimeout(this.userRefreshTimer);
235
+ this.userRefreshTimer = undefined;
236
+ }
237
+ }
149
238
  /** Drop cached discovery and its in-flight dedupe slots. */
150
239
  invalidateScans() {
151
240
  this.scanCache.clear();
@@ -9,14 +9,14 @@
9
9
  */
10
10
  import { mkdir, readdir, rename } from 'node:fs/promises';
11
11
  import { join } from 'node:path';
12
- import { archiveInstall } from '../catalog/archive.js';
13
- import { gitClone, gitCurrentBranch, gitHead, gitRemoteUrl, gitRemove, gitSetRemoteUrl, gitSync } from '../catalog/git.js';
14
- import { repoName } from '../catalog/manifests.js';
15
- import { deriveSourceIdCandidates, expandHome, sanitizeId, sourceCheckoutDir, sourcesDir } from '../catalog/paths.js';
16
- import { isDirectory, pathExists } from '../catalog/fs-probes.js';
17
- import { canonicalGitUrl } from '../catalog/scan-resolvers.js';
12
+ import { archiveInstall } from '../scanning/archive.js';
13
+ import { gitClone, gitCurrentBranch, gitHead, gitRemoteUrl, gitRemove, gitSetRemoteUrl, gitSync } from '../scanning/git.js';
14
+ import { repoName } from '../scanning/manifests.js';
15
+ import { deriveSourceIdCandidates, expandHome, sanitizeId, sourceCheckoutDir, sourcesDir } from '../scanning/paths.js';
16
+ import { isDirectory, pathExists } from '../scanning/fs-probes.js';
17
+ import { canonicalGitUrl } from '../scanning/scan-resolvers.js';
18
18
  import { githubCloneUrl, resolveRegion } from './regions.js';
19
- import { resolveSourceKind } from '../model/types.js';
19
+ import { resolveSourceKind } from '../../../market-contracts/src/model/types.js';
20
20
  export class SourceStore {
21
21
  context;
22
22
  ports;
@@ -224,6 +224,10 @@ export class SourceStore {
224
224
  async refresh(sourceId) {
225
225
  return this.context.enqueue(async () => {
226
226
  const targets = sourceId === undefined ? this.context.state.sources : this.context.state.sources.filter(source => source.id === sourceId);
227
+ // One route for the whole pass: resolving it reads the host locale
228
+ // preference, so asking per source made a refresh of N sources pay N
229
+ // whole-profile projections.
230
+ const route = await this.downloadRoute();
227
231
  for (const source of targets) {
228
232
  const kind = resolveSourceKind(source);
229
233
  if (kind === 'local') {
@@ -279,8 +283,7 @@ export class SourceStore {
279
283
  // source.url) are re-pointed — a foreign remote is left untouched.
280
284
  if (source.kind === 'git' || (source.kind === undefined && source.local !== true)) {
281
285
  try {
282
- const region = resolveRegion(await this.ports.downloadRegion(), this.ports.localePreference());
283
- const routed = githubCloneUrl(region, source.url);
286
+ const routed = githubCloneUrl(route, source.url);
284
287
  const origin = await gitRemoteUrl(checkout);
285
288
  if (origin !== routed && (origin === source.url || origin === githubCloneUrl('china', source.url))) {
286
289
  await gitSetRemoteUrl(checkout, routed);
@@ -301,6 +304,17 @@ export class SourceStore {
301
304
  await this.context.notifyChanged();
302
305
  });
303
306
  }
307
+ /**
308
+ * The download route one acquisition pass applies to its sources.
309
+ *
310
+ * Reading it resolves the host locale preference, which the host answers by
311
+ * projecting every active profile entry's live configuration. A pass over
312
+ * several sources reads it once and reuses the value, so a refresh's cost
313
+ * follows its work instead of its source count.
314
+ */
315
+ async downloadRoute() {
316
+ return resolveRegion(await this.ports.downloadRegion(), this.ports.localePreference());
317
+ }
304
318
  /** Progress snapshot for the progress route. */
305
319
  progress() {
306
320
  const state = this.currentSourceState;
@@ -400,8 +414,7 @@ export class SourceStore {
400
414
  try {
401
415
  // The region routes github.com clones through the China mirror prefix;
402
416
  // the proxied URL becomes `origin`, so refreshes follow the same route.
403
- const region = resolveRegion(await this.ports.downloadRegion(), this.ports.localePreference());
404
- await gitClone(githubCloneUrl(region, source.url), source.branch, checkout, this.context.git);
417
+ await gitClone(githubCloneUrl(await this.downloadRoute(), source.url), source.branch, checkout, this.context.git);
405
418
  return undefined;
406
419
  }
407
420
  catch (error) {
@@ -8,7 +8,7 @@
8
8
  * in `src/model/types.ts`; only the reading and writing live here.
9
9
  */
10
10
  import { readJsonFile, writeJsonDocument } from '../json-file.js';
11
- import { SUITE_SURFACE_KEYS } from '../../model/types.js';
11
+ import { SUITE_SURFACE_KEYS } from '../../../../market-contracts/src/model/types.js';
12
12
  export const EMPTY_STATE = { version: 1, sources: [], installed: {} };
13
13
  /** Parse persisted state; unreadable or wrong-version files yield a contained empty state. */
14
14
  export async function loadState(statePath) {