@lesliechan721/aw 0.1.0-beta.3

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 (429) hide show
  1. package/dist/authoring/assets/aw-config.d.mts +2 -0
  2. package/dist/authoring/assets/aw-config.mjs +556 -0
  3. package/dist/authoring/assets/aw-config.mjs.map +1 -0
  4. package/dist/authoring/scripts/add-skill.d.mts +2 -0
  5. package/dist/authoring/scripts/add-skill.mjs +355 -0
  6. package/dist/authoring/scripts/add-skill.mjs.map +1 -0
  7. package/dist/authoring/scripts/check-plugin-versions.d.mts +2 -0
  8. package/dist/authoring/scripts/check-plugin-versions.mjs +5 -0
  9. package/dist/authoring/scripts/check-plugin-versions.mjs.map +1 -0
  10. package/dist/authoring/scripts/init-plugin.d.mts +2 -0
  11. package/dist/authoring/scripts/init-plugin.mjs +512 -0
  12. package/dist/authoring/scripts/init-plugin.mjs.map +1 -0
  13. package/dist/authoring/scripts/lib/javascript-import-scanner.d.mts +4 -0
  14. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs +261 -0
  15. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs.map +1 -0
  16. package/dist/authoring/scripts/lib/plugin-root.d.mts +26 -0
  17. package/dist/authoring/scripts/lib/plugin-root.mjs +125 -0
  18. package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -0
  19. package/dist/authoring/scripts/lib/plugin-version-check.d.mts +55 -0
  20. package/dist/authoring/scripts/lib/plugin-version-check.mjs +777 -0
  21. package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -0
  22. package/dist/authoring/scripts/lib/semver.d.mts +9 -0
  23. package/dist/authoring/scripts/lib/semver.mjs +63 -0
  24. package/dist/authoring/scripts/lib/semver.mjs.map +1 -0
  25. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +124 -0
  26. package/dist/authoring/scripts/lib/skill-scaffold.mjs +374 -0
  27. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -0
  28. package/dist/authoring/scripts/plugin-status.d.mts +2 -0
  29. package/dist/authoring/scripts/plugin-status.mjs +96 -0
  30. package/dist/authoring/scripts/plugin-status.mjs.map +1 -0
  31. package/dist/authoring/scripts/validate-plugin.d.mts +2 -0
  32. package/dist/authoring/scripts/validate-plugin.mjs +4442 -0
  33. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -0
  34. package/dist/authoring/scripts/validate-skill.d.mts +2 -0
  35. package/dist/authoring/scripts/validate-skill.mjs +126 -0
  36. package/dist/authoring/scripts/validate-skill.mjs.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +8 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/scripts/aw-skill-eval-engine.d.ts +13 -0
  41. package/dist/scripts/aw-skill-eval-engine.js +31 -0
  42. package/dist/scripts/aw-skill-eval-engine.js.map +1 -0
  43. package/dist/scripts/bundle-plugins.d.ts +18 -0
  44. package/dist/scripts/bundle-plugins.js +123 -0
  45. package/dist/scripts/bundle-plugins.js.map +1 -0
  46. package/dist/scripts/codex-eval-app-server.d.ts +89 -0
  47. package/dist/scripts/codex-eval-app-server.js +1228 -0
  48. package/dist/scripts/codex-eval-app-server.js.map +1 -0
  49. package/dist/scripts/codex-eval-isolation.d.ts +61 -0
  50. package/dist/scripts/codex-eval-isolation.js +318 -0
  51. package/dist/scripts/codex-eval-isolation.js.map +1 -0
  52. package/dist/scripts/codex-eval-process-management.d.ts +8 -0
  53. package/dist/scripts/codex-eval-process-management.js +69 -0
  54. package/dist/scripts/codex-eval-process-management.js.map +1 -0
  55. package/dist/scripts/codex-eval-process-tree.d.ts +38 -0
  56. package/dist/scripts/codex-eval-process-tree.js +803 -0
  57. package/dist/scripts/codex-eval-process-tree.js.map +1 -0
  58. package/dist/scripts/codex-eval-runtime-config.d.ts +62 -0
  59. package/dist/scripts/codex-eval-runtime-config.js +843 -0
  60. package/dist/scripts/codex-eval-runtime-config.js.map +1 -0
  61. package/dist/scripts/codex-trigger-eval.d.ts +84 -0
  62. package/dist/scripts/codex-trigger-eval.js +968 -0
  63. package/dist/scripts/codex-trigger-eval.js.map +1 -0
  64. package/dist/scripts/eval-plugin-skills-audited.d.ts +6 -0
  65. package/dist/scripts/eval-plugin-skills-audited.js +261 -0
  66. package/dist/scripts/eval-plugin-skills-audited.js.map +1 -0
  67. package/dist/scripts/eval-plugin-skills.d.ts +45 -0
  68. package/dist/scripts/eval-plugin-skills.js +1586 -0
  69. package/dist/scripts/eval-plugin-skills.js.map +1 -0
  70. package/dist/scripts/eval-run-layout.d.ts +17 -0
  71. package/dist/scripts/eval-run-layout.js +26 -0
  72. package/dist/scripts/eval-run-layout.js.map +1 -0
  73. package/dist/scripts/plugin-eval-contract.d.ts +185 -0
  74. package/dist/scripts/plugin-eval-contract.js +695 -0
  75. package/dist/scripts/plugin-eval-contract.js.map +1 -0
  76. package/dist/scripts/plugin-eval-materializer.d.ts +13 -0
  77. package/dist/scripts/plugin-eval-materializer.js +421 -0
  78. package/dist/scripts/plugin-eval-materializer.js.map +1 -0
  79. package/dist/scripts/plugin-staging.d.ts +43 -0
  80. package/dist/scripts/plugin-staging.js +196 -0
  81. package/dist/scripts/plugin-staging.js.map +1 -0
  82. package/dist/scripts/skill-reporting.d.ts +212 -0
  83. package/dist/scripts/skill-reporting.js +922 -0
  84. package/dist/scripts/skill-reporting.js.map +1 -0
  85. package/dist/scripts/test-plugin-scripts.d.ts +7 -0
  86. package/dist/scripts/test-plugin-scripts.js +674 -0
  87. package/dist/scripts/test-plugin-scripts.js.map +1 -0
  88. package/dist/src/adapters/helpers.d.ts +44 -0
  89. package/dist/src/adapters/helpers.js +95 -0
  90. package/dist/src/adapters/helpers.js.map +1 -0
  91. package/dist/src/authoring/workspace-commands.d.ts +46 -0
  92. package/dist/src/authoring/workspace-commands.js +133 -0
  93. package/dist/src/authoring/workspace-commands.js.map +1 -0
  94. package/dist/src/commands/catalog-publish.d.ts +33 -0
  95. package/dist/src/commands/catalog-publish.js +374 -0
  96. package/dist/src/commands/catalog-publish.js.map +1 -0
  97. package/dist/src/commands/catalog-source.d.ts +111 -0
  98. package/dist/src/commands/catalog-source.js +266 -0
  99. package/dist/src/commands/catalog-source.js.map +1 -0
  100. package/dist/src/commands/console.d.ts +3 -0
  101. package/dist/src/commands/console.js +44 -0
  102. package/dist/src/commands/console.js.map +1 -0
  103. package/dist/src/commands/dependency-operation-plan.d.ts +28 -0
  104. package/dist/src/commands/dependency-operation-plan.js +15 -0
  105. package/dist/src/commands/dependency-operation-plan.js.map +1 -0
  106. package/dist/src/commands/init.d.ts +31 -0
  107. package/dist/src/commands/init.js +63 -0
  108. package/dist/src/commands/init.js.map +1 -0
  109. package/dist/src/commands/options.d.ts +68 -0
  110. package/dist/src/commands/options.js +146 -0
  111. package/dist/src/commands/options.js.map +1 -0
  112. package/dist/src/commands/rebuild-command.d.ts +77 -0
  113. package/dist/src/commands/rebuild-command.js +1681 -0
  114. package/dist/src/commands/rebuild-command.js.map +1 -0
  115. package/dist/src/commands/rebuild-integration.d.ts +94 -0
  116. package/dist/src/commands/rebuild-integration.js +3289 -0
  117. package/dist/src/commands/rebuild-integration.js.map +1 -0
  118. package/dist/src/commands/rebuild-operations.d.ts +110 -0
  119. package/dist/src/commands/rebuild-operations.js +791 -0
  120. package/dist/src/commands/rebuild-operations.js.map +1 -0
  121. package/dist/src/commands/review-publication.d.ts +99 -0
  122. package/dist/src/commands/review-publication.js +904 -0
  123. package/dist/src/commands/review-publication.js.map +1 -0
  124. package/dist/src/commands/runtime.d.ts +176 -0
  125. package/dist/src/commands/runtime.js +746 -0
  126. package/dist/src/commands/runtime.js.map +1 -0
  127. package/dist/src/commands/status-v4.d.ts +102 -0
  128. package/dist/src/commands/status-v4.js +844 -0
  129. package/dist/src/commands/status-v4.js.map +1 -0
  130. package/dist/src/commands/status.d.ts +93 -0
  131. package/dist/src/commands/status.js +442 -0
  132. package/dist/src/commands/status.js.map +1 -0
  133. package/dist/src/commands/wizard.d.ts +57 -0
  134. package/dist/src/commands/wizard.js +58 -0
  135. package/dist/src/commands/wizard.js.map +1 -0
  136. package/dist/src/commands/write-commands.d.ts +7 -0
  137. package/dist/src/commands/write-commands.js +167 -0
  138. package/dist/src/commands/write-commands.js.map +1 -0
  139. package/dist/src/constants.d.ts +25 -0
  140. package/dist/src/constants.js +26 -0
  141. package/dist/src/constants.js.map +1 -0
  142. package/dist/src/generators/agents.d.ts +3 -0
  143. package/dist/src/generators/agents.js +46 -0
  144. package/dist/src/generators/agents.js.map +1 -0
  145. package/dist/src/generators/hooks.d.ts +15 -0
  146. package/dist/src/generators/hooks.js +76 -0
  147. package/dist/src/generators/hooks.js.map +1 -0
  148. package/dist/src/generators/instructions.d.ts +13 -0
  149. package/dist/src/generators/instructions.js +66 -0
  150. package/dist/src/generators/instructions.js.map +1 -0
  151. package/dist/src/generators/local-plugin.d.ts +53 -0
  152. package/dist/src/generators/local-plugin.js +1268 -0
  153. package/dist/src/generators/local-plugin.js.map +1 -0
  154. package/dist/src/generators/permissions.d.ts +10 -0
  155. package/dist/src/generators/permissions.js +37 -0
  156. package/dist/src/generators/permissions.js.map +1 -0
  157. package/dist/src/generators/shared.d.ts +2 -0
  158. package/dist/src/generators/shared.js +15 -0
  159. package/dist/src/generators/shared.js.map +1 -0
  160. package/dist/src/index.d.ts +35 -0
  161. package/dist/src/index.js +2344 -0
  162. package/dist/src/index.js.map +1 -0
  163. package/dist/src/output/command-receipt.d.ts +90 -0
  164. package/dist/src/output/command-receipt.js +129 -0
  165. package/dist/src/output/command-receipt.js.map +1 -0
  166. package/dist/src/output/debug-log.d.ts +4 -0
  167. package/dist/src/output/debug-log.js +97 -0
  168. package/dist/src/output/debug-log.js.map +1 -0
  169. package/dist/src/output/equivalent-command.d.ts +9 -0
  170. package/dist/src/output/equivalent-command.js +39 -0
  171. package/dist/src/output/equivalent-command.js.map +1 -0
  172. package/dist/src/output/model.d.ts +117 -0
  173. package/dist/src/output/model.js +145 -0
  174. package/dist/src/output/model.js.map +1 -0
  175. package/dist/src/output/rebuild-progress.d.ts +21 -0
  176. package/dist/src/output/rebuild-progress.js +138 -0
  177. package/dist/src/output/rebuild-progress.js.map +1 -0
  178. package/dist/src/output/redact.d.ts +3 -0
  179. package/dist/src/output/redact.js +39 -0
  180. package/dist/src/output/redact.js.map +1 -0
  181. package/dist/src/output/reporter.d.ts +9 -0
  182. package/dist/src/output/reporter.js +133 -0
  183. package/dist/src/output/reporter.js.map +1 -0
  184. package/dist/src/portable/commands.d.ts +120 -0
  185. package/dist/src/portable/commands.js +506 -0
  186. package/dist/src/portable/commands.js.map +1 -0
  187. package/dist/src/portable/materializer.d.ts +50 -0
  188. package/dist/src/portable/materializer.js +408 -0
  189. package/dist/src/portable/materializer.js.map +1 -0
  190. package/dist/src/portable/skills-cli.d.ts +43 -0
  191. package/dist/src/portable/skills-cli.js +148 -0
  192. package/dist/src/portable/skills-cli.js.map +1 -0
  193. package/dist/src/tui/components.d.ts +32 -0
  194. package/dist/src/tui/components.js +42 -0
  195. package/dist/src/tui/components.js.map +1 -0
  196. package/dist/src/tui/console-app-v4.d.ts +20 -0
  197. package/dist/src/tui/console-app-v4.js +2613 -0
  198. package/dist/src/tui/console-app-v4.js.map +1 -0
  199. package/dist/src/tui/controller-runtime.d.ts +11 -0
  200. package/dist/src/tui/controller-runtime.js +902 -0
  201. package/dist/src/tui/controller-runtime.js.map +1 -0
  202. package/dist/src/tui/controller.d.ts +367 -0
  203. package/dist/src/tui/controller.js +1724 -0
  204. package/dist/src/tui/controller.js.map +1 -0
  205. package/dist/src/tui/index.d.ts +13 -0
  206. package/dist/src/tui/index.js +14 -0
  207. package/dist/src/tui/index.js.map +1 -0
  208. package/dist/src/tui/keys.d.ts +12 -0
  209. package/dist/src/tui/keys.js +22 -0
  210. package/dist/src/tui/keys.js.map +1 -0
  211. package/dist/src/tui/layout.d.ts +12 -0
  212. package/dist/src/tui/layout.js +19 -0
  213. package/dist/src/tui/layout.js.map +1 -0
  214. package/dist/src/tui/model.d.ts +279 -0
  215. package/dist/src/tui/model.js +652 -0
  216. package/dist/src/tui/model.js.map +1 -0
  217. package/dist/src/tui/prompt.d.ts +8 -0
  218. package/dist/src/tui/prompt.js +242 -0
  219. package/dist/src/tui/prompt.js.map +1 -0
  220. package/dist/src/tui/router.d.ts +153 -0
  221. package/dist/src/tui/router.js +102 -0
  222. package/dist/src/tui/router.js.map +1 -0
  223. package/dist/src/tui/runner.d.ts +11 -0
  224. package/dist/src/tui/runner.js +71 -0
  225. package/dist/src/tui/runner.js.map +1 -0
  226. package/dist/src/tui/theme.d.ts +18 -0
  227. package/dist/src/tui/theme.js +20 -0
  228. package/dist/src/tui/theme.js.map +1 -0
  229. package/dist/src/tui/views.d.ts +57 -0
  230. package/dist/src/tui/views.js +173 -0
  231. package/dist/src/tui/views.js.map +1 -0
  232. package/dist/src/tui/wizard.d.ts +11 -0
  233. package/dist/src/tui/wizard.js +321 -0
  234. package/dist/src/tui/wizard.js.map +1 -0
  235. package/dist/src/types.d.ts +313 -0
  236. package/dist/src/types.js +33 -0
  237. package/dist/src/types.js.map +1 -0
  238. package/dist/src/utils/active-marketplace-runtime-lock.d.ts +12 -0
  239. package/dist/src/utils/active-marketplace-runtime-lock.js +133 -0
  240. package/dist/src/utils/active-marketplace-runtime-lock.js.map +1 -0
  241. package/dist/src/utils/agent-version.d.ts +13 -0
  242. package/dist/src/utils/agent-version.js +172 -0
  243. package/dist/src/utils/agent-version.js.map +1 -0
  244. package/dist/src/utils/artifact-plan.d.ts +26 -0
  245. package/dist/src/utils/artifact-plan.js +444 -0
  246. package/dist/src/utils/artifact-plan.js.map +1 -0
  247. package/dist/src/utils/artifact-renderer.d.ts +124 -0
  248. package/dist/src/utils/artifact-renderer.js +442 -0
  249. package/dist/src/utils/artifact-renderer.js.map +1 -0
  250. package/dist/src/utils/artifact-sources.d.ts +8 -0
  251. package/dist/src/utils/artifact-sources.js +10 -0
  252. package/dist/src/utils/artifact-sources.js.map +1 -0
  253. package/dist/src/utils/aw-home-mutation-lock.d.ts +10 -0
  254. package/dist/src/utils/aw-home-mutation-lock.js +55 -0
  255. package/dist/src/utils/aw-home-mutation-lock.js.map +1 -0
  256. package/dist/src/utils/bundle-integrity.d.ts +3 -0
  257. package/dist/src/utils/bundle-integrity.js +88 -0
  258. package/dist/src/utils/bundle-integrity.js.map +1 -0
  259. package/dist/src/utils/bundle-layout.d.ts +4 -0
  260. package/dist/src/utils/bundle-layout.js +546 -0
  261. package/dist/src/utils/bundle-layout.js.map +1 -0
  262. package/dist/src/utils/catalog-digests.d.ts +8 -0
  263. package/dist/src/utils/catalog-digests.js +108 -0
  264. package/dist/src/utils/catalog-digests.js.map +1 -0
  265. package/dist/src/utils/catalog-manifest-v3.d.ts +2 -0
  266. package/dist/src/utils/catalog-manifest-v3.js +3 -0
  267. package/dist/src/utils/catalog-manifest-v3.js.map +1 -0
  268. package/dist/src/utils/catalog-manifest-v4.d.ts +5 -0
  269. package/dist/src/utils/catalog-manifest-v4.js +106 -0
  270. package/dist/src/utils/catalog-manifest-v4.js.map +1 -0
  271. package/dist/src/utils/catalog-public-error.d.ts +15 -0
  272. package/dist/src/utils/catalog-public-error.js +84 -0
  273. package/dist/src/utils/catalog-public-error.js.map +1 -0
  274. package/dist/src/utils/catalog-runtime-projection.d.ts +36 -0
  275. package/dist/src/utils/catalog-runtime-projection.js +172 -0
  276. package/dist/src/utils/catalog-runtime-projection.js.map +1 -0
  277. package/dist/src/utils/catalog-snapshot.d.ts +8 -0
  278. package/dist/src/utils/catalog-snapshot.js +12 -0
  279. package/dist/src/utils/catalog-snapshot.js.map +1 -0
  280. package/dist/src/utils/catalog-source-cache.d.ts +61 -0
  281. package/dist/src/utils/catalog-source-cache.js +276 -0
  282. package/dist/src/utils/catalog-source-cache.js.map +1 -0
  283. package/dist/src/utils/catalog-source-identity.d.ts +4 -0
  284. package/dist/src/utils/catalog-source-identity.js +118 -0
  285. package/dist/src/utils/catalog-source-identity.js.map +1 -0
  286. package/dist/src/utils/catalog-source-presentation.d.ts +1 -0
  287. package/dist/src/utils/catalog-source-presentation.js +32 -0
  288. package/dist/src/utils/catalog-source-presentation.js.map +1 -0
  289. package/dist/src/utils/catalog-source-references.d.ts +65 -0
  290. package/dist/src/utils/catalog-source-references.js +1418 -0
  291. package/dist/src/utils/catalog-source-references.js.map +1 -0
  292. package/dist/src/utils/catalog-sources.d.ts +39 -0
  293. package/dist/src/utils/catalog-sources.js +293 -0
  294. package/dist/src/utils/catalog-sources.js.map +1 -0
  295. package/dist/src/utils/codex-config.d.ts +124 -0
  296. package/dist/src/utils/codex-config.js +1011 -0
  297. package/dist/src/utils/codex-config.js.map +1 -0
  298. package/dist/src/utils/codex-project-surface.d.ts +3 -0
  299. package/dist/src/utils/codex-project-surface.js +49 -0
  300. package/dist/src/utils/codex-project-surface.js.map +1 -0
  301. package/dist/src/utils/codex-roles.d.ts +71 -0
  302. package/dist/src/utils/codex-roles.js +257 -0
  303. package/dist/src/utils/codex-roles.js.map +1 -0
  304. package/dist/src/utils/codex-skill-staging.d.ts +9 -0
  305. package/dist/src/utils/codex-skill-staging.js +8 -0
  306. package/dist/src/utils/codex-skill-staging.js.map +1 -0
  307. package/dist/src/utils/config-value.d.ts +3 -0
  308. package/dist/src/utils/config-value.js +23 -0
  309. package/dist/src/utils/config-value.js.map +1 -0
  310. package/dist/src/utils/dynamic-skill-tree.d.ts +32 -0
  311. package/dist/src/utils/dynamic-skill-tree.js +436 -0
  312. package/dist/src/utils/dynamic-skill-tree.js.map +1 -0
  313. package/dist/src/utils/file-rules.d.ts +1 -0
  314. package/dist/src/utils/file-rules.js +2 -0
  315. package/dist/src/utils/file-rules.js.map +1 -0
  316. package/dist/src/utils/git-catalog-provider.d.ts +7 -0
  317. package/dist/src/utils/git-catalog-provider.js +510 -0
  318. package/dist/src/utils/git-catalog-provider.js.map +1 -0
  319. package/dist/src/utils/hooks-contract.d.ts +1 -0
  320. package/dist/src/utils/hooks-contract.js +2 -0
  321. package/dist/src/utils/hooks-contract.js.map +1 -0
  322. package/dist/src/utils/json.d.ts +4 -0
  323. package/dist/src/utils/json.js +29 -0
  324. package/dist/src/utils/json.js.map +1 -0
  325. package/dist/src/utils/lifecycle-active-store.d.ts +175 -0
  326. package/dist/src/utils/lifecycle-active-store.js +1276 -0
  327. package/dist/src/utils/lifecycle-active-store.js.map +1 -0
  328. package/dist/src/utils/local-marketplace.d.ts +41 -0
  329. package/dist/src/utils/local-marketplace.js +317 -0
  330. package/dist/src/utils/local-marketplace.js.map +1 -0
  331. package/dist/src/utils/manifest.d.ts +14 -0
  332. package/dist/src/utils/manifest.js +36 -0
  333. package/dist/src/utils/manifest.js.map +1 -0
  334. package/dist/src/utils/marketplace.d.ts +3 -0
  335. package/dist/src/utils/marketplace.js +76 -0
  336. package/dist/src/utils/marketplace.js.map +1 -0
  337. package/dist/src/utils/multi-source-catalog.d.ts +72 -0
  338. package/dist/src/utils/multi-source-catalog.js +402 -0
  339. package/dist/src/utils/multi-source-catalog.js.map +1 -0
  340. package/dist/src/utils/native-cli.d.ts +75 -0
  341. package/dist/src/utils/native-cli.js +435 -0
  342. package/dist/src/utils/native-cli.js.map +1 -0
  343. package/dist/src/utils/orphan-marketplace-cleanup.d.ts +18 -0
  344. package/dist/src/utils/orphan-marketplace-cleanup.js +202 -0
  345. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -0
  346. package/dist/src/utils/ownership.d.ts +130 -0
  347. package/dist/src/utils/ownership.js +766 -0
  348. package/dist/src/utils/ownership.js.map +1 -0
  349. package/dist/src/utils/path-catalog-provider.d.ts +7 -0
  350. package/dist/src/utils/path-catalog-provider.js +87 -0
  351. package/dist/src/utils/path-catalog-provider.js.map +1 -0
  352. package/dist/src/utils/paths.d.ts +41 -0
  353. package/dist/src/utils/paths.js +138 -0
  354. package/dist/src/utils/paths.js.map +1 -0
  355. package/dist/src/utils/platform-entries.d.ts +1 -0
  356. package/dist/src/utils/platform-entries.js +2 -0
  357. package/dist/src/utils/platform-entries.js.map +1 -0
  358. package/dist/src/utils/platform-support.d.ts +1 -0
  359. package/dist/src/utils/platform-support.js +2 -0
  360. package/dist/src/utils/platform-support.js.map +1 -0
  361. package/dist/src/utils/plugin-authoring-capabilities.d.ts +23 -0
  362. package/dist/src/utils/plugin-authoring-capabilities.js +37 -0
  363. package/dist/src/utils/plugin-authoring-capabilities.js.map +1 -0
  364. package/dist/src/utils/plugin-authoring-capabilities.json +92 -0
  365. package/dist/src/utils/plugin-config-write.d.ts +107 -0
  366. package/dist/src/utils/plugin-config-write.js +565 -0
  367. package/dist/src/utils/plugin-config-write.js.map +1 -0
  368. package/dist/src/utils/plugin-config.d.ts +396 -0
  369. package/dist/src/utils/plugin-config.js +1898 -0
  370. package/dist/src/utils/plugin-config.js.map +1 -0
  371. package/dist/src/utils/plugin-dependencies.d.ts +12 -0
  372. package/dist/src/utils/plugin-dependencies.js +162 -0
  373. package/dist/src/utils/plugin-dependencies.js.map +1 -0
  374. package/dist/src/utils/plugin-release.d.ts +2 -0
  375. package/dist/src/utils/plugin-release.js +2 -0
  376. package/dist/src/utils/plugin-release.js.map +1 -0
  377. package/dist/src/utils/plugin-script-contract.d.ts +1 -0
  378. package/dist/src/utils/plugin-script-contract.js +2 -0
  379. package/dist/src/utils/plugin-script-contract.js.map +1 -0
  380. package/dist/src/utils/plugin-scripts.d.ts +172 -0
  381. package/dist/src/utils/plugin-scripts.js +585 -0
  382. package/dist/src/utils/plugin-scripts.js.map +1 -0
  383. package/dist/src/utils/process-lock.d.ts +47 -0
  384. package/dist/src/utils/process-lock.js +532 -0
  385. package/dist/src/utils/process-lock.js.map +1 -0
  386. package/dist/src/utils/process-tree.d.ts +2 -0
  387. package/dist/src/utils/process-tree.js +2 -0
  388. package/dist/src/utils/process-tree.js.map +1 -0
  389. package/dist/src/utils/project-boundary.d.ts +21 -0
  390. package/dist/src/utils/project-boundary.js +95 -0
  391. package/dist/src/utils/project-boundary.js.map +1 -0
  392. package/dist/src/utils/rendered-contract.d.ts +8 -0
  393. package/dist/src/utils/rendered-contract.js +134 -0
  394. package/dist/src/utils/rendered-contract.js.map +1 -0
  395. package/dist/src/utils/runtime-skill-closure.d.ts +13 -0
  396. package/dist/src/utils/runtime-skill-closure.js +863 -0
  397. package/dist/src/utils/runtime-skill-closure.js.map +1 -0
  398. package/dist/src/utils/skill-authoring.d.ts +1 -0
  399. package/dist/src/utils/skill-authoring.js +2 -0
  400. package/dist/src/utils/skill-authoring.js.map +1 -0
  401. package/dist/src/utils/skill-frontmatter-capabilities.d.ts +201 -0
  402. package/dist/src/utils/skill-frontmatter-capabilities.js +5 -0
  403. package/dist/src/utils/skill-frontmatter-capabilities.js.map +1 -0
  404. package/dist/src/utils/skill-frontmatter-capabilities.json +200 -0
  405. package/dist/src/utils/skill-validation.d.ts +37 -0
  406. package/dist/src/utils/skill-validation.js +326 -0
  407. package/dist/src/utils/skill-validation.js.map +1 -0
  408. package/dist/src/utils/slash-commands.d.ts +1 -0
  409. package/dist/src/utils/slash-commands.js +2 -0
  410. package/dist/src/utils/slash-commands.js.map +1 -0
  411. package/dist/src/utils/state-paths.d.ts +13 -0
  412. package/dist/src/utils/state-paths.js +129 -0
  413. package/dist/src/utils/state-paths.js.map +1 -0
  414. package/dist/src/utils/target-eligibility.d.ts +7 -0
  415. package/dist/src/utils/target-eligibility.js +26 -0
  416. package/dist/src/utils/target-eligibility.js.map +1 -0
  417. package/dist/src/utils/target-order.d.ts +7 -0
  418. package/dist/src/utils/target-order.js +10 -0
  419. package/dist/src/utils/target-order.js.map +1 -0
  420. package/dist/src/utils/template-engine.d.ts +1 -0
  421. package/dist/src/utils/template-engine.js +2 -0
  422. package/dist/src/utils/template-engine.js.map +1 -0
  423. package/dist/src/utils/test-path-fence.d.ts +12 -0
  424. package/dist/src/utils/test-path-fence.js +31 -0
  425. package/dist/src/utils/test-path-fence.js.map +1 -0
  426. package/dist/vitest.config.d.ts +2 -0
  427. package/dist/vitest.config.js +16 -0
  428. package/dist/vitest.config.js.map +1 -0
  429. package/package.json +61 -0
