bun-workspaces 1.6.0 → 1.8.0
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/README.md +1 -8
- package/package.json +5 -1
- package/src/2392.mjs +1 -1
- package/src/{1108.mjs → 3725.mjs} +11 -4
- package/src/ai/mcp/bwMcpServer.mjs +23 -313
- package/src/ai/mcp/resources.mjs +27 -19
- package/src/ai/mcp/serverState.mjs +20 -0
- package/src/ai/mcp/tools.mjs +51 -13
- package/src/cli/commands/mcp.mjs +10 -5
- package/src/cli/createCli.mjs +4 -5
- package/src/cli/globalOptions/globalOptions.mjs +1 -0
- package/src/cli/index.d.ts +5 -3
- package/src/internal/generated/aiDocs/docs.mjs +19 -3
- package/src/project/implementations/fileSystemProject.mjs +24 -13
- package/src/runScript/index.mjs +1 -1
- package/src/runScript/public.d.ts +42 -0
- package/src/runScript/public.mjs +1 -0
- package/src/runScript/recursion.mjs +3 -3
- package/src/runScript/workspaceScriptMetadata.mjs +60 -0
- package/src/runScript/scriptRuntimeMetadata.mjs +0 -43
package/README.md
CHANGED
|
@@ -6,20 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
### [**See Full Documentation Here**: _https://bunworkspaces.com_](https://bunworkspaces.com)
|
|
8
8
|
|
|
9
|
-
**Big Recent Updates!**
|
|
10
|
-
|
|
11
|
-
- Version 1 is here after the initial alpha! 🍔🍔👁️🍔🍔
|
|
12
|
-
- You can demo the CLI [directly in the browser](https://bunworkspaces.com/web-cli)
|
|
13
|
-
- There's now [an official blog](https://bunworkspaces.com/blog/bun-workspaces-v1) to cover noteworthy releases and more!
|
|
14
|
-
- There's now a provided [MCP server](https://bunworkspaces.com/ai/mcp) for your AI tooling to understand how to use `bun-workspaces`!
|
|
15
|
-
<hr/>
|
|
16
|
-
|
|
17
9
|
This is a CLI and TypeScript API to enhance your monorepo development with Bun's [native workspaces](https://bun.sh/docs/install/workspaces) feature for nested JavaScript/TypeScript packages.
|
|
18
10
|
|
|
19
11
|
- Works right away, with no boilerplate required 🍔🍴
|
|
20
12
|
- Get metadata about your monorepo 🤖
|
|
21
13
|
- Orchestrate your workspaces' `package.json` scripts 📋
|
|
22
14
|
- Run inline [Bun Shell](https://bun.com/docs/runtime/shell) scripts in workspaces 🐚
|
|
15
|
+
Use the [MCP server](https://bunworkspaces.com/ai/mcp) for your AI tooling to learn how to use `bun-workspaces` and add project metadata to context! 🛠️
|
|
23
16
|
|
|
24
17
|
This is a tool to help manage a Bun monorepo, offering features beyond what [Bun's --filter feature](https://bun.com/docs/pm/filter) can do. It can be used to get a variety of metadata about your project and run scripts across your workspaces with advanced control.
|
|
25
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bun-workspaces",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "A monorepo management tool for Bun, with a CLI and API to enhance Bun's native workspaces.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"./config": {
|
|
16
16
|
"types": "./src/config/public.d.ts",
|
|
17
17
|
"default": "./src/config/public.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./script": {
|
|
20
|
+
"types": "./src/runScript/public.d.ts",
|
|
21
|
+
"default": "./src/runScript/public.mjs"
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
"types": "./src/index.d.ts",
|
package/src/2392.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const WORKSPACE_SCRIPT_METADATA_CONFIG = {
|
|
2
2
|
projectPath: {
|
|
3
3
|
inlineName: "<projectPath>",
|
|
4
4
|
envVarName: "BW_PROJECT_PATH",
|
|
@@ -24,7 +24,14 @@ const SCRIPT_RUNTIME_METADATA_CONFIG = {
|
|
|
24
24
|
envVarName: "BW_WORKSPACE_NAME",
|
|
25
25
|
},
|
|
26
26
|
};
|
|
27
|
-
const
|
|
28
|
-
|
|
27
|
+
const validateWorkspaceScriptMetadataKey = (key) => {
|
|
28
|
+
if (!(key in WORKSPACE_SCRIPT_METADATA_CONFIG)) {
|
|
29
|
+
throw new Error(`Invalid workspace script metadata key: ${key}`);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const getWorkspaceScriptMetadataConfig = (key) => {
|
|
33
|
+
validateWorkspaceScriptMetadataKey(key);
|
|
34
|
+
return WORKSPACE_SCRIPT_METADATA_CONFIG[key];
|
|
35
|
+
};
|
|
29
36
|
|
|
30
|
-
export {
|
|
37
|
+
export { getWorkspaceScriptMetadataConfig };
|
|
@@ -1,336 +1,46 @@
|
|
|
1
1
|
import package_0 from "../../../package.json";
|
|
2
2
|
import { createMcpServer } from "./core/index.mjs";
|
|
3
3
|
import { registerBwResources } from "./resources.mjs";
|
|
4
|
+
import { setServerWorkingDirectory } from "./serverState.mjs";
|
|
4
5
|
import { registerBwTools } from "./tools.mjs";
|
|
5
6
|
|
|
6
|
-
const CLI_QUICKSTART = `
|
|
7
|
-
# You can add this to .bashrc, .zshrc, or similar.
|
|
8
|
-
# You can also invoke "bw" in your root package.json scripts.
|
|
9
|
-
alias bw="bunx bun-workspaces"
|
|
10
|
-
|
|
11
|
-
# List all workspaces in your project
|
|
12
|
-
bw list-workspaces
|
|
13
|
-
|
|
14
|
-
# ls is an alias for list-workspaces
|
|
15
|
-
bw ls --json --pretty # Output as formatted JSON
|
|
16
|
-
|
|
17
|
-
# Get info about a workspace
|
|
18
|
-
bw workspace-info my-workspace
|
|
19
|
-
bw info my-workspace --json --pretty # info is alias for workspace-info
|
|
20
|
-
|
|
21
|
-
# Get info about a script, such as the workspaces that have it
|
|
22
|
-
bw script-info my-script
|
|
23
|
-
|
|
24
|
-
# Run the lint script for all workspaces
|
|
25
|
-
# that have it in their package.json "scripts" field
|
|
26
|
-
bw run-script lint
|
|
27
|
-
|
|
28
|
-
# run is an alias for run-script
|
|
29
|
-
bw run lint my-workspace # Run for a single workspace
|
|
30
|
-
bw run lint my-workspace-a my-workspace-b # Run for multiple workspaces
|
|
31
|
-
bw run lint my-alias-a my-alias-b # Run by alias (set by optional config)
|
|
32
|
-
|
|
33
|
-
# A workspace's script will wait until any workspaces it depends on have completed
|
|
34
|
-
# Similar to Bun's --filter behavior
|
|
35
|
-
bw run lint --dep-order
|
|
36
|
-
|
|
37
|
-
# Continue running scripts even if a dependency fails
|
|
38
|
-
bw run lint --dep-order --ignore-dep-failure
|
|
39
|
-
|
|
40
|
-
bw run lint "my-workspace-*" # Run for matching workspace names
|
|
41
|
-
bw run lint "alias:my-alias-*" "path:my-glob/**/*" "tag:my-tag" # Use matching specifiers
|
|
42
|
-
bw run lint "*" "not:path:my-path/*" # Run for all workspaces not in my-path/
|
|
43
|
-
|
|
44
|
-
bw run lint --args="--my-appended-args" # Add args to each script call
|
|
45
|
-
bw run lint --args="--my-arg=<workspaceName>" # Use the workspace name in args
|
|
46
|
-
|
|
47
|
-
bw run "bun build" --inline # Run an inline command via the Bun shell
|
|
48
|
-
|
|
49
|
-
# Scripts run in parallel by default
|
|
50
|
-
bw run lint --parallel=false # Run in series
|
|
51
|
-
bw run lint --parallel=2 # Run in parallel with a max of 2 concurrent scripts
|
|
52
|
-
bw run lint --parallel=auto # Default, based on number of available logical CPUs
|
|
53
|
-
bw run lint --parallel=50% # Run in parallel with a max of 50% of the "auto" limit
|
|
54
|
-
|
|
55
|
-
# Use the grouped output style (default when on a TTY)
|
|
56
|
-
bw run my-script --output-style=grouped
|
|
57
|
-
|
|
58
|
-
# Set the max preview lines for script output in grouped output style
|
|
59
|
-
bw run my-script --output-style=grouped --grouped-lines=auto
|
|
60
|
-
bw run my-script --output-style=grouped --grouped-lines=10
|
|
61
|
-
|
|
62
|
-
# Use simple script output with workspace prefixes (default when not on a TTY)
|
|
63
|
-
bw run my-script --output-style=prefixed
|
|
64
|
-
|
|
65
|
-
# Use the plain output style (no workspace prefixes)
|
|
66
|
-
bw run my-script --output-style=plain
|
|
67
|
-
|
|
68
|
-
# Silence all output of the run command
|
|
69
|
-
bw --log-level=silent run my-script --output-style=none
|
|
70
|
-
|
|
71
|
-
# Show usage (you can pass --help to any command)
|
|
72
|
-
bw help
|
|
73
|
-
bw --help
|
|
74
|
-
|
|
75
|
-
# Show version
|
|
76
|
-
bw --version
|
|
77
|
-
|
|
78
|
-
# Pass --cwd to any command
|
|
79
|
-
bw --cwd=/path/to/your/project ls
|
|
80
|
-
bw --cwd=/path/to/your/project run my-script
|
|
81
|
-
|
|
82
|
-
# Pass --log-level to any command (debug, info, warn, error, or silent)
|
|
83
|
-
bw --log-level=debug ls
|
|
84
|
-
`.trim();
|
|
85
|
-
const INLINE_SCRIPT_EXAMPLE =
|
|
86
|
-
/* unused pure expression or super */ null &&
|
|
87
|
-
`
|
|
88
|
-
# Run an inline command from the workspace directory
|
|
89
|
-
bw run "bun run build" --inline
|
|
90
|
-
`.trim();
|
|
91
|
-
|
|
92
|
-
const RUN_WORKSPACE_SCRIPT_EXAMPLE = `
|
|
93
|
-
const { output, exit } = project.runWorkspaceScript({
|
|
94
|
-
workspaceNameOrAlias: "my-workspace",
|
|
95
|
-
script: "my-script",
|
|
96
|
-
|
|
97
|
-
// Optional. Arguments to add to the command
|
|
98
|
-
// Can be a string or an array of strings
|
|
99
|
-
// If string, the argv will be parsed POSIX-style
|
|
100
|
-
args: ["--my", "--appended", "--args"],
|
|
101
|
-
|
|
102
|
-
// Optional. Whether to ignore all output from the script.
|
|
103
|
-
// This saves memory when you don't need script output.
|
|
104
|
-
ignoreOutput: false,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Get a stream of the script subprocess's output
|
|
108
|
-
for await (const { chunk, metadata } of output.text()) {
|
|
109
|
-
// console.log(chunk); // The output chunk's content (string)
|
|
110
|
-
// console.log(metadata.streamName); // The output stream, "stdout" or "stderr"
|
|
111
|
-
// console.log(metadata.workspace); // The target Workspace
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Get data about the script execution after it exits
|
|
115
|
-
const exitResult = await exit;
|
|
116
|
-
|
|
117
|
-
// exitResult.exitCode // The exit code (number)
|
|
118
|
-
// exitResult.signal // The exit signal (string), or null
|
|
119
|
-
// exitResult.success // true if exit code was 0
|
|
120
|
-
// exitResult.startTimeISO // Start time (string)
|
|
121
|
-
// exitResult.endTimeISO // End time (string)
|
|
122
|
-
// exitResult.durationMs // Duration in milliseconds (number)
|
|
123
|
-
// exitResult.metadata.workspace // The target workspace (Workspace)
|
|
124
|
-
|
|
125
|
-
`.trim();
|
|
126
|
-
const RUN_SCRIPT_ACROSS_WORKSPACES_EXAMPLE = `
|
|
127
|
-
|
|
128
|
-
const { output, summary } = project.runScriptAcrossWorkspaces({
|
|
129
|
-
// Optional. This will run in all matching workspaces that have my-script
|
|
130
|
-
// Accepts same values as the CLI run-script command's workspace patterns
|
|
131
|
-
// When not provided, all workspaces that have the script will be used.
|
|
132
|
-
workspacePatterns: ["my-workspace", "my-name-pattern-*"],
|
|
133
|
-
|
|
134
|
-
// Required. The package.json "scripts" field name to run
|
|
135
|
-
script: "my-script",
|
|
136
|
-
|
|
137
|
-
// Optional. Arguments to add to the command (same as for runWorkspaceScript)
|
|
138
|
-
args: ["--my", "--appended", "--args"],
|
|
139
|
-
|
|
140
|
-
// Optional. Whether to run the scripts in parallel (default: true)
|
|
141
|
-
parallel: true,
|
|
142
|
-
|
|
143
|
-
// Optional. When true, a workspace's script will wait
|
|
144
|
-
// until any workspaces it depends on have completed
|
|
145
|
-
dependencyOrder: false,
|
|
146
|
-
|
|
147
|
-
// Optional. When true and dependencyOrder is true,
|
|
148
|
-
// continue running scripts even if a dependency fails
|
|
149
|
-
ignoreDependencyFailure: false,
|
|
150
|
-
|
|
151
|
-
// Optional. Whether to ignore all output from the scripts.
|
|
152
|
-
// This saves memory when you don't need script output.
|
|
153
|
-
ignoreOutput: false,
|
|
154
|
-
|
|
155
|
-
// Optional, callback when script starts, skips, or exits
|
|
156
|
-
onScriptEvent: (event, { workspace, exitResult }) => {
|
|
157
|
-
// event: "start", "skip", "exit"
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Get a stream of script output
|
|
162
|
-
for await (const { chunk, metadata } of output.text()) {
|
|
163
|
-
// console.log(chunk); // the output chunk's content (string)
|
|
164
|
-
// console.log(metadata.streamName); // "stdout" or "stderr"
|
|
165
|
-
// console.log(metadata.workspace); // the Workspace that the output came from
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Get final summary data and script exit details after all scripts have completed
|
|
169
|
-
const summaryResult = await summary;
|
|
170
|
-
|
|
171
|
-
// summaryResult.totalCount // Total number of scripts
|
|
172
|
-
// summaryResult.allSuccess // true if all scripts succeeded
|
|
173
|
-
// summaryResult.successCount // Number of scripts that succeeded
|
|
174
|
-
// summaryResult.failureCount // Number of scripts that failed
|
|
175
|
-
// summaryResult.startTimeISO // Start time (string)
|
|
176
|
-
// summaryResult.endTimeISO // End time (string)
|
|
177
|
-
// summaryResult.durationMs // Total duration in milliseconds (number)
|
|
178
|
-
|
|
179
|
-
// The exit details of each workspace script
|
|
180
|
-
for (const exitResult of summaryResult.scriptResults) {
|
|
181
|
-
// exitResult.exitCode // The exit code (number)
|
|
182
|
-
// exitResult.signal // The exit signal (string), or null
|
|
183
|
-
// exitResult.success // true if exit code was 0
|
|
184
|
-
// exitResult.startTimeISO // Start time (ISO string)
|
|
185
|
-
// exitResult.endTimeISO // End time (ISO string)
|
|
186
|
-
// exitResult.durationMs // Duration in milliseconds (number)
|
|
187
|
-
// exitResult.metadata.workspace // The target workspace (Workspace)
|
|
188
|
-
}
|
|
189
|
-
`.trim();
|
|
190
|
-
const API_QUICKSTART = `
|
|
191
|
-
import { createFileSystemProject } from "bun-workspaces";
|
|
192
|
-
|
|
193
|
-
// A Project contains the core functionality of bun-workspaces.
|
|
194
|
-
// Below defaults to process.cwd() for the project root directory
|
|
195
|
-
// Pass { rootDirectory: "path/to/your/project" } to use a different root directory
|
|
196
|
-
const project = createFileSystemProject();
|
|
197
|
-
|
|
198
|
-
// A Workspace that matches the name or alias "my-workspace"
|
|
199
|
-
const myWorkspace = project.findWorkspaceByNameOrAlias("my-workspace");
|
|
200
|
-
|
|
201
|
-
// Array of workspaces whose names match the wildcard pattern
|
|
202
|
-
const wildcardWorkspaces = project.findWorkspacesByPattern("my-workspace-*");
|
|
203
|
-
|
|
204
|
-
// Array of workspaces that have "my-script" in their package.json "scripts"
|
|
205
|
-
const workspacesWithScript = project.listWorkspacesWithScript("my-script");
|
|
206
|
-
|
|
207
|
-
// Run a script in a workspace
|
|
208
|
-
const runSingleScript = async () => {
|
|
209
|
-
${RUN_WORKSPACE_SCRIPT_EXAMPLE.split("\n").join("\n ")}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Run a script in all workspaces that have it in their package.json "scripts" field
|
|
213
|
-
const runManyScripts = async () => {
|
|
214
|
-
${RUN_SCRIPT_ACROSS_WORKSPACES_EXAMPLE.split("\n").join("\n ")}
|
|
215
|
-
}
|
|
216
|
-
`.trim();
|
|
217
|
-
|
|
218
|
-
const ROOT_CONFIG_QUICKSTART = `
|
|
219
|
-
// bw.root.ts — place in your project root directory
|
|
220
|
-
// Also supported: bw.root.js, bw.root.json, bw.root.jsonc, or a "bw" key in package.json
|
|
221
|
-
import { defineRootConfig } from "bun-workspaces/config";
|
|
222
|
-
|
|
223
|
-
export default defineRootConfig({
|
|
224
|
-
defaults: {
|
|
225
|
-
// default value for --parallel option
|
|
226
|
-
parallelMax: 4,
|
|
227
|
-
// default value for --shell option
|
|
228
|
-
shell: "system",
|
|
229
|
-
// default value for global --include-root-workspace option
|
|
230
|
-
includeRootWorkspace: false,
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
// Apply workspace configs in bulk by workspace pattern, in order.
|
|
234
|
-
// Each entry merges into matching workspaces' accumulated config.
|
|
235
|
-
// Pattern matching reflects aliases and tags added by earlier entries.
|
|
236
|
-
workspacePatternConfigs: [
|
|
237
|
-
{
|
|
238
|
-
patterns: ["path:packages/apps/**/*"],
|
|
239
|
-
config: { tags: ["app"] },
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
patterns: ["path:packages/libs/**/*"],
|
|
243
|
-
config: { tags: ["lib"] },
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
// "tag:app" matches because the first entry added it
|
|
247
|
-
patterns: ["tag:app"],
|
|
248
|
-
config: {
|
|
249
|
-
rules: {
|
|
250
|
-
workspaceDependencies: {
|
|
251
|
-
allowPatterns: ["tag:lib"], // apps may only depend on libs
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
patterns: ["tag:app"],
|
|
258
|
-
// Factory form: receives static workspace data and accumulated config
|
|
259
|
-
config: (workspace, prevConfig) => ({
|
|
260
|
-
alias: workspace.name.replace(/^@my-scope\\//, ""),
|
|
261
|
-
}),
|
|
262
|
-
},
|
|
263
|
-
],
|
|
264
|
-
});
|
|
265
|
-
`.trim();
|
|
266
|
-
const WORKSPACE_CONFIG_QUICKSTART = `
|
|
267
|
-
// bw.workspace.ts — place in a workspace directory
|
|
268
|
-
|
|
269
|
-
// Also supported: bw.workspace.js, bw.workspace.json, bw.workspace.jsonc, or a "bw" key in package.json
|
|
270
|
-
|
|
271
|
-
import { defineWorkspaceConfig } from "bun-workspaces/config";
|
|
272
|
-
|
|
273
|
-
export default defineWorkspaceConfig({
|
|
274
|
-
alias: "my-web-app", // shorthand name; use array for multiple
|
|
275
|
-
tags: ["app", "frontend"],
|
|
276
|
-
scripts: {
|
|
277
|
-
// lower order runs first in sequenced script execution
|
|
278
|
-
build: { order: 1 },
|
|
279
|
-
test: { order: 2 },
|
|
280
|
-
},
|
|
281
|
-
rules: {
|
|
282
|
-
workspaceDependencies: {
|
|
283
|
-
// Only "my-workspace" or workspaces tagged "lib" are allowed as dependencies
|
|
284
|
-
allowPatterns: ["tag:lib", "my-workspace"],
|
|
285
|
-
// Workspaces tagged "backend" are forbidden as dependencies
|
|
286
|
-
denyPatterns: ["tag:backend"],
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
`.trim();
|
|
291
|
-
|
|
292
7
|
const SERVER_INSTRUCTIONS = `
|
|
293
|
-
bun-workspaces MCP server: tools to query Bun monorepo workspace metadata and documentation resources for the bun-workspaces CLI and TypeScript API.
|
|
8
|
+
bun-workspaces ${package_0.version} MCP server: tools to query Bun monorepo workspace metadata and documentation resources for the bun-workspaces CLI and TypeScript API.
|
|
294
9
|
|
|
295
|
-
bun-workspaces is an npm package that works on top of Bun's native workspaces.
|
|
10
|
+
bun-workspaces is an npm package that works on top of Bun's native workspaces. It has a CLI and TS API.
|
|
296
11
|
|
|
297
|
-
|
|
12
|
+
Files such as bw.workspace.ts and bw.root.ts may be present for configuration.
|
|
298
13
|
|
|
299
|
-
|
|
14
|
+
Use resources for docs on the CLI and TS API, or get a project overview via bw://project.
|
|
15
|
+
bw://docs/overview, bw://docs/concepts, bw://docs/cli, bw://docs/api, and bw://docs/config cover most functionality.
|
|
300
16
|
|
|
301
|
-
|
|
17
|
+
Use the tools to get specific metadata about the project.
|
|
302
18
|
|
|
19
|
+
## CLI quickstart
|
|
303
20
|
\`\`\`bash
|
|
304
|
-
$
|
|
21
|
+
$ alias bw="bunx bun-workspaces"
|
|
22
|
+
$ bw --help # usage
|
|
23
|
+
$ # run is an alias for run-script
|
|
24
|
+
$ bw run lint # run the "lint" script for all workspaces that have it
|
|
25
|
+
$ bw run "echo inline script" --inline # run an inline command via the Bun shell
|
|
26
|
+
$ bw run lint my-workspace-a my-workspace-b # run for specific workspaces
|
|
27
|
+
$ bw run lint --dep-order # run the lint script for all workspaces, waiting for all dependencies to complete
|
|
28
|
+
$ bw run lint "my-workspace-*" # wildcard for workspace names
|
|
29
|
+
$ bw run lint "alias:my-alias-*" "path:packages/**/*" "not:path:my-path/*" # use workspace patterns
|
|
305
30
|
\`\`\`
|
|
306
31
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
\`\`\`typescript
|
|
310
|
-
${API_QUICKSTART}
|
|
311
|
-
\`\`\`
|
|
312
|
-
|
|
313
|
-
## Root config quickstart
|
|
314
|
-
|
|
315
|
-
\`\`\`typescript
|
|
316
|
-
${ROOT_CONFIG_QUICKSTART}
|
|
317
|
-
\`\`\`
|
|
318
|
-
|
|
319
|
-
## Workspace config quickstart
|
|
320
|
-
|
|
321
|
-
\`\`\`typescript
|
|
322
|
-
${WORKSPACE_CONFIG_QUICKSTART}
|
|
323
|
-
\`\`\`
|
|
32
|
+
(end bun-workspaces MCP instructions)
|
|
324
33
|
`.trim();
|
|
325
|
-
const startBwMcpServer = async (
|
|
34
|
+
const startBwMcpServer = async (options) => {
|
|
35
|
+
setServerWorkingDirectory(options.initialWorkingDirectory);
|
|
326
36
|
const server = createMcpServer({
|
|
327
37
|
name: "bun-workspaces",
|
|
328
38
|
version: package_0.version,
|
|
329
39
|
instructions: SERVER_INSTRUCTIONS,
|
|
330
40
|
});
|
|
331
|
-
registerBwTools(server
|
|
332
|
-
registerBwResources(server
|
|
41
|
+
registerBwTools(server);
|
|
42
|
+
registerBwResources(server);
|
|
333
43
|
await server.start();
|
|
334
44
|
};
|
|
335
45
|
|
|
336
|
-
export { startBwMcpServer };
|
|
46
|
+
export { SERVER_INSTRUCTIONS, startBwMcpServer };
|
package/src/ai/mcp/resources.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DOC_CONFIG,
|
|
6
6
|
DOC_OVERVIEW,
|
|
7
7
|
} from "../../internal/generated/aiDocs/docs.mjs";
|
|
8
|
+
import { getServerProject } from "./serverState.mjs";
|
|
8
9
|
|
|
9
10
|
const textResource = (uri, text) => ({
|
|
10
11
|
contents: [
|
|
@@ -15,7 +16,7 @@ const textResource = (uri, text) => ({
|
|
|
15
16
|
},
|
|
16
17
|
],
|
|
17
18
|
});
|
|
18
|
-
const registerBwResources = (server
|
|
19
|
+
const registerBwResources = (server) => {
|
|
19
20
|
server.registerResource(
|
|
20
21
|
{
|
|
21
22
|
uri: "bw://project",
|
|
@@ -24,23 +25,30 @@ const registerBwResources = (server, project) => {
|
|
|
24
25
|
"Overview of this bun-workspaces project: name, root directory, and all workspace metadata.",
|
|
25
26
|
mimeType: "application/json",
|
|
26
27
|
},
|
|
27
|
-
(uri) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
(uri) => {
|
|
29
|
+
const project = getServerProject();
|
|
30
|
+
const data = project
|
|
31
|
+
? {
|
|
32
|
+
available: true,
|
|
33
|
+
name: project.name,
|
|
34
|
+
rootDirectory: project.rootDirectory,
|
|
35
|
+
workspaces: project.workspaces,
|
|
36
|
+
}
|
|
37
|
+
: {
|
|
38
|
+
available: false,
|
|
39
|
+
message:
|
|
40
|
+
"No bun-workspaces project is available in the current directory.",
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
contents: [
|
|
44
|
+
{
|
|
45
|
+
uri,
|
|
46
|
+
mimeType: "application/json",
|
|
47
|
+
text: JSON.stringify(data, null, 2),
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
},
|
|
44
52
|
);
|
|
45
53
|
server.registerResource(
|
|
46
54
|
{
|
|
@@ -57,7 +65,7 @@ const registerBwResources = (server, project) => {
|
|
|
57
65
|
uri: "bw://docs/concepts",
|
|
58
66
|
name: "bun-workspaces concepts",
|
|
59
67
|
description:
|
|
60
|
-
"Workspace patterns, script
|
|
68
|
+
"Workspace patterns, workspace script metadata, and how to run scripts via the CLI.",
|
|
61
69
|
mimeType: "text/markdown",
|
|
62
70
|
},
|
|
63
71
|
(uri) => textResource(uri, DOC_CONCEPTS),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createFileSystemProject } from "../../project/implementations/fileSystemProject.mjs";
|
|
2
|
+
|
|
3
|
+
const SERVER_STATE = {
|
|
4
|
+
workingDirectory: null,
|
|
5
|
+
};
|
|
6
|
+
const setServerWorkingDirectory = (directory) => {
|
|
7
|
+
SERVER_STATE.workingDirectory = directory;
|
|
8
|
+
};
|
|
9
|
+
const getServerProject = () => {
|
|
10
|
+
if (!SERVER_STATE.workingDirectory) return null;
|
|
11
|
+
try {
|
|
12
|
+
return createFileSystemProject({
|
|
13
|
+
rootDirectory: SERVER_STATE.workingDirectory,
|
|
14
|
+
});
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { getServerProject, setServerWorkingDirectory };
|
package/src/ai/mcp/tools.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getDoctorInfo } from "../../doctor/index.mjs";
|
|
2
2
|
import { BUN_WORKSPACES_VERSION } from "../../internal/version.mjs";
|
|
3
|
+
import { getServerProject, setServerWorkingDirectory } from "./serverState.mjs";
|
|
3
4
|
|
|
4
5
|
const textResult = (data) => ({
|
|
5
6
|
content: [
|
|
@@ -18,7 +19,14 @@ const errorResult = (message) => ({
|
|
|
18
19
|
],
|
|
19
20
|
isError: true,
|
|
20
21
|
});
|
|
21
|
-
const
|
|
22
|
+
const NO_PROJECT_RESULT = errorResult(
|
|
23
|
+
"No bun-workspaces project is available in the current directory.",
|
|
24
|
+
);
|
|
25
|
+
const withProject = (handler) => (input) => {
|
|
26
|
+
const project = getServerProject();
|
|
27
|
+
return project ? handler(project, input) : NO_PROJECT_RESULT;
|
|
28
|
+
};
|
|
29
|
+
const registerBwTools = (server) => {
|
|
22
30
|
server.registerTool(
|
|
23
31
|
{
|
|
24
32
|
name: "version",
|
|
@@ -51,13 +59,13 @@ const registerBwTools = (server, project) => {
|
|
|
51
59
|
},
|
|
52
60
|
},
|
|
53
61
|
},
|
|
54
|
-
({ patterns }) => {
|
|
62
|
+
withProject((project, { patterns }) => {
|
|
55
63
|
const workspaces =
|
|
56
64
|
patterns && Array.isArray(patterns) && patterns.length > 0
|
|
57
65
|
? project.findWorkspacesByPattern(...patterns)
|
|
58
66
|
: project.workspaces;
|
|
59
67
|
return textResult(workspaces);
|
|
60
|
-
},
|
|
68
|
+
}),
|
|
61
69
|
);
|
|
62
70
|
server.registerTool(
|
|
63
71
|
{
|
|
@@ -76,7 +84,7 @@ const registerBwTools = (server, project) => {
|
|
|
76
84
|
required: ["nameOrAlias"],
|
|
77
85
|
},
|
|
78
86
|
},
|
|
79
|
-
({ nameOrAlias }) => {
|
|
87
|
+
withProject((project, { nameOrAlias }) => {
|
|
80
88
|
const name = nameOrAlias;
|
|
81
89
|
const workspace =
|
|
82
90
|
name === /* inlined export .ROOT_WORKSPACE_SELECTOR */ "@root"
|
|
@@ -86,7 +94,7 @@ const registerBwTools = (server, project) => {
|
|
|
86
94
|
return errorResult(`Workspace not found: "${name}"`);
|
|
87
95
|
}
|
|
88
96
|
return textResult(workspace);
|
|
89
|
-
},
|
|
97
|
+
}),
|
|
90
98
|
);
|
|
91
99
|
server.registerTool(
|
|
92
100
|
{
|
|
@@ -96,7 +104,7 @@ const registerBwTools = (server, project) => {
|
|
|
96
104
|
type: "object",
|
|
97
105
|
},
|
|
98
106
|
},
|
|
99
|
-
() => textResult(project.rootWorkspace),
|
|
107
|
+
withProject((project) => textResult(project.rootWorkspace)),
|
|
100
108
|
);
|
|
101
109
|
server.registerTool(
|
|
102
110
|
{
|
|
@@ -107,14 +115,14 @@ const registerBwTools = (server, project) => {
|
|
|
107
115
|
type: "object",
|
|
108
116
|
},
|
|
109
117
|
},
|
|
110
|
-
() => {
|
|
118
|
+
withProject((project) => {
|
|
111
119
|
const scriptMap = project.mapScriptsToWorkspaces();
|
|
112
120
|
const scripts = Object.values(scriptMap).map(({ name, workspaces }) => ({
|
|
113
121
|
name,
|
|
114
122
|
workspaces: workspaces.map((w) => w.name),
|
|
115
123
|
}));
|
|
116
124
|
return textResult(scripts);
|
|
117
|
-
},
|
|
125
|
+
}),
|
|
118
126
|
);
|
|
119
127
|
server.registerTool(
|
|
120
128
|
{
|
|
@@ -132,7 +140,7 @@ const registerBwTools = (server, project) => {
|
|
|
132
140
|
required: ["script"],
|
|
133
141
|
},
|
|
134
142
|
},
|
|
135
|
-
({ script }) => {
|
|
143
|
+
withProject((project, { script }) => {
|
|
136
144
|
const scriptMap = project.mapScriptsToWorkspaces();
|
|
137
145
|
const scriptMetadata = scriptMap[script];
|
|
138
146
|
if (!scriptMetadata) {
|
|
@@ -142,7 +150,7 @@ const registerBwTools = (server, project) => {
|
|
|
142
150
|
name: scriptMetadata.name,
|
|
143
151
|
workspaces: scriptMetadata.workspaces.map((w) => w.name),
|
|
144
152
|
});
|
|
145
|
-
},
|
|
153
|
+
}),
|
|
146
154
|
);
|
|
147
155
|
server.registerTool(
|
|
148
156
|
{
|
|
@@ -153,14 +161,14 @@ const registerBwTools = (server, project) => {
|
|
|
153
161
|
type: "object",
|
|
154
162
|
},
|
|
155
163
|
},
|
|
156
|
-
() => {
|
|
164
|
+
withProject((project) => {
|
|
157
165
|
const tagMap = project.mapTagsToWorkspaces();
|
|
158
166
|
const tags = Object.entries(tagMap).map(([tag, workspaces]) => ({
|
|
159
167
|
tag,
|
|
160
168
|
workspaces: workspaces.map((w) => w.name),
|
|
161
169
|
}));
|
|
162
170
|
return textResult(tags);
|
|
163
|
-
},
|
|
171
|
+
}),
|
|
164
172
|
);
|
|
165
173
|
server.registerTool(
|
|
166
174
|
{
|
|
@@ -178,7 +186,7 @@ const registerBwTools = (server, project) => {
|
|
|
178
186
|
required: ["tag"],
|
|
179
187
|
},
|
|
180
188
|
},
|
|
181
|
-
({ tag }) => {
|
|
189
|
+
withProject((project, { tag }) => {
|
|
182
190
|
const tagMap = project.mapTagsToWorkspaces();
|
|
183
191
|
const tagWorkspaces = tagMap[tag];
|
|
184
192
|
if (!tagWorkspaces) {
|
|
@@ -188,6 +196,36 @@ const registerBwTools = (server, project) => {
|
|
|
188
196
|
name: tag,
|
|
189
197
|
workspaces: tagWorkspaces.map((w) => w.name),
|
|
190
198
|
});
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
server.registerTool(
|
|
202
|
+
{
|
|
203
|
+
name: "set_working_directory",
|
|
204
|
+
description:
|
|
205
|
+
"Set the working directory used by this MCP server. All subsequent project queries will reflect the new directory.",
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: "object",
|
|
208
|
+
properties: {
|
|
209
|
+
directory: {
|
|
210
|
+
type: "string",
|
|
211
|
+
description: "Absolute path to the new working directory",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
required: ["directory"],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
({ directory }) => {
|
|
218
|
+
setServerWorkingDirectory(directory);
|
|
219
|
+
const project = getServerProject();
|
|
220
|
+
return textResult({
|
|
221
|
+
directory,
|
|
222
|
+
project: project
|
|
223
|
+
? {
|
|
224
|
+
name: project.name,
|
|
225
|
+
workspaces: project.workspaces.map((w) => w.name),
|
|
226
|
+
}
|
|
227
|
+
: null,
|
|
228
|
+
});
|
|
191
229
|
},
|
|
192
230
|
);
|
|
193
231
|
server.registerTool(
|
package/src/cli/commands/mcp.mjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { startBwMcpServer } from "../../ai/mcp/index.mjs";
|
|
2
2
|
import { logger } from "../../internal/logger/index.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { handleGlobalCommand } from "./commandHandlerUtils.mjs";
|
|
4
4
|
|
|
5
|
-
const mcpServer =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const mcpServer = handleGlobalCommand(
|
|
6
|
+
"mcpServer",
|
|
7
|
+
async ({ workingDirectory }) => {
|
|
8
|
+
logger.printLevel = "silent";
|
|
9
|
+
await startBwMcpServer({
|
|
10
|
+
initialWorkingDirectory: workingDirectory,
|
|
11
|
+
});
|
|
12
|
+
},
|
|
13
|
+
);
|
|
9
14
|
|
|
10
15
|
export { mcpServer };
|
package/src/cli/createCli.mjs
CHANGED
|
@@ -82,11 +82,8 @@ const createCli = ({ defaultCwd = process.cwd(), defaultMiddleware } = {}) => {
|
|
|
82
82
|
process.exit(1);
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
const { project, projectError } =
|
|
86
|
-
program,
|
|
87
|
-
args,
|
|
88
|
-
middleware,
|
|
89
|
-
);
|
|
85
|
+
const { project, projectError, workingDirectory } =
|
|
86
|
+
initializeWithGlobalOptions(program, args, middleware);
|
|
90
87
|
middleware.findProject({
|
|
91
88
|
...defaultContext,
|
|
92
89
|
project,
|
|
@@ -105,6 +102,7 @@ const createCli = ({ defaultCwd = process.cwd(), defaultMiddleware } = {}) => {
|
|
|
105
102
|
outputWriters,
|
|
106
103
|
terminalWidth,
|
|
107
104
|
terminalHeight,
|
|
105
|
+
workingDirectory,
|
|
108
106
|
});
|
|
109
107
|
defineGlobalCommands({
|
|
110
108
|
program,
|
|
@@ -113,6 +111,7 @@ const createCli = ({ defaultCwd = process.cwd(), defaultMiddleware } = {}) => {
|
|
|
113
111
|
outputWriters,
|
|
114
112
|
terminalWidth,
|
|
115
113
|
terminalHeight,
|
|
114
|
+
workingDirectory,
|
|
116
115
|
});
|
|
117
116
|
logger.debug(`Commands initialized. Parsing args...`);
|
|
118
117
|
middleware.preParse({
|
package/src/cli/index.d.ts
CHANGED
|
@@ -587,7 +587,7 @@ export declare const CLI_COMMANDS_CONFIG: {
|
|
|
587
587
|
};
|
|
588
588
|
readonly mcpServer: {
|
|
589
589
|
readonly command: "mcp-server";
|
|
590
|
-
readonly isGlobal:
|
|
590
|
+
readonly isGlobal: true;
|
|
591
591
|
readonly aliases: [];
|
|
592
592
|
readonly description: "Start the bun-workspaces MCP (Model Context Protocol) server over stdio";
|
|
593
593
|
readonly options: {};
|
|
@@ -791,7 +791,7 @@ export declare const getCliCommandConfig: (commandName: CliCommandName) =>
|
|
|
791
791
|
}
|
|
792
792
|
| {
|
|
793
793
|
readonly command: "mcp-server";
|
|
794
|
-
readonly isGlobal:
|
|
794
|
+
readonly isGlobal: true;
|
|
795
795
|
readonly aliases: [];
|
|
796
796
|
readonly description: "Start the bun-workspaces MCP (Model Context Protocol) server over stdio";
|
|
797
797
|
readonly options: {};
|
|
@@ -919,6 +919,7 @@ export type GlobalCommandContext = {
|
|
|
919
919
|
outputWriters: Required<WriteOutputOptions>;
|
|
920
920
|
terminalWidth: number;
|
|
921
921
|
terminalHeight: number;
|
|
922
|
+
workingDirectory: string;
|
|
922
923
|
};
|
|
923
924
|
export type ProjectCommandContext = GlobalCommandContext & {
|
|
924
925
|
project: FileSystemProject;
|
|
@@ -1022,7 +1023,7 @@ export declare const defineProjectCommands: (
|
|
|
1022
1023
|
context: ProjectCommandContext,
|
|
1023
1024
|
) => void;
|
|
1024
1025
|
export declare const mcpServer: (
|
|
1025
|
-
context:
|
|
1026
|
+
context: GlobalCommandContext,
|
|
1026
1027
|
) => import("commander").Command;
|
|
1027
1028
|
export declare const runScript: (
|
|
1028
1029
|
context: ProjectCommandContext,
|
|
@@ -1080,6 +1081,7 @@ export declare const initializeWithGlobalOptions: (
|
|
|
1080
1081
|
): CreateProjectScriptCommandResult;
|
|
1081
1082
|
}>;
|
|
1082
1083
|
projectError: Error | null;
|
|
1084
|
+
workingDirectory: string;
|
|
1083
1085
|
};
|
|
1084
1086
|
|
|
1085
1087
|
export {};
|
|
@@ -25,12 +25,28 @@ Patterns can include a wildcard to match only by workspace name: \`my-workspace-
|
|
|
25
25
|
- Special root workspace selector: \`@root\`.
|
|
26
26
|
- Any pattern can start with \`not:\` to negate the pattern. (e.g. "not:my-workspace-name", "not:tag:my-tag-\\*") This excludes workspaces that match any other present patterns from a result.
|
|
27
27
|
|
|
28
|
-
### Script
|
|
28
|
+
### Workspace Script Metadata
|
|
29
29
|
|
|
30
|
-
Scripts ran via
|
|
30
|
+
Scripts ran via bun-workspaces can access metadata about the workspace, script, and project
|
|
31
|
+
via env vars. This same metadata can also be interpolated into inline scripts and appended args.
|
|
31
32
|
|
|
32
33
|
\`\`\`typescript
|
|
33
|
-
// in a script
|
|
34
|
+
// in a workspace's script invoked by bun-workspaces using a metadata function
|
|
35
|
+
import { getWorkspaceScriptMetadata } from "bun-workspaces/script";
|
|
36
|
+
|
|
37
|
+
// Use the helper within a script that was invoked via bun-workspaces
|
|
38
|
+
const projectPath = getWorkspaceScriptMetadata("projectPath");
|
|
39
|
+
const projectName = getWorkspaceScriptMetadata("projectName");
|
|
40
|
+
const workspaceName = getWorkspaceScriptMetadata("workspaceName");
|
|
41
|
+
const workspacePath = getWorkspaceScriptMetadata("workspacePath");
|
|
42
|
+
const workspaceRelativePath = getWorkspaceScriptMetadata(
|
|
43
|
+
"workspaceRelativePath",
|
|
44
|
+
);
|
|
45
|
+
const scriptName = getWorkspaceScriptMetadata("scriptName");
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
\`\`\`typescript
|
|
49
|
+
// In a script, but accessing the same data via plain environment variables (same values as previous example)
|
|
34
50
|
const projectPath = process.env.BW_PROJECT_PATH;
|
|
35
51
|
const workspaceName = process.env.BW_WORKSPACE_NAME;
|
|
36
52
|
const workspacePath = process.env.BW_WORKSPACE_PATH;
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { logger } from "../../internal/logger/index.mjs";
|
|
16
16
|
import {
|
|
17
17
|
createScriptRuntimeEnvVars,
|
|
18
|
-
|
|
18
|
+
interpolateWorkspaceScriptMetadata,
|
|
19
19
|
runScript,
|
|
20
20
|
runScripts,
|
|
21
21
|
} from "../../runScript/index.mjs";
|
|
@@ -39,11 +39,18 @@ const serializeArgs = (args, metadata, shell) => {
|
|
|
39
39
|
if (Array.isArray(args)) {
|
|
40
40
|
return args
|
|
41
41
|
.map((arg) =>
|
|
42
|
-
quoteArg(
|
|
42
|
+
quoteArg(
|
|
43
|
+
interpolateWorkspaceScriptMetadata(arg, metadata, shell),
|
|
44
|
+
shell,
|
|
45
|
+
),
|
|
43
46
|
)
|
|
44
47
|
.join(" ");
|
|
45
48
|
}
|
|
46
|
-
const interpolated =
|
|
49
|
+
const interpolated = interpolateWorkspaceScriptMetadata(
|
|
50
|
+
args,
|
|
51
|
+
metadata,
|
|
52
|
+
shell,
|
|
53
|
+
);
|
|
47
54
|
// Escape backslashes in interpolated values before POSIX parse on Windows,
|
|
48
55
|
// so that path separators survive parse's escape processing (\\→\)
|
|
49
56
|
const parseInput =
|
|
@@ -215,7 +222,7 @@ class _FileSystemProject extends ProjectBase {
|
|
|
215
222
|
typeof options.inline === "object"
|
|
216
223
|
? (options.inline?.scriptName ?? "")
|
|
217
224
|
: "";
|
|
218
|
-
const
|
|
225
|
+
const workspaceScriptMetadata = {
|
|
219
226
|
projectPath: this.rootDirectory,
|
|
220
227
|
projectName: this.name,
|
|
221
228
|
workspacePath: resolveWorkspacePath(this, workspace),
|
|
@@ -223,11 +230,11 @@ class _FileSystemProject extends ProjectBase {
|
|
|
223
230
|
workspaceName: workspace.name,
|
|
224
231
|
scriptName: options.inline ? inlineScriptName : options.script,
|
|
225
232
|
};
|
|
226
|
-
const args = serializeArgs(options.args,
|
|
233
|
+
const args = serializeArgs(options.args, workspaceScriptMetadata, shell);
|
|
227
234
|
const script = options.inline
|
|
228
|
-
?
|
|
235
|
+
? interpolateWorkspaceScriptMetadata(
|
|
229
236
|
options.script,
|
|
230
|
-
|
|
237
|
+
workspaceScriptMetadata,
|
|
231
238
|
shell,
|
|
232
239
|
) + (args ? " " + args : "")
|
|
233
240
|
: options.script;
|
|
@@ -251,7 +258,7 @@ class _FileSystemProject extends ProjectBase {
|
|
|
251
258
|
metadata: {
|
|
252
259
|
workspace,
|
|
253
260
|
},
|
|
254
|
-
env: createScriptRuntimeEnvVars(
|
|
261
|
+
env: createScriptRuntimeEnvVars(workspaceScriptMetadata),
|
|
255
262
|
shell,
|
|
256
263
|
ignoreOutput: options.ignoreOutput ?? false,
|
|
257
264
|
});
|
|
@@ -422,7 +429,7 @@ class _FileSystemProject extends ProjectBase {
|
|
|
422
429
|
typeof options.inline === "object"
|
|
423
430
|
? (options.inline?.scriptName ?? "")
|
|
424
431
|
: "";
|
|
425
|
-
const
|
|
432
|
+
const workspaceScriptMetadata = {
|
|
426
433
|
projectPath: this.rootDirectory,
|
|
427
434
|
projectName: this.name,
|
|
428
435
|
workspacePath: resolveWorkspacePath(this, workspace),
|
|
@@ -430,11 +437,15 @@ class _FileSystemProject extends ProjectBase {
|
|
|
430
437
|
workspaceName: workspace.name,
|
|
431
438
|
scriptName: options.inline ? inlineScriptName : options.script,
|
|
432
439
|
};
|
|
433
|
-
const args = serializeArgs(
|
|
440
|
+
const args = serializeArgs(
|
|
441
|
+
options.args,
|
|
442
|
+
workspaceScriptMetadata,
|
|
443
|
+
shell,
|
|
444
|
+
);
|
|
434
445
|
const script = options.inline
|
|
435
|
-
?
|
|
446
|
+
? interpolateWorkspaceScriptMetadata(
|
|
436
447
|
options.script,
|
|
437
|
-
|
|
448
|
+
workspaceScriptMetadata,
|
|
438
449
|
shell,
|
|
439
450
|
) + (args ? " " + args : "")
|
|
440
451
|
: options.script;
|
|
@@ -456,7 +467,7 @@ class _FileSystemProject extends ProjectBase {
|
|
|
456
467
|
workspace,
|
|
457
468
|
},
|
|
458
469
|
scriptCommand,
|
|
459
|
-
env: createScriptRuntimeEnvVars(
|
|
470
|
+
env: createScriptRuntimeEnvVars(workspaceScriptMetadata),
|
|
460
471
|
shell,
|
|
461
472
|
dependsOn: options.dependencyOrder
|
|
462
473
|
? workspace.dependencies
|
package/src/runScript/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./runScripts.mjs";
|
|
|
3
3
|
export * from "./scriptCommand.mjs";
|
|
4
4
|
export * from "./output/index.mjs";
|
|
5
5
|
export * from "./parallel.mjs";
|
|
6
|
-
export * from "./
|
|
6
|
+
export * from "./workspaceScriptMetadata.mjs";
|
|
7
7
|
export * from "./scriptShellOption.mjs";
|
|
8
8
|
|
|
9
9
|
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
+
|
|
3
|
+
declare const WORKSPACE_SCRIPT_METADATA_CONFIG: {
|
|
4
|
+
readonly projectPath: {
|
|
5
|
+
readonly inlineName: "<projectPath>";
|
|
6
|
+
readonly envVarName: "BW_PROJECT_PATH";
|
|
7
|
+
};
|
|
8
|
+
readonly projectName: {
|
|
9
|
+
readonly inlineName: "<projectName>";
|
|
10
|
+
readonly envVarName: "BW_PROJECT_NAME";
|
|
11
|
+
};
|
|
12
|
+
readonly workspacePath: {
|
|
13
|
+
readonly inlineName: "<workspacePath>";
|
|
14
|
+
readonly envVarName: "BW_WORKSPACE_PATH";
|
|
15
|
+
};
|
|
16
|
+
readonly workspaceRelativePath: {
|
|
17
|
+
readonly inlineName: "<workspaceRelativePath>";
|
|
18
|
+
readonly envVarName: "BW_WORKSPACE_RELATIVE_PATH";
|
|
19
|
+
};
|
|
20
|
+
readonly scriptName: {
|
|
21
|
+
readonly inlineName: "<scriptName>";
|
|
22
|
+
readonly envVarName: "BW_SCRIPT_NAME";
|
|
23
|
+
};
|
|
24
|
+
readonly workspaceName: {
|
|
25
|
+
readonly inlineName: "<workspaceName>";
|
|
26
|
+
readonly envVarName: "BW_WORKSPACE_NAME";
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type WorkspaceScriptMetadataKey =
|
|
30
|
+
keyof typeof WORKSPACE_SCRIPT_METADATA_CONFIG;
|
|
31
|
+
/**
|
|
32
|
+
* This is a utility to run from a workspace's script that was called via `bun-workspaces`.
|
|
33
|
+
*
|
|
34
|
+
* It gets the value of some metadata value about the project, workspace, or script that was invoked.
|
|
35
|
+
*/
|
|
36
|
+
export declare const getWorkspaceScriptMetadata: (
|
|
37
|
+
key: WorkspaceScriptMetadataKey,
|
|
38
|
+
) => string;
|
|
39
|
+
/** @deprecated Renamed: Use {@link WorkspaceScriptMetadataKey} instead */
|
|
40
|
+
export type ScriptRuntimeMetadataKey = WorkspaceScriptMetadataKey;
|
|
41
|
+
|
|
42
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getWorkspaceScriptMetadata } from "./workspaceScriptMetadata.mjs";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getWorkspaceScriptMetadataConfig } from "../3725.mjs";
|
|
2
2
|
|
|
3
3
|
const checkIsRecursiveScript = (workspaceName, scriptName) => {
|
|
4
4
|
const parentWorkspace =
|
|
5
|
-
process.env[
|
|
5
|
+
process.env[getWorkspaceScriptMetadataConfig("workspaceName").envVarName];
|
|
6
6
|
const parentScript =
|
|
7
|
-
process.env[
|
|
7
|
+
process.env[getWorkspaceScriptMetadataConfig("scriptName").envVarName];
|
|
8
8
|
if (!parentWorkspace || !parentScript) {
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BunWorkspacesError, IS_WINDOWS } from "../internal/core/index.mjs";
|
|
2
|
+
import { getWorkspaceScriptMetadataConfig } from "../3725.mjs";
|
|
3
|
+
|
|
4
|
+
const createScriptRuntimeEnvVars = (metadata) => {
|
|
5
|
+
const keys = [
|
|
6
|
+
"projectPath",
|
|
7
|
+
"projectName",
|
|
8
|
+
"workspacePath",
|
|
9
|
+
"workspaceRelativePath",
|
|
10
|
+
"scriptName",
|
|
11
|
+
"workspaceName",
|
|
12
|
+
];
|
|
13
|
+
return keys.reduce((acc, key) => {
|
|
14
|
+
const { envVarName } = getWorkspaceScriptMetadataConfig(key);
|
|
15
|
+
acc[envVarName] = metadata[key];
|
|
16
|
+
return acc;
|
|
17
|
+
}, {});
|
|
18
|
+
};
|
|
19
|
+
const interpolateWorkspaceScriptMetadata = (text, metadata, shell) => {
|
|
20
|
+
const keys = [
|
|
21
|
+
"projectPath",
|
|
22
|
+
"projectName",
|
|
23
|
+
"workspacePath",
|
|
24
|
+
"workspaceRelativePath",
|
|
25
|
+
"scriptName",
|
|
26
|
+
"workspaceName",
|
|
27
|
+
];
|
|
28
|
+
const inlineNames = keys.map(
|
|
29
|
+
(key) => getWorkspaceScriptMetadataConfig(key).inlineName,
|
|
30
|
+
);
|
|
31
|
+
return text.replace(new RegExp(inlineNames.join("|"), "g"), (match) => {
|
|
32
|
+
const key = keys.find(
|
|
33
|
+
(k) => getWorkspaceScriptMetadataConfig(k).inlineName === match,
|
|
34
|
+
);
|
|
35
|
+
const value = metadata[key];
|
|
36
|
+
if (IS_WINDOWS && shell === "bun") {
|
|
37
|
+
return value.replace(/\\/g, "\\\\");
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* This is a utility to run from a workspace's script that was called via `bun-workspaces`.
|
|
44
|
+
*
|
|
45
|
+
* It gets the value of some metadata value about the project, workspace, or script that was invoked.
|
|
46
|
+
*/ const getWorkspaceScriptMetadata = (key) => {
|
|
47
|
+
const { envVarName } = getWorkspaceScriptMetadataConfig(key);
|
|
48
|
+
if (!(envVarName in process.env)) {
|
|
49
|
+
throw new BunWorkspacesError(
|
|
50
|
+
`getScriptMetadata() called with key "${key}" but environment variable ${envVarName} is not set. getScriptMetadata() may not have been called in a workspace script running via bun-workspaces.`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return process.env[envVarName];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
createScriptRuntimeEnvVars,
|
|
58
|
+
getWorkspaceScriptMetadata,
|
|
59
|
+
interpolateWorkspaceScriptMetadata,
|
|
60
|
+
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { IS_WINDOWS } from "../internal/core/index.mjs";
|
|
2
|
-
import { getScriptRuntimeMetadataConfig } from "../1108.mjs";
|
|
3
|
-
|
|
4
|
-
const createScriptRuntimeEnvVars = (metadata) => {
|
|
5
|
-
const keys = [
|
|
6
|
-
"projectPath",
|
|
7
|
-
"projectName",
|
|
8
|
-
"workspacePath",
|
|
9
|
-
"workspaceRelativePath",
|
|
10
|
-
"scriptName",
|
|
11
|
-
"workspaceName",
|
|
12
|
-
];
|
|
13
|
-
return keys.reduce((acc, key) => {
|
|
14
|
-
const { envVarName } = getScriptRuntimeMetadataConfig(key);
|
|
15
|
-
acc[envVarName] = metadata[key];
|
|
16
|
-
return acc;
|
|
17
|
-
}, {});
|
|
18
|
-
};
|
|
19
|
-
const interpolateScriptRuntimeMetadata = (text, metadata, shell) => {
|
|
20
|
-
const keys = [
|
|
21
|
-
"projectPath",
|
|
22
|
-
"projectName",
|
|
23
|
-
"workspacePath",
|
|
24
|
-
"workspaceRelativePath",
|
|
25
|
-
"scriptName",
|
|
26
|
-
"workspaceName",
|
|
27
|
-
];
|
|
28
|
-
const inlineNames = keys.map(
|
|
29
|
-
(key) => getScriptRuntimeMetadataConfig(key).inlineName,
|
|
30
|
-
);
|
|
31
|
-
return text.replace(new RegExp(inlineNames.join("|"), "g"), (match) => {
|
|
32
|
-
const key = keys.find(
|
|
33
|
-
(k) => getScriptRuntimeMetadataConfig(k).inlineName === match,
|
|
34
|
-
);
|
|
35
|
-
const value = metadata[key];
|
|
36
|
-
if (IS_WINDOWS && shell === "bun") {
|
|
37
|
-
return value.replace(/\\/g, "\\\\");
|
|
38
|
-
}
|
|
39
|
-
return value;
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export { createScriptRuntimeEnvVars, interpolateScriptRuntimeMetadata };
|