agents-inc 0.164.0 → 0.166.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 (191) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +8 -9
  3. package/dist/{chunk-X4SSJZLY.js → chunk-25MPBIK3.js} +12 -261
  4. package/dist/chunk-25MPBIK3.js.map +1 -0
  5. package/dist/{chunk-LT5GXEB2.js → chunk-2VUYFTUB.js} +8 -7
  6. package/dist/chunk-2VUYFTUB.js.map +1 -0
  7. package/dist/chunk-4AAOOAIN.js +49 -0
  8. package/dist/chunk-4AAOOAIN.js.map +1 -0
  9. package/dist/{chunk-ARYNOWKF.js → chunk-4NDBUJHK.js} +8 -8
  10. package/dist/{chunk-S63LXWMC.js → chunk-6L75SQZU.js} +2 -2
  11. package/dist/{chunk-7REKOTKG.js → chunk-6LF4CQBY.js} +3 -3
  12. package/dist/{chunk-K5ITEA3I.js → chunk-7JNJ52CD.js} +34 -17
  13. package/dist/chunk-7JNJ52CD.js.map +1 -0
  14. package/dist/{chunk-XPDVAJDH.js → chunk-A4KDXNOT.js} +3519 -1568
  15. package/dist/chunk-A4KDXNOT.js.map +1 -0
  16. package/dist/{chunk-XHPWTL4I.js → chunk-DAIEQJIF.js} +3 -3
  17. package/dist/{chunk-UITEKY2R.js → chunk-ENGYJCTF.js} +28 -4
  18. package/dist/chunk-ENGYJCTF.js.map +1 -0
  19. package/dist/{chunk-G2JJ5BO5.js → chunk-G4JK7WVO.js} +336 -140
  20. package/dist/chunk-G4JK7WVO.js.map +1 -0
  21. package/dist/{chunk-X37UYIE3.js → chunk-G6UREQ4V.js} +436 -739
  22. package/dist/chunk-G6UREQ4V.js.map +1 -0
  23. package/dist/chunk-GE3WKJ6Q.js +375 -0
  24. package/dist/chunk-GE3WKJ6Q.js.map +1 -0
  25. package/dist/{chunk-RGYDFBCT.js → chunk-HHIYT3PI.js} +5 -5
  26. package/dist/{chunk-2CQNPLVF.js → chunk-HWEKHVLE.js} +63 -42
  27. package/dist/chunk-HWEKHVLE.js.map +1 -0
  28. package/dist/{chunk-XVAQG2CV.js → chunk-JOEA52NR.js} +10 -8
  29. package/dist/chunk-JOEA52NR.js.map +1 -0
  30. package/dist/{chunk-3WVH2CTK.js → chunk-JQRJQ4SS.js} +15 -8
  31. package/dist/chunk-JQRJQ4SS.js.map +1 -0
  32. package/dist/{chunk-DSL66I4N.js → chunk-LFWLEDUG.js} +6 -6
  33. package/dist/{chunk-B3Y3QMWI.js → chunk-MAWNVT2C.js} +4 -4
  34. package/dist/{chunk-Q4IRRVXK.js → chunk-MPTNC32T.js} +3 -3
  35. package/dist/chunk-NBXXFIIW.js +73 -0
  36. package/dist/chunk-NBXXFIIW.js.map +1 -0
  37. package/dist/{chunk-B6FSLXYN.js → chunk-PMJWD27C.js} +3 -3
  38. package/dist/{chunk-XATLUKXK.js → chunk-PNB3524H.js} +6 -6
  39. package/dist/chunk-PXWG7KFO.js +39 -0
  40. package/dist/chunk-PXWG7KFO.js.map +1 -0
  41. package/dist/{chunk-4VL3CEOS.js → chunk-QHDPLLK6.js} +3 -3
  42. package/dist/{chunk-AOTCIUGX.js → chunk-RAHSOJQ2.js} +2 -2
  43. package/dist/{chunk-PHCPUQVR.js → chunk-RZDXDMT6.js} +2 -2
  44. package/dist/{chunk-6MV4JOCL.js → chunk-SAYZWCH6.js} +2 -2
  45. package/dist/{chunk-URXIQE7I.js → chunk-SCOQ34YM.js} +2 -2
  46. package/dist/{chunk-NQXO4LR3.js → chunk-SXVHSOTH.js} +16 -11
  47. package/dist/chunk-SXVHSOTH.js.map +1 -0
  48. package/dist/{chunk-QZX7SYKU.js → chunk-T6UWJAB3.js} +2 -2
  49. package/dist/{chunk-ZVXGW2IC.js → chunk-TODCQFRB.js} +4 -6
  50. package/dist/chunk-TODCQFRB.js.map +1 -0
  51. package/dist/{chunk-YRS3QZP2.js → chunk-TTY6DPJN.js} +3 -3
  52. package/dist/{chunk-QGUP3QJF.js → chunk-TZ2YJJKK.js} +22 -18
  53. package/dist/{chunk-QGUP3QJF.js.map → chunk-TZ2YJJKK.js.map} +1 -1
  54. package/dist/chunk-V3I7VQ7N.js +356 -0
  55. package/dist/chunk-V3I7VQ7N.js.map +1 -0
  56. package/dist/{chunk-AVK2HEKB.js → chunk-V5WXIM2F.js} +2 -6
  57. package/dist/{chunk-AVK2HEKB.js.map → chunk-V5WXIM2F.js.map} +1 -1
  58. package/dist/{chunk-NKGYKOB7.js → chunk-VAPTVR3J.js} +7 -8
  59. package/dist/chunk-VAPTVR3J.js.map +1 -0
  60. package/dist/chunk-VRXX4D6K.js +31 -0
  61. package/dist/chunk-VRXX4D6K.js.map +1 -0
  62. package/dist/{chunk-ABAZMMG4.js → chunk-WVUDLKIO.js} +2 -2
  63. package/dist/{chunk-ECURHW3T.js → chunk-WWIFNPJG.js} +13 -12
  64. package/dist/chunk-WWIFNPJG.js.map +1 -0
  65. package/dist/{chunk-J27W6TXS.js → chunk-XQHZPINL.js} +8 -4
  66. package/dist/chunk-XQHZPINL.js.map +1 -0
  67. package/dist/{chunk-V5GLL2JB.js → chunk-XZEVWPX6.js} +7 -7
  68. package/dist/chunk-Y3VIRVVE.js +932 -0
  69. package/dist/chunk-Y3VIRVVE.js.map +1 -0
  70. package/dist/{chunk-NTF4UXGK.js → chunk-Y47EV74W.js} +73 -30
  71. package/dist/chunk-Y47EV74W.js.map +1 -0
  72. package/dist/chunk-ZR4YPKXQ.js +159 -0
  73. package/dist/chunk-ZR4YPKXQ.js.map +1 -0
  74. package/dist/chunk-ZXKBERQU.js +250 -0
  75. package/dist/chunk-ZXKBERQU.js.map +1 -0
  76. package/dist/commands/build/marketplace.js +17 -17
  77. package/dist/commands/build/marketplace.js.map +1 -1
  78. package/dist/commands/build/plugins.js +11 -9
  79. package/dist/commands/build/plugins.js.map +1 -1
  80. package/dist/commands/compile.js +105 -27
  81. package/dist/commands/compile.js.map +1 -1
  82. package/dist/commands/doctor.js +309 -171
  83. package/dist/commands/doctor.js.map +1 -1
  84. package/dist/commands/edit.js +503 -314
  85. package/dist/commands/edit.js.map +1 -1
  86. package/dist/commands/eject.js +40 -23
  87. package/dist/commands/eject.js.map +1 -1
  88. package/dist/commands/init.js +44 -40
  89. package/dist/commands/list.js +44 -10
  90. package/dist/commands/list.js.map +1 -1
  91. package/dist/commands/new/marketplace.js +13 -10
  92. package/dist/commands/new/marketplace.js.map +1 -1
  93. package/dist/commands/search.js +12 -10
  94. package/dist/commands/search.js.map +1 -1
  95. package/dist/commands/share.js +102 -15
  96. package/dist/commands/share.js.map +1 -1
  97. package/dist/commands/uninstall.js +231 -103
  98. package/dist/commands/uninstall.js.map +1 -1
  99. package/dist/commands/update.js +49 -20
  100. package/dist/commands/update.js.map +1 -1
  101. package/dist/components/common/prompt-confirm.js +1 -1
  102. package/dist/components/common/removal-plan-confirm.js +2 -2
  103. package/dist/components/common/select-list.js +3 -3
  104. package/dist/components/common/spinner.js +6 -3
  105. package/dist/components/wizard/category-grid.js +5 -5
  106. package/dist/components/wizard/checkbox-grid.js +4 -4
  107. package/dist/components/wizard/domain-selection.js +9 -9
  108. package/dist/components/wizard/run-wizard-session.js +29 -29
  109. package/dist/components/wizard/scroll-affordance.js +2 -2
  110. package/dist/components/wizard/skill-agent-summary.js +5 -5
  111. package/dist/components/wizard/source-grid.js +6 -6
  112. package/dist/components/wizard/stack-selection.js +8 -8
  113. package/dist/components/wizard/step-agents.js +8 -8
  114. package/dist/components/wizard/step-build.js +8 -8
  115. package/dist/components/wizard/step-confirm.js +9 -9
  116. package/dist/components/wizard/step-sources.js +9 -9
  117. package/dist/components/wizard/step-stack.js +9 -9
  118. package/dist/components/wizard/summary-panel.js +8 -8
  119. package/dist/components/wizard/toast.js +2 -2
  120. package/dist/components/wizard/wizard-layout.js +12 -12
  121. package/dist/components/wizard/wizard-tabs.js +2 -2
  122. package/dist/components/wizard/wizard.js +27 -27
  123. package/dist/hooks/init.js +69 -43
  124. package/dist/hooks/init.js.map +1 -1
  125. package/dist/load-agent-defs-3C27ENC7.js +14 -0
  126. package/dist/recompile-project-agents-DGNBCU3N.js +18 -0
  127. package/dist/{source-loader-GRBVNRAW.js → source-loader-7KZ3MD5O.js} +6 -4
  128. package/dist/src/agents/_templates/agent-body.liquid +55 -0
  129. package/dist/src/agents/_templates/agent.liquid +1 -55
  130. package/dist/src/agents/meta/agent-summoner/output.md +1 -1
  131. package/dist/src/agents/meta/agent-summoner/playbook.md +15 -7
  132. package/dist/stores/wizard-store.js +4 -4
  133. package/package.json +10 -9
  134. package/src/agents/_templates/agent-body.liquid +55 -0
  135. package/src/agents/_templates/agent.liquid +1 -55
  136. package/src/agents/meta/agent-summoner/output.md +1 -1
  137. package/src/agents/meta/agent-summoner/playbook.md +15 -7
  138. package/src/schemas/project-config.schema.json +1 -1
  139. package/src/schemas/project-source-config.schema.json +1 -1
  140. package/dist/chunk-2CQNPLVF.js.map +0 -1
  141. package/dist/chunk-3WVH2CTK.js.map +0 -1
  142. package/dist/chunk-7ANJQLPJ.js +0 -35
  143. package/dist/chunk-7ANJQLPJ.js.map +0 -1
  144. package/dist/chunk-ECURHW3T.js.map +0 -1
  145. package/dist/chunk-FLW25ORT.js +0 -130
  146. package/dist/chunk-FLW25ORT.js.map +0 -1
  147. package/dist/chunk-G2JJ5BO5.js.map +0 -1
  148. package/dist/chunk-J27W6TXS.js.map +0 -1
  149. package/dist/chunk-JCPANDNR.js +0 -35
  150. package/dist/chunk-JCPANDNR.js.map +0 -1
  151. package/dist/chunk-JIERYE6B.js +0 -480
  152. package/dist/chunk-JIERYE6B.js.map +0 -1
  153. package/dist/chunk-JU4ZGJ7A.js +0 -668
  154. package/dist/chunk-JU4ZGJ7A.js.map +0 -1
  155. package/dist/chunk-K5ITEA3I.js.map +0 -1
  156. package/dist/chunk-LT5GXEB2.js.map +0 -1
  157. package/dist/chunk-NKGYKOB7.js.map +0 -1
  158. package/dist/chunk-NQXO4LR3.js.map +0 -1
  159. package/dist/chunk-NTF4UXGK.js.map +0 -1
  160. package/dist/chunk-UITEKY2R.js.map +0 -1
  161. package/dist/chunk-X37UYIE3.js.map +0 -1
  162. package/dist/chunk-X4SSJZLY.js.map +0 -1
  163. package/dist/chunk-XPDVAJDH.js.map +0 -1
  164. package/dist/chunk-XVAQG2CV.js.map +0 -1
  165. package/dist/chunk-ZBPEFQ4G.js +0 -12
  166. package/dist/chunk-ZBPEFQ4G.js.map +0 -1
  167. package/dist/chunk-ZVXGW2IC.js.map +0 -1
  168. package/dist/load-agent-defs-7IM3GBEQ.js +0 -13
  169. package/dist/recompile-project-agents-VR4NLGOU.js +0 -17
  170. /package/dist/{chunk-ARYNOWKF.js.map → chunk-4NDBUJHK.js.map} +0 -0
  171. /package/dist/{chunk-S63LXWMC.js.map → chunk-6L75SQZU.js.map} +0 -0
  172. /package/dist/{chunk-7REKOTKG.js.map → chunk-6LF4CQBY.js.map} +0 -0
  173. /package/dist/{chunk-XHPWTL4I.js.map → chunk-DAIEQJIF.js.map} +0 -0
  174. /package/dist/{chunk-RGYDFBCT.js.map → chunk-HHIYT3PI.js.map} +0 -0
  175. /package/dist/{chunk-DSL66I4N.js.map → chunk-LFWLEDUG.js.map} +0 -0
  176. /package/dist/{chunk-B3Y3QMWI.js.map → chunk-MAWNVT2C.js.map} +0 -0
  177. /package/dist/{chunk-Q4IRRVXK.js.map → chunk-MPTNC32T.js.map} +0 -0
  178. /package/dist/{chunk-B6FSLXYN.js.map → chunk-PMJWD27C.js.map} +0 -0
  179. /package/dist/{chunk-XATLUKXK.js.map → chunk-PNB3524H.js.map} +0 -0
  180. /package/dist/{chunk-4VL3CEOS.js.map → chunk-QHDPLLK6.js.map} +0 -0
  181. /package/dist/{chunk-AOTCIUGX.js.map → chunk-RAHSOJQ2.js.map} +0 -0
  182. /package/dist/{chunk-PHCPUQVR.js.map → chunk-RZDXDMT6.js.map} +0 -0
  183. /package/dist/{chunk-6MV4JOCL.js.map → chunk-SAYZWCH6.js.map} +0 -0
  184. /package/dist/{chunk-URXIQE7I.js.map → chunk-SCOQ34YM.js.map} +0 -0
  185. /package/dist/{chunk-QZX7SYKU.js.map → chunk-T6UWJAB3.js.map} +0 -0
  186. /package/dist/{chunk-YRS3QZP2.js.map → chunk-TTY6DPJN.js.map} +0 -0
  187. /package/dist/{chunk-ABAZMMG4.js.map → chunk-WVUDLKIO.js.map} +0 -0
  188. /package/dist/{chunk-V5GLL2JB.js.map → chunk-XZEVWPX6.js.map} +0 -0
  189. /package/dist/{load-agent-defs-7IM3GBEQ.js.map → load-agent-defs-3C27ENC7.js.map} +0 -0
  190. /package/dist/{recompile-project-agents-VR4NLGOU.js.map → recompile-project-agents-DGNBCU3N.js.map} +0 -0
  191. /package/dist/{source-loader-GRBVNRAW.js.map → source-loader-7KZ3MD5O.js.map} +0 -0
