@ai-agent-forge/agent-forge 0.86.7 → 0.87.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 (665) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +8 -9
  3. package/dist/artifacts/artifact-store.d.ts.map +1 -1
  4. package/dist/artifacts/artifact-store.js +9 -5
  5. package/dist/artifacts/artifact-store.js.map +1 -1
  6. package/dist/bundle/.build-manifest.json +410 -371
  7. package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
  8. package/dist/bundle/chunks/chunk-BFC2BDVJ.js +13 -0
  9. package/dist/bundle/chunks/chunk-MOHOLL3F.js +1456 -0
  10. package/dist/bundle/chunks/image-resize-worker.js +12 -1
  11. package/dist/bundle/chunks/{virtual-modules-3IZ4MYSQ.js → virtual-modules-KZ5DRH7Q.js} +1 -1
  12. package/dist/bundle/cli.js +1 -1
  13. package/dist/bundle/client.js +1 -1
  14. package/dist/bundle/index.js +2 -2
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/cli/args.d.ts.map +1 -1
  17. package/dist/cli/args.js +231 -185
  18. package/dist/cli/args.js.map +1 -1
  19. package/dist/cli/auth-check.d.ts.map +1 -1
  20. package/dist/cli/auth-check.js +3 -2
  21. package/dist/cli/auth-check.js.map +1 -1
  22. package/dist/cli/auth-command.d.ts.map +1 -1
  23. package/dist/cli/auth-command.js +15 -9
  24. package/dist/cli/auth-command.js.map +1 -1
  25. package/dist/cli/credential-print.d.ts.map +1 -1
  26. package/dist/cli/credential-print.js +14 -7
  27. package/dist/cli/credential-print.js.map +1 -1
  28. package/dist/cli/experimental/command.d.ts.map +1 -1
  29. package/dist/cli/experimental/command.js +6 -5
  30. package/dist/cli/experimental/command.js.map +1 -1
  31. package/dist/cli/list-models.d.ts.map +1 -1
  32. package/dist/cli/list-models.js +9 -8
  33. package/dist/cli/list-models.js.map +1 -1
  34. package/dist/cli/plugin-manager-controller.d.ts.map +1 -1
  35. package/dist/cli/plugin-manager-controller.js +2 -1
  36. package/dist/cli/plugin-manager-controller.js.map +1 -1
  37. package/dist/cli/serve.d.ts.map +1 -1
  38. package/dist/cli/serve.js +8 -5
  39. package/dist/cli/serve.js.map +1 -1
  40. package/dist/client/remote-session.d.ts.map +1 -1
  41. package/dist/client/remote-session.js +16 -9
  42. package/dist/client/remote-session.js.map +1 -1
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +2 -1
  45. package/dist/config.js.map +1 -1
  46. package/dist/core/agent-capability-contract.d.ts +0 -7
  47. package/dist/core/agent-capability-contract.d.ts.map +1 -1
  48. package/dist/core/agent-capability-contract.js +72 -68
  49. package/dist/core/agent-capability-contract.js.map +1 -1
  50. package/dist/core/agent-session-bash.d.ts.map +1 -1
  51. package/dist/core/agent-session-bash.js +5 -4
  52. package/dist/core/agent-session-bash.js.map +1 -1
  53. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  54. package/dist/core/agent-session-compaction.js +28 -22
  55. package/dist/core/agent-session-compaction.js.map +1 -1
  56. package/dist/core/agent-session-context.d.ts.map +1 -1
  57. package/dist/core/agent-session-context.js +18 -13
  58. package/dist/core/agent-session-context.js.map +1 -1
  59. package/dist/core/agent-session-model.d.ts.map +1 -1
  60. package/dist/core/agent-session-model.js +2 -1
  61. package/dist/core/agent-session-model.js.map +1 -1
  62. package/dist/core/agent-session-retry.d.ts.map +1 -1
  63. package/dist/core/agent-session-retry.js +3 -2
  64. package/dist/core/agent-session-retry.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  66. package/dist/core/agent-session-runtime.js +7 -6
  67. package/dist/core/agent-session-runtime.js.map +1 -1
  68. package/dist/core/agent-session-services.d.ts +1 -1
  69. package/dist/core/agent-session-services.d.ts.map +1 -1
  70. package/dist/core/agent-session-services.js.map +1 -1
  71. package/dist/core/agent-session-tools.d.ts.map +1 -1
  72. package/dist/core/agent-session-tools.js +3 -2
  73. package/dist/core/agent-session-tools.js.map +1 -1
  74. package/dist/core/agent-session.d.ts +40 -2
  75. package/dist/core/agent-session.d.ts.map +1 -1
  76. package/dist/core/agent-session.js +142 -34
  77. package/dist/core/agent-session.js.map +1 -1
  78. package/dist/core/auth-guidance.d.ts.map +1 -1
  79. package/dist/core/auth-guidance.js +11 -5
  80. package/dist/core/auth-guidance.js.map +1 -1
  81. package/dist/core/auth-storage.d.ts.map +1 -1
  82. package/dist/core/auth-storage.js +9 -6
  83. package/dist/core/auth-storage.js.map +1 -1
  84. package/dist/core/compaction/compaction.d.ts.map +1 -1
  85. package/dist/core/compaction/compaction.js +2 -1
  86. package/dist/core/compaction/compaction.js.map +1 -1
  87. package/dist/core/embedded-sdk.d.ts.map +1 -1
  88. package/dist/core/embedded-sdk.js +10 -6
  89. package/dist/core/embedded-sdk.js.map +1 -1
  90. package/dist/core/export-html/index.d.ts.map +1 -1
  91. package/dist/core/export-html/index.js +9 -4
  92. package/dist/core/export-html/index.js.map +1 -1
  93. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  94. package/dist/core/extensions/agent-composition.js +26 -19
  95. package/dist/core/extensions/agent-composition.js.map +1 -1
  96. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  97. package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
  98. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  99. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  100. package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
  101. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  102. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
  103. package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
  104. package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
  105. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
  106. package/dist/core/extensions/bootstrap-retry-policy.js +2 -1
  107. package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
  108. package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
  109. package/dist/core/extensions/bootstrap-skills.js +7 -6
  110. package/dist/core/extensions/bootstrap-skills.js.map +1 -1
  111. package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
  112. package/dist/core/extensions/bootstrap-tools.js +2 -1
  113. package/dist/core/extensions/bootstrap-tools.js.map +1 -1
  114. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  115. package/dist/core/extensions/capability-plugin.js +37 -13
  116. package/dist/core/extensions/capability-plugin.js.map +1 -1
  117. package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
  118. package/dist/core/extensions/capability-runtime-events.js +17 -13
  119. package/dist/core/extensions/capability-runtime-events.js.map +1 -1
  120. package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
  121. package/dist/core/extensions/capability-runtime-guards.js +16 -15
  122. package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
  123. package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
  124. package/dist/core/extensions/capability-runtime-manifest.js +52 -30
  125. package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
  126. package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
  127. package/dist/core/extensions/capability-runtime-validation.js +66 -65
  128. package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
  129. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  130. package/dist/core/extensions/capability-runtime.js +147 -127
  131. package/dist/core/extensions/capability-runtime.js.map +1 -1
  132. package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
  133. package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
  134. package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
  135. package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
  136. package/dist/core/extensions/context-strategy-binding.js +7 -4
  137. package/dist/core/extensions/context-strategy-binding.js.map +1 -1
  138. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  139. package/dist/core/extensions/lifecycle-catalog.js +290 -279
  140. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  141. package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
  142. package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
  143. package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
  144. package/dist/core/facade/coding-agent-facade.d.ts +6 -0
  145. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  146. package/dist/core/facade/coding-agent-facade.js +2 -0
  147. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  148. package/dist/core/http-dispatcher.d.ts.map +1 -1
  149. package/dist/core/http-dispatcher.js +2 -1
  150. package/dist/core/http-dispatcher.js.map +1 -1
  151. package/dist/core/i18n/index.d.ts +14 -0
  152. package/dist/core/i18n/index.d.ts.map +1 -0
  153. package/dist/core/i18n/index.js +67 -0
  154. package/dist/core/i18n/index.js.map +1 -0
  155. package/dist/core/i18n/locales/en/example.d.ts +7 -0
  156. package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
  157. package/dist/core/i18n/locales/en/example.js +7 -0
  158. package/dist/core/i18n/locales/en/example.js.map +1 -0
  159. package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
  160. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
  161. package/dist/core/i18n/locales/zh-cn/cli.js +227 -0
  162. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
  163. package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
  164. package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
  165. package/dist/core/i18n/locales/zh-cn/common.js +6 -0
  166. package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
  167. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
  168. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
  169. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
  170. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
  171. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
  172. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
  173. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
  174. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
  175. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
  176. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
  177. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
  178. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
  179. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
  180. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
  181. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
  182. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
  183. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
  184. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
  185. package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
  186. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
  187. package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
  188. package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
  189. package/dist/core/i18n/locales/zh-cn/example.js +10 -0
  190. package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
  191. package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
  192. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
  193. package/dist/core/i18n/locales/zh-cn/index.js +41 -0
  194. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
  195. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
  196. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
  197. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +265 -0
  198. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
  199. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
  200. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
  201. package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
  202. package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
  203. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
  204. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
  205. package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
  206. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
  207. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
  208. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
  209. package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
  210. package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
  211. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
  212. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
  213. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
  214. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
  215. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
  216. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
  217. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +288 -0
  218. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
  219. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
  220. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
  221. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
  222. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
  223. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
  224. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
  225. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
  226. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
  227. package/dist/core/keybindings.d.ts +15 -0
  228. package/dist/core/keybindings.d.ts.map +1 -1
  229. package/dist/core/keybindings.js +18 -0
  230. package/dist/core/keybindings.js.map +1 -1
  231. package/dist/core/logger.d.ts.map +1 -1
  232. package/dist/core/logger.js +5 -1
  233. package/dist/core/logger.js.map +1 -1
  234. package/dist/core/model-registry.d.ts.map +1 -1
  235. package/dist/core/model-registry.js +2 -1
  236. package/dist/core/model-registry.js.map +1 -1
  237. package/dist/core/model-runtime.d.ts.map +1 -1
  238. package/dist/core/model-runtime.js +8 -4
  239. package/dist/core/model-runtime.js.map +1 -1
  240. package/dist/core/package-install-host.d.ts.map +1 -1
  241. package/dist/core/package-install-host.js +4 -3
  242. package/dist/core/package-install-host.js.map +1 -1
  243. package/dist/core/package-manager.d.ts.map +1 -1
  244. package/dist/core/package-manager.js +15 -10
  245. package/dist/core/package-manager.js.map +1 -1
  246. package/dist/core/package-resource-collection.d.ts.map +1 -1
  247. package/dist/core/package-resource-collection.js +2 -1
  248. package/dist/core/package-resource-collection.js.map +1 -1
  249. package/dist/core/package-source.d.ts.map +1 -1
  250. package/dist/core/package-source.js +3 -2
  251. package/dist/core/package-source.js.map +1 -1
  252. package/dist/core/provider-composer.d.ts.map +1 -1
  253. package/dist/core/provider-composer.js +22 -13
  254. package/dist/core/provider-composer.js.map +1 -1
  255. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  256. package/dist/core/remote-catalog-provider.js +6 -2
  257. package/dist/core/remote-catalog-provider.js.map +1 -1
  258. package/dist/core/resolve-config-value.d.ts.map +1 -1
  259. package/dist/core/resolve-config-value.js +15 -5
  260. package/dist/core/resolve-config-value.js.map +1 -1
  261. package/dist/core/sdk.d.ts +19 -5
  262. package/dist/core/sdk.d.ts.map +1 -1
  263. package/dist/core/sdk.js +74 -54
  264. package/dist/core/sdk.js.map +1 -1
  265. package/dist/core/session-cwd.d.ts.map +1 -1
  266. package/dist/core/session-cwd.js +5 -2
  267. package/dist/core/session-cwd.js.map +1 -1
  268. package/dist/core/session-export.d.ts.map +1 -1
  269. package/dist/core/session-export.js +2 -1
  270. package/dist/core/session-export.js.map +1 -1
  271. package/dist/core/session-manager.d.ts.map +1 -1
  272. package/dist/core/session-manager.js +39 -29
  273. package/dist/core/session-manager.js.map +1 -1
  274. package/dist/core/session-storage.d.ts.map +1 -1
  275. package/dist/core/session-storage.js +3 -3
  276. package/dist/core/session-storage.js.map +1 -1
  277. package/dist/core/settings-manager.d.ts +11 -0
  278. package/dist/core/settings-manager.d.ts.map +1 -1
  279. package/dist/core/settings-manager.js +27 -5
  280. package/dist/core/settings-manager.js.map +1 -1
  281. package/dist/core/slash-commands.d.ts.map +1 -1
  282. package/dist/core/slash-commands.js +53 -32
  283. package/dist/core/slash-commands.js.map +1 -1
  284. package/dist/core/system-prompt.d.ts.map +1 -1
  285. package/dist/core/system-prompt.js +25 -2
  286. package/dist/core/system-prompt.js.map +1 -1
  287. package/dist/core/tools/bash.d.ts.map +1 -1
  288. package/dist/core/tools/bash.js +11 -7
  289. package/dist/core/tools/bash.js.map +1 -1
  290. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  291. package/dist/core/tools/edit-diff.js +9 -4
  292. package/dist/core/tools/edit-diff.js.map +1 -1
  293. package/dist/core/tools/edit.d.ts.map +1 -1
  294. package/dist/core/tools/edit.js +4 -3
  295. package/dist/core/tools/edit.js.map +1 -1
  296. package/dist/core/tools/index.d.ts.map +1 -1
  297. package/dist/core/tools/index.js +3 -2
  298. package/dist/core/tools/index.js.map +1 -1
  299. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  300. package/dist/core/tools/output-accumulator.js +2 -1
  301. package/dist/core/tools/output-accumulator.js.map +1 -1
  302. package/dist/core/tools/read.d.ts.map +1 -1
  303. package/dist/core/tools/read.js +6 -2
  304. package/dist/core/tools/read.js.map +1 -1
  305. package/dist/core/tools/write.d.ts.map +1 -1
  306. package/dist/core/tools/write.js +2 -1
  307. package/dist/core/tools/write.js.map +1 -1
  308. package/dist/durable/durable-service.d.ts.map +1 -1
  309. package/dist/durable/durable-service.js +25 -18
  310. package/dist/durable/durable-service.js.map +1 -1
  311. package/dist/host/checkpoint-commit.d.ts.map +1 -1
  312. package/dist/host/checkpoint-commit.js +2 -1
  313. package/dist/host/checkpoint-commit.js.map +1 -1
  314. package/dist/host/manual-compaction.d.ts.map +1 -1
  315. package/dist/host/manual-compaction.js +2 -1
  316. package/dist/host/manual-compaction.js.map +1 -1
  317. package/dist/host/output-projection.d.ts +0 -13
  318. package/dist/host/output-projection.d.ts.map +1 -1
  319. package/dist/host/output-projection.js +16 -2
  320. package/dist/host/output-projection.js.map +1 -1
  321. package/dist/host/summary-retry.d.ts.map +1 -1
  322. package/dist/host/summary-retry.js +3 -2
  323. package/dist/host/summary-retry.js.map +1 -1
  324. package/dist/main.d.ts.map +1 -1
  325. package/dist/main.js +94 -58
  326. package/dist/main.js.map +1 -1
  327. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/agents-view.js +18 -15
  329. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  330. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/assistant-message.js +6 -5
  332. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  333. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/bash-execution.js +12 -7
  335. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  336. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/bordered-loader.js +2 -1
  338. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  339. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/branch-summary-message.js +6 -5
  341. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  342. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  343. package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
  344. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  345. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/config-selector.js +18 -15
  347. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  349. package/dist/modes/interactive/components/custom-entry.js +2 -1
  350. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  351. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/dialog-editor.js +5 -4
  353. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  354. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/dialog-input.js +2 -1
  356. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  357. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  358. package/dist/modes/interactive/components/dialog-selector.js +4 -3
  359. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/first-time-setup.js +11 -10
  362. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  363. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/footer.js +7 -4
  365. package/dist/modes/interactive/components/footer.js.map +1 -1
  366. package/dist/modes/interactive/components/index.d.ts +1 -0
  367. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/index.js +1 -0
  369. package/dist/modes/interactive/components/index.js.map +1 -1
  370. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/keybinding-hints.js +3 -2
  372. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  373. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/login-dialog.js +12 -11
  375. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  376. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/mermaid.js +6 -2
  378. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  379. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/model-selector.js +28 -16
  381. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/oauth-selector.js +10 -9
  384. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
  387. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  388. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
  390. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  391. package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
  392. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
  393. package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
  394. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
  395. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  396. package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
  397. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  398. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/session-selector.js +43 -31
  400. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  401. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  402. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/settings-selector.js +113 -96
  404. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  405. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/settings-submenu.js +5 -4
  407. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  408. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/show-images-selector.js +3 -2
  410. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  411. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
  413. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  414. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/status-indicator.js +14 -5
  416. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  417. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/theme-selector.js +2 -1
  419. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  420. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/thinking-selector.js +11 -4
  422. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  423. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/tool-execution.js +8 -3
  425. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  426. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/tree-list.js +7 -6
  428. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  429. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/tree-render.js +28 -23
  431. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  432. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/tree-selector.js +9 -7
  434. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  435. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  436. package/dist/modes/interactive/components/user-message-selector.js +5 -4
  437. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  438. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  439. package/dist/modes/interactive/components/workflow-view.js +36 -21
  440. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  441. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  442. package/dist/modes/interactive/external-editor.js +2 -1
  443. package/dist/modes/interactive/external-editor.js.map +1 -1
  444. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  445. package/dist/modes/interactive/interactive-auth.js +71 -40
  446. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  447. package/dist/modes/interactive/interactive-commands.d.ts +1 -0
  448. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  449. package/dist/modes/interactive/interactive-commands.js +3 -0
  450. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  451. package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
  452. package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
  453. package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
  454. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  455. package/dist/modes/interactive/interactive-format.js +34 -18
  456. package/dist/modes/interactive/interactive-format.js.map +1 -1
  457. package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
  458. package/dist/modes/interactive/interactive-helpers.js +7 -2
  459. package/dist/modes/interactive/interactive-helpers.js.map +1 -1
  460. package/dist/modes/interactive/interactive-mode.d.ts +4 -1
  461. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-mode.js +327 -243
  463. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  464. package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
  465. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-selectors.js +79 -25
  467. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  468. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  469. package/dist/modes/interactive/theme/theme-controller.js +5 -1
  470. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  471. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  472. package/dist/modes/interactive/theme/theme.js +26 -23
  473. package/dist/modes/interactive/theme/theme.js.map +1 -1
  474. package/dist/modes/json-event.d.ts.map +1 -1
  475. package/dist/modes/json-event.js +3 -2
  476. package/dist/modes/json-event.js.map +1 -1
  477. package/dist/modes/print-mode.d.ts.map +1 -1
  478. package/dist/modes/print-mode.js +3 -2
  479. package/dist/modes/print-mode.js.map +1 -1
  480. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  481. package/dist/modes/rpc/rpc-client.js +3 -2
  482. package/dist/modes/rpc/rpc-client.js.map +1 -1
  483. package/dist/package-manager-cli.d.ts.map +1 -1
  484. package/dist/package-manager-cli.js +28 -13
  485. package/dist/package-manager-cli.js.map +1 -1
  486. package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
  487. package/dist/plugins/ecosystem/catalog.js +3 -2
  488. package/dist/plugins/ecosystem/catalog.js.map +1 -1
  489. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  490. package/dist/plugins/ecosystem/cli.js +2 -1
  491. package/dist/plugins/ecosystem/cli.js.map +1 -1
  492. package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
  493. package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
  494. package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
  495. package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
  496. package/dist/plugins/ecosystem/distribution.js +2 -1
  497. package/dist/plugins/ecosystem/distribution.js.map +1 -1
  498. package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
  499. package/dist/plugins/ecosystem/installer.js +3 -2
  500. package/dist/plugins/ecosystem/installer.js.map +1 -1
  501. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  502. package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
  503. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  504. package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
  505. package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
  506. package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
  507. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  508. package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
  509. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  510. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  511. package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
  512. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  513. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  514. package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
  515. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  516. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  517. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +21 -5
  518. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  519. package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
  520. package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
  521. package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
  522. package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
  523. package/dist/plugins/ecosystem/node-registry-source.js +31 -30
  524. package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
  525. package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
  526. package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
  527. package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
  528. package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
  529. package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
  530. package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
  531. package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
  532. package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
  533. package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
  534. package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
  535. package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
  536. package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
  537. package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
  538. package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
  539. package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
  540. package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
  541. package/dist/plugins/ecosystem/registry.js +35 -32
  542. package/dist/plugins/ecosystem/registry.js.map +1 -1
  543. package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
  544. package/dist/plugins/ecosystem/resolver.js +3 -2
  545. package/dist/plugins/ecosystem/resolver.js.map +1 -1
  546. package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
  547. package/dist/plugins/ecosystem/selection-store.js +11 -10
  548. package/dist/plugins/ecosystem/selection-store.js.map +1 -1
  549. package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
  550. package/dist/plugins/ecosystem/selection.js +8 -7
  551. package/dist/plugins/ecosystem/selection.js.map +1 -1
  552. package/dist/plugins/ecosystem/state.d.ts.map +1 -1
  553. package/dist/plugins/ecosystem/state.js +24 -23
  554. package/dist/plugins/ecosystem/state.js.map +1 -1
  555. package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
  556. package/dist/plugins/ecosystem/updates.js +5 -4
  557. package/dist/plugins/ecosystem/updates.js.map +1 -1
  558. package/dist/plugins/mcp-http.d.ts +0 -17
  559. package/dist/plugins/mcp-http.d.ts.map +1 -1
  560. package/dist/plugins/mcp-http.js +30 -7
  561. package/dist/plugins/mcp-http.js.map +1 -1
  562. package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
  563. package/dist/plugins/plugin-supervisor.js +19 -1
  564. package/dist/plugins/plugin-supervisor.js.map +1 -1
  565. package/dist/profile/first-roles.d.ts.map +1 -1
  566. package/dist/profile/first-roles.js +10 -1
  567. package/dist/profile/first-roles.js.map +1 -1
  568. package/dist/profile/goal-plugin.d.ts.map +1 -1
  569. package/dist/profile/goal-plugin.js +24 -5
  570. package/dist/profile/goal-plugin.js.map +1 -1
  571. package/dist/profile/identity.d.ts.map +1 -1
  572. package/dist/profile/identity.js +7 -6
  573. package/dist/profile/identity.js.map +1 -1
  574. package/dist/profile/lock.d.ts.map +1 -1
  575. package/dist/profile/lock.js +15 -1
  576. package/dist/profile/lock.js.map +1 -1
  577. package/dist/profile/plan-plugin.d.ts.map +1 -1
  578. package/dist/profile/plan-plugin.js +26 -13
  579. package/dist/profile/plan-plugin.js.map +1 -1
  580. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  581. package/dist/profile/plugin-profiles.js +2 -1
  582. package/dist/profile/plugin-profiles.js.map +1 -1
  583. package/dist/profile/policy-manifest.d.ts.map +1 -1
  584. package/dist/profile/policy-manifest.js +5 -4
  585. package/dist/profile/policy-manifest.js.map +1 -1
  586. package/dist/profile/profile-registry.d.ts +0 -12
  587. package/dist/profile/profile-registry.d.ts.map +1 -1
  588. package/dist/profile/profile-registry.js +14 -1
  589. package/dist/profile/profile-registry.js.map +1 -1
  590. package/dist/profile/role-catalog.d.ts +0 -1
  591. package/dist/profile/role-catalog.d.ts.map +1 -1
  592. package/dist/profile/role-catalog.js +17 -15
  593. package/dist/profile/role-catalog.js.map +1 -1
  594. package/dist/profile/role-orchestrator.d.ts.map +1 -1
  595. package/dist/profile/role-orchestrator.js +8 -7
  596. package/dist/profile/role-orchestrator.js.map +1 -1
  597. package/dist/profile/role-runner.d.ts.map +1 -1
  598. package/dist/profile/role-runner.js +3 -2
  599. package/dist/profile/role-runner.js.map +1 -1
  600. package/dist/profile/root-facade.d.ts.map +1 -1
  601. package/dist/profile/root-facade.js +2 -1
  602. package/dist/profile/root-facade.js.map +1 -1
  603. package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
  604. package/dist/profile/skill-discovery-wiring.js +7 -2
  605. package/dist/profile/skill-discovery-wiring.js.map +1 -1
  606. package/dist/profile/state-store.d.ts.map +1 -1
  607. package/dist/profile/state-store.js +13 -9
  608. package/dist/profile/state-store.js.map +1 -1
  609. package/dist/profile/todo-plugin.d.ts.map +1 -1
  610. package/dist/profile/todo-plugin.js +9 -4
  611. package/dist/profile/todo-plugin.js.map +1 -1
  612. package/dist/profiles/builtin-suites.d.ts +13 -6
  613. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  614. package/dist/profiles/builtin-suites.js +15 -6
  615. package/dist/profiles/builtin-suites.js.map +1 -1
  616. package/dist/profiles/suite-loader.d.ts +25 -1
  617. package/dist/profiles/suite-loader.d.ts.map +1 -1
  618. package/dist/profiles/suite-loader.js +34 -9
  619. package/dist/profiles/suite-loader.js.map +1 -1
  620. package/dist/remote/server-entry.d.ts.map +1 -1
  621. package/dist/remote/server-entry.js +3 -2
  622. package/dist/remote/server-entry.js.map +1 -1
  623. package/dist/remote/session-source.d.ts.map +1 -1
  624. package/dist/remote/session-source.js +8 -4
  625. package/dist/remote/session-source.js.map +1 -1
  626. package/dist/share/session-share.d.ts.map +1 -1
  627. package/dist/share/session-share.js +14 -2
  628. package/dist/share/session-share.js.map +1 -1
  629. package/dist/testing/plugin-testkit.d.ts.map +1 -1
  630. package/dist/testing/plugin-testkit.js +4 -3
  631. package/dist/testing/plugin-testkit.js.map +1 -1
  632. package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
  633. package/dist/testing/runtime-delivery-queue.js +2 -1
  634. package/dist/testing/runtime-delivery-queue.js.map +1 -1
  635. package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
  636. package/dist/testing/session-plugin-testkit.js +10 -7
  637. package/dist/testing/session-plugin-testkit.js.map +1 -1
  638. package/dist/utils/ansi.d.ts.map +1 -1
  639. package/dist/utils/ansi.js +2 -1
  640. package/dist/utils/ansi.js.map +1 -1
  641. package/dist/utils/clipboard.d.ts.map +1 -1
  642. package/dist/utils/clipboard.js +7 -6
  643. package/dist/utils/clipboard.js.map +1 -1
  644. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  645. package/dist/utils/image-resize-worker.js +3 -2
  646. package/dist/utils/image-resize-worker.js.map +1 -1
  647. package/dist/utils/shell.d.ts.map +1 -1
  648. package/dist/utils/shell.js +9 -8
  649. package/dist/utils/shell.js.map +1 -1
  650. package/dist/utils/tools-manager.d.ts.map +1 -1
  651. package/dist/utils/tools-manager.js +23 -13
  652. package/dist/utils/tools-manager.js.map +1 -1
  653. package/dist/utils/version-check.d.ts.map +1 -1
  654. package/dist/utils/version-check.js +5 -1
  655. package/dist/utils/version-check.js.map +1 -1
  656. package/docs/keybindings.md +3 -0
  657. package/docs/quickstart.md +1 -1
  658. package/docs/settings.md +1 -0
  659. package/docs/terminal-setup.md +2 -3
  660. package/docs/usage.md +6 -5
  661. package/examples/extensions/with-deps/package-lock.json +2 -2
  662. package/examples/extensions/with-deps/package.json +1 -1
  663. package/examples/extensions/with-deps/plugin.json +1 -1
  664. package/package.json +1 -1
  665. package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { t } from "../../core/i18n/index.js";
