@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
@@ -6,7 +6,7 @@ import { createRequire } from 'node:module';
6
6
  import * as os from 'node:os';
7
7
  import * as path from 'node:path';
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url';
9
- import { assertPluginConfigReferenceSchemas, AW_RUNTIME_CONFIG_READER_PATH, createNativeToolReaderSource, createRuntimeConfigSnapshot, getPluginAuthoringAcceptedValues as getCorePluginAuthoringAcceptedValues, getSkillFrontmatterCapabilityRegistry, getManagedCommandArtifactTargets, normalizePluginConfigDefinition, parseManagedCommandPlaceholders, replaceManagedCommandPlaceholders, validateCommandEntryFiles, validatePluginConfigCandidate, formatPluginConfigIssue, } from '@lesliechan721/aw-plugin-core/manifest';
9
+ import { assertPluginConfigReferenceSchemas, AW_RUNTIME_CONFIG_READER_PATH, createNativeToolReaderSource, createRuntimeConfigSnapshot, getPluginAuthoringAcceptedValues as getCorePluginAuthoringAcceptedValues, getSkillFrontmatterCapabilityRegistry, getManagedCommandArtifactTargets, normalizePluginConfigDefinition, compilePluginConfigDefinition, resolveSupportedPlatforms, PLATFORM_TARGETS, isPortablePlatformTarget, SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION, parseManagedCommandPlaceholders, replaceManagedCommandPlaceholders, validateCommandEntryFiles, validatePluginConfigCandidate, formatPluginConfigIssue, } from '@lesliechan721/aw-plugin-core/manifest';
10
10
  import { readCatalogWorkspace } from '@lesliechan721/aw-plugin-core';
11
11
  import { checkPluginVersions } from './lib/plugin-version-check.mjs';
12
12
  import { scanJavaScriptImportSpecifiers } from './lib/javascript-import-scanner.mjs';
@@ -19,7 +19,6 @@ const CLI_PACKAGE_ROOT = path.basename(authoringRuntimeRoot) === 'dist'
19
19
  : authoringRuntimeRoot;
20
20
  const errors = [];
21
21
  const warnings = [];
22
- const SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION = 18;
23
22
  let capabilityDiagnostic = null;
24
23
  const MAX_SKILL_NAME_LEN = 64;
25
24
  const MAX_SKILL_DESCRIPTION_LEN = 1024;
@@ -52,7 +51,7 @@ const CODEX_POLICY_PRODUCTS = new Set([
52
51
  'codex',
53
52
  'CODEX',
54
53
  ]);
55
- const MANIFEST_POLICY_PRODUCTS = new Set(getPluginAuthoringAcceptedValues('manifest', 'marketplace.policy.products'));
54
+ const MANIFEST_PLATFORMS = new Set(getPluginAuthoringAcceptedValues('manifest', 'platforms'));
56
55
  const MARKETPLACE_AUTHENTICATION_POLICIES = new Set(getPluginAuthoringAcceptedValues('manifest', 'marketplace.policy.authentication'));
57
56
  const MARKETPLACE_INSTALLATION_POLICIES = new Set(getPluginAuthoringAcceptedValues('manifest', 'marketplace.policy.installation'));
58
57
  const PUBLIC_HOOK_EVENTS = new Set(['before_tool', 'after_tool', 'session_start']);
@@ -128,23 +127,6 @@ const DEFAULT_SLASH_COMMANDS_DIR = 'slash-commands';
128
127
  const SCRIPT_NODE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs']);
129
128
  const SCRIPT_TIMEOUT_MIN_MS = 1000;
130
129
  const SCRIPT_TIMEOUT_MAX_MS = 1800000;
131
- const ARTIFACT_TARGETS = new Set(getPluginAuthoringAcceptedValues('artifacts', 'artifacts.targets[].target'));
132
- const ARTIFACT_STATES = new Set(getPluginAuthoringAcceptedValues('artifacts', 'artifacts.targets[].states'));
133
- const ARTIFACT_SCOPES = new Set(['user', 'project']);
134
- const ARTIFACT_KINDS = new Set(['instruction', 'codexRole', 'skill']);
135
- const ARTIFACT_PROJECT_MANAGED_KINDS = new Set(['instruction', 'agent', 'skill']);
136
- const ARTIFACT_KIND_BY_TARGET = {
137
- 'codex.developerInstructionsBlock': 'instruction',
138
- 'codex.agentRole': 'codexRole',
139
- 'codex.skill': 'skill',
140
- 'claude.skill': 'skill',
141
- 'agent-skills.skill': 'skill',
142
- };
143
- const ARTIFACT_PROJECT_MANAGED_KIND_BY_TARGET = {
144
- 'codex.developerInstructionsBlock': 'instruction',
145
- 'codex.agentRole': 'agent',
146
- 'codex.skill': 'skill',
147
- };
148
130
  const PLUGIN_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
149
131
  let yamlParser = null;
150
132
  let pluginVersionCheckResult = null;
@@ -493,167 +475,11 @@ function validateStrictSemVerString(value, fieldName) {
493
475
  }
494
476
  return value;
495
477
  }