@@ -3,83 +3,105 @@ import {
3
3
  publishSeedConfig,
4
4
  seedPayloadForInstallation,
5
5
  skillsAuthoredHere
6
- } from "../chunk-NTF4UXGK.js";
6
+ } from "../chunk-Y47EV74W.js";
7
7
  import {
8
8
  RemovalPlanConfirm
9
- } from "../chunk-ZVXGW2IC.js";
10
- import "../chunk-OZXAJNLA.js";
9
+ } from "../chunk-TODCQFRB.js";
10
+ import {
11
+ unofferablePlacementsFound
12
+ } from "../chunk-PXWG7KFO.js";
11
13
  import {
12
- openUrl
13
- } from "../chunk-7ANJQLPJ.js";
14
+ arrivalLines,
15
+ arrivalsByScope,
16
+ notInstalledGlobally,
17
+ openUrl,
18
+ readInstalledGlobal,
19
+ reconcileSharedConfig,
20
+ restoreInstalledGlobal,
21
+ sameAssignments,
22
+ skillLabel,
23
+ withUnplaceableAssignees
24
+ } from "../chunk-V3I7VQ7N.js";
14
25
  import {
15
26
  runWizardSession
16
- } from "../chunk-RGYDFBCT.js";
17
- import "../chunk-ECURHW3T.js";
18
- import "../chunk-AOTCIUGX.js";
19
- import "../chunk-XHPWTL4I.js";
20
- import "../chunk-URXIQE7I.js";
21
- import "../chunk-ARYNOWKF.js";
22
- import "../chunk-LT5GXEB2.js";
23
- import "../chunk-QZX7SYKU.js";
24
- import "../chunk-S63LXWMC.js";
25
- import "../chunk-DSL66I4N.js";
26
- import "../chunk-QGUP3QJF.js";
27
- import "../chunk-6MV4JOCL.js";
28
- import "../chunk-XATLUKXK.js";
29
- import "../chunk-V5GLL2JB.js";
30
- import "../chunk-4VL3CEOS.js";
31
- import "../chunk-Q4IRRVXK.js";
27
+ } from "../chunk-HHIYT3PI.js";
28
+ import "../chunk-WWIFNPJG.js";
29
+ import "../chunk-RAHSOJQ2.js";
30
+ import "../chunk-DAIEQJIF.js";
31
+ import "../chunk-SCOQ34YM.js";
32
+ import "../chunk-4NDBUJHK.js";
33
+ import "../chunk-2VUYFTUB.js";
34
+ import "../chunk-T6UWJAB3.js";
35
+ import "../chunk-6L75SQZU.js";
36
+ import "../chunk-LFWLEDUG.js";
37
+ import "../chunk-TZ2YJJKK.js";
38
+ import "../chunk-SAYZWCH6.js";
39
+ import "../chunk-PNB3524H.js";
40
+ import "../chunk-XZEVWPX6.js";
41
+ import "../chunk-QHDPLLK6.js";
42
+ import "../chunk-MPTNC32T.js";
32
43
  import "../chunk-TSIU7DME.js";
33
- import "../chunk-XVAQG2CV.js";
44
+ import "../chunk-JOEA52NR.js";
34
45
  import {
35
- Spinner
36
- } from "../chunk-ZBPEFQ4G.js";
37
- import "../chunk-NQXO4LR3.js";
38
- import "../chunk-J27W6TXS.js";
39
- import "../chunk-3WVH2CTK.js";
40
- import "../chunk-YRS3QZP2.js";
46
+ awaitUnderSpinner
47
+ } from "../chunk-VRXX4D6K.js";
48
+ import "../chunk-SXVHSOTH.js";
49
+ import "../chunk-XQHZPINL.js";
50
+ import "../chunk-JQRJQ4SS.js";
51
+ import "../chunk-TTY6DPJN.js";
41
52
  import "../chunk-WTJ3AY33.js";