2
3
  import { detectPluginPackageMediaTypeV1 } from "./node-package-media.js";
3
4
  /**
4
5
  * Custom-URL plugin package download (design §4.6 "自定义 URL" row). The URL
@@ -24,7 +25,7 @@ export class NodeUrlPackageSourceErrorV1 extends Error {
24
25
  function boundedPositive(value, fallback, maximum, label) {
25
26
  const result = value ?? fallback;
26
27
  if (!Number.isSafeInteger(result) || result <= 0 || result > maximum)
27
- throw new NodeUrlPackageSourceErrorV1("invalid_configuration", `${label} must be a positive integer at most ${maximum}`);
28
+ throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("{label} must be a positive integer at most {maximum}", { label, maximum }));
28
29
  return result;
29
30
  }
30
31
  function packageUrl(value) {
@@ -33,14 +34,14 @@ function packageUrl(value) {
33
34
  parsed = new URL(value);
34
35
  }
35
36
  catch {
36
- throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL is invalid");
37
+ throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL is invalid"));
37
38
  }
38
39
  if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") ||
39
40
  parsed.username !== "" ||
40
41
  parsed.password !== "")
41
- throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL must use http(s) without credentials");
42
+ throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL must use http(s) without credentials"));
42
43
  if (parsed.hash !== "")
43
- throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL must not include a fragment");
44
+ throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL must not include a fragment"));
44
45
  return parsed;
45
46
  }
46
47
  function isAbortLike(error) {
@@ -54,17 +55,17 @@ function isAbortLike(error) {
54
55
  export async function downloadNodeUrlPackageV1(options, input) {
55
56
  const transport = options.fetch ?? globalThis.fetch;
56
57
  if (typeof transport !== "function")
57
- throw new NodeUrlPackageSourceErrorV1("invalid_configuration", "Node fetch is unavailable");
58
+ throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("Node fetch is unavailable"));
58
59
  const timeoutMs = boundedPositive(options.requestTimeoutMs, DEFAULT_TIMEOUT_MS_V1, MAX_TIMEOUT_MS_V1, "requestTimeoutMs");
59
60
  const maxPackageBytes = boundedPositive(options.maxPackageBytes, DEFAULT_MAX_PACKAGE_BYTES_V1, MAX_PACKAGE_BYTES_V1, "maxPackageBytes");
60
61
  const maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;
61
62
  if (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)
62
- throw new NodeUrlPackageSourceErrorV1("invalid_configuration", `maxRedirects must be an integer between 0 and ${MAX_REDIRECTS_V1}`);
63
+ throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("maxRedirects must be an integer between 0 and {max}", { max: MAX_REDIRECTS_V1 }));
63
64
  const userAgent = options.userAgent ?? "agent-forge-plugin-url/1";
64
65
  if (userAgent.length === 0 || userAgent.length > 256 || /[\r\n]/u.test(userAgent))
65
- throw new NodeUrlPackageSourceErrorV1("invalid_configuration", "userAgent is invalid");
66
+ throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("userAgent is invalid"));
66
67
  if (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))
67
- throw new NodeUrlPackageSourceErrorV1("invalid_url", "expected sha256 digest is invalid");
68
+ throw new NodeUrlPackageSourceErrorV1("invalid_url", t("expected sha256 digest is invalid"));
68
69
  let current = packageUrl(input.url);
69
70
  let response;
70
71
  const controller = new AbortController();
@@ -81,7 +82,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
81
82
  try {
82
83
  for (let redirect = 0;; redirect += 1) {
83
84
  if (controller.signal.aborted)
84
- throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
85
+ throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
85
86
  let hop;
86
87
  try {
87
88
  hop = await transport(current.toString(), {
@@ -93,10 +94,10 @@ export async function downloadNodeUrlPackageV1(options, input) {
93
94
  }
94
95
  catch (error) {
95
96
  if (timedOut)
96
- throw new NodeUrlPackageSourceErrorV1("request_timed_out", "plugin package download timed out");
97
+ throw new NodeUrlPackageSourceErrorV1("request_timed_out", t("plugin package download timed out"));
97
98
  if (isAbortLike(error) || input.signal?.aborted === true)
98
- throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
99
- throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download failed");
99
+ throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
100
+ throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download failed"));
100
101
  }
101
102
  if (!REDIRECT_STATUS.has(hop.status)) {
102
103
  response = hop;
@@ -105,15 +106,15 @@ export async function downloadNodeUrlPackageV1(options, input) {
105
106
  const location = hop.headers.get("location");
106
107
  await hop.body?.cancel().catch(() => undefined);
107
108
  if (location === null || redirect >= maxRedirects)
108
- throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package redirect limit exceeded");
109
+ throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package redirect limit exceeded"));
109
110
  current = packageUrl(new URL(location, current).toString());
110
111
  }
111
112
  if (response === undefined)
112
- throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download failed");
113
+ throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download failed"));
113
114
  if (response.status < 200 || response.status >= 300)
114
- throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download did not succeed");
115
+ throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download did not succeed"));
115
116
  if (response.body === null)
116
- throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package response has no body");
117
+ throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package response has no body"));
117
118
  const reader = response.body.getReader();
118
119
  const chunks = [];
119
120
  const hash = createHash("sha256");
@@ -121,13 +122,13 @@ export async function downloadNodeUrlPackageV1(options, input) {
121
122
  try {
122
123
  for (;;) {
123
124
  if (controller.signal.aborted)
124
- throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
125
+ throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
125
126
  const item = await reader.read();
126
127
  if (item.done)
127
128
  break;
128
129
  total += item.value.byteLength;
129
130
  if (total > maxPackageBytes)
130
- throw new NodeUrlPackageSourceErrorV1("response_too_large", "plugin package exceeds the configured size limit");
131
+ throw new NodeUrlPackageSourceErrorV1("response_too_large", t("plugin package exceeds the configured size limit"));
131
132
  hash.update(item.value);
132
133
  chunks.push(item.value);
133
134
  }
@@ -136,7 +137,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
136
137
  reader.releaseLock();
137
138
  }
138
139
  if (controller.signal.aborted)
139
- throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
140
+ throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
140
141
  const bytes = new Uint8Array(total);
141
142
  let offset = 0;
142
143
  for (const chunk of chunks) {
@@ -145,7 +146,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
145
146
  }
146
147
  const digestHex = hash.digest("hex");
147
148
  if (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)
148
- throw new NodeUrlPackageSourceErrorV1("digest_mismatch", "plugin package bytes do not match the expected sha256 digest");
149
+ throw new NodeUrlPackageSourceErrorV1("digest_mismatch", t("plugin package bytes do not match the expected sha256 digest"));
149
150
  const fileName = current.pathname.split("/").pop();
150
151
  const mediaType = detectPluginPackageMediaTypeV1(bytes, fileName === undefined || fileName.length === 0 ? undefined : fileName);
151
152
  return { bytes, mediaType, digestHex };
@@ -1 +1 @@
1
- {"version":3,"file":"node-url-package-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-url-package-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { detectPluginPackageMediaTypeV1, type PluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\n\n/**\n * Custom-URL plugin package download (design §4.6 \"自定义 URL\" row). The URL\n * is the package file itself (zip/tgz); integrity is layered: a `#sha256:<hex>`\n * ref fragment becomes a strong digest check, otherwise TLS plus the double\n * manifest validation performed by the install host.\n */\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_PACKAGE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_PACKAGE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeUrlPackageSourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_url\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"response_too_large\"\n\t| \"digest_mismatch\";\n\nexport class NodeUrlPackageSourceErrorV1 extends Error {\n\treadonly code: NodeUrlPackageSourceErrorCodeV1;\n\n\tconstructor(code: NodeUrlPackageSourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeUrlPackageSourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeUrlPackageSourceOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxPackageBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeUrlPackageDownloadV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: PluginPackageMediaTypeV1;\n\t/** sha256 hex of the downloaded bytes; always computed, verified when expected. */\n\treadonly digestHex: string;\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\t`${label} must be a positive integer at most ${maximum}`,\n\t\t);\n\treturn result;\n}\n\nfunction packageUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL is invalid\");\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL must use http(s) without credentials\");\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL must not include a fragment\");\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\n/**\n * Download one package file over http(s). Redirects are followed manually and\n * every hop must again be a valid http(s) URL without credentials. When\n * `expectedDigestHex` is present the sha256 of the bytes must match exactly.\n */\nexport async function downloadNodeUrlPackageV1(\n\toptions: NodeUrlPackageSourceOptionsV1,\n\tinput: {\n\t\treadonly url: string;\n\t\treadonly expectedDigestHex?: string;\n\t\treadonly signal?: AbortSignal;\n\t},\n): Promise<NodeUrlPackageDownloadV1> {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", \"Node fetch is unavailable\");\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxPackageBytes = boundedPositive(\n\t\toptions.maxPackageBytes,\n\t\tDEFAULT_MAX_PACKAGE_BYTES_V1,\n\t\tMAX_PACKAGE_BYTES_V1,\n\t\t\"maxPackageBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\t`maxRedirects must be an integer between 0 and ${MAX_REDIRECTS_V1}`,\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-url/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", \"userAgent is invalid\");\n\tif (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"expected sha256 digest is invalid\");\n\n\tlet current = packageUrl(input.url);\n\tlet response: Response | undefined;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(input.signal?.reason);\n\tif (input.signal?.aborted === true) abort();\n\telse input.signal?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\ttry {\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tif (controller.signal.aborted)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\tlet hop: Response;\n\t\t\ttry {\n\t\t\t\thop = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (timedOut)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_timed_out\", \"plugin package download timed out\");\n\t\t\t\tif (isAbortLike(error) || input.signal?.aborted === true)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download failed\");\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(hop.status)) {\n\t\t\t\tresponse = hop;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst location = hop.headers.get(\"location\");\n\t\t\tawait hop.body?.cancel().catch(() => undefined);\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package redirect limit exceeded\");\n\t\t\tcurrent = packageUrl(new URL(location, current).toString());\n\t\t}\n\t\tif (response === undefined)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download failed\");\n\t\tif (response.status < 200 || response.status >= 300)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download did not succeed\");\n\t\tif (response.body === null)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package response has no body\");\n\t\tconst reader = response.body.getReader();\n\t\tconst chunks: Uint8Array[] = [];\n\t\tconst hash = createHash(\"sha256\");\n\t\tlet total = 0;\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (controller.signal.aborted)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\t\tconst item = await reader.read();\n\t\t\t\tif (item.done) break;\n\t\t\t\ttotal += item.value.byteLength;\n\t\t\t\tif (total > maxPackageBytes)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\t\t\"plugin package exceeds the configured size limit\",\n\t\t\t\t\t);\n\t\t\t\thash.update(item.value);\n\t\t\t\tchunks.push(item.value);\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tif (controller.signal.aborted)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\tconst bytes = new Uint8Array(total);\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, offset);\n\t\t\toffset += chunk.byteLength;\n\t\t}\n\t\tconst digestHex = hash.digest(\"hex\");\n\t\tif (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\"digest_mismatch\",\n\t\t\t\t\"plugin package bytes do not match the expected sha256 digest\",\n\t\t\t);\n\t\tconst fileName = current.pathname.split(\"/\").pop();\n\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\tbytes,\n\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t);\n\t\treturn { bytes, mediaType, digestHex };\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tinput.signal?.removeEventListener(\"abort\", abort);\n\t\tawait response?.body?.cancel().catch(() => undefined);\n\t}\n}\n"]}
1
+ {"version":3,"file":"node-url-package-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-url-package-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { detectPluginPackageMediaTypeV1, type PluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\n\n/**\n * Custom-URL plugin package download (design §4.6 \"自定义 URL\" row). The URL\n * is the package file itself (zip/tgz); integrity is layered: a `#sha256:<hex>`\n * ref fragment becomes a strong digest check, otherwise TLS plus the double\n * manifest validation performed by the install host.\n */\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_PACKAGE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_PACKAGE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeUrlPackageSourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_url\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"response_too_large\"\n\t| \"digest_mismatch\";\n\nexport class NodeUrlPackageSourceErrorV1 extends Error {\n\treadonly code: NodeUrlPackageSourceErrorCodeV1;\n\n\tconstructor(code: NodeUrlPackageSourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeUrlPackageSourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeUrlPackageSourceOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxPackageBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeUrlPackageDownloadV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: PluginPackageMediaTypeV1;\n\t/** sha256 hex of the downloaded bytes; always computed, verified when expected. */\n\treadonly digestHex: string;\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction packageUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"plugin package URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_url\",\n\t\t\tt(\"plugin package URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"plugin package URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\n/**\n * Download one package file over http(s). Redirects are followed manually and\n * every hop must again be a valid http(s) URL without credentials. When\n * `expectedDigestHex` is present the sha256 of the bytes must match exactly.\n */\nexport async function downloadNodeUrlPackageV1(\n\toptions: NodeUrlPackageSourceOptionsV1,\n\tinput: {\n\t\treadonly url: string;\n\t\treadonly expectedDigestHex?: string;\n\t\treadonly signal?: AbortSignal;\n\t},\n): Promise<NodeUrlPackageDownloadV1> {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxPackageBytes = boundedPositive(\n\t\toptions.maxPackageBytes,\n\t\tDEFAULT_MAX_PACKAGE_BYTES_V1,\n\t\tMAX_PACKAGE_BYTES_V1,\n\t\t\"maxPackageBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-url/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\tif (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"expected sha256 digest is invalid\"));\n\n\tlet current = packageUrl(input.url);\n\tlet response: Response | undefined;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(input.signal?.reason);\n\tif (input.signal?.aborted === true) abort();\n\telse input.signal?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\ttry {\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tif (controller.signal.aborted)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\tlet hop: Response;\n\t\t\ttry {\n\t\t\t\thop = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (timedOut)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_timed_out\", t(\"plugin package download timed out\"));\n\t\t\t\tif (isAbortLike(error) || input.signal?.aborted === true)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download failed\"));\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(hop.status)) {\n\t\t\t\tresponse = hop;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst location = hop.headers.get(\"location\");\n\t\t\tawait hop.body?.cancel().catch(() => undefined);\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package redirect limit exceeded\"));\n\t\t\tcurrent = packageUrl(new URL(location, current).toString());\n\t\t}\n\t\tif (response === undefined)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download failed\"));\n\t\tif (response.status < 200 || response.status >= 300)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download did not succeed\"));\n\t\tif (response.body === null)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package response has no body\"));\n\t\tconst reader = response.body.getReader();\n\t\tconst chunks: Uint8Array[] = [];\n\t\tconst hash = createHash(\"sha256\");\n\t\tlet total = 0;\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (controller.signal.aborted)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\t\tconst item = await reader.read();\n\t\t\t\tif (item.done) break;\n\t\t\t\ttotal += item.value.byteLength;\n\t\t\t\tif (total > maxPackageBytes)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\t\tt(\"plugin package exceeds the configured size limit\"),\n\t\t\t\t\t);\n\t\t\t\thash.update(item.value);\n\t\t\t\tchunks.push(item.value);\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tif (controller.signal.aborted)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\tconst bytes = new Uint8Array(total);\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, offset);\n\t\t\toffset += chunk.byteLength;\n\t\t}\n\t\tconst digestHex = hash.digest(\"hex\");\n\t\tif (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\"digest_mismatch\",\n\t\t\t\tt(\"plugin package bytes do not match the expected sha256 digest\"),\n\t\t\t);\n\t\tconst fileName = current.pathname.split(\"/\").pop();\n\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\tbytes,\n\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t);\n\t\treturn { bytes, mediaType, digestHex };\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tinput.signal?.removeEventListener(\"abort\", abort);\n\t\tawait response?.body?.cancel().catch(() => undefined);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-acquisition.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,wHAAwH;IACxH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,4BAA4B,GACrC,aAAa,GACb,uBAAuB,GACvB,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,WAAW,GACX,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,wBAAwB,GACxB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,yBAAyB,GACzB,yBAAyB,GACzB,cAAc,CAAC;AAsBlB,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAE5C,mGAAmG;IACnG,YAAY,IAAI,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,MAAM,EAQ9D;CACD;AAED,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACpF;AAoFD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,6BAA6B,GAAG,sBAAsB,CAcrH;AAaD;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAetE","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? ACQUISITION_ERROR_MESSAGES_V1[code]\n\t\t\t\t: `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
1
+ {"version":3,"file":"plugin-acquisition.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,wHAAwH;IACxH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,4BAA4B,GACrC,aAAa,GACb,uBAAuB,GACvB,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,WAAW,GACX,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,wBAAwB,GACxB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,yBAAyB,GACzB,yBAAyB,GACzB,cAAc,CAAC;AAsBlB,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAE5C,mGAAmG;IACnG,YAAY,IAAI,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,MAAM,EAQ9D;CACD;AAED,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACpF;AAoFD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,6BAA6B,GAAG,sBAAsB,CAcrH;AAaD;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAetE","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport { t } from \"../../core/i18n/index.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? t(ACQUISITION_ERROR_MESSAGES_V1[code])\n\t\t\t\t: `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
@@ -19,6 +19,7 @@
19
19
  * name parsing. The CLI additionally routes only refs that cannot be legacy
20
20
  * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).
21
21
  */
22
+ import { t } from "../../core/i18n/index.js";
22
23
  export const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;
23
24
  export const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;
24
25
  const ACQUISITION_ERROR_MESSAGES_V1 = {
@@ -45,8 +46,8 @@ export class PluginAcquisitionErrorV1 extends Error {
45
46
  /** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */
46
47
  constructor(code, detail) {
47
48
  super(detail === undefined || detail.length === 0
48
- ? ACQUISITION_ERROR_MESSAGES_V1[code]
49
- : `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`);
49
+ ? t(ACQUISITION_ERROR_MESSAGES_V1[code])
50
+ : `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`);
50
51
  this.name = "PluginAcquisitionErrorV1";
51
52
  this.code = code;
52
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-acquisition.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? ACQUISITION_ERROR_MESSAGES_V1[code]\n\t\t\t\t: `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
1
+ {"version":3,"file":"plugin-acquisition.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport { t } from \"../../core/i18n/index.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? t(ACQUISITION_ERROR_MESSAGES_V1[code])\n\t\t\t\t: `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"registry-cli-adapter.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,gBAAgB,GAAG,yBAAyB,CAS5G","sourcesContent":["import type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", \"Registry does not expose a host-side package resolver\");\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
1
+ {"version":3,"file":"registry-cli-adapter.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,gBAAgB,GAAG,yBAAyB,CAS5G","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Registry does not expose a host-side package resolver\"));\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { t } from "../../core/i18n/index.js";
1
2
  import { PluginRegistryErrorV1 } from "./registry.js";
2
3
  /**
3
4
  * Adapt a verified registry to the CLI's host-injected package resolver.
@@ -5,7 +6,7 @@ import { PluginRegistryErrorV1 } from "./registry.js";
5
6
  */
6
7
  export function createPluginEcosystemRegistryAdapterV1(registry) {
7
8
  if (registry.resolve === undefined)
8
- throw new PluginRegistryErrorV1("invalid_source", "Registry does not expose a host-side package resolver");
9
+ throw new PluginRegistryErrorV1("invalid_source", t("Registry does not expose a host-side package resolver"));
9
10
  const resolve = registry.resolve;
10
11
  const list = registry.listManifests;
11
12
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"registry-cli-adapter.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAyB,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,MAAM,UAAU,sCAAsC,CAAC,QAA0B,EAA6B;IAC7G,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QACjC,MAAM,IAAI,qBAAqB,CAAC,gBAAgB,EAAE,uDAAuD,CAAC,CAAC;IAC5G,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC;IACpC,OAAO;QACN,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,OAAO;KACP,CAAC;AAAA,CACF","sourcesContent":["import type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", \"Registry does not expose a host-side package resolver\");\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
1
+ {"version":3,"file":"registry-cli-adapter.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAyB,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,MAAM,UAAU,sCAAsC,CAAC,QAA0B,EAA6B;IAC7G,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QACjC,MAAM,IAAI,qBAAqB,CAAC,gBAAgB,EAAE,CAAC,CAAC,uDAAuD,CAAC,CAAC,CAAC;IAC/G,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC;IACpC,OAAO;QACN,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,OAAO;KACP,CAAC;AAAA,CACF","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Registry does not expose a host-side package resolver\"));\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { buildPluginCatalogV1, comparePluginVersionsV1, type PluginCatalogSnapshotV1 } from \"./catalog.ts\";\nimport type { PluginDistributionDescriptorV1 } from \"./distribution.ts\";\nimport { createPluginDistributionV1 } from \"./distribution.ts\";\nimport type { CapabilityRefV1, HostFactsV1, PluginManifestV1, PluginSourceVerifierV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\n/** Maximum manifest JSON bytes accepted by the registry boundary. */\nexport const MAX_PLUGIN_REGISTRY_MANIFEST_BYTES_V1 = 64 * 1024;\n/** Maximum number of manifests returned by one source query. */\nexport const MAX_PLUGIN_REGISTRY_MANIFESTS_V1 = 256;\n/** Maximum aggregate manifest metadata returned by one source query. */\nexport const MAX_PLUGIN_REGISTRY_PAYLOAD_BYTES_V1 = 4 * 1024 * 1024;\n/** Maximum source URI length; sources are identifiers, never package paths. */\nexport const MAX_PLUGIN_REGISTRY_SOURCE_CHARS_V1 = 2048;\n/** Maximum digest/signature text length accepted from a source. */\nexport const MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1 = 512;\n\nexport interface PluginRegistryManifestEnvelopeV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly source: string;\n\treadonly manifestDigest: string;\n\t/** Optional host- or registry-supplied signature. The verifier owns semantics. */\n\treadonly signature?: string;\n\t/** Optional signed artifact descriptor bound to this exact manifest identity. */\n\treadonly distribution?: PluginDistributionDescriptorV1;\n}\n\n/**\n * A transport-neutral registry source. Hosts inject HTTP, filesystem, or\n * package-manager implementations. The registry never receives package bytes\n * and never exposes source response bodies to the model context.\n */\nexport interface PluginRegistrySourceV1 {\n\t/** Optional stable source identity shown in diagnostics; never a local path. */\n\treadonly source?: string;\n\treadonly list: (input: { readonly signal?: AbortSignal }) => Promise<readonly PluginRegistryManifestEnvelopeV1[]>;\n}\n\nexport interface PluginRegistryDigestVerifierV1 {\n\treadonly verify: (input: {\n\t\treadonly manifest: PluginManifestV1;\n\t\treadonly source: string;\n\t\treadonly manifestDigest: string;\n\t\treadonly expectedDigest?: string;\n\t\treadonly signature?: string;\n\t}) =>\n\t\t| { readonly status: \"accepted\" }\n\t\t| { readonly status: \"rejected\"; readonly reason?: string }\n\t\t| Promise<{ readonly status: \"accepted\" } | { readonly status: \"rejected\"; readonly reason?: string }>;\n}\n\nexport interface PluginRegistryOptionsV1 {\n\treadonly source: PluginRegistrySourceV1;\n\treadonly host: HostFactsV1;\n\t/** Required digest/signature verifier. No implicit trust fallback. */\n\treadonly verify: PluginRegistryDigestVerifierV1;\n\t/** Existing source verifier contract is mandatory at the registry boundary. */\n\treadonly sourceVerifier: PluginSourceVerifierV1;\n\treadonly availableCapabilities?: readonly CapabilityRefV1[];\n\treadonly maxManifests?: number;\n}\n\nexport type PluginRegistryErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_limit\"\n\t| \"source_rejected\"\n\t| \"invalid_manifest\"\n\t| \"invalid_source\"\n\t| \"invalid_digest\"\n\t| \"payload_too_large\"\n\t| \"too_many_manifests\"\n\t| \"incompatible\";\n\nexport class PluginRegistryErrorV1 extends Error {\n\treadonly code: PluginRegistryErrorCodeV1;\n\treadonly cause?: unknown;\n\n\tconstructor(code: PluginRegistryErrorCodeV1, message: string, cause?: unknown) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"PluginRegistryErrorV1\";\n\t\tthis.code = code;\n\t\tthis.cause = cause;\n\t}\n}\n\nexport interface PluginRegistryEntryV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly source: string;\n\treadonly manifestDigest: string;\n\treadonly signed: boolean;\n}\n\nexport type PluginRegistryRejectionCodeV1 = \"source_rejected\" | \"digest_rejected\" | \"incompatible\";\n\nexport interface PluginRegistryRejectionV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly code: PluginRegistryRejectionCodeV1;\n\treadonly reason: string;\n}\n\nexport interface PluginRegistryVerifiedEntryV1 extends PluginRegistryEntryV1 {\n\treadonly resolutionStatus: \"installed-ready\";\n}\n\nexport interface PluginRegistrySnapshotV1 {\n\treadonly version: 1;\n\treadonly source: string;\n\treadonly entries: readonly PluginRegistryEntryV1[];\n\treadonly catalog: PluginCatalogSnapshotV1;\n\t/** Only entries that passed proof validation and host compatibility. */\n\treadonly verified: readonly PluginRegistryVerifiedEntryV1[];\n\t/** Platform/API/test-only entries remain visible in catalog but are not verified. */\n\treadonly rejected: readonly PluginRegistryRejectionV1[];\n}\n\n/** Host-side package projection; package bytes never cross this boundary. */\nexport interface PluginRegistryResolvedPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly source: string;\n\treadonly expectedDigest: string;\n\treadonly distribution?: PluginDistributionDescriptorV1;\n}\n\nexport interface PluginRegistryV1 {\n\treadonly list: (input?: { readonly signal?: AbortSignal }) => Promise<PluginRegistrySnapshotV1>;\n\t/** Optional host-side resolver. Older custom registry implementations may omit it. */\n\treadonly resolve?: (input: {\n\t\treadonly pluginId: string;\n\t\treadonly pluginVersion?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<PluginRegistryResolvedPackageV1 | undefined>;\n\t/** Optional host-side manifest projection used by the CLI catalog command. */\n\treadonly listManifests?: (input?: { readonly signal?: AbortSignal }) => Promise<readonly PluginManifestV1[]>;\n}\n\nfunction isAbortLike(error: unknown, signal: AbortSignal | undefined): boolean {\n\treturn (\n\t\tsignal?.aborted === true ||\n\t\t(error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\"))\n\t);\n}\n\nfunction boundedString(\n\tvalue: unknown,\n\tlabel: string,\n\tmax: number,\n\tcode: PluginRegistryErrorCodeV1 = \"invalid_source\",\n): string {\n\tif (typeof value !== \"string\" || value.trim() === \"\" || value.length > max || /[\\u0000-\\u001f]/u.test(value)) {\n\t\tthrow new PluginRegistryErrorV1(code, `${label} must be a non-empty bounded string`);\n\t}\n\treturn value;\n}\n\nfunction assertAllowedKeys(value: Record<string, unknown>, allowed: readonly string[], label: string): void {\n\tconst expected = new Set(allowed);\n\tif (Object.keys(value).some((key) => !expected.has(key)))\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", `${label} contains an unsupported field`);\n}\n\nfunction validateSource(source: unknown): string {\n\tconst value = boundedString(source, \"source\", MAX_PLUGIN_REGISTRY_SOURCE_CHARS_V1);\n\tif (/^(?:file:|[a-zA-Z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(value) || /\\s/u.test(value)) {\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_source\",\n\t\t\t\"Plugin registry source must be an opaque URI, not a local path\",\n\t\t);\n\t}\n\tif (/^https?:\\/\\//iu.test(value)) {\n\t\ttry {\n\t\t\tconst parsed = new URL(value);\n\t\t\tconst pathname = parsed.pathname.length > 512 ? `${parsed.pathname.slice(0, 511)}…` : parsed.pathname;\n\t\t\treturn `${parsed.origin}${pathname || \"/\"}`;\n\t\t} catch (error) {\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", \"Plugin registry source URL is invalid\", error);\n\t\t}\n\t}\n\treturn value;\n}\n\nfunction validateManifest(manifest: unknown): PluginManifestV1 {\n\tif (typeof manifest !== \"object\" || manifest === null || Array.isArray(manifest)) {\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry manifest must be an object\");\n\t}\n\tconst value = manifest as Record<string, unknown>;\n\tassertAllowedKeys(\n\t\tvalue,\n\t\t[\n\t\t\t\"id\",\n\t\t\t\"pluginVersion\",\n\t\t\t\"apiVersion\",\n\t\t\t\"minHostVersion\",\n\t\t\t\"maxHostVersion\",\n\t\t\t\"capabilityRefs\",\n\t\t\t\"requires\",\n\t\t\t\"platform\",\n\t\t\t\"testOnly\",\n\t\t],\n\t\t\"Registry manifest\",\n\t);\n\tif (typeof value.id !== \"string\" || value.id.trim() === \"\" || value.id.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry manifest id is invalid\");\n\tif (typeof value.pluginVersion !== \"string\" || value.pluginVersion.trim() === \"\" || value.pluginVersion.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry manifest pluginVersion is invalid\");\n\tif (typeof value.apiVersion !== \"string\" || value.apiVersion.trim() === \"\" || value.apiVersion.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry manifest apiVersion is invalid\");\n\tif (value.minHostVersion === undefined && value.maxHostVersion === undefined)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_manifest\",\n\t\t\t\"Published plugins must declare host version compatibility range: set minHostVersion and/or maxHostVersion\",\n\t\t);\n\tlet bytes: number;\n\ttry {\n\t\tbytes = new TextEncoder().encode(JSON.stringify(manifest)).byteLength;\n\t} catch (error) {\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry manifest cannot be serialized\", error);\n\t}\n\tif (bytes > MAX_PLUGIN_REGISTRY_MANIFEST_BYTES_V1)\n\t\tthrow new PluginRegistryErrorV1(\"payload_too_large\", \"Registry manifest exceeds the size limit\");\n\treturn Object.freeze({ ...value } as unknown as PluginManifestV1);\n}\n\nfunction validateEnvelope(value: unknown): PluginRegistryManifestEnvelopeV1 {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry response entry must be an object\");\n\tconst entry = value as Record<string, unknown>;\n\tassertAllowedKeys(\n\t\tentry,\n\t\t[\"manifest\", \"source\", \"manifestDigest\", \"signature\", \"distribution\"],\n\t\t\"Registry response entry\",\n\t);\n\tconst manifest = validateManifest(entry.manifest);\n\tconst source = validateSource(entry.source);\n\tconst manifestDigest = boundedString(entry.manifestDigest, \"manifestDigest\", MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1);\n\tif (entry.signature !== undefined) boundedString(entry.signature, \"signature\", MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1);\n\tlet distribution: PluginDistributionDescriptorV1 | undefined;\n\tif (entry.distribution !== undefined) {\n\t\ttry {\n\t\t\tdistribution = createPluginDistributionV1().validateDescriptor(entry.distribution);\n\t\t} catch (error) {\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry distribution descriptor is invalid\", error);\n\t\t}\n\t\tif (\n\t\t\tdistribution.pluginId !== manifest.id ||\n\t\t\tdistribution.pluginVersion !== manifest.pluginVersion ||\n\t\t\tdistribution.manifestDigest !== manifestDigest\n\t\t)\n\t\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\t\"invalid_manifest\",\n\t\t\t\t\"Registry distribution descriptor does not match the manifest identity\",\n\t\t\t);\n\t}\n\treturn Object.freeze({\n\t\tmanifest,\n\t\tsource,\n\t\tmanifestDigest,\n\t\t...(entry.signature === undefined ? {} : { signature: entry.signature as string }),\n\t\t...(distribution === undefined ? {} : { distribution }),\n\t});\n}\n\nfunction validateMax(value: number | undefined): number {\n\tconst max = value ?? MAX_PLUGIN_REGISTRY_MANIFESTS_V1;\n\tif (!Number.isSafeInteger(max) || max < 1 || max > MAX_PLUGIN_REGISTRY_MANIFESTS_V1)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_limit\",\n\t\t\t`maxManifests must be an integer between 1 and ${MAX_PLUGIN_REGISTRY_MANIFESTS_V1}`,\n\t\t);\n\treturn max;\n}\n\nasync function validateSourceProof(\n\tentry: PluginRegistryManifestEnvelopeV1,\n\tverifier: PluginRegistryDigestVerifierV1,\n\tsourceVerifier: PluginSourceVerifierV1,\n): Promise<void> {\n\tconst actualDigest = pluginManifestDigestV1(entry.manifest);\n\tif (entry.manifestDigest !== actualDigest)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_digest\",\n\t\t\t`Manifest digest mismatch for ${entry.manifest.id}@${entry.manifest.pluginVersion}`,\n\t\t);\n\ttry {\n\t\tconst result = await verifier.verify({\n\t\t\tmanifest: entry.manifest,\n\t\t\tsource: entry.source,\n\t\t\tmanifestDigest: actualDigest,\n\t\t\texpectedDigest: entry.manifestDigest,\n\t\t\tsignature: entry.signature,\n\t\t});\n\t\tif (result.status !== \"accepted\")\n\t\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", result.reason ?? \"Registry source proof was rejected\");\n\t} catch (error) {\n\t\tif (error instanceof PluginRegistryErrorV1) throw error;\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", \"Registry source proof was rejected\", error);\n\t}\n\tlet result: ReturnType<PluginSourceVerifierV1>;\n\ttry {\n\t\tresult = sourceVerifier({\n\t\t\tpluginId: entry.manifest.id,\n\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\tsource: entry.source,\n\t\t\tmanifestDigest: actualDigest,\n\t\t});\n\t} catch (error) {\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", \"Plugin source verifier failed\", error);\n\t}\n\tif (result.status !== \"accepted\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", result.reason ?? \"Plugin source was rejected\");\n}\n\nfunction sourceIdentity(entries: readonly PluginRegistryManifestEnvelopeV1[]): string {\n\tconst sources = [...new Set(entries.map((entry) => entry.source))].sort((left, right) => left.localeCompare(right));\n\treturn sources.join(\",\");\n}\n\ninterface RegistryLoadV1 {\n\treadonly accepted: readonly PluginRegistryManifestEnvelopeV1[];\n\treadonly snapshot: PluginRegistrySnapshotV1;\n}\n\n/** Create a deterministic, host-injected registry client. */\nexport function createPluginRegistryV1(options: PluginRegistryOptionsV1): PluginRegistryV1 {\n\tconst maxManifests = validateMax(options.maxManifests);\n\tif (options.source === undefined || typeof options.source.list !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", \"Registry source must provide list()\");\n\tif (options.source.source !== undefined) validateSource(options.source.source);\n\tif (options.verify === undefined || typeof options.verify.verify !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", \"Registry source/digest verifier is required\");\n\tif (options.sourceVerifier === undefined || typeof options.sourceVerifier !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", \"Registry source verifier is required\");\n\n\tconst load = async (input: { readonly signal?: AbortSignal } = {}): Promise<RegistryLoadV1> => {\n\t\tif (input.signal?.aborted)\n\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", \"Plugin registry operation was cancelled\");\n\t\tlet raw: readonly PluginRegistryManifestEnvelopeV1[];\n\t\ttry {\n\t\t\traw = await options.source.list({ signal: input.signal });\n\t\t} catch (error) {\n\t\t\tif (isAbortLike(error, input.signal))\n\t\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", \"Plugin registry operation was cancelled\", error);\n\t\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", \"Plugin registry source failed\", error);\n\t\t}\n\t\tif (input.signal?.aborted)\n\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", \"Plugin registry operation was cancelled\");\n\t\tif (!Array.isArray(raw))\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", \"Registry source must return an array\");\n\t\tif (raw.length > maxManifests)\n\t\t\tthrow new PluginRegistryErrorV1(\"too_many_manifests\", \"Registry response contains too many manifests\");\n\t\tconst entries = raw.map(validateEnvelope);\n\t\tconst payloadBytes = entries.reduce((total, entry) => {\n\t\t\tconst manifestBytes = new TextEncoder().encode(JSON.stringify(entry.manifest)).byteLength;\n\t\t\tconst distributionBytes =\n\t\t\t\tentry.distribution === undefined\n\t\t\t\t\t? 0\n\t\t\t\t\t: new TextEncoder().encode(JSON.stringify(entry.distribution)).byteLength;\n\t\t\treturn (\n\t\t\t\ttotal +\n\t\t\t\tmanifestBytes +\n\t\t\t\tdistributionBytes +\n\t\t\t\tnew TextEncoder().encode(entry.source).byteLength +\n\t\t\t\tnew TextEncoder().encode(entry.manifestDigest).byteLength +\n\t\t\t\t(entry.signature === undefined ? 0 : new TextEncoder().encode(entry.signature).byteLength)\n\t\t\t);\n\t\t}, 0);\n\t\tif (payloadBytes > MAX_PLUGIN_REGISTRY_PAYLOAD_BYTES_V1)\n\t\t\tthrow new PluginRegistryErrorV1(\"payload_too_large\", \"Registry response exceeds the aggregate size limit\");\n\t\tconst seen = new Set<string>();\n\t\tconst accepted: PluginRegistryManifestEnvelopeV1[] = [];\n\t\tconst rejected: PluginRegistryRejectionV1[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tconst identity = `${entry.manifest.id}@${entry.manifest.pluginVersion}`;\n\t\t\tif (seen.has(identity))\n\t\t\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", `Duplicate registry manifest: ${identity}`);\n\t\t\tseen.add(identity);\n\t\t\ttry {\n\t\t\t\tawait validateSourceProof(entry, options.verify, options.sourceVerifier);\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof PluginRegistryErrorV1)) throw error;\n\t\t\t\tif (error.cause !== undefined) throw error;\n\t\t\t\tif (error.code !== \"source_rejected\" && error.code !== \"invalid_digest\") throw error;\n\t\t\t\trejected.push({\n\t\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\t\t\tcode: error.code === \"invalid_digest\" ? \"digest_rejected\" : \"source_rejected\",\n\t\t\t\t\treason:\n\t\t\t\t\t\terror.code === \"invalid_digest\" ? \"Manifest digest mismatch\" : \"Registry source proof was rejected\",\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (input.signal?.aborted)\n\t\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", \"Plugin registry operation was cancelled\");\n\t\t\taccepted.push(entry);\n\t\t}\n\t\tconst manifests = accepted.map((entry) => entry.manifest);\n\t\tconst catalog = buildPluginCatalogV1({\n\t\t\tmanifests,\n\t\t\thost: options.host,\n\t\t\tavailableCapabilities: options.availableCapabilities,\n\t\t\tmaxEntries: maxManifests,\n\t\t});\n\t\tconst publicEntries = Object.freeze(\n\t\t\t[...accepted]\n\t\t\t\t.sort((left, right) => {\n\t\t\t\t\tconst idOrder = left.manifest.id.localeCompare(right.manifest.id);\n\t\t\t\t\treturn idOrder === 0\n\t\t\t\t\t\t? comparePluginVersionsV1(right.manifest.pluginVersion, left.manifest.pluginVersion)\n\t\t\t\t\t\t: idOrder;\n\t\t\t\t})\n\t\t\t\t.map((entry) =>\n\t\t\t\t\tObject.freeze({\n\t\t\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\t\t\t\tsource: entry.source,\n\t\t\t\t\t\tmanifestDigest: entry.manifestDigest,\n\t\t\t\t\t\tsigned: entry.signature !== undefined,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t);\n\t\tconst catalogByIdentity = new Map(\n\t\t\tcatalog.entries.map((entry) => [`${entry.pluginId}@${entry.pluginVersion}`, entry] as const),\n\t\t);\n\t\tconst verified = Object.freeze(\n\t\t\tpublicEntries.flatMap((entry) => {\n\t\t\t\tconst catalogEntry = catalogByIdentity.get(`${entry.pluginId}@${entry.pluginVersion}`);\n\t\t\t\tif (catalogEntry?.resolution.status === \"installed-ready\")\n\t\t\t\t\treturn [{ ...entry, resolutionStatus: \"installed-ready\" as const }];\n\t\t\t\tconst reason = catalogEntry?.resolution.diagnostics[0]?.message ?? \"Plugin is incompatible with this host\";\n\t\t\t\trejected.push({\n\t\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\t\tpluginVersion: entry.pluginVersion,\n\t\t\t\t\tcode: \"incompatible\",\n\t\t\t\t\treason,\n\t\t\t\t});\n\t\t\t\treturn [];\n\t\t\t}),\n\t\t);\n\t\treturn {\n\t\t\taccepted: Object.freeze(accepted),\n\t\t\tsnapshot: Object.freeze({\n\t\t\t\tversion: 1,\n\t\t\t\tsource:\n\t\t\t\t\toptions.source.source === undefined ? sourceIdentity(accepted) : validateSource(options.source.source),\n\t\t\t\tentries: publicEntries,\n\t\t\t\tcatalog,\n\t\t\t\tverified,\n\t\t\t\trejected: Object.freeze(rejected),\n\t\t\t}),\n\t\t};\n\t};\n\tconst listManifests = async (\n\t\tinput: { readonly signal?: AbortSignal } = {},\n\t): Promise<readonly PluginManifestV1[]> => {\n\t\tconst loaded = await load(input);\n\t\treturn Object.freeze(\n\t\t\tloaded.snapshot.catalog.entries.flatMap((catalogEntry) =>\n\t\t\t\tloaded.accepted\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\tentry.manifest.id === catalogEntry.pluginId &&\n\t\t\t\t\t\t\tentry.manifest.pluginVersion === catalogEntry.pluginVersion,\n\t\t\t\t\t)\n\t\t\t\t\t.map((entry) => entry.manifest),\n\t\t\t),\n\t\t);\n\t};\n\treturn {\n\t\tlist: async (input = {}) => (await load(input)).snapshot,\n\t\tlistManifests,\n\t\tresolve: async (input) => {\n\t\t\tconst loaded = await load({ signal: input.signal });\n\t\t\tconst verified = new Set(loaded.snapshot.verified.map((entry) => `${entry.pluginId}@${entry.pluginVersion}`));\n\t\t\tconst identity =\n\t\t\t\tinput.pluginVersion === undefined\n\t\t\t\t\t? loaded.snapshot.catalog.entries.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.pluginId === input.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.resolution.status === \"installed-ready\" &&\n\t\t\t\t\t\t\t\tverified.has(`${candidate.pluginId}@${candidate.pluginVersion}`),\n\t\t\t\t\t\t)\n\t\t\t\t\t: loaded.snapshot.catalog.entries.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.pluginId === input.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.pluginVersion === input.pluginVersion &&\n\t\t\t\t\t\t\t\tcandidate.resolution.status === \"installed-ready\" &&\n\t\t\t\t\t\t\t\tverified.has(`${candidate.pluginId}@${candidate.pluginVersion}`),\n\t\t\t\t\t\t);\n\t\t\tconst entry =\n\t\t\t\tidentity === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: loaded.accepted.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.manifest.id === identity.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.manifest.pluginVersion === identity.pluginVersion,\n\t\t\t\t\t\t);\n\t\t\tif (entry === undefined) return undefined;\n\t\t\treturn Object.freeze({\n\t\t\t\tmanifest: entry.manifest,\n\t\t\t\tsource: entry.source,\n\t\t\t\texpectedDigest: entry.manifestDigest,\n\t\t\t\t...(entry.distribution === undefined ? {} : { distribution: entry.distribution }),\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport { buildPluginCatalogV1, comparePluginVersionsV1, type PluginCatalogSnapshotV1 } from \"./catalog.ts\";\nimport type { PluginDistributionDescriptorV1 } from \"./distribution.ts\";\nimport { createPluginDistributionV1 } from \"./distribution.ts\";\nimport type { CapabilityRefV1, HostFactsV1, PluginManifestV1, PluginSourceVerifierV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\n/** Maximum manifest JSON bytes accepted by the registry boundary. */\nexport const MAX_PLUGIN_REGISTRY_MANIFEST_BYTES_V1 = 64 * 1024;\n/** Maximum number of manifests returned by one source query. */\nexport const MAX_PLUGIN_REGISTRY_MANIFESTS_V1 = 256;\n/** Maximum aggregate manifest metadata returned by one source query. */\nexport const MAX_PLUGIN_REGISTRY_PAYLOAD_BYTES_V1 = 4 * 1024 * 1024;\n/** Maximum source URI length; sources are identifiers, never package paths. */\nexport const MAX_PLUGIN_REGISTRY_SOURCE_CHARS_V1 = 2048;\n/** Maximum digest/signature text length accepted from a source. */\nexport const MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1 = 512;\n\nexport interface PluginRegistryManifestEnvelopeV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly source: string;\n\treadonly manifestDigest: string;\n\t/** Optional host- or registry-supplied signature. The verifier owns semantics. */\n\treadonly signature?: string;\n\t/** Optional signed artifact descriptor bound to this exact manifest identity. */\n\treadonly distribution?: PluginDistributionDescriptorV1;\n}\n\n/**\n * A transport-neutral registry source. Hosts inject HTTP, filesystem, or\n * package-manager implementations. The registry never receives package bytes\n * and never exposes source response bodies to the model context.\n */\nexport interface PluginRegistrySourceV1 {\n\t/** Optional stable source identity shown in diagnostics; never a local path. */\n\treadonly source?: string;\n\treadonly list: (input: { readonly signal?: AbortSignal }) => Promise<readonly PluginRegistryManifestEnvelopeV1[]>;\n}\n\nexport interface PluginRegistryDigestVerifierV1 {\n\treadonly verify: (input: {\n\t\treadonly manifest: PluginManifestV1;\n\t\treadonly source: string;\n\t\treadonly manifestDigest: string;\n\t\treadonly expectedDigest?: string;\n\t\treadonly signature?: string;\n\t}) =>\n\t\t| { readonly status: \"accepted\" }\n\t\t| { readonly status: \"rejected\"; readonly reason?: string }\n\t\t| Promise<{ readonly status: \"accepted\" } | { readonly status: \"rejected\"; readonly reason?: string }>;\n}\n\nexport interface PluginRegistryOptionsV1 {\n\treadonly source: PluginRegistrySourceV1;\n\treadonly host: HostFactsV1;\n\t/** Required digest/signature verifier. No implicit trust fallback. */\n\treadonly verify: PluginRegistryDigestVerifierV1;\n\t/** Existing source verifier contract is mandatory at the registry boundary. */\n\treadonly sourceVerifier: PluginSourceVerifierV1;\n\treadonly availableCapabilities?: readonly CapabilityRefV1[];\n\treadonly maxManifests?: number;\n}\n\nexport type PluginRegistryErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_limit\"\n\t| \"source_rejected\"\n\t| \"invalid_manifest\"\n\t| \"invalid_source\"\n\t| \"invalid_digest\"\n\t| \"payload_too_large\"\n\t| \"too_many_manifests\"\n\t| \"incompatible\";\n\nexport class PluginRegistryErrorV1 extends Error {\n\treadonly code: PluginRegistryErrorCodeV1;\n\treadonly cause?: unknown;\n\n\tconstructor(code: PluginRegistryErrorCodeV1, message: string, cause?: unknown) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"PluginRegistryErrorV1\";\n\t\tthis.code = code;\n\t\tthis.cause = cause;\n\t}\n}\n\nexport interface PluginRegistryEntryV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly source: string;\n\treadonly manifestDigest: string;\n\treadonly signed: boolean;\n}\n\nexport type PluginRegistryRejectionCodeV1 = \"source_rejected\" | \"digest_rejected\" | \"incompatible\";\n\nexport interface PluginRegistryRejectionV1 {\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly code: PluginRegistryRejectionCodeV1;\n\treadonly reason: string;\n}\n\nexport interface PluginRegistryVerifiedEntryV1 extends PluginRegistryEntryV1 {\n\treadonly resolutionStatus: \"installed-ready\";\n}\n\nexport interface PluginRegistrySnapshotV1 {\n\treadonly version: 1;\n\treadonly source: string;\n\treadonly entries: readonly PluginRegistryEntryV1[];\n\treadonly catalog: PluginCatalogSnapshotV1;\n\t/** Only entries that passed proof validation and host compatibility. */\n\treadonly verified: readonly PluginRegistryVerifiedEntryV1[];\n\t/** Platform/API/test-only entries remain visible in catalog but are not verified. */\n\treadonly rejected: readonly PluginRegistryRejectionV1[];\n}\n\n/** Host-side package projection; package bytes never cross this boundary. */\nexport interface PluginRegistryResolvedPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly source: string;\n\treadonly expectedDigest: string;\n\treadonly distribution?: PluginDistributionDescriptorV1;\n}\n\nexport interface PluginRegistryV1 {\n\treadonly list: (input?: { readonly signal?: AbortSignal }) => Promise<PluginRegistrySnapshotV1>;\n\t/** Optional host-side resolver. Older custom registry implementations may omit it. */\n\treadonly resolve?: (input: {\n\t\treadonly pluginId: string;\n\t\treadonly pluginVersion?: string;\n\t\treadonly signal?: AbortSignal;\n\t}) => Promise<PluginRegistryResolvedPackageV1 | undefined>;\n\t/** Optional host-side manifest projection used by the CLI catalog command. */\n\treadonly listManifests?: (input?: { readonly signal?: AbortSignal }) => Promise<readonly PluginManifestV1[]>;\n}\n\nfunction isAbortLike(error: unknown, signal: AbortSignal | undefined): boolean {\n\treturn (\n\t\tsignal?.aborted === true ||\n\t\t(error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\"))\n\t);\n}\n\nfunction boundedString(\n\tvalue: unknown,\n\tlabel: string,\n\tmax: number,\n\tcode: PluginRegistryErrorCodeV1 = \"invalid_source\",\n): string {\n\tif (typeof value !== \"string\" || value.trim() === \"\" || value.length > max || /[\\u0000-\\u001f]/u.test(value)) {\n\t\tthrow new PluginRegistryErrorV1(code, t(\"{label} must be a non-empty bounded string\", { label }));\n\t}\n\treturn value;\n}\n\nfunction assertAllowedKeys(value: Record<string, unknown>, allowed: readonly string[], label: string): void {\n\tconst expected = new Set(allowed);\n\tif (Object.keys(value).some((key) => !expected.has(key)))\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"{label} contains an unsupported field\", { label }));\n}\n\nfunction validateSource(source: unknown): string {\n\tconst value = boundedString(source, \"source\", MAX_PLUGIN_REGISTRY_SOURCE_CHARS_V1);\n\tif (/^(?:file:|[a-zA-Z]:[\\\\/]|[\\\\/]{1,2}|\\\\\\\\)/iu.test(value) || /\\s/u.test(value)) {\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_source\",\n\t\t\tt(\"Plugin registry source must be an opaque URI, not a local path\"),\n\t\t);\n\t}\n\tif (/^https?:\\/\\//iu.test(value)) {\n\t\ttry {\n\t\t\tconst parsed = new URL(value);\n\t\t\tconst pathname = parsed.pathname.length > 512 ? `${parsed.pathname.slice(0, 511)}…` : parsed.pathname;\n\t\t\treturn `${parsed.origin}${pathname || \"/\"}`;\n\t\t} catch (error) {\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Plugin registry source URL is invalid\"), error);\n\t\t}\n\t}\n\treturn value;\n}\n\nfunction validateManifest(manifest: unknown): PluginManifestV1 {\n\tif (typeof manifest !== \"object\" || manifest === null || Array.isArray(manifest)) {\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry manifest must be an object\"));\n\t}\n\tconst value = manifest as Record<string, unknown>;\n\tassertAllowedKeys(\n\t\tvalue,\n\t\t[\n\t\t\t\"id\",\n\t\t\t\"pluginVersion\",\n\t\t\t\"apiVersion\",\n\t\t\t\"minHostVersion\",\n\t\t\t\"maxHostVersion\",\n\t\t\t\"capabilityRefs\",\n\t\t\t\"requires\",\n\t\t\t\"platform\",\n\t\t\t\"testOnly\",\n\t\t],\n\t\t\"Registry manifest\",\n\t);\n\tif (typeof value.id !== \"string\" || value.id.trim() === \"\" || value.id.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry manifest id is invalid\"));\n\tif (typeof value.pluginVersion !== \"string\" || value.pluginVersion.trim() === \"\" || value.pluginVersion.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry manifest pluginVersion is invalid\"));\n\tif (typeof value.apiVersion !== \"string\" || value.apiVersion.trim() === \"\" || value.apiVersion.length > 256)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry manifest apiVersion is invalid\"));\n\tif (value.minHostVersion === undefined && value.maxHostVersion === undefined)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_manifest\",\n\t\t\tt(\"Published plugins must declare host version compatibility range: set minHostVersion and/or maxHostVersion\"),\n\t\t);\n\tlet bytes: number;\n\ttry {\n\t\tbytes = new TextEncoder().encode(JSON.stringify(manifest)).byteLength;\n\t} catch (error) {\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry manifest cannot be serialized\"), error);\n\t}\n\tif (bytes > MAX_PLUGIN_REGISTRY_MANIFEST_BYTES_V1)\n\t\tthrow new PluginRegistryErrorV1(\"payload_too_large\", t(\"Registry manifest exceeds the size limit\"));\n\treturn Object.freeze({ ...value } as unknown as PluginManifestV1);\n}\n\nfunction validateEnvelope(value: unknown): PluginRegistryManifestEnvelopeV1 {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry response entry must be an object\"));\n\tconst entry = value as Record<string, unknown>;\n\tassertAllowedKeys(\n\t\tentry,\n\t\t[\"manifest\", \"source\", \"manifestDigest\", \"signature\", \"distribution\"],\n\t\t\"Registry response entry\",\n\t);\n\tconst manifest = validateManifest(entry.manifest);\n\tconst source = validateSource(entry.source);\n\tconst manifestDigest = boundedString(entry.manifestDigest, \"manifestDigest\", MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1);\n\tif (entry.signature !== undefined) boundedString(entry.signature, \"signature\", MAX_PLUGIN_REGISTRY_PROOF_CHARS_V1);\n\tlet distribution: PluginDistributionDescriptorV1 | undefined;\n\tif (entry.distribution !== undefined) {\n\t\ttry {\n\t\t\tdistribution = createPluginDistributionV1().validateDescriptor(entry.distribution);\n\t\t} catch (error) {\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry distribution descriptor is invalid\"), error);\n\t\t}\n\t\tif (\n\t\t\tdistribution.pluginId !== manifest.id ||\n\t\t\tdistribution.pluginVersion !== manifest.pluginVersion ||\n\t\t\tdistribution.manifestDigest !== manifestDigest\n\t\t)\n\t\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\t\"invalid_manifest\",\n\t\t\t\tt(\"Registry distribution descriptor does not match the manifest identity\"),\n\t\t\t);\n\t}\n\treturn Object.freeze({\n\t\tmanifest,\n\t\tsource,\n\t\tmanifestDigest,\n\t\t...(entry.signature === undefined ? {} : { signature: entry.signature as string }),\n\t\t...(distribution === undefined ? {} : { distribution }),\n\t});\n}\n\nfunction validateMax(value: number | undefined): number {\n\tconst max = value ?? MAX_PLUGIN_REGISTRY_MANIFESTS_V1;\n\tif (!Number.isSafeInteger(max) || max < 1 || max > MAX_PLUGIN_REGISTRY_MANIFESTS_V1)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_limit\",\n\t\t\tt(\"maxManifests must be an integer between 1 and {max}\", { max: MAX_PLUGIN_REGISTRY_MANIFESTS_V1 }),\n\t\t);\n\treturn max;\n}\n\nasync function validateSourceProof(\n\tentry: PluginRegistryManifestEnvelopeV1,\n\tverifier: PluginRegistryDigestVerifierV1,\n\tsourceVerifier: PluginSourceVerifierV1,\n): Promise<void> {\n\tconst actualDigest = pluginManifestDigestV1(entry.manifest);\n\tif (entry.manifestDigest !== actualDigest)\n\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\"invalid_digest\",\n\t\t\tt(\"Manifest digest mismatch for {identity}\", {\n\t\t\t\tidentity: `${entry.manifest.id}@${entry.manifest.pluginVersion}`,\n\t\t\t}),\n\t\t);\n\ttry {\n\t\tconst result = await verifier.verify({\n\t\t\tmanifest: entry.manifest,\n\t\t\tsource: entry.source,\n\t\t\tmanifestDigest: actualDigest,\n\t\t\texpectedDigest: entry.manifestDigest,\n\t\t\tsignature: entry.signature,\n\t\t});\n\t\tif (result.status !== \"accepted\")\n\t\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", result.reason ?? t(\"Registry source proof was rejected\"));\n\t} catch (error) {\n\t\tif (error instanceof PluginRegistryErrorV1) throw error;\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", t(\"Registry source proof was rejected\"), error);\n\t}\n\tlet result: ReturnType<PluginSourceVerifierV1>;\n\ttry {\n\t\tresult = sourceVerifier({\n\t\t\tpluginId: entry.manifest.id,\n\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\tsource: entry.source,\n\t\t\tmanifestDigest: actualDigest,\n\t\t});\n\t} catch (error) {\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", t(\"Plugin source verifier failed\"), error);\n\t}\n\tif (result.status !== \"accepted\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", result.reason ?? t(\"Plugin source was rejected\"));\n}\n\nfunction sourceIdentity(entries: readonly PluginRegistryManifestEnvelopeV1[]): string {\n\tconst sources = [...new Set(entries.map((entry) => entry.source))].sort((left, right) => left.localeCompare(right));\n\treturn sources.join(\",\");\n}\n\ninterface RegistryLoadV1 {\n\treadonly accepted: readonly PluginRegistryManifestEnvelopeV1[];\n\treadonly snapshot: PluginRegistrySnapshotV1;\n}\n\n/** Create a deterministic, host-injected registry client. */\nexport function createPluginRegistryV1(options: PluginRegistryOptionsV1): PluginRegistryV1 {\n\tconst maxManifests = validateMax(options.maxManifests);\n\tif (options.source === undefined || typeof options.source.list !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Registry source must provide list()\"));\n\tif (options.source.source !== undefined) validateSource(options.source.source);\n\tif (options.verify === undefined || typeof options.verify.verify !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", t(\"Registry source/digest verifier is required\"));\n\tif (options.sourceVerifier === undefined || typeof options.sourceVerifier !== \"function\")\n\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", t(\"Registry source verifier is required\"));\n\n\tconst load = async (input: { readonly signal?: AbortSignal } = {}): Promise<RegistryLoadV1> => {\n\t\tif (input.signal?.aborted)\n\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", t(\"Plugin registry operation was cancelled\"));\n\t\tlet raw: readonly PluginRegistryManifestEnvelopeV1[];\n\t\ttry {\n\t\t\traw = await options.source.list({ signal: input.signal });\n\t\t} catch (error) {\n\t\t\tif (isAbortLike(error, input.signal))\n\t\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", t(\"Plugin registry operation was cancelled\"), error);\n\t\t\tthrow new PluginRegistryErrorV1(\"source_rejected\", t(\"Plugin registry source failed\"), error);\n\t\t}\n\t\tif (input.signal?.aborted)\n\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", t(\"Plugin registry operation was cancelled\"));\n\t\tif (!Array.isArray(raw))\n\t\t\tthrow new PluginRegistryErrorV1(\"invalid_manifest\", t(\"Registry source must return an array\"));\n\t\tif (raw.length > maxManifests)\n\t\t\tthrow new PluginRegistryErrorV1(\"too_many_manifests\", t(\"Registry response contains too many manifests\"));\n\t\tconst entries = raw.map(validateEnvelope);\n\t\tconst payloadBytes = entries.reduce((total, entry) => {\n\t\t\tconst manifestBytes = new TextEncoder().encode(JSON.stringify(entry.manifest)).byteLength;\n\t\t\tconst distributionBytes =\n\t\t\t\tentry.distribution === undefined\n\t\t\t\t\t? 0\n\t\t\t\t\t: new TextEncoder().encode(JSON.stringify(entry.distribution)).byteLength;\n\t\t\treturn (\n\t\t\t\ttotal +\n\t\t\t\tmanifestBytes +\n\t\t\t\tdistributionBytes +\n\t\t\t\tnew TextEncoder().encode(entry.source).byteLength +\n\t\t\t\tnew TextEncoder().encode(entry.manifestDigest).byteLength +\n\t\t\t\t(entry.signature === undefined ? 0 : new TextEncoder().encode(entry.signature).byteLength)\n\t\t\t);\n\t\t}, 0);\n\t\tif (payloadBytes > MAX_PLUGIN_REGISTRY_PAYLOAD_BYTES_V1)\n\t\t\tthrow new PluginRegistryErrorV1(\"payload_too_large\", t(\"Registry response exceeds the aggregate size limit\"));\n\t\tconst seen = new Set<string>();\n\t\tconst accepted: PluginRegistryManifestEnvelopeV1[] = [];\n\t\tconst rejected: PluginRegistryRejectionV1[] = [];\n\t\tfor (const entry of entries) {\n\t\t\tconst identity = `${entry.manifest.id}@${entry.manifest.pluginVersion}`;\n\t\t\tif (seen.has(identity))\n\t\t\t\tthrow new PluginRegistryErrorV1(\n\t\t\t\t\t\"invalid_manifest\",\n\t\t\t\t\tt(\"Duplicate registry manifest: {identity}\", { identity }),\n\t\t\t\t);\n\t\t\tseen.add(identity);\n\t\t\ttry {\n\t\t\t\tawait validateSourceProof(entry, options.verify, options.sourceVerifier);\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof PluginRegistryErrorV1)) throw error;\n\t\t\t\tif (error.cause !== undefined) throw error;\n\t\t\t\tif (error.code !== \"source_rejected\" && error.code !== \"invalid_digest\") throw error;\n\t\t\t\trejected.push({\n\t\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\t\t\tcode: error.code === \"invalid_digest\" ? \"digest_rejected\" : \"source_rejected\",\n\t\t\t\t\treason:\n\t\t\t\t\t\terror.code === \"invalid_digest\" ? \"Manifest digest mismatch\" : \"Registry source proof was rejected\",\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (input.signal?.aborted)\n\t\t\t\tthrow new PluginRegistryErrorV1(\"cancelled\", t(\"Plugin registry operation was cancelled\"));\n\t\t\taccepted.push(entry);\n\t\t}\n\t\tconst manifests = accepted.map((entry) => entry.manifest);\n\t\tconst catalog = buildPluginCatalogV1({\n\t\t\tmanifests,\n\t\t\thost: options.host,\n\t\t\tavailableCapabilities: options.availableCapabilities,\n\t\t\tmaxEntries: maxManifests,\n\t\t});\n\t\tconst publicEntries = Object.freeze(\n\t\t\t[...accepted]\n\t\t\t\t.sort((left, right) => {\n\t\t\t\t\tconst idOrder = left.manifest.id.localeCompare(right.manifest.id);\n\t\t\t\t\treturn idOrder === 0\n\t\t\t\t\t\t? comparePluginVersionsV1(right.manifest.pluginVersion, left.manifest.pluginVersion)\n\t\t\t\t\t\t: idOrder;\n\t\t\t\t})\n\t\t\t\t.map((entry) =>\n\t\t\t\t\tObject.freeze({\n\t\t\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\t\t\tpluginVersion: entry.manifest.pluginVersion,\n\t\t\t\t\t\tsource: entry.source,\n\t\t\t\t\t\tmanifestDigest: entry.manifestDigest,\n\t\t\t\t\t\tsigned: entry.signature !== undefined,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t);\n\t\tconst catalogByIdentity = new Map(\n\t\t\tcatalog.entries.map((entry) => [`${entry.pluginId}@${entry.pluginVersion}`, entry] as const),\n\t\t);\n\t\tconst verified = Object.freeze(\n\t\t\tpublicEntries.flatMap((entry) => {\n\t\t\t\tconst catalogEntry = catalogByIdentity.get(`${entry.pluginId}@${entry.pluginVersion}`);\n\t\t\t\tif (catalogEntry?.resolution.status === \"installed-ready\")\n\t\t\t\t\treturn [{ ...entry, resolutionStatus: \"installed-ready\" as const }];\n\t\t\t\tconst reason = catalogEntry?.resolution.diagnostics[0]?.message ?? \"Plugin is incompatible with this host\";\n\t\t\t\trejected.push({\n\t\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\t\tpluginVersion: entry.pluginVersion,\n\t\t\t\t\tcode: \"incompatible\",\n\t\t\t\t\treason,\n\t\t\t\t});\n\t\t\t\treturn [];\n\t\t\t}),\n\t\t);\n\t\treturn {\n\t\t\taccepted: Object.freeze(accepted),\n\t\t\tsnapshot: Object.freeze({\n\t\t\t\tversion: 1,\n\t\t\t\tsource:\n\t\t\t\t\toptions.source.source === undefined ? sourceIdentity(accepted) : validateSource(options.source.source),\n\t\t\t\tentries: publicEntries,\n\t\t\t\tcatalog,\n\t\t\t\tverified,\n\t\t\t\trejected: Object.freeze(rejected),\n\t\t\t}),\n\t\t};\n\t};\n\tconst listManifests = async (\n\t\tinput: { readonly signal?: AbortSignal } = {},\n\t): Promise<readonly PluginManifestV1[]> => {\n\t\tconst loaded = await load(input);\n\t\treturn Object.freeze(\n\t\t\tloaded.snapshot.catalog.entries.flatMap((catalogEntry) =>\n\t\t\t\tloaded.accepted\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t\tentry.manifest.id === catalogEntry.pluginId &&\n\t\t\t\t\t\t\tentry.manifest.pluginVersion === catalogEntry.pluginVersion,\n\t\t\t\t\t)\n\t\t\t\t\t.map((entry) => entry.manifest),\n\t\t\t),\n\t\t);\n\t};\n\treturn {\n\t\tlist: async (input = {}) => (await load(input)).snapshot,\n\t\tlistManifests,\n\t\tresolve: async (input) => {\n\t\t\tconst loaded = await load({ signal: input.signal });\n\t\t\tconst verified = new Set(loaded.snapshot.verified.map((entry) => `${entry.pluginId}@${entry.pluginVersion}`));\n\t\t\tconst identity =\n\t\t\t\tinput.pluginVersion === undefined\n\t\t\t\t\t? loaded.snapshot.catalog.entries.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.pluginId === input.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.resolution.status === \"installed-ready\" &&\n\t\t\t\t\t\t\t\tverified.has(`${candidate.pluginId}@${candidate.pluginVersion}`),\n\t\t\t\t\t\t)\n\t\t\t\t\t: loaded.snapshot.catalog.entries.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.pluginId === input.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.pluginVersion === input.pluginVersion &&\n\t\t\t\t\t\t\t\tcandidate.resolution.status === \"installed-ready\" &&\n\t\t\t\t\t\t\t\tverified.has(`${candidate.pluginId}@${candidate.pluginVersion}`),\n\t\t\t\t\t\t);\n\t\t\tconst entry =\n\t\t\t\tidentity === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: loaded.accepted.find(\n\t\t\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\t\t\tcandidate.manifest.id === identity.pluginId &&\n\t\t\t\t\t\t\t\tcandidate.manifest.pluginVersion === identity.pluginVersion,\n\t\t\t\t\t\t);\n\t\t\tif (entry === undefined) return undefined;\n\t\t\treturn Object.freeze({\n\t\t\t\tmanifest: entry.manifest,\n\t\t\t\tsource: entry.source,\n\t\t\t\texpectedDigest: entry.manifestDigest,\n\t\t\t\t...(entry.distribution === undefined ? {} : { distribution: entry.distribution }),\n\t\t\t});\n\t\t},\n\t};\n}\n"]}