bun-workspaces 1.0.0-alpha.2 → 1.0.0-alpha.20

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 (122) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +124 -79
  3. package/bin/cli.js +1 -2
  4. package/package.json +13 -27
  5. package/src/cli/createCli.d.ts +19 -0
  6. package/src/cli/createCli.mjs +99 -0
  7. package/src/cli/fatalErrorLogger.d.ts +1 -0
  8. package/src/cli/fatalErrorLogger.mjs +7 -0
  9. package/src/cli/globalOptions/globalOptions.d.ts +38 -0
  10. package/src/cli/globalOptions/globalOptions.mjs +120 -0
  11. package/src/cli/globalOptions/globalOptionsConfig.d.ts +43 -0
  12. package/src/cli/globalOptions/globalOptionsConfig.mjs +34 -0
  13. package/src/cli/globalOptions/index.d.ts +2 -0
  14. package/src/cli/globalOptions/index.mjs +2 -0
  15. package/src/cli/index.d.ts +3 -0
  16. package/src/cli/index.mjs +3 -0
  17. package/src/cli/projectCommands/commandHandlerUtils.d.ts +31 -0
  18. package/src/cli/projectCommands/commandHandlerUtils.mjs +52 -0
  19. package/src/cli/projectCommands/handleRunScript.d.ts +5 -0
  20. package/src/cli/projectCommands/handleRunScript.mjs +153 -0
  21. package/src/cli/projectCommands/handleSimpleCommands.d.ts +20 -0
  22. package/src/cli/projectCommands/handleSimpleCommands.mjs +131 -0
  23. package/src/cli/projectCommands/index.d.ts +2 -0
  24. package/src/cli/projectCommands/index.mjs +2 -0
  25. package/src/cli/projectCommands/projectCommands.d.ts +4 -0
  26. package/src/cli/projectCommands/projectCommands.mjs +19 -0
  27. package/src/cli/projectCommands/projectCommandsConfig.d.ts +218 -0
  28. package/src/cli/projectCommands/projectCommandsConfig.mjs +110 -0
  29. package/src/config/bunWorkspacesConfig.d.ts +17 -0
  30. package/src/config/bunWorkspacesConfig.mjs +50 -0
  31. package/src/config/configFile.d.ts +8 -0
  32. package/src/config/configFile.mjs +43 -0
  33. package/src/config/errors.d.ts +3 -0
  34. package/src/config/errors.mjs +10 -0
  35. package/src/config/{index.ts → index.d.ts} +1 -0
  36. package/src/config/index.mjs +11 -0
  37. package/src/config/workspaceConfig/errors.d.ts +3 -0
  38. package/src/config/workspaceConfig/errors.mjs +9 -0
  39. package/src/config/workspaceConfig/index.d.ts +4 -0
  40. package/src/config/workspaceConfig/index.mjs +4 -0
  41. package/src/config/workspaceConfig/loadWorkspaceConfig.d.ts +5 -0
  42. package/src/config/workspaceConfig/loadWorkspaceConfig.mjs +82 -0
  43. package/src/config/workspaceConfig/workspaceConfig.d.ts +14 -0
  44. package/src/config/workspaceConfig/workspaceConfig.mjs +48 -0
  45. package/src/config/workspaceConfig/workspaceConfigLocation.d.ts +2 -0
  46. package/src/config/workspaceConfig/workspaceConfigLocation.mjs +5 -0
  47. package/src/index.d.ts +23 -0
  48. package/src/index.mjs +9 -0
  49. package/src/internal/asyncIterableQueue.d.ts +15 -0
  50. package/src/internal/asyncIterableQueue.mjs +73 -0
  51. package/src/internal/bunVersion.d.ts +17 -0
  52. package/src/internal/bunVersion.mjs +28 -0
  53. package/src/internal/env.d.ts +5 -0
  54. package/src/internal/env.mjs +29 -0
  55. package/src/internal/error.d.ts +9 -0
  56. package/src/internal/{error.ts → error.mjs} +7 -16
  57. package/src/internal/json.d.ts +9 -0
  58. package/src/internal/json.mjs +6 -0
  59. package/src/internal/logger.d.ts +44 -0
  60. package/src/internal/logger.mjs +110 -0
  61. package/src/internal/mergeAsyncIterables.d.ts +5 -0
  62. package/src/internal/mergeAsyncIterables.mjs +27 -0
  63. package/src/internal/optionalArray.d.ts +15 -0
  64. package/src/internal/optionalArray.mjs +8 -0
  65. package/src/internal/os.d.ts +4 -0
  66. package/src/internal/os.mjs +7 -0
  67. package/src/internal/regex.d.ts +3 -0
  68. package/src/internal/regex.mjs +10 -0
  69. package/src/internal/types.d.ts +6 -0
  70. package/src/internal/types.mjs +3 -0
  71. package/src/project/errors.d.ts +3 -0
  72. package/src/project/errors.mjs +9 -0
  73. package/src/project/implementations/fileSystemProject.d.ts +88 -0
  74. package/src/project/implementations/fileSystemProject.mjs +152 -0
  75. package/src/project/implementations/memoryProject.d.ts +32 -0
  76. package/src/project/implementations/memoryProject.mjs +46 -0
  77. package/src/project/implementations/projectBase.d.ts +27 -0
  78. package/src/project/implementations/projectBase.mjs +97 -0
  79. package/src/project/index.d.ts +6 -0
  80. package/src/project/index.mjs +5 -0
  81. package/src/project/project.d.ts +64 -0
  82. package/src/project/project.mjs +6 -0
  83. package/src/project/runScript/index.d.ts +3 -0
  84. package/src/project/runScript/index.mjs +3 -0
  85. package/src/project/runScript/runScript.d.ts +41 -0
  86. package/src/project/runScript/runScript.mjs +63 -0
  87. package/src/project/runScript/runScripts.d.ts +47 -0
  88. package/src/project/runScript/runScripts.mjs +95 -0
  89. package/src/project/runScript/scriptCommand.d.ts +33 -0
  90. package/src/project/runScript/scriptCommand.mjs +19 -0
  91. package/src/project/runScript/scriptRuntimeMetadata.d.ts +73 -0
  92. package/src/project/runScript/scriptRuntimeMetadata.mjs +56 -0
  93. package/src/workspaces/errors.d.ts +12 -0
  94. package/src/workspaces/{errors.ts → errors.mjs} +5 -2
  95. package/src/workspaces/findWorkspaces.d.ts +20 -0
  96. package/src/workspaces/findWorkspaces.mjs +147 -0
  97. package/src/workspaces/index.d.ts +4 -0
  98. package/src/workspaces/index.mjs +3 -0
  99. package/src/workspaces/packageJson.d.ts +15 -0
  100. package/src/workspaces/packageJson.mjs +134 -0
  101. package/src/workspaces/{workspace.ts → workspace.d.ts} +5 -6
  102. package/src/workspaces/workspace.mjs +2 -0
  103. package/bun.lock +0 -576
  104. package/src/cli/cli.ts +0 -87
  105. package/src/cli/globalOptions.ts +0 -122
  106. package/src/cli/index.ts +0 -1
  107. package/src/cli/projectCommands.ts +0 -390
  108. package/src/config/bunWorkspacesConfig.ts +0 -62
  109. package/src/config/configFile.ts +0 -33
  110. package/src/index.ts +0 -3
  111. package/src/internal/bunVersion.ts +0 -26
  112. package/src/internal/env.ts +0 -25
  113. package/src/internal/logger.ts +0 -187
  114. package/src/internal/regex.ts +0 -5
  115. package/src/project/errors.ts +0 -6
  116. package/src/project/index.ts +0 -6
  117. package/src/project/project.ts +0 -155
  118. package/src/project/scriptCommand.ts +0 -40
  119. package/src/workspaces/findWorkspaces.ts +0 -137
  120. package/src/workspaces/index.ts +0 -7
  121. package/src/workspaces/packageJson.ts +0 -166
  122. package/tsconfig.json +0 -28
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Scott Morse
3
+ Copyright (c) 2025 Scott Morse
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,113 +1,158 @@
1
- # bun-workspaces
2
-
3
- This is a CLI meant to help manage [Bun workspaces](https://bun.sh/docs/install/workspaces).
1
+ <img src="./packages/doc-website/src/docs/public/bw-eye.png" alt="bun-workspaces" width="50" />
4
2
 
5
- ## Installation
3
+ # bun-workspaces
6
4
 
7
- You can install the CLI in your project or simply use `bunx bun-workspaces`.
5
+ ### [**See Full Documentation Here:** _https://bunworkspaces.com_](https://bunworkspaces.com)
8
6
 
9
- ```bash
10
- $ bun add --dev bun-workspaces
11
- $ bunx bun-workspaces --help
12
- ```
7
+ **_New: [An API is now officially released!](https://bunworkspaces.com/api)_**
13
8
 
14
- ### Config file
9
+ This is a CLI and API that help you manage your monorepo on top of native [Bun workspaces](https://bun.sh/docs/install/workspaces), with no additional setup required. Get metadata about your workspaces and scripts, and run scripts across your workspaces.
15
10
 
16
- You can create a config file at `bw.json` in your project root, or you can pass a config file to the CLI with the `--configFile` (or `-c`) option.
11
+ <a href="https://buymeacoffee.com/scottmorse">
12
+ <img src="./packages/doc-website/src/docs/public/bmac-logo-circle.png" alt="Link to Buy Me A Coffee" width="60" />
13
+ </a>
17
14
 
18
- #### Example config
15
+ ## Quick Start
19
16
 
20
- In this config, "app-a" is an alias for package "@my-org/application-a" and "app-b" is an alias for package "@my-org/application-b".
17
+ Installation:
21
18
 
22
- CLI log levels are `debug`, `info`, `warn`, and `error` or `silent`. The default log level is `info`. Commands that are intended to print specific output will still print at `silent`, such as `list-workspaces`, `list-scripts`, `workspace-info`, `script-info`, etc., but other logs will be suppressed.
23
-
24
- ```json
25
- {
26
- "workspaceAliases": {
27
- "app-a": "@my-org/application-a",
28
- "app-b": "@my-org/application-b"
29
- },
30
- "cli": {
31
- "logLevel": "warn"
32
- }
33
- }
19
+ ```bash
20
+ $ # Install to use the API and/or lock your CLI version for your project
21
+ $ bun add --dev bun-workspaces
22
+ $ # Start using the CLI with or without the installation step
23
+ $ bunx bun-workspaces --help
34
24
  ```
35
25
 
36
- You can also pass a config file to the CLI with the `-c` or `--configFile` option.
37
-
38
- ### Examples
26
+ ### CLI
39
27
 
40
- You might consider making a shorter alias in your `.bashrc`, `.zshrc`, or similar shell configuration file, such as `alias bw="bunx bun-workspaces"`, for convenience.
28
+ [Full CLI documentation here](https://bunworkspaces.com/cli)
41
29
 
42
30
  ```bash
43
- alias bw="bunx bun-workspaces"
31
+ alias bw="bunx bun-workspaces" # can place in .zshrc, .bashrc, or similar
44
32
 
45
- # List all workspaces
33
+ # List all workspaces in your project
46
34
  bw list-workspaces
47
- bw ls
48
35
 
49
- # List workspace names only
50
- bw list-workspaces --name-only
36
+ # ls is an alias for list-workspaces
37
+ bw ls --json --pretty # Output as formatted JSON
51
38
 
52
- # Filter list of workspaces with wildcard
53
- bw list-workspaces "my-*"
39
+ # Run the lint script for all workspaces
40
+ # that have it in their "scripts" field
41
+ bw run-script lint
54
42
 
55
- # List all workspace scripts
56
- bw list-scripts
43
+ # run is an alias for run-script
44
+ bw run lint my-workspace # Run for a single workspace
45
+ bw run lint my-workspace-a my-workspace-b # Run for multiple workspaces
46
+ bw run lint "my-workspace-*" # Run for matching workspace names
47
+ bw run lint --parallel # Run at the same time
48
+ bw run lint --args="--my-appended-args" # Add args to each script call
49
+ bw run lint --args="--my-arg=<workspaceName>" # Use the workspace name in args
57
50
 
58
- # List script names only
59
- bw list-scripts --name-only
51
+ # Run an inline command from the workspace directory
52
+ bw run "echo 'this is my inline script for <workspaceName>'" --inline
60
53
 
61
- # Get info about a workspace
62
- bw workspace-info my-workspace
63
- bw info my-workspace
64
-
65
- # Get info about a script
66
- bw script-info my-script
54
+ # Show usage (you can pass --help to any command)
55
+ bw help
56
+ bw --help
67
57
 
68
- # Only print list of workspace names that have the script
69
- bw script-info my-script --workspaces-only
58
+ # Pass --cwd to any command
59
+ bw --cwd=/path/to/your/project ls
60
+ bw --cwd=/path/to/your/project run my-script
70
61
 
71
- # Get JSON output
72
- bw list-workspaces --json --pretty # optionally pretty print JSON
73
- bw list-scripts --json
74
- bw workspace-info my-workspace --json
75
- bw script-info my-script --json
62
+ # Pass --log-level to any command (debug, info, warn, error, or silent)
63
+ bw --log-level=silent run my-script
64
+ ```
76
65
 
77
- # Run a script for all
78
- # workspaces that have it
79
- # in their `scripts` field
80
- bw run my-script
66
+ ### API
81
67
 
82
- # Run a script for a specific workspace by its package.json name or alias from the config
83
- bw run my-script my-workspace
68
+ [Full API documentation here](https://bunworkspaces.com/api)
84
69
 
85
- # Run a script for multiple workspaces
86
- bw run my-script workspace-a workspace-b
70
+ ```typescript
71
+ import { createFileSystemProject } from "bun-workspaces";
87
72
 
88
- # Run a script for workspaces using wildcard (does not take into account workspace aliases)
89
- bw run my-script "my-workspace-*"
73
+ // A Project contains the core functionality of bun-workspaces.
74
+ const project = createFileSystemProject({
75
+ rootDirectory: "path/to/your/project",
76
+ });
90
77
 
91
- # Run script in parallel for all workspaces
92
- bw run my-script --parallel
78
+ // A Workspace that matches the name or alias "my-workspace"
79
+ const myWorkspace = project.findWorkspaceByNameOrAlias("my-workspace");
93
80
 
94
- # Append args to each script call
95
- bw run my-script --args "--my --args"
81
+ // Array of workspaces whose names match the wildcard pattern
82
+ const wildcardWorkspaces = project.findWorkspacesByPattern("my-workspace-*");
96
83
 
97
- # Use the workspace name in args
98
- bw run my-script --args "--my --args=<workspace>"
84
+ // Array of workspaces that have "my-script" in their package.json "scripts"
85
+ const workspacesWithScript = project.listWorkspacesWithScript("my-script");
99
86
 
100
- # Help (--help can also be passed to any command)
101
- bw help
102
- bw --help
87
+ // Run a script in a workspace
88
+ const runSingleScript = async () => {
89
+ const { output, exit } = project.runWorkspaceScript({
90
+ workspaceNameOrAlias: "my-workspace",
91
+ script: "my-script",
92
+ args: "--my --appended --args", // optional, arguments to add to the command
93
+ });
103
94
 
104
- # Pass --cwd to any command
105
- bw --cwd /path/to/your/project ls
106
- bw --cwd /path/to/your/project run-script my-script
95
+ // Get a stream of the script subprocess's output
96
+ for await (const { text, textNoAnsi, streamName } of output) {
97
+ console.log(text); // The output chunk's content (string)
98
+ console.log(textNoAnsi); // Text with ANSI codes sanitized (string)
99
+ console.log(streamName); // The output stream, "stdout" or "stderr"
100
+ }
107
101
 
108
- # Pass --configFile to any command
109
- bw --configFile /path/to/your/config.json ls
102
+ // Get data about the script execution after it exits
103
+ const exitResult = await exit;
104
+
105
+ console.log(exitResult.exitCode); // The exit code (number)
106
+ console.log(exitResult.signal); // The exit signal (string), or null
107
+ console.log(exitResult.success); // true if exit code was 0
108
+ console.log(exitResult.startTimeISO); // Start time (string)
109
+ console.log(exitResult.endTimeISO); // End time (string)
110
+ console.log(exitResult.durationMs); // Duration in milliseconds (number)
111
+ console.log(exitResult.metadata.workspace); // The target workspace (Workspace)
112
+ };
113
+
114
+ // Run a script in all workspaces that have it in their package.json "scripts" field
115
+ const runManyScripts = async () => {
116
+ const { output, summary } = project.runScriptAcrossWorkspaces({
117
+ workspacePatterns: ["*"], // this will run in all workspaces that have my-script
118
+ script: "my-script", // the package.json "scripts" field name to run
119
+ args: "--my --appended --args", // optional, arguments to add to the command
120
+ parallel: true, // optional, run the scripts in parallel
121
+ });
122
+
123
+ // Get a stream of script output
124
+ for await (const { outputChunk, scriptMetadata } of output) {
125
+ console.log(outputChunk.text); // the output chunk's content (string)
126
+ console.log(outputChunk.textNoAnsi); // text with ANSI codes sanitized (string)
127
+ console.log(outputChunk.streamName); // "stdout" or "stderr"
128
+
129
+ // The metadata can distinguish which workspace script
130
+ // the current output chunk came from
131
+ console.log(scriptMetadata.workspace); // Workspace object
132
+ }
110
133
 
111
- # Pass --logLevel to any command (debug, info, warn, error, or silent)
112
- bw --logLevel silent run my-script
134
+ // Get final summary data and script exit details after all scripts have completed
135
+ const summaryResult = await summary;
136
+
137
+ console.log(summaryResult.totalCount); // Total number of scripts
138
+ console.log(summaryResult.allSuccess); // true if all scripts succeeded
139
+ console.log(summaryResult.successCount); // Number of scripts that succeeded
140
+ console.log(summaryResult.failureCount); // Number of scripts that failed
141
+ console.log(summaryResult.startTimeISO); // Start time (string)
142
+ console.log(summaryResult.endTimeISO); // End time (string)
143
+ console.log(summaryResult.durationMs); // Total duration in milliseconds (number)
144
+
145
+ // The exit details of each workspace script
146
+ for (const exitResult of summaryResult.scriptResults) {
147
+ console.log(exitResult.exitCode); // The exit code (number)
148
+ console.log(exitResult.signal); // The exit signal (string), or null
149
+ console.log(exitResult.success); // true if exit code was 0
150
+ console.log(exitResult.startTimeISO); // Start time (ISO string)
151
+ console.log(exitResult.endTimeISO); // End time (ISO string)
152
+ console.log(exitResult.durationMs); // Duration in milliseconds (number)
153
+ console.log(exitResult.metadata.workspace); // The target workspace (Workspace)
154
+ }
155
+ };
113
156
  ```
157
+
158
+ _`bun-workspaces` is independent from the [Bun](https://bun.sh) project and is not affiliated with or endorsed by Oven. This project aims to enhance enhance the experience of Bun for its users._
package/bin/cli.js CHANGED
@@ -1,4 +1,3 @@
1
1
  #!/usr/bin/env bun
2
- import { createCli } from "bun-workspaces";
3
-
2
+ import { createCli } from "bun-workspaces/src/cli";
4
3
  createCli().run();
package/package.json CHANGED
@@ -1,40 +1,26 @@
1
1
  {
2
2
  "name": "bun-workspaces",
3
- "version": "1.0.0-alpha.2",
4
- "main": "src/index.ts",
5
- "homepage": "https://github.com/ScottMorse/bun-workspaces#readme",
3
+ "version": "1.0.0-alpha.20",
4
+ "license": "MIT",
5
+ "main": "src/index.mjs",
6
+ "types": "src/index.d.ts",
7
+ "homepage": "https://bunworkspaces.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/ScottMorse/bun-workspaces.git"
11
+ },
6
12
  "bin": {
7
- "bun-workspaces": "bin/cli.js"
13
+ "bun-workspaces": "bin/cli.js",
14
+ "bw": "bin/cli.js"
8
15
  },
9
16
  "custom": {
10
17
  "bunVersion": {
11
- "build": "1.2.22",
18
+ "build": "1.3.1",
12
19
  "libraryConsumer": "^1.1.x"
13
20
  }
14
21
  },
15
- "scripts": {
16
- "cli": "bun run bin/cli.js",
17
- "cli:dev": "_BW_RUNTIME_MODE=development bun run bin/cli.js",
18
- "type-check": "tsc --noEmit",
19
- "lint": "eslint .",
20
- "format": "prettier --write .",
21
- "format-check": "prettier --check ."
22
- },
23
- "devDependencies": {
24
- "@types/bun": "^1.2.22",
25
- "@typescript-eslint/eslint-plugin": "^8.44.1",
26
- "@typescript-eslint/parser": "^8.44.1",
27
- "bun-workspaces": "file:.",
28
- "eslint": "^9.36.0",
29
- "eslint-plugin-import": "^2.32.0",
30
- "prettier": "^3.6.2",
31
- "typescript-eslint": "^8.44.1"
32
- },
33
22
  "dependencies": {
34
23
  "commander": "^12.1.0",
35
- "glob": "^11.0.3"
36
- },
37
- "peerDependencies": {
38
- "typescript": "^5.9.2"
24
+ "glob": "^11.1.0"
39
25
  }
40
26
  }
@@ -0,0 +1,19 @@
1
+ import { type Command } from "commander";
2
+ export interface RunCliOptions {
3
+ argv?: string | string[];
4
+ /** Should be `true` if args do not include the binary name (e.g. `bunx bun-workspaces`) */
5
+ programmatic?: true;
6
+ }
7
+ export interface CLI {
8
+ run: (options?: RunCliOptions) => Promise<void>;
9
+ }
10
+ export interface CreateCliOptions {
11
+ handleError?: (error: Error) => void;
12
+ postInit?: (program: Command) => unknown;
13
+ defaultCwd?: string;
14
+ }
15
+ export declare const createCli: ({
16
+ handleError,
17
+ postInit,
18
+ defaultCwd,
19
+ }?: CreateCliOptions) => CLI;
@@ -0,0 +1,99 @@
1
+ import { createCommand } from "commander";
2
+ import package_0 from "../../package.json";
3
+ import {
4
+ getRequiredBunVersion,
5
+ validateCurrentBunVersion,
6
+ } from "../internal/bunVersion.mjs";
7
+ import { BunWorkspacesError } from "../internal/error.mjs";
8
+ import { logger } from "../internal/logger.mjs";
9
+ import { fatalErrorLogger } from "./fatalErrorLogger.mjs";
10
+ import { initializeWithGlobalOptions } from "./globalOptions/index.mjs";
11
+ import { defineProjectCommands } from "./projectCommands/index.mjs"; // CONCATENATED MODULE: external "commander"
12
+ // CONCATENATED MODULE: external "../../package.json"
13
+ // CONCATENATED MODULE: external "../internal/bunVersion.mjs"
14
+ // CONCATENATED MODULE: external "../internal/error.mjs"
15
+ // CONCATENATED MODULE: external "../internal/logger.mjs"
16
+ // CONCATENATED MODULE: external "./fatalErrorLogger.mjs"
17
+ // CONCATENATED MODULE: external "./globalOptions/index.mjs"
18
+ // CONCATENATED MODULE: external "./projectCommands/index.mjs"
19
+ // CONCATENATED MODULE: ./src/cli/createCli.ts
20
+
21
+ const createCli = ({
22
+ handleError,
23
+ postInit,
24
+ defaultCwd = process.cwd(),
25
+ } = {}) => {
26
+ const run = async ({ argv = process.argv, programmatic } = {}) => {
27
+ const errorListener =
28
+ handleError ??
29
+ ((error) => {
30
+ fatalErrorLogger.error(error);
31
+ process.exit(1);
32
+ });
33
+ process.on("unhandledRejection", errorListener);
34
+ try {
35
+ const program = createCommand("bunx bun-workspaces")
36
+ .description("A CLI on top of native Bun workspaces")
37
+ .version(package_0.version)
38
+ .showHelpAfterError(true);
39
+ postInit?.(program);
40
+ if (!validateCurrentBunVersion()) {
41
+ fatalErrorLogger.error(
42
+ `Bun version mismatch. Required: ${getRequiredBunVersion()}, Found: ${Bun.version}`,
43
+ );
44
+ process.exit(1);
45
+ }
46
+ const args = tempFixCamelCaseOptions(
47
+ typeof argv === "string" ? argv.split(/s+/) : argv,
48
+ );
49
+ const { project, error } = initializeWithGlobalOptions(
50
+ program,
51
+ args,
52
+ defaultCwd,
53
+ );
54
+ defineProjectCommands({
55
+ program,
56
+ project,
57
+ projectError: error,
58
+ });
59
+ await program.parseAsync(args, {
60
+ from: programmatic ? "user" : "node",
61
+ });
62
+ if (error) throw error;
63
+ } catch (error) {
64
+ if (error instanceof BunWorkspacesError) {
65
+ logger.debug(error);
66
+ fatalErrorLogger.error(error.message);
67
+ process.exit(1);
68
+ } else {
69
+ errorListener(error);
70
+ }
71
+ } finally {
72
+ process.off("unhandledRejection", errorListener);
73
+ }
74
+ };
75
+ return {
76
+ run,
77
+ };
78
+ };
79
+ /**
80
+ * @todo
81
+ * ! Temp backwards support for deprecated camel case options
82
+ * ! Added October 2025, drop support in some reasonable future release
83
+ */ const tempOptions = {
84
+ "--nameOnly": "--name-only",
85
+ "--noPrefix": "--no-prefix",
86
+ "--configFile": "--config-file",
87
+ "--logLevel": "--log-level",
88
+ };
89
+ const tempFixCamelCaseOptions = (args) =>
90
+ args.map((arg) => {
91
+ for (const [camel, kebab] of Object.entries(tempOptions)) {
92
+ if (arg.startsWith(camel)) {
93
+ return arg.replace(camel, kebab);
94
+ }
95
+ }
96
+ return arg;
97
+ });
98
+
99
+ export { createCli };
@@ -0,0 +1 @@
1
+ export declare const fatalErrorLogger: import("../internal/logger").Logger;
@@ -0,0 +1,7 @@
1
+ import { createLogger } from "../internal/logger.mjs"; // CONCATENATED MODULE: external "../internal/logger.mjs"
2
+ // CONCATENATED MODULE: ./src/cli/fatalErrorLogger.ts
3
+
4
+ const fatalErrorLogger = createLogger("fatalError");
5
+ fatalErrorLogger.printLevel = "error";
6
+
7
+ export { fatalErrorLogger };
@@ -0,0 +1,38 @@
1
+ import { type Command } from "commander";
2
+ export declare const initializeWithGlobalOptions: (
3
+ program: Command,
4
+ args: string[],
5
+ defaultCwd: string,
6
+ ) => {
7
+ project: import("../../internal/types").Simplify<{
8
+ readonly rootDirectory: string;
9
+ readonly workspaces: import("../..").Workspace[];
10
+ readonly name: string;
11
+ readonly sourceType: "fileSystem";
12
+ runWorkspaceScript(
13
+ options: import("../..").RunWorkspaceScriptOptions,
14
+ ): import("../..").RunWorkspaceScriptResult;
15
+ runScriptAcrossWorkspaces(
16
+ options: import("../..").RunScriptAcrossWorkspacesOptions,
17
+ ): import("../..").RunScriptAcrossWorkspacesResult;
18
+ listWorkspacesWithScript(scriptName: string): import("../..").Workspace[];
19
+ mapScriptsToWorkspaces(): Record<
20
+ string,
21
+ import("../..").WorkspaceScriptMetadata
22
+ >;
23
+ findWorkspaceByName(
24
+ workspaceName: string,
25
+ ): import("../..").Workspace | null;
26
+ findWorkspaceByAlias(alias: string): import("../..").Workspace | null;
27
+ findWorkspaceByNameOrAlias(
28
+ nameOrAlias: string,
29
+ ): import("../..").Workspace | null;
30
+ findWorkspacesByPattern(
31
+ workspacePattern: string,
32
+ ): import("../..").Workspace[];
33
+ createScriptCommand(
34
+ options: import("../..").CreateProjectScriptCommandOptions,
35
+ ): import("../..").CreateProjectScriptCommandResult;
36
+ }>;
37
+ error: Error | null;
38
+ };
@@ -0,0 +1,120 @@
1
+ import node_fs from "node:fs";
2
+ import node_path from "node:path";
3
+ import { Option } from "commander";
4
+ import {
5
+ DEFAULT_CONFIG_FILE_PATH,
6
+ loadConfigFile,
7
+ } from "../../config/index.mjs";
8
+ import { defineErrors } from "../../internal/error.mjs";
9
+ import { logger } from "../../internal/logger.mjs";
10
+ import {
11
+ _internalCreateFileSystemProject,
12
+ createMemoryProject,
13
+ } from "../../project/index.mjs";
14
+ import { getCliGlobalOptionConfig } from "./globalOptionsConfig.mjs"; // CONCATENATED MODULE: external "node:fs"
15
+ // CONCATENATED MODULE: external "node:path"
16
+ // CONCATENATED MODULE: external "commander"
17
+ // CONCATENATED MODULE: external "../../config/index.mjs"
18
+ // CONCATENATED MODULE: external "../../internal/error.mjs"
19
+ // CONCATENATED MODULE: external "../../internal/logger.mjs"
20
+ // CONCATENATED MODULE: external "../../project/index.mjs"
21
+ // CONCATENATED MODULE: external "./globalOptionsConfig.mjs"
22
+ // CONCATENATED MODULE: ./src/cli/globalOptions/globalOptions.ts
23
+
24
+ const ERRORS = defineErrors(
25
+ "WorkingDirectoryNotFound",
26
+ "WorkingDirectoryNotADirectory",
27
+ );
28
+ const addGlobalOption = (program, optionName, defaultOverride) => {
29
+ const { mainOption, shortOption, description, param, values, defaultValue } =
30
+ getCliGlobalOptionConfig(optionName);
31
+ let option = new Option(
32
+ `${shortOption} ${mainOption}${param ? ` <${param}>` : ""}`,
33
+ description,
34
+ );
35
+ const effectiveDefaultValue = defaultOverride ?? defaultValue;
36
+ if (effectiveDefaultValue) {
37
+ option = option.default(effectiveDefaultValue);
38
+ }
39
+ if (values?.length) {
40
+ option = option.choices(values);
41
+ }
42
+ program.addOption(option);
43
+ };
44
+ const getWorkingDirectoryFromArgs = (program, args, defaultCwd) => {
45
+ addGlobalOption(program, "cwd", defaultCwd);
46
+ program.parseOptions(args);
47
+ return program.opts().cwd;
48
+ };
49
+ const getConfigFileFromArgs = (program, args) => {
50
+ addGlobalOption(program, "configFile");
51
+ program.parseOptions(args);
52
+ return program.opts().configFile;
53
+ };
54
+ const defineGlobalOptions = (program, args, defaultCwd) => {
55
+ const cwd = getWorkingDirectoryFromArgs(program, args, defaultCwd);
56
+ if (!node_fs.existsSync(cwd)) {
57
+ throw new ERRORS.WorkingDirectoryNotFound(
58
+ `Working directory not found at path "${cwd}"`,
59
+ );
60
+ }
61
+ if (!node_fs.statSync(cwd).isDirectory()) {
62
+ throw new ERRORS.WorkingDirectoryNotADirectory(
63
+ `Working directory is not a directory at path "${cwd}"`,
64
+ );
65
+ }
66
+ const configFilePath = getConfigFileFromArgs(program, args);
67
+ const config = loadConfigFile(configFilePath, cwd);
68
+ if (config) {
69
+ logger.warn(
70
+ // TODO link to docs
71
+ `Using the config file at ${configFilePath || DEFAULT_CONFIG_FILE_PATH} is deprecated. Migrate to the new workspace config file.`,
72
+ );
73
+ }
74
+ addGlobalOption(program, "logLevel");
75
+ return {
76
+ cwd,
77
+ config,
78
+ };
79
+ };
80
+ const applyGlobalOptions = (options, config) => {
81
+ logger.printLevel = options.logLevel;
82
+ logger.debug("Log level: " + options.logLevel);
83
+ let project;
84
+ let error = null;
85
+ try {
86
+ project = _internalCreateFileSystemProject({
87
+ rootDirectory: options.cwd,
88
+ workspaceAliases: config?.project?.workspaceAliases ?? {},
89
+ });
90
+ logger.debug(
91
+ `Project: ${JSON.stringify(project.name)} (${project.workspaces.length} workspace${project.workspaces.length === 1 ? "" : "s"})`,
92
+ );
93
+ logger.debug("Project root: " + node_path.resolve(project.rootDirectory));
94
+ } catch (_error) {
95
+ error = _error;
96
+ project = createMemoryProject({
97
+ workspaces: [],
98
+ });
99
+ }
100
+ return {
101
+ project,
102
+ error,
103
+ };
104
+ };
105
+ const initializeWithGlobalOptions = (program, args, defaultCwd) => {
106
+ program.allowUnknownOption(true);
107
+ const { cwd, config } = defineGlobalOptions(program, args, defaultCwd);
108
+ program.parseOptions(args);
109
+ program.allowUnknownOption(false);
110
+ const options = program.opts();
111
+ return applyGlobalOptions(
112
+ {
113
+ ...options,
114
+ cwd,
115
+ },
116
+ config,
117
+ );
118
+ };
119
+
120
+ export { initializeWithGlobalOptions };
@@ -0,0 +1,43 @@
1
+ import { type LogLevelSetting } from "../../internal/logger";
2
+ export interface CliGlobalOptions {
3
+ logLevel: LogLevelSetting;
4
+ cwd: string;
5
+ configFile?: string;
6
+ }
7
+ export interface CliGlobalOptionConfig {
8
+ mainOption: string;
9
+ shortOption: string;
10
+ description: string;
11
+ defaultValue: string;
12
+ values: LogLevelSetting[] | null;
13
+ param: string;
14
+ }
15
+ export type CliGlobalOptionName = keyof CliGlobalOptions;
16
+ export declare const getCliGlobalOptionConfig: (
17
+ optionName: CliGlobalOptionName,
18
+ ) =>
19
+ | {
20
+ readonly mainOption: "--log-level";
21
+ readonly shortOption: "-l";
22
+ readonly description: "Log levels";
23
+ readonly defaultValue: "info";
24
+ readonly values: ["debug", "info", "warn", "error", "silent"];
25
+ readonly param: "level";
26
+ }
27
+ | {
28
+ readonly mainOption: "--cwd";
29
+ readonly shortOption: "-d";
30
+ readonly description: "Working directory";
31
+ readonly defaultValue: ".";
32
+ readonly values: null;
33
+ readonly param: "path";
34
+ }
35
+ | {
36
+ readonly mainOption: "--config-file";
37
+ readonly shortOption: "-c";
38
+ readonly description: "(DEPRECATED) Config file";
39
+ readonly defaultValue: "";
40
+ readonly values: null;
41
+ readonly param: "path";
42
+ };
43
+ export declare const getCliGlobalOptionNames: () => CliGlobalOptionName[];