@skaile/workspaces 0.43.0 → 0.44.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 (160) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/{asset-feeds-3PSV57NT.js → asset-feeds-EGSG4FUB.js} +15 -11
  3. package/dist/asset-feeds-EGSG4FUB.js.map +1 -0
  4. package/dist/asset-manager/index.js +5 -5
  5. package/dist/asset-manager/installer.js +4 -4
  6. package/dist/asset-manager/src/index.d.ts +102 -4
  7. package/dist/asset-manager/src/index.d.ts.map +1 -1
  8. package/dist/{chunk-XMKBIVG3.js → chunk-5LHPKVGR.js} +9 -9
  9. package/dist/{chunk-XMKBIVG3.js.map → chunk-5LHPKVGR.js.map} +1 -1
  10. package/dist/{chunk-4UTJNFUS.js → chunk-7NQXVBCQ.js} +5 -5
  11. package/dist/{chunk-4UTJNFUS.js.map → chunk-7NQXVBCQ.js.map} +1 -1
  12. package/dist/{chunk-KYQNWFJV.js → chunk-BLGHFVXE.js} +3 -3
  13. package/dist/{chunk-KYQNWFJV.js.map → chunk-BLGHFVXE.js.map} +1 -1
  14. package/dist/{chunk-R4H6EJW5.js → chunk-CBZEIFU4.js} +3 -3
  15. package/dist/{chunk-R4H6EJW5.js.map → chunk-CBZEIFU4.js.map} +1 -1
  16. package/dist/{chunk-GJI6FZ56.js → chunk-COSTF7QW.js} +60 -8
  17. package/dist/chunk-COSTF7QW.js.map +1 -0
  18. package/dist/{chunk-NYMRKIOR.js → chunk-CVWA4RIK.js} +4 -4
  19. package/dist/{chunk-NYMRKIOR.js.map → chunk-CVWA4RIK.js.map} +1 -1
  20. package/dist/{chunk-BXYMGZCI.js → chunk-ETDXTGDF.js} +3 -3
  21. package/dist/{chunk-BXYMGZCI.js.map → chunk-ETDXTGDF.js.map} +1 -1
  22. package/dist/{chunk-TDSRLMDB.js → chunk-EVZKWY5J.js} +2 -2
  23. package/dist/chunk-EVZKWY5J.js.map +1 -0
  24. package/dist/{chunk-3HUUP3JC.js → chunk-FYLIR4AV.js} +107 -7
  25. package/dist/chunk-FYLIR4AV.js.map +1 -0
  26. package/dist/{chunk-G6FJZG4C.js → chunk-GM3BV6JK.js} +2 -2
  27. package/dist/{chunk-G6FJZG4C.js.map → chunk-GM3BV6JK.js.map} +1 -1
  28. package/dist/{chunk-R2SKIYU2.js → chunk-JUZLVRI4.js} +265 -38
  29. package/dist/chunk-JUZLVRI4.js.map +1 -0
  30. package/dist/{chunk-F5Q2RMH4.js → chunk-LMRO2QNF.js} +177 -135
  31. package/dist/chunk-LMRO2QNF.js.map +1 -0
  32. package/dist/{chunk-JZQFZ55W.js → chunk-NHLXS2CH.js} +2 -2
  33. package/dist/{chunk-JZQFZ55W.js.map → chunk-NHLXS2CH.js.map} +1 -1
  34. package/dist/{chunk-CIEKKLMG.js → chunk-PCXU2CVW.js} +3 -3
  35. package/dist/{chunk-CIEKKLMG.js.map → chunk-PCXU2CVW.js.map} +1 -1
  36. package/dist/{chunk-HVCZLD5Z.js → chunk-VPXV2Z5E.js} +5 -7
  37. package/dist/chunk-VPXV2Z5E.js.map +1 -0
  38. package/dist/{chunk-2BEDUMTA.js → chunk-XF2BBX6P.js} +3 -3
  39. package/dist/{chunk-2BEDUMTA.js.map → chunk-XF2BBX6P.js.map} +1 -1
  40. package/dist/{chunk-3K2CYDBT.js → chunk-Z5Z3MYDL.js} +8 -4
  41. package/dist/chunk-Z5Z3MYDL.js.map +1 -0
  42. package/dist/{chunk-M54RYUXY.js → chunk-ZAEJ33Y6.js} +19 -7
  43. package/dist/chunk-ZAEJ33Y6.js.map +1 -0
  44. package/dist/cli/index.js +395 -286
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  47. package/dist/cli/src/commands/cache.d.ts +27 -0
  48. package/dist/cli/src/commands/cache.d.ts.map +1 -0
  49. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  50. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  51. package/dist/cli/src/commands/npx.d.ts +1 -1
  52. package/dist/cli/src/commands/source.d.ts +3 -1
  53. package/dist/cli/src/commands/source.d.ts.map +1 -1
  54. package/dist/cli/src/commands/update.d.ts +1 -1
  55. package/dist/cli/src/ensure-sources.d.ts +2 -2
  56. package/dist/cli/src/ensure-sources.d.ts.map +1 -1
  57. package/dist/connectors/config.js +4 -4
  58. package/dist/connectors/index.js +6 -6
  59. package/dist/connectors/rclone.js +1 -1
  60. package/dist/connectors/src/connector-manager.d.ts +21 -4
  61. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  62. package/dist/connectors/src/fleet-health-gate.d.ts +2 -0
  63. package/dist/connectors/src/fleet-health-gate.d.ts.map +1 -1
  64. package/dist/connectors/src/fleet-utils.d.ts +10 -0
  65. package/dist/connectors/src/fleet-utils.d.ts.map +1 -1
  66. package/dist/connectors/src/mount-placeholder.d.ts +11 -0
  67. package/dist/connectors/src/mount-placeholder.d.ts.map +1 -1
  68. package/dist/connectors/src/rclone-process-manager.d.ts +57 -2
  69. package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -1
  70. package/dist/core/index.js +3 -3
  71. package/dist/core/runtime-assets.js +2 -2
  72. package/dist/core/src/cache-paths.d.ts +25 -0
  73. package/dist/core/src/cache-paths.d.ts.map +1 -0
  74. package/dist/core/src/index.d.ts +1 -0
  75. package/dist/core/src/index.d.ts.map +1 -1
  76. package/dist/core/src/repo-manager.d.ts +11 -8
  77. package/dist/core/src/repo-manager.d.ts.map +1 -1
  78. package/dist/core/src/runtime-assets.d.ts.map +1 -1
  79. package/dist/core/src/workspace-config.d.ts +2 -2
  80. package/dist/core/src/workspace-config.d.ts.map +1 -1
  81. package/dist/core/workspace-config.js +1 -1
  82. package/dist/deploy/index.js +3 -3
  83. package/dist/{ensure-sources-VQDZB7NT.js → ensure-sources-NSDMTAWN.js} +6 -12
  84. package/dist/ensure-sources-NSDMTAWN.js.map +1 -0
  85. package/dist/factory-assets/connectors/deploy.js +6 -6
  86. package/dist/factory-assets/connectors/devserver.js +6 -6
  87. package/dist/factory-assets/connectors/flow/adapter.js +6 -6
  88. package/dist/factory-assets/connectors/flow/engine.js +3 -3
  89. package/dist/factory-assets/connectors/flow/run-flow.js +7 -7
  90. package/dist/factory-assets/connectors/flow.js +6 -6
  91. package/dist/factory-assets/connectors/git.js +6 -6
  92. package/dist/factory-assets/connectors/gmail.js +6 -6
  93. package/dist/factory-assets/connectors/googledrive.js +6 -6
  94. package/dist/factory-assets/connectors/local.js +6 -6
  95. package/dist/factory-assets/connectors/mattermost.js +6 -6
  96. package/dist/factory-assets/connectors/memory.js +6 -6
  97. package/dist/factory-assets/connectors/minio.js +6 -6
  98. package/dist/factory-assets/connectors/postgres.js +6 -6
  99. package/dist/factory-assets/connectors/s3.js +6 -6
  100. package/dist/factory-assets/connectors/sharepoint.js +6 -6
  101. package/dist/factory-assets/connectors/sqlite.js +6 -6
  102. package/dist/factory-assets/connectors/static-server.js +6 -6
  103. package/dist/factory-assets/connectors/tunnel.js +6 -6
  104. package/dist/factory-assets/connectors/webdav.js +6 -6
  105. package/dist/factory-assets/connectors/xstate-store.js +6 -6
  106. package/dist/factory-assets/connectors/xstate.js +6 -6
  107. package/dist/{flows-KTBCZ5GQ.js → flows-WELXQ7IG.js} +3 -3
  108. package/dist/{flows-KTBCZ5GQ.js.map → flows-WELXQ7IG.js.map} +1 -1
  109. package/dist/library/index.js +4 -4
  110. package/dist/library/install.js +3 -3
  111. package/dist/library/src/local/local-catalog-source.d.ts +1 -1
  112. package/dist/library/src/local/sidecar-git.d.ts +2 -2
  113. package/dist/library/src/local/sidecar-paths.d.ts +12 -10
  114. package/dist/library/src/local/sidecar-paths.d.ts.map +1 -1
  115. package/dist/library/src/local/store-paths.d.ts +2 -2
  116. package/dist/library/src/remote/cache.d.ts +8 -2
  117. package/dist/library/src/remote/cache.d.ts.map +1 -1
  118. package/dist/library/src/remote/remote-catalog-source.d.ts +1 -1
  119. package/dist/library/src/remote/rest-catalog-source.d.ts +1 -1
  120. package/dist/{open-library-FHUXOCN7.js → open-library-362BZ6OW.js} +7 -7
  121. package/dist/{open-library-FHUXOCN7.js.map → open-library-362BZ6OW.js.map} +1 -1
  122. package/dist/{paths-7H5CSBLQ.js → paths-4SSFMX5Z.js} +6 -6
  123. package/dist/{paths-7H5CSBLQ.js.map → paths-4SSFMX5Z.js.map} +1 -1
  124. package/dist/{plugin-store-LGLN2QUX.js → plugin-store-RBCDBO7K.js} +5 -5
  125. package/dist/{plugin-store-LGLN2QUX.js.map → plugin-store-RBCDBO7K.js.map} +1 -1
  126. package/dist/runner/index.js +9 -9
  127. package/dist/sdk/asset-manager.js +5 -5
  128. package/dist/sdk/core.js +3 -3
  129. package/dist/sdk/flow.js +3 -3
  130. package/dist/sdk/index.js +9 -9
  131. package/dist/sdk/runner.js +9 -9
  132. package/dist/sdk/session.js +2 -2
  133. package/dist/sdk/types.js +1 -1
  134. package/dist/session/index.js +2 -2
  135. package/dist/session/src/index.d.ts +1 -1
  136. package/dist/session/src/index.d.ts.map +1 -1
  137. package/dist/session/src/mentions.d.ts +11 -0
  138. package/dist/session/src/mentions.d.ts.map +1 -1
  139. package/dist/{setup-EVNPECSY.js → setup-VGZTFQ32.js} +5 -5
  140. package/dist/{setup-EVNPECSY.js.map → setup-VGZTFQ32.js.map} +1 -1
  141. package/dist/{store-client-4XN7IB3R.js → store-client-XFZFKY3W.js} +6 -6
  142. package/dist/{store-client-4XN7IB3R.js.map → store-client-XFZFKY3W.js.map} +1 -1
  143. package/dist/tui/index.js +9 -9
  144. package/dist/types/index.js +1 -1
  145. package/dist/types/src/mentions.d.ts +12 -0
  146. package/dist/types/src/mentions.d.ts.map +1 -1
  147. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  148. package/dist/workspace-plugin/adapters/omp.js +3 -3
  149. package/dist/workspace-plugin/index.js +1 -1
  150. package/package.json +1 -1
  151. package/dist/asset-feeds-3PSV57NT.js.map +0 -1
  152. package/dist/chunk-3HUUP3JC.js.map +0 -1
  153. package/dist/chunk-3K2CYDBT.js.map +0 -1
  154. package/dist/chunk-F5Q2RMH4.js.map +0 -1
  155. package/dist/chunk-GJI6FZ56.js.map +0 -1
  156. package/dist/chunk-HVCZLD5Z.js.map +0 -1
  157. package/dist/chunk-M54RYUXY.js.map +0 -1
  158. package/dist/chunk-R2SKIYU2.js.map +0 -1
  159. package/dist/chunk-TDSRLMDB.js.map +0 -1
  160. package/dist/ensure-sources-VQDZB7NT.js.map +0 -1
