@ai-agent-forge/agent-forge 0.86.7 → 0.88.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 (717) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +10 -11
  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 +430 -413
  7. package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
  8. package/dist/bundle/chunks/chunk-HLJEVRWP.js +13 -0
  9. package/dist/bundle/chunks/chunk-YGHQME4V.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 +17 -4
  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 +5 -3
  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 +6 -10
  54. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  55. package/dist/core/agent-session-compaction.js +35 -133
  56. package/dist/core/agent-session-compaction.js.map +1 -1
  57. package/dist/core/agent-session-context.d.ts.map +1 -1
  58. package/dist/core/agent-session-context.js +18 -13
  59. package/dist/core/agent-session-context.js.map +1 -1
  60. package/dist/core/agent-session-internal.d.ts +0 -6
  61. package/dist/core/agent-session-internal.d.ts.map +1 -1
  62. package/dist/core/agent-session-internal.js.map +1 -1
  63. package/dist/core/agent-session-model.d.ts.map +1 -1
  64. package/dist/core/agent-session-model.js +2 -1
  65. package/dist/core/agent-session-model.js.map +1 -1
  66. package/dist/core/agent-session-retry.d.ts.map +1 -1
  67. package/dist/core/agent-session-retry.js +3 -3
  68. package/dist/core/agent-session-retry.js.map +1 -1
  69. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  70. package/dist/core/agent-session-runtime.js +7 -6
  71. package/dist/core/agent-session-runtime.js.map +1 -1
  72. package/dist/core/agent-session-services.d.ts +1 -1
  73. package/dist/core/agent-session-services.d.ts.map +1 -1
  74. package/dist/core/agent-session-services.js.map +1 -1
  75. package/dist/core/agent-session-tools.d.ts.map +1 -1
  76. package/dist/core/agent-session-tools.js +3 -2
  77. package/dist/core/agent-session-tools.js.map +1 -1
  78. package/dist/core/agent-session.d.ts +40 -22
  79. package/dist/core/agent-session.d.ts.map +1 -1
  80. package/dist/core/agent-session.js +147 -67
  81. package/dist/core/agent-session.js.map +1 -1
  82. package/dist/core/auth-guidance.d.ts.map +1 -1
  83. package/dist/core/auth-guidance.js +11 -5
  84. package/dist/core/auth-guidance.js.map +1 -1
  85. package/dist/core/auth-storage.d.ts.map +1 -1
  86. package/dist/core/auth-storage.js +9 -6
  87. package/dist/core/auth-storage.js.map +1 -1
  88. package/dist/core/compaction/compaction.d.ts.map +1 -1
  89. package/dist/core/compaction/compaction.js +2 -1
  90. package/dist/core/compaction/compaction.js.map +1 -1
  91. package/dist/core/embedded-sdk.d.ts.map +1 -1
  92. package/dist/core/embedded-sdk.js +10 -6
  93. package/dist/core/embedded-sdk.js.map +1 -1
  94. package/dist/core/export-html/index.d.ts.map +1 -1
  95. package/dist/core/export-html/index.js +9 -4
  96. package/dist/core/export-html/index.js.map +1 -1
  97. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  98. package/dist/core/extensions/agent-composition.js +26 -19
  99. package/dist/core/extensions/agent-composition.js.map +1 -1
  100. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  101. package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
  102. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  103. package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +1 -1
  104. package/dist/core/extensions/bootstrap-compaction-policy.js +0 -34
  105. package/dist/core/extensions/bootstrap-compaction-policy.js.map +1 -1
  106. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  107. package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
  108. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  109. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
  110. package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
  111. package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
  112. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
  113. package/dist/core/extensions/bootstrap-retry-policy.js +4 -3
  114. package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
  115. package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
  116. package/dist/core/extensions/bootstrap-skills.js +7 -6
  117. package/dist/core/extensions/bootstrap-skills.js.map +1 -1
  118. package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
  119. package/dist/core/extensions/bootstrap-tools.js +2 -1
  120. package/dist/core/extensions/bootstrap-tools.js.map +1 -1
  121. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  122. package/dist/core/extensions/capability-plugin.js +37 -13
  123. package/dist/core/extensions/capability-plugin.js.map +1 -1
  124. package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
  125. package/dist/core/extensions/capability-runtime-events.js +17 -13
  126. package/dist/core/extensions/capability-runtime-events.js.map +1 -1
  127. package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
  128. package/dist/core/extensions/capability-runtime-guards.js +16 -15
  129. package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
  130. package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
  131. package/dist/core/extensions/capability-runtime-manifest.js +52 -30
  132. package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
  133. package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
  134. package/dist/core/extensions/capability-runtime-validation.js +66 -65
  135. package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
  136. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  137. package/dist/core/extensions/capability-runtime.js +147 -127
  138. package/dist/core/extensions/capability-runtime.js.map +1 -1
  139. package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
  140. package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
  141. package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
  142. package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
  143. package/dist/core/extensions/context-strategy-binding.js +7 -4
  144. package/dist/core/extensions/context-strategy-binding.js.map +1 -1
  145. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  146. package/dist/core/extensions/lifecycle-catalog.js +290 -279
  147. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  148. package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
  149. package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
  150. package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
  151. package/dist/core/extensions/provider-failover.d.ts +7 -3
  152. package/dist/core/extensions/provider-failover.d.ts.map +1 -1
  153. package/dist/core/extensions/provider-failover.js +9 -8
  154. package/dist/core/extensions/provider-failover.js.map +1 -1
  155. package/dist/core/facade/coding-agent-facade.d.ts +6 -6
  156. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  157. package/dist/core/facade/coding-agent-facade.js +2 -3
  158. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  159. package/dist/core/http-dispatcher.d.ts.map +1 -1
  160. package/dist/core/http-dispatcher.js +2 -1
  161. package/dist/core/http-dispatcher.js.map +1 -1
  162. package/dist/core/i18n/index.d.ts +14 -0
  163. package/dist/core/i18n/index.d.ts.map +1 -0
  164. package/dist/core/i18n/index.js +67 -0
  165. package/dist/core/i18n/index.js.map +1 -0
  166. package/dist/core/i18n/locales/en/example.d.ts +7 -0
  167. package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
  168. package/dist/core/i18n/locales/en/example.js +7 -0
  169. package/dist/core/i18n/locales/en/example.js.map +1 -0
  170. package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
  171. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
  172. package/dist/core/i18n/locales/zh-cn/cli.js +229 -0
  173. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
  174. package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
  175. package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
  176. package/dist/core/i18n/locales/zh-cn/common.js +6 -0
  177. package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
  178. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
  179. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
  180. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
  181. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
  182. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
  183. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
  184. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
  185. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
  186. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
  187. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
  188. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
  189. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
  190. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
  191. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
  192. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
  193. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
  194. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
  195. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
  196. package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
  197. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
  198. package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
  199. package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
  200. package/dist/core/i18n/locales/zh-cn/example.js +10 -0
  201. package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
  202. package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
  203. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
  204. package/dist/core/i18n/locales/zh-cn/index.js +41 -0
  205. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
  206. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
  207. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
  208. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +267 -0
  209. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
  210. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
  211. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
  212. package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
  213. package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
  214. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
  215. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
  216. package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
  217. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
  218. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
  219. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
  220. package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
  221. package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
  222. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
  223. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
  224. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
  225. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
  226. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
  227. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
  228. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +286 -0
  229. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
  230. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
  231. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
  232. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
  233. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
  234. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
  235. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
  236. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
  237. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
  238. package/dist/core/keybindings.d.ts +15 -0
  239. package/dist/core/keybindings.d.ts.map +1 -1
  240. package/dist/core/keybindings.js +18 -0
  241. package/dist/core/keybindings.js.map +1 -1
  242. package/dist/core/logger.d.ts.map +1 -1
  243. package/dist/core/logger.js +5 -1
  244. package/dist/core/logger.js.map +1 -1
  245. package/dist/core/model-config.d.ts +0 -1
  246. package/dist/core/model-config.d.ts.map +1 -1
  247. package/dist/core/model-config.js +9 -1
  248. package/dist/core/model-config.js.map +1 -1
  249. package/dist/core/model-registry.d.ts.map +1 -1
  250. package/dist/core/model-registry.js +2 -1
  251. package/dist/core/model-registry.js.map +1 -1
  252. package/dist/core/model-runtime.d.ts.map +1 -1
  253. package/dist/core/model-runtime.js +11 -7
  254. package/dist/core/model-runtime.js.map +1 -1
  255. package/dist/core/package-install-host.d.ts.map +1 -1
  256. package/dist/core/package-install-host.js +4 -3
  257. package/dist/core/package-install-host.js.map +1 -1
  258. package/dist/core/package-manager.d.ts.map +1 -1
  259. package/dist/core/package-manager.js +15 -10
  260. package/dist/core/package-manager.js.map +1 -1
  261. package/dist/core/package-resource-collection.d.ts.map +1 -1
  262. package/dist/core/package-resource-collection.js +2 -1
  263. package/dist/core/package-resource-collection.js.map +1 -1
  264. package/dist/core/package-source.d.ts.map +1 -1
  265. package/dist/core/package-source.js +3 -2
  266. package/dist/core/package-source.js.map +1 -1
  267. package/dist/core/provider-composer.d.ts +2 -2
  268. package/dist/core/provider-composer.d.ts.map +1 -1
  269. package/dist/core/provider-composer.js +29 -21
  270. package/dist/core/provider-composer.js.map +1 -1
  271. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  272. package/dist/core/remote-catalog-provider.js +6 -2
  273. package/dist/core/remote-catalog-provider.js.map +1 -1
  274. package/dist/core/resolve-config-value.d.ts.map +1 -1
  275. package/dist/core/resolve-config-value.js +15 -5
  276. package/dist/core/resolve-config-value.js.map +1 -1
  277. package/dist/core/sdk.d.ts +27 -5
  278. package/dist/core/sdk.d.ts.map +1 -1
  279. package/dist/core/sdk.js +80 -55
  280. package/dist/core/sdk.js.map +1 -1
  281. package/dist/core/session-cwd.d.ts.map +1 -1
  282. package/dist/core/session-cwd.js +5 -2
  283. package/dist/core/session-cwd.js.map +1 -1
  284. package/dist/core/session-export.d.ts.map +1 -1
  285. package/dist/core/session-export.js +2 -1
  286. package/dist/core/session-export.js.map +1 -1
  287. package/dist/core/session-manager.d.ts.map +1 -1
  288. package/dist/core/session-manager.js +39 -29
  289. package/dist/core/session-manager.js.map +1 -1
  290. package/dist/core/session-storage.d.ts.map +1 -1
  291. package/dist/core/session-storage.js +3 -3
  292. package/dist/core/session-storage.js.map +1 -1
  293. package/dist/core/settings-manager.d.ts +20 -20
  294. package/dist/core/settings-manager.d.ts.map +1 -1
  295. package/dist/core/settings-manager.js +47 -59
  296. package/dist/core/settings-manager.js.map +1 -1
  297. package/dist/core/slash-commands.d.ts.map +1 -1
  298. package/dist/core/slash-commands.js +53 -32
  299. package/dist/core/slash-commands.js.map +1 -1
  300. package/dist/core/system-prompt.d.ts.map +1 -1
  301. package/dist/core/system-prompt.js +25 -2
  302. package/dist/core/system-prompt.js.map +1 -1
  303. package/dist/core/tools/bash.d.ts.map +1 -1
  304. package/dist/core/tools/bash.js +11 -7
  305. package/dist/core/tools/bash.js.map +1 -1
  306. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  307. package/dist/core/tools/edit-diff.js +9 -4
  308. package/dist/core/tools/edit-diff.js.map +1 -1
  309. package/dist/core/tools/edit.d.ts.map +1 -1
  310. package/dist/core/tools/edit.js +4 -3
  311. package/dist/core/tools/edit.js.map +1 -1
  312. package/dist/core/tools/index.d.ts.map +1 -1
  313. package/dist/core/tools/index.js +3 -2
  314. package/dist/core/tools/index.js.map +1 -1
  315. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  316. package/dist/core/tools/output-accumulator.js +2 -1
  317. package/dist/core/tools/output-accumulator.js.map +1 -1
  318. package/dist/core/tools/read.d.ts.map +1 -1
  319. package/dist/core/tools/read.js +6 -2
  320. package/dist/core/tools/read.js.map +1 -1
  321. package/dist/core/tools/write.d.ts.map +1 -1
  322. package/dist/core/tools/write.js +2 -1
  323. package/dist/core/tools/write.js.map +1 -1
  324. package/dist/durable/durable-service.d.ts.map +1 -1
  325. package/dist/durable/durable-service.js +25 -18
  326. package/dist/durable/durable-service.js.map +1 -1
  327. package/dist/host/checkpoint-commit.d.ts.map +1 -1
  328. package/dist/host/checkpoint-commit.js +2 -1
  329. package/dist/host/checkpoint-commit.js.map +1 -1
  330. package/dist/host/manual-compaction.d.ts.map +1 -1
  331. package/dist/host/manual-compaction.js +2 -1
  332. package/dist/host/manual-compaction.js.map +1 -1
  333. package/dist/host/output-projection.d.ts +0 -13
  334. package/dist/host/output-projection.d.ts.map +1 -1
  335. package/dist/host/output-projection.js +16 -2
  336. package/dist/host/output-projection.js.map +1 -1
  337. package/dist/host/summary-retry.d.ts.map +1 -1
  338. package/dist/host/summary-retry.js +3 -2
  339. package/dist/host/summary-retry.js.map +1 -1
  340. package/dist/main.d.ts.map +1 -1
  341. package/dist/main.js +97 -60
  342. package/dist/main.js.map +1 -1
  343. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  344. package/dist/modes/interactive/components/agents-view.js +18 -15
  345. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  346. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  347. package/dist/modes/interactive/components/assistant-message.js +6 -5
  348. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  349. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/bash-execution.js +12 -7
  351. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  352. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/bordered-loader.js +2 -1
  354. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  355. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  356. package/dist/modes/interactive/components/branch-summary-message.js +6 -5
  357. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  358. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  359. package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
  360. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  361. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  362. package/dist/modes/interactive/components/config-selector.js +18 -15
  363. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  364. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  365. package/dist/modes/interactive/components/custom-entry.js +2 -1
  366. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  367. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/dialog-editor.js +5 -4
  369. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  370. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/dialog-input.js +2 -1
  372. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  373. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/dialog-selector.js +4 -3
  375. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  376. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/first-time-setup.js +11 -10
  378. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  379. package/dist/modes/interactive/components/footer.d.ts +0 -2
  380. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  381. package/dist/modes/interactive/components/footer.js +8 -10
  382. package/dist/modes/interactive/components/footer.js.map +1 -1
  383. package/dist/modes/interactive/components/index.d.ts +1 -0
  384. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/index.js +1 -0
  386. package/dist/modes/interactive/components/index.js.map +1 -1
  387. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  388. package/dist/modes/interactive/components/keybinding-hints.js +3 -2
  389. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  390. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/login-dialog.js +12 -11
  392. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  393. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  394. package/dist/modes/interactive/components/mermaid.js +6 -2
  395. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  396. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/model-selector.js +28 -16
  398. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  399. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/oauth-selector.js +10 -9
  401. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  402. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
  404. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  405. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
  407. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  408. package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
  409. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
  410. package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
  411. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
  412. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
  414. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  415. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/session-selector.js +43 -31
  417. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  418. package/dist/modes/interactive/components/settings-selector.d.ts +4 -6
  419. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/settings-selector.js +115 -120
  421. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  422. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  423. package/dist/modes/interactive/components/settings-submenu.js +5 -4
  424. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  425. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/show-images-selector.js +3 -2
  427. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  428. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
  430. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  431. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  432. package/dist/modes/interactive/components/status-indicator.js +14 -5
  433. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  434. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/theme-selector.js +2 -1
  436. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  437. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/thinking-selector.js +11 -4
  439. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  440. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  441. package/dist/modes/interactive/components/tool-execution.js +8 -3
  442. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  443. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  444. package/dist/modes/interactive/components/tree-list.js +7 -6
  445. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  446. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  447. package/dist/modes/interactive/components/tree-render.js +28 -23
  448. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  449. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/tree-selector.js +9 -7
  451. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  452. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  453. package/dist/modes/interactive/components/user-message-selector.js +5 -4
  454. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  455. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/workflow-view.js +36 -21
  457. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  458. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  459. package/dist/modes/interactive/external-editor.js +2 -1
  460. package/dist/modes/interactive/external-editor.js.map +1 -1
  461. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-auth.js +71 -40
  463. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  464. package/dist/modes/interactive/interactive-commands.d.ts +1 -0
  465. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-commands.js +3 -0
  467. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  468. package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
  469. package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
  470. package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
  471. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  472. package/dist/modes/interactive/interactive-format.js +34 -18
  473. package/dist/modes/interactive/interactive-format.js.map +1 -1
  474. package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
  475. package/dist/modes/interactive/interactive-helpers.js +7 -2
  476. package/dist/modes/interactive/interactive-helpers.js.map +1 -1
  477. package/dist/modes/interactive/interactive-mode.d.ts +4 -2
  478. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  479. package/dist/modes/interactive/interactive-mode.js +350 -279
  480. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  481. package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
  482. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  483. package/dist/modes/interactive/interactive-selectors.js +79 -25
  484. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  485. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  486. package/dist/modes/interactive/theme/theme-controller.js +5 -1
  487. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  488. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  489. package/dist/modes/interactive/theme/theme.js +26 -23
  490. package/dist/modes/interactive/theme/theme.js.map +1 -1
  491. package/dist/modes/json-event.d.ts.map +1 -1
  492. package/dist/modes/json-event.js +3 -2
  493. package/dist/modes/json-event.js.map +1 -1
  494. package/dist/modes/print-mode.d.ts.map +1 -1
  495. package/dist/modes/print-mode.js +3 -2
  496. package/dist/modes/print-mode.js.map +1 -1
  497. package/dist/modes/rpc/rpc-client.d.ts +0 -8
  498. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  499. package/dist/modes/rpc/rpc-client.js +3 -14
  500. package/dist/modes/rpc/rpc-client.js.map +1 -1
  501. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  502. package/dist/modes/rpc/rpc-mode.js +0 -9
  503. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  504. package/dist/modes/rpc/rpc-types.d.ts +0 -19
  505. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  506. package/dist/modes/rpc/rpc-types.js.map +1 -1
  507. package/dist/package-manager-cli.d.ts.map +1 -1
  508. package/dist/package-manager-cli.js +28 -13
  509. package/dist/package-manager-cli.js.map +1 -1
  510. package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
  511. package/dist/plugins/ecosystem/catalog.js +3 -2
  512. package/dist/plugins/ecosystem/catalog.js.map +1 -1
  513. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  514. package/dist/plugins/ecosystem/cli.js +2 -1
  515. package/dist/plugins/ecosystem/cli.js.map +1 -1
  516. package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
  517. package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
  518. package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
  519. package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
  520. package/dist/plugins/ecosystem/distribution.js +2 -1
  521. package/dist/plugins/ecosystem/distribution.js.map +1 -1
  522. package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
  523. package/dist/plugins/ecosystem/installer.js +3 -2
  524. package/dist/plugins/ecosystem/installer.js.map +1 -1
  525. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  526. package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
  527. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  528. package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
  529. package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
  530. package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
  531. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  532. package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
  533. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  534. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  535. package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
  536. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  537. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  538. package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
  539. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  540. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +9 -2
  541. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  542. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +44 -5
  543. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  544. package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
  545. package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
  546. package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
  547. package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
  548. package/dist/plugins/ecosystem/node-registry-source.js +31 -30
  549. package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
  550. package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
  551. package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
  552. package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
  553. package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
  554. package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
  555. package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
  556. package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
  557. package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
  558. package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
  559. package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
  560. package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
  561. package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
  562. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +9 -1
  563. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  564. package/dist/plugins/ecosystem/plugin-bootstrap.js +5 -0
  565. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  566. package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
  567. package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
  568. package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
  569. package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
  570. package/dist/plugins/ecosystem/registry.js +35 -32
  571. package/dist/plugins/ecosystem/registry.js.map +1 -1
  572. package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
  573. package/dist/plugins/ecosystem/resolver.js +3 -2
  574. package/dist/plugins/ecosystem/resolver.js.map +1 -1
  575. package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
  576. package/dist/plugins/ecosystem/selection-store.js +11 -10
  577. package/dist/plugins/ecosystem/selection-store.js.map +1 -1
  578. package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
  579. package/dist/plugins/ecosystem/selection.js +8 -7
  580. package/dist/plugins/ecosystem/selection.js.map +1 -1
  581. package/dist/plugins/ecosystem/state.d.ts.map +1 -1
  582. package/dist/plugins/ecosystem/state.js +24 -23
  583. package/dist/plugins/ecosystem/state.js.map +1 -1
  584. package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
  585. package/dist/plugins/ecosystem/updates.js +5 -4
  586. package/dist/plugins/ecosystem/updates.js.map +1 -1
  587. package/dist/plugins/mcp-http.d.ts +0 -17
  588. package/dist/plugins/mcp-http.d.ts.map +1 -1
  589. package/dist/plugins/mcp-http.js +30 -7
  590. package/dist/plugins/mcp-http.js.map +1 -1
  591. package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
  592. package/dist/plugins/plugin-supervisor.js +19 -1
  593. package/dist/plugins/plugin-supervisor.js.map +1 -1
  594. package/dist/profile/first-roles.d.ts.map +1 -1
  595. package/dist/profile/first-roles.js +10 -1
  596. package/dist/profile/first-roles.js.map +1 -1
  597. package/dist/profile/goal-plugin.d.ts.map +1 -1
  598. package/dist/profile/goal-plugin.js +24 -5
  599. package/dist/profile/goal-plugin.js.map +1 -1
  600. package/dist/profile/identity.d.ts.map +1 -1
  601. package/dist/profile/identity.js +7 -6
  602. package/dist/profile/identity.js.map +1 -1
  603. package/dist/profile/lock.d.ts.map +1 -1
  604. package/dist/profile/lock.js +15 -1
  605. package/dist/profile/lock.js.map +1 -1
  606. package/dist/profile/plan-plugin.d.ts.map +1 -1
  607. package/dist/profile/plan-plugin.js +26 -13
  608. package/dist/profile/plan-plugin.js.map +1 -1
  609. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  610. package/dist/profile/plugin-profiles.js +2 -1
  611. package/dist/profile/plugin-profiles.js.map +1 -1
  612. package/dist/profile/policy-manifest.d.ts.map +1 -1
  613. package/dist/profile/policy-manifest.js +5 -4
  614. package/dist/profile/policy-manifest.js.map +1 -1
  615. package/dist/profile/profile-registry.d.ts +0 -12
  616. package/dist/profile/profile-registry.d.ts.map +1 -1
  617. package/dist/profile/profile-registry.js +14 -1
  618. package/dist/profile/profile-registry.js.map +1 -1
  619. package/dist/profile/role-catalog.d.ts +0 -1
  620. package/dist/profile/role-catalog.d.ts.map +1 -1
  621. package/dist/profile/role-catalog.js +17 -15
  622. package/dist/profile/role-catalog.js.map +1 -1
  623. package/dist/profile/role-orchestrator.d.ts.map +1 -1
  624. package/dist/profile/role-orchestrator.js +8 -7
  625. package/dist/profile/role-orchestrator.js.map +1 -1
  626. package/dist/profile/role-runner.d.ts.map +1 -1
  627. package/dist/profile/role-runner.js +3 -2
  628. package/dist/profile/role-runner.js.map +1 -1
  629. package/dist/profile/root-facade.d.ts.map +1 -1
  630. package/dist/profile/root-facade.js +2 -1
  631. package/dist/profile/root-facade.js.map +1 -1
  632. package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
  633. package/dist/profile/skill-discovery-wiring.js +7 -2
  634. package/dist/profile/skill-discovery-wiring.js.map +1 -1
  635. package/dist/profile/state-store.d.ts.map +1 -1
  636. package/dist/profile/state-store.js +13 -9
  637. package/dist/profile/state-store.js.map +1 -1
  638. package/dist/profile/todo-plugin.d.ts.map +1 -1
  639. package/dist/profile/todo-plugin.js +9 -4
  640. package/dist/profile/todo-plugin.js.map +1 -1
  641. package/dist/profiles/builtin-suites.d.ts +13 -6
  642. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  643. package/dist/profiles/builtin-suites.js +15 -6
  644. package/dist/profiles/builtin-suites.js.map +1 -1
  645. package/dist/profiles/suite-loader.d.ts +25 -1
  646. package/dist/profiles/suite-loader.d.ts.map +1 -1
  647. package/dist/profiles/suite-loader.js +34 -9
  648. package/dist/profiles/suite-loader.js.map +1 -1
  649. package/dist/remote/server-entry.d.ts.map +1 -1
  650. package/dist/remote/server-entry.js +3 -2
  651. package/dist/remote/server-entry.js.map +1 -1
  652. package/dist/remote/session-source.d.ts.map +1 -1
  653. package/dist/remote/session-source.js +8 -4
  654. package/dist/remote/session-source.js.map +1 -1
  655. package/dist/share/session-share.d.ts.map +1 -1
  656. package/dist/share/session-share.js +14 -2
  657. package/dist/share/session-share.js.map +1 -1
  658. package/dist/testing/plugin-testkit.d.ts.map +1 -1
  659. package/dist/testing/plugin-testkit.js +4 -3
  660. package/dist/testing/plugin-testkit.js.map +1 -1
  661. package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
  662. package/dist/testing/runtime-delivery-queue.js +2 -1
  663. package/dist/testing/runtime-delivery-queue.js.map +1 -1
  664. package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
  665. package/dist/testing/session-plugin-testkit.js +10 -7
  666. package/dist/testing/session-plugin-testkit.js.map +1 -1
  667. package/dist/utils/ansi.d.ts.map +1 -1
  668. package/dist/utils/ansi.js +2 -1
  669. package/dist/utils/ansi.js.map +1 -1
  670. package/dist/utils/clipboard.d.ts.map +1 -1
  671. package/dist/utils/clipboard.js +7 -6
  672. package/dist/utils/clipboard.js.map +1 -1
  673. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  674. package/dist/utils/image-resize-worker.js +3 -2
  675. package/dist/utils/image-resize-worker.js.map +1 -1
  676. package/dist/utils/photon.d.ts +2 -2
  677. package/dist/utils/photon.d.ts.map +1 -1
  678. package/dist/utils/photon.js +2 -2
  679. package/dist/utils/photon.js.map +1 -1
  680. package/dist/utils/shell.d.ts.map +1 -1
  681. package/dist/utils/shell.js +9 -8
  682. package/dist/utils/shell.js.map +1 -1
  683. package/dist/utils/tools-manager.d.ts.map +1 -1
  684. package/dist/utils/tools-manager.js +23 -13
  685. package/dist/utils/tools-manager.js.map +1 -1
  686. package/dist/utils/version-check.d.ts.map +1 -1
  687. package/dist/utils/version-check.js +5 -1
  688. package/dist/utils/version-check.js.map +1 -1
  689. package/docs/compaction.md +1 -3
  690. package/docs/docs.json +4 -0
  691. package/docs/index.md +1 -0
  692. package/docs/keybindings.md +3 -0
  693. package/docs/mcp.md +103 -0
  694. package/docs/models.md +14 -22
  695. package/docs/providers.md +0 -1
  696. package/docs/quickstart.md +1 -1
  697. package/docs/rpc.md +1 -26
  698. package/docs/sdk.md +4 -6
  699. package/docs/settings.md +10 -12
  700. package/docs/skills.md +1 -9
  701. package/docs/terminal-setup.md +2 -3
  702. package/docs/usage.md +7 -6
  703. package/examples/extensions/with-deps/package-lock.json +2 -2
  704. package/examples/extensions/with-deps/package.json +1 -1
  705. package/examples/extensions/with-deps/plugin.json +1 -1
  706. package/examples/sdk/10-settings.ts +2 -4
  707. package/examples/sdk/12-full-control.ts +1 -2
  708. package/package.json +1 -3
  709. package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
  710. package/dist/core/extensions/microcompact.d.ts +0 -80
  711. package/dist/core/extensions/microcompact.d.ts.map +0 -1
  712. package/dist/core/extensions/microcompact.js +0 -134
  713. package/dist/core/extensions/microcompact.js.map +0 -1
  714. package/dist/server/create-harness.d.ts +0 -26
  715. package/dist/server/create-harness.d.ts.map +0 -1
  716. package/dist/server/create-harness.js +0 -106
  717. package/dist/server/create-harness.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"node-package-install-host.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-package-install-host.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAO3G,OAAO,KAAK,EAAoB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGzE,QAAA,MAAM,oCAAoC,GAAa,CAAC;AACxD,eAAO,MAAM,8BAA8B,GAAa,CAAC;AAmBzD,MAAM,MAAM,6BAA6B,GACtC,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,wBAAwB,GACxB,iBAAiB,GACjB,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,2BAA2B,GAC3B,sBAAsB,GACtB,gCAAgC,GAChC,wBAAwB,CAAC;AAE5B,qBAAa,yBAA0B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAE7C,YAAY,IAAI,EAAE,6BAA6B,EAI9C;CACD;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,+BAAgC,SAAQ,sBAAsB;IAC9E,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE;QAC9B,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC9B,KAAK,aAAa,CAAC,UAAU,CAAC,CAAC;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChE,mFAAmF;IACnF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAC7B,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;QAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;QACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;KAC7B,KAAK,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACxE;AAED,6EAA6E;AAC7E,MAAM,WAAW,2CAA2C;IAC3D,QAAQ,CAAC,4BAA4B,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7C,CAAC,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACtD,OAAO,EAAE,2CAA2C,GAClD,WAAW,CAAC,+BAA+B,CAAC,YAAY,CAAC,CAAC,CAK5D;AAED;;;;GAIG;AACH,wBAAsB,wCAAwC,CAC7D,OAAO,EAAE,+BAA+B,EACxC,OAAO,EAAE,2CAA2C,GAClD,OAAO,CAAC,wBAAwB,CAAC,CAMnC;AAED,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,OAAO,EAAE,OAAO,oCAAoC,CAAC;IAC9D,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;IAClE,+FAA+F;IAC/F,QAAQ,CAAC,wBAAwB,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;KAAE,KAAK,MAAM,CAAC;IACtG,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAoCD,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,sBAAsB,GAAG,QAAQ,CAAC,sBAAsB,CAAC,CAsBhH;AAsBD,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAqBzG;AA2LD,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,UAAU,EACjB,WAAW,GAAE,sBAA2B,GACtC,SAAS,qBAAqB,EAAE,CAclC;AAkKD;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CACnD,OAAO,EAAE,+BAA+B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CA+ZnC","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, mkdtemp, rename, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport { inflateRawSync } from \"node:zlib\";\nimport { parseCapabilityPluginManifest } from \"../../core/extensions/capability-plugin.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginInstallationScopeV1, PluginInstallationV1, PluginInstallHostV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallPersistenceV1,\n\ttype NodePackageInstallPersistenceV1,\n\ttype NodePackageInstallPersistentRecordV1,\n} from \"./node-package-install-persistence.ts\";\nimport { parseNodeTarGzPackageV1 } from \"./node-tar-package.ts\";\nimport type { PluginManifestV1, PluginUpdateRecordV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\nconst NODE_PACKAGE_INSTALL_HOST_VERSION_V1 = 1 as const;\nexport const NODE_PACKAGE_FORMAT_VERSION_V1 = 1 as const;\nconst DEFAULT_MAX_ARCHIVE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_ARCHIVE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_MAX_EXTRACTED_BYTES_V1 = 256 * 1024 * 1024;\nconst MAX_EXTRACTED_BYTES_V1 = 1024 * 1024 * 1024;\nconst DEFAULT_MAX_ENTRY_BYTES_V1 = 64 * 1024 * 1024;\nconst MAX_ENTRY_BYTES_V1 = 256 * 1024 * 1024;\nconst DEFAULT_MAX_ENTRIES_V1 = 2048;\nconst MAX_ENTRIES_V1 = 8192;\nconst MAX_PACKAGE_MANIFEST_BYTES_V1 = 64 * 1024;\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\nconst CAPABILITY_MANIFEST_FILE_V1 = \"plugin.json\";\n\nconst LOCAL_FILE_HEADER_V1 = 0x04034b50;\nconst CENTRAL_FILE_HEADER_V1 = 0x02014b50;\nconst END_OF_CENTRAL_DIRECTORY_V1 = 0x06054b50;\nconst ZIP64_END_OF_CENTRAL_DIRECTORY_V1 = 0x06064b50;\nconst ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_V1 = 0x07064b50;\n\nexport type NodePackageInstallErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"host_closed\"\n\t| \"invalid_artifact\"\n\t| \"unsupported_media_type\"\n\t| \"archive_invalid\"\n\t| \"archive_budget_exceeded\"\n\t| \"package_manifest_missing\"\n\t| \"package_manifest_invalid\"\n\t| \"package_manifest_mismatch\"\n\t| \"installation_unknown\"\n\t| \"installation_identity_mismatch\"\n\t| \"installation_io_failed\";\n\nexport class NodePackageInstallErrorV1 extends Error {\n\treadonly code: NodePackageInstallErrorCodeV1;\n\n\tconstructor(code: NodePackageInstallErrorCodeV1) {\n\t\tsuper(`Node package installation failed: ${code}`);\n\t\tthis.name = \"NodePackageInstallErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeZipPackageEntryV1 {\n\treadonly name: string;\n\treadonly directory: boolean;\n\treadonly bytes: Uint8Array;\n}\n\nexport interface NodeZipPackageLimitsV1 {\n\treadonly maxArchiveBytes?: number;\n\treadonly maxExtractedBytes?: number;\n\treadonly maxEntryBytes?: number;\n\treadonly maxEntries?: number;\n}\n\nexport interface NodePackageInstallHostOptionsV1 extends NodeZipPackageLimitsV1 {\n\t/** An opaque artifact reader owned by the distribution host. */\n\treadonly openArtifact: (input: {\n\t\treadonly artifact: PluginDistributionArtifactV1;\n\t\treadonly signal?: AbortSignal;\n\t}) => AsyncIterable<Uint8Array>;\n\t/** Parent directory owned by the host; no local path leaves this adapter. */\n\treadonly installationDirectory?: string;\n\treadonly supportedScopes?: readonly PluginInstallationScopeV1[];\n\t/** Persistent host-owned index; omitted keeps the test-friendly ephemeral mode. */\n\treadonly persistence?: \"ephemeral\" | \"persistent\";\n\treadonly persistenceLockTimeoutMs?: number;\n\t/**\n\t * Host-only runtime assembly seam. The directory and manifest path never\n\t * cross the public installer DTO or model/tool context.\n\t */\n\treadonly loadPlugin?: (input: {\n\t\treadonly installation: PluginInstallationV1;\n\t\treadonly record?: PluginUpdateRecordV1;\n\t\treadonly directory: string;\n\t\treadonly manifestPath: string;\n\t\treadonly signal: AbortSignal;\n\t}) => Promise<{ readonly dispose?: () => void | Promise<void> } | void>;\n}\n\n/** Minimal structural bridge for an AgentSession-owned capability loader. */\nexport interface NodePackageInstallCapabilityPluginSessionV1 {\n\treadonly loadCapabilityPluginManifest: (manifestPath: string) => Promise<{\n\t\treadonly dispose: () => void | Promise<void>;\n\t}>;\n}\n\n/**\n * Adapt an AgentSession-like loader to the host-only runtime seam. The\n * manifest path is never returned as a DTO or sent through model context.\n */\nexport function createNodePackageInstallSessionLoaderV1(\n\tsession: NodePackageInstallCapabilityPluginSessionV1,\n): NonNullable<NodePackageInstallHostOptionsV1[\"loadPlugin\"]> {\n\treturn async ({ manifestPath }) => {\n\t\tconst handle = await session.loadCapabilityPluginManifest(manifestPath);\n\t\treturn { dispose: handle.dispose };\n\t};\n}\n\n/**\n * Create a package host with an explicit AgentSession-compatible runtime\n * loader. This is an opt-in composition helper; it does not alter Core's\n * default session construction or install untrusted package code.\n */\nexport async function createNodePackageInstallHostForSessionV1(\n\toptions: NodePackageInstallHostOptionsV1,\n\tsession: NodePackageInstallCapabilityPluginSessionV1,\n): Promise<NodePackageInstallHostV1> {\n\tif (options.loadPlugin !== undefined) throw new Error(\"loadPlugin must be omitted when binding a session\");\n\treturn await createNodePackageInstallHostV1({\n\t\t...options,\n\t\tloadPlugin: createNodePackageInstallSessionLoaderV1(session),\n\t});\n}\n\nexport interface NodePackageInstallHostV1 extends PluginInstallHostV1 {\n\treadonly version: typeof NODE_PACKAGE_INSTALL_HOST_VERSION_V1;\n\treadonly uninstall: NonNullable<PluginInstallHostV1[\"uninstall\"]>;\n\t/** Host-only bridge for local runtime assembly; never put this path in a DTO or transcript. */\n\treadonly getInstallationDirectory: (input: { readonly installation: PluginInstallationV1 }) => string;\n\treadonly close: () => Promise<void>;\n}\n\ninterface ZipEntryDescriptorV1 {\n\treadonly name: string;\n\treadonly directory: boolean;\n\treadonly flags: number;\n\treadonly method: number;\n\treadonly compressedSize: number;\n\treadonly uncompressedSize: number;\n\treadonly crc32: number;\n\treadonly localOffset: number;\n}\n\ninterface ZipLocalSpanV1 {\n\treadonly start: number;\n\treadonly end: number;\n}\n\ninterface InstalledRecordV1 {\n\treadonly installationRef: string;\n\treadonly directory: string;\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly scope: PluginInstallationScopeV1;\n\treadonly scopeRef: string;\n\tstate: \"installed\" | \"active\" | \"retained\";\n}\n\nfunction positiveLimit(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(`${label} must be a positive integer at most ${maximum}`);\n\treturn result;\n}\n\n/** Resolve the archive budget limits shared by the ZIP and tgz package parsers. */\nexport function resolveNodePackageLimitsV1(limitsInput: NodeZipPackageLimitsV1): Required<NodeZipPackageLimitsV1> {\n\treturn {\n\t\tmaxArchiveBytes: positiveLimit(\n\t\t\tlimitsInput.maxArchiveBytes,\n\t\t\tDEFAULT_MAX_ARCHIVE_BYTES_V1,\n\t\t\tMAX_ARCHIVE_BYTES_V1,\n\t\t\t\"maxArchiveBytes\",\n\t\t),\n\t\tmaxExtractedBytes: positiveLimit(\n\t\t\tlimitsInput.maxExtractedBytes,\n\t\t\tDEFAULT_MAX_EXTRACTED_BYTES_V1,\n\t\t\tMAX_EXTRACTED_BYTES_V1,\n\t\t\t\"maxExtractedBytes\",\n\t\t),\n\t\tmaxEntryBytes: positiveLimit(\n\t\t\tlimitsInput.maxEntryBytes,\n\t\t\tDEFAULT_MAX_ENTRY_BYTES_V1,\n\t\t\tMAX_ENTRY_BYTES_V1,\n\t\t\t\"maxEntryBytes\",\n\t\t),\n\t\tmaxEntries: positiveLimit(limitsInput.maxEntries, DEFAULT_MAX_ENTRIES_V1, MAX_ENTRIES_V1, \"maxEntries\"),\n\t};\n}\n\nfunction readU16(bytes: Uint8Array, offset: number): number {\n\tif (offset < 0 || offset + 2 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn bytes[offset]! | (bytes[offset + 1]! << 8);\n}\n\nfunction readU32(bytes: Uint8Array, offset: number): number {\n\tif (offset < 0 || offset + 4 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;\n}\n\nfunction decodeName(bytes: Uint8Array, utf8: boolean): string {\n\ttry {\n\t\tconst value = new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t\tif (!utf8 && /[^\\x00-\\x7f]/u.test(value)) throw new Error(\"non-ascii zip name\");\n\t\treturn value;\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n}\n\n/** Normalized archive entry name shared by the ZIP and tgz package parsers. */\nexport function normalizedEntryName(value: string): { readonly name: string; readonly directory: boolean } {\n\tif (value.length === 0 || value.includes(\"\\\\\") || /[\\u0000-\\u001f\\u007f]/u.test(value))\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst directory = value.endsWith(\"/\");\n\tif (value.startsWith(\"/\") || /^[a-z]:/iu.test(value)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst parts = value.split(\"/\");\n\tif (directory) parts.pop();\n\tif (\n\t\tparts.length === 0 ||\n\t\tparts.some(\n\t\t\t(part) =>\n\t\t\t\tpart === \"\" ||\n\t\t\t\tpart === \".\" ||\n\t\t\t\tpart === \"..\" ||\n\t\t\t\tpart.includes(\":\") ||\n\t\t\t\t/[ .]$/u.test(part) ||\n\t\t\t\t/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\..*)?$/iu.test(part),\n\t\t)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn { name: parts.join(\"/\"), directory };\n}\n\nfunction crcTable(): Uint32Array {\n\tconst table = new Uint32Array(256);\n\tfor (let index = 0; index < table.length; index += 1) {\n\t\tlet value = index;\n\t\tfor (let bit = 0; bit < 8; bit += 1) value = (value & 1) === 0 ? value >>> 1 : (value >>> 1) ^ 0xedb88320;\n\t\ttable[index] = value >>> 0;\n\t}\n\treturn table;\n}\n\nconst CRC_TABLE_V1 = crcTable();\n\nfunction crc32(bytes: Uint8Array): number {\n\tlet value = 0xffffffff;\n\tfor (const byte of bytes) value = (value >>> 8) ^ CRC_TABLE_V1[(value ^ byte) & 0xff]!;\n\treturn (value ^ 0xffffffff) >>> 0;\n}\n\nfunction findEndOfCentralDirectory(bytes: Uint8Array): {\n\treadonly offset: number;\n\treadonly entries: number;\n\treadonly size: number;\n\treadonly start: number;\n} {\n\tconst minimum = Math.max(0, bytes.byteLength - 0xffff - 22);\n\tfor (let offset = bytes.byteLength - 22; offset >= minimum; offset -= 1) {\n\t\tif (readU32(bytes, offset) !== END_OF_CENTRAL_DIRECTORY_V1) continue;\n\t\tconst disk = readU16(bytes, offset + 4);\n\t\tconst centralDisk = readU16(bytes, offset + 6);\n\t\tconst entries = readU16(bytes, offset + 10);\n\t\tconst centralEntries = readU16(bytes, offset + 8);\n\t\tconst size = readU32(bytes, offset + 12);\n\t\tconst start = readU32(bytes, offset + 16);\n\t\tconst commentLength = readU16(bytes, offset + 20);\n\t\tif (\n\t\t\tdisk !== 0 ||\n\t\t\tcentralDisk !== 0 ||\n\t\t\tentries !== centralEntries ||\n\t\t\toffset + 22 + commentLength !== bytes.byteLength\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (entries === 0xffff || size === 0xffffffff || start === 0xffffffff)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (start + size > offset) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\treturn { offset, entries, size, start };\n\t}\n\tfor (let offset = Math.max(0, bytes.byteLength - 64); offset < bytes.byteLength - 3; offset += 1) {\n\t\tconst signature = readU32(bytes, offset);\n\t\tif (signature === ZIP64_END_OF_CENTRAL_DIRECTORY_V1 || signature === ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_V1)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n}\n\nfunction parseCentralDirectory(\n\tbytes: Uint8Array,\n\tlimits: Required<NodeZipPackageLimitsV1>,\n): readonly ZipEntryDescriptorV1[] {\n\tconst end = findEndOfCentralDirectory(bytes);\n\tif (end.entries > limits.maxEntries || end.size > bytes.byteLength || end.start + end.size > end.offset)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\tconst entries: ZipEntryDescriptorV1[] = [];\n\tconst names = new Set<string>();\n\tlet offset = end.start;\n\tfor (let index = 0; index < end.entries; index += 1) {\n\t\tif (readU32(bytes, offset) !== CENTRAL_FILE_HEADER_V1) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tconst madeBy = readU16(bytes, offset + 4) >>> 8;\n\t\tconst flags = readU16(bytes, offset + 8);\n\t\tconst method = readU16(bytes, offset + 10);\n\t\tconst crc = readU32(bytes, offset + 16);\n\t\tconst compressedSize = readU32(bytes, offset + 20);\n\t\tconst uncompressedSize = readU32(bytes, offset + 24);\n\t\tconst nameLength = readU16(bytes, offset + 28);\n\t\tconst extraLength = readU16(bytes, offset + 30);\n\t\tconst commentLength = readU16(bytes, offset + 32);\n\t\tconst disk = readU16(bytes, offset + 34);\n\t\tconst externalAttributes = readU32(bytes, offset + 38);\n\t\tconst localOffset = readU32(bytes, offset + 42);\n\t\tconst nameStart = offset + 46;\n\t\tconst recordEnd = nameStart + nameLength + extraLength + commentLength;\n\t\tif (\n\t\t\trecordEnd > end.start + end.size ||\n\t\t\tdisk !== 0 ||\n\t\t\t(flags & ~(0x8 | 0x800)) !== 0 ||\n\t\t\t(flags & 1) !== 0 ||\n\t\t\t(flags & 0x40) !== 0\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (method !== 0 && method !== 8) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (uncompressedSize > limits.maxEntryBytes || compressedSize > limits.maxArchiveBytes)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\tconst name = normalizedEntryName(\n\t\t\tdecodeName(bytes.subarray(nameStart, nameStart + nameLength), (flags & 0x800) !== 0),\n\t\t);\n\t\tif (names.has(name.name)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tnames.add(name.name);\n\t\tconst unixMode = madeBy === 3 ? (externalAttributes >>> 16) & 0xffff : 0;\n\t\tif ((unixMode & 0xf000) === 0xa000) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tentries.push({\n\t\t\tname: name.name,\n\t\t\tdirectory: name.directory,\n\t\t\tflags,\n\t\t\tmethod,\n\t\t\tcompressedSize,\n\t\t\tuncompressedSize,\n\t\t\tcrc32: crc,\n\t\t\tlocalOffset,\n\t\t});\n\t\toffset = recordEnd;\n\t}\n\tif (offset !== end.start + end.size) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t// Validate the local-file regions before extraction. A forged central\n\t// directory must not be able to point into another entry or into the\n\t// central directory/EOCD; otherwise extraction could reinterpret metadata\n\t// bytes as package contents.\n\tconst spans: ZipLocalSpanV1[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.localOffset < 0 || entry.localOffset + 30 > end.start)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (readU32(bytes, entry.localOffset) !== LOCAL_FILE_HEADER_V1)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tconst localNameLength = readU16(bytes, entry.localOffset + 26);\n\t\tconst localExtraLength = readU16(bytes, entry.localOffset + 28);\n\t\tconst dataStart = entry.localOffset + 30 + localNameLength + localExtraLength;\n\t\tconst dataEnd = dataStart + entry.compressedSize;\n\t\tif (dataStart < entry.localOffset + 30 || dataEnd < dataStart || dataEnd > end.start)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tspans.push({ start: entry.localOffset, end: dataEnd });\n\t}\n\tspans.sort((left, right) => left.start - right.start || left.end - right.end);\n\tfor (let index = 1; index < spans.length; index += 1) {\n\t\tif (spans[index - 1]!.end > spans[index]!.start) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\treturn entries;\n}\n\nfunction extractEntry(bytes: Uint8Array, entry: ZipEntryDescriptorV1, maxEntryBytes: number): Uint8Array {\n\tif (entry.directory) {\n\t\tif (entry.compressedSize !== 0 || entry.uncompressedSize !== 0)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\treturn new Uint8Array();\n\t}\n\tif (entry.localOffset + 30 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tif (readU32(bytes, entry.localOffset) !== LOCAL_FILE_HEADER_V1)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst localFlags = readU16(bytes, entry.localOffset + 6);\n\tconst localMethod = readU16(bytes, entry.localOffset + 8);\n\tconst nameLength = readU16(bytes, entry.localOffset + 26);\n\tconst extraLength = readU16(bytes, entry.localOffset + 28);\n\tconst localName = decodeName(\n\t\tbytes.subarray(entry.localOffset + 30, entry.localOffset + 30 + nameLength),\n\t\t(entry.flags & 0x800) !== 0,\n\t);\n\tif (normalizedEntryName(localName).name !== entry.name || localFlags !== entry.flags || localMethod !== entry.method)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst localCompressedSize = readU32(bytes, entry.localOffset + 18);\n\tconst localUncompressedSize = readU32(bytes, entry.localOffset + 22);\n\tif (\n\t\t(entry.flags & 8) === 0 &&\n\t\t(localCompressedSize !== entry.compressedSize || localUncompressedSize !== entry.uncompressedSize)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst dataStart = entry.localOffset + 30 + nameLength + extraLength;\n\tconst dataEnd = dataStart + entry.compressedSize;\n\tif (dataStart > bytes.byteLength || dataEnd > bytes.byteLength)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst compressed = bytes.subarray(dataStart, dataEnd);\n\tlet output: Uint8Array;\n\ttry {\n\t\toutput =\n\t\t\tentry.method === 0\n\t\t\t\t? new Uint8Array(compressed)\n\t\t\t\t: inflateRawSync(compressed, { maxOutputLength: maxEntryBytes });\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\tif (\n\t\toutput.byteLength !== entry.uncompressedSize ||\n\t\toutput.byteLength > maxEntryBytes ||\n\t\tcrc32(output) !== entry.crc32\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn output;\n}\n\nexport function parseNodeZipPackageV1(\n\tinput: Uint8Array,\n\tlimitsInput: NodeZipPackageLimitsV1 = {},\n): readonly NodeZipPackageEntryV1[] {\n\tif (!(input instanceof Uint8Array)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst limits = resolveNodePackageLimitsV1(limitsInput);\n\tif (input.byteLength > limits.maxArchiveBytes) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\tconst descriptors = parseCentralDirectory(input, limits);\n\tlet extractedBytes = 0;\n\treturn Object.freeze(\n\t\tdescriptors.map((descriptor) => {\n\t\t\tconst bytes = extractEntry(input, descriptor, limits.maxEntryBytes);\n\t\t\textractedBytes += bytes.byteLength;\n\t\t\tif (extractedBytes > limits.maxExtractedBytes) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\t\treturn Object.freeze({ name: descriptor.name, directory: descriptor.directory, bytes });\n\t\t}),\n\t);\n}\n\nfunction manifestKeys(value: Record<string, unknown>): boolean {\n\tconst allowed = new Set([\n\t\t\"packageFormatVersion\",\n\t\t\"id\",\n\t\t\"pluginVersion\",\n\t\t\"apiVersion\",\n\t\t\"minHostVersion\",\n\t\t\"maxHostVersion\",\n\t\t\"capabilityRefs\",\n\t\t\"requires\",\n\t\t\"platform\",\n\t\t\"testOnly\",\n\t]);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction packageManifest(value: unknown, record: PluginUpdateRecordV1): void {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\tconst manifest = value as Record<string, unknown>;\n\tif (\n\t\t!manifestKeys(manifest) ||\n\t\tmanifest.packageFormatVersion !== NODE_PACKAGE_FORMAT_VERSION_V1 ||\n\t\tmanifest.id !== record.pluginId ||\n\t\tmanifest.pluginVersion !== record.pluginVersion\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\tif (typeof manifest.apiVersion !== \"string\" || manifest.apiVersion !== record.manifest.apiVersion)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\ttry {\n\t\tif (pluginManifestDigestV1(manifest as unknown as PluginManifestV1) !== record.manifestDigest)\n\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\t} catch (error) {\n\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t}\n}\n\nfunction capabilityManifest(\n\tvalue: unknown,\n\trecord: PluginUpdateRecordV1,\n\tentries: readonly NodeZipPackageEntryV1[],\n): void {\n\tlet manifest: ReturnType<typeof parseCapabilityPluginManifest>;\n\ttry {\n\t\tmanifest = parseCapabilityPluginManifest(value, \"<installed plugin.json>\");\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t}\n\tif (manifest.id !== record.pluginId || manifest.version !== record.pluginVersion)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\tconst entryValue = manifest.entry.startsWith(\"./\") ? manifest.entry.slice(2) : manifest.entry;\n\tconst entry = normalizedEntryName(entryValue);\n\tif (entry.directory || !entries.some((candidate) => candidate.name === entry.name && !candidate.directory))\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n}\n\nfunction opaqueScope(value: string): string {\n\tif (\n\t\ttypeof value !== \"string\" ||\n\t\tvalue.trim() === \"\" ||\n\t\tvalue.length > 2048 ||\n\t\t/\\s|[\\u0000-\\u001f\\u007f]/u.test(value)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\treturn value;\n}\n\nfunction installationKey(scope: PluginInstallationScopeV1, scopeRef: string, pluginId: string): string {\n\treturn `${scope}\\u0000${scopeRef}\\u0000${pluginId}`;\n}\n\nfunction identityMatches(\n\trecord: InstalledRecordV1,\n\tinput: {\n\t\treadonly pluginId: string;\n\t\treadonly pluginVersion: string;\n\t\treadonly manifestDigest: string;\n\t\treadonly scope: PluginInstallationScopeV1;\n\t\treadonly scopeRef: string;\n\t},\n): boolean {\n\treturn (\n\t\trecord.pluginId === input.pluginId &&\n\t\trecord.pluginVersion === input.pluginVersion &&\n\t\trecord.manifestDigest === input.manifestDigest &&\n\t\trecord.scope === input.scope &&\n\t\trecord.scopeRef === input.scopeRef\n\t);\n}\n\nfunction artifactIdentityMatchesRecord(artifact: PluginDistributionArtifactV1, record: PluginUpdateRecordV1): boolean {\n\treturn (\n\t\tartifact.version === 1 &&\n\t\tartifact.pluginId === record.pluginId &&\n\t\tartifact.pluginVersion === record.pluginVersion &&\n\t\tartifact.manifestDigest === record.manifestDigest\n\t);\n}\n\nfunction expectedArtifactDigest(value: string): { readonly algorithm: \"sha256\" | \"sha512\"; readonly hex: string } {\n\tconst prefixed = /^(sha256|sha512):([0-9a-f]+)$/iu.exec(value);\n\tif (prefixed !== null) {\n\t\tconst algorithm = prefixed[1]!.toLowerCase() as \"sha256\" | \"sha512\";\n\t\tconst hex = prefixed[2]!.toLowerCase();\n\t\tif ((algorithm === \"sha256\" && hex.length === 64) || (algorithm === \"sha512\" && hex.length === 128))\n\t\t\treturn { algorithm, hex };\n\t}\n\tif (/^[0-9a-f]{64}$/iu.test(value)) return { algorithm: \"sha256\", hex: value.toLowerCase() };\n\tif (/^[0-9a-f]{128}$/iu.test(value)) return { algorithm: \"sha512\", hex: value.toLowerCase() };\n\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n}\n\nasync function collectArtifact(\n\topenArtifact: NodePackageInstallHostOptionsV1[\"openArtifact\"],\n\tartifact: PluginDistributionArtifactV1,\n\tmaxBytes: number,\n\tsignal: AbortSignal,\n): Promise<Uint8Array> {\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\tfor await (const chunk of openArtifact({ artifact, signal })) {\n\t\tif (signal.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\tif (!(chunk instanceof Uint8Array)) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\tif (chunk.byteLength > maxBytes - total) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\tchunks.push(new Uint8Array(chunk));\n\t\ttotal += chunk.byteLength;\n\t}\n\tconst result = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tresult.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn result;\n}\n\nfunction packagePath(root: string, key: string): string {\n\treturn join(root, createHash(\"sha256\").update(key).digest(\"hex\"));\n}\n\nasync function writeEntries(\n\troot: string,\n\tentries: readonly NodeZipPackageEntryV1[],\n\tsignal: AbortSignal,\n): Promise<void> {\n\tawait mkdir(root, { recursive: true, mode: 0o700 });\n\tfor (const entry of entries) {\n\t\tif (signal.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\tconst target = join(root, ...entry.name.split(\"/\"));\n\t\tif (entry.directory) {\n\t\t\tawait mkdir(target, { recursive: true, mode: 0o700 });\n\t\t\tcontinue;\n\t\t}\n\t\tconst parent = join(root, ...entry.name.split(\"/\").slice(0, -1));\n\t\tawait mkdir(parent, { recursive: true, mode: 0o700 });\n\t\tawait writeFile(target, entry.bytes, { flag: \"wx\", mode: 0o600 });\n\t}\n}\n\n/**\n * Host-owned ZIP/tgz package installer. It extracts only a bounded,\n * non-encrypted ZIP (\"application/zip\") or gzip-compressed tar\n * (\"application/gzip\") package and never executes package contents. The\n * returned installation handle is opaque; paths stay inside the host-owned\n * instance directory.\n */\nexport async function createNodePackageInstallHostV1(\n\toptions: NodePackageInstallHostOptionsV1,\n): Promise<NodePackageInstallHostV1> {\n\tif (typeof options.openArtifact !== \"function\") throw new Error(\"openArtifact is required\");\n\tconst limits = resolveNodePackageLimitsV1(options);\n\tconst parent = options.installationDirectory ?? tmpdir();\n\tif (!isAbsolute(parent)) throw new Error(\"installationDirectory must be absolute\");\n\tif (options.persistence !== undefined && options.persistence !== \"ephemeral\" && options.persistence !== \"persistent\")\n\t\tthrow new Error(\"persistence mode is invalid\");\n\tconst supportedScopes = options.supportedScopes ?? [\"global\", \"project\"];\n\tif (\n\t\t!Array.isArray(supportedScopes) ||\n\t\tsupportedScopes.length === 0 ||\n\t\tnew Set(supportedScopes).size !== supportedScopes.length ||\n\t\tsupportedScopes.some((scope) => scope !== \"global\" && scope !== \"project\")\n\t)\n\t\tthrow new Error(\"supportedScopes is invalid\");\n\tawait mkdir(parent, { recursive: true, mode: 0o700 });\n\tconst persistent = options.persistence === \"persistent\";\n\tconst instanceRoot = persistent\n\t\t? join(parent, \"agent-forge-plugin-install-store-v1\")\n\t\t: await mkdtemp(join(parent, \"agent-forge-plugin-install-\"));\n\tconst persistence: NodePackageInstallPersistenceV1 | undefined = persistent\n\t\t? await createNodePackageInstallPersistenceV1({\n\t\t\t\trootDirectory: instanceRoot,\n\t\t\t\tlockTimeoutMs: options.persistenceLockTimeoutMs,\n\t\t\t})\n\t\t: undefined;\n\tconst records = new Map<string, InstalledRecordV1>();\n\tconst activeByKey = new Map<string, string>();\n\tif (persistence !== undefined) {\n\t\tfor (const record of await persistence.load()) records.set(record.installationRef, { ...record });\n\t}\n\tfor (const record of records.values()) {\n\t\tif (record.state === \"active\")\n\t\t\tactiveByKey.set(installationKey(record.scope, record.scopeRef, record.pluginId), record.installationRef);\n\t}\n\tlet closed = false;\n\tconst activeOperations = new Set<AbortController>();\n\tconst runtimeHandles = new Map<string, { readonly dispose?: () => void | Promise<void> }>();\n\tconst applyPersistentSnapshot = (snapshot: readonly NodePackageInstallPersistentRecordV1[]): void => {\n\t\trecords.clear();\n\t\tactiveByKey.clear();\n\t\tfor (const value of snapshot) records.set(value.installationRef, { ...value });\n\t\tfor (const value of records.values()) {\n\t\t\tif (value.state === \"active\")\n\t\t\t\tactiveByKey.set(installationKey(value.scope, value.scopeRef, value.pluginId), value.installationRef);\n\t\t}\n\t};\n\tconst commitRecords = async (\n\t\tupdate: (values: Map<string, NodePackageInstallPersistentRecordV1>) => void | Promise<void>,\n\t): Promise<void> => {\n\t\tif (persistence === undefined) {\n\t\t\tawait update(records);\n\t\t\treturn;\n\t\t}\n\t\tapplyPersistentSnapshot(await persistence.mutate({ update }));\n\t};\n\tlet drained: (() => void) | undefined;\n\tlet closePromise: Promise<void> | undefined;\n\n\tconst begin = (\n\t\tparentSignal: AbortSignal | undefined,\n\t): { readonly controller: AbortController; readonly signal: AbortSignal } => {\n\t\tif (closed) throw new NodePackageInstallErrorV1(\"host_closed\");\n\t\tconst controller = new AbortController();\n\t\tif (parentSignal?.aborted) controller.abort(parentSignal.reason);\n\t\telse parentSignal?.addEventListener(\"abort\", () => controller.abort(parentSignal.reason), { once: true });\n\t\tactiveOperations.add(controller);\n\t\treturn { controller, signal: controller.signal };\n\t};\n\tconst end = (controller: AbortController): void => {\n\t\tactiveOperations.delete(controller);\n\t\tif (activeOperations.size === 0) {\n\t\t\tdrained?.();\n\t\t\tdrained = undefined;\n\t\t}\n\t};\n\tconst waitDrained = async (): Promise<void> => {\n\t\tif (activeOperations.size === 0) return;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tdrained = resolve;\n\t\t});\n\t};\n\tconst getRecord = (\n\t\tinstallation: PluginInstallationV1,\n\t\trecord: PluginUpdateRecordV1,\n\t\tscope: PluginInstallationScopeV1,\n\t\tscopeRef: string,\n\t): InstalledRecordV1 => {\n\t\tconst value = records.get(installation.installationRef);\n\t\tif (\n\t\t\tvalue === undefined ||\n\t\t\tinstallation.pluginId !== record.pluginId ||\n\t\t\tinstallation.pluginVersion !== record.pluginVersion ||\n\t\t\tinstallation.manifestDigest !== record.manifestDigest ||\n\t\t\tinstallation.scope !== scope ||\n\t\t\tinstallation.scopeRef !== scopeRef ||\n\t\t\t!identityMatches(value, {\n\t\t\t\tpluginId: record.pluginId,\n\t\t\t\tpluginVersion: record.pluginVersion,\n\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\tscope,\n\t\t\t\tscopeRef,\n\t\t\t})\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\treturn value;\n\t};\n\tconst disposeRuntime = async (installationRef: string): Promise<void> => {\n\t\tconst handle = runtimeHandles.get(installationRef);\n\t\tif (handle === undefined) return;\n\t\tif (handle.dispose !== undefined) await Promise.resolve(handle.dispose());\n\t\truntimeHandles.delete(installationRef);\n\t};\n\tconst loadRuntime = async (\n\t\tinstallation: PluginInstallationV1,\n\t\trecord: PluginUpdateRecordV1 | undefined,\n\t\tdirectory: string,\n\t\tsignal: AbortSignal,\n\t): Promise<{ readonly dispose?: () => void | Promise<void> } | undefined> => {\n\t\tif (options.loadPlugin === undefined) return undefined;\n\t\ttry {\n\t\t\tconst loaded = await options.loadPlugin({\n\t\t\t\tinstallation,\n\t\t\t\trecord,\n\t\t\t\tdirectory,\n\t\t\t\tmanifestPath: join(directory, CAPABILITY_MANIFEST_FILE_V1),\n\t\t\t\tsignal,\n\t\t\t});\n\t\t\treturn loaded ?? undefined;\n\t\t} catch (error) {\n\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t}\n\t};\n\n\tconst host: NodePackageInstallHostV1 = {\n\t\tversion: NODE_PACKAGE_INSTALL_HOST_VERSION_V1,\n\t\tsupportedScopes: Object.freeze([...supportedScopes]),\n\t\tgetInstallationDirectory(input) {\n\t\t\tconst record = records.get(input.installation.installationRef);\n\t\t\tif (\n\t\t\t\trecord === undefined ||\n\t\t\t\trecord.pluginId !== input.installation.pluginId ||\n\t\t\t\trecord.pluginVersion !== input.installation.pluginVersion ||\n\t\t\t\trecord.manifestDigest !== input.installation.manifestDigest ||\n\t\t\t\trecord.scope !== input.installation.scope ||\n\t\t\t\trecord.scopeRef !== input.installation.scopeRef\n\t\t\t)\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_unknown\");\n\t\t\treturn record.directory;\n\t\t},\n\t\tasync install(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet staging: string | undefined;\n\t\t\ttry {\n\t\t\t\tif (input.artifact === undefined) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tif (!artifactIdentityMatchesRecord(input.artifact, input.record))\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst mediaType = input.artifact.mediaType.toLowerCase();\n\t\t\t\tif (mediaType !== \"application/zip\" && mediaType !== \"application/gzip\")\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"unsupported_media_type\");\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst bytes = await collectArtifact(\n\t\t\t\t\toptions.openArtifact,\n\t\t\t\t\tinput.artifact,\n\t\t\t\t\tlimits.maxArchiveBytes,\n\t\t\t\t\toperation.signal,\n\t\t\t\t);\n\t\t\t\tif (input.artifact.sizeBytes !== bytes.byteLength) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst digest = expectedArtifactDigest(input.artifact.artifactDigest);\n\t\t\t\tif (createHash(digest.algorithm).update(bytes).digest(\"hex\") !== digest.hex)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst entries =\n\t\t\t\t\tmediaType === \"application/gzip\"\n\t\t\t\t\t\t? await parseNodeTarGzPackageV1(bytes, limits)\n\t\t\t\t\t\t: parseNodeZipPackageV1(bytes, limits);\n\t\t\t\tconst manifestEntry = entries.find(\n\t\t\t\t\t(entry) => entry.name === ECOSYSTEM_MANIFEST_FILE_V1 && !entry.directory,\n\t\t\t\t);\n\t\t\t\tif (manifestEntry === undefined) throw new NodePackageInstallErrorV1(\"package_manifest_missing\");\n\t\t\t\tif (manifestEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\tlet manifest: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tmanifest = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(manifestEntry.bytes));\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\t}\n\t\t\t\tpackageManifest(manifest, input.record);\n\t\t\t\tconst capabilityEntry = entries.find(\n\t\t\t\t\t(entry) => entry.name === CAPABILITY_MANIFEST_FILE_V1 && !entry.directory,\n\t\t\t\t);\n\t\t\t\tif (capabilityEntry === undefined) throw new NodePackageInstallErrorV1(\"package_manifest_missing\");\n\t\t\t\tif (capabilityEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\tlet capability: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tcapability = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(capabilityEntry.bytes));\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\t}\n\t\t\t\tcapabilityManifest(capability, input.record, entries);\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, input.record.pluginId);\n\t\t\t\tstaging = join(instanceRoot, `.staging-${randomUUID()}`);\n\t\t\t\tawait writeEntries(staging, entries, operation.signal);\n\t\t\t\tconst installRef = `plugin-install://node-zip/${randomUUID()}`;\n\t\t\t\tconst destination = packagePath(instanceRoot, `${key}\\u0000${installRef}`);\n\t\t\t\tawait rename(staging, destination);\n\t\t\t\tstaging = undefined;\n\t\t\t\tconst installedRecord: InstalledRecordV1 = {\n\t\t\t\t\tinstallationRef: installRef,\n\t\t\t\t\tdirectory: destination,\n\t\t\t\t\tpluginId: input.record.pluginId,\n\t\t\t\t\tpluginVersion: input.record.pluginVersion,\n\t\t\t\t\tmanifestDigest: input.record.manifestDigest,\n\t\t\t\t\tscope: input.scope,\n\t\t\t\t\tscopeRef,\n\t\t\t\t\tstate: \"installed\",\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\t\tvalues.set(installRef, installedRecord);\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rm(destination, { recursive: true, force: true }).catch(() => undefined);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\treturn { installationRef: installRef, scope: input.scope, scopeRef };\n\t\t\t} catch (error) {\n\t\t\t\tif (operation.signal.aborted || input.signal?.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tif (staging !== undefined) await rm(staging, { recursive: true, force: true }).catch(() => undefined);\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync activate(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet candidate: { readonly dispose?: () => void | Promise<void> } | undefined;\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst record = getRecord(input.installation, input.record, input.scope, scopeRef);\n\t\t\t\tif (record.state !== \"installed\") throw new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tcandidate = await loadRuntime(input.installation, input.record, record.directory, operation.signal);\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, input.record.pluginId);\n\t\t\t\tconst previousRef = activeByKey.get(key);\n\t\t\t\tif (previousRef !== undefined) {\n\t\t\t\t\tconst previous = records.get(previousRef);\n\t\t\t\t\tif (previous !== undefined) {\n\t\t\t\t\t\tawait disposeRuntime(previousRef);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tconst candidateRecord = values.get(input.installation.installationRef);\n\t\t\t\t\tif (candidateRecord === undefined) throw new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\t\tif (previousRef !== undefined) {\n\t\t\t\t\t\tconst previousRecord = values.get(previousRef);\n\t\t\t\t\t\tif (previousRecord !== undefined) values.set(previousRef, { ...previousRecord, state: \"retained\" });\n\t\t\t\t\t}\n\t\t\t\t\tvalues.set(input.installation.installationRef, { ...candidateRecord, state: \"active\" });\n\t\t\t\t});\n\t\t\t\tactiveByKey.set(key, input.installation.installationRef);\n\t\t\t\tif (candidate !== undefined) runtimeHandles.set(input.installation.installationRef, candidate);\n\t\t\t\tcandidate = undefined;\n\t\t\t} catch (error) {\n\t\t\t\tif (candidate?.dispose !== undefined) await Promise.resolve(candidate.dispose()).catch(() => undefined);\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync rollback(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet candidate: { readonly dispose?: () => void | Promise<void> } | undefined;\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst failed = records.get(input.failed.installationRef);\n\t\t\t\tif (\n\t\t\t\t\tfailed === undefined ||\n\t\t\t\t\t!identityMatches(failed, {\n\t\t\t\t\t\tpluginId: input.failed.pluginId,\n\t\t\t\t\t\tpluginVersion: input.failed.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.failed.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tconst previous = records.get(input.previous.installationRef);\n\t\t\t\tif (\n\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t!identityMatches(previous, {\n\t\t\t\t\t\tpluginId: input.previous.pluginId,\n\t\t\t\t\t\tpluginVersion: input.previous.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.previous.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t}) ||\n\t\t\t\t\t(previous.state !== \"active\" && previous.state !== \"retained\") ||\n\t\t\t\t\tfailed.pluginId !== previous.pluginId\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tconst previousInstallation: PluginInstallationV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tpluginId: previous.pluginId,\n\t\t\t\t\tpluginVersion: previous.pluginVersion,\n\t\t\t\t\tmanifestDigest: previous.manifestDigest,\n\t\t\t\t\tscope: previous.scope,\n\t\t\t\t\tscopeRef: previous.scopeRef,\n\t\t\t\t\tinstallationRef: input.previous.installationRef,\n\t\t\t\t\tstate: \"active\",\n\t\t\t\t};\n\t\t\t\tcandidate = await loadRuntime(previousInstallation, undefined, previous.directory, operation.signal);\n\t\t\t\tawait disposeRuntime(input.failed.installationRef);\n\t\t\t\tawait rm(failed.directory, { recursive: true, force: true });\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tvalues.delete(input.failed.installationRef);\n\t\t\t\t\tconst previousRecord = values.get(input.previous.installationRef);\n\t\t\t\t\tif (previousRecord !== undefined)\n\t\t\t\t\t\tvalues.set(input.previous.installationRef, { ...previousRecord, state: \"active\" });\n\t\t\t\t});\n\t\t\t\tactiveByKey.set(installationKey(input.scope, scopeRef, failed.pluginId), input.previous.installationRef);\n\t\t\t\tif (candidate !== undefined) runtimeHandles.set(input.previous.installationRef, candidate);\n\t\t\t\tcandidate = undefined;\n\t\t\t} catch (error) {\n\t\t\t\tif (candidate?.dispose !== undefined) await Promise.resolve(candidate.dispose()).catch(() => undefined);\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync uninstall(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst record = records.get(input.installation.installationRef);\n\t\t\t\tif (\n\t\t\t\t\trecord === undefined ||\n\t\t\t\t\t!identityMatches(record, {\n\t\t\t\t\t\tpluginId: input.installation.pluginId,\n\t\t\t\t\t\tpluginVersion: input.installation.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.installation.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_unknown\");\n\t\t\t\tawait disposeRuntime(input.installation.installationRef);\n\t\t\t\t// force:false keeps rm strict, but a directory that is already\n\t\t\t\t// gone (ghost record from an interrupted uninstall) is the\n\t\t\t\t// desired end state — continue to the index commit instead of\n\t\t\t\t// bricking every later store operation on ENOENT.\n\t\t\t\tawait rm(record.directory, { recursive: true, force: false }).catch((error: unknown) => {\n\t\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tvalues.delete(input.installation.installationRef);\n\t\t\t\t});\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, record.pluginId);\n\t\t\t\tif (activeByKey.get(key) === input.installation.installationRef) activeByKey.delete(key);\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync close() {\n\t\t\tif (closePromise !== undefined) return await closePromise;\n\t\t\tclosed = true;\n\t\t\tfor (const operation of activeOperations) operation.abort();\n\t\t\tclosePromise = (async () => {\n\t\t\t\tawait waitDrained();\n\t\t\t\tlet disposeError = false;\n\t\t\t\tfor (const installationRef of runtimeHandles.keys()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait disposeRuntime(installationRef);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tdisposeError = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (persistence === undefined) await rm(instanceRoot, { recursive: true, force: true });\n\t\t\t\telse await persistence.close();\n\t\t\t\trecords.clear();\n\t\t\t\tactiveByKey.clear();\n\t\t\t\tif (disposeError) throw new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t})();\n\t\t\treturn await closePromise;\n\t\t},\n\t};\n\tif (options.loadPlugin !== undefined) {\n\t\ttry {\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.state !== \"active\") continue;\n\t\t\t\tconst installation: PluginInstallationV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tpluginId: record.pluginId,\n\t\t\t\t\tpluginVersion: record.pluginVersion,\n\t\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\t\tscope: record.scope,\n\t\t\t\t\tscopeRef: record.scopeRef,\n\t\t\t\t\tinstallationRef: record.installationRef,\n\t\t\t\t\tstate: \"active\",\n\t\t\t\t};\n\t\t\t\tconst runtime = await loadRuntime(installation, undefined, record.directory, new AbortController().signal);\n\t\t\t\tif (runtime !== undefined) runtimeHandles.set(record.installationRef, runtime);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait host.close().catch(() => undefined);\n\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t}\n\t}\n\treturn host;\n}\n"]}
