bun-workspaces 1.0.1-alpha → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +189 -70
  3. package/bin/cli.js +1 -2
  4. package/package.json +27 -30
  5. package/src/cli/commands/commandHandlerUtils.d.ts +50 -0
  6. package/src/cli/commands/commandHandlerUtils.mjs +91 -0
  7. package/src/cli/commands/commands.d.ts +10 -0
  8. package/src/cli/commands/commands.mjs +23 -0
  9. package/src/cli/commands/commandsConfig.d.ts +351 -0
  10. package/src/cli/commands/commandsConfig.mjs +183 -0
  11. package/src/cli/commands/handleSimpleCommands.d.ts +15 -0
  12. package/src/cli/commands/handleSimpleCommands.mjs +174 -0
  13. package/src/cli/commands/index.d.ts +3 -0
  14. package/src/cli/commands/index.mjs +3 -0
  15. package/src/cli/commands/runScript/handleRunScript.d.ts +3 -0
  16. package/src/cli/commands/runScript/handleRunScript.mjs +250 -0
  17. package/src/cli/commands/runScript/index.d.ts +2 -0
  18. package/src/cli/commands/runScript/index.mjs +2 -0
  19. package/src/cli/commands/runScript/output/index.d.ts +1 -0
  20. package/src/cli/commands/runScript/output/index.mjs +1 -0
  21. package/src/cli/commands/runScript/output/outputStyle.d.ts +8 -0
  22. package/src/cli/commands/runScript/output/outputStyle.mjs +17 -0
  23. package/src/cli/commands/runScript/output/renderGroupedOutput.d.ts +74 -0
  24. package/src/cli/commands/runScript/output/renderGroupedOutput.mjs +331 -0
  25. package/src/cli/commands/runScript/output/renderPlainOutput.d.ts +24 -0
  26. package/src/cli/commands/runScript/output/renderPlainOutput.mjs +44 -0
  27. package/src/cli/commands/runScript/output/sanitizeChunk.d.ts +4 -0
  28. package/src/cli/commands/runScript/output/sanitizeChunk.mjs +101 -0
  29. package/src/cli/createCli.d.ts +25 -0
  30. package/src/cli/createCli.mjs +157 -0
  31. package/src/cli/fatalErrorLogger.d.ts +1 -0
  32. package/src/cli/fatalErrorLogger.mjs +7 -0
  33. package/src/cli/globalOptions/globalOptions.d.ts +42 -0
  34. package/src/cli/globalOptions/globalOptions.mjs +113 -0
  35. package/src/cli/globalOptions/globalOptionsConfig.d.ts +43 -0
  36. package/src/cli/globalOptions/globalOptionsConfig.mjs +34 -0
  37. package/src/cli/globalOptions/index.d.ts +2 -0
  38. package/src/cli/globalOptions/index.mjs +2 -0
  39. package/src/cli/index.d.ts +3 -0
  40. package/src/cli/index.mjs +3 -0
  41. package/src/cli/middleware.d.ts +83 -0
  42. package/src/cli/middleware.mjs +39 -0
  43. package/src/config/index.d.ts +3 -0
  44. package/src/config/index.mjs +3 -0
  45. package/src/config/rootConfig/errors.d.ts +1 -0
  46. package/src/config/rootConfig/errors.mjs +6 -0
  47. package/src/config/rootConfig/index.d.ts +5 -0
  48. package/src/config/rootConfig/index.mjs +5 -0
  49. package/src/config/rootConfig/loadRootConfig.d.ts +3 -0
  50. package/src/config/rootConfig/loadRootConfig.mjs +22 -0
  51. package/src/config/rootConfig/rootConfig.d.ts +17 -0
  52. package/src/config/rootConfig/rootConfig.mjs +43 -0
  53. package/src/config/rootConfig/rootConfigLocation.d.ts +2 -0
  54. package/src/config/rootConfig/rootConfigLocation.mjs +5 -0
  55. package/src/config/rootConfig/rootConfigSchema.d.ts +21 -0
  56. package/src/config/rootConfig/rootConfigSchema.mjs +24 -0
  57. package/src/config/userEnvVars/index.d.ts +1 -0
  58. package/src/config/userEnvVars/index.mjs +1 -0
  59. package/src/config/userEnvVars/userEnvVars.d.ts +13 -0
  60. package/src/config/userEnvVars/userEnvVars.mjs +10 -0
  61. package/src/config/util/ajvTypes.d.ts +10 -0
  62. package/src/config/util/ajvTypes.mjs +2 -0
  63. package/src/config/util/configLocation.d.ts +12 -0
  64. package/src/config/util/configLocation.mjs +11 -0
  65. package/src/config/util/index.d.ts +4 -0
  66. package/src/config/util/index.mjs +3 -0
  67. package/src/config/util/loadConfig.d.ts +16 -0
  68. package/src/config/util/loadConfig.mjs +118 -0
  69. package/src/config/util/validateConfig.d.ts +8 -0
  70. package/src/config/util/validateConfig.mjs +17 -0
  71. package/src/config/workspaceConfig/errors.d.ts +1 -0
  72. package/src/config/workspaceConfig/errors.mjs +6 -0
  73. package/src/config/workspaceConfig/index.d.ts +5 -0
  74. package/src/config/workspaceConfig/index.mjs +5 -0
  75. package/src/config/workspaceConfig/loadWorkspaceConfig.d.ts +3 -0
  76. package/src/config/workspaceConfig/loadWorkspaceConfig.mjs +25 -0
  77. package/src/config/workspaceConfig/workspaceConfig.d.ts +22 -0
  78. package/src/config/workspaceConfig/workspaceConfig.mjs +31 -0
  79. package/src/config/workspaceConfig/workspaceConfigLocation.d.ts +2 -0
  80. package/src/config/workspaceConfig/workspaceConfigLocation.mjs +5 -0
  81. package/src/config/workspaceConfig/workspaceConfigSchema.d.ts +25 -0
  82. package/src/config/workspaceConfig/workspaceConfigSchema.mjs +28 -0
  83. package/src/doctor/doctor.d.ts +35 -0
  84. package/src/doctor/doctor.mjs +52 -0
  85. package/src/doctor/index.d.ts +1 -0
  86. package/src/doctor/index.mjs +1 -0
  87. package/src/index.d.ts +37 -0
  88. package/src/index.mjs +16 -0
  89. package/src/internal/bun/bunLock.d.ts +20 -0
  90. package/src/internal/bun/bunLock.mjs +70 -0
  91. package/src/internal/bun/bunVersion.d.ts +21 -0
  92. package/src/internal/bun/bunVersion.mjs +43 -0
  93. package/src/internal/bun/index.d.ts +2 -0
  94. package/src/internal/bun/index.mjs +2 -0
  95. package/src/internal/core/error/error.d.ts +13 -0
  96. package/src/internal/{error.ts → core/error/error.mjs} +16 -18
  97. package/src/internal/core/error/index.d.ts +1 -0
  98. package/src/internal/core/error/index.mjs +1 -0
  99. package/src/internal/core/index.d.ts +4 -0
  100. package/src/internal/core/index.mjs +4 -0
  101. package/src/internal/core/json/index.d.ts +2 -0
  102. package/src/internal/core/json/index.mjs +2 -0
  103. package/src/internal/core/json/json.d.ts +49 -0
  104. package/src/internal/core/json/json.mjs +12 -0
  105. package/src/internal/core/json/jsonc.d.ts +9 -0
  106. package/src/internal/core/json/jsonc.mjs +117 -0
  107. package/src/internal/core/language/array/index.d.ts +1 -0
  108. package/src/internal/core/language/array/index.mjs +1 -0
  109. package/src/internal/core/language/array/optionalArray.d.ts +15 -0
  110. package/src/internal/core/language/array/optionalArray.mjs +8 -0
  111. package/src/internal/core/language/asyncIterable/asyncIterableQueue.d.ts +16 -0
  112. package/src/internal/core/language/asyncIterable/asyncIterableQueue.mjs +81 -0
  113. package/src/internal/core/language/asyncIterable/index.d.ts +2 -0
  114. package/src/internal/core/language/asyncIterable/index.mjs +2 -0
  115. package/src/internal/core/language/asyncIterable/mergeAsyncIterables.d.ts +5 -0
  116. package/src/internal/core/language/asyncIterable/mergeAsyncIterables.mjs +27 -0
  117. package/src/internal/core/language/events/typedEventTarget.d.ts +50 -0
  118. package/src/internal/core/language/events/typedEventTarget.mjs +14 -0
  119. package/src/internal/core/language/index.d.ts +5 -0
  120. package/src/internal/core/language/index.mjs +5 -0
  121. package/src/internal/core/language/regex/index.d.ts +1 -0
  122. package/src/internal/core/language/regex/index.mjs +1 -0
  123. package/src/internal/core/language/regex/regex.d.ts +3 -0
  124. package/src/internal/core/language/regex/regex.mjs +10 -0
  125. package/src/internal/core/language/string/id.d.ts +1 -0
  126. package/src/internal/core/language/string/id.mjs +10 -0
  127. package/src/internal/core/language/string/index.d.ts +1 -0
  128. package/src/internal/core/language/string/index.mjs +1 -0
  129. package/src/internal/core/language/string/utf/eastAsianWidth.d.ts +16 -0
  130. package/src/internal/core/language/string/utf/eastAsianWidth.mjs +326 -0
  131. package/src/internal/core/language/string/utf/visibleLength.d.ts +5 -0
  132. package/src/internal/core/language/string/utf/visibleLength.mjs +29 -0
  133. package/src/internal/core/language/types/index.d.ts +2 -0
  134. package/src/internal/core/language/types/index.mjs +1 -0
  135. package/src/internal/core/language/types/typeof.d.ts +102 -0
  136. package/src/internal/core/language/types/typeof.mjs +123 -0
  137. package/src/internal/core/language/types/types.d.ts +14 -0
  138. package/src/internal/core/language/types/types.mjs +2 -0
  139. package/src/internal/core/runtime/env.d.ts +6 -0
  140. package/src/internal/core/runtime/env.mjs +36 -0
  141. package/src/internal/core/runtime/index.d.ts +5 -0
  142. package/src/internal/core/runtime/index.mjs +5 -0
  143. package/src/internal/core/runtime/onExit.d.ts +4 -0
  144. package/src/internal/core/runtime/onExit.mjs +54 -0
  145. package/src/internal/core/runtime/os.d.ts +4 -0
  146. package/src/internal/core/runtime/os.mjs +7 -0
  147. package/src/internal/core/runtime/tempFile.d.ts +20 -0
  148. package/src/internal/core/runtime/tempFile.mjs +87 -0
  149. package/src/internal/core/runtime/terminal.d.ts +1 -0
  150. package/src/internal/core/runtime/terminal.mjs +4 -0
  151. package/src/internal/generated/ajv/validateRootConfig.mjs +1 -0
  152. package/src/internal/generated/ajv/validateWorkspaceConfig.mjs +1 -0
  153. package/src/internal/logger/index.d.ts +1 -0
  154. package/src/internal/logger/index.mjs +1 -0
  155. package/src/internal/logger/logger.d.ts +45 -0
  156. package/src/internal/logger/logger.mjs +133 -0
  157. package/src/internal/version.d.ts +1 -0
  158. package/src/internal/version.mjs +6 -0
  159. package/src/project/errors.d.ts +5 -0
  160. package/src/project/errors.mjs +10 -0
  161. package/src/project/implementations/fileSystemProject.d.ts +148 -0
  162. package/src/project/implementations/fileSystemProject.mjs +455 -0
  163. package/src/project/implementations/memoryProject.d.ts +41 -0
  164. package/src/project/implementations/memoryProject.mjs +148 -0
  165. package/src/project/implementations/projectBase.d.ts +35 -0
  166. package/src/project/implementations/projectBase.mjs +197 -0
  167. package/src/project/index.d.ts +5 -0
  168. package/src/project/index.mjs +4 -0
  169. package/src/project/project.d.ts +75 -0
  170. package/src/project/project.mjs +6 -0
  171. package/src/runScript/index.d.ts +7 -0
  172. package/src/runScript/index.mjs +7 -0
  173. package/src/runScript/output/index.d.ts +3 -0
  174. package/src/runScript/output/index.mjs +2 -0
  175. package/src/runScript/output/multiProcessOutput.d.ts +14 -0
  176. package/src/runScript/output/multiProcessOutput.mjs +21 -0
  177. package/src/runScript/output/outputStream.d.ts +1 -0
  178. package/src/runScript/output/outputStream.mjs +1 -0
  179. package/src/runScript/output/processOutput.d.ts +33 -0
  180. package/src/runScript/output/processOutput.mjs +124 -0
  181. package/src/runScript/parallel.d.ts +15 -0
  182. package/src/runScript/parallel.mjs +56 -0
  183. package/src/runScript/recursion.d.ts +4 -0
  184. package/src/runScript/recursion.mjs +17 -0
  185. package/src/runScript/runScript.d.ts +45 -0
  186. package/src/runScript/runScript.mjs +89 -0
  187. package/src/runScript/runScripts.d.ts +65 -0
  188. package/src/runScript/runScripts.mjs +263 -0
  189. package/src/runScript/scriptCommand.d.ts +33 -0
  190. package/src/runScript/scriptCommand.mjs +19 -0
  191. package/src/runScript/scriptExecution.d.ts +9 -0
  192. package/src/runScript/scriptExecution.mjs +50 -0
  193. package/src/runScript/scriptRuntimeMetadata.d.ts +73 -0
  194. package/src/runScript/scriptRuntimeMetadata.mjs +61 -0
  195. package/src/runScript/scriptShellOption.d.ts +8 -0
  196. package/src/runScript/scriptShellOption.mjs +39 -0
  197. package/src/runScript/subprocesses.d.ts +11 -0
  198. package/src/runScript/subprocesses.mjs +34 -0
  199. package/src/workspaces/dependencyGraph/cycles.d.ts +9 -0
  200. package/src/workspaces/dependencyGraph/cycles.mjs +91 -0
  201. package/src/workspaces/dependencyGraph/index.d.ts +2 -0
  202. package/src/workspaces/dependencyGraph/index.mjs +2 -0
  203. package/src/workspaces/dependencyGraph/resolveDependencies.d.ts +18 -0
  204. package/src/workspaces/dependencyGraph/resolveDependencies.mjs +52 -0
  205. package/src/workspaces/errors.d.ts +13 -0
  206. package/src/workspaces/errors.mjs +18 -0
  207. package/src/workspaces/findWorkspaces.d.ts +24 -0
  208. package/src/workspaces/findWorkspaces.mjs +217 -0
  209. package/src/workspaces/index.d.ts +4 -0
  210. package/src/workspaces/index.mjs +3 -0
  211. package/src/workspaces/packageJson.d.ts +31 -0
  212. package/src/workspaces/packageJson.mjs +188 -0
  213. package/src/workspaces/{workspace.ts → workspace.d.ts} +11 -6
  214. package/src/workspaces/workspace.mjs +2 -0
  215. package/src/workspaces/workspacePattern.d.ts +21 -0
  216. package/src/workspaces/workspacePattern.mjs +104 -0
  217. package/bun.lock +0 -576
  218. package/src/cli/cli.ts +0 -87
  219. package/src/cli/globalOptions.ts +0 -122
  220. package/src/cli/index.ts +0 -1
  221. package/src/cli/projectCommands.ts +0 -396
  222. package/src/config/bunWorkspacesConfig.ts +0 -62
  223. package/src/config/configFile.ts +0 -33
  224. package/src/config/index.ts +0 -7
  225. package/src/index.ts +0 -3
  226. package/src/internal/bunVersion.ts +0 -26
  227. package/src/internal/env.ts +0 -25
  228. package/src/internal/logger.ts +0 -145
  229. package/src/internal/regex.ts +0 -5
  230. package/src/project/errors.ts +0 -6
  231. package/src/project/index.ts +0 -6
  232. package/src/project/project.ts +0 -155
  233. package/src/project/scriptCommand.ts +0 -40
  234. package/src/workspaces/errors.ts +0 -14
  235. package/src/workspaces/findWorkspaces.ts +0 -137
  236. package/src/workspaces/index.ts +0 -7
  237. package/src/workspaces/packageJson.ts +0 -166
  238. package/tsconfig.json +0 -28
