@slats/claude-assets-sync 0.1.0 → 0.1.1

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 (61) hide show
  1. package/dist/commands/add.cjs +24 -0
  2. package/dist/commands/add.d.ts +2 -6
  3. package/dist/commands/add.mjs +24 -0
  4. package/dist/commands/index.d.ts +1 -2
  5. package/dist/commands/list.cjs +12 -1
  6. package/dist/commands/list.d.ts +10 -1
  7. package/dist/commands/list.mjs +12 -2
  8. package/dist/commands/remove.cjs +49 -31
  9. package/dist/commands/remove.mjs +49 -30
  10. package/dist/commands/types.d.ts +9 -0
  11. package/dist/commands/update.cjs +27 -0
  12. package/dist/commands/update.d.ts +16 -0
  13. package/dist/commands/update.mjs +27 -1
  14. package/dist/components/add/BulkAddView.cjs +169 -0
  15. package/dist/components/add/BulkAddView.d.ts +11 -0
  16. package/dist/components/add/BulkAddView.mjs +167 -0
  17. package/dist/components/list/ListCommand.cjs +585 -392
  18. package/dist/components/list/ListCommand.d.ts +0 -3
  19. package/dist/components/list/ListCommand.mjs +590 -377
  20. package/dist/components/list/index.d.ts +1 -0
  21. package/dist/components/list/types.d.ts +14 -0
  22. package/dist/components/remove/RemoveConfirm.cjs +18 -0
  23. package/dist/components/remove/RemoveConfirm.d.ts +11 -0
  24. package/dist/components/remove/RemoveConfirm.mjs +16 -0
  25. package/dist/components/shared/Confirm.cjs +30 -0
  26. package/dist/components/shared/Confirm.d.ts +8 -0
  27. package/dist/components/shared/Confirm.mjs +28 -0
  28. package/dist/components/shared/MenuItem.cjs +18 -0
  29. package/dist/components/shared/MenuItem.d.ts +7 -0
  30. package/dist/components/shared/MenuItem.mjs +16 -0
  31. package/dist/components/shared/ProgressBar.d.ts +7 -0
  32. package/dist/components/shared/StepRunner.cjs +58 -0
  33. package/dist/components/shared/StepRunner.d.ts +15 -0
  34. package/dist/components/shared/StepRunner.mjs +56 -0
  35. package/dist/components/shared/Table.cjs +19 -0
  36. package/dist/components/shared/Table.d.ts +8 -0
  37. package/dist/components/shared/Table.mjs +17 -0
  38. package/dist/components/shared/index.d.ts +6 -0
  39. package/dist/core/cli.cjs +4 -8
  40. package/dist/core/cli.mjs +5 -9
  41. package/dist/core/constants.cjs +2 -0
  42. package/dist/core/constants.d.ts +4 -0
  43. package/dist/core/constants.mjs +2 -1
  44. package/dist/core/io.mjs +1 -1
  45. package/dist/core/listOperations.cjs +228 -0
  46. package/dist/core/listOperations.d.ts +43 -0
  47. package/dist/core/listOperations.mjs +205 -0
  48. package/dist/core/packageScanner.cjs +8 -6
  49. package/dist/core/packageScanner.mjs +9 -7
  50. package/dist/core/sync.cjs +9 -15
  51. package/dist/core/sync.mjs +10 -16
  52. package/dist/utils/asyncPool.cjs +26 -0
  53. package/dist/utils/asyncPool.d.ts +5 -0
  54. package/dist/utils/asyncPool.mjs +24 -0
  55. package/dist/utils/dependencies.cjs +57 -0
  56. package/dist/utils/dependencies.d.ts +10 -0
  57. package/dist/utils/dependencies.mjs +34 -0
  58. package/dist/utils/package.cjs +5 -0
  59. package/dist/utils/package.d.ts +6 -1
  60. package/dist/utils/package.mjs +6 -2
  61. package/package.json +2 -1
