@skaile/workspaces 5.18.1 → 5.19.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 +82 -0
  2. package/dist/{asset-feeds-MKB5JUML.js → asset-feeds-QGLI3AXI.js} +16 -16
  3. package/dist/{asset-feeds-MKB5JUML.js.map → asset-feeds-QGLI3AXI.js.map} +1 -1
  4. package/dist/asset-manager/catalog-deployer.js +5 -5
  5. package/dist/asset-manager/index.js +12 -12
  6. package/dist/asset-manager/installer.js +8 -8
  7. package/dist/asset-manager/renderers.js +7 -7
  8. package/dist/asset-manager/src/index.d.ts +91 -2
  9. package/dist/asset-manager/src/index.d.ts.map +1 -1
  10. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  11. package/dist/asset-manager/src/mcp-config.d.ts +29 -3
  12. package/dist/asset-manager/src/mcp-config.d.ts.map +1 -1
  13. package/dist/bridge/drivers/claude-sdk.js +22 -20
  14. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  15. package/dist/bridge/drivers/codex.js +11 -11
  16. package/dist/bridge/drivers/continue.js +10 -10
  17. package/dist/bridge/drivers/echo.js +2 -2
  18. package/dist/bridge/drivers/gemini.js +8 -8
  19. package/dist/bridge/drivers/goose.js +10 -10
  20. package/dist/bridge/drivers/omp.js +18 -460
  21. package/dist/bridge/drivers/omp.js.map +1 -1
  22. package/dist/bridge/drivers/opencode.js +10 -10
  23. package/dist/bridge/drivers/qwen.js +8 -8
  24. package/dist/bridge/index.js +15 -13
  25. package/dist/bridge/src/driver-model-check.d.ts +8 -4
  26. package/dist/bridge/src/driver-model-check.d.ts.map +1 -1
  27. package/dist/bridge/src/drivers/_subprocess-cli.d.ts.map +1 -1
  28. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  29. package/dist/bridge/src/drivers/omp-models-yml.d.ts +11 -0
  30. package/dist/bridge/src/drivers/omp-models-yml.d.ts.map +1 -1
  31. package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
  32. package/dist/{chunk-V3D4HQMS.js → chunk-25ZVWL2R.js} +4 -4
  33. package/dist/{chunk-V3D4HQMS.js.map → chunk-25ZVWL2R.js.map} +1 -1
  34. package/dist/{chunk-7FHZB2QU.js → chunk-2GXSSZAM.js} +3 -3
  35. package/dist/{chunk-7FHZB2QU.js.map → chunk-2GXSSZAM.js.map} +1 -1
  36. package/dist/{chunk-VOBXINUZ.js → chunk-2LSDMJI2.js} +3 -3
  37. package/dist/{chunk-VOBXINUZ.js.map → chunk-2LSDMJI2.js.map} +1 -1
  38. package/dist/{chunk-CKBCX3HQ.js → chunk-2PBSAH3Z.js} +4 -4
  39. package/dist/{chunk-CKBCX3HQ.js.map → chunk-2PBSAH3Z.js.map} +1 -1
  40. package/dist/{chunk-CKNIYIV2.js → chunk-335ENCCS.js} +5 -5
  41. package/dist/chunk-335ENCCS.js.map +1 -0
  42. package/dist/{chunk-PBSN4RTV.js → chunk-7NT4F6SR.js} +151 -27
  43. package/dist/chunk-7NT4F6SR.js.map +1 -0
  44. package/dist/{chunk-YARXR3CN.js → chunk-7SCS64BG.js} +13 -7
  45. package/dist/chunk-7SCS64BG.js.map +1 -0
  46. package/dist/{chunk-U2FI547Z.js → chunk-7XSAW5OC.js} +3 -3
  47. package/dist/{chunk-U2FI547Z.js.map → chunk-7XSAW5OC.js.map} +1 -1
  48. package/dist/{chunk-KSBDLCZI.js → chunk-A6SMCEEE.js} +2 -2
  49. package/dist/{chunk-KSBDLCZI.js.map → chunk-A6SMCEEE.js.map} +1 -1
  50. package/dist/{chunk-SRNCN4X2.js → chunk-C7WBGSBV.js} +4 -4
  51. package/dist/{chunk-SRNCN4X2.js.map → chunk-C7WBGSBV.js.map} +1 -1
  52. package/dist/chunk-COJIL7G4.js +505 -0
  53. package/dist/chunk-COJIL7G4.js.map +1 -0
  54. package/dist/{chunk-KY4UXX7M.js → chunk-CQJH4G2K.js} +2 -2
  55. package/dist/{chunk-KY4UXX7M.js.map → chunk-CQJH4G2K.js.map} +1 -1
  56. package/dist/{chunk-WJLYL6RY.js → chunk-F6AA42GW.js} +5 -5
  57. package/dist/{chunk-WJLYL6RY.js.map → chunk-F6AA42GW.js.map} +1 -1
  58. package/dist/{chunk-IW6F6R2W.js → chunk-FPHNJE4M.js} +102 -32
  59. package/dist/chunk-FPHNJE4M.js.map +1 -0
  60. package/dist/{chunk-ZBMC6IAE.js → chunk-HT35SQZD.js} +15 -14
  61. package/dist/chunk-HT35SQZD.js.map +1 -0
  62. package/dist/chunk-HU5HVKY7.js +285 -0
  63. package/dist/chunk-HU5HVKY7.js.map +1 -0
  64. package/dist/{chunk-HPVMTX6M.js → chunk-I37INEWE.js} +47 -12
  65. package/dist/chunk-I37INEWE.js.map +1 -0
  66. package/dist/{chunk-WJCQFNF6.js → chunk-I7TWVK6N.js} +3 -3
  67. package/dist/{chunk-WJCQFNF6.js.map → chunk-I7TWVK6N.js.map} +1 -1
  68. package/dist/{chunk-D6UBEYQH.js → chunk-IF6IA3PZ.js} +6 -6
  69. package/dist/chunk-IF6IA3PZ.js.map +1 -0
  70. package/dist/{chunk-AIBAOXDU.js → chunk-IP2IPMEH.js} +7 -7
  71. package/dist/{chunk-AIBAOXDU.js.map → chunk-IP2IPMEH.js.map} +1 -1
  72. package/dist/{chunk-X6GUNN7X.js → chunk-J24CY3PF.js} +8 -8
  73. package/dist/chunk-J24CY3PF.js.map +1 -0
  74. package/dist/{chunk-YZ3N7IUU.js → chunk-JTOWA6RS.js} +60 -19
  75. package/dist/{chunk-YZ3N7IUU.js.map → chunk-JTOWA6RS.js.map} +1 -1
  76. package/dist/{chunk-BBWSGVVE.js → chunk-MKRWN7XP.js} +4 -4
  77. package/dist/{chunk-BBWSGVVE.js.map → chunk-MKRWN7XP.js.map} +1 -1
  78. package/dist/{chunk-VM3PH7BB.js → chunk-MRHVPQNO.js} +519 -86
  79. package/dist/chunk-MRHVPQNO.js.map +1 -0
  80. package/dist/{chunk-A2ULN3KX.js → chunk-MWXYN6NY.js} +2 -2
  81. package/dist/{chunk-A2ULN3KX.js.map → chunk-MWXYN6NY.js.map} +1 -1
  82. package/dist/{chunk-T2TQAH2X.js → chunk-N46LQR46.js} +74 -18
  83. package/dist/chunk-N46LQR46.js.map +1 -0
  84. package/dist/{chunk-CD7SVH6W.js → chunk-PYJS5K7V.js} +3 -3
  85. package/dist/{chunk-CD7SVH6W.js.map → chunk-PYJS5K7V.js.map} +1 -1
  86. package/dist/{chunk-BO426QWN.js → chunk-QG6GHTRM.js} +4 -4
  87. package/dist/{chunk-BO426QWN.js.map → chunk-QG6GHTRM.js.map} +1 -1
  88. package/dist/{chunk-RD6N2D7I.js → chunk-R4I3VBSS.js} +2 -2
  89. package/dist/{chunk-RD6N2D7I.js.map → chunk-R4I3VBSS.js.map} +1 -1
  90. package/dist/{chunk-OYIENLJI.js → chunk-RO6VOM6Z.js} +15 -15
  91. package/dist/{chunk-OYIENLJI.js.map → chunk-RO6VOM6Z.js.map} +1 -1
  92. package/dist/{chunk-B4X2N7JQ.js → chunk-RPZVHXQ3.js} +12 -12
  93. package/dist/chunk-RPZVHXQ3.js.map +1 -0
  94. package/dist/{chunk-KC6HGWXN.js → chunk-TIIXG3PN.js} +3 -3
  95. package/dist/{chunk-KC6HGWXN.js.map → chunk-TIIXG3PN.js.map} +1 -1
  96. package/dist/{chunk-CKICWXMU.js → chunk-UQ33Y4DM.js} +139 -10
  97. package/dist/chunk-UQ33Y4DM.js.map +1 -0
  98. package/dist/{chunk-2NOLF7B2.js → chunk-V257LUBM.js} +16 -7
  99. package/dist/chunk-V257LUBM.js.map +1 -0
  100. package/dist/{chunk-2ABUJYVI.js → chunk-VIM3PWZM.js} +3 -3
  101. package/dist/{chunk-2ABUJYVI.js.map → chunk-VIM3PWZM.js.map} +1 -1
  102. package/dist/{chunk-3KMREAR2.js → chunk-VJ7NU7GD.js} +22 -22
  103. package/dist/{chunk-3KMREAR2.js.map → chunk-VJ7NU7GD.js.map} +1 -1
  104. package/dist/{chunk-GBYNC5V3.js → chunk-VSZWNUZC.js} +3 -3
  105. package/dist/{chunk-GBYNC5V3.js.map → chunk-VSZWNUZC.js.map} +1 -1
  106. package/dist/{chunk-XTO436PV.js → chunk-W4Q6CKJ5.js} +6 -6
  107. package/dist/chunk-W4Q6CKJ5.js.map +1 -0
  108. package/dist/{chunk-7ANRSTNR.js → chunk-WG6V4ISA.js} +34 -15
  109. package/dist/chunk-WG6V4ISA.js.map +1 -0
  110. package/dist/{chunk-RP3FZ2T6.js → chunk-WOIRYY5L.js} +110 -37
  111. package/dist/chunk-WOIRYY5L.js.map +1 -0
  112. package/dist/{chunk-WMF2C5U7.js → chunk-WST6UITC.js} +6 -6
  113. package/dist/{chunk-WMF2C5U7.js.map → chunk-WST6UITC.js.map} +1 -1
  114. package/dist/{chunk-X3AUS4RW.js → chunk-X4ZZTHU3.js} +4 -4
  115. package/dist/{chunk-X3AUS4RW.js.map → chunk-X4ZZTHU3.js.map} +1 -1
  116. package/dist/{chunk-GOK4QRJR.js → chunk-XJVBUDDJ.js} +5 -5
  117. package/dist/{chunk-GOK4QRJR.js.map → chunk-XJVBUDDJ.js.map} +1 -1
  118. package/dist/{chunk-VKPBUPH7.js → chunk-XM6T2AZ2.js} +36 -11
  119. package/dist/chunk-XM6T2AZ2.js.map +1 -0
  120. package/dist/{chunk-34C2EKWJ.js → chunk-XWOPZW26.js} +3 -3
  121. package/dist/{chunk-34C2EKWJ.js.map → chunk-XWOPZW26.js.map} +1 -1
  122. package/dist/{chunk-LW7ZI6EQ.js → chunk-Y5MBW5EU.js} +3 -3
  123. package/dist/chunk-Y5MBW5EU.js.map +1 -0
  124. package/dist/{chunk-U7V5SIFW.js → chunk-ZQSOJH6I.js} +36 -18
  125. package/dist/chunk-ZQSOJH6I.js.map +1 -0
  126. package/dist/{chunk-JYWW32JI.js → chunk-ZX4KRWRB.js} +17 -5
  127. package/dist/chunk-ZX4KRWRB.js.map +1 -0
  128. package/dist/claude-code-2PU7TITZ.js +10 -0
  129. package/dist/claude-code-2PU7TITZ.js.map +1 -0
  130. package/dist/cli/index.js +574 -492
  131. package/dist/cli/index.js.map +1 -1
  132. package/dist/cli/src/agent-checks.d.ts +5 -0
  133. package/dist/cli/src/agent-checks.d.ts.map +1 -1
  134. package/dist/cli/src/agent-pins.d.ts +18 -0
  135. package/dist/cli/src/agent-pins.d.ts.map +1 -0
  136. package/dist/cli/src/commands/catalog.d.ts +6 -0
  137. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  138. package/dist/cli/src/commands/config.d.ts.map +1 -1
  139. package/dist/cli/src/commands/diff.d.ts.map +1 -1
  140. package/dist/cli/src/commands/flow.d.ts +8 -8
  141. package/dist/cli/src/commands/flow.d.ts.map +1 -1
  142. package/dist/cli/src/commands/integration.d.ts.map +1 -1
  143. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  144. package/dist/cli/src/commands/library-index.d.ts +17 -5
  145. package/dist/cli/src/commands/library-index.d.ts.map +1 -1
  146. package/dist/cli/src/commands/library-publish.d.ts +3 -0
  147. package/dist/cli/src/commands/library-publish.d.ts.map +1 -1
  148. package/dist/cli/src/commands/migrate-assets.d.ts +2 -0
  149. package/dist/cli/src/commands/migrate-assets.d.ts.map +1 -1
  150. package/dist/cli/src/commands/migrate.d.ts.map +1 -1
  151. package/dist/cli/src/commands/outdated.d.ts.map +1 -1
  152. package/dist/cli/src/commands/plugin/claude-code.d.ts +6 -0
  153. package/dist/cli/src/commands/plugin/claude-code.d.ts.map +1 -1
  154. package/dist/cli/src/commands/plugin/codex.d.ts +19 -4
  155. package/dist/cli/src/commands/plugin/codex.d.ts.map +1 -1
  156. package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
  157. package/dist/cli/src/commands/project.d.ts +6 -3
  158. package/dist/cli/src/commands/project.d.ts.map +1 -1
  159. package/dist/cli/src/commands/providers.d.ts +13 -0
  160. package/dist/cli/src/commands/providers.d.ts.map +1 -1
  161. package/dist/cli/src/commands/run.d.ts.map +1 -1
  162. package/dist/cli/src/commands/serve-preflight.d.ts +23 -0
  163. package/dist/cli/src/commands/serve-preflight.d.ts.map +1 -1
  164. package/dist/cli/src/commands/serve.d.ts.map +1 -1
  165. package/dist/cli/src/commands/update.d.ts.map +1 -1
  166. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  167. package/dist/cli/src/driver-error.d.ts +7 -0
  168. package/dist/cli/src/driver-error.d.ts.map +1 -1
  169. package/dist/cli/src/flow-discovery.d.ts +69 -53
  170. package/dist/cli/src/flow-discovery.d.ts.map +1 -1
  171. package/dist/cli/src/plugin-store/index.d.ts +6 -2
  172. package/dist/cli/src/plugin-store/index.d.ts.map +1 -1
  173. package/dist/cli/src/skill-checks.d.ts +32 -1
  174. package/dist/cli/src/skill-checks.d.ts.map +1 -1
  175. package/dist/connectors/config.js +3 -3
  176. package/dist/connectors/index.js +18 -16
  177. package/dist/{connectors-YNQ3WJGM.js → connectors-RBGZ3M7G.js} +21 -19
  178. package/dist/{connectors-YNQ3WJGM.js.map → connectors-RBGZ3M7G.js.map} +1 -1
  179. package/dist/core/discovery.js +1 -1
  180. package/dist/core/index.js +5 -5
  181. package/dist/core/publish-manifest.js +1 -1
  182. package/dist/core/runtime-assets.js +3 -3
  183. package/dist/core/src/asset-roots.d.ts +14 -0
  184. package/dist/core/src/asset-roots.d.ts.map +1 -1
  185. package/dist/core/src/bind.d.ts +33 -14
  186. package/dist/core/src/bind.d.ts.map +1 -1
  187. package/dist/core/src/discovery.d.ts +1 -1
  188. package/dist/core/src/index.d.ts +4 -4
  189. package/dist/core/src/index.d.ts.map +1 -1
  190. package/dist/core/src/lock.d.ts +8 -0
  191. package/dist/core/src/lock.d.ts.map +1 -1
  192. package/dist/core/src/publish-manifest.d.ts +45 -10
  193. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  194. package/dist/core/src/workspace-config.d.ts +18 -1
  195. package/dist/core/src/workspace-config.d.ts.map +1 -1
  196. package/dist/core/workspace-config.js +2 -2
  197. package/dist/deploy/index.js +5 -5
  198. package/dist/discovery/index.js +3 -3
  199. package/dist/discovery/src/discover-manifest.d.ts +1 -1
  200. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  201. package/dist/discovery/src/discover.d.ts.map +1 -1
  202. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  203. package/dist/{ensure-sources-UJWEZSR3.js → ensure-sources-GKVLE6L5.js} +15 -15
  204. package/dist/{ensure-sources-UJWEZSR3.js.map → ensure-sources-GKVLE6L5.js.map} +1 -1
  205. package/dist/factory-assets/connectors/box.js +18 -16
  206. package/dist/factory-assets/connectors/deploy.js +18 -16
  207. package/dist/factory-assets/connectors/devserver.js +18 -16
  208. package/dist/factory-assets/connectors/flow/adapter.js +18 -16
  209. package/dist/factory-assets/connectors/flow/engine/loader.d.ts +1 -1
  210. package/dist/factory-assets/connectors/flow/engine/locate.d.ts +8 -5
  211. package/dist/factory-assets/connectors/flow/engine/locate.d.ts.map +1 -1
  212. package/dist/factory-assets/connectors/flow/engine.js +6 -6
  213. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  214. package/dist/factory-assets/connectors/flow/run-flow.js +19 -17
  215. package/dist/factory-assets/connectors/flow.js +18 -16
  216. package/dist/factory-assets/connectors/git.js +18 -16
  217. package/dist/factory-assets/connectors/gmail.js +18 -16
  218. package/dist/factory-assets/connectors/googledrive.js +18 -16
  219. package/dist/factory-assets/connectors/local.js +18 -16
  220. package/dist/factory-assets/connectors/mattermost.js +18 -16
  221. package/dist/factory-assets/connectors/memory.js +18 -16
  222. package/dist/factory-assets/connectors/minio.js +18 -16
  223. package/dist/factory-assets/connectors/postgres.js +18 -16
  224. package/dist/factory-assets/connectors/s3.js +18 -16
  225. package/dist/factory-assets/connectors/sharepoint.js +18 -16
  226. package/dist/factory-assets/connectors/sqlite.js +18 -16
  227. package/dist/factory-assets/connectors/static-server.js +18 -16
  228. package/dist/factory-assets/connectors/tunnel.js +18 -16
  229. package/dist/factory-assets/connectors/webdav.js +18 -16
  230. package/dist/factory-assets/connectors/xstate/adapter.d.ts +1 -1
  231. package/dist/factory-assets/connectors/xstate/adapter.d.ts.map +1 -1
  232. package/dist/factory-assets/connectors/xstate-store.js +18 -16
  233. package/dist/factory-assets/connectors/xstate.js +18 -16
  234. package/dist/factory-assets/skills/skaile-manage-workspace/SKILL.md +1 -1
  235. package/dist/{flows-BHY73K3O.js → flows-W2FB7WIM.js} +8 -8
  236. package/dist/{flows-BHY73K3O.js.map → flows-W2FB7WIM.js.map} +1 -1
  237. package/dist/{helpers-3CG7ZVX4.js → helpers-34QNVIGB.js} +15 -15
  238. package/dist/{helpers-3CG7ZVX4.js.map → helpers-34QNVIGB.js.map} +1 -1
  239. package/dist/library/index.js +9 -9
  240. package/dist/library/install.js +2 -2
  241. package/dist/library/src/index.d.ts +1 -1
  242. package/dist/library/src/index.d.ts.map +1 -1
  243. package/dist/library/src/manifest-writer.d.ts +13 -0
  244. package/dist/library/src/manifest-writer.d.ts.map +1 -1
  245. package/dist/{library-publish-NWWVYJUK.js → library-publish-RUQTKTJU.js} +125 -48
  246. package/dist/library-publish-RUQTKTJU.js.map +1 -0
  247. package/dist/model-endpoint/index.js +8 -8
  248. package/dist/{open-library-7ZG2FFAX.js → open-library-PVTIUQUF.js} +18 -18
  249. package/dist/{open-library-7ZG2FFAX.js.map → open-library-PVTIUQUF.js.map} +1 -1
  250. package/dist/{open-registry-RBELV5YH.js → open-registry-SOIS3TA2.js} +13 -13
  251. package/dist/{open-registry-RBELV5YH.js.map → open-registry-SOIS3TA2.js.map} +1 -1
  252. package/dist/{paths-BFM6K2QO.js → paths-JLNX7Y4X.js} +8 -8
  253. package/dist/{paths-BFM6K2QO.js.map → paths-JLNX7Y4X.js.map} +1 -1
  254. package/dist/{plugin-store-QOQDM24E.js → plugin-store-G2GWAHSD.js} +8 -8
  255. package/dist/{plugin-store-QOQDM24E.js.map → plugin-store-G2GWAHSD.js.map} +1 -1
  256. package/dist/{project-YQM3I25D.js → project-EX47PUBN.js} +38 -37
  257. package/dist/{project-YQM3I25D.js.map → project-EX47PUBN.js.map} +1 -1
  258. package/dist/resolver/index.js +5 -5
  259. package/dist/runner/index.js +30 -29
  260. package/dist/runner/src/agents/instances.d.ts.map +1 -1
  261. package/dist/runner/src/composition/compile.d.ts +11 -0
  262. package/dist/runner/src/composition/compile.d.ts.map +1 -1
  263. package/dist/runner/src/composition/index.d.ts +1 -1
  264. package/dist/runner/src/composition/index.d.ts.map +1 -1
  265. package/dist/runner/src/serve.d.ts.map +1 -1
  266. package/dist/runner/src/turn-end-contract.d.ts +55 -0
  267. package/dist/runner/src/turn-end-contract.d.ts.map +1 -0
  268. package/dist/runner/src/turn-scheduler.d.ts +5 -0
  269. package/dist/runner/src/turn-scheduler.d.ts.map +1 -1
  270. package/dist/sdk/asset-manager.js +12 -12
  271. package/dist/sdk/bridge.js +15 -13
  272. package/dist/sdk/core.js +5 -5
  273. package/dist/sdk/flow.js +6 -6
  274. package/dist/sdk/index.js +30 -29
  275. package/dist/sdk/index.js.map +1 -1
  276. package/dist/sdk/resolver.js +5 -5
  277. package/dist/sdk/runner.js +30 -29
  278. package/dist/sdk/transport/ws/server.js +6 -6
  279. package/dist/sdk/transport/ws.js +6 -6
  280. package/dist/sdk/transport.js +6 -6
  281. package/dist/serve-preflight-QXRKGOI5.js +108 -0
  282. package/dist/serve-preflight-QXRKGOI5.js.map +1 -0
  283. package/dist/{setup-AAHVAXRA.js → setup-AFZQNGKA.js} +25 -23
  284. package/dist/setup-AFZQNGKA.js.map +1 -0
  285. package/dist/{skills-RSZVUIYZ.js → skills-YYYC6D5X.js} +8 -8
  286. package/dist/{skills-RSZVUIYZ.js.map → skills-YYYC6D5X.js.map} +1 -1
  287. package/dist/{source-KWMCMEMB.js → source-DGPCT5IC.js} +40 -39
  288. package/dist/{source-KWMCMEMB.js.map → source-DGPCT5IC.js.map} +1 -1
  289. package/dist/{source-manifest-publish-EDYKM4YZ.js → source-manifest-publish-AGJ63JF2.js} +42 -41
  290. package/dist/source-manifest-publish-AGJ63JF2.js.map +1 -0
  291. package/dist/transport/index.js +6 -6
  292. package/dist/transport/src/ws/server.d.ts +1 -1
  293. package/dist/transport/src/ws/server.d.ts.map +1 -1
  294. package/dist/transport/ws/server.js +6 -6
  295. package/dist/transport/ws.js +6 -6
  296. package/dist/tui/index.js +30 -29
  297. package/dist/tui/index.js.map +1 -1
  298. package/dist/types/manifests.js +1 -1
  299. package/dist/types/src/manifests/scaffold-body.d.ts +6 -3
  300. package/dist/types/src/manifests/scaffold-body.d.ts.map +1 -1
  301. package/dist/workspace-plugin/adapters/mcp.js +22 -20
  302. package/dist/workspace-plugin/adapters/omp.js +14 -14
  303. package/dist/workspace-plugin/index.js +1 -1
  304. package/package.json +1 -1
  305. package/dist/chunk-2NOLF7B2.js.map +0 -1
  306. package/dist/chunk-7ANRSTNR.js.map +0 -1
  307. package/dist/chunk-B4X2N7JQ.js.map +0 -1
  308. package/dist/chunk-CKICWXMU.js.map +0 -1
  309. package/dist/chunk-CKNIYIV2.js.map +0 -1
  310. package/dist/chunk-D6UBEYQH.js.map +0 -1
  311. package/dist/chunk-HPVMTX6M.js.map +0 -1
  312. package/dist/chunk-IW6F6R2W.js.map +0 -1
  313. package/dist/chunk-JYWW32JI.js.map +0 -1
  314. package/dist/chunk-LW7ZI6EQ.js.map +0 -1
  315. package/dist/chunk-PBSN4RTV.js.map +0 -1
  316. package/dist/chunk-RP3FZ2T6.js.map +0 -1
  317. package/dist/chunk-T2TQAH2X.js.map +0 -1
  318. package/dist/chunk-U7V5SIFW.js.map +0 -1
  319. package/dist/chunk-VKPBUPH7.js.map +0 -1
  320. package/dist/chunk-VM3PH7BB.js.map +0 -1
  321. package/dist/chunk-X6GUNN7X.js.map +0 -1
  322. package/dist/chunk-XTO436PV.js.map +0 -1
  323. package/dist/chunk-YARXR3CN.js.map +0 -1
  324. package/dist/chunk-ZBMC6IAE.js.map +0 -1
  325. package/dist/library-publish-NWWVYJUK.js.map +0 -1
  326. package/dist/serve-preflight-5QMY7DBC.js +0 -60
  327. package/dist/serve-preflight-5QMY7DBC.js.map +0 -1
  328. package/dist/setup-AAHVAXRA.js.map +0 -1
  329. package/dist/source-manifest-publish-EDYKM4YZ.js.map +0 -1
