@skaile/workspaces 5.17.0 → 5.18.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 (329) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/{asset-feeds-MALYFZUM.js → asset-feeds-WAKBHGEV.js} +21 -21
  3. package/dist/{asset-feeds-MALYFZUM.js.map → asset-feeds-WAKBHGEV.js.map} +1 -1
  4. package/dist/asset-manager/catalog-deployer.js +8 -8
  5. package/dist/asset-manager/index.js +18 -14
  6. package/dist/asset-manager/installer.js +10 -10
  7. package/dist/asset-manager/renderers.js +9 -9
  8. package/dist/asset-manager/src/index.d.ts +122 -5
  9. package/dist/asset-manager/src/index.d.ts.map +1 -1
  10. package/dist/asset-manager/src/installer.d.ts +13 -10
  11. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  12. package/dist/asset-manager/src/mcp-config.d.ts +61 -1
  13. package/dist/asset-manager/src/mcp-config.d.ts.map +1 -1
  14. package/dist/asset-manager/src/renderers.d.ts.map +1 -1
  15. package/dist/bridge/drivers/claude-sdk.js +12 -12
  16. package/dist/bridge/drivers/codex.js +12 -12
  17. package/dist/bridge/drivers/continue.js +11 -11
  18. package/dist/bridge/drivers/echo.js +2 -2
  19. package/dist/bridge/drivers/gemini.js +7 -7
  20. package/dist/bridge/drivers/goose.js +11 -11
  21. package/dist/bridge/drivers/omp.js +31 -5
  22. package/dist/bridge/drivers/omp.js.map +1 -1
  23. package/dist/bridge/drivers/opencode.js +11 -11
  24. package/dist/bridge/drivers/qwen.js +7 -7
  25. package/dist/bridge/index.js +14 -14
  26. package/dist/bridge/src/driver-model-check.d.ts +8 -8
  27. package/dist/bridge/src/driver-model-check.d.ts.map +1 -1
  28. package/dist/bridge/src/drivers/omp-models-yml.d.ts +5 -0
  29. package/dist/bridge/src/drivers/omp-models-yml.d.ts.map +1 -1
  30. package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
  31. package/dist/bridge/src/index.d.ts +1 -1
  32. package/dist/bridge/src/index.d.ts.map +1 -1
  33. package/dist/{chunk-KZWZRNIY.js → chunk-24AXETE3.js} +55 -17
  34. package/dist/chunk-24AXETE3.js.map +1 -0
  35. package/dist/{chunk-ZVZTCDUN.js → chunk-2NOLF7B2.js} +37 -9
  36. package/dist/chunk-2NOLF7B2.js.map +1 -0
  37. package/dist/{chunk-3OYOBTY4.js → chunk-3KMREAR2.js} +3 -3
  38. package/dist/{chunk-3OYOBTY4.js.map → chunk-3KMREAR2.js.map} +1 -1
  39. package/dist/{chunk-D54T2F54.js → chunk-5TBFN46Z.js} +4 -4
  40. package/dist/chunk-5TBFN46Z.js.map +1 -0
  41. package/dist/{chunk-5SWED2LW.js → chunk-6HK6RUFM.js} +3 -3
  42. package/dist/{chunk-5SWED2LW.js.map → chunk-6HK6RUFM.js.map} +1 -1
  43. package/dist/{chunk-PGZDSDOB.js → chunk-6Z5KTFJT.js} +3 -3
  44. package/dist/{chunk-PGZDSDOB.js.map → chunk-6Z5KTFJT.js.map} +1 -1
  45. package/dist/{chunk-46IRZJV4.js → chunk-CD7SVH6W.js} +4 -4
  46. package/dist/{chunk-46IRZJV4.js.map → chunk-CD7SVH6W.js.map} +1 -1
  47. package/dist/{chunk-WKEBNB5S.js → chunk-CKBCX3HQ.js} +4 -4
  48. package/dist/{chunk-WKEBNB5S.js.map → chunk-CKBCX3HQ.js.map} +1 -1
  49. package/dist/{chunk-H7R7R5BN.js → chunk-CKICWXMU.js} +18 -15
  50. package/dist/chunk-CKICWXMU.js.map +1 -0
  51. package/dist/{chunk-YK3XLEQJ.js → chunk-CKNIYIV2.js} +83 -77
  52. package/dist/chunk-CKNIYIV2.js.map +1 -0
  53. package/dist/{chunk-SPV2CXJ3.js → chunk-D6UBEYQH.js} +4 -4
  54. package/dist/{chunk-SPV2CXJ3.js.map → chunk-D6UBEYQH.js.map} +1 -1
  55. package/dist/{chunk-OXUCYHL5.js → chunk-DA2MCPFN.js} +53 -16
  56. package/dist/chunk-DA2MCPFN.js.map +1 -0
  57. package/dist/{chunk-QBY74UBH.js → chunk-DJD36HC5.js} +7 -7
  58. package/dist/{chunk-QBY74UBH.js.map → chunk-DJD36HC5.js.map} +1 -1
  59. package/dist/{chunk-EYDRONKO.js → chunk-E5YNGE3I.js} +4 -4
  60. package/dist/{chunk-EYDRONKO.js.map → chunk-E5YNGE3I.js.map} +1 -1
  61. package/dist/{chunk-V5CDPKDA.js → chunk-EELKR2WP.js} +44 -27
  62. package/dist/chunk-EELKR2WP.js.map +1 -0
  63. package/dist/{chunk-BVXXBZWA.js → chunk-EZVZDCHZ.js} +24 -15
  64. package/dist/chunk-EZVZDCHZ.js.map +1 -0
  65. package/dist/{chunk-WY22FMZF.js → chunk-FHIMIXT3.js} +5 -5
  66. package/dist/{chunk-WY22FMZF.js.map → chunk-FHIMIXT3.js.map} +1 -1
  67. package/dist/{chunk-D5REDKVU.js → chunk-FKU57Q5Q.js} +3 -3
  68. package/dist/{chunk-D5REDKVU.js.map → chunk-FKU57Q5Q.js.map} +1 -1
  69. package/dist/{chunk-OQN7PCI4.js → chunk-FV2MSBVA.js} +4 -4
  70. package/dist/{chunk-OQN7PCI4.js.map → chunk-FV2MSBVA.js.map} +1 -1
  71. package/dist/{chunk-YW2BNDSE.js → chunk-GOCWM7FN.js} +22 -4
  72. package/dist/chunk-GOCWM7FN.js.map +1 -0
  73. package/dist/{chunk-GYZJKZPJ.js → chunk-GRKU3S5V.js} +3 -3
  74. package/dist/{chunk-GYZJKZPJ.js.map → chunk-GRKU3S5V.js.map} +1 -1
  75. package/dist/{chunk-AP24HESN.js → chunk-H6UVIKQ2.js} +3 -3
  76. package/dist/{chunk-AP24HESN.js.map → chunk-H6UVIKQ2.js.map} +1 -1
  77. package/dist/{chunk-ES6ARJPQ.js → chunk-HPVMTX6M.js} +15 -10
  78. package/dist/chunk-HPVMTX6M.js.map +1 -0
  79. package/dist/{chunk-MMARPEV7.js → chunk-JJ7LDI3S.js} +6 -6
  80. package/dist/{chunk-MMARPEV7.js.map → chunk-JJ7LDI3S.js.map} +1 -1
  81. package/dist/{chunk-DR5ZOEYI.js → chunk-JY7GVNYU.js} +32 -18
  82. package/dist/chunk-JY7GVNYU.js.map +1 -0
  83. package/dist/{chunk-HUKUYWBJ.js → chunk-JYWW32JI.js} +17 -6
  84. package/dist/chunk-JYWW32JI.js.map +1 -0
  85. package/dist/{chunk-QEX75L77.js → chunk-K5LVU2MN.js} +13 -7
  86. package/dist/chunk-K5LVU2MN.js.map +1 -0
  87. package/dist/{chunk-5RDZ5JHH.js → chunk-KC6HGWXN.js} +4 -4
  88. package/dist/{chunk-5RDZ5JHH.js.map → chunk-KC6HGWXN.js.map} +1 -1
  89. package/dist/{chunk-ZPCABSSW.js → chunk-L5XUEC2W.js} +4 -4
  90. package/dist/{chunk-ZPCABSSW.js.map → chunk-L5XUEC2W.js.map} +1 -1
  91. package/dist/{chunk-QW534EZB.js → chunk-L6IFN6ER.js} +53 -8
  92. package/dist/chunk-L6IFN6ER.js.map +1 -0
  93. package/dist/{chunk-L6UMSKDF.js → chunk-LW7ZI6EQ.js} +8 -36
  94. package/dist/chunk-LW7ZI6EQ.js.map +1 -0
  95. package/dist/{chunk-QXA2W6UB.js → chunk-MQIRRN76.js} +3 -3
  96. package/dist/{chunk-QXA2W6UB.js.map → chunk-MQIRRN76.js.map} +1 -1
  97. package/dist/{chunk-CWAWYXD5.js → chunk-N5P2WBUL.js} +3 -3
  98. package/dist/{chunk-CWAWYXD5.js.map → chunk-N5P2WBUL.js.map} +1 -1
  99. package/dist/{chunk-BBRMS4IC.js → chunk-ODDATIII.js} +8 -8
  100. package/dist/{chunk-BBRMS4IC.js.map → chunk-ODDATIII.js.map} +1 -1
  101. package/dist/{chunk-WXWQNJCT.js → chunk-PUK7TQT4.js} +3 -3
  102. package/dist/{chunk-WXWQNJCT.js.map → chunk-PUK7TQT4.js.map} +1 -1
  103. package/dist/{chunk-ZWUJ22RF.js → chunk-PZ6NF5DE.js} +16 -23
  104. package/dist/chunk-PZ6NF5DE.js.map +1 -0
  105. package/dist/{chunk-5DCOG5B5.js → chunk-RD6N2D7I.js} +3 -3
  106. package/dist/{chunk-5DCOG5B5.js.map → chunk-RD6N2D7I.js.map} +1 -1
  107. package/dist/{chunk-HLETG3CX.js → chunk-RO2BPKXK.js} +3 -3
  108. package/dist/{chunk-HLETG3CX.js.map → chunk-RO2BPKXK.js.map} +1 -1
  109. package/dist/{chunk-6GSE63K2.js → chunk-SRNCN4X2.js} +13 -5
  110. package/dist/chunk-SRNCN4X2.js.map +1 -0
  111. package/dist/{chunk-PIC23DDE.js → chunk-T2TQAH2X.js} +42 -11
  112. package/dist/chunk-T2TQAH2X.js.map +1 -0
  113. package/dist/{chunk-W44KA24A.js → chunk-TDQ2ERCM.js} +695 -96
  114. package/dist/chunk-TDQ2ERCM.js.map +1 -0
  115. package/dist/{chunk-SXWGLW23.js → chunk-U2FI547Z.js} +4 -4
  116. package/dist/{chunk-SXWGLW23.js.map → chunk-U2FI547Z.js.map} +1 -1
  117. package/dist/{chunk-EOKWTN4N.js → chunk-V4RV2NJF.js} +44 -29
  118. package/dist/chunk-V4RV2NJF.js.map +1 -0
  119. package/dist/{chunk-D3PU3C6F.js → chunk-VKPBUPH7.js} +41 -15
  120. package/dist/chunk-VKPBUPH7.js.map +1 -0
  121. package/dist/{chunk-FT4ZHLYR.js → chunk-WDXZA7QW.js} +33 -3
  122. package/dist/chunk-WDXZA7QW.js.map +1 -0
  123. package/dist/{chunk-FSSRBWYL.js → chunk-WJCQFNF6.js} +4 -4
  124. package/dist/chunk-WJCQFNF6.js.map +1 -0
  125. package/dist/{chunk-2SKPPIV7.js → chunk-WJLYL6RY.js} +5 -5
  126. package/dist/{chunk-2SKPPIV7.js.map → chunk-WJLYL6RY.js.map} +1 -1
  127. package/dist/{chunk-LQT2IKYY.js → chunk-X54YR4AW.js} +2 -2
  128. package/dist/{chunk-LQT2IKYY.js.map → chunk-X54YR4AW.js.map} +1 -1
  129. package/dist/{chunk-QSLXB44M.js → chunk-YU6AURJY.js} +3 -3
  130. package/dist/{chunk-QSLXB44M.js.map → chunk-YU6AURJY.js.map} +1 -1
  131. package/dist/{chunk-FSLVMZXR.js → chunk-YZ3N7IUU.js} +72 -31
  132. package/dist/chunk-YZ3N7IUU.js.map +1 -0
  133. package/dist/{chunk-FACRITOL.js → chunk-ZNN7ONJX.js} +8 -4
  134. package/dist/chunk-ZNN7ONJX.js.map +1 -0
  135. package/dist/cli/index.js +346 -147
  136. package/dist/cli/index.js.map +1 -1
  137. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  138. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  139. package/dist/cli/src/commands/config.d.ts.map +1 -1
  140. package/dist/cli/src/commands/integration.d.ts.map +1 -1
  141. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  142. package/dist/cli/src/commands/library-publish.d.ts.map +1 -1
  143. package/dist/cli/src/commands/plugin/claude-code.d.ts.map +1 -1
  144. package/dist/cli/src/commands/plugin/codex.d.ts +6 -0
  145. package/dist/cli/src/commands/plugin/codex.d.ts.map +1 -1
  146. package/dist/cli/src/commands/project.d.ts.map +1 -1
  147. package/dist/cli/src/commands/run.d.ts.map +1 -1
  148. package/dist/cli/src/commands/serve.d.ts +5 -0
  149. package/dist/cli/src/commands/serve.d.ts.map +1 -1
  150. package/dist/cli/src/commands/source.d.ts.map +1 -1
  151. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  152. package/dist/cli/src/commands/verify.d.ts.map +1 -1
  153. package/dist/cli/src/driver-error.d.ts +3 -1
  154. package/dist/cli/src/driver-error.d.ts.map +1 -1
  155. package/dist/cli/src/helpers.d.ts +6 -4
  156. package/dist/cli/src/helpers.d.ts.map +1 -1
  157. package/dist/cli/src/plugin-store/index.d.ts +6 -0
  158. package/dist/cli/src/plugin-store/index.d.ts.map +1 -1
  159. package/dist/cli/src/skill-checks.d.ts +4 -3
  160. package/dist/cli/src/skill-checks.d.ts.map +1 -1
  161. package/dist/connectors/config.js +5 -5
  162. package/dist/connectors/index.js +20 -20
  163. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  164. package/dist/connectors/src/connector-types.d.ts +5 -0
  165. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  166. package/dist/connectors/src/watcher.d.ts.map +1 -1
  167. package/dist/{connectors-CIEIMJY2.js → connectors-QL4GBMH3.js} +23 -23
  168. package/dist/{connectors-CIEIMJY2.js.map → connectors-QL4GBMH3.js.map} +1 -1
  169. package/dist/core/index.js +7 -7
  170. package/dist/core/manifest.js +2 -2
  171. package/dist/core/models.js +1 -1
  172. package/dist/core/publish-manifest.js +3 -3
  173. package/dist/core/ref.js +1 -1
  174. package/dist/core/runtime-assets.js +5 -5
  175. package/dist/core/src/bind.d.ts +30 -0
  176. package/dist/core/src/bind.d.ts.map +1 -0
  177. package/dist/core/src/index.d.ts +4 -3
  178. package/dist/core/src/index.d.ts.map +1 -1
  179. package/dist/core/src/lock.d.ts +11 -2
  180. package/dist/core/src/lock.d.ts.map +1 -1
  181. package/dist/core/src/manifest.d.ts.map +1 -1
  182. package/dist/core/src/models.d.ts +19 -0
  183. package/dist/core/src/models.d.ts.map +1 -1
  184. package/dist/core/src/publish-manifest.d.ts +15 -13
  185. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  186. package/dist/core/src/store.d.ts +2 -1
  187. package/dist/core/src/store.d.ts.map +1 -1
  188. package/dist/core/src/workspace-config.d.ts +26 -1
  189. package/dist/core/src/workspace-config.d.ts.map +1 -1
  190. package/dist/core/store.js +1 -1
  191. package/dist/core/workspace-config.js +4 -4
  192. package/dist/deploy/index.js +7 -7
  193. package/dist/discovery/index.js +5 -5
  194. package/dist/discovery/src/parse-manifest.d.ts +1 -1
  195. package/dist/discovery/src/source-config.d.ts +2 -1
  196. package/dist/discovery/src/source-config.d.ts.map +1 -1
  197. package/dist/{ensure-sources-I62QMZZP.js → ensure-sources-CEFODJCE.js} +21 -17
  198. package/dist/ensure-sources-CEFODJCE.js.map +1 -0
  199. package/dist/factory-assets/connectors/box.js +20 -20
  200. package/dist/factory-assets/connectors/deploy.js +20 -20
  201. package/dist/factory-assets/connectors/devserver.js +20 -20
  202. package/dist/factory-assets/connectors/flow/adapter.js +20 -20
  203. package/dist/factory-assets/connectors/flow/engine.js +9 -9
  204. package/dist/factory-assets/connectors/flow/run-flow.js +22 -22
  205. package/dist/factory-assets/connectors/flow.js +20 -20
  206. package/dist/factory-assets/connectors/git.js +20 -20
  207. package/dist/factory-assets/connectors/gmail.js +20 -20
  208. package/dist/factory-assets/connectors/googledrive.js +20 -20
  209. package/dist/factory-assets/connectors/local.js +20 -20
  210. package/dist/factory-assets/connectors/mattermost.js +20 -20
  211. package/dist/factory-assets/connectors/memory.js +20 -20
  212. package/dist/factory-assets/connectors/minio.js +20 -20
  213. package/dist/factory-assets/connectors/postgres.js +20 -20
  214. package/dist/factory-assets/connectors/s3.js +20 -20
  215. package/dist/factory-assets/connectors/sharepoint.js +20 -20
  216. package/dist/factory-assets/connectors/sqlite.js +20 -20
  217. package/dist/factory-assets/connectors/static-server.js +20 -20
  218. package/dist/factory-assets/connectors/tunnel.js +20 -20
  219. package/dist/factory-assets/connectors/webdav.js +20 -20
  220. package/dist/factory-assets/connectors/xstate-store/adapter.d.ts +1 -1
  221. package/dist/factory-assets/connectors/xstate-store/adapter.d.ts.map +1 -1
  222. package/dist/factory-assets/connectors/xstate-store.js +20 -20
  223. package/dist/factory-assets/connectors/xstate.js +20 -20
  224. package/dist/{flows-YKC53LDP.js → flows-BHY73K3O.js} +12 -12
  225. package/dist/{flows-YKC53LDP.js.map → flows-BHY73K3O.js.map} +1 -1
  226. package/dist/{helpers-3FOM37BO.js → helpers-R22QNPFN.js} +21 -17
  227. package/dist/{helpers-3FOM37BO.js.map → helpers-R22QNPFN.js.map} +1 -1
  228. package/dist/library/index.js +11 -11
  229. package/dist/library/install.js +4 -4
  230. package/dist/library/src/index.d.ts +1 -1
  231. package/dist/library/src/index.d.ts.map +1 -1
  232. package/dist/library/src/manifest-writer.d.ts +17 -1
  233. package/dist/library/src/manifest-writer.d.ts.map +1 -1
  234. package/dist/{library-publish-EFKITCGE.js → library-publish-VBE3X2TH.js} +60 -63
  235. package/dist/library-publish-VBE3X2TH.js.map +1 -0
  236. package/dist/model-endpoint/index.js +10 -10
  237. package/dist/model-endpoint/src/server.d.ts.map +1 -1
  238. package/dist/open-library-JP5TC5UX.js +42 -0
  239. package/dist/{open-library-NZUI4XGF.js.map → open-library-JP5TC5UX.js.map} +1 -1
  240. package/dist/open-registry-RBELV5YH.js +32 -0
  241. package/dist/{open-registry-YPRQDUMK.js.map → open-registry-RBELV5YH.js.map} +1 -1
  242. package/dist/paths-BFM6K2QO.js +22 -0
  243. package/dist/{paths-P55DTBEK.js.map → paths-BFM6K2QO.js.map} +1 -1
  244. package/dist/plugin-store-QOQDM24E.js +23 -0
  245. package/dist/{plugin-store-IPIBZRBX.js.map → plugin-store-QOQDM24E.js.map} +1 -1
  246. package/dist/{project-2BNFZ2CR.js → project-6ETXGQWD.js} +45 -45
  247. package/dist/{project-2BNFZ2CR.js.map → project-6ETXGQWD.js.map} +1 -1
  248. package/dist/resolver/index.js +8 -8
  249. package/dist/runner/index.js +37 -37
  250. package/dist/runner/src/agent.d.ts.map +1 -1
  251. package/dist/runner/src/capability-roundtrip.d.ts.map +1 -1
  252. package/dist/sdk/asset-manager.js +18 -14
  253. package/dist/sdk/bridge.js +14 -14
  254. package/dist/sdk/core.js +7 -7
  255. package/dist/sdk/flow.js +9 -9
  256. package/dist/sdk/index.js +37 -37
  257. package/dist/sdk/resolver.js +8 -8
  258. package/dist/sdk/runner.js +37 -37
  259. package/dist/sdk/transport/ws/server.js +19 -1
  260. package/dist/sdk/transport/ws.js +19 -1
  261. package/dist/sdk/transport.js +19 -1
  262. package/dist/{serve-preflight-V5GM33T3.js → serve-preflight-BTGTZUDN.js} +9 -9
  263. package/dist/{serve-preflight-V5GM33T3.js.map → serve-preflight-BTGTZUDN.js.map} +1 -1
  264. package/dist/{setup-ZMAPTKJW.js → setup-JQDTYPSD.js} +28 -24
  265. package/dist/setup-JQDTYPSD.js.map +1 -0
  266. package/dist/{skills-7G6QCDEM.js → skills-RSZVUIYZ.js} +13 -13
  267. package/dist/{skills-7G6QCDEM.js.map → skills-RSZVUIYZ.js.map} +1 -1
  268. package/dist/{source-6BZA34F5.js → source-FPLHY3DP.js} +47 -47
  269. package/dist/{source-6BZA34F5.js.map → source-FPLHY3DP.js.map} +1 -1
  270. package/dist/{source-manifest-publish-MJXCSUKT.js → source-manifest-publish-LY4H63VA.js} +49 -49
  271. package/dist/{source-manifest-publish-MJXCSUKT.js.map → source-manifest-publish-LY4H63VA.js.map} +1 -1
  272. package/dist/transport/index.js +19 -1
  273. package/dist/transport/src/ws/server.d.ts +2 -16
  274. package/dist/transport/src/ws/server.d.ts.map +1 -1
  275. package/dist/transport/ws/server.js +19 -1
  276. package/dist/transport/ws.js +19 -1
  277. package/dist/tui/index.js +54 -42
  278. package/dist/tui/index.js.map +1 -1
  279. package/dist/tui/src/repl.d.ts +4 -1
  280. package/dist/tui/src/repl.d.ts.map +1 -1
  281. package/dist/types/manifests.js +1 -1
  282. package/dist/types/src/manifests/index.d.ts +1 -1
  283. package/dist/types/src/manifests/index.d.ts.map +1 -1
  284. package/dist/types/src/manifests/scaffold-body.d.ts +8 -0
  285. package/dist/types/src/manifests/scaffold-body.d.ts.map +1 -1
  286. package/dist/types/src/manifests/skill.d.ts +0 -2
  287. package/dist/types/src/manifests/skill.d.ts.map +1 -1
  288. package/dist/workspace-plugin/adapters/mcp.js +27 -27
  289. package/dist/workspace-plugin/adapters/omp.js +32 -18
  290. package/dist/workspace-plugin/adapters/omp.js.map +1 -1
  291. package/dist/workspace-plugin/index.js +1 -1
  292. package/dist/workspace-plugin/src/adapters/claude-code.d.ts +1 -1
  293. package/dist/workspace-plugin/src/adapters/omp.d.ts +8 -5
  294. package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -1
  295. package/dist/workspace-plugin/src/plugin.d.ts +7 -1
  296. package/dist/workspace-plugin/src/plugin.d.ts.map +1 -1
  297. package/package.json +1 -1
  298. package/dist/chunk-6GSE63K2.js.map +0 -1
  299. package/dist/chunk-BVXXBZWA.js.map +0 -1
  300. package/dist/chunk-D3PU3C6F.js.map +0 -1
  301. package/dist/chunk-D54T2F54.js.map +0 -1
  302. package/dist/chunk-DR5ZOEYI.js.map +0 -1
  303. package/dist/chunk-EOKWTN4N.js.map +0 -1
  304. package/dist/chunk-ES6ARJPQ.js.map +0 -1
  305. package/dist/chunk-FACRITOL.js.map +0 -1
  306. package/dist/chunk-FSLVMZXR.js.map +0 -1
  307. package/dist/chunk-FSSRBWYL.js.map +0 -1
  308. package/dist/chunk-FT4ZHLYR.js.map +0 -1
  309. package/dist/chunk-H7R7R5BN.js.map +0 -1
  310. package/dist/chunk-HUKUYWBJ.js.map +0 -1
  311. package/dist/chunk-KZWZRNIY.js.map +0 -1
  312. package/dist/chunk-L6UMSKDF.js.map +0 -1
  313. package/dist/chunk-OXUCYHL5.js.map +0 -1
  314. package/dist/chunk-PIC23DDE.js.map +0 -1
  315. package/dist/chunk-QEX75L77.js.map +0 -1
  316. package/dist/chunk-QW534EZB.js.map +0 -1
  317. package/dist/chunk-V5CDPKDA.js.map +0 -1
  318. package/dist/chunk-W44KA24A.js.map +0 -1
  319. package/dist/chunk-YK3XLEQJ.js.map +0 -1
  320. package/dist/chunk-YW2BNDSE.js.map +0 -1
  321. package/dist/chunk-ZVZTCDUN.js.map +0 -1
  322. package/dist/chunk-ZWUJ22RF.js.map +0 -1
  323. package/dist/ensure-sources-I62QMZZP.js.map +0 -1
  324. package/dist/library-publish-EFKITCGE.js.map +0 -1
  325. package/dist/open-library-NZUI4XGF.js +0 -40
  326. package/dist/open-registry-YPRQDUMK.js +0 -32
  327. package/dist/paths-P55DTBEK.js +0 -22
  328. package/dist/plugin-store-IPIBZRBX.js +0 -23
  329. package/dist/setup-ZMAPTKJW.js.map +0 -1
