@slats/claude-assets-sync 0.0.3 → 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 +13 -13
- package/dist/commands/remove.mjs +7 -7
- 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/assetStructure.d.ts +1 -1
- 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 +18 -12
- package/dist/core/filesystem.d.ts +3 -2
- package/dist/core/filesystem.mjs +18 -12
- package/dist/core/github.cjs +31 -3
- package/dist/core/github.d.ts +14 -1
- package/dist/core/github.mjs +31 -4
- package/dist/core/migration.cjs +17 -15
- package/dist/core/migration.mjs +12 -10
- package/dist/core/packageScanner.cjs +110 -29
- package/dist/core/packageScanner.d.ts +6 -1
- package/dist/core/packageScanner.mjs +109 -30
- package/dist/core/sync.cjs +83 -59
- package/dist/core/sync.mjs +55 -31
- 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/nameTransform.cjs +7 -6
- package/dist/utils/nameTransform.d.ts +22 -33
- package/dist/utils/nameTransform.mjs +8 -6
- 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 +2 -2
- package/CHANGELOG.md +0 -189
|
@@ -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,24 +58,30 @@ 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
|
-
for (const
|
|
62
|
-
const fileName =
|
|
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
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const filePath = path.join(destDir, fileName);
|
|
71
|
+
if (io.fileExists(filePath)) {
|
|
72
|
+
fs.rmSync(filePath, { force: true });
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
}
|
|
72
78
|
else {
|
|
73
79
|
const pattern = `${prefix}_`;
|
|
74
|
-
const
|
|
75
|
-
for (const
|
|
76
|
-
if (
|
|
77
|
-
const
|
|
78
|
-
fs.rmSync(
|
|
80
|
+
const entries = io.listDirectory(destDir);
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry.startsWith(pattern)) {
|
|
83
|
+
const entryPath = path.join(destDir, entry);
|
|
84
|
+
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetType, SyncMeta, UnifiedSyncMeta } from '../utils/types';
|
|
1
|
+
import type { AssetType, SyncMeta, UnifiedSyncMeta } from '../utils/types.js';
|
|
2
2
|
import { ensureDirectory, writeTextFile } from './io';
|
|
3
3
|
/**
|
|
4
4
|
* Ensure directory exists (creates recursively if needed)
|
|
@@ -71,7 +71,8 @@ export declare const createSyncMeta: (version: string, files: string[]) => SyncM
|
|
|
71
71
|
export declare const writeFlatAssetFile: (cwd: string, assetType: AssetType, flatFileName: string, content: string) => void;
|
|
72
72
|
/**
|
|
73
73
|
* Clean flat asset files with specific prefix
|
|
74
|
-
* Removes only files belonging to the specified package, preserving others
|
|
74
|
+
* Removes only files belonging to the specified package, preserving others.
|
|
75
|
+
* Handles both single flat files (prefix_file.md) and directory-based skills (prefix_dir/).
|
|
75
76
|
* @param cwd - Current working directory
|
|
76
77
|
* @param assetType - Asset type (commands, skills, agents, or any custom string)
|
|
77
78
|
* @param prefix - Package prefix (e.g., "canard-schemaForm")
|
package/dist/core/filesystem.mjs
CHANGED
|
@@ -56,24 +56,30 @@ 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
|
-
for (const
|
|
60
|
-
const fileName =
|
|
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
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const filePath = join(destDir, fileName);
|
|
69
|
+
if (fileExists(filePath)) {
|
|
70
|
+
rmSync(filePath, { force: true });
|
|
71
|
+
}
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
}
|
|
70
76
|
else {
|
|
71
77
|
const pattern = `${prefix}_`;
|
|
72
|
-
const
|
|
73
|
-
for (const
|
|
74
|
-
if (
|
|
75
|
-
const
|
|
76
|
-
rmSync(
|
|
78
|
+
const entries = listDirectory(destDir);
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
if (entry.startsWith(pattern)) {
|
|
81
|
+
const entryPath = join(destDir, entry);
|
|
82
|
+
rmSync(entryPath, { recursive: true, force: true });
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
}
|
package/dist/core/github.cjs
CHANGED
|
@@ -37,17 +37,44 @@ const fetchDirectoryContents = async (repoInfo, path, tag) => {
|
|
|
37
37
|
if (!response.ok)
|
|
38
38
|
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
39
39
|
const data = await response.json();
|
|
40
|
-
return data.filter((entry) => entry.type === 'file' && entry.name.endsWith('.md'))
|
|
40
|
+
return data.filter((entry) => (entry.type === 'file' && entry.name.endsWith('.md')) ||
|
|
41
|
+
entry.type === 'dir');
|
|
42
|
+
};
|
|
43
|
+
const expandDirectoryEntries = async (repoInfo, parentPath, entries, tag, prefix = '') => {
|
|
44
|
+
const result = [];
|
|
45
|
+
for (const entry of entries) {
|
|
46
|
+
const entryPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
47
|
+
if (entry.type === 'file') {
|
|
48
|
+
result.push({
|
|
49
|
+
...entry,
|
|
50
|
+
name: prefix ? entryPrefix : entry.name,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else if (entry.type === 'dir') {
|
|
54
|
+
const subEntries = await fetchDirectoryContents(repoInfo, `${parentPath}/${entry.name}`, tag);
|
|
55
|
+
if (subEntries) {
|
|
56
|
+
const expanded = await expandDirectoryEntries(repoInfo, `${parentPath}/${entry.name}`, subEntries, tag, entryPrefix);
|
|
57
|
+
result.push(...expanded);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
41
62
|
};
|
|
42
63
|
const fetchAssetFiles = async (repoInfo, assetPath, tag, assetTypes) => {
|
|
43
64
|
const basePath = repoInfo.directory
|
|
44
65
|
? `${repoInfo.directory}/${assetPath}`
|
|
45
66
|
: assetPath;
|
|
46
67
|
const fetchPromises = assetTypes.map((assetType) => fetchDirectoryContents(repoInfo, `${basePath}/${assetType}`, tag));
|
|
47
|
-
const
|
|
68
|
+
const rawResults = await Promise.all(fetchPromises);
|
|
69
|
+
const expandedResults = await Promise.all(rawResults.map((entries, index) => {
|
|
70
|
+
if (!entries)
|
|
71
|
+
return Promise.resolve([]);
|
|
72
|
+
const assetDirPath = `${basePath}/${assetTypes[index]}`;
|
|
73
|
+
return expandDirectoryEntries(repoInfo, assetDirPath, entries, tag);
|
|
74
|
+
}));
|
|
48
75
|
const assetFiles = {};
|
|
49
76
|
assetTypes.forEach((assetType, index) => {
|
|
50
|
-
assetFiles[assetType] =
|
|
77
|
+
assetFiles[assetType] = expandedResults[index] || [];
|
|
51
78
|
});
|
|
52
79
|
return assetFiles;
|
|
53
80
|
};
|
|
@@ -83,5 +110,6 @@ exports.NotFoundError = NotFoundError;
|
|
|
83
110
|
exports.RateLimitError = RateLimitError;
|
|
84
111
|
exports.downloadAssetFiles = downloadAssetFiles;
|
|
85
112
|
exports.downloadFile = downloadFile;
|
|
113
|
+
exports.expandDirectoryEntries = expandDirectoryEntries;
|
|
86
114
|
exports.fetchAssetFiles = fetchAssetFiles;
|
|
87
115
|
exports.fetchDirectoryContents = fetchDirectoryContents;
|
package/dist/core/github.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetType, GitHubEntry, GitHubRepoInfo } from '../utils/types';
|
|
1
|
+
import type { AssetType, GitHubEntry, GitHubRepoInfo } from '../utils/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Error thrown when GitHub API rate limit is exceeded
|
|
4
4
|
*/
|
|
@@ -19,6 +19,19 @@ export declare class NotFoundError extends Error {
|
|
|
19
19
|
* @returns Array of GitHubEntry or null if directory doesn't exist
|
|
20
20
|
*/
|
|
21
21
|
export declare const fetchDirectoryContents: (repoInfo: GitHubRepoInfo, path: string, tag: string) => Promise<GitHubEntry[] | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Expand directory entries into flat file entries with recursive traversal.
|
|
24
|
+
* Fetches contents of each directory and prefixes file names with the directory path.
|
|
25
|
+
* Recursively traverses subdirectories to collect all nested files.
|
|
26
|
+
*
|
|
27
|
+
* @param repoInfo - GitHub repository information
|
|
28
|
+
* @param parentPath - Parent directory path in the repository
|
|
29
|
+
* @param entries - Array of GitHubEntry (may contain both file and dir types)
|
|
30
|
+
* @param tag - Git tag or ref to fetch from
|
|
31
|
+
* @param prefix - Accumulated path prefix for nested entries
|
|
32
|
+
* @returns Flat array of file GitHubEntry with dir-prefixed names
|
|
33
|
+
*/
|
|
34
|
+
export declare const expandDirectoryEntries: (repoInfo: GitHubRepoInfo, parentPath: string, entries: GitHubEntry[], tag: string, prefix?: string) => Promise<GitHubEntry[]>;
|
|
22
35
|
/**
|
|
23
36
|
* Fetch asset files dynamically from GitHub
|
|
24
37
|
* @param repoInfo - GitHub repository information
|
package/dist/core/github.mjs
CHANGED
|
@@ -35,17 +35,44 @@ const fetchDirectoryContents = async (repoInfo, path, tag) => {
|
|
|
35
35
|
if (!response.ok)
|
|
36
36
|
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
37
37
|
const data = await response.json();
|
|
38
|
-
return data.filter((entry) => entry.type === 'file' && entry.name.endsWith('.md'))
|
|
38
|
+
return data.filter((entry) => (entry.type === 'file' && entry.name.endsWith('.md')) ||
|
|
39
|
+
entry.type === 'dir');
|
|
40
|
+
};
|
|
41
|
+
const expandDirectoryEntries = async (repoInfo, parentPath, entries, tag, prefix = '') => {
|
|
42
|
+
const result = [];
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const entryPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
45
|
+
if (entry.type === 'file') {
|
|
46
|
+
result.push({
|
|
47
|
+
...entry,
|
|
48
|
+
name: prefix ? entryPrefix : entry.name,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else if (entry.type === 'dir') {
|
|
52
|
+
const subEntries = await fetchDirectoryContents(repoInfo, `${parentPath}/${entry.name}`, tag);
|
|
53
|
+
if (subEntries) {
|
|
54
|
+
const expanded = await expandDirectoryEntries(repoInfo, `${parentPath}/${entry.name}`, subEntries, tag, entryPrefix);
|
|
55
|
+
result.push(...expanded);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
39
60
|
};
|
|
40
61
|
const fetchAssetFiles = async (repoInfo, assetPath, tag, assetTypes) => {
|
|
41
62
|
const basePath = repoInfo.directory
|
|
42
63
|
? `${repoInfo.directory}/${assetPath}`
|
|
43
64
|
: assetPath;
|
|
44
65
|
const fetchPromises = assetTypes.map((assetType) => fetchDirectoryContents(repoInfo, `${basePath}/${assetType}`, tag));
|
|
45
|
-
const
|
|
66
|
+
const rawResults = await Promise.all(fetchPromises);
|
|
67
|
+
const expandedResults = await Promise.all(rawResults.map((entries, index) => {
|
|
68
|
+
if (!entries)
|
|
69
|
+
return Promise.resolve([]);
|
|
70
|
+
const assetDirPath = `${basePath}/${assetTypes[index]}`;
|
|
71
|
+
return expandDirectoryEntries(repoInfo, assetDirPath, entries, tag);
|
|
72
|
+
}));
|
|
46
73
|
const assetFiles = {};
|
|
47
74
|
assetTypes.forEach((assetType, index) => {
|
|
48
|
-
assetFiles[assetType] =
|
|
75
|
+
assetFiles[assetType] = expandedResults[index] || [];
|
|
49
76
|
});
|
|
50
77
|
return assetFiles;
|
|
51
78
|
};
|
|
@@ -77,4 +104,4 @@ const downloadAssetFiles = async (repoInfo, assetPath, assetType, entries, tag)
|
|
|
77
104
|
return results;
|
|
78
105
|
};
|
|
79
106
|
|
|
80
|
-
export { NotFoundError, RateLimitError, downloadAssetFiles, downloadFile, fetchAssetFiles, fetchDirectoryContents };
|
|
107
|
+
export { NotFoundError, RateLimitError, downloadAssetFiles, downloadFile, expandDirectoryEntries, fetchAssetFiles, fetchDirectoryContents };
|
package/dist/core/migration.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var fs = require('node:fs');
|
|
4
4
|
var path = require('node:path');
|
|
5
5
|
var nameTransform = require('../utils/nameTransform.cjs');
|
|
6
|
+
var packageName = require('../utils/packageName.cjs');
|
|
6
7
|
var filesystem = require('./filesystem.cjs');
|
|
7
8
|
var syncMeta = require('./syncMeta.cjs');
|
|
8
9
|
|
|
@@ -62,8 +63,8 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
62
63
|
});
|
|
63
64
|
for (const packageDir of packageDirs) {
|
|
64
65
|
const packagePath = path.join(scopePath, packageDir);
|
|
65
|
-
const packageName = `${scopeDir}/${packageDir}`;
|
|
66
|
-
console.log(` 📦 Processing ${packageName}...`);
|
|
66
|
+
const packageName$1 = `${scopeDir}/${packageDir}`;
|
|
67
|
+
console.log(` 📦 Processing ${packageName$1}...`);
|
|
67
68
|
try {
|
|
68
69
|
const metaPath = path.join(packagePath, '.sync-meta.json');
|
|
69
70
|
let legacyMeta = null;
|
|
@@ -75,9 +76,9 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
75
76
|
console.log(` ⚠️ No .sync-meta.json found, skipping`);
|
|
76
77
|
continue;
|
|
77
78
|
}
|
|
78
|
-
const prefix =
|
|
79
|
-
const
|
|
80
|
-
const
|
|
79
|
+
const prefix = packageName.packageNameToPrefix(packageName$1);
|
|
80
|
+
const commandUnits = [];
|
|
81
|
+
const skillUnits = [];
|
|
81
82
|
for (const fileName of legacyMeta.files) {
|
|
82
83
|
const sourcePath = path.join(packagePath, fileName);
|
|
83
84
|
if (!fs.existsSync(sourcePath)) {
|
|
@@ -93,14 +94,10 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
93
94
|
else {
|
|
94
95
|
console.log(` 🔍 Would migrate: ${fileName}`);
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
commandUnits.push({ name: fileName, isDirectory: false });
|
|
97
98
|
}
|
|
98
99
|
else {
|
|
99
100
|
const flatFileName = nameTransform.toFlatFileName(prefix, fileName);
|
|
100
|
-
fileMappings.push({
|
|
101
|
-
original: fileName,
|
|
102
|
-
transformed: flatFileName,
|
|
103
|
-
});
|
|
104
101
|
if (!dryRun) {
|
|
105
102
|
const content = fs.readFileSync(sourcePath, 'utf-8');
|
|
106
103
|
filesystem.writeFlatAssetFile(cwd, assetType, flatFileName, content);
|
|
@@ -109,14 +106,19 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
109
106
|
else {
|
|
110
107
|
console.log(` 🔍 Would migrate: ${fileName} → ${flatFileName}`);
|
|
111
108
|
}
|
|
109
|
+
skillUnits.push({
|
|
110
|
+
name: fileName,
|
|
111
|
+
isDirectory: false,
|
|
112
|
+
transformed: flatFileName,
|
|
113
|
+
});
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
const packageInfo = {
|
|
115
|
-
originalName: packageName,
|
|
117
|
+
originalName: packageName$1,
|
|
116
118
|
version: legacyMeta.version,
|
|
117
119
|
files: {
|
|
118
|
-
commands: assetType === 'commands' ?
|
|
119
|
-
skills: assetType === 'skills' ?
|
|
120
|
+
commands: assetType === 'commands' ? commandUnits : [],
|
|
121
|
+
skills: assetType === 'skills' ? skillUnits : [],
|
|
120
122
|
agents: [],
|
|
121
123
|
},
|
|
122
124
|
};
|
|
@@ -136,11 +138,11 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
unifiedMeta = syncMeta.updatePackageInMeta(unifiedMeta, prefix, packageInfo);
|
|
139
|
-
migratedPackages.push(packageName);
|
|
141
|
+
migratedPackages.push(packageName$1);
|
|
140
142
|
legacyDirs.push(packagePath);
|
|
141
143
|
}
|
|
142
144
|
catch (error) {
|
|
143
|
-
const errorMsg = `Failed to migrate ${packageName}: ${error}`;
|
|
145
|
+
const errorMsg = `Failed to migrate ${packageName$1}: ${error}`;
|
|
144
146
|
console.error(` ❌ ${errorMsg}`);
|
|
145
147
|
errors.push(errorMsg);
|
|
146
148
|
}
|
package/dist/core/migration.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync, statSync, readFileSync, rmSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { toFlatFileName } from '../utils/nameTransform.mjs';
|
|
4
|
+
import { packageNameToPrefix } from '../utils/packageName.mjs';
|
|
4
5
|
import { writeFlatAssetFile } from './filesystem.mjs';
|
|
5
6
|
import { readUnifiedSyncMeta, createEmptyUnifiedMeta, updatePackageInMeta, writeUnifiedSyncMeta } from './syncMeta.mjs';
|
|
6
7
|
|
|
@@ -74,8 +75,8 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
74
75
|
continue;
|
|
75
76
|
}
|
|
76
77
|
const prefix = packageNameToPrefix(packageName);
|
|
77
|
-
const
|
|
78
|
-
const
|
|
78
|
+
const commandUnits = [];
|
|
79
|
+
const skillUnits = [];
|
|
79
80
|
for (const fileName of legacyMeta.files) {
|
|
80
81
|
const sourcePath = join(packagePath, fileName);
|
|
81
82
|
if (!existsSync(sourcePath)) {
|
|
@@ -91,14 +92,10 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
91
92
|
else {
|
|
92
93
|
console.log(` 🔍 Would migrate: ${fileName}`);
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
commandUnits.push({ name: fileName, isDirectory: false });
|
|
95
96
|
}
|
|
96
97
|
else {
|
|
97
98
|
const flatFileName = toFlatFileName(prefix, fileName);
|
|
98
|
-
fileMappings.push({
|
|
99
|
-
original: fileName,
|
|
100
|
-
transformed: flatFileName,
|
|
101
|
-
});
|
|
102
99
|
if (!dryRun) {
|
|
103
100
|
const content = readFileSync(sourcePath, 'utf-8');
|
|
104
101
|
writeFlatAssetFile(cwd, assetType, flatFileName, content);
|
|
@@ -107,14 +104,19 @@ async function migrateToFlat(cwd, options = {}) {
|
|
|
107
104
|
else {
|
|
108
105
|
console.log(` 🔍 Would migrate: ${fileName} → ${flatFileName}`);
|
|
109
106
|
}
|
|
107
|
+
skillUnits.push({
|
|
108
|
+
name: fileName,
|
|
109
|
+
isDirectory: false,
|
|
110
|
+
transformed: flatFileName,
|
|
111
|
+
});
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
const packageInfo = {
|
|
113
115
|
originalName: packageName,
|
|
114
116
|
version: legacyMeta.version,
|
|
115
117
|
files: {
|
|
116
|
-
commands: assetType === 'commands' ?
|
|
117
|
-
skills: assetType === 'skills' ?
|
|
118
|
+
commands: assetType === 'commands' ? commandUnits : [],
|
|
119
|
+
skills: assetType === 'skills' ? skillUnits : [],
|
|
118
120
|
agents: [],
|
|
119
121
|
},
|
|
120
122
|
};
|