@@ -0,0 +1,228 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs');
4
+ var path = require('node:path');
5
+ var sync = require('./sync.cjs');
6
+ var syncMeta = require('./syncMeta.cjs');
7
+
8
+ function _interopNamespaceDefault(e) {
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
26
+ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
27
+
28
+ function computeFileOperations(meta, packageFiles, selectedTrees, cwd) {
29
+ const newPackageFiles = { ...packageFiles };
30
+ for (const packageTree of selectedTrees) {
31
+ const prefix = packageTree.id;
32
+ if (!newPackageFiles[prefix])
33
+ continue;
34
+ const selectedPaths = new Set();
35
+ if (packageTree.children) {
36
+ for (const assetTypeNode of packageTree.children) {
37
+ if (assetTypeNode.children) {
38
+ for (const fileNode of assetTypeNode.children) {
39
+ if (fileNode.disabled)
40
+ continue;
41
+ if (fileNode.selected) {
42
+ selectedPaths.add(fileNode.path);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ newPackageFiles[prefix] = {
49
+ ...newPackageFiles[prefix],
50
+ selected: selectedPaths,
51
+ };
52
+ }
53
+ const fileOperations = [];
54
+ const filesToDelete = [];
55
+ const packagesToSync = [];
56
+ for (const [prefix] of Object.entries(meta.packages)) {
57
+ const packageTree = selectedTrees.find((t) => t.id === prefix);
58
+ const packageInfo = meta.packages[prefix];
59
+ const packageData = newPackageFiles[prefix];
60
+ if (!packageTree || !packageTree.selected || !packageData) {
61
+ for (const [assetType, files] of Object.entries(packageInfo.files)) {
62
+ if (!Array.isArray(files))
63
+ continue;
64
+ const units = files;
65
+ for (const unit of units) {
66
+ fileOperations.push({
67
+ type: 'remove',
68
+ prefix,
69
+ assetType,
70
+ skillName: unit.name,
71
+ });
72
+ }
73
+ const firstUnit = units[0];
74
+ if (firstUnit?.transformed) {
75
+ for (const unit of units) {
76
+ const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
77
+ filesToDelete.push(targetPath);
78
+ }
79
+ }
80
+ else {
81
+ const dirPath = path__namespace.join(cwd, '.claude', assetType, packageInfo.originalName);
82
+ filesToDelete.push(dirPath);
83
+ }
84
+ }
85
+ continue;
86
+ }
87
+ let hasChanges = false;
88
+ const selectedByAssetType = {};
89
+ for (const filePath of packageData.selected) {
90
+ const [assetType, fileName] = filePath.split('/');
91
+ if (!selectedByAssetType[assetType]) {
92
+ selectedByAssetType[assetType] = new Set();
93
+ }
94
+ selectedByAssetType[assetType].add(fileName);
95
+ }
96
+ for (const [assetType, originalFiles] of Object.entries(packageInfo.files)) {
97
+ const selectedFiles = selectedByAssetType[assetType];
98
+ const units = Array.isArray(originalFiles)
99
+ ? originalFiles
100
+ : [];
101
+ const firstUnit = units[0];
102
+ const isFlat = !!firstUnit?.transformed;
103
+ if (!selectedFiles || selectedFiles.size === 0) {
104
+ hasChanges = true;
105
+ for (const unit of units) {
106
+ fileOperations.push({
107
+ type: 'remove',
108
+ prefix,
109
+ assetType,
110
+ skillName: unit.name,
111
+ });
112
+ }
113
+ if (isFlat) {
114
+ for (const unit of units) {
115
+ const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
116
+ filesToDelete.push(targetPath);
117
+ }
118
+ }
119
+ else {
120
+ const dirPath = path__namespace.join(cwd, '.claude', assetType, packageInfo.originalName);
121
+ filesToDelete.push(dirPath);
122
+ }
123
+ continue;
124
+ }
125
+ const originalNames = new Set(units.map((u) => u.name));
126
+ for (const unit of units) {
127
+ if (!selectedFiles.has(unit.name)) {
128
+ hasChanges = true;
129
+ fileOperations.push({
130
+ type: 'remove',
131
+ prefix,
132
+ assetType,
133
+ skillName: unit.name,
134
+ });
135
+ if (unit.transformed) {
136
+ const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
137
+ filesToDelete.push(targetPath);
138
+ }
139
+ else {
140
+ const filePath = path__namespace.join(cwd, '.claude', assetType, packageInfo.originalName, unit.name);
141
+ filesToDelete.push(filePath);
142
+ }
143
+ }
144
+ }
145
+ for (const skillName of selectedFiles) {
146
+ if (!originalNames.has(skillName)) {
147
+ hasChanges = true;
148
+ fileOperations.push({
149
+ type: 'add',
150
+ prefix,
151
+ assetType,
152
+ skillName,
153
+ });
154
+ }
155
+ }
156
+ }
157
+ if (hasChanges) {
158
+ packagesToSync.push({
159
+ prefix,
160
+ name: packageInfo.originalName,
161
+ local: packageInfo.local,
162
+ });
163
+ }
164
+ }
165
+ return { filesToDelete, fileOperations, packagesToSync };
166
+ }
167
+ async function applyChangesAndSync(changesSummary, meta, cwd, callbacks) {
168
+ const syncErrors = [];
169
+ for (const filePath of changesSummary.filesToDelete) {
170
+ try {
171
+ const stat = fs__namespace.statSync(filePath);
172
+ if (stat.isDirectory()) {
173
+ fs__namespace.rmSync(filePath, { recursive: true, force: true });
174
+ }
175
+ else {
176
+ fs__namespace.unlinkSync(filePath);
177
+ }
178
+ }
179
+ catch (error) {
180
+ if (error.code !== 'ENOENT') {
181
+ console.error(`Failed to remove ${filePath}: ${error}`);
182
+ }
183
+ }
184
+ }
185
+ let updatedMeta = { ...meta };
186
+ const hasAddOperations = changesSummary.fileOperations.some((op) => op.type === 'add');
187
+ for (const op of changesSummary.fileOperations) {
188
+ if (op.type === 'remove') {
189
+ updatedMeta = syncMeta.removeSkillUnitFromPackage(updatedMeta, op.prefix, op.assetType, op.skillName);
190
+ }
191
+ }
192
+ for (const prefix of Object.keys(updatedMeta.packages)) {
193
+ const pkg = updatedMeta.packages[prefix];
194
+ if (!pkg.files || Object.keys(pkg.files).length === 0) {
195
+ updatedMeta = syncMeta.removePackageFromMeta(updatedMeta, prefix);
196
+ }
197
+ }
198
+ syncMeta.writeUnifiedSyncMeta(cwd, updatedMeta);
199
+ if (hasAddOperations && changesSummary.packagesToSync.length > 0) {
200
+ callbacks?.onSyncStart?.();
201
+ for (const { prefix, name, local } of changesSummary.packagesToSync) {
202
+ try {
203
+ const removedFiles = changesSummary.fileOperations
204
+ .filter((op) => op.type === 'remove' && op.prefix === prefix)
205
+ .map((op) => `${op.assetType}/${op.skillName}`);
206
+ const exclusions = removedFiles.length > 0
207
+ ? { directories: [], files: removedFiles }
208
+ : undefined;
209
+ await sync.syncPackage(name, {
210
+ force: true,
211
+ dryRun: false,
212
+ local: local ?? false,
213
+ ref: undefined,
214
+ flat: undefined,
215
+ }, cwd, exclusions);
216
+ }
217
+ catch (error) {
218
+ const msg = `Failed to sync ${name}: ${error}`;
219
+ console.error(msg);
220
+ syncErrors.push(msg);
221
+ }
222
+ }
223
+ }
224
+ return { updatedMeta, syncErrors };
225
+ }
226
+
227
+ exports.applyChangesAndSync = applyChangesAndSync;
228
+ exports.computeFileOperations = computeFileOperations;
@@ -0,0 +1,43 @@
1
+ import type { TreeNode, UnifiedSyncMeta } from '../utils/types.js';
2
+ export type FileOperation = {
3
+ type: 'add';
4
+ prefix: string;
5
+ assetType: string;
6
+ skillName: string;
7
+ } | {
8
+ type: 'remove';
9
+ prefix: string;
10
+ assetType: string;
11
+ skillName: string;
12
+ };
13
+ export interface ChangesSummary {
14
+ filesToDelete: string[];
15
+ fileOperations: FileOperation[];
16
+ packagesToSync: Array<{
17
+ prefix: string;
18
+ name: string;
19
+ local?: boolean;
20
+ }>;
21
+ }
22
+ export interface PackageFiles {
23
+ [prefix: string]: {
24
+ available: TreeNode[];
25
+ selected: Set<string>;
26
+ };
27
+ }
28
+ /**
29
+ * Pure computation: given current meta, packageFiles, and selected trees,
30
+ * compute what file operations need to happen.
31
+ * No React state, no side effects.
32
+ */
33
+ export declare function computeFileOperations(meta: UnifiedSyncMeta, packageFiles: PackageFiles, selectedTrees: TreeNode[], cwd: string): ChangesSummary;
34
+ /**
35
+ * Apply file changes and sync packages.
36
+ * Has side effects (filesystem writes, sync calls) but NO React/ink dependencies.
37
+ */
38
+ export declare function applyChangesAndSync(changesSummary: ChangesSummary, meta: UnifiedSyncMeta, cwd: string, callbacks?: {
39
+ onSyncStart?: () => void;
40
+ }): Promise<{
41
+ updatedMeta: UnifiedSyncMeta;
42
+ syncErrors: string[];
43
+ }>;
@@ -0,0 +1,205 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { syncPackage } from './sync.mjs';
4
+ import { removeSkillUnitFromPackage, removePackageFromMeta, writeUnifiedSyncMeta } from './syncMeta.mjs';
5
+
6
+ function computeFileOperations(meta, packageFiles, selectedTrees, cwd) {
7
+ const newPackageFiles = { ...packageFiles };
8
+ for (const packageTree of selectedTrees) {
9
+ const prefix = packageTree.id;
10
+ if (!newPackageFiles[prefix])
11
+ continue;
12
+ const selectedPaths = new Set();
13
+ if (packageTree.children) {
14
+ for (const assetTypeNode of packageTree.children) {
15
+ if (assetTypeNode.children) {
16
+ for (const fileNode of assetTypeNode.children) {
17
+ if (fileNode.disabled)
18
+ continue;
19
+ if (fileNode.selected) {
20
+ selectedPaths.add(fileNode.path);
21
+ }
22
+ }
23
+ }
24
+ }
25
+ }
26
+ newPackageFiles[prefix] = {
27
+ ...newPackageFiles[prefix],
28
+ selected: selectedPaths,
29
+ };
30
+ }
31
+ const fileOperations = [];
32
+ const filesToDelete = [];
33
+ const packagesToSync = [];
34
+ for (const [prefix] of Object.entries(meta.packages)) {
35
+ const packageTree = selectedTrees.find((t) => t.id === prefix);
36
+ const packageInfo = meta.packages[prefix];
37
+ const packageData = newPackageFiles[prefix];
38
+ if (!packageTree || !packageTree.selected || !packageData) {
39
+ for (const [assetType, files] of Object.entries(packageInfo.files)) {
40
+ if (!Array.isArray(files))
41
+ continue;
42
+ const units = files;
43
+ for (const unit of units) {
44
+ fileOperations.push({
45
+ type: 'remove',
46
+ prefix,
47
+ assetType,
48
+ skillName: unit.name,
49
+ });
50
+ }
51
+ const firstUnit = units[0];
52
+ if (firstUnit?.transformed) {
53
+ for (const unit of units) {
54
+ const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
55
+ filesToDelete.push(targetPath);
56
+ }
57
+ }
58
+ else {
59
+ const dirPath = path.join(cwd, '.claude', assetType, packageInfo.originalName);
60
+ filesToDelete.push(dirPath);
61
+ }
62
+ }
63
+ continue;
64
+ }
65
+ let hasChanges = false;
66
+ const selectedByAssetType = {};
67
+ for (const filePath of packageData.selected) {
68
+ const [assetType, fileName] = filePath.split('/');
69
+ if (!selectedByAssetType[assetType]) {
70
+ selectedByAssetType[assetType] = new Set();
71
+ }
72
+ selectedByAssetType[assetType].add(fileName);
73
+ }
74
+ for (const [assetType, originalFiles] of Object.entries(packageInfo.files)) {
75
+ const selectedFiles = selectedByAssetType[assetType];
76
+ const units = Array.isArray(originalFiles)
77
+ ? originalFiles
78
+ : [];
79
+ const firstUnit = units[0];
80
+ const isFlat = !!firstUnit?.transformed;
81
+ if (!selectedFiles || selectedFiles.size === 0) {
82
+ hasChanges = true;
83
+ for (const unit of units) {
84
+ fileOperations.push({
85
+ type: 'remove',
86
+ prefix,
87
+ assetType,
88
+ skillName: unit.name,
89
+ });
90
+ }
91
+ if (isFlat) {
92
+ for (const unit of units) {
93
+ const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
94
+ filesToDelete.push(targetPath);
95
+ }
96
+ }
97
+ else {
98
+ const dirPath = path.join(cwd, '.claude', assetType, packageInfo.originalName);
99
+ filesToDelete.push(dirPath);
100
+ }
101
+ continue;
102
+ }
103
+ const originalNames = new Set(units.map((u) => u.name));
104
+ for (const unit of units) {
105
+ if (!selectedFiles.has(unit.name)) {
106
+ hasChanges = true;
107
+ fileOperations.push({
108
+ type: 'remove',
109
+ prefix,
110
+ assetType,
111
+ skillName: unit.name,
112
+ });
113
+ if (unit.transformed) {
114
+ const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
115
+ filesToDelete.push(targetPath);
116
+ }
117
+ else {
118
+ const filePath = path.join(cwd, '.claude', assetType, packageInfo.originalName, unit.name);
119
+ filesToDelete.push(filePath);
120
+ }
121
+ }
122
+ }
123
+ for (const skillName of selectedFiles) {
124
+ if (!originalNames.has(skillName)) {
125
+ hasChanges = true;
126
+ fileOperations.push({
127
+ type: 'add',
128
+ prefix,
129
+ assetType,
130
+ skillName,
131
+ });
132
+ }
133
+ }
134
+ }
135
+ if (hasChanges) {
136
+ packagesToSync.push({
137
+ prefix,
138
+ name: packageInfo.originalName,
139
+ local: packageInfo.local,
140
+ });
141
+ }
142
+ }
143
+ return { filesToDelete, fileOperations, packagesToSync };
144
+ }
145
+ async function applyChangesAndSync(changesSummary, meta, cwd, callbacks) {
146
+ const syncErrors = [];
147
+ for (const filePath of changesSummary.filesToDelete) {
148
+ try {
149
+ const stat = fs.statSync(filePath);
150
+ if (stat.isDirectory()) {
151
+ fs.rmSync(filePath, { recursive: true, force: true });
152
+ }
153
+ else {
154
+ fs.unlinkSync(filePath);
155
+ }
156
+ }
157
+ catch (error) {
158
+ if (error.code !== 'ENOENT') {
159
+ console.error(`Failed to remove ${filePath}: ${error}`);
160
+ }
161
+ }
162
+ }
163
+ let updatedMeta = { ...meta };
164
+ const hasAddOperations = changesSummary.fileOperations.some((op) => op.type === 'add');
165
+ for (const op of changesSummary.fileOperations) {
166
+ if (op.type === 'remove') {
167
+ updatedMeta = removeSkillUnitFromPackage(updatedMeta, op.prefix, op.assetType, op.skillName);
168
+ }
169
+ }
170
+ for (const prefix of Object.keys(updatedMeta.packages)) {
171
+ const pkg = updatedMeta.packages[prefix];
172
+ if (!pkg.files || Object.keys(pkg.files).length === 0) {
173
+ updatedMeta = removePackageFromMeta(updatedMeta, prefix);
174
+ }
175
+ }
176
+ writeUnifiedSyncMeta(cwd, updatedMeta);
177
+ if (hasAddOperations && changesSummary.packagesToSync.length > 0) {
178
+ callbacks?.onSyncStart?.();
179
+ for (const { prefix, name, local } of changesSummary.packagesToSync) {
180
+ try {
181
+ const removedFiles = changesSummary.fileOperations
182
+ .filter((op) => op.type === 'remove' && op.prefix === prefix)
183
+ .map((op) => `${op.assetType}/${op.skillName}`);
184
+ const exclusions = removedFiles.length > 0
185
+ ? { directories: [], files: removedFiles }
186
+ : undefined;
187
+ await syncPackage(name, {
188
+ force: true,
189
+ dryRun: false,
190
+ local: local ?? false,
191
+ ref: undefined,
192
+ flat: undefined,
193
+ }, cwd, exclusions);
194
+ }
195
+ catch (error) {
196
+ const msg = `Failed to sync ${name}: ${error}`;
197
+ console.error(msg);
198
+ syncErrors.push(msg);
199
+ }
200
+ }
201
+ }
202
+ return { updatedMeta, syncErrors };
203
+ }
204
+
205
+ export { applyChangesAndSync, computeFileOperations };
@@ -39,10 +39,11 @@ async function scanLocalAssets(packageName, cwd) {
39
39
  throw new Error(`Package ${packageName} not found in local workspace`);
40
40
  }
41
41
  const pkgInfo = readPackageJsonFromPath(packagePath);
42
- if (!pkgInfo || !pkgInfo.claude?.assetPath) {
43
- throw new Error(`Package ${packageName} has no claude.assetPath configured`);
42
+ if (!pkgInfo) {
43
+ throw new Error(`Package ${packageName} not found in local workspace`);
44
44
  }
45
- const assetPath = path.join(packagePath, pkgInfo.claude.assetPath);
45
+ const claudeConfig = _package.resolveClaudeConfig(pkgInfo.claude);
46
+ const assetPath = path.join(packagePath, claudeConfig.assetPath);
46
47
  if (!fs.existsSync(assetPath)) {
47
48
  throw new Error(`Asset path ${assetPath} does not exist`);
48
49
  }
@@ -62,10 +63,11 @@ async function scanLocalAssets(packageName, cwd) {
62
63
  async function scanRemoteAssets(packageName, ref) {
63
64
  const nodeModulesPath = path.join(process.cwd(), 'node_modules', packageName);
64
65
  const pkgInfo = readPackageJsonFromPath(nodeModulesPath);
65
- if (!pkgInfo || !pkgInfo.claude?.assetPath) {
66
- throw new Error(`Package ${packageName} has no claude.assetPath configured`);
66
+ if (!pkgInfo) {
67
+ throw new Error(`Package ${packageName} not found`);
67
68
  }
68
- const assetBasePath = pkgInfo.claude.assetPath;
69
+ const claudeConfig = _package.resolveClaudeConfig(pkgInfo.claude);
70
+ const assetBasePath = claudeConfig.assetPath;
69
71
  if (!ref) {
70
72
  const localDocsPath = path.join(nodeModulesPath, assetBasePath);
71
73
  if (fs.existsSync(localDocsPath)) {
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { toFlatFileName } from '../utils/nameTransform.mjs';
4
- import { parseGitHubRepo } from '../utils/package.mjs';
4
+ import { resolveClaudeConfig, parseGitHubRepo } from '../utils/package.mjs';
5
5
  import { DEFAULT_ASSET_TYPES } from './constants.mjs';
6
6
  import { fetchDirectoryContents } from './github.mjs';
7
7
 
@@ -37,10 +37,11 @@ async function scanLocalAssets(packageName, cwd) {
37
37
  throw new Error(`Package ${packageName} not found in local workspace`);
38
38
  }
39
39
  const pkgInfo = readPackageJsonFromPath(packagePath);
40
- if (!pkgInfo || !pkgInfo.claude?.assetPath) {
41
- throw new Error(`Package ${packageName} has no claude.assetPath configured`);
40
+ if (!pkgInfo) {
41
+ throw new Error(`Package ${packageName} not found in local workspace`);
42
42
  }
43
- const assetPath = join(packagePath, pkgInfo.claude.assetPath);
43
+ const claudeConfig = resolveClaudeConfig(pkgInfo.claude);
44
+ const assetPath = join(packagePath, claudeConfig.assetPath);
44
45
  if (!existsSync(assetPath)) {
45
46
  throw new Error(`Asset path ${assetPath} does not exist`);
46
47
  }
@@ -60,10 +61,11 @@ async function scanLocalAssets(packageName, cwd) {
60
61
  async function scanRemoteAssets(packageName, ref) {
61
62
  const nodeModulesPath = join(process.cwd(), 'node_modules', packageName);
62
63
  const pkgInfo = readPackageJsonFromPath(nodeModulesPath);
63
- if (!pkgInfo || !pkgInfo.claude?.assetPath) {
64
- throw new Error(`Package ${packageName} has no claude.assetPath configured`);
64
+ if (!pkgInfo) {
65
+ throw new Error(`Package ${packageName} not found`);
65
66
  }
66
- const assetBasePath = pkgInfo.claude.assetPath;
67
+ const claudeConfig = resolveClaudeConfig(pkgInfo.claude);
68
+ const assetBasePath = claudeConfig.assetPath;
67
69
  if (!ref) {
68
70
  const localDocsPath = join(nodeModulesPath, assetBasePath);
69
71
  if (existsSync(localDocsPath)) {
@@ -60,13 +60,7 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
60
60
  reason: `Package not found in ${location}`,
61
61
  };
62
62
  }
63
- if (!packageInfo.claude?.assetPath)
64
- return {
65
- packageName: packageName$1,
66
- success: false,
67
- skipped: true,
68
- reason: 'Package does not have claude.assetPath in package.json',
69
- };
63
+ const claudeConfig = _package.resolveClaudeConfig(packageInfo.claude);
70
64
  const repoInfo = _package.parseGitHubRepo(packageInfo.repository);
71
65
  const useFlat = options.flat !== false;
72
66
  if (useFlat) {
@@ -81,11 +75,11 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
81
75
  reason: `Already synced at version ${packageInfo.version}`,
82
76
  };
83
77
  }
84
- const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
78
+ const assetPath = _package.buildAssetPath(claudeConfig.assetPath);
85
79
  const useLocalSource = options.ref
86
80
  ? { available: false }
87
81
  : localSource.canUseLocalSource(packageName$1, packageInfo.version, assetPath, cwd);
88
- const assetTypes = _package.getAssetTypes(packageInfo.claude);
82
+ const assetTypes = _package.getAssetTypes(claudeConfig);
89
83
  let assetFiles;
90
84
  let isLocalSource;
91
85
  if (useLocalSource.available && useLocalSource.docsPath) {
@@ -135,7 +129,7 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
135
129
  });
136
130
  if (filteredEntries.length === 0)
137
131
  continue;
138
- const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
132
+ const structure = assetStructure.getAssetStructure(assetType, claudeConfig);
139
133
  if (structure === 'nested') {
140
134
  fileMappings[assetType] = filteredEntries.map((e) => ({
141
135
  name: e.name,
@@ -151,7 +145,7 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
151
145
  const units = fileMappings[assetType];
152
146
  if (!units || units.length === 0)
153
147
  continue;
154
- const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
148
+ const structure = assetStructure.getAssetStructure(assetType, claudeConfig);
155
149
  if (structure === 'nested') {
156
150
  logger.logger.step(`Would sync ${assetType} to`, paths.getDestinationDir(destDir, packageName$1, assetType));
157
151
  units.forEach((unit) => {
@@ -181,7 +175,7 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
181
175
  };
182
176
  }
183
177
  for (const assetType of assetTypes) {
184
- const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
178
+ const structure = assetStructure.getAssetStructure(assetType, claudeConfig);
185
179
  if (structure === 'nested') {
186
180
  filesystem.cleanAssetDir(destDir, packageName$1, assetType);
187
181
  }
@@ -201,7 +195,7 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
201
195
  });
202
196
  if (filteredEntries.length === 0)
203
197
  continue;
204
- const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
198
+ const structure = assetStructure.getAssetStructure(assetType, claudeConfig);
205
199
  logger.logger.step('Downloading', assetType);
206
200
  let downloadedFiles;
207
201
  if (isLocalSource && useLocalSource.docsPath) {
@@ -252,11 +246,11 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
252
246
  };
253
247
  }
254
248
  else {
255
- const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
249
+ const assetPath = _package.buildAssetPath(claudeConfig.assetPath);
256
250
  const useLocalSource = options.ref
257
251
  ? { available: false }
258
252
  : localSource.canUseLocalSource(packageName$1, packageInfo.version, assetPath, cwd);
259
- const assetTypes = _package.getAssetTypes(packageInfo.claude);
253
+ const assetTypes = _package.getAssetTypes(claudeConfig);
260
254
  let assetFiles;
261
255
  let isLocalSource;
262
256
  if (useLocalSource.available && useLocalSource.docsPath) {