@lesliechan721/aw 0.1.0-beta.7 → 0.1.0-beta.9
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/scripts/add-skill.mjs +4 -4
- package/dist/authoring/scripts/add-skill.mjs.map +1 -1
- package/dist/authoring/scripts/init-plugin.mjs +8 -37
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +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 +2 -1
- package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +64 -758
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
- package/dist/scripts/{plugin-eval-materializer.js → aw-skill-eval-materializer.js} +34 -145
- 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 +2 -1
- package/dist/scripts/bundle-plugins.js.map +1 -1
- package/dist/scripts/plugin-staging.d.ts +6 -8
- package/dist/scripts/plugin-staging.js +15 -28
- package/dist/scripts/plugin-staging.js.map +1 -1
- package/dist/scripts/test-plugin-scripts.js +2 -33
- package/dist/scripts/test-plugin-scripts.js.map +1 -1
- 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 +254 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -0
- package/dist/src/commands/catalog-dev-source.d.ts +118 -0
- package/dist/src/commands/catalog-dev-source.js +417 -0
- package/dist/src/commands/catalog-dev-source.js.map +1 -0
- package/dist/src/commands/catalog-generation.d.ts +13 -0
- package/dist/src/commands/catalog-generation.js +13 -0
- package/dist/src/commands/catalog-generation.js.map +1 -0
- package/dist/src/commands/catalog-publication-inspection.d.ts +29 -28
- package/dist/src/commands/catalog-publication-inspection.js +138 -50
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
- package/dist/src/commands/catalog-publication-journal.d.ts +49 -0
- package/dist/src/commands/catalog-publication-journal.js +147 -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 +58 -15
- package/dist/src/commands/catalog-publish.js +590 -210
- package/dist/src/commands/catalog-publish.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +12 -15
- package/dist/src/commands/catalog-source.js +61 -86
- 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-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/dependency-operation-plan.d.ts +88 -9
- package/dist/src/commands/dependency-operation-plan.js +331 -6
- 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 +43 -0
- package/dist/src/commands/offline-cleanup-evidence.js +116 -0
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
- package/dist/src/commands/options.d.ts +7 -1
- package/dist/src/commands/options.js +65 -6
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +5 -1
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +27 -13
- package/dist/src/commands/rebuild-command.js +1472 -471
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +63 -8
- package/dist/src/commands/rebuild-integration.js +761 -439
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +2 -8
- package/dist/src/commands/rebuild-operations.js +48 -132
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/commands/runtime.js +21 -34
- package/dist/src/commands/runtime.js.map +1 -1
- package/dist/src/commands/skill-eval.d.ts +33 -0
- package/dist/src/commands/skill-eval.js +363 -0
- package/dist/src/commands/skill-eval.js.map +1 -0
- package/dist/src/commands/status-v6.d.ts +202 -0
- package/dist/src/commands/status-v6.js +1938 -0
- package/dist/src/commands/status-v6.js.map +1 -0
- package/dist/src/commands/sync-command.d.ts +21 -0
- package/dist/src/commands/sync-command.js +206 -0
- package/dist/src/commands/sync-command.js.map +1 -0
- package/dist/src/commands/wizard.d.ts +2 -2
- package/dist/src/commands/wizard.js +2 -2
- package/dist/src/commands/wizard.js.map +1 -1
- package/dist/src/commands/write-commands.js +33 -19
- 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 +66 -0
- package/dist/src/eval/manifest-v1.js +326 -0
- package/dist/src/eval/manifest-v1.js.map +1 -0
- package/dist/src/generators/local-plugin.d.ts +3 -0
- package/dist/src/generators/local-plugin.js +167 -45
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.d.ts +6 -1
- package/dist/src/index.js +863 -126
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.d.ts +58 -8
- package/dist/src/output/command-receipt.js +141 -11
- 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 +0 -3
- package/dist/src/output/rebuild-progress.js.map +1 -1
- package/dist/src/portable/commands.d.ts +6 -2
- package/dist/src/portable/commands.js +57 -6
- package/dist/src/portable/commands.js.map +1 -1
- package/dist/src/portable/materializer.d.ts +4 -4
- package/dist/src/portable/materializer.js +61 -12
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/tui/catalog-generation.d.ts +35 -0
- package/dist/src/tui/catalog-generation.js +85 -0
- package/dist/src/tui/catalog-generation.js.map +1 -0
- package/dist/src/tui/components.js +1 -2
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/console-app-v4.d.ts +1 -1
- package/dist/src/tui/console-app-v4.js +647 -196
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.d.ts +6 -2
- package/dist/src/tui/controller-runtime.js +646 -137
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +77 -15
- package/dist/src/tui/controller.js +647 -306
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/diagnostics.d.ts +1 -2
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/index.d.ts +1 -0
- package/dist/src/tui/index.js +1 -0
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/input-display.d.ts +8 -0
- package/dist/src/tui/input-display.js +36 -0
- package/dist/src/tui/input-display.js.map +1 -0
- package/dist/src/tui/model.d.ts +102 -14
- package/dist/src/tui/model.js +630 -139
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/router.d.ts +35 -0
- package/dist/src/tui/router.js.map +1 -1
- 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/views.js +31 -3
- package/dist/src/tui/views.js.map +1 -1
- package/dist/src/types.d.ts +104 -13
- 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/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 +8 -6
- package/dist/src/utils/bundle-layout.js.map +1 -1
- package/dist/src/utils/catalog-digests.d.ts +7 -0
- package/dist/src/utils/catalog-digests.js +40 -2
- 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 +13 -0
- package/dist/src/utils/catalog-generation-error.js +28 -0
- package/dist/src/utils/catalog-generation-error.js.map +1 -0
- package/dist/src/utils/catalog-generation-resolver.d.ts +20 -0
- package/dist/src/utils/catalog-generation-resolver.js +143 -0
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
- package/dist/src/utils/catalog-generation-service.d.ts +43 -0
- package/dist/src/utils/catalog-generation-service.js +306 -0
- package/dist/src/utils/catalog-generation-service.js.map +1 -0
- package/dist/src/utils/catalog-generation-state.d.ts +17 -0
- package/dist/src/utils/catalog-generation-state.js +168 -0
- package/dist/src/utils/catalog-generation-state.js.map +1 -0
- package/dist/src/utils/catalog-generation-store.d.ts +34 -0
- package/dist/src/utils/catalog-generation-store.js +251 -0
- package/dist/src/utils/catalog-generation-store.js.map +1 -0
- package/dist/src/utils/catalog-manifest-v6.d.ts +5 -0
- package/dist/src/utils/{catalog-manifest-v4.js → catalog-manifest-v6.js} +35 -43
- package/dist/src/utils/catalog-manifest-v6.js.map +1 -0
- package/dist/src/utils/catalog-operation-context.d.ts +20 -0
- package/dist/src/utils/catalog-operation-context.js +141 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -0
- package/dist/src/utils/catalog-public-error.d.ts +7 -3
- package/dist/src/utils/catalog-public-error.js +21 -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-references.d.ts +7 -0
- package/dist/src/utils/catalog-source-references.js +44 -55
- package/dist/src/utils/catalog-source-references.js.map +1 -1
- package/dist/src/utils/catalog-sources.d.ts +1 -0
- package/dist/src/utils/catalog-sources.js +55 -20
- 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 +81 -0
- package/dist/src/utils/codex-manager.js +810 -0
- package/dist/src/utils/codex-manager.js.map +1 -0
- package/dist/src/utils/codex-reconciler.d.ts +131 -0
- package/dist/src/utils/codex-reconciler.js +327 -0
- package/dist/src/utils/codex-reconciler.js.map +1 -0
- package/dist/src/utils/codex-shared-native.d.ts +56 -0
- package/dist/src/utils/codex-shared-native.js +87 -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 +44 -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.js +66 -140
- package/dist/src/utils/git-catalog-provider.js.map +1 -1
- package/dist/src/utils/lifecycle-active-store.d.ts +0 -28
- package/dist/src/utils/lifecycle-active-store.js +35 -247
- package/dist/src/utils/lifecycle-active-store.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 +53 -110
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +49 -6
- package/dist/src/utils/native-cli.js +116 -33
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/orphan-marketplace-cleanup.js +1 -3
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
- package/dist/src/utils/ownership.d.ts +10 -11
- package/dist/src/utils/ownership.js +55 -112
- 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 +52 -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-write.js +18 -40
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +1 -12
- package/dist/src/utils/plugin-config.js +107 -226
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/dist/src/utils/plugin-intent-state.d.ts +39 -0
- package/dist/src/utils/plugin-intent-state.js +325 -0
- package/dist/src/utils/plugin-intent-state.js.map +1 -0
- package/dist/src/utils/plugin-scripts.d.ts +1 -1
- package/dist/src/utils/plugin-scripts.js +1 -1
- package/dist/src/utils/plugin-scripts.js.map +1 -1
- 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 +9 -5
- package/dist/src/utils/target-eligibility.js.map +1 -1
- package/package.json +6 -4
- 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.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/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
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Box, Text, useInput, useWindowSize } from 'ink';
|
|
3
3
|
import { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { CATALOG_BETA_REF, CATALOG_LATEST_REF, OFFICIAL_CATALOG_SOURCE_SSH_URL, OFFICIAL_CATALOG_SOURCE_URL, } from '../constants.js';
|
|
5
6
|
import { CATALOG_SOURCE_ID_PATTERN } from '../utils/catalog-sources.js';
|
|
6
7
|
import { canonicalizeCatalogGitUrl } from '../utils/catalog-source-identity.js';
|
|
7
8
|
import { normalizePortableAgents } from '../portable/commands.js';
|
|
@@ -10,6 +11,8 @@ import { ActionRow, Callout, ChoiceRow, DiagnosticSummary, InputCard, PluginList
|
|
|
10
11
|
import { safeDiagnosticCode, sanitizeDiagnosticText, } from './diagnostics.js';
|
|
11
12
|
import { extractPortableError, userIssueKey } from './controller.js';
|
|
12
13
|
import { resolveTuiSizePolicy } from './layout.js';
|
|
14
|
+
import { InputDisplay, removeLastGrapheme } from './input-display.js';
|
|
15
|
+
import { catalogRefPolicyForPreset } from './source-ref-presets.js';
|
|
13
16
|
import { buildPlatformActions, buildPluginDetailActions, buildPluginPreviewActions, hasInstalledPlacement, } from './model.js';
|
|
14
17
|
import { tuiTheme } from './theme.js';
|
|
15
18
|
import { contentRowBudget, rowViewport } from './viewport.js';
|
|
@@ -26,11 +29,16 @@ export const CONSOLE_V4_SCREEN_IDS = [
|
|
|
26
29
|
'D01', 'D02', 'D03', 'D04', 'D05', 'D06', 'D07', 'D08', 'D09',
|
|
27
30
|
'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17',
|
|
28
31
|
'U01', 'U02', 'U03', 'U04', 'U05', 'U06', 'U07', 'U08', 'U09', 'U10', 'U11',
|
|
32
|
+
'K01', 'K02', 'K03', 'K04', 'K05', 'K06', 'K07',
|
|
29
33
|
];
|
|
30
34
|
function pluginMenuActionId(action) {
|
|
31
35
|
return action.id === 'platform' || action.id === 'scopeConflict'
|
|
32
36
|
? `${action.id}:${action.platform}`
|
|
33
|
-
: action.id
|
|
37
|
+
: action.id === 'addScope'
|
|
38
|
+
? `${action.id}:${action.platform}:${action.scope}`
|
|
39
|
+
: action.id === 'resolveScopeConflict'
|
|
40
|
+
? `${action.id}:${action.pluginId}:${action.platform}:${action.scope}`
|
|
41
|
+
: action.id;
|
|
34
42
|
}
|
|
35
43
|
function isCharacterInputMode(route, searchMode) {
|
|
36
44
|
return searchMode
|
|
@@ -118,13 +126,36 @@ function pluginPlacementSummary(plugin) {
|
|
|
118
126
|
const placement = plugin.installedPlacements.find((entry) => entry.platform === platform);
|
|
119
127
|
if (!placement || placement.state === 'notInstalled')
|
|
120
128
|
return `${label} · 未添加`;
|
|
129
|
+
if (placement.state === 'blocked')
|
|
130
|
+
return `${label} · 无法添加 · 输出冲突`;
|
|
121
131
|
if (placement.state === 'scopeConflict')
|
|
122
132
|
return `${label} · 位置冲突`;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
if (placement.blockingReason === 'artifactCollision') {
|
|
134
|
+
return `${label} · ${scopeLabel(placement.scope)} · 输出冲突`;
|
|
135
|
+
}
|
|
136
|
+
const health = placement.actualState === 'needsSync' ? '需要同步'
|
|
137
|
+
: placement.actualState === 'drifted' ? '已漂移'
|
|
138
|
+
: placement.actualState === 'conflict' ? '位置冲突'
|
|
139
|
+
: placement.health === 'ready' ? '可用'
|
|
140
|
+
: placement.health === 'incomplete' ? '需要处理' : '不可用';
|
|
141
|
+
const desired = placement.desiredScopes?.length
|
|
142
|
+
? placement.desiredScopes.map(scopeLabel).join('+')
|
|
143
|
+
: scopeLabel(placement.scope);
|
|
144
|
+
return `${label} · ${desired} · ${health}`;
|
|
126
145
|
}).join(' | ') || '没有可用平台';
|
|
127
146
|
}
|
|
147
|
+
function issueGroupLabel(group) {
|
|
148
|
+
return {
|
|
149
|
+
sourceRemoved: '来源已移除',
|
|
150
|
+
artifactCollision: '输出冲突',
|
|
151
|
+
sourceUnavailable: '来源不可用',
|
|
152
|
+
dependency: '依赖',
|
|
153
|
+
scope: '位置',
|
|
154
|
+
config: '设置',
|
|
155
|
+
installation: '安装',
|
|
156
|
+
diagnostic: '诊断',
|
|
157
|
+
}[group];
|
|
158
|
+
}
|
|
128
159
|
function pluginRowStatus(plugin) {
|
|
129
160
|
if (plugin.aggregateStatus === 'needsAttention')
|
|
130
161
|
return 'warning';
|
|
@@ -305,38 +336,38 @@ function configUnavailableDiagnostic(route) {
|
|
|
305
336
|
},
|
|
306
337
|
};
|
|
307
338
|
}
|
|
308
|
-
function sourceDiagnostic(sourceId, state, detail) {
|
|
309
|
-
const degraded = state === 'degraded';
|
|
339
|
+
function sourceDiagnostic(sourceId, state, detail, generation) {
|
|
310
340
|
const unavailable = state === 'unavailable' || state === 'error';
|
|
311
|
-
if (!
|
|
341
|
+
if (!unavailable)
|
|
312
342
|
return undefined;
|
|
343
|
+
const metadataInvalid = generation?.errorCode === 'catalogGenerationMetadataInvalid';
|
|
313
344
|
return {
|
|
314
|
-
severity:
|
|
315
|
-
title:
|
|
316
|
-
userMessage:
|
|
317
|
-
|
|
318
|
-
: '
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
]
|
|
324
|
-
: [
|
|
325
|
-
{ state: 'blocked', message: '当前不能浏览或安装这个来源中的插件。' },
|
|
326
|
-
{ state: 'preserved', message: '已安装插件和已保存设置不会被删除。' },
|
|
327
|
-
],
|
|
328
|
-
nextStep: degraded
|
|
329
|
-
? '重新检查来源;在修复前也可以继续使用匹配缓存。'
|
|
345
|
+
severity: 'error',
|
|
346
|
+
title: 'Catalog 来源不可用',
|
|
347
|
+
userMessage: '当前无法读取这个来源。',
|
|
348
|
+
impact: [
|
|
349
|
+
{ state: 'blocked', message: '当前不能浏览或安装这个来源中的插件。' },
|
|
350
|
+
{ state: 'preserved', message: '已安装插件和已保存设置不会被删除。' },
|
|
351
|
+
],
|
|
352
|
+
nextStep: metadataInvalid && generation.recoveryEntryPath
|
|
353
|
+
? `先安全删除 AW_HOME 下的精确条目 ${generation.recoveryEntryPath},再运行 ${generation.syncInstruction}。`
|
|
330
354
|
: '重新检查来源;如仍失败,请编辑来源 URL、路径或 ref。',
|
|
331
355
|
technical: {
|
|
332
|
-
code: safeDiagnosticCode(detail?.errorCode,
|
|
356
|
+
code: safeDiagnosticCode(generation?.errorCode ?? detail?.errorCode, 'catalogSourceUnavailable'),
|
|
333
357
|
stage: 'resolve-source',
|
|
334
358
|
sourceId,
|
|
335
359
|
...(detail?.requestedRef ? { requestedRef: detail.requestedRef } : {}),
|
|
336
360
|
...(detail?.resolvedCommit ? { resolvedCommit: detail.resolvedCommit } : {}),
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
361
|
+
...(metadataInvalid && generation.recoveryEntryPath
|
|
362
|
+
? { context: [{ key: 'storeEntry', value: generation.recoveryEntryPath }] }
|
|
363
|
+
: {}),
|
|
364
|
+
checks: metadataInvalid && generation.recoveryEntryPath
|
|
365
|
+
? [
|
|
366
|
+
`确认损坏条目为 AW_HOME/${generation.recoveryEntryPath}。`,
|
|
367
|
+
'只删除该精确条目,不删除 Catalog store 根或其它 digest。',
|
|
368
|
+
`运行 ${generation.syncInstruction} 重建 Active。`,
|
|
369
|
+
]
|
|
370
|
+
: ['检查 Git URL、ref 或本地目录。', '确认当前终端具备来源授权。', '运行“重新检查来源”验证修复。'],
|
|
340
371
|
},
|
|
341
372
|
};
|
|
342
373
|
}
|
|
@@ -407,7 +438,7 @@ function SourceTabs(props) {
|
|
|
407
438
|
const state = 'state' in tab ? tab.state : 'ready';
|
|
408
439
|
return (_jsxs(Text, { bold: active, color: active ? tuiTheme.colors.accent
|
|
409
440
|
: state === 'error' ? tuiTheme.statusColors.error
|
|
410
|
-
:
|
|
441
|
+
: tuiTheme.colors.muted, children: [active ? '[' : '', tab.label, state === 'error' ? ' !' : ` ${tab.count ?? ''}`, active ? ']' : '', ' '] }, tab.id));
|
|
411
442
|
})] }));
|
|
412
443
|
}
|
|
413
444
|
function configTabs(page) {
|
|
@@ -439,13 +470,22 @@ function placementStatus(placement) {
|
|
|
439
470
|
if (placement.state === 'notInstalled') {
|
|
440
471
|
return { value: '未添加', status: 'muted', description: '选择使用位置后添加' };
|
|
441
472
|
}
|
|
473
|
+
if (placement.state === 'blocked') {
|
|
474
|
+
return { value: '无法添加', status: 'error', description: '输出冲突;不会覆盖或删除占用内容' };
|
|
475
|
+
}
|
|
442
476
|
if (placement.state === 'scopeConflict') {
|
|
443
477
|
return { value: '位置冲突', status: 'warning', description: '需要先处理两个安装位置' };
|
|
444
478
|
}
|
|
479
|
+
if (placement.blockingReason === 'artifactCollision') {
|
|
480
|
+
return { value: '输出冲突', status: 'error', description: '只允许查看或安全移除受管内容' };
|
|
481
|
+
}
|
|
445
482
|
return {
|
|
446
|
-
value: `${scopeLabel(placement.scope)} · ${placement.health === 'ready' ? '可用' : placement.health === 'incomplete' ? '需要处理' : '不可用'}`,
|
|
447
|
-
status: placement.health === 'ready' ? 'success' : placement.health === 'incomplete' ? 'warning' : 'error',
|
|
448
|
-
description: placement.
|
|
483
|
+
value: `${placement.desiredScopes?.map(scopeLabel).join('+') || scopeLabel(placement.scope)} · ${placement.actualState === 'needsSync' ? '需要同步' : placement.actualState === 'drifted' ? '已漂移' : placement.actualState === 'conflict' ? '位置冲突' : placement.health === 'ready' ? '可用' : placement.health === 'incomplete' ? '需要处理' : '不可用'}`,
|
|
484
|
+
status: placement.actualState === 'conflict' ? 'error' : placement.health === 'ready' ? 'success' : placement.health === 'incomplete' ? 'warning' : 'error',
|
|
485
|
+
description: placement.actualState === 'needsSync' ? 'desired intent 与现场不同;可安全同步'
|
|
486
|
+
: placement.actualState === 'drifted' ? '现场已漂移;查看同步计划'
|
|
487
|
+
: placement.actualState === 'conflict' ? 'mixed 或 AW-only 重叠;查看恢复路径'
|
|
488
|
+
: placement.health === 'ready' ? '当前检查正常' : '查看影响和建议操作',
|
|
449
489
|
};
|
|
450
490
|
}
|
|
451
491
|
function dependencyStatus(item) {
|
|
@@ -459,9 +499,29 @@ function dependencyStatus(item) {
|
|
|
459
499
|
}
|
|
460
500
|
function dependencyPlacementLabel(item) {
|
|
461
501
|
const aggregate = dependencyStatus(item);
|
|
502
|
+
const installed = item.placements.filter((entry) => entry.state === 'installed');
|
|
503
|
+
const modern = installed.filter((entry) => entry.state === 'installed'
|
|
504
|
+
&& (entry.desiredScopes !== undefined || entry.actualState !== undefined));
|
|
505
|
+
if (modern.length > 0) {
|
|
506
|
+
return modern.map((entry) => {
|
|
507
|
+
if (entry.state !== 'installed')
|
|
508
|
+
return '';
|
|
509
|
+
const desired = entry.desiredScopes?.map(scopeLabel).join('+') || scopeLabel(entry.scope);
|
|
510
|
+
const actualScopes = [
|
|
511
|
+
...(entry.activation?.user ? ['所有项目'] : []),
|
|
512
|
+
...(entry.activation?.project ? ['当前项目'] : []),
|
|
513
|
+
];
|
|
514
|
+
const actual = actualScopes.join('+') || scopeLabel(entry.scope);
|
|
515
|
+
const state = entry.actualState === 'needsSync' ? '需同步'
|
|
516
|
+
: entry.actualState === 'drifted' ? '已漂移'
|
|
517
|
+
: entry.actualState === 'conflict' ? '冲突'
|
|
518
|
+
: entry.actualState === 'ready' ? '可用' : aggregate.value;
|
|
519
|
+
return `${platformLabel(entry.platform)} · desired ${desired} · actual ${actual} · ${state}`;
|
|
520
|
+
}).join(' | ');
|
|
521
|
+
}
|
|
462
522
|
if (item.aggregateStatus !== 'ready')
|
|
463
523
|
return aggregate.value;
|
|
464
|
-
const ready =
|
|
524
|
+
const ready = installed.filter((entry) => entry.state === 'installed' && entry.health === 'ready');
|
|
465
525
|
const scopes = new Set(ready.map((entry) => entry.state === 'installed' ? entry.scope : undefined));
|
|
466
526
|
return scopes.size === 1 && ready[0]?.state === 'installed'
|
|
467
527
|
? `${scopeLabel(ready[0].scope)} · ${aggregate.value}`
|
|
@@ -551,6 +611,10 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
551
611
|
return 'D16';
|
|
552
612
|
return controller.getPluginOverview(route.pluginId)?.dependencySummary?.totalCount ? 'D04' : 'P06';
|
|
553
613
|
}
|
|
614
|
+
if (route.name === 'dependencyPlacement')
|
|
615
|
+
return 'D03';
|
|
616
|
+
if (route.name === 'dependencyPlacementEditor')
|
|
617
|
+
return 'D04';
|
|
554
618
|
if (route.name === 'pluginDetail') {
|
|
555
619
|
return controller.getPluginOverview(route.pluginId)?.dependencySummary?.totalCount ? 'D09' : 'P13';
|
|
556
620
|
}
|
|
@@ -567,8 +631,11 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
567
631
|
}
|
|
568
632
|
if (route.name === 'reviewPreparing')
|
|
569
633
|
return 'P07';
|
|
634
|
+
if (route.name === 'review' && snapshot.activeReview?.originIssue)
|
|
635
|
+
return 'I10';
|
|
570
636
|
const dependencyOperation = snapshot.activeReview?.operationKind === 'pluginWrite'
|
|
571
|
-
&& Boolean(snapshot.activeReview.changes.some((change) => change.
|
|
637
|
+
&& Boolean(snapshot.activeReview.changes.some((change) => change.relation === 'direct' || change.relation === 'transitive'
|
|
638
|
+
|| change.group === 'dependencies'));
|
|
572
639
|
if (route.name === 'review' && dependencyOperation) {
|
|
573
640
|
return snapshot.activeReview?.pluginAction === 'uninstall' || snapshot.activeReview?.pluginAction === 'cleanup'
|
|
574
641
|
? 'D11' : 'D05';
|
|
@@ -584,8 +651,6 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
584
651
|
return snapshot.result.state === 'succeeded' ? 'D07' : 'D08';
|
|
585
652
|
}
|
|
586
653
|
}
|
|
587
|
-
if (route.name === 'review' && snapshot.activeReview?.originIssue)
|
|
588
|
-
return 'I10';
|
|
589
654
|
if (route.name === 'progress' && snapshot.activeReview?.originIssue)
|
|
590
655
|
return 'I11';
|
|
591
656
|
if (route.name === 'result' && snapshot.result?.originIssue) {
|
|
@@ -630,6 +695,8 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
630
695
|
return 'C01';
|
|
631
696
|
if (route.name === 'configFields')
|
|
632
697
|
return route.layer.scope === 'effective' ? 'C02' : 'C03';
|
|
698
|
+
if (route.name === 'configFieldAction')
|
|
699
|
+
return 'C04';
|
|
633
700
|
if (route.name === 'configFieldEditor')
|
|
634
701
|
return {
|
|
635
702
|
enum: 'C05', boolean: 'C06', number: 'C07', string: 'C08', path: 'C09', sensitive: 'C10',
|
|
@@ -639,7 +706,7 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
639
706
|
if (route.name === 'sourceList')
|
|
640
707
|
return 'S01';
|
|
641
708
|
if (route.name === 'sourceDetail')
|
|
642
|
-
return '
|
|
709
|
+
return 'K02';
|
|
643
710
|
if (route.name === 'sourceTechnical')
|
|
644
711
|
return 'S03';
|
|
645
712
|
if (route.name === 'sourceAdd')
|
|
@@ -658,7 +725,7 @@ export function resolveConsoleV4ScreenId(snapshot, controller, overlay, tooSmall
|
|
|
658
725
|
const category = controller.listUserIssues().find((issue) => issue.issueId === route.issueId)?.category;
|
|
659
726
|
return {
|
|
660
727
|
incompleteInstallation: 'I03',
|
|
661
|
-
|
|
728
|
+
artifactCollision: 'I09',
|
|
662
729
|
sourceUnavailable: 'I04',
|
|
663
730
|
sourceMissing: 'I05',
|
|
664
731
|
sourceIdentityChanged: 'I06',
|
|
@@ -685,7 +752,7 @@ export function ConsoleAppV4(props) {
|
|
|
685
752
|
const [discardForExit, setDiscardForExit] = useState(false);
|
|
686
753
|
const [focus, setFocus] = useState(0);
|
|
687
754
|
const [scrollOffset, setScrollOffset] = useState(0);
|
|
688
|
-
const [
|
|
755
|
+
const [searchFocus, setSearchFocus] = useState(false);
|
|
689
756
|
const [query, setQuery] = useState('');
|
|
690
757
|
const [installFilter, setInstallFilter] = useState(props.controller.snapshot.router.current.context.installFilter ?? 'all');
|
|
691
758
|
const [scope, setScope] = useState('user');
|
|
@@ -699,7 +766,6 @@ export function ConsoleAppV4(props) {
|
|
|
699
766
|
const [dirty, setDirty] = useState(false);
|
|
700
767
|
const [configPage, setConfigPage] = useState();
|
|
701
768
|
const [configLayerCounts, setConfigLayerCounts] = useState({});
|
|
702
|
-
const [configLoadKey, setConfigLoadKey] = useState(0);
|
|
703
769
|
const [draftUpdates, setDraftUpdates] = useState({});
|
|
704
770
|
const [draftRemoves, setDraftRemoves] = useState([]);
|
|
705
771
|
const [inputValue, setInputValue] = useState('');
|
|
@@ -714,6 +780,8 @@ export function ConsoleAppV4(props) {
|
|
|
714
780
|
const [portableAgentInput, setPortableAgentInput] = useState('');
|
|
715
781
|
const [draftOwner, setDraftOwner] = useState();
|
|
716
782
|
const [pendingPresetId, setPendingPresetId] = useState();
|
|
783
|
+
const [pendingLayerFieldKey, setPendingLayerFieldKey] = useState();
|
|
784
|
+
const [confirmedSharedReviewToken, setConfirmedSharedReviewToken] = useState();
|
|
717
785
|
const dynamicMenuFocus = useRef(undefined);
|
|
718
786
|
const exitSent = useRef(false);
|
|
719
787
|
const operationBusy = useRef(false);
|
|
@@ -804,6 +872,7 @@ export function ConsoleAppV4(props) {
|
|
|
804
872
|
}, [route.name]);
|
|
805
873
|
const configRoute = route.name === 'configFields'
|
|
806
874
|
|| route.name === 'configFieldEditor'
|
|
875
|
+
|| route.name === 'configFieldAction'
|
|
807
876
|
? route
|
|
808
877
|
: undefined;
|
|
809
878
|
const currentConfigPage = configPageMatches(configPage, configRoute) ? configPage : undefined;
|
|
@@ -867,7 +936,7 @@ export function ConsoleAppV4(props) {
|
|
|
867
936
|
}
|
|
868
937
|
});
|
|
869
938
|
return () => abort.abort();
|
|
870
|
-
}, [
|
|
939
|
+
}, [configRoute?.pluginId, configRoute?.layer.scope, configRoute?.layer.projectLayer, props.controller]);
|
|
871
940
|
useEffect(() => {
|
|
872
941
|
if (route.name !== 'configFields' || !currentConfigPage)
|
|
873
942
|
return;
|
|
@@ -910,7 +979,7 @@ export function ConsoleAppV4(props) {
|
|
|
910
979
|
route.name === 'pluginList' ? route.sourceId : '',
|
|
911
980
|
snapshot.viewModel,
|
|
912
981
|
]);
|
|
913
|
-
const activeField = route.name === 'configFieldEditor'
|
|
982
|
+
const activeField = route.name === 'configFieldEditor' || route.name === 'configFieldAction'
|
|
914
983
|
? currentConfigPage?.groups.flatMap((group) => group.fields).find((field) => field.key === route.fieldKey)
|
|
915
984
|
: undefined;
|
|
916
985
|
useEffect(() => {
|
|
@@ -945,7 +1014,7 @@ export function ConsoleAppV4(props) {
|
|
|
945
1014
|
setSourceReferenceSummary({ blocked: true, inventoryComplete: false, dependencies: [] }); });
|
|
946
1015
|
return () => abort.abort();
|
|
947
1016
|
}, [props.controller, route.name, route.name === 'sourceRemoveBlocked' ? route.sourceId : '']);
|
|
948
|
-
const screenId = resolveConsoleV4ScreenId(snapshot, props.controller, overlay, tooSmall,
|
|
1017
|
+
const screenId = resolveConsoleV4ScreenId(snapshot, props.controller, overlay, tooSmall, searchFocus);
|
|
949
1018
|
const portableVariantCandidates = route.name === 'portableSkillSelect' && snapshot.portableDraft
|
|
950
1019
|
? snapshot.portableDraft.candidates.filter(portableScopeVariantsDiffer)
|
|
951
1020
|
: [];
|
|
@@ -962,19 +1031,12 @@ export function ConsoleAppV4(props) {
|
|
|
962
1031
|
|| Boolean(route.name === 'result' && snapshot.result && 'operationKind' in snapshot.result
|
|
963
1032
|
&& snapshot.result.operationKind === 'portableInstall');
|
|
964
1033
|
const canOpenHelp = !tooSmall
|
|
965
|
-
&& !isCharacterInputMode(route,
|
|
1034
|
+
&& !isCharacterInputMode(route, searchFocus)
|
|
966
1035
|
&& !(route.name === 'installTargets' && route.view !== 'blocked');
|
|
967
1036
|
useEffect(() => {
|
|
968
1037
|
props.onScreenChange?.(screenId);
|
|
969
1038
|
}, [props.onScreenChange, screenId]);
|
|
970
1039
|
const dependencyOverview = (candidate) => candidate ? props.controller.getPluginDependencyOverview(candidate.pluginId) : undefined;
|
|
971
|
-
const installIntent = (candidate, targets = selectedTargets) => ({
|
|
972
|
-
kind: 'pluginWrite',
|
|
973
|
-
action: 'install',
|
|
974
|
-
pluginId: candidate.pluginId,
|
|
975
|
-
platform: targets.length === 2 ? 'both' : targets[0],
|
|
976
|
-
scope,
|
|
977
|
-
});
|
|
978
1040
|
let title = '管理你的 Agent 工作流插件';
|
|
979
1041
|
let description = '为 Codex 和 Claude Code 添加、设置或移除开发能力。';
|
|
980
1042
|
let breadcrumb = '首页';
|
|
@@ -1012,6 +1074,7 @@ export function ConsoleAppV4(props) {
|
|
|
1012
1074
|
compact: policy.mode === 'compact',
|
|
1013
1075
|
staticRows,
|
|
1014
1076
|
});
|
|
1077
|
+
const dependencyPlacementStaticRows = policy.mode === 'compact' ? 3 : 10;
|
|
1015
1078
|
const responsiveBudget = (compactRows, standardRows) => {
|
|
1016
1079
|
const baseline = policy.mode === 'compact' ? 18 : 24;
|
|
1017
1080
|
const base = policy.mode === 'compact' ? compactRows : standardRows;
|
|
@@ -1022,7 +1085,7 @@ export function ConsoleAppV4(props) {
|
|
|
1022
1085
|
props.controller.push(next);
|
|
1023
1086
|
setFocus(0);
|
|
1024
1087
|
setScrollOffset(0);
|
|
1025
|
-
|
|
1088
|
+
setSearchFocus(false);
|
|
1026
1089
|
setShowTechnical(false);
|
|
1027
1090
|
setActionError(undefined);
|
|
1028
1091
|
};
|
|
@@ -1037,7 +1100,7 @@ export function ConsoleAppV4(props) {
|
|
|
1037
1100
|
props.controller.beginConfigFlow(pluginId);
|
|
1038
1101
|
setFocus(0);
|
|
1039
1102
|
setScrollOffset(0);
|
|
1040
|
-
|
|
1103
|
+
setSearchFocus(false);
|
|
1041
1104
|
setShowTechnical(false);
|
|
1042
1105
|
setActionError(undefined);
|
|
1043
1106
|
};
|
|
@@ -1051,7 +1114,7 @@ export function ConsoleAppV4(props) {
|
|
|
1051
1114
|
setScrollOffset(restored.scrollOffset ?? 0);
|
|
1052
1115
|
setQuery(restored.query ?? '');
|
|
1053
1116
|
setInstallFilter(restored.installFilter ?? 'all');
|
|
1054
|
-
|
|
1117
|
+
setSearchFocus(false);
|
|
1055
1118
|
setActionError(undefined);
|
|
1056
1119
|
};
|
|
1057
1120
|
const leaveResult = (target) => {
|
|
@@ -1061,7 +1124,7 @@ export function ConsoleAppV4(props) {
|
|
|
1061
1124
|
setScrollOffset(restored.scrollOffset ?? 0);
|
|
1062
1125
|
setQuery(restored.query ?? '');
|
|
1063
1126
|
setInstallFilter(restored.installFilter ?? 'all');
|
|
1064
|
-
|
|
1127
|
+
setSearchFocus(false);
|
|
1065
1128
|
setShowTechnical(false);
|
|
1066
1129
|
setActionError(undefined);
|
|
1067
1130
|
};
|
|
@@ -1080,6 +1143,18 @@ export function ConsoleAppV4(props) {
|
|
|
1080
1143
|
setFocus(0);
|
|
1081
1144
|
setScrollOffset(0);
|
|
1082
1145
|
};
|
|
1146
|
+
const continueInstallAfterTargets = async (candidate, targets) => {
|
|
1147
|
+
if (props.controller.snapshot.installPlacementDraft?.pluginId !== candidate.pluginId) {
|
|
1148
|
+
props.controller.beginInstallFlow(candidate.pluginId, scope);
|
|
1149
|
+
}
|
|
1150
|
+
props.controller.setInstallPlatforms(targets);
|
|
1151
|
+
const hasConfigurableDependencies = await props.controller.prepareInstallDependencyPlacement();
|
|
1152
|
+
if (hasConfigurableDependencies) {
|
|
1153
|
+
go({ name: 'dependencyPlacement', pluginId: candidate.pluginId });
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
beginReview(props.controller.installPlacementIntent());
|
|
1157
|
+
};
|
|
1083
1158
|
const beginPortable = async (pluginId) => {
|
|
1084
1159
|
try {
|
|
1085
1160
|
await props.controller.preparePortableInstall(pluginId, route.name === 'portableBlocker' ? 'replace' : 'push');
|
|
@@ -1148,6 +1223,24 @@ export function ConsoleAppV4(props) {
|
|
|
1148
1223
|
scope: selectedScope,
|
|
1149
1224
|
});
|
|
1150
1225
|
};
|
|
1226
|
+
const beginSecondScope = (candidate, platform, selectedScope) => {
|
|
1227
|
+
setScope(selectedScope);
|
|
1228
|
+
setSelectedTargets([]);
|
|
1229
|
+
setTargetSelections({});
|
|
1230
|
+
setPreferredTarget(platform);
|
|
1231
|
+
props.controller.beginInstallFlow(candidate.pluginId, selectedScope);
|
|
1232
|
+
go({ name: 'installPlacement', pluginId: candidate.pluginId });
|
|
1233
|
+
};
|
|
1234
|
+
const beginScopeConflictRecovery = (action) => {
|
|
1235
|
+
void beginReview({
|
|
1236
|
+
kind: 'pluginWrite',
|
|
1237
|
+
action: 'uninstall',
|
|
1238
|
+
pluginId: action.pluginId,
|
|
1239
|
+
platform: action.platform,
|
|
1240
|
+
scope: action.scope,
|
|
1241
|
+
recoveryDescription: action.description,
|
|
1242
|
+
});
|
|
1243
|
+
};
|
|
1151
1244
|
const beginAddSource = () => {
|
|
1152
1245
|
const owner = `source-add:${Date.now()}`;
|
|
1153
1246
|
setSourceDraft({ owner, mode: 'add', sourceId: '', type: 'git', location: '', refPolicy: 'cliChannel', ref: '', subdir: '' });
|
|
@@ -1183,6 +1276,9 @@ export function ConsoleAppV4(props) {
|
|
|
1183
1276
|
pluginId,
|
|
1184
1277
|
platform: selectedPlatform,
|
|
1185
1278
|
scope: selectedScope,
|
|
1279
|
+
...(selectedIssue.category === 'scopeConflict' && action.description
|
|
1280
|
+
? { recoveryDescription: action.description }
|
|
1281
|
+
: {}),
|
|
1186
1282
|
originIssue: {
|
|
1187
1283
|
issueId: selectedIssue.issueId,
|
|
1188
1284
|
issueKey: userIssueKey(selectedIssue),
|
|
@@ -1314,6 +1410,12 @@ export function ConsoleAppV4(props) {
|
|
|
1314
1410
|
return next;
|
|
1315
1411
|
});
|
|
1316
1412
|
};
|
|
1413
|
+
const cancelDraftRemoval = (key) => {
|
|
1414
|
+
const nextRemoves = draftRemoves.filter((candidate) => candidate !== key);
|
|
1415
|
+
setDraftRemoves(nextRemoves);
|
|
1416
|
+
setDirty(Object.keys(draftUpdates).length + nextRemoves.length > 0);
|
|
1417
|
+
setConfigActionError(undefined);
|
|
1418
|
+
};
|
|
1317
1419
|
const configFieldTarget = (page, key) => {
|
|
1318
1420
|
if (!key)
|
|
1319
1421
|
return undefined;
|
|
@@ -1384,15 +1486,8 @@ export function ConsoleAppV4(props) {
|
|
|
1384
1486
|
setScrollOffset(0);
|
|
1385
1487
|
return;
|
|
1386
1488
|
}
|
|
1387
|
-
if (field && route.fieldKey)
|
|
1388
|
-
|
|
1389
|
-
name: 'configFieldEditor',
|
|
1390
|
-
pluginId: route.pluginId,
|
|
1391
|
-
layer,
|
|
1392
|
-
fieldKey: route.fieldKey,
|
|
1393
|
-
editor: fieldEditor(field),
|
|
1394
|
-
});
|
|
1395
|
-
}
|
|
1489
|
+
if (field && route.fieldKey)
|
|
1490
|
+
setPendingLayerFieldKey(route.fieldKey);
|
|
1396
1491
|
setFocus(0);
|
|
1397
1492
|
setScrollOffset(0);
|
|
1398
1493
|
};
|
|
@@ -1405,7 +1500,9 @@ export function ConsoleAppV4(props) {
|
|
|
1405
1500
|
key,
|
|
1406
1501
|
title: field?.title ?? key,
|
|
1407
1502
|
before: field?.displayValue ?? '未设置',
|
|
1408
|
-
after: draftRemoves.includes(key)
|
|
1503
|
+
after: draftRemoves.includes(key)
|
|
1504
|
+
? `恢复继承(${field?.fallbackDisplayValue ?? '未设置'} · ${field?.fallbackSourceLabel ?? '未设置'})`
|
|
1505
|
+
: currentFieldDisplay(field),
|
|
1409
1506
|
};
|
|
1410
1507
|
});
|
|
1411
1508
|
};
|
|
@@ -1431,6 +1528,38 @@ export function ConsoleAppV4(props) {
|
|
|
1431
1528
|
setConfigActionError('设置值未通过验证。请重新检查修改。');
|
|
1432
1529
|
}
|
|
1433
1530
|
};
|
|
1531
|
+
useEffect(() => {
|
|
1532
|
+
if (!pendingLayerFieldKey || route.name !== 'configFields'
|
|
1533
|
+
|| route.layer.scope === 'effective' || !currentConfigPage)
|
|
1534
|
+
return;
|
|
1535
|
+
const field = currentConfigPage.groups.flatMap((group) => group.fields)
|
|
1536
|
+
.find((candidate) => candidate.key === pendingLayerFieldKey);
|
|
1537
|
+
setPendingLayerFieldKey(undefined);
|
|
1538
|
+
if (!field)
|
|
1539
|
+
return;
|
|
1540
|
+
const layer = { scope: route.layer.scope, projectLayer: route.layer.projectLayer };
|
|
1541
|
+
props.controller.push(field.configured ? {
|
|
1542
|
+
name: 'configFieldAction',
|
|
1543
|
+
pluginId: route.pluginId,
|
|
1544
|
+
layer,
|
|
1545
|
+
fieldKey: field.key,
|
|
1546
|
+
} : {
|
|
1547
|
+
name: 'configFieldEditor',
|
|
1548
|
+
pluginId: route.pluginId,
|
|
1549
|
+
layer,
|
|
1550
|
+
fieldKey: field.key,
|
|
1551
|
+
editor: fieldEditor(field),
|
|
1552
|
+
});
|
|
1553
|
+
}, [pendingLayerFieldKey, route.name, currentConfigPage]);
|
|
1554
|
+
useEffect(() => {
|
|
1555
|
+
if (!pendingLayerFieldKey)
|
|
1556
|
+
return;
|
|
1557
|
+
if (route.name === 'configFields' && route.layer.scope !== 'effective')
|
|
1558
|
+
return;
|
|
1559
|
+
if (route.name === 'configLayer')
|
|
1560
|
+
return;
|
|
1561
|
+
setPendingLayerFieldKey(undefined);
|
|
1562
|
+
}, [pendingLayerFieldKey, route.name]);
|
|
1434
1563
|
useEffect(() => {
|
|
1435
1564
|
if (!pendingPresetId || route.name !== 'configFields'
|
|
1436
1565
|
|| route.layer.scope === 'effective' || !currentConfigPage)
|
|
@@ -1469,7 +1598,7 @@ export function ConsoleAppV4(props) {
|
|
|
1469
1598
|
{ label: '需要处理', description: '解决安装、来源或设置问题', meta: String(home.issueCount), status: 'warning', run: () => go({ name: 'issueList' }) },
|
|
1470
1599
|
{ label: '插件来源', description: '管理 Git 仓库和本地目录', meta: String(home.sourceCount), run: () => go({ name: 'sourceList' }) },
|
|
1471
1600
|
];
|
|
1472
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(StatusCard, { status: home.issueCount > 0 || home.unavailableSourceCount > 0 ? 'warning' : 'success', title: "\u5F53\u524D\u72B6\u6001", children: [_jsx(ResultRow, { title: `${home.installedPlugins} 个插件可用`, status: "success" }), _jsx(ResultRow, { title: `${home.issueCount} 项需要处理`, status: home.issueCount > 0 ? 'warning' : 'muted' }), home.
|
|
1601
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(StatusCard, { status: home.issueCount > 0 || home.unavailableSourceCount > 0 ? 'warning' : 'success', title: "\u5F53\u524D\u72B6\u6001", children: [_jsx(ResultRow, { title: `${home.installedPlugins} 个插件可用`, status: "success" }), _jsx(ResultRow, { title: `${home.issueCount} 项需要处理`, status: home.issueCount > 0 ? 'warning' : 'muted' }), home.unavailableSourceCount > 0 ? _jsx(ResultRow, { title: `${home.unavailableSourceCount} 个来源不可用`, status: "error" }) : null] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "task", compact: policy.mode === 'compact' })] });
|
|
1473
1602
|
}
|
|
1474
1603
|
else if (route.name === 'pluginList') {
|
|
1475
1604
|
const sourceId = route.sourceId ?? 'all';
|
|
@@ -1479,6 +1608,12 @@ export function ConsoleAppV4(props) {
|
|
|
1479
1608
|
...(query ? { query } : {}),
|
|
1480
1609
|
installFilter,
|
|
1481
1610
|
});
|
|
1611
|
+
const uninstalledCount = props.controller.listPlugins({
|
|
1612
|
+
mode: route.mode,
|
|
1613
|
+
...(sourceId !== 'all' ? { sourceId } : {}),
|
|
1614
|
+
...(query ? { query } : {}),
|
|
1615
|
+
installFilter: 'uninstalled',
|
|
1616
|
+
}).length;
|
|
1482
1617
|
breadcrumb = route.mode === 'browse' ? '添加插件' : '我的插件';
|
|
1483
1618
|
title = breadcrumb;
|
|
1484
1619
|
description = route.mode === 'browse' ? '选择希望 Agent 获得的能力。' : '查看状态,或选择一个插件进行管理。';
|
|
@@ -1486,13 +1621,15 @@ export function ConsoleAppV4(props) {
|
|
|
1486
1621
|
help = `↑↓ 移动 · Enter 查看 · ←→ 来源 · / 搜索${route.mode === 'browse' ? ' · f 未安装' : ''} · Esc 返回`;
|
|
1487
1622
|
const sourceError = sourceId !== 'all' && props.controller.getSourceOverview(sourceId).source?.state === 'error';
|
|
1488
1623
|
actions = sourceError
|
|
1489
|
-
? [{ label: '查看来源问题', description: '
|
|
1624
|
+
? [{ label: '查看来源问题', description: '当前不能浏览这个来源', run: () => go({ name: 'issueDetail', issueId: `source:${sourceId}:unavailable` }) }]
|
|
1490
1625
|
: [];
|
|
1491
1626
|
pluginRows = sourceError ? [] : items.map((item) => ({
|
|
1492
1627
|
pluginId: item.pluginId,
|
|
1493
1628
|
name: item.displayName,
|
|
1494
1629
|
sourceLabel: item.sourceLabel,
|
|
1495
|
-
description: item.
|
|
1630
|
+
description: item.primaryAttention
|
|
1631
|
+
? `${item.primaryAttention.code} · ${item.primaryAttention.message}`
|
|
1632
|
+
: item.description,
|
|
1496
1633
|
placementSummary: pluginPlacementSummary(item),
|
|
1497
1634
|
statusLabel: statusText(item),
|
|
1498
1635
|
status: pluginRowStatus(item),
|
|
@@ -1505,7 +1642,9 @@ export function ConsoleAppV4(props) {
|
|
|
1505
1642
|
else if (route.mode === 'browse' && items.length === 0 && !sourceError) {
|
|
1506
1643
|
actions = [{
|
|
1507
1644
|
label: '没有匹配插件',
|
|
1508
|
-
description: installFilter === 'uninstalled'
|
|
1645
|
+
description: installFilter === 'uninstalled'
|
|
1646
|
+
? '当前来源和搜索条件下没有未安装插件;按 f 查看全部,或按 / 编辑搜索'
|
|
1647
|
+
: '按 / 编辑搜索,或切换来源',
|
|
1509
1648
|
disabled: '没有可打开的插件',
|
|
1510
1649
|
}];
|
|
1511
1650
|
}
|
|
@@ -1521,10 +1660,12 @@ export function ConsoleAppV4(props) {
|
|
|
1521
1660
|
if (viewport.hiddenBefore > 0 || viewport.hiddenAfter > 0) {
|
|
1522
1661
|
context = `${items.length} 个插件 · ${viewport.position}/${viewport.total}`;
|
|
1523
1662
|
}
|
|
1524
|
-
content = (_jsxs(Box, { flexDirection: "column", children: [_jsx(SourceTabs, { controller: props.controller, current: sourceId, compact: policy.mode === 'compact', columns: size.columns - 2, mode: route.mode, query: query || undefined, installFilter: installFilter }), _jsxs(Text, { color:
|
|
1525
|
-
|
|
1663
|
+
content = (_jsxs(Box, { flexDirection: "column", children: [_jsx(SourceTabs, { controller: props.controller, current: sourceId, compact: policy.mode === 'compact', columns: size.columns - 2, mode: route.mode, query: query || undefined, installFilter: installFilter }), _jsxs(Text, { color: searchFocus ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: ["\u641C\u7D22 / ", searchFocus
|
|
1664
|
+
? _jsx(InputDisplay, { value: query, placeholder: "\u8F93\u5165\u641C\u7D22\u5185\u5BB9", columns: Math.max(8, size.columns - 14) })
|
|
1665
|
+
: _jsxs(_Fragment, { children: [query || '搜索名称、用途或来源…', query ? ' / 编辑' : ''] })] }), route.mode === 'browse'
|
|
1666
|
+
? _jsxs(Text, { color: tuiTheme.colors.muted, children: ["\u72B6\u6001 ", _jsx(Text, { color: installFilter === 'all' ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: installFilter === 'all' ? '[全部]' : '全部' }), " ", _jsxs(Text, { color: installFilter === 'uninstalled' ? tuiTheme.colors.accent : tuiTheme.colors.muted, children: [installFilter === 'uninstalled' ? '[未安装]' : '未安装', " ", uninstalledCount] }), " f \u5207\u6362"] })
|
|
1526
1667
|
: null, sourceError
|
|
1527
|
-
? _jsx(Callout, { status: "error", title: `${sourceId} 暂时无法提供插件`, description: "\
|
|
1668
|
+
? _jsx(Callout, { status: "error", title: `${sourceId} 暂时无法提供插件`, description: "\u5F53\u524D\u4E0D\u80FD\u6D4F\u89C8\u8FD9\u4E2A\u6765\u6E90\u3002" })
|
|
1528
1669
|
: route.mode === 'installed' && items.length === 0
|
|
1529
1670
|
? _jsx(Callout, { title: "\u5F00\u59CB\u6DFB\u52A0\u7B2C\u4E00\u4E2A\u63D2\u4EF6", description: "\u63D2\u4EF6\u53EF\u4EE5\u5B89\u88C5\u5230 Codex\u3001Claude Code \u6216\u4E24\u8005\u3002" })
|
|
1530
1671
|
: null, pluginRows.length > 0
|
|
@@ -1547,6 +1688,7 @@ export function ConsoleAppV4(props) {
|
|
|
1547
1688
|
setSelectedTargets([]);
|
|
1548
1689
|
setTargetSelections({});
|
|
1549
1690
|
setPreferredTarget(undefined);
|
|
1691
|
+
props.controller.beginInstallFlow(plugin.pluginId, initialScope);
|
|
1550
1692
|
if (available.length > 0)
|
|
1551
1693
|
go({ name: 'installPlacement', pluginId: plugin.pluginId });
|
|
1552
1694
|
else
|
|
@@ -1572,6 +1714,19 @@ export function ConsoleAppV4(props) {
|
|
|
1572
1714
|
return { label: '查看插件设置', description: `${plugin.configFieldCount} 个配置字段及当前来源`, run: () => beginConfigFlow(plugin.pluginId) };
|
|
1573
1715
|
if (action.id === 'sourceProblem')
|
|
1574
1716
|
return { label: '查看来源问题', status: 'warning', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) };
|
|
1717
|
+
if (action.id === 'outputCollision') {
|
|
1718
|
+
const collision = props.controller.listUserIssues().find((issue) => issue.pluginId === plugin.pluginId && issue.category === 'artifactCollision');
|
|
1719
|
+
return {
|
|
1720
|
+
label: '查看输出冲突',
|
|
1721
|
+
description: '目标位置已有不属于当前插件的内容',
|
|
1722
|
+
status: 'error',
|
|
1723
|
+
run: () => collision
|
|
1724
|
+
? go({ name: 'issueDetail', issueId: collision.issueId })
|
|
1725
|
+
: go({ name: 'pluginTechnical', pluginId: plugin.pluginId }),
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
if (action.id === 'about')
|
|
1729
|
+
return { label: '关于', run: () => go({ name: 'pluginAbout', pluginId: plugin.pluginId }) };
|
|
1575
1730
|
return { label: '查看来源', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) };
|
|
1576
1731
|
};
|
|
1577
1732
|
const previewMenu = dynamicMenu;
|
|
@@ -1718,7 +1873,7 @@ export function ConsoleAppV4(props) {
|
|
|
1718
1873
|
title = '输入 Agent ID';
|
|
1719
1874
|
description = '多个 Agent 可使用逗号或空格分隔。';
|
|
1720
1875
|
help = '输入 Agent ID · Enter 保存 · Esc 返回';
|
|
1721
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(InputCard, { focused: true, title: portableAgentInput
|
|
1876
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: portableAgentInput, columns: Math.max(8, size.columns - 8) }), description: inputError ?? 'Enter 保存并继续 · Esc 返回;q 和 b 会作为输入。', status: inputError ? 'error' : undefined }), _jsx(StaticRow, { title: "\u793A\u4F8B", meta: "cursor, claude-code, codex", status: "muted", compact: true })] });
|
|
1722
1877
|
}
|
|
1723
1878
|
else if (route.name === 'portableScope' && plugin && snapshot.portableDraft) {
|
|
1724
1879
|
breadcrumb = `${plugin.displayName} / 通用 Skills / 范围`;
|
|
@@ -1814,8 +1969,28 @@ export function ConsoleAppV4(props) {
|
|
|
1814
1969
|
breadcrumb = `${plugin.displayName} / 依赖关系`;
|
|
1815
1970
|
context = overview ? `${overview.summary.totalCount + 1} 个插件` : '只读';
|
|
1816
1971
|
title = hasInstalledPlacement(plugin) ? '依赖与被使用情况' : '安装所需插件';
|
|
1817
|
-
description = '
|
|
1972
|
+
description = '依赖由同一来源快照解析;调整前会进入 Review。';
|
|
1973
|
+
const installedTargets = plugin.installedPlacements.filter((placement) => placement.state === 'installed');
|
|
1818
1974
|
actions = [
|
|
1975
|
+
...(hasInstalledPlacement(plugin) && dependencyCount > 0 && installedTargets.length > 0 ? [{
|
|
1976
|
+
label: '调整依赖位置…',
|
|
1977
|
+
description: '按平台设置 project/user;不会自动清理所有项目内容',
|
|
1978
|
+
run: async () => {
|
|
1979
|
+
const rootScope = installedTargets.some((placement) => placement.desiredScopes?.includes('project') || placement.scope === 'project')
|
|
1980
|
+
? 'project' : 'user';
|
|
1981
|
+
const platforms = [...new Set(installedTargets.map((placement) => placement.platform))];
|
|
1982
|
+
setScope(rootScope);
|
|
1983
|
+
setSelectedTargets(platforms);
|
|
1984
|
+
props.controller.beginInstallFlow(plugin.pluginId, rootScope, { adjustingExisting: true });
|
|
1985
|
+
props.controller.setInstallPlatforms(platforms);
|
|
1986
|
+
const configurable = await props.controller.prepareInstallDependencyPlacement();
|
|
1987
|
+
if (!configurable) {
|
|
1988
|
+
setActionError('当前依赖位置都由约束固定,没有可调整项。');
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
go({ name: 'dependencyPlacement', pluginId: plugin.pluginId });
|
|
1992
|
+
},
|
|
1993
|
+
}] : []),
|
|
1819
1994
|
{ label: '技术详情', description: '显示 canonical pluginId 和安全错误代码', run: () => setShowTechnical((value) => !value) },
|
|
1820
1995
|
];
|
|
1821
1996
|
const rootStatus = plugin.aggregateStatus === 'installed' ? 'success'
|
|
@@ -1867,23 +2042,19 @@ export function ConsoleAppV4(props) {
|
|
|
1867
2042
|
breadcrumb = `${plugin.displayName} / 添加`;
|
|
1868
2043
|
context = '第 1 步,共 2 步';
|
|
1869
2044
|
title = `你希望在哪里使用 ${plugin.displayName}?`;
|
|
1870
|
-
const overview = dependencyOverview(plugin);
|
|
1871
2045
|
const hasDependencies = (plugin.dependencySummary?.totalCount ?? 0) > 0;
|
|
1872
2046
|
description = hasDependencies
|
|
1873
|
-
? '
|
|
2047
|
+
? '这里只选择根插件位置。依赖可以在下一步单独调整;依赖不能比根插件位置更窄。'
|
|
1874
2048
|
: '选择位置后,再选择一个或多个目标平台。';
|
|
1875
2049
|
const availableScopes = ['user', 'project'].filter((candidateScope) => props.controller.listInstallTargets(plugin.pluginId, candidateScope)
|
|
1876
2050
|
.some((entry) => entry.compatible));
|
|
1877
|
-
const reusableDependencies = overview?.dependencies.filter((dependency) => dependency.placements.some((placement) => placement.state === 'installed' && placement.health === 'ready'
|
|
1878
|
-
&& (scope === 'project' || placement.scope === 'user'))).length ?? 0;
|
|
1879
|
-
const missingDependencies = Math.max(0, (overview?.summary.totalCount ?? 0) - reusableDependencies);
|
|
1880
2051
|
actions = [
|
|
1881
2052
|
...availableScopes.map((candidateScope) => ({
|
|
1882
2053
|
label: scopeLabel(candidateScope),
|
|
1883
2054
|
selected: candidateScope === scope,
|
|
1884
2055
|
description: candidateScope === 'user'
|
|
1885
|
-
? hasDependencies ? '
|
|
1886
|
-
: hasDependencies ? '
|
|
2056
|
+
? hasDependencies ? '根插件在任意项目中可用;依赖位置下一步确认' : '在任意项目中可使用,适合个人常用能力'
|
|
2057
|
+
: hasDependencies ? '根插件只在当前项目使用;依赖可单独调整为所有项目' : '仅在当前项目中使用,适合团队共享',
|
|
1887
2058
|
meta: candidateScope === 'user' ? '推荐' : undefined,
|
|
1888
2059
|
run: () => {
|
|
1889
2060
|
const choices = props.controller.listInstallTargets(plugin.pluginId, candidateScope);
|
|
@@ -1897,6 +2068,7 @@ export function ConsoleAppV4(props) {
|
|
|
1897
2068
|
setScope(candidateScope);
|
|
1898
2069
|
setSelectedTargets(next);
|
|
1899
2070
|
setTargetSelections((current) => ({ ...current, [candidateScope]: next }));
|
|
2071
|
+
props.controller.setInstallRootScope(candidateScope);
|
|
1900
2072
|
go({
|
|
1901
2073
|
name: 'installTargets',
|
|
1902
2074
|
pluginId: plugin.pluginId,
|
|
@@ -1905,7 +2077,7 @@ export function ConsoleAppV4(props) {
|
|
|
1905
2077
|
},
|
|
1906
2078
|
})),
|
|
1907
2079
|
];
|
|
1908
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' }), hasDependencies ?
|
|
2080
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' }), hasDependencies ? _jsx(SectionCard, { title: "\u4F9D\u8D56\u4F4D\u7F6E", children: _jsx(StaticRow, { title: `${plugin.dependencySummary?.totalCount ?? 0} 个依赖将在下一步单独确认`, status: "info" }) }) : null] });
|
|
1909
2081
|
}
|
|
1910
2082
|
else if (route.name === 'installTargets' && plugin) {
|
|
1911
2083
|
breadcrumb = `${plugin.displayName} / 添加 / 目标平台`;
|
|
@@ -1913,8 +2085,8 @@ export function ConsoleAppV4(props) {
|
|
|
1913
2085
|
title = '选择目标平台';
|
|
1914
2086
|
const hasDependencies = (plugin.dependencySummary?.totalCount ?? 0) > 0;
|
|
1915
2087
|
description = hasDependencies
|
|
1916
|
-
? '
|
|
1917
|
-
: '
|
|
2088
|
+
? '根插件必须支持所选位置;每个依赖必须至少有一个合法位置。'
|
|
2089
|
+
: '目标平台按所选位置验证;仅含 Codex native 的插件可同时启用两个位置。';
|
|
1918
2090
|
const choices = props.controller.listInstallTargets(plugin.pluginId, scope);
|
|
1919
2091
|
const validSelectedTargets = selectedTargets.filter((platform) => choices.some((choice) => choice.platform === platform && choice.compatible));
|
|
1920
2092
|
const allUnavailable = choices.length > 0 && choices.every((choice) => !choice.compatible);
|
|
@@ -1943,6 +2115,7 @@ export function ConsoleAppV4(props) {
|
|
|
1943
2115
|
? current.filter((platform) => platform !== choice.platform)
|
|
1944
2116
|
: [...current, choice.platform];
|
|
1945
2117
|
setTargetSelections((selections) => ({ ...selections, [scope]: next }));
|
|
2118
|
+
props.controller.setInstallPlatforms(next);
|
|
1946
2119
|
return next;
|
|
1947
2120
|
});
|
|
1948
2121
|
},
|
|
@@ -1955,7 +2128,15 @@ export function ConsoleAppV4(props) {
|
|
|
1955
2128
|
disabled: validSelectedTargets.length === 0 ? '至少选择一个目标平台' : undefined,
|
|
1956
2129
|
run: () => {
|
|
1957
2130
|
setDirty(false);
|
|
1958
|
-
|
|
2131
|
+
if (!hasDependencies) {
|
|
2132
|
+
if (props.controller.snapshot.installPlacementDraft?.pluginId !== plugin.pluginId) {
|
|
2133
|
+
props.controller.beginInstallFlow(plugin.pluginId, scope);
|
|
2134
|
+
}
|
|
2135
|
+
props.controller.setInstallPlatforms(validSelectedTargets);
|
|
2136
|
+
beginReview(props.controller.installPlacementIntent());
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
return continueInstallAfterTargets(plugin, validSelectedTargets);
|
|
1959
2140
|
},
|
|
1960
2141
|
},
|
|
1961
2142
|
{ label: '返回选择位置', run: back },
|
|
@@ -1964,6 +2145,83 @@ export function ConsoleAppV4(props) {
|
|
|
1964
2145
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "toggle", compact: policy.mode === 'compact', limit: targetActions.length }), hasDependencies ? _jsx(Callout, { title: "\u76EE\u6807\u5E73\u53F0\u517C\u5BB9\u6027", description: "\u4E0D\u517C\u5BB9\u7684\u76EE\u6807\u5E73\u53F0\u4E0D\u80FD\u9009\u62E9\uFF1B\u8BF7\u67E5\u770B\u4F9D\u8D56\u5173\u7CFB\u4E86\u89E3\u539F\u56E0\u3002" }) : null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: targetActions.length })] });
|
|
1965
2146
|
}
|
|
1966
2147
|
}
|
|
2148
|
+
else if (route.name === 'dependencyPlacement' && plugin) {
|
|
2149
|
+
const draft = snapshot.installPlacementDraft?.pluginId === plugin.pluginId
|
|
2150
|
+
? snapshot.installPlacementDraft : undefined;
|
|
2151
|
+
breadcrumb = `${plugin.displayName} / 添加 / 依赖位置`;
|
|
2152
|
+
context = '依赖位置';
|
|
2153
|
+
title = '选择每个平台的依赖位置';
|
|
2154
|
+
description = '每个直接或间接依赖都可独立设置。所有项目位置更宽,会影响其他项目和你的用户环境。';
|
|
2155
|
+
const dependencyActions = (draft?.targets ?? []).map((target) => ({
|
|
2156
|
+
label: `${target.displayName} · ${platformLabel(target.platform)}`,
|
|
2157
|
+
description: `${target.relation === 'direct' ? '直接依赖' : '间接依赖'} · ${target.explanation}`,
|
|
2158
|
+
meta: `${scopeLabel(target.scope)}${target.assignmentSource === 'consumerPromotion' ? ' · fixed-point 提升' : ''}`,
|
|
2159
|
+
selected: true,
|
|
2160
|
+
disabled: target.locked ? '位置由平台或上游约束固定' : undefined,
|
|
2161
|
+
run: () => go({
|
|
2162
|
+
name: 'dependencyPlacementEditor',
|
|
2163
|
+
pluginId: plugin.pluginId,
|
|
2164
|
+
dependencyPluginId: target.pluginId,
|
|
2165
|
+
platform: target.platform,
|
|
2166
|
+
}),
|
|
2167
|
+
}));
|
|
2168
|
+
actions = [
|
|
2169
|
+
...dependencyActions,
|
|
2170
|
+
{
|
|
2171
|
+
label: '继续到确认',
|
|
2172
|
+
description: draft?.canContinue ? '使用这些最终位置准备 Review' : undefined,
|
|
2173
|
+
disabled: !draft?.canContinue ? draft?.error?.message ?? '依赖位置尚未就绪' : undefined,
|
|
2174
|
+
run: () => beginReview(props.controller.installPlacementIntent()),
|
|
2175
|
+
},
|
|
2176
|
+
{
|
|
2177
|
+
label: '恢复推荐位置',
|
|
2178
|
+
description: '恢复默认、健康 user 复用和 fixed-point 计算结果',
|
|
2179
|
+
run: () => props.controller.resetDependencyScopes(),
|
|
2180
|
+
},
|
|
2181
|
+
{ label: '返回目标平台', run: back },
|
|
2182
|
+
];
|
|
2183
|
+
const placementViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(dependencyPlacementStaticRows));
|
|
2184
|
+
const userCount = draft?.targets.filter((target) => target.scope === 'user').length ?? 0;
|
|
2185
|
+
const defaultCount = draft?.targets.filter((target) => target.assignmentSource === 'default').length ?? 0;
|
|
2186
|
+
const reusedCount = draft?.targets.filter((target) => target.assignmentSource === 'existingWiderTarget').length ?? 0;
|
|
2187
|
+
const promotedCount = draft?.targets.filter((target) => target.assignmentSource === 'consumerPromotion').length ?? 0;
|
|
2188
|
+
const reasonSummary = [
|
|
2189
|
+
...(defaultCount > 0 ? [`默认 project ${defaultCount} 项`] : []),
|
|
2190
|
+
...(reusedCount > 0 ? [`复用健康的所有项目安装 ${reusedCount} 项`] : []),
|
|
2191
|
+
...(promotedCount > 0 ? [`fixed-point 提升 ${promotedCount} 项`] : []),
|
|
2192
|
+
].join(';');
|
|
2193
|
+
content = _jsxs(Box, { flexDirection: "column", children: [policy.mode === 'compact'
|
|
2194
|
+
? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `根插件 · ${plugin.displayName}`, meta: draft ? scopeLabel(draft.rootScope) : '未就绪', compact: true }), _jsx(StaticRow, { title: `位置原因 · ${reasonSummary || '由平台或上游约束固定'}`, status: userCount > 0 ? 'warning' : 'info', compact: true }), _jsx(StaticRow, { title: "\u8303\u56F4\u63D0\u793A \u00B7 \u6240\u6709\u9879\u76EE\u4F4D\u7F6E\u4F1A\u5F71\u54CD\u5176\u4ED6\u9879\u76EE\u548C\u7528\u6237\u73AF\u5883", status: userCount > 0 ? 'warning' : 'muted', compact: true })] })
|
|
2195
|
+
: _jsxs(_Fragment, { children: [_jsx(SectionCard, { title: "\u6839\u63D2\u4EF6\u4F4D\u7F6E", children: _jsx(StaticRow, { title: plugin.displayName, meta: draft ? scopeLabel(draft.rootScope) : '未就绪', compact: true }) }), _jsx(Callout, { status: userCount > 0 ? 'warning' : 'info', title: userCount > 0 ? `${userCount} 个依赖平台目标使用所有项目位置` : '位置计算原因', description: `${reasonSummary || '依赖位置由平台或上游约束固定'}${userCount > 0 ? ';所有项目位置对其他项目也可见,并会改变你的用户环境' : ''}。` })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: placementViewport.offset, limit: placementViewport.limit })] });
|
|
2196
|
+
help = '↑↓ 移动 · Enter 打开/继续 · Esc 返回';
|
|
2197
|
+
}
|
|
2198
|
+
else if (route.name === 'dependencyPlacementEditor' && plugin) {
|
|
2199
|
+
const target = snapshot.installPlacementDraft?.targets.find((entry) => entry.pluginId === route.dependencyPluginId && entry.platform === route.platform);
|
|
2200
|
+
breadcrumb = `${plugin.displayName} / 依赖位置 / ${target?.displayName ?? route.dependencyPluginId}`;
|
|
2201
|
+
context = platformLabel(route.platform);
|
|
2202
|
+
title = `设置 ${target?.displayName ?? route.dependencyPluginId} 的位置`;
|
|
2203
|
+
description = target?.explanation ?? '依赖位置已变化。请返回重新检查。';
|
|
2204
|
+
actions = ['project', 'user'].map((candidateScope) => {
|
|
2205
|
+
const unavailable = !target?.allowedScopes.includes(candidateScope)
|
|
2206
|
+
|| target.minimumScope === 'user' && candidateScope === 'project';
|
|
2207
|
+
return {
|
|
2208
|
+
label: scopeLabel(candidateScope),
|
|
2209
|
+
selected: target?.scope === candidateScope,
|
|
2210
|
+
description: candidateScope === 'user'
|
|
2211
|
+
? '更宽:对其他项目可见,并会改变你的用户环境'
|
|
2212
|
+
: '仅供当前项目使用;适合项目共享 intent',
|
|
2213
|
+
disabled: unavailable ? '这个依赖或上游约束不允许此位置' : undefined,
|
|
2214
|
+
run: async () => {
|
|
2215
|
+
await props.controller.setDependencyScope(route.dependencyPluginId, route.platform, candidateScope);
|
|
2216
|
+
back();
|
|
2217
|
+
},
|
|
2218
|
+
};
|
|
2219
|
+
});
|
|
2220
|
+
content = _jsxs(Box, { flexDirection: "column", children: [target?.assignmentSource === 'consumerPromotion'
|
|
2221
|
+
? _jsx(Callout, { status: "warning", title: "fixed-point \u4F4D\u7F6E\u63D0\u5347", description: `上游依赖需要至少使用${scopeLabel(target.minimumScope)}。` })
|
|
2222
|
+
: null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' })] });
|
|
2223
|
+
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
2224
|
+
}
|
|
1967
2225
|
else if (route.name === 'pluginDetail' && plugin) {
|
|
1968
2226
|
breadcrumb = `我的插件 / ${plugin.displayName}`;
|
|
1969
2227
|
context = `${plugin.sourceLabel}${plugin.version ? ` · ${plugin.version}` : ''}`;
|
|
@@ -1972,6 +2230,13 @@ export function ConsoleAppV4(props) {
|
|
|
1972
2230
|
const dependencySummary = plugin.dependencySummary;
|
|
1973
2231
|
const detailMenu = dynamicMenu;
|
|
1974
2232
|
actions = detailMenu.map((action) => {
|
|
2233
|
+
if (action.id === 'resolveScopeConflict')
|
|
2234
|
+
return {
|
|
2235
|
+
label: `保留${scopeLabel(action.keepScope)},移除${scopeLabel(action.scope)} root…`,
|
|
2236
|
+
description: action.description,
|
|
2237
|
+
status: 'error',
|
|
2238
|
+
run: () => beginScopeConflictRecovery(action),
|
|
2239
|
+
};
|
|
1975
2240
|
if (action.id === 'platform' || action.id === 'scopeConflict') {
|
|
1976
2241
|
const placement = plugin.installedPlacements.find((entry) => entry.platform === action.platform);
|
|
1977
2242
|
const projected = placementStatus(placement);
|
|
@@ -2017,14 +2282,20 @@ export function ConsoleAppV4(props) {
|
|
|
2017
2282
|
&& candidate.platform === route.platform
|
|
2018
2283
|
&& candidate.scope === placement.scope)
|
|
2019
2284
|
: undefined;
|
|
2285
|
+
const collisionIssue = placement?.state === 'blocked'
|
|
2286
|
+
|| placement?.state === 'installed' && placement.blockingReason === 'artifactCollision'
|
|
2287
|
+
? props.controller.listUserIssues().find((candidate) => candidate.pluginId === plugin.pluginId
|
|
2288
|
+
&& candidate.platform === route.platform
|
|
2289
|
+
&& candidate.category === 'artifactCollision')
|
|
2290
|
+
: undefined;
|
|
2020
2291
|
const sourceIssue = plugin.aggregateStatus === 'unavailable'
|
|
2021
2292
|
? props.controller.listUserIssues().find((candidate) => candidate.entity.kind === 'source' && candidate.sourceId === plugin.sourceId)
|
|
2022
2293
|
: undefined;
|
|
2023
2294
|
const platformAction = (action) => {
|
|
2024
2295
|
if (action.id === 'sourceProblem')
|
|
2025
|
-
return { label: '查看来源问题', description: `${plugin.sourceId}
|
|
2296
|
+
return { label: '查看来源问题', description: `${plugin.sourceId} 当前不可用`, run: () => go({ name: 'issueDetail', issueId: `source:${plugin.sourceId}:unavailable` }) };
|
|
2026
2297
|
if (action.id === 'refreshSource')
|
|
2027
|
-
return { label: '
|
|
2298
|
+
return { label: '重新加载状态', description: `如需同步,先在终端运行 aw catalog source sync ${plugin.sourceId}`, run: async () => { await props.controller.reloadCatalog({ sourceId: plugin.sourceId }); } };
|
|
2028
2299
|
if (action.id === 'add')
|
|
2029
2300
|
return { label: `添加到 ${platformLabel(route.platform)}…`, description: '选择使用位置', run: () => {
|
|
2030
2301
|
const initialScope = placement?.state === 'notInstalled'
|
|
@@ -2034,14 +2305,50 @@ export function ConsoleAppV4(props) {
|
|
|
2034
2305
|
setSelectedTargets([]);
|
|
2035
2306
|
setTargetSelections({});
|
|
2036
2307
|
setPreferredTarget(route.platform);
|
|
2308
|
+
props.controller.beginInstallFlow(plugin.pluginId, initialScope);
|
|
2037
2309
|
go({ name: 'installPlacement', pluginId: plugin.pluginId });
|
|
2038
2310
|
} };
|
|
2311
|
+
if (action.id === 'addScope')
|
|
2312
|
+
return {
|
|
2313
|
+
label: `在${scopeLabel(action.scope)}中启用…`,
|
|
2314
|
+
description: '只增加该 scope 的 activation;shared native 保持复用',
|
|
2315
|
+
run: () => beginSecondScope(plugin, action.platform, action.scope),
|
|
2316
|
+
};
|
|
2039
2317
|
if (action.id === 'about')
|
|
2040
2318
|
return { label: '查看支持信息', description: 'manifest 与平台能力', run: () => go({ name: 'pluginAbout', pluginId: plugin.pluginId }) };
|
|
2319
|
+
if (action.id === 'source')
|
|
2320
|
+
return { label: '查看来源', run: () => go({ name: 'sourceDetail', sourceId: plugin.sourceId }) };
|
|
2321
|
+
if (action.id === 'outputCollision')
|
|
2322
|
+
return {
|
|
2323
|
+
label: '查看输出冲突',
|
|
2324
|
+
description: '不会覆盖或删除占用内容',
|
|
2325
|
+
status: 'error',
|
|
2326
|
+
run: () => collisionIssue
|
|
2327
|
+
? go({ name: 'issueDetail', issueId: collisionIssue.issueId })
|
|
2328
|
+
: go({ name: 'pluginTechnical', pluginId: plugin.pluginId }),
|
|
2329
|
+
};
|
|
2041
2330
|
if (action.id === 'scopeConflict')
|
|
2042
2331
|
return { label: '查看位置冲突问题', run: () => go({ name: 'issueDetail', issueId: `scope:${plugin.pluginId}:${route.platform}` }) };
|
|
2332
|
+
if (action.id === 'resolveScopeConflict')
|
|
2333
|
+
return {
|
|
2334
|
+
label: `保留${scopeLabel(action.keepScope)},移除${scopeLabel(action.scope)} root…`,
|
|
2335
|
+
description: action.description,
|
|
2336
|
+
status: 'error',
|
|
2337
|
+
run: () => beginScopeConflictRecovery(action),
|
|
2338
|
+
};
|
|
2043
2339
|
if (action.id === 'upgrade')
|
|
2044
2340
|
return { label: `升级到 ${action.availableVersion}…`, description: '使用当前来源中的版本重建', run: () => beginReview({ kind: 'pluginWrite', action: 'upgrade', pluginId: plugin.pluginId, platform: action.platform, scope: action.scope }) };
|
|
2341
|
+
if (action.id === 'sync')
|
|
2342
|
+
return {
|
|
2343
|
+
label: '同步 desired intent…',
|
|
2344
|
+
description: placement?.state === 'installed'
|
|
2345
|
+
? placement.recovery?.find((entry) => entry.command === 'sync')?.description
|
|
2346
|
+
?? '进入现有 Review、进度和结果链修复 needsSync 或 drift'
|
|
2347
|
+
: undefined,
|
|
2348
|
+
run: () => placement?.state === 'installed'
|
|
2349
|
+
? beginReview({ kind: 'pluginWrite', action: 'sync', pluginId: plugin.pluginId, platform: route.platform, scope: placement.scope })
|
|
2350
|
+
: undefined,
|
|
2351
|
+
};
|
|
2045
2352
|
if (action.id === 'reinstall')
|
|
2046
2353
|
return { label: placement?.state === 'installed' && placement.health === 'incomplete' ? '重新连接缺失内容…' : '重新安装…', description: '保留现有设置并重新生成受管内容', run: () => beginReview({ kind: 'pluginWrite', action: 'reinstall', pluginId: plugin.pluginId, platform: action.platform, scope: action.scope }) };
|
|
2047
2354
|
if (action.id === 'remove')
|
|
@@ -2053,6 +2360,7 @@ export function ConsoleAppV4(props) {
|
|
|
2053
2360
|
return { label: '返回插件', run: back };
|
|
2054
2361
|
};
|
|
2055
2362
|
breadcrumb = `${plugin.displayName} / ${platformLabel(route.platform)}`;
|
|
2363
|
+
const installedPlacementRows = placement?.state === 'installed' ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "Desired placement", meta: placement.desiredScopes?.map(scopeLabel).join('、') || scopeLabel(placement.scope), compact: true }), _jsx(StaticRow, { title: "Actual scope \u72B6\u6001", meta: placement.actualState ?? placement.health, status: placement.actualState === 'ready' ? 'success' : placement.actualState === 'conflict' ? 'error' : 'warning', compact: true }), placement.sharedNative ? _jsx(StaticRow, { title: "Shared native", meta: placement.sharedNative.state, status: placement.sharedNative.state === 'present' ? 'success' : 'warning', compact: true }) : null, placement.activation ? _jsx(StaticRow, { title: "Activation", meta: `user ${placement.activation.user ? 'on' : 'off'} · project ${placement.activation.project ? 'on' : 'off'}`, compact: true }) : null, placement.extensions ? _jsx(StaticRow, { title: "AW-only extensions", meta: `${placement.extensions.state} · ${placement.extensions.kinds.join('、') || '无'}`, status: placement.extensions.state === 'ready' ? 'success' : placement.extensions.state === 'conflict' ? 'error' : 'warning', compact: true }) : null] }) : null;
|
|
2056
2364
|
if (plugin.aggregateStatus === 'unavailable') {
|
|
2057
2365
|
const sourceOverview = props.controller.getSourceOverview(plugin.sourceId);
|
|
2058
2366
|
const diagnostic = sourceIssue?.diagnostic ?? sourceDiagnostic(plugin.sourceId, sourceOverview.health?.state ?? sourceOverview.source?.state, sourceOverview.detail);
|
|
@@ -2069,6 +2377,15 @@ export function ConsoleAppV4(props) {
|
|
|
2069
2377
|
actions = platformMenu.map(platformAction);
|
|
2070
2378
|
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: "muted", title: "\u672A\u6DFB\u52A0", description: "\u63D2\u4EF6\u8BBE\u7F6E\u4FDD\u6301\u4E0D\u53D8" }), _jsx(SemanticRows, { actions: actions, focus: effectiveFocus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2071
2379
|
}
|
|
2380
|
+
else if (placement.state === 'blocked'
|
|
2381
|
+
|| placement.state === 'installed' && placement.blockingReason === 'artifactCollision') {
|
|
2382
|
+
title = `${platformLabel(route.platform)} 无法添加`;
|
|
2383
|
+
description = placement.state === 'installed'
|
|
2384
|
+
? '受管内容仍可安全移除;输出位置同时存在冲突内容。'
|
|
2385
|
+
: '输出位置已有不属于当前插件的内容。';
|
|
2386
|
+
actions = platformMenu.map(platformAction);
|
|
2387
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: "error", title: "\u8F93\u51FA\u51B2\u7A81", description: "AW \u4E0D\u4F1A\u8986\u76D6\u6216\u5220\u9664\u5360\u7528\u5185\u5BB9" }), _jsx(SemanticRows, { actions: actions, focus: effectiveFocus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2388
|
+
}
|
|
2072
2389
|
else if (placement.state === 'scopeConflict') {
|
|
2073
2390
|
title = '安装位置冲突';
|
|
2074
2391
|
description = '正常状态只能保留一个位置。';
|
|
@@ -2104,14 +2421,17 @@ export function ConsoleAppV4(props) {
|
|
|
2104
2421
|
title = `${platformLabel(route.platform)} ${placement.health === 'incomplete' ? '安装不完整' : '暂时不可用'}`;
|
|
2105
2422
|
description = '缺少一项必要内容,插件可能无法稳定启动。';
|
|
2106
2423
|
actions = platformMenu.map(platformAction);
|
|
2107
|
-
|
|
2424
|
+
const actualTitle = placement.actualState === 'needsSync' ? '需要同步'
|
|
2425
|
+
: placement.actualState === 'drifted' ? '现场已漂移'
|
|
2426
|
+
: placement.actualState === 'conflict' ? '位置与扩展冲突' : '需要处理';
|
|
2427
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: placement.actualState === 'conflict' ? 'error' : 'warning', title: actualTitle, description: `${scopeLabel(placement.scope)} · ${plugin.sourceLabel}`, children: installedPlacementRows }), _jsx(SemanticRows, { actions: actions, focus: effectiveFocus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2108
2428
|
}
|
|
2109
2429
|
else {
|
|
2110
2430
|
title = `已安装到${scopeLabel(placement.scope)}`;
|
|
2111
2431
|
const installedVersion = placement.revision.installedVersion;
|
|
2112
2432
|
description = `当前检查正常${installedVersion ? `;已安装版本 ${installedVersion}` : ''}。`;
|
|
2113
2433
|
actions = platformMenu.map(platformAction);
|
|
2114
|
-
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: "success", title: "\u72B6\u6001\u6B63\u5E38", description: `${scopeLabel(placement.scope)}${installedVersion ? ` · 已安装版本 ${installedVersion}` : ''}
|
|
2434
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(StatusCard, { status: "success", title: "\u72B6\u6001\u6B63\u5E38", description: `${scopeLabel(placement.scope)}${installedVersion ? ` · 已安装版本 ${installedVersion}` : ''}`, children: installedPlacementRows }), _jsx(SemanticRows, { actions: actions, focus: effectiveFocus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2115
2435
|
}
|
|
2116
2436
|
}
|
|
2117
2437
|
else if (route.name === 'configLayer' && plugin) {
|
|
@@ -2190,7 +2510,12 @@ export function ConsoleAppV4(props) {
|
|
|
2190
2510
|
fieldKey: field.key,
|
|
2191
2511
|
groupId: activeGroup.id,
|
|
2192
2512
|
})
|
|
2193
|
-
: () => go({
|
|
2513
|
+
: () => go(field.configured ? {
|
|
2514
|
+
name: 'configFieldAction',
|
|
2515
|
+
pluginId: plugin.pluginId,
|
|
2516
|
+
layer: mutableLayer,
|
|
2517
|
+
fieldKey: field.key,
|
|
2518
|
+
} : {
|
|
2194
2519
|
name: 'configFieldEditor',
|
|
2195
2520
|
pluginId: plugin.pluginId,
|
|
2196
2521
|
layer: mutableLayer,
|
|
@@ -2200,13 +2525,27 @@ export function ConsoleAppV4(props) {
|
|
|
2200
2525
|
}));
|
|
2201
2526
|
const operationActions = readonly ? [] : [
|
|
2202
2527
|
{ label: '保存修改', description: dirty ? '查看安全变更汇总' : '当前没有未保存修改', disabled: dirty ? undefined : '当前没有未保存修改', run: beginConfigSave },
|
|
2203
|
-
{
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2528
|
+
...(currentConfigPage.storedCount > 0 ? [{
|
|
2529
|
+
label: route.layer.scope === 'user'
|
|
2530
|
+
? '清空个人默认…'
|
|
2531
|
+
: route.layer.projectLayer === 'local' ? '删除本机设置…' : '清空当前项目共享设置…',
|
|
2532
|
+
description: `删除${configLayerLabel(route.layer)}中的全部值并恢复继承;其他设置层保持不变`,
|
|
2533
|
+
status: 'error',
|
|
2534
|
+
run: () => beginReview({
|
|
2535
|
+
kind: 'configReset',
|
|
2536
|
+
pluginId: plugin.pluginId,
|
|
2537
|
+
scope: route.layer.scope,
|
|
2538
|
+
projectLayer: route.layer.projectLayer,
|
|
2539
|
+
changes: currentConfigPage.groups.flatMap((group) => group.fields)
|
|
2540
|
+
.filter((field) => field.configured)
|
|
2541
|
+
.map((field) => ({
|
|
2542
|
+
key: field.key,
|
|
2543
|
+
title: field.title,
|
|
2544
|
+
before: field.displayValue,
|
|
2545
|
+
after: `恢复继承(${field.fallbackDisplayValue ?? '未设置'} · ${field.fallbackSourceLabel ?? '未设置'})`,
|
|
2546
|
+
})),
|
|
2547
|
+
}),
|
|
2548
|
+
}] : []),
|
|
2210
2549
|
];
|
|
2211
2550
|
actions = [...tabActions, ...operationActions];
|
|
2212
2551
|
const effectiveConfigFocus = Math.min(focus, Math.max(0, actions.length - 1));
|
|
@@ -2226,6 +2565,32 @@ export function ConsoleAppV4(props) {
|
|
|
2226
2565
|
: null] });
|
|
2227
2566
|
}
|
|
2228
2567
|
}
|
|
2568
|
+
else if (route.name === 'configFieldAction' && plugin && activeField) {
|
|
2569
|
+
const layer = configLayerLabel(route.layer);
|
|
2570
|
+
breadcrumb = `${plugin.displayName} / 设置 / ${layer} / ${activeField.title}`;
|
|
2571
|
+
title = activeField.title;
|
|
2572
|
+
description = `这个字段在${layer}中已经有值。`;
|
|
2573
|
+
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
2574
|
+
const deleteLabel = route.layer.scope === 'user'
|
|
2575
|
+
? '删除个人默认中的值'
|
|
2576
|
+
: route.layer.projectLayer === 'local' ? '删除本机设置中的值' : '删除当前项目中的值';
|
|
2577
|
+
actions = [
|
|
2578
|
+
{
|
|
2579
|
+
label: '修改值…',
|
|
2580
|
+
run: () => go({
|
|
2581
|
+
name: 'configFieldEditor',
|
|
2582
|
+
pluginId: plugin.pluginId,
|
|
2583
|
+
layer: route.layer,
|
|
2584
|
+
fieldKey: activeField.key,
|
|
2585
|
+
editor: fieldEditor(activeField),
|
|
2586
|
+
}),
|
|
2587
|
+
},
|
|
2588
|
+
draftRemoves.includes(activeField.key)
|
|
2589
|
+
? { label: '撤销删除', run: () => { cancelDraftRemoval(activeField.key); back(); } }
|
|
2590
|
+
: { label: deleteLabel, status: 'error', run: () => { removeDraft(activeField.key); back(); } },
|
|
2591
|
+
];
|
|
2592
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(SectionCard, { children: [_jsx(StaticRow, { title: `${layer}中的值`, meta: currentFieldDisplay(activeField) }), _jsx(StaticRow, { title: "\u5F53\u524D\u5B9E\u9645\u751F\u6548", meta: `${effectiveFieldDisplay(activeField)} · 来自${activeField.effectiveSourceLabel}` }), _jsx(StaticRow, { title: "\u5220\u9664\u540E\u5C06\u6062\u590D", meta: `${activeField.fallbackDisplayValue ?? '未设置'} · 来自${activeField.fallbackSourceLabel ?? '未设置'}` })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2593
|
+
}
|
|
2229
2594
|
else if (route.name === 'configFieldEditor' && plugin && activeField) {
|
|
2230
2595
|
breadcrumb = `${plugin.displayName} / 设置 / ${activeField.title}`;
|
|
2231
2596
|
help = route.editor === 'enum' || route.editor === 'boolean'
|
|
@@ -2253,10 +2618,8 @@ export function ConsoleAppV4(props) {
|
|
|
2253
2618
|
? `允许范围:${activeField.min ?? '不限'}–${activeField.max ?? '不限'}${activeField.unit ? ` ${activeField.unit}` : ''}。`
|
|
2254
2619
|
: route.editor === 'path' ? `${activeField.type === 'file' ? '文件' : '目录'}路径会在保存前由现有 schema 路径验证。`
|
|
2255
2620
|
: route.editor === 'sensitive' ? '当前值不会回显;留空不会自动删除旧值。' : activeField.description ?? '';
|
|
2256
|
-
const visibleInput = route.editor === '
|
|
2257
|
-
|
|
2258
|
-
: route.editor === 'path' ? privatePathInput(inputValue) : inputValue;
|
|
2259
|
-
content = _jsx(InputCard, { focused: true, title: visibleInput || activeField.placeholder || ' ', description: inputError ?? (route.editor === 'sensitive' ? '输入已隐藏。' : route.editor === 'path' ? '已隐藏父目录;Backspace 仍会编辑原始输入。' : activeField.placeholder ?? '按 Enter 使用输入值。'), status: inputError ? 'error' : undefined });
|
|
2621
|
+
const visibleInput = route.editor === 'path' ? privatePathInput(inputValue) : inputValue;
|
|
2622
|
+
content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: visibleInput, sensitive: route.editor === 'sensitive', placeholder: activeField.placeholder, columns: Math.max(8, size.columns - 8) }), description: inputError ?? (route.editor === 'sensitive' ? '输入已隐藏。' : route.editor === 'path' ? '已隐藏父目录;Backspace 仍会编辑原始输入。' : activeField.placeholder ?? '按 Enter 使用输入值。'), status: inputError ? 'error' : undefined });
|
|
2260
2623
|
}
|
|
2261
2624
|
}
|
|
2262
2625
|
else if (route.name === 'configUnavailable' && plugin) {
|
|
@@ -2266,11 +2629,7 @@ export function ConsoleAppV4(props) {
|
|
|
2266
2629
|
title = diagnostic.title;
|
|
2267
2630
|
description = '';
|
|
2268
2631
|
actions = [
|
|
2269
|
-
{ label:
|
|
2270
|
-
await props.controller.refreshSource(plugin.sourceId);
|
|
2271
|
-
setConfigLoadKey((value) => value + 1);
|
|
2272
|
-
props.controller.replace({ name: 'configFields', pluginId: plugin.pluginId, layer: route.layer ?? { scope: 'user', projectLayer: 'shared' } });
|
|
2273
|
-
} },
|
|
2632
|
+
{ label: `在终端运行 aw catalog source sync ${plugin.sourceId}`, description: '同步成功后重新加载 TUI', run: back },
|
|
2274
2633
|
{ label: showTechnical ? '返回问题摘要' : '技术详情', description: '查看脱敏错误代码和阶段', run: () => setShowTechnical((value) => !value) },
|
|
2275
2634
|
{ label: '返回', run: back },
|
|
2276
2635
|
];
|
|
@@ -2281,22 +2640,21 @@ export function ConsoleAppV4(props) {
|
|
|
2281
2640
|
title = '插件来源';
|
|
2282
2641
|
description = '单个来源失败不会阻止其他来源继续工作。';
|
|
2283
2642
|
context = `${props.controller.listSources().length} 个来源`;
|
|
2284
|
-
help = '↑↓ 移动 · Enter 打开 ·
|
|
2643
|
+
help = '↑↓ 移动 · Enter 打开 · Esc 返回';
|
|
2285
2644
|
actions = [
|
|
2286
2645
|
...props.controller.listSources().map((source) => {
|
|
2287
2646
|
const overview = props.controller.getSourceOverview(source.id);
|
|
2647
|
+
const generation = props.controller.getCatalogGeneration(source.id);
|
|
2288
2648
|
const health = overview.health?.state ?? source.state;
|
|
2289
|
-
const status =
|
|
2290
|
-
: health === '
|
|
2291
|
-
:
|
|
2292
|
-
: health === 'cache' || health === 'degraded' ? '使用缓存' : '无法读取';
|
|
2649
|
+
const status = generation?.active ? `Active ${generation.active.catalogVersion}`
|
|
2650
|
+
: health === 'ready' ? '当前使用'
|
|
2651
|
+
: '无法读取';
|
|
2293
2652
|
return {
|
|
2294
2653
|
label: `${source.id}${source.primary ? ' 主来源' : ''}`,
|
|
2295
2654
|
description: `${overview.detail?.type === 'path' ? '本地目录' : 'Git 仓库'} · ${source.count ?? 0} 个插件`,
|
|
2296
2655
|
meta: status,
|
|
2297
|
-
status: health === 'unavailable' ? 'error'
|
|
2298
|
-
:
|
|
2299
|
-
: source.primary ? 'success' : undefined,
|
|
2656
|
+
status: !generation?.active || health === 'unavailable' ? 'error'
|
|
2657
|
+
: source.primary ? 'success' : undefined,
|
|
2300
2658
|
run: () => go({ name: 'sourceDetail', sourceId: source.id }),
|
|
2301
2659
|
};
|
|
2302
2660
|
}),
|
|
@@ -2309,43 +2667,35 @@ export function ConsoleAppV4(props) {
|
|
|
2309
2667
|
else if (route.name === 'sourceDetail') {
|
|
2310
2668
|
const overview = props.controller.getSourceOverview(route.sourceId);
|
|
2311
2669
|
const detail = overview.detail;
|
|
2312
|
-
const
|
|
2313
|
-
const
|
|
2670
|
+
const generation = props.controller.getCatalogGeneration(route.sourceId);
|
|
2671
|
+
const activeVersion = generation?.active?.catalogVersion;
|
|
2672
|
+
const metadataInvalid = generation?.errorCode === 'catalogGenerationMetadataInvalid';
|
|
2673
|
+
const damagedEntry = generation?.recoveryEntryPath;
|
|
2314
2674
|
breadcrumb = `插件来源 / ${route.sourceId}`;
|
|
2315
2675
|
context = detail?.type === 'path' ? '本地目录' : 'Git';
|
|
2316
2676
|
title = route.sourceId;
|
|
2317
|
-
description =
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
{ label: '重新检查来源', description: '读取远端并更新缓存', run: () => props.controller.refreshSource(route.sourceId) },
|
|
2334
|
-
{ label: '编辑来源…', description: 'ID 与类型创建后不可修改', run: () => go({ name: 'sourceEdit', sourceId: route.sourceId }) },
|
|
2335
|
-
{ label: '设为主来源…', description: '只改变默认 marketplace', disabled: detail?.primary ? '当前已经是主来源' : undefined, run: () => beginReview({ kind: 'sourceMutation', action: 'setPrimary', sourceId: route.sourceId, changes: [{ title: '主来源', before: snapshot.viewModel?.sourceTabs.find((source) => source.primary)?.id, after: route.sourceId }] }) },
|
|
2336
|
-
{ label: '移除来源…', description: '移除来源配置', status: 'error', disabled: detail?.primary ? '主来源不能直接移除' : undefined, run: () => beginReview({ kind: 'sourceMutation', action: 'remove', sourceId: route.sourceId, changes: [{ title: `移除来源 ${route.sourceId}` }] }) },
|
|
2337
|
-
{ label: '技术详情', description: '只读身份与解析证据', run: () => go({ name: 'sourceTechnical', sourceId: route.sourceId }) },
|
|
2338
|
-
];
|
|
2339
|
-
const sourceActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(2, 6));
|
|
2340
|
-
content = _jsxs(Box, { flexDirection: "column", children: [diagnostic
|
|
2341
|
-
? _jsx(DiagnosticSummary, { diagnostic: diagnostic, compact: policy.mode === 'compact' })
|
|
2342
|
-
: _jsxs(_Fragment, { children: [_jsx(StatusCard, { status: state === 'checking' ? 'warning' : 'success', title: state === 'checking' ? '正在检查' : '可用' }), _jsxs(SectionCard, { title: "\u6765\u6E90\u914D\u7F6E", children: [_jsx(StaticRow, { title: "\u4F4D\u7F6E", meta: detail?.locationSummary ?? '不可用' }), _jsx(StaticRow, { title: "\u63D2\u4EF6", meta: `${detail?.pluginCount ?? 0} 个` }), policy.mode === 'compact' ? null : _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: "\u7248\u672C\u9009\u62E9", meta: detail?.type === 'path' ? '本地目录' : detail?.refPolicy === 'explicit' ? '固定 Git 引用' : '跟随 AW 版本通道' }), detail?.explicitRef ? _jsx(StaticRow, { title: "\u5F15\u7528", meta: detail.explicitRef }) : null] })] })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: sourceActionViewport.offset, limit: sourceActionViewport.limit })] });
|
|
2677
|
+
description = activeVersion ? `当前使用 Active Catalog ${activeVersion}。`
|
|
2678
|
+
: metadataInvalid && damagedEntry
|
|
2679
|
+
? `Active Catalog 条目已损坏。先安全删除 AW_HOME 下的精确条目 ${damagedEntry},再运行 ${generation.syncInstruction},然后重新加载 TUI。`
|
|
2680
|
+
: `来源没有可用 Active。请在终端运行 ${generation?.syncInstruction ?? `aw catalog source sync ${route.sourceId}`},然后重新加载 TUI。`;
|
|
2681
|
+
help = '↑↓ 移动 · Enter 选择 · Esc 返回';
|
|
2682
|
+
actions = [
|
|
2683
|
+
{ label: metadataInvalid ? '修复后重新加载 TUI' : '重新加载 TUI', description: metadataInvalid && damagedEntry
|
|
2684
|
+
? `先删除精确条目 ${damagedEntry},再运行 ${generation.syncInstruction}`
|
|
2685
|
+
: `先在终端运行 aw catalog source sync ${route.sourceId},再重新加载 Active`, run: () => props.controller.reloadCatalog({ sourceId: route.sourceId }) },
|
|
2686
|
+
...(!metadataInvalid ? [{ label: '编辑来源…', description: '只修改来源配置;不会访问网络', run: () => go({ name: 'sourceEdit', sourceId: route.sourceId }) }] : []),
|
|
2687
|
+
{ label: '设为主来源…', description: '只改变默认 marketplace', disabled: detail?.primary ? '当前已经是主来源' : undefined, run: () => beginReview({ kind: 'sourceMutation', action: 'setPrimary', sourceId: route.sourceId, changes: [{ title: '主来源', before: snapshot.viewModel?.sourceTabs.find((source) => source.primary)?.id, after: route.sourceId }] }) },
|
|
2688
|
+
{ label: '移除来源…', description: '移除来源配置', status: 'error', disabled: detail?.primary ? '主来源不能直接移除' : undefined, run: () => beginReview({ kind: 'sourceMutation', action: 'remove', sourceId: route.sourceId, changes: [{ title: `移除来源 ${route.sourceId}` }] }) },
|
|
2689
|
+
{ label: '技术详情', description: '查看脱敏错误代码和 Active 证据', run: () => go({ name: 'sourceTechnical', sourceId: route.sourceId }) },
|
|
2690
|
+
];
|
|
2691
|
+
const sourceActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(2, 5));
|
|
2692
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SectionCard, { title: "Active Catalog", status: activeVersion ? 'success' : 'warning', compact: policy.mode === 'compact', children: _jsx(StaticRow, { title: activeVersion ? `Catalog ${activeVersion}` : '未同步', meta: activeVersion ? generation?.active?.digestShort : generation?.syncInstruction, compact: true }) }), _jsxs(SectionCard, { title: "\u6765\u6E90\u914D\u7F6E", compact: policy.mode === 'compact', children: [_jsx(StaticRow, { title: "\u4F4D\u7F6E", meta: detail?.locationSummary ?? '不可用', compact: true }), _jsx(StaticRow, { title: "\u5F15\u7528", meta: generation?.active?.requestedRef ?? detail?.explicitRef ?? detail?.requestedRef ?? '本地目录', compact: true })] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: sourceActionViewport.offset, limit: sourceActionViewport.limit })] });
|
|
2343
2693
|
}
|
|
2344
2694
|
else if (route.name === 'sourceTechnical') {
|
|
2345
2695
|
const overview = props.controller.getSourceOverview(route.sourceId);
|
|
2346
2696
|
const detail = overview.detail;
|
|
2347
2697
|
const state = overview.health?.state ?? overview.source?.state;
|
|
2348
|
-
const diagnostic = sourceDiagnostic(route.sourceId, state, detail) ?? {
|
|
2698
|
+
const diagnostic = sourceDiagnostic(route.sourceId, state, detail, props.controller.getCatalogGeneration(route.sourceId)) ?? {
|
|
2349
2699
|
severity: 'warning',
|
|
2350
2700
|
title: '来源解析详情',
|
|
2351
2701
|
userMessage: '来源当前可用。',
|
|
@@ -2357,7 +2707,6 @@ export function ConsoleAppV4(props) {
|
|
|
2357
2707
|
sourceId: route.sourceId,
|
|
2358
2708
|
...(detail?.requestedRef ? { requestedRef: detail.requestedRef } : {}),
|
|
2359
2709
|
...(detail?.resolvedCommit ? { resolvedCommit: detail.resolvedCommit } : {}),
|
|
2360
|
-
...(detail?.freshness ? { context: [{ key: 'freshness', value: detail.freshness }] } : {}),
|
|
2361
2710
|
},
|
|
2362
2711
|
};
|
|
2363
2712
|
breadcrumb = `插件来源 / ${route.sourceId} / 技术详情`;
|
|
@@ -2383,16 +2732,23 @@ export function ConsoleAppV4(props) {
|
|
|
2383
2732
|
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' });
|
|
2384
2733
|
}
|
|
2385
2734
|
else if (route.step === 'refPolicy') {
|
|
2386
|
-
title = '
|
|
2387
|
-
description = '
|
|
2735
|
+
title = '选择版本来源';
|
|
2736
|
+
description = 'Release 和 Beta 是固定 Git ref 的显示预设。';
|
|
2737
|
+
const useRefPreset = async (refPolicy, ref) => {
|
|
2738
|
+
const next = { ...sourceDraft, refPolicy, ref };
|
|
2739
|
+
setSourceDraft(next);
|
|
2740
|
+
if (next.mode === 'update')
|
|
2741
|
+
await beginSourceUpdateReview(next);
|
|
2742
|
+
else
|
|
2743
|
+
go({ name: 'sourceAdd', step: 'subdir', owner: route.owner });
|
|
2744
|
+
};
|
|
2388
2745
|
actions = [
|
|
2389
|
-
{ label: '跟随 AW
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
{ label: '固定 Git 引用', description: 'branch、tag 或 commit', run: () => { setSourceDraft({ ...sourceDraft, refPolicy: 'explicit' }); go({ name: 'sourceAdd', step: 'ref', owner: route.owner }); } },
|
|
2746
|
+
{ label: '跟随 AW CLI', description: `当前 CLI ${snapshot.cliChannel === 'beta' ? 'beta' : 'release'} → catalog/${snapshot.cliChannel === 'beta' ? 'beta' : 'latest'}`, selected: sourceDraft.refPolicy === 'cliChannel', run: () => { const policy = catalogRefPolicyForPreset('followCli'); return useRefPreset(policy.type, ''); } },
|
|
2747
|
+
{ label: 'Release', description: '固定读取 catalog/latest', selected: sourceDraft.refPolicy === 'explicit' && sourceDraft.ref === CATALOG_LATEST_REF, run: () => { const policy = catalogRefPolicyForPreset('release'); return useRefPreset(policy.type, policy.type === 'explicit' ? policy.ref : ''); } },
|
|
2748
|
+
{ label: 'Beta', description: '固定读取 catalog/beta', selected: sourceDraft.refPolicy === 'explicit' && sourceDraft.ref === CATALOG_BETA_REF, run: () => { const policy = catalogRefPolicyForPreset('beta'); return useRefPreset(policy.type, policy.type === 'explicit' ? policy.ref : ''); } },
|
|
2749
|
+
{ label: '指定 Git ref…', description: 'branch、tag、完整 ref 或 commit', selected: sourceDraft.refPolicy === 'explicit' && sourceDraft.ref !== CATALOG_LATEST_REF && sourceDraft.ref !== CATALOG_BETA_REF, run: () => { setSourceDraft({ ...sourceDraft, refPolicy: 'explicit' }); go({ name: 'sourceAdd', step: 'ref', owner: route.owner }); } },
|
|
2394
2750
|
];
|
|
2395
|
-
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' });
|
|
2751
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: tuiTheme.colors.muted, children: ["\u8DDF\u968F\u542B\u4E49\uFF1A\u5F53\u524D CLI ", snapshot.cliChannel === 'beta' ? 'beta → catalog/beta' : 'release → catalog/latest'] }), _jsx(SemanticRows, { actions: actions, focus: focus, kind: "choice", compact: policy.mode === 'compact' })] });
|
|
2396
2752
|
}
|
|
2397
2753
|
else {
|
|
2398
2754
|
title = route.step === 'id' ? '输入来源 ID' : route.step === 'location' ? `输入 ${sourceDraft.type === 'git' ? 'Git URL' : '绝对路径'}` : route.step === 'ref' ? '输入固定 Git 引用' : '输入 Catalog 子目录';
|
|
@@ -2402,7 +2758,7 @@ export function ConsoleAppV4(props) {
|
|
|
2402
2758
|
: route.step === 'location' && sourceDraft.type === 'path'
|
|
2403
2759
|
? privatePathInput(sourceInput)
|
|
2404
2760
|
: sourceInput;
|
|
2405
|
-
content = _jsx(InputCard, { focused: true, title: displayedInput
|
|
2761
|
+
content = _jsx(InputCard, { focused: true, title: _jsx(InputDisplay, { value: displayedInput, columns: Math.max(8, size.columns - 8) }), description: sourceInputError ?? (route.step === 'location' && sourceDraft.type === 'path' ? '已隐藏父目录;Backspace 仍会编辑原始输入。' : '按 Enter 继续。'), status: sourceInputError ? 'error' : undefined });
|
|
2406
2762
|
}
|
|
2407
2763
|
}
|
|
2408
2764
|
else if (route.name === 'sourceEdit') {
|
|
@@ -2418,12 +2774,35 @@ export function ConsoleAppV4(props) {
|
|
|
2418
2774
|
setDirty(true);
|
|
2419
2775
|
go({ name: 'sourceAdd', step: field === 'location' ? 'location' : field === 'subdir' ? 'subdir' : 'refPolicy', owner });
|
|
2420
2776
|
};
|
|
2777
|
+
const switchOfficialTransport = (location) => {
|
|
2778
|
+
if (!detail || detail.type !== 'git'
|
|
2779
|
+
|| detail.locationSummary === projectCatalogSourceLocation(location))
|
|
2780
|
+
return;
|
|
2781
|
+
const owner = `source-update:${route.sourceId}:location:${Date.now()}`;
|
|
2782
|
+
const next = {
|
|
2783
|
+
owner,
|
|
2784
|
+
mode: 'update',
|
|
2785
|
+
sourceId: route.sourceId,
|
|
2786
|
+
type: 'git',
|
|
2787
|
+
location,
|
|
2788
|
+
refPolicy: detail.refPolicy ?? 'cliChannel',
|
|
2789
|
+
ref: detail.explicitRef ?? '',
|
|
2790
|
+
subdir: detail.subdir ?? '',
|
|
2791
|
+
editField: 'location',
|
|
2792
|
+
};
|
|
2793
|
+
setSourceDraft(next);
|
|
2794
|
+
setDirty(true);
|
|
2795
|
+
void beginSourceUpdateReview(next);
|
|
2796
|
+
};
|
|
2421
2797
|
actions = detail?.type === 'git' ? [
|
|
2422
|
-
|
|
2798
|
+
...(route.sourceId === 'official' ? [
|
|
2799
|
+
{ label: 'HTTPS', description: '使用系统 Git credential helper', selected: detail.locationSummary === projectCatalogSourceLocation(OFFICIAL_CATALOG_SOURCE_URL), run: () => switchOfficialTransport(OFFICIAL_CATALOG_SOURCE_URL) },
|
|
2800
|
+
{ label: 'SSH', description: '使用本机 SSH key;Git 连接使用 BatchMode', selected: detail.locationSummary === projectCatalogSourceLocation(OFFICIAL_CATALOG_SOURCE_SSH_URL), run: () => switchOfficialTransport(OFFICIAL_CATALOG_SOURCE_SSH_URL) },
|
|
2801
|
+
] : [{ label: 'Git URL', description: detail.locationSummary, run: () => startEdit('location') }]),
|
|
2423
2802
|
{ label: '版本引用', description: detail.refPolicy === 'explicit' ? `固定:${detail.explicitRef}` : '跟随 AW 版本通道', run: () => startEdit('refPolicy') },
|
|
2424
2803
|
{ label: 'Catalog 子目录', description: detail.subdir ?? '未设置', run: () => startEdit('subdir') },
|
|
2425
2804
|
] : [{ label: '本地目录', description: '已选择本地目录', run: () => startEdit('location') }];
|
|
2426
|
-
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "section", compact: policy.mode === 'compact' });
|
|
2805
|
+
content = _jsxs(Box, { flexDirection: "column", children: [_jsx(SemanticRows, { actions: actions, focus: focus, kind: "section", compact: policy.mode === 'compact' }), route.sourceId === 'official' && detail?.type === 'git' ? _jsxs(SectionCard, { title: "\u6765\u6E90\u8EAB\u4EFD", children: [_jsx(StaticRow, { title: "\u903B\u8F91 Catalog", meta: "lesliechan721-arch/agent-workflow" }), _jsx(StaticRow, { title: "source identity", meta: "HTTPS / SSH \u4FDD\u6301\u4E00\u81F4" }), _jsx(StaticRow, { title: "\u660E\u6587 HTTP", meta: "\u4E0D\u652F\u6301", status: "warning" })] }) : null] });
|
|
2427
2806
|
}
|
|
2428
2807
|
else if (route.name === 'sourceRemoveBlocked') {
|
|
2429
2808
|
breadcrumb = `插件来源 / ${route.sourceId} / 移除`;
|
|
@@ -2456,7 +2835,7 @@ export function ConsoleAppV4(props) {
|
|
|
2456
2835
|
description: entry.category.startsWith('dependency')
|
|
2457
2836
|
? `${props.controller.getPluginOverview(entry.dependencyPluginId ?? '')?.displayName ?? entry.dependencyPluginId ?? entry.explanation} · ${entry.impact[0] ?? ''}`
|
|
2458
2837
|
: `${entry.explanation} · ${entry.impact[0] ?? ''}`,
|
|
2459
|
-
status:
|
|
2838
|
+
status: 'error',
|
|
2460
2839
|
run: () => entry.category === 'dependencyStillRequired' && entry.pluginId
|
|
2461
2840
|
? go({ name: 'pluginDependencies', pluginId: entry.pluginId, view: 'removeBlocked',
|
|
2462
2841
|
...(entry.platform ? { platform: entry.platform } : {}),
|
|
@@ -2465,7 +2844,27 @@ export function ConsoleAppV4(props) {
|
|
|
2465
2844
|
}));
|
|
2466
2845
|
}
|
|
2467
2846
|
const viewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, responsiveBudget(8, 12));
|
|
2468
|
-
|
|
2847
|
+
if (issues.length === 0) {
|
|
2848
|
+
content = _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: viewport.offset, limit: viewport.limit });
|
|
2849
|
+
}
|
|
2850
|
+
else {
|
|
2851
|
+
const groupCounts = new Map();
|
|
2852
|
+
for (const issueEntry of issues) {
|
|
2853
|
+
groupCounts.set(issueEntry.group, (groupCounts.get(issueEntry.group) ?? 0) + 1);
|
|
2854
|
+
}
|
|
2855
|
+
const visibleGroups = [];
|
|
2856
|
+
const visibleEnd = Math.min(actions.length, viewport.offset + viewport.limit);
|
|
2857
|
+
for (let index = viewport.offset; index < visibleEnd; index += 1) {
|
|
2858
|
+
const group = issues[index].group;
|
|
2859
|
+
const currentGroup = visibleGroups.at(-1);
|
|
2860
|
+
if (!currentGroup || currentGroup.group !== group) {
|
|
2861
|
+
visibleGroups.push({ group, startIndex: index, actions: [actions[index]] });
|
|
2862
|
+
}
|
|
2863
|
+
else
|
|
2864
|
+
currentGroup.actions.push(actions[index]);
|
|
2865
|
+
}
|
|
2866
|
+
content = _jsx(Box, { flexDirection: "column", children: visibleGroups.map((group) => _jsx(SectionCard, { title: issueGroupLabel(group.group), meta: `${groupCounts.get(group.group) ?? group.actions.length} 项`, compact: policy.mode === 'compact', children: _jsx(SemanticRows, { actions: group.actions, focus: focus - group.startIndex, kind: "task", compact: policy.mode === 'compact' }) }, `${group.group}:${group.startIndex}`)) });
|
|
2867
|
+
}
|
|
2469
2868
|
}
|
|
2470
2869
|
else if (route.name === 'issueDetail' && issue) {
|
|
2471
2870
|
breadcrumb = `需要处理 / ${issue.pluginId ?? issue.sourceId ?? issue.entity.id}`;
|
|
@@ -2479,8 +2878,8 @@ export function ConsoleAppV4(props) {
|
|
|
2479
2878
|
return;
|
|
2480
2879
|
}
|
|
2481
2880
|
if (entry.id === 'refreshSource' && issue.sourceId)
|
|
2482
|
-
await props.controller.
|
|
2483
|
-
else if (entry.id === '
|
|
2881
|
+
await props.controller.reloadCatalog({ sourceId: issue.sourceId });
|
|
2882
|
+
else if (entry.id === 'retryLater')
|
|
2484
2883
|
go({ name: 'issueList' });
|
|
2485
2884
|
else if (entry.id === 'editSource' && issue.sourceId)
|
|
2486
2885
|
go(issue.entity.kind === 'source'
|
|
@@ -2519,7 +2918,8 @@ export function ConsoleAppV4(props) {
|
|
|
2519
2918
|
}));
|
|
2520
2919
|
const issuePlugin = issue.pluginId ? props.controller.getPluginOverview(issue.pluginId) : undefined;
|
|
2521
2920
|
const issueOverview = issue.pluginId ? props.controller.getPluginDependencyOverview(issue.pluginId) : undefined;
|
|
2522
|
-
const issueDiagnosticSummary = _jsx(DiagnosticSummary, { diagnostic: issue.diagnostic, technical: showTechnical, compact: policy.mode === 'compact' || issue.category.startsWith('dependency')
|
|
2921
|
+
const issueDiagnosticSummary = _jsx(DiagnosticSummary, { diagnostic: issue.diagnostic, technical: showTechnical, compact: policy.mode === 'compact' || issue.category.startsWith('dependency')
|
|
2922
|
+
|| issue.category === 'scopeConflict' });
|
|
2523
2923
|
const issueActionViewport = actionViewport(actions, policy.mode === 'compact', focus, scrollOffset, pageActionBudget(6));
|
|
2524
2924
|
const compactTechnicalActionViewport = policy.mode === 'compact' && showTechnical
|
|
2525
2925
|
? {
|
|
@@ -2566,12 +2966,15 @@ export function ConsoleAppV4(props) {
|
|
|
2566
2966
|
setScope(issueScope);
|
|
2567
2967
|
setSelectedTargets([entry.platform]);
|
|
2568
2968
|
setTargetSelections((current) => ({ ...current, [issueScope]: [entry.platform] }));
|
|
2969
|
+
props.controller.beginInstallFlow(issuePlugin.pluginId, issueScope);
|
|
2970
|
+
props.controller.setInstallPlatforms([entry.platform]);
|
|
2569
2971
|
go({ name: 'installTargets', pluginId: issuePlugin.pluginId });
|
|
2570
2972
|
} })),
|
|
2571
2973
|
{ label: '返回调整目标平台', run: () => {
|
|
2572
2974
|
setScope(issueScope);
|
|
2573
2975
|
setSelectedTargets([]);
|
|
2574
2976
|
setTargetSelections((current) => ({ ...current, [issueScope]: [] }));
|
|
2977
|
+
props.controller.beginInstallFlow(issuePlugin.pluginId, issueScope);
|
|
2575
2978
|
go({ name: 'installTargets', pluginId: issuePlugin.pluginId });
|
|
2576
2979
|
} },
|
|
2577
2980
|
{ label: '查看依赖关系', run: () => go({ name: 'pluginDependencies', pluginId: issuePlugin.pluginId }) },
|
|
@@ -2595,12 +2998,9 @@ export function ConsoleAppV4(props) {
|
|
|
2595
2998
|
content = _jsxs(Box, { flexDirection: "column", children: [issueDiagnosticSummary, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact' })] });
|
|
2596
2999
|
}
|
|
2597
3000
|
else {
|
|
2598
|
-
const
|
|
2599
|
-
? `aw cleanup ${issue.pluginId} --platform ${issue.platform} --scope ${issue.scope}`
|
|
2600
|
-
: undefined;
|
|
2601
|
-
const hasRecoveryEvidence = sourceMissingCleanup || issue.category === 'sourceIdentityChanged'
|
|
3001
|
+
const hasRecoveryEvidence = issue.category === 'sourceIdentityChanged'
|
|
2602
3002
|
|| issue.placements || issue.requiredFields;
|
|
2603
|
-
const recoveryRows = _jsxs(_Fragment, { children: [
|
|
3003
|
+
const recoveryRows = _jsxs(_Fragment, { children: [issue.category === 'sourceIdentityChanged' ? _jsx(StaticRow, { title: "\u6765\u6E90\u8EAB\u4EFD\u5DF2\u53D8\u5316\uFF1B\u8BF7\u786E\u8BA4\u53D8\u66F4\u6216\u6062\u590D\u539F\u6765\u6E90\u3002", status: "warning", compact: true }) : null, issue.placements ? _jsx(StaticRow, { title: "\u4F4D\u7F6E", meta: issue.placements.map(scopeLabel).join('、'), compact: true }) : null, issue.requiredFields ? _jsx(StaticRow, { title: "\u5B57\u6BB5", meta: sanitizeDiagnosticText(issue.requiredFields.map((field) => field.title).join('、')), compact: true }) : null] });
|
|
2604
3004
|
content = _jsxs(Box, { flexDirection: "column", children: [issueDiagnosticSummary, !showTechnical && hasRecoveryEvidence
|
|
2605
3005
|
? policy.mode === 'compact' ? recoveryRows : _jsx(SectionCard, { title: "\u6062\u590D\u8BC1\u636E", children: recoveryRows })
|
|
2606
3006
|
: null, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: policy.mode === 'compact', offset: issueActionViewport.offset, limit: issueActionViewport.limit })] });
|
|
@@ -2638,11 +3038,24 @@ export function ConsoleAppV4(props) {
|
|
|
2638
3038
|
}
|
|
2639
3039
|
else if (route.name === 'review' && snapshot.activeReview) {
|
|
2640
3040
|
const review = snapshot.activeReview;
|
|
3041
|
+
const sharedImpactConfirmed = !review.requiresConfirmation
|
|
3042
|
+
|| confirmedSharedReviewToken === review.reviewToken;
|
|
2641
3043
|
breadcrumb = `${review.subject.name} / ${review.title}`;
|
|
2642
3044
|
title = `${snapshot.result?.state === 'stale' ? '状态已变化 · ' : ''}${review.operationKind === 'portableInstall' ? review.title : `确认${review.title}`} ${review.subject.name}`;
|
|
2643
|
-
description = snapshot.result?.state === 'stale'
|
|
3045
|
+
description = snapshot.result?.state === 'stale'
|
|
3046
|
+
? '当前状态已变化。请检查新的变化后再次确认。'
|
|
3047
|
+
: review.requiresConfirmation ? '' : review.description;
|
|
2644
3048
|
actions = [
|
|
2645
|
-
|
|
3049
|
+
...(review.requiresConfirmation ? [{
|
|
3050
|
+
label: sharedImpactConfirmed ? '已确认 shared impact' : '确认 shared impact',
|
|
3051
|
+
description: review.sharedImpact.warning ?? '此操作会修改多个插件共享的 Codex native 内容',
|
|
3052
|
+
selected: sharedImpactConfirmed,
|
|
3053
|
+
run: () => {
|
|
3054
|
+
setConfirmedSharedReviewToken(review.reviewToken);
|
|
3055
|
+
setFocus(1);
|
|
3056
|
+
},
|
|
3057
|
+
}] : []),
|
|
3058
|
+
{ label: review.primaryLabel, description: '执行前将再次检查当前状态', status: review.destructive ? 'error' : undefined, disabled: sharedImpactConfirmed ? undefined : '请先显式确认 shared impact', run: () => {
|
|
2646
3059
|
if (operationBusy.current)
|
|
2647
3060
|
return;
|
|
2648
3061
|
operationBusy.current = true;
|
|
@@ -2661,18 +3074,28 @@ export function ConsoleAppV4(props) {
|
|
|
2661
3074
|
: back },
|
|
2662
3075
|
];
|
|
2663
3076
|
const groupedChanges = review.changes.some((change) => change.group);
|
|
3077
|
+
const compressedReview = policy.mode === 'compact' || review.requiresConfirmation;
|
|
2664
3078
|
const groupTitle = {
|
|
2665
3079
|
requested: review.operationKind === 'portableInstall' ? '已选择 Skills · 当前插件' : '你选择的插件',
|
|
2666
3080
|
dependencies: review.operationKind === 'portableInstall' ? '已选择 Skills · 来自依赖插件' : '必需依赖',
|
|
3081
|
+
projectIntent: 'Project intent',
|
|
3082
|
+
userIntent: 'User intent',
|
|
3083
|
+
sharedCodexNative: 'Shared Codex native',
|
|
3084
|
+
userActivation: 'User activation',
|
|
3085
|
+
projectActivation: 'Project activation',
|
|
3086
|
+
awExtensions: 'AW extensions',
|
|
3087
|
+
runtime: 'Codex runtime',
|
|
2667
3088
|
portableTarget: '安装目标',
|
|
2668
3089
|
portableInputs: '准备内容',
|
|
2669
3090
|
portableWarnings: '覆盖冲突',
|
|
3091
|
+
configChanges: '设置变更',
|
|
3092
|
+
configImpact: '应用影响',
|
|
2670
3093
|
preserved: '保持不变',
|
|
2671
3094
|
};
|
|
2672
3095
|
const changeStatus = (change) => change.kind === 'remove' ? 'error'
|
|
2673
3096
|
: change.kind === 'warning' ? 'warning'
|
|
2674
3097
|
: change.kind === 'keep' || change.kind === 'add' ? 'success' : undefined;
|
|
2675
|
-
const groupOrder = ['portableWarnings', 'portableTarget', 'requested', 'dependencies', 'preserved', 'portableInputs'];
|
|
3098
|
+
const groupOrder = ['portableWarnings', 'portableTarget', 'configChanges', 'configImpact', 'requested', 'dependencies', 'projectIntent', 'userIntent', 'sharedCodexNative', 'userActivation', 'projectActivation', 'awExtensions', 'runtime', 'preserved', 'portableInputs'];
|
|
2676
3099
|
const groupedSpecs = groupedChanges
|
|
2677
3100
|
? groupOrder.map((group) => ({
|
|
2678
3101
|
key: group,
|
|
@@ -2686,7 +3109,7 @@ export function ConsoleAppV4(props) {
|
|
|
2686
3109
|
{ key: 'changes', label: undefined, protectedCount: false, changes: review.changes.filter((change) => change.kind !== 'warning' && change.kind !== 'keep') },
|
|
2687
3110
|
];
|
|
2688
3111
|
const visibleSpecs = groupedSpecs.filter((group) => group.changes.length > 0);
|
|
2689
|
-
const headingLines =
|
|
3112
|
+
const headingLines = compressedReview ? 0 : visibleSpecs.filter((group) => group.label).length;
|
|
2690
3113
|
const staticRowBudget = Math.max(visibleSpecs.length, responsiveBudget(7, 12) - headingLines);
|
|
2691
3114
|
const allocations = new Map(visibleSpecs.map((group) => [group.key, 1]));
|
|
2692
3115
|
const targetGroup = visibleSpecs.find((group) => group.key === 'portableTarget');
|
|
@@ -2705,14 +3128,15 @@ export function ConsoleAppV4(props) {
|
|
|
2705
3128
|
const changeGroups = visibleSpecs.map((group) => {
|
|
2706
3129
|
const visibleCount = allocations.get(group.key) ?? 1;
|
|
2707
3130
|
const hiddenCount = group.changes.length - visibleCount;
|
|
2708
|
-
return _jsxs(Box, { flexDirection: "column", children: [
|
|
3131
|
+
return _jsxs(Box, { flexDirection: "column", children: [!compressedReview && group.label ? _jsx(Text, { bold: true, color: tuiTheme.colors.muted, children: group.label }) : null, group.changes.slice(0, visibleCount).map((change, index) => {
|
|
2709
3132
|
const retainDescription = change.kind === 'warning' || group.key === 'portableTarget'
|
|
2710
|
-
|| group.key === 'requested' || group.key === 'dependencies'
|
|
3133
|
+
|| group.key === 'requested' || group.key === 'dependencies'
|
|
3134
|
+
|| group.key === 'configChanges' || group.key === 'configImpact';
|
|
2711
3135
|
const description = retainDescription ? change.description : undefined;
|
|
2712
3136
|
const compactGroupLabel = group.key === 'requested' ? '根插件'
|
|
2713
3137
|
: group.key === 'dependencies' ? '依赖'
|
|
2714
3138
|
: group.key === 'preserved' ? '保持' : group.label;
|
|
2715
|
-
const category =
|
|
3139
|
+
const category = compressedReview && index === 0 && compactGroupLabel ? `${compactGroupLabel} · ` : '';
|
|
2716
3140
|
const count = index === visibleCount - 1 && (hiddenCount > 0 || group.protectedCount)
|
|
2717
3141
|
? hiddenCount > 0 ? `另有 ${hiddenCount} 项` : `共 ${group.changes.length} 项`
|
|
2718
3142
|
: undefined;
|
|
@@ -2737,7 +3161,9 @@ export function ConsoleAppV4(props) {
|
|
|
2737
3161
|
return _jsx(ReviewChangeRow, { title: `${category ? `${category} · ` : ''}${reviewSymbol(change)} ${change.title}${change.description ? ` · ${change.description}` : ''}`, meta: index === visibleTechnicalChanges.length - 1 && hiddenTechnicalChanges > 0
|
|
2738
3162
|
? `另有 ${hiddenTechnicalChanges} 项` : undefined, status: changeStatus(change), compact: true }, `${change.title}:${index}`);
|
|
2739
3163
|
});
|
|
2740
|
-
|
|
3164
|
+
const showEquivalentCommand = Boolean(review.equivalentCommand
|
|
3165
|
+
&& (!review.requiresConfirmation || showTechnical));
|
|
3166
|
+
content = _jsx(Box, { flexDirection: "column", children: _jsxs(ReviewCard, { title: review.requiresConfirmation ? undefined : review.subject.name, meta: review.requiresConfirmation ? undefined : `${review.subject.sourceLabel ?? ''} ${review.subject.version ?? ''}`, description: showEquivalentCommand ? review.description : undefined, children: [showEquivalentCommand ? _jsxs(Text, { children: ["\u7B49\u4EF7\u547D\u4EE4\uFF1A", review.equivalentCommand] }) : null, review.catalogBinding ? _jsxs(_Fragment, { children: [_jsx(StaticRow, { title: `Catalog:${review.catalogBinding.sourceId} ${review.catalogBinding.catalogVersion} · 当前使用`, meta: `generation ${review.catalogBinding.generationDigestShort}`, status: "success", compact: true }), _jsx(StaticRow, { title: "\u64CD\u4F5C\u671F\u95F4\u4E0D\u68C0\u67E5\u8FDC\u7AEF Catalog", status: "success", compact: true })] }) : null, review.requiresConfirmation ? _jsx(StaticRow, { title: "! Shared impact \u9700\u8981\u663E\u5F0F\u786E\u8BA4", meta: review.sharedImpact.pluginIds.length > 0 ? `${review.sharedImpact.pluginIds.length} 个插件` : undefined, description: review.sharedImpact.warning, status: "warning", compact: true }) : null, showTechnical ? technicalChanges : changeGroups, _jsx(SemanticRows, { actions: actions, focus: focus, kind: "action", compact: true }), compressedReview || showTechnical ? null : _jsx(StaticRow, { title: "\u6280\u672F\u8BE6\u60C5\uFF08d\uFF09", status: "muted" }), showTechnical ? _jsx(TechnicalDetails, { children: visibleTechnicalDetails.map((detail, index) => _jsx(StaticRow, { title: detail, meta: index === visibleTechnicalDetails.length - 1 && hiddenTechnicalDetails > 0 ? `另有 ${hiddenTechnicalDetails} 项` : undefined, compact: true }, detail)) }) : null] }) });
|
|
2741
3167
|
}
|
|
2742
3168
|
else if (route.name === 'progress') {
|
|
2743
3169
|
const portableOperation = snapshot.activeReview?.operationKind === 'portableInstall';
|
|
@@ -2746,8 +3172,8 @@ export function ConsoleAppV4(props) {
|
|
|
2746
3172
|
const sourceOperation = snapshot.activeReview?.operationKind === 'sourceMutation';
|
|
2747
3173
|
const issueOperation = snapshot.activeReview?.originIssue;
|
|
2748
3174
|
breadcrumb = portableOperation ? '通用 Skills / 进度' : issueOperation ? '需要处理 / 进度' : sourceOperation ? '插件来源 / 保存' : configOperation ? '设置 / 进度' : '插件操作 / 进度';
|
|
2749
|
-
title = portableOperation ? '正在安装通用 Skills' : issueOperation ? '正在处理问题' : sourceOperation ? '
|
|
2750
|
-
description = issueOperation ? '完成后会使用新的状态 generation 重新检查问题。' : sourceOperation ? '
|
|
3175
|
+
title = portableOperation ? '正在安装通用 Skills' : issueOperation ? '正在处理问题' : sourceOperation ? '正在保存来源配置' : configOperation ? '正在保存并应用设置' : '正在执行插件操作';
|
|
3176
|
+
description = issueOperation ? '完成后会使用新的状态 generation 重新检查问题。' : sourceOperation ? '只原子保存来源配置,不访问网络。' : configOperation ? '先保存所选层,再重新应用当前可见安装位置。' : '请勿关闭当前终端。';
|
|
2751
3177
|
help = 'Ctrl-C 完成后退出';
|
|
2752
3178
|
const progress = snapshot.progress;
|
|
2753
3179
|
const elapsedSeconds = Math.max(0, Math.floor(((progress.elapsedMs
|
|
@@ -2847,7 +3273,7 @@ export function ConsoleAppV4(props) {
|
|
|
2847
3273
|
return step === 2 ? '正在安装' : step === 3 ? '正在验证' : step === 1 ? '正在生成' : '正在检查';
|
|
2848
3274
|
};
|
|
2849
3275
|
const compactPortableProgress = policy.mode === 'compact' && showTechnical;
|
|
2850
|
-
content = portableOperation ? _jsxs(StatusCard, { status: failedProgress ? 'error' : 'info', title: "Skills CLI", children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u63D2\u4EF6\u548C\u4F9D\u8D56", description: `${snapshot.activeReview?.subject.name ?? '当前插件'} · ${portableDraft?.dependencySummary?.directCount ?? 0} 个直接依赖`, meta: portableProgressMeta(0), state: portableProgressState(0), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u751F\u6210\u5DF2\u9009\u5019\u9009 Skills", description: `${portableProviderCount} 个 provider 提供 ${portableSelectedCount} 个 Skills`, meta: portableProgressMeta(1), state: portableProgressState(1), compact: compactPortableProgress }), _jsx(ProgressRow, { title: `安装已选择的 ${portableSelectedCount} 个 Skills`, description: `Agent:${portableDraft?.agentMode === 'explicit' ? portableDraft.requestedAgents.join('、') : 'Skills CLI 默认选择'}`, meta: portableProgressMeta(2), state: portableProgressState(2), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", description: "\u9010\u9879\u786E\u8BA4\u6240\u9009 Skill \u7684\u5B89\u88C5\u76EE\u6807", meta: portableProgressMeta(3), state: portableProgressState(3), compact: compactPortableProgress }), showTechnical ? _jsxs(TechnicalDetails, { children: [technicalMessages.map((message, index) => _jsx(StaticRow, { title: message, compact: true }, `${index}:${message}`)), hiddenTechnicalMessages > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenTechnicalMessages} 条技术消息`, status: "muted", compact: true }) : null] }) : null] }) : _jsxs(StatusCard, { status: "info", children: [dependencyProgress ? _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u4F9D\u8D56\u5173\u7CFB", state: relationStep }), _jsx(ProgressRow, { title: "\u751F\u6210\u6267\u884C\u8BA1\u5212", state: planStep }), _jsx(ProgressRow, { title: "\u6267\u884C\u4F9D\u8D56\u95ED\u5305", description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: closureStep, compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u5B8C\u6574\u7ED3\u679C", state: verificationStep })] }) : _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: sourceOperation ? '检查来源操作输入' : configOperation ? '验证设置值' : '检查兼容性', state: !currentPhase ? 'pending' : preflightActive ? 'active' : 'complete' }), _jsx(ProgressRow, { title: progress.current?.phase || (sourceOperation ? '
|
|
3276
|
+
content = portableOperation ? _jsxs(StatusCard, { status: failedProgress ? 'error' : 'info', title: "Skills CLI", children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u63D2\u4EF6\u548C\u4F9D\u8D56", description: `${snapshot.activeReview?.subject.name ?? '当前插件'} · ${portableDraft?.dependencySummary?.directCount ?? 0} 个直接依赖`, meta: portableProgressMeta(0), state: portableProgressState(0), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u751F\u6210\u5DF2\u9009\u5019\u9009 Skills", description: `${portableProviderCount} 个 provider 提供 ${portableSelectedCount} 个 Skills`, meta: portableProgressMeta(1), state: portableProgressState(1), compact: compactPortableProgress }), _jsx(ProgressRow, { title: `安装已选择的 ${portableSelectedCount} 个 Skills`, description: `Agent:${portableDraft?.agentMode === 'explicit' ? portableDraft.requestedAgents.join('、') : 'Skills CLI 默认选择'}`, meta: portableProgressMeta(2), state: portableProgressState(2), compact: compactPortableProgress }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", description: "\u9010\u9879\u786E\u8BA4\u6240\u9009 Skill \u7684\u5B89\u88C5\u76EE\u6807", meta: portableProgressMeta(3), state: portableProgressState(3), compact: compactPortableProgress }), showTechnical ? _jsxs(TechnicalDetails, { children: [technicalMessages.map((message, index) => _jsx(StaticRow, { title: message, compact: true }, `${index}:${message}`)), hiddenTechnicalMessages > 0 ? _jsx(StaticRow, { title: `另有 ${hiddenTechnicalMessages} 条技术消息`, status: "muted", compact: true }) : null] }) : null] }) : _jsxs(StatusCard, { status: "info", children: [dependencyProgress ? _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: "\u68C0\u67E5\u4F9D\u8D56\u5173\u7CFB", state: relationStep }), _jsx(ProgressRow, { title: "\u751F\u6210\u6267\u884C\u8BA1\u5212", state: planStep }), _jsx(ProgressRow, { title: "\u6267\u884C\u4F9D\u8D56\u95ED\u5305", description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: closureStep, compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u5B8C\u6574\u7ED3\u679C", state: verificationStep })] }) : _jsxs(_Fragment, { children: [_jsx(ProgressRow, { title: sourceOperation ? '检查来源操作输入' : configOperation ? '验证设置值' : '检查兼容性', state: !currentPhase ? 'pending' : preflightActive ? 'active' : 'complete' }), _jsx(ProgressRow, { title: progress.current?.phase || (sourceOperation ? '保存来源配置' : configOperation ? '保存设置层并重新应用' : '连接到所选目标平台'), description: progress.current?.target ? `当前:${progress.current.target}` : undefined, meta: `${elapsedSeconds}s`, state: failedProgress ? 'error' : executionActive ? 'active' : validationActive ? 'complete' : 'pending', compact: policy.mode === 'compact' }), _jsx(ProgressRow, { title: "\u9A8C\u8BC1\u7ED3\u679C", state: failedProgress ? 'error' : validationActive ? 'active' : 'pending' })] }), dependencyProgress ? _jsxs(SectionCard, { title: "\u6267\u884C\u76EE\u6807", meta: `${snapshot.progressTargets.length} 个目标`, children: [visibleProgressTargets.map((entry) => {
|
|
2851
3277
|
const state = progressLabel(entry);
|
|
2852
3278
|
const relation = entry.relation === 'requested' ? '你选择的插件' : entry.relation === 'direct' ? '直接依赖' : '间接依赖';
|
|
2853
3279
|
const title = props.controller.getPluginOverview(entry.pluginId)?.displayName
|
|
@@ -2877,8 +3303,6 @@ export function ConsoleAppV4(props) {
|
|
|
2877
3303
|
? operationKind : undefined;
|
|
2878
3304
|
const successfulConfigOperation = configOperation !== undefined && !blocked && !partial;
|
|
2879
3305
|
const sourceOperation = operationKind === 'sourceMutation';
|
|
2880
|
-
const sourceRefreshWarning = sourceOperation && 'summary' in result
|
|
2881
|
-
&& result.summary?.messages?.some((message) => message.startsWith('警告:'));
|
|
2882
3306
|
const issueOperation = result.originIssue;
|
|
2883
3307
|
const completedTitle = {
|
|
2884
3308
|
install: '✓ 插件添加完成',
|
|
@@ -2886,6 +3310,7 @@ export function ConsoleAppV4(props) {
|
|
|
2886
3310
|
reinstall: '✓ 插件重新安装完成',
|
|
2887
3311
|
uninstall: '✓ 插件移除完成',
|
|
2888
3312
|
cleanup: '✓ 插件清理完成',
|
|
3313
|
+
sync: '✓ 插件同步完成',
|
|
2889
3314
|
}[action ?? 'install'];
|
|
2890
3315
|
title = portableOperation
|
|
2891
3316
|
? blocked ? '× 通用 Skills 安装被阻止'
|
|
@@ -2895,7 +3320,7 @@ export function ConsoleAppV4(props) {
|
|
|
2895
3320
|
: issueOperation
|
|
2896
3321
|
? blocked || partial ? '× 问题仍未解决' : '✓ 问题已处理'
|
|
2897
3322
|
: sourceOperation
|
|
2898
|
-
? blocked ? '× 来源操作未完成' :
|
|
3323
|
+
? blocked ? '× 来源操作未完成' : '✓ 来源配置已保存'
|
|
2899
3324
|
: configOperation
|
|
2900
3325
|
? blocked
|
|
2901
3326
|
? '× 设置未确认保存'
|
|
@@ -2926,11 +3351,9 @@ export function ConsoleAppV4(props) {
|
|
|
2926
3351
|
: sourceOperation
|
|
2927
3352
|
? blocked
|
|
2928
3353
|
? result.writeMayHaveCompleted
|
|
2929
|
-
? '
|
|
3354
|
+
? '来源配置可能已保存。请重新检查来源列表。'
|
|
2930
3355
|
: '来源操作未执行。草稿已保留,可返回修改。'
|
|
2931
|
-
:
|
|
2932
|
-
? '来源配置已保留。请根据警告修复来源后重试刷新。'
|
|
2933
|
-
: '来源配置已保存,刷新已完成。'
|
|
3356
|
+
: '来源配置已保存。请在终端运行 aw catalog source sync,然后重新加载 TUI。'
|
|
2934
3357
|
: blocked ? result.message
|
|
2935
3358
|
: configOperation ? '设置层已经更新。' : '状态已刷新。';
|
|
2936
3359
|
const pluginId = resultSummary?.pluginId
|
|
@@ -3212,7 +3635,9 @@ export function ConsoleAppV4(props) {
|
|
|
3212
3635
|
try {
|
|
3213
3636
|
const pending = action.run?.();
|
|
3214
3637
|
if (pending)
|
|
3215
|
-
void pending.catch(() => {
|
|
3638
|
+
void pending.catch((error) => {
|
|
3639
|
+
if (error instanceof Error && error.name === 'AbortError')
|
|
3640
|
+
return;
|
|
3216
3641
|
setActionError('操作未完成。请重新检查后重试。');
|
|
3217
3642
|
});
|
|
3218
3643
|
}
|
|
@@ -3326,7 +3751,7 @@ export function ConsoleAppV4(props) {
|
|
|
3326
3751
|
return;
|
|
3327
3752
|
}
|
|
3328
3753
|
if (key.backspace || key.delete)
|
|
3329
|
-
setPortableAgentInput(
|
|
3754
|
+
setPortableAgentInput(removeLastGrapheme);
|
|
3330
3755
|
else if (input && !key.ctrl && !key.meta && input >= ' ')
|
|
3331
3756
|
setPortableAgentInput((value) => value + input);
|
|
3332
3757
|
setInputError(undefined);
|
|
@@ -3413,7 +3838,7 @@ export function ConsoleAppV4(props) {
|
|
|
3413
3838
|
return;
|
|
3414
3839
|
}
|
|
3415
3840
|
if (key.backspace || key.delete)
|
|
3416
|
-
setSourceInput(
|
|
3841
|
+
setSourceInput(removeLastGrapheme);
|
|
3417
3842
|
else if (input && !key.ctrl && !key.meta && input >= ' ')
|
|
3418
3843
|
setSourceInput((value) => value + input);
|
|
3419
3844
|
setSourceInputError(undefined);
|
|
@@ -3455,19 +3880,44 @@ export function ConsoleAppV4(props) {
|
|
|
3455
3880
|
return;
|
|
3456
3881
|
}
|
|
3457
3882
|
if (key.backspace || key.delete)
|
|
3458
|
-
setInputValue(
|
|
3883
|
+
setInputValue(removeLastGrapheme);
|
|
3459
3884
|
else if (input && !key.ctrl && !key.meta && input >= ' ')
|
|
3460
3885
|
setInputValue((value) => value + input);
|
|
3461
3886
|
setInputError(undefined);
|
|
3462
3887
|
return;
|
|
3463
3888
|
}
|
|
3464
|
-
if (
|
|
3889
|
+
if (searchFocus && route.name === 'pluginList') {
|
|
3465
3890
|
if (key.escape) {
|
|
3466
|
-
|
|
3891
|
+
setSearchFocus(false);
|
|
3892
|
+
return;
|
|
3893
|
+
}
|
|
3894
|
+
if (key.return) {
|
|
3895
|
+
setSearchFocus(false);
|
|
3896
|
+
const row = pluginRows[focus];
|
|
3897
|
+
if (row)
|
|
3898
|
+
go(route.mode === 'browse'
|
|
3899
|
+
? { name: 'pluginPreview', pluginId: row.pluginId }
|
|
3900
|
+
: { name: 'pluginDetail', pluginId: row.pluginId });
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
if (key.upArrow || key.downArrow) {
|
|
3904
|
+
setSearchFocus(false);
|
|
3905
|
+
setFocus((value) => moveIndex(pluginRows.length, value, key.upArrow ? -1 : 1));
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
if (key.leftArrow || key.rightArrow) {
|
|
3909
|
+
setSearchFocus(false);
|
|
3910
|
+
const tabs = ['all', ...props.controller.listSources().map((source) => source.id)];
|
|
3911
|
+
const current = route.sourceId ?? 'all';
|
|
3912
|
+
const direction = key.leftArrow ? -1 : 1;
|
|
3913
|
+
const next = tabs[(tabs.indexOf(current) + direction + tabs.length) % tabs.length];
|
|
3914
|
+
props.controller.replace({ name: 'pluginList', mode: route.mode, ...(next !== 'all' ? { sourceId: next } : {}) }, { ...snapshot.router.current.context, query, installFilter, sourceTabId: next });
|
|
3915
|
+
setFocus(0);
|
|
3916
|
+
setScrollOffset(0);
|
|
3467
3917
|
return;
|
|
3468
3918
|
}
|
|
3469
3919
|
if (key.backspace || key.delete)
|
|
3470
|
-
setQuery(
|
|
3920
|
+
setQuery(removeLastGrapheme);
|
|
3471
3921
|
else if (input && !key.ctrl && !key.meta && input >= ' ')
|
|
3472
3922
|
setQuery((value) => value + input);
|
|
3473
3923
|
setFocus(0);
|
|
@@ -3492,7 +3942,7 @@ export function ConsoleAppV4(props) {
|
|
|
3492
3942
|
setShowTechnical((value) => !value);
|
|
3493
3943
|
}
|
|
3494
3944
|
else if ((key.escape || input.toLowerCase() === 'b')
|
|
3495
|
-
&& route.name === 'configFieldEditor') {
|
|
3945
|
+
&& (route.name === 'configFieldEditor' || route.name === 'configFieldAction')) {
|
|
3496
3946
|
back();
|
|
3497
3947
|
}
|
|
3498
3948
|
else if (key.escape || input.toLowerCase() === 'b') {
|
|
@@ -3505,7 +3955,7 @@ export function ConsoleAppV4(props) {
|
|
|
3505
3955
|
back();
|
|
3506
3956
|
}
|
|
3507
3957
|
else if (route.name === 'pluginList' && input === '/') {
|
|
3508
|
-
|
|
3958
|
+
setSearchFocus(true);
|
|
3509
3959
|
}
|
|
3510
3960
|
else if (route.name === 'pluginList' && route.mode === 'browse' && input.toLowerCase() === 'f') {
|
|
3511
3961
|
const selectedPluginId = pluginRows[focus]?.pluginId;
|
|
@@ -3543,12 +3993,13 @@ export function ConsoleAppV4(props) {
|
|
|
3543
3993
|
setScrollOffset(0);
|
|
3544
3994
|
}
|
|
3545
3995
|
else if (input.toLowerCase() === 'r' && route.name === 'sourceDetail') {
|
|
3546
|
-
void props.controller.
|
|
3996
|
+
void props.controller.reloadCatalog({ sourceId: route.sourceId });
|
|
3547
3997
|
}
|
|
3548
3998
|
else if (input.toLowerCase() === 'r' && route.name === 'sourceList') {
|
|
3549
3999
|
const source = props.controller.listSources()[focus];
|
|
3550
|
-
if (source)
|
|
3551
|
-
void props.controller.
|
|
4000
|
+
if (source) {
|
|
4001
|
+
void props.controller.reloadCatalog({ sourceId: source.id });
|
|
4002
|
+
}
|
|
3552
4003
|
}
|
|
3553
4004
|
else if (route.name === 'pluginList' && (key.leftArrow || key.rightArrow || input === '[' || input === ']')) {
|
|
3554
4005
|
const tabs = ['all', ...props.controller.listSources().map((source) => source.id)];
|
|
@@ -3590,7 +4041,7 @@ export function ConsoleAppV4(props) {
|
|
|
3590
4041
|
const viewport = route.name === 'portableSkillSelect' && snapshot.portableDraft
|
|
3591
4042
|
? portableSkillCandidateViewport(actions.slice(0, snapshot.portableDraft.candidates.length), snapshot.portableDraft.candidates, policy.mode === 'compact', next, scrollOffset, pageActionBudget(actions.length - snapshot.portableDraft.candidates.length
|
|
3592
4043
|
+ (portableVariantCandidates.length > 0 ? 3 : 0)))
|
|
3593
|
-
: actionViewport(actions, policy.mode === 'compact', next, scrollOffset, pageActionBudget());
|
|
4044
|
+
: actionViewport(actions, policy.mode === 'compact', next, scrollOffset, pageActionBudget(route.name === 'dependencyPlacement' ? dependencyPlacementStaticRows : 0));
|
|
3594
4045
|
setScrollOffset(viewport.offset);
|
|
3595
4046
|
return next;
|
|
3596
4047
|
});
|
|
@@ -3609,7 +4060,7 @@ export function ConsoleAppV4(props) {
|
|
|
3609
4060
|
const viewport = route.name === 'portableSkillSelect' && snapshot.portableDraft
|
|
3610
4061
|
? portableSkillCandidateViewport(actions.slice(0, snapshot.portableDraft.candidates.length), snapshot.portableDraft.candidates, policy.mode === 'compact', next, scrollOffset, pageActionBudget(actions.length - snapshot.portableDraft.candidates.length
|
|
3611
4062
|
+ (portableVariantCandidates.length > 0 ? 3 : 0)))
|
|
3612
|
-
: actionViewport(actions, policy.mode === 'compact', next, scrollOffset, pageActionBudget());
|
|
4063
|
+
: actionViewport(actions, policy.mode === 'compact', next, scrollOffset, pageActionBudget(route.name === 'dependencyPlacement' ? dependencyPlacementStaticRows : 0));
|
|
3613
4064
|
setScrollOffset(viewport.offset);
|
|
3614
4065
|
return next;
|
|
3615
4066
|
});
|