@skaile/workspaces 1.3.0 → 1.5.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 (269) hide show
  1. package/CHANGELOG.md +395 -0
  2. package/README.md +1 -1
  3. package/dist/app-sdk/index.d.ts +2 -0
  4. package/dist/app-sdk/index.js +481 -0
  5. package/dist/app-sdk/index.js.map +1 -0
  6. package/dist/app-sdk/src/app.d.ts +152 -0
  7. package/dist/app-sdk/src/app.d.ts.map +1 -0
  8. package/dist/app-sdk/src/connection-params.d.ts +117 -0
  9. package/dist/app-sdk/src/connection-params.d.ts.map +1 -0
  10. package/dist/app-sdk/src/define-app-capability.d.ts +139 -0
  11. package/dist/app-sdk/src/define-app-capability.d.ts.map +1 -0
  12. package/dist/app-sdk/src/index.d.ts +17 -0
  13. package/dist/app-sdk/src/index.d.ts.map +1 -0
  14. package/dist/app-sdk/src/logger.d.ts +26 -0
  15. package/dist/app-sdk/src/logger.d.ts.map +1 -0
  16. package/dist/app-sdk/src/transport.d.ts +93 -0
  17. package/dist/app-sdk/src/transport.d.ts.map +1 -0
  18. package/dist/app-sdk/src/ws-transport.d.ts +79 -0
  19. package/dist/app-sdk/src/ws-transport.d.ts.map +1 -0
  20. package/dist/{asset-feeds-NEZKG6YS.js → asset-feeds-T35ELX2O.js} +11 -11
  21. package/dist/{asset-feeds-NEZKG6YS.js.map → asset-feeds-T35ELX2O.js.map} +1 -1
  22. package/dist/asset-manager/index.js +15 -10
  23. package/dist/asset-manager/installer.js +9 -9
  24. package/dist/asset-manager/renderers.js +2 -2
  25. package/dist/asset-manager/src/index.d.ts +42 -6
  26. package/dist/asset-manager/src/index.d.ts.map +1 -1
  27. package/dist/bridge/drivers/claude-sdk.js +2 -2
  28. package/dist/bridge/drivers/codex.js +1 -1
  29. package/dist/bridge/drivers/continue.js +2 -2
  30. package/dist/bridge/drivers/echo.js +1 -1
  31. package/dist/bridge/drivers/gemini.js +3 -3
  32. package/dist/bridge/drivers/goose.js +2 -2
  33. package/dist/bridge/drivers/omp.js +1 -1
  34. package/dist/bridge/drivers/opencode.js +2 -2
  35. package/dist/bridge/drivers/qwen.js +3 -3
  36. package/dist/bridge/index.js +3 -3
  37. package/dist/{chunk-YOPSHV7V.js → chunk-2DWXGUZA.js} +3 -3
  38. package/dist/{chunk-YOPSHV7V.js.map → chunk-2DWXGUZA.js.map} +1 -1
  39. package/dist/{chunk-XBG2YDQQ.js → chunk-2ZMO4CFG.js} +3 -3
  40. package/dist/{chunk-XBG2YDQQ.js.map → chunk-2ZMO4CFG.js.map} +1 -1
  41. package/dist/{chunk-OBSSORCE.js → chunk-3CHARYD4.js} +84 -12
  42. package/dist/chunk-3CHARYD4.js.map +1 -0
  43. package/dist/{chunk-SKADPHAM.js → chunk-4N5XR5DQ.js} +2 -2
  44. package/dist/chunk-4N5XR5DQ.js.map +1 -0
  45. package/dist/{chunk-WFEPI5LA.js → chunk-6NR2BEIY.js} +6 -6
  46. package/dist/{chunk-WFEPI5LA.js.map → chunk-6NR2BEIY.js.map} +1 -1
  47. package/dist/{chunk-7CNIRF42.js → chunk-BGIC25VK.js} +26 -15
  48. package/dist/chunk-BGIC25VK.js.map +1 -0
  49. package/dist/{chunk-YXEPZ7LP.js → chunk-CNSNN7N6.js} +6 -6
  50. package/dist/{chunk-YXEPZ7LP.js.map → chunk-CNSNN7N6.js.map} +1 -1
  51. package/dist/{chunk-PSMW5HLX.js → chunk-DMG6NJH7.js} +5 -5
  52. package/dist/{chunk-PSMW5HLX.js.map → chunk-DMG6NJH7.js.map} +1 -1
  53. package/dist/{chunk-P3MJYPZE.js → chunk-FDE7XRQA.js} +57 -9
  54. package/dist/chunk-FDE7XRQA.js.map +1 -0
  55. package/dist/{chunk-K5SD7FSF.js → chunk-HKX5VSWQ.js} +3 -3
  56. package/dist/{chunk-K5SD7FSF.js.map → chunk-HKX5VSWQ.js.map} +1 -1
  57. package/dist/{chunk-AZAS3FKN.js → chunk-HY33RMEA.js} +49 -3
  58. package/dist/chunk-HY33RMEA.js.map +1 -0
  59. package/dist/{chunk-XKARS6EE.js → chunk-IEX5YV4R.js} +3 -3
  60. package/dist/{chunk-XKARS6EE.js.map → chunk-IEX5YV4R.js.map} +1 -1
  61. package/dist/{chunk-GB4SEEK4.js → chunk-IRORTHGA.js} +10 -4
  62. package/dist/chunk-IRORTHGA.js.map +1 -0
  63. package/dist/chunk-J5TI55E7.js +203 -0
  64. package/dist/chunk-J5TI55E7.js.map +1 -0
  65. package/dist/chunk-JIDKX7GC.js +122 -0
  66. package/dist/chunk-JIDKX7GC.js.map +1 -0
  67. package/dist/{chunk-BDUANIAR.js → chunk-KEQ4GLVM.js} +3 -3
  68. package/dist/{chunk-BDUANIAR.js.map → chunk-KEQ4GLVM.js.map} +1 -1
  69. package/dist/{chunk-5XS3BFJS.js → chunk-KMY7HVQ6.js} +3 -3
  70. package/dist/{chunk-5XS3BFJS.js.map → chunk-KMY7HVQ6.js.map} +1 -1
  71. package/dist/{chunk-BZMTR5WW.js → chunk-MZV6WCF3.js} +83 -51
  72. package/dist/chunk-MZV6WCF3.js.map +1 -0
  73. package/dist/{chunk-QK5JDAFF.js → chunk-NKTFEV7Q.js} +4 -4
  74. package/dist/{chunk-QK5JDAFF.js.map → chunk-NKTFEV7Q.js.map} +1 -1
  75. package/dist/{chunk-DZCK7GRW.js → chunk-P4VHQA4N.js} +22 -6
  76. package/dist/chunk-P4VHQA4N.js.map +1 -0
  77. package/dist/{chunk-EVZKWY5J.js → chunk-PK7Q7MC7.js} +5 -4
  78. package/dist/chunk-PK7Q7MC7.js.map +1 -0
  79. package/dist/{chunk-ETYDLXI5.js → chunk-RDYOU6N6.js} +2 -2
  80. package/dist/{chunk-ETYDLXI5.js.map → chunk-RDYOU6N6.js.map} +1 -1
  81. package/dist/{chunk-RHMQPLIK.js → chunk-RSYV7XEN.js} +14 -8
  82. package/dist/chunk-RSYV7XEN.js.map +1 -0
  83. package/dist/{chunk-SUOGVHGJ.js → chunk-TNSCHS4I.js} +2 -2
  84. package/dist/{chunk-SUOGVHGJ.js.map → chunk-TNSCHS4I.js.map} +1 -1
  85. package/dist/{chunk-Z5Z3MYDL.js → chunk-UPZGQZEJ.js} +3 -3
  86. package/dist/{chunk-Z5Z3MYDL.js.map → chunk-UPZGQZEJ.js.map} +1 -1
  87. package/dist/{chunk-RJ3HUSBC.js → chunk-UQ5FK2AB.js} +3 -3
  88. package/dist/{chunk-RJ3HUSBC.js.map → chunk-UQ5FK2AB.js.map} +1 -1
  89. package/dist/{chunk-OUWNTFDG.js → chunk-UQKYT4V6.js} +38 -6
  90. package/dist/chunk-UQKYT4V6.js.map +1 -0
  91. package/dist/chunk-WYGXYGJH.js +688 -0
  92. package/dist/chunk-WYGXYGJH.js.map +1 -0
  93. package/dist/{chunk-TJRWGMD2.js → chunk-ZBZQC5R7.js} +3 -3
  94. package/dist/{chunk-TJRWGMD2.js.map → chunk-ZBZQC5R7.js.map} +1 -1
  95. package/dist/cli/index.js +1022 -374
  96. package/dist/cli/index.js.map +1 -1
  97. package/dist/cli/src/commands/catalog.d.ts +18 -0
  98. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  99. package/dist/cli/src/commands/library-cmd.d.ts +2 -2
  100. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  101. package/dist/cli/src/commands/library-publish.d.ts +53 -0
  102. package/dist/cli/src/commands/library-publish.d.ts.map +1 -0
  103. package/dist/cli/src/commands/preset-apply.d.ts +59 -0
  104. package/dist/cli/src/commands/preset-apply.d.ts.map +1 -0
  105. package/dist/cli/src/commands/preset-cmd.d.ts +8 -2
  106. package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
  107. package/dist/cli/src/commands/preset-export.d.ts +102 -0
  108. package/dist/cli/src/commands/preset-export.d.ts.map +1 -0
  109. package/dist/cli/src/commands/project.d.ts.map +1 -1
  110. package/dist/cli/src/commands/publish-core.d.ts +75 -0
  111. package/dist/cli/src/commands/publish-core.d.ts.map +1 -0
  112. package/dist/cli/src/commands/run.d.ts.map +1 -1
  113. package/dist/cli/src/commands/source-manifest-publish.d.ts +82 -0
  114. package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -0
  115. package/dist/cli/src/commands/source-manifest.d.ts +65 -6
  116. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
  117. package/dist/cli/src/commands/source.d.ts +13 -0
  118. package/dist/cli/src/commands/source.d.ts.map +1 -1
  119. package/dist/cli/src/commands/store.d.ts.map +1 -1
  120. package/dist/cli/src/commands/why.d.ts +18 -0
  121. package/dist/cli/src/commands/why.d.ts.map +1 -1
  122. package/dist/cli/src/driver-error.d.ts +12 -0
  123. package/dist/cli/src/driver-error.d.ts.map +1 -0
  124. package/dist/cli/src/open-library.d.ts +4 -0
  125. package/dist/cli/src/open-library.d.ts.map +1 -1
  126. package/dist/cli/src/store-auth.d.ts +42 -0
  127. package/dist/cli/src/store-auth.d.ts.map +1 -0
  128. package/dist/cli/src/store-client.d.ts +20 -22
  129. package/dist/cli/src/store-client.d.ts.map +1 -1
  130. package/dist/cli/src/store-publisher.d.ts +91 -0
  131. package/dist/cli/src/store-publisher.d.ts.map +1 -0
  132. package/dist/connectors/config.js +6 -6
  133. package/dist/connectors/index.js +8 -8
  134. package/dist/core/index.js +5 -5
  135. package/dist/core/publish-manifest.js +1 -1
  136. package/dist/core/runtime-assets.js +3 -3
  137. package/dist/core/src/cache-paths.d.ts +17 -0
  138. package/dist/core/src/cache-paths.d.ts.map +1 -1
  139. package/dist/core/src/index.d.ts +2 -2
  140. package/dist/core/src/index.d.ts.map +1 -1
  141. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  142. package/dist/core/src/repo-manager.d.ts +13 -2
  143. package/dist/core/src/repo-manager.d.ts.map +1 -1
  144. package/dist/core/src/walker.d.ts +10 -0
  145. package/dist/core/src/walker.d.ts.map +1 -1
  146. package/dist/core/src/workspace-yaml-editor.d.ts +14 -1
  147. package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
  148. package/dist/core/workspace-config.js +2 -2
  149. package/dist/deploy/index.js +5 -5
  150. package/dist/discovery/index.js +3 -3
  151. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  152. package/dist/discovery/src/discover.d.ts +17 -4
  153. package/dist/discovery/src/discover.d.ts.map +1 -1
  154. package/dist/discovery/src/index.d.ts +1 -1
  155. package/dist/discovery/src/index.d.ts.map +1 -1
  156. package/dist/discovery/src/reference-lint.d.ts +7 -0
  157. package/dist/discovery/src/reference-lint.d.ts.map +1 -1
  158. package/dist/discovery/src/source-config.d.ts +28 -0
  159. package/dist/discovery/src/source-config.d.ts.map +1 -1
  160. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  161. package/dist/{ensure-sources-4BAJGJRK.js → ensure-sources-QDVFUIUP.js} +18 -13
  162. package/dist/ensure-sources-QDVFUIUP.js.map +1 -0
  163. package/dist/factory-assets/connectors/box.js +8 -8
  164. package/dist/factory-assets/connectors/deploy.js +8 -8
  165. package/dist/factory-assets/connectors/devserver.js +8 -8
  166. package/dist/factory-assets/connectors/flow/adapter.js +8 -8
  167. package/dist/factory-assets/connectors/flow/engine/engine.d.ts +4 -1
  168. package/dist/factory-assets/connectors/flow/engine/engine.d.ts.map +1 -1
  169. package/dist/factory-assets/connectors/flow/engine/types.d.ts +41 -6
  170. package/dist/factory-assets/connectors/flow/engine/types.d.ts.map +1 -1
  171. package/dist/factory-assets/connectors/flow/engine.js +6 -6
  172. package/dist/factory-assets/connectors/flow/run-flow.js +9 -9
  173. package/dist/factory-assets/connectors/flow.js +8 -8
  174. package/dist/factory-assets/connectors/git.js +8 -8
  175. package/dist/factory-assets/connectors/gmail.js +8 -8
  176. package/dist/factory-assets/connectors/googledrive.js +8 -8
  177. package/dist/factory-assets/connectors/local.js +8 -8
  178. package/dist/factory-assets/connectors/mattermost.js +8 -8
  179. package/dist/factory-assets/connectors/memory.js +8 -8
  180. package/dist/factory-assets/connectors/minio.js +8 -8
  181. package/dist/factory-assets/connectors/postgres.js +8 -8
  182. package/dist/factory-assets/connectors/s3.js +8 -8
  183. package/dist/factory-assets/connectors/sharepoint.js +8 -8
  184. package/dist/factory-assets/connectors/sqlite.js +8 -8
  185. package/dist/factory-assets/connectors/static-server.js +8 -8
  186. package/dist/factory-assets/connectors/tunnel.js +8 -8
  187. package/dist/factory-assets/connectors/webdav.js +8 -8
  188. package/dist/factory-assets/connectors/xstate-store.js +8 -8
  189. package/dist/factory-assets/connectors/xstate.js +8 -8
  190. package/dist/factory-assets/skills/skaile-author-asset/SKILL.md +1 -1
  191. package/dist/factory-assets/skills/skaile-manage-workspace/SKILL.md +1 -1
  192. package/dist/{flows-UFCOGAAM.js → flows-MRVXTYWC.js} +4 -4
  193. package/dist/{flows-UFCOGAAM.js.map → flows-MRVXTYWC.js.map} +1 -1
  194. package/dist/helpers-TF7GCBRQ.js +27 -0
  195. package/dist/{helpers-2OL4FRFB.js.map → helpers-TF7GCBRQ.js.map} +1 -1
  196. package/dist/library/index.js +9 -9
  197. package/dist/library/install.js +5 -5
  198. package/dist/library/src/index.d.ts +2 -2
  199. package/dist/library/src/index.d.ts.map +1 -1
  200. package/dist/library/src/local/local-catalog-source.d.ts +12 -1
  201. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  202. package/dist/library/src/sync/manifest-writeback.d.ts +36 -0
  203. package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
  204. package/dist/library-publish-K5IBE44D.js +249 -0
  205. package/dist/library-publish-K5IBE44D.js.map +1 -0
  206. package/dist/open-library-4HMIDK3N.js +29 -0
  207. package/dist/{open-library-RPV2LIKL.js.map → open-library-4HMIDK3N.js.map} +1 -1
  208. package/dist/{paths-ML33B5SB.js → paths-P3DWFUPS.js} +8 -8
  209. package/dist/{paths-ML33B5SB.js.map → paths-P3DWFUPS.js.map} +1 -1
  210. package/dist/{plugin-store-G4HKWCTU.js → plugin-store-S7OMGI7N.js} +7 -7
  211. package/dist/{plugin-store-G4HKWCTU.js.map → plugin-store-S7OMGI7N.js.map} +1 -1
  212. package/dist/runner/index.js +14 -14
  213. package/dist/runner/src/agent.d.ts.map +1 -1
  214. package/dist/runner/src/capability-registry.d.ts +15 -4
  215. package/dist/runner/src/capability-registry.d.ts.map +1 -1
  216. package/dist/sdk/asset-manager.js +15 -10
  217. package/dist/sdk/bridge.js +3 -3
  218. package/dist/sdk/core.js +5 -5
  219. package/dist/sdk/flow.js +6 -6
  220. package/dist/sdk/index.js +14 -14
  221. package/dist/sdk/runner.js +14 -14
  222. package/dist/sdk/session.js +2 -2
  223. package/dist/sdk/types.js +1 -1
  224. package/dist/session/index.js +2 -2
  225. package/dist/{setup-WS6PF6JQ.js → setup-2CCS63L6.js} +10 -10
  226. package/dist/{setup-WS6PF6JQ.js.map → setup-2CCS63L6.js.map} +1 -1
  227. package/dist/source-LOAM7IIQ.js +30 -0
  228. package/dist/{source-22U5NOY4.js.map → source-LOAM7IIQ.js.map} +1 -1
  229. package/dist/source-manifest-publish-TGVZ6KMC.js +228 -0
  230. package/dist/source-manifest-publish-TGVZ6KMC.js.map +1 -0
  231. package/dist/tui/index.js +14 -14
  232. package/dist/types/index.js +1 -1
  233. package/dist/types/manifests.js +1 -1
  234. package/dist/types/src/capabilities.d.ts +8 -2
  235. package/dist/types/src/capabilities.d.ts.map +1 -1
  236. package/dist/types/src/logging.d.ts +3 -2
  237. package/dist/types/src/logging.d.ts.map +1 -1
  238. package/dist/types/src/manifests/_shared.d.ts +4 -4
  239. package/dist/types/src/manifests/index.d.ts +2 -2
  240. package/dist/types/src/manifests/index.d.ts.map +1 -1
  241. package/dist/types/src/manifests/preset.d.ts +10 -0
  242. package/dist/types/src/manifests/preset.d.ts.map +1 -1
  243. package/dist/types/src/version.d.ts +11 -1
  244. package/dist/types/src/version.d.ts.map +1 -1
  245. package/dist/workspace-plugin/adapters/mcp.js +2 -2
  246. package/dist/workspace-plugin/adapters/omp.js +3 -3
  247. package/dist/workspace-plugin/index.js +1 -1
  248. package/package.json +7 -1
  249. package/dist/chunk-7CNIRF42.js.map +0 -1
  250. package/dist/chunk-AZAS3FKN.js.map +0 -1
  251. package/dist/chunk-BZMTR5WW.js.map +0 -1
  252. package/dist/chunk-DZCK7GRW.js.map +0 -1
  253. package/dist/chunk-EVZKWY5J.js.map +0 -1
  254. package/dist/chunk-GB4SEEK4.js.map +0 -1
  255. package/dist/chunk-JQMIG7D3.js +0 -93
  256. package/dist/chunk-JQMIG7D3.js.map +0 -1
  257. package/dist/chunk-OBSSORCE.js.map +0 -1
  258. package/dist/chunk-OUWNTFDG.js.map +0 -1
  259. package/dist/chunk-P3MJYPZE.js.map +0 -1
  260. package/dist/chunk-RHMQPLIK.js.map +0 -1
  261. package/dist/chunk-RYRJEVQ4.js +0 -377
  262. package/dist/chunk-RYRJEVQ4.js.map +0 -1
  263. package/dist/chunk-SKADPHAM.js.map +0 -1
  264. package/dist/ensure-sources-4BAJGJRK.js.map +0 -1
  265. package/dist/helpers-2OL4FRFB.js +0 -22
  266. package/dist/open-library-RPV2LIKL.js +0 -29
  267. package/dist/source-22U5NOY4.js +0 -30
  268. package/dist/store-client-YLMBH5MF.js +0 -15
  269. package/dist/store-client-YLMBH5MF.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,400 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#340](https://github.com/skaile-ai/workspaces/pull/340) [`cde9457`](https://github.com/skaile-ai/workspaces/commit/cde9457c22d7e58111156effec1d4f5a8b9c50ec) Thanks [@henkbla](https://github.com/henkbla)! - `app-sdk`: connection-param handshake, reconnect, and registration replay.
