@skaile/workspaces 1.4.0 → 1.6.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 (198) hide show
  1. package/CHANGELOG.md +326 -0
  2. package/dist/app-sdk/index.js +241 -55
  3. package/dist/app-sdk/index.js.map +1 -1
  4. package/dist/app-sdk/src/app.d.ts +55 -4
  5. package/dist/app-sdk/src/app.d.ts.map +1 -1
  6. package/dist/app-sdk/src/connection-params.d.ts +117 -0
  7. package/dist/app-sdk/src/connection-params.d.ts.map +1 -0
  8. package/dist/app-sdk/src/index.d.ts +3 -2
  9. package/dist/app-sdk/src/index.d.ts.map +1 -1
  10. package/dist/app-sdk/src/transport.d.ts +9 -0
  11. package/dist/app-sdk/src/transport.d.ts.map +1 -1
  12. package/dist/app-sdk/src/ws-transport.d.ts +18 -2
  13. package/dist/app-sdk/src/ws-transport.d.ts.map +1 -1
  14. package/dist/{asset-feeds-NG5TKB3V.js → asset-feeds-T35ELX2O.js} +9 -9
  15. package/dist/{asset-feeds-NG5TKB3V.js.map → asset-feeds-T35ELX2O.js.map} +1 -1
  16. package/dist/asset-manager/index.js +11 -6
  17. package/dist/asset-manager/installer.js +5 -5
  18. package/dist/asset-manager/src/index.d.ts.map +1 -1
  19. package/dist/{chunk-BE5KTS2L.js → chunk-2DWXGUZA.js} +2 -2
  20. package/dist/{chunk-BE5KTS2L.js.map → chunk-2DWXGUZA.js.map} +1 -1
  21. package/dist/{chunk-XBG2YDQQ.js → chunk-2ZMO4CFG.js} +3 -3
  22. package/dist/{chunk-XBG2YDQQ.js.map → chunk-2ZMO4CFG.js.map} +1 -1
  23. package/dist/{chunk-X57AMTAH.js → chunk-3CHARYD4.js} +16 -7
  24. package/dist/chunk-3CHARYD4.js.map +1 -0
  25. package/dist/{chunk-LCTRCWBK.js → chunk-6NR2BEIY.js} +4 -4
  26. package/dist/{chunk-LCTRCWBK.js.map → chunk-6NR2BEIY.js.map} +1 -1
  27. package/dist/{chunk-JZPEEMIM.js → chunk-BEO6KN7P.js} +5 -5
  28. package/dist/{chunk-JZPEEMIM.js.map → chunk-BEO6KN7P.js.map} +1 -1
  29. package/dist/{chunk-AAGD2J4H.js → chunk-CBA2XIBF.js} +33 -15
  30. package/dist/chunk-CBA2XIBF.js.map +1 -0
  31. package/dist/{chunk-GWDZW44L.js → chunk-DMG6NJH7.js} +4 -4
  32. package/dist/{chunk-GWDZW44L.js.map → chunk-DMG6NJH7.js.map} +1 -1
  33. package/dist/{chunk-HWTQ6HPO.js → chunk-FDE7XRQA.js} +56 -8
  34. package/dist/chunk-FDE7XRQA.js.map +1 -0
  35. package/dist/{chunk-26YCXWCU.js → chunk-HY33RMEA.js} +3 -3
  36. package/dist/{chunk-26YCXWCU.js.map → chunk-HY33RMEA.js.map} +1 -1
  37. package/dist/chunk-J5TI55E7.js +203 -0
  38. package/dist/chunk-J5TI55E7.js.map +1 -0
  39. package/dist/chunk-JIDKX7GC.js +122 -0
  40. package/dist/chunk-JIDKX7GC.js.map +1 -0
  41. package/dist/{chunk-BDUANIAR.js → chunk-KEQ4GLVM.js} +3 -3
  42. package/dist/{chunk-BDUANIAR.js.map → chunk-KEQ4GLVM.js.map} +1 -1
  43. package/dist/{chunk-DNFIKRO6.js → chunk-KMY7HVQ6.js} +3 -3
  44. package/dist/{chunk-DNFIKRO6.js.map → chunk-KMY7HVQ6.js.map} +1 -1
  45. package/dist/{chunk-B6SSXVF2.js → chunk-MZV6WCF3.js} +81 -49
  46. package/dist/chunk-MZV6WCF3.js.map +1 -0
  47. package/dist/{chunk-DZCK7GRW.js → chunk-P4VHQA4N.js} +22 -6
  48. package/dist/chunk-P4VHQA4N.js.map +1 -0
  49. package/dist/{chunk-OSCJRUKM.js → chunk-RDYOU6N6.js} +2 -2
  50. package/dist/{chunk-OSCJRUKM.js.map → chunk-RDYOU6N6.js.map} +1 -1
  51. package/dist/{chunk-77OXU44H.js → chunk-RSYV7XEN.js} +13 -7
  52. package/dist/chunk-RSYV7XEN.js.map +1 -0
  53. package/dist/{chunk-OUWNTFDG.js → chunk-UQKYT4V6.js} +38 -6
  54. package/dist/chunk-UQKYT4V6.js.map +1 -0
  55. package/dist/chunk-WYGXYGJH.js +688 -0
  56. package/dist/chunk-WYGXYGJH.js.map +1 -0
  57. package/dist/{chunk-TJRWGMD2.js → chunk-ZBZQC5R7.js} +3 -3
  58. package/dist/{chunk-TJRWGMD2.js.map → chunk-ZBZQC5R7.js.map} +1 -1
  59. package/dist/cli/index.js +259 -192
  60. package/dist/cli/index.js.map +1 -1
  61. package/dist/cli/src/commands/catalog.d.ts +18 -0
  62. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  63. package/dist/cli/src/commands/library-cmd.d.ts +2 -2
  64. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  65. package/dist/cli/src/commands/library-publish.d.ts +53 -0
  66. package/dist/cli/src/commands/library-publish.d.ts.map +1 -0
  67. package/dist/cli/src/commands/preset-cmd.d.ts +6 -0
  68. package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -1
  69. package/dist/cli/src/commands/preset-export.d.ts +10 -1
  70. package/dist/cli/src/commands/preset-export.d.ts.map +1 -1
  71. package/dist/cli/src/commands/project.d.ts.map +1 -1
  72. package/dist/cli/src/commands/publish-core.d.ts +75 -0
  73. package/dist/cli/src/commands/publish-core.d.ts.map +1 -0
  74. package/dist/cli/src/commands/run.d.ts.map +1 -1
  75. package/dist/cli/src/commands/source-manifest-publish.d.ts +82 -0
  76. package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -0
  77. package/dist/cli/src/commands/source-manifest.d.ts +65 -6
  78. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
  79. package/dist/cli/src/commands/source.d.ts +13 -0
  80. package/dist/cli/src/commands/source.d.ts.map +1 -1
  81. package/dist/cli/src/commands/store.d.ts.map +1 -1
  82. package/dist/cli/src/driver-error.d.ts +12 -0
  83. package/dist/cli/src/driver-error.d.ts.map +1 -0
  84. package/dist/cli/src/open-library.d.ts +4 -0
  85. package/dist/cli/src/open-library.d.ts.map +1 -1
  86. package/dist/cli/src/store-auth.d.ts +42 -0
  87. package/dist/cli/src/store-auth.d.ts.map +1 -0
  88. package/dist/cli/src/store-client.d.ts +20 -22
  89. package/dist/cli/src/store-client.d.ts.map +1 -1
  90. package/dist/cli/src/store-publisher.d.ts +91 -0
  91. package/dist/cli/src/store-publisher.d.ts.map +1 -0
  92. package/dist/connectors/config.js +5 -5
  93. package/dist/connectors/index.js +6 -6
  94. package/dist/core/index.js +4 -4
  95. package/dist/core/publish-manifest.js +1 -1
  96. package/dist/core/runtime-assets.js +3 -3
  97. package/dist/core/src/cache-paths.d.ts +17 -0
  98. package/dist/core/src/cache-paths.d.ts.map +1 -1
  99. package/dist/core/src/index.d.ts +2 -2
  100. package/dist/core/src/index.d.ts.map +1 -1
  101. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  102. package/dist/core/src/repo-manager.d.ts +13 -2
  103. package/dist/core/src/repo-manager.d.ts.map +1 -1
  104. package/dist/core/src/walker.d.ts +10 -0
  105. package/dist/core/src/walker.d.ts.map +1 -1
  106. package/dist/core/workspace-config.js +2 -2
  107. package/dist/deploy/index.js +4 -4
  108. package/dist/discovery/index.js +2 -2
  109. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  110. package/dist/discovery/src/discover.d.ts +17 -4
  111. package/dist/discovery/src/discover.d.ts.map +1 -1
  112. package/dist/discovery/src/index.d.ts +1 -1
  113. package/dist/discovery/src/index.d.ts.map +1 -1
  114. package/dist/discovery/src/reference-lint.d.ts +7 -0
  115. package/dist/discovery/src/reference-lint.d.ts.map +1 -1
  116. package/dist/discovery/src/source-config.d.ts +28 -0
  117. package/dist/discovery/src/source-config.d.ts.map +1 -1
  118. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  119. package/dist/{ensure-sources-CHC7X7AJ.js → ensure-sources-QDVFUIUP.js} +14 -9
  120. package/dist/ensure-sources-QDVFUIUP.js.map +1 -0
  121. package/dist/factory-assets/connectors/box.js +6 -6
  122. package/dist/factory-assets/connectors/deploy.js +6 -6
  123. package/dist/factory-assets/connectors/devserver.js +6 -6
  124. package/dist/factory-assets/connectors/flow/adapter.js +6 -6
  125. package/dist/factory-assets/connectors/flow/engine.js +4 -4
  126. package/dist/factory-assets/connectors/flow/run-flow.js +7 -7
  127. package/dist/factory-assets/connectors/flow.js +6 -6
  128. package/dist/factory-assets/connectors/git.js +6 -6
  129. package/dist/factory-assets/connectors/gmail.js +6 -6
  130. package/dist/factory-assets/connectors/googledrive.js +6 -6
  131. package/dist/factory-assets/connectors/local.js +6 -6
  132. package/dist/factory-assets/connectors/mattermost.js +6 -6
  133. package/dist/factory-assets/connectors/memory.js +6 -6
  134. package/dist/factory-assets/connectors/minio.js +6 -6
  135. package/dist/factory-assets/connectors/postgres.js +6 -6
  136. package/dist/factory-assets/connectors/s3.js +6 -6
  137. package/dist/factory-assets/connectors/sharepoint.js +6 -6
  138. package/dist/factory-assets/connectors/sqlite.js +6 -6
  139. package/dist/factory-assets/connectors/static-server.js +6 -6
  140. package/dist/factory-assets/connectors/tunnel.js +6 -6
  141. package/dist/factory-assets/connectors/webdav.js +6 -6
  142. package/dist/factory-assets/connectors/xstate-store.js +6 -6
  143. package/dist/factory-assets/connectors/xstate.js +6 -6
  144. package/dist/{flows-CGOCUNO6.js → flows-MRVXTYWC.js} +3 -3
  145. package/dist/{flows-CGOCUNO6.js.map → flows-MRVXTYWC.js.map} +1 -1
  146. package/dist/{helpers-GWG4CYYC.js → helpers-TF7GCBRQ.js} +14 -9
  147. package/dist/{helpers-GWG4CYYC.js.map → helpers-TF7GCBRQ.js.map} +1 -1
  148. package/dist/library/index.js +6 -6
  149. package/dist/library/install.js +4 -4
  150. package/dist/library/src/index.d.ts +2 -2
  151. package/dist/library/src/index.d.ts.map +1 -1
  152. package/dist/library/src/local/local-catalog-source.d.ts +12 -1
  153. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  154. package/dist/library/src/sync/manifest-writeback.d.ts +36 -0
  155. package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
  156. package/dist/library-publish-K5IBE44D.js +249 -0
  157. package/dist/library-publish-K5IBE44D.js.map +1 -0
  158. package/dist/{open-library-37PXN6MK.js → open-library-4HMIDK3N.js} +13 -13
  159. package/dist/{open-library-37PXN6MK.js.map → open-library-4HMIDK3N.js.map} +1 -1
  160. package/dist/{paths-UVOHWUPY.js → paths-P3DWFUPS.js} +7 -7
  161. package/dist/{paths-UVOHWUPY.js.map → paths-P3DWFUPS.js.map} +1 -1
  162. package/dist/{plugin-store-EIMVEH3O.js → plugin-store-S7OMGI7N.js} +6 -6
  163. package/dist/{plugin-store-EIMVEH3O.js.map → plugin-store-S7OMGI7N.js.map} +1 -1
  164. package/dist/runner/index.js +8 -8
  165. package/dist/runner/src/agent.d.ts.map +1 -1
  166. package/dist/runner/src/capability-registry.d.ts +21 -2
  167. package/dist/runner/src/capability-registry.d.ts.map +1 -1
  168. package/dist/sdk/asset-manager.js +11 -6
  169. package/dist/sdk/core.js +4 -4
  170. package/dist/sdk/flow.js +4 -4
  171. package/dist/sdk/index.js +8 -8
  172. package/dist/sdk/runner.js +8 -8
  173. package/dist/{setup-DINVR6ZQ.js → setup-2CCS63L6.js} +6 -6
  174. package/dist/{setup-DINVR6ZQ.js.map → setup-2CCS63L6.js.map} +1 -1
  175. package/dist/source-LOAM7IIQ.js +30 -0
  176. package/dist/{source-RXAHIGMD.js.map → source-LOAM7IIQ.js.map} +1 -1
  177. package/dist/source-manifest-publish-TGVZ6KMC.js +228 -0
  178. package/dist/source-manifest-publish-TGVZ6KMC.js.map +1 -0
  179. package/dist/tui/index.js +8 -8
  180. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  181. package/dist/workspace-plugin/adapters/omp.js +3 -3
  182. package/dist/workspace-plugin/index.js +1 -1
  183. package/package.json +1 -1
  184. package/dist/chunk-77OXU44H.js.map +0 -1
  185. package/dist/chunk-AAGD2J4H.js.map +0 -1
  186. package/dist/chunk-B6SSXVF2.js.map +0 -1
  187. package/dist/chunk-BJHZHNKR.js +0 -93
  188. package/dist/chunk-BJHZHNKR.js.map +0 -1
  189. package/dist/chunk-DZCK7GRW.js.map +0 -1
  190. package/dist/chunk-HWTQ6HPO.js.map +0 -1
  191. package/dist/chunk-OUWNTFDG.js.map +0 -1
  192. package/dist/chunk-QM2TT2PJ.js +0 -385
  193. package/dist/chunk-QM2TT2PJ.js.map +0 -1
  194. package/dist/chunk-X57AMTAH.js.map +0 -1
  195. package/dist/ensure-sources-CHC7X7AJ.js.map +0 -1
  196. package/dist/source-RXAHIGMD.js +0 -30
  197. package/dist/store-client-T3F663YG.js +0 -15
  198. package/dist/store-client-T3F663YG.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,331 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#346](https://github.com/skaile-ai/workspaces/pull/346) [`b878750`](https://github.com/skaile-ai/workspaces/commit/b878750cb8a99c317a074e88acad3f9e102b6df2) Thanks [@henkbla](https://github.com/henkbla)! - `runner`: carry an embedded app's `origin: {kind:'app', appId}` end-to-end instead of
