@skaile/workspaces 3.27.0 → 4.0.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 (346) hide show
  1. package/CHANGELOG.md +480 -0
  2. package/dist/app-sdk/index.js +1 -1
  3. package/dist/{asset-feeds-AJOUKX55.js → asset-feeds-OPG6SUXU.js} +11 -9
  4. package/dist/asset-feeds-OPG6SUXU.js.map +1 -0
  5. package/dist/asset-manager/catalog-deployer.js +5 -3
  6. package/dist/asset-manager/index.js +11 -9
  7. package/dist/asset-manager/installer.js +8 -6
  8. package/dist/asset-manager/renderers.js +2 -2
  9. package/dist/asset-manager/src/renderers.d.ts.map +1 -1
  10. package/dist/bridge/drivers/claude-sdk.js +102 -55
  11. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  12. package/dist/bridge/drivers/codex.js +178 -22
  13. package/dist/bridge/drivers/codex.js.map +1 -1
  14. package/dist/bridge/drivers/continue.js +199 -7
  15. package/dist/bridge/drivers/continue.js.map +1 -1
  16. package/dist/bridge/drivers/echo.js +10 -4
  17. package/dist/bridge/drivers/echo.js.map +1 -1
  18. package/dist/bridge/drivers/gemini.js +7 -4
  19. package/dist/bridge/drivers/goose.js +160 -7
  20. package/dist/bridge/drivers/goose.js.map +1 -1
  21. package/dist/bridge/drivers/omp.js +321 -96
  22. package/dist/bridge/drivers/omp.js.map +1 -1
  23. package/dist/bridge/drivers/opencode.js +148 -13
  24. package/dist/bridge/drivers/opencode.js.map +1 -1
  25. package/dist/bridge/drivers/qwen.js +41 -11
  26. package/dist/bridge/drivers/qwen.js.map +1 -1
  27. package/dist/bridge/index.js +12 -9
  28. package/dist/bridge/src/cloud.d.ts +62 -71
  29. package/dist/bridge/src/cloud.d.ts.map +1 -1
  30. package/dist/bridge/src/codex/config-toml.d.ts +128 -0
  31. package/dist/bridge/src/codex/config-toml.d.ts.map +1 -0
  32. package/dist/bridge/src/codex/credentials.d.ts +26 -0
  33. package/dist/bridge/src/codex/credentials.d.ts.map +1 -1
  34. package/dist/bridge/src/codex/managed-driver.d.ts.map +1 -1
  35. package/dist/bridge/src/drivers/_subprocess-cli.d.ts +9 -4
  36. package/dist/bridge/src/drivers/_subprocess-cli.d.ts.map +1 -1
  37. package/dist/bridge/src/drivers/claude-sdk.d.ts +19 -11
  38. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  39. package/dist/bridge/src/drivers/codex.d.ts +26 -1
  40. package/dist/bridge/src/drivers/codex.d.ts.map +1 -1
  41. package/dist/bridge/src/drivers/continue.d.ts +31 -5
  42. package/dist/bridge/src/drivers/continue.d.ts.map +1 -1
  43. package/dist/bridge/src/drivers/echo.d.ts.map +1 -1
  44. package/dist/bridge/src/drivers/gemini.d.ts +34 -3
  45. package/dist/bridge/src/drivers/gemini.d.ts.map +1 -1
  46. package/dist/bridge/src/drivers/goose.d.ts +26 -2
  47. package/dist/bridge/src/drivers/goose.d.ts.map +1 -1
  48. package/dist/bridge/src/drivers/omp-models-yml.d.ts +216 -0
  49. package/dist/bridge/src/drivers/omp-models-yml.d.ts.map +1 -0
  50. package/dist/bridge/src/drivers/omp.d.ts +26 -23
  51. package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
  52. package/dist/bridge/src/drivers/opencode.d.ts +28 -3
  53. package/dist/bridge/src/drivers/opencode.d.ts.map +1 -1
  54. package/dist/bridge/src/drivers/qwen.d.ts +10 -4
  55. package/dist/bridge/src/drivers/qwen.d.ts.map +1 -1
  56. package/dist/bridge/src/index.d.ts +3 -1
  57. package/dist/bridge/src/index.d.ts.map +1 -1
  58. package/dist/bridge/src/models.d.ts +118 -19
  59. package/dist/bridge/src/models.d.ts.map +1 -1
  60. package/dist/bridge/src/provider-catalog.d.ts +188 -0
  61. package/dist/bridge/src/provider-catalog.d.ts.map +1 -0
  62. package/dist/bridge/src/provider-materialize/continue-config-yaml.d.ts +117 -0
  63. package/dist/bridge/src/provider-materialize/continue-config-yaml.d.ts.map +1 -0
  64. package/dist/bridge/src/provider-materialize/credential-env.d.ts +103 -0
  65. package/dist/bridge/src/provider-materialize/credential-env.d.ts.map +1 -0
  66. package/dist/bridge/src/provider-materialize/env-drivers.d.ts +209 -0
  67. package/dist/bridge/src/provider-materialize/env-drivers.d.ts.map +1 -0
  68. package/dist/bridge/src/provider-materialize/goose-custom-providers.d.ts +127 -0
  69. package/dist/bridge/src/provider-materialize/goose-custom-providers.d.ts.map +1 -0
  70. package/dist/bridge/src/provider-materialize/opencode-config.d.ts +127 -0
  71. package/dist/bridge/src/provider-materialize/opencode-config.d.ts.map +1 -0
  72. package/dist/bridge/src/provider-materialize/session-config-home.d.ts +63 -0
  73. package/dist/bridge/src/provider-materialize/session-config-home.d.ts.map +1 -0
  74. package/dist/bridge/src/provider-registry-derive.d.ts +59 -0
  75. package/dist/bridge/src/provider-registry-derive.d.ts.map +1 -0
  76. package/dist/bridge/src/registry.d.ts +19 -7
  77. package/dist/bridge/src/registry.d.ts.map +1 -1
  78. package/dist/bridge/src/runtime.d.ts.map +1 -1
  79. package/dist/bridge/src/types.d.ts +79 -60
  80. package/dist/bridge/src/types.d.ts.map +1 -1
  81. package/dist/bridge/src/validation.d.ts +2 -3
  82. package/dist/bridge/src/validation.d.ts.map +1 -1
  83. package/dist/{chunk-GURXUF2J.js → chunk-3ZTQY276.js} +95 -80
  84. package/dist/chunk-3ZTQY276.js.map +1 -0
  85. package/dist/{chunk-T3YLZQS4.js → chunk-45LLHKQ2.js} +24 -3
  86. package/dist/chunk-45LLHKQ2.js.map +1 -0
  87. package/dist/{chunk-UAEGKCE5.js → chunk-5IIHO2HI.js} +7 -7
  88. package/dist/{chunk-UAEGKCE5.js.map → chunk-5IIHO2HI.js.map} +1 -1
  89. package/dist/{chunk-HSRHO7SK.js → chunk-C3QLJTMB.js} +106 -150
  90. package/dist/chunk-C3QLJTMB.js.map +1 -0
  91. package/dist/chunk-CUU3AMGE.js +500 -0
  92. package/dist/chunk-CUU3AMGE.js.map +1 -0
  93. package/dist/{chunk-K6VZQNTR.js → chunk-DKCFWSVW.js} +3 -3
  94. package/dist/{chunk-K6VZQNTR.js.map → chunk-DKCFWSVW.js.map} +1 -1
  95. package/dist/{chunk-AEN2UFDN.js → chunk-DNGAA24M.js} +7 -7
  96. package/dist/{chunk-AEN2UFDN.js.map → chunk-DNGAA24M.js.map} +1 -1
  97. package/dist/{chunk-TCHEW3T2.js → chunk-EBHY23RZ.js} +6 -6
  98. package/dist/{chunk-TCHEW3T2.js.map → chunk-EBHY23RZ.js.map} +1 -1
  99. package/dist/{chunk-MQASB52N.js → chunk-FEFTOV2Y.js} +3 -3
  100. package/dist/{chunk-MQASB52N.js.map → chunk-FEFTOV2Y.js.map} +1 -1
  101. package/dist/{chunk-XMULHVKX.js → chunk-FODAC4RE.js} +17 -15
  102. package/dist/chunk-FODAC4RE.js.map +1 -0
  103. package/dist/{chunk-6H6HLMWG.js → chunk-G2F3ZCPK.js} +3 -3
  104. package/dist/{chunk-6H6HLMWG.js.map → chunk-G2F3ZCPK.js.map} +1 -1
  105. package/dist/{chunk-YLL65VXQ.js → chunk-HO2FQ76C.js} +175 -178
  106. package/dist/chunk-HO2FQ76C.js.map +1 -0
  107. package/dist/chunk-ILG4BXYE.js +936 -0
  108. package/dist/chunk-ILG4BXYE.js.map +1 -0
  109. package/dist/{chunk-E7HKNQTH.js → chunk-JXCUUZA3.js} +3 -4
  110. package/dist/chunk-JXCUUZA3.js.map +1 -0
  111. package/dist/{chunk-MBARHWMZ.js → chunk-K27T47OO.js} +79 -53
  112. package/dist/chunk-K27T47OO.js.map +1 -0
  113. package/dist/chunk-K3YR33F6.js +187 -0
  114. package/dist/chunk-K3YR33F6.js.map +1 -0
  115. package/dist/{chunk-7P6ASOFL.js → chunk-KIQGTAJ5.js} +3 -3
  116. package/dist/{chunk-7P6ASOFL.js.map → chunk-KIQGTAJ5.js.map} +1 -1
  117. package/dist/chunk-KSIRR5PL.js +142 -0
  118. package/dist/chunk-KSIRR5PL.js.map +1 -0
  119. package/dist/{chunk-SIREWRZE.js → chunk-KW7YIRYL.js} +3 -3
  120. package/dist/{chunk-SIREWRZE.js.map → chunk-KW7YIRYL.js.map} +1 -1
  121. package/dist/{chunk-3U3ZKYR7.js → chunk-LN2BQVRB.js} +139 -29
  122. package/dist/chunk-LN2BQVRB.js.map +1 -0
  123. package/dist/{chunk-DZ4UZOFB.js → chunk-M5H4DWIA.js} +3 -3
  124. package/dist/{chunk-DZ4UZOFB.js.map → chunk-M5H4DWIA.js.map} +1 -1
  125. package/dist/{chunk-JMYOJ3PA.js → chunk-MIP4IC3O.js} +3 -3
  126. package/dist/{chunk-JMYOJ3PA.js.map → chunk-MIP4IC3O.js.map} +1 -1
  127. package/dist/{chunk-O5JUZIVR.js → chunk-MJY2BO6N.js} +6 -6
  128. package/dist/{chunk-O5JUZIVR.js.map → chunk-MJY2BO6N.js.map} +1 -1
  129. package/dist/{chunk-AN6NAFRT.js → chunk-N7B3LZ7V.js} +31 -6
  130. package/dist/chunk-N7B3LZ7V.js.map +1 -0
  131. package/dist/{chunk-MX6TGDZ7.js → chunk-NBPL76HH.js} +5 -5
  132. package/dist/{chunk-MX6TGDZ7.js.map → chunk-NBPL76HH.js.map} +1 -1
  133. package/dist/{chunk-DY5GHUTC.js → chunk-NR6BPOW5.js} +2 -7
  134. package/dist/chunk-NR6BPOW5.js.map +1 -0
  135. package/dist/{chunk-F2GEM5B3.js → chunk-PCJF3XBH.js} +10 -10
  136. package/dist/{chunk-F2GEM5B3.js.map → chunk-PCJF3XBH.js.map} +1 -1
  137. package/dist/{chunk-NW65H5EV.js → chunk-PTETBRRC.js} +3 -3
  138. package/dist/{chunk-NW65H5EV.js.map → chunk-PTETBRRC.js.map} +1 -1
  139. package/dist/{chunk-UL4LD7KD.js → chunk-QQL3ET3J.js} +3 -3
  140. package/dist/{chunk-UL4LD7KD.js.map → chunk-QQL3ET3J.js.map} +1 -1
  141. package/dist/{chunk-IB4XKQMQ.js → chunk-REILIKVM.js} +3 -3
  142. package/dist/{chunk-IB4XKQMQ.js.map → chunk-REILIKVM.js.map} +1 -1
  143. package/dist/{chunk-N27DSFA7.js → chunk-RM4C5AU3.js} +27 -21
  144. package/dist/chunk-RM4C5AU3.js.map +1 -0
  145. package/dist/chunk-SG4D2UOK.js +843 -0
  146. package/dist/chunk-SG4D2UOK.js.map +1 -0
  147. package/dist/{chunk-AU4TUVHW.js → chunk-T7RHDVSY.js} +4 -4
  148. package/dist/{chunk-AU4TUVHW.js.map → chunk-T7RHDVSY.js.map} +1 -1
  149. package/dist/{chunk-773WLEXL.js → chunk-UKWEJPZZ.js} +3 -3
  150. package/dist/{chunk-773WLEXL.js.map → chunk-UKWEJPZZ.js.map} +1 -1
  151. package/dist/{chunk-3NCGSSCU.js → chunk-WLFRA5RM.js} +47 -45
  152. package/dist/chunk-WLFRA5RM.js.map +1 -0
  153. package/dist/{chunk-FFE7YLYO.js → chunk-XEVWRSLS.js} +7 -7
  154. package/dist/chunk-XEVWRSLS.js.map +1 -0
  155. package/dist/{chunk-5UWAOYDN.js → chunk-Y6E62LFB.js} +9 -12
  156. package/dist/chunk-Y6E62LFB.js.map +1 -0
  157. package/dist/{chunk-72DG6GSB.js → chunk-YS4XBN7O.js} +4 -4
  158. package/dist/{chunk-72DG6GSB.js.map → chunk-YS4XBN7O.js.map} +1 -1
  159. package/dist/chunk-YSJKLJD4.js +32 -0
  160. package/dist/chunk-YSJKLJD4.js.map +1 -0
  161. package/dist/cli/index.js +765 -334
  162. package/dist/cli/index.js.map +1 -1
  163. package/dist/cli/src/commands/config.d.ts +17 -6
  164. package/dist/cli/src/commands/config.d.ts.map +1 -1
  165. package/dist/cli/src/commands/migrate-legacy-entry.d.ts +46 -0
  166. package/dist/cli/src/commands/migrate-legacy-entry.d.ts.map +1 -0
  167. package/dist/cli/src/commands/migrate-providers.d.ts +93 -0
  168. package/dist/cli/src/commands/migrate-providers.d.ts.map +1 -0
  169. package/dist/cli/src/commands/providers.d.ts +89 -0
  170. package/dist/cli/src/commands/providers.d.ts.map +1 -0
  171. package/dist/cli/src/commands/run.d.ts +1 -1
  172. package/dist/cli/src/commands/run.d.ts.map +1 -1
  173. package/dist/cli/src/setup.d.ts +46 -6
  174. package/dist/cli/src/setup.d.ts.map +1 -1
  175. package/dist/connectors/config.js +6 -4
  176. package/dist/connectors/index.js +15 -12
  177. package/dist/core/index.js +5 -3
  178. package/dist/core/provider-registry-credentials.d.ts +2 -0
  179. package/dist/core/provider-registry-credentials.js +5 -0
  180. package/dist/core/provider-registry-credentials.js.map +1 -0
  181. package/dist/core/provider-registry.d.ts +2 -0
  182. package/dist/core/provider-registry.js +4 -0
  183. package/dist/core/provider-registry.js.map +1 -0
  184. package/dist/core/runtime-assets.js +2 -2
  185. package/dist/core/src/index.d.ts +10 -4
  186. package/dist/core/src/index.d.ts.map +1 -1
  187. package/dist/core/src/provider-registry-credentials.d.ts +50 -0
  188. package/dist/core/src/provider-registry-credentials.d.ts.map +1 -0
  189. package/dist/core/src/provider-registry-files.d.ts +97 -0
  190. package/dist/core/src/provider-registry-files.d.ts.map +1 -0
  191. package/dist/core/src/provider-registry.d.ts +450 -0
  192. package/dist/core/src/provider-registry.d.ts.map +1 -0
  193. package/dist/core/src/settings.d.ts +18 -78
  194. package/dist/core/src/settings.d.ts.map +1 -1
  195. package/dist/core/src/workspace-config.d.ts +31 -47
  196. package/dist/core/src/workspace-config.d.ts.map +1 -1
  197. package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
  198. package/dist/core/workspace-config.js +1 -1
  199. package/dist/deploy/index.js +5 -3
  200. package/dist/deploy/index.js.map +1 -1
  201. package/dist/discovery/index.js +2 -2
  202. package/dist/{ensure-sources-DYGQNAJM.js → ensure-sources-QZAQ4SY2.js} +14 -12
  203. package/dist/ensure-sources-QZAQ4SY2.js.map +1 -0
  204. package/dist/factory-assets/connectors/box.js +15 -12
  205. package/dist/factory-assets/connectors/deploy.js +15 -12
  206. package/dist/factory-assets/connectors/devserver.js +15 -12
  207. package/dist/factory-assets/connectors/flow/adapter.js +15 -12
  208. package/dist/factory-assets/connectors/flow/engine.js +6 -4
  209. package/dist/factory-assets/connectors/flow/index.d.ts +1 -1
  210. package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
  211. package/dist/factory-assets/connectors/flow/run-flow.d.ts +0 -3
  212. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  213. package/dist/factory-assets/connectors/flow/run-flow.js +16 -13
  214. package/dist/factory-assets/connectors/flow/subprompt-runner.d.ts +31 -28
  215. package/dist/factory-assets/connectors/flow/subprompt-runner.d.ts.map +1 -1
  216. package/dist/factory-assets/connectors/flow.js +15 -12
  217. package/dist/factory-assets/connectors/git.js +15 -12
  218. package/dist/factory-assets/connectors/gmail.js +15 -12
  219. package/dist/factory-assets/connectors/googledrive.js +15 -12
  220. package/dist/factory-assets/connectors/local.js +15 -12
  221. package/dist/factory-assets/connectors/mattermost.js +15 -12
  222. package/dist/factory-assets/connectors/memory.js +15 -12
  223. package/dist/factory-assets/connectors/minio.js +15 -12
  224. package/dist/factory-assets/connectors/postgres.js +15 -12
  225. package/dist/factory-assets/connectors/s3.js +15 -12
  226. package/dist/factory-assets/connectors/sharepoint.js +15 -12
  227. package/dist/factory-assets/connectors/sqlite.js +15 -12
  228. package/dist/factory-assets/connectors/static-server.js +15 -12
  229. package/dist/factory-assets/connectors/tunnel.js +15 -12
  230. package/dist/factory-assets/connectors/webdav.js +15 -12
  231. package/dist/factory-assets/connectors/xstate-store.js +15 -12
  232. package/dist/factory-assets/connectors/xstate.js +15 -12
  233. package/dist/{flows-MI2VM5JZ.js → flows-4EIENFNT.js} +9 -7
  234. package/dist/{flows-MI2VM5JZ.js.map → flows-4EIENFNT.js.map} +1 -1
  235. package/dist/{helpers-G6XZPN6L.js → helpers-DISRVGRJ.js} +14 -12
  236. package/dist/{helpers-G6XZPN6L.js.map → helpers-DISRVGRJ.js.map} +1 -1
  237. package/dist/library/index.js +8 -6
  238. package/dist/library/install.js +5 -3
  239. package/dist/{library-publish-WHGKK7G5.js → library-publish-I2QYQSB4.js} +18 -16
  240. package/dist/library-publish-I2QYQSB4.js.map +1 -0
  241. package/dist/{open-library-4JSLGWL6.js → open-library-6LM4W4DR.js} +16 -14
  242. package/dist/{open-library-4JSLGWL6.js.map → open-library-6LM4W4DR.js.map} +1 -1
  243. package/dist/paths-P26QGQP5.js +18 -0
  244. package/dist/{paths-CZEH643M.js.map → paths-P26QGQP5.js.map} +1 -1
  245. package/dist/plugin-registry/src/targets.d.ts +16 -2
  246. package/dist/plugin-registry/src/targets.d.ts.map +1 -1
  247. package/dist/{plugin-store-QJNBPIQK.js → plugin-store-T2DJGKBW.js} +7 -5
  248. package/dist/plugin-store-T2DJGKBW.js.map +1 -0
  249. package/dist/{project-LISE6I5O.js → project-HP3IR7RW.js} +15 -13
  250. package/dist/{project-LISE6I5O.js.map → project-HP3IR7RW.js.map} +1 -1
  251. package/dist/resolver/index.js +5 -3
  252. package/dist/runner/index.js +25 -22
  253. package/dist/runner/src/agent.d.ts +0 -2
  254. package/dist/runner/src/agent.d.ts.map +1 -1
  255. package/dist/runner/src/codex-init.d.ts.map +1 -1
  256. package/dist/runner/src/codex-resource-tools.d.ts.map +1 -1
  257. package/dist/runner/src/managed-codex-bootstrap.d.ts.map +1 -1
  258. package/dist/runner/src/resources.d.ts +1 -2
  259. package/dist/runner/src/resources.d.ts.map +1 -1
  260. package/dist/runner/src/serve.d.ts.map +1 -1
  261. package/dist/runner/src/session-builder.d.ts +31 -35
  262. package/dist/runner/src/session-builder.d.ts.map +1 -1
  263. package/dist/runner/src/session.d.ts +0 -2
  264. package/dist/runner/src/session.d.ts.map +1 -1
  265. package/dist/sdk/asset-manager.js +11 -9
  266. package/dist/sdk/bridge.js +12 -9
  267. package/dist/sdk/core.js +5 -3
  268. package/dist/sdk/flow.js +6 -4
  269. package/dist/sdk/index.js +25 -22
  270. package/dist/sdk/index.js.map +1 -1
  271. package/dist/sdk/resolver.js +5 -3
  272. package/dist/sdk/runner.js +25 -22
  273. package/dist/sdk/session.js +2 -2
  274. package/dist/sdk/types.js +1 -1
  275. package/dist/session/index.js +2 -2
  276. package/dist/setup-HLRSU3MR.js +435 -0
  277. package/dist/setup-HLRSU3MR.js.map +1 -0
  278. package/dist/{skills-IE3IWWB7.js → skills-QPYHHZ54.js} +7 -5
  279. package/dist/{skills-IE3IWWB7.js.map → skills-QPYHHZ54.js.map} +1 -1
  280. package/dist/{source-FKVEUOBQ.js → source-G2VCWPDU.js} +17 -15
  281. package/dist/{source-FKVEUOBQ.js.map → source-G2VCWPDU.js.map} +1 -1
  282. package/dist/{source-manifest-publish-LTRXO2OQ.js → source-manifest-publish-WYKCKJFC.js} +19 -17
  283. package/dist/source-manifest-publish-WYKCKJFC.js.map +1 -0
  284. package/dist/tui/index.js +25 -23
  285. package/dist/tui/index.js.map +1 -1
  286. package/dist/tui/src/repl.d.ts +0 -2
  287. package/dist/tui/src/repl.d.ts.map +1 -1
  288. package/dist/types/index.js +1 -1
  289. package/dist/types/manifests.js +1 -1
  290. package/dist/types/src/flow.d.ts +6 -1
  291. package/dist/types/src/flow.d.ts.map +1 -1
  292. package/dist/types/src/index.d.ts +1 -1
  293. package/dist/types/src/index.d.ts.map +1 -1
  294. package/dist/types/src/lifecycle.d.ts +35 -10
  295. package/dist/types/src/lifecycle.d.ts.map +1 -1
  296. package/dist/types/src/manifests/agent.d.ts +116 -22
  297. package/dist/types/src/manifests/agent.d.ts.map +1 -1
  298. package/dist/types/src/manifests/index.d.ts +2 -2
  299. package/dist/types/src/manifests/index.d.ts.map +1 -1
  300. package/dist/types/src/manifests/preset.d.ts +5 -5
  301. package/dist/types/src/runtime.d.ts +51 -5
  302. package/dist/types/src/runtime.d.ts.map +1 -1
  303. package/dist/types/src/version.d.ts +18 -2
  304. package/dist/types/src/version.d.ts.map +1 -1
  305. package/dist/validator-P5ESKTW5.js +5 -0
  306. package/dist/{validator-RN64BKFW.js.map → validator-P5ESKTW5.js.map} +1 -1
  307. package/dist/workspace-plugin/adapters/mcp.js +11 -9
  308. package/dist/workspace-plugin/adapters/omp.js +11 -11
  309. package/dist/workspace-plugin/adapters/omp.js.map +1 -1
  310. package/dist/workspace-plugin/index.js +1 -1
  311. package/dist/workspace-plugin/src/plugin.d.ts +1 -4
  312. package/dist/workspace-plugin/src/plugin.d.ts.map +1 -1
  313. package/dist/workspace-plugin/src/tools/validator.d.ts +4 -4
  314. package/dist/workspace-plugin/src/tools/validator.d.ts.map +1 -1
  315. package/package.json +13 -1
  316. package/dist/asset-feeds-AJOUKX55.js.map +0 -1
  317. package/dist/bridge/src/provider-endpoints.d.ts +0 -55
  318. package/dist/bridge/src/provider-endpoints.d.ts.map +0 -1
  319. package/dist/chunk-3NCGSSCU.js.map +0 -1
  320. package/dist/chunk-3U3ZKYR7.js.map +0 -1
  321. package/dist/chunk-5UWAOYDN.js.map +0 -1
  322. package/dist/chunk-AN6NAFRT.js.map +0 -1
  323. package/dist/chunk-AQW4BWNR.js +0 -324
  324. package/dist/chunk-AQW4BWNR.js.map +0 -1
  325. package/dist/chunk-DY5GHUTC.js.map +0 -1
  326. package/dist/chunk-E7HKNQTH.js.map +0 -1
  327. package/dist/chunk-FFE7YLYO.js.map +0 -1
  328. package/dist/chunk-FYIHH56K.js +0 -110
  329. package/dist/chunk-FYIHH56K.js.map +0 -1
  330. package/dist/chunk-GURXUF2J.js.map +0 -1
  331. package/dist/chunk-HSRHO7SK.js.map +0 -1
  332. package/dist/chunk-MBARHWMZ.js.map +0 -1
  333. package/dist/chunk-N27DSFA7.js.map +0 -1
  334. package/dist/chunk-T3YLZQS4.js.map +0 -1
  335. package/dist/chunk-XMULHVKX.js.map +0 -1
  336. package/dist/chunk-YLL65VXQ.js.map +0 -1
  337. package/dist/ensure-sources-DYGQNAJM.js.map +0 -1
  338. package/dist/library-publish-WHGKK7G5.js.map +0 -1
  339. package/dist/paths-CZEH643M.js +0 -16
  340. package/dist/plugin-store-QJNBPIQK.js.map +0 -1
  341. package/dist/runner/src/cloud-bundle.d.ts +0 -36
  342. package/dist/runner/src/cloud-bundle.d.ts.map +0 -1
  343. package/dist/setup-CIRH5BYB.js +0 -517
  344. package/dist/setup-CIRH5BYB.js.map +0 -1
  345. package/dist/source-manifest-publish-LTRXO2OQ.js.map +0 -1
  346. package/dist/validator-RN64BKFW.js +0 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,485 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - The AI provider registry is the only provider surface in the runtime.
