@slats/claude-assets-sync 0.0.1 → 0.0.2
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/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 -4
- package/dist/index.d.ts +4 -2
- package/dist/index.mjs +3 -2
- 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 +15 -6
- 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,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name transformation utilities for Claude assets synchronization
|
|
3
|
+
* Handles conversion between package names and flat file naming conventions
|
|
4
|
+
*/
|
|
5
|
+
import { packageNameToPrefix as packageNameToPrefixUtil } from './packageName';
|
|
6
|
+
/**
|
|
7
|
+
* Converts kebab-case string to camelCase
|
|
8
|
+
* All hyphens are removed and the following character is capitalized
|
|
9
|
+
*
|
|
10
|
+
* @param str - Input string in kebab-case format
|
|
11
|
+
* @returns String in camelCase format
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* kebabToCamel('schema-form') // 'schemaForm'
|
|
16
|
+
* kebabToCamel('schema-form-plugin') // 'schemaFormPlugin'
|
|
17
|
+
* kebabToCamel('my-long-name') // 'myLongName'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function kebabToCamel(str: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Converts a scoped package name to a flat prefix
|
|
23
|
+
* @deprecated Import from './packageName' instead
|
|
24
|
+
* @param packageName - Scoped package name (e.g., '@canard/schema-form')
|
|
25
|
+
* @returns Flat prefix (e.g., 'canard-schemaForm')
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* packageNameToPrefix('@canard/schema-form') // 'canard-schemaForm'
|
|
30
|
+
* packageNameToPrefix('@canard/schema-form-plugin') // 'canard-schemaFormPlugin'
|
|
31
|
+
* packageNameToPrefix('@winglet/react-utils') // 'winglet-reactUtils'
|
|
32
|
+
* packageNameToPrefix('@lerx/promise-modal') // 'lerx-promiseModal'
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const packageNameToPrefix: typeof packageNameToPrefixUtil;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a flat file name by combining prefix and original file name
|
|
38
|
+
*
|
|
39
|
+
* @param prefix - Package prefix (e.g., 'canard-schemaForm')
|
|
40
|
+
* @param fileName - Original file name (e.g., 'guide.md')
|
|
41
|
+
* @returns Flat file name (e.g., 'canard-schemaForm_guide.md')
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* toFlatFileName('canard-schemaForm', 'guide.md') // 'canard-schemaForm_guide.md'
|
|
46
|
+
* toFlatFileName('winglet-reactUtils', 'README.md') // 'winglet-reactUtils_README.md'
|
|
47
|
+
* toFlatFileName('lerx-promiseModal', 'api/types.md') // 'lerx-promiseModal_api_types.md'
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function toFlatFileName(prefix: string, fileName: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* Parses a flat file name back into prefix and original file name
|
|
53
|
+
* Returns null if the file name doesn't match the expected pattern
|
|
54
|
+
*
|
|
55
|
+
* @param flatName - Flat file name (e.g., 'canard-schemaForm_guide.md')
|
|
56
|
+
* @returns Object with prefix and original name, or null if invalid
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* parseFlatFileName('canard-schemaForm_guide.md')
|
|
61
|
+
* // { prefix: 'canard-schemaForm', original: 'guide.md' }
|
|
62
|
+
*
|
|
63
|
+
* parseFlatFileName('winglet-reactUtils_README.md')
|
|
64
|
+
* // { prefix: 'winglet-reactUtils', original: 'README.md' }
|
|
65
|
+
*
|
|
66
|
+
* parseFlatFileName('lerx-promiseModal_api_types.md')
|
|
67
|
+
* // { prefix: 'lerx-promiseModal', original: 'api/types.md' }
|
|
68
|
+
*
|
|
69
|
+
* parseFlatFileName('invalid-name.md')
|
|
70
|
+
* // null (no underscore separator)
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseFlatFileName(flatName: string): {
|
|
74
|
+
prefix: string;
|
|
75
|
+
original: string;
|
|
76
|
+
} | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { packageNameToPrefix as packageNameToPrefix$1 } from './packageName.mjs';
|
|
2
|
+
|
|
3
|
+
const packageNameToPrefix = packageNameToPrefix$1;
|
|
4
|
+
function toFlatFileName(prefix, fileName) {
|
|
5
|
+
const flatFileName = fileName.replace(/[/\\]/g, '_');
|
|
6
|
+
return `${prefix}_${flatFileName}`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { packageNameToPrefix, toFlatFileName };
|
package/dist/utils/package.cjs
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_child_process = require('node:child_process');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var fs = require('node:fs');
|
|
5
|
+
var path = require('node:path');
|
|
6
|
+
var constants = require('../core/constants.cjs');
|
|
6
7
|
|
|
7
|
-
const GITHUB_HTTPS_URL_PATTERN = /https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
8
|
-
const GITHUB_SSH_URL_PATTERN = /git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
9
|
-
const GITHUB_SHORTHAND_PATTERN = /^github:([^/]+)\/([^/]+)$/;
|
|
10
8
|
const readPackageJson = (packageName, cwd = process.cwd()) => {
|
|
11
9
|
try {
|
|
12
|
-
const packageJsonPath =
|
|
13
|
-
const content =
|
|
10
|
+
const packageJsonPath = path.join(cwd, 'node_modules', packageName, 'package.json');
|
|
11
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
14
12
|
const json = JSON.parse(content);
|
|
15
13
|
if (!json.name || !json.version || !json.repository)
|
|
16
14
|
return null;
|
|
@@ -29,21 +27,21 @@ const parseGitHubRepo = (repository) => {
|
|
|
29
27
|
if (!repository || typeof repository.url !== 'string')
|
|
30
28
|
return null;
|
|
31
29
|
const url = repository.url;
|
|
32
|
-
const httpsMatch = url.match(
|
|
30
|
+
const httpsMatch = url.match(constants.FS_PATTERNS.GITHUB_HTTPS_URL);
|
|
33
31
|
if (httpsMatch)
|
|
34
32
|
return {
|
|
35
33
|
owner: httpsMatch[1],
|
|
36
34
|
repo: httpsMatch[2],
|
|
37
35
|
directory: repository.directory,
|
|
38
36
|
};
|
|
39
|
-
const sshMatch = url.match(
|
|
37
|
+
const sshMatch = url.match(constants.FS_PATTERNS.GITHUB_SSH_URL);
|
|
40
38
|
if (sshMatch)
|
|
41
39
|
return {
|
|
42
40
|
owner: sshMatch[1],
|
|
43
41
|
repo: sshMatch[2],
|
|
44
42
|
directory: repository.directory,
|
|
45
43
|
};
|
|
46
|
-
const shorthandMatch = url.match(
|
|
44
|
+
const shorthandMatch = url.match(constants.FS_PATTERNS.GITHUB_SHORTHAND);
|
|
47
45
|
if (shorthandMatch)
|
|
48
46
|
return {
|
|
49
47
|
owner: shorthandMatch[1],
|
|
@@ -70,10 +68,10 @@ const findGitRoot = (cwd = process.cwd()) => {
|
|
|
70
68
|
const findWorkspaceRoot = (startDir = process.cwd()) => {
|
|
71
69
|
let currentDir = startDir;
|
|
72
70
|
while (currentDir !== '/') {
|
|
73
|
-
const packageJsonPath =
|
|
74
|
-
if (
|
|
71
|
+
const packageJsonPath = path.join(currentDir, 'package.json');
|
|
72
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
75
73
|
try {
|
|
76
|
-
const content =
|
|
74
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
77
75
|
const json = JSON.parse(content);
|
|
78
76
|
if (json.workspaces)
|
|
79
77
|
return currentDir;
|
|
@@ -81,7 +79,7 @@ const findWorkspaceRoot = (startDir = process.cwd()) => {
|
|
|
81
79
|
catch {
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
|
-
currentDir =
|
|
82
|
+
currentDir = path.dirname(currentDir);
|
|
85
83
|
}
|
|
86
84
|
return null;
|
|
87
85
|
};
|
|
@@ -105,7 +103,7 @@ const getWorkspaceList = (workspaceRoot) => {
|
|
|
105
103
|
const findWorkspaceLocation = (packageName, workspaceRoot) => {
|
|
106
104
|
const workspaces = getWorkspaceList(workspaceRoot);
|
|
107
105
|
const workspace = workspaces.find((ws) => ws.name === packageName);
|
|
108
|
-
return workspace ?
|
|
106
|
+
return workspace ? path.join(workspaceRoot, workspace.location) : null;
|
|
109
107
|
};
|
|
110
108
|
const readLocalPackageJson = (packageName, cwd = process.cwd()) => {
|
|
111
109
|
try {
|
|
@@ -115,8 +113,8 @@ const readLocalPackageJson = (packageName, cwd = process.cwd()) => {
|
|
|
115
113
|
const packageLocation = findWorkspaceLocation(packageName, workspaceRoot);
|
|
116
114
|
if (!packageLocation)
|
|
117
115
|
return null;
|
|
118
|
-
const packageJsonPath =
|
|
119
|
-
const content =
|
|
116
|
+
const packageJsonPath = path.join(packageLocation, 'package.json');
|
|
117
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
120
118
|
const json = JSON.parse(content);
|
|
121
119
|
if (!json.name || !json.version || !json.repository)
|
|
122
120
|
return null;
|
|
@@ -131,12 +129,19 @@ const readLocalPackageJson = (packageName, cwd = process.cwd()) => {
|
|
|
131
129
|
return null;
|
|
132
130
|
}
|
|
133
131
|
};
|
|
132
|
+
function getAssetTypes(config) {
|
|
133
|
+
if (!config.assets) {
|
|
134
|
+
return Array.from(constants.DEFAULT_ASSET_TYPES);
|
|
135
|
+
}
|
|
136
|
+
return Object.keys(config.assets);
|
|
137
|
+
}
|
|
134
138
|
|
|
135
139
|
exports.buildAssetPath = buildAssetPath;
|
|
136
140
|
exports.buildVersionTag = buildVersionTag;
|
|
137
141
|
exports.findGitRoot = findGitRoot;
|
|
138
142
|
exports.findWorkspaceLocation = findWorkspaceLocation;
|
|
139
143
|
exports.findWorkspaceRoot = findWorkspaceRoot;
|
|
144
|
+
exports.getAssetTypes = getAssetTypes;
|
|
140
145
|
exports.getWorkspaceList = getWorkspaceList;
|
|
141
146
|
exports.parseGitHubRepo = parseGitHubRepo;
|
|
142
147
|
exports.readLocalPackageJson = readLocalPackageJson;
|
package/dist/utils/package.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GitHubRepoInfo, PackageInfo, WorkspaceInfo } from './types';
|
|
2
|
+
export { getAssetStructure } from '../core/assetStructure';
|
|
2
3
|
/**
|
|
3
4
|
* Read package.json from node_modules
|
|
4
5
|
* @param packageName - Package name (e.g., "@canard/schema-form")
|
|
@@ -64,3 +65,27 @@ export declare const findWorkspaceLocation: (packageName: string, workspaceRoot:
|
|
|
64
65
|
* @returns PackageInfo or null if not found
|
|
65
66
|
*/
|
|
66
67
|
export declare const readLocalPackageJson: (packageName: string, cwd?: string) => PackageInfo | null;
|
|
68
|
+
/**
|
|
69
|
+
* Parse assets configuration from package.json with defaults
|
|
70
|
+
* @param config - ClaudeConfig from package.json
|
|
71
|
+
* @returns Normalized AssetsConfig with defaults
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseAssetsConfig(config: {
|
|
74
|
+
assetPath: string;
|
|
75
|
+
assets?: Record<string, {
|
|
76
|
+
structure: 'nested' | 'flat';
|
|
77
|
+
}>;
|
|
78
|
+
}): Record<string, {
|
|
79
|
+
structure: 'nested' | 'flat';
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Get list of asset types to sync from configuration
|
|
83
|
+
* @param config - ClaudeConfig from package.json
|
|
84
|
+
* @returns Array of asset type names
|
|
85
|
+
*/
|
|
86
|
+
export declare function getAssetTypes(config: {
|
|
87
|
+
assetPath: string;
|
|
88
|
+
assets?: Record<string, {
|
|
89
|
+
structure: 'nested' | 'flat';
|
|
90
|
+
}>;
|
|
91
|
+
}): string[];
|
package/dist/utils/package.mjs
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import { readFileSync, existsSync } from 'node:fs';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
|
+
import { FS_PATTERNS, DEFAULT_ASSET_TYPES } from '../core/constants.mjs';
|
|
4
5
|
|
|
5
|
-
const GITHUB_HTTPS_URL_PATTERN = /https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
6
|
-
const GITHUB_SSH_URL_PATTERN = /git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
7
|
-
const GITHUB_SHORTHAND_PATTERN = /^github:([^/]+)\/([^/]+)$/;
|
|
8
6
|
const readPackageJson = (packageName, cwd = process.cwd()) => {
|
|
9
7
|
try {
|
|
10
8
|
const packageJsonPath = join(cwd, 'node_modules', packageName, 'package.json');
|
|
@@ -27,21 +25,21 @@ const parseGitHubRepo = (repository) => {
|
|
|
27
25
|
if (!repository || typeof repository.url !== 'string')
|
|
28
26
|
return null;
|
|
29
27
|
const url = repository.url;
|
|
30
|
-
const httpsMatch = url.match(
|
|
28
|
+
const httpsMatch = url.match(FS_PATTERNS.GITHUB_HTTPS_URL);
|
|
31
29
|
if (httpsMatch)
|
|
32
30
|
return {
|
|
33
31
|
owner: httpsMatch[1],
|
|
34
32
|
repo: httpsMatch[2],
|
|
35
33
|
directory: repository.directory,
|
|
36
34
|
};
|
|
37
|
-
const sshMatch = url.match(
|
|
35
|
+
const sshMatch = url.match(FS_PATTERNS.GITHUB_SSH_URL);
|
|
38
36
|
if (sshMatch)
|
|
39
37
|
return {
|
|
40
38
|
owner: sshMatch[1],
|
|
41
39
|
repo: sshMatch[2],
|
|
42
40
|
directory: repository.directory,
|
|
43
41
|
};
|
|
44
|
-
const shorthandMatch = url.match(
|
|
42
|
+
const shorthandMatch = url.match(FS_PATTERNS.GITHUB_SHORTHAND);
|
|
45
43
|
if (shorthandMatch)
|
|
46
44
|
return {
|
|
47
45
|
owner: shorthandMatch[1],
|
|
@@ -129,5 +127,11 @@ const readLocalPackageJson = (packageName, cwd = process.cwd()) => {
|
|
|
129
127
|
return null;
|
|
130
128
|
}
|
|
131
129
|
};
|
|
130
|
+
function getAssetTypes(config) {
|
|
131
|
+
if (!config.assets) {
|
|
132
|
+
return Array.from(DEFAULT_ASSET_TYPES);
|
|
133
|
+
}
|
|
134
|
+
return Object.keys(config.assets);
|
|
135
|
+
}
|
|
132
136
|
|
|
133
|
-
export { buildAssetPath, buildVersionTag, findGitRoot, findWorkspaceLocation, findWorkspaceRoot, getWorkspaceList, parseGitHubRepo, readLocalPackageJson, readPackageJson };
|
|
137
|
+
export { buildAssetPath, buildVersionTag, findGitRoot, findWorkspaceLocation, findWorkspaceRoot, getAssetTypes, getWorkspaceList, parseGitHubRepo, readLocalPackageJson, readPackageJson };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function parsePackageName(packageName) {
|
|
4
|
+
if (packageName.startsWith('@')) {
|
|
5
|
+
const [scope, name] = packageName.split('/');
|
|
6
|
+
return [scope, name];
|
|
7
|
+
}
|
|
8
|
+
return ['', packageName];
|
|
9
|
+
}
|
|
10
|
+
function kebabToCamel(str) {
|
|
11
|
+
return str.replace(/-./g, (match) => match[1].toUpperCase());
|
|
12
|
+
}
|
|
13
|
+
function packageNameToPrefix(packageName) {
|
|
14
|
+
const [scope, name] = parsePackageName(packageName);
|
|
15
|
+
if (!scope) {
|
|
16
|
+
return kebabToCamel(name);
|
|
17
|
+
}
|
|
18
|
+
const scopeWithoutAt = scope.replace('@', '');
|
|
19
|
+
const camelName = kebabToCamel(name);
|
|
20
|
+
return `${scopeWithoutAt}-${camelName}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.packageNameToPrefix = packageNameToPrefix;
|
|
24
|
+
exports.parsePackageName = parsePackageName;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse scoped package name into scope and name
|
|
3
|
+
* @param packageName - Package name (e.g., "@canard/schema-form")
|
|
4
|
+
* @returns [scope, name] tuple (e.g., ["@canard", "schema-form"])
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* parsePackageName('@canard/schema-form') // ['@canard', 'schema-form']
|
|
8
|
+
* parsePackageName('lodash') // ['', 'lodash']
|
|
9
|
+
*/
|
|
10
|
+
export declare function parsePackageName(packageName: string): [string, string];
|
|
11
|
+
/**
|
|
12
|
+
* Converts a scoped package name to a flat prefix
|
|
13
|
+
* @param packageName - Scoped package name (e.g., '@canard/schema-form')
|
|
14
|
+
* @returns Flat prefix (e.g., 'canard-schemaForm')
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* packageNameToPrefix('@canard/schema-form') // 'canard-schemaForm'
|
|
18
|
+
* packageNameToPrefix('@winglet/react-utils') // 'winglet-reactUtils'
|
|
19
|
+
* packageNameToPrefix('lodash') // 'lodash'
|
|
20
|
+
*/
|
|
21
|
+
export declare function packageNameToPrefix(packageName: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Converts a flat prefix back to package name
|
|
24
|
+
* @param prefix - Flat prefix (e.g., 'canard-schemaForm')
|
|
25
|
+
* @returns Package name (e.g., '@canard/schema-form')
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* prefixToPackageName('canard-schemaForm') // '@canard/schema-form'
|
|
29
|
+
* prefixToPackageName('winglet-reactUtils') // '@winglet/react-utils'
|
|
30
|
+
* prefixToPackageName('lodash') // 'lodash'
|
|
31
|
+
*/
|
|
32
|
+
export declare function prefixToPackageName(prefix: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function parsePackageName(packageName) {
|
|
2
|
+
if (packageName.startsWith('@')) {
|
|
3
|
+
const [scope, name] = packageName.split('/');
|
|
4
|
+
return [scope, name];
|
|
5
|
+
}
|
|
6
|
+
return ['', packageName];
|
|
7
|
+
}
|
|
8
|
+
function kebabToCamel(str) {
|
|
9
|
+
return str.replace(/-./g, (match) => match[1].toUpperCase());
|
|
10
|
+
}
|
|
11
|
+
function packageNameToPrefix(packageName) {
|
|
12
|
+
const [scope, name] = parsePackageName(packageName);
|
|
13
|
+
if (!scope) {
|
|
14
|
+
return kebabToCamel(name);
|
|
15
|
+
}
|
|
16
|
+
const scopeWithoutAt = scope.replace('@', '');
|
|
17
|
+
const camelName = kebabToCamel(name);
|
|
18
|
+
return `${scopeWithoutAt}-${camelName}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { packageNameToPrefix, parsePackageName };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var path = require('node:path');
|
|
4
|
+
var constants = require('../core/constants.cjs');
|
|
5
|
+
var packageName = require('./packageName.cjs');
|
|
6
|
+
|
|
7
|
+
function getDestinationDir(cwd, packageName$1, assetType) {
|
|
8
|
+
const [scope, name] = packageName.parsePackageName(packageName$1);
|
|
9
|
+
if (scope)
|
|
10
|
+
return path.join(cwd, constants.CLAUDE_BASE_DIR, assetType, scope, name);
|
|
11
|
+
return path.join(cwd, constants.CLAUDE_BASE_DIR, assetType, name);
|
|
12
|
+
}
|
|
13
|
+
function getFlatDestinationDir(cwd, assetType) {
|
|
14
|
+
return path.join(cwd, constants.CLAUDE_BASE_DIR, assetType);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.getDestinationDir = getDestinationDir;
|
|
18
|
+
exports.getFlatDestinationDir = getFlatDestinationDir;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AssetType } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Get the destination directory for synced assets (nested structure)
|
|
4
|
+
* @param cwd - Current working directory
|
|
5
|
+
* @param packageName - Package name
|
|
6
|
+
* @param assetType - Asset type (commands or skills)
|
|
7
|
+
* @returns Full path to destination directory
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* getDestinationDir('/project', '@canard/schema-form', 'commands')
|
|
11
|
+
* // => '/project/.claude/commands/@canard/schema-form'
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDestinationDir(cwd: string, packageName: string, assetType: AssetType): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the flat destination directory for synced assets (no nesting)
|
|
16
|
+
* @param cwd - Current working directory
|
|
17
|
+
* @param assetType - Asset type (commands or skills)
|
|
18
|
+
* @returns Full path to flat destination directory
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* getFlatDestinationDir('/project', 'commands')
|
|
22
|
+
* // => '/project/.claude/commands'
|
|
23
|
+
*/
|
|
24
|
+
export declare function getFlatDestinationDir(cwd: string, assetType: AssetType): string;
|
|
25
|
+
/**
|
|
26
|
+
* Get the path to sync metadata file for nested structure
|
|
27
|
+
* @param cwd - Current working directory
|
|
28
|
+
* @param packageName - Package name
|
|
29
|
+
* @param assetType - Asset type
|
|
30
|
+
* @returns Full path to .sync-meta.json
|
|
31
|
+
*/
|
|
32
|
+
export declare function getMetaFilePath(cwd: string, packageName: string, assetType: AssetType): string;
|
|
33
|
+
/**
|
|
34
|
+
* Get the path to unified sync metadata file
|
|
35
|
+
* @param cwd - Current working directory
|
|
36
|
+
* @returns Full path to .claude/.sync-meta.json
|
|
37
|
+
*/
|
|
38
|
+
export declare function getUnifiedMetaFilePath(cwd: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Get the path to an asset file in nested structure
|
|
41
|
+
* @param cwd - Current working directory
|
|
42
|
+
* @param packageName - Package name
|
|
43
|
+
* @param assetType - Asset type
|
|
44
|
+
* @param fileName - File name
|
|
45
|
+
* @returns Full path to asset file
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAssetFilePath(cwd: string, packageName: string, assetType: AssetType, fileName: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Get the path to an asset file in flat structure
|
|
50
|
+
* @param cwd - Current working directory
|
|
51
|
+
* @param assetType - Asset type
|
|
52
|
+
* @param flatFileName - Flat file name with prefix
|
|
53
|
+
* @returns Full path to flat asset file
|
|
54
|
+
*/
|
|
55
|
+
export declare function getFlatAssetFilePath(cwd: string, assetType: AssetType, flatFileName: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { CLAUDE_BASE_DIR } from '../core/constants.mjs';
|
|
3
|
+
import { parsePackageName } from './packageName.mjs';
|
|
4
|
+
|
|
5
|
+
function getDestinationDir(cwd, packageName, assetType) {
|
|
6
|
+
const [scope, name] = parsePackageName(packageName);
|
|
7
|
+
if (scope)
|
|
8
|
+
return join(cwd, CLAUDE_BASE_DIR, assetType, scope, name);
|
|
9
|
+
return join(cwd, CLAUDE_BASE_DIR, assetType, name);
|
|
10
|
+
}
|
|
11
|
+
function getFlatDestinationDir(cwd, assetType) {
|
|
12
|
+
return join(cwd, CLAUDE_BASE_DIR, assetType);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { getDestinationDir, getFlatDestinationDir };
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset structure type (nested or flat)
|
|
3
|
+
*/
|
|
4
|
+
export type AssetStructure = 'nested' | 'flat';
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for a specific asset type
|
|
7
|
+
*/
|
|
8
|
+
export interface AssetTypeConfig {
|
|
9
|
+
structure: AssetStructure;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Configuration mapping asset types to their structure
|
|
13
|
+
*/
|
|
14
|
+
export interface AssetsConfig {
|
|
15
|
+
[assetType: string]: AssetTypeConfig;
|
|
16
|
+
}
|
|
1
17
|
/**
|
|
2
18
|
* Claude configuration in package.json
|
|
3
19
|
*/
|
|
4
20
|
export interface ClaudeConfig {
|
|
5
21
|
/** Path to Claude assets directory (e.g., "docs/claude") */
|
|
6
22
|
assetPath: string;
|
|
23
|
+
/** Optional configuration for asset types */
|
|
24
|
+
assets?: AssetsConfig;
|
|
7
25
|
}
|
|
8
26
|
/**
|
|
9
27
|
* Repository information from package.json
|
|
@@ -52,9 +70,9 @@ export interface SyncMeta {
|
|
|
52
70
|
files: string[];
|
|
53
71
|
}
|
|
54
72
|
/**
|
|
55
|
-
* Asset type (
|
|
73
|
+
* Asset type (can be any string, not limited to commands/skills/agents)
|
|
56
74
|
*/
|
|
57
|
-
export type AssetType =
|
|
75
|
+
export type AssetType = string;
|
|
58
76
|
/**
|
|
59
77
|
* Sync result for a single package
|
|
60
78
|
*/
|
|
@@ -63,10 +81,7 @@ export interface SyncResult {
|
|
|
63
81
|
success: boolean;
|
|
64
82
|
skipped: boolean;
|
|
65
83
|
reason?: string;
|
|
66
|
-
syncedFiles?:
|
|
67
|
-
commands: string[];
|
|
68
|
-
skills: string[];
|
|
69
|
-
};
|
|
84
|
+
syncedFiles?: Record<string, string[]>;
|
|
70
85
|
}
|
|
71
86
|
/**
|
|
72
87
|
* CLI options
|
|
@@ -78,6 +93,8 @@ export interface CliOptions {
|
|
|
78
93
|
local: boolean;
|
|
79
94
|
/** Custom git ref (branch, tag, or commit) to fetch from */
|
|
80
95
|
ref?: string;
|
|
96
|
+
/** Use flat structure (default: true in v2) */
|
|
97
|
+
flat?: boolean;
|
|
81
98
|
}
|
|
82
99
|
/**
|
|
83
100
|
* Workspace info from yarn workspaces
|
|
@@ -86,3 +103,133 @@ export interface WorkspaceInfo {
|
|
|
86
103
|
name: string;
|
|
87
104
|
location: string;
|
|
88
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Unified sync metadata for all packages (flat structure)
|
|
108
|
+
*/
|
|
109
|
+
export interface UnifiedSyncMeta {
|
|
110
|
+
/** Schema version for migration support */
|
|
111
|
+
schemaVersion: string;
|
|
112
|
+
/** Last sync timestamp */
|
|
113
|
+
syncedAt: string;
|
|
114
|
+
/** Package metadata keyed by transformed name (e.g., "canard-schemaForm") */
|
|
115
|
+
packages: Record<string, PackageSyncInfo>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Individual package sync info within unified meta
|
|
119
|
+
*/
|
|
120
|
+
export interface PackageSyncInfo {
|
|
121
|
+
/** Original package name (e.g., "@canard/schema-form") */
|
|
122
|
+
originalName: string;
|
|
123
|
+
/** Package version at sync time */
|
|
124
|
+
version: string;
|
|
125
|
+
/** Whether this package is from local workspace (true) or remote npm (false/undefined) */
|
|
126
|
+
local?: boolean;
|
|
127
|
+
/** Synced files - dynamic structure based on asset configuration:
|
|
128
|
+
* - For nested structure: array of original filenames
|
|
129
|
+
* - For flat structure: array of FileMapping with original → transformed
|
|
130
|
+
*/
|
|
131
|
+
files: Record<string, string[] | FileMapping[]>;
|
|
132
|
+
/** Optional exclusions for selective syncing */
|
|
133
|
+
exclusions?: {
|
|
134
|
+
/** Excluded directory paths (e.g., ["skills/deprecated"]) */
|
|
135
|
+
directories: string[];
|
|
136
|
+
/** Excluded file paths (e.g., ["commands/old-cmd.md"]) */
|
|
137
|
+
files: string[];
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* File name mapping (original to transformed)
|
|
142
|
+
*/
|
|
143
|
+
export interface FileMapping {
|
|
144
|
+
/** Original file name (e.g., "guide.md") */
|
|
145
|
+
original: string;
|
|
146
|
+
/** Transformed file name (e.g., "canard-schemaForm_guide.md") */
|
|
147
|
+
transformed: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Add command selection result
|
|
151
|
+
*/
|
|
152
|
+
export interface AddCommandSelection {
|
|
153
|
+
/** Package name */
|
|
154
|
+
packageName: string;
|
|
155
|
+
/** Source type */
|
|
156
|
+
source: 'local' | 'npm';
|
|
157
|
+
/** Git ref (branch, tag, or commit) */
|
|
158
|
+
ref?: string;
|
|
159
|
+
/** Included assets by type */
|
|
160
|
+
includedAssets: Record<string, string[]>;
|
|
161
|
+
/** Excluded assets by type */
|
|
162
|
+
excludedAssets: Record<string, string[]>;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Tree node for asset selection
|
|
166
|
+
*/
|
|
167
|
+
export interface TreeNode {
|
|
168
|
+
/** Unique identifier */
|
|
169
|
+
id: string;
|
|
170
|
+
/** Node label */
|
|
171
|
+
label: string;
|
|
172
|
+
/** Full path */
|
|
173
|
+
path: string;
|
|
174
|
+
/** Node type */
|
|
175
|
+
type: 'directory' | 'file' | 'skill-directory';
|
|
176
|
+
/** Child nodes */
|
|
177
|
+
children?: TreeNode[];
|
|
178
|
+
/** Selection state */
|
|
179
|
+
selected: boolean;
|
|
180
|
+
/** Expanded state */
|
|
181
|
+
expanded: boolean;
|
|
182
|
+
/** Disabled state */
|
|
183
|
+
disabled?: boolean;
|
|
184
|
+
/** Additional metadata */
|
|
185
|
+
metadata?: {
|
|
186
|
+
assetType: string;
|
|
187
|
+
originalName?: string;
|
|
188
|
+
transformedName?: string;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Re-export asset structure utilities from core module
|
|
193
|
+
*
|
|
194
|
+
* @deprecated These exports are kept for backward compatibility only.
|
|
195
|
+
* Please update your imports to use the recommended paths below.
|
|
196
|
+
*
|
|
197
|
+
* Migration Guide:
|
|
198
|
+
* ================
|
|
199
|
+
*
|
|
200
|
+
* ❌ OLD (Deprecated - will be removed in v1.0.0)
|
|
201
|
+
* ```typescript
|
|
202
|
+
* import {
|
|
203
|
+
* DEFAULT_ASSET_TYPES,
|
|
204
|
+
* DEFAULT_ASSET_STRUCTURES,
|
|
205
|
+
* getAssetStructure,
|
|
206
|
+
* detectStructureType,
|
|
207
|
+
* validateAssetStructure,
|
|
208
|
+
* normalizeAssetStructure,
|
|
209
|
+
* } from './utils/types';
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* ✅ NEW (Recommended)
|
|
213
|
+
* ```typescript
|
|
214
|
+
* import {
|
|
215
|
+
* DEFAULT_ASSET_TYPES,
|
|
216
|
+
* DEFAULT_ASSET_STRUCTURES,
|
|
217
|
+
* getAssetStructure,
|
|
218
|
+
* detectStructureType,
|
|
219
|
+
* validateAssetStructure,
|
|
220
|
+
* normalizeAssetStructure,
|
|
221
|
+
* } from './core/assetStructure';
|
|
222
|
+
* ```
|
|
223
|
+
*
|
|
224
|
+
* Why the change?
|
|
225
|
+
* - Clearer module organization (asset structure logic lives in core/)
|
|
226
|
+
* - Direct imports are more maintainable and tree-shake friendly
|
|
227
|
+
* - Reduces coupling between utils and core modules
|
|
228
|
+
*
|
|
229
|
+
* Timeline:
|
|
230
|
+
* - v0.x: Old imports work (with deprecation warnings)
|
|
231
|
+
* - v1.0.0: Re-exports removed
|
|
232
|
+
*
|
|
233
|
+
* @see ../core/assetStructure for the actual implementations
|
|
234
|
+
*/
|
|
235
|
+
export { DEFAULT_ASSET_TYPES, DEFAULT_ASSET_STRUCTURES, getAssetStructure, detectStructureType, validateAssetStructure, normalizeAssetStructure, } from '../core/assetStructure';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function compareVersions(v1, v2) {
|
|
4
|
+
return v1 === v2;
|
|
5
|
+
}
|
|
6
|
+
function needsVersionSync(currentVersion, syncedVersion) {
|
|
7
|
+
if (syncedVersion === undefined) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (currentVersion === '' || syncedVersion === '') {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return !compareVersions(currentVersion, syncedVersion);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.compareVersions = compareVersions;
|
|
17
|
+
exports.needsVersionSync = needsVersionSync;
|