@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
package/dist/commands/add.cjs
CHANGED
|
@@ -38,13 +38,8 @@ async function performSync(selection, cwd) {
|
|
|
38
38
|
files: [],
|
|
39
39
|
};
|
|
40
40
|
for (const assetType of Object.keys(selection.excludedAssets)) {
|
|
41
|
-
for (const
|
|
42
|
-
|
|
43
|
-
exclusions.files.push(path);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
exclusions.directories.push(path);
|
|
47
|
-
}
|
|
41
|
+
for (const excludedPath of selection.excludedAssets[assetType]) {
|
|
42
|
+
exclusions.files.push(excludedPath);
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
45
|
await sync.syncPackage(selection.packageName, {
|
package/dist/commands/add.mjs
CHANGED
|
@@ -36,13 +36,8 @@ async function performSync(selection, cwd) {
|
|
|
36
36
|
files: [],
|
|
37
37
|
};
|
|
38
38
|
for (const assetType of Object.keys(selection.excludedAssets)) {
|
|
39
|
-
for (const
|
|
40
|
-
|
|
41
|
-
exclusions.files.push(path);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
exclusions.directories.push(path);
|
|
45
|
-
}
|
|
39
|
+
for (const excludedPath of selection.excludedAssets[assetType]) {
|
|
40
|
+
exclusions.files.push(excludedPath);
|
|
46
41
|
}
|
|
47
42
|
}
|
|
48
43
|
await syncPackage(selection.packageName, {
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export { runRemoveCommand } from './remove';
|
|
|
8
8
|
export { runStatusCommand } from './status';
|
|
9
9
|
export { runMigrateCommand } from './migrate';
|
|
10
10
|
export { runAddCommand } from './add';
|
|
11
|
+
export { runUpdateCommand } from './update';
|
|
11
12
|
export type { AddCommandOptions } from './add';
|
|
13
|
+
export type { UpdateCommandOptions } from './update';
|
|
12
14
|
/**
|
|
13
15
|
* Command metadata for CLI help and documentation
|
|
14
16
|
*/
|
|
@@ -88,4 +90,24 @@ export declare const COMMANDS: {
|
|
|
88
90
|
readonly description: "Preview migration without making changes";
|
|
89
91
|
}];
|
|
90
92
|
};
|
|
93
|
+
readonly update: {
|
|
94
|
+
readonly name: "update";
|
|
95
|
+
readonly description: "Update package metadata in .sync-meta.json";
|
|
96
|
+
readonly options: readonly [{
|
|
97
|
+
readonly flag: "-p, --package <name>";
|
|
98
|
+
readonly description: "Package name to update (default: all)";
|
|
99
|
+
}, {
|
|
100
|
+
readonly flag: "-l, --local";
|
|
101
|
+
readonly description: "Read from local workspace";
|
|
102
|
+
}, {
|
|
103
|
+
readonly flag: "-r, --ref <ref>";
|
|
104
|
+
readonly description: "Git ref to fetch from";
|
|
105
|
+
}, {
|
|
106
|
+
readonly flag: "--dry-run";
|
|
107
|
+
readonly description: "Preview changes without writing";
|
|
108
|
+
}, {
|
|
109
|
+
readonly flag: "--sync";
|
|
110
|
+
readonly description: "Re-sync files after updating metadata";
|
|
111
|
+
}];
|
|
112
|
+
};
|
|
91
113
|
};
|
package/dist/commands/remove.cjs
CHANGED
|
@@ -48,12 +48,12 @@ const runRemoveCommand = async (options, cwd = process.cwd()) => {
|
|
|
48
48
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
49
49
|
if (!Array.isArray(files) || files.length === 0)
|
|
50
50
|
continue;
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
for (const
|
|
55
|
-
const
|
|
56
|
-
filesToRemove.push({ assetType, path:
|
|
51
|
+
const units = files;
|
|
52
|
+
const firstUnit = units[0];
|
|
53
|
+
if (firstUnit.transformed) {
|
|
54
|
+
for (const unit of units) {
|
|
55
|
+
const targetPath = path__namespace.join(cwd, '.claude', assetType, unit.transformed);
|
|
56
|
+
filesToRemove.push({ assetType, path: targetPath });
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
else {
|
package/dist/commands/remove.mjs
CHANGED
|
@@ -25,12 +25,12 @@ const runRemoveCommand = async (options, cwd = process.cwd()) => {
|
|
|
25
25
|
for (const [assetType, files] of Object.entries(packageInfo.files)) {
|
|
26
26
|
if (!Array.isArray(files) || files.length === 0)
|
|
27
27
|
continue;
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
for (const
|
|
32
|
-
const
|
|
33
|
-
filesToRemove.push({ assetType, path:
|
|
28
|
+
const units = files;
|
|
29
|
+
const firstUnit = units[0];
|
|
30
|
+
if (firstUnit.transformed) {
|
|
31
|
+
for (const unit of units) {
|
|
32
|
+
const targetPath = path.join(cwd, '.claude', assetType, unit.transformed);
|
|
33
|
+
filesToRemove.push({ assetType, path: targetPath });
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
else {
|
package/dist/commands/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Common types for command modules
|
|
3
3
|
*/
|
|
4
|
+
import type { SkillUnit } from '../utils/types';
|
|
4
5
|
/**
|
|
5
6
|
* Base command result
|
|
6
7
|
*/
|
|
@@ -65,10 +66,7 @@ export interface PackageStatusItem {
|
|
|
65
66
|
upToDate: boolean;
|
|
66
67
|
syncedAt: string;
|
|
67
68
|
error?: string;
|
|
68
|
-
files: Record<string,
|
|
69
|
-
original: string;
|
|
70
|
-
transformed: string;
|
|
71
|
-
}>>;
|
|
69
|
+
files: Record<string, SkillUnit[]>;
|
|
72
70
|
fileCount: number;
|
|
73
71
|
}
|
|
74
72
|
/**
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pc = require('picocolors');
|
|
4
|
+
var packageScanner = require('../core/packageScanner.cjs');
|
|
5
|
+
var sync = require('../core/sync.cjs');
|
|
6
|
+
var syncMeta = require('../core/syncMeta.cjs');
|
|
7
|
+
var constants = require('../core/constants.cjs');
|
|
8
|
+
var logger = require('../utils/logger.cjs');
|
|
9
|
+
var _package = require('../utils/package.cjs');
|
|
10
|
+
var packageName = require('../utils/packageName.cjs');
|
|
11
|
+
|
|
12
|
+
const runUpdateCommand = async (options, cwd = process.cwd()) => {
|
|
13
|
+
const destDir = _package.findGitRoot(cwd) ?? cwd;
|
|
14
|
+
const meta = syncMeta.readUnifiedSyncMeta(destDir);
|
|
15
|
+
if (!meta || Object.keys(meta.packages).length === 0) {
|
|
16
|
+
logger.logger.info('No packages synced yet. Use "sync" or "add" first.');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const packagesToUpdate = [];
|
|
20
|
+
if (options.package) {
|
|
21
|
+
const prefix = packageName.packageNameToPrefix(options.package);
|
|
22
|
+
if (!meta.packages[prefix]) {
|
|
23
|
+
logger.logger.error(`Package ${options.package} is not synced.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
packagesToUpdate.push(prefix);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
packagesToUpdate.push(...Object.keys(meta.packages));
|
|
31
|
+
}
|
|
32
|
+
let updatedMeta = { ...meta };
|
|
33
|
+
let hasChanges = false;
|
|
34
|
+
for (const prefix of packagesToUpdate) {
|
|
35
|
+
const packageInfo = updatedMeta.packages[prefix];
|
|
36
|
+
const packageName = packageInfo.originalName;
|
|
37
|
+
console.log(pc.cyan(`\nUpdating ${packageName}...`));
|
|
38
|
+
const isLocal = options.local ?? packageInfo.local ?? false;
|
|
39
|
+
const currentPkgInfo = isLocal
|
|
40
|
+
? _package.readLocalPackageJson(packageName, cwd)
|
|
41
|
+
: _package.readPackageJson(packageName, cwd);
|
|
42
|
+
if (!currentPkgInfo) {
|
|
43
|
+
const location = isLocal ? 'workspace' : 'node_modules';
|
|
44
|
+
console.log(pc.yellow(` ⚠ Package not found in ${location}, skipping version update`));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const newVersion = currentPkgInfo.version;
|
|
48
|
+
if (newVersion !== packageInfo.version) {
|
|
49
|
+
if (options.dryRun) {
|
|
50
|
+
console.log(pc.gray(` [DRY RUN] Would update version: ${packageInfo.version} → ${newVersion}`));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
updatedMeta = syncMeta.updatePackageVersion(updatedMeta, prefix, newVersion);
|
|
54
|
+
console.log(pc.green(` ✓ Version updated: ${packageInfo.version} → ${newVersion}`));
|
|
55
|
+
hasChanges = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(pc.gray(` Version unchanged: ${packageInfo.version}`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const scannedTrees = await packageScanner.scanPackageAssets(packageName, {
|
|
64
|
+
local: isLocal,
|
|
65
|
+
ref: options.ref,
|
|
66
|
+
cwd,
|
|
67
|
+
});
|
|
68
|
+
if (scannedTrees && scannedTrees.length > 0) {
|
|
69
|
+
for (const assetTypeTree of scannedTrees) {
|
|
70
|
+
const assetType = assetTypeTree.label;
|
|
71
|
+
const scannedUnits = packageScanner.buildSkillUnitsFromTree(assetTypeTree, prefix);
|
|
72
|
+
const currentUnits = packageInfo.files[assetType] || [];
|
|
73
|
+
const scannedNames = new Set(scannedUnits.map((u) => u.name));
|
|
74
|
+
const currentNames = new Set(currentUnits.map((u) => u.name));
|
|
75
|
+
const added = scannedUnits.filter((u) => !currentNames.has(u.name));
|
|
76
|
+
const removed = currentUnits.filter((u) => !scannedNames.has(u.name));
|
|
77
|
+
const unchanged = currentUnits.filter((u) => scannedNames.has(u.name));
|
|
78
|
+
if (added.length > 0 || removed.length > 0) {
|
|
79
|
+
const mergedUnits = [...unchanged, ...added];
|
|
80
|
+
if (options.dryRun) {
|
|
81
|
+
if (added.length > 0) {
|
|
82
|
+
console.log(pc.gray(` [DRY RUN] ${assetType}: ${added.length} new skill(s) found`));
|
|
83
|
+
for (const u of added) {
|
|
84
|
+
console.log(pc.gray(` + ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (removed.length > 0) {
|
|
88
|
+
console.log(pc.yellow(` [DRY RUN] ${assetType}: ${removed.length} skill(s) no longer in upstream`));
|
|
89
|
+
for (const u of removed) {
|
|
90
|
+
console.log(pc.yellow(` - ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
updatedMeta = syncMeta.updatePackageFilesystemMeta(updatedMeta, prefix, assetType, mergedUnits);
|
|
96
|
+
if (added.length > 0) {
|
|
97
|
+
console.log(pc.green(` ✓ ${assetType}: ${added.length} new skill(s) added to meta`));
|
|
98
|
+
for (const u of added) {
|
|
99
|
+
console.log(pc.green(` + ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (removed.length > 0) {
|
|
103
|
+
console.log(pc.yellow(` ⚠ ${assetType}: ${removed.length} skill(s) no longer in upstream (kept in meta)`));
|
|
104
|
+
for (const u of removed) {
|
|
105
|
+
console.log(pc.yellow(` - ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
hasChanges = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
let internalChanged = false;
|
|
113
|
+
const refreshedUnits = currentUnits.map((current) => {
|
|
114
|
+
const scanned = scannedUnits.find((s) => s.name === current.name);
|
|
115
|
+
if (scanned && scanned.isDirectory && current.isDirectory) {
|
|
116
|
+
const currentInternal = (current.internalFiles || []).sort().join(',');
|
|
117
|
+
const scannedInternal = (scanned.internalFiles || []).sort().join(',');
|
|
118
|
+
if (currentInternal !== scannedInternal) {
|
|
119
|
+
internalChanged = true;
|
|
120
|
+
return { ...current, internalFiles: scanned.internalFiles };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return current;
|
|
124
|
+
});
|
|
125
|
+
if (internalChanged && !options.dryRun) {
|
|
126
|
+
updatedMeta = syncMeta.updatePackageFilesystemMeta(updatedMeta, prefix, assetType, refreshedUnits);
|
|
127
|
+
console.log(pc.green(` ✓ ${assetType}: internal file lists updated`));
|
|
128
|
+
hasChanges = true;
|
|
129
|
+
}
|
|
130
|
+
else if (internalChanged && options.dryRun) {
|
|
131
|
+
console.log(pc.gray(` [DRY RUN] ${assetType}: would update internal file lists`));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log(pc.gray(` ${assetType}: no changes`));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
console.log(pc.yellow(` ⚠ Could not scan package assets, skipping filesystem update`));
|
|
142
|
+
}
|
|
143
|
+
if (options.sync && !options.dryRun) {
|
|
144
|
+
console.log(pc.cyan(` Syncing files...`));
|
|
145
|
+
try {
|
|
146
|
+
await sync.syncPackage(packageName, {
|
|
147
|
+
force: true,
|
|
148
|
+
dryRun: false,
|
|
149
|
+
local: isLocal,
|
|
150
|
+
ref: options.ref,
|
|
151
|
+
flat: true,
|
|
152
|
+
}, cwd, packageInfo.exclusions, destDir);
|
|
153
|
+
console.log(pc.green(` ✓ Files synced`));
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
157
|
+
console.log(pc.red(` ✗ Sync failed: ${message}`));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else if (options.sync && options.dryRun) {
|
|
161
|
+
console.log(pc.gray(` [DRY RUN] Would re-sync files`));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (hasChanges && !options.dryRun) {
|
|
165
|
+
updatedMeta.syncedAt = new Date().toISOString();
|
|
166
|
+
updatedMeta.skillUnitFormat = constants.SCHEMA_VERSIONS.SKILL_UNIT_FORMAT;
|
|
167
|
+
syncMeta.writeUnifiedSyncMeta(destDir, updatedMeta);
|
|
168
|
+
console.log(pc.green(`\n✓ Metadata updated`));
|
|
169
|
+
}
|
|
170
|
+
else if (options.dryRun) {
|
|
171
|
+
console.log(pc.gray(`\n[DRY RUN] No changes written`));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
console.log(pc.gray(`\nNo changes needed`));
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
exports.runUpdateCommand = runUpdateCommand;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface UpdateCommandOptions {
|
|
2
|
+
package?: string;
|
|
3
|
+
local?: boolean;
|
|
4
|
+
ref?: string;
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
sync?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Run the update command
|
|
10
|
+
* @param options - Update command options
|
|
11
|
+
* @param cwd - Current working directory
|
|
12
|
+
*/
|
|
13
|
+
export declare const runUpdateCommand: (options: UpdateCommandOptions, cwd?: string) => Promise<void>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { scanPackageAssets, buildSkillUnitsFromTree } from '../core/packageScanner.mjs';
|
|
3
|
+
import { syncPackage } from '../core/sync.mjs';
|
|
4
|
+
import { readUnifiedSyncMeta, updatePackageVersion, updatePackageFilesystemMeta, writeUnifiedSyncMeta } from '../core/syncMeta.mjs';
|
|
5
|
+
import { SCHEMA_VERSIONS } from '../core/constants.mjs';
|
|
6
|
+
import { logger } from '../utils/logger.mjs';
|
|
7
|
+
import { findGitRoot, readLocalPackageJson, readPackageJson } from '../utils/package.mjs';
|
|
8
|
+
import { packageNameToPrefix } from '../utils/packageName.mjs';
|
|
9
|
+
|
|
10
|
+
const runUpdateCommand = async (options, cwd = process.cwd()) => {
|
|
11
|
+
const destDir = findGitRoot(cwd) ?? cwd;
|
|
12
|
+
const meta = readUnifiedSyncMeta(destDir);
|
|
13
|
+
if (!meta || Object.keys(meta.packages).length === 0) {
|
|
14
|
+
logger.info('No packages synced yet. Use "sync" or "add" first.');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const packagesToUpdate = [];
|
|
18
|
+
if (options.package) {
|
|
19
|
+
const prefix = packageNameToPrefix(options.package);
|
|
20
|
+
if (!meta.packages[prefix]) {
|
|
21
|
+
logger.error(`Package ${options.package} is not synced.`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
packagesToUpdate.push(prefix);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
packagesToUpdate.push(...Object.keys(meta.packages));
|
|
29
|
+
}
|
|
30
|
+
let updatedMeta = { ...meta };
|
|
31
|
+
let hasChanges = false;
|
|
32
|
+
for (const prefix of packagesToUpdate) {
|
|
33
|
+
const packageInfo = updatedMeta.packages[prefix];
|
|
34
|
+
const packageName = packageInfo.originalName;
|
|
35
|
+
console.log(pc.cyan(`\nUpdating ${packageName}...`));
|
|
36
|
+
const isLocal = options.local ?? packageInfo.local ?? false;
|
|
37
|
+
const currentPkgInfo = isLocal
|
|
38
|
+
? readLocalPackageJson(packageName, cwd)
|
|
39
|
+
: readPackageJson(packageName, cwd);
|
|
40
|
+
if (!currentPkgInfo) {
|
|
41
|
+
const location = isLocal ? 'workspace' : 'node_modules';
|
|
42
|
+
console.log(pc.yellow(` ⚠ Package not found in ${location}, skipping version update`));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const newVersion = currentPkgInfo.version;
|
|
46
|
+
if (newVersion !== packageInfo.version) {
|
|
47
|
+
if (options.dryRun) {
|
|
48
|
+
console.log(pc.gray(` [DRY RUN] Would update version: ${packageInfo.version} → ${newVersion}`));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
updatedMeta = updatePackageVersion(updatedMeta, prefix, newVersion);
|
|
52
|
+
console.log(pc.green(` ✓ Version updated: ${packageInfo.version} → ${newVersion}`));
|
|
53
|
+
hasChanges = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(pc.gray(` Version unchanged: ${packageInfo.version}`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const scannedTrees = await scanPackageAssets(packageName, {
|
|
62
|
+
local: isLocal,
|
|
63
|
+
ref: options.ref,
|
|
64
|
+
cwd,
|
|
65
|
+
});
|
|
66
|
+
if (scannedTrees && scannedTrees.length > 0) {
|
|
67
|
+
for (const assetTypeTree of scannedTrees) {
|
|
68
|
+
const assetType = assetTypeTree.label;
|
|
69
|
+
const scannedUnits = buildSkillUnitsFromTree(assetTypeTree, prefix);
|
|
70
|
+
const currentUnits = packageInfo.files[assetType] || [];
|
|
71
|
+
const scannedNames = new Set(scannedUnits.map((u) => u.name));
|
|
72
|
+
const currentNames = new Set(currentUnits.map((u) => u.name));
|
|
73
|
+
const added = scannedUnits.filter((u) => !currentNames.has(u.name));
|
|
74
|
+
const removed = currentUnits.filter((u) => !scannedNames.has(u.name));
|
|
75
|
+
const unchanged = currentUnits.filter((u) => scannedNames.has(u.name));
|
|
76
|
+
if (added.length > 0 || removed.length > 0) {
|
|
77
|
+
const mergedUnits = [...unchanged, ...added];
|
|
78
|
+
if (options.dryRun) {
|
|
79
|
+
if (added.length > 0) {
|
|
80
|
+
console.log(pc.gray(` [DRY RUN] ${assetType}: ${added.length} new skill(s) found`));
|
|
81
|
+
for (const u of added) {
|
|
82
|
+
console.log(pc.gray(` + ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (removed.length > 0) {
|
|
86
|
+
console.log(pc.yellow(` [DRY RUN] ${assetType}: ${removed.length} skill(s) no longer in upstream`));
|
|
87
|
+
for (const u of removed) {
|
|
88
|
+
console.log(pc.yellow(` - ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
updatedMeta = updatePackageFilesystemMeta(updatedMeta, prefix, assetType, mergedUnits);
|
|
94
|
+
if (added.length > 0) {
|
|
95
|
+
console.log(pc.green(` ✓ ${assetType}: ${added.length} new skill(s) added to meta`));
|
|
96
|
+
for (const u of added) {
|
|
97
|
+
console.log(pc.green(` + ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (removed.length > 0) {
|
|
101
|
+
console.log(pc.yellow(` ⚠ ${assetType}: ${removed.length} skill(s) no longer in upstream (kept in meta)`));
|
|
102
|
+
for (const u of removed) {
|
|
103
|
+
console.log(pc.yellow(` - ${u.name}${u.isDirectory ? '/' : ''}`));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
hasChanges = true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
let internalChanged = false;
|
|
111
|
+
const refreshedUnits = currentUnits.map((current) => {
|
|
112
|
+
const scanned = scannedUnits.find((s) => s.name === current.name);
|
|
113
|
+
if (scanned && scanned.isDirectory && current.isDirectory) {
|
|
114
|
+
const currentInternal = (current.internalFiles || []).sort().join(',');
|
|
115
|
+
const scannedInternal = (scanned.internalFiles || []).sort().join(',');
|
|
116
|
+
if (currentInternal !== scannedInternal) {
|
|
117
|
+
internalChanged = true;
|
|
118
|
+
return { ...current, internalFiles: scanned.internalFiles };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return current;
|
|
122
|
+
});
|
|
123
|
+
if (internalChanged && !options.dryRun) {
|
|
124
|
+
updatedMeta = updatePackageFilesystemMeta(updatedMeta, prefix, assetType, refreshedUnits);
|
|
125
|
+
console.log(pc.green(` ✓ ${assetType}: internal file lists updated`));
|
|
126
|
+
hasChanges = true;
|
|
127
|
+
}
|
|
128
|
+
else if (internalChanged && options.dryRun) {
|
|
129
|
+
console.log(pc.gray(` [DRY RUN] ${assetType}: would update internal file lists`));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log(pc.gray(` ${assetType}: no changes`));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
console.log(pc.yellow(` ⚠ Could not scan package assets, skipping filesystem update`));
|
|
140
|
+
}
|
|
141
|
+
if (options.sync && !options.dryRun) {
|
|
142
|
+
console.log(pc.cyan(` Syncing files...`));
|
|
143
|
+
try {
|
|
144
|
+
await syncPackage(packageName, {
|
|
145
|
+
force: true,
|
|
146
|
+
dryRun: false,
|
|
147
|
+
local: isLocal,
|
|
148
|
+
ref: options.ref,
|
|
149
|
+
flat: true,
|
|
150
|
+
}, cwd, packageInfo.exclusions, destDir);
|
|
151
|
+
console.log(pc.green(` ✓ Files synced`));
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
155
|
+
console.log(pc.red(` ✗ Sync failed: ${message}`));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else if (options.sync && options.dryRun) {
|
|
159
|
+
console.log(pc.gray(` [DRY RUN] Would re-sync files`));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (hasChanges && !options.dryRun) {
|
|
163
|
+
updatedMeta.syncedAt = new Date().toISOString();
|
|
164
|
+
updatedMeta.skillUnitFormat = SCHEMA_VERSIONS.SKILL_UNIT_FORMAT;
|
|
165
|
+
writeUnifiedSyncMeta(destDir, updatedMeta);
|
|
166
|
+
console.log(pc.green(`\n✓ Metadata updated`));
|
|
167
|
+
}
|
|
168
|
+
else if (options.dryRun) {
|
|
169
|
+
console.log(pc.gray(`\n[DRY RUN] No changes written`));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.log(pc.gray(`\nNo changes needed`));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export { runUpdateCommand };
|
|
@@ -70,6 +70,17 @@ const AddCommand = ({ packageName, local, ref, onComplete, onError, onCancel, })
|
|
|
70
70
|
};
|
|
71
71
|
function extractSelection(nodes, included, excluded) {
|
|
72
72
|
for (const node of nodes) {
|
|
73
|
+
if (node.disabled)
|
|
74
|
+
continue;
|
|
75
|
+
if (node.type === 'skill-directory') {
|
|
76
|
+
if (node.selected) {
|
|
77
|
+
included.push(node.path);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
excluded.push(node.path);
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
73
84
|
if (node.selected) {
|
|
74
85
|
included.push(node.path);
|
|
75
86
|
}
|
|
@@ -68,6 +68,17 @@ const AddCommand = ({ packageName, local, ref, onComplete, onError, onCancel, })
|
|
|
68
68
|
};
|
|
69
69
|
function extractSelection(nodes, included, excluded) {
|
|
70
70
|
for (const node of nodes) {
|
|
71
|
+
if (node.disabled)
|
|
72
|
+
continue;
|
|
73
|
+
if (node.type === 'skill-directory') {
|
|
74
|
+
if (node.selected) {
|
|
75
|
+
included.push(node.path);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
excluded.push(node.path);
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
71
82
|
if (node.selected) {
|
|
72
83
|
included.push(node.path);
|
|
73
84
|
}
|