8
+
9
+ `provider`, `cloud`, `cloudConfig`, `cloudSecrets` and the flat `apiKeys`
10
+ fan-out are deleted from `AgentConfig` (bridge), `AgentRuntimeConfig` and
11
+ `ResolvedAgentConfig` (types), and `AgentSessionConfig` / `AgentSession`
12
+ (runner). A session carries `registry` + `modelRef`; each entry references its
13
+ credential and the value reaches the child under `SKAILE_AIP_<ID>_KEY`.
14
+
15
+ Gone with them: `bridge/src/cloud.ts`'s legacy half (`buildClaudeCloudEnv`,
16
+ `CloudConfig`, `CloudId`, `SUPPORTED_CLOUDS`, `CLOUD_SECRET_ENV_KEYS`), the
17
+ vendor endpoint table (`bridge/src/provider-endpoints.ts` — model discovery and
18
+ key validation resolve through the catalog presets now), the per-driver env
19
+ allowlists and key fan-out (`OMP_PROVIDER_ENV_KEYS`, `mapApiKeysToEnv`, the
20
+ codex/gemini/qwen/continue key cascades), the mixed LLM/voice id list
21
+ (`core` `ALL_PROVIDERS`, with `providerEnvKey`, `resolveApiKey`,
22
+ `detectEnvApiKeys`, `resolveAllKeys`), the runner's per-session cloud resolver
23
+ and provider-key secrets lookup (`runner/src/cloud-bundle.ts` deleted), and the
24
+ session-boundary legacy derivation (`resolveSessionProviderBinding`,
25
+ `deriveLegacyProviderRegistry`). The one survivor is the user-local
26
+ `settings.json` `apiKeys` normalizer (`deriveRegistryFromLegacyApiKeys`), which
27
+ goes one minor later; `skaile migrate providers` keeps its own copy of the
28
+ `provider` × `cloud` translation because that is what it exists to migrate.
29
+
30
+ The runner now resolves each entry's `platform:<configId>` reference against
31
+ the `session_init` secrets map itself and materializes the values into the
32
+ child environment. A `session_init` whose `resolvedConfig.agentConfig` still
33
+ carries `provider`, `cloud` or `cloudConfig` is **rejected** with a fatal error
34
+ naming the replacement. Wire protocol 3.13.0 → **4.0.0**.
35
+
36
+ See `MIGRATION.md` for the full `from → to` table.
37
+
38
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - `skaile.yaml` selects a model, it no longer defines a provider.
39
+
40
+ `agent_config.<profile>.model` is a selector resolved through `parseModelRef`:
41
+ `"<providerId>/<modelId>"` picks a registry entry, a bare `"<modelId>"`
42
+ resolves against registry order, and `"@role"` resolves through the new
43
+ top-level `roles:` table (`SkWorkspaceConfig.roles`, merged per role name
44
+ across the scope chain, surfaced as `SkaileSettings.roles`). Role resolution is
45
+ lenient: an undefined role, a role chain, or a role naming a provider this
46
+ machine lacks falls back to registry order with a warning instead of failing
47
+ the session.
48
+
49
+ **Breaking — hard cutover, no warning period** (repo convention for
50
+ `skaile.yaml` schema changes). These are parse errors, and every message names
51
+ `skaile migrate providers`:
52
+
53
+ - `agent-config.<profile>.provider`, `.cloud`, `.cloud_config` (and
54
+ `.cloudConfig`) — including inside a flat, un-profiled `agent-config` block
55
+ - `providers`, `base_url`, `credential`, `headers`, `query_params`,
56
+ `transport` — at the top level and inside any profile
57
+
58
+ The reserved names are scoped to those two places: `mcp_servers[].transport`
59
+ and `mcp_servers[].headers` are a different noun and keep working.
60
+ `encodeSkaileYaml` strips the three legacy profile keys so the writer cannot
61
+ emit a file its own decoder rejects, and the now-unreachable
62
+ `unknown_provider` / `unknown_cloud` / `gateway_missing_base_url` diagnostics
63
+ are gone.
64
+
65
+ New `skaile migrate providers [--project-dir] [--workspace] [--dry-run]
66
+ [--force]` performs the one-time rewrite: for every `skaile.yaml` in the
67
+ project it derives the endpoint the legacy fields addressed (through the same
68
+ `deriveLegacyProviderRegistry` the runtime uses, so the base URL, surface and
69
+ credential carrier are identical), writes it to `~/.skaile/providers.yml`
70
+ through the `skaile providers add` write path, lifts a reserved top-level
71
+ `providers:` block into the same file, and leaves
72
+ `model: <providerId>/<modelId>` behind. Comments and formatting survive, an id
73
+ that already exists with different settings is reported instead of clobbered,
74
+ and a second run is a no-op.
75
+
76
+ `skaile setup` is now a front-end over `skaile providers add`: it picks
77
+ endpoints from the catalog presets (not `ALL_PROVIDERS`), writes entries whose
78
+ credential is an `env:` reference, sends typed secrets to a `.env` file or the
79
+ operator's shell, and saves `driver` plus one selector. It never writes
80
+ `settings.apiKeys`.
81
+
82
+ `skaile config` follows: `set provider|cloud|cloudConfig` is rejected with the
83
+ commands that replace it, `set apiKey.<provider>` creates the registry entry
84
+ with an `env:` reference instead of storing the secret, and `config show` gains
85
+ a "Model selection" section showing which entry, endpoint and credential the
86
+ selector resolves to.
87
+
88
+ A user-local `settings.json` that still carries `apiKeys` keeps working for one
89
+ more minor: `deriveRegistryFromLegacyApiKeys()` (new, in
90
+ `@skaile/workspaces/bridge`) normalizes it into registry entries with `env:`
91
+ references plus one deprecation line, and returns the literal values in a
92
+ `credentialEnv` map for the child environment.
93
+
94
+ Also fixed: `WorkspaceYamlEditor.setAgentConfig` threw when the file had no
95
+ `agent-config` section (it stored a plain object where a YAML node was
96
+ required), and `getAgentConfig` returned the AST node instead of the profile.
97
+
98
+ ### Minor Changes
99
+
100
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - Every session now carries an AI provider `registry` and a `modelRef` beside the
101
+ fields it carried before. Nothing that works today changes: this is the expand
102
+ half of the provider-registry cutover, and the legacy `provider` / `cloud` /
103
+ `cloudConfig` / `cloudSecrets` / `apiKeys` inputs keep driving the drivers.
104
+
105
+ `AgentConfig` (bridge), `AgentRuntimeConfig` (types), `AgentSessionConfig` +
106
+ `AgentSession` (runner) and `SessionSubpromptRunnerOptions` (flow) all gain the
107
+ optional pair. Every session-assembly boundary fills it — CLI flags, the
108
+ platform's `session_init` resolved config, `skaile.yaml`, user settings, the
109
+ in-process `BridgeRuntime`, and isolated sub-prompt sessions. When a boundary
110
+ has only the legacy axis, `resolveSessionProviderBinding()`
111
+ (`@skaile/workspaces/bridge`) derives a **one-entry** registry describing
112
+ exactly the endpoint those fields already addressed — the catalog preset's base
113
+ URL (or the provider's `*_BASE_URL` override), the same wire surface, and the
114
+ same credential kind and carrier that `buildClaudeCloudEnv` uses for
115
+ `bedrock` / `vertex` / `azure` / `gateway` — and returns one deprecation line
116
+ for that boundary to log. The derivation lives in exactly one place; no
117
+ boundary re-implements it. Secrets never enter an entry: the derived
118
+ `credential.ref` names an env var and the value comes back separately as
119
+ `credentialEnv`.
120
+
121
+ **Protocol 3.12.0 → 3.13.0 (additive minor).**
122
+ `ResolvedAgentConfig` (`session_init.resolvedConfig.agentConfig`) gains optional
123
+ `registry?` — the bare `id → entry` map or the merged view — and `modelRef?`
124
+ (`"<providerId>/<modelId>"`, a bare id, or `"@role"`). Control-plane
125
+ credentials are referenced as `platform:<configId>` against the same sibling
126
+ `secrets` map that carries `<PROVIDER>_API_KEY` today. A platform that sends
127
+ only the legacy fields is byte-identical; a 3.12 runner ignores both keys.
128
+
129
+ **Breaking for callers of the model-listing API.** `listModelsForDriver()` and
130
+ `DriverTarget.listModels()` take a registry instead of a flat key map:
131
+
132
+ ```ts
133
+ // before
134
+ await listModelsForDriver("omp", settings.apiKeys ?? {});
135
+ // after
136
+ const { registry, credentialEnv } = deriveLegacyProviderRegistry({
137
+ provider: settings.provider,
138
+ apiKeys: settings.apiKeys,
139
+ });
140
+ await listModelsForDriver("omp", registry, {
141
+ env: { ...process.env, ...credentialEnv },
142
+ });
143
+ ```
144
+
145
+ A legacy-derived registry yields the same results as the flat map did —
146
+ `registryApiKeys()` is the exact inverse. See `MIGRATION.md`.
147
+
148
+ `BUILTIN_DRIVER_CATALOG` now declares, per driver, the `surfaces` it can speak
149
+ and its `providerPlurality` (`registry` for omp; `credentials-n` for opencode,
150
+ goose and continue; `single` for claude-sdk, codex, gemini and qwen), so a
151
+ consumer can filter registry entries by what a backend can actually address
152
+ instead of matching vendor names. `DriverInfo` is now declared once, in
153
+ `@skaile/workspaces/types`, and re-exported from `@skaile/workspaces/bridge`
154
+ (it was duplicated field-for-field in both).
155
+
156
+ No driver dispatches through the registry yet — that lands per driver in the
157
+ following releases.
158
+
159
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - The `claude-sdk` driver now addresses the endpoint its AI provider registry
160
+ entry describes — on **every** transport, including the plain `direct` one.
161
+
162
+ Until now the Claude Agent SDK child env was assembled only when `cloud` was
163
+ something other than `default`, so a session whose provider config named a
164
+ custom `base_url` on the default transport silently talked to
165
+ `api.anthropic.com` with that endpoint's credential. The gate is gone: the
166
+ driver resolves its entry through `resolveSessionProviderBinding()` and builds
167
+ the child env from it with `buildClaudeEndpointEnv()`
168
+ (`@skaile/workspaces/bridge`, `src/cloud.ts`).
169
+
170
+ What the entry now decides:
171
+
172
+ - **Endpoint** — `base_url` (or the transport-derived one) becomes
173
+ `ANTHROPIC_BASE_URL`, except for Anthropic's own host, which needs no
174
+ redirect.
175
+ - **Credential** — `credential.kind: api_key_header` rides as
176
+ `ANTHROPIC_API_KEY` (the SDK sends `x-api-key`), `bearer` as
177
+ `ANTHROPIC_AUTH_TOKEN` (`Authorization: Bearer`). `sigv4`, `google_adc` and
178
+ `azure_entra` emit nothing and let the AWS/Google/Azure chain sign, as
179
+ before. `oauth` keeps the shipped `CLAUDE_CODE_CREDENTIALS_JSON` mechanism
180
+ (the runner writes the blob to the Claude credentials file; the driver adds
181
+ no env). `env:` and `cmd:` refs resolve against `process.env` + `config.env`;
182
+ a `platform:<configId>` ref is resolved by the runner (which holds the
183
+ `session_init` secrets map) and picked up from the `SKAILE_AIP_<ID>_KEY`
184
+ carrier it delivers.
185
+ - **Transport flag** — `bedrock-converse-stream` → `CLAUDE_CODE_USE_BEDROCK`,
186
+ `google-vertex` → `CLAUDE_CODE_USE_VERTEX`, `transport: foundry` →
187
+ `CLAUDE_CODE_USE_FOUNDRY`, with the same routing vars the `cloud` axis
188
+ emitted. A golden test pins Bedrock, Vertex, Foundry (by resource and by
189
+ base URL) and gateway output against the legacy builder, entry for entry.
190
+ - **Headers** — an entry's static `headers` reach the wire as
191
+ `ANTHROPIC_CUSTOM_HEADERS`, minus the ones the SDK owns.
192
+ - **Model** — the selector's `model_map` result is the model the session runs.
193
+
194
+ The child env is the driver's base environment **plus** the endpoint vars, so
195
+ `PATH`, `HOME` and `SKAILE_SESSION_ID` survive on every path (the OAuth path
196
+ previously dropped `config.env` entirely).
197
+
198
+ Model discovery follows the same entry: `listModels()` asks the entry's own
199
+ base URL with the entry's credential, reports nothing for Bedrock / Vertex /
200
+ Foundry (their model catalogs live behind their own control planes) and
201
+ nothing at all for an entry with no resolvable endpoint, rather than falling
202
+ back to Anthropic with someone else's key.
203
+
204
+ Sessions that still carry only the legacy `cloud` / `cloudConfig` /
205
+ `cloudSecrets` / `apiKeys` fields are unchanged: they get the one-entry
206
+ derivation, which now also keeps the Foundry transport when the endpoint is
207
+ given as a base URL rather than a resource name, and lets an explicitly
208
+ configured key override an ambient variable of the same name — the precedence
209
+ the drivers applied before the registry existed.
210
+
211
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - Codex takes its endpoints from a session-private `config.toml` instead of the
212
+ ambient `~/.codex`.
213
+
214
+ Codex is a file-shaped backend: it reads providers from `$CODEX_HOME/config.toml`
215
+ and from nowhere else. The standalone driver now renders the session's AI
216
+ provider registry into one — `[model_providers.<id>]` per entry, with
217
+ `base_url`, `env_key`, `wire_api`, `query_params` and `http_headers` mapping
218
+ 1:1 onto the entry's `base_url`, `credential`, `surface`, `query_params` and
219
+ `headers`, plus top-level `model_provider`/`model` naming the selection — and
220
+ sets `CODEX_HOME` to the directory holding it. A session pointed at a gateway
221
+ now actually reaches that gateway, and `listModels()` discovers against the
222
+ same endpoint rather than always asking `api.openai.com`.
223
+
224
+ The rendered file never contains a credential. `env_key` names the per-entry
225
+ variable `SKAILE_AIP_<ID>_KEY` (the programme-wide naming rule, shared with the
226
+ omp and env-shaped adapters) and the value is delivered in the child
227
+ environment. An `oauth` entry gets `requires_openai_auth` instead, which routes
228
+ codex to its own auth manager.
229
+
230
+ Two deliberate limits, both from codex-cli itself. `wire_api` accepts only
231
+ `responses` as of codex-cli 0.154 (`chat` was removed, openai/codex#7782) and
232
+ an unknown value fails the whole document at load, so entries on a surface
233
+ codex cannot speak — `openai-completions`, `anthropic-messages`,
234
+ `bedrock-converse-stream`, `google-*` — are left out of the file and logged
235
+ rather than rendered into a config codex would reject. A session with no
236
+ registry entry codex can address writes no file at all and keeps codex's
237
+ built-in providers, exactly as before.
238
+
239
+ Managed codex restates its credential-isolation invariant on the registry: a
240
+ managed session may carry exactly one enabled `llm` entry, on
241
+ `openai-codex-responses`, whose credential is a platform-injected `oauth`
242
+ reference. A second entry, another surface, or an `env:` / `cmd:` / `keyring:`
243
+ reference fails the session with the existing `AI_PROFILE_INVALID` before the
244
+ native process starts. The one-entry projection the session boundary derives
245
+ from the legacy `provider`/`apiKeys`/`cloud` fields (layer `runtime`) is not a
246
+ configured endpoint and is exempt — those inputs are already covered by the
247
+ sibling checks on `provider`, `apiKeys.openai` and `env.OPENAI_API_KEY`.
248
+ Managed mode continues to bind its provider through the app-server login flow
249
+ and renders no provider table: a config-defined provider authenticates from
250
+ `env_key`, so redirecting `model_provider` at one would strip a managed session
251
+ of the very credential the isolation exists to protect.
252
+
253
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - The env-shaped CLI drivers — `gemini`, `qwen`, `opencode`, `goose` and
254
+ `continue` — now take their endpoints and credentials from the AI provider
255
+ registry instead of a hardcoded per-driver key allowlist.
256
+
257
+ **Single-provider backends (`gemini`, `qwen`).** The entry the session's model
258
+ selector names supplies everything: `qwen` sends that entry's `base_url`,
259
+ credential and mapped model id as `OPENAI_BASE_URL` / `OPENAI_API_KEY` /
260
+ `OPENAI_MODEL` (plus `-m`), and `gemini` sends `GEMINI_API_KEY` with `-m` from
261
+ the model ref and `GOOGLE_GEMINI_BASE_URL` for a non-default host. Once an
262
+ entry is bound it is the only authority: an inherited `OPENAI_*` /
263
+ `GEMINI_API_KEY` from the host shell no longer leaks into a session pointed
264
+ somewhere else. Pointing one of them at an entry whose `surface` it cannot
265
+ speak now fails at `start()` — before the first spawn — with the offending
266
+ surface and the backend's own surfaces named, rather than surfacing as an
267
+ opaque HTTP error mid-turn.
268
+
269
+ **`credentials-n` backends (`opencode`, `goose`, `continue`).** Every _enabled_
270
+ entry contributes one credential variable, `SKAILE_AIP_<ID>_KEY`, plus the
271
+ vendor carrier a stock catalog endpoint is already known by
272
+ (`ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, …). The active model is the registry
273
+ selection: `opencode -m <provider>/<model>`, `GOOSE_PROVIDER` +
274
+ `GOOSE_MODEL`, and — because `cn` has no model flag — a Continue **role
275
+ binding** for the `chat` role, which is also the shape the generated
276
+ `config.yaml` will be rendered from. A model selector that the registry
277
+ resolves is no longer passed to `cn --config`, which only ever named a Hub
278
+ assistant.
279
+
280
+ Model discovery takes the registry throughout: `gemini` and `qwen` query the
281
+ bound entry's own endpoint with its credential, and the three `credentials-n`
282
+ backends — which have no discovery endpoint of their own — list what the
283
+ registry declares, namespaced the way each takes it.
284
+
285
+ Two shared pieces come with this:
286
+ `bridge/src/provider-materialize/credential-env.ts` is the single naming rule
287
+ for per-entry credential variables (`providerCredentialEnvName`,
288
+ `registryCredentialEnv`), used by the omp, codex and CLI adapters alike, and
289
+ `bridge/src/provider-materialize/env-drivers.ts` resolves a session's
290
+ registry, binds its selector to an entry and enforces the surface.
291
+
292
+ `SubprocessCliDriver.baseEnv()` now merges `config.env` **over** the allowlist
293
+ instead of replacing it: setting one variable used to drop `PATH` and `HOME`
294
+ and make the spawn fail, which the registry delivery path depends on.
295
+
296
+ Sessions carrying only the legacy `provider` / `model` / `apiKeys` fields are
297
+ unchanged. The one-entry derivation those produce describes a credential, not
298
+ a chosen endpoint — `provider` defaults to `anthropic` for every session — so
299
+ the drivers take its credentials but keep their pre-registry model selection,
300
+ and a single-provider driver handed such an entry with an unusable surface
301
+ warns and falls back instead of failing.
302
+
303
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - Model identity is per wire surface, and model tiers resolve through the provider
304
+ registry.
305
+
306
+ An Anthropic-shaped model id is now required for exactly one target: `surface:
307
+ anthropic-messages` on `transport: direct` pointed at `api.anthropic.com`. Every
308
+ other endpoint names models we cannot enumerate — a Bedrock inference-profile
309
+ ARN, an Azure deployment name, `accounts/fireworks/models/…`,
310
+ `meta-llama/Llama-3.3-70B`, an Ollama tag — and those ids are now accepted.
311
+ New in `@skaile/workspaces/types/manifests`: `ModelIdTarget`,
312
+ `requiresAnthropicModelId()`, `modelIdSchemaForTarget()`,
313
+ `isFirstPartyAnthropicEndpoint()`, `ANTHROPIC_FIRST_PARTY_HOSTS`,
314
+ `FreeFormModelIdSchema` and `ModelSelectorSchema`. `ModelIdSchema` is unchanged
315
+ but is no longer a universal rule: it is the first-party Anthropic vocabulary,
316
+ selected by `modelIdSchemaForTarget()`. `modelIdSchemaForCloud()` keeps its
317
+ signature and is now free-form for every `cloud` other than `default` —
318
+ `bedrock`, `vertex` and `azure` rename the ids, so validating them against
319
+ Anthropic's namespace rejected working deployments.
320
+
321
+ `AgentManifest.model.preferred` / `.fallback` accept a model **selector**:
322
+ `@role`, `<providerId>/<modelId>`, a bare id, or an Anthropic alias. A manifest
323
+ is portable across providers and cannot know which entry will serve it, so the
324
+ id-vocabulary check moved to where the endpoint is known. Only a value no
325
+ endpoint could be handed (empty, or containing whitespace) still fails
326
+ `validateAgent`.
327
+
328
+ New in `@skaile/workspaces/bridge` (`bridge/src/models.ts`):
329
+ `resolveManifestModel()` resolves a manifest preference against the registry —
330
+ `@role` through `roles`, then `provider/id`, then a bare id, all via
331
+ `parseModelRef()` — and reports an `error` when the id the entry would receive
332
+ is not legal for its surface. `modelIdTargetForEntry()` derives that target from
333
+ an entry (falling back to its catalog preset for `surface` / `base_url`).
334
+ `resolveModelCapabilities()` reads `capabilities.context_window` /
335
+ `thinking_max` / `tools` / `images` from the entry serving a model, field by
336
+ field over a caller-supplied per-model fallback table.
337
+
338
+ `resolveModelTier()` takes `{registry, roles, providerId}` and resolves
339
+ `small`/`default`/`deep` through `roles[tier]` and then the selected entry's
340
+ `model_map[tier]` — which works for every provider, not just the ten in
341
+ `PROVIDER_MODEL_TIERS`. That table is now the **no-registry fallback only**:
342
+ where a registry is configured it is not consulted, and a tier the registry does
343
+ not define raises `ModelTierResolutionError` instead of substituting a guess.
344
+ Precedence is unchanged otherwise: a configured override first, and `default`
345
+ still inherits the session model before any table.
346
+
347
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - omp sees every configured AI provider, out of a session-private agent directory.
348
+
349
+ omp is the one backend whose native config already _is_ the registry shape:
350
+ `models.yml` is a `providers:` map with `baseUrl`, `api`, `apiKey`, `headers`,
351
+ `authHeader`, `auth`, `discovery` and `models[]`. So the new adapter
352
+ (`bridge/src/drivers/omp-models-yml.ts`) is a serializer, not a translator —
353
+ each enabled `llm` entry becomes one omp provider, `surface` is written
354
+ verbatim as `api` (the two enums are the same list), `model_map` becomes
355
+ `models[]` keyed by the provider-side id, and `AgentConfig.roles` becomes
356
+ `modelRoles` in a sibling `config.yml`. The result: three configured endpoints
357
+ are three selectable providers in one session, `@smol` and `@default` resolve
358
+ to different vendors, and a subagent pinned to `@smol` reaches that endpoint —
359
+ verified against omp 18.2.6 with fake servers logging the requests.
360
+
361
+ `apiKey` holds the **name** of `SKAILE_AIP_<ID>_KEY`, never a value: omp
362
+ resolves a `models.yml` `apiKey` as an environment variable name before it
363
+ falls back to treating it as a literal token, so the credential can stay in the
364
+ child environment where a config file cannot leak it. The ~50-name
365
+ `OMP_PROVIDER_ENV_KEYS` allowlist stops being the mechanism by which
366
+ credentials reach omp and survives only as an ambient fallback (and as the
367
+ carrier for the `sigv4` / `google_adc` signing chains an entry delegates to)
368
+ until the legacy-contract change deletes it.
369
+
370
+ `PI_CODING_AGENT_DIR` relocates omp's whole agent base — `config.yml`,
371
+ `models.yml` _and_ the auth store `agent.db` — so pointing it at a
372
+ session-private directory is what makes N providers per session possible
373
+ without ever writing the user's `~/.omp/agent`. The directory sits outside
374
+ `cwd`, the one tree the agent has write access to, matching the line managed
375
+ codex already draws for its private directory; `AgentConfig.agentDir`'s
376
+ identity files are symlinked in so `agent.yaml` / `SOUL.md` / `RULES.md` /
377
+ `knowledge/` still resolve.
378
+
379
+ Relocating that base would also have cost a developer their stored OAuth
380
+ logins, which was the one risk that could have descoped this to
381
+ "one active provider". It does not: a machine that has `~/.omp/agent` gets its
382
+ contents symlinked into the session directory, and an OAuth account stored
383
+ there still authenticates inside the relocated session (checked with `omp
384
+ token`, omp 18.2.6). `models.yml` is never seeded and `config.yml` is copied
385
+ rather than linked, so neither of the user's files can be written through the
386
+ session. A platform container has no such directory, so its session starts
387
+ empty — which is the correct behaviour there.
388
+
389
+ `AgentConfig` gains `roles` (the `skaile.yaml` role table) and
390
+ `DriverOptions.omp` (`agentHome`, `seedUserAgentDir`, `userAgentDir`); both are
391
+ additive. A session with no registry keeps the previous behaviour exactly.
392
+
393
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - A custom endpoint now reaches OpenCode, Goose and Continue, not only the
394
+ vendors their own tables know.
395
+
396
+ The env half of these three backends (`SKAILE_AIP_<ID>_KEY` per entry, plus
397
+ `-m <provider>/<model>` / `GOOSE_PROVIDER` / a Continue `chat` binding) can
398
+ name an endpoint the backend already knows. It cannot describe one it has
399
+ never heard of — a self-hosted gateway, a LiteLLM proxy, an Ollama box — and
400
+ each of these backends learns such an endpoint only from its own config file.
401
+ Each driver now renders one:
402
+
403
+ - `opencode` — `opencode/opencode.json` with a `provider.<id>` block
404
+ (`npm` from the entry's `surface`, `options.baseURL`, `options.apiKey`,
405
+ `models`), reached by pointing `XDG_CONFIG_HOME` at the session's own
406
+ directory.
407
+ - `goose` — a declarative provider per entry,
408
+ `config/custom_providers/<id>.json` (`engine`, `base_url`, `api_key_env`,
409
+ `models[]`, `headers`), reached through `GOOSE_PATH_ROOT`.
410
+ - `continue` — `config.yaml` with one `models[]` row per bound model, reached
411
+ through `CONTINUE_GLOBAL_DIR`. `cn` has no model flag, so the session's
412
+ `roles:` table is what binds them: each key that is a Continue role
413
+ (`chat`, `edit`, `apply`, `autocomplete`, `embed`, `rerank`, `summarize`;
414
+ `default` is read as `chat`) becomes that role's model, and the session's
415
+ own selector wins `chat`.
416
+
417
+ Three invariants hold across all three. The rendered file never contains a
418
+ credential — it names the per-entry variable (`{env:SKAILE_AIP_<ID>_KEY}`,
419
+ `api_key_env`, `${{ secrets.… }}`) and the value is delivered in the child
420
+ environment, the same rule the codex and omp adapters follow. The provider
421
+ name in the file is `backendProviderName`, the same name the env half puts on
422
+ the command line, so the two halves cannot drift apart. And the config home is
423
+ session-private, under `$SKAILE_HOME/<driver>/<sessionId>`: the developer's
424
+ `~/.config/opencode`, Goose config directory and `~/.continue` are neither
425
+ read nor written, which also keeps a session's state out of them.
426
+
427
+ Nothing is rendered unless something has to be. A session whose endpoints are
428
+ all stock catalog endpoints, and a session that carries only the legacy
429
+ `provider`/`model`/`apiKeys` fields, write no file and leave the config-home
430
+ variable unset — those backends behave exactly as before, including reading
431
+ the developer's own config.
432
+
433
+ Entries a backend genuinely cannot express are left out of the file and
434
+ logged, never guessed at: Goose's declarative providers are `openai` /
435
+ `anthropic` / `ollama` engines only, so `google-*` and
436
+ `bedrock-converse-stream` entries are reported instead; the same applies to
437
+ any surface with no OpenCode AI SDK package or Continue provider class.
438
+
439
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`194a9c3`](https://github.com/skaile-ai/workspaces/commit/194a9c36cfc6ed6ac028db4aeadaf6d37e32f3cf) Thanks [@mortegro](https://github.com/mortegro)! - Add the AI provider registry: `providers.yml` defines every LLM and voice
440
+ endpoint once, and `skaile providers list|add|set|rm|test` manages it.
441
+
442
+ New in `@skaile/workspaces/core` (`core/src/provider-registry.ts`, also exported
443
+ as `@skaile/workspaces/core/provider-registry`): the record types
444
+ (`kind, label, preset, surface, transport, base_url, params, headers,
445
+ query_params, credential{kind, ref}, model_map, capabilities, discovery,
446
+ enabled, locked`), `validateRegistry()`, `mergeRegistries()`,
447
+ `resolveCredential()`, `resolveEntryBaseUrl()` and `parseModelRef()`.
448
+ `surface` is omp's `api` vocabulary verbatim; `params` is a discriminated union
449
+ keyed on `transport`; `stt`/`tts` entries use a reduced record and reject the
450
+ llm-only fields. A literal secret in `credential.ref`, `headers`,
451
+ `query_params` or `base_url` is a validation error naming the offending key —
452
+ credentials are referenced as `env:NAME`, `cmd:<shell>`, `platform:<configId>`
453
+ or `keyring:<service>/<account>`.
454
+
455
+ `core/src/provider-registry-files.ts` loads `~/.skaile/providers.yml` under
456
+ `<workspace>/.skaile/providers.yml`; the layers are merged **before** they are
457
+ gated, so a file may hold a _partial_ entry — one that names only the fields it
458
+ overrides, `kind` included — and the nearer layer wins per key. An entry no
459
+ layer completes is the error (`missing_kind`, `missing_surface`, naming the
460
+ files that fed it), reported by `loadProviderRegistry()`;
461
+ `validateMergedRegistry()` is that gate for anyone merging layers themselves,
462
+ and `validateRegistry(raw, { layer })` reads one layer. An entry marked
463
+ `locked: true` in a higher layer cannot be overridden from a lower one.
464
+ `bridge/src/provider-catalog.ts` ships presets for the surveyed endpoints
465
+ (Anthropic, OpenAI, Google, Groq, DeepSeek, OpenRouter, Mistral, xAI, Together,
466
+ Fireworks, Bedrock, Vertex, Azure OpenAI, Foundry, Ollama, LM Studio, vLLM,
467
+ LiteLLM, Deepgram, ElevenLabs) so `skaile providers add --preset groq` needs
468
+ nothing but a credential reference.
469
+
470
+ `skaile init` now gitignores `.skaile/providers.yml`. No driver reads the
471
+ registry yet — this release is the schema, the catalog and the CLI.
472
+
473
+ ### Patch Changes
474
+
475
+ - [#736](https://github.com/skaile-ai/workspaces/pull/736) [`2de14a6`](https://github.com/skaile-ai/workspaces/commit/2de14a64fdcd77ec8273679bb13f2a0bf149d845) Thanks [@mortegro](https://github.com/mortegro)! - Fix the provider registry dropping entries whose `kind` or transport `params` come from a preset: the catalog layer is now built from the pre-gate merge (`LoadedProviderRegistry.patches`), so `groq: { preset: groq }` plus a workspace `base_url` override resolves to a complete entry instead of a false "no layer supplies it" error, and a session whose entries all fail the gate logs the diagnostics instead of silently running with no endpoint. The completeness gate also re-scans `credential.ref`, `headers`, `query_params` and `base_url` on programmatically injected layers for literal secrets, and every merge-time diagnostic now names the files that contributed the entry.
476
+
477
+ ## 3.27.1
478
+
479
+ ### Patch Changes
480
+
481
+ - [#732](https://github.com/skaile-ai/workspaces/pull/732) [`35218ed`](https://github.com/skaile-ai/workspaces/commit/35218ed500b4c433ff1106538dd59ea0784d183b) Thanks [@peteralbert](https://github.com/peteralbert)! - A classifier node's persisted score `distribution` is now keyed by the authored `const`, like its `value` and `expected`, instead of the wire's level index. A wire score distribution with any key that is not a declared level index is dropped; the answer itself is kept.
482
+
3
483
  ## 3.27.0
4
484
 
5
485
  ### Minor Changes
@@ -1,4 +1,4 @@
1
- import { PROTOCOL_VERSION_STRING } from '../chunk-72DG6GSB.js';
1
+ import { PROTOCOL_VERSION_STRING } from '../chunk-YS4XBN7O.js';
2
2
  import '../chunk-NSBPE2FW.js';
3
3
  import * as z from 'zod';
4
4
 
@@ -1,18 +1,20 @@
1
- import { assignDomain, buildDomainIndex, DOMAIN_MD_FILENAME, parseDomainMd } from './chunk-DZ4UZOFB.js';
1
+ import { assignDomain, buildDomainIndex, DOMAIN_MD_FILENAME, parseDomainMd } from './chunk-M5H4DWIA.js';
2
2
  import './chunk-JXT46QFC.js';
3
- import './chunk-HSRHO7SK.js';
3
+ import './chunk-C3QLJTMB.js';
4
+ import { factoryAssetRoots } from './chunk-REILIKVM.js';
4
5
  import './chunk-F3HNW354.js';
5
6
  import './chunk-K5GBV4SA.js';
6
7
  import './chunk-QVZA2MDT.js';
7
- import { factoryAssetRoots } from './chunk-IB4XKQMQ.js';
8
- import { scanRepo } from './chunk-MBARHWMZ.js';
8
+ import { scanRepo } from './chunk-K27T47OO.js';
9
9
  import './chunk-MENCWIHW.js';
10
10
  import './chunk-P4VHQA4N.js';
11
11
  import { walkDir, parseFrontmatter } from './chunk-MKZOK4JU.js';
12
12
  import './chunk-GEEW6SY2.js';
13
13
  import './chunk-FTG7CRFD.js';
14
+ import './chunk-KSIRR5PL.js';
15
+ import './chunk-ILG4BXYE.js';
14
16
  import './chunk-W4IPN3DD.js';
15
- import './chunk-AN6NAFRT.js';
17
+ import './chunk-N7B3LZ7V.js';
16
18
  import './chunk-NSBPE2FW.js';
17
19
  import { existsSync, readFileSync } from 'fs';
18
20
  import * as path from 'path';
@@ -65,7 +67,7 @@ async function libraryAssets() {
65
67
  const domains = [];
66
68
  try {
67
69
  const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([
68
- import('./open-library-4JSLGWL6.js'),
70
+ import('./open-library-6LM4W4DR.js'),
69
71
  import('./library/index.js'),
70
72
  import('./core/index.js')
71
73
  ]);
@@ -98,7 +100,7 @@ async function libraryAssets() {
98
100
  async function storeAssets(projectDir) {
99
101
  const notes = [];
100
102
  try {
101
- const { resolveCatalogSource } = await import('./open-library-4JSLGWL6.js');
103
+ const { resolveCatalogSource } = await import('./open-library-6LM4W4DR.js');
102
104
  const { source, close } = await resolveCatalogSource({ projectDir });
103
105
  try {
104
106
  const assets = await source.listAssets();
@@ -202,5 +204,5 @@ function dedupeBySlug(domains) {
202
204
  }
203
205
 
204
206
  export { gatherAssetFeeds };
205
- //# sourceMappingURL=asset-feeds-AJOUKX55.js.map
206
- //# sourceMappingURL=asset-feeds-AJOUKX55.js.map
207
+ //# sourceMappingURL=asset-feeds-OPG6SUXU.js.map
208
+ //# sourceMappingURL=asset-feeds-OPG6SUXU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-OPG6SUXU.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nasync function loadDomainMds(root: string): Promise<DomainMd[]> {\n const out: DomainMd[] = [];\n for await (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nasync function stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): Promise<CatalogDomain[]> {\n const domainMds = await loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...(await scanRepo(lib.path, lib.name))];\n domains.push(...(await stampDomains(lib.path, lib.name, libEntries, false)));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => Promise<CatalogEntry[]>;\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nasync function sourceAssets(\n am: AssetManagerLike,\n): Promise<{ entries: OriginEntry[]; domains: CatalogDomain[] }> {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = (await am.search()).filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...(await stampDomains(root, sourceName, owned, false)));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Local disk only, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nasync function factoryAssets(): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...(await scanRepo(root, \"skaile-factory\"))];\n domains.push(...(await stampDomains(root, \"skaile-factory\", rootEntries)));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local disk only, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = await factoryAssets();\n const src = await sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
@@ -1,15 +1,17 @@
1
1
  export { WORKSPACE_MOUNT_ENV_VAR, deployAll, deployCatalogEntry, findAiAssetsRoot, isUnderWorkspaceMount, resolveFlowSkills, undeployCatalogEntry, workspaceMountDirs } from '../chunk-7BUZQVRR.js';
2
- import '../chunk-HSRHO7SK.js';
2
+ import '../chunk-C3QLJTMB.js';
3
+ import '../chunk-REILIKVM.js';
3
4
  import '../chunk-F3HNW354.js';
4
5
  import '../chunk-K5GBV4SA.js';
5
6
  import '../chunk-QVZA2MDT.js';
6
- import '../chunk-IB4XKQMQ.js';
7
- import '../chunk-MBARHWMZ.js';
7
+ import '../chunk-K27T47OO.js';
8
8
  import '../chunk-MENCWIHW.js';
9
9
  import '../chunk-P4VHQA4N.js';
10
10
  import '../chunk-MKZOK4JU.js';
11
11
  import '../chunk-GEEW6SY2.js';
12
12
  import '../chunk-FTG7CRFD.js';
13
+ import '../chunk-KSIRR5PL.js';
14
+ import '../chunk-ILG4BXYE.js';
13
15
  import '../chunk-W4IPN3DD.js';
14
16
  import '../chunk-NSBPE2FW.js';
15
17
  //# sourceMappingURL=catalog-deployer.js.map