agents-inc 0.153.0 → 0.155.0

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 (218) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/chunk-2H7UWE2G.js +246 -0
  3. package/dist/chunk-2H7UWE2G.js.map +1 -0
  4. package/dist/{chunk-ZNDLUWWD.js → chunk-4A4L3YIW.js} +5 -5
  5. package/dist/chunk-4G2YHZIM.js +132 -0
  6. package/dist/chunk-4G2YHZIM.js.map +1 -0
  7. package/dist/{chunk-WDAO3RUY.js → chunk-5F2YR5XV.js} +3 -3
  8. package/dist/{chunk-JFAUQDZM.js → chunk-5OKLCVM4.js} +3 -3
  9. package/dist/{chunk-REKOWTIB.js → chunk-5QZAK6J7.js} +44 -10
  10. package/dist/chunk-5QZAK6J7.js.map +1 -0
  11. package/dist/{chunk-VECFAKM5.js → chunk-6RLV45HN.js} +10 -10
  12. package/dist/{chunk-VECFAKM5.js.map → chunk-6RLV45HN.js.map} +1 -1
  13. package/dist/{chunk-K7PJDWER.js → chunk-CLFHC2DK.js} +15 -106
  14. package/dist/chunk-CLFHC2DK.js.map +1 -0
  15. package/dist/chunk-D2CAV7MG.js +61 -0
  16. package/dist/chunk-D2CAV7MG.js.map +1 -0
  17. package/dist/{chunk-NXGMM5YN.js → chunk-F2AMBBIA.js} +6 -6
  18. package/dist/{chunk-NXGMM5YN.js.map → chunk-F2AMBBIA.js.map} +1 -1
  19. package/dist/{chunk-HEBPKK5L.js → chunk-F5T6TV4Z.js} +213 -92
  20. package/dist/chunk-F5T6TV4Z.js.map +1 -0
  21. package/dist/{chunk-K3O3YQYG.js → chunk-G47TDUK3.js} +2 -2
  22. package/dist/{chunk-U2DNAHFE.js → chunk-GS2NZ3GD.js} +8 -8
  23. package/dist/chunk-GS2NZ3GD.js.map +1 -0
  24. package/dist/{chunk-ORJ5Y222.js → chunk-H6UTKTLK.js} +176 -256
  25. package/dist/chunk-H6UTKTLK.js.map +1 -0
  26. package/dist/{chunk-M5HSTNYU.js → chunk-HG4JPXJT.js} +11 -29
  27. package/dist/chunk-HG4JPXJT.js.map +1 -0
  28. package/dist/{chunk-VGEBYCQZ.js → chunk-HTYH7CKN.js} +4 -15
  29. package/dist/chunk-HTYH7CKN.js.map +1 -0
  30. package/dist/{chunk-JC7DBPRD.js → chunk-HXKOIWLU.js} +2 -2
  31. package/dist/chunk-HXKOIWLU.js.map +1 -0
  32. package/dist/{chunk-NSJ2S7R5.js → chunk-ILUVL7WM.js} +2 -2
  33. package/dist/{chunk-R54KIGN2.js → chunk-IO5YBKHV.js} +13 -2
  34. package/dist/chunk-IO5YBKHV.js.map +1 -0
  35. package/dist/chunk-IXRZAHZF.js +53 -0
  36. package/dist/chunk-IXRZAHZF.js.map +1 -0
  37. package/dist/chunk-JCPANDNR.js +35 -0
  38. package/dist/chunk-JCPANDNR.js.map +1 -0
  39. package/dist/{chunk-R4SEU3DF.js → chunk-LJCNUP6M.js} +2 -2
  40. package/dist/{chunk-FRWKCE6R.js → chunk-MHRC3KRX.js} +5 -5
  41. package/dist/chunk-MHRC3KRX.js.map +1 -0
  42. package/dist/chunk-MO5FGLVS.js +142 -0
  43. package/dist/chunk-MO5FGLVS.js.map +1 -0
  44. package/dist/{chunk-Q5FLW4JG.js → chunk-OKH64JZE.js} +2 -2
  45. package/dist/{chunk-WG6V6VJV.js → chunk-PCC4LBKB.js} +2 -2
  46. package/dist/chunk-PMUABBPG.js +258 -0
  47. package/dist/chunk-PMUABBPG.js.map +1 -0
  48. package/dist/{chunk-EFU6P3B7.js → chunk-PNMM5HNX.js} +5 -5
  49. package/dist/{chunk-4VYALFQZ.js → chunk-QWVXOCXO.js} +6 -6
  50. package/dist/{chunk-35VOK7XE.js → chunk-RWOYPOMR.js} +4365 -4355
  51. package/dist/chunk-RWOYPOMR.js.map +1 -0
  52. package/dist/{chunk-IO4VEW5U.js → chunk-SY4X2LND.js} +4 -4
  53. package/dist/{chunk-XGMOXMS4.js → chunk-TBOVYLQJ.js} +2 -2
  54. package/dist/{chunk-BMGBA6HJ.js → chunk-TNGMF4UX.js} +20 -20
  55. package/dist/{chunk-BMGBA6HJ.js.map → chunk-TNGMF4UX.js.map} +1 -1
  56. package/dist/{chunk-TY6CAOL7.js → chunk-UMH2YZKG.js} +14 -5
  57. package/dist/chunk-UMH2YZKG.js.map +1 -0
  58. package/dist/{chunk-6CNRMCFM.js → chunk-VPASBA7P.js} +2 -2
  59. package/dist/{chunk-NXQAY5U7.js → chunk-WCAUUBHO.js} +5860 -5126
  60. package/dist/chunk-WCAUUBHO.js.map +1 -0
  61. package/dist/{chunk-V3ENMW7G.js → chunk-WFRTHH3A.js} +3 -3
  62. package/dist/{chunk-2HC2SNRP.js → chunk-WTJ3AY33.js} +1 -5
  63. package/dist/chunk-WTJ3AY33.js.map +1 -0
  64. package/dist/{chunk-F7Z5I6GU.js → chunk-WUQ3MTPF.js} +11 -5
  65. package/dist/{chunk-F7Z5I6GU.js.map → chunk-WUQ3MTPF.js.map} +1 -1
  66. package/dist/{chunk-U2YSGBHA.js → chunk-XAXJWXI4.js} +93 -43
  67. package/dist/chunk-XAXJWXI4.js.map +1 -0
  68. package/dist/{chunk-ACKC577F.js → chunk-Y5Y7XHVU.js} +4 -4
  69. package/dist/{chunk-X5XJ6WKO.js → chunk-YO2LTXB4.js} +107 -16
  70. package/dist/chunk-YO2LTXB4.js.map +1 -0
  71. package/dist/{chunk-FIHTAFST.js → chunk-ZUAZHDKP.js} +64 -65
  72. package/dist/chunk-ZUAZHDKP.js.map +1 -0
  73. package/dist/commands/build/marketplace.js +98 -120
  74. package/dist/commands/build/marketplace.js.map +1 -1
  75. package/dist/commands/build/plugins.js +8 -8
  76. package/dist/commands/compile.js +57 -24
  77. package/dist/commands/compile.js.map +1 -1
  78. package/dist/commands/doctor.js +220 -79
  79. package/dist/commands/doctor.js.map +1 -1
  80. package/dist/commands/edit.js +608 -100
  81. package/dist/commands/edit.js.map +1 -1
  82. package/dist/commands/eject.js +26 -21
  83. package/dist/commands/eject.js.map +1 -1
  84. package/dist/commands/init.js +41 -39
  85. package/dist/commands/list.js +11 -11
  86. package/dist/commands/list.js.map +1 -1
  87. package/dist/commands/new/marketplace.js +243 -0
  88. package/dist/commands/new/marketplace.js.map +1 -0
  89. package/dist/commands/search.js +34 -24
  90. package/dist/commands/search.js.map +1 -1
  91. package/dist/commands/share.js +67 -0
  92. package/dist/commands/share.js.map +1 -0
  93. package/dist/commands/uninstall.js +234 -196
  94. package/dist/commands/uninstall.js.map +1 -1
  95. package/dist/commands/update.js +9 -9
  96. package/dist/commands/update.js.map +1 -1
  97. package/dist/components/common/prompt-confirm.js +1 -1
  98. package/dist/components/common/removal-plan-confirm.js +10 -0
  99. package/dist/components/common/select-list.js +2 -2
  100. package/dist/components/wizard/category-grid.js +5 -5
  101. package/dist/components/wizard/checkbox-grid.js +5 -5
  102. package/dist/components/wizard/domain-selection.js +11 -11
  103. package/dist/components/wizard/run-wizard-session.js +29 -28
  104. package/dist/components/wizard/scroll-affordance.js +2 -2
  105. package/dist/components/wizard/skill-agent-summary.js +6 -6
  106. package/dist/components/wizard/source-grid.js +6 -6
  107. package/dist/components/wizard/stack-selection.js +8 -8
  108. package/dist/components/wizard/step-agents.js +10 -11
  109. package/dist/components/wizard/step-build.js +9 -9
  110. package/dist/components/wizard/step-confirm.js +10 -10
  111. package/dist/components/wizard/step-sources.js +10 -10
  112. package/dist/components/wizard/step-stack.js +9 -9
  113. package/dist/components/wizard/summary-panel.js +9 -9
  114. package/dist/components/wizard/toast.js +2 -2
  115. package/dist/components/wizard/wizard-layout.js +14 -14
  116. package/dist/components/wizard/wizard-tabs.js +2 -2
  117. package/dist/components/wizard/wizard.js +27 -27
  118. package/dist/copy-local-skills-NSUTBVLJ.js +14 -0
  119. package/dist/hooks/init.js +42 -62
  120. package/dist/hooks/init.js.map +1 -1
  121. package/dist/load-agent-defs-X4E57I2U.js +15 -0
  122. package/dist/{loader-4U7UCE2Y.js → loader-G6BFG2VA.js} +3 -3
  123. package/dist/recompile-project-agents-JE4MM72I.js +20 -0
  124. package/dist/{source-loader-ZNSYJJCI.js → source-loader-3DL3NYUX.js} +7 -5
  125. package/dist/source-loader-3DL3NYUX.js.map +1 -0
  126. package/dist/src/agents/developer/ai-developer/critical-reminders.md +1 -1
  127. package/dist/src/agents/developer/ai-developer/critical-requirements.md +1 -1
  128. package/dist/src/agents/developer/ai-developer/identity.md +1 -1
  129. package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
  130. package/dist/src/agents/developer/api-developer/identity.md +1 -1
  131. package/dist/src/agents/developer/cli-developer/identity.md +1 -1
  132. package/dist/src/agents/developer/web-developer/identity.md +1 -1
  133. package/dist/src/agents/meta/codex-keeper/identity.md +1 -1
  134. package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
  135. package/dist/src/agents/meta/skill-summoner/identity.md +1 -1
  136. package/dist/src/agents/researcher/ai-researcher/identity.md +1 -1
  137. package/dist/src/agents/researcher/api-researcher/identity.md +1 -1
  138. package/dist/src/agents/researcher/cli-researcher/identity.md +1 -1
  139. package/dist/src/agents/researcher/web-researcher/identity.md +1 -1
  140. package/dist/src/agents/reviewer/reviewer/playbook.md +1 -1
  141. package/dist/src/agents/tester/ai-tester/identity.md +1 -1
  142. package/dist/src/agents/tester/api-tester/critical-reminders.md +1 -1
  143. package/dist/src/agents/tester/api-tester/critical-requirements.md +1 -1
  144. package/dist/src/agents/tester/api-tester/identity.md +2 -2
  145. package/dist/src/agents/tester/cli-tester/identity.md +1 -1
  146. package/dist/src/agents/tester/web-tester/identity.md +3 -3
  147. package/dist/stores/wizard-store.js +7 -5
  148. package/package.json +10 -7
  149. package/src/agents/developer/ai-developer/critical-reminders.md +1 -1
  150. package/src/agents/developer/ai-developer/critical-requirements.md +1 -1
  151. package/src/agents/developer/ai-developer/identity.md +1 -1
  152. package/src/agents/developer/ai-developer/playbook.md +1 -1
  153. package/src/agents/developer/api-developer/identity.md +1 -1
  154. package/src/agents/developer/cli-developer/identity.md +1 -1
  155. package/src/agents/developer/web-developer/identity.md +1 -1
  156. package/src/agents/meta/codex-keeper/identity.md +1 -1
  157. package/src/agents/meta/convention-keeper/identity.md +1 -1
  158. package/src/agents/meta/skill-summoner/identity.md +1 -1
  159. package/src/agents/researcher/ai-researcher/identity.md +1 -1
  160. package/src/agents/researcher/api-researcher/identity.md +1 -1
  161. package/src/agents/researcher/cli-researcher/identity.md +1 -1
  162. package/src/agents/researcher/web-researcher/identity.md +1 -1
  163. package/src/agents/reviewer/reviewer/playbook.md +1 -1
  164. package/src/agents/tester/ai-tester/identity.md +1 -1
  165. package/src/agents/tester/api-tester/critical-reminders.md +1 -1
  166. package/src/agents/tester/api-tester/critical-requirements.md +1 -1
  167. package/src/agents/tester/api-tester/identity.md +2 -2
  168. package/src/agents/tester/cli-tester/identity.md +1 -1
  169. package/src/agents/tester/web-tester/identity.md +3 -3
  170. package/src/schemas/custom-metadata.schema.json +3 -0
  171. package/src/schemas/metadata.schema.json +3 -0
  172. package/src/schemas/plugin.schema.json +3 -0
  173. package/src/schemas/project-config.schema.json +4 -8
  174. package/src/schemas/project-source-config.schema.json +2 -2
  175. package/dist/chunk-2HC2SNRP.js.map +0 -1
  176. package/dist/chunk-35VOK7XE.js.map +0 -1
  177. package/dist/chunk-FIHTAFST.js.map +0 -1
  178. package/dist/chunk-FRWKCE6R.js.map +0 -1
  179. package/dist/chunk-HEBPKK5L.js.map +0 -1
  180. package/dist/chunk-JC7DBPRD.js.map +0 -1
  181. package/dist/chunk-K7PJDWER.js.map +0 -1
  182. package/dist/chunk-KET3EVGX.js +0 -41
  183. package/dist/chunk-KET3EVGX.js.map +0 -1
  184. package/dist/chunk-M5HSTNYU.js.map +0 -1
  185. package/dist/chunk-NXQAY5U7.js.map +0 -1
  186. package/dist/chunk-OJJLYHM3.js +0 -34
  187. package/dist/chunk-OJJLYHM3.js.map +0 -1
  188. package/dist/chunk-ORJ5Y222.js.map +0 -1
  189. package/dist/chunk-R54KIGN2.js.map +0 -1
  190. package/dist/chunk-REKOWTIB.js.map +0 -1
  191. package/dist/chunk-TY6CAOL7.js.map +0 -1
  192. package/dist/chunk-U2DNAHFE.js.map +0 -1
  193. package/dist/chunk-U2YSGBHA.js.map +0 -1
  194. package/dist/chunk-VGEBYCQZ.js.map +0 -1
  195. package/dist/chunk-X5XJ6WKO.js.map +0 -1
  196. package/dist/copy-local-skills-KF2RAVD3.js +0 -14
  197. package/dist/load-agent-defs-DGXGBU3Q.js +0 -15
  198. package/dist/recompile-project-agents-CJVBAWDJ.js +0 -20
  199. /package/dist/{chunk-ZNDLUWWD.js.map → chunk-4A4L3YIW.js.map} +0 -0
  200. /package/dist/{chunk-WDAO3RUY.js.map → chunk-5F2YR5XV.js.map} +0 -0
  201. /package/dist/{chunk-JFAUQDZM.js.map → chunk-5OKLCVM4.js.map} +0 -0
  202. /package/dist/{chunk-K3O3YQYG.js.map → chunk-G47TDUK3.js.map} +0 -0
  203. /package/dist/{chunk-NSJ2S7R5.js.map → chunk-ILUVL7WM.js.map} +0 -0
  204. /package/dist/{chunk-R4SEU3DF.js.map → chunk-LJCNUP6M.js.map} +0 -0
  205. /package/dist/{chunk-Q5FLW4JG.js.map → chunk-OKH64JZE.js.map} +0 -0
  206. /package/dist/{chunk-WG6V6VJV.js.map → chunk-PCC4LBKB.js.map} +0 -0
  207. /package/dist/{chunk-EFU6P3B7.js.map → chunk-PNMM5HNX.js.map} +0 -0
  208. /package/dist/{chunk-4VYALFQZ.js.map → chunk-QWVXOCXO.js.map} +0 -0
  209. /package/dist/{chunk-IO4VEW5U.js.map → chunk-SY4X2LND.js.map} +0 -0
  210. /package/dist/{chunk-XGMOXMS4.js.map → chunk-TBOVYLQJ.js.map} +0 -0
  211. /package/dist/{chunk-6CNRMCFM.js.map → chunk-VPASBA7P.js.map} +0 -0
  212. /package/dist/{chunk-V3ENMW7G.js.map → chunk-WFRTHH3A.js.map} +0 -0
  213. /package/dist/{chunk-ACKC577F.js.map → chunk-Y5Y7XHVU.js.map} +0 -0
  214. /package/dist/{copy-local-skills-KF2RAVD3.js.map → components/common/removal-plan-confirm.js.map} +0 -0
  215. /package/dist/{load-agent-defs-DGXGBU3Q.js.map → copy-local-skills-NSUTBVLJ.js.map} +0 -0
  216. /package/dist/{loader-4U7UCE2Y.js.map → load-agent-defs-X4E57I2U.js.map} +0 -0
  217. /package/dist/{recompile-project-agents-CJVBAWDJ.js.map → loader-G6BFG2VA.js.map} +0 -0
  218. /package/dist/{source-loader-ZNSYJJCI.js.map → recompile-project-agents-JE4MM72I.js.map} +0 -0