1
+ {"version":3,"file":"node-package-install-host.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-package-install-host.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAO3G,OAAO,KAAK,EAAoB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGzE,QAAA,MAAM,oCAAoC,GAAa,CAAC;AACxD,eAAO,MAAM,8BAA8B,GAAa,CAAC;AAmBzD,MAAM,MAAM,6BAA6B,GACtC,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,wBAAwB,GACxB,iBAAiB,GACjB,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,2BAA2B,GAC3B,sBAAsB,GACtB,gCAAgC,GAChC,wBAAwB,CAAC;AAE5B,qBAAa,yBAA0B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAE7C,YAAY,IAAI,EAAE,6BAA6B,EAI9C;CACD;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,+BAAgC,SAAQ,sBAAsB;IAC9E,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE;QAC9B,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;KAC9B,KAAK,aAAa,CAAC,UAAU,CAAC,CAAC;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChE,mFAAmF;IACnF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAC7B,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;QAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;QACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;KAC7B,KAAK,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACxE;AAED,6EAA6E;AAC7E,MAAM,WAAW,2CAA2C;IAC3D,QAAQ,CAAC,4BAA4B,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7C,CAAC,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACtD,OAAO,EAAE,2CAA2C,GAClD,WAAW,CAAC,+BAA+B,CAAC,YAAY,CAAC,CAAC,CAK5D;AAED;;;;GAIG;AACH,wBAAsB,wCAAwC,CAC7D,OAAO,EAAE,+BAA+B,EACxC,OAAO,EAAE,2CAA2C,GAClD,OAAO,CAAC,wBAAwB,CAAC,CAMnC;AAED,MAAM,WAAW,wBAAyB,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,OAAO,EAAE,OAAO,oCAAoC,CAAC;IAC9D,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;IAClE,+FAA+F;IAC/F,QAAQ,CAAC,wBAAwB,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;KAAE,KAAK,MAAM,CAAC;IACtG,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAoCD,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,sBAAsB,GAAG,QAAQ,CAAC,sBAAsB,CAAC,CAsBhH;AAsBD,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAqBzG;AA2LD,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,UAAU,EACjB,WAAW,GAAE,sBAA2B,GACtC,SAAS,qBAAqB,EAAE,CAclC;AAkKD;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CACnD,OAAO,EAAE,+BAA+B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CA+ZnC","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, mkdtemp, rename, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport { inflateRawSync } from \"node:zlib\";\nimport { parseCapabilityPluginManifest } from \"../../core/extensions/capability-plugin.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginInstallationScopeV1, PluginInstallationV1, PluginInstallHostV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallPersistenceV1,\n\ttype NodePackageInstallPersistenceV1,\n\ttype NodePackageInstallPersistentRecordV1,\n} from \"./node-package-install-persistence.ts\";\nimport { parseNodeTarGzPackageV1 } from \"./node-tar-package.ts\";\nimport type { PluginManifestV1, PluginUpdateRecordV1 } from \"./types.ts\";\nimport { pluginManifestDigestV1 } from \"./updates.ts\";\n\nconst NODE_PACKAGE_INSTALL_HOST_VERSION_V1 = 1 as const;\nexport const NODE_PACKAGE_FORMAT_VERSION_V1 = 1 as const;\nconst DEFAULT_MAX_ARCHIVE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_ARCHIVE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_MAX_EXTRACTED_BYTES_V1 = 256 * 1024 * 1024;\nconst MAX_EXTRACTED_BYTES_V1 = 1024 * 1024 * 1024;\nconst DEFAULT_MAX_ENTRY_BYTES_V1 = 64 * 1024 * 1024;\nconst MAX_ENTRY_BYTES_V1 = 256 * 1024 * 1024;\nconst DEFAULT_MAX_ENTRIES_V1 = 2048;\nconst MAX_ENTRIES_V1 = 8192;\nconst MAX_PACKAGE_MANIFEST_BYTES_V1 = 64 * 1024;\nconst ECOSYSTEM_MANIFEST_FILE_V1 = \"agent-forge.json\";\nconst CAPABILITY_MANIFEST_FILE_V1 = \"plugin.json\";\n\nconst LOCAL_FILE_HEADER_V1 = 0x04034b50;\nconst CENTRAL_FILE_HEADER_V1 = 0x02014b50;\nconst END_OF_CENTRAL_DIRECTORY_V1 = 0x06054b50;\nconst ZIP64_END_OF_CENTRAL_DIRECTORY_V1 = 0x06064b50;\nconst ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_V1 = 0x07064b50;\n\nexport type NodePackageInstallErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"host_closed\"\n\t| \"invalid_artifact\"\n\t| \"unsupported_media_type\"\n\t| \"archive_invalid\"\n\t| \"archive_budget_exceeded\"\n\t| \"package_manifest_missing\"\n\t| \"package_manifest_invalid\"\n\t| \"package_manifest_mismatch\"\n\t| \"installation_unknown\"\n\t| \"installation_identity_mismatch\"\n\t| \"installation_io_failed\";\n\nexport class NodePackageInstallErrorV1 extends Error {\n\treadonly code: NodePackageInstallErrorCodeV1;\n\n\tconstructor(code: NodePackageInstallErrorCodeV1) {\n\t\tsuper(t(\"Node package installation failed: {code}\", { code }));\n\t\tthis.name = \"NodePackageInstallErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeZipPackageEntryV1 {\n\treadonly name: string;\n\treadonly directory: boolean;\n\treadonly bytes: Uint8Array;\n}\n\nexport interface NodeZipPackageLimitsV1 {\n\treadonly maxArchiveBytes?: number;\n\treadonly maxExtractedBytes?: number;\n\treadonly maxEntryBytes?: number;\n\treadonly maxEntries?: number;\n}\n\nexport interface NodePackageInstallHostOptionsV1 extends NodeZipPackageLimitsV1 {\n\t/** An opaque artifact reader owned by the distribution host. */\n\treadonly openArtifact: (input: {\n\t\treadonly artifact: PluginDistributionArtifactV1;\n\t\treadonly signal?: AbortSignal;\n\t}) => AsyncIterable<Uint8Array>;\n\t/** Parent directory owned by the host; no local path leaves this adapter. */\n\treadonly installationDirectory?: string;\n\treadonly supportedScopes?: readonly PluginInstallationScopeV1[];\n\t/** Persistent host-owned index; omitted keeps the test-friendly ephemeral mode. */\n\treadonly persistence?: \"ephemeral\" | \"persistent\";\n\treadonly persistenceLockTimeoutMs?: number;\n\t/**\n\t * Host-only runtime assembly seam. The directory and manifest path never\n\t * cross the public installer DTO or model/tool context.\n\t */\n\treadonly loadPlugin?: (input: {\n\t\treadonly installation: PluginInstallationV1;\n\t\treadonly record?: PluginUpdateRecordV1;\n\t\treadonly directory: string;\n\t\treadonly manifestPath: string;\n\t\treadonly signal: AbortSignal;\n\t}) => Promise<{ readonly dispose?: () => void | Promise<void> } | void>;\n}\n\n/** Minimal structural bridge for an AgentSession-owned capability loader. */\nexport interface NodePackageInstallCapabilityPluginSessionV1 {\n\treadonly loadCapabilityPluginManifest: (manifestPath: string) => Promise<{\n\t\treadonly dispose: () => void | Promise<void>;\n\t}>;\n}\n\n/**\n * Adapt an AgentSession-like loader to the host-only runtime seam. The\n * manifest path is never returned as a DTO or sent through model context.\n */\nexport function createNodePackageInstallSessionLoaderV1(\n\tsession: NodePackageInstallCapabilityPluginSessionV1,\n): NonNullable<NodePackageInstallHostOptionsV1[\"loadPlugin\"]> {\n\treturn async ({ manifestPath }) => {\n\t\tconst handle = await session.loadCapabilityPluginManifest(manifestPath);\n\t\treturn { dispose: handle.dispose };\n\t};\n}\n\n/**\n * Create a package host with an explicit AgentSession-compatible runtime\n * loader. This is an opt-in composition helper; it does not alter Core's\n * default session construction or install untrusted package code.\n */\nexport async function createNodePackageInstallHostForSessionV1(\n\toptions: NodePackageInstallHostOptionsV1,\n\tsession: NodePackageInstallCapabilityPluginSessionV1,\n): Promise<NodePackageInstallHostV1> {\n\tif (options.loadPlugin !== undefined) throw new Error(t(\"loadPlugin must be omitted when binding a session\"));\n\treturn await createNodePackageInstallHostV1({\n\t\t...options,\n\t\tloadPlugin: createNodePackageInstallSessionLoaderV1(session),\n\t});\n}\n\nexport interface NodePackageInstallHostV1 extends PluginInstallHostV1 {\n\treadonly version: typeof NODE_PACKAGE_INSTALL_HOST_VERSION_V1;\n\treadonly uninstall: NonNullable<PluginInstallHostV1[\"uninstall\"]>;\n\t/** Host-only bridge for local runtime assembly; never put this path in a DTO or transcript. */\n\treadonly getInstallationDirectory: (input: { readonly installation: PluginInstallationV1 }) => string;\n\treadonly close: () => Promise<void>;\n}\n\ninterface ZipEntryDescriptorV1 {\n\treadonly name: string;\n\treadonly directory: boolean;\n\treadonly flags: number;\n\treadonly method: number;\n\treadonly compressedSize: number;\n\treadonly uncompressedSize: number;\n\treadonly crc32: number;\n\treadonly localOffset: number;\n}\n\ninterface ZipLocalSpanV1 {\n\treadonly start: number;\n\treadonly end: number;\n}\n\ninterface InstalledRecordV1 {\n\treadonly installationRef: string;\n\treadonly directory: string;\n\treadonly pluginId: string;\n\treadonly pluginVersion: string;\n\treadonly manifestDigest: string;\n\treadonly scope: PluginInstallationScopeV1;\n\treadonly scopeRef: string;\n\tstate: \"installed\" | \"active\" | \"retained\";\n}\n\nfunction positiveLimit(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result < 1 || result > maximum)\n\t\tthrow new Error(t(\"{label} must be a positive integer at most {maximum}\", { label, maximum }));\n\treturn result;\n}\n\n/** Resolve the archive budget limits shared by the ZIP and tgz package parsers. */\nexport function resolveNodePackageLimitsV1(limitsInput: NodeZipPackageLimitsV1): Required<NodeZipPackageLimitsV1> {\n\treturn {\n\t\tmaxArchiveBytes: positiveLimit(\n\t\t\tlimitsInput.maxArchiveBytes,\n\t\t\tDEFAULT_MAX_ARCHIVE_BYTES_V1,\n\t\t\tMAX_ARCHIVE_BYTES_V1,\n\t\t\t\"maxArchiveBytes\",\n\t\t),\n\t\tmaxExtractedBytes: positiveLimit(\n\t\t\tlimitsInput.maxExtractedBytes,\n\t\t\tDEFAULT_MAX_EXTRACTED_BYTES_V1,\n\t\t\tMAX_EXTRACTED_BYTES_V1,\n\t\t\t\"maxExtractedBytes\",\n\t\t),\n\t\tmaxEntryBytes: positiveLimit(\n\t\t\tlimitsInput.maxEntryBytes,\n\t\t\tDEFAULT_MAX_ENTRY_BYTES_V1,\n\t\t\tMAX_ENTRY_BYTES_V1,\n\t\t\t\"maxEntryBytes\",\n\t\t),\n\t\tmaxEntries: positiveLimit(limitsInput.maxEntries, DEFAULT_MAX_ENTRIES_V1, MAX_ENTRIES_V1, \"maxEntries\"),\n\t};\n}\n\nfunction readU16(bytes: Uint8Array, offset: number): number {\n\tif (offset < 0 || offset + 2 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn bytes[offset]! | (bytes[offset + 1]! << 8);\n}\n\nfunction readU32(bytes: Uint8Array, offset: number): number {\n\tif (offset < 0 || offset + 4 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;\n}\n\nfunction decodeName(bytes: Uint8Array, utf8: boolean): string {\n\ttry {\n\t\tconst value = new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t\tif (!utf8 && /[^\\x00-\\x7f]/u.test(value)) throw new Error(t(\"non-ascii zip name\"));\n\t\treturn value;\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n}\n\n/** Normalized archive entry name shared by the ZIP and tgz package parsers. */\nexport function normalizedEntryName(value: string): { readonly name: string; readonly directory: boolean } {\n\tif (value.length === 0 || value.includes(\"\\\\\") || /[\\u0000-\\u001f\\u007f]/u.test(value))\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst directory = value.endsWith(\"/\");\n\tif (value.startsWith(\"/\") || /^[a-z]:/iu.test(value)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst parts = value.split(\"/\");\n\tif (directory) parts.pop();\n\tif (\n\t\tparts.length === 0 ||\n\t\tparts.some(\n\t\t\t(part) =>\n\t\t\t\tpart === \"\" ||\n\t\t\t\tpart === \".\" ||\n\t\t\t\tpart === \"..\" ||\n\t\t\t\tpart.includes(\":\") ||\n\t\t\t\t/[ .]$/u.test(part) ||\n\t\t\t\t/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\\..*)?$/iu.test(part),\n\t\t)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn { name: parts.join(\"/\"), directory };\n}\n\nfunction crcTable(): Uint32Array {\n\tconst table = new Uint32Array(256);\n\tfor (let index = 0; index < table.length; index += 1) {\n\t\tlet value = index;\n\t\tfor (let bit = 0; bit < 8; bit += 1) value = (value & 1) === 0 ? value >>> 1 : (value >>> 1) ^ 0xedb88320;\n\t\ttable[index] = value >>> 0;\n\t}\n\treturn table;\n}\n\nconst CRC_TABLE_V1 = crcTable();\n\nfunction crc32(bytes: Uint8Array): number {\n\tlet value = 0xffffffff;\n\tfor (const byte of bytes) value = (value >>> 8) ^ CRC_TABLE_V1[(value ^ byte) & 0xff]!;\n\treturn (value ^ 0xffffffff) >>> 0;\n}\n\nfunction findEndOfCentralDirectory(bytes: Uint8Array): {\n\treadonly offset: number;\n\treadonly entries: number;\n\treadonly size: number;\n\treadonly start: number;\n} {\n\tconst minimum = Math.max(0, bytes.byteLength - 0xffff - 22);\n\tfor (let offset = bytes.byteLength - 22; offset >= minimum; offset -= 1) {\n\t\tif (readU32(bytes, offset) !== END_OF_CENTRAL_DIRECTORY_V1) continue;\n\t\tconst disk = readU16(bytes, offset + 4);\n\t\tconst centralDisk = readU16(bytes, offset + 6);\n\t\tconst entries = readU16(bytes, offset + 10);\n\t\tconst centralEntries = readU16(bytes, offset + 8);\n\t\tconst size = readU32(bytes, offset + 12);\n\t\tconst start = readU32(bytes, offset + 16);\n\t\tconst commentLength = readU16(bytes, offset + 20);\n\t\tif (\n\t\t\tdisk !== 0 ||\n\t\t\tcentralDisk !== 0 ||\n\t\t\tentries !== centralEntries ||\n\t\t\toffset + 22 + commentLength !== bytes.byteLength\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (entries === 0xffff || size === 0xffffffff || start === 0xffffffff)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (start + size > offset) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\treturn { offset, entries, size, start };\n\t}\n\tfor (let offset = Math.max(0, bytes.byteLength - 64); offset < bytes.byteLength - 3; offset += 1) {\n\t\tconst signature = readU32(bytes, offset);\n\t\tif (signature === ZIP64_END_OF_CENTRAL_DIRECTORY_V1 || signature === ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_V1)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n}\n\nfunction parseCentralDirectory(\n\tbytes: Uint8Array,\n\tlimits: Required<NodeZipPackageLimitsV1>,\n): readonly ZipEntryDescriptorV1[] {\n\tconst end = findEndOfCentralDirectory(bytes);\n\tif (end.entries > limits.maxEntries || end.size > bytes.byteLength || end.start + end.size > end.offset)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\tconst entries: ZipEntryDescriptorV1[] = [];\n\tconst names = new Set<string>();\n\tlet offset = end.start;\n\tfor (let index = 0; index < end.entries; index += 1) {\n\t\tif (readU32(bytes, offset) !== CENTRAL_FILE_HEADER_V1) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tconst madeBy = readU16(bytes, offset + 4) >>> 8;\n\t\tconst flags = readU16(bytes, offset + 8);\n\t\tconst method = readU16(bytes, offset + 10);\n\t\tconst crc = readU32(bytes, offset + 16);\n\t\tconst compressedSize = readU32(bytes, offset + 20);\n\t\tconst uncompressedSize = readU32(bytes, offset + 24);\n\t\tconst nameLength = readU16(bytes, offset + 28);\n\t\tconst extraLength = readU16(bytes, offset + 30);\n\t\tconst commentLength = readU16(bytes, offset + 32);\n\t\tconst disk = readU16(bytes, offset + 34);\n\t\tconst externalAttributes = readU32(bytes, offset + 38);\n\t\tconst localOffset = readU32(bytes, offset + 42);\n\t\tconst nameStart = offset + 46;\n\t\tconst recordEnd = nameStart + nameLength + extraLength + commentLength;\n\t\tif (\n\t\t\trecordEnd > end.start + end.size ||\n\t\t\tdisk !== 0 ||\n\t\t\t(flags & ~(0x8 | 0x800)) !== 0 ||\n\t\t\t(flags & 1) !== 0 ||\n\t\t\t(flags & 0x40) !== 0\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (method !== 0 && method !== 8) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (uncompressedSize > limits.maxEntryBytes || compressedSize > limits.maxArchiveBytes)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\tconst name = normalizedEntryName(\n\t\t\tdecodeName(bytes.subarray(nameStart, nameStart + nameLength), (flags & 0x800) !== 0),\n\t\t);\n\t\tif (names.has(name.name)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tnames.add(name.name);\n\t\tconst unixMode = madeBy === 3 ? (externalAttributes >>> 16) & 0xffff : 0;\n\t\tif ((unixMode & 0xf000) === 0xa000) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tentries.push({\n\t\t\tname: name.name,\n\t\t\tdirectory: name.directory,\n\t\t\tflags,\n\t\t\tmethod,\n\t\t\tcompressedSize,\n\t\t\tuncompressedSize,\n\t\t\tcrc32: crc,\n\t\t\tlocalOffset,\n\t\t});\n\t\toffset = recordEnd;\n\t}\n\tif (offset !== end.start + end.size) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t// Validate the local-file regions before extraction. A forged central\n\t// directory must not be able to point into another entry or into the\n\t// central directory/EOCD; otherwise extraction could reinterpret metadata\n\t// bytes as package contents.\n\tconst spans: ZipLocalSpanV1[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.localOffset < 0 || entry.localOffset + 30 > end.start)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tif (readU32(bytes, entry.localOffset) !== LOCAL_FILE_HEADER_V1)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tconst localNameLength = readU16(bytes, entry.localOffset + 26);\n\t\tconst localExtraLength = readU16(bytes, entry.localOffset + 28);\n\t\tconst dataStart = entry.localOffset + 30 + localNameLength + localExtraLength;\n\t\tconst dataEnd = dataStart + entry.compressedSize;\n\t\tif (dataStart < entry.localOffset + 30 || dataEnd < dataStart || dataEnd > end.start)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\tspans.push({ start: entry.localOffset, end: dataEnd });\n\t}\n\tspans.sort((left, right) => left.start - right.start || left.end - right.end);\n\tfor (let index = 1; index < spans.length; index += 1) {\n\t\tif (spans[index - 1]!.end > spans[index]!.start) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\treturn entries;\n}\n\nfunction extractEntry(bytes: Uint8Array, entry: ZipEntryDescriptorV1, maxEntryBytes: number): Uint8Array {\n\tif (entry.directory) {\n\t\tif (entry.compressedSize !== 0 || entry.uncompressedSize !== 0)\n\t\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t\treturn new Uint8Array();\n\t}\n\tif (entry.localOffset + 30 > bytes.byteLength) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tif (readU32(bytes, entry.localOffset) !== LOCAL_FILE_HEADER_V1)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst localFlags = readU16(bytes, entry.localOffset + 6);\n\tconst localMethod = readU16(bytes, entry.localOffset + 8);\n\tconst nameLength = readU16(bytes, entry.localOffset + 26);\n\tconst extraLength = readU16(bytes, entry.localOffset + 28);\n\tconst localName = decodeName(\n\t\tbytes.subarray(entry.localOffset + 30, entry.localOffset + 30 + nameLength),\n\t\t(entry.flags & 0x800) !== 0,\n\t);\n\tif (normalizedEntryName(localName).name !== entry.name || localFlags !== entry.flags || localMethod !== entry.method)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst localCompressedSize = readU32(bytes, entry.localOffset + 18);\n\tconst localUncompressedSize = readU32(bytes, entry.localOffset + 22);\n\tif (\n\t\t(entry.flags & 8) === 0 &&\n\t\t(localCompressedSize !== entry.compressedSize || localUncompressedSize !== entry.uncompressedSize)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst dataStart = entry.localOffset + 30 + nameLength + extraLength;\n\tconst dataEnd = dataStart + entry.compressedSize;\n\tif (dataStart > bytes.byteLength || dataEnd > bytes.byteLength)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst compressed = bytes.subarray(dataStart, dataEnd);\n\tlet output: Uint8Array;\n\ttry {\n\t\toutput =\n\t\t\tentry.method === 0\n\t\t\t\t? new Uint8Array(compressed)\n\t\t\t\t: inflateRawSync(compressed, { maxOutputLength: maxEntryBytes });\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\t}\n\tif (\n\t\toutput.byteLength !== entry.uncompressedSize ||\n\t\toutput.byteLength > maxEntryBytes ||\n\t\tcrc32(output) !== entry.crc32\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"archive_invalid\");\n\treturn output;\n}\n\nexport function parseNodeZipPackageV1(\n\tinput: Uint8Array,\n\tlimitsInput: NodeZipPackageLimitsV1 = {},\n): readonly NodeZipPackageEntryV1[] {\n\tif (!(input instanceof Uint8Array)) throw new NodePackageInstallErrorV1(\"archive_invalid\");\n\tconst limits = resolveNodePackageLimitsV1(limitsInput);\n\tif (input.byteLength > limits.maxArchiveBytes) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\tconst descriptors = parseCentralDirectory(input, limits);\n\tlet extractedBytes = 0;\n\treturn Object.freeze(\n\t\tdescriptors.map((descriptor) => {\n\t\t\tconst bytes = extractEntry(input, descriptor, limits.maxEntryBytes);\n\t\t\textractedBytes += bytes.byteLength;\n\t\t\tif (extractedBytes > limits.maxExtractedBytes) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\t\treturn Object.freeze({ name: descriptor.name, directory: descriptor.directory, bytes });\n\t\t}),\n\t);\n}\n\nfunction manifestKeys(value: Record<string, unknown>): boolean {\n\tconst allowed = new Set([\n\t\t\"packageFormatVersion\",\n\t\t\"id\",\n\t\t\"pluginVersion\",\n\t\t\"apiVersion\",\n\t\t\"minHostVersion\",\n\t\t\"maxHostVersion\",\n\t\t\"capabilityRefs\",\n\t\t\"requires\",\n\t\t\"platform\",\n\t\t\"testOnly\",\n\t]);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction packageManifest(value: unknown, record: PluginUpdateRecordV1): void {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\tconst manifest = value as Record<string, unknown>;\n\tif (\n\t\t!manifestKeys(manifest) ||\n\t\tmanifest.packageFormatVersion !== NODE_PACKAGE_FORMAT_VERSION_V1 ||\n\t\tmanifest.id !== record.pluginId ||\n\t\tmanifest.pluginVersion !== record.pluginVersion\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\tif (typeof manifest.apiVersion !== \"string\" || manifest.apiVersion !== record.manifest.apiVersion)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\ttry {\n\t\tif (pluginManifestDigestV1(manifest as unknown as PluginManifestV1) !== record.manifestDigest)\n\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\t} catch (error) {\n\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t}\n}\n\nfunction capabilityManifest(\n\tvalue: unknown,\n\trecord: PluginUpdateRecordV1,\n\tentries: readonly NodeZipPackageEntryV1[],\n): void {\n\tlet manifest: ReturnType<typeof parseCapabilityPluginManifest>;\n\ttry {\n\t\tmanifest = parseCapabilityPluginManifest(value, \"<installed plugin.json>\");\n\t} catch {\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t}\n\tif (manifest.id !== record.pluginId || manifest.version !== record.pluginVersion)\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n\tconst entryValue = manifest.entry.startsWith(\"./\") ? manifest.entry.slice(2) : manifest.entry;\n\tconst entry = normalizedEntryName(entryValue);\n\tif (entry.directory || !entries.some((candidate) => candidate.name === entry.name && !candidate.directory))\n\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_mismatch\");\n}\n\nfunction opaqueScope(value: string): string {\n\tif (\n\t\ttypeof value !== \"string\" ||\n\t\tvalue.trim() === \"\" ||\n\t\tvalue.length > 2048 ||\n\t\t/\\s|[\\u0000-\\u001f\\u007f]/u.test(value)\n\t)\n\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\treturn value;\n}\n\nfunction installationKey(scope: PluginInstallationScopeV1, scopeRef: string, pluginId: string): string {\n\treturn `${scope}\\u0000${scopeRef}\\u0000${pluginId}`;\n}\n\nfunction identityMatches(\n\trecord: InstalledRecordV1,\n\tinput: {\n\t\treadonly pluginId: string;\n\t\treadonly pluginVersion: string;\n\t\treadonly manifestDigest: string;\n\t\treadonly scope: PluginInstallationScopeV1;\n\t\treadonly scopeRef: string;\n\t},\n): boolean {\n\treturn (\n\t\trecord.pluginId === input.pluginId &&\n\t\trecord.pluginVersion === input.pluginVersion &&\n\t\trecord.manifestDigest === input.manifestDigest &&\n\t\trecord.scope === input.scope &&\n\t\trecord.scopeRef === input.scopeRef\n\t);\n}\n\nfunction artifactIdentityMatchesRecord(artifact: PluginDistributionArtifactV1, record: PluginUpdateRecordV1): boolean {\n\treturn (\n\t\tartifact.version === 1 &&\n\t\tartifact.pluginId === record.pluginId &&\n\t\tartifact.pluginVersion === record.pluginVersion &&\n\t\tartifact.manifestDigest === record.manifestDigest\n\t);\n}\n\nfunction expectedArtifactDigest(value: string): { readonly algorithm: \"sha256\" | \"sha512\"; readonly hex: string } {\n\tconst prefixed = /^(sha256|sha512):([0-9a-f]+)$/iu.exec(value);\n\tif (prefixed !== null) {\n\t\tconst algorithm = prefixed[1]!.toLowerCase() as \"sha256\" | \"sha512\";\n\t\tconst hex = prefixed[2]!.toLowerCase();\n\t\tif ((algorithm === \"sha256\" && hex.length === 64) || (algorithm === \"sha512\" && hex.length === 128))\n\t\t\treturn { algorithm, hex };\n\t}\n\tif (/^[0-9a-f]{64}$/iu.test(value)) return { algorithm: \"sha256\", hex: value.toLowerCase() };\n\tif (/^[0-9a-f]{128}$/iu.test(value)) return { algorithm: \"sha512\", hex: value.toLowerCase() };\n\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n}\n\nasync function collectArtifact(\n\topenArtifact: NodePackageInstallHostOptionsV1[\"openArtifact\"],\n\tartifact: PluginDistributionArtifactV1,\n\tmaxBytes: number,\n\tsignal: AbortSignal,\n): Promise<Uint8Array> {\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\tfor await (const chunk of openArtifact({ artifact, signal })) {\n\t\tif (signal.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\tif (!(chunk instanceof Uint8Array)) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\tif (chunk.byteLength > maxBytes - total) throw new NodePackageInstallErrorV1(\"archive_budget_exceeded\");\n\t\tchunks.push(new Uint8Array(chunk));\n\t\ttotal += chunk.byteLength;\n\t}\n\tconst result = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tresult.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn result;\n}\n\nfunction packagePath(root: string, key: string): string {\n\treturn join(root, createHash(\"sha256\").update(key).digest(\"hex\"));\n}\n\nasync function writeEntries(\n\troot: string,\n\tentries: readonly NodeZipPackageEntryV1[],\n\tsignal: AbortSignal,\n): Promise<void> {\n\tawait mkdir(root, { recursive: true, mode: 0o700 });\n\tfor (const entry of entries) {\n\t\tif (signal.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\tconst target = join(root, ...entry.name.split(\"/\"));\n\t\tif (entry.directory) {\n\t\t\tawait mkdir(target, { recursive: true, mode: 0o700 });\n\t\t\tcontinue;\n\t\t}\n\t\tconst parent = join(root, ...entry.name.split(\"/\").slice(0, -1));\n\t\tawait mkdir(parent, { recursive: true, mode: 0o700 });\n\t\tawait writeFile(target, entry.bytes, { flag: \"wx\", mode: 0o600 });\n\t}\n}\n\n/**\n * Host-owned ZIP/tgz package installer. It extracts only a bounded,\n * non-encrypted ZIP (\"application/zip\") or gzip-compressed tar\n * (\"application/gzip\") package and never executes package contents. The\n * returned installation handle is opaque; paths stay inside the host-owned\n * instance directory.\n */\nexport async function createNodePackageInstallHostV1(\n\toptions: NodePackageInstallHostOptionsV1,\n): Promise<NodePackageInstallHostV1> {\n\tif (typeof options.openArtifact !== \"function\") throw new Error(t(\"openArtifact is required\"));\n\tconst limits = resolveNodePackageLimitsV1(options);\n\tconst parent = options.installationDirectory ?? tmpdir();\n\tif (!isAbsolute(parent)) throw new Error(t(\"installationDirectory must be absolute\"));\n\tif (options.persistence !== undefined && options.persistence !== \"ephemeral\" && options.persistence !== \"persistent\")\n\t\tthrow new Error(t(\"persistence mode is invalid\"));\n\tconst supportedScopes = options.supportedScopes ?? [\"global\", \"project\"];\n\tif (\n\t\t!Array.isArray(supportedScopes) ||\n\t\tsupportedScopes.length === 0 ||\n\t\tnew Set(supportedScopes).size !== supportedScopes.length ||\n\t\tsupportedScopes.some((scope) => scope !== \"global\" && scope !== \"project\")\n\t)\n\t\tthrow new Error(t(\"supportedScopes is invalid\"));\n\tawait mkdir(parent, { recursive: true, mode: 0o700 });\n\tconst persistent = options.persistence === \"persistent\";\n\tconst instanceRoot = persistent\n\t\t? join(parent, \"agent-forge-plugin-install-store-v1\")\n\t\t: await mkdtemp(join(parent, \"agent-forge-plugin-install-\"));\n\tconst persistence: NodePackageInstallPersistenceV1 | undefined = persistent\n\t\t? await createNodePackageInstallPersistenceV1({\n\t\t\t\trootDirectory: instanceRoot,\n\t\t\t\tlockTimeoutMs: options.persistenceLockTimeoutMs,\n\t\t\t})\n\t\t: undefined;\n\tconst records = new Map<string, InstalledRecordV1>();\n\tconst activeByKey = new Map<string, string>();\n\tif (persistence !== undefined) {\n\t\tfor (const record of await persistence.load()) records.set(record.installationRef, { ...record });\n\t}\n\tfor (const record of records.values()) {\n\t\tif (record.state === \"active\")\n\t\t\tactiveByKey.set(installationKey(record.scope, record.scopeRef, record.pluginId), record.installationRef);\n\t}\n\tlet closed = false;\n\tconst activeOperations = new Set<AbortController>();\n\tconst runtimeHandles = new Map<string, { readonly dispose?: () => void | Promise<void> }>();\n\tconst applyPersistentSnapshot = (snapshot: readonly NodePackageInstallPersistentRecordV1[]): void => {\n\t\trecords.clear();\n\t\tactiveByKey.clear();\n\t\tfor (const value of snapshot) records.set(value.installationRef, { ...value });\n\t\tfor (const value of records.values()) {\n\t\t\tif (value.state === \"active\")\n\t\t\t\tactiveByKey.set(installationKey(value.scope, value.scopeRef, value.pluginId), value.installationRef);\n\t\t}\n\t};\n\tconst commitRecords = async (\n\t\tupdate: (values: Map<string, NodePackageInstallPersistentRecordV1>) => void | Promise<void>,\n\t): Promise<void> => {\n\t\tif (persistence === undefined) {\n\t\t\tawait update(records);\n\t\t\treturn;\n\t\t}\n\t\tapplyPersistentSnapshot(await persistence.mutate({ update }));\n\t};\n\tlet drained: (() => void) | undefined;\n\tlet closePromise: Promise<void> | undefined;\n\n\tconst begin = (\n\t\tparentSignal: AbortSignal | undefined,\n\t): { readonly controller: AbortController; readonly signal: AbortSignal } => {\n\t\tif (closed) throw new NodePackageInstallErrorV1(\"host_closed\");\n\t\tconst controller = new AbortController();\n\t\tif (parentSignal?.aborted) controller.abort(parentSignal.reason);\n\t\telse parentSignal?.addEventListener(\"abort\", () => controller.abort(parentSignal.reason), { once: true });\n\t\tactiveOperations.add(controller);\n\t\treturn { controller, signal: controller.signal };\n\t};\n\tconst end = (controller: AbortController): void => {\n\t\tactiveOperations.delete(controller);\n\t\tif (activeOperations.size === 0) {\n\t\t\tdrained?.();\n\t\t\tdrained = undefined;\n\t\t}\n\t};\n\tconst waitDrained = async (): Promise<void> => {\n\t\tif (activeOperations.size === 0) return;\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tdrained = resolve;\n\t\t});\n\t};\n\tconst getRecord = (\n\t\tinstallation: PluginInstallationV1,\n\t\trecord: PluginUpdateRecordV1,\n\t\tscope: PluginInstallationScopeV1,\n\t\tscopeRef: string,\n\t): InstalledRecordV1 => {\n\t\tconst value = records.get(installation.installationRef);\n\t\tif (\n\t\t\tvalue === undefined ||\n\t\t\tinstallation.pluginId !== record.pluginId ||\n\t\t\tinstallation.pluginVersion !== record.pluginVersion ||\n\t\t\tinstallation.manifestDigest !== record.manifestDigest ||\n\t\t\tinstallation.scope !== scope ||\n\t\t\tinstallation.scopeRef !== scopeRef ||\n\t\t\t!identityMatches(value, {\n\t\t\t\tpluginId: record.pluginId,\n\t\t\t\tpluginVersion: record.pluginVersion,\n\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\tscope,\n\t\t\t\tscopeRef,\n\t\t\t})\n\t\t)\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\treturn value;\n\t};\n\tconst disposeRuntime = async (installationRef: string): Promise<void> => {\n\t\tconst handle = runtimeHandles.get(installationRef);\n\t\tif (handle === undefined) return;\n\t\tif (handle.dispose !== undefined) await Promise.resolve(handle.dispose());\n\t\truntimeHandles.delete(installationRef);\n\t};\n\tconst loadRuntime = async (\n\t\tinstallation: PluginInstallationV1,\n\t\trecord: PluginUpdateRecordV1 | undefined,\n\t\tdirectory: string,\n\t\tsignal: AbortSignal,\n\t): Promise<{ readonly dispose?: () => void | Promise<void> } | undefined> => {\n\t\tif (options.loadPlugin === undefined) return undefined;\n\t\ttry {\n\t\t\tconst loaded = await options.loadPlugin({\n\t\t\t\tinstallation,\n\t\t\t\trecord,\n\t\t\t\tdirectory,\n\t\t\t\tmanifestPath: join(directory, CAPABILITY_MANIFEST_FILE_V1),\n\t\t\t\tsignal,\n\t\t\t});\n\t\t\treturn loaded ?? undefined;\n\t\t} catch (error) {\n\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t}\n\t};\n\n\tconst host: NodePackageInstallHostV1 = {\n\t\tversion: NODE_PACKAGE_INSTALL_HOST_VERSION_V1,\n\t\tsupportedScopes: Object.freeze([...supportedScopes]),\n\t\tgetInstallationDirectory(input) {\n\t\t\tconst record = records.get(input.installation.installationRef);\n\t\t\tif (\n\t\t\t\trecord === undefined ||\n\t\t\t\trecord.pluginId !== input.installation.pluginId ||\n\t\t\t\trecord.pluginVersion !== input.installation.pluginVersion ||\n\t\t\t\trecord.manifestDigest !== input.installation.manifestDigest ||\n\t\t\t\trecord.scope !== input.installation.scope ||\n\t\t\t\trecord.scopeRef !== input.installation.scopeRef\n\t\t\t)\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_unknown\");\n\t\t\treturn record.directory;\n\t\t},\n\t\tasync install(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet staging: string | undefined;\n\t\t\ttry {\n\t\t\t\tif (input.artifact === undefined) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tif (!artifactIdentityMatchesRecord(input.artifact, input.record))\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst mediaType = input.artifact.mediaType.toLowerCase();\n\t\t\t\tif (mediaType !== \"application/zip\" && mediaType !== \"application/gzip\")\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"unsupported_media_type\");\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst bytes = await collectArtifact(\n\t\t\t\t\toptions.openArtifact,\n\t\t\t\t\tinput.artifact,\n\t\t\t\t\tlimits.maxArchiveBytes,\n\t\t\t\t\toperation.signal,\n\t\t\t\t);\n\t\t\t\tif (input.artifact.sizeBytes !== bytes.byteLength) throw new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst digest = expectedArtifactDigest(input.artifact.artifactDigest);\n\t\t\t\tif (createHash(digest.algorithm).update(bytes).digest(\"hex\") !== digest.hex)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"invalid_artifact\");\n\t\t\t\tconst entries =\n\t\t\t\t\tmediaType === \"application/gzip\"\n\t\t\t\t\t\t? await parseNodeTarGzPackageV1(bytes, limits)\n\t\t\t\t\t\t: parseNodeZipPackageV1(bytes, limits);\n\t\t\t\tconst manifestEntry = entries.find(\n\t\t\t\t\t(entry) => entry.name === ECOSYSTEM_MANIFEST_FILE_V1 && !entry.directory,\n\t\t\t\t);\n\t\t\t\tif (manifestEntry === undefined) throw new NodePackageInstallErrorV1(\"package_manifest_missing\");\n\t\t\t\tif (manifestEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\tlet manifest: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tmanifest = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(manifestEntry.bytes));\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\t}\n\t\t\t\tpackageManifest(manifest, input.record);\n\t\t\t\tconst capabilityEntry = entries.find(\n\t\t\t\t\t(entry) => entry.name === CAPABILITY_MANIFEST_FILE_V1 && !entry.directory,\n\t\t\t\t);\n\t\t\t\tif (capabilityEntry === undefined) throw new NodePackageInstallErrorV1(\"package_manifest_missing\");\n\t\t\t\tif (capabilityEntry.bytes.byteLength > MAX_PACKAGE_MANIFEST_BYTES_V1)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\tlet capability: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tcapability = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(capabilityEntry.bytes));\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"package_manifest_invalid\");\n\t\t\t\t}\n\t\t\t\tcapabilityManifest(capability, input.record, entries);\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, input.record.pluginId);\n\t\t\t\tstaging = join(instanceRoot, `.staging-${randomUUID()}`);\n\t\t\t\tawait writeEntries(staging, entries, operation.signal);\n\t\t\t\tconst installRef = `plugin-install://node-zip/${randomUUID()}`;\n\t\t\t\tconst destination = packagePath(instanceRoot, `${key}\\u0000${installRef}`);\n\t\t\t\tawait rename(staging, destination);\n\t\t\t\tstaging = undefined;\n\t\t\t\tconst installedRecord: InstalledRecordV1 = {\n\t\t\t\t\tinstallationRef: installRef,\n\t\t\t\t\tdirectory: destination,\n\t\t\t\t\tpluginId: input.record.pluginId,\n\t\t\t\t\tpluginVersion: input.record.pluginVersion,\n\t\t\t\t\tmanifestDigest: input.record.manifestDigest,\n\t\t\t\t\tscope: input.scope,\n\t\t\t\t\tscopeRef,\n\t\t\t\t\tstate: \"installed\",\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\t\tvalues.set(installRef, installedRecord);\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tawait rm(destination, { recursive: true, force: true }).catch(() => undefined);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\treturn { installationRef: installRef, scope: input.scope, scopeRef };\n\t\t\t} catch (error) {\n\t\t\t\tif (operation.signal.aborted || input.signal?.aborted) throw new NodePackageInstallErrorV1(\"cancelled\");\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tif (staging !== undefined) await rm(staging, { recursive: true, force: true }).catch(() => undefined);\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync activate(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet candidate: { readonly dispose?: () => void | Promise<void> } | undefined;\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst record = getRecord(input.installation, input.record, input.scope, scopeRef);\n\t\t\t\tif (record.state !== \"installed\") throw new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tcandidate = await loadRuntime(input.installation, input.record, record.directory, operation.signal);\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, input.record.pluginId);\n\t\t\t\tconst previousRef = activeByKey.get(key);\n\t\t\t\tif (previousRef !== undefined) {\n\t\t\t\t\tconst previous = records.get(previousRef);\n\t\t\t\t\tif (previous !== undefined) {\n\t\t\t\t\t\tawait disposeRuntime(previousRef);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tconst candidateRecord = values.get(input.installation.installationRef);\n\t\t\t\t\tif (candidateRecord === undefined) throw new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\t\tif (previousRef !== undefined) {\n\t\t\t\t\t\tconst previousRecord = values.get(previousRef);\n\t\t\t\t\t\tif (previousRecord !== undefined) values.set(previousRef, { ...previousRecord, state: \"retained\" });\n\t\t\t\t\t}\n\t\t\t\t\tvalues.set(input.installation.installationRef, { ...candidateRecord, state: \"active\" });\n\t\t\t\t});\n\t\t\t\tactiveByKey.set(key, input.installation.installationRef);\n\t\t\t\tif (candidate !== undefined) runtimeHandles.set(input.installation.installationRef, candidate);\n\t\t\t\tcandidate = undefined;\n\t\t\t} catch (error) {\n\t\t\t\tif (candidate?.dispose !== undefined) await Promise.resolve(candidate.dispose()).catch(() => undefined);\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync rollback(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\tlet candidate: { readonly dispose?: () => void | Promise<void> } | undefined;\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst failed = records.get(input.failed.installationRef);\n\t\t\t\tif (\n\t\t\t\t\tfailed === undefined ||\n\t\t\t\t\t!identityMatches(failed, {\n\t\t\t\t\t\tpluginId: input.failed.pluginId,\n\t\t\t\t\t\tpluginVersion: input.failed.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.failed.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tconst previous = records.get(input.previous.installationRef);\n\t\t\t\tif (\n\t\t\t\t\tprevious === undefined ||\n\t\t\t\t\t!identityMatches(previous, {\n\t\t\t\t\t\tpluginId: input.previous.pluginId,\n\t\t\t\t\t\tpluginVersion: input.previous.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.previous.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t}) ||\n\t\t\t\t\t(previous.state !== \"active\" && previous.state !== \"retained\") ||\n\t\t\t\t\tfailed.pluginId !== previous.pluginId\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_identity_mismatch\");\n\t\t\t\tconst previousInstallation: PluginInstallationV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tpluginId: previous.pluginId,\n\t\t\t\t\tpluginVersion: previous.pluginVersion,\n\t\t\t\t\tmanifestDigest: previous.manifestDigest,\n\t\t\t\t\tscope: previous.scope,\n\t\t\t\t\tscopeRef: previous.scopeRef,\n\t\t\t\t\tinstallationRef: input.previous.installationRef,\n\t\t\t\t\tstate: \"active\",\n\t\t\t\t};\n\t\t\t\tcandidate = await loadRuntime(previousInstallation, undefined, previous.directory, operation.signal);\n\t\t\t\tawait disposeRuntime(input.failed.installationRef);\n\t\t\t\tawait rm(failed.directory, { recursive: true, force: true });\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tvalues.delete(input.failed.installationRef);\n\t\t\t\t\tconst previousRecord = values.get(input.previous.installationRef);\n\t\t\t\t\tif (previousRecord !== undefined)\n\t\t\t\t\t\tvalues.set(input.previous.installationRef, { ...previousRecord, state: \"active\" });\n\t\t\t\t});\n\t\t\t\tactiveByKey.set(installationKey(input.scope, scopeRef, failed.pluginId), input.previous.installationRef);\n\t\t\t\tif (candidate !== undefined) runtimeHandles.set(input.previous.installationRef, candidate);\n\t\t\t\tcandidate = undefined;\n\t\t\t} catch (error) {\n\t\t\t\tif (candidate?.dispose !== undefined) await Promise.resolve(candidate.dispose()).catch(() => undefined);\n\t\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync uninstall(input) {\n\t\t\tconst operation = begin(input.signal);\n\t\t\ttry {\n\t\t\t\tconst scopeRef = opaqueScope(input.scopeRef);\n\t\t\t\tconst record = records.get(input.installation.installationRef);\n\t\t\t\tif (\n\t\t\t\t\trecord === undefined ||\n\t\t\t\t\t!identityMatches(record, {\n\t\t\t\t\t\tpluginId: input.installation.pluginId,\n\t\t\t\t\t\tpluginVersion: input.installation.pluginVersion,\n\t\t\t\t\t\tmanifestDigest: input.installation.manifestDigest,\n\t\t\t\t\t\tscope: input.scope,\n\t\t\t\t\t\tscopeRef,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t\t\tthrow new NodePackageInstallErrorV1(\"installation_unknown\");\n\t\t\t\tawait disposeRuntime(input.installation.installationRef);\n\t\t\t\t// force:false keeps rm strict, but a directory that is already\n\t\t\t\t// gone (ghost record from an interrupted uninstall) is the\n\t\t\t\t// desired end state — continue to the index commit instead of\n\t\t\t\t// bricking every later store operation on ENOENT.\n\t\t\t\tawait rm(record.directory, { recursive: true, force: false }).catch((error: unknown) => {\n\t\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t\t\tawait commitRecords((values) => {\n\t\t\t\t\tvalues.delete(input.installation.installationRef);\n\t\t\t\t});\n\t\t\t\tconst key = installationKey(input.scope, scopeRef, record.pluginId);\n\t\t\t\tif (activeByKey.get(key) === input.installation.installationRef) activeByKey.delete(key);\n\t\t\t} finally {\n\t\t\t\tend(operation.controller);\n\t\t\t}\n\t\t},\n\t\tasync close() {\n\t\t\tif (closePromise !== undefined) return await closePromise;\n\t\t\tclosed = true;\n\t\t\tfor (const operation of activeOperations) operation.abort();\n\t\t\tclosePromise = (async () => {\n\t\t\t\tawait waitDrained();\n\t\t\t\tlet disposeError = false;\n\t\t\t\tfor (const installationRef of runtimeHandles.keys()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait disposeRuntime(installationRef);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tdisposeError = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (persistence === undefined) await rm(instanceRoot, { recursive: true, force: true });\n\t\t\t\telse await persistence.close();\n\t\t\t\trecords.clear();\n\t\t\t\tactiveByKey.clear();\n\t\t\t\tif (disposeError) throw new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t\t})();\n\t\t\treturn await closePromise;\n\t\t},\n\t};\n\tif (options.loadPlugin !== undefined) {\n\t\ttry {\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.state !== \"active\") continue;\n\t\t\t\tconst installation: PluginInstallationV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tpluginId: record.pluginId,\n\t\t\t\t\tpluginVersion: record.pluginVersion,\n\t\t\t\t\tmanifestDigest: record.manifestDigest,\n\t\t\t\t\tscope: record.scope,\n\t\t\t\t\tscopeRef: record.scopeRef,\n\t\t\t\t\tinstallationRef: record.installationRef,\n\t\t\t\t\tstate: \"active\",\n\t\t\t\t};\n\t\t\t\tconst runtime = await loadRuntime(installation, undefined, record.directory, new AbortController().signal);\n\t\t\t\tif (runtime !== undefined) runtimeHandles.set(record.installationRef, runtime);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait host.close().catch(() => undefined);\n\t\t\tif (error instanceof NodePackageInstallErrorV1) throw error;\n\t\t\tthrow new NodePackageInstallErrorV1(\"installation_io_failed\");\n\t\t}\n\t}\n\treturn host;\n}\n"]}
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os";
4
4
  import { isAbsolute, join } from "node:path";