@@ -1,18 +1,18 @@
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';
1
+ import { unregisteredLibraryNames, renamedLibraryName, resolveConfig, RemoteCatalogSource, OfflineError, describeCatalogError, CatalogHttpError, scanUnlistedAssets, missingRootAssets, storeManifestFile, missingLibraryDirMessage, filesEntryPaths } from './chunk-XM6T2AZ2.js';
2
+ import { SEMVER_RE, invalidSemverMessage, flowFileNameError, readManifestSourceConfig, discoverAssetsInTree, isManifestMode } from './chunk-I37INEWE.js';
3
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
+ import { installTargetOf, readKeptLegacyCopies, writeKeptLegacyCopies, canonicalEntryRef, diffDeployedAgent, deployedAssetDrift, assertNoLibrarySymlinks, deployAll, removeAsset, createScaffold, installAgent } from './chunk-JTOWA6RS.js';
5
5
  import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
6
6
  import { commitChanges } from './chunk-UQ6LFBPZ.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';
7
+ import { driverTargetSupportsAgents, CODEX_IDENTITY_DIR } from './chunk-C7WBGSBV.js';
8
+ import { isScaffoldBody, isScaffoldDescription } from './chunk-335ENCCS.js';
9
+ import { resolveConfiguredDriverTarget, GLOBAL_INSTALL_DIR_NAME, resolveLibraryDir, buildLibraryLockEntries, writeLock, computeHash, buildLockFile, readLock, assertLockHashes, verifyLock, mergeLockFile, resyncLockSources, extractForPatch, generatePatch, savePatch, applyPatch, LOCK_SCHEMA_VERSION } from './chunk-N46LQR46.js';
10
+ import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-TIIXG3PN.js';
11
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
+ 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-V257LUBM.js';
13
13
  import { globalSkaileDir, globalCacheRoot, migrateLegacyDir } from './chunk-L5VSIPQD.js';