@@ -1,19 +1,20 @@
1
- import { unregisteredLibraryNames, renamedLibraryName, resolveConfig, RemoteCatalogSource, OfflineError, describeCatalogError, CatalogHttpError, scanUnlistedAssets, storeManifestFile, missingLibraryDirMessage } from './chunk-D3PU3C6F.js';
2
- import { SEMVER_RE, invalidSemverMessage, flowFileNameError, readManifestSourceConfig, discoverAssetsInTree, isManifestMode } from './chunk-ES6ARJPQ.js';
3
- import { installTargetOf, readKeptLegacyCopies, writeKeptLegacyCopies, canonicalEntryRef, diffDeployedAgent, deployedAssetDrift, deployAll, removeAsset, createScaffold, installAgent } from './chunk-FSLVMZXR.js';
1
+ import { unregisteredLibraryNames, renamedLibraryName, resolveConfig, RemoteCatalogSource, OfflineError, describeCatalogError, CatalogHttpError, scanUnlistedAssets, storeManifestFile, missingLibraryDirMessage } from './chunk-VKPBUPH7.js';
2
+ import { SEMVER_RE, invalidSemverMessage, flowFileNameError, readManifestSourceConfig, discoverAssetsInTree, isManifestMode } from './chunk-HPVMTX6M.js';
3
+ import { parseFlowDefinition } from './chunk-X3RMRJNR.js';
4
+ import { installTargetOf, readKeptLegacyCopies, writeKeptLegacyCopies, canonicalEntryRef, diffDeployedAgent, deployedAssetDrift, assertNoLibrarySymlinks, deployAll, removeAsset, createScaffold, installAgent } from './chunk-YZ3N7IUU.js';
4
5
  import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
