@slats/claude-assets-sync 0.0.1 → 0.0.3

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 (110) hide show
  1. package/CHANGELOG.md +189 -0
  2. package/README.md +541 -45
  3. package/dist/cli.cjs +8 -0
  4. package/dist/cli.d.ts +1 -0
  5. package/dist/cli.mjs +7 -0
  6. package/dist/commands/add.cjs +61 -0
  7. package/dist/commands/add.d.ts +12 -0
  8. package/dist/commands/add.mjs +59 -0
  9. package/dist/commands/index.d.ts +91 -0
  10. package/dist/commands/list.cjs +83 -0
  11. package/dist/commands/list.d.ts +6 -0
  12. package/dist/commands/list.mjs +81 -0
  13. package/dist/commands/migrate.cjs +9 -0
  14. package/dist/commands/migrate.d.ts +6 -0
  15. package/dist/commands/migrate.mjs +7 -0
  16. package/dist/commands/remove.cjs +109 -0
  17. package/dist/commands/remove.d.ts +6 -0
  18. package/dist/commands/remove.mjs +86 -0
  19. package/dist/commands/status.cjs +193 -0
  20. package/dist/commands/status.d.ts +6 -0
  21. package/dist/commands/status.mjs +171 -0
  22. package/dist/commands/sync.cjs +28 -0
  23. package/dist/commands/sync.d.ts +6 -0
  24. package/dist/commands/sync.mjs +26 -0
  25. package/dist/commands/types.d.ts +82 -0
  26. package/dist/components/add/AddCommand.cjs +92 -0
  27. package/dist/components/add/AddCommand.d.ts +14 -0
  28. package/dist/components/add/AddCommand.mjs +90 -0
  29. package/dist/components/add/index.d.ts +2 -0
  30. package/dist/components/index.d.ts +2 -0
  31. package/dist/components/list/EditableTreeItem.d.ts +13 -0
  32. package/dist/components/list/ListCommand.cjs +440 -0
  33. package/dist/components/list/ListCommand.d.ts +8 -0
  34. package/dist/components/list/ListCommand.mjs +418 -0
  35. package/dist/components/list/SyncedPackageTree.d.ts +14 -0
  36. package/dist/components/list/index.d.ts +9 -0
  37. package/dist/components/primitives/Box.d.ts +4 -0
  38. package/dist/components/primitives/Spinner.d.ts +6 -0
  39. package/dist/components/primitives/Text.d.ts +4 -0
  40. package/dist/components/primitives/index.d.ts +3 -0
  41. package/dist/components/status/PackageStatusCard.d.ts +10 -0
  42. package/dist/components/status/StatusDisplay.cjs +25 -0
  43. package/dist/components/status/StatusDisplay.d.ts +25 -0
  44. package/dist/components/status/StatusDisplay.mjs +23 -0
  45. package/dist/components/status/StatusTreeNode.cjs +40 -0
  46. package/dist/components/status/StatusTreeNode.d.ts +15 -0
  47. package/dist/components/status/StatusTreeNode.mjs +38 -0
  48. package/dist/components/status/index.d.ts +6 -0
  49. package/dist/components/tree/AssetTreeNode.cjs +37 -0
  50. package/dist/components/tree/AssetTreeNode.d.ts +12 -0
  51. package/dist/components/tree/AssetTreeNode.mjs +35 -0
  52. package/dist/components/tree/TreeSelect.cjs +121 -0
  53. package/dist/components/tree/TreeSelect.d.ts +12 -0
  54. package/dist/components/tree/TreeSelect.mjs +119 -0
  55. package/dist/components/tree/index.d.ts +4 -0
  56. package/dist/core/assetStructure.cjs +30 -0
  57. package/dist/core/assetStructure.d.ts +36 -0
  58. package/dist/core/assetStructure.mjs +27 -0
  59. package/dist/core/cli.cjs +92 -0
  60. package/dist/core/cli.mjs +89 -0
  61. package/dist/core/constants.cjs +23 -0
  62. package/dist/core/constants.d.ts +83 -0
  63. package/dist/core/constants.mjs +17 -0
  64. package/dist/core/filesystem.cjs +62 -51
  65. package/dist/core/filesystem.d.ts +38 -18
  66. package/dist/core/filesystem.mjs +56 -44
  67. package/dist/core/github.cjs +8 -11
  68. package/dist/core/github.d.ts +4 -6
  69. package/dist/core/github.mjs +8 -11
  70. package/dist/core/io.cjs +46 -0
  71. package/dist/core/io.d.ts +40 -0
  72. package/dist/core/io.mjs +39 -0
  73. package/dist/core/migration.cjs +199 -0
  74. package/dist/core/migration.d.ts +57 -0
  75. package/dist/core/migration.mjs +196 -0
  76. package/dist/core/packageScanner.cjs +259 -0
  77. package/dist/core/packageScanner.d.ts +17 -0
  78. package/dist/core/packageScanner.mjs +257 -0
  79. package/dist/core/sync.cjs +244 -61
  80. package/dist/core/sync.d.ts +6 -2
  81. package/dist/core/sync.mjs +246 -63
  82. package/dist/core/syncMeta.cjs +93 -0
  83. package/dist/core/syncMeta.d.ts +71 -0
  84. package/dist/core/syncMeta.mjs +84 -0
  85. package/dist/index.cjs +7 -8
  86. package/dist/index.d.ts +4 -3
  87. package/dist/index.mjs +2 -10
  88. package/dist/utils/nameTransform.cjs +12 -0
  89. package/dist/utils/nameTransform.d.ts +76 -0
  90. package/dist/utils/nameTransform.mjs +9 -0
  91. package/dist/utils/package.cjs +22 -17
  92. package/dist/utils/package.d.ts +25 -0
  93. package/dist/utils/package.mjs +11 -7
  94. package/dist/utils/packageName.cjs +24 -0
  95. package/dist/utils/packageName.d.ts +32 -0
  96. package/dist/utils/packageName.mjs +21 -0
  97. package/dist/utils/paths.cjs +18 -0
  98. package/dist/utils/paths.d.ts +55 -0
  99. package/dist/utils/paths.mjs +15 -0
  100. package/dist/utils/types.d.ts +153 -6
  101. package/dist/utils/version.cjs +17 -0
  102. package/dist/utils/version.d.ts +55 -0
  103. package/dist/utils/version.mjs +14 -0
  104. package/dist/version.cjs +5 -0
  105. package/dist/version.d.ts +5 -0
  106. package/dist/version.mjs +3 -0
  107. package/package.json +16 -7
  108. package/dist/cli/index.cjs +0 -56
  109. package/dist/cli/index.mjs +0 -53
  110. /package/dist/{cli/index.d.ts → core/cli.d.ts} +0 -0