496
- function validateManifestLightweight(manifest) {
497
- const input = expectRecord(manifest, 'plugin manifest');
498
- if (!input)
499
- return;
500
- if (Object.prototype.hasOwnProperty.call(input, 'commands')) {
501
- error('top-level "commands" has been removed; use "slashCommands" instead');
502
- }
503
- validateAllowedKeys(input, 'plugin manifest', [
504
- 'schemaVersion',
505
- 'name',
506
- 'version',
507
- 'description',
508
- 'dependencies',
509
- 'requires',
510
- 'skills',
511
- 'slashCommands',
512
- 'mcpServers',
513
- 'apps',
514
- 'distributions',
515
- 'marketplace',
516
- 'interface',
517
- 'extensions',
518
- 'buildConfig',
519
- 'scripts',
520
- 'config',
521
- 'artifacts',
522
- 'managedCommands',
523
- ]);
524
- if (manifest.dependencies !== undefined) {
525
- if (!Array.isArray(manifest.dependencies)) {
526
- error('dependencies must be an array');
527
- }
528
- else if (manifest.dependencies.length > 64) {
529
- error('dependencies must contain at most 64 direct plugin dependencies');
530
- }
531
- else {
532
- const seen = new Set();
533
- for (const [index, dependency] of manifest.dependencies.entries()) {
534
- if (typeof dependency !== 'string' || !PLUGIN_NAME_PATTERN.test(dependency)) {
535
- error(`dependencies[${index}] must be an ASCII lowercase hyphen-case plugin name`);
536
- continue;
537
- }
538
- if (dependency === manifest.name) {
539
- error(`plugin "${manifest.name}" cannot depend on itself`);
540
- }
541
- if (seen.has(dependency)) {
542
- error(`dependencies contains duplicate plugin "${dependency}"`);
543
- }
544
- seen.add(dependency);
545
- }
546
- }
547
- }
548
- for (const field of ['name', 'version', 'description', 'marketplace']) {
549
- if (!manifest[field]) {
550
- error(`Missing required field: ${field}`);
551
- }
552
- }
553
- if (manifest.name && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(manifest.name)) {
554
- error(`manifest name "${manifest.name}" is not lowercase-hyphen-case`);
555
- }
556
- if (manifest.version) {
557
- const pluginVersion = parseStrictSemVer(manifest.version);
558
- if (!pluginVersion) {
559
- error(`manifest.version must be a strict SemVer 2.0.0 string, got "${manifest.version}"`);
560
- }
561
- else if (pluginVersion.prerelease.length > 0 || pluginVersion.build.length > 0) {
562
- error('manifest.version must be a stable SemVer without prerelease or build metadata');
563
- }
564
- }
565
- if (manifest.marketplace) {
566
- const mp = manifest.marketplace;
567
- if (!mp.category)
568
- error('marketplace.category is required');
569
- if (typeof mp.strict !== 'boolean')
570
- error('marketplace.strict must be a boolean');
571
- if (!mp.policy || !mp.policy.installation)
572
- error('marketplace.policy.installation is required');
573
- else if (!MARKETPLACE_INSTALLATION_POLICIES.has(mp.policy.installation))
574
- error(`marketplace.policy.installation must be one of ${[...MARKETPLACE_INSTALLATION_POLICIES].map((value) => JSON.stringify(value)).join(', ')}`);
575
- if (!mp.policy || !mp.policy.authentication)
576
- error('marketplace.policy.authentication is required');
577
- else if (!MARKETPLACE_AUTHENTICATION_POLICIES.has(mp.policy.authentication))
578
- error('marketplace.policy.authentication must be "ON_INSTALL" or "ON_USE"');
579
- validateManifestPolicyProducts(mp.policy?.products);
580
- }
581
- for (const field of ['skills', 'slashCommands', 'mcpServers', 'apps']) {
582
- if (manifest[field] && !manifest[field].startsWith('./')) {
583
- error(`${field} path must start with "./", got "${manifest[field]}"`);
584
- }
585
- }
586
- const claudeCommands = manifest.buildConfig?.manifestOverrides?.claude?.commands;
587
- if (claudeCommands !== undefined) {
588
- error('buildConfig.manifestOverrides.claude.commands has been removed; use "slashCommands" instead');
589
- }
590
- for (const platform of ['claude', 'codex']) {
591
- const rules = manifest.buildConfig?.fileRules?.[platform];
592
- if (!rules)
593
- continue;
594
- for (const pattern of [...(rules.include ?? []), ...(rules.exclude ?? [])]) {
595
- const normalized = String(pattern).replace(/\\/g, '/').replace(/^\.\//, '');
596
- if (normalized === 'commands' || normalized.startsWith('commands/')) {
597
- error(`buildConfig.fileRules.${platform} no longer accepts legacy "commands/**" source rules; use "slashCommands" instead`);
598
- }
599
- }
600
- }
601
- validateExtensionsLightweight(manifest.extensions);
602
- validatePlatformFieldSupport(manifest);
603
- }
604
- function validatePortableNativeArtifactCapabilityLightweight(manifest) {
605
- if (manifest.distributions?.agentSkills === undefined)
606
- return;
607
- const hasOtherNativeDeclaration = Boolean(manifest.skills
608
- || manifest.slashCommands
609
- || manifest.mcpServers
610
- || manifest.apps
611
- || (manifest.extensions?.instructions?.length ?? 0) > 0
612
- || (manifest.extensions?.permissions?.length ?? 0) > 0
613
- || (manifest.extensions?.hooks?.length ?? 0) > 0
614
- || (manifest.extensions?.nativeHooks?.claude?.length ?? 0) > 0
615
- || (manifest.extensions?.nativeHooks?.codex?.length ?? 0) > 0
616
- || (manifest.extensions?.agents?.length ?? 0) > 0);
617
- const hasPresentNativeArtifact = (manifest.artifacts?.targets ?? []).some((target) => (target?.platform === 'claude' || target?.platform === 'codex')
618
- && Array.isArray(target.states)
619
- && target.states.includes('present'));
620
- if (!hasOtherNativeDeclaration && !hasPresentNativeArtifact) {
621
- const message = 'Invalid plugin manifest: portable-only plugins are not supported. Declare at least one non-empty native capability.';
622
- if (!errors.includes(message))
623
- error(message);
624
- }
625
- }
626
- function normalizeManifestProductToken(value) {
627
- return String(value).trim().toUpperCase().replace(/[\s-]+/g, '_');
628
- }
629
- function resolveSupportedPlatforms(manifest) {
630
- const products = manifest.marketplace?.policy?.products;
631
- if (!Array.isArray(products) || products.length === 0) {
632
- return new Set(['claude', 'codex']);
633
- }
634
- const supported = new Set();
635
- for (const product of products) {
636
- const normalized = normalizeManifestProductToken(product);
637
- if (normalized === 'CLAUDE')
638
- supported.add('claude');
639
- if (normalized === 'CODEX')
640
- supported.add('codex');
641
- }
642
- return supported;
643
- }
644
478
  function supportsManifestPlatform(manifest, platform) {
645
479
  return resolveSupportedPlatforms(manifest).has(platform);
646
480
  }
647
- function formatManifestProductsForError(manifest) {
648
- const products = manifest.marketplace?.policy?.products;
649
- if (!Array.isArray(products) || products.length === 0) {
650
- return 'marketplace.policy.products=[]';
651
- }
652
- const normalized = [...new Set(products.map(normalizeManifestProductToken))];
653
- return `marketplace.policy.products=[${normalized.join(', ')}]`;
654
- }
655
- function platformProductName(platform) {
656
- return platform === 'claude' ? 'CLAUDE' : 'CODEX';
481
+ function formatManifestPlatformsForError(manifest) {
482
+ return `platforms=[${[...resolveSupportedPlatforms(manifest)].join(', ')}]`;
657
483
  }
658
484
  function pluginNameForError(manifest) {
659
485
  return typeof manifest.name === 'string' && manifest.name.trim()
@@ -663,30 +489,11 @@ function pluginNameForError(manifest) {
663
489
  function assertPlatformFieldSupported(manifest, fieldPath, requiredPlatform) {
664
490
  if (supportsManifestPlatform(manifest, requiredPlatform))
665
491
  return;
666
- error(`Invalid plugin "${pluginNameForError(manifest)}": ${fieldPath} requires ${platformProductName(requiredPlatform)} support, but ${formatManifestProductsForError(manifest)}.`);
492
+ error(`Invalid plugin "${pluginNameForError(manifest)}": ${fieldPath} requires ${requiredPlatform} support, but ${formatManifestPlatformsForError(manifest)}.`);
667
493
  }
668
494
  function hasNonEmptyOverride(value) {
669
495
  return isRecord(value) && Object.keys(value).length > 0;
670
496
  }
671
- function validateManifestPolicyProducts(products) {
672
- if (products === undefined)
673
- return;
674
- if (!Array.isArray(products)) {
675
- error('marketplace.policy.products must be an array');
676
- return;
677
- }
678
- for (const [index, product] of products.entries()) {
679
- const fieldName = `marketplace.policy.products[${index}]`;
680
- if (typeof product !== 'string' || product.trim() === '') {
681
- error(`${fieldName} must be a non-empty string`);
682
- continue;
683
- }
684
- const normalized = normalizeManifestProductToken(product);
685
- if (!MANIFEST_POLICY_PRODUCTS.has(normalized)) {
686
- error(`${fieldName} must be one of "CODEX" or "CLAUDE"`);
687
- }
688
- }
689
- }
690
497
  function validatePlatformFieldSupport(manifest) {
691
498
  if (manifest.buildConfig?.fileRules?.claude !== undefined) {
692
499
  assertPlatformFieldSupported(manifest, 'buildConfig.fileRules.claude', 'claude');
@@ -1278,7 +1085,7 @@ function targetedPlatforms(manifest) {
1278
1085
  platforms.push('claude');
1279
1086
  if (isCodexTargeted(manifest))
1280
1087
  platforms.push('codex');
1281
- return platforms.length > 0 ? platforms : ['claude', 'codex'];
1088
+ return platforms;
1282
1089
  }
1283
1090
  // ---------------------------------------------------------------------------
1284
1091
  // Supplemental checks (always run — not covered by CLI validator)
@@ -1326,7 +1133,7 @@ function validateCanonicalSkillLayout(pluginDir, manifest) {
1326
1133
  : [])
1327
1134
  .filter((target) => target &&
1328
1135
  typeof target === 'object' &&
1329
- (target.target === 'codex.skill' || target.target === 'claude.skill') &&
1136
+ (target.target === 'codex.skill' || target.target === 'claude.skill' || target.target === 'agent-skills.skill') &&
1330
1137
  typeof target.skillKey === 'string' &&
1331
1138
  Array.isArray(target.sourceDirs) &&
1332
1139
  target.sourceDirs.length > 0)
@@ -1347,18 +1154,6 @@ function validateCanonicalSkillLayout(pluginDir, manifest) {
1347
1154
  error(`skills/${skill}/README.md must not be empty`);
1348
1155
  }
1349
1156
  }
1350
- const portableRoot = manifest.distributions?.agentSkills?.skills;
1351
- for (const skill of declared.portable) {
1352
- const skillRoot = path.join(pluginDir, portableRoot, skill);
1353
- const skillReadme = path.join(skillRoot, 'README.md');
1354
- if (!fs.statSync(skillReadme, { throwIfNoEntry: false })?.isFile()) {
1355
- error(`${normalizeRelativePath(path.join(portableRoot, skill, 'README.md'))} is required`);
1356
- continue;
1357
- }
1358
- if (fs.readFileSync(skillReadme, 'utf8').trim() === '') {
1359
- error(`${normalizeRelativePath(path.join(portableRoot, skill, 'README.md'))} must not be empty`);
1360
- }
1361
- }
1362
1157
  }
1363
1158
  function validateDeclaredNativeAssets(pluginDir, manifest) {
1364
1159
  const defaults = [
@@ -1418,21 +1213,9 @@ function collectDeclaredSkillNames(pluginDir, manifest) {
1418
1213
  .map((target) => target.skillKey.trim())
1419
1214
  .sort();
1420
1215
  const dynamicSkillNameSet = new Set(dynamicSkillNames);
1421
- const portableRoot = typeof manifest.distributions?.agentSkills?.skills === 'string'
1422
- ? path.join(pluginDir, manifest.distributions.agentSkills.skills)
1423
- : null;
1424
- const portableRootStats = portableRoot
1425
- ? fs.lstatSync(portableRoot, { throwIfNoEntry: false })
1426
- : null;
1427
- const portableSkillNameSet = new Set(portableRootStats?.isDirectory() && !portableRootStats.isSymbolicLink()
1428
- ? fs.readdirSync(portableRoot, { withFileTypes: true })
1429
- .filter((entry) => entry.isDirectory())
1430
- .map((entry) => entry.name)
1431
- : []);
1432
1216
  return {
1433
1217
  static: staticSkillNameSet,
1434
1218
  dynamic: dynamicSkillNameSet,
1435
- portable: portableSkillNameSet,
1436
1219
  all: new Set([...staticSkillNames, ...dynamicSkillNames]),
1437
1220
  };
1438
1221
  }
@@ -1713,12 +1496,8 @@ function validateConfigSchemaLightweight(config, manifest) {
1713
1496
  error(validationError instanceof Error ? validationError.message : String(validationError));
1714
1497
  }
1715
1498
  }
1716
- function configSchemaKeys(manifest) {
1717
- const schema = manifest.config?.fields;
1718
- return isRecord(schema) ? new Set(Object.keys(schema)) : new Set();
1719
- }
1720
- function defaultConfigValues(manifest) {
1721
- const schema = manifest.config?.fields;
1499
+ function defaultConfigValues(manifest, platform) {
1500
+ const schema = compilePluginConfigDefinition(manifest.config ?? { fields: {} }, platform).fields;
1722
1501
  const values = {};
1723
1502
  if (!isRecord(schema))
1724
1503
  return values;
@@ -1749,23 +1528,6 @@ function configFieldContainsSensitiveValue(field) {
1749
1528
  || (isRecord(field.additionalProperties)
1750
1529
  && field.additionalProperties.sensitive === true));
1751
1530
  }
1752
- function codexStaticNativeComponentKeys(manifest) {
1753
- if (!isCodexTargeted(manifest))
1754
- return [];
1755
- const keys = [];
1756
- if (manifest.skills)
1757
- keys.push('skills');
1758
- if (manifest.mcpServers)
1759
- keys.push('mcpServers');
1760
- if ((Array.isArray(manifest.extensions?.hooks)
1761
- && manifest.extensions.hooks.some((hook) => hook?.agentOverrides?.codex !== null))
1762
- || (Array.isArray(manifest.extensions?.nativeHooks?.codex)
1763
- && manifest.extensions.nativeHooks.codex.length > 0))
1764
- keys.push('hooks');
1765
- if (manifest.apps)
1766
- keys.push('apps');
1767
- return keys;
1768
- }
1769
1531
  function validateArtifactId(value, fieldName) {
1770
1532
  const id = validateManifestString(value, fieldName);
1771
1533
  if (!id)
@@ -1775,33 +1537,6 @@ function validateArtifactId(value, fieldName) {
1775
1537
  }
1776
1538
  return id;
1777
1539
  }
1778
- function validateCodexRoleKey(value, fieldName) {
1779
- const roleKey = validateManifestString(value, fieldName);
1780
- if (!roleKey)
1781
- return null;
1782
- if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(roleKey)) {
1783
- error(`${fieldName}: expected a valid Codex role key`);
1784
- }
1785
- return roleKey;
1786
- }
1787
- function validateCodexSkillKey(value, fieldName) {
1788
- const skillKey = validateManifestString(value, fieldName);
1789
- if (!skillKey)
1790
- return null;
1791
- if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(skillKey)) {
1792
- error(`${fieldName}: expected a valid Codex skill key`);
1793
- }
1794
- return skillKey;
1795
- }
1796
- function validatePortableSkillKey(value, fieldName) {
1797
- const skillKey = validateManifestString(value, fieldName);
1798
- if (!skillKey)
1799
- return null;
1800
- if (skillKey.length > MAX_SKILL_NAME_LEN || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(skillKey)) {
1801
- error(`${fieldName}: expected at most 64 ASCII lowercase hyphen-case characters`);
1802
- }
1803
- return skillKey;
1804
- }
1805
1540
  function validateStringArray(value, fieldName, options = {}) {
1806
1541
  if (!Array.isArray(value)) {
1807
1542
  error(`${fieldName} must be an array`);
@@ -1826,323 +1561,8 @@ function validateStringArray(value, fieldName, options = {}) {
1826
1561
  }
1827
1562
  return output;
1828
1563
  }
1829
- function validateArtifactTargetEntry(entry, index, manifest, pluginDir) {
1830
- const fieldName = `artifacts.targets[${index}]`;
1831
- const target = expectRecord(entry, fieldName);
1832
- if (!target)
1833
- return null;
1834
- validateAllowedKeys(target, fieldName, [
1835
- 'id',
1836
- 'platform',
1837
- 'distribution',
1838
- 'scopes',
1839
- 'target',
1840
- 'kind',
1841
- 'projectManagedKind',
1842
- 'states',
1843
- 'refreshKeys',
1844
- 'delivery',
1845
- 'requiresCodexProjectConfig',
1846
- 'roleKey',
1847
- 'skillKey',
1848
- 'sourceDirs',
1849
- 'runtimeImports',
1850
- 'runtimeConfig',
1851
- ]);
1852
- const id = validateArtifactId(target.id, `${fieldName}.id`);
1853
- const artifactTarget = validateManifestString(target.target, `${fieldName}.target`);
1854
- if (artifactTarget && !ARTIFACT_TARGETS.has(artifactTarget)) {
1855
- error(`${fieldName}.target: unsupported artifact target "${artifactTarget}"`);
1856
- }
1857
- const portable = artifactTarget === 'agent-skills.skill';
1858
- let delivery;
1859
- if (artifactTarget === 'codex.skill') {
1860
- delivery = expectRecord(target.delivery, `${fieldName}.delivery`);
1861
- if (delivery) {
1862
- if (delivery.mode === 'aw-extension') {
1863
- validateAllowedKeys(delivery, `${fieldName}.delivery`, ['mode']);
1864
- }
1865
- else if (delivery.mode === 'codex-native') {
1866
- validateAllowedKeys(delivery, `${fieldName}.delivery`, ['mode', 'identity', 'renderProfile']);
1867
- if (delivery.identity !== 'shared') {
1868
- error(`${fieldName}.delivery.identity: expected "shared"`);
1869
- }
1870
- if (delivery.renderProfile !== 'user') {
1871
- error(`${fieldName}.delivery.renderProfile: expected "user"`);
1872
- }
1873
- }
1874
- else {
1875
- error(`${fieldName}.delivery.mode: expected "codex-native" or "aw-extension"`);
1876
- }
1877
- }
1878
- }
1879
- else if (target.delivery !== undefined) {
1880
- error(`${fieldName}.delivery: delivery is only supported for codex.skill targets`);
1881
- }
1882
- const platform = portable || target.platform === undefined
1883
- ? undefined
1884
- : validateManifestString(target.platform, `${fieldName}.platform`);
1885
- const distribution = portable || target.distribution !== undefined
1886
- ? validateManifestString(target.distribution, `${fieldName}.distribution`)
1887
- : undefined;
1888
- if (portable) {
1889
- if (distribution !== 'agent-skills') {
1890
- error(`${fieldName}.distribution: expected "agent-skills"`);
1891
- }
1892
- if (target.platform !== undefined) {
1893
- error(`${fieldName}.platform: distribution targets do not support platform`);
1894
- }
1895
- }
1896
- else {
1897
- const expectedPlatform = artifactTarget === 'claude.skill' ? 'claude' : 'codex';
1898
- if (platform && artifactTarget && platform !== expectedPlatform) {
1899
- error(`${fieldName}.platform: target "${artifactTarget}" must use "${expectedPlatform}"`);
1900
- }
1901
- if (target.distribution !== undefined) {
1902
- error(`${fieldName}.distribution: platform targets do not support distribution`);
1903
- }
1904
- }
1905
- const expectedKind = ARTIFACT_KIND_BY_TARGET[artifactTarget];
1906
- const kind = target.kind === undefined
1907
- ? expectedKind
1908
- : validateManifestString(target.kind, `${fieldName}.kind`);
1909
- if (kind && !ARTIFACT_KINDS.has(kind)) {
1910
- error(`${fieldName}.kind: unsupported artifact kind "${kind}"`);
1911
- }
1912
- if (expectedKind && kind && kind !== expectedKind) {
1913
- error(`${fieldName}.kind: target "${artifactTarget}" requires kind "${expectedKind}"`);
1914
- }
1915
- const expectedProjectManagedKind = ARTIFACT_PROJECT_MANAGED_KIND_BY_TARGET[artifactTarget];
1916
- const projectManagedKind = target.projectManagedKind === undefined
1917
- ? expectedProjectManagedKind
1918
- : validateManifestString(target.projectManagedKind, `${fieldName}.projectManagedKind`);
1919
- if (projectManagedKind && !ARTIFACT_PROJECT_MANAGED_KINDS.has(projectManagedKind)) {
1920
- error(`${fieldName}.projectManagedKind: unsupported Codex project managed kind "${projectManagedKind}"`);
1921
- }
1922
- if (expectedProjectManagedKind &&
1923
- projectManagedKind &&
1924
- projectManagedKind !== expectedProjectManagedKind) {
1925
- error(`${fieldName}.projectManagedKind: target "${artifactTarget}" must map to "${expectedProjectManagedKind}"`);
1926
- }
1927
- if (!expectedProjectManagedKind && projectManagedKind) {
1928
- error(`${fieldName}.projectManagedKind: target "${artifactTarget}" does not support projectManagedKind`);
1929
- }
1930
- const scopes = validateStringArray(target.scopes, `${fieldName}.scopes`, {
1931
- allowed: ARTIFACT_SCOPES,
1932
- label: 'artifact scope',
1933
- requireNonEmpty: true,
1934
- });
1935
- const states = validateStringArray(target.states, `${fieldName}.states`, {
1936
- allowed: ARTIFACT_STATES,
1937
- label: 'artifact state',
1938
- requireNonEmpty: true,
1939
- });
1940
- const refreshKeys = validateStringArray(target.refreshKeys, `${fieldName}.refreshKeys`);
1941
- const schemaKeys = configSchemaKeys(manifest);
1942
- for (const [refreshIndex, refreshKey] of refreshKeys.entries()) {
1943
- if (!schemaKeys.has(refreshKey)) {
1944
- error(`${fieldName}.refreshKeys[${refreshIndex}]: unknown config key "${refreshKey}"`);
1945
- continue;
1946
- }
1947
- const sensitiveRefreshKey = configFieldContainsSensitiveValue(manifest.config?.fields?.[refreshKey]);
1948
- const skillTarget = artifactTarget === 'codex.skill'
1949
- || artifactTarget === 'claude.skill'
1950
- || artifactTarget === 'agent-skills.skill';
1951
- if (skillTarget && sensitiveRefreshKey) {
1952
- const native = delivery?.mode === 'codex-native';
1953
- error(`${native ? 'codexNativeRenderSensitiveRefreshKey' : 'skillRenderSensitiveRefreshKey'}: ` +
1954
- `${fieldName}.refreshKeys[${refreshIndex}]: ` +
1955
- `${native ? 'codex-native renderers' : 'Skill renderers'} cannot read sensitive config field "${refreshKey}"`);
1956
- }
1957
- }
1958
- if (target.requiresCodexProjectConfig !== undefined &&
1959
- typeof target.requiresCodexProjectConfig !== 'boolean') {
1960
- error(`${fieldName}.requiresCodexProjectConfig must be a boolean`);
1961
- }
1962
- if (artifactTarget === 'codex.skill' && target.requiresCodexProjectConfig === true) {
1963
- error(`${fieldName}.requiresCodexProjectConfig: codex.skill writes the skill runtime and must not require Codex project config preflight`);
1964
- }
1965
- if ((platform === 'claude' || portable) && target.requiresCodexProjectConfig !== undefined) {
1966
- error(`${fieldName}.requiresCodexProjectConfig: this target does not support the field`);
1967
- }
1968
- let roleKey;
1969
- let skillKey;
1970
- if (artifactTarget === 'codex.agentRole') {
1971
- roleKey = validateCodexRoleKey(target.roleKey, `${fieldName}.roleKey`);
1972
- if (!roleKey) {
1973
- error(`${fieldName}.roleKey: codex.agentRole targets must declare a static roleKey`);
1974
- }
1975
- }
1976
- else if (target.roleKey !== undefined) {
1977
- error(`${fieldName}.roleKey: roleKey is only supported for codex.agentRole targets`);
1978
- }
1979
- if (artifactTarget === 'codex.skill' || artifactTarget === 'claude.skill' || portable) {
1980
- skillKey = portable
1981
- ? validatePortableSkillKey(target.skillKey, `${fieldName}.skillKey`)
1982
- : validateCodexSkillKey(target.skillKey, `${fieldName}.skillKey`);
1983
- if (!skillKey) {
1984
- error(`${fieldName}.skillKey: ${artifactTarget} targets must declare a static skillKey`);
1985
- }
1986
- }
1987
- else if (target.skillKey !== undefined) {
1988
- error(`${fieldName}.skillKey: skillKey is only supported for skill targets`);
1989
- }
1990
- const normalizedSourceDirs = Array.isArray(target.sourceDirs)
1991
- ? target.sourceDirs
1992
- .filter((sourceDir) => typeof sourceDir === 'string' && sourceDir.trim() !== '')
1993
- .map((sourceDir) => path.posix.normalize(sourceDir))
1994
- : [];
1995
- if (new Set(normalizedSourceDirs).size !== normalizedSourceDirs.length) {
1996
- error(`${fieldName}.sourceDirs must not contain duplicate directories`);
1997
- }
1998
- const sourceDirs = target.sourceDirs === undefined
1999
- ? []
2000
- : validateStringArray(target.sourceDirs, `${fieldName}.sourceDirs`);
2001
- if (sourceDirs.length > 0 && artifactTarget !== 'codex.skill' && artifactTarget !== 'claude.skill' && !portable) {
2002
- error(`${fieldName}.sourceDirs: sourceDirs are only supported for skill targets`);
2003
- }
2004
- for (const [sourceIndex, sourceDir] of sourceDirs.entries()) {
2005
- const sourceField = `${fieldName}.sourceDirs[${sourceIndex}]`;
2006
- if (!sourceDir.startsWith('./') || path.posix.isAbsolute(sourceDir)) {
2007
- error(`${sourceField} must start with "./" and stay inside the plugin root`);
2008
- continue;
2009
- }
2010
- const normalized = path.posix.normalize(sourceDir);
2011
- if (normalized === '.' || normalized === '..' || normalized.startsWith('../')) {
2012
- error(`${sourceField} must stay inside the plugin root`);
2013
- continue;
2014
- }
2015
- const stats = fs.lstatSync(path.join(pluginDir, normalized), { throwIfNoEntry: false });
2016
- if (!stats?.isDirectory() || stats.isSymbolicLink()) {
2017
- error(`${sourceField} must point to an existing directory`);
2018
- }
2019
- if (skillKey && !portable &&
2020
- normalized !== `skills/${skillKey}` &&
2021
- !normalized.startsWith(`skills/${skillKey}/`)) {
2022
- error(`${sourceField} must stay inside "./skills/${skillKey}"`);
2023
- }
2024
- if (skillKey && !portable &&
2025
- isSkillAuthorOnlyPath(path.posix.relative(`skills/${skillKey}`, normalized))) {
2026
- error(`${sourceField} must not point inside an author-only Skill directory`);
2027
- }
2028
- }
2029
- if (skillKey && !portable &&
2030
- sourceDirs.length > 0 &&
2031
- !normalizedSourceDirs.includes(`skills/${skillKey}`)) {
2032
- error(`${fieldName}.sourceDirs must include "./skills/${skillKey}" so README.md is published`);
2033
- }
2034
- return {
2035
- id,
2036
- platform,
2037
- distribution,
2038
- scopes,
2039
- target: artifactTarget,
2040
- kind,
2041
- projectManagedKind,
2042
- states,
2043
- refreshKeys,
2044
- delivery,
2045
- roleKey,
2046
- skillKey,
2047
- sourceDirs,
2048
- runtimeConfig: target.runtimeConfig,
2049
- runtimeImports: Array.isArray(target.runtimeImports) ? target.runtimeImports : [],
2050
- };
2051
- }
2052
- function validateArtifactsConfigLightweight(pluginDir, manifest) {
2053
- if (manifest.artifacts === undefined)
2054
- return [];
2055
- const artifacts = expectRecord(manifest.artifacts, 'artifacts');
2056
- if (!artifacts)
2057
- return [];
2058
- validateAllowedKeys(artifacts, 'artifacts', ['targets']);
2059
- if (artifacts.targets === undefined)
2060
- return [];
2061
- if (!Array.isArray(artifacts.targets)) {
2062
- error('artifacts.targets must be an array');
2063
- return [];
2064
- }
2065
- const declarations = artifacts.targets
2066
- .map((entry, index) => validateArtifactTargetEntry(entry, index, manifest, pluginDir))
2067
- .filter(Boolean);
2068
- const idsBySurfaceScope = new Map();
2069
- const nativeIds = new Map();
2070
- const nativeSkillKeys = new Map();
2071
- for (const [declarationIndex, declaration] of declarations.entries()) {
2072
- for (const scope of declaration.scopes) {
2073
- const surface = declaration.platform ?? declaration.distribution;
2074
- const key = `${surface}:${scope}:${declaration.id}`;
2075
- const existing = idsBySurfaceScope.get(key);
2076
- if (existing !== undefined) {
2077
- error(`artifacts.targets has duplicate artifact id "${declaration.id}" for surface/scope "${surface}:${scope}" in targets[${existing}] and targets[${declarationIndex}]`);
2078
- }
2079
- else {
2080
- idsBySurfaceScope.set(key, declarationIndex);
2081
- }
2082
- }
2083
- if (declaration.delivery?.mode === 'codex-native') {
2084
- const existingId = nativeIds.get(declaration.id);
2085
- if (existingId !== undefined) {
2086
- error(`artifacts.targets has duplicate codex-native artifact id "${declaration.id}" in the shared projection at targets[${existingId}] and targets[${declarationIndex}]`);
2087
- }
2088
- else {
2089
- nativeIds.set(declaration.id, declarationIndex);
2090
- }
2091
- const existingSkillKey = nativeSkillKeys.get(declaration.skillKey);
2092
- if (existingSkillKey !== undefined) {
2093
- error(`artifacts.targets has duplicate codex-native skillKey "${declaration.skillKey}" in the shared projection at targets[${existingSkillKey}] and targets[${declarationIndex}]`);
2094
- }
2095
- else {
2096
- nativeSkillKeys.set(declaration.skillKey, declarationIndex);
2097
- }
2098
- }
2099
- }
2100
- const nativeComponents = codexStaticNativeComponentKeys(manifest).map((key) => ({
2101
- key,
2102
- scopes: ['project', 'user'],
2103
- }));
2104
- declarations.forEach((declaration, index) => {
2105
- if (declaration.delivery?.mode === 'codex-native') {
2106
- nativeComponents.push({ key: `artifacts.targets[${index}]`, scopes: declaration.scopes });
2107
- }
2108
- });
2109
- const expectedNativeComponent = nativeComponents[0];
2110
- if (expectedNativeComponent) {
2111
- const canonicalScopes = (component) => [...component.scopes].sort().join(',');
2112
- const expectedScopes = canonicalScopes(expectedNativeComponent);
2113
- const mismatch = nativeComponents.find((component) => canonicalScopes(component) !== expectedScopes);
2114
- if (mismatch) {
2115
- error(`codexSharedNativeScopeMismatch: Codex native component scope sets must match exactly; ` +
2116
- `${expectedNativeComponent.key} has {${expectedScopes}} but ${mismatch.key} has ` +
2117
- `{${canonicalScopes(mismatch)}}`);
2118
- }
2119
- }
2120
- const staticSkillNames = new Set(collectDeclaredSkillNames(pluginDir, manifest).static);
2121
- for (const [index, declaration] of declarations.entries()) {
2122
- if (declaration.target === 'codex.skill'
2123
- && declaration.delivery?.mode === 'codex-native'
2124
- && staticSkillNames.has(declaration.skillKey)) {
2125
- error(`artifacts.targets[${index}].skillKey: native dynamic Skill "${declaration.skillKey}" conflicts with a static Skill of the same name`);
2126
- }
2127
- }
2128
- const owners = new Map();
2129
- for (const declaration of declarations) {
2130
- if ((declaration.target !== 'codex.skill' && declaration.target !== 'claude.skill' && declaration.target !== 'agent-skills.skill') ||
2131
- !declaration.skillKey) {
2132
- continue;
2133
- }
2134
- for (const scope of declaration.scopes) {
2135
- const ownerKey = `${declaration.platform ?? declaration.distribution}:${scope}:${declaration.skillKey}`;
2136
- const existing = owners.get(ownerKey);
2137
- if (existing) {
2138
- error(`artifacts.targets has duplicate skill ownership "${ownerKey}" in artifacts "${existing}" and "${declaration.id}"`);
2139
- }
2140
- else {
2141
- owners.set(ownerKey, declaration.id);
2142
- }
2143
- }
2144
- }
2145
- return declarations;
1564
+ function validateArtifactsConfigLightweight(_pluginDir, manifest) {
1565
+ return (manifest.artifacts?.targets ?? []).map((target) => ({ ...target, sourceDirs: target.sourceDirs ?? [] }));
2146
1566
  }
2147
1567
  function validateArtifactPlanRefreshKeys(refreshKeys, declaration, fieldName) {
2148
1568
  const keys = validateStringArray(refreshKeys, `${fieldName}.refreshKeys`);
@@ -2168,7 +1588,7 @@ function isSkillAuthorOnlyPath(relativePath) {
2168
1588
  const [topLevel] = relativePath.split('/').filter(Boolean);
2169
1589
  return topLevel === 'evals' || topLevel === 'reports';
2170
1590
  }
2171
- function collectArtifactSourceFiles(rootDir, fieldName, files) {
1591
+ function collectArtifactSourceFiles(rootDir, fieldName, files, transform = (_relative, bytes) => bytes) {
2172
1592
  const rootStats = fs.lstatSync(rootDir, { throwIfNoEntry: false });
2173
1593
  if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
2174
1594
  return;
@@ -2192,7 +1612,7 @@ function collectArtifactSourceFiles(rootDir, fieldName, files) {
2192
1612
  error(`${fieldName} contains unsupported non-regular file "${relativePath}"`);
2193
1613
  continue;
2194
1614
  }
2195
- files.set(relativePath, fs.readFileSync(absolutePath));
1615
+ files.set(relativePath, transform(relativePath, fs.readFileSync(absolutePath)));
2196
1616
  }
2197
1617
  };
2198
1618
  visit(rootDir, '');
@@ -2206,25 +1626,21 @@ function findArtifactFilePrefixConflict(files) {
2206
1626
  }
2207
1627
  return null;
2208
1628
  }
2209
- function authorRuntimeImportKey(artifactId, importIndex) {
2210
- return `${artifactId}\0${importIndex}`;
1629
+ function authorRuntimeImportKey(artifactId, importIndex, platform) {
1630
+ return `${platform ?? "common"}\0${artifactId}\0${importIndex}`;
2211
1631
  }
2212
1632
  async function resolveAuthorRuntimeImports(options) {
2213
1633
  const artifactImports = (options.manifest.artifacts?.targets ?? []).flatMap((target) => (target.runtimeImports ?? []).map((reference, importIndex) => ({
2214
- key: authorRuntimeImportKey(target.id, importIndex),
1634
+ key: authorRuntimeImportKey(target.id, importIndex, target.platform),
2215
1635
  label: `artifacts target ${JSON.stringify(target.id)} runtime import ${JSON.stringify(reference.name)}`,
2216
1636
  purpose: 'artifact-runtime',
1637
+ platforms: target.platform ? [target.platform] : [undefined],
2217
1638
  reference,
2218
1639
  })));
2219
1640
  const skillRuntimeImports = (options.manifest.buildConfig?.skillRuntimeFiles ?? []).flatMap((entry, importIndex) => {
2220
1641
  if (!isRecord(entry.import))
2221
1642
  return [];
2222
- const platforms = [
2223
- ...(entry.platforms !== undefined || entry.distributions === undefined
2224
- ? (entry.platforms ?? [...resolveSupportedPlatforms(options.manifest)])
2225
- : []),
2226
- ...(entry.distributions?.includes('agent-skills') ? [undefined] : []),
2227
- ];
1643
+ const platforms = entry.platforms?.length ? entry.platforms : [...resolveSupportedPlatforms(options.manifest)];
2228
1644
  return platforms.length > 0 ? [{
2229
1645
  key: importIndex,
2230
1646
  label: `buildConfig.skillRuntimeFiles[${importIndex}].import`,
@@ -2312,10 +1728,10 @@ async function resolveAuthorRuntimeImports(options) {
2312
1728
  skillRuntimeImports: resolvedSkillRuntimeFiles,
2313
1729
  };
2314
1730
  }
2315
- function overlayPortableRuntimeFiles(files, manifest, pluginDir, skillKey, runtimeImports) {
1731
+ function overlayPortableRuntimeFiles(files, manifest, pluginDir, skillKey, runtimeImports, platform) {
2316
1732
  for (const [runtimeIndex, runtimeFile] of (manifest.buildConfig?.skillRuntimeFiles ?? []).entries()) {
2317
1733
  if (runtimeFile.skill !== skillKey
2318
- || !runtimeFile.distributions?.includes('agent-skills'))
1734
+ || (runtimeFile.platforms?.length && !runtimeFile.platforms.includes(platform)))
2319
1735
  continue;
2320
1736
  if (typeof runtimeFile.source === 'string') {
2321
1737
  const sourcePath = path.join(pluginDir, normalizeRelativePath(runtimeFile.source));
@@ -2344,10 +1760,12 @@ function validateRenderedSkillTree(options) {
2344
1760
  }
2345
1761
  const files = new Map();
2346
1762
  declaration.sourceDirs.forEach((sourceDir, index) => {
2347
- collectArtifactSourceFiles(path.join(pluginDir, normalizeRelativePath(sourceDir)), `artifacts.targets sourceDirs[${index}] for artifact "${declaration.id}"`, files);
1763
+ collectArtifactSourceFiles(path.join(pluginDir, normalizeRelativePath(sourceDir)), `artifacts.targets sourceDirs[${index}] for artifact "${declaration.id}"`, files, (relative, bytes) => isTemplateTextFile(relative)
1764
+ ? Buffer.from(renderTemplateForPlatform(manifest, `${normalizeRelativePath(sourceDir)}/${relative}`, bytes.toString('utf8'), declaration.platform))
1765
+ : bytes);
2348
1766
  });
2349
1767
  if (declaration.target === 'agent-skills.skill') {
2350
- overlayPortableRuntimeFiles(files, manifest, pluginDir, declaration.skillKey, options.runtimeImports);
1768
+ overlayPortableRuntimeFiles(files, manifest, pluginDir, declaration.skillKey, options.runtimeImports, declaration.platform);
2351
1769
  }
2352
1770
  for (const [relativePath, content] of Object.entries(entry.content.files)) {
2353
1771
  if (isSkillAuthorOnlyPath(relativePath)) {
@@ -2433,37 +1851,31 @@ function validateRenderedSkillTree(options) {
2433
1851
  options.managedTrees?.push({ declaration, files, scope: options.managedScope });
2434
1852
  }
2435
1853
  function validateStaticPortableFinalTrees(pluginDir, manifest, runtimeImports, skillValidationTools) {
2436
- const portableRoot = manifest.distributions?.agentSkills?.skills;
2437
- if (typeof portableRoot !== 'string')
1854
+ if (!manifest.skills)
2438
1855
  return;
2439
- const rootDir = path.join(pluginDir, normalizeRelativePath(portableRoot));
1856
+ const rootDir = path.join(pluginDir, normalizeRelativePath(manifest.skills));
2440
1857
  const rootStats = fs.lstatSync(rootDir, { throwIfNoEntry: false });
2441
1858
  if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
2442
1859
  return;
2443
- const dynamicKeys = new Set((manifest.artifacts?.targets ?? [])
2444
- .filter((target) => target.target === 'agent-skills.skill' && typeof target.skillKey === 'string')
2445
- .map((target) => target.skillKey));
2446
1860
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'aw-static-portable-final-'));
2447
1861
  try {
2448
- for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
2449
- if (!entry.isDirectory() || dynamicKeys.has(entry.name))
1862
+ for (const platform of resolveSupportedPlatforms(manifest)) {
1863
+ if (!isPortablePlatformTarget(platform))
2450
1864
  continue;
2451
- validateRenderedSkillTree({
2452
- entry: { state: 'present', content: { files: {} } },
2453
- declaration: {
2454
- id: `static:${entry.name}`,
2455
- distribution: 'agent-skills',
2456
- target: 'agent-skills.skill',
2457
- skillKey: entry.name,
2458
- sourceDirs: [`${portableRoot}/${entry.name}`],
2459
- },
2460
- fieldName: `static portable Skill "${entry.name}"`,
2461
- pluginDir,
2462
- manifest,
2463
- runtimeImports,
2464
- materializedRoot: path.join(tempRoot, entry.name),
2465
- skillValidationTools,
2466
- });
1865
+ const dynamicKeys = new Set((manifest.artifacts?.targets ?? [])
1866
+ .filter((target) => target.platform === platform && target.target === 'agent-skills.skill')
1867
+ .map((target) => target.skillKey));
1868
+ for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
1869
+ if (!entry.isDirectory() || dynamicKeys.has(entry.name))
1870
+ continue;
1871
+ validateRenderedSkillTree({
1872
+ entry: { state: 'present', content: { files: {} } },
1873
+ declaration: { id: `static:${entry.name}`, platform, distribution: 'agent-skills',
1874
+ target: 'agent-skills.skill', skillKey: entry.name, sourceDirs: [`${manifest.skills}/${entry.name}`] },
1875
+ fieldName: `static Portable Skill "${entry.name}" (${platform})`, pluginDir, manifest, runtimeImports,
1876
+ materializedRoot: path.join(tempRoot, platform, entry.name), skillValidationTools,
1877
+ });
1878
+ }
2467
1879
  }
2468
1880
  }
2469
1881
  finally {
@@ -2525,11 +1937,8 @@ function validateRenderedArtifactPlan(plan, declarations, scopeLabel, options) {
2525
1937
  if (entry.distribution !== declaration.distribution) {
2526
1938
  error(`${fieldName}.distribution: expected "${declaration.distribution}"`);
2527
1939
  }
2528
- if (entry.platform !== undefined) {
2529
- error(`${fieldName}.platform: distribution artifacts do not support platform`);
2530
- }
2531
1940
  }
2532
- else if (entry.platform !== declaration.platform) {
1941
+ if (entry.platform !== declaration.platform) {
2533
1942
  error(`${fieldName}.platform: expected "${declaration.platform}"`);
2534
1943
  }
2535
1944
  if (entry.kind !== declaration.kind) {
@@ -2619,68 +2028,53 @@ function validateRenderedArtifactPlan(plan, declarations, scopeLabel, options) {
2619
2028
  }
2620
2029
  }
2621
2030
  function resolveArtifactRendererFixtureRequests(declarations, manifest, requiresNonSensitiveArtifactInput) {
2622
- const awOwned = new Map();
2623
- const codexNative = new Map();
2031
+ const requests = new Map();
2624
2032
  for (const declaration of declarations) {
2625
- if (declaration.delivery?.mode === 'codex-native') {
2626
- const scope = declaration.scopes.includes('user') ? 'user' : 'project';
2627
- const request = codexNative.get(scope) ?? {
2628
- kind: 'codex-native',
2629
- surface: 'codex',
2630
- scope,
2631
- configScope: 'user',
2632
- declarations: [],
2633
- };
2634
- request.declarations.push(declaration);
2635
- codexNative.set(scope, request);
2636
- continue;
2637
- }
2638
- const surface = declaration.surface?.kind === 'aw'
2639
- ? declaration.surface.name
2640
- : declaration.platform ?? declaration.distribution;
2033
+ const nativeSkill = declaration.target === 'codex.skill' || declaration.target === 'claude.skill';
2034
+ const surface = declaration.surface?.kind === 'aw' ? declaration.surface.name : declaration.platform;
2641
2035
  if (!surface)
2642
2036
  continue;
2643
- for (const scope of declaration.scopes) {
2644
- const key = `${surface}:${scope}`;
2645
- const request = awOwned.get(key) ?? {
2646
- kind: 'aw-owned',
2647
- surface,
2648
- scope,
2649
- configScope: scope,
2650
- declarations: [],
2651
- };
2037
+ for (const scope of nativeSkill ? ['user'] : declaration.scopes) {
2038
+ const key = `${nativeSkill ? 'native' : 'ordinary'}:${surface}:${scope}`;
2039
+ const request = requests.get(key) ?? { kind: nativeSkill ? 'native' : 'ordinary', surface, scope,
2040
+ configScope: nativeSkill ? 'user' : scope, declarations: [] };
2652
2041
  request.declarations.push(declaration);
2653
- awOwned.set(key, request);
2042
+ requests.set(key, request);
2654
2043
  }
2655
2044
  }
2656
- const partitionedAwOwned = [...awOwned.values()].flatMap((request) => {
2045
+ return [...requests.values()].flatMap((request) => {
2046
+ const definition = compilePluginConfigDefinition(manifest.config ?? { fields: {} }, MANIFEST_PLATFORMS.has(request.surface) ? request.surface : undefined);
2657
2047
  const hasNonSensitiveTarget = request.declarations.some(requiresNonSensitiveArtifactInput);
2658
2048
  const hasSensitiveOtherTarget = request.declarations.some((declaration) => !requiresNonSensitiveArtifactInput(declaration)
2659
- && declaration.refreshKeys.some((key) => configFieldContainsSensitiveValue(manifest.config?.fields?.[key])));
2049
+ && declaration.refreshKeys.some((key) => configFieldContainsSensitiveValue(definition.fields[key])));
2660
2050
  if (!hasNonSensitiveTarget || !hasSensitiveOtherTarget)
2661
2051
  return [request];
2662
- const nonSensitiveDeclarations = request.declarations.filter(requiresNonSensitiveArtifactInput);
2663
- const otherDeclarations = request.declarations.filter((declaration) => !requiresNonSensitiveArtifactInput(declaration));
2664
2052
  return [
2665
- { ...request, declarations: nonSensitiveDeclarations },
2666
- { ...request, declarations: otherDeclarations },
2053
+ { ...request, declarations: request.declarations.filter(requiresNonSensitiveArtifactInput) },
2054
+ { ...request, declarations: request.declarations.filter((declaration) => !requiresNonSensitiveArtifactInput(declaration)) },
2667
2055
  ];
2668
2056
  });
2669
- return [...partitionedAwOwned, ...codexNative.values()];
2670
2057
  }
2671
2058
  async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declarations, resolvedRuntimeImports, skillValidationTools, managedContext, requiresNonSensitiveArtifactInput, referenceContext) {
2672
2059
  if (!renderEntry || declarations.length === 0)
2673
2060
  return [];
2674
2061
  const requests = resolveArtifactRendererFixtureRequests(declarations, manifest, requiresNonSensitiveArtifactInput);
2675
- const values = defaultConfigValues(manifest);
2676
2062
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'aw-artifact-render-'));
2677
2063
  const returnedArtifacts = [];
2678
2064
  try {
2679
2065
  for (const [requestIndex, request] of requests.entries()) {
2680
2066
  const { kind, surface, scope, configScope, declarations: scopedDeclarations, } = request;
2681
- const distribution = surface === 'agent-skills' ? surface : undefined;
2067
+ const distribution = isPortablePlatformTarget(surface) ? 'agent-skills' : undefined;
2682
2068
  const awSurface = surface === 'managed-commands';
2683
- const platform = distribution || awSurface ? undefined : surface;
2069
+ const platform = awSurface ? undefined : surface;
2070
+ const definition = compilePluginConfigDefinition(manifest.config ?? { fields: {} }, platform);
2071
+ const values = defaultConfigValues(manifest, platform);
2072
+ const platformReferences = referenceContext ? { ...referenceContext, platform,
2073
+ plugins: Object.fromEntries(Object.entries(referenceContext.plugins).map(([name, entry]) => {
2074
+ const compiled = compilePluginConfigDefinition(entry.definition, platform);
2075
+ return [name, { ...entry, definition: compiled, values: defaultConfigValues({ config: compiled }) }];
2076
+ })),
2077
+ } : undefined;
2684
2078
  const event = distribution ? 'materialize' : 'install';
2685
2079
  const requestRoot = path.join(tempRoot, `${requestIndex}-${kind}-${surface}-${scope}`);
2686
2080
  const rendererAwHome = path.join(requestRoot, 'aw-home');
@@ -2689,7 +2083,7 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2689
2083
  fs.mkdirSync(requestRoot, { recursive: true });
2690
2084
  const contextPath = path.join(requestRoot, 'context.json');
2691
2085
  const runtimeImports = scopedDeclarations.flatMap((target) => (target.runtimeImports ?? []).map((runtimeImport, importIndex) => {
2692
- const resolved = resolvedRuntimeImports?.artifactImports.get(authorRuntimeImportKey(target.id, importIndex));
2086
+ const resolved = resolvedRuntimeImports?.artifactImports.get(authorRuntimeImportKey(target.id, importIndex, target.platform));
2693
2087
  if (!resolved)
2694
2088
  return null;
2695
2089
  const importPath = path.join(requestRoot, `runtime-${target.id}-${importIndex}`);
@@ -2704,18 +2098,15 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2704
2098
  };
2705
2099
  }).filter(Boolean));
2706
2100
  const refreshKeys = [...new Set(scopedDeclarations.flatMap((target) => target.refreshKeys))];
2707
- const scopedSchema = Object.fromEntries(refreshKeys.flatMap((key) => manifest.config?.fields?.[key] === undefined
2708
- ? []
2709
- : [[key, manifest.config.fields[key]]]));
2101
+ const scopedSchema = Object.fromEntries(refreshKeys.flatMap((key) => definition.fields[key] === undefined ? [] : [[key, definition.fields[key]]]));
2710
2102
  const scopedValues = Object.fromEntries(refreshKeys.flatMap((key) => Object.prototype.hasOwnProperty.call(values, key) ? [[key, values[key]]] : []));
2711
2103
  try {
2712
2104
  if (manifest.config) {
2713
- const issues = validatePluginConfigCandidate(manifest.config, values, refreshKeys, referenceContext);
2105
+ const issues = validatePluginConfigCandidate(definition, values, refreshKeys, platformReferences);
2714
2106
  if (issues.length > 0)
2715
2107
  throw new Error(formatPluginConfigIssue(issues[0]));
2716
2108
  }
2717
2109
  for (const target of scopedDeclarations.filter((declaration) => declaration.runtimeConfig)) {
2718
- const definition = manifest.config;
2719
2110
  createRuntimeConfigSnapshot({
2720
2111
  installedIdentity: {
2721
2112
  sourceId: 'authoring',
@@ -2724,7 +2115,7 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2724
2115
  pluginName: manifest.name,
2725
2116
  pluginVersion: manifest.version,
2726
2117
  platform: target.platform,
2727
- scope: target.delivery?.mode === 'codex-native' ? 'user' : scope,
2118
+ scope: target.target === 'codex.skill' || target.target === 'claude.skill' ? 'user' : scope,
2728
2119
  configScope,
2729
2120
  artifactId: target.id,
2730
2121
  skillKey: target.skillKey,
@@ -2732,7 +2123,7 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2732
2123
  declaration: target.runtimeConfig,
2733
2124
  definition,
2734
2125
  values,
2735
- referenceContext,
2126
+ referenceContext: platformReferences,
2736
2127
  });
2737
2128
  }
2738
2129
  }
@@ -2765,11 +2156,11 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2765
2156
  requestedArtifactIds: scopedDeclarations.map((target) => target.id),
2766
2157
  previousArtifacts: [],
2767
2158
  artifactSources: declarations.filter((target) => (target.target === 'codex.skill' || target.target === 'claude.skill' || target.target === 'agent-skills.skill')
2768
- && (distribution ? target.distribution === distribution : target.platform === platform)
2159
+ && target.platform === platform
2769
2160
  && target.scopes.includes(scope)).map((target) => ({
2770
2161
  id: target.id,
2771
2162
  target: target.target,
2772
- sourceDirs: target.sourceDirs.map((sourceDir) => path.join(pluginDir, normalizeRelativePath(sourceDir))),
2163
+ sourceDirs: (target.sourceDirs ?? []).map((sourceDir) => path.join(pluginDir, normalizeRelativePath(sourceDir))),
2773
2164
  })),
2774
2165
  commandSources: (managedContext?.manifest.managedCommands?.packages ?? [])
2775
2166
  .filter((entry) => scopedDeclarations.some((target) => target.packageKey === entry.key))
@@ -2798,8 +2189,15 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2798
2189
  fs.mkdirSync(rendererTemp, { recursive: true });
2799
2190
  const rendererEnv = {
2800
2191
  AW_HOME: rendererAwHome,
2801
- AW_CODEX_HOME: rendererCodexHome,
2802
- AW_CLAUDE_HOME: rendererClaudeHome,
2192
+ CODEX_HOME: rendererCodexHome,
2193
+ CLAUDE_CONFIG_DIR: rendererClaudeHome,
2194
+ HOME: rendererHome,
2195
+ USERPROFILE: rendererHome,
2196
+ XDG_CONFIG_HOME: path.join(requestRoot, 'xdg-config'),
2197
+ XDG_CACHE_HOME: path.join(requestRoot, 'xdg-cache'),
2198
+ XDG_STATE_HOME: path.join(requestRoot, 'xdg-state'),
2199
+ XDG_DATA_HOME: path.join(requestRoot, 'xdg-data'),
2200
+ XDG_RUNTIME_DIR: path.join(requestRoot, 'xdg-runtime'),
2803
2201
  PATH: process.env.PATH ?? process.env.Path ?? '',
2804
2202
  AW_PLUGIN_CONTEXT: contextPath,
2805
2203
  AW_PLUGIN_ROOT: pluginDir,
@@ -2812,7 +2210,6 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2812
2210
  AW_PLUGIN_SCOPE: scope,
2813
2211
  };
2814
2212
  if (process.platform === 'win32') {
2815
- rendererEnv.USERPROFILE = rendererHome;
2816
2213
  rendererEnv.TEMP = rendererTemp;
2817
2214
  rendererEnv.TMP = rendererTemp;
2818
2215
  if (process.env.SystemRoot)
@@ -2821,7 +2218,6 @@ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, decl
2821
2218
  rendererEnv.ComSpec = process.env.ComSpec;
2822
2219
  }
2823
2220
  else {
2824
- rendererEnv.HOME = rendererHome;
2825
2221
  rendererEnv.TMPDIR = rendererTemp;
2826
2222
  }
2827
2223
  const result = spawnSync(process.execPath, [path.join(pluginDir, renderEntry.path), ...(renderEntry.args ?? [])], {
@@ -2957,8 +2353,8 @@ async function validateAuthorManagedCommands(pluginDir, manifest, rendered, cont
2957
2353
  }
2958
2354
  for (const [index, tree] of trees.entries()) {
2959
2355
  const { declaration } = tree;
2960
- const scope = declaration.delivery?.mode === 'codex-native' ? 'user' : tree.scope;
2961
- if (!declaration.platform)
2356
+ const scope = declaration.target === 'codex.skill' || declaration.target === 'claude.skill' ? 'user' : tree.scope;
2357
+ if (declaration.platform !== 'codex' && declaration.platform !== 'claude')
2962
2358
  continue;
2963
2359
  const producer = declaration.staticSkill
2964
2360
  ? { kind: 'static-skill', platform: declaration.platform, skillKey: declaration.skillKey }
@@ -2975,9 +2371,9 @@ async function validateAuthorManagedCommands(pluginDir, manifest, rendered, cont
2975
2371
  candidates.push({ producer: await tools.managedCommandProducerIdentity({ plugin, producer, scope, cwd: pluginDir }), sets });
2976
2372
  }
2977
2373
  for (const tree of trees) {
2978
- if (!tree.declaration.platform)
2374
+ if (tree.declaration.platform !== 'codex' && tree.declaration.platform !== 'claude')
2979
2375
  continue;
2980
- const scope = tree.declaration.delivery?.mode === 'codex-native' ? 'user' : tree.scope;
2376
+ const scope = tree.declaration.target === 'codex.skill' || tree.declaration.target === 'claude.skill' ? 'user' : tree.scope;
2981
2377
  const resolve = await tools.createManagedCommandReferenceResolver({ plugin, platform: tree.declaration.platform, scope, cwd: pluginDir, env, candidates });
2982
2378
  for (const [relative, bytes] of tree.files) {
2983
2379
  if (!relative.endsWith('.md'))
@@ -3271,8 +2667,6 @@ function validateSkills(pluginDir, manifest, options, skillValidationTools) {
3271
2667
  const skillsDir = path.join(pluginDir, manifest.skills);
3272
2668
  if (!fs.existsSync(skillsDir))
3273
2669
  return;
3274
- const requiresCodexMetadata = isCodexTargeted(manifest);
3275
- const targetsClaude = isClaudeTargeted(manifest);
3276
2670
  const skillDirs = fs
3277
2671
  .readdirSync(skillsDir, { withFileTypes: true })
3278
2672
  .filter((d) => d.isDirectory());
@@ -3280,6 +2674,11 @@ function validateSkills(pluginDir, manifest, options, skillValidationTools) {
3280
2674
  error('skills directory exists but contains no skill subdirectories');
3281
2675
  }
3282
2676
  for (const dir of skillDirs) {
2677
+ const staticPlatforms = [...resolveSupportedPlatforms(manifest)].filter((platform) => !(manifest.artifacts?.targets ?? []).some((target) => target.platform === platform && target.skillKey === dir.name));
2678
+ if (staticPlatforms.length === 0)
2679
+ continue;
2680
+ const requiresCodexMetadata = staticPlatforms.includes('codex');
2681
+ const targetsClaude = staticPlatforms.includes('claude');
3283
2682
  const skillPath = path.join(skillsDir, dir.name);
3284
2683
  const skillMdPath = path.join(skillPath, 'SKILL.md');
3285
2684
  const openaiYamlPath = path.join(skillPath, 'agents', 'openai.yaml');
@@ -3293,7 +2692,7 @@ function validateSkills(pluginDir, manifest, options, skillValidationTools) {
3293
2692
  if (lineCount >= MAX_SKILL_LINES) {
3294
2693
  warn(`skills/${dir.name}/SKILL.md has ${lineCount} lines; Agent Skills recommends keeping SKILL.md under ${MAX_SKILL_LINES} lines`);
3295
2694
  }
3296
- const variants = renderedContentVariants(manifest, skillMdRelativePath, content, targetedPlatforms(manifest));
2695
+ const variants = renderedContentVariants(manifest, skillMdRelativePath, content, staticPlatforms);
3297
2696
  for (const variant of variants) {
3298
2697
  const sourceName = variant.platform
3299
2698
  ? `skills/${dir.name}/SKILL.md (${variant.platform} render)`
@@ -3307,7 +2706,7 @@ function validateSkills(pluginDir, manifest, options, skillValidationTools) {
3307
2706
  error(`${entry.path} [${entry.code}] ${entry.message}`);
3308
2707
  }
3309
2708
  if (parsed.frontmatter) {
3310
- const profile = options.strictAgentSkills || !targetsClaude
2709
+ const profile = options.strictAgentSkills || !targetsClaude || isPortablePlatformTarget(variant.platform)
3311
2710
  ? 'portable-agent-skills'
3312
2711
  : options.claudeSkillProfile === 'current'
3313
2712
  ? 'claude-current'
@@ -3616,9 +3015,7 @@ async function validatePluginDir(pluginDir, options) {
3616
3015
  let referenceContext;
3617
3016
  try {
3618
3017
  normalizedManifest = await cliManifestTools.validateSourcePluginManifest(pluginDir, manifest);
3619
- // Renderer fixtures consume the same compiled config as installed runtime consumers.
3620
- if (normalizedManifest.config)
3621
- manifest.config = normalizedManifest.config;
3018
+ manifest = normalizedManifest;
3622
3019
  // The Workspace is the sole source of dependency definitions and defaults.
3623
3020
  // No installed plugin or user config can complete an author fixture.
3624
3021
  if (manifest.config) {
@@ -3669,9 +3066,9 @@ async function validatePluginDir(pluginDir, options) {
3669
3066
  }
3670
3067
  catch (e) {
3671
3068
  error(e.message);
3069
+ return;
3672
3070
  }
3673
3071
  validatePlatformFieldSupport(manifest);
3674
- validatePortableNativeArtifactCapabilityLightweight(manifest);
3675
3072
  validateNameMatchesDirectory(pluginDir, manifest);
3676
3073
  validateNoBuildOutputDirs(pluginDir);
3677
3074
  validateDeclaredNativeAssets(pluginDir, manifest);