@ai-agent-forge/agent-forge 0.86.7 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/README.md +10 -11
- package/dist/artifacts/artifact-store.d.ts.map +1 -1
- package/dist/artifacts/artifact-store.js +9 -5
- package/dist/artifacts/artifact-store.js.map +1 -1
- package/dist/bundle/.build-manifest.json +430 -413
- package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
- package/dist/bundle/chunks/chunk-HLJEVRWP.js +13 -0
- package/dist/bundle/chunks/chunk-YGHQME4V.js +1456 -0
- package/dist/bundle/chunks/image-resize-worker.js +12 -1
- package/dist/bundle/chunks/{virtual-modules-3IZ4MYSQ.js → virtual-modules-KZ5DRH7Q.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/client.js +1 -1
- package/dist/bundle/index.js +2 -2
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +231 -185
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts.map +1 -1
- package/dist/cli/auth-check.js +17 -4
- package/dist/cli/auth-check.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +15 -9
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/credential-print.d.ts.map +1 -1
- package/dist/cli/credential-print.js +14 -7
- package/dist/cli/credential-print.js.map +1 -1
- package/dist/cli/experimental/command.d.ts.map +1 -1
- package/dist/cli/experimental/command.js +6 -5
- package/dist/cli/experimental/command.js.map +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +9 -8
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/plugin-manager-controller.d.ts.map +1 -1
- package/dist/cli/plugin-manager-controller.js +2 -1
- package/dist/cli/plugin-manager-controller.js.map +1 -1
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +8 -5
- package/dist/cli/serve.js.map +1 -1
- package/dist/client/remote-session.d.ts.map +1 -1
- package/dist/client/remote-session.js +16 -9
- package/dist/client/remote-session.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-capability-contract.d.ts +0 -7
- package/dist/core/agent-capability-contract.d.ts.map +1 -1
- package/dist/core/agent-capability-contract.js +72 -68
- package/dist/core/agent-capability-contract.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +5 -4
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +6 -10
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +35 -133
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-context.d.ts.map +1 -1
- package/dist/core/agent-session-context.js +18 -13
- package/dist/core/agent-session-context.js.map +1 -1
- package/dist/core/agent-session-internal.d.ts +0 -6
- package/dist/core/agent-session-internal.d.ts.map +1 -1
- package/dist/core/agent-session-internal.js.map +1 -1
- package/dist/core/agent-session-model.d.ts.map +1 -1
- package/dist/core/agent-session-model.js +2 -1
- package/dist/core/agent-session-model.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +3 -3
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +7 -6
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-tools.d.ts.map +1 -1
- package/dist/core/agent-session-tools.js +3 -2
- package/dist/core/agent-session-tools.js.map +1 -1
- package/dist/core/agent-session.d.ts +40 -22
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +147 -67
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js +11 -5
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +9 -6
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +2 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/embedded-sdk.d.ts.map +1 -1
- package/dist/core/embedded-sdk.js +10 -6
- package/dist/core/embedded-sdk.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +9 -4
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/agent-composition.d.ts.map +1 -1
- package/dist/core/extensions/agent-composition.js +26 -19
- package/dist/core/extensions/agent-composition.js.map +1 -1
- package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
- package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
- package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-compaction-policy.js +0 -34
- package/dist/core/extensions/bootstrap-compaction-policy.js.map +1 -1
- package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
- package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
- package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
- package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
- package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-retry-policy.js +4 -3
- package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
- package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-skills.js +7 -6
- package/dist/core/extensions/bootstrap-skills.js.map +1 -1
- package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-tools.js +2 -1
- package/dist/core/extensions/bootstrap-tools.js.map +1 -1
- package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
- package/dist/core/extensions/capability-plugin.js +37 -13
- package/dist/core/extensions/capability-plugin.js.map +1 -1
- package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-events.js +17 -13
- package/dist/core/extensions/capability-runtime-events.js.map +1 -1
- package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-guards.js +16 -15
- package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
- package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-manifest.js +52 -30
- package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
- package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-validation.js +66 -65
- package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
- package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime.js +147 -127
- package/dist/core/extensions/capability-runtime.js.map +1 -1
- package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
- package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
- package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
- package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
- package/dist/core/extensions/context-strategy-binding.js +7 -4
- package/dist/core/extensions/context-strategy-binding.js.map +1 -1
- package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
- package/dist/core/extensions/lifecycle-catalog.js +290 -279
- package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
- package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
- package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
- package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
- package/dist/core/extensions/provider-failover.d.ts +7 -3
- package/dist/core/extensions/provider-failover.d.ts.map +1 -1
- package/dist/core/extensions/provider-failover.js +9 -8
- package/dist/core/extensions/provider-failover.js.map +1 -1
- package/dist/core/facade/coding-agent-facade.d.ts +6 -6
- package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-facade.js +2 -3
- package/dist/core/facade/coding-agent-facade.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/i18n/index.d.ts +14 -0
- package/dist/core/i18n/index.d.ts.map +1 -0
- package/dist/core/i18n/index.js +67 -0
- package/dist/core/i18n/index.js.map +1 -0
- package/dist/core/i18n/locales/en/example.d.ts +7 -0
- package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
- package/dist/core/i18n/locales/en/example.js +7 -0
- package/dist/core/i18n/locales/en/example.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
- package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/cli.js +229 -0
- package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
- package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/common.js +6 -0
- package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
- package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
- package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
- package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/example.js +10 -0
- package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
- package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/index.js +41 -0
- package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
- package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/interactive-mode.js +267 -0
- package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
- package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
- package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
- package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
- package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +286 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
- package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
- package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
- package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
- package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
- package/dist/core/keybindings.d.ts +15 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +18 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +5 -1
- package/dist/core/logger.js.map +1 -1
- package/dist/core/model-config.d.ts +0 -1
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +9 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +11 -7
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-install-host.d.ts.map +1 -1
- package/dist/core/package-install-host.js +4 -3
- package/dist/core/package-install-host.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +15 -10
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/package-resource-collection.d.ts.map +1 -1
- package/dist/core/package-resource-collection.js +2 -1
- package/dist/core/package-resource-collection.js.map +1 -1
- package/dist/core/package-source.d.ts.map +1 -1
- package/dist/core/package-source.js +3 -2
- package/dist/core/package-source.js.map +1 -1
- package/dist/core/provider-composer.d.ts +2 -2
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +29 -21
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +6 -2
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +15 -5
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +27 -5
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +80 -55
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +5 -2
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/session-export.d.ts.map +1 -1
- package/dist/core/session-export.js +2 -1
- package/dist/core/session-export.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +39 -29
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-storage.d.ts.map +1 -1
- package/dist/core/session-storage.js +3 -3
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/settings-manager.d.ts +20 -20
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +47 -59
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +53 -32
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +25 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +11 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +9 -4
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +4 -3
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +3 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +2 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +6 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/durable/durable-service.d.ts.map +1 -1
- package/dist/durable/durable-service.js +25 -18
- package/dist/durable/durable-service.js.map +1 -1
- package/dist/host/checkpoint-commit.d.ts.map +1 -1
- package/dist/host/checkpoint-commit.js +2 -1
- package/dist/host/checkpoint-commit.js.map +1 -1
- package/dist/host/manual-compaction.d.ts.map +1 -1
- package/dist/host/manual-compaction.js +2 -1
- package/dist/host/manual-compaction.js.map +1 -1
- package/dist/host/output-projection.d.ts +0 -13
- package/dist/host/output-projection.d.ts.map +1 -1
- package/dist/host/output-projection.js +16 -2
- package/dist/host/output-projection.js.map +1 -1
- package/dist/host/summary-retry.d.ts.map +1 -1
- package/dist/host/summary-retry.js +3 -2
- package/dist/host/summary-retry.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +97 -60
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/agents-view.js +18 -15
- package/dist/modes/interactive/components/agents-view.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +6 -5
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +12 -7
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +2 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +6 -5
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +18 -15
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +2 -1
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.js +5 -4
- package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
- package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-input.js +2 -1
- package/dist/modes/interactive/components/dialog-input.js.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.js +4 -3
- package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +11 -10
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -2
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -10
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +3 -2
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +12 -11
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
- package/dist/modes/interactive/components/mermaid.js +6 -2
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +28 -16
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +10 -9
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
- package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
- package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
- package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
- package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +43 -31
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -6
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +115 -120
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.js +5 -4
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +3 -2
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +14 -5
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +2 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +11 -4
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +8 -3
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-list.js +7 -6
- package/dist/modes/interactive/components/tree-list.js.map +1 -1
- package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-render.js +28 -23
- package/dist/modes/interactive/components/tree-render.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +9 -7
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +5 -4
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/workflow-view.js +36 -21
- package/dist/modes/interactive/components/workflow-view.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +2 -1
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth.js +71 -40
- package/dist/modes/interactive/interactive-auth.js.map +1 -1
- package/dist/modes/interactive/interactive-commands.d.ts +1 -0
- package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-commands.js +3 -0
- package/dist/modes/interactive/interactive-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
- package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
- package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-format.js +34 -18
- package/dist/modes/interactive/interactive-format.js.map +1 -1
- package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-helpers.js +7 -2
- package/dist/modes/interactive/interactive-helpers.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +350 -279
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +79 -25
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +5 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +26 -23
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +3 -2
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +0 -8
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -14
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +0 -9
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +0 -19
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +28 -13
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
- package/dist/plugins/ecosystem/catalog.js +3 -2
- package/dist/plugins/ecosystem/catalog.js.map +1 -1
- package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
- package/dist/plugins/ecosystem/cli.js +2 -1
- package/dist/plugins/ecosystem/cli.js.map +1 -1
- package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
- package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
- package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
- package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
- package/dist/plugins/ecosystem/distribution.js +2 -1
- package/dist/plugins/ecosystem/distribution.js.map +1 -1
- package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
- package/dist/plugins/ecosystem/installer.js +3 -2
- package/dist/plugins/ecosystem/installer.js.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
- package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
- package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
- package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
- package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
- package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
- package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
- package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +9 -2
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js +44 -5
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
- package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
- package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-registry-source.js +31 -30
- package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
- package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
- package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
- package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
- package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
- package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
- package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
- package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +9 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.js +5 -0
- package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
- package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
- package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
- package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
- package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
- package/dist/plugins/ecosystem/registry.js +35 -32
- package/dist/plugins/ecosystem/registry.js.map +1 -1
- package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
- package/dist/plugins/ecosystem/resolver.js +3 -2
- package/dist/plugins/ecosystem/resolver.js.map +1 -1
- package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
- package/dist/plugins/ecosystem/selection-store.js +11 -10
- package/dist/plugins/ecosystem/selection-store.js.map +1 -1
- package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
- package/dist/plugins/ecosystem/selection.js +8 -7
- package/dist/plugins/ecosystem/selection.js.map +1 -1
- package/dist/plugins/ecosystem/state.d.ts.map +1 -1
- package/dist/plugins/ecosystem/state.js +24 -23
- package/dist/plugins/ecosystem/state.js.map +1 -1
- package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
- package/dist/plugins/ecosystem/updates.js +5 -4
- package/dist/plugins/ecosystem/updates.js.map +1 -1
- package/dist/plugins/mcp-http.d.ts +0 -17
- package/dist/plugins/mcp-http.d.ts.map +1 -1
- package/dist/plugins/mcp-http.js +30 -7
- package/dist/plugins/mcp-http.js.map +1 -1
- package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
- package/dist/plugins/plugin-supervisor.js +19 -1
- package/dist/plugins/plugin-supervisor.js.map +1 -1
- package/dist/profile/first-roles.d.ts.map +1 -1
- package/dist/profile/first-roles.js +10 -1
- package/dist/profile/first-roles.js.map +1 -1
- package/dist/profile/goal-plugin.d.ts.map +1 -1
- package/dist/profile/goal-plugin.js +24 -5
- package/dist/profile/goal-plugin.js.map +1 -1
- package/dist/profile/identity.d.ts.map +1 -1
- package/dist/profile/identity.js +7 -6
- package/dist/profile/identity.js.map +1 -1
- package/dist/profile/lock.d.ts.map +1 -1
- package/dist/profile/lock.js +15 -1
- package/dist/profile/lock.js.map +1 -1
- package/dist/profile/plan-plugin.d.ts.map +1 -1
- package/dist/profile/plan-plugin.js +26 -13
- package/dist/profile/plan-plugin.js.map +1 -1
- package/dist/profile/plugin-profiles.d.ts.map +1 -1
- package/dist/profile/plugin-profiles.js +2 -1
- package/dist/profile/plugin-profiles.js.map +1 -1
- package/dist/profile/policy-manifest.d.ts.map +1 -1
- package/dist/profile/policy-manifest.js +5 -4
- package/dist/profile/policy-manifest.js.map +1 -1
- package/dist/profile/profile-registry.d.ts +0 -12
- package/dist/profile/profile-registry.d.ts.map +1 -1
- package/dist/profile/profile-registry.js +14 -1
- package/dist/profile/profile-registry.js.map +1 -1
- package/dist/profile/role-catalog.d.ts +0 -1
- package/dist/profile/role-catalog.d.ts.map +1 -1
- package/dist/profile/role-catalog.js +17 -15
- package/dist/profile/role-catalog.js.map +1 -1
- package/dist/profile/role-orchestrator.d.ts.map +1 -1
- package/dist/profile/role-orchestrator.js +8 -7
- package/dist/profile/role-orchestrator.js.map +1 -1
- package/dist/profile/role-runner.d.ts.map +1 -1
- package/dist/profile/role-runner.js +3 -2
- package/dist/profile/role-runner.js.map +1 -1
- package/dist/profile/root-facade.d.ts.map +1 -1
- package/dist/profile/root-facade.js +2 -1
- package/dist/profile/root-facade.js.map +1 -1
- package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
- package/dist/profile/skill-discovery-wiring.js +7 -2
- package/dist/profile/skill-discovery-wiring.js.map +1 -1
- package/dist/profile/state-store.d.ts.map +1 -1
- package/dist/profile/state-store.js +13 -9
- package/dist/profile/state-store.js.map +1 -1
- package/dist/profile/todo-plugin.d.ts.map +1 -1
- package/dist/profile/todo-plugin.js +9 -4
- package/dist/profile/todo-plugin.js.map +1 -1
- package/dist/profiles/builtin-suites.d.ts +13 -6
- package/dist/profiles/builtin-suites.d.ts.map +1 -1
- package/dist/profiles/builtin-suites.js +15 -6
- package/dist/profiles/builtin-suites.js.map +1 -1
- package/dist/profiles/suite-loader.d.ts +25 -1
- package/dist/profiles/suite-loader.d.ts.map +1 -1
- package/dist/profiles/suite-loader.js +34 -9
- package/dist/profiles/suite-loader.js.map +1 -1
- package/dist/remote/server-entry.d.ts.map +1 -1
- package/dist/remote/server-entry.js +3 -2
- package/dist/remote/server-entry.js.map +1 -1
- package/dist/remote/session-source.d.ts.map +1 -1
- package/dist/remote/session-source.js +8 -4
- package/dist/remote/session-source.js.map +1 -1
- package/dist/share/session-share.d.ts.map +1 -1
- package/dist/share/session-share.js +14 -2
- package/dist/share/session-share.js.map +1 -1
- package/dist/testing/plugin-testkit.d.ts.map +1 -1
- package/dist/testing/plugin-testkit.js +4 -3
- package/dist/testing/plugin-testkit.js.map +1 -1
- package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
- package/dist/testing/runtime-delivery-queue.js +2 -1
- package/dist/testing/runtime-delivery-queue.js.map +1 -1
- package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
- package/dist/testing/session-plugin-testkit.js +10 -7
- package/dist/testing/session-plugin-testkit.js.map +1 -1
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js +2 -1
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +7 -6
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/image-resize-worker.d.ts.map +1 -1
- package/dist/utils/image-resize-worker.js +3 -2
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/photon.d.ts +2 -2
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js +2 -2
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +9 -8
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +23 -13
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +5 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -3
- package/docs/docs.json +4 -0
- package/docs/index.md +1 -0
- package/docs/keybindings.md +3 -0
- package/docs/mcp.md +103 -0
- package/docs/models.md +14 -22
- package/docs/providers.md +0 -1
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +1 -26
- package/docs/sdk.md +4 -6
- package/docs/settings.md +10 -12
- package/docs/skills.md +1 -9
- package/docs/terminal-setup.md +2 -3
- package/docs/usage.md +7 -6
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/with-deps/plugin.json +1 -1
- package/examples/sdk/10-settings.ts +2 -4
- package/examples/sdk/12-full-control.ts +1 -2
- package/package.json +1 -3
- package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
- package/dist/core/extensions/microcompact.d.ts +0 -80
- package/dist/core/extensions/microcompact.d.ts.map +0 -1
- package/dist/core/extensions/microcompact.js +0 -134
- package/dist/core/extensions/microcompact.js.map +0 -1
- package/dist/server/create-harness.d.ts +0 -26
- package/dist/server/create-harness.d.ts.map +0 -1
- package/dist/server/create-harness.js +0 -106
- package/dist/server/create-harness.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { t } from "../../core/i18n/index.js";
|
|
2
3
|
import { detectPluginPackageMediaTypeV1 } from "./node-package-media.js";
|
|
3
4
|
/**
|
|
4
5
|
* Custom-URL plugin package download (design §4.6 "自定义 URL" row). The URL
|
|
@@ -24,7 +25,7 @@ export class NodeUrlPackageSourceErrorV1 extends Error {
|
|
|
24
25
|
function boundedPositive(value, fallback, maximum, label) {
|
|
25
26
|
const result = value ?? fallback;
|
|
26
27
|
if (!Number.isSafeInteger(result) || result <= 0 || result > maximum)
|
|
27
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_configuration",
|
|
28
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("{label} must be a positive integer at most {maximum}", { label, maximum }));
|
|
28
29
|
return result;
|
|
29
30
|
}
|
|
30
31
|
function packageUrl(value) {
|
|
@@ -33,14 +34,14 @@ function packageUrl(value) {
|
|
|
33
34
|
parsed = new URL(value);
|
|
34
35
|
}
|
|
35
36
|
catch {
|
|
36
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL is invalid");
|
|
37
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL is invalid"));
|
|
37
38
|
}
|
|
38
39
|
if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") ||
|
|
39
40
|
parsed.username !== "" ||
|
|
40
41
|
parsed.password !== "")
|
|
41
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL must use http(s) without credentials");
|
|
42
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL must use http(s) without credentials"));
|
|
42
43
|
if (parsed.hash !== "")
|
|
43
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_url", "plugin package URL must not include a fragment");
|
|
44
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_url", t("plugin package URL must not include a fragment"));
|
|
44
45
|
return parsed;
|
|
45
46
|
}
|
|
46
47
|
function isAbortLike(error) {
|
|
@@ -54,17 +55,17 @@ function isAbortLike(error) {
|
|
|
54
55
|
export async function downloadNodeUrlPackageV1(options, input) {
|
|
55
56
|
const transport = options.fetch ?? globalThis.fetch;
|
|
56
57
|
if (typeof transport !== "function")
|
|
57
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", "Node fetch is unavailable");
|
|
58
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("Node fetch is unavailable"));
|
|
58
59
|
const timeoutMs = boundedPositive(options.requestTimeoutMs, DEFAULT_TIMEOUT_MS_V1, MAX_TIMEOUT_MS_V1, "requestTimeoutMs");
|
|
59
60
|
const maxPackageBytes = boundedPositive(options.maxPackageBytes, DEFAULT_MAX_PACKAGE_BYTES_V1, MAX_PACKAGE_BYTES_V1, "maxPackageBytes");
|
|
60
61
|
const maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;
|
|
61
62
|
if (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)
|
|
62
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_configuration",
|
|
63
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("maxRedirects must be an integer between 0 and {max}", { max: MAX_REDIRECTS_V1 }));
|
|
63
64
|
const userAgent = options.userAgent ?? "agent-forge-plugin-url/1";
|
|
64
65
|
if (userAgent.length === 0 || userAgent.length > 256 || /[\r\n]/u.test(userAgent))
|
|
65
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", "userAgent is invalid");
|
|
66
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_configuration", t("userAgent is invalid"));
|
|
66
67
|
if (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))
|
|
67
|
-
throw new NodeUrlPackageSourceErrorV1("invalid_url", "expected sha256 digest is invalid");
|
|
68
|
+
throw new NodeUrlPackageSourceErrorV1("invalid_url", t("expected sha256 digest is invalid"));
|
|
68
69
|
let current = packageUrl(input.url);
|
|
69
70
|
let response;
|
|
70
71
|
const controller = new AbortController();
|
|
@@ -81,7 +82,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
81
82
|
try {
|
|
82
83
|
for (let redirect = 0;; redirect += 1) {
|
|
83
84
|
if (controller.signal.aborted)
|
|
84
|
-
throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
|
|
85
|
+
throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
|
|
85
86
|
let hop;
|
|
86
87
|
try {
|
|
87
88
|
hop = await transport(current.toString(), {
|
|
@@ -93,10 +94,10 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
93
94
|
}
|
|
94
95
|
catch (error) {
|
|
95
96
|
if (timedOut)
|
|
96
|
-
throw new NodeUrlPackageSourceErrorV1("request_timed_out", "plugin package download timed out");
|
|
97
|
+
throw new NodeUrlPackageSourceErrorV1("request_timed_out", t("plugin package download timed out"));
|
|
97
98
|
if (isAbortLike(error) || input.signal?.aborted === true)
|
|
98
|
-
throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
|
|
99
|
-
throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download failed");
|
|
99
|
+
throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
|
|
100
|
+
throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download failed"));
|
|
100
101
|
}
|
|
101
102
|
if (!REDIRECT_STATUS.has(hop.status)) {
|
|
102
103
|
response = hop;
|
|
@@ -105,15 +106,15 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
105
106
|
const location = hop.headers.get("location");
|
|
106
107
|
await hop.body?.cancel().catch(() => undefined);
|
|
107
108
|
if (location === null || redirect >= maxRedirects)
|
|
108
|
-
throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package redirect limit exceeded");
|
|
109
|
+
throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package redirect limit exceeded"));
|
|
109
110
|
current = packageUrl(new URL(location, current).toString());
|
|
110
111
|
}
|
|
111
112
|
if (response === undefined)
|
|
112
|
-
throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download failed");
|
|
113
|
+
throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download failed"));
|
|
113
114
|
if (response.status < 200 || response.status >= 300)
|
|
114
|
-
throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package download did not succeed");
|
|
115
|
+
throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package download did not succeed"));
|
|
115
116
|
if (response.body === null)
|
|
116
|
-
throw new NodeUrlPackageSourceErrorV1("request_failed", "plugin package response has no body");
|
|
117
|
+
throw new NodeUrlPackageSourceErrorV1("request_failed", t("plugin package response has no body"));
|
|
117
118
|
const reader = response.body.getReader();
|
|
118
119
|
const chunks = [];
|
|
119
120
|
const hash = createHash("sha256");
|
|
@@ -121,13 +122,13 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
121
122
|
try {
|
|
122
123
|
for (;;) {
|
|
123
124
|
if (controller.signal.aborted)
|
|
124
|
-
throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
|
|
125
|
+
throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
|
|
125
126
|
const item = await reader.read();
|
|
126
127
|
if (item.done)
|
|
127
128
|
break;
|
|
128
129
|
total += item.value.byteLength;
|
|
129
130
|
if (total > maxPackageBytes)
|
|
130
|
-
throw new NodeUrlPackageSourceErrorV1("response_too_large", "plugin package exceeds the configured size limit");
|
|
131
|
+
throw new NodeUrlPackageSourceErrorV1("response_too_large", t("plugin package exceeds the configured size limit"));
|
|
131
132
|
hash.update(item.value);
|
|
132
133
|
chunks.push(item.value);
|
|
133
134
|
}
|
|
@@ -136,7 +137,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
136
137
|
reader.releaseLock();
|
|
137
138
|
}
|
|
138
139
|
if (controller.signal.aborted)
|
|
139
|
-
throw new NodeUrlPackageSourceErrorV1("cancelled", "plugin package download was cancelled");
|
|
140
|
+
throw new NodeUrlPackageSourceErrorV1("cancelled", t("plugin package download was cancelled"));
|
|
140
141
|
const bytes = new Uint8Array(total);
|
|
141
142
|
let offset = 0;
|
|
142
143
|
for (const chunk of chunks) {
|
|
@@ -145,7 +146,7 @@ export async function downloadNodeUrlPackageV1(options, input) {
|
|
|
145
146
|
}
|
|
146
147
|
const digestHex = hash.digest("hex");
|
|
147
148
|
if (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)
|
|
148
|
-
throw new NodeUrlPackageSourceErrorV1("digest_mismatch", "plugin package bytes do not match the expected sha256 digest");
|
|
149
|
+
throw new NodeUrlPackageSourceErrorV1("digest_mismatch", t("plugin package bytes do not match the expected sha256 digest"));
|
|
149
150
|
const fileName = current.pathname.split("/").pop();
|
|
150
151
|
const mediaType = detectPluginPackageMediaTypeV1(bytes, fileName === undefined || fileName.length === 0 ? undefined : fileName);
|
|
151
152
|
return { bytes, mediaType, digestHex };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-url-package-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-url-package-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { detectPluginPackageMediaTypeV1, type PluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\n\n/**\n * Custom-URL plugin package download (design §4.6 \"自定义 URL\" row). The URL\n * is the package file itself (zip/tgz); integrity is layered: a `#sha256:<hex>`\n * ref fragment becomes a strong digest check, otherwise TLS plus the double\n * manifest validation performed by the install host.\n */\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_PACKAGE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_PACKAGE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeUrlPackageSourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_url\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"response_too_large\"\n\t| \"digest_mismatch\";\n\nexport class NodeUrlPackageSourceErrorV1 extends Error {\n\treadonly code: NodeUrlPackageSourceErrorCodeV1;\n\n\tconstructor(code: NodeUrlPackageSourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeUrlPackageSourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeUrlPackageSourceOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxPackageBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeUrlPackageDownloadV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: PluginPackageMediaTypeV1;\n\t/** sha256 hex of the downloaded bytes; always computed, verified when expected. */\n\treadonly digestHex: string;\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\t`${label} must be a positive integer at most ${maximum}`,\n\t\t);\n\treturn result;\n}\n\nfunction packageUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL is invalid\");\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL must use http(s) without credentials\");\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"plugin package URL must not include a fragment\");\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\n/**\n * Download one package file over http(s). Redirects are followed manually and\n * every hop must again be a valid http(s) URL without credentials. When\n * `expectedDigestHex` is present the sha256 of the bytes must match exactly.\n */\nexport async function downloadNodeUrlPackageV1(\n\toptions: NodeUrlPackageSourceOptionsV1,\n\tinput: {\n\t\treadonly url: string;\n\t\treadonly expectedDigestHex?: string;\n\t\treadonly signal?: AbortSignal;\n\t},\n): Promise<NodeUrlPackageDownloadV1> {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", \"Node fetch is unavailable\");\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxPackageBytes = boundedPositive(\n\t\toptions.maxPackageBytes,\n\t\tDEFAULT_MAX_PACKAGE_BYTES_V1,\n\t\tMAX_PACKAGE_BYTES_V1,\n\t\t\"maxPackageBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\t`maxRedirects must be an integer between 0 and ${MAX_REDIRECTS_V1}`,\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-url/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", \"userAgent is invalid\");\n\tif (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", \"expected sha256 digest is invalid\");\n\n\tlet current = packageUrl(input.url);\n\tlet response: Response | undefined;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(input.signal?.reason);\n\tif (input.signal?.aborted === true) abort();\n\telse input.signal?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\ttry {\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tif (controller.signal.aborted)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\tlet hop: Response;\n\t\t\ttry {\n\t\t\t\thop = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (timedOut)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_timed_out\", \"plugin package download timed out\");\n\t\t\t\tif (isAbortLike(error) || input.signal?.aborted === true)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download failed\");\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(hop.status)) {\n\t\t\t\tresponse = hop;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst location = hop.headers.get(\"location\");\n\t\t\tawait hop.body?.cancel().catch(() => undefined);\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package redirect limit exceeded\");\n\t\t\tcurrent = packageUrl(new URL(location, current).toString());\n\t\t}\n\t\tif (response === undefined)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download failed\");\n\t\tif (response.status < 200 || response.status >= 300)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package download did not succeed\");\n\t\tif (response.body === null)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", \"plugin package response has no body\");\n\t\tconst reader = response.body.getReader();\n\t\tconst chunks: Uint8Array[] = [];\n\t\tconst hash = createHash(\"sha256\");\n\t\tlet total = 0;\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (controller.signal.aborted)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\t\t\tconst item = await reader.read();\n\t\t\t\tif (item.done) break;\n\t\t\t\ttotal += item.value.byteLength;\n\t\t\t\tif (total > maxPackageBytes)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\t\t\"plugin package exceeds the configured size limit\",\n\t\t\t\t\t);\n\t\t\t\thash.update(item.value);\n\t\t\t\tchunks.push(item.value);\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tif (controller.signal.aborted)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", \"plugin package download was cancelled\");\n\t\tconst bytes = new Uint8Array(total);\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, offset);\n\t\t\toffset += chunk.byteLength;\n\t\t}\n\t\tconst digestHex = hash.digest(\"hex\");\n\t\tif (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\"digest_mismatch\",\n\t\t\t\t\"plugin package bytes do not match the expected sha256 digest\",\n\t\t\t);\n\t\tconst fileName = current.pathname.split(\"/\").pop();\n\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\tbytes,\n\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t);\n\t\treturn { bytes, mediaType, digestHex };\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tinput.signal?.removeEventListener(\"abort\", abort);\n\t\tawait response?.body?.cancel().catch(() => undefined);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node-url-package-source.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/node-url-package-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAC;AAC7C,OAAO,EAAE,8BAA8B,EAAiC,MAAM,yBAAyB,CAAC;AAExG;;;;;GAKG;AAEH,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAClC,MAAM,4BAA4B,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AACvD,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAC/C,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAW3D,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IAC5C,IAAI,CAAkC;IAE/C,YAAY,IAAqC,EAAE,OAAe,EAAE;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;CACD;AAkBD,SAAS,eAAe,CAAC,KAAyB,EAAE,QAAgB,EAAE,OAAe,EAAE,KAAa,EAAU;IAC7G,MAAM,MAAM,GAAG,KAAK,IAAI,QAAQ,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO;QACnE,MAAM,IAAI,2BAA2B,CACpC,uBAAuB,EACvB,CAAC,CAAC,sDAAsD,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAC7E,CAAC;IACH,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,UAAU,CAAC,KAAa,EAAO;IACvC,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,2BAA2B,CAAC,aAAa,EAAE,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAC1F,CAAC;IACD,IACC,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAC7D,MAAM,CAAC,QAAQ,KAAK,EAAE;QACtB,MAAM,CAAC,QAAQ,KAAK,EAAE;QAEtB,MAAM,IAAI,2BAA2B,CACpC,aAAa,EACb,CAAC,CAAC,yDAAyD,CAAC,CAC5D,CAAC;IACH,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE;QACrB,MAAM,IAAI,2BAA2B,CAAC,aAAa,EAAE,CAAC,CAAC,gDAAgD,CAAC,CAAC,CAAC;IAC3G,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,WAAW,CAAC,KAAc,EAAW;IAC7C,OAAO,KAAK,YAAY,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC;AAAA,CACpG;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,OAAsC,EACtC,KAIC,EACmC;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IACpD,IAAI,OAAO,SAAS,KAAK,UAAU;QAClC,MAAM,IAAI,2BAA2B,CAAC,uBAAuB,EAAE,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC;IAChG,MAAM,SAAS,GAAG,eAAe,CAChC,OAAO,CAAC,gBAAgB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,CAClB,CAAC;IACF,MAAM,eAAe,GAAG,eAAe,CACtC,OAAO,CAAC,eAAe,EACvB,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,CACjB,CAAC;IACF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,oBAAoB,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,GAAG,gBAAgB;QAC7F,MAAM,IAAI,2BAA2B,CACpC,uBAAuB,EACvB,CAAC,CAAC,qDAAqD,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CACnF,CAAC;IACH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,0BAA0B,CAAC;IAClE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;QAChF,MAAM,IAAI,2BAA2B,CAAC,uBAAuB,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC3F,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC;QAC5F,MAAM,IAAI,2BAA2B,CAAC,aAAa,EAAE,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAE9F,IAAI,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,QAA8B,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3D,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;QAAE,KAAK,EAAE,CAAC;;QACvC,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;QAChC,QAAQ,GAAG,IAAI,CAAC;QAChB,UAAU,CAAC,KAAK,EAAE,CAAC;IAAA,CACnB,EAAE,SAAS,CAAC,CAAC;IACd,IAAI,CAAC;QACJ,KAAK,IAAI,QAAQ,GAAG,CAAC,GAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YACxC,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;gBAC5B,MAAM,IAAI,2BAA2B,CAAC,WAAW,EAAE,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;YAChG,IAAI,GAAa,CAAC;YAClB,IAAI,CAAC;gBACJ,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE;oBACzC,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE;oBACnD,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,UAAU,CAAC,MAAM;iBACzB,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,QAAQ;oBACX,MAAM,IAAI,2BAA2B,CAAC,mBAAmB,EAAE,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC;gBACpG,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;oBACvD,MAAM,IAAI,2BAA2B,CAAC,WAAW,EAAE,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBAChG,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,EAAE,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC;YAC9F,CAAC;YACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtC,QAAQ,GAAG,GAAG,CAAC;gBACf,MAAM;YACP,CAAC;YACD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,YAAY;gBAChD,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,EAAE,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC;YACtG,OAAO,GAAG,UAAU,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS;YACzB,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,EAAE,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC9F,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;YAClD,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,EAAE,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC;QACvG,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI;YACzB,MAAM,IAAI,2BAA2B,CAAC,gBAAgB,EAAE,CAAC,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACnG,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACJ,SAAS,CAAC;gBACT,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;oBAC5B,MAAM,IAAI,2BAA2B,CAAC,WAAW,EAAE,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBAChG,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,IAAI;oBAAE,MAAM;gBACrB,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;gBAC/B,IAAI,KAAK,GAAG,eAAe;oBAC1B,MAAM,IAAI,2BAA2B,CACpC,oBAAoB,EACpB,CAAC,CAAC,kDAAkD,CAAC,CACrD,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,MAAM,CAAC,WAAW,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;YAC5B,MAAM,IAAI,2BAA2B,CAAC,WAAW,EAAE,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;QAChG,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC;QAC5B,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK,CAAC,iBAAiB;YACjF,MAAM,IAAI,2BAA2B,CACpC,iBAAiB,EACjB,CAAC,CAAC,8DAA8D,CAAC,CACjE,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACnD,MAAM,SAAS,GAAG,8BAA8B,CAC/C,KAAK,EACL,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CACtE,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IACxC,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,KAAK,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC;AAAA,CACD","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { t } from \"../../core/i18n/index.ts\";\nimport { detectPluginPackageMediaTypeV1, type PluginPackageMediaTypeV1 } from \"./node-package-media.ts\";\n\n/**\n * Custom-URL plugin package download (design §4.6 \"自定义 URL\" row). The URL\n * is the package file itself (zip/tgz); integrity is layered: a `#sha256:<hex>`\n * ref fragment becomes a strong digest check, otherwise TLS plus the double\n * manifest validation performed by the install host.\n */\n\nconst DEFAULT_TIMEOUT_MS_V1 = 30_000;\nconst MAX_TIMEOUT_MS_V1 = 120_000;\nconst DEFAULT_MAX_PACKAGE_BYTES_V1 = 128 * 1024 * 1024;\nconst MAX_PACKAGE_BYTES_V1 = 512 * 1024 * 1024;\nconst DEFAULT_REDIRECTS_V1 = 3;\nconst MAX_REDIRECTS_V1 = 5;\nconst REDIRECT_STATUS = new Set([301, 302, 303, 307, 308]);\n\nexport type NodeUrlPackageSourceErrorCodeV1 =\n\t| \"cancelled\"\n\t| \"invalid_configuration\"\n\t| \"invalid_url\"\n\t| \"request_failed\"\n\t| \"request_timed_out\"\n\t| \"response_too_large\"\n\t| \"digest_mismatch\";\n\nexport class NodeUrlPackageSourceErrorV1 extends Error {\n\treadonly code: NodeUrlPackageSourceErrorCodeV1;\n\n\tconstructor(code: NodeUrlPackageSourceErrorCodeV1, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"NodeUrlPackageSourceErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\nexport interface NodeUrlPackageSourceOptionsV1 {\n\t/** Real fetch or a deterministic test replacement. */\n\treadonly fetch?: typeof globalThis.fetch;\n\treadonly requestTimeoutMs?: number;\n\treadonly maxPackageBytes?: number;\n\treadonly maxRedirects?: number;\n\treadonly userAgent?: string;\n}\n\nexport interface NodeUrlPackageDownloadV1 {\n\treadonly bytes: Uint8Array;\n\treadonly mediaType: PluginPackageMediaTypeV1;\n\t/** sha256 hex of the downloaded bytes; always computed, verified when expected. */\n\treadonly digestHex: string;\n}\n\nfunction boundedPositive(value: number | undefined, fallback: number, maximum: number, label: string): number {\n\tconst result = value ?? fallback;\n\tif (!Number.isSafeInteger(result) || result <= 0 || result > maximum)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"{label} must be a positive integer at most {maximum}\", { label, maximum }),\n\t\t);\n\treturn result;\n}\n\nfunction packageUrl(value: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"plugin package URL is invalid\"));\n\t}\n\tif (\n\t\t(parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") ||\n\t\tparsed.username !== \"\" ||\n\t\tparsed.password !== \"\"\n\t)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_url\",\n\t\t\tt(\"plugin package URL must use http(s) without credentials\"),\n\t\t);\n\tif (parsed.hash !== \"\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"plugin package URL must not include a fragment\"));\n\treturn parsed;\n}\n\nfunction isAbortLike(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === \"AbortError\" || error.name === \"AbortSignalError\");\n}\n\n/**\n * Download one package file over http(s). Redirects are followed manually and\n * every hop must again be a valid http(s) URL without credentials. When\n * `expectedDigestHex` is present the sha256 of the bytes must match exactly.\n */\nexport async function downloadNodeUrlPackageV1(\n\toptions: NodeUrlPackageSourceOptionsV1,\n\tinput: {\n\t\treadonly url: string;\n\t\treadonly expectedDigestHex?: string;\n\t\treadonly signal?: AbortSignal;\n\t},\n): Promise<NodeUrlPackageDownloadV1> {\n\tconst transport = options.fetch ?? globalThis.fetch;\n\tif (typeof transport !== \"function\")\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", t(\"Node fetch is unavailable\"));\n\tconst timeoutMs = boundedPositive(\n\t\toptions.requestTimeoutMs,\n\t\tDEFAULT_TIMEOUT_MS_V1,\n\t\tMAX_TIMEOUT_MS_V1,\n\t\t\"requestTimeoutMs\",\n\t);\n\tconst maxPackageBytes = boundedPositive(\n\t\toptions.maxPackageBytes,\n\t\tDEFAULT_MAX_PACKAGE_BYTES_V1,\n\t\tMAX_PACKAGE_BYTES_V1,\n\t\t\"maxPackageBytes\",\n\t);\n\tconst maxRedirects = options.maxRedirects ?? DEFAULT_REDIRECTS_V1;\n\tif (!Number.isSafeInteger(maxRedirects) || maxRedirects < 0 || maxRedirects > MAX_REDIRECTS_V1)\n\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\"invalid_configuration\",\n\t\t\tt(\"maxRedirects must be an integer between 0 and {max}\", { max: MAX_REDIRECTS_V1 }),\n\t\t);\n\tconst userAgent = options.userAgent ?? \"agent-forge-plugin-url/1\";\n\tif (userAgent.length === 0 || userAgent.length > 256 || /[\\r\\n]/u.test(userAgent))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_configuration\", t(\"userAgent is invalid\"));\n\tif (input.expectedDigestHex !== undefined && !/^[0-9a-f]{64}$/u.test(input.expectedDigestHex))\n\t\tthrow new NodeUrlPackageSourceErrorV1(\"invalid_url\", t(\"expected sha256 digest is invalid\"));\n\n\tlet current = packageUrl(input.url);\n\tlet response: Response | undefined;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst abort = () => controller.abort(input.signal?.reason);\n\tif (input.signal?.aborted === true) abort();\n\telse input.signal?.addEventListener(\"abort\", abort, { once: true });\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\ttry {\n\t\tfor (let redirect = 0; ; redirect += 1) {\n\t\t\tif (controller.signal.aborted)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\tlet hop: Response;\n\t\t\ttry {\n\t\t\t\thop = await transport(current.toString(), {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\theaders: { accept: \"*/*\", \"user-agent\": userAgent },\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (timedOut)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_timed_out\", t(\"plugin package download timed out\"));\n\t\t\t\tif (isAbortLike(error) || input.signal?.aborted === true)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download failed\"));\n\t\t\t}\n\t\t\tif (!REDIRECT_STATUS.has(hop.status)) {\n\t\t\t\tresponse = hop;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst location = hop.headers.get(\"location\");\n\t\t\tawait hop.body?.cancel().catch(() => undefined);\n\t\t\tif (location === null || redirect >= maxRedirects)\n\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package redirect limit exceeded\"));\n\t\t\tcurrent = packageUrl(new URL(location, current).toString());\n\t\t}\n\t\tif (response === undefined)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download failed\"));\n\t\tif (response.status < 200 || response.status >= 300)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package download did not succeed\"));\n\t\tif (response.body === null)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"request_failed\", t(\"plugin package response has no body\"));\n\t\tconst reader = response.body.getReader();\n\t\tconst chunks: Uint8Array[] = [];\n\t\tconst hash = createHash(\"sha256\");\n\t\tlet total = 0;\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tif (controller.signal.aborted)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\t\t\tconst item = await reader.read();\n\t\t\t\tif (item.done) break;\n\t\t\t\ttotal += item.value.byteLength;\n\t\t\t\tif (total > maxPackageBytes)\n\t\t\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\t\t\"response_too_large\",\n\t\t\t\t\t\tt(\"plugin package exceeds the configured size limit\"),\n\t\t\t\t\t);\n\t\t\t\thash.update(item.value);\n\t\t\t\tchunks.push(item.value);\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t\tif (controller.signal.aborted)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\"cancelled\", t(\"plugin package download was cancelled\"));\n\t\tconst bytes = new Uint8Array(total);\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tbytes.set(chunk, offset);\n\t\t\toffset += chunk.byteLength;\n\t\t}\n\t\tconst digestHex = hash.digest(\"hex\");\n\t\tif (input.expectedDigestHex !== undefined && digestHex !== input.expectedDigestHex)\n\t\t\tthrow new NodeUrlPackageSourceErrorV1(\n\t\t\t\t\"digest_mismatch\",\n\t\t\t\tt(\"plugin package bytes do not match the expected sha256 digest\"),\n\t\t\t);\n\t\tconst fileName = current.pathname.split(\"/\").pop();\n\t\tconst mediaType = detectPluginPackageMediaTypeV1(\n\t\t\tbytes,\n\t\t\tfileName === undefined || fileName.length === 0 ? undefined : fileName,\n\t\t);\n\t\treturn { bytes, mediaType, digestHex };\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tinput.signal?.removeEventListener(\"abort\", abort);\n\t\tawait response?.body?.cancel().catch(() => undefined);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-acquisition.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,wHAAwH;IACxH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,4BAA4B,GACrC,aAAa,GACb,uBAAuB,GACvB,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,WAAW,GACX,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,wBAAwB,GACxB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,yBAAyB,GACzB,yBAAyB,GACzB,cAAc,CAAC;AAsBlB,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAE5C,mGAAmG;IACnG,YAAY,IAAI,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,MAAM,EAQ9D;CACD;AAED,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACpF;AAoFD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,6BAA6B,GAAG,sBAAsB,CAcrH;AAaD;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAetE","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? ACQUISITION_ERROR_MESSAGES_V1[code]\n\t\t\t\t: `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugin-acquisition.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,wHAAwH;IACxH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,4BAA4B,GACrC,aAAa,GACb,uBAAuB,GACvB,oBAAoB,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,WAAW,GACX,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,wBAAwB,GACxB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,yBAAyB,GACzB,yBAAyB,GACzB,cAAc,CAAC;AAsBlB,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAE5C,mGAAmG;IACnG,YAAY,IAAI,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,MAAM,EAQ9D;CACD;AAED,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL,kFAAkF;AAClF,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACpF;AAoFD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,6BAA6B,GAAG,sBAAsB,CAcrH;AAaD;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAetE","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport { t } from \"../../core/i18n/index.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? t(ACQUISITION_ERROR_MESSAGES_V1[code])\n\t\t\t\t: `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* name parsing. The CLI additionally routes only refs that cannot be legacy
|
|
20
20
|
* plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).
|
|
21
21
|
*/
|
|
22
|
+
import { t } from "../../core/i18n/index.js";
|
|
22
23
|
export const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;
|
|
23
24
|
export const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;
|
|
24
25
|
const ACQUISITION_ERROR_MESSAGES_V1 = {
|
|
@@ -45,8 +46,8 @@ export class PluginAcquisitionErrorV1 extends Error {
|
|
|
45
46
|
/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */
|
|
46
47
|
constructor(code, detail) {
|
|
47
48
|
super(detail === undefined || detail.length === 0
|
|
48
|
-
? ACQUISITION_ERROR_MESSAGES_V1[code]
|
|
49
|
-
: `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`);
|
|
49
|
+
? t(ACQUISITION_ERROR_MESSAGES_V1[code])
|
|
50
|
+
: `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`);
|
|
50
51
|
this.name = "PluginAcquisitionErrorV1";
|
|
51
52
|
this.code = code;
|
|
52
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-acquisition.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? ACQUISITION_ERROR_MESSAGES_V1[code]\n\t\t\t\t: `${ACQUISITION_ERROR_MESSAGES_V1[code]}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugin-acquisition.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-acquisition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure ref parsing for multi-source plugin package acquisition\n * (`plugin install <ref>`, design `插件独立分发与启动装配设计.md` §4.6).\n *\n * Ref grammar and resolution priority:\n * 1. local path (existing directory or `.zip`/`.tgz` file); a ref that exists\n * locally but is neither of those is an explicit `unsupported_local_ref`\n * error and never falls through to later priorities;\n * 2. `github:<owner>/<repo>[@<tag>]` / `gitee:...` — resolved against the\n * matching release API by the acquisition host;\n * 3. `http://`/`https://` URL, optionally with a `#sha256:<hex>` fragment that\n * is stripped before resolution and becomes a strong digest check;\n * 4. anything else is an npm package ref (`@scope/name[@range]` or\n * `name[@range]`) with the minimal range subset `x.y.z`, `^x.y.z`,\n * `~x.y.z`, `latest`.\n *\n * Reserved scheme prefixes (`github:`, `gitee:`, and any other URL scheme) are\n * never probed as local paths; every other ref is probed locally before npm\n * name parsing. The CLI additionally routes only refs that cannot be legacy\n * plugin IDs to this parser (see {@link isPluginAcquisitionRefTargetV1}).\n */\n\nimport { t } from \"../../core/i18n/index.ts\";\nimport type { PluginDistributionArtifactV1 } from \"./distribution.ts\";\nimport type { PluginManifestV1 } from \"./types.ts\";\n\nexport const MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 = 2048;\nexport const MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 = 214;\n\n/**\n * Resolved acquisition package handed to an install transaction. The manifest\n * identity is discovered from the package itself (`agent-forge.json`); the\n * artifact is an opaque host-owned handle bound to the acquired bytes.\n */\nexport interface PluginAcquisitionPackageV1 {\n\treadonly manifest: PluginManifestV1;\n\treadonly manifestDigest: string;\n\t/** Opaque source label persisted in the plugin state record (`npm:<host>`, `url:<host>`, `local:dir`, `local:file`). */\n\treadonly source: string;\n\treadonly artifact: PluginDistributionArtifactV1;\n\t/** Release the artifact bytes; resolves `true` when nothing remains held. */\n\treadonly release: () => Promise<boolean>;\n}\n\nexport type PluginAcquisitionErrorCodeV1 =\n\t| \"invalid_ref\"\n\t| \"unsupported_local_ref\"\n\t| \"unsupported_scheme\"\n\t| \"invalid_digest_fragment\"\n\t| \"invalid_npm_ref\"\n\t| \"cancelled\"\n\t| \"download_failed\"\n\t| \"package_not_found\"\n\t| \"version_not_found\"\n\t| \"digest_mismatch\"\n\t| \"unsupported_media_type\"\n\t| \"package_invalid\"\n\t| \"budget_exceeded\"\n\t| \"release_not_found\"\n\t| \"release_asset_not_found\"\n\t| \"release_asset_ambiguous\"\n\t| \"rate_limited\";\n\nconst ACQUISITION_ERROR_MESSAGES_V1: Readonly<Record<PluginAcquisitionErrorCodeV1, string>> = {\n\tinvalid_ref: \"Plugin ref is invalid\",\n\tunsupported_local_ref: \"Local plugin ref exists but is neither a directory nor a .zip/.tgz file\",\n\tunsupported_scheme: \"Plugin ref URL scheme is not supported\",\n\tinvalid_digest_fragment: \"Plugin ref #sha256 digest fragment is invalid\",\n\tinvalid_npm_ref: \"Plugin npm package ref is invalid\",\n\tcancelled: \"Plugin package acquisition was cancelled\",\n\tdownload_failed: \"Plugin package download failed\",\n\tpackage_not_found: \"Plugin npm package was not found on the registry\",\n\tversion_not_found: \"No npm package version matches the requested range\",\n\tdigest_mismatch: \"Plugin package bytes do not match the expected digest\",\n\tunsupported_media_type: \"Plugin package bytes are neither a zip nor a tgz\",\n\tpackage_invalid: \"Plugin package contents are invalid\",\n\tbudget_exceeded: \"Plugin package exceeds the configured size budget\",\n\trelease_not_found: \"Plugin release was not found\",\n\trelease_asset_not_found: \"Plugin release has no .zip/.tgz asset\",\n\trelease_asset_ambiguous: \"Plugin release has multiple .zip/.tgz assets\",\n\trate_limited: \"Plugin release API rate limit was exceeded\",\n};\n\nexport class PluginAcquisitionErrorV1 extends Error {\n\treadonly code: PluginAcquisitionErrorCodeV1;\n\n\t/** Optional factual suffix (asset candidates, rate-limit reset) appended to the static message. */\n\tconstructor(code: PluginAcquisitionErrorCodeV1, detail?: string) {\n\t\tsuper(\n\t\t\tdetail === undefined || detail.length === 0\n\t\t\t\t? t(ACQUISITION_ERROR_MESSAGES_V1[code])\n\t\t\t\t: `${t(ACQUISITION_ERROR_MESSAGES_V1[code])}: ${detail}`,\n\t\t);\n\t\tthis.name = \"PluginAcquisitionErrorV1\";\n\t\tthis.code = code;\n\t}\n}\n\n/** A parsed acquisition ref. Digests are lowercase hex without an algorithm prefix. */\nexport type PluginAcquisitionRefV1 =\n\t| { readonly kind: \"local-path\"; readonly path: string }\n\t| { readonly kind: \"local-file\"; readonly path: string }\n\t| { readonly kind: \"url\"; readonly url: string; readonly expectedDigestHex?: string }\n\t| { readonly kind: \"npm\"; readonly name: string; readonly range?: string }\n\t| {\n\t\t\treadonly kind: \"github\" | \"gitee\";\n\t\t\treadonly owner: string;\n\t\t\treadonly repo: string;\n\t\t\treadonly tag?: string;\n\t\t\treadonly expectedDigestHex?: string;\n\t };\n\n/** Host-injected local filesystem classification; it must not follow symlinks. */\nexport interface PluginAcquisitionLocalProbeV1 {\n\treadonly statLocalRef: (path: string) => \"directory\" | \"file\" | \"other\" | \"missing\";\n}\n\nconst DIGEST_FRAGMENT_SUFFIX_V1 = /^#sha256:([0-9a-fA-F]{64})$/u;\n\nfunction boundedRef(ref: string): string {\n\tif (\n\t\ttypeof ref !== \"string\" ||\n\t\tref.length === 0 ||\n\t\tref.length > MAX_PLUGIN_ACQUISITION_REF_CHARS_V1 ||\n\t\t/[\\u0000-\\u001f\\s]/u.test(ref)\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn ref;\n}\n\n/** Split and validate a trailing `#sha256:<64 hex>` fragment from a scheme ref. */\nfunction splitDigestFragment(ref: string): { readonly value: string; readonly digestHex?: string } {\n\tconst hash = ref.lastIndexOf(\"#\");\n\tif (hash < 0) return { value: ref };\n\tconst fragment = ref.slice(hash);\n\tconst match = DIGEST_FRAGMENT_SUFFIX_V1.exec(fragment);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn { value: ref.slice(0, hash), digestHex: match[1]!.toLowerCase() };\n}\n\nfunction ownerRepoTag(kind: \"github\" | \"gitee\", value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tconst match =\n\t\t/^([A-Za-z0-9][A-Za-z0-9._-]{0,99})\\/([A-Za-z0-9][A-Za-z0-9._-]{0,99})(?:@([A-Za-z0-9][A-Za-z0-9._+-]{0,127}))?$/u.exec(\n\t\t\tvalue,\n\t\t);\n\tif (match === null) throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\treturn {\n\t\tkind,\n\t\towner: match[1]!,\n\t\trepo: match[2]!,\n\t\t...(match[3] === undefined ? {} : { tag: match[3] }),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nfunction parseUrlRef(value: string, digestHex?: string): PluginAcquisitionRefV1 {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(value);\n\t} catch {\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_ref\");\n\t}\n\tif (parsed.username !== \"\" || parsed.password !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_ref\");\n\tif (parsed.hash !== \"\") throw new PluginAcquisitionErrorV1(\"invalid_digest_fragment\");\n\treturn {\n\t\tkind: \"url\",\n\t\turl: parsed.toString(),\n\t\t...(digestHex === undefined ? {} : { expectedDigestHex: digestHex }),\n\t};\n}\n\nconst NPM_RANGE_V1 = /^(?:latest|[~^]?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)$/u;\nconst NPM_NAME_V1 = /^@?[a-z0-9][a-z0-9-._]*(?:\\/[a-z0-9][a-z0-9-._]*)?$/u;\n\nfunction parseNpmRef(ref: string): PluginAcquisitionRefV1 {\n\tconst at = ref.lastIndexOf(\"@\");\n\tconst name = at > 0 ? ref.slice(0, at) : ref;\n\tconst range = at > 0 ? ref.slice(at + 1) : undefined;\n\tif (\n\t\tname.length === 0 ||\n\t\tname.length > MAX_PLUGIN_ACQUISITION_NPM_NAME_CHARS_V1 ||\n\t\t!NPM_NAME_V1.test(name) ||\n\t\t(name.startsWith(\"@\") && !name.includes(\"/\")) ||\n\t\t(!name.startsWith(\"@\") && name.includes(\"/\"))\n\t)\n\t\tthrow new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\tif (range !== undefined && !NPM_RANGE_V1.test(range)) throw new PluginAcquisitionErrorV1(\"invalid_npm_ref\");\n\treturn {\n\t\tkind: \"npm\",\n\t\tname,\n\t\t...(range === undefined ? {} : { range }),\n\t};\n}\n\nfunction isLocalPackageFile(path: string): boolean {\n\tconst value = path.toLowerCase();\n\treturn value.endsWith(\".zip\") || value.endsWith(\".tgz\") || value.endsWith(\".tar.gz\");\n}\n\n/**\n * Parse one acquisition ref. Priority: local (probe-injected) → github/gitee\n * (recognized only) → http(s) URL → npm name. Throws\n * {@link PluginAcquisitionErrorV1} for every unsupported or malformed ref.\n */\nexport function parsePluginAcquisitionRefV1(ref: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst value = boundedRef(ref);\n\t// Windows drive-letter paths must not be mistaken for URL schemes.\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(value)) return localRef(value, probe);\n\tconst scheme = /^([a-zA-Z][a-zA-Z\\d+.-]*):/u.exec(value);\n\tif (scheme !== null) {\n\t\tconst prefix = scheme[1]!.toLowerCase();\n\t\tconst stripped = splitDigestFragment(value);\n\t\tif (prefix === \"github\" || prefix === \"gitee\")\n\t\t\treturn ownerRepoTag(prefix, stripped.value.slice(prefix.length + 1), stripped.digestHex);\n\t\tif (prefix === \"http\" || prefix === \"https\") return parseUrlRef(stripped.value, stripped.digestHex);\n\t\tthrow new PluginAcquisitionErrorV1(\"unsupported_scheme\");\n\t}\n\treturn localRef(value, probe);\n}\n\nfunction localRef(value: string, probe: PluginAcquisitionLocalProbeV1): PluginAcquisitionRefV1 {\n\tconst stat = probe.statLocalRef(value);\n\tif (stat === \"directory\") return { kind: \"local-path\", path: value };\n\tif (stat === \"file\") {\n\t\tif (!isLocalPackageFile(value)) throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\t\treturn { kind: \"local-file\", path: value };\n\t}\n\tif (stat === \"other\") throw new PluginAcquisitionErrorV1(\"unsupported_local_ref\");\n\treturn parseNpmRef(value);\n}\n\n/**\n * CLI routing predicate: legacy registry plugin IDs never contain `/`, `\\`,\n * `:`, `#`, a leading `@`, or an npm range suffix (`@^…`, `@~…`, `@latest`).\n * Only targets with one of those markers enter acquisition ref parsing, so the\n * existing `plugin install <pluginId>[@<exact version>]` registry path keeps\n * its exact behavior. Note `name@1.2.3` (exact version) stays a registry\n * identity; an unscoped npm package must be installed through a range suffix\n * (`name@^1.2.3`, `name@latest`) or a scoped `@scope/name…` ref.\n */\nexport function isPluginAcquisitionRefTargetV1(target: string): boolean {\n\tif (typeof target !== \"string\" || target.length === 0) return false;\n\tif (target.startsWith(\"@\")) return true;\n\tif (/^[a-zA-Z]:[\\\\/]/u.test(target)) return true;\n\tif (target.startsWith(\"/\") || target.startsWith(\"\\\\\")) return true;\n\tif (target.startsWith(\"./\") || target.startsWith(\".\\\\\")) return true;\n\tif (target.startsWith(\"../\") || target.startsWith(\"..\\\\\")) return true;\n\tif (/[:#]/u.test(target)) return true;\n\tif (/[\\\\/]/u.test(target)) return true;\n\tconst at = target.lastIndexOf(\"@\");\n\tif (at > 0) {\n\t\tconst suffix = target.slice(at + 1);\n\t\tif (suffix === \"latest\" || suffix.startsWith(\"^\") || suffix.startsWith(\"~\")) return true;\n\t}\n\treturn false;\n}\n"]}
|
|
@@ -55,7 +55,7 @@ export interface PluginBootstrapActionV1 {
|
|
|
55
55
|
/** Acquisition or install failure code for failed actions. */
|
|
56
56
|
readonly errorCode?: string;
|
|
57
57
|
}
|
|
58
|
-
export type PluginBootstrapDiagnosticCodeV1 = "range_not_satisfied" | "install_failed" | "list_active_failed" | "cancelled" | "bootstrap_failed";
|
|
58
|
+
export type PluginBootstrapDiagnosticCodeV1 = "range_not_satisfied" | "install_failed" | "list_active_failed" | "cancelled" | "bootstrap_failed" | "bootstrap_skipped_offline";
|
|
59
59
|
export interface PluginBootstrapDiagnosticV1 {
|
|
60
60
|
readonly code: PluginBootstrapDiagnosticCodeV1;
|
|
61
61
|
readonly message: string;
|
|
@@ -83,5 +83,13 @@ export declare function pluginBootstrapInstallCommandV1(entry: {
|
|
|
83
83
|
export declare function runPluginBootstrapV1(input: {
|
|
84
84
|
readonly manifest: readonly PluginBootstrapFactoryEntryV1[];
|
|
85
85
|
readonly deps: PluginBootstrapDepsV1;
|
|
86
|
+
/**
|
|
87
|
+
* Fired once after the local active-state read when at least one factory
|
|
88
|
+
* entry has no active installation — the host's first-run progress line
|
|
89
|
+
* hook (设计 §4.4 首装进度行, 2026-10-03): a fresh install is otherwise
|
|
90
|
+
* silent for the whole network install window. Injected effect, the loop
|
|
91
|
+
* itself stays free of console I/O.
|
|
92
|
+
*/
|
|
93
|
+
readonly onPendingInstalls?: (count: number) => void;
|
|
86
94
|
}): Promise<PluginBootstrapResultV1>;
|
|
87
95
|
//# 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":"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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 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\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}): 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\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 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"]}
|
|
@@ -76,6 +76,11 @@ export async function runPluginBootstrapV1(input) {
|
|
|
76
76
|
}
|
|
77
77
|
const actions = [];
|
|
78
78
|
const diagnostics = [];
|
|
79
|
+
if (input.onPendingInstalls !== undefined) {
|
|
80
|
+
const pending = input.manifest.filter((entry) => !active.has(entry.pluginId)).length;
|
|
81
|
+
if (pending > 0)
|
|
82
|
+
input.onPendingInstalls(pending);
|
|
83
|
+
}
|
|
79
84
|
for (const entry of input.manifest) {
|
|
80
85
|
if (signal?.aborted === true) {
|
|
81
86
|
diagnostics.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-bootstrap.js","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 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\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}): 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\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.js","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 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-cli-adapter.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry-cli-adapter.d.ts","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,gBAAgB,GAAG,yBAAyB,CAS5G","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Registry does not expose a host-side package resolver\"));\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t } from "../../core/i18n/index.js";
|
|
1
2
|
import { PluginRegistryErrorV1 } from "./registry.js";
|
|
2
3
|
/**
|
|
3
4
|
* Adapt a verified registry to the CLI's host-injected package resolver.
|
|
@@ -5,7 +6,7 @@ import { PluginRegistryErrorV1 } from "./registry.js";
|
|
|
5
6
|
*/
|
|
6
7
|
export function createPluginEcosystemRegistryAdapterV1(registry) {
|
|
7
8
|
if (registry.resolve === undefined)
|
|
8
|
-
throw new PluginRegistryErrorV1("invalid_source", "Registry does not expose a host-side package resolver");
|
|
9
|
+
throw new PluginRegistryErrorV1("invalid_source", t("Registry does not expose a host-side package resolver"));
|
|
9
10
|
const resolve = registry.resolve;
|
|
10
11
|
const list = registry.listManifests;
|
|
11
12
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-cli-adapter.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry-cli-adapter.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/registry-cli-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAyB,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,MAAM,UAAU,sCAAsC,CAAC,QAA0B,EAA6B;IAC7G,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QACjC,MAAM,IAAI,qBAAqB,CAAC,gBAAgB,EAAE,CAAC,CAAC,uDAAuD,CAAC,CAAC,CAAC;IAC/G,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC;IACpC,OAAO;QACN,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,OAAO;KACP,CAAC;AAAA,CACF","sourcesContent":["import { t } from \"../../core/i18n/index.ts\";\nimport type { PluginEcosystemRegistryV1 } from \"./cli.ts\";\nimport { PluginRegistryErrorV1, type PluginRegistryV1 } from \"./registry.ts\";\n\n/**\n * Adapt a verified registry to the CLI's host-injected package resolver.\n * The adapter forwards only bounded manifest metadata and never package bytes.\n */\nexport function createPluginEcosystemRegistryAdapterV1(registry: PluginRegistryV1): PluginEcosystemRegistryV1 {\n\tif (registry.resolve === undefined)\n\t\tthrow new PluginRegistryErrorV1(\"invalid_source\", t(\"Registry does not expose a host-side package resolver\"));\n\tconst resolve = registry.resolve;\n\tconst list = registry.listManifests;\n\treturn {\n\t\t...(list === undefined ? {} : { list }),\n\t\tresolve,\n\t};\n}\n"]}
|