@lesliechan721/aw 0.1.0-beta.10

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 (508) hide show
  1. package/dist/authoring/assets/aw-config.d.mts +51 -0
  2. package/dist/authoring/assets/aw-config.mjs +1025 -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/init-plugin.d.mts +2 -0
  8. package/dist/authoring/scripts/init-plugin.mjs +487 -0
  9. package/dist/authoring/scripts/init-plugin.mjs.map +1 -0
  10. package/dist/authoring/scripts/lib/javascript-import-scanner.d.mts +4 -0
  11. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs +261 -0
  12. package/dist/authoring/scripts/lib/javascript-import-scanner.mjs.map +1 -0
  13. package/dist/authoring/scripts/lib/plugin-root.d.mts +26 -0
  14. package/dist/authoring/scripts/lib/plugin-root.mjs +125 -0
  15. package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -0
  16. package/dist/authoring/scripts/lib/plugin-version-check.d.mts +69 -0
  17. package/dist/authoring/scripts/lib/plugin-version-check.mjs +563 -0
  18. package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -0
  19. package/dist/authoring/scripts/lib/semver.d.mts +9 -0
  20. package/dist/authoring/scripts/lib/semver.mjs +63 -0
  21. package/dist/authoring/scripts/lib/semver.mjs.map +1 -0
  22. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +111 -0
  23. package/dist/authoring/scripts/lib/skill-scaffold.mjs +353 -0
  24. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -0
  25. package/dist/authoring/scripts/plugin-status.d.mts +2 -0
  26. package/dist/authoring/scripts/plugin-status.mjs +93 -0
  27. package/dist/authoring/scripts/plugin-status.mjs.map +1 -0
  28. package/dist/authoring/scripts/remove-plugin.d.mts +2 -0
  29. package/dist/authoring/scripts/remove-plugin.mjs +367 -0
  30. package/dist/authoring/scripts/remove-plugin.mjs.map +1 -0
  31. package/dist/authoring/scripts/validate-plugin.d.mts +2 -0
  32. package/dist/authoring/scripts/validate-plugin.mjs +3465 -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/authoring/templates/aw-config-runtime.d.mts +2 -0
  38. package/dist/authoring/templates/aw-config-runtime.mjs +407 -0
  39. package/dist/authoring/templates/aw-config-runtime.mjs.map +1 -0
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.js +8 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
  44. package/dist/scripts/aw-skill-eval-materializer.js +309 -0
  45. package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
  46. package/dist/scripts/bundle-plugins.d.ts +17 -0
  47. package/dist/scripts/bundle-plugins.js +126 -0
  48. package/dist/scripts/bundle-plugins.js.map +1 -0
  49. package/dist/scripts/plugin-staging.d.ts +26 -0
  50. package/dist/scripts/plugin-staging.js +76 -0
  51. package/dist/scripts/plugin-staging.js.map +1 -0
  52. package/dist/scripts/test-plugin-scripts.d.ts +7 -0
  53. package/dist/scripts/test-plugin-scripts.js +610 -0
  54. package/dist/scripts/test-plugin-scripts.js.map +1 -0
  55. package/dist/src/adapters/helpers.d.ts +44 -0
  56. package/dist/src/adapters/helpers.js +95 -0
  57. package/dist/src/adapters/helpers.js.map +1 -0
  58. package/dist/src/authoring/workspace-commands.d.ts +70 -0
  59. package/dist/src/authoring/workspace-commands.js +158 -0
  60. package/dist/src/authoring/workspace-commands.js.map +1 -0
  61. package/dist/src/commands/aw-capabilities.d.ts +78 -0
  62. package/dist/src/commands/aw-capabilities.js +254 -0
  63. package/dist/src/commands/aw-capabilities.js.map +1 -0
  64. package/dist/src/commands/catalog-dev-source.d.ts +120 -0
  65. package/dist/src/commands/catalog-dev-source.js +434 -0
  66. package/dist/src/commands/catalog-dev-source.js.map +1 -0
  67. package/dist/src/commands/catalog-generation.d.ts +16 -0
  68. package/dist/src/commands/catalog-generation.js +9 -0
  69. package/dist/src/commands/catalog-generation.js.map +1 -0
  70. package/dist/src/commands/catalog-publication-inspection.d.ts +138 -0
  71. package/dist/src/commands/catalog-publication-inspection.js +711 -0
  72. package/dist/src/commands/catalog-publication-inspection.js.map +1 -0
  73. package/dist/src/commands/catalog-publication-journal.d.ts +56 -0
  74. package/dist/src/commands/catalog-publication-journal.js +215 -0
  75. package/dist/src/commands/catalog-publication-journal.js.map +1 -0
  76. package/dist/src/commands/catalog-publication-target.d.ts +18 -0
  77. package/dist/src/commands/catalog-publication-target.js +95 -0
  78. package/dist/src/commands/catalog-publication-target.js.map +1 -0
  79. package/dist/src/commands/catalog-publish.d.ts +103 -0
  80. package/dist/src/commands/catalog-publish.js +804 -0
  81. package/dist/src/commands/catalog-publish.js.map +1 -0
  82. package/dist/src/commands/catalog-source.d.ts +134 -0
  83. package/dist/src/commands/catalog-source.js +377 -0
  84. package/dist/src/commands/catalog-source.js.map +1 -0
  85. package/dist/src/commands/catalog-status.d.ts +56 -0
  86. package/dist/src/commands/catalog-status.js +217 -0
  87. package/dist/src/commands/catalog-status.js.map +1 -0
  88. package/dist/src/commands/catalog-store.d.ts +80 -0
  89. package/dist/src/commands/catalog-store.js +348 -0
  90. package/dist/src/commands/catalog-store.js.map +1 -0
  91. package/dist/src/commands/catalog-workspace-resolution.d.ts +13 -0
  92. package/dist/src/commands/catalog-workspace-resolution.js +42 -0
  93. package/dist/src/commands/catalog-workspace-resolution.js.map +1 -0
  94. package/dist/src/commands/console.d.ts +3 -0
  95. package/dist/src/commands/console.js +44 -0
  96. package/dist/src/commands/console.js.map +1 -0
  97. package/dist/src/commands/dependency-operation-plan.d.ts +58 -0
  98. package/dist/src/commands/dependency-operation-plan.js +261 -0
  99. package/dist/src/commands/dependency-operation-plan.js.map +1 -0
  100. package/dist/src/commands/init.d.ts +25 -0
  101. package/dist/src/commands/init.js +42 -0
  102. package/dist/src/commands/init.js.map +1 -0
  103. package/dist/src/commands/offline-cleanup-evidence.d.ts +59 -0
  104. package/dist/src/commands/offline-cleanup-evidence.js +163 -0
  105. package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
  106. package/dist/src/commands/operation-plan.d.ts +126 -0
  107. package/dist/src/commands/operation-plan.js +47 -0
  108. package/dist/src/commands/operation-plan.js.map +1 -0
  109. package/dist/src/commands/operation-planner.d.ts +46 -0
  110. package/dist/src/commands/operation-planner.js +139 -0
  111. package/dist/src/commands/operation-planner.js.map +1 -0
  112. package/dist/src/commands/options.d.ts +70 -0
  113. package/dist/src/commands/options.js +194 -0
  114. package/dist/src/commands/options.js.map +1 -0
  115. package/dist/src/commands/plugin-capabilities.d.ts +22 -0
  116. package/dist/src/commands/plugin-capabilities.js +159 -0
  117. package/dist/src/commands/plugin-capabilities.js.map +1 -0
  118. package/dist/src/commands/rebuild-command.d.ts +88 -0
  119. package/dist/src/commands/rebuild-command.js +3626 -0
  120. package/dist/src/commands/rebuild-command.js.map +1 -0
  121. package/dist/src/commands/rebuild-integration.d.ts +190 -0
  122. package/dist/src/commands/rebuild-integration.js +4439 -0
  123. package/dist/src/commands/rebuild-integration.js.map +1 -0
  124. package/dist/src/commands/rebuild-operations.d.ts +100 -0
  125. package/dist/src/commands/rebuild-operations.js +625 -0
  126. package/dist/src/commands/rebuild-operations.js.map +1 -0
  127. package/dist/src/commands/reconcile-operation-plan.d.ts +26 -0
  128. package/dist/src/commands/reconcile-operation-plan.js +28 -0
  129. package/dist/src/commands/reconcile-operation-plan.js.map +1 -0
  130. package/dist/src/commands/review-publication.d.ts +99 -0
  131. package/dist/src/commands/review-publication.js +904 -0
  132. package/dist/src/commands/review-publication.js.map +1 -0
  133. package/dist/src/commands/runtime.d.ts +172 -0
  134. package/dist/src/commands/runtime.js +720 -0
  135. package/dist/src/commands/runtime.js.map +1 -0
  136. package/dist/src/commands/skill-eval.d.ts +33 -0
  137. package/dist/src/commands/skill-eval.js +363 -0
  138. package/dist/src/commands/skill-eval.js.map +1 -0
  139. package/dist/src/commands/status-v6.d.ts +206 -0
  140. package/dist/src/commands/status-v6.js +2175 -0
  141. package/dist/src/commands/status-v6.js.map +1 -0
  142. package/dist/src/commands/sync-command.d.ts +23 -0
  143. package/dist/src/commands/sync-command.js +242 -0
  144. package/dist/src/commands/sync-command.js.map +1 -0
  145. package/dist/src/commands/wizard.d.ts +56 -0
  146. package/dist/src/commands/wizard.js +58 -0
  147. package/dist/src/commands/wizard.js.map +1 -0
  148. package/dist/src/commands/write-commands.d.ts +7 -0
  149. package/dist/src/commands/write-commands.js +190 -0
  150. package/dist/src/commands/write-commands.js.map +1 -0
  151. package/dist/src/constants.d.ts +31 -0
  152. package/dist/src/constants.js +32 -0
  153. package/dist/src/constants.js.map +1 -0
  154. package/dist/src/eval/manifest-v1.d.ts +67 -0
  155. package/dist/src/eval/manifest-v1.js +347 -0
  156. package/dist/src/eval/manifest-v1.js.map +1 -0
  157. package/dist/src/generators/agents.d.ts +3 -0
  158. package/dist/src/generators/agents.js +46 -0
  159. package/dist/src/generators/agents.js.map +1 -0
  160. package/dist/src/generators/hooks.d.ts +15 -0
  161. package/dist/src/generators/hooks.js +76 -0
  162. package/dist/src/generators/hooks.js.map +1 -0
  163. package/dist/src/generators/instructions.d.ts +13 -0
  164. package/dist/src/generators/instructions.js +66 -0
  165. package/dist/src/generators/instructions.js.map +1 -0
  166. package/dist/src/generators/local-plugin.d.ts +56 -0
  167. package/dist/src/generators/local-plugin.js +1373 -0
  168. package/dist/src/generators/local-plugin.js.map +1 -0
  169. package/dist/src/generators/permissions.d.ts +10 -0
  170. package/dist/src/generators/permissions.js +37 -0
  171. package/dist/src/generators/permissions.js.map +1 -0
  172. package/dist/src/generators/shared.d.ts +2 -0
  173. package/dist/src/generators/shared.js +15 -0
  174. package/dist/src/generators/shared.js.map +1 -0
  175. package/dist/src/index.d.ts +41 -0
  176. package/dist/src/index.js +3327 -0
  177. package/dist/src/index.js.map +1 -0
  178. package/dist/src/output/command-receipt.d.ts +87 -0
  179. package/dist/src/output/command-receipt.js +302 -0
  180. package/dist/src/output/command-receipt.js.map +1 -0
  181. package/dist/src/output/debug-log.d.ts +4 -0
  182. package/dist/src/output/debug-log.js +97 -0
  183. package/dist/src/output/debug-log.js.map +1 -0
  184. package/dist/src/output/equivalent-command.d.ts +9 -0
  185. package/dist/src/output/equivalent-command.js +39 -0
  186. package/dist/src/output/equivalent-command.js.map +1 -0
  187. package/dist/src/output/model.d.ts +76 -0
  188. package/dist/src/output/model.js +2 -0
  189. package/dist/src/output/model.js.map +1 -0
  190. package/dist/src/output/rebuild-progress.d.ts +21 -0
  191. package/dist/src/output/rebuild-progress.js +128 -0
  192. package/dist/src/output/rebuild-progress.js.map +1 -0
  193. package/dist/src/output/redact.d.ts +3 -0
  194. package/dist/src/output/redact.js +39 -0
  195. package/dist/src/output/redact.js.map +1 -0
  196. package/dist/src/output/reporter.d.ts +9 -0
  197. package/dist/src/output/reporter.js +133 -0
  198. package/dist/src/output/reporter.js.map +1 -0
  199. package/dist/src/portable/commands.d.ts +124 -0
  200. package/dist/src/portable/commands.js +557 -0
  201. package/dist/src/portable/commands.js.map +1 -0
  202. package/dist/src/portable/materializer.d.ts +50 -0
  203. package/dist/src/portable/materializer.js +462 -0
  204. package/dist/src/portable/materializer.js.map +1 -0
  205. package/dist/src/portable/skills-cli.d.ts +43 -0
  206. package/dist/src/portable/skills-cli.js +148 -0
  207. package/dist/src/portable/skills-cli.js.map +1 -0
  208. package/dist/src/tui/catalog-freshness.d.ts +1 -0
  209. package/dist/src/tui/catalog-freshness.js +2 -0
  210. package/dist/src/tui/catalog-freshness.js.map +1 -0
  211. package/dist/src/tui/catalog-generation.d.ts +21 -0
  212. package/dist/src/tui/catalog-generation.js +116 -0
  213. package/dist/src/tui/catalog-generation.js.map +1 -0
  214. package/dist/src/tui/catalog-sources/projection.d.ts +4 -0
  215. package/dist/src/tui/catalog-sources/projection.js +17 -0
  216. package/dist/src/tui/catalog-sources/projection.js.map +1 -0
  217. package/dist/src/tui/catalog-sources/review.d.ts +3 -0
  218. package/dist/src/tui/catalog-sources/review.js +13 -0
  219. package/dist/src/tui/catalog-sources/review.js.map +1 -0
  220. package/dist/src/tui/catalog-sources/screens.d.ts +12 -0
  221. package/dist/src/tui/catalog-sources/screens.js +33 -0
  222. package/dist/src/tui/catalog-sources/screens.js.map +1 -0
  223. package/dist/src/tui/catalog-sources/session.d.ts +22 -0
  224. package/dist/src/tui/catalog-sources/session.js +225 -0
  225. package/dist/src/tui/catalog-sources/session.js.map +1 -0
  226. package/dist/src/tui/catalog-sources/types.d.ts +41 -0
  227. package/dist/src/tui/catalog-sources/types.js +2 -0
  228. package/dist/src/tui/catalog-sources/types.js.map +1 -0
  229. package/dist/src/tui/components.d.ts +102 -0
  230. package/dist/src/tui/components.js +184 -0
  231. package/dist/src/tui/components.js.map +1 -0
  232. package/dist/src/tui/console-app-v4.d.ts +20 -0
  233. package/dist/src/tui/console-app-v4.js +5066 -0
  234. package/dist/src/tui/console-app-v4.js.map +1 -0
  235. package/dist/src/tui/controller-runtime.d.ts +23 -0
  236. package/dist/src/tui/controller-runtime.js +2011 -0
  237. package/dist/src/tui/controller-runtime.js.map +1 -0
  238. package/dist/src/tui/controller.d.ts +557 -0
  239. package/dist/src/tui/controller.js +2120 -0
  240. package/dist/src/tui/controller.js.map +1 -0
  241. package/dist/src/tui/diagnostics.d.ts +30 -0
  242. package/dist/src/tui/diagnostics.js +71 -0
  243. package/dist/src/tui/diagnostics.js.map +1 -0
  244. package/dist/src/tui/index.d.ts +17 -0
  245. package/dist/src/tui/index.js +17 -0
  246. package/dist/src/tui/index.js.map +1 -0
  247. package/dist/src/tui/input-display.d.ts +8 -0
  248. package/dist/src/tui/input-display.js +36 -0
  249. package/dist/src/tui/input-display.js.map +1 -0
  250. package/dist/src/tui/keys.d.ts +12 -0
  251. package/dist/src/tui/keys.js +22 -0
  252. package/dist/src/tui/keys.js.map +1 -0
  253. package/dist/src/tui/layout.d.ts +12 -0
  254. package/dist/src/tui/layout.js +19 -0
  255. package/dist/src/tui/layout.js.map +1 -0
  256. package/dist/src/tui/model.d.ts +424 -0
  257. package/dist/src/tui/model.js +1493 -0
  258. package/dist/src/tui/model.js.map +1 -0
  259. package/dist/src/tui/operation-review-planner.d.ts +21 -0
  260. package/dist/src/tui/operation-review-planner.js +622 -0
  261. package/dist/src/tui/operation-review-planner.js.map +1 -0
  262. package/dist/src/tui/prompt.d.ts +8 -0
  263. package/dist/src/tui/prompt.js +231 -0
  264. package/dist/src/tui/prompt.js.map +1 -0
  265. package/dist/src/tui/router.d.ts +206 -0
  266. package/dist/src/tui/router.js +137 -0
  267. package/dist/src/tui/router.js.map +1 -0
  268. package/dist/src/tui/runner.d.ts +11 -0
  269. package/dist/src/tui/runner.js +71 -0
  270. package/dist/src/tui/runner.js.map +1 -0
  271. package/dist/src/tui/source-ref-presets.d.ts +3 -0
  272. package/dist/src/tui/source-ref-presets.js +11 -0
  273. package/dist/src/tui/source-ref-presets.js.map +1 -0
  274. package/dist/src/tui/theme.d.ts +26 -0
  275. package/dist/src/tui/theme.js +28 -0
  276. package/dist/src/tui/theme.js.map +1 -0
  277. package/dist/src/tui/viewport.d.ts +20 -0
  278. package/dist/src/tui/viewport.js +29 -0
  279. package/dist/src/tui/viewport.js.map +1 -0
  280. package/dist/src/tui/views.d.ts +57 -0
  281. package/dist/src/tui/views.js +201 -0
  282. package/dist/src/tui/views.js.map +1 -0
  283. package/dist/src/tui/wizard.d.ts +11 -0
  284. package/dist/src/tui/wizard.js +323 -0
  285. package/dist/src/tui/wizard.js.map +1 -0
  286. package/dist/src/types.d.ts +474 -0
  287. package/dist/src/types.js +34 -0
  288. package/dist/src/types.js.map +1 -0
  289. package/dist/src/utils/agent-version.d.ts +19 -0
  290. package/dist/src/utils/agent-version.js +205 -0
  291. package/dist/src/utils/agent-version.js.map +1 -0
  292. package/dist/src/utils/artifact-plan.d.ts +27 -0
  293. package/dist/src/utils/artifact-plan.js +453 -0
  294. package/dist/src/utils/artifact-plan.js.map +1 -0
  295. package/dist/src/utils/artifact-renderer.d.ts +129 -0
  296. package/dist/src/utils/artifact-renderer.js +400 -0
  297. package/dist/src/utils/artifact-renderer.js.map +1 -0
  298. package/dist/src/utils/artifact-request.d.ts +16 -0
  299. package/dist/src/utils/artifact-request.js +42 -0
  300. package/dist/src/utils/artifact-request.js.map +1 -0
  301. package/dist/src/utils/artifact-sources.d.ts +8 -0
  302. package/dist/src/utils/artifact-sources.js +10 -0
  303. package/dist/src/utils/artifact-sources.js.map +1 -0
  304. package/dist/src/utils/aw-home-mutation-lock.d.ts +11 -0
  305. package/dist/src/utils/aw-home-mutation-lock.js +83 -0
  306. package/dist/src/utils/aw-home-mutation-lock.js.map +1 -0
  307. package/dist/src/utils/bundle-integrity.d.ts +2 -0
  308. package/dist/src/utils/bundle-integrity.js +63 -0
  309. package/dist/src/utils/bundle-integrity.js.map +1 -0
  310. package/dist/src/utils/bundle-layout.d.ts +4 -0
  311. package/dist/src/utils/bundle-layout.js +531 -0
  312. package/dist/src/utils/bundle-layout.js.map +1 -0
  313. package/dist/src/utils/catalog-digests.d.ts +18 -0
  314. package/dist/src/utils/catalog-digests.js +156 -0
  315. package/dist/src/utils/catalog-digests.js.map +1 -0
  316. package/dist/src/utils/catalog-generation-control-snapshot.d.ts +11 -0
  317. package/dist/src/utils/catalog-generation-control-snapshot.js +45 -0
  318. package/dist/src/utils/catalog-generation-control-snapshot.js.map +1 -0
  319. package/dist/src/utils/catalog-generation-error.d.ts +16 -0
  320. package/dist/src/utils/catalog-generation-error.js +30 -0
  321. package/dist/src/utils/catalog-generation-error.js.map +1 -0
  322. package/dist/src/utils/catalog-generation-resolver.d.ts +32 -0
  323. package/dist/src/utils/catalog-generation-resolver.js +251 -0
  324. package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
  325. package/dist/src/utils/catalog-generation-service.d.ts +161 -0
  326. package/dist/src/utils/catalog-generation-service.js +1237 -0
  327. package/dist/src/utils/catalog-generation-service.js.map +1 -0
  328. package/dist/src/utils/catalog-generation-state.d.ts +22 -0
  329. package/dist/src/utils/catalog-generation-state.js +192 -0
  330. package/dist/src/utils/catalog-generation-state.js.map +1 -0
  331. package/dist/src/utils/catalog-generation-store.d.ts +57 -0
  332. package/dist/src/utils/catalog-generation-store.js +397 -0
  333. package/dist/src/utils/catalog-generation-store.js.map +1 -0
  334. package/dist/src/utils/catalog-manifest-v7.d.ts +5 -0
  335. package/dist/src/utils/catalog-manifest-v7.js +98 -0
  336. package/dist/src/utils/catalog-manifest-v7.js.map +1 -0
  337. package/dist/src/utils/catalog-operation-context.d.ts +20 -0
  338. package/dist/src/utils/catalog-operation-context.js +141 -0
  339. package/dist/src/utils/catalog-operation-context.js.map +1 -0
  340. package/dist/src/utils/catalog-public-error.d.ts +19 -0
  341. package/dist/src/utils/catalog-public-error.js +100 -0
  342. package/dist/src/utils/catalog-public-error.js.map +1 -0
  343. package/dist/src/utils/catalog-runtime-projection.d.ts +33 -0
  344. package/dist/src/utils/catalog-runtime-projection.js +77 -0
  345. package/dist/src/utils/catalog-runtime-projection.js.map +1 -0
  346. package/dist/src/utils/catalog-snapshot.d.ts +10 -0
  347. package/dist/src/utils/catalog-snapshot.js +20 -0
  348. package/dist/src/utils/catalog-snapshot.js.map +1 -0
  349. package/dist/src/utils/catalog-source-identity.d.ts +5 -0
  350. package/dist/src/utils/catalog-source-identity.js +137 -0
  351. package/dist/src/utils/catalog-source-identity.js.map +1 -0
  352. package/dist/src/utils/catalog-source-impact.d.ts +20 -0
  353. package/dist/src/utils/catalog-source-impact.js +222 -0
  354. package/dist/src/utils/catalog-source-impact.js.map +1 -0
  355. package/dist/src/utils/catalog-source-presentation.d.ts +1 -0
  356. package/dist/src/utils/catalog-source-presentation.js +32 -0
  357. package/dist/src/utils/catalog-source-presentation.js.map +1 -0
  358. package/dist/src/utils/catalog-source-references.d.ts +66 -0
  359. package/dist/src/utils/catalog-source-references.js +1180 -0
  360. package/dist/src/utils/catalog-source-references.js.map +1 -0
  361. package/dist/src/utils/catalog-sources.d.ts +53 -0
  362. package/dist/src/utils/catalog-sources.js +456 -0
  363. package/dist/src/utils/catalog-sources.js.map +1 -0
  364. package/dist/src/utils/codex-config.d.ts +126 -0
  365. package/dist/src/utils/codex-config.js +1032 -0
  366. package/dist/src/utils/codex-config.js.map +1 -0
  367. package/dist/src/utils/codex-manager.d.ts +81 -0
  368. package/dist/src/utils/codex-manager.js +810 -0
  369. package/dist/src/utils/codex-manager.js.map +1 -0
  370. package/dist/src/utils/codex-marketplace-path.d.ts +5 -0
  371. package/dist/src/utils/codex-marketplace-path.js +45 -0
  372. package/dist/src/utils/codex-marketplace-path.js.map +1 -0
  373. package/dist/src/utils/codex-native-observation.d.ts +16 -0
  374. package/dist/src/utils/codex-native-observation.js +22 -0
  375. package/dist/src/utils/codex-native-observation.js.map +1 -0
  376. package/dist/src/utils/codex-native-render-receipt.d.ts +40 -0
  377. package/dist/src/utils/codex-native-render-receipt.js +205 -0
  378. package/dist/src/utils/codex-native-render-receipt.js.map +1 -0
  379. package/dist/src/utils/codex-reconciler.d.ts +128 -0
  380. package/dist/src/utils/codex-reconciler.js +294 -0
  381. package/dist/src/utils/codex-reconciler.js.map +1 -0
  382. package/dist/src/utils/codex-roles.d.ts +71 -0
  383. package/dist/src/utils/codex-roles.js +257 -0
  384. package/dist/src/utils/codex-roles.js.map +1 -0
  385. package/dist/src/utils/codex-shared-native.d.ts +63 -0
  386. package/dist/src/utils/codex-shared-native.js +142 -0
  387. package/dist/src/utils/codex-shared-native.js.map +1 -0
  388. package/dist/src/utils/codex-skill-staging.d.ts +11 -0
  389. package/dist/src/utils/codex-skill-staging.js +8 -0
  390. package/dist/src/utils/codex-skill-staging.js.map +1 -0
  391. package/dist/src/utils/codex-surface-analysis.d.ts +45 -0
  392. package/dist/src/utils/codex-surface-analysis.js +245 -0
  393. package/dist/src/utils/codex-surface-analysis.js.map +1 -0
  394. package/dist/src/utils/config-value.d.ts +3 -0
  395. package/dist/src/utils/config-value.js +23 -0
  396. package/dist/src/utils/config-value.js.map +1 -0
  397. package/dist/src/utils/dynamic-skill-tree.d.ts +36 -0
  398. package/dist/src/utils/dynamic-skill-tree.js +466 -0
  399. package/dist/src/utils/dynamic-skill-tree.js.map +1 -0
  400. package/dist/src/utils/file-rules.d.ts +1 -0
  401. package/dist/src/utils/file-rules.js +2 -0
  402. package/dist/src/utils/file-rules.js.map +1 -0
  403. package/dist/src/utils/git-catalog-provider.d.ts +22 -0
  404. package/dist/src/utils/git-catalog-provider.js +497 -0
  405. package/dist/src/utils/git-catalog-provider.js.map +1 -0
  406. package/dist/src/utils/hooks-contract.d.ts +1 -0
  407. package/dist/src/utils/hooks-contract.js +2 -0
  408. package/dist/src/utils/hooks-contract.js.map +1 -0
  409. package/dist/src/utils/json.d.ts +4 -0
  410. package/dist/src/utils/json.js +29 -0
  411. package/dist/src/utils/json.js.map +1 -0
  412. package/dist/src/utils/local-marketplace.d.ts +41 -0
  413. package/dist/src/utils/local-marketplace.js +316 -0
  414. package/dist/src/utils/local-marketplace.js.map +1 -0
  415. package/dist/src/utils/manifest.d.ts +11 -0
  416. package/dist/src/utils/manifest.js +33 -0
  417. package/dist/src/utils/manifest.js.map +1 -0
  418. package/dist/src/utils/marketplace.d.ts +3 -0
  419. package/dist/src/utils/marketplace.js +76 -0
  420. package/dist/src/utils/marketplace.js.map +1 -0
  421. package/dist/src/utils/multi-source-catalog.d.ts +66 -0
  422. package/dist/src/utils/multi-source-catalog.js +345 -0
  423. package/dist/src/utils/multi-source-catalog.js.map +1 -0
  424. package/dist/src/utils/native-cli.d.ts +118 -0
  425. package/dist/src/utils/native-cli.js +518 -0
  426. package/dist/src/utils/native-cli.js.map +1 -0
  427. package/dist/src/utils/orphan-marketplace-cleanup.d.ts +18 -0
  428. package/dist/src/utils/orphan-marketplace-cleanup.js +198 -0
  429. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -0
  430. package/dist/src/utils/ownership.d.ts +194 -0
  431. package/dist/src/utils/ownership.js +723 -0
  432. package/dist/src/utils/ownership.js.map +1 -0
  433. package/dist/src/utils/path-catalog-provider.d.ts +7 -0
  434. package/dist/src/utils/path-catalog-provider.js +74 -0
  435. package/dist/src/utils/path-catalog-provider.js.map +1 -0
  436. package/dist/src/utils/paths.d.ts +40 -0
  437. package/dist/src/utils/paths.js +137 -0
  438. package/dist/src/utils/paths.js.map +1 -0
  439. package/dist/src/utils/platform-entries.d.ts +1 -0
  440. package/dist/src/utils/platform-entries.js +2 -0
  441. package/dist/src/utils/platform-entries.js.map +1 -0
  442. package/dist/src/utils/platform-support.d.ts +1 -0
  443. package/dist/src/utils/platform-support.js +2 -0
  444. package/dist/src/utils/platform-support.js.map +1 -0
  445. package/dist/src/utils/plugin-config-write.d.ts +110 -0
  446. package/dist/src/utils/plugin-config-write.js +773 -0
  447. package/dist/src/utils/plugin-config-write.js.map +1 -0
  448. package/dist/src/utils/plugin-config.d.ts +389 -0
  449. package/dist/src/utils/plugin-config.js +1642 -0
  450. package/dist/src/utils/plugin-config.js.map +1 -0
  451. package/dist/src/utils/plugin-dependencies.d.ts +12 -0
  452. package/dist/src/utils/plugin-dependencies.js +162 -0
  453. package/dist/src/utils/plugin-dependencies.js.map +1 -0
  454. package/dist/src/utils/plugin-intent-state.d.ts +34 -0
  455. package/dist/src/utils/plugin-intent-state.js +289 -0
  456. package/dist/src/utils/plugin-intent-state.js.map +1 -0
  457. package/dist/src/utils/plugin-script-contract.d.ts +1 -0
  458. package/dist/src/utils/plugin-script-contract.js +2 -0
  459. package/dist/src/utils/plugin-script-contract.js.map +1 -0
  460. package/dist/src/utils/plugin-scripts.d.ts +101 -0
  461. package/dist/src/utils/plugin-scripts.js +253 -0
  462. package/dist/src/utils/plugin-scripts.js.map +1 -0
  463. package/dist/src/utils/process-lock.d.ts +47 -0
  464. package/dist/src/utils/process-lock.js +532 -0
  465. package/dist/src/utils/process-lock.js.map +1 -0
  466. package/dist/src/utils/process-tree.d.ts +2 -0
  467. package/dist/src/utils/process-tree.js +2 -0
  468. package/dist/src/utils/process-tree.js.map +1 -0
  469. package/dist/src/utils/project-boundary.d.ts +9 -0
  470. package/dist/src/utils/project-boundary.js +67 -0
  471. package/dist/src/utils/project-boundary.js.map +1 -0
  472. package/dist/src/utils/rendered-contract.d.ts +8 -0
  473. package/dist/src/utils/rendered-contract.js +134 -0
  474. package/dist/src/utils/rendered-contract.js.map +1 -0
  475. package/dist/src/utils/runtime-skill-closure.d.ts +13 -0
  476. package/dist/src/utils/runtime-skill-closure.js +863 -0
  477. package/dist/src/utils/runtime-skill-closure.js.map +1 -0
  478. package/dist/src/utils/safe-fs.d.ts +21 -0
  479. package/dist/src/utils/safe-fs.js +111 -0
  480. package/dist/src/utils/safe-fs.js.map +1 -0
  481. package/dist/src/utils/skill-authoring.d.ts +1 -0
  482. package/dist/src/utils/skill-authoring.js +2 -0
  483. package/dist/src/utils/skill-authoring.js.map +1 -0
  484. package/dist/src/utils/skill-validation.d.ts +37 -0
  485. package/dist/src/utils/skill-validation.js +326 -0
  486. package/dist/src/utils/skill-validation.js.map +1 -0
  487. package/dist/src/utils/slash-commands.d.ts +1 -0
  488. package/dist/src/utils/slash-commands.js +2 -0
  489. package/dist/src/utils/slash-commands.js.map +1 -0
  490. package/dist/src/utils/state-paths.d.ts +14 -0
  491. package/dist/src/utils/state-paths.js +139 -0
  492. package/dist/src/utils/state-paths.js.map +1 -0
  493. package/dist/src/utils/target-eligibility.d.ts +13 -0
  494. package/dist/src/utils/target-eligibility.js +35 -0
  495. package/dist/src/utils/target-eligibility.js.map +1 -0
  496. package/dist/src/utils/target-order.d.ts +7 -0
  497. package/dist/src/utils/target-order.js +10 -0
  498. package/dist/src/utils/target-order.js.map +1 -0
  499. package/dist/src/utils/template-engine.d.ts +1 -0
  500. package/dist/src/utils/template-engine.js +2 -0
  501. package/dist/src/utils/template-engine.js.map +1 -0
  502. package/dist/src/utils/test-path-fence.d.ts +12 -0
  503. package/dist/src/utils/test-path-fence.js +31 -0
  504. package/dist/src/utils/test-path-fence.js.map +1 -0
  505. package/dist/vitest.config.d.ts +2 -0
  506. package/dist/vitest.config.js +16 -0
  507. package/dist/vitest.config.js.map +1 -0
  508. package/package.json +64 -0
