@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.
Files changed (107) hide show
  1. package/CHANGELOG.md +189 -0
  2. package/README.md +541 -45
  3. package/dist/commands/add.cjs +61 -0
  4. package/dist/commands/add.d.ts +12 -0
  5. package/dist/commands/add.mjs +59 -0
  6. package/dist/commands/index.d.ts +91 -0
  7. package/dist/commands/list.cjs +83 -0
  8. package/dist/commands/list.d.ts +6 -0
  9. package/dist/commands/list.mjs +81 -0
  10. package/dist/commands/migrate.cjs +9 -0
  11. package/dist/commands/migrate.d.ts +6 -0
  12. package/dist/commands/migrate.mjs +7 -0
  13. package/dist/commands/remove.cjs +109 -0
  14. package/dist/commands/remove.d.ts +6 -0
  15. package/dist/commands/remove.mjs +86 -0
  16. package/dist/commands/status.cjs +193 -0
  17. package/dist/commands/status.d.ts +6 -0
  18. package/dist/commands/status.mjs +171 -0
  19. package/dist/commands/sync.cjs +28 -0
  20. package/dist/commands/sync.d.ts +6 -0
  21. package/dist/commands/sync.mjs +26 -0
  22. package/dist/commands/types.d.ts +82 -0
  23. package/dist/components/add/AddCommand.cjs +92 -0
  24. package/dist/components/add/AddCommand.d.ts +14 -0
  25. package/dist/components/add/AddCommand.mjs +90 -0
  26. package/dist/components/add/index.d.ts +2 -0
  27. package/dist/components/index.d.ts +2 -0
  28. package/dist/components/list/EditableTreeItem.d.ts +13 -0
  29. package/dist/components/list/ListCommand.cjs +440 -0
  30. package/dist/components/list/ListCommand.d.ts +8 -0
  31. package/dist/components/list/ListCommand.mjs +418 -0
  32. package/dist/components/list/SyncedPackageTree.d.ts +14 -0
  33. package/dist/components/list/index.d.ts +9 -0
  34. package/dist/components/primitives/Box.d.ts +4 -0
  35. package/dist/components/primitives/Spinner.d.ts +6 -0
  36. package/dist/components/primitives/Text.d.ts +4 -0
  37. package/dist/components/primitives/index.d.ts +3 -0
  38. package/dist/components/status/PackageStatusCard.d.ts +10 -0
  39. package/dist/components/status/StatusDisplay.cjs +25 -0
  40. package/dist/components/status/StatusDisplay.d.ts +25 -0
  41. package/dist/components/status/StatusDisplay.mjs +23 -0
  42. package/dist/components/status/StatusTreeNode.cjs +40 -0
  43. package/dist/components/status/StatusTreeNode.d.ts +15 -0
  44. package/dist/components/status/StatusTreeNode.mjs +38 -0
  45. package/dist/components/status/index.d.ts +6 -0
  46. package/dist/components/tree/AssetTreeNode.cjs +37 -0
  47. package/dist/components/tree/AssetTreeNode.d.ts +12 -0
  48. package/dist/components/tree/AssetTreeNode.mjs +35 -0
  49. package/dist/components/tree/TreeSelect.cjs +121 -0
  50. package/dist/components/tree/TreeSelect.d.ts +12 -0
  51. package/dist/components/tree/TreeSelect.mjs +119 -0
  52. package/dist/components/tree/index.d.ts +4 -0
  53. package/dist/core/assetStructure.cjs +30 -0
  54. package/dist/core/assetStructure.d.ts +36 -0
  55. package/dist/core/assetStructure.mjs +27 -0
  56. package/dist/core/cli.cjs +92 -0
  57. package/dist/core/cli.mjs +89 -0
  58. package/dist/core/constants.cjs +23 -0
  59. package/dist/core/constants.d.ts +83 -0
  60. package/dist/core/constants.mjs +17 -0
  61. package/dist/core/filesystem.cjs +62 -51
  62. package/dist/core/filesystem.d.ts +38 -18
  63. package/dist/core/filesystem.mjs +56 -44
  64. package/dist/core/github.cjs +8 -11
  65. package/dist/core/github.d.ts +4 -6
  66. package/dist/core/github.mjs +8 -11
  67. package/dist/core/io.cjs +46 -0
  68. package/dist/core/io.d.ts +40 -0
  69. package/dist/core/io.mjs +39 -0
  70. package/dist/core/migration.cjs +199 -0
  71. package/dist/core/migration.d.ts +57 -0
  72. package/dist/core/migration.mjs +196 -0
  73. package/dist/core/packageScanner.cjs +259 -0
  74. package/dist/core/packageScanner.d.ts +17 -0
  75. package/dist/core/packageScanner.mjs +257 -0
  76. package/dist/core/sync.cjs +244 -61
  77. package/dist/core/sync.d.ts +6 -2
  78. package/dist/core/sync.mjs +246 -63
  79. package/dist/core/syncMeta.cjs +93 -0
  80. package/dist/core/syncMeta.d.ts +71 -0
  81. package/dist/core/syncMeta.mjs +84 -0
  82. package/dist/index.cjs +7 -4
  83. package/dist/index.d.ts +4 -2
  84. package/dist/index.mjs +3 -2
  85. package/dist/utils/nameTransform.cjs +12 -0
  86. package/dist/utils/nameTransform.d.ts +76 -0
  87. package/dist/utils/nameTransform.mjs +9 -0
  88. package/dist/utils/package.cjs +22 -17
  89. package/dist/utils/package.d.ts +25 -0
  90. package/dist/utils/package.mjs +11 -7
  91. package/dist/utils/packageName.cjs +24 -0
  92. package/dist/utils/packageName.d.ts +32 -0
  93. package/dist/utils/packageName.mjs +21 -0
  94. package/dist/utils/paths.cjs +18 -0
  95. package/dist/utils/paths.d.ts +55 -0
  96. package/dist/utils/paths.mjs +15 -0
  97. package/dist/utils/types.d.ts +153 -6
  98. package/dist/utils/version.cjs +17 -0
  99. package/dist/utils/version.d.ts +55 -0
  100. package/dist/utils/version.mjs +14 -0
  101. package/dist/version.cjs +5 -0
  102. package/dist/version.d.ts +5 -0
  103. package/dist/version.mjs +3 -0
  104. package/package.json +15 -6
  105. package/dist/cli/index.cjs +0 -56
  106. package/dist/cli/index.mjs +0 -53
  107. /package/dist/{cli/index.d.ts → core/cli.d.ts} +0 -0
