@ai-agent-forge/agent-forge 0.88.1 → 0.88.3

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 (518) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +1 -1
  3. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  4. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  5. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  6. package/bundled-plugins/coding-tools/plugin.json +1 -1
  7. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  8. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  9. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  10. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  11. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  12. package/bundled-plugins/provider-failover/plugin.json +1 -1
  13. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  14. package/bundled-plugins/retry-policy/plugin.json +1 -1
  15. package/dist/artifacts/paged-read.d.ts +6 -1
  16. package/dist/artifacts/paged-read.d.ts.map +1 -1
  17. package/dist/artifacts/paged-read.js.map +1 -1
  18. package/dist/bundle/.build-manifest.json +283 -263
  19. package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
  20. package/dist/bundle/chunks/anthropic.js +1 -1
  21. package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
  22. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  23. package/dist/bundle/chunks/{chunk-Z72JWUZ4.js → chunk-32YDZI4J.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-AQLNTW2B.js → chunk-755VNWIF.js} +17 -16
  25. package/dist/bundle/chunks/{chunk-LZOEQITZ.js → chunk-B42Y2VME.js} +120 -104
  26. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-D3ARGZFR.js → chunk-V3ACW7VD.js} +3 -3
  29. package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
  30. package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
  31. package/dist/bundle/chunks/image-resize-worker.js +3 -3
  32. package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
  33. package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
  34. package/dist/bundle/chunks/openai-codex.js +1 -1
  35. package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
  36. package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
  37. package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
  38. package/dist/bundle/chunks/openrouter.js +1 -1
  39. package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
  40. package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
  41. package/dist/bundle/cli.js +1 -1
  42. package/dist/bundle/client.js +1 -1
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/bundle/rpc-entry.js +1 -1
  45. package/dist/cli/args.d.ts +0 -1
  46. package/dist/cli/args.d.ts.map +1 -1
  47. package/dist/cli/args.js +1 -4
  48. package/dist/cli/args.js.map +1 -1
  49. package/dist/cli/config-selector.d.ts.map +1 -1
  50. package/dist/cli/config-selector.js +1 -1
  51. package/dist/cli/config-selector.js.map +1 -1
  52. package/dist/cli/experimental/cli.d.ts +3 -3
  53. package/dist/cli/experimental/cli.d.ts.map +1 -1
  54. package/dist/cli/experimental/cli.js +2 -2
  55. package/dist/cli/experimental/cli.js.map +1 -1
  56. package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
  57. package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
  58. package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
  59. package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
  60. package/dist/cli/plugin-command.d.ts.map +1 -1
  61. package/dist/cli/plugin-command.js +8 -2
  62. package/dist/cli/plugin-command.js.map +1 -1
  63. package/dist/cli/startup-ui.d.ts.map +1 -1
  64. package/dist/cli/startup-ui.js +1 -1
  65. package/dist/cli/startup-ui.js.map +1 -1
  66. package/dist/config.d.ts +4 -4
  67. package/dist/config.d.ts.map +1 -1
  68. package/dist/config.js +7 -7
  69. package/dist/config.js.map +1 -1
  70. package/dist/core/agent-forge-manifest.d.ts +7 -0
  71. package/dist/core/agent-forge-manifest.d.ts.map +1 -0
  72. package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
  73. package/dist/core/agent-forge-manifest.js.map +1 -0
  74. package/dist/core/agent-session-compaction.d.ts +1 -1
  75. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  76. package/dist/core/agent-session-compaction.js +3 -3
  77. package/dist/core/agent-session-compaction.js.map +1 -1
  78. package/dist/core/agent-session-internal.d.ts +2 -0
  79. package/dist/core/agent-session-internal.d.ts.map +1 -1
  80. package/dist/core/agent-session-internal.js.map +1 -1
  81. package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
  82. package/dist/core/agent-session-lifecycle.js +12 -1
  83. package/dist/core/agent-session-lifecycle.js.map +1 -1
  84. package/dist/core/agent-session-projection.d.ts.map +1 -1
  85. package/dist/core/agent-session-projection.js +3 -3
  86. package/dist/core/agent-session-projection.js.map +1 -1
  87. package/dist/core/agent-session-services.d.ts +3 -1
  88. package/dist/core/agent-session-services.d.ts.map +1 -1
  89. package/dist/core/agent-session-services.js +2 -1
  90. package/dist/core/agent-session-services.js.map +1 -1
  91. package/dist/core/agent-session-store.d.ts.map +1 -1
  92. package/dist/core/agent-session-store.js +6 -1
  93. package/dist/core/agent-session-store.js.map +1 -1
  94. package/dist/core/agent-session-tools.d.ts.map +1 -1
  95. package/dist/core/agent-session-tools.js +13 -0
  96. package/dist/core/agent-session-tools.js.map +1 -1
  97. package/dist/core/agent-session.d.ts +24 -0
  98. package/dist/core/agent-session.d.ts.map +1 -1
  99. package/dist/core/agent-session.js +58 -4
  100. package/dist/core/agent-session.js.map +1 -1
  101. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  102. package/dist/core/compaction/branch-summarization.js +1 -1
  103. package/dist/core/compaction/branch-summarization.js.map +1 -1
  104. package/dist/core/experimental.d.ts.map +1 -1
  105. package/dist/core/experimental.js +1 -3
  106. package/dist/core/experimental.js.map +1 -1
  107. package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
  108. package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
  109. package/dist/core/extensions/capability-runtime-store.js +67 -0
  110. package/dist/core/extensions/capability-runtime-store.js.map +1 -1
  111. package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
  112. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  113. package/dist/core/extensions/capability-runtime-types.js +7 -1
  114. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  115. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  116. package/dist/core/extensions/capability-runtime.js +144 -42
  117. package/dist/core/extensions/capability-runtime.js.map +1 -1
  118. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  119. package/dist/core/extensions/virtual-modules.js +6 -1
  120. package/dist/core/extensions/virtual-modules.js.map +1 -1
  121. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  122. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  123. package/dist/core/facade/coding-agent-facade.js +1 -1
  124. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  125. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
  126. package/dist/core/i18n/locales/zh-cn/cli.js +2 -0
  127. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
  128. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
  129. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
  130. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
  131. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
  132. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
  133. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
  134. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
  135. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  136. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
  137. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  138. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -1
  139. package/dist/core/i18n/locales/zh-cn/index.js +2 -0
  140. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -1
  141. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  142. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +5 -0
  143. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  144. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts +7 -0
  145. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts.map +1 -0
  146. package/dist/core/i18n/locales/zh-cn/session-cleanup.js +15 -0
  147. package/dist/core/i18n/locales/zh-cn/session-cleanup.js.map +1 -0
  148. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -1
  149. package/dist/core/i18n/locales/zh-cn/slash-commands.js +1 -0
  150. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -1
  151. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
  152. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
  153. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
  154. package/dist/core/model-resolver.d.ts +2 -0
  155. package/dist/core/model-resolver.d.ts.map +1 -1
  156. package/dist/core/model-resolver.js +4 -1
  157. package/dist/core/model-resolver.js.map +1 -1
  158. package/dist/core/package-resource-collection.d.ts.map +1 -1
  159. package/dist/core/package-resource-collection.js +5 -5
  160. package/dist/core/package-resource-collection.js.map +1 -1
  161. package/dist/core/provider-composer.d.ts.map +1 -1
  162. package/dist/core/provider-composer.js +3 -3
  163. package/dist/core/provider-composer.js.map +1 -1
  164. package/dist/core/resource-loader.d.ts.map +1 -1
  165. package/dist/core/resource-loader.js +1 -1
  166. package/dist/core/resource-loader.js.map +1 -1
  167. package/dist/core/sdk.d.ts +1 -1
  168. package/dist/core/sdk.d.ts.map +1 -1
  169. package/dist/core/sdk.js +30 -8
  170. package/dist/core/sdk.js.map +1 -1
  171. package/dist/core/session-cleanup.d.ts +49 -0
  172. package/dist/core/session-cleanup.d.ts.map +1 -0
  173. package/dist/core/session-cleanup.js +159 -0
  174. package/dist/core/session-cleanup.js.map +1 -0
  175. package/dist/core/session-index.d.ts +75 -0
  176. package/dist/core/session-index.d.ts.map +1 -0
  177. package/dist/core/session-index.js +455 -0
  178. package/dist/core/session-index.js.map +1 -0
  179. package/dist/core/session-manager.d.ts +9 -0
  180. package/dist/core/session-manager.d.ts.map +1 -1
  181. package/dist/core/session-manager.js +206 -51
  182. package/dist/core/session-manager.js.map +1 -1
  183. package/dist/core/settings-manager.d.ts.map +1 -1
  184. package/dist/core/settings-manager.js +5 -10
  185. package/dist/core/settings-manager.js.map +1 -1
  186. package/dist/core/slash-commands.d.ts.map +1 -1
  187. package/dist/core/slash-commands.js +5 -0
  188. package/dist/core/slash-commands.js.map +1 -1
  189. package/dist/core/system-prompt.d.ts.map +1 -1
  190. package/dist/core/system-prompt.js +12 -1
  191. package/dist/core/system-prompt.js.map +1 -1
  192. package/dist/core/timings.d.ts.map +1 -1
  193. package/dist/core/timings.js +1 -3
  194. package/dist/core/timings.js.map +1 -1
  195. package/dist/core/tools/capability-mount.d.ts +40 -0
  196. package/dist/core/tools/capability-mount.d.ts.map +1 -0
  197. package/dist/core/tools/capability-mount.js +112 -0
  198. package/dist/core/tools/capability-mount.js.map +1 -0
  199. package/dist/core/tools/render-utils.d.ts +1 -1
  200. package/dist/core/tools/render-utils.d.ts.map +1 -1
  201. package/dist/core/tools/render-utils.js.map +1 -1
  202. package/dist/core/tools/tool-definition.d.ts +1 -1
  203. package/dist/core/tools/tool-definition.d.ts.map +1 -1
  204. package/dist/core/tools/tool-definition.js.map +1 -1
  205. package/dist/core/trace-retention.d.ts +16 -1
  206. package/dist/core/trace-retention.d.ts.map +1 -1
  207. package/dist/core/trace-retention.js +43 -20
  208. package/dist/core/trace-retention.js.map +1 -1
  209. package/dist/export-html/ansi-to-html.d.ts.map +1 -0
  210. package/dist/export-html/ansi-to-html.js.map +1 -0
  211. package/dist/{core/export-html → export-html}/index.d.ts +1 -1
  212. package/dist/export-html/index.d.ts.map +1 -0
  213. package/dist/{core/export-html → export-html}/index.js +5 -5
  214. package/dist/export-html/index.js.map +1 -0
  215. package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
  216. package/dist/export-html/tool-renderer.d.ts.map +1 -0
  217. package/dist/export-html/tool-renderer.js.map +1 -0
  218. package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
  219. package/dist/host/model-catalog-refresh.d.ts.map +1 -0
  220. package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
  221. package/dist/host/model-catalog-refresh.js.map +1 -0
  222. package/dist/index.d.ts +5 -5
  223. package/dist/index.d.ts.map +1 -1
  224. package/dist/index.js +12 -12
  225. package/dist/index.js.map +1 -1
  226. package/dist/main.d.ts.map +1 -1
  227. package/dist/main.js +26 -14
  228. package/dist/main.js.map +1 -1
  229. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/agents-view.js +1 -1
  231. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  232. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  233. package/dist/modes/interactive/components/armin.js +1 -1
  234. package/dist/modes/interactive/components/armin.js.map +1 -1
  235. package/dist/modes/interactive/components/assistant-message.d.ts +6 -0
  236. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  237. package/dist/modes/interactive/components/assistant-message.js +108 -27
  238. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  239. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  240. package/dist/modes/interactive/components/bash-execution.js +1 -1
  241. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  242. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  243. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  244. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  245. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  246. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  247. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  248. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  249. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  250. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  251. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  252. package/dist/modes/interactive/components/config-selector.js +1 -1
  253. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  254. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/custom-entry.js +1 -1
  256. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  257. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/custom-message.js +1 -1
  259. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  260. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  261. package/dist/modes/interactive/components/daxnuts.js +1 -1
  262. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  263. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  264. package/dist/modes/interactive/components/dialog-editor.js +1 -1
  265. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  266. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  267. package/dist/modes/interactive/components/dialog-input.js +1 -1
  268. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  269. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  270. package/dist/modes/interactive/components/dialog-selector.js +1 -1
  271. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  272. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/diff.js +1 -1
  274. package/dist/modes/interactive/components/diff.js.map +1 -1
  275. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  276. package/dist/modes/interactive/components/dynamic-border.js +1 -1
  277. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  278. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  279. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  281. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  282. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/footer.js +1 -1
  284. package/dist/modes/interactive/components/footer.js.map +1 -1
  285. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  286. package/dist/modes/interactive/components/keybinding-hints.js +1 -1
  287. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  288. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  289. package/dist/modes/interactive/components/login-dialog.js +1 -1
  290. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  291. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  292. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  293. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  294. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  295. package/dist/modes/interactive/components/model-selector.js +2 -2
  296. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  297. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  298. package/dist/modes/interactive/components/oauth-selector.js +1 -1
  299. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  300. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  301. package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
  302. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  303. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  304. package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
  305. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  306. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
  307. package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
  308. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
  309. package/dist/modes/interactive/components/render-types.d.ts +1 -1
  310. package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
  311. package/dist/modes/interactive/components/render-types.js.map +1 -1
  312. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  313. package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
  314. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  315. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/session-selector-search.js +5 -1
  317. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  318. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/session-selector.js +11 -2
  320. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  321. package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
  322. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  323. package/dist/modes/interactive/components/settings-selector.js +1 -1
  324. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  325. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/settings-submenu.js +1 -1
  327. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  328. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  329. package/dist/modes/interactive/components/show-images-selector.js +1 -1
  330. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  331. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  332. package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
  333. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  334. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/status-indicator.js +1 -1
  336. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  337. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/theme-selector.js +1 -1
  339. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  340. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  341. package/dist/modes/interactive/components/thinking-selector.js +1 -1
  342. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  343. package/dist/modes/interactive/components/tool-execution.d.ts +19 -0
  344. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  345. package/dist/modes/interactive/components/tool-execution.js +139 -4
  346. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  347. package/dist/modes/interactive/components/tool-run-group.d.ts +44 -0
  348. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -0
  349. package/dist/modes/interactive/components/tool-run-group.js +121 -0
  350. package/dist/modes/interactive/components/tool-run-group.js.map +1 -0
  351. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/tree-list.js +1 -1
  353. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  354. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/tree-render.js +1 -1
  356. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  357. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  358. package/dist/modes/interactive/components/tree-selector.js +1 -1
  359. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  362. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  363. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/user-message.js +1 -1
  365. package/dist/modes/interactive/components/user-message.js.map +1 -1
  366. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/workflow-view.js +1 -1
  368. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  369. package/dist/modes/interactive/interactive-auth.d.ts +1 -1
  370. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  371. package/dist/modes/interactive/interactive-auth.js +1 -1
  372. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  373. package/dist/modes/interactive/interactive-commands.d.ts +125 -6
  374. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  375. package/dist/modes/interactive/interactive-commands.js +698 -4
  376. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  377. package/dist/modes/interactive/interactive-events.d.ts +174 -0
  378. package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
  379. package/dist/modes/interactive/interactive-events.js +704 -0
  380. package/dist/modes/interactive/interactive-events.js.map +1 -0
  381. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  382. package/dist/modes/interactive/interactive-format.js +1 -1
  383. package/dist/modes/interactive/interactive-format.js.map +1 -1
  384. package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
  385. package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
  386. package/dist/modes/interactive/interactive-lifecycle.js +177 -0
  387. package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
  388. package/dist/modes/interactive/interactive-mode.d.ts +254 -129
  389. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  390. package/dist/modes/interactive/interactive-mode.js +275 -2101
  391. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  392. package/dist/modes/interactive/interactive-queues.d.ts +96 -0
  393. package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
  394. package/dist/modes/interactive/interactive-queues.js +183 -0
  395. package/dist/modes/interactive/interactive-queues.js.map +1 -0
  396. package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
  397. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  398. package/dist/modes/interactive/interactive-selectors.js +517 -6
  399. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  400. package/dist/modes/interactive/startup-services.d.ts +31 -0
  401. package/dist/modes/interactive/startup-services.d.ts.map +1 -0
  402. package/dist/modes/interactive/startup-services.js +123 -0
  403. package/dist/modes/interactive/startup-services.js.map +1 -0
  404. package/dist/modes/memory-preheat.d.ts +11 -0
  405. package/dist/modes/memory-preheat.d.ts.map +1 -0
  406. package/dist/modes/memory-preheat.js +20 -0
  407. package/dist/modes/memory-preheat.js.map +1 -0
  408. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  409. package/dist/modes/rpc/rpc-mode.js +3 -1
  410. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  411. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  412. package/dist/plugins/ecosystem/cli.js +6 -3
  413. package/dist/plugins/ecosystem/cli.js.map +1 -1
  414. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +7 -1
  415. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  416. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +50 -3
  417. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  418. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +28 -16
  419. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  420. package/dist/plugins/ecosystem/plugin-bootstrap.js +35 -33
  421. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  422. package/dist/profile/plugin-profiles.d.ts +1 -1
  423. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  424. package/dist/profile/plugin-profiles.js +18 -0
  425. package/dist/profile/plugin-profiles.js.map +1 -1
  426. package/dist/remote/server-assembly.d.ts.map +1 -1
  427. package/dist/remote/server-assembly.js +7 -2
  428. package/dist/remote/server-assembly.js.map +1 -1
  429. package/dist/{profiles → suites}/builtin-suites.d.ts +14 -4
  430. package/dist/suites/builtin-suites.d.ts.map +1 -0
  431. package/dist/{profiles → suites}/builtin-suites.js +20 -5
  432. package/dist/suites/builtin-suites.js.map +1 -0
  433. package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
  434. package/dist/suites/resolved-agent-profile.js.map +1 -0
  435. package/dist/suites/suite-lifecycle.d.ts.map +1 -0
  436. package/dist/suites/suite-lifecycle.js.map +1 -0
  437. package/dist/suites/suite-loader.d.ts.map +1 -0
  438. package/dist/suites/suite-loader.js.map +1 -0
  439. package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
  440. package/dist/{modes/interactive/theme → theme}/light.json +1 -1
  441. package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
  442. package/dist/theme/theme-controller.d.ts.map +1 -0
  443. package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
  444. package/dist/theme/theme-controller.js.map +1 -0
  445. package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
  446. package/dist/theme/theme.d.ts.map +1 -0
  447. package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
  448. package/dist/theme/theme.js.map +1 -0
  449. package/docs/compaction.md +7 -7
  450. package/docs/environment-variables.md +10 -4
  451. package/docs/keybindings.md +3 -3
  452. package/docs/models.md +17 -17
  453. package/docs/packages.md +1 -1
  454. package/docs/prompt-templates.md +1 -1
  455. package/docs/rpc.md +2 -2
  456. package/docs/sdk.md +5 -5
  457. package/docs/session-format.md +3 -3
  458. package/docs/settings.md +368 -354
  459. package/docs/shell-aliases.md +1 -1
  460. package/docs/skills.md +1 -1
  461. package/docs/terminal-setup.md +17 -17
  462. package/docs/themes.md +5 -5
  463. package/docs/tmux.md +4 -4
  464. package/docs/tui.md +1 -1
  465. package/docs/windows.md +1 -1
  466. package/examples/extensions/bash-spawn-hook/index.ts +1 -1
  467. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  468. package/examples/extensions/with-deps/package-lock.json +2 -2
  469. package/examples/extensions/with-deps/package.json +1 -6
  470. package/examples/extensions/with-deps/plugin.json +1 -1
  471. package/package.json +2 -2
  472. package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
  473. package/dist/bundle/chunks/virtual-modules-WF6WRHP7.js +0 -5
  474. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  475. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  476. package/dist/cli/experimental/commands/pi.js.map +0 -1
  477. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  478. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  479. package/dist/core/export-html/index.d.ts.map +0 -1
  480. package/dist/core/export-html/index.js.map +0 -1
  481. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  482. package/dist/core/export-html/tool-renderer.js.map +0 -1
  483. package/dist/core/pi-manifest.d.ts +0 -7
  484. package/dist/core/pi-manifest.d.ts.map +0 -1
  485. package/dist/core/pi-manifest.js.map +0 -1
  486. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
  487. package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
  488. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  489. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  490. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  491. package/dist/modes/interactive/theme/theme.js.map +0 -1
  492. package/dist/profiles/builtin-suites.d.ts.map +0 -1
  493. package/dist/profiles/builtin-suites.js.map +0 -1
  494. package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
  495. package/dist/profiles/resolved-agent-profile.js.map +0 -1
  496. package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
  497. package/dist/profiles/suite-lifecycle.js.map +0 -1
  498. package/dist/profiles/suite-loader.d.ts.map +0 -1
  499. package/dist/profiles/suite-loader.js.map +0 -1
  500. package/dist/utils/deprecation.d.ts +0 -4
  501. package/dist/utils/deprecation.d.ts.map +0 -1
  502. package/dist/utils/deprecation.js +0 -13
  503. package/dist/utils/deprecation.js.map +0 -1
  504. /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
  505. /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
  506. /package/dist/{core/export-html → export-html}/template.css +0 -0
  507. /package/dist/{core/export-html → export-html}/template.html +0 -0
  508. /package/dist/{core/export-html → export-html}/template.js +0 -0
  509. /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
  510. /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
  511. /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
  512. /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
  513. /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
  514. /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
  515. /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
  516. /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
  517. /package/dist/{profiles → suites}/suite-loader.js +0 -0
  518. /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"node-plugin-bootstrap.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AASrF,OAAO,EAGN,KAAK,sBAAsB,EAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,uBAAuB,EAAwB,MAAM,uBAAuB,CAAC;AAGvH,6EAA6E;AAC7E,eAAO,MAAM,mCAAmC,iCAAiC,CAAC;AAKlF,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;IAC7D,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;IACzC,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,MAAM,2BAA2B,GAAG,uBAAuB,GAAG;IACnE;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC1C,CAAC;AAqCF;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,4BAA4B,GACnC,OAAO,CAAC,2BAA2B,CAAC,CA4LtC","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport { type PluginBootstrapDepsV1, type PluginBootstrapResultV1, runPluginBootstrapV1 } from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"node-plugin-bootstrap.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AASrF,OAAO,EAGN,KAAK,sBAAsB,EAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACN,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAE5B,MAAM,uBAAuB,CAAC;AAG/B,6EAA6E;AAC7E,eAAO,MAAM,mCAAmC,iCAAiC,CAAC;AAKlF,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;IAC7D,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;IACzC,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;CAC9D;AAED,MAAM,MAAM,2BAA2B,GAAG,uBAAuB,GAAG;IACnE;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC1C,CAAC;AAqCF;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,4BAA4B,GACnC,OAAO,CAAC,2BAA2B,CAAC,CAuPtC","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport {\n\ttype PluginBootstrapActionV1,\n\ttype PluginBootstrapDepsV1,\n\ttype PluginBootstrapResultV1,\n\trunPluginBootstrapV1,\n} from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Overrides the per-plugin progress renderer (stderr) for tests and hosts.\n\t * The default prints one line per installed/aligned/failed entry and stays\n\t * silent for satisfied entries.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t\t...(options.onAction === undefined ? {} : { onAction: options.onAction }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\t// Download retry (设计 §4.4 下载重试, 2026-10-04): transient registry\n\t\t\t// failures retried with backoff at this wiring layer so the decision\n\t\t\t// loop stays pure. Abort propagates immediately between attempts.\n\t\t\tlet lastError: unknown;\n\t\t\tfor (let attempt = 1; attempt <= 3; attempt++) {\n\t\t\t\tif (signal?.aborted === true) throw lastError ?? new Error(\"install aborted\");\n\t\t\t\ttry {\n\t\t\t\t\treturn await installFromNpmOnce({ npmName, range, signal });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlastError = error;\n\t\t\t\t\t// Abort during the attempt surfaces as the attempt's own error;\n\t\t\t\t\t// the loop-top check and the backoff listener cover the pauses.\n\t\t\t\t\tif (attempt === 3) throw error;\n\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tconst timer = setTimeout(resolve, 400 * 2 ** (attempt - 1));\n\t\t\t\t\t\tsignal?.addEventListener(\n\t\t\t\t\t\t\t\"abort\",\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\t\t\treject(lastError);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ once: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastError;\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\tconst installFromNpmOnce = async (input: {\n\t\treadonly npmName: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<{ readonly pluginVersion: string; readonly source: string }> => {\n\t\tconst { npmName, range, signal } = input;\n\t\t{\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t}\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t\t// Per-plugin progress (设计 §4.4 逐插件进度, 2026-10-04): one stderr\n\t\t\t// line per installed/aligned/failed entry; satisfied entries stay\n\t\t\t// silent so an all-green startup prints nothing extra.\n\t\t\tonAction:\n\t\t\t\toptions.onAction ??\n\t\t\t\t((action: PluginBootstrapActionV1) => {\n\t\t\t\t\tif (action.status === \"installed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\"{pluginId}: installed {version}\", {\n\t\t\t\t\t\t\t\tpluginId: action.pluginId,\n\t\t\t\t\t\t\t\tversion: action.installedVersion ?? \"\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (action.status === \"failed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\n\t\t\t\t\t\t\t\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\",\n\t\t\t\t\t\t\t\t{ pluginId: action.pluginId, code: action.errorCode ?? \"install_failed\" },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
@@ -22,7 +22,7 @@ import { DEFAULT_PLUGIN_STATE_FILE_V1, defaultPluginHostFactsV1, defaultPluginIn
22
22
  import { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1 } from "./installer.js";
23
23
  import { createNodePackageInstallHostV1, } from "./node-package-install-host.js";
24
24
  import { createNodePluginAcquisitionHostV1 } from "./node-plugin-acquisition-host.js";
25
- import { runPluginBootstrapV1 } from "./plugin-bootstrap.js";
25
+ import { runPluginBootstrapV1, } from "./plugin-bootstrap.js";
26
26
  import { createPluginStateStoreV1 } from "./state.js";
27
27
  /** Environment variable disabling the startup bootstrap entirely (`off`). */
28
28
  export const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = "AGENT_FORGE_PLUGIN_BOOTSTRAP";
@@ -86,6 +86,7 @@ export async function runNodePluginBootstrapV1(options) {
86
86
  manifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,
87
87
  deps: options.deps,
88
88
  ...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),
89
+ ...(options.onAction === undefined ? {} : { onAction: options.onAction }),
89
90
  });
