@skaile/workspaces 0.49.0 → 0.52.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 (186) hide show
  1. package/CHANGELOG.md +248 -0
  2. package/dist/asset-feeds-OEGJ6NOF.js +205 -0
  3. package/dist/asset-feeds-OEGJ6NOF.js.map +1 -0
  4. package/dist/asset-manager/index.js +8 -8
  5. package/dist/asset-manager/installer.js +7 -7
  6. package/dist/asset-manager/src/index.d.ts +94 -6
  7. package/dist/asset-manager/src/index.d.ts.map +1 -1
  8. package/dist/asset-manager/src/installer.d.ts +19 -8
  9. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  10. package/dist/{chunk-P4BDTJMI.js → chunk-2D5YE3FL.js} +4 -4
  11. package/dist/{chunk-P4BDTJMI.js.map → chunk-2D5YE3FL.js.map} +1 -1
  12. package/dist/{chunk-4IGNQG6E.js → chunk-2ZK7M2SG.js} +3 -3
  13. package/dist/{chunk-4IGNQG6E.js.map → chunk-2ZK7M2SG.js.map} +1 -1
  14. package/dist/{chunk-SXT6BAQJ.js → chunk-3IHBGDCG.js} +2 -2
  15. package/dist/{chunk-SXT6BAQJ.js.map → chunk-3IHBGDCG.js.map} +1 -1
  16. package/dist/{chunk-SDAKQCOB.js → chunk-3KPNDTMR.js} +3 -3
  17. package/dist/{chunk-SDAKQCOB.js.map → chunk-3KPNDTMR.js.map} +1 -1
  18. package/dist/{chunk-H74X4TSR.js → chunk-6K4RVXAM.js} +6 -6
  19. package/dist/{chunk-H74X4TSR.js.map → chunk-6K4RVXAM.js.map} +1 -1
  20. package/dist/{chunk-XVDXGQ55.js → chunk-7X53KHQ4.js} +4 -2
  21. package/dist/{chunk-XVDXGQ55.js.map → chunk-7X53KHQ4.js.map} +1 -1
  22. package/dist/{chunk-LTUTK2Q3.js → chunk-7ZWLZ5H3.js} +35 -22
  23. package/dist/chunk-7ZWLZ5H3.js.map +1 -0
  24. package/dist/{chunk-6IDBWPK2.js → chunk-BQCGFPHW.js} +4 -3
  25. package/dist/chunk-BQCGFPHW.js.map +1 -0
  26. package/dist/chunk-BXC5547R.js +377 -0
  27. package/dist/chunk-BXC5547R.js.map +1 -0
  28. package/dist/{chunk-3A3OACI2.js → chunk-EOINYN5T.js} +2 -2
  29. package/dist/{chunk-3A3OACI2.js.map → chunk-EOINYN5T.js.map} +1 -1
  30. package/dist/{chunk-XGCXFX7X.js → chunk-F3HNW354.js} +3 -3
  31. package/dist/{chunk-XGCXFX7X.js.map → chunk-F3HNW354.js.map} +1 -1
  32. package/dist/{chunk-33WB7VFV.js → chunk-LKOMH3QC.js} +3 -3
  33. package/dist/{chunk-33WB7VFV.js.map → chunk-LKOMH3QC.js.map} +1 -1
  34. package/dist/{chunk-O4JH3KUE.js → chunk-MENCWIHW.js} +11 -3
  35. package/dist/chunk-MENCWIHW.js.map +1 -0
  36. package/dist/{chunk-LV73DB4G.js → chunk-MGB657EG.js} +16 -21
  37. package/dist/chunk-MGB657EG.js.map +1 -0
  38. package/dist/{chunk-PBO6SCT2.js → chunk-NXC6IEL4.js} +37 -14
  39. package/dist/chunk-NXC6IEL4.js.map +1 -0
  40. package/dist/{chunk-EBSIZYM6.js → chunk-QLLFCQU5.js} +12 -12
  41. package/dist/chunk-QLLFCQU5.js.map +1 -0
  42. package/dist/{chunk-X46FY45B.js → chunk-SKADPHAM.js} +12 -8
  43. package/dist/chunk-SKADPHAM.js.map +1 -0
  44. package/dist/{chunk-BWCGSGAC.js → chunk-TCNYSHPM.js} +165 -28
  45. package/dist/chunk-TCNYSHPM.js.map +1 -0
  46. package/dist/{chunk-JXHULIOA.js → chunk-UTHEIPEY.js} +387 -42
  47. package/dist/chunk-UTHEIPEY.js.map +1 -0
  48. package/dist/{chunk-ZJ3VRPOI.js → chunk-VE2UIJ7Y.js} +11 -15
  49. package/dist/chunk-VE2UIJ7Y.js.map +1 -0
  50. package/dist/{chunk-WBF7JLTY.js → chunk-W53D5Q52.js} +4 -4
  51. package/dist/{chunk-WBF7JLTY.js.map → chunk-W53D5Q52.js.map} +1 -1
  52. package/dist/{chunk-HNORRENR.js → chunk-WD2NRI3T.js} +5 -5
  53. package/dist/{chunk-HNORRENR.js.map → chunk-WD2NRI3T.js.map} +1 -1
  54. package/dist/cli/index.js +688 -480
  55. package/dist/cli/index.js.map +1 -1
  56. package/dist/cli/src/asset-feeds.d.ts +17 -3
  57. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  58. package/dist/cli/src/commands/catalog.d.ts +3 -2
  59. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  60. package/dist/cli/src/commands/manage.d.ts +47 -8
  61. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  62. package/dist/cli/src/commands/project.d.ts.map +1 -1
  63. package/dist/cli/src/commands/source.d.ts +32 -0
  64. package/dist/cli/src/commands/source.d.ts.map +1 -1
  65. package/dist/cli/src/commands/update.d.ts +7 -0
  66. package/dist/cli/src/commands/update.d.ts.map +1 -1
  67. package/dist/connectors/config.js +7 -7
  68. package/dist/connectors/index.js +9 -9
  69. package/dist/connectors/src/config.d.ts +5 -13
  70. package/dist/connectors/src/config.d.ts.map +1 -1
  71. package/dist/connectors/src/index.d.ts +1 -1
  72. package/dist/connectors/src/index.d.ts.map +1 -1
  73. package/dist/core/driver-targets.js +1 -1
  74. package/dist/core/index.js +6 -6
  75. package/dist/core/manifest.js +1 -1
  76. package/dist/core/runtime-assets.js +4 -3
  77. package/dist/core/src/cache-paths.d.ts +6 -0
  78. package/dist/core/src/cache-paths.d.ts.map +1 -1
  79. package/dist/core/src/driver-targets.d.ts +12 -7
  80. package/dist/core/src/driver-targets.d.ts.map +1 -1
  81. package/dist/core/src/index.d.ts +3 -3
  82. package/dist/core/src/index.d.ts.map +1 -1
  83. package/dist/core/src/manifest.d.ts +6 -6
  84. package/dist/core/src/manifest.d.ts.map +1 -1
  85. package/dist/core/src/workspace-config.d.ts +36 -0
  86. package/dist/core/src/workspace-config.d.ts.map +1 -1
  87. package/dist/core/store.js +2 -2
  88. package/dist/core/workspace-config.js +3 -2
  89. package/dist/deploy/index.js +6 -6
  90. package/dist/discovery/index.js +2 -2
  91. package/dist/discovery/src/atomization-conventions.d.ts +30 -0
  92. package/dist/discovery/src/atomization-conventions.d.ts.map +1 -0
  93. package/dist/discovery/src/builtin-providers.d.ts.map +1 -1
  94. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  95. package/dist/discovery/src/discover.d.ts +38 -0
  96. package/dist/discovery/src/discover.d.ts.map +1 -1
  97. package/dist/discovery/src/index.d.ts +5 -2
  98. package/dist/discovery/src/index.d.ts.map +1 -1
  99. package/dist/discovery/src/reference-lint.d.ts +112 -0
  100. package/dist/discovery/src/reference-lint.d.ts.map +1 -0
  101. package/dist/discovery/src/requires-graph.d.ts +1 -1
  102. package/dist/discovery/src/tree-entries.d.ts +9 -1
  103. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  104. package/dist/{ensure-sources-EE7Z2HKS.js → ensure-sources-GJOXWVWO.js} +8 -8
  105. package/dist/{ensure-sources-EE7Z2HKS.js.map → ensure-sources-GJOXWVWO.js.map} +1 -1
  106. package/dist/factory-assets/connectors/deploy.js +9 -9
  107. package/dist/factory-assets/connectors/devserver.js +9 -9
  108. package/dist/factory-assets/connectors/flow/adapter.js +9 -9
  109. package/dist/factory-assets/connectors/flow/engine/flow-kind-provider.d.ts +1 -1
  110. package/dist/factory-assets/connectors/flow/engine/flow-kind-provider.d.ts.map +1 -1
  111. package/dist/factory-assets/connectors/flow/engine.js +7 -7
  112. package/dist/factory-assets/connectors/flow/run-flow.js +10 -10
  113. package/dist/factory-assets/connectors/flow.js +9 -9
  114. package/dist/factory-assets/connectors/git.js +9 -9
  115. package/dist/factory-assets/connectors/gmail/adapter.d.ts.map +1 -1
  116. package/dist/factory-assets/connectors/gmail.js +9 -9
  117. package/dist/factory-assets/connectors/googledrive.js +9 -9
  118. package/dist/factory-assets/connectors/local.js +9 -9
  119. package/dist/factory-assets/connectors/mattermost/adapter.d.ts.map +1 -1
  120. package/dist/factory-assets/connectors/mattermost.js +9 -9
  121. package/dist/factory-assets/connectors/memory.js +9 -9
  122. package/dist/factory-assets/connectors/minio/adapter.d.ts.map +1 -1
  123. package/dist/factory-assets/connectors/minio.js +9 -9
  124. package/dist/factory-assets/connectors/postgres/adapter.d.ts.map +1 -1
  125. package/dist/factory-assets/connectors/postgres.js +9 -9
  126. package/dist/factory-assets/connectors/s3/driver.d.ts.map +1 -1
  127. package/dist/factory-assets/connectors/s3.js +9 -9
  128. package/dist/factory-assets/connectors/sharepoint.js +9 -9
  129. package/dist/factory-assets/connectors/sqlite/adapter.d.ts.map +1 -1
  130. package/dist/factory-assets/connectors/sqlite.js +9 -9
  131. package/dist/factory-assets/connectors/static-server.js +9 -9
  132. package/dist/factory-assets/connectors/tunnel.js +9 -9
  133. package/dist/factory-assets/connectors/webdav.js +9 -9
  134. package/dist/factory-assets/connectors/xstate-store.js +9 -9
  135. package/dist/factory-assets/connectors/xstate.js +9 -9
  136. package/dist/{flows-AAHXXXCH.js → flows-AGPIE6JM.js} +3 -3
  137. package/dist/{flows-AAHXXXCH.js.map → flows-AGPIE6JM.js.map} +1 -1
  138. package/dist/library/index.js +8 -8
  139. package/dist/library/install.js +6 -6
  140. package/dist/open-library-ERKRGH4B.js +23 -0
  141. package/dist/{open-library-TXJMFG34.js.map → open-library-ERKRGH4B.js.map} +1 -1
  142. package/dist/paths-D6RUQ522.js +15 -0
  143. package/dist/{paths-OMVC4UWY.js.map → paths-D6RUQ522.js.map} +1 -1
  144. package/dist/{plugin-store-JWJHIPUT.js → plugin-store-SGNJTBYS.js} +8 -8
  145. package/dist/{plugin-store-JWJHIPUT.js.map → plugin-store-SGNJTBYS.js.map} +1 -1
  146. package/dist/runner/index.js +11 -11
  147. package/dist/runner/src/serve.d.ts.map +1 -1
  148. package/dist/sdk/asset-manager.js +8 -8
  149. package/dist/sdk/core.js +6 -6
  150. package/dist/sdk/flow.js +7 -7
  151. package/dist/sdk/index.js +17 -11
  152. package/dist/sdk/index.js.map +1 -1
  153. package/dist/sdk/runner.js +11 -11
  154. package/dist/sdk/src/transport.d.ts +2 -0
  155. package/dist/sdk/src/transport.d.ts.map +1 -1
  156. package/dist/sdk/store.js +1 -1
  157. package/dist/{setup-ETNBVZQA.js → setup-IV2JFW3T.js} +8 -8
  158. package/dist/{setup-ETNBVZQA.js.map → setup-IV2JFW3T.js.map} +1 -1
  159. package/dist/source-FGOMQMZT.js +24 -0
  160. package/dist/source-FGOMQMZT.js.map +1 -0
  161. package/dist/store/index.js +1 -1
  162. package/dist/store/src/store.d.ts.map +1 -1
  163. package/dist/store-client-GJT2XQ5Z.js +15 -0
  164. package/dist/{store-client-SLFAAKSV.js.map → store-client-GJT2XQ5Z.js.map} +1 -1
  165. package/dist/tui/index.js +11 -11
  166. package/dist/types/src/transport.d.ts +12 -0
  167. package/dist/types/src/transport.d.ts.map +1 -1
  168. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  169. package/dist/workspace-plugin/adapters/omp.js +3 -3
  170. package/dist/workspace-plugin/index.js +1 -1
  171. package/package.json +1 -1
  172. package/dist/asset-feeds-O6R6J4RI.js +0 -128
  173. package/dist/asset-feeds-O6R6J4RI.js.map +0 -1
  174. package/dist/chunk-6IDBWPK2.js.map +0 -1
  175. package/dist/chunk-BWCGSGAC.js.map +0 -1
  176. package/dist/chunk-EBSIZYM6.js.map +0 -1
  177. package/dist/chunk-JXHULIOA.js.map +0 -1
  178. package/dist/chunk-LTUTK2Q3.js.map +0 -1
  179. package/dist/chunk-LV73DB4G.js.map +0 -1
  180. package/dist/chunk-O4JH3KUE.js.map +0 -1
  181. package/dist/chunk-PBO6SCT2.js.map +0 -1
  182. package/dist/chunk-X46FY45B.js.map +0 -1
  183. package/dist/chunk-ZJ3VRPOI.js.map +0 -1
  184. package/dist/open-library-TXJMFG34.js +0 -23
  185. package/dist/paths-OMVC4UWY.js +0 -15
  186. package/dist/store-client-SLFAAKSV.js +0 -15
package/dist/cli/index.js CHANGED
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env node
2
- import { openCatalogSource, openLibraryManager, createFullRegistry, openLibrary } from '../chunk-HNORRENR.js';
2
+ import { AI_RESOURCES, aiResourceRoots } from '../chunk-LKOMH3QC.js';
3
+ import { makeSourceCommand, syncProjectSources } from '../chunk-BXC5547R.js';
4
+ import { openCatalogSource, openLibraryManager, createFullRegistry, openLibrary } from '../chunk-WD2NRI3T.js';
3
5
  import { logErr, S, logOk, logInfo, colorRef, logWarn, kindColorPad, kindColor, formatRelativeTime, fitWidth } from '../chunk-GYPA2Q7F.js';
