@lesliechan721/aw 0.1.0-beta.7 → 0.1.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/dist/authoring/scripts/add-skill.mjs +4 -4
  2. package/dist/authoring/scripts/add-skill.mjs.map +1 -1
  3. package/dist/authoring/scripts/init-plugin.mjs +8 -37
  4. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  5. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  6. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +77 -90
  7. package/dist/authoring/scripts/lib/skill-scaffold.mjs +99 -120
  8. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
  9. package/dist/authoring/scripts/plugin-status.mjs +8 -11
  10. package/dist/authoring/scripts/plugin-status.mjs.map +1 -1
  11. package/dist/authoring/scripts/remove-plugin.mjs +2 -1
  12. package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
  13. package/dist/authoring/scripts/validate-plugin.mjs +64 -758
  14. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  15. package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
  16. package/dist/scripts/{plugin-eval-materializer.js → aw-skill-eval-materializer.js} +34 -145
  17. package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
  18. package/dist/scripts/bundle-plugins.d.ts +1 -0
  19. package/dist/scripts/bundle-plugins.js +2 -1
  20. package/dist/scripts/bundle-plugins.js.map +1 -1
  21. package/dist/scripts/plugin-staging.d.ts +6 -8
  22. package/dist/scripts/plugin-staging.js +15 -28
  23. package/dist/scripts/plugin-staging.js.map +1 -1
  24. package/dist/scripts/test-plugin-scripts.js +2 -33
  25. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  26. package/dist/src/adapters/helpers.js +2 -2
  27. package/dist/src/adapters/helpers.js.map +1 -1
  28. package/dist/src/authoring/workspace-commands.d.ts +17 -1
  29. package/dist/src/authoring/workspace-commands.js +21 -4
  30. package/dist/src/authoring/workspace-commands.js.map +1 -1
  31. package/dist/src/commands/aw-capabilities.d.ts +78 -0
  32. package/dist/src/commands/aw-capabilities.js +254 -0
  33. package/dist/src/commands/aw-capabilities.js.map +1 -0
  34. package/dist/src/commands/catalog-dev-source.d.ts +118 -0
  35. package/dist/src/commands/catalog-dev-source.js +417 -0
  36. package/dist/src/commands/catalog-dev-source.js.map +1 -0
  37. package/dist/src/commands/catalog-generation.d.ts +13 -0
  38. package/dist/src/commands/catalog-generation.js +13 -0
  39. package/dist/src/commands/catalog-generation.js.map +1 -0
  40. package/dist/src/commands/catalog-publication-inspection.d.ts +29 -28
  41. package/dist/src/commands/catalog-publication-inspection.js +138 -50
  42. package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
  43. package/dist/src/commands/catalog-publication-journal.d.ts +49 -0
  44. package/dist/src/commands/catalog-publication-journal.js +147 -0
  45. package/dist/src/commands/catalog-publication-journal.js.map +1 -0
  46. package/dist/src/commands/catalog-publication-target.d.ts +18 -0
  47. package/dist/src/commands/catalog-publication-target.js +95 -0
  48. package/dist/src/commands/catalog-publication-target.js.map +1 -0
  49. package/dist/src/commands/catalog-publish.d.ts +58 -15
  50. package/dist/src/commands/catalog-publish.js +590 -210
  51. package/dist/src/commands/catalog-publish.js.map +1 -1
  52. package/dist/src/commands/catalog-source.d.ts +12 -15
  53. package/dist/src/commands/catalog-source.js +61 -86
  54. package/dist/src/commands/catalog-source.js.map +1 -1
  55. package/dist/src/commands/catalog-status.d.ts +18 -22
  56. package/dist/src/commands/catalog-status.js +81 -115
  57. package/dist/src/commands/catalog-status.js.map +1 -1
  58. package/dist/src/commands/catalog-workspace-resolution.d.ts +13 -0
  59. package/dist/src/commands/catalog-workspace-resolution.js +42 -0
  60. package/dist/src/commands/catalog-workspace-resolution.js.map +1 -0
  61. package/dist/src/commands/dependency-operation-plan.d.ts +88 -9
  62. package/dist/src/commands/dependency-operation-plan.js +331 -6
  63. package/dist/src/commands/dependency-operation-plan.js.map +1 -1
  64. package/dist/src/commands/init.d.ts +5 -11
  65. package/dist/src/commands/init.js +30 -51
  66. package/dist/src/commands/init.js.map +1 -1
  67. package/dist/src/commands/offline-cleanup-evidence.d.ts +43 -0
  68. package/dist/src/commands/offline-cleanup-evidence.js +116 -0
  69. package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
  70. package/dist/src/commands/options.d.ts +7 -1
  71. package/dist/src/commands/options.js +65 -6
  72. package/dist/src/commands/options.js.map +1 -1
  73. package/dist/src/commands/plugin-capabilities.js +5 -1
  74. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  75. package/dist/src/commands/rebuild-command.d.ts +27 -13
  76. package/dist/src/commands/rebuild-command.js +1472 -471
  77. package/dist/src/commands/rebuild-command.js.map +1 -1
  78. package/dist/src/commands/rebuild-integration.d.ts +63 -8
  79. package/dist/src/commands/rebuild-integration.js +761 -439
  80. package/dist/src/commands/rebuild-integration.js.map +1 -1
  81. package/dist/src/commands/rebuild-operations.d.ts +2 -8
  82. package/dist/src/commands/rebuild-operations.js +48 -132
  83. package/dist/src/commands/rebuild-operations.js.map +1 -1
  84. package/dist/src/commands/runtime.js +21 -34
  85. package/dist/src/commands/runtime.js.map +1 -1
  86. package/dist/src/commands/skill-eval.d.ts +33 -0
  87. package/dist/src/commands/skill-eval.js +363 -0
  88. package/dist/src/commands/skill-eval.js.map +1 -0
  89. package/dist/src/commands/status-v6.d.ts +202 -0
  90. package/dist/src/commands/status-v6.js +1938 -0
  91. package/dist/src/commands/status-v6.js.map +1 -0
  92. package/dist/src/commands/sync-command.d.ts +21 -0
  93. package/dist/src/commands/sync-command.js +206 -0
  94. package/dist/src/commands/sync-command.js.map +1 -0
  95. package/dist/src/commands/wizard.d.ts +2 -2
  96. package/dist/src/commands/wizard.js +2 -2
  97. package/dist/src/commands/wizard.js.map +1 -1
  98. package/dist/src/commands/write-commands.js +33 -19
  99. package/dist/src/commands/write-commands.js.map +1 -1
  100. package/dist/src/constants.d.ts +7 -1
  101. package/dist/src/constants.js +7 -1
  102. package/dist/src/constants.js.map +1 -1
  103. package/dist/src/eval/manifest-v1.d.ts +66 -0
  104. package/dist/src/eval/manifest-v1.js +326 -0
  105. package/dist/src/eval/manifest-v1.js.map +1 -0
  106. package/dist/src/generators/local-plugin.d.ts +3 -0
  107. package/dist/src/generators/local-plugin.js +167 -45
  108. package/dist/src/generators/local-plugin.js.map +1 -1
  109. package/dist/src/index.d.ts +6 -1
  110. package/dist/src/index.js +863 -126
  111. package/dist/src/index.js.map +1 -1
  112. package/dist/src/output/command-receipt.d.ts +58 -8
  113. package/dist/src/output/command-receipt.js +141 -11
  114. package/dist/src/output/command-receipt.js.map +1 -1
  115. package/dist/src/output/model.d.ts +3 -44
  116. package/dist/src/output/model.js +1 -144
  117. package/dist/src/output/model.js.map +1 -1
  118. package/dist/src/output/rebuild-progress.js +0 -3
  119. package/dist/src/output/rebuild-progress.js.map +1 -1
  120. package/dist/src/portable/commands.d.ts +6 -2
  121. package/dist/src/portable/commands.js +57 -6
  122. package/dist/src/portable/commands.js.map +1 -1
  123. package/dist/src/portable/materializer.d.ts +4 -4
  124. package/dist/src/portable/materializer.js +61 -12
  125. package/dist/src/portable/materializer.js.map +1 -1
  126. package/dist/src/tui/catalog-generation.d.ts +35 -0
  127. package/dist/src/tui/catalog-generation.js +85 -0
  128. package/dist/src/tui/catalog-generation.js.map +1 -0
  129. package/dist/src/tui/components.js +1 -2
  130. package/dist/src/tui/components.js.map +1 -1
  131. package/dist/src/tui/console-app-v4.d.ts +1 -1
  132. package/dist/src/tui/console-app-v4.js +647 -196
  133. package/dist/src/tui/console-app-v4.js.map +1 -1
  134. package/dist/src/tui/controller-runtime.d.ts +6 -2
  135. package/dist/src/tui/controller-runtime.js +646 -137
  136. package/dist/src/tui/controller-runtime.js.map +1 -1
  137. package/dist/src/tui/controller.d.ts +77 -15
  138. package/dist/src/tui/controller.js +647 -306
  139. package/dist/src/tui/controller.js.map +1 -1
  140. package/dist/src/tui/diagnostics.d.ts +1 -2
  141. package/dist/src/tui/diagnostics.js.map +1 -1
  142. package/dist/src/tui/index.d.ts +1 -0
  143. package/dist/src/tui/index.js +1 -0
  144. package/dist/src/tui/index.js.map +1 -1
  145. package/dist/src/tui/input-display.d.ts +8 -0
  146. package/dist/src/tui/input-display.js +36 -0
  147. package/dist/src/tui/input-display.js.map +1 -0
  148. package/dist/src/tui/model.d.ts +102 -14
  149. package/dist/src/tui/model.js +630 -139
  150. package/dist/src/tui/model.js.map +1 -1
  151. package/dist/src/tui/router.d.ts +35 -0
  152. package/dist/src/tui/router.js.map +1 -1
  153. package/dist/src/tui/source-ref-presets.d.ts +3 -0
  154. package/dist/src/tui/source-ref-presets.js +11 -0
  155. package/dist/src/tui/source-ref-presets.js.map +1 -0
  156. package/dist/src/tui/views.js +31 -3
  157. package/dist/src/tui/views.js.map +1 -1
  158. package/dist/src/types.d.ts +104 -13
  159. package/dist/src/types.js.map +1 -1
  160. package/dist/src/utils/agent-version.d.ts +7 -1
  161. package/dist/src/utils/agent-version.js +41 -8
  162. package/dist/src/utils/agent-version.js.map +1 -1
  163. package/dist/src/utils/aw-home-mutation-lock.d.ts +1 -0
  164. package/dist/src/utils/aw-home-mutation-lock.js +32 -4
  165. package/dist/src/utils/aw-home-mutation-lock.js.map +1 -1
  166. package/dist/src/utils/bundle-integrity.d.ts +0 -1
  167. package/dist/src/utils/bundle-integrity.js +0 -25
  168. package/dist/src/utils/bundle-integrity.js.map +1 -1
  169. package/dist/src/utils/bundle-layout.js +8 -6
  170. package/dist/src/utils/bundle-layout.js.map +1 -1
  171. package/dist/src/utils/catalog-digests.d.ts +7 -0
  172. package/dist/src/utils/catalog-digests.js +40 -2
  173. package/dist/src/utils/catalog-digests.js.map +1 -1
  174. package/dist/src/utils/catalog-generation-control-snapshot.d.ts +11 -0
  175. package/dist/src/utils/catalog-generation-control-snapshot.js +45 -0
  176. package/dist/src/utils/catalog-generation-control-snapshot.js.map +1 -0
  177. package/dist/src/utils/catalog-generation-error.d.ts +13 -0
  178. package/dist/src/utils/catalog-generation-error.js +28 -0
  179. package/dist/src/utils/catalog-generation-error.js.map +1 -0
  180. package/dist/src/utils/catalog-generation-resolver.d.ts +20 -0
  181. package/dist/src/utils/catalog-generation-resolver.js +143 -0
  182. package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
  183. package/dist/src/utils/catalog-generation-service.d.ts +43 -0
  184. package/dist/src/utils/catalog-generation-service.js +306 -0
  185. package/dist/src/utils/catalog-generation-service.js.map +1 -0
  186. package/dist/src/utils/catalog-generation-state.d.ts +17 -0
  187. package/dist/src/utils/catalog-generation-state.js +168 -0
  188. package/dist/src/utils/catalog-generation-state.js.map +1 -0
  189. package/dist/src/utils/catalog-generation-store.d.ts +34 -0
  190. package/dist/src/utils/catalog-generation-store.js +251 -0
  191. package/dist/src/utils/catalog-generation-store.js.map +1 -0
  192. package/dist/src/utils/catalog-manifest-v6.d.ts +5 -0
  193. package/dist/src/utils/{catalog-manifest-v4.js → catalog-manifest-v6.js} +35 -43
  194. package/dist/src/utils/catalog-manifest-v6.js.map +1 -0
  195. package/dist/src/utils/catalog-operation-context.d.ts +20 -0
  196. package/dist/src/utils/catalog-operation-context.js +141 -0
  197. package/dist/src/utils/catalog-operation-context.js.map +1 -0
  198. package/dist/src/utils/catalog-public-error.d.ts +7 -3
  199. package/dist/src/utils/catalog-public-error.js +21 -8
  200. package/dist/src/utils/catalog-public-error.js.map +1 -1
  201. package/dist/src/utils/catalog-runtime-projection.d.ts +3 -0
  202. package/dist/src/utils/catalog-runtime-projection.js +5 -40
  203. package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
  204. package/dist/src/utils/catalog-snapshot.d.ts +5 -3
  205. package/dist/src/utils/catalog-snapshot.js +11 -3
  206. package/dist/src/utils/catalog-snapshot.js.map +1 -1
  207. package/dist/src/utils/catalog-source-identity.d.ts +1 -0
  208. package/dist/src/utils/catalog-source-identity.js +21 -2
  209. package/dist/src/utils/catalog-source-identity.js.map +1 -1
  210. package/dist/src/utils/catalog-source-references.d.ts +7 -0
  211. package/dist/src/utils/catalog-source-references.js +44 -55
  212. package/dist/src/utils/catalog-source-references.js.map +1 -1
  213. package/dist/src/utils/catalog-sources.d.ts +1 -0
  214. package/dist/src/utils/catalog-sources.js +55 -20
  215. package/dist/src/utils/catalog-sources.js.map +1 -1
  216. package/dist/src/utils/codex-config.d.ts +2 -0
  217. package/dist/src/utils/codex-config.js +26 -5
  218. package/dist/src/utils/codex-config.js.map +1 -1
  219. package/dist/src/utils/codex-manager.d.ts +81 -0
  220. package/dist/src/utils/codex-manager.js +810 -0
  221. package/dist/src/utils/codex-manager.js.map +1 -0
  222. package/dist/src/utils/codex-reconciler.d.ts +131 -0
  223. package/dist/src/utils/codex-reconciler.js +327 -0
  224. package/dist/src/utils/codex-reconciler.js.map +1 -0
  225. package/dist/src/utils/codex-shared-native.d.ts +56 -0
  226. package/dist/src/utils/codex-shared-native.js +87 -0
  227. package/dist/src/utils/codex-shared-native.js.map +1 -0
  228. package/dist/src/utils/codex-skill-staging.d.ts +2 -0
  229. package/dist/src/utils/codex-skill-staging.js.map +1 -1
  230. package/dist/src/utils/codex-surface-analysis.d.ts +44 -0
  231. package/dist/src/utils/codex-surface-analysis.js +247 -0
  232. package/dist/src/utils/codex-surface-analysis.js.map +1 -0
  233. package/dist/src/utils/dynamic-skill-tree.d.ts +4 -0
  234. package/dist/src/utils/dynamic-skill-tree.js +35 -5
  235. package/dist/src/utils/dynamic-skill-tree.js.map +1 -1
  236. package/dist/src/utils/git-catalog-provider.js +66 -140
  237. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  238. package/dist/src/utils/lifecycle-active-store.d.ts +0 -28
  239. package/dist/src/utils/lifecycle-active-store.js +35 -247
  240. package/dist/src/utils/lifecycle-active-store.js.map +1 -1
  241. package/dist/src/utils/manifest.d.ts +1 -3
  242. package/dist/src/utils/manifest.js +1 -3
  243. package/dist/src/utils/manifest.js.map +1 -1
  244. package/dist/src/utils/multi-source-catalog.d.ts +3 -9
  245. package/dist/src/utils/multi-source-catalog.js +53 -110
  246. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  247. package/dist/src/utils/native-cli.d.ts +49 -6
  248. package/dist/src/utils/native-cli.js +116 -33
  249. package/dist/src/utils/native-cli.js.map +1 -1
  250. package/dist/src/utils/orphan-marketplace-cleanup.js +1 -3
  251. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
  252. package/dist/src/utils/ownership.d.ts +10 -11
  253. package/dist/src/utils/ownership.js +55 -112
  254. package/dist/src/utils/ownership.js.map +1 -1
  255. package/dist/src/utils/path-catalog-provider.d.ts +1 -1
  256. package/dist/src/utils/path-catalog-provider.js +52 -65
  257. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  258. package/dist/src/utils/paths.d.ts +0 -1
  259. package/dist/src/utils/paths.js +0 -1
  260. package/dist/src/utils/paths.js.map +1 -1
  261. package/dist/src/utils/plugin-config-write.js +18 -40
  262. package/dist/src/utils/plugin-config-write.js.map +1 -1
  263. package/dist/src/utils/plugin-config.d.ts +1 -12
  264. package/dist/src/utils/plugin-config.js +107 -226
  265. package/dist/src/utils/plugin-config.js.map +1 -1
  266. package/dist/src/utils/plugin-intent-state.d.ts +39 -0
  267. package/dist/src/utils/plugin-intent-state.js +325 -0
  268. package/dist/src/utils/plugin-intent-state.js.map +1 -0
  269. package/dist/src/utils/plugin-scripts.d.ts +1 -1
  270. package/dist/src/utils/plugin-scripts.js +1 -1
  271. package/dist/src/utils/plugin-scripts.js.map +1 -1
  272. package/dist/src/utils/state-paths.js +7 -2
  273. package/dist/src/utils/state-paths.js.map +1 -1
  274. package/dist/src/utils/target-eligibility.d.ts +8 -2
  275. package/dist/src/utils/target-eligibility.js +9 -5
  276. package/dist/src/utils/target-eligibility.js.map +1 -1
  277. package/package.json +6 -4
  278. package/dist/authoring/scripts/check-plugin-versions.d.mts +0 -2
  279. package/dist/authoring/scripts/check-plugin-versions.mjs +0 -5
  280. package/dist/authoring/scripts/check-plugin-versions.mjs.map +0 -1
  281. package/dist/scripts/aw-skill-eval-engine.d.ts +0 -13
  282. package/dist/scripts/aw-skill-eval-engine.js +0 -31
  283. package/dist/scripts/aw-skill-eval-engine.js.map +0 -1
  284. package/dist/scripts/codex-eval-app-server.d.ts +0 -89
  285. package/dist/scripts/codex-eval-app-server.js +0 -1228
  286. package/dist/scripts/codex-eval-app-server.js.map +0 -1
  287. package/dist/scripts/codex-eval-isolation.d.ts +0 -61
  288. package/dist/scripts/codex-eval-isolation.js +0 -318
  289. package/dist/scripts/codex-eval-isolation.js.map +0 -1
  290. package/dist/scripts/codex-eval-process-management.d.ts +0 -8
  291. package/dist/scripts/codex-eval-process-management.js +0 -69
  292. package/dist/scripts/codex-eval-process-management.js.map +0 -1
  293. package/dist/scripts/codex-eval-process-tree.d.ts +0 -38
  294. package/dist/scripts/codex-eval-process-tree.js +0 -803
  295. package/dist/scripts/codex-eval-process-tree.js.map +0 -1
  296. package/dist/scripts/codex-eval-runtime-config.d.ts +0 -62
  297. package/dist/scripts/codex-eval-runtime-config.js +0 -843
  298. package/dist/scripts/codex-eval-runtime-config.js.map +0 -1
  299. package/dist/scripts/codex-trigger-eval.d.ts +0 -84
  300. package/dist/scripts/codex-trigger-eval.js +0 -968
  301. package/dist/scripts/codex-trigger-eval.js.map +0 -1
  302. package/dist/scripts/eval-plugin-skills-audited.d.ts +0 -6
  303. package/dist/scripts/eval-plugin-skills-audited.js +0 -261
  304. package/dist/scripts/eval-plugin-skills-audited.js.map +0 -1
  305. package/dist/scripts/eval-plugin-skills.d.ts +0 -45
  306. package/dist/scripts/eval-plugin-skills.js +0 -1586
  307. package/dist/scripts/eval-plugin-skills.js.map +0 -1
  308. package/dist/scripts/eval-run-layout.d.ts +0 -17
  309. package/dist/scripts/eval-run-layout.js +0 -26
  310. package/dist/scripts/eval-run-layout.js.map +0 -1
  311. package/dist/scripts/plugin-eval-contract.d.ts +0 -185
  312. package/dist/scripts/plugin-eval-contract.js +0 -695
  313. package/dist/scripts/plugin-eval-contract.js.map +0 -1
  314. package/dist/scripts/plugin-eval-materializer.d.ts +0 -13
  315. package/dist/scripts/plugin-eval-materializer.js.map +0 -1
  316. package/dist/scripts/skill-reporting.d.ts +0 -212
  317. package/dist/scripts/skill-reporting.js +0 -922
  318. package/dist/scripts/skill-reporting.js.map +0 -1
  319. package/dist/src/commands/status-v4.d.ts +0 -123
  320. package/dist/src/commands/status-v4.js +0 -905
  321. package/dist/src/commands/status-v4.js.map +0 -1
  322. package/dist/src/commands/status.d.ts +0 -93
  323. package/dist/src/commands/status.js +0 -442
  324. package/dist/src/commands/status.js.map +0 -1
  325. package/dist/src/utils/active-marketplace-runtime-lock.d.ts +0 -12
  326. package/dist/src/utils/active-marketplace-runtime-lock.js +0 -133
  327. package/dist/src/utils/active-marketplace-runtime-lock.js.map +0 -1
  328. package/dist/src/utils/catalog-manifest-v3.d.ts +0 -2
  329. package/dist/src/utils/catalog-manifest-v3.js +0 -3
  330. package/dist/src/utils/catalog-manifest-v3.js.map +0 -1
  331. package/dist/src/utils/catalog-manifest-v4.d.ts +0 -5
  332. package/dist/src/utils/catalog-manifest-v4.js.map +0 -1
  333. package/dist/src/utils/catalog-source-cache.d.ts +0 -62
  334. package/dist/src/utils/catalog-source-cache.js +0 -296
  335. package/dist/src/utils/catalog-source-cache.js.map +0 -1
  336. package/dist/src/utils/codex-project-surface.d.ts +0 -3
  337. package/dist/src/utils/codex-project-surface.js +0 -49
  338. package/dist/src/utils/codex-project-surface.js.map +0 -1
  339. package/dist/src/utils/plugin-release.d.ts +0 -2
  340. package/dist/src/utils/plugin-release.js +0 -2
  341. package/dist/src/utils/plugin-release.js.map +0 -1