@@ -0,0 +1,3327 @@
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 { doctorEvalProviders } from '@lesliechan721/agent-skill-eval';
8
+ import { initCommand } from './commands/init.js';
9
+ import { resolveCatalogWorkspaceRoot } from './commands/catalog-workspace-resolution.js';
10
+ import { addCatalogSourceCommand, explicitRefPolicy, listCatalogSources, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from './commands/catalog-source.js';
11
+ import { catalogSourceStatusCommand, syncCatalogSourceCommand, } from './commands/catalog-generation.js';
12
+ import { catalogStorePrune, catalogStoreStatus } from './commands/catalog-store.js';
13
+ import { cleanupWriteCommand as cleanupCommand, installWriteCommand as installCommand, reinstallWriteCommand as reinstallCommand, uninstallWriteCommand as uninstallCommand, } from './commands/write-commands.js';
14
+ import { syncCommand } from './commands/sync-command.js';
15
+ import { formatInteractiveConsoleUnavailableMessage, runConsoleController, } from './commands/console.js';
16
+ import { runCommandWizard, toWizardCandidates, WizardExecutionError, } from './commands/wizard.js';
17
+ import { createCliExecutionContext, emitCommandEvent, } from './commands/runtime.js';
18
+ import { loadConsoleItemsResult, statusCommandV7 } from './commands/status-v6.js';
19
+ import { normalizeUninstallCommandOptions, normalizeCleanupCommandOptions, resolveConfigReadResolution, resolveConfigWriteScope, normalizeInstallCommandOptions, normalizeReinstallCommandOptions, } from './commands/options.js';
20
+ import { isCommandWarningError, } from './types.js';
21
+ import { formatWarnings } from './output/reporter.js';
22
+ import { redactString, redactValue } from './output/redact.js';
23
+ import { renderShellCommand, } from './output/equivalent-command.js';
24
+ import { buildRebuildReceiptJson, buildInitReceiptJson, renderRebuildReceipt, renderInitReceipt, } from './output/command-receipt.js';
25
+ import { resolveCliPackageRoot } from './utils/paths.js';
26
+ import { findConfigFieldEntry, listNamespacedPluginConfigStores, listPluginConfigStorePluginNames, readPluginConfigStore, renderPluginConfigValueForDisplay, resolveConfigRead, } from './utils/plugin-config.js';
27
+ import { applyPluginConfigWrite, buildConfigMutationReceipt, describeResetAffectedFields, resetPluginConfigWithHelper, } from './utils/plugin-config-write.js';
28
+ import { assertStrictSemVer } from './utils/manifest.js';
29
+ import { writeCandidateEligibility } from './utils/target-eligibility.js';
30
+ import { assertCatalogSourceReferencesSupported, inventoryLegacyConfigReferences, } from './utils/catalog-source-references.js';
31
+ import { parsePluginId, withResolvedCatalogPlugin, withResolvedMultiSourceCatalog, } from './utils/multi-source-catalog.js';
32
+ import { sanitizeCatalogSourceError, sanitizeCatalogSourceErrorMessage, } from './utils/catalog-public-error.js';
33
+ import { catalogGenerationErrorCode } from './utils/catalog-generation-error.js';
34
+ import { resolveCatalogOperationContext, } from './utils/catalog-operation-context.js';
35
+ import { withAwHomeMutationLock, } from './utils/aw-home-mutation-lock.js';
36
+ import { installPortableSkills, materializePortableSkillsToDirectory, PortableCommandError, renderPortableReview, } from './portable/commands.js';
37
+ import { SkillsCliError } from './portable/skills-cli.js';
38
+ import { computeReviewComponentDigest, listReviewRecords, parseReviewAttachment, publishReviewRecord, showReviewRecord, verifyReviewRecord, } from './commands/review-publication.js';
39
+ import { resolveRepoRoot } from './utils/state-paths.js';
40
+ import { runCatalogBuildCommand, runCatalogInitCommand, runCatalogValidateCommand, runCatalogVersionCommand, runPluginBuildCommand, runPluginTestCommand, } from './authoring/workspace-commands.js';
41
+ import { runCatalogPublishApplyCommand, runCatalogPublishPlanCommand, } from './commands/catalog-publish.js';
42
+ import { catalogPublicationFailure, CatalogPublicationInspectionError, } from './commands/catalog-publication-inspection.js';
43
+ import { getCatalogStatus, renderCatalogStatus } from './commands/catalog-status.js';
44
+ import { activateCatalogDevSource, catalogDevSourceError, createCatalogDevFailureReceipt, deactivateCatalogDevSource, getCatalogDevSourceStatus, } from './commands/catalog-dev-source.js';
45
+ import { getPluginCapabilitiesResult, parsePluginCapabilitySurface, renderPluginCapabilities, } from './commands/plugin-capabilities.js';
46
+ import { AwCapabilityUnsupportedError, checkCurrentAw, describeCurrentAw, inspectPluginRequirements, } from './commands/aw-capabilities.js';
47
+ import { prepareSkillEval } from './commands/skill-eval.js';
48
+ function createDefaultIo() {
49
+ return {
50
+ stdout: (text) => process.stdout.write(text),
51
+ stderr: (text) => process.stderr.write(text),
52
+ };
53
+ }
54
+ function writeLine(write, line) {
55
+ write(`${line}\n`);
56
+ }
57
+ function writeWarnings(write, warnings, options = {}) {
58
+ for (const warning of formatWarnings(warnings, options)) {
59
+ writeLine(write, warning);
60
+ }
61
+ }
62
+ function resolveCliVersion() {
63
+ const packageJsonPath = path.join(resolveCliPackageRoot(), 'package.json');
64
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
65
+ return assertStrictSemVer(packageJson.version, 'packages/cli/package.json version');
66
+ }
67
+ function resolveCommandReceiptExitCode(result) {
68
+ return result.overallState === 'succeeded' ? 0 : 1;
69
+ }
70
+ class WriteCommandRequestError extends Error {
71
+ code = 'invalidArguments';
72
+ }
73
+ function normalizeWriteRequest(normalize) {
74
+ try {
75
+ return normalize();
76
+ }
77
+ catch (error) {
78
+ throw new WriteCommandRequestError(error instanceof Error ? error.message : String(error));
79
+ }
80
+ }
81
+ function writeCommandFailure(error) {
82
+ const message = redactString(error instanceof Error ? error.message : String(error));
83
+ if (error instanceof CommanderError || error instanceof WriteCommandRequestError) {
84
+ return { code: 'invalidArguments', message };
85
+ }
86
+ const explicitCode = error?.code;
87
+ if (typeof explicitCode === 'string' && /^[A-Za-z][A-Za-z0-9]*$/u.test(explicitCode)) {
88
+ return { code: explicitCode, message };
89
+ }
90
+ const separator = message.indexOf(':');
91
+ const prefix = separator > 0 ? message.slice(0, separator) : '';
92
+ return {
93
+ code: /^[A-Za-z][A-Za-z0-9]*$/u.test(prefix) ? prefix : 'writeCommandFailed',
94
+ message,
95
+ };
96
+ }
97
+ function preparseWriteReceiptRequest(argv) {
98
+ const request = { json: false, plugins: [] };
99
+ let positionalOnly = false;
100
+ for (let index = 1; index < argv.length; index += 1) {
101
+ const token = argv[index];
102
+ if (positionalOnly) {
103
+ request.plugins.push(token);
104
+ continue;
105
+ }
106
+ if (token === '--') {
107
+ positionalOnly = true;
108
+ continue;
109
+ }
110
+ if (token === '--json') {
111
+ request.json = true;
112
+ continue;
113
+ }
114
+ if (token === '--platform' || token === '--scope') {
115
+ const value = argv[index + 1];
116
+ if (token === '--platform')
117
+ request.platform = value;
118
+ else
119
+ request.scope = value;
120
+ index += 1;
121
+ continue;
122
+ }
123
+ if (token.startsWith('--platform=')) {
124
+ request.platform = token.slice('--platform='.length);
125
+ continue;
126
+ }
127
+ if (token.startsWith('--scope=')) {
128
+ request.scope = token.slice('--scope='.length);
129
+ continue;
130
+ }
131
+ if (token === '--dependency-scope' || token === '--script-timeout' || token === '--log-file') {
132
+ index += 1;
133
+ continue;
134
+ }
135
+ if (token.startsWith('--'))
136
+ continue;
137
+ if (token.startsWith('-') && token !== '-') {
138
+ const shortOptions = token.slice(1);
139
+ for (let offset = 0; offset < shortOptions.length; offset += 1) {
140
+ const option = shortOptions[offset];
141
+ if (option === 'j') {
142
+ request.json = true;
143
+ continue;
144
+ }
145
+ if (option === 'p' || option === 's') {
146
+ const value = shortOptions.slice(offset + 1) || argv[index + 1];
147
+ if (option === 'p')
148
+ request.platform = value;
149
+ else
150
+ request.scope = value;
151
+ if (shortOptions.length === offset + 1)
152
+ index += 1;
153
+ break;
154
+ }
155
+ }
156
+ continue;
157
+ }
158
+ request.plugins.push(token);
159
+ }
160
+ return request;
161
+ }
162
+ function jsonWriteCommandRequest(argv) {
163
+ const command = argv[0];
164
+ if (!['install', 'reinstall', 'uninstall', 'cleanup', 'sync'].includes(command ?? '')) {
165
+ return null;
166
+ }
167
+ const request = preparseWriteReceiptRequest(argv);
168
+ if (!request.json)
169
+ return null;
170
+ const rawPlatform = request.platform;
171
+ const platform = rawPlatform === 'codex' || rawPlatform === 'claude' || rawPlatform === 'both'
172
+ ? rawPlatform
173
+ : 'codex';
174
+ return {
175
+ command: command,
176
+ plugins: request.plugins,
177
+ platform,
178
+ scope: request.scope === 'project' ? 'project' : 'user',
179
+ };
180
+ }
181
+ function writeCommandFailureReceipt(write, request, error) {
182
+ const platforms = request.platform === 'both'
183
+ ? ['codex', 'claude']
184
+ : [request.platform];
185
+ writeJsonReceipt(write, buildRebuildReceiptJson(request.command, {
186
+ platforms,
187
+ plugins: request.plugins,
188
+ warnings: [],
189
+ overallState: 'failed',
190
+ errors: [writeCommandFailure(error)],
191
+ receiptTargets: request.plugins.flatMap((selector) => platforms.map((platform) => {
192
+ let pluginName = selector;
193
+ let sourceId;
194
+ try {
195
+ const parsed = parsePluginId(selector);
196
+ pluginName = parsed.pluginName;
197
+ sourceId = parsed.sourceId;
198
+ }
199
+ catch {
200
+ // Keep the raw selector in the failed receipt.
201
+ }
202
+ return {
203
+ pluginName,
204
+ pluginId: selector,
205
+ ...(sourceId ? { sourceId } : {}),
206
+ platform,
207
+ scope: request.scope,
208
+ };
209
+ })),
210
+ }));
211
+ }
212
+ function scanConfigMutationShortOptions(token, command) {
213
+ if (!/^-[^-].*/u.test(token))
214
+ return { json: false, consumesNextValue: false };
215
+ let json = false;
216
+ for (let index = 1; index < token.length; index += 1) {
217
+ const option = token[index];
218
+ if (option === 's') {
219
+ return {
220
+ json,
221
+ consumesNextValue: index === token.length - 1,
222
+ };
223
+ }
224
+ if (option === 'j') {
225
+ json = true;
226
+ continue;
227
+ }
228
+ if (option === 'v' || option === 'D' || (option === 'y' && command === 'config:reset')) {
229
+ continue;
230
+ }
231
+ break;
232
+ }
233
+ return { json, consumesNextValue: false };
234
+ }
235
+ function jsonConfigMutationRequest(argv) {
236
+ if (argv[0] !== 'config' || !['set', 'unset', 'reset'].includes(argv[1] ?? '')) {
237
+ return null;
238
+ }
239
+ const command = `config:${argv[1]}`;
240
+ let json = false;
241
+ let plugin;
242
+ const valueOptions = new Set(['--scope', '--value-json', '--preset', '--log-file']);
243
+ for (let index = 2; index < argv.length; index += 1) {
244
+ const token = argv[index];
245
+ if (token === '--')
246
+ break;
247
+ if (valueOptions.has(token)) {
248
+ index += 1;
249
+ continue;
250
+ }
251
+ if (token === '--json') {
252
+ json = true;
253
+ continue;
254
+ }
255
+ const shortOptions = scanConfigMutationShortOptions(token, command);
256
+ if (shortOptions.json)
257
+ json = true;
258
+ if (shortOptions.consumesNextValue)
259
+ index += 1;
260
+ if (token.startsWith('-'))
261
+ continue;
262
+ plugin ??= token;
263
+ }
264
+ if (!json)
265
+ return null;
266
+ return {
267
+ command,
268
+ ...(plugin ? { plugin } : {}),
269
+ };
270
+ }
271
+ function configMutationFailure(error, env, cwd) {
272
+ if (error instanceof CommanderError) {
273
+ return {
274
+ code: 'invalidArguments',
275
+ message: 'error: invalid config mutation arguments',
276
+ };
277
+ }
278
+ const message = catalogPublicationFailure({
279
+ error,
280
+ env,
281
+ sensitiveRoots: [cwd],
282
+ }).message;
283
+ if (message.includes('Usage:'))
284
+ return { code: 'invalidArguments', message };
285
+ const generationCode = catalogGenerationErrorCode(error);
286
+ if (generationCode === 'catalogGenerationUnavailable'
287
+ || generationCode === 'catalogGenerationSourceMissing') {
288
+ return { code: 'catalogSourceUnavailable', message };
289
+ }
290
+ if (generationCode !== 'catalogGenerationFailed')
291
+ return { code: generationCode, message };
292
+ const explicitCode = error?.code;
293
+ if (typeof explicitCode === 'string' && /^[A-Za-z][A-Za-z0-9]*$/u.test(explicitCode)) {
294
+ return { code: explicitCode, message };
295
+ }
296
+ if (message.includes('legacyStateUnsupported'))
297
+ return { code: 'legacyStateUnsupported', message };
298
+ if (message.includes('sourceChanged'))
299
+ return { code: 'sourceChanged', message };
300
+ if (message.includes('sourceMissing'))
301
+ return { code: 'sourceMissing', message };
302
+ if (message.startsWith('Cannot resolve required catalog sources:')) {
303
+ return { code: 'catalogSourceUnavailable', message };
304
+ }
305
+ const prefix = message.match(/^([A-Za-z][A-Za-z0-9]*):/u)?.[1];
306
+ return { code: prefix ?? 'configMutationFailed', message };
307
+ }
308
+ function writeConfigMutationFailureReceipt(write, request, failure) {
309
+ let plugin;
310
+ try {
311
+ if (request.plugin) {
312
+ parsePluginId(request.plugin);
313
+ plugin = request.plugin;
314
+ }
315
+ }
316
+ catch {
317
+ // Do not echo an invalid selector from raw argv in an early failure receipt.
318
+ }
319
+ writeJsonReceipt(write, buildConfigMutationReceipt(request.command, {
320
+ ok: false,
321
+ overallState: 'failed',
322
+ ...(plugin ? { plugin } : {}),
323
+ errors: [failure],
324
+ }));
325
+ }
326
+ async function runAuthoringScript(options) {
327
+ const scriptPath = path.join(resolveCliPackageRoot(), 'dist', 'authoring', 'scripts', options.scriptName);
328
+ return new Promise((resolve, reject) => {
329
+ const child = spawn(process.execPath, [scriptPath, ...options.args], {
330
+ cwd: options.cwd,
331
+ env: options.env,
332
+ stdio: ['ignore', 'pipe', 'pipe'],
333
+ });
334
+ child.stdout.on('data', (chunk) => options.io.stdout(String(chunk)));
335
+ child.stderr.on('data', (chunk) => options.io.stderr(String(chunk)));
336
+ child.once('error', reject);
337
+ child.once('close', (code, signal) => {
338
+ if (signal) {
339
+ reject(new Error(`Plugin authoring command terminated by signal ${signal}.`));
340
+ return;
341
+ }
342
+ resolve(code ?? 1);
343
+ });
344
+ });
345
+ }
346
+ function toCliDiagnosticsOptions(commandName, rawOptions, runtimeDiagnostics) {
347
+ return {
348
+ ...runtimeDiagnostics,
349
+ commandName,
350
+ verbose: runtimeDiagnostics?.verbose === true || rawOptions.verbose === true,
351
+ debug: runtimeDiagnostics?.debug === true || rawOptions.debug === true,
352
+ logFile: rawOptions.logFile ?? runtimeDiagnostics?.logFile,
353
+ };
354
+ }
355
+ function isWizardAvailable(context, rawOptions) {
356
+ return context.interactive && context.isTty && !context.isCi && rawOptions.json !== true;
357
+ }
358
+ function shellCommand(tokens) {
359
+ return renderShellCommand(tokens, 'posix');
360
+ }
361
+ function optionTokens(flag, value) {
362
+ return value === undefined ? [] : [flag, value];
363
+ }
364
+ function writeCommandUsage(command) {
365
+ const cardinality = command === 'reinstall' || command === 'cleanup' ? '<plugin>' : '<plugin...>';
366
+ const scope = command === 'cleanup' ? ' --scope <project|user>' : ' [--scope <project|user>]';
367
+ return [
368
+ `${command} 命令缺少必要参数。`,
369
+ `Usage: aw ${command} ${cardinality} --platform <codex|claude|both>${scope}`,
370
+ `Example: aw ${command} example-plugin --platform codex --scope user`,
371
+ ].join('\n');
372
+ }
373
+ function configCommandUsage(command) {
374
+ const argumentsByCommand = {
375
+ list: '<plugin>',
376
+ get: '<plugin> [key]',
377
+ set: '<plugin> <field> --scope <project|user> (--value-json <json> | --preset <id>)',
378
+ unset: '<plugin> <key>',
379
+ reset: '<plugin> --scope <project|user> --yes',
380
+ };
381
+ return [
382
+ `config ${command} 命令缺少必要参数。`,
383
+ `Usage: aw config ${command} ${argumentsByCommand[command]}`,
384
+ `Example: aw config ${command} example-plugin${command === 'set' ? ' mode --scope user --value-json \'"safe"\'' : command === 'unset' ? ' key' : command === 'reset' ? ' --scope user --yes' : ''}`,
385
+ ].join('\n');
386
+ }
387
+ function equivalentWriteCommand(command, selection, rawOptions) {
388
+ return shellCommand(buildEquivalentWriteCommandTokens(command, selection, rawOptions));
389
+ }
390
+ export function buildEquivalentWriteCommandTokens(command, selection, rawOptions) {
391
+ return [
392
+ 'aw',
393
+ command,
394
+ '--platform',
395
+ selection.platform ?? 'both',
396
+ '--scope',
397
+ selection.scope ?? 'user',
398
+ ...(rawOptions.allowManagedCodexInstall === true
399
+ ? ['--allow-managed-codex-install']
400
+ : []),
401
+ ...(command === 'install'
402
+ ? (rawOptions.dependencyScope ?? []).flatMap((value) => ['--dependency-scope', value])
403
+ : []),
404
+ ...(command === 'cleanup' ? [] : optionTokens('--script-timeout', rawOptions.scriptTimeout)),
405
+ ...(selection.plugins.length > 0 ? ['--', ...selection.plugins] : []),
406
+ ];
407
+ }
408
+ function equivalentConfigCommand(options) {
409
+ return shellCommand(buildEquivalentConfigCommandTokens(options));
410
+ }
411
+ function equivalentConfigCommandProjection(resolve) {
412
+ return {
413
+ equivalentCommand: (selection) => equivalentConfigCommand(resolve(selection)),
414
+ equivalentCommandTokens: (selection) => buildEquivalentConfigCommandTokens(resolve(selection)),
415
+ };
416
+ }
417
+ export function buildEquivalentConfigCommandTokens(options) {
418
+ return [
419
+ 'aw',
420
+ 'config',
421
+ options.command,
422
+ ...optionTokens('--scope', options.scope),
423
+ ...optionTokens('--value-json', options.valueJson),
424
+ ...optionTokens('--preset', options.preset),
425
+ ...(options.confirmed ? ['--yes'] : []),
426
+ '--',
427
+ options.plugin,
428
+ ...(options.key === undefined ? [] : [options.key]),
429
+ ...(options.value === undefined ? [] : [options.value]),
430
+ ];
431
+ }
432
+ function hasSelectableWriteCandidate(command, candidates, selection, options) {
433
+ const platforms = options.missingPlatform
434
+ ? ['codex', 'claude', 'both']
435
+ : [selection.platform ?? 'both'];
436
+ const scopes = options.missingScope ? ['user', 'project'] : [selection.scope ?? 'user'];
437
+ return candidates.some((candidate) => platforms.some((platform) => scopes.some((scope) => writeCandidateEligibility(command, candidate, { ...selection, platform, scope }).selectable)));
438
+ }
439
+ function hasConfigSchemaKeys(candidate) {
440
+ return candidate.configSchema !== undefined && Object.keys(candidate.configSchema).length > 0;
441
+ }
442
+ async function loadWizardCandidates(context, rawOptions) {
443
+ const loaded = await loadConsoleItemsResult({
444
+ cwd: context.cwd,
445
+ scope: rawOptions.scope,
446
+ platform: rawOptions.platform,
447
+ }, context);
448
+ return toWizardCandidates(loaded.items);
449
+ }
450
+ function mergeWizardCandidates(current, stored) {
451
+ const merged = new Map(current.map((candidate) => [candidate.pluginName, candidate]));
452
+ for (const candidate of stored) {
453
+ const existing = merged.get(candidate.pluginName);
454
+ if (!existing) {
455
+ merged.set(candidate.pluginName, candidate);
456
+ }
457
+ else if (!existing.configSchema) {
458
+ merged.set(candidate.pluginName, { ...candidate, ...existing });
459
+ }
460
+ }
461
+ return [...merged.values()];
462
+ }
463
+ async function loadStoredConfigWizardCandidates(context, locations, options = {}) {
464
+ const legacy = await listPluginConfigStorePluginNames({ cwd: context.cwd, env: context.env });
465
+ if (legacy.length > 0) {
466
+ throw new Error('legacyStateUnsupported: legacy bare-name config stores are not supported.');
467
+ }
468
+ const storesByPlugin = new Map();
469
+ for (const location of locations) {
470
+ const stores = await listNamespacedPluginConfigStores({
471
+ cwd: context.cwd,
472
+ env: context.env,
473
+ scope: location.scope,
474
+ });
475
+ for (const store of stores) {
476
+ const keys = Object.keys(store.values);
477
+ if (keys.length === 0 && options.includeEmptyStores !== true)
478
+ continue;
479
+ const existing = storesByPlugin.get(store.pluginId) ?? {
480
+ sourceId: store.sourceId,
481
+ sourceIdentity: store.sourceIdentity,
482
+ keys: new Set(),
483
+ };
484
+ if (existing.sourceIdentity !== store.sourceIdentity) {
485
+ throw new Error(`sourceChanged: ${store.pluginId} config stores have different source identities.`);
486
+ }
487
+ for (const key of keys)
488
+ existing.keys.add(key);
489
+ storesByPlugin.set(store.pluginId, existing);
490
+ }
491
+ }
492
+ return [...storesByPlugin]
493
+ .sort(([left], [right]) => left.localeCompare(right))
494
+ .map(([pluginId, store]) => ({
495
+ pluginName: pluginId,
496
+ pluginId,
497
+ sourceId: store.sourceId,
498
+ sourceIdentity: store.sourceIdentity,
499
+ targets: [],
500
+ configKeys: [...store.keys].sort((left, right) => left.localeCompare(right)),
501
+ }));
502
+ }
503
+ function configReadStoreLocations(rawOptions) {
504
+ if (rawOptions.scope === 'user')
505
+ return [{ scope: 'user' }];
506
+ if (rawOptions.scope === 'project')
507
+ return [{ scope: 'project' }];
508
+ return [
509
+ { scope: 'user' },
510
+ { scope: 'project' },
511
+ ];
512
+ }
513
+ function overallResultState(value) {
514
+ return value.overallState === 'succeeded' ? 'succeeded' : 'failed';
515
+ }
516
+ async function resolveStoredConfigResetIdentity(options) {
517
+ const parsed = parsePluginId(options.selector);
518
+ if (parsed.sourceId) {
519
+ return {
520
+ pluginName: parsed.pluginName,
521
+ pluginId: options.selector,
522
+ sourceId: parsed.sourceId,
523
+ };
524
+ }
525
+ const matches = (await listNamespacedPluginConfigStores({
526
+ cwd: options.context.cwd,
527
+ env: options.context.env,
528
+ scope: options.scope,
529
+ })).filter((store) => store.pluginName === parsed.pluginName);
530
+ if (matches.length === 0) {
531
+ throw new Error(`configStoreMissing: ${options.selector} has no config in the selected store.`);
532
+ }
533
+ if (matches.length > 1) {
534
+ throw new Error(`configTargetAmbiguous: ${options.selector} exists in multiple source namespaces: ${matches.map((store) => store.pluginId).join(', ')}. Use a full pluginId.`);
535
+ }
536
+ const [match] = matches;
537
+ return {
538
+ pluginName: match.pluginName,
539
+ pluginId: match.pluginId,
540
+ sourceId: match.sourceId,
541
+ sourceIdentity: match.sourceIdentity,
542
+ };
543
+ }
544
+ async function resolveStoredOnlyConfigIdentity(options) {
545
+ const parsed = parsePluginId(options.selector);
546
+ if (!parsed.sourceId)
547
+ throw new Error(`Plugin "${options.selector}" is not a qualified stored config target.`);
548
+ const stores = (await Promise.all(options.locations.map((location) => listNamespacedPluginConfigStores({
549
+ cwd: options.context.cwd,
550
+ env: options.context.env,
551
+ scope: location.scope,
552
+ })))).flat().filter((store) => store.pluginId === options.selector);
553
+ if (stores.length === 0)
554
+ throw new Error(`Plugin "${options.selector}" does not have a namespaced config store.`);
555
+ const identities = new Set(stores.map((store) => store.sourceIdentity));
556
+ if (identities.size !== 1) {
557
+ throw new Error(`sourceChanged: ${options.selector} config stores have different source identities.`);
558
+ }
559
+ const sourceIdentity = [...identities][0];
560
+ await withResolvedMultiSourceCatalog({
561
+ cliVersion: resolveCliVersion(),
562
+ sourceIds: [parsed.sourceId],
563
+ env: options.context.env,
564
+ consume: async (catalog) => {
565
+ const source = catalog.sources.find((entry) => entry.sourceId === parsed.sourceId);
566
+ if (!source?.resolution) {
567
+ throw source?.error ?? new Error(`Catalog source "${parsed.sourceId}" is unavailable.`);
568
+ }
569
+ if (source.resolution.sourceIdentity !== sourceIdentity) {
570
+ throw new Error(`sourceChanged: ${options.selector} config source identity does not match the current source.`);
571
+ }
572
+ },
573
+ });
574
+ return {
575
+ pluginName: parsed.pluginName,
576
+ pluginId: options.selector,
577
+ sourceId: parsed.sourceId,
578
+ sourceIdentity,
579
+ };
580
+ }
581
+ async function resolveMultiSourceConfigRead(options) {
582
+ const inventory = await inventoryLegacyConfigReferences({
583
+ cwd: options.context.cwd,
584
+ env: options.context.env,
585
+ });
586
+ assertCatalogSourceReferencesSupported(inventory);
587
+ return withResolvedCatalogPlugin({
588
+ selector: options.selector,
589
+ cliVersion: resolveCliVersion(),
590
+ env: options.context.env,
591
+ consume: async ({ pluginId, source, plugin }) => {
592
+ const result = await resolveConfigRead({
593
+ pluginName: plugin.manifest.name,
594
+ plugin,
595
+ scope: resolveConfigReadResolution(options.rawOptions.scope),
596
+ cwd: options.context.cwd,
597
+ env: options.context.env,
598
+ });
599
+ if (options.key !== undefined) {
600
+ const field = findConfigFieldEntry(result.fields, options.key);
601
+ if (!field && plugin.manifest.config?.fields?.[options.key] === undefined) {
602
+ throw new Error(`Unknown config key "${options.key}".`);
603
+ }
604
+ if (field)
605
+ result.fields = [field];
606
+ }
607
+ return {
608
+ pluginName: plugin.manifest.name,
609
+ pluginId,
610
+ sourceId: source.sourceId,
611
+ sourceIdentity: source.sourceIdentity,
612
+ result,
613
+ };
614
+ },
615
+ }).catch(async (error) => {
616
+ const message = error instanceof Error ? error.message : String(error);
617
+ if (!message.includes('does not exist in the required catalog source set'))
618
+ throw error;
619
+ const stored = await resolveStoredOnlyConfigIdentity({
620
+ selector: options.selector,
621
+ context: options.context,
622
+ locations: configReadStoreLocations(options.rawOptions),
623
+ });
624
+ const result = await resolveConfigRead({
625
+ sourceId: stored.sourceId,
626
+ sourceIdentity: stored.sourceIdentity,
627
+ pluginName: stored.pluginName,
628
+ plugin: null,
629
+ scope: resolveConfigReadResolution(options.rawOptions.scope),
630
+ cwd: options.context.cwd,
631
+ env: options.context.env,
632
+ });
633
+ if (options.key !== undefined) {
634
+ const field = findConfigFieldEntry(result.fields, options.key);
635
+ if (!field)
636
+ throw new Error(`Unknown config key "${options.key}".`);
637
+ result.fields = [field];
638
+ }
639
+ return { ...stored, result };
640
+ });
641
+ }
642
+ export function createManagedCodexAuthorizer(rawOptions, context) {
643
+ if (rawOptions.allowManagedCodexInstall === true)
644
+ return async () => true;
645
+ if (!(context.interactive && context.isTty && !context.isCi && rawOptions.json !== true)
646
+ || !context.prompt.confirm)
647
+ return undefined;
648
+ return async () => {
649
+ const response = await context.prompt.confirm({
650
+ message: '系统中没有可用的 Codex CLI。是否获取本次操作所需的 AW-managed Codex runtime?',
651
+ defaultValue: false,
652
+ });
653
+ return !response.cancelled && response.value === true;
654
+ };
655
+ }
656
+ async function executeWriteCommand(command, pluginNames, rawOptions, context, directCli = false) {
657
+ const raw = { cwd: context.cwd, ...rawOptions };
658
+ const commandOptions = normalizeWriteRequest(() => command === 'install'
659
+ ? normalizeInstallCommandOptions(raw)
660
+ : command === 'uninstall'
661
+ ? normalizeUninstallCommandOptions(raw)
662
+ : command === 'cleanup'
663
+ ? normalizeCleanupCommandOptions(raw)
664
+ : normalizeReinstallCommandOptions(raw));
665
+ await emitCommandEvent(context, {
666
+ type: 'options:normalized',
667
+ data: { plugins: pluginNames, options: commandOptions },
668
+ });
669
+ const managedCodexAuthorizer = createManagedCodexAuthorizer(rawOptions, context);
670
+ const runtime = {
671
+ ...context,
672
+ directCli,
673
+ ...(managedCodexAuthorizer ? { managedCodexAuthorizer } : {}),
674
+ };
675
+ switch (command) {
676
+ case 'install': return installCommand(pluginNames, commandOptions, runtime);
677
+ case 'uninstall': return uninstallCommand(pluginNames, commandOptions, runtime);
678
+ case 'cleanup': return cleanupCommand(pluginNames, commandOptions, runtime);
679
+ case 'reinstall': return reinstallCommand(pluginNames, commandOptions, runtime);
680
+ }
681
+ }
682
+ async function runWriteCommandAction(command, pluginNames, rawOptions, context) {
683
+ if ((command === 'cleanup' || command === 'reinstall') && pluginNames.length > 1) {
684
+ throw new WriteCommandRequestError(`${command} 命令当前只支持单个插件目标。`);
685
+ }
686
+ const missingPlugin = pluginNames.length === 0;
687
+ const missingPlatform = rawOptions.platform === undefined;
688
+ const missingScope = command === 'cleanup' && rawOptions.scope === undefined;
689
+ const missing = missingPlugin || missingPlatform || missingScope;
690
+ // Validate every value already supplied by the caller before opening the TUI.
691
+ const validationOptions = {
692
+ cwd: context.cwd,
693
+ ...rawOptions,
694
+ platform: rawOptions.platform ?? 'both',
695
+ ...(command === 'cleanup' ? { scope: rawOptions.scope ?? 'user' } : {}),
696
+ };
697
+ void validationOptions;
698
+ if (!missing) {
699
+ return {
700
+ cancelled: false,
701
+ result: await executeWriteCommand(command, pluginNames, rawOptions, context, true),
702
+ };
703
+ }
704
+ if (!isWizardAvailable(context, rawOptions)) {
705
+ throw new WriteCommandRequestError(writeCommandUsage(command));
706
+ }
707
+ const loaded = await loadConsoleItemsResult({
708
+ cwd: context.cwd,
709
+ scope: rawOptions.scope,
710
+ platform: rawOptions.platform,
711
+ }, context);
712
+ if (loaded.catalogUnavailable) {
713
+ throw new Error('插件目录不可用。请运行 `aw init` 或 `aw init --force`,或使用完整参数重试。');
714
+ }
715
+ const candidates = missingPlugin ? toWizardCandidates(loaded.items) : [];
716
+ const initialSelection = {
717
+ plugins: pluginNames,
718
+ platform: rawOptions.platform,
719
+ scope: (rawOptions.scope ?? 'user'),
720
+ };
721
+ if (missingPlugin && !hasSelectableWriteCandidate(command, candidates, initialSelection, {
722
+ missingPlatform,
723
+ missingScope,
724
+ })) {
725
+ throw new Error('没有可执行此操作的目标。请运行 `aw status` 检查当前状态。');
726
+ }
727
+ const result = await runCommandWizard(context, {
728
+ command,
729
+ candidates,
730
+ initial: initialSelection,
731
+ pluginMode: missingPlugin
732
+ ? command === 'cleanup' || command === 'reinstall' ? 'single' : 'multiple'
733
+ : 'none',
734
+ promptForPlatform: missingPlatform,
735
+ promptForScope: missingScope,
736
+ destructive: command === 'uninstall' || command === 'cleanup',
737
+ equivalentCommand: (selection) => equivalentWriteCommand(command, selection, rawOptions),
738
+ equivalentCommandTokens: (selection) => buildEquivalentWriteCommandTokens(command, selection, rawOptions),
739
+ isPluginSelectable: (candidate, selection) => writeCandidateEligibility(command, candidate, selection),
740
+ resultState: overallResultState,
741
+ execute: (selection) => executeWriteCommand(command, selection.plugins, {
742
+ ...rawOptions,
743
+ platform: selection.platform,
744
+ scope: selection.scope,
745
+ }, context),
746
+ });
747
+ if (result.cancelled)
748
+ return { cancelled: true };
749
+ return { cancelled: false, result: result.value };
750
+ }
751
+ function parseBareConsoleOptions(argv) {
752
+ if (argv.length === 0) {
753
+ return {};
754
+ }
755
+ const parsed = {};
756
+ for (let index = 0; index < argv.length; index += 1) {
757
+ const token = argv[index];
758
+ if (!token) {
759
+ continue;
760
+ }
761
+ if (token === '--help' || token === '-h' || token === '--version' || token === '-V') {
762
+ return null;
763
+ }
764
+ if (token === '-v' || token === '--verbose') {
765
+ parsed.verbose = true;
766
+ continue;
767
+ }
768
+ if (token === '-D' || token === '--debug') {
769
+ parsed.debug = true;
770
+ continue;
771
+ }
772
+ if (token === '--log-file') {
773
+ parsed.logFile = readBareConsoleOptionValue(argv[index + 1], '--log-file <path>');
774
+ index += 1;
775
+ continue;
776
+ }
777
+ if (token.startsWith('--log-file=')) {
778
+ parsed.logFile = readBareConsoleOptionValue(token.slice('--log-file='.length), '--log-file <path>');
779
+ continue;
780
+ }
781
+ return null;
782
+ }
783
+ return parsed;
784
+ }
785
+ function readBareConsoleOptionValue(value, option) {
786
+ if (!value || value.startsWith('-')) {
787
+ throw new Error(`option '${option}' argument missing`);
788
+ }
789
+ return value;
790
+ }
791
+ async function runActionWithContext(context, action) {
792
+ await emitCommandEvent(context, {
793
+ type: 'command:start',
794
+ data: {
795
+ cwd: context.cwd,
796
+ verbose: context.diagnostics.verbose,
797
+ debug: context.diagnostics.debug,
798
+ logFile: context.diagnostics.logFile,
799
+ },
800
+ });
801
+ try {
802
+ const result = await action();
803
+ await emitCommandEvent(context, { type: 'command:success' });
804
+ await Promise.allSettled([
805
+ Promise.resolve().then(() => context.debugLogger.flush?.()),
806
+ ]);
807
+ if (context.diagnostics.debug && context.debugLogger.logFile) {
808
+ writeLine(context.io.stderr, `调试日志:${context.debugLogger.logFile}`);
809
+ }
810
+ return result;
811
+ }
812
+ catch (error) {
813
+ if (error instanceof WizardExecutionError) {
814
+ const diagnostic = error.diagnostic;
815
+ await Promise.allSettled([
816
+ Promise.resolve().then(() => context.reporter.event({
817
+ type: 'command:error',
818
+ commandName: context.diagnostics.commandName,
819
+ message: error.message,
820
+ data: { name: error.name },
821
+ })),
822
+ Promise.resolve().then(() => context.debugLogger.log(redactValue({
823
+ type: 'command:error',
824
+ commandName: context.diagnostics.commandName,
825
+ message: diagnostic instanceof Error ? diagnostic.message : error.message,
826
+ data: diagnostic instanceof Error
827
+ ? { name: diagnostic.name, stack: diagnostic.stack }
828
+ : { result: diagnostic },
829
+ }))),
830
+ ]);
831
+ }
832
+ else {
833
+ await emitCommandEvent(context, {
834
+ type: 'command:error',
835
+ message: error instanceof Error ? error.message : String(error),
836
+ data: error instanceof Error
837
+ ? {
838
+ name: error.name,
839
+ stack: error.stack,
840
+ }
841
+ : undefined,
842
+ });
843
+ }
844
+ await Promise.allSettled([
845
+ Promise.resolve().then(() => context.debugLogger.flush?.()),
846
+ ]);
847
+ if (context.diagnostics.debug && context.debugLogger.logFile) {
848
+ writeLine(context.io.stderr, `调试日志:${context.debugLogger.logFile}`);
849
+ }
850
+ throw error;
851
+ }
852
+ }
853
+ function writeJsonReceipt(write, payload) {
854
+ writeLine(write, JSON.stringify(payload, null, 2));
855
+ }
856
+ function configLayerLabel(scope) {
857
+ if (scope === 'user') {
858
+ return '个人';
859
+ }
860
+ return '当前项目';
861
+ }
862
+ function writeConfigApplyNotice(write, receipt) {
863
+ if (receipt.targetResults.length === 0) {
864
+ const message = receipt.applySkippedReason === 'noConfigChange'
865
+ ? '配置内容没有变化,因此没有运行 reinstall。'
866
+ : receipt.applySkippedReason === 'invalidConfig'
867
+ ? '配置已保存,但当前配置无效,因此没有运行 reinstall。请先修复无效字段。'
868
+ : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
869
+ writeLine(write, message);
870
+ }
871
+ else {
872
+ const completed = receipt.targetResults.filter((entry) => entry.state === 'completed').length;
873
+ const failed = receipt.targetResults.filter((entry) => entry.state === 'failed');
874
+ writeLine(write, `配置已保存。已重装 ${completed} 个当前可见目标;失败 ${failed.length} 个。`);
875
+ for (const entry of failed) {
876
+ writeLine(write, `${entry.target.platform}/${entry.target.scope}:${entry.message ?? 'reinstall 失败。'} `
877
+ + `请重试 aw reinstall ${receipt.plugin} -p ${entry.target.platform} -s ${entry.target.scope}。`);
878
+ }
879
+ }
880
+ if (receipt.otherProjectsRequireReinstall) {
881
+ writeLine(write, '其它项目没有被扫描。请进入每个项目目录并运行对应的 aw reinstall 命令。');
882
+ }
883
+ }
884
+ function renderConfigFieldState(field) {
885
+ if (field.valueState === 'invalid') {
886
+ return 'invalid-config';
887
+ }
888
+ return field.valueState;
889
+ }
890
+ function writeConfigReadHuman(write, resolved, pluginName) {
891
+ for (const field of resolved.fields) {
892
+ const effectiveValue = field.effectiveValue === null
893
+ ? '<unset>'
894
+ : renderPluginConfigValueForDisplay(field.effectiveValue);
895
+ const source = field.sourceLayer ?? 'none';
896
+ writeLine(write, `${field.key}: ${renderConfigFieldState(field)} (source=${source}, effective=${effectiveValue})`);
897
+ if (field.storedValue !== undefined && field.storedSourceLayer) {
898
+ writeLine(write, ` stored=${field.storedSourceLayer} ${renderPluginConfigValueForDisplay(field.storedValue)}`);
899
+ }
900
+ if (field.kind === 'manifest' && field.valueState === 'invalid') {
901
+ const sourceScope = field.sourceLayer === 'project'
902
+ ? ' -s project'
903
+ : ' -s user';
904
+ writeLine(write, ` aw config set ${pluginName} ${field.key}${sourceScope} --value-json '<json>'`);
905
+ writeLine(write, ` aw config unset ${pluginName} ${field.key}${sourceScope}`);
906
+ writeLine(write, ` aw config reset ${pluginName}${sourceScope}`);
907
+ }
908
+ }
909
+ }
910
+ export function buildProgram(options = {}) {
911
+ const cwd = options.cwd ?? process.cwd();
912
+ const env = options.env ?? process.env;
913
+ const commandExitState = { exitCode: 0 };
914
+ const io = {
915
+ ...createDefaultIo(),
916
+ ...options.io,
917
+ };
918
+ const createActionContext = (commandName, rawOptions) => createCliExecutionContext({
919
+ ...options,
920
+ cwd,
921
+ env,
922
+ io,
923
+ interactive: options.interactive,
924
+ diagnostics: toCliDiagnosticsOptions(commandName, rawOptions, options.diagnostics),
925
+ });
926
+ const program = new Command();
927
+ program
928
+ .name('aw')
929
+ .description('Agent workflow marketplace installer')
930
+ .version(resolveCliVersion(), '-V, --version', 'output the current aw cli version')
931
+ .exitOverride()
932
+ .configureOutput({
933
+ writeOut: (text) => io.stdout(text),
934
+ writeErr: (text) => io.stderr(text),
935
+ outputError: (text, write) => write(text),
936
+ });
937
+ const plugin = program
938
+ .command('plugin')
939
+ .description('Create and validate AW plugin source');
940
+ const self = program
941
+ .command('self')
942
+ .description('Describe and check this AW executable');
943
+ self
944
+ .command('describe')
945
+ .description('Describe implemented AW capabilities')
946
+ .requiredOption('--json', 'emit one machine-readable JSON object')
947
+ .action(() => {
948
+ writeJsonReceipt(io.stdout, describeCurrentAw(resolveCliVersion()));
949
+ });
950
+ self
951
+ .command('check')
952
+ .description('Check nearby plugin requirements against this AW executable')
953
+ .option('--from <path>', 'start discovery from this file or directory')
954
+ .requiredOption('--json', 'emit one machine-readable JSON object')
955
+ .action(async (rawOptions) => {
956
+ const result = await checkCurrentAw({
957
+ awVersion: resolveCliVersion(),
958
+ from: path.resolve(cwd, rawOptions.from ?? '.'),
959
+ });
960
+ writeJsonReceipt(io.stdout, result);
961
+ commandExitState.exitCode = result.ok ? 0 : 1;
962
+ });
963
+ plugin
964
+ .command('capabilities')
965
+ .description('Show the current plugin manifest authoring surface')
966
+ .option('--surface <surface>', 'manifest | build-config | extensions | slash-commands | mcp-apps | config | post-apply | artifacts')
967
+ .option('--json', 'emit one machine-readable JSON object', false)
968
+ .action((rawOptions) => {
969
+ try {
970
+ const surface = rawOptions.surface === undefined
971
+ ? undefined
972
+ : parsePluginCapabilitySurface(rawOptions.surface);
973
+ const result = getPluginCapabilitiesResult({
974
+ awVersion: resolveCliVersion(),
975
+ ...(surface ? { surface } : {}),
976
+ });
977
+ if (rawOptions.json)
978
+ writeJsonReceipt(io.stdout, result);
979
+ else
980
+ for (const line of renderPluginCapabilities(result))
981
+ writeLine(io.stdout, line);
982
+ }
983
+ catch (error) {
984
+ writeLine(io.stderr, error instanceof Error ? error.message : String(error));
985
+ commandExitState.exitCode = 1;
986
+ }
987
+ });
988
+ plugin
989
+ .command('requirements')
990
+ .description('Inspect or update effective AW capabilities required by a plugin')
991
+ .argument('<plugin-directory>', 'plugin source directory')
992
+ .option('--workspace-root <root>', 'Catalog Workspace root (default: nearest ancestor from plugin directory)')
993
+ .option('--add <capability>', 'add one declared AW capability')
994
+ .option('--remove <capability>', 'remove one declared AW capability')
995
+ .requiredOption('--json', 'emit one machine-readable JSON object')
996
+ .action(async (pluginDirectory, rawOptions) => {
997
+ try {
998
+ const result = await inspectPluginRequirements({
999
+ pluginDirectory,
1000
+ ...(rawOptions.workspaceRoot ? { workspaceRoot: rawOptions.workspaceRoot } : {}),
1001
+ ...(rawOptions.add ? { add: rawOptions.add } : {}),
1002
+ ...(rawOptions.remove ? { remove: rawOptions.remove } : {}),
1003
+ cwd,
1004
+ });
1005
+ writeJsonReceipt(io.stdout, result);
1006
+ if (result.observations.some((observation) => observation.blocking)) {
1007
+ commandExitState.exitCode = 1;
1008
+ }
1009
+ }
1010
+ catch (error) {
1011
+ writeJsonReceipt(io.stdout, {
1012
+ schemaVersion: 1,
1013
+ command: 'plugin:requirements',
1014
+ ok: false,
1015
+ error: error instanceof Error ? error.message : String(error),
1016
+ });
1017
+ commandExitState.exitCode = 1;
1018
+ }
1019
+ });
1020
+ const skill = program
1021
+ .command('skill')
1022
+ .description('Install, materialize, or validate Agent Skills');
1023
+ const skillEval = skill
1024
+ .command('eval')
1025
+ .description('Prepare or diagnose deterministic Agent Skill Eval inputs');
1026
+ skillEval
1027
+ .command('doctor')
1028
+ .description('Inspect Agent Skill Eval provider readiness without model execution')
1029
+ .requiredOption('--json', 'emit one provider doctor JSON object')
1030
+ .action(async () => {
1031
+ try {
1032
+ writeJsonReceipt(io.stdout, await doctorEvalProviders({ sourceEnv: env }));
1033
+ }
1034
+ catch (error) {
1035
+ writeJsonReceipt(io.stdout, {
1036
+ ok: false,
1037
+ error: redactString(error instanceof Error ? error.message : String(error)),
1038
+ });
1039
+ commandExitState.exitCode = 1;
1040
+ }
1041
+ });
1042
+ skillEval
1043
+ .command('prepare')
1044
+ .description('Prepare one complete Agent Skill Eval input directory')
1045
+ .argument('<plugin>', 'canonical Workspace plugin name')
1046
+ .argument('<skill>', 'owner Skill name')
1047
+ .option('--suite <suite>', 'Eval suite ID')
1048
+ .option('--profile <profile>', 'Eval profile ID')
1049
+ .option('--workspace-root <root>', 'Catalog Workspace root')
1050
+ .option('--split <split>', 'case split filter')
1051
+ .option('--case <id>', 'case ID filter')
1052
+ .option('--runs <count>', 'runs per selected case')
1053
+ .option('--timeout-ms <milliseconds>', 'timeout for each provider attempt')
1054
+ .option('--baseline <mode>', 'append without-skill comparison')
1055
+ .option('--previous-version <runtime-skill-root>', 'append a previous-version comparison')
1056
+ .option('--keep-workspace', 'retain the preparation materialization workspace', false)
1057
+ .requiredOption('--output <spec-directory>', 'new EvalSpec directory')
1058
+ .requiredOption('--json', 'emit one preparation receipt JSON object')
1059
+ .action(async (pluginName, skillName, rawOptions) => {
1060
+ try {
1061
+ const workspace = await resolveCatalogWorkspaceRoot({
1062
+ cwd,
1063
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: rawOptions.workspaceRoot }),
1064
+ mode: 'existing',
1065
+ env,
1066
+ });
1067
+ const runs = rawOptions.runs === undefined
1068
+ ? undefined
1069
+ : (/^[1-9][0-9]*$/u.test(rawOptions.runs) ? Number(rawOptions.runs) : Number.NaN);
1070
+ const timeoutMs = rawOptions.timeoutMs === undefined
1071
+ ? undefined
1072
+ : (/^[1-9][0-9]*$/u.test(rawOptions.timeoutMs) ? Number(rawOptions.timeoutMs) : Number.NaN);
1073
+ const receipt = await prepareSkillEval({
1074
+ workspaceRoot: workspace.workspaceRoot,
1075
+ workspaceRootResolvedFrom: workspace.workspaceRootResolvedFrom,
1076
+ pluginName,
1077
+ skillName,
1078
+ ...(rawOptions.suite === undefined ? {} : { suiteId: rawOptions.suite }),
1079
+ ...(rawOptions.profile === undefined ? {} : { profileId: rawOptions.profile }),
1080
+ output: rawOptions.output,
1081
+ cwd,
1082
+ env,
1083
+ ...(rawOptions.split === undefined ? {} : { split: rawOptions.split }),
1084
+ ...(rawOptions.case === undefined ? {} : { caseId: rawOptions.case }),
1085
+ ...(runs === undefined ? {} : { runs }),
1086
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
1087
+ ...(rawOptions.baseline === undefined ? {} : {
1088
+ baseline: rawOptions.baseline,
1089
+ }),
1090
+ ...(rawOptions.previousVersion === undefined ? {} : {
1091
+ previousVersion: rawOptions.previousVersion,
1092
+ }),
1093
+ ...(rawOptions.keepWorkspace === true ? { keepWorkspace: true } : {}),
1094
+ });
1095
+ writeJsonReceipt(io.stdout, receipt);
1096
+ }
1097
+ catch (error) {
1098
+ writeJsonReceipt(io.stdout, {
1099
+ schemaVersion: 1,
1100
+ command: 'skill:eval:prepare',
1101
+ ok: false,
1102
+ errors: [{
1103
+ code: 'evalPreparationFailed',
1104
+ message: redactString(error instanceof Error ? error.message : String(error)),
1105
+ }],
1106
+ });
1107
+ commandExitState.exitCode = 1;
1108
+ }
1109
+ });
1110
+ const review = program
1111
+ .command('review')
1112
+ .description('Publish and inspect immutable review records');
1113
+ const reviewRecordDir = (repoRoot, record) => path.relative(fs.realpathSync(repoRoot), record.root).split(path.sep).join('/');
1114
+ const reviewJsonRecord = (repoRoot, record) => ({
1115
+ recordDir: reviewRecordDir(repoRoot, record),
1116
+ manifest: record.manifest,
1117
+ });
1118
+ review
1119
+ .command('digest')
1120
+ .description('Compute one canonical workflow component digest')
1121
+ .argument('<path>', 'repository file or directory')
1122
+ .option('--json', 'emit one component digest JSON object', false)
1123
+ .action(async (componentPath, rawOptions) => {
1124
+ const repoRoot = await resolveRepoRoot(cwd);
1125
+ const result = await computeReviewComponentDigest({ repoRoot, path: componentPath });
1126
+ if (rawOptions.json) {
1127
+ writeJsonReceipt(io.stdout, {
1128
+ schemaVersion: 1,
1129
+ command: 'review:digest',
1130
+ ok: true,
1131
+ ...result,
1132
+ });
1133
+ return;
1134
+ }
1135
+ writeLine(io.stdout, `${result.path}: ${result.digest}`);
1136
+ });
1137
+ review
1138
+ .command('publish')
1139
+ .description('Publish one immutable review record')
1140
+ .requiredOption('--kind <skill|workflow|aw-plugin|aw-workflow>', 'review target kind')
1141
+ .requiredOption('--target <path-or-id>', 'review target path or ID')
1142
+ .requiredOption('--report <report.md>', 'review report Markdown file')
1143
+ .option('--scope <scope.json>', 'workflow scope JSON file')
1144
+ .option('--result <review-result.json>', 'review result JSON file')
1145
+ .option('--check <kind=path>', 'archive one JSON check attachment', (value, previous) => [
1146
+ ...previous,
1147
+ parseReviewAttachment(value, 'Check'),
1148
+ ], [])
1149
+ .option('--evidence <kind=path>', 'archive one JSON evidence attachment', (value, previous) => [
1150
+ ...previous,
1151
+ parseReviewAttachment(value, 'Evidence'),
1152
+ ], [])
1153
+ .option('--release-check <release-check.json>', 'release check JSON file')
1154
+ .option('--supersedes <review-id>', 'review ID that this record supersedes')
1155
+ .option('--json', 'emit one review record JSON object', false)
1156
+ .action(async (rawOptions) => {
1157
+ const repoRoot = await resolveRepoRoot(cwd);
1158
+ const record = await publishReviewRecord({
1159
+ repoRoot,
1160
+ kind: rawOptions.kind,
1161
+ target: rawOptions.target,
1162
+ report: rawOptions.report,
1163
+ ...(rawOptions.scope === undefined ? {} : { scope: rawOptions.scope }),
1164
+ ...(rawOptions.result === undefined ? {} : { result: rawOptions.result }),
1165
+ ...(rawOptions.check.length === 0 ? {} : { checks: rawOptions.check }),
1166
+ ...(rawOptions.evidence.length === 0 ? {} : { evidence: rawOptions.evidence }),
1167
+ ...(rawOptions.releaseCheck === undefined ? {} : { releaseCheck: rawOptions.releaseCheck }),
1168
+ ...(rawOptions.supersedes === undefined ? {} : { supersedes: rawOptions.supersedes }),
1169
+ });
1170
+ const recordDir = reviewRecordDir(repoRoot, record);
1171
+ if (rawOptions.json) {
1172
+ writeJsonReceipt(io.stdout, {
1173
+ schemaVersion: 1,
1174
+ command: 'review:publish',
1175
+ ok: true,
1176
+ ...reviewJsonRecord(repoRoot, record),
1177
+ existing: record.existing,
1178
+ });
1179
+ return;
1180
+ }
1181
+ writeLine(io.stdout, `${record.existing ? 'Existing' : 'Published'} review ${record.manifest.reviewId}: ${recordDir}`);
1182
+ });
1183
+ review
1184
+ .command('verify')
1185
+ .description('Verify one archived review record')
1186
+ .argument('<report-dir>', 'review record directory')
1187
+ .option('--json', 'emit one review record JSON object', false)
1188
+ .action(async (reportDir, rawOptions) => {
1189
+ const repoRoot = await resolveRepoRoot(cwd);
1190
+ const record = await verifyReviewRecord({ repoRoot, reportDir });
1191
+ const relativeRecordDir = reviewRecordDir(repoRoot, record);
1192
+ if (rawOptions.json) {
1193
+ writeJsonReceipt(io.stdout, {
1194
+ schemaVersion: 1,
1195
+ command: 'review:verify',
1196
+ ok: true,
1197
+ ...reviewJsonRecord(repoRoot, record),
1198
+ });
1199
+ return;
1200
+ }
1201
+ writeLine(io.stdout, `Verified review ${record.manifest.reviewId}: ${relativeRecordDir}`);
1202
+ });
1203
+ review
1204
+ .command('list')
1205
+ .description('List immutable review records')
1206
+ .option('--kind <kind>', 'filter by review target kind')
1207
+ .option('--target <id>', 'filter by review target ID')
1208
+ .option('--json', 'emit one review records JSON object', false)
1209
+ .action(async (rawOptions) => {
1210
+ const repoRoot = await resolveRepoRoot(cwd);
1211
+ const records = await listReviewRecords({
1212
+ repoRoot,
1213
+ ...(rawOptions.kind === undefined ? {} : { kind: rawOptions.kind }),
1214
+ ...(rawOptions.target === undefined ? {} : { targetId: rawOptions.target }),
1215
+ });
1216
+ if (rawOptions.json) {
1217
+ writeJsonReceipt(io.stdout, {
1218
+ schemaVersion: 1,
1219
+ command: 'review:list',
1220
+ ok: true,
1221
+ records: records.map((record) => reviewJsonRecord(repoRoot, record)),
1222
+ });
1223
+ return;
1224
+ }
1225
+ for (const record of records) {
1226
+ writeLine(io.stdout, [
1227
+ record.manifest.reviewId,
1228
+ record.manifest.target.kind,
1229
+ record.manifest.target.id,
1230
+ record.manifest.publishedAt,
1231
+ ].join(' '));
1232
+ }
1233
+ });
1234
+ review
1235
+ .command('show')
1236
+ .description('Show one immutable review record')
1237
+ .argument('<review-id>', 'review record ID')
1238
+ .option('--json', 'emit one review record JSON object', false)
1239
+ .action(async (reviewId, rawOptions) => {
1240
+ const repoRoot = await resolveRepoRoot(cwd);
1241
+ const record = await showReviewRecord({ repoRoot, reviewId });
1242
+ if (rawOptions.json) {
1243
+ writeJsonReceipt(io.stdout, {
1244
+ schemaVersion: 1,
1245
+ command: 'review:show',
1246
+ ok: true,
1247
+ ...reviewJsonRecord(repoRoot, record),
1248
+ });
1249
+ return;
1250
+ }
1251
+ const manifest = record.manifest;
1252
+ writeLine(io.stdout, `Review: ${manifest.reviewId}`);
1253
+ writeLine(io.stdout, `Target: ${manifest.target.kind} ${manifest.target.id}`);
1254
+ writeLine(io.stdout, `Published: ${manifest.publishedAt}`);
1255
+ writeLine(io.stdout, `Report: ${manifest.report.path}`);
1256
+ writeLine(io.stdout, `Result: ${manifest.result?.path ?? 'none'}`);
1257
+ writeLine(io.stdout, `Checks: ${manifest.checks.map((entry) => entry.kind).join(', ') || 'none'}`);
1258
+ writeLine(io.stdout, `Evidence: ${manifest.evidence.map((entry) => entry.kind).join(', ') || 'none'}`);
1259
+ writeLine(io.stdout, `Release check: ${manifest.releaseCheck?.path ?? 'none'}`);
1260
+ writeLine(io.stdout, `Supersedes: ${manifest.supersedes ?? 'none'}`);
1261
+ });
1262
+ skill
1263
+ .command('install')
1264
+ .description('Install portable Skills through the skills CLI')
1265
+ .argument('<plugin>', 'plugin or source/plugin selector')
1266
+ .requiredOption('-s, --scope <scope>', 'project or user')
1267
+ .option('--skill <name...>', 'install only selected Skill names')
1268
+ .option('--agent <id...>', 'install to explicit Agent IDs')
1269
+ .option('-y, --yes', 'confirm the reviewed install', false)
1270
+ .option('-j, --json', 'emit one receipt v5 JSON object', false)
1271
+ .action(async (selector, rawOptions) => {
1272
+ const context = createActionContext('skill:install', {});
1273
+ const writeFailure = (error) => {
1274
+ const capabilityError = error instanceof AwCapabilityUnsupportedError ? error : undefined;
1275
+ const code = capabilityError?.code
1276
+ ?? (error instanceof PortableCommandError || error instanceof SkillsCliError
1277
+ ? error.code
1278
+ : 'portableInstallFailed');
1279
+ writeJsonReceipt(io.stdout, {
1280
+ receiptSchemaVersion: 5,
1281
+ command: 'skill:install',
1282
+ ok: false,
1283
+ status: 'failed',
1284
+ plugin: { id: selector },
1285
+ scope: rawOptions.scope,
1286
+ selectedSkills: [],
1287
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
1288
+ agentMode: rawOptions.agent ? 'explicit' : 'automatic',
1289
+ requestedAgents: rawOptions.agent ?? [],
1290
+ skillsCliVersion: null,
1291
+ collisions: [],
1292
+ dependencies: [],
1293
+ materializationDigest: null,
1294
+ verification: { records: [], missing: [] },
1295
+ warnings: [],
1296
+ failures: [{
1297
+ code,
1298
+ message: capabilityError?.message ?? `${code}: portable Skill 安装未执行。`,
1299
+ ...(capabilityError ? {
1300
+ plugin: capabilityError.plugin,
1301
+ missingCapabilities: capabilityError.missingCapabilities,
1302
+ availableCapabilities: capabilityError.availableCapabilities,
1303
+ } : {}),
1304
+ }],
1305
+ });
1306
+ };
1307
+ if (rawOptions.json && !rawOptions.yes) {
1308
+ writeFailure(new PortableCommandError('confirmationRequired', '写入型 --json 必须同时使用 --yes。'));
1309
+ commandExitState.exitCode = 1;
1310
+ return;
1311
+ }
1312
+ try {
1313
+ const receipt = await runActionWithContext(context, () => installPortableSkills({
1314
+ selector,
1315
+ scope: rawOptions.scope,
1316
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
1317
+ ...(rawOptions.agent ? { requestedAgents: rawOptions.agent } : {}),
1318
+ yes: rawOptions.yes,
1319
+ cwd: context.cwd,
1320
+ cliVersion: resolveCliVersion(),
1321
+ env: context.env,
1322
+ ...(context.interactive && context.prompt.confirm ? {
1323
+ confirm: async () => context.prompt.confirm({
1324
+ message: '确认按以上 Review 安装 portable Skills?',
1325
+ defaultValue: false,
1326
+ }),
1327
+ } : {}),
1328
+ ...(!rawOptions.json ? {
1329
+ onReview: (review) => {
1330
+ for (const line of renderPortableReview(review))
1331
+ writeLine(io.stdout, line);
1332
+ },
1333
+ } : {}),
1334
+ }));
1335
+ if (rawOptions.json)
1336
+ writeJsonReceipt(io.stdout, receipt);
1337
+ else if (receipt.ok)
1338
+ writeLine(io.stdout, `portable Skill 安装完成:${receipt.selectedSkills.length} 项。`);
1339
+ else {
1340
+ const sanitize = (value) => redactString(value)
1341
+ .replace(/https?:\/\/\S+/giu, '[REDACTED URL]')
1342
+ .replace(/(?:file:\/\/)?(?:\/[\w.@+-]+){2,}/gu, '[REDACTED PATH]')
1343
+ .replace(/[A-Za-z]:\\(?:[^\s\\]+\\)+[^\s\\]*/gu, '[REDACTED PATH]');
1344
+ const lines = new Set();
1345
+ for (const failure of receipt.failures) {
1346
+ lines.add(`${failure.code}: ${sanitize(failure.message)}`);
1347
+ }
1348
+ for (const warning of receipt.warnings)
1349
+ lines.add(`警告:${sanitize(warning)}`);
1350
+ const recoveries = receipt.failures.map((failure) => failure.recovery).filter(Boolean);
1351
+ const recovery = recoveries.find((entry) => entry.includes('aw skill install')
1352
+ && entry.includes('skills remove'))
1353
+ ?? '重新运行 aw skill install;如需清理外部写入,请使用 skills remove。';
1354
+ lines.add(`恢复:${sanitize(recovery)}`);
1355
+ for (const line of lines)
1356
+ writeLine(io.stderr, line);
1357
+ }
1358
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
1359
+ }
1360
+ catch (error) {
1361
+ if (!rawOptions.json)
1362
+ throw error;
1363
+ writeFailure(error);
1364
+ commandExitState.exitCode = 1;
1365
+ }
1366
+ });
1367
+ skill
1368
+ .command('materialize')
1369
+ .description('Write portable Skills to a safe output directory')
1370
+ .argument('<plugin>', 'plugin or source/plugin selector')
1371
+ .requiredOption('-s, --scope <scope>', 'project or user')
1372
+ .requiredOption('--out <dir>', 'output directory')
1373
+ .option('--skill <name...>', 'write only selected Skill names')
1374
+ .option('-j, --json', 'emit one receipt v5 JSON object', false)
1375
+ .action(async (selector, rawOptions) => {
1376
+ const context = createActionContext('skill:materialize', {});
1377
+ try {
1378
+ const receipt = await runActionWithContext(context, () => materializePortableSkillsToDirectory({
1379
+ selector,
1380
+ scope: rawOptions.scope,
1381
+ out: rawOptions.out,
1382
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
1383
+ cwd: context.cwd,
1384
+ cliVersion: resolveCliVersion(),
1385
+ env: context.env,
1386
+ }));
1387
+ if (rawOptions.json)
1388
+ writeJsonReceipt(io.stdout, receipt);
1389
+ else
1390
+ writeLine(io.stdout, `portable Skill 已写入 ${receipt.out}:${receipt.selectedSkills.length} 项。`);
1391
+ }
1392
+ catch (error) {
1393
+ if (!rawOptions.json)
1394
+ throw error;
1395
+ const capabilityError = error instanceof AwCapabilityUnsupportedError ? error : undefined;
1396
+ const code = capabilityError?.code
1397
+ ?? (error instanceof PortableCommandError || error instanceof SkillsCliError
1398
+ ? error.code
1399
+ : 'portableMaterializeFailed');
1400
+ writeJsonReceipt(io.stdout, {
1401
+ receiptSchemaVersion: 5,
1402
+ command: 'skill:materialize',
1403
+ ok: false,
1404
+ plugin: { id: selector },
1405
+ scope: rawOptions.scope,
1406
+ out: path.resolve(context.cwd, rawOptions.out),
1407
+ selectedSkills: [],
1408
+ ...(rawOptions.skill ? { requestedSkills: rawOptions.skill } : {}),
1409
+ dependencies: [],
1410
+ configDigest: null,
1411
+ materializationDigest: null,
1412
+ outputDigest: null,
1413
+ errors: [{
1414
+ code,
1415
+ message: capabilityError?.message ?? `${code}: portable Skill 导出未执行。`,
1416
+ ...(capabilityError ? {
1417
+ plugin: capabilityError.plugin,
1418
+ missingCapabilities: capabilityError.missingCapabilities,
1419
+ availableCapabilities: capabilityError.availableCapabilities,
1420
+ } : {}),
1421
+ }],
1422
+ });
1423
+ commandExitState.exitCode = 1;
1424
+ }
1425
+ });
1426
+ plugin
1427
+ .command('init')
1428
+ .description('Create a new deterministic plugin scaffold')
1429
+ .addHelpText('after', [
1430
+ '',
1431
+ 'During development, keep the current stable target when production content changes.',
1432
+ 'Next, run `aw plugin validate`, `aw plugin test`, `aw plugin build`, and `aw catalog build`.',
1433
+ 'Publish only as an explicit later step; inspect `aw catalog publish plan --help` first.',
1434
+ '',
1435
+ ].join('\n'))
1436
+ .argument('<plugin-name>', 'lowercase hyphen-case plugin name')
1437
+ .option('--description <text>', 'plugin description (required)')
1438
+ .option('--display-name <text>', 'human-facing plugin display name')
1439
+ .option('--short-description <text>', 'short plugin UI description')
1440
+ .option('--skill-name <name>', 'initial static Skill name')
1441
+ .option('--skill-description <text>', 'initial Skill goal and discovery description')
1442
+ .option('--skill-short-description <text>', 'initial Skill UI summary (25-64 characters)')
1443
+ .option('--skill-invocation <mode>', 'model | manual | claude-model-only (default: model)')
1444
+ .option('--version <semver>', 'initial stable plugin version (default: 0.1.0)')
1445
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1446
+ .option('--no-skills', 'create the plugin without a skills directory')
1447
+ .option('--with-mcp', 'add a minimal .mcp.json', false)
1448
+ .option('--with-apps', 'add a minimal .app.json', false)
1449
+ .option('--with-config-api', 'add AW config schema and helper', false)
1450
+ .option('--with-post-apply', 'add a Node postApply script sample', false);
1451
+ plugin
1452
+ .command('add-skill')
1453
+ .description('Add one static Skill scaffold to an existing plugin')
1454
+ .addHelpText('after', [
1455
+ '',
1456
+ 'During development, keep the current stable target when production content changes.',
1457
+ 'Next, run `aw plugin validate`, `aw plugin test`, `aw plugin build`, and `aw catalog build`.',
1458
+ 'Publish only as an explicit later step; inspect `aw catalog publish plan --help` first.',
1459
+ '',
1460
+ ].join('\n'))
1461
+ .argument('<plugin-name>', 'existing lowercase hyphen-case plugin name')
1462
+ .option('--skill-name <name>', 'new static Skill name (required)')
1463
+ .option('--skill-description <text>', 'Skill goal and discovery description (required)')
1464
+ .option('--skill-short-description <text>', 'Skill UI summary (25-64 characters)')
1465
+ .option('--skill-invocation <mode>', 'model | manual | claude-model-only (default: model)')
1466
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)');
1467
+ plugin
1468
+ .command('remove')
1469
+ .description('Remove one committed and unchanged canonical plugin source tree')
1470
+ .argument('<plugin-name>', 'existing lowercase hyphen-case plugin name')
1471
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1472
+ .option('--yes', 'confirm plugin source deletion', false)
1473
+ .option('--json', 'emit one schema 1 JSON object', false);
1474
+ plugin
1475
+ .command('validate')
1476
+ .description('Validate one source plugin directory')
1477
+ .argument('<plugin-directory>', 'source plugin directory')
1478
+ .option('--strict-agent-skills', 'allow only Agent Skills portable core frontmatter', false)
1479
+ .option('--claude-skill-profile <profile>', 'minimum | current (default: minimum)')
1480
+ .option('--version-base <git-ref>', 'production bundle comparison base (default: HEAD)')
1481
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from plugin directory)')
1482
+ .option('--json', 'emit one machine-readable JSON result', false);
1483
+ plugin
1484
+ .command('test')
1485
+ .description('Run deterministic Node tests declared by one source plugin')
1486
+ .argument('<plugin-directory>', 'source plugin directory')
1487
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from plugin directory)')
1488
+ .option('--json', 'emit one machine-readable JSON result', false)
1489
+ .action(async (pluginDirectory, rawOptions) => {
1490
+ try {
1491
+ const workspace = await resolveCatalogWorkspaceRoot({
1492
+ cwd: path.resolve(cwd, pluginDirectory),
1493
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: path.resolve(cwd, rawOptions.workspaceRoot) }),
1494
+ mode: 'existing',
1495
+ });
1496
+ commandExitState.exitCode = await runPluginTestCommand({
1497
+ ...workspace,
1498
+ pluginDirectory: path.resolve(cwd, pluginDirectory),
1499
+ json: rawOptions.json,
1500
+ io,
1501
+ });
1502
+ }
1503
+ catch (error) {
1504
+ const message = error instanceof Error ? error.message : String(error);
1505
+ if (rawOptions.json)
1506
+ writeJsonReceipt(io.stdout, { command: 'plugin:test', ok: false, errors: [{ message }] });
1507
+ writeLine(io.stderr, message);
1508
+ commandExitState.exitCode = 1;
1509
+ }
1510
+ });
1511
+ plugin
1512
+ .command('build')
1513
+ .description('Build and inspect one source plugin bundle')
1514
+ .argument('<plugin-directory>', 'source plugin directory')
1515
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from plugin directory)')
1516
+ .option('--out <path>', 'output path inside the Catalog Workspace')
1517
+ .option('--force', 'replace an existing generated output', false)
1518
+ .option('--json', 'emit one machine-readable JSON result', false)
1519
+ .action(async (pluginDirectory, rawOptions) => {
1520
+ try {
1521
+ const workspace = await resolveCatalogWorkspaceRoot({
1522
+ cwd: path.resolve(cwd, pluginDirectory),
1523
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: path.resolve(cwd, rawOptions.workspaceRoot) }),
1524
+ mode: 'existing',
1525
+ });
1526
+ await runPluginBuildCommand({
1527
+ ...workspace,
1528
+ pluginDirectory: path.resolve(cwd, pluginDirectory),
1529
+ out: rawOptions.out,
1530
+ force: rawOptions.force,
1531
+ json: rawOptions.json,
1532
+ io,
1533
+ });
1534
+ }
1535
+ catch (error) {
1536
+ const message = error instanceof Error ? error.message : String(error);
1537
+ if (rawOptions.json)
1538
+ writeJsonReceipt(io.stdout, { command: 'plugin:build', ok: false, errors: [{ message }] });
1539
+ writeLine(io.stderr, message);
1540
+ commandExitState.exitCode = 1;
1541
+ }
1542
+ });
1543
+ plugin
1544
+ .command('status')
1545
+ .description('Show current plugin status or compare against an explicit Git base')
1546
+ .argument('[plugin-name]', 'one explicit plugin name')
1547
+ .option('--all', 'check every current Catalog Workspace plugin', false)
1548
+ .option('--base <git-ref>', 'explicit Git comparison base')
1549
+ .option('--json', 'emit one schema v3 JSON document', false)
1550
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)');
1551
+ skill
1552
+ .command('validate')
1553
+ .description('Validate one Agent Skill directory')
1554
+ .argument('<skill-directory>', 'Agent Skill directory')
1555
+ .option('--frontmatter-profile <profile>', 'portable-agent-skills | claude-2.1.88 | claude-current (default: portable-agent-skills)')
1556
+ .option('--codex-metadata <policy>', 'required | optional | ignore (default: optional)')
1557
+ .option('--json', 'emit one machine-readable JSON result', false);
1558
+ const catalog = program
1559
+ .command('catalog')
1560
+ .description('Build and manage catalogs');
1561
+ catalog
1562
+ .command('init')
1563
+ .description('Initialize a local AW Catalog Workspace')
1564
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor, then Git worktree root, then current directory)')
1565
+ .option('--owner-name <name>', 'catalog owner name')
1566
+ .option('--owner-url <url>', 'catalog owner URL')
1567
+ .option('--display-name <name>', 'catalog display name')
1568
+ .option('--catalog-version <version>', 'initial stable or x.y.z-beta.N catalog version (default: 0.1.0)')
1569
+ .option('--force', 'repair a matching managed Catalog Workspace scaffold', false)
1570
+ .option('--json', 'emit one machine-readable JSON result', false)
1571
+ .action(async (rawOptions) => {
1572
+ try {
1573
+ const workspace = await resolveCatalogWorkspaceRoot({
1574
+ cwd,
1575
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: rawOptions.workspaceRoot }),
1576
+ mode: 'initialize',
1577
+ env,
1578
+ });
1579
+ await runCatalogInitCommand({
1580
+ ...rawOptions,
1581
+ ...workspace,
1582
+ io,
1583
+ });
1584
+ }
1585
+ catch (error) {
1586
+ const message = error instanceof Error ? error.message : String(error);
1587
+ if (rawOptions.json)
1588
+ writeJsonReceipt(io.stdout, { command: 'catalog:init', ok: false, errors: [{ message }] });
1589
+ writeLine(io.stderr, message);
1590
+ commandExitState.exitCode = 1;
1591
+ }
1592
+ });
1593
+ catalog
1594
+ .command('version')
1595
+ .description('Read or set the Catalog version')
1596
+ .argument('[version]', 'stable or x.y.z-beta.N catalog version')
1597
+ .option('--bump <level>', 'bump the stable SemVer base: patch, minor, or major')
1598
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1599
+ .option('--json', 'emit one machine-readable JSON result', false)
1600
+ .action(async (version, rawOptions) => {
1601
+ try {
1602
+ const workspace = await resolveCatalogWorkspaceRoot({
1603
+ cwd,
1604
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: rawOptions.workspaceRoot }),
1605
+ mode: 'existing',
1606
+ });
1607
+ await runCatalogVersionCommand({
1608
+ ...workspace,
1609
+ version,
1610
+ bump: rawOptions.bump,
1611
+ json: rawOptions.json,
1612
+ io,
1613
+ });
1614
+ }
1615
+ catch (error) {
1616
+ const message = error instanceof Error ? error.message : String(error);
1617
+ if (rawOptions.json)
1618
+ writeJsonReceipt(io.stdout, { command: 'catalog:version', ok: false, errors: [{ message }] });
1619
+ writeLine(io.stderr, message);
1620
+ commandExitState.exitCode = 1;
1621
+ }
1622
+ });
1623
+ catalog
1624
+ .command('build')
1625
+ .description('Build a deterministic development Catalog snapshot')
1626
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1627
+ .option('--out <path>', 'output path inside the Catalog Workspace')
1628
+ .option('--force', 'replace an existing generated output', false)
1629
+ .option('--json', 'emit one machine-readable JSON result', false)
1630
+ .action(async (rawOptions) => {
1631
+ try {
1632
+ const workspace = await resolveCatalogWorkspaceRoot({
1633
+ cwd,
1634
+ ...(rawOptions.workspaceRoot === undefined ? {} : { explicitRoot: rawOptions.workspaceRoot }),
1635
+ mode: 'existing',
1636
+ });
1637
+ await runCatalogBuildCommand({
1638
+ ...workspace,
1639
+ out: rawOptions.out,
1640
+ force: rawOptions.force,
1641
+ json: rawOptions.json,
1642
+ io,
1643
+ });
1644
+ }
1645
+ catch (error) {
1646
+ const message = error instanceof Error ? error.message : String(error);
1647
+ if (rawOptions.json)
1648
+ writeJsonReceipt(io.stdout, { command: 'catalog:build', ok: false, errors: [{ message }] });
1649
+ writeLine(io.stderr, message);
1650
+ commandExitState.exitCode = 1;
1651
+ }
1652
+ });
1653
+ catalog
1654
+ .command('validate')
1655
+ .description('Validate a schema 7 Catalog snapshot')
1656
+ .argument('<snapshot-directory>', 'Catalog snapshot directory')
1657
+ .option('--json', 'emit one machine-readable JSON result', false)
1658
+ .action(async (snapshotDirectory, rawOptions) => {
1659
+ try {
1660
+ await runCatalogValidateCommand({
1661
+ snapshotDirectory: path.resolve(cwd, snapshotDirectory),
1662
+ json: rawOptions.json,
1663
+ io,
1664
+ });
1665
+ }
1666
+ catch (error) {
1667
+ const message = error instanceof Error ? error.message : String(error);
1668
+ if (rawOptions.json)
1669
+ writeJsonReceipt(io.stdout, { command: 'catalog:validate', ok: false, errors: [{ message }] });
1670
+ writeLine(io.stderr, message);
1671
+ commandExitState.exitCode = 1;
1672
+ }
1673
+ });
1674
+ catalog
1675
+ .command('status')
1676
+ .description('Inspect static Catalog Workspace, snapshot, and Git facts')
1677
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1678
+ .option('--json', 'emit one machine-readable JSON status object', false)
1679
+ .action(async (rawOptions) => {
1680
+ const receipt = await getCatalogStatus({
1681
+ cwd,
1682
+ workspaceRoot: rawOptions.workspaceRoot,
1683
+ env,
1684
+ });
1685
+ if (rawOptions.json)
1686
+ writeJsonReceipt(io.stdout, receipt);
1687
+ else
1688
+ io.stdout(renderCatalogStatus(receipt));
1689
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
1690
+ });
1691
+ const catalogPublish = catalog
1692
+ .command('publish')
1693
+ .description('Plan or apply a versioned Catalog publication');
1694
+ catalogPublish
1695
+ .command('plan')
1696
+ .description('Prepare and inspect the exact Catalog publication plan')
1697
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1698
+ .option('--remote <name>', 'Git remote (default: origin, otherwise sole remote; explicit if ambiguous)')
1699
+ .option('--branch <name>', 'dedicated Catalog branch (default: catalog)')
1700
+ .option('--json', 'emit one machine-readable JSON result', false)
1701
+ .action(async (rawOptions) => {
1702
+ try {
1703
+ const result = await runCatalogPublishPlanCommand({
1704
+ cwd,
1705
+ workspaceRoot: rawOptions.workspaceRoot,
1706
+ remote: rawOptions.remote,
1707
+ branch: rawOptions.branch,
1708
+ env,
1709
+ io,
1710
+ });
1711
+ if (rawOptions.json)
1712
+ writeJsonReceipt(io.stdout, result);
1713
+ else {
1714
+ writeLine(io.stdout, `Workspace identity: ${result.workspaceIdentity}`);
1715
+ writeLine(io.stdout, `Source HEAD: ${result.sourceHead}`);
1716
+ writeLine(io.stdout, `Remote identity: ${result.descriptor.remote.identityDigest}`);
1717
+ writeLine(io.stdout, `Remote: ${result.remote} (${result.remoteUrl})`);
1718
+ writeLine(io.stdout, `Branch: refs/heads/${result.branch}`);
1719
+ writeLine(io.stdout, `Parent: ${result.parent ?? '<root>'}`);
1720
+ writeLine(io.stdout, `Tag: refs/tags/${result.tag}`);
1721
+ writeLine(io.stdout, `Snapshot digest: ${result.snapshotDigest}`);
1722
+ writeLine(io.stdout, `Expected commit: ${result.expectedCommit}`);
1723
+ writeLine(io.stdout, `Plan digest: ${result.planDigest}`);
1724
+ }
1725
+ }
1726
+ catch (error) {
1727
+ const failure = catalogPublicationFailure({
1728
+ error,
1729
+ env,
1730
+ sensitiveRoots: [
1731
+ cwd,
1732
+ ...(rawOptions.workspaceRoot ? [path.resolve(cwd, rawOptions.workspaceRoot)] : []),
1733
+ ],
1734
+ });
1735
+ if (rawOptions.json)
1736
+ writeJsonReceipt(io.stdout, failure);
1737
+ writeLine(io.stderr, failure.message);
1738
+ commandExitState.exitCode = 1;
1739
+ }
1740
+ });
1741
+ catalogPublish
1742
+ .command('apply')
1743
+ .description('Apply an authorized Catalog publication plan')
1744
+ .option('--workspace-root <path>', 'Catalog Workspace root (default: nearest ancestor from current directory)')
1745
+ .option('--remote <name>', 'Git remote (default: origin, otherwise sole remote; explicit if ambiguous)')
1746
+ .option('--branch <name>', 'dedicated Catalog branch (default: catalog)')
1747
+ .requiredOption('--expected-plan-digest <sha256>', 'exact plan digest returned by catalog publish plan')
1748
+ .option('-y, --yes', 'confirm publication without a prompt', false)
1749
+ .option('--json', 'emit one machine-readable JSON result', false)
1750
+ .action(async (rawOptions) => {
1751
+ try {
1752
+ const context = createActionContext('catalog:publish:apply', {});
1753
+ const result = await runCatalogPublishApplyCommand({
1754
+ cwd,
1755
+ workspaceRoot: rawOptions.workspaceRoot,
1756
+ remote: rawOptions.remote,
1757
+ branch: rawOptions.branch,
1758
+ expectedPlanDigest: rawOptions.expectedPlanDigest,
1759
+ yes: rawOptions.yes,
1760
+ json: rawOptions.json,
1761
+ env,
1762
+ interactive: context.interactive,
1763
+ ...(context.prompt.confirm ? {
1764
+ confirm: async (message) => {
1765
+ const response = await context.prompt.confirm({ message, defaultValue: false });
1766
+ return !response.cancelled && response.value === true;
1767
+ },
1768
+ } : {}),
1769
+ io,
1770
+ });
1771
+ if (!result)
1772
+ return;
1773
+ if (rawOptions.json)
1774
+ writeJsonReceipt(io.stdout, result);
1775
+ else {
1776
+ writeLine(io.stdout, `Published Catalog ${result.catalogVersion} to ${result.remote} (${result.pushUrl}).`);
1777
+ writeLine(io.stdout, `Branch: refs/heads/${result.branch}`);
1778
+ writeLine(io.stdout, `Tag: refs/tags/${result.tag}`);
1779
+ writeLine(io.stdout, `Commit: ${result.commit}`);
1780
+ writeLine(io.stdout, `Add it as a source: aw catalog source add <id> --git ${result.fetchUrl} --ref refs/heads/${result.branch}`);
1781
+ }
1782
+ }
1783
+ catch (error) {
1784
+ const failure = catalogPublicationFailure({
1785
+ error,
1786
+ env,
1787
+ sensitiveRoots: [
1788
+ cwd,
1789
+ ...(rawOptions.workspaceRoot ? [path.resolve(cwd, rawOptions.workspaceRoot)] : []),
1790
+ ],
1791
+ });
1792
+ if (rawOptions.json)
1793
+ writeJsonReceipt(io.stdout, failure);
1794
+ writeLine(io.stderr, failure.message);
1795
+ commandExitState.exitCode = 1;
1796
+ }
1797
+ });
1798
+ const catalogDev = catalog
1799
+ .command('dev')
1800
+ .description('Manage the current Catalog Workspace development source');
1801
+ catalogDev
1802
+ .command('activate')
1803
+ .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1804
+ .option('--source-id <id>', 'explicit managed source ID')
1805
+ .option('--primary', 'make the development source primary', false)
1806
+ .option('--force-build', 'rebuild a current snapshot', false)
1807
+ .option('-y, --yes', 'confirm affected or unknown source references', false)
1808
+ .requiredOption('--json', 'emit one schema 2 JSON receipt')
1809
+ .action(async (rawOptions) => {
1810
+ try {
1811
+ const receipt = await activateCatalogDevSource({
1812
+ cwd,
1813
+ workspaceRoot: rawOptions.workspaceRoot,
1814
+ sourceId: rawOptions.sourceId,
1815
+ primary: rawOptions.primary,
1816
+ forceBuild: rawOptions.forceBuild,
1817
+ yes: rawOptions.yes,
1818
+ cliVersion: resolveCliVersion(),
1819
+ env,
1820
+ });
1821
+ writeJsonReceipt(io.stdout, receipt);
1822
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
1823
+ }
1824
+ catch (error) {
1825
+ const failure = catalogDevSourceError(error);
1826
+ writeJsonReceipt(io.stdout, createCatalogDevFailureReceipt({
1827
+ command: 'activate', cwd, workspaceRoot: rawOptions.workspaceRoot,
1828
+ sourceId: rawOptions.sourceId, ...failure,
1829
+ }));
1830
+ commandExitState.exitCode = 1;
1831
+ }
1832
+ });
1833
+ catalogDev
1834
+ .command('status')
1835
+ .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1836
+ .requiredOption('--json', 'emit one schema 3 JSON receipt')
1837
+ .action(async (rawOptions) => {
1838
+ const receipt = await getCatalogDevSourceStatus({
1839
+ cwd,
1840
+ workspaceRoot: rawOptions.workspaceRoot,
1841
+ cliVersion: resolveCliVersion(),
1842
+ env,
1843
+ });
1844
+ writeJsonReceipt(io.stdout, receipt);
1845
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
1846
+ });
1847
+ catalogDev
1848
+ .command('deactivate')
1849
+ .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1850
+ .option('--source-id <id>', 'recover one managed source by exact ID')
1851
+ .option('--replacement-primary <id>', 'replacement when the target source is primary')
1852
+ .option('-y, --yes', 'confirm recovery by source ID', false)
1853
+ .requiredOption('--json', 'emit one schema 2 JSON receipt')
1854
+ .action(async (rawOptions) => {
1855
+ try {
1856
+ const receipt = await deactivateCatalogDevSource({
1857
+ cwd,
1858
+ workspaceRoot: rawOptions.workspaceRoot,
1859
+ sourceId: rawOptions.sourceId,
1860
+ replacementPrimary: rawOptions.replacementPrimary,
1861
+ yes: rawOptions.yes,
1862
+ env,
1863
+ });
1864
+ writeJsonReceipt(io.stdout, receipt);
1865
+ commandExitState.exitCode = receipt.ok ? 0 : 1;
1866
+ }
1867
+ catch (error) {
1868
+ const failure = catalogDevSourceError(error);
1869
+ writeJsonReceipt(io.stdout, createCatalogDevFailureReceipt({
1870
+ command: 'deactivate', cwd, workspaceRoot: rawOptions.workspaceRoot,
1871
+ sourceId: rawOptions.sourceId, ...failure,
1872
+ }));
1873
+ commandExitState.exitCode = 1;
1874
+ }
1875
+ });
1876
+ const catalogSource = catalog
1877
+ .command('source')
1878
+ .description('Manage catalog sources');
1879
+ const writeCatalogSourceFailure = async (command, sourceId, json, error, sensitiveRoots = []) => {
1880
+ const failure = sanitizeCatalogSourceError(error, env, sensitiveRoots);
1881
+ const message = failure instanceof Error ? failure.message : String(error);
1882
+ if (json) {
1883
+ writeJsonReceipt(io.stdout, {
1884
+ receiptSchemaVersion: 5,
1885
+ command,
1886
+ ok: false,
1887
+ changed: false,
1888
+ sourceId,
1889
+ references: failure.impact?.references ?? failure.inventory?.references ?? [],
1890
+ errors: [{ code: failure.code ?? failure.name ?? 'catalogSourceMutationFailed', message }],
1891
+ });
1892
+ }
1893
+ writeLine(io.stderr, message);
1894
+ commandExitState.exitCode = 1;
1895
+ };
1896
+ const writeCatalogGenerationFailure = (command, sourceId, json, error) => {
1897
+ const failure = sanitizeCatalogSourceError(error, env);
1898
+ const message = redactString(failure.message);
1899
+ if (json) {
1900
+ writeJsonReceipt(io.stdout, {
1901
+ ...(command === 'catalog:source:sync'
1902
+ ? { catalogGenerationSchemaVersion: 1 }
1903
+ : { catalogGenerationStatusSchemaVersion: 1 }),
1904
+ command,
1905
+ ok: false,
1906
+ ...(sourceId ? { sourceId } : {}),
1907
+ ...(failure.impact ? { impact: failure.impact } : {}),
1908
+ errors: [{ code: catalogGenerationErrorCode(error), message }],
1909
+ });
1910
+ }
1911
+ writeLine(io.stderr, message);
1912
+ commandExitState.exitCode = 1;
1913
+ };
1914
+ const writeConfigMutationFailure = (command, plugin, json, error) => {
1915
+ const failure = configMutationFailure(error, env, cwd);
1916
+ if (json) {
1917
+ writeConfigMutationFailureReceipt(io.stdout, {
1918
+ command,
1919
+ ...(plugin ? { plugin } : {}),
1920
+ }, failure);
1921
+ }
1922
+ const message = json
1923
+ ? failure.message
1924
+ : redactString(sanitizeCatalogSourceErrorMessage(error instanceof Error ? error.message : String(error), env, [cwd]));
1925
+ writeLine(io.stderr, message);
1926
+ commandExitState.exitCode = 1;
1927
+ };
1928
+ const withResolvedConfigMutationPlugin = (context, selector, consume) => (async () => {
1929
+ const parsed = parsePluginId(selector);
1930
+ return withAwHomeMutationLock({
1931
+ env: context.env,
1932
+ action: async (awHomeMutationToken) => {
1933
+ const catalogOperationContext = await resolveCatalogOperationContext({
1934
+ ...(parsed.sourceId ? { sourceIds: [parsed.sourceId] } : {}),
1935
+ env: context.env,
1936
+ });
1937
+ return withResolvedCatalogPlugin({
1938
+ selector,
1939
+ cliVersion: resolveCliVersion(),
1940
+ operationContext: catalogOperationContext,
1941
+ env: context.env,
1942
+ consume: (resolution) => consume(resolution, awHomeMutationToken, catalogOperationContext),
1943
+ });
1944
+ },
1945
+ });
1946
+ })();
1947
+ catalogSource
1948
+ .command('list')
1949
+ .option('-j, --json', 'print catalog sources as JSON', false)
1950
+ .action(async (rawOptions) => {
1951
+ const payload = await listCatalogSources({ env });
1952
+ if (rawOptions.json) {
1953
+ writeJsonReceipt(io.stdout, payload);
1954
+ return;
1955
+ }
1956
+ writeLine(io.stdout, `Primary source: ${payload.primarySourceId}`);
1957
+ for (const source of payload.sources) {
1958
+ writeLine(io.stdout, `${source.primary ? '*' : '-'} ${source.id} ${source.type} ${source.sourceIdentity}`);
1959
+ }
1960
+ });
1961
+ catalogSource
1962
+ .command('sync')
1963
+ .argument('<id>')
1964
+ .option('--check', 'fetch and validate without changing the Catalog store or Active state', false)
1965
+ .option('--replace-damaged', 'replace a damaged Active entry with the current candidate', false)
1966
+ .option('-y, --yes', 'confirm affected, unknown, or damaged Active replacement impact', false)
1967
+ .option('-j, --json', 'print the source sync result as JSON', false)
1968
+ .action(async (id, rawOptions) => {
1969
+ try {
1970
+ if (rawOptions.check && rawOptions.replaceDamaged) {
1971
+ throw new Error('catalog source sync --check cannot use --replace-damaged.');
1972
+ }
1973
+ const result = await syncCatalogSourceCommand({
1974
+ sourceId: id,
1975
+ cliVersion: resolveCliVersion(),
1976
+ cwd,
1977
+ check: rawOptions.check === true,
1978
+ impactConfirmed: rawOptions.yes === true,
1979
+ replaceDamaged: rawOptions.replaceDamaged === true,
1980
+ env,
1981
+ });
1982
+ if (rawOptions.json) {
1983
+ writeJsonReceipt(io.stdout, {
1984
+ ...result,
1985
+ command: 'catalog:source:sync',
1986
+ ok: true,
1987
+ });
1988
+ }
1989
+ else {
1990
+ writeLine(io.stdout, rawOptions.check
1991
+ ? `Catalog source ${id} is valid.`
1992
+ : `Catalog source ${id}: ${result.outcome}.`);
1993
+ }
1994
+ }
1995
+ catch (error) {
1996
+ writeCatalogGenerationFailure('catalog:source:sync', id, rawOptions.json === true, error);
1997
+ }
1998
+ });
1999
+ catalogSource
2000
+ .command('status')
2001
+ .argument('[id]')
2002
+ .option('-j, --json', 'print offline Catalog source status as JSON', false)
2003
+ .action(async (id, rawOptions) => {
2004
+ try {
2005
+ const result = await catalogSourceStatusCommand({ sourceId: id, env });
2006
+ if (rawOptions.json) {
2007
+ writeJsonReceipt(io.stdout, result);
2008
+ }
2009
+ else {
2010
+ for (const source of result.sources) {
2011
+ const active = source.active
2012
+ ? `Active ${source.active.snapshotDigest}`
2013
+ : 'no Active';
2014
+ const readiness = source.activeReady ? 'ready' : 'not ready';
2015
+ writeLine(io.stdout, `${source.sourceId}: ${active}, ${readiness}`);
2016
+ }
2017
+ }
2018
+ }
2019
+ catch (error) {
2020
+ writeCatalogGenerationFailure('catalog:source:status', id, rawOptions.json === true, error);
2021
+ }
2022
+ });
2023
+ catalogSource
2024
+ .command('add')
2025
+ .argument('<id>')
2026
+ .addOption(new Option('--git <url>', 'add a Git catalog source'))
2027
+ .addOption(new Option('--path <path>', 'add a local path catalog source'))
2028
+ .addOption(new Option('--ref <ref>', 'use an explicit Git ref'))
2029
+ .addOption(new Option('--default-ref', 'select the Git ref from the CLI release channel'))
2030
+ .option('--subdir <path>', 'use a catalog snapshot below the Git repository root')
2031
+ .option('--no-auto-check', 'disable automatic update checks for this source')
2032
+ .option('--primary', 'make this source primary', false)
2033
+ .option('-j, --json', 'print mutation receipt as JSON', false)
2034
+ .action(async (id, rawOptions) => {
2035
+ try {
2036
+ if ((rawOptions.git === undefined) === (rawOptions.path === undefined)) {
2037
+ throw new Error('catalog source add requires exactly one of `--git` or `--path`.');
2038
+ }
2039
+ if (rawOptions.git !== undefined && ((rawOptions.ref === undefined) === (rawOptions.defaultRef !== true))) {
2040
+ throw new Error('Git catalog source add requires exactly one of `--ref` or `--default-ref`.');
2041
+ }
2042
+ if (rawOptions.path !== undefined && (rawOptions.ref !== undefined || rawOptions.defaultRef === true || rawOptions.subdir !== undefined)) {
2043
+ throw new Error('Path catalog source add only accepts `--path`, `--primary`, and `--no-auto-check`.');
2044
+ }
2045
+ const source = rawOptions.git !== undefined
2046
+ ? {
2047
+ id,
2048
+ type: 'git',
2049
+ primary: rawOptions.primary === true,
2050
+ url: rawOptions.git,
2051
+ refPolicy: explicitRefPolicy(rawOptions.ref, rawOptions.defaultRef === true),
2052
+ ...(rawOptions.subdir ? { subdir: rawOptions.subdir } : {}),
2053
+ ...(rawOptions.autoCheck === false ? { autoCheck: false } : {}),
2054
+ }
2055
+ : {
2056
+ id,
2057
+ type: 'path',
2058
+ primary: rawOptions.primary === true,
2059
+ path: rawOptions.path,
2060
+ ...(rawOptions.autoCheck === false ? { autoCheck: false } : {}),
2061
+ };
2062
+ const receipt = await addCatalogSourceCommand({
2063
+ source,
2064
+ cliVersion: resolveCliVersion(),
2065
+ cwd,
2066
+ env,
2067
+ });
2068
+ if (rawOptions.json)
2069
+ writeJsonReceipt(io.stdout, receipt);
2070
+ else
2071
+ writeLine(io.stdout, `Catalog source ${id} added.`);
2072
+ for (const diagnostic of receipt.errors)
2073
+ writeLine(io.stderr, `Warning: ${diagnostic.message}`);
2074
+ }
2075
+ catch (error) {
2076
+ await writeCatalogSourceFailure('catalog:source:add', id, rawOptions.json === true, error, rawOptions.path === undefined ? [] : [rawOptions.path, path.resolve(cwd, rawOptions.path)]);
2077
+ }
2078
+ });
2079
+ catalogSource
2080
+ .command('update')
2081
+ .argument('<id>')
2082
+ .addOption(new Option('--git <url>', 'update a Git catalog URL'))
2083
+ .addOption(new Option('--path <path>', 'update a local catalog path'))
2084
+ .addOption(new Option('--ref <ref>', 'use an explicit Git ref'))
2085
+ .addOption(new Option('--default-ref', 'select the Git ref from the CLI release channel'))
2086
+ .addOption(new Option('--subdir <path>', 'update the Git catalog subdirectory'))
2087
+ .addOption(new Option('--no-subdir', 'remove the Git catalog subdirectory'))
2088
+ .addOption(new Option('--auto-check', 'enable automatic update checks for this source'))
2089
+ .addOption(new Option('--no-auto-check', 'disable automatic update checks for this source'))
2090
+ .option('-y, --yes', 'confirm a source identity change', false)
2091
+ .option('-j, --json', 'print mutation receipt as JSON', false)
2092
+ .action(async (id, rawOptions) => {
2093
+ try {
2094
+ if (rawOptions.git !== undefined && rawOptions.path !== undefined) {
2095
+ throw new Error('catalog source update cannot combine `--git` and `--path`.');
2096
+ }
2097
+ if (rawOptions.ref !== undefined && rawOptions.defaultRef === true) {
2098
+ throw new Error('catalog source update cannot combine `--ref` and `--default-ref`.');
2099
+ }
2100
+ const hasUpdate = rawOptions.git !== undefined
2101
+ || rawOptions.path !== undefined
2102
+ || rawOptions.ref !== undefined
2103
+ || rawOptions.defaultRef === true
2104
+ || rawOptions.subdir !== undefined
2105
+ || rawOptions.autoCheck !== undefined;
2106
+ if (!hasUpdate)
2107
+ throw new Error('catalog source update requires at least one update option.');
2108
+ if (rawOptions.path !== undefined && (rawOptions.ref !== undefined || rawOptions.defaultRef === true || rawOptions.subdir !== undefined))
2109
+ throw new Error('Path catalog source update only accepts `--path` and auto-check options.');
2110
+ const hasGitUpdate = rawOptions.git !== undefined
2111
+ || rawOptions.ref !== undefined
2112
+ || rawOptions.defaultRef === true
2113
+ || rawOptions.subdir !== undefined;
2114
+ const update = rawOptions.path !== undefined
2115
+ ? {
2116
+ type: 'path',
2117
+ path: rawOptions.path,
2118
+ ...(rawOptions.autoCheck !== undefined ? { autoCheck: rawOptions.autoCheck } : {}),
2119
+ }
2120
+ : hasGitUpdate ? {
2121
+ type: 'git',
2122
+ ...(rawOptions.autoCheck !== undefined ? { autoCheck: rawOptions.autoCheck } : {}),
2123
+ ...(rawOptions.git !== undefined ? { url: rawOptions.git } : {}),
2124
+ ...(rawOptions.ref !== undefined || rawOptions.defaultRef === true
2125
+ ? { refPolicy: explicitRefPolicy(rawOptions.ref, rawOptions.defaultRef === true) }
2126
+ : {}),
2127
+ ...(rawOptions.subdir !== undefined
2128
+ ? { subdir: rawOptions.subdir === false ? null : rawOptions.subdir }
2129
+ : {}),
2130
+ }
2131
+ : { autoCheck: rawOptions.autoCheck };
2132
+ const receipt = await updateCatalogSourceCommand({
2133
+ sourceId: id,
2134
+ update,
2135
+ cliVersion: resolveCliVersion(),
2136
+ cwd,
2137
+ env,
2138
+ requireIdentityChangeConfirmation: true,
2139
+ confirmIdentityChange: rawOptions.yes === true,
2140
+ });
2141
+ if (rawOptions.json)
2142
+ writeJsonReceipt(io.stdout, receipt);
2143
+ else
2144
+ writeLine(io.stdout, `Catalog source ${id} updated.`);
2145
+ for (const diagnostic of receipt.errors)
2146
+ writeLine(io.stderr, `Warning: ${diagnostic.message}`);
2147
+ }
2148
+ catch (error) {
2149
+ await writeCatalogSourceFailure('catalog:source:update', id, rawOptions.json === true, error, rawOptions.path === undefined ? [] : [rawOptions.path, path.resolve(cwd, rawOptions.path)]);
2150
+ }
2151
+ });
2152
+ catalogSource
2153
+ .command('set-primary')
2154
+ .argument('<id>')
2155
+ .option('-j, --json', 'print mutation receipt as JSON', false)
2156
+ .action(async (id, rawOptions) => {
2157
+ try {
2158
+ const receipt = await setPrimaryCatalogSourceCommand({ sourceId: id, cwd, env });
2159
+ if (rawOptions.json)
2160
+ writeJsonReceipt(io.stdout, receipt);
2161
+ else
2162
+ writeLine(io.stdout, `Primary catalog source set to ${id}.`);
2163
+ }
2164
+ catch (error) {
2165
+ await writeCatalogSourceFailure('catalog:source:set-primary', id, rawOptions.json === true, error);
2166
+ }
2167
+ });
2168
+ catalogSource
2169
+ .command('remove')
2170
+ .argument('<id>')
2171
+ .option('-y, --yes', 'confirm affected or unknown source references', false)
2172
+ .option('-j, --json', 'print mutation receipt as JSON', false)
2173
+ .action(async (id, rawOptions) => {
2174
+ try {
2175
+ const receipt = await removeCatalogSourceCommand({
2176
+ sourceId: id,
2177
+ cwd,
2178
+ env,
2179
+ requireImpactConfirmation: true,
2180
+ confirmImpact: rawOptions.yes === true,
2181
+ });
2182
+ if (rawOptions.json)
2183
+ writeJsonReceipt(io.stdout, receipt);
2184
+ else
2185
+ writeLine(io.stdout, `Catalog source ${id} removed.`);
2186
+ }
2187
+ catch (error) {
2188
+ await writeCatalogSourceFailure('catalog:source:remove', id, rawOptions.json === true, error);
2189
+ }
2190
+ });
2191
+ const catalogStore = catalog
2192
+ .command('store')
2193
+ .description('Inspect or prune the immutable Catalog store');
2194
+ catalogStore
2195
+ .command('status')
2196
+ .option('-j, --json', 'print Catalog store status as JSON', false)
2197
+ .action(async (rawOptions) => {
2198
+ try {
2199
+ const result = await catalogStoreStatus({ env });
2200
+ if (rawOptions.json) {
2201
+ writeJsonReceipt(io.stdout, result);
2202
+ }
2203
+ else if (result.entries.length === 0) {
2204
+ writeLine(io.stdout, 'Catalog store is empty.');
2205
+ }
2206
+ else {
2207
+ for (const entry of result.entries) {
2208
+ const bytes = entry.reclaimableBytes === null ? 'unknown bytes' : `${entry.reclaimableBytes} bytes`;
2209
+ writeLine(io.stdout, `${entry.storeKey}: ${entry.category}, ${entry.status}, ${entry.reason}, ${bytes}`);
2210
+ }
2211
+ writeLine(io.stdout, `Reclaimable: ${result.totals.reclaimableEntries} item(s).`);
2212
+ }
2213
+ }
2214
+ catch (error) {
2215
+ const failure = sanitizeCatalogSourceError(error, env);
2216
+ const message = redactString(failure.message);
2217
+ if (rawOptions.json)
2218
+ writeJsonReceipt(io.stdout, {
2219
+ catalogStoreSchemaVersion: 1,
2220
+ command: 'catalog:store:status',
2221
+ ok: false,
2222
+ entries: [],
2223
+ errors: [{ code: catalogGenerationErrorCode(error), message }],
2224
+ });
2225
+ writeLine(io.stderr, message);
2226
+ commandExitState.exitCode = 1;
2227
+ }
2228
+ });
2229
+ catalogStore
2230
+ .command('prune')
2231
+ .option('--dry-run', 'inspect reclaimable items without deleting them', false)
2232
+ .option('-y, --yes', 'delete items classified as safely reclaimable', false)
2233
+ .option('-j, --json', 'print the prune receipt as JSON', false)
2234
+ .action(async (rawOptions) => {
2235
+ const dryRun = rawOptions.yes !== true;
2236
+ try {
2237
+ if (rawOptions.dryRun === true && rawOptions.yes === true) {
2238
+ throw Object.assign(new Error('catalog store prune cannot combine `--dry-run` and `--yes`.'), {
2239
+ code: 'invalidArguments',
2240
+ });
2241
+ }
2242
+ const result = await catalogStorePrune({ dryRun, env });
2243
+ if (rawOptions.json) {
2244
+ writeJsonReceipt(io.stdout, result);
2245
+ }
2246
+ else if (dryRun) {
2247
+ writeLine(io.stdout, `Dry run: ${result.entries.filter((entry) => entry.status === 'reclaimable').length} item(s) are reclaimable.`);
2248
+ writeLine(io.stdout, 'Run `aw catalog store prune --yes` to delete them.');
2249
+ }
2250
+ else {
2251
+ writeLine(io.stdout, `Deleted ${result.deleted.length} Catalog store item(s) (${result.deletedBytes} bytes).`);
2252
+ if (result.errors.length > 0)
2253
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be deleted and were retained.`);
2254
+ }
2255
+ commandExitState.exitCode = result.ok ? 0 : 1;
2256
+ }
2257
+ catch (error) {
2258
+ const failure = sanitizeCatalogSourceError(error, env);
2259
+ const message = redactString(failure.message);
2260
+ const explicitCode = error.code;
2261
+ const code = typeof explicitCode === 'string'
2262
+ ? explicitCode
2263
+ : catalogGenerationErrorCode(error);
2264
+ if (rawOptions.json)
2265
+ writeJsonReceipt(io.stdout, {
2266
+ catalogStoreSchemaVersion: 1,
2267
+ command: 'catalog:store:prune',
2268
+ ok: false,
2269
+ overallState: 'failed',
2270
+ dryRun,
2271
+ entries: [],
2272
+ deleted: [],
2273
+ retained: [],
2274
+ errors: [{ code, message }],
2275
+ reclaimableBytes: null,
2276
+ deletedBytes: 0,
2277
+ });
2278
+ writeLine(io.stderr, message);
2279
+ commandExitState.exitCode = 1;
2280
+ }
2281
+ });
2282
+ program
2283
+ .command('init')
2284
+ .option('-j, --json', 'print receipt as JSON', false)
2285
+ .option('-v, --verbose', 'show command diagnostics', false)
2286
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2287
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2288
+ .action(async (rawOptions) => {
2289
+ const context = createActionContext('init', rawOptions);
2290
+ const result = await runActionWithContext(context, () => initCommand({
2291
+ env: context.env,
2292
+ }));
2293
+ if (rawOptions.json) {
2294
+ writeJsonReceipt(io.stdout, buildInitReceiptJson(result));
2295
+ }
2296
+ else {
2297
+ for (const line of renderInitReceipt(result)) {
2298
+ writeLine(io.stdout, line);
2299
+ }
2300
+ }
2301
+ for (const source of result.sources) {
2302
+ if (!source.ok && source.error)
2303
+ writeLine(io.stderr, `${source.id}: ${source.error}`);
2304
+ }
2305
+ commandExitState.exitCode = result.ok ? 0 : 1;
2306
+ });
2307
+ program
2308
+ .command('sync')
2309
+ .description('Reconcile actual state from existing desired intent')
2310
+ .argument('[plugins...]')
2311
+ .requiredOption('-s, --scope <scope>', 'project or user')
2312
+ .requiredOption('-p, --platform <platform>', 'codex, claude, or both')
2313
+ .option('-a, --all', 'reconcile every desired plugin in the selected scope', false)
2314
+ .option('--refresh', 'refresh only Catalog sources required by selected intent roots', false)
2315
+ .option('-y, --yes', 'authorize shared native replacement or forced repair', false)
2316
+ .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2317
+ .option('-j, --json', 'print sync receipt as JSON', false)
2318
+ .option('-v, --verbose', 'show command diagnostics', false)
2319
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2320
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2321
+ .action(async (plugins, rawOptions) => {
2322
+ const context = createActionContext('sync', rawOptions);
2323
+ const normalized = normalizeWriteRequest(() => normalizeInstallCommandOptions({
2324
+ cwd: context.cwd,
2325
+ scope: rawOptions.scope,
2326
+ platform: rawOptions.platform,
2327
+ allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2328
+ }));
2329
+ const syncPlatform = normalized.platform;
2330
+ const result = await runActionWithContext(context, () => syncCommand(plugins ?? [], {
2331
+ cwd: context.cwd,
2332
+ env: context.env,
2333
+ platform: syncPlatform,
2334
+ scope: normalized.scope,
2335
+ all: rawOptions.all,
2336
+ refresh: rawOptions.refresh,
2337
+ cliVersion: resolveCliVersion(),
2338
+ yes: rawOptions.yes,
2339
+ json: rawOptions.json,
2340
+ interactive: context.interactive && context.isTty && !context.isCi,
2341
+ prompt: context.prompt,
2342
+ allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2343
+ }, context));
2344
+ if (rawOptions.json) {
2345
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('sync', result));
2346
+ }
2347
+ else {
2348
+ for (const line of renderRebuildReceipt('sync', result))
2349
+ writeLine(io.stdout, line);
2350
+ }
2351
+ writeWarnings(io.stderr, result.warnings, { actionableOnly: true });
2352
+ commandExitState.exitCode = resolveCommandReceiptExitCode(result);
2353
+ });
2354
+ program
2355
+ .command('install')
2356
+ .argument('[plugins...]')
2357
+ .option('-s, --scope <scope>', 'project or user')
2358
+ .option('-p, --platform <platform>', 'codex | claude | both')
2359
+ .option('--dependency-scope <pluginId[#platform]=scope>', 'place one dependency at project or user scope; repeat for more dependencies', (value, previous) => [...previous, value], [])
2360
+ .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2361
+ .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2362
+ .option('-y, --yes', 'authorize shared Codex native replacement', false)
2363
+ .option('-j, --json', 'print receipt as JSON', false)
2364
+ .option('-v, --verbose', 'show command diagnostics', false)
2365
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2366
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2367
+ .action(async (plugins, rawOptions) => {
2368
+ const context = createActionContext('install', rawOptions);
2369
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('install', plugins ?? [], rawOptions, context));
2370
+ if (outcome.cancelled)
2371
+ return;
2372
+ const receipt = outcome.result;
2373
+ if (rawOptions.json) {
2374
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('install', receipt));
2375
+ }
2376
+ else {
2377
+ for (const line of renderRebuildReceipt('install', receipt)) {
2378
+ writeLine(io.stdout, line);
2379
+ }
2380
+ }
2381
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
2382
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
2383
+ });
2384
+ program
2385
+ .command('uninstall')
2386
+ .argument('[plugins...]')
2387
+ .option('-s, --scope <scope>', 'project or user')
2388
+ .option('-p, --platform <platform>', 'codex | claude | both')
2389
+ .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2390
+ .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2391
+ .option('-j, --json', 'print receipt as JSON', false)
2392
+ .option('-v, --verbose', 'show command diagnostics', false)
2393
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2394
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2395
+ .action(async (plugins, rawOptions) => {
2396
+ const context = createActionContext('uninstall', rawOptions);
2397
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('uninstall', plugins ?? [], rawOptions, context));
2398
+ if (outcome.cancelled)
2399
+ return;
2400
+ const receipt = outcome.result;
2401
+ if (rawOptions.json) {
2402
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('uninstall', receipt));
2403
+ }
2404
+ else {
2405
+ for (const line of renderRebuildReceipt('uninstall', receipt)) {
2406
+ writeLine(io.stdout, line);
2407
+ }
2408
+ }
2409
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
2410
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
2411
+ });
2412
+ program
2413
+ .command('cleanup')
2414
+ .argument('[plugins...]')
2415
+ .option('-s, --scope <scope>', 'project or user')
2416
+ .option('-p, --platform <platform>', 'codex | claude | both')
2417
+ .option('-j, --json', 'print cleanup result as JSON', false)
2418
+ .option('--force', 'remove exclusively owned plugin output without dependency protection', false)
2419
+ .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2420
+ .option('-v, --verbose', 'show command diagnostics', false)
2421
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2422
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2423
+ .action(async (plugins, rawOptions) => {
2424
+ const context = createActionContext('cleanup', rawOptions);
2425
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('cleanup', plugins ?? [], rawOptions, context));
2426
+ if (outcome.cancelled)
2427
+ return;
2428
+ const result = outcome.result;
2429
+ if (rawOptions.json) {
2430
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('cleanup', result));
2431
+ }
2432
+ else {
2433
+ for (const line of renderRebuildReceipt('cleanup', result)) {
2434
+ writeLine(io.stdout, line);
2435
+ }
2436
+ }
2437
+ writeWarnings(io.stderr, result.warnings, { actionableOnly: true });
2438
+ commandExitState.exitCode = resolveCommandReceiptExitCode(result);
2439
+ });
2440
+ program
2441
+ .command('reinstall')
2442
+ .argument('[plugins...]')
2443
+ .option('-s, --scope <scope>', 'project or user')
2444
+ .option('-p, --platform <platform>', 'codex | claude | both')
2445
+ .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2446
+ .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2447
+ .option('-y, --yes', 'authorize shared Codex native replacement or forced reinstall', false)
2448
+ .option('-j, --json', 'print receipt as JSON', false)
2449
+ .option('-v, --verbose', 'show command diagnostics', false)
2450
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2451
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2452
+ .action(async (plugins, rawOptions) => {
2453
+ const context = createActionContext('reinstall', rawOptions);
2454
+ const outcome = await runActionWithContext(context, () => runWriteCommandAction('reinstall', plugins ?? [], rawOptions, context));
2455
+ if (outcome.cancelled)
2456
+ return;
2457
+ const receipt = outcome.result;
2458
+ if (rawOptions.json) {
2459
+ writeJsonReceipt(io.stdout, buildRebuildReceiptJson('reinstall', receipt));
2460
+ }
2461
+ else {
2462
+ const lines = renderRebuildReceipt('reinstall', receipt);
2463
+ for (const line of lines) {
2464
+ writeLine(io.stdout, line);
2465
+ }
2466
+ }
2467
+ writeWarnings(io.stderr, receipt.warnings, { actionableOnly: true });
2468
+ commandExitState.exitCode = resolveCommandReceiptExitCode(receipt);
2469
+ });
2470
+ const config = program
2471
+ .command('config')
2472
+ .description('Manage AW plugin configuration');
2473
+ config
2474
+ .command('list')
2475
+ .argument('[plugin]')
2476
+ .option('-s, --scope <scope>', 'read only project or user config')
2477
+ .option('-j, --json', 'print config as JSON', false)
2478
+ .option('-v, --verbose', 'show command diagnostics', false)
2479
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2480
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2481
+ .action(async (pluginName, rawOptions) => {
2482
+ const context = createActionContext('config:list', rawOptions);
2483
+ const outcome = await runActionWithContext(context, async () => {
2484
+ resolveConfigReadResolution(rawOptions.scope);
2485
+ const execute = async (selectedPlugin) => resolveMultiSourceConfigRead({
2486
+ selector: selectedPlugin,
2487
+ rawOptions,
2488
+ context,
2489
+ });
2490
+ if (pluginName)
2491
+ return { cancelled: false, pluginName, value: await execute(pluginName) };
2492
+ if (!isWizardAvailable(context, rawOptions))
2493
+ throw new Error(configCommandUsage('list'));
2494
+ const currentCandidates = await loadWizardCandidates(context, {});
2495
+ const storedCandidates = await loadStoredConfigWizardCandidates(context, configReadStoreLocations(rawOptions));
2496
+ const candidates = mergeWizardCandidates(currentCandidates, storedCandidates);
2497
+ if (candidates.length === 0) {
2498
+ throw new Error('No plugin config candidates exist in the selected location.');
2499
+ }
2500
+ const result = await runCommandWizard(context, {
2501
+ command: 'config:list',
2502
+ candidates,
2503
+ initial: { plugins: [], scope: rawOptions.scope },
2504
+ pluginMode: 'single',
2505
+ ...equivalentConfigCommandProjection((selection) => ({
2506
+ command: 'list',
2507
+ plugin: selection.plugins[0],
2508
+ scope: rawOptions.scope,
2509
+ })),
2510
+ execute: (selection) => execute(selection.plugins[0]),
2511
+ });
2512
+ return result.cancelled
2513
+ ? { cancelled: true }
2514
+ : { cancelled: false, pluginName: result.selection.plugins[0], value: result.value };
2515
+ });
2516
+ if (outcome.cancelled)
2517
+ return;
2518
+ const resolved = outcome.value;
2519
+ const selectedPluginName = resolved.pluginName;
2520
+ if (rawOptions.json) {
2521
+ writeJsonReceipt(io.stdout, {
2522
+ ok: true,
2523
+ configSchemaVersion: 4,
2524
+ command: 'config:list',
2525
+ plugin: selectedPluginName,
2526
+ pluginName: selectedPluginName,
2527
+ pluginId: resolved.pluginId,
2528
+ sourceId: resolved.sourceId,
2529
+ sourceIdentity: resolved.sourceIdentity,
2530
+ scope: rawOptions.scope ?? 'effective',
2531
+ ...(resolved.result.schema ? { schema: resolved.result.schema } : {}),
2532
+ fields: resolved.result.fields,
2533
+ });
2534
+ }
2535
+ else {
2536
+ writeConfigReadHuman(io.stdout, resolved.result, resolved.pluginId);
2537
+ }
2538
+ });
2539
+ config
2540
+ .command('get')
2541
+ .argument('[plugin]')
2542
+ .argument('[key]')
2543
+ .option('-s, --scope <scope>', 'read only project or user config')
2544
+ .option('-j, --json', 'print config as JSON', false)
2545
+ .option('-v, --verbose', 'show command diagnostics', false)
2546
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2547
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2548
+ .action(async (pluginName, key, rawOptions) => {
2549
+ const context = createActionContext('config:get', rawOptions);
2550
+ const outcome = await runActionWithContext(context, async () => {
2551
+ resolveConfigReadResolution(rawOptions.scope);
2552
+ const execute = async (selectedPlugin) => resolveMultiSourceConfigRead({
2553
+ selector: selectedPlugin,
2554
+ ...(key === undefined ? {} : { key }),
2555
+ rawOptions,
2556
+ context,
2557
+ });
2558
+ if (pluginName)
2559
+ return { cancelled: false, pluginName, value: await execute(pluginName) };
2560
+ if (!isWizardAvailable(context, rawOptions))
2561
+ throw new Error(configCommandUsage('get'));
2562
+ const currentCandidates = await loadWizardCandidates(context, {});
2563
+ const storedCandidates = await loadStoredConfigWizardCandidates(context, configReadStoreLocations(rawOptions));
2564
+ const candidates = mergeWizardCandidates(currentCandidates, storedCandidates);
2565
+ if (candidates.length === 0) {
2566
+ throw new Error('No plugin config candidates exist in the selected location.');
2567
+ }
2568
+ const result = await runCommandWizard(context, {
2569
+ command: 'config:get',
2570
+ candidates,
2571
+ initial: { plugins: [], key, scope: rawOptions.scope },
2572
+ pluginMode: 'single',
2573
+ ...equivalentConfigCommandProjection((selection) => ({
2574
+ command: 'get',
2575
+ plugin: selection.plugins[0],
2576
+ key,
2577
+ scope: rawOptions.scope,
2578
+ })),
2579
+ execute: (selection) => execute(selection.plugins[0]),
2580
+ });
2581
+ return result.cancelled
2582
+ ? { cancelled: true }
2583
+ : { cancelled: false, pluginName: result.selection.plugins[0], value: result.value };
2584
+ });
2585
+ if (outcome.cancelled)
2586
+ return;
2587
+ const resolved = outcome.value;
2588
+ const selectedPluginName = resolved.pluginName;
2589
+ if (rawOptions.json) {
2590
+ writeJsonReceipt(io.stdout, {
2591
+ ok: true,
2592
+ configSchemaVersion: 4,
2593
+ command: 'config:get',
2594
+ plugin: selectedPluginName,
2595
+ pluginName: selectedPluginName,
2596
+ pluginId: resolved.pluginId,
2597
+ sourceId: resolved.sourceId,
2598
+ sourceIdentity: resolved.sourceIdentity,
2599
+ key,
2600
+ scope: rawOptions.scope ?? 'effective',
2601
+ ...(resolved.result.schema ? { schema: resolved.result.schema } : {}),
2602
+ fields: resolved.result.fields,
2603
+ });
2604
+ }
2605
+ else {
2606
+ writeConfigReadHuman(io.stdout, resolved.result, resolved.pluginId);
2607
+ }
2608
+ });
2609
+ config
2610
+ .command('set')
2611
+ .argument('[plugin]')
2612
+ .argument('[field]')
2613
+ .option('-s, --scope <scope>', 'project or user')
2614
+ .option('--value-json <json>', 'set the field to an exact JSON value')
2615
+ .option('--preset <id>', 'set the field to the current manifest preset value')
2616
+ .option('--apply', 'apply the saved config to visible desired placements', false)
2617
+ .option('-y, --yes', 'confirm shared Codex native config apply', false)
2618
+ .option('-j, --json', 'print receipt as JSON', false)
2619
+ .option('-v, --verbose', 'show command diagnostics', false)
2620
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2621
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2622
+ .action(async (pluginName, key, rawOptions) => {
2623
+ if (!pluginName || !key)
2624
+ throw new Error(configCommandUsage('set'));
2625
+ const context = createActionContext('config:set', rawOptions);
2626
+ let outcome;
2627
+ try {
2628
+ outcome = await runActionWithContext(context, async () => {
2629
+ const scope = resolveConfigWriteScope(rawOptions.scope);
2630
+ if ((rawOptions.valueJson === undefined) === (rawOptions.preset === undefined)) {
2631
+ throw new Error('Use exactly one of --value-json <json> or --preset <id>.');
2632
+ }
2633
+ return withResolvedConfigMutationPlugin(context, pluginName, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2634
+ if (!plugin.manifest.config?.fields) {
2635
+ throw new Error(`configSchemaUnavailable: Plugin "${pluginName}" does not declare an AW config schema.`);
2636
+ }
2637
+ const field = plugin.manifest.config.fields[key];
2638
+ if (!field) {
2639
+ throw new Error(`Unknown config key "${key}".`);
2640
+ }
2641
+ let inputValue;
2642
+ if (rawOptions.valueJson !== undefined) {
2643
+ try {
2644
+ inputValue = JSON.parse(rawOptions.valueJson);
2645
+ }
2646
+ catch {
2647
+ throw new Error('--value-json must contain valid JSON.');
2648
+ }
2649
+ }
2650
+ else {
2651
+ const preset = field.choices?.presets.find((entry) => entry.id === rawOptions.preset);
2652
+ if (!preset)
2653
+ throw new Error(`Unknown preset "${rawOptions.preset}" for config key "${key}".`);
2654
+ inputValue = structuredClone(preset.value);
2655
+ }
2656
+ const writeReceipt = await applyPluginConfigWrite({
2657
+ plugin,
2658
+ pluginName: plugin.manifest.name,
2659
+ scope,
2660
+ cwd: context.cwd,
2661
+ env: context.env,
2662
+ nativeCliRunner: context.nativeCliRunner,
2663
+ rebuildRuntime: {
2664
+ ...context,
2665
+ awHomeMutationToken,
2666
+ catalogOperationContext,
2667
+ expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2668
+ },
2669
+ awHomeMutationToken,
2670
+ request: {
2671
+ updates: { [key]: inputValue },
2672
+ },
2673
+ apply: rawOptions.apply === true,
2674
+ sharedNativeApplyConfirmed: rawOptions.yes === true,
2675
+ });
2676
+ return buildConfigMutationReceipt('config:set', {
2677
+ ok: writeReceipt.overallState === 'succeeded',
2678
+ ...writeReceipt,
2679
+ plugin: plugin.manifest.name,
2680
+ pluginName: plugin.manifest.name,
2681
+ pluginId,
2682
+ sourceId: source.sourceId,
2683
+ sourceIdentity: source.sourceIdentity,
2684
+ affectedFields: [{
2685
+ key,
2686
+ title: field.title ?? key,
2687
+ kind: 'manifest',
2688
+ reserved: false,
2689
+ action: 'set',
2690
+ scope,
2691
+ }],
2692
+ });
2693
+ });
2694
+ });
2695
+ }
2696
+ catch (error) {
2697
+ writeConfigMutationFailure('config:set', pluginName, rawOptions.json === true, error);
2698
+ return;
2699
+ }
2700
+ const receipt = outcome;
2701
+ if (rawOptions.json) {
2702
+ writeJsonReceipt(io.stdout, receipt);
2703
+ }
2704
+ else {
2705
+ writeLine(io.stdout, `已写入 ${receipt.plugin}.${key}(${configLayerLabel(receipt.scope)}配置)。`);
2706
+ writeConfigApplyNotice(io.stderr, receipt);
2707
+ }
2708
+ commandExitState.exitCode = receipt.overallState === 'succeeded' ? 0 : 1;
2709
+ });
2710
+ config
2711
+ .command('unset')
2712
+ .argument('[plugin]')
2713
+ .argument('[key]')
2714
+ .option('-s, --scope <scope>', 'project or user')
2715
+ .option('--apply', 'apply the saved config to visible desired placements', false)
2716
+ .option('-y, --yes', 'confirm shared Codex native config apply', false)
2717
+ .option('-j, --json', 'print receipt as JSON', false)
2718
+ .option('-v, --verbose', 'show command diagnostics', false)
2719
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2720
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2721
+ .action(async (pluginName, key, rawOptions) => {
2722
+ const context = createActionContext('config:unset', rawOptions);
2723
+ let outcome;
2724
+ try {
2725
+ outcome = await runActionWithContext(context, async () => {
2726
+ const scope = resolveConfigWriteScope(rawOptions.scope);
2727
+ const execute = async (selectedPlugin, selectedKey) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2728
+ if (plugin.manifest.config?.fields && !plugin.manifest.config.fields[selectedKey]) {
2729
+ throw new Error(`Unknown config key "${selectedKey}".`);
2730
+ }
2731
+ const store = await readPluginConfigStore({
2732
+ sourceId: source.sourceId,
2733
+ sourceIdentity: source.sourceIdentity,
2734
+ pluginName: plugin.manifest.name,
2735
+ scope,
2736
+ cwd: context.cwd,
2737
+ env: context.env,
2738
+ schema: plugin.manifest.config?.fields,
2739
+ });
2740
+ const existed = Object.hasOwn(store.values, selectedKey);
2741
+ if (!existed)
2742
+ throw new Error(`Unknown config key "${selectedKey}".`);
2743
+ const writeReceipt = await applyPluginConfigWrite({
2744
+ plugin,
2745
+ pluginName: plugin.manifest.name,
2746
+ scope,
2747
+ cwd: context.cwd,
2748
+ env: context.env,
2749
+ nativeCliRunner: context.nativeCliRunner,
2750
+ rebuildRuntime: {
2751
+ ...context,
2752
+ awHomeMutationToken,
2753
+ catalogOperationContext,
2754
+ expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2755
+ },
2756
+ awHomeMutationToken,
2757
+ request: {
2758
+ removeKeys: [selectedKey],
2759
+ },
2760
+ apply: rawOptions.apply === true,
2761
+ sharedNativeApplyConfirmed: rawOptions.yes === true,
2762
+ });
2763
+ return buildConfigMutationReceipt('config:unset', {
2764
+ ok: writeReceipt.overallState === 'succeeded',
2765
+ ...writeReceipt,
2766
+ plugin: plugin.manifest.name,
2767
+ pluginName: plugin.manifest.name,
2768
+ pluginId,
2769
+ sourceId: source.sourceId,
2770
+ sourceIdentity: source.sourceIdentity,
2771
+ removedKey: selectedKey,
2772
+ existed,
2773
+ affectedFields: [{
2774
+ key: selectedKey,
2775
+ title: plugin?.manifest.config?.fields?.[selectedKey]?.title ?? selectedKey,
2776
+ kind: 'manifest',
2777
+ reserved: false,
2778
+ action: 'unset',
2779
+ scope,
2780
+ }],
2781
+ });
2782
+ });
2783
+ if (pluginName && key) {
2784
+ return { cancelled: false, value: await execute(pluginName, key) };
2785
+ }
2786
+ if (!isWizardAvailable(context, rawOptions))
2787
+ throw new Error(configCommandUsage('unset'));
2788
+ const loadedCurrentCandidates = await loadWizardCandidates(context, {});
2789
+ const currentCandidates = loadedCurrentCandidates.filter(hasConfigSchemaKeys);
2790
+ const candidates = currentCandidates;
2791
+ if (pluginName && !candidates.some((entry) => entry.pluginName === pluginName)) {
2792
+ throw new Error(`Unknown plugin "${pluginName}".`);
2793
+ }
2794
+ if (candidates.length === 0) {
2795
+ throw new Error('No plugin config candidates exist in the selected location.');
2796
+ }
2797
+ const result = await runCommandWizard(context, {
2798
+ command: 'config:unset',
2799
+ candidates,
2800
+ initial: { plugins: pluginName ? [pluginName] : [], key, scope },
2801
+ pluginMode: pluginName ? 'none' : 'single',
2802
+ promptForKey: key === undefined,
2803
+ destructive: true,
2804
+ ...equivalentConfigCommandProjection((selection) => ({
2805
+ command: 'unset',
2806
+ plugin: selection.plugins[0],
2807
+ key: selection.key,
2808
+ scope: selection.scope ?? 'user',
2809
+ })),
2810
+ resultState: overallResultState,
2811
+ execute: (selection) => execute(selection.plugins[0], selection.key),
2812
+ });
2813
+ return result.cancelled
2814
+ ? { cancelled: true }
2815
+ : { cancelled: false, value: result.value };
2816
+ });
2817
+ }
2818
+ catch (error) {
2819
+ writeConfigMutationFailure('config:unset', pluginName, rawOptions.json === true, error);
2820
+ return;
2821
+ }
2822
+ if (outcome.cancelled)
2823
+ return;
2824
+ const receipt = outcome.value;
2825
+ if (rawOptions.json) {
2826
+ writeJsonReceipt(io.stdout, receipt);
2827
+ }
2828
+ else {
2829
+ writeLine(io.stdout, receipt.existed
2830
+ ? `已删除 ${receipt.plugin}.${receipt.removedKey}(${configLayerLabel(receipt.scope)}配置)。`
2831
+ : `${receipt.plugin}.${receipt.removedKey}(${configLayerLabel(receipt.scope)}配置)原本不存在。`);
2832
+ writeConfigApplyNotice(io.stderr, receipt);
2833
+ }
2834
+ commandExitState.exitCode = receipt.overallState === 'succeeded' ? 0 : 1;
2835
+ });
2836
+ config
2837
+ .command('reset')
2838
+ .argument('[plugin]')
2839
+ .option('-s, --scope <scope>', 'project or user')
2840
+ .option('--apply', 'apply the saved config to visible desired placements', false)
2841
+ .option('-y, --yes', 'confirm destructive reset', false)
2842
+ .option('-j, --json', 'print receipt as JSON', false)
2843
+ .option('-v, --verbose', 'show command diagnostics', false)
2844
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2845
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2846
+ .action(async (pluginName, rawOptions) => {
2847
+ const context = createActionContext('config:reset', rawOptions);
2848
+ let outcome;
2849
+ try {
2850
+ outcome = await runActionWithContext(context, async () => {
2851
+ const execute = async (selectedPlugin, selectedScope, confirmed) => {
2852
+ if (!confirmed) {
2853
+ throw new Error(`Reset requires confirmation. Re-run \`aw config reset ${selectedPlugin} -s ${selectedScope} --yes\` to delete this store.`);
2854
+ }
2855
+ const located = await resolveStoredConfigResetIdentity({
2856
+ selector: selectedPlugin,
2857
+ context,
2858
+ scope: selectedScope,
2859
+ });
2860
+ const resetLocatedStore = async (plugin, pluginError) => {
2861
+ const affectedFields = await describeResetAffectedFields({
2862
+ sourceId: located.sourceId,
2863
+ sourceIdentity: located.sourceIdentity,
2864
+ pluginName: located.pluginName,
2865
+ plugin,
2866
+ pluginError,
2867
+ scope: selectedScope,
2868
+ cwd: context.cwd,
2869
+ env: context.env,
2870
+ }).catch(() => []);
2871
+ const resetReceipt = await resetPluginConfigWithHelper({
2872
+ sourceId: located.sourceId,
2873
+ sourceIdentity: located.sourceIdentity,
2874
+ pluginName: located.pluginName,
2875
+ scope: selectedScope,
2876
+ cwd: context.cwd,
2877
+ env: context.env,
2878
+ nativeCliRunner: context.nativeCliRunner,
2879
+ plugin,
2880
+ pluginError,
2881
+ apply: rawOptions.apply === true,
2882
+ });
2883
+ return buildConfigMutationReceipt('config:reset', {
2884
+ ok: resetReceipt.overallState === 'succeeded',
2885
+ ...resetReceipt,
2886
+ plugin: located.pluginName,
2887
+ pluginName: located.pluginName,
2888
+ pluginId: located.pluginId,
2889
+ sourceId: located.sourceId,
2890
+ ...(located.sourceIdentity ? { sourceIdentity: located.sourceIdentity } : {}),
2891
+ affectedFields,
2892
+ });
2893
+ };
2894
+ let resetStarted = false;
2895
+ try {
2896
+ return await withResolvedCatalogPlugin({
2897
+ selector: located.pluginId,
2898
+ cliVersion: resolveCliVersion(),
2899
+ env: context.env,
2900
+ consume: async ({ plugin }) => {
2901
+ resetStarted = true;
2902
+ return resetLocatedStore(plugin, null);
2903
+ },
2904
+ });
2905
+ }
2906
+ catch (error) {
2907
+ if (resetStarted)
2908
+ throw error;
2909
+ return resetLocatedStore(null, error instanceof Error ? error : new Error(String(error)));
2910
+ }
2911
+ };
2912
+ const scope = resolveConfigWriteScope(rawOptions.scope);
2913
+ const needsWizard = pluginName === undefined || rawOptions.yes !== true;
2914
+ if (!needsWizard) {
2915
+ return {
2916
+ cancelled: false,
2917
+ value: await execute(pluginName, scope, true),
2918
+ };
2919
+ }
2920
+ if (!isWizardAvailable(context, rawOptions)) {
2921
+ if (!pluginName)
2922
+ throw new Error(configCommandUsage('reset'));
2923
+ return {
2924
+ cancelled: false,
2925
+ value: await execute(pluginName, scope, false),
2926
+ };
2927
+ }
2928
+ const currentCandidates = pluginName ? [] : await loadWizardCandidates(context, {});
2929
+ const candidatesByScope = new Map();
2930
+ if (!pluginName && (rawOptions.scope === undefined || scope === 'user')) {
2931
+ candidatesByScope.set('user', mergeWizardCandidates(currentCandidates, await loadStoredConfigWizardCandidates(context, [{ scope: 'user' }], { includeEmptyStores: true })));
2932
+ }
2933
+ if (!pluginName && (rawOptions.scope === undefined || scope === 'project')) {
2934
+ candidatesByScope.set('project', mergeWizardCandidates(currentCandidates, await loadStoredConfigWizardCandidates(context, [{ scope: 'project' }], { includeEmptyStores: true })));
2935
+ }
2936
+ const candidates = mergeWizardCandidates(candidatesByScope.get('user') ?? [], candidatesByScope.get('project') ?? []);
2937
+ if (!pluginName && candidates.length === 0) {
2938
+ throw new Error('No plugin config candidates exist in the selected location.');
2939
+ }
2940
+ const result = await runCommandWizard(context, {
2941
+ command: 'config:reset',
2942
+ candidates,
2943
+ initial: { plugins: pluginName ? [pluginName] : [], scope },
2944
+ pluginMode: pluginName ? 'none' : 'single',
2945
+ promptForScope: rawOptions.scope === undefined,
2946
+ destructive: true,
2947
+ isPluginVisible: (candidate, selection) => candidatesByScope
2948
+ .get(selection.scope ?? 'user')
2949
+ ?.some((entry) => entry.pluginName === candidate.pluginName) !== false,
2950
+ ...equivalentConfigCommandProjection((selection) => ({
2951
+ command: 'reset',
2952
+ plugin: selection.plugins[0],
2953
+ scope: selection.scope ?? 'user',
2954
+ confirmed: true,
2955
+ })),
2956
+ resultState: overallResultState,
2957
+ execute: (selection) => execute(selection.plugins[0], selection.scope ?? 'user', true),
2958
+ });
2959
+ return result.cancelled
2960
+ ? { cancelled: true }
2961
+ : { cancelled: false, value: result.value };
2962
+ });
2963
+ }
2964
+ catch (error) {
2965
+ writeConfigMutationFailure('config:reset', pluginName, rawOptions.json === true, error);
2966
+ return;
2967
+ }
2968
+ if (outcome.cancelled)
2969
+ return;
2970
+ const receipt = outcome.value;
2971
+ if (rawOptions.json) {
2972
+ writeJsonReceipt(io.stdout, receipt);
2973
+ }
2974
+ else {
2975
+ writeLine(io.stdout, receipt.deleted
2976
+ ? `已重置 ${receipt.plugin} 的${configLayerLabel(receipt.scope)}配置。`
2977
+ : `${receipt.plugin} 没有可重置的${configLayerLabel(receipt.scope)}配置。`);
2978
+ writeConfigApplyNotice(io.stderr, receipt);
2979
+ }
2980
+ commandExitState.exitCode = receipt.overallState === 'succeeded' ? 0 : 1;
2981
+ });
2982
+ program
2983
+ .command('status')
2984
+ .argument('[plugins...]')
2985
+ .option('-s, --scope <scope>', 'filter by scope')
2986
+ .option('-p, --platform <platform>', 'filter by platform')
2987
+ .option('-v, --verbose', 'show status details and command diagnostics', false)
2988
+ .option('-D, --debug', 'write debug diagnostics to a log file', false)
2989
+ .option('--log-file <path>', 'write debug diagnostics to the specified file')
2990
+ .option('-j, --json', 'print status as JSON', false)
2991
+ .action(async (plugins, rawOptions) => {
2992
+ const context = createActionContext('status', rawOptions);
2993
+ const result = await runActionWithContext(context, () => statusCommandV7({
2994
+ plugins: plugins ?? [],
2995
+ cwd,
2996
+ env: context.env,
2997
+ cliVersion: resolveCliVersion(),
2998
+ platform: rawOptions.platform,
2999
+ scope: rawOptions.scope,
3000
+ json: rawOptions.json,
3001
+ verbose: rawOptions.verbose,
3002
+ }));
3003
+ commandExitState.exitCode = result.hasErrors ? 1 : 0;
3004
+ writeLine(io.stdout, result.output);
3005
+ for (const source of result.payload.catalog.sources) {
3006
+ if (source.error)
3007
+ writeLine(io.stderr, `${source.id}: ${source.error}`);
3008
+ }
3009
+ for (const error of result.payload.errors) {
3010
+ if (error.code !== 'nativeStateUnreadable' && error.code !== 'stateInventoryFailed') {
3011
+ writeLine(io.stderr, error.message);
3012
+ }
3013
+ }
3014
+ });
3015
+ Object.assign(program, { __awCommandExitState: commandExitState });
3016
+ return program;
3017
+ }
3018
+ function handleCliError(error, writeError) {
3019
+ if (error instanceof CommanderError) {
3020
+ return error.exitCode;
3021
+ }
3022
+ if (isCommandWarningError(error)) {
3023
+ writeWarnings(writeError, error.warnings);
3024
+ writeLine(writeError, error.message);
3025
+ return error.exitCode;
3026
+ }
3027
+ writeLine(writeError, error instanceof Error ? error.message : String(error));
3028
+ return 1;
3029
+ }
3030
+ export async function runCli(argv, options = {}) {
3031
+ const io = {
3032
+ ...createDefaultIo(),
3033
+ ...options.io,
3034
+ };
3035
+ const jsonAuthoringCommand = argv.includes('--json')
3036
+ && ((argv[0] === 'catalog' && ['init', 'context', 'version', 'build', 'validate', 'status', 'publish'].includes(argv[1] ?? ''))
3037
+ || (argv[0] === 'plugin' && ['build', 'test', 'validate', 'status', 'remove'].includes(argv[1] ?? '')))
3038
+ ? `${argv[0]}:${argv[1]}`
3039
+ : null;
3040
+ const jsonCatalogDevCommand = argv.includes('--json')
3041
+ && argv[0] === 'catalog'
3042
+ && argv[1] === 'dev'
3043
+ && ['activate', 'status', 'deactivate'].includes(argv[2] ?? '')
3044
+ ? argv[2]
3045
+ : null;
3046
+ const jsonWriteRequest = jsonWriteCommandRequest(argv);
3047
+ const jsonConfigMutation = jsonConfigMutationRequest(argv);
3048
+ try {
3049
+ const authoringScriptByCommand = {
3050
+ init: 'init-plugin.mjs',
3051
+ 'add-skill': 'add-skill.mjs',
3052
+ remove: 'remove-plugin.mjs',
3053
+ validate: 'validate-plugin.mjs',
3054
+ status: 'plugin-status.mjs',
3055
+ };
3056
+ const authoringScript = argv[0] === 'plugin'
3057
+ ? authoringScriptByCommand[argv[1] ?? '']
3058
+ : argv[0] === 'skill' && argv[1] === 'validate'
3059
+ ? 'validate-skill.mjs'
3060
+ : undefined;
3061
+ if (authoringScript && !argv.includes('--help') && !argv.includes('-h')) {
3062
+ const authoringArgs = argv.slice(2);
3063
+ let authoringEnv = options.env ?? process.env;
3064
+ if (argv[0] === 'plugin'
3065
+ && !authoringArgs.some((token) => token === '--plugin-root' || token.startsWith('--plugin-root='))) {
3066
+ let explicitRoot;
3067
+ for (let index = 0; index < authoringArgs.length; index += 1) {
3068
+ const token = authoringArgs[index];
3069
+ if (token.startsWith('--workspace-root='))
3070
+ explicitRoot = token.slice('--workspace-root='.length);
3071
+ if (token === '--workspace-root')
3072
+ explicitRoot = authoringArgs[index + 1];
3073
+ }
3074
+ const originalCwd = options.cwd ?? process.cwd();
3075
+ let discoveryCwd = originalCwd;
3076
+ if (argv[1] === 'validate') {
3077
+ const valueOptions = new Set(['--workspace-root', '--claude-skill-profile', '--version-base']);
3078
+ for (let index = 0; index < authoringArgs.length; index += 1) {
3079
+ const token = authoringArgs[index];
3080
+ if (valueOptions.has(token)) {
3081
+ index += 1;
3082
+ continue;
3083
+ }
3084
+ if (!token.startsWith('-')) {
3085
+ discoveryCwd = path.resolve(originalCwd, token);
3086
+ authoringArgs[index] = discoveryCwd;
3087
+ break;
3088
+ }
3089
+ }
3090
+ }
3091
+ const workspace = await resolveCatalogWorkspaceRoot({
3092
+ cwd: discoveryCwd,
3093
+ ...(explicitRoot === undefined ? {} : { explicitRoot: path.resolve(options.cwd ?? process.cwd(), explicitRoot) }),
3094
+ mode: 'existing',
3095
+ });
3096
+ authoringEnv = {
3097
+ ...authoringEnv,
3098
+ AW_AUTHORING_WORKSPACE_ROOT: workspace.workspaceRoot,
3099
+ AW_AUTHORING_WORKSPACE_ROOT_RESOLVED_FROM: workspace.workspaceRootResolvedFrom,
3100
+ };
3101
+ if (explicitRoot === undefined)
3102
+ authoringArgs.push('--workspace-root', workspace.workspaceRoot);
3103
+ }
3104
+ return runAuthoringScript({
3105
+ scriptName: authoringScript,
3106
+ args: authoringArgs,
3107
+ cwd: options.cwd ?? process.cwd(),
3108
+ env: authoringEnv,
3109
+ io,
3110
+ });
3111
+ }
3112
+ if (!jsonConfigMutation
3113
+ && argv.some((token) => token === '--subdir' || token.startsWith('--subdir='))
3114
+ && argv.includes('--no-subdir')) {
3115
+ const message = 'option --subdir cannot be used with option --no-subdir';
3116
+ if (argv.includes('--json') && argv[0] === 'catalog' && argv[1] === 'source' && argv[2] === 'update') {
3117
+ writeJsonReceipt(io.stdout, {
3118
+ receiptSchemaVersion: 5,
3119
+ command: 'catalog:source:update',
3120
+ ok: false,
3121
+ changed: false,
3122
+ sourceId: argv[3] ?? '',
3123
+ references: [],
3124
+ errors: [{ code: 'catalogSourceOptionConflict', message }],
3125
+ });
3126
+ }
3127
+ writeLine(io.stderr, `error: ${message}`);
3128
+ return 1;
3129
+ }
3130
+ if (argv[0] === 'catalog' && argv[1] === 'source' && argv[2] === 'update'
3131
+ && argv.includes('--auto-check') && argv.includes('--no-auto-check')) {
3132
+ const message = 'option --auto-check cannot be used with option --no-auto-check';
3133
+ if (argv.includes('--json') || argv.includes('-j')) {
3134
+ writeJsonReceipt(io.stdout, {
3135
+ receiptSchemaVersion: 5,
3136
+ command: 'catalog:source:update',
3137
+ ok: false,
3138
+ changed: false,
3139
+ sourceId: argv[3] ?? '',
3140
+ references: [],
3141
+ errors: [{ code: 'catalogSourceOptionConflict', message }],
3142
+ });
3143
+ }
3144
+ writeLine(io.stderr, `error: ${message}`);
3145
+ return 1;
3146
+ }
3147
+ const bareConsoleOptions = parseBareConsoleOptions(argv);
3148
+ if (bareConsoleOptions) {
3149
+ const context = createCliExecutionContext({
3150
+ ...options,
3151
+ io,
3152
+ env: options.env ?? process.env,
3153
+ diagnostics: {
3154
+ ...toCliDiagnosticsOptions('console', bareConsoleOptions, options.diagnostics),
3155
+ metadata: {
3156
+ ...options.diagnostics?.metadata,
3157
+ argCount: argv.length,
3158
+ },
3159
+ },
3160
+ });
3161
+ if (!context.interactive) {
3162
+ writeLine(io.stderr, formatInteractiveConsoleUnavailableMessage(context));
3163
+ return 1;
3164
+ }
3165
+ return await runActionWithContext(context, () => runConsoleController(context));
3166
+ }
3167
+ let catalogPublicationActionStarted = false;
3168
+ let configMutationActionStarted = false;
3169
+ const programIo = jsonCatalogDevCommand || jsonWriteRequest
3170
+ ? { ...io, stderr: () => undefined }
3171
+ : jsonConfigMutation
3172
+ ? {
3173
+ ...io,
3174
+ stderr: (text) => {
3175
+ if (configMutationActionStarted)
3176
+ io.stderr(text);
3177
+ },
3178
+ }
3179
+ : jsonAuthoringCommand === 'catalog:publish'
3180
+ ? {
3181
+ ...io,
3182
+ stderr: (text) => {
3183
+ if (catalogPublicationActionStarted)
3184
+ io.stderr(text);
3185
+ },
3186
+ }
3187
+ : io;
3188
+ const program = buildProgram({
3189
+ ...options,
3190
+ io: programIo,
3191
+ diagnostics: {
3192
+ ...options.diagnostics,
3193
+ metadata: {
3194
+ ...options.diagnostics?.metadata,
3195
+ argCount: argv.length,
3196
+ },
3197
+ },
3198
+ });
3199
+ if (jsonAuthoringCommand === 'catalog:publish') {
3200
+ program.hook('preAction', () => {
3201
+ catalogPublicationActionStarted = true;
3202
+ });
3203
+ }
3204
+ if (jsonConfigMutation) {
3205
+ program.hook('preAction', () => {
3206
+ configMutationActionStarted = true;
3207
+ });
3208
+ }
3209
+ await program.parseAsync(['node', 'aw', ...argv]);
3210
+ return program.__awCommandExitState?.exitCode ?? 0;
3211
+ }
3212
+ catch (error) {
3213
+ if (jsonCatalogDevCommand) {
3214
+ const workspaceRootIndex = argv.findIndex((token) => token === '--workspace-root');
3215
+ const workspaceRootOption = argv.find((token) => token.startsWith('--workspace-root='));
3216
+ const workspaceRoot = workspaceRootOption?.slice('--workspace-root='.length)
3217
+ ?? (workspaceRootIndex >= 0 ? argv[workspaceRootIndex + 1] : undefined);
3218
+ const sourceIdIndex = argv.findIndex((token) => token === '--source-id');
3219
+ const sourceIdOption = argv.find((token) => token.startsWith('--source-id='));
3220
+ const sourceId = sourceIdOption?.slice('--source-id='.length)
3221
+ ?? (sourceIdIndex >= 0 ? argv[sourceIdIndex + 1] : undefined);
3222
+ const failure = error instanceof CommanderError
3223
+ ? { code: 'invalidArguments', message: error.message }
3224
+ : catalogDevSourceError(error);
3225
+ writeJsonReceipt(io.stdout, createCatalogDevFailureReceipt({
3226
+ command: jsonCatalogDevCommand,
3227
+ cwd: options.cwd ?? process.cwd(),
3228
+ workspaceRoot,
3229
+ sourceId,
3230
+ ...failure,
3231
+ }));
3232
+ return 1;
3233
+ }
3234
+ if (jsonWriteRequest) {
3235
+ writeCommandFailureReceipt(io.stdout, jsonWriteRequest, error);
3236
+ return 1;
3237
+ }
3238
+ if (jsonConfigMutation) {
3239
+ if (error instanceof CommanderError && error.exitCode === 0)
3240
+ return 0;
3241
+ const failure = configMutationFailure(error, options.env ?? process.env, options.cwd ?? process.cwd());
3242
+ writeConfigMutationFailureReceipt(io.stdout, error instanceof CommanderError
3243
+ ? { command: jsonConfigMutation.command }
3244
+ : jsonConfigMutation, failure);
3245
+ writeLine(io.stderr, failure.message);
3246
+ return 1;
3247
+ }
3248
+ if (jsonAuthoringCommand === 'catalog:publish' && error instanceof CommanderError) {
3249
+ const failure = catalogPublicationFailure({
3250
+ error: new CatalogPublicationInspectionError('invalidArguments', error.message),
3251
+ env: options.env,
3252
+ sensitiveRoots: [options.cwd ?? process.cwd()],
3253
+ });
3254
+ writeJsonReceipt(io.stdout, failure);
3255
+ writeLine(io.stderr, failure.message);
3256
+ return 1;
3257
+ }
3258
+ if (jsonAuthoringCommand && !(error instanceof CommanderError)) {
3259
+ const message = error instanceof Error ? error.message : String(error);
3260
+ if (jsonAuthoringCommand === 'plugin:validate') {
3261
+ writeJsonReceipt(io.stdout, {
3262
+ ok: false,
3263
+ profile: 'unknown',
3264
+ warnings: [],
3265
+ errors: [message],
3266
+ });
3267
+ }
3268
+ else if (jsonAuthoringCommand === 'plugin:status') {
3269
+ writeJsonReceipt(io.stdout, {
3270
+ schemaVersion: 3,
3271
+ policy: 'development',
3272
+ ok: false,
3273
+ base: null,
3274
+ requestedBase: null,
3275
+ baseCommit: null,
3276
+ checkedPlugins: 0,
3277
+ checks: [],
3278
+ workspaceRoot: null,
3279
+ workspaceRootResolvedFrom: null,
3280
+ errors: [{ code: 'workspaceResolutionFailed', message }],
3281
+ });
3282
+ }
3283
+ else if (jsonAuthoringCommand === 'plugin:remove') {
3284
+ writeJsonReceipt(io.stdout, {
3285
+ schemaVersion: 1,
3286
+ command: 'plugin:remove',
3287
+ ok: false,
3288
+ workspaceRoot: null,
3289
+ workspaceRootResolvedFrom: null,
3290
+ baseCommit: null,
3291
+ plugin: null,
3292
+ removed: false,
3293
+ errors: [{ code: 'workspaceResolutionFailed', message }],
3294
+ });
3295
+ }
3296
+ else {
3297
+ writeJsonReceipt(io.stdout, {
3298
+ command: jsonAuthoringCommand,
3299
+ ok: false,
3300
+ errors: [{ code: 'workspaceResolutionFailed', message }],
3301
+ });
3302
+ }
3303
+ return 1;
3304
+ }
3305
+ if (jsonAuthoringCommand && error instanceof CommanderError) {
3306
+ writeJsonReceipt(io.stdout, {
3307
+ command: jsonAuthoringCommand,
3308
+ ok: false,
3309
+ errors: [{ code: 'invalidArguments', message: error.message }],
3310
+ });
3311
+ }
3312
+ return handleCliError(error, io.stderr);
3313
+ }
3314
+ }
3315
+ export async function main(argv = process.argv.slice(2), options = {}) {
3316
+ return runCli(argv, options);
3317
+ }
3318
+ const currentEntryPath = fileURLToPath(import.meta.url);
3319
+ const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : null;
3320
+ if (invokedPath === currentEntryPath) {
3321
+ void main().then((exitCode) => {
3322
+ if (exitCode !== 0) {
3323
+ process.exitCode = exitCode;
3324
+ }
3325
+ });
3326
+ }
3327
+ //# sourceMappingURL=index.js.map