@@ -1,98 +1,136 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- Spinner
4
- } from "../chunk-ZBPEFQ4G.js";
3
+ publishSeedConfig,
4
+ seedPayloadForInstallation,
5
+ skillsAuthoredHere
6
+ } from "../chunk-2H7UWE2G.js";
7
+ import {
8
+ RemovalPlanConfirm
9
+ } from "../chunk-D2CAV7MG.js";
10
+ import "../chunk-OZXAJNLA.js";
11
+ import {
12
+ seedToWizardResult
13
+ } from "../chunk-MO5FGLVS.js";
5
14
  import {
6
15
  runWizardSession
7
- } from "../chunk-KET3EVGX.js";
8
- import "../chunk-BMGBA6HJ.js";
9
- import "../chunk-M5HSTNYU.js";
10
- import "../chunk-NSJ2S7R5.js";
11
- import "../chunk-JC7DBPRD.js";
12
- import "../chunk-K7PJDWER.js";
13
- import "../chunk-WDAO3RUY.js";
14
- import "../chunk-R4SEU3DF.js";
15
- import "../chunk-VECFAKM5.js";
16
- import "../chunk-VGEBYCQZ.js";
17
- import "../chunk-U2DNAHFE.js";
18
- import "../chunk-WG6V6VJV.js";
19
- import "../chunk-EFU6P3B7.js";
16
+ } from "../chunk-IXRZAHZF.js";
17
+ import "../chunk-TNGMF4UX.js";
18
+ import "../chunk-LJCNUP6M.js";
19
+ import "../chunk-HTYH7CKN.js";
20
+ import "../chunk-PCC4LBKB.js";
21
+ import "../chunk-HG4JPXJT.js";
22
+ import "../chunk-6RLV45HN.js";
23
+ import "../chunk-ILUVL7WM.js";
24
+ import "../chunk-HXKOIWLU.js";
25
+ import "../chunk-QWVXOCXO.js";
26
+ import "../chunk-GS2NZ3GD.js";
27
+ import "../chunk-VPASBA7P.js";
28
+ import "../chunk-PNMM5HNX.js";
29
+ import "../chunk-CLFHC2DK.js";
30
+ import "../chunk-5OKLCVM4.js";
31
+ import "../chunk-5F2YR5XV.js";
20
32
  import "../chunk-TSIU7DME.js";
