bunosh 0.5.0 → 0.5.8
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 +26 -2
- package/bunosh.js +0 -39
- package/index.js +7 -4
- package/package.json +18 -2
- package/src/formatters/console.js +5 -1
- package/src/io.js +0 -5
- package/src/printer.js +29 -9
- package/src/program.js +46 -12
- package/src/task.js +27 -16
- package/src/tasks/assert.js +23 -0
- package/src/tasks/exec.js +4 -248
- package/src/tasks/fetch.js +2 -1
- package/src/tasks/shell.js +194 -119
- package/src/upgrade.js +135 -30
- package/types.d.ts +2 -1
- package/src/mcp-server.js +0 -575
package/README.md
CHANGED
|
@@ -187,7 +187,7 @@ Bunoshfile.api.js # bunosh api:deploy, bunosh api:test
|
|
|
187
187
|
Built-in tasks are available via `global.bunosh`:
|
|
188
188
|
|
|
189
189
|
```javascript
|
|
190
|
-
const { exec, shell, fetch, writeToFile, copyFile, task } = global.bunosh;
|
|
190
|
+
const { exec, shell, fetch, writeToFile, copyFile, task, assert } = global.bunosh;
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
> Global variables are used instead of imports so bunosh works with the single-executable on any platform.
|
|
@@ -195,6 +195,7 @@ const { exec, shell, fetch, writeToFile, copyFile, task } = global.bunosh;
|
|
|
195
195
|
* Async tasks: `exec`, `shell`, `fetch`
|
|
196
196
|
* Sync tasks: `writeToFile`, `copyFile`
|
|
197
197
|
* Task wrapper: `task`
|
|
198
|
+
* Precondition guard: `assert`
|
|
198
199
|
|
|
199
200
|
Each task returns a `TaskResult` object:
|
|
200
201
|
|
|
@@ -273,6 +274,30 @@ For details see the [Bun shell](https://bun.sh/docs/runtime/shell) reference.
|
|
|
273
274
|
| `exec` | Single command execution | spawn process | Node.js + Bun, platform dependent |
|
|
274
275
|
| `shell` | Cross-platform shell commands | Bun shell | Bun only, cross-platform |
|
|
275
276
|
|
|
277
|
+
### `assert`
|
|
278
|
+
|
|
279
|
+
Guard a command on a precondition. If the condition is falsy, `assert` prints a red failure line and records a failed task — the run continues, and the process exits with code 1 at the end:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
export async function deploy() {
|
|
283
|
+
assert(process.env.TOKEN, 'TOKEN must be set');
|
|
284
|
+
assert(await Bun.file('dist/bundle.js').exists(), 'bundle not built');
|
|
285
|
+
await shell`./scripts/deploy.sh`;
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
With `task.stopOnFailures()` enabled, a failed `assert` exits immediately at that line:
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
export async function strict() {
|
|
293
|
+
task.stopOnFailures();
|
|
294
|
+
assert(process.env.TOKEN, 'TOKEN must be set');
|
|
295
|
+
await shell`./scripts/deploy.sh`;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`assert` does not throw a JavaScript exception in default mode — it records the failure and execution continues. Use `task.stopOnFailures()` (or `return` after the `assert`) when you need a hard stop.
|
|
300
|
+
|
|
276
301
|
### `fetch`
|
|
277
302
|
|
|
278
303
|
Wraps the fetch API as a task:
|
|
@@ -427,7 +452,6 @@ export async function checkServices() {
|
|
|
427
452
|
|
|
428
453
|
- **[Examples](docs/examples.md)** — Real-world examples and workflows
|
|
429
454
|
- **[AI Integration](docs/ai.md)** — Built-in AI support
|
|
430
|
-
- **[MCP Integration](docs/mcp.md)** — Expose commands to AI assistants (Claude, Cursor, etc.)
|
|
431
455
|
- **[JavaScript Execution](docs/javascript-execution.md)** — Execute JavaScript directly via CLI
|
|
432
456
|
- **[Bash Migration Guide](docs/bash-migration-guide.md)** — Convert bash scripts to Bunosh
|
|
433
457
|
- **[Node.js Migration Guide](docs/nodejs-migration-guide.md)** — Migrate from Node.js scripts
|
package/bunosh.js
CHANGED
|
@@ -124,45 +124,6 @@ async function main() {
|
|
|
124
124
|
process.argv.splice(envFileIndex, 1);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
const mcpFlagIndex = process.argv.indexOf('-mcp');
|
|
128
|
-
if (mcpFlagIndex !== -1) {
|
|
129
|
-
process.argv.splice(mcpFlagIndex, 1);
|
|
130
|
-
|
|
131
|
-
process.env.BUNOSH_MCP_MODE = 'true';
|
|
132
|
-
|
|
133
|
-
const { createMcpServer, startMcpServer } = await import('./src/mcp-server.js');
|
|
134
|
-
|
|
135
|
-
let tasksFile;
|
|
136
|
-
let bunoshfileDir;
|
|
137
|
-
if (customBunoshfile) {
|
|
138
|
-
const resolvedPath = path.isAbsolute(customBunoshfile) ? customBunoshfile : path.resolve(customBunoshfile);
|
|
139
|
-
if (existsSync(resolvedPath) && statSync(resolvedPath).isDirectory()) {
|
|
140
|
-
tasksFile = path.join(resolvedPath, BUNOSHFILE);
|
|
141
|
-
bunoshfileDir = resolvedPath;
|
|
142
|
-
} else {
|
|
143
|
-
tasksFile = resolvedPath;
|
|
144
|
-
bunoshfileDir = path.dirname(resolvedPath);
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
tasksFile = path.join(process.cwd(), BUNOSHFILE);
|
|
148
|
-
bunoshfileDir = process.cwd();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (!existsSync(tasksFile)) {
|
|
152
|
-
console.error('Bunoshfile not found for MCP mode');
|
|
153
|
-
process.exit(1);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
loadEnvFiles(bunoshfileDir, customEnvFile);
|
|
157
|
-
|
|
158
|
-
const { tasks, sources } = await loadBunoshfiles(tasksFile);
|
|
159
|
-
|
|
160
|
-
const server = createMcpServer(tasks, sources);
|
|
161
|
-
await startMcpServer(server);
|
|
162
|
-
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
127
|
let tasksFile;
|
|
167
128
|
let bunoshfileDir;
|
|
168
129
|
if (customBunoshfile) {
|
package/index.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import exec from "./src/tasks/exec.js";
|
|
2
1
|
import shell from "./src/tasks/shell.js";
|
|
2
|
+
// Deprecated: `exec` is an alias for `shell`, kept for backward compatibility.
|
|
3
|
+
const exec = shell;
|
|
3
4
|
import fetch from "./src/tasks/fetch.js";
|
|
4
5
|
import writeToFile from "./src/tasks/writeToFile.js";
|
|
5
6
|
import copyFile from "./src/tasks/copyFile.js";
|
|
6
7
|
import ai from "./src/tasks/ai.js";
|
|
8
|
+
import assert from "./src/tasks/assert.js";
|
|
7
9
|
import { ask, yell, say } from "./src/io.js";
|
|
8
10
|
import { task, tryTask, stopOnFail, ignoreFail, stopOnFailures, ignoreFailures, silence, prints, silent, TaskResult } from "./src/task.js";
|
|
9
11
|
|
|
10
|
-
export { exec, shell, fetch, writeToFile, copyFile, ai, ask, yell, say, task, tryTask, stopOnFail, ignoreFail, stopOnFailures, ignoreFailures, silence, prints, silent, TaskResult };
|
|
12
|
+
export { exec, shell, fetch, writeToFile, copyFile, ai, assert, ask, yell, say, task, tryTask, stopOnFail, ignoreFail, stopOnFailures, ignoreFailures, silence, prints, silent, TaskResult };
|
|
11
13
|
|
|
12
14
|
export function buildCmd(cmd) {
|
|
13
15
|
return function (args) {
|
|
14
|
-
return
|
|
16
|
+
return shell`${cmd} ${args}`;
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -25,6 +27,7 @@ global.bunosh = {
|
|
|
25
27
|
writeToFile,
|
|
26
28
|
copyFile,
|
|
27
29
|
ai,
|
|
30
|
+
assert,
|
|
28
31
|
stopOnFail,
|
|
29
32
|
ignoreFail,
|
|
30
33
|
task,
|
|
@@ -35,7 +38,7 @@ global.bunosh = {
|
|
|
35
38
|
silent,
|
|
36
39
|
TaskResult,
|
|
37
40
|
buildCmd,
|
|
38
|
-
$:
|
|
41
|
+
$: shell,
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
export default global.bunosh;
|
package/package.json
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunosh",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
|
+
"description": "Task runner that turns JavaScript functions into CLI commands. Runs on Bun and Node.js.",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"module": "index.js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/DavertMik/bunosh.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/DavertMik/bunosh#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/DavertMik/bunosh/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "davert",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"task-runner",
|
|
18
|
+
"cli",
|
|
19
|
+
"bun",
|
|
20
|
+
"automation",
|
|
21
|
+
"scripts"
|
|
22
|
+
],
|
|
6
23
|
"bin": {
|
|
7
24
|
"bunosh": "./bunosh.js"
|
|
8
25
|
},
|
|
@@ -19,7 +36,6 @@
|
|
|
19
36
|
"@ai-sdk/openai": "^2.0.23",
|
|
20
37
|
"@babel/parser": "^7.27.5",
|
|
21
38
|
"@babel/traverse": "^7.27.4",
|
|
22
|
-
"@modelcontextprotocol/sdk": "^1.19.1",
|
|
23
39
|
"ai": "^5.0.29",
|
|
24
40
|
"chalk": "^5.4.1",
|
|
25
41
|
"commander": "^14.0.0",
|
|
@@ -12,7 +12,11 @@ const STATUS_CONFIG = {
|
|
|
12
12
|
|
|
13
13
|
export class ConsoleFormatter extends BaseFormatter {
|
|
14
14
|
shouldDelayStart() {
|
|
15
|
-
return
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getStartDelay() {
|
|
19
|
+
return 1000;
|
|
16
20
|
}
|
|
17
21
|
format(taskName, status, taskType, extra = {}) {
|
|
18
22
|
const config = STATUS_CONFIG[status];
|
package/src/io.js
CHANGED
|
@@ -7,11 +7,6 @@ export function say(...args) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export async function ask(question, defaultValueOrOptions = {}, options = {}) {
|
|
10
|
-
// Check if we're in MCP mode and should use the interactive ask function
|
|
11
|
-
if (globalThis._mcpAskFunction) {
|
|
12
|
-
return globalThis._mcpAskFunction(question, defaultValueOrOptions, options);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
10
|
// Track that we're in an ask operation to prevent duplicate exit summaries
|
|
16
11
|
globalThis._bunoshInAskOperation = true;
|
|
17
12
|
// Smart parameter detection
|
package/src/printer.js
CHANGED
|
@@ -85,7 +85,10 @@ export class Printer {
|
|
|
85
85
|
const delay = this.formatter.getStartDelay ? this.formatter.getStartDelay() : 50;
|
|
86
86
|
|
|
87
87
|
if (this.formatter.shouldDelayStart && this.formatter.shouldDelayStart()) {
|
|
88
|
+
this.pendingStart = { taskName, extra };
|
|
88
89
|
this.startTimeout = setTimeout(() => {
|
|
90
|
+
this.startTimeout = null;
|
|
91
|
+
this.pendingStart = null;
|
|
89
92
|
this.hasStarted = true;
|
|
90
93
|
this.print(taskName, 'start', extra);
|
|
91
94
|
}, delay);
|
|
@@ -95,19 +98,37 @@ export class Printer {
|
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
_flushPendingStart() {
|
|
102
|
+
if (!this.startTimeout) return;
|
|
103
|
+
clearTimeout(this.startTimeout);
|
|
104
|
+
this.startTimeout = null;
|
|
105
|
+
const pending = this.pendingStart;
|
|
106
|
+
this.pendingStart = null;
|
|
107
|
+
if (pending) {
|
|
108
|
+
this.hasStarted = true;
|
|
109
|
+
this.print(pending.taskName, 'start', pending.extra);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_cancelPendingStart() {
|
|
99
114
|
if (this.startTimeout) {
|
|
100
115
|
clearTimeout(this.startTimeout);
|
|
101
116
|
this.startTimeout = null;
|
|
102
117
|
}
|
|
118
|
+
this.pendingStart = null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
cancel() {
|
|
122
|
+
this._cancelPendingStart();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
finish(taskName, extra = {}) {
|
|
126
|
+
this._cancelPendingStart();
|
|
103
127
|
this.print(taskName, 'finish', extra);
|
|
104
128
|
}
|
|
105
129
|
|
|
106
130
|
error(taskName, error = null, extra = {}) {
|
|
107
|
-
|
|
108
|
-
clearTimeout(this.startTimeout);
|
|
109
|
-
this.startTimeout = null;
|
|
110
|
-
}
|
|
131
|
+
this._cancelPendingStart();
|
|
111
132
|
if (error) {
|
|
112
133
|
extra.error = typeof error === 'string' ? error : error.message;
|
|
113
134
|
}
|
|
@@ -115,10 +136,7 @@ export class Printer {
|
|
|
115
136
|
}
|
|
116
137
|
|
|
117
138
|
warning(taskName, error = null, extra = {}) {
|
|
118
|
-
|
|
119
|
-
clearTimeout(this.startTimeout);
|
|
120
|
-
this.startTimeout = null;
|
|
121
|
-
}
|
|
139
|
+
this._cancelPendingStart();
|
|
122
140
|
if (error) {
|
|
123
141
|
extra.error = typeof error === 'string' ? error : error.message;
|
|
124
142
|
}
|
|
@@ -128,6 +146,8 @@ export class Printer {
|
|
|
128
146
|
output(line, isError = false) {
|
|
129
147
|
if (!line.trim()) return;
|
|
130
148
|
|
|
149
|
+
this._flushPendingStart();
|
|
150
|
+
|
|
131
151
|
// Add task prefix for parallel tasks on output lines
|
|
132
152
|
const prefix = this.taskId ? getTaskPrefix(this.taskId) : '';
|
|
133
153
|
const prefixedLine = prefix ? `${prefix} ${line}` : line;
|
package/src/program.js
CHANGED
|
@@ -8,7 +8,7 @@ import { yell } from './io.js';
|
|
|
8
8
|
import { formatError } from './error-formatter.js';
|
|
9
9
|
import cprint from "./font.js";
|
|
10
10
|
import { handleCompletion, detectCurrentShell, installCompletion, getCompletionPaths } from './completion.js';
|
|
11
|
-
import { upgradeCommand } from './upgrade.js';
|
|
11
|
+
import { upgradeCommand, printUpgradeNoticeIfAvailable } from './upgrade.js';
|
|
12
12
|
|
|
13
13
|
export const BUNOSHFILE = `Bunoshfile.js`;
|
|
14
14
|
|
|
@@ -265,16 +265,22 @@ export default async function bunosh(commands, sources) {
|
|
|
265
265
|
}
|
|
266
266
|
});
|
|
267
267
|
|
|
268
|
-
const
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
const optNames = Object.keys(opts);
|
|
269
|
+
if (optNames.length > 0) {
|
|
270
|
+
const lastArg = commanderArgs[commanderArgs.length - 1];
|
|
271
|
+
const optionsObj = (lastArg && typeof lastArg.opts === 'function') ? lastArg.opts() : lastArg;
|
|
272
|
+
const mergedOpts = {};
|
|
273
|
+
optNames.forEach((optName) => {
|
|
274
|
+
const camelName = optName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
275
|
+
if (optionsObj && optionsObj[camelName] !== undefined) {
|
|
276
|
+
mergedOpts[camelName] = optionsObj[camelName];
|
|
277
|
+
} else if (optionsObj && optionsObj[optName] !== undefined) {
|
|
278
|
+
mergedOpts[camelName] = optionsObj[optName];
|
|
274
279
|
} else {
|
|
275
|
-
|
|
280
|
+
mergedOpts[camelName] = opts[optName];
|
|
276
281
|
}
|
|
277
282
|
});
|
|
283
|
+
transformedArgs.push(mergedOpts);
|
|
278
284
|
}
|
|
279
285
|
|
|
280
286
|
try {
|
|
@@ -385,6 +391,23 @@ export default async function bunosh(commands, sources) {
|
|
|
385
391
|
|
|
386
392
|
internalCommands.push(setupCompletionCmd);
|
|
387
393
|
|
|
394
|
+
const SKILLS_REPO = 'DavertMik/bunosh-skills';
|
|
395
|
+
|
|
396
|
+
const installSkillsCmd = program.command('install-skills')
|
|
397
|
+
.description('Print the command to install Bunosh AI agent skills.')
|
|
398
|
+
.action(() => {
|
|
399
|
+
console.log();
|
|
400
|
+
console.log(`🤖 Install Bunosh AI agent skills (Claude Code, Cursor, Codex, ...):`);
|
|
401
|
+
console.log();
|
|
402
|
+
console.log(` ${color.bold(`npx skills add ${SKILLS_REPO}`)}`);
|
|
403
|
+
console.log();
|
|
404
|
+
console.log(color.dim(` Skills: bunosh-fundamentals, migrate-to-bunosh`));
|
|
405
|
+
console.log(color.dim(` ${SKILLS_REPO} · https://buno.sh`));
|
|
406
|
+
console.log();
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
internalCommands.push(installSkillsCmd);
|
|
410
|
+
|
|
388
411
|
const upgradeCmd = program.command('upgrade')
|
|
389
412
|
.description('Upgrade bunosh to the latest version')
|
|
390
413
|
.option('-f, --force', 'Force upgrade even if already on latest version')
|
|
@@ -410,7 +433,7 @@ export default async function bunosh(commands, sources) {
|
|
|
410
433
|
}
|
|
411
434
|
|
|
412
435
|
const lines = description.split('\n');
|
|
413
|
-
const firstLine = ` ${color.white.bold(paddedName)} ${lines[0]}`;
|
|
436
|
+
const firstLine = ` ${color.white.bold(paddedName)} ${color.dim(lines[0])}`;
|
|
414
437
|
const indentedLines = lines.slice(1).map(line =>
|
|
415
438
|
line.trim() ? ` ${line}` : ''
|
|
416
439
|
).filter(line => line);
|
|
@@ -445,7 +468,7 @@ ${mainCommands}
|
|
|
445
468
|
}
|
|
446
469
|
|
|
447
470
|
const lines = description.split('\n');
|
|
448
|
-
const firstLine = ` ${color.white.bold(paddedName)} ${lines[0]}`;
|
|
471
|
+
const firstLine = ` ${color.white.bold(paddedName)} ${color.dim(lines[0])}`;
|
|
449
472
|
const indentedLines = lines.slice(1).map(line =>
|
|
450
473
|
line.trim() ? ` ${line}` : ''
|
|
451
474
|
).filter(line => line);
|
|
@@ -471,7 +494,7 @@ ${devCommands}
|
|
|
471
494
|
}
|
|
472
495
|
|
|
473
496
|
const lines = description.split('\n');
|
|
474
|
-
const firstLine = ` ${color.white.bold(paddedName)} ${lines[0]}`;
|
|
497
|
+
const firstLine = ` ${color.white.bold(paddedName)} ${color.dim(lines[0])}`;
|
|
475
498
|
const indentedLines = lines.slice(1).map(line =>
|
|
476
499
|
line.trim() ? ` ${line}` : ''
|
|
477
500
|
).filter(line => line);
|
|
@@ -485,7 +508,10 @@ ${namespaceCommands}
|
|
|
485
508
|
}
|
|
486
509
|
});
|
|
487
510
|
|
|
488
|
-
|
|
511
|
+
const helpFlagRequested = process.argv.includes('--help') || process.argv.includes('-h');
|
|
512
|
+
|
|
513
|
+
if (helpFlagRequested) {
|
|
514
|
+
helpText += color.dim(`Special Commands:
|
|
489
515
|
${color.bold('bunosh edit')} 📝 Edit bunosh file with $EDITOR
|
|
490
516
|
${color.bold('bunosh export:scripts')} 📥 Export commands to package.json
|
|
491
517
|
${color.bold('bunosh upgrade')} 🦾 Upgrade bunosh
|
|
@@ -494,6 +520,13 @@ ${namespaceCommands}
|
|
|
494
520
|
${color.bold('bunosh --env-file …')} 🔧 Load custom environment file
|
|
495
521
|
`);
|
|
496
522
|
|
|
523
|
+
helpText += `
|
|
524
|
+
${color.bold('🤖 AI agent skills')} ${color.dim('(Claude Code, Cursor, Codex, ...)')}
|
|
525
|
+
${color.bold('npx skills add DavertMik/bunosh-skills')}
|
|
526
|
+
${color.dim('bunosh-fundamentals · migrate-to-bunosh — see "bunosh install-skills"')}
|
|
527
|
+
`;
|
|
528
|
+
}
|
|
529
|
+
|
|
497
530
|
program.addHelpText('after', helpText);
|
|
498
531
|
|
|
499
532
|
program.on("command:*", (cmd) => {
|
|
@@ -505,6 +538,7 @@ ${namespaceCommands}
|
|
|
505
538
|
|
|
506
539
|
if (process.argv.length === 2) {
|
|
507
540
|
program.outputHelp();
|
|
541
|
+
await printUpgradeNoticeIfAvailable();
|
|
508
542
|
return program;
|
|
509
543
|
}
|
|
510
544
|
|
package/src/task.js
CHANGED
|
@@ -47,6 +47,22 @@ export function getIgnoreFailuresMode() {
|
|
|
47
47
|
return ignoreFailuresMode;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
export function isStopOnFailuresMode() {
|
|
51
|
+
return stopOnFailuresMode;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isTestEnv() {
|
|
55
|
+
const commandArgs = process.argv.slice(2);
|
|
56
|
+
return process.env.NODE_ENV === 'test' ||
|
|
57
|
+
commandArgs.some(arg => {
|
|
58
|
+
const lower = arg.toLowerCase();
|
|
59
|
+
return lower.includes('vitest') ||
|
|
60
|
+
lower.includes('jest') ||
|
|
61
|
+
lower === '--test' ||
|
|
62
|
+
lower.startsWith('test:');
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
export function silence() {
|
|
51
67
|
globalSilenceMode = true;
|
|
52
68
|
}
|
|
@@ -198,6 +214,8 @@ export async function task(name, fn, isSilent = false) {
|
|
|
198
214
|
|
|
199
215
|
// Check if result is a TaskResult instance
|
|
200
216
|
if (result && result.constructor && result.constructor.name === 'TaskResult') {
|
|
217
|
+
printer.cancel();
|
|
218
|
+
runningTasks.delete(taskInfo.id);
|
|
201
219
|
return result;
|
|
202
220
|
}
|
|
203
221
|
|
|
@@ -220,24 +238,12 @@ export async function task(name, fn, isSilent = false) {
|
|
|
220
238
|
printer.error(name, err);
|
|
221
239
|
runningTasks.delete(taskInfo.id);
|
|
222
240
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const isTestEnvironment = process.env.NODE_ENV === 'test' ||
|
|
226
|
-
typeof Bun?.jest !== 'undefined' ||
|
|
227
|
-
commandArgs.some(arg => {
|
|
228
|
-
const lowerArg = arg.toLowerCase();
|
|
229
|
-
return lowerArg.includes('vitest') ||
|
|
230
|
-
lowerArg.includes('jest') ||
|
|
231
|
-
lowerArg === '--test' ||
|
|
232
|
-
lowerArg.startsWith('test:');
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
// Exit immediately if stopOnFailures mode is enabled
|
|
241
|
+
const isTestEnvironment = isTestEnv();
|
|
242
|
+
|
|
236
243
|
if (stopOnFailuresMode && !isTestEnvironment) {
|
|
237
244
|
process.exit(1);
|
|
238
245
|
}
|
|
239
|
-
|
|
240
|
-
// Also exit if stopFailToggle is enabled (legacy behavior)
|
|
246
|
+
|
|
241
247
|
if (stopFailToggle && !isTestEnvironment) {
|
|
242
248
|
process.exit(1);
|
|
243
249
|
}
|
|
@@ -246,8 +252,13 @@ export async function task(name, fn, isSilent = false) {
|
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
// Add
|
|
255
|
+
// Add methods to task function
|
|
250
256
|
task.try = tryTask;
|
|
257
|
+
task.stopOnFailures = stopOnFailures;
|
|
258
|
+
task.ignoreFailures = ignoreFailures;
|
|
259
|
+
task.silence = silence;
|
|
260
|
+
task.prints = prints;
|
|
261
|
+
task.silent = silent;
|
|
251
262
|
|
|
252
263
|
|
|
253
264
|
export class SilentTaskWrapper {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createTaskInfo, finishTaskInfo, getCurrentTaskId, runningTasks, isStopOnFailuresMode, isTestEnv } from '../task.js';
|
|
2
|
+
import Printer from '../printer.js';
|
|
3
|
+
|
|
4
|
+
export default function assert(condition, message = 'Assertion failed') {
|
|
5
|
+
const currentTaskId = getCurrentTaskId();
|
|
6
|
+
const parent = currentTaskId ? runningTasks.get(currentTaskId) : null;
|
|
7
|
+
const isParentSilent = parent?.isSilent || false;
|
|
8
|
+
|
|
9
|
+
const taskInfo = createTaskInfo(message, currentTaskId, isParentSilent);
|
|
10
|
+
const printer = new Printer('assert', taskInfo.id);
|
|
11
|
+
|
|
12
|
+
if (condition) {
|
|
13
|
+
printer.finish(message);
|
|
14
|
+
finishTaskInfo(taskInfo, true, null, message);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const error = new Error(message);
|
|
19
|
+
printer.error(message, error);
|
|
20
|
+
finishTaskInfo(taskInfo, false, error, message);
|
|
21
|
+
|
|
22
|
+
if (isStopOnFailuresMode() && !isTestEnv()) process.exit(1);
|
|
23
|
+
}
|