@slats/claude-assets-sync 0.0.4 → 0.0.5
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 +2 -7
- package/dist/commands/add.mjs +2 -7
- package/dist/commands/index.d.ts +22 -0
- package/dist/commands/remove.cjs +6 -6
- package/dist/commands/remove.mjs +6 -6
- package/dist/commands/types.d.ts +2 -4
- package/dist/commands/update.cjs +178 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.mjs +176 -0
- package/dist/components/add/AddCommand.cjs +11 -0
- package/dist/components/add/AddCommand.mjs +11 -0
- package/dist/components/list/ListCommand.cjs +65 -47
- package/dist/components/list/ListCommand.mjs +66 -48
- package/dist/components/status/StatusDisplay.cjs +4 -3
- package/dist/components/status/StatusDisplay.d.ts +2 -4
- package/dist/components/status/StatusDisplay.mjs +4 -3
- package/dist/components/tree/AssetTreeNode.cjs +21 -4
- package/dist/components/tree/AssetTreeNode.d.ts +1 -1
- package/dist/components/tree/AssetTreeNode.mjs +21 -4
- package/dist/components/tree/TreeSelect.cjs +14 -6
- package/dist/components/tree/TreeSelect.mjs +14 -6
- package/dist/core/cli.cjs +18 -0
- package/dist/core/cli.mjs +18 -0
- package/dist/core/constants.cjs +4 -1
- package/dist/core/constants.d.ts +8 -1
- package/dist/core/constants.mjs +4 -1
- package/dist/core/filesystem.cjs +7 -13
- package/dist/core/filesystem.mjs +7 -13
- package/dist/core/migration.cjs +10 -9
- package/dist/core/migration.mjs +10 -9
- package/dist/core/packageScanner.cjs +76 -0
- package/dist/core/packageScanner.d.ts +6 -1
- package/dist/core/packageScanner.mjs +76 -1
- package/dist/core/sync.cjs +53 -30
- package/dist/core/sync.mjs +53 -30
- package/dist/core/syncMeta.cjs +153 -9
- package/dist/core/syncMeta.d.ts +22 -18
- package/dist/core/syncMeta.mjs +149 -9
- package/dist/utils/types.d.ts +24 -7
- package/dist/version.cjs +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +1 -1
|
@@ -50,10 +50,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
50
50
|
const clonedTree = { ...assetTypeTree };
|
|
51
51
|
if (clonedTree.children) {
|
|
52
52
|
clonedTree.children = clonedTree.children.map((fileNode) => {
|
|
53
|
-
const
|
|
53
|
+
const selected = packageData.selected.has(fileNode.path);
|
|
54
54
|
return {
|
|
55
55
|
...fileNode,
|
|
56
|
-
selected
|
|
56
|
+
selected,
|
|
57
57
|
};
|
|
58
58
|
});
|
|
59
59
|
const anySelected = clonedTree.children.some((f) => f.selected);
|
|
@@ -112,15 +112,35 @@ const ListCommand = ({ cwd }) => {
|
|
|
112
112
|
catch {
|
|
113
113
|
const assetTypeTrees = [];
|
|
114
114
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
115
|
-
const
|
|
116
|
-
if (
|
|
115
|
+
const units = Array.isArray(files) ? files : [];
|
|
116
|
+
if (units.length === 0)
|
|
117
117
|
continue;
|
|
118
|
-
const
|
|
119
|
-
const
|
|
118
|
+
const skillNodes = units.map((unit) => {
|
|
119
|
+
const displayName = unit.transformed ?? unit.name;
|
|
120
|
+
if (unit.isDirectory) {
|
|
121
|
+
return {
|
|
122
|
+
id: `${prefix}/${assetType}/${displayName}`,
|
|
123
|
+
label: displayName,
|
|
124
|
+
path: `${assetType}/${unit.name}`,
|
|
125
|
+
type: 'skill-directory',
|
|
126
|
+
viewOnly: true,
|
|
127
|
+
selected: true,
|
|
128
|
+
expanded: false,
|
|
129
|
+
children: (unit.internalFiles || []).map((f) => ({
|
|
130
|
+
id: `${prefix}/${assetType}/${displayName}/${f}`,
|
|
131
|
+
label: f,
|
|
132
|
+
path: `${assetType}/${unit.name}/${f}`,
|
|
133
|
+
type: 'file',
|
|
134
|
+
selected: true,
|
|
135
|
+
expanded: false,
|
|
136
|
+
disabled: true,
|
|
137
|
+
})),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
120
140
|
return {
|
|
121
|
-
id: `${prefix}/${assetType}/${
|
|
122
|
-
label:
|
|
123
|
-
path: `${assetType}/${
|
|
141
|
+
id: `${prefix}/${assetType}/${displayName}`,
|
|
142
|
+
label: displayName,
|
|
143
|
+
path: `${assetType}/${unit.name}`,
|
|
124
144
|
type: 'file',
|
|
125
145
|
selected: true,
|
|
126
146
|
expanded: false,
|
|
@@ -131,7 +151,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
131
151
|
label: assetType,
|
|
132
152
|
path: assetType,
|
|
133
153
|
type: 'directory',
|
|
134
|
-
children:
|
|
154
|
+
children: skillNodes,
|
|
135
155
|
selected: true,
|
|
136
156
|
expanded: true,
|
|
137
157
|
});
|
|
@@ -144,11 +164,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
144
164
|
for (const { prefix, available, packageInfo } of results) {
|
|
145
165
|
const excludedFiles = new Set(packageInfo.exclusions?.files || []);
|
|
146
166
|
const metaSelectedFiles = new Set(Object.entries(packageInfo.files).flatMap(([assetType, files]) => (Array.isArray(files) ? files : [])
|
|
147
|
-
.map((
|
|
148
|
-
const
|
|
149
|
-
const filePath = `${assetType}/${fileName}`;
|
|
167
|
+
.map((unit) => {
|
|
168
|
+
const filePath = `${assetType}/${unit.name}`;
|
|
150
169
|
if (excludedFiles.has(filePath) ||
|
|
151
|
-
excludedFiles.has(
|
|
170
|
+
excludedFiles.has(unit.name)) {
|
|
152
171
|
return null;
|
|
153
172
|
}
|
|
154
173
|
return filePath;
|
|
@@ -216,8 +235,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
216
235
|
for (const assetTypeNode of packageTree.children) {
|
|
217
236
|
if (assetTypeNode.children) {
|
|
218
237
|
for (const fileNode of assetTypeNode.children) {
|
|
238
|
+
if (fileNode.disabled)
|
|
239
|
+
continue;
|
|
219
240
|
if (fileNode.selected) {
|
|
220
|
-
selectedPaths.add(
|
|
241
|
+
selectedPaths.add(fileNode.path);
|
|
221
242
|
}
|
|
222
243
|
}
|
|
223
244
|
}
|
|
@@ -240,21 +261,20 @@ const ListCommand = ({ cwd }) => {
|
|
|
240
261
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
241
262
|
if (!Array.isArray(files))
|
|
242
263
|
continue;
|
|
243
|
-
const
|
|
244
|
-
const
|
|
245
|
-
for (const file of files) {
|
|
246
|
-
const fileName = typeof file === 'string' ? file : file.original;
|
|
264
|
+
const units = files;
|
|
265
|
+
for (const unit of units) {
|
|
247
266
|
fileOperations.push({
|
|
248
267
|
type: 'remove',
|
|
249
268
|
prefix,
|
|
250
269
|
assetType,
|
|
251
|
-
|
|
270
|
+
skillName: unit.name,
|
|
252
271
|
});
|
|
253
272
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
273
|
+
const firstUnit = units[0];
|
|
274
|
+
if (firstUnit?.transformed) {
|
|
275
|
+
for (const unit of units) {
|
|
276
|
+
const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
|
|
277
|
+
filesToDelete.push(targetPath);
|
|
258
278
|
}
|
|
259
279
|
}
|
|
260
280
|
else {
|
|
@@ -275,24 +295,23 @@ const ListCommand = ({ cwd }) => {
|
|
|
275
295
|
}
|
|
276
296
|
for (const [assetType, originalFiles] of Object.entries(packageInfo.files)) {
|
|
277
297
|
const selectedFiles = selectedByAssetType[assetType];
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
const isFlat =
|
|
298
|
+
const units = Array.isArray(originalFiles) ? originalFiles : [];
|
|
299
|
+
const firstUnit = units[0];
|
|
300
|
+
const isFlat = !!firstUnit?.transformed;
|
|
281
301
|
if (!selectedFiles || selectedFiles.size === 0) {
|
|
282
302
|
hasChanges = true;
|
|
283
|
-
for (const
|
|
284
|
-
const fileName = typeof file === 'string' ? file : file.original;
|
|
303
|
+
for (const unit of units) {
|
|
285
304
|
fileOperations.push({
|
|
286
305
|
type: 'remove',
|
|
287
306
|
prefix,
|
|
288
307
|
assetType,
|
|
289
|
-
|
|
308
|
+
skillName: unit.name,
|
|
290
309
|
});
|
|
291
310
|
}
|
|
292
311
|
if (isFlat) {
|
|
293
|
-
for (const
|
|
294
|
-
const
|
|
295
|
-
filesToDelete.push(
|
|
312
|
+
for (const unit of units) {
|
|
313
|
+
const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
|
|
314
|
+
filesToDelete.push(targetPath);
|
|
296
315
|
}
|
|
297
316
|
}
|
|
298
317
|
else {
|
|
@@ -301,35 +320,34 @@ const ListCommand = ({ cwd }) => {
|
|
|
301
320
|
}
|
|
302
321
|
continue;
|
|
303
322
|
}
|
|
304
|
-
const
|
|
305
|
-
for (const
|
|
306
|
-
|
|
307
|
-
if (!selectedFiles.has(fileName)) {
|
|
323
|
+
const originalNames = new Set(units.map((u) => u.name));
|
|
324
|
+
for (const unit of units) {
|
|
325
|
+
if (!selectedFiles.has(unit.name)) {
|
|
308
326
|
hasChanges = true;
|
|
309
327
|
fileOperations.push({
|
|
310
328
|
type: 'remove',
|
|
311
329
|
prefix,
|
|
312
330
|
assetType,
|
|
313
|
-
|
|
331
|
+
skillName: unit.name,
|
|
314
332
|
});
|
|
315
|
-
if (
|
|
316
|
-
const
|
|
317
|
-
filesToDelete.push(
|
|
333
|
+
if (unit.transformed) {
|
|
334
|
+
const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
|
|
335
|
+
filesToDelete.push(targetPath);
|
|
318
336
|
}
|
|
319
337
|
else {
|
|
320
|
-
const filePath = path__namespace.join(cwd, '.claude', assetType, packageInfo.originalName,
|
|
338
|
+
const filePath = path__namespace.join(cwd, '.claude', assetType, packageInfo.originalName, unit.name);
|
|
321
339
|
filesToDelete.push(filePath);
|
|
322
340
|
}
|
|
323
341
|
}
|
|
324
342
|
}
|
|
325
|
-
for (const
|
|
326
|
-
if (!
|
|
343
|
+
for (const skillName of selectedFiles) {
|
|
344
|
+
if (!originalNames.has(skillName)) {
|
|
327
345
|
hasChanges = true;
|
|
328
346
|
fileOperations.push({
|
|
329
347
|
type: 'add',
|
|
330
348
|
prefix,
|
|
331
349
|
assetType,
|
|
332
|
-
|
|
350
|
+
skillName,
|
|
333
351
|
});
|
|
334
352
|
}
|
|
335
353
|
}
|
|
@@ -369,7 +387,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
369
387
|
const hasAddOperations = changesSummary.fileOperations.some((op) => op.type === 'add');
|
|
370
388
|
for (const op of changesSummary.fileOperations) {
|
|
371
389
|
if (op.type === 'remove') {
|
|
372
|
-
updatedMeta = syncMeta.
|
|
390
|
+
updatedMeta = syncMeta.removeSkillUnitFromPackage(updatedMeta, op.prefix, op.assetType, op.skillName);
|
|
373
391
|
}
|
|
374
392
|
}
|
|
375
393
|
for (const prefix of Object.keys(updatedMeta.packages)) {
|
|
@@ -385,7 +403,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
385
403
|
try {
|
|
386
404
|
const removedFiles = changesSummary.fileOperations
|
|
387
405
|
.filter((op) => op.type === 'remove' && op.prefix === prefix)
|
|
388
|
-
.map((op) => `${op.assetType}/${op.
|
|
406
|
+
.map((op) => `${op.assetType}/${op.skillName}`);
|
|
389
407
|
const exclusions = removedFiles.length > 0
|
|
390
408
|
? { directories: [], files: removedFiles }
|
|
391
409
|
: undefined;
|
|
@@ -6,7 +6,7 @@ import Spinner from 'ink-spinner';
|
|
|
6
6
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
7
7
|
import { scanPackageAssets } from '../../core/packageScanner.mjs';
|
|
8
8
|
import { syncPackage } from '../../core/sync.mjs';
|
|
9
|
-
import { readUnifiedSyncMeta,
|
|
9
|
+
import { readUnifiedSyncMeta, removeSkillUnitFromPackage, removePackageFromMeta, writeUnifiedSyncMeta } from '../../core/syncMeta.mjs';
|
|
10
10
|
import { TreeSelect } from '../tree/TreeSelect.mjs';
|
|
11
11
|
|
|
12
12
|
const ListCommand = ({ cwd }) => {
|
|
@@ -28,10 +28,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
28
28
|
const clonedTree = { ...assetTypeTree };
|
|
29
29
|
if (clonedTree.children) {
|
|
30
30
|
clonedTree.children = clonedTree.children.map((fileNode) => {
|
|
31
|
-
const
|
|
31
|
+
const selected = packageData.selected.has(fileNode.path);
|
|
32
32
|
return {
|
|
33
33
|
...fileNode,
|
|
34
|
-
selected
|
|
34
|
+
selected,
|
|
35
35
|
};
|
|
36
36
|
});
|
|
37
37
|
const anySelected = clonedTree.children.some((f) => f.selected);
|
|
@@ -90,15 +90,35 @@ const ListCommand = ({ cwd }) => {
|
|
|
90
90
|
catch {
|
|
91
91
|
const assetTypeTrees = [];
|
|
92
92
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
93
|
+
const units = Array.isArray(files) ? files : [];
|
|
94
|
+
if (units.length === 0)
|
|
95
95
|
continue;
|
|
96
|
-
const
|
|
97
|
-
const
|
|
96
|
+
const skillNodes = units.map((unit) => {
|
|
97
|
+
const displayName = unit.transformed ?? unit.name;
|
|
98
|
+
if (unit.isDirectory) {
|
|
99
|
+
return {
|
|
100
|
+
id: `${prefix}/${assetType}/${displayName}`,
|
|
101
|
+
label: displayName,
|
|
102
|
+
path: `${assetType}/${unit.name}`,
|
|
103
|
+
type: 'skill-directory',
|
|
104
|
+
viewOnly: true,
|
|
105
|
+
selected: true,
|
|
106
|
+
expanded: false,
|
|
107
|
+
children: (unit.internalFiles || []).map((f) => ({
|
|
108
|
+
id: `${prefix}/${assetType}/${displayName}/${f}`,
|
|
109
|
+
label: f,
|
|
110
|
+
path: `${assetType}/${unit.name}/${f}`,
|
|
111
|
+
type: 'file',
|
|
112
|
+
selected: true,
|
|
113
|
+
expanded: false,
|
|
114
|
+
disabled: true,
|
|
115
|
+
})),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
98
118
|
return {
|
|
99
|
-
id: `${prefix}/${assetType}/${
|
|
100
|
-
label:
|
|
101
|
-
path: `${assetType}/${
|
|
119
|
+
id: `${prefix}/${assetType}/${displayName}`,
|
|
120
|
+
label: displayName,
|
|
121
|
+
path: `${assetType}/${unit.name}`,
|
|
102
122
|
type: 'file',
|
|
103
123
|
selected: true,
|
|
104
124
|
expanded: false,
|
|
@@ -109,7 +129,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
109
129
|
label: assetType,
|
|
110
130
|
path: assetType,
|
|
111
131
|
type: 'directory',
|
|
112
|
-
children:
|
|
132
|
+
children: skillNodes,
|
|
113
133
|
selected: true,
|
|
114
134
|
expanded: true,
|
|
115
135
|
});
|
|
@@ -122,11 +142,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
122
142
|
for (const { prefix, available, packageInfo } of results) {
|
|
123
143
|
const excludedFiles = new Set(packageInfo.exclusions?.files || []);
|
|
124
144
|
const metaSelectedFiles = new Set(Object.entries(packageInfo.files).flatMap(([assetType, files]) => (Array.isArray(files) ? files : [])
|
|
125
|
-
.map((
|
|
126
|
-
const
|
|
127
|
-
const filePath = `${assetType}/${fileName}`;
|
|
145
|
+
.map((unit) => {
|
|
146
|
+
const filePath = `${assetType}/${unit.name}`;
|
|
128
147
|
if (excludedFiles.has(filePath) ||
|
|
129
|
-
excludedFiles.has(
|
|
148
|
+
excludedFiles.has(unit.name)) {
|
|
130
149
|
return null;
|
|
131
150
|
}
|
|
132
151
|
return filePath;
|
|
@@ -194,8 +213,10 @@ const ListCommand = ({ cwd }) => {
|
|
|
194
213
|
for (const assetTypeNode of packageTree.children) {
|
|
195
214
|
if (assetTypeNode.children) {
|
|
196
215
|
for (const fileNode of assetTypeNode.children) {
|
|
216
|
+
if (fileNode.disabled)
|
|
217
|
+
continue;
|
|
197
218
|
if (fileNode.selected) {
|
|
198
|
-
selectedPaths.add(
|
|
219
|
+
selectedPaths.add(fileNode.path);
|
|
199
220
|
}
|
|
200
221
|
}
|
|
201
222
|
}
|
|
@@ -218,21 +239,20 @@ const ListCommand = ({ cwd }) => {
|
|
|
218
239
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
219
240
|
if (!Array.isArray(files))
|
|
220
241
|
continue;
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
for (const file of files) {
|
|
224
|
-
const fileName = typeof file === 'string' ? file : file.original;
|
|
242
|
+
const units = files;
|
|
243
|
+
for (const unit of units) {
|
|
225
244
|
fileOperations.push({
|
|
226
245
|
type: 'remove',
|
|
227
246
|
prefix,
|
|
228
247
|
assetType,
|
|
229
|
-
|
|
248
|
+
skillName: unit.name,
|
|
230
249
|
});
|
|
231
250
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
251
|
+
const firstUnit = units[0];
|
|
252
|
+
if (firstUnit?.transformed) {
|
|
253
|
+
for (const unit of units) {
|
|
254
|
+
const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
|
|
255
|
+
filesToDelete.push(targetPath);
|
|
236
256
|
}
|
|
237
257
|
}
|
|
238
258
|
else {
|
|
@@ -253,24 +273,23 @@ const ListCommand = ({ cwd }) => {
|
|
|
253
273
|
}
|
|
254
274
|
for (const [assetType, originalFiles] of Object.entries(packageInfo.files)) {
|
|
255
275
|
const selectedFiles = selectedByAssetType[assetType];
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
const isFlat =
|
|
276
|
+
const units = Array.isArray(originalFiles) ? originalFiles : [];
|
|
277
|
+
const firstUnit = units[0];
|
|
278
|
+
const isFlat = !!firstUnit?.transformed;
|
|
259
279
|
if (!selectedFiles || selectedFiles.size === 0) {
|
|
260
280
|
hasChanges = true;
|
|
261
|
-
for (const
|
|
262
|
-
const fileName = typeof file === 'string' ? file : file.original;
|
|
281
|
+
for (const unit of units) {
|
|
263
282
|
fileOperations.push({
|
|
264
283
|
type: 'remove',
|
|
265
284
|
prefix,
|
|
266
285
|
assetType,
|
|
267
|
-
|
|
286
|
+
skillName: unit.name,
|
|
268
287
|
});
|
|
269
288
|
}
|
|
270
289
|
if (isFlat) {
|
|
271
|
-
for (const
|
|
272
|
-
const
|
|
273
|
-
filesToDelete.push(
|
|
290
|
+
for (const unit of units) {
|
|
291
|
+
const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
|
|
292
|
+
filesToDelete.push(targetPath);
|
|
274
293
|
}
|
|
275
294
|
}
|
|
276
295
|
else {
|
|
@@ -279,35 +298,34 @@ const ListCommand = ({ cwd }) => {
|
|
|
279
298
|
}
|
|
280
299
|
continue;
|
|
281
300
|
}
|
|
282
|
-
const
|
|
283
|
-
for (const
|
|
284
|
-
|
|
285
|
-
if (!selectedFiles.has(fileName)) {
|
|
301
|
+
const originalNames = new Set(units.map((u) => u.name));
|
|
302
|
+
for (const unit of units) {
|
|
303
|
+
if (!selectedFiles.has(unit.name)) {
|
|
286
304
|
hasChanges = true;
|
|
287
305
|
fileOperations.push({
|
|
288
306
|
type: 'remove',
|
|
289
307
|
prefix,
|
|
290
308
|
assetType,
|
|
291
|
-
|
|
309
|
+
skillName: unit.name,
|
|
292
310
|
});
|
|
293
|
-
if (
|
|
294
|
-
const
|
|
295
|
-
filesToDelete.push(
|
|
311
|
+
if (unit.transformed) {
|
|
312
|
+
const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
|
|
313
|
+
filesToDelete.push(targetPath);
|
|
296
314
|
}
|
|
297
315
|
else {
|
|
298
|
-
const filePath = path.join(cwd, '.claude', assetType, packageInfo.originalName,
|
|
316
|
+
const filePath = path.join(cwd, '.claude', assetType, packageInfo.originalName, unit.name);
|
|
299
317
|
filesToDelete.push(filePath);
|
|
300
318
|
}
|
|
301
319
|
}
|
|
302
320
|
}
|
|
303
|
-
for (const
|
|
304
|
-
if (!
|
|
321
|
+
for (const skillName of selectedFiles) {
|
|
322
|
+
if (!originalNames.has(skillName)) {
|
|
305
323
|
hasChanges = true;
|
|
306
324
|
fileOperations.push({
|
|
307
325
|
type: 'add',
|
|
308
326
|
prefix,
|
|
309
327
|
assetType,
|
|
310
|
-
|
|
328
|
+
skillName,
|
|
311
329
|
});
|
|
312
330
|
}
|
|
313
331
|
}
|
|
@@ -347,7 +365,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
347
365
|
const hasAddOperations = changesSummary.fileOperations.some((op) => op.type === 'add');
|
|
348
366
|
for (const op of changesSummary.fileOperations) {
|
|
349
367
|
if (op.type === 'remove') {
|
|
350
|
-
updatedMeta =
|
|
368
|
+
updatedMeta = removeSkillUnitFromPackage(updatedMeta, op.prefix, op.assetType, op.skillName);
|
|
351
369
|
}
|
|
352
370
|
}
|
|
353
371
|
for (const prefix of Object.keys(updatedMeta.packages)) {
|
|
@@ -363,7 +381,7 @@ const ListCommand = ({ cwd }) => {
|
|
|
363
381
|
try {
|
|
364
382
|
const removedFiles = changesSummary.fileOperations
|
|
365
383
|
.filter((op) => op.type === 'remove' && op.prefix === prefix)
|
|
366
|
-
.map((op) => `${op.assetType}/${op.
|
|
384
|
+
.map((op) => `${op.assetType}/${op.skillName}`);
|
|
367
385
|
const exclusions = removedFiles.length > 0
|
|
368
386
|
? { directories: [], files: removedFiles }
|
|
369
387
|
: undefined;
|
|
@@ -14,9 +14,10 @@ const StatusDisplay = ({ packages, loading, summary, }) => {
|
|
|
14
14
|
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", marginBottom: 1, children: [jsxRuntime.jsx(StatusTreeNode.StatusTreeNode, { label: pkg.name, depth: 0, type: "package", expanded: true, status: pkg.status, version: pkg.localVersion, remoteVersion: pkg.remoteVersion, fileCount: pkg.fileCount }), assetTypes.map((assetType) => {
|
|
15
15
|
const files = pkg.files[assetType];
|
|
16
16
|
const fileArray = Array.isArray(files) ? files : [];
|
|
17
|
-
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [jsxRuntime.jsx(StatusTreeNode.StatusTreeNode, { label: assetType, depth: 1, type: "assetType", expanded: true, fileCount: fileArray.length }), fileArray.map((
|
|
18
|
-
const
|
|
19
|
-
|
|
17
|
+
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [jsxRuntime.jsx(StatusTreeNode.StatusTreeNode, { label: assetType, depth: 1, type: "assetType", expanded: true, fileCount: fileArray.length }), fileArray.map((unit, index) => {
|
|
18
|
+
const displayName = unit.transformed ?? unit.name;
|
|
19
|
+
const label = unit.isDirectory ? `${displayName}/` : displayName;
|
|
20
|
+
return (jsxRuntime.jsx(StatusTreeNode.StatusTreeNode, { label: label, depth: 2, type: "file" }, `${assetType}-${index}`));
|
|
20
21
|
})] }, assetType));
|
|
21
22
|
}), jsxRuntime.jsx(ink.Box, { marginLeft: 2, children: jsxRuntime.jsxs(ink.Text, { dimColor: true, children: ["Last synced: ", new Date(pkg.syncedAt).toLocaleString()] }) }), pkg.error && (jsxRuntime.jsx(ink.Box, { marginLeft: 2, children: jsxRuntime.jsxs(ink.Text, { color: "red", children: ["Error: ", pkg.error] }) }))] }, pkg.name));
|
|
22
23
|
}), jsxRuntime.jsx(ink.Box, { marginTop: 1, paddingTop: 1, borderStyle: "single", borderTop: true, borderColor: "gray", children: jsxRuntime.jsxs(ink.Text, { dimColor: true, children: ["Summary: ", summary.upToDate, " up to date", summary.outdated > 0 && `, ${summary.outdated} updates available`, summary.error > 0 && `, ${summary.error} errors`, summary.unknown > 0 && `, ${summary.unknown} unknown`] }) })] }));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { SkillUnit } from '../../utils/types.js';
|
|
2
3
|
export interface PackageStatusItem {
|
|
3
4
|
name: string;
|
|
4
5
|
localVersion: string;
|
|
@@ -6,10 +7,7 @@ export interface PackageStatusItem {
|
|
|
6
7
|
status: 'up-to-date' | 'outdated' | 'error' | 'unknown';
|
|
7
8
|
syncedAt: string;
|
|
8
9
|
error?: string;
|
|
9
|
-
files: Record<string,
|
|
10
|
-
original: string;
|
|
11
|
-
transformed: string;
|
|
12
|
-
}>>;
|
|
10
|
+
files: Record<string, SkillUnit[]>;
|
|
13
11
|
fileCount: number;
|
|
14
12
|
}
|
|
15
13
|
export interface StatusDisplayProps {
|
|
@@ -12,9 +12,10 @@ const StatusDisplay = ({ packages, loading, summary, }) => {
|
|
|
12
12
|
return (jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [jsx(StatusTreeNode, { label: pkg.name, depth: 0, type: "package", expanded: true, status: pkg.status, version: pkg.localVersion, remoteVersion: pkg.remoteVersion, fileCount: pkg.fileCount }), assetTypes.map((assetType) => {
|
|
13
13
|
const files = pkg.files[assetType];
|
|
14
14
|
const fileArray = Array.isArray(files) ? files : [];
|
|
15
|
-
return (jsxs(Box, { flexDirection: "column", children: [jsx(StatusTreeNode, { label: assetType, depth: 1, type: "assetType", expanded: true, fileCount: fileArray.length }), fileArray.map((
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
return (jsxs(Box, { flexDirection: "column", children: [jsx(StatusTreeNode, { label: assetType, depth: 1, type: "assetType", expanded: true, fileCount: fileArray.length }), fileArray.map((unit, index) => {
|
|
16
|
+
const displayName = unit.transformed ?? unit.name;
|
|
17
|
+
const label = unit.isDirectory ? `${displayName}/` : displayName;
|
|
18
|
+
return (jsx(StatusTreeNode, { label: label, depth: 2, type: "file" }, `${assetType}-${index}`));
|
|
18
19
|
})] }, assetType));
|
|
19
20
|
}), jsx(Box, { marginLeft: 2, children: jsxs(Text, { dimColor: true, children: ["Last synced: ", new Date(pkg.syncedAt).toLocaleString()] }) }), pkg.error && (jsx(Box, { marginLeft: 2, children: jsxs(Text, { color: "red", children: ["Error: ", pkg.error] }) }))] }, pkg.name));
|
|
20
21
|
}), jsx(Box, { marginTop: 1, paddingTop: 1, borderStyle: "single", borderTop: true, borderColor: "gray", children: jsxs(Text, { dimColor: true, children: ["Summary: ", summary.upToDate, " up to date", summary.outdated > 0 && `, ${summary.outdated} updates available`, summary.error > 0 && `, ${summary.error} errors`, summary.unknown > 0 && `, ${summary.unknown} unknown`] }) })] }));
|
|
@@ -10,8 +10,24 @@ function hasPartialSelection(node) {
|
|
|
10
10
|
const selectedCount = node.children.filter((child) => child.selected).length;
|
|
11
11
|
return selectedCount > 0 && selectedCount < node.children.length;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
function getTreePrefix(isLastAtDepth) {
|
|
14
|
+
let prefix = '';
|
|
15
|
+
const depth = isLastAtDepth.length;
|
|
16
|
+
for (let i = 0; i < depth; i++) {
|
|
17
|
+
if (i === depth - 1) {
|
|
18
|
+
prefix += isLastAtDepth[i] ? '└─ ' : '├─ ';
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
prefix += isLastAtDepth[i] ? ' ' : '│ ';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return prefix;
|
|
25
|
+
}
|
|
26
|
+
const AssetTreeNode = ({ node, isLastAtDepth, isSelected, }) => {
|
|
27
|
+
const treePrefix = getTreePrefix(isLastAtDepth);
|
|
28
|
+
if (node.disabled) {
|
|
29
|
+
return (jsxRuntime.jsx(ink.Box, { children: jsxRuntime.jsxs(ink.Text, { color: isSelected ? 'cyan' : undefined, dimColor: !isSelected, children: [treePrefix, node.label] }) }));
|
|
30
|
+
}
|
|
15
31
|
let selectionIcon;
|
|
16
32
|
let iconColor;
|
|
17
33
|
if (hasPartialSelection(node)) {
|
|
@@ -26,12 +42,13 @@ const AssetTreeNode = ({ node, depth, isSelected, }) => {
|
|
|
26
42
|
selectionIcon = '○';
|
|
27
43
|
iconColor = 'red';
|
|
28
44
|
}
|
|
29
|
-
const expandIcon = node.type === 'directory'
|
|
45
|
+
const expandIcon = (node.type === 'directory' || node.type === 'skill-directory') &&
|
|
46
|
+
node.children
|
|
30
47
|
? node.expanded
|
|
31
48
|
? '▼'
|
|
32
49
|
: '▶'
|
|
33
50
|
: ' ';
|
|
34
|
-
return (jsxRuntime.jsx(ink.Box, { children: jsxRuntime.jsxs(ink.Text, { color: isSelected ? 'cyan' : undefined, children: [
|
|
51
|
+
return (jsxRuntime.jsx(ink.Box, { children: jsxRuntime.jsxs(ink.Text, { color: isSelected ? 'cyan' : undefined, children: [treePrefix, expandIcon, " ", jsxRuntime.jsx(ink.Text, { color: iconColor, children: selectionIcon }), " ", node.label] }) }));
|
|
35
52
|
};
|
|
36
53
|
|
|
37
54
|
exports.AssetTreeNode = AssetTreeNode;
|
|
@@ -8,8 +8,24 @@ function hasPartialSelection(node) {
|
|
|
8
8
|
const selectedCount = node.children.filter((child) => child.selected).length;
|
|
9
9
|
return selectedCount > 0 && selectedCount < node.children.length;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
function getTreePrefix(isLastAtDepth) {
|
|
12
|
+
let prefix = '';
|
|
13
|
+
const depth = isLastAtDepth.length;
|
|
14
|
+
for (let i = 0; i < depth; i++) {
|
|
15
|
+
if (i === depth - 1) {
|
|
16
|
+
prefix += isLastAtDepth[i] ? '└─ ' : '├─ ';
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
prefix += isLastAtDepth[i] ? ' ' : '│ ';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return prefix;
|
|
23
|
+
}
|
|
24
|
+
const AssetTreeNode = ({ node, isLastAtDepth, isSelected, }) => {
|
|
25
|
+
const treePrefix = getTreePrefix(isLastAtDepth);
|
|
26
|
+
if (node.disabled) {
|
|
27
|
+
return (jsx(Box, { children: jsxs(Text, { color: isSelected ? 'cyan' : undefined, dimColor: !isSelected, children: [treePrefix, node.label] }) }));
|
|
28
|
+
}
|
|
13
29
|
let selectionIcon;
|
|
14
30
|
let iconColor;
|
|
15
31
|
if (hasPartialSelection(node)) {
|
|
@@ -24,12 +40,13 @@ const AssetTreeNode = ({ node, depth, isSelected, }) => {
|
|
|
24
40
|
selectionIcon = '○';
|
|
25
41
|
iconColor = 'red';
|
|
26
42
|
}
|
|
27
|
-
const expandIcon = node.type === 'directory'
|
|
43
|
+
const expandIcon = (node.type === 'directory' || node.type === 'skill-directory') &&
|
|
44
|
+
node.children
|
|
28
45
|
? node.expanded
|
|
29
46
|
? '▼'
|
|
30
47
|
: '▶'
|
|
31
48
|
: ' ';
|
|
32
|
-
return (jsx(Box, { children: jsxs(Text, { color: isSelected ? 'cyan' : undefined, children: [
|
|
49
|
+
return (jsx(Box, { children: jsxs(Text, { color: isSelected ? 'cyan' : undefined, children: [treePrefix, expandIcon, " ", jsx(Text, { color: iconColor, children: selectionIcon }), " ", node.label] }) }));
|
|
33
50
|
};
|
|
34
51
|
|
|
35
52
|
export { AssetTreeNode };
|