@@ -18,7 +18,8 @@ const CLI_PACKAGE_ROOT = path.basename(authoringRuntimeRoot) === 'dist'
18
18
  : authoringRuntimeRoot;
19
19
  const errors = [];
20
20
  const warnings = [];
21
- const SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION = 7;
21
+ const SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION = 9;
22
+ let capabilityDiagnostic = null;
22
23
  const MAX_SKILL_NAME_LEN = 64;
23
24
  const MAX_SKILL_DESCRIPTION_LEN = 1024;
24
25
  const MAX_SKILL_COMPATIBILITY_LEN = 500;
@@ -149,22 +150,9 @@ const ARTIFACT_PROJECT_MANAGED_KIND_BY_TARGET = {
149
150
  'codex.skill': 'skill',
150
151
  };
151
152
  const PLUGIN_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
152
- const PLUGIN_EVAL_SCHEMA_VERSION = 2;
153
- const PLUGIN_EVAL_CASE_SCHEMA_VERSION = 1;
154
- const PLUGIN_EVAL_SCOPES = new Set(['user', 'project']);
155
- const PLUGIN_EVAL_SPLITS = new Set(['train', 'validation', 'sanity', 'all']);
156
- const PLUGIN_EVAL_TRIGGER_CASE_SPLITS = new Set(['train', 'validation', 'sanity']);
157
- const PLUGIN_EVAL_COMMAND_SUPPORTS = new Set([
158
- 'split',
159
- 'runs',
160
- 'case',
161
- 'model',
162
- 'codexBin',
163
- 'timeout',
164
- 'allowEnvironmentSkips',
165
- ]);
166
153
  let yamlParser = null;