4
- import { getStoreConfig, storeFetch, saveStoreTokens, clearStoreTokens, isStoreAuthenticated } from '../chunk-4IGNQG6E.js';
5
- import { AI_RESOURCES, aiResourceRoots } from '../chunk-33WB7VFV.js';
6
+ import { getStoreConfig, storeFetch, saveStoreTokens, clearStoreTokens, isStoreAuthenticated } from '../chunk-2ZK7M2SG.js';
6
7
  import { LocalSecretsProvider } from '../chunk-6BEGKO2Q.js';
7
- import { resolveLibraryDir, LocalCatalogSource } from '../chunk-P4BDTJMI.js';
8
- import '../chunk-JXHULIOA.js';
8
+ import { resolveLibraryDir } from '../chunk-2D5YE3FL.js';
9
+ import '../chunk-UTHEIPEY.js';
9
10
  import '../chunk-JXT46QFC.js';
10
11
  import '../chunk-UKJMQZV6.js';
11
12
  import '../chunk-R7FOF242.js';
12
- import { runFlow, resumeFlow } from '../chunk-H74X4TSR.js';
13
+ import { runFlow, resumeFlow } from '../chunk-6K4RVXAM.js';
13
14
  import '../chunk-4R6DROGN.js';
14
15
  import { validateFlowVersions, parseSkillFrontmatter } from '../chunk-GXC3TYMQ.js';
15
- import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-LV73DB4G.js';
16
- import { buildClaudePluginFiles } from '../chunk-SXT6BAQJ.js';
16
+ import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-MGB657EG.js';
17
+ import { buildClaudePluginFiles } from '../chunk-3IHBGDCG.js';
17
18
  import '../chunk-X5YPJV4N.js';
18
19
  import '../chunk-O7SG5PC2.js';
19
20
  import '../chunk-7QBNJTTQ.js';
@@ -28,25 +29,25 @@ import '../chunk-BMQKMOQY.js';
28
29
  import '../chunk-GAH4YRCI.js';
29
30
  import '../chunk-N5AE5SOC.js';
30
31
  import '../chunk-LV2HPH3C.js';
31
- import '../chunk-EBSIZYM6.js';
32
+ import '../chunk-QLLFCQU5.js';
32
33
  import '../chunk-OVRSNIKJ.js';
33
- import '../chunk-ZJ3VRPOI.js';
34
+ import '../chunk-VE2UIJ7Y.js';
34
35
  import '../chunk-RAIRWFAN.js';
35
36
  import '../chunk-6E6PKKAD.js';
36
- import { loadFlow, loadAllFlows } from '../chunk-X46FY45B.js';
37
+ import { loadFlow, loadAllFlows } from '../chunk-SKADPHAM.js';
37
38
  import '../chunk-DEYYRFQU.js';
38
39
  import '../chunk-IFGTRL2I.js';
39
- import { AssetManager, NON_DEPLOYABLE_KINDS, MissingManifestError } from '../chunk-BWCGSGAC.js';
40
- import '../chunk-LTUTK2Q3.js';
41
- import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync, WorkspaceYamlEditor, checkAgentSkillConformance } from '../chunk-SDAKQCOB.js';
40
+ import { AssetManager, NON_DEPLOYABLE_KINDS, MissingManifestError } from '../chunk-TCNYSHPM.js';
41
+ import '../chunk-7ZWLZ5H3.js';
42
+ import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync, WorkspaceYamlEditor, checkAgentSkillConformance } from '../chunk-3KPNDTMR.js';
42
43
  import { assetSearchDirs, detectDomains } from '../chunk-ZAP2BDHG.js';
43
- import '../chunk-WBF7JLTY.js';
44
- import { globalCacheRoot, sourceCacheKey, getGlobalCacheDir, resolveAgentDir, sourceShortName, findWorkspaceRoot, workspaceConfigFilename, resolveSkWorkspaceConfig } from '../chunk-PBO6SCT2.js';
44
+ import '../chunk-W53D5Q52.js';
45
+ import { globalCacheRoot, sourceCacheKey, getGlobalCacheDir, resolveAgentDir, resolveSkWorkspaceConfig } from '../chunk-NXC6IEL4.js';
45
46
  import { SKAILE_MANIFEST_FILENAME, decodeSkaileManifest, loadSkPublishManifest, saveSkPublishManifest } from '../chunk-DZCK7GRW.js';
46
- import { parseFrontmatter } from '../chunk-6IDBWPK2.js';
47
+ import { parseFrontmatter } from '../chunk-BQCGFPHW.js';
47
48
  import { parseAssetRef, ASSET_KINDS, isValidAssetName, slugifyAssetName, ASSET_NAME_HINT, assetRefToStr } from '../chunk-GEEW6SY2.js';
48
- import '../chunk-XGCXFX7X.js';
49
- import { SUPPORTED_DRIVER_TARGETS } from '../chunk-O4JH3KUE.js';
49
+ import '../chunk-F3HNW354.js';
50
+ import { SUPPORTED_DRIVER_TARGETS } from '../chunk-MENCWIHW.js';
50
51
  import { DRIVER_DEFAULTS } from '../chunk-K5GBV4SA.js';
51
52
  import { openSqlite } from '../chunk-JB35MVBN.js';
52
53
  import '../chunk-KTBKW2FI.js';
@@ -70,7 +71,7 @@ import * as readline from 'readline';
70
71
  import { createInterface } from 'readline';
71
72
  import fs6 from 'fs/promises';
72
73
  import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
73
- import { execSync, spawnSync } from 'child_process';
74
+ import { execSync } from 'child_process';
74
75
  import { createTRPCUntypedClient, httpLink, httpSubscriptionLink } from '@trpc/client';
75
76
 
76
77
  async function runSearch(kind, query, opts) {
@@ -80,16 +81,24 @@ async function runSearch(kind, query, opts) {
80
81
  }
81
82
  const showLocal = !opts.store;
82
83
  const showStore = !opts.local;
84
+ const { resolveConfig } = await import('../library/index.js');
85
+ const airGapped = resolveConfig({ projectDir: path14__default.resolve(opts.projectDir) }).catalog.cache_ttl === 0;
83
86
  if (showLocal) {
84
- searchLocal(query, kind, opts, showStore);
87
+ await searchLocal(query, kind, opts, showStore, airGapped);
85
88
  }
86
89
  if (showStore) {
87
- await searchStore(query, kind, opts);
90
+ await searchStore(query, kind, opts, airGapped);
88
91
  }
89
92
  }
