@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
|
@@ -1,74 +1,68 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
|
-
import { probeAgentVersion } from '../utils/agent-version.js';
|
|
3
|
+
import { getCodexOperationRequirement, probeAgentVersion } from '../utils/agent-version.js';
|
|
4
|
+
import { previewCodexManager, resolveCodexOperationConsumer, } from '../utils/codex-manager.js';
|
|
4
5
|
import { createNoopDebugLogger } from '../output/debug-log.js';
|
|
5
6
|
import { createNoopReporter } from '../output/reporter.js';
|
|
6
7
|
import { getDefaultNativeCliRunner } from '../utils/native-cli.js';
|
|
7
|
-
import { readPluginManifest
|
|
8
|
-
import { resolveAwHome } from '../utils/paths.js';
|
|
8
|
+
import { readPluginManifest } from '../utils/manifest.js';
|
|
9
|
+
import { resolveAwHome, resolveCodexPaths } from '../utils/paths.js';
|
|
9
10
|
import { resolveCliPackageRoot } from '../utils/paths.js';
|
|
10
11
|
import { supportsPlatform } from '../utils/platform-support.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { analyzeCodexSurface } from '../utils/codex-surface-analysis.js';
|
|
13
|
+
import { createCodexReconcilePlan, } from '../utils/codex-reconciler.js';
|
|
14
|
+
import { readCodexConfigFile } from '../utils/codex-config.js';
|
|
15
|
+
import { createRebuildActiveStore, executeRebuildOperation, } from './rebuild-operations.js';
|
|
16
|
+
import { assertNoClaudeUnboundNativeNameCollision, createRebuildIntegration, discoverRebuildTargetNames, executeCodexReconcileActivations, inspectCodexSharedNativeLive, inspectNativeMarketplaceRegistrations, } from './rebuild-integration.js';
|
|
17
|
+
import { getNamespacedMarketplaceName, readStrictNamespacedMarketplaceRoot, } from '../utils/local-marketplace.js';
|
|
15
18
|
import { formatPluginId, parsePluginId, planPluginSelectorSourceIds, preflightDesiredArtifactCollisions, withResolvedMultiSourceCatalog, } from '../utils/multi-source-catalog.js';
|
|
19
|
+
import { calculateCodexSharedNativePayloadDigest } from '../utils/catalog-digests.js';
|
|
20
|
+
import { resolveCatalogOperationContext, } from '../utils/catalog-operation-context.js';
|
|
16
21
|
import { assertStrictSemVer } from '../utils/manifest.js';
|
|
17
22
|
import { assertCatalogSourceInventoryComplete, canonicalMarketplaceRegistrationNames, inventoryCatalogSourceReferences, } from '../utils/catalog-source-references.js';
|
|
18
23
|
import { resolveEffectivePluginConfig } from '../utils/plugin-config.js';
|
|
19
|
-
import {
|
|
20
|
-
import { codexProjectConfigAliasesUserHome,
|
|
24
|
+
import { inspectOwnedComponents, } from '../utils/ownership.js';
|
|
25
|
+
import { codexProjectConfigAliasesUserHome, resolveCanonicalRepoProjectKey, } from '../utils/state-paths.js';
|
|
21
26
|
import { resolvePluginMetaDependencyClosure } from '../utils/plugin-dependencies.js';
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
plugin: options.identity.pluginName,
|
|
33
|
-
platform: options.identity.platform,
|
|
34
|
-
scope: options.identity.scope,
|
|
35
|
-
action: options.command,
|
|
36
|
-
};
|
|
27
|
+
import { readCatalogSourcesConfigSnapshot } from '../utils/catalog-sources.js';
|
|
28
|
+
import { readCatalogStoreEntry } from '../utils/catalog-generation-store.js';
|
|
29
|
+
import { catalogGenerationErrorCode, isOfflineCleanupCatalogGenerationError, } from '../utils/catalog-generation-error.js';
|
|
30
|
+
import { canonicalizePluginIntentState, convergePluginIntentManagedCodexOwnership, createEmptyPluginIntentState, mergePluginIntentRootPlatforms, readPluginIntentState, removePluginIntentRootPlatforms, widenPluginIntentManagedCodexOwnership, writePluginIntentState, } from '../utils/plugin-intent-state.js';
|
|
31
|
+
import { validateCatalogSnapshotPluginEntriesComplete } from '../utils/catalog-snapshot.js';
|
|
32
|
+
import { AwCapabilityUnsupportedError, IMPLEMENTED_AW_CAPABILITIES, } from './aw-capabilities.js';
|
|
33
|
+
import { checkAwCapabilitySupport } from '../utils/manifest.js';
|
|
34
|
+
import { createDependencyOperationPlan, createDependencyPlacementPlan, } from './dependency-operation-plan.js';
|
|
35
|
+
import { offlineCleanupEvidenceFromInventory, offlineCleanupEvidenceMatches, } from './offline-cleanup-evidence.js';
|
|
36
|
+
async function measureCommandPerformanceStage(runtime, name, operation) {
|
|
37
37
|
const startedAt = Date.now();
|
|
38
|
-
|
|
39
|
-
type: 'rebuild:action',
|
|
40
|
-
source,
|
|
41
|
-
data: { name: options.name, phase: 'start' },
|
|
42
|
-
});
|
|
43
|
-
let result;
|
|
38
|
+
let phase = 'success';
|
|
44
39
|
try {
|
|
45
|
-
|
|
40
|
+
return await operation();
|
|
46
41
|
}
|
|
47
42
|
catch (error) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
phase = 'failure';
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await Promise.resolve().then(() => runtime?.debugLogger?.log({
|
|
48
|
+
type: 'performance:stage',
|
|
49
|
+
level: 'debug',
|
|
50
|
+
target: 'debugLog',
|
|
51
|
+
message: 'Command performance stage completed.',
|
|
51
52
|
data: {
|
|
52
|
-
name
|
|
53
|
-
phase
|
|
53
|
+
name,
|
|
54
|
+
phase,
|
|
54
55
|
durationMs: Math.max(0, Date.now() - startedAt),
|
|
55
|
-
message: options.name === 'operation.lock'
|
|
56
|
-
? '获取操作锁失败。'
|
|
57
|
-
: '释放操作锁失败。',
|
|
58
56
|
},
|
|
59
|
-
});
|
|
60
|
-
throw error;
|
|
57
|
+
})).catch(() => undefined);
|
|
61
58
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
return result;
|
|
59
|
+
}
|
|
60
|
+
let rebuildCommandTestHooks;
|
|
61
|
+
async function emitRebuildActionEvent(runtime, event) {
|
|
62
|
+
await Promise.allSettled([
|
|
63
|
+
Promise.resolve().then(() => runtime.reporter.event(event)),
|
|
64
|
+
Promise.resolve().then(() => runtime.debugLogger.log(event)),
|
|
65
|
+
]);
|
|
72
66
|
}
|
|
73
67
|
export function setRebuildCommandTestHooksForTests(hooks) {
|
|
74
68
|
rebuildCommandTestHooks = hooks;
|
|
@@ -76,17 +70,91 @@ export function setRebuildCommandTestHooksForTests(hooks) {
|
|
|
76
70
|
function selectedPlatforms(selection) {
|
|
77
71
|
return selection === 'both' ? ['codex', 'claude'] : [selection];
|
|
78
72
|
}
|
|
73
|
+
function updateIntentOverrides(options) {
|
|
74
|
+
const plannedKeys = new Set(options.plan.targets.map((target) => `${target.pluginId}\0${target.platform}`));
|
|
75
|
+
return canonicalizePluginIntentState({
|
|
76
|
+
...options.state,
|
|
77
|
+
dependencyScopeOverrides: [
|
|
78
|
+
...options.state.dependencyScopeOverrides.filter((override) => !plannedKeys.has(`${override.pluginId}\0${override.platform}`)),
|
|
79
|
+
...options.plan.scopeOverrides,
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function effectiveDependencyScopeOverrides(options) {
|
|
84
|
+
const nodeKeys = new Set(options.nodes.map((node) => `${node.pluginId}\0${node.platform}`));
|
|
85
|
+
const explicitMatches = (pluginId, platform) => options.explicit.some((override) => override.pluginId === pluginId
|
|
86
|
+
&& (override.platform === undefined || override.platform === platform));
|
|
87
|
+
return [
|
|
88
|
+
...options.state.dependencyScopeOverrides.filter((override) => nodeKeys.has(`${override.pluginId}\0${override.platform}`)
|
|
89
|
+
&& !options.ignoredPersistedRootIds?.has(override.pluginId)
|
|
90
|
+
&& !explicitMatches(override.pluginId, override.platform)),
|
|
91
|
+
...options.explicit.filter((override) => options.nodes.some((node) => node.pluginId === override.pluginId
|
|
92
|
+
&& (override.platform === undefined || node.platform === override.platform))),
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
function deriveDesiredIntentState(options) {
|
|
96
|
+
if (options.reconcileIntentOnly)
|
|
97
|
+
return options.state;
|
|
98
|
+
let next = options.state;
|
|
99
|
+
if (options.command === 'install') {
|
|
100
|
+
for (const root of options.selectedRoots)
|
|
101
|
+
next = mergePluginIntentRootPlatforms(next, root);
|
|
102
|
+
next = updateIntentOverrides({ state: next, plan: options.plan });
|
|
103
|
+
}
|
|
104
|
+
else if (options.command === 'uninstall') {
|
|
105
|
+
for (const root of options.selectedRoots)
|
|
106
|
+
next = removePluginIntentRootPlatforms(next, root);
|
|
107
|
+
}
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
async function writeDesiredIntentSuperset(options) {
|
|
111
|
+
const location = { scope: options.scope, cwd: options.cwd, env: options.env };
|
|
112
|
+
let next = deriveDesiredIntentState({
|
|
113
|
+
command: options.command,
|
|
114
|
+
state: await readPluginIntentState(location),
|
|
115
|
+
selectedRoots: options.selectedRoots,
|
|
116
|
+
plan: options.plan,
|
|
117
|
+
reconcileIntentOnly: options.reconcileIntentOnly,
|
|
118
|
+
});
|
|
119
|
+
const convergedCodexPluginIds = options.codexPlan?.managedInventory.converged
|
|
120
|
+
?? next.managed.codexPluginIds;
|
|
121
|
+
const superset = options.codexPlan
|
|
122
|
+
? widenPluginIntentManagedCodexOwnership(next, options.codexPlan.managedInventory.ownershipSuperset)
|
|
123
|
+
: next;
|
|
124
|
+
await writePluginIntentState(location, superset);
|
|
125
|
+
const writes = [{ location, superset, convergedCodexPluginIds }];
|
|
126
|
+
if (options.command === 'install' || options.codexPlan) {
|
|
127
|
+
const otherScope = options.scope === 'user' ? 'project' : 'user';
|
|
128
|
+
const otherLocation = { scope: otherScope, cwd: options.cwd, env: options.env };
|
|
129
|
+
let other = await readPluginIntentState(otherLocation);
|
|
130
|
+
if (options.command === 'install' && !options.reconcileIntentOnly) {
|
|
131
|
+
for (const root of options.selectedRoots)
|
|
132
|
+
other = removePluginIntentRootPlatforms(other, root);
|
|
133
|
+
}
|
|
134
|
+
const otherConvergedCodexPluginIds = options.codexPlan?.managedInventory.related.converged
|
|
135
|
+
?? other.managed.codexPluginIds;
|
|
136
|
+
const otherSuperset = options.codexPlan
|
|
137
|
+
? widenPluginIntentManagedCodexOwnership(other, options.codexPlan.managedInventory.related.ownershipSuperset)
|
|
138
|
+
: other;
|
|
139
|
+
await writePluginIntentState(otherLocation, otherSuperset);
|
|
140
|
+
writes.push({
|
|
141
|
+
location: otherLocation,
|
|
142
|
+
superset: otherSuperset,
|
|
143
|
+
convergedCodexPluginIds: otherConvergedCodexPluginIds,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return writes;
|
|
147
|
+
}
|
|
79
148
|
function createSyntheticPlugin(pluginName, env) {
|
|
80
149
|
const rootDir = path.join(resolveAwHome(env), 'plugins', pluginName);
|
|
81
150
|
return {
|
|
82
151
|
rootDir,
|
|
83
152
|
manifestPath: path.join(rootDir, '.agents-plugin', 'plugin.json'),
|
|
84
153
|
manifest: {
|
|
85
|
-
schemaVersion:
|
|
154
|
+
schemaVersion: 2,
|
|
86
155
|
name: pluginName,
|
|
87
156
|
version: '0.0.0',
|
|
88
157
|
description: 'Cleanup-only target for a plugin missing from the current catalog.',
|
|
89
|
-
compatibility: { aw: { minVersion: '0.0.0' } },
|
|
90
158
|
marketplace: {
|
|
91
159
|
category: 'cleanup',
|
|
92
160
|
strict: true,
|
|
@@ -110,17 +178,6 @@ function failedResult(command, identity, message, phase = 'preflight') {
|
|
|
110
178
|
error: { phase, message },
|
|
111
179
|
};
|
|
112
180
|
}
|
|
113
|
-
function appendOperationReleaseFailure(result, message) {
|
|
114
|
-
result.actions.push({ name: 'operation.release', status: 'failed' });
|
|
115
|
-
result.failures.push({ phase: 'operation.release', message });
|
|
116
|
-
if (result.status === 'failed')
|
|
117
|
-
return result;
|
|
118
|
-
return {
|
|
119
|
-
...result,
|
|
120
|
-
status: 'failed',
|
|
121
|
-
error: { phase: 'operation.release', message },
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
181
|
function toTargetResult(result) {
|
|
125
182
|
return {
|
|
126
183
|
target: {
|
|
@@ -138,17 +195,17 @@ function toTargetResult(result) {
|
|
|
138
195
|
...(result.status === 'failed' ? { message: result.error.message } : {}),
|
|
139
196
|
};
|
|
140
197
|
}
|
|
141
|
-
async function
|
|
198
|
+
async function assertClaudeVersion(options) {
|
|
199
|
+
if (!options.platforms.includes('claude'))
|
|
200
|
+
return;
|
|
142
201
|
const failures = [];
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
failures.push(result);
|
|
151
|
-
}
|
|
202
|
+
const result = await probeAgentVersion('claude', {
|
|
203
|
+
cwd: options.cwd,
|
|
204
|
+
env: options.env,
|
|
205
|
+
runner: options.runtime.nativeCliRunner,
|
|
206
|
+
});
|
|
207
|
+
if (result.status !== 'supported')
|
|
208
|
+
failures.push(result);
|
|
152
209
|
if (failures.length > 0) {
|
|
153
210
|
throw new Error(failures.map((failure) => `${failure.command} 版本检查失败:${failure.details ?? failure.status};最低版本 ${failure.requiredMinVersion}。`)
|
|
154
211
|
.join(';'));
|
|
@@ -177,8 +234,7 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
177
234
|
nativeCliRunner: options.runtime?.nativeCliRunner ?? getDefaultNativeCliRunner(),
|
|
178
235
|
reporter: options.runtime?.reporter ?? createNoopReporter(),
|
|
179
236
|
debugLogger: options.runtime?.debugLogger ?? createNoopDebugLogger(),
|
|
180
|
-
|
|
181
|
-
lifecycleLeaseHeld: options.runtime?.lifecycleLeaseHeld,
|
|
237
|
+
...(options.runtime?.codexManager ? { codexManager: options.runtime.codexManager } : {}),
|
|
182
238
|
expectedCatalogConfigDigest: options.runtime?.expectedCatalogConfigDigest,
|
|
183
239
|
};
|
|
184
240
|
const env = runtime.env;
|
|
@@ -186,7 +242,23 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
186
242
|
const catalog = options.runtime?.catalogResolution;
|
|
187
243
|
if (!catalog)
|
|
188
244
|
throw new Error('Internal error: a resolved catalog source is required.');
|
|
189
|
-
const
|
|
245
|
+
const requestedByPlatform = await resolveRequestedNames({
|
|
246
|
+
command: options.command,
|
|
247
|
+
pluginNames: options.pluginNames,
|
|
248
|
+
all: options.all,
|
|
249
|
+
platforms: selected,
|
|
250
|
+
scope: options.commandOptions.scope,
|
|
251
|
+
cwd: options.commandOptions.cwd,
|
|
252
|
+
env,
|
|
253
|
+
nativeCliRunner: runtime.nativeCliRunner,
|
|
254
|
+
});
|
|
255
|
+
const exactPluginNames = [...new Set([...requestedByPlatform.values()].flat())];
|
|
256
|
+
const catalogPlugins = options.runtime?.resolvedCatalogPlugins ?? (await Promise.all(exactPluginNames.map(async (pluginName) => {
|
|
257
|
+
const pluginRoot = path.join(catalog.rootDir, 'plugins', pluginName);
|
|
258
|
+
return await fs.pathExists(pluginRoot)
|
|
259
|
+
? readPluginManifest(pluginRoot, { mode: 'bundle' })
|
|
260
|
+
: null;
|
|
261
|
+
}))).filter((plugin) => plugin !== null);
|
|
190
262
|
if (options.runtime?.namespacedSource) {
|
|
191
263
|
for (const plugin of catalogPlugins) {
|
|
192
264
|
plugin.sourceId = options.runtime.namespacedSource.sourceId;
|
|
@@ -199,16 +271,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
199
271
|
}
|
|
200
272
|
}
|
|
201
273
|
const catalogByName = new Map(catalogPlugins.map((plugin) => [plugin.manifest.name, plugin]));
|
|
202
|
-
const requestedByPlatform = await resolveRequestedNames({
|
|
203
|
-
command: options.command,
|
|
204
|
-
pluginNames: options.pluginNames,
|
|
205
|
-
all: options.all,
|
|
206
|
-
platforms: selected,
|
|
207
|
-
scope: options.commandOptions.scope,
|
|
208
|
-
cwd: options.commandOptions.cwd,
|
|
209
|
-
env,
|
|
210
|
-
nativeCliRunner: runtime.nativeCliRunner,
|
|
211
|
-
});
|
|
212
274
|
if (options.commandOptions.platform === 'both'
|
|
213
275
|
&& options.command !== 'cleanup'
|
|
214
276
|
&& options.command !== 'uninstall') {
|
|
@@ -220,12 +282,14 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
220
282
|
}
|
|
221
283
|
}
|
|
222
284
|
const platforms = selected.filter((platform) => (requestedByPlatform.get(platform)?.length ?? 0) > 0);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
285
|
+
if (options.runtime?.bypassDependencyPlan) {
|
|
286
|
+
await assertClaudeVersion({
|
|
287
|
+
platforms,
|
|
288
|
+
cwd: options.commandOptions.cwd,
|
|
289
|
+
env,
|
|
290
|
+
runtime,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
229
293
|
const integration = options.runtime?.preparedTarget
|
|
230
294
|
? {
|
|
231
295
|
driver: options.runtime.preparedTarget.driver,
|
|
@@ -238,7 +302,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
238
302
|
const activeStore = createRebuildActiveStore({
|
|
239
303
|
env,
|
|
240
304
|
loadPlugin: (bundleRoot) => readPluginManifest(bundleRoot, { mode: 'bundle' }),
|
|
241
|
-
isLifecycleLeaseHeld: () => runtime.lifecycleLeaseHeld === true,
|
|
242
305
|
});
|
|
243
306
|
const targets = [];
|
|
244
307
|
const results = [];
|
|
@@ -286,44 +349,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
286
349
|
results.push(failedResult(options.command, identity, 'codexScopePathAlias: Codex project config 与用户配置目录相同。请进入实际项目目录后重试。'));
|
|
287
350
|
continue;
|
|
288
351
|
}
|
|
289
|
-
if (currentPlugin
|
|
290
|
-
&& platform === 'codex'
|
|
291
|
-
&& options.commandOptions.scope === 'project'
|
|
292
|
-
&& options.command !== 'cleanup'
|
|
293
|
-
&& options.command !== 'uninstall'
|
|
294
|
-
&& currentPlugin.manifest.apps) {
|
|
295
|
-
results.push(failedResult(options.command, identity, `${pluginName} 声明了 apps;Codex project scope 不支持 apps。`));
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (currentPlugin
|
|
299
|
-
&& platform === 'codex'
|
|
300
|
-
&& options.commandOptions.scope === 'project'
|
|
301
|
-
&& options.command !== 'cleanup'
|
|
302
|
-
&& options.command !== 'uninstall'
|
|
303
|
-
&& !hasCodexProjectManagedArtifacts(currentPlugin)) {
|
|
304
|
-
results.push(failedResult(options.command, identity, `${pluginName} 没有 Codex project scope 可生成的 Skills、instructions、roles、MCP、hooks 或 permissions。`));
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
let operationLock;
|
|
308
|
-
if (!options.runtime?.operationLeaseHeld) {
|
|
309
|
-
try {
|
|
310
|
-
await rebuildCommandTestHooks?.beforeOperationLockAcquire?.({
|
|
311
|
-
command: options.command,
|
|
312
|
-
identity,
|
|
313
|
-
});
|
|
314
|
-
operationLock = await withRebuildActionEvent({
|
|
315
|
-
runtime,
|
|
316
|
-
command: options.command,
|
|
317
|
-
identity,
|
|
318
|
-
name: 'operation.lock',
|
|
319
|
-
operation: () => activeStore.acquireOperation(identity),
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
catch (error) {
|
|
323
|
-
results.push(failedResult(options.command, identity, error instanceof Error ? error.message : String(error), 'operation.lock'));
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
352
|
let result;
|
|
328
353
|
try {
|
|
329
354
|
if (options.runtime?.preparedTargetError)
|
|
@@ -358,49 +383,21 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
358
383
|
...options.runtime.resolvedReviewEvidenceByPlugin?.[pluginName],
|
|
359
384
|
});
|
|
360
385
|
}
|
|
361
|
-
const { acquireOperation: _acquireOperation, ...operationHeldStore } = activeStore;
|
|
362
386
|
result = await executeRebuildOperation({
|
|
363
387
|
command: options.command,
|
|
364
388
|
target,
|
|
365
389
|
driver: integration.driver,
|
|
366
|
-
activeStore
|
|
390
|
+
activeStore,
|
|
367
391
|
onActionEvent: (event) => emitRebuildActionEvent(runtime, event),
|
|
368
392
|
});
|
|
369
393
|
}
|
|
370
394
|
catch (error) {
|
|
371
395
|
result = error.result ?? failedResult(options.command, identity, error instanceof Error ? error.message : String(error), 'preflight');
|
|
372
396
|
}
|
|
373
|
-
result.actions.unshift({ name: 'operation.lock', status: 'succeeded' });
|
|
374
|
-
if (operationLock) {
|
|
375
|
-
try {
|
|
376
|
-
await withRebuildActionEvent({
|
|
377
|
-
runtime,
|
|
378
|
-
command: options.command,
|
|
379
|
-
identity,
|
|
380
|
-
name: 'operation.release',
|
|
381
|
-
operation: () => releaseRebuildOperationLease(operationLock),
|
|
382
|
-
});
|
|
383
|
-
result.actions.push({ name: 'operation.release', status: 'succeeded' });
|
|
384
|
-
}
|
|
385
|
-
catch (error) {
|
|
386
|
-
result = appendOperationReleaseFailure(result, error instanceof Error ? error.message : String(error));
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
397
|
results.push(result);
|
|
390
398
|
}
|
|
391
399
|
}
|
|
392
400
|
const successful = results.filter((result) => result.status === 'succeeded');
|
|
393
|
-
const artifacts = targets.flatMap((target) => [...target.artifacts]);
|
|
394
|
-
const nativePlugins = {};
|
|
395
|
-
for (const result of successful) {
|
|
396
|
-
const target = targets.find((entry) => entry.identity.pluginName === result.target.pluginName
|
|
397
|
-
&& entry.identity.platform === result.target.platform
|
|
398
|
-
&& entry.identity.scope === result.target.scope);
|
|
399
|
-
if (target?.requiresNative && options.command !== 'cleanup' && options.command !== 'uninstall') {
|
|
400
|
-
nativePlugins[result.target.platform] ??= [];
|
|
401
|
-
nativePlugins[result.target.platform].push(result.target.pluginName);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
401
|
return {
|
|
405
402
|
platforms,
|
|
406
403
|
plugins: [...new Set(successful.map((result) => result.target.pluginName))],
|
|
@@ -408,8 +405,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
408
405
|
rebuildResults: results,
|
|
409
406
|
targetResults: results.map(toTargetResult),
|
|
410
407
|
overallState: results.every((result) => result.status === 'succeeded') ? 'succeeded' : 'failed',
|
|
411
|
-
nativePlugins,
|
|
412
|
-
repoManagedArtifacts: artifacts,
|
|
413
408
|
receiptTargets: results.map((result) => ({
|
|
414
409
|
pluginName: result.target.pluginName,
|
|
415
410
|
...(result.target.sourceId ? {
|
|
@@ -431,20 +426,11 @@ function toCatalogResolution(source) {
|
|
|
431
426
|
source: 'local',
|
|
432
427
|
catalogVersion: source.manifest.catalogVersion,
|
|
433
428
|
channel: source.manifest.channel,
|
|
434
|
-
minAwVersion: source.manifest.compatibility.aw.minVersion,
|
|
435
429
|
};
|
|
436
430
|
}
|
|
437
431
|
function mergeRebuildCommandResults(results) {
|
|
438
432
|
const rebuildResults = results.flatMap((result) => result.rebuildResults);
|
|
439
433
|
const platforms = [...new Set(results.flatMap((result) => result.platforms))];
|
|
440
|
-
const nativePlugins = {};
|
|
441
|
-
for (const result of results) {
|
|
442
|
-
for (const platform of ['codex', 'claude']) {
|
|
443
|
-
const names = result.nativePlugins[platform];
|
|
444
|
-
if (names)
|
|
445
|
-
nativePlugins[platform] = [...new Set([...(nativePlugins[platform] ?? []), ...names])];
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
434
|
return {
|
|
449
435
|
platforms,
|
|
450
436
|
plugins: [...new Set(results.flatMap((result) => result.plugins))],
|
|
@@ -454,19 +440,22 @@ function mergeRebuildCommandResults(results) {
|
|
|
454
440
|
overallState: rebuildResults.every((result) => result.status === 'succeeded')
|
|
455
441
|
? 'succeeded'
|
|
456
442
|
: 'failed',
|
|
457
|
-
nativePlugins,
|
|
458
|
-
repoManagedArtifacts: [],
|
|
459
443
|
receiptTargets: results.flatMap((result) => result.receiptTargets),
|
|
460
444
|
...(results.find((result) => result.dependencyPlan)?.dependencyPlan
|
|
461
445
|
? { dependencyPlan: results.find((result) => result.dependencyPlan).dependencyPlan }
|
|
462
446
|
: {}),
|
|
447
|
+
...(results.find((result) => result.codexManagerPreview)?.codexManagerPreview
|
|
448
|
+
? { codexManagerPreview: results.find((result) => result.codexManagerPreview).codexManagerPreview }
|
|
449
|
+
: {}),
|
|
450
|
+
...(results.some((result) => result.offlineCleanupPlans !== undefined)
|
|
451
|
+
? { offlineCleanupPlans: results.flatMap((result) => result.offlineCleanupPlans ?? []) }
|
|
452
|
+
: {}),
|
|
463
453
|
};
|
|
464
454
|
}
|
|
465
455
|
function leaseSafeRebuildResult(result) {
|
|
466
456
|
const projectPath = (value) => path.basename(value);
|
|
467
457
|
return {
|
|
468
458
|
...result,
|
|
469
|
-
repoManagedArtifacts: [],
|
|
470
459
|
rebuildResults: result.rebuildResults.map((entry) => ({
|
|
471
460
|
...entry,
|
|
472
461
|
target: { ...entry.target, cwd: '.' },
|
|
@@ -497,12 +486,18 @@ function projectLegacyTargets(references) {
|
|
|
497
486
|
return [`${target.pluginName}\0${target.platform}\0${target.scope}`, target];
|
|
498
487
|
})).values()];
|
|
499
488
|
}
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return
|
|
489
|
+
function desiredCleanupNoopResult(targets, cwd) {
|
|
490
|
+
const rebuildResults = targets.map((target) => ({
|
|
491
|
+
status: 'succeeded', command: 'cleanup', target: { ...target, pluginVersion: 'unavailable', cwd },
|
|
492
|
+
actions: [], cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
493
|
+
}));
|
|
494
|
+
return {
|
|
495
|
+
platforms: [...new Set(targets.map((target) => target.platform))],
|
|
496
|
+
plugins: [...new Set(targets.map((target) => target.pluginName))],
|
|
497
|
+
warnings: [], rebuildResults,
|
|
498
|
+
targetResults: rebuildResults.map((result) => ({ target: result.target, action: 'keep', state: 'completed' })),
|
|
499
|
+
overallState: 'succeeded', receiptTargets: targets,
|
|
500
|
+
};
|
|
506
501
|
}
|
|
507
502
|
function resolveLiveCleanupTargets(options) {
|
|
508
503
|
const visible = options.references.filter((reference) => (reference.kind === 'namespacedOwner'
|
|
@@ -520,6 +515,12 @@ function resolveLiveCleanupTargets(options) {
|
|
|
520
515
|
const matchesByTarget = new Map();
|
|
521
516
|
for (const reference of visible.filter((entry) => entry.pluginName === parsed.pluginName
|
|
522
517
|
&& (parsed.sourceId === undefined || entry.sourceId === parsed.sourceId))) {
|
|
518
|
+
const lifecycleReference = visible.find((entry) => entry.kind === 'namespacedLifecycle'
|
|
519
|
+
&& entry.sourceId === reference.sourceId
|
|
520
|
+
&& entry.sourceIdentity === reference.sourceIdentity
|
|
521
|
+
&& entry.pluginName === reference.pluginName
|
|
522
|
+
&& entry.platform === reference.platform
|
|
523
|
+
&& entry.scope === reference.scope);
|
|
523
524
|
const liveNames = new Set(options.references.flatMap((candidate) => candidate.sourceId === reference.sourceId
|
|
524
525
|
&& candidate.sourceIdentity === reference.sourceIdentity
|
|
525
526
|
&& candidate.pluginName === reference.pluginName
|
|
@@ -553,7 +554,19 @@ function resolveLiveCleanupTargets(options) {
|
|
|
553
554
|
platform: reference.platform,
|
|
554
555
|
scope: reference.scope,
|
|
555
556
|
...(marketplaceName ? { marketplaceName } : {}),
|
|
557
|
+
...((liveNames.size === 1
|
|
558
|
+
|| (marketplaceName !== undefined && unboundNativeNames.has(marketplaceName)))
|
|
559
|
+
? { nativeRegistration: true }
|
|
560
|
+
: {}),
|
|
556
561
|
...(marketplaceIdentityUnresolved ? { marketplaceIdentityUnresolved: true } : {}),
|
|
562
|
+
...(lifecycleReference?.lifecycleMetadataIntegrityDigest
|
|
563
|
+
? {
|
|
564
|
+
lifecycleMetadataIntegrityDigest: lifecycleReference.lifecycleMetadataIntegrityDigest,
|
|
565
|
+
}
|
|
566
|
+
: {}),
|
|
567
|
+
...(lifecycleReference?.pluginVersion
|
|
568
|
+
? { lifecyclePluginVersion: lifecycleReference.pluginVersion }
|
|
569
|
+
: {}),
|
|
557
570
|
};
|
|
558
571
|
const key = [target.pluginId, target.sourceIdentity, target.platform, target.scope].join('\0');
|
|
559
572
|
const previous = matchesByTarget.get(key);
|
|
@@ -574,60 +587,18 @@ function resolveLiveCleanupTargets(options) {
|
|
|
574
587
|
].join('\0'), target])).values()],
|
|
575
588
|
};
|
|
576
589
|
}
|
|
577
|
-
async function discoverDamagedExclusiveCleanupTargets(options) {
|
|
578
|
-
const parsed = parsePluginId(options.selector);
|
|
579
|
-
if (!parsed.sourceId)
|
|
580
|
-
return [];
|
|
581
|
-
const targets = [];
|
|
582
|
-
for (const platform of options.platforms) {
|
|
583
|
-
const root = exclusiveSkillRoot({
|
|
584
|
-
platform,
|
|
585
|
-
scope: options.scope,
|
|
586
|
-
cwd: options.cwd,
|
|
587
|
-
env: options.env,
|
|
588
|
-
});
|
|
589
|
-
const entries = await fs.readdir(root, { withFileTypes: true }).catch(() => []);
|
|
590
|
-
for (const entry of entries) {
|
|
591
|
-
if (!entry.isDirectory() || entry.isSymbolicLink())
|
|
592
|
-
continue;
|
|
593
|
-
const markerPath = path.join(root, entry.name, '.agent-workflows-owner.json');
|
|
594
|
-
const markerStats = await fs.lstat(markerPath).catch(() => null);
|
|
595
|
-
if (!markerStats?.isFile() || markerStats.isSymbolicLink())
|
|
596
|
-
continue;
|
|
597
|
-
const raw = await fs.readJson(markerPath).catch(() => null);
|
|
598
|
-
if (!raw
|
|
599
|
-
|| raw.schemaVersion !== 2
|
|
600
|
-
|| raw.owner !== 'agent-workflows'
|
|
601
|
-
|| raw.sourceId !== parsed.sourceId
|
|
602
|
-
|| raw.plugin !== parsed.pluginName
|
|
603
|
-
|| raw.pluginId !== options.selector
|
|
604
|
-
|| raw.platform !== platform
|
|
605
|
-
|| raw.scope !== options.scope)
|
|
606
|
-
continue;
|
|
607
|
-
targets.push({
|
|
608
|
-
pluginId: options.selector,
|
|
609
|
-
pluginName: parsed.pluginName,
|
|
610
|
-
sourceId: parsed.sourceId,
|
|
611
|
-
sourceIdentity: typeof raw.sourceIdentity === 'string'
|
|
612
|
-
&& /^sha256:[0-9a-f]{64}$/u.test(raw.sourceIdentity)
|
|
613
|
-
? raw.sourceIdentity
|
|
614
|
-
: `sha256:${'0'.repeat(64)}`,
|
|
615
|
-
platform,
|
|
616
|
-
scope: raw.scope,
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
return [...new Map(targets.map((target) => [[target.platform, target.scope].join('\0'), target])).values()];
|
|
621
|
-
}
|
|
622
590
|
async function cleanupOfflineOwnedComponents(options) {
|
|
623
591
|
if (options.targets.some((target) => target.marketplaceIdentityUnresolved)) {
|
|
624
592
|
throw namespacedPreflightError('marketplaceIdentityUnavailable: Cannot uniquely recover the native marketplace name from live inventory or a canonical native registration path.', options.targets);
|
|
625
593
|
}
|
|
626
594
|
const results = [];
|
|
627
595
|
const warnings = [];
|
|
596
|
+
const nativeCliRunner = options.nativeCliRunner ?? getDefaultNativeCliRunner();
|
|
597
|
+
const codexManager = options.codexManager;
|
|
628
598
|
const context = {
|
|
629
599
|
env: options.env,
|
|
630
|
-
nativeCliRunner
|
|
600
|
+
nativeCliRunner,
|
|
601
|
+
...(codexManager ? { codexManager } : {}),
|
|
631
602
|
reporter: createNoopReporter(),
|
|
632
603
|
debugLogger: createNoopDebugLogger(),
|
|
633
604
|
};
|
|
@@ -635,56 +606,36 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
635
606
|
const activeStore = createRebuildActiveStore({
|
|
636
607
|
env: options.env,
|
|
637
608
|
loadPlugin: (bundleRoot) => readPluginManifest(bundleRoot, { mode: 'bundle' }),
|
|
638
|
-
isLifecycleLeaseHeld: () => context.lifecycleLeaseHeld === true,
|
|
639
609
|
});
|
|
640
610
|
for (const target of options.targets) {
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
611
|
+
const inventoryErrors = (options.inventoryErrors ?? []).filter((error) => error.relevance.global || ((error.relevance.sourceId === undefined || error.relevance.sourceId === target.sourceId)
|
|
612
|
+
&& (error.relevance.pluginName === undefined || error.relevance.pluginName === target.pluginName)
|
|
613
|
+
&& (error.relevance.platform === undefined || error.relevance.platform === target.platform)
|
|
614
|
+
&& (error.relevance.scope === undefined || error.relevance.scope === target.scope)));
|
|
615
|
+
const evidence = options.evidence?.find((candidate) => candidate.pluginId === target.pluginId
|
|
616
|
+
&& candidate.sourceIdentity === target.sourceIdentity
|
|
617
|
+
&& candidate.platform === target.platform
|
|
618
|
+
&& candidate.scope === target.scope);
|
|
619
|
+
const activationAction = target.platform === 'codex'
|
|
620
|
+
? evidence?.plan.actions.find((action) => action.action === 'removeNativeRegistration'
|
|
621
|
+
&& action.activationScope === target.scope)
|
|
622
|
+
: undefined;
|
|
623
|
+
let activationDisposition = 'remove';
|
|
624
|
+
if (activationAction && target.scope === 'user') {
|
|
625
|
+
const projectIntent = await readPluginIntentState({
|
|
626
|
+
scope: 'project',
|
|
648
627
|
cwd: options.cwd,
|
|
649
628
|
env: options.env,
|
|
650
629
|
});
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
const directory = path.join(root, entry.name);
|
|
656
|
-
let recovered;
|
|
657
|
-
try {
|
|
658
|
-
recovered = await cleanupCorruptExclusivePluginDirectory({
|
|
659
|
-
directory,
|
|
660
|
-
allowedRoot: root,
|
|
661
|
-
sourceId: target.sourceId,
|
|
662
|
-
pluginName: target.pluginName,
|
|
663
|
-
platform: target.platform,
|
|
664
|
-
scope: target.scope,
|
|
665
|
-
...options.corruptExclusiveDirectoryOperations,
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
catch (error) {
|
|
669
|
-
recovered = {
|
|
670
|
-
removed: [], absent: [], residual: [directory], quarantined: [],
|
|
671
|
-
failures: [{
|
|
672
|
-
label: directory,
|
|
673
|
-
phase: 'mutation',
|
|
674
|
-
message: error instanceof Error ? error.message : String(error),
|
|
675
|
-
}],
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
if (recovered) {
|
|
679
|
-
exclusiveRecovery.removed.push(...recovered.removed);
|
|
680
|
-
exclusiveRecovery.absent.push(...recovered.absent);
|
|
681
|
-
exclusiveRecovery.residual.push(...recovered.residual);
|
|
682
|
-
exclusiveRecovery.quarantined.push(...recovered.quarantined);
|
|
683
|
-
exclusiveRecovery.failures.push(...recovered.failures);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
630
|
+
const remainsDesired = projectIntent.roots.some((root) => root.pluginId === target.pluginId && root.platforms.includes('codex'))
|
|
631
|
+
|| projectIntent.managed.codexPluginIds.includes(activationAction.target);
|
|
632
|
+
if (remainsDesired)
|
|
633
|
+
activationDisposition = 'disable';
|
|
686
634
|
}
|
|
687
635
|
const plugin = createSyntheticPlugin(target.pluginName, options.env);
|
|
636
|
+
if (target.lifecyclePluginVersion) {
|
|
637
|
+
plugin.manifest.version = target.lifecyclePluginVersion;
|
|
638
|
+
}
|
|
688
639
|
plugin.sourceId = target.sourceId;
|
|
689
640
|
plugin.sourceIdentity = target.sourceIdentity;
|
|
690
641
|
plugin.pluginId = target.pluginId;
|
|
@@ -706,54 +657,46 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
706
657
|
source: 'local',
|
|
707
658
|
catalogVersion: '0.0.0',
|
|
708
659
|
channel: 'beta',
|
|
709
|
-
minAwVersion: '0.0.0',
|
|
710
660
|
},
|
|
711
|
-
includeHistoricalLifecycleArtifacts:
|
|
661
|
+
includeHistoricalLifecycleArtifacts: target.lifecycleMetadataIntegrityDigest !== undefined,
|
|
662
|
+
...(target.lifecycleMetadataIntegrityDigest
|
|
663
|
+
? {
|
|
664
|
+
expectedLifecycleMetadataIntegrityDigest: target.lifecycleMetadataIntegrityDigest,
|
|
665
|
+
}
|
|
666
|
+
: {}),
|
|
667
|
+
includeNativeCleanupCandidate: target.nativeRegistration === true,
|
|
668
|
+
...(activationAction
|
|
669
|
+
? {
|
|
670
|
+
codexActivationCleanup: [{
|
|
671
|
+
codexPluginId: activationAction.target,
|
|
672
|
+
scope: activationAction.activationScope,
|
|
673
|
+
disposition: activationDisposition,
|
|
674
|
+
}],
|
|
675
|
+
preserveCodexSharedNativePayload: true,
|
|
676
|
+
}
|
|
677
|
+
: {}),
|
|
712
678
|
});
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
679
|
+
const preserveDamagedLifecycle = inventoryErrors.some((error) => error.kind.startsWith('lifecycle'));
|
|
680
|
+
const result = await executeRebuildOperation({
|
|
681
|
+
command: 'cleanup',
|
|
682
|
+
target: desired,
|
|
683
|
+
driver: integration.driver,
|
|
684
|
+
activeStore: preserveDamagedLifecycle
|
|
685
|
+
? { ...activeStore, remove: async () => undefined }
|
|
686
|
+
: activeStore,
|
|
687
|
+
});
|
|
688
|
+
if (result.status === 'succeeded' && evidence) {
|
|
689
|
+
result.removed = [...new Set([
|
|
690
|
+
...result.removed,
|
|
691
|
+
...evidence.plan.actions.flatMap((action) => action.action === 'removeLifecycleSnapshot' ? [action.target] : []),
|
|
692
|
+
])];
|
|
723
693
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const residualPath = failure.quarantinePath ?? failure.label;
|
|
731
|
-
return await fs.pathExists(residualPath) ? failure : null;
|
|
732
|
-
}))).filter((failure) => failure !== null);
|
|
733
|
-
const removed = [...new Set([...result.removed, ...exclusiveRecovery.removed])];
|
|
734
|
-
const absent = [...new Set([...result.absent, ...exclusiveRecovery.absent])]
|
|
735
|
-
.filter((entry) => !removed.includes(entry));
|
|
736
|
-
result = {
|
|
737
|
-
...result,
|
|
738
|
-
removed,
|
|
739
|
-
absent,
|
|
740
|
-
residual: [...new Set([...result.residual, ...exclusiveResidual])],
|
|
741
|
-
quarantined: [...new Set([...result.quarantined, ...exclusiveQuarantined])],
|
|
742
|
-
};
|
|
743
|
-
if (exclusiveFailures.length > 0) {
|
|
744
|
-
const failures = exclusiveFailures.map((failure) => ({
|
|
745
|
-
phase: 'cleanup.owned',
|
|
746
|
-
label: failure.label,
|
|
747
|
-
message: `exclusiveRecoveryFailed: ${failure.phase} ${failure.label}: ${failure.message}`,
|
|
748
|
-
}));
|
|
749
|
-
const message = failures[0].message;
|
|
750
|
-
result = {
|
|
751
|
-
...result,
|
|
752
|
-
status: 'failed',
|
|
753
|
-
actions: [{ name: 'cleanup.owned', status: 'failed' }],
|
|
754
|
-
failures: [...result.failures, ...failures],
|
|
755
|
-
error: { phase: 'cleanup.owned', message },
|
|
756
|
-
};
|
|
694
|
+
if (inventoryErrors.length > 0) {
|
|
695
|
+
result.residual = [...new Set([
|
|
696
|
+
...result.residual,
|
|
697
|
+
...inventoryErrors.map((error) => error.location),
|
|
698
|
+
])];
|
|
699
|
+
warnings.push(...inventoryErrors.map((error) => `stateInventoryResidual: ${error.kind}: ${error.message}`));
|
|
757
700
|
}
|
|
758
701
|
results.push(result);
|
|
759
702
|
}
|
|
@@ -767,11 +710,10 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
767
710
|
return leaseSafeRebuildResult({
|
|
768
711
|
platforms: [...new Set(results.map((result) => result.target.platform))],
|
|
769
712
|
plugins: results.filter((result) => result.status === 'succeeded').map((result) => result.target.pluginName),
|
|
770
|
-
warnings,
|
|
713
|
+
warnings: [...new Set(warnings)],
|
|
771
714
|
rebuildResults: results,
|
|
772
715
|
targetResults: results.map(toTargetResult),
|
|
773
716
|
overallState: results.every((result) => result.status === 'succeeded') ? 'succeeded' : 'failed',
|
|
774
|
-
nativePlugins: {}, repoManagedArtifacts: [],
|
|
775
717
|
receiptTargets: results.map((result) => ({
|
|
776
718
|
pluginName: result.target.pluginName,
|
|
777
719
|
pluginId: result.target.pluginId,
|
|
@@ -779,57 +721,188 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
779
721
|
platform: result.target.platform,
|
|
780
722
|
scope: result.target.scope,
|
|
781
723
|
})),
|
|
724
|
+
...(options.evidence ? { offlineCleanupPlans: options.evidence } : {}),
|
|
782
725
|
});
|
|
783
726
|
}
|
|
727
|
+
async function previewOfflineOwnedComponents(options) {
|
|
728
|
+
if (options.targets.some((target) => target.marketplaceIdentityUnresolved)) {
|
|
729
|
+
throw namespacedPreflightError('marketplaceIdentityUnavailable: Cannot uniquely recover the native marketplace name from live inventory or a canonical native registration path.', options.targets);
|
|
730
|
+
}
|
|
731
|
+
await options.onPreviewStage?.('inventory');
|
|
732
|
+
const preview = mergeRebuildCommandResults([]);
|
|
733
|
+
if (options.evidence)
|
|
734
|
+
preview.offlineCleanupPlans = options.evidence;
|
|
735
|
+
await options.onPreviewStage?.('dependencyPlan');
|
|
736
|
+
return preview;
|
|
737
|
+
}
|
|
784
738
|
async function assertOfflineCleanupDependents(options) {
|
|
785
|
-
const inventory = await
|
|
786
|
-
cwd: options.cwd,
|
|
787
|
-
env: options.env,
|
|
788
|
-
includeHistoricalProjects: true,
|
|
739
|
+
const inventory = await options.readInventory({
|
|
740
|
+
cwd: options.cwd, env: options.env, includeHistoricalProjects: true,
|
|
789
741
|
});
|
|
790
742
|
const currentProjectKey = await resolveCanonicalRepoProjectKey(options.cwd);
|
|
743
|
+
const cleanupIds = new Set(options.targets.map((target) => target.pluginId));
|
|
791
744
|
for (const target of options.targets) {
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
.
|
|
745
|
+
const consumerNames = [...new Set(inventory.references.flatMap((reference) => (reference.kind === 'namespacedOwner'
|
|
746
|
+
|| reference.kind === 'namespacedMarketplace'
|
|
747
|
+
|| reference.kind === 'namespacedLifecycle')
|
|
748
|
+
&& reference.sourceId === target.sourceId
|
|
749
|
+
&& reference.sourceIdentity === target.sourceIdentity
|
|
750
|
+
&& reference.pluginName
|
|
751
|
+
&& reference.pluginName !== target.pluginName
|
|
752
|
+
&& reference.platform === target.platform
|
|
753
|
+
&& (target.scope === 'user' || reference.scope === 'project')
|
|
754
|
+
? [reference.pluginName]
|
|
755
|
+
: []))];
|
|
756
|
+
const consumerPlugins = (await Promise.all(consumerNames.map((pluginName) => readOfflinePluginManifestCandidates({
|
|
757
|
+
target,
|
|
758
|
+
sourceIdentity: target.sourceIdentity,
|
|
759
|
+
pluginName,
|
|
760
|
+
env: options.env,
|
|
761
|
+
inventory,
|
|
762
|
+
})))).flat();
|
|
763
|
+
for (const consumer of consumerPlugins) {
|
|
799
764
|
if (!consumer?.manifest.dependencies?.includes(target.pluginName))
|
|
800
765
|
continue;
|
|
801
766
|
const consumerId = formatPluginId({ sourceId: target.sourceId, pluginName: consumer.manifest.name });
|
|
802
|
-
|
|
767
|
+
if (cleanupIds.has(consumerId))
|
|
768
|
+
continue;
|
|
769
|
+
const live = inventory.references.some((reference) => (reference.kind === 'namespacedOwner'
|
|
770
|
+
|| reference.kind === 'namespacedMarketplace'
|
|
771
|
+
|| reference.kind === 'namespacedLifecycle')
|
|
803
772
|
&& reference.sourceId === target.sourceId
|
|
804
773
|
&& reference.sourceIdentity === target.sourceIdentity
|
|
805
774
|
&& reference.pluginName === consumer.manifest.name
|
|
806
775
|
&& reference.platform === target.platform
|
|
807
776
|
&& (target.scope === 'user' || reference.scope === 'project')
|
|
808
777
|
&& (target.scope === 'user' || reference.projectKey === currentProjectKey));
|
|
809
|
-
if (live)
|
|
778
|
+
if (live)
|
|
810
779
|
throw namespacedPreflightError(`dependencyStillRequired: ${target.pluginId} is required by ${consumerId}.`, options.targets);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
async function readPluginManifestIfPresent(root) {
|
|
784
|
+
return readPluginManifest(root, { mode: 'bundle' }).catch(() => null);
|
|
785
|
+
}
|
|
786
|
+
async function readOfflinePluginManifestCandidates(options) {
|
|
787
|
+
const lifecycleRoots = options.inventory.references.flatMap((reference) => reference.kind === 'namespacedLifecycle'
|
|
788
|
+
&& reference.sourceId === options.target.sourceId
|
|
789
|
+
&& reference.sourceIdentity === options.sourceIdentity
|
|
790
|
+
&& reference.pluginName === options.pluginName
|
|
791
|
+
? [path.join(reference.location, 'bundle')]
|
|
792
|
+
: []);
|
|
793
|
+
const marketplaceRoot = path.join(resolveAwHome(options.env), 'marketplaces', options.target.sourceId);
|
|
794
|
+
const marketplace = await readStrictNamespacedMarketplaceRoot({
|
|
795
|
+
rootDir: marketplaceRoot,
|
|
796
|
+
sourceId: options.target.sourceId,
|
|
797
|
+
}).catch(() => null);
|
|
798
|
+
const marketplaceRoots = marketplace?.config.sourceIdentity === options.sourceIdentity
|
|
799
|
+
? [marketplaceRoot]
|
|
800
|
+
: [];
|
|
801
|
+
const roots = [
|
|
802
|
+
...lifecycleRoots,
|
|
803
|
+
...marketplaceRoots.map((root) => path.join(root, 'plugins', options.pluginName)),
|
|
804
|
+
];
|
|
805
|
+
const storeRoot = path.join(resolveAwHome(options.env), 'catalog-store');
|
|
806
|
+
const logicalEntries = await fs.readdir(storeRoot, { withFileTypes: true }).catch(() => []);
|
|
807
|
+
for (const logicalEntry of logicalEntries) {
|
|
808
|
+
if (!logicalEntry.isDirectory() || logicalEntry.isSymbolicLink())
|
|
809
|
+
continue;
|
|
810
|
+
const logicalRoot = path.join(storeRoot, logicalEntry.name);
|
|
811
|
+
const snapshotEntries = await fs.readdir(logicalRoot, { withFileTypes: true }).catch(() => []);
|
|
812
|
+
for (const snapshotEntry of snapshotEntries) {
|
|
813
|
+
if (!snapshotEntry.isDirectory()
|
|
814
|
+
|| snapshotEntry.isSymbolicLink()
|
|
815
|
+
|| !/^[0-9a-f]{64}$/u.test(snapshotEntry.name))
|
|
816
|
+
continue;
|
|
817
|
+
let logicalIdentity;
|
|
818
|
+
try {
|
|
819
|
+
logicalIdentity = decodeURIComponent(logicalEntry.name);
|
|
820
|
+
}
|
|
821
|
+
catch {
|
|
822
|
+
continue;
|
|
811
823
|
}
|
|
824
|
+
const entry = await readCatalogStoreEntry({
|
|
825
|
+
logicalIdentity,
|
|
826
|
+
snapshotDigest: `sha256:${snapshotEntry.name}`,
|
|
827
|
+
env: options.env,
|
|
828
|
+
}).catch(() => null);
|
|
829
|
+
if (!entry)
|
|
830
|
+
continue;
|
|
831
|
+
const storeAnchor = await readPluginManifestIfPresent(path.join(entry.snapshotRoot, 'plugins', options.target.pluginName));
|
|
832
|
+
if (!storeAnchor || storeAnchor.manifest.name !== options.target.pluginName)
|
|
833
|
+
continue;
|
|
834
|
+
roots.push(path.join(entry.snapshotRoot, 'plugins', options.pluginName));
|
|
812
835
|
}
|
|
813
836
|
}
|
|
837
|
+
const plugins = await Promise.all([...new Set(roots)].map(readPluginManifestIfPresent));
|
|
838
|
+
return plugins.filter((plugin) => plugin !== null);
|
|
839
|
+
}
|
|
840
|
+
async function cleanupTargetIsDesired(options) {
|
|
841
|
+
const pending = options.roots.filter((root) => root.platforms.includes(options.target.platform));
|
|
842
|
+
const visited = new Set();
|
|
843
|
+
while (pending.length > 0) {
|
|
844
|
+
const root = pending.pop();
|
|
845
|
+
if (visited.has(root.pluginId))
|
|
846
|
+
continue;
|
|
847
|
+
visited.add(root.pluginId);
|
|
848
|
+
if (root.pluginId === options.target.pluginId)
|
|
849
|
+
return true;
|
|
850
|
+
const parsed = parsePluginId(root.pluginId);
|
|
851
|
+
if (parsed.sourceId !== options.target.sourceId)
|
|
852
|
+
continue;
|
|
853
|
+
const plugins = await readOfflinePluginManifestCandidates({
|
|
854
|
+
target: options.target,
|
|
855
|
+
sourceIdentity: options.target.sourceIdentity,
|
|
856
|
+
pluginName: parsed.pluginName,
|
|
857
|
+
env: options.env,
|
|
858
|
+
inventory: options.inventory,
|
|
859
|
+
});
|
|
860
|
+
pending.push(...plugins.flatMap((plugin) => plugin.manifest.dependencies ?? []).map((pluginName) => ({
|
|
861
|
+
pluginId: formatPluginId({ sourceId: parsed.sourceId, pluginName }),
|
|
862
|
+
platforms: [options.target.platform],
|
|
863
|
+
})));
|
|
864
|
+
}
|
|
865
|
+
return false;
|
|
814
866
|
}
|
|
815
867
|
export async function runRebuildCommand(options) {
|
|
816
868
|
if (options.runtime?.catalogResolution && options.runtime.bypassDependencyPlan) {
|
|
817
869
|
return runSingleSourceRebuildCommand(options);
|
|
818
870
|
}
|
|
819
871
|
const runtimeEnv = options.runtime?.env ?? process.env;
|
|
872
|
+
const readInventory = options.runtime?.inventoryCatalogSourceReferences
|
|
873
|
+
?? inventoryCatalogSourceReferences;
|
|
874
|
+
let ordinaryInventory;
|
|
875
|
+
const readOrdinaryInventory = async () => {
|
|
876
|
+
ordinaryInventory ??= await measureCommandPerformanceStage(options.runtime, 'inventory', () => readInventory({
|
|
877
|
+
cwd: options.commandOptions.cwd,
|
|
878
|
+
env: runtimeEnv,
|
|
879
|
+
...(options.command === 'cleanup' && options.all
|
|
880
|
+
? { includeOrphanedCodexNativeResidue: true }
|
|
881
|
+
: {}),
|
|
882
|
+
...(options.command === 'cleanup' && !options.all
|
|
883
|
+
? {
|
|
884
|
+
codexNativeResidueTargets: options.pluginNames.map((selector) => {
|
|
885
|
+
const parsed = parsePluginId(selector);
|
|
886
|
+
return {
|
|
887
|
+
pluginName: parsed.pluginName,
|
|
888
|
+
...(parsed.sourceId ? { sourceId: parsed.sourceId } : {}),
|
|
889
|
+
};
|
|
890
|
+
}),
|
|
891
|
+
}
|
|
892
|
+
: {}),
|
|
893
|
+
}));
|
|
894
|
+
return ordinaryInventory;
|
|
895
|
+
};
|
|
820
896
|
let requestedPluginNames = options.pluginNames;
|
|
821
897
|
const cleanupForce = options.command === 'cleanup'
|
|
822
898
|
&& options.commandOptions.force === true;
|
|
899
|
+
const expectedOfflineCleanup = options.runtime?.expectedOfflineCleanupEvidence;
|
|
823
900
|
let cleanupInventory;
|
|
824
901
|
let cleanupLiveTargets = [];
|
|
825
|
-
let cleanupHasDamagedExclusiveTarget = false;
|
|
826
902
|
let liveTargets = [];
|
|
827
903
|
let legacyLiveTargets = [];
|
|
828
904
|
if (options.command === 'cleanup' && !options.all) {
|
|
829
|
-
cleanupInventory = await
|
|
830
|
-
cwd: options.commandOptions.cwd,
|
|
831
|
-
env: runtimeEnv,
|
|
832
|
-
});
|
|
905
|
+
cleanupInventory = await readOrdinaryInventory();
|
|
833
906
|
const live = resolveLiveCleanupTargets({
|
|
834
907
|
selectors: requestedPluginNames,
|
|
835
908
|
platforms: selectedPlatforms(options.commandOptions.platform),
|
|
@@ -838,40 +911,30 @@ export async function runRebuildCommand(options) {
|
|
|
838
911
|
});
|
|
839
912
|
requestedPluginNames = live.selectors;
|
|
840
913
|
cleanupLiveTargets = live.targets;
|
|
841
|
-
if (
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
914
|
+
if (expectedOfflineCleanup) {
|
|
915
|
+
const liveTarget = cleanupLiveTargets.find((target) => target.pluginId === expectedOfflineCleanup.pluginId
|
|
916
|
+
&& target.pluginName === expectedOfflineCleanup.pluginName
|
|
917
|
+
&& target.sourceId === expectedOfflineCleanup.sourceId
|
|
918
|
+
&& target.sourceIdentity === expectedOfflineCleanup.sourceIdentity
|
|
919
|
+
&& target.platform === expectedOfflineCleanup.platform
|
|
920
|
+
&& target.scope === expectedOfflineCleanup.scope);
|
|
921
|
+
const actualOfflineCleanup = liveTarget
|
|
922
|
+
? offlineCleanupEvidenceFromInventory({
|
|
923
|
+
...expectedOfflineCleanup,
|
|
924
|
+
inventory: cleanupInventory,
|
|
849
925
|
})
|
|
850
|
-
:
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
926
|
+
: null;
|
|
927
|
+
if (!liveTarget
|
|
928
|
+
|| !actualOfflineCleanup
|
|
929
|
+
|| !offlineCleanupEvidenceMatches(expectedOfflineCleanup, actualOfflineCleanup)) {
|
|
930
|
+
throw namespacedPreflightError('operationReviewStale: offline cleanup ownership evidence changed before mutation.', cleanupLiveTargets);
|
|
931
|
+
}
|
|
932
|
+
cleanupLiveTargets = [liveTarget];
|
|
856
933
|
}
|
|
857
934
|
liveTargets = cleanupLiveTargets;
|
|
858
935
|
}
|
|
859
|
-
if (cleanupHasDamagedExclusiveTarget) {
|
|
860
|
-
return cleanupOfflineOwnedComponents({
|
|
861
|
-
targets: cleanupLiveTargets,
|
|
862
|
-
cwd: options.commandOptions.cwd,
|
|
863
|
-
env: runtimeEnv,
|
|
864
|
-
force: true,
|
|
865
|
-
removeObsoleteInstallationContracts: options.runtime?.removeObsoleteInstallationContracts,
|
|
866
|
-
nativeCliRunner: options.runtime?.nativeCliRunner,
|
|
867
|
-
corruptExclusiveDirectoryOperations: options.runtime?.corruptExclusiveDirectoryOperations,
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
936
|
if (options.all) {
|
|
871
|
-
const inventory = await
|
|
872
|
-
cwd: options.commandOptions.cwd,
|
|
873
|
-
env: runtimeEnv,
|
|
874
|
-
});
|
|
937
|
+
const inventory = await readOrdinaryInventory();
|
|
875
938
|
if (options.command !== 'cleanup')
|
|
876
939
|
assertCatalogSourceInventoryComplete(inventory);
|
|
877
940
|
const requestedPlatforms = new Set(selectedPlatforms(options.commandOptions.platform));
|
|
@@ -902,6 +965,10 @@ export async function runRebuildCommand(options) {
|
|
|
902
965
|
].join('\0'), target];
|
|
903
966
|
})).values()];
|
|
904
967
|
liveTargets = projectedTargets;
|
|
968
|
+
if (options.command === 'cleanup') {
|
|
969
|
+
cleanupInventory = inventory;
|
|
970
|
+
cleanupLiveTargets = projectedTargets;
|
|
971
|
+
}
|
|
905
972
|
const identities = new Map();
|
|
906
973
|
for (const reference of live) {
|
|
907
974
|
if (!reference.sourceIdentity) {
|
|
@@ -924,38 +991,184 @@ export async function runRebuildCommand(options) {
|
|
|
924
991
|
}
|
|
925
992
|
return mergeRebuildCommandResults([]);
|
|
926
993
|
}
|
|
994
|
+
if (options.command === 'cleanup') {
|
|
995
|
+
if (cleanupLiveTargets.some((target) => target.marketplaceIdentityUnresolved)) {
|
|
996
|
+
throw namespacedPreflightError('marketplaceIdentityUnavailable: Cannot uniquely recover the native marketplace name from live inventory or a canonical native registration path.', cleanupLiveTargets);
|
|
997
|
+
}
|
|
998
|
+
if (cleanupLiveTargets.length === 0) {
|
|
999
|
+
const configuredSnapshot = await readCatalogSourcesConfigSnapshot(runtimeEnv).catch(() => null);
|
|
1000
|
+
const configuredSources = new Set(configuredSnapshot?.config.sources.map((source) => source.id) ?? []);
|
|
1001
|
+
const requestedPlatforms = selectedPlatforms(options.commandOptions.platform);
|
|
1002
|
+
const primarySource = configuredSnapshot?.config.sources.find((source) => source.primary)?.id;
|
|
1003
|
+
const unresolvedTargets = requestedPluginNames.flatMap((selector) => {
|
|
1004
|
+
const parsed = parsePluginId(selector);
|
|
1005
|
+
const sourceId = parsed.sourceId ?? primarySource;
|
|
1006
|
+
return sourceId ? requestedPlatforms.map((platform) => ({
|
|
1007
|
+
pluginId: formatPluginId({ sourceId, pluginName: parsed.pluginName }),
|
|
1008
|
+
pluginName: parsed.pluginName,
|
|
1009
|
+
sourceId,
|
|
1010
|
+
sourceIdentity: 'unavailable',
|
|
1011
|
+
platform,
|
|
1012
|
+
scope: options.commandOptions.scope,
|
|
1013
|
+
})) : [];
|
|
1014
|
+
});
|
|
1015
|
+
const inventoryError = cleanupInventory?.errors.find((error) => error.relevance.global || unresolvedTargets.some((target) => !error.relevance.global
|
|
1016
|
+
&& (error.relevance.sourceId === undefined || error.relevance.sourceId === target.sourceId)
|
|
1017
|
+
&& (error.relevance.pluginName === undefined || error.relevance.pluginName === target.pluginName)
|
|
1018
|
+
&& (error.relevance.platform === undefined || error.relevance.platform === target.platform)
|
|
1019
|
+
&& (error.relevance.scope === undefined
|
|
1020
|
+
|| error.relevance.scope === target.scope
|
|
1021
|
+
|| target.platform === 'codex')));
|
|
1022
|
+
if (inventoryError) {
|
|
1023
|
+
throw namespacedPreflightError(`stateInventoryFailed: ${inventoryError.message}`, unresolvedTargets);
|
|
1024
|
+
}
|
|
1025
|
+
const missingTargets = requestedPluginNames.flatMap((selector) => {
|
|
1026
|
+
const parsed = parsePluginId(selector);
|
|
1027
|
+
return parsed.sourceId && !configuredSources.has(parsed.sourceId)
|
|
1028
|
+
? requestedPlatforms.map((platform) => ({
|
|
1029
|
+
pluginId: selector,
|
|
1030
|
+
pluginName: parsed.pluginName,
|
|
1031
|
+
sourceId: parsed.sourceId,
|
|
1032
|
+
sourceIdentity: 'unavailable',
|
|
1033
|
+
platform,
|
|
1034
|
+
scope: options.commandOptions.scope,
|
|
1035
|
+
}))
|
|
1036
|
+
: [];
|
|
1037
|
+
});
|
|
1038
|
+
if (missingTargets.length > 0) {
|
|
1039
|
+
throw namespacedPreflightError('sourceMissing: cleanup target source is unavailable.', missingTargets);
|
|
1040
|
+
}
|
|
1041
|
+
const result = mergeRebuildCommandResults([]);
|
|
1042
|
+
if (cleanupForce && !options.runtime?.previewDependencyPlanOnly) {
|
|
1043
|
+
try {
|
|
1044
|
+
await (options.runtime?.removeObsoleteInstallationContracts ?? fs.remove)(path.join(resolveAwHome(runtimeEnv), 'installation-contracts'));
|
|
1045
|
+
}
|
|
1046
|
+
catch (error) {
|
|
1047
|
+
result.warnings.push(`obsoleteContractsCleanupFailed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
return result;
|
|
1051
|
+
}
|
|
1052
|
+
const configuredSources = await readCatalogSourcesConfigSnapshot(runtimeEnv)
|
|
1053
|
+
.then((snapshot) => new Set(snapshot.config.sources.map((source) => source.id)))
|
|
1054
|
+
.catch(() => new Set());
|
|
1055
|
+
if (!cleanupForce) {
|
|
1056
|
+
await assertOfflineCleanupDependents({
|
|
1057
|
+
targets: cleanupLiveTargets,
|
|
1058
|
+
cwd: options.commandOptions.cwd,
|
|
1059
|
+
env: runtimeEnv,
|
|
1060
|
+
readInventory,
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
const desiredIntent = await readPluginIntentState({
|
|
1064
|
+
scope: options.commandOptions.scope,
|
|
1065
|
+
cwd: options.commandOptions.cwd,
|
|
1066
|
+
env: runtimeEnv,
|
|
1067
|
+
});
|
|
1068
|
+
const desiredFlags = await Promise.all(cleanupLiveTargets.map((target) => cleanupTargetIsDesired({
|
|
1069
|
+
target,
|
|
1070
|
+
roots: desiredIntent.roots,
|
|
1071
|
+
inventory: cleanupInventory,
|
|
1072
|
+
env: runtimeEnv,
|
|
1073
|
+
})));
|
|
1074
|
+
const desiredTargets = cleanupLiveTargets.filter((_, index) => desiredFlags[index]);
|
|
1075
|
+
const removalTargets = cleanupLiveTargets.filter((_, index) => !desiredFlags[index]);
|
|
1076
|
+
if (removalTargets.length === 0) {
|
|
1077
|
+
const result = desiredCleanupNoopResult(desiredTargets, options.commandOptions.cwd);
|
|
1078
|
+
if (cleanupForce && !options.runtime?.previewDependencyPlanOnly) {
|
|
1079
|
+
try {
|
|
1080
|
+
await (options.runtime?.removeObsoleteInstallationContracts ?? fs.remove)(path.join(resolveAwHome(runtimeEnv), 'installation-contracts'));
|
|
1081
|
+
}
|
|
1082
|
+
catch (error) {
|
|
1083
|
+
result.warnings.push(`obsoleteContractsCleanupFailed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return leaseSafeRebuildResult(result);
|
|
1087
|
+
}
|
|
1088
|
+
const evidence = expectedOfflineCleanup
|
|
1089
|
+
? [expectedOfflineCleanup]
|
|
1090
|
+
: removalTargets.flatMap((target) => {
|
|
1091
|
+
const value = offlineCleanupEvidenceFromInventory({
|
|
1092
|
+
reason: configuredSources.has(target.sourceId) ? 'bundleUnavailable' : 'sourceMissing',
|
|
1093
|
+
pluginId: target.pluginId,
|
|
1094
|
+
pluginName: target.pluginName,
|
|
1095
|
+
sourceId: target.sourceId,
|
|
1096
|
+
sourceIdentity: target.sourceIdentity,
|
|
1097
|
+
platform: target.platform,
|
|
1098
|
+
scope: target.scope,
|
|
1099
|
+
inventory: cleanupInventory,
|
|
1100
|
+
});
|
|
1101
|
+
return value ? [value] : [];
|
|
1102
|
+
});
|
|
1103
|
+
if (options.runtime?.previewDependencyPlanOnly) {
|
|
1104
|
+
const previewResult = await previewOfflineOwnedComponents({
|
|
1105
|
+
targets: removalTargets,
|
|
1106
|
+
evidence,
|
|
1107
|
+
cwd: options.commandOptions.cwd,
|
|
1108
|
+
env: runtimeEnv,
|
|
1109
|
+
onPreviewStage: options.runtime.onPreviewStage,
|
|
1110
|
+
});
|
|
1111
|
+
return desiredTargets.length > 0
|
|
1112
|
+
? mergeRebuildCommandResults([
|
|
1113
|
+
desiredCleanupNoopResult(desiredTargets, options.commandOptions.cwd),
|
|
1114
|
+
previewResult,
|
|
1115
|
+
])
|
|
1116
|
+
: previewResult;
|
|
1117
|
+
}
|
|
1118
|
+
const cleanupResult = await cleanupOfflineOwnedComponents({
|
|
1119
|
+
targets: removalTargets,
|
|
1120
|
+
evidence,
|
|
1121
|
+
cwd: options.commandOptions.cwd,
|
|
1122
|
+
env: runtimeEnv,
|
|
1123
|
+
inventoryErrors: cleanupInventory.errors,
|
|
1124
|
+
removeObsoleteInstallationContracts: options.runtime?.removeObsoleteInstallationContracts,
|
|
1125
|
+
nativeCliRunner: options.runtime?.nativeCliRunner,
|
|
1126
|
+
codexManager: options.runtime?.codexManager,
|
|
1127
|
+
});
|
|
1128
|
+
return desiredTargets.length > 0
|
|
1129
|
+
? mergeRebuildCommandResults([
|
|
1130
|
+
desiredCleanupNoopResult(desiredTargets, options.commandOptions.cwd),
|
|
1131
|
+
cleanupResult,
|
|
1132
|
+
])
|
|
1133
|
+
: cleanupResult;
|
|
1134
|
+
}
|
|
927
1135
|
try {
|
|
928
1136
|
if (options.runtime?.previewDependencyPlanOnly) {
|
|
929
1137
|
await options.runtime.onPreviewStage?.('catalog');
|
|
930
1138
|
}
|
|
1139
|
+
if (options.runtime?.catalogBootstrapError !== undefined) {
|
|
1140
|
+
throw options.runtime.catalogBootstrapError;
|
|
1141
|
+
}
|
|
1142
|
+
const catalogOperation = options.runtime?.catalogOperationContext
|
|
1143
|
+
?? await measureCommandPerformanceStage(options.runtime, 'catalog.load', () => resolveCatalogOperationContext({
|
|
1144
|
+
...(sourceIds ? { sourceIds } : {}),
|
|
1145
|
+
env: runtimeEnv,
|
|
1146
|
+
}));
|
|
1147
|
+
if (options.runtime?.expectedGenerationSetDigest
|
|
1148
|
+
&& catalogOperation?.generationSetDigest !== options.runtime.expectedGenerationSetDigest) {
|
|
1149
|
+
throw new Error('operationReviewStale: Active Catalog generation changed before mutation.');
|
|
1150
|
+
}
|
|
931
1151
|
const resolvedResult = await withResolvedMultiSourceCatalog({
|
|
932
1152
|
cliVersion: resolveRuntimeCliVersion(),
|
|
933
|
-
freshnessPolicy: options.command === 'cleanup'
|
|
934
|
-
? 'cacheFirst'
|
|
935
|
-
: options.runtime?.previewDependencyPlanOnly
|
|
936
|
-
? options.runtime.previewCatalogFreshnessPolicy ?? 'requireRemote'
|
|
937
|
-
: 'requireRemote',
|
|
938
1153
|
...(sourceIds ? { sourceIds } : {}),
|
|
1154
|
+
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
939
1155
|
env: runtimeEnv,
|
|
940
1156
|
consume: async (catalog) => {
|
|
941
1157
|
const failedSources = catalog.sources.filter((source) => source.error);
|
|
942
1158
|
if (failedSources.length > 0) {
|
|
943
1159
|
throw namespacedPreflightError(`Cannot resolve required catalog sources: ${failedSources.map((source) => source.sourceId).join(', ')}.`, liveTargets, legacyLiveTargets);
|
|
944
1160
|
}
|
|
945
|
-
const
|
|
1161
|
+
const availableEntries = catalog.sources.flatMap((item) => {
|
|
946
1162
|
const source = item.resolution;
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
const selected = selectors.map((selector, index) => {
|
|
957
|
-
const matches = available.filter((entry) => entry.plugin.manifest.name === selector.pluginName
|
|
958
|
-
&& (selector.sourceId === undefined || entry.source.sourceId === selector.sourceId));
|
|
1163
|
+
return source.manifest.entries.map((entry) => ({
|
|
1164
|
+
source,
|
|
1165
|
+
entry,
|
|
1166
|
+
pluginId: formatPluginId({ sourceId: source.sourceId, pluginName: entry.name }),
|
|
1167
|
+
}));
|
|
1168
|
+
});
|
|
1169
|
+
const selectedEntries = selectors.map((selector, index) => {
|
|
1170
|
+
const matches = availableEntries.filter((candidate) => candidate.entry.name === selector.pluginName
|
|
1171
|
+
&& (selector.sourceId === undefined || candidate.source.sourceId === selector.sourceId));
|
|
959
1172
|
if (matches.length === 0) {
|
|
960
1173
|
throw new Error(`Plugin "${requestedPluginNames[index]}" does not exist in the required catalog source set.`);
|
|
961
1174
|
}
|
|
@@ -967,6 +1180,74 @@ export async function runRebuildCommand(options) {
|
|
|
967
1180
|
const dependencyEnabled = options.command === 'install'
|
|
968
1181
|
|| options.command === 'upgrade'
|
|
969
1182
|
|| options.command === 'reinstall';
|
|
1183
|
+
const entryClosure = (roots) => {
|
|
1184
|
+
const result = [];
|
|
1185
|
+
const seen = new Set();
|
|
1186
|
+
const visiting = new Set();
|
|
1187
|
+
const byId = new Map(availableEntries.map((candidate) => [candidate.pluginId, candidate]));
|
|
1188
|
+
const visit = (candidate) => {
|
|
1189
|
+
if (seen.has(candidate.pluginId))
|
|
1190
|
+
return;
|
|
1191
|
+
if (visiting.has(candidate.pluginId))
|
|
1192
|
+
throw new Error(`Catalog dependency cycle includes "${candidate.pluginId}".`);
|
|
1193
|
+
visiting.add(candidate.pluginId);
|
|
1194
|
+
for (const dependency of candidate.entry.dependencies) {
|
|
1195
|
+
const dependencyId = formatPluginId({ sourceId: candidate.source.sourceId, pluginName: dependency });
|
|
1196
|
+
const resolved = byId.get(dependencyId);
|
|
1197
|
+
if (!resolved)
|
|
1198
|
+
throw new Error(`Catalog plugin "${candidate.pluginId}" depends on missing plugin "${dependency}".`);
|
|
1199
|
+
visit(resolved);
|
|
1200
|
+
}
|
|
1201
|
+
visiting.delete(candidate.pluginId);
|
|
1202
|
+
seen.add(candidate.pluginId);
|
|
1203
|
+
result.push(candidate);
|
|
1204
|
+
};
|
|
1205
|
+
for (const root of roots)
|
|
1206
|
+
visit(root);
|
|
1207
|
+
return result;
|
|
1208
|
+
};
|
|
1209
|
+
const removalConsumerEntries = options.command === 'cleanup' || options.command === 'uninstall'
|
|
1210
|
+
? availableEntries.filter((candidate) => selectedEntries.some((selectedEntry) => candidate.source.sourceId === selectedEntry.source.sourceId
|
|
1211
|
+
&& candidate.entry.dependencies.includes(selectedEntry.entry.name)))
|
|
1212
|
+
: [];
|
|
1213
|
+
const removalDesiredEntries = options.command === 'cleanup' || options.command === 'uninstall'
|
|
1214
|
+
? entryClosure(selectedEntries)
|
|
1215
|
+
: [];
|
|
1216
|
+
const requiredEntryClosure = dependencyEnabled
|
|
1217
|
+
? entryClosure(selectedEntries)
|
|
1218
|
+
: [...new Map([
|
|
1219
|
+
...selectedEntries,
|
|
1220
|
+
...removalDesiredEntries,
|
|
1221
|
+
...removalConsumerEntries,
|
|
1222
|
+
].map((candidate) => [candidate.pluginId, candidate])).values()];
|
|
1223
|
+
if (dependencyEnabled) {
|
|
1224
|
+
for (const candidate of requiredEntryClosure) {
|
|
1225
|
+
const requiredCapabilities = candidate.entry.requires.aw.capabilities ?? [];
|
|
1226
|
+
const support = checkAwCapabilitySupport(requiredCapabilities, IMPLEMENTED_AW_CAPABILITIES);
|
|
1227
|
+
if (!support.supported) {
|
|
1228
|
+
throw new AwCapabilityUnsupportedError(candidate.pluginId, support.missing);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
await measureCommandPerformanceStage(options.runtime, 'catalog.validation', async () => {
|
|
1232
|
+
for (const item of catalog.sources) {
|
|
1233
|
+
const source = item.resolution;
|
|
1234
|
+
const names = requiredEntryClosure
|
|
1235
|
+
.filter((candidate) => candidate.source.sourceId === source.sourceId)
|
|
1236
|
+
.map((candidate) => candidate.entry.name);
|
|
1237
|
+
if (names.length > 0) {
|
|
1238
|
+
await validateCatalogSnapshotPluginEntriesComplete(source.rootDir, names);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
const available = await Promise.all(requiredEntryClosure.map(async (candidate) => {
|
|
1244
|
+
const plugin = await readPluginManifest(path.join(candidate.source.rootDir, 'plugins', candidate.entry.name), { mode: 'bundle' });
|
|
1245
|
+
plugin.sourceId = candidate.source.sourceId;
|
|
1246
|
+
plugin.sourceIdentity = candidate.source.sourceIdentity;
|
|
1247
|
+
plugin.pluginId = candidate.pluginId;
|
|
1248
|
+
return { source: candidate.source, plugin, pluginId: candidate.pluginId };
|
|
1249
|
+
}));
|
|
1250
|
+
const selected = selectedEntries.map((entry) => available.find((candidate) => candidate.pluginId === entry.pluginId));
|
|
970
1251
|
const selectedIds = new Set(selected.map((entry) => entry.pluginId));
|
|
971
1252
|
const resolveClosureEntries = (rootsBySource) => catalog.sources.flatMap((item) => {
|
|
972
1253
|
const source = item.resolution;
|
|
@@ -993,7 +1274,9 @@ export async function runRebuildCommand(options) {
|
|
|
993
1274
|
}
|
|
994
1275
|
const closureEntries = dependencyEnabled
|
|
995
1276
|
? [...new Map([...closureEntriesByPlatform.values()].flat().map((entry) => [entry.pluginId, entry])).values()]
|
|
996
|
-
:
|
|
1277
|
+
: options.command === 'cleanup' || options.command === 'uninstall'
|
|
1278
|
+
? resolveClosureEntries(selected)
|
|
1279
|
+
: selected;
|
|
997
1280
|
const rawExecutionSelections = options.all
|
|
998
1281
|
? liveTargets.flatMap((target) => {
|
|
999
1282
|
const entry = selected.find((candidate) => candidate.pluginId === target.pluginId);
|
|
@@ -1034,12 +1317,23 @@ export async function runRebuildCommand(options) {
|
|
|
1034
1317
|
if (options.runtime?.previewDependencyPlanOnly) {
|
|
1035
1318
|
await options.runtime.onPreviewStage?.('inventory');
|
|
1036
1319
|
}
|
|
1037
|
-
const stateInventory = await
|
|
1038
|
-
cwd: options.commandOptions.cwd,
|
|
1039
|
-
env: runtimeEnv,
|
|
1040
|
-
});
|
|
1320
|
+
const stateInventory = await readOrdinaryInventory();
|
|
1041
1321
|
if (options.command !== 'cleanup')
|
|
1042
1322
|
assertCatalogSourceInventoryComplete(stateInventory);
|
|
1323
|
+
const hasCodexSelection = executionSelections.some((selection) => selection.platform === 'codex');
|
|
1324
|
+
const intentBeforeByScope = hasCodexSelection || dependencyEnabled
|
|
1325
|
+
? {
|
|
1326
|
+
user: await readPluginIntentState({
|
|
1327
|
+
scope: 'user', cwd: options.commandOptions.cwd, env: runtimeEnv,
|
|
1328
|
+
}),
|
|
1329
|
+
project: await readPluginIntentState({
|
|
1330
|
+
scope: 'project', cwd: options.commandOptions.cwd, env: runtimeEnv,
|
|
1331
|
+
}),
|
|
1332
|
+
}
|
|
1333
|
+
: {
|
|
1334
|
+
user: createEmptyPluginIntentState(),
|
|
1335
|
+
project: createEmptyPluginIntentState(),
|
|
1336
|
+
};
|
|
1043
1337
|
const commandProjectKey = await resolveCanonicalRepoProjectKey(options.commandOptions.cwd);
|
|
1044
1338
|
const codexScopePathsAlias = codexProjectConfigAliasesUserHome(options.commandOptions.cwd, runtimeEnv);
|
|
1045
1339
|
const selectedLegacy = selectedLegacyLiveReferences(stateInventory.references, new Set(executionSelections.map((selection) => selection.platform)), options.commandOptions.scope);
|
|
@@ -1121,22 +1415,33 @@ export async function runRebuildCommand(options) {
|
|
|
1121
1415
|
nativeCliRunner: options.runtime?.nativeCliRunner ?? getDefaultNativeCliRunner(),
|
|
1122
1416
|
reporter: options.runtime?.reporter ?? createNoopReporter(),
|
|
1123
1417
|
debugLogger: options.runtime?.debugLogger ?? createNoopDebugLogger(),
|
|
1124
|
-
runtimeLeaseHeld: options.runtime?.runtimeLeaseHeld,
|
|
1125
|
-
lifecycleLeaseHeld: options.runtime?.lifecycleLeaseHeld,
|
|
1126
1418
|
expectedCatalogConfigDigest: catalog.configDigest,
|
|
1127
1419
|
};
|
|
1128
1420
|
const inspection = createRebuildIntegration({
|
|
1129
1421
|
context: executionContext,
|
|
1130
1422
|
scriptTimeoutMs: options.commandOptions.scriptTimeoutMs,
|
|
1131
1423
|
});
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1424
|
+
const selectedRootsForPlan = (plan) => [...new Map(plan.targets.flatMap((target) => target.relation === 'requested'
|
|
1425
|
+
? [[target.pluginId, {
|
|
1426
|
+
pluginId: target.pluginId,
|
|
1427
|
+
platforms: plan.targets.flatMap((candidate) => candidate.relation === 'requested'
|
|
1428
|
+
&& candidate.pluginId === target.pluginId
|
|
1429
|
+
? [candidate.platform]
|
|
1430
|
+
: []),
|
|
1431
|
+
}]]
|
|
1432
|
+
: [])).values()];
|
|
1433
|
+
const createPlan = async (inventory) => {
|
|
1137
1434
|
if (options.command !== 'cleanup')
|
|
1138
1435
|
assertCatalogSourceInventoryComplete(inventory);
|
|
1436
|
+
const codexActivationSnapshots = executionSelections.some((selection) => selection.platform === 'codex')
|
|
1437
|
+
? Object.fromEntries(await Promise.all(['user', 'project'].map(async (scope) => [
|
|
1438
|
+
scope,
|
|
1439
|
+
(await readCodexConfigFile(resolveCodexPaths(options.commandOptions.cwd, scope, runtimeEnv).configTomlPath)).snapshot,
|
|
1440
|
+
])))
|
|
1441
|
+
: undefined;
|
|
1139
1442
|
const targets = [];
|
|
1443
|
+
const placementNodes = [];
|
|
1444
|
+
const blockingTargets = new Map();
|
|
1140
1445
|
for (const [order, { entry, platform }] of executionSelections.entries()) {
|
|
1141
1446
|
const relation = selectedIds.has(entry.pluginId) ? 'requested' : 'dependency';
|
|
1142
1447
|
let resolvedScope = options.commandOptions.scope;
|
|
@@ -1172,8 +1477,8 @@ export async function runRebuildCommand(options) {
|
|
|
1172
1477
|
const hasUnexpectedPresent = result.components.some((entry) => entry.state === 'present' && !required.has(entry.component) && !optional.has(entry.component));
|
|
1173
1478
|
const hasPartial = result.components.some((entry) => entry.state === 'partial');
|
|
1174
1479
|
const hasAnyPresent = result.components.some((entry) => entry.state === 'present');
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1480
|
+
const hasAnyOwned = hasAnyPresent || hasPartial;
|
|
1481
|
+
const state = !hasAnyOwned
|
|
1177
1482
|
? 'absent'
|
|
1178
1483
|
: hasPartial || hasUnexpectedPresent || !presentRequired
|
|
1179
1484
|
? 'partial'
|
|
@@ -1189,26 +1494,90 @@ export async function runRebuildCommand(options) {
|
|
|
1189
1494
|
? Promise.resolve({ state: 'absent', components: [], errors: [] })
|
|
1190
1495
|
: inspectScope(otherScope),
|
|
1191
1496
|
]);
|
|
1192
|
-
|
|
1497
|
+
const surface = platform === 'codex'
|
|
1498
|
+
? analyzeCodexSurface(entry.plugin.manifest)
|
|
1499
|
+
: undefined;
|
|
1500
|
+
const codexPluginId = `${entry.plugin.manifest.name}@${marketplaceNameFor(entry, platform, resolvedScope)}`;
|
|
1501
|
+
const placementState = (inspected, scope) => {
|
|
1502
|
+
if (platform !== 'codex'
|
|
1503
|
+
|| surface?.classification !== 'native'
|
|
1504
|
+
|| options.command === 'cleanup'
|
|
1505
|
+
|| options.command === 'uninstall')
|
|
1506
|
+
return inspected.state;
|
|
1507
|
+
const nativePresent = inspected.components.some((component) => component.component.kind === 'native-plugin' && component.state === 'present');
|
|
1508
|
+
return nativePresent
|
|
1509
|
+
&& codexActivationSnapshots?.[scope].plugins[codexPluginId]?.enabled === true
|
|
1510
|
+
? 'present'
|
|
1511
|
+
: 'absent';
|
|
1512
|
+
};
|
|
1513
|
+
const requestedPlacementState = placementState(requestedInspection, options.commandOptions.scope);
|
|
1514
|
+
let otherPlacementState = placementState(otherInspection, otherScope);
|
|
1515
|
+
if (surface?.classification === 'native'
|
|
1516
|
+
&& requestedPlacementState === 'present'
|
|
1517
|
+
&& otherPlacementState === 'present') {
|
|
1518
|
+
otherPlacementState = 'absent';
|
|
1519
|
+
}
|
|
1520
|
+
const allowedScopes = platform === 'codex'
|
|
1521
|
+
? [
|
|
1522
|
+
...(surface?.ok ? ['user'] : []),
|
|
1523
|
+
...(surface?.ok && !codexScopePathsAlias ? ['project'] : []),
|
|
1524
|
+
]
|
|
1525
|
+
: ['project', 'user'];
|
|
1526
|
+
if (allowedScopes.length === 0)
|
|
1527
|
+
allowedScopes.push(options.commandOptions.scope);
|
|
1528
|
+
placementNodes.push({
|
|
1529
|
+
pluginId: entry.pluginId,
|
|
1530
|
+
pluginName: entry.plugin.manifest.name,
|
|
1531
|
+
platform,
|
|
1532
|
+
relation,
|
|
1533
|
+
depth: order,
|
|
1534
|
+
allowedScopes,
|
|
1535
|
+
current: {
|
|
1536
|
+
project: options.commandOptions.scope === 'project'
|
|
1537
|
+
? requestedPlacementState
|
|
1538
|
+
: otherPlacementState,
|
|
1539
|
+
user: options.commandOptions.scope === 'user'
|
|
1540
|
+
? requestedPlacementState
|
|
1541
|
+
: otherPlacementState,
|
|
1542
|
+
},
|
|
1543
|
+
});
|
|
1544
|
+
let state = requestedPlacementState;
|
|
1193
1545
|
let action = relation === 'requested'
|
|
1194
1546
|
? options.command
|
|
1195
1547
|
: options.command === 'reinstall' ? 'reinstall' : 'upgrade';
|
|
1196
1548
|
let errorCode;
|
|
1197
1549
|
const hasForeignCollision = [...requestedInspection.components, ...otherInspection.components]
|
|
1198
|
-
.some((component) => component.
|
|
1550
|
+
.some((component) => component.collision !== undefined);
|
|
1199
1551
|
if (dependencyEnabled && hasForeignCollision) {
|
|
1200
1552
|
action = 'block';
|
|
1201
1553
|
errorCode = 'artifactCollision';
|
|
1202
1554
|
}
|
|
1555
|
+
else if (dependencyEnabled
|
|
1556
|
+
&& platform === 'codex'
|
|
1557
|
+
&& relation === 'requested'
|
|
1558
|
+
&& surface?.scopeOverlap === 'aw-owned-conflict'
|
|
1559
|
+
&& options.runtime?.reconcileIntentOnly !== true
|
|
1560
|
+
&& !(options.command === 'install'
|
|
1561
|
+
&& intentBeforeByScope[otherScope].roots.some((root) => root.pluginId === entry.pluginId && root.platforms.includes(platform)))
|
|
1562
|
+
&& otherInspection.components.some((component) => component.state !== 'absent'
|
|
1563
|
+
&& component.component.kind !== 'native-plugin'
|
|
1564
|
+
&& !component.component.identity.artifactKey.startsWith('activation-')
|
|
1565
|
+
&& !component.component.identity.artifactKey.startsWith('marketplace-'))) {
|
|
1566
|
+
action = 'block';
|
|
1567
|
+
errorCode = 'codexExtensionScopeConflict';
|
|
1568
|
+
}
|
|
1203
1569
|
else if (dependencyEnabled && relation === 'requested'
|
|
1204
1570
|
&& (requestedInspection.state === 'error'
|
|
1205
|
-
|| (requestedInspection.state === 'partial'
|
|
1571
|
+
|| (requestedInspection.state === 'partial'
|
|
1572
|
+
&& platform !== 'codex'
|
|
1573
|
+
&& options.command !== 'reinstall'
|
|
1574
|
+
&& options.command !== 'cleanup'))) {
|
|
1206
1575
|
action = 'block';
|
|
1207
1576
|
errorCode = 'dependencyNotReady';
|
|
1208
1577
|
}
|
|
1209
1578
|
if (!hasForeignCollision && relation === 'dependency'
|
|
1210
|
-
&&
|
|
1211
|
-
&&
|
|
1579
|
+
&& requestedPlacementState === 'present'
|
|
1580
|
+
&& otherPlacementState === 'present') {
|
|
1212
1581
|
action = 'block';
|
|
1213
1582
|
state = 'partial';
|
|
1214
1583
|
errorCode = 'dependencyScopeConflict';
|
|
@@ -1221,24 +1590,26 @@ export async function runRebuildCommand(options) {
|
|
|
1221
1590
|
}
|
|
1222
1591
|
else if (!hasForeignCollision && relation === 'dependency'
|
|
1223
1592
|
&& options.commandOptions.scope === 'project'
|
|
1224
|
-
&& (
|
|
1593
|
+
&& (otherPlacementState === 'partial' || otherPlacementState === 'error')) {
|
|
1225
1594
|
resolvedScope = 'user';
|
|
1226
|
-
state =
|
|
1227
|
-
if (
|
|
1595
|
+
state = otherPlacementState;
|
|
1596
|
+
if (otherPlacementState === 'error') {
|
|
1228
1597
|
action = 'block';
|
|
1229
1598
|
errorCode = 'dependencyNotReady';
|
|
1230
1599
|
}
|
|
1231
1600
|
}
|
|
1232
1601
|
else if (!hasForeignCollision && relation === 'dependency'
|
|
1233
1602
|
&& options.commandOptions.scope === 'user'
|
|
1234
|
-
&&
|
|
1603
|
+
&& otherPlacementState !== 'absent') {
|
|
1235
1604
|
action = 'block';
|
|
1236
1605
|
errorCode = 'dependencyScopeTooNarrow';
|
|
1237
1606
|
}
|
|
1238
1607
|
const resolvedInspection = resolvedScope === options.commandOptions.scope
|
|
1239
1608
|
? requestedInspection
|
|
1240
1609
|
: otherInspection;
|
|
1241
|
-
state =
|
|
1610
|
+
state = resolvedScope === options.commandOptions.scope
|
|
1611
|
+
? requestedPlacementState
|
|
1612
|
+
: otherPlacementState;
|
|
1242
1613
|
if (!hasForeignCollision && !errorCode
|
|
1243
1614
|
&& relation === 'dependency' && options.command === 'install') {
|
|
1244
1615
|
action = state === 'present' ? 'keep' : state === 'partial' ? 'reinstall' : 'install';
|
|
@@ -1249,13 +1620,6 @@ export async function runRebuildCommand(options) {
|
|
|
1249
1620
|
state = resolvedInspection.state;
|
|
1250
1621
|
errorCode ??= 'dependencyNotReady';
|
|
1251
1622
|
}
|
|
1252
|
-
if (!hasForeignCollision && relation === 'dependency'
|
|
1253
|
-
&& platform === 'codex'
|
|
1254
|
-
&& resolvedScope === 'project'
|
|
1255
|
-
&& (entry.plugin.manifest.apps || !hasCodexProjectManagedArtifacts(entry.plugin))) {
|
|
1256
|
-
action = 'block';
|
|
1257
|
-
errorCode = 'dependencyTargetUnsupported';
|
|
1258
|
-
}
|
|
1259
1623
|
if (entry.plugin.manifest.config?.schema
|
|
1260
1624
|
&& (action === 'install' || action === 'upgrade' || action === 'reinstall')) {
|
|
1261
1625
|
const effective = await resolveEffectivePluginConfig({
|
|
@@ -1278,6 +1642,12 @@ export async function runRebuildCommand(options) {
|
|
|
1278
1642
|
action = 'block';
|
|
1279
1643
|
errorCode = 'codexScopePathAlias';
|
|
1280
1644
|
}
|
|
1645
|
+
if (dependencyEnabled && platform === 'codex' && !surface?.ok) {
|
|
1646
|
+
action = 'block';
|
|
1647
|
+
errorCode = surface?.errorCode ?? 'codexNativeKindUnsupported';
|
|
1648
|
+
}
|
|
1649
|
+
if (errorCode)
|
|
1650
|
+
blockingTargets.set(`${entry.pluginId}\0${platform}`, errorCode);
|
|
1281
1651
|
targets.push({
|
|
1282
1652
|
pluginId: entry.pluginId,
|
|
1283
1653
|
pluginName: entry.plugin.manifest.name,
|
|
@@ -1295,6 +1665,46 @@ export async function runRebuildCommand(options) {
|
|
|
1295
1665
|
...(errorCode ? { errorCode } : {}),
|
|
1296
1666
|
});
|
|
1297
1667
|
}
|
|
1668
|
+
if (dependencyEnabled) {
|
|
1669
|
+
const placement = createDependencyPlacementPlan({
|
|
1670
|
+
requestedPluginIds: selected.map((entry) => entry.pluginId),
|
|
1671
|
+
nodes: placementNodes,
|
|
1672
|
+
roots: placementNodes.flatMap((node) => selectedIds.has(node.pluginId)
|
|
1673
|
+
? [{ pluginId: node.pluginId, platform: node.platform, scope: options.commandOptions.scope }]
|
|
1674
|
+
: []),
|
|
1675
|
+
dependencyEdges: closureEntries.flatMap((entry) => (entry.plugin.manifest.dependencies ?? []).flatMap((dependency) => {
|
|
1676
|
+
const dependencyId = formatPluginId({
|
|
1677
|
+
sourceId: entry.source.sourceId,
|
|
1678
|
+
pluginName: dependency,
|
|
1679
|
+
});
|
|
1680
|
+
return ['codex', 'claude'].flatMap((platform) => placementNodes.some((node) => node.pluginId === entry.pluginId && node.platform === platform)
|
|
1681
|
+
&& placementNodes.some((node) => node.pluginId === dependencyId && node.platform === platform)
|
|
1682
|
+
? [{ from: entry.pluginId, to: dependencyId, platform }]
|
|
1683
|
+
: []);
|
|
1684
|
+
})),
|
|
1685
|
+
scopeOverrides: effectiveDependencyScopeOverrides({
|
|
1686
|
+
state: intentBeforeByScope[options.commandOptions.scope],
|
|
1687
|
+
explicit: options.commandOptions
|
|
1688
|
+
.dependencyScopeOverrides ?? [],
|
|
1689
|
+
nodes: placementNodes,
|
|
1690
|
+
ignoredPersistedRootIds: selectedIds,
|
|
1691
|
+
}),
|
|
1692
|
+
operation: options.command,
|
|
1693
|
+
});
|
|
1694
|
+
return createDependencyOperationPlan({
|
|
1695
|
+
requestedPluginIds: placement.requestedPluginIds,
|
|
1696
|
+
resolvedPluginIds: placement.resolvedPluginIds,
|
|
1697
|
+
dependencyEdges: placement.dependencyEdges,
|
|
1698
|
+
scopeOverrides: placement.scopeOverrides,
|
|
1699
|
+
claimRoots: placement.claimRoots,
|
|
1700
|
+
targets: placement.targets.map((target) => {
|
|
1701
|
+
const errorCode = blockingTargets.get(`${target.pluginId}\0${target.platform}`);
|
|
1702
|
+
return errorCode
|
|
1703
|
+
? { ...target, action: 'block', errorCode }
|
|
1704
|
+
: target;
|
|
1705
|
+
}),
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1298
1708
|
return createDependencyOperationPlan({
|
|
1299
1709
|
requestedPluginIds: selected.map((entry) => entry.pluginId),
|
|
1300
1710
|
resolvedPluginIds: closureEntries.map((entry) => entry.pluginId),
|
|
@@ -1305,11 +1715,302 @@ export async function runRebuildCommand(options) {
|
|
|
1305
1715
|
targets,
|
|
1306
1716
|
});
|
|
1307
1717
|
};
|
|
1718
|
+
const createCodexPlans = async (plan, activationSupport = 'observed') => {
|
|
1719
|
+
const codexTargets = plan.targets.filter((target) => target.platform === 'codex');
|
|
1720
|
+
const selectedRoots = selectedRootsForPlan(plan);
|
|
1721
|
+
const currentScope = options.commandOptions.scope;
|
|
1722
|
+
const otherScope = currentScope === 'user' ? 'project' : 'user';
|
|
1723
|
+
const reconciledCodexTargets = codexTargets;
|
|
1724
|
+
if (reconciledCodexTargets.length === 0)
|
|
1725
|
+
return [];
|
|
1726
|
+
const beforeByScope = intentBeforeByScope;
|
|
1727
|
+
const afterByScope = {
|
|
1728
|
+
user: beforeByScope.user,
|
|
1729
|
+
project: beforeByScope.project,
|
|
1730
|
+
};
|
|
1731
|
+
afterByScope[currentScope] = deriveDesiredIntentState({
|
|
1732
|
+
command: options.command,
|
|
1733
|
+
state: beforeByScope[currentScope],
|
|
1734
|
+
selectedRoots,
|
|
1735
|
+
plan,
|
|
1736
|
+
reconcileIntentOnly: options.runtime?.reconcileIntentOnly,
|
|
1737
|
+
});
|
|
1738
|
+
if (options.command === 'install' && options.runtime?.reconcileIntentOnly !== true) {
|
|
1739
|
+
let other = afterByScope[otherScope];
|
|
1740
|
+
for (const root of selectedRoots)
|
|
1741
|
+
other = removePluginIntentRootPlatforms(other, root);
|
|
1742
|
+
afterByScope[otherScope] = other;
|
|
1743
|
+
}
|
|
1744
|
+
const desiredScopesForEntry = (entry) => {
|
|
1745
|
+
const scopes = new Set();
|
|
1746
|
+
for (const intentScope of ['user', 'project']) {
|
|
1747
|
+
const intent = afterByScope[intentScope];
|
|
1748
|
+
for (const root of intent.roots.filter((candidate) => candidate.platforms.includes('codex'))) {
|
|
1749
|
+
const rootEntry = available.find((candidate) => candidate.pluginId === root.pluginId);
|
|
1750
|
+
if (!rootEntry || rootEntry.source.sourceId !== entry.source.sourceId)
|
|
1751
|
+
continue;
|
|
1752
|
+
const sourcePlugins = available
|
|
1753
|
+
.filter((candidate) => candidate.source.sourceId === entry.source.sourceId)
|
|
1754
|
+
.map((candidate) => candidate.plugin);
|
|
1755
|
+
let closure;
|
|
1756
|
+
try {
|
|
1757
|
+
closure = resolvePluginMetaDependencyClosure(sourcePlugins, [rootEntry.plugin.manifest.name]);
|
|
1758
|
+
}
|
|
1759
|
+
catch {
|
|
1760
|
+
closure = [rootEntry.plugin];
|
|
1761
|
+
}
|
|
1762
|
+
if (!closure.some((plugin) => plugin.manifest.name === entry.plugin.manifest.name)) {
|
|
1763
|
+
continue;
|
|
1764
|
+
}
|
|
1765
|
+
const currentPlannedScope = intentScope === currentScope
|
|
1766
|
+
&& selectedRoots.some((selectedRoot) => selectedRoot.pluginId === root.pluginId)
|
|
1767
|
+
? plan.targets.find((target) => target.pluginId === entry.pluginId && target.platform === 'codex')?.resolvedScope
|
|
1768
|
+
: undefined;
|
|
1769
|
+
const override = intent.dependencyScopeOverrides.find((candidate) => candidate.pluginId === entry.pluginId && candidate.platform === 'codex');
|
|
1770
|
+
const reusedUserDependency = intentScope === 'project'
|
|
1771
|
+
&& root.pluginId !== entry.pluginId
|
|
1772
|
+
&& scopes.has('user');
|
|
1773
|
+
scopes.add(currentPlannedScope
|
|
1774
|
+
?? override?.scope
|
|
1775
|
+
?? (reusedUserDependency ? 'user' : intentScope));
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
return [...scopes].sort();
|
|
1779
|
+
};
|
|
1780
|
+
const intentScopesForEntry = (entry) => {
|
|
1781
|
+
const scopes = new Set();
|
|
1782
|
+
for (const intentScope of ['user', 'project']) {
|
|
1783
|
+
for (const root of afterByScope[intentScope].roots.filter((candidate) => candidate.platforms.includes('codex'))) {
|
|
1784
|
+
const rootEntry = available.find((candidate) => candidate.pluginId === root.pluginId);
|
|
1785
|
+
if (!rootEntry || rootEntry.source.sourceId !== entry.source.sourceId)
|
|
1786
|
+
continue;
|
|
1787
|
+
const sourcePlugins = available
|
|
1788
|
+
.filter((candidate) => candidate.source.sourceId === entry.source.sourceId)
|
|
1789
|
+
.map((candidate) => candidate.plugin);
|
|
1790
|
+
let closure;
|
|
1791
|
+
try {
|
|
1792
|
+
closure = resolvePluginMetaDependencyClosure(sourcePlugins, [rootEntry.plugin.manifest.name]);
|
|
1793
|
+
}
|
|
1794
|
+
catch {
|
|
1795
|
+
closure = [rootEntry.plugin];
|
|
1796
|
+
}
|
|
1797
|
+
if (closure.some((plugin) => plugin.manifest.name === entry.plugin.manifest.name)) {
|
|
1798
|
+
scopes.add(intentScope);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return [...scopes].sort();
|
|
1803
|
+
};
|
|
1804
|
+
const inspectBothScopes = options.command !== 'cleanup' && options.command !== 'uninstall';
|
|
1805
|
+
const readActivationConfig = async (scope) => {
|
|
1806
|
+
return readCodexConfigFile(resolveCodexPaths(options.commandOptions.cwd, scope, runtimeEnv).configTomlPath);
|
|
1807
|
+
};
|
|
1808
|
+
const [userConfig, projectConfig] = await Promise.all([
|
|
1809
|
+
readActivationConfig('user'),
|
|
1810
|
+
readActivationConfig('project'),
|
|
1811
|
+
]);
|
|
1812
|
+
const catalogClosure = [];
|
|
1813
|
+
const liveEvidence = [];
|
|
1814
|
+
for (const planned of reconciledCodexTargets) {
|
|
1815
|
+
const entry = available.find((candidate) => candidate.pluginId === planned.pluginId);
|
|
1816
|
+
const surface = analyzeCodexSurface(entry.plugin.manifest);
|
|
1817
|
+
const marketplaceName = marketplaceNameFor(entry, 'codex', planned.resolvedScope);
|
|
1818
|
+
const codexPluginId = `${entry.plugin.manifest.name}@${marketplaceName}`;
|
|
1819
|
+
const contentDigest = await calculateCodexSharedNativePayloadDigest(entry.plugin.rootDir);
|
|
1820
|
+
const desiredScopes = desiredScopesForEntry(entry);
|
|
1821
|
+
catalogClosure.push({
|
|
1822
|
+
pluginId: entry.pluginId,
|
|
1823
|
+
pluginName: entry.plugin.manifest.name,
|
|
1824
|
+
codexPluginId,
|
|
1825
|
+
version: entry.plugin.manifest.version,
|
|
1826
|
+
payloadDigest: contentDigest,
|
|
1827
|
+
relation: planned.relation,
|
|
1828
|
+
resolvedScope: planned.resolvedScope,
|
|
1829
|
+
desiredScopes,
|
|
1830
|
+
intentScopes: intentScopesForEntry(entry),
|
|
1831
|
+
surface,
|
|
1832
|
+
});
|
|
1833
|
+
const managedBefore = beforeByScope.user.managed.codexPluginIds.includes(codexPluginId)
|
|
1834
|
+
|| beforeByScope.project.managed.codexPluginIds.includes(codexPluginId);
|
|
1835
|
+
const sharedInspection = surface.nativeKinds.length > 0
|
|
1836
|
+
? await inspectCodexSharedNativeLive({
|
|
1837
|
+
pluginName: entry.plugin.manifest.name,
|
|
1838
|
+
desiredVersion: entry.plugin.manifest.version,
|
|
1839
|
+
expectedPayloadDigest: contentDigest,
|
|
1840
|
+
cwd: options.commandOptions.cwd,
|
|
1841
|
+
env: runtimeEnv,
|
|
1842
|
+
managedByCurrentIntent: managedBefore,
|
|
1843
|
+
marketplaceName,
|
|
1844
|
+
marketplaceRoot: path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId),
|
|
1845
|
+
})
|
|
1846
|
+
: undefined;
|
|
1847
|
+
const sharedNative = sharedInspection?.sharedNative
|
|
1848
|
+
?? { state: 'absent', nativeAction: 'install' };
|
|
1849
|
+
const projectionEntries = [];
|
|
1850
|
+
const extensions = [];
|
|
1851
|
+
for (const scope of (inspectBothScopes
|
|
1852
|
+
? ['user', 'project']
|
|
1853
|
+
: [currentScope])) {
|
|
1854
|
+
const desired = await inspection.buildTarget({
|
|
1855
|
+
sourceId: entry.source.sourceId,
|
|
1856
|
+
sourceIdentity: entry.source.sourceIdentity,
|
|
1857
|
+
pluginId: entry.pluginId,
|
|
1858
|
+
marketplaceName,
|
|
1859
|
+
marketplaceRoot: path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId),
|
|
1860
|
+
plugin: entry.plugin,
|
|
1861
|
+
platform: 'codex',
|
|
1862
|
+
scope,
|
|
1863
|
+
cwd: options.commandOptions.cwd,
|
|
1864
|
+
command: options.command,
|
|
1865
|
+
catalog: toCatalogResolution(entry.source),
|
|
1866
|
+
includeHistoricalLifecycleArtifacts: false,
|
|
1867
|
+
readOnlyInspectionPlan: true,
|
|
1868
|
+
});
|
|
1869
|
+
const inspected = await inspectOwnedComponents({
|
|
1870
|
+
components: desired.ownedComponents,
|
|
1871
|
+
nativeProbe: inspection.driver.probeNative,
|
|
1872
|
+
verifyHealth: true,
|
|
1873
|
+
});
|
|
1874
|
+
const projected = inspected.components.filter((component) => component.component.kind !== 'native-plugin'
|
|
1875
|
+
&& !component.component.identity.artifactKey.startsWith('activation-')
|
|
1876
|
+
&& !component.component.identity.artifactKey.startsWith('marketplace-'));
|
|
1877
|
+
projectionEntries.push(...projected.map((component) => ({
|
|
1878
|
+
scope,
|
|
1879
|
+
artifactKey: component.component.identity.artifactKey,
|
|
1880
|
+
state: component.state,
|
|
1881
|
+
collision: component.collision?.reason,
|
|
1882
|
+
})));
|
|
1883
|
+
const projectionState = projected.some((component) => component.collision)
|
|
1884
|
+
? planned.action === 'block' ? 'absent' : 'foreign'
|
|
1885
|
+
: projected.some((component) => component.state === 'partial'
|
|
1886
|
+
|| component.state === 'error')
|
|
1887
|
+
? 'drifted'
|
|
1888
|
+
: projected.some((component) => component.state === 'present')
|
|
1889
|
+
? 'present'
|
|
1890
|
+
: 'absent';
|
|
1891
|
+
for (const component of surface.components.filter((candidate) => candidate.owner === 'aw')) {
|
|
1892
|
+
extensions.push({ componentKey: component.key, scope, state: projectionState });
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
liveEvidence.push({
|
|
1896
|
+
codexPluginId,
|
|
1897
|
+
sharedNative,
|
|
1898
|
+
...(sharedInspection?.actualPayloadDigest
|
|
1899
|
+
? { sharedNativePayloadDigest: sharedInspection.actualPayloadDigest }
|
|
1900
|
+
: {}),
|
|
1901
|
+
...(sharedInspection?.payloadPath
|
|
1902
|
+
? { sharedNativePayloadPath: sharedInspection.payloadPath }
|
|
1903
|
+
: {}),
|
|
1904
|
+
...(sharedNative.state === 'corrupt' ? { repairableSharedNative: true } : {}),
|
|
1905
|
+
activations: {
|
|
1906
|
+
user: userConfig?.snapshot.plugins[codexPluginId]?.enabled,
|
|
1907
|
+
project: projectConfig?.snapshot.plugins[codexPluginId]?.enabled,
|
|
1908
|
+
},
|
|
1909
|
+
extensions,
|
|
1910
|
+
projectionDigest: JSON.stringify(projectionEntries.sort((left, right) => `${left.scope}\0${left.artifactKey}`.localeCompare(`${right.scope}\0${right.artifactKey}`, 'en'))),
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
return [createCodexReconcilePlan({
|
|
1914
|
+
scope: currentScope,
|
|
1915
|
+
cwd: options.commandOptions.cwd,
|
|
1916
|
+
operation: options.runtime?.reconcileIntentOnly ? 'sync' : options.command,
|
|
1917
|
+
intentBefore: beforeByScope[currentScope],
|
|
1918
|
+
intentAfter: afterByScope[currentScope],
|
|
1919
|
+
relatedIntentBefore: beforeByScope[otherScope],
|
|
1920
|
+
relatedIntentAfter: afterByScope[otherScope],
|
|
1921
|
+
catalogClosure,
|
|
1922
|
+
liveEvidence,
|
|
1923
|
+
activationSupport,
|
|
1924
|
+
})];
|
|
1925
|
+
};
|
|
1926
|
+
const operationNeedsNativeCli = async (platform, plan) => {
|
|
1927
|
+
for (const { entry, platform: selectedPlatform } of executionSelections) {
|
|
1928
|
+
if (selectedPlatform !== platform)
|
|
1929
|
+
continue;
|
|
1930
|
+
const planned = plan?.targets.find((target) => target.pluginId === entry.pluginId && target.platform === selectedPlatform);
|
|
1931
|
+
if (dependencyEnabled && (!planned
|
|
1932
|
+
|| planned.action === 'keep'
|
|
1933
|
+
|| planned.action === 'block'))
|
|
1934
|
+
continue;
|
|
1935
|
+
const scope = planned?.resolvedScope ?? options.commandOptions.scope;
|
|
1936
|
+
const marketplaceName = marketplaceNameFor(entry, selectedPlatform, scope);
|
|
1937
|
+
entry.plugin.marketplaceName = marketplaceName;
|
|
1938
|
+
const marketplaceRoot = path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId);
|
|
1939
|
+
if (!dependencyEnabled && selectedPlatform === 'codex') {
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
const target = await inspection.buildTarget({
|
|
1943
|
+
sourceId: entry.source.sourceId,
|
|
1944
|
+
sourceIdentity: entry.source.sourceIdentity,
|
|
1945
|
+
pluginId: entry.pluginId,
|
|
1946
|
+
marketplaceName,
|
|
1947
|
+
marketplaceRoot,
|
|
1948
|
+
plugin: entry.plugin,
|
|
1949
|
+
platform: selectedPlatform,
|
|
1950
|
+
scope,
|
|
1951
|
+
cwd: options.commandOptions.cwd,
|
|
1952
|
+
command: dependencyEnabled
|
|
1953
|
+
? planned.action
|
|
1954
|
+
: options.command,
|
|
1955
|
+
catalog: toCatalogResolution(entry.source),
|
|
1956
|
+
includeHistoricalLifecycleArtifacts: false,
|
|
1957
|
+
readOnlyInspectionPlan: true,
|
|
1958
|
+
});
|
|
1959
|
+
if (dependencyEnabled && (target.writeNativeRequired ?? target.requiresNative))
|
|
1960
|
+
return true;
|
|
1961
|
+
const nativeComponents = target.ownedComponents.filter((component) => component.kind === 'native-plugin'
|
|
1962
|
+
|| (component.kind === 'shared-config'
|
|
1963
|
+
&& component.identity.artifactKey.startsWith('marketplace-')));
|
|
1964
|
+
if (nativeComponents.length === 0)
|
|
1965
|
+
continue;
|
|
1966
|
+
const nativeInspection = await inspectOwnedComponents({
|
|
1967
|
+
components: nativeComponents,
|
|
1968
|
+
nativeProbe: inspection.driver.probeNative,
|
|
1969
|
+
});
|
|
1970
|
+
if (nativeInspection.components.some((component) => component.state === 'present' || component.state === 'partial')) {
|
|
1971
|
+
return true;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return false;
|
|
1975
|
+
};
|
|
1308
1976
|
if (options.runtime?.previewDependencyPlanOnly) {
|
|
1309
1977
|
await options.runtime.onPreviewStage?.('dependencyPlan');
|
|
1310
|
-
const initialPlan =
|
|
1978
|
+
const initialPlan = dependencyEnabled
|
|
1979
|
+
? await measureCommandPerformanceStage(options.runtime, 'dependency.plan', () => createPlan(stateInventory))
|
|
1980
|
+
: undefined;
|
|
1981
|
+
const provisionalCodexPlans = initialPlan ? await createCodexPlans(initialPlan) : [];
|
|
1982
|
+
const previewNeedsNativeMaterialization = provisionalCodexPlans.some((plan) => plan.sharedNativeActions.some((action) => action.action === 'install'
|
|
1983
|
+
|| action.action === 'replace'
|
|
1984
|
+
|| action.action === 'repair'));
|
|
1985
|
+
const previewActivationOnlyProject = !previewNeedsNativeMaterialization
|
|
1986
|
+
&& provisionalCodexPlans.some((plan) => plan.requirement.requiresProjectPluginContract
|
|
1987
|
+
&& plan.postcheck.plugins.length > 0);
|
|
1988
|
+
const previewConsumer = previewActivationOnlyProject
|
|
1989
|
+
? await (options.runtime?.codexOperationConsumerResolver ?? resolveCodexOperationConsumer)({
|
|
1990
|
+
cwd: options.commandOptions.cwd,
|
|
1991
|
+
env: runtimeEnv,
|
|
1992
|
+
runner: options.runtime?.nativeCliRunner ?? getDefaultNativeCliRunner(),
|
|
1993
|
+
operationRequirement: getCodexOperationRequirement('project'),
|
|
1994
|
+
requiresNativeMaterialization: false,
|
|
1995
|
+
})
|
|
1996
|
+
: undefined;
|
|
1997
|
+
const initialCodexPlans = initialPlan && previewConsumer?.support === 'assumed'
|
|
1998
|
+
? await createCodexPlans(initialPlan, 'assumed')
|
|
1999
|
+
: provisionalCodexPlans;
|
|
1311
2000
|
const preview = mergeRebuildCommandResults([]);
|
|
1312
|
-
|
|
2001
|
+
if (initialPlan)
|
|
2002
|
+
preview.dependencyPlan = initialPlan;
|
|
2003
|
+
if (initialCodexPlans.length > 0)
|
|
2004
|
+
preview.codexReconcilePlans = initialCodexPlans;
|
|
2005
|
+
if (initialCodexPlans.some((plan) => plan.sharedNativeActions.some((action) => action.action === 'install'
|
|
2006
|
+
|| action.action === 'replace'
|
|
2007
|
+
|| action.action === 'repair'))) {
|
|
2008
|
+
preview.codexManagerPreview = await (options.runtime.codexManagerPreviewer ?? previewCodexManager)({
|
|
2009
|
+
cwd: options.commandOptions.cwd,
|
|
2010
|
+
env: runtimeEnv,
|
|
2011
|
+
runner: options.runtime?.nativeCliRunner,
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
1313
2014
|
return preview;
|
|
1314
2015
|
}
|
|
1315
2016
|
for (const { entry, platform } of executionSelections.filter((selection) => selectedIds.has(selection.entry.pluginId))) {
|
|
@@ -1326,6 +2027,9 @@ export async function runRebuildCommand(options) {
|
|
|
1326
2027
|
cwd: options.commandOptions.cwd,
|
|
1327
2028
|
},
|
|
1328
2029
|
configDigest: catalog.configDigest,
|
|
2030
|
+
...(catalogOperation
|
|
2031
|
+
? { generationSetDigest: catalogOperation.generationSetDigest }
|
|
2032
|
+
: {}),
|
|
1329
2033
|
sourceId: entry.source.sourceId,
|
|
1330
2034
|
sourceIdentity: entry.source.sourceIdentity,
|
|
1331
2035
|
resolvedCommit: entry.source.resolvedCommit,
|
|
@@ -1334,7 +2038,62 @@ export async function runRebuildCommand(options) {
|
|
|
1334
2038
|
contentDigest: entry.source.manifest.entries.find((candidate) => candidate.name === entry.plugin.manifest.name)?.contentDigest,
|
|
1335
2039
|
});
|
|
1336
2040
|
}
|
|
1337
|
-
const lockedPlan = await createPlan();
|
|
2041
|
+
const lockedPlan = await measureCommandPerformanceStage(options.runtime, 'dependency.plan', () => createPlan(stateInventory));
|
|
2042
|
+
const provisionalLockedCodexPlans = await createCodexPlans(lockedPlan);
|
|
2043
|
+
const codexManagerRequired = provisionalLockedCodexPlans.some((plan) => plan.sharedNativeActions.some((action) => action.action === 'install'
|
|
2044
|
+
|| action.action === 'replace'
|
|
2045
|
+
|| action.action === 'repair'));
|
|
2046
|
+
const activationOnlyProjectOperation = !codexManagerRequired
|
|
2047
|
+
&& provisionalLockedCodexPlans.some((plan) => plan.requirement.requiresProjectPluginContract
|
|
2048
|
+
&& plan.postcheck.plugins.length > 0);
|
|
2049
|
+
const activationConsumer = activationOnlyProjectOperation
|
|
2050
|
+
? await (options.runtime?.codexOperationConsumerResolver ?? resolveCodexOperationConsumer)({
|
|
2051
|
+
cwd: options.commandOptions.cwd,
|
|
2052
|
+
env: runtimeEnv,
|
|
2053
|
+
runner: executionContext.nativeCliRunner,
|
|
2054
|
+
operationRequirement: getCodexOperationRequirement('project'),
|
|
2055
|
+
requiresNativeMaterialization: false,
|
|
2056
|
+
})
|
|
2057
|
+
: undefined;
|
|
2058
|
+
const lockedCodexPlans = activationConsumer?.support === 'assumed'
|
|
2059
|
+
? await createCodexPlans(lockedPlan, 'assumed')
|
|
2060
|
+
: provisionalLockedCodexPlans;
|
|
2061
|
+
if (activationConsumer?.support === 'observed') {
|
|
2062
|
+
executionContext.codexManager = activationConsumer.manager;
|
|
2063
|
+
}
|
|
2064
|
+
if (options.runtime?.expectedOperationDependencyPlan
|
|
2065
|
+
&& JSON.stringify(lockedPlan) !== JSON.stringify(options.runtime.expectedOperationDependencyPlan)) {
|
|
2066
|
+
throw namespacedPreflightError('operationReviewStale: dependency plan changed before mutation.', preflightTargets);
|
|
2067
|
+
}
|
|
2068
|
+
if (options.runtime?.expectedCodexReconcilePlans
|
|
2069
|
+
&& JSON.stringify(lockedCodexPlans) !== JSON.stringify(options.runtime.expectedCodexReconcilePlans)) {
|
|
2070
|
+
throw namespacedPreflightError('operationReviewStale: Codex reconciliation evidence or plan changed before mutation.', preflightTargets);
|
|
2071
|
+
}
|
|
2072
|
+
if (options.runtime?.directCli
|
|
2073
|
+
&& options.commandOptions.yes !== true
|
|
2074
|
+
&& (options.command === 'install'
|
|
2075
|
+
|| options.command === 'upgrade'
|
|
2076
|
+
|| options.command === 'reinstall')) {
|
|
2077
|
+
const sharedNativeImpact = lockedCodexPlans.some((plan) => plan.review.requiresConfirmation);
|
|
2078
|
+
if (sharedNativeImpact) {
|
|
2079
|
+
throw namespacedPreflightError('sharedNativeImpactAuthorizationRequired: Replacing or force-reinstalling shared Codex native state requires --yes.', preflightTargets);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
let desiredIntent;
|
|
2083
|
+
if (options.runtime?.awHomeMutationToken
|
|
2084
|
+
&& !lockedPlan.targets.some((target) => target.action === 'block')) {
|
|
2085
|
+
const selectedRoots = selectedRootsForPlan(lockedPlan);
|
|
2086
|
+
desiredIntent = await writeDesiredIntentSuperset({
|
|
2087
|
+
command: options.command,
|
|
2088
|
+
cwd: options.commandOptions.cwd,
|
|
2089
|
+
scope: options.commandOptions.scope,
|
|
2090
|
+
selectedRoots,
|
|
2091
|
+
plan: lockedPlan,
|
|
2092
|
+
codexPlan: lockedCodexPlans[0],
|
|
2093
|
+
reconcileIntentOnly: options.runtime?.reconcileIntentOnly,
|
|
2094
|
+
env: runtimeEnv,
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
1338
2097
|
for (const pluginName of new Set(lockedPlan.targets.flatMap((target) => target.platform === 'claude'
|
|
1339
2098
|
&& (target.action === 'install'
|
|
1340
2099
|
|| target.action === 'upgrade'
|
|
@@ -1347,29 +2106,76 @@ export async function runRebuildCommand(options) {
|
|
|
1347
2106
|
env: runtimeEnv,
|
|
1348
2107
|
});
|
|
1349
2108
|
}
|
|
1350
|
-
await
|
|
1351
|
-
|
|
2109
|
+
const claudeCliRequired = await operationNeedsNativeCli('claude', lockedPlan);
|
|
2110
|
+
const codexUserActivationDesired = new Set(lockedCodexPlans.flatMap((plan) => plan.activationActions.user.flatMap((action) => action.desired ? [action.codexPluginId] : [])));
|
|
2111
|
+
executionContext.codexUserActivationDesired = codexUserActivationDesired;
|
|
2112
|
+
if (codexManagerRequired) {
|
|
2113
|
+
const codexRequirementScope = lockedCodexPlans.some((plan) => plan.requirement.requiresProjectPluginContract)
|
|
2114
|
+
? 'project'
|
|
2115
|
+
: 'user';
|
|
2116
|
+
if (options.runtime?.codexManagerResolver && codexManagerRequired) {
|
|
2117
|
+
executionContext.codexManager = await options.runtime.codexManagerResolver({
|
|
2118
|
+
cwd: options.commandOptions.cwd,
|
|
2119
|
+
env: runtimeEnv,
|
|
2120
|
+
runner: executionContext.nativeCliRunner,
|
|
2121
|
+
authorizer: options.runtime?.managedCodexAuthorizer,
|
|
2122
|
+
operationRequirement: getCodexOperationRequirement(codexRequirementScope),
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
else {
|
|
2126
|
+
const consumer = await (options.runtime?.codexOperationConsumerResolver ?? resolveCodexOperationConsumer)({
|
|
2127
|
+
cwd: options.commandOptions.cwd,
|
|
2128
|
+
env: runtimeEnv,
|
|
2129
|
+
runner: executionContext.nativeCliRunner,
|
|
2130
|
+
authorizer: options.runtime?.managedCodexAuthorizer,
|
|
2131
|
+
operationRequirement: getCodexOperationRequirement(codexRequirementScope),
|
|
2132
|
+
requiresNativeMaterialization: codexManagerRequired,
|
|
2133
|
+
});
|
|
2134
|
+
if (consumer.support !== 'observed') {
|
|
2135
|
+
throw new Error('Codex native materialization requires an observed CLI consumer.');
|
|
2136
|
+
}
|
|
2137
|
+
executionContext.codexManager = consumer.manager;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
await assertClaudeVersion({
|
|
2141
|
+
platforms: claudeCliRequired ? ['claude'] : [],
|
|
1352
2142
|
cwd: options.commandOptions.cwd,
|
|
1353
2143
|
env: runtimeEnv,
|
|
1354
|
-
runtime:
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
},
|
|
2144
|
+
runtime: executionContext,
|
|
2145
|
+
});
|
|
2146
|
+
const executionIntegration = createRebuildIntegration({
|
|
2147
|
+
context: executionContext,
|
|
2148
|
+
scriptTimeoutMs: options.commandOptions.scriptTimeoutMs,
|
|
1360
2149
|
});
|
|
1361
2150
|
const preparedTargets = new Map();
|
|
1362
2151
|
const preparedTargetErrors = new Map();
|
|
1363
2152
|
const lockedCollisionSelections = [];
|
|
1364
2153
|
for (const { entry, platform } of executionSelections) {
|
|
1365
2154
|
const planned = lockedPlan.targets.find((candidate) => candidate.pluginId === entry.pluginId && candidate.platform === platform);
|
|
2155
|
+
const desiredCleanup = platform === 'codex'
|
|
2156
|
+
&& options.command === 'cleanup'
|
|
2157
|
+
&& lockedCodexPlans.some((plan) => plan.desiredTargets.some((target) => target.pluginId === entry.pluginId && target.scopes.includes(planned.resolvedScope)));
|
|
2158
|
+
const reconcileObsolete = platform === 'codex'
|
|
2159
|
+
&& options.runtime?.reconcileIntentOnly === true
|
|
2160
|
+
&& lockedCodexPlans.some((plan) => plan.desiredTargets.some((target) => target.pluginId === entry.pluginId && !target.scopes.includes(planned.resolvedScope)));
|
|
2161
|
+
if (reconcileObsolete)
|
|
2162
|
+
continue;
|
|
1366
2163
|
if (planned.action !== 'install'
|
|
1367
2164
|
&& planned.action !== 'upgrade'
|
|
1368
|
-
&& planned.action !== 'reinstall'
|
|
2165
|
+
&& planned.action !== 'reinstall'
|
|
2166
|
+
&& planned.action !== 'move'
|
|
2167
|
+
&& !desiredCleanup)
|
|
1369
2168
|
continue;
|
|
2169
|
+
const buildCommand = desiredCleanup
|
|
2170
|
+
? 'install'
|
|
2171
|
+
: planned.action === 'move'
|
|
2172
|
+
? 'install'
|
|
2173
|
+
: planned.relation === 'dependency'
|
|
2174
|
+
? planned.action
|
|
2175
|
+
: options.command;
|
|
1370
2176
|
const marketplaceName = marketplaceNameFor(entry, platform, planned.resolvedScope);
|
|
1371
2177
|
try {
|
|
1372
|
-
const target = await
|
|
2178
|
+
const target = await measureCommandPerformanceStage(options.runtime, 'target.build', () => executionIntegration.buildTarget({
|
|
1373
2179
|
sourceId: entry.source.sourceId,
|
|
1374
2180
|
sourceIdentity: entry.source.sourceIdentity,
|
|
1375
2181
|
pluginId: entry.pluginId,
|
|
@@ -1379,21 +2185,27 @@ export async function runRebuildCommand(options) {
|
|
|
1379
2185
|
platform,
|
|
1380
2186
|
scope: planned.resolvedScope,
|
|
1381
2187
|
cwd: options.commandOptions.cwd,
|
|
1382
|
-
command:
|
|
2188
|
+
command: buildCommand,
|
|
1383
2189
|
catalog: toCatalogResolution(entry.source),
|
|
1384
2190
|
includeHistoricalLifecycleArtifacts: true,
|
|
1385
|
-
});
|
|
2191
|
+
}));
|
|
2192
|
+
if (platform === 'codex') {
|
|
2193
|
+
const plannedNative = lockedCodexPlans.flatMap((plan) => plan.sharedNativeActions).find((action) => action.pluginId === entry.pluginId);
|
|
2194
|
+
if (plannedNative) {
|
|
2195
|
+
target.writeNativeRequired = plannedNative.action === 'install'
|
|
2196
|
+
|| plannedNative.action === 'replace'
|
|
2197
|
+
|| plannedNative.action === 'repair';
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
1386
2200
|
preparedTargets.set(`${entry.pluginId}\0${platform}`, {
|
|
1387
2201
|
target,
|
|
1388
|
-
driver:
|
|
2202
|
+
driver: executionIntegration.driver,
|
|
1389
2203
|
context: executionContext,
|
|
1390
2204
|
});
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
});
|
|
1396
|
-
}
|
|
2205
|
+
await rebuildCommandTestHooks?.afterTargetBuilt?.({
|
|
2206
|
+
command: options.command,
|
|
2207
|
+
identity: target.identity,
|
|
2208
|
+
});
|
|
1397
2209
|
lockedCollisionSelections.push({
|
|
1398
2210
|
pluginId: entry.pluginId,
|
|
1399
2211
|
targetKey: `${platform}/${target.identity.scope}`,
|
|
@@ -1416,8 +2228,10 @@ export async function runRebuildCommand(options) {
|
|
|
1416
2228
|
throw namespacedPreflightError(`artifactCollision: ${lockedCollisions.map((collision) => `${collision.targetKey} (${collision.pluginIds.join(', ')})`).join('; ')}`, preflightTargets);
|
|
1417
2229
|
}
|
|
1418
2230
|
const removalRequiredConsumers = new Map();
|
|
1419
|
-
if ((options.command === 'cleanup' && !cleanupForce)
|
|
1420
|
-
|
|
2231
|
+
if ((options.command === 'cleanup' && !cleanupForce)
|
|
2232
|
+
|| options.command === 'uninstall'
|
|
2233
|
+
|| options.runtime?.reconcileIntentOnly === true) {
|
|
2234
|
+
const removalStateInventory = await readInventory({
|
|
1421
2235
|
cwd: options.commandOptions.cwd,
|
|
1422
2236
|
env: runtimeEnv,
|
|
1423
2237
|
includeHistoricalProjects: true,
|
|
@@ -1560,6 +2374,32 @@ export async function runRebuildCommand(options) {
|
|
|
1560
2374
|
scope: planned.resolvedScope,
|
|
1561
2375
|
cwd: options.commandOptions.cwd,
|
|
1562
2376
|
};
|
|
2377
|
+
const codexReconcilePlan = platform === 'codex'
|
|
2378
|
+
? lockedCodexPlans.find((plan) => plan.desiredTargets.some((target) => target.pluginId === entry.pluginId))
|
|
2379
|
+
: undefined;
|
|
2380
|
+
const desiredInCurrentScope = codexReconcilePlan?.desiredTargets.some((target) => target.pluginId === entry.pluginId && target.scopes.includes(planned.resolvedScope)) === true;
|
|
2381
|
+
const reconcileObsolete = platform === 'codex'
|
|
2382
|
+
&& options.runtime?.reconcileIntentOnly === true
|
|
2383
|
+
&& !desiredInCurrentScope;
|
|
2384
|
+
const desiredCleanupMutation = codexReconcilePlan !== undefined && (codexReconcilePlan.sharedNativeActions.some((action) => action.pluginId === entry.pluginId
|
|
2385
|
+
&& (action.action === 'install'
|
|
2386
|
+
|| action.action === 'replace'
|
|
2387
|
+
|| action.action === 'repair'))
|
|
2388
|
+
|| [...codexReconcilePlan.activationActions.user,
|
|
2389
|
+
...codexReconcilePlan.activationActions.project].some((action) => action.pluginId === entry.pluginId && action.action !== 'none')
|
|
2390
|
+
|| [...codexReconcilePlan.extensionWrites,
|
|
2391
|
+
...codexReconcilePlan.extensionRemovals].some((action) => action.pluginId === entry.pluginId));
|
|
2392
|
+
const plannedNativeAction = codexReconcilePlan?.sharedNativeActions.find((action) => action.pluginId === entry.pluginId);
|
|
2393
|
+
const hasCodexExtensionMutation = codexReconcilePlan !== undefined
|
|
2394
|
+
&& [...codexReconcilePlan.extensionWrites, ...codexReconcilePlan.extensionRemovals]
|
|
2395
|
+
.some((action) => action.pluginId === entry.pluginId);
|
|
2396
|
+
const reconcileActivationOnly = platform === 'codex'
|
|
2397
|
+
&& plannedNativeAction !== undefined
|
|
2398
|
+
&& (plannedNativeAction.action === 'reuse'
|
|
2399
|
+
|| plannedNativeAction.action === 'claim'
|
|
2400
|
+
|| plannedNativeAction.action === 'none')
|
|
2401
|
+
&& !hasCodexExtensionMutation
|
|
2402
|
+
&& entry.plugin.manifest.scripts?.lifecycle?.uninstall === undefined;
|
|
1563
2403
|
if (failedDependency || failedConsumer || planned.action === 'block') {
|
|
1564
2404
|
const code = failedConsumer
|
|
1565
2405
|
? 'dependencyStillRequired'
|
|
@@ -1583,7 +2423,7 @@ export async function runRebuildCommand(options) {
|
|
|
1583
2423
|
errorCode: code,
|
|
1584
2424
|
message,
|
|
1585
2425
|
}],
|
|
1586
|
-
overallState: 'failed',
|
|
2426
|
+
overallState: 'failed',
|
|
1587
2427
|
receiptTargets: [{
|
|
1588
2428
|
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
1589
2429
|
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
@@ -1592,7 +2432,68 @@ export async function runRebuildCommand(options) {
|
|
|
1592
2432
|
dependencyStates.set(`${entry.pluginId}\0${platform}`, failedDependency || failedConsumer ? 'skipped' : 'failed');
|
|
1593
2433
|
continue;
|
|
1594
2434
|
}
|
|
1595
|
-
if (
|
|
2435
|
+
if (reconcileActivationOnly) {
|
|
2436
|
+
const preparedError = preparedTargetErrors.get(`${entry.pluginId}\0${platform}`);
|
|
2437
|
+
if (preparedError) {
|
|
2438
|
+
const message = preparedError instanceof Error
|
|
2439
|
+
? preparedError.message
|
|
2440
|
+
: String(preparedError);
|
|
2441
|
+
const result = failedResult(options.command, identity, message);
|
|
2442
|
+
results.push({
|
|
2443
|
+
platforms: [platform], plugins: [], warnings: [], rebuildResults: [result],
|
|
2444
|
+
targetResults: [{
|
|
2445
|
+
target: identity,
|
|
2446
|
+
action: planned.action,
|
|
2447
|
+
state: 'failed',
|
|
2448
|
+
errorCode: message.split(':', 1)[0] ?? 'targetPreparationFailed',
|
|
2449
|
+
message,
|
|
2450
|
+
}],
|
|
2451
|
+
overallState: 'failed',
|
|
2452
|
+
receiptTargets: [{
|
|
2453
|
+
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
2454
|
+
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
2455
|
+
}],
|
|
2456
|
+
});
|
|
2457
|
+
dependencyStates.set(`${entry.pluginId}\0${platform}`, 'failed');
|
|
2458
|
+
continue;
|
|
2459
|
+
}
|
|
2460
|
+
const result = {
|
|
2461
|
+
status: 'succeeded', command: options.command, target: identity, actions: [],
|
|
2462
|
+
cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
2463
|
+
};
|
|
2464
|
+
results.push({
|
|
2465
|
+
platforms: [platform], plugins: [identity.pluginName], warnings: [], rebuildResults: [result],
|
|
2466
|
+
targetResults: [{ target: identity, action: planned.action, state: 'completed' }],
|
|
2467
|
+
overallState: 'succeeded',
|
|
2468
|
+
receiptTargets: [{
|
|
2469
|
+
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
2470
|
+
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
2471
|
+
}],
|
|
2472
|
+
});
|
|
2473
|
+
dependencyStates.set(`${entry.pluginId}\0${platform}`, 'completed');
|
|
2474
|
+
continue;
|
|
2475
|
+
}
|
|
2476
|
+
if (platform === 'codex'
|
|
2477
|
+
&& desiredInCurrentScope
|
|
2478
|
+
&& (options.command === 'uninstall'
|
|
2479
|
+
|| (options.command === 'cleanup' && !desiredCleanupMutation))) {
|
|
2480
|
+
const result = {
|
|
2481
|
+
status: 'succeeded', command: options.command, target: identity, actions: [],
|
|
2482
|
+
cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
2483
|
+
};
|
|
2484
|
+
results.push({
|
|
2485
|
+
platforms: [platform], plugins: [identity.pluginName], warnings: [], rebuildResults: [result],
|
|
2486
|
+
targetResults: [{ target: identity, action: 'keep', state: 'completed' }],
|
|
2487
|
+
overallState: 'succeeded',
|
|
2488
|
+
receiptTargets: [{
|
|
2489
|
+
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
2490
|
+
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
2491
|
+
}],
|
|
2492
|
+
});
|
|
2493
|
+
dependencyStates.set(`${entry.pluginId}\0${platform}`, 'kept');
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
if (planned.action === 'keep' && !reconcileObsolete) {
|
|
1596
2497
|
const result = {
|
|
1597
2498
|
status: 'succeeded', command: options.command, target: identity, actions: [],
|
|
1598
2499
|
cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
@@ -1600,7 +2501,7 @@ export async function runRebuildCommand(options) {
|
|
|
1600
2501
|
results.push({
|
|
1601
2502
|
platforms: [platform], plugins: [identity.pluginName], warnings: [], rebuildResults: [result],
|
|
1602
2503
|
targetResults: [{ target: identity, action: 'keep', state: 'completed' }],
|
|
1603
|
-
overallState: 'succeeded',
|
|
2504
|
+
overallState: 'succeeded',
|
|
1604
2505
|
receiptTargets: [{
|
|
1605
2506
|
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
1606
2507
|
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
@@ -1617,20 +2518,34 @@ export async function runRebuildCommand(options) {
|
|
|
1617
2518
|
marketplaceRoot: path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId),
|
|
1618
2519
|
};
|
|
1619
2520
|
entry.plugin.marketplaceName = marketplaceName;
|
|
2521
|
+
const reconcileDesiredCleanup = platform === 'codex'
|
|
2522
|
+
&& options.command === 'cleanup'
|
|
2523
|
+
&& desiredInCurrentScope;
|
|
1620
2524
|
const executionResult = await runSingleSourceRebuildCommand({
|
|
1621
2525
|
...options,
|
|
1622
|
-
command:
|
|
1623
|
-
?
|
|
1624
|
-
:
|
|
2526
|
+
command: reconcileObsolete
|
|
2527
|
+
? 'cleanup'
|
|
2528
|
+
: reconcileDesiredCleanup
|
|
2529
|
+
? 'install'
|
|
2530
|
+
: planned.action === 'move'
|
|
2531
|
+
? 'install'
|
|
2532
|
+
: planned.relation === 'dependency'
|
|
2533
|
+
? planned.action
|
|
2534
|
+
: options.command,
|
|
1625
2535
|
pluginNames: [entry.plugin.manifest.name],
|
|
1626
2536
|
all: false,
|
|
1627
2537
|
commandOptions: { ...options.commandOptions, platform, scope: planned.resolvedScope },
|
|
1628
2538
|
runtime: {
|
|
1629
2539
|
...options.runtime,
|
|
1630
2540
|
env: runtimeEnv,
|
|
2541
|
+
...(executionContext.codexManager
|
|
2542
|
+
? { codexManager: executionContext.codexManager }
|
|
2543
|
+
: {}),
|
|
1631
2544
|
catalogResolution: toCatalogResolution(entry.source),
|
|
2545
|
+
resolvedCatalogPlugins: available
|
|
2546
|
+
.filter((candidate) => candidate.source.sourceId === entry.source.sourceId)
|
|
2547
|
+
.map((candidate) => candidate.plugin),
|
|
1632
2548
|
namespacedSource,
|
|
1633
|
-
operationLeaseHeld: true,
|
|
1634
2549
|
dependencyReviewPreflightHandled: true,
|
|
1635
2550
|
targetBuiltHookHandled: true,
|
|
1636
2551
|
preparedTarget: preparedTargets.get(`${entry.pluginId}\0${platform}`),
|
|
@@ -1639,6 +2554,9 @@ export async function runRebuildCommand(options) {
|
|
|
1639
2554
|
resolvedReviewEvidenceByPlugin: {
|
|
1640
2555
|
[entry.plugin.manifest.name]: {
|
|
1641
2556
|
configDigest: catalog.configDigest,
|
|
2557
|
+
...(catalogOperation
|
|
2558
|
+
? { generationSetDigest: catalogOperation.generationSetDigest }
|
|
2559
|
+
: {}),
|
|
1642
2560
|
sourceId: entry.source.sourceId,
|
|
1643
2561
|
sourceIdentity: entry.source.sourceIdentity,
|
|
1644
2562
|
resolvedCommit: entry.source.resolvedCommit,
|
|
@@ -1649,15 +2567,119 @@ export async function runRebuildCommand(options) {
|
|
|
1649
2567
|
},
|
|
1650
2568
|
},
|
|
1651
2569
|
});
|
|
2570
|
+
if (reconcileDesiredCleanup) {
|
|
2571
|
+
for (const result of executionResult.rebuildResults)
|
|
2572
|
+
result.command = 'cleanup';
|
|
2573
|
+
for (const result of executionResult.targetResults)
|
|
2574
|
+
result.action = 'cleanup';
|
|
2575
|
+
}
|
|
1652
2576
|
results.push(executionResult);
|
|
1653
2577
|
dependencyStates.set(`${entry.pluginId}\0${platform}`, executionResult.overallState === 'succeeded' ? 'completed' : 'failed');
|
|
1654
2578
|
}
|
|
2579
|
+
if (lockedCodexPlans.length > 0
|
|
2580
|
+
&& mergeRebuildCommandResults(results).overallState === 'succeeded') {
|
|
2581
|
+
try {
|
|
2582
|
+
await executeCodexReconcileActivations({
|
|
2583
|
+
plans: lockedCodexPlans,
|
|
2584
|
+
cwd: options.commandOptions.cwd,
|
|
2585
|
+
env: runtimeEnv,
|
|
2586
|
+
manager: executionContext.codexManager,
|
|
2587
|
+
runner: executionContext.nativeCliRunner,
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
catch (error) {
|
|
2591
|
+
const selection = executionSelections.find((candidate) => candidate.platform === 'codex');
|
|
2592
|
+
if (!selection)
|
|
2593
|
+
throw error;
|
|
2594
|
+
const planned = lockedPlan.targets.find((target) => target.pluginId === selection.entry.pluginId && target.platform === 'codex');
|
|
2595
|
+
const identity = {
|
|
2596
|
+
sourceId: selection.entry.source.sourceId,
|
|
2597
|
+
sourceIdentity: selection.entry.source.sourceIdentity,
|
|
2598
|
+
pluginId: selection.entry.pluginId,
|
|
2599
|
+
pluginName: selection.entry.plugin.manifest.name,
|
|
2600
|
+
pluginVersion: selection.entry.plugin.manifest.version,
|
|
2601
|
+
platform: 'codex',
|
|
2602
|
+
scope: planned.resolvedScope,
|
|
2603
|
+
cwd: options.commandOptions.cwd,
|
|
2604
|
+
};
|
|
2605
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2606
|
+
const failed = failedResult(options.command, identity, message, 'postcheck.inspect');
|
|
2607
|
+
results.push({
|
|
2608
|
+
platforms: ['codex'],
|
|
2609
|
+
plugins: [],
|
|
2610
|
+
warnings: [],
|
|
2611
|
+
rebuildResults: [failed],
|
|
2612
|
+
targetResults: [{
|
|
2613
|
+
target: identity,
|
|
2614
|
+
action: options.command,
|
|
2615
|
+
state: 'failed',
|
|
2616
|
+
errorCode: message.split(':', 1)[0] ?? 'codexActivationPostcheckFailed',
|
|
2617
|
+
message,
|
|
2618
|
+
}],
|
|
2619
|
+
overallState: 'failed',
|
|
2620
|
+
receiptTargets: [{
|
|
2621
|
+
pluginName: identity.pluginName,
|
|
2622
|
+
pluginId: identity.pluginId,
|
|
2623
|
+
sourceId: identity.sourceId,
|
|
2624
|
+
platform: 'codex',
|
|
2625
|
+
scope: identity.scope,
|
|
2626
|
+
}],
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
if (options.command === 'install'
|
|
2631
|
+
&& mergeRebuildCommandResults(results).overallState === 'succeeded') {
|
|
2632
|
+
for (const { entry, platform } of executionSelections) {
|
|
2633
|
+
const planned = lockedPlan.targets.find((target) => target.pluginId === entry.pluginId && target.platform === platform);
|
|
2634
|
+
if (planned.action !== 'move'
|
|
2635
|
+
|| dependencyStates.get(`${entry.pluginId}\0${platform}`) !== 'completed')
|
|
2636
|
+
continue;
|
|
2637
|
+
const previousScope = planned.resolvedScope === 'user' ? 'project' : 'user';
|
|
2638
|
+
const marketplaceName = marketplaceNameFor(entry, platform, previousScope);
|
|
2639
|
+
entry.plugin.marketplaceName = marketplaceName;
|
|
2640
|
+
const migration = await runSingleSourceRebuildCommand({
|
|
2641
|
+
command: 'cleanup',
|
|
2642
|
+
pluginNames: [entry.plugin.manifest.name],
|
|
2643
|
+
commandOptions: { ...options.commandOptions, platform, scope: previousScope },
|
|
2644
|
+
runtime: {
|
|
2645
|
+
...options.runtime,
|
|
2646
|
+
env: runtimeEnv,
|
|
2647
|
+
...(executionContext.codexManager
|
|
2648
|
+
? { codexManager: executionContext.codexManager }
|
|
2649
|
+
: {}),
|
|
2650
|
+
catalogResolution: toCatalogResolution(entry.source),
|
|
2651
|
+
resolvedCatalogPlugins: available
|
|
2652
|
+
.filter((candidate) => candidate.source.sourceId === entry.source.sourceId)
|
|
2653
|
+
.map((candidate) => candidate.plugin),
|
|
2654
|
+
namespacedSource: {
|
|
2655
|
+
sourceId: entry.source.sourceId,
|
|
2656
|
+
sourceIdentity: entry.source.sourceIdentity,
|
|
2657
|
+
marketplaceName,
|
|
2658
|
+
marketplaceRoot: path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId),
|
|
2659
|
+
},
|
|
2660
|
+
dependencyReviewPreflightHandled: true,
|
|
2661
|
+
bypassDependencyPlan: true,
|
|
2662
|
+
},
|
|
2663
|
+
});
|
|
2664
|
+
results.push(migration);
|
|
2665
|
+
if (migration.overallState !== 'succeeded') {
|
|
2666
|
+
dependencyStates.set(`${entry.pluginId}\0${platform}`, 'failed');
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
1655
2670
|
const merged = mergeRebuildCommandResults(results);
|
|
1656
2671
|
merged.dependencyPlan = lockedPlan;
|
|
2672
|
+
if (lockedCodexPlans.length > 0)
|
|
2673
|
+
merged.codexReconcilePlans = lockedCodexPlans;
|
|
2674
|
+
if (desiredIntent && merged.overallState === 'succeeded') {
|
|
2675
|
+
for (const intent of desiredIntent) {
|
|
2676
|
+
await writePluginIntentState(intent.location, convergePluginIntentManagedCodexOwnership(intent.superset, intent.convergedCodexPluginIds));
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
1657
2679
|
return leaseSafeRebuildResult(merged);
|
|
1658
2680
|
},
|
|
1659
2681
|
});
|
|
1660
|
-
if (cleanupForce) {
|
|
2682
|
+
if (cleanupForce && !options.runtime?.previewDependencyPlanOnly) {
|
|
1661
2683
|
try {
|
|
1662
2684
|
await (options.runtime?.removeObsoleteInstallationContracts ?? fs.remove)(path.join(resolveAwHome(runtimeEnv), 'installation-contracts'));
|
|
1663
2685
|
}
|
|
@@ -1672,37 +2694,16 @@ export async function runRebuildCommand(options) {
|
|
|
1672
2694
|
const projected = error;
|
|
1673
2695
|
error = namespacedPreflightError(error instanceof Error ? error.message : String(error), projected.namespacedTargets ?? liveTargets, projected.legacyTargets ?? legacyLiveTargets);
|
|
1674
2696
|
}
|
|
1675
|
-
if (options.command !== '
|
|
2697
|
+
if (options.command !== 'uninstall')
|
|
1676
2698
|
throw error;
|
|
1677
2699
|
const message = error instanceof Error ? error.message : String(error);
|
|
1678
|
-
const catalogUnavailable =
|
|
1679
|
-
|| message.
|
|
1680
|
-
||
|
|
1681
|
-
if (options.command === 'cleanup'
|
|
1682
|
-
&& (catalogUnavailable || message.includes('sourceChanged'))
|
|
1683
|
-
&& cleanupInventory
|
|
1684
|
-
&& cleanupLiveTargets.length > 0) {
|
|
1685
|
-
if (!cleanupForce) {
|
|
1686
|
-
await assertOfflineCleanupDependents({
|
|
1687
|
-
targets: cleanupLiveTargets,
|
|
1688
|
-
cwd: options.commandOptions.cwd,
|
|
1689
|
-
env: runtimeEnv,
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
return cleanupOfflineOwnedComponents({
|
|
1693
|
-
targets: cleanupLiveTargets,
|
|
1694
|
-
cwd: options.commandOptions.cwd,
|
|
1695
|
-
env: runtimeEnv,
|
|
1696
|
-
force: cleanupForce,
|
|
1697
|
-
removeObsoleteInstallationContracts: options.runtime?.removeObsoleteInstallationContracts,
|
|
1698
|
-
nativeCliRunner: options.runtime?.nativeCliRunner,
|
|
1699
|
-
corruptExclusiveDirectoryOperations: options.runtime?.corruptExclusiveDirectoryOperations,
|
|
1700
|
-
});
|
|
1701
|
-
}
|
|
2700
|
+
const catalogUnavailable = isOfflineCleanupCatalogGenerationError(error)
|
|
2701
|
+
|| message.startsWith('Cannot resolve required catalog sources:')
|
|
2702
|
+
|| message.includes('does not exist in the required catalog source set');
|
|
1702
2703
|
if (options.command === 'uninstall' && catalogUnavailable) {
|
|
1703
2704
|
throw namespacedPreflightError(`catalogSourceUnavailable: ${message} Restore the source to run lifecycle uninstall, or use cleanup; use cleanup --force only for exclusively owned damaged output.`, liveTargets, legacyLiveTargets);
|
|
1704
2705
|
}
|
|
1705
|
-
if ((
|
|
2706
|
+
if (catalogGenerationErrorCode(error) === 'catalogGenerationSourceMissing'
|
|
1706
2707
|
|| message.includes('does not exist in the required catalog source set')) {
|
|
1707
2708
|
throw namespacedPreflightError(`sourceMissing: ${message} Run cleanup for owner recovery, or cleanup --force for an exclusively owned damaged target.`, liveTargets, legacyLiveTargets);
|
|
1708
2709
|
}
|