@slats/claude-assets-sync 0.0.1 → 0.0.3
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/CHANGELOG.md +189 -0
- package/README.md +541 -45
- package/dist/cli.cjs +8 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +7 -0
- package/dist/commands/add.cjs +61 -0
- package/dist/commands/add.d.ts +12 -0
- package/dist/commands/add.mjs +59 -0
- package/dist/commands/index.d.ts +91 -0
- package/dist/commands/list.cjs +83 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.mjs +81 -0
- package/dist/commands/migrate.cjs +9 -0
- package/dist/commands/migrate.d.ts +6 -0
- package/dist/commands/migrate.mjs +7 -0
- package/dist/commands/remove.cjs +109 -0
- package/dist/commands/remove.d.ts +6 -0
- package/dist/commands/remove.mjs +86 -0
- package/dist/commands/status.cjs +193 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.mjs +171 -0
- package/dist/commands/sync.cjs +28 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.mjs +26 -0
- package/dist/commands/types.d.ts +82 -0
- package/dist/components/add/AddCommand.cjs +92 -0
- package/dist/components/add/AddCommand.d.ts +14 -0
- package/dist/components/add/AddCommand.mjs +90 -0
- package/dist/components/add/index.d.ts +2 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/list/EditableTreeItem.d.ts +13 -0
- package/dist/components/list/ListCommand.cjs +440 -0
- package/dist/components/list/ListCommand.d.ts +8 -0
- package/dist/components/list/ListCommand.mjs +418 -0
- package/dist/components/list/SyncedPackageTree.d.ts +14 -0
- package/dist/components/list/index.d.ts +9 -0
- package/dist/components/primitives/Box.d.ts +4 -0
- package/dist/components/primitives/Spinner.d.ts +6 -0
- package/dist/components/primitives/Text.d.ts +4 -0
- package/dist/components/primitives/index.d.ts +3 -0
- package/dist/components/status/PackageStatusCard.d.ts +10 -0
- package/dist/components/status/StatusDisplay.cjs +25 -0
- package/dist/components/status/StatusDisplay.d.ts +25 -0
- package/dist/components/status/StatusDisplay.mjs +23 -0
- package/dist/components/status/StatusTreeNode.cjs +40 -0
- package/dist/components/status/StatusTreeNode.d.ts +15 -0
- package/dist/components/status/StatusTreeNode.mjs +38 -0
- package/dist/components/status/index.d.ts +6 -0
- package/dist/components/tree/AssetTreeNode.cjs +37 -0
- package/dist/components/tree/AssetTreeNode.d.ts +12 -0
- package/dist/components/tree/AssetTreeNode.mjs +35 -0
- package/dist/components/tree/TreeSelect.cjs +121 -0
- package/dist/components/tree/TreeSelect.d.ts +12 -0
- package/dist/components/tree/TreeSelect.mjs +119 -0
- package/dist/components/tree/index.d.ts +4 -0
- package/dist/core/assetStructure.cjs +30 -0
- package/dist/core/assetStructure.d.ts +36 -0
- package/dist/core/assetStructure.mjs +27 -0
- package/dist/core/cli.cjs +92 -0
- package/dist/core/cli.mjs +89 -0
- package/dist/core/constants.cjs +23 -0
- package/dist/core/constants.d.ts +83 -0
- package/dist/core/constants.mjs +17 -0
- package/dist/core/filesystem.cjs +62 -51
- package/dist/core/filesystem.d.ts +38 -18
- package/dist/core/filesystem.mjs +56 -44
- package/dist/core/github.cjs +8 -11
- package/dist/core/github.d.ts +4 -6
- package/dist/core/github.mjs +8 -11
- package/dist/core/io.cjs +46 -0
- package/dist/core/io.d.ts +40 -0
- package/dist/core/io.mjs +39 -0
- package/dist/core/migration.cjs +199 -0
- package/dist/core/migration.d.ts +57 -0
- package/dist/core/migration.mjs +196 -0
- package/dist/core/packageScanner.cjs +259 -0
- package/dist/core/packageScanner.d.ts +17 -0
- package/dist/core/packageScanner.mjs +257 -0
- package/dist/core/sync.cjs +244 -61
- package/dist/core/sync.d.ts +6 -2
- package/dist/core/sync.mjs +246 -63
- package/dist/core/syncMeta.cjs +93 -0
- package/dist/core/syncMeta.d.ts +71 -0
- package/dist/core/syncMeta.mjs +84 -0
- package/dist/index.cjs +7 -8
- package/dist/index.d.ts +4 -3
- package/dist/index.mjs +2 -10
- package/dist/utils/nameTransform.cjs +12 -0
- package/dist/utils/nameTransform.d.ts +76 -0
- package/dist/utils/nameTransform.mjs +9 -0
- package/dist/utils/package.cjs +22 -17
- package/dist/utils/package.d.ts +25 -0
- package/dist/utils/package.mjs +11 -7
- package/dist/utils/packageName.cjs +24 -0
- package/dist/utils/packageName.d.ts +32 -0
- package/dist/utils/packageName.mjs +21 -0
- package/dist/utils/paths.cjs +18 -0
- package/dist/utils/paths.d.ts +55 -0
- package/dist/utils/paths.mjs +15 -0
- package/dist/utils/types.d.ts +153 -6
- package/dist/utils/version.cjs +17 -0
- package/dist/utils/version.d.ts +55 -0
- package/dist/utils/version.mjs +14 -0
- package/dist/version.cjs +5 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.mjs +3 -0
- package/package.json +16 -7
- package/dist/cli/index.cjs +0 -56
- package/dist/cli/index.mjs +0 -53
- /package/dist/{cli/index.d.ts → core/cli.d.ts} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var ink = require('ink');
|
|
5
|
+
|
|
6
|
+
function hasPartialSelection(node) {
|
|
7
|
+
if (!node.children || node.children.length === 0) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const selectedCount = node.children.filter((child) => child.selected).length;
|
|
11
|
+
return selectedCount > 0 && selectedCount < node.children.length;
|
|
12
|
+
}
|
|
13
|
+
const AssetTreeNode = ({ node, depth, isSelected, }) => {
|
|
14
|
+
const indent = ' '.repeat(depth);
|
|
15
|
+
let selectionIcon;
|
|
16
|
+
let iconColor;
|
|
17
|
+
if (hasPartialSelection(node)) {
|
|
18
|
+
selectionIcon = '◐';
|
|
19
|
+
iconColor = 'yellow';
|
|
20
|
+
}
|
|
21
|
+
else if (node.selected) {
|
|
22
|
+
selectionIcon = '●';
|
|
23
|
+
iconColor = 'green';
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
selectionIcon = '○';
|
|
27
|
+
iconColor = 'red';
|
|
28
|
+
}
|
|
29
|
+
const expandIcon = node.type === 'directory' && node.children
|
|
30
|
+
? node.expanded
|
|
31
|
+
? '▼'
|
|
32
|
+
: '▶'
|
|
33
|
+
: ' ';
|
|
34
|
+
return (jsxRuntime.jsx(ink.Box, { children: jsxRuntime.jsxs(ink.Text, { color: isSelected ? 'cyan' : undefined, children: [indent, expandIcon, " ", jsxRuntime.jsx(ink.Text, { color: iconColor, children: selectionIcon }), " ", node.label] }) }));
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
exports.AssetTreeNode = AssetTreeNode;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TreeNode } from '../../utils/types.js';
|
|
3
|
+
export interface AssetTreeNodeProps {
|
|
4
|
+
node: TreeNode;
|
|
5
|
+
depth: number;
|
|
6
|
+
isSelected: boolean;
|
|
7
|
+
onToggle: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Single tree node component for asset selection
|
|
11
|
+
*/
|
|
12
|
+
export declare const AssetTreeNode: React.FC<AssetTreeNodeProps>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
|
|
4
|
+
function hasPartialSelection(node) {
|
|
5
|
+
if (!node.children || node.children.length === 0) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const selectedCount = node.children.filter((child) => child.selected).length;
|
|
9
|
+
return selectedCount > 0 && selectedCount < node.children.length;
|
|
10
|
+
}
|
|
11
|
+
const AssetTreeNode = ({ node, depth, isSelected, }) => {
|
|
12
|
+
const indent = ' '.repeat(depth);
|
|
13
|
+
let selectionIcon;
|
|
14
|
+
let iconColor;
|
|
15
|
+
if (hasPartialSelection(node)) {
|
|
16
|
+
selectionIcon = '◐';
|
|
17
|
+
iconColor = 'yellow';
|
|
18
|
+
}
|
|
19
|
+
else if (node.selected) {
|
|
20
|
+
selectionIcon = '●';
|
|
21
|
+
iconColor = 'green';
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
selectionIcon = '○';
|
|
25
|
+
iconColor = 'red';
|
|
26
|
+
}
|
|
27
|
+
const expandIcon = node.type === 'directory' && node.children
|
|
28
|
+
? node.expanded
|
|
29
|
+
? '▼'
|
|
30
|
+
: '▶'
|
|
31
|
+
: ' ';
|
|
32
|
+
return (jsx(Box, { children: jsxs(Text, { color: isSelected ? 'cyan' : undefined, children: [indent, expandIcon, " ", jsx(Text, { color: iconColor, children: selectionIcon }), " ", node.label] }) }));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { AssetTreeNode };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var ink = require('ink');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var AssetTreeNode = require('./AssetTreeNode.cjs');
|
|
7
|
+
|
|
8
|
+
const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
9
|
+
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
10
|
+
const [treeData, setTreeData] = React.useState(trees);
|
|
11
|
+
const flattenTree = (nodes, depth = 0) => {
|
|
12
|
+
const result = [];
|
|
13
|
+
const traverse = (items, currentDepth, parentPath = []) => {
|
|
14
|
+
items.forEach((item, index) => {
|
|
15
|
+
const currentPath = [...parentPath, index];
|
|
16
|
+
result.push({ node: item, depth: currentDepth, path: currentPath });
|
|
17
|
+
if (item.expanded && item.children) {
|
|
18
|
+
traverse(item.children, currentDepth + 1, currentPath);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
traverse(nodes, depth);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
const flatItems = flattenTree(treeData);
|
|
26
|
+
ink.useInput((input, key) => {
|
|
27
|
+
if (key.upArrow) {
|
|
28
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
29
|
+
}
|
|
30
|
+
else if (key.downArrow) {
|
|
31
|
+
setSelectedIndex((prev) => Math.min(flatItems.length - 1, prev + 1));
|
|
32
|
+
}
|
|
33
|
+
else if (key.rightArrow) {
|
|
34
|
+
const current = flatItems[selectedIndex];
|
|
35
|
+
if (current.node.type === 'directory' && !current.node.expanded) {
|
|
36
|
+
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
37
|
+
...node,
|
|
38
|
+
expanded: true,
|
|
39
|
+
}));
|
|
40
|
+
setTreeData(newTrees);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (key.leftArrow) {
|
|
44
|
+
const current = flatItems[selectedIndex];
|
|
45
|
+
if (current.node.type === 'directory' && current.node.expanded) {
|
|
46
|
+
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
47
|
+
...node,
|
|
48
|
+
expanded: false,
|
|
49
|
+
}));
|
|
50
|
+
setTreeData(newTrees);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (input === ' ') {
|
|
54
|
+
const current = flatItems[selectedIndex];
|
|
55
|
+
const newTrees = toggleNodeSelection(treeData, current.path);
|
|
56
|
+
setTreeData(newTrees);
|
|
57
|
+
}
|
|
58
|
+
else if (input === 'r' && onRefresh) {
|
|
59
|
+
onRefresh();
|
|
60
|
+
}
|
|
61
|
+
else if (key.return) {
|
|
62
|
+
onSubmit(treeData);
|
|
63
|
+
}
|
|
64
|
+
else if (key.escape || input === 'q') {
|
|
65
|
+
onCancel();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return (jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsxRuntime.jsx(AssetTreeNode.AssetTreeNode, { node: item.node, depth: item.depth, isSelected: index === selectedIndex, onToggle: () => {
|
|
69
|
+
const newTrees = toggleNodeSelection(treeData, item.path);
|
|
70
|
+
setTreeData(newTrees);
|
|
71
|
+
} }, item.path.join('-')))) }));
|
|
72
|
+
};
|
|
73
|
+
function updateNodeAtPath(trees, path, updater) {
|
|
74
|
+
if (path.length === 0)
|
|
75
|
+
return trees;
|
|
76
|
+
const [index, ...rest] = path;
|
|
77
|
+
const newTrees = [...trees];
|
|
78
|
+
if (rest.length === 0) {
|
|
79
|
+
newTrees[index] = updater(newTrees[index]);
|
|
80
|
+
}
|
|
81
|
+
else if (newTrees[index].children) {
|
|
82
|
+
newTrees[index] = {
|
|
83
|
+
...newTrees[index],
|
|
84
|
+
children: updateNodeAtPath(newTrees[index].children, rest, updater),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return newTrees;
|
|
88
|
+
}
|
|
89
|
+
function toggleNodeSelection(trees, path) {
|
|
90
|
+
const updatedTrees = updateNodeAtPath(trees, path, (node) => {
|
|
91
|
+
const newSelected = !node.selected;
|
|
92
|
+
return toggleNodeAndChildren(node, newSelected);
|
|
93
|
+
});
|
|
94
|
+
return updateAncestors(updatedTrees, path);
|
|
95
|
+
}
|
|
96
|
+
function toggleNodeAndChildren(node, selected) {
|
|
97
|
+
const newNode = { ...node, selected };
|
|
98
|
+
if (node.children) {
|
|
99
|
+
newNode.children = node.children.map((child) => toggleNodeAndChildren(child, selected));
|
|
100
|
+
}
|
|
101
|
+
return newNode;
|
|
102
|
+
}
|
|
103
|
+
function updateAncestors(trees, path) {
|
|
104
|
+
if (path.length <= 1) {
|
|
105
|
+
return trees;
|
|
106
|
+
}
|
|
107
|
+
const parentPath = path.slice(0, -1);
|
|
108
|
+
const updatedTrees = updateNodeAtPath(trees, parentPath, (parentNode) => {
|
|
109
|
+
if (!parentNode.children || parentNode.children.length === 0) {
|
|
110
|
+
return parentNode;
|
|
111
|
+
}
|
|
112
|
+
const anySelected = parentNode.children.some((child) => child.selected);
|
|
113
|
+
return {
|
|
114
|
+
...parentNode,
|
|
115
|
+
selected: anySelected,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
return updateAncestors(updatedTrees, parentPath);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.TreeSelect = TreeSelect;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TreeNode } from '../../utils/types.js';
|
|
3
|
+
export interface TreeSelectProps {
|
|
4
|
+
trees: TreeNode[];
|
|
5
|
+
onSubmit: (trees: TreeNode[]) => void;
|
|
6
|
+
onCancel: () => void;
|
|
7
|
+
onRefresh?: () => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Interactive tree selection component
|
|
11
|
+
*/
|
|
12
|
+
export declare const TreeSelect: React.FC<TreeSelectProps>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useInput, Box } from 'ink';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { AssetTreeNode } from './AssetTreeNode.mjs';
|
|
5
|
+
|
|
6
|
+
const TreeSelect = ({ trees, onSubmit, onCancel, onRefresh, }) => {
|
|
7
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
8
|
+
const [treeData, setTreeData] = useState(trees);
|
|
9
|
+
const flattenTree = (nodes, depth = 0) => {
|
|
10
|
+
const result = [];
|
|
11
|
+
const traverse = (items, currentDepth, parentPath = []) => {
|
|
12
|
+
items.forEach((item, index) => {
|
|
13
|
+
const currentPath = [...parentPath, index];
|
|
14
|
+
result.push({ node: item, depth: currentDepth, path: currentPath });
|
|
15
|
+
if (item.expanded && item.children) {
|
|
16
|
+
traverse(item.children, currentDepth + 1, currentPath);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
traverse(nodes, depth);
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
const flatItems = flattenTree(treeData);
|
|
24
|
+
useInput((input, key) => {
|
|
25
|
+
if (key.upArrow) {
|
|
26
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
27
|
+
}
|
|
28
|
+
else if (key.downArrow) {
|
|
29
|
+
setSelectedIndex((prev) => Math.min(flatItems.length - 1, prev + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (key.rightArrow) {
|
|
32
|
+
const current = flatItems[selectedIndex];
|
|
33
|
+
if (current.node.type === 'directory' && !current.node.expanded) {
|
|
34
|
+
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
35
|
+
...node,
|
|
36
|
+
expanded: true,
|
|
37
|
+
}));
|
|
38
|
+
setTreeData(newTrees);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else if (key.leftArrow) {
|
|
42
|
+
const current = flatItems[selectedIndex];
|
|
43
|
+
if (current.node.type === 'directory' && current.node.expanded) {
|
|
44
|
+
const newTrees = updateNodeAtPath(treeData, current.path, (node) => ({
|
|
45
|
+
...node,
|
|
46
|
+
expanded: false,
|
|
47
|
+
}));
|
|
48
|
+
setTreeData(newTrees);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else if (input === ' ') {
|
|
52
|
+
const current = flatItems[selectedIndex];
|
|
53
|
+
const newTrees = toggleNodeSelection(treeData, current.path);
|
|
54
|
+
setTreeData(newTrees);
|
|
55
|
+
}
|
|
56
|
+
else if (input === 'r' && onRefresh) {
|
|
57
|
+
onRefresh();
|
|
58
|
+
}
|
|
59
|
+
else if (key.return) {
|
|
60
|
+
onSubmit(treeData);
|
|
61
|
+
}
|
|
62
|
+
else if (key.escape || input === 'q') {
|
|
63
|
+
onCancel();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return (jsx(Box, { flexDirection: "column", children: flatItems.map((item, index) => (jsx(AssetTreeNode, { node: item.node, depth: item.depth, isSelected: index === selectedIndex, onToggle: () => {
|
|
67
|
+
const newTrees = toggleNodeSelection(treeData, item.path);
|
|
68
|
+
setTreeData(newTrees);
|
|
69
|
+
} }, item.path.join('-')))) }));
|
|
70
|
+
};
|
|
71
|
+
function updateNodeAtPath(trees, path, updater) {
|
|
72
|
+
if (path.length === 0)
|
|
73
|
+
return trees;
|
|
74
|
+
const [index, ...rest] = path;
|
|
75
|
+
const newTrees = [...trees];
|
|
76
|
+
if (rest.length === 0) {
|
|
77
|
+
newTrees[index] = updater(newTrees[index]);
|
|
78
|
+
}
|
|
79
|
+
else if (newTrees[index].children) {
|
|
80
|
+
newTrees[index] = {
|
|
81
|
+
...newTrees[index],
|
|
82
|
+
children: updateNodeAtPath(newTrees[index].children, rest, updater),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return newTrees;
|
|
86
|
+
}
|
|
87
|
+
function toggleNodeSelection(trees, path) {
|
|
88
|
+
const updatedTrees = updateNodeAtPath(trees, path, (node) => {
|
|
89
|
+
const newSelected = !node.selected;
|
|
90
|
+
return toggleNodeAndChildren(node, newSelected);
|
|
91
|
+
});
|
|
92
|
+
return updateAncestors(updatedTrees, path);
|
|
93
|
+
}
|
|
94
|
+
function toggleNodeAndChildren(node, selected) {
|
|
95
|
+
const newNode = { ...node, selected };
|
|
96
|
+
if (node.children) {
|
|
97
|
+
newNode.children = node.children.map((child) => toggleNodeAndChildren(child, selected));
|
|
98
|
+
}
|
|
99
|
+
return newNode;
|
|
100
|
+
}
|
|
101
|
+
function updateAncestors(trees, path) {
|
|
102
|
+
if (path.length <= 1) {
|
|
103
|
+
return trees;
|
|
104
|
+
}
|
|
105
|
+
const parentPath = path.slice(0, -1);
|
|
106
|
+
const updatedTrees = updateNodeAtPath(trees, parentPath, (parentNode) => {
|
|
107
|
+
if (!parentNode.children || parentNode.children.length === 0) {
|
|
108
|
+
return parentNode;
|
|
109
|
+
}
|
|
110
|
+
const anySelected = parentNode.children.some((child) => child.selected);
|
|
111
|
+
return {
|
|
112
|
+
...parentNode,
|
|
113
|
+
selected: anySelected,
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
return updateAncestors(updatedTrees, parentPath);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { TreeSelect };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('node:fs');
|
|
4
|
+
require('node:path');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_ASSET_STRUCTURES = {
|
|
7
|
+
commands: 'nested',
|
|
8
|
+
skills: 'flat',
|
|
9
|
+
agents: 'flat',
|
|
10
|
+
};
|
|
11
|
+
function getAssetStructure(assetType, config) {
|
|
12
|
+
if (!config) {
|
|
13
|
+
return DEFAULT_ASSET_STRUCTURES[assetType] || 'flat';
|
|
14
|
+
}
|
|
15
|
+
let assetsConfig;
|
|
16
|
+
if ('assetPath' in config) {
|
|
17
|
+
assetsConfig = config
|
|
18
|
+
.assets;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
assetsConfig = config;
|
|
22
|
+
}
|
|
23
|
+
if (assetsConfig?.[assetType]?.structure) {
|
|
24
|
+
return assetsConfig[assetType].structure;
|
|
25
|
+
}
|
|
26
|
+
return DEFAULT_ASSET_STRUCTURES[assetType] || 'nested';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.DEFAULT_ASSET_STRUCTURES = DEFAULT_ASSET_STRUCTURES;
|
|
30
|
+
exports.getAssetStructure = getAssetStructure;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AssetStructure, AssetsConfig } from '../utils/types';
|
|
2
|
+
import { DEFAULT_ASSET_TYPES } from './constants';
|
|
3
|
+
export { DEFAULT_ASSET_TYPES };
|
|
4
|
+
/**
|
|
5
|
+
* Default structure configuration for built-in asset types
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_ASSET_STRUCTURES: Record<string, AssetStructure>;
|
|
8
|
+
/**
|
|
9
|
+
* Get the structure type for a given asset type
|
|
10
|
+
* @param assetType - The asset type to query
|
|
11
|
+
* @param config - Optional ClaudeConfig or AssetsConfig
|
|
12
|
+
* @returns The structure type ('nested' or 'flat')
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAssetStructure(assetType: string, config?: AssetsConfig | {
|
|
15
|
+
assetPath: string;
|
|
16
|
+
assets?: AssetsConfig;
|
|
17
|
+
}): AssetStructure;
|
|
18
|
+
/**
|
|
19
|
+
* Detect the structure type of an asset directory
|
|
20
|
+
* @param dir - Directory path to check
|
|
21
|
+
* @returns Structure type ('flat' | 'nested') or null if directory doesn't exist
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectStructureType(dir: string): AssetStructure | null;
|
|
24
|
+
/**
|
|
25
|
+
* Validate that an asset structure value is valid
|
|
26
|
+
* @param structure - Structure value to validate
|
|
27
|
+
* @returns True if valid, false otherwise
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateAssetStructure(structure: unknown): structure is AssetStructure;
|
|
30
|
+
/**
|
|
31
|
+
* Validate and normalize asset structure value
|
|
32
|
+
* @param structure - Structure value to normalize
|
|
33
|
+
* @param defaultValue - Default value if validation fails
|
|
34
|
+
* @returns Validated structure or default
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeAssetStructure(structure: unknown, defaultValue?: AssetStructure): AssetStructure;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import 'node:fs';
|
|
2
|
+
import 'node:path';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_ASSET_STRUCTURES = {
|
|
5
|
+
commands: 'nested',
|
|
6
|
+
skills: 'flat',
|
|
7
|
+
agents: 'flat',
|
|
8
|
+
};
|
|
9
|
+
function getAssetStructure(assetType, config) {
|
|
10
|
+
if (!config) {
|
|
11
|
+
return DEFAULT_ASSET_STRUCTURES[assetType] || 'flat';
|
|
12
|
+
}
|
|
13
|
+
let assetsConfig;
|
|
14
|
+
if ('assetPath' in config) {
|
|
15
|
+
assetsConfig = config
|
|
16
|
+
.assets;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
assetsConfig = config;
|
|
20
|
+
}
|
|
21
|
+
if (assetsConfig?.[assetType]?.structure) {
|
|
22
|
+
return assetsConfig[assetType].structure;
|
|
23
|
+
}
|
|
24
|
+
return DEFAULT_ASSET_STRUCTURES[assetType] || 'nested';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { DEFAULT_ASSET_STRUCTURES, getAssetStructure };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var commander = require('commander');
|
|
4
|
+
var sync = require('../commands/sync.cjs');
|
|
5
|
+
var list = require('../commands/list.cjs');
|
|
6
|
+
var remove = require('../commands/remove.cjs');
|
|
7
|
+
var status = require('../commands/status.cjs');
|
|
8
|
+
var migrate = require('../commands/migrate.cjs');
|
|
9
|
+
var add = require('../commands/add.cjs');
|
|
10
|
+
var version = require('../version.cjs');
|
|
11
|
+
|
|
12
|
+
const createProgram = () => {
|
|
13
|
+
const program = new commander.Command();
|
|
14
|
+
program
|
|
15
|
+
.name('claude-assets-sync')
|
|
16
|
+
.description('Sync Claude commands and skills from npm packages to your project')
|
|
17
|
+
.version(version.VERSION);
|
|
18
|
+
program
|
|
19
|
+
.command('sync', { isDefault: true })
|
|
20
|
+
.description('Sync Claude assets from npm packages')
|
|
21
|
+
.option('-p, --package <name>', 'Package name to sync (can be specified multiple times)', (value, previous) => [...previous, value], [])
|
|
22
|
+
.option('-f, --force', 'Force sync even if version matches', false)
|
|
23
|
+
.option('--dry-run', 'Preview changes without writing files', false)
|
|
24
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
25
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from (overrides version tag)')
|
|
26
|
+
.option('--no-flat', 'Use legacy nested directory structure instead of flat structure (default: flat)')
|
|
27
|
+
.action(async (opts) => {
|
|
28
|
+
await sync.runSyncCommand({
|
|
29
|
+
package: opts.package,
|
|
30
|
+
force: opts.force,
|
|
31
|
+
dryRun: opts.dryRun,
|
|
32
|
+
local: opts.local,
|
|
33
|
+
ref: opts.ref,
|
|
34
|
+
flat: opts.flat,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
program
|
|
38
|
+
.command('add')
|
|
39
|
+
.description('Add a package with interactive asset selection')
|
|
40
|
+
.requiredOption('-p, --package <name>', 'Package name to add')
|
|
41
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
42
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from')
|
|
43
|
+
.action(async (opts) => {
|
|
44
|
+
await add.runAddCommand({
|
|
45
|
+
package: opts.package,
|
|
46
|
+
local: opts.local,
|
|
47
|
+
ref: opts.ref,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
program
|
|
51
|
+
.command('list')
|
|
52
|
+
.description('List all synced packages')
|
|
53
|
+
.option('--json', 'Output as JSON')
|
|
54
|
+
.action(async (opts) => {
|
|
55
|
+
await list.runListCommand({ json: opts.json });
|
|
56
|
+
});
|
|
57
|
+
program
|
|
58
|
+
.command('remove')
|
|
59
|
+
.description('Remove a synced package')
|
|
60
|
+
.requiredOption('-p, --package <name>', 'Package name to remove')
|
|
61
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
62
|
+
.option('--dry-run', 'Preview changes without removing files')
|
|
63
|
+
.action(async (opts) => {
|
|
64
|
+
await remove.runRemoveCommand({
|
|
65
|
+
package: opts.package,
|
|
66
|
+
yes: opts.yes,
|
|
67
|
+
dryRun: opts.dryRun,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
program
|
|
71
|
+
.command('status')
|
|
72
|
+
.description('Show sync status of all packages')
|
|
73
|
+
.option('--no-remote', 'Skip remote version check')
|
|
74
|
+
.action(async (opts) => {
|
|
75
|
+
await status.runStatusCommand({ noRemote: !opts.remote });
|
|
76
|
+
});
|
|
77
|
+
program
|
|
78
|
+
.command('migrate')
|
|
79
|
+
.description('Migrate from legacy nested structure to flat structure')
|
|
80
|
+
.option('--dry-run', 'Preview migration without making changes')
|
|
81
|
+
.action(async (opts) => {
|
|
82
|
+
await migrate.runMigrateCommand({ dryRun: opts.dryRun });
|
|
83
|
+
});
|
|
84
|
+
return program;
|
|
85
|
+
};
|
|
86
|
+
const run = async () => {
|
|
87
|
+
const program = createProgram();
|
|
88
|
+
await program.parseAsync(process.argv);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
exports.createProgram = createProgram;
|
|
92
|
+
exports.run = run;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { runSyncCommand } from '../commands/sync.mjs';
|
|
3
|
+
import { runListCommand } from '../commands/list.mjs';
|
|
4
|
+
import { runRemoveCommand } from '../commands/remove.mjs';
|
|
5
|
+
import { runStatusCommand } from '../commands/status.mjs';
|
|
6
|
+
import { runMigrateCommand } from '../commands/migrate.mjs';
|
|
7
|
+
import { runAddCommand } from '../commands/add.mjs';
|
|
8
|
+
import { VERSION } from '../version.mjs';
|
|
9
|
+
|
|
10
|
+
const createProgram = () => {
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name('claude-assets-sync')
|
|
14
|
+
.description('Sync Claude commands and skills from npm packages to your project')
|
|
15
|
+
.version(VERSION);
|
|
16
|
+
program
|
|
17
|
+
.command('sync', { isDefault: true })
|
|
18
|
+
.description('Sync Claude assets from npm packages')
|
|
19
|
+
.option('-p, --package <name>', 'Package name to sync (can be specified multiple times)', (value, previous) => [...previous, value], [])
|
|
20
|
+
.option('-f, --force', 'Force sync even if version matches', false)
|
|
21
|
+
.option('--dry-run', 'Preview changes without writing files', false)
|
|
22
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
23
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from (overrides version tag)')
|
|
24
|
+
.option('--no-flat', 'Use legacy nested directory structure instead of flat structure (default: flat)')
|
|
25
|
+
.action(async (opts) => {
|
|
26
|
+
await runSyncCommand({
|
|
27
|
+
package: opts.package,
|
|
28
|
+
force: opts.force,
|
|
29
|
+
dryRun: opts.dryRun,
|
|
30
|
+
local: opts.local,
|
|
31
|
+
ref: opts.ref,
|
|
32
|
+
flat: opts.flat,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command('add')
|
|
37
|
+
.description('Add a package with interactive asset selection')
|
|
38
|
+
.requiredOption('-p, --package <name>', 'Package name to add')
|
|
39
|
+
.option('-l, --local', 'Read packages from local workspace instead of node_modules', false)
|
|
40
|
+
.option('-r, --ref <ref>', 'Git ref (branch, tag, or commit) to fetch from')
|
|
41
|
+
.action(async (opts) => {
|
|
42
|
+
await runAddCommand({
|
|
43
|
+
package: opts.package,
|
|
44
|
+
local: opts.local,
|
|
45
|
+
ref: opts.ref,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
program
|
|
49
|
+
.command('list')
|
|
50
|
+
.description('List all synced packages')
|
|
51
|
+
.option('--json', 'Output as JSON')
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
await runListCommand({ json: opts.json });
|
|
54
|
+
});
|
|
55
|
+
program
|
|
56
|
+
.command('remove')
|
|
57
|
+
.description('Remove a synced package')
|
|
58
|
+
.requiredOption('-p, --package <name>', 'Package name to remove')
|
|
59
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
60
|
+
.option('--dry-run', 'Preview changes without removing files')
|
|
61
|
+
.action(async (opts) => {
|
|
62
|
+
await runRemoveCommand({
|
|
63
|
+
package: opts.package,
|
|
64
|
+
yes: opts.yes,
|
|
65
|
+
dryRun: opts.dryRun,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
program
|
|
69
|
+
.command('status')
|
|
70
|
+
.description('Show sync status of all packages')
|
|
71
|
+
.option('--no-remote', 'Skip remote version check')
|
|
72
|
+
.action(async (opts) => {
|
|
73
|
+
await runStatusCommand({ noRemote: !opts.remote });
|
|
74
|
+
});
|
|
75
|
+
program
|
|
76
|
+
.command('migrate')
|
|
77
|
+
.description('Migrate from legacy nested structure to flat structure')
|
|
78
|
+
.option('--dry-run', 'Preview migration without making changes')
|
|
79
|
+
.action(async (opts) => {
|
|
80
|
+
await runMigrateCommand({ dryRun: opts.dryRun });
|
|
81
|
+
});
|
|
82
|
+
return program;
|
|
83
|
+
};
|
|
84
|
+
const run = async () => {
|
|
85
|
+
const program = createProgram();
|
|
86
|
+
await program.parseAsync(process.argv);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export { createProgram, run };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var version = require('../version.cjs');
|
|
4
|
+
|
|
5
|
+
const CLAUDE_BASE_DIR = '.claude';
|
|
6
|
+
const META_FILES = {
|
|
7
|
+
SYNC_META: '.sync-meta.json',
|
|
8
|
+
UNIFIED_SYNC_META: '.claude/.sync-meta.json',
|
|
9
|
+
};
|
|
10
|
+
const SCHEMA_VERSIONS = {
|
|
11
|
+
UNIFIED_SYNC_META: version.VERSION};
|
|
12
|
+
const DEFAULT_ASSET_TYPES = ['commands', 'skills', 'agents'];
|
|
13
|
+
const FS_PATTERNS = {
|
|
14
|
+
GITHUB_HTTPS_URL: /https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
|
|
15
|
+
GITHUB_SSH_URL: /git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/,
|
|
16
|
+
GITHUB_SHORTHAND: /^github:([^/]+)\/([^/]+)$/,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.CLAUDE_BASE_DIR = CLAUDE_BASE_DIR;
|
|
20
|
+
exports.DEFAULT_ASSET_TYPES = DEFAULT_ASSET_TYPES;
|
|
21
|
+
exports.FS_PATTERNS = FS_PATTERNS;
|
|
22
|
+
exports.META_FILES = META_FILES;
|
|
23
|
+
exports.SCHEMA_VERSIONS = SCHEMA_VERSIONS;
|