@visulima/task-runner 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (53) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +193 -51
  3. package/dist/affected.d.ts +37 -3
  4. package/dist/command-parser/expand-arguments.d.ts +11 -0
  5. package/dist/command-parser/expand-shortcut.d.ts +15 -0
  6. package/dist/command-parser/expand-wildcard.d.ts +13 -0
  7. package/dist/command-parser/index.d.ts +18 -0
  8. package/dist/command-parser/strip-quotes.d.ts +6 -0
  9. package/dist/concurrent-fallback.d.ts +16 -0
  10. package/dist/concurrent.d.ts +23 -0
  11. package/dist/detect-shell.d.ts +19 -0
  12. package/dist/flow-controllers/index.d.ts +7 -0
  13. package/dist/flow-controllers/input-handler.d.ts +44 -0
  14. package/dist/flow-controllers/log-timings.d.ts +18 -0
  15. package/dist/flow-controllers/restart-process.d.ts +21 -0
  16. package/dist/flow-controllers/teardown.d.ts +22 -0
  17. package/dist/index.d.ts +13 -3
  18. package/dist/index.js +26 -12
  19. package/dist/native-binding.d.ts +44 -2
  20. package/dist/packem_shared/{Cache-IYpTYVUC.js → Cache-C23LywYn.js} +2 -3
  21. package/dist/packem_shared/{FingerprintManager-D6Y0erg-.js → FingerprintManager-Cu-ta9ee.js} +0 -1
  22. package/dist/packem_shared/{IncrementalFileHasher-Ds3J6dgb.js → IncrementalFileHasher-Cm_kJY5V.js} +1 -1
  23. package/dist/packem_shared/{TaskOrchestrator-BvYs3ONw.js → TaskOrchestrator-lLn-PH1m.js} +2 -5
  24. package/dist/packem_shared/TerminalBuffer-D6zP2zLh.js +250 -0
  25. package/dist/packem_shared/{filterAffectedTasks-I-18zPg6.js → buildForwardDependencyMap-Cu08NWB1.js} +58 -20
  26. package/dist/packem_shared/{computeTaskHash-BoCnnvIJ.js → computeTaskHash-B2SVZqgp.js} +1 -2
  27. package/dist/packem_shared/createInputHandler-DTfePcTG.js +37 -0
  28. package/dist/packem_shared/{defaultTaskRunner-CrW4v5Ye.js → defaultTaskRunner-X1MIynHu.js} +6 -7
  29. package/dist/packem_shared/detectScriptShell-CR-xXKA4.js +53 -0
  30. package/dist/packem_shared/enforceProjectConstraints-_Ej0zHch.js +90 -0
  31. package/dist/packem_shared/expandArguments-0AwD2BIA.js +26 -0
  32. package/dist/packem_shared/expandShortcut-BVG05ee4.js +23 -0
  33. package/dist/packem_shared/expandWildcard-B0xN_knq.js +107 -0
  34. package/dist/packem_shared/{findCycle-DF4_BRdO.js → findCycle-DefgNYhg.js} +1 -1
  35. package/dist/packem_shared/formatTimingTable-3qtCM552.js +46 -0
  36. package/dist/packem_shared/isNativeAvailable-BpD28A6Z.js +44 -0
  37. package/dist/packem_shared/parseCommands-D-IgF8Zh.js +26 -0
  38. package/dist/packem_shared/{TaskScheduler-CJilHDta.js → parsePartition-C4-P5RjK.js} +44 -1
  39. package/dist/packem_shared/{projectGraphToDot-VdTjHcVp.js → projectGraphToDot-C8uYeaPo.js} +20 -3
  40. package/dist/packem_shared/runConcurrentFallback-3q46z4AS.js +357 -0
  41. package/dist/packem_shared/runConcurrently-ATDwJNR6.js +67 -0
  42. package/dist/packem_shared/runTeardown-BAezH79J.js +49 -0
  43. package/dist/packem_shared/stripQuotes-Cey-zwFf.js +9 -0
  44. package/dist/packem_shared/withRestart-BREjRJa4.js +49 -0
  45. package/dist/project-constraints.d.ts +16 -0
  46. package/dist/task-scheduler.d.ts +23 -0
  47. package/dist/terminal-buffer.d.ts +29 -0
  48. package/dist/types.d.ts +220 -1
  49. package/index.js +599 -0
  50. package/package.json +14 -13
  51. package/binding.js +0 -204
  52. package/dist/packem_shared/isNativeAvailable-BWhnZ4ES.js +0 -19
  53. package/dist/packem_shared/{RemoteCache-BDqrnDEi.js → RemoteCache-BFceSe4a.js} +1 -1
