@lesliechan721/aw 0.1.0-beta.63 → 0.1.0-beta.65

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.
Files changed (302) hide show
  1. package/dist/authoring/assets/aw-runtime-config.mjs +3 -3
  2. package/dist/authoring/assets/aw-runtime-config.mjs.map +1 -1
  3. package/dist/authoring/scripts/add-skill.mjs +3 -17
  4. package/dist/authoring/scripts/add-skill.mjs.map +1 -1
  5. package/dist/authoring/scripts/init-plugin.mjs +1 -0
  6. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  7. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  8. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +2 -0
  9. package/dist/authoring/scripts/lib/skill-scaffold.mjs +2 -0
  10. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
  11. package/dist/authoring/scripts/validate-plugin.mjs +95 -698
  12. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  13. package/dist/scripts/aw-skill-eval-materializer.d.ts +2 -0
  14. package/dist/scripts/aw-skill-eval-materializer.js +74 -44
  15. package/dist/scripts/aw-skill-eval-materializer.js.map +1 -1
  16. package/dist/scripts/bundle-plugins.js +10 -2
  17. package/dist/scripts/bundle-plugins.js.map +1 -1
  18. package/dist/scripts/plugin-staging.d.ts +1 -1
  19. package/dist/scripts/plugin-staging.js +1 -1
  20. package/dist/scripts/plugin-staging.js.map +1 -1
  21. package/dist/scripts/test-plugin-scripts.js +31 -31
  22. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  23. package/dist/src/commands/aw-capabilities.d.ts +1 -1
  24. package/dist/src/commands/aw-capabilities.js +2 -0
  25. package/dist/src/commands/aw-capabilities.js.map +1 -1
  26. package/dist/src/commands/console.js +4 -3
  27. package/dist/src/commands/console.js.map +1 -1
  28. package/dist/src/commands/intent-command.d.ts +30 -0
  29. package/dist/src/commands/intent-command.js +164 -0
  30. package/dist/src/commands/intent-command.js.map +1 -0
  31. package/dist/src/commands/operation-plan.d.ts +2 -0
  32. package/dist/src/commands/operation-plan.js +2 -1
  33. package/dist/src/commands/operation-plan.js.map +1 -1
  34. package/dist/src/commands/options.d.ts +3 -11
  35. package/dist/src/commands/options.js +11 -17
  36. package/dist/src/commands/options.js.map +1 -1
  37. package/dist/src/commands/plugin-capabilities.js +27 -33
  38. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  39. package/dist/src/commands/rebuild-command.d.ts +108 -6
  40. package/dist/src/commands/rebuild-command.js +617 -1549
  41. package/dist/src/commands/rebuild-command.js.map +1 -1
  42. package/dist/src/commands/rebuild-integration.d.ts +19 -3
  43. package/dist/src/commands/rebuild-integration.js +500 -459
  44. package/dist/src/commands/rebuild-integration.js.map +1 -1
  45. package/dist/src/commands/rebuild-operations.js +1 -2
  46. package/dist/src/commands/rebuild-operations.js.map +1 -1
  47. package/dist/src/commands/review-inspection.d.ts +2 -2
  48. package/dist/src/commands/review-inspection.js +30 -86
  49. package/dist/src/commands/review-inspection.js.map +1 -1
  50. package/dist/src/commands/review-preparation.js +16 -7
  51. package/dist/src/commands/review-preparation.js.map +1 -1
  52. package/dist/src/commands/skill-eval.d.ts +2 -0
  53. package/dist/src/commands/skill-eval.js +15 -9
  54. package/dist/src/commands/skill-eval.js.map +1 -1
  55. package/dist/src/commands/status-v6.d.ts +38 -5
  56. package/dist/src/commands/status-v6.js +269 -102
  57. package/dist/src/commands/status-v6.js.map +1 -1
  58. package/dist/src/commands/targets-command.d.ts +27 -0
  59. package/dist/src/commands/targets-command.js +77 -0
  60. package/dist/src/commands/targets-command.js.map +1 -0
  61. package/dist/src/commands/write-commands.js +5 -5
  62. package/dist/src/commands/write-commands.js.map +1 -1
  63. package/dist/src/eval/manifest-v1.d.ts +2 -0
  64. package/dist/src/eval/manifest-v1.js +7 -2
  65. package/dist/src/eval/manifest-v1.js.map +1 -1
  66. package/dist/src/generators/local-plugin.d.ts +2 -1
  67. package/dist/src/generators/local-plugin.js +111 -108
  68. package/dist/src/generators/local-plugin.js.map +1 -1
  69. package/dist/src/index.d.ts +10 -17
  70. package/dist/src/index.js +585 -1349
  71. package/dist/src/index.js.map +1 -1
  72. package/dist/src/intent/deployment-preferences.d.ts +63 -0
  73. package/dist/src/intent/deployment-preferences.js +170 -0
  74. package/dist/src/intent/deployment-preferences.js.map +1 -0
  75. package/dist/src/intent/diagnostics.d.ts +11 -0
  76. package/dist/src/intent/diagnostics.js +14 -0
  77. package/dist/src/intent/diagnostics.js.map +1 -0
  78. package/dist/src/intent/intent-codec.d.ts +19 -0
  79. package/dist/src/intent/intent-codec.js +117 -0
  80. package/dist/src/intent/intent-codec.js.map +1 -0
  81. package/dist/src/intent/intent-store.d.ts +43 -0
  82. package/dist/src/intent/intent-store.js +118 -0
  83. package/dist/src/intent/intent-store.js.map +1 -0
  84. package/dist/src/intent/scope-context.d.ts +33 -0
  85. package/dist/src/intent/scope-context.js +145 -0
  86. package/dist/src/intent/scope-context.js.map +1 -0
  87. package/dist/src/intent/work-context.d.ts +13 -0
  88. package/dist/src/intent/work-context.js +22 -0
  89. package/dist/src/intent/work-context.js.map +1 -0
  90. package/dist/src/output/command-receipt.js +16 -9
  91. package/dist/src/output/command-receipt.js.map +1 -1
  92. package/dist/src/portable/commands.d.ts +18 -8
  93. package/dist/src/portable/commands.js +46 -562
  94. package/dist/src/portable/commands.js.map +1 -1
  95. package/dist/src/portable/historical-materialization.d.ts +22 -0
  96. package/dist/src/portable/historical-materialization.js +124 -0
  97. package/dist/src/portable/historical-materialization.js.map +1 -0
  98. package/dist/src/portable/materializer.d.ts +8 -0
  99. package/dist/src/portable/materializer.js +75 -44
  100. package/dist/src/portable/materializer.js.map +1 -1
  101. package/dist/src/portable/recovery-layout.d.ts +17 -0
  102. package/dist/src/portable/recovery-layout.js +55 -0
  103. package/dist/src/portable/recovery-layout.js.map +1 -0
  104. package/dist/src/portable/recovery.d.ts +143 -0
  105. package/dist/src/portable/recovery.js +339 -0
  106. package/dist/src/portable/recovery.js.map +1 -0
  107. package/dist/src/portable/writer.d.ts +64 -0
  108. package/dist/src/portable/writer.js +316 -0
  109. package/dist/src/portable/writer.js.map +1 -0
  110. package/dist/src/recovery/coordinator.d.ts +137 -0
  111. package/dist/src/recovery/coordinator.js +1198 -0
  112. package/dist/src/recovery/coordinator.js.map +1 -0
  113. package/dist/src/recovery/demand.d.ts +44 -0
  114. package/dist/src/recovery/demand.js +178 -0
  115. package/dist/src/recovery/demand.js.map +1 -0
  116. package/dist/src/recovery/joint-coordinator.d.ts +24 -0
  117. package/dist/src/recovery/joint-coordinator.js +770 -0
  118. package/dist/src/recovery/joint-coordinator.js.map +1 -0
  119. package/dist/src/recovery/joint-demand.d.ts +68 -0
  120. package/dist/src/recovery/joint-demand.js +166 -0
  121. package/dist/src/recovery/joint-demand.js.map +1 -0
  122. package/dist/src/recovery/receipt.d.ts +81 -0
  123. package/dist/src/recovery/receipt.js +2 -0
  124. package/dist/src/recovery/receipt.js.map +1 -0
  125. package/dist/src/recovery/retirement.d.ts +45 -0
  126. package/dist/src/recovery/retirement.js +366 -0
  127. package/dist/src/recovery/retirement.js.map +1 -0
  128. package/dist/src/recovery/status.d.ts +108 -0
  129. package/dist/src/recovery/status.js +417 -0
  130. package/dist/src/recovery/status.js.map +1 -0
  131. package/dist/src/recovery/types.d.ts +86 -0
  132. package/dist/src/recovery/types.js +2 -0
  133. package/dist/src/recovery/types.js.map +1 -0
  134. package/dist/src/review/review-profile.d.ts +2 -1
  135. package/dist/src/review/review-profile.js +15 -15
  136. package/dist/src/review/review-profile.js.map +1 -1
  137. package/dist/src/review/review-selection.d.ts +1 -2
  138. package/dist/src/review/review-selection.js +40 -114
  139. package/dist/src/review/review-selection.js.map +1 -1
  140. package/dist/src/review/review-types.d.ts +4 -4
  141. package/dist/src/review/review-types.js.map +1 -1
  142. package/dist/src/review/skill-materialization.js +15 -6
  143. package/dist/src/review/skill-materialization.js.map +1 -1
  144. package/dist/src/review/source-binding.d.ts +14 -4
  145. package/dist/src/review/source-binding.js +62 -117
  146. package/dist/src/review/source-binding.js.map +1 -1
  147. package/dist/src/tui/agent-management.d.ts +23 -0
  148. package/dist/src/tui/agent-management.js +217 -0
  149. package/dist/src/tui/agent-management.js.map +1 -0
  150. package/dist/src/tui/agent-settings.d.ts +44 -0
  151. package/dist/src/tui/agent-settings.js +98 -0
  152. package/dist/src/tui/agent-settings.js.map +1 -0
  153. package/dist/src/tui/components.d.ts +3 -0
  154. package/dist/src/tui/components.js +10 -1
  155. package/dist/src/tui/components.js.map +1 -1
  156. package/dist/src/tui/config-references.d.ts +6 -3
  157. package/dist/src/tui/config-references.js +17 -12
  158. package/dist/src/tui/config-references.js.map +1 -1
  159. package/dist/src/tui/console-app-v4.d.ts +1 -2
  160. package/dist/src/tui/console-app-v4.js +1533 -1047
  161. package/dist/src/tui/console-app-v4.js.map +1 -1
  162. package/dist/src/tui/controller-runtime.d.ts +2 -1
  163. package/dist/src/tui/controller-runtime.js +457 -1634
  164. package/dist/src/tui/controller-runtime.js.map +1 -1
  165. package/dist/src/tui/controller.d.ts +131 -81
  166. package/dist/src/tui/controller.js +307 -227
  167. package/dist/src/tui/controller.js.map +1 -1
  168. package/dist/src/tui/entity-cards.d.ts +2 -2
  169. package/dist/src/tui/entity-cards.js +98 -20
  170. package/dist/src/tui/entity-cards.js.map +1 -1
  171. package/dist/src/tui/glossary.d.ts +2 -0
  172. package/dist/src/tui/glossary.js +20 -0
  173. package/dist/src/tui/glossary.js.map +1 -1
  174. package/dist/src/tui/model.d.ts +28 -10
  175. package/dist/src/tui/model.js +41 -41
  176. package/dist/src/tui/model.js.map +1 -1
  177. package/dist/src/tui/operation-review-planner.d.ts +2 -0
  178. package/dist/src/tui/operation-review-planner.js +58 -122
  179. package/dist/src/tui/operation-review-planner.js.map +1 -1
  180. package/dist/src/tui/plugin-content.js +7 -4
  181. package/dist/src/tui/plugin-content.js.map +1 -1
  182. package/dist/src/tui/plugin-detail.d.ts +22 -3
  183. package/dist/src/tui/plugin-detail.js +113 -26
  184. package/dist/src/tui/plugin-detail.js.map +1 -1
  185. package/dist/src/tui/reader.d.ts +1 -0
  186. package/dist/src/tui/reader.js +3 -1
  187. package/dist/src/tui/reader.js.map +1 -1
  188. package/dist/src/tui/router.d.ts +23 -33
  189. package/dist/src/tui/router.js.map +1 -1
  190. package/dist/src/tui/scoped-flow.d.ts +45 -0
  191. package/dist/src/tui/scoped-flow.js +96 -0
  192. package/dist/src/tui/scoped-flow.js.map +1 -0
  193. package/dist/src/tui/scoped-inventory.d.ts +122 -0
  194. package/dist/src/tui/scoped-inventory.js +225 -0
  195. package/dist/src/tui/scoped-inventory.js.map +1 -0
  196. package/dist/src/tui/screen-registry.d.ts +25 -25
  197. package/dist/src/tui/screen-registry.js +3 -7
  198. package/dist/src/tui/screen-registry.js.map +1 -1
  199. package/dist/src/tui/session-console-app.js +1 -1
  200. package/dist/src/tui/session-console-app.js.map +1 -1
  201. package/dist/src/tui/session-host.js +12 -2
  202. package/dist/src/tui/session-host.js.map +1 -1
  203. package/dist/src/types.d.ts +15 -12
  204. package/dist/src/types.js.map +1 -1
  205. package/dist/src/utils/agent-version.js +2 -0
  206. package/dist/src/utils/agent-version.js.map +1 -1
  207. package/dist/src/utils/artifact-plan.js +13 -6
  208. package/dist/src/utils/artifact-plan.js.map +1 -1
  209. package/dist/src/utils/artifact-renderer.d.ts +6 -3
  210. package/dist/src/utils/artifact-renderer.js +27 -32
  211. package/dist/src/utils/artifact-renderer.js.map +1 -1
  212. package/dist/src/utils/artifact-request.d.ts +1 -0
  213. package/dist/src/utils/artifact-request.js +22 -12
  214. package/dist/src/utils/artifact-request.js.map +1 -1
  215. package/dist/src/utils/artifact-sources.d.ts +2 -2
  216. package/dist/src/utils/bundle-layout.js +18 -16
  217. package/dist/src/utils/bundle-layout.js.map +1 -1
  218. package/dist/src/utils/catalog-digests.js +2 -0
  219. package/dist/src/utils/catalog-digests.js.map +1 -1
  220. package/dist/src/utils/catalog-runtime-projection.d.ts +4 -3
  221. package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
  222. package/dist/src/utils/catalog-source-references.d.ts +5 -0
  223. package/dist/src/utils/catalog-source-references.js +42 -57
  224. package/dist/src/utils/catalog-source-references.js.map +1 -1
  225. package/dist/src/utils/claude-native-render-receipt.d.ts +14 -0
  226. package/dist/src/utils/claude-native-render-receipt.js +26 -0
  227. package/dist/src/utils/claude-native-render-receipt.js.map +1 -0
  228. package/dist/src/utils/claude-skills-root.js +14 -3
  229. package/dist/src/utils/claude-skills-root.js.map +1 -1
  230. package/dist/src/utils/codex-manager.js +6 -12
  231. package/dist/src/utils/codex-manager.js.map +1 -1
  232. package/dist/src/utils/codex-native-observation.js +29 -13
  233. package/dist/src/utils/codex-native-observation.js.map +1 -1
  234. package/dist/src/utils/codex-reconciler.d.ts +2 -5
  235. package/dist/src/utils/codex-reconciler.js +25 -1
  236. package/dist/src/utils/codex-reconciler.js.map +1 -1
  237. package/dist/src/utils/codex-surface-analysis.js +5 -3
  238. package/dist/src/utils/codex-surface-analysis.js.map +1 -1
  239. package/dist/src/utils/local-marketplace.d.ts +14 -2
  240. package/dist/src/utils/local-marketplace.js +209 -42
  241. package/dist/src/utils/local-marketplace.js.map +1 -1
  242. package/dist/src/utils/managed-command-evidence.js +1 -1
  243. package/dist/src/utils/managed-command-evidence.js.map +1 -1
  244. package/dist/src/utils/managed-command-materialization.d.ts +4 -0
  245. package/dist/src/utils/managed-command-materialization.js +15 -6
  246. package/dist/src/utils/managed-command-materialization.js.map +1 -1
  247. package/dist/src/utils/managed-command-store.d.ts +15 -0
  248. package/dist/src/utils/managed-command-store.js +73 -8
  249. package/dist/src/utils/managed-command-store.js.map +1 -1
  250. package/dist/src/utils/native-cli.d.ts +2 -0
  251. package/dist/src/utils/native-cli.js +22 -0
  252. package/dist/src/utils/native-cli.js.map +1 -1
  253. package/dist/src/utils/native-demand.d.ts +10 -0
  254. package/dist/src/utils/native-demand.js +4 -0
  255. package/dist/src/utils/native-demand.js.map +1 -0
  256. package/dist/src/utils/ownership.js +2 -0
  257. package/dist/src/utils/ownership.js.map +1 -1
  258. package/dist/src/utils/paths.js +1 -1
  259. package/dist/src/utils/paths.js.map +1 -1
  260. package/dist/src/utils/platform-support.d.ts +1 -1
  261. package/dist/src/utils/platform-support.js +1 -1
  262. package/dist/src/utils/platform-support.js.map +1 -1
  263. package/dist/src/utils/plugin-config-impact.d.ts +3 -0
  264. package/dist/src/utils/plugin-config-impact.js +115 -273
  265. package/dist/src/utils/plugin-config-impact.js.map +1 -1
  266. package/dist/src/utils/plugin-config-references.d.ts +11 -2
  267. package/dist/src/utils/plugin-config-references.js +85 -90
  268. package/dist/src/utils/plugin-config-references.js.map +1 -1
  269. package/dist/src/utils/plugin-config-write.d.ts +58 -1
  270. package/dist/src/utils/plugin-config-write.js +756 -809
  271. package/dist/src/utils/plugin-config-write.js.map +1 -1
  272. package/dist/src/utils/plugin-config.d.ts +47 -46
  273. package/dist/src/utils/plugin-config.js +292 -833
  274. package/dist/src/utils/plugin-config.js.map +1 -1
  275. package/dist/src/utils/plugin-scripts.d.ts +11 -6
  276. package/dist/src/utils/plugin-scripts.js +52 -35
  277. package/dist/src/utils/plugin-scripts.js.map +1 -1
  278. package/dist/src/utils/runtime-config.js +5 -4
  279. package/dist/src/utils/runtime-config.js.map +1 -1
  280. package/dist/src/utils/runtime-skill-closure.d.ts +2 -2
  281. package/dist/src/utils/runtime-skill-closure.js.map +1 -1
  282. package/dist/src/utils/state-paths.d.ts +8 -3
  283. package/dist/src/utils/state-paths.js +53 -16
  284. package/dist/src/utils/state-paths.js.map +1 -1
  285. package/dist/src/utils/windows-npm-shim.d.ts +2 -0
  286. package/dist/src/utils/windows-npm-shim.js +5 -7
  287. package/dist/src/utils/windows-npm-shim.js.map +1 -1
  288. package/dist/vitest.config.js +1 -0
  289. package/dist/vitest.config.js.map +1 -1
  290. package/package.json +3 -3
  291. package/dist/src/commands/sync-command.d.ts +0 -40
  292. package/dist/src/commands/sync-command.js +0 -254
  293. package/dist/src/commands/sync-command.js.map +0 -1
  294. package/dist/src/portable/skills-cli.d.ts +0 -51
  295. package/dist/src/portable/skills-cli.js +0 -202
  296. package/dist/src/portable/skills-cli.js.map +0 -1
  297. package/dist/src/tui/project-inventory.d.ts +0 -68
  298. package/dist/src/tui/project-inventory.js +0 -203
  299. package/dist/src/tui/project-inventory.js.map +0 -1
  300. package/dist/src/utils/plugin-intent-state.d.ts +0 -49
  301. package/dist/src/utils/plugin-intent-state.js +0 -320
  302. package/dist/src/utils/plugin-intent-state.js.map +0 -1