5
6
  import { commitChanges } from './chunk-UQ6LFBPZ.js';
6
- import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-6GSE63K2.js';
7
- import { isScaffoldBody } from './chunk-YK3XLEQJ.js';
8
- import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, computeHash, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, resyncLockSources, extractForPatch, generatePatch, savePatch, applyPatch, LOCK_SCHEMA_VERSION } from './chunk-PIC23DDE.js';
9
- import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-5RDZ5JHH.js';
10
- import { deployedBase, isDeployed, deployedPaths, deployedDir } from './chunk-D54T2F54.js';
11
- import { resolveSkWorkspaceConfig, effectiveAgentInstances, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, buildProvenanceIndex, coerceVersion, sourceShortName, readLinks, isCommitOnRemote, resolveAll, agentSourceCacheDir, ensureRepo, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAgentDefinitionDir, resolveAsset, MAX_PRESET_DEPTH, PresetDepthError, DEFAULT_AGENT_INSTANCE_ID } from './chunk-ZVZTCDUN.js';
7
+ import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-SRNCN4X2.js';
8
+ import { isScaffoldBody, isScaffoldDescription } from './chunk-CKNIYIV2.js';
9
+ import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, computeHash, buildLockFile, writeLock, readLock, verifyLock, mergeLockFile, resyncLockSources, extractForPatch, generatePatch, savePatch, applyPatch, LOCK_SCHEMA_VERSION } from './chunk-T2TQAH2X.js';
10
+ import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-KC6HGWXN.js';
11
+ import { deployedBase, isDeployed, deployedPaths, deployedDir } from './chunk-5TBFN46Z.js';
12
+ import { resolveSkWorkspaceConfig, effectiveAgentInstances, loadMcpServerDeclarations, resolveGlobalHarnesses, resolveGlobalSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, matchPin, buildProvenanceIndex, coerceVersion, sourceShortName, readLinks, isCommitOnRemote, resolveAll, agentSourceCacheDir, ensureRepo, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAgentDefinitionDir, resolveAsset, MAX_PRESET_DEPTH, PresetDepthError, DEFAULT_AGENT_INSTANCE_ID } from './chunk-2NOLF7B2.js';
12
13
  import { globalSkaileDir, globalCacheRoot, migrateLegacyDir } from './chunk-L5VSIPQD.js';
13
14
  import { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS } from './chunk-IG5LZ3WU.js';
14
- import { listAssetFiles, loadSkPublishManifest } from './chunk-H7R7R5BN.js';
15
- import { scanDirectory, parseFrontmatter, parseRequires, dedupeRequirements, readAssetBody } from './chunk-YW2BNDSE.js';
16
- import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr, parseDep } from './chunk-FT4ZHLYR.js';
15
+ import { listAssetFiles, loadSkPublishManifest, isNonAssetDir, isNonAssetFile } from './chunk-CKICWXMU.js';
16
+ import { scanDirectory, parseFrontmatter, parseRequires, dedupeRequirements, readAssetBody } from './chunk-GOCWM7FN.js';
17
+ import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr, parseDep } from './chunk-WDXZA7QW.js';
17
18
  import { spawnSync } from 'child_process';
18
19
  import { existsSync, rmSync, readFileSync, readdirSync, lstatSync, writeFileSync, unlinkSync, mkdirSync } from 'fs';
19
20
  import path, { resolve, dirname, sep, join, relative, posix } from 'path';
@@ -279,17 +280,33 @@ async function markEsmPayload(dir, dest, bytes) {
279
280
  } catch {
280
281
  }
281
282
  }
283
+ function rawPayloadDest(payload) {
284
+ if (payload.dest !== void 0) return payload.dest;
285
+ try {
286
+ return decodeSegment(new URL(payload.url).pathname.split("/").pop() ?? "");
287
+ } catch {
288
+ return void 0;
289
+ }
290
+ }
291
+ async function extraPayloadEntries(dir, dest) {
292
+ let entries;
293
+ try {
294
+ entries = await fs.readdir(dir, { withFileTypes: true });
295
+ } catch {
296
+ return [];
297
+ }
298
+ if (entries.some((e) => e.name === "MCP.md")) return [];
299
+ return entries.filter((e) => e.name !== dest && e.name !== "package.json").filter((e) => !(e.isDirectory() ? isNonAssetDir(e.name) : isNonAssetFile(e.name))).map((e) => e.name).sort();
300
+ }
301
+ async function pruneExtraPayloadFiles(dir, dest) {
302
+ for (const name of await extraPayloadEntries(dir, dest)) {
303
+ await fs.rm(path.join(dir, name), { recursive: true, force: true });
304
+ }
305
+ }
282
306
  async function ensurePayload(projectDir, decl, fetchPayload) {
283
307
  const payload = decl.payload;
284
308
  if (!payload) return void 0;
285
- let dest = payload.dest;
286
- if (dest === void 0) {
287
- try {
288
- dest = decodeSegment(new URL(payload.url).pathname.split("/").pop() ?? "");
289
- } catch {
290
- dest = void 0;
291
- }
292
- }
309
+ const dest = rawPayloadDest(payload);
293
310
  if (dest === void 0 || !isPlainName(dest)) {
294
311
  return `payload ${payload.url} has no usable file name (${JSON.stringify(dest ?? "")}): a plain file name is required`;
295
312
  }
@@ -304,6 +321,7 @@ async function ensurePayload(projectDir, decl, fetchPayload) {
304
321
  }
305
322
  if (existing && sha(existing) === payload.sha256) {
306
323
  await markEsmPayload(dir, dest, existing);
324
+ await pruneExtraPayloadFiles(dir, dest);
307
325
  return void 0;
308
326
  }
309
327
  let bytes;
@@ -326,6 +344,7 @@ async function ensurePayload(projectDir, decl, fetchPayload) {
326
344
  return `payload ${dest} could not be written: ${err instanceof Error ? err.message : String(err)}`;
327
345
  }
328
346
  await markEsmPayload(dir, dest, bytes);
347
+ await pruneExtraPayloadFiles(dir, dest);
329
348
  return void 0;
330
349
  }
331
350
  async function removePayloadDir(projectDir, id) {
@@ -444,6 +463,104 @@ function mergeServers(existing, renderable, managedIds, warn, configLabel) {
444
463
  }
445
464
  return { next, owned, removed };
446
465
  }