@@ -0,0 +1,357 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ spawn: spawn$1
22
+ } = __cjs_getBuiltinModule("node:child_process");
23
+ import { spawn } from '@lydell/node-pty';
24
+
25
+ const evaluateSuccess = (events, condition) => {
26
+ if (events.length === 0) {
27
+ return true;
28
+ }
29
+ const normalized = condition.trim().toLowerCase();
30
+ if (normalized === "first") {
31
+ return events[0].exitCode === 0;
32
+ }
33
+ if (normalized === "last") {
34
+ return events.at(-1).exitCode === 0;
35
+ }
36
+ const commandMatch = /^(!?)command-(.+)$/.exec(normalized);
37
+ if (commandMatch) {
38
+ const [, negated, target] = commandMatch;
39
+ const isNegated = negated === "!";
40
+ const matching = events.filter((e) => e.name === target || String(e.index) === target);
41
+ if (isNegated) {
42
+ return events.filter((e) => !matching.includes(e)).every((e) => e.exitCode === 0);
43
+ }
44
+ return matching.length > 0 && matching.every((e) => e.exitCode === 0);
45
+ }
46
+ return events.every((e) => e.exitCode === 0);
47
+ };
48
+ const killTree = (pid, signal) => {
49
+ try {
50
+ if (process.platform === "win32") {
51
+ spawn$1("taskkill", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore" });
52
+ } else {
53
+ process.kill(-pid, signal);
54
+ }
55
+ } catch {
56
+ }
57
+ };
58
+ const spawnCommand = (index, config, shellPath, onEvent, onComplete) => {
59
+ const startTime = process.hrtime();
60
+ const useShell = config.shell !== false;
61
+ const stdinMode = config.stdin ?? "null";
62
+ const stdinStdio = stdinMode === "inherit" ? "inherit" : stdinMode === "pipe" ? "pipe" : "ignore";
63
+ let child;
64
+ if (useShell) {
65
+ let shellProgram;
66
+ let shellArgs;
67
+ let verbatimArgs = false;
68
+ if (shellPath) {
69
+ shellProgram = shellPath;
70
+ shellArgs = ["-c", config.command];
71
+ } else if (process.platform === "win32") {
72
+ shellProgram = "cmd.exe";
73
+ shellArgs = ["/s", "/c", `"${config.command}"`];
74
+ verbatimArgs = true;
75
+ } else {
76
+ shellProgram = "/bin/sh";
77
+ shellArgs = ["-c", config.command];
78
+ }
79
+ child = spawn$1(shellProgram, shellArgs, {
80
+ cwd: config.cwd,
81
+ detached: process.platform !== "win32",
82
+ env: {
83
+ ...process.env,
84
+ ...config.env,
85
+ FORCE_COLOR: process.env["FORCE_COLOR"] ?? "1"
86
+ },
87
+ stdio: [stdinStdio, "pipe", "pipe"],
88
+ windowsVerbatimArguments: verbatimArgs
89
+ });
90
+ } else {
91
+ const parts = config.command.split(/\s+/);
92
+ const program = parts[0];
93
+ const args = parts.slice(1);
94
+ child = spawn$1(program, args, {
95
+ cwd: config.cwd,
96
+ detached: process.platform !== "win32",
97
+ env: {
98
+ ...process.env,
99
+ ...config.env,
100
+ FORCE_COLOR: process.env["FORCE_COLOR"] ?? "1"
101
+ },
102
+ stdio: [stdinStdio, "pipe", "pipe"]
103
+ });
104
+ }
105
+ onEvent({
106
+ index,
107
+ kill: child.pid ? (signal) => killTree(child.pid, signal ?? "SIGTERM") : void 0,
108
+ kind: "started",
109
+ write: child.stdin ? (data) => child.stdin.write(data) : void 0
110
+ });
111
+ let stdoutBuffer = "";
112
+ let stdoutFlushTimer;
113
+ const flushStdoutBuffer = () => {
114
+ if (stdoutBuffer) {
115
+ onEvent({ index, kind: "stdout", text: stdoutBuffer });
116
+ stdoutBuffer = "";
117
+ }
118
+ };
119
+ child.stdout?.on("data", (data) => {
120
+ if (stdoutFlushTimer) {
121
+ clearTimeout(stdoutFlushTimer);
122
+ stdoutFlushTimer = void 0;
123
+ }
124
+ stdoutBuffer += data.toString();
125
+ const lines = stdoutBuffer.split("\n");
126
+ stdoutBuffer = lines.pop() ?? "";
127
+ for (const line of lines) {
128
+ onEvent({ index, kind: "stdout", text: line });
129
+ }
130
+ if (stdoutBuffer) {
131
+ stdoutFlushTimer = setTimeout(flushStdoutBuffer, 100);
132
+ }
133
+ });
134
+ child.stdout?.on("end", () => {
135
+ if (stdoutFlushTimer) {
136
+ clearTimeout(stdoutFlushTimer);
137
+ stdoutFlushTimer = void 0;
138
+ }
139
+ flushStdoutBuffer();
140
+ });
141
+ let stderrBuffer = "";
142
+ let stderrFlushTimer;
143
+ const flushStderrBuffer = () => {
144
+ if (stderrBuffer) {
145
+ onEvent({ index, kind: "stderr", text: stderrBuffer });
146
+ stderrBuffer = "";
147
+ }
148
+ };
149
+ child.stderr?.on("data", (data) => {
150
+ if (stderrFlushTimer) {
151
+ clearTimeout(stderrFlushTimer);
152
+ stderrFlushTimer = void 0;
153
+ }
154
+ stderrBuffer += data.toString();
155
+ const lines = stderrBuffer.split("\n");
156
+ stderrBuffer = lines.pop() ?? "";
157
+ for (const line of lines) {
158
+ onEvent({ index, kind: "stderr", text: line });
159
+ }
160
+ if (stderrBuffer) {
161
+ stderrFlushTimer = setTimeout(flushStderrBuffer, 100);
162
+ }
163
+ });
164
+ child.stderr?.on("end", () => {
165
+ if (stderrFlushTimer) {
166
+ clearTimeout(stderrFlushTimer);
167
+ stderrFlushTimer = void 0;
168
+ }
169
+ flushStderrBuffer();
170
+ });
171
+ child.on("error", (error) => {
172
+ onEvent({ index, kind: "error", message: error.message });
173
+ });
174
+ child.on("close", (code, signal) => {
175
+ if (stdoutFlushTimer) {
176
+ clearTimeout(stdoutFlushTimer);
177
+ stdoutFlushTimer = void 0;
178
+ }
179
+ if (stderrFlushTimer) {
180
+ clearTimeout(stderrFlushTimer);
181
+ stderrFlushTimer = void 0;
182
+ }
183
+ flushStdoutBuffer();
184
+ flushStderrBuffer();
185
+ const elapsed = process.hrtime(startTime);
186
+ const durationMs = elapsed[0] * 1e3 + elapsed[1] / 1e6;
187
+ const exitCode = code ?? (signal ? 1 : -1);
188
+ const closeEvent = {
189
+ command: config.command,
190
+ durationMs,
191
+ exitCode,
192
+ index,
193
+ killed: signal !== null,
194
+ name: config.name
195
+ };
196
+ onEvent({
197
+ commandName: config.name,
198
+ durationMs,
199
+ exitCode,
200
+ index,
201
+ killed: signal !== null,
202
+ kind: "close"
203
+ });
204
+ onComplete(closeEvent);
205
+ });
206
+ return { child, index, startTime };
207
+ };
208
+ const spawnCommandPty = (index, config, shellPath, onEvent, onComplete) => {
209
+ const startTime = process.hrtime();
210
+ let shellProgram;
211
+ let shellArgs;
212
+ if (shellPath) {
213
+ shellProgram = shellPath;
214
+ shellArgs = ["-c", config.command];
215
+ } else if (process.platform === "win32") {
216
+ shellProgram = "cmd.exe";
217
+ shellArgs = ["/s", "/c", config.command];
218
+ } else {
219
+ shellProgram = "/bin/sh";
220
+ shellArgs = ["-c", config.command];
221
+ }
222
+ const ptyInstance = spawn(shellProgram, shellArgs, {
223
+ cols: config.ptySize?.cols ?? 80,
224
+ cwd: config.cwd ?? process.cwd(),
225
+ env: Object.fromEntries(
226
+ Object.entries({ ...process.env, ...config.env, FORCE_COLOR: process.env["FORCE_COLOR"] ?? "1", TERM: "xterm-256color" }).filter((entry) => entry[1] !== void 0)
227
+ ),
228
+ name: "xterm-256color",
229
+ rows: config.ptySize?.rows ?? 24
230
+ });
231
+ onEvent({
232
+ index,
233
+ kill: (signal) => ptyInstance.kill(signal),
234
+ kind: "started",
235
+ resize: (cols, rows) => ptyInstance.resize(cols, rows),
236
+ write: (data) => ptyInstance.write(data)
237
+ });
238
+ ptyInstance.onData((data) => {
239
+ onEvent({ index, kind: "stdout", text: data });
240
+ });
241
+ ptyInstance.onExit(({ exitCode, signal }) => {
242
+ const elapsed = process.hrtime(startTime);
243
+ const durationMs = elapsed[0] * 1e3 + elapsed[1] / 1e6;
244
+ const code = exitCode ?? (signal ? 1 : -1);
245
+ const closeEvent = {
246
+ command: config.command,
247
+ durationMs,
248
+ exitCode: code,
249
+ index,
250
+ killed: signal !== void 0 && signal !== 0,
251
+ name: config.name
252
+ };
253
+ onEvent({
254
+ commandName: config.name,
255
+ durationMs,
256
+ exitCode: code,
257
+ index,
258
+ killed: signal !== void 0 && signal !== 0,
259
+ kind: "close"
260
+ });
261
+ onComplete(closeEvent);
262
+ });
263
+ return { index, pty: ptyInstance, startTime };
264
+ };
265
+ const runConcurrentFallback = (commands, options) => new Promise((resolve) => {
266
+ if (commands.length === 0) {
267
+ resolve({ closeEvents: [], success: true });
268
+ return;
269
+ }
270
+ const maxProcesses = options.maxProcesses && options.maxProcesses > 0 ? options.maxProcesses : commands.length;
271
+ const killSignal = options.killSignal ?? "SIGTERM";
272
+ const killOthers = options.killOthers ?? [];
273
+ const successCondition = options.successCondition ?? "all";
274
+ const onEvent = options.onEvent ?? (() => {
275
+ });
276
+ const active = [];
277
+ const closeEvents = [];
278
+ const pending = commands.map((_, i) => i);
279
+ let aborting = false;
280
+ let sigintAbort = false;
281
+ const killAll = () => {
282
+ for (const proc of active) {
283
+ if (proc.pty) {
284
+ proc.pty.kill(killSignal);
285
+ } else if (proc.child?.pid) {
286
+ killTree(proc.child.pid, killSignal);
287
+ }
288
+ }
289
+ };
290
+ const shouldKillOthers = (event) => {
291
+ for (const condition of killOthers) {
292
+ if (condition === "failure" && event.exitCode !== 0) {
293
+ return true;
294
+ }
295
+ if (condition === "success" && event.exitCode === 0) {
296
+ return true;
297
+ }
298
+ }
299
+ return false;
300
+ };
301
+ const handleClose = (cmdIndex, closeEvent) => {
302
+ const activeIndex = active.findIndex((p) => p.index === cmdIndex);
303
+ if (activeIndex !== -1) {
304
+ active.splice(activeIndex, 1);
305
+ }
306
+ if (aborting) {
307
+ closeEvent.killed = true;
308
+ if (sigintAbort) {
309
+ closeEvent.exitCode = 0;
310
+ }
311
+ }
312
+ closeEvents.push(closeEvent);
313
+ if (!aborting && shouldKillOthers(closeEvent)) {
314
+ aborting = true;
315
+ killAll();
316
+ }
317
+ if (!aborting) {
318
+ maybeSpawnMore();
319
+ }
320
+ if (active.length === 0 && pending.length === 0) {
321
+ const success = evaluateSuccess(closeEvents, successCondition);
322
+ resolve({ closeEvents, success });
323
+ }
324
+ };
325
+ const maybeSpawnMore = () => {
326
+ while (active.length < maxProcesses && pending.length > 0) {
327
+ const cmdIndex = pending.shift();
328
+ const config = commands[cmdIndex];
329
+ const proc = config.stdin === "pty" ? spawnCommandPty(cmdIndex, config, options.shellPath, onEvent, (ce) => handleClose(cmdIndex, ce)) : spawnCommand(cmdIndex, config, options.shellPath, onEvent, (ce) => handleClose(cmdIndex, ce));
330
+ active.push(proc);
331
+ }
332
+ };
333
+ const handleSigint = () => {
334
+ if (!aborting) {
335
+ aborting = true;
336
+ sigintAbort = true;
337
+ killAll();
338
+ }
339
+ };
340
+ const handleSigterm = () => {
341
+ if (!aborting) {
342
+ aborting = true;
343
+ killAll();
344
+ }
345
+ };
346
+ process.on("SIGINT", handleSigint);
347
+ process.on("SIGTERM", handleSigterm);
348
+ const originalResolve = resolve;
349
+ resolve = ((result) => {
350
+ process.removeListener("SIGINT", handleSigint);
351
+ process.removeListener("SIGTERM", handleSigterm);
352
+ originalResolve(result);
353
+ });
354
+ maybeSpawnMore();
355
+ });
356
+
357
+ export { runConcurrentFallback };
@@ -0,0 +1,67 @@
1
+ import { runConcurrentFallback } from './runConcurrentFallback-3q46z4AS.js';
2
+ import { detectScriptShell } from './detectScriptShell-CR-xXKA4.js';
3
+ import { logTimings } from './formatTimingTable-3qtCM552.js';
4
+ import { withRestart } from './withRestart-BREjRJa4.js';
5
+ import { runTeardown } from './runTeardown-BAezH79J.js';
6
+ import { loadNativeBindings } from './isNativeAvailable-BpD28A6Z.js';
7
+
8
+ const normalizeCommands = (inputs) => inputs.map((input) => {
9
+ if (typeof input === "string") {
10
+ return { command: input };
11
+ }
12
+ return input;
13
+ });
14
+ const coreRun = async (configs, options) => {
15
+ const shellPath = options.shellPath ?? detectScriptShell();
16
+ const native = loadNativeBindings();
17
+ const needsJsFallback = configs.some((c) => c.stdin === "pipe" || c.stdin === "pty") || !!options.onEvent;
18
+ if (native && !needsJsFallback) {
19
+ const nativeOptions = {
20
+ killOthers: options.killOthers,
21
+ killSignal: options.killSignal,
22
+ killTimeout: options.killTimeout,
23
+ maxProcesses: options.maxProcesses,
24
+ shellPath,
25
+ successCondition: options.successCondition
26
+ };
27
+ const nativeCommands = configs.map((c) => {
28
+ return {
29
+ command: c.command,
30
+ cwd: c.cwd,
31
+ env: c.env,
32
+ name: c.name,
33
+ shell: c.shell,
34
+ stdin: c.stdin
35
+ };
36
+ });
37
+ return native.runConcurrentBatch(nativeCommands, nativeOptions);
38
+ }
39
+ return runConcurrentFallback(configs, { ...options, shellPath });
40
+ };
41
+ const runConcurrently = async (commands, options = {}) => {
42
+ const configs = normalizeCommands(commands);
43
+ if (configs.length === 0) {
44
+ return { closeEvents: [], success: true };
45
+ }
46
+ let result;
47
+ if (options.restart && options.restart.tries !== 0) {
48
+ result = await withRestart((cmds, options_) => coreRun(cmds, options_), configs, options, {
49
+ delay: options.restart.delay ?? 0,
50
+ tries: options.restart.tries
51
+ });
52
+ } else {
53
+ result = await coreRun(configs, options);
54
+ }
55
+ if (options.timings) {
56
+ logTimings(result.closeEvents);
57
+ }
58
+ if (options.teardown && options.teardown.length > 0) {
59
+ await runTeardown({
60
+ commands: options.teardown,
61
+ cwd: options.teardownCwd
62
+ });
63
+ }
64
+ return result;
65
+ };
66
+
67
+ export { runConcurrently };
@@ -0,0 +1,49 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ spawn
22
+ } = __cjs_getBuiltinModule("node:child_process");
23
+
24
+ const runTeardown = async (options) => {
25
+ const { commands, cwd } = options;
26
+ const results = [];
27
+ for (const command of commands) {
28
+ const code = await runTeardownCommand(command, cwd);
29
+ results.push(code);
30
+ }
31
+ return results;
32
+ };
33
+ const runTeardownCommand = (command, cwd) => new Promise((resolve) => {
34
+ const shellProgram = process.platform === "win32" ? "cmd.exe" : "/bin/sh";
35
+ const shellArgs = process.platform === "win32" ? ["/s", "/c", `"${command}"`] : ["-c", command];
36
+ const child = spawn(shellProgram, shellArgs, {
37
+ cwd,
38
+ stdio: "inherit",
39
+ windowsVerbatimArguments: process.platform === "win32"
40
+ });
41
+ child.on("close", (code) => {
42
+ resolve(code ?? 1);
43
+ });
44
+ child.on("error", () => {
45
+ resolve(1);
46
+ });
47
+ });
48
+
49
+ export { runTeardown };
@@ -0,0 +1,9 @@
1
+ const stripQuotes = (config) => {
2
+ const { command } = config;
3
+ if (/^".+?"$/.test(command) || /^'.+?'$/.test(command)) {
4
+ return { ...config, command: command.slice(1, -1) };
5
+ }
6
+ return config;
7
+ };
8
+
9
+ export { stripQuotes };
@@ -0,0 +1,49 @@
1
+ const withRestart = async (runFunction, commands, options, restartOptions) => {
2
+ const { delay, tries } = restartOptions;
3
+ if (tries === 0) {
4
+ return runFunction(commands, options);
5
+ }
6
+ const state = /* @__PURE__ */ new Map();
7
+ const allCloseEvents = [];
8
+ const userOnEvent = options.onEvent;
9
+ let pendingRestarts = [...commands];
10
+ let iteration = 0;
11
+ while (pendingRestarts.length > 0) {
12
+ const currentBatch = pendingRestarts;
13
+ pendingRestarts = [];
14
+ const result = await runFunction(currentBatch, {
15
+ ...options,
16
+ onEvent: (event) => {
17
+ userOnEvent?.(event);
18
+ }
19
+ });
20
+ for (const closeEvent of result.closeEvents) {
21
+ if (closeEvent.exitCode !== 0) {
22
+ const cmdState = state.get(closeEvent.index) ?? { attempts: 0, commandIndex: closeEvent.index };
23
+ cmdState.attempts++;
24
+ state.set(closeEvent.index, cmdState);
25
+ const shouldRestart = tries === -1 || cmdState.attempts <= tries;
26
+ if (shouldRestart) {
27
+ const delayMs = delay === "exponential" ? Math.min(2 ** (cmdState.attempts - 1) * 1e3, 3e4) : delay;
28
+ if (delayMs > 0) {
29
+ await sleep(delayMs);
30
+ }
31
+ pendingRestarts.push(currentBatch[closeEvent.index]);
32
+ continue;
33
+ }
34
+ }
35
+ allCloseEvents.push(closeEvent);
36
+ }
37
+ iteration++;
38
+ if (iteration > 1e3) {
39
+ break;
40
+ }
41
+ }
42
+ const success = allCloseEvents.every((e) => e.exitCode === 0);
43
+ return { closeEvents: allCloseEvents, success };
44
+ };
45
+ const sleep = (ms) => new Promise((resolve) => {
46
+ setTimeout(resolve, ms);
47
+ });
48
+
49
+ export { withRestart };
@@ -0,0 +1,16 @@
1
+ import type { ConstraintsConfig, ConstraintViolation, ProjectGraph } from "./types.d.ts";
2
+ /**
3
+ * Enforces project dependency constraints on a project graph.
4
+ * Returns an array of violations found. Does not throw — the caller
5
+ * decides how to handle violations (fatal error, warning, etc.).
6
+ *
7
+ * Three constraint mechanisms:
8
+ * 1. **Tag relationships**: If a project has a tag listed in `tagRelationships`,
9
+ * its dependencies must have at least one of the required tags.
10
+ * 2. **Type boundaries**: Controls which project types can depend on which.
11
+ * By default, no project may depend on an "application" type project.
12
+ * 3. **Dependency kind rules**: Controls rules based on whether the dependency
13
+ * is a production dependency, devDependency, or peerDependency.
14
+ */
15
+ declare const enforceProjectConstraints: (projectGraph: ProjectGraph, constraints: ConstraintsConfig) => ConstraintViolation[];
16
+ export { enforceProjectConstraints };
@@ -1,10 +1,33 @@
1
1
  import type { ProjectGraph, Task, TaskGraph } from "./types.d.ts";
