@skaile/workspaces 0.43.1 → 0.45.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 (163) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/{asset-feeds-3PSV57NT.js → asset-feeds-AOZLZMDV.js} +15 -11
  3. package/dist/asset-feeds-AOZLZMDV.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 +149 -4
  7. package/dist/asset-manager/src/index.d.ts.map +1 -1
  8. package/dist/{chunk-KYQNWFJV.js → chunk-BLGHFVXE.js} +3 -3
  9. package/dist/{chunk-KYQNWFJV.js.map → chunk-BLGHFVXE.js.map} +1 -1
  10. package/dist/{chunk-R4H6EJW5.js → chunk-CBZEIFU4.js} +3 -3
  11. package/dist/{chunk-R4H6EJW5.js.map → chunk-CBZEIFU4.js.map} +1 -1
  12. package/dist/{chunk-GJI6FZ56.js → chunk-COSTF7QW.js} +60 -8
  13. package/dist/chunk-COSTF7QW.js.map +1 -0
  14. package/dist/{chunk-NYMRKIOR.js → chunk-CVWA4RIK.js} +4 -4
  15. package/dist/{chunk-NYMRKIOR.js.map → chunk-CVWA4RIK.js.map} +1 -1
  16. package/dist/{chunk-BXYMGZCI.js → chunk-ETDXTGDF.js} +3 -3
  17. package/dist/{chunk-BXYMGZCI.js.map → chunk-ETDXTGDF.js.map} +1 -1
  18. package/dist/{chunk-TDSRLMDB.js → chunk-EVZKWY5J.js} +2 -2
  19. package/dist/chunk-EVZKWY5J.js.map +1 -0
  20. package/dist/{chunk-3HUUP3JC.js → chunk-FYLIR4AV.js} +107 -7
  21. package/dist/chunk-FYLIR4AV.js.map +1 -0
  22. package/dist/{chunk-G6FJZG4C.js → chunk-GM3BV6JK.js} +2 -2
  23. package/dist/{chunk-G6FJZG4C.js.map → chunk-GM3BV6JK.js.map} +1 -1
  24. package/dist/{chunk-R4YUZRGF.js → chunk-JUZGLINM.js} +2 -2
  25. package/dist/{chunk-R4YUZRGF.js.map → chunk-JUZGLINM.js.map} +1 -1
  26. package/dist/{chunk-WKZ5R4NP.js → chunk-L6BKSTAX.js} +332 -38
  27. package/dist/chunk-L6BKSTAX.js.map +1 -0
  28. package/dist/{chunk-WRDHUTOK.js → chunk-LHUCCPH4.js} +5 -5
  29. package/dist/{chunk-WRDHUTOK.js.map → chunk-LHUCCPH4.js.map} +1 -1
  30. package/dist/{chunk-U2XHHLE3.js → chunk-LMRO2QNF.js} +5 -5
  31. package/dist/{chunk-U2XHHLE3.js.map → chunk-LMRO2QNF.js.map} +1 -1
  32. package/dist/{chunk-N4FSBCLV.js → chunk-N2KV5RK3.js} +127 -10
  33. package/dist/chunk-N2KV5RK3.js.map +1 -0
  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 +969 -572
  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/asset-cmd.d.ts +1 -1
  48. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  49. package/dist/cli/src/commands/cache.d.ts +27 -0
  50. package/dist/cli/src/commands/cache.d.ts.map +1 -0
  51. package/dist/cli/src/commands/catalog.d.ts +9 -3
  52. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  53. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  54. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  55. package/dist/cli/src/commands/npx.d.ts +1 -1
  56. package/dist/cli/src/commands/skailify-lib.d.ts +108 -0
  57. package/dist/cli/src/commands/skailify-lib.d.ts.map +1 -0
  58. package/dist/cli/src/commands/source.d.ts +3 -1
  59. package/dist/cli/src/commands/source.d.ts.map +1 -1
  60. package/dist/cli/src/commands/update.d.ts +1 -1
  61. package/dist/cli/src/ensure-sources.d.ts +2 -2
  62. package/dist/cli/src/ensure-sources.d.ts.map +1 -1
  63. package/dist/connectors/config.js +4 -4
  64. package/dist/connectors/index.js +6 -6
  65. package/dist/connectors/rclone.js +1 -1
  66. package/dist/connectors/src/rclone-process-manager.d.ts +57 -2
  67. package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -1
  68. package/dist/core/index.js +3 -3
  69. package/dist/core/runtime-assets.js +2 -2
  70. package/dist/core/src/cache-paths.d.ts +25 -0
  71. package/dist/core/src/cache-paths.d.ts.map +1 -0
  72. package/dist/core/src/index.d.ts +2 -1
  73. package/dist/core/src/index.d.ts.map +1 -1
  74. package/dist/core/src/repo-manager.d.ts +11 -8
  75. package/dist/core/src/repo-manager.d.ts.map +1 -1
  76. package/dist/core/src/runtime-assets.d.ts.map +1 -1
  77. package/dist/core/src/workspace-config.d.ts +2 -2
  78. package/dist/core/src/workspace-config.d.ts.map +1 -1
  79. package/dist/core/workspace-config.js +1 -1
  80. package/dist/deploy/index.js +3 -3
  81. package/dist/{ensure-sources-VQDZB7NT.js → ensure-sources-NSDMTAWN.js} +6 -12
  82. package/dist/ensure-sources-NSDMTAWN.js.map +1 -0
  83. package/dist/factory-assets/connectors/deploy.js +6 -6
  84. package/dist/factory-assets/connectors/devserver.js +6 -6
  85. package/dist/factory-assets/connectors/flow/adapter.js +6 -6
  86. package/dist/factory-assets/connectors/flow/engine.js +3 -3
  87. package/dist/factory-assets/connectors/flow/run-flow.js +7 -7
  88. package/dist/factory-assets/connectors/flow.js +6 -6
  89. package/dist/factory-assets/connectors/git.js +6 -6
  90. package/dist/factory-assets/connectors/gmail.js +6 -6
  91. package/dist/factory-assets/connectors/googledrive.js +6 -6
  92. package/dist/factory-assets/connectors/local.js +6 -6
  93. package/dist/factory-assets/connectors/mattermost.js +6 -6
  94. package/dist/factory-assets/connectors/memory.js +6 -6
  95. package/dist/factory-assets/connectors/minio.js +6 -6
  96. package/dist/factory-assets/connectors/postgres.js +6 -6
  97. package/dist/factory-assets/connectors/s3.js +6 -6
  98. package/dist/factory-assets/connectors/sharepoint.js +6 -6
  99. package/dist/factory-assets/connectors/sqlite.js +6 -6
  100. package/dist/factory-assets/connectors/static-server.js +6 -6
  101. package/dist/factory-assets/connectors/tunnel.js +6 -6
  102. package/dist/factory-assets/connectors/webdav.js +6 -6
  103. package/dist/factory-assets/connectors/xstate-store.js +6 -6
  104. package/dist/factory-assets/connectors/xstate.js +6 -6
  105. package/dist/factory-assets/skaile.manifest.yaml +3 -0
  106. package/dist/factory-assets/skills/skailify/SKILL.md +84 -0
  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-2X2YXJVG.js} +5 -5
  125. package/dist/{plugin-store-LGLN2QUX.js.map → plugin-store-2X2YXJVG.js.map} +1 -1
  126. package/dist/runner/index.js +9 -9
  127. package/dist/runner/src/file-changed-coalescer.d.ts +48 -0
  128. package/dist/runner/src/file-changed-coalescer.d.ts.map +1 -0
  129. package/dist/runner/src/resources.d.ts.map +1 -1
  130. package/dist/sdk/asset-manager.js +5 -5
  131. package/dist/sdk/core.js +3 -3
  132. package/dist/sdk/flow.js +3 -3
  133. package/dist/sdk/index.js +9 -9
  134. package/dist/sdk/runner.js +9 -9
  135. package/dist/sdk/session.js +2 -2
  136. package/dist/sdk/types.js +1 -1
  137. package/dist/session/index.js +2 -2
  138. package/dist/session/src/index.d.ts +1 -1
  139. package/dist/session/src/index.d.ts.map +1 -1
  140. package/dist/session/src/mentions.d.ts +11 -0
  141. package/dist/session/src/mentions.d.ts.map +1 -1
  142. package/dist/{setup-EVNPECSY.js → setup-VGZTFQ32.js} +5 -5
  143. package/dist/{setup-EVNPECSY.js.map → setup-VGZTFQ32.js.map} +1 -1
  144. package/dist/{store-client-4XN7IB3R.js → store-client-XFZFKY3W.js} +6 -6
  145. package/dist/{store-client-4XN7IB3R.js.map → store-client-XFZFKY3W.js.map} +1 -1
  146. package/dist/tui/index.js +9 -9
  147. package/dist/types/index.js +1 -1
  148. package/dist/types/src/mentions.d.ts +12 -0
  149. package/dist/types/src/mentions.d.ts.map +1 -1
  150. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  151. package/dist/workspace-plugin/adapters/omp.js +3 -3
  152. package/dist/workspace-plugin/index.js +1 -1
  153. package/package.json +1 -1
  154. package/dist/asset-feeds-3PSV57NT.js.map +0 -1
  155. package/dist/chunk-3HUUP3JC.js.map +0 -1
  156. package/dist/chunk-3K2CYDBT.js.map +0 -1
  157. package/dist/chunk-GJI6FZ56.js.map +0 -1
  158. package/dist/chunk-HVCZLD5Z.js.map +0 -1
  159. package/dist/chunk-M54RYUXY.js.map +0 -1
  160. package/dist/chunk-N4FSBCLV.js.map +0 -1
  161. package/dist/chunk-TDSRLMDB.js.map +0 -1
  162. package/dist/chunk-WKZ5R4NP.js.map +0 -1
  163. 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, SKAILE_YAML_DEFAULT, 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 ?? {})) {
@@ -69,6 +108,14 @@ function parseCanonicalLockKey(key) {
69
108
  return {};
70
109
  }
71
110
  }