466
+ function canonicalJson(value) {
467
+ return JSON.stringify(
468
+ value,
469
+ (_key, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : v
470
+ );
471
+ }
472
+ async function mcpServerDrift(projectDir, driverTarget, opts = {}) {
473
+ const relConfig = TARGET_MCP_CONFIG[driverTarget];
474
+ if (!relConfig) return [];
475
+ const declarations = opts.declarations ?? await loadMcpServerDeclarations(projectDir);
476
+ const skippedNow = await readNotedSkips(projectDir, driverTarget);
477
+ const managed = new Set(await readManagedIds(projectDir, driverTarget));
478
+ let servers = {};
479
+ try {
480
+ const file = await readJsonStrict(path.join(projectDir, relConfig));
481
+ servers = file?.mcpServers ?? {};
482
+ } catch {
483
+ return [];
484
+ }
485
+ const rel = (p) => path.relative(projectDir, p).split(path.sep).join("/");
486
+ const out = [];
487
+ for (const decl of declarations) {
488
+ if (skippedNow[decl.id] !== void 0 || skipReason(decl)) continue;
489
+ const drift = { id: decl.id, missing: [], modified: [], extra: [] };
490
+ const dest = decl.payload ? rawPayloadDest(decl.payload) : void 0;
491
+ const dir = payloadDir(projectDir, decl.id);
492
+ if (decl.payload && dest !== void 0 && isPlainName(dest) && dir) {
493
+ const file = rel(path.join(dir, dest));
494
+ let actual;
495
+ try {
496
+ actual = createHash("sha256").update(await fs.readFile(path.join(dir, dest))).digest("hex");
497
+ } catch {
498
+ }
499
+ if (actual === void 0) {
500
+ drift.missing.push(file);
501
+ drift.payload = { file, pinned: decl.payload.sha256 };
502
+ } else if (actual !== decl.payload.sha256) {
503
+ drift.modified.push(file);
504
+ drift.payload = { file, pinned: decl.payload.sha256, actual };
505
+ }
506
+ for (const name of await extraPayloadEntries(dir, dest)) {
507
+ drift.extra.push(rel(path.join(dir, name)));
508
+ }
509
+ }
510
+ const owned = managed.has(decl.id);
511
+ const lockedHere = opts.locked?.has(decl.id) || opts.locked?.has(decl.id.split("/").pop() ?? "");
512
+ if (owned || lockedHere) {
513
+ const expected = JSON.parse(JSON.stringify(buildEntry(decl, projectDir)));
514
+ const actual = Object.hasOwn(servers, decl.id) ? servers[decl.id] : void 0;
515
+ const label = `${relConfig} entry "${decl.id}"`;
516
+ if (actual === void 0) {
517
+ drift.missing.push(label);
518
+ drift.entry = { expected, actual };
519
+ } else if (owned && canonicalJson(actual) !== canonicalJson(expected)) {
520
+ drift.modified.push(label);
521
+ drift.entry = { expected, actual };
522
+ }
523
+ }
524
+ if (drift.missing.length + drift.modified.length + drift.extra.length > 0) out.push(drift);
525
+ }
526
+ return out;
527
+ }
528
+ function jsonLineDiff(from, to) {
529
+ const lines = (v) => v === void 0 ? [] : JSON.stringify(v, null, 2).split("\n");
530
+ const a = lines(from);
531
+ const b = lines(to);
532
+ return [
533
+ ...a.filter((l) => !b.includes(l)).map((l) => `-${l}`),
534
+ ...b.filter((l) => !a.includes(l)).map((l) => `+${l}`)
535
+ ];
536
+ }
537
+ function mcpDriftDiff(drift) {
538
+ const out = [];
539
+ if (drift.payload) {
540
+ const { file, pinned, actual } = drift.payload;
541
+ out.push(`--- ${file} (deployed)`, `+++ ${file} (pinned)`);
542
+ out.push(
543
+ actual === void 0 ? "-(file is missing)" : `-sha256 ${actual}`,
544
+ `+sha256 ${pinned}`
545
+ );
546
+ }
547
+ for (const f of drift.extra)
548
+ out.push(`--- ${f} (deployed)`, "+++ /dev/null (not part of the asset)");
549
+ if (drift.entry) {
550
+ const file = drift.missing.concat(drift.modified).find((f) => f.includes(" entry ")) ?? "MCP config entry";
551
+ out.push(`--- ${file} (deployed)`, `+++ ${file} (declared)`);
552
+ out.push(...jsonLineDiff(drift.entry.actual, drift.entry.expected));
553
+ }
554
+ return `${out.join("\n")}
555
+ `;
556
+ }
557
+ var readSkippedMcpServers = readNotedSkips;
558
+ function unsetRequiredFields(decl) {
559
+ return (decl.fields ?? []).filter((f) => f.required === true && f.default === void 0).filter((f) => !(decl.env && Object.hasOwn(decl.env, f.key))).map((f) => f.key);
560
+ }
561
+ function requiredFieldsAdvice(id, keys) {
562
+ return `needs ${keys.join(", ")} (required): set it with an mcp_servers entry (id: ${id}, env: \u2026) in skaile.yaml`;
563
+ }
447
564
  async function renderMcpServerConfig(projectDir, driverTarget, opts) {
448
565
  const warn = opts?.warn ?? ((m) => console.warn(`skaile: ${m}`));
449
566
  const relConfig = TARGET_MCP_CONFIG[driverTarget];
@@ -480,6 +597,11 @@ async function renderMcpServerConfig(projectDir, driverTarget, opts) {
480
597
  relConfig
481
598
  );
482
599
  for (const id of removed) await removePayloadDir(projectDir, id);
600
+ for (const decl of declarations) {
601
+ if (!owned.includes(decl.id) || managedIds.includes(decl.id)) continue;
602
+ const unset = unsetRequiredFields(decl);
603
+ if (unset.length > 0) warn(`MCP server "${decl.id}" ${requiredFieldsAdvice(decl.id, unset)}`);
604
+ }
483
605
  const ledgerStale = JSON.stringify(owned) !== JSON.stringify(managedIds);
484
606
  if (ledgerStale) await writeManagedIds(projectDir, driverTarget, owned);
485
607
  if (Object.keys(next).length === 0 && !existingFile) {
@@ -583,6 +705,7 @@ function lockedAssetFiles(kind, files) {
583
705
  });
584
706
  }
585
707
  var GITHUB_REPO_URL = /github\.com[/:]/i;
708
+ var GIT_URL = /^(?:[a-z][a-z0-9+.-]*:\/\/|[\w.-]+@[\w.-]+:)/i;
586
709
  function indexLockByKindName(lock) {
587
710
  const lockByKindName = /* @__PURE__ */ new Map();
588
711
  for (const [key, entry] of Object.entries(lock?.assets ?? {})) {
@@ -763,6 +886,11 @@ function scaffoldBodyRefs(entries, deployed) {
763
886
  }
764
887
  return out;
765
888
  }
889
+ function scaffoldDescriptionRefs(entries, deployed) {
890
+ return entries.filter(
891
+ (e) => deployed.includes(canonicalEntryRef(e)) && isScaffoldDescription(e.kind, e.description)
892
+ ).map((e) => canonicalEntryRef(e));
893
+ }
766
894
  function libraryEntryDepRefs(e) {
767
895
  const publisher = e.publisher ?? "";
768
896
  const refs = /* @__PURE__ */ new Set();
@@ -775,6 +903,30 @@ function libraryEntryDepRefs(e) {
775
903
  }
776
904
  return [...refs];
777
905
  }
906
+ function assertFlowsLoad(entries) {
907
+ for (const e of entries) {
908
+ if (e.kind !== "flow" || !e.source) continue;
909
+ let file = e.source;
910
+ let authored;
911
+ try {
912
+ if (lstatSync(file).isDirectory()) {
913
+ const inside = [`${e.name}.flow.yaml`, `${e.name}.flow.yml`, `${e.name}.flow.json`].map((n) => join(file, n)).find((p) => existsSync(p));
914
+ if (!inside) continue;
915
+ file = inside;
916
+ }
917
+ const raw = readFileSync(file, "utf8");
918
+ authored = /\.json$/i.test(file) ? JSON.parse(raw) : parse(raw);
919
+ } catch {
920
+ continue;
921
+ }
922
+ const parsed = parseFlowDefinition(authored);
923
+ if (parsed.ok) continue;
924
+ const details = parsed.errors.slice(0, 3).map((issue) => `${issue.path || "<root>"}: ${issue.message}`).join("; ");
925
+ throw new Error(
926
+ `${canonicalEntryRef(e).split("#")[0]} is not a flow the flow engine can load (${details}) \u2014 nothing was added; fix the flow in its library or source`
927
+ );
928
+ }
929
+ }
778
930
  function refIdentity(ref) {
779
931
  try {
780
932
  const p = parseAssetRef(ref);
@@ -853,6 +1005,12 @@ function parseRefTolerant(ref) {
853
1005
  return { kind, name, publisher: void 0 };
854
1006
  }
855
1007
  }
1008
+ var LibraryEntryError = class extends Error {
1009
+ constructor(message) {
1010
+ super(message);
1011
+ this.name = "LibraryEntryError";
1012
+ }
1013
+ };
856
1014
  function keptLockEntries(prev, missing) {
857
1015
  const out = { assets: {}, sources: [], refs: /* @__PURE__ */ new Set(), keysByRef: /* @__PURE__ */ new Map() };
858
1016
  if (!prev) return out;
@@ -892,6 +1050,7 @@ function relockedRefs(prev, next) {
892
1050
  if (!prev) return [];
893
1051
  const fingerprint = (e, key) => [
894
1052
  e.library?.version ?? "",
1053
+ e.library && !e.library.installed ? e.library.name : "",
895
1054
  e.library?.sha256 ?? e.sha256,
896
1055
  key.includes("#0.0.0-sha.") ? "" : e.source?.commit ?? ""
897
1056
  ].join("\0");
@@ -943,6 +1102,18 @@ function sameAsset(ref, want) {
943
1102
  const p = parseRefTolerant(ref);
944
1103
  return p !== null && p.kind === want.kind && p.name === want.name && (!want.publisher || !p.publisher || p.publisher === want.publisher);
945
1104
  }
1105
+ function libraryCollisionMessage(c) {
1106
+ return `${c.key} exists in ${c.libraries.length} libraries: ${c.held.join(", ")} \u2014 using ${c.chosen} (${c.version}). Highest version wins; an equal version goes to the default library, then by name. ` + (c.differing.length > 0 ? `Same version, different content: ${c.chosen} and ${c.differing.join(", ")} hold ${c.version} with different bytes. ` : "") + `Pin a version (${c.key}#<version>) to choose another.`;
1107
+ }
1108
+ function libraryCollisionSummary(all) {
1109
+ const libraries = [...new Set(all.flatMap((c) => c.libraries))].sort();
1110
+ const used = /* @__PURE__ */ new Map();
1111
+ for (const c of all) used.set(c.chosen, (used.get(c.chosen) ?? 0) + 1);
1112
+ const usedText = [...used].sort((a, b) => b[1] - a[1]).map(([lib, n]) => `${lib} for ${n}`);
1113
+ const short = (key) => key.slice(key.lastIndexOf("/") + 1);
1114
+ const differing = all.filter((c) => c.differing.length > 0).map((c) => short(c.key));
1115
+ return `${all.length} assets exist in several libraries (${libraries.join(", ")}); using ${usedText.join(", ")}. Highest version wins; an equal version goes to the default library, then by name. ` + (differing.length > 0 ? `Same version, different bytes for: ${differing.join(", ")}. ` : "") + "Pin a version (<ref>#<version>) to choose another; `--verbose` lists each asset.";
1116
+ }
946
1117
  function lockedLibraryProblem(lookup, origin, ref) {
947
1118
  return lookup.state === "dir-missing" ? missingLibraryDirMessage({ name: origin.name, path: lookup.path }) : `library "${origin.name}" is not registered \u2014 renamed or removed? ${unregisteredLibraryFix(origin, ref)}`;
948
1119
  }
@@ -1087,6 +1258,8 @@ var AssetManager = class {
1087
1258
  indexPathOverride;
1088
1259
  /** Sink for cross-library collision warnings; else `console.warn`. */
1089
1260
  onLibraryCollision;
1261
+ /** Print every colliding asset's full message instead of one summary ({@link AssetManagerOptions.verboseCollisions}). */
1262
+ verboseCollisions;
1090
1263
  /** Store URLs whose failed version lookup was already reported (one warning per URL). */
1091
1264
  warnedStoreVersionLookups = /* @__PURE__ */ new Set();
1092
1265
  /** Stores a lookup could not reach (store URL -> one line why); `add` reports them instead of "not found". */
@@ -1113,6 +1286,7 @@ var AssetManager = class {
1113
1286
  this.catalogUrlOverride = opts.catalogUrl;
1114
1287
  this.indexPathOverride = opts.indexPath;
1115
1288
  this.onLibraryCollision = opts.onLibraryCollision;
1289
+ this.verboseCollisions = opts.verboseCollisions ?? false;
1116
1290
  }
1117
1291
  /** Registered kind names — the `knownKinds` argument of the manifest scanners. */
1118
1292
  get knownKinds() {
@@ -1317,17 +1491,57 @@ var AssetManager = class {
1317
1491
  }
1318
1492
  /** Deploy options for one harness. In global mode, `driverTarget` is the
1319
1493
  * fan-out target (not the constructor's `driverTarget`, which is project-only). */
1320
- deployOptsFor(target, link, onSkippedSymlink, onEnvFile) {
1494
+ deployOptsFor(target, link, onSecretFile) {
1321
1495
  return {
1322
1496
  registry: this.registry,
1323
1497
  driverTarget: target,
1324
1498
  global: this.global,
1325
1499
  cwd: this.projectDir,
1326
1500
  link: link === true,
1327
- ...onSkippedSymlink ? { onSkippedSymlink: (entry, p) => onSkippedSymlink(canonicalEntryRef(entry), p) } : {},
1328
- ...onEnvFile ? { onEnvFile: (entry, p) => onEnvFile(canonicalEntryRef(entry), p) } : {}
1501
+ ...onSecretFile ? { onSecretFile: (entry, p) => onSecretFile(canonicalEntryRef(entry), p) } : {}
1329
1502
  };
1330
1503
  }
1504
+ /**
1505
+ * Names of the `mcp-server` assets the lock holds (the declaration ids, unscoped); a missing
1506
+ * `.mcp.json` entry of one counts as drift even before skaile owned it.
1507
+ */
1508
+ lockedMcpNames() {
1509
+ return new Set(
1510
+ Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey).filter((id) => id.kind === "mcp-server" && id.name).map((id) => id.name)
1511
+ );
1512
+ }
1513
+ /**
1514
+ * The payloads and managed `.mcp.json` entries of the project's **locked** `mcp-server`
1515
+ * assets that differ from what the declarations render (see {@link mcpServerDrift}), one row
1516
+ * per server, named by the lock identity `mcp-server:@publisher/name`; `key` is the lock key.
1517
+ * An `mcp_servers:` entry of `skaile.yaml` is configuration, not a locked asset: it has no
1518
+ * row. Empty for a global manager and for a project that locks no `mcp-server`.
1519
+ */
1520
+ async mcpDriftRows() {
1521
+ if (this.global) return [];
1522
+ const locked = this.lockedMcpNames();
1523
+ if (locked.size === 0) return [];
1524
+ let rows;
1525
+ try {
1526
+ rows = await mcpServerDrift(this.projectDir, this.driverTarget, { locked });
1527
+ } catch {
1528
+ return [];
1529
+ }
1530
+ const keys = Object.keys(this.tryReadLock()?.assets ?? {});
1531
+ const out = [];
1532
+ for (const drift of rows) {
1533
+ const name = unscopedName(drift.id);
1534
+ const key = keys.find((k) => {
1535
+ const id = parseCanonicalLockKey(k);
1536
+ return id.kind === "mcp-server" && id.name === name;
1537
+ });
1538
+ if (!key) continue;
1539
+ const publisher = parseCanonicalLockKey(key).publisher;
1540
+ const ref = publisher ? `mcp-server:@${publisher}/${name}` : `mcp-server:${name}`;
1541
+ out.push({ ref, key, drift });
1542
+ }
1543
+ return out;
1544
+ }
1331
1545
  /**
1332
1546
  * Render the project's declared MCP servers into the driver target's own
1333
1547
  * native MCP config (`<project>/.mcp.json` for `claude-code`), so the coding
@@ -1337,16 +1551,34 @@ var AssetManager = class {
1337
1551
  * write, and the coding agent's user scope is a large user-state file this
1338
1552
  * must not touch. Never fails an install — a render error is warned and
1339
1553
  * swallowed.
1554
+ *
1555
+ * @returns The payload files and config entries the render wrote back (and the files it
1556
+ * removed) because they had drifted from the declaration: `install` names them, as it does
1557
+ * a restored skill file.
1340
1558
  */
1341
1559
  async renderDriverMcpConfig() {
1342
- if (this.global) return;
1560
+ if (this.global) return [];
1561
+ const before = await this.mcpDriftRows();
1343
1562
  try {
1344
1563
  await renderMcpServerConfig(this.projectDir, this.driverTarget);
1345
1564
  } catch (err) {
1346
1565
  console.warn(
1347
1566
  `skaile: could not render MCP config for ${this.driverTarget}: ${err instanceof Error ? err.message : String(err)}`
1348
1567
  );
1568
+ return [];
1569
+ }
1570
+ if (before.length === 0) return [];
1571
+ const after = await this.mcpDriftRows();
1572
+ const restored = [];
1573
+ for (const { ref, key, drift } of before) {
1574
+ const left = after.find((a) => a.ref === ref)?.drift;
1575
+ const stillWrong = /* @__PURE__ */ new Set([...left?.missing ?? [], ...left?.modified ?? []]);
1576
+ const rewritten = [...drift.missing, ...drift.modified].filter((f) => !stillWrong.has(f));
1577
+ const removed = drift.extra.filter((f) => !left?.extra.includes(f));
1578
+ if (rewritten.length > 0 || removed.length > 0)
1579
+ restored.push({ ref: key, restored: rewritten, removed });
1349
1580
  }
1581
+ return restored;
1350
1582
  }
1351
1583
  /**
1352
1584
  * Render every agent instance of `skaile.yaml` into the driver target's native
@@ -1362,16 +1594,21 @@ var AssetManager = class {
1362
1594
  projectDir: this.projectDir,
1363
1595
  driverTarget: this.driverTarget
1364
1596
  });
1597
+ const details = [];
1365
1598
  for (const u of unboundAgentInstances(this.projectDir, this.driverTarget)) {
1366
1599
  if (!u.ref.startsWith("agent:")) continue;
1367
1600
  const at = result.errors.findIndex((e) => e.startsWith(`agent instance "${u.id}":`));
1368
- if (at >= 0) result.errors[at] += ` \u2014 ${(await this.unboundAgentAdvice(u.ref)).advice}`;
1601
+ if (at < 0) continue;
1602
+ details.push(result.errors[at]);
1603
+ const { lead, advice } = await this.unboundAgentAdvice(u.ref);
1604
+ result.errors[at] = `agent instance "${u.id}" is bound to ${u.ref} but ${lead} \u2014 ${advice}`;
1369
1605
  }
1370
1606
  for (const w of [...result.warnings, ...result.errors]) console.warn(`skaile: ${w}`);
1371
1607
  return {
1372
1608
  agentInstances: result.instances,
1373
1609
  agentFilesRemoved: result.removed,
1374
- ...result.errors.length > 0 ? { agentInstanceErrors: result.errors } : {}
1610
+ ...result.errors.length > 0 ? { agentInstanceErrors: result.errors } : {},
1611
+ ...details.length > 0 ? { agentInstanceDetails: details } : {}
1375
1612
  };
1376
1613
  } catch (err) {
1377
1614
  console.warn(
@@ -1610,13 +1847,13 @@ var AssetManager = class {
1610
1847
  candidates.sort(libraryPreference(isDefaultLib, prefer));
1611
1848
  const hit = candidates[0];
1612
1849
  if (hit.entry.version && !SEMVER_RE.test(hit.entry.version)) {
1613
- throw new Error(
1850
+ throw new LibraryEntryError(
1614
1851
  `${canonicalEntryRef(hit.entry)} (library ${hit.library}): ${invalidSemverMessage(hit.entry.version)}. Set a valid version in the asset file and run \`skaile library index ${hit.library}\`.`
1615
1852
  );
1616
1853
  }
1617
1854
  const flowFileError = hit.entry.kind === "flow" && hit.entry.source ? flowFileNameError({ id: hit.entry.name }, hit.entry.source.split(/[\\/]/).pop()) : void 0;
1618
1855
  if (flowFileError) {
1619
- throw new Error(
1856
+ throw new LibraryEntryError(
1620
1857
  `${canonicalEntryRef(hit.entry)} (library ${hit.library}): ${flowFileError}. Fix it, then run \`skaile library index ${hit.library}\`.`
1621
1858
  );
1622
1859
  }
@@ -1954,7 +2191,11 @@ var AssetManager = class {
1954
2191
  if (!origin) continue;
1955
2192
  const plain = want.publisher ? `${want.kind}:@${want.publisher}/${want.name}` : `${want.kind}:${want.name}`;
1956
2193
  const moved = findings.get(ref)?.moved;
1957
- const lookup = this.lockedLibrary(origin, snap);
2194
+ const lookup = this.lockedLibrary(
2195
+ origin,
2196
+ snap,
2197
+ want.publisher ? { kind: want.kind, publisher: want.publisher, name: want.name } : void 0
2198
+ );
1958
2199
  if (moved?.library && want.publisher) {
1959
2200
  out.set(
1960
2201
  ref,
@@ -1964,6 +2205,8 @@ var AssetManager = class {
1964
2205
  out.set(ref, lockedLibraryProblem(lookup, origin, plain));
1965
2206
  } else if (lookup.state === "unregistered") {
1966
2207
  out.set(ref, unregisteredLibraryFix(origin, plain));
2208
+ } else if (await this.pinNeverHeld(ref, plain, lookup, out)) {
2209
+ continue;
1967
2210
  } else {
1968
2211
  const renamedTo = await this.renamedFlowRef(lookup, want.publisher, want.kind, want.name);
1969
2212
  out.set(
@@ -1974,6 +2217,22 @@ var AssetManager = class {
1974
2217
  }
1975
2218
  return out;
1976
2219
  }
2220
+ /**
2221
+ * A ref pinned to a version its library never held (`#9.9.9`): the thing to change is the pin
2222
+ * in `skaile.yaml`, not the library (p1096). Sets the fix and returns `true` when it applies.
2223
+ */
2224
+ async pinNeverHeld(ref, plain, lookup, out) {
2225
+ const pin = (ref.split(" ")[0] ?? ref).split("#")[1];
2226
+ if (!pin || lookup.state !== "ok") return false;
2227
+ const held = (await this.resolveLibraryEntries([plain], { quiet: true, library: lookup.name })).entries[0];
2228
+ if (!held?.version || held.version === pin) return false;
2229
+ const name = plain.split(/[:/]/).pop() ?? plain;
2230
+ out.set(
2231
+ ref,
2232
+ `Asset not found: ${plain}#${pin} (${name} has version(s): ${held.version}); change the pin in skaile.yaml`
2233
+ );
2234
+ return true;
2235
+ }
1977
2236
  /**
1978
2237
  * The ref a library now holds a flow under when a project still locks it by the slug of the
1979
2238
  * flow's `name:` (5.12.0 named a flow by `name:`; later releases name it by `id:`), or
@@ -1996,20 +2255,58 @@ var AssetManager = class {
1996
2255
  }
1997
2256
  /** Collision messages already printed by this instance (one warning per ref + library set). */
1998
2257
  warnedLibraryCollisions = /* @__PURE__ */ new Set();
2258
+ /**
2259
+ * Collisions of one `add`, held back until {@link flushLibraryCollisions} so a dependency
2260
+ * tree that touches several colliding assets prints one summary, not one line per asset
2261
+ * (p1097). `null` outside an `add`: a collision then warns at once.
2262
+ */
2263
+ collisionBatch = null;
1999
2264
  /**
2000
2265
  * Warn once when `key` is held by more than one library: names every library
2001
2266
  * with its version and the one chosen, so a silent pick can't surprise.
2002
2267
  */
2003
2268
  warnLibraryCollision(key, candidates, chosen, differing = []) {
2004
- const libraries = new Set(candidates.map((c) => c.library));
2005
- if (libraries.size < 2) return;
2006
- const held = candidates.map((c) => `${c.library} (${c.entry.version || "unversioned"})`);
2007
- const msg = `${key} exists in ${libraries.size} libraries: ${held.join(", ")} \u2014 using ${chosen.library} (${chosen.entry.version || "unversioned"}). Highest version wins; an equal version goes to the default library, then by name. ` + (differing.length > 0 ? `Same version, different content: ${chosen.library} and ${differing.join(", ")} hold ${chosen.entry.version || "unversioned"} with different bytes. ` : "") + `Pin a version (${key}#<version>) to choose another.`;
2269
+ const libraries = [...new Set(candidates.map((c) => c.library))];
2270
+ if (libraries.length < 2) return;
2271
+ const collision = {
2272
+ key,
2273
+ libraries,
2274
+ held: candidates.map((c) => `${c.library} (${c.entry.version || "unversioned"})`),
2275
+ chosen: chosen.library,
2276
+ version: chosen.entry.version || "unversioned",
2277
+ differing
2278
+ };
2279
+ if (this.collisionBatch) {
2280
+ this.collisionBatch.set(key, collision);
2281
+ return;
2282
+ }
2283
+ this.emitLibraryCollision(libraryCollisionMessage(collision), [key]);
2284
+ }
2285
+ /** Print each distinct collision message once; the sink also gets the keys it names. */
2286
+ emitLibraryCollision(msg, keys) {
2008
2287
  if (this.warnedLibraryCollisions.has(msg)) return;
2009
2288
  this.warnedLibraryCollisions.add(msg);
2010
- if (this.onLibraryCollision) this.onLibraryCollision(msg);
2289
+ if (this.onLibraryCollision) this.onLibraryCollision(msg, keys);
2011
2290
  else console.warn(`skaile: ${msg}`);
2012
2291
  }
2292
+ /**
2293
+ * End the batch of {@link collisionBatch}: one collision prints its full message; several
2294
+ * print one summary (how many libraries and assets, the library each asset came from, the
2295
+ * assets whose bytes differ). `verboseCollisions` prints every asset's full message instead.
2296
+ */
2297
+ flushLibraryCollisions() {
2298
+ const batch = this.collisionBatch ? [...this.collisionBatch.values()] : [];
2299
+ this.collisionBatch = null;
2300
+ if (batch.length === 0) return;
2301
+ if (batch.length === 1 || this.verboseCollisions) {
2302
+ for (const c of batch) this.emitLibraryCollision(libraryCollisionMessage(c), [c.key]);
2303
+ return;
2304
+ }
2305
+ this.emitLibraryCollision(
2306
+ libraryCollisionSummary(batch),
2307
+ batch.map((c) => c.key)
2308
+ );
2309
+ }
2013
2310
  /** Kind, name and bare publisher of a deploy entry; the publisher comes from its canonical ref. */
2014
2311
  entryIdentity(entry) {
2015
2312
  const ref = parseAssetRefLoose(canonicalEntryRef(entry));
@@ -2207,7 +2504,7 @@ var AssetManager = class {
2207
2504
  * name and URL: the lock does not change because it was installed on another machine. A
2208
2505
  * library renamed on this machine with `library rename` is locked under its new name.
2209
2506
  */
2210
- async libraryLockEntries(lib) {
2507
+ async libraryLockEntries(lib, relockGit = false) {
2211
2508
  if (lib.entries.length === 0) return {};
2212
2509
  const snap = await this.loadLibraryIndex();
2213
2510
  const previous = Object.entries(this.tryReadLock()?.assets ?? {}).filter(
@@ -2229,15 +2526,28 @@ var AssetManager = class {
2229
2526
  return id.kind === e.kind && id.name === e.name && id.publisher === publisher;
2230
2527
  })?.[1].library;
2231
2528
  if (locked) {
2232
- const lookup = this.lockedLibrary(locked, snap);
2233
- const renamedHere = !locked.url && !url && renamedLibraryName(locked.name) === name;
2234
- if (lookup.state === "ok" && lookup.name === name && !renamedHere) {
2529
+ const lookup = this.lockedLibrary(locked, snap, {
2530
+ kind: e.kind,
2531
+ publisher,
2532
+ name: e.name
2533
+ });
2534
+ const renamedHere = renamedLibraryName(locked.name) === name || lookup.state === "ok" && lookup.matched === "content";
2535
+ const keepName = !renamedHere || Boolean(locked.url) && !relockGit;
2536
+ if (lookup.state === "ok" && lookup.name === name && keepName) {
2235
2537
  lockName = locked.name;
2236
2538
  if (locked.url && url && normalizeRepoUrl(locked.url) === normalizeRepoUrl(url)) {
2237
2539
  url = locked.url;
2238
2540
  }
2239
2541
  }
2240
2542
  }
2543
+ const requires = [
2544
+ ...new Set(
2545
+ libraryEntryDepRefs(e).flatMap((dep) => {
2546
+ const id = memberIdentity(dep);
2547
+ return id?.publisher ? [`${id.kind}:@${id.publisher}/${id.name}`] : [];
2548
+ })
2549
+ )
2550
+ ].sort();
2241
2551
  return {
2242
2552
  kind: e.kind,
2243
2553
  publisher,
@@ -2247,7 +2557,8 @@ var AssetManager = class {
2247
2557
  version: e.version || def?.version || "0.0.0",
2248
2558
  sha256,
2249
2559
  ...url ? { url } : {}
2250
- }
2560
+ },
2561
+ ...requires.length > 0 ? { requires } : {}
2251
2562
  };
2252
2563
  })
2253
2564
  );
@@ -2306,7 +2617,7 @@ var AssetManager = class {
2306
2617
  for (const [ref, e] of locked) {
2307
2618
  const { publisher, kind, name } = parseCanonicalLockKey(ref);
2308
2619
  if (!publisher || !kind || !name) continue;
2309
- const lookup = this.lockedLibrary(e.library, snap);
2620
+ const lookup = this.lockedLibrary(e.library, snap, { kind, publisher, name });
2310
2621
  if (lookup.state === "ok") continue;
2311
2622
  const component = this.installTarget(kind);
2312
2623
  const deployed = component !== void 0 && isDeployed(component, name, this.driverTarget, this.global, this.projectDir);
@@ -2339,7 +2650,7 @@ var AssetManager = class {
2339
2650
  missing.push(`${ref} (unparseable lock key)`);
2340
2651
  continue;
2341
2652
  }
2342
- const lookup = this.lockedLibrary(origin, snap);
2653
+ const lookup = this.lockedLibrary(origin, snap, { kind, publisher, name });
2343
2654
  if (lookup.state !== "ok") {
2344
2655
  missing.push(
2345
2656
  `${ref} (${lockedLibraryProblem(lookup, origin, `${kind}:@${publisher}/${name}`)})`
@@ -2360,9 +2671,14 @@ var AssetManager = class {
2360
2671
  const current = libraryAssetVersion(snap, lookup.name, { kind, publisher, name }, found.version) || "0.0.0";
2361
2672
  const sameVersion = current === origin.version || isPseudoVersion(current) && isPseudoVersion(origin.version);
2362
2673
  if (!sameVersion) {
2363
- missing.push(
2364
- `${ref} (library "${lookup.name}" is at ${current}, locked ${origin.version})`
2365
- );
2674
+ const component = this.installTarget(kind);
2675
+ const newer = gt(coerceVersion(current), coerceVersion(origin.version));
2676
+ const intact = newer && (component === void 0 || isDeployed(component, name, this.driverTarget, this.global, this.projectDir));
2677
+ if (!intact) {
2678
+ missing.push(
2679
+ `${ref} (library "${lookup.name}" is at ${current}, locked ${origin.version}${newer ? "; `skaile update` moves the lock to it" : ""})`
2680
+ );
2681
+ }
2366
2682
  continue;
2367
2683
  }
2368
2684
  if (origin.sha256) {
@@ -2394,6 +2710,30 @@ var AssetManager = class {
2394
2710
  return component !== void 0 && isDeployed(component, id.name, this.driverTarget, this.global, this.projectDir);
2395
2711
  });
2396
2712
  }
2713
+ /** Whether the deployed copy of a library asset is on disk; a kind with no install target has none to check. */
2714
+ lockedCopyDeployed(kind, name) {
2715
+ const component = this.installTarget(kind);
2716
+ return component === void 0 || isDeployed(component, name, this.driverTarget, this.global, this.projectDir);
2717
+ }
2718
+ /**
2719
+ * The library-origin lock entries `install` keeps when the library holds a newer version:
2720
+ * only `update` moves a locked asset, so `install` restores the locked one (p1095).
2721
+ * Keyed by `<publisher>/<kind>:<name>`. `requires` is what the locked version needs: the
2722
+ * lock's own list, or for a lock that predates the field the deployed copy's requirements,
2723
+ * never the newer library entry's.
2724
+ */
2725
+ async keepLockedLibraryEntries(lock) {
2726
+ if (!lock) return void 0;
2727
+ const out = /* @__PURE__ */ new Map();
2728
+ for (const [key, entry] of Object.entries(lock.assets)) {
2729
+ if (!entry.library || entry.library.installed || !entry.library.version) continue;
2730
+ const id = parseCanonicalLockKey(key);
2731
+ if (!id.publisher || !id.kind || !id.name) continue;
2732
+ const requires = entry.requires ?? await this.deployedRequirementsOf(id);
2733
+ out.set(`${id.publisher}/${id.kind}:${id.name}`, { key, entry, requires });
2734
+ }
2735
+ return out.size > 0 ? out : void 0;
2736
+ }
2397
2737
  /**
2398
2738
  * How the library `origin` names stands on this machine. THE one lookup of a locked library
2399
2739
  * ("is it registered here?"): `check`, `outdated`, `install` and `install --locked` all ask it.
@@ -2409,7 +2749,7 @@ var AssetManager = class {
2409
2749
  * `ok`, with `name` set to the name it is registered under here. The library name is
2410
2750
  * machine-local; the remote is what a clone shares.
2411
2751
  */
2412
- lockedLibrary(origin, snap) {
2752
+ lockedLibrary(origin, snap, asset) {
2413
2753
  const { name } = origin;
2414
2754
  if (name === GLOBAL_INSTALL_DIR_NAME) return { state: "unregistered" };
2415
2755
  let byName = { state: "unregistered" };
@@ -2430,13 +2770,29 @@ var AssetManager = class {
2430
2770
  const now = renamed ? snap?.libraries.find((l) => l.name === renamed) : void 0;
2431
2771
  if (now && existsSync(now.path)) return { state: "ok", path: now.path, name: now.name };
2432
2772
  }
2433
- if (byName.state === "ok" || !origin.url) return byName;
2434
- const wanted = normalizeRepoUrl(origin.url);
2435
- const byUrl = snap?.libraries.find((l) => {
2436
- const url = libraryRemoteUrl(l);
2437
- return l.name !== name && url !== void 0 && normalizeRepoUrl(url) === wanted && existsSync(l.path);
2438
- });
2439
- return byUrl ? { state: "ok", path: byUrl.path, name: byUrl.name } : byName;
2773
+ if (byName.state === "ok") return byName;
2774
+ if (origin.url) {
2775
+ const wanted = normalizeRepoUrl(origin.url);
2776
+ const byUrl = snap?.libraries.find((l) => {
2777
+ const url = libraryRemoteUrl(l);
2778
+ return l.name !== name && url !== void 0 && normalizeRepoUrl(url) === wanted && existsSync(l.path);
2779
+ });
2780
+ if (byUrl) return { state: "ok", path: byUrl.path, name: byUrl.name };
2781
+ }
2782
+ const holder = asset && origin.sha256 ? this.libraryHoldingLockedBytes(origin.sha256, asset, snap) : void 0;
2783
+ return holder ? { state: "ok", path: holder.path, name: holder.name, matched: "content" } : byName;
2784
+ }
2785
+ /** The registered library whose files for `asset` hash to `sha256` (the locked bytes), if any. */
2786
+ libraryHoldingLockedBytes(sha256, asset, snap) {
2787
+ if (!snap) return void 0;
2788
+ for (const l of snap.libraries) {
2789
+ if (!existsSync(l.path) || !newestLibraryDef(snap, l.name, asset)) continue;
2790
+ const onDisk = libraryDiskHashes(l.path, /* @__PURE__ */ new Map(), this.registry).get(
2791
+ `${asset.kind}:${asset.name}`
2792
+ );
2793
+ if (onDisk === sha256) return { name: l.name, path: l.path };
2794
+ }
2795
+ return void 0;
2440
2796
  }
2441
2797
  /** On-disk root of the library `origin` names; `null` unless {@link lockedLibrary} says `ok`. */
2442
2798
  libraryPath(origin, snap) {
@@ -2474,7 +2830,7 @@ var AssetManager = class {
2474
2830
  const { publisher, kind, name } = parseCanonicalLockKey(key);
2475
2831
  if (!publisher || !kind || !name) continue;
2476
2832
  const origin = e.library;
2477
- const lookup = this.lockedLibrary(origin, snap);
2833
+ const lookup = this.lockedLibrary(origin, snap, { kind, publisher, name });
2478
2834
  const resolved = lookup.state === "ok" ? lookup.name : origin.installed ? origin.name : null;
2479
2835
  out.set(`${kind}:${publisher}/${name}`, resolved);
2480
2836
  }
@@ -2559,6 +2915,8 @@ var AssetManager = class {
2559
2915
  const overridesApplied = /* @__PURE__ */ new Set();
2560
2916
  const presets = [];
2561
2917
  const requiredBy = /* @__PURE__ */ new Map();
2918
+ const keptVersions = {};
2919
+ const versionBlocked = [];
2562
2920
  const lib = { entries: [], resolved: /* @__PURE__ */ new Set(), libraryOf: /* @__PURE__ */ new Map() };
2563
2921
  const missing = /* @__PURE__ */ new Set();
2564
2922
  const seen = /* @__PURE__ */ new Set();
@@ -2569,6 +2927,15 @@ var AssetManager = class {
2569
2927
  if (id !== null) declaredById.set(id, d);
2570
2928
  }
2571
2929
  const presetParent = /* @__PURE__ */ new Map();
2930
+ const keepFor = (e, id, asked) => {
2931
+ const locked = opts.keepLocked?.get(id);
2932
+ const lockedVersion = locked?.entry.library?.version;
2933
+ if (!locked || !lockedVersion || !e.version) return void 0;
2934
+ if (isPseudoVersion(lockedVersion) || isPseudoVersion(e.version)) return void 0;
2935
+ if (!gt(coerceVersion(e.version), coerceVersion(lockedVersion))) return void 0;
2936
+ for (const r of asked) if (refIdentity(r) === id && r.includes("#")) return void 0;
2937
+ return locked;
2938
+ };
2572
2939
  const absorb = (hit) => {
2573
2940
  const next = [];
2574
2941
  for (const e of hit.entries) {
@@ -2576,7 +2943,8 @@ var AssetManager = class {
2576
2943
  const id = `${e.publisher}/${e.kind}:${e.name}`;
2577
2944
  seen.add(id);
2578
2945
  covered.add(id);
2579
- const deps2 = libraryEntryDepRefs(e);
2946
+ const keep = e.kind === "preset" ? void 0 : keepFor(e, id, hit.resolved);
2947
+ const deps2 = keep?.requires ?? libraryEntryDepRefs(e);
2580
2948
  if (e.kind === "preset") {
2581
2949
  const chain = [id];
2582
2950
  for (let up = presetParent.get(id); up !== void 0; up = presetParent.get(up)) {
@@ -2597,6 +2965,13 @@ var AssetManager = class {
2597
2965
  skipped: e.skippedItems ?? 0,
2598
2966
  ...origin ? { library: origin } : {}
2599
2967
  });
2968
+ } else if (keep) {
2969
+ keptVersions[keep.key] = keep.entry;
2970
+ if (!this.lockedCopyDeployed(e.kind, e.name)) {
2971
+ versionBlocked.push(
2972
+ `${keep.key} (library "${origin ?? keep.entry.library?.name}" is at ${e.version}, locked ${keep.entry.library?.version}; the deployed copy is gone and cannot be restored from the newer files \u2014 \`skaile update\` moves the lock to it)`
2973
+ );
2974
+ }
2600
2975
  } else {
2601
2976
  lib.entries.push(e);
2602
2977
  if (origin) lib.libraryOf.set(e, origin);
@@ -2611,7 +2986,10 @@ var AssetManager = class {
2611
2986
  for (const dep of deps2) {
2612
2987
  const depId = refIdentity(dep);
2613
2988
  if (depId !== null && declaredById.has(depId)) continue;
2614
- requiredBy.set(dep, [...requiredBy.get(dep) ?? [], canonicalEntryRef(e)]);
2989
+ requiredBy.set(dep, [
2990
+ ...requiredBy.get(dep) ?? [],
2991
+ keep ? keep.key : canonicalEntryRef(e)
2992
+ ]);
2615
2993
  }
2616
2994
  }
2617
2995
  }
@@ -2672,7 +3050,16 @@ var AssetManager = class {
2672
3050
  return !lib.resolved.has(m) && !(id !== null && covered.has(id));
2673
3051
  });
2674
3052
  this.keepUnchangedSourceVersions(resolved, [...deps, ...opts.declaredRefs ?? []]);
2675
- return { resolved, missing: stillMissing, overridesApplied, lib, presets, requiredBy };
3053
+ return {
3054
+ resolved,
3055
+ missing: stillMissing,
3056
+ overridesApplied,
3057
+ lib,
3058
+ presets,
3059
+ requiredBy,
3060
+ keptVersions,
3061
+ versionBlocked
3062
+ };
2676
3063
  }
2677
3064
  /**
2678
3065
  * A source asset without a declared version is keyed `0.0.0-sha.<repo commit>`, so every
@@ -2892,7 +3279,9 @@ var AssetManager = class {
2892
3279
  * @returns {@link InstallResult} summarising what was deployed, what was missing, and any collisions.
2893
3280
  */
2894
3281
  async install(opts) {
2895
- const { repositories, sources, stores, dependencies, overrides, patches } = this.loadConfig();
3282
+ const config = this.loadConfig();
3283
+ const { repositories, sources, stores, overrides, patches } = config;
3284
+ const dependencies = [...config.dependencies, ...this.lockedAgentBindings(config.dependencies)];
2896
3285
  if (opts?.locked) {
2897
3286
  return this.installLocked(repositories, patches, dependencies);
2898
3287
  }
@@ -2921,14 +3310,25 @@ var AssetManager = class {
2921
3310
  knownKinds: this.knownKinds,
2922
3311
  onSourceError: this.reportSourceError
2923
3312
  });
2924
- const { resolved, missing, overridesApplied, lib, presets, requiredBy } = await this.resolveLibraryFirst(dependencies, {
3313
+ const keepLocked = opts?.moveLibraries ? void 0 : await this.keepLockedLibraryEntries(lockForLibraries);
3314
+ const {
3315
+ resolved,
3316
+ missing,
3317
+ overridesApplied,
3318
+ lib,
3319
+ presets,
3320
+ requiredBy,
3321
+ keptVersions,
3322
+ versionBlocked
3323
+ } = await this.resolveLibraryFirst(dependencies, {
2925
3324
  provenanceIndex,
2926
3325
  overrides,
2927
3326
  stores,
2928
3327
  declaredRefs: dependencies,
2929
3328
  // `install` restores what the lock recorded: a changed default library or a second
2930
3329
  // library holding the same ref does not move a locked asset. `update` re-resolves.
2931
- ...opts?.moveLibraries ? { preferLocked: await this.lockedPreference() } : { lockedLibraries: await this.lockedLibraryNames() }
3330
+ ...opts?.moveLibraries ? { preferLocked: await this.lockedPreference() } : { lockedLibraries: await this.lockedLibraryNames() },
3331
+ ...keepLocked ? { keepLocked } : {}
2932
3332
  });
2933
3333
  this.assertNoFolderCollision([...resolved, ...lib.entries.map((e) => this.entryIdentity(e))]);
2934
3334
  if (!opts?.force && !(existsSync(this.lockPath) && this.tryReadLock() === null)) {
@@ -2985,17 +3385,22 @@ var AssetManager = class {
2985
3385
  missingHints[ref] = `${fix ? "" : missingHints[ref] ?? ""} (${notes.join("; ")})`;
2986
3386
  }
2987
3387
  const directLock = this.directInstallLockEntries();
2988
- const libraryLock = { ...directLock, ...await this.libraryLockEntries(lib) };
3388
+ const libraryLock = {
3389
+ ...directLock,
3390
+ ...await this.libraryLockEntries(lib, opts?.moveLibraries === true),
3391
+ ...keptVersions
3392
+ };
2989
3393
  const freshLock = {
2990
3394
  ...buildLockFile(resolved, overridesApplied, libraryLock),
2991
3395
  ...presetsLockSlice(presets)
2992
3396
  };
2993
3397
  await this.keepRequiredByKept(prevLock, kept, Object.keys(freshLock.assets));
3398
+ const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
3399
+ assertNoLibrarySymlinks(entries, this.registry, repositories, opts?.link === true);
2994
3400
  const { removed, replaced } = this.reconcileRemovedAssets(
2995
3401
  resolved,
2996
3402
  /* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
2997
3403
  );
2998
- const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
2999
3404
  const copyDrift = await this.lockedCopyDrift();
3000
3405
  const missingCopies = await this.incompleteDeploys();
3001
3406
  const unrecordedAgents = this.unrecordedAgentFiles(prevLock);
@@ -3012,9 +3417,9 @@ var AssetManager = class {
3012
3417
  )
3013
3418
  ];
3014
3419
  this.sweepLegacyOmpCopies(entries);
3015
- await this.renderDriverMcpConfig();
3420
+ const mcpRestored = await this.renderDriverMcpConfig();
3016
3421
  const agentRender = await this.renderAgentInstances();
3017
- const restored = this.restoredCopies(copyDrift, deployed, missingCopies);
3422
+ const restored = [...this.restoredCopies(copyDrift, deployed, missingCopies), ...mcpRestored];
3018
3423
  const rewritten = this.rewrittenAgentFiles(unrecordedAgents);
3019
3424
  const lockWanted = resolved.length > 0 || lib.entries.length > 0 || existsSync(this.lockPath);
3020
3425
  let lockWritten = false;
@@ -3022,8 +3427,9 @@ var AssetManager = class {
3022
3427
  let moved = [];
3023
3428
  if (lockWanted) {
3024
3429
  const lockData = this.withRenderedAgents(withKeptLockEntries(freshLock, kept));
3025
- relocked = relockedRefs(prevLock, lockData);
3026
3430
  moved = libraryMoves(prevLock, libraryLock);
3431
+ const movedRefs = new Set(moved.map((m) => m.ref));
3432
+ relocked = relockedRefs(prevLock, lockData).filter((k) => !movedRefs.has(k.split("#")[0]));
3027
3433
  lockWritten = writeLock(this.lockPath, lockData);
3028
3434
  }
3029
3435
  this.recordInstallHistory(deployed, removed);
@@ -3032,11 +3438,13 @@ var AssetManager = class {
3032
3438
  for (const n of storeNotChecked) delete missingHints[n.ref];
3033
3439
  await this.adviseMissing(reportedMissing, missingHints);
3034
3440
  const placeholderBodies = scaffoldBodyRefs(lib.entries, deployed);
3441
+ const placeholderDescriptions = scaffoldDescriptionRefs(lib.entries, deployed);
3035
3442
  return {
3036
3443
  deployed,
3037
3444
  removed,
3038
- missing: reportedMissing,
3445
+ missing: [...reportedMissing, ...versionBlocked.filter((b) => !reportedMissing.includes(b))],
3039
3446
  ...placeholderBodies.length > 0 ? { placeholderBodies } : {},
3447
+ ...placeholderDescriptions.length > 0 ? { placeholderDescriptions } : {},
3040
3448
  ...storeNotChecked.length > 0 ? { storeNotChecked } : {},
3041
3449
  ...Object.keys(missingHints).length > 0 ? { missingHints } : {},
3042
3450
  ...relocked.length > 0 ? { relocked } : {},
@@ -3410,7 +3818,8 @@ var AssetManager = class {
3410
3818
  async installLocked(repositories, patches, dependencies) {
3411
3819
  const lock = this.tryReadLock();
3412
3820
  if (!lock) {
3413
- const gaps2 = (await this.projectState()).gaps.filter((g) => g.type !== "agent");
3821
+ const all = (await this.projectState()).gaps;
3822
+ const gaps2 = all.filter((g) => g.type !== "agent");
3414
3823
  if (gaps2.some((g) => g.manualFix)) {
3415
3824
  return {
3416
3825
  deployed: [],
@@ -3422,10 +3831,11 @@ var AssetManager = class {
3422
3831
  };
3423
3832
  }
3424
3833
  if (dependencies.length === 0) {
3834
+ const unbound = all.filter((g) => g.type === "agent");
3425
3835
  return {
3426
3836
  deployed: [],
3427
3837
  removed: [],
3428
- missing: [],
3838
+ missing: unbound.map((g) => g.message),
3429
3839
  lockWritten: false,
3430
3840
  npmInstalled: [],
3431
3841
  npmFailed: []
@@ -3503,6 +3913,7 @@ var AssetManager = class {
3503
3913
  ${reason}`);
3504
3914
  }
3505
3915
  const library = await this.restoreLibraryLockEntries(lock);
3916
+ assertNoLibrarySymlinks([...resolved, ...library.entries], this.registry, repositories);
3506
3917
  const copyDrift = await this.lockedCopyDrift();
3507
3918
  const missingCopies = await this.incompleteDeploys();
3508
3919
  const unrecordedAgents = this.unrecordedAgentFiles(lock);
@@ -3519,9 +3930,9 @@ var AssetManager = class {
3519
3930
  )
3520
3931
  ];
3521
3932
  this.sweepLegacyOmpCopies([...resolved, ...library.entries]);
3522
- await this.renderDriverMcpConfig();
3933
+ const mcpRestored = await this.renderDriverMcpConfig();
3523
3934
  const agentRender = await this.renderAgentInstances();
3524
- const restored = this.restoredCopies(copyDrift, deployed, missingCopies);
3935
+ const restored = [...this.restoredCopies(copyDrift, deployed, missingCopies), ...mcpRestored];
3525
3936
  const rewritten = this.rewrittenAgentFiles(unrecordedAgents);
3526
3937
  const alreadyMissing = new Set(
3527
3938
  library.missing.map((m) => {
@@ -3535,11 +3946,13 @@ var AssetManager = class {
3535
3946
  return !(p && alreadyMissing.has(`${p.kind}:${p.name}`));
3536
3947
  }).map((g) => g.message);
3537
3948
  const placeholderBodies = scaffoldBodyRefs(library.entries, deployed);
3949
+ const placeholderDescriptions = scaffoldDescriptionRefs(library.entries, deployed);
3538
3950
  return {
3539
3951
  deployed,
3540
3952
  removed: [],
3541
3953
  missing: [...library.missing, ...gaps],
3542
3954
  ...placeholderBodies.length > 0 ? { placeholderBodies } : {},
3955
+ ...placeholderDescriptions.length > 0 ? { placeholderDescriptions } : {},
3543
3956
  lockWritten: false,
3544
3957
  ...restored.length > 0 ? { restored } : {},
3545
3958
  ...rewritten.length > 0 ? { rewritten } : {},
@@ -3657,17 +4070,21 @@ var AssetManager = class {
3657
4070
  knownKinds: this.knownKinds,
3658
4071
  onSourceError: this.reportSourceError
3659
4072
  });
3660
- const { resolved, missing, overridesApplied, lib, presets } = await this.resolveLibraryFirst(
3661
- [ref],
3662
- {
4073
+ this.collisionBatch = /* @__PURE__ */ new Map();
4074
+ let resolution;
4075
+ try {
4076
+ resolution = await this.resolveLibraryFirst([ref], {
3663
4077
  provenanceIndex,
3664
4078
  overrides,
3665
4079
  stores,
3666
4080
  declaredRefs: dependencies,
3667
4081
  warnCollisions: true,
3668
4082
  ...opts?.preferLockedLibrary ? { preferLocked: await this.lockedPreference() } : {}
3669
- }
3670
- );
4083
+ });
4084
+ } finally {
4085
+ this.flushLibraryCollisions();
4086
+ }
4087
+ const { resolved, missing, overridesApplied, lib, presets } = resolution;
3671
4088
  if (resolved.length === 0 && lib.entries.length === 0 && presets.length === 0) {
3672
4089
  const snap = await this.loadLibraryIndex();
3673
4090
  const bare = (p) => (p ?? "").replace(/^@/, "");
@@ -3752,6 +4169,8 @@ var AssetManager = class {
3752
4169
  );
3753
4170
  }
3754
4171
  const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
4172
+ assertFlowsLoad(entries);
4173
+ assertNoLibrarySymlinks(entries, this.registry, repositories, opts?.link === true);
3755
4174
  const deployed = [
3756
4175
  ...new Set(
3757
4176
  this.targetHarnesses().flatMap(
@@ -3759,7 +4178,7 @@ var AssetManager = class {
3759
4178
  this.entriesForHarness(entries, t),
3760
4179
  repositories,
3761
4180
  patches,
3762
- this.deployOptsFor(t, opts?.link, opts?.onSkippedSymlink, opts?.onEnvFile)
4181
+ this.deployOptsFor(t, opts?.link, opts?.onSecretFile)
3763
4182
  )
3764
4183
  )
3765
4184
  )
@@ -3776,6 +4195,9 @@ var AssetManager = class {
3776
4195
  for (const placeholder of scaffoldBodyRefs(lib.entries, deployed)) {
3777
4196
  opts?.onPlaceholderBody?.(placeholder);
3778
4197
  }
4198
+ for (const placeholder of scaffoldDescriptionRefs(lib.entries, deployed)) {
4199
+ opts?.onPlaceholderDescription?.(placeholder);
4200
+ }
3779
4201
  this.addDependencyToConfig(ref);
3780
4202
  await this.renderDriverMcpConfig();
3781
4203
  await this.renderAgentInstances();
@@ -4350,9 +4772,12 @@ var AssetManager = class {
4350
4772
  const lock = this.tryReadLock();
4351
4773
  if (!lock) return false;
4352
4774
  let changed = false;
4775
+ const droppedUrls = [];
4353
4776
  for (const key of Object.keys(lock.assets)) {
4354
4777
  const id = parseCanonicalLockKey(key);
4355
4778
  if (id.kind === parsed.kind && id.name === parsed.name && (!parsed.publisher || id.publisher === parsed.publisher)) {
4779
+ const url = lock.assets[key]?.source?.url;
4780
+ if (url) droppedUrls.push(url);
4356
4781
  delete lock.assets[key];
4357
4782
  changed = true;
4358
4783
  }
@@ -4368,7 +4793,7 @@ var AssetManager = class {
4368
4793
  changed = true;
4369
4794
  }
4370
4795
  }
4371
- if (changed) writeLock(this.lockPath, resyncLockSources(lock));
4796
+ if (changed) writeLock(this.lockPath, resyncLockSources(lock, droppedUrls));
4372
4797
  return changed;
4373
4798
  }
4374
4799
  // ── Query ──────────────────────────────────────────────────────────────
@@ -4614,11 +5039,24 @@ var AssetManager = class {
4614
5039
  (k) => k.kind === parsed.kind && k.name === parsed.name && (!parsed.publisher || k.publisher === parsed.publisher)
4615
5040
  );
4616
5041
  let state;
5042
+ let reason;
4617
5043
  if (!locked) {
4618
5044
  state = "declared";
4619
5045
  } else if (parsed.kind === "mcp-server") {
4620
5046
  const wired = await wiredMcpNames();
4621
- state = wired.has(parsed.name) || wired.has(unscopedName(parsed.name)) ? "installed" : "drift";
5047
+ const isWired = wired.has(parsed.name) || wired.has(unscopedName(parsed.name));
5048
+ const skippedReason = Object.entries(
5049
+ await readSkippedMcpServers(this.projectDir, this.driverTarget)
5050
+ ).find(([id]) => id === parsed.name || unscopedName(id) === parsed.name)?.[1];
5051
+ const drifted = (await this.mcpDriftRows()).some(
5052
+ (r) => unscopedName(r.drift.id) === unscopedName(parsed.name)
5053
+ );
5054
+ if (isWired && skippedReason !== void 0) {
5055
+ state = "skipped";
5056
+ reason = skippedReason;
5057
+ } else {
5058
+ state = isWired && !drifted ? "installed" : "drift";
5059
+ }
4622
5060
  } else {
4623
5061
  const component = this.installTarget(parsed.kind);
4624
5062
  if (!component) {
@@ -4634,7 +5072,40 @@ var AssetManager = class {
4634
5072
  state = onDisk ? "installed" : "drift";
4635
5073
  }
4636
5074
  }
4637
- out.push({ ref, kind: parsed.kind, name: parsed.name, state });
5075
+ out.push({ ref, kind: parsed.kind, name: parsed.name, state, ...reason ? { reason } : {} });
5076
+ }
5077
+ return out;
5078
+ }
5079
+ /**
5080
+ * Notes about the project's `mcp-server`s that are not drift and fail nothing: a declared
5081
+ * server skaile does not write to the coding agent's MCP config (`reason` from the last
5082
+ * render), and a required `MCP.md` field nothing sets. `check` and `doctor` print them as
5083
+ * `!` lines; `list` shows the first kind as `skipped`.
5084
+ *
5085
+ * @returns One {@link McpNotice} per note; empty for a global manager.
5086
+ */
5087
+ async mcpNotices() {
5088
+ if (this.global) return [];
5089
+ const out = [];
5090
+ const skipped = await readSkippedMcpServers(this.projectDir, this.driverTarget);
5091
+ for (const [id, reason] of Object.entries(skipped)) {
5092
+ out.push({ id, kind: "skipped", reason, text: `MCP server "${id}" is skipped: ${reason}` });
5093
+ }
5094
+ let decls = [];
5095
+ try {
5096
+ decls = await loadMcpServerDeclarations(this.projectDir);
5097
+ } catch {
5098
+ }
5099
+ for (const decl of decls) {
5100
+ if (skipped[decl.id] !== void 0) continue;
5101
+ const unset = unsetRequiredFields(decl);
5102
+ if (unset.length > 0) {
5103
+ out.push({
5104
+ id: decl.id,
5105
+ kind: "unset-field",
5106
+ text: `MCP server "${decl.id}" ${requiredFieldsAdvice(decl.id, unset)}`
5107
+ });
5108
+ }
4638
5109
  }
4639
5110
  return out;
4640
5111
  }
@@ -5048,7 +5519,7 @@ var AssetManager = class {
5048
5519
  const origin = entry.library;
5049
5520
  const { publisher, kind, name } = parseCanonicalLockKey(ref);
5050
5521
  if (!publisher || !kind || !name) continue;
5051
- const lookup = this.lockedLibrary(origin, snap);
5522
+ const lookup = this.lockedLibrary(origin, snap, { kind, publisher, name });
5052
5523
  if (lookup.state !== "ok") continue;
5053
5524
  const libPath = lookup.path;
5054
5525
  const scanKey = `${libPath}\0${publisher}`;
@@ -5241,7 +5712,11 @@ var AssetManager = class {
5241
5712
  if (want.publisher && id.publisher !== want.publisher) continue;
5242
5713
  const canonical = `${id.kind}:@${id.publisher}/${id.name}`;
5243
5714
  const refs = e.library.version ? [`${canonical}#${e.library.version}`, canonical] : [canonical];
5244
- const lookup = this.lockedLibrary(e.library, snap);
5715
+ const lookup = this.lockedLibrary(e.library, snap, {
5716
+ kind: id.kind,
5717
+ publisher: id.publisher,
5718
+ name: id.name
5719
+ });
5245
5720
  const library = lookup.state === "ok" ? lookup.name : e.library.name;
5246
5721
  for (const r of refs) {
5247
5722
  const hit = (await this.resolveLibraryEntries([r], { library })).entries[0];
@@ -5298,6 +5773,19 @@ var AssetManager = class {
5298
5773
  async diff(ref) {
5299
5774
  const parsed = parseRefTolerant(ref);
5300
5775
  if (!parsed) return { status: "not-found" };
5776
+ if (parsed.kind === "mcp-server") {
5777
+ const wantPub = parsed.publisher?.replace(/^@/, "");
5778
+ const lockedHere = Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey).filter((id) => id.kind === "mcp-server" && id.name === parsed.name);
5779
+ if (lockedHere.length > 0) {
5780
+ if (wantPub && !lockedHere.some((id) => id.publisher === wantPub)) {
5781
+ return { status: "not-deployed" };
5782
+ }
5783
+ const row = (await this.mcpDriftRows()).find(
5784
+ (r) => unscopedName(r.drift.id) === unscopedName(parsed.name)
5785
+ );
5786
+ return row ? { status: "differs", diff: mcpDriftDiff(row.drift) } : { status: "identical" };
5787
+ }
5788
+ }
5301
5789
  const entry = await this.lockedLibraryEntry(parsed) ?? this.lockedSourceEntry(parsed) ?? await this.info(ref);
5302
5790
  if (!entry || !existsSync(entry.source)) return { status: "not-found" };
5303
5791
  const wantPublisher = parsed.publisher?.replace(/^@/, "");
@@ -5680,6 +6168,22 @@ var AssetManager = class {
5680
6168
  gaps.push(gap);
5681
6169
  named.add(gapIdentity(gap.ref));
5682
6170
  }
6171
+ const skipped = [];
6172
+ const sourceIndex = await buildProvenanceIndex(
6173
+ this.buildClones(this.loadConfig().repositories),
6174
+ {
6175
+ projectDir: this.projectDir,
6176
+ knownKinds: this.knownKinds,
6177
+ onSourceError: (clone, err) => skipped.push({
6178
+ url: clone.sourceUrl,
6179
+ why: err instanceof Error ? err.message : String(err)
6180
+ })
6181
+ }
6182
+ );
6183
+ for (const gap of await this.sourceOriginGaps(named, sourceIndex)) {
6184
+ gaps.push(gap);
6185
+ named.add(gapIdentity(gap.ref));
6186
+ }
5683
6187
  const libraryHeld = (dep) => {
5684
6188
  const want = parseRefTolerant(dep);
5685
6189
  return want !== null && gaps.some((g) => g.type === "library" && sameAsset(g.ref, want));
@@ -5702,20 +6206,22 @@ var AssetManager = class {
5702
6206
  gaps.push({ type: "modified", ref: d.ref, reason, message: `${d.ref} ${reason}` });
5703
6207
  named.add(gapIdentity(d.ref));
5704
6208
  }
6209
+ for (const { ref, drift } of await this.mcpDriftRows()) {
6210
+ if (named.has(gapIdentity(ref))) continue;
6211
+ const parts = [
6212
+ ...drift.missing.map((f) => `${f} is missing`),
6213
+ ...drift.modified.map((f) => `${f} was edited`),
6214
+ ...drift.extra.map((f) => `${f} is not part of the asset`)
6215
+ ];
6216
+ const reason = `is locked, but its deployed copy differs from the lock (${parts.join("; ")}) \u2014 run \`skaile install --locked\` to restore it`;
6217
+ gaps.push({ type: "modified", ref, reason, message: `${ref} ${reason}` });
6218
+ named.add(gapIdentity(ref));
6219
+ }
5705
6220
  gaps.push(...await this.declaredGaps(requirements, named));
5706
6221
  for (const d of await this.incompleteDeploys()) {
5707
6222
  const reason = `is deployed without ${d.missing.join(", ")} \u2014 run \`skaile install --locked\` to restore it`;
5708
6223
  gaps.push({ type: "incomplete", ref: d.ref, reason, message: `${d.ref} ${reason}` });
5709
6224
  }
5710
- const skipped = [];
5711
- await buildProvenanceIndex(this.buildClones(this.loadConfig().repositories), {
5712
- projectDir: this.projectDir,
5713
- knownKinds: this.knownKinds,
5714
- onSourceError: (clone, err) => skipped.push({
5715
- url: clone.sourceUrl,
5716
- why: err instanceof Error ? err.message : String(err)
5717
- })
5718
- });
5719
6225
  for (const s of skipped) {
5720
6226
  const reason = `is skipped: ${s.why.replace(`${s.url}: `, "")} \u2014 fix it or run \`skaile source remove\``;
5721
6227
  gaps.push({
@@ -5773,12 +6279,12 @@ var AssetManager = class {
5773
6279
  ""
5774
6280
  );
5775
6281
  return {
5776
- lead: "the agent is locked but its library cannot supply it here",
6282
+ lead: "its agent is locked and the library cannot supply it here",
5777
6283
  advice: `${register}, ${drop}`
5778
6284
  };
5779
6285
  }
5780
6286
  return {
5781
- lead: "the agent is locked but not restored here",
6287
+ lead: "its agent is locked and not restored here",
5782
6288
  advice: `run \`skaile install --locked\` first, ${drop}`
5783
6289
  };
5784
6290
  }
@@ -5896,7 +6402,7 @@ var AssetManager = class {
5896
6402
  const { publisher, kind, name } = parseCanonicalLockKey(key);
5897
6403
  if (!publisher || !kind || !name || named.has(`${kind}:${name}`)) continue;
5898
6404
  const ref = `${kind}:@${publisher}/${name}`;
5899
- const lookup = this.lockedLibrary(origin, snap);
6405
+ const lookup = this.lockedLibrary(origin, snap, { kind, publisher, name });
5900
6406
  const libPath = lookup.state === "ok" ? lookup.path : null;
5901
6407
  if (lookup.state === "ok" && libPath) {
5902
6408
  const scanKey = `${libPath}\0${publisher}`;
@@ -5945,6 +6451,65 @@ var AssetManager = class {
5945
6451
  }
5946
6452
  return gaps;
5947
6453
  }
6454
+ /**
6455
+ * Locked source assets whose source cannot supply them any more: the source is no longer in
6456
+ * `skaile.yaml` `sources:` (`source remove`, a hand edit), or it is there but now publishes
6457
+ * the asset under another publisher (`source add <url> --publisher`). `skaile install` has
6458
+ * nothing to restore them from, so the fix is manual. A source of a store-resolved lock entry
6459
+ * is not told apart from one, so no source is called missing while a `stores:` entry exists.
6460
+ *
6461
+ * @param named - `kind:name` identities already reported; they are skipped.
6462
+ * @param index - What the registered sources publish today.
6463
+ */
6464
+ async sourceOriginGaps(named, index) {
6465
+ let config;
6466
+ try {
6467
+ config = this.loadConfig();
6468
+ } catch {
6469
+ return [];
6470
+ }
6471
+ const storeBacked = config.stores.length > 0 || (await this.globalStoreFallback(config.stores)).length > 0;
6472
+ const registered = new Set(config.sources.map((s) => sourceCacheKey(s.url)));
6473
+ const published = [...index.values()].flat();
6474
+ const gaps = [];
6475
+ for (const [key, entry] of Object.entries(this.tryReadLock()?.assets ?? {})) {
6476
+ const url = entry.source?.url;
6477
+ if (!url || entry.library || !GIT_URL.test(url)) continue;
6478
+ if (normalizeRepoUrl(url) === normalizeRepoUrl(FACTORY_SOURCE_URL)) continue;
6479
+ const { publisher, kind, name } = parseCanonicalLockKey(key);
6480
+ if (!publisher || !kind || !name || named.has(`${kind}:${name}`)) continue;
6481
+ const ref = `${kind}:@${publisher}/${name}`;
6482
+ if (!registered.has(sourceCacheKey(url))) {
6483
+ if (storeBacked && GITHUB_REPO_URL.test(url)) continue;
6484
+ const reason = `is locked, but its source ${url} is not in skaile.yaml sources: any more \u2014 register it again with \`skaile source add ${url}\`, or drop the dependency with \`skaile remove ${ref}\``;
6485
+ gaps.push({ type: "source", ref, reason, message: `${ref} ${reason}`, manualFix: true });
6486
+ continue;
6487
+ }
6488
+ const here = published.filter(
6489
+ (c) => c.kind === kind && c.name === name && sourceCacheKey(c.sourceUrl) === sourceCacheKey(url)
6490
+ );
6491
+ if (here.length > 0 && !here.some((c) => c.publisher === publisher)) {
6492
+ const now = here[0].publisher;
6493
+ const reason = `is locked, but source ${url} publishes it as ${kind}:@${now}/${name} now (the source's publisher changed) \u2014 run \`skaile source add ${url} --publisher ${publisher} --force\` to give it back, or change the ref in skaile.yaml to the new one`;
6494
+ gaps.push({ type: "source", ref, reason, message: `${ref} ${reason}`, manualFix: true });
6495
+ }
6496
+ }
6497
+ return gaps;
6498
+ }
6499
+ /**
6500
+ * The locked assets that come from the source `url` (a `sources:` entry): canonical refs,
6501
+ * `kind:@publisher/name`. `skaile source remove` refuses while this list is not empty.
6502
+ */
6503
+ lockedFromSource(url) {
6504
+ const want = sourceCacheKey(url);
6505
+ const out = [];
6506
+ for (const [key, entry] of Object.entries(this.tryReadLock()?.assets ?? {})) {
6507
+ if (entry.library || !entry.source || sourceCacheKey(entry.source.url) !== want) continue;
6508
+ const { publisher, kind, name } = parseCanonicalLockKey(key);
6509
+ if (kind && name) out.push(publisher ? `${kind}:@${publisher}/${name}` : `${kind}:${name}`);
6510
+ }
6511
+ return out;
6512
+ }
5948
6513
  /**
5949
6514
  * Record, on every agent entry of `lock` that has none, the files the agent's harness
5950
6515
  * rendering occupies and their sha256. Call it after the deploy, so the bytes hashed are the
@@ -6266,7 +6831,14 @@ var AssetManager = class {
6266
6831
  if (!renderedGone) continue;
6267
6832
  }
6268
6833
  const ref = publisher ? `${kind}:@${publisher}/${name}` : `${kind}:${name}`;
6269
- const reason = "is locked but its deployed copy is missing \u2014 run `skaile install --locked`";
6834
+ const dangling = deployedPaths(
6835
+ component,
6836
+ name,
6837
+ this.driverTarget,
6838
+ this.global,
6839
+ this.projectDir
6840
+ ).find((p) => isSymlink(p) && !existsSync(p));
6841
+ const reason = dangling ? `is locked but its deployed copy is a symlink to nothing (${relative(this.projectDir, dangling)}) \u2014 run \`skaile install --locked\`` : "is locked but its deployed copy is missing \u2014 run `skaile install --locked`";
6270
6842
  gaps.push({ type: "drift", ref, reason, message: `${ref} ${reason}` });
6271
6843
  }
6272
6844
  return gaps;
@@ -6715,6 +7287,33 @@ var AssetManager = class {
6715
7287
  writeFileSync(configPath, stringify(raw, { lineWidth: 120 }));
6716
7288
  return true;
6717
7289
  }
7290
+ /**
7291
+ * The locked agents an agent instance binds (`agents.<id>.ref`, `agent.definition`) that
7292
+ * `declared` does not name, as version-less `agent:@publisher/name`. An agent no lock entry
7293
+ * holds is left out: `install` does not add what the user never added (`skaile add` does).
7294
+ */
7295
+ lockedAgentBindings(declared) {
7296
+ const lock = this.tryReadLock();
7297
+ if (!lock) return [];
7298
+ const locked = Object.keys(lock.assets).map(parseCanonicalLockKey);
7299
+ const named = declared.map(memberIdentity);
7300
+ const out = [];
7301
+ for (const ref of this.declaredAgentInstanceRefs()) {
7302
+ const want = memberIdentity(ref.split("#")[0] ?? ref);
7303
+ if (want?.kind !== "agent") continue;
7304
+ const hit = locked.find(
7305
+ (id) => id.kind === "agent" && id.name === want.name && !!id.publisher && (!want.publisher || id.publisher === want.publisher)
7306
+ );
7307
+ if (!hit?.publisher) continue;
7308
+ if (named.some(
7309
+ (n) => n?.kind === "agent" && n.name === hit.name && (!n.publisher || n.publisher === hit.publisher)
7310
+ ))
7311
+ continue;
7312
+ const canonical = `agent:@${hit.publisher}/${hit.name}`;
7313
+ if (!out.includes(canonical)) out.push(canonical);
7314
+ }
7315
+ return out;
7316
+ }
6718
7317
  /** The refs `skaile.yaml` binds agent instances to: every `agents.<id>.ref` and `agent.definition`. Project mode only. */
6719
7318
  declaredAgentInstanceRefs() {
6720
7319
  if (this.global) return [];
@@ -6796,6 +7395,6 @@ var AssetManager = class {
6796
7395
  }
6797
7396
  };
6798
7397
 
6799
- export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
6800
- //# sourceMappingURL=chunk-W44KA24A.js.map
6801
- //# sourceMappingURL=chunk-W44KA24A.js.map
7398
+ export { AssetManager, FACTORY_SOURCE_URL, LibraryEntryError, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
7399
+ //# sourceMappingURL=chunk-TDQ2ERCM.js.map
7400
+ //# sourceMappingURL=chunk-TDQ2ERCM.js.map