14
14
  import { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS } from './chunk-IG5LZ3WU.js';
15
- import { listAssetFiles, loadSkPublishManifest, isNonAssetDir, isNonAssetFile } from './chunk-CKICWXMU.js';
15
+ import { loadSkPublishManifest, listAssetFiles, isNonAssetDir, isNonAssetFile } from './chunk-UQ33Y4DM.js';
16
16
  import { scanDirectory, parseFrontmatter, parseRequires, dedupeRequirements, readAssetBody } from './chunk-GOCWM7FN.js';
17
17
  import { parseAssetRef, parseAssetRefLoose, assetRefToStr, slugifyAssetName, depToStr, parseDep } from './chunk-WDXZA7QW.js';
18
18
  import { spawnSync } from 'child_process';
@@ -208,17 +208,17 @@ var UNSUPPORTED_SECRET_PREFIXES = [
208
208
  var TEMPLATE_PLACEHOLDER = /<[^<>\s/]+>/;
209
209
  var PAYLOAD_FETCH_TIMEOUT_MS = 6e4;
210
210
  var WORKSPACE_MARKER = /\$\{workspace\}/g;
211
- function substituteWorkspace(value, projectDir) {
212
- return value.replace(WORKSPACE_MARKER, projectDir);
211
+ function substituteWorkspace(value, absoluteRoot) {
212
+ return value.replace(WORKSPACE_MARKER, absoluteRoot ?? ".");
213
213
  }
214
214
  function renderSecretRef(value) {
215
215
  return value.startsWith("env:") ? `\${${value.slice(4)}}` : value;
216
216
  }
217
- function renderValueMap(map, projectDir) {
217
+ function renderValueMap(map, substitute) {
218
218
  if (!map) return void 0;
219
219
  const out = {};
220
220
  for (const [k, v] of Object.entries(map)) {
221
- out[k] = renderSecretRef(projectDir ? substituteWorkspace(v, projectDir) : v);
221
+ out[k] = renderSecretRef(substitute ? substitute(v) : v);
222
222
  }
223
223
  return Object.keys(out).length > 0 ? out : void 0;
224
224
  }
@@ -226,6 +226,12 @@ function findUnsupportedSecretRef(decl) {
226
226
  const values = [...Object.values(decl.env ?? {}), ...Object.values(decl.headers ?? {})];
227
227
  return values.find((v) => UNSUPPORTED_SECRET_PREFIXES.some((p) => v.startsWith(p)));
228
228
  }
229
+ function literalSecretField(decl) {
230
+ return (decl.fields ?? []).filter((f) => f.sensitive === true || f.type === "password").map((f) => f.key).find((key) => {
231
+ const value = decl.env?.[key];
232
+ return value !== void 0 && value !== "" && !value.startsWith("env:");
233
+ });
234
+ }
229
235
  function skipReason(decl) {
230
236
  if (RESERVED_MCP_SERVER_IDS.has(decl.id)) return "reserved id";
231
237
  if (decl.launcher === "recipe" || decl.launcher == null && decl.recipe != null) {
@@ -243,6 +249,10 @@ function skipReason(decl) {
243
249
  }
244
250
  const badRef = findUnsupportedSecretRef(decl);
245
251
  if (badRef) return `unsupported secret reference '${badRef}'`;
252
+ const literal = literalSecretField(decl);
253
+ if (literal) {
254
+ return `${literal} holds a literal secret, and .mcp.json is committed - set ${literal}: env:${literal} in the mcp_servers entry of skaile.yaml and export ${literal}, then run skaile install`;
255
+ }
246
256
  return void 0;
247
257
  }
248
258
  function payloadDir(projectDir, id) {
@@ -357,7 +367,7 @@ async function removePayloadDir(projectDir, id) {
357
367
  }
358
368
  await fs.rm(dir, { recursive: true, force: true });
359
369
  }
360
- function buildEntry(decl, projectDir) {
370
+ function buildEntry(decl, absoluteRoot) {
361
371
  const transport = decl.transport ?? "stdio";
362
372
  if (transport !== "stdio") {
363
373
  const entry2 = { type: transport, url: decl.url };
@@ -365,12 +375,13 @@ function buildEntry(decl, projectDir) {
365
375
  if (headers) entry2.headers = headers;
366
376
  return entry2;
367
377
  }
378
+ const workspace = (value) => substituteWorkspace(value, absoluteRoot);
368
379
  const entry = {
369
- command: substituteWorkspace(decl.command, projectDir)
380
+ command: workspace(decl.command)
370
381
  };
371
- const args = decl.args?.map((a) => substituteWorkspace(a, projectDir));
382
+ const args = decl.args?.map(workspace);
372
383
  if (args && args.length > 0) entry.args = args;
373
- const env = renderValueMap(decl.env, projectDir);
384
+ const env = renderValueMap(decl.env, workspace);
374
385
  if (env) entry.env = env;
375
386
  return entry;
376
387
  }
@@ -419,18 +430,32 @@ async function writeNotedSkips(projectDir, target, before, skipped) {
419
430
  else delete targets[target];
420
431
  await writeJson(notedSkipsPath(projectDir), { version: 1, targets });
421
432
  }
422
- async function readManagedIds(projectDir, target) {
433
+ async function readManaged(projectDir, target) {
423
434
  const state = await readJsonStrict(managedStatePath(projectDir));
424
435
  const ids = state?.targets?.[target];
425
- return Array.isArray(ids) ? ids : [];
436
+ const rendered = state?.rendered?.[target];
437
+ return {
438
+ ids: Array.isArray(ids) ? ids : [],
439
+ rendered: rendered && typeof rendered === "object" ? rendered : {}
440
+ };
426
441
  }
427
- async function writeManagedIds(projectDir, target, ids) {
442
+ async function writeManaged(projectDir, target, record) {
428
443
  const p = managedStatePath(projectDir);
429
444
  const state = await readJsonStrict(p) ?? { targets: {} };
430
445
  const targets = { ...state.targets ?? {} };
431
- if (ids.length > 0) targets[target] = ids;
432
- else delete targets[target];
433
- await writeJson(p, { version: 1, targets });
446
+ const rendered = { ...state.rendered ?? {} };
447
+ if (record.ids.length > 0) {
448
+ targets[target] = record.ids;
449
+ rendered[target] = record.rendered;
450
+ } else {
451
+ delete targets[target];
452
+ delete rendered[target];
453
+ }
454
+ await writeJson(p, {
455
+ version: 1,
456
+ targets,
457
+ ...Object.keys(rendered).length > 0 ? { rendered } : {}
458
+ });
434
459
  }
435
460
  async function removeEmptyLedger(projectDir) {
436
461
  const p = managedStatePath(projectDir);
@@ -469,12 +494,16 @@ function canonicalJson(value) {
469
494
  (_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
495
  );
471
496
  }
497
+ function entryHash(entry) {
498
+ return createHash("sha256").update(canonicalJson(entry)).digest("hex");
499
+ }
472
500
  async function mcpServerDrift(projectDir, driverTarget, opts = {}) {
473
501
  const relConfig = TARGET_MCP_CONFIG[driverTarget];
474
502
  if (!relConfig) return [];
475
503
  const declarations = opts.declarations ?? await loadMcpServerDeclarations(projectDir);
476
504
  const skippedNow = await readNotedSkips(projectDir, driverTarget);
477
- const managed = new Set(await readManagedIds(projectDir, driverTarget));
505
+ const ledger = await readManaged(projectDir, driverTarget);
506
+ const managed = new Set(ledger.ids);
478
507
  let servers = {};
479
508
  try {
480
509
  const file = await readJsonStrict(path.join(projectDir, relConfig));
@@ -486,7 +515,7 @@ async function mcpServerDrift(projectDir, driverTarget, opts = {}) {
486
515
  const out = [];
487
516
  for (const decl of declarations) {
488
517
  if (skippedNow[decl.id] !== void 0 || skipReason(decl)) continue;
489
- const drift = { id: decl.id, missing: [], modified: [], extra: [] };
518
+ const drift = { id: decl.id, missing: [], modified: [], extra: [], stale: [] };
490
519
  const dest = decl.payload ? rawPayloadDest(decl.payload) : void 0;
491
520
  const dir = payloadDir(projectDir, decl.id);
492
521
  if (decl.payload && dest !== void 0 && isPlainName(dest) && dir) {
@@ -510,18 +539,22 @@ async function mcpServerDrift(projectDir, driverTarget, opts = {}) {
510
539
  const owned = managed.has(decl.id);
511
540
  const lockedHere = opts.locked?.has(decl.id) || opts.locked?.has(decl.id.split("/").pop() ?? "");
512
541
  if (owned || lockedHere) {
513
- const expected = JSON.parse(JSON.stringify(buildEntry(decl, projectDir)));
542
+ const expected = JSON.parse(JSON.stringify(buildEntry(decl)));
514
543
  const actual = Object.hasOwn(servers, decl.id) ? servers[decl.id] : void 0;
515
544
  const label = `${relConfig} entry "${decl.id}"`;
516
545
  if (actual === void 0) {
517
546
  drift.missing.push(label);
518
547
  drift.entry = { expected, actual };
519
548
  } else if (owned && canonicalJson(actual) !== canonicalJson(expected)) {
520
- drift.modified.push(label);
549
+ const recorded = ledger.rendered[decl.id];
550
+ const untouched = recorded !== void 0 ? entryHash(actual) === recorded : entryHash(actual) === entryHash(buildEntry(decl, projectDir));
551
+ (untouched ? drift.stale : drift.modified).push(label);
521
552
  drift.entry = { expected, actual };
522
553
  }
523
554
  }
524
- if (drift.missing.length + drift.modified.length + drift.extra.length > 0) out.push(drift);
555
+ if (drift.missing.length + drift.modified.length + drift.extra.length + drift.stale.length > 0) {
556
+ out.push(drift);
557
+ }
525
558
  }
526
559
  return out;
527
560
  }
@@ -547,7 +580,7 @@ function mcpDriftDiff(drift) {
547
580
  for (const f of drift.extra)
548
581
  out.push(`--- ${f} (deployed)`, "+++ /dev/null (not part of the asset)");
549
582
  if (drift.entry) {
550
- const file = drift.missing.concat(drift.modified).find((f) => f.includes(" entry ")) ?? "MCP config entry";
583
+ const file = drift.missing.concat(drift.modified, drift.stale).find((f) => f.includes(" entry ")) ?? "MCP config entry";
551
584
  out.push(`--- ${file} (deployed)`, `+++ ${file} (declared)`);
552
585
  out.push(...jsonLineDiff(drift.entry.actual, drift.entry.expected));
553
586
  }
@@ -559,7 +592,29 @@ function unsetRequiredFields(decl) {
559
592
  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
593
  }
561
594
  function requiredFieldsAdvice(id, keys) {
562
- return `needs ${keys.join(", ")} (required): set it with an mcp_servers entry (id: ${id}, env: \u2026) in skaile.yaml`;
595
+ const setting = keys.map((k) => `${k}: env:${k}`).join(", ");
596
+ return `needs ${keys.join(", ")} (required): set it with an mcp_servers entry (id: ${id}, env: ${setting}) in skaile.yaml and export the variable, then run skaile install`;
597
+ }
598
+ function mcpConfigFileOf(driverTarget) {
599
+ return TARGET_MCP_CONFIG[driverTarget];
600
+ }
601
+ async function mcpRenderedFootprint(projectDir, driverTarget, name) {
602
+ const relConfig = TARGET_MCP_CONFIG[driverTarget];
603
+ if (!relConfig) return void 0;
604
+ const ledger = await readManaged(projectDir, driverTarget);
605
+ if (!ledger.ids.includes(name)) return void 0;
606
+ const dir = payloadDir(projectDir, name);
607
+ let hasPayload = false;
608
+ if (dir) {
609
+ try {
610
+ hasPayload = (await fs.stat(dir)).isDirectory();
611
+ } catch {
612
+ }
613
+ }
614
+ return {
615
+ file: relConfig,
616
+ ...dir && hasPayload ? { payloadDir: `${path.relative(projectDir, dir).split(path.sep).join("/")}/` } : {}
617
+ };
563
618
  }
564
619
  async function renderMcpServerConfig(projectDir, driverTarget, opts) {
565
620
  const warn = opts?.warn ?? ((m) => console.warn(`skaile: ${m}`));
@@ -579,10 +634,11 @@ async function renderMcpServerConfig(projectDir, driverTarget, opts) {
579
634
  }
580
635
  continue;
581
636
  }
582
- renderable.set(decl.id, buildEntry(decl, projectDir));
637
+ renderable.set(decl.id, buildEntry(decl));
583
638
  }
584
639
  await writeNotedSkips(projectDir, driverTarget, noted, skipped);
585
- const managedIds = await readManagedIds(projectDir, driverTarget);
640
+ const ledger = await readManaged(projectDir, driverTarget);
641
+ const managedIds = ledger.ids;
586
642
  const existingFile = await readJsonStrict(configPath);
587
643
  if (renderable.size === 0 && managedIds.length === 0 && !existingFile) {
588
644
  return { path: configPath, written: false, servers: [], removed: [], skipped };
@@ -602,8 +658,9 @@ async function renderMcpServerConfig(projectDir, driverTarget, opts) {
602
658
  const unset = unsetRequiredFields(decl);
603
659
  if (unset.length > 0) warn(`MCP server "${decl.id}" ${requiredFieldsAdvice(decl.id, unset)}`);
604
660
  }
605
- const ledgerStale = JSON.stringify(owned) !== JSON.stringify(managedIds);
606
- if (ledgerStale) await writeManagedIds(projectDir, driverTarget, owned);
661
+ const rendered = Object.fromEntries(owned.map((id) => [id, entryHash(next[id])]));
662
+ const ledgerStale = JSON.stringify(owned) !== JSON.stringify(managedIds) || canonicalJson(rendered) !== canonicalJson(ledger.rendered);
663
+ if (ledgerStale) await writeManaged(projectDir, driverTarget, { ids: owned, rendered });
607
664
  if (Object.keys(next).length === 0 && !existingFile) {
608
665
  return { path: configPath, written: false, servers: owned, removed, skipped };
609
666
  }
@@ -797,7 +854,10 @@ function isUnlistedLibraryAsset(entry, libPath) {
797
854
  if (listed.length === 0 && !manifestFileHasAssetsArray(libPath)) return false;
798
855
  const file = resolve(entry.source);
799
856
  return !listed.some((a) => {
800
- if (!a.root || a.source) return false;
857
+ if (a.source) return false;
858
+ const filesOnly = filesEntryPaths(libPath, a);
859
+ if (filesOnly) return filesOnly.some((f) => resolve(libPath, f) === file);
860
+ if (!a.root) return false;
801
861
  const root = resolve(libPath, a.root);
802
862
  return file === root || file.startsWith(root + sep);
803
863
  });
@@ -807,7 +867,7 @@ function withLibraryFiles(entry, libPath, cache, registry) {
807
867
  if (!byManifest) {
808
868
  byManifest = /* @__PURE__ */ new Map();
809
869
  const sourceConfig = readManifestSourceConfig(libPath, "library");
810
- if (sourceConfig && isManifestMode(sourceConfig)) {
870
+ if (sourceConfig && isManifestMode(sourceConfig) || existsSync(join(libPath, ".git"))) {
811
871
  for (const a of discoverAssetsInTree(libPath, { sourceConfig, registry }).assets) {
812
872
  const { assetRoot, files: files2 } = a.fileFilter;
813
873
  byManifest.set(
@@ -903,27 +963,32 @@ function libraryEntryDepRefs(e) {
903
963
  }
904
964
  return [...refs];
905
965
  }
906
- function assertFlowsLoad(entries) {
966
+ function flowLoadError(e) {
967
+ let file = e.source;
968
+ if (!file) return void 0;
969
+ let authored;
970
+ try {
971
+ if (lstatSync(file).isDirectory()) {
972
+ const inside = [`${e.name}.flow.yaml`, `${e.name}.flow.yml`, `${e.name}.flow.json`].map((n) => join(file, n)).find((p) => existsSync(p));
973
+ if (!inside) return void 0;
974
+ file = inside;
975
+ }
976
+ const raw = readFileSync(file, "utf8");
977
+ authored = /\.json$/i.test(file) ? JSON.parse(raw) : parse(raw);
978
+ } catch {
979
+ return void 0;
980
+ }
981
+ const parsed = parseFlowDefinition(authored);
982
+ if (parsed.ok) return void 0;
983
+ return parsed.errors.slice(0, 3).map((issue) => `${issue.path || "<root>"}: ${issue.message}`).join("; ");
984
+ }
985
+ function assertFlowsLoad(entries, done) {
907
986
  for (const e of entries) {
908
987
  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("; ");
988
+ const details = flowLoadError(e);
989
+ if (details === void 0) continue;
925
990
  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`
991
+ `${canonicalEntryRef(e).split("#")[0]} is not a flow the flow engine can load (${details}) \u2014 nothing was ${done}; fix the flow in its library or source`
927
992
  );
928
993
  }
929
994
  }
@@ -1542,6 +1607,50 @@ var AssetManager = class {
1542
1607
  }
1543
1608
  return out;
1544
1609
  }
1610
+ /**
1611
+ * What the render wrote for the `mcp-server` asset `name` into the coding agent's MCP
1612
+ * config: the config file and, for a server with a payload, the payload directory
1613
+ * (project-relative). `written` is false when the render left the server out (see
1614
+ * {@link AssetManager.mcpNotices}). `undefined` when the harness has no MCP config skaile
1615
+ * writes (`codex`, `omp`) or for a global manager: the asset is composed at run time only.
1616
+ */
1617
+ async mcpRenderFootprint(name) {
1618
+ if (this.global) return void 0;
1619
+ const file = mcpConfigFileOf(this.driverTarget);
1620
+ if (!file) return void 0;
1621
+ const footprint = await mcpRenderedFootprint(
1622
+ this.projectDir,
1623
+ this.driverTarget,
1624
+ unscopedName(name)
1625
+ );
1626
+ return footprint ? { ...footprint, written: true } : { file, written: false };
1627
+ }
1628
+ /**
1629
+ * The declared MCP servers whose `.mcp.json` entry skaile wrote and nothing edited, but that
1630
+ * `skaile.yaml` (or a newer asset) now renders differently: the config waits for
1631
+ * `skaile install`. Covers a locked `mcp-server` and an `mcp_servers:` entry alike; the
1632
+ * server is named by its lock identity when it has one, else `mcp-server:<id>`. Empty for a
1633
+ * global manager.
1634
+ */
1635
+ async mcpPendingRender() {
1636
+ if (this.global) return [];
1637
+ const file = mcpConfigFileOf(this.driverTarget);
1638
+ if (!file) return [];
1639
+ let rows;
1640
+ try {
1641
+ rows = await mcpServerDrift(this.projectDir, this.driverTarget, {
1642
+ locked: this.lockedMcpNames()
1643
+ });
1644
+ } catch {
1645
+ return [];
1646
+ }
1647
+ const keys = Object.keys(this.tryReadLock()?.assets ?? {}).map(parseCanonicalLockKey);
1648
+ return rows.filter((r) => r.stale.length > 0).map((r) => {
1649
+ const name = unscopedName(r.id);
1650
+ const publisher = keys.find((k) => k.kind === "mcp-server" && k.name === name)?.publisher;
1651
+ return { ref: publisher ? `mcp-server:@${publisher}/${name}` : `mcp-server:${name}`, file };
1652
+ });
1653
+ }
1545
1654
  /**
1546
1655
  * Render the project's declared MCP servers into the driver target's own
1547
1656
  * native MCP config (`<project>/.mcp.json` for `claude-code`), so the coding
@@ -1572,8 +1681,14 @@ var AssetManager = class {
1572
1681
  const restored = [];
1573
1682
  for (const { ref, key, drift } of before) {
1574
1683
  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));
1684
+ const stillWrong = /* @__PURE__ */ new Set([
1685
+ ...left?.missing ?? [],
1686
+ ...left?.modified ?? [],
1687
+ ...left?.stale ?? []
1688
+ ]);
1689
+ const rewritten = [...drift.missing, ...drift.modified, ...drift.stale].filter(
1690
+ (f) => !stillWrong.has(f)
1691
+ );
1577
1692
  const removed = drift.extra.filter((f) => !left?.extra.includes(f));
1578
1693
  if (rewritten.length > 0 || removed.length > 0)
1579
1694
  restored.push({ ref: key, restored: rewritten, removed });
@@ -2116,12 +2231,18 @@ var AssetManager = class {
2116
2231
  const id = refIdentity(d);
2117
2232
  if (id !== null) held.add(id);
2118
2233
  }
2234
+ const declaredSources = new Set(this.loadConfig().sources.map((s) => sourceCacheKey(s.url)));
2235
+ const orphanReaders = new Set(
2236
+ ((await this.loadLibraryIndex())?.libraries ?? []).filter(
2237
+ (l) => l.ownership === "reader" && "url" in l.backendConfig && !declaredSources.has(sourceCacheKey(l.backendConfig.url))
2238
+ ).map((l) => l.name)
2239
+ );
2119
2240
  for (const [ref, w] of wanted) {
2120
2241
  const origin = lockEntries.map(([key, e]) => ({ id: parseCanonicalLockKey(key), library: e.library })).find(
2121
2242
  ({ id, library }) => library && !library.installed && id.kind === w.kind && id.name === w.name && id.publisher === w.publisher
2122
2243
  )?.library?.name;
2123
2244
  const pool = [...scan.byKey.values()].flat().filter(
2124
- (c) => c.entry.kind === w.kind && c.entry.name === w.name && c.entry.publisher !== w.publisher && (origin ? c.library === origin : !held.has(`${c.entry.publisher}/${c.entry.kind}:${c.entry.name}`))
2245
+ (c) => c.entry.kind === w.kind && c.entry.name === w.name && c.entry.publisher !== w.publisher && !orphanReaders.has(c.library) && (origin ? c.library === origin : !held.has(`${c.entry.publisher}/${c.entry.kind}:${c.entry.name}`))
2125
2246
  );
2126
2247
  const publishers = new Set(pool.map((c) => c.entry.publisher));
2127
2248
  const best = publishers.size === 1 ? pool.sort(libraryPreference(scan.isDefaultLib))[0] : void 0;
@@ -2673,10 +2794,11 @@ var AssetManager = class {
2673
2794
  if (!sameVersion) {
2674
2795
  const component = this.installTarget(kind);
2675
2796
  const newer = gt(coerceVersion(current), coerceVersion(origin.version));
2676
- const intact = newer && (component === void 0 || isDeployed(component, name, this.driverTarget, this.global, this.projectDir));
2797
+ const comparable = !isPseudoVersion(current) && !isPseudoVersion(origin.version);
2798
+ const intact = (newer || comparable) && (component === void 0 || isDeployed(component, name, this.driverTarget, this.global, this.projectDir));
2677
2799
  if (!intact) {
2678
2800
  missing.push(
2679
- `${ref} (library "${lookup.name}" is at ${current}, locked ${origin.version}${newer ? "; `skaile update` moves the lock to it" : ""})`
2801
+ `${ref} (library "${lookup.name}" is at ${current}, locked ${origin.version}${newer || comparable ? "; `skaile update` moves the lock to it" : ""})`
2680
2802
  );
2681
2803
  }
2682
2804
  continue;
@@ -2799,6 +2921,30 @@ var AssetManager = class {
2799
2921
  const found = this.lockedLibrary(origin, snap);
2800
2922
  return found.state === "ok" ? found.path : null;
2801
2923
  }
2924
+ /**
2925
+ * Rename the library every library-origin lock entry names: `library rename <interim> <old>`
2926
+ * puts a library back under its old name, and an entry locked in between would keep the
2927
+ * interim name, so a later "register library again" advice would name a library nobody knows
2928
+ * any more (p893). Nothing is written when no entry names `from`.
2929
+ *
2930
+ * @returns the number of lock entries renamed.
2931
+ */
2932
+ renameLockedLibrary(from, to) {
2933
+ const lock = this.tryReadLock();
2934
+ if (!lock) return 0;
2935
+ let renamed = 0;
2936
+ const assets = {};
2937
+ for (const [key, entry] of Object.entries(lock.assets)) {
2938
+ if (entry.library && !entry.library.installed && entry.library.name === from) {
2939
+ assets[key] = { ...entry, library: { ...entry.library, name: to } };
2940
+ renamed++;
2941
+ } else {
2942
+ assets[key] = entry;
2943
+ }
2944
+ }
2945
+ if (renamed > 0) writeLock(this.lockPath, { ...lock, assets });
2946
+ return renamed;
2947
+ }
2802
2948
  /**
2803
2949
  * The `kind:@publisher/name` identities the lock holds for one `kind` and `name`, whatever
2804
2950
  * their publisher. `diff` uses it to accept a ref without a publisher only when it names
@@ -2932,7 +3078,7 @@ var AssetManager = class {
2932
3078
  const lockedVersion = locked?.entry.library?.version;
2933
3079
  if (!locked || !lockedVersion || !e.version) return void 0;
2934
3080
  if (isPseudoVersion(lockedVersion) || isPseudoVersion(e.version)) return void 0;
2935
- if (!gt(coerceVersion(e.version), coerceVersion(lockedVersion))) return void 0;
3081
+ if (coerceVersion(e.version) === coerceVersion(lockedVersion)) return void 0;
2936
3082
  for (const r of asked) if (refIdentity(r) === id && r.includes("#")) return void 0;
2937
3083
  return locked;
2938
3084
  };
@@ -2969,7 +3115,7 @@ var AssetManager = class {
2969
3115
  keptVersions[keep.key] = keep.entry;
2970
3116
  if (!this.lockedCopyDeployed(e.kind, e.name)) {
2971
3117
  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)`
3118
+ `${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 ${gt(coerceVersion(e.version ?? ""), coerceVersion(keep.entry.library?.version ?? "")) ? "newer" : "older"} files \u2014 \`skaile update\` moves the lock to it)`
2973
3119
  );
2974
3120
  }
2975
3121
  } else {
@@ -3031,6 +3177,12 @@ var AssetManager = class {
3031
3177
  resolved.push(c);
3032
3178
  }
3033
3179
  for (const o of r.overridesApplied) overridesApplied.add(o);
3180
+ if (opts.readStoreRequires) {
3181
+ const repositories = this.loadConfig().repositories;
3182
+ for (const c of r.resolved) {
3183
+ next.push(...await this.readStoreCandidateRequires(c, repositories));
3184
+ }
3185
+ }
3034
3186
  presets.push(...r.presets);
3035
3187
  const hit2 = await this.resolveLibraryEntries(
3036
3188
  r.missing.filter((m) => !libraryTried.has(m)),
@@ -3103,8 +3255,8 @@ var AssetManager = class {
3103
3255
  * project store should be synthesized — `local` sentinel, already-declared,
3104
3256
  * or no URL. Honours an explicit `catalogUrl` injection (`""` and `"local"` disable it).
3105
3257
  */
3106
- async globalStoreFallback(projectStores) {
3107
- let url = this.catalogUrlOverride;
3258
+ async globalStoreFallback(projectStores, honourOverride = true) {
3259
+ let url = honourOverride ? this.catalogUrlOverride : void 0;
3108
3260
  if (url === void 0) {
3109
3261
  try {
3110
3262
  const { resolveConfig: resolveConfig2 } = await import('./library/index.js');
@@ -3194,6 +3346,43 @@ var AssetManager = class {
3194
3346
  }
3195
3347
  return staged;
3196
3348
  }
3349
+ /**
3350
+ * The requirements a store candidate's own manifest declares (`metadata.requires`, a manifest
3351
+ * `dependencies:`) that its catalog row did not list, read from the staged bytes. The catalog
3352
+ * row is the store's own summary and may hold only same-kind ones; the deployed copy is what
3353
+ * `check` reads, so a requirement only the manifest names would be missing right after `add`
3354
+ * (p1221). Each one is added to the candidate's `deps` and `storeRequires` (the lock records
3355
+ * them) and returned so the caller resolves, deploys and locks it like any other dependency.
3356
+ * A candidate whose bytes come from a source clone, or that has none, adds nothing.
3357
+ */
3358
+ async readStoreCandidateRequires(c, repositories) {
3359
+ if (c.kind === "preset") return [];
3360
+ const staged = (await this.stageStoreAssets([c], repositories)).get(this.candidateKey(c));
3361
+ if (!staged) return [];
3362
+ let own;
3363
+ try {
3364
+ const scanned = await scanDirectory(dirname(staged), c.publisher, {
3365
+ knownKinds: this.knownKinds
3366
+ });
3367
+ own = scanned.find((e) => e.kind === c.kind && e.name === c.name);
3368
+ } catch {
3369
+ return [];
3370
+ }
3371
+ if (!own) return [];
3372
+ const known = new Set((c.deps ?? []).map((d) => refIdentity(qualifyDepRef(d, c.publisher))));
3373
+ const added = [];
3374
+ for (const ref of libraryEntryDepRefs(own)) {
3375
+ const id = refIdentity(ref);
3376
+ if (id === null || known.has(id)) continue;
3377
+ known.add(id);
3378
+ added.push(ref);
3379
+ }
3380
+ if (added.length > 0) {
3381
+ c.deps = [...c.deps ?? [], ...added];
3382
+ c.storeRequires = [...c.storeRequires ?? [], ...added];
3383
+ }
3384
+ return added;
3385
+ }
3197
3386
  /** Repo-relative path of a candidate's primary manifest (un-stripped). */
3198
3387
  primaryManifestRel(c) {
3199
3388
  const paths = (c.files ?? []).map((f) => f.path);
@@ -3298,6 +3487,19 @@ var AssetManager = class {
3298
3487
  npmFailed: []
3299
3488
  };
3300
3489
  }
3490
+ const orphans = await this.orphanedSourceGaps(
3491
+ await this.declaredLockKeys(lockForLibraries, dependencies)
3492
+ );
3493
+ if (orphans.size > 0) {
3494
+ return {
3495
+ deployed: [],
3496
+ removed: [],
3497
+ missing: [...orphans.values()].map((g) => g.message),
3498
+ lockWritten: false,
3499
+ npmInstalled: [],
3500
+ npmFailed: []
3501
+ };
3502
+ }
3301
3503
  }
3302
3504
  const cloneError = this.ensureSourceClones(
3303
3505
  repositories,
@@ -3328,7 +3530,8 @@ var AssetManager = class {
3328
3530
  // `install` restores what the lock recorded: a changed default library or a second
3329
3531
  // library holding the same ref does not move a locked asset. `update` re-resolves.
3330
3532
  ...opts?.moveLibraries ? { preferLocked: await this.lockedPreference() } : { lockedLibraries: await this.lockedLibraryNames() },
3331
- ...keepLocked ? { keepLocked } : {}
3533
+ ...keepLocked ? { keepLocked } : {},
3534
+ readStoreRequires: true
3332
3535
  });
3333
3536
  this.assertNoFolderCollision([...resolved, ...lib.entries.map((e) => this.entryIdentity(e))]);
3334
3537
  if (!opts?.force && !(existsSync(this.lockPath) && this.tryReadLock() === null)) {
@@ -3396,7 +3599,14 @@ var AssetManager = class {
3396
3599
  };
3397
3600
  await this.keepRequiredByKept(prevLock, kept, Object.keys(freshLock.assets));
3398
3601
  const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
3602
+ assertFlowsLoad(entries, "installed");
3399
3603
  assertNoLibrarySymlinks(entries, this.registry, repositories, opts?.link === true);
3604
+ if (!opts?.force) {
3605
+ await this.assertNoHandEditsPruned(
3606
+ resolved,
3607
+ /* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
3608
+ );
3609
+ }
3400
3610
  const { removed, replaced } = this.reconcileRemovedAssets(
3401
3611
  resolved,
3402
3612
  /* @__PURE__ */ new Set([...Object.keys(libraryLock), ...Object.keys(kept.assets)])
@@ -3620,6 +3830,46 @@ var AssetManager = class {
3620
3830
  const entries = this.tryReadLock()?.assets ?? {};
3621
3831
  return Object.fromEntries(Object.entries(entries).filter(([, e]) => e.library?.installed));
3622
3832
  }
3833
+ /**
3834
+ * Refuse to prune a stale lock entry (in the old lock, not in the new resolved set, with no
3835
+ * other version taking its place) whose deployed folder holds hand edits: the files that differ
3836
+ * from the lock are named, nothing is removed, and `--force` prunes anyway (OQ6).
3837
+ */
3838
+ async assertNoHandEditsPruned(resolved, keep) {
3839
+ const oldLock = this.tryReadLock();
3840
+ if (!oldLock) return;
3841
+ const resolvedRefs = [
3842
+ ...resolved.map((c) => `${c.kind}:@${c.publisher}/${c.name}#${c.version}`),
3843
+ ...keep
3844
+ ];
3845
+ const stale = /* @__PURE__ */ new Set();
3846
+ for (const key of Object.keys(oldLock.assets)) {
3847
+ if (resolvedRefs.includes(key)) continue;
3848
+ const { kind, name, publisher } = parseCanonicalLockKey(key);
3849
+ if (!kind || !name || kind === "preset") continue;
3850
+ const replaced = resolvedRefs.some((r) => {
3851
+ const o = parseCanonicalLockKey(r);
3852
+ return o.kind === kind && o.name === name && o.publisher === publisher;
3853
+ });
3854
+ if (!replaced) stale.add(key);
3855
+ }
3856
+ if (stale.size === 0) return;
3857
+ const lines = [];
3858
+ for (const d of await this.lockedCopyDrift()) {
3859
+ if (!stale.has(d.key)) continue;
3860
+ const files = [
3861
+ ...d.modified.map((f) => `${f} was edited`),
3862
+ ...d.extra.map((f) => `${f} is not part of the asset`)
3863
+ ];
3864
+ lines.push(`${d.ref} (${files.join("; ")})`);
3865
+ }
3866
+ if (lines.length === 0) return;
3867
+ throw new Error(
3868
+ `Not pruned: skaile.yaml no longer declares ${lines.length === 1 ? "an asset" : "assets"} whose deployed copy holds your edits:
3869
+ ${lines.join("\n ")}
3870
+ Nothing was changed. Declare it again to keep it, or run \`skaile install --force\` to prune it with its edits.`
3871
+ );
3872
+ }
3623
3873
  /**
3624
3874
  * Remove stale assets — those recorded in the old lock but absent from the
3625
3875
  * newly resolved set (`resolved` source candidates plus `keep`, the canonical
@@ -3843,7 +4093,15 @@ var AssetManager = class {
3843
4093
  }
3844
4094
  throw new Error("No lock file found. Run `skaile install` first.");
3845
4095
  }
4096
+ assertLockHashes(lock);
3846
4097
  this.assertNoFolderCollision(Object.keys(lock.assets).map(parseCanonicalLockKey));
4098
+ const orphaned = [...(await this.orphanedSourceGaps()).values()];
4099
+ if (orphaned.length > 0) {
4100
+ throw new Error(
4101
+ `Lock file verification failed:
4102
+ ${orphaned.map((g) => g.message).join("\n ")}`
4103
+ );
4104
+ }
3847
4105
  const declBySlug = new Map(Object.entries(repositories));
3848
4106
  const factoryUrl = normalizeRepoUrl(FACTORY_SOURCE_URL);
3849
4107
  const factoryDecl = Object.values(repositories).find((d) => d.factory);
@@ -3913,6 +4171,7 @@ var AssetManager = class {
3913
4171
  ${reason}`);
3914
4172
  }
3915
4173
  const library = await this.restoreLibraryLockEntries(lock);
4174
+ assertFlowsLoad([...resolved, ...library.entries], "installed");
3916
4175
  assertNoLibrarySymlinks([...resolved, ...library.entries], this.registry, repositories);
3917
4176
  const copyDrift = await this.lockedCopyDrift();
3918
4177
  const missingCopies = await this.incompleteDeploys();
@@ -4079,6 +4338,7 @@ var AssetManager = class {
4079
4338
  stores,
4080
4339
  declaredRefs: dependencies,
4081
4340
  warnCollisions: true,
4341
+ readStoreRequires: true,
4082
4342
  ...opts?.preferLockedLibrary ? { preferLocked: await this.lockedPreference() } : {}
4083
4343
  });
4084
4344
  } finally {
@@ -4101,6 +4361,19 @@ var AssetManager = class {
4101
4361
  );
4102
4362
  }
4103
4363
  }
4364
+ for (const l of snap?.libraries ?? []) {
4365
+ const libPath = this.libraryPath({ name: l.name }, snap);
4366
+ const manifest = libPath ? loadSkPublishManifest(libPath) : null;
4367
+ if (!libPath || !manifest) continue;
4368
+ const gone = missingRootAssets(libPath, manifest).find(
4369
+ (a) => a.kind === parsed.kind && a.name === parsed.name && (!parsed.publisher || bare(a.publisher ?? manifest.publisher) === bare(parsed.publisher))
4370
+ );
4371
+ if (gone) {
4372
+ throw new Error(
4373
+ `library "${l.name}" lists ${parsed.kind}:${parsed.name} but its directory ${gone.root}/ is missing: run \`skaile library index ${l.name}\` to drop the entry, or restore the directory.`
4374
+ );
4375
+ }
4376
+ }
4104
4377
  const unreachable = [...this.storeFailures.values()];
4105
4378
  if (unreachable.length > 0) {
4106
4379
  throw new Error(
@@ -4169,8 +4442,20 @@ var AssetManager = class {
4169
4442
  );
4170
4443
  }
4171
4444
  const entries = [...await this.buildCatalogEntries(resolved, repositories), ...lib.entries];
4172
- assertFlowsLoad(entries);
4445
+ assertFlowsLoad(entries, "added");
4173
4446
  assertNoLibrarySymlinks(entries, this.registry, repositories, opts?.link === true);
4447
+ if (parsed.kind === "mcp-server" && !this.global) {
4448
+ const decls = await loadMcpServerDeclarations(this.projectDir, { alsoDeclared: [ref] });
4449
+ const mine = decls.find(
4450
+ (d) => d.id === parsed.name || unscopedName(d.id) === unscopedName(parsed.name)
4451
+ );
4452
+ const literal = mine ? literalSecretField(mine) : void 0;
4453
+ if (mine && literal) {
4454
+ throw new Error(
4455
+ `${ref.split("#")[0]}: ${literal} is set to a literal value, and .mcp.json is committed - write ${literal}: env:${literal} in the mcp_servers entry of skaile.yaml and export ${literal}. Nothing was added`
4456
+ );
4457
+ }
4458
+ }
4174
4459
  const deployed = [
4175
4460
  ...new Set(
4176
4461
  this.targetHarnesses().flatMap(
@@ -5049,7 +5334,7 @@ var AssetManager = class {
5049
5334
  await readSkippedMcpServers(this.projectDir, this.driverTarget)
5050
5335
  ).find(([id]) => id === parsed.name || unscopedName(id) === parsed.name)?.[1];
5051
5336
  const drifted = (await this.mcpDriftRows()).some(
5052
- (r) => unscopedName(r.drift.id) === unscopedName(parsed.name)
5337
+ (r) => unscopedName(r.drift.id) === unscopedName(parsed.name) && r.drift.missing.length + r.drift.modified.length + r.drift.extra.length > 0
5053
5338
  );
5054
5339
  if (isWired && skippedReason !== void 0) {
5055
5340
  state = "skipped";
@@ -5076,6 +5361,22 @@ var AssetManager = class {
5076
5361
  }
5077
5362
  return out;
5078
5363
  }
5364
+ /**
5365
+ * One note per locked library asset whose library went back to an older version than the lock
5366
+ * (`library is at 0.1.0, locked 0.3.0`). Not drift: `install` keeps the lock and only `update`
5367
+ * moves it, so `check` and `doctor` print the note as a `!` line and still exit 0 (p1257).
5368
+ * Empty for a global manager or when the libraries cannot be read.
5369
+ */
5370
+ async libraryOlderNotices() {
5371
+ if (this.global) return [];
5372
+ try {
5373
+ return (await this.outdated()).filter((e) => e.library !== void 0 && e.libraryOlder !== void 0).map(
5374
+ (e) => `${e.kind}:${e.publisher ? `@${e.publisher.replace(/^@/, "")}/` : ""}${e.name}: library is at ${e.libraryOlder}, locked ${e.currentVersion} (library ${e.library}); \`skaile update\` moves the lock to it`
5375
+ );
5376
+ } catch {
5377
+ return [];
5378
+ }
5379
+ }
5079
5380
  /**
5080
5381
  * Notes about the project's `mcp-server`s that are not drift and fail nothing: a declared
5081
5382
  * server skaile does not write to the coding agent's MCP config (`reason` from the last
@@ -5142,8 +5443,13 @@ var AssetManager = class {
5142
5443
  }
5143
5444
  const locked = Object.entries(lock.assets).filter(([, e]) => e.library !== void 0 && !e.library.installed).map(([key]) => key);
5144
5445
  if (locked.length === 0) return out;
5145
- const lib = await this.resolveLibraryEntries(locked, { quiet: true });
5446
+ const lockedLibraries = await this.lockedLibraryNames();
5447
+ const lib = await this.resolveLibraryEntries(locked, { quiet: true, lockedLibraries });
5146
5448
  for (const entry of lib.entries) {
5449
+ const lockedIn = lockedLibraries.get(
5450
+ `${entry.kind}:${(entry.publisher ?? "").replace(/^@/, "")}/${entry.name}`
5451
+ );
5452
+ if (lockedIn && lib.libraryOf.get(entry) !== lockedIn) continue;
5147
5453
  const component = this.installTarget(entry.kind);
5148
5454
  if (!entry.files || !component || component === "agent") continue;
5149
5455
  const dest = join(
@@ -5548,6 +5854,18 @@ var AssetManager = class {
5548
5854
  });
5549
5855
  continue;
5550
5856
  }
5857
+ if (diskVersion && diskVersion !== origin.version && !isPseudoVersion(diskVersion) && !isPseudoVersion(origin.version)) {
5858
+ result.push({
5859
+ kind,
5860
+ name,
5861
+ publisher,
5862
+ currentVersion: origin.version,
5863
+ behind: 0,
5864
+ library: lookup.name,
5865
+ libraryOlder: diskVersion
5866
+ });
5867
+ continue;
5868
+ }
5551
5869
  if (origin.sha256) {
5552
5870
  const onDisk = libraryDiskHashes(libPath, diskHashes, this.registry).get(
5553
5871
  `${kind}:${name}`
@@ -5568,8 +5886,56 @@ var AssetManager = class {
5568
5886
  await this.addLibraryMoves(libraryAssets, result);
5569
5887
  }
5570
5888
  await this.addRekeyRows(lock, result);
5889
+ await this.addPinnedRows(lock, result);
5571
5890
  return this.addLockGapRows(result);
5572
5891
  }
5892
+ /**
5893
+ * List a locked asset whose `skaile.yaml` ref carries a `#version` pin while a source, a
5894
+ * library or a store holds a newer one: `locked 0.7.0 -> 0.9.0 (pinned)`. The pin is the
5895
+ * user's choice, so the row only informs (`pinned`): `update` leaves it, `outdated` does not
5896
+ * fail on it (OQ13, p1291). An asset already listed keeps its own row.
5897
+ */
5898
+ async addPinnedRows(lock, rows) {
5899
+ const { dependencies, stores } = this.loadConfig();
5900
+ for (const dep of dependencies) {
5901
+ let parsed;
5902
+ try {
5903
+ parsed = parseAssetRef(dep);
5904
+ } catch {
5905
+ continue;
5906
+ }
5907
+ if (!parsed.pin || !parsed.publisher) continue;
5908
+ const publisher = parsed.publisher.replace(/^@/, "");
5909
+ const lockedKey = Object.keys(lock.assets).find((k) => {
5910
+ const id = parseCanonicalLockKey(k);
5911
+ return id.kind === parsed.kind && id.name === parsed.name && id.publisher === publisher;
5912
+ });
5913
+ const locked = lockedKey ? parseCanonicalLockKey(lockedKey).version : void 0;
5914
+ if (!locked || isPseudoVersion(locked)) continue;
5915
+ if (rows.some(
5916
+ (r) => r.kind === parsed.kind && r.name === parsed.name && r.publisher.replace(/^@/, "") === publisher
5917
+ )) {
5918
+ continue;
5919
+ }
5920
+ let latest;
5921
+ try {
5922
+ latest = (await this.availableVersions(parsed, stores))[0];
5923
+ } catch {
5924
+ continue;
5925
+ }
5926
+ if (!latest || isPseudoVersion(latest)) continue;
5927
+ if (!gt(coerceVersion(latest), coerceVersion(locked))) continue;
5928
+ rows.push({
5929
+ kind: parsed.kind,
5930
+ name: parsed.name,
5931
+ publisher,
5932
+ currentVersion: locked,
5933
+ behind: 0,
5934
+ latestVersion: latest,
5935
+ pinned: true
5936
+ });
5937
+ }
5938
+ }
5573
5939
  /**
5574
5940
  * List a source asset locked under a `0.0.0-sha.<commit>` key whose file now declares a
5575
5941
  * version: the next `install` or `update` re-keys it (`replaced 0.0.0-sha.7de3555 → 0.2.0`),
@@ -5783,7 +6149,13 @@ var AssetManager = class {
5783
6149
  const row = (await this.mcpDriftRows()).find(
5784
6150
  (r) => unscopedName(r.drift.id) === unscopedName(parsed.name)
5785
6151
  );
5786
- return row ? { status: "differs", diff: mcpDriftDiff(row.drift) } : { status: "identical" };
6152
+ if (!row) return { status: "identical" };
6153
+ const fileSetDiffers = row.drift.extra.length > 0 || row.drift.missing.some((f) => !f.includes(" entry "));
6154
+ return {
6155
+ status: "differs",
6156
+ diff: mcpDriftDiff(row.drift),
6157
+ ...fileSetDiffers ? { fileSetDiffers: true } : {}
6158
+ };
5787
6159
  }
5788
6160
  }
5789
6161
  const entry = await this.lockedLibraryEntry(parsed) ?? this.lockedSourceEntry(parsed) ?? await this.info(ref);
@@ -6193,6 +6565,15 @@ var AssetManager = class {
6193
6565
  gaps.push(gap);
6194
6566
  named.add(gapIdentity(gap.ref));
6195
6567
  }
6568
+ for (const f of this.listDeployed("flow")) {
6569
+ const details = flowLoadError(f);
6570
+ if (details === void 0) continue;
6571
+ const ref = lockIdentity("flow", f.name);
6572
+ if (named.has(gapIdentity(ref))) continue;
6573
+ const reason = `is not a flow the flow engine can load (${details}) \u2014 fix the flow (in its library or source when it came from one), then run skaile install`;
6574
+ gaps.push({ type: "flow", ref, reason, message: `${ref} ${reason}` });
6575
+ named.add(gapIdentity(ref));
6576
+ }
6196
6577
  for (const d of await this.lockedCopyDrift()) {
6197
6578
  if (named.has(gapIdentity(d.ref))) continue;
6198
6579
  const parts = [
@@ -6213,10 +6594,16 @@ var AssetManager = class {
6213
6594
  ...drift.modified.map((f) => `${f} was edited`),
6214
6595
  ...drift.extra.map((f) => `${f} is not part of the asset`)
6215
6596
  ];
6597
+ if (parts.length === 0) continue;
6216
6598
  const reason = `is locked, but its deployed copy differs from the lock (${parts.join("; ")}) \u2014 run \`skaile install --locked\` to restore it`;
6217
6599
  gaps.push({ type: "modified", ref, reason, message: `${ref} ${reason}` });
6218
6600
  named.add(gapIdentity(ref));
6219
6601
  }
6602
+ const pending = await this.mcpPendingRender();
6603
+ if (pending.length > 0) {
6604
+ const reason = `${pending[0].file} is out of date for skaile.yaml - run skaile install`;
6605
+ gaps.push({ type: "render", ref: pending[0].ref, reason, message: reason });
6606
+ }
6220
6607
  gaps.push(...await this.declaredGaps(requirements, named));
6221
6608
  for (const d of await this.incompleteDeploys()) {
6222
6609
  const reason = `is deployed without ${d.missing.join(", ")} \u2014 run \`skaile install --locked\` to restore it`;
@@ -6267,12 +6654,12 @@ var AssetManager = class {
6267
6654
  const drop = "or drop the binding from skaile.yaml";
6268
6655
  const parsedRef = parseRefTolerant(ref);
6269
6656
  const publisher = parsedRef?.publisher;
6270
- const lockedAgent = Object.keys(this.tryReadLock()?.assets ?? {}).some((key) => {
6657
+ const lockedAgentKey = Object.keys(this.tryReadLock()?.assets ?? {}).find((key) => {
6271
6658
  const k = parseCanonicalLockKey(key);
6272
6659
  return k.kind === "agent" && k.name === parsedRef?.name && (!publisher || !k.publisher || k.publisher === publisher);
6273
6660
  });
6274
- if (lockedAgent) {
6275
- const libraryFix = (await this.unresolvedFixes([ref])).get(ref);
6661
+ if (lockedAgentKey !== void 0) {
6662
+ const libraryFix = await this.lockedAgentLibraryHolds(lockedAgentKey) ? void 0 : (await this.unresolvedFixes([ref])).get(ref);
6276
6663
  if (libraryFix) {
6277
6664
  const register = libraryFix.replace(
6278
6665
  /, or drop the dependency with `skaile remove [^`]*`$/,
@@ -6313,6 +6700,26 @@ var AssetManager = class {
6313
6700
  advice: `register the library that holds it with \`skaile library init <name> --path <dir>\`, ${drop}`
6314
6701
  };
6315
6702
  }
6703
+ /**
6704
+ * Whether the library a locked agent names is here and holds the agent, or the agent comes
6705
+ * from a source or store: `install --locked` restores it, so its missing cache is no fault of
6706
+ * the library.
6707
+ */
6708
+ async lockedAgentLibraryHolds(lockKey) {
6709
+ const entry = this.tryReadLock()?.assets[lockKey];
6710
+ if (!entry) return false;
6711
+ if (!entry.library || entry.library.installed) return true;
6712
+ const { publisher, kind, name } = parseCanonicalLockKey(lockKey);
6713
+ if (!publisher || !kind || !name) return false;
6714
+ const lookup = this.lockedLibrary(entry.library, await this.loadLibraryIndex(), {
6715
+ kind,
6716
+ publisher,
6717
+ name
6718
+ });
6719
+ if (lookup.state !== "ok") return false;
6720
+ const scanned = await scanDirectory(lookup.path, publisher, { knownKinds: this.knownKinds });
6721
+ return scanned.some((x) => x.kind === kind && x.name === name);
6722
+ }
6316
6723
  /** @deprecated Use `(await projectState()).gaps`; removed in the next major. */
6317
6724
  async lockGaps() {
6318
6725
  return (await this.projectState()).gaps;
@@ -6421,7 +6828,7 @@ var AssetManager = class {
6421
6828
  { kind, publisher, name },
6422
6829
  found.version
6423
6830
  );
6424
- if (!diskVersion || isPseudoVersion(diskVersion) || !gt(coerceVersion(diskVersion), coerceVersion(origin.version))) {
6831
+ if (!diskVersion || isPseudoVersion(diskVersion) || !gt(coerceVersion(diskVersion), coerceVersion(origin.version)) && (isPseudoVersion(origin.version) || diskVersion === origin.version)) {
6425
6832
  const reason2 = `is locked, but library "${lookup.name}" content changed since lock \u2014 or the lock predates the one shared asset hash; run \`skaile install\` to re-lock it`;
6426
6833
  gaps.push({ type: "content", ref, reason: reason2, message: `${ref} ${reason2}` });
6427
6834
  }
@@ -6451,6 +6858,40 @@ var AssetManager = class {
6451
6858
  }
6452
6859
  return gaps;
6453
6860
  }
6861
+ /**
6862
+ * The locked source assets whose source is no longer in `skaile.yaml` `sources:` (`source
6863
+ * remove`, a hand edit), keyed by lock key. ONE sentence for it: `check`, `doctor`, `outdated`,
6864
+ * `install`, `install --locked` and `update` all say it (p1062), and none re-clones the source.
6865
+ * A source of a store-resolved lock entry is not told apart from one, so no GitHub source is
6866
+ * called missing while a `stores:` entry exists.
6867
+ *
6868
+ * @param inScope - Only these lock keys count (`install` prunes an undeclared entry as usual).
6869
+ */
6870
+ async orphanedSourceGaps(inScope) {
6871
+ const out = /* @__PURE__ */ new Map();
6872
+ let config;
6873
+ try {
6874
+ config = this.loadConfig();
6875
+ } catch {
6876
+ return out;
6877
+ }
6878
+ const storeBacked = config.stores.length > 0 || (await this.globalStoreFallback(config.stores, false)).length > 0;
6879
+ const registered = new Set(config.sources.map((s) => sourceCacheKey(s.url)));
6880
+ for (const [key, entry] of Object.entries(this.tryReadLock()?.assets ?? {})) {
6881
+ const url = entry.source?.url;
6882
+ if (!url || entry.library || !GIT_URL.test(url)) continue;
6883
+ if (inScope && !inScope.has(key)) continue;
6884
+ if (normalizeRepoUrl(url) === normalizeRepoUrl(FACTORY_SOURCE_URL)) continue;
6885
+ const { publisher, kind, name } = parseCanonicalLockKey(key);
6886
+ if (!publisher || !kind || !name) continue;
6887
+ if (registered.has(sourceCacheKey(url))) continue;
6888
+ if (storeBacked && GITHUB_REPO_URL.test(url)) continue;
6889
+ const ref = `${kind}:@${publisher}/${name}`;
6890
+ 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}\``;
6891
+ out.set(key, { type: "source", ref, reason, message: `${ref} ${reason}`, manualFix: true });
6892
+ }
6893
+ return out;
6894
+ }
6454
6895
  /**
6455
6896
  * Locked source assets whose source cannot supply them any more: the source is no longer in
6456
6897
  * `skaile.yaml` `sources:` (`source remove`, a hand edit), or it is there but now publishes
@@ -6462,14 +6903,7 @@ var AssetManager = class {
6462
6903
  * @param index - What the registered sources publish today.
6463
6904
  */
6464
6905
  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)));
6906
+ const orphans = await this.orphanedSourceGaps();
6473
6907
  const published = [...index.values()].flat();
6474
6908
  const gaps = [];
6475
6909
  for (const [key, entry] of Object.entries(this.tryReadLock()?.assets ?? {})) {
@@ -6479,10 +6913,9 @@ var AssetManager = class {
6479
6913
  const { publisher, kind, name } = parseCanonicalLockKey(key);
6480
6914
  if (!publisher || !kind || !name || named.has(`${kind}:${name}`)) continue;
6481
6915
  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 });
6916
+ const orphan = orphans.get(key);
6917
+ if (orphan) {
6918
+ gaps.push(orphan);
6486
6919
  continue;
6487
6920
  }
6488
6921
  const here = published.filter(
@@ -7396,5 +7829,5 @@ var AssetManager = class {
7396
7829
  };
7397
7830
 
7398
7831
  export { AssetManager, FACTORY_SOURCE_URL, LibraryEntryError, MissingManifestError, installAgentInstances, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
7399
- //# sourceMappingURL=chunk-VM3PH7BB.js.map
7400
- //# sourceMappingURL=chunk-VM3PH7BB.js.map
7832
+ //# sourceMappingURL=chunk-MRHVPQNO.js.map
7833
+ //# sourceMappingURL=chunk-MRHVPQNO.js.map