90
91
  }
91
92
  let session;
@@ -123,6 +124,38 @@ export async function runNodePluginBootstrapV1(options) {
123
124
  return new Map([...globalResult, ...projectResult]);
124
125
  },
125
126
  installFromNpm: async ({ npmName, range, signal }) => {
127
+ // Download retry (设计 §4.4 下载重试, 2026-10-04): transient registry
128
+ // failures retried with backoff at this wiring layer so the decision
129
+ // loop stays pure. Abort propagates immediately between attempts.
130
+ let lastError;
131
+ for (let attempt = 1; attempt <= 3; attempt++) {
132
+ if (signal?.aborted === true)
133
+ throw lastError ?? new Error("install aborted");
134
+ try {
135
+ return await installFromNpmOnce({ npmName, range, signal });
136
+ }
137
+ catch (error) {
138
+ lastError = error;
139
+ // Abort during the attempt surfaces as the attempt's own error;
140
+ // the loop-top check and the backoff listener cover the pauses.
141
+ if (attempt === 3)
142
+ throw error;
143
+ await new Promise((resolve, reject) => {
144
+ const timer = setTimeout(resolve, 400 * 2 ** (attempt - 1));
145
+ signal?.addEventListener("abort", () => {
146
+ clearTimeout(timer);
147
+ reject(lastError);
148
+ }, { once: true });
149
+ });
150
+ }
151
+ }
152
+ throw lastError;
153
+ },
154
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
155
+ };
156
+ const installFromNpmOnce = async (input) => {
157
+ const { npmName, range, signal } = input;
158
+ {
126
159
  const active = await ensureSession();
127
160
  // npm refs only (§0.7): scoped or plain names with the shared minimal
128
161
  // range subset; no github/gitee/url/local ref can be expressed here.
@@ -203,8 +236,7 @@ export async function runNodePluginBootstrapV1(options) {
203
236
  finally {
204
237
  await release();
205
238
  }
206
- },
207
- ...(options.signal === undefined ? {} : { signal: options.signal }),
239
+ }
208
240
  };
