@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.
- package/dist/commands/add.cjs +24 -0
- package/dist/commands/add.d.ts +2 -6
- package/dist/commands/add.mjs +24 -0
- package/dist/commands/index.d.ts +1 -2
- package/dist/commands/list.cjs +12 -1
- package/dist/commands/list.d.ts +10 -1
- package/dist/commands/list.mjs +12 -2
- package/dist/commands/remove.cjs +49 -31
- package/dist/commands/remove.mjs +49 -30
- package/dist/commands/types.d.ts +9 -0
- package/dist/commands/update.cjs +27 -0
- package/dist/commands/update.d.ts +16 -0
- package/dist/commands/update.mjs +27 -1
- package/dist/components/add/BulkAddView.cjs +169 -0
- package/dist/components/add/BulkAddView.d.ts +11 -0
- package/dist/components/add/BulkAddView.mjs +167 -0
- package/dist/components/list/ListCommand.cjs +585 -392
- package/dist/components/list/ListCommand.d.ts +0 -3
- package/dist/components/list/ListCommand.mjs +590 -377
- package/dist/components/list/index.d.ts +1 -0
- package/dist/components/list/types.d.ts +14 -0
- package/dist/components/remove/RemoveConfirm.cjs +18 -0
- package/dist/components/remove/RemoveConfirm.d.ts +11 -0
- package/dist/components/remove/RemoveConfirm.mjs +16 -0
- package/dist/components/shared/Confirm.cjs +30 -0
- package/dist/components/shared/Confirm.d.ts +8 -0
- package/dist/components/shared/Confirm.mjs +28 -0
- package/dist/components/shared/MenuItem.cjs +18 -0
- package/dist/components/shared/MenuItem.d.ts +7 -0
- package/dist/components/shared/MenuItem.mjs +16 -0
- package/dist/components/shared/ProgressBar.d.ts +7 -0
- package/dist/components/shared/StepRunner.cjs +58 -0
- package/dist/components/shared/StepRunner.d.ts +15 -0
- package/dist/components/shared/StepRunner.mjs +56 -0
- package/dist/components/shared/Table.cjs +19 -0
- package/dist/components/shared/Table.d.ts +8 -0
- package/dist/components/shared/Table.mjs +17 -0
- package/dist/components/shared/index.d.ts +6 -0
- package/dist/core/cli.cjs +4 -8
- package/dist/core/cli.mjs +5 -9
- package/dist/core/constants.cjs +2 -0
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/constants.mjs +2 -1
- package/dist/core/io.mjs +1 -1
- package/dist/core/listOperations.cjs +228 -0
- package/dist/core/listOperations.d.ts +43 -0
- package/dist/core/listOperations.mjs +205 -0
- package/dist/core/packageScanner.cjs +8 -6
- package/dist/core/packageScanner.mjs +9 -7
- package/dist/core/sync.cjs +9 -15
- package/dist/core/sync.mjs +10 -16
- package/dist/utils/asyncPool.cjs +26 -0
- package/dist/utils/asyncPool.d.ts +5 -0
- package/dist/utils/asyncPool.mjs +24 -0
- package/dist/utils/dependencies.cjs +57 -0
- package/dist/utils/dependencies.d.ts +10 -0
- package/dist/utils/dependencies.mjs +34 -0
- package/dist/utils/package.cjs +5 -0
- package/dist/utils/package.d.ts +6 -1
- package/dist/utils/package.mjs +6 -2
- 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
|
|
43
|
-
throw new Error(`Package ${packageName}
|
|
42
|
+
if (!pkgInfo) {
|
|
43
|
+
throw new Error(`Package ${packageName} not found in local workspace`);
|
|
44
44
|
}
|
|
45
|
-
const
|
|
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
|
|
66
|
-
throw new Error(`Package ${packageName}
|
|
66
|
+
if (!pkgInfo) {
|
|
67
|
+
throw new Error(`Package ${packageName} not found`);
|
|
67
68
|
}
|
|
68
|
-
const
|
|
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
|
|
41
|
-
throw new Error(`Package ${packageName}
|
|
40
|
+
if (!pkgInfo) {
|
|
41
|
+
throw new Error(`Package ${packageName} not found in local workspace`);
|
|
42
42
|
}
|
|
43
|
-
const
|
|
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
|
|
64
|
-
throw new Error(`Package ${packageName}
|
|
64
|
+
if (!pkgInfo) {
|
|
65
|
+
throw new Error(`Package ${packageName} not found`);
|
|
65
66
|
}
|
|
66
|
-
const
|
|
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)) {
|
package/dist/core/sync.cjs
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
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(
|
|
253
|
+
const assetTypes = _package.getAssetTypes(claudeConfig);
|
|
260
254
|
let assetFiles;
|
|
261
255
|
let isLocalSource;
|
|
262
256
|
if (useLocalSource.available && useLocalSource.docsPath) {
|