21
33
  import "../chunk-XVAQG2CV.js";
22
- import "../chunk-ZNDLUWWD.js";
34
+ import {
35
+ Spinner
36
+ } from "../chunk-ZBPEFQ4G.js";
37
+ import "../chunk-4A4L3YIW.js";
23
38
  import "../chunk-J27W6TXS.js";
24
- import "../chunk-4VYALFQZ.js";
25
- import "../chunk-JFAUQDZM.js";
26
- import "../chunk-IO4VEW5U.js";
27
- import "../chunk-V3ENMW7G.js";
28
- import "../chunk-2HC2SNRP.js";
29
- import "../chunk-Q5FLW4JG.js";
30
- import "../chunk-6CNRMCFM.js";
39
+ import "../chunk-SY4X2LND.js";
40
+ import "../chunk-WFRTHH3A.js";
41
+ import "../chunk-WTJ3AY33.js";
42
+ import "../chunk-OKH64JZE.js";
43
+ import {
44
+ fetchSeedConfig,
45
+ registerExternalSkills,
46
+ writeExternalSkills
47
+ } from "../chunk-PMUABBPG.js";
48
+ import {
49
+ promptConfirm
50
+ } from "../chunk-JCPANDNR.js";
31
51
  import {
32
52
  compileAgentsAllScopes,
33
53
  detectProject,
34
54
  loadSource,
35
55
  writeProjectConfig
36
- } from "../chunk-F7Z5I6GU.js";
56
+ } from "../chunk-WUQ3MTPF.js";
37
57
  import {
38
58
  discoverInstalledSkills,
59
+ removeCompiledAgents,
39
60
  uninstallPluginSkills
40
- } from "../chunk-REKOWTIB.js";
41
- import {
42
- copyLocalSkills
43
- } from "../chunk-NXGMM5YN.js";
61
+ } from "../chunk-5QZAK6J7.js";
44
62
  import {
45
63
  loadAgentDefs
46
- } from "../chunk-FRWKCE6R.js";
47
- import "../chunk-FIHTAFST.js";
48
- import "../chunk-ACKC577F.js";
64
+ } from "../chunk-MHRC3KRX.js";
65
+ import {
66
+ copyLocalSkills
67
+ } from "../chunk-F2AMBBIA.js";
68
+ import "../chunk-ZUAZHDKP.js";
69
+ import "../chunk-Y5Y7XHVU.js";
49
70
  import {
50
71
  render
51
72
  } from "../chunk-JFLVEFFP.js";
52
73
  import {
53
- formatScopeTag
54
- } from "../chunk-HEBPKK5L.js";
74
+ formatScopeTag,
75
+ orderDomains
76
+ } from "../chunk-F5T6TV4Z.js";
55
77
  import {
56
78
  BaseCommand,
57
79
  EXIT_CODES
58
- } from "../chunk-X5XJ6WKO.js";
59
- import "../chunk-TY6CAOL7.js";
60
- import "../chunk-K3O3YQYG.js";
80
+ } from "../chunk-YO2LTXB4.js";
81
+ import "../chunk-UMH2YZKG.js";
82
+ import "../chunk-G47TDUK3.js";
61
83
  import {
62
84
  ERROR_MESSAGES,
63
85
  INFO_MESSAGES,
64
86
  INSTALL_MODE_DESCRIPTIONS,
87
+ SHARED_CONFIG_APPLY,
88
+ SHARED_CONFIG_ONE_DIRECTION,
65
89
  STATUS_MESSAGES,
66
90
  activeAgentNames,
67
91
  activeAgentScopeMap,
68
92
  applyMigratedGlobalSources,
93
+ authoredHereKept,
69
94
  buildMarketplacePluginRef,
95
+ carriedSkillsWritten,
70
96
  claudePluginInstall,
71
97
  claudePluginUninstall,
72
98
  deleteLocalSkill,
73
99
  detectMigrations,
74
100
  discoverAllPluginSkills,
101
+ ejectCopyFailureError,
102
+ execCommand,
75
103
  executeMigration,
104
+ globallyInstalledRemoved,
76
105
  installBaseDir,
77
106
  isActiveAt,
78
107
  isHomeDirectory,
108
+ loadProjectConfigFromDir,
109
+ localSkillsCopied,
79
110
  migrateLocalSkillScope,
80
111
  mutateGlobal,
112
+ normalizeProjectPath,
81
113
  recompileSummary,
82
114
  resolveInstallPaths,
115
+ sharedConfigDestinations,
116
+ sharedConfigNeedsTerminal,
117
+ skippedUnknownAgents,
118
+ skippedUnknownSkills,
83
119
  toClaudePluginScope,
120
+ unplaceableKept,
84
121
  unresolvedSkillRemovalReasons
85
- } from "../chunk-NXQAY5U7.js";
122
+ } from "../chunk-WCAUUBHO.js";
86
123
  import {
87
- getErrorMessage,
88
- remove
89
- } from "../chunk-U2YSGBHA.js";
124
+ getErrorMessage
125
+ } from "../chunk-XAXJWXI4.js";
90
126
  import {
127
+ getCategoryDomain,
91
128
  getSkillById,
92
129
  getSkillDisplayName,
93
130
  matrix
94
- } from "../chunk-35VOK7XE.js";
131
+ } from "../chunk-RWOYPOMR.js";
95
132
  import {
133
+ typedEntries,
96
134
  typedKeys
97
135
  } from "../chunk-VASLW636.js";