90
- function searchLocal(query, kind, opts, showStore) {
91
- const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
92
- const entries = am2.search(query, kind);
93
+ async function searchLocal(query, kind, opts, showStore, airGapped) {
94
+ const projectDir = path14__default.resolve(opts.projectDir);
95
+ let entries = new AssetManager({ projectDir }).search(query, kind);
96
+ if (entries.length === 0 && !query && !kind && !airGapped) {
97
+ const { autoSyncForSearch } = await import('../source-FGOMQMZT.js');
98
+ if (await autoSyncForSearch(projectDir)) {
99
+ entries = new AssetManager({ projectDir }).search(query, kind);
100
+ }
101
+ }
93
102
  if (entries.length === 0) {
94
103
  if (!showStore) {
95
104
  logInfo(
@@ -126,9 +135,19 @@ function printLocalEntries(entries) {
126
135
  ${S.dim(`${entries.length} total`)}
127
136
  `);
128
137
  }
129
- async function searchStore(query, kind, opts) {
138
+ async function searchStore(query, kind, opts, airGapped) {
139
+ if (airGapped) {
140
+ if (opts.store) {
141
+ logErr(
142
+ "air-gapped (catalog.cache_ttl: 0) \u2014 store search is disabled. Set catalog.cache_ttl > 0 to query the store."
143
+ );
144
+ process.exit(1);
145
+ }
146
+ logInfo("air-gapped (cache_ttl: 0) \u2014 local sources only");
147
+ return;
148
+ }
130
149
  try {
131
- const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-SLFAAKSV.js');
150
+ const { getStoreConfig: getStoreConfig2, storeFetch: storeFetch2 } = await import('../store-client-GJT2XQ5Z.js');
132
151
  const config = getStoreConfig2();
133
152
  const params = {};
134
153
  if (query) params.q = query;
@@ -149,6 +168,8 @@ async function searchStore(query, kind, opts) {
149
168
  } catch (e) {
150
169
  if (opts.store) {
151
170
  logErr(`Store search failed: ${e.message}`);
171
+ } else {
172
+ logInfo("store unavailable \u2014 showing local results only (run with --store to see the error)");
152
173
  }
153
174
  }
154
175
  }
@@ -157,17 +178,38 @@ function makeSearchCommand() {
157
178
  await runSearch(kind, query, opts);
158
179
  });
159
180
  }
181
+ function parseBackendFilter(raw) {
182
+ if (!raw) return void 0;
183
+ const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
184
+ const out = [];
185
+ for (const id of ids) {
186
+ if (!SUPPORTED_DRIVER_TARGETS.includes(id)) {
187
+ logErr(`unknown backend '${id}' \u2014 expected one of: ${SUPPORTED_DRIVER_TARGETS.join(", ")}`);
188
+ process.exit(1);
189
+ }
190
+ out.push(id);
191
+ }
192
+ return out.length > 0 ? out : void 0;
193
+ }
160
194
  function makeAddCommand() {
161
- return new Command("add").description("Add to skaile.yaml + deploy").argument("<ref>", "Asset reference (kind:@<publisher>/name#<version>)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Deploy to global dir (~/.claude)").option("--target <agent>", "Driver target", "claude-code").action(async (ref, opts) => {
195
+ return new Command("add").description("Add to skaile.yaml + deploy").argument("<ref>", "Asset reference (kind:@<publisher>/name#<version>)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Record in ~/.skaile/skaile.yaml + deploy to every global backend").option(
196
+ "--backend <ids>",
197
+ "Comma-separated global backends to deploy into (default: all resolved); implies --global"
198
+ ).option("--target <agent>", "Driver target", "claude-code").option(
199
+ "--link",
200
+ "symlink local-path assets instead of copying (dev loop; machine-local, not for committing)"
201
+ ).action(async (ref, opts) => {
202
+ const backends = parseBackendFilter(opts.backend);
162
203
  const am2 = new AssetManager({
163
204
  projectDir: path14__default.resolve(opts.projectDir),
164
- global: opts.global,
205
+ global: opts.global || backends !== void 0,
206
+ backends,
165
207
  driverTarget: opts.target
166
208
  });
167
209
  const spinner5 = p6.spinner();
168
210
  spinner5.start(`Adding ${ref}`);
169
211
  try {
170
- const added = await am2.add(ref);
212
+ const added = await am2.add(ref, { link: opts.link });
171
213
  spinner5.stop("Done");
172
214
  if (added.length === 0) {
173
215
  const kind = parseAssetRef(ref).kind;
@@ -185,10 +227,15 @@ function makeAddCommand() {
185
227
  });
186
228
  }
187
229
  function makeRemoveCommand() {
188
- return new Command("remove").description("Remove from skaile.yaml + undeploy").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Remove from global dir").option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
230
+ return new Command("remove").description("Remove from skaile.yaml + undeploy").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Remove from ~/.skaile/skaile.yaml + undeploy from every global backend").option(
231
+ "--backend <ids>",
232
+ "Comma-separated global backends to undeploy from (default: all resolved); implies --global"
233
+ ).option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
234
+ const backends = parseBackendFilter(opts.backend);
189
235
  const am2 = new AssetManager({
190
236
  projectDir: path14__default.resolve(opts.projectDir),
191
- global: opts.global,
237
+ global: opts.global || backends !== void 0,
238
+ backends,
192
239
  driverTarget: opts.target
193
240
  });
194
241
  const ok = am2.remove(ref);
@@ -203,12 +250,19 @@ function stateLabel(s) {
203
250
  return S.dim(s);
204
251
  }
205
252
  function makeListCommand() {
206
- return new Command("list").description("List declared dependencies from skaile.yaml with state").argument("[kind]", "Filter by asset kind").option("--project-dir <path>", "Project directory", process.cwd()).option("-g, --global", "Inspect the global deployment dir for state").option("--json", "Output as JSON").addOption(
253
+ return new Command("list").description("List declared dependencies from skaile.yaml with state").argument("[kind]", "Filter by asset kind").option("--project-dir <path>", "Project directory", process.cwd()).option(
254
+ "-g, --global",
255
+ "Read the global SSOT (~/.skaile/skaile.yaml); report state per backend"
256
+ ).option("--backend <ids>", "Comma-separated global backends to report (implies --global)").option("--json", "Output as JSON").addOption(
207
257
  new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
208
258
  ).action((kind, opts) => {
259
+ const backends = parseBackendFilter(opts.backend);
260
+ if (opts.global || backends) {
261
+ runGlobalList(kind, opts, backends);
262
+ return;
263
+ }
209
264
  const am2 = new AssetManager({
210
265
  projectDir: path14__default.resolve(opts.projectDir),
211
- global: opts.global,
212
266
  driverTarget: opts.target
213
267
  });
214
268
  let declared;
@@ -251,6 +305,47 @@ function makeListCommand() {
251
305
  console.log();
252
306
  });
253
307
  }
308
+ function runGlobalList(kind, opts, backends) {
309
+ const am2 = new AssetManager({
310
+ projectDir: path14__default.resolve(opts.projectDir),
311
+ global: true,
312
+ backends
313
+ });
314
+ let rows;
315
+ try {
316
+ rows = am2.globalState({ kind });
317
+ } catch (err) {
318
+ logErr(err instanceof Error ? err.message : String(err));
319
+ process.exit(1);
320
+ }
321
+ if (opts.json) {
322
+ console.log(JSON.stringify(rows, null, 2));
323
+ return;
324
+ }
325
+ if (rows.length === 0) {
326
+ logInfo("No global dependencies declared in ~/.skaile/skaile.yaml.");
327
+ return;
328
+ }
329
+ const kindW = Math.max(4, ...rows.map((e) => e.kind.length));
330
+ const nameW = Math.max(4, ...rows.map((e) => e.name.length));
331
+ const beW = Math.max(7, ...rows.map((e) => e.backend.length));
332
+ console.log();
333
+ console.log(
334
+ ` ${S.dim("KIND".padEnd(kindW))} ${S.dim("NAME".padEnd(nameW))} ${S.dim("BACKEND".padEnd(beW))} ${S.dim("STATE")}`
335
+ );
336
+ console.log(` ${S.rule(kindW + nameW + beW + 6 + "installed".length)}`);
337
+ for (const e of rows) {
338
+ console.log(
339
+ ` ${kindColorPad(e.kind, kindW)} ${e.name.padEnd(nameW)} ${e.backend.padEnd(beW)} ${stateLabel(e.state)}`
340
+ );
341
+ }
342
+ console.log(`
343
+ ${S.dim(`${rows.length} entries`)}`);
344
+ const drift = rows.filter((e) => e.state === "drift").length;
345
+ if (drift > 0)
346
+ logInfo(`${drift} with drift \u2014 run ${S.cmd("skaile install --global")} to materialize.`);
347
+ console.log();
348
+ }
254
349
  function makeInfoCommand() {
255
350
  return new Command("info").description("Show asset metadata, deps, deploy status").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
256
351
  const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
@@ -512,9 +607,9 @@ function makeAssetCommand() {
512
607
  });
513
608
  logOk(`${up.added ? "Added" : "Updated"} manifest entry skill:${norm.name}`);
514
609
  if (target.backend === "git" && opts.commit) {
515
- const { spawnSync: spawnSync2 } = await import('child_process');
516
- spawnSync2("git", ["add", "--", destDir], { cwd: target.path, stdio: "inherit" });
517
- const r = spawnSync2("git", ["commit", "-m", `skaile: import ${norm.name}`], {
610
+ const { spawnSync } = await import('child_process');
611
+ spawnSync("git", ["add", "--", destDir], { cwd: target.path, stdio: "inherit" });
612
+ const r = spawnSync("git", ["commit", "-m", `skaile: import ${norm.name}`], {
518
613
  cwd: target.path,
519
614
  stdio: "inherit"
520
615
  });
@@ -582,9 +677,9 @@ function makeAssetCommand() {
582
677
  break;
583
678
  }
584
679
  if (target.backend === "git" && opts.commit) {
585
- const { spawnSync: spawnSync2 } = await import('child_process');
586
- spawnSync2("git", ["add", "--", destPath], { cwd: target.path, stdio: "inherit" });
587
- const r = spawnSync2("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
680
+ const { spawnSync } = await import('child_process');
681
+ spawnSync("git", ["add", "--", destPath], { cwd: target.path, stdio: "inherit" });
682
+ const r = spawnSync("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
588
683
  cwd: target.path,
589
684
  stdio: "inherit"
590
685
  });
@@ -829,7 +924,7 @@ function makeCatalogCommand() {
829
924
  return catalog;
830
925
  }
831
926
  async function runLocalCatalogTest(projectDir) {
832
- const { resolveCatalogSource } = await import('../open-library-TXJMFG34.js');
927
+ const { resolveCatalogSource } = await import('../open-library-ERKRGH4B.js');
833
928
  let resolved;
834
929
  try {
835
930
  resolved = await resolveCatalogSource({ projectDir });
@@ -1080,13 +1175,13 @@ function collectWorkspaceDefaults(projectDir) {
1080
1175
  const wsDefaults = {};
1081
1176
  try {
1082
1177
  const ws = resolveSkWorkspaceConfig(projectDir);
1083
- const p9 = ws.agent_config?.default ?? {};
1084
- if (p9.driver) wsDefaults.driver = p9.driver;
1085
- if (p9.provider) wsDefaults.provider = p9.provider;
1086
- if (p9.model) wsDefaults.model = p9.model;
1087
- if (p9.skills_dir) wsDefaults.skills_dir = p9.skills_dir;
1088
- if (p9.agents_dir) wsDefaults.agents_dir = p9.agents_dir;
1089
- if (p9.prompts_dir) wsDefaults.prompts_dir = p9.prompts_dir;
1178
+ const p8 = ws.agent_config?.default ?? {};
1179
+ if (p8.driver) wsDefaults.driver = p8.driver;
1180
+ if (p8.provider) wsDefaults.provider = p8.provider;
1181
+ if (p8.model) wsDefaults.model = p8.model;
1182
+ if (p8.skills_dir) wsDefaults.skills_dir = p8.skills_dir;
1183
+ if (p8.agents_dir) wsDefaults.agents_dir = p8.agents_dir;
1184
+ if (p8.prompts_dir) wsDefaults.prompts_dir = p8.prompts_dir;
1090
1185
  } catch {
1091
1186
  }
1092
1187
  return wsDefaults;
@@ -1819,7 +1914,7 @@ async function ensureTargetsRegistered(projectDir) {
1819
1914
  const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
1820
1915
  const config = resolveSkWorkspaceConfig2(projectDir);
1821
1916
  if (config.plugins && config.plugins.length > 0) {
1822
- const { ensurePluginsLoaded } = await import('../plugin-store-JWJHIPUT.js');
1917
+ const { ensurePluginsLoaded } = await import('../plugin-store-SGNJTBYS.js');
1823
1918
  const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
1824
1919
  for (const f of result.failed) logWarn(f.error);
1825
1920
  }
@@ -2028,10 +2123,10 @@ var MCP_SERVER_ENTRY = {
2028
2123
  function pluginDir(projectDir) {
2029
2124
  return path14__default.join(projectDir, ".claude", "plugins", "skaile");
2030
2125
  }
2031
- async function readJsonStrict(p9) {
2126
+ async function readJsonStrict(p8) {
2032
2127
  let raw;
2033
2128
  try {
2034
- raw = await fs6.readFile(p9, "utf-8");
2129
+ raw = await fs6.readFile(p8, "utf-8");
2035
2130
  } catch {
2036
2131
  return null;
2037
2132
  }
@@ -2039,13 +2134,13 @@ async function readJsonStrict(p9) {
2039
2134
  return JSON.parse(raw);
2040
2135
  } catch (e) {
2041
2136
  throw new Error(
2042
- `cannot parse ${p9}: ${e instanceof Error ? e.message : String(e)}; please fix or remove`
2137
+ `cannot parse ${p8}: ${e instanceof Error ? e.message : String(e)}; please fix or remove`
2043
2138
  );
2044
2139
  }
2045
2140
  }
2046
- async function writeJson(p9, value) {
2047
- await fs6.mkdir(path14__default.dirname(p9), { recursive: true });
2048
- await fs6.writeFile(p9, `${JSON.stringify(value, null, 2)}
2141
+ async function writeJson(p8, value) {
2142
+ await fs6.mkdir(path14__default.dirname(p8), { recursive: true });
2143
+ await fs6.writeFile(p8, `${JSON.stringify(value, null, 2)}
2049
2144
  `);
2050
2145
  }
2051
2146
  async function copyDir(src, dest) {
@@ -2100,7 +2195,7 @@ async function uninstall(projectDir) {
2100
2195
  let changed = false;
2101
2196
  const settings = await readJsonStrict(settingsPath);
2102
2197
  if (settings && Array.isArray(settings.plugins)) {
2103
- const next = settings.plugins.filter((p9) => p9 !== dir);
2198
+ const next = settings.plugins.filter((p8) => p8 !== dir);
2104
2199
  if (next.length !== settings.plugins.length) {
2105
2200
  changed = true;
2106
2201
  const updated = { ...settings, plugins: next };
@@ -2147,7 +2242,7 @@ async function enable(projectDir) {
2147
2242
  const settings = await readJsonStrict(settingsPath) ?? {};
2148
2243
  if (detected.method === "plugin") {
2149
2244
  const disabled2 = settings.disabledPlugins ?? [];
2150
- const next2 = disabled2.filter((p9) => p9 !== detected.pluginPath);
2245
+ const next2 = disabled2.filter((p8) => p8 !== detected.pluginPath);
2151
2246
  if (next2.length === disabled2.length) return { changed: false };
2152
2247
  const updated2 = { ...settings, disabledPlugins: next2 };
2153
2248
  if (next2.length === 0) delete updated2.disabledPlugins;
@@ -2228,10 +2323,10 @@ function buildEntry(projectDir) {
2228
2323
  env: { SKAILE_PROJECT_DIR: projectDir }
2229
2324
  };
2230
2325
  }
2231
- async function readConfig(p9) {
2326
+ async function readConfig(p8) {
2232
2327
  let raw;
2233
2328
  try {
2234
- raw = await fs6.readFile(p9, "utf-8");
2329
+ raw = await fs6.readFile(p8, "utf-8");
2235
2330
  } catch {
2236
2331
  return null;
2237
2332
  }
@@ -2239,41 +2334,41 @@ async function readConfig(p9) {
2239
2334
  return parse$1(raw);
2240
2335
  } catch (e) {
2241
2336
  throw new Error(
2242
- `cannot parse ${p9}: ${e instanceof Error ? e.message : String(e)}; please fix or remove`
2337
+ `cannot parse ${p8}: ${e instanceof Error ? e.message : String(e)}; please fix or remove`
2243
2338
  );
2244
2339
  }
2245
2340
  }
2246
- async function writeConfig(p9, value) {
2247
- await fs6.mkdir(path14__default.dirname(p9), { recursive: true });
2341
+ async function writeConfig(p8, value) {
2342
+ await fs6.mkdir(path14__default.dirname(p8), { recursive: true });
2248
2343
  const cleaned = {};
2249
2344
  for (const [k, v] of Object.entries(value)) {
2250
2345
  if (v === void 0) continue;
2251
2346
  cleaned[k] = v;
2252
2347
  }
2253
- await fs6.writeFile(p9, stringify$1(cleaned));
2348
+ await fs6.writeFile(p8, stringify$1(cleaned));
2254
2349
  }
2255
2350
  function configPath(projectDir) {
2256
2351
  return path14__default.join(projectDir, ".codex", "config.toml");
2257
2352
  }
2258
2353
  async function install2(projectDir) {
2259
- const p9 = configPath(projectDir);
2260
- const cfg = await readConfig(p9) ?? {};
2354
+ const p8 = configPath(projectDir);
2355
+ const cfg = await readConfig(p8) ?? {};
2261
2356
  const next = buildEntry(projectDir);
2262
2357
  const servers = { ...cfg.mcp_servers ?? {} };
2263
2358
  const previous = servers[SKAILE_MCP_NAME2];
2264
2359
  const matches = previous && JSON.stringify(previous) === JSON.stringify(next);
2265
2360
  let warning;
2266
2361
  if (previous && !matches) {
2267
- warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path14__default.relative(projectDir, p9)}`;
2362
+ warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path14__default.relative(projectDir, p8)}`;
2268
2363
  }
2269
2364
  if (matches) return { changed: false, method: "toml" };
2270
2365
  servers[SKAILE_MCP_NAME2] = next;
2271
- await writeConfig(p9, { ...cfg, mcp_servers: servers });
2366
+ await writeConfig(p8, { ...cfg, mcp_servers: servers });
2272
2367
  return { changed: true, method: "toml", warning };
2273
2368
  }
2274
2369
  async function uninstall2(projectDir) {
2275
- const p9 = configPath(projectDir);
2276
- const cfg = await readConfig(p9);
2370
+ const p8 = configPath(projectDir);
2371
+ const cfg = await readConfig(p8);
2277
2372
  if (!cfg?.mcp_servers || !(SKAILE_MCP_NAME2 in cfg.mcp_servers)) {
2278
2373
  return { changed: false };
2279
2374
  }
@@ -2281,15 +2376,15 @@ async function uninstall2(projectDir) {
2281
2376
  const updated = { ...cfg, mcp_servers: rest };
2282
2377
  if (Object.keys(rest).length === 0) delete updated.mcp_servers;
2283
2378
  if (Object.keys(updated).length === 0) {
2284
- await fs6.unlink(p9);
2379
+ await fs6.unlink(p8);
2285
2380
  } else {
2286
- await writeConfig(p9, updated);
2381
+ await writeConfig(p8, updated);
2287
2382
  }
2288
2383
  return { changed: true };
2289
2384
  }
2290
2385
  async function status2(projectDir) {
2291
- const p9 = configPath(projectDir);
2292
- const cfg = await readConfig(p9);
2386
+ const p8 = configPath(projectDir);
2387
+ const cfg = await readConfig(p8);
2293
2388
  const installed = !!(cfg?.mcp_servers && SKAILE_MCP_NAME2 in cfg.mcp_servers);
2294
2389
  if (!installed) {
2295
2390
  return {
@@ -2305,7 +2400,7 @@ async function status2(projectDir) {
2305
2400
  installed: "yes",
2306
2401
  enabled: "n/a",
2307
2402
  method: "mcp",
2308
- location: path14__default.relative(projectDir, p9)
2403
+ location: path14__default.relative(projectDir, p8)
2309
2404
  };
2310
2405
  }
2311
2406
  async function install3(projectDir) {
@@ -2522,7 +2617,7 @@ function printStatusTable(rows) {
2522
2617
  const widths = cols.map(
2523
2618
  (c) => Math.max(c.header.length, ...rows.map((r) => String(r[c.key] ?? "").length))
2524
2619
  );
2525
- const fmtRow = (parts) => parts.map((p9, i) => p9.padEnd(widths[i] ?? p9.length)).join(" ");
2620
+ const fmtRow = (parts) => parts.map((p8, i) => p8.padEnd(widths[i] ?? p8.length)).join(" ");
2526
2621
  console.log();
2527
2622
  console.log(` ${S.heading(fmtRow(cols.map((c) => c.header)))}`);
2528
2623
  for (const r of rows) {
@@ -2977,9 +3072,9 @@ function makeLibraryCommand() {
2977
3072
  logErr("`library commit` only applies to git-backed libraries.");
2978
3073
  process.exit(1);
2979
3074
  }
2980
- const { spawnSync: spawnSync2 } = await import('child_process');
2981
- spawnSync2("git", ["add", "-A"], { cwd: lib.path, stdio: "inherit" });
2982
- const r = spawnSync2("git", ["commit", "-m", opts.message], {
3075
+ const { spawnSync } = await import('child_process');
3076
+ spawnSync("git", ["add", "-A"], { cwd: lib.path, stdio: "inherit" });
3077
+ const r = spawnSync("git", ["commit", "-m", opts.message], {
2983
3078
  cwd: lib.path,
2984
3079
  stdio: "inherit"
2985
3080
  });
@@ -2997,8 +3092,8 @@ function makeLibraryCommand() {
2997
3092
  const { manager, close } = await openLibraryManager();
2998
3093
  try {
2999
3094
  const lib = await manager.requireLibrary(name);
3000
- const { spawnSync: spawnSync2 } = await import('child_process');
3001
- const r = spawnSync2("git", args, { cwd: lib.path, stdio: "inherit" });
3095
+ const { spawnSync } = await import('child_process');
3096
+ const r = spawnSync("git", args, { cwd: lib.path, stdio: "inherit" });
3002
3097
  process.exit(r.status ?? 0);
3003
3098
  } finally {
3004
3099
  close();
@@ -3261,6 +3356,8 @@ var ORIGIN_META = {
3261
3356
  var ORIGIN_ORDER = ["library", "source", "factory", "store"];
3262
3357
  var srcKey = (origin, publisher) => `${origin}:${publisher}`;
3263
3358
  var domainKey = (origin, publisher, slug) => `${origin}:${publisher}:dom:${slug}`;
3359
+ var repoKey = (org, repo) => `${org}/${repo}`;
3360
+ var srcDomainKey = (org, repo, slug) => `${org}/${repo}:dom:${slug}`;
3264
3361
  var NO_DOMAIN = "";
3265
3362
  var domainRegistry = /* @__PURE__ */ new Map();
3266
3363
  function relationBadge(relation) {
@@ -3289,12 +3386,20 @@ var state = {
3289
3386
  sourceRows: [],
3290
3387
  libraryRows: [],
3291
3388
  visibleRows: [],
3389
+ sourceTreeRows: [],
3390
+ visibleSourceRows: [],
3292
3391
  pendingAdds: /* @__PURE__ */ new Set(),
3293
3392
  pendingRemoves: /* @__PURE__ */ new Set(),
3294
3393
  collapsedOrigins: /* @__PURE__ */ new Set(),
3295
3394
  collapsedSources: /* @__PURE__ */ new Set(),
3296
3395
  collapsedDomains: /* @__PURE__ */ new Set(),
3297
3396
  expandedDomainInfo: /* @__PURE__ */ new Set(),
3397
+ seenDomains: /* @__PURE__ */ new Set(),
3398
+ collapsedSourceOrgs: /* @__PURE__ */ new Set(),
3399
+ collapsedSourceRepos: /* @__PURE__ */ new Set(),
3400
+ collapsedSourceDomains: /* @__PURE__ */ new Set(),
3401
+ expandedSourceDomainInfo: /* @__PURE__ */ new Set(),
3402
+ seenSourceDomains: /* @__PURE__ */ new Set(),
3298
3403
  seenOrigins: /* @__PURE__ */ new Set(),
3299
3404
  originFilter: null,
3300
3405
  message: "",
@@ -3308,13 +3413,13 @@ function buildVisibleRows(rows, collapsedOrigins, collapsedSources, collapsedDom
3308
3413
  if (row.type === "origin-header") return true;
3309
3414
  if (collapsedOrigins.has(origin)) return false;
3310
3415
  if (row.type === "publisher-header") return true;
3311
- if (collapsedSources.has(srcKey(origin, row.source ?? rowPublisher(row)))) return false;
3416
+ if (collapsedSources.has(srcKey(origin, rowGroup(row)))) return false;
3312
3417
  if (row.type === "domain-header") return true;
3313
3418
  if (row.type === "domain-info") {
3314
3419
  return !collapsedDomains.has(domainKey(origin, row.source, row.domainSlug ?? NO_DOMAIN));
3315
3420
  }
3316
3421
  if (row.underDomain) {
3317
- return !collapsedDomains.has(domainKey(origin, rowPublisher(row), rowDomain(row)));
3422
+ return !collapsedDomains.has(domainKey(origin, rowGroup(row), rowDomain(row)));
3318
3423
  }
3319
3424
  return true;
3320
3425
  });
@@ -3328,6 +3433,80 @@ function domainAssetRefs(rows, origin, publisher, slug) {
3328
3433
  function sourceAssetRefs(rows, origin, source) {
3329
3434
  return refsOf(rows.filter((r) => isAsset(r) && inSource(r, origin, source)));
3330
3435
  }
3436
+ function buildSourceTreeRows(assetRows, registered = []) {
3437
+ const byOrg = /* @__PURE__ */ new Map();
3438
+ const ensure = (org, repo) => {
3439
+ if (!byOrg.has(org)) byOrg.set(org, /* @__PURE__ */ new Map());
3440
+ const byRepo = byOrg.get(org);
3441
+ if (!byRepo.has(repo)) byRepo.set(repo, /* @__PURE__ */ new Map());
3442
+ return byRepo.get(repo);
3443
+ };
3444
+ for (const r of assetRows) {
3445
+ if (!isAsset(r) || rowOrigin(r) !== "source") continue;
3446
+ const org = rowOrg(r);
3447
+ const repo = rowGroup(r);
3448
+ const slug = rowDomain(r);
3449
+ const byDomain = ensure(org, repo);
3450
+ if (!byDomain.has(slug)) byDomain.set(slug, []);
3451
+ byDomain.get(slug).push(r);
3452
+ }
3453
+ for (const { org, repo } of registered) ensure(org, repo);
3454
+ if (byOrg.size === 0) return [];
3455
+ const rows = [{ type: "source-root" }];
3456
+ for (const org of [...byOrg.keys()].sort((a, b) => a.localeCompare(b))) {
3457
+ rows.push({ type: "org-header", origin: "source", org });
3458
+ const byRepo = byOrg.get(org);
3459
+ for (const repo of [...byRepo.keys()].sort((a, b) => a.localeCompare(b))) {
3460
+ rows.push({ type: "repo-header", origin: "source", org, source: repo });
3461
+ const byDomain = byRepo.get(repo);
3462
+ const loose = byDomain.get(NO_DOMAIN);
3463
+ if (loose) for (const a of loose) rows.push({ ...a, org });
3464
+ for (const slug of sortedDomainSlugs([...byDomain.keys()])) {
3465
+ const meta = domainRegistry.get(slug);
3466
+ rows.push({ type: "domain-header", origin: "source", org, source: repo, domainSlug: slug });
3467
+ if (meta?.description) {
3468
+ rows.push({ type: "domain-info", origin: "source", org, source: repo, domainSlug: slug });
3469
+ }
3470
+ for (const a of byDomain.get(slug)) rows.push({ ...a, org });
3471
+ }
3472
+ }
3473
+ }
3474
+ return rows;
3475
+ }
3476
+ function buildVisibleSourceRows(rows, collapsedOrgs, collapsedRepos, collapsedDomains) {
3477
+ return rows.filter((row) => {
3478
+ if (row.type === "source-root" || row.type === "org-header") return true;
3479
+ const org = row.org ?? UNKNOWN_ORG;
3480
+ if (collapsedOrgs.has(org)) return false;
3481
+ if (row.type === "repo-header") return true;
3482
+ if (collapsedRepos.has(repoKey(org, row.source))) return false;
3483
+ if (row.type === "domain-header") return true;
3484
+ if (row.type === "domain-info") {
3485
+ return !collapsedDomains.has(srcDomainKey(org, row.source, row.domainSlug ?? NO_DOMAIN));
3486
+ }
3487
+ if (row.underDomain) {
3488
+ return !collapsedDomains.has(srcDomainKey(org, rowGroup(row), rowDomain(row)));
3489
+ }
3490
+ return true;
3491
+ });
3492
+ }
3493
+ function sourceOrgRefs(rows, org) {
3494
+ return refsOf(rows.filter((r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org));
3495
+ }
3496
+ function sourceRepoRefs(rows, org, repo) {
3497
+ return refsOf(
3498
+ rows.filter(
3499
+ (r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org && rowGroup(r) === repo
3500
+ )
3501
+ );
3502
+ }
3503
+ function sourceDomainRefs(rows, org, repo, slug) {
3504
+ return refsOf(
3505
+ rows.filter(
3506
+ (r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org && rowGroup(r) === repo && rowDomain(r) === slug
3507
+ )
3508
+ );
3509
+ }
3331
3510
  function isAsset(r) {
3332
3511
  return r.type === "asset";
3333
3512
  }
@@ -3337,14 +3516,24 @@ function rowOrigin(r) {
3337
3516
  function rowPublisher(r) {
3338
3517
  return r.entry?.publisher || "other";
3339
3518
  }
3519
+ function rowGroup(r) {
3520
+ return r.source ?? rowPublisher(r);
3521
+ }
3340
3522
  function rowDomain(r) {
3341
3523
  return r.entry?.domainSlug || NO_DOMAIN;
3342
3524
  }
3525
+ var UNKNOWN_ORG = "(unknown)";
3526
+ function rowOrg(r) {
3527
+ if (r.org) return r.org;
3528
+ const repo = r.entry?.repo;
3529
+ if (repo?.includes("/")) return repo.slice(0, repo.indexOf("/"));
3530
+ return UNKNOWN_ORG;
3531
+ }
3343
3532
  function refsOf(rows) {
3344
3533
  return rows.map((r) => assetRefOf(r)).filter((ref) => ref !== null);
3345
3534
  }
3346
3535
  function inSource(r, origin, source) {
3347
- return rowOrigin(r) === origin && rowPublisher(r) === source;
3536
+ return rowOrigin(r) === origin && rowGroup(r) === source;
3348
3537
  }
3349
3538
  function inDomain(r, origin, publisher, slug) {
3350
3539
  if (!inSource(r, origin, publisher)) return false;
@@ -3405,7 +3594,7 @@ function actOnHeader(row, action3) {
3405
3594
  return row.type === "domain-header" || row.type === "domain-info";
3406
3595
  }
3407
3596
  async function loadAssets() {
3408
- const { gatherAssetFeeds } = await import('../asset-feeds-O6R6J4RI.js');
3597
+ const { gatherAssetFeeds } = await import('../asset-feeds-OEGJ6NOF.js');
3409
3598
  const { entries, domains, notes } = await gatherAssetFeeds(am, am.projectDir);
3410
3599
  if (notes.length > 0) {
3411
3600
  state.message = notes.map((n) => `[${n.feed}] ${n.message}`).join(" \u2022 ");
@@ -3417,11 +3606,60 @@ async function loadAssets() {
3417
3606
  state.assetRows = rows;
3418
3607
  reconcileCollapsedSets(rows);
3419
3608
  rebuildVisible();
3609
+ rebuildSourceTree();
3610
+ }
3611
+ function rebuildSourceTree() {
3612
+ const registered = state.sourceRows.map((s) => sourceOrgRepo(s)).filter((x) => x !== null);
3613
+ state.sourceTreeRows = buildSourceTreeRows(state.assetRows, registered);
3614
+ reconcileSourceCollapsedSets(state.sourceTreeRows);
3615
+ rebuildVisibleSources();
3616
+ }
3617
+ function sourceOrgRepo(s) {
3618
+ const parts = s.path.split(path14__default.sep).filter(Boolean);
3619
+ if (parts.length < 2) return null;
3620
+ return { org: parts[parts.length - 2], repo: parts[parts.length - 1] };
3621
+ }
3622
+ function reconcileSourceCollapsedSets(rows) {
3623
+ const orgKeys = new Set(rows.filter((r) => r.type === "org-header").map((r) => r.org));
3624
+ const repoKeys = new Set(
3625
+ rows.filter((r) => r.type === "repo-header").map((r) => repoKey(r.org, r.source))
3626
+ );
3627
+ const domainKeys = new Set(
3628
+ rows.filter((r) => r.type === "domain-header").map((r) => srcDomainKey(r.org, r.source, r.domainSlug ?? NO_DOMAIN))
3629
+ );
3630
+ for (const k of state.collapsedSourceOrgs)
3631
+ if (!orgKeys.has(k)) state.collapsedSourceOrgs.delete(k);
3632
+ for (const k of state.collapsedSourceRepos) {
3633
+ if (!repoKeys.has(k)) state.collapsedSourceRepos.delete(k);
3634
+ }
3635
+ for (const k of domainKeys) {
3636
+ if (!state.seenSourceDomains.has(k)) {
3637
+ state.collapsedSourceDomains.add(k);
3638
+ state.seenSourceDomains.add(k);
3639
+ }
3640
+ }
3641
+ for (const k of state.collapsedSourceDomains) {
3642
+ if (!domainKeys.has(k)) state.collapsedSourceDomains.delete(k);
3643
+ }
3644
+ for (const k of state.expandedSourceDomainInfo) {
3645
+ if (!domainKeys.has(k)) state.expandedSourceDomainInfo.delete(k);
3646
+ }
3647
+ for (const k of state.seenSourceDomains)
3648
+ if (!domainKeys.has(k)) state.seenSourceDomains.delete(k);
3649
+ }
3650
+ function rebuildVisibleSources() {
3651
+ state.visibleSourceRows = buildVisibleSourceRows(
3652
+ state.sourceTreeRows,
3653
+ state.collapsedSourceOrgs,
3654
+ state.collapsedSourceRepos,
3655
+ state.collapsedSourceDomains
3656
+ );
3657
+ clampCursor();
3420
3658
  }
3421
3659
  function groupEntriesByOriginPublisherDomain(entries) {
3422
3660
  const byOrigin = /* @__PURE__ */ new Map();
3423
- for (const { origin, entry } of entries) {
3424
- const publisher = entry.publisher || "other";
3661
+ for (const { origin, entry, group } of entries) {
3662
+ const publisher = group || entry.publisher || "other";
3425
3663
  const slug = entry.domainSlug || NO_DOMAIN;
3426
3664
  if (!byOrigin.has(origin)) byOrigin.set(origin, /* @__PURE__ */ new Map());
3427
3665
  const byPublisher = byOrigin.get(origin);
@@ -3444,29 +3682,40 @@ function buildAssetRowsFromGroups(byOrigin, installed) {
3444
3682
  const sortItems = (items) => items.sort(
3445
3683
  (a, b) => a.kind !== b.kind ? a.kind.localeCompare(b.kind) : a.name.localeCompare(b.name)
3446
3684
  );
3447
- const pushAsset = (origin, entry, underDomain, seq) => {
3685
+ const pushAsset = (origin, group, entry, underDomain, seq) => {
3448
3686
  const ref = `${entry.kind}:${entry.name}`;
3449
- rows.push({ type: "asset", origin, entry, installed: installed.has(ref), underDomain, seq });
3687
+ rows.push({
3688
+ type: "asset",
3689
+ origin,
3690
+ source: group,
3691
+ org: entry.repo?.includes("/") ? entry.repo.slice(0, entry.repo.indexOf("/")) : void 0,
3692
+ entry,
3693
+ installed: installed.has(ref),
3694
+ underDomain,
3695
+ seq
3696
+ });
3450
3697
  };
3451
3698
  for (const origin of ORIGIN_ORDER) {
3452
- const byPublisher = byOrigin.get(origin);
3453
- if (!byPublisher || byPublisher.size === 0) continue;
3699
+ const byGroup = byOrigin.get(origin);
3700
+ if (!byGroup || byGroup.size === 0) continue;
3454
3701
  rows.push({ type: "origin-header", origin });
3455
- for (const [publisher, byDomain] of [...byPublisher.entries()].sort(
3702
+ for (const [group, byDomain] of [...byGroup.entries()].sort(
3456
3703
  (a, b) => a[0].localeCompare(b[0])
3457
3704
  )) {
3458
- rows.push({ type: "publisher-header", origin, source: publisher });
3705
+ rows.push({ type: "publisher-header", origin, source: group });
3459
3706
  const loose = byDomain.get(NO_DOMAIN);
3460
- if (loose) for (const entry of sortItems(loose)) pushAsset(origin, entry, false);
3707
+ if (loose) for (const entry of sortItems(loose)) pushAsset(origin, group, entry, false);
3461
3708
  for (const slug of sortedDomainSlugs([...byDomain.keys()])) {
3462
3709
  const meta = domainRegistry.get(slug);
3463
- rows.push({ type: "domain-header", origin, source: publisher, domainSlug: slug });
3710
+ rows.push({ type: "domain-header", origin, source: group, domainSlug: slug });
3464
3711
  if (meta?.description) {
3465
- rows.push({ type: "domain-info", origin, source: publisher, domainSlug: slug });
3712
+ rows.push({ type: "domain-info", origin, source: group, domainSlug: slug });
3466
3713
  }
3467
3714
  const items = sortItems(byDomain.get(slug));
3468
3715
  const sequenced = meta?.relation === "sequence";
3469
- items.forEach((entry, i) => pushAsset(origin, entry, true, sequenced ? i + 1 : void 0));
3716
+ items.forEach(
3717
+ (entry, i) => pushAsset(origin, group, entry, true, sequenced ? i + 1 : void 0)
3718
+ );
3470
3719
  }
3471
3720
  }
3472
3721
  }
@@ -3493,17 +3742,26 @@ function reconcileCollapsedSets(rows) {
3493
3742
  const newDomainKeys = new Set(
3494
3743
  rows.filter((r) => r.type === "domain-header").map((r) => domainKey(rowOrigin(r), r.source, r.domainSlug ?? NO_DOMAIN))
3495
3744
  );
3745
+ for (const k of newDomainKeys) {
3746
+ if (!state.seenDomains.has(k)) {
3747
+ state.collapsedDomains.add(k);
3748
+ state.seenDomains.add(k);
3749
+ }
3750
+ }
3496
3751
  for (const d of state.collapsedDomains) {
3497
3752
  if (!newDomainKeys.has(d)) state.collapsedDomains.delete(d);
3498
3753
  }
3499
3754
  for (const d of state.expandedDomainInfo) {
3500
3755
  if (!newDomainKeys.has(d)) state.expandedDomainInfo.delete(d);
3501
3756
  }
3757
+ for (const d of state.seenDomains) {
3758
+ if (!newDomainKeys.has(d)) state.seenDomains.delete(d);
3759
+ }
3502
3760
  }
3503
3761
  async function loadSourcesAndLibraries() {
3504
3762
  try {
3505
3763
  const [{ openLibraryManager: openLibraryManager2 }, { skaileHomeDir }, { getGlobalCacheDir: getGlobalCacheDir2 }] = await Promise.all([
3506
- import('../open-library-TXJMFG34.js'),
3764
+ import('../open-library-ERKRGH4B.js'),
3507
3765
  import('../library/index.js'),
3508
3766
  import('../core/index.js')
3509
3767
  ]);
@@ -3539,6 +3797,7 @@ async function loadSourcesAndLibraries() {
3539
3797
  state.sourceRows = [];
3540
3798
  state.libraryRows = [];
3541
3799
  }
3800
+ rebuildSourceTree();
3542
3801
  }
3543
3802
  function rebuildVisible() {
3544
3803
  state.visibleRows = buildVisibleRows(
@@ -3574,11 +3833,11 @@ var TABS = {
3574
3833
  },
3575
3834
  sources: {
3576
3835
  label: "Sources",
3577
- rowCount: () => state.sourceRows.length,
3578
- selectableCount: () => state.sourceRows.length,
3836
+ rowCount: () => state.visibleSourceRows.length,
3837
+ selectableCount: () => state.sourceTreeRows.filter(isAsset).length,
3579
3838
  emptyMsg: " No sources registered. Run `skaile source add <git-url>` from the shell to track a github repo.",
3580
- renderRow: (i, sel) => renderSourceRow(state.sourceRows[i], sel),
3581
- footer: " \u2191\u2193 navigate Tab switch q quit (use `skaile source \u2026` from the shell for CRUD)"
3839
+ renderRow: (i, sel) => renderSourceTreeRow(state.visibleSourceRows[i], sel),
3840
+ footer: " \u2191\u2193/jk nav \u2190/\u2192 collapse/expand [space/+/-] select [a/\u21B5] apply [d] domain info [i] info Tab [q] quit"
3582
3841
  },
3583
3842
  libraries: {
3584
3843
  label: "Libraries",
@@ -3642,8 +3901,9 @@ function groupStatus(refs) {
3642
3901
  }
3643
3902
  function renderHeaderLine(opts) {
3644
3903
  const indicator = opts.collapsed ? "\u25B6" : "\u25BC";
3645
- const total = state.assetRows.filter(opts.match).length;
3646
- const installed = state.assetRows.filter((r) => opts.match(r) && r.installed).length;
3904
+ const countRows = opts.rows ?? state.assetRows;
3905
+ const total = countRows.filter(opts.match).length;
3906
+ const installed = countRows.filter((r) => opts.match(r) && r.installed).length;
3647
3907
  const [add, remove] = pendingCountsFor(opts.match);
3648
3908
  let count = String(installed);
3649
3909
  if (add > 0) count += pc5.green(`+${add}`);
@@ -3682,8 +3942,8 @@ function renderAssetRow(row, selected) {
3682
3942
  const slug = row.domainSlug ?? NO_DOMAIN;
3683
3943
  const meta = domainRegistry.get(slug);
3684
3944
  const title = meta?.title || slug || "(no domain)";
3685
- const badge2 = relationBadge(meta?.relation);
3686
- const label = `${pc5.magenta("\u25C8")} ${pc5.bold(title)}${badge2 ? ` ${badge2}` : ""}`;
3945
+ const badge = relationBadge(meta?.relation);
3946
+ const label = `${pc5.magenta("\u25C8")} ${pc5.bold(title)}${badge ? ` ${badge}` : ""}`;
3687
3947
  return renderHeaderLine({
3688
3948
  indent: " ".repeat(5),
3689
3949
  collapsed: state.collapsedDomains.has(domainKey(origin, row.source, slug)),
@@ -3697,15 +3957,18 @@ function renderAssetRow(row, selected) {
3697
3957
  const origin = rowOrigin(row);
3698
3958
  const slug = row.domainSlug ?? NO_DOMAIN;
3699
3959
  const key = domainKey(origin, row.source, slug);
3700
- const line2 = renderDomainInfoLine(
3960
+ const line = renderDomainInfoLine(
3701
3961
  domainRegistry.get(slug),
3702
3962
  origin,
3703
3963
  row.source,
3704
3964
  slug,
3705
3965
  state.expandedDomainInfo.has(key)
3706
3966
  );
3707
- return selected ? pc5.inverse(line2.padEnd(state.cols)) : line2;
3967
+ return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
3708
3968
  }
3969
+ return renderAssetLeaf(row, selected);
3970
+ }
3971
+ function renderAssetLeaf(row, selected, looseIndent = 5) {
3709
3972
  const e = row.entry;
3710
3973
  const ref = assetRefOf(row) ?? "";
3711
3974
  let status4;
@@ -3727,10 +3990,86 @@ function renderAssetRow(row, selected) {
3727
3990
  const repoBadge = repoBare ? pc5.dim(` \xB7${repoBare}`) : "";
3728
3991
  const repoWidth = repoBare ? repoBare.length + 2 : 0;
3729
3992
  const desc = e.description?.slice(0, Math.max(0, state.cols - 56 - badgeWidth - hintWidth - repoWidth)) ?? "";
3730
- const indent = " ".repeat(row.underDomain ? 7 : 5);
3993
+ const indent = " ".repeat(looseIndent + (row.underDomain ? 2 : 0));
3731
3994
  const line = `${indent}${status4} ${hint}${kind} ${name} ${badge}${pc5.dim(desc)}${repoBadge}`;
3732
3995
  return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
3733
3996
  }
3997
+ function renderSourceTreeRow(row, selected) {
3998
+ if (row.type === "source-root") {
3999
+ const total = state.sourceTreeRows.filter(isAsset).length;
4000
+ const meta = ORIGIN_META.source;
4001
+ const line = ` \u25BC ${meta.icon} ${pc5.bold(pc5.cyan(meta.label))} (${total} assets)`;
4002
+ return selected ? pc5.bgWhite(pc5.black(`${line} `.padEnd(state.cols))) : line;
4003
+ }
4004
+ if (row.type === "org-header") {
4005
+ const org = row.org;
4006
+ return renderHeaderLine({
4007
+ indent: " ".repeat(3),
4008
+ collapsed: state.collapsedSourceOrgs.has(org),
4009
+ match: (r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org,
4010
+ refs: sourceOrgRefs(state.sourceTreeRows, org),
4011
+ label: pc5.bold(pc5.cyan(org)),
4012
+ selected,
4013
+ rows: state.sourceTreeRows
4014
+ });
4015
+ }
4016
+ if (row.type === "repo-header") {
4017
+ const org = row.org;
4018
+ const repo = row.source;
4019
+ return renderHeaderLine({
4020
+ indent: " ".repeat(5),
4021
+ collapsed: state.collapsedSourceRepos.has(repoKey(org, repo)),
4022
+ match: (r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org && rowGroup(r) === repo,
4023
+ refs: sourceRepoRefs(state.sourceTreeRows, org, repo),
4024
+ label: pc5.bold(repo),
4025
+ selected,
4026
+ rows: state.sourceTreeRows
4027
+ });
4028
+ }
4029
+ if (row.type === "domain-header") {
4030
+ const org = row.org;
4031
+ const repo = row.source;
4032
+ const slug = row.domainSlug ?? NO_DOMAIN;
4033
+ const meta = domainRegistry.get(slug);
4034
+ const title = meta?.title || slug || "(no domain)";
4035
+ const badge = relationBadge(meta?.relation);
4036
+ const label = `${pc5.magenta("\u25C8")} ${pc5.bold(title)}${badge ? ` ${badge}` : ""}`;
4037
+ return renderHeaderLine({
4038
+ indent: " ".repeat(7),
4039
+ collapsed: state.collapsedSourceDomains.has(srcDomainKey(org, repo, slug)),
4040
+ match: (r) => isAsset(r) && rowOrigin(r) === "source" && rowOrg(r) === org && rowGroup(r) === repo && rowDomain(r) === slug,
4041
+ refs: sourceDomainRefs(state.sourceTreeRows, org, repo, slug),
4042
+ label,
4043
+ selected,
4044
+ rows: state.sourceTreeRows
4045
+ });
4046
+ }
4047
+ if (row.type === "domain-info") {
4048
+ const slug = row.domainSlug ?? NO_DOMAIN;
4049
+ const meta = domainRegistry.get(slug);
4050
+ const members = sourceDomainRefs(state.sourceTreeRows, row.org, row.source, slug).length;
4051
+ const key = srcDomainKey(row.org, row.source, slug);
4052
+ const line = renderSourceDomainInfoLine(meta, members, state.expandedSourceDomainInfo.has(key));
4053
+ return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
4054
+ }
4055
+ return renderAssetLeaf(row, selected, 7);
4056
+ }
4057
+ function renderSourceDomainInfoLine(meta, members, expanded) {
4058
+ const indent = " ".repeat(9);
4059
+ const desc = meta?.description ?? "";
4060
+ if (!expanded) {
4061
+ const budget2 = Math.max(0, state.cols - indent.length - 12);
4062
+ const shown2 = desc.length > budget2 ? `${desc.slice(0, Math.max(0, budget2 - 1))}\u2026` : desc;
4063
+ return pc5.dim(`${indent}\u24D8 ${shown2} [d]`);
4064
+ }
4065
+ const parts = [desc, `${members} members`];
4066
+ if (meta?.recommendedRef) parts.push(`\u2605 ${meta.recommendedRef}`);
4067
+ if (meta?.sidecarSource) parts.push(`sidecar ${meta.sidecarSource}`);
4068
+ const full = parts.join(" \xB7 ");
4069
+ const budget = Math.max(0, state.cols - indent.length - 3);
4070
+ const shown = full.length > budget ? `${full.slice(0, Math.max(0, budget - 1))}\u2026` : full;
4071
+ return pc5.dim(`${indent}\u24D8 ${shown}`);
4072
+ }
3734
4073
  function renderDomainInfoLine(meta, origin, publisher, slug, expanded) {
3735
4074
  const indent = " ".repeat(7);
3736
4075
  const desc = meta?.description ?? "";
@@ -3748,10 +4087,6 @@ function renderDomainInfoLine(meta, origin, publisher, slug, expanded) {
3748
4087
  const shown = full.length > budget ? `${full.slice(0, Math.max(0, budget - 1))}\u2026` : full;
3749
4088
  return pc5.dim(`${indent}\u24D8 ${shown}`);
3750
4089
  }
3751
- function renderSourceRow(row, selected) {
3752
- const line = ` ${S.cmd(fitWidth(row.name, 20))} ${pc5.dim(row.ownership.padEnd(12))} ${pc5.dim(`${row.assetCount} assets`)} ${pc5.dim(row.path)}`;
3753
- return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
3754
- }
3755
4090
  function renderLibraryRow(row, selected) {
3756
4091
  const mark = row.isDefault ? pc5.green("\u25B8") : " ";
3757
4092
  const line = `${mark} ${S.cmd(fitWidth(row.name, 16))} ${pc5.dim(row.backend.padEnd(7))} ${pc5.dim(row.ownership.padEnd(12))} ${pc5.dim(`${row.assetCount} assets`)}`;
@@ -3855,19 +4190,15 @@ async function syncAll() {
3855
4190
  "Sync is not yet driven from the manage TUI. Run `skaile source sync` (sources) or `skaile library sync <name>` (git-backed libraries) from the shell."
3856
4191
  );
3857
4192
  }
3858
- function sourceShellHint(action3) {
3859
- state.message = pc5.yellow(
3860
- `${action3} is a shell command. Run \`skaile source \u2026\` from the shell.`
3861
- );
3862
- }
3863
4193
  function libraryShellHint(action3) {
3864
4194
  state.message = pc5.yellow(
3865
4195
  `${action3} is a shell command. Run \`skaile library \u2026\` from the shell.`
3866
4196
  );
3867
4197
  }
3868
4198
  async function showInfo() {
3869
- if (state.tab !== "assets") return;
3870
- const row = state.visibleRows[state.cursor];
4199
+ const rows = state.tab === "sources" ? state.visibleSourceRows : state.visibleRows;
4200
+ if (state.tab !== "assets" && state.tab !== "sources") return;
4201
+ const row = rows[state.cursor];
3871
4202
  if (row?.type !== "asset") return;
3872
4203
  const e = row.entry;
3873
4204
  clearScreen();
@@ -3995,6 +4326,115 @@ function toggleDomainInfoUnderCursor() {
3995
4326
  else state.expandedDomainInfo.add(key);
3996
4327
  rebuildVisible();
3997
4328
  }
4329
+ function actOnSourceHeader(row, action3) {
4330
+ if (row.type === "org-header") {
4331
+ bulkSelection(sourceOrgRefs(state.sourceTreeRows, row.org), action3);
4332
+ return true;
4333
+ }
4334
+ if (row.type === "repo-header") {
4335
+ bulkSelection(sourceRepoRefs(state.sourceTreeRows, row.org, row.source), action3);
4336
+ return true;
4337
+ }
4338
+ return row.type === "source-root" || row.type === "domain-header" || row.type === "domain-info";
4339
+ }
4340
+ function selectSourceUnderCursor(action3) {
4341
+ const row = state.visibleSourceRows[state.cursor];
4342
+ if (!row) return;
4343
+ if (actOnSourceHeader(row, action3 === "toggle" ? "toggle" : action3)) return;
4344
+ const ref = assetRefOf(row);
4345
+ if (!ref) return;
4346
+ if (action3 === "toggle") {
4347
+ setSelection(ref, "toggle");
4348
+ } else if (action3 === "add") {
4349
+ setSelection(ref, state.pendingAdds.has(ref) ? "clear" : "add");
4350
+ } else {
4351
+ setSelection(ref, state.pendingRemoves.has(ref) ? "clear" : "remove");
4352
+ }
4353
+ }
4354
+ function expandSourceUnderCursor() {
4355
+ const row = state.visibleSourceRows[state.cursor];
4356
+ if (!row) return;
4357
+ if (row.type === "org-header" && state.collapsedSourceOrgs.has(row.org)) {
4358
+ state.collapsedSourceOrgs.delete(row.org);
4359
+ rebuildVisibleSources();
4360
+ } else if (row.type === "repo-header") {
4361
+ const k = repoKey(row.org, row.source);
4362
+ if (state.collapsedSourceRepos.has(k)) {
4363
+ state.collapsedSourceRepos.delete(k);
4364
+ rebuildVisibleSources();
4365
+ }
4366
+ } else if (row.type === "domain-header") {
4367
+ const k = srcDomainKey(row.org, row.source, row.domainSlug ?? NO_DOMAIN);
4368
+ if (state.collapsedSourceDomains.has(k)) {
4369
+ state.collapsedSourceDomains.delete(k);
4370
+ rebuildVisibleSources();
4371
+ }
4372
+ }
4373
+ }
4374
+ function collapseOrJumpSourceUnderCursor() {
4375
+ const row = state.visibleSourceRows[state.cursor];
4376
+ if (!row) return;
4377
+ if (row.type === "org-header") {
4378
+ if (!state.collapsedSourceOrgs.has(row.org)) {
4379
+ state.collapsedSourceOrgs.add(row.org);
4380
+ rebuildVisibleSources();
4381
+ }
4382
+ return;
4383
+ }
4384
+ if (row.type === "repo-header") {
4385
+ const k = repoKey(row.org, row.source);
4386
+ if (!state.collapsedSourceRepos.has(k)) {
4387
+ state.collapsedSourceRepos.add(k);
4388
+ rebuildVisibleSources();
4389
+ } else {
4390
+ const idx2 = findLastIndex(
4391
+ state.visibleSourceRows,
4392
+ state.cursor,
4393
+ (r) => r.type === "org-header"
4394
+ );
4395
+ if (idx2 >= 0) state.cursor = idx2;
4396
+ }
4397
+ return;
4398
+ }
4399
+ if (row.type === "domain-header") {
4400
+ const k = srcDomainKey(row.org, row.source, row.domainSlug ?? NO_DOMAIN);
4401
+ if (!state.collapsedSourceDomains.has(k)) {
4402
+ state.collapsedSourceDomains.add(k);
4403
+ rebuildVisibleSources();
4404
+ } else {
4405
+ const idx2 = findLastIndex(
4406
+ state.visibleSourceRows,
4407
+ state.cursor,
4408
+ (r) => r.type === "repo-header"
4409
+ );
4410
+ if (idx2 >= 0) state.cursor = idx2;
4411
+ }
4412
+ return;
4413
+ }
4414
+ const idx = findLastIndex(
4415
+ state.visibleSourceRows,
4416
+ state.cursor,
4417
+ (r) => r.type === "domain-header" || r.type === "repo-header" || r.type === "org-header"
4418
+ );
4419
+ if (idx >= 0) state.cursor = idx;
4420
+ }
4421
+ function toggleSourceDomainInfoUnderCursor() {
4422
+ const row = state.visibleSourceRows[state.cursor];
4423
+ if (!row) return;
4424
+ let key = null;
4425
+ if (row.type === "domain-header" || row.type === "domain-info") {
4426
+ key = srcDomainKey(row.org, row.source, row.domainSlug ?? NO_DOMAIN);
4427
+ } else if (row.type === "asset" && row.underDomain) {
4428
+ key = srcDomainKey(rowOrg(row), rowGroup(row), rowDomain(row));
4429
+ }
4430
+ if (!key) {
4431
+ state.message = pc5.dim("No domain here \u2014 [d] opens a domain's info region.");
4432
+ return;
4433
+ }
4434
+ if (state.expandedSourceDomainInfo.has(key)) state.expandedSourceDomainInfo.delete(key);
4435
+ else state.expandedSourceDomainInfo.add(key);
4436
+ rebuildVisibleSources();
4437
+ }
3998
4438
  function findLastIndex(arr, endExclusive, pred) {
3999
4439
  for (let i = Math.min(endExclusive, arr.length) - 1; i >= 0; i--) {
4000
4440
  if (pred(arr[i])) return i;
@@ -4022,9 +4462,12 @@ var KEYMAP = [
4022
4462
  { keys: [" "], run: () => void nextTab() },
4023
4463
  { keys: ["\x1B[A", "k"], run: () => void moveCursor(-1) },
4024
4464
  { keys: ["\x1B[B", "j"], run: () => void moveCursor(1) },
4025
- // Collapse / expand — assets tab only
4465
+ // Collapse / expand — assets tab
4026
4466
  { keys: ["\x1B[C"], when: TAB_ASSETS, run: expandUnderCursor },
4027
4467
  { keys: ["\x1B[D"], when: TAB_ASSETS, run: collapseOrJumpUnderCursor },
4468
+ // Collapse / expand — sources tab
4469
+ { keys: ["\x1B[C"], when: TAB_SOURCES, run: expandSourceUnderCursor },
4470
+ { keys: ["\x1B[D"], when: TAB_SOURCES, run: collapseOrJumpSourceUnderCursor },
4028
4471
  // + : assets → bulk-add or single-add toggle
4029
4472
  {
4030
4473
  keys: ["+"],
@@ -4038,10 +4481,13 @@ var KEYMAP = [
4038
4481
  }
4039
4482
  }
4040
4483
  },
4041
- // Sources tab: +/-/n/r/x map to shell hints in the minimal scaffold.
4042
- { keys: ["+", "n", "a"], when: TAB_SOURCES, run: () => sourceShellHint("Adding a source") },
4043
- { keys: ["-", "r", "x"], when: TAB_SOURCES, run: () => sourceShellHint("Removing a source") },
4044
- { keys: ["\r", "\n"], when: TAB_SOURCES, run: () => sourceShellHint("Source actions") },
4484
+ // Sources tab: + / - / space select (asset leaf or org/repo bulk header).
4485
+ { keys: ["+"], when: TAB_SOURCES, run: () => selectSourceUnderCursor("add") },
4486
+ { keys: ["-"], when: TAB_SOURCES, run: () => selectSourceUnderCursor("remove") },
4487
+ { keys: [" "], when: TAB_SOURCES, run: () => selectSourceUnderCursor("toggle") },
4488
+ { keys: ["a", "\r", "\n"], when: TAB_SOURCES, run: applyChanges },
4489
+ { keys: ["i"], when: TAB_SOURCES, run: showInfo },
4490
+ { keys: ["d"], when: TAB_SOURCES, run: toggleSourceDomainInfoUnderCursor },
4045
4491
  // Libraries tab: +/-/n/r/x/d/enter map to shell hints in the minimal scaffold.
4046
4492
  {
4047
4493
  keys: ["+", "n", "a"],
@@ -4151,8 +4597,8 @@ function makeManageCommand() {
4151
4597
  }
4152
4598
  function makeMcpServerCommand() {
4153
4599
  return new Command("mcp-server").description("Start skaile workspace MCP server (stdio transport)").option("--project-dir <path>", "Project directory (default: cwd)", process.cwd()).action(async (opts) => {
4154
- const path37 = await import('path');
4155
- const projectDir = path37.default.resolve(opts.projectDir);
4600
+ const path36 = await import('path');
4601
+ const projectDir = path36.default.resolve(opts.projectDir);
4156
4602
  const { LogStore, StdoutSink, registerLogStore } = await import('../core/logging.js');
4157
4603
  registerLogStore(
4158
4604
  new LogStore({
@@ -4368,7 +4814,7 @@ function action2(fn) {
4368
4814
  };
4369
4815
  }
4370
4816
  async function reconcileAndReport(projectDir, plugins) {
4371
- const { reconcilePlugins } = await import('../plugin-store-JWJHIPUT.js');
4817
+ const { reconcilePlugins } = await import('../plugin-store-SGNJTBYS.js');
4372
4818
  if (plugins.length === 0) {
4373
4819
  logInfo("No plugins declared \u2014 nothing to reconcile.");
4374
4820
  return;
@@ -4384,7 +4830,7 @@ async function reconcileAndReport(projectDir, plugins) {
4384
4830
  async function runInstall2(spec, opts) {
4385
4831
  const projectDir = path14__default.resolve(opts.projectDir);
4386
4832
  const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
4387
- const { specName } = await import('../plugin-store-JWJHIPUT.js');
4833
+ const { specName } = await import('../plugin-store-SGNJTBYS.js');
4388
4834
  const yamlPath = path14__default.join(projectDir, "skaile.yaml");
4389
4835
  const editor = WorkspaceYamlEditor2.load(yamlPath);
4390
4836
  const replaced = editor.addPlugin(spec, specName);
@@ -4396,7 +4842,7 @@ async function runInstall2(spec, opts) {
4396
4842
  async function runRemove(name, opts) {
4397
4843
  const projectDir = path14__default.resolve(opts.projectDir);
4398
4844
  const { WorkspaceYamlEditor: WorkspaceYamlEditor2 } = await import('../core/index.js');
4399
- const { specName } = await import('../plugin-store-JWJHIPUT.js');
4845
+ const { specName } = await import('../plugin-store-SGNJTBYS.js');
4400
4846
  const yamlPath = path14__default.join(projectDir, "skaile.yaml");
4401
4847
  const editor = WorkspaceYamlEditor2.load(yamlPath);
4402
4848
  const removed = editor.removePlugin(name, specName);
@@ -4424,7 +4870,7 @@ async function runList(opts) {
4424
4870
  const registry = createPluginRegistry();
4425
4871
  if (declared.length > 0) {
4426
4872
  try {
4427
- const { loadPlugins } = await import('../plugin-store-JWJHIPUT.js');
4873
+ const { loadPlugins } = await import('../plugin-store-SGNJTBYS.js');
4428
4874
  const result = await loadPlugins(projectDir, declared, registry);
4429
4875
  for (const f of result.failed) logWarn(f.error);
4430
4876
  } catch (err) {
@@ -4639,7 +5085,29 @@ async function runPointerOnlyInstall(ref, deps) {
4639
5085
  };
4640
5086
  }
4641
5087
  function makeInstallCommand() {
4642
- return new Command("install").description(`Install dependencies from skaile.yaml, or a single asset by ref (${REF_HINT})`).argument("[ref]", `Asset ref to install from the Catalog (${REF_HINT})`).option("--locked", "Install from lock file (CI mode \u2014 fails on drift)").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").action(runInstallCommand);
5088
+ return new Command("install").description(`Install dependencies from skaile.yaml, or a single asset by ref (${REF_HINT})`).argument("[ref]", `Asset ref to install from the Catalog (${REF_HINT})`).option("--locked", "Install from lock file (CI mode \u2014 fails on drift)").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").option(
5089
+ "--global",
5090
+ "Install the global SSOT (~/.skaile/skaile.yaml), fanning out to every global backend"
5091
+ ).option(
5092
+ "--backend <ids>",
5093
+ "Comma-separated global backends to install into (default: all resolved); implies --global"
5094
+ ).option(
5095
+ "--link",
5096
+ "symlink local-path assets instead of copying (dev loop; machine-local, not for committing)"
5097
+ ).action(runInstallCommand);
5098
+ }
5099
+ function parseBackendFilter2(raw) {
5100
+ if (!raw) return void 0;
5101
+ const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
5102
+ const out = [];
5103
+ for (const id of ids) {
5104
+ if (!SUPPORTED_DRIVER_TARGETS.includes(id)) {
5105
+ logErr(`unknown backend '${id}' \u2014 expected one of: ${SUPPORTED_DRIVER_TARGETS.join(", ")}`);
5106
+ process.exit(1);
5107
+ }
5108
+ out.push(id);
5109
+ }
5110
+ return out.length > 0 ? out : void 0;
4643
5111
  }
4644
5112
  async function runInstallCommand(ref, opts) {
4645
5113
  if (ref !== void 0) {
@@ -4656,7 +5124,7 @@ async function runRefInstall(ref, opts) {
4656
5124
  const spinner5 = p6.spinner();
4657
5125
  spinner5.start(`Installing ${ref}`);
4658
5126
  try {
4659
- const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-TXJMFG34.js');
5127
+ const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-ERKRGH4B.js');
4660
5128
  const catalog = await openCatalogSource2({ projectDir: path14__default.resolve(opts.projectDir) });
4661
5129
  if (!supportsInstallManifest(catalog)) {
4662
5130
  throw new Error(
@@ -4687,8 +5155,13 @@ async function runRefInstall(ref, opts) {
4687
5155
  }
4688
5156
  async function runYamlInstall(opts) {
4689
5157
  const projectDir = path14__default.resolve(opts.projectDir);
5158
+ const backends = parseBackendFilter2(opts.backend);
5159
+ if (opts.global || backends) {
5160
+ await runGlobalInstall(opts, backends);
5161
+ return;
5162
+ }
4690
5163
  try {
4691
- const { ensureSourcesCloned } = await import('../ensure-sources-EE7Z2HKS.js');
5164
+ const { ensureSourcesCloned } = await import('../ensure-sources-GJOXWVWO.js');
4692
5165
  const hydrate = ensureSourcesCloned(projectDir, { quiet: true });
4693
5166
  if (hydrate.cloned.length > 0) {
4694
5167
  logOk(`Cloned source(s): ${hydrate.cloned.join(", ")}`);
@@ -4706,7 +5179,7 @@ async function runYamlInstall(opts) {
4706
5179
  const spinner5 = p6.spinner();
4707
5180
  spinner5.start(opts.locked ? "Installing from lock file" : "Installing dependencies");
4708
5181
  try {
4709
- const result = await am2.install({ locked: opts.locked });
5182
+ const result = await am2.install({ locked: opts.locked, link: opts.link });
4710
5183
  spinner5.stop("Done");
4711
5184
  if (result.deployed.length > 0) {
4712
5185
  for (const d of result.deployed) logOk(d);
@@ -4730,6 +5203,37 @@ async function runYamlInstall(opts) {
4730
5203
  process.exit(1);
4731
5204
  }
4732
5205
  }
5206
+ async function runGlobalInstall(opts, backends) {
5207
+ const am2 = new AssetManager({
5208
+ projectDir: path14__default.resolve(opts.projectDir),
5209
+ global: true,
5210
+ backends
5211
+ });
5212
+ const spinner5 = p6.spinner();
5213
+ spinner5.start("Installing global dependencies");
5214
+ try {
5215
+ const result = await am2.install({ locked: opts.locked, link: opts.link });
5216
+ spinner5.stop("Done");
5217
+ if (result.deployed.length > 0) for (const d of result.deployed) logOk(d);
5218
+ if (result.removed.length > 0) for (const r of result.removed) logWarn(`Removed: ${r}`);
5219
+ if (result.deployed.length === 0 && result.removed.length === 0)
5220
+ logInfo("Nothing to install (already up to date).");
5221
+ if (result.missing.length > 0) {
5222
+ for (const m of result.missing) logErr(`Missing: ${m}`);
5223
+ process.exitCode = 1;
5224
+ }
5225
+ if (result.lockWritten) logInfo(`Global lock written: ${S.dim("~/.skaile/skaile.lock.yaml")}`);
5226
+ const state2 = am2.globalState({});
5227
+ const byBackend = /* @__PURE__ */ new Map();
5228
+ for (const s of state2)
5229
+ if (s.state === "installed") byBackend.set(s.backend, (byBackend.get(s.backend) ?? 0) + 1);
5230
+ for (const [backend, n] of byBackend) logInfo(`${backend}: ${n} installed`);
5231
+ } catch (err) {
5232
+ spinner5.stop("Failed");
5233
+ logErr(String(err));
5234
+ process.exit(1);
5235
+ }
5236
+ }
4733
5237
  function makeCheckCommand() {
4734
5238
  return new Command("check").description("Check for unmet requirements").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
4735
5239
  const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
@@ -4776,8 +5280,8 @@ function makeCleanCommand() {
4776
5280
  return;
4777
5281
  }
4778
5282
  if (!opts.yes) {
4779
- const confirm5 = await p6.confirm({ message: "Proceed?" });
4780
- if (p6.isCancel(confirm5) || !confirm5) {
5283
+ const confirm6 = await p6.confirm({ message: "Proceed?" });
5284
+ if (p6.isCancel(confirm6) || !confirm6) {
4781
5285
  logInfo("Cancelled.");
4782
5286
  return;
4783
5287
  }
@@ -5044,11 +5548,11 @@ function makeClearCommand() {
5044
5548
  }
5045
5549
  function makeReplCommand() {
5046
5550
  return new Command("repl").description("Start an interactive agent session").option("--project-dir <path>", "Project directory").option("--driver <name>", "Driver backend (claude-sdk, omp)").option("--provider <name>", "LLM provider").option("--model <name>", "Model override").option("--resume", "Resume last session").option("--resume-session <id>", "Resume specific session").action(async (opts) => {
5047
- const { findWorkspaceRoot: findWorkspaceRoot2 } = await import('../core/index.js');
5551
+ const { findWorkspaceRoot } = await import('../core/index.js');
5048
5552
  const { startRepl } = await import('../tui/index.js');
5049
5553
  const os2 = await import('os');
5050
5554
  const userCwd = path14__default.resolve(opts.projectDir ?? process.cwd());
5051
- const workspaceRoot = findWorkspaceRoot2(userCwd);
5555
+ const workspaceRoot = findWorkspaceRoot(userCwd);
5052
5556
  let projectDir;
5053
5557
  let agentCwd;
5054
5558
  let driverOverride = opts.driver;
@@ -5126,7 +5630,7 @@ async function ensurePluginsLoadedForServe(projectDir) {
5126
5630
  const { resolveSkWorkspaceConfig: resolveSkWorkspaceConfig2 } = await import('../core/index.js');
5127
5631
  const config = resolveSkWorkspaceConfig2(projectDir);
5128
5632
  if (!config.plugins || config.plugins.length === 0) return;
5129
- const { ensurePluginsLoaded } = await import('../plugin-store-JWJHIPUT.js');
5633
+ const { ensurePluginsLoaded } = await import('../plugin-store-SGNJTBYS.js');
5130
5634
  const { pluginRegistry } = await import('../plugin-registry/index.js');
5131
5635
  const result = await ensurePluginsLoaded(projectDir, config.plugins, pluginRegistry);
5132
5636
  if (result.loaded.length > 0) {
@@ -5142,21 +5646,21 @@ async function ensurePluginsLoadedForServe(projectDir) {
5142
5646
  async function runCompileTest(opts) {
5143
5647
  const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-F4NZ66VD.js');
5144
5648
  const { tmpdir } = await import('os');
5145
- const { dirname: dirname5, join: join6, resolve: resolve5 } = await import('path');
5649
+ const { dirname: dirname4, join: join5, resolve: resolve5 } = await import('path');
5146
5650
  const { fileURLToPath: fileURLToPath2 } = await import('url');
5147
- const { unlinkSync, existsSync: existsSync14 } = await import('fs');
5651
+ const { unlinkSync, existsSync: existsSync13 } = await import('fs');
5148
5652
  const { spawn } = await import('child_process');
5149
5653
  const { portableSpawnSync: portableSpawnSync2 } = await import('../core/index.js');
5150
- const { MONOREPO_ROOT } = await import('../paths-OMVC4UWY.js');
5654
+ const { MONOREPO_ROOT } = await import('../paths-D6RUQ522.js');
5151
5655
  if (MONOREPO_ROOT === null) {
5152
5656
  logErr2("--compile-test is only available inside the skaile-dev workspace.");
5153
5657
  logInfo2("Run it from a checkout of skaile-ai/skaile-dev (the monorepo shell).");
5154
5658
  process.exitCode = 2;
5155
5659
  return;
5156
5660
  }
5157
- const outfile = join6(tmpdir(), `skaile-compile-test-${Date.now()}`);
5661
+ const outfile = join5(tmpdir(), `skaile-compile-test-${Date.now()}`);
5158
5662
  const __thisFile = fileURLToPath2(import.meta.url);
5159
- const entryPoint = resolve5(dirname5(__thisFile), "..", "index.ts");
5663
+ const entryPoint = resolve5(dirname4(__thisFile), "..", "index.ts");
5160
5664
  logInfo2(`Building compiled binary...`);
5161
5665
  logInfo2(`Entry: ${S2.dim(entryPoint)}`);
5162
5666
  logInfo2(`Output: ${S2.dim(outfile)}`);
@@ -5206,7 +5710,7 @@ async function runCompileTest(opts) {
5206
5710
  } catch {
5207
5711
  }
5208
5712
  try {
5209
- if (existsSync14(outfile)) unlinkSync(outfile);
5713
+ if (existsSync13(outfile)) unlinkSync(outfile);
5210
5714
  } catch {
5211
5715
  }
5212
5716
  }
@@ -5960,324 +6464,6 @@ function makeShowCommand() {
5960
6464
  }
5961
6465
  });
5962
6466
  }
5963
-
5964
- // cli/src/commands/source-manifest.ts
5965
- var NOT_WIRED_MSG = "`skaile source manifest *` is scaffolded but not yet wired. Server-side endpoint (`POST /sources/<id>/manifest`) lands in a follow-up PR.";
5966
- function notWired2(verb) {
5967
- logErr(`${NOT_WIRED_MSG} (verb: source manifest ${verb})`);
5968
- process.exit(2);
5969
- }
5970
- function addSourceManifestCommands(src) {
5971
- const manifest = src.command("manifest").description("Sidecar manifest lifecycle for a source");
5972
- manifest.command("init <src>").description("Start a sidecar manifest for a source").action(() => notWired2("init"));
5973
- manifest.command("edit <src>").description("Open the sidecar manifest in $EDITOR").action(() => notWired2("edit"));
5974
- manifest.command("rebuild <src>").description("Re-derive the manifest after an upstream change").option("--merge", "Merge with existing entries instead of overwriting", false).action(() => notWired2("rebuild"));
5975
- manifest.command("verify <src>").description("Verify hashes, deps, and schema").option("--strict", "Fail on advisory checks", false).action(() => notWired2("verify"));
5976
- manifest.command("publish <src>").description("Register the manifest in the store (provenance=curator)").action(() => notWired2("publish"));
5977
- manifest.command("propose <src>").description("Open a PR to upstream with the sidecar manifest").action(() => notWired2("propose"));
5978
- manifest.command("yank <src>").description("Retract a published manifest from the remote store").option("--version <v>", "Version to yank").action(() => notWired2("yank"));
5979
- }
5980
-
5981
- // cli/src/commands/source.ts
5982
- function sourceClonePath(key) {
5983
- return path14.join(getGlobalCacheDir(), key);
5984
- }
5985
- var SKAILE_MANIFEST_FILENAME2 = "skaile.manifest.yaml";
5986
- var LEGACY_SOURCE_CONFIG_FILENAME = ".skaile-source.yaml";
5987
- function indexingHadFailures(result) {
5988
- return result.errors.length > 0;
5989
- }
5990
- function legacySourceConfigHint(dest) {
5991
- const hasLegacy = existsSync(path14.join(dest, LEGACY_SOURCE_CONFIG_FILENAME));
5992
- const hasManifest = existsSync(path14.join(dest, SKAILE_MANIFEST_FILENAME2));
5993
- if (hasLegacy && !hasManifest) {
5994
- return `This source ships a legacy ${LEGACY_SOURCE_CONFIG_FILENAME} but no ${SKAILE_MANIFEST_FILENAME2}; its declared publisher is ignored and assets are published under their first path segment. Add a ${SKAILE_MANIFEST_FILENAME2} (\`skaile source manifest init\`) to set the publisher and asset inventory.`;
5995
- }
5996
- return void 0;
5997
- }
5998
- function normalizeSourceUrl(input) {
5999
- const s = input.trim();
6000
- if (/^(?:https?|git|ssh|file):\/\//.test(s) || /^git@/.test(s)) return s;
6001
- const repo = s.replace(/\.git$/, "");
6002
- if (/^[\w.-]+\/[\w.-]+$/.test(repo)) return `git@github.com:${repo}.git`;
6003
- if (/^[\w.-]+$/.test(repo)) return `git@github.com:skaile-ai/${repo}.git`;
6004
- return s;
6005
- }
6006
- function sourceMatchesKey(entry, key) {
6007
- if (entry.url === key) return true;
6008
- if (sourceCacheKey(entry.url) === key || sourceShortName(entry.url) === key) return true;
6009
- return entry.url === normalizeSourceUrl(key);
6010
- }
6011
- function findCacheKeyCollision(sources, url) {
6012
- const key = sourceCacheKey(url);
6013
- return sources.find((s) => s.url !== url && sourceCacheKey(s.url) === key);
6014
- }
6015
- function requireProjectYamlPath() {
6016
- const root = findWorkspaceRoot(process.cwd());
6017
- if (!root) {
6018
- logErr(
6019
- "No skaile.yaml found in the current directory or any parent. Run `skaile init` first."
6020
- );
6021
- process.exit(1);
6022
- }
6023
- return path14.join(root, workspaceConfigFilename());
6024
- }
6025
- function readProjectSources(yamlPath) {
6026
- if (!existsSync(yamlPath)) return [];
6027
- try {
6028
- return WorkspaceYamlEditor.load(yamlPath).getSources();
6029
- } catch (err) {
6030
- logErr(`Could not read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}`);
6031
- process.exit(1);
6032
- }
6033
- }
6034
- function ensureClone(entry, opts = {}) {
6035
- const dest = sourceClonePath(sourceCacheKey(entry.url));
6036
- if (existsSync(dest)) {
6037
- if (!opts.force) return false;
6038
- rmSync(dest, { recursive: true, force: true });
6039
- }
6040
- mkdirSync(path14.dirname(dest), { recursive: true });
6041
- const args = ["clone", entry.url, dest];
6042
- if (entry.pin) args.splice(1, 0, "--branch", entry.pin);
6043
- const clone = spawnSync("git", args, { stdio: "inherit" });
6044
- if (clone.status !== 0) {
6045
- logErr(`git clone failed for ${entry.url}`);
6046
- process.exit(1);
6047
- }
6048
- return true;
6049
- }
6050
- async function refreshManifestCache(entry, includeDev = false) {
6051
- const { manager, library, close } = await openLibraryManager();
6052
- try {
6053
- const name = sourceShortName(entry.url);
6054
- const dest = sourceClonePath(sourceCacheKey(entry.url));
6055
- const existing = (await manager.listLibraries()).find((l) => l.name === name);
6056
- const lib = existing ?? await manager.addLibrary({
6057
- name,
6058
- path: dest,
6059
- backend: "git",
6060
- backendConfig: { url: entry.url, branch: entry.pin ?? "main", authHint: "ssh" },
6061
- ownership: "reader"
6062
- });
6063
- const catalog = new LocalCatalogSource(library, lib.id, dest, createFullRegistry());
6064
- const result = await catalog.sync({ includeDev });
6065
- await library.syncSource(lib.id);
6066
- return result;
6067
- } finally {
6068
- close();
6069
- }
6070
- }
6071
- async function dropManifestCache(url, purgeClone) {
6072
- const name = sourceShortName(url);
6073
- const { manager, close } = await openLibraryManager();
6074
- try {
6075
- const existing = (await manager.listLibraries()).find((l) => l.name === name);
6076
- if (existing) {
6077
- await manager.removeLibrary(name, { purge: false });
6078
- }
6079
- } finally {
6080
- close();
6081
- }
6082
- if (purgeClone) {
6083
- const dest = sourceClonePath(sourceCacheKey(url));
6084
- if (existsSync(dest)) rmSync(dest, { recursive: true, force: true });
6085
- }
6086
- }
6087
- function makeSourceCommand() {
6088
- const cmd = new Command("source").description(
6089
- "Manage github sources for the current project (recorded in skaile.yaml)"
6090
- );
6091
- cmd.command("add <source>").description(
6092
- "Clone a github repo and register it in this project's skaile.yaml. <source> may be a full git URL, an owner/repo shorthand, or a bare name (\u2192 git@github.com:skaile-ai/<name>.git)."
6093
- ).option("--name <slug>", "[deprecated] no-op \u2014 the source entry stores only the URL").option("--pin <ref>", "Pin a branch, tag, or 40-char SHA").option("--branch <branch>", "[deprecated] alias for --pin").option("--force", "Remove an existing clone and re-clone", false).option("--dev", "Also index dev-only assets under the source's dev_paths", false).action(
6094
- async (source, opts) => {
6095
- const url = normalizeSourceUrl(source);
6096
- const yamlPath = requireProjectYamlPath();
6097
- const collision = findCacheKeyCollision(readProjectSources(yamlPath), url);
6098
- if (collision) {
6099
- logErr(
6100
- `"${url}" maps to the same cache key (${sourceCacheKey(url)}) as already-registered "${collision.url}". Remove that source first (skaile source remove) or re-use its exact URL to update it.`
6101
- );
6102
- process.exitCode = 1;
6103
- return;
6104
- }
6105
- if (opts.name) {
6106
- logWarn(
6107
- "the --name flag is deprecated; the source entry now stores only the URL (the cache slug is derived from it)."
6108
- );
6109
- }
6110
- const pin = opts.pin ?? opts.branch;
6111
- const slug = sourceShortName(url);
6112
- const entry = { url };
6113
- if (pin) entry.pin = pin;
6114
- const editor = WorkspaceYamlEditor.load(yamlPath);
6115
- editor.setSource(entry);
6116
- editor.save();
6117
- const dest = sourceClonePath(sourceCacheKey(url));
6118
- const preexisting = existsSync(dest);
6119
- const cloned = ensureClone(entry, { force: opts.force });
6120
- if (!cloned) {
6121
- logOk(`Reusing cached clone at ${dest}`);
6122
- } else if (preexisting) {
6123
- logOk(`Re-cloned ${url} \u2192 ${dest}`);
6124
- } else {
6125
- logOk(`Cloned ${url} \u2192 ${dest}`);
6126
- }
6127
- const result = await refreshManifestCache(entry, opts.dev);
6128
- const failed = indexingHadFailures(result);
6129
- const indexedMsg = `Indexed ${result.assetsUpdated} of ${result.assetsFound} asset(s) from "${slug}".`;
6130
- if (failed) {
6131
- logWarn(indexedMsg);
6132
- } else {
6133
- logOk(indexedMsg);
6134
- }
6135
- for (const err of result.errors) logWarn(err);
6136
- const legacyHint = legacySourceConfigHint(dest);
6137
- if (legacyHint) logWarn(legacyHint);
6138
- const where = path14.relative(process.cwd(), yamlPath);
6139
- if (failed) {
6140
- logWarn(
6141
- `Source "${slug}" registered in ${where}, but ${result.errors.length} asset(s) failed to index (see above). Fix the cause, then re-run \`skaile source sync ${slug}\`.`
6142
- );
6143
- process.exitCode = 1;
6144
- } else {
6145
- logOk(`Source "${slug}" registered in ${where}.`);
6146
- }
6147
- }
6148
- );
6149
- cmd.command("list").description("List sources registered in this project's skaile.yaml").option("--json", "Output as JSON").action(async (opts) => {
6150
- const yamlPath = requireProjectYamlPath();
6151
- const sources = readProjectSources(yamlPath);
6152
- if (opts.json) return console.log(JSON.stringify(sources, null, 2));
6153
- if (sources.length === 0) {
6154
- logInfo("No sources in skaile.yaml. Run `skaile source add <git-url>` to register one.");
6155
- return;
6156
- }
6157
- console.log();
6158
- console.log(S.heading(" Sources"));
6159
- for (const s of sources) {
6160
- const slug = sourceShortName(s.url);
6161
- const cached = existsSync(sourceClonePath(sourceCacheKey(s.url))) ? "" : S.warn(" (not cached)");
6162
- console.log(` ${S.cmd(slug.padEnd(24))} ${S.dim(s.url)}${cached}`);
6163
- }
6164
- console.log(`
6165
- ${S.dim(`${sources.length} source(s)`)}
6166
- `);
6167
- });
6168
- cmd.command("show <name-or-url>").description("Show details for a source (matched by URL or derived slug)").action(async (key) => {
6169
- const yamlPath = requireProjectYamlPath();
6170
- const entry = readProjectSources(yamlPath).find((s) => sourceMatchesKey(s, key));
6171
- if (!entry) {
6172
- logErr(`No source matching "${key}" in ${yamlPath}.`);
6173
- process.exit(1);
6174
- }
6175
- const slug = sourceShortName(entry.url);
6176
- const clonePath = sourceClonePath(sourceCacheKey(entry.url));
6177
- console.log(
6178
- JSON.stringify(
6179
- {
6180
- ...entry,
6181
- slug,
6182
- clonePath,
6183
- cached: existsSync(clonePath)
6184
- },
6185
- null,
6186
- 2
6187
- )
6188
- );
6189
- });
6190
- cmd.command("remove <name-or-url>").description("Remove a source from this project's skaile.yaml (matched by URL or slug)").option("--purge", "Also delete the cached clone from ~/.skaile/cache/sources/", false).action(async (key, opts) => {
6191
- const yamlPath = requireProjectYamlPath();
6192
- const editor = WorkspaceYamlEditor.load(yamlPath);
6193
- const match = editor.getSources().find((s) => sourceMatchesKey(s, key));
6194
- if (!match) {
6195
- logErr(`No source matching "${key}" in ${yamlPath}.`);
6196
- process.exit(1);
6197
- }
6198
- const slug = sourceShortName(match.url);
6199
- editor.removeSource(match.url);
6200
- editor.save();
6201
- await dropManifestCache(match.url, opts.purge);
6202
- logOk(
6203
- opts.purge ? `Removed source "${slug}" and purged its clone.` : `Removed source "${slug}" from skaile.yaml (clone left in ~/.skaile/cache/sources/).`
6204
- );
6205
- });
6206
- cmd.command("sync [name]").description("Pull upstream changes and refresh the manifest cache").option("--dev", "Also index dev-only assets under each source's dev_paths", false).option("--all", "Sync every source without prompting", false).action(async (key, opts) => {
6207
- const yamlPath = requireProjectYamlPath();
6208
- const sources = readProjectSources(yamlPath);
6209
- if (sources.length === 0) {
6210
- logInfo("No sources in skaile.yaml.");
6211
- return;
6212
- }
6213
- let targets;
6214
- if (key) {
6215
- targets = sources.filter((s) => sourceMatchesKey(s, key));
6216
- if (targets.length === 0) {
6217
- logInfo(`No source matching "${key}".`);
6218
- return;
6219
- }
6220
- } else if (opts.all || sources.length === 1 || !process.stdin.isTTY) {
6221
- targets = sources;
6222
- } else {
6223
- const selected = await p6.multiselect({
6224
- message: "Select sources to sync",
6225
- options: sources.map((s) => ({
6226
- value: s.url,
6227
- label: sourceShortName(s.url),
6228
- hint: s.url
6229
- })),
6230
- required: true
6231
- });
6232
- if (p6.isCancel(selected)) {
6233
- p6.cancel("Cancelled.");
6234
- return;
6235
- }
6236
- const picked = new Set(selected);
6237
- targets = sources.filter((s) => picked.has(s.url));
6238
- }
6239
- for (const entry of targets) {
6240
- const slug = sourceShortName(entry.url);
6241
- const dest = sourceClonePath(sourceCacheKey(entry.url));
6242
- if (!existsSync(dest)) {
6243
- ensureClone(entry);
6244
- logOk(`${slug}: cloned to ${dest}.`);
6245
- } else {
6246
- const pull = spawnSync("git", ["pull", "--ff-only"], { cwd: dest, stdio: "inherit" });
6247
- if (pull.status !== 0) {
6248
- logWarn(`${slug}: git pull failed, skipping manifest refresh.`);
6249
- continue;
6250
- }
6251
- }
6252
- const result = await refreshManifestCache(entry, opts.dev);
6253
- const failed = indexingHadFailures(result);
6254
- const indexedMsg = `${slug}: indexed ${result.assetsUpdated} of ${result.assetsFound} asset(s).`;
6255
- if (failed) {
6256
- logWarn(indexedMsg);
6257
- process.exitCode = 1;
6258
- } else {
6259
- logOk(indexedMsg);
6260
- }
6261
- for (const err of result.errors) logWarn(`${slug}: ${err}`);
6262
- const legacyHint = legacySourceConfigHint(dest);
6263
- if (legacyHint) logWarn(`${slug}: ${legacyHint}`);
6264
- }
6265
- });
6266
- cmd.command("patch <ref>").description("Extract an asset for editing against the source").action((_ref) => {
6267
- logErr(
6268
- "`skaile source patch` is scaffolded but not yet wired. The patch flow lands in a follow-up PR."
6269
- );
6270
- process.exit(2);
6271
- });
6272
- cmd.command("propose <ref>").description("Open a PR with the patch against the source upstream").action((_ref) => {
6273
- logErr(
6274
- "`skaile source propose` is scaffolded but not yet wired. The propose flow lands in a follow-up PR."
6275
- );
6276
- process.exit(2);
6277
- });
6278
- addSourceManifestCommands(cmd);
6279
- return cmd;
6280
- }
6281
6467
  function makeStoreCommand() {
6282
6468
  const store = new Command("store").description("Manage the AI Asset Store");
6283
6469
  store.command("login").description("Authenticate with the store").option("--email <email>", "Login with email instead of GitHub").action(async (opts) => {
@@ -6455,7 +6641,7 @@ function makeTreeCommand() {
6455
6641
  });
6456
6642
  }
6457
6643
  function makeUpdateCommand() {
6458
- return new Command("update").description("Refresh the Catalog cache and re-deploy outdated assets in the current project").argument("[name]", "Update a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--no-catalog", "Skip refreshing the catalog cache").option("--catalog-only", "Refresh the catalog cache only; do not re-deploy assets").action(
6644
+ return new Command("update").description("Refresh the Catalog cache and re-deploy outdated assets in the current project").argument("[name]", "Update a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--no-catalog", "Skip refreshing the catalog cache").option("--catalog-only", "Refresh the catalog cache only; do not re-deploy assets").option("--no-sync", "Skip syncing sources from upstream before re-deploying").option("-y, --yes", "Sync sources without the confirmation prompt").action(
6459
6645
  async (_name, opts) => {
6460
6646
  if (opts.catalog !== false) {
6461
6647
  try {
@@ -6473,7 +6659,16 @@ function makeUpdateCommand() {
6473
6659
  }
6474
6660
  }
6475
6661
  if (opts.catalogOnly) return;
6476
- const am2 = new AssetManager({ projectDir: path14__default.resolve(opts.projectDir) });
6662
+ const projectDir = path14__default.resolve(opts.projectDir);
6663
+ if (await shouldSyncSources(opts)) {
6664
+ const syncSpinner = p6.spinner();
6665
+ syncSpinner.start("Syncing sources");
6666
+ const { total, synced, failed } = await syncProjectSources(projectDir);
6667
+ syncSpinner.stop(
6668
+ total === 0 ? "No sources to sync." : `Synced ${S.heading(`${synced}/${total}`)} source(s)` + (failed ? ` (${failed} failed)` : "")
6669
+ );
6670
+ }
6671
+ const am2 = new AssetManager({ projectDir });
6477
6672
  const spinner5 = p6.spinner();
6478
6673
  spinner5.start("Re-deploying assets");
6479
6674
  const result = await am2.install();
@@ -6486,6 +6681,19 @@ function makeUpdateCommand() {
6486
6681
  }
6487
6682
  );
6488
6683
  }
6684
+ async function shouldSyncSources(opts) {
6685
+ if (opts.sync === false) return false;
6686
+ if (opts.yes || !process.stdin.isTTY) return true;
6687
+ const answer = await p6.confirm({
6688
+ message: "Sync sources from upstream before re-deploying?",
6689
+ initialValue: true
6690
+ });
6691
+ if (p6.isCancel(answer)) {
6692
+ p6.cancel("Cancelled.");
6693
+ process.exit(130);
6694
+ }
6695
+ return answer;
6696
+ }
6489
6697
  var MANIFEST_GLOBS = [
6490
6698
  { pattern: /\/SKILL\.md$/, kind: "skill" },
6491
6699
  { pattern: /\/agent\.yaml$/, kind: "agent" },
@@ -7215,7 +7423,7 @@ program.command("init [project-dir]").description("Initialize a project director
7215
7423
  (projectDir, opts) => runInit(projectDir, opts)
7216
7424
  );
7217
7425
  async function runInit(projectDir, opts) {
7218
- const { mkdirSync: mkdirSync6, writeFileSync: writeFileSync4 } = await import('fs');
7426
+ const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import('fs');
7219
7427
  const { stringify } = await import('yaml');
7220
7428
  const { DRIVER_TARGETS, SUPPORTED_DRIVER_TARGETS: SUPPORTED_DRIVER_TARGETS2 } = await import('../core/index.js');
7221
7429
  const backend = opts.backend;
@@ -7227,30 +7435,30 @@ async function runInit(projectDir, opts) {
7227
7435
  const resolved = path14__default.resolve(projectDir ?? ".");
7228
7436
  const projectName = path14__default.basename(resolved);
7229
7437
  const created = [];
7230
- const { existsSync: existsSync14 } = await import('fs');
7231
- if (!existsSync14(resolved)) {
7232
- mkdirSync6(resolved, { recursive: true });
7438
+ const { existsSync: existsSync13 } = await import('fs');
7439
+ if (!existsSync13(resolved)) {
7440
+ mkdirSync5(resolved, { recursive: true });
7233
7441
  created.push(".");
7234
7442
  }
7235
7443
  const skaileDir = path14__default.join(resolved, ".skaile");
7236
- if (!existsSync14(skaileDir)) {
7237
- mkdirSync6(path14__default.join(skaileDir, "sessions"), { recursive: true });
7444
+ if (!existsSync13(skaileDir)) {
7445
+ mkdirSync5(path14__default.join(skaileDir, "sessions"), { recursive: true });
7238
7446
  created.push(".skaile/");
7239
7447
  }
7240
7448
  const settingsPath = path14__default.join(skaileDir, "settings.json");
7241
- if (!existsSync14(settingsPath)) {
7449
+ if (!existsSync13(settingsPath)) {
7242
7450
  writeFileSync4(settingsPath, "{}\n");
7243
7451
  created.push(".skaile/settings.json");
7244
7452
  }
7245
7453
  const wsConfigPath = path14__default.join(resolved, "skaile.yaml");
7246
- if (!existsSync14(wsConfigPath)) {
7454
+ if (!existsSync13(wsConfigPath)) {
7247
7455
  writeFileSync4(wsConfigPath, stringify(buildInitWorkspaceConfig(projectName, backend)));
7248
7456
  created.push("skaile.yaml");
7249
7457
  }
7250
7458
  for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
7251
7459
  const full = path14__default.join(resolved, dir);
7252
- if (!existsSync14(full)) {
7253
- mkdirSync6(full, { recursive: true });
7460
+ if (!existsSync13(full)) {
7461
+ mkdirSync5(full, { recursive: true });
7254
7462
  created.push(`${dir}/`);
7255
7463
  }
7256
7464
  }
@@ -7280,7 +7488,7 @@ function buildInitWorkspaceConfig(projectName, backend) {
7280
7488
  }
7281
7489
  async function initGitScaffold(resolved, created) {
7282
7490
  const { execSync: execSync3 } = await import('child_process');
7283
- const { existsSync: existsSync14, readFileSync: readFileSync8, writeFileSync: writeFileSync4 } = await import('fs');
7491
+ const { existsSync: existsSync13, readFileSync: readFileSync8, writeFileSync: writeFileSync4 } = await import('fs');
7284
7492
  const gitignorePath = path14__default.join(resolved, ".gitignore");
7285
7493
  const entries = [
7286
7494
  "node_modules/",
@@ -7296,7 +7504,7 @@ async function initGitScaffold(resolved, created) {
7296
7504
  ".env",
7297
7505
  ".env.local"
7298
7506
  ];
7299
- const existing = existsSync14(gitignorePath) ? readFileSync8(gitignorePath, "utf-8") : "";
7507
+ const existing = existsSync13(gitignorePath) ? readFileSync8(gitignorePath, "utf-8") : "";
7300
7508
  const have = new Set(existing.split("\n").map((l) => l.trim()));
7301
7509
  const append = entries.filter((e) => !have.has(e));
7302
7510
  if (append.length > 0) {
@@ -7305,7 +7513,7 @@ async function initGitScaffold(resolved, created) {
7305
7513
  `);
7306
7514
  if (!existing) created.push(".gitignore");
7307
7515
  }
7308
- if (!existsSync14(path14__default.join(resolved, ".git"))) {
7516
+ if (!existsSync13(path14__default.join(resolved, ".git"))) {
7309
7517
  try {
7310
7518
  execSync3("git init", { cwd: resolved, stdio: "pipe" });
7311
7519
  created.push(".git/");
@@ -7335,7 +7543,7 @@ async function bootstrapUserConfig() {
7335
7543
  }
7336
7544
  async function hydrateInitSources(resolved, created) {
7337
7545
  try {
7338
- const { ensureSourcesCloned } = await import('../ensure-sources-EE7Z2HKS.js');
7546
+ const { ensureSourcesCloned } = await import('../ensure-sources-GJOXWVWO.js');
7339
7547
  const hydrate = ensureSourcesCloned(resolved, { quiet: true });
7340
7548
  for (const n of hydrate.cloned) created.push(`~/.skaile/cache/sources/${n}/`);
7341
7549
  if (hydrate.failed.length > 0) {
@@ -7371,7 +7579,7 @@ function printInitSummary(resolved, projectDir, created) {
7371
7579
  console.log();
7372
7580
  }
7373
7581
  program.command("setup").description("Interactive provider setup wizard").action(async () => {
7374
- const { cmdSetup } = await import('../setup-ETNBVZQA.js');
7582
+ const { cmdSetup } = await import('../setup-IV2JFW3T.js');
7375
7583
  await cmdSetup([], { projectDir: process.cwd() });
7376
7584
  });
7377
7585
  program.addCommand(makeInstallCommand());