@lesliechan721/aw 0.1.0-beta.10
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/dist/authoring/assets/aw-config.d.mts +51 -0
- package/dist/authoring/assets/aw-config.mjs +1025 -0
- package/dist/authoring/assets/aw-config.mjs.map +1 -0
- package/dist/authoring/scripts/add-skill.d.mts +2 -0
- package/dist/authoring/scripts/add-skill.mjs +355 -0
- package/dist/authoring/scripts/add-skill.mjs.map +1 -0
- package/dist/authoring/scripts/init-plugin.d.mts +2 -0
- package/dist/authoring/scripts/init-plugin.mjs +487 -0
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.d.mts +4 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.mjs +261 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.mjs.map +1 -0
- package/dist/authoring/scripts/lib/plugin-root.d.mts +26 -0
- package/dist/authoring/scripts/lib/plugin-root.mjs +125 -0
- package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -0
- package/dist/authoring/scripts/lib/plugin-version-check.d.mts +69 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +563 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -0
- package/dist/authoring/scripts/lib/semver.d.mts +9 -0
- package/dist/authoring/scripts/lib/semver.mjs +63 -0
- package/dist/authoring/scripts/lib/semver.mjs.map +1 -0
- package/dist/authoring/scripts/lib/skill-scaffold.d.mts +111 -0
- package/dist/authoring/scripts/lib/skill-scaffold.mjs +353 -0
- package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -0
- package/dist/authoring/scripts/plugin-status.d.mts +2 -0
- package/dist/authoring/scripts/plugin-status.mjs +93 -0
- package/dist/authoring/scripts/plugin-status.mjs.map +1 -0
- package/dist/authoring/scripts/remove-plugin.d.mts +2 -0
- package/dist/authoring/scripts/remove-plugin.mjs +367 -0
- package/dist/authoring/scripts/remove-plugin.mjs.map +1 -0
- package/dist/authoring/scripts/validate-plugin.d.mts +2 -0
- package/dist/authoring/scripts/validate-plugin.mjs +3465 -0
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -0
- package/dist/authoring/scripts/validate-skill.d.mts +2 -0
- package/dist/authoring/scripts/validate-skill.mjs +126 -0
- package/dist/authoring/scripts/validate-skill.mjs.map +1 -0
- package/dist/authoring/templates/aw-config-runtime.d.mts +2 -0
- package/dist/authoring/templates/aw-config-runtime.mjs +407 -0
- package/dist/authoring/templates/aw-config-runtime.mjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
- package/dist/scripts/aw-skill-eval-materializer.js +309 -0
- package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
- package/dist/scripts/bundle-plugins.d.ts +17 -0
- package/dist/scripts/bundle-plugins.js +126 -0
- package/dist/scripts/bundle-plugins.js.map +1 -0
- package/dist/scripts/plugin-staging.d.ts +26 -0
- package/dist/scripts/plugin-staging.js +76 -0
- package/dist/scripts/plugin-staging.js.map +1 -0
- package/dist/scripts/test-plugin-scripts.d.ts +7 -0
- package/dist/scripts/test-plugin-scripts.js +610 -0
- package/dist/scripts/test-plugin-scripts.js.map +1 -0
- package/dist/src/adapters/helpers.d.ts +44 -0
- package/dist/src/adapters/helpers.js +95 -0
- package/dist/src/adapters/helpers.js.map +1 -0
- package/dist/src/authoring/workspace-commands.d.ts +70 -0
- package/dist/src/authoring/workspace-commands.js +158 -0
- package/dist/src/authoring/workspace-commands.js.map +1 -0
- package/dist/src/commands/aw-capabilities.d.ts +78 -0
- package/dist/src/commands/aw-capabilities.js +254 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -0
- package/dist/src/commands/catalog-dev-source.d.ts +120 -0
- package/dist/src/commands/catalog-dev-source.js +434 -0
- package/dist/src/commands/catalog-dev-source.js.map +1 -0
- package/dist/src/commands/catalog-generation.d.ts +16 -0
- package/dist/src/commands/catalog-generation.js +9 -0
- package/dist/src/commands/catalog-generation.js.map +1 -0
- package/dist/src/commands/catalog-publication-inspection.d.ts +138 -0
- package/dist/src/commands/catalog-publication-inspection.js +711 -0
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -0
- package/dist/src/commands/catalog-publication-journal.d.ts +56 -0
- package/dist/src/commands/catalog-publication-journal.js +215 -0
- package/dist/src/commands/catalog-publication-journal.js.map +1 -0
- package/dist/src/commands/catalog-publication-target.d.ts +18 -0
- package/dist/src/commands/catalog-publication-target.js +95 -0
- package/dist/src/commands/catalog-publication-target.js.map +1 -0
- package/dist/src/commands/catalog-publish.d.ts +103 -0
- package/dist/src/commands/catalog-publish.js +804 -0
- package/dist/src/commands/catalog-publish.js.map +1 -0
- package/dist/src/commands/catalog-source.d.ts +134 -0
- package/dist/src/commands/catalog-source.js +377 -0
- package/dist/src/commands/catalog-source.js.map +1 -0
- package/dist/src/commands/catalog-status.d.ts +56 -0
- package/dist/src/commands/catalog-status.js +217 -0
- package/dist/src/commands/catalog-status.js.map +1 -0
- package/dist/src/commands/catalog-store.d.ts +80 -0
- package/dist/src/commands/catalog-store.js +348 -0
- package/dist/src/commands/catalog-store.js.map +1 -0
- package/dist/src/commands/catalog-workspace-resolution.d.ts +13 -0
- package/dist/src/commands/catalog-workspace-resolution.js +42 -0
- package/dist/src/commands/catalog-workspace-resolution.js.map +1 -0
- package/dist/src/commands/console.d.ts +3 -0
- package/dist/src/commands/console.js +44 -0
- package/dist/src/commands/console.js.map +1 -0
- package/dist/src/commands/dependency-operation-plan.d.ts +58 -0
- package/dist/src/commands/dependency-operation-plan.js +261 -0
- package/dist/src/commands/dependency-operation-plan.js.map +1 -0
- package/dist/src/commands/init.d.ts +25 -0
- package/dist/src/commands/init.js +42 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/offline-cleanup-evidence.d.ts +59 -0
- package/dist/src/commands/offline-cleanup-evidence.js +163 -0
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
- package/dist/src/commands/operation-plan.d.ts +126 -0
- package/dist/src/commands/operation-plan.js +47 -0
- package/dist/src/commands/operation-plan.js.map +1 -0
- package/dist/src/commands/operation-planner.d.ts +46 -0
- package/dist/src/commands/operation-planner.js +139 -0
- package/dist/src/commands/operation-planner.js.map +1 -0
- package/dist/src/commands/options.d.ts +70 -0
- package/dist/src/commands/options.js +194 -0
- package/dist/src/commands/options.js.map +1 -0
- package/dist/src/commands/plugin-capabilities.d.ts +22 -0
- package/dist/src/commands/plugin-capabilities.js +159 -0
- package/dist/src/commands/plugin-capabilities.js.map +1 -0
- package/dist/src/commands/rebuild-command.d.ts +88 -0
- package/dist/src/commands/rebuild-command.js +3626 -0
- package/dist/src/commands/rebuild-command.js.map +1 -0
- package/dist/src/commands/rebuild-integration.d.ts +190 -0
- package/dist/src/commands/rebuild-integration.js +4439 -0
- package/dist/src/commands/rebuild-integration.js.map +1 -0
- package/dist/src/commands/rebuild-operations.d.ts +100 -0
- package/dist/src/commands/rebuild-operations.js +625 -0
- package/dist/src/commands/rebuild-operations.js.map +1 -0
- package/dist/src/commands/reconcile-operation-plan.d.ts +26 -0
- package/dist/src/commands/reconcile-operation-plan.js +28 -0
- package/dist/src/commands/reconcile-operation-plan.js.map +1 -0
- package/dist/src/commands/review-publication.d.ts +99 -0
- package/dist/src/commands/review-publication.js +904 -0
- package/dist/src/commands/review-publication.js.map +1 -0
- package/dist/src/commands/runtime.d.ts +172 -0
- package/dist/src/commands/runtime.js +720 -0
- package/dist/src/commands/runtime.js.map +1 -0
- package/dist/src/commands/skill-eval.d.ts +33 -0
- package/dist/src/commands/skill-eval.js +363 -0
- package/dist/src/commands/skill-eval.js.map +1 -0
- package/dist/src/commands/status-v6.d.ts +206 -0
- package/dist/src/commands/status-v6.js +2175 -0
- package/dist/src/commands/status-v6.js.map +1 -0
- package/dist/src/commands/sync-command.d.ts +23 -0
- package/dist/src/commands/sync-command.js +242 -0
- package/dist/src/commands/sync-command.js.map +1 -0
- package/dist/src/commands/wizard.d.ts +56 -0
- package/dist/src/commands/wizard.js +58 -0
- package/dist/src/commands/wizard.js.map +1 -0
- package/dist/src/commands/write-commands.d.ts +7 -0
- package/dist/src/commands/write-commands.js +190 -0
- package/dist/src/commands/write-commands.js.map +1 -0
- package/dist/src/constants.d.ts +31 -0
- package/dist/src/constants.js +32 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/eval/manifest-v1.d.ts +67 -0
- package/dist/src/eval/manifest-v1.js +347 -0
- package/dist/src/eval/manifest-v1.js.map +1 -0
- package/dist/src/generators/agents.d.ts +3 -0
- package/dist/src/generators/agents.js +46 -0
- package/dist/src/generators/agents.js.map +1 -0
- package/dist/src/generators/hooks.d.ts +15 -0
- package/dist/src/generators/hooks.js +76 -0
- package/dist/src/generators/hooks.js.map +1 -0
- package/dist/src/generators/instructions.d.ts +13 -0
- package/dist/src/generators/instructions.js +66 -0
- package/dist/src/generators/instructions.js.map +1 -0
- package/dist/src/generators/local-plugin.d.ts +56 -0
- package/dist/src/generators/local-plugin.js +1373 -0
- package/dist/src/generators/local-plugin.js.map +1 -0
- package/dist/src/generators/permissions.d.ts +10 -0
- package/dist/src/generators/permissions.js +37 -0
- package/dist/src/generators/permissions.js.map +1 -0
- package/dist/src/generators/shared.d.ts +2 -0
- package/dist/src/generators/shared.js +15 -0
- package/dist/src/generators/shared.js.map +1 -0
- package/dist/src/index.d.ts +41 -0
- package/dist/src/index.js +3327 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/output/command-receipt.d.ts +87 -0
- package/dist/src/output/command-receipt.js +302 -0
- package/dist/src/output/command-receipt.js.map +1 -0
- package/dist/src/output/debug-log.d.ts +4 -0
- package/dist/src/output/debug-log.js +97 -0
- package/dist/src/output/debug-log.js.map +1 -0
- package/dist/src/output/equivalent-command.d.ts +9 -0
- package/dist/src/output/equivalent-command.js +39 -0
- package/dist/src/output/equivalent-command.js.map +1 -0
- package/dist/src/output/model.d.ts +76 -0
- package/dist/src/output/model.js +2 -0
- package/dist/src/output/model.js.map +1 -0
- package/dist/src/output/rebuild-progress.d.ts +21 -0
- package/dist/src/output/rebuild-progress.js +128 -0
- package/dist/src/output/rebuild-progress.js.map +1 -0
- package/dist/src/output/redact.d.ts +3 -0
- package/dist/src/output/redact.js +39 -0
- package/dist/src/output/redact.js.map +1 -0
- package/dist/src/output/reporter.d.ts +9 -0
- package/dist/src/output/reporter.js +133 -0
- package/dist/src/output/reporter.js.map +1 -0
- package/dist/src/portable/commands.d.ts +124 -0
- package/dist/src/portable/commands.js +557 -0
- package/dist/src/portable/commands.js.map +1 -0
- package/dist/src/portable/materializer.d.ts +50 -0
- package/dist/src/portable/materializer.js +462 -0
- package/dist/src/portable/materializer.js.map +1 -0
- package/dist/src/portable/skills-cli.d.ts +43 -0
- package/dist/src/portable/skills-cli.js +148 -0
- package/dist/src/portable/skills-cli.js.map +1 -0
- package/dist/src/tui/catalog-freshness.d.ts +1 -0
- package/dist/src/tui/catalog-freshness.js +2 -0
- package/dist/src/tui/catalog-freshness.js.map +1 -0
- package/dist/src/tui/catalog-generation.d.ts +21 -0
- package/dist/src/tui/catalog-generation.js +116 -0
- package/dist/src/tui/catalog-generation.js.map +1 -0
- package/dist/src/tui/catalog-sources/projection.d.ts +4 -0
- package/dist/src/tui/catalog-sources/projection.js +17 -0
- package/dist/src/tui/catalog-sources/projection.js.map +1 -0
- package/dist/src/tui/catalog-sources/review.d.ts +3 -0
- package/dist/src/tui/catalog-sources/review.js +13 -0
- package/dist/src/tui/catalog-sources/review.js.map +1 -0
- package/dist/src/tui/catalog-sources/screens.d.ts +12 -0
- package/dist/src/tui/catalog-sources/screens.js +33 -0
- package/dist/src/tui/catalog-sources/screens.js.map +1 -0
- package/dist/src/tui/catalog-sources/session.d.ts +22 -0
- package/dist/src/tui/catalog-sources/session.js +225 -0
- package/dist/src/tui/catalog-sources/session.js.map +1 -0
- package/dist/src/tui/catalog-sources/types.d.ts +41 -0
- package/dist/src/tui/catalog-sources/types.js +2 -0
- package/dist/src/tui/catalog-sources/types.js.map +1 -0
- package/dist/src/tui/components.d.ts +102 -0
- package/dist/src/tui/components.js +184 -0
- package/dist/src/tui/components.js.map +1 -0
- package/dist/src/tui/console-app-v4.d.ts +20 -0
- package/dist/src/tui/console-app-v4.js +5066 -0
- package/dist/src/tui/console-app-v4.js.map +1 -0
- package/dist/src/tui/controller-runtime.d.ts +23 -0
- package/dist/src/tui/controller-runtime.js +2011 -0
- package/dist/src/tui/controller-runtime.js.map +1 -0
- package/dist/src/tui/controller.d.ts +557 -0
- package/dist/src/tui/controller.js +2120 -0
- package/dist/src/tui/controller.js.map +1 -0
- package/dist/src/tui/diagnostics.d.ts +30 -0
- package/dist/src/tui/diagnostics.js +71 -0
- package/dist/src/tui/diagnostics.js.map +1 -0
- package/dist/src/tui/index.d.ts +17 -0
- package/dist/src/tui/index.js +17 -0
- package/dist/src/tui/index.js.map +1 -0
- package/dist/src/tui/input-display.d.ts +8 -0
- package/dist/src/tui/input-display.js +36 -0
- package/dist/src/tui/input-display.js.map +1 -0
- package/dist/src/tui/keys.d.ts +12 -0
- package/dist/src/tui/keys.js +22 -0
- package/dist/src/tui/keys.js.map +1 -0
- package/dist/src/tui/layout.d.ts +12 -0
- package/dist/src/tui/layout.js +19 -0
- package/dist/src/tui/layout.js.map +1 -0
- package/dist/src/tui/model.d.ts +424 -0
- package/dist/src/tui/model.js +1493 -0
- package/dist/src/tui/model.js.map +1 -0
- package/dist/src/tui/operation-review-planner.d.ts +21 -0
- package/dist/src/tui/operation-review-planner.js +622 -0
- package/dist/src/tui/operation-review-planner.js.map +1 -0
- package/dist/src/tui/prompt.d.ts +8 -0
- package/dist/src/tui/prompt.js +231 -0
- package/dist/src/tui/prompt.js.map +1 -0
- package/dist/src/tui/router.d.ts +206 -0
- package/dist/src/tui/router.js +137 -0
- package/dist/src/tui/router.js.map +1 -0
- package/dist/src/tui/runner.d.ts +11 -0
- package/dist/src/tui/runner.js +71 -0
- package/dist/src/tui/runner.js.map +1 -0
- package/dist/src/tui/source-ref-presets.d.ts +3 -0
- package/dist/src/tui/source-ref-presets.js +11 -0
- package/dist/src/tui/source-ref-presets.js.map +1 -0
- package/dist/src/tui/theme.d.ts +26 -0
- package/dist/src/tui/theme.js +28 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/tui/viewport.d.ts +20 -0
- package/dist/src/tui/viewport.js +29 -0
- package/dist/src/tui/viewport.js.map +1 -0
- package/dist/src/tui/views.d.ts +57 -0
- package/dist/src/tui/views.js +201 -0
- package/dist/src/tui/views.js.map +1 -0
- package/dist/src/tui/wizard.d.ts +11 -0
- package/dist/src/tui/wizard.js +323 -0
- package/dist/src/tui/wizard.js.map +1 -0
- package/dist/src/types.d.ts +474 -0
- package/dist/src/types.js +34 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/agent-version.d.ts +19 -0
- package/dist/src/utils/agent-version.js +205 -0
- package/dist/src/utils/agent-version.js.map +1 -0
- package/dist/src/utils/artifact-plan.d.ts +27 -0
- package/dist/src/utils/artifact-plan.js +453 -0
- package/dist/src/utils/artifact-plan.js.map +1 -0
- package/dist/src/utils/artifact-renderer.d.ts +129 -0
- package/dist/src/utils/artifact-renderer.js +400 -0
- package/dist/src/utils/artifact-renderer.js.map +1 -0
- package/dist/src/utils/artifact-request.d.ts +16 -0
- package/dist/src/utils/artifact-request.js +42 -0
- package/dist/src/utils/artifact-request.js.map +1 -0
- package/dist/src/utils/artifact-sources.d.ts +8 -0
- package/dist/src/utils/artifact-sources.js +10 -0
- package/dist/src/utils/artifact-sources.js.map +1 -0
- package/dist/src/utils/aw-home-mutation-lock.d.ts +11 -0
- package/dist/src/utils/aw-home-mutation-lock.js +83 -0
- package/dist/src/utils/aw-home-mutation-lock.js.map +1 -0
- package/dist/src/utils/bundle-integrity.d.ts +2 -0
- package/dist/src/utils/bundle-integrity.js +63 -0
- package/dist/src/utils/bundle-integrity.js.map +1 -0
- package/dist/src/utils/bundle-layout.d.ts +4 -0
- package/dist/src/utils/bundle-layout.js +531 -0
- package/dist/src/utils/bundle-layout.js.map +1 -0
- package/dist/src/utils/catalog-digests.d.ts +18 -0
- package/dist/src/utils/catalog-digests.js +156 -0
- package/dist/src/utils/catalog-digests.js.map +1 -0
- package/dist/src/utils/catalog-generation-control-snapshot.d.ts +11 -0
- package/dist/src/utils/catalog-generation-control-snapshot.js +45 -0
- package/dist/src/utils/catalog-generation-control-snapshot.js.map +1 -0
- package/dist/src/utils/catalog-generation-error.d.ts +16 -0
- package/dist/src/utils/catalog-generation-error.js +30 -0
- package/dist/src/utils/catalog-generation-error.js.map +1 -0
- package/dist/src/utils/catalog-generation-resolver.d.ts +32 -0
- package/dist/src/utils/catalog-generation-resolver.js +251 -0
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
- package/dist/src/utils/catalog-generation-service.d.ts +161 -0
- package/dist/src/utils/catalog-generation-service.js +1237 -0
- package/dist/src/utils/catalog-generation-service.js.map +1 -0
- package/dist/src/utils/catalog-generation-state.d.ts +22 -0
- package/dist/src/utils/catalog-generation-state.js +192 -0
- package/dist/src/utils/catalog-generation-state.js.map +1 -0
- package/dist/src/utils/catalog-generation-store.d.ts +57 -0
- package/dist/src/utils/catalog-generation-store.js +397 -0
- package/dist/src/utils/catalog-generation-store.js.map +1 -0
- package/dist/src/utils/catalog-manifest-v7.d.ts +5 -0
- package/dist/src/utils/catalog-manifest-v7.js +98 -0
- package/dist/src/utils/catalog-manifest-v7.js.map +1 -0
- package/dist/src/utils/catalog-operation-context.d.ts +20 -0
- package/dist/src/utils/catalog-operation-context.js +141 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -0
- package/dist/src/utils/catalog-public-error.d.ts +19 -0
- package/dist/src/utils/catalog-public-error.js +100 -0
- package/dist/src/utils/catalog-public-error.js.map +1 -0
- package/dist/src/utils/catalog-runtime-projection.d.ts +33 -0
- package/dist/src/utils/catalog-runtime-projection.js +77 -0
- package/dist/src/utils/catalog-runtime-projection.js.map +1 -0
- package/dist/src/utils/catalog-snapshot.d.ts +10 -0
- package/dist/src/utils/catalog-snapshot.js +20 -0
- package/dist/src/utils/catalog-snapshot.js.map +1 -0
- package/dist/src/utils/catalog-source-identity.d.ts +5 -0
- package/dist/src/utils/catalog-source-identity.js +137 -0
- package/dist/src/utils/catalog-source-identity.js.map +1 -0
- package/dist/src/utils/catalog-source-impact.d.ts +20 -0
- package/dist/src/utils/catalog-source-impact.js +222 -0
- package/dist/src/utils/catalog-source-impact.js.map +1 -0
- package/dist/src/utils/catalog-source-presentation.d.ts +1 -0
- package/dist/src/utils/catalog-source-presentation.js +32 -0
- package/dist/src/utils/catalog-source-presentation.js.map +1 -0
- package/dist/src/utils/catalog-source-references.d.ts +66 -0
- package/dist/src/utils/catalog-source-references.js +1180 -0
- package/dist/src/utils/catalog-source-references.js.map +1 -0
- package/dist/src/utils/catalog-sources.d.ts +53 -0
- package/dist/src/utils/catalog-sources.js +456 -0
- package/dist/src/utils/catalog-sources.js.map +1 -0
- package/dist/src/utils/codex-config.d.ts +126 -0
- package/dist/src/utils/codex-config.js +1032 -0
- package/dist/src/utils/codex-config.js.map +1 -0
- package/dist/src/utils/codex-manager.d.ts +81 -0
- package/dist/src/utils/codex-manager.js +810 -0
- package/dist/src/utils/codex-manager.js.map +1 -0
- package/dist/src/utils/codex-marketplace-path.d.ts +5 -0
- package/dist/src/utils/codex-marketplace-path.js +45 -0
- package/dist/src/utils/codex-marketplace-path.js.map +1 -0
- package/dist/src/utils/codex-native-observation.d.ts +16 -0
- package/dist/src/utils/codex-native-observation.js +22 -0
- package/dist/src/utils/codex-native-observation.js.map +1 -0
- package/dist/src/utils/codex-native-render-receipt.d.ts +40 -0
- package/dist/src/utils/codex-native-render-receipt.js +205 -0
- package/dist/src/utils/codex-native-render-receipt.js.map +1 -0
- package/dist/src/utils/codex-reconciler.d.ts +128 -0
- package/dist/src/utils/codex-reconciler.js +294 -0
- package/dist/src/utils/codex-reconciler.js.map +1 -0
- package/dist/src/utils/codex-roles.d.ts +71 -0
- package/dist/src/utils/codex-roles.js +257 -0
- package/dist/src/utils/codex-roles.js.map +1 -0
- package/dist/src/utils/codex-shared-native.d.ts +63 -0
- package/dist/src/utils/codex-shared-native.js +142 -0
- package/dist/src/utils/codex-shared-native.js.map +1 -0
- package/dist/src/utils/codex-skill-staging.d.ts +11 -0
- package/dist/src/utils/codex-skill-staging.js +8 -0
- package/dist/src/utils/codex-skill-staging.js.map +1 -0
- package/dist/src/utils/codex-surface-analysis.d.ts +45 -0
- package/dist/src/utils/codex-surface-analysis.js +245 -0
- package/dist/src/utils/codex-surface-analysis.js.map +1 -0
- package/dist/src/utils/config-value.d.ts +3 -0
- package/dist/src/utils/config-value.js +23 -0
- package/dist/src/utils/config-value.js.map +1 -0
- package/dist/src/utils/dynamic-skill-tree.d.ts +36 -0
- package/dist/src/utils/dynamic-skill-tree.js +466 -0
- package/dist/src/utils/dynamic-skill-tree.js.map +1 -0
- package/dist/src/utils/file-rules.d.ts +1 -0
- package/dist/src/utils/file-rules.js +2 -0
- package/dist/src/utils/file-rules.js.map +1 -0
- package/dist/src/utils/git-catalog-provider.d.ts +22 -0
- package/dist/src/utils/git-catalog-provider.js +497 -0
- package/dist/src/utils/git-catalog-provider.js.map +1 -0
- package/dist/src/utils/hooks-contract.d.ts +1 -0
- package/dist/src/utils/hooks-contract.js +2 -0
- package/dist/src/utils/hooks-contract.js.map +1 -0
- package/dist/src/utils/json.d.ts +4 -0
- package/dist/src/utils/json.js +29 -0
- package/dist/src/utils/json.js.map +1 -0
- package/dist/src/utils/local-marketplace.d.ts +41 -0
- package/dist/src/utils/local-marketplace.js +316 -0
- package/dist/src/utils/local-marketplace.js.map +1 -0
- package/dist/src/utils/manifest.d.ts +11 -0
- package/dist/src/utils/manifest.js +33 -0
- package/dist/src/utils/manifest.js.map +1 -0
- package/dist/src/utils/marketplace.d.ts +3 -0
- package/dist/src/utils/marketplace.js +76 -0
- package/dist/src/utils/marketplace.js.map +1 -0
- package/dist/src/utils/multi-source-catalog.d.ts +66 -0
- package/dist/src/utils/multi-source-catalog.js +345 -0
- package/dist/src/utils/multi-source-catalog.js.map +1 -0
- package/dist/src/utils/native-cli.d.ts +118 -0
- package/dist/src/utils/native-cli.js +518 -0
- package/dist/src/utils/native-cli.js.map +1 -0
- package/dist/src/utils/orphan-marketplace-cleanup.d.ts +18 -0
- package/dist/src/utils/orphan-marketplace-cleanup.js +198 -0
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -0
- package/dist/src/utils/ownership.d.ts +194 -0
- package/dist/src/utils/ownership.js +723 -0
- package/dist/src/utils/ownership.js.map +1 -0
- package/dist/src/utils/path-catalog-provider.d.ts +7 -0
- package/dist/src/utils/path-catalog-provider.js +74 -0
- package/dist/src/utils/path-catalog-provider.js.map +1 -0
- package/dist/src/utils/paths.d.ts +40 -0
- package/dist/src/utils/paths.js +137 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/utils/platform-entries.d.ts +1 -0
- package/dist/src/utils/platform-entries.js +2 -0
- package/dist/src/utils/platform-entries.js.map +1 -0
- package/dist/src/utils/platform-support.d.ts +1 -0
- package/dist/src/utils/platform-support.js +2 -0
- package/dist/src/utils/platform-support.js.map +1 -0
- package/dist/src/utils/plugin-config-write.d.ts +110 -0
- package/dist/src/utils/plugin-config-write.js +773 -0
- package/dist/src/utils/plugin-config-write.js.map +1 -0
- package/dist/src/utils/plugin-config.d.ts +389 -0
- package/dist/src/utils/plugin-config.js +1642 -0
- package/dist/src/utils/plugin-config.js.map +1 -0
- package/dist/src/utils/plugin-dependencies.d.ts +12 -0
- package/dist/src/utils/plugin-dependencies.js +162 -0
- package/dist/src/utils/plugin-dependencies.js.map +1 -0
- package/dist/src/utils/plugin-intent-state.d.ts +34 -0
- package/dist/src/utils/plugin-intent-state.js +289 -0
- package/dist/src/utils/plugin-intent-state.js.map +1 -0
- package/dist/src/utils/plugin-script-contract.d.ts +1 -0
- package/dist/src/utils/plugin-script-contract.js +2 -0
- package/dist/src/utils/plugin-script-contract.js.map +1 -0
- package/dist/src/utils/plugin-scripts.d.ts +101 -0
- package/dist/src/utils/plugin-scripts.js +253 -0
- package/dist/src/utils/plugin-scripts.js.map +1 -0
- package/dist/src/utils/process-lock.d.ts +47 -0
- package/dist/src/utils/process-lock.js +532 -0
- package/dist/src/utils/process-lock.js.map +1 -0
- package/dist/src/utils/process-tree.d.ts +2 -0
- package/dist/src/utils/process-tree.js +2 -0
- package/dist/src/utils/process-tree.js.map +1 -0
- package/dist/src/utils/project-boundary.d.ts +9 -0
- package/dist/src/utils/project-boundary.js +67 -0
- package/dist/src/utils/project-boundary.js.map +1 -0
- package/dist/src/utils/rendered-contract.d.ts +8 -0
- package/dist/src/utils/rendered-contract.js +134 -0
- package/dist/src/utils/rendered-contract.js.map +1 -0
- package/dist/src/utils/runtime-skill-closure.d.ts +13 -0
- package/dist/src/utils/runtime-skill-closure.js +863 -0
- package/dist/src/utils/runtime-skill-closure.js.map +1 -0
- package/dist/src/utils/safe-fs.d.ts +21 -0
- package/dist/src/utils/safe-fs.js +111 -0
- package/dist/src/utils/safe-fs.js.map +1 -0
- package/dist/src/utils/skill-authoring.d.ts +1 -0
- package/dist/src/utils/skill-authoring.js +2 -0
- package/dist/src/utils/skill-authoring.js.map +1 -0
- package/dist/src/utils/skill-validation.d.ts +37 -0
- package/dist/src/utils/skill-validation.js +326 -0
- package/dist/src/utils/skill-validation.js.map +1 -0
- package/dist/src/utils/slash-commands.d.ts +1 -0
- package/dist/src/utils/slash-commands.js +2 -0
- package/dist/src/utils/slash-commands.js.map +1 -0
- package/dist/src/utils/state-paths.d.ts +14 -0
- package/dist/src/utils/state-paths.js +139 -0
- package/dist/src/utils/state-paths.js.map +1 -0
- package/dist/src/utils/target-eligibility.d.ts +13 -0
- package/dist/src/utils/target-eligibility.js +35 -0
- package/dist/src/utils/target-eligibility.js.map +1 -0
- package/dist/src/utils/target-order.d.ts +7 -0
- package/dist/src/utils/target-order.js +10 -0
- package/dist/src/utils/target-order.js.map +1 -0
- package/dist/src/utils/template-engine.d.ts +1 -0
- package/dist/src/utils/template-engine.js +2 -0
- package/dist/src/utils/template-engine.js.map +1 -0
- package/dist/src/utils/test-path-fence.d.ts +12 -0
- package/dist/src/utils/test-path-fence.js +31 -0
- package/dist/src/utils/test-path-fence.js.map +1 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +16 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,2011 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { statusCommandV7, statusTargetIntent, } from '../commands/status-v6.js';
|
|
4
|
+
import { addCatalogSourceCommand, listCatalogSources, preflightCatalogSourceMutation, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from '../commands/catalog-source.js';
|
|
5
|
+
import { cleanupWriteCommand, installWriteCommand, reinstallWriteCommand, syncWriteCommand, uninstallWriteCommand, } from '../commands/write-commands.js';
|
|
6
|
+
import { readCliPackageInfo } from '../utils/local-marketplace.js';
|
|
7
|
+
import { readCatalogSourcesConfigSnapshot, recoverInvalidCatalogSourcesConfig, } from '../utils/catalog-sources.js';
|
|
8
|
+
import { withResolvedCatalogPlugin, withResolvedMultiSourceCatalog, formatPluginId, parsePluginId, } from '../utils/multi-source-catalog.js';
|
|
9
|
+
import { coercePluginConfigUpdates, inspectPluginConfigResetTarget, readPluginConfigStore, resolveConfigRead, resolveEffectivePluginConfig, } from '../utils/plugin-config.js';
|
|
10
|
+
import { applyPluginConfigWrite, replayConfigRuntimeWrites, resetPluginConfigWithHelper, } from '../utils/plugin-config-write.js';
|
|
11
|
+
import { offlineCleanupEvidenceFromInventory, } from '../commands/offline-cleanup-evidence.js';
|
|
12
|
+
import { inventoryCatalogSourceReferences } from '../utils/catalog-source-references.js';
|
|
13
|
+
import { operationEvidenceMatches, operationEvidenceFingerprint, TuiConfigInvalidStoreError, TuiController, TuiOperationBlockedError, } from './controller.js';
|
|
14
|
+
import { buildConfigGroups, buildConfigPage, projectPlatformPlacement, } from './model.js';
|
|
15
|
+
import { projectCatalogSourceLocation } from '../utils/catalog-source-presentation.js';
|
|
16
|
+
import { calculateCatalogSourceConfigFingerprint, calculateCatalogSourceIdentity, } from '../utils/catalog-source-identity.js';
|
|
17
|
+
import { checkAwCapabilitySupport, readPluginManifest } from '../utils/manifest.js';
|
|
18
|
+
import { withAwHomeMutationLock } from '../utils/aw-home-mutation-lock.js';
|
|
19
|
+
import { IMPLEMENTED_AW_CAPABILITIES } from '../commands/aw-capabilities.js';
|
|
20
|
+
import { calculateCatalogGenerationSetDigest, resolveActiveCatalogGeneration, } from '../utils/catalog-generation-resolver.js';
|
|
21
|
+
import { resolveCatalogOperationContext, resolvePartialCatalogOperationContext, selectCatalogOperationContext, } from '../utils/catalog-operation-context.js';
|
|
22
|
+
import { createCatalogStoreKey, readCatalogStoreEntry, } from '../utils/catalog-generation-store.js';
|
|
23
|
+
import { activateCatalogSourceGeneration, compareCatalogGenerationFreshness, probeCatalogSourceFreshness, probeCatalogSourceGeneration, probeCatalogSourceRepairGeneration, recoverCatalogGenerationStateAndActivate, repairCatalogSourceGeneration, replaceDamagedCatalogSourceGeneration, syncCatalogSourceGeneration, } from '../utils/catalog-generation-service.js';
|
|
24
|
+
import { calculateCatalogSourceImpactDigest, inspectCatalogSourceImpact, } from '../utils/catalog-source-impact.js';
|
|
25
|
+
import { readCatalogGenerationState } from '../utils/catalog-generation-state.js';
|
|
26
|
+
import { CatalogGenerationError } from '../utils/catalog-generation-error.js';
|
|
27
|
+
import { CatalogProviderCompatibilityError } from '../utils/catalog-public-error.js';
|
|
28
|
+
import { loadCatalogGenerationViewModels } from './catalog-generation.js';
|
|
29
|
+
import { installPortableSkills, preparePortableInstall, PortableCommandError, } from '../portable/commands.js';
|
|
30
|
+
import { MANAGED_CODEX_PACKAGE_NAME, MANAGED_CODEX_VERSION, } from '../utils/codex-manager.js';
|
|
31
|
+
function reusableCandidateEvidenceIsComplete(candidate) {
|
|
32
|
+
const evidence = candidate.probe.candidate;
|
|
33
|
+
return [
|
|
34
|
+
evidence.sourceConfigFingerprint,
|
|
35
|
+
evidence.sourceIdentity,
|
|
36
|
+
evidence.logicalIdentity,
|
|
37
|
+
evidence.requestedRef,
|
|
38
|
+
evidence.resolvedCommit,
|
|
39
|
+
evidence.catalogVersion,
|
|
40
|
+
evidence.channel,
|
|
41
|
+
evidence.manifestDigest,
|
|
42
|
+
evidence.snapshotDigest,
|
|
43
|
+
].every((value) => typeof value === 'string' && value.length > 0)
|
|
44
|
+
&& typeof candidate.probe.manifest === 'object'
|
|
45
|
+
&& candidate.probe.manifest !== null;
|
|
46
|
+
}
|
|
47
|
+
async function loadPortablePluginIds(options) {
|
|
48
|
+
return withResolvedMultiSourceCatalog({
|
|
49
|
+
cliVersion: options.cliVersion,
|
|
50
|
+
env: options.context.env,
|
|
51
|
+
signal: options.signal,
|
|
52
|
+
...(options.catalogOperationContext
|
|
53
|
+
? { operationContext: options.catalogOperationContext }
|
|
54
|
+
: {}),
|
|
55
|
+
consume: async (catalog) => (await Promise.all(catalog.sources.flatMap((item) => item.resolution
|
|
56
|
+
? item.resolution.manifest.entries.flatMap((entry) => {
|
|
57
|
+
const support = checkAwCapabilitySupport(entry.requires.aw.capabilities ?? [], IMPLEMENTED_AW_CAPABILITIES);
|
|
58
|
+
return support.supported
|
|
59
|
+
? [readPluginManifest(path.join(item.resolution.rootDir, 'plugins', entry.name), { mode: 'bundle' }).then((plugin) => plugin.manifest.distributions?.agentSkills
|
|
60
|
+
? formatPluginId({
|
|
61
|
+
sourceId: item.resolution.sourceId,
|
|
62
|
+
pluginName: entry.name,
|
|
63
|
+
})
|
|
64
|
+
: null)]
|
|
65
|
+
: [];
|
|
66
|
+
})
|
|
67
|
+
: []))).filter((pluginId) => pluginId !== null),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
let tuiControllerRuntimeTestHooks;
|
|
71
|
+
export function setTuiControllerRuntimeTestHooksForTests(hooks) {
|
|
72
|
+
tuiControllerRuntimeTestHooks = hooks;
|
|
73
|
+
}
|
|
74
|
+
function digest(value) {
|
|
75
|
+
return `sha256:${crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex')}`;
|
|
76
|
+
}
|
|
77
|
+
export function statusTargetFingerprint(targets, revisions = []) {
|
|
78
|
+
return digest({
|
|
79
|
+
targets: targets.map((target) => ({
|
|
80
|
+
pluginId: target.pluginId,
|
|
81
|
+
sourceIdentity: target.sourceIdentity,
|
|
82
|
+
platform: target.platform,
|
|
83
|
+
scope: target.scope,
|
|
84
|
+
state: target.state,
|
|
85
|
+
errors: target.reasons.map((error) => error.code).sort(),
|
|
86
|
+
components: target.components.map((component) => [component.key, component.state])
|
|
87
|
+
.sort(([left], [right]) => left.localeCompare(right, 'en')),
|
|
88
|
+
})).sort((left, right) => [left.pluginId, left.platform, left.scope].join('\0')
|
|
89
|
+
.localeCompare([right.pluginId, right.platform, right.scope].join('\0'), 'en')),
|
|
90
|
+
revisions: revisions.map((entry) => ({
|
|
91
|
+
pluginId: entry.pluginId,
|
|
92
|
+
platform: entry.platform,
|
|
93
|
+
scope: entry.scope,
|
|
94
|
+
revision: entry.revision,
|
|
95
|
+
})).sort((left, right) => [left.pluginId, left.platform, left.scope].join('\0')
|
|
96
|
+
.localeCompare([right.pluginId, right.platform, right.scope].join('\0'), 'en')),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
export function configAffectedStatusTargets(targets, pluginId, configScope) {
|
|
100
|
+
const affected = new Map();
|
|
101
|
+
for (const target of targets) {
|
|
102
|
+
const intent = statusTargetIntent(target);
|
|
103
|
+
if (target.pluginId !== pluginId || !intent.enabled)
|
|
104
|
+
continue;
|
|
105
|
+
for (const scope of intent.scopes) {
|
|
106
|
+
if (configScope === 'project' && scope !== 'project')
|
|
107
|
+
continue;
|
|
108
|
+
affected.set(`${target.platform}\0${scope}`, { ...target, scope });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [...affected.values()]
|
|
112
|
+
.sort((left, right) => `${left.platform}\0${left.scope}`
|
|
113
|
+
.localeCompare(`${right.platform}\0${right.scope}`, 'en'));
|
|
114
|
+
}
|
|
115
|
+
function configSharedNativeRenderTargets(plugin, changedKeys) {
|
|
116
|
+
const changed = new Set(changedKeys);
|
|
117
|
+
return (plugin.manifest.artifacts?.targets ?? []).flatMap((target) => target.platform === 'codex'
|
|
118
|
+
&& target.target === 'codex.skill'
|
|
119
|
+
&& target.delivery.mode === 'codex-native'
|
|
120
|
+
&& target.skillKey
|
|
121
|
+
&& target.refreshKeys.some((key) => changed.has(key))
|
|
122
|
+
? [{ id: target.id, skillKey: target.skillKey, refreshKeys: [...target.refreshKeys] }]
|
|
123
|
+
: []);
|
|
124
|
+
}
|
|
125
|
+
function operationReviewStale(message) {
|
|
126
|
+
return new TuiOperationBlockedError('operationReviewStale', `operationReviewStale: ${message}`);
|
|
127
|
+
}
|
|
128
|
+
function sourceEvidenceForPlugin(source, pluginName) {
|
|
129
|
+
const entry = source.manifest.entries.find((candidate) => candidate.name === pluginName);
|
|
130
|
+
return {
|
|
131
|
+
sourceId: source.sourceId,
|
|
132
|
+
sourceIdentity: source.sourceIdentity,
|
|
133
|
+
requestedRef: source.requestedRef,
|
|
134
|
+
resolvedCommit: source.resolvedCommit,
|
|
135
|
+
manifestDigest: source.manifestDigest,
|
|
136
|
+
snapshotDigest: source.snapshotDigest,
|
|
137
|
+
contentDigest: entry.contentDigest,
|
|
138
|
+
pluginVersion: entry.version,
|
|
139
|
+
catalogVersion: source.manifest.catalogVersion,
|
|
140
|
+
channel: source.manifest.channel,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function assertSourceEvidenceMatches(expected, actual) {
|
|
144
|
+
if (actual.sourceId !== expected.sourceId
|
|
145
|
+
|| actual.sourceIdentity !== expected.sourceIdentity
|
|
146
|
+
|| actual.resolvedCommit !== expected.resolvedCommit
|
|
147
|
+
|| actual.manifestDigest !== expected.manifestDigest
|
|
148
|
+
|| actual.snapshotDigest !== expected.snapshotDigest
|
|
149
|
+
|| actual.contentDigest !== expected.contentDigest) {
|
|
150
|
+
throw operationReviewStale('确认后来源内容发生变化。');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function throwIfWriteReviewStale(result) {
|
|
154
|
+
const stale = result.targetResults.find((target) => target.errorCode === 'operationReviewStale'
|
|
155
|
+
|| target.errorCode === 'operationPlanStale');
|
|
156
|
+
if (stale) {
|
|
157
|
+
throw operationReviewStale('确认后实际写入计划发生变化。');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const SOURCE_PROGRESS_PHASES = {
|
|
161
|
+
savingConfig: '保存来源配置',
|
|
162
|
+
};
|
|
163
|
+
function pluginIntent(intent) {
|
|
164
|
+
return 'pluginId' in intent;
|
|
165
|
+
}
|
|
166
|
+
async function loadDependencyOverviews(options) {
|
|
167
|
+
const graph = await withResolvedMultiSourceCatalog({
|
|
168
|
+
cliVersion: options.cliVersion,
|
|
169
|
+
env: options.context.env,
|
|
170
|
+
signal: options.signal,
|
|
171
|
+
...(options.catalogOperationContext
|
|
172
|
+
? { operationContext: options.catalogOperationContext }
|
|
173
|
+
: {}),
|
|
174
|
+
consume: async (catalog) => ({
|
|
175
|
+
nodes: catalog.sources.flatMap((item) => item.resolution
|
|
176
|
+
? item.resolution.manifest.entries.map((entry) => ({
|
|
177
|
+
pluginId: formatPluginId({
|
|
178
|
+
sourceId: item.resolution.sourceId,
|
|
179
|
+
pluginName: entry.name,
|
|
180
|
+
}),
|
|
181
|
+
displayName: entry.interface?.displayName ?? entry.name,
|
|
182
|
+
dependencies: entry.dependencies.map((pluginName) => formatPluginId({ sourceId: item.resolution.sourceId, pluginName })),
|
|
183
|
+
}))
|
|
184
|
+
: []),
|
|
185
|
+
sourceErrors: catalog.sources.flatMap((item) => item.error
|
|
186
|
+
? [{ sourceId: item.sourceId, code: 'dependencyGraphInvalid' }]
|
|
187
|
+
: []),
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
const nodes = new Map(graph.nodes.map((node) => [node.pluginId, node]));
|
|
191
|
+
const summaryById = new Map(options.status.pluginSummaries.map((summary) => [summary.pluginId, summary]));
|
|
192
|
+
const displayName = (pluginId) => nodes.get(pluginId)?.displayName
|
|
193
|
+
?? parsePluginId(pluginId).pluginName;
|
|
194
|
+
const reverse = new Map();
|
|
195
|
+
for (const node of graph.nodes) {
|
|
196
|
+
for (const dependency of node.dependencies) {
|
|
197
|
+
reverse.set(dependency, [...(reverse.get(dependency) ?? []), node.pluginId]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const targetsByPlugin = new Map();
|
|
201
|
+
for (const target of options.status.payload.targets) {
|
|
202
|
+
targetsByPlugin.set(target.pluginId, [...(targetsByPlugin.get(target.pluginId) ?? []), target]);
|
|
203
|
+
}
|
|
204
|
+
const unsupportedPluginIds = new Set(options.status.pluginSummaries
|
|
205
|
+
.filter((summary) => (summary.missingCapabilities?.length ?? 0) > 0)
|
|
206
|
+
.map((summary) => summary.pluginId));
|
|
207
|
+
const placementReferences = new Map();
|
|
208
|
+
for (const consumer of options.status.payload.targets.filter((target) => target.state !== 'absent')) {
|
|
209
|
+
const consumerNode = nodes.get(consumer.pluginId);
|
|
210
|
+
if (!consumerNode)
|
|
211
|
+
continue;
|
|
212
|
+
for (const dependencyPluginId of consumerNode.dependencies) {
|
|
213
|
+
const dependencyTargets = (targetsByPlugin.get(dependencyPluginId) ?? [])
|
|
214
|
+
.filter((target) => target.platform === consumer.platform);
|
|
215
|
+
const projectTarget = dependencyTargets.find((target) => target.scope === 'project');
|
|
216
|
+
const userTarget = dependencyTargets.find((target) => target.scope === 'user');
|
|
217
|
+
const dependencyScope = consumer.scope === 'user'
|
|
218
|
+
? 'user'
|
|
219
|
+
: userTarget && (!projectTarget
|
|
220
|
+
|| (userTarget.state !== 'absent' && projectTarget.state === 'absent'))
|
|
221
|
+
? 'user'
|
|
222
|
+
: 'project';
|
|
223
|
+
const reference = {
|
|
224
|
+
consumer: {
|
|
225
|
+
pluginId: consumer.pluginId,
|
|
226
|
+
platform: consumer.platform,
|
|
227
|
+
scope: consumer.scope,
|
|
228
|
+
project: consumer.scope === 'project' ? 'current' : null,
|
|
229
|
+
},
|
|
230
|
+
dependency: {
|
|
231
|
+
pluginId: dependencyPluginId,
|
|
232
|
+
platform: consumer.platform,
|
|
233
|
+
scope: dependencyScope,
|
|
234
|
+
project: dependencyScope === 'project' ? 'current' : null,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
const key = `${consumer.pluginId}\0${dependencyPluginId}`;
|
|
238
|
+
placementReferences.set(key, [...(placementReferences.get(key) ?? []), reference]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const placementsFor = (pluginId) => {
|
|
242
|
+
const targets = targetsByPlugin.get(pluginId) ?? [];
|
|
243
|
+
if (targets.length > 0) {
|
|
244
|
+
return ['codex', 'claude'].flatMap((platform) => {
|
|
245
|
+
const selected = targets.filter((target) => target.platform === platform);
|
|
246
|
+
return selected.length > 0 ? [projectPlatformPlacement(platform, selected)] : [];
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return [];
|
|
250
|
+
};
|
|
251
|
+
const aggregateFor = (pluginId, placements) => {
|
|
252
|
+
const sourceId = parsePluginId(pluginId).sourceId;
|
|
253
|
+
if (graph.sourceErrors.some((error) => error.sourceId === sourceId)
|
|
254
|
+
|| unsupportedPluginIds.has(pluginId))
|
|
255
|
+
return 'unavailable';
|
|
256
|
+
if (placements.length === 0 || placements.every((placement) => placement.state === 'notInstalled')) {
|
|
257
|
+
return 'notInstalled';
|
|
258
|
+
}
|
|
259
|
+
return placements.some((placement) => placement.state === 'scopeConflict'
|
|
260
|
+
|| (placement.state === 'installed'
|
|
261
|
+
&& (placement.health !== 'ready' || placement.blockingReason !== undefined)))
|
|
262
|
+
? 'needsAttention'
|
|
263
|
+
: 'ready';
|
|
264
|
+
};
|
|
265
|
+
const allPluginIds = new Set([
|
|
266
|
+
...nodes.keys(),
|
|
267
|
+
...reverse.keys(),
|
|
268
|
+
...targetsByPlugin.keys(),
|
|
269
|
+
]);
|
|
270
|
+
return [...allPluginIds].sort().map((pluginId) => {
|
|
271
|
+
const dependencies = [];
|
|
272
|
+
const seen = new Set([pluginId]);
|
|
273
|
+
let frontier = [pluginId];
|
|
274
|
+
let depth = 0;
|
|
275
|
+
let graphInvalid = false;
|
|
276
|
+
while (frontier.length > 0) {
|
|
277
|
+
depth += 1;
|
|
278
|
+
const next = [];
|
|
279
|
+
const requiredBy = new Map();
|
|
280
|
+
for (const parent of frontier) {
|
|
281
|
+
for (const dependency of nodes.get(parent)?.dependencies ?? []) {
|
|
282
|
+
const parents = requiredBy.get(dependency) ?? new Set();
|
|
283
|
+
parents.add(parent);
|
|
284
|
+
requiredBy.set(dependency, parents);
|
|
285
|
+
if (seen.has(dependency)) {
|
|
286
|
+
if (dependency === pluginId)
|
|
287
|
+
graphInvalid = true;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
seen.add(dependency);
|
|
291
|
+
next.push(dependency);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
for (const dependency of next) {
|
|
295
|
+
dependencies.push({ pluginId: dependency, depth, requiredBy: [...(requiredBy.get(dependency) ?? [])] });
|
|
296
|
+
}
|
|
297
|
+
frontier = next;
|
|
298
|
+
}
|
|
299
|
+
const dependencyItems = dependencies.map((dependency) => {
|
|
300
|
+
const placements = placementsFor(dependency.pluginId);
|
|
301
|
+
return {
|
|
302
|
+
pluginId: dependency.pluginId,
|
|
303
|
+
displayName: displayName(dependency.pluginId),
|
|
304
|
+
relation: dependency.depth === 1 ? 'direct' : 'transitive',
|
|
305
|
+
depth: dependency.depth,
|
|
306
|
+
requiredBy: dependency.requiredBy.map((requiredBy) => ({
|
|
307
|
+
pluginId: requiredBy,
|
|
308
|
+
displayName: displayName(requiredBy),
|
|
309
|
+
})),
|
|
310
|
+
placements,
|
|
311
|
+
aggregateStatus: aggregateFor(dependency.pluginId, placements),
|
|
312
|
+
placementReferences: placementReferences.get(`${pluginId}\0${dependency.pluginId}`) ?? [],
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
const dependentIds = [...new Set(reverse.get(pluginId) ?? [])].sort();
|
|
316
|
+
const dependents = dependentIds.map((dependentId) => {
|
|
317
|
+
const placements = placementsFor(dependentId);
|
|
318
|
+
return {
|
|
319
|
+
pluginId: dependentId,
|
|
320
|
+
displayName: displayName(dependentId),
|
|
321
|
+
relation: 'dependent',
|
|
322
|
+
depth: 1,
|
|
323
|
+
requiredBy: [],
|
|
324
|
+
placements,
|
|
325
|
+
aggregateStatus: aggregateFor(dependentId, placements),
|
|
326
|
+
placementReferences: placementReferences.get(`${dependentId}\0${pluginId}`) ?? [],
|
|
327
|
+
};
|
|
328
|
+
});
|
|
329
|
+
const targetBlockers = (targetsByPlugin.get(pluginId) ?? []).flatMap((target) => target.reasons.filter((error) => error.code.startsWith('dependency') || error.code === 'sourceChanged')
|
|
330
|
+
.map((error) => ({
|
|
331
|
+
code: error.code,
|
|
332
|
+
title: '依赖关系需要处理',
|
|
333
|
+
explanation: '当前目标的依赖证据不能安全通过检查。',
|
|
334
|
+
})));
|
|
335
|
+
const consumerTargets = summaryById.get(pluginId)?.supportedTargets;
|
|
336
|
+
const unsupportedDependency = dependencyItems.find((dependency) => {
|
|
337
|
+
const dependencyTargets = summaryById.get(dependency.pluginId)?.supportedTargets;
|
|
338
|
+
if (!consumerTargets || !dependencyTargets)
|
|
339
|
+
return true;
|
|
340
|
+
return ['codex', 'claude'].some((platform) => consumerTargets[platform].length > 0 && dependencyTargets[platform].length === 0);
|
|
341
|
+
});
|
|
342
|
+
const sourceId = parsePluginId(pluginId).sourceId;
|
|
343
|
+
const blockers = [
|
|
344
|
+
...graph.sourceErrors.filter((error) => error.sourceId === sourceId).map((error) => ({
|
|
345
|
+
code: error.code,
|
|
346
|
+
title: '来源依赖关系不可用',
|
|
347
|
+
explanation: '当前来源快照不能安全读取。反向安装记录仍可显示。',
|
|
348
|
+
})),
|
|
349
|
+
...(graphInvalid ? [{
|
|
350
|
+
code: 'dependencyGraphInvalid',
|
|
351
|
+
title: '依赖关系无效',
|
|
352
|
+
explanation: '依赖关系形成环。',
|
|
353
|
+
}] : []),
|
|
354
|
+
...(unsupportedDependency ? [{
|
|
355
|
+
code: 'dependencyTargetUnsupported',
|
|
356
|
+
title: '依赖目标不兼容',
|
|
357
|
+
explanation: `${unsupportedDependency.displayName} 不支持根插件所需的平台。`,
|
|
358
|
+
}] : []),
|
|
359
|
+
...targetBlockers,
|
|
360
|
+
];
|
|
361
|
+
const directCount = dependencyItems.filter((item) => item.relation === 'direct').length;
|
|
362
|
+
const readyCount = dependencyItems.filter((item) => item.aggregateStatus === 'ready').length;
|
|
363
|
+
const missingCount = dependencyItems.filter((item) => item.aggregateStatus === 'notInstalled').length;
|
|
364
|
+
const issueCount = dependencyItems.length - readyCount - missingCount + blockers.length;
|
|
365
|
+
return {
|
|
366
|
+
pluginId,
|
|
367
|
+
summary: {
|
|
368
|
+
directCount,
|
|
369
|
+
transitiveCount: dependencyItems.length - directCount,
|
|
370
|
+
totalCount: dependencyItems.length,
|
|
371
|
+
readyCount,
|
|
372
|
+
missingCount,
|
|
373
|
+
issueCount,
|
|
374
|
+
},
|
|
375
|
+
dependencies: dependencyItems,
|
|
376
|
+
dependents,
|
|
377
|
+
blockers,
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function createReviewStageReporter(options) {
|
|
382
|
+
let active;
|
|
383
|
+
const finish = async () => {
|
|
384
|
+
if (!active)
|
|
385
|
+
return;
|
|
386
|
+
const completed = active;
|
|
387
|
+
active = undefined;
|
|
388
|
+
await Promise.allSettled([Promise.resolve().then(() => options.context.debugLogger.log({
|
|
389
|
+
type: `review.prepare.${completed.stage}`,
|
|
390
|
+
level: 'debug',
|
|
391
|
+
target: 'debugLog',
|
|
392
|
+
message: 'TUI review preparation stage completed.',
|
|
393
|
+
data: { durationMs: Math.max(0, options.now() - completed.startedAt) },
|
|
394
|
+
}))]);
|
|
395
|
+
};
|
|
396
|
+
return {
|
|
397
|
+
async emit(stage) {
|
|
398
|
+
await finish();
|
|
399
|
+
active = { stage, startedAt: options.now() };
|
|
400
|
+
await options.onStage(stage);
|
|
401
|
+
},
|
|
402
|
+
finish,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
export function createTuiControllerDependencies(context, progressFeed, options = {}) {
|
|
406
|
+
const readInventory = options.inventoryCatalogSourceReferences
|
|
407
|
+
?? inventoryCatalogSourceReferences;
|
|
408
|
+
const validatedStoreEntries = new Map();
|
|
409
|
+
const validatingStoreEntries = new Map();
|
|
410
|
+
const loadCatalogGenerations = async () => {
|
|
411
|
+
const generations = await loadCatalogGenerationViewModels({
|
|
412
|
+
env: context.env,
|
|
413
|
+
validatedStoreEntries,
|
|
414
|
+
validatingStoreEntries,
|
|
415
|
+
onStage: (event) => context.debugLogger.log({
|
|
416
|
+
type: 'performance:stage',
|
|
417
|
+
level: 'debug',
|
|
418
|
+
target: 'debugLog',
|
|
419
|
+
message: 'Catalog generation load stage completed.',
|
|
420
|
+
data: event,
|
|
421
|
+
}),
|
|
422
|
+
});
|
|
423
|
+
const retained = new Set(generations.flatMap((source) => [
|
|
424
|
+
source.active?.storeKey,
|
|
425
|
+
].filter((value) => value !== undefined)));
|
|
426
|
+
for (const storeKey of validatedStoreEntries.keys()) {
|
|
427
|
+
if (!retained.has(storeKey))
|
|
428
|
+
validatedStoreEntries.delete(storeKey);
|
|
429
|
+
}
|
|
430
|
+
return generations;
|
|
431
|
+
};
|
|
432
|
+
const createOperationInventoryReader = () => {
|
|
433
|
+
let ordinaryInventory;
|
|
434
|
+
return (inventoryOptions) => {
|
|
435
|
+
ordinaryInventory ??= readInventory(inventoryOptions);
|
|
436
|
+
return ordinaryInventory;
|
|
437
|
+
};
|
|
438
|
+
};
|
|
439
|
+
const catalogOperationByEvidence = new WeakMap();
|
|
440
|
+
let sessionCatalogOperationContext;
|
|
441
|
+
let sessionStatusResult;
|
|
442
|
+
const sessionContextForPlugin = (pluginId) => {
|
|
443
|
+
const sourceId = parsePluginId(pluginId).sourceId;
|
|
444
|
+
if (!sourceId || !sessionCatalogOperationContext)
|
|
445
|
+
return undefined;
|
|
446
|
+
return selectCatalogOperationContext(sessionCatalogOperationContext, [sourceId]);
|
|
447
|
+
};
|
|
448
|
+
const readConfigStoresForTui = async (config) => {
|
|
449
|
+
const scopes = config.scope === 'user' ? ['user'] : ['user', 'project'];
|
|
450
|
+
const stores = await Promise.all(scopes.map((scope) => readPluginConfigStore({
|
|
451
|
+
sourceId: config.sourceId,
|
|
452
|
+
sourceIdentity: config.sourceIdentity,
|
|
453
|
+
pluginName: config.pluginName,
|
|
454
|
+
scope,
|
|
455
|
+
cwd: context.cwd,
|
|
456
|
+
env: context.env,
|
|
457
|
+
schema: config.schema,
|
|
458
|
+
})));
|
|
459
|
+
const user = stores[0];
|
|
460
|
+
const project = config.scope === 'user' ? undefined : stores[1];
|
|
461
|
+
config.signal.throwIfAborted();
|
|
462
|
+
const invalidStores = ([
|
|
463
|
+
{ scope: 'user', store: user },
|
|
464
|
+
...(project ? [{ scope: 'project', store: project }] : []),
|
|
465
|
+
]).flatMap(({ scope, store }) => store.state === 'invalid' ? [{
|
|
466
|
+
scope,
|
|
467
|
+
code: store.invalidCode,
|
|
468
|
+
pathSummary: scope === 'user'
|
|
469
|
+
? `AW_HOME/plugin-config/${config.sourceId ?? '<source>'}/${config.pluginName}/config.json`
|
|
470
|
+
: `<project>/.agent-workflows/plugin-config/${config.sourceId ?? '<source>'}/${config.pluginName}/config.json`,
|
|
471
|
+
}] : []);
|
|
472
|
+
if (invalidStores.length > 0)
|
|
473
|
+
throw new TuiConfigInvalidStoreError(invalidStores);
|
|
474
|
+
return { user, ...(project ? { project } : {}) };
|
|
475
|
+
};
|
|
476
|
+
const loadStatus = async (signal) => {
|
|
477
|
+
signal.throwIfAborted();
|
|
478
|
+
const packageInfo = await readCliPackageInfo();
|
|
479
|
+
const catalogOperationContext = sessionCatalogOperationContext
|
|
480
|
+
?? await resolvePartialCatalogOperationContext({
|
|
481
|
+
env: context.env,
|
|
482
|
+
signal,
|
|
483
|
+
validatedStoreEntries,
|
|
484
|
+
validatingStoreEntries,
|
|
485
|
+
}).catch(async (error) => {
|
|
486
|
+
if (!(error instanceof CatalogGenerationError)
|
|
487
|
+
|| error.code !== 'catalogGenerationStateInvalid')
|
|
488
|
+
return undefined;
|
|
489
|
+
const snapshot = await readCatalogSourcesConfigSnapshot(context.env);
|
|
490
|
+
const primarySourceId = snapshot.config.sources.find((source) => source.primary).id;
|
|
491
|
+
const generationSetDigest = calculateCatalogGenerationSetDigest(snapshot.digest, primarySourceId, []);
|
|
492
|
+
return {
|
|
493
|
+
generationSet: {
|
|
494
|
+
generationSetDigest,
|
|
495
|
+
configDigest: snapshot.digest,
|
|
496
|
+
primarySourceId,
|
|
497
|
+
sources: [],
|
|
498
|
+
},
|
|
499
|
+
generationSetDigest,
|
|
500
|
+
catalog: {
|
|
501
|
+
sources: snapshot.config.sources.map((source) => ({
|
|
502
|
+
sourceId: source.id,
|
|
503
|
+
error,
|
|
504
|
+
})),
|
|
505
|
+
primarySourceId,
|
|
506
|
+
configDigest: snapshot.digest,
|
|
507
|
+
compositeDigest: generationSetDigest,
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
});
|
|
511
|
+
if (catalogOperationContext)
|
|
512
|
+
sessionCatalogOperationContext = catalogOperationContext;
|
|
513
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
514
|
+
const result = await statusCommandV7({
|
|
515
|
+
cwd: context.cwd,
|
|
516
|
+
env: context.env,
|
|
517
|
+
cliVersion: packageInfo.version,
|
|
518
|
+
verbose: context.diagnostics.verbose,
|
|
519
|
+
...(catalogOperationContext ? { catalogOperationContext } : {}),
|
|
520
|
+
inventoryCatalogSourceReferences: readInventory,
|
|
521
|
+
});
|
|
522
|
+
signal.throwIfAborted();
|
|
523
|
+
const configured = await listCatalogSources({ env: context.env });
|
|
524
|
+
signal.throwIfAborted();
|
|
525
|
+
if (result.payload.catalog.configDigest !== configured.configDigest)
|
|
526
|
+
continue;
|
|
527
|
+
sessionStatusResult = result;
|
|
528
|
+
const dependencyOverviews = await loadDependencyOverviews({
|
|
529
|
+
context,
|
|
530
|
+
cliVersion: packageInfo.version,
|
|
531
|
+
status: result,
|
|
532
|
+
signal,
|
|
533
|
+
...(catalogOperationContext ? { catalogOperationContext } : {}),
|
|
534
|
+
});
|
|
535
|
+
const portablePluginIds = await loadPortablePluginIds({
|
|
536
|
+
context,
|
|
537
|
+
cliVersion: packageInfo.version,
|
|
538
|
+
signal,
|
|
539
|
+
...(catalogOperationContext ? { catalogOperationContext } : {}),
|
|
540
|
+
});
|
|
541
|
+
signal.throwIfAborted();
|
|
542
|
+
const catalogGenerations = await loadCatalogGenerations();
|
|
543
|
+
signal.throwIfAborted();
|
|
544
|
+
const statusById = new Map(result.payload.catalog.sources.map((source) => [source.id, source]));
|
|
545
|
+
return {
|
|
546
|
+
cliChannel: packageInfo.version.includes('-') ? 'beta' : 'latest',
|
|
547
|
+
payload: result.payload,
|
|
548
|
+
pluginSummaries: result.pluginSummaries,
|
|
549
|
+
targetRevisions: result.targetRevisions,
|
|
550
|
+
dependencyOverviews,
|
|
551
|
+
portablePluginIds,
|
|
552
|
+
catalogGenerations,
|
|
553
|
+
sessionGenerationKeys: Object.fromEntries((catalogOperationContext?.generationSet.sources ?? [])
|
|
554
|
+
.map((source) => [source.sourceId, source.storeKey])),
|
|
555
|
+
sourceDetails: configured.sources.map((source) => {
|
|
556
|
+
const status = statusById.get(source.id);
|
|
557
|
+
return {
|
|
558
|
+
id: source.id,
|
|
559
|
+
type: source.type,
|
|
560
|
+
primary: source.primary,
|
|
561
|
+
autoCheck: source.autoCheck,
|
|
562
|
+
locationSummary: projectCatalogSourceLocation(source.type === 'git' ? source.url : source.path),
|
|
563
|
+
...(source.type === 'git' ? {
|
|
564
|
+
refPolicy: source.refPolicy.type,
|
|
565
|
+
...(source.refPolicy.type === 'explicit' ? { explicitRef: source.refPolicy.ref } : {}),
|
|
566
|
+
...(source.subdir ? { subdir: source.subdir } : {}),
|
|
567
|
+
} : {}),
|
|
568
|
+
pluginCount: 0,
|
|
569
|
+
sourceIdentity: source.sourceIdentity,
|
|
570
|
+
requestedRef: status?.requestedRef ?? (source.type === 'path' ? 'path' : 'AW channel'),
|
|
571
|
+
...(status?.resolvedCommit ? { resolvedCommit: status.resolvedCommit } : {}),
|
|
572
|
+
...(status?.catalogVersion ? { catalogVersion: status.catalogVersion } : {}),
|
|
573
|
+
...(status?.channel ? { channel: status.channel } : {}),
|
|
574
|
+
...(status?.freshness ? { freshness: status.freshness } : {}),
|
|
575
|
+
...(status?.errorCode ? { errorCode: status.errorCode } : {}),
|
|
576
|
+
configDigest: configured.configDigest,
|
|
577
|
+
};
|
|
578
|
+
}),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
throw new TuiOperationBlockedError('operationReviewStale', '状态读取期间来源配置持续变化。请重试。');
|
|
582
|
+
};
|
|
583
|
+
const captureEvidence = async (intent, signal, preparation, operationInventory = createOperationInventoryReader(), freshCatalog = false, reusableCandidate) => {
|
|
584
|
+
if (intent.kind === 'configReset') {
|
|
585
|
+
const parsed = parsePluginId(intent.pluginId);
|
|
586
|
+
if (!parsed.sourceId || !parsed.pluginName) {
|
|
587
|
+
throw new TuiOperationBlockedError('invalidPluginId', '设置目标必须使用 canonical pluginId。');
|
|
588
|
+
}
|
|
589
|
+
await preparation?.reporter.emit('config');
|
|
590
|
+
const target = await inspectPluginConfigResetTarget({
|
|
591
|
+
sourceId: parsed.sourceId,
|
|
592
|
+
pluginName: parsed.pluginName,
|
|
593
|
+
scope: intent.scope,
|
|
594
|
+
cwd: context.cwd,
|
|
595
|
+
env: context.env,
|
|
596
|
+
});
|
|
597
|
+
signal?.throwIfAborted();
|
|
598
|
+
if (target.kind === 'special') {
|
|
599
|
+
throw new TuiOperationBlockedError('configResetTargetUnsupported', '设置目标是特殊文件系统节点,不能自动重置。请手动移动后重试。');
|
|
600
|
+
}
|
|
601
|
+
let source;
|
|
602
|
+
try {
|
|
603
|
+
const packageInfo = await readCliPackageInfo();
|
|
604
|
+
source = await withResolvedCatalogPlugin({
|
|
605
|
+
selector: intent.pluginId,
|
|
606
|
+
cliVersion: packageInfo.version,
|
|
607
|
+
env: context.env,
|
|
608
|
+
...(preparation && sessionContextForPlugin(intent.pluginId)
|
|
609
|
+
? { operationContext: sessionContextForPlugin(intent.pluginId) }
|
|
610
|
+
: {}),
|
|
611
|
+
...(signal ? { signal } : {}),
|
|
612
|
+
consume: async ({ plugin, source: resolvedSource }) => sourceEvidenceForPlugin(resolvedSource, plugin.manifest.name),
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
catch {
|
|
616
|
+
source = undefined;
|
|
617
|
+
}
|
|
618
|
+
signal?.throwIfAborted();
|
|
619
|
+
const relevantTargets = sessionStatusResult
|
|
620
|
+
? configAffectedStatusTargets(sessionStatusResult.payload.targets, intent.pluginId, intent.scope)
|
|
621
|
+
: [];
|
|
622
|
+
await preparation?.reporter.emit('evidence');
|
|
623
|
+
return {
|
|
624
|
+
catalog: sessionStatusResult ? {
|
|
625
|
+
configDigest: sessionStatusResult.payload.catalog.configDigest,
|
|
626
|
+
compositeDigest: sessionStatusResult.payload.catalog.compositeDigest,
|
|
627
|
+
} : {
|
|
628
|
+
configDigest: 'config-reset-offline',
|
|
629
|
+
compositeDigest: 'config-reset-target',
|
|
630
|
+
},
|
|
631
|
+
...(source ? { source } : {}),
|
|
632
|
+
config: {
|
|
633
|
+
scope: intent.scope,
|
|
634
|
+
storeDigest: target.fingerprint,
|
|
635
|
+
affectedTargets: relevantTargets.map(({ platform, scope }) => ({ platform, scope })),
|
|
636
|
+
},
|
|
637
|
+
resetTarget: {
|
|
638
|
+
sourceId: parsed.sourceId,
|
|
639
|
+
pluginName: parsed.pluginName,
|
|
640
|
+
scope: intent.scope,
|
|
641
|
+
kind: target.kind,
|
|
642
|
+
fingerprint: target.fingerprint,
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
if (intent.kind === 'catalogSourcesRecovery') {
|
|
647
|
+
signal?.throwIfAborted();
|
|
648
|
+
await preparation?.reporter.emit('validate');
|
|
649
|
+
await preparation?.reporter.emit('evidence');
|
|
650
|
+
return {
|
|
651
|
+
catalog: {
|
|
652
|
+
configDigest: 'invalid-catalog-sources-config',
|
|
653
|
+
compositeDigest: 'bootstrap-recovery',
|
|
654
|
+
},
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
if (intent.kind === 'catalogGeneration') {
|
|
658
|
+
signal?.throwIfAborted();
|
|
659
|
+
await preparation?.reporter.emit('validate');
|
|
660
|
+
const packageInfo = await readCliPackageInfo();
|
|
661
|
+
const config = await readCatalogSourcesConfigSnapshot(context.env);
|
|
662
|
+
const configuredSource = config.config.sources.find((source) => source.id === intent.sourceId);
|
|
663
|
+
let proposedSource;
|
|
664
|
+
let proposedConfigDigest;
|
|
665
|
+
let explicitSourceChange = false;
|
|
666
|
+
let sourceIdentityChangeImpact;
|
|
667
|
+
if (intent.sourceMutation) {
|
|
668
|
+
const preview = await preflightCatalogSourceMutation({
|
|
669
|
+
request: intent.sourceMutation.action === 'add'
|
|
670
|
+
? intent.sourceMutation
|
|
671
|
+
: { action: 'update', sourceId: intent.sourceId, update: intent.sourceMutation.update },
|
|
672
|
+
cwd: context.cwd,
|
|
673
|
+
env: context.env,
|
|
674
|
+
});
|
|
675
|
+
proposedSource = preview.proposedSource;
|
|
676
|
+
proposedConfigDigest = preview.proposedConfigDigest;
|
|
677
|
+
if (preview.configDigest !== config.digest) {
|
|
678
|
+
throw operationReviewStale('准备 Catalog 候选期间来源配置发生变化。');
|
|
679
|
+
}
|
|
680
|
+
const sourceFingerprintChanged = Boolean(proposedSource && (!configuredSource
|
|
681
|
+
|| calculateCatalogSourceConfigFingerprint(proposedSource)
|
|
682
|
+
!== calculateCatalogSourceConfigFingerprint(configuredSource)));
|
|
683
|
+
explicitSourceChange = preview.proposedConfigDigest !== preview.configDigest
|
|
684
|
+
&& (preview.identityChanged || sourceFingerprintChanged);
|
|
685
|
+
if (preview.identityChanged)
|
|
686
|
+
sourceIdentityChangeImpact = {
|
|
687
|
+
impactSchemaVersion: 1,
|
|
688
|
+
sourceId: preview.sourceId,
|
|
689
|
+
inventoryComplete: preview.references.inventoryComplete,
|
|
690
|
+
references: preview.references.references,
|
|
691
|
+
affectedReferences: preview.references.references,
|
|
692
|
+
changes: { added: [], removed: [], changed: [], newlyIncompatible: [], dependencyChanged: [] },
|
|
693
|
+
errors: preview.references.errors,
|
|
694
|
+
};
|
|
695
|
+
if (!explicitSourceChange) {
|
|
696
|
+
throw new TuiOperationBlockedError('sourceNoChanges', '来源没有变化。');
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
let previousActive;
|
|
700
|
+
let healthyActive;
|
|
701
|
+
let previousActiveVersion;
|
|
702
|
+
let previousStoreReady = false;
|
|
703
|
+
try {
|
|
704
|
+
previousActive = (await readCatalogGenerationState(context.env))
|
|
705
|
+
.sources[intent.sourceId]?.active;
|
|
706
|
+
}
|
|
707
|
+
catch (error) {
|
|
708
|
+
if (intent.action !== 'recoverState'
|
|
709
|
+
|| !(error instanceof CatalogGenerationError)
|
|
710
|
+
|| error.code !== 'catalogGenerationStateInvalid')
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
713
|
+
const activeStoreKey = previousActive
|
|
714
|
+
? createCatalogStoreKey(previousActive.logicalIdentity, previousActive.snapshotDigest)
|
|
715
|
+
: null;
|
|
716
|
+
const configuredFingerprint = configuredSource
|
|
717
|
+
? calculateCatalogSourceConfigFingerprint(configuredSource)
|
|
718
|
+
: undefined;
|
|
719
|
+
const canReuseCandidate = Boolean(reusableCandidate
|
|
720
|
+
&& !intent.sourceMutation
|
|
721
|
+
&& (intent.action === 'activate' || intent.action === 'update')
|
|
722
|
+
&& configuredFingerprint
|
|
723
|
+
&& reusableCandidate.sourceId === intent.sourceId
|
|
724
|
+
&& reusableCandidate.sourceConfigFingerprint === configuredFingerprint
|
|
725
|
+
&& reusableCandidate.probe.candidate.sourceConfigFingerprint === configuredFingerprint
|
|
726
|
+
&& reusableCandidate.activeStoreKey === activeStoreKey
|
|
727
|
+
&& reusableCandidate.probe.sourceId === intent.sourceId
|
|
728
|
+
&& reusableCandidateEvidenceIsComplete(reusableCandidate));
|
|
729
|
+
const probe = intent.action === 'repair'
|
|
730
|
+
? await probeCatalogSourceRepairGeneration({
|
|
731
|
+
sourceId: intent.sourceId,
|
|
732
|
+
cliVersion: packageInfo.version,
|
|
733
|
+
...(previousActive ? { expectedActive: previousActive } : {}),
|
|
734
|
+
expectedConfigDigest: config.digest,
|
|
735
|
+
env: context.env,
|
|
736
|
+
signal,
|
|
737
|
+
runtime: options.catalogGenerationRuntime,
|
|
738
|
+
})
|
|
739
|
+
: canReuseCandidate
|
|
740
|
+
? structuredClone(reusableCandidate.probe)
|
|
741
|
+
: await probeCatalogSourceGeneration({
|
|
742
|
+
sourceId: intent.sourceId,
|
|
743
|
+
...(proposedSource ? { source: proposedSource } : {}),
|
|
744
|
+
cliVersion: packageInfo.version,
|
|
745
|
+
env: context.env,
|
|
746
|
+
signal,
|
|
747
|
+
runtime: options.catalogGenerationRuntime,
|
|
748
|
+
});
|
|
749
|
+
signal?.throwIfAborted();
|
|
750
|
+
await preparation?.reporter.emit('evidence');
|
|
751
|
+
if (intent.action === 'activate' || intent.action === 'update') {
|
|
752
|
+
try {
|
|
753
|
+
healthyActive = await resolveActiveCatalogGeneration({ sourceId: intent.sourceId, env: context.env });
|
|
754
|
+
}
|
|
755
|
+
catch (error) {
|
|
756
|
+
if (!(error instanceof CatalogGenerationError)
|
|
757
|
+
&& !(error instanceof CatalogProviderCompatibilityError))
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
const comparisonSource = proposedSource
|
|
762
|
+
?? configuredSource;
|
|
763
|
+
if (previousActive) {
|
|
764
|
+
const store = await readCatalogStoreEntry({
|
|
765
|
+
logicalIdentity: previousActive.logicalIdentity,
|
|
766
|
+
snapshotDigest: previousActive.snapshotDigest,
|
|
767
|
+
env: context.env,
|
|
768
|
+
}).catch(() => undefined);
|
|
769
|
+
previousStoreReady = Boolean(store);
|
|
770
|
+
previousActiveVersion = healthyActive?.catalogVersion
|
|
771
|
+
?? store?.metadata.catalogVersion;
|
|
772
|
+
}
|
|
773
|
+
if (intent.action === 'update' && !intent.sourceMutation && previousActive && comparisonSource) {
|
|
774
|
+
explicitSourceChange = previousActive.sourceConfigFingerprint
|
|
775
|
+
!== calculateCatalogSourceConfigFingerprint(comparisonSource)
|
|
776
|
+
|| previousActive.sourceIdentity !== await calculateCatalogSourceIdentity(comparisonSource);
|
|
777
|
+
}
|
|
778
|
+
const comparisonActive = healthyActive
|
|
779
|
+
? {
|
|
780
|
+
logicalIdentity: healthyActive.logicalIdentity,
|
|
781
|
+
catalogVersion: healthyActive.catalogVersion,
|
|
782
|
+
snapshotDigest: healthyActive.snapshotDigest,
|
|
783
|
+
resolvedCommit: healthyActive.resolvedCommit,
|
|
784
|
+
}
|
|
785
|
+
: previousActive && previousActiveVersion
|
|
786
|
+
? {
|
|
787
|
+
logicalIdentity: previousActive.logicalIdentity,
|
|
788
|
+
catalogVersion: previousActiveVersion,
|
|
789
|
+
snapshotDigest: previousActive.snapshotDigest,
|
|
790
|
+
resolvedCommit: previousActive.resolvedCommit,
|
|
791
|
+
}
|
|
792
|
+
: undefined;
|
|
793
|
+
const candidateRelation = comparisonActive && comparisonSource
|
|
794
|
+
? compareCatalogGenerationFreshness({
|
|
795
|
+
sourceType: comparisonSource.type,
|
|
796
|
+
active: comparisonActive,
|
|
797
|
+
candidate: probe.candidate,
|
|
798
|
+
}).state
|
|
799
|
+
: undefined;
|
|
800
|
+
const exactStoreTarget = Boolean(previousActive)
|
|
801
|
+
&& createCatalogStoreKey(previousActive.logicalIdentity, previousActive.snapshotDigest)
|
|
802
|
+
=== createCatalogStoreKey(probe.candidate.logicalIdentity, probe.candidate.snapshotDigest);
|
|
803
|
+
if (intent.action === 'repair' && !exactStoreTarget) {
|
|
804
|
+
throw new CatalogGenerationError({
|
|
805
|
+
code: 'catalogReplaceDamagedRequired', sourceId: intent.sourceId,
|
|
806
|
+
message: `Catalog source "${intent.sourceId}" cannot reproduce the damaged Active entry. Use the current candidate replacement Review.`,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
const exactRepair = (intent.action === 'repair' || intent.action === 'update')
|
|
810
|
+
&& exactStoreTarget && !previousStoreReady;
|
|
811
|
+
if (previousActive && !previousStoreReady && !exactStoreTarget
|
|
812
|
+
&& !intent.sourceMutation && intent.action !== 'replaceDamaged') {
|
|
813
|
+
throw new CatalogGenerationError({
|
|
814
|
+
code: 'catalogReplaceDamagedRequired',
|
|
815
|
+
sourceId: intent.sourceId,
|
|
816
|
+
message: `Catalog source "${intent.sourceId}" has a damaged Active entry whose version cannot be compared safely. The current Active remains unchanged. Edit the source explicitly, or remove and add it again.`,
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
if (intent.action !== 'replaceDamaged' && !explicitSourceChange && candidateRelation === 'incompatible') {
|
|
820
|
+
throw new CatalogGenerationError({
|
|
821
|
+
code: 'catalogLogicalIdentityChanged', sourceId: intent.sourceId,
|
|
822
|
+
message: `Catalog source "${intent.sourceId}" changed logical identity. Edit or remove and re-add the source.`,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
if (intent.action !== 'replaceDamaged' && !explicitSourceChange && candidateRelation === 'versionConflict') {
|
|
826
|
+
throw new TuiOperationBlockedError('catalogVersionConflict', '候选 Catalog 与当前 Active 版本相同,但内容摘要不同。普通更新已阻止。');
|
|
827
|
+
}
|
|
828
|
+
if (intent.action !== 'replaceDamaged' && !explicitSourceChange && candidateRelation === 'rollbackDetected') {
|
|
829
|
+
throw new TuiOperationBlockedError('catalogRollbackDetected', '候选 Catalog 版本低于当前 Active。普通更新已阻止。');
|
|
830
|
+
}
|
|
831
|
+
const impact = intent.action === 'repair' ? undefined
|
|
832
|
+
: sourceIdentityChangeImpact ?? await inspectCatalogSourceImpact({
|
|
833
|
+
sourceId: intent.sourceId,
|
|
834
|
+
cwd: context.cwd,
|
|
835
|
+
env: context.env,
|
|
836
|
+
sourcePrimary: comparisonSource?.primary === true,
|
|
837
|
+
mode: 'generation',
|
|
838
|
+
candidateManifest: probe.manifest,
|
|
839
|
+
});
|
|
840
|
+
return {
|
|
841
|
+
catalog: {
|
|
842
|
+
configDigest: config.digest,
|
|
843
|
+
compositeDigest: probe.candidate.snapshotDigest,
|
|
844
|
+
},
|
|
845
|
+
catalogGeneration: {
|
|
846
|
+
action: intent.action,
|
|
847
|
+
...(previousActive ? { previousActive } : {}),
|
|
848
|
+
...(previousActiveVersion ? { previousActiveVersion } : {}),
|
|
849
|
+
candidate: probe.candidate,
|
|
850
|
+
...(candidateRelation ? { candidateRelation } : {}),
|
|
851
|
+
...(explicitSourceChange ? { explicitSourceChange: true } : {}),
|
|
852
|
+
...(exactRepair ? { exactRepair: true } : {}),
|
|
853
|
+
activationMode: intent.action === 'replaceDamaged' ? 'replaceDamaged'
|
|
854
|
+
: explicitSourceChange ? 'explicitSourceChange' : 'normal',
|
|
855
|
+
...(impact ? {
|
|
856
|
+
impact,
|
|
857
|
+
impactDigest: calculateCatalogSourceImpactDigest(impact),
|
|
858
|
+
impactMode: sourceIdentityChangeImpact ? 'identityChange' : 'generation',
|
|
859
|
+
} : {}),
|
|
860
|
+
configDigest: config.digest,
|
|
861
|
+
...(proposedConfigDigest ? { proposedConfigDigest } : {}),
|
|
862
|
+
...(proposedSource ? { proposedSource } : {}),
|
|
863
|
+
...(intent.sourceMutation ? { sourceMutation: intent.sourceMutation } : {}),
|
|
864
|
+
...(intent.setPrimaryAfterActivation ? { setPrimaryAfterActivation: true } : {}),
|
|
865
|
+
},
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
if (intent.kind === 'sourceMutation') {
|
|
869
|
+
signal?.throwIfAborted();
|
|
870
|
+
if (intent.action === 'add' && !intent.source
|
|
871
|
+
|| intent.action === 'update' && !intent.update) {
|
|
872
|
+
throw new TuiOperationBlockedError('invalidSourceMutation', '来源操作缺少候选输入。');
|
|
873
|
+
}
|
|
874
|
+
const request = intent.action === 'add'
|
|
875
|
+
? { action: 'add', source: intent.source }
|
|
876
|
+
: intent.action === 'update'
|
|
877
|
+
? { action: 'update', sourceId: intent.sourceId, update: intent.update }
|
|
878
|
+
: { action: intent.action, sourceId: intent.sourceId };
|
|
879
|
+
await preparation?.reporter.emit('validate');
|
|
880
|
+
const preview = await preflightCatalogSourceMutation({
|
|
881
|
+
request,
|
|
882
|
+
cwd: context.cwd,
|
|
883
|
+
env: context.env,
|
|
884
|
+
});
|
|
885
|
+
signal?.throwIfAborted();
|
|
886
|
+
await preparation?.reporter.emit('evidence');
|
|
887
|
+
signal?.throwIfAborted();
|
|
888
|
+
const evidence = {
|
|
889
|
+
catalog: { configDigest: preview.configDigest, compositeDigest: preview.proposedConfigDigest },
|
|
890
|
+
sourceWrite: {
|
|
891
|
+
configDigest: preview.configDigest,
|
|
892
|
+
proposedConfigDigest: preview.proposedConfigDigest,
|
|
893
|
+
...(preview.sourceIdentity ? { sourceIdentity: preview.sourceIdentity } : {}),
|
|
894
|
+
inventoryDigest: digest({ references: preview.references.references, errors: preview.references.errors }),
|
|
895
|
+
impactDigest: preview.impactDigest,
|
|
896
|
+
referenceCount: preview.references.references.length,
|
|
897
|
+
inventoryComplete: preview.references.inventoryComplete,
|
|
898
|
+
impact: {
|
|
899
|
+
impactSchemaVersion: 1,
|
|
900
|
+
sourceId: preview.sourceId,
|
|
901
|
+
inventoryComplete: preview.references.inventoryComplete,
|
|
902
|
+
references: preview.references.references,
|
|
903
|
+
affectedReferences: preview.references.references,
|
|
904
|
+
changes: { added: [], removed: [], changed: [], newlyIncompatible: [], dependencyChanged: [] },
|
|
905
|
+
errors: preview.references.errors,
|
|
906
|
+
},
|
|
907
|
+
},
|
|
908
|
+
};
|
|
909
|
+
if (preparation?.validateIntent
|
|
910
|
+
&& evidence.sourceWrite?.configDigest === evidence.sourceWrite?.proposedConfigDigest) {
|
|
911
|
+
throw new TuiOperationBlockedError('sourceNoChanges', '来源没有变化。');
|
|
912
|
+
}
|
|
913
|
+
return evidence;
|
|
914
|
+
}
|
|
915
|
+
if (!pluginIntent(intent)) {
|
|
916
|
+
throw new TuiOperationBlockedError('operationNotImplemented', '这个写操作尚未接入新 Controller。');
|
|
917
|
+
}
|
|
918
|
+
signal?.throwIfAborted();
|
|
919
|
+
const packageInfo = await readCliPackageInfo();
|
|
920
|
+
const offlineCleanupReason = intent.kind === 'pluginWrite'
|
|
921
|
+
&& intent.action === 'cleanup'
|
|
922
|
+
&& intent.originIssue?.actionId === 'cleanup'
|
|
923
|
+
&& (intent.originIssue?.category === 'sourceMissing'
|
|
924
|
+
|| intent.originIssue?.category === 'sourceUnavailable')
|
|
925
|
+
? intent.originIssue.category === 'sourceMissing' ? 'sourceMissing' : 'bundleUnavailable'
|
|
926
|
+
: undefined;
|
|
927
|
+
let catalogOperation;
|
|
928
|
+
let catalogOperationError;
|
|
929
|
+
if (!offlineCleanupReason && intent.kind !== 'portableInstall') {
|
|
930
|
+
try {
|
|
931
|
+
const sourceIds = [parsePluginId(intent.pluginId).sourceId];
|
|
932
|
+
catalogOperation = !freshCatalog && sessionCatalogOperationContext
|
|
933
|
+
? selectCatalogOperationContext(sessionCatalogOperationContext, sourceIds)
|
|
934
|
+
: await resolveCatalogOperationContext({
|
|
935
|
+
sourceIds,
|
|
936
|
+
env: context.env,
|
|
937
|
+
...(!freshCatalog ? { validatedStoreEntries, validatingStoreEntries } : {}),
|
|
938
|
+
...(signal ? { signal } : {}),
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
catch (error) {
|
|
942
|
+
catalogOperationError = error;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (intent.kind === 'portableInstall') {
|
|
946
|
+
await preparation?.reporter.emit('portable');
|
|
947
|
+
const portableSourceId = parsePluginId(intent.pluginId).sourceId;
|
|
948
|
+
const portableCatalogOperation = sessionCatalogOperationContext
|
|
949
|
+
? selectCatalogOperationContext(sessionCatalogOperationContext, [portableSourceId])
|
|
950
|
+
: undefined;
|
|
951
|
+
const portable = await preparePortableInstall({
|
|
952
|
+
selector: intent.pluginId,
|
|
953
|
+
scope: intent.scope,
|
|
954
|
+
...(intent.selectedSkills.length > 0 ? { requestedSkills: intent.selectedSkills } : {}),
|
|
955
|
+
...(intent.requestedAgents ? { requestedAgents: intent.requestedAgents } : {}),
|
|
956
|
+
cwd: context.cwd,
|
|
957
|
+
env: context.env,
|
|
958
|
+
cliVersion: packageInfo.version,
|
|
959
|
+
signal,
|
|
960
|
+
...(portableCatalogOperation
|
|
961
|
+
? { catalogOperationContext: portableCatalogOperation }
|
|
962
|
+
: {}),
|
|
963
|
+
});
|
|
964
|
+
signal?.throwIfAborted();
|
|
965
|
+
await preparation?.reporter.emit('evidence');
|
|
966
|
+
signal?.throwIfAborted();
|
|
967
|
+
const evidence = {
|
|
968
|
+
catalog: {
|
|
969
|
+
configDigest: portable.configDigest,
|
|
970
|
+
compositeDigest: portable.evidenceDigest,
|
|
971
|
+
...(portable.generationSetDigest
|
|
972
|
+
? { generationSetDigest: portable.generationSetDigest }
|
|
973
|
+
: {}),
|
|
974
|
+
},
|
|
975
|
+
portable,
|
|
976
|
+
};
|
|
977
|
+
if (catalogOperation)
|
|
978
|
+
catalogOperationByEvidence.set(evidence, catalogOperation);
|
|
979
|
+
return evidence;
|
|
980
|
+
}
|
|
981
|
+
if (preparation && intent.kind === 'configSave') {
|
|
982
|
+
if (!sessionStatusResult || !catalogOperation) {
|
|
983
|
+
throw operationReviewStale('当前 TUI session 没有可复用的设置证据。');
|
|
984
|
+
}
|
|
985
|
+
await preparation.reporter.emit('config');
|
|
986
|
+
const configSnapshot = await readCatalogSourcesConfigSnapshot(context.env);
|
|
987
|
+
signal?.throwIfAborted();
|
|
988
|
+
if (configSnapshot.digest !== sessionStatusResult.payload.catalog.configDigest) {
|
|
989
|
+
throw operationReviewStale('准备设置确认期间来源配置发生变化。');
|
|
990
|
+
}
|
|
991
|
+
const selected = await withResolvedCatalogPlugin({
|
|
992
|
+
selector: intent.pluginId,
|
|
993
|
+
cliVersion: packageInfo.version,
|
|
994
|
+
configSnapshot,
|
|
995
|
+
env: context.env,
|
|
996
|
+
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
997
|
+
...(signal ? { signal } : {}),
|
|
998
|
+
consume: async ({ plugin, source }) => {
|
|
999
|
+
if (!plugin.manifest.config) {
|
|
1000
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1001
|
+
}
|
|
1002
|
+
if (intent.kind === 'configSave') {
|
|
1003
|
+
await coercePluginConfigUpdates({
|
|
1004
|
+
schema: plugin.manifest.config.fields,
|
|
1005
|
+
updates: intent.updates ?? {},
|
|
1006
|
+
cwd: context.cwd,
|
|
1007
|
+
});
|
|
1008
|
+
for (const key of intent.removeKeys ?? []) {
|
|
1009
|
+
if (!plugin.manifest.config.fields[key]) {
|
|
1010
|
+
throw new TuiOperationBlockedError('unknownConfigKey', '设置字段已变化,请重新检查。');
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
return {
|
|
1015
|
+
pluginName: plugin.manifest.name,
|
|
1016
|
+
source: sourceEvidenceForPlugin(source, plugin.manifest.name),
|
|
1017
|
+
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
1018
|
+
? configSharedNativeRenderTargets(plugin, [
|
|
1019
|
+
...Object.keys(intent.updates ?? {}),
|
|
1020
|
+
...(intent.removeKeys ?? []),
|
|
1021
|
+
])
|
|
1022
|
+
: [],
|
|
1023
|
+
};
|
|
1024
|
+
},
|
|
1025
|
+
});
|
|
1026
|
+
const store = await readPluginConfigStore({
|
|
1027
|
+
sourceId: selected.source?.sourceId ?? parsePluginId(intent.pluginId).sourceId,
|
|
1028
|
+
...(selected.source?.sourceIdentity
|
|
1029
|
+
? { sourceIdentity: selected.source.sourceIdentity }
|
|
1030
|
+
: {}),
|
|
1031
|
+
pluginName: selected.pluginName,
|
|
1032
|
+
scope: intent.scope,
|
|
1033
|
+
cwd: context.cwd,
|
|
1034
|
+
env: context.env,
|
|
1035
|
+
});
|
|
1036
|
+
signal?.throwIfAborted();
|
|
1037
|
+
const relevantTargets = configAffectedStatusTargets(sessionStatusResult.payload.targets, intent.pluginId, intent.scope);
|
|
1038
|
+
const relevantRevisions = (sessionStatusResult.targetRevisions ?? []).filter((revision) => relevantTargets.some((target) => target.platform === revision.platform
|
|
1039
|
+
&& target.scope === revision.scope
|
|
1040
|
+
&& target.pluginId === revision.pluginId));
|
|
1041
|
+
await preparation.reporter.emit('evidence');
|
|
1042
|
+
const evidence = {
|
|
1043
|
+
catalog: {
|
|
1044
|
+
configDigest: sessionStatusResult.payload.catalog.configDigest,
|
|
1045
|
+
compositeDigest: sessionStatusResult.payload.catalog.compositeDigest,
|
|
1046
|
+
...(catalogOperation ? { generationSetDigest: catalogOperation.generationSetDigest } : {}),
|
|
1047
|
+
},
|
|
1048
|
+
...(selected.source ? { source: selected.source } : {}),
|
|
1049
|
+
targetFingerprint: statusTargetFingerprint(relevantTargets, relevantRevisions),
|
|
1050
|
+
config: {
|
|
1051
|
+
scope: intent.scope,
|
|
1052
|
+
...(selected.source?.manifestDigest ? { schemaIdentity: selected.source.manifestDigest } : {}),
|
|
1053
|
+
storeDigest: digest({ exists: store.exists, rawDigest: store.rawDigest }),
|
|
1054
|
+
affectedTargets: relevantTargets.map(({ platform, scope }) => ({ platform, scope })),
|
|
1055
|
+
...(selected.sharedNativeRenderTargets.length > 0
|
|
1056
|
+
? { sharedNativeRenderTargets: selected.sharedNativeRenderTargets }
|
|
1057
|
+
: {}),
|
|
1058
|
+
},
|
|
1059
|
+
};
|
|
1060
|
+
if (catalogOperation)
|
|
1061
|
+
catalogOperationByEvidence.set(evidence, catalogOperation);
|
|
1062
|
+
return evidence;
|
|
1063
|
+
}
|
|
1064
|
+
await preparation?.reporter.emit('status');
|
|
1065
|
+
const statusCatalogOperation = offlineCleanupReason
|
|
1066
|
+
? undefined
|
|
1067
|
+
: catalogOperation ?? (!freshCatalog ? sessionCatalogOperationContext : undefined);
|
|
1068
|
+
const status = await statusCommandV7({
|
|
1069
|
+
plugins: [...new Set([intent.pluginId,
|
|
1070
|
+
...(intent.kind === 'pluginWrite' && intent.originIssue?.consumerPluginId
|
|
1071
|
+
? [intent.originIssue.consumerPluginId] : [])])],
|
|
1072
|
+
...('platform' in intent ? { platform: intent.platform } : {}),
|
|
1073
|
+
...(intent.kind !== 'pluginWrite' && intent.scope === 'project'
|
|
1074
|
+
? { scope: intent.scope }
|
|
1075
|
+
: {}),
|
|
1076
|
+
cwd: context.cwd,
|
|
1077
|
+
env: context.env,
|
|
1078
|
+
cliVersion: packageInfo.version,
|
|
1079
|
+
...(statusCatalogOperation ? { catalogOperationContext: statusCatalogOperation } : {}),
|
|
1080
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1081
|
+
});
|
|
1082
|
+
signal?.throwIfAborted();
|
|
1083
|
+
const configSnapshot = await readCatalogSourcesConfigSnapshot(context.env);
|
|
1084
|
+
signal?.throwIfAborted();
|
|
1085
|
+
if (configSnapshot.digest !== status.payload.catalog.configDigest) {
|
|
1086
|
+
throw operationReviewStale('准备确认信息期间来源配置发生变化。');
|
|
1087
|
+
}
|
|
1088
|
+
if (catalogOperationError)
|
|
1089
|
+
throw catalogOperationError;
|
|
1090
|
+
if (!offlineCleanupReason && !catalogOperation) {
|
|
1091
|
+
catalogOperation = await resolveCatalogOperationContext({
|
|
1092
|
+
sourceIds: [parsePluginId(intent.pluginId).sourceId],
|
|
1093
|
+
configSnapshot,
|
|
1094
|
+
env: context.env,
|
|
1095
|
+
...(!freshCatalog ? { validatedStoreEntries, validatingStoreEntries } : {}),
|
|
1096
|
+
...(signal ? { signal } : {}),
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
let dependencyPlan;
|
|
1100
|
+
let codexReconcilePlans;
|
|
1101
|
+
let operationPlan;
|
|
1102
|
+
await preparation?.reporter.emit('catalog');
|
|
1103
|
+
const offlineCleanupTarget = offlineCleanupReason && intent.kind === 'pluginWrite'
|
|
1104
|
+
? status.payload.targets.find((target) => target.pluginId === intent.pluginId
|
|
1105
|
+
&& target.platform === intent.platform
|
|
1106
|
+
&& target.scope === intent.scope
|
|
1107
|
+
&& target.reasons.some((error) => error.code === offlineCleanupReason))
|
|
1108
|
+
: undefined;
|
|
1109
|
+
const catalogSource = offlineCleanupTarget
|
|
1110
|
+
? status.payload.catalog.sources.find((source) => source.id === offlineCleanupTarget.sourceId)
|
|
1111
|
+
: undefined;
|
|
1112
|
+
let offlineCleanup;
|
|
1113
|
+
if (offlineCleanupReason && offlineCleanupTarget) {
|
|
1114
|
+
await preparation?.reporter.emit('inventory');
|
|
1115
|
+
const inventory = await operationInventory({
|
|
1116
|
+
cwd: context.cwd,
|
|
1117
|
+
env: context.env,
|
|
1118
|
+
});
|
|
1119
|
+
signal?.throwIfAborted();
|
|
1120
|
+
offlineCleanup = offlineCleanupEvidenceFromInventory({
|
|
1121
|
+
reason: offlineCleanupReason,
|
|
1122
|
+
pluginId: offlineCleanupTarget.pluginId,
|
|
1123
|
+
pluginName: offlineCleanupTarget.pluginName,
|
|
1124
|
+
sourceId: offlineCleanupTarget.sourceId,
|
|
1125
|
+
sourceIdentity: offlineCleanupTarget.sourceIdentity,
|
|
1126
|
+
platform: offlineCleanupTarget.platform,
|
|
1127
|
+
scope: offlineCleanupTarget.scope,
|
|
1128
|
+
inventory,
|
|
1129
|
+
}) ?? undefined;
|
|
1130
|
+
if (!offlineCleanup) {
|
|
1131
|
+
throw operationReviewStale('离线清理现场证据已消失或无法验证。');
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const selected = offlineCleanupTarget
|
|
1135
|
+
? {
|
|
1136
|
+
pluginName: offlineCleanupTarget.pluginName,
|
|
1137
|
+
source: {
|
|
1138
|
+
sourceId: offlineCleanupTarget.sourceId,
|
|
1139
|
+
sourceIdentity: offlineCleanupTarget.sourceIdentity,
|
|
1140
|
+
...(catalogSource?.requestedRef ? { requestedRef: catalogSource.requestedRef } : {}),
|
|
1141
|
+
...(catalogSource?.resolvedCommit ? { resolvedCommit: catalogSource.resolvedCommit } : {}),
|
|
1142
|
+
},
|
|
1143
|
+
}
|
|
1144
|
+
: await withResolvedCatalogPlugin({
|
|
1145
|
+
selector: intent.pluginId,
|
|
1146
|
+
cliVersion: packageInfo.version,
|
|
1147
|
+
configSnapshot,
|
|
1148
|
+
env: context.env,
|
|
1149
|
+
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
1150
|
+
...(signal ? { signal } : {}),
|
|
1151
|
+
consume: async ({ plugin, source }) => {
|
|
1152
|
+
if (preparation?.validateIntent && intent.kind === 'configSave') {
|
|
1153
|
+
await preparation.reporter.emit('config');
|
|
1154
|
+
if (!plugin.manifest.config) {
|
|
1155
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1156
|
+
}
|
|
1157
|
+
await coercePluginConfigUpdates({
|
|
1158
|
+
schema: plugin.manifest.config.fields,
|
|
1159
|
+
updates: intent.updates ?? {},
|
|
1160
|
+
cwd: context.cwd,
|
|
1161
|
+
});
|
|
1162
|
+
for (const key of intent.removeKeys ?? []) {
|
|
1163
|
+
if (!plugin.manifest.config.fields[key]) {
|
|
1164
|
+
throw new TuiOperationBlockedError('unknownConfigKey', '设置字段已变化,请重新检查。');
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return {
|
|
1169
|
+
pluginName: plugin.manifest.name,
|
|
1170
|
+
source: sourceEvidenceForPlugin(source, plugin.manifest.name),
|
|
1171
|
+
sharedNativeRenderTargets: intent.kind === 'configSave'
|
|
1172
|
+
? configSharedNativeRenderTargets(plugin, [
|
|
1173
|
+
...Object.keys(intent.updates ?? {}),
|
|
1174
|
+
...(intent.removeKeys ?? []),
|
|
1175
|
+
])
|
|
1176
|
+
: [],
|
|
1177
|
+
};
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
let codexManager;
|
|
1181
|
+
const hasDeclaredDependencies = (status.pluginSummaries.find((summary) => summary.pluginId === intent.pluginId)?.dependencyTotalCount ?? 0) > 0;
|
|
1182
|
+
if (intent.kind === 'pluginWrite') {
|
|
1183
|
+
const command = {
|
|
1184
|
+
install: installWriteCommand,
|
|
1185
|
+
refreshAndSync: syncWriteCommand,
|
|
1186
|
+
reinstall: reinstallWriteCommand,
|
|
1187
|
+
uninstall: uninstallWriteCommand,
|
|
1188
|
+
cleanup: cleanupWriteCommand,
|
|
1189
|
+
sync: syncWriteCommand,
|
|
1190
|
+
}[intent.action];
|
|
1191
|
+
const preview = await command([intent.pluginId], {
|
|
1192
|
+
cwd: context.cwd,
|
|
1193
|
+
platform: intent.platform,
|
|
1194
|
+
scope: intent.scope,
|
|
1195
|
+
...(intent.action === 'install' && intent.dependencyScopeOverrides
|
|
1196
|
+
? { dependencyScopeOverrides: intent.dependencyScopeOverrides }
|
|
1197
|
+
: {}),
|
|
1198
|
+
...(intent.action === 'cleanup' ? { force: intent.force === true } : {}),
|
|
1199
|
+
}, {
|
|
1200
|
+
...context,
|
|
1201
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1202
|
+
expectedCatalogConfigDigest: status.payload.catalog.configDigest,
|
|
1203
|
+
...(catalogOperation ? {
|
|
1204
|
+
catalogOperationContext: catalogOperation,
|
|
1205
|
+
expectedGenerationSetDigest: catalogOperation.generationSetDigest,
|
|
1206
|
+
} : {}),
|
|
1207
|
+
previewOperationPlan: true,
|
|
1208
|
+
...(preparation ? {
|
|
1209
|
+
onPreviewStage: (stage) => stage === 'catalog' ? undefined : preparation.reporter.emit(stage),
|
|
1210
|
+
} : {}),
|
|
1211
|
+
});
|
|
1212
|
+
signal?.throwIfAborted();
|
|
1213
|
+
codexReconcilePlans = preview?.codexReconcilePlans;
|
|
1214
|
+
operationPlan = preview?.operationPlan;
|
|
1215
|
+
if (hasDeclaredDependencies
|
|
1216
|
+
&& (intent.action === 'install'
|
|
1217
|
+
|| intent.action === 'refreshAndSync'
|
|
1218
|
+
|| intent.action === 'reinstall'
|
|
1219
|
+
|| intent.action === 'sync')) {
|
|
1220
|
+
dependencyPlan = preview.dependencyPlan;
|
|
1221
|
+
if (!dependencyPlan) {
|
|
1222
|
+
throw new TuiOperationBlockedError('dependencyGraphInvalid', '无法建立可信的依赖安装计划。');
|
|
1223
|
+
}
|
|
1224
|
+
const blocker = dependencyPlan.targets.find((target) => target.action === 'block');
|
|
1225
|
+
if (blocker) {
|
|
1226
|
+
throw new TuiOperationBlockedError(blocker.errorCode ?? 'dependencyNotReady', `${blocker.errorCode ?? 'dependencyNotReady'}: 依赖安装计划被阻止。`);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
const managerPreview = preview?.codexManagerPreview;
|
|
1230
|
+
if (managerPreview?.state === 'blocked') {
|
|
1231
|
+
const message = managerPreview.code === 'codexSystemCliUnsupported'
|
|
1232
|
+
? '系统 Codex CLI 版本不受支持。请升级官方 Codex CLI 后重试。'
|
|
1233
|
+
: 'AW-managed Codex runtime 当前不可用。请重试、升级 AW,或安装官方 Codex CLI。';
|
|
1234
|
+
throw new TuiOperationBlockedError(managerPreview.code, `${managerPreview.code}: ${message}`);
|
|
1235
|
+
}
|
|
1236
|
+
if (managerPreview) {
|
|
1237
|
+
codexManager = {
|
|
1238
|
+
state: managerPreview.state,
|
|
1239
|
+
packageName: MANAGED_CODEX_PACKAGE_NAME,
|
|
1240
|
+
version: managerPreview.state === 'requires-install'
|
|
1241
|
+
? MANAGED_CODEX_VERSION
|
|
1242
|
+
: managerPreview.manager.version,
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
await preparation?.reporter.emit('evidence');
|
|
1247
|
+
signal?.throwIfAborted();
|
|
1248
|
+
const evidenceTargets = intent.kind === 'configSave'
|
|
1249
|
+
? configAffectedStatusTargets(status.payload.targets, intent.pluginId, intent.scope)
|
|
1250
|
+
: status.payload.targets;
|
|
1251
|
+
const evidenceRevisions = intent.kind === 'configSave'
|
|
1252
|
+
? (status.targetRevisions ?? []).filter((revision) => evidenceTargets.some((target) => target.platform === revision.platform
|
|
1253
|
+
&& target.scope === revision.scope
|
|
1254
|
+
&& target.pluginId === revision.pluginId))
|
|
1255
|
+
: (status.targetRevisions ?? []);
|
|
1256
|
+
const evidence = {
|
|
1257
|
+
catalog: {
|
|
1258
|
+
configDigest: status.payload.catalog.configDigest,
|
|
1259
|
+
compositeDigest: status.payload.catalog.compositeDigest,
|
|
1260
|
+
...(catalogOperation
|
|
1261
|
+
? { generationSetDigest: catalogOperation.generationSetDigest }
|
|
1262
|
+
: {}),
|
|
1263
|
+
},
|
|
1264
|
+
source: selected.source,
|
|
1265
|
+
...(offlineCleanup ? { offlineCleanup } : {}),
|
|
1266
|
+
...(dependencyPlan ? { dependencyPlan } : {}),
|
|
1267
|
+
...(codexReconcilePlans ? { codexReconcilePlans } : {}),
|
|
1268
|
+
...(operationPlan ? { operationPlan } : {}),
|
|
1269
|
+
...(codexManager ? { codexManager } : {}),
|
|
1270
|
+
targetFingerprint: statusTargetFingerprint(evidenceTargets, evidenceRevisions),
|
|
1271
|
+
};
|
|
1272
|
+
if (intent.kind === 'configSave') {
|
|
1273
|
+
const store = await readPluginConfigStore({
|
|
1274
|
+
sourceId: selected.source.sourceId,
|
|
1275
|
+
sourceIdentity: selected.source.sourceIdentity,
|
|
1276
|
+
pluginName: selected.pluginName,
|
|
1277
|
+
scope: intent.scope,
|
|
1278
|
+
cwd: context.cwd,
|
|
1279
|
+
env: context.env,
|
|
1280
|
+
});
|
|
1281
|
+
signal?.throwIfAborted();
|
|
1282
|
+
evidence.config = {
|
|
1283
|
+
scope: intent.scope,
|
|
1284
|
+
...('manifestDigest' in selected.source
|
|
1285
|
+
? { schemaIdentity: selected.source.manifestDigest }
|
|
1286
|
+
: {}),
|
|
1287
|
+
storeDigest: digest({ exists: store.exists, rawDigest: store.rawDigest }),
|
|
1288
|
+
affectedTargets: evidenceTargets.map(({ platform, scope }) => ({ platform, scope })),
|
|
1289
|
+
...('sharedNativeRenderTargets' in selected
|
|
1290
|
+
&& selected.sharedNativeRenderTargets.length > 0
|
|
1291
|
+
? { sharedNativeRenderTargets: selected.sharedNativeRenderTargets }
|
|
1292
|
+
: {}),
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
if (catalogOperation)
|
|
1296
|
+
catalogOperationByEvidence.set(evidence, catalogOperation);
|
|
1297
|
+
return evidence;
|
|
1298
|
+
};
|
|
1299
|
+
const dependencies = {
|
|
1300
|
+
beginCatalogSession(sessionOptions) {
|
|
1301
|
+
sessionCatalogOperationContext = undefined;
|
|
1302
|
+
if (sessionOptions?.reuseValidatedGenerations !== true) {
|
|
1303
|
+
validatedStoreEntries.clear();
|
|
1304
|
+
validatingStoreEntries.clear();
|
|
1305
|
+
}
|
|
1306
|
+
},
|
|
1307
|
+
loadStatus,
|
|
1308
|
+
async probeCatalogFreshness(sourceId, freshnessOptions, signal) {
|
|
1309
|
+
signal.throwIfAborted();
|
|
1310
|
+
const packageInfo = await readCliPackageInfo();
|
|
1311
|
+
return probeCatalogSourceFreshness({
|
|
1312
|
+
sourceId,
|
|
1313
|
+
cliVersion: packageInfo.version,
|
|
1314
|
+
env: context.env,
|
|
1315
|
+
signal,
|
|
1316
|
+
fullValidation: freshnessOptions.fullValidation,
|
|
1317
|
+
runtime: {
|
|
1318
|
+
...options.catalogGenerationRuntime,
|
|
1319
|
+
validatedStoreEntries,
|
|
1320
|
+
validatingStoreEntries,
|
|
1321
|
+
},
|
|
1322
|
+
});
|
|
1323
|
+
},
|
|
1324
|
+
async inspectSourceRemoval(sourceId, signal) {
|
|
1325
|
+
signal.throwIfAborted();
|
|
1326
|
+
const config = await readCatalogSourcesConfigSnapshot(context.env);
|
|
1327
|
+
const source = config.config.sources.find((entry) => entry.id === sourceId);
|
|
1328
|
+
if (!source)
|
|
1329
|
+
throw new TuiOperationBlockedError('catalogGenerationSourceMissing', '来源不存在。');
|
|
1330
|
+
const impact = await inspectCatalogSourceImpact({
|
|
1331
|
+
sourceId,
|
|
1332
|
+
cwd: context.cwd,
|
|
1333
|
+
env: context.env,
|
|
1334
|
+
sourcePrimary: source.primary,
|
|
1335
|
+
mode: 'remove',
|
|
1336
|
+
});
|
|
1337
|
+
const counts = (category) => impact.affectedReferences.filter((reference) => reference.category === category).length;
|
|
1338
|
+
return {
|
|
1339
|
+
blocked: impact.affectedReferences.length > 0 || !impact.inventoryComplete,
|
|
1340
|
+
inventoryComplete: impact.inventoryComplete,
|
|
1341
|
+
installationCount: counts('installation'),
|
|
1342
|
+
configCount: counts('config'),
|
|
1343
|
+
lifecycleCount: counts('lifecycle'),
|
|
1344
|
+
marketplaceCount: counts('marketplace'),
|
|
1345
|
+
dependencies: impact.affectedReferences,
|
|
1346
|
+
};
|
|
1347
|
+
},
|
|
1348
|
+
async prepareReviewEvidence(intent, signal, onStage, reusableCandidate) {
|
|
1349
|
+
const reporter = createReviewStageReporter({
|
|
1350
|
+
context,
|
|
1351
|
+
onStage,
|
|
1352
|
+
now: options.now ?? Date.now,
|
|
1353
|
+
});
|
|
1354
|
+
try {
|
|
1355
|
+
const preparationWarnings = [];
|
|
1356
|
+
if (intent.kind === 'pluginWrite' && intent.action === 'refreshAndSync') {
|
|
1357
|
+
await reporter.emit('refresh');
|
|
1358
|
+
const packageInfo = await readCliPackageInfo();
|
|
1359
|
+
const sourceId = parsePluginId(intent.pluginId).sourceId;
|
|
1360
|
+
await syncCatalogSourceGeneration({
|
|
1361
|
+
sourceId,
|
|
1362
|
+
cliVersion: packageInfo.version,
|
|
1363
|
+
cwd: context.cwd,
|
|
1364
|
+
env: context.env,
|
|
1365
|
+
signal,
|
|
1366
|
+
}).catch((error) => {
|
|
1367
|
+
preparationWarnings.push(`catalogSourceRefreshFailed: ${sourceId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1368
|
+
});
|
|
1369
|
+
sessionCatalogOperationContext = undefined;
|
|
1370
|
+
sessionStatusResult = undefined;
|
|
1371
|
+
validatedStoreEntries.clear();
|
|
1372
|
+
validatingStoreEntries.clear();
|
|
1373
|
+
}
|
|
1374
|
+
const evidence = await captureEvidence(intent, signal, {
|
|
1375
|
+
reporter,
|
|
1376
|
+
validateIntent: true,
|
|
1377
|
+
}, createOperationInventoryReader(), intent.kind === 'pluginWrite'
|
|
1378
|
+
&& intent.action === 'refreshAndSync', reusableCandidate);
|
|
1379
|
+
if (preparationWarnings.length > 0)
|
|
1380
|
+
evidence.preparationWarnings = preparationWarnings;
|
|
1381
|
+
return evidence;
|
|
1382
|
+
}
|
|
1383
|
+
finally {
|
|
1384
|
+
await reporter.finish();
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
async previewDependencyPlacement(intent, signal) {
|
|
1388
|
+
const evidence = await captureEvidence(intent, signal);
|
|
1389
|
+
return evidence.dependencyPlan;
|
|
1390
|
+
},
|
|
1391
|
+
async validateIntent(intent, signal) {
|
|
1392
|
+
if (intent.kind === 'catalogSourcesRecovery') {
|
|
1393
|
+
signal.throwIfAborted();
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
if (intent.kind === 'catalogGeneration') {
|
|
1397
|
+
signal.throwIfAborted();
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (intent.kind === 'sourceMutation') {
|
|
1401
|
+
const evidence = await captureEvidence(intent, signal);
|
|
1402
|
+
if (evidence.sourceWrite?.configDigest === evidence.sourceWrite?.proposedConfigDigest) {
|
|
1403
|
+
throw new TuiOperationBlockedError('sourceNoChanges', '来源没有变化。');
|
|
1404
|
+
}
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
if (intent.kind === 'configSave') {
|
|
1408
|
+
const packageInfo = await readCliPackageInfo();
|
|
1409
|
+
await withResolvedCatalogPlugin({
|
|
1410
|
+
selector: intent.pluginId,
|
|
1411
|
+
cliVersion: packageInfo.version,
|
|
1412
|
+
env: context.env,
|
|
1413
|
+
signal,
|
|
1414
|
+
...(sessionContextForPlugin(intent.pluginId)
|
|
1415
|
+
? { operationContext: sessionContextForPlugin(intent.pluginId) }
|
|
1416
|
+
: {}),
|
|
1417
|
+
consume: async ({ plugin }) => {
|
|
1418
|
+
if (!plugin.manifest.config) {
|
|
1419
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1420
|
+
}
|
|
1421
|
+
await coercePluginConfigUpdates({
|
|
1422
|
+
schema: plugin.manifest.config.fields,
|
|
1423
|
+
updates: intent.updates ?? {},
|
|
1424
|
+
cwd: context.cwd,
|
|
1425
|
+
});
|
|
1426
|
+
for (const key of intent.removeKeys ?? []) {
|
|
1427
|
+
if (!plugin.manifest.config.fields[key]) {
|
|
1428
|
+
throw new TuiOperationBlockedError('unknownConfigKey', '设置字段已变化,请重新检查。');
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
});
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
if (intent.kind !== 'pluginWrite')
|
|
1436
|
+
return;
|
|
1437
|
+
signal.throwIfAborted();
|
|
1438
|
+
const parsed = parsePluginId(intent.pluginId);
|
|
1439
|
+
if (!parsed.sourceId || !parsed.pluginName) {
|
|
1440
|
+
throw new TuiOperationBlockedError('invalidPluginId', '操作必须使用 canonical pluginId。');
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
captureEvidence,
|
|
1444
|
+
logError(_error, code, logContext) {
|
|
1445
|
+
return context.debugLogger.log({
|
|
1446
|
+
type: 'tui:controller-error',
|
|
1447
|
+
level: 'debug',
|
|
1448
|
+
target: 'debugLog',
|
|
1449
|
+
message: logContext?.privateConfigOperation
|
|
1450
|
+
? 'TUI config operation failed.'
|
|
1451
|
+
: 'TUI controller operation failed.',
|
|
1452
|
+
data: { code },
|
|
1453
|
+
});
|
|
1454
|
+
},
|
|
1455
|
+
async getConfigGroups(pluginId, layer, signal) {
|
|
1456
|
+
const packageInfo = await readCliPackageInfo();
|
|
1457
|
+
return withResolvedCatalogPlugin({
|
|
1458
|
+
selector: pluginId,
|
|
1459
|
+
cliVersion: packageInfo.version,
|
|
1460
|
+
env: context.env,
|
|
1461
|
+
signal,
|
|
1462
|
+
...(sessionContextForPlugin(pluginId)
|
|
1463
|
+
? { operationContext: sessionContextForPlugin(pluginId) }
|
|
1464
|
+
: {}),
|
|
1465
|
+
consume: async ({ plugin }) => {
|
|
1466
|
+
if (!plugin.manifest.config) {
|
|
1467
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1468
|
+
}
|
|
1469
|
+
const read = await resolveConfigRead({
|
|
1470
|
+
pluginName: plugin.manifest.name,
|
|
1471
|
+
plugin,
|
|
1472
|
+
scope: layer.scope,
|
|
1473
|
+
cwd: context.cwd,
|
|
1474
|
+
env: context.env,
|
|
1475
|
+
});
|
|
1476
|
+
const effectiveRead = await resolveConfigRead({
|
|
1477
|
+
pluginName: plugin.manifest.name,
|
|
1478
|
+
plugin,
|
|
1479
|
+
scope: 'effective',
|
|
1480
|
+
cwd: context.cwd,
|
|
1481
|
+
env: context.env,
|
|
1482
|
+
});
|
|
1483
|
+
return buildConfigGroups({ schema: plugin.manifest.config, read, effectiveRead });
|
|
1484
|
+
},
|
|
1485
|
+
});
|
|
1486
|
+
},
|
|
1487
|
+
async getConfigPage(pluginId, layer, signal) {
|
|
1488
|
+
const packageInfo = await readCliPackageInfo();
|
|
1489
|
+
return withResolvedCatalogPlugin({
|
|
1490
|
+
selector: pluginId,
|
|
1491
|
+
cliVersion: packageInfo.version,
|
|
1492
|
+
env: context.env,
|
|
1493
|
+
signal,
|
|
1494
|
+
...(sessionContextForPlugin(pluginId)
|
|
1495
|
+
? { operationContext: sessionContextForPlugin(pluginId) }
|
|
1496
|
+
: {}),
|
|
1497
|
+
consume: async ({ plugin }) => {
|
|
1498
|
+
if (!plugin.manifest.config) {
|
|
1499
|
+
throw new TuiOperationBlockedError('configSchemaUnavailable', '这个插件没有设置 schema。');
|
|
1500
|
+
}
|
|
1501
|
+
const stores = await readConfigStoresForTui({
|
|
1502
|
+
sourceId: plugin.sourceId,
|
|
1503
|
+
sourceIdentity: plugin.sourceIdentity,
|
|
1504
|
+
pluginName: plugin.manifest.name,
|
|
1505
|
+
schema: plugin.manifest.config.fields,
|
|
1506
|
+
scope: layer.scope,
|
|
1507
|
+
signal,
|
|
1508
|
+
});
|
|
1509
|
+
const userStore = stores.user;
|
|
1510
|
+
const projectStore = stores.project;
|
|
1511
|
+
const read = await resolveConfigRead({
|
|
1512
|
+
pluginName: plugin.manifest.name,
|
|
1513
|
+
plugin,
|
|
1514
|
+
scope: layer.scope,
|
|
1515
|
+
cwd: context.cwd,
|
|
1516
|
+
env: context.env,
|
|
1517
|
+
});
|
|
1518
|
+
const effectiveRead = layer.scope === 'effective' ? read : await resolveConfigRead({
|
|
1519
|
+
pluginName: plugin.manifest.name,
|
|
1520
|
+
plugin,
|
|
1521
|
+
scope: 'effective',
|
|
1522
|
+
cwd: context.cwd,
|
|
1523
|
+
env: context.env,
|
|
1524
|
+
});
|
|
1525
|
+
const layerReads = layer.scope === 'effective' ? undefined : {
|
|
1526
|
+
user: layer.scope === 'user' ? read : await resolveConfigRead({
|
|
1527
|
+
pluginName: plugin.manifest.name,
|
|
1528
|
+
plugin,
|
|
1529
|
+
scope: 'user',
|
|
1530
|
+
cwd: context.cwd,
|
|
1531
|
+
env: context.env,
|
|
1532
|
+
}),
|
|
1533
|
+
...(layer.scope === 'user' ? {} : { project: read }),
|
|
1534
|
+
};
|
|
1535
|
+
const effectiveRaw = await resolveEffectivePluginConfig({
|
|
1536
|
+
sourceId: plugin.sourceId,
|
|
1537
|
+
sourceIdentity: plugin.sourceIdentity,
|
|
1538
|
+
pluginName: plugin.manifest.name,
|
|
1539
|
+
manifest: plugin.manifest,
|
|
1540
|
+
targetScope: layer.scope === 'user' ? 'user' : 'project',
|
|
1541
|
+
cwd: context.cwd,
|
|
1542
|
+
env: context.env,
|
|
1543
|
+
});
|
|
1544
|
+
const layerStore = layer.scope === 'effective'
|
|
1545
|
+
? undefined
|
|
1546
|
+
: layer.scope === 'user' ? userStore : projectStore;
|
|
1547
|
+
return buildConfigPage({
|
|
1548
|
+
pluginId,
|
|
1549
|
+
schema: plugin.manifest.config,
|
|
1550
|
+
read,
|
|
1551
|
+
effectiveRead,
|
|
1552
|
+
...(layerReads ? { layerReads } : {}),
|
|
1553
|
+
...(layerStore ? { rawValues: layerStore.values } : {}),
|
|
1554
|
+
rawLayerValues: {
|
|
1555
|
+
user: userStore.values,
|
|
1556
|
+
...(projectStore ? { project: projectStore.values } : {}),
|
|
1557
|
+
},
|
|
1558
|
+
effectiveRawValues: effectiveRaw.values,
|
|
1559
|
+
sharedNativeRefreshKeys: new Set((plugin.manifest.artifacts?.targets ?? []).flatMap((target) => target.target === 'codex.skill' && target.delivery.mode === 'codex-native'
|
|
1560
|
+
? target.refreshKeys
|
|
1561
|
+
: [])),
|
|
1562
|
+
});
|
|
1563
|
+
},
|
|
1564
|
+
});
|
|
1565
|
+
},
|
|
1566
|
+
async getConfigResetAvailability(pluginId, layer, signal) {
|
|
1567
|
+
const parsed = parsePluginId(pluginId);
|
|
1568
|
+
if (!parsed.sourceId || !parsed.pluginName) {
|
|
1569
|
+
throw new TuiOperationBlockedError('invalidPluginId', '设置目标必须使用 canonical pluginId。');
|
|
1570
|
+
}
|
|
1571
|
+
let sourceIdentity;
|
|
1572
|
+
try {
|
|
1573
|
+
const packageInfo = await readCliPackageInfo();
|
|
1574
|
+
sourceIdentity = await withResolvedCatalogPlugin({
|
|
1575
|
+
selector: pluginId,
|
|
1576
|
+
cliVersion: packageInfo.version,
|
|
1577
|
+
env: context.env,
|
|
1578
|
+
signal,
|
|
1579
|
+
...(sessionContextForPlugin(pluginId)
|
|
1580
|
+
? { operationContext: sessionContextForPlugin(pluginId) }
|
|
1581
|
+
: {}),
|
|
1582
|
+
consume: async ({ source }) => source.sourceIdentity,
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
catch {
|
|
1586
|
+
sourceIdentity = undefined;
|
|
1587
|
+
}
|
|
1588
|
+
signal.throwIfAborted();
|
|
1589
|
+
const target = await inspectPluginConfigResetTarget({
|
|
1590
|
+
sourceId: parsed.sourceId,
|
|
1591
|
+
pluginName: parsed.pluginName,
|
|
1592
|
+
scope: layer.scope,
|
|
1593
|
+
cwd: context.cwd,
|
|
1594
|
+
env: context.env,
|
|
1595
|
+
});
|
|
1596
|
+
signal.throwIfAborted();
|
|
1597
|
+
if (target.kind === 'regularFile') {
|
|
1598
|
+
const store = await readPluginConfigStore({
|
|
1599
|
+
sourceId: parsed.sourceId,
|
|
1600
|
+
...(sourceIdentity ? { sourceIdentity } : {}),
|
|
1601
|
+
pluginName: parsed.pluginName,
|
|
1602
|
+
scope: layer.scope,
|
|
1603
|
+
cwd: context.cwd,
|
|
1604
|
+
env: context.env,
|
|
1605
|
+
});
|
|
1606
|
+
signal.throwIfAborted();
|
|
1607
|
+
return {
|
|
1608
|
+
exists: store.exists,
|
|
1609
|
+
state: store.state,
|
|
1610
|
+
...(store.invalidCode ? { invalidCode: store.invalidCode } : {}),
|
|
1611
|
+
sourceIdentityPresent: sourceIdentity !== undefined,
|
|
1612
|
+
...(sourceIdentity ? { sourceIdentity } : {}),
|
|
1613
|
+
targetKind: target.kind,
|
|
1614
|
+
resettable: target.resettable,
|
|
1615
|
+
storeDigest: target.fingerprint,
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
return {
|
|
1619
|
+
exists: target.exists,
|
|
1620
|
+
state: target.kind === 'absent' ? 'missing' : 'invalid',
|
|
1621
|
+
sourceIdentityPresent: sourceIdentity !== undefined,
|
|
1622
|
+
...(sourceIdentity ? { sourceIdentity } : {}),
|
|
1623
|
+
targetKind: target.kind,
|
|
1624
|
+
resettable: target.resettable,
|
|
1625
|
+
storeDigest: target.fingerprint,
|
|
1626
|
+
};
|
|
1627
|
+
},
|
|
1628
|
+
async executeIntent(intent, expectedEvidence, signal) {
|
|
1629
|
+
if (intent.kind === 'catalogSourcesRecovery') {
|
|
1630
|
+
signal?.throwIfAborted();
|
|
1631
|
+
return recoverInvalidCatalogSourcesConfig({ env: context.env });
|
|
1632
|
+
}
|
|
1633
|
+
if (intent.kind === 'catalogGeneration') {
|
|
1634
|
+
signal?.throwIfAborted();
|
|
1635
|
+
const expected = expectedEvidence.catalogGeneration;
|
|
1636
|
+
if (!expected)
|
|
1637
|
+
throw new TuiOperationBlockedError('catalogGenerationReviewStale', '确认信息缺少 Catalog candidate。');
|
|
1638
|
+
const packageInfo = await readCliPackageInfo();
|
|
1639
|
+
let configSaved = false;
|
|
1640
|
+
if (intent.sourceMutation) {
|
|
1641
|
+
const common = {
|
|
1642
|
+
cwd: context.cwd,
|
|
1643
|
+
env: context.env,
|
|
1644
|
+
cliVersion: packageInfo.version,
|
|
1645
|
+
expectedConfigDigest: expected.configDigest,
|
|
1646
|
+
};
|
|
1647
|
+
if (intent.sourceMutation.action === 'add') {
|
|
1648
|
+
await addCatalogSourceCommand({ ...common, source: intent.sourceMutation.source });
|
|
1649
|
+
}
|
|
1650
|
+
else {
|
|
1651
|
+
await updateCatalogSourceCommand({
|
|
1652
|
+
...common,
|
|
1653
|
+
sourceId: intent.sourceId,
|
|
1654
|
+
update: intent.sourceMutation.update,
|
|
1655
|
+
expectedImpactDigest: expected.impactDigest,
|
|
1656
|
+
requireIdentityChangeConfirmation: true,
|
|
1657
|
+
confirmIdentityChange: true,
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
configSaved = true;
|
|
1661
|
+
await tuiControllerRuntimeTestHooks?.afterCatalogSourceConfigCommit?.();
|
|
1662
|
+
}
|
|
1663
|
+
try {
|
|
1664
|
+
let generation;
|
|
1665
|
+
if (intent.action === 'recoverState') {
|
|
1666
|
+
generation = await recoverCatalogGenerationStateAndActivate({
|
|
1667
|
+
sourceId: intent.sourceId,
|
|
1668
|
+
cliVersion: packageInfo.version,
|
|
1669
|
+
cwd: context.cwd,
|
|
1670
|
+
impactConfirmed: true,
|
|
1671
|
+
expectedImpactDigest: expected.impactDigest,
|
|
1672
|
+
expectedCandidate: expected.candidate,
|
|
1673
|
+
env: context.env,
|
|
1674
|
+
signal,
|
|
1675
|
+
runtime: options.catalogGenerationRuntime,
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
else if (intent.action === 'repair') {
|
|
1679
|
+
generation = await repairCatalogSourceGeneration({
|
|
1680
|
+
sourceId: intent.sourceId,
|
|
1681
|
+
cliVersion: packageInfo.version,
|
|
1682
|
+
cwd: context.cwd,
|
|
1683
|
+
expectedCandidate: expected.candidate,
|
|
1684
|
+
expectedActive: expected.previousActive ?? null,
|
|
1685
|
+
expectedConfigDigest: expected.proposedConfigDigest ?? expected.configDigest,
|
|
1686
|
+
env: context.env,
|
|
1687
|
+
signal,
|
|
1688
|
+
runtime: {
|
|
1689
|
+
...options.catalogGenerationRuntime,
|
|
1690
|
+
afterCandidateResolved: tuiControllerRuntimeTestHooks
|
|
1691
|
+
?.afterCatalogGenerationCandidateResolved,
|
|
1692
|
+
},
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
else if (intent.action === 'update' && expected.exactRepair) {
|
|
1696
|
+
generation = await repairCatalogSourceGeneration({
|
|
1697
|
+
sourceId: intent.sourceId,
|
|
1698
|
+
cliVersion: packageInfo.version,
|
|
1699
|
+
cwd: context.cwd,
|
|
1700
|
+
expectedActive: expected.previousActive ?? null,
|
|
1701
|
+
expectedConfigDigest: expected.proposedConfigDigest ?? expected.configDigest,
|
|
1702
|
+
env: context.env,
|
|
1703
|
+
signal,
|
|
1704
|
+
runtime: options.catalogGenerationRuntime,
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
else if (intent.action === 'replaceDamaged') {
|
|
1708
|
+
generation = await replaceDamagedCatalogSourceGeneration({
|
|
1709
|
+
sourceId: intent.sourceId,
|
|
1710
|
+
cliVersion: packageInfo.version,
|
|
1711
|
+
cwd: context.cwd,
|
|
1712
|
+
expectedCandidate: expected.candidate,
|
|
1713
|
+
expectedActive: expected.previousActive,
|
|
1714
|
+
expectedConfigDigest: expected.proposedConfigDigest ?? expected.configDigest,
|
|
1715
|
+
impactConfirmed: true,
|
|
1716
|
+
expectedImpactDigest: expected.impactDigest,
|
|
1717
|
+
env: context.env,
|
|
1718
|
+
signal,
|
|
1719
|
+
runtime: {
|
|
1720
|
+
...options.catalogGenerationRuntime,
|
|
1721
|
+
afterCandidateResolved: tuiControllerRuntimeTestHooks
|
|
1722
|
+
?.afterCatalogGenerationCandidateResolved,
|
|
1723
|
+
},
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
else {
|
|
1727
|
+
generation = await activateCatalogSourceGeneration({
|
|
1728
|
+
sourceId: intent.sourceId,
|
|
1729
|
+
cliVersion: packageInfo.version,
|
|
1730
|
+
cwd: context.cwd,
|
|
1731
|
+
activationMode: expected.activationMode,
|
|
1732
|
+
impactConfirmed: true,
|
|
1733
|
+
expectedImpactDigest: expected.impactDigest,
|
|
1734
|
+
impactMode: expected.impactMode,
|
|
1735
|
+
expectedCandidate: expected.candidate,
|
|
1736
|
+
expectedActive: expected.previousActive ?? null,
|
|
1737
|
+
expectedConfigDigest: expected.proposedConfigDigest ?? expected.configDigest,
|
|
1738
|
+
env: context.env,
|
|
1739
|
+
signal,
|
|
1740
|
+
runtime: {
|
|
1741
|
+
...options.catalogGenerationRuntime,
|
|
1742
|
+
afterCandidateResolved: tuiControllerRuntimeTestHooks
|
|
1743
|
+
?.afterCatalogGenerationCandidateResolved,
|
|
1744
|
+
},
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
let primaryChanged = false;
|
|
1748
|
+
if (intent.setPrimaryAfterActivation) {
|
|
1749
|
+
try {
|
|
1750
|
+
await setPrimaryCatalogSourceCommand({
|
|
1751
|
+
sourceId: intent.sourceId,
|
|
1752
|
+
cwd: context.cwd,
|
|
1753
|
+
env: context.env,
|
|
1754
|
+
});
|
|
1755
|
+
primaryChanged = true;
|
|
1756
|
+
}
|
|
1757
|
+
catch (error) {
|
|
1758
|
+
return {
|
|
1759
|
+
status: 'partial',
|
|
1760
|
+
partialReason: 'primary',
|
|
1761
|
+
configSaved,
|
|
1762
|
+
generation,
|
|
1763
|
+
activeAvailable: true,
|
|
1764
|
+
errorCode: error instanceof Error ? error.name : 'catalogSourcePrimaryFailed',
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
return { status: 'succeeded', generation, configSaved, primaryChanged };
|
|
1769
|
+
}
|
|
1770
|
+
catch (error) {
|
|
1771
|
+
if (!configSaved)
|
|
1772
|
+
throw error;
|
|
1773
|
+
return {
|
|
1774
|
+
status: 'partial',
|
|
1775
|
+
partialReason: 'activation',
|
|
1776
|
+
configSaved: true,
|
|
1777
|
+
errorCode: error instanceof CatalogGenerationError ? error.code : 'catalogGenerationRefreshFailed',
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if (intent.kind === 'portableInstall') {
|
|
1782
|
+
if (!expectedEvidence.portable) {
|
|
1783
|
+
throw operationReviewStale('确认信息缺少 Portable evidence。');
|
|
1784
|
+
}
|
|
1785
|
+
const packageInfo = await readCliPackageInfo();
|
|
1786
|
+
try {
|
|
1787
|
+
return await installPortableSkills({
|
|
1788
|
+
selector: intent.pluginId,
|
|
1789
|
+
scope: intent.scope,
|
|
1790
|
+
requestedSkills: intent.selectedSkills,
|
|
1791
|
+
...(intent.requestedAgents ? { requestedAgents: intent.requestedAgents } : {}),
|
|
1792
|
+
yes: true,
|
|
1793
|
+
cwd: context.cwd,
|
|
1794
|
+
env: context.env,
|
|
1795
|
+
cliVersion: packageInfo.version,
|
|
1796
|
+
expectedEvidenceDigest: expectedEvidence.portable.evidenceDigest,
|
|
1797
|
+
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
1798
|
+
onProgress(stage) {
|
|
1799
|
+
const phase = stage === 'prepare' ? '检查插件依赖并生成候选'
|
|
1800
|
+
: stage === 'add' ? '安装已选择的 Skills' : '验证安装结果';
|
|
1801
|
+
progressFeed?.setCurrent({ target: 'Skills CLI', phase }, `Portable Skills:${phase}`);
|
|
1802
|
+
},
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
catch (error) {
|
|
1806
|
+
if (error instanceof PortableCommandError && error.code === 'reviewStale') {
|
|
1807
|
+
throw operationReviewStale('确认后 Portable 安装证据发生变化。');
|
|
1808
|
+
}
|
|
1809
|
+
throw error;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
if (intent.kind === 'sourceMutation') {
|
|
1813
|
+
const currentEvidence = await captureEvidence(intent);
|
|
1814
|
+
if (operationEvidenceFingerprint(currentEvidence) !== operationEvidenceFingerprint(expectedEvidence)) {
|
|
1815
|
+
throw new TuiOperationBlockedError('operationReviewStale', '确认后状态发生变化。');
|
|
1816
|
+
}
|
|
1817
|
+
await tuiControllerRuntimeTestHooks?.afterMutationEvidenceCapture?.();
|
|
1818
|
+
const packageInfo = await readCliPackageInfo();
|
|
1819
|
+
const runtime = {
|
|
1820
|
+
onProgress: async (event) => {
|
|
1821
|
+
const phase = SOURCE_PROGRESS_PHASES[event.stage];
|
|
1822
|
+
progressFeed?.setCurrent({ target: 'Catalog 来源配置', phase }, `来源操作:${phase}`);
|
|
1823
|
+
await tuiControllerRuntimeTestHooks?.onCatalogSourceProgress?.(event);
|
|
1824
|
+
},
|
|
1825
|
+
};
|
|
1826
|
+
const common = {
|
|
1827
|
+
cwd: context.cwd,
|
|
1828
|
+
env: context.env,
|
|
1829
|
+
expectedConfigDigest: expectedEvidence.sourceWrite?.configDigest,
|
|
1830
|
+
expectedImpactDigest: expectedEvidence.sourceWrite?.impactDigest,
|
|
1831
|
+
runtime,
|
|
1832
|
+
};
|
|
1833
|
+
if (intent.action === 'add' && intent.source) {
|
|
1834
|
+
return addCatalogSourceCommand({ ...common, source: intent.source, cliVersion: packageInfo.version });
|
|
1835
|
+
}
|
|
1836
|
+
if (intent.action === 'update' && intent.update) {
|
|
1837
|
+
return updateCatalogSourceCommand({
|
|
1838
|
+
...common,
|
|
1839
|
+
sourceId: intent.sourceId,
|
|
1840
|
+
update: intent.update,
|
|
1841
|
+
cliVersion: packageInfo.version,
|
|
1842
|
+
requireIdentityChangeConfirmation: true,
|
|
1843
|
+
confirmIdentityChange: true,
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
if (intent.action === 'setPrimary') {
|
|
1847
|
+
return setPrimaryCatalogSourceCommand({ ...common, sourceId: intent.sourceId });
|
|
1848
|
+
}
|
|
1849
|
+
if (intent.action === 'remove') {
|
|
1850
|
+
return removeCatalogSourceCommand({
|
|
1851
|
+
...common,
|
|
1852
|
+
sourceId: intent.sourceId,
|
|
1853
|
+
requireImpactConfirmation: true,
|
|
1854
|
+
confirmImpact: true,
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
throw new TuiOperationBlockedError('invalidSourceMutation', '来源操作缺少候选输入。');
|
|
1858
|
+
}
|
|
1859
|
+
return withAwHomeMutationLock({
|
|
1860
|
+
env: context.env,
|
|
1861
|
+
action: async (awHomeMutationToken) => {
|
|
1862
|
+
await tuiControllerRuntimeTestHooks?.beforeMutationEvidenceCapture?.();
|
|
1863
|
+
const operationInventory = createOperationInventoryReader();
|
|
1864
|
+
const currentEvidence = await captureEvidence(intent, undefined, undefined, operationInventory, true);
|
|
1865
|
+
if (intent.kind !== 'pluginWrite'
|
|
1866
|
+
&& !operationEvidenceMatches(expectedEvidence, currentEvidence)) {
|
|
1867
|
+
throw new TuiOperationBlockedError('operationReviewStale', '确认后状态发生变化。');
|
|
1868
|
+
}
|
|
1869
|
+
const catalogOperation = catalogOperationByEvidence.get(currentEvidence);
|
|
1870
|
+
if (expectedEvidence.catalog.generationSetDigest
|
|
1871
|
+
&& catalogOperation?.generationSetDigest !== expectedEvidence.catalog.generationSetDigest) {
|
|
1872
|
+
throw operationReviewStale('确认后 Active Catalog generation 发生变化。');
|
|
1873
|
+
}
|
|
1874
|
+
await tuiControllerRuntimeTestHooks?.afterMutationEvidenceCapture?.();
|
|
1875
|
+
if (intent.kind === 'pluginWrite') {
|
|
1876
|
+
const options = {
|
|
1877
|
+
cwd: context.cwd,
|
|
1878
|
+
platform: intent.platform,
|
|
1879
|
+
scope: intent.scope,
|
|
1880
|
+
...(intent.action === 'install' && intent.dependencyScopeOverrides
|
|
1881
|
+
? { dependencyScopeOverrides: intent.dependencyScopeOverrides }
|
|
1882
|
+
: {}),
|
|
1883
|
+
...(expectedEvidence.codexManager?.state === 'requires-install'
|
|
1884
|
+
? { allowManagedCodexInstall: true }
|
|
1885
|
+
: {}),
|
|
1886
|
+
...(intent.action === 'cleanup' ? { force: intent.force === true } : {}),
|
|
1887
|
+
};
|
|
1888
|
+
const command = {
|
|
1889
|
+
install: installWriteCommand,
|
|
1890
|
+
refreshAndSync: syncWriteCommand,
|
|
1891
|
+
reinstall: reinstallWriteCommand,
|
|
1892
|
+
uninstall: uninstallWriteCommand,
|
|
1893
|
+
cleanup: cleanupWriteCommand,
|
|
1894
|
+
sync: syncWriteCommand,
|
|
1895
|
+
}[intent.action];
|
|
1896
|
+
const currentSource = currentEvidence.source;
|
|
1897
|
+
const offlineCleanup = currentEvidence.offlineCleanup;
|
|
1898
|
+
if (!offlineCleanup && (!expectedEvidence.source || !currentSource)) {
|
|
1899
|
+
throw new TuiOperationBlockedError('operationReviewStale', '确认信息缺少来源身份。');
|
|
1900
|
+
}
|
|
1901
|
+
const result = await command([intent.pluginId], options, {
|
|
1902
|
+
...context,
|
|
1903
|
+
awHomeMutationToken,
|
|
1904
|
+
inventoryCatalogSourceReferences: operationInventory,
|
|
1905
|
+
...(expectedEvidence.operationPlan
|
|
1906
|
+
? { expectedPlanFingerprint: expectedEvidence.operationPlan.planFingerprint }
|
|
1907
|
+
: {}),
|
|
1908
|
+
expectedCatalogConfigDigest: expectedEvidence.catalog.configDigest,
|
|
1909
|
+
...(catalogOperation ? {
|
|
1910
|
+
catalogOperationContext: catalogOperation,
|
|
1911
|
+
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
1912
|
+
} : {}),
|
|
1913
|
+
...(expectedEvidence.codexManager?.state === 'requires-install'
|
|
1914
|
+
? { managedCodexAuthorizer: async () => true }
|
|
1915
|
+
: {}),
|
|
1916
|
+
...(offlineCleanup
|
|
1917
|
+
? { expectedOfflineCleanupEvidence: offlineCleanup }
|
|
1918
|
+
: { reviewPreflight: (actual) => assertSourceEvidenceMatches(currentSource, actual) }),
|
|
1919
|
+
});
|
|
1920
|
+
throwIfWriteReviewStale(result);
|
|
1921
|
+
return result;
|
|
1922
|
+
}
|
|
1923
|
+
if (intent.kind === 'configSave' || intent.kind === 'configReset') {
|
|
1924
|
+
const currentSource = currentEvidence.source;
|
|
1925
|
+
if (intent.kind === 'configReset') {
|
|
1926
|
+
const parsed = parsePluginId(intent.pluginId);
|
|
1927
|
+
if (!parsed.sourceId || !parsed.pluginName) {
|
|
1928
|
+
throw operationReviewStale('确认信息缺少 qualified 设置目标。');
|
|
1929
|
+
}
|
|
1930
|
+
return resetPluginConfigWithHelper({
|
|
1931
|
+
sourceId: parsed.sourceId,
|
|
1932
|
+
pluginName: parsed.pluginName,
|
|
1933
|
+
scope: intent.scope,
|
|
1934
|
+
cwd: context.cwd,
|
|
1935
|
+
env: context.env,
|
|
1936
|
+
nativeCliRunner: context.nativeCliRunner,
|
|
1937
|
+
rebuildRuntime: { ...context, awHomeMutationToken },
|
|
1938
|
+
awHomeMutationToken,
|
|
1939
|
+
apply: false,
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
if (!currentSource) {
|
|
1943
|
+
throw operationReviewStale('确认信息缺少来源身份。');
|
|
1944
|
+
}
|
|
1945
|
+
const packageInfo = await readCliPackageInfo();
|
|
1946
|
+
return withResolvedCatalogPlugin({
|
|
1947
|
+
selector: intent.pluginId,
|
|
1948
|
+
cliVersion: packageInfo.version,
|
|
1949
|
+
env: context.env,
|
|
1950
|
+
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
1951
|
+
consume: async ({ plugin, source }) => {
|
|
1952
|
+
assertSourceEvidenceMatches(currentSource, sourceEvidenceForPlugin(source, plugin.manifest.name));
|
|
1953
|
+
const applyTargets = intent.apply
|
|
1954
|
+
? currentEvidence.config?.affectedTargets.map((target) => ({
|
|
1955
|
+
pluginName: plugin.manifest.name,
|
|
1956
|
+
platform: target.platform,
|
|
1957
|
+
scope: target.scope,
|
|
1958
|
+
})) ?? []
|
|
1959
|
+
: [];
|
|
1960
|
+
const result = intent.retryApply
|
|
1961
|
+
? await replayConfigRuntimeWrites({
|
|
1962
|
+
plugin,
|
|
1963
|
+
scope: intent.scope,
|
|
1964
|
+
cwd: context.cwd,
|
|
1965
|
+
env: context.env,
|
|
1966
|
+
nativeCliRunner: context.nativeCliRunner,
|
|
1967
|
+
rebuildRuntime: {
|
|
1968
|
+
...context,
|
|
1969
|
+
awHomeMutationToken,
|
|
1970
|
+
...(catalogOperation ? {
|
|
1971
|
+
catalogOperationContext: catalogOperation,
|
|
1972
|
+
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
1973
|
+
} : {}),
|
|
1974
|
+
},
|
|
1975
|
+
awHomeMutationToken,
|
|
1976
|
+
applyTargets,
|
|
1977
|
+
})
|
|
1978
|
+
: await applyPluginConfigWrite({
|
|
1979
|
+
plugin,
|
|
1980
|
+
pluginName: plugin.manifest.name,
|
|
1981
|
+
scope: intent.scope,
|
|
1982
|
+
cwd: context.cwd,
|
|
1983
|
+
env: context.env,
|
|
1984
|
+
nativeCliRunner: context.nativeCliRunner,
|
|
1985
|
+
rebuildRuntime: {
|
|
1986
|
+
...context,
|
|
1987
|
+
awHomeMutationToken,
|
|
1988
|
+
...(catalogOperation ? {
|
|
1989
|
+
catalogOperationContext: catalogOperation,
|
|
1990
|
+
expectedGenerationSetDigest: expectedEvidence.catalog.generationSetDigest,
|
|
1991
|
+
} : {}),
|
|
1992
|
+
},
|
|
1993
|
+
awHomeMutationToken,
|
|
1994
|
+
applyTargets,
|
|
1995
|
+
request: { updates: intent.updates, removeKeys: intent.removeKeys },
|
|
1996
|
+
});
|
|
1997
|
+
return result;
|
|
1998
|
+
},
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
throw new TuiOperationBlockedError('operationNotImplemented', '这个写操作尚未接入新 Controller。');
|
|
2002
|
+
},
|
|
2003
|
+
});
|
|
2004
|
+
},
|
|
2005
|
+
};
|
|
2006
|
+
return dependencies;
|
|
2007
|
+
}
|
|
2008
|
+
export function createConsoleTuiV4Controller(context, progressFeed) {
|
|
2009
|
+
return new TuiController(createTuiControllerDependencies(context, progressFeed), progressFeed);
|
|
2010
|
+
}
|
|
2011
|
+
//# sourceMappingURL=controller-runtime.js.map
|