98
136
  import {
@@ -100,15 +138,121 @@ import {
100
138
  CLI_INVOKE_COMMAND,
101
139
  EDIT_PROJECT_SETUP_FLAG,
102
140
  EJECT_SOURCE,
141
+ editorConfigUrl,
103
142
  formatSourceDisplayName
104
- } from "../chunk-R54KIGN2.js";
143
+ } from "../chunk-IO5YBKHV.js";
105
144
  import "../chunk-VZRO7RYT.js";
106
145
 
107
146
  // src/cli/commands/edit.tsx
147
+ import os from "os";
108
148
  import path from "path";
109
149
  import chalk from "chalk";
110
150
  import { Flags } from "@oclif/core";
111
- import { difference, indexBy } from "remeda";
151
+ import { difference, indexBy, partition } from "remeda";
152
+
153
+ // src/cli/lib/seed/seed-apply.ts
154
+ var NOTHING_KEPT = {
155
+ authoredSkillIds: [],
156
+ unplaceableSkillIds: []
157
+ };
158
+ function reconcileSharedConfig(options) {
159
+ const { decoded, installed } = options;
160
+ if (!installed) return { result: decoded, kept: NOTHING_KEPT };
161
+ const keptSkills = skillsToKeep(options, installed);
162
+ if (keptSkills.length === 0) return { result: decoded, kept: NOTHING_KEPT };
163
+ return {
164
+ result: withKeptEntries(decoded, installed, keptSkills),
165
+ kept: describeKept(options, keptSkills)
166
+ };
167
+ }
168
+ function skillsToKeep(options, installed) {
169
+ const named = new Set(options.decoded.skills.map((skill) => skill.id));
170
+ return installed.skills.filter(
171
+ (skill) => !skill.excluded && !named.has(skill.id) && mayNotRemove(skill, options)
172
+ );
173
+ }
174
+ function mayNotRemove(skill, options) {
175
+ return options.authoredHere.has(skill.id) || options.unplaceable.has(skill.id);
176
+ }
177
+ function describeKept(options, keptSkills) {
178
+ const idsKeptFor = (reason) => keptSkills.filter((skill) => reasonKept(skill, options) === reason).map((skill) => skill.id);
179
+ return {
180
+ authoredSkillIds: idsKeptFor("authored"),
181
+ unplaceableSkillIds: idsKeptFor("unplaceable")
182
+ };
183
+ }
184
+ function reasonKept(skill, options) {
185
+ return options.authoredHere.has(skill.id) ? "authored" : "unplaceable";
186
+ }
187
+ function withKeptEntries(decoded, installed, keptSkills) {
188
+ return {
189
+ ...decoded,
190
+ skills: [...decoded.skills, ...keptSkills],
191
+ selectedDomains: withKeptDomains(decoded.selectedDomains, keptSkills),
192
+ ...decoded.assignedStack !== void 0 && {
193
+ assignedStack: withKeptStackRows(decoded.assignedStack, installed.stack, {
194
+ keptSkillIds: new Set(keptSkills.map((skill) => skill.id)),
195
+ survivingAgents: new Set(decoded.selectedAgents)
196
+ })
197
+ }
198
+ };
199
+ }
200
+ function withKeptDomains(selected, keptSkills) {
201
+ const keptDomains = keptSkills.flatMap((skill) => domainOfSkill(skill.id) ?? []);
202
+ const missing = keptDomains.filter((domain) => !selected.includes(domain));
203
+ if (missing.length === 0) return selected;
204
+ return orderDomains([...selected, ...new Set(missing)]);
205
+ }
206
+ function domainOfSkill(skillId) {
207
+ const category = matrix.skills[skillId]?.category;
208
+ return category === void 0 ? void 0 : getCategoryDomain(category);
209
+ }
210
+ function withKeptStackRows(assigned, installedStack, filter) {
211
+ if (!installedStack) return assigned;
212
+ const carried = { ...assigned };
213
+ for (const [agent, agentStack] of typedEntries(installedStack)) {
214
+ if (!filter.survivingAgents.has(agent)) continue;
215
+ const rows = keptRowsFor(agentStack, filter.keptSkillIds);
216
+ if (typedKeys(rows).length === 0) continue;
217
+ carried[agent] = { ...carried[agent], ...rows };
218
+ }
219
+ return carried;
220
+ }
221
+ function keptRowsFor(agentStack, keptSkillIds) {
222
+ const rows = {};
223
+ for (const [category, assignments] of typedEntries(agentStack)) {
224
+ const carried = assignments.filter((assignment) => keptSkillIds.has(assignment.id));
225
+ if (carried.length > 0) rows[category] = carried;
226
+ }
227
+ return rows;
228
+ }
229
+
230
+ // src/cli/utils/open-url.ts
231
+ function browserOpenerCommand(platform, url) {
232
+ if (platform === "darwin") return { command: "open", args: [url] };
233
+ if (platform === "win32") return { command: "cmd", args: ["/c", "start", "", url] };
234
+ return { command: "xdg-open", args: [url] };
235
+ }
236
+ function openerRefusedMessage(command, exitCode) {
237
+ return `Could not open your browser \u2014 '${command}' exited ${exitCode}.`;
238
+ }
239
+ function openerUnavailableMessage(command, reason) {
240
+ return `Could not open your browser \u2014 '${command}' could not be run: ${reason}`;
241
+ }
242
+ async function openUrl(url) {
243
+ const { command, args } = browserOpenerCommand(process.platform, url);
244
+ try {
245
+ const result = await execCommand(command, args);
246
+ if (result.exitCode !== 0) {
247
+ return { ok: false, error: openerRefusedMessage(command, result.exitCode) };
248
+ }
249
+ return { ok: true };
250
+ } catch (error) {
251
+ return { ok: false, error: openerUnavailableMessage(command, getErrorMessage(error)) };
252
+ }
253
+ }
254
+
255
+ // src/cli/commands/edit.tsx
112
256
  import { jsx } from "react/jsx-runtime";
113
257
  var RECOMPILE_SUBJECT = "agents";