@@ -1,11 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  var logger = require('../utils/logger.cjs');
4
+ var nameTransform = require('../utils/nameTransform.cjs');
4
5
  var _package = require('../utils/package.cjs');
6
+ var paths = require('../utils/paths.cjs');
5
7
  var filesystem = require('./filesystem.cjs');
6
8
  var github = require('./github.cjs');
9
+ var syncMeta = require('./syncMeta.cjs');
10
+ var assetStructure = require('./assetStructure.cjs');
7
11
 
8
- const syncPackage = async (packageName, options, cwd = process.cwd(), outputDir) => {
12
+ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions, outputDir) => {
9
13
  logger.logger.packageStart(packageName);
10
14
  try {
11
15
  const destDir = outputDir ?? _package.findGitRoot(cwd) ?? cwd;
@@ -37,78 +41,257 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), outputDir)
37
41
  reason: 'Unable to parse GitHub repository URL',
38
42
  };
39
43
  }
40
- if (!options.force &&
41
- !filesystem.needsSync(destDir, packageName, packageInfo.version)) {
44
+ const useFlat = options.flat !== false;
45
+ if (useFlat) {
46
+ const prefix = nameTransform.packageNameToPrefix(packageName);
47
+ const unifiedMeta = syncMeta.readUnifiedSyncMeta(destDir) ?? syncMeta.createEmptyUnifiedMeta();
48
+ if (!options.force &&
49
+ !syncMeta.needsSyncUnified(unifiedMeta, prefix, packageInfo.version)) {
50
+ return {
51
+ packageName,
52
+ success: true,
53
+ skipped: true,
54
+ reason: `Already synced at version ${packageInfo.version}`,
55
+ };
56
+ }
57
+ const tag = options.ref ?? _package.buildVersionTag(packageName, packageInfo.version);
58
+ const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
59
+ logger.logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
60
+ const assetTypes = _package.getAssetTypes(packageInfo.claude);
61
+ const assetFiles = await github.fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
62
+ let totalFiles = 0;
63
+ for (const assetType of assetTypes) {
64
+ totalFiles += (assetFiles[assetType] || []).length;
65
+ }
66
+ if (totalFiles === 0)
67
+ return {
68
+ packageName,
69
+ success: false,
70
+ skipped: true,
71
+ reason: `No assets found in package (checked: ${assetTypes.join(', ')})`,
72
+ };
73
+ const foundSummary = assetTypes
74
+ .map((type) => `${(assetFiles[type] || []).length} ${type}`)
75
+ .join(', ');
76
+ logger.logger.step('Found', foundSummary);
77
+ const fileMappings = {};
78
+ for (const assetType of assetTypes) {
79
+ const entries = assetFiles[assetType] || [];
80
+ if (entries.length === 0)
81
+ continue;
82
+ const filteredEntries = entries.filter((entry) => {
83
+ if (!exclusions)
84
+ return true;
85
+ const excludedPath = `${assetType}/${entry.name}`;
86
+ return !exclusions.files.includes(excludedPath);
87
+ });
88
+ if (filteredEntries.length === 0)
89
+ continue;
90
+ const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
91
+ if (structure === 'nested') {
92
+ fileMappings[assetType] = filteredEntries.map((e) => e.name);
93
+ }
94
+ else {
95
+ fileMappings[assetType] = filteredEntries.map((entry) => ({
96
+ original: entry.name,
97
+ transformed: nameTransform.toFlatFileName(prefix, entry.name),
98
+ }));
99
+ }
100
+ }
101
+ if (options.dryRun) {
102
+ for (const assetType of assetTypes) {
103
+ const mappings = fileMappings[assetType];
104
+ if (!mappings || mappings.length === 0)
105
+ continue;
106
+ const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
107
+ if (structure === 'nested') {
108
+ logger.logger.step(`Would sync ${assetType} to`, paths.getDestinationDir(destDir, packageName, assetType));
109
+ mappings.forEach((fileName) => {
110
+ logger.logger.file('create', fileName);
111
+ });
112
+ }
113
+ else {
114
+ logger.logger.step(`Would sync ${assetType} to`, paths.getFlatDestinationDir(destDir, assetType));
115
+ mappings.forEach((mapping) => {
116
+ logger.logger.file('create', mapping.transformed);
117
+ });
118
+ }
119
+ }
120
+ const syncedFiles = {};
121
+ for (const assetType of assetTypes) {
122
+ const mappings = fileMappings[assetType];
123
+ if (!mappings || mappings.length === 0)
124
+ continue;
125
+ if (typeof mappings[0] === 'string') {
126
+ syncedFiles[assetType] = mappings;
127
+ }
128
+ else {
129
+ syncedFiles[assetType] = mappings.map((m) => m.transformed);
130
+ }
131
+ }
132
+ return {
133
+ packageName,
134
+ success: true,
135
+ skipped: false,
136
+ syncedFiles,
137
+ };
138
+ }
139
+ for (const assetType of assetTypes) {
140
+ const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
141
+ if (structure === 'nested') {
142
+ filesystem.cleanAssetDir(destDir, packageName, assetType);
143
+ }
144
+ else {
145
+ filesystem.cleanFlatAssetFiles(destDir, assetType, prefix, unifiedMeta);
146
+ }
147
+ }
148
+ for (const assetType of assetTypes) {
149
+ const entries = assetFiles[assetType] || [];
150
+ if (entries.length === 0)
151
+ continue;
152
+ const filteredEntries = entries.filter((entry) => {
153
+ if (!exclusions)
154
+ return true;
155
+ const excludedPath = `${assetType}/${entry.name}`;
156
+ return !exclusions.files.includes(excludedPath);
157
+ });
158
+ if (filteredEntries.length === 0)
159
+ continue;
160
+ const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
161
+ logger.logger.step('Downloading', assetType);
162
+ const downloadedFiles = await github.downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
163
+ if (structure === 'nested') {
164
+ for (const [fileName, content] of downloadedFiles) {
165
+ filesystem.writeAssetFile(destDir, packageName, assetType, fileName, content);
166
+ logger.logger.file('create', fileName);
167
+ }
168
+ }
169
+ else {
170
+ const mappings = fileMappings[assetType];
171
+ for (const [fileName, content] of downloadedFiles) {
172
+ const mapping = mappings.find((m) => m.original === fileName);
173
+ const flatName = mapping?.transformed ?? nameTransform.toFlatFileName(prefix, fileName);
174
+ filesystem.writeFlatAssetFile(destDir, assetType, flatName, content);
175
+ logger.logger.file('create', flatName);
176
+ }
177
+ }
178
+ }
179
+ const updatedMeta = syncMeta.updatePackageInMeta(unifiedMeta, prefix, {
180
+ originalName: packageName,
181
+ version: packageInfo.version,
182
+ local: options.local,
183
+ files: fileMappings,
184
+ exclusions: exclusions &&
185
+ (exclusions.directories.length > 0 || exclusions.files.length > 0)
186
+ ? exclusions
187
+ : undefined,
188
+ });
189
+ syncMeta.writeUnifiedSyncMeta(destDir, updatedMeta);
190
+ const syncedFiles = {};
191
+ for (const assetType of assetTypes) {
192
+ const mappings = fileMappings[assetType];
193
+ if (!mappings || mappings.length === 0)
194
+ continue;
195
+ if (typeof mappings[0] === 'string') {
196
+ syncedFiles[assetType] = mappings;
197
+ }
198
+ else {
199
+ syncedFiles[assetType] = mappings.map((m) => m.transformed);
200
+ }
201
+ }
42
202
  return {
43
203
  packageName,
44
204
  success: true,
45
- skipped: true,
46
- reason: `Already synced at version ${packageInfo.version}`,
205
+ skipped: false,
206
+ syncedFiles,
47
207
  };
48
208
  }
49
- const tag = options.ref ?? _package.buildVersionTag(packageName, packageInfo.version);
50
- const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
51
- logger.logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
52
- const { commands, skills } = await github.fetchAssetFiles(repoInfo, assetPath, tag);
53
- if (commands.length === 0 && skills.length === 0)
54
- return {
55
- packageName,
56
- success: false,
57
- skipped: true,
58
- reason: 'No commands or skills found in package',
59
- };
60
- logger.logger.step('Found', `${commands.length} commands, ${skills.length} skills`);
61
- if (options.dryRun) {
62
- if (commands.length > 0) {
63
- logger.logger.step('Would sync commands to', filesystem.getDestinationDir(destDir, packageName, 'commands'));
64
- commands.forEach((entry) => logger.logger.file('create', entry.name));
209
+ else {
210
+ const tag = options.ref ?? _package.buildVersionTag(packageName, packageInfo.version);
211
+ const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
212
+ logger.logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
213
+ const assetTypes = _package.getAssetTypes(packageInfo.claude);
214
+ const assetFiles = await github.fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
215
+ let totalFiles = 0;
216
+ for (const assetType of assetTypes) {
217
+ totalFiles += (assetFiles[assetType] || []).length;
218
+ }
219
+ if (totalFiles === 0)
220
+ return {
221
+ packageName,
222
+ success: false,
223
+ skipped: true,
224
+ reason: `No assets found in package (checked: ${assetTypes.join(', ')})`,
225
+ };
226
+ const foundSummary = assetTypes
227
+ .map((type) => `${(assetFiles[type] || []).length} ${type}`)
228
+ .join(', ');
229
+ logger.logger.step('Found', foundSummary);
230
+ if (!options.force &&
231
+ !filesystem.needsSync(destDir, packageName, packageInfo.version, assetTypes)) {
232
+ return {
233
+ packageName,
234
+ success: true,
235
+ skipped: true,
236
+ reason: `Already synced at version ${packageInfo.version}`,
237
+ };
238
+ }
239
+ if (options.dryRun) {
240
+ const syncedFiles = {};
241
+ for (const assetType of assetTypes) {
242
+ const entries = assetFiles[assetType] || [];
243
+ if (entries.length === 0)
244
+ continue;
245
+ const filteredEntries = entries.filter((entry) => {
246
+ if (!exclusions)
247
+ return true;
248
+ const excludedPath = `${assetType}/${entry.name}`;
249
+ return !exclusions.files.includes(excludedPath);
250
+ });
251
+ if (filteredEntries.length === 0)
252
+ continue;
253
+ logger.logger.step(`Would sync ${assetType} to`, paths.getDestinationDir(destDir, packageName, assetType));
254
+ filteredEntries.forEach((entry) => logger.logger.file('create', entry.name));
255
+ syncedFiles[assetType] = filteredEntries.map((e) => e.name);
256
+ }
257
+ return {
258
+ packageName,
259
+ success: true,
260
+ skipped: false,
261
+ syncedFiles,
262
+ };
65
263
  }
66
- if (skills.length > 0) {
67
- logger.logger.step('Would sync skills to', filesystem.getDestinationDir(destDir, packageName, 'skills'));
68
- skills.forEach((entry) => logger.logger.file('create', entry.name));
264
+ const syncedFiles = {};
265
+ for (const assetType of assetTypes) {
266
+ const entries = assetFiles[assetType] || [];
267
+ if (entries.length === 0)
268
+ continue;
269
+ const filteredEntries = entries.filter((entry) => {
270
+ if (!exclusions)
271
+ return true;
272
+ const excludedPath = `${assetType}/${entry.name}`;
273
+ return !exclusions.files.includes(excludedPath);
274
+ });
275
+ if (filteredEntries.length === 0)
276
+ continue;
277
+ logger.logger.step('Downloading', assetType);
278
+ const downloadedFiles = await github.downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
279
+ filesystem.cleanAssetDir(destDir, packageName, assetType);
280
+ syncedFiles[assetType] = [];
281
+ for (const [fileName, content] of downloadedFiles) {
282
+ filesystem.writeAssetFile(destDir, packageName, assetType, fileName, content);
283
+ logger.logger.file('create', fileName);
284
+ syncedFiles[assetType].push(fileName);
285
+ }
286
+ filesystem.writeSyncMeta(destDir, packageName, assetType, filesystem.createSyncMeta(packageInfo.version, syncedFiles[assetType]));
69
287
  }
70
288
  return {
71
289
  packageName,
72
290
  success: true,
73
291
  skipped: false,
74
- syncedFiles: {
75
- commands: commands.map((e) => e.name),
76
- skills: skills.map((e) => e.name),
77
- },
292
+ syncedFiles,
78
293
  };
79
294
  }
80
- const syncedFiles = {
81
- commands: [],
82
- skills: [],
83
- };
84
- if (commands.length > 0) {
85
- logger.logger.step('Downloading', 'commands');
86
- const commandFiles = await github.downloadAssetFiles(repoInfo, assetPath, 'commands', commands, tag);
87
- filesystem.cleanAssetDir(destDir, packageName, 'commands');
88
- for (const [fileName, content] of commandFiles) {
89
- filesystem.writeAssetFile(destDir, packageName, 'commands', fileName, content);
90
- logger.logger.file('create', fileName);
91
- syncedFiles.commands.push(fileName);
92
- }
93
- filesystem.writeSyncMeta(destDir, packageName, 'commands', filesystem.createSyncMeta(packageInfo.version, syncedFiles.commands));
94
- }
95
- if (skills.length > 0) {
96
- logger.logger.step('Downloading', 'skills');
97
- const skillFiles = await github.downloadAssetFiles(repoInfo, assetPath, 'skills', skills, tag);
98
- filesystem.cleanAssetDir(destDir, packageName, 'skills');
99
- for (const [fileName, content] of skillFiles) {
100
- filesystem.writeAssetFile(destDir, packageName, 'skills', fileName, content);
101
- logger.logger.file('create', fileName);
102
- syncedFiles.skills.push(fileName);
103
- }
104
- filesystem.writeSyncMeta(destDir, packageName, 'skills', filesystem.createSyncMeta(packageInfo.version, syncedFiles.skills));
105
- }
106
- return {
107
- packageName,
108
- success: true,
109
- skipped: false,
110
- syncedFiles,
111
- };
112
295
  }
113
296
  catch (error) {
114
297
  if (error instanceof github.RateLimitError)
@@ -133,7 +316,7 @@ const syncPackages = async (packages, options, cwd = process.cwd()) => {
133
316
  if (gitRoot)
134
317
  logger.logger.info(`[Output] ${gitRoot}/.claude\n`);
135
318
  for (const packageName of packages) {
136
- const result = await syncPackage(packageName, options, cwd, gitRoot ?? undefined);
319
+ const result = await syncPackage(packageName, options, cwd, undefined, gitRoot ?? undefined);
137
320
  logger.logger.packageEnd(packageName, result);
138
321
  results.push(result);
139
322
  }
@@ -4,9 +4,13 @@ import type { CliOptions, SyncResult } from '../utils/types';
4
4
  * @param packageName - Package name to sync
5
5
  * @param options - CLI options
6
6
  * @param cwd - Current working directory
7
+ * @param exclusions - Optional exclusions for selective syncing
7
8
  * @returns Sync result
8
9
  */
9
- export declare const syncPackage: (packageName: string, options: Pick<CliOptions, "force" | "dryRun" | "local" | "ref">, cwd?: string, outputDir?: string) => Promise<SyncResult>;
10
+ export declare const syncPackage: (packageName: string, options: Pick<CliOptions, "force" | "dryRun" | "local" | "ref" | "flat">, cwd?: string, exclusions?: {
11
+ directories: string[];
12
+ files: string[];
13
+ }, outputDir?: string) => Promise<SyncResult>;
10
14
  /**
11
15
  * Sync Claude assets for multiple packages
12
16
  * @param packages - List of package names to sync
@@ -14,4 +18,4 @@ export declare const syncPackage: (packageName: string, options: Pick<CliOptions
14
18
  * @param cwd - Current working directory
15
19
  * @returns Array of sync results
16
20
  */
17
- export declare const syncPackages: (packages: string[], options: Pick<CliOptions, "force" | "dryRun" | "local" | "ref">, cwd?: string) => Promise<SyncResult[]>;
21
+ export declare const syncPackages: (packages: string[], options: Pick<CliOptions, "force" | "dryRun" | "local" | "ref" | "flat">, cwd?: string) => Promise<SyncResult[]>;