@@ -0,0 +1,2344 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawn } from 'node:child_process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Command, CommanderError, Option } from 'commander';
7
+ import { initCommand } from './commands/init.js';
8
+ import { addCatalogSourceCommand, explicitRefPolicy, listCatalogSources, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from './commands/catalog-source.js';
9
+ import { cleanupWriteCommand as cleanupCommand, installWriteCommand as installCommand, reinstallWriteCommand as reinstallCommand, uninstallWriteCommand as uninstallCommand, upgradeWriteCommand as upgradeCommand, } from './commands/write-commands.js';
10
+ import { formatInteractiveConsoleUnavailableMessage, runConsoleController, } from './commands/console.js';
11
+ import { runCommandWizard, toWizardCandidates, WizardExecutionError, } from './commands/wizard.js';
12
+ import { createCliExecutionContext, emitCommandEvent, } from './commands/runtime.js';
13
+ import { loadConsoleItemsResult } from './commands/status.js';
14
+ import { statusCommandV4 } from './commands/status-v4.js';
15
+ import { normalizeUninstallCommandOptions, normalizeCleanupCommandOptions, resolveConfigReadResolution, resolveConfigProjectLayer, resolveConfigWriteScope, normalizeInstallCommandOptions, normalizeReinstallCommandOptions, normalizeUpgradeCommandOptions, } from './commands/options.js';
16
+ import { isCommandWarningError, } from './types.js';
17
+ import { formatWarnings } from './output/reporter.js';
18
+ import { redactString, redactValue } from './output/redact.js';
19
+ import { renderShellCommand, } from './output/equivalent-command.js';
20
+ import { buildRebuildReceiptJson, buildInitReceiptJson, renderRebuildReceipt, renderInitReceipt, } from './output/command-receipt.js';
21
+ import { resolveCliPackageRoot } from './utils/paths.js';
22
+ import { coercePluginConfigUpdates, findConfigFieldEntry, listNamespacedPluginConfigStores, listPluginConfigStorePluginNames, readPluginConfigStore, renderPluginConfigValueForDisplay, resolveConfigRead, } from './utils/plugin-config.js';
23
+ import { applyPluginConfigWrite, describeResetAffectedFields, resetPluginConfigWithHelper, } from './utils/plugin-config-write.js';
24
+ import { assertStrictSemVer } from './utils/manifest.js';
25
+ import { writeCandidateEligibility } from './utils/target-eligibility.js';
26
+ import { assertCatalogSourceReferencesSupported, inventoryLegacyConfigReferences, } from './utils/catalog-source-references.js';
27
+ import { parsePluginId, withResolvedCatalogPlugin, withResolvedMultiSourceCatalog, } from './utils/multi-source-catalog.js';
28
+ import { sanitizeCatalogSourceError } from './utils/catalog-public-error.js';
29
+ import { formatConfigCommandValue, parseConfigValue, } from './utils/config-value.js';
30
+ import { withAwHomeMutationLock, } from './utils/aw-home-mutation-lock.js';
31
+ import { installPortableSkills, materializePortableSkillsToDirectory, PortableCommandError, renderPortableReview, } from './portable/commands.js';
32
+ import { SkillsCliError } from './portable/skills-cli.js';
33
+ import { computeReviewComponentDigest, listReviewRecords, parseReviewAttachment, publishReviewRecord, showReviewRecord, verifyReviewRecord, } from './commands/review-publication.js';
34
+ import { resolveRepoRoot } from './utils/state-paths.js';
35
+ import { runCatalogBuildCommand, runCatalogInitCommand, runCatalogValidateCommand, runCatalogVersionCommand, runPluginBuildCommand, runPluginTestCommand, } from './authoring/workspace-commands.js';
36
+ import { runCatalogPublishCommand } from './commands/catalog-publish.js';
37
+ function createDefaultIo() {
38
+ return {
39
+ stdout: (text) => process.stdout.write(text),
40
+ stderr: (text) => process.stderr.write(text),
41
+ };
42
+ }
43
+ function writeLine(write, line) {
44
+ write(`${line}\n`);
45
+ }
46
+ function writeWarnings(write, warnings, options = {}) {
47
+ for (const warning of formatWarnings(warnings, options)) {
48
+ writeLine(write, warning);
49
+ }
50
+ }
51
+ function resolveCliVersion() {
52
+ const packageJsonPath = path.join(resolveCliPackageRoot(), 'package.json');
53
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
54
+ return assertStrictSemVer(packageJson.version, 'packages/cli/package.json version');
55
+ }
56
+ function resolveCommandReceiptExitCode(result) {
57
+ if (result.overallState === 'failed') {
58
+ return 1;
59
+ }
60
+ return 0;
61
+ }
62
+ async function runAuthoringScript(options) {
63
+ const scriptPath = path.join(resolveCliPackageRoot(), 'dist', 'authoring', 'scripts', options.scriptName);
64
+ return new Promise((resolve, reject) => {
65
+ const child = spawn(process.execPath, [scriptPath, ...options.args], {
66
+ cwd: options.cwd,
67
+ env: options.env,
68
+ stdio: ['ignore', 'pipe', 'pipe'],
69
+ });
70
+ child.stdout.on('data', (chunk) => options.io.stdout(String(chunk)));
71
+ child.stderr.on('data', (chunk) => options.io.stderr(String(chunk)));
72
+ child.once('error', reject);
73
+ child.once('close', (code, signal) => {
74
+ if (signal) {
75
+ reject(new Error(`Plugin authoring command terminated by signal ${signal}.`));
76
+ return;
77
+ }
78
+ resolve(code ?? 1);
79
+ });
80
+ });
81
+ }
82
+ function toCliDiagnosticsOptions(commandName, rawOptions, runtimeDiagnostics) {
83
+ return {
84
+ ...runtimeDiagnostics,
85
+ commandName,
86
+ verbose: runtimeDiagnostics?.verbose === true || rawOptions.verbose === true,
87
+ debug: runtimeDiagnostics?.debug === true || rawOptions.debug === true,
88
+ logFile: rawOptions.logFile ?? runtimeDiagnostics?.logFile,
89
+ };
90
+ }
91
+ function isWizardAvailable(context, rawOptions) {
92
+ return context.interactive && context.isTty && !context.isCi && rawOptions.json !== true;
93
+ }
94
+ function shellCommand(tokens) {
95
+ return renderShellCommand(tokens, 'posix');
96
+ }
97
+ function optionTokens(flag, value) {
98
+ return value === undefined ? [] : [flag, value];
99
+ }
100
+ function writeCommandUsage(command) {
101
+ const cardinality = command === 'reinstall' || command === 'cleanup' ? '<plugin>' : '<plugin...>';
102
+ const scope = command === 'cleanup' ? ' --scope <project|user>' : ' [--scope <project|user>]';
103
+ const all = command === 'upgrade' ? ' 或 aw upgrade --all --platform both --scope user' : '';
104
+ return [
105
+ `${command} 命令缺少必要参数。`,
106
+ `Usage: aw ${command} ${cardinality} --platform <codex|claude|both>${scope}`,
107
+ `Example: aw ${command} example-plugin --platform codex --scope user${all}`,
108
+ ].join('\n');
109
+ }
110
+ function configCommandUsage(command) {
111
+ const argumentsByCommand = {
112
+ list: '<plugin>',
113
+ get: '<plugin> [key]',
114
+ set: '<plugin> <key> <value>',
115
+ unset: '<plugin> <key>',
116
+ reset: '<plugin> --scope <project|user> --yes',
117
+ };
118
+ return [
119
+ `config ${command} 命令缺少必要参数。`,
120
+ `Usage: aw config ${command} ${argumentsByCommand[command]}`,
121
+ `Example: aw config ${command} example-plugin${command === 'set' ? ' key value' : command === 'unset' ? ' key' : command === 'reset' ? ' --scope user --yes' : ''}`,
122
+ ].join('\n');
123
+ }
124
+ function assertUpgradeAllConflict(pluginNames, all) {
125
+ if (all && pluginNames.length > 0) {
126
+ throw new Error('upgrade 命令不能同时使用插件名和 `--all`。');
127
+ }
128
+ }
129
+ function equivalentWriteCommand(command, selection, rawOptions) {
130
+ return shellCommand(buildEquivalentWriteCommandTokens(command, selection, rawOptions));
131
+ }
132
+ export function buildEquivalentWriteCommandTokens(command, selection, rawOptions) {
133
+ const all = command === 'upgrade' && rawOptions.all === true;
134
+ return [
135
+ 'aw',
136
+ command,
137
+ ...(all ? ['--all'] : []),
138
+ '--platform',
139
+ selection.platform ?? 'both',
140
+ '--scope',
141
+ selection.scope ?? 'user',
142
+ ...(command === 'cleanup' ? [] : optionTokens('--script-timeout', rawOptions.scriptTimeout)),
143
+ ...(!all && selection.plugins.length > 0 ? ['--', ...selection.plugins] : []),
144
+ ];
145
+ }
146
+ function equivalentConfigCommand(options) {
147
+ return shellCommand(buildEquivalentConfigCommandTokens(options));
148
+ }
149
+ function equivalentConfigCommandProjection(resolve) {
150
+ return {
151
+ equivalentCommand: (selection) => equivalentConfigCommand(resolve(selection)),
152
+ equivalentCommandTokens: (selection) => buildEquivalentConfigCommandTokens(resolve(selection)),
153
+ };
154
+ }
155
+ function configSetEquivalentOptions(selection, candidates, rawOptions) {
156
+ const field = candidates.find((entry) => entry.pluginName === selection.plugins[0])
157
+ ?.configSchema?.[selection.key ?? ''];
158
+ const placeholder = configFieldPlaceholder(field);
159
+ return {
160
+ command: 'set',
161
+ plugin: selection.plugins[0],
162
+ key: selection.key,
163
+ value: placeholder
164
+ ? rawOptions.valueJson ? JSON.stringify(placeholder) : placeholder
165
+ : formatConfigCommandValue(selection.value, rawOptions.valueJson === true),
166
+ scope: selection.scope ?? 'user',
167
+ projectLayer: selection.projectLayer,
168
+ valueJson: rawOptions.valueJson,
169
+ };
170
+ }
171
+ function configFieldPlaceholder(field) {
172
+ if (field?.sensitive)
173
+ return '<sensitive-value>';
174
+ if (field?.type === 'file')
175
+ return '<file-path>';
176
+ if (field?.type === 'directory')
177
+ return '<directory-path>';
178
+ return undefined;
179
+ }
180
+ export function buildEquivalentConfigCommandTokens(options) {
181
+ return [
182
+ 'aw',
183
+ 'config',
184
+ options.command,
185
+ ...optionTokens('--scope', options.scope),
186
+ ...(options.projectLayer === 'local' ? ['--local'] : []),
187
+ ...(options.valueJson ? ['--value-json'] : []),
188
+ ...(options.confirmed ? ['--yes'] : []),
189
+ '--',
190
+ options.plugin,
191
+ ...(options.key === undefined ? [] : [options.key]),
192
+ ...(options.value === undefined ? [] : [options.value]),
193
+ ];
194
+ }
195
+ function hasSelectableWriteCandidate(command, candidates, selection, options) {
196
+ const platforms = options.missingPlatform
197
+ ? ['codex', 'claude', 'both']
198
+ : [selection.platform ?? 'both'];
199
+ const scopes = options.missingScope ? ['user', 'project'] : [selection.scope ?? 'user'];
200
+ return candidates.some((candidate) => platforms.some((platform) => scopes.some((scope) => writeCandidateEligibility(command, candidate, { ...selection, platform, scope }).selectable)));
201
+ }
202
+ function hasConfigSchemaKeys(candidate) {
203
+ return candidate.configSchema !== undefined && Object.keys(candidate.configSchema).length > 0;
204
+ }
205
+ async function loadWizardCandidates(context, rawOptions) {
206
+ const loaded = await loadConsoleItemsResult({
207
+ cwd: context.cwd,
208
+ scope: rawOptions.scope,
209
+ platform: rawOptions.platform,
210
+ includeCatalogOnly: true,
211
+ }, context);
212
+ return toWizardCandidates(loaded.items);
213
+ }
214
+ function mergeWizardCandidates(current, stored) {
215
+ const merged = new Map(current.map((candidate) => [candidate.pluginName, candidate]));
216
+ for (const candidate of stored) {
217
+ const existing = merged.get(candidate.pluginName);
218
+ if (!existing) {
219
+ merged.set(candidate.pluginName, candidate);
220
+ }
221
+ else if (!existing.configSchema) {
222
+ merged.set(candidate.pluginName, { ...candidate, ...existing });
223
+ }
224
+ }
225
+ return [...merged.values()];
226
+ }
227
+ async function loadStoredConfigWizardCandidates(context, locations, options = {}) {
228
+ const legacy = await listPluginConfigStorePluginNames({ cwd: context.cwd, env: context.env });
229
+ if (legacy.length > 0) {
230
+ throw new Error('legacyStateUnsupported: legacy bare-name config stores are not supported.');
231
+ }
232
+ const storesByPlugin = new Map();
233
+ for (const location of locations) {
234
+ const stores = await listNamespacedPluginConfigStores({
235
+ cwd: context.cwd,
236
+ env: context.env,
237
+ scope: location.scope,
238
+ ...(location.scope === 'project' ? { projectLayer: location.projectLayer } : {}),
239
+ });
240
+ for (const store of stores) {
241
+ const keys = Object.keys(store.values);
242
+ if (keys.length === 0 && options.includeEmptyStores !== true)
243
+ continue;
244
+ const existing = storesByPlugin.get(store.pluginId) ?? {
245
+ sourceId: store.sourceId,
246
+ sourceIdentity: store.sourceIdentity,
247
+ keys: new Set(),
248
+ };
249
+ if (existing.sourceIdentity !== store.sourceIdentity) {
250
+ throw new Error(`sourceChanged: ${store.pluginId} config stores have different source identities.`);
251
+ }
252
+ for (const key of keys)
253
+ existing.keys.add(key);
254
+ storesByPlugin.set(store.pluginId, existing);
255
+ }
256
+ }
257
+ return [...storesByPlugin]
258
+ .sort(([left], [right]) => left.localeCompare(right))
259
+ .map(([pluginId, store]) => ({
260
+ pluginName: pluginId,
261
+ pluginId,
262
+ sourceId: store.sourceId,
263
+ sourceIdentity: store.sourceIdentity,
264
+ targets: [],
265
+ configKeys: [...store.keys].sort((left, right) => left.localeCompare(right)),
266
+ }));
267
+ }
268
+ function configReadStoreLocations(rawOptions) {
269
+ if (rawOptions.local)
270
+ return [{ scope: 'project', projectLayer: 'local' }];
271
+ if (rawOptions.scope === 'user')
272
+ return [{ scope: 'user', projectLayer: 'shared' }];
273
+ if (rawOptions.scope === 'project')
274
+ return [{ scope: 'project', projectLayer: 'shared' }];
275
+ return [
276
+ { scope: 'user', projectLayer: 'shared' },
277
+ { scope: 'project', projectLayer: 'shared' },
278
+ { scope: 'project', projectLayer: 'local' },
279
+ ];
280
+ }
281
+ function overallResultState(value) {
282
+ return value.overallState;
283
+ }
284
+ async function resolveStoredOnlyConfigIdentity(options) {
285
+ const parsed = parsePluginId(options.selector);
286
+ if (!parsed.sourceId)
287
+ throw new Error(`Plugin "${options.selector}" is not a qualified stored config target.`);
288
+ const stores = (await Promise.all(options.locations.map((location) => listNamespacedPluginConfigStores({
289
+ cwd: options.context.cwd,
290
+ env: options.context.env,
291
+ scope: location.scope,
292
+ ...(location.scope === 'project' ? { projectLayer: location.projectLayer } : {}),
293
+ })))).flat().filter((store) => store.pluginId === options.selector);
294
+ if (stores.length === 0)
295
+ throw new Error(`Plugin "${options.selector}" does not have a namespaced config store.`);
296
+ const identities = new Set(stores.map((store) => store.sourceIdentity));
297
+ if (identities.size !== 1)
298
+ throw new Error(`sourceChanged: ${options.selector} config stores have different source identities.`);
299
+ const sourceIdentity = [...identities][0];
300
+ await withResolvedMultiSourceCatalog({
301
+ cliVersion: resolveCliVersion(),
302
+ freshnessPolicy: 'cacheFirst',
303
+ sourceIds: [parsed.sourceId],
304
+ env: options.context.env,
305
+ consume: async (catalog) => {
306
+ const source = catalog.sources.find((entry) => entry.sourceId === parsed.sourceId);
307
+ if (!source?.resolution)
308
+ throw source?.error ?? new Error(`Catalog source "${parsed.sourceId}" is unavailable.`);
309
+ if (source.resolution.sourceIdentity !== sourceIdentity) {
310
+ throw new Error(`sourceChanged: ${options.selector} config source identity does not match the current source.`);
311
+ }
312
+ },
313
+ });
314
+ return {
315
+ pluginName: parsed.pluginName,
316
+ pluginId: options.selector,
317
+ sourceId: parsed.sourceId,
318
+ sourceIdentity,
319
+ };
320
+ }
321
+ async function resolveMultiSourceConfigRead(options) {
322
+ const inventory = await inventoryLegacyConfigReferences({
323
+ cwd: options.context.cwd,
324
+ env: options.context.env,
325
+ });
326
+ assertCatalogSourceReferencesSupported(inventory);
327
+ const projectLayer = resolveConfigProjectLayer(options.rawOptions);
328
+ return withResolvedCatalogPlugin({
329
+ selector: options.selector,
330
+ cliVersion: resolveCliVersion(),
331
+ freshnessPolicy: 'cacheFirst',
332
+ env: options.context.env,
333
+ consume: async ({ pluginId, source, plugin }) => {
334
+ const result = await resolveConfigRead({
335
+ pluginName: plugin.manifest.name,
336
+ plugin,
337
+ scope: options.rawOptions.local
338
+ ? 'project'
339
+ : resolveConfigReadResolution(options.rawOptions.scope),
340
+ projectLayer,
341
+ cwd: options.context.cwd,
342
+ env: options.context.env,
343
+ });
344
+ if (options.key !== undefined) {
345
+ const field = findConfigFieldEntry(result.fields, options.key);
346
+ if (!field && plugin.manifest.config?.schema?.[options.key] === undefined) {
347
+ throw new Error(`Unknown config key "${options.key}".`);
348
+ }
349
+ if (field)
350
+ result.fields = [field];
351
+ }
352
+ return {
353
+ pluginName: plugin.manifest.name,
354
+ pluginId,
355
+ sourceId: source.sourceId,
356
+ sourceIdentity: source.sourceIdentity,
357
+ result,
358
+ };
359
+ },
360
+ }).catch(async (error) => {
361
+ const message = error instanceof Error ? error.message : String(error);
362
+ if (!message.includes('does not exist in the required catalog source set'))
363
+ throw error;
364
+ const stored = await resolveStoredOnlyConfigIdentity({
365
+ selector: options.selector,
366
+ context: options.context,
367
+ locations: configReadStoreLocations(options.rawOptions),
368
+ });
369
+ const result = await resolveConfigRead({
370
+ sourceId: stored.sourceId,
371
+ sourceIdentity: stored.sourceIdentity,
372
+ pluginName: stored.pluginName,
373
+ plugin: null,
374
+ scope: options.rawOptions.local
375
+ ? 'project'
376
+ : resolveConfigReadResolution(options.rawOptions.scope),
377
+ projectLayer,
378
+ cwd: options.context.cwd,
379
+ env: options.context.env,
380
+ });
381
+ if (options.key !== undefined) {
382
+ const field = findConfigFieldEntry(result.fields, options.key);
383
+ if (!field)
384
+ throw new Error(`Unknown config key "${options.key}".`);
385
+ result.fields = [field];
386
+ }
387
+ return { ...stored, result };
388
+ });
389
+ }
390
+ async function executeWriteCommand(command, pluginNames, rawOptions, context) {
391
+ const raw = { cwd: context.cwd, ...rawOptions };
392
+ const commandOptions = command === 'install'
393
+ ? normalizeInstallCommandOptions(raw)
394
+ : command === 'upgrade'
395
+ ? normalizeUpgradeCommandOptions(raw)
396
+ : command === 'uninstall'
397
+ ? normalizeUninstallCommandOptions(raw)
398
+ : command === 'cleanup'
399
+ ? normalizeCleanupCommandOptions(raw)
400
+ : normalizeReinstallCommandOptions(raw);
401
+ await emitCommandEvent(context, {
402
+ type: 'options:normalized',
403
+ data: { plugins: pluginNames, options: commandOptions },
404
+ });
405
+ switch (command) {
406
+ case 'install': return installCommand(pluginNames, commandOptions, context);
407
+ case 'upgrade': return upgradeCommand(pluginNames, commandOptions, context);
408
+ case 'uninstall': return uninstallCommand(pluginNames, commandOptions, context);
409
+ case 'cleanup': return cleanupCommand(pluginNames, commandOptions, context);
410
+ case 'reinstall': return reinstallCommand(pluginNames, commandOptions, context);
411
+ }
412
+ }
413
+ async function runWriteCommandAction(command, pluginNames, rawOptions, context) {
414
+ if ((command === 'cleanup' || command === 'reinstall') && pluginNames.length > 1) {
415
+ throw new Error(`${command} 命令当前只支持单个插件目标。`);
416
+ }
417
+ if (command === 'upgrade')
418
+ assertUpgradeAllConflict(pluginNames, rawOptions.all === true);
419
+ const missingPlugin = pluginNames.length === 0 && !(command === 'upgrade' && rawOptions.all === true);
420
+ const missingPlatform = rawOptions.platform === undefined;
421
+ const missingScope = command === 'cleanup' && rawOptions.scope === undefined;
422
+ const missing = missingPlugin || missingPlatform || missingScope;
423
+ // Validate every value already supplied by the caller before opening the TUI.
424
+ const validationOptions = {
425
+ cwd: context.cwd,
426
+ ...rawOptions,
427
+ platform: rawOptions.platform ?? 'both',
428
+ ...(command === 'cleanup' ? { scope: rawOptions.scope ?? 'user' } : {}),
429
+ };
430
+ void validationOptions;
431
+ if (!missing) {
432
+ return {
433
+ cancelled: false,
434
+ result: await executeWriteCommand(command, pluginNames, rawOptions, context),
435
+ };
436
+ }
437
+ if (!isWizardAvailable(context, rawOptions)) {
438
+ throw new Error(writeCommandUsage(command));
439
+ }
440
+ const loaded = await loadConsoleItemsResult({
441
+ cwd: context.cwd,
442
+ scope: rawOptions.scope,
443
+ platform: rawOptions.platform,
444
+ includeCatalogOnly: true,
445
+ }, context);
446
+ if (loaded.catalogUnavailable) {
447
+ throw new Error('插件目录不可用。请运行 `aw init` 或 `aw init --force`,或使用完整参数重试。');
448
+ }
449
+ const candidates = missingPlugin ? toWizardCandidates(loaded.items) : [];
450
+ const initialSelection = {
451
+ plugins: pluginNames,
452
+ platform: rawOptions.platform,
453
+ scope: (rawOptions.scope ?? 'user'),
454
+ };
455
+ if (missingPlugin && !hasSelectableWriteCandidate(command, candidates, initialSelection, {
456
+ missingPlatform,
457
+ missingScope,
458
+ })) {
459
+ throw new Error('没有可执行此操作的目标。请运行 `aw status` 检查当前状态。');
460
+ }
461
+ const result = await runCommandWizard(context, {
462
+ command,
463
+ candidates,
464
+ initial: initialSelection,
465
+ pluginMode: missingPlugin
466
+ ? command === 'cleanup' || command === 'reinstall' ? 'single' : 'multiple'
467
+ : 'none',
468
+ promptForPlatform: missingPlatform,
469
+ promptForScope: missingScope,
470
+ destructive: command === 'uninstall' || command === 'cleanup',
471
+ equivalentCommand: (selection) => equivalentWriteCommand(command, selection, rawOptions),
472
+ equivalentCommandTokens: (selection) => buildEquivalentWriteCommandTokens(command, selection, rawOptions),
473
+ isPluginSelectable: (candidate, selection) => writeCandidateEligibility(command, candidate, selection),
474
+ resultState: overallResultState,
475
+ execute: (selection) => executeWriteCommand(command, selection.plugins, {
476
+ ...rawOptions,
477
+ platform: selection.platform,
478
+ scope: selection.scope,
479
+ }, context),
480
+ });
481
+ if (result.cancelled)
482
+ return { cancelled: true };
483
+ return { cancelled: false, result: result.value };
484
+ }
485
+ function parseBareConsoleOptions(argv) {
486
+ if (argv.length === 0) {
487
+ return {};
488
+ }
489
+ const parsed = {};
490
+ for (let index = 0; index < argv.length; index += 1) {
491
+ const token = argv[index];
492
+ if (!token) {
493
+ continue;
494
+ }
495
+ if (token === '--help' || token === '-h' || token === '--version' || token === '-V') {
496
+ return null;
497
+ }
498
+ if (token === '-v' || token === '--verbose') {
499
+ parsed.verbose = true;
500
+ continue;
501
+ }
502
+ if (token === '-D' || token === '--debug') {
503
+ parsed.debug = true;
504
+ continue;
505
+ }
506
+ if (token === '--log-file') {
507
+ parsed.logFile = readBareConsoleOptionValue(argv[index + 1], '--log-file <path>');
508
+ index += 1;
509
+ continue;
510
+ }
511
+ if (token.startsWith('--log-file=')) {
512
+ parsed.logFile = readBareConsoleOptionValue(token.slice('--log-file='.length), '--log-file <path>');
513
+ continue;
514
+ }
515
+ return null;
516
+ }
517
+ return parsed;
518
+ }
519
+ function readBareConsoleOptionValue(value, option) {
520
+ if (!value || value.startsWith('-')) {
521
+ throw new Error(`option '${option}' argument missing`);
522
+ }
523
+ return value;
524
+ }
525
+ async function runActionWithContext(context, action) {
526
+ await emitCommandEvent(context, {
527
+ type: 'command:start',
528
+ data: {
529
+ cwd: context.cwd,
530
+ verbose: context.diagnostics.verbose,
531
+ debug: context.diagnostics.debug,
532
+ logFile: context.diagnostics.logFile,
533
+ },
534
+ });
535
+ try {
536
+ const result = await action();
537
+ await emitCommandEvent(context, { type: 'command:success' });
538
+ await Promise.allSettled([
539
+ Promise.resolve().then(() => context.debugLogger.flush?.()),
540
+ ]);
541
+ if (context.diagnostics.debug && context.debugLogger.logFile) {
542
+ writeLine(context.io.stderr, `调试日志:${context.debugLogger.logFile}`);
543
+ }
544
+ return result;
545
+ }
546
+ catch (error) {
547
+ if (error instanceof WizardExecutionError) {
548
+ const diagnostic = error.diagnostic;
549
+ await Promise.allSettled([
550
+ Promise.resolve().then(() => context.reporter.event({
551
+ type: 'command:error',
552
+ commandName: context.diagnostics.commandName,
553
+ message: error.message,
554
+ data: { name: error.name },
555
+ })),
556
+ Promise.resolve().then(() => context.debugLogger.log(redactValue({
557
+ type: 'command:error',
558
+ commandName: context.diagnostics.commandName,
559
+ message: diagnostic instanceof Error ? diagnostic.message : error.message,
560
+ data: diagnostic instanceof Error
561
+ ? { name: diagnostic.name, stack: diagnostic.stack }
562
+ : { result: diagnostic },
563
+ }))),
564
+ ]);
565
+ }
566
+ else {
567
+ await emitCommandEvent(context, {
568
+ type: 'command:error',
569
+ message: error instanceof Error ? error.message : String(error),
570
+ data: error instanceof Error
571
+ ? {
572
+ name: error.name,
573
+ stack: error.stack,
574
+ }
575
+ : undefined,
576
+ });
577
+ }
578
+ await Promise.allSettled([
579
+ Promise.resolve().then(() => context.debugLogger.flush?.()),
580
+ ]);
581
+ if (context.diagnostics.debug && context.debugLogger.logFile) {
582
+ writeLine(context.io.stderr, `调试日志:${context.debugLogger.logFile}`);
583
+ }
584
+ throw error;
585
+ }
586
+ }
587
+ function writeJsonReceipt(write, payload) {
588
+ writeLine(write, JSON.stringify(payload, null, 2));
589
+ }
590
+ function configLayerLabel(scope, projectLayer = 'shared') {
591
+ if (scope === 'user') {
592
+ return '个人';
593
+ }
594
+ return projectLayer === 'local' ? '当前项目(本机私有覆盖)' : '当前项目';
595
+ }
596
+ function writeConfigApplyNotice(write, receipt) {
597
+ if (receipt.targetResults.length === 0) {
598
+ const message = receipt.applySkippedReason === 'noConfigChange'
599
+ ? '配置内容没有变化,因此没有运行 reinstall。'
600
+ : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
601
+ writeLine(write, message);
602
+ }
603
+ else {
604
+ const completed = receipt.targetResults.filter((entry) => entry.state === 'completed').length;
605
+ const failed = receipt.targetResults.filter((entry) => entry.state === 'failed');
606
+ writeLine(write, `配置已保存。已重装 ${completed} 个当前可见目标;失败 ${failed.length} 个。`);
607
+ for (const entry of failed) {
608
+ writeLine(write, `${entry.target.platform}/${entry.target.scope}:${entry.message ?? 'reinstall 失败。'} `
609
+ + `请重试 aw reinstall ${receipt.plugin} -p ${entry.target.platform} -s ${entry.target.scope}。`);
610
+ }
611
+ }
612
+ if (receipt.otherProjectsRequireReinstall) {
613
+ writeLine(write, '其它项目没有被扫描。请进入每个项目目录并运行对应的 aw reinstall 命令。');
614
+ }
615
+ }
616
+ function writeProjectLocalConfigNotice(write) {
617
+ writeLine(write, '当前显示的是当前项目的本机私有覆盖层,不作为 repo-visible artifact 渲染输入。');
618
+ }
619
+ function renderConfigFieldState(field) {
620
+ if (field.valueState === 'invalid') {
621
+ return 'invalid-config';
622
+ }
623
+ return field.valueState;
624
+ }
625
+ function writeConfigReadHuman(write, resolved, pluginName) {
626
+ for (const field of resolved.fields) {
627
+ const effectiveValue = field.effectiveValue === null
628
+ ? '<unset>'
629
+ : renderPluginConfigValueForDisplay(field.effectiveValue);
630
+ const source = field.sourceLayer ?? 'none';
631
+ writeLine(write, `${field.key}: ${renderConfigFieldState(field)} (source=${source}, effective=${effectiveValue})`);
632
+ if (field.storedValue !== undefined && field.storedSourceLayer) {
633
+ writeLine(write, ` stored=${field.storedSourceLayer} ${renderPluginConfigValueForDisplay(field.storedValue)}`);
634
+ }
635
+ if (field.kind === 'manifest' && field.valueState === 'invalid') {
636
+ const sourceScope = field.sourceLayer === 'project'
637
+ ? ' -s project'
638
+ : field.sourceLayer === 'local'
639
+ ? ' -s project --local'
640
+ : ' -s user';
641
+ writeLine(write, ` aw config set ${pluginName} ${field.key} <value>${sourceScope}`);
642
+ writeLine(write, ` aw config unset ${pluginName} ${field.key}${sourceScope}`);
643
+ writeLine(write, ` aw config reset ${pluginName}${sourceScope}`);
644
+ }
645
+ }
646
+ }
647
+ export function buildProgram(options = {}) {
648
+ const cwd = options.cwd ?? process.cwd();
649
+ const env = options.env ?? process.env;
650
+ const commandExitState = { exitCode: 0 };
651
+ const io = {
652
+ ...createDefaultIo(),
653
+ ...options.io,
654
+ };
655
+ const createActionContext = (commandName, rawOptions) => createCliExecutionContext({
656
+ ...options,
657
+ cwd,
658
+ env,
659
+ io,
660
+ interactive: options.interactive,
661
+ diagnostics: toCliDiagnosticsOptions(commandName, rawOptions, options.diagnostics),
662
+ });
663
+ const program = new Command();
664
+ program
665
+ .name('aw')
666
+ .description('Agent workflow marketplace installer')
667
+ .version(resolveCliVersion(), '-V, --version', 'output the current aw cli version')
668
+ .exitOverride()
669
+ .configureOutput({
670
+ writeOut: (text) => io.stdout(text),
671
+ writeErr: (text) => io.stderr(text),
672
+ outputError: (text, write) => write(text),
673
+ });
674
+ const plugin = program
675
+ .command('plugin')
676
+ .description('Create and validate AW plugin source');
677
+ const skill = program
678
+ .command('skill')
679
+ .description('Install, materialize, or validate Agent Skills');
680
+ const review = program
681
+ .command('review')
682
+ .description('Publish and inspect immutable review records');
683
+ const reviewRecordDir = (repoRoot, record) => path.relative(fs.realpathSync(repoRoot), record.root).split(path.sep).join('/');
684
+ const reviewJsonRecord = (repoRoot, record) => ({
685
+ recordDir: reviewRecordDir(repoRoot, record),
686
+ manifest: record.manifest,
687
+ });
688
+ review
689
+ .command('digest')
690
+ .description('Compute one canonical workflow component digest')
691
+ .argument('<path>', 'repository file or directory')
692
+ .option('--json', 'emit one component digest JSON object', false)
693
+ .action(async (componentPath, rawOptions) => {
694
+ const repoRoot = await resolveRepoRoot(cwd);
695
+ const result = await computeReviewComponentDigest({ repoRoot, path: componentPath });
696
+ if (rawOptions.json) {
697
+ writeJsonReceipt(io.stdout, {
698
+ schemaVersion: 1,
699
+ command: 'review:digest',
700
+ ok: true,
701
+ ...result,
702
+ });
703
+ return;
704
+ }
705
+ writeLine(io.stdout, `${result.path}: ${result.digest}`);
706
+ });
707
+ review
708
+ .command('publish')
709
+ .description('Publish one immutable review record')
710
+ .requiredOption('--kind <skill|workflow|aw-plugin|aw-workflow>', 'review target kind')
711
+ .requiredOption('--target <path-or-id>', 'review target path or ID')
712
+ .requiredOption('--report <report.md>', 'review report Markdown file')
713
+ .option('--scope <scope.json>', 'workflow scope JSON file')
714
+ .option('--result <review-result.json>', 'review result JSON file')
715
+ .option('--check <kind=path>', 'archive one JSON check attachment', (value, previous) => [
716
+ ...previous,
717
+ parseReviewAttachment(value, 'Check'),
718
+ ], [])
719
+ .option('--evidence <kind=path>', 'archive one JSON evidence attachment', (value, previous) => [
720
+ ...previous,
721
+ parseReviewAttachment(value, 'Evidence'),
722
+ ], [])
723
+ .option('--release-check <release-check.json>', 'release check JSON file')
724
+ .option('--supersedes <review-id>', 'review ID that this record supersedes')
725
+ .option('--json', 'emit one review record JSON object', false)
726
+ .action(async (rawOptions) => {
727
+ const repoRoot = await resolveRepoRoot(cwd);
728
+ const record = await publishReviewRecord({
729
+ repoRoot,
730
+ kind: rawOptions.kind,
731
+ target: rawOptions.target,
732
+ report: rawOptions.report,
733
+ ...(rawOptions.scope === undefined ? {} : { scope: rawOptions.scope }),
734
+ ...(rawOptions.result === undefined ? {} : { result: rawOptions.result }),
735
+ ...(rawOptions.check.length === 0 ? {} : { checks: rawOptions.check }),
736
+ ...(rawOptions.evidence.length === 0 ? {} : { evidence: rawOptions.evidence }),
737
+ ...(rawOptions.releaseCheck === undefined ? {} : { releaseCheck: rawOptions.releaseCheck }),
738
+ ...(rawOptions.supersedes === undefined ? {} : { supersedes: rawOptions.supersedes }),
739
+ });
740
+ const recordDir = reviewRecordDir(repoRoot, record);
741
+ if (rawOptions.json) {
742
+ writeJsonReceipt(io.stdout, {
743
+ schemaVersion: 1,
744
+ command: 'review:publish',
745
+ ok: true,
746
+ ...reviewJsonRecord(repoRoot, record),
747
+ existing: record.existing,
748
+ });
749
+ return;
750
+ }
751
+ writeLine(io.stdout, `${record.existing ? 'Existing' : 'Published'} review ${record.manifest.reviewId}: ${recordDir}`);
752
+ });
753
+ review
754
+ .command('verify')
755
+ .description('Verify one archived review record')
756
+ .argument('<report-dir>', 'review record directory')
757
+ .option('--json', 'emit one review record JSON object', false)
758
+ .action(async (reportDir, rawOptions) => {
759
+ const repoRoot = await resolveRepoRoot(cwd);
760
+ const record = await verifyReviewRecord({ repoRoot, reportDir });
761
+ const relativeRecordDir = reviewRecordDir(repoRoot, record);
762
+ if (rawOptions.json) {
763
+ writeJsonReceipt(io.stdout, {
764
+ schemaVersion: 1,
765
+ command: 'review:verify',
766
+ ok: true,
767
+ ...reviewJsonRecord(repoRoot, record),
768
+ });
769
+ return;
770
+ }
771
+ writeLine(io.stdout, `Verified review ${record.manifest.reviewId}: ${relativeRecordDir}`);
772
+ });
773
+ review
774
+ .command('list')
775
+ .description('List immutable review records')
776
+ .option('--kind <kind>', 'filter by review target kind')
777
+ .option('--target <id>', 'filter by review target ID')
778
+ .option('--json', 'emit one review records JSON object', false)
779
+ .action(async (rawOptions) => {
780
+ const repoRoot = await resolveRepoRoot(cwd);
781
+ const records = await listReviewRecords({
782
+ repoRoot,
783
+ ...(rawOptions.kind === undefined ? {} : { kind: rawOptions.kind }),
784
+ ...(rawOptions.target === undefined ? {} : { targetId: rawOptions.target }),
785
+ });
786
+ if (rawOptions.json) {
787
+ writeJsonReceipt(io.stdout, {
788
+ schemaVersion: 1,
789
+ command: 'review:list',
790
+ ok: true,
791
+ records: records.map((record) => reviewJsonRecord(repoRoot, record)),
792
+ });
793
+ return;
794
+ }
795
+ for (const record of records) {
796
+ writeLine(io.stdout, [
797
+ record.manifest.reviewId,
798
+ record.manifest.target.kind,
799
+ record.manifest.target.id,
800
+ record.manifest.publishedAt,
801
+ ].join(' '));
802
+ }
803
+ });
804
+ review
805
+ .command('show')
806
+ .description('Show one immutable review record')
807
+ .argument('<review-id>', 'review record ID')
808
+ .option('--json', 'emit one review record JSON object', false)
809
+ .action(async (reviewId, rawOptions) => {
810
+ const repoRoot = await resolveRepoRoot(cwd);
811
+ const record = await showReviewRecord({ repoRoot, reviewId });
812
+ if (rawOptions.json) {
813
+ writeJsonReceipt(io.stdout, {
814
+ schemaVersion: 1,
815
+ command: 'review:show',
816
+ ok: true,
817
+ ...reviewJsonRecord(repoRoot, record),
818
+ });
819
+ return;
820
+ }
821
+ const manifest = record.manifest;
822
+ writeLine(io.stdout, `Review: ${manifest.reviewId}`);
823
+ writeLine(io.stdout, `Target: ${manifest.target.kind} ${manifest.target.id}`);
824
+ writeLine(io.stdout, `Published: ${manifest.publishedAt}`);
825
+ writeLine(io.stdout, `Report: ${manifest.report.path}`);
826
+ writeLine(io.stdout, `Result: ${manifest.result?.path ?? 'none'}`);
827
+ writeLine(io.stdout, `Checks: ${manifest.checks.map((entry) => entry.kind).join(', ') || 'none'}`);
828
+ writeLine(io.stdout, `Evidence: ${manifest.evidence.map((entry) => entry.kind).join(', ') || 'none'}`);
829
+ writeLine(io.stdout, `Release check: ${manifest.releaseCheck?.path ?? 'none'}`);
830
+ writeLine(io.stdout, `Supersedes: ${manifest.supersedes ?? 'none'}`);
831
+ });
832
+ skill
833
+ .command('install')
834
+ .description('Install portable Skills through the skills CLI')
835
+ .argument('<plugin>', 'plugin or source/plugin selector')
836
+ .requiredOption('-s, --scope <scope>', 'project or user')
837
+ .option('--skill <name...>', 'install only selected Skill names')
838
+ .option('--agent <id...>', 'install to explicit Agent IDs')
839
+ .option('-y, --yes', 'confirm the reviewed install', false)
840
+ .option('-j, --json', 'emit one receipt v4 JSON object', false)
841
+ .action(async (selector, rawOptions) => {
842
+ const context = createActionContext('skill:install', {});
843
+ const writeFailure = (error) => {
844
+ const code = error instanceof PortableCommandError || error instanceof SkillsCliError
845
+ ? error.code
846
+ : 'portableInstallFailed';
847
+ writeJsonReceipt(io.stdout, {
848
+ receiptSchemaVersion: 4,
849
+ command: 'skill:install',
850
+ ok: false,
851
+ status: 'failed',
852
+ plugin: { id: selector },
853
+ scope: rawOptions.scope,
854
+ selectedSkills: [],
855
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
856
+ agentMode: rawOptions.agent ? 'explicit' : 'automatic',
857
+ requestedAgents: rawOptions.agent ?? [],
858
+ skillsCliVersion: null,
859
+ collisions: [],
860
+ dependencies: [],
861
+ materializationDigest: null,
862
+ verification: { records: [], missing: [] },
863
+ warnings: [],
864
+ failures: [{ code, message: `${code}: portable Skill 安装未执行。` }],
865
+ });
866
+ };
867
+ if (rawOptions.json && !rawOptions.yes) {
868
+ writeFailure(new PortableCommandError('confirmationRequired', '写入型 --json 必须同时使用 --yes。'));
869
+ commandExitState.exitCode = 1;
870
+ return;
871
+ }
872
+ try {
873
+ const receipt = await runActionWithContext(context, () => installPortableSkills({
874
+ selector,
875
+ scope: rawOptions.scope,
876
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
877
+ ...(rawOptions.agent ? { requestedAgents: rawOptions.agent } : {}),
878
+ yes: rawOptions.yes,
879
+ cwd: context.cwd,
880
+ cliVersion: resolveCliVersion(),
881
+ env: context.env,
882
+ ...(context.interactive && context.prompt.confirm ? {
883
+ confirm: async () => context.prompt.confirm({
884
+ message: '确认按以上 Review 安装 portable Skills?',
885
+ defaultValue: false,
886
+ }),
887
+ } : {}),
888
+ ...(!rawOptions.json ? {
889
+ onReview: (review) => {
890
+ for (const line of renderPortableReview(review))
891
+ writeLine(io.stdout, line);
892
+ },
893
+ } : {}),
894
+ }));
895
+ if (rawOptions.json)
896
+ writeJsonReceipt(io.stdout, receipt);
897
+ else if (receipt.ok)
898
+ writeLine(io.stdout, `portable Skill 安装完成:${receipt.selectedSkills.length} 项。`);
899
+ else {
900
+ const sanitize = (value) => redactString(value)
901
+ .replace(/https?:\/\/\S+/giu, '[REDACTED URL]')
902
+ .replace(/(?:file:\/\/)?(?:\/[\w.@+-]+){2,}/gu, '[REDACTED PATH]')
903
+ .replace(/[A-Za-z]:\\(?:[^\s\\]+\\)+[^\s\\]*/gu, '[REDACTED PATH]');
904
+ const lines = new Set();
905
+ for (const failure of receipt.failures) {
906
+ lines.add(`${failure.code}: ${sanitize(failure.message)}`);
907
+ }
908
+ for (const warning of receipt.warnings)
909
+ lines.add(`警告:${sanitize(warning)}`);
910
+ const recoveries = receipt.failures.map((failure) => failure.recovery).filter(Boolean);
911
+ const recovery = recoveries.find((entry) => entry.includes('aw skill install')
912
+ && entry.includes('skills remove'))
913
+ ?? '重新运行 aw skill install;如需清理外部写入,请使用 skills remove。';
914
+ lines.add(`恢复:${sanitize(recovery)}`);
915
+ for (const line of lines)
916
+ writeLine(io.stderr, line);
917
+ }
918
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
919
+ }
920
+ catch (error) {
921
+ if (!rawOptions.json)
922
+ throw error;
923
+ writeFailure(error);
924
+ commandExitState.exitCode = 1;
925
+ }
926
+ });
927
+ skill
928
+ .command('materialize')
929
+ .description('Write portable Skills to a safe output directory')
930
+ .argument('<plugin>', 'plugin or source/plugin selector')
931
+ .requiredOption('-s, --scope <scope>', 'project or user')
932
+ .requiredOption('--out <dir>', 'output directory')
933
+ .option('--skill <name...>', 'write only selected Skill names')
934
+ .option('-j, --json', 'emit one receipt v4 JSON object', false)
935
+ .action(async (selector, rawOptions) => {
936
+ const context = createActionContext('skill:materialize', {});
937
+ try {
938
+ const receipt = await runActionWithContext(context, () => materializePortableSkillsToDirectory({
939
+ selector,
940
+ scope: rawOptions.scope,
941
+ out: rawOptions.out,
942
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
943
+ cwd: context.cwd,
944
+ cliVersion: resolveCliVersion(),
945
+ env: context.env,
946
+ }));
947
+ if (rawOptions.json)
948
+ writeJsonReceipt(io.stdout, receipt);
949
+ else
950
+ writeLine(io.stdout, `portable Skill 已写入 ${receipt.out}:${receipt.selectedSkills.length} 项。`);
951
+ }
952
+ catch (error) {
953
+ if (!rawOptions.json)
954
+ throw error;
955
+ const code = error instanceof PortableCommandError || error instanceof SkillsCliError
956
+ ? error.code
957
+ : 'portableMaterializeFailed';
958
+ writeJsonReceipt(io.stdout, {
959
+ receiptSchemaVersion: 4,
960
+ command: 'skill:materialize',
961
+ ok: false,
962
+ plugin: { id: selector },
963
+ scope: rawOptions.scope,
964
+ out: path.resolve(context.cwd, rawOptions.out),
965
+ selectedSkills: [],
966
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
967
+ dependencies: [],
968
+ configDigest: null,
969
+ materializationDigest: null,
970
+ outputDigest: null,
971
+ errors: [{ code, message: `${code}: portable Skill 导出未执行。` }],
972
+ });
973
+ commandExitState.exitCode = 1;
974
+ }
975
+ });
976
+ plugin
977
+ .command('init')
978
+ .description('Create a new deterministic plugin scaffold')
979
+ .addHelpText('after', [
980
+ '',
981
+ 'During development, keep the current stable target when production content changes.',
982
+ 'Next, run `aw plugin validate`, `aw plugin test`, `aw plugin build`, and `aw catalog build`.',
983
+ 'Publish only as an explicit later step; inspect `aw catalog publish --help` first.',
984
+ '',
985
+ ].join('\n'))
986
+ .argument('<plugin-name>', 'lowercase hyphen-case plugin name')
987
+ .option('--description <text>', 'plugin description (required)')
988
+ .option('--display-name <text>', 'human-facing plugin display name')
989
+ .option('--short-description <text>', 'short plugin UI description')
990
+ .option('--skill-name <name>', 'initial static Skill name')
991
+ .option('--skill-description <text>', 'initial Skill goal and discovery description')
992
+ .option('--skill-short-description <text>', 'initial Skill UI summary (25-64 characters)')
993
+ .option('--skill-invocation <mode>', 'model | manual | claude-model-only (default: model)')
994
+ .option('--version <semver>', 'initial stable plugin version (default: 0.1.0)')
995
+ .option('--min-version <semver>', 'compatibility.aw.minVersion')
996
+ .option('--catalog-min-version <semver>', 'target catalog compatibility minimum')
997
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
998
+ .option('--no-skills', 'create the plugin without a skills directory')
999
+ .option('--with-mcp', 'add a minimal .mcp.json', false)
1000
+ .option('--with-apps', 'add a minimal .app.json', false)
1001
+ .option('--with-config-api', 'add AW config schema and helper', false)
1002
+ .option('--with-lifecycle', 'add a lifecycle script sample', false);
1003
+ plugin
1004
+ .command('add-skill')
1005
+ .description('Add one static Skill scaffold to an existing plugin')
1006
+ .addHelpText('after', [
1007
+ '',
1008
+ 'During development, keep the current stable target when production content changes.',
1009
+ 'Next, run `aw plugin validate`, `aw plugin test`, `aw plugin build`, and `aw catalog build`.',
1010
+ 'Publish only as an explicit later step; inspect `aw catalog publish --help` first.',
1011
+ '',
1012
+ ].join('\n'))
1013
+ .argument('<plugin-name>', 'existing lowercase hyphen-case plugin name')
1014
+ .option('--skill-name <name>', 'new static Skill name (required)')
1015
+ .option('--skill-description <text>', 'Skill goal and discovery description (required)')
1016
+ .option('--skill-short-description <text>', 'Skill UI summary (25-64 characters)')
1017
+ .option('--skill-invocation <mode>', 'model | manual | claude-model-only (default: model)')
1018
+ .option('--workspace-root <path>', 'workspace root (default: current directory)');
1019
+ plugin
1020
+ .command('validate')
1021
+ .description('Validate one source plugin directory')
1022
+ .argument('<plugin-directory>', 'source plugin directory')
1023
+ .option('--catalog-min-version <semver>', 'validate compatibility against a target catalog')
1024
+ .option('--strict-agent-skills', 'allow only Agent Skills portable core frontmatter', false)
1025
+ .option('--claude-skill-profile <profile>', 'minimum | current (default: minimum)')
1026
+ .option('--version-base <git-ref>', 'production bundle comparison base (default: HEAD)')
1027
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1028
+ .option('--json', 'emit one machine-readable JSON result', false);
1029
+ plugin
1030
+ .command('test')
1031
+ .description('Run deterministic Node tests declared by one source plugin')
1032
+ .argument('<plugin-directory>', 'source plugin directory')
1033
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1034
+ .option('--json', 'emit one machine-readable JSON result', false)
1035
+ .action(async (pluginDirectory, rawOptions) => {
1036
+ try {
1037
+ commandExitState.exitCode = await runPluginTestCommand({
1038
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1039
+ pluginDirectory,
1040
+ json: rawOptions.json,
1041
+ io,
1042
+ });
1043
+ }
1044
+ catch (error) {
1045
+ const message = error instanceof Error ? error.message : String(error);
1046
+ if (rawOptions.json)
1047
+ writeJsonReceipt(io.stdout, { command: 'plugin:test', ok: false, errors: [{ message }] });
1048
+ writeLine(io.stderr, message);
1049
+ commandExitState.exitCode = 1;
1050
+ }
1051
+ });
1052
+ plugin
1053
+ .command('build')
1054
+ .description('Build and inspect one source plugin bundle')
1055
+ .argument('<plugin-directory>', 'source plugin directory')
1056
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1057
+ .option('--out <path>', 'output path inside the workspace')
1058
+ .option('--force', 'replace an existing generated output', false)
1059
+ .option('--json', 'emit one machine-readable JSON result', false)
1060
+ .action(async (pluginDirectory, rawOptions) => {
1061
+ try {
1062
+ await runPluginBuildCommand({
1063
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1064
+ pluginDirectory,
1065
+ out: rawOptions.out,
1066
+ force: rawOptions.force,
1067
+ json: rawOptions.json,
1068
+ io,
1069
+ });
1070
+ }
1071
+ catch (error) {
1072
+ const message = error instanceof Error ? error.message : String(error);
1073
+ if (rawOptions.json)
1074
+ writeJsonReceipt(io.stdout, { command: 'plugin:build', ok: false, errors: [{ message }] });
1075
+ writeLine(io.stderr, message);
1076
+ commandExitState.exitCode = 1;
1077
+ }
1078
+ });
1079
+ plugin
1080
+ .command('status')
1081
+ .description('Show current plugin status or compare against an explicit Git base')
1082
+ .argument('[plugin-name]', 'one explicit plugin name')
1083
+ .option('--all', 'check every current workspace plugin', false)
1084
+ .option('--base <git-ref>', 'explicit Git comparison base')
1085
+ .option('--json', 'emit one schema v3 JSON document', false)
1086
+ .option('--workspace-root <path>', 'workspace root (default: current directory)');
1087
+ plugin
1088
+ .command('check-versions')
1089
+ .description('Deprecated alias for plugin status')
1090
+ .argument('[plugin-name]', 'one explicit plugin name')
1091
+ .option('--all', 'check every plugin changed relative to the Git base', false)
1092
+ .option('--base <git-ref>', 'explicit Git comparison base')
1093
+ .option('--json', 'emit one schema v3 JSON document', false)
1094
+ .option('--workspace-root <path>', 'workspace root (default: current directory)');
1095
+ skill
1096
+ .command('validate')
1097
+ .description('Validate one Agent Skill directory')
1098
+ .argument('<skill-directory>', 'Agent Skill directory')
1099
+ .option('--frontmatter-profile <profile>', 'portable-agent-skills | claude-2.1.88 | claude-current (default: portable-agent-skills)')
1100
+ .option('--codex-metadata <policy>', 'required | optional | ignore (default: optional)')
1101
+ .option('--json', 'emit one machine-readable JSON result', false);
1102
+ const catalog = program
1103
+ .command('catalog')
1104
+ .description('Build and manage catalogs');
1105
+ catalog
1106
+ .command('init')
1107
+ .description('Initialize a local AW plugin workspace')
1108
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1109
+ .option('--owner-name <name>', 'catalog owner name')
1110
+ .option('--owner-url <url>', 'catalog owner URL')
1111
+ .option('--display-name <name>', 'catalog display name')
1112
+ .option('--catalog-version <version>', 'initial stable or x.y.z-beta.N catalog version (default: 0.1.0)')
1113
+ .option('--force', 'repair a matching managed workspace scaffold', false)
1114
+ .option('--json', 'emit one machine-readable JSON result', false)
1115
+ .action(async (rawOptions) => {
1116
+ try {
1117
+ await runCatalogInitCommand({
1118
+ ...rawOptions,
1119
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1120
+ io,
1121
+ });
1122
+ }
1123
+ catch (error) {
1124
+ const message = error instanceof Error ? error.message : String(error);
1125
+ if (rawOptions.json)
1126
+ writeJsonReceipt(io.stdout, { command: 'catalog:init', ok: false, errors: [{ message }] });
1127
+ writeLine(io.stderr, message);
1128
+ commandExitState.exitCode = 1;
1129
+ }
1130
+ });
1131
+ catalog
1132
+ .command('version')
1133
+ .description('Read or set the workspace catalog version')
1134
+ .argument('[version]', 'stable or x.y.z-beta.N catalog version')
1135
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1136
+ .option('--json', 'emit one machine-readable JSON result', false)
1137
+ .action(async (version, rawOptions) => {
1138
+ try {
1139
+ await runCatalogVersionCommand({
1140
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1141
+ version,
1142
+ json: rawOptions.json,
1143
+ io,
1144
+ });
1145
+ }
1146
+ catch (error) {
1147
+ const message = error instanceof Error ? error.message : String(error);
1148
+ if (rawOptions.json)
1149
+ writeJsonReceipt(io.stdout, { command: 'catalog:version', ok: false, errors: [{ message }] });
1150
+ writeLine(io.stderr, message);
1151
+ commandExitState.exitCode = 1;
1152
+ }
1153
+ });
1154
+ catalog
1155
+ .command('build')
1156
+ .description('Build a deterministic development Catalog snapshot')
1157
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1158
+ .option('--out <path>', 'output path inside the workspace')
1159
+ .option('--force', 'replace an existing generated output', false)
1160
+ .option('--json', 'emit one machine-readable JSON result', false)
1161
+ .action(async (rawOptions) => {
1162
+ try {
1163
+ await runCatalogBuildCommand({
1164
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1165
+ out: rawOptions.out,
1166
+ force: rawOptions.force,
1167
+ json: rawOptions.json,
1168
+ io,
1169
+ });
1170
+ }
1171
+ catch (error) {
1172
+ const message = error instanceof Error ? error.message : String(error);
1173
+ if (rawOptions.json)
1174
+ writeJsonReceipt(io.stdout, { command: 'catalog:build', ok: false, errors: [{ message }] });
1175
+ writeLine(io.stderr, message);
1176
+ commandExitState.exitCode = 1;
1177
+ }
1178
+ });
1179
+ catalog
1180
+ .command('validate')
1181
+ .description('Validate a schema 4 Catalog snapshot')
1182
+ .argument('<snapshot-directory>', 'Catalog snapshot directory')
1183
+ .option('--json', 'emit one machine-readable JSON result', false)
1184
+ .action(async (snapshotDirectory, rawOptions) => {
1185
+ try {
1186
+ await runCatalogValidateCommand({
1187
+ snapshotDirectory: path.resolve(cwd, snapshotDirectory),
1188
+ json: rawOptions.json,
1189
+ io,
1190
+ });
1191
+ }
1192
+ catch (error) {
1193
+ const message = error instanceof Error ? error.message : String(error);
1194
+ if (rawOptions.json)
1195
+ writeJsonReceipt(io.stdout, { command: 'catalog:validate', ok: false, errors: [{ message }] });
1196
+ writeLine(io.stderr, message);
1197
+ commandExitState.exitCode = 1;
1198
+ }
1199
+ });
1200
+ catalog
1201
+ .command('publish')
1202
+ .description('Publish a versioned Catalog snapshot to a configured Git remote')
1203
+ .option('--workspace-root <path>', 'workspace root (default: current directory)')
1204
+ .option('--remote <name>', 'configured Git remote name (default: origin)')
1205
+ .option('--branch <name>', 'dedicated Catalog branch (default: catalog)')
1206
+ .option('-y, --yes', 'confirm publication without a prompt', false)
1207
+ .option('--json', 'emit one machine-readable JSON result', false)
1208
+ .action(async (rawOptions) => {
1209
+ try {
1210
+ const context = createActionContext('catalog:publish', {});
1211
+ const result = await runCatalogPublishCommand({
1212
+ workspaceRoot: path.resolve(cwd, rawOptions.workspaceRoot ?? '.'),
1213
+ remote: rawOptions.remote,
1214
+ branch: rawOptions.branch,
1215
+ yes: rawOptions.yes,
1216
+ json: rawOptions.json,
1217
+ env,
1218
+ interactive: context.interactive,
1219
+ ...(context.prompt.confirm ? {
1220
+ confirm: async (message) => {
1221
+ const response = await context.prompt.confirm({ message, defaultValue: false });
1222
+ return !response.cancelled && response.value === true;
1223
+ },
1224
+ } : {}),
1225
+ io,
1226
+ });
1227
+ if (!result)
1228
+ return;
1229
+ if (rawOptions.json)
1230
+ writeJsonReceipt(io.stdout, result);
1231
+ else {
1232
+ writeLine(io.stdout, `Published Catalog ${result.catalogVersion} to ${result.remote} (${result.pushUrl}).`);
1233
+ writeLine(io.stdout, `Branch: refs/heads/${result.branch}`);
1234
+ writeLine(io.stdout, `Tag: refs/tags/${result.tag}`);
1235
+ writeLine(io.stdout, `Commit: ${result.commit}`);
1236
+ writeLine(io.stdout, `Add it as a source: aw catalog source add <id> --git ${result.fetchUrl} --ref refs/heads/${result.branch}`);
1237
+ }
1238
+ }
1239
+ catch (error) {
1240
+ const message = error instanceof Error ? error.message : String(error);
1241
+ if (rawOptions.json)
1242
+ writeJsonReceipt(io.stdout, {
1243
+ command: 'catalog:publish',
1244
+ ok: false,
1245
+ errors: [{ message }],
1246
+ });
1247
+ writeLine(io.stderr, message);
1248
+ commandExitState.exitCode = 1;
1249
+ }
1250
+ });
1251
+ const catalogSource = catalog
1252
+ .command('source')
1253
+ .description('Manage catalog sources');
1254
+ const writeCatalogSourceFailure = async (command, sourceId, json, error, sensitiveRoots = []) => {
1255
+ const failure = sanitizeCatalogSourceError(error, env, sensitiveRoots);
1256
+ const message = failure instanceof Error ? failure.message : String(error);
1257
+ if (json) {
1258
+ writeJsonReceipt(io.stdout, {
1259
+ receiptSchemaVersion: 4,
1260
+ command,
1261
+ ok: false,
1262
+ changed: false,
1263
+ sourceId,
1264
+ references: failure.inventory?.references ?? [],
1265
+ errors: [{ code: failure.code ?? failure.name ?? 'catalogSourceMutationFailed', message }],
1266
+ });
1267
+ }
1268
+ writeLine(io.stderr, message);
1269
+ commandExitState.exitCode = 1;
1270
+ };
1271
+ const writeConfigMutationFailure = (command, plugin, json, error) => {
1272
+ const message = error instanceof Error ? error.message : String(error);
1273
+ const code = message.includes('legacyStateUnsupported')
1274
+ ? 'legacyStateUnsupported'
1275
+ : message.includes('sourceChanged')
1276
+ ? 'sourceChanged'
1277
+ : message.includes('sourceMissing')
1278
+ ? 'sourceMissing'
1279
+ : message.startsWith('Cannot resolve required catalog sources:')
1280
+ ? 'catalogSourceUnavailable'
1281
+ : message.split(':', 1)[0] || 'configMutationFailed';
1282
+ if (json && !message.includes('Usage:')) {
1283
+ writeJsonReceipt(io.stdout, {
1284
+ receiptSchemaVersion: 4,
1285
+ command,
1286
+ ok: false,
1287
+ overallState: 'failed',
1288
+ ...(plugin ? { plugin } : {}),
1289
+ errors: [{ code, message }],
1290
+ });
1291
+ }
1292
+ writeLine(io.stderr, message);
1293
+ commandExitState.exitCode = 1;
1294
+ };
1295
+ const withResolvedConfigMutationPlugin = (context, selector, consume) => withAwHomeMutationLock({
1296
+ env: context.env,
1297
+ action: (awHomeMutationToken) => withResolvedCatalogPlugin({
1298
+ selector,
1299
+ cliVersion: resolveCliVersion(),
1300
+ freshnessPolicy: 'requireRemote',
1301
+ env: context.env,
1302
+ consume: (resolution) => consume(resolution, awHomeMutationToken),
1303
+ }),
1304
+ });
1305
+ catalogSource
1306
+ .command('list')
1307
+ .option('-j, --json', 'print catalog sources as JSON', false)
1308
+ .action(async (rawOptions) => {
1309
+ const payload = await listCatalogSources({ env });
1310
+ if (rawOptions.json) {
1311
+ writeJsonReceipt(io.stdout, payload);
1312
+ return;
1313
+ }
1314
+ writeLine(io.stdout, `Primary source: ${payload.primarySourceId}`);
1315
+ for (const source of payload.sources) {
1316
+ writeLine(io.stdout, `${source.primary ? '*' : '-'} ${source.id} ${source.type} ${source.sourceIdentity}`);
1317
+ }
1318
+ });
1319
+ catalogSource
1320
+ .command('add')
1321
+ .argument('<id>')
1322
+ .addOption(new Option('--git <url>', 'add a Git catalog source'))
1323
+ .addOption(new Option('--path <path>', 'add a local path catalog source'))
1324
+ .addOption(new Option('--ref <ref>', 'use an explicit Git ref'))
1325
+ .addOption(new Option('--default-ref', 'select the Git ref from the CLI release channel'))
1326
+ .option('--subdir <path>', 'use a catalog snapshot below the Git repository root')
1327
+ .option('--primary', 'make this source primary', false)
1328
+ .option('-j, --json', 'print mutation receipt as JSON', false)
1329
+ .action(async (id, rawOptions) => {
1330
+ try {
1331
+ if ((rawOptions.git === undefined) === (rawOptions.path === undefined)) {
1332
+ throw new Error('catalog source add requires exactly one of `--git` or `--path`.');
1333
+ }
1334
+ if (rawOptions.git !== undefined && ((rawOptions.ref === undefined) === (rawOptions.defaultRef !== true))) {
1335
+ throw new Error('Git catalog source add requires exactly one of `--ref` or `--default-ref`.');
1336
+ }
1337
+ if (rawOptions.path !== undefined && (rawOptions.ref !== undefined || rawOptions.defaultRef === true || rawOptions.subdir !== undefined)) {
1338
+ throw new Error('Path catalog source add only accepts `--path` and `--primary`.');
1339
+ }
1340
+ const source = rawOptions.git !== undefined
1341
+ ? {
1342
+ id,
1343
+ type: 'git',
1344
+ primary: rawOptions.primary === true,
1345
+ url: rawOptions.git,
1346
+ refPolicy: explicitRefPolicy(rawOptions.ref, rawOptions.defaultRef === true),
1347
+ ...(rawOptions.subdir ? { subdir: rawOptions.subdir } : {}),
1348
+ }
1349
+ : {
1350
+ id,
1351
+ type: 'path',
1352
+ primary: rawOptions.primary === true,
1353
+ path: rawOptions.path,
1354
+ };
1355
+ const receipt = await addCatalogSourceCommand({
1356
+ source,
1357
+ cliVersion: resolveCliVersion(),
1358
+ cwd,
1359
+ env,
1360
+ });
1361
+ if (rawOptions.json)
1362
+ writeJsonReceipt(io.stdout, receipt);
1363
+ else
1364
+ writeLine(io.stdout, `Catalog source ${id} added.`);
1365
+ for (const diagnostic of receipt.errors)
1366
+ writeLine(io.stderr, `Warning: ${diagnostic.message}`);
1367
+ }
1368
+ catch (error) {
1369
+ await writeCatalogSourceFailure('catalog:source:add', id, rawOptions.json === true, error, rawOptions.path === undefined ? [] : [rawOptions.path, path.resolve(cwd, rawOptions.path)]);
1370
+ }
1371
+ });
1372
+ catalogSource
1373
+ .command('update')
1374
+ .argument('<id>')
1375
+ .addOption(new Option('--git <url>', 'update a Git catalog URL'))
1376
+ .addOption(new Option('--path <path>', 'update a local catalog path'))
1377
+ .addOption(new Option('--ref <ref>', 'use an explicit Git ref'))
1378
+ .addOption(new Option('--default-ref', 'select the Git ref from the CLI release channel'))
1379
+ .addOption(new Option('--subdir <path>', 'update the Git catalog subdirectory'))
1380
+ .addOption(new Option('--no-subdir', 'remove the Git catalog subdirectory'))
1381
+ .option('-j, --json', 'print mutation receipt as JSON', false)
1382
+ .action(async (id, rawOptions) => {
1383
+ try {
1384
+ if (rawOptions.git !== undefined && rawOptions.path !== undefined) {
1385
+ throw new Error('catalog source update cannot combine `--git` and `--path`.');
1386
+ }
1387
+ if (rawOptions.ref !== undefined && rawOptions.defaultRef === true) {
1388
+ throw new Error('catalog source update cannot combine `--ref` and `--default-ref`.');
1389
+ }
1390
+ const hasUpdate = rawOptions.git !== undefined
1391
+ || rawOptions.path !== undefined
1392
+ || rawOptions.ref !== undefined
1393
+ || rawOptions.defaultRef === true
1394
+ || rawOptions.subdir !== undefined;
1395
+ if (!hasUpdate)
1396
+ throw new Error('catalog source update requires at least one update option.');
1397
+ if (rawOptions.path !== undefined && (rawOptions.ref !== undefined || rawOptions.defaultRef === true || rawOptions.subdir !== undefined))
1398
+ throw new Error('Path catalog source update only accepts `--path`.');
1399
+ const update = rawOptions.path !== undefined
1400
+ ? { type: 'path', path: rawOptions.path }
1401
+ : {
1402
+ type: 'git',
1403
+ ...(rawOptions.git !== undefined ? { url: rawOptions.git } : {}),
1404
+ ...(rawOptions.ref !== undefined || rawOptions.defaultRef === true
1405
+ ? { refPolicy: explicitRefPolicy(rawOptions.ref, rawOptions.defaultRef === true) }
1406
+ : {}),
1407
+ ...(rawOptions.subdir !== undefined
1408
+ ? { subdir: rawOptions.subdir === false ? null : rawOptions.subdir }
1409
+ : {}),
1410
+ };
1411
+ const receipt = await updateCatalogSourceCommand({
1412
+ sourceId: id,
1413
+ update,
1414
+ cliVersion: resolveCliVersion(),
1415
+ cwd,
1416
+ env,
1417
+ });
1418
+ if (rawOptions.json)
1419
+ writeJsonReceipt(io.stdout, receipt);
1420
+ else
1421
+ writeLine(io.stdout, `Catalog source ${id} updated.`);
1422
+ for (const diagnostic of receipt.errors)
1423
+ writeLine(io.stderr, `Warning: ${diagnostic.message}`);
1424
+ }
1425
+ catch (error) {
1426
+ await writeCatalogSourceFailure('catalog:source:update', id, rawOptions.json === true, error, rawOptions.path === undefined ? [] : [rawOptions.path, path.resolve(cwd, rawOptions.path)]);
1427
+ }
1428
+ });
1429
+ catalogSource
1430
+ .command('set-primary')
1431
+ .argument('<id>')
1432
+ .option('-j, --json', 'print mutation receipt as JSON', false)
1433
+ .action(async (id, rawOptions) => {
1434
+ try {
1435
+ const receipt = await setPrimaryCatalogSourceCommand({ sourceId: id, cwd, env });
1436
+ if (rawOptions.json)
1437
+ writeJsonReceipt(io.stdout, receipt);
1438
+ else
1439
+ writeLine(io.stdout, `Primary catalog source set to ${id}.`);
1440
+ }
1441
+ catch (error) {
1442
+ await writeCatalogSourceFailure('catalog:source:set-primary', id, rawOptions.json === true, error);
1443
+ }
1444
+ });
1445
+ catalogSource
1446
+ .command('remove')
1447
+ .argument('<id>')
1448
+ .option('-j, --json', 'print mutation receipt as JSON', false)
1449
+ .action(async (id, rawOptions) => {
1450
+ try {
1451
+ const receipt = await removeCatalogSourceCommand({ sourceId: id, cwd, env });
1452
+ if (rawOptions.json)
1453
+ writeJsonReceipt(io.stdout, receipt);
1454
+ else
1455
+ writeLine(io.stdout, `Catalog source ${id} removed.`);
1456
+ }
1457
+ catch (error) {
1458
+ await writeCatalogSourceFailure('catalog:source:remove', id, rawOptions.json === true, error);
1459
+ }
1460
+ });
1461
+ program
1462
+ .command('init')
1463
+ .option('-f, --force', 're-fetch and rebuild the current catalog cache entry', false)
1464
+ .option('-j, --json', 'print receipt as JSON', false)
1465
+ .option('-v, --verbose', 'show command diagnostics', false)
1466
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1467
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1468
+ .action(async (rawOptions) => {
1469
+ const context = createActionContext('init', rawOptions);
1470
+ const result = await runActionWithContext(context, () => initCommand({
1471
+ force: rawOptions.force,
1472
+ cliVersion: resolveCliVersion(),
1473
+ env: context.env,
1474
+ }));
1475
+ if (rawOptions.json) {
1476
+ writeJsonReceipt(io.stdout, buildInitReceiptJson(result));
1477
+ }
1478
+ else {
1479
+ for (const line of renderInitReceipt(result)) {
1480
+ writeLine(io.stdout, line);
1481
+ }
1482
+ }
1483
+ writeWarnings(io.stderr, result.warnings, { actionableOnly: true });
1484
+ for (const source of result.sources) {
1485
+ if (!source.ok && source.error)
1486
+ writeLine(io.stderr, `${source.id}: ${source.error}`);
1487
+ }
1488
+ commandExitState.exitCode = result.ok ? 0 : 1;
1489
+ });
1490
+ program
1491
+ .command('install')
1492
+ .argument('[plugins...]')
1493
+ .option('-s, --scope <scope>', 'project or user')
1494
+ .option('-p, --platform <platform>', 'codex | claude | both')
1495
+ .option('--script-timeout <ms>', 'override plugin lifecycle script timeout in milliseconds')
1496
+ .option('-j, --json', 'print receipt as JSON', false)
1497
+ .option('-v, --verbose', 'show command diagnostics', false)
1498
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1499
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1500
+ .action(async (plugins, rawOptions) => {
1501
+ const context = createActionContext('install', rawOptions);
1502
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('install', plugins ?? [], rawOptions, context));
1503
+ if (outcome.cancelled)
1504
+ return;
1505
+ const receipt = outcome.result;
1506
+ if (rawOptions.json) {
1507
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('install', receipt));
1508
+ }
1509
+ else {
1510
+ for (const line of renderRebuildReceipt('install', receipt)) {
1511
+ writeLine(io.stdout, line);
1512
+ }
1513
+ }
1514
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
1515
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
1516
+ });
1517
+ program
1518
+ .command('uninstall')
1519
+ .argument('[plugins...]')
1520
+ .option('-s, --scope <scope>', 'project or user')
1521
+ .option('-p, --platform <platform>', 'codex | claude | both')
1522
+ .option('--script-timeout <ms>', 'override plugin lifecycle script timeout in milliseconds')
1523
+ .option('-j, --json', 'print receipt as JSON', false)
1524
+ .option('-v, --verbose', 'show command diagnostics', false)
1525
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1526
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1527
+ .action(async (plugins, rawOptions) => {
1528
+ const context = createActionContext('uninstall', rawOptions);
1529
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('uninstall', plugins ?? [], rawOptions, context));
1530
+ if (outcome.cancelled)
1531
+ return;
1532
+ const receipt = outcome.result;
1533
+ if (rawOptions.json) {
1534
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('uninstall', receipt));
1535
+ }
1536
+ else {
1537
+ for (const line of renderRebuildReceipt('uninstall', receipt)) {
1538
+ writeLine(io.stdout, line);
1539
+ }
1540
+ }
1541
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
1542
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
1543
+ });
1544
+ program
1545
+ .command('upgrade')
1546
+ .argument('[plugins...]')
1547
+ .option('-a, --all', 'upgrade all plugins', false)
1548
+ .option('-s, --scope <scope>', 'project or user')
1549
+ .option('-p, --platform <platform>', 'codex | claude | both')
1550
+ .option('--script-timeout <ms>', 'override plugin lifecycle script timeout in milliseconds')
1551
+ .option('-j, --json', 'print receipt as JSON', false)
1552
+ .option('-v, --verbose', 'show command diagnostics', false)
1553
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1554
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1555
+ .action(async (plugins, rawOptions) => {
1556
+ const context = createActionContext('upgrade', rawOptions);
1557
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('upgrade', plugins ?? [], rawOptions, context));
1558
+ if (outcome.cancelled)
1559
+ return;
1560
+ const receipt = outcome.result;
1561
+ if (rawOptions.json) {
1562
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('upgrade', receipt));
1563
+ }
1564
+ else {
1565
+ for (const line of renderRebuildReceipt('upgrade', receipt)) {
1566
+ writeLine(io.stdout, line);
1567
+ }
1568
+ }
1569
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
1570
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
1571
+ });
1572
+ program
1573
+ .command('cleanup')
1574
+ .argument('[plugins...]')
1575
+ .option('-s, --scope <scope>', 'project or user')
1576
+ .option('-p, --platform <platform>', 'codex | claude | both')
1577
+ .option('-j, --json', 'print cleanup result as JSON', false)
1578
+ .option('--force', 'remove exclusively owned plugin output without dependency protection', false)
1579
+ .option('-v, --verbose', 'show command diagnostics', false)
1580
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1581
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1582
+ .action(async (plugins, rawOptions) => {
1583
+ const context = createActionContext('cleanup', rawOptions);
1584
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('cleanup', plugins ?? [], rawOptions, context));
1585
+ if (outcome.cancelled)
1586
+ return;
1587
+ const result = outcome.result;
1588
+ if (rawOptions.json) {
1589
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('cleanup', result));
1590
+ }
1591
+ else {
1592
+ for (const line of renderRebuildReceipt('cleanup', result)) {
1593
+ writeLine(io.stdout, line);
1594
+ }
1595
+ }
1596
+ writeWarnings(io.stderr, result.warnings, { actionableOnly: true });
1597
+ commandExitState.exitCode = result.overallState === 'failed' ? 1 : 0;
1598
+ });
1599
+ program
1600
+ .command('reinstall')
1601
+ .argument('[plugins...]')
1602
+ .option('-s, --scope <scope>', 'project or user')
1603
+ .option('-p, --platform <platform>', 'codex | claude | both')
1604
+ .option('--script-timeout <ms>', 'override plugin lifecycle script timeout in milliseconds')
1605
+ .option('-j, --json', 'print receipt as JSON', false)
1606
+ .option('-v, --verbose', 'show command diagnostics', false)
1607
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1608
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1609
+ .action(async (plugins, rawOptions) => {
1610
+ const context = createActionContext('reinstall', rawOptions);
1611
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('reinstall', plugins ?? [], rawOptions, context));
1612
+ if (outcome.cancelled)
1613
+ return;
1614
+ const receipt = outcome.result;
1615
+ if (rawOptions.json) {
1616
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('reinstall', receipt));
1617
+ }
1618
+ else {
1619
+ const lines = renderRebuildReceipt('reinstall', receipt);
1620
+ for (const line of lines) {
1621
+ writeLine(io.stdout, line);
1622
+ }
1623
+ }
1624
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
1625
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
1626
+ });
1627
+ const config = program
1628
+ .command('config')
1629
+ .description('Manage AW plugin configuration');
1630
+ config
1631
+ .command('list')
1632
+ .argument('[plugin]')
1633
+ .option('-s, --scope <scope>', 'read only project or user config')
1634
+ .option('--local', 'read only the current project local override layer', false)
1635
+ .option('-j, --json', 'print config as JSON', false)
1636
+ .option('-v, --verbose', 'show command diagnostics', false)
1637
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1638
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1639
+ .action(async (pluginName, rawOptions) => {
1640
+ const context = createActionContext('config:list', rawOptions);
1641
+ const outcome = await runActionWithContext(context, async () => {
1642
+ resolveConfigProjectLayer(rawOptions);
1643
+ if (!rawOptions.local)
1644
+ resolveConfigReadResolution(rawOptions.scope);
1645
+ const execute = async (selectedPlugin) => resolveMultiSourceConfigRead({
1646
+ selector: selectedPlugin,
1647
+ rawOptions,
1648
+ context,
1649
+ });
1650
+ if (pluginName)
1651
+ return { cancelled: false, pluginName, value: await execute(pluginName) };
1652
+ if (!isWizardAvailable(context, rawOptions))
1653
+ throw new Error(configCommandUsage('list'));
1654
+ const currentCandidates = await loadWizardCandidates(context, {});
1655
+ const storedCandidates = await loadStoredConfigWizardCandidates(context, configReadStoreLocations(rawOptions));
1656
+ const candidates = mergeWizardCandidates(currentCandidates, storedCandidates);
1657
+ if (candidates.length === 0) {
1658
+ throw new Error('No plugin config candidates exist in the selected location.');
1659
+ }
1660
+ const result = await runCommandWizard(context, {
1661
+ command: 'config:list',
1662
+ candidates,
1663
+ initial: { plugins: [], scope: rawOptions.scope },
1664
+ pluginMode: 'single',
1665
+ ...equivalentConfigCommandProjection((selection) => ({
1666
+ command: 'list',
1667
+ plugin: selection.plugins[0],
1668
+ scope: rawOptions.scope,
1669
+ projectLayer: rawOptions.local ? 'local' : 'shared',
1670
+ })),
1671
+ execute: (selection) => execute(selection.plugins[0]),
1672
+ });
1673
+ return result.cancelled
1674
+ ? { cancelled: true }
1675
+ : { cancelled: false, pluginName: result.selection.plugins[0], value: result.value };
1676
+ });
1677
+ if (outcome.cancelled)
1678
+ return;
1679
+ const resolved = outcome.value;
1680
+ const selectedPluginName = resolved.pluginName;
1681
+ if (rawOptions.json) {
1682
+ writeJsonReceipt(io.stdout, {
1683
+ ok: true,
1684
+ configSchemaVersion: 4,
1685
+ command: 'config:list',
1686
+ plugin: selectedPluginName,
1687
+ pluginName: selectedPluginName,
1688
+ pluginId: resolved.pluginId,
1689
+ sourceId: resolved.sourceId,
1690
+ sourceIdentity: resolved.sourceIdentity,
1691
+ scope: rawOptions.local ? 'project' : rawOptions.scope ?? 'effective',
1692
+ projectLayer: rawOptions.local ? 'local' : 'shared',
1693
+ ...(resolved.result.schema ? { schema: resolved.result.schema } : {}),
1694
+ fields: resolved.result.fields,
1695
+ });
1696
+ }
1697
+ else {
1698
+ writeConfigReadHuman(io.stdout, resolved.result, resolved.pluginId);
1699
+ }
1700
+ });
1701
+ config
1702
+ .command('get')
1703
+ .argument('[plugin]')
1704
+ .argument('[key]')
1705
+ .option('-s, --scope <scope>', 'read only project or user config')
1706
+ .option('--local', 'read only the current project local override layer', false)
1707
+ .option('-j, --json', 'print config as JSON', false)
1708
+ .option('-v, --verbose', 'show command diagnostics', false)
1709
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1710
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1711
+ .action(async (pluginName, key, rawOptions) => {
1712
+ const context = createActionContext('config:get', rawOptions);
1713
+ const outcome = await runActionWithContext(context, async () => {
1714
+ resolveConfigProjectLayer(rawOptions);
1715
+ if (!rawOptions.local)
1716
+ resolveConfigReadResolution(rawOptions.scope);
1717
+ const execute = async (selectedPlugin) => resolveMultiSourceConfigRead({
1718
+ selector: selectedPlugin,
1719
+ ...(key === undefined ? {} : { key }),
1720
+ rawOptions,
1721
+ context,
1722
+ });
1723
+ if (pluginName)
1724
+ return { cancelled: false, pluginName, value: await execute(pluginName) };
1725
+ if (!isWizardAvailable(context, rawOptions))
1726
+ throw new Error(configCommandUsage('get'));
1727
+ const currentCandidates = await loadWizardCandidates(context, {});
1728
+ const storedCandidates = await loadStoredConfigWizardCandidates(context, configReadStoreLocations(rawOptions));
1729
+ const candidates = mergeWizardCandidates(currentCandidates, storedCandidates);
1730
+ if (candidates.length === 0) {
1731
+ throw new Error('No plugin config candidates exist in the selected location.');
1732
+ }
1733
+ const result = await runCommandWizard(context, {
1734
+ command: 'config:get',
1735
+ candidates,
1736
+ initial: { plugins: [], key, scope: rawOptions.scope },
1737
+ pluginMode: 'single',
1738
+ ...equivalentConfigCommandProjection((selection) => ({
1739
+ command: 'get',
1740
+ plugin: selection.plugins[0],
1741
+ key,
1742
+ scope: rawOptions.scope,
1743
+ projectLayer: rawOptions.local ? 'local' : 'shared',
1744
+ })),
1745
+ execute: (selection) => execute(selection.plugins[0]),
1746
+ });
1747
+ return result.cancelled
1748
+ ? { cancelled: true }
1749
+ : { cancelled: false, pluginName: result.selection.plugins[0], value: result.value };
1750
+ });
1751
+ if (outcome.cancelled)
1752
+ return;
1753
+ const resolved = outcome.value;
1754
+ const selectedPluginName = resolved.pluginName;
1755
+ if (rawOptions.json) {
1756
+ writeJsonReceipt(io.stdout, {
1757
+ ok: true,
1758
+ configSchemaVersion: 4,
1759
+ command: 'config:get',
1760
+ plugin: selectedPluginName,
1761
+ pluginName: selectedPluginName,
1762
+ pluginId: resolved.pluginId,
1763
+ sourceId: resolved.sourceId,
1764
+ sourceIdentity: resolved.sourceIdentity,
1765
+ key,
1766
+ scope: rawOptions.local ? 'project' : rawOptions.scope ?? 'effective',
1767
+ projectLayer: rawOptions.local ? 'local' : 'shared',
1768
+ ...(resolved.result.schema ? { schema: resolved.result.schema } : {}),
1769
+ fields: resolved.result.fields,
1770
+ });
1771
+ }
1772
+ else {
1773
+ writeConfigReadHuman(io.stdout, resolved.result, resolved.pluginId);
1774
+ }
1775
+ });
1776
+ config
1777
+ .command('set')
1778
+ .argument('[plugin]')
1779
+ .argument('[key]')
1780
+ .argument('[value]')
1781
+ .option('-s, --scope <scope>', 'project or user')
1782
+ .option('--local', 'write only the current project local override layer', false)
1783
+ .option('--value-json', 'parse value as a JSON literal', false)
1784
+ .option('-j, --json', 'print receipt as JSON', false)
1785
+ .option('-v, --verbose', 'show command diagnostics', false)
1786
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1787
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1788
+ .action(async (pluginName, key, rawValue, rawOptions) => {
1789
+ const context = createActionContext('config:set', rawOptions);
1790
+ let outcome;
1791
+ try {
1792
+ outcome = await runActionWithContext(context, async () => {
1793
+ const scope = resolveConfigWriteScope(rawOptions.scope);
1794
+ const projectLayer = resolveConfigProjectLayer(rawOptions);
1795
+ const execute = async (selectedPlugin, selectedKey, inputValue) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken) => {
1796
+ if (!plugin.manifest.config?.schema) {
1797
+ throw new Error(`configSchemaUnavailable: Plugin "${selectedPlugin}" does not declare an AW config schema.`);
1798
+ }
1799
+ if (!plugin.manifest.config.schema[selectedKey]) {
1800
+ throw new Error(`Unknown config key "${selectedKey}".`);
1801
+ }
1802
+ const writeReceipt = await applyPluginConfigWrite({
1803
+ plugin,
1804
+ pluginName: plugin.manifest.name,
1805
+ scope,
1806
+ projectLayer,
1807
+ cwd: context.cwd,
1808
+ env: context.env,
1809
+ nativeCliRunner: context.nativeCliRunner,
1810
+ rebuildRuntime: { ...context, awHomeMutationToken },
1811
+ awHomeMutationToken,
1812
+ request: {
1813
+ updates: { [selectedKey]: inputValue },
1814
+ },
1815
+ });
1816
+ return {
1817
+ ok: writeReceipt.overallState === 'succeeded',
1818
+ receiptSchemaVersion: 4,
1819
+ command: 'config:set',
1820
+ ...writeReceipt,
1821
+ plugin: plugin.manifest.name,
1822
+ pluginName: plugin.manifest.name,
1823
+ pluginId,
1824
+ sourceId: source.sourceId,
1825
+ sourceIdentity: source.sourceIdentity,
1826
+ affectedFields: [{
1827
+ key: selectedKey,
1828
+ title: plugin?.manifest.config?.schema?.[selectedKey]?.title ?? selectedKey,
1829
+ kind: 'manifest',
1830
+ reserved: false,
1831
+ action: 'set',
1832
+ scope,
1833
+ ...(scope === 'project' ? { projectLayer } : {}),
1834
+ }],
1835
+ };
1836
+ });
1837
+ if (pluginName && key && rawValue !== undefined) {
1838
+ const inputValue = parseConfigValue(rawValue, rawOptions.valueJson === true);
1839
+ return {
1840
+ cancelled: false,
1841
+ key,
1842
+ value: await execute(pluginName, key, inputValue),
1843
+ };
1844
+ }
1845
+ if (!isWizardAvailable(context, rawOptions))
1846
+ throw new Error(configCommandUsage('set'));
1847
+ const candidates = await loadWizardCandidates(context, {});
1848
+ if (pluginName) {
1849
+ const candidate = candidates.find((entry) => entry.pluginName === pluginName);
1850
+ if (!candidate)
1851
+ throw new Error(`Unknown plugin "${pluginName}".`);
1852
+ if (!hasConfigSchemaKeys(candidate)) {
1853
+ throw new Error(`configSchemaUnavailable: Plugin "${pluginName}" does not declare an AW config schema.`);
1854
+ }
1855
+ if (key && !candidate.configSchema?.[key])
1856
+ throw new Error(`Unknown config key "${key}".`);
1857
+ }
1858
+ const configurableCandidates = candidates.filter(hasConfigSchemaKeys);
1859
+ if (configurableCandidates.length === 0) {
1860
+ throw new Error('configSchemaUnavailable: No current plugin declares an AW config schema.');
1861
+ }
1862
+ const result = await runCommandWizard(context, {
1863
+ command: 'config:set',
1864
+ candidates: configurableCandidates,
1865
+ initial: {
1866
+ plugins: pluginName ? [pluginName] : [],
1867
+ key,
1868
+ ...(rawValue !== undefined ? { value: rawValue } : {}),
1869
+ scope,
1870
+ projectLayer,
1871
+ },
1872
+ pluginMode: pluginName ? 'none' : 'single',
1873
+ valueJson: rawOptions.valueJson === true,
1874
+ promptForKey: key === undefined,
1875
+ promptForValue: rawValue === undefined,
1876
+ ...equivalentConfigCommandProjection((selection) => configSetEquivalentOptions(selection, candidates, rawOptions)),
1877
+ commandIsTemplate: (selection) => candidates.find((entry) => entry.pluginName === selection.plugins[0])?.configSchema?.[selection.key ?? ''] !== undefined
1878
+ && configFieldPlaceholder(candidates.find((entry) => entry.pluginName === selection.plugins[0])?.configSchema?.[selection.key ?? '']) !== undefined,
1879
+ resultState: overallResultState,
1880
+ execute: async (selection) => {
1881
+ const selectedPlugin = selection.plugins[0];
1882
+ const selectedKey = selection.key;
1883
+ const schema = candidates.find((entry) => entry.pluginName === selectedPlugin).configSchema;
1884
+ const updates = await coercePluginConfigUpdates({
1885
+ schema,
1886
+ updates: {
1887
+ [selectedKey]: parseConfigValue(selection.value, rawOptions.valueJson === true),
1888
+ },
1889
+ cwd: context.cwd,
1890
+ });
1891
+ return execute(selectedPlugin, selectedKey, updates[selectedKey]);
1892
+ },
1893
+ });
1894
+ return result.cancelled
1895
+ ? { cancelled: true }
1896
+ : { cancelled: false, key: result.selection.key, value: result.value };
1897
+ });
1898
+ }
1899
+ catch (error) {
1900
+ writeConfigMutationFailure('config:set', pluginName, rawOptions.json === true, error);
1901
+ return;
1902
+ }
1903
+ if (outcome.cancelled)
1904
+ return;
1905
+ const receipt = outcome.value;
1906
+ const selectedKey = outcome.key;
1907
+ if (rawOptions.json) {
1908
+ writeJsonReceipt(io.stdout, receipt);
1909
+ }
1910
+ else {
1911
+ writeLine(io.stdout, `已写入 ${receipt.plugin}.${selectedKey}(${configLayerLabel(receipt.scope, receipt.projectLayer)}配置)。`);
1912
+ if (receipt.projectLayer === 'local') {
1913
+ writeProjectLocalConfigNotice(io.stdout);
1914
+ }
1915
+ writeConfigApplyNotice(io.stderr, receipt);
1916
+ }
1917
+ commandExitState.exitCode = receipt.overallState === 'failed' ? 1 : 0;
1918
+ });
1919
+ config
1920
+ .command('unset')
1921
+ .argument('[plugin]')
1922
+ .argument('[key]')
1923
+ .option('-s, --scope <scope>', 'project or user')
1924
+ .option('--local', 'write only the current project local override layer', false)
1925
+ .option('-j, --json', 'print receipt as JSON', false)
1926
+ .option('-v, --verbose', 'show command diagnostics', false)
1927
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
1928
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
1929
+ .action(async (pluginName, key, rawOptions) => {
1930
+ const context = createActionContext('config:unset', rawOptions);
1931
+ let outcome;
1932
+ try {
1933
+ outcome = await runActionWithContext(context, async () => {
1934
+ const scope = resolveConfigWriteScope(rawOptions.scope);
1935
+ const projectLayer = resolveConfigProjectLayer(rawOptions);
1936
+ const execute = async (selectedPlugin, selectedKey) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken) => {
1937
+ if (plugin.manifest.config?.schema && !plugin.manifest.config.schema[selectedKey]) {
1938
+ throw new Error(`Unknown config key "${selectedKey}".`);
1939
+ }
1940
+ const store = await readPluginConfigStore({
1941
+ sourceId: source.sourceId,
1942
+ sourceIdentity: source.sourceIdentity,
1943
+ pluginName: plugin.manifest.name,
1944
+ scope,
1945
+ ...(scope === 'project' ? { projectLayer } : {}),
1946
+ cwd: context.cwd,
1947
+ env: context.env,
1948
+ });
1949
+ const existed = Object.hasOwn(store.values, selectedKey);
1950
+ if (!existed)
1951
+ throw new Error(`Unknown config key "${selectedKey}".`);
1952
+ const writeReceipt = await applyPluginConfigWrite({
1953
+ plugin,
1954
+ pluginName: plugin.manifest.name,
1955
+ scope,
1956
+ projectLayer,
1957
+ cwd: context.cwd,
1958
+ env: context.env,
1959
+ nativeCliRunner: context.nativeCliRunner,
1960
+ rebuildRuntime: { ...context, awHomeMutationToken },
1961
+ awHomeMutationToken,
1962
+ request: {
1963
+ removeKeys: [selectedKey],
1964
+ },
1965
+ });
1966
+ return {
1967
+ ok: writeReceipt.overallState === 'succeeded',
1968
+ receiptSchemaVersion: 4,
1969
+ command: 'config:unset',
1970
+ ...writeReceipt,
1971
+ plugin: plugin.manifest.name,
1972
+ pluginName: plugin.manifest.name,
1973
+ pluginId,
1974
+ sourceId: source.sourceId,
1975
+ sourceIdentity: source.sourceIdentity,
1976
+ removedKey: selectedKey,
1977
+ existed,
1978
+ affectedFields: [{
1979
+ key: selectedKey,
1980
+ title: plugin?.manifest.config?.schema?.[selectedKey]?.title ?? selectedKey,
1981
+ kind: 'manifest',
1982
+ reserved: false,
1983
+ action: 'unset',
1984
+ scope,
1985
+ ...(scope === 'project' ? { projectLayer } : {}),
1986
+ }],
1987
+ };
1988
+ });
1989
+ if (pluginName && key) {
1990
+ return { cancelled: false, value: await execute(pluginName, key) };
1991
+ }
1992
+ if (!isWizardAvailable(context, rawOptions))
1993
+ throw new Error(configCommandUsage('unset'));
1994
+ const loadedCurrentCandidates = await loadWizardCandidates(context, {});
1995
+ const currentCandidates = loadedCurrentCandidates.filter(hasConfigSchemaKeys);
1996
+ const candidates = currentCandidates;
1997
+ if (pluginName && !candidates.some((entry) => entry.pluginName === pluginName)) {
1998
+ throw new Error(`Unknown plugin "${pluginName}".`);
1999
+ }
2000
+ if (candidates.length === 0) {
2001
+ throw new Error('No plugin config candidates exist in the selected location.');
2002
+ }
2003
+ const result = await runCommandWizard(context, {
2004
+ command: 'config:unset',
2005
+ candidates,
2006
+ initial: { plugins: pluginName ? [pluginName] : [], key, scope, projectLayer },
2007
+ pluginMode: pluginName ? 'none' : 'single',
2008
+ promptForKey: key === undefined,
2009
+ destructive: true,
2010
+ ...equivalentConfigCommandProjection((selection) => ({
2011
+ command: 'unset',
2012
+ plugin: selection.plugins[0],
2013
+ key: selection.key,
2014
+ scope: selection.scope ?? 'user',
2015
+ projectLayer: selection.projectLayer,
2016
+ })),
2017
+ resultState: overallResultState,
2018
+ execute: (selection) => execute(selection.plugins[0], selection.key),
2019
+ });
2020
+ return result.cancelled
2021
+ ? { cancelled: true }
2022
+ : { cancelled: false, value: result.value };
2023
+ });
2024
+ }
2025
+ catch (error) {
2026
+ writeConfigMutationFailure('config:unset', pluginName, rawOptions.json === true, error);
2027
+ return;
2028
+ }
2029
+ if (outcome.cancelled)
2030
+ return;
2031
+ const receipt = outcome.value;
2032
+ if (rawOptions.json) {
2033
+ writeJsonReceipt(io.stdout, receipt);
2034
+ }
2035
+ else {
2036
+ writeLine(io.stdout, receipt.existed
2037
+ ? `已删除 ${receipt.plugin}.${receipt.removedKey}(${configLayerLabel(receipt.scope, receipt.projectLayer)}配置)。`
2038
+ : `${receipt.plugin}.${receipt.removedKey}(${configLayerLabel(receipt.scope, receipt.projectLayer)}配置)原本不存在。`);
2039
+ if (receipt.projectLayer === 'local') {
2040
+ writeProjectLocalConfigNotice(io.stdout);
2041
+ }
2042
+ writeConfigApplyNotice(io.stderr, receipt);
2043
+ }
2044
+ commandExitState.exitCode = receipt.overallState === 'failed' ? 1 : 0;
2045
+ });
2046
+ config
2047
+ .command('reset')
2048
+ .argument('[plugin]')
2049
+ .option('-s, --scope <scope>', 'project or user')
2050
+ .option('--local', 'reset only the current project local override layer', false)
2051
+ .option('-y, --yes', 'confirm destructive reset', false)
2052
+ .option('-j, --json', 'print receipt as JSON', false)
2053
+ .option('-v, --verbose', 'show command diagnostics', false)
2054
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2055
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2056
+ .action(async (pluginName, rawOptions) => {
2057
+ const context = createActionContext('config:reset', rawOptions);
2058
+ let outcome;
2059
+ try {
2060
+ outcome = await runActionWithContext(context, async () => {
2061
+ const execute = async (selectedPlugin, selectedScope, projectLayer, confirmed) => {
2062
+ if (!confirmed) {
2063
+ throw new Error(`Reset requires confirmation. Re-run \`aw config reset ${selectedPlugin} -s ${selectedScope}${projectLayer === 'local' ? ' --local' : ''} --yes\` to delete this store.`);
2064
+ }
2065
+ return withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken) => {
2066
+ const affectedFields = await describeResetAffectedFields({
2067
+ pluginName: plugin.manifest.name,
2068
+ plugin,
2069
+ scope: selectedScope,
2070
+ projectLayer,
2071
+ cwd: context.cwd,
2072
+ env: context.env,
2073
+ });
2074
+ const resetReceipt = await resetPluginConfigWithHelper({
2075
+ pluginName: plugin.manifest.name,
2076
+ scope: selectedScope,
2077
+ projectLayer,
2078
+ cwd: context.cwd,
2079
+ env: context.env,
2080
+ nativeCliRunner: context.nativeCliRunner,
2081
+ rebuildRuntime: { ...context, awHomeMutationToken },
2082
+ awHomeMutationToken,
2083
+ plugin,
2084
+ });
2085
+ return {
2086
+ ok: resetReceipt.overallState === 'succeeded',
2087
+ receiptSchemaVersion: 4,
2088
+ command: 'config:reset',
2089
+ ...resetReceipt,
2090
+ plugin: plugin.manifest.name,
2091
+ pluginName: plugin.manifest.name,
2092
+ pluginId,
2093
+ sourceId: source.sourceId,
2094
+ sourceIdentity: source.sourceIdentity,
2095
+ affectedFields,
2096
+ };
2097
+ }).catch((error) => {
2098
+ const message = error instanceof Error ? error.message : String(error);
2099
+ if (message.includes('Catalog source')
2100
+ || message.startsWith('Cannot resolve required catalog sources:')) {
2101
+ throw new Error(`sourceMissing: ${selectedPlugin} source is unavailable; config store was not changed.`);
2102
+ }
2103
+ if (message.includes('does not exist in the required catalog source set')) {
2104
+ throw new Error(`configSchemaUnavailable: Plugin "${selectedPlugin}" is unavailable; config store was not changed.`);
2105
+ }
2106
+ throw error;
2107
+ });
2108
+ };
2109
+ const scope = resolveConfigWriteScope(rawOptions.scope);
2110
+ const projectLayer = resolveConfigProjectLayer(rawOptions);
2111
+ const needsWizard = pluginName === undefined || rawOptions.yes !== true;
2112
+ if (!needsWizard) {
2113
+ return {
2114
+ cancelled: false,
2115
+ value: await execute(pluginName, scope, projectLayer, true),
2116
+ };
2117
+ }
2118
+ if (!isWizardAvailable(context, rawOptions)) {
2119
+ if (!pluginName)
2120
+ throw new Error(configCommandUsage('reset'));
2121
+ return {
2122
+ cancelled: false,
2123
+ value: await execute(pluginName, scope, projectLayer, false),
2124
+ };
2125
+ }
2126
+ const currentCandidates = pluginName ? [] : await loadWizardCandidates(context, {});
2127
+ const candidatesByScope = new Map();
2128
+ if (!pluginName && (rawOptions.scope === undefined || scope === 'user')) {
2129
+ candidatesByScope.set('user', mergeWizardCandidates(currentCandidates, await loadStoredConfigWizardCandidates(context, [{ scope: 'user', projectLayer: 'shared' }], { includeEmptyStores: true })));
2130
+ }
2131
+ if (!pluginName && (rawOptions.scope === undefined || scope === 'project')) {
2132
+ candidatesByScope.set('project', mergeWizardCandidates(currentCandidates, await loadStoredConfigWizardCandidates(context, [{ scope: 'project', projectLayer }], { includeEmptyStores: true })));
2133
+ }
2134
+ const candidates = mergeWizardCandidates(candidatesByScope.get('user') ?? [], candidatesByScope.get('project') ?? []);
2135
+ if (!pluginName && candidates.length === 0) {
2136
+ throw new Error('No plugin config candidates exist in the selected location.');
2137
+ }
2138
+ const result = await runCommandWizard(context, {
2139
+ command: 'config:reset',
2140
+ candidates,
2141
+ initial: { plugins: pluginName ? [pluginName] : [], scope, projectLayer },
2142
+ pluginMode: pluginName ? 'none' : 'single',
2143
+ promptForScope: rawOptions.scope === undefined,
2144
+ destructive: true,
2145
+ isPluginVisible: (candidate, selection) => candidatesByScope
2146
+ .get(selection.scope ?? 'user')
2147
+ ?.some((entry) => entry.pluginName === candidate.pluginName) !== false,
2148
+ ...equivalentConfigCommandProjection((selection) => ({
2149
+ command: 'reset',
2150
+ plugin: selection.plugins[0],
2151
+ scope: selection.scope ?? 'user',
2152
+ projectLayer: selection.projectLayer,
2153
+ confirmed: true,
2154
+ })),
2155
+ resultState: overallResultState,
2156
+ execute: (selection) => execute(selection.plugins[0], selection.scope ?? 'user', selection.projectLayer ?? 'shared', true),
2157
+ });
2158
+ return result.cancelled
2159
+ ? { cancelled: true }
2160
+ : { cancelled: false, value: result.value };
2161
+ });
2162
+ }
2163
+ catch (error) {
2164
+ writeConfigMutationFailure('config:reset', pluginName, rawOptions.json === true, error);
2165
+ return;
2166
+ }
2167
+ if (outcome.cancelled)
2168
+ return;
2169
+ const receipt = outcome.value;
2170
+ if (rawOptions.json) {
2171
+ writeJsonReceipt(io.stdout, receipt);
2172
+ }
2173
+ else {
2174
+ writeLine(io.stdout, receipt.deleted
2175
+ ? `已重置 ${receipt.plugin} 的${configLayerLabel(receipt.scope, receipt.projectLayer)}配置。`
2176
+ : `${receipt.plugin} 没有可重置的${configLayerLabel(receipt.scope, receipt.projectLayer)}配置。`);
2177
+ if (receipt.projectLayer === 'local') {
2178
+ writeProjectLocalConfigNotice(io.stdout);
2179
+ }
2180
+ writeConfigApplyNotice(io.stderr, receipt);
2181
+ }
2182
+ commandExitState.exitCode = receipt.overallState === 'failed' ? 1 : 0;
2183
+ });
2184
+ program
2185
+ .command('status')
2186
+ .argument('[plugins...]')
2187
+ .option('-s, --scope <scope>', 'filter by scope')
2188
+ .option('-p, --platform <platform>', 'filter by platform')
2189
+ .option('-v, --verbose', 'show status details and command diagnostics', false)
2190
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2191
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2192
+ .option('-j, --json', 'print status as JSON', false)
2193
+ .action(async (plugins, rawOptions) => {
2194
+ const context = createActionContext('status', rawOptions);
2195
+ const result = await runActionWithContext(context, () => statusCommandV4({
2196
+ plugins: plugins ?? [],
2197
+ cwd,
2198
+ env: context.env,
2199
+ cliVersion: resolveCliVersion(),
2200
+ platform: rawOptions.platform,
2201
+ scope: rawOptions.scope,
2202
+ json: rawOptions.json,
2203
+ verbose: rawOptions.verbose,
2204
+ }));
2205
+ commandExitState.exitCode = result.hasErrors ? 1 : 0;
2206
+ writeLine(io.stdout, result.output);
2207
+ for (const source of result.payload.catalog.sources) {
2208
+ if (source.error)
2209
+ writeLine(io.stderr, `${source.id}: ${source.error}`);
2210
+ }
2211
+ for (const error of result.payload.errors) {
2212
+ if (error.code !== 'nativeStateUnreadable' && error.code !== 'stateInventoryFailed') {
2213
+ writeLine(io.stderr, error.message);
2214
+ }
2215
+ }
2216
+ });
2217
+ Object.assign(program, { __awCommandExitState: commandExitState });
2218
+ return program;
2219
+ }
2220
+ function handleCliError(error, writeError) {
2221
+ if (error instanceof CommanderError) {
2222
+ return error.exitCode;
2223
+ }
2224
+ if (isCommandWarningError(error)) {
2225
+ writeWarnings(writeError, error.warnings);
2226
+ writeLine(writeError, error.message);
2227
+ return error.exitCode;
2228
+ }
2229
+ writeLine(writeError, error instanceof Error ? error.message : String(error));
2230
+ return 1;
2231
+ }
2232
+ export async function runCli(argv, options = {}) {
2233
+ const io = {
2234
+ ...createDefaultIo(),
2235
+ ...options.io,
2236
+ };
2237
+ const jsonAuthoringCommand = argv.includes('--json')
2238
+ && ((argv[0] === 'catalog' && ['init', 'version', 'build', 'validate', 'publish'].includes(argv[1] ?? ''))
2239
+ || (argv[0] === 'plugin' && ['build', 'test'].includes(argv[1] ?? '')))
2240
+ ? `${argv[0]}:${argv[1]}`
2241
+ : null;
2242
+ try {
2243
+ const authoringScriptByCommand = {
2244
+ init: 'init-plugin.mjs',
2245
+ 'add-skill': 'add-skill.mjs',
2246
+ validate: 'validate-plugin.mjs',
2247
+ status: 'plugin-status.mjs',
2248
+ 'check-versions': 'check-plugin-versions.mjs',
2249
+ };
2250
+ const authoringScript = argv[0] === 'plugin'
2251
+ ? authoringScriptByCommand[argv[1] ?? '']
2252
+ : argv[0] === 'skill' && argv[1] === 'validate'
2253
+ ? 'validate-skill.mjs'
2254
+ : undefined;
2255
+ if (authoringScript && !argv.includes('--help') && !argv.includes('-h')) {
2256
+ const authoringArgs = argv.slice(2);
2257
+ if (argv[0] === 'plugin'
2258
+ && argv[1] === 'validate'
2259
+ && !authoringArgs.some((token) => token === '--workspace-root' || token.startsWith('--workspace-root='))) {
2260
+ authoringArgs.push('--workspace-root', options.cwd ?? process.cwd());
2261
+ }
2262
+ return runAuthoringScript({
2263
+ scriptName: authoringScript,
2264
+ args: authoringArgs,
2265
+ cwd: options.cwd ?? process.cwd(),
2266
+ env: options.env ?? process.env,
2267
+ io,
2268
+ });
2269
+ }
2270
+ if (argv.some((token) => token === '--subdir' || token.startsWith('--subdir='))
2271
+ && argv.includes('--no-subdir')) {
2272
+ const message = 'option --subdir cannot be used with option --no-subdir';
2273
+ if (argv.includes('--json') && argv[0] === 'catalog' && argv[1] === 'source' && argv[2] === 'update') {
2274
+ writeJsonReceipt(io.stdout, {
2275
+ receiptSchemaVersion: 4,
2276
+ command: 'catalog:source:update',
2277
+ ok: false,
2278
+ changed: false,
2279
+ sourceId: argv[3] ?? '',
2280
+ references: [],
2281
+ errors: [{ code: 'catalogSourceOptionConflict', message }],
2282
+ });
2283
+ }
2284
+ writeLine(io.stderr, `error: ${message}`);
2285
+ return 1;
2286
+ }
2287
+ const bareConsoleOptions = parseBareConsoleOptions(argv);
2288
+ if (bareConsoleOptions) {
2289
+ const context = createCliExecutionContext({
2290
+ ...options,
2291
+ io,
2292
+ env: options.env ?? process.env,
2293
+ diagnostics: {
2294
+ ...toCliDiagnosticsOptions('console', bareConsoleOptions, options.diagnostics),
2295
+ metadata: {
2296
+ ...options.diagnostics?.metadata,
2297
+ argCount: argv.length,
2298
+ },
2299
+ },
2300
+ });
2301
+ if (!context.interactive) {
2302
+ writeLine(io.stderr, formatInteractiveConsoleUnavailableMessage(context));
2303
+ return 1;
2304
+ }
2305
+ return await runActionWithContext(context, () => runConsoleController(context));
2306
+ }
2307
+ const program = buildProgram({
2308
+ ...options,
2309
+ io,
2310
+ diagnostics: {
2311
+ ...options.diagnostics,
2312
+ metadata: {
2313
+ ...options.diagnostics?.metadata,
2314
+ argCount: argv.length,
2315
+ },
2316
+ },
2317
+ });
2318
+ await program.parseAsync(['node', 'aw', ...argv]);
2319
+ return program.__awCommandExitState?.exitCode ?? 0;
2320
+ }
2321
+ catch (error) {
2322
+ if (jsonAuthoringCommand && error instanceof CommanderError) {
2323
+ writeJsonReceipt(io.stdout, {
2324
+ command: jsonAuthoringCommand,
2325
+ ok: false,
2326
+ errors: [{ code: 'invalidArguments', message: error.message }],
2327
+ });
2328
+ }
2329
+ return handleCliError(error, io.stderr);
2330
+ }
2331
+ }
2332
+ export async function main(argv = process.argv.slice(2), options = {}) {
2333
+ return runCli(argv, options);
2334
+ }
2335
+ const currentEntryPath = fileURLToPath(import.meta.url);
2336
+ const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : null;
2337
+ if (invokedPath === currentEntryPath) {
2338
+ void main().then((exitCode) => {
2339
+ if (exitCode !== 0) {
2340
+ process.exitCode = exitCode;
2341
+ }
2342
+ });
2343
+ }
2344
+ //# sourceMappingURL=index.js.map