@slats/claude-assets-sync 0.0.5 → 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/core/constants.d.ts +1 -1
- 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/packageScanner.cjs +18 -1
- package/dist/core/packageScanner.mjs +18 -1
- package/dist/core/sync.cjs +65 -16
- package/dist/core/sync.mjs +66 -17
- package/dist/core/syncMeta.d.ts +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +1 -1
package/dist/core/constants.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ 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
27
|
readonly SKILL_UNIT_FORMAT: "2";
|
|
28
28
|
};
|
|
@@ -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 };
|
|
@@ -65,6 +65,24 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
65
65
|
if (!pkgInfo || !pkgInfo.claude?.assetPath) {
|
|
66
66
|
throw new Error(`Package ${packageName} has no claude.assetPath configured`);
|
|
67
67
|
}
|
|
68
|
+
const assetBasePath = pkgInfo.claude.assetPath;
|
|
69
|
+
if (!ref) {
|
|
70
|
+
const localDocsPath = path.join(nodeModulesPath, assetBasePath);
|
|
71
|
+
if (fs.existsSync(localDocsPath)) {
|
|
72
|
+
const trees = [];
|
|
73
|
+
for (const assetType of constants.DEFAULT_ASSET_TYPES) {
|
|
74
|
+
const assetDir = path.join(localDocsPath, assetType);
|
|
75
|
+
if (!fs.existsSync(assetDir))
|
|
76
|
+
continue;
|
|
77
|
+
const tree = buildTreeFromLocalDir(assetType, assetDir, assetType);
|
|
78
|
+
if (tree.children && tree.children.length > 0) {
|
|
79
|
+
trees.push(tree);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (trees.length > 0)
|
|
83
|
+
return trees;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
68
86
|
if (!pkgInfo.repository) {
|
|
69
87
|
throw new Error(`Package ${packageName} has no repository field`);
|
|
70
88
|
}
|
|
@@ -72,7 +90,6 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
72
90
|
if (!repoInfo) {
|
|
73
91
|
throw new Error(`Invalid GitHub repository URL in package ${packageName}`);
|
|
74
92
|
}
|
|
75
|
-
const assetBasePath = pkgInfo.claude.assetPath;
|
|
76
93
|
const tag = ref ?? 'HEAD';
|
|
77
94
|
const trees = [];
|
|
78
95
|
for (const assetType of constants.DEFAULT_ASSET_TYPES) {
|
|
@@ -63,6 +63,24 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
63
63
|
if (!pkgInfo || !pkgInfo.claude?.assetPath) {
|
|
64
64
|
throw new Error(`Package ${packageName} has no claude.assetPath configured`);
|
|
65
65
|
}
|
|
66
|
+
const assetBasePath = pkgInfo.claude.assetPath;
|
|
67
|
+
if (!ref) {
|
|
68
|
+
const localDocsPath = join(nodeModulesPath, assetBasePath);
|
|
69
|
+
if (existsSync(localDocsPath)) {
|
|
70
|
+
const trees = [];
|
|
71
|
+
for (const assetType of DEFAULT_ASSET_TYPES) {
|
|
72
|
+
const assetDir = join(localDocsPath, assetType);
|
|
73
|
+
if (!existsSync(assetDir))
|
|
74
|
+
continue;
|
|
75
|
+
const tree = buildTreeFromLocalDir(assetType, assetDir, assetType);
|
|
76
|
+
if (tree.children && tree.children.length > 0) {
|
|
77
|
+
trees.push(tree);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (trees.length > 0)
|
|
81
|
+
return trees;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
66
84
|
if (!pkgInfo.repository) {
|
|
67
85
|
throw new Error(`Package ${packageName} has no repository field`);
|
|
68
86
|
}
|
|
@@ -70,7 +88,6 @@ async function scanRemoteAssets(packageName, ref) {
|
|
|
70
88
|
if (!repoInfo) {
|
|
71
89
|
throw new Error(`Invalid GitHub repository URL in package ${packageName}`);
|
|
72
90
|
}
|
|
73
|
-
const assetBasePath = pkgInfo.claude.assetPath;
|
|
74
91
|
const tag = ref ?? 'HEAD';
|
|
75
92
|
const trees = [];
|
|
76
93
|
for (const assetType of DEFAULT_ASSET_TYPES) {
|
package/dist/core/sync.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var packageName = require('../utils/packageName.cjs');
|
|
|
7
7
|
var paths = require('../utils/paths.cjs');
|
|
8
8
|
var filesystem = require('./filesystem.cjs');
|
|
9
9
|
var github = require('./github.cjs');
|
|
10
|
+
var localSource = require('./localSource.cjs');
|
|
10
11
|
var syncMeta = require('./syncMeta.cjs');
|
|
11
12
|
var constants = require('./constants.cjs');
|
|
12
13
|
var assetStructure = require('./assetStructure.cjs');
|
|
@@ -67,14 +68,6 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
|
|
|
67
68
|
reason: 'Package does not have claude.assetPath in package.json',
|
|
68
69
|
};
|
|
69
70
|
const repoInfo = _package.parseGitHubRepo(packageInfo.repository);
|
|
70
|
-
if (!repoInfo) {
|
|
71
|
-
return {
|
|
72
|
-
packageName: packageName$1,
|
|
73
|
-
success: false,
|
|
74
|
-
skipped: true,
|
|
75
|
-
reason: 'Unable to parse GitHub repository URL',
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
71
|
const useFlat = options.flat !== false;
|
|
79
72
|
if (useFlat) {
|
|
80
73
|
const prefix = packageName.packageNameToPrefix(packageName$1);
|
|
@@ -88,11 +81,32 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
|
|
|
88
81
|
reason: `Already synced at version ${packageInfo.version}`,
|
|
89
82
|
};
|
|
90
83
|
}
|
|
91
|
-
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
92
84
|
const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
|
|
93
|
-
|
|
85
|
+
const useLocalSource = options.ref
|
|
86
|
+
? { available: false }
|
|
87
|
+
: localSource.canUseLocalSource(packageName$1, packageInfo.version, assetPath, cwd);
|
|
94
88
|
const assetTypes = _package.getAssetTypes(packageInfo.claude);
|
|
95
|
-
|
|
89
|
+
let assetFiles;
|
|
90
|
+
let isLocalSource;
|
|
91
|
+
if (useLocalSource.available && useLocalSource.docsPath) {
|
|
92
|
+
isLocalSource = true;
|
|
93
|
+
logger.logger.step('Using', 'local docs from node_modules');
|
|
94
|
+
assetFiles = await localSource.fetchLocalAssetFiles(useLocalSource.docsPath, assetTypes);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
if (!repoInfo) {
|
|
98
|
+
return {
|
|
99
|
+
packageName: packageName$1,
|
|
100
|
+
success: false,
|
|
101
|
+
skipped: true,
|
|
102
|
+
reason: `Package ${packageName$1} has no valid GitHub repository URL for remote fetch`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
isLocalSource = false;
|
|
106
|
+
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
107
|
+
logger.logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
|
|
108
|
+
assetFiles = await github.fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
|
|
109
|
+
}
|
|
96
110
|
let totalFiles = 0;
|
|
97
111
|
for (const assetType of assetTypes) {
|
|
98
112
|
totalFiles += (assetFiles[assetType] || []).length;
|
|
@@ -189,7 +203,14 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
|
|
|
189
203
|
continue;
|
|
190
204
|
const structure = assetStructure.getAssetStructure(assetType, packageInfo.claude);
|
|
191
205
|
logger.logger.step('Downloading', assetType);
|
|
192
|
-
|
|
206
|
+
let downloadedFiles;
|
|
207
|
+
if (isLocalSource && useLocalSource.docsPath) {
|
|
208
|
+
downloadedFiles = await localSource.downloadLocalAssetFiles(useLocalSource.docsPath, assetType, filteredEntries);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
212
|
+
downloadedFiles = await github.downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
|
|
213
|
+
}
|
|
193
214
|
if (structure === 'nested') {
|
|
194
215
|
for (const [fileName, content] of downloadedFiles) {
|
|
195
216
|
filesystem.writeAssetFile(destDir, packageName$1, assetType, fileName, content);
|
|
@@ -231,11 +252,32 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
|
|
|
231
252
|
};
|
|
232
253
|
}
|
|
233
254
|
else {
|
|
234
|
-
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
235
255
|
const assetPath = _package.buildAssetPath(packageInfo.claude.assetPath);
|
|
236
|
-
|
|
256
|
+
const useLocalSource = options.ref
|
|
257
|
+
? { available: false }
|
|
258
|
+
: localSource.canUseLocalSource(packageName$1, packageInfo.version, assetPath, cwd);
|
|
237
259
|
const assetTypes = _package.getAssetTypes(packageInfo.claude);
|
|
238
|
-
|
|
260
|
+
let assetFiles;
|
|
261
|
+
let isLocalSource;
|
|
262
|
+
if (useLocalSource.available && useLocalSource.docsPath) {
|
|
263
|
+
isLocalSource = true;
|
|
264
|
+
logger.logger.step('Using', 'local docs from node_modules');
|
|
265
|
+
assetFiles = await localSource.fetchLocalAssetFiles(useLocalSource.docsPath, assetTypes);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
if (!repoInfo) {
|
|
269
|
+
return {
|
|
270
|
+
packageName: packageName$1,
|
|
271
|
+
success: false,
|
|
272
|
+
skipped: true,
|
|
273
|
+
reason: `Package ${packageName$1} has no valid GitHub repository URL for remote fetch`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
isLocalSource = false;
|
|
277
|
+
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
278
|
+
logger.logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
|
|
279
|
+
assetFiles = await github.fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
|
|
280
|
+
}
|
|
239
281
|
let totalFiles = 0;
|
|
240
282
|
for (const assetType of assetTypes) {
|
|
241
283
|
totalFiles += (assetFiles[assetType] || []).length;
|
|
@@ -299,7 +341,14 @@ const syncPackage = async (packageName$1, options, cwd = process.cwd(), exclusio
|
|
|
299
341
|
if (filteredEntries.length === 0)
|
|
300
342
|
continue;
|
|
301
343
|
logger.logger.step('Downloading', assetType);
|
|
302
|
-
|
|
344
|
+
let downloadedFiles;
|
|
345
|
+
if (isLocalSource && useLocalSource.docsPath) {
|
|
346
|
+
downloadedFiles = await localSource.downloadLocalAssetFiles(useLocalSource.docsPath, assetType, filteredEntries);
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
const tag = options.ref ?? _package.buildVersionTag(packageName$1, packageInfo.version);
|
|
350
|
+
downloadedFiles = await github.downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
|
|
351
|
+
}
|
|
303
352
|
filesystem.cleanAssetDir(destDir, packageName$1, assetType);
|
|
304
353
|
syncedFiles[assetType] = [];
|
|
305
354
|
for (const [fileName, content] of downloadedFiles) {
|
package/dist/core/sync.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { logger } from '../utils/logger.mjs';
|
|
2
2
|
import { toFlatFileName } from '../utils/nameTransform.mjs';
|
|
3
|
-
import { findGitRoot, readLocalPackageJson, readPackageJson, parseGitHubRepo,
|
|
3
|
+
import { findGitRoot, readLocalPackageJson, readPackageJson, parseGitHubRepo, buildAssetPath, getAssetTypes, buildVersionTag } from '../utils/package.mjs';
|
|
4
4
|
import { packageNameToPrefix } from '../utils/packageName.mjs';
|
|
5
5
|
import { getDestinationDir, getFlatDestinationDir } from '../utils/paths.mjs';
|
|
6
6
|
import { cleanAssetDir, cleanFlatAssetFiles, writeAssetFile, writeFlatAssetFile, needsSync, writeSyncMeta, createSyncMeta } from './filesystem.mjs';
|
|
7
7
|
import { fetchAssetFiles, downloadAssetFiles, RateLimitError } from './github.mjs';
|
|
8
|
+
import { canUseLocalSource, fetchLocalAssetFiles, downloadLocalAssetFiles } from './localSource.mjs';
|
|
8
9
|
import { readUnifiedSyncMeta, createEmptyUnifiedMeta, needsSyncUnified, updatePackageInMeta, writeUnifiedSyncMeta } from './syncMeta.mjs';
|
|
9
10
|
import { SCHEMA_VERSIONS } from './constants.mjs';
|
|
10
11
|
import { getAssetStructure } from './assetStructure.mjs';
|
|
@@ -65,14 +66,6 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions
|
|
|
65
66
|
reason: 'Package does not have claude.assetPath in package.json',
|
|
66
67
|
};
|
|
67
68
|
const repoInfo = parseGitHubRepo(packageInfo.repository);
|
|
68
|
-
if (!repoInfo) {
|
|
69
|
-
return {
|
|
70
|
-
packageName,
|
|
71
|
-
success: false,
|
|
72
|
-
skipped: true,
|
|
73
|
-
reason: 'Unable to parse GitHub repository URL',
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
69
|
const useFlat = options.flat !== false;
|
|
77
70
|
if (useFlat) {
|
|
78
71
|
const prefix = packageNameToPrefix(packageName);
|
|
@@ -86,11 +79,32 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions
|
|
|
86
79
|
reason: `Already synced at version ${packageInfo.version}`,
|
|
87
80
|
};
|
|
88
81
|
}
|
|
89
|
-
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
90
82
|
const assetPath = buildAssetPath(packageInfo.claude.assetPath);
|
|
91
|
-
|
|
83
|
+
const useLocalSource = options.ref
|
|
84
|
+
? { available: false }
|
|
85
|
+
: canUseLocalSource(packageName, packageInfo.version, assetPath, cwd);
|
|
92
86
|
const assetTypes = getAssetTypes(packageInfo.claude);
|
|
93
|
-
|
|
87
|
+
let assetFiles;
|
|
88
|
+
let isLocalSource;
|
|
89
|
+
if (useLocalSource.available && useLocalSource.docsPath) {
|
|
90
|
+
isLocalSource = true;
|
|
91
|
+
logger.step('Using', 'local docs from node_modules');
|
|
92
|
+
assetFiles = await fetchLocalAssetFiles(useLocalSource.docsPath, assetTypes);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
if (!repoInfo) {
|
|
96
|
+
return {
|
|
97
|
+
packageName,
|
|
98
|
+
success: false,
|
|
99
|
+
skipped: true,
|
|
100
|
+
reason: `Package ${packageName} has no valid GitHub repository URL for remote fetch`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
isLocalSource = false;
|
|
104
|
+
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
105
|
+
logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
|
|
106
|
+
assetFiles = await fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
|
|
107
|
+
}
|
|
94
108
|
let totalFiles = 0;
|
|
95
109
|
for (const assetType of assetTypes) {
|
|
96
110
|
totalFiles += (assetFiles[assetType] || []).length;
|
|
@@ -187,7 +201,14 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions
|
|
|
187
201
|
continue;
|
|
188
202
|
const structure = getAssetStructure(assetType, packageInfo.claude);
|
|
189
203
|
logger.step('Downloading', assetType);
|
|
190
|
-
|
|
204
|
+
let downloadedFiles;
|
|
205
|
+
if (isLocalSource && useLocalSource.docsPath) {
|
|
206
|
+
downloadedFiles = await downloadLocalAssetFiles(useLocalSource.docsPath, assetType, filteredEntries);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
210
|
+
downloadedFiles = await downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
|
|
211
|
+
}
|
|
191
212
|
if (structure === 'nested') {
|
|
192
213
|
for (const [fileName, content] of downloadedFiles) {
|
|
193
214
|
writeAssetFile(destDir, packageName, assetType, fileName, content);
|
|
@@ -229,11 +250,32 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions
|
|
|
229
250
|
};
|
|
230
251
|
}
|
|
231
252
|
else {
|
|
232
|
-
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
233
253
|
const assetPath = buildAssetPath(packageInfo.claude.assetPath);
|
|
234
|
-
|
|
254
|
+
const useLocalSource = options.ref
|
|
255
|
+
? { available: false }
|
|
256
|
+
: canUseLocalSource(packageName, packageInfo.version, assetPath, cwd);
|
|
235
257
|
const assetTypes = getAssetTypes(packageInfo.claude);
|
|
236
|
-
|
|
258
|
+
let assetFiles;
|
|
259
|
+
let isLocalSource;
|
|
260
|
+
if (useLocalSource.available && useLocalSource.docsPath) {
|
|
261
|
+
isLocalSource = true;
|
|
262
|
+
logger.step('Using', 'local docs from node_modules');
|
|
263
|
+
assetFiles = await fetchLocalAssetFiles(useLocalSource.docsPath, assetTypes);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
if (!repoInfo) {
|
|
267
|
+
return {
|
|
268
|
+
packageName,
|
|
269
|
+
success: false,
|
|
270
|
+
skipped: true,
|
|
271
|
+
reason: `Package ${packageName} has no valid GitHub repository URL for remote fetch`,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
isLocalSource = false;
|
|
275
|
+
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
276
|
+
logger.step('Fetching', `asset list from GitHub (ref: ${tag})`);
|
|
277
|
+
assetFiles = await fetchAssetFiles(repoInfo, assetPath, tag, assetTypes);
|
|
278
|
+
}
|
|
237
279
|
let totalFiles = 0;
|
|
238
280
|
for (const assetType of assetTypes) {
|
|
239
281
|
totalFiles += (assetFiles[assetType] || []).length;
|
|
@@ -297,7 +339,14 @@ const syncPackage = async (packageName, options, cwd = process.cwd(), exclusions
|
|
|
297
339
|
if (filteredEntries.length === 0)
|
|
298
340
|
continue;
|
|
299
341
|
logger.step('Downloading', assetType);
|
|
300
|
-
|
|
342
|
+
let downloadedFiles;
|
|
343
|
+
if (isLocalSource && useLocalSource.docsPath) {
|
|
344
|
+
downloadedFiles = await downloadLocalAssetFiles(useLocalSource.docsPath, assetType, filteredEntries);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
const tag = options.ref ?? buildVersionTag(packageName, packageInfo.version);
|
|
348
|
+
downloadedFiles = await downloadAssetFiles(repoInfo, assetPath, assetType, filteredEntries, tag);
|
|
349
|
+
}
|
|
301
350
|
cleanAssetDir(destDir, packageName, assetType);
|
|
302
351
|
syncedFiles[assetType] = [];
|
|
303
352
|
for (const [fileName, content] of downloadedFiles) {
|
package/dist/core/syncMeta.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { PackageSyncInfo, SkillUnit, UnifiedSyncMeta } from '../utils/types
|
|
|
2
2
|
/**
|
|
3
3
|
* Schema version for the unified metadata format
|
|
4
4
|
*/
|
|
5
|
-
export declare const SCHEMA_VERSION: "0.0.
|
|
5
|
+
export declare const SCHEMA_VERSION: "0.0.6";
|
|
6
6
|
/**
|
|
7
7
|
* Read unified sync metadata from .claude/.sync-meta.json
|
|
8
8
|
*
|
package/dist/version.cjs
CHANGED
package/dist/version.d.ts
CHANGED
package/dist/version.mjs
CHANGED