bunosh 0.3.1 β†’ 0.3.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.
package/README.md CHANGED
@@ -1,27 +1,72 @@
1
1
  # 🍲 Bunosh
2
2
 
3
- > *Named after **banosh**, a traditional Ukrainian dish from cornmeal cooked with various ingredients such as mushrooms, cheese, sour cream*
4
-
5
3
  <p align="center">
6
4
  <img src="assets/logo.png" alt="Logo" width="150">
7
5
  </p>
8
6
 
7
+ <p align="center">
8
+ <strong>ONE TOOL TO SCRIPT THEM ALL</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ Transform JavaScript functions into powerful CLI commands. Write once, run anywhere.
13
+ </p>
14
+
15
+ ---
16
+
9
17
  ## What is Bunosh?
10
18
 
11
- Bunosh is a modern task runner that transforms JavaScript functions into CLI commands. Write your build, deploy, and automation tasks in JavaScript and run them directly from the command line.
19
+ Bunosh is a modern task runner that turns your JavaScript functions into CLI commands instantly. No configuration, no boilerplate - just write functions and run them from the terminal.
20
+
21
+ > *Named after **banosh**, a traditional Ukrainian dish from cornmeal cooked with various ingredients*
22
+
23
+ ### ✨ Key Features
24
+
25
+ - **πŸš€ Zero Configuration** - Write functions, get CLI commands automatically
26
+ - **🎨 pure JavaScript** - write commands as JavaScript functions
27
+ - **πŸ“¦ Built-in Tasks** - Shell execution, HTTP requests, file operations
28
+ - **πŸ€– AI-Powered** - integrate LLM calls into your daily tasks
29
+ - **πŸ”§ Cross-Platform** - Works seamlessly on macOS, Linux, and Windows. Via bun, npm, or as single executable.
30
+ - **🎯 Smart CLI** - Auto-completion, help generation, and intuitive argument handling
12
31
 