111
+ var MissingManifestError = class extends Error {
112
+ constructor(projectDir) {
113
+ super(`No skaile.yaml in ${projectDir}.`);
114
+ this.projectDir = projectDir;
115
+ this.name = "MissingManifestError";
116
+ }
117
+ projectDir;
118
+ };
72
119
  var FACTORY_SOURCE_URL = "https://github.com/skaile-ai/ai-assets";
73
120
  function resolveFactoryAssetsDir() {
74
121
  for (const dir of factoryAssetRoots()) {
@@ -99,13 +146,39 @@ var AssetManager = class {
99
146
  driverTarget;
100
147
  /** Whether this instance operates in global-install mode. */
101
148
  global;
149
+ /** Injected catalog fetcher (tests / custom); falls back to a built one. */
150
+ injectedStoreFetcher;
151
+ /** Injected byte fetcher for store staging; falls back to GitHub. */
152
+ injectedAssetFetcher;
153
+ /** Injected global catalog URL override for the no-project-store fallback. */
154
+ catalogUrlOverride;
102
155
  constructor(opts) {
103
156
  this.projectDir = resolve(opts.projectDir);
104
157
  this.driverTarget = opts.driverTarget ?? "claude-code";
105
158
  this.global = opts.global ?? false;
159
+ this.injectedStoreFetcher = opts.storeFetcher;
160
+ this.injectedAssetFetcher = opts.assetFetcher;
161
+ this.catalogUrlOverride = opts.catalogUrl;
162
+ }
163
+ get storeCacheDir() {
164
+ return migrateLegacyDir(
165
+ join(this.projectDir, ".skaile", "cache", "store"),
166
+ join(this.projectDir, ".skaile", "store-cache")
167
+ );
106
168
  }
107
169
  get reposDir() {
108
- return join(this.projectDir, ".skaile", "repos");
170
+ return migrateLegacyDir(
171
+ join(this.projectDir, ".skaile", "cache", "sources"),
172
+ join(this.projectDir, ".skaile", "repos")
173
+ );
174
+ }
175
+ /**
176
+ * Project-scoped cache dirs rooted at `.skaile/cache/` (`store`, `sources`)
177
+ * relative to `projectDir`. Reading is a side effect: it triggers lazy
178
+ * migration of the legacy `.skaile/{store-cache,repos}` dirs.
179
+ */
180
+ get projectCacheDirs() {
181
+ return { store: this.storeCacheDir, sources: this.reposDir };
109
182
  }
110
183
  get lockPath() {
111
184
  return join(this.projectDir, "skaile.lock.yaml");
@@ -123,8 +196,7 @@ var AssetManager = class {
123
196
  const dependencies = config.dependencies ?? [];
124
197
  const overrides = config.overrides ?? [];
125
198
  const patches = config.patches ?? {};
126
- const skaileHome = process.env.SKAILE_HOME ?? join(homedir(), ".skaile");
127
- const sourcesDir = join(skaileHome, "sources");
199
+ const sourcesDir = getGlobalCacheDir();
128
200
  const repositories = {};
129
201
  for (const s of sources) {
130
202
  const slug = sourceSlug(s.url);
@@ -185,15 +257,6 @@ var AssetManager = class {
185
257
  }
186
258
  }
187
259
  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
260
  const mdName = MD_BY_KIND[c.kind];
198
261
  const mdRel = c.files.find((f) => mdName ? f.path.endsWith(mdName) : false)?.path;
199
262
  const source = mdRel ? join(cloneDir, mdRel) : cloneDir;
@@ -215,6 +278,184 @@ var AssetManager = class {
215
278
  if (c.homepage != null) entry.homepage = c.homepage;
216
279
  return entry;
217
280
  }
281
+ // ── Store fetch-then-deploy ────────────────────────────────────────────
282
+ /** A candidate's stable identity key (`<publisher>/<kind>:<name>@<version>`). */
283
+ candidateKey(c) {
284
+ return `${c.publisher}/${c.kind}:${c.name}@${c.version}`;
285
+ }
286
+ /**
287
+ * Resolve `deps`, falling back to the global `catalog.url` store when the
288
+ * project declares no store and the first pass leaves something missing.
289
+ *
290
+ * The first pass uses the project stores only, so locally-resolvable refs
291
+ * never trigger a network probe. The fallback retry is best-effort: any error
292
+ * (offline, store down) keeps the first pass's result rather than regressing.
293
+ */
294
+ async resolveWithStores(deps, opts) {
295
+ const first = await resolveAll(deps, {
296
+ provenanceIndex: opts.provenanceIndex,
297
+ overrides: opts.overrides,
298
+ stores: opts.stores,
299
+ storeFetcher: this.storeFetcherFor(opts.stores),
300
+ projectDir: this.projectDir
301
+ });
302
+ if (first.missing.length === 0) return first;
303
+ const fallback = await this.globalStoreFallback(opts.stores);
304
+ if (fallback.length === 0) return first;
305
+ const stores = [...opts.stores, ...fallback];
306
+ try {
307
+ const retry = await resolveAll(deps, {
308
+ provenanceIndex: opts.provenanceIndex,
309
+ overrides: opts.overrides,
310
+ stores,
311
+ storeFetcher: this.storeFetcherFor(stores),
312
+ projectDir: this.projectDir
313
+ });
314
+ return retry.missing.length < first.missing.length ? retry : first;
315
+ } catch {
316
+ return first;
317
+ }
318
+ }
319
+ /** The catalog fetcher to use: an injected one, else built from `stores`. */
320
+ storeFetcherFor(stores) {
321
+ return this.injectedStoreFetcher ?? this.buildStoreFetcher(stores);
322
+ }
323
+ /**
324
+ * The global `catalog.url` as a single-store fallback, or `[]` when no
325
+ * project store should be synthesized — `local` sentinel, already-declared,
326
+ * or no URL. Honours an explicit `catalogUrl` injection (`""` disables it).
327
+ */
328
+ async globalStoreFallback(projectStores) {
329
+ let url = this.catalogUrlOverride;
330
+ if (url === void 0) {
331
+ try {
332
+ const { resolveConfig } = await import('./library/index.js');
333
+ url = resolveConfig({ projectDir: this.projectDir }).catalog.url;
334
+ } catch {
335
+ return [];
336
+ }
337
+ }
338
+ if (!url || url.trim().toLowerCase() === "local") return [];
339
+ if (projectStores.some((s) => normalizeRepoUrl(s.url) === normalizeRepoUrl(url))) return [];
340
+ return [{ url }];
341
+ }
342
+ /**
343
+ * Build deployable catalog entries from resolved candidates. Store-resolved
344
+ * candidates (no local clone bytes) are fetched + SHA-verified into the
345
+ * project store-cache first, then their entry points at the staged bytes so
346
+ * the existing copy-deploy path works. Source-backed candidates keep the
347
+ * clone-relative entry.
348
+ */
349
+ async buildCatalogEntries(resolved, repositories) {
350
+ const staged = await this.stageStoreAssets(resolved, repositories);
351
+ const entries = [];
352
+ for (const c of resolved) {
353
+ const stagedPath = staged.get(this.candidateKey(c));
354
+ const entry = stagedPath ? this.stagedCandidateToEntry(c, stagedPath) : this.candidateToCatalogEntry(c, repositories);
355
+ if (entry) entries.push(entry);
356
+ }
357
+ return entries;
358
+ }
359
+ /**
360
+ * Fetch + SHA-verify the bytes of every store-resolved deployable candidate
361
+ * into `.skaile/cache/store/`, reusing the same verified-fetch path the
362
+ * pointer-only `library.install` uses (`installFromManifest` flat mode).
363
+ *
364
+ * @returns Map of candidate key → staged primary-manifest path.
365
+ */
366
+ async stageStoreAssets(resolved, repositories) {
367
+ const staged = /* @__PURE__ */ new Map();
368
+ let installFromManifest;
369
+ for (const c of resolved) {
370
+ if (NON_DEPLOYABLE_KINDS.has(c.kind)) continue;
371
+ if (!c.files || c.files.length === 0 || !c.sourceUrl || !c.commit) continue;
372
+ if (this.candidateHasLocalBytes(c, repositories)) continue;
373
+ if (!installFromManifest) {
374
+ ({ installFromManifest } = await import('./library/index.js'));
375
+ }
376
+ const targetDir = join(this.storeCacheDir, c.publisher, c.kind, c.name, c.version);
377
+ const cacheRoot = resolve(this.storeCacheDir);
378
+ if (!resolve(targetDir).startsWith(cacheRoot + sep)) {
379
+ throw new Error(`unsafe store-cache path for ${this.candidateKey(c)}`);
380
+ }
381
+ const manifest = {
382
+ ref: `${c.kind}:@${c.publisher}/${c.name}#${c.version}`,
383
+ source: { url: c.sourceUrl, commitSha: c.commit },
384
+ files: c.files,
385
+ sha256: c.sha256,
386
+ kind: c.kind,
387
+ // tier = catalog storage hint (S3/CDN); flat-mode verified fetch pulls
388
+ // from source.url@commit and ignores it, so "" is inert.
389
+ tier: ""
390
+ };
391
+ const { installPath } = await installFromManifest({
392
+ manifest,
393
+ libraryRoot: this.storeCacheDir,
394
+ targetDir,
395
+ fetcher: this.injectedAssetFetcher
396
+ });
397
+ staged.set(this.candidateKey(c), join(installPath, this.stagedManifestRel(c)));
398
+ }
399
+ return staged;
400
+ }
401
+ /** Repo-relative path of a candidate's primary manifest (un-stripped). */
402
+ primaryManifestRel(c) {
403
+ const paths = (c.files ?? []).map((f) => f.path);
404
+ return matchManifestPath(c.kind, paths) ?? paths[0];
405
+ }
406
+ /**
407
+ * The primary-manifest path relative to a staged asset dir. Takes the kind's
408
+ * manifest (e.g. `SKILL.md`), then strips the same common-dir prefix
409
+ * `installFromManifest` flat mode removed on write.
410
+ */
411
+ stagedManifestRel(c) {
412
+ const paths = (c.files ?? []).map((f) => f.path);
413
+ const mdRel = this.primaryManifestRel(c) ?? "";
414
+ const root = commonDirPrefix(paths);
415
+ return root && mdRel.startsWith(`${root}/`) ? mdRel.slice(root.length + 1) : mdRel;
416
+ }
417
+ /**
418
+ * `true` when a candidate's primary manifest is present on a local source
419
+ * clone — its `sourceUrl` matches a registered source AND the manifest file
420
+ * exists on disk at the expected path. A URL match alone is not enough: a
421
+ * store can pin a different commit (or a subtree not bundled) of a repo that
422
+ * is also a registered source, in which case the bytes must be fetched from
423
+ * the store rather than read from the clone. (Only the primary manifest is
424
+ * probed — a partially-cloned source is deployed as-is, matching the existing
425
+ * clone-deploy path.)
426
+ */
427
+ candidateHasLocalBytes(c, repositories) {
428
+ if (!c.sourceUrl) return false;
429
+ const rel = this.primaryManifestRel(c);
430
+ for (const [slug, decl] of Object.entries(repositories)) {
431
+ if (decl.url === void 0 || decl.url !== c.sourceUrl) continue;
432
+ const dir = this.resolveRepoDir(decl, slug);
433
+ if (!dir) continue;
434
+ if (existsSync(rel ? join(dir, rel) : dir)) return true;
435
+ }
436
+ return false;
437
+ }
438
+ /** Build a copy-deploy catalog entry pointing at staged store bytes. */
439
+ stagedCandidateToEntry(c, stagedManifestPath) {
440
+ const entry = {
441
+ name: c.name,
442
+ kind: c.kind,
443
+ description: c.description ?? "",
444
+ source: stagedManifestPath,
445
+ // Real publisher (never a clone slug) → deployAsset copies rather than
446
+ // symlinking the ephemeral store-cache dir.
447
+ publisher: c.publisher,
448
+ version: c.version,
449
+ requires: [],
450
+ dependencies: c.deps ?? [],
451
+ metadata: c.metadata
452
+ };
453
+ if (c.category != null) entry.category = c.category;
454
+ if (c.keywords && c.keywords.length > 0) entry.keywords = c.keywords;
455
+ if (c.license != null) entry.license = c.license;
456
+ if (c.homepage != null) entry.homepage = c.homepage;
457
+ return entry;
458
+ }
218
459
  // ── Install / resolve ──────────────────────────────────────────────────
219
460
  /**
220
461
  * Install all dependencies declared in `skaile.yaml`.
@@ -237,15 +478,13 @@ var AssetManager = class {
237
478
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
238
479
  projectDir: this.projectDir
239
480
  });
240
- const { resolved, missing, overridesApplied } = await resolveAll(dependencies, {
481
+ const { resolved, missing, overridesApplied } = await this.resolveWithStores(dependencies, {
241
482
  provenanceIndex,
242
483
  overrides,
243
- stores,
244
- storeFetcher: this.buildStoreFetcher(stores),
245
- projectDir: this.projectDir
484
+ stores
246
485
  });
247
486
  const removed = this.reconcileRemovedAssets(resolved);
248
- const entries = resolved.map((c) => this.candidateToCatalogEntry(c, repositories)).filter((e) => e !== null);
487
+ const entries = await this.buildCatalogEntries(resolved, repositories);
249
488
  const deployed = deployAll(entries, repositories, patches, this.deployOpts);
250
489
  writeLock(this.lockPath, buildLockFile(resolved, overridesApplied));
251
490
  this.recordInstallHistory(deployed, removed);
@@ -453,19 +692,17 @@ var AssetManager = class {
453
692
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
454
693
  projectDir: this.projectDir
455
694
  });
456
- const { resolved, missing } = await resolveAll([ref], {
695
+ const { resolved, missing } = await this.resolveWithStores([ref], {
457
696
  provenanceIndex,
458
697
  overrides,
459
- stores,
460
- storeFetcher: this.buildStoreFetcher(stores),
461
- projectDir: this.projectDir
698
+ stores
462
699
  });
463
700
  if (resolved.length === 0) {
464
701
  throw new Error(
465
702
  `Asset not found: ${ref}${missing.length ? ` (missing: ${missing.join(", ")})` : ""}`
466
703
  );
467
704
  }
468
- const entries = resolved.map((c) => this.candidateToCatalogEntry(c, repositories)).filter((e) => e !== null);
705
+ const entries = await this.buildCatalogEntries(resolved, repositories);
469
706
  const deployed = deployAll(entries, repositories, patches, this.deployOpts);
470
707
  this.addDependencyToConfig(ref);
471
708
  for (const d of deployed) {
@@ -590,6 +827,65 @@ var AssetManager = class {
590
827
  }
591
828
  return result;
592
829
  }
830
+ /**
831
+ * List the **declared** top-level dependencies from `skaile.yaml`, each tagged
832
+ * with a reconciliation {@link DeclaredState}:
833
+ *
834
+ * - `declared` — in `skaile.yaml`, not yet resolved into the lock.
835
+ * - `installed` — declared + locked, and (for deployable kinds) materialized on
836
+ * disk. Non-deployable kinds ({@link NON_DEPLOYABLE_KINDS}) count as installed
837
+ * once locked — they are wired at session start, never written to the target dir.
838
+ * - `drift` — declared + locked but the deployed files are missing on disk.
839
+ * - `invalid` — the `dependencies:` entry isn't a parseable canonical ref. Only
840
+ * surfaced in the unfiltered listing (a `kind` filter can't classify it).
841
+ *
842
+ * Transitive (lock-only) deps are excluded by construction — only the declared
843
+ * set is walked, so a lock entry with no matching `dependencies:` ref never shows.
844
+ *
845
+ * @param kind - Filter by asset kind. Omit to return all kinds.
846
+ * @returns One {@link DeclaredAsset} per declared dep (after the optional kind filter).
847
+ * @throws {MissingManifestError} when the project has no `skaile.yaml`.
848
+ * @throws {Error} with a `migrate-skaile-manifest` hint on legacy `repositories:` / `ai_resources:` keys.
849
+ */
850
+ listDeclared(kind) {
851
+ if (!existsSync(join(this.projectDir, SKAILE_YAML_DEFAULT))) {
852
+ throw new MissingManifestError(this.projectDir);
853
+ }
854
+ const dependencies = resolveSkWorkspaceConfig(this.projectDir).dependencies ?? [];
855
+ const lock = this.tryReadLock();
856
+ const lockKeys = lock ? Object.keys(lock.assets).map(parseCanonicalLockKey) : [];
857
+ const out = [];
858
+ for (const ref of dependencies) {
859
+ let parsed;
860
+ try {
861
+ parsed = parseAssetRef(ref);
862
+ } catch {
863
+ if (!kind) out.push({ ref, kind: "", name: ref, state: "invalid" });
864
+ continue;
865
+ }
866
+ if (kind && parsed.kind !== kind) continue;
867
+ const locked = lockKeys.some(
868
+ (k) => k.kind === parsed.kind && k.name === parsed.name && (!parsed.publisher || k.publisher === parsed.publisher)
869
+ );
870
+ let state;
871
+ if (!locked) {
872
+ state = "declared";
873
+ } else if (NON_DEPLOYABLE_KINDS.has(parsed.kind)) {
874
+ state = "installed";
875
+ } else {
876
+ const onDisk = isDeployed(
877
+ parsed.kind,
878
+ parsed.name,
879
+ this.driverTarget,
880
+ this.global,
881
+ this.projectDir
882
+ );
883
+ state = onDisk ? "installed" : "drift";
884
+ }
885
+ out.push({ ref, kind: parsed.kind, name: parsed.name, state });
886
+ }
887
+ return out;
888
+ }
593
889
  /**
594
890
  * Build an aggregated workspace overview with domain grouping and sync status.
595
891
  *
@@ -739,12 +1035,10 @@ var AssetManager = class {
739
1035
  const provenanceIndex = buildProvenanceIndex(this.buildClones(repositories), {
740
1036
  projectDir: this.projectDir
741
1037
  });
742
- const { resolved, overridesApplied } = await resolveAll(dependencies, {
1038
+ const { resolved, overridesApplied } = await this.resolveWithStores(dependencies, {
743
1039
  provenanceIndex,
744
1040
  overrides,
745
- stores,
746
- storeFetcher: this.buildStoreFetcher(stores),
747
- projectDir: this.projectDir
1041
+ stores
748
1042
  });
749
1043
  const lockData = buildLockFile(resolved, overridesApplied);
750
1044
  writeLock(this.lockPath, lockData);
@@ -911,8 +1205,8 @@ var AssetManager = class {
911
1205
  * Remove deployed assets tracked by the lock file and report unmanaged ones.
912
1206
  *
913
1207
  * 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.
1208
+ * `.skaile/cache/sources/`, and `skaile.lock.yaml` — effectively resetting the
1209
+ * workspace to a pre-install state.
916
1210
  *
917
1211
  * @param opts - Optional cleanup options.
918
1212
  * @param opts.all - When `true`, remove all Skaile-managed state in addition to deployed assets.
@@ -976,7 +1270,7 @@ var AssetManager = class {
976
1270
  }
977
1271
  return unmanaged;
978
1272
  }
979
- /** Delete all Skaile-managed state: history file, patches/, repos/, lock. */
1273
+ /** Delete all Skaile-managed state: history file, patches/, cache/sources/, lock. */
980
1274
  removeAllManagedState() {
981
1275
  const historyFile = join(this.projectDir, ".skaile", "history.yaml");
982
1276
  try {
@@ -1039,6 +1333,6 @@ var AssetManager = class {
1039
1333
  }
1040
1334
  };
1041
1335
 
1042
- export { AssetManager, parseCanonicalLockKey };
1043
- //# sourceMappingURL=chunk-WKZ5R4NP.js.map
1044
- //# sourceMappingURL=chunk-WKZ5R4NP.js.map
1336
+ export { AssetManager, MissingManifestError, NON_DEPLOYABLE_KINDS, parseCanonicalLockKey };
1337
+ //# sourceMappingURL=chunk-L6BKSTAX.js.map
1338
+ //# sourceMappingURL=chunk-L6BKSTAX.js.map