8
+ relabelling it to `client`.
9
+
10
+ The platform gateway used to forward an app's capabilities to the runner relabelled as
11
+ `origin:'client'`, because the origin-trust guard rejected an `app` origin from any
12
+ source but a (non-existent) direct app connection. That relabel worked, but it erased
13
+ the app's identity before anything downstream could use it: the per-app audit slice the
14
+ design calls for was impossible, `ORIGIN_PROMPT_ORDER`'s `app` row and
15
+ `isUserInvokable`'s `app` row were unreachable, and the agent could not tell which app
16
+ owned which action.
17
+
18
+ **Trust-guard change.** `source: 'client'` may now declare `origin.kind: 'app'` as well
19
+ as `'client'`. The platform gateway is the only client peer; it binds every app
20
+ registration to the socket it arrived on before forwarding, and the runner cannot verify
21
+ an `appId` in any case. The guard that actually enforces something is unchanged and
22
+ still live: `source: 'agent'` may never claim an `app` origin, so a skill, connector, or
23
+ flow cannot impersonate an app.
24
+
25
+ **Audit.** A capability handler's logger is now built with an `appId`-qualified instance
26
+ for app origins: `capability:app:<appId>.<name>`. Exported as `capabilityLogInstance()`.
27
+
28
+ `side: 'app'` needs no separate dispatch path — `buildClientCapabilityHandler` already
29
+ round-trips the invocation to the platform, which routes it to the app connection.
30
+
31
+ **Compatibility.** A platform that forwards `app`-origin capabilities requires a runner
32
+ built from this version or later; an older runner drops them with an origin-mismatch
33
+ warning. The runner ships in the agent container image, so the image and the platform's
34
+ `@skaile/workspaces` pin must move together. No wire-type change — `origin.kind:'app'`
35
+ and `side:'app'` have been in the protocol since 3.4.0; this only widens who may declare
36
+ them.
37
+
38
+ ### Patch Changes
39
+
40
+ - [#342](https://github.com/skaile-ai/workspaces/pull/342) [`9b362db`](https://github.com/skaile-ai/workspaces/commit/9b362dbd33f58658caa1eed56278b4e2198783de) Thanks [@henkbla](https://github.com/henkbla)! - `runner`: `CapabilityRegistry.hydrate()` no longer restores embedded-app capabilities.
41
+
42
+ App capabilities are the app SDK's responsibility to re-register — it reconnects and
43
+ replays them on session resume. Hydrating them would leave the agent handler-less stubs
44
+ for an app whose back-connection is gone after a wake: tools it can see and never call.
45
+
46
+ The existing `origin.kind !== 'client'` skip could not catch them. The platform gateway
47
+ forwards an app's capabilities to the runner relabelled `origin:'client'`, so they look
48
+ like ordinary client capabilities by the time they reach the registry. `hydrate()` now
49
+ also skips the reserved `app.` namespace, which the gateway enforces on registration and
50
+ which therefore survives the relabel.
51
+
52
+ Latent fix: `serialize()` / `hydrate()` have no callers today (the runner does not yet
53
+ write a capability snapshot), so nothing changes at runtime. It closes the trap before
54
+ capability snapshotting lands.
55
+
56
+ ## 1.5.0
57
+
58
+ ### Minor Changes
59
+
60
+ - [#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.
61
+
62
+ The embedded app needs three things to open its back-connection — the gateway
63
+ URL, its `appId`, and a session identity token. The token is a credential, and
64
+ the preview surface that serves the app is unauthenticated, so it must not ride
65
+ in the iframe `src`. `resolveAppConnectionParams()` obtains it over
66
+ `postMessage` instead: the app posts a `skaile_app_ready` ping to its embedder
67
+ and awaits a `skaile_app_params` reply, with both sides pinning the peer on
68
+ `event.origin` **and** `event.source`. The app learns the expected host origin
69
+ from a non-secret `skaileParentOrigin` query param — safe to leak precisely
70
+ because it is not a credential. `"*"` and `"null"` host origins are refused: an
71
+ unpinnable peer defeats the point of keeping the token out of the URL.
72
+
73
+ `createWebSocketAppTransport` now accepts a `SessionTokenProvider` for
74
+ `sessionToken` as well as a bare string. The gateway's token is **single-use**
75
+ (consumed at `app_hello`), so a reconnecting transport cannot replay the one it
76
+ opened with; a provider mints a fresh token per attempt. A bare string still
77
+ opens the socket synchronously.
78
+
79
+ `createSkaileApp` gains a `reconnect` policy (default
80
+ `{maxAttempts:5, baseMs:1000, maxMs:30000}`, or `false` to disable). It rebinds
81
+ after a dropped socket and **replays its capability registry**, since the
82
+ gateway deregisters an app's capabilities when its connection closes. It also
83
+ retries a _retryable_ `app_hello_nack` — the app boots independently of the
84
+ session's agent container and can win that race. A permanent refusal (bad token,
85
+ `appId` not permitted) is never retried, because retrying only burns tokens.
86
+ `AppHelloNackMessage` gains an optional `retryable` field to carry that
87
+ distinction, and the SDK surfaces it as `AppHandshakeRefusedError.retryable`.
88
+ New `onSessionChange(handler)` fires on every bind — including the initial
89
+ `connect()` — and with `null` whenever the connection drops.
90
+
91
+ Behaviour change for `1.4.0` consumers: reconnect is **on by default**, so a
92
+ dropped socket now re-dials instead of leaving the app inert. Pass
93
+ `reconnect: false` for the old single-shot behaviour. Purely additive otherwise
94
+ — new exports, a widened `sessionToken` type, and one new optional wire field.
95
+
96
+ - [#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
97
+
98
+ Publish a git-backed library you own (in-repo `skaile.manifest.yaml`) to the
99
+ store: `library publish <lib>` commits + pushes the library repo, registers +
100
+ syncs it as a store source (no sidecar — the in-repo manifest drives discovery),
101
+ and publishes its assets under the manifest's own `publisher` (no namespace
102
+ remap). `--asset <ref>` narrows to one asset; `--create-repo` provisions + links
103
+ a public `github.com/<you>/<lib>` via `gh` when the library has no remote;
104
+ `--dry-run` prints an offline plan. `register` skips the commit/push (already on
105
+ GitHub); `yank` unpublishes. Requires a public git remote + `store login`.
106
+
107
+ Extracts the shared store-interaction core (`publish-core.ts` `publishToStore`)
108
+ reused by both `library publish` and `source manifest publish`, so the two
109
+ front-ends can't drift on the register → sync → candidates → per-asset publish
110
+ sequence.
111
+
112
+ - [#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.
113
+
114
+ **Sidecar authoring (`skaile source manifest init` / `edit` + overlay read + add).** You can
115
+ now curate assets from a foreign GitHub repo you don't control by authoring a
116
+ `skaile.manifest.yaml` stored _outside_ that repo, then consume + `add` them under a clean
117
+ curated publisher.
118
+
119
+ - `skaile source manifest init <src> [--publisher <name>] [--dev] [--force]` — clone (if
120
+ needed), run discovery, and write a curated manifest to the local store catalog at
121
+ `~/.skaile/store/manifests/<slug>.yaml`. Publisher defaults to the source's GitHub org.
122
+ Every asset inherits the top-level publisher (no per-asset path-segment stamp).
123
+ Idempotent (won't overwrite without `--force`).
124
+ - `skaile source manifest edit <src>` — open the curated manifest in `$EDITOR` and
125
+ re-validate on save (warnings surfaced, never a hard fail).
126
+ - `skaile source add` / `source sync` apply the curated manifest as a **read overlay**:
127
+ the curated publisher + asset inventory win over raw glob discovery. `LocalCatalogSource`
128
+ gained a `sidecarManifestFile` option; discovery gained `loadMergedSourceConfigFromFile`
129
+ - a `sidecarManifestFile` discovery option; the library gained `writeCuratedManifest`.
130
+ - `skaile add` now resolves the curated publisher too: the provenance walker
131
+ (`buildProvenanceIndex`) reads the same curated store overlay (via a new
132
+ `SourceClone.overlayManifestPath`), so the ref `search --local` displays
133
+ (`skill:@lark/…`) is the ref `add` accepts and deploys.
134
+ - Store manifests are keyed by a collision-free `storeManifestSlug(url)`
135
+ (`<host>__<owner>__<repo>`), so two repos sharing a trailing name (`orgA/cli`,
136
+ `orgB/cli`) no longer collide on `cli.yaml`.
137
+
138
+ **Bug fix — publisher normalization (glob AND manifest paths).** Discovery stored
139
+ publishers _with_ a leading `@`, which the local ref formatter doubled into `@@scripts`
140
+ (glob) / made `@lark` assets un-addable (manifest/curated overlay). `DiscoveredAsset.publisher`
141
+ is now **bare** on every discovery path (glob + manifest, local-FS + virtual-tree), unifying
142
+ them; the single `@` scope sigil is re-added by the ref formatter, and refs carry exactly
143
+ one `@` across both modes. The internal `SourceConfig` layer (`publisher_default` /
144
+ `atPublisher`) is unchanged — the `@`-prefix is correct there.
145
+
146
+ **Bug fix — `search --local` reads the index (and unions the factory source).** It now
147
+ reads the index (`asset_definitions` via `listAssetDefs`) instead of re-scanning the repo
148
+ tree, so its result set and count match exactly what `source add`/`sync` wrote — no scanner
149
+ `kind:name` dedup collapsing same-named or multi-kind assets — and unions the bundled
150
+ first-party factory source (never indexed) so built-in skills still appear in a fresh
151
+ project.
152
+
153
+ - [#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
154
+
155
+ `source manifest publish <src>` takes a locally-curated sidecar manifest (over a
156
+ foreign **public** GitHub repo), pushes it to a public "sidecar" repo you own,
157
+ then registers + syncs the source with the store and publishes each curated asset
158
+ under your namespace (default: your store username; `--as <ns>` to override, e.g.
159
+ a GitHub org you belong to). `--dry-run` prints an offline plan (no push, no store
160
+ calls). `yank` unpublishes the source's published assets; `propose` stays a stub.
161
+
162
+ Requires the store's self-service `sources.add` sidecar support (skaile-store#79)
163
+ and a deployed store backend. Mono-repo sidecars (`sidecar_path`) are a documented
164
+ follow-up.
165
+
166
+ - [#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`,
167
+ extend the init test-fixture filter, and fix key-aware legacy clone migration.
168
+
169
+ - **`source manifest rebuild <src>` (new verb).** Refreshes a curated manifest
170
+ after the upstream repo changed. **Merge is the default — curation is sacred:**
171
+ it updates the clone (`git pull --ff-only`, best-effort), re-runs discovery,
172
+ and matches existing↔discovered entries by repo-relative `root` path. Existing
173
+ entries whose root is still present are KEPT verbatim (all hand-edits
174
+ preserved: publisher, per-asset name/version/description); entries whose root
175
+ is gone upstream are DROPPED and reported (`removed (gone upstream): …`).
176
+ Freshly-discovered assets not already curated are NOT auto-added — they are
177
+ reported (`N new upstream asset(s) available (not added): … — add with
178
+ \`skaile source manifest edit\``), so a curated foreign-repo sidecar never
179
+ silently absorbs new upstream skills, and an asset the curator deliberately
180
+ dropped stays dropped. Writes only when something changed (else `already up to
181
+ date`). `--overwrite`re-scans the full inventory with`init --force`
182
+ semantics, warning that curation is replaced.
183
+ - **`source manifest verify <src>` (new verb), read-only.** Checks each manifest
184
+ asset against the clone: `root`/`files` paths still exist upstream (missing →
185
+ error); a declared `sha256` on a **`files:` entry** recomputes to the same
186
+ deterministic composite hash (mismatch → error) — hashed exactly as discovery
187
+ does (repo-root anchored, files verbatim as repo-relative strings), so a
188
+ correctly-pinned hash verifies clean; a declared `sha256` on a `root:` entry is
189
+ **skipped with a warning** (discovery hashes only the per-kind filtered set, so
190
+ a whole-dir recompute would false-mismatch, and the writer never emits sha256
191
+ for `root:` entries); schema decodes cleanly (`decodeSkaileManifest`
192
+ diagnostics → warnings/errors); dependency refs parse (`parseAssetRef`;
193
+ malformed → warning). Prints a summary and exits 0 when there are no errors;
194
+ `--strict` forces a nonzero exit if there are any warnings. Writes nothing.
195
+ - **Extended init/rebuild test-fixture filter.** In addition to
196
+ `tests`/`test`/`__tests__`, the filter now also drops assets whose
197
+ repo-relative root contains a `testdata`, `fixtures`, or `__fixtures__` path
198
+ SEGMENT (exact segment), catching leaks like
199
+ `internal/qualitygate/skillscan/testdata/skills/lark-demo`. `init`/`rebuild`
200
+ path only; the general discovery walk (`source add`) is untouched.
201
+ - **Key-aware legacy clone migration.** `getGlobalCacheDir()` migration of a
202
+ legacy `~/.skaile/sources/<bare-name>` clone now re-derives the clone's true
203
+ cache key from its `origin` remote and lands it at
204
+ `<cacheRoot>/sources/<host>/<owner>/<repo>` (was: preserved the bare name, so a
205
+ URL-keyed lookup missed it and it lingered mis-placed). Non-clone leftovers
206
+ (the sidecar remainder) are untouched. New `mergeLegacyEntriesKeyed` primitive
207
+ in `@skaile/workspaces/core`.
208
+
209
+ `publish` / `propose` / `yank` remain stubs (they need the store publish
210
+ endpoint).
211
+
212
+ - [#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
213
+
214
+ The CLI's store auth was broken against the deployed store: the default URL
215
+ (`store.skaile.ai`) is dead and the old `/api/auth/*` login endpoints return 404.
216
+ `store login` now runs the Keycloak Device Authorization Grant (RFC 8628) against
217
+ `SKAILE_KEYCLOAK_URL` (default `https://auth.skaile.ai`, realm `skaile-store`,
218
+ public client `skaile-store-cli`) — it prints a URL + code to approve in a
219
+ browser, caches the token at `~/.skaile/auth.json` (shared with `store/cli`), and
220
+ refreshes transparently. The default store API URL is now `https://api.skaile.store`;
221
+ `whoami` reads `/api/v1/me`; every `/api/v1/*` publisher call authorizes with a
222
+ fresh device-flow token. Overridable via `SKAILE_STORE_URL` / `SKAILE_KEYCLOAK_URL`
223
+ / `SKAILE_STORE_REALM` / `SKAILE_STORE_CLI_CLIENT`.
224
+
225
+ Note: live login requires a public `skaile-store-cli` client (device-grant
226
+ enabled) registered on the store's Keycloak realm.
227
+
228
+ ### Patch Changes
229
+
230
+ - [#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:
231
+
232
+ - `skaile run "<prompt>"` no longer crashes with a raw `spawn omp ENOENT` when the
233
+ configured driver's binary is missing. The single-shot chat path now catches the
234
+ failure and prints the bridge's actionable hint (the binary is not installed /
235
+ not on PATH) plus a suggestion to try `--driver claude-sdk`; unrelated errors
236
+ still surface their own message and a non-zero exit.
237
+ - `skaile source add` warns about a missing `sha256` by pointing at the real
238
+ `skaile source manifest rebuild` command instead of the non-existent
239
+ `skaile source build-manifest --write`.
240
+ - `skaile source remove` (without `--purge`) now tells the user how to reclaim the
241
+ leftover clone — pass `--purge` or run `skaile cache clean`.
242
+ - `skaile install <ref>` (pointer-only global install) adds a clarifying line that
243
+ it installed globally under `~/.skaile/libraries/installed/`, and that
244
+ `skaile add <ref>` is how to deploy the asset into the current project.
245
+
246
+ - [#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
247
+ spurious "required" warning for a required placeholder with no default (that is
248
+ exactly what `export --redact` produces — required-ness is enforced at apply, not
249
+ validate); `skaile init` next-steps now suggests `preset apply`; and the apply
250
+ env-var hint points users to `.env`/shell (not skaile.yaml) so a first-time user
251
+ applying a shared preset knows where the secret value goes.
252
+
253
+ - [#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
254
+ goes through the shared catalog client (tRPC to `skaile.store`) instead of the dead
255
+ `store.skaile.ai` REST endpoint, surfaces `catalog.url: local` and failures
256
+ non-silently, and prints copyable `kind:@publisher/name#version` refs for both store
257
+ and local results.
258
+
259
+ - [#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.
260
+
261
+ Since `source manifest init` stopped writing per-asset `sha256` for `root:`
262
+ entries, `skaile source add` / `source sync` printed one
263
+ `Missing sha256 — computed <hash> …` advisory line per asset. For a curated
264
+ overlay with dozens of assets that was pure noise.
265
+
266
+ Discovery now tags each absent-sha256 warning with a machine-readable
267
+ `code: "missing_sha256"` (on `ReferenceWarning`) instead of relying on the
268
+ message text, and `LocalCatalogSource.sync()` counts those and emits exactly
269
+ one collapsed advisory:
270
+ `<n> asset(s): sha256 not pinned — auto-computed locally (pin only for store publish)`.
271
+ All other advisories (e.g. unknown-kind ghost-install) still print individually.
272
+ The fatal `ManifestHashMismatch` path for a DECLARED-but-wrong sha256 is
273
+ unchanged.
274
+
275
+ - [#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
276
+ authoring flow, found consuming `github.com/larksuite/cli`.
277
+
278
+ - **`init` no longer writes per-asset `sha256`.** The init writer emitted the
279
+ discovery `sha256` (computed over the FILTERED per-kind file set) on each
280
+ `root:` entry; `source add` then re-walked the WHOLE root dir → a different
281
+ file set → a different composite hash → `ManifestHashMismatch`, failing every
282
+ asset. `init` now omits `sha256` for `root:`-mode entries (a missing hash is a
283
+ non-fatal advisory), so `source add` on init output indexes cleanly with zero
284
+ hash mismatches.
285
+ - **`init` skips test-fixture directories.** Assets whose repo-relative `root`
286
+ contains a `tests` / `test` / `__tests__` path segment are dropped from the
287
+ generated manifest (conservative, not repo-specific) so fixture "skills"
288
+ (`scripts/*/tests/*`, `tests/cli_e2e/*`) don't pollute the curated inventory.
289
+ `init`-path only; the general discovery walk (`source add`) is untouched.
290
+ - **`init` next-step hint prints a runnable command; `edit` accepts the store
291
+ slug.** The hint now echoes the exact `<src>` the user passed (the URL) instead
292
+ of a bare short name that mis-expanded to the skaile-ai org. `resolveSourceArg`
293
+ additionally accepts the collision-free store slug (`<host>__<owner>__<repo>`)
294
+ as an identifier, matched against existing `~/.skaile/store/manifests/<arg>.yaml`
295
+ before bare-name expansion. Full-URL resolution still works.
296
+ - **`edit` respects a full `$EDITOR` command.** `EDITOR="code --wait"` now spawns
297
+ `code` with args `["--wait", <file>]` (was treated as one binary and failed).
298
+ New `resolveEditorCommand` splits the editor value on whitespace and appends
299
+ the target last; unset falls back to `vi`.
300
+ - **`preset export` warns on machine-local sidecar overlays.** When a captured
301
+ source resolves through a curated store manifest on this machine, export now
302
+ warns that those assets may not resolve elsewhere until the sidecar is shared.
303
+
304
+ - [#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
305
+ `skaile.manifest.yaml`, added via `skaile source add`, deployed via `skaile add`):
306
+
307
+ - **P-A — publisher `@` normalization.** A manifest declaring `publisher: '@acme'`
308
+ is now stored as `acme` (the leading `@` is the scope sigil the ref formatter
309
+ adds automatically). Previously it indexed as `@@acme` and the asset was
310
+ un-addable. Both manifest read paths are covered: `decodeSkaileManifest` (index
311
+ side, emits a `warning` diagnostic) **and** `resolveSourcePublisher` / `scanRepo`
312
+ (the `skaile search --local` scan/display side, which previously rendered the
313
+ copyable ref as `@@acme`). Only a single leading `@` is stripped; bare names are
314
+ untouched.
315
+ - **P-B — missing `sha256` is an advisory, not an indexing failure.** A manifest
316
+ asset with no `sha256` (and an unknown asset kind) now flows through the
317
+ discovery `warnings` channel and surfaces as an `advisory` on
318
+ `LocalCatalogSource.sync()` — never on `errors`. `skaile source add` /
319
+ `source sync` no longer report a false "N asset(s) failed to index" or exit 1
320
+ in this case; the asset is indexed and deployable, and the advisory is printed
321
+ on its own info line.
322
+ - **P-C — dead command pointer removed.** The missing-`sha256` advisory no longer
323
+ points at the not-wired `skaile source manifest rebuild` stub; it now reads
324
+ "only needed for store publish; auto-computed locally".
325
+ - **P-E — search kind-miss message.** `skaile search <kind>` with no matches now
326
+ says `No "<kind>" assets found in this project's sources.` instead of the
327
+ misleading never-synced `Run \`skaile source sync\` first` hint.
328
+
3
329
  ## 1.4.0
4
330
 
5
331
  ### Minor Changes