@@ -3,11 +3,11 @@ import { captureNativeToolChanges } from '../utils/native-tool-review.js';
3
3
  import { forceOfflineCleanupEvidence } from './offline-cleanup-evidence.js';
4
4
  import path from 'node:path';
5
5
  import fs from 'fs-extra';
6
- import { catalogFileMode } from '@lesliechan721/aw-plugin-core';
6
+ import { catalogFileMode, compilePluginConfigDefinition } from '@lesliechan721/aw-plugin-core';
7
7
  import { COMMAND_PRODUCER_RECORD_FILE, getManagedCommandArtifactTargets, getCommandPackageId } from '@lesliechan721/aw-plugin-core/manifest';
8
8
  import os from 'node:os';
9
9
  import { injectNativeToolClosureFiles, nativeToolsForCommandSets, commandSetsForProducer, createManagedCommandReferenceResolver, discoverRetainedManagedCommandPackages, retainedManagedCommandPackageResult, managedCommandProducerIdentity, prepareManagedCommandPackage, resolveSkillManagedCommandReferences, } from '../utils/managed-command-materialization.js';
10
- import { assertManagedCommandBindingIdentities, normalizeInstalledCommandProducer, managedCommandDiagnostic, ManagedCommandError, publishManagedCommandBindings, revokeManagedCommandBindings, syncManagedCommandPackage, readInstalledCommandProducer, listManagedCommands } from '../utils/managed-command-store.js';
10
+ import { assertManagedCommandBindingIdentities, captureManagedCommandBindingRecoveryEvidence, normalizeInstalledCommandProducer, managedCommandDiagnostic, ManagedCommandError, publishManagedCommandBindings, revokeManagedCommandBindings, syncManagedCommandPackage, readInstalledCommandProducer, listManagedCommands } from '../utils/managed-command-store.js';
11
11
  import { injectInstalledRuntimeConfig, carryRuntimeConfigNativeReceipt } from '../utils/runtime-config.js';
12
12
  import { resolveCodexSkillsRelativeRoot } from '../utils/codex-skills-root.js';
13
13
  import { resolveClaudeSkillsRelativeRoot } from '../utils/claude-skills-root.js';
@@ -17,7 +17,7 @@ import { generateCodexPermissionArtifacts, mergeClaudePermissions, } from '../ge
17
17
  import { buildGeneratedName } from '../generators/shared.js';
18
18
  import { applyConditionalCodexConfigTransactionFile, applyCodexConfigTransactionFile, composeManagedDeveloperInstructionsBlock, readCodexConfigFile, } from '../utils/codex-config.js';
19
19
  import { canonicalizePathThroughExistingAncestor, resolveClaudeProjectKey, resolveCodexProjectKey, } from '../utils/state-paths.js';
20
- import { createCodexSkillExpectedTree, createCodexSkillStagingTreeContentDigest, } from '../utils/codex-skill-staging.js';
20
+ import { createCodexSkillStagingTreeContentDigest, } from '../utils/codex-skill-staging.js';
21
21
  import { AW_PLUGIN_REQUIREMENTS_RECEIPT_PATH, createDynamicSkillExpectedTree, createDynamicSkillTreeContentDigest, readDynamicSkillTree, validateSkillDirectory, writeDynamicSkillTree, } from '../utils/dynamic-skill-tree.js';
22
22
  import { parseCodexSharedHooksFile, serializeTrackedHookGroupIdentity, } from '../utils/hooks-contract.js';
23
23
  import { buildCodexMarketplaceAddInvocation, buildCodexMarketplaceRemoveInvocation, buildCodexPluginAddInvocation, buildCodexPluginRemoveInvocation, CodexProjectConfigNotEffectiveError, runNativeCliChecked, SYSTEM_CODEX_MANAGER, } from '../utils/native-cli.js';
