@slats/claude-assets-sync 0.0.4 → 0.0.6
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/localSource.cjs +112 -0
- package/dist/core/localSource.d.ts +33 -0
- package/dist/core/localSource.mjs +106 -0
- package/dist/core/migration.cjs +10 -9
- package/dist/core/migration.mjs +10 -9
- package/dist/core/packageScanner.cjs +94 -1
- package/dist/core/packageScanner.d.ts +6 -1
- package/dist/core/packageScanner.mjs +94 -2
- package/dist/core/sync.cjs +118 -46
- package/dist/core/sync.mjs +119 -47
- 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.6";
|
|
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 {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('node:fs');
|
|
4
|
+
var path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const canUseLocalSource = (packageName, requestedVersion, assetPath, cwd) => {
|
|
7
|
+
const docsPath = path.join(cwd, 'node_modules', packageName, assetPath);
|
|
8
|
+
if (!fs.existsSync(docsPath)) {
|
|
9
|
+
return { available: false, reason: `Local docs path not found: ${docsPath}` };
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const pkgJsonPath = path.join(cwd, 'node_modules', packageName, 'package.json');
|
|
13
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
14
|
+
if (pkgJson.version !== requestedVersion) {
|
|
15
|
+
return {
|
|
16
|
+
available: false,
|
|
17
|
+
reason: `Version mismatch: installed=${pkgJson.version}, requested=${requestedVersion}`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { available: false, reason: 'Failed to read package.json from node_modules' };
|
|
23
|
+
}
|
|
24
|
+
return { available: true, docsPath };
|
|
25
|
+
};
|
|
26
|
+
const fetchLocalDirectoryContents = (dirPath) => {
|
|
27
|
+
if (!fs.existsSync(dirPath))
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
const entries = fs.readdirSync(dirPath);
|
|
31
|
+
const result = [];
|
|
32
|
+
for (const name of entries) {
|
|
33
|
+
const fullPath = path.join(dirPath, name);
|
|
34
|
+
const stat = fs.statSync(fullPath);
|
|
35
|
+
if (stat.isDirectory()) {
|
|
36
|
+
result.push({
|
|
37
|
+
name,
|
|
38
|
+
path: fullPath,
|
|
39
|
+
type: 'dir',
|
|
40
|
+
download_url: null,
|
|
41
|
+
sha: '',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (stat.isFile() && name.endsWith('.md')) {
|
|
45
|
+
result.push({
|
|
46
|
+
name,
|
|
47
|
+
path: fullPath,
|
|
48
|
+
type: 'file',
|
|
49
|
+
download_url: null,
|
|
50
|
+
sha: '',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const expandLocalDirectoryEntries = (dirPath, entries, prefix = '') => {
|
|
61
|
+
const result = [];
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
const entryPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
64
|
+
if (entry.type === 'file') {
|
|
65
|
+
result.push({
|
|
66
|
+
...entry,
|
|
67
|
+
name: prefix ? entryPrefix : entry.name,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else if (entry.type === 'dir') {
|
|
71
|
+
const subDirPath = path.join(dirPath, entry.name);
|
|
72
|
+
const subEntries = fetchLocalDirectoryContents(subDirPath);
|
|
73
|
+
if (subEntries) {
|
|
74
|
+
const expanded = expandLocalDirectoryEntries(subDirPath, subEntries, entryPrefix);
|
|
75
|
+
result.push(...expanded);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
};
|
|
81
|
+
const fetchLocalAssetFiles = async (docsBasePath, assetTypes) => {
|
|
82
|
+
const assetFiles = {};
|
|
83
|
+
for (const assetType of assetTypes) {
|
|
84
|
+
const assetDirPath = path.join(docsBasePath, assetType);
|
|
85
|
+
const entries = fetchLocalDirectoryContents(assetDirPath);
|
|
86
|
+
if (!entries) {
|
|
87
|
+
assetFiles[assetType] = [];
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
assetFiles[assetType] = expandLocalDirectoryEntries(assetDirPath, entries);
|
|
91
|
+
}
|
|
92
|
+
return assetFiles;
|
|
93
|
+
};
|
|
94
|
+
const downloadLocalAssetFiles = async (docsBasePath, assetType, entries) => {
|
|
95
|
+
const results = new Map();
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
const filePath = path.join(docsBasePath, assetType, entry.name);
|
|
98
|
+
try {
|
|
99
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
100
|
+
results.set(entry.name, content);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
exports.canUseLocalSource = canUseLocalSource;
|
|
109
|
+
exports.downloadLocalAssetFiles = downloadLocalAssetFiles;
|
|
110
|
+
exports.expandLocalDirectoryEntries = expandLocalDirectoryEntries;
|
|
111
|
+
exports.fetchLocalAssetFiles = fetchLocalAssetFiles;
|
|
112
|
+
exports.fetchLocalDirectoryContents = fetchLocalDirectoryContents;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AssetType, GitHubEntry } from '../utils/types.js';
|
|
2
|
+
export interface LocalSourceResult {
|
|
3
|
+
available: boolean;
|
|
4
|
+
docsPath?: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Check if local docs source is available in node_modules.
|
|
9
|
+
* Returns available=true if:
|
|
10
|
+
* 1. node_modules/<packageName>/<assetPath> directory exists
|
|
11
|
+
* 2. Installed version matches requestedVersion
|
|
12
|
+
*/
|
|
13
|
+
export declare const canUseLocalSource: (packageName: string, requestedVersion: string, assetPath: string, cwd: string) => LocalSourceResult;
|
|
14
|
+
/**
|
|
15
|
+
* Read directory contents and return .md files and subdirs in GitHubEntry format.
|
|
16
|
+
* Returns null if the directory doesn't exist.
|
|
17
|
+
*/
|
|
18
|
+
export declare const fetchLocalDirectoryContents: (dirPath: string) => GitHubEntry[] | null;
|
|
19
|
+
/**
|
|
20
|
+
* Recursively expand directory entries into flat file entries with path prefixes.
|
|
21
|
+
* Mirrors github.ts expandDirectoryEntries behaviour but reads from local filesystem.
|
|
22
|
+
*/
|
|
23
|
+
export declare const expandLocalDirectoryEntries: (dirPath: string, entries: GitHubEntry[], prefix?: string) => GitHubEntry[];
|
|
24
|
+
/**
|
|
25
|
+
* Fetch asset files from local filesystem.
|
|
26
|
+
* Mirrors github.ts fetchAssetFiles but reads from node_modules instead of GitHub API.
|
|
27
|
+
*/
|
|
28
|
+
export declare const fetchLocalAssetFiles: (docsBasePath: string, assetTypes: string[]) => Promise<Record<string, GitHubEntry[]>>;
|
|
29
|
+
/**
|
|
30
|
+
* Read file contents from local filesystem for the given entries.
|
|
31
|
+
* Mirrors github.ts downloadAssetFiles but reads local files instead of HTTP requests.
|
|
32
|
+
*/
|
|
33
|
+
export declare const downloadLocalAssetFiles: (docsBasePath: string, assetType: AssetType, entries: GitHubEntry[]) => Promise<Map<string, string>>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const canUseLocalSource = (packageName, requestedVersion, assetPath, cwd) => {
|
|
5
|
+
const docsPath = join(cwd, 'node_modules', packageName, assetPath);
|
|
6
|
+
if (!existsSync(docsPath)) {
|
|
7
|
+
return { available: false, reason: `Local docs path not found: ${docsPath}` };
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const pkgJsonPath = join(cwd, 'node_modules', packageName, 'package.json');
|
|
11
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
12
|
+
if (pkgJson.version !== requestedVersion) {
|
|
13
|
+
return {
|
|
14
|
+
available: false,
|
|
15
|
+
reason: `Version mismatch: installed=${pkgJson.version}, requested=${requestedVersion}`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { available: false, reason: 'Failed to read package.json from node_modules' };
|
|
21
|
+
}
|
|
22
|
+
return { available: true, docsPath };
|
|
23
|
+
};
|
|
24
|
+
const fetchLocalDirectoryContents = (dirPath) => {
|
|
25
|
+
if (!existsSync(dirPath))
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
const entries = readdirSync(dirPath);
|
|
29
|
+
const result = [];
|
|
30
|
+
for (const name of entries) {
|
|
31
|
+
const fullPath = join(dirPath, name);
|
|
32
|
+
const stat = statSync(fullPath);
|
|
33
|
+
if (stat.isDirectory()) {
|
|
34
|
+
result.push({
|
|
35
|
+
name,
|
|
36
|
+
path: fullPath,
|
|
37
|
+
type: 'dir',
|
|
38
|
+
download_url: null,
|
|
39
|
+
sha: '',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else if (stat.isFile() && name.endsWith('.md')) {
|
|
43
|
+
result.push({
|
|
44
|
+
name,
|
|
45
|
+
path: fullPath,
|
|
46
|
+
type: 'file',
|
|
47
|
+
download_url: null,
|
|
48
|
+
sha: '',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const expandLocalDirectoryEntries = (dirPath, entries, prefix = '') => {
|
|
59
|
+
const result = [];
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
const entryPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
62
|
+
if (entry.type === 'file') {
|
|
63
|
+
result.push({
|
|
64
|
+
...entry,
|
|
65
|
+
name: prefix ? entryPrefix : entry.name,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else if (entry.type === 'dir') {
|
|
69
|
+
const subDirPath = join(dirPath, entry.name);
|
|
70
|
+
const subEntries = fetchLocalDirectoryContents(subDirPath);
|
|
71
|
+
if (subEntries) {
|
|
72
|
+
const expanded = expandLocalDirectoryEntries(subDirPath, subEntries, entryPrefix);
|
|
73
|
+
result.push(...expanded);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
const fetchLocalAssetFiles = async (docsBasePath, assetTypes) => {
|
|
80
|
+
const assetFiles = {};
|
|
81
|
+
for (const assetType of assetTypes) {
|
|
82
|
+
const assetDirPath = join(docsBasePath, assetType);
|
|
83
|
+
const entries = fetchLocalDirectoryContents(assetDirPath);
|
|
84
|
+
if (!entries) {
|
|
85
|
+
assetFiles[assetType] = [];
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
assetFiles[assetType] = expandLocalDirectoryEntries(assetDirPath, entries);
|
|
89
|
+
}
|
|
90
|
+
return assetFiles;
|
|
91
|
+
};
|
|
92
|
+
const downloadLocalAssetFiles = async (docsBasePath, assetType, entries) => {
|
|
93
|
+
const results = new Map();
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
const filePath = join(docsBasePath, assetType, entry.name);
|
|
96
|
+
try {
|
|
97
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
98
|
+
results.set(entry.name, content);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return results;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { canUseLocalSource, downloadLocalAssetFiles, expandLocalDirectoryEntries, fetchLocalAssetFiles, fetchLocalDirectoryContents };
|
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
|
};
|