13
- **Why Bunosh?**
14
- - ✨ **Zero Configuration**: Write functions, get CLI commands
15
- - πŸš€ **Fast Execution**: Built for speed with beautiful terminal output
16
- - 🎨 **Rich Output**: Colored formatting with progress indicators
17
- - πŸ“¦ **Built-in Tasks**: Shell execution, HTTP requests, file operations
18
- - πŸ”§ **Cross-Platform**: Works on macOS, Linux, and Windows
32
+ ## Why Choose Bunosh?
33
+
34
+ ### Over Bash Scripts
35
+
36
+ - **Readable** syntax if you already know JavaScript (no cryptic bash symbol)
37
+ - **Cross-platform** without compatibility headaches
38
+ - **Rich ecosystem** - use any npm package
39
+
40
+ ### Over npm scripts
41
+
42
+ - **Real programming** - loops, conditions, async/await
43
+ - **Interactive** - outputs, prompts, confirmations, selections
44
+ - **Composable** - one file for everything! Call functions from other functions
45
+ - **Arguments & options** - full CLI parameter support
46
+
47
+ ### Over Traditional Task Runners
48
+
49
+ - **No configuration files** - just export functions
50
+ - **No DSL to learn** - it's just JavaScript
51
+ - **Native speed** - runs on Bun or Node.js
52
+ - **Modern DX** - auto-completion, beautiful output
53
+
54
+ ## Table of Contents
55
+
56
+ - [Installation](#installation)
57
+ - [Quickstart](#quickstart)
58
+ - [Commands](#commands)
59
+ - [Tasks](#tasks)
60
+ - [Input/Output](#inputoutput)
61
+ - [Task Control](#task-control)
62
+ - [AI Integration](#ai-integration)
63
+ - [Examples](#examples)
19
64
 
20
65
  ## Installation
21
66
 
22
67
  ### Option 1: Single Executable (Recommended)
23
68
 
24
- Download and install the standalone executable - no Node.js or Bun required. Includes built-in upgrade functionality:
69
+ Download the standalone executable - no Node.js or Bun required:
25
70
 
26
71
  **macOS:**
27
72
  ```bash
@@ -40,553 +85,270 @@ sudo mv bunosh-linux-x64 /usr/local/bin/bunosh
40
85
  Invoke-WebRequest -Uri "https://github.com/davertmik/bunosh/releases/latest/download/bunosh-windows-x64.exe.zip" -OutFile "bunosh.zip"
41
86
  Expand-Archive -Path "bunosh.zip" -DestinationPath .
42
87
  Move-Item "bunosh-windows-x64.exe" "bunosh.exe"
43
- # Add bunosh.exe to your PATH
44
88
  ```
45
89
 
46
- ### Option 2: Bun Package Manager
90
+ ### Option 2: Package Managers
47
91
 
48
92
  ```bash
93
+ # Using Bun
49
94
  bun add -g bunosh
50
- ```
51
95
 
52
- ### Option 3: NPM Package
53
-
54
- ```bash
96
+ # Using npm
55
97
  npm install -g bunosh
56
98
  ```
57
99
 
100
+ ## Quickstart
58
101
 
102
+ 1. **Initialize your Bunoshfile:**
59
103
  ```bash
60
- # Initialize a new Bunoshfile
61
104
  bunosh init
62
-
63
- # This creates Bunoshfile.js with sample tasks
64
105
  ```
65
106
 
66
- ### Example: Web Development Tasks
67
-
68
- Create a `Bunoshfile.js`:
69
-
107
+ 2. **Write your first command:**
70
108
  ```javascript
71
- // Import Bunosh functions from global object
72
- const { exec, fetch, writeToFile, say, ask, yell } = global.bunosh;
73
-
74
- /**
75
- * Installs project dependencies
76
- */
77
- export async function install() {
78
- await exec`npm install`;
79
- say('πŸ“¦ Dependencies installed!');
80
- }
81
-
82
- /**
83
- * Starts development server
84
- */
85
- export async function dev() {
86
- say('πŸš€ Starting development server...');
87
- await exec`npm run dev`;
88
- }
89
-
90
- /**
91
- * Builds project for production
92
- */
93
- export async function build(target = 'production') {
94
- say(`πŸ”¨ Building for ${target}...`);
95
- await exec`npm run build`;
96
-
97
- if (target === 'production') {
98
- await exec`npm run optimize`;
99
- yell('BUILD COMPLETE!');
100
- }
101
- }
102
-
103
- /**
104
- * Deploys to specified environment
105
- */
106
- export async function deploy(env = 'staging', options = { skipTests: false }) {
107
- if (!options.skipTests) {
108
- say('πŸ§ͺ Running tests...');
109
- await exec`npm test`;
110
- }
111
-
112
- say(`πŸš€ Deploying to ${env}...`);
113
- await build('production');
114
- await exec`docker build -t myapp:${env} .`;
115
- await exec`docker push myapp:${env}`;
116
-
117
- yell(`DEPLOYED TO ${env.toUpperCase()}!`);
118
- }
109
+ // Bunoshfile.js
110
+ const { exec, say } = global.bunosh;
119
111
 
120
112
  /**
121
- * Cleans up temporary files
113
+ * Builds the project for production
122
114
  */
123
- export async function clean() {
124
- await exec`rm -rf dist node_modules/.cache tmp`;
125
- say('✨ All clean!');
126
- }
127
-
128
- /**
129
- * Setup new project environment
130
- */
131
- export async function setup() {
132
- const projectName = await ask('What is your project name?');
133
- const useTypescript = await ask('Use TypeScript? (y/n)') === 'y';
134
-
135
- say('πŸ—οΈ Setting up project...');
136
-
137
- // Create package.json
138
- writeToFile('package.json', (line) => {
139
- line`{`;
140
- line` "name": "${projectName}",`;
141
- line` "version": "1.0.0",`;
142
- line` "type": "module"`;
143
- if (useTypescript) {
144
- line`, "devDependencies": {`;
145
- line` "typescript": "^5.0.0"`;
146
- line` }`;
147
- }
148
- line`}`;
149
- });
150
-
151
- if (useTypescript) {
152
- await exec`npm install typescript --save-dev`;
153
- }
154
-
155
- yell('PROJECT READY!');
115
+ export async function build(env = 'production') {
116
+ say(`πŸ”¨ Building for ${env}...`);
117
+ await exec`npm run build`.env({ NODE_ENV: env });
118
+ say('βœ… Build complete!');
156
119
  }
157
120
  ```
158
121
 
159
- ### Run Your Tasks
122
+ That's it! Your function is now a CLI command.
160
123
 
124
+ 3. **Run it:**
161
125
  ```bash
162
- # List all available commands
163
- bunosh
164
-
165
- # Run individual tasks
166
- bunosh install
167
- bunosh dev
126
+ # build for production
168
127
  bunosh build
169
- bunosh build staging
170
- bunosh deploy production --skip-tests
171
- bunosh clean
172
- bunosh setup
173
- ```
174
128
 
175
- **Bunosh will display your tasks like this:**
129
+ # build for staging
130
+ bunosh build staging
176
131
 
132
+ # build for development
133
+ bunosh build development
177
134
  ```
178
- 🍲 Your exceptional task runner
179
-
180
- Usage: bunosh <command> <args> [options]
181
135
 
182
- Commands are loaded from exported functions in Bunoshfile.js
136
+ ## Commands
183
137
 
184
- Commands:
185
- build Builds project for production
186
- bunosh build [target]
187
- clean Cleans up temporary files
188
- deploy Deploys to specified environment
189
- bunosh deploy [env] --skip-tests
190
- dev Starts development server
191
- install Installs project dependencies
192
- setup Setup new project environment
193
- ```
138
+ ### Creating Commands
194
139
 
195
- ## Example: DevOps Tasks
140
+ Every exported function in `Bunoshfile.js` becomes a CLI command:
196
141
 
197
142
  ```javascript
198
- const { exec, fetch, writeToFile, say, task } = global.bunosh;
199
-
200
- /**
201
- * Checks service health across environments
202
- */
203
- export async function healthCheck(env = 'production') {
204
- const services = ['api', 'web', 'database'];
205
-
206
- for (const service of services) {
207
- const url = `https://${service}.${env}.example.com/health`;
208
- await task(`Checking ${service}`, async () => {
209
- const response = await fetch(url);
210
- if (!response.ok) throw new Error(`${service} is down!`);
211
- });
212
- }
213
-
214
- say('βœ… All services healthy!');
215
- }
216
-
217
- /**
218
- * Backup database with compression
219
- */
220
- export async function backup(database = 'main') {
221
- const timestamp = new Date().toISOString().split('T')[0];
222
- const filename = `backup-${database}-${timestamp}.sql.gz`;
223
-
224
- await exec`pg_dump ${database} | gzip > ${filename}`;
225
- await exec`aws s3 cp ${filename} s3://backups/${filename}`;
226
- await exec`rm ${filename}`;
227
-
228
- say(`πŸ“¦ Backup saved: ${filename}`);
143
+ // Simple command
144
+ export function hello() {
145
+ console.log('Hello, World!');
229
146
  }
230
147
 
231
- /**
232
- * Updates SSL certificates
233
- */
234
- export async function updateCerts() {
235
- await exec`certbot renew`;
236
- await exec`nginx -s reload`;
237
- say('πŸ”’ Certificates updated!');
148
+ // Command with parameters
149
+ export function greet(name = 'friend') {
150
+ console.log(`Hello, ${name}!`);
238
151
  }
239
152
 
240
- /**
241
- * Deploys application with health checks
242
- */
243
- export async function deployWithChecks(env = 'staging') {
244
- await exec`kubectl apply -f k8s/${env}/`;
245
- await exec`kubectl rollout status deployment/myapp`;
246
- await healthCheck(env);
247
- say(`πŸš€ Successfully deployed to ${env}!`);
248
- }
249
-
250
- /**
251
- * Scales application instances
252
- */
253
- export async function scale(replicas = 3, service = 'myapp') {
254
- await exec`kubectl scale deployment/${service} --replicas=${replicas}`;
255
- say(`βš–οΈ Scaled ${service} to ${replicas} replicas`);
153
+ // Command with options
154
+ export function deploy(env = 'staging', options = { force: false, verbose: false }) {
155
+ if (options.verbose) console.log('Verbose mode enabled');
156
+ console.log(`Deploying to ${env}${options.force ? ' (forced)' : ''}`);
256
157
  }
257
158
  ```
258
159
 
259
- **Bunosh displays these as:**
260
-
160
+ **CLI Usage:**
161
+ ```bash
162
+ bunosh hello
163
+ bunosh greet John
164
+ bunosh deploy production --force --verbose
261
165
  ```
262
- Usage: bunosh <command> <args> [options]
263
166
 
264
- Commands are loaded from exported functions in Bunoshfile.js
167
+ ### Arguments and Options
265
168
 
266
- Commands:
267
- backup Backup database with compression
268
- bunosh backup [database]
269
- deploy:with-checks Deploys application with health checks
270
- bunosh deploy:with-checks [env]
271
- health:check Checks service health across environments
272
- bunosh health:check [env]
273
- scale Scales application instances
274
- bunosh scale [replicas] [service]
275
- update:certs Updates SSL certificates
276
-
277
- ```
278
-
279
- ## Example: Content Management
169
+ Bunosh automatically maps function parameters to CLI arguments:
280
170
 
281
171
  ```javascript
282
- const { exec, writeToFile, ask, say } = global.bunosh;
283
-
284
- /**
285
- * Creates new blog post template
286
- */
287
- export async function newPost() {
288
- const title = await ask('Post title:');
289
- const slug = title.toLowerCase().replace(/\s+/g, '-');
290
- const date = new Date().toISOString().split('T')[0];
291
-
292
- writeToFile(`posts/${date}-${slug}.md`, (line) => {
293
- line`---`;
294
- line`title: "${title}"`;
295
- line`date: ${date}`;
296
- line`draft: true`;
297
- line`---`;
298
- line``;
299
- line`# ${title}`;
300
- line``;
301
- line`Your content here...`;
302
- });
303
-
304
- say(`πŸ“ Created: posts/${date}-${slug}.md`);
305
- }
306
-
307
172
  /**
308
- * Optimizes and compresses images
173
+ * Create a new feature branch
174
+ * @param {string} name - Feature name (required)
175
+ * @param {string} base - Base branch (optional, defaults to 'main')
176
+ * @param {object} options - CLI options
177
+ * @param {boolean} options.push - Push to remote after creation
309
178
  */
310
- export async function optimizeImages() {
311
- await exec`find ./images -name "*.jpg" -exec jpegoptim --max=80 {} \\;`;
312
- await exec`find ./images -name "*.png" -exec optipng -o2 {} \\;`;
313
- say('πŸ–ΌοΈ Images optimized!');
314
- }
315
-
316
- /**
317
- * Creates new page template
318
- */
319
- export async function newPage(name) {
320
- const slug = name.toLowerCase().replace(/\s+/g, '-');
321
-
322
- writeToFile(`content/pages/${slug}.md`, (line) => {
323
- line`---`;
324
- line`title: "${name}"`;
325
- line`type: "page"`;
326
- line`---`;
327
- line``;
328
- line`# ${name}`;
329
- line``;
330
- line`Page content here...`;
331
- });
332
-
333
- say(`πŸ“„ Created: content/pages/${slug}.md`);
334
- }
335
-
336
- /**
337
- * Generates site and deploys
338
- */
339
- export async function publish() {
340
- await exec`hugo --minify`;
341
- await exec`rsync -avz public/ user@server:/var/www/site/`;
342
- say('🌐 Site published!');
343
- }
179
+ export async function feature(name, base = 'main', options = { push: false }) {
180
+ await exec`git checkout -b feature/${name} ${base}`;
344
181
 
345
- /**
346
- * Builds and serves development site
347
- */
348
- export async function serve(port = 1313) {
349
- await exec`hugo server --port ${port} --buildDrafts`;
182
+ if (options.push) {
183
+ await exec`git push -u origin feature/${name}`;
184
+ }
350
185
  }
351
186
  ```
352
187
 
353
- **Bunosh displays these as:**
354
-
188
+ **Generated CLI:**
189
+ ```bash
190
+ bunosh feature my-feature # Creates from main
191
+ bunosh feature my-feature develop # Creates from develop
192
+ bunosh feature my-feature --push # Creates and pushes
355
193
  ```
356
- Usage: bunosh <command> <args> [options]
357
194
 
358
- Commands are loaded from exported functions in Bunoshfile.js
195
+ ### Command Naming
359
196
 
360
- Commands:
361
- new:page Creates new page template
362
- bunosh new:page <name>
363
- new:post Creates new blog post template
364
- optimize:images Optimizes and compresses images
365
- publish Generates site and deploys
366
- serve Builds and serves development site
367
- bunosh serve [port]
197
+ Functions are automatically converted to kebab-case commands:
368
198
 
369
- ```
199
+ | Function Name | CLI Command |
200
+ |--------------|-------------|
201
+ | `build` | `bunosh build` |
202
+ | `gitPush` | `bunosh git:push` |
203
+ | `npmInstall` | `bunosh npm:install` |
204
+ | `buildAndDeploy` | `bunosh build:and-deploy` |
370
205
 
371
- ## Built-in Functions
206
+ ## Tasks
372
207
 
373
- All Bunosh functions are available via `global.bunosh`:
208
+ All Bunosh utilities are available via `global.bunosh`:
374
209
 
375
210
  ```javascript
376
- const { exec, shell, fetch, writeToFile, copyFile, say, ask, yell, task } = global.bunosh;
211
+ const { exec, shell, fetch, writeToFile, copyFile, task, ai, say, ask, yell } = global.bunosh;
377
212
  ```
378
213
 
379
- ### Shell Execution
214
+ > We use global variables instead of imports to ensure you can use it with bunosh single-executable on any platform.
380
215
 
381
- Bunosh provides two ways to execute shell commands:
382
216
 
383
- #### `exec` - Universal Shell Execution
217
+ #### `exec`
384
218
 
385
- Best for complex commands, cross-platform compatibility, and when you need real-time streaming output.
219
+ Run single command using [child process `spawn`](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)
386
220
 
387
221
  ```javascript
388
- // Complex shell commands with pipes and redirections
389
- await exec`find . -name "*.js" | grep -v node_modules | wc -l`;
390
- await exec`npm install --verbose`; // Shows progress in real-time
222
+ // Complex commands with pipes and streaming output
223
+ await exec`npm install --verbose`;
391
224
  await exec`docker build . | tee build.log`;
392
- ```
393
-
394
- #### `shell` - Native Bun Shell (with Node.js fallback)
225
+ await exec`find . -name "*.js" | grep -v node_modules | wc -l`;
395
226
 
396
- Best for simple commands when running under Bun for maximum performance.
227
+ // With environment variables
228
+ await exec`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
397
229
 
398
- ```javascript
399
- // Simple, fast commands
400
- await shell`pwd`;
401
- await shell`echo "Hello World"`;
402
- await shell`ls -la`;
403
- await shell`cat package.json`;
230
+ // In specific directory
231
+ await exec`npm install`.cwd('/tmp/project');
404
232
  ```
405
233
 
406
- #### When to Use Which?
407
-
408
- **Use `shell` when:**
409
- - βœ… Running under Bun for optimal performance
410
- - βœ… Executing simple commands (`pwd`, `ls`, `echo`, `cat`)
411
- - βœ… Want fastest possible execution
412
- - βœ… Working with basic file operations
413
-
414
- **Use `exec` when:**
415
- - βœ… Need cross-platform compatibility (Node.js + Bun)
416
- - βœ… Using complex shell features (pipes, redirections, command chaining)
417
- - βœ… Want real-time streaming output for long-running commands
418
- - βœ… Running package managers (`npm install`, `docker build`)
419
-
420
- Both support the same API and return the same `TaskResult` object:
234
+ By default task prints live line-by-line output from stdout and stderr. To disable output, use `silent` method:
421
235
 
422
236
  ```javascript
423
- // Both tasks support environment variables
424
- await shell`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
425
- await exec`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
426
237
 
427
- // Both support working directory changes
428
- await shell`pwd`.cwd('/tmp');
429
- await exec`ls -la`.cwd('/tmp');
238
+ // disable printing output
239
+ await task.silent(() => exec`npm install`);
430
240
 
431
- // Choose based on complexity and performance needs
432
- await shell`cat package.json`; // Simple, fast
433
- await exec`npm install --verbose`; // Complex, streaming
241
+ // disable output for all commands
242
+ await task.silence();
434
243
  ```
435
244
 
436
- #### TaskResult Object
245
+ See more [#silent](#silent)
437
246
 
438
- Both `exec` and `shell` return a `TaskResult` object with the following properties and methods:
247
+ #### `shell` - Fast Native Execution
439
248
 
440
- ```javascript
441
- const result = await exec`ls -la`;
442
- // or
443
- const result = await shell`ls -la`;
249
+ Optimized for simple, fast commands when running under Bun:
444
250
 
445
- // Properties
446
- result.status // 'success' or 'fail'
447
- result.output // Combined stdout/stderr as string
448
-
449
- // Getters (boolean)
450
- result.hasFailed // true if command failed (non-zero exit code)
451
- result.hasSucceeded // true if command succeeded (exit code 0)
251
+ ```javascript
252
+ // Simple, fast commands
253
+ await shell`pwd`;
254
+ await shell`ls -la`;
255
+ await shell`cat package.json`;
452
256
  ```
453
257
 
454
- #### Error Handling Examples
258
+ For more details see [bun shell](https://bun.sh/docs/runtime/shell) reference
455
259
 
456
- ```javascript
457
- // Check command success
458
- const result = await exec`npm test`;
459
- if (result.hasSucceeded) {
460
- say('βœ… Tests passed!');
461
- } else {
462
- yell('❌ Tests failed!');
463
- console.log(result.output); // Show error details
464
- }
260
+ `shell` vs `exec`
465
261
 
466
- // Get command output
467
- const result = await exec`git rev-parse HEAD`;
468
- if (result.hasSucceeded) {
469
- const commitHash = result.output.trim();
470
- say(`Current commit: ${commitHash}`);
471
- }
262
+ | Command | Best For | Use Cases | Implementation | Compatibility |
263
+ |---------|----------|-----------|----------------|---------------|
264
+ | `exec` | Single command execution | single command | spawn process | NodeJS + Bun but platform dependent |
265
+ | `shell` | Multiple cross-platform shell commands | exec + `pwd`, `ls`, `echo`, `cat`, basic file ops | bun shell | Bun only but Cross-platform |
472
266
 
473
- // Handle failures gracefully
474
- const result = await exec`optional-command-that-might-fail`;
475
- if (result.hasFailed) {
476
- say('Command failed, but continuing...');
477
- console.log('Error output:', result.output);
478
- }
267
+ shell prints output from stdout and stderr. To disable output, [make tasks silent](#silent):
479
268
 
480
- // Old vs New style comparison
481
- // ❌ Old: Commands throw on failure
482
- try {
483
- await someOtherTaskRunner('failing-command');
484
- } catch (error) {
485
- // Handle error
486
- }
269
+ ### HTTP Requests
487
270
 
488
- // βœ… New: Explicit success/failure handling
489
- const result = await exec`failing-command`;
490
- if (result.hasFailed) {
491
- // Handle failure explicitly
492
- }
493
- ```
271
+ Built-in fetch with progress indicators:
494
272
 
495
- ### HTTP Requests (`fetch`)
496
273
  ```javascript
497
- // GET request with progress indicator
498
- const response = await fetch('https://api.github.com/repos/user/repo');
499
- const data = await response.json();
274
+ /**
275
+ * Check service health
276
+ */
277
+ export async function healthCheck(url) {
278
+ const response = await fetch(url);
279
+
280
+ if (response.ok) {
281
+ const data = await response.json();
282
+ say(`βœ… Service healthy: ${data.status}`);
283
+ } else {
284
+ yell(`❌ Service down: ${response.status}`);
285
+ }
286
+ }
500
287
  ```
501
288
 
502
289
  ### File Operations
290
+
291
+ Template-based file writing and copying:
292
+
503
293
  ```javascript
504
- // Write file with template builder
505
- writeToFile('config.json', (line) => {
506
- line`{`;
507
- line` "name": "myapp",`;
508
- line` "version": "1.0.0"`;
509
- line`}`;
510
- });
294
+ /**
295
+ * Generate configuration file
296
+ */
297
+ export function generateConfig(name, port = 3000) {
298
+ writeToFile('config.json', (line) => {
299
+ line`{`;
300
+ line` "name": "${name}",`;
301
+ line` "port": ${port},`;
302
+ line` "environment": "development"`;
303
+ line`}`;
304
+ });
305
+
306
+ say('πŸ“ Config file created');
307
+ }
511
308
 
512
309
  // Copy files
513
- copyFile('template.js', 'output.js');
310
+ copyFile('template.env', '.env');
514
311
  ```
515
312
 
516
- ### User Interaction
313
+ ## Input/Output
517
314
 
518
- #### `ask()` - Interactive User Input
315
+ ### `say` - Normal Output
519
316
 
520
- The `ask()` function provides flexible ways to get user input with smart parameter detection and multiple modes:
317
+ Standard output with visual indicator:
521
318
 
522
319
  ```javascript
523
- // === SIMPLE SYNTAX WITH SMART DETECTION ===
524
-
525
- // Basic text input
526
- const name = await ask('What is your name?');
527
-
528
- // Text input with default value
529
- const projectName = await ask('Project name:', 'my-awesome-app');
530
-
531
- // Boolean confirmation (auto-detects confirm type)
532
- const shouldContinue = await ask('Continue with deployment?', true);
533
- const forceUpdate = await ask('Force update?', false);
534
-
535
- // Number input with default
536
- const port = await ask('Enter port number:', 3000);
537
-
538
- // Single choice selection (auto-detects from array)
539
- const framework = await ask('Choose your framework:', [
540
- 'React', 'Vue', 'Angular', 'Svelte'
541
- ]);
320
+ say('Building project...');
321
+ say('πŸ“¦ Dependencies installed');
322
+ say(`Found ${count} files to process`);
323
+ ```
542
324
 
543
- // Multiple choice selection (array + options)
544
- const features = await ask('Select features to include:', [
545
- 'TypeScript', 'ESLint', 'Prettier', 'Tests', 'CI/CD'
546
- ], { multiple: true });
325
+ ### `ask` - User Input
547
326
 
548
- // === ADVANCED OPTIONS SYNTAX ===
327
+ Flexible user input with smart parameter detection:
549
328
 
550
- // Multiline text input (opens system editor)
551
- const description = await ask('Enter project description:', {
552
- multiline: true // Same as editor: true
553
- });
329
+ ```javascript
330
+ // Text input with default
331
+ const name = await ask('Project name:', 'my-app');
554
332
 
555
- // Editor input with default content
556
- const config = await ask('Edit configuration:', {
557
- editor: true,
558
- default: 'Initial content here...'
559
- });
333
+ // Boolean confirmation (auto-detects)
334
+ const proceed = await ask('Continue?', true);
560
335
 
561
- // Password input (hidden)
562
- const password = await ask('Enter password:', {
563
- type: 'password'
564
- });
336
+ // Single selection (auto-detects from array)
337
+ const env = await ask('Select environment:', ['dev', 'staging', 'prod']);
565
338
 
566
- // Mixed: default value + additional options
567
- const email = await ask('Email address:', 'user@example.com', {
568
- validate: (input) => input.includes('@') || 'Please enter valid email'
569
- });
570
- ```
339
+ // Multiple selection
340
+ const features = await ask('Select features:',
341
+ ['TypeScript', 'ESLint', 'Tests'],
342
+ { multiple: true }
343
+ );
571
344
 
572
- #### Ask Function Signatures
345
+ // Password input
346
+ const password = await ask('Enter password:', { type: 'password' });
573
347
 
574
- ```javascript
575
- // Smart detection syntax
576
- ask(question, defaultValue, options?)
577
- ask(question, choices[], options?)
578
- ask(question, options)
579
-
580
- // Examples:
581
- ask('Name?', 'John') // String default
582
- ask('Continue?', true) // Boolean -> confirm type
583
- ask('Port?', 3000) // Number default
584
- ask('Color?', ['red', 'blue']) // Array -> choices
585
- ask('Colors?', ['red', 'blue'], { multiple: true }) // Array + options
348
+ // Multiline editor input
349
+ const description = await ask('Enter description:', { editor: true });
586
350
  ```
587
351
 
588
- #### Ask Options Reference
589
-
590
352
  | Parameter/Option | Type | Description | Example |
591
353
  |------------------|------|-------------|---------|
592
354
  | **Smart Detection** | | |
@@ -601,493 +363,508 @@ ask('Colors?', ['red', 'blue'], { multiple: true }) // Array + options
601
363
  | `type` | String | Input type: `'input'`, `'confirm'`, `'password'`, `'number'` | `'password'` |
602
364
  | `validate` | Function | Custom validation function | `(input) => input.length > 0` |
603
365
 
604
- #### Advanced Ask Examples
366
+
367
+ ### `yell`
368
+
369
+ Emphasized Output
370
+
371
+ ASCII art output for important messages:
605
372
 
606
373
  ```javascript
607
- /**
608
- * Interactive project setup with smart syntax
609
- */
610
- export async function setupProject() {
611
- // Simple syntax with smart detection
612
- const projectName = await ask('Project name:', 'my-awesome-project');
613
-
614
- const projectType = await ask('Project type:', [
615
- 'Web App', 'API', 'CLI Tool', 'Library'
616
- ]);
617
-
618
- const dependencies = await ask('Select dependencies:', [
619
- 'express', 'lodash', 'axios', 'moment', 'uuid'
620
- ], { multiple: true });
621
-
622
- const useTypescript = await ask('Use TypeScript?', false);
623
-
624
- // Editor input for complex configuration
625
- const packageJson = await ask('Customize package.json:', {
626
- editor: true,
627
- default: JSON.stringify({
628
- name: projectName,
629
- version: '1.0.0',
630
- description: '',
631
- dependencies: {}
632
- }, null, 2)
633
- });
634
-
635
- say(`Creating ${projectType}: ${projectName}`);
636
- say(`Dependencies: ${dependencies.join(', ')}`);
637
- say(`TypeScript: ${useTypescript ? 'Yes' : 'No'}`);
638
-
639
- writeToFile('package.json', packageJson);
640
- }
374
+ yell('BUILD COMPLETE!');
375
+ yell('DEPLOYMENT SUCCESSFUL!');
376
+ ```
641
377
 
642
- /**
643
- * Git commit with editor input
644
- */
645
- export async function interactiveCommit() {
646
- const message = await ask('Enter commit message:', {
647
- editor: true,
648
- default: 'feat: \n\n# Write your commit message above\n# First line: brief summary (50 chars max)\n# Blank line, then detailed explanation'
649
- });
650
-
651
- await exec`git commit -m "${message}"`;
652
- say('βœ… Committed successfully!');
653
- }
378
+ ### `silent`
654
379
 
655
- /**
656
- * Database migration with smart syntax
657
- */
658
- export async function migrate() {
659
- // Smart array detection for choices
660
- const action = await ask('Migration action:', [
661
- 'Run pending migrations',
662
- 'Rollback last migration',
663
- 'Reset database',
664
- 'Create new migration'
665
- ]);
666
-
667
- if (action === 'Reset database') {
668
- // Smart boolean detection for confirmation
669
- const confirmed = await ask('⚠️ This will DELETE ALL DATA. Are you sure?', false);
670
-
671
- if (!confirmed) {
672
- say('Migration cancelled');
673
- return;
674
- }
675
- }
676
-
677
- // Execute migration based on selection...
678
- }
380
+ Stop printing realtime output
679
381
 
680
- /**
681
- * Server configuration with mixed smart syntax
682
- */
683
- export async function configureServer() {
684
- // Simple defaults
685
- const serverName = await ask('Server name:', 'my-server');
686
- const port = await ask('Port number:', 8080);
687
- const enableHTTPS = await ask('Enable HTTPS?', true);
688
-
689
- // Array with additional options
690
- const databases = await ask('Select databases to connect:', [
691
- 'PostgreSQL', 'MongoDB', 'Redis', 'MySQL'
692
- ], { multiple: true });
693
-
694
- // Mix of default + validation
695
- const adminEmail = await ask('Admin email:', 'admin@example.com', {
696
- validate: (email) => email.includes('@') || 'Please enter a valid email'
697
- });
698
-
699
- say(`Configuring ${serverName} on port ${port}`);
700
- say(`HTTPS: ${enableHTTPS ? 'Enabled' : 'Disabled'}`);
701
- say(`Databases: ${databases.join(', ')}`);
702
- say(`Admin: ${adminEmail}`);
703
- }
382
+ ```javascript
383
+ // Silence all task output
384
+ task.silence();
385
+ await shell`npm build`;
386
+
387
+ // restore printing output
388
+ task.prints();
389
+
390
+ // Silent specific task
391
+ const labels = await task.silent(() => shell(`gh api repos/:org/:repo/labels`));
704
392
  ```
705
393
 
706
- #### Output Functions
394
+ ## Task Control
395
+
396
+ ### Parallel Executions
397
+
398
+ No magic here. Use `Promise.all()` to run tasks in parallel:
707
399
 
708
400
  ```javascript
709
- // Output messages
710
- say('Building project...'); // Normal output with !
711
- yell('BUILD COMPLETE!'); // Emphasized ASCII art output
401
+ // Parallel tasks
402
+ const results = await Promise.all([
403
+ exec`npm run build:frontend`,
404
+ exec`npm run build:backend`,
405
+ exec`npm run build:docs`
406
+ ]);
407
+ ```
408
+
409
+ ### Custom Tasks
410
+
411
+ Name and group your tasks operations:
712
412
 
713
- // Wrap long operations with progress
714
- await task('Installing dependencies', async () => {
715
- await exec`npm install`;
413
+ ```js
414
+ await task('Build', () => {
415
+ await exec`npm run build:frontend`);
416
+ await exec`npm run build:docs`);
716
417
  });
717
- ```
418
+ ````
718
419
 
719
- ## πŸ€– AI-Powered Tasks
420
+ ### Stop on Failure
720
421
 
721
- Bunosh now supports AI integration with structured outputs! Connect to popular AI providers and generate content, analyze data, or automate text processing with simple function calls.
422
+ By default bunosh executes all tasks event if they fail. To stop execution immediately on failure, use the `task.stopOnFailures()` method.
722
423
 
723
- ### Quick Setup
724
424
 
725
- Set your AI provider credentials:
726
- ```bash
727
- # Required: Choose your model
728
- export AI_MODEL=gpt-4o # or claude-3-5-sonnet-20241022, llama-3.3-70b-versatile, etc.
425
+ ```javascript
426
+ /**
427
+ * Strict deployment - stop on any failure
428
+ */
429
+ export async function deployStrict() {
430
+ task.stopOnFailures(); // Exit immediately on any task failure
729
431
 
730
- # Required: Set API key for your chosen provider
731
- export OPENAI_API_KEY=your_key_here # for OpenAI models
732
- # export ANTHROPIC_API_KEY=your_key_here # for Claude models
733
- # export GROQ_API_KEY=your_key_here # for Groq models
734
- ```
432
+ await exec`npm test`;
433
+ await exec`npm run build`;
434
+ await exec`deploy-script`;
435
+ // If any task fails, script exits immediately
436
+ }
735
437
 
736
- ### Built-in AI Providers
438
+ /**
439
+ * Cleanup - continue despite failures
440
+ */
441
+ export async function cleanup() {
442
+ task.ignoreFailures(); // Continue even if tasks fail
737
443
 
738
- - **OpenAI** - GPT-4o, GPT-4o-mini, GPT-3.5-turbo (via `OPENAI_API_KEY`)
739
- - **Anthropic** - Claude 3.5 Sonnet, Claude 3 Haiku (via `ANTHROPIC_API_KEY`)
740
- - **Groq** - Llama 3.3, Mixtral, Gemma models (via `GROQ_API_KEY` or `GROQ_KEY`)
444
+ await task('Remove temp files', () => shell`rm -rf tmp/*`);
445
+ await task('Clear logs', () => shell`rm -f logs/*.log`);
446
+ await task('Reset cache', () => shell`rm -rf .cache`);
447
+ // All tasks run regardless of failures
448
+ }
449
+ ```
741
450
 
742
- ### Custom AI Providers
451
+ ### Try Operations
743
452
 
744
- For enterprise and custom setups, you can import and register any AI provider manually:
453
+ Gracefully handle operations that might fail:
745
454
 
746
455
  ```javascript
747
- const { ai } = global.bunosh;
748
-
749
- // Method 1: Direct model configuration (most flexible)
750
- import { bedrock } from '@ai-sdk/amazon-bedrock';
751
- const bedrockModel = bedrock('anthropic.claude-3-sonnet-20240229-v1:0', {
752
- region: 'us-east-1',
753
- credentials: {
754
- accessKeyId: 'your-access-key',
755
- secretAccessKey: 'your-secret-key'
456
+ /**
457
+ * Check service availability
458
+ */
459
+ export async function checkServices() {
460
+ const dbConnected = await task.try(shell`nc -z localhost 5432`);
461
+
462
+ if (dbConnected) {
463
+ say('βœ… Database connected');
464
+ } else {
465
+ say('⚠️ Database unavailable, using fallback');
466
+ await useFallbackDatabase();
756
467
  }
757
- });
758
468
 
759
- ai.configure({ model: bedrockModel });
469
+ const apiHealthy = await task.try(() => fetch('http://localhost:3000/health');
760
470
 
761
- // Method 2: Register custom provider with environment variable
762
- import { xai } from '@ai-sdk/xai';
763
- ai.configure({
764
- registerProvider: {
765
- envVar: 'XAI_API_KEY',
766
- provider: {
767
- createInstance: (modelName) => xai(modelName)
768
- }
471
+ if (!apiHealthy) {
472
+ yell('API IS DOWN!');
769
473
  }
770
- });
474
+ }
475
+ ```
771
476
 
772
- // Method 3: Register any custom provider (Azure OpenAI, OpenRouter, etc.)
773
- import { openrouter } from '@openrouter/ai-sdk-provider';
774
- ai.configure({
775
- registerProvider: {
776
- envVar: 'OPENROUTER_API_KEY',
777
- provider: {
778
- createInstance: (modelName) => openrouter(modelName)
779
- }
780
- }
781
- });
477
+ ## πŸ’« AI Integration
782
478
 
783
- // Method 4: Register completely custom provider
784
- ai.configure({
785
- registerProvider: {
786
- envVar: 'CUSTOM_AI_API_KEY',
787
- provider: {
788
- createInstance: (modelName) => {
789
- // Your custom provider logic
790
- return customAIProvider(modelName, {
791
- apiKey: process.env.CUSTOM_AI_API_KEY,
792
- endpoint: 'https://custom-ai.company.com/v1'
793
- });
794
- }
795
- }
796
- }
797
- });
479
+ Built-in AI support for code generation, documentation, and automation.
480
+ Automatically responds to structured JSON output.
481
+
482
+ AI provider automatically detected, but you need to provide API key and model name.
483
+ Use `.env` file with `AI_MODEL` and `OPENAI_API_KEY` variables.
484
+ In case you use provider other than OpenAI, Anthropic, Groq, you may need to configure it manually in top of Bunoshfile
798
485
 
799
- // Reset to environment variable configuration
800
- ai.reset();
486
+ ```bash
487
+ # Choose your AI model
488
+ export AI_MODEL=gpt-5 # or claude-4-sonnet, llama-3.3-70b, etc.
801
489
 
802
- // Check current configuration
803
- const config = ai.getConfig();
804
- console.log('Current AI config:', config);
490
+ # Set API key for your provider
491
+ export OPENAI_API_KEY=your_key_here # For OpenAI
492
+ # export ANTHROPIC_API_KEY=your_key_here # For Claude
493
+ # export GROQ_API_KEY=your_key_here # For Groq
805
494
  ```
806
495
 
807
- ### AI Task Examples
496
+
497
+ Use the `ai` function to interact with the AI.
498
+
499
+ ```js
500
+ const resp = await ai(message, { field1: 'what should be there', field2: 'what should be there' })
501
+ ```
502
+
503
+ ### Usage
808
504
 
809
505
  ```javascript
810
- const { ai, writeToFile, say } = global.bunosh;
506
+ const { ai, writeToFile } = global.bunosh;
811
507
 
812
508
  /**
813
- * Generate project documentation with AI
509
+ * Generate commit message from staged changes
814
510
  */
815
- export async function generateDocs() {
816
- const codebase = fs.readFileSync('src/index.js', 'utf8');
817
-
818
- const result = await ai(
819
- `Generate documentation for this code: ${codebase}`,
820
- {
821
- overview: 'Brief project overview',
822
- apiReference: 'API documentation',
823
- examples: 'Usage examples',
824
- installation: 'Installation instructions'
825
- }
826
- );
827
-
828
- writeToFile('README.md', (line) => {
829
- line`# ${result.overview}`;
830
- line``;
831
- line`## Installation`;
832
- line`${result.installation}`;
833
- line``;
834
- line`## API Reference`;
835
- line`${result.apiReference}`;
836
- line``;
837
- line`## Examples`;
838
- line`${result.examples}`;
839
- });
840
-
841
- say('πŸ“š Documentation generated!');
842
- }
511
+ export async function commit() {
512
+ const diff = await exec`git diff --staged`;
843
513
 
844
- /**
845
- * Analyze and optimize code with AI suggestions
846
- */
847
- export async function codeReview(filename) {
848
- const code = fs.readFileSync(filename, 'utf8');
849
-
850
- const analysis = await ai(
851
- `Review this code for improvements: ${code}`,
514
+ if (!diff.output.trim()) {
515
+ say('No staged changes');
516
+ return;
517
+ }
518
+
519
+ const commit = await ai(
520
+ `Generate a conventional commit message for: ${diff.output}`,
852
521
  {
853
- issues: 'List of potential issues',
854
- suggestions: 'Specific improvement suggestions',
855
- security: 'Security considerations',
856
- performance: 'Performance optimization tips',
857
- rating: 'Overall code quality rating (1-10)'
522
+ type: 'Commit type (feat/fix/docs/chore)',
523
+ scope: 'Commit scope (optional)',
524
+ subject: 'Brief subject line (50 chars max)',
525
+ body: 'Detailed explanation'
858
526
  }
859
527
  );
860
-
861
- say(`πŸ” Code Review for ${filename}:`);
862
- console.log(`Rating: ${analysis.rating}/10`);
863
- console.log(`Issues: ${analysis.issues}`);
864
- console.log(`Suggestions: ${analysis.suggestions}`);
865
- console.log(`Security: ${analysis.security}`);
866
- console.log(`Performance: ${analysis.performance}`);
528
+
529
+ const message = commit.scope
530
+ ? `${commit.type}(${commit.scope}): ${commit.subject}\n\n${commit.body}`
531
+ : `${commit.type}: ${commit.subject}\n\n${commit.body}`;
532
+
533
+ await exec`git commit -m "${message}"`;
534
+ say('βœ… AI-generated commit created');
867
535
  }
536
+ ```
537
+
538
+ See more ai usage examples below:
868
539
 
540
+ ## Examples
541
+
542
+ ### Development Examples
543
+
544
+ #### Feature Branch Workflow
545
+
546
+ ```
547
+ bunosh worktree:create
548
+ bunosh worktree:delete
549
+ ```
550
+
551
+ ```javascript
869
552
  /**
870
- * Generate test cases from code
553
+ * Create worktree for feature development
871
554
  */
872
- export async function generateTests(sourceFile) {
873
- const code = fs.readFileSync(sourceFile, 'utf8');
874
-
875
- const tests = await ai(
876
- `Generate comprehensive unit tests for this code: ${code}`,
877
- {
878
- testSuite: 'Complete test suite code',
879
- edgeCases: 'List of edge cases covered',
880
- mockSetup: 'Required mocks and setup code'
881
- }
882
- );
883
-
884
- const testFile = sourceFile.replace('.js', '.test.js');
885
- writeToFile(testFile, (line) => {
886
- line`${tests.mockSetup}`;
887
- line``;
888
- line`${tests.testSuite}`;
889
- });
890
-
891
- say(`πŸ§ͺ Tests generated: ${testFile}`);
892
- say(`Edge cases: ${tests.edgeCases}`);
555
+ export async function worktreeCreate(name = '') {
556
+ const worktreeName = name || await ask('What is feature name?');
557
+ const newDir = `../app-${worktreeName}`;
558
+
559
+ await exec`git worktree add ${newDir}`;
560
+ say(`Created worktree for feature ${worktreeName} in ${newDir}`);
893
561
  }
894
562
 
895
563
  /**
896
- * Create commit messages from git diff
564
+ * Remove worktree when feature is merged
897
565
  */
898
- export async function smartCommit() {
899
- const diff = await exec`git diff --staged`;
900
-
901
- if (diff.hasFailed || !diff.output.trim()) {
902
- say('No staged changes found');
566
+ export async function worktreeDelete(worktree = '') {
567
+ const worktrees = await shell`git worktree list`;
568
+ const worktreePaths = worktrees.output
569
+ .split('\n')
570
+ .map(line => line.split(' ')[0])
571
+ .filter(path => path !== process.cwd());
572
+
573
+ if (worktreePaths.length === 0) {
574
+ say('No worktrees found');
903
575
  return;
904
576
  }
905
-
906
- const commit = await ai(
907
- `Generate a commit message for these changes: ${diff.output}`,
908
- {
909
- title: 'Concise commit title (50 chars max)',
910
- body: 'Detailed commit body explaining what and why',
911
- type: 'Commit type (feat/fix/docs/refactor/test/chore)'
912
- }
913
- );
914
-
915
- const message = `${commit.type}: ${commit.title}\n\n${commit.body}`;
916
- await exec`git commit -m "${message}"`;
917
-
918
- say(`βœ… Committed with AI-generated message:`);
919
- console.log(message);
577
+
578
+ const worktreeName = worktree || await ask('Select worktree to delete', worktreePaths);
579
+ const rmDir = worktreePaths.find(path => path.includes(worktreeName));
580
+
581
+ if (!rmDir) {
582
+ say(`Worktree for feature ${worktreeName} not found`);
583
+ return;
584
+ }
585
+
586
+ await exec`git worktree remove ${rmDir} --force`;
587
+ say(`Deleted worktree for feature ${worktreeName} in ${rmDir}`);
920
588
  }
589
+ ```
590
+
591
+ #### Generate Release Notes with AI
921
592
 
593
+ ```javascript
922
594
  /**
923
- * Enterprise AI setup with custom provider
595
+ * Generate comprehensive release notes using AI
924
596
  */
925
- export async function setupEnterpriseAI() {
926
- // Import your enterprise AI provider
927
- import { bedrock } from '@ai-sdk/amazon-bedrock';
928
-
929
- // Configure for enterprise use
930
- const enterpriseModel = bedrock('anthropic.claude-3-sonnet-20240229-v1:0', {
931
- region: 'us-east-1'
932
- // Uses AWS credentials from environment/profile
933
- });
934
-
935
- ai.configure({ model: enterpriseModel });
936
-
937
- const analysis = await ai(
938
- 'Analyze our company performance from this quarterly report: [data]',
597
+ export async function generateReleaseNotes(fromTag = '', toTag = 'HEAD') {
598
+ const { ai, writeToFile, exec, say, ask } = global.bunosh;
599
+
600
+ // Get version
601
+ const version = await ask('Release version:', '1.0.0');
602
+
603
+ // Get commit history
604
+ const gitLog = fromTag
605
+ ? await exec`git log ${fromTag}..${toTag} --pretty=format:"%h %s" --no-merges`
606
+ : await exec`git log -n 50 --pretty=format:"%h %s" --no-merges`;
607
+
608
+ // Get diff statistics
609
+ const stats = fromTag
610
+ ? await exec`git diff --stat ${fromTag}..${toTag}`
611
+ : await exec`git diff --stat HEAD~50..HEAD`;
612
+
613
+ // Generate release notes with AI
614
+ const releaseNotes = await ai(
615
+ `Generate professional release notes for version ${version} based on these commits and changes:
616
+
617
+ Commits:
618
+ ${gitLog.output}
619
+
620
+ Statistics:
621
+ ${stats.output}
622
+
623
+ Group changes logically and write user-friendly descriptions.`,
939
624
  {
940
- summary: 'Executive summary of performance',
941
- risks: 'Identified business risks',
942
- opportunities: 'Growth opportunities',
943
- recommendations: 'Strategic recommendations'
625
+ features: 'New features (bullet points with emoji)',
626
+ fixes: 'Bug fixes',
627
+ acknowledgments: 'Contributors and acknowledgments'
944
628
  }
945
629
  );
946
-
947
- say('πŸ“Š Enterprise AI analysis complete');
948
- console.log(analysis);
630
+
631
+ // Write release notes
632
+ writeToFile(`CHANGELOG.md`, (line) => {
633
+ line`# Release v${version}`;
634
+ line`*${new Date().toLocaleDateString()}*`;
635
+ line``;
636
+ line`## ✨ New Features`;
637
+ line`${releaseNotes.features}`;
638
+ line``;
639
+ line`## πŸ› Bug Fixes`;
640
+ line`${releaseNotes.fixes}`;
641
+ line``;
642
+ line`## πŸ™ Acknowledgments`;
643
+ line`${releaseNotes.acknowledgments}`;
644
+
645
+ // append previous contents
646
+ line.fromFile('CHANGELOG.md');
647
+ });
648
+
649
+ say(`πŸ“ Release notes generated for v${version}`);
949
650
  }
950
651
  ```
951
652
 
952
- ### Simple Text Generation
653
+ ### Analyze Logs with AI
654
+
655
+ ```js
656
+ const fileContents = await shell`tail -n 500 error.log`
657
+ const analysis = await ai(`Analyze this error log ${fileContents.output}`, {
658
+ severity: "critical/high/medium/low",
659
+ rootCause: "specific issue identified",
660
+ solution: "step-by-step fix",
661
+ preventionTips: "how to avoid this"
662
+ });
663
+ ```
953
664
 
954
- For quick text generation without structured output:
665
+ #### Build and Publish Containers in Parallel
955
666
 
956
667
  ```javascript
957
668
  /**
958
- * Generate marketing copy
669
+ * Build and publish multiple services in parallel
959
670
  */
960
- export async function generateCopy(product) {
961
- const copy = await ai(`Write compelling marketing copy for: ${product}`);
962
- say('πŸ“ Generated copy:');
963
- console.log(copy);
964
- }
671
+ export async function publishContainers(registry = 'docker.io/myorg') {
672
+ const { exec, task, say, yell } = global.bunosh;
965
673
 
966
- /**
967
- * Translate content
968
- */
969
- export async function translate(text, language = 'Spanish') {
970
- const translation = await ai(`Translate to ${language}: ${text}`);
971
- say(`🌐 Translation to ${language}:`);
972
- console.log(translation);
973
- }
974
- ```
674
+ const services = ['api', 'web', 'worker', 'admin'];
675
+ const version = process.env.VERSION || 'latest';
975
676
 
976
- ### Progressive Enhancement
677
+ say(`🐳 Building ${services.length} containers...`);
977
678
 
978
- The AI task features:
979
- - **🎭 Animated Progress**: Braille spinner animation during generation
980
- - **πŸ“Š Token Tracking**: Shows token usage for cost monitoring
981
- - **⚑ Fast Inference**: Optimized for speed with Groq and other providers
982
- - **πŸ”§ Structured Output**: Get JSON responses with defined schemas
983
- - **🎯 Provider Auto-Detection**: Automatically detects available API keys
984
- - **πŸ’ͺ Error Handling**: Graceful handling of API errors and rate limits
679
+ task.stopOnFailures();
680
+ // Build all containers in parallel
681
+ const buildResults = await Promise.all(
682
+ services.map(service =>
683
+ exec`docker build -t ${registry}/${service}:${version} -f ${service}/Dockerfile ${service}`
684
+ )
685
+ );
985
686
 
986
- Transform your development workflow with AI-powered automation! Generate documentation, analyze code, create tests, write commit messages, and much more.
687
+ say('βœ… All containers built successfully');
987
688
 
988
- ## Command Features
689
+ // Push all containers in parallel
690
+ say('πŸ“€ Publishing to registry...');
989
691
 
990
- ### Automatic CLI Generation
991
- - `functionName` β†’ `bunosh function:name`
992
- - Function parameters become command arguments
993
- - Last object parameter becomes CLI options
994
- - JSDoc comments become help descriptions
692
+ const pushResults = await Promise.all(
693
+ services.map(service =>
694
+ exec`docker push ${registry}/${service}:${version}`
695
+ )
696
+ );
995
697
 
996
- ### Smart Argument Handling
997
- ```javascript
998
- // Function definition
999
- export function deploy(env = 'staging', options = { force: false, verbose: false }) {
1000
- // ...
698
+ yell('CONTAINERS PUBLISHED!');
699
+ say(`Published: ${pushResults.join(', ')}`);
700
+ say(`Registry: ${registry}`);
701
+ say(`Version: ${version}`);
1001
702
  }
1002
-
1003
- // CLI usage
1004
- bunosh deploy production --force --verbose
1005
703
  ```
1006
704
 
1007
- ### Help and Documentation
1008
- ```bash
1009
- # List all commands
1010
- bunosh
705
+ #### Kubernetes Deployment Control
1011
706
 
1012
- # Get help for specific command
1013
- bunosh deploy --help
1014
- ```
707
+ ```javascript
708
+ /**
709
+ * Deploy to Kubernetes with health checks
710
+ */
711
+ export async function kubeDeploy(
712
+ environment = 'staging',
713
+ options = { wait: true, replicas: 3 }
714
+ ) {
715
+ const { exec, task, say, yell, ask } = global.bunosh;
716
+
717
+ // Confirm production deployments
718
+ if (environment === 'production') {
719
+ const confirmed = await ask(
720
+ `⚠️ Deploy to PRODUCTION?`,
721
+ false
722
+ );
723
+ if (!confirmed) {
724
+ say('Deployment cancelled');
725
+ return;
726
+ }
727
+ }
1015
728
 
1016
- ### Shell Auto-Completion
1017
- Enable tab completion for faster command typing:
729
+ // Set kubectl context
730
+ await task('Setting context', () =>
731
+ exec`kubectl config use-context ${environment}`
732
+ );
1018
733
 
1019
- ```bash
1020
- # πŸš€ Auto-setup (recommended) - detects your shell and installs completion
1021
- bunosh setup-completion
734
+ // Apply configurations
735
+ await task('Applying configurations', () =>
736
+ exec`kubectl apply -f k8s/${environment}/`
737
+ );
1022
738
 
1023
- # Manual setup if needed
1024
- bunosh completion bash > ~/.bunosh-completion.bash
1025
- echo "source ~/.bunosh-completion.bash" >> ~/.bashrc
1026
- source ~/.bashrc
739
+ // Scale if needed
740
+ if (options.replicas) {
741
+ await task(`Scaling to ${options.replicas} replicas`, () =>
742
+ exec`kubectl scale deployment/app --replicas=${options.replicas}`
743
+ );
744
+ }
1027
745
 
1028
- # Now use tab completion
1029
- bunosh dep<TAB> # Completes to 'deploy'
1030
- bunosh <TAB><TAB> # Shows all available commands
1031
- ```
746
+ // Wait for rollout
747
+ if (options.wait) {
748
+ await task('Waiting for rollout', () =>
749
+ exec`kubectl rollout status deployment/app --timeout=5m`
750
+ );
751
+ }
1032
752
 
1033
- **Supported shells:** bash, zsh, fish. The `setup-completion` command automatically detects your shell and handles installation. See [COMPLETION.md](COMPLETION.md) for detailed setup.
753
+ // Verify deployment
754
+ const pods = await exec`kubectl get pods -l app=myapp -o json`;
755
+ const podData = JSON.parse(pods.output);
756
+ const runningPods = podData.items.filter(
757
+ pod => pod.status.phase === 'Running'
758
+ ).length;
759
+
760
+ if (runningPods === options.replicas) {
761
+ yell('DEPLOYMENT SUCCESSFUL!');
762
+ say(`βœ… ${runningPods} pods running in ${environment}`);
763
+ } else {
764
+ yell('DEPLOYMENT ISSUES!');
765
+ say(`⚠️ Only ${runningPods}/${options.replicas} pods running`);
766
+ }
767
+ }
1034
768
 
1035
- ### Staying Up to Date
769
+ /**
770
+ * Rollback Kubernetes deployment
771
+ */
772
+ export async function kubeRollback(environment = 'staging') {
773
+ const { exec, say, ask } = global.bunosh;
1036
774
 
1037
- **Single Executable:**
1038
- ```bash
1039
- # Check for updates
1040
- bunosh upgrade --check
775
+ const confirmed = await ask(
776
+ `Rollback ${environment} deployment?`,
777
+ false
778
+ );
1041
779
 
1042
- # Upgrade to latest version
1043
- bunosh upgrade
780
+ if (!confirmed) {
781
+ say('Rollback cancelled');
782
+ return;
783
+ }
1044
784
 
1045
- # Force reinstall current version
1046
- bunosh upgrade --force
1047
- ```
785
+ await exec`kubectl config use-context ${environment}`;
786
+ await exec`kubectl rollout undo deployment/app`;
787
+ await exec`kubectl rollout status deployment/app`;
1048
788
 
1049
- **NPM Installation:**
1050
- ```bash
1051
- npm update -g bunosh
789
+ say(`βœ… Rolled back ${environment} deployment`);
790
+ }
1052
791
  ```
1053
792
 
1054
- ## Advanced Usage
793
+ #### AWS Infrastructure Management
1055
794
 
1056
- ### Parallel Task Execution
1057
- ```javascript
1058
- const results = await Promise.all([
1059
- task('Task 1', () => exec`sleep 2 && echo "Done 1"`),
1060
- task('Task 2', () => exec`sleep 2 && echo "Done 2"`),
1061
- task('Task 3', () => exec`sleep 2 && echo "Done 3"`)
1062
- ]);
795
+ ```
796
+ bunosh aws:spawn-server --count 3
1063
797
  ```
1064
798
 
1065
- ### Error Handling
1066
799
  ```javascript
1067
- export async function deployWithRollback(env) {
1068
- try {
1069
- await deploy(env);
1070
- } catch (error) {
1071
- say('❌ Deployment failed, rolling back...');
1072
- await exec`kubectl rollout undo deployment/myapp`;
1073
- throw error;
1074
- }
1075
- }
1076
- ```
800
+ /**
801
+ * Spawn EC2 instances and configure
802
+ *
803
+ */
804
+ export async function awsSpawnServer(
805
+ instanceType = 't3.micro',
806
+ options = { count: 1, region: 'us-east-1' }
807
+ ) {
808
+ const { exec, task, say, writeToFile } = global.bunosh;
809
+
810
+ const result = await exec`aws ec2 run-instances \
811
+ --image-id ami-0c55b159cbfafe1f0 \
812
+ --instance-type ${instanceType} \
813
+ --count ${options.count} \
814
+ --region ${options.region} \
815
+ --output json`;
816
+
817
+ const instanceIds = JSON.parse(result.output).Instances.map(i => i.InstanceId);
818
+ say(`πŸš€ Launched instances: ${instanceIds.join(', ')}`);
819
+
820
+ exec`aws ec2 wait instance-running --instance-ids ${instanceIds.join(' ')}`
821
+
822
+ const details = await exec`aws ec2 describe-instances \
823
+ --instance-ids ${instanceIds.join(' ')} \
824
+ --output json`;
825
+ const instances = JSON.parse(details.output).Reservations[0].Instances;
826
+
827
+ writeToFile('instances.json', (line) => {
828
+ line`${JSON.stringify(instances, null, 2)}`;
829
+ });
1077
830
 
1078
- ### NPM Scripts Integration
1079
- Bunosh automatically includes your package.json scripts:
1080
- ```bash
1081
- bunosh npm:test # runs npm run test
1082
- bunosh npm:build # runs npm run build
1083
- ```
831
+ // Output connection info
832
+ instances.forEach(instance => {
833
+ say(`Instance ${instance.InstanceId}:`);
834
+ say(` Public IP: ${instance.PublicIpAddress}`);
835
+ say(` SSH: ssh -i key.pem ec2-user@${instance.PublicIpAddress}`);
836
+ });
1084
837
 
1085
- ## Contributing
838
+ return instances;
839
+ }
1086
840
 
1087
- 1. Fork the repository
1088
- 2. Create a feature branch
1089
- 3. Write tests for new functionality
1090
- 4. Submit a pull request
841
+ /**
842
+ * Configure Cloudflare DNS for new servers
843
+ */
844
+ export async function cloudflareSetup(domain, ipAddress) {
845
+ const { exec, task, say } = global.bunosh;
846
+
847
+ const zoneId = process.env.CLOUDFLARE_ZONE_ID;
848
+ const apiToken = process.env.CLOUDFLARE_API_TOKEN;
849
+
850
+ await task('Creating DNS record', async () => {
851
+ const result = await exec`curl -X POST \
852
+ "https://api.cloudflare.com/client/v4/zones/${zoneId}/dns_records" \
853
+ -H "Authorization: Bearer ${apiToken}" \
854
+ -H "Content-Type: application/json" \
855
+ --data '{
856
+ "type": "A",
857
+ "name": "${domain}",
858
+ "content": "${ipAddress}",
859
+ "ttl": 3600
860
+ }'`;
861
+
862
+ return JSON.parse(result.output);
863
+ });
864
+
865
+ say(`βœ… DNS configured: ${domain} β†’ ${ipAddress}`);
866
+ }
867
+ ```
1091
868
 
1092
869
  ## License
1093
870
 
@@ -1095,4 +872,4 @@ MIT License - see LICENSE file for details.
1095
872
 
1096
873
  ---
1097
874
 
1098
- Built with ❀️ for modern JavaScript development
875
+ Cooked with ❀️ from Ukraine πŸ‡ΊπŸ‡¦