42
- import "../chunk-ABAZMMG4.js";
53
+ import "../chunk-WVUDLKIO.js";
43
54
  import {
44
- fetchSeedConfig,
45
- registerExternalSkills,
46
- writeExternalSkills
47
- } from "../chunk-X4SSJZLY.js";
55
+ fetchSeedConfig
56
+ } from "../chunk-25MPBIK3.js";
48
57
  import {
49
58
  promptConfirm
50
- } from "../chunk-JCPANDNR.js";
59
+ } from "../chunk-4AAOOAIN.js";
60
+ import "../chunk-OZXAJNLA.js";
61
+ import {
62
+ hostCompileNotices
63
+ } from "../chunk-ZXKBERQU.js";
51
64
  import {
52
65
  applyMigratedGlobalSources,
53
66
  compileAgentsAllScopes,
67
+ compileProjectScope,
54
68
  detectProject,
55
69
  loadSource,
70
+ movedGlobalAgentInputs,
56
71
  mutateGlobal,
57
- normalizeProjectPath,
72
+ sayCapturedWarnings,
58
73
  writeProjectConfig
59
- } from "../chunk-X37UYIE3.js";
74
+ } from "../chunk-G6UREQ4V.js";
60
75
  import {
61
76
  copyLocalSkills,
62
77
  discoverInstalledSkills,
63
78
  removeCompiledAgents,
64
79
  uninstallPluginSkills
65
- } from "../chunk-2CQNPLVF.js";
80
+ } from "../chunk-HWEKHVLE.js";
66
81
  import {
67
82
  loadAgentDefs
68
- } from "../chunk-B6FSLXYN.js";
69
- import "../chunk-JU4ZGJ7A.js";
70
- import "../chunk-B3Y3QMWI.js";
71
- import {
72
- render
73
- } from "../chunk-JFLVEFFP.js";
83
+ } from "../chunk-PMJWD27C.js";
84
+ import "../chunk-ZR4YPKXQ.js";
85
+ import "../chunk-GE3WKJ6Q.js";
86
+ import "../chunk-MAWNVT2C.js";
87
+ import "../chunk-JFLVEFFP.js";
74
88
  import {
75
89
  formatScopeTag
76
- } from "../chunk-K5ITEA3I.js";
90
+ } from "../chunk-7JNJ52CD.js";
91
+ import {
92
+ providerFlag,
93
+ providerNamedBy,
94
+ refuseAnAmbiguousInstallation
95
+ } from "../chunk-NBXXFIIW.js";
77
96
  import {
78
97
  BaseCommand,
79
- EXIT_CODES
80
- } from "../chunk-JIERYE6B.js";
81
- import "../chunk-NKGYKOB7.js";
82
- import "../chunk-PHCPUQVR.js";
98
+ EXIT_CODES,
99
+ carriedSkillsThatDiffer,
100
+ registerExternalSkills,
101
+ writeExternalSkills
102
+ } from "../chunk-Y3VIRVVE.js";
103
+ import "../chunk-VAPTVR3J.js";
104
+ import "../chunk-RZDXDMT6.js";
83
105
  import {
84
106
  ERROR_MESSAGES,
85
107
  INCOMPLETE_WORK_RECOVERY,
@@ -88,23 +110,28 @@ import {
88
110
  SHARED_CONFIG_APPLY,
89
111
  STATUS_MESSAGES,
90
112
  agentsNotCompiled,
113
+ applySharedConfigHere,
91
114
  authoredHereKept,
92
115
  buildMarketplacePluginRef,
93
116
  carriedSkillsWritten,
94
- claudePluginInstall,
95
- claudePluginUninstall,
96
117
  deleteLocalSkill,
97
118
  detectMigrations,
98
119
  discoverAllPluginSkills,
99
120
  ejectCopyFailureError,
100
121
  executeMigration,
122
+ foldLocalSkillIntoGlobal,
101
123
  getErrorMessage,
102
- globallyInstalledRemoved,
103
- installBaseDir,
124
+ holdsItsOwnInstallation,
125
+ hostAt,
104
126
  isHomeDirectory,
105
- loadProjectConfigFromDir,
127
+ keptAsInstalledGlobally,
128
+ keptUnassigned,
106
129
  localSkillsCopied,
107
130
  migrateLocalSkillScope,
131
+ nothingInstalledToApplyTo,
132
+ plural,
133
+ projectCopyRemoved,
134
+ providerInUse,
108
135
  recompileSummary,
109
136
  resolveInstallPaths,
110
137
  seedToWizardResult,
@@ -112,119 +139,38 @@ import {
112
139
  sharedConfigNeedsTerminal,
113
140
  skippedUnknownAgents,
114
141
  skippedUnknownSkills,
115
- toClaudePluginScope,
116
142
  unplaceableKept,
117
- unresolvedSkillRemovalReasons
118
- } from "../chunk-XPDVAJDH.js";
143
+ unresolvedSkillRemovalReasons,
144
+ wizardNeedsTerminal
145
+ } from "../chunk-A4KDXNOT.js";
119
146
  import {
120
- getCategoryDomain,
121
147
  getSkillById,
122
148
  getSkillDisplayName,
123
149
  matrix,
124
- typedEntries,
125
150
  typedKeys
126
- } from "../chunk-AVK2HEKB.js";
151
+ } from "../chunk-V5WXIM2F.js";
127
152
  import {
128
153
  CLI_COLORS,
129
154
  CLI_INVOKE_COMMAND,
130
155
  EDIT_PROJECT_SETUP_FLAG,
156
+ EDIT_PROJECT_SETUP_MARKETPLACE_FLAG,
131
157
  EJECT_SOURCE,
132
158
  activeAgentNames,
133
159
  activeAgentScopeMap,
134
160
  editorConfigUrl,
135
161
  formatSourceDisplayName,
136
162
  isActiveAt,
137
- orderDomains
138
- } from "../chunk-UITEKY2R.js";
163
+ isGlobalTombstone
164
+ } from "../chunk-ENGYJCTF.js";
139
165
  import "../chunk-OI2H6M5I.js";
140
166
 
141
167
  // src/cli/commands/edit.tsx
142
- import os from "os";
143
168
  import path from "path";
144
169
  import chalk from "chalk";
145
170
  import { Flags } from "@oclif/core";
146
171
  import { difference, indexBy, partition } from "remeda";
147
-
148
- // src/cli/lib/seed/seed-apply.ts
149
- var NOTHING_KEPT = {
150
- authoredSkillIds: [],
151
- unplaceableSkillIds: []
152
- };
153
- function reconcileSharedConfig(options) {
154
- const { decoded, installed } = options;
155
- if (!installed) return { result: decoded, kept: NOTHING_KEPT };
156
- const keptSkills = skillsToKeep(options, installed);
157
- if (keptSkills.length === 0) return { result: decoded, kept: NOTHING_KEPT };
158
- return {
159
- result: withKeptEntries(decoded, installed, keptSkills),
160
- kept: describeKept(options, keptSkills)
161
- };
162
- }
163
- function skillsToKeep(options, installed) {
164
- const named = new Set(options.decoded.skills.map((skill) => skill.id));
165
- return installed.skills.filter(
166
- (skill) => !skill.excluded && !named.has(skill.id) && mayNotRemove(skill, options)
167
- );
168
- }
169
- function mayNotRemove(skill, options) {
170
- return options.authoredHere.has(skill.id) || options.unplaceable.has(skill.id);
171
- }
172
- function describeKept(options, keptSkills) {
173
- const idsKeptFor = (reason) => keptSkills.filter((skill) => reasonKept(skill, options) === reason).map((skill) => skill.id);
174
- return {
175
- authoredSkillIds: idsKeptFor("authored"),
176
- unplaceableSkillIds: idsKeptFor("unplaceable")
177
- };
178
- }
179
- function reasonKept(skill, options) {
180
- return options.authoredHere.has(skill.id) ? "authored" : "unplaceable";
181
- }
182
- function withKeptEntries(decoded, installed, keptSkills) {
183
- return {
184
- ...decoded,
185
- skills: [...decoded.skills, ...keptSkills],
186
- selectedDomains: withKeptDomains(decoded.selectedDomains, keptSkills),
187
- ...decoded.assignedStack !== void 0 && {
188
- assignedStack: withKeptStackRows(decoded.assignedStack, installed.stack, {
189
- keptSkillIds: new Set(keptSkills.map((skill) => skill.id)),
190
- survivingAgents: new Set(decoded.selectedAgents)
191
- })
192
- }
193
- };
194
- }
195
- function withKeptDomains(selected, keptSkills) {
196
- const keptDomains = keptSkills.flatMap((skill) => domainOfSkill(skill.id) ?? []);
197
- const missing = keptDomains.filter((domain) => !selected.includes(domain));
198
- if (missing.length === 0) return selected;
199
- return orderDomains([...selected, ...new Set(missing)]);
200
- }
201
- function domainOfSkill(skillId) {
202
- const category = matrix.skills[skillId]?.category;
203
- return category === void 0 ? void 0 : getCategoryDomain(category);
204
- }
205
- function withKeptStackRows(assigned, installedStack, filter) {
206
- if (!installedStack) return assigned;
207
- const carried = { ...assigned };
208
- for (const [agent, agentStack] of typedEntries(installedStack)) {
209
- if (!filter.survivingAgents.has(agent)) continue;
210
- const rows = keptRowsFor(agentStack, filter.keptSkillIds);
211
- if (typedKeys(rows).length === 0) continue;
212
- carried[agent] = { ...carried[agent], ...rows };
213
- }
214
- return carried;
215
- }
216
- function keptRowsFor(agentStack, keptSkillIds) {
217
- const rows = {};
218
- for (const [category, assignments] of typedEntries(agentStack)) {
219
- const carried = assignments.filter((assignment) => keptSkillIds.has(assignment.id));
220
- if (carried.length > 0) rows[category] = carried;
221
- }
222
- return rows;
223
- }
224
-
225
- // src/cli/commands/edit.tsx
226
172
  import { jsx } from "react/jsx-runtime";
