@lesliechan721/aw 0.1.0-beta.5 → 0.1.0-beta.50
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.mjs +100 -501
- package/dist/authoring/assets/aw-config.mjs.map +1 -1
- package/dist/authoring/assets/aw-runtime-config.d.mts +13 -0
- package/dist/authoring/assets/aw-runtime-config.mjs +199 -0
- package/dist/authoring/assets/aw-runtime-config.mjs.map +1 -0
- package/dist/authoring/scripts/add-skill.mjs +4 -4
- package/dist/authoring/scripts/add-skill.mjs.map +1 -1
- package/dist/authoring/scripts/init-plugin.mjs +67 -97
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-root.mjs +4 -4
- package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-version-check.d.mts +1 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +229 -8
- package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -1
- package/dist/authoring/scripts/lib/skill-scaffold.d.mts +77 -90
- package/dist/authoring/scripts/lib/skill-scaffold.mjs +99 -120
- package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
- package/dist/authoring/scripts/plugin-status.mjs +8 -11
- package/dist/authoring/scripts/plugin-status.mjs.map +1 -1
- package/dist/authoring/scripts/remove-plugin.mjs +3 -2
- package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +346 -1131
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/scripts/aw-skill-eval-materializer.d.ts +26 -0
- package/dist/scripts/aw-skill-eval-materializer.js +306 -0
- package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
- package/dist/scripts/bundle-plugins.d.ts +1 -0
- package/dist/scripts/bundle-plugins.js +20 -5
- package/dist/scripts/bundle-plugins.js.map +1 -1
- package/dist/scripts/plugin-staging.d.ts +7 -9
- package/dist/scripts/plugin-staging.js +18 -29
- package/dist/scripts/plugin-staging.js.map +1 -1
- package/dist/scripts/test-plugin-scripts.d.ts +2 -0
- package/dist/scripts/test-plugin-scripts.js +47 -76
- package/dist/scripts/test-plugin-scripts.js.map +1 -1
- package/dist/scripts/test-workers.d.mts +24 -0
- package/dist/scripts/test-workers.mjs +59 -0
- package/dist/scripts/test-workers.mjs.map +1 -0
- package/dist/src/adapters/helpers.js +2 -2
- package/dist/src/adapters/helpers.js.map +1 -1
- package/dist/src/authoring/workspace-commands.d.ts +17 -1
- package/dist/src/authoring/workspace-commands.js +21 -4
- package/dist/src/authoring/workspace-commands.js.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +78 -0
- package/dist/src/commands/aw-capabilities.js +264 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -0
- package/dist/src/commands/catalog-dev-source.d.ts +154 -0
- package/dist/src/commands/catalog-dev-source.js +655 -0
- package/dist/src/commands/catalog-dev-source.js.map +1 -0
- package/dist/src/commands/catalog-generation.d.ts +21 -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 +71 -30
- package/dist/src/commands/catalog-publication-inspection.js +475 -63
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
- package/dist/src/commands/catalog-publication-journal.d.ts +68 -0
- package/dist/src/commands/catalog-publication-journal.js +292 -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 +73 -15
- package/dist/src/commands/catalog-publish.js +701 -212
- package/dist/src/commands/catalog-publish.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +60 -22
- package/dist/src/commands/catalog-source.js +311 -91
- package/dist/src/commands/catalog-source.js.map +1 -1
- package/dist/src/commands/catalog-status.d.ts +18 -22
- package/dist/src/commands/catalog-status.js +81 -115
- package/dist/src/commands/catalog-status.js.map +1 -1
- package/dist/src/commands/catalog-store.d.ts +104 -0
- package/dist/src/commands/catalog-store.js +685 -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.js +28 -17
- package/dist/src/commands/console.js.map +1 -1
- package/dist/src/commands/dependency-operation-plan.d.ts +52 -15
- package/dist/src/commands/dependency-operation-plan.js +289 -7
- package/dist/src/commands/dependency-operation-plan.js.map +1 -1
- package/dist/src/commands/init.d.ts +5 -11
- package/dist/src/commands/init.js +30 -51
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/offline-cleanup-evidence.d.ts +67 -0
- package/dist/src/commands/offline-cleanup-evidence.js +181 -0
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
- package/dist/src/commands/operation-plan.d.ts +146 -0
- package/dist/src/commands/operation-plan.js +71 -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 +141 -0
- package/dist/src/commands/operation-planner.js.map +1 -0
- package/dist/src/commands/options.d.ts +9 -7
- package/dist/src/commands/options.js +83 -21
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +23 -3
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +77 -31
- package/dist/src/commands/rebuild-command.js +4862 -729
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +131 -21
- package/dist/src/commands/rebuild-integration.js +2866 -1339
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +58 -30
- package/dist/src/commands/rebuild-operations.js +260 -319
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/commands/reconcile-operation-plan.d.ts +28 -0
- package/dist/src/commands/reconcile-operation-plan.js +47 -0
- package/dist/src/commands/reconcile-operation-plan.js.map +1 -0
- package/dist/src/commands/review-inspection.d.ts +228 -0
- package/dist/src/commands/review-inspection.js +1341 -0
- package/dist/src/commands/review-inspection.js.map +1 -0
- package/dist/src/commands/review-preparation.d.ts +49 -0
- package/dist/src/commands/review-preparation.js +427 -0
- package/dist/src/commands/review-preparation.js.map +1 -0
- package/dist/src/commands/runtime.d.ts +1 -5
- package/dist/src/commands/runtime.js +24 -50
- package/dist/src/commands/runtime.js.map +1 -1
- package/dist/src/commands/skill-eval.d.ts +39 -0
- package/dist/src/commands/skill-eval.js +400 -0
- package/dist/src/commands/skill-eval.js.map +1 -0
- package/dist/src/commands/status-v6.d.ts +279 -0
- package/dist/src/commands/status-v6.js +2787 -0
- package/dist/src/commands/status-v6.js.map +1 -0
- package/dist/src/commands/sync-command.d.ts +40 -0
- package/dist/src/commands/sync-command.js +250 -0
- package/dist/src/commands/sync-command.js.map +1 -0
- package/dist/src/commands/wizard.d.ts +8 -5
- package/dist/src/commands/wizard.js +6 -4
- package/dist/src/commands/wizard.js.map +1 -1
- package/dist/src/commands/write-commands.d.ts +9 -3
- package/dist/src/commands/write-commands.js +127 -31
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/constants.d.ts +7 -1
- package/dist/src/constants.js +7 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/eval/manifest-v1.d.ts +71 -0
- package/dist/src/eval/manifest-v1.js +370 -0
- package/dist/src/eval/manifest-v1.js.map +1 -0
- package/dist/src/generators/local-plugin.d.ts +5 -1
- package/dist/src/generators/local-plugin.js +236 -109
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.d.ts +10 -4
- package/dist/src/index.js +1793 -486
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.d.ts +43 -46
- package/dist/src/output/command-receipt.js +256 -80
- package/dist/src/output/command-receipt.js.map +1 -1
- package/dist/src/output/model.d.ts +3 -44
- package/dist/src/output/model.js +1 -144
- package/dist/src/output/model.js.map +1 -1
- package/dist/src/output/rebuild-progress.js +1 -13
- package/dist/src/output/rebuild-progress.js.map +1 -1
- package/dist/src/portable/commands.d.ts +46 -7
- package/dist/src/portable/commands.js +349 -37
- package/dist/src/portable/commands.js.map +1 -1
- package/dist/src/portable/materializer.d.ts +17 -4
- package/dist/src/portable/materializer.js +179 -41
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/portable/skills-cli.d.ts +15 -7
- package/dist/src/portable/skills-cli.js +74 -20
- package/dist/src/portable/skills-cli.js.map +1 -1
- package/dist/src/review/eval-source-input.d.ts +43 -0
- package/dist/src/review/eval-source-input.js +207 -0
- package/dist/src/review/eval-source-input.js.map +1 -0
- package/dist/src/review/review-profile.d.ts +17 -0
- package/dist/src/review/review-profile.js +234 -0
- package/dist/src/review/review-profile.js.map +1 -0
- package/dist/src/review/review-selection.d.ts +30 -0
- package/dist/src/review/review-selection.js +527 -0
- package/dist/src/review/review-selection.js.map +1 -0
- package/dist/src/review/review-types.d.ts +68 -0
- package/dist/src/review/review-types.js +16 -0
- package/dist/src/review/review-types.js.map +1 -0
- package/dist/src/review/skill-materialization.d.ts +13 -0
- package/dist/src/review/skill-materialization.js +75 -0
- package/dist/src/review/skill-materialization.js.map +1 -0
- package/dist/src/review/source-binding.d.ts +183 -0
- package/dist/src/review/source-binding.js +708 -0
- package/dist/src/review/source-binding.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 +156 -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 +40 -0
- package/dist/src/tui/catalog-sources/screens.js.map +1 -0
- package/dist/src/tui/catalog-sources/session.d.ts +32 -0
- package/dist/src/tui/catalog-sources/session.js +300 -0
- package/dist/src/tui/catalog-sources/session.js.map +1 -0
- package/dist/src/tui/catalog-sources/types.d.ts +54 -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/catalog-store-task.d.ts +16 -0
- package/dist/src/tui/catalog-store-task.js +19 -0
- package/dist/src/tui/catalog-store-task.js.map +1 -0
- package/dist/src/tui/clipboard.d.ts +13 -0
- package/dist/src/tui/clipboard.js +95 -0
- package/dist/src/tui/clipboard.js.map +1 -0
- package/dist/src/tui/components.d.ts +110 -3
- package/dist/src/tui/components.js +183 -36
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/config-array-draft.d.ts +29 -0
- package/dist/src/tui/config-array-draft.js +48 -0
- package/dist/src/tui/config-array-draft.js.map +1 -0
- package/dist/src/tui/config-leaf-editor.d.ts +16 -0
- package/dist/src/tui/config-leaf-editor.js +206 -0
- package/dist/src/tui/config-leaf-editor.js.map +1 -0
- package/dist/src/tui/config-value-presentation.d.ts +20 -0
- package/dist/src/tui/config-value-presentation.js +104 -0
- package/dist/src/tui/config-value-presentation.js.map +1 -0
- package/dist/src/tui/console-app-v4.d.ts +14 -4
- package/dist/src/tui/console-app-v4.js +8941 -1872
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/content-item-card.d.ts +13 -0
- package/dist/src/tui/content-item-card.js +51 -0
- package/dist/src/tui/content-item-card.js.map +1 -0
- package/dist/src/tui/controller-runtime.d.ts +10 -2
- package/dist/src/tui/controller-runtime.js +3211 -388
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +615 -45
- package/dist/src/tui/controller.js +3558 -768
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/dependency-graph-view.d.ts +39 -0
- package/dist/src/tui/dependency-graph-view.js +121 -0
- package/dist/src/tui/dependency-graph-view.js.map +1 -0
- package/dist/src/tui/dependency-graph.d.ts +81 -0
- package/dist/src/tui/dependency-graph.js +452 -0
- package/dist/src/tui/dependency-graph.js.map +1 -0
- package/dist/src/tui/diagnostic-projection.d.ts +23 -0
- package/dist/src/tui/diagnostic-projection.js +567 -0
- package/dist/src/tui/diagnostic-projection.js.map +1 -0
- package/dist/src/tui/diagnostics.d.ts +3 -3
- package/dist/src/tui/diagnostics.js +14 -2
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/entity-cards.d.ts +55 -0
- package/dist/src/tui/entity-cards.js +220 -0
- package/dist/src/tui/entity-cards.js.map +1 -0
- package/dist/src/tui/glossary.d.ts +23 -0
- package/dist/src/tui/glossary.js +42 -0
- package/dist/src/tui/glossary.js.map +1 -0
- package/dist/src/tui/index.d.ts +6 -1
- package/dist/src/tui/index.js +5 -1
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/input-display.d.ts +9 -0
- package/dist/src/tui/input-display.js +58 -0
- package/dist/src/tui/input-display.js.map +1 -0
- package/dist/src/tui/keys.d.ts +44 -0
- package/dist/src/tui/keys.js +43 -15
- package/dist/src/tui/keys.js.map +1 -1
- package/dist/src/tui/lifecycle-action-view.d.ts +6 -0
- package/dist/src/tui/lifecycle-action-view.js +36 -0
- package/dist/src/tui/lifecycle-action-view.js.map +1 -0
- package/dist/src/tui/model.d.ts +223 -31
- package/dist/src/tui/model.js +1510 -397
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/operation-diagnostic-screens.d.ts +8 -0
- package/dist/src/tui/operation-diagnostic-screens.js +71 -0
- package/dist/src/tui/operation-diagnostic-screens.js.map +1 -0
- package/dist/src/tui/operation-history.d.ts +81 -0
- package/dist/src/tui/operation-history.js +136 -0
- package/dist/src/tui/operation-history.js.map +1 -0
- package/dist/src/tui/operation-review-planner.d.ts +21 -0
- package/dist/src/tui/operation-review-planner.js +1295 -0
- package/dist/src/tui/operation-review-planner.js.map +1 -0
- package/dist/src/tui/plugin-content.d.ts +31 -0
- package/dist/src/tui/plugin-content.js +680 -0
- package/dist/src/tui/plugin-content.js.map +1 -0
- package/dist/src/tui/plugin-detail.d.ts +52 -0
- package/dist/src/tui/plugin-detail.js +165 -0
- package/dist/src/tui/plugin-detail.js.map +1 -0
- package/dist/src/tui/plugin-write-task.d.ts +69 -0
- package/dist/src/tui/plugin-write-task.js +286 -0
- package/dist/src/tui/plugin-write-task.js.map +1 -0
- package/dist/src/tui/project-inventory.d.ts +68 -0
- package/dist/src/tui/project-inventory.js +203 -0
- package/dist/src/tui/project-inventory.js.map +1 -0
- package/dist/src/tui/prompt.js +4 -15
- package/dist/src/tui/prompt.js.map +1 -1
- package/dist/src/tui/query-header.d.ts +30 -0
- package/dist/src/tui/query-header.js +40 -0
- package/dist/src/tui/query-header.js.map +1 -0
- package/dist/src/tui/reader.d.ts +37 -0
- package/dist/src/tui/reader.js +47 -0
- package/dist/src/tui/reader.js.map +1 -0
- package/dist/src/tui/router.d.ts +197 -10
- package/dist/src/tui/router.js +338 -50
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/screen-registry.d.ts +701 -0
- package/dist/src/tui/screen-registry.js +230 -0
- package/dist/src/tui/screen-registry.js.map +1 -0
- package/dist/src/tui/session-console-app.d.ts +6 -0
- package/dist/src/tui/session-console-app.js +13 -0
- package/dist/src/tui/session-console-app.js.map +1 -0
- package/dist/src/tui/session-host.d.ts +45 -0
- package/dist/src/tui/session-host.js +209 -0
- package/dist/src/tui/session-host.js.map +1 -0
- package/dist/src/tui/source-detail-card.d.ts +29 -0
- package/dist/src/tui/source-detail-card.js +45 -0
- package/dist/src/tui/source-detail-card.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 +12 -0
- package/dist/src/tui/theme.js +12 -0
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/viewport.d.ts +1 -0
- package/dist/src/tui/viewport.js +23 -0
- package/dist/src/tui/viewport.js.map +1 -1
- package/dist/src/tui/views.js +31 -3
- package/dist/src/tui/views.js.map +1 -1
- package/dist/src/tui/wizard.js +37 -13
- package/dist/src/tui/wizard.js.map +1 -1
- package/dist/src/types.d.ts +244 -20
- package/dist/src/types.js +1 -0
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/agent-version.d.ts +7 -1
- package/dist/src/utils/agent-version.js +41 -8
- package/dist/src/utils/agent-version.js.map +1 -1
- package/dist/src/utils/artifact-plan.d.ts +5 -4
- package/dist/src/utils/artifact-plan.js +18 -7
- package/dist/src/utils/artifact-plan.js.map +1 -1
- package/dist/src/utils/artifact-renderer.d.ts +17 -7
- package/dist/src/utils/artifact-renderer.js +214 -216
- package/dist/src/utils/artifact-renderer.js.map +1 -1
- package/dist/src/utils/artifact-request.d.ts +21 -0
- package/dist/src/utils/artifact-request.js +78 -0
- package/dist/src/utils/artifact-request.js.map +1 -0
- package/dist/src/utils/aw-home-mutation-lock.d.ts +1 -0
- package/dist/src/utils/aw-home-mutation-lock.js +32 -4
- package/dist/src/utils/aw-home-mutation-lock.js.map +1 -1
- package/dist/src/utils/bundle-integrity.d.ts +0 -1
- package/dist/src/utils/bundle-integrity.js +0 -25
- package/dist/src/utils/bundle-integrity.js.map +1 -1
- package/dist/src/utils/bundle-layout.js +22 -29
- package/dist/src/utils/bundle-layout.js.map +1 -1
- package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
- package/dist/src/utils/catalog-capability-projection.js +14 -0
- package/dist/src/utils/catalog-capability-projection.js.map +1 -0
- package/dist/src/utils/catalog-digests.d.ts +10 -0
- package/dist/src/utils/catalog-digests.js +57 -20
- package/dist/src/utils/catalog-digests.js.map +1 -1
- 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 +44 -0
- package/dist/src/utils/catalog-generation-resolver.js +273 -0
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
- package/dist/src/utils/catalog-generation-service.d.ts +172 -0
- package/dist/src/utils/catalog-generation-service.js +1271 -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 +58 -0
- package/dist/src/utils/catalog-generation-store.js +452 -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-v4.js → catalog-manifest-v7.js} +35 -43
- 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 +142 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -0
- package/dist/src/utils/catalog-public-error.d.ts +7 -3
- package/dist/src/utils/catalog-public-error.js +28 -8
- package/dist/src/utils/catalog-public-error.js.map +1 -1
- package/dist/src/utils/catalog-runtime-projection.d.ts +3 -0
- package/dist/src/utils/catalog-runtime-projection.js +5 -40
- package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
- package/dist/src/utils/catalog-snapshot.d.ts +5 -3
- package/dist/src/utils/catalog-snapshot.js +11 -3
- package/dist/src/utils/catalog-snapshot.js.map +1 -1
- package/dist/src/utils/catalog-source-identity.d.ts +1 -0
- package/dist/src/utils/catalog-source-identity.js +21 -2
- package/dist/src/utils/catalog-source-identity.js.map +1 -1
- package/dist/src/utils/catalog-source-impact.d.ts +21 -0
- package/dist/src/utils/catalog-source-impact.js +344 -0
- package/dist/src/utils/catalog-source-impact.js.map +1 -0
- package/dist/src/utils/catalog-source-references.d.ts +3 -2
- package/dist/src/utils/catalog-source-references.js +195 -347
- package/dist/src/utils/catalog-source-references.js.map +1 -1
- package/dist/src/utils/catalog-sources.d.ts +15 -1
- package/dist/src/utils/catalog-sources.js +206 -27
- package/dist/src/utils/catalog-sources.js.map +1 -1
- package/dist/src/utils/codex-config.d.ts +2 -0
- package/dist/src/utils/codex-config.js +26 -5
- package/dist/src/utils/codex-config.js.map +1 -1
- package/dist/src/utils/codex-manager.d.ts +79 -0
- package/dist/src/utils/codex-manager.js +747 -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 +49 -0
- package/dist/src/utils/codex-native-observation.js +154 -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 +126 -0
- package/dist/src/utils/codex-reconciler.js +298 -0
- package/dist/src/utils/codex-reconciler.js.map +1 -0
- package/dist/src/utils/codex-shared-native.d.ts +43 -0
- package/dist/src/utils/codex-shared-native.js +81 -0
- package/dist/src/utils/codex-shared-native.js.map +1 -0
- package/dist/src/utils/codex-skill-staging.d.ts +2 -0
- package/dist/src/utils/codex-skill-staging.js.map +1 -1
- package/dist/src/utils/codex-surface-analysis.d.ts +46 -0
- package/dist/src/utils/codex-surface-analysis.js +247 -0
- package/dist/src/utils/codex-surface-analysis.js.map +1 -0
- package/dist/src/utils/dynamic-skill-tree.d.ts +4 -0
- package/dist/src/utils/dynamic-skill-tree.js +35 -5
- package/dist/src/utils/dynamic-skill-tree.js.map +1 -1
- package/dist/src/utils/git-catalog-provider.d.ts +16 -0
- package/dist/src/utils/git-catalog-provider.js +177 -145
- package/dist/src/utils/git-catalog-provider.js.map +1 -1
- package/dist/src/utils/local-marketplace.d.ts +18 -1
- package/dist/src/utils/local-marketplace.js +354 -84
- package/dist/src/utils/local-marketplace.js.map +1 -1
- package/dist/src/utils/manifest.d.ts +1 -3
- package/dist/src/utils/manifest.js +1 -3
- package/dist/src/utils/manifest.js.map +1 -1
- package/dist/src/utils/multi-source-catalog.d.ts +3 -9
- package/dist/src/utils/multi-source-catalog.js +54 -110
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +55 -7
- package/dist/src/utils/native-cli.js +400 -58
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/orphan-marketplace-cleanup.js +0 -4
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
- package/dist/src/utils/ownership.d.ts +84 -20
- package/dist/src/utils/ownership.js +179 -222
- package/dist/src/utils/ownership.js.map +1 -1
- package/dist/src/utils/path-catalog-provider.d.ts +1 -1
- package/dist/src/utils/path-catalog-provider.js +54 -65
- package/dist/src/utils/path-catalog-provider.js.map +1 -1
- package/dist/src/utils/paths.d.ts +0 -1
- package/dist/src/utils/paths.js +0 -1
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/plugin-config-impact.d.ts +33 -0
- package/dist/src/utils/plugin-config-impact.js +298 -0
- package/dist/src/utils/plugin-config-impact.js.map +1 -0
- package/dist/src/utils/plugin-config-write.d.ts +52 -27
- package/dist/src/utils/plugin-config-write.js +1000 -296
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +153 -93
- package/dist/src/utils/plugin-config.js +1116 -968
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/dist/src/utils/plugin-intent-state.d.ts +49 -0
- package/dist/src/utils/plugin-intent-state.js +320 -0
- package/dist/src/utils/plugin-intent-state.js.map +1 -0
- package/dist/src/utils/plugin-scripts.d.ts +65 -125
- package/dist/src/utils/plugin-scripts.js +484 -524
- package/dist/src/utils/plugin-scripts.js.map +1 -1
- package/dist/src/utils/process-tree.d.ts +2 -2
- package/dist/src/utils/process-tree.js +1 -1
- package/dist/src/utils/process-tree.js.map +1 -1
- package/dist/src/utils/project-boundary.d.ts +11 -13
- package/dist/src/utils/project-boundary.js +28 -34
- package/dist/src/utils/project-boundary.js.map +1 -1
- package/dist/src/utils/runtime-config.d.ts +20 -0
- package/dist/src/utils/runtime-config.js +75 -0
- package/dist/src/utils/runtime-config.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/safe-operation-diagnostic.d.ts +15 -0
- package/dist/src/utils/safe-operation-diagnostic.js +33 -0
- package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
- package/dist/src/utils/sensitive-content.d.ts +4 -0
- package/dist/src/utils/sensitive-content.js +36 -0
- package/dist/src/utils/sensitive-content.js.map +1 -0
- package/dist/src/utils/state-paths.js +7 -2
- package/dist/src/utils/state-paths.js.map +1 -1
- package/dist/src/utils/target-eligibility.d.ts +8 -2
- package/dist/src/utils/target-eligibility.js +17 -8
- package/dist/src/utils/target-eligibility.js.map +1 -1
- package/dist/src/utils/windows-claude-shim.d.ts +7 -0
- package/dist/src/utils/windows-claude-shim.js +10 -0
- package/dist/src/utils/windows-claude-shim.js.map +1 -0
- package/dist/src/utils/windows-npm-shim.d.ts +14 -0
- package/dist/src/utils/windows-npm-shim.js +140 -0
- package/dist/src/utils/windows-npm-shim.js.map +1 -0
- package/dist/vitest.config.js +92 -10
- package/dist/vitest.config.js.map +1 -1
- package/package.json +27 -18
- package/dist/authoring/scripts/check-plugin-versions.d.mts +0 -2
- package/dist/authoring/scripts/check-plugin-versions.mjs +0 -5
- package/dist/authoring/scripts/check-plugin-versions.mjs.map +0 -1
- package/dist/scripts/aw-skill-eval-engine.d.ts +0 -13
- package/dist/scripts/aw-skill-eval-engine.js +0 -31
- package/dist/scripts/aw-skill-eval-engine.js.map +0 -1
- package/dist/scripts/codex-eval-app-server.d.ts +0 -89
- package/dist/scripts/codex-eval-app-server.js +0 -1228
- package/dist/scripts/codex-eval-app-server.js.map +0 -1
- package/dist/scripts/codex-eval-isolation.d.ts +0 -61
- package/dist/scripts/codex-eval-isolation.js +0 -318
- package/dist/scripts/codex-eval-isolation.js.map +0 -1
- package/dist/scripts/codex-eval-process-management.d.ts +0 -8
- package/dist/scripts/codex-eval-process-management.js +0 -69
- package/dist/scripts/codex-eval-process-management.js.map +0 -1
- package/dist/scripts/codex-eval-process-tree.d.ts +0 -38
- package/dist/scripts/codex-eval-process-tree.js +0 -803
- package/dist/scripts/codex-eval-process-tree.js.map +0 -1
- package/dist/scripts/codex-eval-runtime-config.d.ts +0 -62
- package/dist/scripts/codex-eval-runtime-config.js +0 -843
- package/dist/scripts/codex-eval-runtime-config.js.map +0 -1
- package/dist/scripts/codex-trigger-eval.d.ts +0 -84
- package/dist/scripts/codex-trigger-eval.js +0 -968
- package/dist/scripts/codex-trigger-eval.js.map +0 -1
- package/dist/scripts/eval-plugin-skills-audited.d.ts +0 -6
- package/dist/scripts/eval-plugin-skills-audited.js +0 -261
- package/dist/scripts/eval-plugin-skills-audited.js.map +0 -1
- package/dist/scripts/eval-plugin-skills.d.ts +0 -45
- package/dist/scripts/eval-plugin-skills.js +0 -1586
- package/dist/scripts/eval-plugin-skills.js.map +0 -1
- package/dist/scripts/eval-run-layout.d.ts +0 -17
- package/dist/scripts/eval-run-layout.js +0 -26
- package/dist/scripts/eval-run-layout.js.map +0 -1
- package/dist/scripts/plugin-eval-contract.d.ts +0 -185
- package/dist/scripts/plugin-eval-contract.js +0 -695
- package/dist/scripts/plugin-eval-contract.js.map +0 -1
- package/dist/scripts/plugin-eval-materializer.d.ts +0 -13
- package/dist/scripts/plugin-eval-materializer.js +0 -421
- package/dist/scripts/plugin-eval-materializer.js.map +0 -1
- package/dist/scripts/skill-reporting.d.ts +0 -212
- package/dist/scripts/skill-reporting.js +0 -922
- package/dist/scripts/skill-reporting.js.map +0 -1
- package/dist/src/commands/status-v4.d.ts +0 -123
- package/dist/src/commands/status-v4.js +0 -905
- package/dist/src/commands/status-v4.js.map +0 -1
- package/dist/src/commands/status.d.ts +0 -93
- package/dist/src/commands/status.js +0 -442
- package/dist/src/commands/status.js.map +0 -1
- package/dist/src/utils/active-marketplace-runtime-lock.d.ts +0 -12
- package/dist/src/utils/active-marketplace-runtime-lock.js +0 -133
- package/dist/src/utils/active-marketplace-runtime-lock.js.map +0 -1
- package/dist/src/utils/catalog-manifest-v3.d.ts +0 -2
- package/dist/src/utils/catalog-manifest-v3.js +0 -3
- package/dist/src/utils/catalog-manifest-v3.js.map +0 -1
- package/dist/src/utils/catalog-manifest-v4.d.ts +0 -5
- package/dist/src/utils/catalog-manifest-v4.js.map +0 -1
- package/dist/src/utils/catalog-source-cache.d.ts +0 -62
- package/dist/src/utils/catalog-source-cache.js +0 -296
- package/dist/src/utils/catalog-source-cache.js.map +0 -1
- package/dist/src/utils/codex-project-surface.d.ts +0 -3
- package/dist/src/utils/codex-project-surface.js +0 -49
- package/dist/src/utils/codex-project-surface.js.map +0 -1
- package/dist/src/utils/lifecycle-active-store.d.ts +0 -175
- package/dist/src/utils/lifecycle-active-store.js +0 -1276
- package/dist/src/utils/lifecycle-active-store.js.map +0 -1
- package/dist/src/utils/plugin-release.d.ts +0 -2
- package/dist/src/utils/plugin-release.js +0 -2
- package/dist/src/utils/plugin-release.js.map +0 -1
package/dist/src/tui/model.js
CHANGED
|
@@ -1,20 +1,321 @@
|
|
|
1
|
+
import { configObjectHasSensitiveChild, presentConfigValue, safeConfigText } from './config-value-presentation.js';
|
|
2
|
+
export { configObjectHasSensitiveChild } from './config-value-presentation.js';
|
|
3
|
+
import { matchPluginConfigPreset, resolvePluginConfigObjectProperties, stablePluginConfigStringify, } from '@lesliechan721/aw-plugin-core/manifest';
|
|
4
|
+
import { flattenStatusTargets, statusTargetActivation, statusTargetExtensions, statusTargetIntent, statusTargetOwnershipState, statusTargetSharedNative, } from '../commands/status-v6.js';
|
|
5
|
+
import { buildAllowedLifecycleActions } from '../commands/operation-planner.js';
|
|
1
6
|
import { safeDiagnosticCode, } from './diagnostics.js';
|
|
7
|
+
import { projectCatalogSourceState } from './catalog-sources/projection.js';
|
|
8
|
+
import { projectLifecycleActionView } from './lifecycle-action-view.js';
|
|
9
|
+
import { compareStrictSemVer, tryParseStrictSemVer } from '../utils/manifest.js';
|
|
10
|
+
import { formatPluginId } from '../utils/multi-source-catalog.js';
|
|
11
|
+
import { createCatalogStoreKey } from '../utils/catalog-generation-store.js';
|
|
12
|
+
function candidateForPlugin(pluginId, sourceId, freshness) {
|
|
13
|
+
return freshness?.candidatePlugins?.find((entry) => formatPluginId({
|
|
14
|
+
sourceId,
|
|
15
|
+
pluginName: entry.name,
|
|
16
|
+
}) === pluginId);
|
|
17
|
+
}
|
|
18
|
+
export function buildPluginUpdateSummary(options) {
|
|
19
|
+
const candidate = candidateForPlugin(options.pluginId, options.sourceId, options.freshness);
|
|
20
|
+
let sameVersionCandidateChange = false;
|
|
21
|
+
let blockedCandidate = Boolean(options.freshness?.candidate
|
|
22
|
+
&& options.freshness.candidatePlugins && !candidate);
|
|
23
|
+
const targets = options.targetRevisions
|
|
24
|
+
.filter((entry) => entry.pluginId === options.pluginId)
|
|
25
|
+
.map((entry) => {
|
|
26
|
+
const installedVersion = entry.revision.installedVersion;
|
|
27
|
+
const activeVersion = entry.revision.availableVersion;
|
|
28
|
+
const liveTarget = options.targets.find((target) => target.pluginId === entry.pluginId
|
|
29
|
+
&& target.platform === entry.platform && target.scope === entry.scope);
|
|
30
|
+
const needsRepair = liveTarget !== undefined && liveTarget.state !== 'ready'
|
|
31
|
+
&& !isDirectCodexVersionUpgrade(liveTarget, entry.revision);
|
|
32
|
+
const installedValid = installedVersion !== undefined && tryParseStrictSemVer(installedVersion) !== null;
|
|
33
|
+
const activeValid = activeVersion !== undefined && tryParseStrictSemVer(activeVersion) !== null;
|
|
34
|
+
const candidateValid = candidate !== undefined && tryParseStrictSemVer(candidate.version) !== null;
|
|
35
|
+
const candidateCompatible = (candidate?.missingCapabilities.length ?? 0) === 0;
|
|
36
|
+
let targetCandidateBlocked = false;
|
|
37
|
+
const candidateEvidence = candidate && options.freshness?.candidate
|
|
38
|
+
? createCatalogStoreKey(options.freshness.candidate.logicalIdentity, options.freshness.candidate.snapshotDigest)
|
|
39
|
+
: undefined;
|
|
40
|
+
if (!installedValid) {
|
|
41
|
+
return {
|
|
42
|
+
platform: entry.platform,
|
|
43
|
+
scope: entry.scope,
|
|
44
|
+
...(installedVersion ? { installedVersion } : {}),
|
|
45
|
+
...(activeVersion ? { activeVersion } : {}),
|
|
46
|
+
...(candidate ? { candidateVersion: candidate.version } : {}),
|
|
47
|
+
...(candidateEvidence ? { candidateEvidence } : {}),
|
|
48
|
+
eligibility: 'unverified',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (entry.revision.state === 'upgradeAvailable' && activeValid) {
|
|
52
|
+
return {
|
|
53
|
+
platform: entry.platform,
|
|
54
|
+
scope: entry.scope,
|
|
55
|
+
installedVersion,
|
|
56
|
+
activeVersion,
|
|
57
|
+
...(candidate ? { candidateVersion: candidate.version } : {}),
|
|
58
|
+
availableVersion: activeVersion,
|
|
59
|
+
...(candidateEvidence ? { candidateEvidence } : {}),
|
|
60
|
+
eligibility: needsRepair ? 'needsRepair' : 'allowed',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (candidateValid) {
|
|
64
|
+
const candidateRelation = compareStrictSemVer(installedVersion, candidate.version);
|
|
65
|
+
const candidateUsable = candidateCompatible
|
|
66
|
+
&& options.freshness?.state !== 'incompatible'
|
|
67
|
+
&& options.freshness?.state !== 'rollbackDetected'
|
|
68
|
+
&& options.freshness?.state !== 'versionConflict';
|
|
69
|
+
if (candidateRelation < 0 && candidateUsable) {
|
|
70
|
+
return {
|
|
71
|
+
platform: entry.platform,
|
|
72
|
+
scope: entry.scope,
|
|
73
|
+
installedVersion,
|
|
74
|
+
...(activeVersion ? { activeVersion } : {}),
|
|
75
|
+
candidateVersion: candidate.version,
|
|
76
|
+
availableVersion: candidate.version,
|
|
77
|
+
...(candidateEvidence ? { candidateEvidence } : {}),
|
|
78
|
+
...(candidate.missingCapabilities.length > 0
|
|
79
|
+
? { missingCapabilities: [...candidate.missingCapabilities] }
|
|
80
|
+
: {}),
|
|
81
|
+
eligibility: needsRepair ? 'needsRepair' : 'allowed',
|
|
82
|
+
requiresCatalogActivation: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (candidateRelation < 0 || candidateRelation > 0) {
|
|
86
|
+
blockedCandidate = true;
|
|
87
|
+
targetCandidateBlocked = true;
|
|
88
|
+
}
|
|
89
|
+
if (candidateRelation === 0 && activeVersion === candidate.version
|
|
90
|
+
&& options.freshness?.state !== 'current')
|
|
91
|
+
sameVersionCandidateChange = true;
|
|
92
|
+
}
|
|
93
|
+
const activeDowngrade = activeValid
|
|
94
|
+
&& compareStrictSemVer(installedVersion, activeVersion) > 0;
|
|
95
|
+
return {
|
|
96
|
+
platform: entry.platform,
|
|
97
|
+
scope: entry.scope,
|
|
98
|
+
installedVersion,
|
|
99
|
+
...(activeVersion ? { activeVersion } : {}),
|
|
100
|
+
...(candidate ? { candidateVersion: candidate.version } : {}),
|
|
101
|
+
...(candidateEvidence ? { candidateEvidence } : {}),
|
|
102
|
+
...(candidate && candidate.missingCapabilities.length > 0
|
|
103
|
+
? { missingCapabilities: [...candidate.missingCapabilities] }
|
|
104
|
+
: {}),
|
|
105
|
+
eligibility: activeDowngrade || targetCandidateBlocked ? 'incompatible'
|
|
106
|
+
: needsRepair ? 'needsRepair' : activeValid ? 'allowed' : 'unverified',
|
|
107
|
+
};
|
|
108
|
+
})
|
|
109
|
+
.sort((left, right) => `${left.platform}\0${left.scope}`.localeCompare(`${right.platform}\0${right.scope}`, 'en'));
|
|
110
|
+
const hasAvailable = targets.some((target) => target.availableVersion !== undefined);
|
|
111
|
+
const hasInstalledVersion = targets.some((target) => target.installedVersion !== undefined);
|
|
112
|
+
const allCurrent = targets.length > 0 && targets.every((target) => target.activeVersion !== undefined
|
|
113
|
+
&& target.installedVersion !== undefined
|
|
114
|
+
&& tryParseStrictSemVer(target.activeVersion) !== null
|
|
115
|
+
&& tryParseStrictSemVer(target.installedVersion) !== null
|
|
116
|
+
&& compareStrictSemVer(target.installedVersion, target.activeVersion) === 0);
|
|
117
|
+
return {
|
|
118
|
+
pluginId: options.pluginId,
|
|
119
|
+
state: hasAvailable ? 'available'
|
|
120
|
+
: sameVersionCandidateChange ? 'sourceChangedUnverified'
|
|
121
|
+
: blockedCandidate || targets.some((target) => target.eligibility === 'incompatible') ? 'blocked'
|
|
122
|
+
: allCurrent ? 'currentAgainstCatalog'
|
|
123
|
+
: hasInstalledVersion ? 'unknown' : 'notChecked',
|
|
124
|
+
...(options.freshness?.checkedAt ? { checkedAt: options.freshness.checkedAt } : {}),
|
|
125
|
+
...(options.freshness?.lastSuccessful ? { lastSuccessful: true } : {}),
|
|
126
|
+
...(options.sourceIdentity ? { sourceIdentity: options.sourceIdentity } : {}),
|
|
127
|
+
...(options.generationKey ? { generationKey: options.generationKey } : {}),
|
|
128
|
+
targets,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
2
131
|
function compareText(left, right) {
|
|
3
132
|
return left.localeCompare(right, 'en');
|
|
4
133
|
}
|
|
5
134
|
function targetHealth(target) {
|
|
6
|
-
if (target.state === '
|
|
135
|
+
if (target.state === 'ready')
|
|
7
136
|
return 'ready';
|
|
8
|
-
if (target.state === '
|
|
137
|
+
if (target.state === 'needsSync' || target.state === 'orphaned')
|
|
9
138
|
return 'incomplete';
|
|
10
|
-
return 'error';
|
|
139
|
+
return target.state === 'blocked' ? 'error' : 'incomplete';
|
|
140
|
+
}
|
|
141
|
+
export function isDirectCodexVersionUpgrade(target, revision) {
|
|
142
|
+
const sharedNative = statusTargetSharedNative(target);
|
|
143
|
+
const reasons = [...target.reasons, ...(target.sharedReasons ?? [])];
|
|
144
|
+
return target.platform === 'codex'
|
|
145
|
+
&& target.state === 'needsSync'
|
|
146
|
+
&& revision.state === 'upgradeAvailable'
|
|
147
|
+
&& sharedNative?.reason === 'outdated'
|
|
148
|
+
&& typeof sharedNative.version === 'string'
|
|
149
|
+
&& typeof sharedNative.desiredVersion === 'string'
|
|
150
|
+
&& sharedNative.version === revision.installedVersion
|
|
151
|
+
&& sharedNative.desiredVersion === revision.availableVersion
|
|
152
|
+
&& compareStrictSemVer(sharedNative.version, sharedNative.desiredVersion) < 0
|
|
153
|
+
&& reasons.length > 0
|
|
154
|
+
&& reasons.every((reason) => reason.code === 'codexSharedNativeUpdateRequired');
|
|
155
|
+
}
|
|
156
|
+
export function isPureNativeCodexTarget(target) {
|
|
157
|
+
const sharedNative = statusTargetSharedNative(target);
|
|
158
|
+
const extensions = statusTargetExtensions(target);
|
|
159
|
+
return target.platform === 'codex'
|
|
160
|
+
&& sharedNative !== undefined
|
|
161
|
+
&& (extensions?.kinds.length ?? 0) === 0;
|
|
162
|
+
}
|
|
163
|
+
function isPureNativeCodexPlacement(placement) {
|
|
164
|
+
return placement.platform === 'codex'
|
|
165
|
+
&& placement.state === 'installed'
|
|
166
|
+
&& placement.sharedNative !== undefined
|
|
167
|
+
&& (placement.extensions?.kinds.length ?? 0) === 0;
|
|
168
|
+
}
|
|
169
|
+
function parsedScopedUninstallRecovery(recovery, expectedPlatform) {
|
|
170
|
+
if (recovery.command !== 'uninstall' || !recovery.scope)
|
|
171
|
+
return undefined;
|
|
172
|
+
const match = /(?:^|\s)aw uninstall ([^\s]+) --platform (codex|claude) --scope (user|project)(?:,|,|\s|$)/u
|
|
173
|
+
.exec(recovery.description);
|
|
174
|
+
if (!match || match[2] !== expectedPlatform || match[3] !== recovery.scope)
|
|
175
|
+
return undefined;
|
|
176
|
+
return { pluginId: match[1], scope: recovery.scope, description: recovery.description };
|
|
177
|
+
}
|
|
178
|
+
function scopeConflictRecoveryMenuActions(placement) {
|
|
179
|
+
if (placement.actualState !== 'blocked')
|
|
180
|
+
return [];
|
|
181
|
+
return (placement.recovery ?? []).flatMap((recovery) => {
|
|
182
|
+
const parsed = parsedScopedUninstallRecovery(recovery, placement.platform);
|
|
183
|
+
return parsed ? [{
|
|
184
|
+
id: 'resolveScopeConflict',
|
|
185
|
+
pluginId: parsed.pluginId,
|
|
186
|
+
platform: placement.platform,
|
|
187
|
+
scope: parsed.scope,
|
|
188
|
+
keepScope: parsed.scope === 'user' ? 'project' : 'user',
|
|
189
|
+
description: parsed.description,
|
|
190
|
+
}] : [];
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function missingPureNativeScopes(plugin, placement) {
|
|
194
|
+
if (!isPureNativeCodexPlacement(placement) || placement.actualState !== 'ready')
|
|
195
|
+
return [];
|
|
196
|
+
const supported = plugin.supportedScopes?.codex ?? ['user', 'project'];
|
|
197
|
+
return supported.filter((scope) => !placement.desiredScopes?.includes(scope) && placement.activation?.[scope] !== true);
|
|
198
|
+
}
|
|
199
|
+
function hasScopedExtensionOwnership(target) {
|
|
200
|
+
return target.components.some((component) => component.kind === 'ownership'
|
|
201
|
+
&& component.key !== 'native'
|
|
202
|
+
&& !component.key.startsWith('activation-')
|
|
203
|
+
&& !component.key.startsWith('marketplace-')
|
|
204
|
+
&& (component.state === 'present' || component.state === 'partial'));
|
|
11
205
|
}
|
|
12
206
|
function isInstalledScopeEvidence(target) {
|
|
13
|
-
|
|
207
|
+
if (target.state === 'absent')
|
|
208
|
+
return false;
|
|
209
|
+
const activation = statusTargetActivation(target);
|
|
210
|
+
const extensions = statusTargetExtensions(target);
|
|
211
|
+
return statusTargetIntent(target).enabled
|
|
212
|
+
|| target.state === 'needsSync' && target.reasons.some((reason) => reason.code === 'codexActivationDrift')
|
|
213
|
+
|| target.platform === 'claude' && (statusTargetOwnershipState(target) === 'present'
|
|
214
|
+
|| statusTargetOwnershipState(target) === 'partial')
|
|
215
|
+
|| target.platform === 'codex' && hasScopedExtensionOwnership(target)
|
|
216
|
+
|| activation?.[target.scope] === true
|
|
217
|
+
|| extensions?.state === 'ready'
|
|
218
|
+
|| extensions?.state === 'drifted'
|
|
219
|
+
|| extensions?.state === 'conflict';
|
|
220
|
+
}
|
|
221
|
+
export function hasActualScopeEvidence(target) {
|
|
222
|
+
if (target.state === 'absent')
|
|
223
|
+
return false;
|
|
224
|
+
const activation = statusTargetActivation(target);
|
|
225
|
+
const extensions = statusTargetExtensions(target);
|
|
226
|
+
return target.platform === 'claude' && (statusTargetOwnershipState(target) === 'present'
|
|
227
|
+
|| statusTargetOwnershipState(target) === 'partial')
|
|
228
|
+
|| target.platform === 'codex' && hasScopedExtensionOwnership(target)
|
|
229
|
+
|| activation?.[target.scope] === true
|
|
230
|
+
|| extensions?.state === 'ready'
|
|
231
|
+
|| extensions?.state === 'drifted'
|
|
232
|
+
|| extensions?.state === 'conflict';
|
|
233
|
+
}
|
|
234
|
+
function dependencyAssignmentExplanation(assignmentSource, requiredBy) {
|
|
235
|
+
const consumer = requiredBy[0];
|
|
236
|
+
return {
|
|
237
|
+
root: '当前插件位置',
|
|
238
|
+
default: '推荐使用当前项目',
|
|
239
|
+
existingWiderTarget: '复用健康的所有项目安装',
|
|
240
|
+
userOverride: '你选择的位置',
|
|
241
|
+
consumerPromotion: consumer
|
|
242
|
+
? `因 ${consumer} 的位置而一并调整`
|
|
243
|
+
: '因上游依赖位置而一并调整',
|
|
244
|
+
platformRequirement: '平台只支持这个位置',
|
|
245
|
+
}[assignmentSource];
|
|
246
|
+
}
|
|
247
|
+
export function dependencyPlacementTargets(plan) {
|
|
248
|
+
return plan.targets.filter((target) => target.relation === 'dependency').map((target) => ({
|
|
249
|
+
key: `${target.pluginId}\0${target.platform}`,
|
|
250
|
+
pluginId: target.pluginId,
|
|
251
|
+
displayName: target.pluginName,
|
|
252
|
+
platform: target.platform,
|
|
253
|
+
relation: target.depth === 1 ? 'direct' : 'transitive',
|
|
254
|
+
scope: target.resolvedScope,
|
|
255
|
+
minimumScope: target.minimumScope,
|
|
256
|
+
allowedScopes: [...target.allowedScopes],
|
|
257
|
+
locked: target.locked && target.lockReason !== 'dependencyScopeOverride',
|
|
258
|
+
requiredBy: [...target.requiredBy],
|
|
259
|
+
assignmentSource: target.assignmentSource,
|
|
260
|
+
explanation: dependencyAssignmentExplanation(target.assignmentSource, target.requiredBy),
|
|
261
|
+
affectsOtherProjects: target.affectsOtherProjects,
|
|
262
|
+
action: target.action,
|
|
263
|
+
}));
|
|
14
264
|
}
|
|
15
265
|
function dependencyPluginIdFromMessage(message) {
|
|
16
266
|
return message.match(/(?:[a-z0-9]+(?:-[a-z0-9]+)*)\/(?:[a-z0-9]+(?:-[a-z0-9]+)*)/u)?.[0];
|
|
17
267
|
}
|
|
268
|
+
function rootPlacementFromIssueId(issueId, fallback) {
|
|
269
|
+
if (issueId) {
|
|
270
|
+
for (const platform of ['claude', 'codex']) {
|
|
271
|
+
for (const scope of ['project', 'user']) {
|
|
272
|
+
if (issueId.includes(`:${platform}:${scope}:`)
|
|
273
|
+
|| issueId.endsWith(`:${platform}:${scope}`))
|
|
274
|
+
return { platform, scope };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return fallback;
|
|
279
|
+
}
|
|
280
|
+
function rootPluginIdFromIssueId(issueId, rootIssueCode) {
|
|
281
|
+
if (!issueId || !rootIssueCode || !issueId.startsWith(`${rootIssueCode}:`))
|
|
282
|
+
return undefined;
|
|
283
|
+
for (const platform of ['claude', 'codex']) {
|
|
284
|
+
for (const scope of ['project', 'user']) {
|
|
285
|
+
const marker = `:${platform}:${scope}`;
|
|
286
|
+
const markerIndex = issueId.indexOf(marker, rootIssueCode.length + 1);
|
|
287
|
+
if (markerIndex > rootIssueCode.length + 1) {
|
|
288
|
+
return issueId.slice(rootIssueCode.length + 1, markerIndex);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
function targetIssueRelationship(options) {
|
|
295
|
+
const consumer = options.error?.rootIssueId !== undefined
|
|
296
|
+
&& options.error.rootIssueCode !== undefined
|
|
297
|
+
&& (options.error.code !== options.error.rootIssueCode
|
|
298
|
+
|| options.dependencyPluginId !== undefined
|
|
299
|
+
&& options.dependencyPluginId !== options.target.pluginId);
|
|
300
|
+
if (!consumer) {
|
|
301
|
+
return {
|
|
302
|
+
relationship: 'direct',
|
|
303
|
+
rootEntity: {
|
|
304
|
+
pluginId: options.target.pluginId,
|
|
305
|
+
platform: options.target.platform,
|
|
306
|
+
scope: options.target.scope,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const placement = rootPlacementFromIssueId(options.error?.rootIssueId, options.target);
|
|
311
|
+
return {
|
|
312
|
+
relationship: 'consumer',
|
|
313
|
+
rootEntity: {
|
|
314
|
+
pluginId: rootPluginIdFromIssueId(options.error?.rootIssueId, options.error?.rootIssueCode) ?? options.dependencyPluginId ?? options.target.pluginId,
|
|
315
|
+
...placement,
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
18
319
|
export function projectPlatformPlacement(platform, targets, revisions = []) {
|
|
19
320
|
const revisionFor = (target) => revisions.find((entry) => entry.pluginId === target.pluginId
|
|
20
321
|
&& entry.platform === target.platform
|
|
@@ -23,7 +324,10 @@ export function projectPlatformPlacement(platform, targets, revisions = []) {
|
|
|
23
324
|
const supportedScopes = [...new Set(targets.map((target) => target.scope))];
|
|
24
325
|
const installed = targets.filter(isInstalledScopeEvidence);
|
|
25
326
|
if (installed.length === 0) {
|
|
26
|
-
|
|
327
|
+
if (targets.some((target) => target.reasons.some((reason) => reason.code === 'artifactCollision' && reason.severity === 'blocking'))) {
|
|
328
|
+
return { platform, state: 'blocked', supportedScopes, reason: 'artifactCollision' };
|
|
329
|
+
}
|
|
330
|
+
const errorTarget = targets.find((target) => target.state === 'blocked');
|
|
27
331
|
if (!errorTarget)
|
|
28
332
|
return { platform, state: 'notInstalled', supportedScopes };
|
|
29
333
|
return {
|
|
@@ -34,165 +338,499 @@ export function projectPlatformPlacement(platform, targets, revisions = []) {
|
|
|
34
338
|
revision: revisionFor(errorTarget),
|
|
35
339
|
};
|
|
36
340
|
}
|
|
37
|
-
if (installed.length
|
|
38
|
-
const
|
|
341
|
+
if (installed.length > 1) {
|
|
342
|
+
const projected = installed.map((target) => projectPlatformPlacement(platform, [target], revisions));
|
|
39
343
|
return {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
344
|
+
...(projected.find((placement) => placement.health === 'error')
|
|
345
|
+
?? projected.find((placement) => placement.health === 'incomplete')
|
|
346
|
+
?? projected[0]),
|
|
347
|
+
scopedPlacements: projected.map((placement) => ({
|
|
348
|
+
scope: placement.scope,
|
|
349
|
+
health: placement.health,
|
|
350
|
+
revision: placement.revision,
|
|
351
|
+
...(placement.actualState ? { actualState: placement.actualState } : {}),
|
|
352
|
+
...(placement.recovery ? { recovery: placement.recovery } : {}),
|
|
353
|
+
...(placement.blockingReason ? { blockingReason: placement.blockingReason } : {}),
|
|
354
|
+
})),
|
|
355
|
+
desiredScopes: [...new Set(projected.flatMap((placement) => placement.desiredScopes ?? []))].sort(compareText),
|
|
356
|
+
actualScopes: [...new Set(installed.filter(hasActualScopeEvidence)
|
|
357
|
+
.map((target) => target.scope))].sort(compareText),
|
|
45
358
|
};
|
|
46
359
|
}
|
|
360
|
+
const target = installed.find((candidate) => candidate.state === 'blocked')
|
|
361
|
+
?? installed.find((candidate) => candidate.state === 'needsSync')
|
|
362
|
+
?? installed.find((candidate) => candidate.state === 'orphaned')
|
|
363
|
+
?? installed[0];
|
|
364
|
+
const intent = statusTargetIntent(target);
|
|
365
|
+
const activation = statusTargetActivation(target);
|
|
366
|
+
const sharedNative = statusTargetSharedNative(target);
|
|
367
|
+
const extensions = statusTargetExtensions(target);
|
|
368
|
+
const blockingReason = target.reasons.some((reason) => reason.code === 'artifactCollision' && reason.severity === 'blocking')
|
|
369
|
+
? 'artifactCollision'
|
|
370
|
+
: undefined;
|
|
47
371
|
return {
|
|
48
372
|
platform,
|
|
49
|
-
state: '
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
373
|
+
state: 'installed',
|
|
374
|
+
scope: target.scope,
|
|
375
|
+
health: targetHealth(target),
|
|
376
|
+
revision: revisionFor(target),
|
|
377
|
+
desiredScopes: [...intent.scopes],
|
|
378
|
+
actualScopes: hasActualScopeEvidence(target) ? [target.scope] : [],
|
|
379
|
+
relation: intent.relation,
|
|
380
|
+
actualState: target.state,
|
|
381
|
+
...(activation ? { activation } : {}),
|
|
382
|
+
...(sharedNative ? { sharedNative } : {}),
|
|
383
|
+
...(extensions ? { extensions } : {}),
|
|
384
|
+
recovery: [...target.recoveryActions],
|
|
385
|
+
...(blockingReason ? { blockingReason } : {}),
|
|
55
386
|
};
|
|
56
387
|
}
|
|
57
388
|
function hasIncompletePlacement(plugin) {
|
|
58
389
|
return plugin.installedPlacements.some((placement) => placement.state === 'scopeConflict'
|
|
59
|
-
|| placement.state === 'installed'
|
|
390
|
+
|| placement.state === 'installed'
|
|
391
|
+
&& placement.scopedPlacements?.some((entry) => entry.health !== 'ready'
|
|
392
|
+
|| entry.blockingReason !== undefined)
|
|
393
|
+
|| placement.state === 'installed'
|
|
394
|
+
&& (placement.health !== 'ready' || placement.blockingReason !== undefined));
|
|
60
395
|
}
|
|
61
396
|
function hasMissingPlatform(plugin) {
|
|
62
397
|
return plugin.supportedPlatforms.some((platform) => plugin.installedPlacements.find((placement) => placement.platform === platform)?.state === 'notInstalled');
|
|
63
398
|
}
|
|
399
|
+
function allSupportedPlatformsBlocked(plugin) {
|
|
400
|
+
return plugin.supportedPlatforms.length > 0 && plugin.supportedPlatforms.every((platform) => plugin.installedPlacements.some((placement) => placement.platform === platform
|
|
401
|
+
&& (placement.state === 'blocked'
|
|
402
|
+
|| placement.state === 'installed' && placement.blockingReason === 'artifactCollision')));
|
|
403
|
+
}
|
|
64
404
|
function capabilityActions(plugin) {
|
|
65
405
|
return [
|
|
66
|
-
...(plugin.portableSkills ? [{ id: 'portableSkills' }] : []),
|
|
67
406
|
...((plugin.dependencySummary?.totalCount ?? 0) > 0 ? [{ id: 'dependencies' }] : []),
|
|
68
407
|
...(plugin.configFieldCount > 0 ? [{ id: 'settings' }] : []),
|
|
69
408
|
];
|
|
70
409
|
}
|
|
410
|
+
function capabilityUnavailableActions() {
|
|
411
|
+
return [{ id: 'upgradeAwCli' }, { id: 'capabilityTechnical' }];
|
|
412
|
+
}
|
|
413
|
+
function isCapabilityUnavailable(plugin) {
|
|
414
|
+
return plugin.capabilityUnsupported === true && plugin.sourceUnavailable !== true;
|
|
415
|
+
}
|
|
71
416
|
export function buildPluginPreviewActions(plugin) {
|
|
72
417
|
const installed = hasInstalledPlacement(plugin);
|
|
73
418
|
if (plugin.aggregateStatus === 'unavailable') {
|
|
419
|
+
if (isCapabilityUnavailable(plugin)) {
|
|
420
|
+
return [...capabilityUnavailableActions(), ...(installed ? [{ id: 'manage' }] : [])];
|
|
421
|
+
}
|
|
74
422
|
return [{ id: 'sourceProblem' }, ...(installed ? [{ id: 'manage' }] : [])];
|
|
75
423
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
424
|
+
if (allSupportedPlatformsBlocked(plugin)) {
|
|
425
|
+
return [
|
|
426
|
+
{ id: 'outputCollision' },
|
|
427
|
+
...(hasInstalledPlacement(plugin) ? [{ id: 'manage' }] : []),
|
|
428
|
+
{ id: 'source' },
|
|
429
|
+
{ id: 'about' },
|
|
430
|
+
];
|
|
431
|
+
}
|
|
432
|
+
const collisionWithInstallablePlatform = hasMissingPlatform(plugin)
|
|
433
|
+
&& plugin.installedPlacements.some((placement) => placement.state === 'blocked'
|
|
434
|
+
|| placement.state === 'installed' && placement.blockingReason === 'artifactCollision');
|
|
435
|
+
const primary = collisionWithInstallablePlatform
|
|
436
|
+
? { id: 'add' }
|
|
437
|
+
: hasIncompletePlacement(plugin) || (plugin.dependencySummary?.issueCount ?? 0) > 0
|
|
438
|
+
? { id: 'repair' }
|
|
439
|
+
: installed && !hasMissingPlatform(plugin) ? { id: 'manage' } : { id: 'add' };
|
|
82
440
|
return [primary, ...capabilityActions(plugin), { id: 'source' }];
|
|
83
441
|
}
|
|
84
442
|
export function buildPluginDetailActions(plugin) {
|
|
85
443
|
if (plugin.aggregateStatus === 'unavailable') {
|
|
444
|
+
if (isCapabilityUnavailable(plugin)) {
|
|
445
|
+
return [
|
|
446
|
+
...plugin.installedPlacements.flatMap((placement) => placement.state === 'notInstalled'
|
|
447
|
+
? []
|
|
448
|
+
: [{ id: 'platform', platform: placement.platform }]),
|
|
449
|
+
...capabilityUnavailableActions(),
|
|
450
|
+
{ id: 'about' },
|
|
451
|
+
];
|
|
452
|
+
}
|
|
86
453
|
return [
|
|
87
454
|
...plugin.installedPlacements.flatMap((placement) => placement.state === 'notInstalled'
|
|
88
455
|
? []
|
|
89
456
|
: [{ id: 'platform', platform: placement.platform }]),
|
|
457
|
+
...(plugin.savedConfigScopes.length > 0 ? [{ id: 'settings' }] : []),
|
|
90
458
|
{ id: 'sourceProblem' },
|
|
91
459
|
{ id: 'about' },
|
|
92
460
|
];
|
|
93
461
|
}
|
|
94
462
|
return [
|
|
95
|
-
...plugin.
|
|
96
|
-
|
|
97
|
-
|
|
463
|
+
...(plugin.update?.targets ?? []).flatMap((target) => target.availableVersion !== undefined && target.installedVersion !== undefined
|
|
464
|
+
&& plugin.update.sourceIdentity !== undefined && plugin.update.generationKey !== undefined
|
|
465
|
+
&& target.requiresCatalogActivation !== true
|
|
466
|
+
&& target.eligibility === 'allowed'
|
|
467
|
+
? [{
|
|
468
|
+
id: 'refreshAndSync',
|
|
469
|
+
platform: target.platform,
|
|
470
|
+
scope: target.scope,
|
|
471
|
+
availableVersion: target.availableVersion,
|
|
472
|
+
installedVersion: target.installedVersion,
|
|
473
|
+
sourceIdentity: plugin.update.sourceIdentity,
|
|
474
|
+
generationKey: plugin.update.generationKey,
|
|
475
|
+
}]
|
|
476
|
+
: []),
|
|
477
|
+
...plugin.installedPlacements.flatMap((placement) => [
|
|
478
|
+
...(placement.state === 'installed' ? scopeConflictRecoveryMenuActions(placement) : []),
|
|
479
|
+
placement.state === 'scopeConflict'
|
|
480
|
+
? { id: 'scopeConflict', platform: placement.platform }
|
|
481
|
+
: { id: 'platform', platform: placement.platform },
|
|
482
|
+
]),
|
|
98
483
|
...((plugin.dependencySummary?.totalCount ?? 0) > 0 ? [{ id: 'dependencies' }] : []),
|
|
99
|
-
...(plugin.portableSkills ? [{ id: 'portableSkills' }] : []),
|
|
100
484
|
...(plugin.configFieldCount > 0 ? [{ id: 'settings' }] : []),
|
|
101
485
|
{ id: 'about' },
|
|
102
486
|
];
|
|
103
487
|
}
|
|
104
488
|
export function buildPlatformActions(plugin, platform) {
|
|
105
489
|
if (plugin.aggregateStatus === 'unavailable') {
|
|
490
|
+
if (isCapabilityUnavailable(plugin))
|
|
491
|
+
return capabilityUnavailableActions();
|
|
106
492
|
return [{ id: 'sourceProblem' }, { id: 'refreshSource' }];
|
|
107
493
|
}
|
|
108
494
|
const placement = plugin.installedPlacements.find((entry) => entry.platform === platform);
|
|
495
|
+
if (placement?.state === 'blocked') {
|
|
496
|
+
return [{ id: 'outputCollision' }, { id: 'source' }, { id: 'about' }];
|
|
497
|
+
}
|
|
109
498
|
if (!placement || placement.state === 'notInstalled')
|
|
110
499
|
return [{ id: 'add' }, { id: 'about' }];
|
|
111
500
|
if (placement.state === 'scopeConflict')
|
|
112
501
|
return [{ id: 'scopeConflict', platform }];
|
|
113
|
-
if (placement.
|
|
114
|
-
|
|
115
|
-
|
|
502
|
+
if (placement.scopedPlacements) {
|
|
503
|
+
const actions = placement.scopedPlacements.flatMap((entry) => buildPlatformActions({
|
|
504
|
+
...plugin,
|
|
505
|
+
installedPlacements: [{
|
|
506
|
+
...placement,
|
|
507
|
+
...entry,
|
|
508
|
+
scopedPlacements: undefined,
|
|
509
|
+
}],
|
|
510
|
+
}, platform));
|
|
511
|
+
return [...new Map(actions.map((action) => [JSON.stringify(action), action])).values()];
|
|
512
|
+
}
|
|
513
|
+
const scopedRecovery = scopeConflictRecoveryMenuActions(placement);
|
|
514
|
+
if (scopedRecovery.length > 0)
|
|
515
|
+
return [...scopedRecovery, { id: 'technical' }];
|
|
516
|
+
if (placement.blockingReason === 'artifactCollision') {
|
|
116
517
|
return [
|
|
117
|
-
{ id: '
|
|
118
|
-
{ id: 'technical' },
|
|
518
|
+
{ id: 'outputCollision' },
|
|
119
519
|
{ id: 'remove', platform, scope: placement.scope },
|
|
520
|
+
{ id: 'technical' },
|
|
120
521
|
];
|
|
121
522
|
}
|
|
523
|
+
const lifecycleActions = buildAllowedLifecycleActions({
|
|
524
|
+
pluginId: plugin.pluginId,
|
|
525
|
+
platform,
|
|
526
|
+
scope: placement.scope,
|
|
527
|
+
state: placement.actualState ?? (placement.health === 'ready'
|
|
528
|
+
? 'ready' : placement.health === 'incomplete' ? 'needsSync' : 'blocked'),
|
|
529
|
+
recoveryActions: placement.recovery ?? [],
|
|
530
|
+
revision: placement.revision,
|
|
531
|
+
}).flatMap((action) => {
|
|
532
|
+
if (action.id === 'install')
|
|
533
|
+
return [{ id: 'add' }];
|
|
534
|
+
if (action.id === 'refreshAndSync') {
|
|
535
|
+
const updateTarget = plugin.update?.targets.find((target) => target.platform === action.platform && target.scope === action.scope
|
|
536
|
+
&& target.availableVersion === action.availableVersion);
|
|
537
|
+
return updateTarget?.installedVersion && plugin.update.sourceIdentity && plugin.update.generationKey
|
|
538
|
+
? [{
|
|
539
|
+
id: 'refreshAndSync',
|
|
540
|
+
platform: action.platform,
|
|
541
|
+
scope: action.scope,
|
|
542
|
+
availableVersion: action.availableVersion,
|
|
543
|
+
installedVersion: updateTarget.installedVersion,
|
|
544
|
+
sourceIdentity: plugin.update.sourceIdentity,
|
|
545
|
+
generationKey: plugin.update.generationKey,
|
|
546
|
+
}]
|
|
547
|
+
: [];
|
|
548
|
+
}
|
|
549
|
+
if (action.id === 'sync')
|
|
550
|
+
return [{
|
|
551
|
+
id: 'sync', platform: action.platform, scope: action.scope,
|
|
552
|
+
}];
|
|
553
|
+
if (action.id === 'reinstall')
|
|
554
|
+
return [{ id: 'reinstall', platform: action.platform, scope: action.scope }];
|
|
555
|
+
if (action.id === 'uninstall')
|
|
556
|
+
return [{ id: 'remove', platform: action.platform, scope: action.scope }];
|
|
557
|
+
return [{ id: 'cleanup', platform: action.platform, scope: action.scope }];
|
|
558
|
+
});
|
|
559
|
+
if (placement.health !== 'ready') {
|
|
560
|
+
return [...lifecycleActions, { id: 'technical' }, ...(lifecycleActions.length === 0 ? [{ id: 'back' }] : [])];
|
|
561
|
+
}
|
|
122
562
|
return [
|
|
123
|
-
...(placement.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
scope: placement.scope,
|
|
128
|
-
availableVersion: placement.revision.availableVersion,
|
|
129
|
-
}]
|
|
130
|
-
: []),
|
|
131
|
-
{ id: 'reinstall', platform, scope: placement.scope },
|
|
132
|
-
{ id: 'remove', platform, scope: placement.scope },
|
|
563
|
+
...missingPureNativeScopes(plugin, placement).map((scope) => ({
|
|
564
|
+
id: 'addScope', platform, scope,
|
|
565
|
+
})),
|
|
566
|
+
...lifecycleActions,
|
|
133
567
|
{ id: 'technical' },
|
|
134
568
|
];
|
|
135
569
|
}
|
|
136
570
|
export function hasInstalledPlacement(plugin) {
|
|
137
|
-
return plugin.installedPlacements.some((placement) => placement.state
|
|
571
|
+
return plugin.installedPlacements.some((placement) => placement.state === 'installed' || placement.state === 'scopeConflict');
|
|
138
572
|
}
|
|
139
|
-
function
|
|
140
|
-
if (health
|
|
141
|
-
return 'ready';
|
|
142
|
-
if (health?.state === 'path')
|
|
143
|
-
return 'path';
|
|
144
|
-
if (health?.state === 'degraded')
|
|
145
|
-
return 'cache';
|
|
146
|
-
if (health?.state === 'unavailable')
|
|
147
|
-
return 'error';
|
|
148
|
-
if (source.error)
|
|
149
|
-
return 'error';
|
|
150
|
-
if (source.type === 'path' || source.freshness === 'path')
|
|
151
|
-
return 'path';
|
|
152
|
-
return source.freshness === 'cache' ? 'cache' : 'ready';
|
|
153
|
-
}
|
|
154
|
-
function sourceIssue(health, impactedTargets = 0) {
|
|
155
|
-
if (health.state !== 'degraded' && health.state !== 'unavailable')
|
|
573
|
+
function sourceIssue(health, targetIssues = []) {
|
|
574
|
+
if (health.state !== 'unavailable')
|
|
156
575
|
return undefined;
|
|
157
|
-
const
|
|
158
|
-
const
|
|
576
|
+
const issueId = health.issueId ?? `source:${health.sourceId}:unavailable`;
|
|
577
|
+
const affectedTargets = [...new Map(targetIssues.flatMap((issue) => issue.affectedTargets ?? [])
|
|
578
|
+
.map((target) => [`${target.pluginId}\0${target.platform}\0${target.scope}`, target])).values()]
|
|
579
|
+
.sort((left, right) => compareText(left.pluginId, right.pluginId)
|
|
580
|
+
|| compareText(left.platform, right.platform)
|
|
581
|
+
|| compareText(left.scope, right.scope));
|
|
582
|
+
const cleanupActions = targetIssues.flatMap((issue) => issue.actions)
|
|
583
|
+
.filter((action) => action.id === 'cleanup');
|
|
159
584
|
return {
|
|
160
585
|
issueId,
|
|
161
|
-
category:
|
|
162
|
-
title: `${health.sourceId} ·
|
|
163
|
-
explanation:
|
|
164
|
-
|
|
165
|
-
:
|
|
166
|
-
impact: [cached ? '插件仍可浏览,但数据可能不是最新。' : '当前不能浏览或安装这个来源的插件。',
|
|
167
|
-
...(impactedTargets > 0 ? [`${impactedTargets} 个安装位置受此来源根问题影响。`] : [])],
|
|
586
|
+
category: 'sourceUnavailable',
|
|
587
|
+
title: `${health.sourceId} · 来源不可用`,
|
|
588
|
+
explanation: '来源检查失败。',
|
|
589
|
+
impact: ['当前不能浏览或安装这个来源的插件。',
|
|
590
|
+
...(affectedTargets.length > 0 ? [`${affectedTargets.length} 个安装位置受此来源根问题影响。`] : [])],
|
|
168
591
|
entity: { kind: 'source', id: health.sourceId },
|
|
169
592
|
sourceId: health.sourceId,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
{ id: 'editSource', label: '编辑来源', description: '检查 URL、路径或 ref' },
|
|
178
|
-
{ id: 'refreshSource', label: '稍后重试', description: '只重新检查来源' },
|
|
179
|
-
{ id: 'viewTechnical', label: '技术详情' },
|
|
180
|
-
],
|
|
593
|
+
...(affectedTargets.length > 0 ? { affectedTargets } : {}),
|
|
594
|
+
actions: dedupeIssueActions([
|
|
595
|
+
...cleanupActions,
|
|
596
|
+
{ id: 'editSource', label: '编辑来源', description: '检查 URL、路径或 ref' },
|
|
597
|
+
{ id: 'refreshSource', label: '稍后重试', description: '只重新检查来源' },
|
|
598
|
+
{ id: 'viewTechnical', label: '技术详情' },
|
|
599
|
+
]),
|
|
181
600
|
technicalDetails: [{
|
|
182
|
-
code:
|
|
183
|
-
message:
|
|
601
|
+
code: 'catalogSourceUnavailable',
|
|
602
|
+
message: '来源检查失败。',
|
|
184
603
|
}],
|
|
185
604
|
};
|
|
186
605
|
}
|
|
187
|
-
function
|
|
606
|
+
function lifecycleIssueActions(target, options = {}) {
|
|
607
|
+
return buildAllowedLifecycleActions(target).flatMap((action) => {
|
|
608
|
+
const view = projectLifecycleActionView(action);
|
|
609
|
+
if (options.dependency) {
|
|
610
|
+
if (action.id === 'install')
|
|
611
|
+
return [{
|
|
612
|
+
id: 'installDependency',
|
|
613
|
+
label: '补齐依赖插件',
|
|
614
|
+
pluginId: action.pluginId,
|
|
615
|
+
platform: action.platform,
|
|
616
|
+
scope: action.scope,
|
|
617
|
+
project: options.project,
|
|
618
|
+
writeAction: 'install',
|
|
619
|
+
}];
|
|
620
|
+
if (action.id === 'sync' || action.id === 'reinstall')
|
|
621
|
+
return [{
|
|
622
|
+
id: 'reinstallDependency',
|
|
623
|
+
label: view.label,
|
|
624
|
+
description: view.description,
|
|
625
|
+
pluginId: action.pluginId,
|
|
626
|
+
platform: action.platform,
|
|
627
|
+
scope: action.scope,
|
|
628
|
+
project: options.project,
|
|
629
|
+
writeAction: action.id,
|
|
630
|
+
}];
|
|
631
|
+
return [];
|
|
632
|
+
}
|
|
633
|
+
const projection = {
|
|
634
|
+
install: { id: 'install', writeAction: 'install' },
|
|
635
|
+
sync: { id: 'sync', writeAction: 'sync' },
|
|
636
|
+
refreshAndSync: { id: 'refreshAndSync', writeAction: 'refreshAndSync' },
|
|
637
|
+
reinstall: { id: 'reinstall', writeAction: 'reinstall' },
|
|
638
|
+
uninstall: { id: 'remove', writeAction: 'uninstall' },
|
|
639
|
+
cleanup: { id: 'cleanup', writeAction: 'cleanup' },
|
|
640
|
+
}[action.id];
|
|
641
|
+
return [{
|
|
642
|
+
...projection,
|
|
643
|
+
label: view.label,
|
|
644
|
+
description: view.description,
|
|
645
|
+
pluginId: action.pluginId,
|
|
646
|
+
platform: action.platform,
|
|
647
|
+
scope: action.scope,
|
|
648
|
+
}];
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
function targetIssues(payload, targetRevisions = []) {
|
|
188
652
|
const issues = [];
|
|
189
|
-
const
|
|
653
|
+
const statusTargets = flattenStatusTargets(payload.targets);
|
|
654
|
+
const canonicalRootsByEntity = new Map();
|
|
655
|
+
for (const target of statusTargets) {
|
|
656
|
+
for (const error of target.reasons) {
|
|
657
|
+
if (!error.rootIssueId || !error.rootIssueCode)
|
|
658
|
+
continue;
|
|
659
|
+
const dependencyPluginId = error.dependencyPluginId
|
|
660
|
+
?? dependencyPluginIdFromMessage(error.message);
|
|
661
|
+
const relationship = targetIssueRelationship({ target, error, dependencyPluginId });
|
|
662
|
+
if (relationship.relationship !== 'consumer')
|
|
663
|
+
continue;
|
|
664
|
+
const key = [
|
|
665
|
+
error.rootIssueCode,
|
|
666
|
+
relationship.rootEntity.pluginId,
|
|
667
|
+
relationship.rootEntity.platform,
|
|
668
|
+
relationship.rootEntity.scope,
|
|
669
|
+
].join('\0');
|
|
670
|
+
const current = canonicalRootsByEntity.get(key);
|
|
671
|
+
if (!current || compareText(error.rootIssueId, current) < 0) {
|
|
672
|
+
canonicalRootsByEntity.set(key, error.rootIssueId);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
190
676
|
for (const target of payload.targets) {
|
|
191
|
-
|
|
192
|
-
byPlacement.set(key, [...(byPlacement.get(key) ?? []), target]);
|
|
193
|
-
if (target.state !== 'partial' && target.state !== 'error')
|
|
677
|
+
if (target.platform !== 'codex' || !target.reasons.some((reason) => reason.code === 'codexExtensionScopeConflict'))
|
|
194
678
|
continue;
|
|
195
|
-
const
|
|
679
|
+
const recoveries = target.recoveryActions.flatMap((recovery) => {
|
|
680
|
+
const parsed = parsedScopedUninstallRecovery(recovery, target.platform);
|
|
681
|
+
return parsed ? [{ ...parsed, keepScope: parsed.scope === 'user'
|
|
682
|
+
? 'project' : 'user' }] : [];
|
|
683
|
+
});
|
|
684
|
+
issues.push({
|
|
685
|
+
issueId: `scope:${target.pluginId}:${target.platform}`,
|
|
686
|
+
category: 'scopeConflict',
|
|
687
|
+
title: `${target.pluginId} · Codex · 扩展位置冲突`,
|
|
688
|
+
explanation: 'AW 管理附加能力不能同时使用所有项目和当前项目位置。',
|
|
689
|
+
impact: ['选择要保留的使用位置。系统将移除另一位置,再同步保留的位置。'],
|
|
690
|
+
entity: { kind: 'plugin', id: target.pluginId },
|
|
691
|
+
pluginId: target.pluginId,
|
|
692
|
+
platform: target.platform,
|
|
693
|
+
sourceId: target.sourceId,
|
|
694
|
+
sourceIdentity: target.sourceIdentity,
|
|
695
|
+
placements: target.placements.map((placement) => placement.scope).sort(compareText),
|
|
696
|
+
actions: [
|
|
697
|
+
...recoveries.map((recovery) => ({
|
|
698
|
+
id: recovery.keepScope === 'user' ? 'keepUserScope' : 'keepProjectScope',
|
|
699
|
+
label: `保留${recovery.keepScope === 'user' ? '所有项目' : '当前项目'}`,
|
|
700
|
+
description: recovery.description,
|
|
701
|
+
pluginId: recovery.pluginId,
|
|
702
|
+
platform: target.platform,
|
|
703
|
+
scope: recovery.scope,
|
|
704
|
+
writeAction: 'uninstall',
|
|
705
|
+
})),
|
|
706
|
+
{ id: 'viewTechnical', label: '查看冲突详情' },
|
|
707
|
+
],
|
|
708
|
+
technicalDetails: [{
|
|
709
|
+
code: 'codexExtensionScopeConflict',
|
|
710
|
+
message: '扩展同时使用 user 和 project scope。',
|
|
711
|
+
}],
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
for (const target of payload.targets) {
|
|
715
|
+
if (target.platform !== 'codex')
|
|
716
|
+
continue;
|
|
717
|
+
const sharedReasons = target.reasons.filter((reason) => reason.code.startsWith('codexSharedNative') || reason.code === 'staleCacheObserved');
|
|
718
|
+
if (sharedReasons.length === 0 || target.state === 'ready' || target.state === 'absent')
|
|
719
|
+
continue;
|
|
720
|
+
const installedTargets = statusTargets.filter((candidate) => candidate.pluginId === target.pluginId
|
|
721
|
+
&& candidate.platform === 'codex' && candidate.state !== 'absent');
|
|
722
|
+
const directUpgrade = installedTargets.length > 0 && installedTargets.every((candidate) => {
|
|
723
|
+
const revision = targetRevisions.find((entry) => entry.pluginId === candidate.pluginId
|
|
724
|
+
&& entry.platform === candidate.platform && entry.scope === candidate.scope);
|
|
725
|
+
return revision !== undefined && isDirectCodexVersionUpgrade(candidate, revision.revision);
|
|
726
|
+
});
|
|
727
|
+
if (directUpgrade)
|
|
728
|
+
continue;
|
|
729
|
+
const codes = new Set(sharedReasons.map((reason) => reason.code));
|
|
730
|
+
const sharedNative = statusTargetSharedNative(target);
|
|
731
|
+
const statusIssue = codes.has('codexSharedNativeForeign')
|
|
732
|
+
? { title: '平台由多个项目共用的内容被占用', explanation: 'Codex 平台位置含有不属于插件的内容。' }
|
|
733
|
+
: codes.has('codexSharedNativeUpdateRequired')
|
|
734
|
+
? { title: '版本待同步', explanation: 'Codex 由平台共用的内容版本与当前插件版本不一致。' }
|
|
735
|
+
: codes.has('codexSharedNativeUnobserved')
|
|
736
|
+
? { title: '状态未确认', explanation: '未取得有效的 Codex 被共用内容的状态证据。' }
|
|
737
|
+
: { title: '由平台共用的内容待同步', explanation: 'Codex 由平台共用的内容缺失、损坏或与当前渲染输入不一致。' };
|
|
738
|
+
const recoveryActions = target.recoveryActions.flatMap((recovery) => {
|
|
739
|
+
if (!recovery.scope)
|
|
740
|
+
return [];
|
|
741
|
+
const scopedTarget = statusTargets.find((candidate) => candidate.pluginId === target.pluginId
|
|
742
|
+
&& candidate.platform === target.platform && candidate.scope === recovery.scope);
|
|
743
|
+
return scopedTarget && isInstalledScopeEvidence(scopedTarget)
|
|
744
|
+
? lifecycleIssueActions({ ...scopedTarget, recoveryActions: [recovery] })
|
|
745
|
+
: [];
|
|
746
|
+
});
|
|
747
|
+
issues.push({
|
|
748
|
+
issueId: `sharedNative:${target.pluginId}`,
|
|
749
|
+
category: target.state === 'blocked' ? 'diagnostic' : 'incompleteInstallation',
|
|
750
|
+
title: `${target.pluginId} · Codex · ${statusIssue.title}`,
|
|
751
|
+
explanation: statusIssue.explanation,
|
|
752
|
+
impact: [sharedNative?.state === 'blocked'
|
|
753
|
+
? '被共用的内容恢复前,当前插件不能安全同步。'
|
|
754
|
+
: '被共用的内容恢复前,相关 Codex 使用位置可能不可用。'],
|
|
755
|
+
entity: { kind: 'plugin', id: target.pluginId },
|
|
756
|
+
pluginId: target.pluginId,
|
|
757
|
+
platform: target.platform,
|
|
758
|
+
sourceId: target.sourceId,
|
|
759
|
+
sourceIdentity: target.sourceIdentity,
|
|
760
|
+
placements: target.placements.map((placement) => placement.scope).sort(compareText),
|
|
761
|
+
actions: [
|
|
762
|
+
...new Map(recoveryActions.map((action) => [
|
|
763
|
+
`${action.id}\0${action.scope ?? ''}`,
|
|
764
|
+
action,
|
|
765
|
+
])).values(),
|
|
766
|
+
{ id: 'viewTechnical', label: '技术详情' },
|
|
767
|
+
],
|
|
768
|
+
technicalDetails: sharedReasons.map((reason) => ({
|
|
769
|
+
code: reason.code,
|
|
770
|
+
message: reason.message,
|
|
771
|
+
})),
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
for (const target of statusTargets) {
|
|
775
|
+
const revision = targetRevisions.find((entry) => entry.pluginId === target.pluginId
|
|
776
|
+
&& entry.platform === target.platform && entry.scope === target.scope);
|
|
777
|
+
if (revision && isDirectCodexVersionUpgrade(target, revision.revision))
|
|
778
|
+
continue;
|
|
779
|
+
if (target.reasons.length === 0 && (target.sharedReasons?.length ?? 0) > 0
|
|
780
|
+
&& isPureNativeCodexTarget(target))
|
|
781
|
+
continue;
|
|
782
|
+
const incomplete = target.state === 'needsSync' || target.state === 'orphaned';
|
|
783
|
+
if (!incomplete && target.state !== 'blocked'
|
|
784
|
+
&& !target.reasons.some((error) => error.code === 'artifactCollision'
|
|
785
|
+
|| error.dependencyPluginId !== undefined && error.rootIssueId !== undefined))
|
|
786
|
+
continue;
|
|
787
|
+
const codes = new Set(target.reasons.map((error) => error.code));
|
|
788
|
+
const orphanedActivation = target.state === 'orphaned'
|
|
789
|
+
&& codes.has('codexActivationDrift') && isPureNativeCodexTarget(target);
|
|
790
|
+
const locationLabel = target.scope === 'project' ? '当前项目' : '所有项目';
|
|
791
|
+
const projectDisablesUserActivation = target.platform === 'codex'
|
|
792
|
+
&& target.scope === 'project' && codes.has('codexActivationDrift')
|
|
793
|
+
&& statusTargetActivation(target)?.user === true
|
|
794
|
+
&& statusTargetActivation(target)?.project === false;
|
|
795
|
+
const sharedNativeRenderDrift = target.state === 'needsSync'
|
|
796
|
+
&& codes.has('codexSharedNativeRenderDrift');
|
|
797
|
+
const sharedNativeDamaged = target.state === 'needsSync'
|
|
798
|
+
&& codes.has('codexSharedNativeCorrupt');
|
|
799
|
+
const sharedNativeProjectionIssue = sharedNativeRenderDrift || sharedNativeDamaged;
|
|
800
|
+
const sharedNative = statusTargetSharedNative(target);
|
|
801
|
+
const systemConsumer = statusTargetActivation(target)?.systemConsumer;
|
|
802
|
+
const statusUnconfirmed = systemConsumer?.state === 'unresolved'
|
|
803
|
+
|| codes.has('codexSharedNativeUnobserved')
|
|
804
|
+
|| codes.has('codexNativeObservationFailed')
|
|
805
|
+
|| (sharedNative?.state === 'blocked' && sharedNative.reason === 'unreadable');
|
|
806
|
+
const contentMissing = codes.has('missingContent')
|
|
807
|
+
|| sharedNative?.state === 'missing'
|
|
808
|
+
|| statusTargetExtensions(target)?.state === 'missing'
|
|
809
|
+
|| target.components.some((component) => component.kind === 'ownership'
|
|
810
|
+
&& component.state === 'absent');
|
|
811
|
+
const statusIssue = systemConsumer?.state === 'incompatible'
|
|
812
|
+
? { title: 'Codex 版本不兼容', explanation: '当前 Codex 版本低于要求,请升级后重试。' }
|
|
813
|
+
: statusUnconfirmed
|
|
814
|
+
? { title: '状态未确认', explanation: '未取得有效的 Codex 状态证据,暂时无法确认插件是否可用。' }
|
|
815
|
+
: projectDisablesUserActivation
|
|
816
|
+
? {
|
|
817
|
+
title: '插件在当前项目被关闭',
|
|
818
|
+
explanation: '这个插件已为所有项目启用,但当前项目的设置将它关闭了,因此在这里无法使用。',
|
|
819
|
+
}
|
|
820
|
+
: orphanedActivation
|
|
821
|
+
? {
|
|
822
|
+
title: `${locationLabel}有多余的启用记录`,
|
|
823
|
+
explanation: `按当前使用设置,不需要在${locationLabel}单独启用这个插件,但 Codex 仍保留着这条启用记录。`,
|
|
824
|
+
}
|
|
825
|
+
: codes.has('codexActivationDrift')
|
|
826
|
+
? { title: '激活范围不一致', explanation: 'Codex 激活配置与期望的使用范围不一致。' }
|
|
827
|
+
: target.state === 'orphaned'
|
|
828
|
+
? { title: '有多余的插件内容', explanation: '按当前使用设置,这个位置不再需要安装此插件,但仍留有插件配置或文件。' }
|
|
829
|
+
: codes.has('codexSharedNativeUpdateRequired')
|
|
830
|
+
? { title: '版本待同步', explanation: '已安装的 Codex 由平台共用的内容版本与当前插件版本不一致。' }
|
|
831
|
+
: sharedNativeDamaged || contentMissing
|
|
832
|
+
? { title: '安装不完整', explanation: '必要内容缺失或损坏,需要运行同步。' }
|
|
833
|
+
: { title: '状态待同步', explanation: '现场状态与期望状态不一致,需要重新检查并同步。' };
|
|
196
834
|
const dependencyCodes = [
|
|
197
835
|
'dependencyMissing',
|
|
198
836
|
'dependencyNotReady',
|
|
@@ -200,165 +838,256 @@ function targetIssues(payload) {
|
|
|
200
838
|
'dependencyStillRequired',
|
|
201
839
|
'dependencyGraphInvalid',
|
|
202
840
|
];
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
841
|
+
const dependencyRootMap = new Map();
|
|
842
|
+
for (const error of target.reasons) {
|
|
843
|
+
if (!dependencyCodes.includes(error.code))
|
|
844
|
+
continue;
|
|
845
|
+
if (error.rootIssueCode === 'artifactCollision') {
|
|
846
|
+
dependencyRootMap.set(error.rootIssueId ?? `artifactCollision\0${error.dependencyPluginId ?? ''}`, {
|
|
847
|
+
code: 'artifactCollision',
|
|
848
|
+
category: 'artifactCollision',
|
|
849
|
+
mergeEligible: false,
|
|
850
|
+
error,
|
|
851
|
+
dependencyPluginId: error.dependencyPluginId,
|
|
852
|
+
});
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
const code = error.code;
|
|
856
|
+
const dependencyPluginId = error.dependencyPluginId ?? dependencyPluginIdFromMessage(error.message);
|
|
857
|
+
dependencyRootMap.set(`${code}\0${dependencyPluginId ?? ''}`, {
|
|
858
|
+
code,
|
|
859
|
+
category: code,
|
|
860
|
+
mergeEligible: false,
|
|
861
|
+
error,
|
|
862
|
+
dependencyPluginId,
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
const dependencyRoots = [...dependencyRootMap.values()];
|
|
866
|
+
const directCollision = target.reasons.find((error) => error.code === 'artifactCollision');
|
|
867
|
+
const projectedCollisionRoots = dependencyRoots.filter((root) => root.code === 'artifactCollision');
|
|
868
|
+
const ordinaryDependencyRoots = dependencyRoots.filter((root) => root.code !== 'artifactCollision');
|
|
869
|
+
const roots = codes.has('sourceMissing')
|
|
870
|
+
? [{ code: 'sourceMissing', category: 'sourceMissing', mergeEligible: false }]
|
|
871
|
+
: directCollision || projectedCollisionRoots.length > 0
|
|
872
|
+
? [{
|
|
873
|
+
code: 'artifactCollision',
|
|
874
|
+
category: 'artifactCollision',
|
|
875
|
+
mergeEligible: false,
|
|
876
|
+
error: directCollision ?? projectedCollisionRoots[0].error,
|
|
877
|
+
dependencyPluginId: projectedCollisionRoots[0]?.dependencyPluginId,
|
|
878
|
+
}]
|
|
879
|
+
: codes.has('sourceChanged')
|
|
880
|
+
? [{ code: 'sourceChanged', category: 'sourceIdentityChanged', mergeEligible: false }]
|
|
881
|
+
: codes.has('catalogSourceUnavailable') || codes.has('bundleUnavailable')
|
|
882
|
+
|| codes.has('codexIntentSourceUnavailable')
|
|
883
|
+
? [
|
|
225
884
|
...(codes.has('catalogSourceUnavailable')
|
|
226
885
|
? [{ code: 'catalogSourceUnavailable', category: 'sourceUnavailable', mergeEligible: true }]
|
|
227
886
|
: []),
|
|
228
887
|
...(codes.has('bundleUnavailable')
|
|
229
888
|
? [{ code: 'bundleUnavailable', category: 'sourceUnavailable', mergeEligible: false }]
|
|
230
889
|
: []),
|
|
231
|
-
...(
|
|
232
|
-
? [{ code: '
|
|
890
|
+
...(codes.has('codexIntentSourceUnavailable')
|
|
891
|
+
? [{ code: 'codexIntentSourceUnavailable', category: 'sourceUnavailable', mergeEligible: false }]
|
|
233
892
|
: []),
|
|
234
|
-
]
|
|
893
|
+
]
|
|
894
|
+
: ordinaryDependencyRoots.length > 0
|
|
895
|
+
? ordinaryDependencyRoots
|
|
896
|
+
: incomplete
|
|
897
|
+
? [{ code: 'partial', category: 'incompleteInstallation', mergeEligible: false }]
|
|
898
|
+
: [
|
|
899
|
+
{ code: 'targetDiagnostic', category: 'diagnostic', mergeEligible: false },
|
|
900
|
+
];
|
|
235
901
|
for (const root of roots) {
|
|
236
|
-
const rootError = root.error ?? target.
|
|
902
|
+
const rootError = root.error ?? target.reasons.find((error) => error.code === root.code);
|
|
237
903
|
const dependencyPluginId = root.dependencyPluginId
|
|
904
|
+
?? rootError?.dependencyPluginId
|
|
238
905
|
?? (rootError ? dependencyPluginIdFromMessage(rootError.message) : undefined);
|
|
906
|
+
const dependencyPlatform = rootError?.dependencyPlatform;
|
|
907
|
+
const dependencyScope = rootError?.dependencyScope;
|
|
908
|
+
const dependencyProject = rootError?.dependencyProject;
|
|
239
909
|
const dependencyCategory = root.category.startsWith('dependency');
|
|
910
|
+
const directLifecycleActions = lifecycleIssueActions(target).map((action) => projectDisablesUserActivation && action.id === 'sync' ? {
|
|
911
|
+
...action,
|
|
912
|
+
label: '恢复在当前项目使用',
|
|
913
|
+
description: '移除当前项目的关闭设置,沿用所有项目的启用设置。',
|
|
914
|
+
} : orphanedActivation && action.id === 'cleanup' ? {
|
|
915
|
+
...action,
|
|
916
|
+
label: '清理多余的启用记录',
|
|
917
|
+
description: `清理${locationLabel}的多余记录;保留其他位置的使用设置和插件文件。`,
|
|
918
|
+
} : action);
|
|
919
|
+
const desiredConsumer = statusTargetIntent(target).enabled
|
|
920
|
+
&& statusTargetIntent(target).scopes.includes(target.scope);
|
|
921
|
+
const consumerRecoveryActions = dependencyCategory
|
|
922
|
+
? directLifecycleActions.filter((action) => desiredConsumer
|
|
923
|
+
? action.id === 'sync' || action.id === 'reinstall' || action.id === 'refreshAndSync'
|
|
924
|
+
: action.id === 'cleanup')
|
|
925
|
+
: directLifecycleActions;
|
|
240
926
|
const actions = root.category === 'dependencyMissing'
|
|
241
927
|
? [
|
|
242
|
-
...
|
|
243
|
-
|
|
928
|
+
...consumerRecoveryActions,
|
|
929
|
+
...(dependencyPluginId ? [
|
|
930
|
+
{ id: 'viewDependencyIssue', label: '查看依赖插件问题', pluginId: dependencyPluginId },
|
|
931
|
+
] : []),
|
|
244
932
|
{ id: 'viewDependencies', label: '查看依赖关系' },
|
|
245
933
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
246
934
|
]
|
|
247
935
|
: root.category === 'dependencyNotReady'
|
|
248
936
|
? [
|
|
937
|
+
...consumerRecoveryActions,
|
|
249
938
|
...(dependencyPluginId ? [
|
|
250
939
|
{ id: 'viewDependencyIssue', label: '查看依赖插件问题', pluginId: dependencyPluginId },
|
|
251
|
-
{ id: 'reinstallDependency', label: '重新安装依赖插件',
|
|
252
|
-
pluginId: dependencyPluginId, writeAction: 'reinstall' },
|
|
253
940
|
] : []),
|
|
254
941
|
{ id: 'viewDependencies', label: '查看依赖关系' },
|
|
255
942
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
256
943
|
]
|
|
257
944
|
: dependencyCategory
|
|
258
945
|
? [
|
|
946
|
+
...consumerRecoveryActions,
|
|
259
947
|
{ id: 'viewDependencies', label: '查看依赖关系' },
|
|
260
948
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
261
949
|
]
|
|
262
|
-
: root.category === '
|
|
950
|
+
: root.category === 'artifactCollision'
|
|
263
951
|
? [
|
|
264
|
-
{ id: '
|
|
265
|
-
{ id: '
|
|
266
|
-
{ id: 'viewTechnical', label: '技术详情' },
|
|
952
|
+
{ id: 'viewTechnical', label: '查看冲突原因' },
|
|
953
|
+
{ id: 'retryLater', label: '处理冲突后重试' },
|
|
267
954
|
]
|
|
268
|
-
: root.category === '
|
|
955
|
+
: root.category === 'incompleteInstallation'
|
|
269
956
|
? [
|
|
270
|
-
|
|
957
|
+
...consumerRecoveryActions,
|
|
271
958
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
272
959
|
]
|
|
273
|
-
: root.category === '
|
|
960
|
+
: root.category === 'sourceMissing'
|
|
274
961
|
? [
|
|
275
|
-
|
|
962
|
+
...consumerRecoveryActions,
|
|
963
|
+
{ id: 'reAddSource', label: '重新添加同一来源', description: '保留来源 ID;来源类型和位置由你选择' },
|
|
276
964
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
277
965
|
]
|
|
278
|
-
: root.category === '
|
|
966
|
+
: root.category === 'sourceIdentityChanged'
|
|
279
967
|
? [
|
|
280
|
-
|
|
281
|
-
id: 'cleanup',
|
|
282
|
-
label: '清理已安装内容',
|
|
283
|
-
description: '只清理 AW 管理的现场内容;保留插件设置',
|
|
284
|
-
writeAction: 'cleanup',
|
|
285
|
-
}] : []),
|
|
286
|
-
{ id: 'editSource', label: '查看来源', description: root.code === 'bundleUnavailable' ? '检查当前 Catalog 或稍后重试' : '修复来源配置或稍后重试' },
|
|
968
|
+
{ id: 'viewSourceChange', label: '查看来源变更', description: '不会自动覆盖现场状态' },
|
|
287
969
|
{ id: 'viewTechnical', label: '技术详情' },
|
|
288
970
|
]
|
|
289
|
-
:
|
|
290
|
-
|
|
971
|
+
: root.category === 'sourceUnavailable'
|
|
972
|
+
? [
|
|
973
|
+
...consumerRecoveryActions.filter((action) => action.id === 'cleanup'),
|
|
974
|
+
{ id: 'editSource', label: '查看来源', description: root.code === 'bundleUnavailable'
|
|
975
|
+
? '检查当前插件目录或稍后重试'
|
|
976
|
+
: root.code === 'codexIntentSourceUnavailable'
|
|
977
|
+
? '恢复来源后可重新同步已保存的使用设置'
|
|
978
|
+
: '修复来源配置或稍后重试' },
|
|
979
|
+
{ id: 'viewTechnical', label: '技术详情' },
|
|
980
|
+
]
|
|
981
|
+
: [...consumerRecoveryActions,
|
|
982
|
+
{ id: 'viewTechnical', label: '技术详情' },
|
|
983
|
+
{ id: 'retryLater', label: '稍后重试' }];
|
|
291
984
|
const bundleUnavailable = root.code === 'bundleUnavailable';
|
|
985
|
+
const codexIntentSourceUnavailable = root.code === 'codexIntentSourceUnavailable';
|
|
986
|
+
const relationship = targetIssueRelationship({
|
|
987
|
+
target,
|
|
988
|
+
error: rootError,
|
|
989
|
+
dependencyPluginId,
|
|
990
|
+
});
|
|
991
|
+
const directRootCode = root.code === 'partial' ? 'incompleteInstallation'
|
|
992
|
+
: root.code === 'targetDiagnostic' ? 'diagnostic'
|
|
993
|
+
: undefined;
|
|
994
|
+
const canonicalRoot = relationship.relationship === 'direct' && directRootCode
|
|
995
|
+
? canonicalRootsByEntity.get([
|
|
996
|
+
directRootCode,
|
|
997
|
+
relationship.rootEntity.pluginId,
|
|
998
|
+
relationship.rootEntity.platform,
|
|
999
|
+
relationship.rootEntity.scope,
|
|
1000
|
+
].join('\0'))
|
|
1001
|
+
: undefined;
|
|
1002
|
+
const issueId = rootError?.rootIssueId
|
|
1003
|
+
?? canonicalRoot
|
|
1004
|
+
?? (directRootCode
|
|
1005
|
+
? `${directRootCode}:${target.pluginId}:${target.platform}:${target.scope}`
|
|
1006
|
+
: `target:${target.pluginId}:${target.platform}:${target.scope}:${target.state}${roots.length > 1 ? `:${root.code}` : ''}${dependencyPluginId ? `:${dependencyPluginId}` : ''}`);
|
|
292
1007
|
issues.push({
|
|
293
1008
|
issueId,
|
|
294
1009
|
category: root.category,
|
|
295
1010
|
rootCode: root.code,
|
|
296
1011
|
mergeEligible: root.mergeEligible,
|
|
297
|
-
|
|
1012
|
+
relationship: relationship.relationship,
|
|
1013
|
+
rootEntity: relationship.rootEntity,
|
|
1014
|
+
affectedTargets: [{
|
|
1015
|
+
pluginId: target.pluginId,
|
|
1016
|
+
platform: target.platform,
|
|
1017
|
+
scope: target.scope,
|
|
1018
|
+
relationship: relationship.relationship,
|
|
1019
|
+
}],
|
|
1020
|
+
title: `${target.pluginId} · ${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${dependencyCategory ? `${target.scope === 'user' ? '所有项目' : '当前项目'} · ` : ''}${sharedNativeProjectionIssue ? '由平台共用的内容待同步' : root.category === 'artifactCollision' ? '输出冲突' : dependencyCategory ? {
|
|
298
1021
|
dependencyMissing: '缺少依赖',
|
|
299
1022
|
dependencyNotReady: '依赖安装不完整',
|
|
300
1023
|
dependencyTargetUnsupported: '依赖目标不兼容',
|
|
301
1024
|
dependencyStillRequired: '依赖仍被使用',
|
|
302
1025
|
dependencyGraphInvalid: '依赖关系无效',
|
|
303
|
-
}[root.category] :
|
|
304
|
-
explanation:
|
|
305
|
-
?
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
? '
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
1026
|
+
}[root.category] : incomplete || statusUnconfirmed || systemConsumer?.state === 'incompatible' ? statusIssue.title : bundleUnavailable ? '当前插件目录不再包含此插件' : codexIntentSourceUnavailable ? '已保存使用设置不能解析' : '检查失败'}`,
|
|
1027
|
+
explanation: root.category === 'artifactCollision'
|
|
1028
|
+
? '目标位置已有不属于当前插件的内容。AW 不会覆盖或删除这些内容。'
|
|
1029
|
+
: dependencyCategory
|
|
1030
|
+
? dependencyPluginId
|
|
1031
|
+
? `依赖 ${dependencyPluginId}${dependencyPlatform && dependencyScope
|
|
1032
|
+
? `(${dependencyPlatform === 'codex' ? 'Codex' : 'Claude Code'} · ${dependencyScope === 'user' ? '所有项目' : '当前项目'})`
|
|
1033
|
+
: ''}未就绪;影响 ${target.pluginId}(${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${target.scope === 'user' ? '所有项目' : '当前项目'})。`
|
|
1034
|
+
: `依赖检查未通过;影响 ${target.pluginId}(${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${target.scope === 'user' ? '所有项目' : '当前项目'})。`
|
|
1035
|
+
: sharedNativeDamaged
|
|
1036
|
+
? 'Codex 平台由多个项目共用的生成内容缺失或损坏。'
|
|
1037
|
+
: sharedNativeRenderDrift
|
|
1038
|
+
? 'Codex 平台由多个项目共用的生成内容与当前渲染输入不一致。'
|
|
1039
|
+
: incomplete || statusUnconfirmed || systemConsumer?.state === 'incompatible'
|
|
1040
|
+
? statusIssue.explanation
|
|
1041
|
+
: bundleUnavailable
|
|
1042
|
+
? '当前插件目录不再包含此插件,但仍发现 AW 管理的已安装内容。'
|
|
1043
|
+
: codexIntentSourceUnavailable
|
|
1044
|
+
? '当前插件目录不能解析这个已保存的使用设置。'
|
|
1045
|
+
: '当前目标不能安全分类为正常安装。',
|
|
1046
|
+
impact: [sharedNativeProjectionIssue
|
|
1047
|
+
? '运行同步可重新生成由平台共用的 Skill。'
|
|
1048
|
+
: projectDisablesUserActivation
|
|
1049
|
+
? '恢复后,当前项目可以继续使用已经安装的插件。'
|
|
1050
|
+
: orphanedActivation
|
|
1051
|
+
? '清理只移除多余的启用记录,不会删除其他位置正在使用的插件。'
|
|
1052
|
+
: root.category === 'artifactCollision'
|
|
1053
|
+
? '请先移除或迁移冲突内容,然后重试安装或重新安装。'
|
|
1054
|
+
: bundleUnavailable || codexIntentSourceUnavailable || root.code === 'catalogSourceUnavailable'
|
|
1055
|
+
? '可以核验后取消这个位置的使用设置,并清理可信的 AW 现场。'
|
|
1056
|
+
: '写操作前需要重新检查这个目标。'],
|
|
316
1057
|
entity: { kind: 'plugin', id: target.pluginId },
|
|
317
1058
|
pluginId: target.pluginId,
|
|
318
1059
|
...(dependencyPluginId ? { dependencyPluginId } : {}),
|
|
1060
|
+
...(dependencyPlatform ? { dependencyPlatform } : {}),
|
|
1061
|
+
...(dependencyScope ? { dependencyScope } : {}),
|
|
1062
|
+
...(dependencyProject !== undefined ? { dependencyProject } : {}),
|
|
319
1063
|
platform: target.platform,
|
|
320
1064
|
scope: target.scope,
|
|
321
1065
|
sourceId: target.sourceId,
|
|
322
1066
|
sourceIdentity: target.sourceIdentity,
|
|
323
1067
|
actions,
|
|
324
|
-
technicalDetails: target.
|
|
325
|
-
? target.
|
|
1068
|
+
technicalDetails: target.reasons.length > 0
|
|
1069
|
+
? target.reasons.filter((error) => root.code === 'targetDiagnostic'
|
|
326
1070
|
|| root.code === 'partial'
|
|
327
|
-
|| error.code === root.code
|
|
328
|
-
|
|
1071
|
+
|| error.code === root.code
|
|
1072
|
+
|| error.rootIssueId === issueId)
|
|
1073
|
+
.map((error) => ({
|
|
1074
|
+
code: error.code,
|
|
1075
|
+
message: error.collision
|
|
1076
|
+
? ({
|
|
1077
|
+
ownerMismatch: '目标由其他 owner 占用。',
|
|
1078
|
+
unownedContent: '目标包含没有 AW owner 标记的内容。',
|
|
1079
|
+
typeMismatch: '目标节点类型不符合预期。',
|
|
1080
|
+
})[error.collision.reason]
|
|
1081
|
+
: '状态检查报告了这个安全错误代码。',
|
|
1082
|
+
}))
|
|
329
1083
|
: [{ code: 'targetStateError', message: '目标状态异常。' }],
|
|
330
1084
|
});
|
|
331
1085
|
}
|
|
332
1086
|
}
|
|
333
|
-
for (const targets of byPlacement.values()) {
|
|
334
|
-
const installed = targets.filter(isInstalledScopeEvidence);
|
|
335
|
-
if (new Set(installed.map((target) => target.scope)).size < 2)
|
|
336
|
-
continue;
|
|
337
|
-
const sample = installed[0];
|
|
338
|
-
issues.push({
|
|
339
|
-
issueId: `scope:${sample.pluginId}:${sample.platform}`,
|
|
340
|
-
category: 'scopeConflict',
|
|
341
|
-
title: `${sample.pluginId} · ${sample.platform === 'codex' ? 'Codex' : 'Claude Code'} · 安装位置冲突`,
|
|
342
|
-
explanation: '所有项目和当前项目同时发现了这个插件。',
|
|
343
|
-
impact: ['正常状态只能保留一个位置。'],
|
|
344
|
-
entity: { kind: 'plugin', id: sample.pluginId },
|
|
345
|
-
pluginId: sample.pluginId,
|
|
346
|
-
platform: sample.platform,
|
|
347
|
-
sourceId: sample.sourceId,
|
|
348
|
-
sourceIdentity: sample.sourceIdentity,
|
|
349
|
-
placements: installed.map((target) => target.scope).sort(compareText),
|
|
350
|
-
actions: [
|
|
351
|
-
{ id: 'keepUserScope', label: '保留所有项目', description: '移除当前项目中的安装;设置保留' },
|
|
352
|
-
{ id: 'keepProjectScope', label: '保留当前项目', description: '移除所有项目中的安装;设置保留' },
|
|
353
|
-
{ id: 'viewTechnical', label: '查看两个位置的详情' },
|
|
354
|
-
],
|
|
355
|
-
technicalDetails: [{ code: 'scopeConflict', message: '同一插件和平台存在两个安装位置。' }],
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
1087
|
return issues;
|
|
359
1088
|
}
|
|
360
1089
|
function statusIssues(payload) {
|
|
361
|
-
const targetCodes = new Set(payload.targets.flatMap((target) => target.
|
|
1090
|
+
const targetCodes = new Set(payload.targets.flatMap((target) => target.reasons.map((error) => error.code)));
|
|
362
1091
|
const issues = new Map();
|
|
363
1092
|
for (const error of payload.errors) {
|
|
364
1093
|
if (targetCodes.has(error.code) || issues.has(error.code))
|
|
@@ -402,154 +1131,164 @@ function statusIssues(payload) {
|
|
|
402
1131
|
function configIssues(pluginSummaries) {
|
|
403
1132
|
return pluginSummaries.flatMap((summary) => {
|
|
404
1133
|
const sourceId = summary.pluginId.slice(0, summary.pluginId.indexOf('/'));
|
|
1134
|
+
const issues = [];
|
|
405
1135
|
if (summary.configDiagnostic) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
1136
|
+
issues.push({
|
|
1137
|
+
issueId: `config:${summary.pluginId}:read`,
|
|
1138
|
+
category: 'diagnostic',
|
|
1139
|
+
title: `${summary.displayName ?? summary.pluginName} · 设置状态不可读`,
|
|
1140
|
+
explanation: '当前不能安全读取这个插件的设置状态。',
|
|
1141
|
+
impact: ['其他插件仍可检查;当前插件的设置值不会显示。'],
|
|
1142
|
+
entity: { kind: 'plugin', id: summary.pluginId },
|
|
1143
|
+
pluginId: summary.pluginId,
|
|
1144
|
+
sourceId,
|
|
1145
|
+
actions: [
|
|
1146
|
+
{ id: 'retryLater', label: '稍后重新检查' },
|
|
1147
|
+
{ id: 'viewTechnical', label: '查看技术详情' },
|
|
1148
|
+
],
|
|
1149
|
+
technicalDetails: [{
|
|
1150
|
+
code: summary.configDiagnostic.code,
|
|
1151
|
+
message: '设置读取报告了这个安全错误代码。',
|
|
1152
|
+
}],
|
|
1153
|
+
});
|
|
424
1154
|
}
|
|
425
1155
|
if (!summary.configIssues?.length)
|
|
426
|
-
return
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
: onlySource === 'projectLocal'
|
|
436
|
-
? { scope: 'project', projectLayer: 'local' }
|
|
437
|
-
: undefined;
|
|
438
|
-
return [{
|
|
439
|
-
issueId: `config:${summary.pluginId}:${invalid ? 'invalid' : 'required'}`,
|
|
440
|
-
category: 'requiredConfigMissing',
|
|
441
|
-
title: `${summary.displayName ?? summary.pluginName} · ${invalid ? '设置值无效' : '缺少必填设置'}`,
|
|
442
|
-
explanation: invalid
|
|
443
|
-
? '已有设置值不符合当前字段规则。'
|
|
444
|
-
: '插件缺少必填设置,写操作会在预检时被阻止。',
|
|
445
|
-
impact: [invalid ? '修正所列字段后才能稳定生成插件内容。' : '完成所列字段后才能稳定生成插件内容。'],
|
|
1156
|
+
return issues;
|
|
1157
|
+
const unsupported = summary.configIssues.filter((issue) => issue.type === 'configLayerUnsupported');
|
|
1158
|
+
if (unsupported.length > 0) {
|
|
1159
|
+
issues.push({
|
|
1160
|
+
issueId: `config:${summary.pluginId}:unsupported-project-layer`,
|
|
1161
|
+
category: 'configLayerUnsupported',
|
|
1162
|
+
title: `${summary.displayName ?? summary.pluginName} · 项目设置包含旧值`,
|
|
1163
|
+
explanation: '本项目旧值不再受支持;当前继承个人或插件默认。',
|
|
1164
|
+
impact: ['旧值不会参与生成。可以进入项目设置删除旧值。'],
|
|
446
1165
|
entity: { kind: 'plugin', id: summary.pluginId },
|
|
447
1166
|
pluginId: summary.pluginId,
|
|
448
1167
|
sourceId,
|
|
449
|
-
|
|
450
|
-
...(configLayer ? { configLayer } : {}),
|
|
1168
|
+
configLayer: { scope: 'project' },
|
|
451
1169
|
actions: [
|
|
452
|
-
{ id: 'openConfig', label:
|
|
1170
|
+
{ id: 'openConfig', label: '删除旧值', description: '进入项目设置并恢复继承' },
|
|
453
1171
|
{ id: 'viewTechnical', label: '查看字段详情' },
|
|
454
1172
|
],
|
|
455
|
-
technicalDetails:
|
|
1173
|
+
technicalDetails: unsupported.map((entry) => ({
|
|
456
1174
|
code: entry.type,
|
|
457
|
-
message: `${entry.title} ·
|
|
1175
|
+
message: `${entry.title} · project · 实际使用 user/default`,
|
|
458
1176
|
})),
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
function enrichDependencyIssuePlacements(issues, overviews) {
|
|
463
|
-
const overviewById = new Map(overviews.map((overview) => [overview.pluginId, overview]));
|
|
464
|
-
return issues.map((issue) => {
|
|
465
|
-
if ((issue.category !== 'dependencyMissing' && issue.category !== 'dependencyNotReady')
|
|
466
|
-
|| !issue.pluginId || !issue.dependencyPluginId || !issue.platform || !issue.scope)
|
|
467
|
-
return issue;
|
|
468
|
-
const dependency = overviewById.get(issue.pluginId)?.dependencies.find((candidate) => candidate.pluginId === issue.dependencyPluginId);
|
|
469
|
-
const references = (dependency?.placementReferences ?? []).filter((reference) => reference.consumer.pluginId === issue.pluginId
|
|
470
|
-
&& reference.consumer.platform === issue.platform
|
|
471
|
-
&& reference.consumer.scope === issue.scope
|
|
472
|
-
&& (issue.scope === 'user' || reference.consumer.project === 'current'))
|
|
473
|
-
.sort((left, right) => [
|
|
474
|
-
left.dependency.pluginId,
|
|
475
|
-
left.dependency.platform,
|
|
476
|
-
left.dependency.scope,
|
|
477
|
-
left.dependency.project ?? '',
|
|
478
|
-
].join('\0').localeCompare([
|
|
479
|
-
right.dependency.pluginId,
|
|
480
|
-
right.dependency.platform,
|
|
481
|
-
right.dependency.scope,
|
|
482
|
-
right.dependency.project ?? '',
|
|
483
|
-
].join('\0'), 'en'));
|
|
484
|
-
const target = references[0]?.dependency;
|
|
485
|
-
if (!target) {
|
|
486
|
-
return {
|
|
487
|
-
...issue,
|
|
488
|
-
actions: issue.actions.filter((action) => action.id !== 'installDependency' && action.id !== 'reinstallDependency'),
|
|
489
|
-
};
|
|
1177
|
+
});
|
|
490
1178
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
1179
|
+
const blockingIssues = summary.configIssues.filter((issue) => issue.type !== 'configLayerUnsupported');
|
|
1180
|
+
if (blockingIssues.length === 0)
|
|
1181
|
+
return issues;
|
|
1182
|
+
const types = new Set(blockingIssues.map((issue) => issue.type));
|
|
1183
|
+
const invalid = types.has('invalid-config') || types.has('sharedCompositeContainsLocalPath');
|
|
1184
|
+
const sources = new Set(blockingIssues.map((issue) => issue.source));
|
|
1185
|
+
const onlySource = sources.size === 1 ? [...sources][0] : undefined;
|
|
1186
|
+
const configLayer = onlySource === 'user'
|
|
1187
|
+
? { scope: 'user' }
|
|
1188
|
+
: onlySource === 'project'
|
|
1189
|
+
? { scope: 'project' }
|
|
1190
|
+
: undefined;
|
|
1191
|
+
issues.push({
|
|
1192
|
+
issueId: `config:${summary.pluginId}:${invalid ? 'invalid' : 'required'}`,
|
|
1193
|
+
category: 'requiredConfigMissing',
|
|
1194
|
+
title: `${summary.displayName ?? summary.pluginName} · ${invalid ? '设置值无效' : '缺少必填设置'}`,
|
|
1195
|
+
explanation: invalid
|
|
1196
|
+
? '已有设置值不符合当前字段规则。'
|
|
1197
|
+
: '插件缺少必填设置,写操作会在预检时被阻止。',
|
|
1198
|
+
impact: [invalid ? '修正所列字段后才能稳定生成插件内容。' : '完成所列字段后才能稳定生成插件内容。'],
|
|
1199
|
+
entity: { kind: 'plugin', id: summary.pluginId },
|
|
1200
|
+
pluginId: summary.pluginId,
|
|
1201
|
+
sourceId,
|
|
1202
|
+
requiredFields: blockingIssues.map(({ key, title, type, source, scope }) => ({
|
|
1203
|
+
key, title, type, source, scope,
|
|
1204
|
+
})),
|
|
1205
|
+
...(configLayer ? { configLayer } : {}),
|
|
1206
|
+
actions: [
|
|
1207
|
+
{ id: 'openConfig', label: invalid ? '修正设置' : '完成设置', description: configLayer ? '进入建议的设置层' : '选择个人或项目设置层' },
|
|
1208
|
+
{ id: 'viewTechnical', label: '查看字段详情' },
|
|
1209
|
+
],
|
|
1210
|
+
technicalDetails: blockingIssues.map((entry) => ({
|
|
1211
|
+
code: entry.type,
|
|
1212
|
+
message: `${entry.title} · ${entry.scope} · ${entry.source}`,
|
|
1213
|
+
})),
|
|
1214
|
+
});
|
|
1215
|
+
return issues;
|
|
505
1216
|
});
|
|
506
1217
|
}
|
|
1218
|
+
function dependencyOverviewIssues(overviews, pluginSummaries, status) {
|
|
1219
|
+
const summaryById = new Map(pluginSummaries.map((summary) => [summary.pluginId, summary]));
|
|
1220
|
+
return overviews.flatMap((overview) => overview.blockers.flatMap((blocker) => {
|
|
1221
|
+
if (blocker.code !== 'dependencyGraphInvalid'
|
|
1222
|
+
&& blocker.code !== 'dependencyTargetUnsupported')
|
|
1223
|
+
return [];
|
|
1224
|
+
if (status.targets.some((target) => target.pluginId === overview.pluginId
|
|
1225
|
+
&& target.reasons.some((error) => error.code === blocker.code)))
|
|
1226
|
+
return [];
|
|
1227
|
+
const summary = summaryById.get(overview.pluginId);
|
|
1228
|
+
const sourceId = overview.pluginId.slice(0, overview.pluginId.indexOf('/'));
|
|
1229
|
+
const category = blocker.code;
|
|
1230
|
+
return [{
|
|
1231
|
+
issueId: `dependency:${overview.pluginId}:${blocker.code}`,
|
|
1232
|
+
category,
|
|
1233
|
+
rootCode: category,
|
|
1234
|
+
mergeEligible: false,
|
|
1235
|
+
title: `${summary?.displayName ?? summary?.pluginName ?? overview.pluginId} · ${blocker.title}`,
|
|
1236
|
+
explanation: blocker.explanation,
|
|
1237
|
+
impact: [category === 'dependencyGraphInvalid'
|
|
1238
|
+
? '修复依赖关系后才能安全计算安装顺序。'
|
|
1239
|
+
: '当前不能在所有声明的平台上安全安装这个插件。'],
|
|
1240
|
+
entity: { kind: 'plugin', id: overview.pluginId },
|
|
1241
|
+
pluginId: overview.pluginId,
|
|
1242
|
+
sourceId,
|
|
1243
|
+
actions: [
|
|
1244
|
+
{ id: 'viewDependencies', label: '查看依赖关系' },
|
|
1245
|
+
{ id: 'viewTechnical', label: '技术详情' },
|
|
1246
|
+
],
|
|
1247
|
+
technicalDetails: [{ code: blocker.code, message: blocker.explanation }],
|
|
1248
|
+
}];
|
|
1249
|
+
}));
|
|
1250
|
+
}
|
|
507
1251
|
function issueDiagnostic(issue, sourceDetails) {
|
|
508
1252
|
const source = issue.sourceId ? sourceDetails.get(issue.sourceId) : undefined;
|
|
509
|
-
const sourceDegraded = issue.category === 'sourceDegraded';
|
|
510
1253
|
const sourceUnavailable = issue.category === 'sourceUnavailable' && issue.entity.kind === 'source';
|
|
1254
|
+
const configLayerUnsupported = issue.category === 'configLayerUnsupported';
|
|
511
1255
|
const configUnavailable = issue.category === 'diagnostic' && issue.issueId.startsWith('config:');
|
|
512
1256
|
const configInvalid = issue.category === 'requiredConfigMissing';
|
|
513
1257
|
const dependency = issue.category.startsWith('dependency');
|
|
514
1258
|
const platformState = issue.issueId.startsWith('status:') || issue.rootCode === 'targetDiagnostic';
|
|
515
|
-
const preserved =
|
|
1259
|
+
const preserved = sourceUnavailable
|
|
516
1260
|
? '已安装插件和已保存设置不会被删除。'
|
|
517
1261
|
: configUnavailable
|
|
518
1262
|
? '已保存的设置保持不变。'
|
|
519
1263
|
: '现有安装和已保存设置不会因本页自动改变。';
|
|
520
|
-
const impact =
|
|
1264
|
+
const impact = sourceUnavailable
|
|
521
1265
|
? [
|
|
522
|
-
{ state: '
|
|
1266
|
+
{ state: 'blocked', message: '当前不能浏览或安装这个来源中的插件。' },
|
|
523
1267
|
{ state: 'preserved', message: preserved },
|
|
524
1268
|
]
|
|
525
|
-
:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
:
|
|
531
|
-
|
|
532
|
-
state: dependency || configUnavailable || configInvalid || platformState ? 'blocked' : 'degraded',
|
|
533
|
-
message,
|
|
534
|
-
})),
|
|
535
|
-
{ state: 'preserved', message: preserved },
|
|
536
|
-
];
|
|
1269
|
+
: [
|
|
1270
|
+
...issue.impact.map((message) => ({
|
|
1271
|
+
state: dependency || configUnavailable || configInvalid || platformState ? 'blocked' : 'degraded',
|
|
1272
|
+
message,
|
|
1273
|
+
})),
|
|
1274
|
+
{ state: 'preserved', message: preserved },
|
|
1275
|
+
];
|
|
537
1276
|
const primaryAction = issue.actions.find((action) => action.id !== 'viewTechnical');
|
|
538
1277
|
const nextStep = primaryAction
|
|
539
1278
|
? `${primaryAction.label},然后重新检查当前状态。`
|
|
540
1279
|
: '打开技术详情,记录安全错误代码后重新检查。';
|
|
541
|
-
const sourceDiagnostic =
|
|
1280
|
+
const sourceDiagnostic = sourceUnavailable;
|
|
542
1281
|
const rawCode = sourceDiagnostic
|
|
543
1282
|
? source?.errorCode ?? issue.technicalDetails[0]?.code
|
|
544
1283
|
: issue.technicalDetails[0]?.code;
|
|
545
|
-
const code = safeDiagnosticCode(rawCode,
|
|
546
|
-
? '
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
1284
|
+
const code = safeDiagnosticCode(rawCode, sourceUnavailable
|
|
1285
|
+
? 'catalogSourceUnavailable' : 'diagnosticUnavailable');
|
|
1286
|
+
const stage = sourceUnavailable ? 'resolve-source'
|
|
1287
|
+
: configLayerUnsupported ? 'read-config'
|
|
1288
|
+
: configUnavailable ? 'read-config'
|
|
1289
|
+
: configInvalid ? 'validate-config'
|
|
1290
|
+
: dependency ? 'resolve-dependencies'
|
|
1291
|
+
: platformState ? 'read-platform-state' : 'inspect-target';
|
|
553
1292
|
const context = [
|
|
554
1293
|
...(issue.pluginId ? [{ key: 'pluginId', value: issue.pluginId }] : []),
|
|
555
1294
|
...(issue.dependencyPluginId
|
|
@@ -557,9 +1296,6 @@ function issueDiagnostic(issue, sourceDetails) {
|
|
|
557
1296
|
: []),
|
|
558
1297
|
...(issue.platform ? [{ key: 'platform', value: issue.platform }] : []),
|
|
559
1298
|
...(issue.scope ? [{ key: 'scope', value: issue.scope }] : []),
|
|
560
|
-
...(sourceDiagnostic && source?.freshness
|
|
561
|
-
? [{ key: 'freshness', value: source.freshness }]
|
|
562
|
-
: []),
|
|
563
1299
|
...(issue.requiredFields?.slice(0, 1).map((field) => ({
|
|
564
1300
|
key: 'field',
|
|
565
1301
|
value: field.title,
|
|
@@ -573,17 +1309,19 @@ function issueDiagnostic(issue, sourceDetails) {
|
|
|
573
1309
|
'按技术详情使用受支持命令或人工处理。',
|
|
574
1310
|
'再次运行状态检查。',
|
|
575
1311
|
]
|
|
576
|
-
:
|
|
577
|
-
? ['
|
|
578
|
-
:
|
|
579
|
-
? ['
|
|
580
|
-
:
|
|
581
|
-
? ['
|
|
582
|
-
:
|
|
583
|
-
? ['
|
|
584
|
-
:
|
|
1312
|
+
: configLayerUnsupported
|
|
1313
|
+
? ['打开项目设置。', '删除本项目旧值。', '重新检查插件设置。']
|
|
1314
|
+
: sourceUnavailable
|
|
1315
|
+
? ['检查 Git URL、ref 或本地目录。', '确认当前终端具备来源授权。', '运行“重新检查来源”验证修复。']
|
|
1316
|
+
: dependency
|
|
1317
|
+
? ['检查依赖关系和依赖插件状态。', '完成恢复动作后重新检查根插件。']
|
|
1318
|
+
: configUnavailable
|
|
1319
|
+
? ['恢复插件来源和可信字段定义。', '重新检查来源后再次打开设置。']
|
|
1320
|
+
: configInvalid
|
|
1321
|
+
? ['完成或修正列出的设置字段。', '重新检查插件设置。']
|
|
1322
|
+
: ['检查目标平台配置和访问权限。', '完成恢复动作后重新运行状态检查。'];
|
|
585
1323
|
return {
|
|
586
|
-
severity:
|
|
1324
|
+
severity: configLayerUnsupported ? 'warning' : 'error',
|
|
587
1325
|
title: issue.title,
|
|
588
1326
|
userMessage: issue.explanation,
|
|
589
1327
|
impact,
|
|
@@ -594,37 +1332,197 @@ function issueDiagnostic(issue, sourceDetails) {
|
|
|
594
1332
|
...(sourceDiagnostic && issue.sourceId ? { sourceId: issue.sourceId } : {}),
|
|
595
1333
|
...(sourceDiagnostic && source?.requestedRef ? { requestedRef: source.requestedRef } : {}),
|
|
596
1334
|
...(sourceDiagnostic && source?.resolvedCommit ? { resolvedCommit: source.resolvedCommit } : {}),
|
|
597
|
-
...(sourceDegraded || sourceUnavailable
|
|
598
|
-
? { lastGood: sourceDegraded ? 'available' : 'unavailable' }
|
|
599
|
-
: {}),
|
|
600
1335
|
...(context.length > 0 ? { context } : {}),
|
|
601
1336
|
checks,
|
|
602
1337
|
},
|
|
603
1338
|
};
|
|
604
1339
|
}
|
|
1340
|
+
const issueGroupOrder = {
|
|
1341
|
+
sourceRemoved: 0,
|
|
1342
|
+
artifactCollision: 1,
|
|
1343
|
+
sourceUnavailable: 2,
|
|
1344
|
+
dependency: 3,
|
|
1345
|
+
scope: 4,
|
|
1346
|
+
config: 5,
|
|
1347
|
+
installation: 6,
|
|
1348
|
+
diagnostic: 7,
|
|
1349
|
+
};
|
|
1350
|
+
function issueGroup(issue) {
|
|
1351
|
+
if (issue.category === 'sourceMissing')
|
|
1352
|
+
return 'sourceRemoved';
|
|
1353
|
+
if (issue.category === 'artifactCollision')
|
|
1354
|
+
return 'artifactCollision';
|
|
1355
|
+
if (issue.category === 'sourceUnavailable'
|
|
1356
|
+
|| issue.category === 'sourceIdentityChanged')
|
|
1357
|
+
return 'sourceUnavailable';
|
|
1358
|
+
if (issue.category.startsWith('dependency'))
|
|
1359
|
+
return 'dependency';
|
|
1360
|
+
if (issue.category === 'scopeConflict')
|
|
1361
|
+
return 'scope';
|
|
1362
|
+
if (issue.category === 'requiredConfigMissing' || issue.category === 'configLayerUnsupported')
|
|
1363
|
+
return 'config';
|
|
1364
|
+
if (issue.category === 'incompleteInstallation')
|
|
1365
|
+
return 'installation';
|
|
1366
|
+
return 'diagnostic';
|
|
1367
|
+
}
|
|
1368
|
+
function primaryAttentionCode(issue) {
|
|
1369
|
+
if (issue.category === 'requiredConfigMissing') {
|
|
1370
|
+
return issue.requiredFields?.some((field) => field.type === 'invalid-config')
|
|
1371
|
+
? 'invalidConfig'
|
|
1372
|
+
: 'requiredConfigMissing';
|
|
1373
|
+
}
|
|
1374
|
+
if (issue.category === 'configLayerUnsupported')
|
|
1375
|
+
return 'configLayerUnsupported';
|
|
1376
|
+
if (issue.category === 'incompleteInstallation')
|
|
1377
|
+
return 'incompleteInstallation';
|
|
1378
|
+
if (issue.category === 'sourceIdentityChanged')
|
|
1379
|
+
return 'sourceUnavailable';
|
|
1380
|
+
return issue.rootCode ?? issue.category;
|
|
1381
|
+
}
|
|
1382
|
+
function issueReasonPriority(issue) {
|
|
1383
|
+
const code = primaryAttentionCode(issue);
|
|
1384
|
+
return {
|
|
1385
|
+
sourceMissing: 0,
|
|
1386
|
+
artifactCollision: 1,
|
|
1387
|
+
sourceUnavailable: 2,
|
|
1388
|
+
catalogSourceUnavailable: 2,
|
|
1389
|
+
bundleUnavailable: 2,
|
|
1390
|
+
codexIntentSourceUnavailable: 2,
|
|
1391
|
+
dependencyGraphInvalid: 3,
|
|
1392
|
+
dependencyTargetUnsupported: 4,
|
|
1393
|
+
dependencyNotReady: 5,
|
|
1394
|
+
dependencyMissing: 5,
|
|
1395
|
+
scopeConflict: 6,
|
|
1396
|
+
requiredConfigMissing: 7,
|
|
1397
|
+
invalidConfig: 7,
|
|
1398
|
+
incompleteInstallation: 8,
|
|
1399
|
+
diagnostic: 9,
|
|
1400
|
+
}[code] ?? 9;
|
|
1401
|
+
}
|
|
1402
|
+
function dedupeIssueActions(actions) {
|
|
1403
|
+
return [...new Map(actions.map((action) => [[
|
|
1404
|
+
action.id,
|
|
1405
|
+
action.pluginId ?? '',
|
|
1406
|
+
action.platform ?? '',
|
|
1407
|
+
action.scope ?? '',
|
|
1408
|
+
].join('\0'), action])).values()];
|
|
1409
|
+
}
|
|
1410
|
+
function collapseRootIssues(issues) {
|
|
1411
|
+
const byId = new Map();
|
|
1412
|
+
for (const issue of issues)
|
|
1413
|
+
byId.set(issue.issueId, [...(byId.get(issue.issueId) ?? []), issue]);
|
|
1414
|
+
return [...byId.values()].map((group) => {
|
|
1415
|
+
const ordered = [...group].sort((left, right) => Number(right.relationship === 'direct') - Number(left.relationship === 'direct')
|
|
1416
|
+
|| compareText(left.pluginId ?? '', right.pluginId ?? '')
|
|
1417
|
+
|| compareText(left.platform ?? '', right.platform ?? '')
|
|
1418
|
+
|| compareText(left.scope ?? '', right.scope ?? ''));
|
|
1419
|
+
const primary = ordered[0];
|
|
1420
|
+
const direct = ordered.find((issue) => issue.relationship === 'direct');
|
|
1421
|
+
const rootEntity = direct?.rootEntity ?? ordered.map((issue) => issue.rootEntity)
|
|
1422
|
+
.filter((entity) => entity !== undefined)
|
|
1423
|
+
.sort((left, right) => compareText(left.pluginId, right.pluginId)
|
|
1424
|
+
|| compareText(left.platform, right.platform)
|
|
1425
|
+
|| compareText(left.scope, right.scope))[0];
|
|
1426
|
+
const affectedTargets = [...new Map(ordered.flatMap((issue) => issue.affectedTargets ?? [])
|
|
1427
|
+
.map((target) => [`${target.pluginId}\0${target.platform}\0${target.scope}`, target])).values()]
|
|
1428
|
+
.sort((left, right) => compareText(left.pluginId, right.pluginId)
|
|
1429
|
+
|| compareText(left.platform, right.platform)
|
|
1430
|
+
|| compareText(left.scope, right.scope));
|
|
1431
|
+
const projected = rootEntity && !direct ? {
|
|
1432
|
+
...primary,
|
|
1433
|
+
title: `${rootEntity.pluginId} · ${rootEntity.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${primary.category === 'artifactCollision' ? '输出冲突' : primary.title.split(' · ').at(-1) ?? primary.title}`,
|
|
1434
|
+
entity: { kind: 'plugin', id: rootEntity.pluginId },
|
|
1435
|
+
pluginId: rootEntity.pluginId,
|
|
1436
|
+
platform: rootEntity.platform,
|
|
1437
|
+
scope: rootEntity.scope,
|
|
1438
|
+
sourceId: rootEntity.pluginId.split('/', 1)[0],
|
|
1439
|
+
} : primary;
|
|
1440
|
+
return {
|
|
1441
|
+
...projected,
|
|
1442
|
+
...(rootEntity ? { rootEntity } : {}),
|
|
1443
|
+
...(affectedTargets.length > 0 ? { affectedTargets } : {}),
|
|
1444
|
+
impact: [...new Set(ordered.flatMap((issue) => issue.impact))],
|
|
1445
|
+
technicalDetails: [...new Map(ordered.flatMap((issue) => issue.technicalDetails)
|
|
1446
|
+
.map((detail) => [`${detail.code}\0${detail.message}`, detail])).values()],
|
|
1447
|
+
actions: dedupeIssueActions(ordered.flatMap((issue) => issue.actions)),
|
|
1448
|
+
};
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
605
1451
|
export function buildTuiViewModel(options) {
|
|
606
1452
|
const dependencyById = new Map((options.dependencyOverviews ?? [])
|
|
607
1453
|
.map((overview) => [overview.pluginId, overview]));
|
|
608
1454
|
const summaryById = new Map(options.pluginSummaries.map((summary) => [summary.pluginId, summary]));
|
|
1455
|
+
const sourceById = new Map(options.status.catalog.sources.map((source) => [source.id, source]));
|
|
609
1456
|
const targetsByPlugin = new Map();
|
|
610
|
-
for (const target of options.status.targets) {
|
|
1457
|
+
for (const target of flattenStatusTargets(options.status.targets)) {
|
|
611
1458
|
targetsByPlugin.set(target.pluginId, [...(targetsByPlugin.get(target.pluginId) ?? []), target]);
|
|
612
1459
|
}
|
|
613
|
-
const
|
|
1460
|
+
const configScopesByPlugin = new Map();
|
|
1461
|
+
for (const store of options.configStoreInventory ?? []) {
|
|
1462
|
+
const scopes = configScopesByPlugin.get(store.pluginId) ?? new Set();
|
|
1463
|
+
scopes.add(store.scope);
|
|
1464
|
+
configScopesByPlugin.set(store.pluginId, scopes);
|
|
1465
|
+
}
|
|
1466
|
+
const retainedStatusIds = new Set([...targetsByPlugin].flatMap(([pluginId, targets]) => targets.some((target) => target.state !== 'absent'
|
|
1467
|
+
|| statusTargetIntent(target).enabled
|
|
1468
|
+
|| target.reasons.length > 0)
|
|
1469
|
+
? [pluginId] : []));
|
|
1470
|
+
const pluginIds = new Set([
|
|
1471
|
+
...summaryById.keys(),
|
|
1472
|
+
...retainedStatusIds,
|
|
1473
|
+
...configScopesByPlugin.keys(),
|
|
1474
|
+
]);
|
|
614
1475
|
const plugins = [...pluginIds].map((pluginId) => {
|
|
615
1476
|
const summary = summaryById.get(pluginId);
|
|
616
|
-
const targets =
|
|
1477
|
+
const targets = summary || retainedStatusIds.has(pluginId)
|
|
1478
|
+
? targetsByPlugin.get(pluginId) ?? [] : [];
|
|
617
1479
|
const sourceId = targets[0]?.sourceId ?? pluginId.slice(0, pluginId.indexOf('/'));
|
|
1480
|
+
const savedConfigScopes = [...(configScopesByPlugin.get(pluginId) ?? [])]
|
|
1481
|
+
.sort((left, right) => (left === 'user' ? 0 : 1) - (right === 'user' ? 0 : 1));
|
|
1482
|
+
const configOnly = summary === undefined && targets.length === 0 && savedConfigScopes.length > 0;
|
|
1483
|
+
const removedPluginCleanupRequired = targets.some((target) => target.reasons.some((reason) => reason.code === 'removedPluginCleanupRequired'));
|
|
618
1484
|
const placements = ['codex', 'claude'].flatMap((platform) => {
|
|
619
1485
|
const platformTargets = targets.filter((target) => target.platform === platform);
|
|
1486
|
+
const aggregateConflict = platform === 'codex' && options.status.targets.some((target) => target.pluginId === pluginId
|
|
1487
|
+
&& target.platform === platform
|
|
1488
|
+
&& target.state === 'blocked'
|
|
1489
|
+
&& target.reasons.some((reason) => reason.code === 'codexExtensionScopeConflict'));
|
|
1490
|
+
if (aggregateConflict) {
|
|
1491
|
+
const scoped = platformTargets.flatMap((target) => {
|
|
1492
|
+
const projected = projectPlatformPlacement(platform, [target], options.targetRevisions);
|
|
1493
|
+
return projected.state === 'installed' ? [{
|
|
1494
|
+
scope: projected.scope,
|
|
1495
|
+
health: projected.health,
|
|
1496
|
+
revision: projected.revision,
|
|
1497
|
+
}] : [];
|
|
1498
|
+
});
|
|
1499
|
+
return [{ platform, state: 'scopeConflict', placements: scoped }];
|
|
1500
|
+
}
|
|
620
1501
|
return platformTargets.length > 0
|
|
621
1502
|
? [projectPlatformPlacement(platform, platformTargets, options.targetRevisions)]
|
|
622
1503
|
: [];
|
|
623
1504
|
});
|
|
624
1505
|
const attention = placements.some((placement) => placement.state === 'scopeConflict'
|
|
625
|
-
|| (placement.state === 'installed'
|
|
626
|
-
|
|
627
|
-
const
|
|
1506
|
+
|| (placement.state === 'installed'
|
|
1507
|
+
&& (placement.health !== 'ready' || placement.blockingReason !== undefined)));
|
|
1508
|
+
const installed = placements.some((placement) => placement.state === 'installed' || placement.state === 'scopeConflict');
|
|
1509
|
+
const sourceUnavailable = options.sourceHealth?.get(sourceId)?.state === 'unavailable'
|
|
1510
|
+
|| sourceById.get(sourceId)?.error !== undefined;
|
|
1511
|
+
const capabilityTargets = targets.filter((target) => target.reasons.some((reason) => reason.code === 'awCapabilityUnsupported'));
|
|
1512
|
+
const capabilityUnsupported = (summary?.missingCapabilities?.length ?? 0) > 0
|
|
1513
|
+
|| capabilityTargets.length > 0;
|
|
1514
|
+
const capabilityRecovery = capabilityTargets.flatMap((target) => target.recoveryActions)
|
|
1515
|
+
.find((action) => action.command === 'manual')?.description;
|
|
1516
|
+
const unavailable = sourceUnavailable || capabilityUnsupported || configOnly;
|
|
1517
|
+
const update = buildPluginUpdateSummary({
|
|
1518
|
+
pluginId,
|
|
1519
|
+
sourceId,
|
|
1520
|
+
targetRevisions: options.targetRevisions ?? [],
|
|
1521
|
+
targets,
|
|
1522
|
+
freshness: options.catalogFreshness?.get(sourceId),
|
|
1523
|
+
sourceIdentity: sourceById.get(sourceId)?.identity,
|
|
1524
|
+
generationKey: options.catalogGenerations?.get(sourceId)?.active?.storeKey,
|
|
1525
|
+
});
|
|
628
1526
|
return {
|
|
629
1527
|
pluginId,
|
|
630
1528
|
sourceId,
|
|
@@ -639,9 +1537,23 @@ export function buildTuiViewModel(options) {
|
|
|
639
1537
|
supportedPlatforms: summary?.supportedTargets
|
|
640
1538
|
? ['codex', 'claude'].filter((platform) => summary.supportedTargets[platform].length > 0)
|
|
641
1539
|
: placements.map((placement) => placement.platform),
|
|
1540
|
+
...(summary?.supportedTargets ? { supportedScopes: {
|
|
1541
|
+
codex: [...summary.supportedTargets.codex],
|
|
1542
|
+
claude: [...summary.supportedTargets.claude],
|
|
1543
|
+
} } : {}),
|
|
642
1544
|
installedPlacements: placements,
|
|
643
1545
|
aggregateStatus: unavailable ? 'unavailable' : attention ? 'needsAttention' : installed ? 'installed' : 'available',
|
|
644
1546
|
portableSkills: options.portablePluginIds?.includes(pluginId) ?? false,
|
|
1547
|
+
...(summary?.missingCapabilities
|
|
1548
|
+
? { missingCapabilities: summary.missingCapabilities }
|
|
1549
|
+
: {}),
|
|
1550
|
+
...(capabilityUnsupported ? { capabilityUnsupported: true } : {}),
|
|
1551
|
+
...(capabilityRecovery ? { capabilityRecovery } : {}),
|
|
1552
|
+
...(sourceUnavailable ? { sourceUnavailable: true } : {}),
|
|
1553
|
+
savedConfigScopes,
|
|
1554
|
+
...(configOnly ? { configOnly: true } : {}),
|
|
1555
|
+
...(summary === undefined ? { catalogEntryMissing: true } : {}),
|
|
1556
|
+
...(removedPluginCleanupRequired ? { removedPluginCleanupRequired: true } : {}),
|
|
645
1557
|
...(dependencyById.get(pluginId)
|
|
646
1558
|
? { dependencySummary: dependencyById.get(pluginId).summary }
|
|
647
1559
|
: summary && (summary.dependencyTotalCount ?? 0) > 0
|
|
@@ -654,74 +1566,133 @@ export function buildTuiViewModel(options) {
|
|
|
654
1566
|
issueCount: summary.dependencyIssueCount ?? 0,
|
|
655
1567
|
} }
|
|
656
1568
|
: {}),
|
|
657
|
-
technicalComponents:
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
1569
|
+
technicalComponents: [
|
|
1570
|
+
...targets.flatMap((target) => [
|
|
1571
|
+
...target.components,
|
|
1572
|
+
...(target.sharedComponents ?? []).filter((component) => component.kind === 'systemConsumer'),
|
|
1573
|
+
].map((component) => ({
|
|
1574
|
+
platform: target.platform,
|
|
1575
|
+
scope: target.scope,
|
|
1576
|
+
key: component.key,
|
|
1577
|
+
state: component.state,
|
|
1578
|
+
...(typeof component.metadata?.errorCode === 'string'
|
|
1579
|
+
? { errorCode: component.metadata.errorCode }
|
|
1580
|
+
: {}),
|
|
1581
|
+
}))),
|
|
1582
|
+
...new Map(targets.flatMap((target) => (target.sharedComponents ?? [])
|
|
1583
|
+
.filter((component) => component.kind === 'sharedNative')
|
|
1584
|
+
.map((component) => [`${target.platform}\0${component.key}`, {
|
|
1585
|
+
platform: target.platform,
|
|
1586
|
+
shared: true,
|
|
1587
|
+
key: component.key,
|
|
1588
|
+
state: component.state,
|
|
1589
|
+
...(typeof component.metadata?.errorCode === 'string'
|
|
1590
|
+
? { errorCode: component.metadata.errorCode }
|
|
1591
|
+
: {}),
|
|
1592
|
+
}]))).values(),
|
|
1593
|
+
],
|
|
1594
|
+
update,
|
|
664
1595
|
};
|
|
665
1596
|
}).sort((left, right) => compareText(left.displayName, right.displayName)
|
|
666
1597
|
|| compareText(left.sourceId, right.sourceId));
|
|
667
|
-
const sourceTabs = options.status.catalog.sources.map((source) =>
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1598
|
+
const sourceTabs = options.status.catalog.sources.map((source) => {
|
|
1599
|
+
const generation = options.catalogGenerations?.get(source.id);
|
|
1600
|
+
const countKnown = generation
|
|
1601
|
+
? generation.state === 'ready' || generation.state === undefined && generation.active !== undefined
|
|
1602
|
+
: source.error === undefined;
|
|
1603
|
+
return {
|
|
1604
|
+
id: source.id,
|
|
1605
|
+
label: source.id,
|
|
1606
|
+
...(countKnown ? { count: plugins.filter((plugin) => plugin.sourceId === source.id).length } : {}),
|
|
1607
|
+
primary: source.primary,
|
|
1608
|
+
state: projectCatalogSourceState(source, options.sourceHealth?.get(source.id), options.catalogFreshness?.get(source.id), generation),
|
|
1609
|
+
};
|
|
1610
|
+
});
|
|
674
1611
|
const sourceRootIds = new Set([...(options.sourceHealth?.values() ?? [])]
|
|
675
|
-
.filter((health) => health.state === '
|
|
1612
|
+
.filter((health) => health.state === 'unavailable')
|
|
676
1613
|
.map((health) => health.sourceId));
|
|
677
|
-
const allTargetIssues = targetIssues(options.status);
|
|
678
|
-
const
|
|
1614
|
+
const allTargetIssues = targetIssues(options.status, options.targetRevisions);
|
|
1615
|
+
const mergedTargetIssues = new Map();
|
|
679
1616
|
for (const issue of allTargetIssues) {
|
|
680
1617
|
if (!issue.mergeEligible || !issue.sourceId || !sourceRootIds.has(issue.sourceId))
|
|
681
1618
|
continue;
|
|
682
|
-
|
|
1619
|
+
mergedTargetIssues.set(issue.sourceId, [...(mergedTargetIssues.get(issue.sourceId) ?? []), issue]);
|
|
683
1620
|
}
|
|
684
1621
|
const sourceDetails = new Map((options.sourceDetails ?? []).map((detail) => [detail.id, detail]));
|
|
685
|
-
const issueDrafts =
|
|
1622
|
+
const issueDrafts = [
|
|
686
1623
|
...allTargetIssues.filter((issue) => !issue.mergeEligible
|
|
687
1624
|
|| !issue.sourceId || !sourceRootIds.has(issue.sourceId)),
|
|
688
1625
|
...statusIssues(options.status),
|
|
689
1626
|
...configIssues(options.pluginSummaries),
|
|
690
|
-
...
|
|
691
|
-
|
|
692
|
-
|
|
1627
|
+
...dependencyOverviewIssues(options.dependencyOverviews ?? [], options.pluginSummaries, options.status),
|
|
1628
|
+
...[...(options.sourceHealth?.values() ?? [])].flatMap((health) => sourceIssue(health, mergedTargetIssues.get(health.sourceId) ?? []) ?? []),
|
|
1629
|
+
];
|
|
1630
|
+
const stableIssueDrafts = collapseRootIssues(issueDrafts).sort((left, right) => issueGroupOrder[issueGroup(left)] - issueGroupOrder[issueGroup(right)]
|
|
1631
|
+
|| issueReasonPriority(left) - issueReasonPriority(right)
|
|
1632
|
+
|| compareText(primaryAttentionCode(left), primaryAttentionCode(right))
|
|
1633
|
+
|| compareText(left.issueId, right.issueId));
|
|
1634
|
+
const issues = stableIssueDrafts.map((issue) => ({
|
|
693
1635
|
...issue,
|
|
1636
|
+
group: issueGroup(issue),
|
|
694
1637
|
diagnostic: issueDiagnostic(issue, sourceDetails),
|
|
695
1638
|
}));
|
|
1639
|
+
const pluginsWithAttention = plugins.map((plugin) => {
|
|
1640
|
+
const primary = stableIssueDrafts.filter((issue) => issue.pluginId === plugin.pluginId
|
|
1641
|
+
|| issue.dependencyPluginId === plugin.pluginId
|
|
1642
|
+
|| issue.affectedTargets?.some((target) => target.pluginId === plugin.pluginId)
|
|
1643
|
+
|| issue.entity.kind === 'source' && issue.sourceId === plugin.sourceId)
|
|
1644
|
+
.sort((left, right) => issueReasonPriority(left) - issueReasonPriority(right)
|
|
1645
|
+
|| compareText(primaryAttentionCode(left), primaryAttentionCode(right))
|
|
1646
|
+
|| compareText(left.issueId, right.issueId))[0];
|
|
1647
|
+
if (!primary)
|
|
1648
|
+
return plugin;
|
|
1649
|
+
return {
|
|
1650
|
+
...plugin,
|
|
1651
|
+
primaryAttention: {
|
|
1652
|
+
severity: primary.category === 'configLayerUnsupported' ? 'warning' : 'error',
|
|
1653
|
+
code: primaryAttentionCode(primary),
|
|
1654
|
+
message: primary.explanation,
|
|
1655
|
+
},
|
|
1656
|
+
};
|
|
1657
|
+
});
|
|
696
1658
|
return {
|
|
697
|
-
plugins,
|
|
1659
|
+
plugins: pluginsWithAttention,
|
|
698
1660
|
sourceTabs,
|
|
699
|
-
sourceDetails: (options.sourceDetails ?? []).map((detail) =>
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
})
|
|
1661
|
+
sourceDetails: (options.sourceDetails ?? []).map((detail) => {
|
|
1662
|
+
const count = sourceTabs.find((source) => source.id === detail.id)?.count;
|
|
1663
|
+
return { ...detail, ...(count === undefined ? {} : { pluginCount: count }) };
|
|
1664
|
+
}),
|
|
703
1665
|
issues,
|
|
704
1666
|
dependencyOverviews: options.dependencyOverviews ?? [],
|
|
1667
|
+
contentOverviews: options.contentOverviews ?? {},
|
|
705
1668
|
home: {
|
|
706
|
-
availablePlugins:
|
|
707
|
-
installedPlugins:
|
|
1669
|
+
availablePlugins: pluginsWithAttention.filter((plugin) => plugin.aggregateStatus === 'available').length,
|
|
1670
|
+
installedPlugins: new Set(pluginsWithAttention
|
|
1671
|
+
.filter(hasInstalledPlacement)
|
|
1672
|
+
.map((plugin) => plugin.pluginId)).size,
|
|
708
1673
|
issueCount: issues.length,
|
|
709
1674
|
sourceCount: sourceTabs.length,
|
|
710
|
-
|
|
711
|
-
|
|
1675
|
+
unavailableSourceCount: options.status.catalog.sources.filter((source) => source.error
|
|
1676
|
+
|| options.sourceHealth?.get(source.id)?.state === 'unavailable').length,
|
|
1677
|
+
catalogUpdateCount: sourceTabs.filter((source) => source.state === 'update').length,
|
|
1678
|
+
catalogRecoveryCount: sourceTabs.filter((source) => source.state === 'recovery'
|
|
1679
|
+
|| source.state === 'error').length,
|
|
1680
|
+
catalogCheckingCount: sourceTabs.filter((source) => source.state === 'checking').length,
|
|
1681
|
+
pluginUpdateCount: pluginsWithAttention.filter((plugin) => plugin.update.state === 'available').length,
|
|
1682
|
+
directPluginUpdateCount: pluginsWithAttention.filter((plugin) => plugin.update.targets.some((target) => target.availableVersion !== undefined && target.requiresCatalogActivation !== true
|
|
1683
|
+
&& target.eligibility === 'allowed')).length,
|
|
712
1684
|
},
|
|
713
1685
|
};
|
|
714
1686
|
}
|
|
715
1687
|
function displayConfigValue(options) {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
return String(options.value);
|
|
1688
|
+
return presentConfigValue({
|
|
1689
|
+
definition: options.field,
|
|
1690
|
+
summary: options.summary,
|
|
1691
|
+
itemSummary: options.itemSummary,
|
|
1692
|
+
value: options.value,
|
|
1693
|
+
configured: options.configured,
|
|
1694
|
+
privateValue: options.privateValue,
|
|
1695
|
+
}).text;
|
|
725
1696
|
}
|
|
726
1697
|
function configSourceLabel(source) {
|
|
727
1698
|
if (!source)
|
|
@@ -730,18 +1701,62 @@ function configSourceLabel(source) {
|
|
|
730
1701
|
default: '默认值',
|
|
731
1702
|
user: '个人默认',
|
|
732
1703
|
project: '当前项目',
|
|
733
|
-
local: '当前项目(仅本机)',
|
|
734
1704
|
}[source];
|
|
735
1705
|
}
|
|
1706
|
+
function configEditorDefinition(field) {
|
|
1707
|
+
const definition = structuredClone(field);
|
|
1708
|
+
delete definition.default;
|
|
1709
|
+
if (definition.sensitive === true)
|
|
1710
|
+
delete definition.choices;
|
|
1711
|
+
return definition;
|
|
1712
|
+
}
|
|
1713
|
+
function configObjectChildChanges(field, before, after) {
|
|
1714
|
+
const properties = { ...resolvePluginConfigObjectProperties(field, before).properties,
|
|
1715
|
+
...resolvePluginConfigObjectProperties(field, after ?? {}).properties };
|
|
1716
|
+
const fixed = Object.keys(properties);
|
|
1717
|
+
const summary = (property, value, object) => {
|
|
1718
|
+
if (value === undefined)
|
|
1719
|
+
return '未设置';
|
|
1720
|
+
const definition = resolvePluginConfigObjectProperties(field, object).properties[property]
|
|
1721
|
+
?? (field.additionalProperties === false ? undefined : field.additionalProperties);
|
|
1722
|
+
if (field.sensitive || definition?.sensitive)
|
|
1723
|
+
return '已设置';
|
|
1724
|
+
return definition ? presentConfigValue({ definition, value, full: true }).text : safeConfigText(JSON.stringify(value));
|
|
1725
|
+
};
|
|
1726
|
+
return [...new Set([...Object.keys(before), ...Object.keys(after ?? {})])]
|
|
1727
|
+
.sort((left, right) => {
|
|
1728
|
+
const leftIndex = fixed.indexOf(left);
|
|
1729
|
+
const rightIndex = fixed.indexOf(right);
|
|
1730
|
+
if (leftIndex >= 0 || rightIndex >= 0) {
|
|
1731
|
+
if (leftIndex < 0)
|
|
1732
|
+
return 1;
|
|
1733
|
+
if (rightIndex < 0)
|
|
1734
|
+
return -1;
|
|
1735
|
+
return leftIndex - rightIndex;
|
|
1736
|
+
}
|
|
1737
|
+
return left.localeCompare(right, 'en');
|
|
1738
|
+
})
|
|
1739
|
+
.filter((property) => !configValuesEqual(before[property], after?.[property]))
|
|
1740
|
+
.map((property) => {
|
|
1741
|
+
const definition = properties[property]
|
|
1742
|
+
?? (field.additionalProperties === false ? undefined : field.additionalProperties);
|
|
1743
|
+
return {
|
|
1744
|
+
property,
|
|
1745
|
+
before: summary(property, before[property], before),
|
|
1746
|
+
after: summary(property, after?.[property], after ?? {}),
|
|
1747
|
+
...(field.sensitive || definition?.sensitive ? { private: true } : {}),
|
|
1748
|
+
};
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
736
1751
|
export function buildConfigGroups(options) {
|
|
737
1752
|
const entryByKey = new Map(options.read.fields.map((field) => [field.key, field]));
|
|
738
1753
|
const effectiveEntryByKey = new Map((options.effectiveRead ?? options.read).fields.map((field) => [field.key, field]));
|
|
739
1754
|
const effectivePage = options.read.scope === 'effective';
|
|
1755
|
+
const layerEntry = (layer, key) => options.layerReads?.[layer]?.fields.find((field) => field.key === key);
|
|
740
1756
|
const fieldModel = (key) => {
|
|
741
|
-
const schema = options.schema.
|
|
1757
|
+
const schema = options.schema.fields[key];
|
|
742
1758
|
const entry = entryByKey.get(key);
|
|
743
1759
|
const effectiveEntry = effectiveEntryByKey.get(key);
|
|
744
|
-
const presentation = options.schema.presentation?.fields?.[key];
|
|
745
1760
|
const inherited = effectivePage
|
|
746
1761
|
? false
|
|
747
1762
|
: entry?.storedSourceLayer === undefined;
|
|
@@ -752,59 +1767,167 @@ export function buildConfigGroups(options) {
|
|
|
752
1767
|
&& entry.effectiveValue !== null
|
|
753
1768
|
&& (entry.valueState === 'configured' || entry.valueState === 'default')
|
|
754
1769
|
: entry?.storedSourceLayer !== undefined;
|
|
755
|
-
const
|
|
1770
|
+
const presentation = options.schema.presentation;
|
|
1771
|
+
const fieldView = presentation && 'fieldViews' in presentation ? presentation.fieldViews?.[key] : undefined;
|
|
1772
|
+
const summaries = presentation && 'summaries' in presentation ? presentation.summaries : undefined;
|
|
1773
|
+
const summary = fieldView?.summary ? summaries?.[fieldView.summary] : undefined;
|
|
1774
|
+
const itemSummary = fieldView?.itemSummary ? summaries?.[fieldView.itemSummary] : undefined;
|
|
1775
|
+
const privateValue = schema.sensitive === true;
|
|
1776
|
+
const choices = schema.choices;
|
|
756
1777
|
const selectedValue = effectivePage ? entry?.effectiveValue : entry?.storedValue;
|
|
1778
|
+
const selectedRawValue = effectivePage
|
|
1779
|
+
? options.effectiveRawValues?.[key]
|
|
1780
|
+
: options.rawValues?.[key];
|
|
757
1781
|
const selectedStoredInvalid = !effectivePage
|
|
758
1782
|
&& entry?.storedSourceLayer !== undefined
|
|
759
1783
|
&& entry.storedValue === undefined;
|
|
1784
|
+
const invalidOverrideSourceCandidate = selectedStoredInvalid
|
|
1785
|
+
? (effectivePage ? entry?.invalidOverride?.sourceLayer : options.read.scope)
|
|
1786
|
+
: entry?.invalidOverride?.sourceLayer;
|
|
1787
|
+
const invalidOverrideSource = invalidOverrideSourceCandidate === 'user'
|
|
1788
|
+
|| invalidOverrideSourceCandidate === 'project'
|
|
1789
|
+
? invalidOverrideSourceCandidate
|
|
1790
|
+
: undefined;
|
|
1791
|
+
const invalidOverride = invalidOverrideSource !== undefined;
|
|
1792
|
+
const invalidOverrideOwnedByLayer = !effectivePage
|
|
1793
|
+
&& invalidOverrideSource === options.read.scope;
|
|
760
1794
|
const effectiveConfigured = effectiveEntry?.sourceLayer !== undefined
|
|
761
1795
|
&& effectiveEntry.sourceLayer !== null
|
|
762
1796
|
&& effectiveEntry.effectiveValue !== undefined
|
|
763
1797
|
&& effectiveEntry.effectiveValue !== null
|
|
764
1798
|
&& (effectiveEntry.valueState === 'configured' || effectiveEntry.valueState === 'default');
|
|
1799
|
+
const omittedLayer = options.read.scope === 'user'
|
|
1800
|
+
? 'user'
|
|
1801
|
+
: 'project';
|
|
1802
|
+
const fallback = options.read.scope === 'user'
|
|
1803
|
+
? undefined
|
|
1804
|
+
: ['project', 'user']
|
|
1805
|
+
.filter((layer) => layer !== omittedLayer)
|
|
1806
|
+
.map((layer) => ({ layer, entry: layerEntry(layer, key) }))
|
|
1807
|
+
.find((candidate) => candidate.entry?.storedSourceLayer !== undefined);
|
|
1808
|
+
const projectedFallback = entry?.fallback;
|
|
1809
|
+
const fallbackInvalid = projectedFallback?.state === 'invalid';
|
|
1810
|
+
const fallbackValue = projectedFallback?.state === 'valid'
|
|
1811
|
+
? projectedFallback.effectiveValue
|
|
1812
|
+
: projectedFallback
|
|
1813
|
+
? undefined
|
|
1814
|
+
: fallback?.entry?.storedValue ?? schema.default;
|
|
1815
|
+
const fallbackRawValue = projectedFallback?.state === 'valid'
|
|
1816
|
+
? projectedFallback.sourceLayer === 'user'
|
|
1817
|
+
? options.rawLayerValues?.user?.[key] ?? fallbackValue
|
|
1818
|
+
: fallbackValue
|
|
1819
|
+
: projectedFallback
|
|
1820
|
+
? undefined
|
|
1821
|
+
: fallback
|
|
1822
|
+
? options.rawLayerValues?.[fallback.layer]?.[key] ?? fallbackValue
|
|
1823
|
+
: schema.default;
|
|
1824
|
+
const fallbackConfigured = projectedFallback
|
|
1825
|
+
? projectedFallback.state !== 'missing'
|
|
1826
|
+
: fallback !== undefined || schema.default !== undefined;
|
|
1827
|
+
const fallbackSource = projectedFallback?.state === 'valid'
|
|
1828
|
+
|| projectedFallback?.state === 'invalid'
|
|
1829
|
+
? projectedFallback.sourceLayer
|
|
1830
|
+
: projectedFallback
|
|
1831
|
+
? undefined
|
|
1832
|
+
: fallback?.layer ?? (schema.default !== undefined ? 'default' : undefined);
|
|
765
1833
|
return {
|
|
766
1834
|
key,
|
|
767
1835
|
title: schema.title ?? key,
|
|
768
1836
|
...(schema.description ? { description: schema.description } : {}),
|
|
769
1837
|
type: schema.type,
|
|
770
|
-
|
|
1838
|
+
definition: configEditorDefinition(schema),
|
|
1839
|
+
...(summary ? { summary } : {}),
|
|
1840
|
+
...(itemSummary ? { itemSummary } : {}),
|
|
1841
|
+
displayValue: selectedStoredInvalid ? '需修正' : displayConfigValue({
|
|
1842
|
+
field: schema,
|
|
1843
|
+
summary,
|
|
1844
|
+
itemSummary,
|
|
771
1845
|
privateValue,
|
|
772
1846
|
inherited,
|
|
773
1847
|
configured,
|
|
774
|
-
value: selectedValue,
|
|
1848
|
+
value: schema.type === 'object' ? selectedRawValue ?? selectedValue : selectedValue,
|
|
775
1849
|
}),
|
|
776
1850
|
required: schema.required === true,
|
|
777
1851
|
sensitive: schema.sensitive === true,
|
|
1852
|
+
writable: (entry?.writable ?? effectivePage)
|
|
1853
|
+
&& !(options.read.scope === 'project' && privateValue),
|
|
1854
|
+
canSet: (entry?.canSet ?? effectivePage)
|
|
1855
|
+
&& !(options.read.scope === 'project' && privateValue),
|
|
1856
|
+
canUnset: entry?.canUnset ?? false,
|
|
778
1857
|
dirty: options.dirtyKeys?.has(key) === true,
|
|
779
1858
|
inherited,
|
|
780
1859
|
configured,
|
|
781
1860
|
sourceLabel: effectivePage
|
|
782
1861
|
? configSourceLabel(entry?.sourceLayer ?? null)
|
|
783
1862
|
: configured ? '本层已设置' : '继承',
|
|
784
|
-
effectiveDisplayValue: displayConfigValue({
|
|
1863
|
+
effectiveDisplayValue: effectiveEntry?.invalidOverride ? '需修正' : displayConfigValue({
|
|
1864
|
+
field: schema,
|
|
1865
|
+
summary,
|
|
1866
|
+
itemSummary,
|
|
785
1867
|
privateValue,
|
|
786
1868
|
inherited: false,
|
|
787
1869
|
configured: effectiveConfigured,
|
|
788
|
-
value:
|
|
1870
|
+
value: schema.type === 'object'
|
|
1871
|
+
? options.effectiveRawValues?.[key] ?? effectiveEntry?.effectiveValue
|
|
1872
|
+
: effectiveEntry?.effectiveValue,
|
|
789
1873
|
}),
|
|
790
1874
|
effectiveSourceLabel: configSourceLabel(effectiveEntry?.sourceLayer ?? null),
|
|
1875
|
+
...(invalidOverride ? {
|
|
1876
|
+
invalidOverrideOwnedByLayer,
|
|
1877
|
+
invalidOverrideIssue: invalidOverrideOwnedByLayer
|
|
1878
|
+
? schema.type === 'object'
|
|
1879
|
+
? `字段“${schema.title ?? key}”在本层的对象值无效。请修改或删除此字段。`
|
|
1880
|
+
: `字段“${schema.title ?? key}”在本层的值无效。请修改或删除此字段。`
|
|
1881
|
+
: `字段“${schema.title ?? key}”在${configSourceLabel(invalidOverrideSource ?? null)}中的值无效。请切换到该设置层修改或删除此字段。`,
|
|
1882
|
+
} : {}),
|
|
1883
|
+
...(!effectivePage && configured ? {
|
|
1884
|
+
fallbackDisplayValue: fallbackInvalid
|
|
1885
|
+
? '值无效;保存可成功,但应用会被阻止'
|
|
1886
|
+
: displayConfigValue({
|
|
1887
|
+
field: schema,
|
|
1888
|
+
summary,
|
|
1889
|
+
itemSummary,
|
|
1890
|
+
privateValue,
|
|
1891
|
+
inherited: false,
|
|
1892
|
+
configured: fallbackConfigured,
|
|
1893
|
+
value: schema.type === 'object' ? fallbackRawValue : fallbackValue,
|
|
1894
|
+
}),
|
|
1895
|
+
fallbackSourceLabel: fallbackSource ? configSourceLabel(fallbackSource) : '未设置',
|
|
1896
|
+
...(!fallbackInvalid && schema.type === 'object'
|
|
1897
|
+
&& typeof (selectedRawValue ?? selectedValue) === 'object'
|
|
1898
|
+
&& (selectedRawValue ?? selectedValue) !== null
|
|
1899
|
+
? { fallbackObjectChanges: configObjectChildChanges(schema, (selectedRawValue ?? selectedValue), typeof fallbackRawValue === 'object' && fallbackRawValue !== null
|
|
1900
|
+
? fallbackRawValue
|
|
1901
|
+
: undefined) }
|
|
1902
|
+
: {}),
|
|
1903
|
+
} : {}),
|
|
791
1904
|
...(!privateValue && selectedValue !== undefined
|
|
792
1905
|
? { value: selectedValue }
|
|
793
1906
|
: {}),
|
|
794
1907
|
...(!privateValue && effectiveEntry?.effectiveValue !== undefined && effectiveEntry.effectiveValue !== null
|
|
795
1908
|
? { effectiveValue: effectiveEntry.effectiveValue }
|
|
796
1909
|
: {}),
|
|
1910
|
+
...(!privateValue && (effectivePage
|
|
1911
|
+
? options.effectiveRawValues?.[key]
|
|
1912
|
+
: selectedRawValue ?? (schema.type === 'object' && !configured
|
|
1913
|
+
? options.effectiveRawValues?.[key]
|
|
1914
|
+
: undefined)) !== undefined
|
|
1915
|
+
? { draftValue: (effectivePage
|
|
1916
|
+
? options.effectiveRawValues?.[key]
|
|
1917
|
+
: selectedRawValue ?? options.effectiveRawValues?.[key]) }
|
|
1918
|
+
: {}),
|
|
797
1919
|
...(!privateValue && schema.default !== undefined ? { defaultValue: schema.default } : {}),
|
|
798
|
-
...(
|
|
799
|
-
|
|
800
|
-
...(
|
|
801
|
-
|
|
1920
|
+
...(!privateValue && choices ? { choices: choices.presets } : {}),
|
|
1921
|
+
allowCustom: choices?.allowCustom ?? true,
|
|
1922
|
+
...(!privateValue && !configObjectHasSensitiveChild(schema)
|
|
1923
|
+
&& (selectedRawValue ?? selectedValue) !== undefined && (selectedRawValue ?? selectedValue) !== null
|
|
1924
|
+
&& matchPluginConfigPreset(schema, (selectedRawValue ?? selectedValue))
|
|
1925
|
+
? { matchedPresetId: matchPluginConfigPreset(schema, (selectedRawValue ?? selectedValue)).id }
|
|
802
1926
|
: {}),
|
|
803
|
-
...(
|
|
804
|
-
...(
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
advanced: presentation?.advanced === true,
|
|
1927
|
+
...(schema.type === 'number' && schema.validation?.minimum !== undefined ? { min: schema.validation.minimum } : {}),
|
|
1928
|
+
...(schema.type === 'number' && schema.validation?.maximum !== undefined ? { max: schema.validation.maximum } : {}),
|
|
1929
|
+
advanced: false,
|
|
1930
|
+
sharedNativeRender: options.sharedNativeRefreshKeys?.has(key) === true,
|
|
808
1931
|
};
|
|
809
1932
|
};
|
|
810
1933
|
const assigned = new Set();
|
|
@@ -828,18 +1951,20 @@ export function buildConfigGroups(options) {
|
|
|
828
1951
|
}
|
|
829
1952
|
return id;
|
|
830
1953
|
};
|
|
831
|
-
const remaining = Object.keys(options.schema.
|
|
1954
|
+
const remaining = Object.keys(options.schema.fields)
|
|
1955
|
+
.filter((key) => !assigned.has(key));
|
|
832
1956
|
if (!options.schema.presentation) {
|
|
833
1957
|
groups.push({
|
|
834
1958
|
id: 'general',
|
|
835
1959
|
title: '插件设置',
|
|
836
1960
|
advanced: false,
|
|
837
|
-
fields: Object.keys(options.schema.
|
|
1961
|
+
fields: Object.keys(options.schema.fields)
|
|
1962
|
+
.map(fieldModel),
|
|
838
1963
|
});
|
|
839
1964
|
}
|
|
840
1965
|
else {
|
|
841
|
-
const ordinary = remaining
|
|
842
|
-
const advanced =
|
|
1966
|
+
const ordinary = remaining;
|
|
1967
|
+
const advanced = [];
|
|
843
1968
|
if (ordinary.length > 0) {
|
|
844
1969
|
groups.push({
|
|
845
1970
|
id: syntheticGroupId('general'),
|
|
@@ -860,28 +1985,16 @@ export function buildConfigGroups(options) {
|
|
|
860
1985
|
return groups;
|
|
861
1986
|
}
|
|
862
1987
|
export function buildConfigPage(options) {
|
|
863
|
-
const privateFields = new Set(Object.entries(options.schema.schema)
|
|
864
|
-
.filter(([, field]) => field.sensitive === true || field.type === 'file' || field.type === 'directory')
|
|
865
|
-
.map(([key]) => key));
|
|
866
|
-
const presets = (options.schema.presentation?.presets ?? []).map((preset) => {
|
|
867
|
-
const privateFieldTitles = Object.keys(preset.values)
|
|
868
|
-
.filter((key) => privateFields.has(key))
|
|
869
|
-
.map((key) => options.schema.schema[key]?.title ?? key);
|
|
870
|
-
return {
|
|
871
|
-
id: preset.id,
|
|
872
|
-
title: preset.title,
|
|
873
|
-
...(preset.description ? { description: preset.description } : {}),
|
|
874
|
-
values: Object.fromEntries(Object.entries(preset.values)
|
|
875
|
-
.filter(([key]) => !privateFields.has(key))),
|
|
876
|
-
...(privateFieldTitles.length > 0 ? { privateFieldTitles } : {}),
|
|
877
|
-
};
|
|
878
|
-
});
|
|
879
1988
|
return {
|
|
880
1989
|
pluginId: options.pluginId,
|
|
881
|
-
layer: { scope: options.read.scope
|
|
1990
|
+
layer: { scope: options.read.scope },
|
|
882
1991
|
groups: buildConfigGroups(options),
|
|
883
|
-
presets,
|
|
1992
|
+
presets: [],
|
|
884
1993
|
storedCount: options.read.fields.filter((field) => field.storedSourceLayer !== undefined).length,
|
|
885
1994
|
};
|
|
886
1995
|
}
|
|
1996
|
+
export function configValuesEqual(left, right) {
|
|
1997
|
+
return left !== undefined && right !== undefined
|
|
1998
|
+
&& stablePluginConfigStringify(left) === stablePluginConfigStringify(right);
|
|
1999
|
+
}
|
|
887
2000
|
//# sourceMappingURL=model.js.map
|