@@ -0,0 +1,331 @@
1
+ import { runOnExit } from "../../../../internal/core/index.mjs";
2
+ import {
3
+ TypedEventTarget,
4
+ createTypedEventFactory,
5
+ } from "../../../../internal/core/language/events/typedEventTarget.mjs";
6
+ import {
7
+ calculateVisibleLength,
8
+ truncateTerminalString,
9
+ } from "../../../../internal/core/language/string/utf/visibleLength.mjs";
10
+ import { logger } from "../../../../internal/logger/index.mjs";
11
+ import { generatePlainOutputLines } from "./renderPlainOutput.mjs"; // CONCATENATED MODULE: external "../../../../internal/core/index.mjs"
12
+ // CONCATENATED MODULE: external "../../../../internal/core/language/events/typedEventTarget.mjs"
13
+ // CONCATENATED MODULE: external "../../../../internal/core/language/string/utf/visibleLength.mjs"
14
+ // CONCATENATED MODULE: external "../../../../internal/logger/index.mjs"
15
+ // CONCATENATED MODULE: external "./renderPlainOutput.mjs"
16
+ // CONCATENATED MODULE: ./src/cli/commands/runScript/output/renderGroupedOutput.ts
17
+
18
+ class ScriptEventTarget extends TypedEventTarget {}
19
+ const createScriptEventTarget = () => new ScriptEventTarget();
20
+ const createScriptEvent = {
21
+ start: createTypedEventFactory("start"),
22
+ skip: createTypedEventFactory("skip"),
23
+ exit: createTypedEventFactory("exit"),
24
+ };
25
+ const cursorOps = {
26
+ up: (n) => `\x1b[${n}A`,
27
+ down: (n) => `\x1b[${n}B`,
28
+ toColumn: (n) => `\x1b[${n}G`,
29
+ hide: () => `\x1b[?25l`,
30
+ show: () => `\x1b[?25h`,
31
+ };
32
+ const lineOps = {
33
+ clearToEnd: () => `\x1b[0K`,
34
+ clearToStart: () => `\x1b[1K`,
35
+ clearFull: () => `\x1b[2K`,
36
+ };
37
+ const textOps = {
38
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
39
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
40
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
41
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
42
+ blue: (s) => `\x1b[34m${s}\x1b[0m`,
43
+ magenta: (s) => `\x1b[35m${s}\x1b[0m`,
44
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
45
+ white: (s) => `\x1b[37m${s}\x1b[0m`,
46
+ gray: (s) => `\x1b[90m${s}\x1b[0m`,
47
+ intenseBlack: (s) => `\x1b[0;90m${s}\x1b[0m`,
48
+ intenseRed: (s) => `\x1b[0;91m${s}\x1b[0m`,
49
+ intenseGreen: (s) => `\x1b[0;92m${s}\x1b[0m`,
50
+ intenseYellow: (s) => `\x1b[0;93m${s}\x1b[0m`,
51
+ intenseBlue: (s) => `\x1b[0;94m${s}\x1b[0m`,
52
+ intenseMagenta: (s) => `\x1b[0;95m${s}\x1b[0m`,
53
+ intenseCyan: (s) => `\x1b[0;96m${s}\x1b[0m`,
54
+ intenseWhite: (s) => `\x1b[0;97m${s}\x1b[0m`,
55
+ };
56
+ const STATUS_COLORS = {
57
+ pending: "gray",
58
+ running: "intenseCyan",
59
+ skipped: "gray",
60
+ success: "intenseGreen",
61
+ failure: "intenseRed",
62
+ interrupted: "intenseYellow",
63
+ cancelled: "gray",
64
+ killed: "intenseRed",
65
+ };
66
+ const BORDER_COLOR = "blue";
67
+ const renderGroupedOutput = async (
68
+ workspaces,
69
+ output,
70
+ summary,
71
+ scriptEventTarget,
72
+ activeScriptLines,
73
+ outputWriters,
74
+ terminalWidth,
75
+ ) => {
76
+ const workspaceState = workspaces.reduce((acc, workspace) => {
77
+ acc[workspace.name] = {
78
+ lines: [],
79
+ status: "pending",
80
+ exitCode: null,
81
+ signal: null,
82
+ };
83
+ return acc;
84
+ }, {});
85
+ let isInitialized = false;
86
+ const initializeTuiTerminal = () => {
87
+ if (isInitialized) {
88
+ return;
89
+ }
90
+ isInitialized = true;
91
+ logger.debug("Initializing TUI state");
92
+ outputWriters.stdout(cursorOps.hide());
93
+ process.stdin.setRawMode?.(true);
94
+ };
95
+ let isReset = false;
96
+ const resetTuiTerminal = () => {
97
+ if (isReset) {
98
+ return;
99
+ }
100
+ isReset = true;
101
+ logger.debug("Resetting TUI state");
102
+ outputWriters.stdout(cursorOps.show());
103
+ process.stdin.unref?.();
104
+ process.stdin.setRawMode?.(false);
105
+ };
106
+ let previousHeight = 0;
107
+ let didFinalRender = false;
108
+ const render = (isFinal = false) => {
109
+ if (didFinalRender) {
110
+ return;
111
+ }
112
+ if (isFinal) {
113
+ didFinalRender = true;
114
+ }
115
+ const width = Math.max(2, terminalWidth || process.stdout.columns);
116
+ const linesToWrite = [];
117
+ const workspaceBoxContents = {};
118
+ workspaces.forEach((workspace) => {
119
+ const state = workspaceState[workspace.name];
120
+ let statusText = state.status;
121
+ const hasExitCode = state.exitCode && state.exitCode !== -1;
122
+ const exitState =
123
+ hasExitCode && state.signal
124
+ ? "exitAndSignal"
125
+ : hasExitCode
126
+ ? "exit"
127
+ : state.signal
128
+ ? "signal"
129
+ : null;
130
+ if (exitState === "exitAndSignal") {
131
+ statusText += ` (exit code: ${state.exitCode}, signal: ${state.signal})`;
132
+ } else if (exitState === "exit") {
133
+ statusText += ` (exit code: ${state.exitCode})`;
134
+ } else if (exitState === "signal") {
135
+ statusText += ` (signal: ${state.signal})`;
136
+ }
137
+ const workspaceLine = "Workspace: " + textOps.bold(workspace.name);
138
+ const statusLine =
139
+ " Status: " + textOps[STATUS_COLORS[state.status]](statusText);
140
+ workspaceBoxContents[workspace.name] = {
141
+ name: workspaceLine,
142
+ status: statusLine,
143
+ };
144
+ });
145
+ const padding = 4; // left border, spaces, right border
146
+ const workspaceBoxWidth = Math.min(
147
+ width,
148
+ Math.max(
149
+ ...Object.values(workspaceBoxContents).map((content) =>
150
+ Math.max(
151
+ calculateVisibleLength(content.name),
152
+ calculateVisibleLength(content.status),
153
+ ),
154
+ ),
155
+ ) + padding,
156
+ );
157
+ workspaces.forEach((workspace) => {
158
+ const state = workspaceState[workspace.name];
159
+ const { name: workspaceNameContent, status: statusTextContent } =
160
+ workspaceBoxContents[workspace.name];
161
+ linesToWrite.push({
162
+ text: textOps[BORDER_COLOR](
163
+ "┌" + "─".repeat(workspaceBoxWidth - 2) + "┐",
164
+ ),
165
+ type: "border",
166
+ });
167
+ const borderText = (text) => {
168
+ const visibleLength = calculateVisibleLength(text);
169
+ const truncated =
170
+ visibleLength > width - padding
171
+ ? truncateTerminalString(text, width - padding - 1) + "\x1b[0m…"
172
+ : text;
173
+ return (
174
+ textOps[BORDER_COLOR]("│ ") +
175
+ truncated +
176
+ " ".repeat(Math.max(0, workspaceBoxWidth - visibleLength - padding)) +
177
+ textOps[BORDER_COLOR](" │")
178
+ );
179
+ };
180
+ linesToWrite.push({
181
+ text: borderText(workspaceNameContent),
182
+ type: "borderedContent",
183
+ });
184
+ linesToWrite.push({
185
+ text: borderText(statusTextContent),
186
+ type: "borderedContent",
187
+ });
188
+ linesToWrite.push({
189
+ text: textOps[BORDER_COLOR](
190
+ "└" + "─".repeat(workspaceBoxWidth - 2) + "┘",
191
+ ),
192
+ type: "border",
193
+ });
194
+ if (
195
+ activeScriptLines !== "all" &&
196
+ state.lines.length > activeScriptLines &&
197
+ !isFinal
198
+ ) {
199
+ const hiddenLines = state.lines.length - activeScriptLines;
200
+ linesToWrite.push({
201
+ text: textOps.gray(
202
+ `(${hiddenLines} line${hiddenLines === 1 ? "" : "s"} hidden until exit)`,
203
+ ),
204
+ type: "scriptOutput",
205
+ });
206
+ }
207
+ linesToWrite.push(
208
+ ...state.lines
209
+ .slice(isFinal ? undefined : -activeScriptLines)
210
+ .map((line) => ({
211
+ text: line.text,
212
+ type: "scriptOutput",
213
+ })),
214
+ );
215
+ return linesToWrite;
216
+ });
217
+ if (previousHeight > 0) {
218
+ // clear previous frame
219
+ outputWriters.stdout(cursorOps.up(previousHeight));
220
+ for (let i = 0; i < previousHeight; i++) {
221
+ outputWriters.stdout(cursorOps.toColumn(1));
222
+ outputWriters.stdout(lineOps.clearFull());
223
+ outputWriters.stdout("\n");
224
+ }
225
+ outputWriters.stdout(cursorOps.up(previousHeight));
226
+ }
227
+ for (const line of linesToWrite) {
228
+ if (isFinal && line.type === "scriptOutput") {
229
+ outputWriters.stdout(line.text.replace(/\n?$/, "\n"));
230
+ } else {
231
+ const visibleLength = calculateVisibleLength(line.text);
232
+ const truncated =
233
+ visibleLength > width
234
+ ? truncateTerminalString(line.text, width - 2) + "\x1b[0m…"
235
+ : line.text;
236
+ outputWriters.stdout(truncated.replace(/\n?$/, "\n"));
237
+ }
238
+ }
239
+ previousHeight = linesToWrite.length;
240
+ if (isFinal) {
241
+ resetTuiTerminal();
242
+ }
243
+ };
244
+ const handleExitResult = (result) => {
245
+ const state = workspaceState[result.metadata.workspace.name];
246
+ if (result.signal) {
247
+ if (state.status === "running") {
248
+ if (result.signal === "SIGINT") {
249
+ state.status = "interrupted";
250
+ } else {
251
+ state.status = "killed";
252
+ state.signal = result.signal ?? null;
253
+ }
254
+ } else if (state.status === "pending") {
255
+ state.status = "cancelled";
256
+ }
257
+ } else {
258
+ state.status = result.skipped
259
+ ? "skipped"
260
+ : result.success
261
+ ? "success"
262
+ : "failure";
263
+ }
264
+ state.exitCode = result.exitCode ?? process.exitCode ?? null;
265
+ };
266
+ scriptEventTarget.addEventListener("start", (event) => {
267
+ const { workspace } = event;
268
+ workspaceState[workspace.name].status = "running";
269
+ render();
270
+ });
271
+ scriptEventTarget.addEventListener("skip", (event) => {
272
+ const { workspace } = event;
273
+ workspaceState[workspace.name].status = "skipped";
274
+ render();
275
+ });
276
+ scriptEventTarget.addEventListener("exit", (event) => {
277
+ if (event.exitResult) handleExitResult(event.exitResult);
278
+ render();
279
+ });
280
+ process.on("SIGWINCH", render);
281
+ process.stdin.on("data", (data) => {
282
+ if (data[0] === 0x03) process.kill(process.pid, "SIGINT");
283
+ if (data[0] === 0x1c) process.kill(process.pid, "SIGQUIT");
284
+ });
285
+ runOnExit((reason) => {
286
+ try {
287
+ if (typeof reason === "string" && reason.startsWith("SIG")) {
288
+ outputWriters.stdout("\r" + lineOps.clearFull());
289
+ }
290
+ Object.keys(workspaceState).forEach((workspaceName) => {
291
+ handleExitResult({
292
+ metadata: {
293
+ workspace: {
294
+ name: workspaceName,
295
+ },
296
+ },
297
+ skipped: false,
298
+ success: false,
299
+ exitCode:
300
+ typeof process.exitCode === "number" ? process.exitCode : -1,
301
+ signal: typeof reason === "string" ? reason : null,
302
+ });
303
+ });
304
+ render(true);
305
+ } finally {
306
+ resetTuiTerminal();
307
+ }
308
+ });
309
+ initializeTuiTerminal();
310
+ render();
311
+ for await (const { metadata, line } of generatePlainOutputLines(output, {
312
+ stripDisruptiveControls: true,
313
+ prefix: false,
314
+ })) {
315
+ const workspaceName = metadata.workspace.name;
316
+ workspaceState[workspaceName].lines.push({
317
+ text: line.replace(/\n$/, ""),
318
+ type: "scriptOutput",
319
+ });
320
+ render();
321
+ }
322
+ await summary.then((summary) => {
323
+ // fallback logic to resolve race conditions with script events
324
+ summary.scriptResults.forEach((result) => {
325
+ handleExitResult(result);
326
+ });
327
+ render(true);
328
+ });
329
+ };
330
+
331
+ export { createScriptEvent, createScriptEventTarget, renderGroupedOutput };
@@ -0,0 +1,24 @@
1
+ import type { RunScriptAcrossWorkspacesOutput } from "../../../../project";
2
+ import type { WriteOutputOptions } from "../../../createCli";
3
+ export type RenderPlainOutputOptions = {
4
+ stripDisruptiveControls?: boolean;
5
+ prefix?: boolean;
6
+ };
7
+ export declare function generatePlainOutputLines(
8
+ output: RunScriptAcrossWorkspacesOutput,
9
+ { stripDisruptiveControls, prefix }: RenderPlainOutputOptions,
10
+ ): AsyncGenerator<
11
+ {
12
+ line: string;
13
+ metadata: import("../../../..").RunWorkspaceScriptMetadata & {
14
+ streamName: import("../../../..").OutputStreamName;
15
+ };
16
+ },
17
+ void,
18
+ unknown
19
+ >;
20
+ export declare const renderPlainOutput: (
21
+ output: RunScriptAcrossWorkspacesOutput,
22
+ outputWriters: Required<WriteOutputOptions>,
23
+ { stripDisruptiveControls, prefix }: RenderPlainOutputOptions,
24
+ ) => Promise<void>;
@@ -0,0 +1,44 @@
1
+ import { sanitizeChunk } from "./sanitizeChunk.mjs"; // CONCATENATED MODULE: external "./sanitizeChunk.mjs"
2
+ // CONCATENATED MODULE: ./src/cli/commands/runScript/output/renderPlainOutput.ts
3
+
4
+ async function* generatePlainOutputLines(
5
+ output,
6
+ { stripDisruptiveControls = true, prefix = false },
7
+ ) {
8
+ const workspaceLineBuffers = {};
9
+ const formatLine = (line, workspaceName) => {
10
+ const prefixedLine = prefix ? `[${workspaceName}] ${line}` : line;
11
+ return `\x1b[0m${prefixedLine}`;
12
+ };
13
+ for await (const { metadata, chunk } of output.text()) {
14
+ const workspaceName = metadata.workspace.name;
15
+ const sanitizedChunk = sanitizeChunk(chunk, stripDisruptiveControls);
16
+ const prior = workspaceLineBuffers[workspaceName] ?? "";
17
+ const content = prior + sanitizedChunk;
18
+ const lines = content.split("\n");
19
+ for (const line of lines) {
20
+ if (line)
21
+ yield {
22
+ line: formatLine(line, workspaceName),
23
+ metadata,
24
+ };
25
+ }
26
+ workspaceLineBuffers[workspaceName] = content.endsWith("\n")
27
+ ? ""
28
+ : (lines[lines.length - 1] ?? "");
29
+ }
30
+ }
31
+ const renderPlainOutput = async (
32
+ output,
33
+ outputWriters,
34
+ { stripDisruptiveControls = true, prefix = false },
35
+ ) => {
36
+ for await (const { line, metadata } of generatePlainOutputLines(output, {
37
+ stripDisruptiveControls,
38
+ prefix,
39
+ })) {
40
+ outputWriters[metadata.streamName](line + "\n");
41
+ }
42
+ };
43
+
44
+ export { generatePlainOutputLines, renderPlainOutput };
@@ -0,0 +1,4 @@
1
+ export declare const sanitizeChunk: (
2
+ input: string,
3
+ stripDisruptiveControls?: boolean,
4
+ ) => string;
@@ -0,0 +1,101 @@
1
+ // CONCATENATED MODULE: ./src/cli/commands/runScript/output/sanitizeChunk.ts
2
+ const sanitizeChunk = (input, stripDisruptiveControls = false) => {
3
+ if (!stripDisruptiveControls) {
4
+ return input.replace(/\r\n/g, "\n");
5
+ }
6
+ // 1) Normalize newline-ish controls
7
+ let normalizedText = input
8
+ .replace(/\r\n/g, "\n")
9
+ .replace(/\r/g, "\n")
10
+ .replace(/\f/g, "\n")
11
+ .replace(/\v/g, "\n");
12
+ // 2) Remove disruptive single-byte controls (except \n, \t)
13
+ // - backspace, bell, and C1 controls
14
+ // eslint-disable-next-line no-control-regex
15
+ normalizedText = normalizedText.replace(/[\b\x07\x80-\x9F]/g, "");
16
+ // 3) Strip ANSI sequences, keeping only SGR (CSI ... m)
17
+ //
18
+ // We'll scan rather than rely on one giant regex so we can:
19
+ // - keep SGR exactly
20
+ // - drop any other ESC sequence
21
+ // - handle incomplete ESC sequences conservatively (drop the ESC byte itself)
22
+ //
23
+ // ESC = \x1B
24
+ const ESC = "\x1B";
25
+ let result = "";
26
+ for (let index = 0; index < normalizedText.length; index++) {
27
+ const currentChar = normalizedText[index];
28
+ if (currentChar !== ESC) {
29
+ result += currentChar;
30
+ continue;
31
+ }
32
+ // If ESC is last char, drop it
33
+ if (index + 1 >= normalizedText.length) break;
34
+ const nextChar = normalizedText[index + 1];
35
+ // Keep only CSI ... m (ESC [ ... m)
36
+ if (nextChar === "[") {
37
+ // Find final byte of CSI sequence (per spec: 0x40-0x7E).
38
+ // We only keep it if the final byte is 'm'.
39
+ let scanIndex = index + 2;
40
+ while (scanIndex < normalizedText.length) {
41
+ const code = normalizedText.charCodeAt(scanIndex);
42
+ if (code >= 0x40 && code <= 0x7e) break; // final byte
43
+ scanIndex++;
44
+ }
45
+ // If we didn't find a final byte, drop the ESC and stop (incomplete)
46
+ if (scanIndex >= normalizedText.length) break;
47
+ const finalByte = normalizedText[scanIndex];
48
+ if (finalByte === "m") {
49
+ // Keep full SGR sequence
50
+ result += normalizedText.slice(index, scanIndex + 1);
51
+ }
52
+ // else: drop the entire CSI sequence
53
+ index = scanIndex; // advance past sequence
54
+ continue;
55
+ }
56
+ // All other ESC sequences: drop them.
57
+ //
58
+ // For 2-byte sequences (like ESC c), we can just drop ESC+next.
59
+ // For string-terminated families (OSC/DCS/APC/PM/SOS), we should skip until terminator.
60
+ //
61
+ // OSC: ESC ] ... (BEL or ESC \)
62
+ // DCS: ESC P ... (ST = ESC \)
63
+ // APC: ESC _ ... (ST)
64
+ // PM : ESC ^ ... (ST)
65
+ // SOS: ESC X ... (ST)
66
+ if (
67
+ nextChar === "]" ||
68
+ nextChar === "P" ||
69
+ nextChar === "_" ||
70
+ nextChar === "^" ||
71
+ nextChar === "X"
72
+ ) {
73
+ let scanIndex = index + 2;
74
+ while (scanIndex < normalizedText.length) {
75
+ const currentByte = normalizedText[scanIndex];
76
+ // BEL terminator (OSC can end with BEL)
77
+ if (currentByte === "\x07") {
78
+ scanIndex++;
79
+ break;
80
+ }
81
+ // ST terminator: ESC \
82
+ if (
83
+ currentByte === ESC &&
84
+ scanIndex + 1 < normalizedText.length &&
85
+ normalizedText[scanIndex + 1] === "\\"
86
+ ) {
87
+ scanIndex += 2;
88
+ break;
89
+ }
90
+ scanIndex++;
91
+ }
92
+ index = scanIndex - 1; // -1 because loop will index++
93
+ continue;
94
+ }
95
+ // Fallback: treat as a 2-byte escape and drop ESC + next.
96
+ index += 1;
97
+ }
98
+ return result;
99
+ };
100
+
101
+ export { sanitizeChunk };
@@ -0,0 +1,25 @@
1
+ import { type CliMiddlewareOptions } from "./middleware";
2
+ export interface WriteOutputOptions {
3
+ stdout?: (...args: Parameters<typeof process.stdout.write>) => void;
4
+ stderr?: (...args: Parameters<typeof process.stderr.write>) => void;
5
+ }
6
+ export interface RunCliOptions {
7
+ argv?: string[];
8
+ /** Should be `true` if args do not include the binary name (e.g. `bunx bun-workspaces`) */
9
+ programmatic?: true;
10
+ middleware?: CliMiddlewareOptions;
11
+ writeOutput?: WriteOutputOptions;
12
+ terminalWidth?: number;
13
+ }
14
+ export interface CLI {
15
+ run: (options?: RunCliOptions) => Promise<void>;
16
+ }
17
+ export interface CreateCliOptions {
18
+ defaultCwd?: string;
19
+ /** Always handled when the result `.run()` is called */
20
+ defaultMiddleware?: CliMiddlewareOptions;
21
+ }
22
+ export declare const createCli: ({
23
+ defaultCwd,
24
+ defaultMiddleware,
25
+ }?: CreateCliOptions) => CLI;
@@ -0,0 +1,157 @@
1
+ import { createCommand } from "commander";
2
+ import package_0 from "../../package.json";
3
+ import { validateCurrentBunVersion } from "../internal/bun/index.mjs";
4
+ import { BunWorkspacesError } from "../internal/core/index.mjs";
5
+ import { logger } from "../internal/logger/index.mjs";
6
+ import {
7
+ defineGlobalCommands,
8
+ defineProjectCommands,
9
+ } from "./commands/index.mjs";
10
+ import { commandOutputLogger } from "./commands/commandHandlerUtils.mjs";
11
+ import { fatalErrorLogger } from "./fatalErrorLogger.mjs";
12
+ import { initializeWithGlobalOptions } from "./globalOptions/index.mjs";
13
+ import { resolveMiddleware } from "./middleware.mjs"; // CONCATENATED MODULE: external "commander"
14
+ // CONCATENATED MODULE: external "../../package.json"
15
+ // CONCATENATED MODULE: external "../internal/bun/index.mjs"
16
+ // CONCATENATED MODULE: external "../internal/core/index.mjs"
17
+ // CONCATENATED MODULE: external "../internal/logger/index.mjs"
18
+ // CONCATENATED MODULE: external "./commands/index.mjs"
19
+ // CONCATENATED MODULE: external "./commands/commandHandlerUtils.mjs"
20
+ // CONCATENATED MODULE: external "./fatalErrorLogger.mjs"
21
+ // CONCATENATED MODULE: external "./globalOptions/index.mjs"
22
+ // CONCATENATED MODULE: external "./middleware.mjs"
23
+ // CONCATENATED MODULE: ./src/cli/createCli.ts
24
+
25
+ const createCli = ({ defaultCwd = process.cwd(), defaultMiddleware } = {}) => {
26
+ logger.debug(`Creating CLI with default cwd: ${defaultCwd}`);
27
+ const run = async ({
28
+ argv = process.argv,
29
+ programmatic,
30
+ middleware: _runMiddleware,
31
+ writeOutput,
32
+ terminalWidth = process.stdout.columns,
33
+ } = {}) => {
34
+ const middleware = resolveMiddleware(
35
+ defaultMiddleware ?? {},
36
+ _runMiddleware ?? {},
37
+ );
38
+ const outputWriters = {
39
+ stdout: (...args) => process.stdout.write(...args),
40
+ stderr: (...args) => process.stderr.write(...args),
41
+ ...writeOutput,
42
+ };
43
+ logger.setPrintStdout(outputWriters.stdout);
44
+ logger.setPrintStderr(outputWriters.stderr);
45
+ commandOutputLogger.setPrintStdout(outputWriters.stdout);
46
+ commandOutputLogger.setPrintStderr(outputWriters.stderr);
47
+ const errorListener = (error) => {
48
+ middleware.catchError(error);
49
+ fatalErrorLogger.error(error);
50
+ process.exit(1);
51
+ };
52
+ process.on("unhandledRejection", errorListener);
53
+ try {
54
+ const program = createCommand("bun-workspaces")
55
+ .description("A CLI on top of native Bun workspaces")
56
+ .version(package_0.version)
57
+ .showHelpAfterError(true)
58
+ .configureOutput({
59
+ writeOut: outputWriters.stdout,
60
+ writeErr: outputWriters.stderr,
61
+ ...(terminalWidth
62
+ ? {
63
+ getOutHelpWidth: () => terminalWidth,
64
+ getErrHelpWidth: () => terminalWidth,
65
+ }
66
+ : {}),
67
+ });
68
+ const defaultContext = {
69
+ commanderProgram: program,
70
+ };
71
+ middleware.initProgram({
72
+ ...defaultContext,
73
+ argv,
74
+ });
75
+ const { args, postTerminatorArgs } = (() => {
76
+ const terminatorIndex = argv.findIndex((arg) => arg === "--");
77
+ return {
78
+ args: terminatorIndex !== -1 ? argv.slice(0, terminatorIndex) : argv,
79
+ postTerminatorArgs:
80
+ terminatorIndex !== -1 ? argv.slice(terminatorIndex + 1) : [],
81
+ };
82
+ })();
83
+ middleware.processArgv({
84
+ ...defaultContext,
85
+ args,
86
+ postTerminatorArgs,
87
+ });
88
+ const bunVersionError = validateCurrentBunVersion();
89
+ if (bunVersionError) {
90
+ fatalErrorLogger.error(bunVersionError.message);
91
+ process.exit(1);
92
+ }
93
+ const { project, projectError } = initializeWithGlobalOptions(
94
+ program,
95
+ args,
96
+ defaultCwd,
97
+ middleware,
98
+ );
99
+ middleware.findProject({
100
+ ...defaultContext,
101
+ project,
102
+ projectError,
103
+ });
104
+ if (postTerminatorArgs.length) {
105
+ logger.debug("Has post-terminator args");
106
+ }
107
+ logger.debug(`Bun version: ${Bun.version}`);
108
+ defineProjectCommands({
109
+ program,
110
+ project,
111
+ projectError,
112
+ postTerminatorArgs,
113
+ middleware,
114
+ outputWriters,
115
+ terminalWidth,
116
+ });
117
+ defineGlobalCommands({
118
+ program,
119
+ postTerminatorArgs,
120
+ middleware,
121
+ outputWriters,
122
+ terminalWidth,
123
+ });
124
+ logger.debug(`Commands initialized. Parsing args...`);
125
+ middleware.preParse({
126
+ ...defaultContext,
127
+ args,
128
+ project,
129
+ projectError,
130
+ });
131
+ await program.parseAsync(args, {
132
+ from: programmatic ? "user" : "node",
133
+ });
134
+ middleware.postParse({
135
+ ...defaultContext,
136
+ args,
137
+ project,
138
+ projectError,
139
+ });
140
+ } catch (error) {
141
+ if (error instanceof BunWorkspacesError) {
142
+ logger.debug(error);
143
+ fatalErrorLogger.error(error.message);
144
+ process.exit(1);
145
+ } else {
146
+ errorListener(error);
147
+ }
148
+ } finally {
149
+ process.off("unhandledRejection", errorListener);
150
+ }
151
+ };
152
+ return {
153
+ run,
154
+ };
155
+ };
156
+
157
+ export { createCli };
@@ -0,0 +1 @@
1
+ export declare const fatalErrorLogger: import("../internal/logger").Logger;