@lesliechan721/aw 0.1.0-beta.8 → 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 +4 -4
- 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/remove-plugin.mjs +1 -1
- package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +34 -778
- 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 +5 -6
- package/dist/scripts/plugin-staging.js +12 -13
- package/dist/scripts/plugin-staging.js.map +1 -1
- package/dist/src/authoring/workspace-commands.d.ts +2 -1
- package/dist/src/authoring/workspace-commands.js.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +2 -2
- package/dist/src/commands/aw-capabilities.js +6 -11
- package/dist/src/commands/aw-capabilities.js.map +1 -1
- package/dist/src/commands/catalog-dev-source.d.ts +18 -12
- package/dist/src/commands/catalog-dev-source.js +241 -305
- package/dist/src/commands/catalog-dev-source.js.map +1 -1
- package/dist/src/commands/catalog-generation.d.ts +6 -19
- package/dist/src/commands/catalog-generation.js +10 -11
- package/dist/src/commands/catalog-generation.js.map +1 -1
- package/dist/src/commands/catalog-publication-inspection.d.ts +28 -27
- package/dist/src/commands/catalog-publication-inspection.js +139 -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 +2 -1
- package/dist/src/commands/catalog-publication-target.js +37 -2
- package/dist/src/commands/catalog-publication-target.js.map +1 -1
- package/dist/src/commands/catalog-publish.d.ts +51 -15
- package/dist/src/commands/catalog-publish.js +576 -219
- package/dist/src/commands/catalog-publish.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +3 -28
- package/dist/src/commands/catalog-source.js +29 -140
- package/dist/src/commands/catalog-source.js.map +1 -1
- package/dist/src/commands/catalog-status.d.ts +6 -26
- package/dist/src/commands/catalog-status.js +8 -146
- 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 +20 -0
- package/dist/src/commands/offline-cleanup-evidence.js +87 -9
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -1
- package/dist/src/commands/options.d.ts +6 -1
- package/dist/src/commands/options.js +64 -6
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +4 -0
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +10 -8
- package/dist/src/commands/rebuild-command.js +1217 -426
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +54 -6
- package/dist/src/commands/rebuild-integration.js +691 -364
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +2 -0
- package/dist/src/commands/rebuild-operations.js +31 -17
- package/dist/src/commands/rebuild-operations.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-v5.d.ts → status-v6.d.ts} +59 -26
- package/dist/src/commands/{status-v5.js → status-v6.js} +882 -79
- 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/write-commands.js +1 -43
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/constants.d.ts +5 -4
- package/dist/src/constants.js +5 -4
- 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 +123 -55
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +412 -152
- 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 -11
- package/dist/src/portable/commands.d.ts +2 -2
- package/dist/src/portable/commands.js +2 -8
- package/dist/src/portable/commands.js.map +1 -1
- package/dist/src/portable/materializer.d.ts +1 -4
- package/dist/src/portable/materializer.js +0 -2
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/tui/catalog-generation.d.ts +20 -41
- package/dist/src/tui/catalog-generation.js +65 -224
- package/dist/src/tui/catalog-generation.js.map +1 -1
- package/dist/src/tui/components.js +1 -2
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/console-app-v4.js +461 -330
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.d.ts +3 -5
- package/dist/src/tui/controller-runtime.js +182 -187
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +42 -45
- package/dist/src/tui/controller.js +454 -407
- 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 -1
- package/dist/src/tui/index.js +1 -1
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/model.d.ts +81 -13
- package/dist/src/tui/model.js +378 -95
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/router.d.ts +9 -0
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/types.d.ts +54 -47
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/agent-version.d.ts +4 -1
- package/dist/src/utils/agent-version.js +28 -3
- package/dist/src/utils/agent-version.js.map +1 -1
- package/dist/src/utils/catalog-digests.d.ts +7 -0
- package/dist/src/utils/catalog-digests.js +27 -0
- 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 +2 -1
- package/dist/src/utils/catalog-generation-error.js +12 -0
- package/dist/src/utils/catalog-generation-error.js.map +1 -1
- package/dist/src/utils/catalog-generation-resolver.d.ts +10 -3
- package/dist/src/utils/catalog-generation-resolver.js +90 -76
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
- package/dist/src/utils/catalog-generation-service.d.ts +24 -33
- package/dist/src/utils/catalog-generation-service.js +253 -567
- package/dist/src/utils/catalog-generation-service.js.map +1 -1
- package/dist/src/utils/catalog-generation-state.d.ts +4 -0
- package/dist/src/utils/catalog-generation-state.js +73 -106
- package/dist/src/utils/catalog-generation-state.js.map +1 -1
- package/dist/src/utils/catalog-generation-store.d.ts +16 -26
- package/dist/src/utils/catalog-generation-store.js +154 -290
- package/dist/src/utils/catalog-generation-store.js.map +1 -1
- package/dist/src/utils/catalog-manifest-v6.d.ts +5 -0
- package/dist/src/utils/{catalog-manifest-v5.js → catalog-manifest-v6.js} +23 -35
- package/dist/src/utils/catalog-manifest-v6.js.map +1 -0
- package/dist/src/utils/catalog-operation-context.d.ts +6 -14
- package/dist/src/utils/catalog-operation-context.js +68 -169
- package/dist/src/utils/catalog-operation-context.js.map +1 -1
- package/dist/src/utils/catalog-public-error.js +1 -4
- 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 +2 -2
- 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.js +25 -9
- 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 +22 -1
- package/dist/src/utils/codex-config.js.map +1 -1
- package/dist/src/utils/codex-manager.d.ts +50 -2
- package/dist/src/utils/codex-manager.js +160 -6
- package/dist/src/utils/codex-manager.js.map +1 -1
- 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-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/git-catalog-provider.js +56 -115
- package/dist/src/utils/git-catalog-provider.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 +1 -10
- package/dist/src/utils/multi-source-catalog.js +8 -175
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +34 -0
- package/dist/src/utils/native-cli.js +91 -0
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/orphan-marketplace-cleanup.js +1 -0
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
- package/dist/src/utils/ownership.d.ts +0 -10
- package/dist/src/utils/ownership.js +3 -88
- 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 +45 -62
- 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 +0 -5
- package/dist/src/utils/plugin-config-write.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/target-eligibility.d.ts +3 -2
- package/dist/src/utils/target-eligibility.js +4 -3
- package/dist/src/utils/target-eligibility.js.map +1 -1
- package/package.json +5 -4
- 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 -91
- package/dist/scripts/codex-eval-app-server.js +0 -1334
- 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 -1589
- 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 -189
- package/dist/scripts/plugin-eval-contract.js +0 -745
- 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/catalog-context.d.ts +0 -52
- package/dist/src/commands/catalog-context.js +0 -156
- package/dist/src/commands/catalog-context.js.map +0 -1
- package/dist/src/commands/status-v5.js.map +0 -1
- package/dist/src/utils/catalog-manifest-v5.d.ts +0 -5
- package/dist/src/utils/catalog-manifest-v5.js.map +0 -1
- package/dist/src/utils/catalog-source-cache.d.ts +0 -62
- package/dist/src/utils/catalog-source-cache.js +0 -321
- 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,31 +1,62 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
|
-
import { probeAgentVersion } from '../utils/agent-version.js';
|
|
4
|
-
import { previewCodexManager,
|
|
3
|
+
import { getCodexOperationRequirement, probeAgentVersion } from '../utils/agent-version.js';
|
|
4
|
+
import { previewCodexManager, resolveCodexOperationConsumer, } from '../utils/codex-manager.js';
|
|
5
5
|
import { createNoopDebugLogger } from '../output/debug-log.js';
|
|
6
6
|
import { createNoopReporter } from '../output/reporter.js';
|
|
7
7
|
import { getDefaultNativeCliRunner } from '../utils/native-cli.js';
|
|
8
8
|
import { readPluginManifest } from '../utils/manifest.js';
|
|
9
|
-
import { resolveAwHome } from '../utils/paths.js';
|
|
9
|
+
import { resolveAwHome, resolveCodexPaths } from '../utils/paths.js';
|
|
10
10
|
import { resolveCliPackageRoot } from '../utils/paths.js';
|
|
11
11
|
import { supportsPlatform } from '../utils/platform-support.js';
|
|
12
|
-
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';
|
|
13
15
|
import { createRebuildActiveStore, executeRebuildOperation, } from './rebuild-operations.js';
|
|
14
|
-
import { assertNoClaudeUnboundNativeNameCollision,
|
|
15
|
-
import { getNamespacedMarketplaceName } from '../utils/local-marketplace.js';
|
|
16
|
+
import { assertNoClaudeUnboundNativeNameCollision, createRebuildIntegration, discoverRebuildTargetNames, executeCodexReconcileActivations, inspectCodexSharedNativeLive, inspectNativeMarketplaceRegistrations, } from './rebuild-integration.js';
|
|
17
|
+
import { getNamespacedMarketplaceName, readStrictNamespacedMarketplaceRoot, } from '../utils/local-marketplace.js';
|
|
16
18
|
import { formatPluginId, parsePluginId, planPluginSelectorSourceIds, preflightDesiredArtifactCollisions, withResolvedMultiSourceCatalog, } from '../utils/multi-source-catalog.js';
|
|
19
|
+
import { calculateCodexSharedNativePayloadDigest } from '../utils/catalog-digests.js';
|
|
17
20
|
import { resolveCatalogOperationContext, } from '../utils/catalog-operation-context.js';
|
|
18
21
|
import { assertStrictSemVer } from '../utils/manifest.js';
|
|
19
22
|
import { assertCatalogSourceInventoryComplete, canonicalMarketplaceRegistrationNames, inventoryCatalogSourceReferences, } from '../utils/catalog-source-references.js';
|
|
20
23
|
import { resolveEffectivePluginConfig } from '../utils/plugin-config.js';
|
|
21
|
-
import {
|
|
22
|
-
import { codexProjectConfigAliasesUserHome,
|
|
24
|
+
import { inspectOwnedComponents, } from '../utils/ownership.js';
|
|
25
|
+
import { codexProjectConfigAliasesUserHome, resolveCanonicalRepoProjectKey, } from '../utils/state-paths.js';
|
|
23
26
|
import { resolvePluginMetaDependencyClosure } from '../utils/plugin-dependencies.js';
|
|
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';
|
|
24
31
|
import { validateCatalogSnapshotPluginEntriesComplete } from '../utils/catalog-snapshot.js';
|
|
25
32
|
import { AwCapabilityUnsupportedError, IMPLEMENTED_AW_CAPABILITIES, } from './aw-capabilities.js';
|
|
26
33
|
import { checkAwCapabilitySupport } from '../utils/manifest.js';
|
|
27
|
-
import { createDependencyOperationPlan, } from './dependency-operation-plan.js';
|
|
34
|
+
import { createDependencyOperationPlan, createDependencyPlacementPlan, } from './dependency-operation-plan.js';
|
|
28
35
|
import { offlineCleanupEvidenceFromInventory, offlineCleanupEvidenceMatches, } from './offline-cleanup-evidence.js';
|
|
36
|
+
async function measureCommandPerformanceStage(runtime, name, operation) {
|
|
37
|
+
const startedAt = Date.now();
|
|
38
|
+
let phase = 'success';
|
|
39
|
+
try {
|
|
40
|
+
return await operation();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
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.',
|
|
52
|
+
data: {
|
|
53
|
+
name,
|
|
54
|
+
phase,
|
|
55
|
+
durationMs: Math.max(0, Date.now() - startedAt),
|
|
56
|
+
},
|
|
57
|
+
})).catch(() => undefined);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
29
60
|
let rebuildCommandTestHooks;
|
|
30
61
|
async function emitRebuildActionEvent(runtime, event) {
|
|
31
62
|
await Promise.allSettled([
|
|
@@ -39,6 +70,81 @@ export function setRebuildCommandTestHooksForTests(hooks) {
|
|
|
39
70
|
function selectedPlatforms(selection) {
|
|
40
71
|
return selection === 'both' ? ['codex', 'claude'] : [selection];
|
|
41
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
|
+
}
|
|
42
148
|
function createSyntheticPlugin(pluginName, env) {
|
|
43
149
|
const rootDir = path.join(resolveAwHome(env), 'plugins', pluginName);
|
|
44
150
|
return {
|
|
@@ -243,24 +349,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
243
349
|
results.push(failedResult(options.command, identity, 'codexScopePathAlias: Codex project config 与用户配置目录相同。请进入实际项目目录后重试。'));
|
|
244
350
|
continue;
|
|
245
351
|
}
|
|
246
|
-
if (currentPlugin
|
|
247
|
-
&& platform === 'codex'
|
|
248
|
-
&& options.commandOptions.scope === 'project'
|
|
249
|
-
&& options.command !== 'cleanup'
|
|
250
|
-
&& options.command !== 'uninstall'
|
|
251
|
-
&& currentPlugin.manifest.apps) {
|
|
252
|
-
results.push(failedResult(options.command, identity, `${pluginName} 声明了 apps;Codex project scope 不支持 apps。`));
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
if (currentPlugin
|
|
256
|
-
&& platform === 'codex'
|
|
257
|
-
&& options.commandOptions.scope === 'project'
|
|
258
|
-
&& options.command !== 'cleanup'
|
|
259
|
-
&& options.command !== 'uninstall'
|
|
260
|
-
&& !hasCodexProjectManagedArtifacts(currentPlugin)) {
|
|
261
|
-
results.push(failedResult(options.command, identity, `${pluginName} 没有 Codex project scope 可生成的 Skills、instructions、roles、MCP、hooks 或 permissions。`));
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
352
|
let result;
|
|
265
353
|
try {
|
|
266
354
|
if (options.runtime?.preparedTargetError)
|
|
@@ -310,17 +398,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
310
398
|
}
|
|
311
399
|
}
|
|
312
400
|
const successful = results.filter((result) => result.status === 'succeeded');
|
|
313
|
-
const artifacts = targets.flatMap((target) => [...target.artifacts]);
|
|
314
|
-
const nativePlugins = {};
|
|
315
|
-
for (const result of successful) {
|
|
316
|
-
const target = targets.find((entry) => entry.identity.pluginName === result.target.pluginName
|
|
317
|
-
&& entry.identity.platform === result.target.platform
|
|
318
|
-
&& entry.identity.scope === result.target.scope);
|
|
319
|
-
if (target?.requiresNative && options.command !== 'cleanup' && options.command !== 'uninstall') {
|
|
320
|
-
nativePlugins[result.target.platform] ??= [];
|
|
321
|
-
nativePlugins[result.target.platform].push(result.target.pluginName);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
401
|
return {
|
|
325
402
|
platforms,
|
|
326
403
|
plugins: [...new Set(successful.map((result) => result.target.pluginName))],
|
|
@@ -328,8 +405,6 @@ async function runSingleSourceRebuildCommand(options) {
|
|
|
328
405
|
rebuildResults: results,
|
|
329
406
|
targetResults: results.map(toTargetResult),
|
|
330
407
|
overallState: results.every((result) => result.status === 'succeeded') ? 'succeeded' : 'failed',
|
|
331
|
-
nativePlugins,
|
|
332
|
-
repoManagedArtifacts: artifacts,
|
|
333
408
|
receiptTargets: results.map((result) => ({
|
|
334
409
|
pluginName: result.target.pluginName,
|
|
335
410
|
...(result.target.sourceId ? {
|
|
@@ -356,14 +431,6 @@ function toCatalogResolution(source) {
|
|
|
356
431
|
function mergeRebuildCommandResults(results) {
|
|
357
432
|
const rebuildResults = results.flatMap((result) => result.rebuildResults);
|
|
358
433
|
const platforms = [...new Set(results.flatMap((result) => result.platforms))];
|
|
359
|
-
const nativePlugins = {};
|
|
360
|
-
for (const result of results) {
|
|
361
|
-
for (const platform of ['codex', 'claude']) {
|
|
362
|
-
const names = result.nativePlugins[platform];
|
|
363
|
-
if (names)
|
|
364
|
-
nativePlugins[platform] = [...new Set([...(nativePlugins[platform] ?? []), ...names])];
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
434
|
return {
|
|
368
435
|
platforms,
|
|
369
436
|
plugins: [...new Set(results.flatMap((result) => result.plugins))],
|
|
@@ -373,8 +440,6 @@ function mergeRebuildCommandResults(results) {
|
|
|
373
440
|
overallState: rebuildResults.every((result) => result.status === 'succeeded')
|
|
374
441
|
? 'succeeded'
|
|
375
442
|
: 'failed',
|
|
376
|
-
nativePlugins,
|
|
377
|
-
repoManagedArtifacts: [],
|
|
378
443
|
receiptTargets: results.flatMap((result) => result.receiptTargets),
|
|
379
444
|
...(results.find((result) => result.dependencyPlan)?.dependencyPlan
|
|
380
445
|
? { dependencyPlan: results.find((result) => result.dependencyPlan).dependencyPlan }
|
|
@@ -382,13 +447,15 @@ function mergeRebuildCommandResults(results) {
|
|
|
382
447
|
...(results.find((result) => result.codexManagerPreview)?.codexManagerPreview
|
|
383
448
|
? { codexManagerPreview: results.find((result) => result.codexManagerPreview).codexManagerPreview }
|
|
384
449
|
: {}),
|
|
450
|
+
...(results.some((result) => result.offlineCleanupPlans !== undefined)
|
|
451
|
+
? { offlineCleanupPlans: results.flatMap((result) => result.offlineCleanupPlans ?? []) }
|
|
452
|
+
: {}),
|
|
385
453
|
};
|
|
386
454
|
}
|
|
387
455
|
function leaseSafeRebuildResult(result) {
|
|
388
456
|
const projectPath = (value) => path.basename(value);
|
|
389
457
|
return {
|
|
390
458
|
...result,
|
|
391
|
-
repoManagedArtifacts: [],
|
|
392
459
|
rebuildResults: result.rebuildResults.map((entry) => ({
|
|
393
460
|
...entry,
|
|
394
461
|
target: { ...entry.target, cwd: '.' },
|
|
@@ -419,12 +486,18 @@ function projectLegacyTargets(references) {
|
|
|
419
486
|
return [`${target.pluginName}\0${target.platform}\0${target.scope}`, target];
|
|
420
487
|
})).values()];
|
|
421
488
|
}
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
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
|
+
};
|
|
428
501
|
}
|
|
429
502
|
function resolveLiveCleanupTargets(options) {
|
|
430
503
|
const visible = options.references.filter((reference) => (reference.kind === 'namespacedOwner'
|
|
@@ -442,6 +515,12 @@ function resolveLiveCleanupTargets(options) {
|
|
|
442
515
|
const matchesByTarget = new Map();
|
|
443
516
|
for (const reference of visible.filter((entry) => entry.pluginName === parsed.pluginName
|
|
444
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);
|
|
445
524
|
const liveNames = new Set(options.references.flatMap((candidate) => candidate.sourceId === reference.sourceId
|
|
446
525
|
&& candidate.sourceIdentity === reference.sourceIdentity
|
|
447
526
|
&& candidate.pluginName === reference.pluginName
|
|
@@ -480,6 +559,14 @@ function resolveLiveCleanupTargets(options) {
|
|
|
480
559
|
? { nativeRegistration: true }
|
|
481
560
|
: {}),
|
|
482
561
|
...(marketplaceIdentityUnresolved ? { marketplaceIdentityUnresolved: true } : {}),
|
|
562
|
+
...(lifecycleReference?.lifecycleMetadataIntegrityDigest
|
|
563
|
+
? {
|
|
564
|
+
lifecycleMetadataIntegrityDigest: lifecycleReference.lifecycleMetadataIntegrityDigest,
|
|
565
|
+
}
|
|
566
|
+
: {}),
|
|
567
|
+
...(lifecycleReference?.pluginVersion
|
|
568
|
+
? { lifecyclePluginVersion: lifecycleReference.pluginVersion }
|
|
569
|
+
: {}),
|
|
483
570
|
};
|
|
484
571
|
const key = [target.pluginId, target.sourceIdentity, target.platform, target.scope].join('\0');
|
|
485
572
|
const previous = matchesByTarget.get(key);
|
|
@@ -500,51 +587,6 @@ function resolveLiveCleanupTargets(options) {
|
|
|
500
587
|
].join('\0'), target])).values()],
|
|
501
588
|
};
|
|
502
589
|
}
|
|
503
|
-
async function discoverDamagedExclusiveCleanupTargets(options) {
|
|
504
|
-
const parsed = parsePluginId(options.selector);
|
|
505
|
-
if (!parsed.sourceId)
|
|
506
|
-
return [];
|
|
507
|
-
const targets = [];
|
|
508
|
-
for (const platform of options.platforms) {
|
|
509
|
-
const root = exclusiveSkillRoot({
|
|
510
|
-
platform,
|
|
511
|
-
scope: options.scope,
|
|
512
|
-
cwd: options.cwd,
|
|
513
|
-
env: options.env,
|
|
514
|
-
});
|
|
515
|
-
const entries = await fs.readdir(root, { withFileTypes: true }).catch(() => []);
|
|
516
|
-
for (const entry of entries) {
|
|
517
|
-
if (!entry.isDirectory() || entry.isSymbolicLink())
|
|
518
|
-
continue;
|
|
519
|
-
const markerPath = path.join(root, entry.name, '.agent-workflows-owner.json');
|
|
520
|
-
const markerStats = await fs.lstat(markerPath).catch(() => null);
|
|
521
|
-
if (!markerStats?.isFile() || markerStats.isSymbolicLink())
|
|
522
|
-
continue;
|
|
523
|
-
const raw = await fs.readJson(markerPath).catch(() => null);
|
|
524
|
-
if (!raw
|
|
525
|
-
|| raw.schemaVersion !== 2
|
|
526
|
-
|| raw.owner !== 'agent-workflows'
|
|
527
|
-
|| raw.sourceId !== parsed.sourceId
|
|
528
|
-
|| raw.plugin !== parsed.pluginName
|
|
529
|
-
|| raw.pluginId !== options.selector
|
|
530
|
-
|| raw.platform !== platform
|
|
531
|
-
|| raw.scope !== options.scope)
|
|
532
|
-
continue;
|
|
533
|
-
targets.push({
|
|
534
|
-
pluginId: options.selector,
|
|
535
|
-
pluginName: parsed.pluginName,
|
|
536
|
-
sourceId: parsed.sourceId,
|
|
537
|
-
sourceIdentity: typeof raw.sourceIdentity === 'string'
|
|
538
|
-
&& /^sha256:[0-9a-f]{64}$/u.test(raw.sourceIdentity)
|
|
539
|
-
? raw.sourceIdentity
|
|
540
|
-
: `sha256:${'0'.repeat(64)}`,
|
|
541
|
-
platform,
|
|
542
|
-
scope: raw.scope,
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
return [...new Map(targets.map((target) => [[target.platform, target.scope].join('\0'), target])).values()];
|
|
547
|
-
}
|
|
548
590
|
async function cleanupOfflineOwnedComponents(options) {
|
|
549
591
|
if (options.targets.some((target) => target.marketplaceIdentityUnresolved)) {
|
|
550
592
|
throw namespacedPreflightError('marketplaceIdentityUnavailable: Cannot uniquely recover the native marketplace name from live inventory or a canonical native registration path.', options.targets);
|
|
@@ -552,35 +594,7 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
552
594
|
const results = [];
|
|
553
595
|
const warnings = [];
|
|
554
596
|
const nativeCliRunner = options.nativeCliRunner ?? getDefaultNativeCliRunner();
|
|
555
|
-
|
|
556
|
-
const codexManagerNeedFailures = new Map();
|
|
557
|
-
if (!codexManager) {
|
|
558
|
-
const codexManagerRequired = (await Promise.all(options.targets.map(async (target) => {
|
|
559
|
-
if (target.platform !== 'codex' || target.scope !== 'user')
|
|
560
|
-
return false;
|
|
561
|
-
try {
|
|
562
|
-
return await codexNativeRemovalRequired({
|
|
563
|
-
pluginName: target.pluginName,
|
|
564
|
-
cwd: options.cwd,
|
|
565
|
-
env: options.env,
|
|
566
|
-
marketplaceName: target.marketplaceName,
|
|
567
|
-
marketplaceRoot: path.join(resolveAwHome(options.env), 'marketplaces', target.sourceId),
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
catch (error) {
|
|
571
|
-
codexManagerNeedFailures.set(target, new Error('codexNativeResidueProbeFailed: Codex native residue was retained because its config or cache evidence could not be read. Repair the damaged Codex weak state, then retry cleanup; you can also upgrade AW or install a compatible official Codex CLI.', { cause: error }));
|
|
572
|
-
return false;
|
|
573
|
-
}
|
|
574
|
-
}))).some(Boolean);
|
|
575
|
-
if (codexManagerRequired) {
|
|
576
|
-
codexManager = await (options.codexManagerResolver ?? resolveCodexManager)({
|
|
577
|
-
cwd: options.cwd,
|
|
578
|
-
env: options.env,
|
|
579
|
-
runner: nativeCliRunner,
|
|
580
|
-
authorizer: options.managedCodexAuthorizer,
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
}
|
|
597
|
+
const codexManager = options.codexManager;
|
|
584
598
|
const context = {
|
|
585
599
|
env: options.env,
|
|
586
600
|
nativeCliRunner,
|
|
@@ -594,59 +608,39 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
594
608
|
loadPlugin: (bundleRoot) => readPluginManifest(bundleRoot, { mode: 'bundle' }),
|
|
595
609
|
});
|
|
596
610
|
for (const target of options.targets) {
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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',
|
|
604
627
|
cwd: options.cwd,
|
|
605
628
|
env: options.env,
|
|
606
629
|
});
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
const directory = path.join(root, entry.name);
|
|
612
|
-
let recovered;
|
|
613
|
-
try {
|
|
614
|
-
recovered = await cleanupCorruptExclusivePluginDirectory({
|
|
615
|
-
directory,
|
|
616
|
-
allowedRoot: root,
|
|
617
|
-
sourceId: target.sourceId,
|
|
618
|
-
pluginName: target.pluginName,
|
|
619
|
-
platform: target.platform,
|
|
620
|
-
scope: target.scope,
|
|
621
|
-
...options.corruptExclusiveDirectoryOperations,
|
|
622
|
-
});
|
|
623
|
-
}
|
|
624
|
-
catch (error) {
|
|
625
|
-
recovered = {
|
|
626
|
-
removed: [], absent: [], residual: [directory], quarantined: [],
|
|
627
|
-
failures: [{
|
|
628
|
-
label: directory,
|
|
629
|
-
phase: 'mutation',
|
|
630
|
-
message: error instanceof Error ? error.message : String(error),
|
|
631
|
-
}],
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
if (recovered) {
|
|
635
|
-
exclusiveRecovery.removed.push(...recovered.removed);
|
|
636
|
-
exclusiveRecovery.absent.push(...recovered.absent);
|
|
637
|
-
exclusiveRecovery.residual.push(...recovered.residual);
|
|
638
|
-
exclusiveRecovery.quarantined.push(...recovered.quarantined);
|
|
639
|
-
exclusiveRecovery.failures.push(...recovered.failures);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
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';
|
|
642
634
|
}
|
|
643
635
|
const plugin = createSyntheticPlugin(target.pluginName, options.env);
|
|
636
|
+
if (target.lifecyclePluginVersion) {
|
|
637
|
+
plugin.manifest.version = target.lifecyclePluginVersion;
|
|
638
|
+
}
|
|
644
639
|
plugin.sourceId = target.sourceId;
|
|
645
640
|
plugin.sourceIdentity = target.sourceIdentity;
|
|
646
641
|
plugin.pluginId = target.pluginId;
|
|
647
642
|
const marketplaceName = target.marketplaceName ?? 'aw';
|
|
648
643
|
plugin.marketplaceName = marketplaceName;
|
|
649
|
-
const codexManagerNeedFailure = codexManagerNeedFailures.get(target);
|
|
650
644
|
const desired = await integration.buildTarget({
|
|
651
645
|
sourceId: target.sourceId,
|
|
652
646
|
sourceIdentity: target.sourceIdentity,
|
|
@@ -664,68 +658,45 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
664
658
|
catalogVersion: '0.0.0',
|
|
665
659
|
channel: 'beta',
|
|
666
660
|
},
|
|
667
|
-
includeHistoricalLifecycleArtifacts:
|
|
668
|
-
|
|
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
|
+
: {}),
|
|
669
678
|
});
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
...integration.driver,
|
|
673
|
-
probeNative: async () => {
|
|
674
|
-
throw codexManagerNeedFailure;
|
|
675
|
-
},
|
|
676
|
-
}
|
|
677
|
-
: integration.driver;
|
|
678
|
-
let result = await executeRebuildOperation({
|
|
679
|
+
const preserveDamagedLifecycle = inventoryErrors.some((error) => error.kind.startsWith('lifecycle'));
|
|
680
|
+
const result = await executeRebuildOperation({
|
|
679
681
|
command: 'cleanup',
|
|
680
682
|
target: desired,
|
|
681
|
-
driver,
|
|
682
|
-
activeStore
|
|
683
|
+
driver: integration.driver,
|
|
684
|
+
activeStore: preserveDamagedLifecycle
|
|
685
|
+
? { ...activeStore, remove: async () => undefined }
|
|
686
|
+
: activeStore,
|
|
683
687
|
});
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
actions: [...result.actions, { name: 'cleanup.owned', status: 'failed' }],
|
|
690
|
-
residual: [...new Set([...result.residual, residual])],
|
|
691
|
-
failures: [...result.failures, {
|
|
692
|
-
phase: 'cleanup.owned',
|
|
693
|
-
label: residual,
|
|
694
|
-
message: codexManagerNeedFailure.message,
|
|
695
|
-
}],
|
|
696
|
-
error: { phase: 'cleanup.owned', message: codexManagerNeedFailure.message },
|
|
697
|
-
};
|
|
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
|
+
])];
|
|
698
693
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const removed = [...new Set([...result.removed, ...exclusiveRecovery.removed])];
|
|
706
|
-
const absent = [...new Set([...result.absent, ...exclusiveRecovery.absent])]
|
|
707
|
-
.filter((entry) => !removed.includes(entry));
|
|
708
|
-
result = {
|
|
709
|
-
...result,
|
|
710
|
-
removed,
|
|
711
|
-
absent,
|
|
712
|
-
residual: [...new Set([...result.residual, ...exclusiveResidual])],
|
|
713
|
-
quarantined: [...new Set([...result.quarantined, ...exclusiveQuarantined])],
|
|
714
|
-
};
|
|
715
|
-
if (exclusiveFailures.length > 0) {
|
|
716
|
-
const failures = exclusiveFailures.map((failure) => ({
|
|
717
|
-
phase: 'cleanup.owned',
|
|
718
|
-
label: failure.label,
|
|
719
|
-
message: `exclusiveRecoveryFailed: ${failure.phase} ${failure.label}: ${failure.message}`,
|
|
720
|
-
}));
|
|
721
|
-
const message = failures[0].message;
|
|
722
|
-
result = {
|
|
723
|
-
...result,
|
|
724
|
-
status: 'failed',
|
|
725
|
-
actions: [{ name: 'cleanup.owned', status: 'failed' }],
|
|
726
|
-
failures: [...result.failures, ...failures],
|
|
727
|
-
error: { phase: 'cleanup.owned', message },
|
|
728
|
-
};
|
|
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}`));
|
|
729
700
|
}
|
|
730
701
|
results.push(result);
|
|
731
702
|
}
|
|
@@ -739,11 +710,10 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
739
710
|
return leaseSafeRebuildResult({
|
|
740
711
|
platforms: [...new Set(results.map((result) => result.target.platform))],
|
|
741
712
|
plugins: results.filter((result) => result.status === 'succeeded').map((result) => result.target.pluginName),
|
|
742
|
-
warnings,
|
|
713
|
+
warnings: [...new Set(warnings)],
|
|
743
714
|
rebuildResults: results,
|
|
744
715
|
targetResults: results.map(toTargetResult),
|
|
745
716
|
overallState: results.every((result) => result.status === 'succeeded') ? 'succeeded' : 'failed',
|
|
746
|
-
nativePlugins: {}, repoManagedArtifacts: [],
|
|
747
717
|
receiptTargets: results.map((result) => ({
|
|
748
718
|
pluginName: result.target.pluginName,
|
|
749
719
|
pluginId: result.target.pluginId,
|
|
@@ -751,6 +721,7 @@ async function cleanupOfflineOwnedComponents(options) {
|
|
|
751
721
|
platform: result.target.platform,
|
|
752
722
|
scope: result.target.scope,
|
|
753
723
|
})),
|
|
724
|
+
...(options.evidence ? { offlineCleanupPlans: options.evidence } : {}),
|
|
754
725
|
});
|
|
755
726
|
}
|
|
756
727
|
async function previewOfflineOwnedComponents(options) {
|
|
@@ -759,55 +730,139 @@ async function previewOfflineOwnedComponents(options) {
|
|
|
759
730
|
}
|
|
760
731
|
await options.onPreviewStage?.('inventory');
|
|
761
732
|
const preview = mergeRebuildCommandResults([]);
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
pluginName: target.pluginName,
|
|
765
|
-
cwd: options.cwd,
|
|
766
|
-
env: options.env,
|
|
767
|
-
marketplaceName: target.marketplaceName,
|
|
768
|
-
marketplaceRoot: path.join(resolveAwHome(options.env), 'marketplaces', target.sourceId),
|
|
769
|
-
})]
|
|
770
|
-
: []))).some(Boolean);
|
|
733
|
+
if (options.evidence)
|
|
734
|
+
preview.offlineCleanupPlans = options.evidence;
|
|
771
735
|
await options.onPreviewStage?.('dependencyPlan');
|
|
772
|
-
if (codexManagerRequired) {
|
|
773
|
-
preview.codexManagerPreview = await (options.codexManagerPreviewer ?? previewCodexManager)({
|
|
774
|
-
cwd: options.cwd,
|
|
775
|
-
env: options.env,
|
|
776
|
-
runner: options.nativeCliRunner,
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
736
|
return preview;
|
|
780
737
|
}
|
|
781
738
|
async function assertOfflineCleanupDependents(options) {
|
|
782
739
|
const inventory = await options.readInventory({
|
|
783
|
-
cwd: options.cwd,
|
|
784
|
-
env: options.env,
|
|
785
|
-
includeHistoricalProjects: true,
|
|
740
|
+
cwd: options.cwd, env: options.env, includeHistoricalProjects: true,
|
|
786
741
|
});
|
|
787
742
|
const currentProjectKey = await resolveCanonicalRepoProjectKey(options.cwd);
|
|
743
|
+
const cleanupIds = new Set(options.targets.map((target) => target.pluginId));
|
|
788
744
|
for (const target of options.targets) {
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
.
|
|
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) {
|
|
796
764
|
if (!consumer?.manifest.dependencies?.includes(target.pluginName))
|
|
797
765
|
continue;
|
|
798
766
|
const consumerId = formatPluginId({ sourceId: target.sourceId, pluginName: consumer.manifest.name });
|
|
799
|
-
|
|
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')
|
|
800
772
|
&& reference.sourceId === target.sourceId
|
|
801
773
|
&& reference.sourceIdentity === target.sourceIdentity
|
|
802
774
|
&& reference.pluginName === consumer.manifest.name
|
|
803
775
|
&& reference.platform === target.platform
|
|
804
776
|
&& (target.scope === 'user' || reference.scope === 'project')
|
|
805
777
|
&& (target.scope === 'user' || reference.projectKey === currentProjectKey));
|
|
806
|
-
if (live)
|
|
778
|
+
if (live)
|
|
807
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);
|
|
808
820
|
}
|
|
821
|
+
catch {
|
|
822
|
+
continue;
|
|
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));
|
|
809
835
|
}
|
|
810
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;
|
|
811
866
|
}
|
|
812
867
|
export async function runRebuildCommand(options) {
|
|
813
868
|
if (options.runtime?.catalogResolution && options.runtime.bypassDependencyPlan) {
|
|
@@ -818,10 +873,24 @@ export async function runRebuildCommand(options) {
|
|
|
818
873
|
?? inventoryCatalogSourceReferences;
|
|
819
874
|
let ordinaryInventory;
|
|
820
875
|
const readOrdinaryInventory = async () => {
|
|
821
|
-
ordinaryInventory ??= await readInventory({
|
|
876
|
+
ordinaryInventory ??= await measureCommandPerformanceStage(options.runtime, 'inventory', () => readInventory({
|
|
822
877
|
cwd: options.commandOptions.cwd,
|
|
823
878
|
env: runtimeEnv,
|
|
824
|
-
|
|
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
|
+
}));
|
|
825
894
|
return ordinaryInventory;
|
|
826
895
|
};
|
|
827
896
|
let requestedPluginNames = options.pluginNames;
|
|
@@ -830,7 +899,6 @@ export async function runRebuildCommand(options) {
|
|
|
830
899
|
const expectedOfflineCleanup = options.runtime?.expectedOfflineCleanupEvidence;
|
|
831
900
|
let cleanupInventory;
|
|
832
901
|
let cleanupLiveTargets = [];
|
|
833
|
-
let cleanupHasDamagedExclusiveTarget = false;
|
|
834
902
|
let liveTargets = [];
|
|
835
903
|
let legacyLiveTargets = [];
|
|
836
904
|
if (options.command === 'cleanup' && !options.all) {
|
|
@@ -863,48 +931,8 @@ export async function runRebuildCommand(options) {
|
|
|
863
931
|
}
|
|
864
932
|
cleanupLiveTargets = [liveTarget];
|
|
865
933
|
}
|
|
866
|
-
if (cleanupForce && !expectedOfflineCleanup) {
|
|
867
|
-
const damagedTargets = (await Promise.all(requestedPluginNames.map(async (selector) => parsePluginId(selector).sourceId
|
|
868
|
-
? discoverDamagedExclusiveCleanupTargets({
|
|
869
|
-
selector,
|
|
870
|
-
platforms: selectedPlatforms(options.commandOptions.platform),
|
|
871
|
-
scope: options.commandOptions.scope,
|
|
872
|
-
cwd: options.commandOptions.cwd,
|
|
873
|
-
env: runtimeEnv,
|
|
874
|
-
})
|
|
875
|
-
: []))).flat();
|
|
876
|
-
cleanupHasDamagedExclusiveTarget = damagedTargets.length > 0;
|
|
877
|
-
cleanupLiveTargets = [...new Map([
|
|
878
|
-
...damagedTargets,
|
|
879
|
-
...cleanupLiveTargets,
|
|
880
|
-
].map((target) => [[target.pluginId, target.platform, target.scope].join('\0'), target])).values()];
|
|
881
|
-
}
|
|
882
934
|
liveTargets = cleanupLiveTargets;
|
|
883
935
|
}
|
|
884
|
-
if (cleanupHasDamagedExclusiveTarget) {
|
|
885
|
-
if (options.runtime?.previewDependencyPlanOnly) {
|
|
886
|
-
return previewOfflineOwnedComponents({
|
|
887
|
-
targets: cleanupLiveTargets,
|
|
888
|
-
cwd: options.commandOptions.cwd,
|
|
889
|
-
env: runtimeEnv,
|
|
890
|
-
nativeCliRunner: options.runtime.nativeCliRunner,
|
|
891
|
-
codexManagerPreviewer: options.runtime.codexManagerPreviewer,
|
|
892
|
-
onPreviewStage: options.runtime.onPreviewStage,
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
return cleanupOfflineOwnedComponents({
|
|
896
|
-
targets: cleanupLiveTargets,
|
|
897
|
-
cwd: options.commandOptions.cwd,
|
|
898
|
-
env: runtimeEnv,
|
|
899
|
-
force: true,
|
|
900
|
-
removeObsoleteInstallationContracts: options.runtime?.removeObsoleteInstallationContracts,
|
|
901
|
-
nativeCliRunner: options.runtime?.nativeCliRunner,
|
|
902
|
-
codexManager: options.runtime?.codexManager,
|
|
903
|
-
codexManagerResolver: options.runtime?.codexManagerResolver,
|
|
904
|
-
managedCodexAuthorizer: options.runtime?.managedCodexAuthorizer,
|
|
905
|
-
corruptExclusiveDirectoryOperations: options.runtime?.corruptExclusiveDirectoryOperations,
|
|
906
|
-
});
|
|
907
|
-
}
|
|
908
936
|
if (options.all) {
|
|
909
937
|
const inventory = await readOrdinaryInventory();
|
|
910
938
|
if (options.command !== 'cleanup')
|
|
@@ -937,6 +965,10 @@ export async function runRebuildCommand(options) {
|
|
|
937
965
|
].join('\0'), target];
|
|
938
966
|
})).values()];
|
|
939
967
|
liveTargets = projectedTargets;
|
|
968
|
+
if (options.command === 'cleanup') {
|
|
969
|
+
cleanupInventory = inventory;
|
|
970
|
+
cleanupLiveTargets = projectedTargets;
|
|
971
|
+
}
|
|
940
972
|
const identities = new Map();
|
|
941
973
|
for (const reference of live) {
|
|
942
974
|
if (!reference.sourceIdentity) {
|
|
@@ -959,6 +991,147 @@ export async function runRebuildCommand(options) {
|
|
|
959
991
|
}
|
|
960
992
|
return mergeRebuildCommandResults([]);
|
|
961
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
|
+
}
|
|
962
1135
|
try {
|
|
963
1136
|
if (options.runtime?.previewDependencyPlanOnly) {
|
|
964
1137
|
await options.runtime.onPreviewStage?.('catalog');
|
|
@@ -967,31 +1140,18 @@ export async function runRebuildCommand(options) {
|
|
|
967
1140
|
throw options.runtime.catalogBootstrapError;
|
|
968
1141
|
}
|
|
969
1142
|
const catalogOperation = options.runtime?.catalogOperationContext
|
|
970
|
-
?? (options.
|
|
971
|
-
?
|
|
972
|
-
:
|
|
973
|
-
|
|
974
|
-
...(sourceIds ? { sourceIds } : {}),
|
|
975
|
-
env: runtimeEnv,
|
|
976
|
-
...(options.runtime?.catalogGenerationRuntime
|
|
977
|
-
? { runtime: options.runtime.catalogGenerationRuntime }
|
|
978
|
-
: {}),
|
|
979
|
-
...(options.runtime?.awHomeMutationToken
|
|
980
|
-
? { bootstrapMissingActive: false }
|
|
981
|
-
: {}),
|
|
982
|
-
}));
|
|
1143
|
+
?? await measureCommandPerformanceStage(options.runtime, 'catalog.load', () => resolveCatalogOperationContext({
|
|
1144
|
+
...(sourceIds ? { sourceIds } : {}),
|
|
1145
|
+
env: runtimeEnv,
|
|
1146
|
+
}));
|
|
983
1147
|
if (options.runtime?.expectedGenerationSetDigest
|
|
984
1148
|
&& catalogOperation?.generationSetDigest !== options.runtime.expectedGenerationSetDigest) {
|
|
985
1149
|
throw new Error('operationReviewStale: Active Catalog generation changed before mutation.');
|
|
986
1150
|
}
|
|
987
1151
|
const resolvedResult = await withResolvedMultiSourceCatalog({
|
|
988
1152
|
cliVersion: resolveRuntimeCliVersion(),
|
|
989
|
-
freshnessPolicy: 'cacheFirst',
|
|
990
1153
|
...(sourceIds ? { sourceIds } : {}),
|
|
991
1154
|
...(catalogOperation ? { operationContext: catalogOperation } : {}),
|
|
992
|
-
...(options.command === 'cleanup' || options.runtime?.awHomeMutationToken
|
|
993
|
-
? { bootstrapMissingActive: false }
|
|
994
|
-
: {}),
|
|
995
1155
|
env: runtimeEnv,
|
|
996
1156
|
consume: async (catalog) => {
|
|
997
1157
|
const failedSources = catalog.sources.filter((source) => source.error);
|
|
@@ -1050,9 +1210,16 @@ export async function runRebuildCommand(options) {
|
|
|
1050
1210
|
? availableEntries.filter((candidate) => selectedEntries.some((selectedEntry) => candidate.source.sourceId === selectedEntry.source.sourceId
|
|
1051
1211
|
&& candidate.entry.dependencies.includes(selectedEntry.entry.name)))
|
|
1052
1212
|
: [];
|
|
1213
|
+
const removalDesiredEntries = options.command === 'cleanup' || options.command === 'uninstall'
|
|
1214
|
+
? entryClosure(selectedEntries)
|
|
1215
|
+
: [];
|
|
1053
1216
|
const requiredEntryClosure = dependencyEnabled
|
|
1054
1217
|
? entryClosure(selectedEntries)
|
|
1055
|
-
: [...new Map([
|
|
1218
|
+
: [...new Map([
|
|
1219
|
+
...selectedEntries,
|
|
1220
|
+
...removalDesiredEntries,
|
|
1221
|
+
...removalConsumerEntries,
|
|
1222
|
+
].map((candidate) => [candidate.pluginId, candidate])).values()];
|
|
1056
1223
|
if (dependencyEnabled) {
|
|
1057
1224
|
for (const candidate of requiredEntryClosure) {
|
|
1058
1225
|
const requiredCapabilities = candidate.entry.requires.aw.capabilities ?? [];
|
|
@@ -1061,15 +1228,17 @@ export async function runRebuildCommand(options) {
|
|
|
1061
1228
|
throw new AwCapabilityUnsupportedError(candidate.pluginId, support.missing);
|
|
1062
1229
|
}
|
|
1063
1230
|
}
|
|
1064
|
-
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
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
|
+
}
|
|
1071
1240
|
}
|
|
1072
|
-
}
|
|
1241
|
+
});
|
|
1073
1242
|
}
|
|
1074
1243
|
const available = await Promise.all(requiredEntryClosure.map(async (candidate) => {
|
|
1075
1244
|
const plugin = await readPluginManifest(path.join(candidate.source.rootDir, 'plugins', candidate.entry.name), { mode: 'bundle' });
|
|
@@ -1105,7 +1274,9 @@ export async function runRebuildCommand(options) {
|
|
|
1105
1274
|
}
|
|
1106
1275
|
const closureEntries = dependencyEnabled
|
|
1107
1276
|
? [...new Map([...closureEntriesByPlatform.values()].flat().map((entry) => [entry.pluginId, entry])).values()]
|
|
1108
|
-
:
|
|
1277
|
+
: options.command === 'cleanup' || options.command === 'uninstall'
|
|
1278
|
+
? resolveClosureEntries(selected)
|
|
1279
|
+
: selected;
|
|
1109
1280
|
const rawExecutionSelections = options.all
|
|
1110
1281
|
? liveTargets.flatMap((target) => {
|
|
1111
1282
|
const entry = selected.find((candidate) => candidate.pluginId === target.pluginId);
|
|
@@ -1149,6 +1320,20 @@ export async function runRebuildCommand(options) {
|
|
|
1149
1320
|
const stateInventory = await readOrdinaryInventory();
|
|
1150
1321
|
if (options.command !== 'cleanup')
|
|
1151
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
|
+
};
|
|
1152
1337
|
const commandProjectKey = await resolveCanonicalRepoProjectKey(options.commandOptions.cwd);
|
|
1153
1338
|
const codexScopePathsAlias = codexProjectConfigAliasesUserHome(options.commandOptions.cwd, runtimeEnv);
|
|
1154
1339
|
const selectedLegacy = selectedLegacyLiveReferences(stateInventory.references, new Set(executionSelections.map((selection) => selection.platform)), options.commandOptions.scope);
|
|
@@ -1236,10 +1421,27 @@ export async function runRebuildCommand(options) {
|
|
|
1236
1421
|
context: executionContext,
|
|
1237
1422
|
scriptTimeoutMs: options.commandOptions.scriptTimeoutMs,
|
|
1238
1423
|
});
|
|
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()];
|
|
1239
1433
|
const createPlan = async (inventory) => {
|
|
1240
1434
|
if (options.command !== 'cleanup')
|
|
1241
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;
|
|
1242
1442
|
const targets = [];
|
|
1443
|
+
const placementNodes = [];
|
|
1444
|
+
const blockingTargets = new Map();
|
|
1243
1445
|
for (const [order, { entry, platform }] of executionSelections.entries()) {
|
|
1244
1446
|
const relation = selectedIds.has(entry.pluginId) ? 'requested' : 'dependency';
|
|
1245
1447
|
let resolvedScope = options.commandOptions.scope;
|
|
@@ -1292,7 +1494,54 @@ export async function runRebuildCommand(options) {
|
|
|
1292
1494
|
? Promise.resolve({ state: 'absent', components: [], errors: [] })
|
|
1293
1495
|
: inspectScope(otherScope),
|
|
1294
1496
|
]);
|
|
1295
|
-
|
|
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;
|
|
1296
1545
|
let action = relation === 'requested'
|
|
1297
1546
|
? options.command
|
|
1298
1547
|
: options.command === 'reinstall' ? 'reinstall' : 'upgrade';
|
|
@@ -1303,15 +1552,32 @@ export async function runRebuildCommand(options) {
|
|
|
1303
1552
|
action = 'block';
|
|
1304
1553
|
errorCode = 'artifactCollision';
|
|
1305
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
|
+
}
|
|
1306
1569
|
else if (dependencyEnabled && relation === 'requested'
|
|
1307
1570
|
&& (requestedInspection.state === 'error'
|
|
1308
|
-
|| (requestedInspection.state === 'partial'
|
|
1571
|
+
|| (requestedInspection.state === 'partial'
|
|
1572
|
+
&& platform !== 'codex'
|
|
1573
|
+
&& options.command !== 'reinstall'
|
|
1574
|
+
&& options.command !== 'cleanup'))) {
|
|
1309
1575
|
action = 'block';
|
|
1310
1576
|
errorCode = 'dependencyNotReady';
|
|
1311
1577
|
}
|
|
1312
1578
|
if (!hasForeignCollision && relation === 'dependency'
|
|
1313
|
-
&&
|
|
1314
|
-
&&
|
|
1579
|
+
&& requestedPlacementState === 'present'
|
|
1580
|
+
&& otherPlacementState === 'present') {
|
|
1315
1581
|
action = 'block';
|
|
1316
1582
|
state = 'partial';
|
|
1317
1583
|
errorCode = 'dependencyScopeConflict';
|
|
@@ -1324,24 +1590,26 @@ export async function runRebuildCommand(options) {
|
|
|
1324
1590
|
}
|
|
1325
1591
|
else if (!hasForeignCollision && relation === 'dependency'
|
|
1326
1592
|
&& options.commandOptions.scope === 'project'
|
|
1327
|
-
&& (
|
|
1593
|
+
&& (otherPlacementState === 'partial' || otherPlacementState === 'error')) {
|
|
1328
1594
|
resolvedScope = 'user';
|
|
1329
|
-
state =
|
|
1330
|
-
if (
|
|
1595
|
+
state = otherPlacementState;
|
|
1596
|
+
if (otherPlacementState === 'error') {
|
|
1331
1597
|
action = 'block';
|
|
1332
1598
|
errorCode = 'dependencyNotReady';
|
|
1333
1599
|
}
|
|
1334
1600
|
}
|
|
1335
1601
|
else if (!hasForeignCollision && relation === 'dependency'
|
|
1336
1602
|
&& options.commandOptions.scope === 'user'
|
|
1337
|
-
&&
|
|
1603
|
+
&& otherPlacementState !== 'absent') {
|
|
1338
1604
|
action = 'block';
|
|
1339
1605
|
errorCode = 'dependencyScopeTooNarrow';
|
|
1340
1606
|
}
|
|
1341
1607
|
const resolvedInspection = resolvedScope === options.commandOptions.scope
|
|
1342
1608
|
? requestedInspection
|
|
1343
1609
|
: otherInspection;
|
|
1344
|
-
state =
|
|
1610
|
+
state = resolvedScope === options.commandOptions.scope
|
|
1611
|
+
? requestedPlacementState
|
|
1612
|
+
: otherPlacementState;
|
|
1345
1613
|
if (!hasForeignCollision && !errorCode
|
|
1346
1614
|
&& relation === 'dependency' && options.command === 'install') {
|
|
1347
1615
|
action = state === 'present' ? 'keep' : state === 'partial' ? 'reinstall' : 'install';
|
|
@@ -1352,13 +1620,6 @@ export async function runRebuildCommand(options) {
|
|
|
1352
1620
|
state = resolvedInspection.state;
|
|
1353
1621
|
errorCode ??= 'dependencyNotReady';
|
|
1354
1622
|
}
|
|
1355
|
-
if (!hasForeignCollision && relation === 'dependency'
|
|
1356
|
-
&& platform === 'codex'
|
|
1357
|
-
&& resolvedScope === 'project'
|
|
1358
|
-
&& (entry.plugin.manifest.apps || !hasCodexProjectManagedArtifacts(entry.plugin))) {
|
|
1359
|
-
action = 'block';
|
|
1360
|
-
errorCode = 'dependencyTargetUnsupported';
|
|
1361
|
-
}
|
|
1362
1623
|
if (entry.plugin.manifest.config?.schema
|
|
1363
1624
|
&& (action === 'install' || action === 'upgrade' || action === 'reinstall')) {
|
|
1364
1625
|
const effective = await resolveEffectivePluginConfig({
|
|
@@ -1381,6 +1642,12 @@ export async function runRebuildCommand(options) {
|
|
|
1381
1642
|
action = 'block';
|
|
1382
1643
|
errorCode = 'codexScopePathAlias';
|
|
1383
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);
|
|
1384
1651
|
targets.push({
|
|
1385
1652
|
pluginId: entry.pluginId,
|
|
1386
1653
|
pluginName: entry.plugin.manifest.name,
|
|
@@ -1398,6 +1665,46 @@ export async function runRebuildCommand(options) {
|
|
|
1398
1665
|
...(errorCode ? { errorCode } : {}),
|
|
1399
1666
|
});
|
|
1400
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
|
+
}
|
|
1401
1708
|
return createDependencyOperationPlan({
|
|
1402
1709
|
requestedPluginIds: selected.map((entry) => entry.pluginId),
|
|
1403
1710
|
resolvedPluginIds: closureEntries.map((entry) => entry.pluginId),
|
|
@@ -1408,6 +1715,214 @@ export async function runRebuildCommand(options) {
|
|
|
1408
1715
|
targets,
|
|
1409
1716
|
});
|
|
1410
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
|
+
};
|
|
1411
1926
|
const operationNeedsNativeCli = async (platform, plan) => {
|
|
1412
1927
|
for (const { entry, platform: selectedPlatform } of executionSelections) {
|
|
1413
1928
|
if (selectedPlatform !== platform)
|
|
@@ -1422,14 +1937,6 @@ export async function runRebuildCommand(options) {
|
|
|
1422
1937
|
entry.plugin.marketplaceName = marketplaceName;
|
|
1423
1938
|
const marketplaceRoot = path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId);
|
|
1424
1939
|
if (!dependencyEnabled && selectedPlatform === 'codex') {
|
|
1425
|
-
if (scope === 'user' && await codexNativeRemovalRequired({
|
|
1426
|
-
pluginName: entry.plugin.manifest.name,
|
|
1427
|
-
cwd: options.commandOptions.cwd,
|
|
1428
|
-
env: runtimeEnv,
|
|
1429
|
-
marketplaceName,
|
|
1430
|
-
marketplaceRoot,
|
|
1431
|
-
}))
|
|
1432
|
-
return true;
|
|
1433
1940
|
continue;
|
|
1434
1941
|
}
|
|
1435
1942
|
const target = await inspection.buildTarget({
|
|
@@ -1449,7 +1956,7 @@ export async function runRebuildCommand(options) {
|
|
|
1449
1956
|
includeHistoricalLifecycleArtifacts: false,
|
|
1450
1957
|
readOnlyInspectionPlan: true,
|
|
1451
1958
|
});
|
|
1452
|
-
if (dependencyEnabled && target.requiresNative)
|
|
1959
|
+
if (dependencyEnabled && (target.writeNativeRequired ?? target.requiresNative))
|
|
1453
1960
|
return true;
|
|
1454
1961
|
const nativeComponents = target.ownedComponents.filter((component) => component.kind === 'native-plugin'
|
|
1455
1962
|
|| (component.kind === 'shared-config'
|
|
@@ -1468,11 +1975,36 @@ export async function runRebuildCommand(options) {
|
|
|
1468
1975
|
};
|
|
1469
1976
|
if (options.runtime?.previewDependencyPlanOnly) {
|
|
1470
1977
|
await options.runtime.onPreviewStage?.('dependencyPlan');
|
|
1471
|
-
const initialPlan = dependencyEnabled
|
|
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;
|
|
1472
2000
|
const preview = mergeRebuildCommandResults([]);
|
|
1473
2001
|
if (initialPlan)
|
|
1474
2002
|
preview.dependencyPlan = initialPlan;
|
|
1475
|
-
if (
|
|
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'))) {
|
|
1476
2008
|
preview.codexManagerPreview = await (options.runtime.codexManagerPreviewer ?? previewCodexManager)({
|
|
1477
2009
|
cwd: options.commandOptions.cwd,
|
|
1478
2010
|
env: runtimeEnv,
|
|
@@ -1506,11 +2038,62 @@ export async function runRebuildCommand(options) {
|
|
|
1506
2038
|
contentDigest: entry.source.manifest.entries.find((candidate) => candidate.name === entry.plugin.manifest.name)?.contentDigest,
|
|
1507
2039
|
});
|
|
1508
2040
|
}
|
|
1509
|
-
const lockedPlan = await createPlan(stateInventory);
|
|
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
|
+
}
|
|
1510
2064
|
if (options.runtime?.expectedOperationDependencyPlan
|
|
1511
2065
|
&& JSON.stringify(lockedPlan) !== JSON.stringify(options.runtime.expectedOperationDependencyPlan)) {
|
|
1512
2066
|
throw namespacedPreflightError('operationReviewStale: dependency plan changed before mutation.', preflightTargets);
|
|
1513
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
|
+
}
|
|
1514
2097
|
for (const pluginName of new Set(lockedPlan.targets.flatMap((target) => target.platform === 'claude'
|
|
1515
2098
|
&& (target.action === 'install'
|
|
1516
2099
|
|| target.action === 'upgrade'
|
|
@@ -1523,15 +2106,36 @@ export async function runRebuildCommand(options) {
|
|
|
1523
2106
|
env: runtimeEnv,
|
|
1524
2107
|
});
|
|
1525
2108
|
}
|
|
1526
|
-
const codexManagerRequired = await operationNeedsNativeCli('codex', lockedPlan);
|
|
1527
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;
|
|
1528
2112
|
if (codexManagerRequired) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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
|
+
}
|
|
1535
2139
|
}
|
|
1536
2140
|
await assertClaudeVersion({
|
|
1537
2141
|
platforms: claudeCliRequired ? ['claude'] : [],
|
|
@@ -1548,13 +2152,30 @@ export async function runRebuildCommand(options) {
|
|
|
1548
2152
|
const lockedCollisionSelections = [];
|
|
1549
2153
|
for (const { entry, platform } of executionSelections) {
|
|
1550
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;
|
|
1551
2163
|
if (planned.action !== 'install'
|
|
1552
2164
|
&& planned.action !== 'upgrade'
|
|
1553
|
-
&& planned.action !== 'reinstall'
|
|
2165
|
+
&& planned.action !== 'reinstall'
|
|
2166
|
+
&& planned.action !== 'move'
|
|
2167
|
+
&& !desiredCleanup)
|
|
1554
2168
|
continue;
|
|
2169
|
+
const buildCommand = desiredCleanup
|
|
2170
|
+
? 'install'
|
|
2171
|
+
: planned.action === 'move'
|
|
2172
|
+
? 'install'
|
|
2173
|
+
: planned.relation === 'dependency'
|
|
2174
|
+
? planned.action
|
|
2175
|
+
: options.command;
|
|
1555
2176
|
const marketplaceName = marketplaceNameFor(entry, platform, planned.resolvedScope);
|
|
1556
2177
|
try {
|
|
1557
|
-
const target = await executionIntegration.buildTarget({
|
|
2178
|
+
const target = await measureCommandPerformanceStage(options.runtime, 'target.build', () => executionIntegration.buildTarget({
|
|
1558
2179
|
sourceId: entry.source.sourceId,
|
|
1559
2180
|
sourceIdentity: entry.source.sourceIdentity,
|
|
1560
2181
|
pluginId: entry.pluginId,
|
|
@@ -1564,21 +2185,27 @@ export async function runRebuildCommand(options) {
|
|
|
1564
2185
|
platform,
|
|
1565
2186
|
scope: planned.resolvedScope,
|
|
1566
2187
|
cwd: options.commandOptions.cwd,
|
|
1567
|
-
command:
|
|
2188
|
+
command: buildCommand,
|
|
1568
2189
|
catalog: toCatalogResolution(entry.source),
|
|
1569
2190
|
includeHistoricalLifecycleArtifacts: true,
|
|
1570
|
-
});
|
|
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
|
+
}
|
|
1571
2200
|
preparedTargets.set(`${entry.pluginId}\0${platform}`, {
|
|
1572
2201
|
target,
|
|
1573
2202
|
driver: executionIntegration.driver,
|
|
1574
2203
|
context: executionContext,
|
|
1575
2204
|
});
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
2205
|
+
await rebuildCommandTestHooks?.afterTargetBuilt?.({
|
|
2206
|
+
command: options.command,
|
|
2207
|
+
identity: target.identity,
|
|
2208
|
+
});
|
|
1582
2209
|
lockedCollisionSelections.push({
|
|
1583
2210
|
pluginId: entry.pluginId,
|
|
1584
2211
|
targetKey: `${platform}/${target.identity.scope}`,
|
|
@@ -1601,7 +2228,9 @@ export async function runRebuildCommand(options) {
|
|
|
1601
2228
|
throw namespacedPreflightError(`artifactCollision: ${lockedCollisions.map((collision) => `${collision.targetKey} (${collision.pluginIds.join(', ')})`).join('; ')}`, preflightTargets);
|
|
1602
2229
|
}
|
|
1603
2230
|
const removalRequiredConsumers = new Map();
|
|
1604
|
-
if ((options.command === 'cleanup' && !cleanupForce)
|
|
2231
|
+
if ((options.command === 'cleanup' && !cleanupForce)
|
|
2232
|
+
|| options.command === 'uninstall'
|
|
2233
|
+
|| options.runtime?.reconcileIntentOnly === true) {
|
|
1605
2234
|
const removalStateInventory = await readInventory({
|
|
1606
2235
|
cwd: options.commandOptions.cwd,
|
|
1607
2236
|
env: runtimeEnv,
|
|
@@ -1745,6 +2374,32 @@ export async function runRebuildCommand(options) {
|
|
|
1745
2374
|
scope: planned.resolvedScope,
|
|
1746
2375
|
cwd: options.commandOptions.cwd,
|
|
1747
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;
|
|
1748
2403
|
if (failedDependency || failedConsumer || planned.action === 'block') {
|
|
1749
2404
|
const code = failedConsumer
|
|
1750
2405
|
? 'dependencyStillRequired'
|
|
@@ -1768,7 +2423,7 @@ export async function runRebuildCommand(options) {
|
|
|
1768
2423
|
errorCode: code,
|
|
1769
2424
|
message,
|
|
1770
2425
|
}],
|
|
1771
|
-
overallState: 'failed',
|
|
2426
|
+
overallState: 'failed',
|
|
1772
2427
|
receiptTargets: [{
|
|
1773
2428
|
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
1774
2429
|
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
@@ -1777,7 +2432,51 @@ export async function runRebuildCommand(options) {
|
|
|
1777
2432
|
dependencyStates.set(`${entry.pluginId}\0${platform}`, failedDependency || failedConsumer ? 'skipped' : 'failed');
|
|
1778
2433
|
continue;
|
|
1779
2434
|
}
|
|
1780
|
-
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))) {
|
|
1781
2480
|
const result = {
|
|
1782
2481
|
status: 'succeeded', command: options.command, target: identity, actions: [],
|
|
1783
2482
|
cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
@@ -1785,7 +2484,24 @@ export async function runRebuildCommand(options) {
|
|
|
1785
2484
|
results.push({
|
|
1786
2485
|
platforms: [platform], plugins: [identity.pluginName], warnings: [], rebuildResults: [result],
|
|
1787
2486
|
targetResults: [{ target: identity, action: 'keep', state: 'completed' }],
|
|
1788
|
-
overallState: 'succeeded',
|
|
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) {
|
|
2497
|
+
const result = {
|
|
2498
|
+
status: 'succeeded', command: options.command, target: identity, actions: [],
|
|
2499
|
+
cleanupAttempted: false, removed: [], absent: [], residual: [], quarantined: [], failures: [],
|
|
2500
|
+
};
|
|
2501
|
+
results.push({
|
|
2502
|
+
platforms: [platform], plugins: [identity.pluginName], warnings: [], rebuildResults: [result],
|
|
2503
|
+
targetResults: [{ target: identity, action: 'keep', state: 'completed' }],
|
|
2504
|
+
overallState: 'succeeded',
|
|
1789
2505
|
receiptTargets: [{
|
|
1790
2506
|
pluginName: identity.pluginName, pluginId: identity.pluginId,
|
|
1791
2507
|
sourceId: identity.sourceId, platform, scope: planned.resolvedScope,
|
|
@@ -1802,11 +2518,20 @@ export async function runRebuildCommand(options) {
|
|
|
1802
2518
|
marketplaceRoot: path.join(resolveAwHome(runtimeEnv), 'marketplaces', entry.source.sourceId),
|
|
1803
2519
|
};
|
|
1804
2520
|
entry.plugin.marketplaceName = marketplaceName;
|
|
2521
|
+
const reconcileDesiredCleanup = platform === 'codex'
|
|
2522
|
+
&& options.command === 'cleanup'
|
|
2523
|
+
&& desiredInCurrentScope;
|
|
1805
2524
|
const executionResult = await runSingleSourceRebuildCommand({
|
|
1806
2525
|
...options,
|
|
1807
|
-
command:
|
|
1808
|
-
?
|
|
1809
|
-
:
|
|
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,
|
|
1810
2535
|
pluginNames: [entry.plugin.manifest.name],
|
|
1811
2536
|
all: false,
|
|
1812
2537
|
commandOptions: { ...options.commandOptions, platform, scope: planned.resolvedScope },
|
|
@@ -1842,11 +2567,115 @@ export async function runRebuildCommand(options) {
|
|
|
1842
2567
|
},
|
|
1843
2568
|
},
|
|
1844
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
|
+
}
|
|
1845
2576
|
results.push(executionResult);
|
|
1846
2577
|
dependencyStates.set(`${entry.pluginId}\0${platform}`, executionResult.overallState === 'succeeded' ? 'completed' : 'failed');
|
|
1847
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
|
+
}
|
|
1848
2670
|
const merged = mergeRebuildCommandResults(results);
|
|
1849
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
|
+
}
|
|
1850
2679
|
return leaseSafeRebuildResult(merged);
|
|
1851
2680
|
},
|
|
1852
2681
|
});
|
|
@@ -1865,54 +2694,16 @@ export async function runRebuildCommand(options) {
|
|
|
1865
2694
|
const projected = error;
|
|
1866
2695
|
error = namespacedPreflightError(error instanceof Error ? error.message : String(error), projected.namespacedTargets ?? liveTargets, projected.legacyTargets ?? legacyLiveTargets);
|
|
1867
2696
|
}
|
|
1868
|
-
if (options.command !== '
|
|
2697
|
+
if (options.command !== 'uninstall')
|
|
1869
2698
|
throw error;
|
|
1870
2699
|
const message = error instanceof Error ? error.message : String(error);
|
|
1871
|
-
const catalogUnavailable =
|
|
1872
|
-
|| message.
|
|
1873
|
-
||
|
|
1874
|
-
&& (message.includes('does not exist')
|
|
1875
|
-
|| message.includes('is not configured')
|
|
1876
|
-
|| message.includes('has no Active generation')));
|
|
1877
|
-
if (options.command === 'cleanup'
|
|
1878
|
-
&& (catalogUnavailable || message.includes('sourceChanged'))
|
|
1879
|
-
&& cleanupInventory
|
|
1880
|
-
&& cleanupLiveTargets.length > 0) {
|
|
1881
|
-
if (!cleanupForce || expectedOfflineCleanup) {
|
|
1882
|
-
await assertOfflineCleanupDependents({
|
|
1883
|
-
targets: cleanupLiveTargets,
|
|
1884
|
-
cwd: options.commandOptions.cwd,
|
|
1885
|
-
env: runtimeEnv,
|
|
1886
|
-
readInventory,
|
|
1887
|
-
});
|
|
1888
|
-
}
|
|
1889
|
-
if (options.runtime?.previewDependencyPlanOnly) {
|
|
1890
|
-
return previewOfflineOwnedComponents({
|
|
1891
|
-
targets: cleanupLiveTargets,
|
|
1892
|
-
cwd: options.commandOptions.cwd,
|
|
1893
|
-
env: runtimeEnv,
|
|
1894
|
-
nativeCliRunner: options.runtime.nativeCliRunner,
|
|
1895
|
-
codexManagerPreviewer: options.runtime.codexManagerPreviewer,
|
|
1896
|
-
onPreviewStage: options.runtime.onPreviewStage,
|
|
1897
|
-
});
|
|
1898
|
-
}
|
|
1899
|
-
return cleanupOfflineOwnedComponents({
|
|
1900
|
-
targets: cleanupLiveTargets,
|
|
1901
|
-
cwd: options.commandOptions.cwd,
|
|
1902
|
-
env: runtimeEnv,
|
|
1903
|
-
force: cleanupForce && !expectedOfflineCleanup,
|
|
1904
|
-
removeObsoleteInstallationContracts: options.runtime?.removeObsoleteInstallationContracts,
|
|
1905
|
-
nativeCliRunner: options.runtime?.nativeCliRunner,
|
|
1906
|
-
codexManager: options.runtime?.codexManager,
|
|
1907
|
-
codexManagerResolver: options.runtime?.codexManagerResolver,
|
|
1908
|
-
managedCodexAuthorizer: options.runtime?.managedCodexAuthorizer,
|
|
1909
|
-
corruptExclusiveDirectoryOperations: options.runtime?.corruptExclusiveDirectoryOperations,
|
|
1910
|
-
});
|
|
1911
|
-
}
|
|
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');
|
|
1912
2703
|
if (options.command === 'uninstall' && catalogUnavailable) {
|
|
1913
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);
|
|
1914
2705
|
}
|
|
1915
|
-
if ((
|
|
2706
|
+
if (catalogGenerationErrorCode(error) === 'catalogGenerationSourceMissing'
|
|
1916
2707
|
|| message.includes('does not exist in the required catalog source set')) {
|
|
1917
2708
|
throw namespacedPreflightError(`sourceMissing: ${message} Run cleanup for owner recovery, or cleanup --force for an exclusively owned damaged target.`, liveTargets, legacyLiveTargets);
|
|
1918
2709
|
}
|