@@ -26,7 +26,7 @@ import { OWNED_TEXT_HEADER_PREFIX, createSharedOwnerToken, createSkillOwnerMarke
26
26
  import { resolveArtifactRenderConfig, resolveArtifactRendererTarget, runArtifactRenderer, } from '../utils/artifact-renderer.js';
27
27
  import { createArtifactConfigDigest, validateArtifactPlan, } from '../utils/artifact-plan.js';
28
28
  import { resolveAwDeliveredArtifactRequestBatches } from '../utils/artifact-request.js';
29
- import { createAwPluginRequirementsReceipt, parseAwPluginRequirementsReceipt, tryParseStrictSemVer, } from '../utils/manifest.js';
29
+ import { createAwPluginRequirementsReceipt, parseAwPluginRequirementsReceipt, readPluginManifest, tryParseStrictSemVer, } from '../utils/manifest.js';
30
30
  import { resolvePlatformEntries } from '../utils/platform-entries.js';
31
31
  import { resolveAwHome, resolveClaudePaths, resolveCodexPaths, resolveRepoRoot, getCodexHome, } from '../utils/paths.js';
32
32
  import { assertNoSensitiveConfigInFiles, collectSensitivePluginConfigValues, runPreApplyScript, } from '../utils/plugin-scripts.js';
@@ -34,11 +34,12 @@ import { validateRuntimeSkillClosure } from '../utils/runtime-skill-closure.js';
34
34
  import { findSensitiveTokenPath } from '../utils/sensitive-content.js';
35
35
  import { atomicRemoveConfigFile, atomicReplaceConfigFile, withConfigFileMutation, } from '../utils/plugin-config.js';
36
36
  import { readCatalogSourcesConfigSnapshot } from '../utils/catalog-sources.js';
37
- import { assertSafeNamespacedMarketplacePluginRoot, getNamespacedMarketplaceName, MarketplaceRootValidationError, projectMarketplaceManifestForPlatform, readStrictNamespacedMarketplaceRoot, replayNamespacedMarketplacePluginProjections, refreshPreservedPlatformReceipt, replayNamespacedCodexSkillOverlays, } from '../utils/local-marketplace.js';
37
+ import { assertSafeNamespacedMarketplacePluginRoot, getNamespacedMarketplaceName, MarketplaceRootValidationError, projectMarketplaceManifestForPlatform, readStrictNamespacedMarketplaceRoot, deferNativeMarketplacePublications, replayNamespacedMarketplacePluginProjections, refreshPreservedPlatformReceipt, replayNamespacedCodexSkillOverlays, } from '../utils/local-marketplace.js';
38
38
  import { commitMarketplaceGenerationBackup } from '../utils/orphan-marketplace-cleanup.js';
39
39
  import { readClaudeSettings, writeClaudeSettings } from '../adapters/helpers.js';
40
40
  import { analyzeCodexSurface } from '../utils/codex-surface-analysis.js';
41
- import { CODEX_NATIVE_RENDER_RECEIPT_PATH, codexNativeRenderProjectionsEqual, createCodexNativeRenderProjection, createCodexNativeRenderReceipt, parseCodexNativeRenderReceipt, serializeCodexNativeRenderReceipt, } from '../utils/codex-native-render-receipt.js';
41
+ import { codexNativeRenderProjectionsEqual, createCodexNativeRenderProjection, createCodexNativeRenderReceipt, } from '../utils/codex-native-render-receipt.js';
42
+ import { createClaudeNativeRenderReceipt, nativeSkillRenderReceiptPath, parseNativeSkillRenderReceipt, serializeNativeSkillRenderReceipt, } from '../utils/claude-native-render-receipt.js';
42
43
  import { inspectCodexSharedNative, } from '../utils/codex-shared-native.js';
43
44
  import { calculateCodexNativeRenderPayloadDigest } from '../utils/catalog-digests.js';
44
45
  import { createCodexNativeObservationSession, } from '../utils/codex-native-observation.js';
@@ -74,11 +75,21 @@ function withoutVerifiedRequirementsReceipt(plugin, files) {
74
75
  const commandPackagePreparationCaches = new WeakMap();
75
76
  const staticCommandPreparationCaches = new WeakMap();
76
77
  const dynamicArtifactPreparationCaches = new WeakMap();
78
+ function artifactRenderResults(context) {
79
+ if (context.preparedArtifactRenderResults)
80
+ return context.preparedArtifactRenderResults;
81
+ let results = dynamicArtifactPreparationCaches.get(context);
82
+ if (!results) {
83
+ results = new Map();
84
+ dynamicArtifactPreparationCaches.set(context, results);
85
+ }
86
+ return results;
87
+ }
77
88
  async function prepareStaticCommandArtifacts(options) {
78
89
  const targets = getManagedCommandArtifactTargets(options.plugin.manifest).filter((target) => target.producer.kind === 'static-skill' && target.platform === options.platform);
79
90
  if (!targets.length)
80
91
  return [];
81
- const config = await resolveArtifactRenderConfig({ sourceId: options.plugin.sourceId, sourceIdentity: options.plugin.sourceIdentity, logicalIdentity: options.plugin.catalogLogicalIdentity, pluginName: options.plugin.manifest.name, manifest: options.plugin.manifest, scope: 'user', cwd: options.cwd, env: options.env, referencePlugins: options.context.referencePlugins });
92
+ const config = await resolveArtifactRenderConfig({ sourceId: options.plugin.sourceId, sourceIdentity: options.plugin.sourceIdentity, logicalIdentity: options.plugin.catalogLogicalIdentity, pluginName: options.plugin.manifest.name, manifest: options.plugin.manifest, platform: options.platform, scope: 'user', cwd: options.plugin.rootDir, env: options.env, referencePlugins: options.context.referencePlugins });
82
93
  const key = JSON.stringify([options.plugin.rootDir, options.platform, config]);
83
94
  let cache = staticCommandPreparationCaches.get(options.context);
84
95
  if (!cache) {
@@ -88,7 +99,7 @@ async function prepareStaticCommandArtifacts(options) {
88
99
  let prepared = cache.get(key);
89
100
  if (!prepared) {
90
101
  prepared = (async () => {
91
- const rendered = await runArtifactRenderer({ plugin: options.plugin, referencePlugins: options.context.referencePlugins, event: 'install', platform: options.platform, scope: 'user', configScope: 'user', cwd: options.cwd, commandEnv: options.env, requestedArtifactIds: targets.map((target) => target.id) });
102
+ const rendered = await runArtifactRenderer({ plugin: options.plugin, referencePlugins: options.context.referencePlugins, event: 'install', platform: options.platform, scope: 'user', configScope: 'user', cwd: options.plugin.rootDir, commandEnv: options.env, requestedArtifactIds: targets.map((target) => target.id), signal: options.context.signal, scriptTimeoutMs: options.context.scriptTimeoutMs });
92
103
  return validateArtifactPlan({ manifest: options.plugin.manifest, plan: rendered.plan, platform: options.platform, scope: 'user', requestedArtifactIds: rendered.context.requestedArtifactIds, renderConfig: rendered.context.config, rendererDigest: rendered.target.rendererDigest, manifestDigest: rendered.target.manifestDigest }).artifacts;
93
104
  })();
94
105
  cache.set(key, prepared);
@@ -128,7 +139,7 @@ async function commandPackageActions(options) {
128
139
  let preparation = cache.get(getCommandPackageId(producer));
129
140
  if (!preparation) {
130
141
  preparation = (async () => {
131
- const prepared = await prepareManagedCommandPackage({ ...options, referencePlugins: options.context.referencePlugins, packageKey: declaration.key, scope: declaration.scope });
142
+ const prepared = await prepareManagedCommandPackage({ ...options, referencePlugins: options.context.referencePlugins, packageKey: declaration.key, scope: declaration.scope, signal: options.context.signal, scriptTimeoutMs: options.context.scriptTimeoutMs });
132
143
  try {
133
144
  const files = [];
134
145
  async function visit(directory, prefix) {
@@ -194,7 +205,7 @@ async function prepareStaticNativeSkillActions(options) {
194
205
  return producer.kind === 'static-skill' && target.platform === options.platform && !artifacts.some((artifact) => artifact.id === target.id) && !options.commandCandidates.some((candidate) => candidate.producer.kind === 'static-skill' && candidate.producer.key === producer.skillKey && candidate.producer.platform === options.platform && candidate.producer.scope === scope);
195
206
  });
196
207
  if (missingTargets.length) {
197
- const rendered = await runArtifactRenderer({ plugin: options.plugin, event: 'install', platform: options.platform, scope, configScope: scope, cwd: options.cwd, commandEnv: options.env, requestedArtifactIds: missingTargets.map((target) => target.id) });
208
+ const rendered = await runArtifactRenderer({ plugin: options.plugin, event: 'install', platform: options.platform, scope, configScope: scope, cwd: options.plugin.rootDir, commandEnv: options.env, requestedArtifactIds: missingTargets.map((target) => target.id), signal: options.signal, scriptTimeoutMs: options.scriptTimeoutMs });
198
209
  artifacts.push(...validateArtifactPlan({ manifest: options.plugin.manifest, plan: rendered.plan, platform: options.platform, scope, requestedArtifactIds: rendered.context.requestedArtifactIds, renderConfig: rendered.context.config, rendererDigest: rendered.target.rendererDigest, manifestDigest: rendered.target.manifestDigest }).artifacts);
199
210
  }
200
211
  for (const entry of await fs.readdir(root, { withFileTypes: true })) {
@@ -511,48 +522,9 @@ function pathComponent(options) {
511
522
  validateHealth: true,
512
523
  };
513
524
  }
514
- function pristineTreeDescriptor(tree) {
515
- return Object.entries(tree.files)
516
- .sort(([left], [right]) => left.localeCompare(right))
517
- .map(([relativePath, content]) => ({
518
- relativePath,
519
- contentDigest: `sha256:${crypto.createHash('sha256').update(content).digest('hex')}`,
520
- ...(tree.fileModes?.[relativePath] ? { mode: tree.fileModes[relativePath] } : {}),
521
- }));
522
- }
523
525
  function pluginActionId(plugin) {
524
526
  return plugin.pluginId ?? plugin.manifest.name;
525
527
  }
526
- function skillWriteAction(options) {
527
- const files = [
528
- ...Object.entries(options.tree.files).map(([relativePath, content]) => ({
529
- relativePath,
530
- contentBase64: content.toString('base64'),
531
- contentDigest: `sha256:${crypto.createHash('sha256').update(content).digest('hex')}`,
532
- ...(options.tree.fileModes?.[relativePath] ? { mode: options.tree.fileModes[relativePath] } : {}),
533
- })),
534
- {
535
- relativePath: '.agent-workflows-owner.json',
536
- contentBase64: Buffer.from(createSkillOwnerMarkerContent(options.identity)).toString('base64'),
537
- contentDigest: `sha256:${crypto.createHash('sha256')
538
- .update(createSkillOwnerMarkerContent(options.identity)).digest('hex')}`,
539
- },
540
- ].sort((left, right) => left.relativePath.localeCompare(right.relativePath));
541
- const contentDigest = `sha256:${crypto.createHash('sha256').update(JSON.stringify(files)).digest('hex')}`;
542
- return {
543
- kind: 'writeOwnedArtifact',
544
- pluginId: pluginActionId(options.plugin),
545
- platform: options.platform,
546
- scope: options.scope,
547
- path: options.path,
548
- allowedRoot: options.allowedRoot,
549
- owner: options.identity,
550
- artifactKind: 'skill-directory',
551
- files,
552
- contentDigest,
553
- allowPristineUnowned: options.allowPristineUnowned,
554
- };
555
- }
556
528
  function finalizeOwnedArtifactActions(actions) {
557
529
  for (const action of actions) {
558
530
  if (action.kind !== 'writeOwnedArtifact' || !action.owner)
@@ -830,6 +802,29 @@ async function codexRoleRegistrationOwned(options) {
830
802
  return false;
831
803
  }
832
804
  }
805
+ export async function removeForceCleanupCodexRoleRegistration(options) {
806
+ const component = options.component;
807
+ if (component.kind !== 'owned-text-file' || component.identity.platform !== 'codex')
808
+ return;
809
+ const paths = resolveCodexPaths(options.cwd, component.identity.scope, options.env);
810
+ const roleKey = component.identity.artifactKey;
811
+ const expectedPath = path.join(paths.agentsDir, `${buildGeneratedName(component.identity.plugin, roleKey)}.toml`);
812
+ if (path.resolve(component.path) !== path.resolve(expectedPath))
813
+ return;
814
+ await applyConditionalCodexConfigTransactionFile(paths.configTomlPath, async (snapshot) => {
815
+ const registration = snapshot.agents[roleKey];
816
+ if (!registration?.configFile
817
+ || path.resolve(path.dirname(paths.configTomlPath), registration.configFile)
818
+ !== path.resolve(component.path))
819
+ return null;
820
+ // Force authorizes the existing exclusive file. The matching registration is
821
+ // removed before that evidence disappears; missing or foreign files grant no authority.
822
+ const inspected = await inspectOwnedComponents({ components: [component], forceExclusive: true });
823
+ return inspected.components[0]?.state === 'present'
824
+ ? { removeAgentRegistrations: [roleKey] }
825
+ : null;
826
+ });
827
+ }
833
828
  function createCodexRoleRegistrationComponent(options) {
834
829
  return {
835
830
  kind: 'shared-config',
@@ -1127,7 +1122,7 @@ function renderCodexRole(options) {
1127
1122
  ].join('\n');
1128
1123
  }
1129
1124
  async function resolveDynamicArtifacts(options) {
1130
- const preparedArtifacts = options.platform === 'codex' && options.context
1125
+ const preparedArtifacts = options.context
1131
1126
  ? await prepareStaticCommandArtifacts({ ...options, context: options.context }) : [];
1132
1127
  const preparedIds = new Set(preparedArtifacts.map((artifact) => artifact.id));
1133
1128
  const requestBatches = (options.requestedArtifactIds
@@ -1141,11 +1136,7 @@ async function resolveDynamicArtifacts(options) {
1141
1136
  return { artifacts: [], sourceDirs: () => [], sensitiveValues: [] };
1142
1137
  }
1143
1138
  const previousArtifacts = [...options.previousArtifacts];
1144
- let preparedResults = options.context && dynamicArtifactPreparationCaches.get(options.context);
1145
- if (options.context && !preparedResults) {
1146
- preparedResults = new Map();
1147
- dynamicArtifactPreparationCaches.set(options.context, preparedResults);
1148
- }
1139
+ const preparedResults = options.context && artifactRenderResults(options.context);
1149
1140
  const renders = [];
1150
1141
  for (const requestedArtifactIds of requestBatches) {
1151
1142
  renders.push(await runArtifactRenderer({
@@ -1159,6 +1150,7 @@ async function resolveDynamicArtifacts(options) {
1159
1150
  previousArtifacts,
1160
1151
  requestedArtifactIds,
1161
1152
  scriptTimeoutMs: options.scriptTimeoutMs,
1153
+ signal: options.signal,
1162
1154
  preparedResults,
1163
1155
  }));
1164
1156
  }
@@ -1168,6 +1160,7 @@ async function resolveDynamicArtifacts(options) {
1168
1160
  logicalIdentity: options.plugin.catalogLogicalIdentity,
1169
1161
  pluginName: options.plugin.manifest.name,
1170
1162
  manifest: options.plugin.manifest,
1163
+ platform: options.platform,
1171
1164
  referencePlugins: options.referencePlugins ?? options.context?.referencePlugins,
1172
1165
  scope: options.scope,
1173
1166
  cwd: options.cwd,
@@ -1194,55 +1187,7 @@ async function resolveDynamicArtifacts(options) {
1194
1187
  artifacts,
1195
1188
  runtimeConfigSnapshots: Object.assign({}, ...renders.map((render) => render.runtimeConfigSnapshots)),
1196
1189
  sourceDirs: (artifact) => sourceDirsByArtifact.get(`${artifact.id}\0${artifact.target}`) ?? [],
1197
- sensitiveValues: collectSensitivePluginConfigValues(options.plugin.manifest, config.values),
1198
- };
1199
- }
1200
- function dynamicSkillWrite(options) {
1201
- const skillKey = 'skillKey' in options.artifact ? options.artifact.skillKey : '';
1202
- const identity = ownerIdentity(options.plugin.manifest.name, skillKey, options.platform, options.scope);
1203
- const component = pathComponent({
1204
- kind: 'skill-directory',
1205
- path: options.skillPath,
1206
- allowedRoot: options.allowedRoot,
1207
- identity,
1208
- ...(options.platform === 'codex' && options.scope === 'user'
1209
- ? {
1210
- pristineTree: pristineTreeDescriptor(options.tree),
1211
- }
1212
- : {}),
1213
- });
1214
- return {
1215
- artifact: {
1216
- path: options.skillPath,
1217
- paths: Object.keys(options.tree.files).map((relativePath) => path.join(options.skillPath, relativePath.split('/').join(path.sep))),
1218
- kind: 'skill',
1219
- platform: options.platform,
1220
- artifactKey: skillKey,
1221
- id: options.artifact.id,
1222
- target: options.artifact.target,
1223
- state: options.artifact.state,
1224
- ...('disabledReason' in options.artifact && options.artifact.disabledReason
1225
- ? { disabledReason: options.artifact.disabledReason }
1226
- : {}),
1227
- refreshKeys: [...options.artifact.refreshKeys],
1228
- configDigest: options.artifact.configDigest,
1229
- contentDigest: options.platform === 'codex'
1230
- ? createCodexSkillStagingTreeContentDigest(options.tree)
1231
- : createDynamicSkillTreeContentDigest(options.tree),
1232
- },
1233
- ...(options.artifact.state === 'present' ? { component } : {}),
1234
- ...(options.artifact.state === 'present' ? {
1235
- action: skillWriteAction({
1236
- plugin: options.plugin,
1237
- platform: options.platform,
1238
- scope: options.scope,
1239
- path: options.skillPath,
1240
- allowedRoot: options.allowedRoot,
1241
- identity,
1242
- tree: options.tree,
1243
- allowPristineUnowned: options.platform === 'codex' && options.scope === 'user',
1244
- }),
1245
- } : {}),
1190
+ sensitiveValues: collectSensitivePluginConfigValues(options.plugin.manifest, config.values, options.platform),
1246
1191
  };
1247
1192
  }
1248
1193
  async function buildClaudeWrites(options) {
@@ -1254,38 +1199,10 @@ async function buildClaudeWrites(options) {
1254
1199
  previousArtifacts: options.historicalArtifacts,
1255
1200
  });
1256
1201
  const commandCandidates = [...(options.commandCandidates ?? [])];
1257
- const preparedSkills = [];
1258
- for (const artifact of dynamic.artifacts.filter((entry) => entry.target === 'claude.skill')) {
1259
- const tree = await createDynamicSkillExpectedTree({
1260
- artifact,
1261
- sourceDirs: dynamic.sourceDirs(artifact),
1262
- requireReadme: true,
1263
- requirementsReceipt: requirementsReceipt(options.plugin),
1264
- sourceRequirementsReceiptPolicy: 'allow',
1265
- });
1266
- await injectInstalledRuntimeConfig(tree, dynamic.runtimeConfigSnapshots?.[artifact.id]);
1267
- const candidate = await prepareSkillCommandCandidate({ ...options, producer: { kind: 'artifact', artifactId: artifact.id }, platform: 'claude', tree, artifacts: dynamic.artifacts });
1268
- if (candidate)
1269
- commandCandidates.push(candidate);
1270
- preparedSkills.push({ artifact, tree });
1271
- }
1272
1202
  const staticSkills = await prepareStaticNativeSkillActions({ ...options, platform: 'claude', artifacts: dynamic.artifacts, commandCandidates });
1273
1203
  commandCandidates.push(...staticSkills.candidates);
1274
1204
  options.nativeSkillActions?.push(...staticSkills.actions);
1275
1205
  const commandResolver = await createManagedCommandReferenceResolver({ ...options, platform: 'claude', candidates: commandCandidates });
1276
- for (const { artifact, tree } of preparedSkills) {
1277
- const skillKey = artifact.skillKey;
1278
- resolveSkillManagedCommandReferences(tree, commandResolver);
1279
- assertNoSensitiveConfigInFiles(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), dynamic.sensitiveValues, 'artifactRendererSensitiveConfigExposed: Final dynamic Skill contains sensitive config.');
1280
- writes.push(dynamicSkillWrite({
1281
- ...options,
1282
- platform: 'claude',
1283
- artifact,
1284
- skillPath: path.join(paths.configDir, 'skills', skillKey),
1285
- allowedRoot: path.join(paths.configDir, 'skills'),
1286
- tree,
1287
- }));
1288
- }
1289
1206
  for (const artifact of generateInstructionArtifacts(options.plugin.manifest.name, resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'claude'), 'claude')) {
1290
1207
  writes.push(generatedTextWrite({
1291
1208
  ...options,
@@ -1333,43 +1250,11 @@ async function buildCodexWrites(options) {
1333
1250
  });
1334
1251
  const dynamicInstructions = dynamic.artifacts.filter((entry) => entry.target === 'codex.developerInstructionsBlock');
1335
1252
  const dynamicRoles = dynamic.artifacts.filter((entry) => entry.target === 'codex.agentRole');
1336
- const dynamicSkills = dynamic.artifacts.filter((entry) => entry.target === 'codex.skill');
1337
1253
  const commandCandidates = [...(options.commandCandidates ?? [])];
1338
- const preparedSkills = [];
1339
- const repoRoot = await resolveRepoRoot(options.cwd);
1340
- const skillRoot = options.scope === 'user'
1341
- ? path.join(getCodexHome(options.env), 'skills')
1342
- : path.join(repoRoot, '.agents', 'skills');
1343
- for (const artifact of dynamicSkills) {
1344
- const tree = await createCodexSkillExpectedTree({
1345
- artifact,
1346
- sourceDirs: dynamic.sourceDirs(artifact),
1347
- requireReadme: true,
1348
- requirementsReceipt: requirementsReceipt(options.plugin),
1349
- sourceRequirementsReceiptPolicy: 'allow',
1350
- });
1351
- await injectInstalledRuntimeConfig(tree, dynamic.runtimeConfigSnapshots?.[artifact.id]);
1352
- const candidate = await prepareSkillCommandCandidate({ ...options, producer: { kind: 'artifact', artifactId: artifact.id }, platform: 'codex', tree, artifacts: dynamic.artifacts });
1353
- if (candidate)
1354
- commandCandidates.push(candidate);
1355
- preparedSkills.push({ artifact, tree });
1356
- }
1357
1254
  const staticSkills = await prepareStaticNativeSkillActions({ ...options, platform: 'codex', artifacts: dynamic.artifacts, commandCandidates });
1358
1255
  commandCandidates.push(...staticSkills.candidates);
1359
1256
  options.nativeSkillActions?.push(...staticSkills.actions);
1360
1257
  const commandResolver = await createManagedCommandReferenceResolver({ ...options, platform: 'codex', candidates: commandCandidates });
1361
- for (const { artifact, tree } of preparedSkills) {
1362
- resolveSkillManagedCommandReferences(tree, commandResolver);
1363
- assertNoSensitiveConfigInFiles(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), dynamic.sensitiveValues, 'artifactRendererSensitiveConfigExposed: Final dynamic Skill contains sensitive config.');
1364
- writes.push(dynamicSkillWrite({
1365
- ...options,
1366
- platform: 'codex',
1367
- artifact,
1368
- skillPath: path.join(skillRoot, artifact.skillKey),
1369
- allowedRoot: skillRoot,
1370
- tree,
1371
- }));
1372
- }
1373
1258
  const staticInstructions = dynamicInstructions.length > 0
1374
1259
  ? []
1375
1260
  : resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'codex');
@@ -1603,40 +1488,9 @@ async function buildInspectionWrites(options) {
1603
1488
  }),
1604
1489
  });
1605
1490
  }
1606
- for (const target of options.plugin.manifest.artifacts?.targets ?? []) {
1607
- if (target.platform !== 'claude'
1608
- || !target.scopes.includes(options.scope)
1609
- || target.target !== 'claude.skill'
1610
- || !target.skillKey)
1611
- continue;
1612
- const state = target.states.includes('present') ? 'present' : 'disabled';
1613
- const skillPath = path.join(paths.configDir, 'skills', target.skillKey);
1614
- const component = pathComponent({
1615
- kind: 'skill-directory',
1616
- path: skillPath,
1617
- allowedRoot: path.dirname(skillPath),
1618
- identity: ownerIdentity(options.plugin.manifest.name, target.skillKey, 'claude', options.scope),
1619
- });
1620
- writes.push({
1621
- artifact: {
1622
- path: skillPath,
1623
- kind: 'skill',
1624
- platform: 'claude',
1625
- artifactKey: target.skillKey,
1626
- id: target.id,
1627
- target: target.target,
1628
- state,
1629
- },
1630
- ...(state === 'present' ? { component } : {}),
1631
- ...(target.states.includes('present') && target.states.includes('disabled')
1632
- ? { optional: true }
1633
- : {}),
1634
- });
1635
- }
1636
1491
  return writes;
1637
1492
  }
1638
1493
  const paths = resolveCodexPaths(options.cwd, options.scope, options.env);
1639
- const repoRoot = await resolveRepoRoot(options.cwd);
1640
1494
  const instructions = resolvePlatformEntries(options.plugin.manifest.extensions?.instructions, 'codex');
1641
1495
  const targets = (options.plugin.manifest.artifacts?.targets ?? []).filter((target) => target.platform === 'codex' && target.scopes.includes(options.scope));
1642
1496
  const instructionTargets = targets.filter((target) => target.target === 'codex.developerInstructionsBlock');
@@ -1655,37 +1509,8 @@ async function buildInspectionWrites(options) {
1655
1509
  ...(instructions.length === 0 && instructionOptional ? { optional: true } : {}),
1656
1510
  });
1657
1511
  }
1658
- const dynamicSkillRoot = options.scope === 'user'
1659
- ? path.join(getCodexHome(options.env), 'skills')
1660
- : path.join(repoRoot, '.agents', 'skills');
1661
1512
  for (const target of targets) {
1662
1513
  const state = target.states.includes('present') ? 'present' : 'disabled';
1663
- if (target.target === 'codex.skill'
1664
- && target.delivery?.mode === 'aw-extension'
1665
- && target.skillKey) {
1666
- const skillPath = path.join(dynamicSkillRoot, target.skillKey);
1667
- const component = pathComponent({
1668
- kind: 'skill-directory',
1669
- path: skillPath,
1670
- allowedRoot: dynamicSkillRoot,
1671
- identity: ownerIdentity(options.plugin.manifest.name, target.skillKey, 'codex', options.scope),
1672
- });
1673
- writes.push({
1674
- artifact: {
1675
- path: skillPath,
1676
- kind: 'skill',
1677
- platform: 'codex',
1678
- artifactKey: target.skillKey,
1679
- id: target.id,
1680
- target: target.target,
1681
- state,
1682
- },
1683
- ...(state === 'present' ? { component } : {}),
1684
- ...(target.states.includes('present') && target.states.includes('disabled')
1685
- ? { optional: true }
1686
- : {}),
1687
- });
1688
- }
1689
1514
  if (target.target === 'codex.agentRole' && target.roleKey) {
1690
1515
  const rolePath = path.join(paths.configDir, 'agents', `${buildGeneratedName(options.plugin.manifest.name, target.roleKey)}.toml`);
1691
1516
  const roleComponent = pathComponent({
@@ -1919,9 +1744,9 @@ async function codexPayloadPathSafe(payloadRoot, allowedRoot = payloadRoot) {
1919
1744
  }
1920
1745
  return true;
1921
1746
  }
1922
- class CodexNativeProjectionUnsafeError extends Error {
1747
+ class NativeSkillProjectionUnsafeError extends Error {
1923
1748
  }
1924
- async function resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot) {
1749
+ async function resolveNativeSkillsRoot(payloadRoot, rawSkillsRoot, platform) {
1925
1750
  const normalizedSeparators = rawSkillsRoot.replace(/\\/gu, '/');
1926
1751
  const relativeRoot = path.posix.normalize(normalizedSeparators.replace(/^\.\//u, ''));
1927
1752
  if (!relativeRoot
@@ -1930,21 +1755,33 @@ async function resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot) {
1930
1755
  || relativeRoot.startsWith('../')
1931
1756
  || path.posix.isAbsolute(normalizedSeparators)
1932
1757
  || path.win32.isAbsolute(rawSkillsRoot)) {
1933
- throw new CodexNativeProjectionUnsafeError('codexNativeSkillsRootInvalid: Codex native Skills root is invalid.');
1758
+ throw new NativeSkillProjectionUnsafeError(`${platform}NativeSkillsRootInvalid: Native Skills root is invalid.`);
1934
1759
  }
1935
1760
  const root = path.join(payloadRoot, ...relativeRoot.split('/'));
1936
1761
  if (!await codexReadPathSafe(payloadRoot, root)) {
1937
- throw new CodexNativeProjectionUnsafeError('codexNativeSkillsRootInvalid: Codex native Skills root is unsafe.');
1762
+ throw new NativeSkillProjectionUnsafeError(`${platform}NativeSkillsRootInvalid: Native Skills root is unsafe.`);
1938
1763
  }
1939
1764
  return { relativeRoot, root };
1940
1765
  }
1941
1766
  function codexNativeRenderTargets(plugin) {
1942
1767
  return (plugin.manifest.artifacts?.targets ?? []).filter((target) => target.platform === 'codex'
1943
- && target.target === 'codex.skill'
1944
- && target.delivery?.mode === 'codex-native');
1768
+ && target.target === 'codex.skill');
1945
1769
  }
1946
- async function readCodexNativeRenderReceiptEvidence(payloadRoot) {
1947
- const receiptPath = path.join(payloadRoot, CODEX_NATIVE_RENDER_RECEIPT_PATH);
1770
+ function nativeSkillRefreshKeys(plugin, target) {
1771
+ const commandKeys = getManagedCommandArtifactTargets(plugin.manifest).flatMap((command) => command.producer.kind === 'artifact'
1772
+ && command.producer.artifactId === target.id
1773
+ && command.platform === target.platform
1774
+ ? command.refreshKeys
1775
+ : []);
1776
+ return [...new Set([...target.refreshKeys, ...commandKeys])];
1777
+ }
1778
+ function nativeSkillContentDigest(platform, tree) {
1779
+ return platform === 'codex'
1780
+ ? createCodexSkillStagingTreeContentDigest(tree)
1781
+ : createDynamicSkillTreeContentDigest(tree);
1782
+ }
1783
+ async function readNativeSkillRenderReceiptEvidence(payloadRoot, platform) {
1784
+ const receiptPath = path.join(payloadRoot, nativeSkillRenderReceiptPath(platform));
1948
1785
  const stats = await lstatIfPresent(receiptPath);
1949
1786
  if (!stats)
1950
1787
  return { state: 'absent' };
@@ -1958,16 +1795,16 @@ async function readCodexNativeRenderReceiptEvidence(payloadRoot) {
1958
1795
  return { state: 'unreadable' };
1959
1796
  }
1960
1797
  try {
1961
- return { state: 'present', receipt: parseCodexNativeRenderReceipt(content) };
1798
+ return { state: 'present', receipt: parseNativeSkillRenderReceipt(platform, content) };
1962
1799
  }
1963
1800
  catch {
1964
1801
  return { state: 'invalid' };
1965
1802
  }
1966
1803
  }
1967
- function codexNativeRenderEvidenceIssue(reason, diagnostic) {
1804
+ function nativeSkillRenderEvidenceIssue(reason, diagnostic) {
1968
1805
  return { state: 'issue', reason, diagnostic };
1969
1806
  }
1970
- async function readCodexNativeProjectionManifest(manifestPath) {
1807
+ async function readNativeSkillProjectionManifest(manifestPath) {
1971
1808
  let stats;
1972
1809
  try {
1973
1810
  stats = await lstatIfPresent(manifestPath);
@@ -1989,142 +1826,146 @@ async function readCodexNativeProjectionManifest(manifestPath) {
1989
1826
  return { state: error instanceof SyntaxError ? 'invalid' : 'unreadable' };
1990
1827
  }
1991
1828
  }
1992
- async function resolveCodexNativeRenderExpectedEvidence(options) {
1829
+ async function resolveNativeSkillRenderExpectedEvidence(options) {
1830
+ const { platform } = options;
1993
1831
  const logicalPluginId = options.plugin.pluginId
1994
1832
  ?? (options.plugin.sourceId ? `${options.plugin.sourceId}/${options.plugin.manifest.name}` : undefined);
1995
1833
  if (!logicalPluginId || !options.plugin.sourceId || !options.plugin.sourceIdentity) {
1996
- throw new Error('Codex native render projection requires namespaced source identity.');
1834
+ throw new Error('Native Skill render projection requires namespaced source identity.');
1997
1835
  }
1998
1836
  const marketplace = await readStrictNamespacedMarketplaceRoot({
1999
1837
  trustedMarketplaceRoot: path.join(resolveAwHome(options.env), 'marketplaces'),
2000
1838
  rootDir: options.marketplaceRoot,
2001
1839
  });
2002
1840
  if (!marketplace) {
2003
- return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1841
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
2004
1842
  }
2005
1843
  if (marketplace.config.sourceId !== options.plugin.sourceId
2006
1844
  || marketplace.config.sourceIdentity !== options.plugin.sourceIdentity
2007
1845
  || marketplace.config.marketplaceName !== options.marketplaceName) {
2008
- return codexNativeRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
1846
+ return nativeSkillRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
2009
1847
  }
2010
1848
  const payloadRoot = path.join(options.marketplaceRoot, 'plugins', options.plugin.manifest.name);
2011
1849
  const payloadStats = await lstatIfPresent(payloadRoot);
2012
1850
  if (!payloadStats) {
2013
- return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1851
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
2014
1852
  }
2015
1853
  if (!payloadStats.isDirectory() || payloadStats.isSymbolicLink()) {
2016
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1854
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2017
1855
  }
2018
1856
  if (!await codexPayloadPathSafe(payloadRoot, options.marketplaceRoot)) {
2019
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1857
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2020
1858
  }
2021
- const codexManifestPath = path.join(payloadRoot, '.codex-plugin', 'plugin.json');
2022
- const [sourceManifestEvidence, codexManifestEvidence] = await Promise.all([
2023
- readCodexNativeProjectionManifest(path.join(payloadRoot, '.agents-plugin', 'plugin.json')),
2024
- readCodexNativeProjectionManifest(codexManifestPath),
1859
+ const platformManifestPath = path.join(payloadRoot, `.${platform}-plugin`, 'plugin.json');
1860
+ const [sourceManifestEvidence, platformManifestEvidence] = await Promise.all([
1861
+ readNativeSkillProjectionManifest(path.join(payloadRoot, '.agents-plugin', 'plugin.json')),
1862
+ readNativeSkillProjectionManifest(platformManifestPath),
2025
1863
  ]);
2026
1864
  if (sourceManifestEvidence.state === 'unsafe'
2027
- || codexManifestEvidence.state === 'unsafe') {
2028
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1865
+ || platformManifestEvidence.state === 'unsafe') {
1866
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2029
1867
  }
2030
1868
  if ((sourceManifestEvidence.state === 'present'
2031
1869
  && sourceManifestEvidence.value.name !== options.plugin.manifest.name)
2032
- || (codexManifestEvidence.state === 'present'
2033
- && codexManifestEvidence.value.name !== options.plugin.manifest.name)
1870
+ || (platformManifestEvidence.state === 'present'
1871
+ && platformManifestEvidence.value.name !== options.plugin.manifest.name)
2034
1872
  || (sourceManifestEvidence.state === 'present'
2035
- && codexManifestEvidence.state === 'present'
2036
- && sourceManifestEvidence.value.version !== codexManifestEvidence.value.version)) {
2037
- return codexNativeRenderEvidenceIssue('foreign', 'manifestIdentityMismatch');
1873
+ && platformManifestEvidence.state === 'present'
1874
+ && sourceManifestEvidence.value.version !== platformManifestEvidence.value.version)) {
1875
+ return nativeSkillRenderEvidenceIssue('foreign', 'manifestIdentityMismatch');
2038
1876
  }
2039
1877
  if (sourceManifestEvidence.state === 'unreadable'
2040
- || codexManifestEvidence.state === 'unreadable') {
2041
- return codexNativeRenderEvidenceIssue('unreadable', 'manifestUnreadable');
1878
+ || platformManifestEvidence.state === 'unreadable') {
1879
+ return nativeSkillRenderEvidenceIssue('unreadable', 'manifestUnreadable');
2042
1880
  }
2043
1881
  if (sourceManifestEvidence.state === 'missing'
2044
- || codexManifestEvidence.state === 'missing') {
2045
- return codexNativeRenderEvidenceIssue('damaged', 'manifestMissing');
1882
+ || platformManifestEvidence.state === 'missing') {
1883
+ return nativeSkillRenderEvidenceIssue('damaged', 'manifestMissing');
2046
1884
  }
2047
1885
  if (sourceManifestEvidence.state === 'invalid'
2048
- || codexManifestEvidence.state === 'invalid') {
2049
- return codexNativeRenderEvidenceIssue('damaged', 'manifestUnreadable');
1886
+ || platformManifestEvidence.state === 'invalid') {
1887
+ return nativeSkillRenderEvidenceIssue('damaged', 'manifestUnreadable');
2050
1888
  }
2051
1889
  if (sourceManifestEvidence.state !== 'present'
2052
- || codexManifestEvidence.state !== 'present') {
2053
- return codexNativeRenderEvidenceIssue('damaged', 'manifestUnreadable');
1890
+ || platformManifestEvidence.state !== 'present') {
1891
+ return nativeSkillRenderEvidenceIssue('damaged', 'manifestUnreadable');
2054
1892
  }
2055
1893
  const sourceManifest = sourceManifestEvidence.value;
2056
- const codexManifest = codexManifestEvidence.value;
1894
+ const platformManifest = platformManifestEvidence.value;
2057
1895
  if (typeof sourceManifest.version !== 'string'
2058
1896
  || !tryParseStrictSemVer(sourceManifest.version)) {
2059
- return codexNativeRenderEvidenceIssue('damaged', 'manifestVersionInvalid');
2060
- }
2061
- const rawSkillsRoot = typeof codexManifest.skills === 'string' && codexManifest.skills.trim() !== ''
2062
- ? codexManifest.skills
2063
- : './codex/skills';
2064
- const { relativeRoot: skillsRelativeRoot } = await resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot);
1897
+ return nativeSkillRenderEvidenceIssue('damaged', 'manifestVersionInvalid');
1898
+ }
1899
+ const defaultSkillsRoot = platform === 'codex'
1900
+ ? './codex/skills'
1901
+ : `./claude/${(options.plugin.manifest.skills ?? './skills').replace(/^\.\//u, '')}`;
1902
+ const rawSkillsRoot = typeof platformManifest.skills === 'string' && platformManifest.skills.trim() !== ''
1903
+ ? platformManifest.skills
1904
+ : defaultSkillsRoot;
1905
+ const { relativeRoot: skillsRelativeRoot } = await resolveNativeSkillsRoot(payloadRoot, rawSkillsRoot, platform);
2065
1906
  const skillsRoot = path.join(payloadRoot, ...skillsRelativeRoot.split('/'));
2066
1907
  const skillsRootStats = await lstatIfPresent(skillsRoot);
2067
1908
  if (skillsRootStats && (!skillsRootStats.isDirectory() || skillsRootStats.isSymbolicLink())) {
2068
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1909
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2069
1910
  }
2070
- const targets = codexNativeRenderTargets(options.plugin);
1911
+ const targets = nativeSkillRenderTargets(options.plugin, platform);
2071
1912
  for (const target of targets) {
2072
1913
  if (await lstatIfPresent(path.join(skillsRoot, target.skillKey, '.agent-workflows-owner.json'))) {
2073
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1914
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2074
1915
  }
2075
1916
  }
2076
- const receiptEvidence = await readCodexNativeRenderReceiptEvidence(payloadRoot);
1917
+ const receiptEvidence = await readNativeSkillRenderReceiptEvidence(payloadRoot, platform);
2077
1918
  if (receiptEvidence.state === 'absent') {
2078
- return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1919
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
2079
1920
  }
2080
1921
  if (receiptEvidence.state === 'unsafe') {
2081
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1922
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2082
1923
  }
2083
1924
  if (receiptEvidence.state === 'invalid') {
2084
- return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptUnreadable');
1925
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionReceiptUnreadable');
2085
1926
  }
2086
1927
  if (receiptEvidence.state === 'unreadable') {
2087
- return codexNativeRenderEvidenceIssue('unreadable', 'projectionReceiptUnreadable');
1928
+ return nativeSkillRenderEvidenceIssue('unreadable', 'projectionReceiptUnreadable');
2088
1929
  }
2089
1930
  const receipt = receiptEvidence.receipt;
2090
1931
  if (receipt.logicalPluginId !== logicalPluginId
2091
1932
  || receipt.strategy !== 'shared-user'
2092
1933
  || receipt.sourceIdentity !== marketplace.config.sourceIdentity
2093
1934
  || receipt.pluginVersion !== sourceManifest.version) {
2094
- return codexNativeRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
1935
+ return nativeSkillRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
2095
1936
  }
2096
- const emptyArtifactDigest = createCodexSkillStagingTreeContentDigest({
1937
+ const emptyArtifactDigest = nativeSkillContentDigest(platform, {
2097
1938
  skillKey: 'empty',
2098
1939
  files: {},
2099
1940
  });
2100
1941
  for (const receiptTarget of receipt.targets) {
2101
1942
  const skillRoot = path.join(payloadRoot, ...skillsRelativeRoot.split('/'), receiptTarget.skillKey);
2102
1943
  if (await lstatIfPresent(path.join(skillRoot, '.agent-workflows-owner.json'))) {
2103
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1944
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2104
1945
  }
2105
1946
  const skillStats = await lstatIfPresent(skillRoot);
2106
1947
  if (skillStats && (!skillStats.isDirectory() || skillStats.isSymbolicLink())) {
2107
- return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1948
+ return nativeSkillRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2108
1949
  }
2109
1950
  let tree;
2110
1951
  try {
2111
- tree = skillStats ? await readDynamicSkillTree(skillRoot, 'codex.skill') : null;
1952
+ tree = skillStats ? await readDynamicSkillTree(skillRoot, `${platform}.skill`) : null;
2112
1953
  }
2113
1954
  catch (error) {
2114
- return codexNativeRenderEvidenceIssue(error instanceof Error && typeof error.code !== 'string'
1955
+ return nativeSkillRenderEvidenceIssue(error instanceof Error && typeof error.code !== 'string'
2115
1956
  ? 'damaged'
2116
1957
  : 'unreadable', 'projectionPayloadDigestMismatch');
2117
1958
  }
2118
1959
  const artifactDigest = tree
2119
- ? createCodexSkillStagingTreeContentDigest(tree)
1960
+ ? nativeSkillContentDigest(platform, tree)
2120
1961
  : emptyArtifactDigest;
2121
1962
  if (artifactDigest !== receiptTarget.artifactDigest) {
2122
- return codexNativeRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
1963
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
2123
1964
  }
2124
1965
  }
2125
1966
  const payloadDigest = await calculateCodexNativeRenderPayloadDigest(payloadRoot);
2126
1967
  if (payloadDigest !== receipt.payloadDigest) {
2127
- return codexNativeRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
1968
+ return nativeSkillRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
2128
1969
  }
2129
1970
  const receiptTargets = new Map(receipt.targets.map((target) => [target.id, target]));
2130
1971
  if (targets.length === 0
@@ -2134,7 +1975,7 @@ async function resolveCodexNativeRenderExpectedEvidence(options) {
2134
1975
  }
2135
1976
  const renderer = await resolveArtifactRendererTarget(options.plugin);
2136
1977
  if (renderer.noOp || !renderer.rendererDigest) {
2137
- throw new Error('Codex native render projection requires an artifact renderer.');
1978
+ throw new Error('Native Skill render projection requires an artifact renderer.');
2138
1979
  }
2139
1980
  const config = await resolveArtifactRenderConfig({
2140
1981
  sourceId: options.plugin.sourceId,
@@ -2142,12 +1983,15 @@ async function resolveCodexNativeRenderExpectedEvidence(options) {
2142
1983
  logicalIdentity: options.plugin.catalogLogicalIdentity,
2143
1984
  pluginName: options.plugin.manifest.name,
2144
1985
  manifest: options.plugin.manifest,
1986
+ platform,
1987
+ referencePlugins: options.referencePlugins,
2145
1988
  scope: 'user',
2146
1989
  cwd: options.plugin.rootDir,
2147
1990
  env: options.env,
2148
1991
  });
2149
1992
  if (config.issues.length > 0) {
2150
- throw new Error(`Invalid AW config for ${options.plugin.manifest.name}.`);
1993
+ // Validated installed bytes remain live while configuration needs repair.
1994
+ return { state: 'present', payloadDigest, receipt, sourceProjection: 'drifted' };
2151
1995
  }
2152
1996
  const projection = createCodexNativeRenderProjection({
2153
1997
  logicalPluginId,
@@ -2160,9 +2004,9 @@ async function resolveCodexNativeRenderExpectedEvidence(options) {
2160
2004
  configDigest: createArtifactConfigDigest({
2161
2005
  artifact: {
2162
2006
  id: target.id,
2163
- platform: 'codex',
2164
- target: 'codex.skill',
2165
- refreshKeys: target.refreshKeys,
2007
+ platform,
2008
+ target: `${platform}.skill`,
2009
+ refreshKeys: nativeSkillRefreshKeys(options.plugin, target),
2166
2010
  },
2167
2011
  renderConfig: config,
2168
2012
  digestSalt: renderer.rendererDigest,
@@ -2200,14 +2044,15 @@ async function assertNoSensitiveValuesInCanonicalCodexNativePayload(options) {
2200
2044
  if (!await codexPayloadPathSafe(payloadRoot, options.marketplaceRoot)) {
2201
2045
  throw new Error('Codex native sensitive scan payload path is unsafe.');
2202
2046
  }
2203
- const receiptEvidence = await readCodexNativeRenderReceiptEvidence(payloadRoot);
2047
+ const receiptEvidence = await readNativeSkillRenderReceiptEvidence(payloadRoot, 'codex');
2204
2048
  if (receiptEvidence.state === 'unsafe') {
2205
2049
  throw new Error('codexNativeRenderReceiptInvalid: Codex native render receipt path is unsafe.');
2206
2050
  }
2207
2051
  let verifiedRenderReceipt;
2208
2052
  if (receiptEvidence.state === 'present') {
2209
- const expected = await resolveCodexNativeRenderExpectedEvidence({
2053
+ const expected = await resolveNativeSkillRenderExpectedEvidence({
2210
2054
  plugin: options.plugin,
2055
+ platform: 'codex',
2211
2056
  marketplaceRoot: options.marketplaceRoot,
2212
2057
  marketplaceName: options.marketplaceName,
2213
2058
  env: options.env,
@@ -2216,7 +2061,7 @@ async function assertNoSensitiveValuesInCanonicalCodexNativePayload(options) {
2216
2061
  verifiedRenderReceipt = expected.receipt;
2217
2062
  }
2218
2063
  }
2219
- await assertNoSensitiveValuesInCodexNativePayload({
2064
+ await assertNoSensitiveValuesInNativeSkillPayload({
2220
2065
  plugin: options.plugin,
2221
2066
  payloadRoot,
2222
2067
  allowedRoot: options.marketplaceRoot,
@@ -2394,8 +2239,9 @@ export async function inspectCodexSharedNativeLive(options) {
2394
2239
  && pluginList.observation.value === 'installed';
2395
2240
  if (installed && dynamicProjectionExpected && options.nativeRenderPlugin) {
2396
2241
  try {
2397
- const expected = await resolveCodexNativeRenderExpectedEvidence({
2242
+ const expected = await resolveNativeSkillRenderExpectedEvidence({
2398
2243
  plugin: options.nativeRenderPlugin,
2244
+ platform: 'codex',
2399
2245
  marketplaceRoot,
2400
2246
  marketplaceName,
2401
2247
  env: options.env,
@@ -2421,8 +2267,8 @@ export async function inspectCodexSharedNativeLive(options) {
2421
2267
  }
2422
2268
  else {
2423
2269
  sourceProjectionIssue = {
2424
- reason: error instanceof CodexNativeProjectionUnsafeError ? 'foreign' : 'unreadable',
2425
- diagnostic: error instanceof CodexNativeProjectionUnsafeError
2270
+ reason: error instanceof NativeSkillProjectionUnsafeError ? 'foreign' : 'unreadable',
2271
+ diagnostic: error instanceof NativeSkillProjectionUnsafeError
2426
2272
  ? 'payloadPathUnsafe'
2427
2273
  : 'projectionReceiptUnreadable',
2428
2274
  };
@@ -2471,6 +2317,23 @@ async function ensureCodexActiveSkillsManifest(options) {
2471
2317
  await fs.outputJson(manifestPath, updated, { spaces: 2 });
2472
2318
  return options.hasRequiredSkills ? relativeSkillsRoot : null;
2473
2319
  }
2320
+ async function ensureNativeActiveSkillsManifest(options) {
2321
+ if (options.platform === 'codex') {
2322
+ await ensureCodexActiveSkillsManifest(options);
2323
+ return;
2324
+ }
2325
+ const pluginRoot = path.join(options.marketplaceRoot, 'plugins', options.plugin.manifest.name);
2326
+ const manifestPath = path.join(pluginRoot, '.claude-plugin', 'plugin.json');
2327
+ const manifest = await fs.readJson(manifestPath);
2328
+ const updated = { ...manifest, name: options.plugin.manifest.name, version: options.plugin.manifest.version };
2329
+ if (options.hasRequiredSkills) {
2330
+ await fs.ensureDir(path.join(pluginRoot, ...options.relativeSkillsRoot.split('/')));
2331
+ updated.skills = `./${options.relativeSkillsRoot}`;
2332
+ }
2333
+ else
2334
+ delete updated.skills;
2335
+ await fs.outputJson(manifestPath, updated, { spaces: 2 });
2336
+ }
2474
2337
  function createCodexMarketplaceComponent(options) {
2475
2338
  const configPath = resolveCodexPaths(options.cwd, 'user', options.env).configTomlPath;
2476
2339
  return {
@@ -2802,21 +2665,29 @@ function createClaudeMarketplaceComponent(options) {
2802
2665
  },
2803
2666
  };
2804
2667
  }
2805
- const codexNativeRenderPreparationCaches = new WeakMap();
2806
- function codexNativeRenderPreparationCache(context) {
2807
- let cache = codexNativeRenderPreparationCaches.get(context);
2668
+ const nativeSkillRenderPreparationCaches = new WeakMap();
2669
+ function nativeSkillRenderPreparationCache(context, platform) {
2670
+ let platforms = nativeSkillRenderPreparationCaches.get(context);
2671
+ if (!platforms) {
2672
+ platforms = new Map();
2673
+ nativeSkillRenderPreparationCaches.set(context, platforms);
2674
+ }
2675
+ let cache = platforms.get(platform);
2808
2676
  if (!cache) {
2809
2677
  cache = new WeakMap();
2810
- codexNativeRenderPreparationCaches.set(context, cache);
2678
+ platforms.set(platform, cache);
2811
2679
  }
2812
2680
  return cache;
2813
2681
  }
2682
+ function nativeSkillRenderTargets(plugin, platform) {
2683
+ return (plugin.manifest.artifacts?.targets ?? []).filter((target) => target.platform === platform && target.target === `${platform}.skill`);
2684
+ }
2814
2685
  function pluginHasCodexNativeSkillSurface(plugin) {
2815
2686
  return plugin.manifest.skills !== undefined
2816
2687
  || codexNativeRenderTargets(plugin).length > 0;
2817
2688
  }
2818
- async function resolveSensitiveUserConfigValues(plugin, env, referencePlugins) {
2819
- const hasSensitiveFields = Object.values(plugin.manifest.config?.fields ?? {}).some((field) => field.sensitive === true);
2689
+ async function resolveSensitiveUserConfigValues(plugin, env, referencePlugins, platform = 'codex') {
2690
+ const hasSensitiveFields = Object.values(plugin.manifest.config ? compilePluginConfigDefinition(plugin.manifest.config, platform).fields : {}).some((field) => field.sensitive === true);
2820
2691
  if (!hasSensitiveFields)
2821
2692
  return [];
2822
2693
  const config = await resolveArtifactRenderConfig({
@@ -2824,20 +2695,22 @@ async function resolveSensitiveUserConfigValues(plugin, env, referencePlugins) {
2824
2695
  sourceIdentity: plugin.sourceIdentity,
2825
2696
  pluginName: plugin.manifest.name,
2826
2697
  manifest: plugin.manifest,
2698
+ platform,
2827
2699
  referencePlugins,
2828
2700
  scope: 'user',
2829
2701
  cwd: plugin.rootDir,
2830
2702
  env,
2831
2703
  });
2832
- return collectSensitivePluginConfigValues(plugin.manifest, config.values);
2704
+ return collectSensitivePluginConfigValues(plugin.manifest, config.values, platform);
2833
2705
  }
2834
- async function assertNoSensitiveValuesInCodexNativePayload(options) {
2706
+ async function assertNoSensitiveValuesInNativeSkillPayload(options) {
2835
2707
  if (options.sensitiveValues.length === 0)
2836
2708
  return;
2709
+ const platform = options.platform ?? 'codex';
2837
2710
  if (!await codexPayloadPathSafe(options.payloadRoot, options.allowedRoot)) {
2838
2711
  throw new Error('Codex native sensitive scan payload path is unsafe.');
2839
2712
  }
2840
- const codexManifestPath = path.join(options.payloadRoot, '.codex-plugin', 'plugin.json');
2713
+ const codexManifestPath = path.join(options.payloadRoot, `.${platform}-plugin`, 'plugin.json');
2841
2714
  const codexManifestStats = await lstatCodexResidueIfPresent(codexManifestPath);
2842
2715
  if (!codexManifestStats?.isFile()) {
2843
2716
  throw new Error('Codex native sensitive scan manifest is missing or unsafe.');
@@ -2853,7 +2726,7 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2853
2726
  if (typeof rawSkillsRoot !== 'string' || rawSkillsRoot.trim() === '') {
2854
2727
  throw new Error('Codex native sensitive scan Skills root is invalid.');
2855
2728
  }
2856
- const { root: skillsRoot } = await resolveCodexSkillsRoot(options.payloadRoot, rawSkillsRoot);
2729
+ const { root: skillsRoot } = await resolveNativeSkillsRoot(options.payloadRoot, rawSkillsRoot, platform);
2857
2730
  const skillsRootStats = await lstatCodexResidueIfPresent(skillsRoot);
2858
2731
  if (!skillsRootStats?.isDirectory()) {
2859
2732
  throw new Error('Codex native sensitive scan Skills root is missing or unsafe.');
@@ -2868,7 +2741,7 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2868
2741
  if (!skillFileStats.isFile()) {
2869
2742
  throw new Error('Codex native sensitive scan Skill entry is unsafe.');
2870
2743
  }
2871
- const tree = await readDynamicSkillTree(skillRoot, 'codex.skill');
2744
+ const tree = await readDynamicSkillTree(skillRoot, `${platform}.skill`);
2872
2745
  if (!tree)
2873
2746
  continue;
2874
2747
  const leakedPath = findSensitiveTokenPath(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), options.sensitiveValues);
@@ -2878,7 +2751,7 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2878
2751
  }
2879
2752
  }
2880
2753
  }
2881
- const receiptPath = path.join(options.payloadRoot, CODEX_NATIVE_RENDER_RECEIPT_PATH);
2754
+ const receiptPath = path.join(options.payloadRoot, nativeSkillRenderReceiptPath(platform));
2882
2755
  const receiptStats = await lstatCodexResidueIfPresent(receiptPath);
2883
2756
  if (receiptStats) {
2884
2757
  if (!receiptStats.isFile()) {
@@ -2887,7 +2760,7 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2887
2760
  const receiptContent = await fs.readFile(receiptPath);
2888
2761
  let actualReceipt;
2889
2762
  try {
2890
- actualReceipt = parseCodexNativeRenderReceipt(receiptContent.toString('utf8'));
2763
+ actualReceipt = parseNativeSkillRenderReceipt(platform, receiptContent.toString('utf8'));
2891
2764
  }
2892
2765
  catch {
2893
2766
  actualReceipt = undefined;
@@ -2895,7 +2768,7 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2895
2768
  const verified = options.verifiedRenderReceipt
2896
2769
  && JSON.stringify(actualReceipt) === JSON.stringify(options.verifiedRenderReceipt);
2897
2770
  if (!verified) {
2898
- const receiptLeak = findSensitiveTokenPath({ [CODEX_NATIVE_RENDER_RECEIPT_PATH]: receiptContent }, options.sensitiveValues);
2771
+ const receiptLeak = findSensitiveTokenPath({ [nativeSkillRenderReceiptPath(platform)]: receiptContent }, options.sensitiveValues);
2899
2772
  if (receiptLeak) {
2900
2773
  throw new Error(`codexNativeRenderSensitiveValue: Codex native render receipt exposes sensitive config in ` +
2901
2774
  `"${receiptLeak}".`);
@@ -2903,47 +2776,41 @@ async function assertNoSensitiveValuesInCodexNativePayload(options) {
2903
2776
  }
2904
2777
  }
2905
2778
  }
2906
- async function prepareCodexNativeRender(options) {
2779
+ async function prepareNativeSkillRender(options) {
2907
2780
  const requested = options.requestedArtifactIds
2908
2781
  ? new Set(options.requestedArtifactIds)
2909
2782
  : undefined;
2910
- const targets = codexNativeRenderTargets(options.plugin)
2783
+ const targets = nativeSkillRenderTargets(options.plugin, options.platform)
2911
2784
  .filter((target) => !requested || requested.has(target.id));
2912
2785
  if (targets.length === 0)
2913
2786
  return null;
2914
2787
  let commandCandidates = [...(options.commandCandidates ?? [])];
2915
2788
  if (!options.commandCandidates) {
2916
2789
  for (const declaration of options.plugin.manifest.managedCommands?.packages ?? []) {
2917
- if (declaration.scope !== 'user' || !declaration.platforms.includes('codex'))
2790
+ if (declaration.scope !== 'user' || !declaration.platforms.includes(options.platform))
2918
2791
  continue;
2919
2792
  const prepared = await prepareManagedCommandPackage({ ...options, packageKey: declaration.key, scope: 'user', cwd: options.plugin.rootDir });
2920
2793
  commandCandidates.push({ producer: prepared.producer, sets: prepared.sets });
2921
2794
  await prepared.cleanup();
2922
2795
  }
2923
2796
  }
2924
- const byScope = new Map();
2925
- for (const target of targets) {
2926
- const ownsCommandSet = options.plugin.manifest.managedCommands?.sets.some((set) => set.producer.kind === 'artifact' && set.producer.artifactId === target.id);
2927
- const requestScope = ownsCommandSet || target.scopes.includes('user') ? 'user' : 'project';
2928
- const group = byScope.get(requestScope) ?? [];
2929
- group.push(target);
2930
- byScope.set(requestScope, group);
2931
- }
2932
- const skillsRelativeRoot = await resolveCodexSkillsRelativeRoot(options.plugin);
2933
- const nativeReceiptPath = `${'../'.repeat(skillsRelativeRoot.split('/').length + 1)}${CODEX_NATIVE_RENDER_RECEIPT_PATH}`;
2797
+ const skillsRelativeRoot = options.platform === 'codex'
2798
+ ? await resolveCodexSkillsRelativeRoot(options.plugin)
2799
+ : `claude/${(options.plugin.manifest.skills ?? './skills').replace(/^\.\//u, '')}`;
2800
+ const receiptPath = nativeSkillRenderReceiptPath(options.platform);
2801
+ const nativeReceiptPath = `${'../'.repeat(skillsRelativeRoot.split('/').length + 1)}${receiptPath}`;
2934
2802
  const renderedArtifacts = [];
2935
2803
  const receiptTargets = [];
2936
2804
  const presentSkillKeys = [];
2937
2805
  let rendererDigest;
2938
- for (const scope of ['user', 'project']) {
2939
- const group = byScope.get(scope);
2940
- if (!group || group.length === 0)
2941
- continue;
2806
+ {
2807
+ const scope = 'user';
2808
+ const group = targets;
2942
2809
  const rendered = await runArtifactRenderer({
2943
2810
  referencePlugins: options.referencePlugins,
2944
2811
  event: 'install',
2945
2812
  plugin: options.plugin,
2946
- platform: 'codex',
2813
+ platform: options.platform,
2947
2814
  scope,
2948
2815
  configScope: 'user',
2949
2816
  cwd: options.plugin.rootDir,
@@ -2953,13 +2820,15 @@ async function prepareCodexNativeRender(options) {
2953
2820
  const producer = target.producer;
2954
2821
  return producer.kind === 'artifact' && group.some((skill) => skill.id === producer.artifactId);
2955
2822
  }).map((target) => target.id)],
2823
+ preparedResults: options.preparedResults,
2956
2824
  scriptTimeoutMs: options.scriptTimeoutMs,
2825
+ signal: options.signal,
2957
2826
  });
2958
2827
  rendererDigest = rendered.target.rendererDigest;
2959
2828
  const validated = validateArtifactPlan({
2960
2829
  manifest: options.plugin.manifest,
2961
2830
  plan: rendered.plan,
2962
- platform: 'codex',
2831
+ platform: options.platform,
2963
2832
  scope,
2964
2833
  requestedArtifactIds: rendered.context.requestedArtifactIds,
2965
2834
  renderConfig: rendered.context.config,
@@ -2969,11 +2838,12 @@ async function prepareCodexNativeRender(options) {
2969
2838
  for (const artifact of validated.artifacts) {
2970
2839
  if (artifact.target === 'aw.command-set')
2971
2840
  continue;
2972
- if (artifact.target !== 'codex.skill') {
2841
+ if ((artifact.target !== 'codex.skill' && artifact.target !== 'claude.skill')
2842
+ || artifact.target !== `${options.platform}.skill`) {
2973
2843
  throw new Error(`Codex native renderer returned non-Skill artifact "${artifact.id}".`);
2974
2844
  }
2975
2845
  const sourceDirs = rendered.context.artifactSources.find((entry) => entry.id === artifact.id && entry.target === artifact.target)?.sourceDirs ?? [];
2976
- const tree = await createCodexSkillExpectedTree({
2846
+ const tree = await createDynamicSkillExpectedTree({
2977
2847
  artifact,
2978
2848
  sourceDirs,
2979
2849
  requireReadme: true,
@@ -2981,10 +2851,10 @@ async function prepareCodexNativeRender(options) {
2981
2851
  sourceRequirementsReceiptPolicy: 'allow',
2982
2852
  });
2983
2853
  await injectInstalledRuntimeConfig(tree, rendered.runtimeConfigSnapshots[artifact.id], { nativeReceiptPath });
2984
- const candidate = await prepareSkillCommandCandidate({ plugin: options.plugin, producer: { kind: 'artifact', artifactId: artifact.id }, platform: 'codex', scope: 'user', cwd: options.plugin.rootDir, tree, artifacts: validated.artifacts });
2854
+ const candidate = await prepareSkillCommandCandidate({ plugin: options.plugin, producer: { kind: 'artifact', artifactId: artifact.id }, platform: options.platform, scope: 'user', cwd: options.plugin.rootDir, tree, artifacts: validated.artifacts });
2985
2855
  if (candidate)
2986
2856
  commandCandidates.push(candidate);
2987
- assertNoSensitiveConfigInFiles(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), collectSensitivePluginConfigValues(options.plugin.manifest, rendered.context.config.values), 'artifactRendererSensitiveConfigExposed: Final dynamic Skill contains sensitive config.');
2857
+ assertNoSensitiveConfigInFiles(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), collectSensitivePluginConfigValues(options.plugin.manifest, rendered.context.config.values, options.platform), 'artifactRendererSensitiveConfigExposed: Final dynamic Skill contains sensitive config.');
2988
2858
  const skillKey = artifact.skillKey;
2989
2859
  renderedArtifacts.push({
2990
2860
  artifact,
@@ -2996,8 +2866,12 @@ async function prepareCodexNativeRender(options) {
2996
2866
  receiptTargets.push({
2997
2867
  id: artifact.id,
2998
2868
  skillKey,
2999
- configDigest: artifact.configDigest,
3000
- artifactDigest: createCodexSkillStagingTreeContentDigest(tree),
2869
+ configDigest: createArtifactConfigDigest({
2870
+ artifact: { ...artifact, refreshKeys: nativeSkillRefreshKeys(options.plugin, artifact) },
2871
+ renderConfig: rendered.context.config,
2872
+ digestSalt: rendered.target.rendererDigest,
2873
+ }),
2874
+ artifactDigest: nativeSkillContentDigest(options.platform, tree),
3001
2875
  });
3002
2876
  }
3003
2877
  }
@@ -3007,14 +2881,14 @@ async function prepareCodexNativeRender(options) {
3007
2881
  if (options.prepareCommandReferences)
3008
2882
  commandCandidates = await options.prepareCommandReferences(renderedArtifacts.map((entry) => entry.tree), commandCandidates);
3009
2883
  else {
3010
- const staticSkills = await prepareStaticNativeSkillActions({ plugin: options.plugin, platform: 'codex', scope: 'user', cwd: options.plugin.rootDir, env: options.env, artifacts: [], commandCandidates });
2884
+ const staticSkills = await prepareStaticNativeSkillActions({ plugin: options.plugin, platform: options.platform, scope: 'user', cwd: options.plugin.rootDir, env: options.env, artifacts: [], commandCandidates, signal: options.signal, scriptTimeoutMs: options.scriptTimeoutMs });
3011
2885
  commandCandidates.push(...staticSkills.candidates);
3012
2886
  }
3013
- const commandResolver = await createManagedCommandReferenceResolver({ plugin: options.plugin, platform: 'codex', scope: 'user', cwd: options.plugin.rootDir, env: options.env, candidates: commandCandidates });
2887
+ const commandResolver = await createManagedCommandReferenceResolver({ plugin: options.plugin, platform: options.platform, scope: 'user', cwd: options.plugin.rootDir, env: options.env, candidates: commandCandidates });
3014
2888
  for (const rendered of renderedArtifacts) {
3015
2889
  resolveSkillManagedCommandReferences(rendered.tree, commandResolver);
3016
2890
  const receiptTarget = receiptTargets.find((target) => target.id === rendered.artifact.id);
3017
- receiptTarget.artifactDigest = createCodexSkillStagingTreeContentDigest(rendered.tree);
2891
+ receiptTarget.artifactDigest = nativeSkillContentDigest(options.platform, rendered.tree);
3018
2892
  }
3019
2893
  const logicalPluginId = options.plugin.pluginId
3020
2894
  ?? (options.plugin.sourceId ? `${options.plugin.sourceId}/${options.plugin.manifest.name}` : undefined);
@@ -3029,6 +2903,7 @@ async function prepareCodexNativeRender(options) {
3029
2903
  targets: receiptTargets,
3030
2904
  });
3031
2905
  return {
2906
+ platform: options.platform,
3032
2907
  commandCandidates,
3033
2908
  logicalPluginId,
3034
2909
  sourceIdentity: options.plugin.sourceIdentity,
@@ -3041,14 +2916,17 @@ async function prepareCodexNativeRender(options) {
3041
2916
  targetSkillKeys: targets.map((target) => target.skillKey).sort(),
3042
2917
  };
3043
2918
  }
3044
- function prepareCodexNativeRenderCached(options) {
3045
- const cache = codexNativeRenderPreparationCache(options.context);
2919
+ function prepareNativeSkillRenderCached(options) {
2920
+ const cache = nativeSkillRenderPreparationCache(options.context, options.platform);
3046
2921
  let preparation = cache.get(options.plugin);
3047
2922
  if (!preparation) {
3048
- preparation = prepareCodexNativeRender({
2923
+ preparation = prepareNativeSkillRender({
2924
+ preparedResults: artifactRenderResults(options.context),
3049
2925
  referencePlugins: options.context.referencePlugins,
3050
2926
  plugin: options.plugin,
2927
+ platform: options.platform,
3051
2928
  env: options.context.env,
2929
+ signal: options.context.signal,
3052
2930
  scriptTimeoutMs: options.scriptTimeoutMs,
3053
2931
  commandCandidates: options.context.managedCommandCandidates?.get(pluginActionId(options.plugin)),
3054
2932
  });
@@ -3056,16 +2934,16 @@ function prepareCodexNativeRenderCached(options) {
3056
2934
  }
3057
2935
  return preparation;
3058
2936
  }
3059
- async function requirePreparedCodexNativeRender(options) {
3060
- if (codexNativeRenderTargets(options.plugin).length === 0)
2937
+ async function requirePreparedNativeSkillRender(options) {
2938
+ if (nativeSkillRenderTargets(options.plugin, options.platform).length === 0)
3061
2939
  return null;
3062
- const preparation = codexNativeRenderPreparationCache(options.context).get(options.plugin);
2940
+ const preparation = nativeSkillRenderPreparationCache(options.context, options.platform).get(options.plugin);
3063
2941
  if (!preparation) {
3064
2942
  throw new Error('codexNativeRenderPreflightMissing: Codex native renderer was not prepared.');
3065
2943
  }
3066
2944
  return preparation;
3067
2945
  }
3068
- async function materializeCodexNativeRender(options) {
2946
+ async function materializeNativeSkillRender(options) {
3069
2947
  const skillsRoot = path.join(options.stagingRoot, 'plugins', options.plugin.manifest.name, ...options.prepared.skillsRelativeRoot.split('/'));
3070
2948
  for (const { artifact, skillKey, tree } of options.prepared.renderedArtifacts) {
3071
2949
  const skillRoot = path.join(skillsRoot, skillKey);
@@ -3076,14 +2954,17 @@ async function materializeCodexNativeRender(options) {
3076
2954
  await fs.remove(skillRoot);
3077
2955
  }
3078
2956
  }
3079
- await ensureCodexActiveSkillsManifest({
2957
+ const platform = options.prepared.platform;
2958
+ await ensureNativeActiveSkillsManifest({
3080
2959
  plugin: options.plugin,
2960
+ platform,
3081
2961
  marketplaceRoot: options.stagingRoot,
3082
2962
  hasRequiredSkills: options.hasStaticSkills || options.prepared.presentSkillKeys.length > 0,
2963
+ relativeSkillsRoot: options.prepared.skillsRelativeRoot,
3083
2964
  });
3084
2965
  const pluginRoot = path.join(options.stagingRoot, 'plugins', options.plugin.manifest.name);
3085
2966
  const payloadDigest = await calculateCodexNativeRenderPayloadDigest(pluginRoot);
3086
- const receipt = createCodexNativeRenderReceipt({
2967
+ const receipt = (platform === 'codex' ? createCodexNativeRenderReceipt : createClaudeNativeRenderReceipt)({
3087
2968
  logicalPluginId: options.prepared.logicalPluginId,
3088
2969
  sourceIdentity: options.prepared.sourceIdentity,
3089
2970
  pluginVersion: options.plugin.manifest.version,
@@ -3091,7 +2972,7 @@ async function materializeCodexNativeRender(options) {
3091
2972
  targets: options.prepared.receiptTargets,
3092
2973
  payloadDigest,
3093
2974
  });
3094
- await fs.outputFile(path.join(pluginRoot, CODEX_NATIVE_RENDER_RECEIPT_PATH), serializeCodexNativeRenderReceipt(receipt), 'utf8');
2975
+ await fs.outputFile(path.join(pluginRoot, nativeSkillRenderReceiptPath(platform)), serializeNativeSkillRenderReceipt(receipt), 'utf8');
3095
2976
  return {
3096
2977
  payloadDigest,
3097
2978
  projection: options.prepared.projection,
@@ -3113,13 +2994,12 @@ export async function materializeReviewNativeSkills(options) {
3113
2994
  await fs.ensureDir(skillsRoot);
3114
2995
  let commandCandidates = [];
3115
2996
  const staticTrees = [];
3116
- const directTrees = [];
3117
2997
  const declarations = options.plugin.manifest.artifacts?.targets ?? [];
3118
2998
  const dynamicSelections = options.skills.filter((skill) => skill.targetId !== null);
3119
2999
  const selectedDeclarations = dynamicSelections.map((selection) => {
3120
3000
  const matches = declarations.filter((target) => target.id === selection.targetId
3121
3001
  && target.platform === options.platform
3122
- && target.scopes.includes(options.scope)
3002
+ && target.scopes.includes('user')
3123
3003
  && target.skillKey === selection.skill
3124
3004
  && target.target === `${options.platform}.skill`);
3125
3005
  if (matches.length !== 1) {
@@ -3145,84 +3025,14 @@ export async function materializeReviewNativeSkills(options) {
3145
3025
  requirementsReceiptPolicy: 'allow',
3146
3026
  }));
3147
3027
  }
3148
- const directTargetIds = requiredDeclarations
3149
- .filter((target) => target.delivery?.mode !== 'codex-native')
3150
- .map((target) => target.id);
3151
- if (directTargetIds.length > 0) {
3152
- const dynamic = await resolveDynamicArtifacts({
3153
- referencePlugins: options.plugins,
3154
- plugin: options.plugin,
3155
- platform: options.platform,
3156
- scope: options.scope,
3157
- cwd: options.cwd,
3158
- env: options.env,
3159
- event: 'install',
3160
- previousArtifacts: [],
3161
- requestedArtifactIds: [
3162
- ...directTargetIds,
3163
- ...getManagedCommandArtifactTargets(options.plugin.manifest)
3164
- .filter((target) => target.producer.kind === 'artifact'
3165
- && directTargetIds.includes(target.producer.artifactId))
3166
- .map((target) => target.id),
3167
- ],
3168
- scriptTimeoutMs: options.scriptTimeoutMs,
3169
- });
3170
- for (const artifact of dynamic.artifacts) {
3171
- if (artifact.target === 'aw.command-set')
3172
- continue;
3173
- if (artifact.state !== 'present') {
3174
- throw new Error(`Selected Skill target "${artifact.id}" did not produce a present Skill.`);
3175
- }
3176
- if (artifact.target !== `${options.platform}.skill`) {
3177
- throw new Error(`Selected target "${artifact.id}" did not produce a ${options.platform} Skill.`);
3178
- }
3179
- let tree;
3180
- if (artifact.target === 'codex.skill') {
3181
- tree = await createCodexSkillExpectedTree({
3182
- artifact,
3183
- sourceDirs: dynamic.sourceDirs(artifact),
3184
- requireReadme: true,
3185
- requirementsReceipt: requirementsReceipt(options.plugin),
3186
- sourceRequirementsReceiptPolicy: 'allow',
3187
- });
3188
- }
3189
- else if (artifact.target === 'claude.skill') {
3190
- tree = await createDynamicSkillExpectedTree({
3191
- artifact,
3192
- sourceDirs: dynamic.sourceDirs(artifact),
3193
- requireReadme: true,
3194
- requirementsReceipt: requirementsReceipt(options.plugin),
3195
- sourceRequirementsReceiptPolicy: 'allow',
3196
- });
3197
- }
3198
- else {
3199
- throw new Error(`Selected target "${artifact.id}" is not a Skill.`);
3200
- }
3201
- await injectInstalledRuntimeConfig(tree, dynamic.runtimeConfigSnapshots?.[artifact.id]);
3202
- assertNoSensitiveConfigInFiles(withoutVerifiedRequirementsReceipt(options.plugin, tree.files), dynamic.sensitiveValues, 'artifactRendererSensitiveConfigExposed: Final dynamic Skill contains sensitive config.');
3203
- const candidate = await prepareSkillCommandCandidate({
3204
- ...options, producer: { kind: 'artifact', artifactId: artifact.id },
3205
- tree, artifacts: dynamic.artifacts,
3206
- });
3207
- if (candidate)
3208
- commandCandidates.push(candidate);
3209
- directTrees.push(tree);
3210
- }
3211
- }
3212
3028
  const prepareReferences = async (trees, scope, copy, candidates = commandCandidates) => prepareIsolatedSkillCommandReferences({
3213
3029
  ...options, scope, candidates,
3214
3030
  trees: copy ? trees.map((tree) => ({ ...tree, files: { ...tree.files } })) : trees,
3215
3031
  });
3216
3032
  const staticScope = 'user';
3217
3033
  commandCandidates = await prepareReferences(staticTrees, staticScope, true);
3218
- commandCandidates = await prepareReferences(directTrees, options.scope, true);
3219
- const nativeTargetIds = requiredDeclarations
3220
- .filter((target) => target.delivery?.mode === 'codex-native')
3221
- .map((target) => target.id);
3034
+ const nativeTargetIds = requiredDeclarations.map((target) => target.id);
3222
3035
  if (nativeTargetIds.length > 0) {
3223
- if (options.platform !== 'codex') {
3224
- throw new Error('Codex native Skill targets are only valid for the Codex platform.');
3225
- }
3226
3036
  const marketplaceRoot = path.join(options.outputRoot, '.native-marketplace');
3227
3037
  const payloadRoot = path.join(marketplaceRoot, 'plugins', options.plugin.manifest.name);
3228
3038
  await fs.copy(options.plugin.rootDir, payloadRoot, {
@@ -3230,9 +3040,10 @@ export async function materializeReviewNativeSkills(options) {
3230
3040
  errorOnExist: true,
3231
3041
  dereference: false,
3232
3042
  });
3233
- const prepared = await prepareCodexNativeRender({
3043
+ const prepared = await prepareNativeSkillRender({
3234
3044
  referencePlugins: options.plugins,
3235
3045
  plugin: options.plugin,
3046
+ platform: options.platform,
3236
3047
  env: options.env,
3237
3048
  requestedArtifactIds: nativeTargetIds,
3238
3049
  scriptTimeoutMs: options.scriptTimeoutMs,
@@ -3243,38 +3054,38 @@ export async function materializeReviewNativeSkills(options) {
3243
3054
  throw new Error('Selected Codex native Skill targets did not produce a projection.');
3244
3055
  }
3245
3056
  commandCandidates = prepared.commandCandidates;
3246
- const staged = await materializeCodexNativeRender({
3057
+ const staged = await materializeNativeSkillRender({
3247
3058
  plugin: options.plugin,
3248
3059
  stagingRoot: marketplaceRoot,
3249
3060
  prepared,
3250
3061
  hasStaticSkills: options.plugin.manifest.skills !== undefined,
3251
3062
  });
3252
- await assertNoSensitiveValuesInCodexNativePayload({
3063
+ await assertNoSensitiveValuesInNativeSkillPayload({
3253
3064
  plugin: options.plugin,
3254
3065
  payloadRoot,
3255
3066
  allowedRoot: marketplaceRoot,
3256
- sensitiveValues: await resolveSensitiveUserConfigValues(options.plugin, options.env, options.plugins),
3067
+ platform: options.platform,
3068
+ sensitiveValues: await resolveSensitiveUserConfigValues(options.plugin, options.env, options.plugins, options.platform),
3257
3069
  verifiedRenderReceipt: staged.receipt,
3258
3070
  });
3259
3071
  const presentSkillKeys = new Set(staged.presentSkillKeys);
3260
3072
  if (options.allowDisabledNativeSkills) {
3261
- for (const target of requiredDeclarations.filter((entry) => entry.delivery?.mode === 'codex-native' && !presentSkillKeys.has(entry.skillKey))) {
3073
+ for (const target of requiredDeclarations.filter((entry) => !presentSkillKeys.has(entry.skillKey))) {
3262
3074
  disabledNativeSkillNames.add(target.skillKey);
3263
3075
  }
3264
3076
  }
3265
- for (const target of requiredDeclarations.filter((entry) => entry.delivery?.mode === 'codex-native' && presentSkillKeys.has(entry.skillKey))) {
3077
+ for (const target of requiredDeclarations.filter((entry) => presentSkillKeys.has(entry.skillKey))) {
3266
3078
  const sourceRoot = path.join(payloadRoot, ...prepared.skillsRelativeRoot.split('/'), target.skillKey);
3267
3079
  await fs.copy(sourceRoot, path.join(skillsRoot, target.skillKey), {
3268
3080
  overwrite: false,
3269
3081
  errorOnExist: true,
3270
3082
  dereference: false,
3271
3083
  });
3272
- await carryRuntimeConfigNativeReceipt(path.join(skillsRoot, target.skillKey), Buffer.from(serializeCodexNativeRenderReceipt(staged.receipt)));
3084
+ await carryRuntimeConfigNativeReceipt(path.join(skillsRoot, target.skillKey), Buffer.from(serializeNativeSkillRenderReceipt(staged.receipt)));
3273
3085
  }
3274
3086
  await fs.remove(marketplaceRoot);
3275
3087
  }
3276
3088
  commandCandidates = await prepareReferences(staticTrees, staticScope, false);
3277
- commandCandidates = await prepareReferences(directTrees, options.scope, false);
3278
3089
  for (const tree of staticTrees) {
3279
3090
  for (const [relativePath, content] of Object.entries(tree.files)) {
3280
3091
  if (relativePath.endsWith('.md')) {
@@ -3282,9 +3093,6 @@ export async function materializeReviewNativeSkills(options) {
3282
3093
  }
3283
3094
  }
3284
3095
  }
3285
- for (const tree of directTrees) {
3286
- await writeDynamicSkillTree(path.join(skillsRoot, tree.skillKey), tree);
3287
- }
3288
3096
  const skills = [];
3289
3097
  for (const skill of selectedNames.sort((left, right) => left.localeCompare(right))) {
3290
3098
  const skillRoot = path.join(skillsRoot, skill);
@@ -3554,6 +3362,71 @@ async function applyPlannedOperationAction(action) {
3554
3362
  }
3555
3363
  function createNativeDriver(options) {
3556
3364
  const runner = options.context.nativeCliRunner;
3365
+ const nativeBindingRecoveryEvidence = new WeakMap();
3366
+ const captureNativeBindingRecoveryEvidence = async (target, producers) => {
3367
+ const captured = nativeBindingRecoveryEvidence.get(target);
3368
+ if (captured)
3369
+ return captured;
3370
+ const evidence = [];
3371
+ const finish = () => {
3372
+ nativeBindingRecoveryEvidence.set(target, evidence);
3373
+ return evidence;
3374
+ };
3375
+ const nativeProducers = producers.filter(({ producer }) => producer.sourceId === target.identity.sourceId
3376
+ && producer.sourceIdentity === target.identity.sourceIdentity
3377
+ && producer.pluginName === target.identity.pluginName
3378
+ && producer.platform === target.identity.platform
3379
+ && producer.scope === 'user' && producer.projectRoot === null
3380
+ && producer.kind !== 'package');
3381
+ if (nativeProducers.length === 0)
3382
+ return finish();
3383
+ const marketplaceRoot = target.identity.marketplaceRoot ?? resolveAwHome(options.context.env);
3384
+ const marketplaceName = target.identity.marketplaceName ?? MARKETPLACE_NAME;
3385
+ const marketplace = await readStrictNamespacedMarketplaceRoot({
3386
+ rootDir: marketplaceRoot, sourceId: target.identity.sourceId,
3387
+ sourceIdentity: target.identity.sourceIdentity, marketplaceName,
3388
+ });
3389
+ if (!marketplace)
3390
+ return finish();
3391
+ const pluginRoot = await assertSafeNamespacedMarketplacePluginRoot(marketplaceRoot, target.identity.pluginName);
3392
+ const manifest = await readNativeSkillProjectionManifest(path.join(pluginRoot, `.${target.identity.platform}-plugin`, 'plugin.json'));
3393
+ if (manifest.state === 'unsafe' || manifest.state === 'unreadable') {
3394
+ throw new Error('commandOwnerMismatch: the previous Native platform manifest cannot authorize binding recovery.');
3395
+ }
3396
+ if (manifest.state !== 'present')
3397
+ return finish();
3398
+ if (manifest.value.name !== target.identity.pluginName) {
3399
+ throw new Error('commandOwnerMismatch: the previous Native platform belongs to another plugin.');
3400
+ }
3401
+ if (typeof manifest.value.skills !== 'string')
3402
+ return finish();
3403
+ const { root: skillsRoot } = await resolveNativeSkillsRoot(pluginRoot, manifest.value.skills, target.identity.platform);
3404
+ const dynamic = nativeProducers.some(({ producer }) => producer.kind === 'artifact')
3405
+ ? await resolveNativeSkillRenderExpectedEvidence({
3406
+ plugin: target.plugin, platform: target.identity.platform,
3407
+ referencePlugins: options.context.referencePlugins,
3408
+ marketplaceRoot, marketplaceName, env: options.context.env,
3409
+ })
3410
+ : undefined;
3411
+ if (dynamic?.state === 'issue' && dynamic.reason !== 'damaged') {
3412
+ throw new Error(`commandOwnerMismatch: previous Native evidence is ${dynamic.reason}: ${dynamic.diagnostic}.`);
3413
+ }
3414
+ for (const { producer } of nativeProducers) {
3415
+ const skillKey = producer.kind === 'static-skill' ? producer.key
3416
+ : dynamic?.state === 'present'
3417
+ ? dynamic.receipt.targets.find((entry) => entry.id === producer.key)?.skillKey
3418
+ : undefined;
3419
+ if (!skillKey)
3420
+ continue;
3421
+ const resourceRoot = path.join(skillsRoot, skillKey);
3422
+ if (!await lstatIfPresent(path.join(resourceRoot, COMMAND_PRODUCER_RECORD_FILE)))
3423
+ continue;
3424
+ evidence.push(await captureManagedCommandBindingRecoveryEvidence({
3425
+ producer, resourceRoot, env: options.context.env,
3426
+ }));
3427
+ }
3428
+ return finish();
3429
+ };
3557
3430
  const preflightCommandBindings = async (targets) => {
3558
3431
  const producers = [];
3559
3432
  for (const target of targets)
@@ -3568,7 +3441,27 @@ function createNativeDriver(options) {
3568
3441
  producers.push(normalizeInstalledCommandProducer(JSON.parse(Buffer.from(file.contentBase64, 'base64').toString('utf8'))));
3569
3442
  }
3570
3443
  }
3571
- await assertManagedCommandBindingIdentities({ producers, env: options.context.env });
3444
+ const captured = targets.flatMap((target) => nativeBindingRecoveryEvidence.get(target) ?? []);
3445
+ try {
3446
+ await assertManagedCommandBindingIdentities({ producers, bindingRecoveryEvidence: captured, env: options.context.env });
3447
+ }
3448
+ catch (error) {
3449
+ if (!(error instanceof ManagedCommandError) || error.code !== 'commandBindingInvalid')
3450
+ throw error;
3451
+ const needsRecovery = [];
3452
+ for (const producer of producers) {
3453
+ try {
3454
+ await assertManagedCommandBindingIdentities({ producers: [producer], bindingRecoveryEvidence: captured, env: options.context.env });
3455
+ }
3456
+ catch (issue) {
3457
+ if (!(issue instanceof ManagedCommandError) || issue.code !== 'commandBindingInvalid')
3458
+ throw issue;
3459
+ needsRecovery.push(producer);
3460
+ }
3461
+ }
3462
+ const bindingRecoveryEvidence = (await Promise.all(targets.map((target) => captureNativeBindingRecoveryEvidence(target, needsRecovery)))).flat();
3463
+ await assertManagedCommandBindingIdentities({ producers, bindingRecoveryEvidence, env: options.context.env });
3464
+ }
3572
3465
  };
3573
3466
  const revokeAtRoot = async (root, recursive = false, platform) => {
3574
3467
  const listed = await listManagedCommands(options.context.env);
@@ -3637,7 +3530,68 @@ function createNativeDriver(options) {
3637
3530
  }
3638
3531
  };
3639
3532
  const currentCodexManager = () => options.context.codexManager;
3533
+ const requireClaudeActivationOnlyProvider = async (target) => {
3534
+ const marketplaceName = target.identity.marketplaceName ?? MARKETPLACE_NAME;
3535
+ const marketplaceRoot = target.identity.marketplaceRoot ?? resolveAwHome(options.context.env);
3536
+ const marketplace = await readStrictNamespacedMarketplaceRoot({
3537
+ trustedMarketplaceRoot: path.join(resolveAwHome(options.context.env), 'marketplaces'),
3538
+ rootDir: marketplaceRoot,
3539
+ });
3540
+ if (!marketplace
3541
+ || marketplace.config.sourceId !== target.identity.sourceId
3542
+ || marketplace.config.sourceIdentity !== target.identity.sourceIdentity
3543
+ || marketplace.config.marketplaceName !== marketplaceName) {
3544
+ throw new Error('nativeActivationOnlyRequiresHealthySharedPackage: the Claude marketplace owner does not match the requested source.');
3545
+ }
3546
+ const provider = await readClaudeNativeState({
3547
+ pluginName: target.identity.pluginName,
3548
+ scope: 'user',
3549
+ cwd: target.identity.cwd,
3550
+ env: options.context.env,
3551
+ marketplaceName,
3552
+ marketplaceRoot,
3553
+ });
3554
+ if (provider.marketplaceDeclaredState !== 'canonical'
3555
+ || provider.marketplaceMaterializedState !== 'canonical'
3556
+ || provider.pluginState !== 'present'
3557
+ || !provider.pluginEnabled
3558
+ || provider.pluginVersions.length === 0
3559
+ || provider.pluginVersions.some((version) => version !== target.identity.pluginVersion)) {
3560
+ throw new Error('nativeActivationOnlyRequiresHealthySharedPackage: an enabled current User Claude provider is required.');
3561
+ }
3562
+ const pluginRoot = await assertSafeNamespacedMarketplacePluginRoot(marketplaceRoot, target.identity.pluginName);
3563
+ if (!await codexPayloadPathSafe(pluginRoot, marketplaceRoot)) {
3564
+ throw new Error('nativeActivationOnlyRequiresHealthySharedPackage: the Claude package has an unsafe payload path.');
3565
+ }
3566
+ const installed = await readPluginManifest(pluginRoot, { mode: 'bundle' });
3567
+ const platformManifest = await readNativeSkillProjectionManifest(path.join(pluginRoot, '.claude-plugin', 'plugin.json'));
3568
+ if (installed.manifest.name !== target.identity.pluginName
3569
+ || installed.manifest.version !== target.identity.pluginVersion
3570
+ || platformManifest.state !== 'present'
3571
+ || platformManifest.value.name !== target.identity.pluginName
3572
+ || platformManifest.value.version !== target.identity.pluginVersion) {
3573
+ throw new Error('nativeActivationOnlyRequiresHealthySharedPackage: the Claude package manifest is missing or outdated.');
3574
+ }
3575
+ if (nativeSkillRenderTargets(target.plugin, 'claude').length > 0) {
3576
+ const evidence = await resolveNativeSkillRenderExpectedEvidence({
3577
+ plugin: target.plugin, platform: 'claude', referencePlugins: options.context.referencePlugins,
3578
+ marketplaceRoot, marketplaceName, env: options.context.env,
3579
+ });
3580
+ if (evidence.state !== 'present' || evidence.sourceProjection !== 'current') {
3581
+ throw new Error('nativeActivationOnlyRequiresHealthySharedPackage: the Claude Skill projection is not current.');
3582
+ }
3583
+ }
3584
+ const selected = await readClaudeNativeState({
3585
+ pluginName: target.identity.pluginName, scope: target.identity.scope,
3586
+ cwd: target.identity.cwd, env: options.context.env, marketplaceName, marketplaceRoot,
3587
+ });
3588
+ if (selected.marketplaceState === 'foreign' || selected.pluginState === 'foreign') {
3589
+ throw new Error('externalOwnershipPresent: the Claude activation target belongs to a foreign marketplace.');
3590
+ }
3591
+ return selected;
3592
+ };
3640
3593
  const nativeGroupPreparations = new Map();
3594
+ const nativeGroupPublications = new Map();
3641
3595
  const nativeTargetPreparations = new WeakMap();
3642
3596
  const codexNativeStates = new Map();
3643
3597
  const pendingCodexNativeStates = new Map();
@@ -3752,15 +3706,15 @@ function createNativeDriver(options) {
3752
3706
  await fs.chmod(destination, file.mode ?? 0o644);
3753
3707
  }
3754
3708
  }
3755
- if (candidate.identity.platform !== 'codex')
3756
- continue;
3709
+ const platform = candidate.identity.platform;
3757
3710
  const hasStaticSkills = candidate.plugin.manifest.skills !== undefined;
3758
- const preparedNativeRender = await requirePreparedCodexNativeRender({
3711
+ const preparedNativeRender = await requirePreparedNativeSkillRender({
3759
3712
  context: options.context,
3760
3713
  plugin: candidate.plugin,
3714
+ platform,
3761
3715
  });
3762
3716
  const nativeRender = preparedNativeRender
3763
- ? await materializeCodexNativeRender({
3717
+ ? await materializeNativeSkillRender({
3764
3718
  plugin: candidate.plugin,
3765
3719
  stagingRoot,
3766
3720
  prepared: preparedNativeRender,
@@ -3769,25 +3723,36 @@ function createNativeDriver(options) {
3769
3723
  : null;
3770
3724
  if (nativeRender)
3771
3725
  renderedReceipts.push({ pluginName: candidate.identity.pluginName, receipt: nativeRender.receipt });
3772
- if (!nativeRender) {
3726
+ if (!nativeRender && platform === 'codex') {
3773
3727
  await ensureCodexActiveSkillsManifest({
3774
3728
  plugin: candidate.plugin,
3775
3729
  marketplaceRoot: stagingRoot,
3776
3730
  hasRequiredSkills: hasStaticSkills,
3777
3731
  });
3778
3732
  }
3779
- if (pluginHasCodexNativeSkillSurface(candidate.plugin)) {
3780
- await assertNoSensitiveValuesInCodexNativePayload({
3733
+ if (hasStaticSkills || nativeSkillRenderTargets(candidate.plugin, platform).length > 0) {
3734
+ await assertNoSensitiveValuesInNativeSkillPayload({
3781
3735
  plugin: candidate.plugin,
3736
+ platform,
3782
3737
  payloadRoot: path.join(stagingRoot, 'plugins', candidate.identity.pluginName),
3783
3738
  allowedRoot: stagingRoot,
3784
- sensitiveValues: await resolveSensitiveUserConfigValues(candidate.plugin, options.context.env, options.context.referencePlugins),
3739
+ sensitiveValues: await resolveSensitiveUserConfigValues(candidate.plugin, options.context.env, options.context.referencePlugins, platform),
3785
3740
  ...(nativeRender ? { verifiedRenderReceipt: nativeRender.receipt } : {}),
3786
3741
  });
3787
3742
  }
3788
3743
  }
3789
3744
  for (const receipt of renderedReceipts)
3790
3745
  await refreshPreservedPlatformReceipt(stagingRoot, receipt);
3746
+ if (first.identity.sourceId && first.identity.sourceIdentity && first.identity.marketplaceRoot) {
3747
+ nativeGroupPublications.set(key, await deferNativeMarketplacePublications({
3748
+ sourceRoot: first.identity.marketplaceRoot,
3749
+ stagingRoot,
3750
+ sourceId: first.identity.sourceId,
3751
+ sourceIdentity: first.identity.sourceIdentity,
3752
+ marketplaceName: first.identity.marketplaceName ?? MARKETPLACE_NAME,
3753
+ requestedPlatforms,
3754
+ }));
3755
+ }
3791
3756
  }, new Set(materializationTargets.map((candidate) => candidate.identity.pluginId ?? `${candidate.identity.sourceId}/${candidate.identity.pluginName}`)), requestedPlatforms);
3792
3757
  try {
3793
3758
  await transaction.commit();
@@ -3804,8 +3769,6 @@ function createNativeDriver(options) {
3804
3769
  throw error;
3805
3770
  }
3806
3771
  committedNativeGroups.add(key);
3807
- for (const candidate of materializationTargets)
3808
- await revokeAtRoot(path.join(candidate.identity.marketplaceRoot ?? resolveAwHome(options.context.env), 'plugins', candidate.identity.pluginName), true, candidate.identity.platform);
3809
3772
  })().catch((error) => {
3810
3773
  throw asNativeGroupFailure(error);
3811
3774
  });
@@ -4178,6 +4141,11 @@ function createNativeDriver(options) {
4178
4141
  : 'user'))));
4179
4142
  },
4180
4143
  preflightMutation: async (target) => {
4144
+ if (target.identity.platform === 'claude'
4145
+ && isNativeActivationOnlyTarget(options.context, target.identity)) {
4146
+ await requireClaudeActivationOnlyProvider(target);
4147
+ return;
4148
+ }
4181
4149
  await preflightCommandBindings([target]);
4182
4150
  if (!target.codexNativeObservationExpectation
4183
4151
  && !target.codexNativeSensitivePreflightRequired)
@@ -4238,10 +4206,13 @@ function createNativeDriver(options) {
4238
4206
  || (Object.hasOwn(config.snapshot.plugins, expectedPluginId) && !canonical)) {
4239
4207
  throw new Error(`externalOwnershipPresent: Codex marketplace ${marketplaceName} has a foreign source instead of its canonical namespaced root.`);
4240
4208
  }
4241
- if (target.nativeOverlayDesired) {
4242
- await prepareCodexNativeRenderCached({
4209
+ if (target.nativeOverlayDesired
4210
+ && options.targets.some((candidate) => nativeGroupKey(candidate) === nativeGroupKey(target)
4211
+ && (candidate.writeNativeRequired ?? candidate.requiresNative))) {
4212
+ await prepareNativeSkillRenderCached({
4243
4213
  context: options.context,
4244
4214
  plugin: target.plugin,
4215
+ platform: target.identity.platform,
4245
4216
  scriptTimeoutMs: options.scriptTimeoutMs,
4246
4217
  });
4247
4218
  }
@@ -4302,7 +4273,25 @@ function createNativeDriver(options) {
4302
4273
  });
4303
4274
  if (state.pluginState !== 'present')
4304
4275
  return state.pluginState;
4305
- return state.pluginEnabled ? 'present' : 'partial';
4276
+ if (!state.pluginEnabled)
4277
+ return 'partial';
4278
+ if (nativeSkillRenderTargets(target.plugin, 'claude').length === 0)
4279
+ return 'present';
4280
+ const evidence = await resolveNativeSkillRenderExpectedEvidence({
4281
+ plugin: target.plugin,
4282
+ platform: 'claude',
4283
+ referencePlugins: options.context.referencePlugins,
4284
+ marketplaceRoot: target.identity.marketplaceRoot ?? resolveAwHome(options.context.env),
4285
+ marketplaceName: target.identity.marketplaceName ?? MARKETPLACE_NAME,
4286
+ env: options.context.env,
4287
+ });
4288
+ if (evidence.state === 'issue') {
4289
+ if (evidence.reason === 'unreadable') {
4290
+ throw new Error(`claudeNativeRenderEvidenceUnreadable: ${evidence.diagnostic}`);
4291
+ }
4292
+ return evidence.reason === 'foreign' ? 'foreign' : 'partial';
4293
+ }
4294
+ return evidence.sourceProjection === 'current' ? 'present' : 'partial';
4306
4295
  }
4307
4296
  if (target.identity.platform === 'codex') {
4308
4297
  const pluginId = `${target.identity.pluginName}@${target.identity.marketplaceName ?? MARKETPLACE_NAME}`;
@@ -4448,6 +4437,10 @@ function createNativeDriver(options) {
4448
4437
  }
4449
4438
  await prepareNativeGroup(target);
4450
4439
  const pluginId = `${target.identity.pluginName}@${marketplaceName}`;
4440
+ const publishPreparedPlatform = async () => {
4441
+ await revokeAtRoot(path.join(expectedMarketplaceRoot, 'plugins', target.identity.pluginName), true, target.identity.platform);
4442
+ await nativeGroupPublications.get(nativeGroupKey(target))?.publish(expectedMarketplaceRoot, target.identity.pluginName, target.identity.platform);
4443
+ };
4451
4444
  if (target.identity.platform === 'codex') {
4452
4445
  const stateKey = codexStateKey(target, pluginId);
4453
4446
  const codexRemovalRequired = pendingCodexNativeStates.get(stateKey)
@@ -4463,6 +4456,7 @@ function createNativeDriver(options) {
4463
4456
  });
4464
4457
  pendingCodexNativeStates.set(stateKey, 'absent');
4465
4458
  }
4459
+ await publishPreparedPlatform();
4466
4460
  const config = await readCodexConfigFile(resolveCodexPaths(target.identity.cwd, 'user', options.context.env).configTomlPath);
4467
4461
  const marketplace = config.snapshot.marketplaces[marketplaceName];
4468
4462
  if (path.normalize(marketplace?.source ?? '') !== path.normalize(expectedMarketplaceRoot)) {
@@ -4488,6 +4482,7 @@ function createNativeDriver(options) {
4488
4482
  }
4489
4483
  }
4490
4484
  else {
4485
+ await publishPreparedPlatform();
4491
4486
  await runNativeCliChecked({
4492
4487
  command: 'claude',
4493
4488
  args: ['plugin', 'marketplace', 'add', expectedMarketplaceRoot, '--scope', target.identity.scope],
@@ -4535,13 +4530,38 @@ function createNativeDriver(options) {
4535
4530
  const installed = await readInstalledCommandProducer(resourceRoot).catch(() => null);
4536
4531
  if (!installed)
4537
4532
  continue;
4538
- const commandIds = await publishManagedCommandBindings({ ...installed, resourceRoot, env: options.context.env });
4533
+ const commandIds = await publishManagedCommandBindings({ ...installed, resourceRoot,
4534
+ bindingRecoveryEvidence: nativeBindingRecoveryEvidence.get(target), env: options.context.env });
4539
4535
  options.context.commandResults ??= [];
4540
4536
  options.context.commandResults.push({ producer: installed.producer, state: 'completed', commandIds, removedCommandIds: [], errors: [], recoveryActions: [] });
4541
4537
  }
4542
4538
  }
4543
4539
  },
4544
4540
  writeArtifacts: async (target) => {
4541
+ if (target.identity.platform === 'claude'
4542
+ && isNativeActivationOnlyTarget(options.context, target.identity)) {
4543
+ const before = await requireClaudeActivationOnlyProvider(target);
4544
+ if (!before.pluginEnabled || !before.pluginVersions.includes(target.identity.pluginVersion)) {
4545
+ await runNativeCliChecked({
4546
+ command: 'claude',
4547
+ args: ['plugin', before.pluginVersions.includes(target.identity.pluginVersion) ? 'enable' : 'install',
4548
+ `${target.identity.pluginName}@${target.identity.marketplaceName ?? MARKETPLACE_NAME}`,
4549
+ '--scope', target.identity.scope],
4550
+ cwd: target.identity.cwd,
4551
+ env: options.context.env,
4552
+ }, runner);
4553
+ }
4554
+ const after = await readClaudeNativeState({
4555
+ pluginName: target.identity.pluginName, scope: target.identity.scope,
4556
+ cwd: target.identity.cwd, env: options.context.env,
4557
+ marketplaceName: target.identity.marketplaceName, marketplaceRoot: target.identity.marketplaceRoot,
4558
+ });
4559
+ if (after.pluginState !== 'present' || !after.pluginEnabled
4560
+ || !after.pluginVersions.includes(target.identity.pluginVersion)) {
4561
+ throw new Error('claudeActivationPostcheckFailed: the requested scope is not enabled at the expected version.');
4562
+ }
4563
+ return [];
4564
+ }
4545
4565
  await preflightCommandBindings([target]);
4546
4566
  await publishPackages(target);
4547
4567
  for (const operationAction of target.operationActions ?? []) {
@@ -4611,7 +4631,13 @@ function createNativeDriver(options) {
4611
4631
  },
4612
4632
  };
4613
4633
  }
4634
+ export function isNativeActivationOnlyTarget(context, identity) {
4635
+ return context.nativeActivationOnlyTargets?.some((target) => target.pluginId === identity.pluginId
4636
+ && target.platform === identity.platform
4637
+ && target.scope === identity.scope) === true;
4638
+ }
4614
4639
  export function createRebuildIntegration(options) {
4640
+ options.context.scriptTimeoutMs ??= options.scriptTimeoutMs;
4615
4641
  const targets = [...(options.preparedTargets ?? [])];
4616
4642
  const driver = createNativeDriver({ targets, ...options });
4617
4643
  return {
@@ -4626,6 +4652,13 @@ export function createRebuildIntegration(options) {
4626
4652
  sourceIdentity: input.sourceIdentity ?? input.plugin.sourceIdentity,
4627
4653
  pluginId: input.pluginId ?? input.plugin.pluginId,
4628
4654
  };
4655
+ const activationOnly = isNativeActivationOnlyTarget(options.context, {
4656
+ pluginId: input.pluginId,
4657
+ platform: input.platform,
4658
+ scope: input.scope,
4659
+ }) && input.command !== 'cleanup' && input.command !== 'uninstall';
4660
+ if (activationOnly)
4661
+ input = { ...input, readOnlyInspectionPlan: true };
4629
4662
  const materializing = input.command !== 'cleanup'
4630
4663
  && input.command !== 'uninstall'
4631
4664
  && input.readOnlyInspectionPlan !== true;
@@ -4652,8 +4685,8 @@ export function createRebuildIntegration(options) {
4652
4685
  options.context.managedCommandCandidates ??= new Map();
4653
4686
  options.context.managedCommandCandidates.set(pluginActionId(input.plugin), commands.candidates);
4654
4687
  const nativeSkillActions = [];
4655
- if (materializing && input.platform === 'codex' && input.plugin.manifest.managedCommands && codexNativeRenderTargets(input.plugin).length) {
4656
- const native = await prepareCodexNativeRenderCached({ context: options.context, plugin: input.plugin, scriptTimeoutMs: options.scriptTimeoutMs });
4688
+ if (materializing && nativeSkillRenderTargets(input.plugin, input.platform).length) {
4689
+ const native = await prepareNativeSkillRenderCached({ context: options.context, plugin: input.plugin, platform: input.platform, scriptTimeoutMs: options.scriptTimeoutMs });
4657
4690
  if (native) {
4658
4691
  commands.candidates.push(...native.commandCandidates);
4659
4692
  for (const { artifact, skillKey, tree } of native.renderedArtifacts) {
@@ -4663,7 +4696,7 @@ export function createRebuildIntegration(options) {
4663
4696
  ...(tree.fileModes?.[relativePath] ? { mode: tree.fileModes[relativePath] } : {}),
4664
4697
  })).sort((left, right) => left.relativePath.localeCompare(right.relativePath));
4665
4698
  nativeSkillActions.push({ kind: 'materializeNativeSkill', pluginId: pluginActionId(input.plugin),
4666
- platform: 'codex', scope: 'user', artifactId: artifact.id, skillKey, files,
4699
+ platform: input.platform, scope: 'user', artifactId: artifact.id, skillKey, files,
4667
4700
  contentDigest: `sha256:${crypto.createHash('sha256').update(JSON.stringify(files)).digest('hex')}` });
4668
4701
  }
4669
4702
  }
@@ -4690,6 +4723,7 @@ export function createRebuildIntegration(options) {
4690
4723
  env: options.context.env,
4691
4724
  event,
4692
4725
  historicalArtifacts,
4726
+ signal: options.context.signal,
4693
4727
  scriptTimeoutMs: options.scriptTimeoutMs,
4694
4728
  marketplaceName: input.marketplaceName,
4695
4729
  userActivationDesired: options.context.codexUserActivationDesired,
@@ -4704,6 +4738,7 @@ export function createRebuildIntegration(options) {
4704
4738
  env: options.context.env,
4705
4739
  event,
4706
4740
  historicalArtifacts,
4741
+ signal: options.context.signal,
4707
4742
  scriptTimeoutMs: options.scriptTimeoutMs,
4708
4743
  commandCandidates: commands.candidates,
4709
4744
  nativeSkillActions,
@@ -4727,6 +4762,8 @@ export function createRebuildIntegration(options) {
4727
4762
  ...(write.component ? [write.component] : []),
4728
4763
  ]);
4729
4764
  }
4765
+ if (activationOnly)
4766
+ writes = [];
4730
4767
  const desiredComponents = writes.filter((write) => !write.optional).flatMap((write) => [
4731
4768
  ...(write.additionalComponents ?? []),
4732
4769
  ...(write.component ? [write.component] : []),
@@ -4867,16 +4904,14 @@ export function createRebuildIntegration(options) {
4867
4904
  && codexRegistration.observation.value === 'installed'
4868
4905
  && (codexRegistration.observation.entry.version === undefined
4869
4906
  || codexRegistration.observation.entry.version === input.plugin.manifest.version);
4870
- const materializeNativeRequired = nativeDesired && (input.platform === 'claude'
4907
+ const materializeNativeRequired = !activationOnly && nativeDesired && (input.platform === 'claude'
4871
4908
  || input.command === 'reinstall'
4872
4909
  || !codexNativeExact
4910
+ || (materializing && nativeSkillRenderTargets(input.plugin, input.platform).length > 0)
4873
4911
  || (materializing && await hasPreparedStaticNativeCommandDrift({ plugin: input.plugin, cwd: input.cwd, env: options.context.env, context: options.context, marketplaceRoot: input.marketplaceRoot ?? resolveAwHome(options.context.env) })));
4874
- const nativeCleanupCandidate = input.platform === 'claude'
4875
- ? input.includeNativeCleanupCandidate !== false
4876
- : input.platform === 'codex'
4877
- && (nativeRequired || (input.removedPluginWhole === true
4878
- && input.includeNativeCleanupCandidate === true))
4879
- && (input.command === 'cleanup' || input.command === 'uninstall');
4912
+ const nativeCleanupCandidate = input.includeNativeCleanupCandidate !== false
4913
+ && (input.command === 'cleanup' || input.command === 'uninstall')
4914
+ && (input.platform === 'claude' || (input.platform === 'codex' && nativeRequired));
4880
4915
  const nativePlugin = (nativeDesired || nativeCleanupCandidate)
4881
4916
  ? [{
4882
4917
  kind: 'native-plugin',
@@ -4956,7 +4991,13 @@ export function createRebuildIntegration(options) {
4956
4991
  ...marketplace,
4957
4992
  ...activationCleanup,
4958
4993
  ...explicitActivationCleanup,
4959
- ]);
4994
+ ]).filter((component) => (!activationOnly
4995
+ || component.kind === 'native-plugin'
4996
+ || (input.platform === 'codex' && component.kind === 'shared-config'
4997
+ && (component.identity.artifactKey.startsWith('marketplace-')
4998
+ || component.identity.artifactKey.startsWith('activation-'))))
4999
+ && (options.context.preserveLegacyNativeSkills !== true
5000
+ || component.kind !== 'skill-directory'));
4960
5001
  bindNamespacedOwnerIdentity(allComponents, input);
4961
5002
  const desiredKeys = new Set(desiredComponents.map(componentIdentityKey));
4962
5003
  const retainedPackages = input.command === 'cleanup' || input.command === 'uninstall'
@@ -5039,7 +5080,7 @@ export function createRebuildIntegration(options) {
5039
5080
  optionalOwnedComponents: allComponents.filter((component) => optionalComponentKeys.has(componentIdentityKey(component))),
5040
5081
  requiresNative: nativeDesired,
5041
5082
  writeNativeRequired: materializeNativeRequired,
5042
- nativeOverlayDesired: nativeDesired,
5083
+ nativeOverlayDesired: nativeDesired && !activationOnly,
5043
5084
  artifacts: writes.map((write) => write.artifact),
5044
5085
  operationActions,
5045
5086
  catalog: input.catalog,