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