114
258
  function formatDualScopeTransition(displayName, to) {
@@ -140,6 +284,71 @@ function scopeArrow(change) {
140
284
  function loadedSourceLabel(sourceResult) {
141
285
  return sourceResult.marketplace ?? sourceResult.sourceConfig.source;
142
286
  }
287
+ function globalScopePlan(changes, kept) {
288
+ const sections = removalSections(changes.removedSkills, changes.removedAgents);
289
+ return { heading: planHeading(sections), sections, statements: kept };
290
+ }
291
+ function projectScopePlan(changes, kept, installed, otherProjects) {
292
+ const { here, global } = splitRemovalsByScope(changes, installed);
293
+ const sections = [
294
+ ...removalSections(here.skills, here.agents),
295
+ ...globalRemovalSections(global.skills, global.agents)
296
+ ];
297
+ return {
298
+ heading: planHeading(sections),
299
+ sections,
300
+ statements: [...globalReachStatement(global, otherProjects), ...kept]
301
+ };
302
+ }
303
+ function splitRemovalsByScope(changes, installed) {
304
+ const isGlobalSkill = (id) => installed.skills.some((skill) => skill.id === id && isActiveAt(skill, "global"));
305
+ const isGlobalAgent = (name) => installed.agents.some((agent) => agent.name === name && isActiveAt(agent, "global"));
306
+ const [globalSkills, projectSkills] = partition(changes.removedSkills, isGlobalSkill);
307
+ const [globalAgents, projectAgents] = partition(changes.removedAgents, isGlobalAgent);
308
+ return {
309
+ here: { skills: projectSkills, agents: projectAgents },
310
+ global: { skills: globalSkills, agents: globalAgents }
311
+ };
312
+ }
313
+ function removalSections(skills, agents) {
314
+ return [
315
+ { label: SHARED_CONFIG_APPLY.SKILLS_HEADING, items: skills.map(skillLabel) },
316
+ { label: SHARED_CONFIG_APPLY.AGENTS_HEADING, items: [...agents] }
317
+ ].filter((section) => section.items.length > 0);
318
+ }
319
+ function globalRemovalSections(skills, agents) {
320
+ return [
321
+ { label: SHARED_CONFIG_APPLY.GLOBAL_SKILLS_HEADING, items: skills.map(skillLabel) },
322
+ { label: SHARED_CONFIG_APPLY.GLOBAL_AGENTS_HEADING, items: [...agents] }
323
+ ].filter((section) => section.items.length > 0);
324
+ }
325
+ function globalReachStatement(global, otherProjects) {
326
+ if (global.skills.length === 0 && global.agents.length === 0) return [];
327
+ return [globallyInstalledRemoved(otherProjects)];
328
+ }
329
+ function planHeading(sections) {
330
+ if (sections.length === 0) return SHARED_CONFIG_APPLY.NOTHING_REMOVED;
331
+ return SHARED_CONFIG_APPLY.PREVIEW_HEADING;
332
+ }
333
+ function skillLabel(skillId) {
334
+ const displayName = getSkillDisplayName(skillId);
335
+ return displayName === skillId ? skillId : `${displayName} (${skillId})`;
336
+ }
337
+ function keptStatements(kept) {
338
+ return [...authorshipStatement(kept), ...catalogueStatement(kept)];
339
+ }
340
+ function authorshipStatement(kept) {
341
+ if (kept.authoredSkillIds.length === 0) return [];
342
+ return [authoredHereKept(kept.authoredSkillIds)];
343
+ }
344
+ function catalogueStatement(kept) {
345
+ if (kept.unplaceableSkillIds.length === 0) return [];
346
+ return [unplaceableKept(kept.unplaceableSkillIds)];
347
+ }
348
+ function applyAuthority(producer, cwd) {
349
+ if (isHomeDirectory(cwd)) return "all";
350
+ return producer === "shared" ? "all" : "owned";
351
+ }
143
352
  var Edit = class _Edit extends BaseCommand {
144
353
  static summary = "Edit skills in the plugin";
145
354
  static description = "Modify the currently installed skills via interactive wizard";
@@ -147,9 +356,25 @@ var Edit = class _Edit extends BaseCommand {
147
356
  {
148
357
  description: "Open the edit wizard",
149
358
  command: "<%= config.bin %> <%= command.id %>"
359
+ },
360
+ {
361
+ description: "Open this installation in the editor instead of the wizard",
362
+ command: "<%= config.bin %> <%= command.id %> --ui"
363
+ },
364
+ {
365
+ description: "Apply a configuration built in the editor, by its id",
366
+ command: "<%= config.bin %> <%= command.id %> --from <id>"
150
367
  }
151
368
  ];
152
369
  static flags = {
370
+ ui: Flags.boolean({
371
+ description: "Edit this installation in the browser at agentsinc.sh instead of the wizard",
372
+ default: false
373
+ }),
374
+ from: Flags.string({
375
+ description: "Apply a configuration shared from agentsinc.sh by its id, removing whatever it leaves out",
376
+ helpValue: "<id>"
377
+ }),
153
378
  [EDIT_PROJECT_SETUP_FLAG]: Flags.boolean({
154
379
  description: "Internal: this run continues an `init` project setup",
155
380
  default: false,
@@ -160,19 +385,20 @@ var Edit = class _Edit extends BaseCommand {
160
385
  const { flags } = await this.parse(_Edit);
161
386
  const cwd = process.cwd();
162
387
  await this.ensureConfigReadable(cwd);
163
- const { unmount, clear: clearSpinner } = render(
164
- /* @__PURE__ */ jsx(Spinner, { label: STATUS_MESSAGES.LOADING_SKILLS })
165
- );
166
- const context = await this.loadContext();
167
- clearSpinner();
168
- unmount();
388
+ if (flags.ui && flags.from !== void 0) {
389
+ this.error(SHARED_CONFIG_ONE_DIRECTION, { exit: EXIT_CODES.ERROR });
390
+ }
391
+ if (flags.ui) return this.openInEditor(cwd);
392
+ const payload = flags.from === void 0 ? null : await this.fetchSharedConfigOrFail(flags.from);
393
+ const context = await this.loadContextUnderSpinner();
169
394
  await this.ensureSavedSkillsReadable(
170
395
  context.projectConfig?.skills ?? [],
171
396
  context.sourceResult.matrix,
172
397
  context.projectDir
173
398
  );
174
- const result = await this.runEditWizard(context, cwd);
175
- if (!result) this.error("Cancelled", { exit: EXIT_CODES.CANCELLED });
399
+ const selection = payload ? await this.selectionFromSharedConfig(payload, context, cwd) : await this.selectionFromWizard(context, cwd);
400
+ if (!selection) this.error("Cancelled", { exit: EXIT_CODES.CANCELLED });
401
+ const { result } = selection;
176
402
  this.reportValidationErrors(result.validation);
177
403
  const activeNewSkills = result.skills.filter((s) => !s.excluded);
178
404
  const activeNewAgents = result.agentConfigs.filter((a) => !a.excluded);
@@ -191,10 +417,20 @@ var Edit = class _Edit extends BaseCommand {
191
417
  oldAgents: context.projectConfig?.agents ?? []
192
418
  });
193
419
  const isProjectSetup = flags[EDIT_PROJECT_SETUP_FLAG] && !isHomeDirectory(cwd);
420
+ if (selection.producer === "shared") {
421
+ await this.confirmSharedConfigOrCancel(
422
+ changes,
423
+ selection.kept,
424
+ { skills: activeOldSkills, agents: activeOldAgents },
425
+ cwd
426
+ );
427
+ await this.writeCarriedSkills(selection.carried);
428
+ }
429
+ const authority = applyAuthority(selection.producer, cwd);
194
430
  if (!hasAnyChanges(changes)) {
195
431
  this.log(chalk.hex(CLI_COLORS.NEUTRAL)("No changes made."));
196
432
  if (!isProjectSetup) return;
197
- await this.writeConfigAndCompile(result, context, cwd);
433
+ await this.writeConfigAndCompile(result, context, cwd, authority);
198
434
  this.logCompletionSummary(changes);
199
435
  return;
200
436
  }
@@ -223,10 +459,239 @@ var Edit = class _Edit extends BaseCommand {
223
459
  await this.applyPluginChanges(changes, filteredResult, activeOldSkills, context, cwd);
224
460
  await this.copyNewLocalSkills(changes, filteredResult, context, cwd);
225
461
  await this.removeDeletedLocalSkills(changes, activeOldSkills, cwd);
226
- await this.writeConfigAndCompile(result, context, cwd);
462
+ await this.writeConfigAndCompile(result, context, cwd, authority);
227
463
  await this.cleanupStaleAgentFiles(changes, activeOldAgents, cwd);
228
464
  this.logCompletionSummary(changes);
229
465
  }
466
+ /** The interactive producer: open the wizard on what is installed, return what was chosen. */
467
+ async selectionFromWizard(context, cwd) {
468
+ const result = await this.runEditWizard(context, cwd);
469
+ if (!result) return null;
470
+ return { producer: "wizard", result };
471
+ }
472
+ /**
473
+ * The `--from <id>` producer: fetch, seat what the configuration carries, decode, and put back
474
+ * what this run has no authority to remove.
475
+ *
476
+ * Everything a shared configuration says is a statement about the whole roster, so the apply
477
+ * that follows is destructive — the project is made to MATCH it. Two exceptions come back into
478
+ * the result: a skill written here, which the producer drops on the way out because
479
+ * `forkedFrom` says the CLI never wrote it, and an id the configuration NAMES that this
480
+ * catalogue cannot place, because a destructive apply removes on intent and never on its own
481
+ * inability. Both are disclosed in the confirm rather than silently excused.
482
+ *
483
+ * A globally installed entry is NOT one of them. It is removable from here, and what its scope
484
+ * changes is who the removal reaches — which the confirm names, rather than this putting the
485
+ * entry back and calling the reach impossible.
486
+ */
487
+ async selectionFromSharedConfig(payload, context, cwd) {
488
+ const { matrix: sourceMatrix } = context.sourceResult;
489
+ const carried = this.registerExternalSkillsOrFail(payload, sourceMatrix, cwd);
490
+ const { result, skippedSkillIds, skippedAgentNames } = this.decodeSeedOrFail(
491
+ payload,
492
+ sourceMatrix
493
+ );
494
+ this.refuseProjectScopedContentAtHome(result, cwd);
495
+ if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));
496
+ if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));
497
+ const reconciled = reconcileSharedConfig({
498
+ decoded: result,
499
+ installed: context.projectConfig,
500
+ authoredHere: await this.readAuthoredHere(context.projectConfig, cwd),
501
+ // The ids the decode above could not place. They are the skips just reported, read as
502
+ // what STAYS rather than as what did not arrive: the payload named them, so their absence
503
+ // from the decode is this catalogue's limit and not an instruction to delete anything.
504
+ unplaceable: new Set(skippedSkillIds)
505
+ });
506
+ return {
507
+ producer: "shared",
508
+ result: reconciled.result,
509
+ kept: keptStatements(reconciled.kept),
510
+ carried
511
+ };
512
+ }
513
+ /**
514
+ * Which installed skills the round trip does not own, asked of the disk exactly as the
515
+ * producing half asks it.
516
+ *
517
+ * Best-effort by nature and never fatal: the question is only ever asked to PROTECT a skill,
518
+ * so a directory that cannot be read protects nothing and must not fail an apply. The
519
+ * consequence of an unanswered question is that the entry is treated as the CLI's own, which
520
+ * is what every other command already assumes about it.
521
+ */
522
+ async readAuthoredHere(projectConfig, cwd) {
523
+ if (!projectConfig) return /* @__PURE__ */ new Set();
524
+ try {
525
+ return await skillsAuthoredHere(projectConfig, cwd);
526
+ } catch (error) {
527
+ this.warn(`Could not tell which skills were written here: ${getErrorMessage(error)}`);
528
+ return /* @__PURE__ */ new Set();
529
+ }
530
+ }
531
+ /**
532
+ * The id, fetched — or the run refused before it is.
533
+ *
534
+ * The terminal question is answered first because nothing in the payload can change its
535
+ * answer: an apply that cannot be confirmed is over before the store is asked, and a refusal
536
+ * that had already spent a round trip would be describing work it never intended to do.
537
+ */
538
+ async fetchSharedConfigOrFail(id) {
539
+ if (!process.stdin.isTTY) {
540
+ this.error(sharedConfigNeedsTerminal(id), { exit: EXIT_CODES.ERROR });
541
+ }
542
+ this.log(`Fetching configuration ${id}...`);
543
+ const fetched = await fetchSeedConfig(id);
544
+ if (!fetched.ok) {
545
+ this.error(fetched.error, { exit: EXIT_CODES.ERROR });
546
+ }
547
+ return fetched.payload;
548
+ }
549
+ /**
550
+ * The decode refuses a payload the config model has nowhere to write (see `seedToWizardResult`).
551
+ * That is a failure of this command, reported with this command's exit code rather than left to
552
+ * surface as an unhandled throw.
553
+ */
554
+ decodeSeedOrFail(payload, sourceMatrix) {
555
+ try {
556
+ return seedToWizardResult(payload, sourceMatrix);
557
+ } catch (error) {
558
+ this.handleError(error);
559
+ }
560
+ }
561
+ /**
562
+ * Seats the catalogue entries the payload carries with it, or refuses the run. The refusal is
563
+ * `registerExternalSkills`' own — a carried skill asked for as a plugin, which no marketplace
564
+ * serves — reported with this command's exit code for the same reason the decode's is.
565
+ */
566
+ registerExternalSkillsOrFail(payload, sourceMatrix, projectDir) {
567
+ try {
568
+ return registerExternalSkills(payload, sourceMatrix, projectDir);
569
+ } catch (error) {
570
+ this.handleError(error);
571
+ }
572
+ }
573
+ /** Writes the skills the configuration brought with it, and says which they were. */
574
+ async writeCarriedSkills(carried) {
575
+ if (carried.length === 0) return;
576
+ await writeExternalSkills(carried);
577
+ this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));
578
+ }
579
+ /**
580
+ * Shows what applying this configuration takes away, and stops the run unless a person says
581
+ * yes.
582
+ *
583
+ * The plan is built from the SAME `ConfigChanges` the apply below acts on, so what is approved
584
+ * and what is removed are one value read twice. Its kept half is the other side of the same
585
+ * honesty: nothing is refused over an entry this run cannot remove, and nothing is silent
586
+ * about one either.
587
+ *
588
+ * WHICH plan is built is decided here and only here, on the directory the run was started in.
589
+ * Inside the global installation the scope was chosen and is obvious, so the ordinary confirm
590
+ * is the whole of the gate; inside a project a global removal reaches projects nobody here is
591
+ * looking at, so it is shown apart and the reach is named.
592
+ */
593
+ async confirmSharedConfigOrCancel(changes, kept, installed, cwd) {
594
+ const plan = isHomeDirectory(cwd) ? globalScopePlan(changes, kept) : projectScopePlan(changes, kept, installed, await this.otherRegisteredProjects(cwd));
595
+ const outcome = await promptConfirm(({ onConfirm, onCancel }) => /* @__PURE__ */ jsx(
596
+ RemovalPlanConfirm,
597
+ {
598
+ heading: plan.heading,
599
+ sections: plan.sections,
600
+ statements: plan.statements,
601
+ message: SHARED_CONFIG_APPLY.CONFIRM,
602
+ onConfirm,
603
+ onCancel
604
+ }
605
+ ));
606
+ if (outcome === "confirmed") return;
607
+ this.log("\nEdit cancelled");
608
+ this.error("Cancelled", { exit: EXIT_CODES.CANCELLED });
609
+ }
610
+ /**
611
+ * Every registered project but this one — the blast radius a global removal actually has.
612
+ *
613
+ * Read from the GLOBAL config rather than from `context.projectConfig`: `projects[]` is the
614
+ * registry the fan-out itself walks, and a project's own config never carries it, so taking
615
+ * the list from anywhere else would let the confirm name a set the propagation does not.
616
+ *
617
+ * Best-effort by nature. The list exists to be DISCLOSED, so a home directory that cannot be
618
+ * read leaves the disclosure counting nobody rather than failing an apply — and the statement
619
+ * it produces then is the one that says no other project is registered.
620
+ */
621
+ async otherRegisteredProjects(cwd) {
622
+ try {
623
+ const global = await loadProjectConfigFromDir(os.homedir());
624
+ const here = normalizeProjectPath(cwd);
625
+ return (global?.config.projects ?? []).filter((projectDir) => projectDir !== here);
626
+ } catch (error) {
627
+ this.warn(`Could not tell which projects share this install: ${getErrorMessage(error)}`);
628
+ return [];
629
+ }
630
+ }
631
+ /**
632
+ * The outbound half of the editor round trip: this installation, minted as a configuration
633
+ * the editor opens, and handed to a browser.
634
+ *
635
+ * It is the same mint `share` performs — same reader, same mapping, same refusals, through
636
+ * `seedPayloadForInstallation` — because an id is the whole of what either command produces
637
+ * and two spellings of "the installation in this directory" would mint two different ids for
638
+ * one project. What differs is only the ending: `share` reports the id, this opens it.
639
+ *
640
+ * Nothing on disk is touched. A configuration is read, not rewritten, so a run that changed
641
+ * anything here would be editing the project on the way to offering to edit it.
642
+ */
643
+ async openInEditor(projectDir) {
644
+ const prepared = await seedPayloadForInstallation(projectDir);
645
+ if (!prepared.ok) {
646
+ this.error(prepared.error, { exit: EXIT_CODES.ERROR });
647
+ }
648
+ this.log(`Opening ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);
649
+ const published = await publishSeedConfig(prepared.payload);
650
+ if (!published.ok) {
651
+ this.error(published.error, { exit: EXIT_CODES.ERROR });
652
+ }
653
+ await this.handToBrowser(published.id);
654
+ }
655
+ /**
656
+ * The link, printed first and opened second.
657
+ *
658
+ * Printed first because it is the only part of this that works everywhere: over a pipe, in CI
659
+ * and on a machine with no desktop session there is no browser to be anybody's, and a link
660
+ * nobody can copy is the whole loss. Opening one is the convenience on top, so a failure to
661
+ * open is a warning beside a link that still works rather than a failed command.
662
+ *
663
+ * `process.stdin.isTTY` is the same question `init`'s dashboard asks before it offers a
664
+ * prompt — is there a person here — because that is exactly what "whose browser is this"
665
+ * means.
666
+ */
667
+ async handToBrowser(id) {
668
+ this.logSuccess(`Shared as ${id}`);
669
+ for (const destination of sharedConfigDestinations(id)) {
670
+ this.log(destination);
671
+ }
672
+ if (!process.stdin.isTTY) return;
673
+ const opened = await openUrl(editorConfigUrl(id));
674
+ if (!opened.ok) this.warn(opened.error);
675
+ }
676
+ /**
677
+ * The load below, behind a spinner that comes down whichever way the await ends.
678
+ *
679
+ * The cleanup is a `finally` because all three of `loadContext`'s refusals are raised
680
+ * while this spinner is mounted, and oclif would otherwise paint its error under an Ink
681
+ * tree still repainting over it. Never a `catch`: the throw reaches oclif untouched, or
682
+ * both the error rendering and the pinned exit codes change with it.
683
+ */
684
+ async loadContextUnderSpinner() {
685
+ const { unmount, clear: clearSpinner } = render(
686
+ /* @__PURE__ */ jsx(Spinner, { label: STATUS_MESSAGES.LOADING_SKILLS })
687
+ );
688
+ try {
689
+ return await this.loadContext();
690
+ } finally {
691
+ clearSpinner();
692
+ unmount();
693
+ }
694
+ }
230
695
  async loadContext() {
231
696
  const detected = await detectProject();
232
697
  if (!detected) {
@@ -317,11 +782,19 @@ var Edit = class _Edit extends BaseCommand {
317
782
  * source contradict the filesystem and the plugin registry.
318
783
  *
319
784
  * So authority follows the work actually performed, and no further: only ids
320
- * `executeMigration` acted on this run are rewritten, and only their `source` field. Global
785
+ * `executeMigration` acted on this run are rewritten, and only their `origin` field. Global
321
786
  * entries this session merely displayed, re-scoped or deselected are untouched, as are
322
787
  * `marketplace`, `stack`, `agents` and every other registered project's view of them.
323
- * Refusing the switch instead is not an option — driving a global-scope migration from a
324
- * project directory is a supported flow (`scope-aware-local-copy` lifecycle tests).
788
+ *
789
+ * Driving a global-scope migration from a project directory is NOT a supported flow, and this
790
+ * method is no longer the thing that permits it. The wizard now refuses it at source: the two
791
+ * bulk install-mode keys are withdrawn, and `setInstallMode` ignores a project-context call
792
+ * against a global slot the hydration snapshot owns — the same authority the Sources grid
793
+ * already enforced by rendering that row inert. What still reaches here is the residue that
794
+ * authority leaves legitimate: a mode change committed on the project half of a `[P][G]` pair
795
+ * and then carried to global scope by a P->G collapse (`s`) in the same session. The entry is
796
+ * the project's own to configure at the moment it is configured, and global at the moment it
797
+ * is written — so the migration is real, and the global config must record it.
325
798
  *
326
799
  * Runs BEFORE `writeConfigAndCompile`, so the global config written here is the one
327
800
  * the wizard write reloads, keeps (existing wins in `mergeGlobalConfigs`) and inlines
@@ -329,14 +802,14 @@ var Edit = class _Edit extends BaseCommand {
329
802
  * classifies as a no-op against what this one left on disk, so the fan-out below
330
803
  * happens once.
331
804
  *
332
- * The migrated `source` decides the reference form a compiled agent emits, so every
805
+ * The migrated `origin` decides the reference form a compiled agent emits, so every
333
806
  * OTHER registered project's config and agents are stale until this write fans out —
334
807
  * which is why it goes through the gate rather than straight to the file.
335
808
  */
336
809
  async recordGlobalSourceMigrations(migratedSkillIds, newSkills, cwd, context) {
337
810
  if (isHomeDirectory(cwd)) return;
338
811
  const migratedSources = new Map(
339
- newSkills.filter((s) => migratedSkillIds.has(s.id) && isActiveAt(s, "global")).map((s) => [s.id, s.source])
812
+ newSkills.filter((s) => migratedSkillIds.has(s.id) && isActiveAt(s, "global")).map((s) => [s.id, s.origin])
340
813
  );
341
814
  if (migratedSources.size === 0) return;
342
815
  try {
@@ -348,12 +821,12 @@ var Edit = class _Edit extends BaseCommand {
348
821
  // matrix in hand already.
349
822
  // eslint-disable-next-line @typescript-eslint/require-await -- deps contract
350
823
  loadMatrix: async () => context.sourceResult.matrix,
351
- loadAgents: async () => (await loadAgentDefs({ projectDir: cwd })).agents
824
+ loadAgents: async () => (await loadAgentDefs()).agents
352
825
  }
353
826
  );
354
827
  this.reportPropagatedRecompile(report);
355
828
  } catch (error) {
356
- this.warn(`Could not record global source change: ${getErrorMessage(error)}`);
829
+ this.warn(`Could not record global origin change: ${getErrorMessage(error)}`);
357
830
  }
358
831
  }
359
832
  logChangeSummary(changes, newSkills, oldSkills, removalReasons) {
@@ -430,11 +903,37 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
430
903
  for (const warning of migrationResult.warnings) {
431
904
  this.warn(warning);
432
905
  }
906
+ if (migrationPlan.toEject.length > 0) {
907
+ this.reportEjectCopies(migrationResult.ejectCopies);
908
+ }
433
909
  if (migrationPlan.toPlugin.length > 0) {
434
910
  this.reportPluginInstalls(migrationResult.pluginInstalls);
435
911
  }
436
912
  return migratedSkillIds;
437
913
  }
914
+ /**
915
+ * What the plugin→eject half copied, what it could not, and the refusal to continue past
916
+ * a failure.
917
+ *
918
+ * The shape of `BaseCommand.reportPluginInstalls`, deliberately: the two directions of one
919
+ * mode switch owe the user the same account, and the eject half having no structured
920
+ * failure at all is what let a config record `origin: "eject"` for a skill whose copy was
921
+ * refused. It stays private because `edit` is the only command that migrates a mode —
922
+ * `init` installs, and has no old state to move.
923
+ *
924
+ * The count line is the same one `copyNewLocalSkills` prints, and names no destination:
925
+ * the migration splits its copies between the project and $HOME by each skill's own scope,
926
+ * so one directory would misname the other half.
927
+ */
928
+ reportEjectCopies(result) {
929
+ for (const item of result.failed) {
930
+ this.warn(`Failed to copy ${item.id} for eject: ${item.error}`);
931
+ }
932
+ if (result.failed.length > 0) {
933
+ this.error(ejectCopyFailureError(result.failed.length), { exit: EXIT_CODES.ERROR });
934
+ }
935
+ this.log(chalk.hex(CLI_COLORS.NEUTRAL)(localSkillsCopied(result.copied.length)));
936
+ }
438
937
  /** Names what this run is switching, in the words `init` describes an install mode with. */
439
938
  logModeSwitch(count, modeDescription) {
440
939
  this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Switching ${count} skill(s) to ${modeDescription}`));