227
- var RECOMPILE_SUBJECT = "agents";
173
+ var RECOMPILE_SUBJECT = "agent";
228
174
  function formatDualScopeTransition(displayName, to) {
229
175
  const isAdd = to === "project";
230
176
  const prefix = isAdd ? "+" : "-";
@@ -251,6 +197,9 @@ function formatAgentScopeChangeLine(agentName, change, dualScopeAgentTransitions
251
197
  function scopeArrow(change) {
252
198
  return ` (${formatScopeTag(change.from)} \u2192 ${formatScopeTag(change.to)})`;
253
199
  }
200
+ function formatValueChangeLine(subject, change, kind) {
201
+ return chalk.hex(CLI_COLORS.WARNING)(` ~ ${subject}`) + chalk.hex(CLI_COLORS.NEUTRAL)(` (${kind}: ${change.from} \u2192 ${change.to})`);
202
+ }
254
203
  function loadedSourceLabel(sourceResult) {
255
204
  return sourceResult.marketplace ?? sourceResult.sourceConfig.source;
256
205
  }
@@ -259,55 +208,73 @@ function resolveEditRoot(installation, cwd, setupRequested) {
259
208
  const isGlobal = isHomeDirectory(dir);
260
209
  return { dir, isGlobal, isProjectSetup: setupRequested && !isGlobal };
261
210
  }
262
- function globalScopePlan(changes, kept) {
263
- const sections = removalSections(changes.removedSkills, changes.removedAgents);
211
+ function sharedConfigPlan(changes, kept) {
212
+ const dropped = droppedProjectHalves(changes);
213
+ const skillLines = [
214
+ ...changes.removedSkills.map(skillLabel),
215
+ ...dropped.skillIds.map(droppedSkillLine)
216
+ ];
217
+ const agentLines = [...changes.removedAgents, ...dropped.agentNames.map(projectCopyRemoved)];
218
+ const sections = removalSections(skillLines, agentLines);
264
219
  return { heading: planHeading(sections), sections, statements: kept };
265
220
  }
266
- function projectScopePlan(changes, kept, installed, otherProjects) {
267
- const { here, global } = splitRemovalsByScope(changes, installed);
268
- const sections = [
269
- ...removalSections(here.skills, here.agents),
270
- ...globalRemovalSections(global.skills, global.agents)
271
- ];
272
- return {
273
- heading: planHeading(sections),
274
- sections,
275
- statements: [...globalReachStatement(global, otherProjects), ...kept]
276
- };
277
- }
278
- function splitRemovalsByScope(changes, installed) {
279
- const isGlobalSkill = (id) => installed.skills.some((skill) => skill.id === id && isActiveAt(skill, "global"));
280
- const isGlobalAgent = (name) => installed.agents.some((agent) => agent.name === name && isActiveAt(agent, "global"));
281
- const [globalSkills, projectSkills] = partition(changes.removedSkills, isGlobalSkill);
282
- const [globalAgents, projectAgents] = partition(changes.removedAgents, isGlobalAgent);
283
- return {
284
- here: { skills: projectSkills, agents: projectAgents },
285
- global: { skills: globalSkills, agents: globalAgents }
286
- };
221
+ function droppedSkillLine(skillId) {
222
+ return projectCopyRemoved(skillLabel(skillId));
287
223
  }
288
224
  function removalSections(skills, agents) {
289
225
  return [
290
- { label: SHARED_CONFIG_APPLY.SKILLS_HEADING, items: skills.map(skillLabel) },
291
- { label: SHARED_CONFIG_APPLY.AGENTS_HEADING, items: [...agents] }
292
- ].filter((section) => section.items.length > 0);
293
- }
294
- function globalRemovalSections(skills, agents) {
295
- return [
296
- { label: SHARED_CONFIG_APPLY.GLOBAL_SKILLS_HEADING, items: skills.map(skillLabel) },
297
- { label: SHARED_CONFIG_APPLY.GLOBAL_AGENTS_HEADING, items: [...agents] }
226
+ { label: SHARED_CONFIG_APPLY.SKILLS_HEADING, items: skills },
227
+ { label: SHARED_CONFIG_APPLY.AGENTS_HEADING, items: agents }
298
228
  ].filter((section) => section.items.length > 0);
299
229
  }
300
- function globalReachStatement(global, otherProjects) {
301
- if (global.skills.length === 0 && global.agents.length === 0) return [];
302
- return [globallyInstalledRemoved(otherProjects)];
230
+ function droppedProjectHalves(changes) {
231
+ const droppedSkills = changes.collapsedPairs.filter((pair) => !pair.folded);
232
+ const droppedAgents = [...changes.agentScopeChanges].filter(
233
+ ([name, change]) => change.to === "global" && changes.dualScopeAgentTransitions.has(name)
234
+ );
235
+ return {
236
+ skillIds: droppedSkills.map(({ projectHalf }) => projectHalf.id),
237
+ agentNames: droppedAgents.map(([name]) => name)
238
+ };
303
239
  }
304
240
  function planHeading(sections) {
305
241
  if (sections.length === 0) return SHARED_CONFIG_APPLY.NOTHING_REMOVED;
306
242
  return SHARED_CONFIG_APPLY.PREVIEW_HEADING;
307
243
  }
308
- function skillLabel(skillId) {
309
- const displayName = getSkillDisplayName(skillId);
310
- return displayName === skillId ? skillId : `${displayName} (${skillId})`;
244
+ function compilesGlobalScope(producer, editRoot, written) {
245
+ if (editRoot.isGlobal || producer === "wizard") return true;
246
+ return movedGlobalAgentInputs(written);
247
+ }
248
+ function withReassignments(changes, result, installedStack, editRoot) {
249
+ const { assignedStack } = result;
250
+ if (assignedStack === void 0) return { ...changes, reassignedAgents: [] };
251
+ const ownedHere = (agent) => editRoot.isGlobal || isActiveAt(agent, "project");
252
+ const countedAsAdded = (agent) => changes.addedAgents.includes(agent.name);
253
+ const rowsMoved = (agent) => !sameAssignments(assignedStack[agent.name], installedStack?.[agent.name]);
254
+ const reassigned = result.agentConfigs.filter(
255
+ (agent) => ownedHere(agent) && !countedAsAdded(agent) && rowsMoved(agent)
256
+ );
257
+ return { ...changes, reassignedAgents: reassigned.map((agent) => agent.name) };
258
+ }
259
+ function applyArrivals(changes, result) {
260
+ const changedSkills = /* @__PURE__ */ new Set([
261
+ ...changes.addedSkills,
262
+ ...changes.sourceChanges.keys(),
263
+ ...changes.scopeChanges.keys()
264
+ ]);
265
+ const changedAgents = /* @__PURE__ */ new Set([
266
+ ...changes.addedAgents,
267
+ ...changes.agentScopeChanges.keys(),
268
+ ...changes.tuningChanges.keys(),
269
+ ...changes.reassignedAgents
270
+ ]);
271
+ const dropped = droppedProjectHalves(changes);
272
+ const skillArrives = (skill) => changedSkills.has(skill.id) && !dropped.skillIds.includes(skill.id);
273
+ const agentArrives = (agent) => changedAgents.has(agent.name) && !dropped.agentNames.includes(agent.name);
274
+ return arrivalsByScope(
275
+ result.skills.filter(skillArrives),
276
+ result.agentConfigs.filter(agentArrives)
277
+ );
311
278
  }
312
279
  function keptStatements(kept) {
313
280
  return [...authorshipStatement(kept), ...catalogueStatement(kept)];
@@ -320,9 +287,20 @@ function catalogueStatement(kept) {
320
287
  if (kept.unplaceableSkillIds.length === 0) return [];
321
288
  return [unplaceableKept(kept.unplaceableSkillIds)];
322
289
  }
323
- function applyAuthority(producer, editRoot) {
324
- if (editRoot.isGlobal) return "all";
325
- return producer === "shared" ? "all" : "owned";
290
+ function unassignedStatement(unassigned) {
291
+ if (unassigned.length === 0) return [];
292
+ return [
293
+ unassigned.map(({ skillId, agentName, category }) => keptUnassigned(skillId, agentName, category)).join("\n")
294
+ ];
295
+ }
296
+ function keptAsInstalledStatement(held, revisedCarried) {
297
+ const skillIds = [...held.keptAsInstalled.skillIds, ...revisedCarried];
298
+ const { agentNames } = held.keptAsInstalled;
299
+ if (skillIds.length === 0 && agentNames.length === 0) return [];
300
+ return [keptAsInstalledGlobally(skillIds, agentNames)];
301
+ }
302
+ function applyAuthority(editRoot) {
303
+ return editRoot.isGlobal ? "all" : "owned";
326
304
  }
327
305
  var Edit = class _Edit extends BaseCommand {
328
306
  static summary = "Edit skills in the plugin";
@@ -347,14 +325,20 @@ var Edit = class _Edit extends BaseCommand {
347
325
  default: false
348
326
  }),
349
327
  from: Flags.string({
350
- description: "Apply a configuration shared from agentsinc.sh by its id, removing whatever it leaves out",
328
+ description: "Apply a configuration shared from agentsinc.sh by its id, removing whatever it leaves out \u2014 from a project, only the project's own entries",
351
329
  helpValue: "<id>"
352
330
  }),
353
331
  [EDIT_PROJECT_SETUP_FLAG]: Flags.boolean({
354
332
  description: "Internal: this run continues an `init` project setup",
355
333
  default: false,
356
334
  hidden: true
357
- })
335
+ }),
336
+ [EDIT_PROJECT_SETUP_MARKETPLACE_FLAG]: Flags.string({
337
+ description: "Internal: the marketplace `init --marketplace` named for that project setup",
338
+ hidden: true,
339
+ dependsOn: [EDIT_PROJECT_SETUP_FLAG]
340
+ }),
341
+ provider: providerFlag()
358
342
  };
359
343
  /**
360
344
  * The command in two statements: do the work, then answer for it.
@@ -371,11 +355,18 @@ var Edit = class _Edit extends BaseCommand {
371
355
  async applyEdit() {
372
356
  const { flags } = await this.parse(_Edit);
373
357
  const cwd = process.cwd();
374
- if (flags.ui && flags.from !== void 0) return this.openSharedInEditor(flags.from);
358
+ if (flags.ui && flags.from !== void 0) return this.openSharedInEditor(flags.from, cwd);
359
+ await refuseAnAmbiguousInstallation(
360
+ cwd,
361
+ "edit",
362
+ providerNamedBy(flags.provider),
363
+ (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS })
364
+ );
375
365
  await this.ensureConfigReadable(cwd);
366
+ await this.refuseUnofferablePlacements(cwd);
376
367
  if (flags.ui) return this.openInEditor(cwd);
377
368
  const payload = flags.from === void 0 ? null : await this.fetchSharedConfigOrFail(flags.from);
378
- const context = await this.loadContextUnderSpinner();
369
+ const context = await this.loadContextUnderSpinner(flags[EDIT_PROJECT_SETUP_MARKETPLACE_FLAG]);
379
370
  const editRoot = resolveEditRoot(context.installation, cwd, flags[EDIT_PROJECT_SETUP_FLAG]);
380
371
  await this.ensureSavedSkillsReadable(
381
372
  context.projectConfig?.skills ?? [],
@@ -396,26 +387,28 @@ var Edit = class _Edit extends BaseCommand {
396
387
  agentConfigs: activeNewAgents
397
388
  };
398
389
  const filteredOldConfig = context.projectConfig ? { ...context.projectConfig, skills: activeOldSkills, agents: activeOldAgents } : null;
399
- const changes = detectConfigChanges(filteredOldConfig, filteredResult, {
400
- newSkills: result.skills,
401
- oldSkills: context.projectConfig?.skills ?? [],
402
- newAgents: result.agentConfigs,
403
- oldAgents: context.projectConfig?.agents ?? []
404
- });
405
- if (selection.producer === "shared") {
406
- await this.confirmSharedConfigOrCancel(
407
- changes,
408
- selection.kept,
409
- { skills: activeOldSkills, agents: activeOldAgents },
410
- editRoot
411
- );
412
- await this.writeCarriedSkills(selection.carried);
413
- }
414
- const authority = applyAuthority(selection.producer, editRoot);
390
+ const planned = withReassignments(
391
+ detectConfigChanges(filteredOldConfig, filteredResult, {
392
+ newSkills: result.skills,
393
+ oldSkills: context.projectConfig?.skills ?? [],
394
+ newAgents: result.agentConfigs,
395
+ oldAgents: context.projectConfig?.agents ?? []
396
+ }),
397
+ filteredResult,
398
+ context.projectConfig?.stack,
399
+ editRoot
400
+ );
401
+ const rewritten = selection.producer === "shared" ? await this.confirmAndWriteCarried(selection, planned, filteredResult) : [];
402
+ const changes = {
403
+ ...planned,
404
+ rewrittenSkills: difference(rewritten, planned.addedSkills)
405
+ };
406
+ const authority = applyAuthority(editRoot);
415
407
  if (!hasAnyChanges(changes)) {
416
408
  this.log(chalk.hex(CLI_COLORS.NEUTRAL)("No changes made."));
417
409
  if (!editRoot.isProjectSetup) return;
418
- await this.writeConfigAndCompile(result, context, editRoot, authority);
410
+ await this.writeConfigAndCompile(result, context, editRoot, authority, selection.producer);
411
+ await this.reportWhatThisHostCannotCarry(editRoot);
419
412
  this.logCompletionSummary(changes);
420
413
  return;
421
414
  }
@@ -445,16 +438,21 @@ var Edit = class _Edit extends BaseCommand {
445
438
  context
446
439
  );
447
440
  await this.applyScopeChanges(changes, filteredResult, context, editRoot);
441
+ await this.applyCollapsedPairs(changes, filteredResult, context, editRoot);
448
442
  await this.applySourceChanges(changes, activeOldSkills, editRoot, migratedSkillIds);
449
443
  await this.applyPluginChanges(changes, filteredResult, activeOldSkills, context, editRoot);
450
444
  await this.copyNewLocalSkills(changes, filteredResult, context, editRoot);
451
445
  await this.removeDeletedLocalSkills(changes, activeOldSkills, editRoot);
452
- await this.writeConfigAndCompile(result, context, editRoot, authority);
446
+ await this.writeConfigAndCompile(result, context, editRoot, authority, selection.producer);
453
447
  await this.cleanupStaleAgentFiles(changes, activeOldAgents, editRoot);
448
+ await this.reportWhatThisHostCannotCarry(editRoot);
454
449
  this.logCompletionSummary(changes);
455
450
  }
456
451
  /** The interactive producer: open the wizard on what is installed, return what was chosen. */
457
452
  async selectionFromWizard(context, editRoot) {
453
+ if (!process.stdin.isTTY) {
454
+ this.error(wizardNeedsTerminal("edit"), { exit: EXIT_CODES.ERROR });
455
+ }
458
456
  const result = await this.runEditWizard(context, editRoot);
459
457
  if (!result) return null;
460
458
  return { producer: "wizard", result };
@@ -470,9 +468,12 @@ var Edit = class _Edit extends BaseCommand {
470
468
  * catalogue cannot place, because a destructive apply removes on intent and never on its own
471
469
  * inability. Both are disclosed in the confirm rather than silently excused.
472
470
  *
473
- * A globally installed entry is NOT one of them. It is removable from here, and what its scope
474
- * changes is who the removal reaches — which the confirm names, rather than this putting the
475
- * entry back and calling the reach impossible.
471
+ * From a project the global install comes back too, whole: it is one installation every project
472
+ * on the machine reads, so a project run only ADDS to it (owner ruling 2026-10-02). Every global
473
+ * entry the configuration leaves out is put back as installed, every one it states otherwise is
474
+ * held as installed and named in the confirm, and only the global entries the global install
475
+ * lacks arrive — a skill with its rows, on a global sub-agent already there too. At the home
476
+ * directory the run IS the global install, so nothing is held there.
476
477
  */
477
478
  async selectionFromSharedConfig(payload, context, editRoot) {
478
479
  const { matrix: sourceMatrix } = context.sourceResult;
@@ -482,22 +483,38 @@ var Edit = class _Edit extends BaseCommand {
482
483
  sourceMatrix
483
484
  );
484
485
  this.refuseProjectScopedContentAtHome(result, editRoot.dir);
485
- if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));
486
- if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));
486
+ const unplaceable = new Set(skippedSkillIds);
487
487
  const reconciled = reconcileSharedConfig({
488
- decoded: result,
488
+ decoded: withUnplaceableAssignees(result, context.projectConfig, payload, unplaceable),
489
489
  installed: context.projectConfig,
490
490
  authoredHere: await this.readAuthoredHere(context.projectConfig, editRoot.dir),
491
- // The ids the decode above could not place. They are the skips just reported, read as
492
- // what STAYS rather than as what did not arrive: the payload named them, so their absence
493
- // from the decode is this catalogue's limit and not an instruction to delete anything.
494
- unplaceable: new Set(skippedSkillIds)
491
+ unplaceable
495
492
  });
493
+ const held = restoreInstalledGlobal(
494
+ reconciled.result,
495
+ editRoot.isGlobal ? null : await readInstalledGlobal(editRoot.dir)
496
+ );
497
+ const arrivingCarried = notInstalledGlobally(carried, held);
498
+ await this.refuseSharedConfigBeforeAsking(
499
+ held.result,
500
+ arrivingCarried,
501
+ editRoot.dir,
502
+ context.sourceResult
503
+ );
504
+ const heldGlobally = difference(carried, arrivingCarried);
505
+ const revisedGlobally = await carriedSkillsThatDiffer(heldGlobally);
506
+ sayCapturedWarnings(context.startupMessages);
507
+ if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));
508
+ if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));
496
509
  return {
497
510
  producer: "shared",
498
- result: reconciled.result,
499
- kept: keptStatements(reconciled.kept),
500
- carried
511
+ result: held.result,
512
+ kept: [
513
+ ...keptStatements(reconciled.kept),
514
+ ...unassignedStatement(reconciled.unassigned),
515
+ ...keptAsInstalledStatement(held, revisedGlobally)
516
+ ],
517
+ carried: arrivingCarried
501
518
  };
