@lesliechan721/aw 0.1.0-beta.7 → 0.1.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring/scripts/add-skill.mjs +4 -4
- package/dist/authoring/scripts/add-skill.mjs.map +1 -1
- package/dist/authoring/scripts/init-plugin.mjs +8 -37
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
- package/dist/authoring/scripts/lib/skill-scaffold.d.mts +77 -90
- package/dist/authoring/scripts/lib/skill-scaffold.mjs +99 -120
- package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
- package/dist/authoring/scripts/plugin-status.mjs +8 -11
- package/dist/authoring/scripts/plugin-status.mjs.map +1 -1
- package/dist/authoring/scripts/remove-plugin.mjs +2 -1
- package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
- package/dist/authoring/scripts/validate-plugin.mjs +64 -758
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
- package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
- package/dist/scripts/{plugin-eval-materializer.js → aw-skill-eval-materializer.js} +34 -145
- package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
- package/dist/scripts/bundle-plugins.d.ts +1 -0
- package/dist/scripts/bundle-plugins.js +2 -1
- package/dist/scripts/bundle-plugins.js.map +1 -1
- package/dist/scripts/plugin-staging.d.ts +6 -8
- package/dist/scripts/plugin-staging.js +15 -28
- package/dist/scripts/plugin-staging.js.map +1 -1
- package/dist/scripts/test-plugin-scripts.js +2 -33
- package/dist/scripts/test-plugin-scripts.js.map +1 -1
- package/dist/src/adapters/helpers.js +2 -2
- package/dist/src/adapters/helpers.js.map +1 -1
- package/dist/src/authoring/workspace-commands.d.ts +17 -1
- package/dist/src/authoring/workspace-commands.js +21 -4
- package/dist/src/authoring/workspace-commands.js.map +1 -1
- package/dist/src/commands/aw-capabilities.d.ts +78 -0
- package/dist/src/commands/aw-capabilities.js +254 -0
- package/dist/src/commands/aw-capabilities.js.map +1 -0
- package/dist/src/commands/catalog-dev-source.d.ts +118 -0
- package/dist/src/commands/catalog-dev-source.js +417 -0
- package/dist/src/commands/catalog-dev-source.js.map +1 -0
- package/dist/src/commands/catalog-generation.d.ts +13 -0
- package/dist/src/commands/catalog-generation.js +13 -0
- package/dist/src/commands/catalog-generation.js.map +1 -0
- package/dist/src/commands/catalog-publication-inspection.d.ts +29 -28
- package/dist/src/commands/catalog-publication-inspection.js +138 -50
- package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
- package/dist/src/commands/catalog-publication-journal.d.ts +49 -0
- package/dist/src/commands/catalog-publication-journal.js +147 -0
- package/dist/src/commands/catalog-publication-journal.js.map +1 -0
- package/dist/src/commands/catalog-publication-target.d.ts +18 -0
- package/dist/src/commands/catalog-publication-target.js +95 -0
- package/dist/src/commands/catalog-publication-target.js.map +1 -0
- package/dist/src/commands/catalog-publish.d.ts +58 -15
- package/dist/src/commands/catalog-publish.js +590 -210
- package/dist/src/commands/catalog-publish.js.map +1 -1
- package/dist/src/commands/catalog-source.d.ts +12 -15
- package/dist/src/commands/catalog-source.js +61 -86
- package/dist/src/commands/catalog-source.js.map +1 -1
- package/dist/src/commands/catalog-status.d.ts +18 -22
- package/dist/src/commands/catalog-status.js +81 -115
- package/dist/src/commands/catalog-status.js.map +1 -1
- package/dist/src/commands/catalog-workspace-resolution.d.ts +13 -0
- package/dist/src/commands/catalog-workspace-resolution.js +42 -0
- package/dist/src/commands/catalog-workspace-resolution.js.map +1 -0
- package/dist/src/commands/dependency-operation-plan.d.ts +88 -9
- package/dist/src/commands/dependency-operation-plan.js +331 -6
- package/dist/src/commands/dependency-operation-plan.js.map +1 -1
- package/dist/src/commands/init.d.ts +5 -11
- package/dist/src/commands/init.js +30 -51
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/offline-cleanup-evidence.d.ts +43 -0
- package/dist/src/commands/offline-cleanup-evidence.js +116 -0
- package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
- package/dist/src/commands/options.d.ts +7 -1
- package/dist/src/commands/options.js +65 -6
- package/dist/src/commands/options.js.map +1 -1
- package/dist/src/commands/plugin-capabilities.js +5 -1
- package/dist/src/commands/plugin-capabilities.js.map +1 -1
- package/dist/src/commands/rebuild-command.d.ts +27 -13
- package/dist/src/commands/rebuild-command.js +1472 -471
- package/dist/src/commands/rebuild-command.js.map +1 -1
- package/dist/src/commands/rebuild-integration.d.ts +63 -8
- package/dist/src/commands/rebuild-integration.js +761 -439
- package/dist/src/commands/rebuild-integration.js.map +1 -1
- package/dist/src/commands/rebuild-operations.d.ts +2 -8
- package/dist/src/commands/rebuild-operations.js +48 -132
- package/dist/src/commands/rebuild-operations.js.map +1 -1
- package/dist/src/commands/runtime.js +21 -34
- package/dist/src/commands/runtime.js.map +1 -1
- package/dist/src/commands/skill-eval.d.ts +33 -0
- package/dist/src/commands/skill-eval.js +363 -0
- package/dist/src/commands/skill-eval.js.map +1 -0
- package/dist/src/commands/status-v6.d.ts +202 -0
- package/dist/src/commands/status-v6.js +1938 -0
- package/dist/src/commands/status-v6.js.map +1 -0
- package/dist/src/commands/sync-command.d.ts +21 -0
- package/dist/src/commands/sync-command.js +206 -0
- package/dist/src/commands/sync-command.js.map +1 -0
- package/dist/src/commands/wizard.d.ts +2 -2
- package/dist/src/commands/wizard.js +2 -2
- package/dist/src/commands/wizard.js.map +1 -1
- package/dist/src/commands/write-commands.js +33 -19
- package/dist/src/commands/write-commands.js.map +1 -1
- package/dist/src/constants.d.ts +7 -1
- package/dist/src/constants.js +7 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/eval/manifest-v1.d.ts +66 -0
- package/dist/src/eval/manifest-v1.js +326 -0
- package/dist/src/eval/manifest-v1.js.map +1 -0
- package/dist/src/generators/local-plugin.d.ts +3 -0
- package/dist/src/generators/local-plugin.js +167 -45
- package/dist/src/generators/local-plugin.js.map +1 -1
- package/dist/src/index.d.ts +6 -1
- package/dist/src/index.js +863 -126
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/command-receipt.d.ts +58 -8
- package/dist/src/output/command-receipt.js +141 -11
- package/dist/src/output/command-receipt.js.map +1 -1
- package/dist/src/output/model.d.ts +3 -44
- package/dist/src/output/model.js +1 -144
- package/dist/src/output/model.js.map +1 -1
- package/dist/src/output/rebuild-progress.js +0 -3
- package/dist/src/output/rebuild-progress.js.map +1 -1
- package/dist/src/portable/commands.d.ts +6 -2
- package/dist/src/portable/commands.js +57 -6
- package/dist/src/portable/commands.js.map +1 -1
- package/dist/src/portable/materializer.d.ts +4 -4
- package/dist/src/portable/materializer.js +61 -12
- package/dist/src/portable/materializer.js.map +1 -1
- package/dist/src/tui/catalog-generation.d.ts +35 -0
- package/dist/src/tui/catalog-generation.js +85 -0
- package/dist/src/tui/catalog-generation.js.map +1 -0
- package/dist/src/tui/components.js +1 -2
- package/dist/src/tui/components.js.map +1 -1
- package/dist/src/tui/console-app-v4.d.ts +1 -1
- package/dist/src/tui/console-app-v4.js +647 -196
- package/dist/src/tui/console-app-v4.js.map +1 -1
- package/dist/src/tui/controller-runtime.d.ts +6 -2
- package/dist/src/tui/controller-runtime.js +646 -137
- package/dist/src/tui/controller-runtime.js.map +1 -1
- package/dist/src/tui/controller.d.ts +77 -15
- package/dist/src/tui/controller.js +647 -306
- package/dist/src/tui/controller.js.map +1 -1
- package/dist/src/tui/diagnostics.d.ts +1 -2
- package/dist/src/tui/diagnostics.js.map +1 -1
- package/dist/src/tui/index.d.ts +1 -0
- package/dist/src/tui/index.js +1 -0
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/input-display.d.ts +8 -0
- package/dist/src/tui/input-display.js +36 -0
- package/dist/src/tui/input-display.js.map +1 -0
- package/dist/src/tui/model.d.ts +102 -14
- package/dist/src/tui/model.js +630 -139
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/router.d.ts +35 -0
- package/dist/src/tui/router.js.map +1 -1
- package/dist/src/tui/source-ref-presets.d.ts +3 -0
- package/dist/src/tui/source-ref-presets.js +11 -0
- package/dist/src/tui/source-ref-presets.js.map +1 -0
- package/dist/src/tui/views.js +31 -3
- package/dist/src/tui/views.js.map +1 -1
- package/dist/src/types.d.ts +104 -13
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/agent-version.d.ts +7 -1
- package/dist/src/utils/agent-version.js +41 -8
- package/dist/src/utils/agent-version.js.map +1 -1
- package/dist/src/utils/aw-home-mutation-lock.d.ts +1 -0
- package/dist/src/utils/aw-home-mutation-lock.js +32 -4
- package/dist/src/utils/aw-home-mutation-lock.js.map +1 -1
- package/dist/src/utils/bundle-integrity.d.ts +0 -1
- package/dist/src/utils/bundle-integrity.js +0 -25
- package/dist/src/utils/bundle-integrity.js.map +1 -1
- package/dist/src/utils/bundle-layout.js +8 -6
- package/dist/src/utils/bundle-layout.js.map +1 -1
- package/dist/src/utils/catalog-digests.d.ts +7 -0
- package/dist/src/utils/catalog-digests.js +40 -2
- package/dist/src/utils/catalog-digests.js.map +1 -1
- package/dist/src/utils/catalog-generation-control-snapshot.d.ts +11 -0
- package/dist/src/utils/catalog-generation-control-snapshot.js +45 -0
- package/dist/src/utils/catalog-generation-control-snapshot.js.map +1 -0
- package/dist/src/utils/catalog-generation-error.d.ts +13 -0
- package/dist/src/utils/catalog-generation-error.js +28 -0
- package/dist/src/utils/catalog-generation-error.js.map +1 -0
- package/dist/src/utils/catalog-generation-resolver.d.ts +20 -0
- package/dist/src/utils/catalog-generation-resolver.js +143 -0
- package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
- package/dist/src/utils/catalog-generation-service.d.ts +43 -0
- package/dist/src/utils/catalog-generation-service.js +306 -0
- package/dist/src/utils/catalog-generation-service.js.map +1 -0
- package/dist/src/utils/catalog-generation-state.d.ts +17 -0
- package/dist/src/utils/catalog-generation-state.js +168 -0
- package/dist/src/utils/catalog-generation-state.js.map +1 -0
- package/dist/src/utils/catalog-generation-store.d.ts +34 -0
- package/dist/src/utils/catalog-generation-store.js +251 -0
- package/dist/src/utils/catalog-generation-store.js.map +1 -0
- package/dist/src/utils/catalog-manifest-v6.d.ts +5 -0
- package/dist/src/utils/{catalog-manifest-v4.js → catalog-manifest-v6.js} +35 -43
- package/dist/src/utils/catalog-manifest-v6.js.map +1 -0
- package/dist/src/utils/catalog-operation-context.d.ts +20 -0
- package/dist/src/utils/catalog-operation-context.js +141 -0
- package/dist/src/utils/catalog-operation-context.js.map +1 -0
- package/dist/src/utils/catalog-public-error.d.ts +7 -3
- package/dist/src/utils/catalog-public-error.js +21 -8
- package/dist/src/utils/catalog-public-error.js.map +1 -1
- package/dist/src/utils/catalog-runtime-projection.d.ts +3 -0
- package/dist/src/utils/catalog-runtime-projection.js +5 -40
- package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
- package/dist/src/utils/catalog-snapshot.d.ts +5 -3
- package/dist/src/utils/catalog-snapshot.js +11 -3
- package/dist/src/utils/catalog-snapshot.js.map +1 -1
- package/dist/src/utils/catalog-source-identity.d.ts +1 -0
- package/dist/src/utils/catalog-source-identity.js +21 -2
- package/dist/src/utils/catalog-source-identity.js.map +1 -1
- package/dist/src/utils/catalog-source-references.d.ts +7 -0
- package/dist/src/utils/catalog-source-references.js +44 -55
- package/dist/src/utils/catalog-source-references.js.map +1 -1
- package/dist/src/utils/catalog-sources.d.ts +1 -0
- package/dist/src/utils/catalog-sources.js +55 -20
- package/dist/src/utils/catalog-sources.js.map +1 -1
- package/dist/src/utils/codex-config.d.ts +2 -0
- package/dist/src/utils/codex-config.js +26 -5
- package/dist/src/utils/codex-config.js.map +1 -1
- package/dist/src/utils/codex-manager.d.ts +81 -0
- package/dist/src/utils/codex-manager.js +810 -0
- package/dist/src/utils/codex-manager.js.map +1 -0
- package/dist/src/utils/codex-reconciler.d.ts +131 -0
- package/dist/src/utils/codex-reconciler.js +327 -0
- package/dist/src/utils/codex-reconciler.js.map +1 -0
- package/dist/src/utils/codex-shared-native.d.ts +56 -0
- package/dist/src/utils/codex-shared-native.js +87 -0
- package/dist/src/utils/codex-shared-native.js.map +1 -0
- package/dist/src/utils/codex-skill-staging.d.ts +2 -0
- package/dist/src/utils/codex-skill-staging.js.map +1 -1
- package/dist/src/utils/codex-surface-analysis.d.ts +44 -0
- package/dist/src/utils/codex-surface-analysis.js +247 -0
- package/dist/src/utils/codex-surface-analysis.js.map +1 -0
- package/dist/src/utils/dynamic-skill-tree.d.ts +4 -0
- package/dist/src/utils/dynamic-skill-tree.js +35 -5
- package/dist/src/utils/dynamic-skill-tree.js.map +1 -1
- package/dist/src/utils/git-catalog-provider.js +66 -140
- package/dist/src/utils/git-catalog-provider.js.map +1 -1
- package/dist/src/utils/lifecycle-active-store.d.ts +0 -28
- package/dist/src/utils/lifecycle-active-store.js +35 -247
- package/dist/src/utils/lifecycle-active-store.js.map +1 -1
- package/dist/src/utils/manifest.d.ts +1 -3
- package/dist/src/utils/manifest.js +1 -3
- package/dist/src/utils/manifest.js.map +1 -1
- package/dist/src/utils/multi-source-catalog.d.ts +3 -9
- package/dist/src/utils/multi-source-catalog.js +53 -110
- package/dist/src/utils/multi-source-catalog.js.map +1 -1
- package/dist/src/utils/native-cli.d.ts +49 -6
- package/dist/src/utils/native-cli.js +116 -33
- package/dist/src/utils/native-cli.js.map +1 -1
- package/dist/src/utils/orphan-marketplace-cleanup.js +1 -3
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
- package/dist/src/utils/ownership.d.ts +10 -11
- package/dist/src/utils/ownership.js +55 -112
- package/dist/src/utils/ownership.js.map +1 -1
- package/dist/src/utils/path-catalog-provider.d.ts +1 -1
- package/dist/src/utils/path-catalog-provider.js +52 -65
- package/dist/src/utils/path-catalog-provider.js.map +1 -1
- package/dist/src/utils/paths.d.ts +0 -1
- package/dist/src/utils/paths.js +0 -1
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/plugin-config-write.js +18 -40
- package/dist/src/utils/plugin-config-write.js.map +1 -1
- package/dist/src/utils/plugin-config.d.ts +1 -12
- package/dist/src/utils/plugin-config.js +107 -226
- package/dist/src/utils/plugin-config.js.map +1 -1
- package/dist/src/utils/plugin-intent-state.d.ts +39 -0
- package/dist/src/utils/plugin-intent-state.js +325 -0
- package/dist/src/utils/plugin-intent-state.js.map +1 -0
- package/dist/src/utils/plugin-scripts.d.ts +1 -1
- package/dist/src/utils/plugin-scripts.js +1 -1
- package/dist/src/utils/plugin-scripts.js.map +1 -1
- package/dist/src/utils/state-paths.js +7 -2
- package/dist/src/utils/state-paths.js.map +1 -1
- package/dist/src/utils/target-eligibility.d.ts +8 -2
- package/dist/src/utils/target-eligibility.js +9 -5
- package/dist/src/utils/target-eligibility.js.map +1 -1
- package/package.json +6 -4
- package/dist/authoring/scripts/check-plugin-versions.d.mts +0 -2
- package/dist/authoring/scripts/check-plugin-versions.mjs +0 -5
- package/dist/authoring/scripts/check-plugin-versions.mjs.map +0 -1
- package/dist/scripts/aw-skill-eval-engine.d.ts +0 -13
- package/dist/scripts/aw-skill-eval-engine.js +0 -31
- package/dist/scripts/aw-skill-eval-engine.js.map +0 -1
- package/dist/scripts/codex-eval-app-server.d.ts +0 -89
- package/dist/scripts/codex-eval-app-server.js +0 -1228
- package/dist/scripts/codex-eval-app-server.js.map +0 -1
- package/dist/scripts/codex-eval-isolation.d.ts +0 -61
- package/dist/scripts/codex-eval-isolation.js +0 -318
- package/dist/scripts/codex-eval-isolation.js.map +0 -1
- package/dist/scripts/codex-eval-process-management.d.ts +0 -8
- package/dist/scripts/codex-eval-process-management.js +0 -69
- package/dist/scripts/codex-eval-process-management.js.map +0 -1
- package/dist/scripts/codex-eval-process-tree.d.ts +0 -38
- package/dist/scripts/codex-eval-process-tree.js +0 -803
- package/dist/scripts/codex-eval-process-tree.js.map +0 -1
- package/dist/scripts/codex-eval-runtime-config.d.ts +0 -62
- package/dist/scripts/codex-eval-runtime-config.js +0 -843
- package/dist/scripts/codex-eval-runtime-config.js.map +0 -1
- package/dist/scripts/codex-trigger-eval.d.ts +0 -84
- package/dist/scripts/codex-trigger-eval.js +0 -968
- package/dist/scripts/codex-trigger-eval.js.map +0 -1
- package/dist/scripts/eval-plugin-skills-audited.d.ts +0 -6
- package/dist/scripts/eval-plugin-skills-audited.js +0 -261
- package/dist/scripts/eval-plugin-skills-audited.js.map +0 -1
- package/dist/scripts/eval-plugin-skills.d.ts +0 -45
- package/dist/scripts/eval-plugin-skills.js +0 -1586
- package/dist/scripts/eval-plugin-skills.js.map +0 -1
- package/dist/scripts/eval-run-layout.d.ts +0 -17
- package/dist/scripts/eval-run-layout.js +0 -26
- package/dist/scripts/eval-run-layout.js.map +0 -1
- package/dist/scripts/plugin-eval-contract.d.ts +0 -185
- package/dist/scripts/plugin-eval-contract.js +0 -695
- package/dist/scripts/plugin-eval-contract.js.map +0 -1
- package/dist/scripts/plugin-eval-materializer.d.ts +0 -13
- package/dist/scripts/plugin-eval-materializer.js.map +0 -1
- package/dist/scripts/skill-reporting.d.ts +0 -212
- package/dist/scripts/skill-reporting.js +0 -922
- package/dist/scripts/skill-reporting.js.map +0 -1
- package/dist/src/commands/status-v4.d.ts +0 -123
- package/dist/src/commands/status-v4.js +0 -905
- package/dist/src/commands/status-v4.js.map +0 -1
- package/dist/src/commands/status.d.ts +0 -93
- package/dist/src/commands/status.js +0 -442
- package/dist/src/commands/status.js.map +0 -1
- package/dist/src/utils/active-marketplace-runtime-lock.d.ts +0 -12
- package/dist/src/utils/active-marketplace-runtime-lock.js +0 -133
- package/dist/src/utils/active-marketplace-runtime-lock.js.map +0 -1
- package/dist/src/utils/catalog-manifest-v3.d.ts +0 -2
- package/dist/src/utils/catalog-manifest-v3.js +0 -3
- package/dist/src/utils/catalog-manifest-v3.js.map +0 -1
- package/dist/src/utils/catalog-manifest-v4.d.ts +0 -5
- package/dist/src/utils/catalog-manifest-v4.js.map +0 -1
- package/dist/src/utils/catalog-source-cache.d.ts +0 -62
- package/dist/src/utils/catalog-source-cache.js +0 -296
- package/dist/src/utils/catalog-source-cache.js.map +0 -1
- package/dist/src/utils/codex-project-surface.d.ts +0 -3
- package/dist/src/utils/codex-project-surface.js +0 -49
- package/dist/src/utils/codex-project-surface.js.map +0 -1
- package/dist/src/utils/plugin-release.d.ts +0 -2
- package/dist/src/utils/plugin-release.js +0 -2
- package/dist/src/utils/plugin-release.js.map +0 -1
|
@@ -1,34 +1,153 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import fs from 'fs-extra';
|
|
4
5
|
import { generateAgentArtifacts } from '../generators/agents.js';
|
|
5
|
-
import { extractCodexHookGroups } from '../generators/hooks.js';
|
|
6
6
|
import { generateInstructionArtifacts, renderCodexManagedInstructionBlock, } from '../generators/instructions.js';
|
|
7
7
|
import { generateCodexPermissionArtifacts, mergeClaudePermissions, } from '../generators/permissions.js';
|
|
8
8
|
import { buildGeneratedName } from '../generators/shared.js';
|
|
9
|
-
import { applyConditionalCodexConfigTransactionFile, applyCodexConfigTransactionFile, composeManagedDeveloperInstructionsBlock, readCodexConfigFile,
|
|
9
|
+
import { applyConditionalCodexConfigTransactionFile, applyCodexConfigTransactionFile, composeManagedDeveloperInstructionsBlock, readCodexConfigFile, } from '../utils/codex-config.js';
|
|
10
|
+
import { canonicalizePathThroughExistingAncestor } from '../utils/state-paths.js';
|
|
10
11
|
import { createCodexSkillExpectedTree, createCodexSkillStagingTreeContentDigest, } from '../utils/codex-skill-staging.js';
|
|
11
12
|
import { createDynamicSkillExpectedTree, createDynamicSkillTreeContentDigest, skillDirectoryMatchesExpectedTree, validateSkillDirectory, writeDynamicSkillTree, } from '../utils/dynamic-skill-tree.js';
|
|
12
|
-
import { parseCodexSharedHooksFile,
|
|
13
|
-
import { buildCodexMarketplaceAddInvocation, buildCodexMarketplaceListInvocation, buildCodexMarketplaceRemoveInvocation, buildCodexPluginAddInvocation, buildCodexPluginListInvocation, buildCodexPluginRemoveInvocation, runNativeCliChecked, } from '../utils/native-cli.js';
|
|
14
|
-
import { OWNED_TEXT_HEADER_PREFIX, createSharedOwnerToken,
|
|
13
|
+
import { parseCodexSharedHooksFile, serializeTrackedHookGroupIdentity, } from '../utils/hooks-contract.js';
|
|
14
|
+
import { buildCodexMarketplaceAddInvocation, buildCodexMarketplaceListInvocation, buildCodexMarketplaceRemoveInvocation, buildCodexPluginAddInvocation, buildCodexPluginListInvocation, buildCodexProjectPluginListInvocations, buildCodexPluginRemoveInvocation, postcheckCodexProjectPluginActivation, runNativeCliChecked, } from '../utils/native-cli.js';
|
|
15
|
+
import { OWNED_TEXT_HEADER_PREFIX, createSharedOwnerToken, parseSharedOwnerToken, parseOwnedTextHeader, readSkillOwnerMarker, inspectOwnedComponents, writeOwnedTextFile, } from '../utils/ownership.js';
|
|
15
16
|
import { resolveArtifactRenderConfig, runArtifactRenderer } from '../utils/artifact-renderer.js';
|
|
16
17
|
import { validateArtifactPlan } from '../utils/artifact-plan.js';
|
|
17
|
-
import { readPluginManifest } from '../utils/manifest.js';
|
|
18
|
+
import { createAwPluginRequirementsReceipt, readPluginManifest, } from '../utils/manifest.js';
|
|
18
19
|
import { resolvePlatformEntries } from '../utils/platform-entries.js';
|
|
19
20
|
import { resolveAwHome, resolveClaudePaths, resolveCodexPaths, resolveRepoRoot, getCodexHome, } from '../utils/paths.js';
|
|
20
21
|
import { runLifecycleScript } from '../utils/plugin-scripts.js';
|
|
21
|
-
import { atomicRemoveConfigFile, atomicReplaceConfigFile,
|
|
22
|
-
import { withActiveMarketplaceLifecycleLease, withActiveMarketplaceRuntimeLease, } from '../utils/active-marketplace-runtime-lock.js';
|
|
22
|
+
import { atomicRemoveConfigFile, atomicReplaceConfigFile, withConfigFileMutation, } from '../utils/plugin-config.js';
|
|
23
23
|
import { readCatalogSourcesConfigSnapshot } from '../utils/catalog-sources.js';
|
|
24
24
|
import { getNamespacedMarketplaceName, projectMarketplaceManifestForPlatform, replayNamespacedCodexSkillOverlays, } from '../utils/local-marketplace.js';
|
|
25
25
|
import { cleanupOrphanNamespacedMarketplaceRoot, commitMarketplaceGenerationBackup, } from '../utils/orphan-marketplace-cleanup.js';
|
|
26
26
|
import { readClaudeSettings, writeClaudeSettings } from '../adapters/helpers.js';
|
|
27
|
-
import {
|
|
27
|
+
import { analyzeCodexSurface } from '../utils/codex-surface-analysis.js';
|
|
28
|
+
import { inspectCodexSharedNative, } from '../utils/codex-shared-native.js';
|
|
29
|
+
import { calculateCodexSharedNativePayloadDigest } from '../utils/catalog-digests.js';
|
|
28
30
|
import { assertCanonicalProjectManagedRoots } from '../utils/project-boundary.js';
|
|
29
31
|
import { findCodexRoleNameConflict, resolveCodexRoleNamespace, } from '../utils/codex-roles.js';
|
|
30
32
|
const MARKETPLACE_NAME = 'aw';
|
|
31
|
-
const
|
|
33
|
+
const LEGACY_MCP_OWNER_ENV = 'AW_AGENT_WORKFLOWS_OWNER';
|
|
34
|
+
function requirementsReceipt(plugin) {
|
|
35
|
+
const receipt = createAwPluginRequirementsReceipt({ name: plugin.manifest.name, version: plugin.manifest.version }, plugin.manifest.requires?.aw.capabilities ?? []);
|
|
36
|
+
return Buffer.from(`${JSON.stringify(receipt, null, 2)}\n`, 'utf8');
|
|
37
|
+
}
|
|
38
|
+
function requireCodexManager(manager) {
|
|
39
|
+
if (!manager) {
|
|
40
|
+
throw new Error('codexManagerRequired: Codex native operation has no resolved manager.');
|
|
41
|
+
}
|
|
42
|
+
return manager;
|
|
43
|
+
}
|
|
44
|
+
export async function executeCodexReconcileActivations(options) {
|
|
45
|
+
const byScope = {
|
|
46
|
+
user: { upserts: {}, removals: new Set() },
|
|
47
|
+
project: { upserts: {}, removals: new Set() },
|
|
48
|
+
};
|
|
49
|
+
for (const plan of options.plans) {
|
|
50
|
+
for (const scope of ['user', 'project']) {
|
|
51
|
+
for (const action of plan.activationActions[scope]) {
|
|
52
|
+
if (action.action === 'enable' || action.action === 'disable') {
|
|
53
|
+
byScope[scope].upserts[action.codexPluginId] = action.desired;
|
|
54
|
+
byScope[scope].removals.delete(action.codexPluginId);
|
|
55
|
+
}
|
|
56
|
+
else if (action.action === 'remove') {
|
|
57
|
+
byScope[scope].removals.add(action.codexPluginId);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const removal of plan.staleActivationRemovals) {
|
|
62
|
+
if (!Object.hasOwn(byScope[removal.scope].upserts, removal.codexPluginId)) {
|
|
63
|
+
byScope[removal.scope].removals.add(removal.codexPluginId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const scope of ['user', 'project']) {
|
|
68
|
+
const enables = Object.fromEntries(Object.entries(byScope[scope].upserts)
|
|
69
|
+
.filter(([, desired]) => desired));
|
|
70
|
+
if (Object.keys(enables).length === 0)
|
|
71
|
+
continue;
|
|
72
|
+
const configPath = resolveCodexPaths(options.cwd, scope, options.env).configTomlPath;
|
|
73
|
+
await applyCodexConfigTransactionFile(configPath, { upsertPluginActivations: enables });
|
|
74
|
+
const enabledConfig = await readCodexConfigFile(configPath);
|
|
75
|
+
for (const pluginId of Object.keys(enables)) {
|
|
76
|
+
if (enabledConfig.snapshot.plugins[pluginId]?.enabled !== true) {
|
|
77
|
+
throw new Error(`codexActivationPostcheckFailed: ${pluginId} ${scope} activation was not enabled before obsolete activation removal.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const scope of ['user', 'project']) {
|
|
82
|
+
const transaction = byScope[scope];
|
|
83
|
+
const disables = Object.fromEntries(Object.entries(transaction.upserts)
|
|
84
|
+
.filter(([, desired]) => !desired));
|
|
85
|
+
if (Object.keys(disables).length === 0 && transaction.removals.size === 0)
|
|
86
|
+
continue;
|
|
87
|
+
await applyCodexConfigTransactionFile(resolveCodexPaths(options.cwd, scope, options.env).configTomlPath, {
|
|
88
|
+
...(transaction.removals.size > 0
|
|
89
|
+
? { removePluginActivations: [...transaction.removals].sort() }
|
|
90
|
+
: {}),
|
|
91
|
+
...(Object.keys(disables).length > 0
|
|
92
|
+
? { upsertPluginActivations: disables }
|
|
93
|
+
: {}),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const [userConfig, projectConfig] = await Promise.all([
|
|
97
|
+
readCodexConfigFile(resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath),
|
|
98
|
+
readCodexConfigFile(resolveCodexPaths(options.cwd, 'project', options.env).configTomlPath),
|
|
99
|
+
]);
|
|
100
|
+
for (const plan of options.plans) {
|
|
101
|
+
for (const scope of ['user', 'project']) {
|
|
102
|
+
const snapshot = scope === 'user' ? userConfig.snapshot : projectConfig.snapshot;
|
|
103
|
+
for (const action of plan.activationActions[scope]) {
|
|
104
|
+
const actual = snapshot.plugins[action.codexPluginId]?.enabled;
|
|
105
|
+
const expected = action.desired
|
|
106
|
+
? true
|
|
107
|
+
: action.action === 'disable' || actual === false ? false : undefined;
|
|
108
|
+
if (actual !== expected) {
|
|
109
|
+
throw new Error(`codexActivationPostcheckFailed: ${action.codexPluginId} ${scope} activation is ${String(actual)}; expected ${String(expected)}.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const removal of plan.staleActivationRemovals.filter((entry) => entry.scope === scope)) {
|
|
113
|
+
if (snapshot.plugins[removal.codexPluginId]?.enabled !== undefined) {
|
|
114
|
+
throw new Error(`codexActivationPostcheckFailed: stale ${removal.codexPluginId} ${scope} activation remains.`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const observedProjectChecks = options.plans.flatMap((plan) => plan.postcheck.support === 'observed'
|
|
120
|
+
? plan.postcheck.plugins.filter((plugin) => plugin.neutralCwdRequired)
|
|
121
|
+
: []);
|
|
122
|
+
if (observedProjectChecks.length === 0)
|
|
123
|
+
return;
|
|
124
|
+
const manager = requireCodexManager(options.manager);
|
|
125
|
+
const neutralCwd = await fs.mkdtemp(path.join(os.tmpdir(), 'aw-codex-postcheck-'));
|
|
126
|
+
try {
|
|
127
|
+
const invocations = buildCodexProjectPluginListInvocations(manager, {
|
|
128
|
+
exactCwd: options.cwd,
|
|
129
|
+
neutralCwd,
|
|
130
|
+
env: options.env,
|
|
131
|
+
});
|
|
132
|
+
const [exactResult, neutralResult] = await Promise.all([
|
|
133
|
+
runNativeCliChecked(invocations.exact, options.runner),
|
|
134
|
+
runNativeCliChecked(invocations.neutral, options.runner),
|
|
135
|
+
]);
|
|
136
|
+
for (const plugin of observedProjectChecks) {
|
|
137
|
+
postcheckCodexProjectPluginActivation({
|
|
138
|
+
pluginId: plugin.codexPluginId,
|
|
139
|
+
userEnabled: plugin.expectedUserEnabled,
|
|
140
|
+
projectEnabled: plugin.expectedProjectEnabled,
|
|
141
|
+
exactResult,
|
|
142
|
+
neutralResult,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await fs.remove(neutralCwd);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const CODEX_REMOVE_RECOVERY = 'Codex residue was retained. Retry cleanup or uninstall, upgrade AW, or install a compatible official Codex CLI.';
|
|
32
151
|
function ownerIdentity(plugin, artifactKey, platform, scope) {
|
|
33
152
|
return { owner: 'agent-workflows', plugin, artifactKey, platform, scope };
|
|
34
153
|
}
|
|
@@ -60,7 +179,7 @@ function pathComponent(options) {
|
|
|
60
179
|
return {
|
|
61
180
|
...options,
|
|
62
181
|
validateHealth: async () => {
|
|
63
|
-
await validateSkillDirectory(options.path, options.identity.platform === 'codex' ? 'codex.skill' : 'claude.skill', { ownerMarkerPolicy: 'ignore' });
|
|
182
|
+
await validateSkillDirectory(options.path, options.identity.platform === 'codex' ? 'codex.skill' : 'claude.skill', { ownerMarkerPolicy: 'ignore', requirementsReceiptPolicy: 'allow' });
|
|
64
183
|
},
|
|
65
184
|
};
|
|
66
185
|
}
|
|
@@ -192,84 +311,85 @@ function createCodexInstructionComponent(options) {
|
|
|
192
311
|
},
|
|
193
312
|
};
|
|
194
313
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
314
|
+
function createCodexActivationComponent(options) {
|
|
315
|
+
return {
|
|
316
|
+
kind: 'shared-config',
|
|
317
|
+
identity: options.identity,
|
|
318
|
+
label: `${options.configPath}#plugins.${options.codexPluginId}.enabled`,
|
|
319
|
+
inspect: async () => {
|
|
320
|
+
const plugin = (await readCodexConfigFile(options.configPath))
|
|
321
|
+
.snapshot.plugins[options.codexPluginId];
|
|
322
|
+
return plugin?.enabled === options.desired ? 'present' : 'absent';
|
|
323
|
+
},
|
|
324
|
+
remove: async () => {
|
|
325
|
+
await applyCodexConfigTransactionFile(options.configPath, {
|
|
326
|
+
removePluginActivations: [options.codexPluginId],
|
|
327
|
+
});
|
|
328
|
+
},
|
|
329
|
+
};
|
|
203
330
|
}
|
|
204
|
-
function
|
|
205
|
-
const ownerKey = createSharedOwnerToken(options.identity);
|
|
331
|
+
function createCodexActivationCleanupComponent(options) {
|
|
206
332
|
return {
|
|
207
333
|
kind: 'shared-config',
|
|
208
334
|
identity: options.identity,
|
|
209
|
-
label: `${options.configPath}#
|
|
335
|
+
label: `${options.configPath}#plugins.${options.codexPluginId}.enabled`,
|
|
210
336
|
inspect: async () => {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
337
|
+
const actual = (await readCodexConfigFile(options.configPath))
|
|
338
|
+
.snapshot.plugins[options.codexPluginId]?.enabled;
|
|
339
|
+
return options.disposition === 'remove'
|
|
340
|
+
? actual === undefined ? 'absent' : 'present'
|
|
341
|
+
: actual === true ? 'present' : 'absent';
|
|
216
342
|
},
|
|
217
343
|
remove: async () => {
|
|
218
344
|
await applyConditionalCodexConfigTransactionFile(options.configPath, (snapshot) => {
|
|
219
|
-
const actual = snapshot.
|
|
220
|
-
|
|
221
|
-
|
|
345
|
+
const actual = snapshot.plugins[options.codexPluginId]?.enabled;
|
|
346
|
+
if (options.disposition === 'remove') {
|
|
347
|
+
return actual === undefined
|
|
348
|
+
? null
|
|
349
|
+
: { removePluginActivations: [options.codexPluginId] };
|
|
350
|
+
}
|
|
351
|
+
return actual === true
|
|
352
|
+
? { upsertPluginActivations: { [options.codexPluginId]: false } }
|
|
222
353
|
: null;
|
|
223
354
|
});
|
|
224
355
|
},
|
|
225
356
|
};
|
|
226
357
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
return Boolean(parseOwnedTextHeader(raw, options.fileIdentity));
|
|
237
|
-
}
|
|
238
|
-
catch {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
358
|
+
function legacyCodexMcpOwner(actual) {
|
|
359
|
+
const envValue = actual?.value?.env;
|
|
360
|
+
return envValue
|
|
361
|
+
&& typeof envValue === 'object'
|
|
362
|
+
&& !Array.isArray(envValue)
|
|
363
|
+
&& typeof envValue[LEGACY_MCP_OWNER_ENV] === 'string'
|
|
364
|
+
? envValue[LEGACY_MCP_OWNER_ENV]
|
|
365
|
+
: null;
|
|
241
366
|
}
|
|
242
|
-
function
|
|
243
|
-
const
|
|
244
|
-
const config = await readCodexConfigFile(options.configPath);
|
|
245
|
-
const registration = config.snapshot.agents[options.roleKey];
|
|
246
|
-
if (!registration)
|
|
247
|
-
return 'absent';
|
|
248
|
-
return await codexRoleRegistrationOwned({ ...options, registration })
|
|
249
|
-
? 'present'
|
|
250
|
-
: 'foreign';
|
|
251
|
-
};
|
|
367
|
+
function createLegacyCodexMcpCleanupComponent(options) {
|
|
368
|
+
const ownerKey = createSharedOwnerToken(options.identity);
|
|
252
369
|
return {
|
|
253
370
|
kind: 'shared-config',
|
|
254
371
|
identity: options.identity,
|
|
255
|
-
label: `${options.configPath}#
|
|
256
|
-
inspect
|
|
372
|
+
label: `${options.configPath}#mcp_servers.${options.serverKey}`,
|
|
373
|
+
inspect: async () => {
|
|
374
|
+
const actual = (await readCodexConfigFile(options.configPath))
|
|
375
|
+
.snapshot.mcpServers[options.serverKey];
|
|
376
|
+
if (!actual)
|
|
377
|
+
return 'absent';
|
|
378
|
+
return legacyCodexMcpOwner(actual) === ownerKey ? 'present' : 'foreign';
|
|
379
|
+
},
|
|
257
380
|
remove: async () => {
|
|
258
|
-
await applyConditionalCodexConfigTransactionFile(options.configPath,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
? { removeAgentRegistrations: [options.roleKey] }
|
|
262
|
-
: null;
|
|
263
|
-
});
|
|
381
|
+
await applyConditionalCodexConfigTransactionFile(options.configPath, (snapshot) => legacyCodexMcpOwner(snapshot.mcpServers[options.serverKey]) === ownerKey
|
|
382
|
+
? { removeMcpServers: [options.serverKey] }
|
|
383
|
+
: null);
|
|
264
384
|
},
|
|
265
385
|
};
|
|
266
386
|
}
|
|
267
|
-
async function
|
|
387
|
+
async function readLegacyCodexHooks(hooksPath) {
|
|
268
388
|
if (!await fs.pathExists(hooksPath))
|
|
269
389
|
return parseCodexSharedHooksFile({ hooks: {} });
|
|
270
390
|
return parseCodexSharedHooksFile(await fs.readJson(hooksPath));
|
|
271
391
|
}
|
|
272
|
-
function
|
|
392
|
+
function renderLegacyCodexHookGroups(groups) {
|
|
273
393
|
const hooks = {};
|
|
274
394
|
for (const group of groups) {
|
|
275
395
|
hooks[group.event] ??= [];
|
|
@@ -277,16 +397,15 @@ function renderCodexHookGroups(groups) {
|
|
|
277
397
|
}
|
|
278
398
|
return `${JSON.stringify({ hooks }, null, 2)}\n`;
|
|
279
399
|
}
|
|
280
|
-
|
|
281
|
-
return
|
|
400
|
+
async function applyLegacyCodexHookCleanupTransactionFile(hooksPath, update) {
|
|
401
|
+
return withConfigFileMutation({
|
|
282
402
|
filePath: hooksPath,
|
|
283
403
|
allowedRoot: path.dirname(hooksPath),
|
|
284
404
|
action: async () => {
|
|
285
|
-
const parsed = await
|
|
405
|
+
const parsed = await readLegacyCodexHooks(hooksPath);
|
|
286
406
|
const groups = update(parsed);
|
|
287
407
|
if (!groups)
|
|
288
408
|
return false;
|
|
289
|
-
await testHooks?.beforeCommit?.();
|
|
290
409
|
if (groups.length === 0) {
|
|
291
410
|
await atomicRemoveConfigFile({
|
|
292
411
|
filePath: hooksPath,
|
|
@@ -297,40 +416,27 @@ export async function applyCodexHookGroupsTransactionFile(hooksPath, update, tes
|
|
|
297
416
|
await atomicReplaceConfigFile({
|
|
298
417
|
filePath: hooksPath,
|
|
299
418
|
allowedRoot: path.dirname(hooksPath),
|
|
300
|
-
content:
|
|
419
|
+
content: renderLegacyCodexHookGroups(groups),
|
|
301
420
|
});
|
|
302
421
|
}
|
|
303
422
|
return true;
|
|
304
423
|
},
|
|
305
424
|
});
|
|
306
425
|
}
|
|
307
|
-
function
|
|
308
|
-
const rendered = renderTrackedHookGroupIdentity(identity);
|
|
309
|
-
const rawGroup = {
|
|
310
|
-
...(rendered.matcher === undefined ? {} : { matcher: rendered.matcher }),
|
|
311
|
-
hooks: rendered.hooks,
|
|
312
|
-
};
|
|
313
|
-
return {
|
|
314
|
-
event: rendered.event,
|
|
315
|
-
matcher: rendered.matcher,
|
|
316
|
-
hooks: rendered.hooks,
|
|
317
|
-
rawGroup,
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function createCodexHookComponent(options) {
|
|
426
|
+
function createLegacyCodexHookCleanupComponent(options) {
|
|
321
427
|
const serialized = serializeTrackedHookGroupIdentity(options.identity);
|
|
322
428
|
return {
|
|
323
429
|
kind: 'shared-config',
|
|
324
430
|
identity: ownerIdentity(options.pluginName, internalArtifactKey('hook', serialized), 'codex', options.scope),
|
|
325
431
|
label: `${options.hooksPath}#${serialized}`,
|
|
326
432
|
inspect: async () => {
|
|
327
|
-
const parsed = await
|
|
433
|
+
const parsed = await readLegacyCodexHooks(options.hooksPath);
|
|
328
434
|
return parsed.managedIdentities.some((entry) => serializeTrackedHookGroupIdentity(entry) === serialized)
|
|
329
435
|
? 'present'
|
|
330
436
|
: 'absent';
|
|
331
437
|
},
|
|
332
438
|
remove: async () => {
|
|
333
|
-
await
|
|
439
|
+
await applyLegacyCodexHookCleanupTransactionFile(options.hooksPath, (parsed) => {
|
|
334
440
|
let removed = false;
|
|
335
441
|
const remaining = parsed.groups.flatMap((entry) => {
|
|
336
442
|
if (!removed
|
|
@@ -346,19 +452,44 @@ function createCodexHookComponent(options) {
|
|
|
346
452
|
},
|
|
347
453
|
};
|
|
348
454
|
}
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
455
|
+
async function codexRoleRegistrationOwned(options) {
|
|
456
|
+
if (!options.registration?.configFile)
|
|
457
|
+
return false;
|
|
458
|
+
const expected = path.normalize(path.relative(path.dirname(options.configPath), options.rolePath));
|
|
459
|
+
const actual = path.normalize(path.relative(path.dirname(options.configPath), path.resolve(path.dirname(options.configPath), options.registration.configFile)));
|
|
460
|
+
if (actual !== expected)
|
|
461
|
+
return false;
|
|
462
|
+
const raw = await fs.readFile(options.rolePath, 'utf8').catch(() => '');
|
|
463
|
+
try {
|
|
464
|
+
return Boolean(parseOwnedTextHeader(raw, options.fileIdentity));
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function createCodexRoleRegistrationComponent(options) {
|
|
471
|
+
const inspect = async () => {
|
|
472
|
+
const config = await readCodexConfigFile(options.configPath);
|
|
473
|
+
const registration = config.snapshot.agents[options.roleKey];
|
|
474
|
+
if (!registration)
|
|
475
|
+
return 'absent';
|
|
476
|
+
return await codexRoleRegistrationOwned({ ...options, registration })
|
|
477
|
+
? 'present'
|
|
478
|
+
: 'foreign';
|
|
358
479
|
};
|
|
359
480
|
return {
|
|
360
|
-
|
|
361
|
-
|
|
481
|
+
kind: 'shared-config',
|
|
482
|
+
identity: options.identity,
|
|
483
|
+
label: `${options.configPath}#agents.${options.roleKey}`,
|
|
484
|
+
inspect,
|
|
485
|
+
remove: async () => {
|
|
486
|
+
await applyConditionalCodexConfigTransactionFile(options.configPath, async (snapshot) => {
|
|
487
|
+
const registration = snapshot.agents[options.roleKey];
|
|
488
|
+
return await codexRoleRegistrationOwned({ ...options, registration })
|
|
489
|
+
? { removeAgentRegistrations: [options.roleKey] }
|
|
490
|
+
: null;
|
|
491
|
+
});
|
|
492
|
+
},
|
|
362
493
|
};
|
|
363
494
|
}
|
|
364
495
|
function sameOwnerIdentity(left, right) {
|
|
@@ -371,17 +502,6 @@ function sameOwnerIdentity(left, right) {
|
|
|
371
502
|
&& left.platform === right.platform
|
|
372
503
|
&& left.scope === right.scope;
|
|
373
504
|
}
|
|
374
|
-
function readOwnedHookIdentity(identity, scope) {
|
|
375
|
-
try {
|
|
376
|
-
const parsed = parseOwnedTextHeader(identity.command);
|
|
377
|
-
return parsed?.identity.platform === 'codex' && parsed.identity.scope === scope
|
|
378
|
-
? parsed.identity
|
|
379
|
-
: null;
|
|
380
|
-
}
|
|
381
|
-
catch {
|
|
382
|
-
return null;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
505
|
function sharedOwnerPluginName(value) {
|
|
386
506
|
return parseSharedOwnerToken(value)?.plugin ?? value;
|
|
387
507
|
}
|
|
@@ -405,7 +525,6 @@ async function scanCodexSharedComponents(options) {
|
|
|
405
525
|
remove: async () => undefined,
|
|
406
526
|
});
|
|
407
527
|
const containsOwnedEvidence = (raw) => raw.includes(options.pluginName) && (raw.includes('[[aw-managed:start plugin=')
|
|
408
|
-
|| raw.includes(MCP_OWNER_ENV)
|
|
409
528
|
|| raw.includes(OWNED_TEXT_HEADER_PREFIX)
|
|
410
529
|
|| raw.includes('agent-workflows'));
|
|
411
530
|
if (options.scanConfig) {
|
|
@@ -427,24 +546,6 @@ async function scanCodexSharedComponents(options) {
|
|
|
427
546
|
configPath: options.paths.configTomlPath,
|
|
428
547
|
}));
|
|
429
548
|
}
|
|
430
|
-
for (const [serverKey, server] of Object.entries(config?.snapshot.mcpServers ?? {})) {
|
|
431
|
-
const envValue = server.value?.env;
|
|
432
|
-
if (envValue
|
|
433
|
-
&& typeof envValue === 'object'
|
|
434
|
-
&& !Array.isArray(envValue)
|
|
435
|
-
&& parseSharedOwnerToken(String(envValue[MCP_OWNER_ENV]))?.pluginId === options.pluginId) {
|
|
436
|
-
const identity = expectedIdentity(internalArtifactKey('mcp', serverKey));
|
|
437
|
-
if (createSharedOwnerToken(identity) !== envValue[MCP_OWNER_ENV])
|
|
438
|
-
continue;
|
|
439
|
-
output.push(createCodexMcpComponent({
|
|
440
|
-
identity,
|
|
441
|
-
scope: options.scope,
|
|
442
|
-
configPath: options.paths.configTomlPath,
|
|
443
|
-
serverKey,
|
|
444
|
-
owned: true,
|
|
445
|
-
}));
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
549
|
for (const [roleKey, registration] of Object.entries(config?.snapshot.agents ?? {})) {
|
|
449
550
|
if (!registration.configFile)
|
|
450
551
|
continue;
|
|
@@ -469,28 +570,6 @@ async function scanCodexSharedComponents(options) {
|
|
|
469
570
|
}));
|
|
470
571
|
}
|
|
471
572
|
}
|
|
472
|
-
if (options.scope === 'project' && options.scanHooks) {
|
|
473
|
-
const hooks = await readCodexHooks(options.paths.hooksPath).catch(async (error) => {
|
|
474
|
-
if (!options.ignoreReadErrors)
|
|
475
|
-
throw error;
|
|
476
|
-
const raw = await fs.readFile(options.paths.hooksPath, 'utf8').catch(() => '');
|
|
477
|
-
if (containsOwnedEvidence(raw)) {
|
|
478
|
-
output.push(corruptedComponent(options.paths.hooksPath, error));
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
481
|
-
});
|
|
482
|
-
for (const identity of hooks?.managedIdentities ?? []) {
|
|
483
|
-
const parsedIdentity = readOwnedHookIdentity(identity, options.scope);
|
|
484
|
-
if (!parsedIdentity || !sameOwnerIdentity(parsedIdentity, expectedIdentity(parsedIdentity.artifactKey)))
|
|
485
|
-
continue;
|
|
486
|
-
output.push(createCodexHookComponent({
|
|
487
|
-
pluginName: options.pluginName,
|
|
488
|
-
scope: options.scope,
|
|
489
|
-
hooksPath: options.paths.hooksPath,
|
|
490
|
-
identity,
|
|
491
|
-
}));
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
573
|
return output;
|
|
495
574
|
}
|
|
496
575
|
async function scanClaudeSharedComponents(options) {
|
|
@@ -536,6 +615,8 @@ async function scanOwnedTextFiles(options) {
|
|
|
536
615
|
}
|
|
537
616
|
if (parsed?.identity.plugin !== options.pluginName
|
|
538
617
|
|| (options.sourceId !== undefined && parsed.identity.sourceId !== options.sourceId)
|
|
618
|
+
|| (options.sourceIdentity !== undefined
|
|
619
|
+
&& parsed.identity.sourceIdentity !== options.sourceIdentity)
|
|
539
620
|
|| parsed.identity.platform !== options.platform
|
|
540
621
|
|| parsed.identity.scope !== options.scope)
|
|
541
622
|
continue;
|
|
@@ -566,6 +647,7 @@ async function scanOwnedSkills(options) {
|
|
|
566
647
|
}).catch(() => null);
|
|
567
648
|
if (marker?.plugin === options.pluginName
|
|
568
649
|
&& (options.sourceId === undefined || marker.sourceId === options.sourceId)
|
|
650
|
+
&& (options.sourceIdentity === undefined || marker.sourceIdentity === options.sourceIdentity)
|
|
569
651
|
&& marker.platform === options.platform
|
|
570
652
|
&& marker.scope === options.scope) {
|
|
571
653
|
output.push(pathComponent({
|
|
@@ -602,14 +684,19 @@ async function preflightCodexWriteSafety(options) {
|
|
|
602
684
|
const pluginName = options.plugin.manifest.name;
|
|
603
685
|
const userConfigPath = resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath;
|
|
604
686
|
const projectConfigPath = resolveCodexPaths(options.cwd, 'project', options.env).configTomlPath;
|
|
687
|
+
const nativeSurface = analyzeCodexSurface(options.plugin.manifest).nativeKinds.length > 0;
|
|
688
|
+
const needsUserConfig = options.scope === 'user'
|
|
689
|
+
|| nativeSurface;
|
|
605
690
|
let userConfig;
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
691
|
+
if (needsUserConfig) {
|
|
692
|
+
try {
|
|
693
|
+
userConfig = await readCodexConfigFile(userConfigPath);
|
|
694
|
+
}
|
|
695
|
+
catch (error) {
|
|
696
|
+
throw new Error(`codexProjectUserConfigUnreadable: 无法解析用户级 Codex 配置 ${userConfigPath}:${error instanceof Error ? error.message : String(error)}`);
|
|
697
|
+
}
|
|
611
698
|
}
|
|
612
|
-
if (options.scope === 'project') {
|
|
699
|
+
if (options.scope === 'project' && userConfig) {
|
|
613
700
|
const expectedPluginId = `${pluginName}@${options.plugin.marketplaceName ?? MARKETPLACE_NAME}`;
|
|
614
701
|
for (const [key, plugin] of Object.entries(userConfig.snapshot.plugins)) {
|
|
615
702
|
if (key !== expectedPluginId
|
|
@@ -624,7 +711,7 @@ async function preflightCodexWriteSafety(options) {
|
|
|
624
711
|
&& target.target === 'codex.agentRole'
|
|
625
712
|
&& target.roleKey)
|
|
626
713
|
.map((target) => target.roleKey));
|
|
627
|
-
const needsProjectConfig = options.scope === 'project' && Boolean(
|
|
714
|
+
const needsProjectConfig = options.scope === 'project' && Boolean(nativeSurface
|
|
628
715
|
|| resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'codex').length > 0
|
|
629
716
|
|| (options.plugin.manifest.artifacts?.targets ?? []).some((target) => target.platform === 'codex'
|
|
630
717
|
&& target.scopes.includes('project')
|
|
@@ -641,7 +728,7 @@ async function preflightCodexWriteSafety(options) {
|
|
|
641
728
|
if (roleKeys.size === 0)
|
|
642
729
|
return;
|
|
643
730
|
for (const configPath of options.scope === 'project'
|
|
644
|
-
? [
|
|
731
|
+
? [projectConfigPath]
|
|
645
732
|
: [userConfigPath]) {
|
|
646
733
|
const configScope = configPath === userConfigPath ? 'user' : 'project';
|
|
647
734
|
const ownedRolePaths = [];
|
|
@@ -692,33 +779,6 @@ function renderCodexRole(options) {
|
|
|
692
779
|
'',
|
|
693
780
|
].join('\n');
|
|
694
781
|
}
|
|
695
|
-
async function resolveCodexMcpServers(plugin, scope) {
|
|
696
|
-
if (!plugin.manifest.mcpServers)
|
|
697
|
-
return {};
|
|
698
|
-
const relative = plugin.manifest.mcpServers.replace(/^\.\//u, '');
|
|
699
|
-
const direct = path.resolve(plugin.rootDir, relative);
|
|
700
|
-
const mcpPath = await fs.pathExists(direct)
|
|
701
|
-
? direct
|
|
702
|
-
: path.resolve(plugin.rootDir, 'codex', relative);
|
|
703
|
-
const servers = await readRenderedCodexMcpServersFile(mcpPath);
|
|
704
|
-
return Object.fromEntries(Object.entries(servers).map(([key, server]) => {
|
|
705
|
-
const existingEnv = server.env;
|
|
706
|
-
if (existingEnv !== undefined && (typeof existingEnv !== 'object' || Array.isArray(existingEnv))) {
|
|
707
|
-
throw new Error(`MCP server ${key} 的 env 必须是 object。`);
|
|
708
|
-
}
|
|
709
|
-
const env = (existingEnv ?? {});
|
|
710
|
-
const ownerKey = createSharedOwnerToken(pluginOwnerIdentity(plugin, internalArtifactKey('mcp', key), 'codex', scope));
|
|
711
|
-
if (env[MCP_OWNER_ENV] !== undefined
|
|
712
|
-
&& env[MCP_OWNER_ENV] !== plugin.manifest.name
|
|
713
|
-
&& env[MCP_OWNER_ENV] !== ownerKey) {
|
|
714
|
-
throw new Error(`MCP server ${key} 不能覆盖保留的 ${MCP_OWNER_ENV} owner marker。`);
|
|
715
|
-
}
|
|
716
|
-
return [key, {
|
|
717
|
-
...server,
|
|
718
|
-
env: { ...env, [MCP_OWNER_ENV]: ownerKey },
|
|
719
|
-
}];
|
|
720
|
-
}));
|
|
721
|
-
}
|
|
722
782
|
async function resolveDynamicArtifacts(options) {
|
|
723
783
|
const declarations = (options.plugin.manifest.artifacts?.targets ?? []).filter((target) => target.platform === options.platform && target.scopes.includes(options.scope));
|
|
724
784
|
if (declarations.length === 0)
|
|
@@ -832,9 +892,7 @@ async function buildBundledCodexSkillWrites(options) {
|
|
|
832
892
|
const dynamicKeys = new Set((options.plugin.manifest.artifacts?.targets ?? [])
|
|
833
893
|
.filter((target) => target.target === 'codex.skill' && target.skillKey)
|
|
834
894
|
.map((target) => target.skillKey));
|
|
835
|
-
const targetRoot = options.
|
|
836
|
-
? path.join(options.repoRoot, '.agents', 'skills')
|
|
837
|
-
: path.join(options.marketplaceRoot ?? resolveAwHome(options.env), 'plugins', options.plugin.manifest.name, ...relativeRoot.split('/'));
|
|
895
|
+
const targetRoot = await canonicalizePathThroughExistingAncestor(path.join(options.marketplaceRoot ?? resolveAwHome(options.env), 'plugins', options.plugin.manifest.name, ...relativeRoot.split('/')));
|
|
838
896
|
const writes = [];
|
|
839
897
|
for (const entry of await fs.readdir(sourceRoot, { withFileTypes: true })) {
|
|
840
898
|
if (entry.isSymbolicLink()) {
|
|
@@ -853,11 +911,12 @@ async function buildBundledCodexSkillWrites(options) {
|
|
|
853
911
|
content: { files: {} },
|
|
854
912
|
},
|
|
855
913
|
sourceDirs: [skillSource],
|
|
914
|
+
sourceRequirementsReceiptPolicy: 'allow',
|
|
856
915
|
});
|
|
857
916
|
const skillPath = path.join(targetRoot, entry.name);
|
|
858
|
-
const canRecoverPristine =
|
|
859
|
-
|
|
860
|
-
const identity = ownerIdentity(options.plugin.manifest.name, entry.name, 'codex',
|
|
917
|
+
const canRecoverPristine = await canonicalizePathThroughExistingAncestor(skillSource)
|
|
918
|
+
!== path.resolve(skillPath);
|
|
919
|
+
const identity = ownerIdentity(options.plugin.manifest.name, entry.name, 'codex', 'user');
|
|
861
920
|
const component = pathComponent({
|
|
862
921
|
kind: 'skill-directory',
|
|
863
922
|
path: skillPath,
|
|
@@ -903,6 +962,8 @@ async function buildClaudeWrites(options) {
|
|
|
903
962
|
artifact,
|
|
904
963
|
sourceDirs: dynamic.sourceDirs(artifact),
|
|
905
964
|
requireReadme: true,
|
|
965
|
+
requirementsReceipt: requirementsReceipt(options.plugin),
|
|
966
|
+
sourceRequirementsReceiptPolicy: 'allow',
|
|
906
967
|
});
|
|
907
968
|
writes.push(dynamicSkillWrite({
|
|
908
969
|
...options,
|
|
@@ -955,22 +1016,23 @@ async function buildCodexWrites(options) {
|
|
|
955
1016
|
const dynamicRoles = dynamic.artifacts.filter((entry) => entry.target === 'codex.agentRole');
|
|
956
1017
|
const dynamicSkills = dynamic.artifacts.filter((entry) => entry.target === 'codex.skill');
|
|
957
1018
|
const repoRoot = await resolveRepoRoot(options.cwd);
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
}
|
|
965
|
-
const relativeSkillsRoot = await resolveCodexSkillsRelativeRoot(options.plugin);
|
|
1019
|
+
if (options.scope === 'user') {
|
|
1020
|
+
writes.push(...await buildBundledCodexSkillWrites({
|
|
1021
|
+
plugin: options.plugin,
|
|
1022
|
+
env: options.env,
|
|
1023
|
+
marketplaceRoot: options.marketplaceRoot,
|
|
1024
|
+
}));
|
|
1025
|
+
}
|
|
966
1026
|
const skillRoot = options.scope === 'user'
|
|
967
|
-
? path.join(
|
|
1027
|
+
? path.join(getCodexHome(options.env), 'skills')
|
|
968
1028
|
: path.join(repoRoot, '.agents', 'skills');
|
|
969
1029
|
for (const artifact of dynamicSkills) {
|
|
970
1030
|
const tree = await createCodexSkillExpectedTree({
|
|
971
1031
|
artifact,
|
|
972
1032
|
sourceDirs: dynamic.sourceDirs(artifact),
|
|
973
1033
|
requireReadme: true,
|
|
1034
|
+
requirementsReceipt: requirementsReceipt(options.plugin),
|
|
1035
|
+
sourceRequirementsReceiptPolicy: 'allow',
|
|
974
1036
|
});
|
|
975
1037
|
writes.push(dynamicSkillWrite({
|
|
976
1038
|
...options,
|
|
@@ -984,7 +1046,6 @@ async function buildCodexWrites(options) {
|
|
|
984
1046
|
const staticInstructions = dynamicInstructions.length > 0
|
|
985
1047
|
? []
|
|
986
1048
|
: resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'codex');
|
|
987
|
-
const mcpServers = await resolveCodexMcpServers(options.plugin, options.scope);
|
|
988
1049
|
const hasInstructionOutput = dynamicInstructions.length > 0 || staticInstructions.length > 0;
|
|
989
1050
|
if (hasInstructionOutput) {
|
|
990
1051
|
const component = createCodexInstructionComponent({
|
|
@@ -1034,34 +1095,6 @@ async function buildCodexWrites(options) {
|
|
|
1034
1095
|
});
|
|
1035
1096
|
}
|
|
1036
1097
|
}
|
|
1037
|
-
for (const [serverKey, server] of Object.entries(mcpServers)) {
|
|
1038
|
-
const component = createCodexMcpComponent({
|
|
1039
|
-
identity: pluginOwnerIdentity(options.plugin, internalArtifactKey('mcp', serverKey), 'codex', options.scope),
|
|
1040
|
-
scope: options.scope,
|
|
1041
|
-
configPath: paths.configTomlPath,
|
|
1042
|
-
serverKey,
|
|
1043
|
-
owned: false,
|
|
1044
|
-
});
|
|
1045
|
-
writes.push({
|
|
1046
|
-
artifact: {
|
|
1047
|
-
path: paths.configTomlPath,
|
|
1048
|
-
kind: 'mcpServer',
|
|
1049
|
-
platform: 'codex',
|
|
1050
|
-
artifactKey: serverKey,
|
|
1051
|
-
},
|
|
1052
|
-
component,
|
|
1053
|
-
write: async () => {
|
|
1054
|
-
await applyConditionalCodexConfigTransactionFile(paths.configTomlPath, (snapshot) => {
|
|
1055
|
-
const actual = snapshot.mcpServers[serverKey];
|
|
1056
|
-
const actualOwner = codexMcpOwner(actual);
|
|
1057
|
-
if (actual && actualOwner !== createSharedOwnerToken(component.identity)) {
|
|
1058
|
-
throw new Error(`Codex MCP server "${serverKey}" is foreign and cannot be overwritten by plugin "${options.plugin.manifest.name}".`);
|
|
1059
|
-
}
|
|
1060
|
-
return { upsertMcpServers: { [serverKey]: server } };
|
|
1061
|
-
});
|
|
1062
|
-
},
|
|
1063
|
-
});
|
|
1064
|
-
}
|
|
1065
1098
|
for (const artifact of dynamicRoles) {
|
|
1066
1099
|
const roleKey = artifact.roleKey;
|
|
1067
1100
|
const rolePath = path.join(paths.configDir, 'agents', `${buildGeneratedName(options.plugin.manifest.name, roleKey)}.toml`);
|
|
@@ -1161,42 +1194,40 @@ async function buildCodexWrites(options) {
|
|
|
1161
1194
|
kind: 'agent',
|
|
1162
1195
|
}));
|
|
1163
1196
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1197
|
+
const codexPluginId = `${options.plugin.manifest.name}@${options.marketplaceName ?? options.plugin.marketplaceName ?? MARKETPLACE_NAME}`;
|
|
1198
|
+
const nativeSurface = analyzeCodexSurface(options.plugin.manifest).nativeKinds.length > 0;
|
|
1199
|
+
const userActivationDesired = options.scope === 'user'
|
|
1200
|
+
|| options.userActivationDesired?.has(codexPluginId) === true;
|
|
1201
|
+
for (const activation of !nativeSurface ? [] : options.scope === 'project'
|
|
1202
|
+
? [
|
|
1203
|
+
{
|
|
1204
|
+
scope: 'user',
|
|
1205
|
+
desired: userActivationDesired,
|
|
1206
|
+
configPath: resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath,
|
|
1207
|
+
},
|
|
1208
|
+
{ scope: 'project', desired: true, configPath: paths.configTomlPath },
|
|
1209
|
+
]
|
|
1210
|
+
: [{ scope: 'user', desired: true, configPath: paths.configTomlPath }]) {
|
|
1211
|
+
const component = createCodexActivationComponent({
|
|
1212
|
+
identity: pluginOwnerIdentity(options.plugin, internalArtifactKey('activation', activation.scope), 'codex', options.scope),
|
|
1213
|
+
configPath: activation.configPath,
|
|
1214
|
+
codexPluginId,
|
|
1215
|
+
desired: activation.desired,
|
|
1216
|
+
});
|
|
1217
|
+
writes.push({
|
|
1218
|
+
artifact: {
|
|
1219
|
+
path: activation.configPath,
|
|
1220
|
+
kind: 'instruction',
|
|
1221
|
+
platform: 'codex',
|
|
1222
|
+
artifactKey: internalArtifactKey('activation', activation.scope),
|
|
1223
|
+
},
|
|
1224
|
+
component,
|
|
1225
|
+
write: async () => {
|
|
1226
|
+
await applyCodexConfigTransactionFile(activation.configPath, {
|
|
1227
|
+
upsertPluginActivations: { [codexPluginId]: activation.desired },
|
|
1228
|
+
});
|
|
1229
|
+
},
|
|
1230
|
+
});
|
|
1200
1231
|
}
|
|
1201
1232
|
return writes;
|
|
1202
1233
|
}
|
|
@@ -1260,13 +1291,13 @@ async function buildInspectionWrites(options) {
|
|
|
1260
1291
|
}
|
|
1261
1292
|
const paths = resolveCodexPaths(options.cwd, options.scope, options.env);
|
|
1262
1293
|
const repoRoot = await resolveRepoRoot(options.cwd);
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
}
|
|
1294
|
+
if (options.scope === 'user') {
|
|
1295
|
+
writes.push(...await buildBundledCodexSkillWrites({
|
|
1296
|
+
plugin: options.plugin,
|
|
1297
|
+
env: options.env,
|
|
1298
|
+
marketplaceRoot: options.marketplaceRoot,
|
|
1299
|
+
}));
|
|
1300
|
+
}
|
|
1270
1301
|
const instructions = resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'codex');
|
|
1271
1302
|
const targets = (options.plugin.manifest.artifacts?.targets ?? []).filter((target) => target.platform === 'codex' && target.scopes.includes(options.scope));
|
|
1272
1303
|
const instructionTargets = targets.filter((target) => target.target === 'codex.developerInstructionsBlock');
|
|
@@ -1286,28 +1317,8 @@ async function buildInspectionWrites(options) {
|
|
|
1286
1317
|
write: async () => undefined,
|
|
1287
1318
|
});
|
|
1288
1319
|
}
|
|
1289
|
-
const mcpServers = await resolveCodexMcpServers(options.plugin, options.scope);
|
|
1290
|
-
for (const serverKey of Object.keys(mcpServers)) {
|
|
1291
|
-
writes.push({
|
|
1292
|
-
artifact: {
|
|
1293
|
-
path: paths.configTomlPath,
|
|
1294
|
-
kind: 'mcpServer',
|
|
1295
|
-
platform: 'codex',
|
|
1296
|
-
artifactKey: serverKey,
|
|
1297
|
-
},
|
|
1298
|
-
component: createCodexMcpComponent({
|
|
1299
|
-
identity: pluginOwnerIdentity(options.plugin, internalArtifactKey('mcp', serverKey), 'codex', options.scope),
|
|
1300
|
-
scope: options.scope,
|
|
1301
|
-
configPath: paths.configTomlPath,
|
|
1302
|
-
serverKey,
|
|
1303
|
-
owned: false,
|
|
1304
|
-
}),
|
|
1305
|
-
write: async () => undefined,
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1308
|
-
const relativeSkillsRoot = await resolveCodexSkillsRelativeRoot(options.plugin);
|
|
1309
1320
|
const dynamicSkillRoot = options.scope === 'user'
|
|
1310
|
-
? path.join(
|
|
1321
|
+
? path.join(getCodexHome(options.env), 'skills')
|
|
1311
1322
|
: path.join(repoRoot, '.agents', 'skills');
|
|
1312
1323
|
for (const target of targets) {
|
|
1313
1324
|
const state = target.states.includes('present') ? 'present' : 'disabled';
|
|
@@ -1392,32 +1403,35 @@ async function buildInspectionWrites(options) {
|
|
|
1392
1403
|
kind: 'agent',
|
|
1393
1404
|
}));
|
|
1394
1405
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
scope:
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1406
|
+
const nativeSurface = analyzeCodexSurface(options.plugin.manifest).nativeKinds.length > 0;
|
|
1407
|
+
const codexPluginId = `${options.plugin.manifest.name}@${options.marketplaceName ?? options.plugin.marketplaceName ?? MARKETPLACE_NAME}`;
|
|
1408
|
+
const userActivationDesired = options.scope === 'user'
|
|
1409
|
+
|| options.userActivationDesired?.has(codexPluginId) === true;
|
|
1410
|
+
for (const activation of !nativeSurface ? [] : options.scope === 'project'
|
|
1411
|
+
? [
|
|
1412
|
+
{
|
|
1413
|
+
scope: 'user',
|
|
1414
|
+
desired: userActivationDesired,
|
|
1415
|
+
configPath: resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath,
|
|
1416
|
+
},
|
|
1417
|
+
{ scope: 'project', desired: true, configPath: paths.configTomlPath },
|
|
1418
|
+
]
|
|
1419
|
+
: [{ scope: 'user', desired: true, configPath: paths.configTomlPath }]) {
|
|
1420
|
+
writes.push({
|
|
1421
|
+
artifact: {
|
|
1422
|
+
path: activation.configPath,
|
|
1423
|
+
kind: 'instruction',
|
|
1424
|
+
platform: 'codex',
|
|
1425
|
+
artifactKey: internalArtifactKey('activation', activation.scope),
|
|
1426
|
+
},
|
|
1427
|
+
component: createCodexActivationComponent({
|
|
1428
|
+
identity: pluginOwnerIdentity(options.plugin, internalArtifactKey('activation', activation.scope), 'codex', options.scope),
|
|
1429
|
+
configPath: activation.configPath,
|
|
1430
|
+
codexPluginId,
|
|
1431
|
+
desired: activation.desired,
|
|
1432
|
+
}),
|
|
1433
|
+
write: async () => undefined,
|
|
1434
|
+
});
|
|
1421
1435
|
}
|
|
1422
1436
|
return writes;
|
|
1423
1437
|
}
|
|
@@ -1439,24 +1453,35 @@ async function buildHistoricalComponents(options) {
|
|
|
1439
1453
|
continue;
|
|
1440
1454
|
if (artifact.state === 'disabled')
|
|
1441
1455
|
continue;
|
|
1442
|
-
if (
|
|
1456
|
+
if (options.platform === 'codex'
|
|
1457
|
+
&& artifact.artifactKey !== undefined
|
|
1458
|
+
&& new Set([
|
|
1459
|
+
internalArtifactKey('activation', 'user'),
|
|
1460
|
+
internalArtifactKey('activation', 'project'),
|
|
1461
|
+
]).has(artifact.artifactKey)) {
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
if (options.command === 'cleanup'
|
|
1465
|
+
&& artifact.kind === 'hook'
|
|
1466
|
+
&& options.platform === 'codex') {
|
|
1443
1467
|
for (const identity of artifact.hookGroups ?? []) {
|
|
1444
|
-
components.push(
|
|
1468
|
+
components.push(createLegacyCodexHookCleanupComponent({
|
|
1445
1469
|
pluginName: options.pluginName,
|
|
1446
1470
|
scope: options.scope,
|
|
1447
|
-
hooksPath: resolveCodexPaths(options.cwd, options.scope, options.env).
|
|
1471
|
+
hooksPath: path.join(resolveCodexPaths(options.cwd, options.scope, options.env).configDir, 'hooks.json'),
|
|
1448
1472
|
identity,
|
|
1449
1473
|
}));
|
|
1450
1474
|
}
|
|
1451
1475
|
continue;
|
|
1452
1476
|
}
|
|
1453
|
-
if (
|
|
1454
|
-
|
|
1477
|
+
if (options.command === 'cleanup'
|
|
1478
|
+
&& artifact.kind === 'mcpServer'
|
|
1479
|
+
&& options.platform === 'codex'
|
|
1480
|
+
&& artifact.artifactKey) {
|
|
1481
|
+
components.push(createLegacyCodexMcpCleanupComponent({
|
|
1455
1482
|
identity: historicalIdentity(internalArtifactKey('mcp', artifact.artifactKey)),
|
|
1456
|
-
scope: options.scope,
|
|
1457
1483
|
configPath: resolveCodexPaths(options.cwd, options.scope, options.env).configTomlPath,
|
|
1458
1484
|
serverKey: artifact.artifactKey,
|
|
1459
|
-
owned: false,
|
|
1460
1485
|
}));
|
|
1461
1486
|
continue;
|
|
1462
1487
|
}
|
|
@@ -1520,7 +1545,7 @@ async function readdirCodexResidueIfPresent(directory) {
|
|
|
1520
1545
|
}
|
|
1521
1546
|
return fs.readdir(directory, { withFileTypes: true });
|
|
1522
1547
|
}
|
|
1523
|
-
async function inspectCodexNativeResidue(options) {
|
|
1548
|
+
export async function inspectCodexNativeResidue(options) {
|
|
1524
1549
|
const marketplaceName = options.marketplaceName ?? MARKETPLACE_NAME;
|
|
1525
1550
|
const marketplaceRoot = options.marketplaceRoot ?? resolveAwHome(options.env);
|
|
1526
1551
|
const pluginId = `${options.pluginName}@${marketplaceName}`;
|
|
@@ -1608,6 +1633,203 @@ async function inspectCodexNativeResidue(options) {
|
|
|
1608
1633
|
installedVersions: [], cacheVersions: [], enabled: false,
|
|
1609
1634
|
};
|
|
1610
1635
|
}
|
|
1636
|
+
function isPathWithin(root, candidate) {
|
|
1637
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
1638
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
|
|
1639
|
+
}
|
|
1640
|
+
async function codexPayloadPathSafe(payloadRoot) {
|
|
1641
|
+
const rootStats = await lstatCodexResidueIfPresent(payloadRoot);
|
|
1642
|
+
if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
|
|
1643
|
+
return false;
|
|
1644
|
+
const pending = [payloadRoot];
|
|
1645
|
+
while (pending.length > 0) {
|
|
1646
|
+
const current = pending.pop();
|
|
1647
|
+
for (const entry of await fs.readdir(current, { withFileTypes: true })) {
|
|
1648
|
+
const entryPath = path.join(current, entry.name);
|
|
1649
|
+
if (entry.isSymbolicLink()) {
|
|
1650
|
+
const target = path.resolve(path.dirname(entryPath), await fs.readlink(entryPath));
|
|
1651
|
+
if (!isPathWithin(payloadRoot, target))
|
|
1652
|
+
return false;
|
|
1653
|
+
}
|
|
1654
|
+
else if (entry.isDirectory()) {
|
|
1655
|
+
pending.push(entryPath);
|
|
1656
|
+
}
|
|
1657
|
+
else if (!entry.isFile()) {
|
|
1658
|
+
return false;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return true;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Read-only filesystem projection for the payload-aware shared-native classifier.
|
|
1666
|
+
* It does not invoke Codex or create native/config state.
|
|
1667
|
+
*/
|
|
1668
|
+
export async function inspectCodexSharedNativeLive(options) {
|
|
1669
|
+
const marketplaceName = options.marketplaceName ?? MARKETPLACE_NAME;
|
|
1670
|
+
const marketplaceRoot = options.marketplaceRoot ?? resolveAwHome(options.env);
|
|
1671
|
+
const pluginId = `${options.pluginName}@${marketplaceName}`;
|
|
1672
|
+
const config = await readCodexConfigFile(resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath);
|
|
1673
|
+
const cacheRoot = path.join(getCodexHome(options.env), 'plugins', 'cache', marketplaceName, options.pluginName);
|
|
1674
|
+
const installedManifestPath = path.join(getCodexHome(options.env), 'plugins', pluginId, 'manifest.json');
|
|
1675
|
+
const cacheRootStats = await lstatCodexResidueIfPresent(cacheRoot);
|
|
1676
|
+
let unsafeCachePath = Boolean(cacheRootStats
|
|
1677
|
+
&& (!cacheRootStats.isDirectory() || cacheRootStats.isSymbolicLink()));
|
|
1678
|
+
const candidates = [];
|
|
1679
|
+
if (cacheRootStats?.isDirectory() && !cacheRootStats.isSymbolicLink()) {
|
|
1680
|
+
for (const entry of await fs.readdir(cacheRoot, { withFileTypes: true })) {
|
|
1681
|
+
const payloadPath = path.join(cacheRoot, entry.name);
|
|
1682
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
1683
|
+
unsafeCachePath = true;
|
|
1684
|
+
continue;
|
|
1685
|
+
}
|
|
1686
|
+
const manifestPaths = [
|
|
1687
|
+
path.join(payloadPath, 'plugin.json'),
|
|
1688
|
+
path.join(payloadPath, '.codex-plugin', 'plugin.json'),
|
|
1689
|
+
];
|
|
1690
|
+
const existingManifestPaths = [];
|
|
1691
|
+
for (const manifestPath of manifestPaths) {
|
|
1692
|
+
const stats = await lstatCodexResidueIfPresent(manifestPath);
|
|
1693
|
+
if (stats)
|
|
1694
|
+
existingManifestPaths.push(manifestPath);
|
|
1695
|
+
}
|
|
1696
|
+
if (existingManifestPaths.length !== 1) {
|
|
1697
|
+
candidates.push({
|
|
1698
|
+
version: entry.name,
|
|
1699
|
+
manifest: existingManifestPaths.length === 0 ? { state: 'absent' } : { state: 'unreadable' },
|
|
1700
|
+
payloadPath,
|
|
1701
|
+
});
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1704
|
+
const manifestPath = existingManifestPaths[0];
|
|
1705
|
+
const manifestStats = await lstatCodexResidueIfPresent(manifestPath);
|
|
1706
|
+
if (!manifestStats?.isFile() || manifestStats.isSymbolicLink()) {
|
|
1707
|
+
candidates.push({ version: entry.name, manifest: { state: 'unreadable' }, payloadPath });
|
|
1708
|
+
continue;
|
|
1709
|
+
}
|
|
1710
|
+
let manifest;
|
|
1711
|
+
try {
|
|
1712
|
+
const value = await fs.readJson(manifestPath);
|
|
1713
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1714
|
+
throw new Error('invalid manifest');
|
|
1715
|
+
manifest = value;
|
|
1716
|
+
}
|
|
1717
|
+
catch {
|
|
1718
|
+
candidates.push({ version: entry.name, manifest: { state: 'unreadable' }, payloadPath });
|
|
1719
|
+
continue;
|
|
1720
|
+
}
|
|
1721
|
+
const pathSafe = await codexPayloadPathSafe(payloadPath);
|
|
1722
|
+
let payloadDigest = options.expectedPayloadDigest;
|
|
1723
|
+
if (pathSafe) {
|
|
1724
|
+
try {
|
|
1725
|
+
payloadDigest = await calculateCodexSharedNativePayloadDigest(payloadPath);
|
|
1726
|
+
}
|
|
1727
|
+
catch {
|
|
1728
|
+
candidates.push({ version: entry.name, manifest: { state: 'unreadable' }, payloadPath });
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
candidates.push({
|
|
1733
|
+
version: typeof manifest.version === 'string' ? manifest.version : entry.name,
|
|
1734
|
+
payloadPath,
|
|
1735
|
+
manifest: {
|
|
1736
|
+
state: 'present',
|
|
1737
|
+
identity: typeof manifest.id === 'string'
|
|
1738
|
+
? manifest.id
|
|
1739
|
+
: typeof manifest.name === 'string' ? manifest.name : '',
|
|
1740
|
+
version: typeof manifest.version === 'string' ? manifest.version : '',
|
|
1741
|
+
payloadDigest,
|
|
1742
|
+
payloadPath,
|
|
1743
|
+
pathSafe,
|
|
1744
|
+
},
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
let installedVersion;
|
|
1749
|
+
const installedStats = await lstatCodexResidueIfPresent(installedManifestPath);
|
|
1750
|
+
if (installedStats?.isFile() && !installedStats.isSymbolicLink()) {
|
|
1751
|
+
try {
|
|
1752
|
+
const installed = await fs.readJson(installedManifestPath);
|
|
1753
|
+
if (typeof installed.version === 'string')
|
|
1754
|
+
installedVersion = installed.version;
|
|
1755
|
+
}
|
|
1756
|
+
catch {
|
|
1757
|
+
installedVersion = undefined;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
const selected = candidates.find((candidate) => candidate.version === installedVersion)
|
|
1761
|
+
?? candidates.find((candidate) => candidate.version === options.desiredVersion)
|
|
1762
|
+
?? (candidates.length === 1 ? candidates[0] : undefined);
|
|
1763
|
+
const pluginListEntries = candidates.map((candidate) => ({
|
|
1764
|
+
pluginId,
|
|
1765
|
+
enabled: config.snapshot.plugins[pluginId]?.enabled === true,
|
|
1766
|
+
...(candidate.version ? { version: candidate.version } : {}),
|
|
1767
|
+
path: candidate.payloadPath,
|
|
1768
|
+
}));
|
|
1769
|
+
if (installedStats && pluginListEntries.length === 0) {
|
|
1770
|
+
pluginListEntries.push({
|
|
1771
|
+
pluginId,
|
|
1772
|
+
enabled: config.snapshot.plugins[pluginId]?.enabled === true,
|
|
1773
|
+
...(installedVersion ? { version: installedVersion } : {}),
|
|
1774
|
+
path: path.dirname(installedManifestPath),
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
if (unsafeCachePath && pluginListEntries.length === 0) {
|
|
1778
|
+
pluginListEntries.push({
|
|
1779
|
+
pluginId,
|
|
1780
|
+
enabled: config.snapshot.plugins[pluginId]?.enabled === true,
|
|
1781
|
+
version: options.desiredVersion,
|
|
1782
|
+
path: cacheRoot,
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
const manifest = unsafeCachePath
|
|
1786
|
+
? {
|
|
1787
|
+
state: 'present',
|
|
1788
|
+
identity: pluginId,
|
|
1789
|
+
version: options.desiredVersion,
|
|
1790
|
+
payloadDigest: options.expectedPayloadDigest,
|
|
1791
|
+
payloadPath: cacheRoot,
|
|
1792
|
+
pathSafe: false,
|
|
1793
|
+
}
|
|
1794
|
+
: selected?.manifest ?? { state: 'absent' };
|
|
1795
|
+
const sharedNative = inspectCodexSharedNative({
|
|
1796
|
+
pluginName: options.pluginName,
|
|
1797
|
+
pluginId,
|
|
1798
|
+
marketplaceName,
|
|
1799
|
+
canonicalMarketplaceRoot: marketplaceRoot,
|
|
1800
|
+
desiredVersion: options.desiredVersion,
|
|
1801
|
+
expectedPayloadDigest: options.expectedPayloadDigest,
|
|
1802
|
+
marketplaceRegistration: config.snapshot.marketplaces[marketplaceName],
|
|
1803
|
+
marketplacePathSafe: true,
|
|
1804
|
+
pluginListEntries,
|
|
1805
|
+
manifest,
|
|
1806
|
+
managedByCurrentIntent: options.managedByCurrentIntent && manifest.state === 'present',
|
|
1807
|
+
});
|
|
1808
|
+
return {
|
|
1809
|
+
sharedNative,
|
|
1810
|
+
...(manifest.state === 'present' ? {
|
|
1811
|
+
actualPayloadDigest: manifest.payloadDigest,
|
|
1812
|
+
payloadPath: manifest.payloadPath,
|
|
1813
|
+
} : {}),
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
export async function codexNativeRemovalRequired(options) {
|
|
1817
|
+
const residue = await inspectCodexNativeResidue(options);
|
|
1818
|
+
if (residue.state === 'present')
|
|
1819
|
+
return true;
|
|
1820
|
+
if (residue.state === 'foreign')
|
|
1821
|
+
return false;
|
|
1822
|
+
const marketplaceName = options.marketplaceName ?? MARKETPLACE_NAME;
|
|
1823
|
+
const marketplaceRoot = options.marketplaceRoot ?? resolveAwHome(options.env);
|
|
1824
|
+
const config = await readCodexConfigFile(resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath);
|
|
1825
|
+
const marketplace = config.snapshot.marketplaces[marketplaceName];
|
|
1826
|
+
const canonical = marketplace?.sourceType === 'local'
|
|
1827
|
+
&& !marketplace.sourcePointsToManifest
|
|
1828
|
+
&& path.normalize(marketplace.source ?? '') === path.normalize(marketplaceRoot);
|
|
1829
|
+
if (!canonical)
|
|
1830
|
+
return false;
|
|
1831
|
+
return (await discoverCodexNativeResidueNames(options)).length === 0;
|
|
1832
|
+
}
|
|
1611
1833
|
export async function discoverCodexNativeResidueNames(options) {
|
|
1612
1834
|
const marketplaceName = options.marketplaceName ?? MARKETPLACE_NAME;
|
|
1613
1835
|
const marketplaceRoot = options.marketplaceRoot ?? resolveAwHome(options.env);
|
|
@@ -1809,8 +2031,13 @@ function createCodexMarketplaceComponent(options) {
|
|
|
1809
2031
|
|| currentResidue.state === 'present'
|
|
1810
2032
|
|| await hasRemainingPlugins())
|
|
1811
2033
|
return;
|
|
1812
|
-
|
|
1813
|
-
|
|
2034
|
+
try {
|
|
2035
|
+
await runNativeCliChecked(buildCodexMarketplaceRemoveInvocation(requireCodexManager(options.codexManager), options.marketplaceName, options.cwd, options.env), options.runner);
|
|
2036
|
+
await runNativeCliChecked(buildCodexMarketplaceListInvocation(requireCodexManager(options.codexManager), options.cwd, options.env), options.runner);
|
|
2037
|
+
}
|
|
2038
|
+
catch {
|
|
2039
|
+
throw new Error(`codexNativeRemoveFailed: ${CODEX_REMOVE_RECOVERY}`);
|
|
2040
|
+
}
|
|
1814
2041
|
},
|
|
1815
2042
|
};
|
|
1816
2043
|
}
|
|
@@ -2414,9 +2641,11 @@ async function mirrorCatalog(catalog, env, target) {
|
|
|
2414
2641
|
}
|
|
2415
2642
|
function createNativeDriver(options) {
|
|
2416
2643
|
const runner = options.context.nativeCliRunner;
|
|
2417
|
-
const
|
|
2644
|
+
const codexManager = options.context.codexManager;
|
|
2418
2645
|
const mirrorTransactions = new WeakMap();
|
|
2419
2646
|
const finalizeNamespacedCleanup = async (target) => {
|
|
2647
|
+
if (target.identity.platform === 'codex')
|
|
2648
|
+
return;
|
|
2420
2649
|
const { sourceId, sourceIdentity, marketplaceRoot, marketplaceName } = target.identity;
|
|
2421
2650
|
if (!sourceId || !sourceIdentity || !marketplaceRoot)
|
|
2422
2651
|
return;
|
|
@@ -2429,53 +2658,13 @@ function createNativeDriver(options) {
|
|
|
2429
2658
|
});
|
|
2430
2659
|
};
|
|
2431
2660
|
return {
|
|
2432
|
-
withOwnershipLease: (target, operation) => (!options.context.runtimeLeaseHeld
|
|
2433
|
-
&& target.identity.platform === 'codex'
|
|
2434
|
-
&& target.identity.scope === 'user'
|
|
2435
|
-
&& !materializeLeaseHeld.has(target)
|
|
2436
|
-
? withActiveMarketplaceRuntimeLease(options.context.env, operation)
|
|
2437
|
-
: operation()),
|
|
2438
|
-
withMaterializeLease: (target, operation) => {
|
|
2439
|
-
if (!target.identity.sourceId)
|
|
2440
|
-
return operation();
|
|
2441
|
-
if (options.context.runtimeLeaseHeld && !options.context.lifecycleLeaseHeld) {
|
|
2442
|
-
throw new Error('lockOrderViolation: namespaced materialization cannot acquire lifecycle after runtime.');
|
|
2443
|
-
}
|
|
2444
|
-
const runOperation = async () => {
|
|
2445
|
-
const previousRuntimeHeld = options.context.runtimeLeaseHeld;
|
|
2446
|
-
options.context.runtimeLeaseHeld = true;
|
|
2447
|
-
materializeLeaseHeld.add(target);
|
|
2448
|
-
try {
|
|
2449
|
-
if (options.context.expectedCatalogConfigDigest) {
|
|
2450
|
-
const current = await readCatalogSourcesConfigSnapshot(options.context.env);
|
|
2451
|
-
if (current.digest !== options.context.expectedCatalogConfigDigest) {
|
|
2452
|
-
throw new Error('catalogSourceConflict: catalog source config changed before owner publication.');
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
|
-
return await operation();
|
|
2456
|
-
}
|
|
2457
|
-
finally {
|
|
2458
|
-
materializeLeaseHeld.delete(target);
|
|
2459
|
-
options.context.runtimeLeaseHeld = previousRuntimeHeld;
|
|
2460
|
-
}
|
|
2461
|
-
};
|
|
2462
|
-
const withRuntime = () => options.context.runtimeLeaseHeld
|
|
2463
|
-
? runOperation()
|
|
2464
|
-
: withActiveMarketplaceRuntimeLease(options.context.env, runOperation);
|
|
2465
|
-
if (options.context.lifecycleLeaseHeld)
|
|
2466
|
-
return withRuntime();
|
|
2467
|
-
return withActiveMarketplaceLifecycleLease(options.context.env, async () => {
|
|
2468
|
-
const previousLifecycleHeld = options.context.lifecycleLeaseHeld;
|
|
2469
|
-
options.context.lifecycleLeaseHeld = true;
|
|
2470
|
-
try {
|
|
2471
|
-
return await withRuntime();
|
|
2472
|
-
}
|
|
2473
|
-
finally {
|
|
2474
|
-
options.context.lifecycleLeaseHeld = previousLifecycleHeld;
|
|
2475
|
-
}
|
|
2476
|
-
});
|
|
2477
|
-
},
|
|
2478
2661
|
preflightMaterialize: async (target) => {
|
|
2662
|
+
if (target.identity.sourceId && options.context.expectedCatalogConfigDigest) {
|
|
2663
|
+
const current = await readCatalogSourcesConfigSnapshot(options.context.env);
|
|
2664
|
+
if (current.digest !== options.context.expectedCatalogConfigDigest) {
|
|
2665
|
+
throw new Error('catalogSourceConflict: catalog source config changed before owner publication.');
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2479
2668
|
if (target.identity.platform === 'claude') {
|
|
2480
2669
|
await assertNoClaudeUnboundNativeNameCollision({
|
|
2481
2670
|
pluginName: target.identity.pluginName,
|
|
@@ -2530,7 +2719,7 @@ function createNativeDriver(options) {
|
|
|
2530
2719
|
});
|
|
2531
2720
|
return state.pluginState;
|
|
2532
2721
|
}
|
|
2533
|
-
if (target.identity.platform === 'codex'
|
|
2722
|
+
if (target.identity.platform === 'codex') {
|
|
2534
2723
|
const residue = await inspectCodexNativeResidue({
|
|
2535
2724
|
pluginName: target.identity.pluginName,
|
|
2536
2725
|
cwd: target.identity.cwd,
|
|
@@ -2562,7 +2751,7 @@ function createNativeDriver(options) {
|
|
|
2562
2751
|
return state.pluginState;
|
|
2563
2752
|
return state.pluginEnabled ? 'present' : 'partial';
|
|
2564
2753
|
}
|
|
2565
|
-
if (target.identity.platform === 'codex'
|
|
2754
|
+
if (target.identity.platform === 'codex') {
|
|
2566
2755
|
const residue = await inspectCodexNativeResidue({
|
|
2567
2756
|
pluginName: target.identity.pluginName,
|
|
2568
2757
|
cwd: target.identity.cwd,
|
|
@@ -2572,7 +2761,34 @@ function createNativeDriver(options) {
|
|
|
2572
2761
|
});
|
|
2573
2762
|
if (residue.state !== 'present')
|
|
2574
2763
|
return residue.state;
|
|
2575
|
-
|
|
2764
|
+
if (target.identity.scope !== 'project' || !codexManager)
|
|
2765
|
+
return 'present';
|
|
2766
|
+
const userConfig = await readCodexConfigFile(resolveCodexPaths(target.identity.cwd, 'user', options.context.env).configTomlPath);
|
|
2767
|
+
const projectConfig = await readCodexConfigFile(resolveCodexPaths(target.identity.cwd, 'project', options.context.env).configTomlPath);
|
|
2768
|
+
const pluginId = `${target.identity.pluginName}@${target.identity.marketplaceName ?? MARKETPLACE_NAME}`;
|
|
2769
|
+
const neutralCwd = await fs.mkdtemp(path.join(os.tmpdir(), 'aw-codex-postcheck-'));
|
|
2770
|
+
try {
|
|
2771
|
+
const invocations = buildCodexProjectPluginListInvocations(codexManager, {
|
|
2772
|
+
exactCwd: target.identity.cwd,
|
|
2773
|
+
neutralCwd,
|
|
2774
|
+
env: options.context.env,
|
|
2775
|
+
});
|
|
2776
|
+
const [exactResult, neutralResult] = await Promise.all([
|
|
2777
|
+
runNativeCliChecked(invocations.exact, runner),
|
|
2778
|
+
runNativeCliChecked(invocations.neutral, runner),
|
|
2779
|
+
]);
|
|
2780
|
+
postcheckCodexProjectPluginActivation({
|
|
2781
|
+
pluginId,
|
|
2782
|
+
userEnabled: userConfig.snapshot.plugins[pluginId]?.enabled === true,
|
|
2783
|
+
projectEnabled: projectConfig.snapshot.plugins[pluginId]?.enabled === true,
|
|
2784
|
+
exactResult,
|
|
2785
|
+
neutralResult,
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
finally {
|
|
2789
|
+
await fs.remove(neutralCwd);
|
|
2790
|
+
}
|
|
2791
|
+
return 'present';
|
|
2576
2792
|
}
|
|
2577
2793
|
return 'absent';
|
|
2578
2794
|
},
|
|
@@ -2596,7 +2812,12 @@ function createNativeDriver(options) {
|
|
|
2596
2812
|
}
|
|
2597
2813
|
if (before.state === 'absent')
|
|
2598
2814
|
return;
|
|
2599
|
-
|
|
2815
|
+
try {
|
|
2816
|
+
await runNativeCliChecked(buildCodexPluginRemoveInvocation(requireCodexManager(codexManager), component.pluginId, target.identity.cwd, options.context.env), runner);
|
|
2817
|
+
}
|
|
2818
|
+
catch {
|
|
2819
|
+
throw new Error(`codexNativeRemoveFailed: ${CODEX_REMOVE_RECOVERY}`);
|
|
2820
|
+
}
|
|
2600
2821
|
const residue = await inspectCodexNativeResidue({
|
|
2601
2822
|
pluginName: target.identity.pluginName,
|
|
2602
2823
|
cwd: target.identity.cwd,
|
|
@@ -2605,7 +2826,7 @@ function createNativeDriver(options) {
|
|
|
2605
2826
|
marketplaceRoot: target.identity.marketplaceRoot,
|
|
2606
2827
|
});
|
|
2607
2828
|
if (residue.state !== 'absent') {
|
|
2608
|
-
throw new Error(`
|
|
2829
|
+
throw new Error(`codexNativeRemoveIncomplete: ${CODEX_REMOVE_RECOVERY}`);
|
|
2609
2830
|
}
|
|
2610
2831
|
}
|
|
2611
2832
|
else {
|
|
@@ -2640,6 +2861,21 @@ function createNativeDriver(options) {
|
|
|
2640
2861
|
throw new Error('Missing rebuild integration plan.');
|
|
2641
2862
|
const marketplaceName = target.identity.marketplaceName ?? MARKETPLACE_NAME;
|
|
2642
2863
|
const expectedMarketplaceRoot = target.identity.marketplaceRoot ?? resolveAwHome(options.context.env);
|
|
2864
|
+
if (target.identity.platform === 'codex') {
|
|
2865
|
+
const before = await inspectCodexNativeResidue({
|
|
2866
|
+
pluginName: target.identity.pluginName,
|
|
2867
|
+
cwd: target.identity.cwd,
|
|
2868
|
+
env: options.context.env,
|
|
2869
|
+
marketplaceName,
|
|
2870
|
+
marketplaceRoot: expectedMarketplaceRoot,
|
|
2871
|
+
});
|
|
2872
|
+
if (before.state === 'foreign') {
|
|
2873
|
+
throw new Error(`codexSharedNativeForeign: ${before.labels.join(', ')}`);
|
|
2874
|
+
}
|
|
2875
|
+
if (before.state === 'present') {
|
|
2876
|
+
await runNativeCliChecked(buildCodexPluginRemoveInvocation(requireCodexManager(codexManager), `${target.identity.pluginName}@${marketplaceName}`, target.identity.cwd, options.context.env), runner);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2643
2879
|
const writeGeneration = async () => {
|
|
2644
2880
|
if (mirrorTransactions.has(target)) {
|
|
2645
2881
|
throw new Error('Marketplace mirror transaction is already active for this target.');
|
|
@@ -2672,27 +2908,31 @@ function createNativeDriver(options) {
|
|
|
2672
2908
|
const marketplaceRoot = mirrored.rootDir;
|
|
2673
2909
|
const pluginId = `${target.identity.pluginName}@${marketplaceName}`;
|
|
2674
2910
|
if (target.identity.platform === 'codex') {
|
|
2911
|
+
const nativePluginRoot = await canonicalizePathThroughExistingAncestor(path.join(marketplaceRoot, 'plugins', target.identity.pluginName));
|
|
2675
2912
|
const requiredSkillWrites = plan.writes.filter((entry) => !entry.optional
|
|
2676
2913
|
&& entry.component?.kind === 'skill-directory'
|
|
2677
2914
|
&& entry.artifact.kind === 'skill'
|
|
2678
2915
|
&& entry.artifact.state !== 'disabled'
|
|
2679
|
-
&& target.identity.scope === 'user'
|
|
2916
|
+
&& target.identity.scope === 'user'
|
|
2917
|
+
&& !path.relative(nativePluginRoot, entry.component.path).startsWith('..'));
|
|
2680
2918
|
for (const write of requiredSkillWrites) {
|
|
2681
2919
|
await write.write();
|
|
2682
2920
|
}
|
|
2683
2921
|
const skillsRelativeRoot = await ensureCodexActiveSkillsManifest({
|
|
2684
2922
|
plugin: target.plugin,
|
|
2685
2923
|
marketplaceRoot,
|
|
2686
|
-
hasRequiredSkills:
|
|
2924
|
+
hasRequiredSkills: target.identity.scope === 'project'
|
|
2925
|
+
? target.plugin.manifest.skills !== undefined
|
|
2926
|
+
: requiredSkillWrites.length > 0,
|
|
2687
2927
|
});
|
|
2688
2928
|
const config = await readCodexConfigFile(resolveCodexPaths(target.identity.cwd, 'user', options.context.env).configTomlPath);
|
|
2689
2929
|
const marketplace = config.snapshot.marketplaces[marketplaceName];
|
|
2690
2930
|
if (path.normalize(marketplace?.source ?? '') !== path.normalize(marketplaceRoot)) {
|
|
2691
|
-
await runNativeCliChecked(buildCodexMarketplaceAddInvocation(marketplaceRoot, target.identity.cwd, options.context.env), runner);
|
|
2931
|
+
await runNativeCliChecked(buildCodexMarketplaceAddInvocation(requireCodexManager(codexManager), marketplaceRoot, target.identity.cwd, options.context.env), runner);
|
|
2692
2932
|
}
|
|
2693
|
-
await runNativeCliChecked(buildCodexMarketplaceListInvocation(target.identity.cwd, options.context.env), runner);
|
|
2694
|
-
await runNativeCliChecked(buildCodexPluginAddInvocation(pluginId, target.identity.cwd, options.context.env), runner);
|
|
2695
|
-
await runNativeCliChecked(buildCodexPluginListInvocation(target.identity.cwd, options.context.env), runner);
|
|
2933
|
+
await runNativeCliChecked(buildCodexMarketplaceListInvocation(requireCodexManager(codexManager), target.identity.cwd, options.context.env), runner);
|
|
2934
|
+
await runNativeCliChecked(buildCodexPluginAddInvocation(requireCodexManager(codexManager), pluginId, target.identity.cwd, options.context.env), runner);
|
|
2935
|
+
await runNativeCliChecked(buildCodexPluginListInvocation(requireCodexManager(codexManager), target.identity.cwd, options.context.env), runner);
|
|
2696
2936
|
await assertCodexNativeInstallState({
|
|
2697
2937
|
pluginName: target.identity.pluginName,
|
|
2698
2938
|
pluginVersion: target.identity.pluginVersion,
|
|
@@ -2741,11 +2981,7 @@ function createNativeDriver(options) {
|
|
|
2741
2981
|
}
|
|
2742
2982
|
}
|
|
2743
2983
|
};
|
|
2744
|
-
await (
|
|
2745
|
-
&& !options.context.runtimeLeaseHeld
|
|
2746
|
-
&& !materializeLeaseHeld.has(target)
|
|
2747
|
-
? withActiveMarketplaceRuntimeLease(options.context.env, writeGeneration)
|
|
2748
|
-
: writeGeneration());
|
|
2984
|
+
await writeGeneration();
|
|
2749
2985
|
},
|
|
2750
2986
|
writeArtifacts: async (target) => {
|
|
2751
2987
|
const plan = options.plans.get(target);
|
|
@@ -2756,11 +2992,7 @@ function createNativeDriver(options) {
|
|
|
2756
2992
|
await write.write();
|
|
2757
2993
|
return plan.writes.map((write) => write.artifact);
|
|
2758
2994
|
};
|
|
2759
|
-
return
|
|
2760
|
-
&& !materializeLeaseHeld.has(target)
|
|
2761
|
-
&& target.identity.platform === 'codex' && target.identity.scope === 'user'
|
|
2762
|
-
? withActiveMarketplaceRuntimeLease(options.context.env, writeAll)
|
|
2763
|
-
: writeAll();
|
|
2995
|
+
return writeAll();
|
|
2764
2996
|
},
|
|
2765
2997
|
runLifecycle: async (invocation) => {
|
|
2766
2998
|
await runLifecycleScript({
|
|
@@ -2799,13 +3031,10 @@ export function createRebuildIntegration(options) {
|
|
|
2799
3031
|
cwd: input.cwd,
|
|
2800
3032
|
rootNames: input.platform === 'codex' ? ['.agents', '.codex'] : ['.claude'],
|
|
2801
3033
|
managedPaths: input.platform === 'codex'
|
|
2802
|
-
? ['.codex/config.toml'
|
|
3034
|
+
? ['.codex/config.toml']
|
|
2803
3035
|
: ['.claude/settings.json'],
|
|
2804
3036
|
});
|
|
2805
3037
|
input = { ...input, cwd: canonicalRepoRoot };
|
|
2806
|
-
if (materializing && input.platform === 'codex' && input.plugin.manifest.apps) {
|
|
2807
|
-
throw new Error(`Codex project scope 不支持 apps:${input.plugin.manifest.name}`);
|
|
2808
|
-
}
|
|
2809
3038
|
}
|
|
2810
3039
|
if (materializing && input.platform === 'codex') {
|
|
2811
3040
|
await preflightCodexWriteSafety({
|
|
@@ -2832,9 +3061,15 @@ export function createRebuildIntegration(options) {
|
|
|
2832
3061
|
env: options.context.env,
|
|
2833
3062
|
loadPlugin,
|
|
2834
3063
|
});
|
|
3064
|
+
if (input.expectedLifecycleMetadataIntegrityDigest !== undefined
|
|
3065
|
+
&& active?.metadata.metadataIntegrityDigest
|
|
3066
|
+
!== input.expectedLifecycleMetadataIntegrityDigest) {
|
|
3067
|
+
throw new Error('stateInventoryFailed: lifecycle active generation changed after verified inventory.');
|
|
3068
|
+
}
|
|
2835
3069
|
historicalArtifacts = active?.artifacts ?? [];
|
|
2836
3070
|
}
|
|
2837
3071
|
let writes = [];
|
|
3072
|
+
let currentRemovalComponents = [];
|
|
2838
3073
|
if (input.command !== 'cleanup' && input.command !== 'uninstall') {
|
|
2839
3074
|
if (input.readOnlyInspectionPlan) {
|
|
2840
3075
|
writes = await buildInspectionWrites({
|
|
@@ -2844,6 +3079,8 @@ export function createRebuildIntegration(options) {
|
|
|
2844
3079
|
cwd: input.cwd,
|
|
2845
3080
|
env: options.context.env,
|
|
2846
3081
|
marketplaceRoot: input.marketplaceRoot,
|
|
3082
|
+
marketplaceName: input.marketplaceName,
|
|
3083
|
+
userActivationDesired: options.context.codexUserActivationDesired,
|
|
2847
3084
|
});
|
|
2848
3085
|
}
|
|
2849
3086
|
else if (input.platform === 'codex') {
|
|
@@ -2853,6 +3090,8 @@ export function createRebuildIntegration(options) {
|
|
|
2853
3090
|
event,
|
|
2854
3091
|
historicalArtifacts,
|
|
2855
3092
|
scriptTimeoutMs: options.scriptTimeoutMs,
|
|
3093
|
+
marketplaceName: input.marketplaceName,
|
|
3094
|
+
userActivationDesired: options.context.codexUserActivationDesired,
|
|
2856
3095
|
});
|
|
2857
3096
|
}
|
|
2858
3097
|
else {
|
|
@@ -2865,6 +3104,22 @@ export function createRebuildIntegration(options) {
|
|
|
2865
3104
|
});
|
|
2866
3105
|
}
|
|
2867
3106
|
}
|
|
3107
|
+
else if (input.platform === 'codex' && input.scope === 'project') {
|
|
3108
|
+
const currentRemovalWrites = await buildInspectionWrites({
|
|
3109
|
+
plugin: input.plugin,
|
|
3110
|
+
platform: input.platform,
|
|
3111
|
+
scope: input.scope,
|
|
3112
|
+
cwd: input.cwd,
|
|
3113
|
+
env: options.context.env,
|
|
3114
|
+
marketplaceRoot: input.marketplaceRoot,
|
|
3115
|
+
marketplaceName: input.marketplaceName,
|
|
3116
|
+
userActivationDesired: options.context.codexUserActivationDesired,
|
|
3117
|
+
});
|
|
3118
|
+
currentRemovalComponents = currentRemovalWrites.flatMap((write) => [
|
|
3119
|
+
...(write.additionalComponents ?? []),
|
|
3120
|
+
...(write.component ? [write.component] : []),
|
|
3121
|
+
]);
|
|
3122
|
+
}
|
|
2868
3123
|
const desiredComponents = writes.filter((write) => !write.optional).flatMap((write) => [
|
|
2869
3124
|
...(write.additionalComponents ?? []),
|
|
2870
3125
|
...(write.component ? [write.component] : []),
|
|
@@ -2892,8 +3147,13 @@ export function createRebuildIntegration(options) {
|
|
|
2892
3147
|
})))).flat();
|
|
2893
3148
|
const skillRoots = input.platform === 'codex'
|
|
2894
3149
|
? input.scope === 'project'
|
|
2895
|
-
? [
|
|
2896
|
-
: [
|
|
3150
|
+
? []
|
|
3151
|
+
: [
|
|
3152
|
+
path.join(getCodexHome(options.context.env), 'skills'),
|
|
3153
|
+
...(input.preserveCodexSharedNativePayload
|
|
3154
|
+
? []
|
|
3155
|
+
: [await canonicalizePathThroughExistingAncestor(path.join(input.marketplaceRoot ?? resolveAwHome(options.context.env), 'plugins', input.plugin.manifest.name))]),
|
|
3156
|
+
]
|
|
2897
3157
|
: [path.join(configDir, 'skills')];
|
|
2898
3158
|
const scanSkills = () => Promise.all(skillRoots.map((root) => scanOwnedSkills({
|
|
2899
3159
|
sourceId: input.sourceId,
|
|
@@ -2903,12 +3163,8 @@ export function createRebuildIntegration(options) {
|
|
|
2903
3163
|
platform: input.platform,
|
|
2904
3164
|
scope: input.scope,
|
|
2905
3165
|
})));
|
|
2906
|
-
const scannedSkills = (await (
|
|
2907
|
-
|
|
2908
|
-
&& input.readOnlyInspectionPlan !== true
|
|
2909
|
-
? withActiveMarketplaceRuntimeLease(options.context.env, scanSkills)
|
|
2910
|
-
: scanSkills())).flat();
|
|
2911
|
-
const historicalComponents = await buildHistoricalComponents({
|
|
3166
|
+
const scannedSkills = (await scanSkills()).flat();
|
|
3167
|
+
let historicalComponents = await buildHistoricalComponents({
|
|
2912
3168
|
sourceId: input.sourceId,
|
|
2913
3169
|
sourceIdentity: input.sourceIdentity,
|
|
2914
3170
|
pluginId: input.pluginId,
|
|
@@ -2918,7 +3174,24 @@ export function createRebuildIntegration(options) {
|
|
|
2918
3174
|
cwd: input.cwd,
|
|
2919
3175
|
env: options.context.env,
|
|
2920
3176
|
artifacts: historicalArtifacts,
|
|
3177
|
+
command: input.command,
|
|
2921
3178
|
});
|
|
3179
|
+
if (input.preserveCodexSharedNativePayload) {
|
|
3180
|
+
const nativePluginRoots = await Promise.all([
|
|
3181
|
+
path.join(input.marketplaceRoot ?? resolveAwHome(options.context.env), 'plugins', input.plugin.manifest.name),
|
|
3182
|
+
path.join(getCodexHome(options.context.env), 'plugins', 'cache', input.marketplaceName ?? MARKETPLACE_NAME, input.plugin.manifest.name),
|
|
3183
|
+
].map((root) => canonicalizePathThroughExistingAncestor(root)));
|
|
3184
|
+
historicalComponents = historicalComponents.filter((component) => {
|
|
3185
|
+
if (!('path' in component))
|
|
3186
|
+
return true;
|
|
3187
|
+
return nativePluginRoots.every((nativePluginRoot) => {
|
|
3188
|
+
const relative = path.relative(nativePluginRoot, path.resolve(component.path));
|
|
3189
|
+
return relative === '..'
|
|
3190
|
+
|| relative.startsWith(`..${path.sep}`)
|
|
3191
|
+
|| path.isAbsolute(relative);
|
|
3192
|
+
});
|
|
3193
|
+
});
|
|
3194
|
+
}
|
|
2922
3195
|
const sharedComponents = input.platform === 'codex'
|
|
2923
3196
|
? await scanCodexSharedComponents({
|
|
2924
3197
|
sourceId: input.sourceId,
|
|
@@ -2928,7 +3201,6 @@ export function createRebuildIntegration(options) {
|
|
|
2928
3201
|
scope: input.scope,
|
|
2929
3202
|
paths: resolveCodexPaths(input.cwd, input.scope, options.context.env),
|
|
2930
3203
|
scanConfig: true,
|
|
2931
|
-
scanHooks: true,
|
|
2932
3204
|
ignoreReadErrors: true,
|
|
2933
3205
|
})
|
|
2934
3206
|
: await scanClaudeSharedComponents({
|
|
@@ -2940,9 +3212,28 @@ export function createRebuildIntegration(options) {
|
|
|
2940
3212
|
settingsPath: resolveClaudePaths(input.cwd, input.scope, options.context.env).settingsPath,
|
|
2941
3213
|
});
|
|
2942
3214
|
const nativeRequired = input.platform === 'claude'
|
|
2943
|
-
|| (input.
|
|
2944
|
-
const
|
|
2945
|
-
|
|
3215
|
+
|| analyzeCodexSurface(input.plugin.manifest).nativeKinds.length > 0;
|
|
3216
|
+
const nativeDesired = nativeRequired
|
|
3217
|
+
&& input.command !== 'cleanup'
|
|
3218
|
+
&& input.command !== 'uninstall';
|
|
3219
|
+
const codexNative = input.platform === 'codex' && nativeRequired
|
|
3220
|
+
? await inspectCodexNativeResidue({
|
|
3221
|
+
pluginName: input.plugin.manifest.name,
|
|
3222
|
+
cwd: input.cwd,
|
|
3223
|
+
env: options.context.env,
|
|
3224
|
+
marketplaceName: input.marketplaceName,
|
|
3225
|
+
marketplaceRoot: input.marketplaceRoot,
|
|
3226
|
+
})
|
|
3227
|
+
: undefined;
|
|
3228
|
+
const codexNativeExact = codexNative?.state === 'present'
|
|
3229
|
+
&& codexNative.versions.length > 0
|
|
3230
|
+
&& codexNative.versions.every((version) => version === input.plugin.manifest.version);
|
|
3231
|
+
const materializeNativeRequired = nativeDesired && (input.platform === 'claude'
|
|
3232
|
+
|| input.command === 'reinstall'
|
|
3233
|
+
|| !codexNativeExact);
|
|
3234
|
+
const nativeCleanupCandidate = input.platform === 'claude'
|
|
3235
|
+
&& input.includeNativeCleanupCandidate !== false;
|
|
3236
|
+
const nativePlugin = (nativeDesired || nativeCleanupCandidate)
|
|
2946
3237
|
? [{
|
|
2947
3238
|
kind: 'native-plugin',
|
|
2948
3239
|
identity: ownerIdentity(input.plugin.manifest.name, 'native', input.platform, input.scope),
|
|
@@ -2952,9 +3243,10 @@ export function createRebuildIntegration(options) {
|
|
|
2952
3243
|
const marketplaceDesired = nativeRequired
|
|
2953
3244
|
&& input.command !== 'cleanup'
|
|
2954
3245
|
&& input.command !== 'uninstall';
|
|
2955
|
-
const marketplace = input.platform === 'codex' && input.scope === 'user'
|
|
3246
|
+
const marketplace = input.platform === 'codex' && input.scope === 'user' && nativeDesired
|
|
2956
3247
|
? [createCodexMarketplaceComponent({
|
|
2957
3248
|
pluginName: input.plugin.manifest.name,
|
|
3249
|
+
codexManager: options.context.codexManager,
|
|
2958
3250
|
cwd: input.cwd,
|
|
2959
3251
|
env: options.context.env,
|
|
2960
3252
|
runner: options.context.nativeCliRunner,
|
|
@@ -2974,20 +3266,48 @@ export function createRebuildIntegration(options) {
|
|
|
2974
3266
|
desired: marketplaceDesired,
|
|
2975
3267
|
})]
|
|
2976
3268
|
: [];
|
|
2977
|
-
if (
|
|
2978
|
-
&& input.command !== 'cleanup'
|
|
2979
|
-
&& input.command !== 'uninstall')
|
|
3269
|
+
if (nativeDesired)
|
|
2980
3270
|
desiredComponents.push(...nativePlugin, ...marketplace);
|
|
3271
|
+
const activationCleanup = input.platform === 'codex'
|
|
3272
|
+
&& nativeRequired
|
|
3273
|
+
&& (input.command === 'cleanup' || input.command === 'uninstall')
|
|
3274
|
+
? (input.scope === 'project'
|
|
3275
|
+
? [
|
|
3276
|
+
createCodexActivationComponent({
|
|
3277
|
+
identity: ownerIdentity(input.plugin.manifest.name, internalArtifactKey('activation', 'project'), 'codex', input.scope),
|
|
3278
|
+
configPath: resolveCodexPaths(input.cwd, 'project', options.context.env).configTomlPath,
|
|
3279
|
+
codexPluginId: `${input.plugin.manifest.name}@${input.marketplaceName ?? MARKETPLACE_NAME}`,
|
|
3280
|
+
desired: true,
|
|
3281
|
+
}),
|
|
3282
|
+
]
|
|
3283
|
+
: [createCodexActivationComponent({
|
|
3284
|
+
identity: ownerIdentity(input.plugin.manifest.name, internalArtifactKey('activation', 'user'), 'codex', input.scope),
|
|
3285
|
+
configPath: resolveCodexPaths(input.cwd, 'user', options.context.env).configTomlPath,
|
|
3286
|
+
codexPluginId: `${input.plugin.manifest.name}@${input.marketplaceName ?? MARKETPLACE_NAME}`,
|
|
3287
|
+
desired: true,
|
|
3288
|
+
})])
|
|
3289
|
+
: [];
|
|
3290
|
+
const explicitActivationCleanup = input.platform === 'codex'
|
|
3291
|
+
? (input.codexActivationCleanup ?? []).map((activation) => createCodexActivationCleanupComponent({
|
|
3292
|
+
identity: ownerIdentity(input.plugin.manifest.name, internalArtifactKey('activation', activation.scope), 'codex', input.scope),
|
|
3293
|
+
configPath: resolveCodexPaths(input.cwd, activation.scope, options.context.env).configTomlPath,
|
|
3294
|
+
codexPluginId: activation.codexPluginId,
|
|
3295
|
+
disposition: activation.disposition,
|
|
3296
|
+
}))
|
|
3297
|
+
: [];
|
|
2981
3298
|
const allComponents = dedupeComponents([
|
|
2982
3299
|
...desiredComponents,
|
|
2983
3300
|
...optionalComponents,
|
|
2984
3301
|
...(input.platform === 'codex' ? sharedComponents : []),
|
|
2985
3302
|
...scannedText,
|
|
2986
3303
|
...scannedSkills,
|
|
3304
|
+
...currentRemovalComponents,
|
|
2987
3305
|
...historicalComponents,
|
|
2988
3306
|
...(input.platform === 'claude' ? sharedComponents : []),
|
|
2989
3307
|
...nativePlugin,
|
|
2990
3308
|
...marketplace,
|
|
3309
|
+
...activationCleanup,
|
|
3310
|
+
...explicitActivationCleanup,
|
|
2991
3311
|
]);
|
|
2992
3312
|
bindNamespacedOwnerIdentity(allComponents, input);
|
|
2993
3313
|
const desiredKeys = new Set(desiredComponents.map(componentIdentityKey));
|
|
@@ -3010,11 +3330,15 @@ export function createRebuildIntegration(options) {
|
|
|
3010
3330
|
ownedComponents: allComponents,
|
|
3011
3331
|
desiredOwnedComponents: allComponents.filter((component) => desiredKeys.has(componentIdentityKey(component))),
|
|
3012
3332
|
optionalOwnedComponents: allComponents.filter((component) => optionalComponentKeys.has(componentIdentityKey(component))),
|
|
3013
|
-
requiresNative:
|
|
3014
|
-
|
|
3015
|
-
&& input.command !== 'uninstall',
|
|
3333
|
+
requiresNative: nativeDesired,
|
|
3334
|
+
writeNativeRequired: materializeNativeRequired,
|
|
3016
3335
|
artifacts: writes.map((write) => write.artifact),
|
|
3017
3336
|
lifecycleSource: input.plugin,
|
|
3337
|
+
...(input.expectedLifecycleMetadataIntegrityDigest
|
|
3338
|
+
? {
|
|
3339
|
+
historicalLifecycleMetadataIntegrityDigest: input.expectedLifecycleMetadataIntegrityDigest,
|
|
3340
|
+
}
|
|
3341
|
+
: {}),
|
|
3018
3342
|
};
|
|
3019
3343
|
plans.set(target, {
|
|
3020
3344
|
catalog: input.catalog,
|
|
@@ -3027,7 +3351,13 @@ export function createRebuildIntegration(options) {
|
|
|
3027
3351
|
};
|
|
3028
3352
|
}
|
|
3029
3353
|
export async function inspectRebuildTarget(options) {
|
|
3030
|
-
const integration = createRebuildIntegration({
|
|
3354
|
+
const integration = createRebuildIntegration({
|
|
3355
|
+
context: {
|
|
3356
|
+
...options.context,
|
|
3357
|
+
codexUserActivationDesired: options.userActivationDesired
|
|
3358
|
+
?? options.context.codexUserActivationDesired,
|
|
3359
|
+
},
|
|
3360
|
+
});
|
|
3031
3361
|
const target = await integration.buildTarget({
|
|
3032
3362
|
...(options.sourceId ? {
|
|
3033
3363
|
sourceId: options.sourceId,
|
|
@@ -3047,7 +3377,9 @@ export async function inspectRebuildTarget(options) {
|
|
|
3047
3377
|
});
|
|
3048
3378
|
const inspection = await inspectOwnedComponents({
|
|
3049
3379
|
components: target.ownedComponents,
|
|
3050
|
-
nativeProbe:
|
|
3380
|
+
nativeProbe: options.nativeProbe
|
|
3381
|
+
?? integration.driver.probeNativeHealth
|
|
3382
|
+
?? integration.driver.probeNative,
|
|
3051
3383
|
verifyHealth: true,
|
|
3052
3384
|
});
|
|
3053
3385
|
if (!target.requiresNative)
|
|
@@ -3146,7 +3478,7 @@ export async function discoverRebuildTargetNames(options) {
|
|
|
3146
3478
|
cwd: options.cwd,
|
|
3147
3479
|
rootNames: options.platform === 'codex' ? ['.agents', '.codex'] : ['.claude'],
|
|
3148
3480
|
managedPaths: options.platform === 'codex'
|
|
3149
|
-
? ['.codex/config.toml'
|
|
3481
|
+
? ['.codex/config.toml']
|
|
3150
3482
|
: ['.claude/settings.json'],
|
|
3151
3483
|
});
|
|
3152
3484
|
options = { ...options, cwd: canonicalRepoRoot };
|
|
@@ -3160,7 +3492,7 @@ export async function discoverRebuildTargetNames(options) {
|
|
|
3160
3492
|
names.add(name);
|
|
3161
3493
|
const skillRoots = options.platform === 'codex'
|
|
3162
3494
|
? options.scope === 'project'
|
|
3163
|
-
? [
|
|
3495
|
+
? []
|
|
3164
3496
|
: [path.join(resolveAwHome(options.env), 'plugins')]
|
|
3165
3497
|
: [path.join(paths.configDir, 'skills')];
|
|
3166
3498
|
if (options.platform === 'codex' && options.scope === 'user') {
|
|
@@ -3195,24 +3527,14 @@ export async function discoverRebuildTargetNames(options) {
|
|
|
3195
3527
|
for (const name of Object.keys(config.snapshot.developerInstructions.managedBlocks)) {
|
|
3196
3528
|
names.add(sharedOwnerPluginName(name));
|
|
3197
3529
|
}
|
|
3198
|
-
for (const server of Object.values(config.snapshot.mcpServers)) {
|
|
3199
|
-
const envValue = server.value?.env;
|
|
3200
|
-
const owner = envValue
|
|
3201
|
-
&& typeof envValue === 'object'
|
|
3202
|
-
&& !Array.isArray(envValue)
|
|
3203
|
-
&& typeof envValue[MCP_OWNER_ENV] === 'string'
|
|
3204
|
-
? envValue[MCP_OWNER_ENV]
|
|
3205
|
-
: null;
|
|
3206
|
-
if (owner)
|
|
3207
|
-
names.add(sharedOwnerPluginName(owner));
|
|
3208
|
-
}
|
|
3209
3530
|
if (options.scope === 'project') {
|
|
3210
|
-
const
|
|
3211
|
-
const
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3531
|
+
const suffix = `@${options.marketplaceName ?? MARKETPLACE_NAME}`;
|
|
3532
|
+
for (const pluginId of Object.keys(config.snapshot.plugins)) {
|
|
3533
|
+
if (!pluginId.endsWith(suffix))
|
|
3534
|
+
continue;
|
|
3535
|
+
const name = pluginId.slice(0, -suffix.length);
|
|
3536
|
+
if (/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(name))
|
|
3537
|
+
names.add(name);
|
|
3216
3538
|
}
|
|
3217
3539
|
}
|
|
3218
3540
|
else {
|