bunosh 0.4.6 → 0.4.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 +1 -36
- package/bunosh.js +39 -17
- package/package.json +1 -1
- package/src/formatters/console.js +36 -4
- package/src/task.js +18 -3
package/README.md
CHANGED
|
@@ -398,41 +398,6 @@ bunosh --bunoshfile Bunoshfile.dev.js -mcp
|
|
|
398
398
|
|
|
399
399
|
</details>
|
|
400
400
|
|
|
401
|
-
<details>
|
|
402
|
-
|
|
403
|
-
#### Best Practices for MCP
|
|
404
|
-
|
|
405
|
-
### Command Design for AI
|
|
406
|
-
|
|
407
|
-
Design your commands to work well with AI assistants:
|
|
408
|
-
|
|
409
|
-
* Add comments to all commands
|
|
410
|
-
* Describe use cases for each Command
|
|
411
|
-
* Describe each param using JSDoc style comments
|
|
412
|
-
* Include types when describing parameters
|
|
413
|
-
|
|
414
|
-
```javascript
|
|
415
|
-
/**
|
|
416
|
-
* Builds the project for specified environment
|
|
417
|
-
* @param {string} environment - Target environment: 'development', 'staging', or 'production'
|
|
418
|
-
* @param {Object} options - Build options
|
|
419
|
-
* @param {boolean} options.verbose - Enable verbose logging
|
|
420
|
-
* @param {boolean} options.analyze - Run bundle analysis after build
|
|
421
|
-
*/
|
|
422
|
-
export async function build(environment = 'development', options = {}) {
|
|
423
|
-
const config = getBuildConfig(environment);
|
|
424
|
-
if (options.verbose) say(`🔨 Building for ${environment}...`);
|
|
425
|
-
|
|
426
|
-
await exec`npm run build:${environment}`;
|
|
427
|
-
|
|
428
|
-
if (options.analyze) {
|
|
429
|
-
await exec`npm run analyze`;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
say('✅ Build complete!');
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
401
|
## Tasks
|
|
437
402
|
|
|
438
403
|
Bunosh provides built-in tasks which are available via `global.bunosh`:
|
|
@@ -738,7 +703,7 @@ Gracefully handle operations that might fail:
|
|
|
738
703
|
* Check service availability
|
|
739
704
|
*/
|
|
740
705
|
export async function checkServices() {
|
|
741
|
-
const dbConnected = await task.try(shell`nc -z localhost 5432`);
|
|
706
|
+
const dbConnected = await task.try(() => shell`nc -z localhost 5432`);
|
|
742
707
|
|
|
743
708
|
if (dbConnected) {
|
|
744
709
|
say('✅ Database connected');
|
package/bunosh.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
globalThis._bunoshStartTime = Date.now();
|
|
5
5
|
globalThis._bunoshCommandCompleted = false;
|
|
6
6
|
globalThis._bunoshGlobalTasksExecuted = [];
|
|
7
|
+
globalThis._bunoshIgnoreFailuresMode = false;
|
|
7
8
|
globalThis._bunoshGlobalTaskStatus = {
|
|
8
9
|
RUNNING: 'running',
|
|
9
10
|
FAIL: 'fail',
|
|
@@ -310,39 +311,60 @@ process.on('uncaughtException', (error) => {
|
|
|
310
311
|
process.exit(1);
|
|
311
312
|
});
|
|
312
313
|
|
|
313
|
-
// Handle exit for task summary
|
|
314
314
|
process.on('exit', (code) => {
|
|
315
315
|
if (!process.env.BUNOSH_COMMAND_STARTED) return;
|
|
316
|
-
|
|
317
|
-
// Don't print summary if exit was due to stdin closing during an ask operation
|
|
318
|
-
// This prevents duplicate output when ask commands don't receive all required input
|
|
316
|
+
|
|
319
317
|
if (globalThis._bunoshInAskOperation && code === 0) {
|
|
320
318
|
return;
|
|
321
319
|
}
|
|
322
|
-
|
|
323
|
-
// Access global values directly
|
|
320
|
+
|
|
324
321
|
const tasksExecuted = globalThis._bunoshGlobalTasksExecuted || [];
|
|
325
322
|
const TaskStatus = globalThis._bunoshGlobalTaskStatus || { FAIL: 'fail', WARNING: 'warning' };
|
|
326
|
-
|
|
327
|
-
// Calculate total time from when the process started
|
|
323
|
+
|
|
328
324
|
const totalTime = Date.now() - globalThis._bunoshStartTime || 0;
|
|
329
325
|
const tasksFailed = tasksExecuted.filter(ti => ti.result?.status === TaskStatus.FAIL).length;
|
|
330
326
|
const tasksWarning = tasksExecuted.filter(ti => ti.result?.status === TaskStatus.WARNING).length;
|
|
331
|
-
|
|
332
|
-
|
|
327
|
+
|
|
328
|
+
const commandArgs = process.argv.slice(2);
|
|
333
329
|
const isTestEnvironment = process.env.NODE_ENV === 'test' ||
|
|
334
330
|
(typeof Bun !== 'undefined' && typeof Bun?.jest !== 'undefined') ||
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
331
|
+
commandArgs.some(arg => {
|
|
332
|
+
const lowerArg = arg.toLowerCase();
|
|
333
|
+
return lowerArg.includes('vitest') ||
|
|
334
|
+
lowerArg.includes('jest') ||
|
|
335
|
+
lowerArg === '--test' ||
|
|
336
|
+
lowerArg.startsWith('test:');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const ignoreFailuresMode = globalThis._bunoshIgnoreFailuresMode || false;
|
|
340
|
+
|
|
341
|
+
if (process.env.BUNOSH_DEBUG) {
|
|
342
|
+
console.log('\n[DEBUG] Exit handler:');
|
|
343
|
+
console.log(' tasksFailed:', tasksFailed);
|
|
344
|
+
console.log(' isTestEnvironment:', isTestEnvironment);
|
|
345
|
+
console.log(' ignoreFailuresMode:', ignoreFailuresMode);
|
|
346
|
+
console.log(' NODE_ENV:', process.env.NODE_ENV);
|
|
347
|
+
console.log(' commandArgs:', commandArgs);
|
|
348
|
+
console.log(' full process.argv:', process.argv);
|
|
349
|
+
if (isTestEnvironment) {
|
|
350
|
+
const matchingArg = commandArgs.find(arg => {
|
|
351
|
+
const lowerArg = arg.toLowerCase();
|
|
352
|
+
return lowerArg.includes('vitest') ||
|
|
353
|
+
lowerArg.includes('jest') ||
|
|
354
|
+
lowerArg === '--test' ||
|
|
355
|
+
lowerArg.startsWith('test:');
|
|
356
|
+
});
|
|
357
|
+
console.log(' Matched command arg:', matchingArg);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (tasksFailed > 0 && !isTestEnvironment && !ignoreFailuresMode) {
|
|
339
362
|
process.exitCode = 1;
|
|
340
363
|
}
|
|
341
|
-
|
|
342
|
-
const finalExitCode = (tasksFailed > 0 && !isTestEnvironment) ? 1 : code;
|
|
364
|
+
|
|
365
|
+
const finalExitCode = (tasksFailed > 0 && !isTestEnvironment && !ignoreFailuresMode) ? 1 : code;
|
|
343
366
|
const success = finalExitCode === 0;
|
|
344
367
|
|
|
345
|
-
// Debug: Check if this handler has already run
|
|
346
368
|
if (globalThis._bunoshExitHandlerCalled) {
|
|
347
369
|
console.log('\n[DEBUG] Exit handler already called, skipping duplicate');
|
|
348
370
|
return;
|
package/package.json
CHANGED
|
@@ -56,9 +56,8 @@ export class ConsoleFormatter extends BaseFormatter {
|
|
|
56
56
|
let line = leftContent + padding + rightContent;
|
|
57
57
|
|
|
58
58
|
if (icon.trim()) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
line = icon + ' ' + chalk.underline(underlineContent) + rightContent;
|
|
59
|
+
const underlineContent = taskTypeFormatted + taskNameFormatted;
|
|
60
|
+
line = icon + ' ' + chalk.underline(underlineContent) + padding + rightContent;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
let result = line;
|
|
@@ -74,7 +73,40 @@ export class ConsoleFormatter extends BaseFormatter {
|
|
|
74
73
|
|
|
75
74
|
formatOutput(line, isError = false) {
|
|
76
75
|
if (!line.trim()) return '';
|
|
77
|
-
|
|
76
|
+
|
|
77
|
+
const indent = ' ';
|
|
78
|
+
const terminalWidth = process.stdout.columns || 100;
|
|
79
|
+
const maxLineWidth = terminalWidth - indent.length;
|
|
80
|
+
|
|
81
|
+
let formattedLine = line;
|
|
82
|
+
const plainLine = this._stripAnsi(line);
|
|
83
|
+
|
|
84
|
+
if (plainLine.length > maxLineWidth) {
|
|
85
|
+
const truncateAt = maxLineWidth - 3;
|
|
86
|
+
let charCount = 0;
|
|
87
|
+
let truncatedLine = '';
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < line.length; i++) {
|
|
90
|
+
if (line[i] === '\u001b') {
|
|
91
|
+
let j = i;
|
|
92
|
+
while (j < line.length && line[j] !== 'm') j++;
|
|
93
|
+
truncatedLine += line.substring(i, j + 1);
|
|
94
|
+
i = j;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (charCount >= truncateAt) break;
|
|
99
|
+
|
|
100
|
+
truncatedLine += line[i];
|
|
101
|
+
charCount++;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
formattedLine = truncatedLine + '...';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
formattedLine = indent + formattedLine;
|
|
108
|
+
|
|
109
|
+
return isError ? chalk.red(formattedLine) : formattedLine;
|
|
78
110
|
}
|
|
79
111
|
|
|
80
112
|
_stripAnsi(str) {
|
package/src/task.js
CHANGED
|
@@ -28,15 +28,23 @@ export function ignoreFail(enable = true) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Global failure mode control
|
|
31
|
-
// true = stop on failures (exit with code 1), false = continue on failures
|
|
32
31
|
let stopOnFailuresMode = false;
|
|
32
|
+
let ignoreFailuresMode = false;
|
|
33
33
|
|
|
34
34
|
export function ignoreFailures() {
|
|
35
35
|
stopOnFailuresMode = false;
|
|
36
|
+
ignoreFailuresMode = true;
|
|
37
|
+
globalThis._bunoshIgnoreFailuresMode = true;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export function stopOnFailures() {
|
|
39
41
|
stopOnFailuresMode = true;
|
|
42
|
+
ignoreFailuresMode = false;
|
|
43
|
+
globalThis._bunoshIgnoreFailuresMode = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getIgnoreFailuresMode() {
|
|
47
|
+
return ignoreFailuresMode;
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
export function silence() {
|
|
@@ -110,7 +118,7 @@ export class TaskInfo {
|
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
export async function tryTask(name, fn, isSilent =
|
|
121
|
+
export async function tryTask(name, fn, isSilent = true) {
|
|
114
122
|
if (!fn) {
|
|
115
123
|
fn = name;
|
|
116
124
|
name = fn.toString().slice(0, 50).replace(/\s+/g, ' ').trim();
|
|
@@ -198,9 +206,16 @@ export async function task(name, fn, isSilent = false) {
|
|
|
198
206
|
runningTasks.delete(taskInfo.id);
|
|
199
207
|
|
|
200
208
|
// Don't exit during testing
|
|
209
|
+
const commandArgs = process.argv.slice(2);
|
|
201
210
|
const isTestEnvironment = process.env.NODE_ENV === 'test' ||
|
|
202
211
|
typeof Bun?.jest !== 'undefined' ||
|
|
203
|
-
|
|
212
|
+
commandArgs.some(arg => {
|
|
213
|
+
const lowerArg = arg.toLowerCase();
|
|
214
|
+
return lowerArg.includes('vitest') ||
|
|
215
|
+
lowerArg.includes('jest') ||
|
|
216
|
+
lowerArg === '--test' ||
|
|
217
|
+
lowerArg.startsWith('test:');
|
|
218
|
+
});
|
|
204
219
|
|
|
205
220
|
// Exit immediately if stopOnFailures mode is enabled
|
|
206
221
|
if (stopOnFailuresMode && !isTestEnvironment) {
|