209
241
  try {
210
242
  return await runPluginBootstrapV1({
@@ -216,6 +248,21 @@ export async function runNodePluginBootstrapV1(options) {
216
248
  ((count) => {
217
249
  console.error(t("First run: installing {count} factory plugins…", { count }));
218
250
  }),
251
+ // Per-plugin progress (设计 §4.4 逐插件进度, 2026-10-04): one stderr
252
+ // line per installed/aligned/failed entry; satisfied entries stay
253
+ // silent so an all-green startup prints nothing extra.
254
+ onAction: options.onAction ??
255
+ ((action) => {
256
+ if (action.status === "installed") {
257
+ console.error(t("{pluginId}: installed {version}", {
258
+ pluginId: action.pluginId,
259
+ version: action.installedVersion ?? "",
260
+ }));
261
+ }
262
+ else if (action.status === "failed") {
263
+ console.error(t("{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically", { pluginId: action.pluginId, code: action.errorCode ?? "install_failed" }));
264
+ }
265
+ }),
219
266
  });
220
267
  }
221
268
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"node-plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport { type PluginBootstrapDepsV1, type PluginBootstrapResultV1, runPluginBootstrapV1 } from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"node-plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-plugin-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,EAAE,oCAAoC,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EACN,4BAA4B,EAC5B,wBAAwB,EACxB,oCAAoC,EACpC,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,kCAAkC,EAA0B,MAAM,gBAAgB,CAAC;AACrH,OAAO,EACN,8BAA8B,GAG9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iCAAiC,EAAoC,MAAM,mCAAmC,CAAC;AACxH,OAAO,EAIN,oBAAoB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAA2B,MAAM,YAAY,CAAC;AAE/E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mCAAmC,GAAG,8BAA8B,CAAC;AAElF,+FAA+F;AAC/F,MAAM,kCAAkC,GAAG,KAAK,CAAC;AA6CjD,SAAS,kBAAkB,CAC1B,KAAyB,EACzB,KAA2B,EAC3B,QAAgB,EAChB,MAA+B,EACQ;IACvC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACjF,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;YACxD,MAAM,IAAI,KAAK,CACd,CAAC,CAAC,2DAA2D,EAAE;gBAC9D,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,MAAM,CAAC,MAAM;gBACpD,KAAK;aACL,CAAC,CACF,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC3C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC9C,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ;gBAAE,SAAS;YACjF,qEAAqE;YACrE,uEAAuE;YACvE,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,KAAK,QAAQ;gBAAE,SAAS;YAClD,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,QAAQ,CAAC;IAAA,CAChB,CAAC,EAAE,CAAC;AAAA,CACL;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,OAAqC,EACE;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,EAAE,IAAI,EAAE,KAAK,kCAAkC,EAAE,CAAC;QACrG,OAAO,MAAM,CAAC,MAAM,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,UAAU;SACnB,CAAC,CAAC;IACJ,CAAC;IACD,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC,MAAM,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC;gBAC1B;oBACC,IAAI,EAAE,2BAA2B;oBACjC,OAAO,EAAE,CAAC,CACT,qJAAqJ,CACrJ;iBACD;aACQ,CAAC;YACX,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,SAAS;SAClB,CAAC,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,MAAM,oBAAoB,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,oCAAoC;YAClE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,CAAC,OAAO,CAAC,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACpG,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;SACzE,CAAC,CAAC;IACJ,CAAC;IACD,IAAI,OAAqC,CAAC;IAC1C,MAAM,aAAa,GAAG,KAAK,IAA+B,EAAE,CAAC;QAC5D,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;QAC1C,MAAM,WAAW,GAAG,iCAAiC,CAAC;YACrD,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;YAClF,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzE,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAChE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;SACnE,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,8BAA8B,CAAC;YACxD,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC;YACxD,qBAAqB,EAAE,oCAAoC,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC7E,WAAW,EAAE,YAAY;YACzB,eAAe,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;YACtC,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,OAAO,GAAG;YACT,WAAW;YACX,WAAW;YACX,SAAS,EAAE,uBAAuB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;YACzD,UAAU,EAAE,wBAAwB,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,4BAA4B,CAAC,EAAE,CAAC;SACxG,CAAC;QACF,OAAO,OAAO,CAAC;IAAA,CACf,CAAC;IACF,MAAM,IAAI,GAA0B;QACnC,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACjC,MAAM,cAAc,GAAG,kBAAkB,CACxC,wBAAwB,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,4BAA4B,CAAC,EAAE,CAAC,EAC5F,QAAQ,EACR,kCAAkC,EAClC,MAAM,CACN,CAAC;YACF,MAAM,eAAe,GAAG,kBAAkB,CACzC,wBAAwB,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,4BAA4B,CAAC,EAAE,CAAC,EACxG,SAAS,EACT,uBAAuB,CAAC,OAAO,CAAC,GAAG,CAAC,EACpC,MAAM,CACN,CAAC;YACF,MAAM,CAAC,YAAY,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;YAC3F,kEAAkE;YAClE,iEAAiE;YACjE,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,YAAY,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC;QAAA,CACpD;QACD,cAAc,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACrD,6EAAgE;YAChE,qEAAqE;YACrE,kEAAkE;YAClE,IAAI,SAAkB,CAAC;YACvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;gBAC/C,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI;oBAAE,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC9E,IAAI,CAAC;oBACJ,OAAO,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC7D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,SAAS,GAAG,KAAK,CAAC;oBAClB,gEAAgE;oBAChE,gEAAgE;oBAChE,IAAI,OAAO,KAAK,CAAC;wBAAE,MAAM,KAAK,CAAC;oBAC/B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;wBAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;wBAC5D,MAAM,EAAE,gBAAgB,CACvB,OAAO,EACP,GAAG,EAAE,CAAC;4BACL,YAAY,CAAC,KAAK,CAAC,CAAC;4BACpB,MAAM,CAAC,SAAS,CAAC,CAAC;wBAAA,CAClB,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACd,CAAC;oBAAA,CACF,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YACD,MAAM,SAAS,CAAC;QAAA,CAChB;QACD,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;KACnE,CAAC;IACF,MAAM,kBAAkB,GAAG,KAAK,EAAE,KAIjC,EAAwE,EAAE,CAAC;QAC3E,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QACzC,CAAC;YACA,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;YACrC,uEAAsE;YACtE,qEAAqE;YACrE,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,EAAE,CAAC;YAClE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YAC/G,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE,CAAC;gBAC1C,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;YAAA,CACzB,CAAC;YACF,IAAI,CAAC;gBACJ,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;oBACzC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,IAAI,EAAE,wBAAwB,EAAE;iBAChC,CAAC,CAAC;gBACH,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;oBACjC,MAAM,IAAI,KAAK,CACd,CAAC,CAAC,iDAAiD,EAAE;wBACpD,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE;wBAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM;qBACvB,CAAC,CACF,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;oBAChD,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,KAAK,EAAE,QAAQ;oBACf,QAAQ,EAAE,kCAAkC;oBAC5C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;iBAC3C,CAAC,CAAC;gBACH,IAAI,SAAS,CAAC,MAAM,KAAK,WAAW;oBACnC,MAAM,IAAI,KAAK,CACd,CAAC,CAAC,+CAA+C,EAAE;wBAClD,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI;wBAC1B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE;qBAC9B,CAAC,CACF,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;oBACjD,YAAY,EAAE,SAAS,CAAC,YAAY;oBACpC,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,KAAK,EAAE,QAAQ;oBACf,QAAQ,EAAE,kCAAkC;oBAC5C,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;iBAC3C,CAAC,CAAC;gBACH,IAAI,SAAS,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBACtC,MAAM,MAAM,CAAC,SAAS;yBACpB,MAAM,CAAC;wBACP,YAAY,EAAE,SAAS,CAAC,YAAY;wBACpC,KAAK,EAAE,QAAQ;wBACf,QAAQ,EAAE,kCAAkC;qBAC5C,CAAC;yBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;oBACzB,MAAM,IAAI,KAAK,CACd,CAAC,CAAC,kDAAkD,EAAE;wBACrD,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI;wBAC1B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE;qBAC9B,CAAC,CACF,CAAC;gBACH,CAAC;gBACD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;oBAChD,YAAY,EAAE,SAAS,CAAC,YAAY;oBACpC,KAAK,EAAE,QAAQ;oBACf,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;iBAC3C,CAAC,CAAC;gBACH,IAAI,SAAS,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;oBAC/B,MAAM,MAAM,CAAC,SAAS;yBACpB,MAAM,CAAC;wBACP,YAAY,EAAE,SAAS,CAAC,YAAY;wBACpC,KAAK,EAAE,QAAQ;wBACf,QAAQ,EAAE,kCAAkC;qBAC5C,CAAC;yBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;oBACzB,MAAM,IAAI,KAAK,CACd,CAAC,CAAC,uDAAuD,EAAE;wBAC1D,MAAM,EAAE,SAAS,CAAC,MAAM;wBACxB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE;qBAC9B,CAAC,CACF,CAAC;gBACH,CAAC;gBACD,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;YACzF,CAAC;oBAAS,CAAC;gBACV,MAAM,OAAO,EAAE,CAAC;YACjB,CAAC;QACF,CAAC;IAAA,CACD,CAAC;IACF,IAAI,CAAC;QACJ,OAAO,MAAM,oBAAoB,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,oCAAoC;YAClE,IAAI;YACJ,yEAAoE;YACpE,yDAAyD;YACzD,iBAAiB,EAChB,OAAO,CAAC,iBAAiB;gBACzB,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC;oBACnB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,kDAAgD,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;gBAAA,CAC9E,CAAC;YACH,6EAA8D;YAC9D,kEAAkE;YAClE,uDAAuD;YACvD,QAAQ,EACP,OAAO,CAAC,QAAQ;gBAChB,CAAC,CAAC,MAA+B,EAAE,EAAE,CAAC;oBACrC,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;wBACnC,OAAO,CAAC,KAAK,CACZ,CAAC,CAAC,iCAAiC,EAAE;4BACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;4BACzB,OAAO,EAAE,MAAM,CAAC,gBAAgB,IAAI,EAAE;yBACtC,CAAC,CACF,CAAC;oBACH,CAAC;yBAAM,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;wBACvC,OAAO,CAAC,KAAK,CACZ,CAAC,CACA,mGAAiG,EACjG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,IAAI,gBAAgB,EAAE,CACzE,CACD,CAAC;oBACH,CAAC;gBAAA,CACD,CAAC;SACH,CAAC,CAAC;IACJ,CAAC;YAAS,CAAC;QACV,MAAM,MAAM,GAAG,OAAO,CAAC;QACvB,OAAO,GAAG,SAAS,CAAC;QACpB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACxD,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzD,CAAC;IACF,CAAC;AAAA,CACD","sourcesContent":["/**\n * Node wiring for the startup plugin bootstrap (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7).\n *\n * `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` skips everything, including the local\n * comparison. The comparison dependency reads the global and project\n * plugin-state.json stores only — read-only, and it never constructs an HTTP\n * client, so an assembled environment starts offline (G3). Network objects\n * (npm acquisition host, install host) are built lazily inside the install\n * action and closed when the bootstrap finishes. Installs go through the\n * npm acquisition path exclusively and persist the `npm:<host>` source label\n * in the global plugin state (same prepare/install/activate/upsert\n * transaction shape as the CLI install flow, implemented as a library\n * function without going through the CLI layer).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../config.ts\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { isOfflineModeEnabled } from \"../../core/package-process-runner.ts\";\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1 } from \"./bootstrap-factory-manifest.ts\";\nimport {\n\tDEFAULT_PLUGIN_STATE_FILE_V1,\n\tdefaultPluginHostFactsV1,\n\tdefaultPluginInstallStoreDirectoryV1,\n\tprojectPluginScopeRefV1,\n} from \"./default-active-bindings.ts\";\nimport { createPluginInstallerV1, DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1, type PluginInstallerV1 } from \"./installer.ts\";\nimport {\n\tcreateNodePackageInstallHostV1,\n\ttype NodePackageInstallHostV1,\n\ttype NodeZipPackageLimitsV1,\n} from \"./node-package-install-host.ts\";\nimport { createNodePluginAcquisitionHostV1, type NodePluginAcquisitionHostV1 } from \"./node-plugin-acquisition-host.ts\";\nimport {\n\ttype PluginBootstrapActionV1,\n\ttype PluginBootstrapDepsV1,\n\ttype PluginBootstrapResultV1,\n\trunPluginBootstrapV1,\n} from \"./plugin-bootstrap.ts\";\nimport { createPluginStateStoreV1, type PluginStateStoreV1 } from \"./state.ts\";\n\n/** Environment variable disabling the startup bootstrap entirely (`off`). */\nexport const AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1 = \"AGENT_FORGE_PLUGIN_BOOTSTRAP\";\n\n/** The only recognized disabling value; every other value (and absence) keeps bootstrap on. */\nconst PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1 = \"off\";\n\nexport interface NodePluginBootstrapOptionsV1 {\n\treadonly agentDir: string;\n\treadonly cwd: string;\n\t/** Defaults to the frozen factory manifest. */\n\treadonly manifest?: readonly PluginBootstrapFactoryEntryV1[];\n\t/** Bare http(s) npm registry origin; forwarded to the acquisition host. */\n\treadonly npmRegistry?: string;\n\t/** npm registry bearer token; forwarded to the acquisition host. */\n\treadonly npmToken?: string;\n\treadonly limits?: NodeZipPackageLimitsV1;\n\t/** Deterministic fetch replacement for tests. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly signal?: AbortSignal;\n\t/** Full dependency override for deterministic tests; the env switch still applies. */\n\treadonly deps?: PluginBootstrapDepsV1;\n\t/** Overrides the first-run progress line (stderr) for tests and hosts. */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Overrides the per-plugin progress renderer (stderr) for tests and hosts.\n\t * The default prints one line per installed/aligned/failed entry and stays\n\t * silent for satisfied entries.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}\n\nexport type NodePluginBootstrapResultV1 = PluginBootstrapResultV1 & {\n\t/**\n\t * Present when a posture switch short-circuited the run before any local\n\t * comparison: the wiring-level env off switch, or the offline posture\n\t * (设计 §4.4 offline 姿态门, 2026-10-03 — offline installs cannot succeed\n\t * and would only fail slowly, so the run is skipped immediately).\n\t */\n\treadonly skipped?: \"disabled\" | \"offline\";\n};\n\n/** Install-scoped boundaries; created lazily by the first install action. */\ninterface InstallSessionV1 {\n\treadonly acquisition: NodePluginAcquisitionHostV1;\n\treadonly installHost: NodePackageInstallHostV1;\n\treadonly installer: PluginInstallerV1;\n\treadonly stateStore: PluginStateStoreV1;\n}\n\nfunction readActiveVersions(\n\tstore: PluginStateStoreV1,\n\tscope: \"global\" | \"project\",\n\tscopeRef: string,\n\tsignal: AbortSignal | undefined,\n): Promise<ReadonlyMap<string, string>> {\n\treturn (async () => {\n\t\tconst result = await store.read({ ...(signal === undefined ? {} : { signal }) });\n\t\tif (result.status !== \"ok\" && result.status !== \"missing\")\n\t\t\tthrow new Error(\n\t\t\t\tt(\"plugin state read failed ({detail}) for the {scope} scope\", {\n\t\t\t\t\tdetail: result.diagnostics[0]?.code ?? result.status,\n\t\t\t\t\tscope,\n\t\t\t\t}),\n\t\t\t);\n\t\tconst versions = new Map<string, string>();\n\t\tfor (const record of result.snapshot.records) {\n\t\t\tif (record.state.scope !== scope || record.state.scopeRef !== scopeRef) continue;\n\t\t\t// Enabled is deliberately not filtered: a disabled plugin still owns\n\t\t\t// its active installation record, and bootstrap never touches it (G5).\n\t\t\tif (record.state.lifecycle !== \"active\") continue;\n\t\t\tversions.set(record.pluginId, record.pluginVersion);\n\t\t}\n\t\treturn versions;\n\t})();\n}\n\n/**\n * Run the startup bootstrap for one agent directory. The function resolves\n * with a structured result and never throws for per-plugin failures; only a\n * wiring-level construction error propagates to the caller (main.ts guards\n * startup with its own catch).\n */\nexport async function runNodePluginBootstrapV1(\n\toptions: NodePluginBootstrapOptionsV1,\n): Promise<NodePluginBootstrapResultV1> {\n\tif (process.env[AGENT_FORGE_PLUGIN_BOOTSTRAP_ENV_V1]?.trim() === PLUGIN_BOOTSTRAP_DISABLED_VALUE_V1) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([]),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"disabled\",\n\t\t});\n\t}\n\tif (isOfflineModeEnabled()) {\n\t\treturn Object.freeze({\n\t\t\tversion: 1,\n\t\t\tstatus: \"succeeded\",\n\t\t\tactions: Object.freeze([]),\n\t\t\tdiagnostics: Object.freeze([\n\t\t\t\t{\n\t\t\t\t\tcode: \"bootstrap_skipped_offline\",\n\t\t\t\t\tmessage: t(\n\t\t\t\t\t\t\"Offline posture (AGENT_FORGE_OFFLINE) skips the startup plugin bootstrap; run `agent-forge plugin install <package>` explicitly to install plugins.\",\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t] as const),\n\t\t\tdurationMs: 0,\n\t\t\tskipped: \"offline\",\n\t\t});\n\t}\n\tif (options.deps !== undefined) {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps: options.deps,\n\t\t\t...(options.onPendingInstalls === undefined ? {} : { onPendingInstalls: options.onPendingInstalls }),\n\t\t\t...(options.onAction === undefined ? {} : { onAction: options.onAction }),\n\t\t});\n\t}\n\tlet session: InstallSessionV1 | undefined;\n\tconst ensureSession = async (): Promise<InstallSessionV1> => {\n\t\tif (session !== undefined) return session;\n\t\tconst acquisition = createNodePluginAcquisitionHostV1({\n\t\t\t...(options.npmRegistry === undefined ? {} : { npmRegistry: options.npmRegistry }),\n\t\t\t...(options.npmToken === undefined ? {} : { npmToken: options.npmToken }),\n\t\t\t...(options.fetch === undefined ? {} : { fetch: options.fetch }),\n\t\t\t...(options.limits === undefined ? {} : { limits: options.limits }),\n\t\t});\n\t\tconst installHost = await createNodePackageInstallHostV1({\n\t\t\topenArtifact: (input) => acquisition.openArtifact(input),\n\t\t\tinstallationDirectory: defaultPluginInstallStoreDirectoryV1(options.agentDir),\n\t\t\tpersistence: \"persistent\",\n\t\t\tsupportedScopes: [\"global\", \"project\"],\n\t\t\t...(options.limits === undefined ? {} : { ...options.limits }),\n\t\t});\n\t\tsession = {\n\t\t\tacquisition,\n\t\t\tinstallHost,\n\t\t\tinstaller: createPluginInstallerV1({ host: installHost }),\n\t\t\tstateStore: createPluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t};\n\t\treturn session;\n\t};\n\tconst deps: PluginBootstrapDepsV1 = {\n\t\tlistActive: async ({ signal }) => {\n\t\t\tconst globalVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.agentDir, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"global\",\n\t\t\t\tDEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst projectVersions = readActiveVersions(\n\t\t\t\tcreatePluginStateStoreV1({ filePath: join(options.cwd, CONFIG_DIR_NAME, DEFAULT_PLUGIN_STATE_FILE_V1) }),\n\t\t\t\t\"project\",\n\t\t\t\tprojectPluginScopeRefV1(options.cwd),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tconst [globalResult, projectResult] = await Promise.all([globalVersions, projectVersions]);\n\t\t\t// Project precedence mirrors active-binding resolution: a project\n\t\t\t// installation shadows the same plugin id from the global scope.\n\t\t\treturn new Map([...globalResult, ...projectResult]);\n\t\t},\n\t\tinstallFromNpm: async ({ npmName, range, signal }) => {\n\t\t\t// Download retry (设计 §4.4 下载重试, 2026-10-04): transient registry\n\t\t\t// failures retried with backoff at this wiring layer so the decision\n\t\t\t// loop stays pure. Abort propagates immediately between attempts.\n\t\t\tlet lastError: unknown;\n\t\t\tfor (let attempt = 1; attempt <= 3; attempt++) {\n\t\t\t\tif (signal?.aborted === true) throw lastError ?? new Error(\"install aborted\");\n\t\t\t\ttry {\n\t\t\t\t\treturn await installFromNpmOnce({ npmName, range, signal });\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlastError = error;\n\t\t\t\t\t// Abort during the attempt surfaces as the attempt's own error;\n\t\t\t\t\t// the loop-top check and the backoff listener cover the pauses.\n\t\t\t\t\tif (attempt === 3) throw error;\n\t\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tconst timer = setTimeout(resolve, 400 * 2 ** (attempt - 1));\n\t\t\t\t\t\tsignal?.addEventListener(\n\t\t\t\t\t\t\t\"abort\",\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t\t\t\treject(lastError);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ once: true },\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow lastError;\n\t\t},\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t};\n\tconst installFromNpmOnce = async (input: {\n\t\treadonly npmName: string;\n\t\treadonly range?: string;\n\t\treadonly signal?: AbortSignal;\n\t}): Promise<{ readonly pluginVersion: string; readonly source: string }> => {\n\t\tconst { npmName, range, signal } = input;\n\t\t{\n\t\t\tconst active = await ensureSession();\n\t\t\t// npm refs only (§0.7): scoped or plain names with the shared minimal\n\t\t\t// range subset; no github/gitee/url/local ref can be expressed here.\n\t\t\tconst ref = range === undefined ? npmName : `${npmName}@${range}`;\n\t\t\tconst acquired = await active.acquisition.resolvePackage({ ref, ...(signal === undefined ? {} : { signal }) });\n\t\t\tlet released = false;\n\t\t\tconst release = async (): Promise<void> => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tawait acquired.release();\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tconst verified = active.installer.prepare({\n\t\t\t\t\tmanifest: acquired.manifest,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\thost: defaultPluginHostFactsV1(),\n\t\t\t\t});\n\t\t\t\tif (verified.status !== \"verified\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"installer prepare rejected {pluginId}: {reason}\", {\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t\treason: verified.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst installed = await active.installer.install({\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\tartifact: acquired.artifact,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (installed.status !== \"succeeded\")\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin install failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: installed.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tconst activated = await active.installer.activate({\n\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\trecord: verified.record,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (activated.status !== \"succeeded\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: installed.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin activation failed ({code}) for {pluginId}\", {\n\t\t\t\t\t\t\tcode: activated.error.code,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst persisted = await active.stateStore.upsert({\n\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\tscope: \"global\",\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tsource: acquired.source,\n\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t});\n\t\t\t\tif (persisted.status !== \"ok\") {\n\t\t\t\t\tawait active.installer\n\t\t\t\t\t\t.remove({\n\t\t\t\t\t\t\tinstallation: activated.installation,\n\t\t\t\t\t\t\tscope: \"global\",\n\t\t\t\t\t\t\tscopeRef: DEFAULT_GLOBAL_PLUGIN_SCOPE_REF_V1,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => undefined);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tt(\"plugin state persist failed ({status}) for {pluginId}\", {\n\t\t\t\t\t\t\tstatus: persisted.status,\n\t\t\t\t\t\t\tpluginId: acquired.manifest.id,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { pluginVersion: activated.installation.pluginVersion, source: acquired.source };\n\t\t\t} finally {\n\t\t\t\tawait release();\n\t\t\t}\n\t\t}\n\t};\n\ttry {\n\t\treturn await runPluginBootstrapV1({\n\t\t\tmanifest: options.manifest ?? BOOTSTRAP_FACTORY_PLUGIN_MANIFEST_V1,\n\t\t\tdeps,\n\t\t\t// First-run progress line (设计 §4.4, 2026-10-03): a fresh install is\n\t\t\t// otherwise silent for the whole network install window.\n\t\t\tonPendingInstalls:\n\t\t\t\toptions.onPendingInstalls ??\n\t\t\t\t((count: number) => {\n\t\t\t\t\tconsole.error(t(\"First run: installing {count} factory plugins…\", { count }));\n\t\t\t\t}),\n\t\t\t// Per-plugin progress (设计 §4.4 逐插件进度, 2026-10-04): one stderr\n\t\t\t// line per installed/aligned/failed entry; satisfied entries stay\n\t\t\t// silent so an all-green startup prints nothing extra.\n\t\t\tonAction:\n\t\t\t\toptions.onAction ??\n\t\t\t\t((action: PluginBootstrapActionV1) => {\n\t\t\t\t\tif (action.status === \"installed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\"{pluginId}: installed {version}\", {\n\t\t\t\t\t\t\t\tpluginId: action.pluginId,\n\t\t\t\t\t\t\t\tversion: action.installedVersion ?? \"\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (action.status === \"failed\") {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\tt(\n\t\t\t\t\t\t\t\t\"{pluginId}: install failed ({code}) — startup continues; the next startup retries automatically\",\n\t\t\t\t\t\t\t\t{ pluginId: action.pluginId, code: action.errorCode ?? \"install_failed\" },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t});\n\t} finally {\n\t\tconst active = session;\n\t\tsession = undefined;\n\t\tif (active !== undefined) {\n\t\t\tawait active.installHost.close().catch(() => undefined);\n\t\t\tawait active.acquisition.close().catch(() => undefined);\n\t\t}\n\t}\n}\n"]}
@@ -2,17 +2,22 @@
2
2
  * Startup plugin bootstrap orchestrator (design
3
3
  * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop
4
4
  * over the frozen factory manifest: every entry is compared against the
5
- * locally resolved active installations and only missing plugins are handed
6
- * to the npm install dependency — bootstrap never acquires through any other
5
+ * locally resolved active installations; missing plugins and factory entries
6
+ * whose active version no longer satisfies the factory range are handed to
7
+ * the npm install dependency — bootstrap never acquires through any other
7
8
  * source.
8
9
  *
9
- * Coverage rules (G5): an existing active installation is never replaced. A
10
- * satisfied range is skipped silently (zero acquisition calls, G3); an
11
- * unsatisfied one produces a diagnostic with a manual install command and no
12
- * automatic replacement. Failure semantics (G4): one plugin's install
13
- * failure is recorded and the loop continues; the run itself never throws.
14
- * All effects live behind the injected dependencies, so the loop is fully
15
- * deterministic under mocks.
10
+ * Coverage rules (G5, with the 2026-10-04 install-and-use exception): a
11
+ * satisfied range is skipped silently (zero acquisition calls, G3); a factory
12
+ * entry whose range is unsatisfied is automatically realigned by installing
13
+ * the factory range — factory plugins are version-locked to the running
14
+ * framework, so an unsatisfied range is a broken compatibility state, not a
15
+ * user preference to protect. User-installed third-party plugins are not in
16
+ * the factory manifest and stay untouched. Failure semantics (G4): one
17
+ * plugin's install failure is recorded and the loop continues; the run itself
18
+ * never throws, and a failed entry self-heals on the next startup because it
19
+ * stays unsatisfied. All effects live behind the injected dependencies, so
20
+ * the loop is fully deterministic under mocks.
16
21
  */
17
22
  import type { PluginBootstrapFactoryEntryV1 } from "./bootstrap-factory-manifest.ts";
18
23
  export declare const PLUGIN_BOOTSTRAP_VERSION_V1: 1;
@@ -37,8 +42,8 @@ export interface PluginBootstrapDepsV1 {
37
42
  /** Cooperative cancellation; checked before each manifest entry. */
38
43
  readonly signal?: AbortSignal;
39
44
  }
40
- export type PluginBootstrapActionStatusV1 = "skipped" | "diagnosed" | "installed" | "failed";
41
- export type PluginBootstrapActionReasonV1 = "satisfies_range" | "range_not_satisfied" | "installed" | "install_failed";
45
+ export type PluginBootstrapActionStatusV1 = "skipped" | "installed" | "failed";
46
+ export type PluginBootstrapActionReasonV1 = "satisfies_range" | "installed" | "range_aligned" | "install_failed" | "align_failed";
42
47
  /** One per-entry outcome; the version fields carry what each status observed. */
43
48
  export interface PluginBootstrapActionV1 {
44
49
  readonly pluginId: string;
@@ -46,7 +51,7 @@ export interface PluginBootstrapActionV1 {
46
51
  readonly reason: PluginBootstrapActionReasonV1;
47
52
  readonly npmName: string;
48
53
  readonly range?: string;
49
- /** Active version that decided a skipped/diagnosed outcome. */
54
+ /** Active version that decided a skipped outcome. */
50
55
  readonly activeVersion?: string;
51
56
  /** Version reported by the install action. */
52
57
  readonly installedVersion?: string;
@@ -55,22 +60,22 @@ export interface PluginBootstrapActionV1 {
55
60
  /** Acquisition or install failure code for failed actions. */
56
61
  readonly errorCode?: string;
57
62
  }
58
- export type PluginBootstrapDiagnosticCodeV1 = "range_not_satisfied" | "install_failed" | "list_active_failed" | "cancelled" | "bootstrap_failed" | "bootstrap_skipped_offline";
63
+ export type PluginBootstrapDiagnosticCodeV1 = "install_failed" | "list_active_failed" | "cancelled" | "bootstrap_failed" | "bootstrap_skipped_offline";
59
64
  export interface PluginBootstrapDiagnosticV1 {
60
65
  readonly code: PluginBootstrapDiagnosticCodeV1;
61
66
  readonly message: string;
62
67
  readonly pluginId?: string;
63
68
  }
64
- export type PluginBootstrapStatusV1 = "succeeded" | "degraded" | "failed";
69
+ export type PluginBootstrapStatusV1 = "succeeded" | "failed";
65
70
  export interface PluginBootstrapResultV1 {
66
71
  readonly version: typeof PLUGIN_BOOTSTRAP_VERSION_V1;
67
- /** Aggregated outcome: failed > degraded (diagnosed entries) > succeeded. */
72
+ /** Aggregated outcome: failed (any failed entry) > succeeded. */
68
73
  readonly status: PluginBootstrapStatusV1;
69
74
  readonly actions: readonly PluginBootstrapActionV1[];
70
75
  readonly diagnostics: readonly PluginBootstrapDiagnosticV1[];
71
76
  readonly durationMs: number;
72
77
  }
73
- /** Executable repair command for diagnostics (G4/G5 remediation hint). */
78
+ /** Executable repair command for diagnostics (G4 remediation hint). */
74
79
  export declare function pluginBootstrapInstallCommandV1(entry: {
75
80
  readonly npmName: string;
76
81
  readonly range?: string;
@@ -91,5 +96,12 @@ export declare function runPluginBootstrapV1(input: {
91
96
  * itself stays free of console I/O.
92
97
  */
93
98
  readonly onPendingInstalls?: (count: number) => void;
99
+ /**
100
+ * Fired after every per-entry action (设计 §4.4 逐插件进度, 2026-10-04):
101
+ * the host renders one line per install/align/failure so the waiting user
102
+ * sees live state; skipped entries stay silent at the host's discretion.
103
+ * Injected effect, the loop itself stays free of console I/O.
104
+ */
105
+ readonly onAction?: (action: PluginBootstrapActionV1) => void;
94
106
  }): Promise<PluginBootstrapResultV1>;
95
107
  //# sourceMappingURL=plugin-bootstrap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-bootstrap.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAIrF,eAAO,MAAM,2BAA2B,GAAa,CAAC;AAEtD,gFAAgF;AAChF,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3C,qFAAqF;AACrF,MAAM,MAAM,+BAA+B,GAAG,CAAC,KAAK,EAAE;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B,KAAK,OAAO,CAAC;IAAE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,UAAU,EAAE,2BAA2B,CAAC;IACjD,QAAQ,CAAC,cAAc,EAAE,+BAA+B,CAAC;IACzD,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,MAAM,6BAA6B,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE7F,MAAM,MAAM,6BAA6B,GAAG,iBAAiB,GAAG,qBAAqB,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAEvH,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,8CAA8C;IAC9C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,+BAA+B,GACxC,qBAAqB,GACrB,gBAAgB,GAChB,oBAAoB,GACpB,WAAW,GACX,kBAAkB,GAClB,2BAA2B,CAAC;AAE/B,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE1E,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,2BAA2B,CAAC;IACrD,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACrD,QAAQ,CAAC,WAAW,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC7D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAWD,0EAA0E;AAC1E,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEpH;AAwBD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,QAAQ,EAAE,SAAS,6BAA6B,EAAE,CAAC;IAC5D,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAgGnC","sourcesContent":["/**\n * Startup plugin bootstrap orchestrator (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop\n * over the frozen factory manifest: every entry is compared against the\n * locally resolved active installations and only missing plugins are handed\n * to the npm install dependency — bootstrap never acquires through any other\n * source.\n *\n * Coverage rules (G5): an existing active installation is never replaced. A\n * satisfied range is skipped silently (zero acquisition calls, G3); an\n * unsatisfied one produces a diagnostic with a manual install command and no\n * automatic replacement. Failure semantics (G4): one plugin's install\n * failure is recorded and the loop continues; the run itself never throws.\n * All effects live behind the injected dependencies, so the loop is fully\n * deterministic under mocks.\n */\n\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { selectNpmPackageVersionV1 } from \"./node-npm-registry-source.ts\";\nimport { PluginAcquisitionErrorV1 } from \"./plugin-acquisition.ts\";\n\nexport const PLUGIN_BOOTSTRAP_VERSION_V1 = 1 as const;\n\n/** Read-only local lookup of active installation versions (never networked). */\nexport type PluginBootstrapListActiveV1 = (input: {\n\treadonly signal?: AbortSignal;\n}) => Promise<ReadonlyMap<string, string>>;\n\n/** npm-only install action; resolves with the installed version and source label. */\nexport type PluginBootstrapInstallFromNpmV1 = (input: {\n\treadonly npmName: string;\n\treadonly range?: string;\n\treadonly signal?: AbortSignal;\n}) => Promise<{ readonly pluginVersion: string; readonly source: string }>;\n\nexport interface PluginBootstrapDepsV1 {\n\treadonly listActive: PluginBootstrapListActiveV1;\n\treadonly installFromNpm: PluginBootstrapInstallFromNpmV1;\n\t/** Deterministic clock for the observed duration; defaults to Date.now. */\n\treadonly now?: () => number;\n\t/** Cooperative cancellation; checked before each manifest entry. */\n\treadonly signal?: AbortSignal;\n}\n\nexport type PluginBootstrapActionStatusV1 = \"skipped\" | \"diagnosed\" | \"installed\" | \"failed\";\n\nexport type PluginBootstrapActionReasonV1 = \"satisfies_range\" | \"range_not_satisfied\" | \"installed\" | \"install_failed\";\n\n/** One per-entry outcome; the version fields carry what each status observed. */\nexport interface PluginBootstrapActionV1 {\n\treadonly pluginId: string;\n\treadonly status: PluginBootstrapActionStatusV1;\n\treadonly reason: PluginBootstrapActionReasonV1;\n\treadonly npmName: string;\n\treadonly range?: string;\n\t/** Active version that decided a skipped/diagnosed outcome. */\n\treadonly activeVersion?: string;\n\t/** Version reported by the install action. */\n\treadonly installedVersion?: string;\n\t/** npm source label reported by the install action. */\n\treadonly source?: string;\n\t/** Acquisition or install failure code for failed actions. */\n\treadonly errorCode?: string;\n}\n\nexport type PluginBootstrapDiagnosticCodeV1 =\n\t| \"range_not_satisfied\"\n\t| \"install_failed\"\n\t| \"list_active_failed\"\n\t| \"cancelled\"\n\t| \"bootstrap_failed\"\n\t| \"bootstrap_skipped_offline\";\n\nexport interface PluginBootstrapDiagnosticV1 {\n\treadonly code: PluginBootstrapDiagnosticCodeV1;\n\treadonly message: string;\n\treadonly pluginId?: string;\n}\n\nexport type PluginBootstrapStatusV1 = \"succeeded\" | \"degraded\" | \"failed\";\n\nexport interface PluginBootstrapResultV1 {\n\treadonly version: typeof PLUGIN_BOOTSTRAP_VERSION_V1;\n\t/** Aggregated outcome: failed > degraded (diagnosed entries) > succeeded. */\n\treadonly status: PluginBootstrapStatusV1;\n\treadonly actions: readonly PluginBootstrapActionV1[];\n\treadonly diagnostics: readonly PluginBootstrapDiagnosticV1[];\n\treadonly durationMs: number;\n}\n\n/**\n * A version satisfies a factory range under the same selection semantics npm\n * resolution uses: it is the version that would be picked if it were the only\n * candidate. Keeps local comparison and registry resolution consistent.\n */\nfunction satisfiesRangeV1(version: string, range: string | undefined): boolean {\n\treturn selectNpmPackageVersionV1([version], range) === version;\n}\n\n/** Executable repair command for diagnostics (G4/G5 remediation hint). */\nexport function pluginBootstrapInstallCommandV1(entry: { readonly npmName: string; readonly range?: string }): string {\n\treturn `agent-forge plugin install ${entry.npmName}@${entry.range ?? \"latest\"}`;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction acquireErrorCode(error: unknown): string {\n\treturn error instanceof PluginAcquisitionErrorV1 ? error.code : \"install_failed\";\n}\n\nfunction actionOf(\n\tentry: PluginBootstrapFactoryEntryV1,\n\tstatus: PluginBootstrapActionStatusV1,\n\treason: PluginBootstrapActionReasonV1,\n): PluginBootstrapActionV1 {\n\treturn Object.freeze({\n\t\tpluginId: entry.pluginId,\n\t\tstatus,\n\t\treason,\n\t\tnpmName: entry.npmName,\n\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t});\n}\n\n/**\n * Run the bootstrap decision loop. An empty manifest short-circuits before\n * any dependency is touched, so the factory-empty S1-c2 state performs zero\n * reads on real startups.\n */\nexport async function runPluginBootstrapV1(input: {\n\treadonly manifest: readonly PluginBootstrapFactoryEntryV1[];\n\treadonly deps: PluginBootstrapDepsV1;\n\t/**\n\t * Fired once after the local active-state read when at least one factory\n\t * entry has no active installation — the host's first-run progress line\n\t * hook (设计 §4.4 首装进度行, 2026-10-03): a fresh install is otherwise\n\t * silent for the whole network install window. Injected effect, the loop\n\t * itself stays free of console I/O.\n\t */\n\treadonly onPendingInstalls?: (count: number) => void;\n}): Promise<PluginBootstrapResultV1> {\n\tconst now = input.deps.now ?? Date.now;\n\tconst startedAt = now();\n\tconst finish = (\n\t\tstatus: PluginBootstrapStatusV1,\n\t\tactions: readonly PluginBootstrapActionV1[],\n\t\tdiagnostics: readonly PluginBootstrapDiagnosticV1[],\n\t): PluginBootstrapResultV1 =>\n\t\tObject.freeze({\n\t\t\tversion: PLUGIN_BOOTSTRAP_VERSION_V1,\n\t\t\tstatus,\n\t\t\tactions: Object.freeze([...actions]),\n\t\t\tdiagnostics: Object.freeze([...diagnostics]),\n\t\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\t});\n\tif (input.manifest.length === 0) return finish(\"succeeded\", [], []);\n\tconst signal = input.deps.signal;\n\tlet active: ReadonlyMap<string, string>;\n\ttry {\n\t\tactive = await input.deps.listActive({ ...(signal === undefined ? {} : { signal }) });\n\t} catch (error) {\n\t\treturn finish(\n\t\t\t\"failed\",\n\t\t\t[],\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcode: \"list_active_failed\",\n\t\t\t\t\tmessage: `Active plugin state could not be read; bootstrap installed nothing: ${errorMessage(error)}`,\n\t\t\t\t},\n\t\t\t],\n\t\t);\n\t}\n\tconst actions: PluginBootstrapActionV1[] = [];\n\tconst diagnostics: PluginBootstrapDiagnosticV1[] = [];\n\tif (input.onPendingInstalls !== undefined) {\n\t\tconst pending = input.manifest.filter((entry) => !active.has(entry.pluginId)).length;\n\t\tif (pending > 0) input.onPendingInstalls(pending);\n\t}\n\tfor (const entry of input.manifest) {\n\t\tif (signal?.aborted === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"cancelled\",\n\t\t\t\tmessage: \"Plugin bootstrap was cancelled before all factory entries were processed\",\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\t\tconst activeVersion = active.get(entry.pluginId);\n\t\tif (activeVersion !== undefined) {\n\t\t\tif (satisfiesRangeV1(activeVersion, entry.range)) {\n\t\t\t\tactions.push(Object.freeze({ ...actionOf(entry, \"skipped\", \"satisfies_range\"), activeVersion }));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tactions.push(Object.freeze({ ...actionOf(entry, \"diagnosed\", \"range_not_satisfied\"), activeVersion }));\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"range_not_satisfied\",\n\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\tmessage:\n\t\t\t\t\t`Active version ${activeVersion} of ${entry.pluginId} does not satisfy the factory range ` +\n\t\t\t\t\t`${entry.range ?? \"latest\"}; bootstrap never replaces active installations. ` +\n\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to install a matching version, ` +\n\t\t\t\t\t`or \\`agent-forge plugin update --all\\` to upgrade every outdated plugin at once.`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst installed = await input.deps.installFromNpm({\n\t\t\t\tnpmName: entry.npmName,\n\t\t\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t});\n\t\t\tactions.push(\n\t\t\t\tObject.freeze({\n\t\t\t\t\t...actionOf(entry, \"installed\", \"installed\"),\n\t\t\t\t\tinstalledVersion: installed.pluginVersion,\n\t\t\t\t\tsource: installed.source,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst errorCode = acquireErrorCode(error);\n\t\t\tactions.push(Object.freeze({ ...actionOf(entry, \"failed\", \"install_failed\"), errorCode }));\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"install_failed\",\n\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\tmessage:\n\t\t\t\t\t`Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t`Startup continues without it; its capabilities stay unavailable until installed. ` +\n\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to install it manually.`,\n\t\t\t});\n\t\t}\n\t}\n\tconst status: PluginBootstrapStatusV1 = actions.some((action) => action.status === \"failed\")\n\t\t? \"failed\"\n\t\t: actions.some((action) => action.status === \"diagnosed\")\n\t\t\t? \"degraded\"\n\t\t\t: \"succeeded\";\n\treturn finish(status, actions, diagnostics);\n}\n"]}
1
+ {"version":3,"file":"plugin-bootstrap.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Startup plugin bootstrap orchestrator (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop\n * over the frozen factory manifest: every entry is compared against the\n * locally resolved active installations; missing plugins and factory entries\n * whose active version no longer satisfies the factory range are handed to\n * the npm install dependency — bootstrap never acquires through any other\n * source.\n *\n * Coverage rules (G5, with the 2026-10-04 install-and-use exception): a\n * satisfied range is skipped silently (zero acquisition calls, G3); a factory\n * entry whose range is unsatisfied is automatically realigned by installing\n * the factory range — factory plugins are version-locked to the running\n * framework, so an unsatisfied range is a broken compatibility state, not a\n * user preference to protect. User-installed third-party plugins are not in\n * the factory manifest and stay untouched. Failure semantics (G4): one\n * plugin's install failure is recorded and the loop continues; the run itself\n * never throws, and a failed entry self-heals on the next startup because it\n * stays unsatisfied. All effects live behind the injected dependencies, so\n * the loop is fully deterministic under mocks.\n */\n\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { selectNpmPackageVersionV1 } from \"./node-npm-registry-source.ts\";\nimport { PluginAcquisitionErrorV1 } from \"./plugin-acquisition.ts\";\n\nexport const PLUGIN_BOOTSTRAP_VERSION_V1 = 1 as const;\n\n/** Read-only local lookup of active installation versions (never networked). */\nexport type PluginBootstrapListActiveV1 = (input: {\n\treadonly signal?: AbortSignal;\n}) => Promise<ReadonlyMap<string, string>>;\n\n/** npm-only install action; resolves with the installed version and source label. */\nexport type PluginBootstrapInstallFromNpmV1 = (input: {\n\treadonly npmName: string;\n\treadonly range?: string;\n\treadonly signal?: AbortSignal;\n}) => Promise<{ readonly pluginVersion: string; readonly source: string }>;\n\nexport interface PluginBootstrapDepsV1 {\n\treadonly listActive: PluginBootstrapListActiveV1;\n\treadonly installFromNpm: PluginBootstrapInstallFromNpmV1;\n\t/** Deterministic clock for the observed duration; defaults to Date.now. */\n\treadonly now?: () => number;\n\t/** Cooperative cancellation; checked before each manifest entry. */\n\treadonly signal?: AbortSignal;\n}\n\nexport type PluginBootstrapActionStatusV1 = \"skipped\" | \"installed\" | \"failed\";\n\nexport type PluginBootstrapActionReasonV1 =\n\t| \"satisfies_range\"\n\t| \"installed\"\n\t| \"range_aligned\"\n\t| \"install_failed\"\n\t| \"align_failed\";\n\n/** One per-entry outcome; the version fields carry what each status observed. */\nexport interface PluginBootstrapActionV1 {\n\treadonly pluginId: string;\n\treadonly status: PluginBootstrapActionStatusV1;\n\treadonly reason: PluginBootstrapActionReasonV1;\n\treadonly npmName: string;\n\treadonly range?: string;\n\t/** Active version that decided a skipped outcome. */\n\treadonly activeVersion?: string;\n\t/** Version reported by the install action. */\n\treadonly installedVersion?: string;\n\t/** npm source label reported by the install action. */\n\treadonly source?: string;\n\t/** Acquisition or install failure code for failed actions. */\n\treadonly errorCode?: string;\n}\n\nexport type PluginBootstrapDiagnosticCodeV1 =\n\t| \"install_failed\"\n\t| \"list_active_failed\"\n\t| \"cancelled\"\n\t| \"bootstrap_failed\"\n\t| \"bootstrap_skipped_offline\";\n\nexport interface PluginBootstrapDiagnosticV1 {\n\treadonly code: PluginBootstrapDiagnosticCodeV1;\n\treadonly message: string;\n\treadonly pluginId?: string;\n}\n\nexport type PluginBootstrapStatusV1 = \"succeeded\" | \"failed\";\n\nexport interface PluginBootstrapResultV1 {\n\treadonly version: typeof PLUGIN_BOOTSTRAP_VERSION_V1;\n\t/** Aggregated outcome: failed (any failed entry) > succeeded. */\n\treadonly status: PluginBootstrapStatusV1;\n\treadonly actions: readonly PluginBootstrapActionV1[];\n\treadonly diagnostics: readonly PluginBootstrapDiagnosticV1[];\n\treadonly durationMs: number;\n}\n\n/**\n * A version satisfies a factory range under the same selection semantics npm\n * resolution uses: it is the version that would be picked if it were the only\n * candidate. Keeps local comparison and registry resolution consistent.\n */\nfunction satisfiesRangeV1(version: string, range: string | undefined): boolean {\n\treturn selectNpmPackageVersionV1([version], range) === version;\n}\n\n/** Executable repair command for diagnostics (G4 remediation hint). */\nexport function pluginBootstrapInstallCommandV1(entry: { readonly npmName: string; readonly range?: string }): string {\n\treturn `agent-forge plugin install ${entry.npmName}@${entry.range ?? \"latest\"}`;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction acquireErrorCode(error: unknown): string {\n\treturn error instanceof PluginAcquisitionErrorV1 ? error.code : \"install_failed\";\n}\n\nfunction actionOf(\n\tentry: PluginBootstrapFactoryEntryV1,\n\tstatus: PluginBootstrapActionStatusV1,\n\treason: PluginBootstrapActionReasonV1,\n): PluginBootstrapActionV1 {\n\treturn Object.freeze({\n\t\tpluginId: entry.pluginId,\n\t\tstatus,\n\t\treason,\n\t\tnpmName: entry.npmName,\n\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t});\n}\n\n/**\n * Run the bootstrap decision loop. An empty manifest short-circuits before\n * any dependency is touched, so the factory-empty S1-c2 state performs zero\n * reads on real startups.\n */\nexport async function runPluginBootstrapV1(input: {\n\treadonly manifest: readonly PluginBootstrapFactoryEntryV1[];\n\treadonly deps: PluginBootstrapDepsV1;\n\t/**\n\t * Fired once after the local active-state read when at least one factory\n\t * entry has no active installation — the host's first-run progress line\n\t * hook (设计 §4.4 首装进度行, 2026-10-03): a fresh install is otherwise\n\t * silent for the whole network install window. Injected effect, the loop\n\t * itself stays free of console I/O.\n\t */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Fired after every per-entry action (设计 §4.4 逐插件进度, 2026-10-04):\n\t * the host renders one line per install/align/failure so the waiting user\n\t * sees live state; skipped entries stay silent at the host's discretion.\n\t * Injected effect, the loop itself stays free of console I/O.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}): Promise<PluginBootstrapResultV1> {\n\tconst now = input.deps.now ?? Date.now;\n\tconst startedAt = now();\n\tconst finish = (\n\t\tstatus: PluginBootstrapStatusV1,\n\t\tactions: readonly PluginBootstrapActionV1[],\n\t\tdiagnostics: readonly PluginBootstrapDiagnosticV1[],\n\t): PluginBootstrapResultV1 =>\n\t\tObject.freeze({\n\t\t\tversion: PLUGIN_BOOTSTRAP_VERSION_V1,\n\t\t\tstatus,\n\t\t\tactions: Object.freeze([...actions]),\n\t\t\tdiagnostics: Object.freeze([...diagnostics]),\n\t\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\t});\n\tif (input.manifest.length === 0) return finish(\"succeeded\", [], []);\n\tconst signal = input.deps.signal;\n\tlet active: ReadonlyMap<string, string>;\n\ttry {\n\t\tactive = await input.deps.listActive({ ...(signal === undefined ? {} : { signal }) });\n\t} catch (error) {\n\t\treturn finish(\n\t\t\t\"failed\",\n\t\t\t[],\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcode: \"list_active_failed\",\n\t\t\t\t\tmessage: `Active plugin state could not be read; bootstrap installed nothing: ${errorMessage(error)}`,\n\t\t\t\t},\n\t\t\t],\n\t\t);\n\t}\n\tconst actions: PluginBootstrapActionV1[] = [];\n\tconst diagnostics: PluginBootstrapDiagnosticV1[] = [];\n\tconst record = (action: PluginBootstrapActionV1): void => {\n\t\tactions.push(action);\n\t\tinput.onAction?.(action);\n\t};\n\tif (input.onPendingInstalls !== undefined) {\n\t\tconst pending = input.manifest.filter((entry) => !active.has(entry.pluginId)).length;\n\t\tif (pending > 0) input.onPendingInstalls(pending);\n\t}\n\tfor (const entry of input.manifest) {\n\t\tif (signal?.aborted === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"cancelled\",\n\t\t\t\tmessage: \"Plugin bootstrap was cancelled before all factory entries were processed\",\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\t\tconst activeVersion = active.get(entry.pluginId);\n\t\tif (activeVersion !== undefined && satisfiesRangeV1(activeVersion, entry.range)) {\n\t\t\trecord(Object.freeze({ ...actionOf(entry, \"skipped\", \"satisfies_range\"), activeVersion }));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst installed = await input.deps.installFromNpm({\n\t\t\t\tnpmName: entry.npmName,\n\t\t\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t});\n\t\t\trecord(\n\t\t\t\tObject.freeze({\n\t\t\t\t\t...actionOf(entry, \"installed\", activeVersion === undefined ? \"installed\" : \"range_aligned\"),\n\t\t\t\t\tinstalledVersion: installed.pluginVersion,\n\t\t\t\t\tsource: installed.source,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst errorCode = acquireErrorCode(error);\n\t\t\tconst aligning = activeVersion !== undefined;\n\t\t\trecord(\n\t\t\t\tObject.freeze({ ...actionOf(entry, \"failed\", aligning ? \"align_failed\" : \"install_failed\"), errorCode }),\n\t\t\t);\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"install_failed\",\n\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\tmessage: aligning\n\t\t\t\t\t? `Bootstrap could not align ${entry.pluginId} (active ${activeVersion}) to the factory range ` +\n\t\t\t\t\t\t`${entry.range ?? \"latest\"} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t`Startup continues; the factory range stays unsatisfied, so the next startup retries automatically. ` +\n\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to align it now.`\n\t\t\t\t\t: `Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t`Startup continues without it; its capabilities stay unavailable until installed, ` +\n\t\t\t\t\t\t`and the next startup retries automatically. ` +\n\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to install it manually.`,\n\t\t\t});\n\t\t}\n\t}\n\tconst status: PluginBootstrapStatusV1 = actions.some((action) => action.status === \"failed\")\n\t\t? \"failed\"\n\t\t: \"succeeded\";\n\treturn finish(status, actions, diagnostics);\n}\n"]}
@@ -2,17 +2,22 @@
2
2
  * Startup plugin bootstrap orchestrator (design
3
3
  * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop
4
4
  * over the frozen factory manifest: every entry is compared against the
5
- * locally resolved active installations and only missing plugins are handed
6
- * to the npm install dependency — bootstrap never acquires through any other
5
+ * locally resolved active installations; missing plugins and factory entries
6
+ * whose active version no longer satisfies the factory range are handed to
7
+ * the npm install dependency — bootstrap never acquires through any other
7
8
  * source.
8
9
  *
9
- * Coverage rules (G5): an existing active installation is never replaced. A
10
- * satisfied range is skipped silently (zero acquisition calls, G3); an
11
- * unsatisfied one produces a diagnostic with a manual install command and no
12
- * automatic replacement. Failure semantics (G4): one plugin's install
13
- * failure is recorded and the loop continues; the run itself never throws.
14
- * All effects live behind the injected dependencies, so the loop is fully
15
- * deterministic under mocks.
10
+ * Coverage rules (G5, with the 2026-10-04 install-and-use exception): a
11
+ * satisfied range is skipped silently (zero acquisition calls, G3); a factory
12
+ * entry whose range is unsatisfied is automatically realigned by installing
13
+ * the factory range — factory plugins are version-locked to the running
14
+ * framework, so an unsatisfied range is a broken compatibility state, not a
15
+ * user preference to protect. User-installed third-party plugins are not in
16
+ * the factory manifest and stay untouched. Failure semantics (G4): one
17
+ * plugin's install failure is recorded and the loop continues; the run itself
18
+ * never throws, and a failed entry self-heals on the next startup because it
19
+ * stays unsatisfied. All effects live behind the injected dependencies, so
20
+ * the loop is fully deterministic under mocks.
16
21
  */
17
22
  import { selectNpmPackageVersionV1 } from "./node-npm-registry-source.js";
18
23
  import { PluginAcquisitionErrorV1 } from "./plugin-acquisition.js";
@@ -25,7 +30,7 @@ export const PLUGIN_BOOTSTRAP_VERSION_V1 = 1;
25
30
  function satisfiesRangeV1(version, range) {
26
31
  return selectNpmPackageVersionV1([version], range) === version;
27
32
  }
28
- /** Executable repair command for diagnostics (G4/G5 remediation hint). */
33
+ /** Executable repair command for diagnostics (G4 remediation hint). */
29
34
  export function pluginBootstrapInstallCommandV1(entry) {
30
35
  return `agent-forge plugin install ${entry.npmName}@${entry.range ?? "latest"}`;
31
36
  }
@@ -76,6 +81,10 @@ export async function runPluginBootstrapV1(input) {
76
81
  }
77
82
  const actions = [];
78
83
  const diagnostics = [];
84
+ const record = (action) => {
85
+ actions.push(action);
86
+ input.onAction?.(action);
87
+ };
79
88
  if (input.onPendingInstalls !== undefined) {
80
89
  const pending = input.manifest.filter((entry) => !active.has(entry.pluginId)).length;
81
90
  if (pending > 0)
@@ -90,20 +99,8 @@ export async function runPluginBootstrapV1(input) {
90
99
  break;
91
100
  }
92
101
  const activeVersion = active.get(entry.pluginId);
93
- if (activeVersion !== undefined) {
94
- if (satisfiesRangeV1(activeVersion, entry.range)) {
95
- actions.push(Object.freeze({ ...actionOf(entry, "skipped", "satisfies_range"), activeVersion }));
96
- continue;
97
- }
98
- actions.push(Object.freeze({ ...actionOf(entry, "diagnosed", "range_not_satisfied"), activeVersion }));
99
- diagnostics.push({
100
- code: "range_not_satisfied",
101
- pluginId: entry.pluginId,
102
- message: `Active version ${activeVersion} of ${entry.pluginId} does not satisfy the factory range ` +
103
- `${entry.range ?? "latest"}; bootstrap never replaces active installations. ` +
104
- `Run \`${pluginBootstrapInstallCommandV1(entry)}\` to install a matching version, ` +
105
- `or \`agent-forge plugin update --all\` to upgrade every outdated plugin at once.`,
106
- });
102
+ if (activeVersion !== undefined && satisfiesRangeV1(activeVersion, entry.range)) {
103
+ record(Object.freeze({ ...actionOf(entry, "skipped", "satisfies_range"), activeVersion }));
107
104
  continue;
108
105
  }
109
106
  try {
@@ -112,29 +109,34 @@ export async function runPluginBootstrapV1(input) {
112
109
  ...(entry.range === undefined ? {} : { range: entry.range }),
113
110
  ...(signal === undefined ? {} : { signal }),
114
111
  });
115
- actions.push(Object.freeze({
116
- ...actionOf(entry, "installed", "installed"),
112
+ record(Object.freeze({
113
+ ...actionOf(entry, "installed", activeVersion === undefined ? "installed" : "range_aligned"),
117
114
  installedVersion: installed.pluginVersion,
118
115
  source: installed.source,
119
116
  }));
120
117
  }
121
118
  catch (error) {
122
119
  const errorCode = acquireErrorCode(error);
123
- actions.push(Object.freeze({ ...actionOf(entry, "failed", "install_failed"), errorCode }));
120
+ const aligning = activeVersion !== undefined;
121
+ record(Object.freeze({ ...actionOf(entry, "failed", aligning ? "align_failed" : "install_failed"), errorCode }));
124
122
  diagnostics.push({
125
123
  code: "install_failed",
126
124
  pluginId: entry.pluginId,
127
- message: `Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +
128
- `Startup continues without it; its capabilities stay unavailable until installed. ` +
129
- `Run \`${pluginBootstrapInstallCommandV1(entry)}\` to install it manually.`,
125
+ message: aligning
126
+ ? `Bootstrap could not align ${entry.pluginId} (active ${activeVersion}) to the factory range ` +
127
+ `${entry.range ?? "latest"} from npm (${errorCode}: ${errorMessage(error)}). ` +
128
+ `Startup continues; the factory range stays unsatisfied, so the next startup retries automatically. ` +
129
+ `Run \`${pluginBootstrapInstallCommandV1(entry)}\` to align it now.`
130
+ : `Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +
131
+ `Startup continues without it; its capabilities stay unavailable until installed, ` +
132
+ `and the next startup retries automatically. ` +
133
+ `Run \`${pluginBootstrapInstallCommandV1(entry)}\` to install it manually.`,
130
134
  });
131
135
  }
132
136
  }
133
137
  const status = actions.some((action) => action.status === "failed")
134
138
  ? "failed"
135
- : actions.some((action) => action.status === "diagnosed")
136
- ? "degraded"
137
- : "succeeded";
139
+ : "succeeded";
138
140
  return finish(status, actions, diagnostics);
139
141
  }
140
142
  //# sourceMappingURL=plugin-bootstrap.js.map