502
519
  }
503
520
  /**
@@ -521,11 +538,17 @@ var Edit = class _Edit extends BaseCommand {
521
538
  /**
522
539
  * The id, fetched — or the run refused before it is.
523
540
  *
524
- * The terminal question is answered first because nothing in the payload can change its
525
- * answer: an apply that cannot be confirmed is over before the store is asked, and a refusal
526
- * that had already spent a round trip would be describing work it never intended to do.
541
+ * Two questions are answered first, because nothing in the payload can change either answer:
542
+ * an apply with nothing to apply to, or that cannot be confirmed, is over before the store is
543
+ * asked, and a refusal that had already spent a round trip would be describing work it never
544
+ * intended to do. Whether anything is installed comes before the terminal: the terminal
545
+ * refusal's way on is this same command from a terminal, which in a folder with nothing
546
+ * installed would only refuse again.
527
547
  */
528
548
  async fetchSharedConfigOrFail(id) {
549
+ if (!await detectProject()) {
550
+ this.error(nothingInstalledToApplyTo(id), { exit: EXIT_CODES.ERROR });
551
+ }
529
552
  if (!process.stdin.isTTY) {
530
553
  this.error(sharedConfigNeedsTerminal(id), { exit: EXIT_CODES.ERROR });
531
554
  }
@@ -562,11 +585,20 @@ var Edit = class _Edit extends BaseCommand {
562
585
  this.handleError(error);
563
586
  }
564
587
  }
588
+ /**
589
+ * Confirms a shared configuration, then writes the skills it brought with it — answering with
590
+ * those whose files now read differently.
591
+ */
592
+ async confirmAndWriteCarried(selection, planned, result) {
593
+ await this.confirmSharedConfigOrCancel(planned, selection.kept, applyArrivals(planned, result));
594
+ return this.writeCarriedSkills(selection.carried);
595
+ }
565
596
  /** Writes the skills the configuration brought with it, and says which they were. */
566
597
  async writeCarriedSkills(carried) {
567
- if (carried.length === 0) return;
568
- await writeExternalSkills(carried);
598
+ if (carried.length === 0) return [];
599
+ const rewritten = await writeExternalSkills(carried);
569
600
  this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));
601
+ return rewritten;
570
602
  }
571
603
  /**
572
604
  * Shows what applying this configuration takes away, and stops the run unless a person says
@@ -577,18 +609,15 @@ var Edit = class _Edit extends BaseCommand {
577
609
  * honesty: nothing is refused over an entry this run cannot remove, and nothing is silent
578
610
  * about one either.
579
611
  *
580
- * WHICH plan is built is decided here and only here, on the directory the run was started in.
581
- * Inside the global installation the scope was chosen and is obvious, so the ordinary confirm
582
- * is the whole of the gate; inside a project a global removal reaches projects nobody here is
583
- * looking at, so it is shown apart and the reach is named.
612
+ * Above it go the two lists every `--from` install prints — what the apply adds or changes in
613
+ * this project, and in the global install — so the question is asked about the whole of what a
614
+ * yes does, not only about what it takes away.
584
615
  */