8
+
9
+ The embedded app needs three things to open its back-connection — the gateway
10
+ URL, its `appId`, and a session identity token. The token is a credential, and
11
+ the preview surface that serves the app is unauthenticated, so it must not ride
12
+ in the iframe `src`. `resolveAppConnectionParams()` obtains it over
13
+ `postMessage` instead: the app posts a `skaile_app_ready` ping to its embedder
14
+ and awaits a `skaile_app_params` reply, with both sides pinning the peer on
15
+ `event.origin` **and** `event.source`. The app learns the expected host origin
16
+ from a non-secret `skaileParentOrigin` query param — safe to leak precisely
17
+ because it is not a credential. `"*"` and `"null"` host origins are refused: an
18
+ unpinnable peer defeats the point of keeping the token out of the URL.
19
+
20
+ `createWebSocketAppTransport` now accepts a `SessionTokenProvider` for
21
+ `sessionToken` as well as a bare string. The gateway's token is **single-use**
22
+ (consumed at `app_hello`), so a reconnecting transport cannot replay the one it
23
+ opened with; a provider mints a fresh token per attempt. A bare string still
24
+ opens the socket synchronously.
25
+
26
+ `createSkaileApp` gains a `reconnect` policy (default
27
+ `{maxAttempts:5, baseMs:1000, maxMs:30000}`, or `false` to disable). It rebinds
28
+ after a dropped socket and **replays its capability registry**, since the
29
+ gateway deregisters an app's capabilities when its connection closes. It also
30
+ retries a _retryable_ `app_hello_nack` — the app boots independently of the
31
+ session's agent container and can win that race. A permanent refusal (bad token,
32
+ `appId` not permitted) is never retried, because retrying only burns tokens.
33
+ `AppHelloNackMessage` gains an optional `retryable` field to carry that
34
+ distinction, and the SDK surfaces it as `AppHandshakeRefusedError.retryable`.
35
+ New `onSessionChange(handler)` fires on every bind — including the initial
36
+ `connect()` — and with `null` whenever the connection drops.
37
+
38
+ Behaviour change for `1.4.0` consumers: reconnect is **on by default**, so a
39
+ dropped socket now re-dials instead of leaving the app inert. Pass
40
+ `reconnect: false` for the old single-shot behaviour. Purely additive otherwise
41
+ — new exports, a widened `sessionToken` type, and one new optional wire field.
42
+
43
+ - [#344](https://github.com/skaile-ai/workspaces/pull/344) [`fdd6c6a`](https://github.com/skaile-ai/workspaces/commit/fdd6c6a2bf89b677274665edd31ba9c6f71e5408) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Wire `skaile library publish` / `register` / `yank` — first-party store publish
44
+
45
+ Publish a git-backed library you own (in-repo `skaile.manifest.yaml`) to the
46
+ store: `library publish <lib>` commits + pushes the library repo, registers +
47
+ syncs it as a store source (no sidecar — the in-repo manifest drives discovery),
48
+ and publishes its assets under the manifest's own `publisher` (no namespace
49
+ remap). `--asset <ref>` narrows to one asset; `--create-repo` provisions + links
50
+ a public `github.com/<you>/<lib>` via `gh` when the library has no remote;
51
+ `--dry-run` prints an offline plan. `register` skips the commit/push (already on
52
+ GitHub); `yank` unpublishes. Requires a public git remote + `store login`.
53
+
54
+ Extracts the shared store-interaction core (`publish-core.ts` `publishToStore`)
55
+ reused by both `library publish` and `source manifest publish`, so the two
56
+ front-ends can't drift on the register → sync → candidates → per-asset publish
57
+ sequence.
58
+
59
+ - [#335](https://github.com/skaile-ai/workspaces/pull/335) [`84565e0`](https://github.com/skaile-ai/workspaces/commit/84565e09c4da6daab4f26d9402cefd42884588ce) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Sidecar authoring + consume bug fixes for third-party sources.
60
+
61
+ **Sidecar authoring (`skaile source manifest init` / `edit` + overlay read + add).** You can
62
+ now curate assets from a foreign GitHub repo you don't control by authoring a
63
+ `skaile.manifest.yaml` stored _outside_ that repo, then consume + `add` them under a clean
64
+ curated publisher.
65
+
66
+ - `skaile source manifest init <src> [--publisher <name>] [--dev] [--force]` — clone (if
67
+ needed), run discovery, and write a curated manifest to the local store catalog at
68
+ `~/.skaile/store/manifests/<slug>.yaml`. Publisher defaults to the source's GitHub org.
69
+ Every asset inherits the top-level publisher (no per-asset path-segment stamp).
70
+ Idempotent (won't overwrite without `--force`).
71
+ - `skaile source manifest edit <src>` — open the curated manifest in `$EDITOR` and
72
+ re-validate on save (warnings surfaced, never a hard fail).
73
+ - `skaile source add` / `source sync` apply the curated manifest as a **read overlay**:
74
+ the curated publisher + asset inventory win over raw glob discovery. `LocalCatalogSource`
75
+ gained a `sidecarManifestFile` option; discovery gained `loadMergedSourceConfigFromFile`
76
+ - a `sidecarManifestFile` discovery option; the library gained `writeCuratedManifest`.
77
+ - `skaile add` now resolves the curated publisher too: the provenance walker
78
+ (`buildProvenanceIndex`) reads the same curated store overlay (via a new
79
+ `SourceClone.overlayManifestPath`), so the ref `search --local` displays
80
+ (`skill:@lark/…`) is the ref `add` accepts and deploys.
81
+ - Store manifests are keyed by a collision-free `storeManifestSlug(url)`
82
+ (`<host>__<owner>__<repo>`), so two repos sharing a trailing name (`orgA/cli`,
83
+ `orgB/cli`) no longer collide on `cli.yaml`.
84
+
85
+ **Bug fix — publisher normalization (glob AND manifest paths).** Discovery stored
86
+ publishers _with_ a leading `@`, which the local ref formatter doubled into `@@scripts`
87
+ (glob) / made `@lark` assets un-addable (manifest/curated overlay). `DiscoveredAsset.publisher`
88
+ is now **bare** on every discovery path (glob + manifest, local-FS + virtual-tree), unifying
89
+ them; the single `@` scope sigil is re-added by the ref formatter, and refs carry exactly
90
+ one `@` across both modes. The internal `SourceConfig` layer (`publisher_default` /
91
+ `atPublisher`) is unchanged — the `@`-prefix is correct there.
92
+
93
+ **Bug fix — `search --local` reads the index (and unions the factory source).** It now
94
+ reads the index (`asset_definitions` via `listAssetDefs`) instead of re-scanning the repo
95
+ tree, so its result set and count match exactly what `source add`/`sync` wrote — no scanner
96
+ `kind:name` dedup collapsing same-named or multi-kind assets — and unions the bundled
97
+ first-party factory source (never indexed) so built-in skills still appear in a fresh
98
+ project.
99
+
100
+ - [#339](https://github.com/skaile-ai/workspaces/pull/339) [`56776b2`](https://github.com/skaile-ai/workspaces/commit/56776b2c709d08d2aff0f46a19cd876db52db5b0) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Wire `skaile source manifest publish` and `yank` — the curator publish flow
101
+
102
+ `source manifest publish <src>` takes a locally-curated sidecar manifest (over a
103
+ foreign **public** GitHub repo), pushes it to a public "sidecar" repo you own,
104
+ then registers + syncs the source with the store and publishes each curated asset
105
+ under your namespace (default: your store username; `--as <ns>` to override, e.g.
106
+ a GitHub org you belong to). `--dry-run` prints an offline plan (no push, no store
107
+ calls). `yank` unpublishes the source's published assets; `propose` stays a stub.
108
+
109
+ Requires the store's self-service `sources.add` sidecar support (skaile-store#79)
110
+ and a deployed store backend. Mono-repo sidecars (`sidecar_path`) are a documented
111
+ follow-up.
112
+
113
+ - [#338](https://github.com/skaile-ai/workspaces/pull/338) [`9e959ee`](https://github.com/skaile-ai/workspaces/commit/9e959eec7d3c935aaa3c6c0c001f366b2bdbd80c) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Sidecar authoring phase 3 — wire `skaile source manifest rebuild` / `verify`,
114
+ extend the init test-fixture filter, and fix key-aware legacy clone migration.
115
+
116
+ - **`source manifest rebuild <src>` (new verb).** Refreshes a curated manifest
117
+ after the upstream repo changed. **Merge is the default — curation is sacred:**
118
+ it updates the clone (`git pull --ff-only`, best-effort), re-runs discovery,
119
+ and matches existing↔discovered entries by repo-relative `root` path. Existing
120
+ entries whose root is still present are KEPT verbatim (all hand-edits
121
+ preserved: publisher, per-asset name/version/description); entries whose root
122
+ is gone upstream are DROPPED and reported (`removed (gone upstream): …`).
123
+ Freshly-discovered assets not already curated are NOT auto-added — they are
124
+ reported (`N new upstream asset(s) available (not added): … — add with
125
+ \`skaile source manifest edit\``), so a curated foreign-repo sidecar never
126
+ silently absorbs new upstream skills, and an asset the curator deliberately
127
+ dropped stays dropped. Writes only when something changed (else `already up to
128
+ date`). `--overwrite`re-scans the full inventory with`init --force`
129
+ semantics, warning that curation is replaced.
130
+ - **`source manifest verify <src>` (new verb), read-only.** Checks each manifest
131
+ asset against the clone: `root`/`files` paths still exist upstream (missing →
132
+ error); a declared `sha256` on a **`files:` entry** recomputes to the same
133
+ deterministic composite hash (mismatch → error) — hashed exactly as discovery
134
+ does (repo-root anchored, files verbatim as repo-relative strings), so a
135
+ correctly-pinned hash verifies clean; a declared `sha256` on a `root:` entry is
136
+ **skipped with a warning** (discovery hashes only the per-kind filtered set, so
137
+ a whole-dir recompute would false-mismatch, and the writer never emits sha256
138
+ for `root:` entries); schema decodes cleanly (`decodeSkaileManifest`
139
+ diagnostics → warnings/errors); dependency refs parse (`parseAssetRef`;
140
+ malformed → warning). Prints a summary and exits 0 when there are no errors;
141
+ `--strict` forces a nonzero exit if there are any warnings. Writes nothing.
142
+ - **Extended init/rebuild test-fixture filter.** In addition to
143
+ `tests`/`test`/`__tests__`, the filter now also drops assets whose
144
+ repo-relative root contains a `testdata`, `fixtures`, or `__fixtures__` path
145
+ SEGMENT (exact segment), catching leaks like
146
+ `internal/qualitygate/skillscan/testdata/skills/lark-demo`. `init`/`rebuild`
147
+ path only; the general discovery walk (`source add`) is untouched.
148
+ - **Key-aware legacy clone migration.** `getGlobalCacheDir()` migration of a
149
+ legacy `~/.skaile/sources/<bare-name>` clone now re-derives the clone's true
150
+ cache key from its `origin` remote and lands it at
151
+ `<cacheRoot>/sources/<host>/<owner>/<repo>` (was: preserved the bare name, so a
152
+ URL-keyed lookup missed it and it lingered mis-placed). Non-clone leftovers
153
+ (the sidecar remainder) are untouched. New `mergeLegacyEntriesKeyed` primitive
154
+ in `@skaile/workspaces/core`.
155
+
156
+ `publish` / `propose` / `yank` remain stubs (they need the store publish
157
+ endpoint).
158
+
159
+ - [#343](https://github.com/skaile-ai/workspaces/pull/343) [`a8c2036`](https://github.com/skaile-ai/workspaces/commit/a8c2036e64c069ee46ebab3ff48e37044856b326) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Fix `skaile store login` — Keycloak device flow + correct store URL
160
+
161
+ The CLI's store auth was broken against the deployed store: the default URL
162
+ (`store.skaile.ai`) is dead and the old `/api/auth/*` login endpoints return 404.
163
+ `store login` now runs the Keycloak Device Authorization Grant (RFC 8628) against
164
+ `SKAILE_KEYCLOAK_URL` (default `https://auth.skaile.ai`, realm `skaile-store`,
165
+ public client `skaile-store-cli`) — it prints a URL + code to approve in a
166
+ browser, caches the token at `~/.skaile/auth.json` (shared with `store/cli`), and
167
+ refreshes transparently. The default store API URL is now `https://api.skaile.store`;
168
+ `whoami` reads `/api/v1/me`; every `/api/v1/*` publisher call authorizes with a
169
+ fresh device-flow token. Overridable via `SKAILE_STORE_URL` / `SKAILE_KEYCLOAK_URL`
170
+ / `SKAILE_STORE_REALM` / `SKAILE_STORE_CLI_CLIENT`.
171
+
172
+ Note: live login requires a public `skaile-store-cli` client (device-grant
173
+ enabled) registered on the store's Keycloak realm.
174
+
175
+ ### Patch Changes
176
+
177
+ - [#332](https://github.com/skaile-ai/workspaces/pull/332) [`bd6e8f7`](https://github.com/skaile-ai/workspaces/commit/bd6e8f710e42017dc07afa4ab00f4134a28a038e) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Four CLI UX papercuts from hands-on testing:
178
+
179
+ - `skaile run "<prompt>"` no longer crashes with a raw `spawn omp ENOENT` when the
180
+ configured driver's binary is missing. The single-shot chat path now catches the
181
+ failure and prints the bridge's actionable hint (the binary is not installed /
182
+ not on PATH) plus a suggestion to try `--driver claude-sdk`; unrelated errors
183
+ still surface their own message and a non-zero exit.
184
+ - `skaile source add` warns about a missing `sha256` by pointing at the real
185
+ `skaile source manifest rebuild` command instead of the non-existent
186
+ `skaile source build-manifest --write`.
187
+ - `skaile source remove` (without `--purge`) now tells the user how to reclaim the
188
+ leftover clone — pass `--purge` or run `skaile cache clean`.
189
+ - `skaile install <ref>` (pointer-only global install) adds a clarifying line that
190
+ it installed globally under `~/.skaile/libraries/installed/`, and that
191
+ `skaile add <ref>` is how to deploy the asset into the current project.
192
+
193
+ - [#328](https://github.com/skaile-ai/workspaces/pull/328) [`e613124`](https://github.com/skaile-ai/workspaces/commit/e613124bc6d5f1a46f01504a1fc239a0a905379f) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Preset UX polish from hands-on testing: `preset validate` no longer emits a
194
+ spurious "required" warning for a required placeholder with no default (that is
195
+ exactly what `export --redact` produces — required-ness is enforced at apply, not
196
+ validate); `skaile init` next-steps now suggests `preset apply`; and the apply
197
+ env-var hint points users to `.env`/shell (not skaile.yaml) so a first-time user
198
+ applying a shared preset knows where the secret value goes.
199
+
200
+ - [#330](https://github.com/skaile-ai/workspaces/pull/330) [`be69fb8`](https://github.com/skaile-ai/workspaces/commit/be69fb816125478d7f1d2d1cc3fea8162d3f0875) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Fix `skaile search` so its store leg reaches the live catalog. The store half now
201
+ goes through the shared catalog client (tRPC to `skaile.store`) instead of the dead
202
+ `store.skaile.ai` REST endpoint, surfaces `catalog.url: local` and failures
203
+ non-silently, and prints copyable `kind:@publisher/name#version` refs for both store
204
+ and local results.
205
+
206
+ - [#337](https://github.com/skaile-ai/workspaces/pull/337) [`b0acd87`](https://github.com/skaile-ai/workspaces/commit/b0acd87f3128946fd48a120afabf5cfe262c42ef) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Collapse per-asset missing-sha256 advisories into one summary line.
207
+
208
+ Since `source manifest init` stopped writing per-asset `sha256` for `root:`
209
+ entries, `skaile source add` / `source sync` printed one
210
+ `Missing sha256 — computed <hash> …` advisory line per asset. For a curated
211
+ overlay with dozens of assets that was pure noise.
212
+
213
+ Discovery now tags each absent-sha256 warning with a machine-readable
214
+ `code: "missing_sha256"` (on `ReferenceWarning`) instead of relying on the
215
+ message text, and `LocalCatalogSource.sync()` counts those and emits exactly
216
+ one collapsed advisory:
217
+ `<n> asset(s): sha256 not pinned — auto-computed locally (pin only for store publish)`.
218
+ All other advisories (e.g. unknown-kind ghost-install) still print individually.
219
+ The fatal `ManifestHashMismatch` path for a DECLARED-but-wrong sha256 is
220
+ unchanged.
221
+
222
+ - [#336](https://github.com/skaile-ai/workspaces/pull/336) [`1d2cf89`](https://github.com/skaile-ai/workspaces/commit/1d2cf8905cd67bd5b568b046d6aff49d01cdc16d) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Sidecar polish — five papercut fixes for the `skaile source manifest` sidecar
223
+ authoring flow, found consuming `github.com/larksuite/cli`.
224
+
225
+ - **`init` no longer writes per-asset `sha256`.** The init writer emitted the
226
+ discovery `sha256` (computed over the FILTERED per-kind file set) on each
227
+ `root:` entry; `source add` then re-walked the WHOLE root dir → a different
228
+ file set → a different composite hash → `ManifestHashMismatch`, failing every
229
+ asset. `init` now omits `sha256` for `root:`-mode entries (a missing hash is a
230
+ non-fatal advisory), so `source add` on init output indexes cleanly with zero
231
+ hash mismatches.
232
+ - **`init` skips test-fixture directories.** Assets whose repo-relative `root`
233
+ contains a `tests` / `test` / `__tests__` path segment are dropped from the
234
+ generated manifest (conservative, not repo-specific) so fixture "skills"
235
+ (`scripts/*/tests/*`, `tests/cli_e2e/*`) don't pollute the curated inventory.
236
+ `init`-path only; the general discovery walk (`source add`) is untouched.
237
+ - **`init` next-step hint prints a runnable command; `edit` accepts the store
238
+ slug.** The hint now echoes the exact `<src>` the user passed (the URL) instead
239
+ of a bare short name that mis-expanded to the skaile-ai org. `resolveSourceArg`
240
+ additionally accepts the collision-free store slug (`<host>__<owner>__<repo>`)
241
+ as an identifier, matched against existing `~/.skaile/store/manifests/<arg>.yaml`
242
+ before bare-name expansion. Full-URL resolution still works.
243
+ - **`edit` respects a full `$EDITOR` command.** `EDITOR="code --wait"` now spawns
244
+ `code` with args `["--wait", <file>]` (was treated as one binary and failed).
245
+ New `resolveEditorCommand` splits the editor value on whitespace and appends
246
+ the target last; unset falls back to `vi`.
247
+ - **`preset export` warns on machine-local sidecar overlays.** When a captured
248
+ source resolves through a curated store manifest on this machine, export now
249
+ warns that those assets may not resolve elsewhere until the sidecar is shared.
250
+
251
+ - [#333](https://github.com/skaile-ai/workspaces/pull/333) [`d213d69`](https://github.com/skaile-ai/workspaces/commit/d213d696e308f5253c618df359e8aa0625be7c8a) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Four asset-consume UX papercuts from hands-on testing (foreign repo shipping a
252
+ `skaile.manifest.yaml`, added via `skaile source add`, deployed via `skaile add`):
253
+
254
+ - **P-A — publisher `@` normalization.** A manifest declaring `publisher: '@acme'`
255
+ is now stored as `acme` (the leading `@` is the scope sigil the ref formatter
256
+ adds automatically). Previously it indexed as `@@acme` and the asset was
257
+ un-addable. Both manifest read paths are covered: `decodeSkaileManifest` (index
258
+ side, emits a `warning` diagnostic) **and** `resolveSourcePublisher` / `scanRepo`
259
+ (the `skaile search --local` scan/display side, which previously rendered the
260
+ copyable ref as `@@acme`). Only a single leading `@` is stripped; bare names are
261
+ untouched.
262
+ - **P-B — missing `sha256` is an advisory, not an indexing failure.** A manifest
263
+ asset with no `sha256` (and an unknown asset kind) now flows through the
264
+ discovery `warnings` channel and surfaces as an `advisory` on
265
+ `LocalCatalogSource.sync()` — never on `errors`. `skaile source add` /
266
+ `source sync` no longer report a false "N asset(s) failed to index" or exit 1
267
+ in this case; the asset is indexed and deployable, and the advisory is printed
268
+ on its own info line.
269
+ - **P-C — dead command pointer removed.** The missing-`sha256` advisory no longer
270
+ points at the not-wired `skaile source manifest rebuild` stub; it now reads
271
+ "only needed for store publish; auto-computed locally".
272
+ - **P-E — search kind-miss message.** `skaile search <kind>` with no matches now
273
+ says `No "<kind>" assets found in this project's sources.` instead of the
274
+ misleading never-synced `Run \`skaile source sync\` first` hint.
275
+
276
+ ## 1.4.0
277
+
278
+ ### Minor Changes
279
+
280
+ - [#325](https://github.com/skaile-ai/workspaces/pull/325) [`a91d49c`](https://github.com/skaile-ai/workspaces/commit/a91d49cba353e1714e97faaa3fb7dde21a40304c) Thanks [@henkbla](https://github.com/henkbla)! - Protocol v3.4.0 — add the embedded-app capability source to the wire types.
281
+ `CapabilityOrigin` gains `{ kind: 'app'; appId: string }` and `Capability.side`
282
+ gains `'app'` ("the handler runs in the embedded app"). Both are additive and
283
+ ride through under the protocol's major-equality rule — a peer that does not
284
+ understand `origin:'app'` / `side:'app'` never produces or routes them, so
285
+ existing consumers (runner, bridge, platform) are unaffected until a source
286
+ actually registers an `app` capability. No new message types:
287
+ `capability_register` / `capability_invoked` / `capability_result` /
288
+ `capability_approve` / `render_invoked` are reused verbatim.
289
+
290
+ `PROTOCOL_VERSION` bumps to `3.4.0`. `isUserInvokable` defaults `app`-origin
291
+ capabilities to LLM-only (`false`) unless the author sets
292
+ `audience: ['llm','user']`. The `capability` log subkind now recognizes `app`
293
+ (with `appId` encoded into `instance` as `<appId>.<name>`).
294
+
295
+ Design: `packages/workspaces/_devlog/specs/2026-07-07-app-capability-source.md`.
296
+ This is the protocol keystone for Skailify (embedding agent-controllable apps in
297
+ Skaile sessions); the runner trust guard and platform-gateway routing land in
298
+ follow-up changes.
299
+
300
+ - [#326](https://github.com/skaile-ai/workspaces/pull/326) [`8f5e6e6`](https://github.com/skaile-ai/workspaces/commit/8f5e6e6f0fe214df35418899e3eb8747fe10fc60) Thanks [@henkbla](https://github.com/henkbla)! - Extend the runner capability-registry origin-trust guard for the `app`
301
+ capability origin (protocol 3.4.0). `RegisterSource` gains an
302
+ `{ kind: 'app'; appId: string }` variant, and `CapabilityRegistry.register`
303
+ now enforces:
304
+
305
+ - an **app source** may declare `origin.kind: 'app'` **only for its own `appId`**;
306
+ - **no other source** (agent, client, skill, connector, mount, flow, mcp,
307
+ framework) may declare an `app` origin — the `agent` rule is tightened to
308
+ exclude `app` so a skill/connector/flow cannot impersonate an embedded app.
309
+
310
+ Violations are dropped with a warn-level log, exactly as origin mismatches are
311
+ today. This closes the forgery hole described in the app-capability-source spec
312
+ (§ Trust / forgery rule): without it a compromised source could register
313
+ `app.delete_everything` under a real app's id. The bare-string `'client'` /
314
+ `'agent'` sources and all existing origin rules are unchanged.
315
+
316
+ Also makes the registry fully `app`-aware in lock-step: `ORIGIN_PROMPT_ORDER`
317
+ and `CapabilityListFilter.side` gain `'app'`, so an `app`-origin capability's
318
+ `promptFragment` reaches the `<CAPABILITIES>` section and `list({ side: 'app' })`
319
+ is expressible. The authoritative per-connection `appId` binding is enforced at
320
+ the platform gateway (follow-up); this is the runner-side defence-in-depth.
321
+
322
+ - [#327](https://github.com/skaile-ai/workspaces/pull/327) [`fc4ed2f`](https://github.com/skaile-ai/workspaces/commit/fc4ed2fa8945484a329f5c1f5f04d9a994cb9694) Thanks [@henkbla](https://github.com/henkbla)! - Add `@skaile/workspaces/app-sdk` — the thin SDK an embedded, agent-controllable
323
+ app uses to become a capability peer inside a Skaile session (the "Skailify"
324
+ embed-in-platform slice; protocol 3.4.0).
325
+
326
+ `createSkaileApp({ appId, transport })` opens an authenticated back-connection,
327
+ performs the app handshake (`app_hello` → `app_hello_ack` binding the session to
328
+ `appId`, or `app_hello_nack` refusal), registers `app.*` capabilities stamped
329
+ with `origin:{kind:'app', appId}` / `side:'app'`, and answers inbound
330
+ `capability_invoked` events by dispatching to the local handler and replying with
331
+ `capability_result` (a thrown handler / invalid input / unknown name rides back
332
+ as `{ error }`). Register / deregister mid-session is supported.
333
+
334
+ Also exports `defineAppCapability` (Zod-typed authoring that fixes `side:'app'`),
335
+ the `AppTransport` interface + app-channel message types, a browser-safe
336
+ `createWebSocketAppTransport` (injected session identity presented as the
337
+ `skaile-bearer.*` subprotocol the gateway already decodes), and an `AppLogger`.
338
+
339
+ Purely additive: a new subpath export; existing consumers are unaffected. No new
340
+ capability wire types — `capability_register` / `capability_invoked` /
341
+ `capability_result` are reused verbatim; only the `app_hello` handshake is
342
+ specific to this app↔gateway channel. Design:
343
+ `packages/workspaces/_devlog/specs/2026-07-07-app-capability-source.md`.
344
+
345
+ - [#314](https://github.com/skaile-ai/workspaces/pull/314) [`d608fd9`](https://github.com/skaile-ai/workspaces/commit/d608fd9e7517662327d48123aad5a3ad080b1232) Thanks [@mortegro](https://github.com/mortegro)! - `FlowNode.type` now includes `"sub-flow"` and `"router"` alongside `"skill"` and
346
+ `"group"`, matching node kinds already shipped in production flows (e.g.
347
+ appbuilder-standard/-complex). `FlowNode.data` gained `flow` (delegated flow ID
348
+ for `sub-flow` nodes) and `routes` (ordered `{condition, target}` table for
349
+ `router` nodes). Consumers that previously cast around the narrower union can
350
+ drop those casts.
351
+
352
+ This is a type-level and documentation change only — the engine
353
+ (`computeFlowState`, `computeFlowStateFromSnapshots`, `computeSkippable`) still
354
+ tracks only `'skill'` nodes; `'sub-flow'` and `'router'` are excluded from
355
+ dependency computation the same as `'group'` today. See
356
+ `docs/flow-execution.md#node-types` for the full semantics of each kind and
357
+ what's intentionally left as downstream/future work.
358
+
359
+ - [#317](https://github.com/skaile-ai/workspaces/pull/317) [`ca173c9`](https://github.com/skaile-ai/workspaces/commit/ca173c9e1617d45051a1d7fa21712660250fe13b) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Add `skaile preset apply <path>` — the consume half of the preset roundtrip. It reads a `.preset.yaml`, resolves placeholders, and writes the items back additively into the target project's `skaile.yaml` (the inverse of `preset export`). Bare-ref items become dependencies (deduped), `connector:<driver>` items become `ConnectorDeclaration`s, and `mcp:<id>` items become `McpServerDeclaration`s; a connector/mcp whose id already exists and differs is skipped (the user's config wins). Placeholder resolution is secret-safe: a `secret` placeholder resolves to an `env:<KEY>` reference (never the raw value) and the key is surfaced in a "set these env vars" summary, while non-secret `${INPUT:KEY}` tokens inline the provided literal (from `--input KEY=VAL`, an interactive prompt, or a declared default). Nested-preset refs are rejected for now. Unless `--no-deploy` is passed, the command runs the project install so new skill deps deploy. Flags: `--project-dir`, `--input` (repeatable), `--yes`, `--no-deploy`. Also adds `WorkspaceYamlEditor.addDependency` (dedupe) and `WorkspaceYamlEditor.setMcpServer` (add/replace-by-id) comment-preserving methods.
360
+
361
+ - [#316](https://github.com/skaile-ai/workspaces/pull/316) [`9c2a7ab`](https://github.com/skaile-ai/workspaces/commit/9c2a7abea4076bb79ce22b9b38f3885b7d75a513) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Add `skaile preset export [name]` — snapshot a workspace's own `skaile.yaml` into a shareable `.preset.yaml`. Dependencies map to bare-ref items (copied verbatim), connectors to `connector:<driver>` items, and MCP servers to `mcp:<id>` items; `agent_config` is deliberately excluded as personal/machine-specific. The command has first-class secret safety: it scans connector/mcp config for inline credentials (anything that is not an `env:`/`forge:`/`secret:`/… reference), prints a loud summary, redacts flagged values into `${INPUT:…}` placeholders under `--redact` (or interactively on a TTY), and stamps a `CONTAINS INLINE SECRETS` header when any inline secret is left in place — so an export is never a silent success. Flags: `--project-dir`, `--out`, `--dir`, `--redact`, `--force`.
362
+
363
+ - [#318](https://github.com/skaile-ai/workspaces/pull/318) [`c5c145c`](https://github.com/skaile-ai/workspaces/commit/c5c145ca06627da766b6df1471d626403daf3c0b) Thanks [@P1umPudding](https://github.com/P1umPudding)! - `skaile preset export`/`apply` now carry the **sources** a preset's dependencies resolve from, so a preset built against a non-factory git source (e.g. `skill:@mattpocock/grill-me` from `mattpocock/skills`) resolves on `apply` even in a workspace that never registered that source. Export captures only the needed sources — each dependency is matched to its lock entry by version-agnostic identity (kind+publisher+name) and the entry's `source.url` is recorded, excluding the bundled factory source; with no lock (or an unresolved dependency) it conservatively records every non-factory source. Apply registers those sources into `skaile.yaml` (deduped by url; an existing url with a differing pin is left untouched) before running install. Adds an optional `sources` field to the preset manifest schema and exports `FACTORY_SOURCE_URL` / `normalizeRepoUrl` from `@skaile/workspaces/asset-manager`.
364
+
365
+ ### Patch Changes
366
+
367
+ - [#300](https://github.com/skaile-ai/workspaces/pull/300) [`5824f67`](https://github.com/skaile-ai/workspaces/commit/5824f671f3ca9c88adcebfe3584c03360f67e1b0) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Fix a hard crash in `skaile doctor`: `AssetManager.info()` now tolerates a bare
368
+ `kind:name` ref (publisher optional) instead of throwing "publisher required".
369
+ `doctor()` iterates `listDeployed()`, which — because it scans deploy dirs —
370
+ emits publisher-less refs; the strict parse in front of `info()`'s already
371
+ publisher-optional matching crashed on the first deployed asset. `info()` falls
372
+ back to a minimal tolerant parse and returns `null` when it can recover neither
373
+ a kind nor a name; the strict `parseAssetRef` is unchanged for other callers.
374
+
375
+ - [#298](https://github.com/skaile-ai/workspaces/pull/298) [`80c9d58`](https://github.com/skaile-ai/workspaces/commit/80c9d5844f8c06a89769bc7c411b69c6a63eca9b) Thanks [@P1umPudding](https://github.com/P1umPudding)! - Fix `skaile install` never pruning manifest-less (content-sha pseudo-version)
376
+ assets. The install reconcile derived asset identity via `parseCanonicalLockKey`,
377
+ which rejected `#0.0.0-sha.<hash>` lock keys and returned `{}`, so a dependency
378
+ removed from `skaile.yaml` left its deployed files behind as a silent orphan.
379
+ `parseCanonicalLockKey` now falls back to parsing the bare identity when the pin
380
+ is a non-canonical pseudo-version — fixing the reconcile plus every other lock-key
381
+ consumer (locked-install restore, `list`/`globalState` state machine, `outdated`)
382
+ for manifest-less assets. `add`/`remove` now also keep `skaile.lock.yaml` in sync
383
+ so an added-then-removed asset can be reconciled away, and the reconcile warns on a
384
+ genuinely unparseable lock key instead of skipping it silently.
385
+
386
+ - [#309](https://github.com/skaile-ai/workspaces/pull/309) [`f7dbdf3`](https://github.com/skaile-ai/workspaces/commit/f7dbdf341cf5f6aa6289d6d971a32183ac1cdcf3) Thanks [@mortegro](https://github.com/mortegro)! - `skaile source add` now clones/validates the repo **before** writing the source
387
+ entry to `skaile.yaml`. Previously the entry was persisted first, so a failed
388
+ clone (repo not found, bad URL, network error) — which hard-exits in
389
+ `ensureClone` — left a stale, un-cloned source recorded in `skaile.yaml`. The
390
+ entry is only written once the source is known-good.
391
+
392
+ A `--force` re-clone now moves the existing clone aside and only deletes it once
393
+ the fresh clone succeeds, so a failed re-clone restores the previous clone
394
+ instead of leaving the source registered with no cache behind it.
395
+
396
+ - [#299](https://github.com/skaile-ai/workspaces/pull/299) [`f91a0dd`](https://github.com/skaile-ai/workspaces/commit/f91a0dd14f5775b76457c79f0d7ff68785fc3180) Thanks [@P1umPudding](https://github.com/P1umPudding)! - `skaile why <ref>` now distinguishes an undeclared ref from a declared-but-uninstalled one when the dependency chain is empty. Previously it always printed "not found in lock file. Run `skaile install` first." — misleading when nothing in `skaile.yaml` requires the ref, since install cannot help. Undeclared refs now get a clearer message pointing to `skaile list`; declared-but-uninstalled refs keep the install hint. The empty-chain decision is factored into a pure exported `whyEmptyMessage` helper.
397
+
3
398
  ## 1.3.0
4
399
 
5
400
  ### Minor Changes
package/README.md CHANGED
@@ -77,6 +77,6 @@ bun run cli run mvp # run a flow
77
77
  ## Architecture Docs
78
78
 
79
79
  - [Client-Server Architecture](../../docs/client-server-architecture.md) — design for the agent client, transport, and shared state protocol (new packages: `client`, `transport`)
80
- - [Session Dispatcher Architecture](../../docs/session/architecture.md) — design for session message dispatching, persistence, and fan-out (new package: `session`)
80
+ - [Session Dispatcher Architecture](../../docs/sections/session/architecture.md) — design for session message dispatching, persistence, and fan-out (new package: `session`)
81
81
 
82
82
  See each package's `CLAUDE.md` for architecture details and developer conventions.
@@ -0,0 +1,2 @@
1
+ // Auto-generated by _scripts/emit-dts-sidecars.ts — do not edit by hand.
2
+ export * from "./src/index.js";