@@ -0,0 +1,259 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs');
4
+ var path = require('node:path');
5
+ var _package = require('../utils/package.cjs');
6
+ var constants = require('./constants.cjs');
7
+ var github = require('./github.cjs');
8
+
9
+ function readPackageJsonFromPath(packagePath) {
10
+ try {
11
+ const packageJsonPath = path.join(packagePath, 'package.json');
12
+ if (!fs.existsSync(packageJsonPath)) {
13
+ return null;
14
+ }
15
+ const content = fs.readFileSync(packageJsonPath, 'utf-8');
16
+ const json = JSON.parse(content);
17
+ return {
18
+ name: json.name,
19
+ version: json.version,
20
+ repository: json.repository,
21
+ claude: json.claude,
22
+ };
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ async function scanPackageAssets(packageName, options) {
29
+ const cwd = options.cwd ?? process.cwd();
30
+ if (options.local) {
31
+ return scanLocalAssets(packageName, cwd);
32
+ }
33
+ return scanRemoteAssets(packageName, options.ref);
34
+ }
35
+ async function scanLocalAssets(packageName, cwd) {
36
+ const packagePath = findLocalPackage(packageName, cwd);
37
+ if (!packagePath) {
38
+ throw new Error(`Package ${packageName} not found in local workspace`);
39
+ }
40
+ const pkgInfo = readPackageJsonFromPath(packagePath);
41
+ if (!pkgInfo || !pkgInfo.claude?.assetPath) {
42
+ throw new Error(`Package ${packageName} has no claude.assetPath configured`);
43
+ }
44
+ const assetPath = path.join(packagePath, pkgInfo.claude.assetPath);
45
+ if (!fs.existsSync(assetPath)) {
46
+ throw new Error(`Asset path ${assetPath} does not exist`);
47
+ }
48
+ const trees = [];
49
+ for (const assetType of constants.DEFAULT_ASSET_TYPES) {
50
+ const assetDir = path.join(assetPath, assetType);
51
+ if (!fs.existsSync(assetDir)) {
52
+ continue;
53
+ }
54
+ const tree = buildTreeFromLocalDir(assetType, assetDir, assetType);
55
+ if (tree.children && tree.children.length > 0) {
56
+ trees.push(tree);
57
+ }
58
+ }
59
+ return trees;
60
+ }
61
+ async function scanRemoteAssets(packageName, ref) {
62
+ const nodeModulesPath = path.join(process.cwd(), 'node_modules', packageName);
63
+ const pkgInfo = readPackageJsonFromPath(nodeModulesPath);
64
+ if (!pkgInfo || !pkgInfo.claude?.assetPath) {
65
+ throw new Error(`Package ${packageName} has no claude.assetPath configured`);
66
+ }
67
+ if (!pkgInfo.repository) {
68
+ throw new Error(`Package ${packageName} has no repository field`);
69
+ }
70
+ const repoInfo = _package.parseGitHubRepo(pkgInfo.repository);
71
+ if (!repoInfo) {
72
+ throw new Error(`Invalid GitHub repository URL in package ${packageName}`);
73
+ }
74
+ const assetBasePath = pkgInfo.claude.assetPath;
75
+ const trees = [];
76
+ for (const assetType of constants.DEFAULT_ASSET_TYPES) {
77
+ const assetPath = repoInfo.directory
78
+ ? `${repoInfo.directory}/${assetBasePath}/${assetType}`
79
+ : `${assetBasePath}/${assetType}`;
80
+ try {
81
+ const entries = await github.fetchDirectoryContents(repoInfo, assetPath, ref ?? 'HEAD');
82
+ if (entries && entries.length > 0) {
83
+ const tree = buildTreeFromGitHubEntries(assetType, entries, assetType);
84
+ if (tree.children && tree.children.length > 0) {
85
+ trees.push(tree);
86
+ }
87
+ }
88
+ }
89
+ catch {
90
+ continue;
91
+ }
92
+ }
93
+ return trees;
94
+ }
95
+ function buildTreeFromLocalDir(label, dirPath, basePath) {
96
+ const entries = fs.readdirSync(dirPath);
97
+ const children = [];
98
+ for (const entry of entries) {
99
+ const fullPath = path.join(dirPath, entry);
100
+ const stat = fs.statSync(fullPath);
101
+ const relativePath = path.join(basePath, entry);
102
+ if (stat.isDirectory()) {
103
+ const isSkill = fs.existsSync(path.join(fullPath, 'Skill.md'));
104
+ if (isSkill) {
105
+ children.push({
106
+ id: relativePath,
107
+ label: entry,
108
+ path: relativePath,
109
+ type: 'skill-directory',
110
+ selected: true,
111
+ expanded: false,
112
+ });
113
+ }
114
+ else {
115
+ const subTree = buildTreeFromLocalDir(entry, fullPath, relativePath);
116
+ if (subTree.children && subTree.children.length > 0) {
117
+ children.push(subTree);
118
+ }
119
+ }
120
+ }
121
+ else {
122
+ children.push({
123
+ id: relativePath,
124
+ label: entry,
125
+ path: relativePath,
126
+ type: 'file',
127
+ selected: true,
128
+ expanded: false,
129
+ });
130
+ }
131
+ }
132
+ return {
133
+ id: basePath,
134
+ label,
135
+ path: basePath,
136
+ type: 'directory',
137
+ children,
138
+ selected: true,
139
+ expanded: true,
140
+ };
141
+ }
142
+ function buildTreeFromGitHubEntries(label, entries, basePath) {
143
+ const children = [];
144
+ const grouped = groupByTopLevel(entries);
145
+ for (const [name, items] of Object.entries(grouped)) {
146
+ if (items.length === 1 && items[0].type === 'file') {
147
+ const filePath = items[0].path;
148
+ children.push({
149
+ id: filePath,
150
+ label: name,
151
+ path: filePath,
152
+ type: 'file',
153
+ selected: true,
154
+ expanded: false,
155
+ });
156
+ }
157
+ else {
158
+ const isSkill = items.some((item) => item.type === 'file' && item.name === 'Skill.md');
159
+ if (isSkill) {
160
+ const skillPath = `${basePath}/${name}`;
161
+ children.push({
162
+ id: skillPath,
163
+ label: name,
164
+ path: skillPath,
165
+ type: 'skill-directory',
166
+ selected: true,
167
+ expanded: false,
168
+ });
169
+ }
170
+ else {
171
+ const subTree = buildTreeFromGitHubEntries(name, items, `${basePath}/${name}`);
172
+ if (subTree.children && subTree.children.length > 0) {
173
+ children.push(subTree);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ return {
179
+ id: basePath,
180
+ label,
181
+ path: basePath,
182
+ type: 'directory',
183
+ children,
184
+ selected: true,
185
+ expanded: true,
186
+ };
187
+ }
188
+ function groupByTopLevel(entries) {
189
+ const groups = {};
190
+ for (const entry of entries) {
191
+ const parts = entry.path.split('/');
192
+ const topLevel = parts[parts.length - (entry.type === 'file' ? 1 : 0)];
193
+ if (!groups[topLevel]) {
194
+ groups[topLevel] = [];
195
+ }
196
+ groups[topLevel].push(entry);
197
+ }
198
+ return groups;
199
+ }
200
+ function findLocalPackage(packageName, cwd) {
201
+ const monorepoRoot = findMonorepoRoot(cwd);
202
+ const searchRoot = monorepoRoot || cwd;
203
+ const packagesDir = path.join(searchRoot, 'packages');
204
+ if (fs.existsSync(packagesDir)) {
205
+ const found = searchPackagesRecursively(packagesDir, packageName);
206
+ if (found)
207
+ return found;
208
+ }
209
+ const nodeModulesPath = path.join(searchRoot, 'node_modules', packageName);
210
+ if (fs.existsSync(nodeModulesPath)) {
211
+ return nodeModulesPath;
212
+ }
213
+ return null;
214
+ }
215
+ function findMonorepoRoot(startDir) {
216
+ let currentDir = startDir;
217
+ const root = '/';
218
+ while (currentDir !== root) {
219
+ const pkgJsonPath = path.join(currentDir, 'package.json');
220
+ if (fs.existsSync(pkgJsonPath)) {
221
+ try {
222
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
223
+ if (pkgJson.workspaces) {
224
+ return currentDir;
225
+ }
226
+ }
227
+ catch {
228
+ }
229
+ }
230
+ currentDir = path.join(currentDir, '..');
231
+ }
232
+ return null;
233
+ }
234
+ function searchPackagesRecursively(dir, packageName) {
235
+ try {
236
+ const entries = fs.readdirSync(dir);
237
+ for (const entry of entries) {
238
+ const fullPath = path.join(dir, entry);
239
+ const stat = fs.statSync(fullPath);
240
+ if (stat.isDirectory()) {
241
+ const pkgJsonPath = path.join(fullPath, 'package.json');
242
+ if (fs.existsSync(pkgJsonPath)) {
243
+ const pkgInfo = readPackageJsonFromPath(fullPath);
244
+ if (pkgInfo && pkgInfo.name === packageName) {
245
+ return fullPath;
246
+ }
247
+ }
248
+ const found = searchPackagesRecursively(fullPath, packageName);
249
+ if (found)
250
+ return found;
251
+ }
252
+ }
253
+ }
254
+ catch {
255
+ }
256
+ return null;
257
+ }
258
+
259
+ exports.scanPackageAssets = scanPackageAssets;
@@ -0,0 +1,17 @@
1
+ import type { GitHubEntry, TreeNode } from '../utils/types.js';
2
+ /**
3
+ * Scan package assets from local workspace or GitHub
4
+ *
5
+ * @param packageName - Package name to scan
6
+ * @param options - Scan options
7
+ * @returns Tree structure of available assets
8
+ */
9
+ export declare function scanPackageAssets(packageName: string, options: {
10
+ local: boolean;
11
+ ref?: string;
12
+ cwd?: string;
13
+ }): Promise<TreeNode[]>;
14
+ /**
15
+ * Check if entries represent a directory-based skill
16
+ */
17
+ export declare function isDirectorySkill(entries: GitHubEntry[]): boolean;
@@ -0,0 +1,257 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { parseGitHubRepo } from '../utils/package.mjs';
4
+ import { DEFAULT_ASSET_TYPES } from './constants.mjs';
5
+ import { fetchDirectoryContents } from './github.mjs';
6
+
7
+ function readPackageJsonFromPath(packagePath) {
8
+ try {
9
+ const packageJsonPath = join(packagePath, 'package.json');
10
+ if (!existsSync(packageJsonPath)) {
11
+ return null;
12
+ }
13
+ const content = readFileSync(packageJsonPath, 'utf-8');
14
+ const json = JSON.parse(content);
15
+ return {
16
+ name: json.name,
17
+ version: json.version,
18
+ repository: json.repository,
19
+ claude: json.claude,
20
+ };
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ async function scanPackageAssets(packageName, options) {
27
+ const cwd = options.cwd ?? process.cwd();
28
+ if (options.local) {
29
+ return scanLocalAssets(packageName, cwd);
30
+ }
31
+ return scanRemoteAssets(packageName, options.ref);
32
+ }
33
+ async function scanLocalAssets(packageName, cwd) {
34
+ const packagePath = findLocalPackage(packageName, cwd);
35
+ if (!packagePath) {
36
+ throw new Error(`Package ${packageName} not found in local workspace`);
37
+ }
38
+ const pkgInfo = readPackageJsonFromPath(packagePath);
39
+ if (!pkgInfo || !pkgInfo.claude?.assetPath) {
40
+ throw new Error(`Package ${packageName} has no claude.assetPath configured`);
41
+ }
42
+ const assetPath = join(packagePath, pkgInfo.claude.assetPath);
43
+ if (!existsSync(assetPath)) {
44
+ throw new Error(`Asset path ${assetPath} does not exist`);
45
+ }
46
+ const trees = [];
47
+ for (const assetType of DEFAULT_ASSET_TYPES) {
48
+ const assetDir = join(assetPath, assetType);
49
+ if (!existsSync(assetDir)) {
50
+ continue;
51
+ }
52
+ const tree = buildTreeFromLocalDir(assetType, assetDir, assetType);
53
+ if (tree.children && tree.children.length > 0) {
54
+ trees.push(tree);
55
+ }
56
+ }
57
+ return trees;
58
+ }
59
+ async function scanRemoteAssets(packageName, ref) {
60
+ const nodeModulesPath = join(process.cwd(), 'node_modules', packageName);
61
+ const pkgInfo = readPackageJsonFromPath(nodeModulesPath);
62
+ if (!pkgInfo || !pkgInfo.claude?.assetPath) {
63
+ throw new Error(`Package ${packageName} has no claude.assetPath configured`);
64
+ }
65
+ if (!pkgInfo.repository) {
66
+ throw new Error(`Package ${packageName} has no repository field`);
67
+ }
68
+ const repoInfo = parseGitHubRepo(pkgInfo.repository);
69
+ if (!repoInfo) {
70
+ throw new Error(`Invalid GitHub repository URL in package ${packageName}`);
71
+ }
72
+ const assetBasePath = pkgInfo.claude.assetPath;
73
+ const trees = [];
74
+ for (const assetType of DEFAULT_ASSET_TYPES) {
75
+ const assetPath = repoInfo.directory
76
+ ? `${repoInfo.directory}/${assetBasePath}/${assetType}`
77
+ : `${assetBasePath}/${assetType}`;
78
+ try {
79
+ const entries = await fetchDirectoryContents(repoInfo, assetPath, ref ?? 'HEAD');
80
+ if (entries && entries.length > 0) {
81
+ const tree = buildTreeFromGitHubEntries(assetType, entries, assetType);
82
+ if (tree.children && tree.children.length > 0) {
83
+ trees.push(tree);
84
+ }
85
+ }
86
+ }
87
+ catch {
88
+ continue;
89
+ }
90
+ }
91
+ return trees;
92
+ }
93
+ function buildTreeFromLocalDir(label, dirPath, basePath) {
94
+ const entries = readdirSync(dirPath);
95
+ const children = [];
96
+ for (const entry of entries) {
97
+ const fullPath = join(dirPath, entry);
98
+ const stat = statSync(fullPath);
99
+ const relativePath = join(basePath, entry);
100
+ if (stat.isDirectory()) {
101
+ const isSkill = existsSync(join(fullPath, 'Skill.md'));
102
+ if (isSkill) {
103
+ children.push({
104
+ id: relativePath,
105
+ label: entry,
106
+ path: relativePath,
107
+ type: 'skill-directory',
108
+ selected: true,
109
+ expanded: false,
110
+ });
111
+ }
112
+ else {
113
+ const subTree = buildTreeFromLocalDir(entry, fullPath, relativePath);
114
+ if (subTree.children && subTree.children.length > 0) {
115
+ children.push(subTree);
116
+ }
117
+ }
118
+ }
119
+ else {
120
+ children.push({
121
+ id: relativePath,
122
+ label: entry,
123
+ path: relativePath,
124
+ type: 'file',
125
+ selected: true,
126
+ expanded: false,
127
+ });
128
+ }
129
+ }
130
+ return {
131
+ id: basePath,
132
+ label,
133
+ path: basePath,
134
+ type: 'directory',
135
+ children,
136
+ selected: true,
137
+ expanded: true,
138
+ };
139
+ }
140
+ function buildTreeFromGitHubEntries(label, entries, basePath) {
141
+ const children = [];
142
+ const grouped = groupByTopLevel(entries);
143
+ for (const [name, items] of Object.entries(grouped)) {
144
+ if (items.length === 1 && items[0].type === 'file') {
145
+ const filePath = items[0].path;
146
+ children.push({
147
+ id: filePath,
148
+ label: name,
149
+ path: filePath,
150
+ type: 'file',
151
+ selected: true,
152
+ expanded: false,
153
+ });
154
+ }
155
+ else {
156
+ const isSkill = items.some((item) => item.type === 'file' && item.name === 'Skill.md');
157
+ if (isSkill) {
158
+ const skillPath = `${basePath}/${name}`;
159
+ children.push({
160
+ id: skillPath,
161
+ label: name,
162
+ path: skillPath,
163
+ type: 'skill-directory',
164
+ selected: true,
165
+ expanded: false,
166
+ });
167
+ }
168
+ else {
169
+ const subTree = buildTreeFromGitHubEntries(name, items, `${basePath}/${name}`);
170
+ if (subTree.children && subTree.children.length > 0) {
171
+ children.push(subTree);
172
+ }
173
+ }
174
+ }
175
+ }
176
+ return {
177
+ id: basePath,
178
+ label,
179
+ path: basePath,
180
+ type: 'directory',
181
+ children,
182
+ selected: true,
183
+ expanded: true,
184
+ };
185
+ }
186
+ function groupByTopLevel(entries) {
187
+ const groups = {};
188
+ for (const entry of entries) {
189
+ const parts = entry.path.split('/');
190
+ const topLevel = parts[parts.length - (entry.type === 'file' ? 1 : 0)];
191
+ if (!groups[topLevel]) {
192
+ groups[topLevel] = [];
193
+ }
194
+ groups[topLevel].push(entry);
195
+ }
196
+ return groups;
197
+ }
198
+ function findLocalPackage(packageName, cwd) {
199
+ const monorepoRoot = findMonorepoRoot(cwd);
200
+ const searchRoot = monorepoRoot || cwd;
201
+ const packagesDir = join(searchRoot, 'packages');
202
+ if (existsSync(packagesDir)) {
203
+ const found = searchPackagesRecursively(packagesDir, packageName);
204
+ if (found)
205
+ return found;
206
+ }
207
+ const nodeModulesPath = join(searchRoot, 'node_modules', packageName);
208
+ if (existsSync(nodeModulesPath)) {
209
+ return nodeModulesPath;
210
+ }
211
+ return null;
212
+ }
213
+ function findMonorepoRoot(startDir) {
214
+ let currentDir = startDir;
215
+ const root = '/';
216
+ while (currentDir !== root) {
217
+ const pkgJsonPath = join(currentDir, 'package.json');
218
+ if (existsSync(pkgJsonPath)) {
219
+ try {
220
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
221
+ if (pkgJson.workspaces) {
222
+ return currentDir;
223
+ }
224
+ }
225
+ catch {
226
+ }
227
+ }
228
+ currentDir = join(currentDir, '..');
229
+ }
230
+ return null;
231
+ }
232
+ function searchPackagesRecursively(dir, packageName) {
233
+ try {
234
+ const entries = readdirSync(dir);
235
+ for (const entry of entries) {
236
+ const fullPath = join(dir, entry);
237
+ const stat = statSync(fullPath);
238
+ if (stat.isDirectory()) {
239
+ const pkgJsonPath = join(fullPath, 'package.json');
240
+ if (existsSync(pkgJsonPath)) {
241
+ const pkgInfo = readPackageJsonFromPath(fullPath);
242
+ if (pkgInfo && pkgInfo.name === packageName) {
243
+ return fullPath;
244
+ }
245
+ }
246
+ const found = searchPackagesRecursively(fullPath, packageName);
247
+ if (found)
248
+ return found;
249
+ }
250
+ }
251
+ }
252
+ catch {
253
+ }
254
+ return null;
255
+ }
256
+
257
+ export { scanPackageAssets };