585
- async confirmSharedConfigOrCancel(changes, kept, installed, editRoot) {
586
- const plan = editRoot.isGlobal ? globalScopePlan(changes, kept) : projectScopePlan(
587
- changes,
588
- kept,
589
- installed,
590
- await this.otherRegisteredProjects(editRoot.dir)
591
- );
616
+ async confirmSharedConfigOrCancel(changes, kept, arrivals) {
617
+ const plan = sharedConfigPlan(changes, kept);
618
+ for (const line of arrivalLines(arrivals)) {
619
+ this.log(line);
620
+ }
592
621
  const outcome = await promptConfirm(({ onConfirm, onCancel }) => /* @__PURE__ */ jsx(
593
622
  RemovalPlanConfirm,
594
623
  {
@@ -605,25 +634,16 @@ var Edit = class _Edit extends BaseCommand {
605
634
  this.error("Cancelled", { exit: EXIT_CODES.CANCELLED });
606
635
  }
607
636
  /**
608
- * Every registered project but this one — the blast radius a global removal actually has.
637
+ * Refuses a configuration whose own host cannot place what it asks for, before the wizard runs.
609
638
  *
610
- * Read from the GLOBAL config rather than from `context.projectConfig`: `projects[]` is the
611
- * registry the fan-out itself walks, and a project's own config never carries it, so taking
612
- * the list from anywhere else would let the confirm name a set the propagation does not.
613
- *
614
- * Best-effort by nature. The list exists to be DISCLOSED, so a home directory that cannot be
615
- * read leaves the disclosure counting nobody rather than failing an apply — and the statement
616
- * it produces then is the one that says no other project is registered.
639
+ * `compile` asks the same question of the same roster and `update` asks it too. `edit` is the
640
+ * command that REWRITES the file, so letting it through would mean a user curating a
641
+ * configuration no command will act on — and then saving it back, with the unofferable row
642
+ * carried forward because nothing on the edit path had any reason to drop it.
617
643
  */
618
- async otherRegisteredProjects(editRoot) {
619
- try {
620
- const global = await loadProjectConfigFromDir(os.homedir());
621
- const here = normalizeProjectPath(editRoot);
622
- return (global?.config.projects ?? []).filter((projectDir) => projectDir !== here);
623
- } catch (error) {
624
- this.warn(`Could not tell which projects share this install: ${getErrorMessage(error)}`);
625
- return [];
626
- }
644
+ async refuseUnofferablePlacements(cwd) {
645
+ const [finding] = await unofferablePlacementsFound(cwd);
646
+ if (finding !== void 0) this.error(finding, { exit: EXIT_CODES.ERROR });
627
647
  }
628
648
  /**
629
649
  * The outbound half of the editor round trip: this installation, minted as a configuration
@@ -637,37 +657,37 @@ var Edit = class _Edit extends BaseCommand {
637
657
  * Nothing on disk is touched. A configuration is read, not rewritten, so a run that changed
638
658
  * anything here would be editing the project on the way to offering to edit it.
639
659
  */
660
+ async openInEditor(projectDir) {
661
+ const prepared = await seedPayloadForInstallation(projectDir);
662
+ if (!prepared.ok) {
663
+ this.error(prepared.error, { exit: EXIT_CODES.ERROR });
664
+ }
665
+ this.log(`Opening ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);
666
+ const published = await publishSeedConfig(prepared.payload);
667
+ if (!published.ok) {
668
+ this.error(published.error, { exit: EXIT_CODES.ERROR });
669
+ }
670
+ await this.handToBrowser(published.id);
671
+ }
640
672
  /**
641
673
  * An id somebody shared, opened rather than applied.
642
674
  *
643
675
  * The counterpart of `openInEditor` above and deliberately not a variant of it: that one MINTS,
644
676
  * because an installation is not yet a configuration the store holds. An id already is one, so
645
- * there is nothing to publish, nothing to read off disk, and no way for this to fail except the
646
- * browser refusing to launch — which is a warning beside a link that still works.
677
+ * there is nothing to publish, and no way for this to fail except the browser refusing to launch
678
+ * — which is a warning beside a link that still works.
647
679
  *
648
680
  * `--from` without `--ui` remains the destructive apply. Looking and applying are the two
649
681
  * things a recipient can do with an id, and this is the one that changes nothing.
650
682
  */
651
- async openSharedInEditor(id) {
683
+ async openSharedInEditor(id, cwd) {
652
684
  const url = editorConfigUrl(id);
653
685
  this.log(`Open it at ${url}`);
654
- this.log(`To apply it here instead, run '${CLI_INVOKE_COMMAND} edit --from ${id}'.`);
686
+ this.log(applySharedConfigHere(id, await holdsItsOwnInstallation(cwd)));
655
687
  if (!process.stdin.isTTY) return;
656
688
  const opened = await openUrl(url);
657
689
  if (!opened.ok) this.warn(opened.error);
658
690
  }
659
- async openInEditor(projectDir) {
660
- const prepared = await seedPayloadForInstallation(projectDir);
661
- if (!prepared.ok) {
662
- this.error(prepared.error, { exit: EXIT_CODES.ERROR });
663
- }
664
- this.log(`Opening ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);
665
- const published = await publishSeedConfig(prepared.payload);
666
- if (!published.ok) {
667
- this.error(published.error, { exit: EXIT_CODES.ERROR });
668
- }
669
- await this.handToBrowser(published.id);
670
- }
671
691
  /**
672
692
  * The link, printed first and opened second.
673
693
  *
@@ -690,25 +710,20 @@ var Edit = class _Edit extends BaseCommand {
690
710
  if (!opened.ok) this.warn(opened.error);
691
711
  }
692
712
  /**
693
- * The load below, behind a spinner that comes down whichever way the await ends.
694
- *
695
- * The cleanup is a `finally` because all three of `loadContext`'s refusals are raised
696
- * while this spinner is mounted, and oclif would otherwise paint its error under an Ink
697
- * tree still repainting over it. Never a `catch`: the throw reaches oclif untouched, or
698
- * both the error rendering and the pinned exit codes change with it.
713
+ * The load below, behind a spinner that comes down whichever way the await ends — all
714
+ * three of `loadContext`'s refusals are raised while it is mounted.
699
715
  */
700
- async loadContextUnderSpinner() {
701
- const { unmount, clear: clearSpinner } = render(
702
- /* @__PURE__ */ jsx(Spinner, { label: STATUS_MESSAGES.LOADING_SKILLS })
716
+ async loadContextUnderSpinner(setupMarketplace) {
717
+ return awaitUnderSpinner(
718
+ STATUS_MESSAGES.LOADING_SKILLS,
719
+ () => this.loadContext(setupMarketplace)
703
720
  );
704
- try {
705
- return await this.loadContext();
706
- } finally {
707
- clearSpinner();
708
- unmount();
709
- }
710
721
  }
711
- async loadContext() {
722
+ /**
723
+ * @param setupMarketplace - What `init --marketplace` named for the project setup this run
724
+ * continues. Absent, the catalogue is the one the installation stored.
725
+ */
726
+ async loadContext(setupMarketplace) {
712
727
  const detected = await detectProject();
713
728
  if (!detected) {
714
729
  this.error(ERROR_MESSAGES.NO_INSTALLATION, {
@@ -720,13 +735,17 @@ var Edit = class _Edit extends BaseCommand {
720
735
  let sourceResult;
721
736
  let startupMessages = [];
722
737
  try {
723
- const loaded = await loadSource({ projectDir, captureStartupMessages: true });
738
+ const loaded = await loadSource({
739
+ projectDir,
740
+ ...setupMarketplace !== void 0 && { sourceFlag: setupMarketplace },
741
+ captureStartupMessages: true
742
+ });
724
743
  sourceResult = loaded.sourceResult;
725
744
  startupMessages = loaded.startupMessages;
726
745
  const sourceInfo = sourceResult.isLocal ? "local" : sourceResult.sourceConfig.sourceOrigin;
727
746
  startupMessages.push({
728
747
  level: "info",
729
- text: `Loaded ${Object.keys(matrix.skills).length} skills (${sourceInfo})`
748
+ text: `Loaded ${plural(Object.keys(matrix.skills).length, "skill")} (${sourceInfo})`
730
749
  });
731
750
  } catch (error) {
732
751
  this.handleError(error);
@@ -744,7 +763,7 @@ var Edit = class _Edit extends BaseCommand {
744
763
  currentSkillIds = [...mergedIds];
745
764
  startupMessages.push({
746
765
  level: "info",
747
- text: `Found ${currentSkillIds.length} installed skills`
766
+ text: `Found ${plural(currentSkillIds.length, "installed skill")}`
748
767
  });
749
768
  } catch (error) {
750
769
  this.handleError(error);
@@ -755,7 +774,8 @@ var Edit = class _Edit extends BaseCommand {
755
774
  projectDir,
756
775
  sourceResult,
757
776
  startupMessages,
758
- currentSkillIds
777
+ currentSkillIds,
778
+ ...setupMarketplace !== void 0 && sourceResult.marketplace !== void 0 && { setupMarketplace: sourceResult.marketplace }
759
779
  };
760
780
  }
761
781
  async runEditWizard(context, editRoot) {
@@ -771,7 +791,10 @@ var Edit = class _Edit extends BaseCommand {
771
791
  installedSkillIds: currentSkillIds,
772
792
  ...projectConfig?.skills !== void 0 && { installedSkillConfigs: projectConfig.skills },
773
793
  ...projectConfig?.agents !== void 0 && { installedAgentConfigs: projectConfig.agents },
774
- isEditingFromGlobalScope: editRoot.isGlobal
794
+ isEditingFromGlobalScope: editRoot.isGlobal,
795
+ ...context.setupMarketplace !== void 0 && {
796
+ setupMarketplace: context.setupMarketplace
797
+ }
775
798
  },
776
799
  props: {
777
800
  version: this.config.version,
@@ -840,7 +863,7 @@ var Edit = class _Edit extends BaseCommand {
840
863
  loadAgents: async () => (await loadAgentDefs()).agents
841
864
  }
842
865
  );
843
- this.reportPropagatedRecompile(report);
866
+ this.reportFanOut(report);
844
867
  } catch (error) {
845
868
  this.reportIncompleteWork(
846
869
  `Could not record global origin change: ${getErrorMessage(error)}`,
@@ -858,7 +881,10 @@ var Edit = class _Edit extends BaseCommand {
858
881
  scopeChanges,
859
882
  agentScopeChanges,
860
883
  dualScopeSkillTransitions,
861
- dualScopeAgentTransitions
884
+ dualScopeAgentTransitions,
885
+ tuningChanges,
886
+ reassignedAgents,
887
+ rewrittenSkills
862
888
  } = changes;
863
889
  this.log(`
864
890
  ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
@@ -901,10 +927,26 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
901
927
  for (const [agentName, change] of agentScopeChanges) {
902
928
  this.log(formatAgentScopeChangeLine(agentName, change, dualScopeAgentTransitions));
903
929
  }
930
+ for (const [agentName, change] of tuningChanges) {
931
+ this.log(formatValueChangeLine(agentName, change, "agent"));
932
+ }
933
+ for (const agentName of reassignedAgents) {
934
+ this.log(
935
+ chalk.hex(CLI_COLORS.WARNING)(` ~ ${agentName}`) + chalk.hex(CLI_COLORS.NEUTRAL)(" (agent: skills reassigned)")
936
+ );
937
+ }
938
+ for (const skillId of rewrittenSkills) {
939
+ this.log(
940
+ chalk.hex(CLI_COLORS.WARNING)(` ~ ${getSkillDisplayName(skillId)}`) + chalk.hex(CLI_COLORS.NEUTRAL)(" (skill: files rewritten)")
941
+ );
942
+ }
904
943
  this.log("");
905
944
  }
906
- async applyMigrations(_changes, filteredResult, activeOldSkills, context, editRoot) {
907
- const migrationPlan = detectMigrations(activeOldSkills, filteredResult.skills);
945
+ async applyMigrations(changes, filteredResult, activeOldSkills, context, editRoot) {
946
+ const migrationPlan = detectMigrations(
947
+ withMaskedGlobalsRestored(activeOldSkills, changes.collapsedPairs),
948
+ filteredResult.skills
949
+ );
908
950
  const migratedSkillIds = /* @__PURE__ */ new Set([
909
951
  ...migrationPlan.toEject.map((m) => m.id),
910
952
  ...migrationPlan.toPlugin.map((m) => m.id)
@@ -915,7 +957,11 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
915
957
  }
916
958
  if (migrationPlan.toPlugin.length > 0) {
917
959
  this.logModeSwitch(migrationPlan.toPlugin.length, INSTALL_MODE_DESCRIPTIONS.plugin);
918
- await this.requireMarketplaceOrExit(context.sourceResult, "migrate skills to plugin mode");
960
+ await this.requireMarketplaceOrExit(
961
+ context.sourceResult,
962
+ "migrate skills to plugin mode",
963
+ hostAt(editRoot.dir)
964
+ );
919
965
  this.announcePluginInstall();
920
966
  }
921
967
  const migrationResult = await executeMigration(
@@ -961,8 +1007,13 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
961
1007
  logModeSwitch(count, modeDescription) {
962
1008
  this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Switching ${count} skill(s) to ${modeDescription}`));
963
1009
  }
1010
+ /**
1011
+ * The scope moves this edit made, on disk. A collapsed `[P][G]` pair is not one of them: its
1012
+ * project half is dropped or folded ({@link applyCollapsedPairs}), and moving every collapse is
1013
+ * what wrote a dropped copy over the global install.
1014
+ */
964
1015
  async applyScopeChanges(changes, filteredResult, context, editRoot) {
965
- const { scopeChanges } = changes;
1016
+ const scopeChanges = scopeMovesOf(changes);
966
1017
  for (const [skillId, change] of scopeChanges) {
967
1018
  const skillConfig = filteredResult.skills.find((s) => s.id === skillId);
968
1019
  if (skillConfig?.origin === EJECT_SOURCE) {
@@ -976,7 +1027,8 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
976
1027
  if (!hasPluginScopeChanges) return;
977
1028
  const marketplace = await this.requireMarketplaceOrExit(
978
1029
  context.sourceResult,
979
- "migrate plugin skill scopes"
1030
+ "migrate plugin skill scopes",
1031
+ hostAt(editRoot.dir)
980
1032
  );
981
1033
  const pluginScopeResult = await migratePluginSkillScopes(
982
1034
  scopeChanges,
@@ -991,6 +1043,63 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
991
1043
  );
992
1044
  }
993
1045
  }
1046
+ /**
1047
+ * The project's own half of each `[P][G]` pair this edit collapsed. A Local copy `s` folded into
1048
+ * a Local global install moves there, edits included, replacing the global copy every project
1049
+ * reads. Every other half is removed at project scope and nowhere else: its ejected copy deleted,
1050
+ * or its project-scope plugin registration uninstalled.
1051
+ *
1052
+ * The global install's MODE is {@link applyMigrations}' to change, and it changes only when the
1053
+ * collapse carried a new install mode with it — a fold into a plugin installs the plugin there.
1054
+ *
1055
+ * The uninstall is diagnostic, as every plugin uninstall here is: the config no longer names the
1056
+ * registration, so one left behind is untidy rather than wrong.
1057
+ */
1058
+ async applyCollapsedPairs(changes, filteredResult, context, editRoot) {
1059
+ const [foldedCopies, removedPairs] = partition(
1060
+ changes.collapsedPairs,
1061
+ (pair) => foldsItsCopyIntoGlobal(pair, filteredResult.skills)
1062
+ );
1063
+ const [ejectedHalves, pluginHalves] = partition(
1064
+ removedPairs.map(({ projectHalf }) => projectHalf),
1065
+ (half) => half.origin === EJECT_SOURCE
1066
+ );
1067
+ for (const { projectHalf } of foldedCopies) {
1068
+ await foldLocalSkillIntoGlobal(editRoot.dir, projectHalf.id);
1069
+ }
1070
+ for (const half of ejectedHalves) {
1071
+ await deleteLocalSkill(editRoot.dir, half.id, half.scope);
1072
+ }
1073
+ await this.uninstallProjectPluginHalves(
1074
+ pluginHalves,
1075
+ context.sourceResult.marketplace,
1076
+ editRoot
1077
+ );
1078
+ }
1079
+ /** The project-scope registrations of collapsed pairs' plugin halves, uninstalled and reported. */
1080
+ async uninstallProjectPluginHalves(pluginHalves, marketplace, editRoot) {
1081
+ if (pluginHalves.length === 0) return;
1082
+ if (marketplace === void 0) {
1083
+ for (const half of pluginHalves) {
1084
+ this.warn(`Could not uninstall this project's plugin for ${half.id}: no marketplace`);
1085
+ }
1086
+ return;
1087
+ }
1088
+ const uninstallResult = await uninstallPluginSkills(
1089
+ pluginHalves.map((half) => half.id),
1090
+ pluginHalves,
1091
+ marketplace,
1092
+ editRoot.dir
1093
+ );
1094
+ if (uninstallResult.uninstalled.length > 0) {
1095
+ this.log(
1096
+ chalk.hex(CLI_COLORS.NEUTRAL)(`Removed ${uninstallResult.uninstalled.length} plugin(s)`)
1097
+ );
1098
+ }
1099
+ for (const item of uninstallResult.failed) {
1100
+ this.warn(`Failed to uninstall plugin ${item.id}: ${item.error}`);
1101
+ }
1102
+ }
994
1103
  async applySourceChanges(changes, activeOldSkills, editRoot, migratedSkillIds) {
995
1104
  const { sourceChanges } = changes;
996
1105
  for (const [skillId, change] of sourceChanges) {
@@ -999,8 +1108,7 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
999
1108
  }
1000
1109
  if (change.from === EJECT_SOURCE) {
1001
1110
  const oldSkill = activeOldSkills.find((s) => s.id === skillId);
1002
- const deleteDir = installBaseDir(editRoot.dir, oldSkill?.scope);
1003
- await deleteLocalSkill(deleteDir, skillId);
1111
+ await deleteLocalSkill(editRoot.dir, skillId, oldSkill?.scope);
1004
1112
  }
1005
1113
  }
1006
1114
  }
@@ -1015,7 +1123,8 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
1015
1123
  if (addedPluginSkills.length === 0 && removedPluginSkills.length === 0) return;
1016
1124
  const marketplace = await this.requireMarketplaceOrExit(
1017
1125
  context.sourceResult,
1018
- "install or uninstall plugin skills"
1126
+ "install or uninstall plugin skills",
1127
+ hostAt(editRoot.dir)
1019
1128
  );
1020
1129
  if (addedPluginSkills.length > 0) {
1021
1130
  await this.installPluginSkillsReported(
@@ -1061,11 +1170,10 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
1061
1170
  for (const skillId of removedSkills) {
1062
1171
  const oldSkill = activeOldSkills.find((s) => s.id === skillId);
1063
1172
  if (oldSkill?.origin !== EJECT_SOURCE) continue;
1064
- const deleteDir = installBaseDir(editRoot.dir, oldSkill.scope);
1065
- await deleteLocalSkill(deleteDir, skillId);
1173
+ await deleteLocalSkill(editRoot.dir, skillId, oldSkill.scope);
1066
1174
  }
1067
1175
  }
1068
- async writeConfigAndCompile(result, context, editRoot, authority) {
1176
+ async writeConfigAndCompile(result, context, editRoot, authority, producer) {
1069
1177
  let agentDefsResult;
1070
1178
  try {
1071
1179
  agentDefsResult = await loadAgentDefs();
@@ -1090,11 +1198,12 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
1090
1198
  exit: EXIT_CODES.ERROR
1091
1199
  });
1092
1200
  }
1093
- this.reportUnassignedSkills(configResult.config);
1201
+ this.reportUnassignedSkills(configResult.config, result.skills);
1094
1202
  try {
1095
1203
  const agentScopeMap = activeAgentScopeMap(result.agentConfigs);
1096
1204
  const { allSkills } = await discoverInstalledSkills(editRoot.dir);
1097
- const compilationResult = await compileAgentsAllScopes({
1205
+ const compile = compilesGlobalScope(producer, editRoot, configResult.propagation) ? compileAgentsAllScopes : compileProjectScope;
1206
+ const compilationResult = await compile({
1098
1207
  projectDir: editRoot.dir,
1099
1208
  sourcePath: agentDefsResult.sourcePath,
1100
1209
  skills: allSkills,
@@ -1126,7 +1235,7 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
1126
1235
  );
1127
1236
  this.log(`You can manually recompile with '${CLI_INVOKE_COMMAND} compile'.`);
1128
1237
  }
1129
- this.reportPropagatedRecompile(configResult.propagation);
1238
+ this.reportFanOut(configResult.propagation);
1130
1239
  }
1131
1240
  async cleanupStaleAgentFiles(changes, oldAgents, editRoot) {
1132
1241
  for (const removal of planStaleAgentRemovals(changes, oldAgents, editRoot.dir)) {
@@ -1140,6 +1249,24 @@ ${chalk.hex(CLI_COLORS.WHITE).bold("Changes:")}`);
1140
1249
  }
1141
1250
  }
1142
1251
  }
1252
+ /**
1253
+ * What this host could not carry, once per run and after the last write: the lines `init` and
1254
+ * `compile` print, from {@link hostCompileNotices}, so `edit` cannot say something different
1255
+ * about the tree it just compiled.
1256
+ *
1257
+ * After {@link cleanupStaleAgentFiles}, because the question is about the tree as it now stands:
1258
+ * an edit that removed the project's last gated sub-agent must not count the file it deleted.
1259
+ *
1260
+ * Not on a run that owes work, which ends on that account instead: such a run may have left
1261
+ * nothing here to read, and a notice that threw over it would turn the run's
1262
+ * `COMPLETED_WITH_FAILURES` exit into an `ERROR`.
1263
+ */
1264
+ async reportWhatThisHostCannotCarry(editRoot) {
1265
+ if (this.hasIncompleteWork) return;
1266
+ for (const notice of await hostCompileNotices(providerInUse(editRoot.dir), editRoot.dir)) {
1267
+ this.log(notice);
1268
+ }
1269
+ }
1143
1270
  logCompletionSummary(_changes) {
1144
1271
  if (this.hasIncompleteWork) return;
1145
1272
  this.log(`
@@ -1166,6 +1293,18 @@ function detectConfigChanges(oldConfig, wizardResult, fullEntries) {
1166
1293
  (a) => a.name,
1167
1294
  (a) => a.scope
1168
1295
  );
1296
+ const dualScopeSkillTransitions = detectDualScopeTransitions(
1297
+ scopeChanges,
1298
+ fullEntries?.newSkills ?? [],
1299
+ fullEntries?.oldSkills ?? [],
1300
+ (s) => s.id
1301
+ );
1302
+ const collapsedPairs = collapsedPairsOf(
1303
+ scopeChanges,
1304
+ dualScopeSkillTransitions,
1305
+ fullEntries?.oldSkills ?? [],
1306
+ wizardResult.foldedSkillIds ?? []
1307
+ );
1169
1308
  return {
1170
1309
  addedSkills: difference(newSkillIds, oldSkillIds),
1171
1310
  removedSkills: difference(oldSkillIds, newSkillIds),
@@ -1173,26 +1312,36 @@ function detectConfigChanges(oldConfig, wizardResult, fullEntries) {
1173
1312
  removedAgents: difference(oldAgentNames, newAgentNames),
1174
1313
  sourceChanges: detectPropertyChanges(
1175
1314
  wizardResult.skills,
1176
- oldSkillsById,
1315
+ indexBy(withMaskedGlobalsRestored(oldConfig?.skills ?? [], collapsedPairs), (s) => s.id),
1177
1316
  (s) => s.id,
1178
1317
  (s) => s.origin
1179
1318
  ),
1180
1319
  scopeChanges,
1181
1320
  agentScopeChanges,
1182
- dualScopeSkillTransitions: detectDualScopeTransitions(
1183
- scopeChanges,
1184
- fullEntries?.newSkills ?? [],
1185
- fullEntries?.oldSkills ?? [],
1186
- (s) => s.id
1187
- ),
1321
+ dualScopeSkillTransitions,
1322
+ collapsedPairs,
1188
1323
  dualScopeAgentTransitions: detectDualScopeTransitions(
1189
1324
  agentScopeChanges,
1190
1325
  fullEntries?.newAgents ?? [],
1191
1326
  fullEntries?.oldAgents ?? [],
1192
1327
  (a) => a.name
1328
+ ),
1329
+ tuningChanges: detectPropertyChanges(
1330
+ wizardResult.agentConfigs,
1331
+ oldAgentsByName,
1332
+ (a) => a.name,
1333
+ describeTuning
1193
1334
  )
1194
1335
  };
1195
1336
  }
1337
+ var RESTING_TUNING = "defaults";
1338
+ function describeTuning(agent) {
1339
+ const settings = [
1340
+ agent.model === void 0 ? void 0 : `model ${agent.model}`,
1341
+ agent.effort === void 0 ? void 0 : `effort ${agent.effort}`
1342
+ ].filter((setting) => setting !== void 0);
1343
+ return settings.length === 0 ? RESTING_TUNING : settings.join(", ");
1344
+ }
1196
1345
  function detectPropertyChanges(newItems, oldByKey, getKey, getValue) {
1197
1346
  const changes = /* @__PURE__ */ new Map();
1198
1347
  for (const item of newItems) {
@@ -1216,6 +1365,46 @@ function detectDualScopeTransitions(scopeChanges, fullNew, fullOld, getKey) {
1216
1365
  }
1217
1366
  return result;
1218
1367
  }
1368
+ function collapsedPairsOf(scopeChanges, dualScopeSkillTransitions, fullOldSkills, foldedSkillIds) {
1369
+ return [...scopeChanges].filter(([id, change]) => change.to === "global" && dualScopeSkillTransitions.has(id)).map(([id]) => ({
1370
+ projectHalf: oldHalfOf(fullOldSkills, id, (skill) => isActiveAt(skill, "project")),
1371
+ maskedGlobal: oldHalfOf(fullOldSkills, id, isGlobalTombstone),
1372
+ folded: foldedSkillIds.includes(id)
1373
+ }));
1374
+ }
1375
+ function foldsItsCopyIntoGlobal(pair, newSkills) {
1376
+ const { projectHalf, folded } = pair;
1377
+ const globalEntry = newSkills.find(
1378
+ (skill) => skill.id === projectHalf.id && isActiveAt(skill, "global")
1379
+ );
1380
+ return folded && projectHalf.origin === EJECT_SOURCE && globalEntry?.origin === EJECT_SOURCE;
1381
+ }
1382
+ function oldHalfOf(fullOldSkills, id, isHalf) {
1383
+ const half = fullOldSkills.find((skill) => skill.id === id && isHalf(skill));
1384
+ if (half === void 0) {
1385
+ throw new Error(`The config before this edit holds no such half of the pair for '${id}'`);
1386
+ }
1387
+ return half;
1388
+ }
1389
+ function withMaskedGlobalsRestored(oldSkills, collapsedPairs) {
1390
+ const maskedById = indexBy(
1391
+ collapsedPairs.map(({ maskedGlobal }) => maskedGlobal),
1392
+ (skill) => skill.id
1393
+ );
1394
+ return oldSkills.map((skill) => {
1395
+ const masked = maskedById[skill.id];
1396
+ if (masked === void 0 || skill.scope !== "project") return skill;
1397
+ return installRecordedBy(masked);
1398
+ });
1399
+ }
1400
+ function installRecordedBy(tombstone) {
1401
+ const { excluded: _masked, ...install } = tombstone;
1402
+ return install;
1403
+ }
1404
+ function scopeMovesOf(changes) {
1405
+ const collapsed = new Set(changes.collapsedPairs.map(({ projectHalf }) => projectHalf.id));
1406
+ return new Map([...changes.scopeChanges].filter(([id]) => !collapsed.has(id)));
1407
+ }
1219
1408
  var STALE_AGENT_SCOPES = ["project", "global"];
1220
1409
  var UNRECORDED_AGENT_SCOPE = "project";
1221
1410
  function installedScope(name, oldAgents) {
@@ -1235,9 +1424,10 @@ function planStaleAgentRemovals(changes, oldAgents, editRoot) {
1235
1424
  return STALE_AGENT_SCOPES.map(removalAtScope).filter((removal) => removal.agents.length > 0);
1236
1425
  }
1237
1426
  function hasAnyChanges(changes) {
1238
- 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;
1427
+ return changes.reassignedAgents.length > 0 || changes.rewrittenSkills.length > 0 || 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 || changes.tuningChanges.size > 0;
1239
1428
  }
1240
1429
  async function migratePluginSkillScopes(scopeChanges, skills, marketplace, projectDir) {
1430
+ const host = hostAt(projectDir);
1241
1431
  const migrated = [];
1242
1432
  const failed = [];
1243
1433
  for (const [skillId, change] of scopeChanges) {
@@ -1245,13 +1435,12 @@ async function migratePluginSkillScopes(scopeChanges, skills, marketplace, proje
1245
1435
  if (!skillConfig || skillConfig.origin === EJECT_SOURCE) {
1246
1436
  continue;
1247
1437
  }
1248
- const newPluginScope = toClaudePluginScope(change.to);
1249
1438
  const pluginRef = buildMarketplacePluginRef(skillId, marketplace);
1250
1439
  try {
1251
1440
  if (change.from === "project") {
1252
- await claudePluginUninstall(pluginRef, "project", projectDir);
1441
+ await host.uninstallPlugin(pluginRef, "project", projectDir);
1253
1442
  }
1254
- await claudePluginInstall(pluginRef, newPluginScope, projectDir);
1443
+ await host.installPlugin(pluginRef, change.to, projectDir);
1255
1444
  migrated.push(skillId);
1256
1445
  } catch (error) {
1257
1446
  failed.push({ id: skillId, error: getErrorMessage(error) });