@@ -1,15 +1,14 @@
1
- import { deployAll, removeAsset, createScaffold } from './chunk-NYMRKIOR.js';
2
- import { writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-KYQNWFJV.js';
3
- import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-HVCZLD5Z.js';
4
- import { resolveSkWorkspaceConfig, getRepoCommit, buildProvenanceIndex, resolveAll, ensureRepo, scanRepo, checkRepoStatus, resolveAsset, readLinks, getGlobalCacheDir } from './chunk-GJI6FZ56.js';
1
+ import { deployAll, removeAsset, createScaffold } from './chunk-CVWA4RIK.js';
2
+ import { writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-BLGHFVXE.js';
3
+ import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-VPXV2Z5E.js';
4
+ import { migrateLegacyDir, resolveSkWorkspaceConfig, getGlobalCacheDir, getRepoCommit, resolveAll, buildProvenanceIndex, ensureRepo, scanRepo, checkRepoStatus, resolveAsset, readLinks } from './chunk-COSTF7QW.js';
5
5
  import { parseAssetRef } from './chunk-GEEW6SY2.js';
6
6
  import { deployedBase, isDeployed, deployedDir } from './chunk-XGCXFX7X.js';
7
7
  import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
8
8
  import { commitChanges } from './chunk-UQ6LFBPZ.js';
9
9
  import { spawnSync } from 'child_process';
10
10
  import { existsSync, readdirSync, rmSync, lstatSync, unlinkSync, readFileSync, writeFileSync } from 'fs';
11
- import { homedir } from 'os';
12
- import { resolve, join, dirname } from 'path';
11
+ import { resolve, join, sep, dirname } from 'path';
13
12
  import { parse, stringify } from 'yaml';
14
13
 
15
14
  function sourceSlug(url) {
@@ -18,6 +17,46 @@ function sourceSlug(url) {
18
17
  function normalizeRepoUrl(url) {
19
18
  return url.trim().replace(/^git@([^:]+):/, "https://$1/").replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
20
19
  }
20
+ var MD_BY_KIND = {
21
+ skill: "SKILL.md",
22
+ agent: "AGENT.md",
23
+ bundle: "BUNDLE.md",
24
+ "mcp-server": "MCP.md",
25
+ connector: "CONNECTOR.md",
26
+ prompt: "PROMPT.md",
27
+ contract: "CONTRACT.md"
28
+ };
29
+ function matchManifestPath(kind, paths) {
30
+ const exact = MD_BY_KIND[kind];
31
+ if (exact) {
32
+ const hit = paths.find((p) => p.endsWith(exact));
33
+ if (hit) return hit;
34
+ }
35
+ if (kind === "prompt") return paths.find((p) => p.endsWith(".prompt.md"));
36
+ if (kind === "flow") {
37
+ return paths.find((p) => p.endsWith(".flow.yaml") || p.endsWith(".flow.json"));
38
+ }
39
+ return void 0;
40
+ }
41
+ var NON_DEPLOYABLE_KINDS = /* @__PURE__ */ new Set([
42
+ "bundle",
43
+ "mcp-server",
44
+ "persona",
45
+ "ruleset",
46
+ "knowledge"
47
+ ]);
48
+ function commonDirPrefix(paths) {
49
+ if (paths.length === 0) return "";
50
+ const dirs = paths.map((p) => p.split("/").slice(0, -1));
51
+ let common = dirs[0];
52
+ for (let i = 1; i < dirs.length && common.length > 0; i++) {
53
+ const segs = dirs[i];
54
+ let n = 0;
55
+ while (n < common.length && n < segs.length && common[n] === segs[n]) n++;
56
+ common = common.slice(0, n);
57
+ }
58
+ return common.join("/");
59
+ }
21
60
  function indexLockByKindName(lock) {
22
61
  const lockByKindName = /* @__PURE__ */ new Map();
23
62
  for (const [key] of Object.entries(lock?.assets ?? {})) {
@@ -99,13 +138,39 @@ var AssetManager = class {
99
138
  driverTarget;
100
139
  /** Whether this instance operates in global-install mode. */
101
140
  global;
141
+ /** Injected catalog fetcher (tests / custom); falls back to a built one. */
142
+ injectedStoreFetcher;
143
+ /** Injected byte fetcher for store staging; falls back to GitHub. */
144
+ injectedAssetFetcher;
145
+ /** Injected global catalog URL override for the no-project-store fallback. */
146
+ catalogUrlOverride;
102
147
  constructor(opts) {
103
148
  this.projectDir = resolve(opts.projectDir);
104
149
  this.driverTarget = opts.driverTarget ?? "claude-code";
105
150
  this.global = opts.global ?? false;
151
+ this.injectedStoreFetcher = opts.storeFetcher;
152
+ this.injectedAssetFetcher = opts.assetFetcher;
153
+ this.catalogUrlOverride = opts.catalogUrl;
154
+ }
155
+ get storeCacheDir() {
156
+ return migrateLegacyDir(
157
+ join(this.projectDir, ".skaile", "cache", "store"),
158
+ join(this.projectDir, ".skaile", "store-cache")
159
+ );
106
160
  }
107
161
  get reposDir() {
108
- return join(this.projectDir, ".skaile", "repos");
162
+ return migrateLegacyDir(
163
+ join(this.projectDir, ".skaile", "cache", "sources"),
164
+ join(this.projectDir, ".skaile", "repos")
165
+ );
166
+ }
167
+ /**
168
+ * Project-scoped cache dirs rooted at `.skaile/cache/` (`store`, `sources`)
169
+ * relative to `projectDir`. Reading is a side effect: it triggers lazy
170
+ * migration of the legacy `.skaile/{store-cache,repos}` dirs.
171
+ */
172
+ get projectCacheDirs() {
173
+ return { store: this.storeCacheDir, sources: this.reposDir };
109
174
  }
110
175
  get lockPath() {
111
176
  return join(this.projectDir, "skaile.lock.yaml");
@@ -123,8 +188,7 @@ var AssetManager = class {
123
188
  const dependencies = config.dependencies ?? [];
124
189
  const overrides = config.overrides ?? [];
125
190
  const patches = config.patches ?? {};
126
- const skaileHome = process.env.SKAILE_HOME ?? join(homedir(), ".skaile");
127
- const sourcesDir = join(skaileHome, "sources");
191
+ const sourcesDir = getGlobalCacheDir();
128
192
  const repositories = {};
129
193
  for (const s of sources) {
130
194
  const slug = sourceSlug(s.url);
@@ -185,15 +249,6 @@ var AssetManager = class {
185
249
  }
186
250
  }
187
251
  if (!cloneDir || !slug) return null;
188
- const MD_BY_KIND = {
189
- skill: "SKILL.md",
190
- agent: "AGENT.md",
191
- bundle: "BUNDLE.md",
192
- "mcp-server": "MCP.md",
193
- connector: "CONNECTOR.md",
194
- prompt: "PROMPT.md",
195
- contract: "CONTRACT.md"
196
- };
197
252
  const mdName = MD_BY_KIND[c.kind];
198
253
  const mdRel = c.files.find((f) => mdName ? f.path.endsWith(mdName) : false)?.path;
199
254
  const source = mdRel ? join(cloneDir, mdRel) : cloneDir;
@@ -215,6 +270,184 @@ var AssetManager = class {
215
270
  if (c.homepage != null) entry.homepage = c.homepage;
216
271
  return entry;
217
272
  }
273
+ // ── Store fetch-then-deploy ────────────────────────────────────────────
274
+ /** A candidate's stable identity key (`<publisher>/<kind>:<name>@<version>`). */
275
+ candidateKey(c) {
276
+ return `${c.publisher}/${c.kind}:${c.name}@${c.version}`;
277
+ }
278
+ /**
279
+ * Resolve `deps`, falling back to the global `catalog.url` store when the
280
+ * project declares no store and the first pass leaves something missing.
281
+ *
282
+ * The first pass uses the project stores only, so locally-resolvable refs
283
+ * never trigger a network probe. The fallback retry is best-effort: any error
284
+ * (offline, store down) keeps the first pass's result rather than regressing.
285
+ */
286
+ async resolveWithStores(deps, opts) {
287
+ const first = await resolveAll(deps, {
288
+ provenanceIndex: opts.provenanceIndex,
289
+ overrides: opts.overrides,
290
+ stores: opts.stores,
291
+ storeFetcher: this.storeFetcherFor(opts.stores),
292
+ projectDir: this.projectDir
293
+ });
294
+ if (first.missing.length === 0) return first;
295
+ const fallback = await this.globalStoreFallback(opts.stores);
296
+ if (fallback.length === 0) return first;
297
+ const stores = [...opts.stores, ...fallback];
298
+ try {
299
+ const retry = await resolveAll(deps, {
300
+ provenanceIndex: opts.provenanceIndex,
301
+ overrides: opts.overrides,
302
+ stores,
303
+ storeFetcher: this.storeFetcherFor(stores),
304
+ projectDir: this.projectDir
305
+ });
306
+ return retry.missing.length < first.missing.length ? retry : first;
307
+ } catch {
308
+ return first;
309
+ }
310
+ }
311
+ /** The catalog fetcher to use: an injected one, else built from `stores`. */
312
+ storeFetcherFor(stores) {
313
+ return this.injectedStoreFetcher ?? this.buildStoreFetcher(stores);
314
+ }
315
+ /**
316
+ * The global `catalog.url` as a single-store fallback, or `[]` when no
317
+ * project store should be synthesized — `local` sentinel, already-declared,
318
+ * or no URL. Honours an explicit `catalogUrl` injection (`""` disables it).
319
+ */
320
+ async globalStoreFallback(projectStores) {
321
+ let url = this.catalogUrlOverride;
322
+ if (url === void 0) {
323
+ try {
324
+ const { resolveConfig } = await import('./library/index.js');
325
+ url = resolveConfig({ projectDir: this.projectDir }).catalog.url;
326
+ } catch {
327
+ return [];
328
+ }
329
+ }
330
+ if (!url || url.trim().toLowerCase() === "local") return [];
331
+ if (projectStores.some((s) => normalizeRepoUrl(s.url) === normalizeRepoUrl(url))) return [];
332
+ return [{ url }];
333
+ }
334
+ /**
335
+ * Build deployable catalog entries from resolved candidates. Store-resolved
336
+ * candidates (no local clone bytes) are fetched + SHA-verified into the
337
+ * project store-cache first, then their entry points at the staged bytes so
338
+ * the existing copy-deploy path works. Source-backed candidates keep the
339
+ * clone-relative entry.
340
+ */
341
+ async buildCatalogEntries(resolved, repositories) {
342
+ const staged = await this.stageStoreAssets(resolved, repositories);
343
+ const entries = [];
344
+ for (const c of resolved) {
345
+ const stagedPath = staged.get(this.candidateKey(c));
346
+ const entry = stagedPath ? this.stagedCandidateToEntry(c, stagedPath) : this.candidateToCatalogEntry(c, repositories);
347
+ if (entry) entries.push(entry);
348
+ }
349
+ return entries;
350
+ }
351
+ /**
352
+ * Fetch + SHA-verify the bytes of every store-resolved deployable candidate
353
+ * into `.skaile/cache/store/`, reusing the same verified-fetch path the
354
+ * pointer-only `library.install` uses (`installFromManifest` flat mode).
355
+ *
356
+ * @returns Map of candidate key → staged primary-manifest path.
357
+ */
358
+ async stageStoreAssets(resolved, repositories) {
359
+ const staged = /* @__PURE__ */ new Map();
360
+ let installFromManifest;
361
+ for (const c of resolved) {
362
+ if (NON_DEPLOYABLE_KINDS.has(c.kind)) continue;
363
+ if (!c.files || c.files.length === 0 || !c.sourceUrl || !c.commit) continue;
364
+ if (this.candidateHasLocalBytes(c, repositories)) continue;
365
+ if (!installFromManifest) {
366
+ ({ installFromManifest } = await import('./library/index.js'));
367
+ }
368
+ const targetDir = join(this.storeCacheDir, c.publisher, c.kind, c.name, c.version);
369
+ const cacheRoot = resolve(this.storeCacheDir);
370
+ if (!resolve(targetDir).startsWith(cacheRoot + sep)) {
371
+ throw new Error(`unsafe store-cache path for ${this.candidateKey(c)}`);
372
+ }
373
+ const manifest = {
374
+ ref: `${c.kind}:@${c.publisher}/${c.name}#${c.version}`,
375
+ source: { url: c.sourceUrl, commitSha: c.commit },
376
+ files: c.files,
377
+ sha256: c.sha256,
378
+ kind: c.kind,
379
+ // tier = catalog storage hint (S3/CDN); flat-mode verified fetch pulls
380
+ // from source.url@commit and ignores it, so "" is inert.
381
+ tier: ""
382
+ };
383
+ const { installPath } = await installFromManifest({
384
+ manifest,
385
+ libraryRoot: this.storeCacheDir,
386
+ targetDir,
387
+ fetcher: this.injectedAssetFetcher
388
+ });
389
+ staged.set(this.candidateKey(c), join(installPath, this.stagedManifestRel(c)));
390
+ }
391
+ return staged;
392
+ }
393
+ /** Repo-relative path of a candidate's primary manifest (un-stripped). */
394
+ primaryManifestRel(c) {
395
+ const paths = (c.files ?? []).map((f) => f.path);
396
+ return matchManifestPath(c.kind, paths) ?? paths[0];
397
+ }
398
+ /**
399
+ * The primary-manifest path relative to a staged asset dir. Takes the kind's
400
+ * manifest (e.g. `SKILL.md`), then strips the same common-dir prefix
401
+ * `installFromManifest` flat mode removed on write.
402
+ */
403
+ stagedManifestRel(c) {
404
+ const paths = (c.files ?? []).map((f) => f.path);
405
+ const mdRel = this.primaryManifestRel(c) ?? "";
406
+ const root = commonDirPrefix(paths);
407
+ return root && mdRel.startsWith(`${root}/`) ? mdRel.slice(root.length + 1) : mdRel;
408
+ }
409
+ /**
410
+ * `true` when a candidate's primary manifest is present on a local source
411
+ * clone — its `sourceUrl` matches a registered source AND the manifest file
412
+ * exists on disk at the expected path. A URL match alone is not enough: a
413
+ * store can pin a different commit (or a subtree not bundled) of a repo that
414
+ * is also a registered source, in which case the bytes must be fetched from
415
+ * the store rather than read from the clone. (Only the primary manifest is
416
+ * probed — a partially-cloned source is deployed as-is, matching the existing
417
+ * clone-deploy path.)
418
+ */
419
+ candidateHasLocalBytes(c, repositories) {
420
+ if (!c.sourceUrl) return false;
421
+ const rel = this.primaryManifestRel(c);
422
+ for (const [slug, decl] of Object.entries(repositories)) {
423
+ if (decl.url === void 0 || decl.url !== c.sourceUrl) continue;
424
+ const dir = this.resolveRepoDir(decl, slug);
425
+ if (!dir) continue;
426
+ if (existsSync(rel ? join(dir, rel) : dir)) return true;
427
+ }
428
+ return false;
429
+ }
430
+ /** Build a copy-deploy catalog entry pointing at staged store bytes. */
431
+ stagedCandidateToEntry(c, stagedManifestPath) {
432
+ const entry = {
433
+ name: c.name,
434
+ kind: c.kind,
435
+ description: c.description ?? "",
436
+ source: stagedManifestPath,
437
+ // Real publisher (never a clone slug) → deployAsset copies rather than
438
+ // symlinking the ephemeral store-cache dir.
439
+ publisher: c.publisher,
440
+ version: c.version,
441
+ requires: [],
442
+ dependencies: c.deps ?? [],
443
+ metadata: c.metadata
444
+ };
445
+ if (c.category != null) entry.category = c.category;
446
+ if (c.keywords && c.keywords.length > 0) entry.keywords = c.keywords;
447
+ if (c.license != null) entry.license = c.license;
448
+ if (c.homepage != null) entry.homepage = c.homepage;
449
+ return entry;
450
+ }
218
451
  // ── Install / resolve ──────────────────────────────────────────────────
219
452
  /**
220
453
  * Install all dependencies declared in `skaile.yaml`.
@@ -237,15 +470,13 @@ var AssetManager = class {
237
470
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
238
471
  projectDir: this.projectDir
239
472
  });
240
- const { resolved, missing, overridesApplied } = await resolveAll(dependencies, {
473
+ const { resolved, missing, overridesApplied } = await this.resolveWithStores(dependencies, {
241
474
  provenanceIndex,
242
475
  overrides,
243
- stores,
244
- storeFetcher: this.buildStoreFetcher(stores),
245
- projectDir: this.projectDir
476
+ stores
246
477
  });
247
478
  const removed = this.reconcileRemovedAssets(resolved);
248
- const entries = resolved.map((c) => this.candidateToCatalogEntry(c, repositories)).filter((e) => e !== null);
479
+ const entries = await this.buildCatalogEntries(resolved, repositories);
249
480
  const deployed = deployAll(entries, repositories, patches, this.deployOpts);
250
481
  writeLock(this.lockPath, buildLockFile(resolved, overridesApplied));
251
482
  this.recordInstallHistory(deployed, removed);
@@ -453,19 +684,17 @@ var AssetManager = class {
453
684
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
454
685
  projectDir: this.projectDir
455
686
  });
456
- const { resolved, missing } = await resolveAll([ref], {
687
+ const { resolved, missing } = await this.resolveWithStores([ref], {
457
688
  provenanceIndex,
458
689
  overrides,
459
- stores,
460
- storeFetcher: this.buildStoreFetcher(stores),
461
- projectDir: this.projectDir
690
+ stores
462
691
  });
463
692
  if (resolved.length === 0) {
464
693
  throw new Error(
465
694
  `Asset not found: ${ref}${missing.length ? ` (missing: ${missing.join(", ")})` : ""}`
466
695
  );
467
696
  }
468
- const entries = resolved.map((c) => this.candidateToCatalogEntry(c, repositories)).filter((e) => e !== null);
697
+ const entries = await this.buildCatalogEntries(resolved, repositories);
469
698
  const deployed = deployAll(entries, repositories, patches, this.deployOpts);
470
699
  this.addDependencyToConfig(ref);
471
700
  for (const d of deployed) {
@@ -739,12 +968,10 @@ var AssetManager = class {
739
968
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
740
969
  projectDir: this.projectDir
741
970
  });
742
- const { resolved, overridesApplied } = await resolveAll(dependencies, {
971
+ const { resolved, overridesApplied } = await this.resolveWithStores(dependencies, {
743
972
  provenanceIndex,
744
973
  overrides,
745
- stores,
746
- storeFetcher: this.buildStoreFetcher(stores),
747
- projectDir: this.projectDir
974
+ stores
748
975
  });
749
976
  const lockData = buildLockFile(resolved, overridesApplied);
750
977
  writeLock(this.lockPath, lockData);
@@ -911,8 +1138,8 @@ var AssetManager = class {
911
1138
  * Remove deployed assets tracked by the lock file and report unmanaged ones.
912
1139
  *
913
1140
  * With `opts.all`, also deletes `.skaile/history.yaml`, `.skaile/patches/`,
914
- * `.skaile/repos/`, and `skaile.lock.yaml` — effectively resetting the workspace
915
- * to a pre-install state.
1141
+ * `.skaile/cache/sources/`, and `skaile.lock.yaml` — effectively resetting the
1142
+ * workspace to a pre-install state.
916
1143
  *
917
1144
  * @param opts - Optional cleanup options.
918
1145
  * @param opts.all - When `true`, remove all Skaile-managed state in addition to deployed assets.
@@ -976,7 +1203,7 @@ var AssetManager = class {
976
1203
  }
977
1204
  return unmanaged;
978
1205
  }
979
- /** Delete all Skaile-managed state: history file, patches/, repos/, lock. */
1206
+ /** Delete all Skaile-managed state: history file, patches/, cache/sources/, lock. */
980
1207
  removeAllManagedState() {
981
1208
  const historyFile = join(this.projectDir, ".skaile", "history.yaml");
982
1209
  try {
@@ -1039,6 +1266,6 @@ var AssetManager = class {
1039
1266
  }
1040
1267
  };
1041
1268
 
1042
- export { AssetManager, parseCanonicalLockKey };
1043
- //# sourceMappingURL=chunk-R2SKIYU2.js.map
1044
- //# sourceMappingURL=chunk-R2SKIYU2.js.map
1269
+ export { AssetManager, NON_DEPLOYABLE_KINDS, parseCanonicalLockKey };
1270
+ //# sourceMappingURL=chunk-JUZLVRI4.js.map
1271
+ //# sourceMappingURL=chunk-JUZLVRI4.js.map