@@ -443,13 +942,13 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
443
942
  const { scopeChanges } = changes;
444
943
  for (const [skillId, change] of scopeChanges) {
445
944
  const skillConfig = filteredResult.skills.find((s) => s.id === skillId);
446
- if (skillConfig?.source === EJECT_SOURCE) {
945
+ if (skillConfig?.origin === EJECT_SOURCE) {
447
946
  await migrateLocalSkillScope(skillId, change.from, cwd);
448
947
  }
449
948
  }
450
949
  const hasPluginScopeChanges = [...scopeChanges.keys()].some((skillId) => {
451
950
  const skillConfig = filteredResult.skills.find((s) => s.id === skillId);
452
- return skillConfig && skillConfig.source !== EJECT_SOURCE;
951
+ return skillConfig && skillConfig.origin !== EJECT_SOURCE;
453
952
  });
454
953
  if (!hasPluginScopeChanges) return;
455
954
  const marketplace = await this.requireMarketplaceOrExit(
@@ -482,10 +981,10 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
482
981
  async applyPluginChanges(changes, filteredResult, activeOldSkills, context, cwd) {
483
982
  const { addedSkills, removedSkills } = changes;
484
983
  const addedPluginSkills = filteredResult.skills.filter(
485
- (s) => addedSkills.includes(s.id) && s.source !== EJECT_SOURCE
984
+ (s) => addedSkills.includes(s.id) && s.origin !== EJECT_SOURCE
486
985
  );
487
986
  const removedPluginSkills = removedSkills.filter(
488
- (id) => activeOldSkills.find((s) => s.id === id)?.source !== EJECT_SOURCE
987
+ (id) => activeOldSkills.find((s) => s.id === id)?.origin !== EJECT_SOURCE
489
988
  );
490
989
  if (addedPluginSkills.length === 0 && removedPluginSkills.length === 0) return;
491
990
  const marketplace = await this.requireMarketplaceOrExit(
@@ -493,7 +992,12 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
493
992
  "install or uninstall plugin skills"
494
993
  );
495
994
  if (addedPluginSkills.length > 0) {
496
- await this.installPluginSkillsReported(addedPluginSkills, marketplace, cwd);
995
+ await this.installPluginSkillsReported(
996
+ addedPluginSkills,
997
+ marketplace,
998
+ cwd,
999
+ context.sourceResult.matrix
1000
+ );
497
1001
  }
498
1002
  if (removedPluginSkills.length > 0) {
499
1003
  const uninstallResult = await uninstallPluginSkills(
@@ -515,26 +1019,26 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
515
1019
  async copyNewLocalSkills(changes, filteredResult, context, cwd) {
516
1020
  const { addedSkills } = changes;
517
1021
  const addedLocalSkills = filteredResult.skills.filter(
518
- (s) => addedSkills.includes(s.id) && s.source === EJECT_SOURCE
1022
+ (s) => addedSkills.includes(s.id) && s.origin === EJECT_SOURCE
519
1023
  );
520
1024
  if (addedLocalSkills.length > 0) {
521
1025
  const copyResult = await copyLocalSkills(addedLocalSkills, cwd, context.sourceResult);
522
- this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Copied ${copyResult.totalCopied} local skill(s)`));
1026
+ this.log(chalk.hex(CLI_COLORS.NEUTRAL)(localSkillsCopied(copyResult.totalCopied)));
523
1027
  }
524
1028
  }
525
1029
  async removeDeletedLocalSkills(changes, activeOldSkills, cwd) {
526
1030
  const { removedSkills } = changes;
527
1031
  for (const skillId of removedSkills) {
528
1032
  const oldSkill = activeOldSkills.find((s) => s.id === skillId);
529
- if (oldSkill?.source !== EJECT_SOURCE) continue;
1033
+ if (oldSkill?.origin !== EJECT_SOURCE) continue;
530
1034
  const deleteDir = installBaseDir(cwd, oldSkill.scope);
531
1035
  await deleteLocalSkill(deleteDir, skillId);
532
1036
  }
533
1037
  }
534
- async writeConfigAndCompile(result, context, cwd) {
1038
+ async writeConfigAndCompile(result, context, cwd, authority) {
535
1039
  let agentDefsResult;
536
1040
  try {
537
- agentDefsResult = await loadAgentDefs({});
1041
+ agentDefsResult = await loadAgentDefs();
538
1042
  } catch (error) {
539
1043
  this.handleError(error);
540
1044
  }
@@ -546,14 +1050,17 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
546
1050
  projectDir: cwd,
547
1051
  agents: agentDefsResult.agents,
548
1052
  // A full `cc edit` pass is authoritative over the roster it owns, so deselected entries
549
- // are removed rather than union-preserved (D-233 Scenario C). Global-context edit owns
550
- // the entire config ("all"); a project edit owns only project-scoped entries and its own
551
- // tombstones ("owned"), never inherited global-active entries.
552
- authoritativeScope: isHomeDirectory(cwd) ? "all" : "owned"
1053
+ // are removed rather than union-preserved (D-233 Scenario C). `applyAuthority` decides
1054
+ // how much that is from the producer and the directory, and hands the same word to the
1055
+ // merger and to the global config the project branch of the gate commits.
1056
+ authoritativeScope: authority
553
1057
  });
554
1058
  } catch (error) {
555
- this.warn(`Could not update config: ${getErrorMessage(error)}`);
1059
+ this.error(`Could not update config: ${getErrorMessage(error)}`, {
1060
+ exit: EXIT_CODES.ERROR
1061
+ });
556
1062
  }
1063
+ this.reportUnassignedSkills(configResult.config);
557
1064
  try {
558
1065
  const agentScopeMap = activeAgentScopeMap(result.agentConfigs);
559
1066
  const { allSkills } = await discoverInstalledSkills(cwd);
@@ -585,31 +1092,14 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
585
1092
  this.warn(`Agent recompilation failed: ${getErrorMessage(error)}`);
586
1093
  this.log(`You can manually recompile with '${CLI_INVOKE_COMMAND} compile'.`);
587
1094
  }
588
- if (configResult) {
589
- this.reportPropagatedRecompile(configResult.propagation);
590
- }
1095
+ this.reportPropagatedRecompile(configResult.propagation);
591
1096
  }
592
1097
  async cleanupStaleAgentFiles(changes, oldAgents, cwd) {
593
- const { agentScopeChanges, removedAgents } = changes;
594
- for (const [agentName, change] of agentScopeChanges) {
595
- if (change.from === "global") continue;
596
- const oldAgentPath = path.join(
597
- resolveInstallPaths(cwd, "project").agentsDir,
598
- `${agentName}.md`
599
- );
600
- try {
601
- await remove(oldAgentPath);
602
- } catch (error) {
603
- this.warn(`Could not remove old agent file ${oldAgentPath}: ${getErrorMessage(error)}`);
604
- }
605
- }
606
- for (const agentName of removedAgents) {
607
- const oldScope = oldAgents.find((a) => a.name === agentName)?.scope ?? "project";
608
- const agentPath = path.join(resolveInstallPaths(cwd, oldScope).agentsDir, `${agentName}.md`);
609
- try {
610
- await remove(agentPath);
611
- } catch (error) {
612
- this.warn(`Could not remove agent file ${agentPath}: ${getErrorMessage(error)}`);
1098
+ for (const removal of planStaleAgentRemovals(changes, oldAgents, cwd)) {
1099
+ const { failed } = await removeCompiledAgents(removal);
1100
+ for (const { name, error } of failed) {
1101
+ const agentPath = path.join(removal.agentsDir, `${name}.md`);
1102
+ this.warn(`Could not remove agent file ${agentPath}: ${error}`);
613
1103
  }
614
1104
  }
615
1105
  }
@@ -647,7 +1137,7 @@ function detectConfigChanges(oldConfig, wizardResult, fullEntries) {
647
1137
  wizardResult.skills,
648
1138
  oldSkillsById,
649
1139
  (s) => s.id,
650
- (s) => s.source
1140
+ (s) => s.origin
651
1141
  ),
652
1142
  scopeChanges,
653
1143
  agentScopeChanges,
@@ -688,6 +1178,24 @@ function detectDualScopeTransitions(scopeChanges, fullNew, fullOld, getKey) {
688
1178
  }
689
1179
  return result;
690
1180
  }
1181
+ var STALE_AGENT_SCOPES = ["project", "global"];
1182
+ var UNRECORDED_AGENT_SCOPE = "project";
1183
+ function installedScope(name, oldAgents) {
1184
+ return oldAgents.find((agent) => agent.name === name)?.scope ?? UNRECORDED_AGENT_SCOPE;
1185
+ }
1186
+ function planStaleAgentRemovals(changes, oldAgents, cwd) {
1187
+ const supersededByGlobal = [...changes.agentScopeChanges].filter(([, change]) => change.from !== "global").map(([name]) => ({ name, scope: "project" }));
1188
+ const deselected = changes.removedAgents.map((name) => ({
1189
+ name,
1190
+ scope: installedScope(name, oldAgents)
1191
+ }));
1192
+ const stale = [...supersededByGlobal, ...deselected];
1193
+ const removalAtScope = (scope) => ({
1194
+ agentsDir: resolveInstallPaths(cwd, scope).agentsDir,
1195
+ agents: stale.filter((agent) => agent.scope === scope).map((agent) => agent.name)
1196
+ });
1197
+ return STALE_AGENT_SCOPES.map(removalAtScope).filter((removal) => removal.agents.length > 0);
1198
+ }
691
1199
  function hasAnyChanges(changes) {
692
1200
  return changes.addedSkills.length > 0 || changes.removedSkills.length > 0 || changes.addedAgents.length > 0 || changes.removedAgents.length > 0 || changes.sourceChanges.size > 0 || changes.scopeChanges.size > 0 || changes.agentScopeChanges.size > 0;
693
1201
  }
@@ -696,7 +1204,7 @@ async function migratePluginSkillScopes(scopeChanges, skills, marketplace, proje
696
1204
  const failed = [];
697
1205
  for (const [skillId, change] of scopeChanges) {
698
1206
  const skillConfig = skills.find((s) => s.id === skillId);
699
- if (!skillConfig || skillConfig.source === EJECT_SOURCE) {
1207
+ if (!skillConfig || skillConfig.origin === EJECT_SOURCE) {
700
1208
  continue;
701
1209
  }
702
1210
  const newPluginScope = toClaudePluginScope(change.to);