@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,1493 @@
1
+ import { matchPluginConfigPreset, stablePluginConfigStringify, } from '@lesliechan721/aw-plugin-core/manifest';
2
+ import { statusTargetActivation, statusTargetExtensions, statusTargetIntent, statusTargetOwnershipState, statusTargetSharedNative, } from '../commands/status-v6.js';
3
+ import { buildAllowedLifecycleActions } from '../commands/operation-planner.js';
4
+ import { safeDiagnosticCode, } from './diagnostics.js';
5
+ import { projectCatalogSourceState } from './catalog-sources/projection.js';
6
+ export function configObjectHasSensitiveChild(field) {
7
+ if (field.type !== 'object')
8
+ return false;
9
+ return Object.values(field.properties ?? {}).some((property) => property.sensitive === true)
10
+ || (field.additionalProperties !== false && field.additionalProperties?.sensitive === true);
11
+ }
12
+ function compareText(left, right) {
13
+ return left.localeCompare(right, 'en');
14
+ }
15
+ function targetHealth(target) {
16
+ if (target.state === 'ready')
17
+ return 'ready';
18
+ if (target.state === 'needsSync' || target.state === 'orphaned')
19
+ return 'incomplete';
20
+ return target.state === 'blocked' ? 'error' : 'incomplete';
21
+ }
22
+ export function isPureNativeCodexTarget(target) {
23
+ const sharedNative = statusTargetSharedNative(target);
24
+ const extensions = statusTargetExtensions(target);
25
+ return target.platform === 'codex'
26
+ && sharedNative !== undefined
27
+ && (extensions?.kinds.length ?? 0) === 0;
28
+ }
29
+ function isPureNativeCodexPlacement(placement) {
30
+ return placement.platform === 'codex'
31
+ && placement.state === 'installed'
32
+ && placement.sharedNative !== undefined
33
+ && (placement.extensions?.kinds.length ?? 0) === 0;
34
+ }
35
+ function parsedScopedUninstallRecovery(recovery, expectedPlatform) {
36
+ if (recovery.command !== 'uninstall' || !recovery.scope)
37
+ return undefined;
38
+ const match = /(?:^|\s)aw uninstall ([^\s]+) --platform (codex|claude) --scope (user|project)(?:,|,|\s|$)/u
39
+ .exec(recovery.description);
40
+ if (!match || match[2] !== expectedPlatform || match[3] !== recovery.scope)
41
+ return undefined;
42
+ return { pluginId: match[1], scope: recovery.scope, description: recovery.description };
43
+ }
44
+ function scopeConflictRecoveryMenuActions(placement) {
45
+ if (placement.actualState !== 'blocked')
46
+ return [];
47
+ return (placement.recovery ?? []).flatMap((recovery) => {
48
+ const parsed = parsedScopedUninstallRecovery(recovery, placement.platform);
49
+ return parsed ? [{
50
+ id: 'resolveScopeConflict',
51
+ pluginId: parsed.pluginId,
52
+ platform: placement.platform,
53
+ scope: parsed.scope,
54
+ keepScope: parsed.scope === 'user' ? 'project' : 'user',
55
+ description: parsed.description,
56
+ }] : [];
57
+ });
58
+ }
59
+ function missingPureNativeScopes(plugin, placement) {
60
+ if (!isPureNativeCodexPlacement(placement) || placement.actualState !== 'ready')
61
+ return [];
62
+ const supported = plugin.supportedScopes?.codex ?? ['user', 'project'];
63
+ return supported.filter((scope) => !placement.desiredScopes?.includes(scope) && placement.activation?.[scope] !== true);
64
+ }
65
+ function isInstalledScopeEvidence(target) {
66
+ return statusTargetIntent(target).enabled
67
+ || statusTargetOwnershipState(target) === 'present'
68
+ || statusTargetOwnershipState(target) === 'partial';
69
+ }
70
+ function dependencyAssignmentExplanation(assignmentSource, requiredBy) {
71
+ const consumer = requiredBy[0];
72
+ return {
73
+ root: '根插件位置',
74
+ default: '推荐使用当前项目',
75
+ existingWiderTarget: '复用健康的所有项目安装',
76
+ userOverride: '你选择的位置',
77
+ consumerPromotion: consumer
78
+ ? `因 ${consumer} 的位置而一并调整`
79
+ : '因上游依赖位置而一并调整',
80
+ platformRequirement: '平台只支持这个位置',
81
+ }[assignmentSource];
82
+ }
83
+ export function dependencyPlacementTargets(plan) {
84
+ return plan.targets.filter((target) => target.relation === 'dependency').map((target) => ({
85
+ key: `${target.pluginId}\0${target.platform}`,
86
+ pluginId: target.pluginId,
87
+ displayName: target.pluginName,
88
+ platform: target.platform,
89
+ relation: target.depth === 1 ? 'direct' : 'transitive',
90
+ scope: target.resolvedScope,
91
+ minimumScope: target.minimumScope,
92
+ allowedScopes: [...target.allowedScopes],
93
+ locked: target.locked && target.lockReason !== 'dependencyScopeOverride',
94
+ requiredBy: [...target.requiredBy],
95
+ assignmentSource: target.assignmentSource,
96
+ explanation: dependencyAssignmentExplanation(target.assignmentSource, target.requiredBy),
97
+ affectsOtherProjects: target.affectsOtherProjects,
98
+ action: target.action,
99
+ }));
100
+ }
101
+ function dependencyPluginIdFromMessage(message) {
102
+ return message.match(/(?:[a-z0-9]+(?:-[a-z0-9]+)*)\/(?:[a-z0-9]+(?:-[a-z0-9]+)*)/u)?.[0];
103
+ }
104
+ function rootPlacementFromIssueId(issueId, fallback) {
105
+ if (issueId) {
106
+ for (const platform of ['claude', 'codex']) {
107
+ for (const scope of ['project', 'user']) {
108
+ if (issueId.includes(`:${platform}:${scope}:`)
109
+ || issueId.endsWith(`:${platform}:${scope}`))
110
+ return { platform, scope };
111
+ }
112
+ }
113
+ }
114
+ return fallback;
115
+ }
116
+ function rootPluginIdFromIssueId(issueId, rootIssueCode) {
117
+ if (!issueId || !rootIssueCode || !issueId.startsWith(`${rootIssueCode}:`))
118
+ return undefined;
119
+ for (const platform of ['claude', 'codex']) {
120
+ for (const scope of ['project', 'user']) {
121
+ const marker = `:${platform}:${scope}`;
122
+ const markerIndex = issueId.indexOf(marker, rootIssueCode.length + 1);
123
+ if (markerIndex > rootIssueCode.length + 1) {
124
+ return issueId.slice(rootIssueCode.length + 1, markerIndex);
125
+ }
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ function targetIssueRelationship(options) {
131
+ const consumer = options.error?.rootIssueId !== undefined
132
+ && options.error.rootIssueCode !== undefined
133
+ && (options.error.code !== options.error.rootIssueCode
134
+ || options.dependencyPluginId !== undefined
135
+ && options.dependencyPluginId !== options.target.pluginId);
136
+ if (!consumer) {
137
+ return {
138
+ relationship: 'direct',
139
+ rootEntity: {
140
+ pluginId: options.target.pluginId,
141
+ platform: options.target.platform,
142
+ scope: options.target.scope,
143
+ },
144
+ };
145
+ }
146
+ const placement = rootPlacementFromIssueId(options.error?.rootIssueId, options.target);
147
+ return {
148
+ relationship: 'consumer',
149
+ rootEntity: {
150
+ pluginId: rootPluginIdFromIssueId(options.error?.rootIssueId, options.error?.rootIssueCode) ?? options.dependencyPluginId ?? options.target.pluginId,
151
+ ...placement,
152
+ },
153
+ };
154
+ }
155
+ export function projectPlatformPlacement(platform, targets, revisions = []) {
156
+ const revisionFor = (target) => revisions.find((entry) => entry.pluginId === target.pluginId
157
+ && entry.platform === target.platform
158
+ && entry.scope === target.scope)?.revision
159
+ ?? { state: 'unknown', ...(target.version ? { availableVersion: target.version } : {}) };
160
+ const supportedScopes = [...new Set(targets.map((target) => target.scope))];
161
+ const installed = targets.filter(isInstalledScopeEvidence);
162
+ if (installed.length === 0) {
163
+ if (targets.some((target) => target.reasons.some((reason) => reason.code === 'artifactCollision' && reason.severity === 'blocking'))) {
164
+ return { platform, state: 'blocked', supportedScopes, reason: 'artifactCollision' };
165
+ }
166
+ const errorTarget = targets.find((target) => target.state === 'blocked');
167
+ if (!errorTarget)
168
+ return { platform, state: 'notInstalled', supportedScopes };
169
+ return {
170
+ platform,
171
+ state: 'installed',
172
+ scope: errorTarget.scope,
173
+ health: 'error',
174
+ revision: revisionFor(errorTarget),
175
+ };
176
+ }
177
+ const target = installed.find((candidate) => candidate.state === 'blocked')
178
+ ?? installed.find((candidate) => candidate.state === 'needsSync')
179
+ ?? installed.find((candidate) => candidate.state === 'orphaned')
180
+ ?? installed[0];
181
+ const intent = statusTargetIntent(target);
182
+ const activation = statusTargetActivation(target);
183
+ const sharedNative = statusTargetSharedNative(target);
184
+ const extensions = statusTargetExtensions(target);
185
+ const blockingReason = target.reasons.some((reason) => reason.code === 'artifactCollision' && reason.severity === 'blocking')
186
+ ? 'artifactCollision'
187
+ : undefined;
188
+ return {
189
+ platform,
190
+ state: 'installed',
191
+ scope: target.scope,
192
+ health: targetHealth(target),
193
+ revision: revisionFor(target),
194
+ desiredScopes: [...intent.scopes],
195
+ relation: intent.relation,
196
+ actualState: target.state,
197
+ ...(activation ? { activation } : {}),
198
+ ...(sharedNative ? { sharedNative } : {}),
199
+ ...(extensions ? { extensions } : {}),
200
+ recovery: [...target.recoveryActions],
201
+ ...(blockingReason ? { blockingReason } : {}),
202
+ };
203
+ }
204
+ function hasIncompletePlacement(plugin) {
205
+ return plugin.installedPlacements.some((placement) => placement.state === 'scopeConflict'
206
+ || placement.state === 'installed'
207
+ && (placement.health !== 'ready' || placement.blockingReason !== undefined));
208
+ }
209
+ function hasMissingPlatform(plugin) {
210
+ return plugin.supportedPlatforms.some((platform) => plugin.installedPlacements.find((placement) => placement.platform === platform)?.state === 'notInstalled');
211
+ }
212
+ function allSupportedPlatformsBlocked(plugin) {
213
+ return plugin.supportedPlatforms.length > 0 && plugin.supportedPlatforms.every((platform) => plugin.installedPlacements.some((placement) => placement.platform === platform
214
+ && (placement.state === 'blocked'
215
+ || placement.state === 'installed' && placement.blockingReason === 'artifactCollision')));
216
+ }
217
+ function capabilityActions(plugin) {
218
+ return [
219
+ ...(plugin.portableSkills ? [{ id: 'portableSkills' }] : []),
220
+ ...((plugin.dependencySummary?.totalCount ?? 0) > 0 ? [{ id: 'dependencies' }] : []),
221
+ ...(plugin.configFieldCount > 0 ? [{ id: 'settings' }] : []),
222
+ ];
223
+ }
224
+ function capabilityUnavailableActions() {
225
+ return [{ id: 'upgradeAwCli' }, { id: 'capabilityTechnical' }];
226
+ }
227
+ function isCapabilityUnavailable(plugin) {
228
+ return plugin.capabilityUnsupported === true && plugin.sourceUnavailable !== true;
229
+ }
230
+ export function buildPluginPreviewActions(plugin) {
231
+ const installed = hasInstalledPlacement(plugin);
232
+ if (plugin.aggregateStatus === 'unavailable') {
233
+ if (isCapabilityUnavailable(plugin)) {
234
+ return [...capabilityUnavailableActions(), ...(installed ? [{ id: 'manage' }] : [])];
235
+ }
236
+ return [{ id: 'sourceProblem' }, ...(installed ? [{ id: 'manage' }] : [])];
237
+ }
238
+ if (allSupportedPlatformsBlocked(plugin)) {
239
+ return [
240
+ { id: 'outputCollision' },
241
+ ...(hasInstalledPlacement(plugin) ? [{ id: 'manage' }] : []),
242
+ { id: 'source' },
243
+ { id: 'about' },
244
+ ];
245
+ }
246
+ const collisionWithInstallablePlatform = hasMissingPlatform(plugin)
247
+ && plugin.installedPlacements.some((placement) => placement.state === 'blocked'
248
+ || placement.state === 'installed' && placement.blockingReason === 'artifactCollision');
249
+ const primary = collisionWithInstallablePlatform
250
+ ? { id: 'add' }
251
+ : hasIncompletePlacement(plugin) || (plugin.dependencySummary?.issueCount ?? 0) > 0
252
+ ? { id: 'repair' }
253
+ : installed && !hasMissingPlatform(plugin) ? { id: 'manage' } : { id: 'add' };
254
+ return [primary, ...capabilityActions(plugin), { id: 'source' }];
255
+ }
256
+ export function buildPluginDetailActions(plugin) {
257
+ if (plugin.aggregateStatus === 'unavailable') {
258
+ if (isCapabilityUnavailable(plugin)) {
259
+ return [
260
+ ...plugin.installedPlacements.flatMap((placement) => placement.state === 'notInstalled'
261
+ ? []
262
+ : [{ id: 'platform', platform: placement.platform }]),
263
+ ...capabilityUnavailableActions(),
264
+ { id: 'about' },
265
+ ];
266
+ }
267
+ return [
268
+ ...plugin.installedPlacements.flatMap((placement) => placement.state === 'notInstalled'
269
+ ? []
270
+ : [{ id: 'platform', platform: placement.platform }]),
271
+ { id: 'sourceProblem' },
272
+ { id: 'about' },
273
+ ];
274
+ }
275
+ return [
276
+ ...plugin.installedPlacements.flatMap((placement) => [
277
+ ...(placement.state === 'installed' ? scopeConflictRecoveryMenuActions(placement) : []),
278
+ placement.state === 'scopeConflict'
279
+ ? { id: 'scopeConflict', platform: placement.platform }
280
+ : { id: 'platform', platform: placement.platform },
281
+ ]),
282
+ ...((plugin.dependencySummary?.totalCount ?? 0) > 0 ? [{ id: 'dependencies' }] : []),
283
+ ...(plugin.portableSkills ? [{ id: 'portableSkills' }] : []),
284
+ ...(plugin.configFieldCount > 0 ? [{ id: 'settings' }] : []),
285
+ { id: 'about' },
286
+ ];
287
+ }
288
+ export function buildPlatformActions(plugin, platform) {
289
+ if (plugin.aggregateStatus === 'unavailable') {
290
+ if (isCapabilityUnavailable(plugin))
291
+ return capabilityUnavailableActions();
292
+ return [{ id: 'sourceProblem' }, { id: 'refreshSource' }];
293
+ }
294
+ const placement = plugin.installedPlacements.find((entry) => entry.platform === platform);
295
+ if (placement?.state === 'blocked') {
296
+ return [{ id: 'outputCollision' }, { id: 'source' }, { id: 'about' }];
297
+ }
298
+ if (!placement || placement.state === 'notInstalled')
299
+ return [{ id: 'add' }, { id: 'about' }];
300
+ if (placement.state === 'scopeConflict')
301
+ return [{ id: 'scopeConflict', platform }];
302
+ const scopedRecovery = scopeConflictRecoveryMenuActions(placement);
303
+ if (scopedRecovery.length > 0)
304
+ return [...scopedRecovery, { id: 'technical' }];
305
+ if (placement.blockingReason === 'artifactCollision') {
306
+ return [
307
+ { id: 'outputCollision' },
308
+ { id: 'remove', platform, scope: placement.scope },
309
+ { id: 'technical' },
310
+ ];
311
+ }
312
+ const lifecycleActions = buildAllowedLifecycleActions({
313
+ pluginId: plugin.pluginId,
314
+ platform,
315
+ scope: placement.scope,
316
+ state: placement.actualState ?? (placement.health === 'ready'
317
+ ? 'ready' : placement.health === 'incomplete' ? 'needsSync' : 'blocked'),
318
+ recoveryActions: placement.recovery ?? [],
319
+ revision: placement.revision,
320
+ }).flatMap((action) => {
321
+ if (action.id === 'install')
322
+ return [{ id: 'add' }];
323
+ if (action.id === 'refreshAndSync')
324
+ return [{
325
+ id: 'refreshAndSync',
326
+ platform: action.platform,
327
+ scope: action.scope,
328
+ availableVersion: action.availableVersion,
329
+ }];
330
+ if (action.id === 'sync')
331
+ return [{ id: 'sync' }];
332
+ if (action.id === 'reinstall')
333
+ return [{ id: 'reinstall', platform: action.platform, scope: action.scope }];
334
+ if (action.id === 'uninstall')
335
+ return [{ id: 'remove', platform: action.platform, scope: action.scope }];
336
+ return [{ id: 'cleanup', platform: action.platform, scope: action.scope }];
337
+ });
338
+ if (placement.health !== 'ready') {
339
+ return [...lifecycleActions, { id: 'technical' }, ...(lifecycleActions.length === 0 ? [{ id: 'back' }] : [])];
340
+ }
341
+ return [
342
+ ...missingPureNativeScopes(plugin, placement).map((scope) => ({
343
+ id: 'addScope', platform, scope,
344
+ })),
345
+ ...lifecycleActions,
346
+ { id: 'technical' },
347
+ ];
348
+ }
349
+ export function hasInstalledPlacement(plugin) {
350
+ return plugin.installedPlacements.some((placement) => placement.state === 'installed' || placement.state === 'scopeConflict');
351
+ }
352
+ function sourceIssue(health, impactedTargets = 0) {
353
+ if (health.state !== 'unavailable')
354
+ return undefined;
355
+ const issueId = health.issueId ?? `source:${health.sourceId}:unavailable`;
356
+ return {
357
+ issueId,
358
+ category: 'sourceUnavailable',
359
+ title: `${health.sourceId} · 来源不可用`,
360
+ explanation: '来源检查失败。',
361
+ impact: ['当前不能浏览或安装这个来源的插件。',
362
+ ...(impactedTargets > 0 ? [`${impactedTargets} 个安装位置受此来源根问题影响。`] : [])],
363
+ entity: { kind: 'source', id: health.sourceId },
364
+ sourceId: health.sourceId,
365
+ actions: [
366
+ { id: 'editSource', label: '编辑来源', description: '检查 URL、路径或 ref' },
367
+ { id: 'refreshSource', label: '稍后重试', description: '只重新检查来源' },
368
+ { id: 'viewTechnical', label: '技术详情' },
369
+ ],
370
+ technicalDetails: [{
371
+ code: 'catalogSourceUnavailable',
372
+ message: '来源检查失败。',
373
+ }],
374
+ };
375
+ }
376
+ function lifecycleIssueActions(target, options = {}) {
377
+ return buildAllowedLifecycleActions(target).flatMap((action) => {
378
+ if (options.dependency) {
379
+ if (action.id === 'install')
380
+ return [{
381
+ id: 'installDependency',
382
+ label: '补齐依赖插件',
383
+ pluginId: action.pluginId,
384
+ platform: action.platform,
385
+ scope: action.scope,
386
+ project: options.project,
387
+ writeAction: 'install',
388
+ }];
389
+ if (action.id === 'sync' || action.id === 'reinstall')
390
+ return [{
391
+ id: 'reinstallDependency',
392
+ label: action.label,
393
+ description: action.description,
394
+ pluginId: action.pluginId,
395
+ platform: action.platform,
396
+ scope: action.scope,
397
+ project: options.project,
398
+ writeAction: action.id,
399
+ }];
400
+ return [];
401
+ }
402
+ const projection = {
403
+ install: { id: 'install', writeAction: 'install' },
404
+ sync: { id: 'sync', writeAction: 'sync' },
405
+ refreshAndSync: { id: 'refreshAndSync', writeAction: 'refreshAndSync' },
406
+ reinstall: { id: 'reinstall', writeAction: 'reinstall' },
407
+ uninstall: { id: 'remove', writeAction: 'uninstall' },
408
+ cleanup: { id: 'cleanup', writeAction: 'cleanup' },
409
+ }[action.id];
410
+ return [{
411
+ ...projection,
412
+ label: action.label,
413
+ description: action.description,
414
+ pluginId: action.pluginId,
415
+ platform: action.platform,
416
+ scope: action.scope,
417
+ }];
418
+ });
419
+ }
420
+ function targetIssues(payload) {
421
+ const issues = [];
422
+ const canonicalRootsByEntity = new Map();
423
+ for (const target of payload.targets) {
424
+ for (const error of target.reasons) {
425
+ if (!error.rootIssueId || !error.rootIssueCode)
426
+ continue;
427
+ const dependencyPluginId = error.dependencyPluginId
428
+ ?? dependencyPluginIdFromMessage(error.message);
429
+ const relationship = targetIssueRelationship({ target, error, dependencyPluginId });
430
+ if (relationship.relationship !== 'consumer')
431
+ continue;
432
+ const key = [
433
+ error.rootIssueCode,
434
+ relationship.rootEntity.pluginId,
435
+ relationship.rootEntity.platform,
436
+ relationship.rootEntity.scope,
437
+ ].join('\0');
438
+ const current = canonicalRootsByEntity.get(key);
439
+ if (!current || compareText(error.rootIssueId, current) < 0) {
440
+ canonicalRootsByEntity.set(key, error.rootIssueId);
441
+ }
442
+ }
443
+ }
444
+ for (const target of payload.targets) {
445
+ const intent = statusTargetIntent(target);
446
+ const scopedConflictRecovery = target.reasons.some((reason) => reason.code === 'codexExtensionScopeConflict')
447
+ ? target.recoveryActions.flatMap((recovery) => {
448
+ const parsed = parsedScopedUninstallRecovery(recovery, target.platform);
449
+ return parsed ? [{ ...parsed, keepScope: parsed.scope === 'user'
450
+ ? 'project' : 'user' }] : [];
451
+ })
452
+ : [];
453
+ if (scopedConflictRecovery.length > 0) {
454
+ issues.push({
455
+ issueId: `scope:${target.pluginId}:${target.platform}`,
456
+ category: 'scopeConflict',
457
+ title: `${target.pluginId} · ${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · 扩展位置冲突`,
458
+ explanation: 'AW-only 扩展不能同时使用所有项目和当前项目位置。',
459
+ impact: ['选择一条 root uninstall 路径,然后按该路径同步保留的 scope。'],
460
+ entity: { kind: 'plugin', id: target.pluginId },
461
+ pluginId: target.pluginId,
462
+ platform: target.platform,
463
+ scope: target.scope,
464
+ sourceId: target.sourceId,
465
+ sourceIdentity: target.sourceIdentity,
466
+ placements: [...intent.scopes].sort(compareText),
467
+ actions: [
468
+ ...scopedConflictRecovery.map((recovery) => ({
469
+ id: recovery.keepScope === 'user' ? 'keepUserScope' : 'keepProjectScope',
470
+ label: `保留${recovery.keepScope === 'user' ? '所有项目' : '当前项目'}`,
471
+ description: recovery.description,
472
+ pluginId: recovery.pluginId,
473
+ platform: target.platform,
474
+ scope: recovery.scope,
475
+ writeAction: 'uninstall',
476
+ })),
477
+ { id: 'viewTechnical', label: '查看冲突详情' },
478
+ ],
479
+ technicalDetails: [{
480
+ code: 'codexExtensionScopeConflict',
481
+ message: 'mixed 或 AW-only 扩展同时使用两个 scope。',
482
+ }],
483
+ });
484
+ }
485
+ if (target.state !== 'needsSync' && target.state !== 'blocked'
486
+ && !target.reasons.some((error) => error.code === 'artifactCollision'
487
+ || error.dependencyPluginId !== undefined && error.rootIssueId !== undefined))
488
+ continue;
489
+ const codes = new Set(target.reasons.map((error) => error.code));
490
+ const sharedNativeRenderDrift = target.state === 'needsSync'
491
+ && codes.has('codexSharedNativeRenderDrift');
492
+ const dependencyCodes = [
493
+ 'dependencyMissing',
494
+ 'dependencyNotReady',
495
+ 'dependencyTargetUnsupported',
496
+ 'dependencyStillRequired',
497
+ 'dependencyGraphInvalid',
498
+ ];
499
+ const dependencyRootMap = new Map();
500
+ for (const error of target.reasons) {
501
+ if (!dependencyCodes.includes(error.code))
502
+ continue;
503
+ if (error.rootIssueCode === 'artifactCollision') {
504
+ dependencyRootMap.set(error.rootIssueId ?? `artifactCollision\0${error.dependencyPluginId ?? ''}`, {
505
+ code: 'artifactCollision',
506
+ category: 'artifactCollision',
507
+ mergeEligible: false,
508
+ error,
509
+ dependencyPluginId: error.dependencyPluginId,
510
+ });
511
+ continue;
512
+ }
513
+ const code = error.code;
514
+ const dependencyPluginId = error.dependencyPluginId ?? dependencyPluginIdFromMessage(error.message);
515
+ dependencyRootMap.set(`${code}\0${dependencyPluginId ?? ''}`, {
516
+ code,
517
+ category: code,
518
+ mergeEligible: false,
519
+ error,
520
+ dependencyPluginId,
521
+ });
522
+ }
523
+ const dependencyRoots = [...dependencyRootMap.values()];
524
+ const directCollision = target.reasons.find((error) => error.code === 'artifactCollision');
525
+ const projectedCollisionRoots = dependencyRoots.filter((root) => root.code === 'artifactCollision');
526
+ const ordinaryDependencyRoots = dependencyRoots.filter((root) => root.code !== 'artifactCollision');
527
+ const roots = codes.has('sourceMissing')
528
+ ? [{ code: 'sourceMissing', category: 'sourceMissing', mergeEligible: false }]
529
+ : directCollision || projectedCollisionRoots.length > 0
530
+ ? [{
531
+ code: 'artifactCollision',
532
+ category: 'artifactCollision',
533
+ mergeEligible: false,
534
+ error: directCollision ?? projectedCollisionRoots[0].error,
535
+ dependencyPluginId: projectedCollisionRoots[0]?.dependencyPluginId,
536
+ }]
537
+ : codes.has('sourceChanged')
538
+ ? [{ code: 'sourceChanged', category: 'sourceIdentityChanged', mergeEligible: false }]
539
+ : codes.has('catalogSourceUnavailable') || codes.has('bundleUnavailable')
540
+ ? [
541
+ ...(codes.has('catalogSourceUnavailable')
542
+ ? [{ code: 'catalogSourceUnavailable', category: 'sourceUnavailable', mergeEligible: true }]
543
+ : []),
544
+ ...(codes.has('bundleUnavailable')
545
+ ? [{ code: 'bundleUnavailable', category: 'sourceUnavailable', mergeEligible: false }]
546
+ : []),
547
+ ]
548
+ : ordinaryDependencyRoots.length > 0
549
+ ? ordinaryDependencyRoots
550
+ : target.state === 'needsSync'
551
+ ? [{ code: 'partial', category: 'incompleteInstallation', mergeEligible: false }]
552
+ : [
553
+ { code: 'targetDiagnostic', category: 'diagnostic', mergeEligible: false },
554
+ ];
555
+ for (const root of roots) {
556
+ const rootError = root.error ?? target.reasons.find((error) => error.code === root.code);
557
+ const dependencyPluginId = root.dependencyPluginId
558
+ ?? rootError?.dependencyPluginId
559
+ ?? (rootError ? dependencyPluginIdFromMessage(rootError.message) : undefined);
560
+ const dependencyPlatform = rootError?.dependencyPlatform;
561
+ const dependencyScope = rootError?.dependencyScope;
562
+ const dependencyProject = rootError?.dependencyProject;
563
+ const dependencyCategory = root.category.startsWith('dependency');
564
+ const dependencyTarget = dependencyPluginId && dependencyPlatform && dependencyScope
565
+ ? payload.targets.find((candidate) => candidate.pluginId === dependencyPluginId
566
+ && candidate.platform === dependencyPlatform && candidate.scope === dependencyScope)
567
+ : undefined;
568
+ const dependencyLifecycleActions = dependencyPluginId && dependencyPlatform && dependencyScope
569
+ ? lifecycleIssueActions(dependencyTarget ?? {
570
+ pluginId: dependencyPluginId,
571
+ platform: dependencyPlatform,
572
+ scope: dependencyScope,
573
+ state: 'absent',
574
+ recoveryActions: [],
575
+ }, { dependency: true, project: dependencyProject })
576
+ : [];
577
+ const directLifecycleActions = dependencyCategory ? [] : lifecycleIssueActions(target);
578
+ const actions = root.category === 'dependencyMissing'
579
+ ? [
580
+ ...dependencyLifecycleActions,
581
+ { id: 'viewDependencies', label: '查看依赖关系' },
582
+ { id: 'viewTechnical', label: '技术详情' },
583
+ ]
584
+ : root.category === 'dependencyNotReady'
585
+ ? [
586
+ ...(dependencyPluginId ? [
587
+ { id: 'viewDependencyIssue', label: '查看依赖插件问题', pluginId: dependencyPluginId },
588
+ ] : []),
589
+ ...dependencyLifecycleActions.filter((action) => action.id === 'reinstallDependency'),
590
+ { id: 'viewDependencies', label: '查看依赖关系' },
591
+ { id: 'viewTechnical', label: '技术详情' },
592
+ ]
593
+ : dependencyCategory
594
+ ? [
595
+ { id: 'viewDependencies', label: '查看依赖关系' },
596
+ { id: 'viewTechnical', label: '技术详情' },
597
+ ]
598
+ : root.category === 'artifactCollision'
599
+ ? [
600
+ { id: 'viewTechnical', label: '查看冲突原因' },
601
+ { id: 'retryLater', label: '处理冲突后重试' },
602
+ ]
603
+ : root.category === 'incompleteInstallation'
604
+ ? [
605
+ ...directLifecycleActions,
606
+ { id: 'viewTechnical', label: '技术详情' },
607
+ ]
608
+ : root.category === 'sourceMissing'
609
+ ? [
610
+ ...directLifecycleActions,
611
+ { id: 'reAddSource', label: '重新添加同一来源', description: '保留来源 ID;来源类型和位置由你选择' },
612
+ { id: 'viewTechnical', label: '技术详情' },
613
+ ]
614
+ : root.category === 'sourceIdentityChanged'
615
+ ? [
616
+ { id: 'viewSourceChange', label: '查看来源变更', description: '不会自动覆盖现场状态' },
617
+ { id: 'viewTechnical', label: '技术详情' },
618
+ ]
619
+ : root.category === 'sourceUnavailable'
620
+ ? [
621
+ ...(root.code === 'bundleUnavailable' ? directLifecycleActions : []),
622
+ { id: 'editSource', label: '查看来源', description: root.code === 'bundleUnavailable' ? '检查当前 Catalog 或稍后重试' : '修复来源配置或稍后重试' },
623
+ { id: 'viewTechnical', label: '技术详情' },
624
+ ]
625
+ : [...directLifecycleActions,
626
+ { id: 'viewTechnical', label: '技术详情' },
627
+ { id: 'retryLater', label: '稍后重试' }];
628
+ const bundleUnavailable = root.code === 'bundleUnavailable';
629
+ const relationship = targetIssueRelationship({
630
+ target,
631
+ error: rootError,
632
+ dependencyPluginId,
633
+ });
634
+ const directRootCode = root.code === 'partial' ? 'incompleteInstallation'
635
+ : root.code === 'targetDiagnostic' ? 'diagnostic'
636
+ : undefined;
637
+ const canonicalRoot = relationship.relationship === 'direct' && directRootCode
638
+ ? canonicalRootsByEntity.get([
639
+ directRootCode,
640
+ relationship.rootEntity.pluginId,
641
+ relationship.rootEntity.platform,
642
+ relationship.rootEntity.scope,
643
+ ].join('\0'))
644
+ : undefined;
645
+ const issueId = rootError?.rootIssueId
646
+ ?? canonicalRoot
647
+ ?? (directRootCode
648
+ ? `${directRootCode}:${target.pluginId}:${target.platform}:${target.scope}`
649
+ : `target:${target.pluginId}:${target.platform}:${target.scope}:${target.state}${roots.length > 1 ? `:${root.code}` : ''}${dependencyPluginId ? `:${dependencyPluginId}` : ''}`);
650
+ issues.push({
651
+ issueId,
652
+ category: root.category,
653
+ rootCode: root.code,
654
+ mergeEligible: root.mergeEligible,
655
+ relationship: relationship.relationship,
656
+ rootEntity: relationship.rootEntity,
657
+ affectedTargets: [{
658
+ pluginId: target.pluginId,
659
+ platform: target.platform,
660
+ scope: target.scope,
661
+ relationship: relationship.relationship,
662
+ }],
663
+ title: `${target.pluginId} · ${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${sharedNativeRenderDrift ? '共享 native 待同步' : root.category === 'artifactCollision' ? '输出冲突' : dependencyCategory ? {
664
+ dependencyMissing: '缺少依赖',
665
+ dependencyNotReady: '依赖安装不完整',
666
+ dependencyTargetUnsupported: '依赖目标不兼容',
667
+ dependencyStillRequired: '依赖仍被使用',
668
+ dependencyGraphInvalid: '依赖关系无效',
669
+ }[root.category] : target.state === 'needsSync' ? '安装不完整' : bundleUnavailable ? '当前 Catalog 不再包含此插件' : '检查失败'}`,
670
+ explanation: root.category === 'artifactCollision'
671
+ ? '目标位置已有不属于当前插件的内容。AW 不会覆盖或删除这些内容。'
672
+ : dependencyCategory
673
+ ? dependencyPluginId
674
+ ? `${dependencyPluginId} 导致当前依赖检查不能通过。`
675
+ : '当前依赖检查不能安全通过。'
676
+ : sharedNativeRenderDrift
677
+ ? '个人默认已变化。共享 Codex native Skill 尚未重新生成。'
678
+ : target.state === 'needsSync'
679
+ ? '必要内容缺失,插件可能不能稳定运行。'
680
+ : bundleUnavailable
681
+ ? '当前 Catalog 不再包含此插件,但仍发现 AW 管理的已安装内容。'
682
+ : '当前目标不能安全分类为正常安装。',
683
+ impact: [sharedNativeRenderDrift
684
+ ? '运行同步可恢复;这不是 cache 损坏。'
685
+ : root.category === 'artifactCollision'
686
+ ? '请先移除或迁移冲突内容,然后重试安装或重新安装。'
687
+ : bundleUnavailable
688
+ ? '可以清理可信的 AW 现场;这不表示来源整体可用。'
689
+ : '写操作前需要重新检查这个目标。'],
690
+ entity: { kind: 'plugin', id: target.pluginId },
691
+ pluginId: target.pluginId,
692
+ ...(dependencyPluginId ? { dependencyPluginId } : {}),
693
+ ...(dependencyPlatform ? { dependencyPlatform } : {}),
694
+ ...(dependencyScope ? { dependencyScope } : {}),
695
+ ...(dependencyProject !== undefined ? { dependencyProject } : {}),
696
+ platform: target.platform,
697
+ scope: target.scope,
698
+ sourceId: target.sourceId,
699
+ sourceIdentity: target.sourceIdentity,
700
+ actions,
701
+ technicalDetails: target.reasons.length > 0
702
+ ? target.reasons.filter((error) => root.code === 'targetDiagnostic'
703
+ || root.code === 'partial'
704
+ || error.code === root.code
705
+ || error.rootIssueId === issueId)
706
+ .map((error) => ({
707
+ code: error.code,
708
+ message: error.collision
709
+ ? ({
710
+ ownerMismatch: '目标由其他 owner 占用。',
711
+ unownedContent: '目标包含没有 AW owner 标记的内容。',
712
+ typeMismatch: '目标节点类型不符合预期。',
713
+ })[error.collision.reason]
714
+ : '状态检查报告了这个安全错误代码。',
715
+ }))
716
+ : [{ code: 'targetStateError', message: '目标状态异常。' }],
717
+ });
718
+ }
719
+ }
720
+ return issues;
721
+ }
722
+ function statusIssues(payload) {
723
+ const targetCodes = new Set(payload.targets.flatMap((target) => target.reasons.map((error) => error.code)));
724
+ const issues = new Map();
725
+ for (const error of payload.errors) {
726
+ if (targetCodes.has(error.code) || issues.has(error.code))
727
+ continue;
728
+ const projection = error.code === 'legacyStateUnsupported'
729
+ ? {
730
+ title: '发现旧版状态',
731
+ explanation: '当前状态使用不受支持的旧格式。',
732
+ impact: '在迁移或清理旧状态前,部分操作不可用。',
733
+ }
734
+ : error.code === 'nativeStateUnreadable'
735
+ ? {
736
+ title: '平台状态不可读',
737
+ explanation: '当前不能安全读取平台状态。',
738
+ impact: '部分安装状态可能不可用。',
739
+ }
740
+ : {
741
+ title: '状态清单不可用',
742
+ explanation: '当前不能完成状态清单检查。',
743
+ impact: '部分安装状态可能不可用。',
744
+ };
745
+ issues.set(error.code, {
746
+ issueId: `status:${error.code}`,
747
+ category: error.code === 'legacyStateUnsupported' ? 'legacyState' : 'diagnostic',
748
+ title: projection.title,
749
+ explanation: projection.explanation,
750
+ impact: [projection.impact],
751
+ entity: { kind: 'source', id: payload.catalog.primarySourceId },
752
+ sourceId: payload.catalog.primarySourceId,
753
+ actions: error.code === 'legacyStateUnsupported'
754
+ ? [
755
+ { id: 'manualMigration', label: '查看手动处理说明', description: '当前没有安全的自动迁移' },
756
+ { id: 'retryLater', label: '稍后重新检查' },
757
+ ]
758
+ : [{ id: 'retryLater', label: '稍后重试' }, { id: 'viewTechnical', label: '技术详情' }],
759
+ technicalDetails: [{ code: error.code, message: projection.explanation }],
760
+ });
761
+ }
762
+ return [...issues.values()];
763
+ }
764
+ function configIssues(pluginSummaries) {
765
+ return pluginSummaries.flatMap((summary) => {
766
+ const sourceId = summary.pluginId.slice(0, summary.pluginId.indexOf('/'));
767
+ const issues = [];
768
+ if (summary.configDiagnostic) {
769
+ issues.push({
770
+ issueId: `config:${summary.pluginId}:read`,
771
+ category: 'diagnostic',
772
+ title: `${summary.displayName ?? summary.pluginName} · 设置状态不可读`,
773
+ explanation: '当前不能安全读取这个插件的设置状态。',
774
+ impact: ['其他插件仍可检查;当前插件的设置值不会显示。'],
775
+ entity: { kind: 'plugin', id: summary.pluginId },
776
+ pluginId: summary.pluginId,
777
+ sourceId,
778
+ actions: [
779
+ { id: 'retryLater', label: '稍后重新检查' },
780
+ { id: 'viewTechnical', label: '查看技术详情' },
781
+ ],
782
+ technicalDetails: [{
783
+ code: summary.configDiagnostic.code,
784
+ message: '设置读取报告了这个安全错误代码。',
785
+ }],
786
+ });
787
+ }
788
+ if (!summary.configIssues?.length)
789
+ return issues;
790
+ const types = new Set(summary.configIssues.map((issue) => issue.type));
791
+ const invalid = types.has('invalid-config') || types.has('sharedCompositeContainsLocalPath');
792
+ const sources = new Set(summary.configIssues.map((issue) => issue.source));
793
+ const onlySource = sources.size === 1 ? [...sources][0] : undefined;
794
+ const configLayer = onlySource === 'user'
795
+ ? { scope: 'user' }
796
+ : onlySource === 'project'
797
+ ? { scope: 'project' }
798
+ : undefined;
799
+ issues.push({
800
+ issueId: `config:${summary.pluginId}:${invalid ? 'invalid' : 'required'}`,
801
+ category: 'requiredConfigMissing',
802
+ title: `${summary.displayName ?? summary.pluginName} · ${invalid ? '设置值无效' : '缺少必填设置'}`,
803
+ explanation: invalid
804
+ ? '已有设置值不符合当前字段规则。'
805
+ : '插件缺少必填设置,写操作会在预检时被阻止。',
806
+ impact: [invalid ? '修正所列字段后才能稳定生成插件内容。' : '完成所列字段后才能稳定生成插件内容。'],
807
+ entity: { kind: 'plugin', id: summary.pluginId },
808
+ pluginId: summary.pluginId,
809
+ sourceId,
810
+ requiredFields: summary.configIssues.map(({ key, title, type, source, scope }) => ({
811
+ key, title, type, source, scope,
812
+ })),
813
+ ...(configLayer ? { configLayer } : {}),
814
+ actions: [
815
+ { id: 'openConfig', label: invalid ? '修正设置' : '完成设置', description: configLayer ? '进入建议的设置层' : '选择个人或项目设置层' },
816
+ { id: 'viewTechnical', label: '查看字段详情' },
817
+ ],
818
+ technicalDetails: summary.configIssues.map((entry) => ({
819
+ code: entry.type,
820
+ message: `${entry.title} · ${entry.scope} · ${entry.source}`,
821
+ })),
822
+ });
823
+ return issues;
824
+ });
825
+ }
826
+ function dependencyOverviewIssues(overviews, pluginSummaries, status) {
827
+ const summaryById = new Map(pluginSummaries.map((summary) => [summary.pluginId, summary]));
828
+ return overviews.flatMap((overview) => overview.blockers.flatMap((blocker) => {
829
+ if (blocker.code !== 'dependencyGraphInvalid'
830
+ && blocker.code !== 'dependencyTargetUnsupported')
831
+ return [];
832
+ if (status.targets.some((target) => target.pluginId === overview.pluginId
833
+ && target.reasons.some((error) => error.code === blocker.code)))
834
+ return [];
835
+ const summary = summaryById.get(overview.pluginId);
836
+ const sourceId = overview.pluginId.slice(0, overview.pluginId.indexOf('/'));
837
+ const category = blocker.code;
838
+ return [{
839
+ issueId: `dependency:${overview.pluginId}:${blocker.code}`,
840
+ category,
841
+ rootCode: category,
842
+ mergeEligible: false,
843
+ title: `${summary?.displayName ?? summary?.pluginName ?? overview.pluginId} · ${blocker.title}`,
844
+ explanation: blocker.explanation,
845
+ impact: [category === 'dependencyGraphInvalid'
846
+ ? '修复依赖关系后才能安全计算安装顺序。'
847
+ : '当前不能在所有声明的平台上安全安装这个插件。'],
848
+ entity: { kind: 'plugin', id: overview.pluginId },
849
+ pluginId: overview.pluginId,
850
+ sourceId,
851
+ actions: [
852
+ { id: 'viewDependencies', label: '查看依赖关系' },
853
+ { id: 'viewTechnical', label: '技术详情' },
854
+ ],
855
+ technicalDetails: [{ code: blocker.code, message: blocker.explanation }],
856
+ }];
857
+ }));
858
+ }
859
+ function issueDiagnostic(issue, sourceDetails) {
860
+ const source = issue.sourceId ? sourceDetails.get(issue.sourceId) : undefined;
861
+ const sourceUnavailable = issue.category === 'sourceUnavailable' && issue.entity.kind === 'source';
862
+ const configUnavailable = issue.category === 'diagnostic' && issue.issueId.startsWith('config:');
863
+ const configInvalid = issue.category === 'requiredConfigMissing';
864
+ const dependency = issue.category.startsWith('dependency');
865
+ const platformState = issue.issueId.startsWith('status:') || issue.rootCode === 'targetDiagnostic';
866
+ const preserved = sourceUnavailable
867
+ ? '已安装插件和已保存设置不会被删除。'
868
+ : configUnavailable
869
+ ? '已保存的设置保持不变。'
870
+ : '现有安装和已保存设置不会因本页自动改变。';
871
+ const impact = sourceUnavailable
872
+ ? [
873
+ { state: 'blocked', message: '当前不能浏览或安装这个来源中的插件。' },
874
+ { state: 'preserved', message: preserved },
875
+ ]
876
+ : [
877
+ ...issue.impact.map((message) => ({
878
+ state: dependency || configUnavailable || configInvalid || platformState ? 'blocked' : 'degraded',
879
+ message,
880
+ })),
881
+ { state: 'preserved', message: preserved },
882
+ ];
883
+ const primaryAction = issue.actions.find((action) => action.id !== 'viewTechnical');
884
+ const nextStep = primaryAction
885
+ ? `${primaryAction.label},然后重新检查当前状态。`
886
+ : '打开技术详情,记录安全错误代码后重新检查。';
887
+ const sourceDiagnostic = sourceUnavailable;
888
+ const rawCode = sourceDiagnostic
889
+ ? source?.errorCode ?? issue.technicalDetails[0]?.code
890
+ : issue.technicalDetails[0]?.code;
891
+ const code = safeDiagnosticCode(rawCode, sourceUnavailable
892
+ ? 'catalogSourceUnavailable' : 'diagnosticUnavailable');
893
+ const stage = sourceUnavailable ? 'resolve-source'
894
+ : configUnavailable ? 'read-config'
895
+ : configInvalid ? 'validate-config'
896
+ : dependency ? 'resolve-dependencies'
897
+ : platformState ? 'read-platform-state' : 'inspect-target';
898
+ const context = [
899
+ ...(issue.pluginId ? [{ key: 'pluginId', value: issue.pluginId }] : []),
900
+ ...(issue.dependencyPluginId
901
+ ? [{ key: 'dependencyPluginId', value: issue.dependencyPluginId }]
902
+ : []),
903
+ ...(issue.platform ? [{ key: 'platform', value: issue.platform }] : []),
904
+ ...(issue.scope ? [{ key: 'scope', value: issue.scope }] : []),
905
+ ...(issue.requiredFields?.slice(0, 1).map((field) => ({
906
+ key: 'field',
907
+ value: field.title,
908
+ })) ?? []),
909
+ ];
910
+ const checks = issue.category === 'legacyState'
911
+ ? [
912
+ '不自动迁移旧版状态。',
913
+ '运行 aw status --json,记录公开错误 code。',
914
+ '备份相关 AW 配置。',
915
+ '按技术详情使用受支持命令或人工处理。',
916
+ '再次运行状态检查。',
917
+ ]
918
+ : sourceUnavailable
919
+ ? ['检查 Git URL、ref 或本地目录。', '确认当前终端具备来源授权。', '运行“重新检查来源”验证修复。']
920
+ : dependency
921
+ ? ['检查依赖关系和依赖插件状态。', '完成恢复动作后重新检查根插件。']
922
+ : configUnavailable
923
+ ? ['恢复插件来源和可信字段定义。', '重新检查来源后再次打开设置。']
924
+ : configInvalid
925
+ ? ['完成或修正列出的设置字段。', '重新检查插件设置。']
926
+ : ['检查目标平台配置和访问权限。', '完成恢复动作后重新运行状态检查。'];
927
+ return {
928
+ severity: 'error',
929
+ title: issue.title,
930
+ userMessage: issue.explanation,
931
+ impact,
932
+ nextStep,
933
+ technical: {
934
+ code,
935
+ stage,
936
+ ...(sourceDiagnostic && issue.sourceId ? { sourceId: issue.sourceId } : {}),
937
+ ...(sourceDiagnostic && source?.requestedRef ? { requestedRef: source.requestedRef } : {}),
938
+ ...(sourceDiagnostic && source?.resolvedCommit ? { resolvedCommit: source.resolvedCommit } : {}),
939
+ ...(context.length > 0 ? { context } : {}),
940
+ checks,
941
+ },
942
+ };
943
+ }
944
+ const issueGroupOrder = {
945
+ sourceRemoved: 0,
946
+ artifactCollision: 1,
947
+ sourceUnavailable: 2,
948
+ dependency: 3,
949
+ scope: 4,
950
+ config: 5,
951
+ installation: 6,
952
+ diagnostic: 7,
953
+ };
954
+ function issueGroup(issue) {
955
+ if (issue.category === 'sourceMissing')
956
+ return 'sourceRemoved';
957
+ if (issue.category === 'artifactCollision')
958
+ return 'artifactCollision';
959
+ if (issue.category === 'sourceUnavailable'
960
+ || issue.category === 'sourceIdentityChanged')
961
+ return 'sourceUnavailable';
962
+ if (issue.category.startsWith('dependency'))
963
+ return 'dependency';
964
+ if (issue.category === 'scopeConflict')
965
+ return 'scope';
966
+ if (issue.category === 'requiredConfigMissing')
967
+ return 'config';
968
+ if (issue.category === 'incompleteInstallation')
969
+ return 'installation';
970
+ return 'diagnostic';
971
+ }
972
+ function primaryAttentionCode(issue) {
973
+ if (issue.category === 'requiredConfigMissing') {
974
+ return issue.requiredFields?.some((field) => field.type === 'invalid-config')
975
+ ? 'invalidConfig'
976
+ : 'requiredConfigMissing';
977
+ }
978
+ if (issue.category === 'incompleteInstallation')
979
+ return 'incompleteInstallation';
980
+ if (issue.category === 'sourceIdentityChanged')
981
+ return 'sourceUnavailable';
982
+ return issue.rootCode ?? issue.category;
983
+ }
984
+ function issueReasonPriority(issue) {
985
+ const code = primaryAttentionCode(issue);
986
+ return {
987
+ sourceMissing: 0,
988
+ artifactCollision: 1,
989
+ sourceUnavailable: 2,
990
+ catalogSourceUnavailable: 2,
991
+ bundleUnavailable: 2,
992
+ dependencyGraphInvalid: 3,
993
+ dependencyTargetUnsupported: 4,
994
+ dependencyNotReady: 5,
995
+ dependencyMissing: 5,
996
+ scopeConflict: 6,
997
+ requiredConfigMissing: 7,
998
+ invalidConfig: 7,
999
+ incompleteInstallation: 8,
1000
+ diagnostic: 9,
1001
+ }[code] ?? 9;
1002
+ }
1003
+ function collapseRootIssues(issues) {
1004
+ const byId = new Map();
1005
+ for (const issue of issues)
1006
+ byId.set(issue.issueId, [...(byId.get(issue.issueId) ?? []), issue]);
1007
+ return [...byId.values()].map((group) => {
1008
+ const ordered = [...group].sort((left, right) => Number(right.relationship === 'direct') - Number(left.relationship === 'direct')
1009
+ || compareText(left.pluginId ?? '', right.pluginId ?? '')
1010
+ || compareText(left.platform ?? '', right.platform ?? '')
1011
+ || compareText(left.scope ?? '', right.scope ?? ''));
1012
+ const primary = ordered[0];
1013
+ const direct = ordered.find((issue) => issue.relationship === 'direct');
1014
+ const rootEntity = direct?.rootEntity ?? ordered.map((issue) => issue.rootEntity)
1015
+ .filter((entity) => entity !== undefined)
1016
+ .sort((left, right) => compareText(left.pluginId, right.pluginId)
1017
+ || compareText(left.platform, right.platform)
1018
+ || compareText(left.scope, right.scope))[0];
1019
+ const affectedTargets = [...new Map(ordered.flatMap((issue) => issue.affectedTargets ?? [])
1020
+ .map((target) => [`${target.pluginId}\0${target.platform}\0${target.scope}`, target])).values()]
1021
+ .sort((left, right) => compareText(left.pluginId, right.pluginId)
1022
+ || compareText(left.platform, right.platform)
1023
+ || compareText(left.scope, right.scope));
1024
+ const projected = rootEntity && !direct ? {
1025
+ ...primary,
1026
+ title: `${rootEntity.pluginId} · ${rootEntity.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${primary.category === 'artifactCollision' ? '输出冲突' : primary.title.split(' · ').at(-1) ?? primary.title}`,
1027
+ entity: { kind: 'plugin', id: rootEntity.pluginId },
1028
+ pluginId: rootEntity.pluginId,
1029
+ platform: rootEntity.platform,
1030
+ scope: rootEntity.scope,
1031
+ sourceId: rootEntity.pluginId.split('/', 1)[0],
1032
+ } : primary;
1033
+ return {
1034
+ ...projected,
1035
+ ...(rootEntity ? { rootEntity } : {}),
1036
+ ...(affectedTargets.length > 0 ? { affectedTargets } : {}),
1037
+ impact: [...new Set(ordered.flatMap((issue) => issue.impact))],
1038
+ technicalDetails: [...new Map(ordered.flatMap((issue) => issue.technicalDetails)
1039
+ .map((detail) => [`${detail.code}\0${detail.message}`, detail])).values()],
1040
+ };
1041
+ });
1042
+ }
1043
+ export function buildTuiViewModel(options) {
1044
+ const dependencyById = new Map((options.dependencyOverviews ?? [])
1045
+ .map((overview) => [overview.pluginId, overview]));
1046
+ const summaryById = new Map(options.pluginSummaries.map((summary) => [summary.pluginId, summary]));
1047
+ const sourceById = new Map(options.status.catalog.sources.map((source) => [source.id, source]));
1048
+ const targetsByPlugin = new Map();
1049
+ for (const target of options.status.targets) {
1050
+ targetsByPlugin.set(target.pluginId, [...(targetsByPlugin.get(target.pluginId) ?? []), target]);
1051
+ }
1052
+ const pluginIds = new Set([...summaryById.keys(), ...targetsByPlugin.keys()]);
1053
+ const plugins = [...pluginIds].map((pluginId) => {
1054
+ const summary = summaryById.get(pluginId);
1055
+ const targets = targetsByPlugin.get(pluginId) ?? [];
1056
+ const sourceId = targets[0]?.sourceId ?? pluginId.slice(0, pluginId.indexOf('/'));
1057
+ const placements = ['codex', 'claude'].flatMap((platform) => {
1058
+ const platformTargets = targets.filter((target) => target.platform === platform);
1059
+ return platformTargets.length > 0
1060
+ ? [projectPlatformPlacement(platform, platformTargets, options.targetRevisions)]
1061
+ : [];
1062
+ });
1063
+ const attention = placements.some((placement) => placement.state === 'scopeConflict'
1064
+ || (placement.state === 'installed'
1065
+ && (placement.health !== 'ready' || placement.blockingReason !== undefined)));
1066
+ const installed = placements.some((placement) => placement.state === 'installed' || placement.state === 'scopeConflict');
1067
+ const sourceUnavailable = options.sourceHealth?.get(sourceId)?.state === 'unavailable'
1068
+ || sourceById.get(sourceId)?.error !== undefined;
1069
+ const capabilityTargets = targets.filter((target) => target.reasons.some((reason) => reason.code === 'awCapabilityUnsupported'));
1070
+ const capabilityUnsupported = (summary?.missingCapabilities?.length ?? 0) > 0
1071
+ || capabilityTargets.length > 0;
1072
+ const capabilityRecovery = capabilityTargets.flatMap((target) => target.recoveryActions)
1073
+ .find((action) => action.command === 'manual')?.description;
1074
+ const unavailable = sourceUnavailable || capabilityUnsupported;
1075
+ return {
1076
+ pluginId,
1077
+ sourceId,
1078
+ displayName: summary?.displayName ?? summary?.pluginName ?? targets[0]?.pluginName ?? pluginId,
1079
+ description: summary?.description ?? '',
1080
+ ...(summary?.version ?? targets[0]?.version
1081
+ ? { version: summary?.version ?? targets[0]?.version }
1082
+ : {}),
1083
+ configFieldCount: summary?.configFieldCount
1084
+ ?? Object.keys(summary?.configSchema ?? {}).length,
1085
+ sourceLabel: sourceId,
1086
+ supportedPlatforms: summary?.supportedTargets
1087
+ ? ['codex', 'claude'].filter((platform) => summary.supportedTargets[platform].length > 0)
1088
+ : placements.map((placement) => placement.platform),
1089
+ ...(summary?.supportedTargets ? { supportedScopes: {
1090
+ codex: [...summary.supportedTargets.codex],
1091
+ claude: [...summary.supportedTargets.claude],
1092
+ } } : {}),
1093
+ installedPlacements: placements,
1094
+ aggregateStatus: unavailable ? 'unavailable' : attention ? 'needsAttention' : installed ? 'installed' : 'available',
1095
+ portableSkills: options.portablePluginIds?.includes(pluginId) ?? false,
1096
+ ...(summary?.missingCapabilities
1097
+ ? { missingCapabilities: summary.missingCapabilities }
1098
+ : {}),
1099
+ ...(capabilityUnsupported ? { capabilityUnsupported: true } : {}),
1100
+ ...(capabilityRecovery ? { capabilityRecovery } : {}),
1101
+ ...(sourceUnavailable ? { sourceUnavailable: true } : {}),
1102
+ ...(dependencyById.get(pluginId)
1103
+ ? { dependencySummary: dependencyById.get(pluginId).summary }
1104
+ : summary && (summary.dependencyTotalCount ?? 0) > 0
1105
+ ? { dependencySummary: {
1106
+ directCount: summary.dependencyDirectCount ?? 0,
1107
+ transitiveCount: Math.max(0, (summary.dependencyTotalCount ?? 0) - (summary.dependencyDirectCount ?? 0)),
1108
+ totalCount: summary.dependencyTotalCount ?? 0,
1109
+ readyCount: 0,
1110
+ missingCount: 0,
1111
+ issueCount: summary.dependencyIssueCount ?? 0,
1112
+ } }
1113
+ : {}),
1114
+ technicalComponents: targets.flatMap((target) => target.components.map((component) => ({
1115
+ platform: target.platform,
1116
+ scope: target.scope,
1117
+ key: component.key,
1118
+ state: component.state,
1119
+ ...(typeof component.metadata?.errorCode === 'string'
1120
+ ? { errorCode: component.metadata.errorCode }
1121
+ : {}),
1122
+ }))),
1123
+ };
1124
+ }).sort((left, right) => compareText(left.displayName, right.displayName)
1125
+ || compareText(left.sourceId, right.sourceId));
1126
+ const sourceTabs = options.status.catalog.sources.map((source) => ({
1127
+ id: source.id,
1128
+ label: source.id,
1129
+ count: plugins.filter((plugin) => plugin.sourceId === source.id).length,
1130
+ primary: source.primary,
1131
+ state: projectCatalogSourceState(source, options.sourceHealth?.get(source.id), options.catalogFreshness?.get(source.id), options.catalogGenerations?.get(source.id)),
1132
+ }));
1133
+ const sourceRootIds = new Set([...(options.sourceHealth?.values() ?? [])]
1134
+ .filter((health) => health.state === 'unavailable')
1135
+ .map((health) => health.sourceId));
1136
+ const allTargetIssues = targetIssues(options.status);
1137
+ const targetImpactCounts = new Map();
1138
+ for (const issue of allTargetIssues) {
1139
+ if (!issue.mergeEligible || !issue.sourceId || !sourceRootIds.has(issue.sourceId))
1140
+ continue;
1141
+ targetImpactCounts.set(issue.sourceId, (targetImpactCounts.get(issue.sourceId) ?? 0) + 1);
1142
+ }
1143
+ const sourceDetails = new Map((options.sourceDetails ?? []).map((detail) => [detail.id, detail]));
1144
+ const issueDrafts = [
1145
+ ...allTargetIssues.filter((issue) => !issue.mergeEligible
1146
+ || !issue.sourceId || !sourceRootIds.has(issue.sourceId)),
1147
+ ...statusIssues(options.status),
1148
+ ...configIssues(options.pluginSummaries),
1149
+ ...dependencyOverviewIssues(options.dependencyOverviews ?? [], options.pluginSummaries, options.status),
1150
+ ...[...(options.sourceHealth?.values() ?? [])].flatMap((health) => sourceIssue(health, targetImpactCounts.get(health.sourceId) ?? 0) ?? []),
1151
+ ];
1152
+ const stableIssueDrafts = collapseRootIssues(issueDrafts).sort((left, right) => issueGroupOrder[issueGroup(left)] - issueGroupOrder[issueGroup(right)]
1153
+ || issueReasonPriority(left) - issueReasonPriority(right)
1154
+ || compareText(primaryAttentionCode(left), primaryAttentionCode(right))
1155
+ || compareText(left.issueId, right.issueId));
1156
+ const issues = stableIssueDrafts.map((issue) => ({
1157
+ ...issue,
1158
+ group: issueGroup(issue),
1159
+ diagnostic: issueDiagnostic(issue, sourceDetails),
1160
+ }));
1161
+ const pluginsWithAttention = plugins.map((plugin) => {
1162
+ const primary = stableIssueDrafts.filter((issue) => issue.pluginId === plugin.pluginId
1163
+ || issue.dependencyPluginId === plugin.pluginId
1164
+ || issue.affectedTargets?.some((target) => target.pluginId === plugin.pluginId)
1165
+ || issue.entity.kind === 'source' && issue.sourceId === plugin.sourceId)
1166
+ .sort((left, right) => issueReasonPriority(left) - issueReasonPriority(right)
1167
+ || compareText(primaryAttentionCode(left), primaryAttentionCode(right))
1168
+ || compareText(left.issueId, right.issueId))[0];
1169
+ if (!primary)
1170
+ return plugin;
1171
+ return {
1172
+ ...plugin,
1173
+ primaryAttention: {
1174
+ severity: 'error',
1175
+ code: primaryAttentionCode(primary),
1176
+ message: primary.explanation,
1177
+ },
1178
+ };
1179
+ });
1180
+ return {
1181
+ plugins: pluginsWithAttention,
1182
+ sourceTabs,
1183
+ sourceDetails: (options.sourceDetails ?? []).map((detail) => ({
1184
+ ...detail,
1185
+ pluginCount: pluginsWithAttention.filter((plugin) => plugin.sourceId === detail.id).length,
1186
+ })),
1187
+ issues,
1188
+ dependencyOverviews: options.dependencyOverviews ?? [],
1189
+ home: {
1190
+ availablePlugins: pluginsWithAttention.filter((plugin) => plugin.aggregateStatus === 'available').length,
1191
+ installedPlugins: pluginsWithAttention.filter(hasInstalledPlacement).length,
1192
+ issueCount: issues.length,
1193
+ sourceCount: sourceTabs.length,
1194
+ unavailableSourceCount: options.status.catalog.sources.filter((source) => source.error
1195
+ || options.sourceHealth?.get(source.id)?.state === 'unavailable').length,
1196
+ catalogUpdateCount: sourceTabs.filter((source) => source.state === 'update').length,
1197
+ catalogRecoveryCount: sourceTabs.filter((source) => source.state === 'recovery'
1198
+ || source.state === 'error').length,
1199
+ catalogCheckingCount: sourceTabs.filter((source) => source.state === 'checking').length,
1200
+ },
1201
+ };
1202
+ }
1203
+ function displayConfigValue(options) {
1204
+ if (!options.configured)
1205
+ return options.inherited ? '继承' : '未设置';
1206
+ if (options.privateValue)
1207
+ return '已设置';
1208
+ if (options.field.type === 'object'
1209
+ && typeof options.value === 'object'
1210
+ && options.value !== null
1211
+ && !Array.isArray(options.value)) {
1212
+ const object = options.value;
1213
+ if (configObjectHasSensitiveChild(options.field)) {
1214
+ const count = Object.keys(object).length;
1215
+ return `已设置 · ${count === 0 ? '空对象' : `${count} 项`}`;
1216
+ }
1217
+ const preset = matchPluginConfigPreset(options.field, object);
1218
+ const keys = Object.keys(object).sort((left, right) => left.localeCompare(right, 'en'));
1219
+ const keySummary = keys.length === 0
1220
+ ? '空对象'
1221
+ : `${keys.length} 项${keys.length > 0 ? `(${keys.slice(0, 2).join('、')}${keys.length > 2 ? '…' : ''})` : ''}`;
1222
+ return preset ? `方案“${preset.title}” · ${keySummary}` : `自定义 · ${keySummary}`;
1223
+ }
1224
+ if (typeof options.value === 'string')
1225
+ return options.value;
1226
+ if (options.value === undefined || options.value === null)
1227
+ return '已设置';
1228
+ return String(options.value);
1229
+ }
1230
+ function configSourceLabel(source) {
1231
+ if (!source)
1232
+ return '未设置';
1233
+ return {
1234
+ default: '默认值',
1235
+ user: '个人默认',
1236
+ project: '当前项目',
1237
+ }[source];
1238
+ }
1239
+ function configEditorDefinition(field) {
1240
+ const definition = structuredClone(field);
1241
+ delete definition.default;
1242
+ return definition;
1243
+ }
1244
+ function configObjectChildChanges(field, before, after) {
1245
+ const fixed = Object.keys(field.properties ?? {});
1246
+ const summary = (property, value) => {
1247
+ if (value === undefined)
1248
+ return '未设置';
1249
+ const definition = field.properties?.[property]
1250
+ ?? (field.additionalProperties === false ? undefined : field.additionalProperties);
1251
+ if (field.sensitive || definition?.sensitive)
1252
+ return '已设置';
1253
+ if (typeof value === 'boolean')
1254
+ return value ? '开启' : '关闭';
1255
+ return String(value);
1256
+ };
1257
+ return [...new Set([...Object.keys(before), ...Object.keys(after ?? {})])]
1258
+ .sort((left, right) => {
1259
+ const leftIndex = fixed.indexOf(left);
1260
+ const rightIndex = fixed.indexOf(right);
1261
+ if (leftIndex >= 0 || rightIndex >= 0) {
1262
+ if (leftIndex < 0)
1263
+ return 1;
1264
+ if (rightIndex < 0)
1265
+ return -1;
1266
+ return leftIndex - rightIndex;
1267
+ }
1268
+ return left.localeCompare(right, 'en');
1269
+ })
1270
+ .filter((property) => before[property] !== after?.[property])
1271
+ .map((property) => {
1272
+ const definition = field.properties?.[property]
1273
+ ?? (field.additionalProperties === false ? undefined : field.additionalProperties);
1274
+ return {
1275
+ property,
1276
+ before: summary(property, before[property]),
1277
+ after: summary(property, after?.[property]),
1278
+ ...(field.sensitive || definition?.sensitive ? { private: true } : {}),
1279
+ };
1280
+ });
1281
+ }
1282
+ export function buildConfigGroups(options) {
1283
+ const entryByKey = new Map(options.read.fields.map((field) => [field.key, field]));
1284
+ const effectiveEntryByKey = new Map((options.effectiveRead ?? options.read).fields.map((field) => [field.key, field]));
1285
+ const effectivePage = options.read.scope === 'effective';
1286
+ const layerEntry = (layer, key) => options.layerReads?.[layer]?.fields.find((field) => field.key === key);
1287
+ const fieldModel = (key) => {
1288
+ const schema = options.schema.fields[key];
1289
+ const entry = entryByKey.get(key);
1290
+ const effectiveEntry = effectiveEntryByKey.get(key);
1291
+ const inherited = effectivePage
1292
+ ? false
1293
+ : entry?.storedSourceLayer === undefined;
1294
+ const configured = effectivePage
1295
+ ? entry?.sourceLayer !== undefined
1296
+ && entry.sourceLayer !== null
1297
+ && entry.effectiveValue !== undefined
1298
+ && entry.effectiveValue !== null
1299
+ && (entry.valueState === 'configured' || entry.valueState === 'default')
1300
+ : entry?.storedSourceLayer !== undefined;
1301
+ const privateValue = schema.sensitive === true;
1302
+ const choices = schema.choices;
1303
+ const selectedValue = effectivePage ? entry?.effectiveValue : entry?.storedValue;
1304
+ const selectedRawValue = effectivePage
1305
+ ? options.effectiveRawValues?.[key]
1306
+ : options.rawValues?.[key];
1307
+ const selectedStoredInvalid = !effectivePage
1308
+ && entry?.storedSourceLayer !== undefined
1309
+ && entry.storedValue === undefined;
1310
+ const invalidOverrideSourceCandidate = selectedStoredInvalid
1311
+ ? (effectivePage ? entry?.invalidOverride?.sourceLayer : options.read.scope)
1312
+ : entry?.invalidOverride?.sourceLayer;
1313
+ const invalidOverrideSource = invalidOverrideSourceCandidate === 'user'
1314
+ || invalidOverrideSourceCandidate === 'project'
1315
+ ? invalidOverrideSourceCandidate
1316
+ : undefined;
1317
+ const invalidOverride = invalidOverrideSource !== undefined;
1318
+ const invalidOverrideOwnedByLayer = !effectivePage
1319
+ && invalidOverrideSource === options.read.scope;
1320
+ const effectiveConfigured = effectiveEntry?.sourceLayer !== undefined
1321
+ && effectiveEntry.sourceLayer !== null
1322
+ && effectiveEntry.effectiveValue !== undefined
1323
+ && effectiveEntry.effectiveValue !== null
1324
+ && (effectiveEntry.valueState === 'configured' || effectiveEntry.valueState === 'default');
1325
+ const omittedLayer = options.read.scope === 'user'
1326
+ ? 'user'
1327
+ : 'project';
1328
+ const fallback = options.read.scope === 'user'
1329
+ ? undefined
1330
+ : ['project', 'user']
1331
+ .filter((layer) => layer !== omittedLayer)
1332
+ .map((layer) => ({ layer, entry: layerEntry(layer, key) }))
1333
+ .find((candidate) => candidate.entry?.storedSourceLayer !== undefined);
1334
+ const fallbackValue = fallback?.entry?.storedValue ?? schema.default;
1335
+ const fallbackRawValue = fallback
1336
+ ? options.rawLayerValues?.[fallback.layer]?.[key] ?? fallbackValue
1337
+ : schema.default;
1338
+ const fallbackConfigured = fallback !== undefined || schema.default !== undefined;
1339
+ const fallbackSource = fallback?.layer ?? (schema.default !== undefined ? 'default' : undefined);
1340
+ return {
1341
+ key,
1342
+ title: schema.title ?? key,
1343
+ ...(schema.description ? { description: schema.description } : {}),
1344
+ type: schema.type,
1345
+ definition: configEditorDefinition(schema),
1346
+ displayValue: selectedStoredInvalid ? '值无效' : displayConfigValue({
1347
+ field: schema,
1348
+ privateValue,
1349
+ inherited,
1350
+ configured,
1351
+ value: schema.type === 'object' ? selectedRawValue ?? selectedValue : selectedValue,
1352
+ }),
1353
+ required: schema.required === true,
1354
+ sensitive: schema.sensitive === true,
1355
+ writable: entry?.writable ?? effectivePage,
1356
+ dirty: options.dirtyKeys?.has(key) === true,
1357
+ inherited,
1358
+ configured,
1359
+ sourceLabel: effectivePage
1360
+ ? configSourceLabel(entry?.sourceLayer ?? null)
1361
+ : configured ? '本层已设置' : '继承',
1362
+ effectiveDisplayValue: displayConfigValue({
1363
+ field: schema,
1364
+ privateValue,
1365
+ inherited: false,
1366
+ configured: effectiveConfigured,
1367
+ value: schema.type === 'object'
1368
+ ? options.effectiveRawValues?.[key] ?? effectiveEntry?.effectiveValue
1369
+ : effectiveEntry?.effectiveValue,
1370
+ }),
1371
+ effectiveSourceLabel: configSourceLabel(effectiveEntry?.sourceLayer ?? null),
1372
+ ...(invalidOverride ? {
1373
+ invalidOverrideOwnedByLayer,
1374
+ invalidOverrideIssue: invalidOverrideOwnedByLayer
1375
+ ? schema.type === 'object'
1376
+ ? `字段“${schema.title ?? key}”在本层的对象值无效。请修改或删除此字段。`
1377
+ : `字段“${schema.title ?? key}”在本层的值无效。请修改或删除此字段。`
1378
+ : `字段“${schema.title ?? key}”在${configSourceLabel(invalidOverrideSource ?? null)}中的值无效。请切换到该设置层修改或删除此字段。`,
1379
+ } : {}),
1380
+ ...(!effectivePage && configured ? {
1381
+ fallbackDisplayValue: displayConfigValue({
1382
+ field: schema,
1383
+ privateValue,
1384
+ inherited: false,
1385
+ configured: fallbackConfigured,
1386
+ value: schema.type === 'object' ? fallbackRawValue : fallbackValue,
1387
+ }),
1388
+ fallbackSourceLabel: fallbackSource ? configSourceLabel(fallbackSource) : '未设置',
1389
+ ...(schema.type === 'object'
1390
+ && typeof (selectedRawValue ?? selectedValue) === 'object'
1391
+ && (selectedRawValue ?? selectedValue) !== null
1392
+ ? { fallbackObjectChanges: configObjectChildChanges(schema, (selectedRawValue ?? selectedValue), typeof fallbackRawValue === 'object' && fallbackRawValue !== null
1393
+ ? fallbackRawValue
1394
+ : undefined) }
1395
+ : {}),
1396
+ } : {}),
1397
+ ...(!privateValue && selectedValue !== undefined
1398
+ ? { value: selectedValue }
1399
+ : {}),
1400
+ ...(!privateValue && effectiveEntry?.effectiveValue !== undefined && effectiveEntry.effectiveValue !== null
1401
+ ? { effectiveValue: effectiveEntry.effectiveValue }
1402
+ : {}),
1403
+ ...(!privateValue && (effectivePage
1404
+ ? options.effectiveRawValues?.[key]
1405
+ : selectedRawValue ?? (schema.type === 'object' && !configured
1406
+ ? options.effectiveRawValues?.[key]
1407
+ : undefined)) !== undefined
1408
+ ? { draftValue: (effectivePage
1409
+ ? options.effectiveRawValues?.[key]
1410
+ : selectedRawValue ?? options.effectiveRawValues?.[key]) }
1411
+ : {}),
1412
+ ...(!privateValue && schema.default !== undefined ? { defaultValue: schema.default } : {}),
1413
+ ...(choices ? { choices: choices.presets } : {}),
1414
+ allowCustom: choices?.allowCustom ?? true,
1415
+ ...(!privateValue && !configObjectHasSensitiveChild(schema)
1416
+ && (selectedRawValue ?? selectedValue) !== undefined && (selectedRawValue ?? selectedValue) !== null
1417
+ && matchPluginConfigPreset(schema, (selectedRawValue ?? selectedValue))
1418
+ ? { matchedPresetId: matchPluginConfigPreset(schema, (selectedRawValue ?? selectedValue)).id }
1419
+ : {}),
1420
+ ...(schema.type === 'number' && schema.validation?.minimum !== undefined ? { min: schema.validation.minimum } : {}),
1421
+ ...(schema.type === 'number' && schema.validation?.maximum !== undefined ? { max: schema.validation.maximum } : {}),
1422
+ advanced: false,
1423
+ sharedNativeRender: options.sharedNativeRefreshKeys?.has(key) === true,
1424
+ };
1425
+ };
1426
+ const assigned = new Set();
1427
+ const groups = (options.schema.presentation?.groups ?? []).map((group) => {
1428
+ group.fields.forEach((key) => assigned.add(key));
1429
+ return {
1430
+ id: group.id,
1431
+ title: group.title,
1432
+ ...(group.description ? { description: group.description } : {}),
1433
+ advanced: group.advanced === true,
1434
+ fields: group.fields.map(fieldModel),
1435
+ };
1436
+ });
1437
+ const syntheticGroupId = (preferred) => {
1438
+ const existing = new Set(groups.map((group) => group.id));
1439
+ let id = preferred;
1440
+ let suffix = 2;
1441
+ while (existing.has(id)) {
1442
+ id = `${preferred}-${suffix}`;
1443
+ suffix += 1;
1444
+ }
1445
+ return id;
1446
+ };
1447
+ const remaining = Object.keys(options.schema.fields)
1448
+ .filter((key) => !assigned.has(key));
1449
+ if (!options.schema.presentation) {
1450
+ groups.push({
1451
+ id: 'general',
1452
+ title: '插件设置',
1453
+ advanced: false,
1454
+ fields: Object.keys(options.schema.fields)
1455
+ .map(fieldModel),
1456
+ });
1457
+ }
1458
+ else {
1459
+ const ordinary = remaining;
1460
+ const advanced = [];
1461
+ if (ordinary.length > 0) {
1462
+ groups.push({
1463
+ id: syntheticGroupId('general'),
1464
+ title: groups.length === 0 ? '插件设置' : '其他设置',
1465
+ advanced: false,
1466
+ fields: ordinary.map(fieldModel),
1467
+ });
1468
+ }
1469
+ if (advanced.length > 0) {
1470
+ groups.push({
1471
+ id: syntheticGroupId('advanced'),
1472
+ title: '高级设置',
1473
+ advanced: true,
1474
+ fields: advanced.map(fieldModel),
1475
+ });
1476
+ }
1477
+ }
1478
+ return groups;
1479
+ }
1480
+ export function buildConfigPage(options) {
1481
+ return {
1482
+ pluginId: options.pluginId,
1483
+ layer: { scope: options.read.scope },
1484
+ groups: buildConfigGroups(options),
1485
+ presets: [],
1486
+ storedCount: options.read.fields.filter((field) => field.storedSourceLayer !== undefined).length,
1487
+ };
1488
+ }
1489
+ export function configValuesEqual(left, right) {
1490
+ return left !== undefined && right !== undefined
1491
+ && stablePluginConfigStringify(left) === stablePluginConfigStringify(right);
1492
+ }
1493
+ //# sourceMappingURL=model.js.map