@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
|
@@ -10,12 +10,14 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
10
10
|
const [treeData, setTreeData] = React.useState(trees);
|
|
11
11
|
const flattenTree = (nodes, depth = 0) => {
|
|
12
12
|
const result = [];
|
|
13
|
-
const traverse = (items, currentDepth, parentPath = []) => {
|
|
13
|
+
const traverse = (items, currentDepth, parentPath = [], ancestorIsLast = []) => {
|
|
14
14
|
items.forEach((item, index) => {
|
|
15
|
+
const isLast = index === items.length - 1;
|
|
16
|
+
const currentIsLast = [...ancestorIsLast, isLast];
|
|
15
17
|
const currentPath = [...parentPath, index];
|
|
16
|
-
result.push({ node: item, depth: currentDepth, path: currentPath });
|
|
18
|
+
result.push({ node: item, depth: currentDepth, path: currentPath, isLastAtDepth: currentIsLast });
|
|
17
19
|
if (item.expanded && item.children) {
|
|
18
|
-
traverse(item.children, currentDepth + 1, currentPath);
|
|
20
|
+
traverse(item.children, currentDepth + 1, currentPath, currentIsLast);
|
|
19
21
|
}
|
|
20
22
|
});
|
|
21
23
|
};
|
|
@@ -32,7 +34,9 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
32
34
|
}
|
|
33
35
|
else if (key.rightArrow) {
|
|
34
36
|
const current = flatItems[selectedIndex];
|
|
35
|
-
if (current.node.type === 'directory'
|
|
37
|
+
if ((current.node.type === 'directory' || current.node.type === 'skill-directory') &&
|
|
38
|
+
!current.node.expanded &&
|
|
39
|
+
current.node.children) {
|
|
36
40
|
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
37
41
|
...node,
|
|
38
42
|
expanded: true,
|
|
@@ -42,7 +46,8 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
42
46
|
}
|
|
43
47
|
else if (key.leftArrow) {
|
|
44
48
|
const current = flatItems[selectedIndex];
|
|
45
|
-
if (current.node.type === 'directory'
|
|
49
|
+
if ((current.node.type === 'directory' || current.node.type === 'skill-directory') &&
|
|
50
|
+
current.node.expanded) {
|
|
46
51
|
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
47
52
|
...node,
|
|
48
53
|
expanded: false,
|
|
@@ -52,6 +57,9 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
52
57
|
}
|
|
53
58
|
else if (input === ' ') {
|
|
54
59
|
const current = flatItems[selectedIndex];
|
|
60
|
+
if (current.node.disabled) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
55
63
|
const newTrees = toggleNodeSelection(treeData, current.path);
|
|
56
64
|
setTreeData(newTrees);
|
|
57
65
|
}
|
|
@@ -65,7 +73,7 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
65
73
|
onCancel();
|
|
66
74
|
}
|
|
67
75
|
});
|
|
68
|
-
return (jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsxRuntime.jsx(AssetTreeNode.AssetTreeNode, { node: item.node,
|
|
76
|
+
return (jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsxRuntime.jsx(AssetTreeNode.AssetTreeNode, { node: item.node, isLastAtDepth: item.isLastAtDepth, isSelected: index === selectedIndex, onToggle: () => {
|
|
69
77
|
const newTrees = toggleNodeSelection(treeData, item.path);
|
|
70
78
|
setTreeData(newTrees);
|
|
71
79
|
} }, item.path.join('-')))) }));
|
|
@@ -8,12 +8,14 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
8
8
|
const [treeData, setTreeData] = useState(trees);
|
|
9
9
|
const flattenTree = (nodes, depth = 0) => {
|
|
10
10
|
const result = [];
|
|
11
|
-
const traverse = (items, currentDepth, parentPath = []) => {
|
|
11
|
+
const traverse = (items, currentDepth, parentPath = [], ancestorIsLast = []) => {
|
|
12
12
|
items.forEach((item, index) => {
|
|
13
|
+
const isLast = index === items.length - 1;
|
|
14
|
+
const currentIsLast = [...ancestorIsLast, isLast];
|
|
13
15
|
const currentPath = [...parentPath, index];
|
|
14
|
-
result.push({ node: item, depth: currentDepth, path: currentPath });
|
|
16
|
+
result.push({ node: item, depth: currentDepth, path: currentPath, isLastAtDepth: currentIsLast });
|
|
15
17
|
if (item.expanded && item.children) {
|
|
16
|
-
traverse(item.children, currentDepth + 1, currentPath);
|
|
18
|
+
traverse(item.children, currentDepth + 1, currentPath, currentIsLast);
|
|
17
19
|
}
|
|
18
20
|
});
|
|
19
21
|
};
|
|
@@ -30,7 +32,9 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
30
32
|
}
|
|
31
33
|
else if (key.rightArrow) {
|
|
32
34
|
const current = flatItems[selectedIndex];
|
|
33
|
-
if (current.node.type === 'directory'
|
|
35
|
+
if ((current.node.type === 'directory' || current.node.type === 'skill-directory') &&
|
|
36
|
+
!current.node.expanded &&
|
|
37
|
+
current.node.children) {
|
|
34
38
|
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
35
39
|
...node,
|
|
36
40
|
expanded: true,
|
|
@@ -40,7 +44,8 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
40
44
|
}
|
|
41
45
|
else if (key.leftArrow) {
|
|
42
46
|
const current = flatItems[selectedIndex];
|
|
43
|
-
if (current.node.type === 'directory'
|
|
47
|
+
if ((current.node.type === 'directory' || current.node.type === 'skill-directory') &&
|
|
48
|
+
current.node.expanded) {
|
|
44
49
|
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
45
50
|
...node,
|
|
46
51
|
expanded: false,
|
|
@@ -50,6 +55,9 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
50
55
|
}
|
|
51
56
|
else if (input === ' ') {
|
|
52
57
|
const current = flatItems[selectedIndex];
|
|
58
|
+
if (current.node.disabled) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
53
61
|
const newTrees = toggleNodeSelection(treeData, current.path);
|
|
54
62
|
setTreeData(newTrees);
|
|
55
63
|
}
|
|
@@ -63,7 +71,7 @@ const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
|
63
71
|
onCancel();
|
|
64
72
|
}
|
|
65
73
|
});
|
|
66
|
-
return (jsx(Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsx(AssetTreeNode, { node: item.node,
|
|
74
|
+
return (jsx(Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsx(AssetTreeNode, { node: item.node, isLastAtDepth: item.isLastAtDepth, isSelected: index === selectedIndex, onToggle: () => {
|
|
67
75
|
const newTrees = toggleNodeSelection(treeData, item.path);
|
|
68
76
|
setTreeData(newTrees);
|
|
69
77
|
} }, item.path.join('-')))) }));
|
package/dist/core/cli.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var remove = require('../commands/remove.cjs');
|
|
|
7
7
|
var status = require('../commands/status.cjs');
|
|
8
8
|
var migrate = require('../commands/migrate.cjs');
|
|
9
9
|
var add = require('../commands/add.cjs');
|
|
10
|
+
var update = require('../commands/update.cjs');
|
|
10
11
|
var version = require('../version.cjs');
|
|
11
12
|
|
|
12
13
|
const createProgram = () => {
|
|
@@ -81,6 +82,23 @@ const createProgram = () => {
|
|
|
81
82
|
.action(async (opts) => {
|
|
82
83
|
await migrate.runMigrateCommand({ dryRun: opts.dryRun });
|
|
83
84
|
});
|
|
85
|
+
program
|
|
86
|
+
.command('update')
|
|
87
|
+
.description('Update package metadata in .sync-meta.json')
|
|
88
|
+
.option('-p, --package <name>', 'Package name to update (default: all)')
|
|
89
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
90
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from')
|
|
91
|
+
.option('--dry-run', 'Preview changes without writing files', false)
|
|
92
|
+
.option('--sync', 'Re-sync files after updating metadata', false)
|
|
93
|
+
.action(async (opts) => {
|
|
94
|
+
await update.runUpdateCommand({
|
|
95
|
+
package: opts.package,
|
|
96
|
+
local: opts.local,
|
|
97
|
+
ref: opts.ref,
|
|
98
|
+
dryRun: opts.dryRun,
|
|
99
|
+
sync: opts.sync,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
84
102
|
return program;
|
|
85
103
|
};
|
|
86
104
|
const run = async () => {
|
package/dist/core/cli.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { runRemoveCommand } from '../commands/remove.mjs';
|
|
|
5
5
|
import { runStatusCommand } from '../commands/status.mjs';
|
|
6
6
|
import { runMigrateCommand } from '../commands/migrate.mjs';
|
|
7
7
|
import { runAddCommand } from '../commands/add.mjs';
|
|
8
|
+
import { runUpdateCommand } from '../commands/update.mjs';
|
|
8
9
|
import { VERSION } from '../version.mjs';
|
|
9
10
|
|
|
10
11
|
const createProgram = () => {
|
|
@@ -79,6 +80,23 @@ const createProgram = () => {
|
|
|
79
80
|
.action(async (opts) => {
|
|
80
81
|
await runMigrateCommand({ dryRun: opts.dryRun });
|
|
81
82
|
});
|
|
83
|
+
program
|
|
84
|
+
.command('update')
|
|
85
|
+
.description('Update package metadata in .sync-meta.json')
|
|
86
|
+
.option('-p, --package <name>', 'Package name to update (default: all)')
|
|
87
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
88
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from')
|
|
89
|
+
.option('--dry-run', 'Preview changes without writing files', false)
|
|
90
|
+
.option('--sync', 'Re-sync files after updating metadata', false)
|
|
91
|
+
.action(async (opts) => {
|
|
92
|
+
await runUpdateCommand({
|
|
93
|
+
package: opts.package,
|
|
94
|
+
local: opts.local,
|
|
95
|
+
ref: opts.ref,
|
|
96
|
+
dryRun: opts.dryRun,
|
|
97
|
+
sync: opts.sync,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
82
100
|
return program;
|
|
83
101
|
};
|
|
84
102
|
const run = async () => {
|
package/dist/core/constants.cjs
CHANGED
|
@@ -8,7 +8,10 @@ const META_FILES = {
|
|
|
8
8
|
UNIFIED_SYNC_META: '.claude/.sync-meta.json',
|
|
9
9
|
};
|
|
10
10
|
const SCHEMA_VERSIONS = {
|
|
11
|
-
UNIFIED_SYNC_META: version.VERSION
|
|
11
|
+
UNIFIED_SYNC_META: version.VERSION,
|
|
12
|
+
LEGACY_SYNC_META: '1.0.0',
|
|
13
|
+
SKILL_UNIT_FORMAT: '2',
|
|
14
|
+
};
|
|
12
15
|
const DEFAULT_ASSET_TYPES = ['commands', 'skills', 'agents'];
|
|
13
16
|
const FS_PATTERNS = {
|
|
14
17
|
GITHUB_HTTPS_URL: /https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -22,9 +22,16 @@ export declare const META_FILES: {
|
|
|
22
22
|
* Schema versions for metadata files
|
|
23
23
|
*/
|
|
24
24
|
export declare const SCHEMA_VERSIONS: {
|
|
25
|
-
readonly UNIFIED_SYNC_META: "0.0.
|
|
25
|
+
readonly UNIFIED_SYNC_META: "0.0.5";
|
|
26
26
|
readonly LEGACY_SYNC_META: "1.0.0";
|
|
27
|
+
readonly SKILL_UNIT_FORMAT: "2";
|
|
27
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Schema version for SkillUnit-based metadata format.
|
|
31
|
+
* Separate from package VERSION to allow independent format evolution.
|
|
32
|
+
* Used to detect whether migration from old format is needed.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SKILL_UNIT_SCHEMA_VERSION: "2";
|
|
28
35
|
/**
|
|
29
36
|
* Default asset types (exported for backward compatibility)
|
|
30
37
|
*/
|
package/dist/core/constants.mjs
CHANGED
|
@@ -6,7 +6,10 @@ const META_FILES = {
|
|
|
6
6
|
UNIFIED_SYNC_META: '.claude/.sync-meta.json',
|
|
7
7
|
};
|
|
8
8
|
const SCHEMA_VERSIONS = {
|
|
9
|
-
UNIFIED_SYNC_META: VERSION
|
|
9
|
+
UNIFIED_SYNC_META: VERSION,
|
|
10
|
+
LEGACY_SYNC_META: '1.0.0',
|
|
11
|
+
SKILL_UNIT_FORMAT: '2',
|
|
12
|
+
};
|
|
10
13
|
const DEFAULT_ASSET_TYPES = ['commands', 'skills', 'agents'];
|
|
11
14
|
const FS_PATTERNS = {
|
|
12
15
|
GITHUB_HTTPS_URL: /https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
|
package/dist/core/filesystem.cjs
CHANGED
|
@@ -58,13 +58,13 @@ const cleanFlatAssetFiles = (cwd, assetType, prefix, existingMeta) => {
|
|
|
58
58
|
const packageInfo = existingMeta.packages[prefix];
|
|
59
59
|
const filesToRemove = packageInfo.files[assetType];
|
|
60
60
|
if (Array.isArray(filesToRemove)) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
for (const unit of filesToRemove) {
|
|
62
|
+
const fileName = unit.transformed ?? unit.name;
|
|
63
|
+
if (unit.isDirectory) {
|
|
64
|
+
const dirPath = path.join(destDir, fileName);
|
|
65
|
+
if (io.fileExists(dirPath)) {
|
|
66
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
70
|
const filePath = path.join(destDir, fileName);
|
|
@@ -73,12 +73,6 @@ const cleanFlatAssetFiles = (cwd, assetType, prefix, existingMeta) => {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
for (const dir of skillDirs) {
|
|
77
|
-
const dirPath = path.join(destDir, dir);
|
|
78
|
-
if (io.fileExists(dirPath)) {
|
|
79
|
-
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
76
|
}
|
|
83
77
|
}
|
|
84
78
|
else {
|
package/dist/core/filesystem.mjs
CHANGED
|
@@ -56,13 +56,13 @@ const cleanFlatAssetFiles = (cwd, assetType, prefix, existingMeta) => {
|
|
|
56
56
|
const packageInfo = existingMeta.packages[prefix];
|
|
57
57
|
const filesToRemove = packageInfo.files[assetType];
|
|
58
58
|
if (Array.isArray(filesToRemove)) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
for (const unit of filesToRemove) {
|
|
60
|
+
const fileName = unit.transformed ?? unit.name;
|
|
61
|
+
if (unit.isDirectory) {
|
|
62
|
+
const dirPath = join(destDir, fileName);
|
|
63
|
+
if (fileExists(dirPath)) {
|
|
64
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
68
|
const filePath = join(destDir, fileName);
|
|
@@ -71,12 +71,6 @@ const cleanFlatAssetFiles = (cwd, assetType, prefix, existingMeta) => {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
for (const dir of skillDirs) {
|
|
75
|
-
const dirPath = join(destDir, dir);
|
|
76
|
-
if (fileExists(dirPath)) {
|
|
77
|
-
rmSync(dirPath, { recursive: true, force: true });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
74
|
}
|
|
81
75
|
}
|
|
82
76
|
else {
|
package/dist/core/migration.cjs
CHANGED
|
@@ -77,8 +77,8 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
79
|
const prefix = packageName.packageNameToPrefix(packageName$1);
|
|
80
|
-
const
|
|
81
|
-
const
|
|
80
|
+
const commandUnits = [];
|
|
81
|
+
const skillUnits = [];
|
|
82
82
|
for (const fileName of legacyMeta.files) {
|
|
83
83
|
const sourcePath = path.join(packagePath, fileName);
|
|
84
84
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -94,14 +94,10 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
94
94
|
else {
|
|
95
95
|
console.log(` 🔍 Would migrate: ${fileName}`);
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
commandUnits.push({ name: fileName, isDirectory: false });
|
|
98
98
|
}
|
|
99
99
|
else {
|
|
100
100
|
const flatFileName = nameTransform.toFlatFileName(prefix, fileName);
|
|
101
|
-
fileMappings.push({
|
|
102
|
-
original: fileName,
|
|
103
|
-
transformed: flatFileName,
|
|
104
|
-
});
|
|
105
101
|
if (!dryRun) {
|
|
106
102
|
const content = fs.readFileSync(sourcePath, 'utf-8');
|
|
107
103
|
filesystem.writeFlatAssetFile(cwd, assetType, flatFileName, content);
|
|
@@ -110,14 +106,19 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
110
106
|
else {
|
|
111
107
|
console.log(` 🔍 Would migrate: ${fileName} → ${flatFileName}`);
|
|
112
108
|
}
|
|
109
|
+
skillUnits.push({
|
|
110
|
+
name: fileName,
|
|
111
|
+
isDirectory: false,
|
|
112
|
+
transformed: flatFileName,
|
|
113
|
+
});
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
const packageInfo = {
|
|
116
117
|
originalName: packageName$1,
|
|
117
118
|
version: legacyMeta.version,
|
|
118
119
|
files: {
|
|
119
|
-
commands: assetType === 'commands' ?
|
|
120
|
-
skills: assetType === 'skills' ?
|
|
120
|
+
commands: assetType === 'commands' ? commandUnits : [],
|
|
121
|
+
skills: assetType === 'skills' ? skillUnits : [],
|
|
121
122
|
agents: [],
|
|
122
123
|
},
|
|
123
124
|
};
|
package/dist/core/migration.mjs
CHANGED
|
@@ -75,8 +75,8 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
75
75
|
continue;
|
|
76
76
|
}
|
|
77
77
|
const prefix = packageNameToPrefix(packageName);
|
|
78
|
-
const
|
|
79
|
-
const
|
|
78
|
+
const commandUnits = [];
|
|
79
|
+
const skillUnits = [];
|
|
80
80
|
for (const fileName of legacyMeta.files) {
|
|
81
81
|
const sourcePath = join(packagePath, fileName);
|
|
82
82
|
if (!existsSync(sourcePath)) {
|
|
@@ -92,14 +92,10 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
92
92
|
else {
|
|
93
93
|
console.log(` 🔍 Would migrate: ${fileName}`);
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
commandUnits.push({ name: fileName, isDirectory: false });
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
98
98
|
const flatFileName = toFlatFileName(prefix, fileName);
|
|
99
|
-
fileMappings.push({
|
|
100
|
-
original: fileName,
|
|
101
|
-
transformed: flatFileName,
|
|
102
|
-
});
|
|
103
99
|
if (!dryRun) {
|
|
104
100
|
const content = readFileSync(sourcePath, 'utf-8');
|
|
105
101
|
writeFlatAssetFile(cwd, assetType, flatFileName, content);
|
|
@@ -108,14 +104,19 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
108
104
|
else {
|
|
109
105
|
console.log(` 🔍 Would migrate: ${fileName} → ${flatFileName}`);
|
|
110
106
|
}
|
|
107
|
+
skillUnits.push({
|
|
108
|
+
name: fileName,
|
|
109
|
+
isDirectory: false,
|
|
110
|
+
transformed: flatFileName,
|
|
111
|
+
});
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
const packageInfo = {
|
|
114
115
|
originalName: packageName,
|
|
115
116
|
version: legacyMeta.version,
|
|
116
117
|
files: {
|
|
117
|
-
commands: assetType === 'commands' ?
|
|
118
|
-
skills: assetType === 'skills' ?
|
|
118
|
+
commands: assetType === 'commands' ? commandUnits : [],
|
|
119
|
+
skills: assetType === 'skills' ? skillUnits : [],
|
|
119
120
|
agents: [],
|
|
120
121
|
},
|
|
121
122
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var fs = require('node:fs');
|
|
4
4
|
var path = require('node:path');
|
|
5
5
|
var _package = require('../utils/package.cjs');
|
|
6
|
+
var nameTransform = require('../utils/nameTransform.cjs');
|
|
6
7
|
var constants = require('./constants.cjs');
|
|
7
8
|
var github = require('./github.cjs');
|
|
8
9
|
|
|
@@ -102,6 +103,26 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
102
103
|
}
|
|
103
104
|
return trees;
|
|
104
105
|
}
|
|
106
|
+
function scanDirectoryRecursive(dirPath, prefix) {
|
|
107
|
+
const results = [];
|
|
108
|
+
try {
|
|
109
|
+
const entries = fs.readdirSync(dirPath);
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
const fullPath = path.join(dirPath, entry);
|
|
112
|
+
const relativePath = prefix ? `${prefix}/${entry}` : entry;
|
|
113
|
+
const stat = fs.statSync(fullPath);
|
|
114
|
+
if (stat.isDirectory()) {
|
|
115
|
+
results.push(...scanDirectoryRecursive(fullPath, relativePath));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
results.push(relativePath);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
}
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
105
126
|
function buildTreeFromLocalDir(label, dirPath, basePath) {
|
|
106
127
|
const entries = fs.readdirSync(dirPath);
|
|
107
128
|
const children = [];
|
|
@@ -113,11 +134,23 @@ function buildTreeFromLocalDir(label, dirPath, basePath) {
|
|
|
113
134
|
const isSkill = fs.existsSync(path.join(fullPath, 'SKILL.md')) ||
|
|
114
135
|
fs.existsSync(path.join(fullPath, 'Skill.md'));
|
|
115
136
|
if (isSkill) {
|
|
137
|
+
const internalFiles = scanDirectoryRecursive(fullPath, '');
|
|
138
|
+
const internalChildren = internalFiles.map((f) => ({
|
|
139
|
+
id: `${relativePath}/${f}`,
|
|
140
|
+
label: f,
|
|
141
|
+
path: `${relativePath}/${f}`,
|
|
142
|
+
type: 'file',
|
|
143
|
+
selected: true,
|
|
144
|
+
expanded: false,
|
|
145
|
+
disabled: true,
|
|
146
|
+
}));
|
|
116
147
|
children.push({
|
|
117
148
|
id: relativePath,
|
|
118
149
|
label: entry,
|
|
119
150
|
path: relativePath,
|
|
120
151
|
type: 'skill-directory',
|
|
152
|
+
children: internalChildren,
|
|
153
|
+
viewOnly: true,
|
|
121
154
|
selected: true,
|
|
122
155
|
expanded: false,
|
|
123
156
|
});
|
|
@@ -170,11 +203,24 @@ function buildTreeFromGitHubEntries(label, entries, basePath, dirContentsMap) {
|
|
|
170
203
|
: false;
|
|
171
204
|
if (hasSkillMd) {
|
|
172
205
|
const skillPath = `${basePath}/${entry.name}`;
|
|
206
|
+
const internalChildren = dirEntries
|
|
207
|
+
? dirEntries.map((de) => ({
|
|
208
|
+
id: `${skillPath}/${de.name}`,
|
|
209
|
+
label: de.name,
|
|
210
|
+
path: `${skillPath}/${de.name}`,
|
|
211
|
+
type: 'file',
|
|
212
|
+
selected: true,
|
|
213
|
+
expanded: false,
|
|
214
|
+
disabled: true,
|
|
215
|
+
}))
|
|
216
|
+
: [];
|
|
173
217
|
children.push({
|
|
174
218
|
id: skillPath,
|
|
175
219
|
label: entry.name,
|
|
176
220
|
path: skillPath,
|
|
177
221
|
type: 'skill-directory',
|
|
222
|
+
children: internalChildren,
|
|
223
|
+
viewOnly: true,
|
|
178
224
|
selected: true,
|
|
179
225
|
expanded: false,
|
|
180
226
|
});
|
|
@@ -259,6 +305,36 @@ function searchPackagesRecursively(dir, packageName) {
|
|
|
259
305
|
}
|
|
260
306
|
return null;
|
|
261
307
|
}
|
|
308
|
+
function buildSkillUnitsFromTree(tree, prefix) {
|
|
309
|
+
if (!tree.children)
|
|
310
|
+
return [];
|
|
311
|
+
const units = [];
|
|
312
|
+
for (const child of tree.children) {
|
|
313
|
+
if (child.type === 'skill-directory') {
|
|
314
|
+
const internalFiles = child.children
|
|
315
|
+
? child.children.map((c) => c.label)
|
|
316
|
+
: [];
|
|
317
|
+
units.push({
|
|
318
|
+
name: child.label,
|
|
319
|
+
isDirectory: true,
|
|
320
|
+
transformed: nameTransform.toFlatFileName(prefix, child.label),
|
|
321
|
+
internalFiles,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
else if (child.type === 'file') {
|
|
325
|
+
units.push({
|
|
326
|
+
name: child.label,
|
|
327
|
+
isDirectory: false,
|
|
328
|
+
transformed: nameTransform.toFlatFileName(prefix, child.label),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else if (child.type === 'directory') {
|
|
332
|
+
units.push(...buildSkillUnitsFromTree(child, prefix));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return units;
|
|
336
|
+
}
|
|
262
337
|
|
|
338
|
+
exports.buildSkillUnitsFromTree = buildSkillUnitsFromTree;
|
|
263
339
|
exports.isDirectorySkill = isDirectorySkill;
|
|
264
340
|
exports.scanPackageAssets = scanPackageAssets;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GitHubEntry, TreeNode } from '../utils/types.js';
|
|
1
|
+
import type { GitHubEntry, SkillUnit, TreeNode } from '../utils/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Scan package assets from local workspace or GitHub
|
|
4
4
|
*
|
|
@@ -15,3 +15,8 @@ export declare function scanPackageAssets(packageName: string, options: {
|
|
|
15
15
|
* Check if entries represent a directory-based skill
|
|
16
16
|
*/
|
|
17
17
|
export declare function isDirectorySkill(entries: GitHubEntry[]): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Convert a TreeNode asset-type subtree into SkillUnit[] for writing to meta.
|
|
20
|
+
* Used by both `add` and `list` commands when saving.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildSkillUnitsFromTree(tree: TreeNode, prefix: string): SkillUnit[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { parseGitHubRepo } from '../utils/package.mjs';
|
|
4
|
+
import { toFlatFileName } from '../utils/nameTransform.mjs';
|
|
4
5
|
import { DEFAULT_ASSET_TYPES } from './constants.mjs';
|
|
5
6
|
import { fetchDirectoryContents } from './github.mjs';
|
|
6
7
|
|
|
@@ -100,6 +101,26 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
100
101
|
}
|
|
101
102
|
return trees;
|
|
102
103
|
}
|
|
104
|
+
function scanDirectoryRecursive(dirPath, prefix) {
|
|
105
|
+
const results = [];
|
|
106
|
+
try {
|
|
107
|
+
const entries = readdirSync(dirPath);
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
const fullPath = join(dirPath, entry);
|
|
110
|
+
const relativePath = prefix ? `${prefix}/${entry}` : entry;
|
|
111
|
+
const stat = statSync(fullPath);
|
|
112
|
+
if (stat.isDirectory()) {
|
|
113
|
+
results.push(...scanDirectoryRecursive(fullPath, relativePath));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
results.push(relativePath);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
}
|
|
122
|
+
return results;
|
|
123
|
+
}
|
|
103
124
|
function buildTreeFromLocalDir(label, dirPath, basePath) {
|
|
104
125
|
const entries = readdirSync(dirPath);
|
|
105
126
|
const children = [];
|
|
@@ -111,11 +132,23 @@ function buildTreeFromLocalDir(label, dirPath, basePath) {
|
|
|
111
132
|
const isSkill = existsSync(join(fullPath, 'SKILL.md')) ||
|
|
112
133
|
existsSync(join(fullPath, 'Skill.md'));
|
|
113
134
|
if (isSkill) {
|
|
135
|
+
const internalFiles = scanDirectoryRecursive(fullPath, '');
|
|
136
|
+
const internalChildren = internalFiles.map((f) => ({
|
|
137
|
+
id: `${relativePath}/${f}`,
|
|
138
|
+
label: f,
|
|
139
|
+
path: `${relativePath}/${f}`,
|
|
140
|
+
type: 'file',
|
|
141
|
+
selected: true,
|
|
142
|
+
expanded: false,
|
|
143
|
+
disabled: true,
|
|
144
|
+
}));
|
|
114
145
|
children.push({
|
|
115
146
|
id: relativePath,
|
|
116
147
|
label: entry,
|
|
117
148
|
path: relativePath,
|
|
118
149
|
type: 'skill-directory',
|
|
150
|
+
children: internalChildren,
|
|
151
|
+
viewOnly: true,
|
|
119
152
|
selected: true,
|
|
120
153
|
expanded: false,
|
|
121
154
|
});
|
|
@@ -168,11 +201,24 @@ function buildTreeFromGitHubEntries(label, entries, basePath, dirContentsMap) {
|
|
|
168
201
|
: false;
|
|
169
202
|
if (hasSkillMd) {
|
|
170
203
|
const skillPath = `${basePath}/${entry.name}`;
|
|
204
|
+
const internalChildren = dirEntries
|
|
205
|
+
? dirEntries.map((de) => ({
|
|
206
|
+
id: `${skillPath}/${de.name}`,
|
|
207
|
+
label: de.name,
|
|
208
|
+
path: `${skillPath}/${de.name}`,
|
|
209
|
+
type: 'file',
|
|
210
|
+
selected: true,
|
|
211
|
+
expanded: false,
|
|
212
|
+
disabled: true,
|
|
213
|
+
}))
|
|
214
|
+
: [];
|
|
171
215
|
children.push({
|
|
172
216
|
id: skillPath,
|
|
173
217
|
label: entry.name,
|
|
174
218
|
path: skillPath,
|
|
175
219
|
type: 'skill-directory',
|
|
220
|
+
children: internalChildren,
|
|
221
|
+
viewOnly: true,
|
|
176
222
|
selected: true,
|
|
177
223
|
expanded: false,
|
|
178
224
|
});
|
|
@@ -257,5 +303,34 @@ function searchPackagesRecursively(dir, packageName) {
|
|
|
257
303
|
}
|
|
258
304
|
return null;
|
|
259
305
|
}
|
|
306
|
+
function buildSkillUnitsFromTree(tree, prefix) {
|
|
307
|
+
if (!tree.children)
|
|
308
|
+
return [];
|
|
309
|
+
const units = [];
|
|
310
|
+
for (const child of tree.children) {
|
|
311
|
+
if (child.type === 'skill-directory') {
|
|
312
|
+
const internalFiles = child.children
|
|
313
|
+
? child.children.map((c) => c.label)
|
|
314
|
+
: [];
|
|
315
|
+
units.push({
|
|
316
|
+
name: child.label,
|
|
317
|
+
isDirectory: true,
|
|
318
|
+
transformed: toFlatFileName(prefix, child.label),
|
|
319
|
+
internalFiles,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
else if (child.type === 'file') {
|
|
323
|
+
units.push({
|
|
324
|
+
name: child.label,
|
|
325
|
+
isDirectory: false,
|
|
326
|
+
transformed: toFlatFileName(prefix, child.label),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
else if (child.type === 'directory') {
|
|
330
|
+
units.push(...buildSkillUnitsFromTree(child, prefix));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return units;
|
|
334
|
+
}
|
|
260
335
|
|
|
261
|
-
export { isDirectorySkill, scanPackageAssets };
|
|
336
|
+
export { buildSkillUnitsFromTree, isDirectorySkill, scanPackageAssets };
|