codemodctl 0.1.14 → 0.1.15

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/cli.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { analyzeCodeowners, getApplicableFiles } from "./codeowner-analysis-pG3p0RPU.js";
3
- import { calculateOptimalShardCount, distributeFilesAcrossShards } from "./consistent-sharding-pjG1rI6w.js";
2
+ import "./codemod-cli-DailrcEf.js";
3
+ import { analyzeCodeowners } from "./codeowner-analysis-BcFoet6s.js";
4
+ import "./consistent-sharding-lYO6XLIO.js";
5
+ import { analyzeDirectories } from "./directory-analysis-6DFgAaDz.js";
4
6
  import { defineCommand, runMain } from "citty";
5
7
  import crypto from "node:crypto";
6
8
  import { $ } from "execa";
7
9
  import { writeFile } from "node:fs/promises";
8
- import path from "node:path";
9
10
 
10
11
  //#region src/commands/git/create-pr.ts
11
12
  const createPrCommand = defineCommand({
@@ -262,97 +263,6 @@ const codeownerCommand = defineCommand({
262
263
  }
263
264
  });
264
265
 
265
- //#endregion
266
- //#region src/utils/directory-analysis.ts
267
- /**
268
- * Groups files by their immediate subdirectory within the target directory
269
- *
270
- * @param files - Array of file paths to group
271
- * @param target - Target directory to analyze subdirectories within
272
- * @returns Map of subdirectory paths to their file lists
273
- */
274
- function groupFilesByDirectory(files, target) {
275
- const normalizedTarget = path.normalize(target);
276
- const filesByDirectory = /* @__PURE__ */ new Map();
277
- for (const filePath of files) {
278
- const normalizedFile = path.normalize(filePath);
279
- if (!normalizedFile.startsWith(normalizedTarget)) continue;
280
- const relativePath = path.relative(normalizedTarget, normalizedFile);
281
- if (!relativePath.includes(path.sep)) continue;
282
- const firstDir = relativePath.split(path.sep)[0];
283
- if (!firstDir) continue;
284
- const subdirectory = path.join(normalizedTarget, firstDir);
285
- if (!filesByDirectory.has(subdirectory)) filesByDirectory.set(subdirectory, []);
286
- filesByDirectory.get(subdirectory).push(normalizedFile);
287
- }
288
- return filesByDirectory;
289
- }
290
- /**
291
- * Creates directory-based shards using consistent hashing within each directory group.
292
- * Maintains consistency with existing state when provided.
293
- *
294
- * @param filesByDirectory - Map of directory paths to their file lists
295
- * @param shardSize - Target number of files per shard
296
- * @param existingState - Optional existing state for consistency
297
- * @returns Array of directory-based shards
298
- */
299
- function createDirectoryShards(filesByDirectory, shardSize, existingState) {
300
- const allShards = [];
301
- const existingByDirectory = /* @__PURE__ */ new Map();
302
- if (existingState) for (const shard of existingState) {
303
- if (!existingByDirectory.has(shard.directory)) existingByDirectory.set(shard.directory, []);
304
- existingByDirectory.get(shard.directory).push(shard);
305
- }
306
- for (const [directory, files] of filesByDirectory.entries()) {
307
- const fileCount = files.length;
308
- const optimalShardCount = calculateOptimalShardCount(fileCount, shardSize);
309
- const existingShards = existingByDirectory.get(directory) || [];
310
- const existingShardCount = existingShards.length > 0 ? existingShards[0]?.shardCount ?? 0 : 0;
311
- const shardCount = existingShardCount > 0 ? existingShardCount : optimalShardCount;
312
- console.log(`Directory "${directory}" contains ${fileCount} files, ${existingShardCount > 0 ? `maintaining ${shardCount} existing shards` : `creating ${shardCount} new shards`}`);
313
- const shardMap = distributeFilesAcrossShards(files, shardCount);
314
- for (let shardIndex = 0; shardIndex < shardCount; shardIndex++) {
315
- const shardFiles = shardMap.get(shardIndex) || [];
316
- allShards.push({
317
- directory,
318
- shard: shardIndex + 1,
319
- shardCount,
320
- files: shardFiles.sort()
321
- });
322
- }
323
- }
324
- return allShards;
325
- }
326
- /**
327
- * Main function to analyze directories and generate shard configuration.
328
- * Maintains consistency with existing state when provided.
329
- *
330
- * @param options - Configuration options for directory analysis
331
- * @returns Promise resolving to directory analysis result
332
- * @throws Error if no files found in target subdirectories
333
- */
334
- async function analyzeDirectories(options) {
335
- const { shardSize, target, rulePath, language, projectRoot = process.cwd(), existingState } = options;
336
- console.debug(`Using rule file: ${rulePath}`);
337
- console.debug(`Target directory: ${target}`);
338
- console.debug(`Shard size: ${shardSize}`);
339
- if (existingState) console.debug(`Using existing state with ${existingState.length} shards`);
340
- console.log("Analyzing files with CLI command...");
341
- const applicableFiles = await getApplicableFiles(rulePath, language, projectRoot);
342
- console.log("Grouping files by directory...");
343
- const filesByDirectory = groupFilesByDirectory(applicableFiles, target);
344
- if (filesByDirectory.size === 0) throw new Error(`No files found in subdirectories of target: ${target}`);
345
- console.log(`Found ${filesByDirectory.size} subdirectories in target`);
346
- console.log("Generating directory-based shards...");
347
- const shards = createDirectoryShards(filesByDirectory, shardSize, existingState);
348
- const totalFiles = Array.from(filesByDirectory.values()).reduce((sum, files) => sum + files.length, 0);
349
- console.log(`Generated ${shards.length} total shards for ${totalFiles} files across ${filesByDirectory.size} directories`);
350
- return {
351
- shards,
352
- totalFiles
353
- };
354
- }
355
-
356
266
  //#endregion
357
267
  //#region src/commands/shard/directory.ts
358
268
  /**
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from "node:child_process";
3
+
4
+ //#region src/utils/codemod-cli.ts
5
+ /**
6
+ * Executes the codemod CLI command and returns applicable file paths
7
+ */
8
+ async function getApplicableFiles(rulePath, language, projectRoot) {
9
+ try {
10
+ const command = `npx -y codemod@latest jssg list-applicable --language ${language} --target ${projectRoot} ${rulePath}`;
11
+ console.debug(`Executing: ${command}`);
12
+ const applicableFiles = execSync(command, {
13
+ encoding: "utf8",
14
+ cwd: projectRoot,
15
+ maxBuffer: 10 * 1024 * 1024
16
+ }).split("\n").filter((line) => line.startsWith("[Applicable] ")).map((line) => line.replace("[Applicable] ", "").trim()).filter((filePath) => filePath.length > 0);
17
+ console.debug(`Found ${applicableFiles.length} applicable files`);
18
+ return applicableFiles;
19
+ } catch (error) {
20
+ console.error("Error executing codemod CLI:", error);
21
+ throw new Error(`Failed to execute codemod CLI: ${error}`);
22
+ }
23
+ }
24
+
25
+ //#endregion
26
+ export { getApplicableFiles };
@@ -1,31 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import { getApplicableFiles } from "./codemod-cli-DailrcEf.js";
2
3
  import { existsSync } from "node:fs";
3
4
  import path, { resolve } from "node:path";
4
5
  import Codeowners from "codeowners";
5
- import { execSync } from "node:child_process";
6
6
 
7
- //#region src/utils/codemod-cli.ts
8
- /**
9
- * Executes the codemod CLI command and returns applicable file paths
10
- */
11
- async function getApplicableFiles(rulePath, language, projectRoot) {
12
- try {
13
- const command = `npx -y codemod@latest jssg list-applicable --language ${language} --target ${projectRoot} ${rulePath}`;
14
- console.debug(`Executing: ${command}`);
15
- const applicableFiles = execSync(command, {
16
- encoding: "utf8",
17
- cwd: projectRoot,
18
- maxBuffer: 10 * 1024 * 1024
19
- }).split("\n").filter((line) => line.startsWith("[Applicable] ")).map((line) => line.replace("[Applicable] ", "").trim()).filter((filePath) => filePath.length > 0);
20
- console.debug(`Found ${applicableFiles.length} applicable files`);
21
- return applicableFiles;
22
- } catch (error) {
23
- console.error("Error executing codemod CLI:", error);
24
- throw new Error(`Failed to execute codemod CLI: ${error}`);
25
- }
26
- }
27
-
28
- //#endregion
29
7
  //#region src/utils/codeowner-analysis.ts
30
8
  /**
31
9
  * Finds and resolves the CODEOWNERS file path
@@ -177,4 +155,4 @@ async function analyzeCodeowners(options) {
177
155
  }
178
156
 
179
157
  //#endregion
180
- export { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getApplicableFiles, getTeamFileInfo, normalizeOwnerName };
158
+ export { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName };
@@ -1,2 +1,2 @@
1
- import { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-B7Jrhm9T.js";
1
+ import { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-CkGR1oU6.js";
2
2
  export { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName };
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-pG3p0RPU.js";
2
+ import "./codemod-cli-DailrcEf.js";
3
+ import { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-BcFoet6s.js";
3
4
 
4
5
  export { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName };
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ import { getApplicableFiles } from "./codemod-cli-DailrcEf.js";
3
+ import { calculateOptimalShardCount, distributeFilesAcrossShards } from "./consistent-sharding-lYO6XLIO.js";
4
+ import path from "node:path";
5
+
6
+ //#region src/utils/directory-analysis.ts
7
+ /**
8
+ * Groups files by their immediate subdirectory within the target directory
9
+ *
10
+ * @param files - Array of file paths to group
11
+ * @param target - Target directory to analyze subdirectories within
12
+ * @returns Map of subdirectory paths to their file lists
13
+ */
14
+ function groupFilesByDirectory(files, target) {
15
+ const normalizedTarget = path.normalize(target);
16
+ const filesByDirectory = /* @__PURE__ */ new Map();
17
+ for (const filePath of files) {
18
+ const normalizedFile = path.normalize(filePath);
19
+ if (!normalizedFile.startsWith(normalizedTarget)) continue;
20
+ const relativePath = path.relative(normalizedTarget, normalizedFile);
21
+ if (!relativePath.includes(path.sep)) continue;
22
+ const firstDir = relativePath.split(path.sep)[0];
23
+ if (!firstDir) continue;
24
+ const subdirectory = path.join(normalizedTarget, firstDir);
25
+ if (!filesByDirectory.has(subdirectory)) filesByDirectory.set(subdirectory, []);
26
+ filesByDirectory.get(subdirectory).push(normalizedFile);
27
+ }
28
+ return filesByDirectory;
29
+ }
30
+ /**
31
+ * Creates directory-based shards using consistent hashing within each directory group.
32
+ * Maintains consistency with existing state when provided.
33
+ *
34
+ * @param filesByDirectory - Map of directory paths to their file lists
35
+ * @param shardSize - Target number of files per shard
36
+ * @param existingState - Optional existing state for consistency
37
+ * @returns Array of directory-based shards
38
+ */
39
+ function createDirectoryShards(filesByDirectory, shardSize, existingState) {
40
+ const allShards = [];
41
+ const existingByDirectory = /* @__PURE__ */ new Map();
42
+ if (existingState) for (const shard of existingState) {
43
+ if (!existingByDirectory.has(shard.directory)) existingByDirectory.set(shard.directory, []);
44
+ existingByDirectory.get(shard.directory).push(shard);
45
+ }
46
+ for (const [directory, files] of filesByDirectory.entries()) {
47
+ const fileCount = files.length;
48
+ const optimalShardCount = calculateOptimalShardCount(fileCount, shardSize);
49
+ const existingShards = existingByDirectory.get(directory) || [];
50
+ const existingShardCount = existingShards.length > 0 ? existingShards[0]?.shardCount ?? 0 : 0;
51
+ const shardCount = existingShardCount > 0 ? existingShardCount : optimalShardCount;
52
+ console.log(`Directory "${directory}" contains ${fileCount} files, ${existingShardCount > 0 ? `maintaining ${shardCount} existing shards` : `creating ${shardCount} new shards`}`);
53
+ const shardMap = distributeFilesAcrossShards(files, shardCount);
54
+ for (let shardIndex = 0; shardIndex < shardCount; shardIndex++) {
55
+ const shardFiles = shardMap.get(shardIndex) || [];
56
+ allShards.push({
57
+ directory,
58
+ shard: shardIndex + 1,
59
+ shardCount,
60
+ files: shardFiles.sort()
61
+ });
62
+ }
63
+ }
64
+ return allShards;
65
+ }
66
+ /**
67
+ * Main function to analyze directories and generate shard configuration.
68
+ * Maintains consistency with existing state when provided.
69
+ *
70
+ * @param options - Configuration options for directory analysis
71
+ * @returns Promise resolving to directory analysis result
72
+ * @throws Error if no files found in target subdirectories
73
+ */
74
+ async function analyzeDirectories(options) {
75
+ const { shardSize, target, rulePath, language, projectRoot = process.cwd(), existingState } = options;
76
+ console.debug(`Using rule file: ${rulePath}`);
77
+ console.debug(`Target directory: ${target}`);
78
+ console.debug(`Shard size: ${shardSize}`);
79
+ if (existingState) console.debug(`Using existing state with ${existingState.length} shards`);
80
+ console.log("Analyzing files with CLI command...");
81
+ const applicableFiles = await getApplicableFiles(rulePath, language, projectRoot);
82
+ console.log("Grouping files by directory...");
83
+ const filesByDirectory = groupFilesByDirectory(applicableFiles, target);
84
+ if (filesByDirectory.size === 0) throw new Error(`No files found in subdirectories of target: ${target}`);
85
+ console.log(`Found ${filesByDirectory.size} subdirectories in target`);
86
+ console.log("Generating directory-based shards...");
87
+ const shards = createDirectoryShards(filesByDirectory, shardSize, existingState);
88
+ const totalFiles = Array.from(filesByDirectory.values()).reduce((sum, files) => sum + files.length, 0);
89
+ console.log(`Generated ${shards.length} total shards for ${totalFiles} files across ${filesByDirectory.size} directories`);
90
+ return {
91
+ shards,
92
+ totalFiles
93
+ };
94
+ }
95
+
96
+ //#endregion
97
+ export { analyzeDirectories, createDirectoryShards, groupFilesByDirectory };
@@ -0,0 +1,69 @@
1
+ //#region src/utils/directory-analysis.d.ts
2
+ /**
3
+ * Result for a single directory-based shard
4
+ */
5
+ interface DirectoryShardResult {
6
+ /** The directory path this shard belongs to */
7
+ directory: string;
8
+ /** The shard number (1-based) within this directory */
9
+ shard: number;
10
+ /** Total number of shards for this directory */
11
+ shardCount: number;
12
+ /** Array of file paths in this shard */
13
+ files: string[];
14
+ }
15
+ /**
16
+ * Options for directory-based analysis
17
+ */
18
+ interface DirectoryAnalysisOptions {
19
+ /** Target number of files per shard */
20
+ shardSize: number;
21
+ /** Target directory to analyze subdirectories within */
22
+ target: string;
23
+ /** Path to the codemod rule file */
24
+ rulePath: string;
25
+ /** Programming language for the codemod */
26
+ language: string;
27
+ /** Project root directory (defaults to process.cwd()) */
28
+ projectRoot?: string;
29
+ /** Existing state for consistency (optional) */
30
+ existingState?: DirectoryShardResult[];
31
+ }
32
+ /**
33
+ * Result of directory-based analysis
34
+ */
35
+ interface DirectoryAnalysisResult {
36
+ /** Array of directory-based shards */
37
+ shards: DirectoryShardResult[];
38
+ /** Total number of files processed */
39
+ totalFiles: number;
40
+ }
41
+ /**
42
+ * Groups files by their immediate subdirectory within the target directory
43
+ *
44
+ * @param files - Array of file paths to group
45
+ * @param target - Target directory to analyze subdirectories within
46
+ * @returns Map of subdirectory paths to their file lists
47
+ */
48
+ declare function groupFilesByDirectory(files: string[], target: string): Map<string, string[]>;
49
+ /**
50
+ * Creates directory-based shards using consistent hashing within each directory group.
51
+ * Maintains consistency with existing state when provided.
52
+ *
53
+ * @param filesByDirectory - Map of directory paths to their file lists
54
+ * @param shardSize - Target number of files per shard
55
+ * @param existingState - Optional existing state for consistency
56
+ * @returns Array of directory-based shards
57
+ */
58
+ declare function createDirectoryShards(filesByDirectory: Map<string, string[]>, shardSize: number, existingState?: DirectoryShardResult[]): DirectoryShardResult[];
59
+ /**
60
+ * Main function to analyze directories and generate shard configuration.
61
+ * Maintains consistency with existing state when provided.
62
+ *
63
+ * @param options - Configuration options for directory analysis
64
+ * @returns Promise resolving to directory analysis result
65
+ * @throws Error if no files found in target subdirectories
66
+ */
67
+ declare function analyzeDirectories(options: DirectoryAnalysisOptions): Promise<DirectoryAnalysisResult>;
68
+ //#endregion
69
+ export { DirectoryAnalysisOptions, DirectoryAnalysisResult, DirectoryShardResult, analyzeDirectories, createDirectoryShards, groupFilesByDirectory };
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import "./codemod-cli-DailrcEf.js";
3
+ import "./consistent-sharding-lYO6XLIO.js";
4
+ import { analyzeDirectories, createDirectoryShards, groupFilesByDirectory } from "./directory-analysis-6DFgAaDz.js";
5
+
6
+ export { analyzeDirectories, createDirectoryShards, groupFilesByDirectory };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-CwWnbSoW.js";
2
- import { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-B7Jrhm9T.js";
1
+ import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-B-Si8jYX.js";
2
+ import { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-CkGR1oU6.js";
3
3
  export { CodeownerAnalysisOptions, CodeownerAnalysisResult, ShardResult, TeamFileInfo, analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, findCodeownersFile, fitsInShard, generateShards, getFileHashPosition, getNumericFileNameSha1, getShardForFilename, getTeamFileInfo, normalizeOwnerName };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-pG3p0RPU.js";
3
- import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-pjG1rI6w.js";
2
+ import "./codemod-cli-DailrcEf.js";
3
+ import { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, findCodeownersFile, generateShards, getTeamFileInfo, normalizeOwnerName } from "./codeowner-analysis-BcFoet6s.js";
4
+ import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-lYO6XLIO.js";
4
5
 
5
6
  export { analyzeCodeowners, analyzeFilesByOwner, analyzeFilesWithoutOwner, analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, findCodeownersFile, fitsInShard, generateShards, getFileHashPosition, getNumericFileNameSha1, getShardForFilename, getTeamFileInfo, normalizeOwnerName };
@@ -1,2 +1,2 @@
1
- import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-CwWnbSoW.js";
1
+ import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-B-Si8jYX.js";
2
2
  export { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename };
package/dist/sharding.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-pjG1rI6w.js";
2
+ import { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename } from "./consistent-sharding-lYO6XLIO.js";
3
3
 
4
4
  export { analyzeShardScaling, calculateOptimalShardCount, distributeFilesAcrossShards, fitsInShard, getFileHashPosition, getNumericFileNameSha1, getShardForFilename };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemodctl",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "CLI tool and utilities for workflow engine operations, file sharding, and codeowner analysis",
5
5
  "type": "module",
6
6
  "exports": {