167
154
  let pluginVersionCheckResult = null;
155
+ let skillEvalManifestTools = null;
168
156
  function error(msg) {
169
157
  errors.push(msg);
170
158
  }
@@ -331,12 +319,16 @@ function loadSkillFrontmatterCapabilityRegistry() {
331
319
  async function tryLoadCliManifestTools() {
332
320
  const manifestModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'manifest.js');
333
321
  const runtimeProjectionModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'catalog-runtime-projection.js');
334
- if (!fs.existsSync(manifestModulePath) || !fs.existsSync(runtimeProjectionModulePath))
322
+ const capabilityModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'commands', 'aw-capabilities.js');
323
+ if (!fs.existsSync(manifestModulePath)
324
+ || !fs.existsSync(runtimeProjectionModulePath)
325
+ || !fs.existsSync(capabilityModulePath))
335
326
  return null;
336
327
  try {
337
- const [manifestModule, runtimeProjectionModule] = await Promise.all([
328
+ const [manifestModule, runtimeProjectionModule, capabilityModule] = await Promise.all([
338
329
  import(pathToFileURL(manifestModulePath).href),
339
330
  import(pathToFileURL(runtimeProjectionModulePath).href),
331
+ import(pathToFileURL(capabilityModulePath).href),
340
332
  ]);
341
333
  if (manifestModule.SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION
342
334
  !== SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION) {
@@ -347,6 +339,8 @@ async function tryLoadCliManifestTools() {
347
339
  validateSourcePluginManifest: manifestModule.validateSourcePluginManifest ?? null,
348
340
  readPluginManifest: manifestModule.readPluginManifest ?? null,
349
341
  discoverPlugins: manifestModule.discoverPlugins ?? null,
342
+ resolvePluginRequirements: manifestModule.resolvePluginRequirements ?? null,
343
+ implementedCapabilities: capabilityModule.IMPLEMENTED_AW_CAPABILITIES ?? null,
350
344
  createRuntimeResolver: runtimeProjectionModule.createCatalogRuntimeImportResolver ?? null,
351
345
  };
352
346
  }
@@ -498,11 +492,12 @@ function validateManifestLightweight(manifest) {
498
492
  error('top-level "commands" has been removed; use "slashCommands" instead');
499
493
  }
500
494
  validateAllowedKeys(input, 'plugin manifest', [
495
+ 'schemaVersion',
501
496
  'name',
502
497
  'version',
503
498
  'description',
504
499
  'dependencies',
505
- 'compatibility',
500
+ 'requires',
506
501
  'skills',
507
502
  'slashCommands',
508
503
  'mcpServers',
@@ -613,7 +608,7 @@ function validatePortableNativeArtifactCapabilityLightweight(manifest) {
613
608
  && Array.isArray(target.states)
614
609
  && target.states.includes('present'));
615
610
  if (!hasOtherNativeDeclaration && !hasPresentNativeArtifact) {
616
- const message = 'Invalid plugin manifest: portable-only plugins are not supported in V1. Declare at least one non-empty native capability.';
611
+ const message = 'Invalid plugin manifest: portable-only plugins are not supported. Declare at least one non-empty native capability.';
617
612
  if (!errors.includes(message))
618
613
  error(message);
619
614
  }
@@ -950,703 +945,19 @@ function validateNonEmptyString(value, fieldName, maxLength) {
950
945
  }
951
946
  return trimmed;
952
947
  }
953
- function isPathInsideOrEqual(root, candidate) {
954
- const relative = path.relative(root, candidate);
955
- return relative === '' || (relative !== '..' &&
956
- !relative.startsWith(`..${path.sep}`) &&
957
- !path.isAbsolute(relative));
958
- }
959
- function validateRealPathBoundary(boundary, candidate, fieldName, boundaryName) {
960
- const canonicalBoundary = fs.realpathSync(boundary);
961
- const canonicalCandidate = fs.realpathSync(candidate);
962
- if (!isPathInsideOrEqual(canonicalBoundary, canonicalCandidate)) {
963
- error(`${fieldName} must stay inside the ${boundaryName}`);
964
- return false;
965
- }
966
- return true;
967
- }
968
- function validateEvalRelativeFile(evalDir, value, fieldName) {
969
- const relativePath = validateNonEmptyString(value, fieldName);
970
- if (!relativePath)
971
- return null;
972
- const normalized = stripDotSlash(relativePath).split('\\').join('/');
973
- if (path.isAbsolute(normalized) || normalized.split('/').includes('..')) {
974
- error(`${fieldName} must stay inside the Skill eval directory`);
975
- return null;
976
- }
977
- const absolutePath = path.resolve(evalDir, normalized);
978
- const relativeToRoot = path.relative(evalDir, absolutePath);
979
- if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
980
- error(`${fieldName} must stay inside the Skill eval directory`);
981
- return null;
982
- }
983
- if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) {
984
- error(`${fieldName} does not exist: ${normalized}`);
985
- return null;
986
- }
987
- if (!validateRealPathBoundary(evalDir, absolutePath, fieldName, 'Skill eval directory')) {
988
- return null;
989
- }
990
- return absolutePath;
991
- }
992
- function validateEvalWorkspacePath(value, fieldName, options = {}) {
993
- const raw = validateNonEmptyString(value, fieldName);
994
- if (!raw)
995
- return null;
996
- const treePattern = options.allowTreePattern === true && raw.endsWith('/**');
997
- const candidate = treePattern ? raw.slice(0, -3) : raw;
998
- if (candidate === '' ||
999
- candidate.includes('\0') ||
1000
- candidate.includes('\\') ||
1001
- candidate.includes('*') ||
1002
- candidate.includes('?') ||
1003
- candidate.includes('[') ||
1004
- candidate.includes(']') ||
1005
- path.isAbsolute(candidate) ||
1006
- path.posix.normalize(candidate) !== candidate ||
1007
- candidate.split('/').includes('..')) {
1008
- error(`${fieldName} must be a normalized POSIX path inside the eval workspace`);
1009
- return null;
1010
- }
1011
- const firstSegment = candidate.split('/')[0];
1012
- if (firstSegment === '.git' || firstSegment === '.agents' || firstSegment === '.codex') {
1013
- error(`${fieldName} must not target an eval control directory`);
1014
- return null;
1015
- }
1016
- return raw;
1017
- }
1018
- function evalWorkspacePathMatchesPattern(relativePath, pattern) {
1019
- if (pattern.endsWith('/**')) {
1020
- const prefix = pattern.slice(0, -3);
1021
- return relativePath === prefix || relativePath.startsWith(`${prefix}/`);
1022
- }
1023
- return relativePath === pattern;
1024
- }
1025
- function validateConversationCaseCorpus(evalDir, suite, fieldName) {
1026
- const casesPath = validateEvalRelativeFile(evalDir, suite.cases, `${fieldName}.cases`);
1027
- if (!casesPath)
1028
- return;
1029
- let document;
1030
- try {
1031
- document = JSON.parse(fs.readFileSync(casesPath, 'utf8'));
1032
- }
1033
- catch (e) {
1034
- error(`${fieldName}.cases is not valid JSON: ${e.message}`);
1035
- return;
1036
- }
1037
- const corpus = expectRecord(document, `${fieldName}.cases document`);
1038
- if (!corpus)
1039
- return;
1040
- const skillName = validateNonEmptyString(corpus.skill_name, `${fieldName}.cases.skill_name`);
1041
- if (skillName && skillName !== suite.skill) {
1042
- error(`${fieldName}.cases.skill_name must match ${JSON.stringify(suite.skill)}`);
1043
- }
1044
- if (!Array.isArray(corpus.evals) || corpus.evals.length === 0) {
1045
- error(`${fieldName}.cases.evals must be a non-empty array`);
1046
- return;
1047
- }
1048
- const ids = new Set();
1049
- corpus.evals.forEach((value, caseIndex) => {
1050
- const caseField = `${fieldName}.cases.evals[${caseIndex}]`;
1051
- const entry = expectRecord(value, caseField);
1052
- if (!entry)
1053
- return;
1054
- const id = validateNonEmptyString(entry.id, `${caseField}.id`);
1055
- if (id && ids.has(id)) {
1056
- error(`${fieldName}.cases has duplicate case id ${JSON.stringify(id)}`);
1057
- }
1058
- else if (id) {
1059
- ids.add(id);
1060
- }
1061
- validateNonEmptyString(entry.prompt, `${caseField}.prompt`);
1062
- const sandbox = entry.sandbox === undefined
1063
- ? 'read-only'
1064
- : validateNonEmptyString(entry.sandbox, `${caseField}.sandbox`);
1065
- if (sandbox && sandbox !== 'read-only' && sandbox !== 'workspace-write') {
1066
- error(`${caseField}.sandbox must be "read-only" or "workspace-write"`);
1067
- }
1068
- if (!Array.isArray(entry.scripted_replies)) {
1069
- error(`${caseField}.scripted_replies must be an array`);
1070
- }
1071
- else {
1072
- entry.scripted_replies.forEach((reply, replyIndex) => {
1073
- const replyField = `${caseField}.scripted_replies[${replyIndex}]`;
1074
- if (typeof reply === 'string')
1075
- return;
1076
- const replyEntry = expectRecord(reply, replyField);
1077
- if (!replyEntry)
1078
- return;
1079
- if (!Array.isArray(replyEntry.answers_by_index) || replyEntry.answers_by_index.some((answer) => typeof answer !== 'string')) {
1080
- error(`${replyField}.answers_by_index must be an array of strings`);
1081
- }
1082
- if (replyEntry.expected_question_count !== undefined &&
1083
- (!Number.isInteger(replyEntry.expected_question_count) ||
1084
- replyEntry.expected_question_count < 0)) {
1085
- error(`${replyField}.expected_question_count must be a non-negative integer`);
1086
- }
1087
- validateNonEmptyString(replyEntry.unexpected_question_answer, `${replyField}.unexpected_question_answer`);
1088
- });
1089
- }
1090
- validateNonEmptyString(entry.expected_output, `${caseField}.expected_output`);
1091
- if (entry.workspace_files !== undefined) {
1092
- const workspaceFiles = expectRecord(entry.workspace_files, `${caseField}.workspace_files`);
1093
- if (workspaceFiles) {
1094
- const workspaceFileEntries = Object.entries(workspaceFiles);
1095
- if (workspaceFileEntries.length === 0) {
1096
- error(`${caseField}.workspace_files must contain at least one file`);
1097
- }
1098
- workspaceFileEntries.forEach(([relativePath, content]) => {
1099
- validateEvalWorkspacePath(relativePath, `${caseField}.workspace_files.${relativePath}`, { allowTreePattern: false });
1100
- validateNonEmptyString(content, `${caseField}.workspace_files.${relativePath}`);
1101
- });
1102
- }
1103
- }
1104
- const review = expectRecord(entry.review, `${caseField}.review`);
1105
- if (review) {
1106
- if (!Array.isArray(review.checks) || review.checks.length === 0 || review.checks.some((check) => typeof check !== 'string' || check.trim() === '')) {
1107
- error(`${caseField}.review.checks must be a non-empty array of strings`);
1108
- }
1109
- if (review.workspace_unchanged !== undefined &&
1110
- typeof review.workspace_unchanged !== 'boolean') {
1111
- error(`${caseField}.review.workspace_unchanged must be boolean`);
1112
- }
1113
- const allowedWorkspaceChanges = [];
1114
- if (review.allowed_workspace_changes !== undefined) {
1115
- if (!Array.isArray(review.allowed_workspace_changes) ||
1116
- review.allowed_workspace_changes.length === 0) {
1117
- error(`${caseField}.review.allowed_workspace_changes must be a non-empty array`);
1118
- }
1119
- else {
1120
- review.allowed_workspace_changes.forEach((pathValue, pathIndex) => {
1121
- const normalized = validateEvalWorkspacePath(pathValue, `${caseField}.review.allowed_workspace_changes[${pathIndex}]`, { allowTreePattern: true });
1122
- if (normalized)
1123
- allowedWorkspaceChanges.push(normalized);
1124
- });
1125
- }
1126
- }
1127
- const artifactPaths = [];
1128
- if (review.artifacts !== undefined) {
1129
- if (!Array.isArray(review.artifacts) || review.artifacts.length === 0) {
1130
- error(`${caseField}.review.artifacts must be a non-empty array`);
1131
- }
1132
- else {
1133
- review.artifacts.forEach((artifactValue, artifactIndex) => {
1134
- const artifactField = `${caseField}.review.artifacts[${artifactIndex}]`;
1135
- const artifact = expectRecord(artifactValue, artifactField);
1136
- if (!artifact)
1137
- return;
1138
- validateAllowedKeys(artifact, artifactField, ['path', 'exists', 'contains', 'not_contains', 'json']);
1139
- const artifactPath = validateEvalWorkspacePath(artifact.path, `${artifactField}.path`);
1140
- if (artifactPath)
1141
- artifactPaths.push(artifactPath);
1142
- if (artifact.exists !== undefined && typeof artifact.exists !== 'boolean') {
1143
- error(`${artifactField}.exists must be boolean`);
1144
- }
1145
- for (const key of ['contains', 'not_contains']) {
1146
- if (artifact[key] !== undefined &&
1147
- (!Array.isArray(artifact[key]) || artifact[key].length === 0 || artifact[key].some((fragment) => typeof fragment !== 'string' || fragment.length === 0))) {
1148
- error(`${artifactField}.${key} must be a non-empty array of strings`);
1149
- }
1150
- }
1151
- if (artifact.json !== undefined && !isRecord(artifact.json)) {
1152
- error(`${artifactField}.json must be an object`);
1153
- }
1154
- });
1155
- }
1156
- }
1157
- if (new Set(artifactPaths).size !== artifactPaths.length) {
1158
- error(`${caseField}.review.artifacts contains duplicate paths`);
1159
- }
1160
- if (sandbox === 'workspace-write') {
1161
- if (review.workspace_unchanged !== false) {
1162
- error(`${caseField} workspace-write requires review.workspace_unchanged=false`);
1163
- }
1164
- if (allowedWorkspaceChanges.length === 0 || artifactPaths.length === 0) {
1165
- error(`${caseField} workspace-write requires allowed changes and artifacts`);
1166
- }
1167
- const unmatchedArtifact = artifactPaths.find((artifactPath) => !allowedWorkspaceChanges.some((pattern) => evalWorkspacePathMatchesPattern(artifactPath, pattern)));
1168
- if (unmatchedArtifact) {
1169
- error(`${caseField} artifact ${JSON.stringify(unmatchedArtifact)} is outside allowed changes`);
1170
- }
1171
- }
1172
- }
1173
- });
1174
- }
1175
- function validateTriggerCaseCorpus(evalDir, suite, fieldName) {
1176
- const casesPath = validateEvalRelativeFile(evalDir, suite.cases, `${fieldName}.cases`);
1177
- if (!casesPath)
1178
- return;
1179
- let document;
1180
- try {
1181
- document = JSON.parse(fs.readFileSync(casesPath, 'utf8'));
1182
- }
1183
- catch (e) {
1184
- error(`${fieldName}.cases is not valid JSON: ${e.message}`);
1185
- return;
1186
- }
1187
- const corpus = expectRecord(document, `${fieldName}.cases document`);
1188
- if (!corpus)
1189
- return;
1190
- if (corpus.schemaVersion !== PLUGIN_EVAL_CASE_SCHEMA_VERSION) {
1191
- error(`${fieldName}.cases.schemaVersion must be ${PLUGIN_EVAL_CASE_SCHEMA_VERSION}`);
1192
- }
1193
- if (corpus.skill !== suite.skill) {
1194
- error(`${fieldName}.cases.skill must match ${JSON.stringify(suite.skill)}`);
1195
- }
1196
- if (!Array.isArray(corpus.cases) || corpus.cases.length === 0) {
1197
- error(`${fieldName}.cases.cases must be a non-empty array`);
1198
- return;
1199
- }
1200
- const ids = new Set();
1201
- const seenSplits = new Set();
1202
- let hasWorkspaceFixture = false;
1203
- corpus.cases.forEach((value, caseIndex) => {
1204
- const caseField = `${fieldName}.cases.cases[${caseIndex}]`;
1205
- const entry = expectRecord(value, caseField);
1206
- if (!entry)
1207
- return;
1208
- const id = validateNonEmptyString(entry.id, `${caseField}.id`);
1209
- if (id && !/^[a-z0-9][a-z0-9_]*$/.test(id)) {
1210
- error(`${caseField}.id must use lowercase snake_case`);
1211
- }
1212
- else if (id && ids.has(id)) {
1213
- error(`${fieldName}.cases has duplicate case id ${JSON.stringify(id)}`);
1214
- }
1215
- else if (id) {
1216
- ids.add(id);
1217
- }
1218
- if (!PLUGIN_EVAL_TRIGGER_CASE_SPLITS.has(entry.split)) {
1219
- error(`${caseField}.split must be train, validation, or sanity`);
1220
- }
1221
- else {
1222
- seenSplits.add(entry.split);
1223
- }
1224
- validateNonEmptyString(entry.query, `${caseField}.query`);
1225
- const usesLegacyExpectation = entry.should_load_skill !== undefined;
1226
- const usesRouteExpectation = entry.expected_loaded_skills !== undefined;
1227
- if (usesLegacyExpectation === usesRouteExpectation) {
1228
- error(`${caseField} must declare exactly one of should_load_skill or expected_loaded_skills`);
1229
- }
1230
- else if (usesLegacyExpectation && typeof entry.should_load_skill !== 'boolean') {
1231
- error(`${caseField}.should_load_skill must be boolean`);
1232
- }
1233
- else if (usesRouteExpectation) {
1234
- if (!Array.isArray(entry.expected_loaded_skills)) {
1235
- error(`${caseField}.expected_loaded_skills must be an array`);
1236
- }
1237
- else {
1238
- const expectedSkills = entry.expected_loaded_skills;
1239
- expectedSkills.forEach((skillName, skillIndex) => {
1240
- if (typeof skillName !== 'string' || skillName.trim() === '') {
1241
- error(`${caseField}.expected_loaded_skills[${skillIndex}] must be a non-empty string`);
1242
- }
1243
- else if (!suite.skills.includes(skillName)) {
1244
- error(`${caseField}.expected_loaded_skills[${skillIndex}] must name a participant Skill`);
1245
- }
1246
- });
1247
- if (new Set(expectedSkills).size !== expectedSkills.length) {
1248
- error(`${caseField}.expected_loaded_skills must not contain duplicates`);
1249
- }
1250
- if (suite.forbidMultipleSkillLoads === true && expectedSkills.length > 1) {
1251
- error(`${caseField} expects multiple Skills but the suite forbids multiple Skill loads`);
1252
- }
1253
- }
1254
- }
1255
- if (suite.observeSpawnAgent === true) {
1256
- if (typeof entry.should_spawn_agent !== 'boolean') {
1257
- error(`${caseField}.should_spawn_agent is required when observeSpawnAgent=true`);
1258
- }
1259
- }
1260
- else if (entry.should_spawn_agent !== undefined) {
1261
- error(`${caseField}.should_spawn_agent requires observeSpawnAgent=true`);
1262
- }
1263
- if (entry.workspace_fixture !== undefined) {
1264
- hasWorkspaceFixture = true;
1265
- validateNonEmptyString(entry.workspace_fixture, `${caseField}.workspace_fixture`);
1266
- }
1267
- if (entry.use_project_rules !== undefined &&
1268
- typeof entry.use_project_rules !== 'boolean') {
1269
- error(`${caseField}.use_project_rules must be boolean`);
1270
- }
1271
- if (entry.tags !== undefined) {
1272
- if (!Array.isArray(entry.tags) || entry.tags.length === 0) {
1273
- error(`${caseField}.tags must be a non-empty array`);
1274
- }
1275
- else {
1276
- entry.tags.forEach((tag, tagIndex) => {
1277
- validateNonEmptyString(tag, `${caseField}.tags[${tagIndex}]`);
1278
- });
1279
- }
1280
- }
1281
- });
1282
- if (hasWorkspaceFixture && suite.fixtureModule === undefined) {
1283
- error(`${fieldName}.fixtureModule is required when cases declare workspace_fixture`);
1284
- }
1285
- if (Array.isArray(suite.releaseSplits)) {
1286
- suite.releaseSplits.forEach((split) => {
1287
- if (split !== 'all' && !seenSplits.has(split)) {
1288
- error(`${fieldName}.cases has no cases for release split ${JSON.stringify(split)}`);
1289
- }
1290
- });
1291
- }
1292
- }
1293
- function resolveEvalProfilePlugin(pluginDir, ownerManifest, pluginName, fieldName) {
1294
- if (pluginName === ownerManifest.name) {
1295
- return { pluginDir, manifest: ownerManifest };
1296
- }
1297
- const companionDir = path.join(path.dirname(pluginDir), pluginName);
1298
- const manifestPath = path.join(companionDir, '.agents-plugin', 'plugin.json');
1299
- if (!fs.existsSync(manifestPath)) {
1300
- error(`${fieldName} must reference repo-local plugin "${pluginName}"`);
1301
- return null;
1302
- }
1303
- let manifest;
948
+ async function loadSkillEvalManifestTools() {
949
+ if (skillEvalManifestTools)
950
+ return skillEvalManifestTools;
951
+ const modulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'eval', 'manifest-v1.js');
1304
952
  try {
1305
- manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
953
+ skillEvalManifestTools = await import(pathToFileURL(modulePath).href);
954
+ return skillEvalManifestTools;
1306
955
  }
1307
- catch (e) {
1308
- error(`${fieldName} companion manifest is not valid JSON: ${e.message}`);
1309
- return null;
1310
- }
1311
- if (!isRecord(manifest) || manifest.name !== pluginName) {
1312
- error(`${fieldName} companion source must declare plugin name "${pluginName}"`);
956
+ catch {
1313
957
  return null;
1314
958
  }
1315
- return { pluginDir: companionDir, manifest };
1316
- }
1317
- function validateOnePluginEvalManifest(pluginDir, pluginManifest, evalDir, expectedSkill) {
1318
- const evalManifestPath = path.join(evalDir, 'manifest.json');
1319
- const manifestField = path.relative(pluginDir, evalManifestPath).split(path.sep).join('/');
1320
- let document;
1321
- try {
1322
- document = JSON.parse(fs.readFileSync(evalManifestPath, 'utf8'));
1323
- }
1324
- catch (e) {
1325
- error(`${manifestField} is not valid JSON: ${e.message}`);
1326
- return;
1327
- }
1328
- const manifest = expectRecord(document, manifestField);
1329
- if (!manifest)
1330
- return;
1331
- validateAllowedKeys(manifest, manifestField, ['schemaVersion', 'plugin', 'skill', 'profiles', 'suites']);
1332
- if (manifest.schemaVersion !== PLUGIN_EVAL_SCHEMA_VERSION) {
1333
- error(`${manifestField}.schemaVersion must be ${PLUGIN_EVAL_SCHEMA_VERSION}`);
1334
- }
1335
- if (manifest.plugin !== pluginManifest.name) {
1336
- error(`${manifestField}.plugin must match plugin name ${JSON.stringify(pluginManifest.name)}`);
1337
- }
1338
- const skill = validateNonEmptyString(manifest.skill, `${manifestField}.skill`);
1339
- if (skill && skill !== expectedSkill) {
1340
- error(`${manifestField}.skill must match owning Skill ${JSON.stringify(expectedSkill)}`);
1341
- }
1342
- if (skill && !collectDeclaredSkillNames(pluginDir, pluginManifest).all.has(skill)) {
1343
- error(`${manifestField}.skill must reference a declared static or dynamic skill`);
1344
- }
1345
- if (!Array.isArray(manifest.profiles) || manifest.profiles.length === 0) {
1346
- error(`${manifestField}.profiles must be a non-empty array`);
1347
- return;
1348
- }
1349
- const profilesById = new Map();
1350
- manifest.profiles.forEach((value, index) => {
1351
- const fieldName = `${manifestField}.profiles[${index}]`;
1352
- const profile = expectRecord(value, fieldName);
1353
- if (!profile)
1354
- return;
1355
- validateAllowedKeys(profile, fieldName, ['id', 'scope', 'plugins', 'runModel', 'requiredForRelease']);
1356
- const id = validateNonEmptyString(profile.id, `${fieldName}.id`);
1357
- if (id && !PLUGIN_NAME_PATTERN.test(id)) {
1358
- error(`${fieldName}.id must use lowercase kebab-case`);
1359
- }
1360
- else if (id && profilesById.has(id)) {
1361
- error(`${manifestField} has duplicate profile id ${JSON.stringify(id)}`);
1362
- }
1363
- if (!PLUGIN_EVAL_SCOPES.has(profile.scope)) {
1364
- error(`${fieldName}.scope must be user or project`);
1365
- }
1366
- const skillOwners = new Map();
1367
- const installedPlugins = new Set();
1368
- if (!Array.isArray(profile.plugins) || profile.plugins.length === 0) {
1369
- error(`${fieldName}.plugins must be a non-empty array`);
1370
- }
1371
- else {
1372
- profile.plugins.forEach((value, pluginIndex) => {
1373
- const pluginField = `${fieldName}.plugins[${pluginIndex}]`;
1374
- const installation = expectRecord(value, pluginField);
1375
- if (!installation)
1376
- return;
1377
- validateAllowedKeys(installation, pluginField, ['name', 'config']);
1378
- const pluginName = validateNonEmptyString(installation.name, `${pluginField}.name`);
1379
- if (!pluginName)
1380
- return;
1381
- if (!PLUGIN_NAME_PATTERN.test(pluginName)) {
1382
- error(`${pluginField}.name must use lowercase kebab-case`);
1383
- }
1384
- if (installedPlugins.has(pluginName)) {
1385
- error(`${fieldName}.plugins has duplicate plugin ${JSON.stringify(pluginName)}`);
1386
- return;
1387
- }
1388
- installedPlugins.add(pluginName);
1389
- if (installation.config !== undefined && !isRecord(installation.config)) {
1390
- error(`${pluginField}.config must be an object`);
1391
- }
1392
- const source = resolveEvalProfilePlugin(pluginDir, pluginManifest, pluginName, `${pluginField}.name`);
1393
- if (!source)
1394
- return;
1395
- for (const skillName of collectDeclaredSkillNames(source.pluginDir, source.manifest).all) {
1396
- const existing = skillOwners.get(skillName);
1397
- if (existing && existing !== pluginName) {
1398
- error(`${fieldName} installs duplicate Skill key ${JSON.stringify(skillName)} ` +
1399
- `from plugins ${JSON.stringify(existing)} and ${JSON.stringify(pluginName)}`);
1400
- }
1401
- else {
1402
- skillOwners.set(skillName, pluginName);
1403
- }
1404
- }
1405
- });
1406
- }
1407
- if (!installedPlugins.has(pluginManifest.name)) {
1408
- error(`${fieldName}.plugins must include owner plugin ${JSON.stringify(pluginManifest.name)}`);
1409
- }
1410
- if (typeof profile.runModel !== 'boolean') {
1411
- error(`${fieldName}.runModel must be boolean`);
1412
- }
1413
- if (typeof profile.requiredForRelease !== 'boolean') {
1414
- error(`${fieldName}.requiredForRelease must be boolean`);
1415
- }
1416
- if (profile.scope === 'user' && profile.runModel === true) {
1417
- error(`${fieldName}: eval schema v2 does not allow real model execution for user scope`);
1418
- }
1419
- if (id && PLUGIN_NAME_PATTERN.test(id) && !profilesById.has(id)) {
1420
- profilesById.set(id, { ...profile, skillOwners });
1421
- }
1422
- });
1423
- if (!manifest.profiles.some((profile) => isRecord(profile) && profile.scope === 'project' && profile.runModel === true)) {
1424
- error(`${manifestField} must define at least one project profile with runModel=true`);
1425
- }
1426
- if (!Array.isArray(manifest.suites) || manifest.suites.length === 0) {
1427
- error(`${manifestField}.suites must be a non-empty array`);
1428
- return;
1429
- }
1430
- const suiteIds = new Set();
1431
- manifest.suites.forEach((value, index) => {
1432
- const fieldName = `${manifestField}.suites[${index}]`;
1433
- const suite = expectRecord(value, fieldName);
1434
- if (!suite)
1435
- return;
1436
- const id = validateNonEmptyString(suite.id, `${fieldName}.id`);
1437
- if (id && !PLUGIN_NAME_PATTERN.test(id)) {
1438
- error(`${fieldName}.id must use lowercase kebab-case`);
1439
- }
1440
- else if (id && suiteIds.has(id)) {
1441
- error(`${manifestField} has duplicate suite id ${JSON.stringify(id)}`);
1442
- }
1443
- else if (id) {
1444
- suiteIds.add(id);
1445
- }
1446
- if (suite.kind !== 'command' && suite.kind !== 'conversation' && suite.kind !== 'trigger') {
1447
- error(`${fieldName}.kind must be command, conversation, or trigger`);
1448
- }
1449
- const suiteSkills = new Set();
1450
- if (!Array.isArray(suite.skills) || suite.skills.length === 0) {
1451
- error(`${fieldName}.skills must be a non-empty array`);
1452
- }
1453
- else {
1454
- suite.skills.forEach((skillName, skillIndex) => {
1455
- const skillField = `${fieldName}.skills[${skillIndex}]`;
1456
- const normalized = validateNonEmptyString(skillName, skillField);
1457
- if (!normalized)
1458
- return;
1459
- if (!PLUGIN_NAME_PATTERN.test(normalized)) {
1460
- error(`${skillField} must use lowercase kebab-case`);
1461
- }
1462
- else if (suiteSkills.has(normalized)) {
1463
- error(`${fieldName}.skills has duplicate Skill ${JSON.stringify(normalized)}`);
1464
- }
1465
- else {
1466
- suiteSkills.add(normalized);
1467
- }
1468
- });
1469
- }
1470
- if (skill && !suiteSkills.has(skill)) {
1471
- error(`${fieldName}.skills must include owner Skill ${JSON.stringify(skill)}`);
1472
- }
1473
- if (!Array.isArray(suite.profiles) || suite.profiles.length === 0) {
1474
- error(`${fieldName}.profiles must be a non-empty array`);
1475
- }
1476
- else {
1477
- suite.profiles.forEach((profileId, profileIndex) => {
1478
- const profileField = `${fieldName}.profiles[${profileIndex}]`;
1479
- if (typeof profileId !== 'string' || profileId.trim() === '') {
1480
- error(`${profileField} must be a non-empty string`);
1481
- return;
1482
- }
1483
- const profile = profilesById.get(profileId);
1484
- if (!profile) {
1485
- error(`${fieldName} references unknown profile ${JSON.stringify(profileId)}`);
1486
- }
1487
- else if (profile.runModel !== true) {
1488
- error(`${fieldName} cannot execute materialize-only profile ${JSON.stringify(profileId)}`);
1489
- }
1490
- if (profile) {
1491
- for (const skillName of suiteSkills) {
1492
- if (!profile.skillOwners.has(skillName)) {
1493
- error(`${fieldName} requires Skill ${JSON.stringify(skillName)}, but profile ` +
1494
- `${JSON.stringify(profileId)} does not install a plugin that declares it`);
1495
- }
1496
- }
1497
- }
1498
- });
1499
- }
1500
- if (!Number.isInteger(suite.defaultRuns) || suite.defaultRuns <= 0) {
1501
- error(`${fieldName}.defaultRuns must be a positive integer`);
1502
- }
1503
- if (!Number.isInteger(suite.perRunTimeoutMs) || suite.perRunTimeoutMs <= 0) {
1504
- error(`${fieldName}.perRunTimeoutMs must be a positive integer`);
1505
- }
1506
- if (typeof suite.requiredForRelease !== 'boolean') {
1507
- error(`${fieldName}.requiredForRelease must be boolean`);
1508
- }
1509
- if (!Array.isArray(suite.releaseSplits)) {
1510
- error(`${fieldName}.releaseSplits must be an array`);
1511
- }
1512
- else {
1513
- suite.releaseSplits.forEach((split, splitIndex) => {
1514
- if (!PLUGIN_EVAL_SPLITS.has(split)) {
1515
- error(`${fieldName}.releaseSplits[${splitIndex}] is unsupported`);
1516
- }
1517
- });
1518
- }
1519
- if (suite.kind === 'command') {
1520
- validateAllowedKeys(suite, fieldName, [
1521
- 'id', 'kind', 'skills', 'entry', 'cases', 'profiles', 'defaultRuns', 'releaseSplits',
1522
- 'requiredForRelease', 'perRunTimeoutMs', 'suiteTimeoutMs', 'supports',
1523
- ]);
1524
- validateEvalRelativeFile(evalDir, suite.entry, `${fieldName}.entry`);
1525
- if (!Number.isInteger(suite.suiteTimeoutMs) || suite.suiteTimeoutMs <= 0) {
1526
- error(`${fieldName}.suiteTimeoutMs must be a positive integer`);
1527
- }
1528
- else if (suite.suiteTimeoutMs < suite.perRunTimeoutMs) {
1529
- error(`${fieldName}.suiteTimeoutMs must be greater than or equal to perRunTimeoutMs`);
1530
- }
1531
- if (!Array.isArray(suite.supports)) {
1532
- error(`${fieldName}.supports must be an array`);
1533
- }
1534
- else {
1535
- suite.supports.forEach((support, supportIndex) => {
1536
- if (!PLUGIN_EVAL_COMMAND_SUPPORTS.has(support)) {
1537
- error(`${fieldName}.supports[${supportIndex}] is unsupported`);
1538
- }
1539
- });
1540
- if (Array.isArray(suite.releaseSplits) &&
1541
- suite.releaseSplits.length > 0 &&
1542
- !suite.supports.includes('split')) {
1543
- error(`${fieldName} declares releaseSplits but does not support split`);
1544
- }
1545
- const supportsCase = suite.supports.includes('case');
1546
- if (supportsCase && suite.cases === undefined) {
1547
- error(`${fieldName}.cases is required when supports includes case`);
1548
- }
1549
- else if (!supportsCase && suite.cases !== undefined) {
1550
- error(`${fieldName}.cases requires supports to include case`);
1551
- }
1552
- if (supportsCase && suite.cases !== undefined) {
1553
- const casesPath = validateEvalRelativeFile(evalDir, suite.cases, `${fieldName}.cases`);
1554
- if (casesPath) {
1555
- try {
1556
- const casesDocument = JSON.parse(fs.readFileSync(casesPath, 'utf8'));
1557
- if (!isRecord(casesDocument) || casesDocument.skill_name !== skill) {
1558
- error(`${fieldName}.cases.skill_name must match ${JSON.stringify(skill)}`);
1559
- }
1560
- else if (!Array.isArray(casesDocument.evals) || casesDocument.evals.length === 0) {
1561
- error(`${fieldName}.cases.evals must be a non-empty array`);
1562
- }
1563
- else {
1564
- const caseIds = new Set();
1565
- casesDocument.evals.forEach((entry, caseIndex) => {
1566
- const caseField = `${fieldName}.cases.evals[${caseIndex}]`;
1567
- if (!isRecord(entry) || typeof entry.id !== 'string' || !/^[a-z0-9_]+$/.test(entry.id)) {
1568
- error(`${caseField}.id must use lowercase snake_case`);
1569
- }
1570
- else if (caseIds.has(entry.id)) {
1571
- error(`${fieldName}.cases has duplicate case id ${JSON.stringify(entry.id)}`);
1572
- }
1573
- else {
1574
- caseIds.add(entry.id);
1575
- }
1576
- });
1577
- }
1578
- }
1579
- catch (cause) {
1580
- error(`${fieldName}.cases is not valid JSON: ${cause.message}`);
1581
- }
1582
- }
1583
- }
1584
- }
1585
- }
1586
- else if (suite.kind === 'conversation' || suite.kind === 'trigger') {
1587
- const normalizedSuite = { ...suite, skill };
1588
- const isolation = suite.isolation ?? 'standard';
1589
- if (isolation !== 'standard' && isolation !== 'strict') {
1590
- error(`${fieldName}.isolation must be standard or strict`);
1591
- }
1592
- if (suite.kind === 'conversation') {
1593
- validateAllowedKeys(suite, fieldName, [
1594
- 'id', 'kind', 'skills', 'cases', 'profiles', 'defaultRuns', 'releaseSplits',
1595
- 'requiredForRelease', 'perRunTimeoutMs', 'isolation',
1596
- ]);
1597
- if (Array.isArray(suite.releaseSplits) && suite.releaseSplits.length > 0) {
1598
- error(`${fieldName} cannot declare releaseSplits because conversation cases do not support split filtering`);
1599
- }
1600
- validateConversationCaseCorpus(evalDir, normalizedSuite, fieldName);
1601
- }
1602
- else {
1603
- validateAllowedKeys(suite, fieldName, [
1604
- 'id', 'kind', 'skills', 'cases', 'fixtureModule', 'observeSpawnAgent', 'isolation',
1605
- 'strictNegativeSplits', 'minimumPassRate', 'forbidMultipleSkillLoads',
1606
- 'profiles', 'defaultRuns', 'releaseSplits',
1607
- 'requiredForRelease', 'perRunTimeoutMs',
1608
- ]);
1609
- if (typeof suite.observeSpawnAgent !== 'boolean') {
1610
- error(`${fieldName}.observeSpawnAgent must be boolean`);
1611
- }
1612
- if (!Array.isArray(suite.strictNegativeSplits)) {
1613
- error(`${fieldName}.strictNegativeSplits must be an array`);
1614
- }
1615
- else {
1616
- suite.strictNegativeSplits.forEach((split, splitIndex) => {
1617
- if (!PLUGIN_EVAL_TRIGGER_CASE_SPLITS.has(split)) {
1618
- error(`${fieldName}.strictNegativeSplits[${splitIndex}] is unsupported`);
1619
- }
1620
- });
1621
- }
1622
- if (suite.minimumPassRate !== undefined &&
1623
- (typeof suite.minimumPassRate !== 'number' ||
1624
- !Number.isFinite(suite.minimumPassRate) ||
1625
- suite.minimumPassRate <= 0 ||
1626
- suite.minimumPassRate > 1)) {
1627
- error(`${fieldName}.minimumPassRate must be greater than 0 and at most 1`);
1628
- }
1629
- if (suite.forbidMultipleSkillLoads !== undefined &&
1630
- typeof suite.forbidMultipleSkillLoads !== 'boolean') {
1631
- error(`${fieldName}.forbidMultipleSkillLoads must be boolean`);
1632
- }
1633
- if (suite.fixtureModule !== undefined) {
1634
- const fixturePath = validateEvalRelativeFile(evalDir, suite.fixtureModule, `${fieldName}.fixtureModule`);
1635
- if (fixturePath && path.extname(fixturePath) !== '.mjs') {
1636
- error(`${fieldName}.fixtureModule must reference an .mjs file`);
1637
- }
1638
- }
1639
- validateTriggerCaseCorpus(evalDir, normalizedSuite, fieldName);
1640
- }
1641
- }
1642
- });
1643
- if (skill
1644
- && collectDeclaredSkillNames(pluginDir, pluginManifest).dynamic.has(skill)
1645
- && !manifest.suites.some((suite) => isRecord(suite) && suite.requiredForRelease === true)) {
1646
- error(`${manifestField}.suites must include at least one release-required suite for dynamic Skill ${JSON.stringify(skill)}`);
1647
- }
1648
959
  }
1649
- function validatePluginEvalManifest(pluginDir, pluginManifest) {
960
+ async function validatePluginEvalManifest(pluginDir, pluginManifest) {
1650
961
  const legacyRoot = path.join(pluginDir, 'evals');
1651
962
  if (fs.existsSync(legacyRoot)) {
1652
963
  error('Plugin-root evals/ is legacy; put evals/ inside its owning static or dynamic Skill directory.');
@@ -1655,17 +966,33 @@ function validatePluginEvalManifest(pluginDir, pluginManifest) {
1655
966
  .sort()
1656
967
  .map((skill) => ({ skill, root: path.join(pluginDir, 'skills', skill) }));
1657
968
  const seenSkills = new Set();
969
+ let manifestTools = null;
1658
970
  for (const owner of skillRoots) {
1659
971
  const evalDir = path.join(owner.root, 'evals');
1660
972
  const manifestPath = path.join(evalDir, 'manifest.json');
1661
973
  if (!fs.existsSync(manifestPath))
1662
974
  continue;
975
+ const manifestField = path.relative(pluginDir, manifestPath).split(path.sep).join('/');
1663
976
  if (seenSkills.has(owner.skill)) {
1664
977
  error(`Skill ${JSON.stringify(owner.skill)} has more than one evals/manifest.json owner`);
1665
978
  continue;
1666
979
  }
1667
980
  seenSkills.add(owner.skill);
1668
- validateOnePluginEvalManifest(pluginDir, pluginManifest, evalDir, owner.skill);
981
+ manifestTools ??= await loadSkillEvalManifestTools();
982
+ if (typeof manifestTools?.validateAwSkillEvalManifest !== 'function') {
983
+ error('Canonical AwSkillEvalManifest v1 validator is unavailable; run the current built aw CLI.');
984
+ continue;
985
+ }
986
+ const validation = await manifestTools.validateAwSkillEvalManifest({
987
+ plugin: {
988
+ rootDir: pluginDir,
989
+ manifestPath: path.join(pluginDir, '.agents-plugin', 'plugin.json'),
990
+ manifest: pluginManifest,
991
+ },
992
+ skill: owner.skill,
993
+ });
994
+ for (const message of validation.errors)
995
+ error(`${manifestField}: ${message}`);
1669
996
  }
1670
997
  }
1671
998
  function countCharacters(value) {
@@ -2058,33 +1385,6 @@ function validateDeclaredNativeAssets(pluginDir, manifest) {
2058
1385
  }
2059
1386
  }
2060
1387
  }
2061
- function validatePluginVersionContracts(manifest, options) {
2062
- if (manifest.compatibility === undefined) {
2063
- error('Invalid compatibility.aw.minVersion: expected a strict SemVer 2.0.0 string. Received undefined.');
2064
- return;
2065
- }
2066
- const compatibility = expectRecord(manifest.compatibility, 'compatibility');
2067
- if (!compatibility) {
2068
- return;
2069
- }
2070
- validateAllowedKeys(compatibility, 'compatibility', ['aw']);
2071
- if (compatibility.aw === undefined) {
2072
- error('Invalid compatibility.aw.minVersion: expected a strict SemVer 2.0.0 string. Received undefined.');
2073
- return;
2074
- }
2075
- const aw = expectRecord(compatibility.aw, 'compatibility.aw');
2076
- if (!aw) {
2077
- return;
2078
- }
2079
- validateAllowedKeys(aw, 'compatibility.aw', ['minVersion']);
2080
- const pluginMinVersion = validateStrictSemVerString(aw.minVersion, 'compatibility.aw.minVersion');
2081
- if (!pluginMinVersion || !options.catalogMinVersion) {
2082
- return;
2083
- }
2084
- if (compareStrictSemVer(pluginMinVersion, options.catalogMinVersion) > 0) {
2085
- error(`Invalid compatibility.aw.minVersion for plugin "${pluginNameForError(manifest)}": received ${JSON.stringify(pluginMinVersion)}, which is higher than target catalog minimum ${JSON.stringify(options.catalogMinVersion)}.`);
2086
- }
2087
- }
2088
1388
  function collectDeclaredSkillNames(pluginDir, manifest) {
2089
1389
  const skillsRoot = typeof manifest.skills === 'string'
2090
1390
  ? path.join(pluginDir, manifest.skills)
@@ -4130,8 +3430,6 @@ function printUsage() {
4130
3430
  aw plugin validate <plugin-directory> [options]
4131
3431
 
4132
3432
  Options:
4133
- --catalog-min-version <semver>
4134
- Validate compatibility.aw.minVersion against a target catalog.
4135
3433
  --strict-agent-skills Allow only Agent Skills portable core frontmatter.
4136
3434
  --claude-skill-profile <minimum|current>
4137
3435
  Validate Claude fields at AW minimum 2.1.88 (default) or current docs.
@@ -4201,7 +3499,27 @@ async function validatePluginDir(pluginDir, options) {
4201
3499
  }
4202
3500
  const skillValidationTools = await tryLoadCliSkillValidationTools();
4203
3501
  try {
4204
- await cliManifestTools.validateSourcePluginManifest(pluginDir, manifest);
3502
+ const normalizedManifest = await cliManifestTools.validateSourcePluginManifest(pluginDir, manifest);
3503
+ const requirements = await cliManifestTools.resolvePluginRequirements({
3504
+ pluginRoot: pluginDir,
3505
+ manifest: normalizedManifest,
3506
+ implementedCapabilities: cliManifestTools.implementedCapabilities,
3507
+ });
3508
+ if (requirements.unsupportedByCurrentAw.length > 0) {
3509
+ capabilityDiagnostic = {
3510
+ errorCode: 'awCapabilityUnsupported',
3511
+ missingCapabilities: requirements.unsupportedByCurrentAw,
3512
+ availableCapabilities: [...cliManifestTools.implementedCapabilities].sort(),
3513
+ };
3514
+ error(`[awCapabilityUnsupported] missingCapabilities=${JSON.stringify(requirements.unsupportedByCurrentAw)}`);
3515
+ }
3516
+ const satisfiedCapabilities = new Set([...requirements.declared, ...requirements.derived]);
3517
+ const advisoryObservations = requirements.observations.filter((observation) => (observation.code !== 'aw-command-detected'
3518
+ || observation.capability === undefined
3519
+ || !satisfiedCapabilities.has(observation.capability)));
3520
+ for (const observation of advisoryObservations) {
3521
+ warn(`[awCapabilityObservation] ${observation.path}: ${observation.message}`);
3522
+ }
4205
3523
  }
4206
3524
  catch (e) {
4207
3525
  error(e.message);
@@ -4212,8 +3530,7 @@ async function validatePluginDir(pluginDir, options) {
4212
3530
  validateNoBuildOutputDirs(pluginDir);
4213
3531
  validateDeclaredNativeAssets(pluginDir, manifest);
4214
3532
  validateCanonicalSkillLayout(pluginDir, manifest);
4215
- validatePluginVersionContracts(manifest, options);
4216
- validatePluginEvalManifest(pluginDir, manifest);
3533
+ await validatePluginEvalManifest(pluginDir, manifest);
4217
3534
  const artifactRenderEntry = validateScriptsLightweight(pluginDir, manifest);
4218
3535
  const runtimeImports = await resolveAuthorRuntimeImports({
4219
3536
  pluginDir,
@@ -4263,7 +3580,6 @@ function parseArgs(argv) {
4263
3580
  const args = argv.slice(2);
4264
3581
  const options = {
4265
3582
  pluginDir: null,
4266
- catalogMinVersion: null,
4267
3583
  strictAgentSkills: false,
4268
3584
  claudeSkillProfile: 'minimum',
4269
3585
  versionBase: 'HEAD',
@@ -4320,18 +3636,6 @@ function parseArgs(argv) {
4320
3636
  }
4321
3637
  exitCliError(`Unknown argument: ${arg}`, options.json);
4322
3638
  }
4323
- if (arg === '--catalog-min-version') {
4324
- const value = args[index + 1];
4325
- if (!value || value.startsWith('--')) {
4326
- exitCliError('--catalog-min-version requires a value.', options.json);
4327
- }
4328
- index += 1;
4329
- if (!STRICT_SEMVER_PATTERN.test(value)) {
4330
- exitCliError(`Invalid --catalog-min-version: expected a strict SemVer 2.0.0 string. Received ${JSON.stringify(value)}.`, options.json);
4331
- }
4332
- options.catalogMinVersion = value;
4333
- continue;
4334
- }
4335
3639
  exitCliError(`Unknown option: ${arg}`, options.json);
4336
3640
  }
4337
3641
  return options;
@@ -4363,7 +3667,6 @@ async function main() {
4363
3667
  const repoRoot = requestedWorkspaceRoot ?? discoverCanonicalRepoRoot(repoRootCandidate);
4364
3668
  const gitRoot = discoverCanonicalRepoRoot(findRepoRootCandidate(resolved));
4365
3669
  await validatePluginDir(resolved, {
4366
- catalogMinVersion: args.catalogMinVersion,
4367
3670
  strictAgentSkills: args.strictAgentSkills,
4368
3671
  claudeSkillProfile: args.claudeSkillProfile,
4369
3672
  versionBase: args.versionBase,
@@ -4377,9 +3680,12 @@ async function main() {
4377
3680
  profile: args.strictAgentSkills ? 'agent-skills-portable-core' : 'aw-source',
4378
3681
  claudeSkillProfile: args.claudeSkillProfile,
4379
3682
  pluginDirectory: resolved,
3683
+ workspaceRoot: process.env.AW_AUTHORING_WORKSPACE_ROOT ?? repoRoot,
3684
+ workspaceRootResolvedFrom: process.env.AW_AUTHORING_WORKSPACE_ROOT_RESOLVED_FROM ?? 'explicit',
4380
3685
  versionCheck: pluginVersionCheckResult,
4381
3686
  warnings,
4382
3687
  errors,
3688
+ ...(capabilityDiagnostic ?? {}),
4383
3689
  }, null, 2));
4384
3690
  if (errors.length > 0) {
4385
3691
  process.exit(1);