2
+ /**
3
+ * Options for partitioning tasks across CI runners.
4
+ */
5
+ export interface PartitionOptions {
6
+ /** 1-based partition index (e.g., 1 for the first partition) */
7
+ index: number;
8
+ /** Total number of partitions */
9
+ total: number;
10
+ }
11
+ /**
12
+ * Parses a partition string like "1/4" into PartitionOptions.
13
+ * Also supports the VIS_PARTITION environment variable as fallback.
14
+ */
15
+ export declare const parsePartition: (value?: string) => PartitionOptions | undefined;
2
16
  /**
3
17
  * Manages the scheduling order of tasks based on dependencies,
4
18
  * parallelism constraints, and estimated execution times.
5
19
  */
6
20
  export declare class TaskScheduler {
7
21
  #private;
22
+ /**
23
+ * Partitions a list of tasks for distributed CI execution.
24
+ * Tasks are sorted by ID for deterministic distribution, then split
25
+ * using ceiling division so partitions differ by at most one task.
26
+ * @param tasks The full list of tasks to partition
27
+ * @param partition The partition configuration (1-based index and total)
28
+ * @returns The subset of tasks assigned to this partition
29
+ */
30
+ static partitionTasks(tasks: Task[], partition: PartitionOptions): Task[];
8
31
  constructor(taskGraph: TaskGraph, projectGraph: ProjectGraph, maxParallel?: number);
9
32
  /**
10
33
  * Returns the next batch of tasks that are ready to execute.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Minimal virtual terminal buffer that processes ANSI escape sequences
3
+ * for cursor movement and line erasure. This allows PTY output from
4
+ * interactive tools (inquirer, etc.) to render correctly by updating
5
+ * lines in place rather than always appending.
6
+ *
7
+ * Supported sequences:
8
+ * - \r carriage return (cursor to column 0)
9
+ * - \n line feed (new line)
10
+ * - \x1b[nA cursor up n lines
11
+ * - \x1b[nB cursor down n lines
12
+ * - \x1b[nC cursor forward n columns
13
+ * - \x1b[nD cursor back n columns
14
+ * - \x1b[nG cursor to column n
15
+ * - \x1b[r;cH cursor position
16
+ * - \x1b[K erase from cursor to end of line (0K, 1K, 2K)
17
+ * - \x1b[J erase from cursor to end of display (0J, 1J, 2J)
18
+ * - \x1b[...m SGR (colors/styles) — passed through into output
19
+ */
20
+ export declare class TerminalBuffer {
21
+ #private;
22
+ constructor(maxBytes?: number);
23
+ /**
24
+ * Process raw PTY output data.
25
+ */
26
+ write(data: string): void;
27
+ /** Get the current buffer content as a string. */
28
+ toString(): string;
29
+ }