5
5
  import { inflateRawSync } from "node:zlib";
6
6
  import { parseCapabilityPluginManifest } from "../../core/extensions/capability-plugin.js";
7
+ import { t } from "../../core/i18n/index.js";
7
8
  import { createNodePackageInstallPersistenceV1, } from "./node-package-install-persistence.js";
8
9
  import { parseNodeTarGzPackageV1 } from "./node-tar-package.js";
9
10
  import { pluginManifestDigestV1 } from "./updates.js";
@@ -28,7 +29,7 @@ const ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_V1 = 0x07064b50;
28
29
  export class NodePackageInstallErrorV1 extends Error {
29
30
  code;
30
31
  constructor(code) {
31
- super(`Node package installation failed: ${code}`);
32
+ super(t("Node package installation failed: {code}", { code }));
32
33
  this.name = "NodePackageInstallErrorV1";
33
34
  this.code = code;
34
35
  }
@@ -50,7 +51,7 @@ export function createNodePackageInstallSessionLoaderV1(session) {
50
51
  */
51
52
  export async function createNodePackageInstallHostForSessionV1(options, session) {
52
53
  if (options.loadPlugin !== undefined)
53
- throw new Error("loadPlugin must be omitted when binding a session");
54
+ throw new Error(t("loadPlugin must be omitted when binding a session"));
54
55
  return await createNodePackageInstallHostV1({
55
56
  ...options,
56
57
  loadPlugin: createNodePackageInstallSessionLoaderV1(session),
@@ -59,7 +60,7 @@ export async function createNodePackageInstallHostForSessionV1(options, session)
59
60
  function positiveLimit(value, fallback, maximum, label) {
60
61
  const result = value ?? fallback;
61
62
  if (!Number.isSafeInteger(result) || result < 1 || result > maximum)
62
- throw new Error(`${label} must be a positive integer at most ${maximum}`);
63
+ throw new Error(t("{label} must be a positive integer at most {maximum}", { label, maximum }));
63
64
  return result;
64
65
  }
65
66
  /** Resolve the archive budget limits shared by the ZIP and tgz package parsers. */
@@ -85,7 +86,7 @@ function decodeName(bytes, utf8) {
85
86
  try {
86
87
  const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
87
88
  if (!utf8 && /[^\x00-\x7f]/u.test(value))
88
- throw new Error("non-ascii zip name");
89
+ throw new Error(t("non-ascii zip name"));
89
90
  return value;
90
91
  }
91
92
  catch {
@@ -435,19 +436,19 @@ async function writeEntries(root, entries, signal) {
435
436
  */
436
437
  export async function createNodePackageInstallHostV1(options) {
437
438
  if (typeof options.openArtifact !== "function")
438
- throw new Error("openArtifact is required");
439
+ throw new Error(t("openArtifact is required"));
439
440
  const limits = resolveNodePackageLimitsV1(options);
440
441
  const parent = options.installationDirectory ?? tmpdir();
441
442
  if (!isAbsolute(parent))
442
- throw new Error("installationDirectory must be absolute");
443
+ throw new Error(t("installationDirectory must be absolute"));
443
444
  if (options.persistence !== undefined && options.persistence !== "ephemeral" && options.persistence !== "persistent")
444
- throw new Error("persistence mode is invalid");
445
+ throw new Error(t("persistence mode is invalid"));
445
446
  const supportedScopes = options.supportedScopes ?? ["global", "project"];
446
447
  if (!Array.isArray(supportedScopes) ||
447
448
  supportedScopes.length === 0 ||
448
449
  new Set(supportedScopes).size !== supportedScopes.length ||
449
450
  supportedScopes.some((scope) => scope !== "global" && scope !== "project"))
450
- throw new Error("supportedScopes is invalid");
451
+ throw new Error(t("supportedScopes is invalid"));
451
452
  await mkdir(parent, { recursive: true, mode: 0o700 });
452
453
  const persistent = options.persistence === "persistent";
453
454
  const instanceRoot = persistent