bunosh 0.3.0 β†’ 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
31
+
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
12
55
 
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
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,826 +85,786 @@ 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
-
52
- ### Option 3: NPM Package
53
95
 
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;
109
+ // Bunoshfile.js
110
+ const { exec, say } = global.bunosh;
73
111
 
74
112
  /**
75
- * Installs project dependencies
113
+ * Builds the project for production
76
114
  */
77
- export async function install() {
78
- await exec`npm install`;
79
- say('πŸ“¦ Dependencies installed!');
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!');
80
119
  }
120
+ ```
81
121
 
82
- /**
83
- * Starts development server
84
- */
85
- export async function dev() {
86
- say('πŸš€ Starting development server...');
87
- await exec`npm run dev`;
88
- }
122
+ That's it! Your function is now a CLI command.
89
123
 
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`;
124
+ 3. **Run it:**
125
+ ```bash
126
+ # build for production
127
+ bunosh build
96
128
 
97
- if (target === 'production') {
98
- await exec`npm run optimize`;
99
- yell('BUILD COMPLETE!');
100
- }
101
- }
129
+ # build for staging
130
+ bunosh build staging
102
131
 
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
- }
132
+ # build for development
133
+ bunosh build development
134
+ ```
135
+
136
+ ## Commands
137
+
138
+ ### Creating Commands
111
139
 
112
- say(`πŸš€ Deploying to ${env}...`);
113
- await build('production');
114
- await exec`docker build -t myapp:${env} .`;
115
- await exec`docker push myapp:${env}`;
140
+ Every exported function in `Bunoshfile.js` becomes a CLI command:
116
141
 
117
- yell(`DEPLOYED TO ${env.toUpperCase()}!`);
142
+ ```javascript
143
+ // Simple command
144
+ export function hello() {
145
+ console.log('Hello, World!');
118
146
  }
119
147
 
120
- /**
121
- * Cleans up temporary files
122
- */
123
- export async function clean() {
124
- await exec`rm -rf dist node_modules/.cache tmp`;
125
- say('✨ All clean!');
148
+ // Command with parameters
149
+ export function greet(name = 'friend') {
150
+ console.log(`Hello, ${name}!`);
126
151
  }
127
152
 
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';
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)' : ''}`);
157
+ }
158
+ ```
134
159
 
135
- say('πŸ—οΈ Setting up project...');
160
+ **CLI Usage:**
161
+ ```bash
162
+ bunosh hello
163
+ bunosh greet John
164
+ bunosh deploy production --force --verbose
165
+ ```
136
166
 
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
- });
167
+ ### Arguments and Options
150
168
 
151
- if (useTypescript) {
152
- await exec`npm install typescript --save-dev`;
153
- }
169
+ Bunosh automatically maps function parameters to CLI arguments:
170
+
171
+ ```javascript
172
+ /**
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
178
+ */
179
+ export async function feature(name, base = 'main', options = { push: false }) {
180
+ await exec`git checkout -b feature/${name} ${base}`;
154
181
 
155
- yell('PROJECT READY!');
182
+ if (options.push) {
183
+ await exec`git push -u origin feature/${name}`;
184
+ }
156
185
  }
157
186
  ```
158
187
 
159
- ### Run Your Tasks
160
-
188
+ **Generated CLI:**
161
189
  ```bash
162
- # List all available commands
163
- bunosh
164
-
165
- # Run individual tasks
166
- bunosh install
167
- bunosh dev
168
- bunosh build
169
- bunosh build staging
170
- bunosh deploy production --skip-tests
171
- bunosh clean
172
- bunosh setup
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
173
193
  ```
174
194
 
175
- **Bunosh will display your tasks like this:**
195
+ ### Command Naming
176
196
 
177
- ```
178
- 🍲 Your exceptional task runner
197
+ Functions are automatically converted to kebab-case commands:
179
198
 
180
- Usage: bunosh <command> <args> [options]
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` |
181
205
 
182
- Commands are loaded from exported functions in Bunoshfile.js
206
+ ## Tasks
183
207
 
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
- ```
194
-
195
- ## Example: DevOps Tasks
208
+ All Bunosh utilities are available via `global.bunosh`:
196
209
 
197
210
  ```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
- }
211
+ const { exec, shell, fetch, writeToFile, copyFile, task, ai, say, ask, yell } = global.bunosh;
212
+ ```
213
213
 
214
- say('βœ… All services healthy!');
215
- }
214
+ > We use global variables instead of imports to ensure you can use it with bunosh single-executable on any platform.
216
215
 
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
216
 
224
- await exec`pg_dump ${database} | gzip > ${filename}`;
225
- await exec`aws s3 cp ${filename} s3://backups/${filename}`;
226
- await exec`rm ${filename}`;
217
+ #### `exec`
227
218
 
228
- say(`πŸ“¦ Backup saved: ${filename}`);
229
- }
219
+ Run single command using [child process `spawn`](https://nodejs.org/api/child_process.html#child_processspawncommand-args-options)
230
220
 
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!');
238
- }
221
+ ```javascript
222
+ // Complex commands with pipes and streaming output
223
+ await exec`npm install --verbose`;
224
+ await exec`docker build . | tee build.log`;
225
+ await exec`find . -name "*.js" | grep -v node_modules | wc -l`;
239
226
 
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
- }
227
+ // With environment variables
228
+ await exec`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
249
229
 
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`);
256
- }
230
+ // In specific directory
231
+ await exec`npm install`.cwd('/tmp/project');
257
232
  ```
258
233
 
259
- **Bunosh displays these as:**
234
+ By default task prints live line-by-line output from stdout and stderr. To disable output, use `silent` method:
260
235
 
261
- ```
262
- Usage: bunosh <command> <args> [options]
263
-
264
- Commands are loaded from exported functions in Bunoshfile.js
236
+ ```javascript
265
237
 
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
238
+ // disable printing output
239
+ await task.silent(() => exec`npm install`);
276
240
 
241
+ // disable output for all commands
242
+ await task.silence();
277
243
  ```
278
244
 
279
- ## Example: Content Management
245
+ See more [#silent](#silent)
246
+
247
+ #### `shell` - Fast Native Execution
248
+
249
+ Optimized for simple, fast commands when running under Bun:
280
250
 
281
251
  ```javascript
282
- const { exec, writeToFile, ask, say } = global.bunosh;
252
+ // Simple, fast commands
253
+ await shell`pwd`;
254
+ await shell`ls -la`;
255
+ await shell`cat package.json`;
256
+ ```
283
257
 
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
- });
258
+ For more details see [bun shell](https://bun.sh/docs/runtime/shell) reference
303
259
 
304
- say(`πŸ“ Created: posts/${date}-${slug}.md`);
305
- }
260
+ `shell` vs `exec`
306
261
 
307
- /**
308
- * Optimizes and compresses images
309
- */
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
- }
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 |
315
266
 
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
- });
267
+ shell prints output from stdout and stderr. To disable output, [make tasks silent](#silent):
332
268
 
333
- say(`πŸ“„ Created: content/pages/${slug}.md`);
334
- }
269
+ ### HTTP Requests
335
270
 
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
- }
271
+ Built-in fetch with progress indicators:
344
272
 
273
+ ```javascript
345
274
  /**
346
- * Builds and serves development site
275
+ * Check service health
347
276
  */
348
- export async function serve(port = 1313) {
349
- await exec`hugo server --port ${port} --buildDrafts`;
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
+ }
350
286
  }
351
287
  ```
352
288
 
353
- **Bunosh displays these as:**
289
+ ### File Operations
354
290
 
355
- ```
356
- Usage: bunosh <command> <args> [options]
291
+ Template-based file writing and copying:
357
292
 
358
- Commands are loaded from exported functions in Bunoshfile.js
293
+ ```javascript
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
+ });
359
305
 
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]
306
+ say('πŸ“ Config file created');
307
+ }
368
308
 
309
+ // Copy files
310
+ copyFile('template.env', '.env');
369
311
  ```
370
312
 
371
- ## Built-in Functions
313
+ ## Input/Output
314
+
315
+ ### `say` - Normal Output
372
316
 
373
- All Bunosh functions are available via `global.bunosh`:
317
+ Standard output with visual indicator:
374
318
 
375
319
  ```javascript
376
- const { exec, fetch, writeToFile, copyFile, say, ask, yell, task } = global.bunosh;
320
+ say('Building project...');
321
+ say('πŸ“¦ Dependencies installed');
322
+ say(`Found ${count} files to process`);
377
323
  ```
378
324
 
379
- ### Shell Execution (`exec`)
325
+ ### `ask` - User Input
380
326
 
381
- The `exec` function runs shell commands and returns a `TaskResult` object with the command output and status.
327
+ Flexible user input with smart parameter detection:
382
328
 
383
329
  ```javascript
384
- // Simple commands
385
- await exec`echo "Hello World"`;
386
- await exec`npm install`;
330
+ // Text input with default
331
+ const name = await ask('Project name:', 'my-app');
387
332
 
388
- // With environment variables
389
- await exec`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
333
+ // Boolean confirmation (auto-detects)
334
+ const proceed = await ask('Continue?', true);
390
335
 
391
- // With working directory
392
- await exec`ls -la`.cwd('/tmp');
336
+ // Single selection (auto-detects from array)
337
+ const env = await ask('Select environment:', ['dev', 'staging', 'prod']);
393
338
 
394
- // Complex shell commands
395
- await exec`find . -name "*.js" | grep -v node_modules | wc -l`;
339
+ // Multiple selection
340
+ const features = await ask('Select features:',
341
+ ['TypeScript', 'ESLint', 'Tests'],
342
+ { multiple: true }
343
+ );
344
+
345
+ // Password input
346
+ const password = await ask('Enter password:', { type: 'password' });
347
+
348
+ // Multiline editor input
349
+ const description = await ask('Enter description:', { editor: true });
396
350
  ```
397
351
 
398
- #### TaskResult Object
352
+ | Parameter/Option | Type | Description | Example |
353
+ |------------------|------|-------------|---------|
354
+ | **Smart Detection** | | |
355
+ | `defaultValue` | String/Number | Sets default value for text/number input | `'John'`, `3000` |
356
+ | `defaultValue` | Boolean | Auto-detects as confirmation prompt | `true`, `false` |
357
+ | `choices` | Array | Auto-detects as selection list | `['A', 'B', 'C']` |
358
+ | **Options Object** | | |
359
+ | `multiple` | Boolean | Enables multiple selections (requires `choices`) | `true` |
360
+ | `multiline` | Boolean | Opens system editor for multi-line input | `true` |
361
+ | `editor` | Boolean | Opens system editor for multi-line input (same as `multiline`) | `true` |
362
+ | `default` | Any | Default value or content (when using options object) | `'default value'` |
363
+ | `type` | String | Input type: `'input'`, `'confirm'`, `'password'`, `'number'` | `'password'` |
364
+ | `validate` | Function | Custom validation function | `(input) => input.length > 0` |
399
365
 
400
- The `exec` function returns a `TaskResult` object with the following properties and methods:
401
366
 
402
- ```javascript
403
- const result = await exec`ls -la`;
367
+ ### `yell`
368
+
369
+ Emphasized Output
404
370
 
405
- // Properties
406
- result.status // 'success' or 'fail'
407
- result.output // Combined stdout/stderr as string
371
+ ASCII art output for important messages:
408
372
 
409
- // Getters (boolean)
410
- result.hasFailed // true if command failed (non-zero exit code)
411
- result.hasSucceeded // true if command succeeded (exit code 0)
373
+ ```javascript
374
+ yell('BUILD COMPLETE!');
375
+ yell('DEPLOYMENT SUCCESSFUL!');
412
376
  ```
413
377
 
414
- #### Error Handling Examples
378
+ ### `silent`
379
+
380
+ Stop printing realtime output
415
381
 
416
382
  ```javascript
417
- // Check command success
418
- const result = await exec`npm test`;
419
- if (result.hasSucceeded) {
420
- say('βœ… Tests passed!');
421
- } else {
422
- yell('❌ Tests failed!');
423
- console.log(result.output); // Show error details
424
- }
383
+ // Silence all task output
384
+ task.silence();
385
+ await shell`npm build`;
425
386
 
426
- // Get command output
427
- const result = await exec`git rev-parse HEAD`;
428
- if (result.hasSucceeded) {
429
- const commitHash = result.output.trim();
430
- say(`Current commit: ${commitHash}`);
431
- }
387
+ // restore printing output
388
+ task.prints();
432
389
 
433
- // Handle failures gracefully
434
- const result = await exec`optional-command-that-might-fail`;
435
- if (result.hasFailed) {
436
- say('Command failed, but continuing...');
437
- console.log('Error output:', result.output);
438
- }
390
+ // Silent specific task
391
+ const labels = await task.silent(() => shell(`gh api repos/:org/:repo/labels`));
392
+ ```
439
393
 
440
- // Old vs New style comparison
441
- // ❌ Old: Commands throw on failure
442
- try {
443
- await someOtherTaskRunner('failing-command');
444
- } catch (error) {
445
- // Handle error
446
- }
394
+ ## Task Control
447
395
 
448
- // βœ… New: Explicit success/failure handling
449
- const result = await exec`failing-command`;
450
- if (result.hasFailed) {
451
- // Handle failure explicitly
452
- }
453
- ```
396
+ ### Parallel Executions
454
397
 
455
- ### HTTP Requests (`fetch`)
456
- ```javascript
457
- // GET request with progress indicator
458
- const response = await fetch('https://api.github.com/repos/user/repo');
459
- const data = await response.json();
460
- ```
398
+ No magic here. Use `Promise.all()` to run tasks in parallel:
461
399
 
462
- ### File Operations
463
400
  ```javascript
464
- // Write file with template builder
465
- writeToFile('config.json', (line) => {
466
- line`{`;
467
- line` "name": "myapp",`;
468
- line` "version": "1.0.0"`;
469
- line`}`;
470
- });
471
-
472
- // Copy files
473
- copyFile('template.js', 'output.js');
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
+ ]);
474
407
  ```
475
408
 
476
- ### User Interaction
477
- ```javascript
478
- // Get user input
479
- const name = await ask('What is your name?');
409
+ ### Custom Tasks
480
410
 
481
- // Output messages
482
- say('Building project...'); // Normal output
483
- yell('BUILD COMPLETE!'); // Emphasized output
411
+ Name and group your tasks operations:
484
412
 
485
- // Wrap long operations
486
- await task('Installing dependencies', async () => {
487
- await exec`npm install`;
413
+ ```js
414
+ await task('Build', () => {
415
+ await exec`npm run build:frontend`);
416
+ await exec`npm run build:docs`);
488
417
  });
489
- ```
418
+ ````
490
419
 
491
- ## πŸ€– AI-Powered Tasks
420
+ ### Stop on Failure
492
421
 
493
- 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.
494
423
 
495
- ### Quick Setup
496
424
 
497
- Set your AI provider credentials:
498
- ```bash
499
- # Required: Choose your model
500
- 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
501
431
 
502
- # Required: Set API key for your chosen provider
503
- export OPENAI_API_KEY=your_key_here # for OpenAI models
504
- # export ANTHROPIC_API_KEY=your_key_here # for Claude models
505
- # export GROQ_API_KEY=your_key_here # for Groq models
506
- ```
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
+ }
507
437
 
508
- ### Built-in AI Providers
438
+ /**
439
+ * Cleanup - continue despite failures
440
+ */
441
+ export async function cleanup() {
442
+ task.ignoreFailures(); // Continue even if tasks fail
509
443
 
510
- - **OpenAI** - GPT-4o, GPT-4o-mini, GPT-3.5-turbo (via `OPENAI_API_KEY`)
511
- - **Anthropic** - Claude 3.5 Sonnet, Claude 3 Haiku (via `ANTHROPIC_API_KEY`)
512
- - **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
+ ```
513
450
 
514
- ### Custom AI Providers
451
+ ### Try Operations
515
452
 
516
- For enterprise and custom setups, you can import and register any AI provider manually:
453
+ Gracefully handle operations that might fail:
517
454
 
518
455
  ```javascript
519
- const { ai } = global.bunosh;
520
-
521
- // Method 1: Direct model configuration (most flexible)
522
- import { bedrock } from '@ai-sdk/amazon-bedrock';
523
- const bedrockModel = bedrock('anthropic.claude-3-sonnet-20240229-v1:0', {
524
- region: 'us-east-1',
525
- credentials: {
526
- accessKeyId: 'your-access-key',
527
- 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();
528
467
  }
529
- });
530
468
 
531
- ai.configure({ model: bedrockModel });
469
+ const apiHealthy = await task.try(() => fetch('http://localhost:3000/health');
532
470
 
533
- // Method 2: Register custom provider with environment variable
534
- import { xai } from '@ai-sdk/xai';
535
- ai.configure({
536
- registerProvider: {
537
- envVar: 'XAI_API_KEY',
538
- provider: {
539
- createInstance: (modelName) => xai(modelName)
540
- }
471
+ if (!apiHealthy) {
472
+ yell('API IS DOWN!');
541
473
  }
542
- });
474
+ }
475
+ ```
543
476
 
544
- // Method 3: Register any custom provider (Azure OpenAI, OpenRouter, etc.)
545
- import { openrouter } from '@openrouter/ai-sdk-provider';
546
- ai.configure({
547
- registerProvider: {
548
- envVar: 'OPENROUTER_API_KEY',
549
- provider: {
550
- createInstance: (modelName) => openrouter(modelName)
551
- }
552
- }
553
- });
477
+ ## πŸ’« AI Integration
554
478
 
555
- // Method 4: Register completely custom provider
556
- ai.configure({
557
- registerProvider: {
558
- envVar: 'CUSTOM_AI_API_KEY',
559
- provider: {
560
- createInstance: (modelName) => {
561
- // Your custom provider logic
562
- return customAIProvider(modelName, {
563
- apiKey: process.env.CUSTOM_AI_API_KEY,
564
- endpoint: 'https://custom-ai.company.com/v1'
565
- });
566
- }
567
- }
568
- }
569
- });
479
+ Built-in AI support for code generation, documentation, and automation.
480
+ Automatically responds to structured JSON output.
570
481
 
571
- // Reset to environment variable configuration
572
- ai.reset();
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
573
485
 
574
- // Check current configuration
575
- const config = ai.getConfig();
576
- console.log('Current AI config:', config);
486
+ ```bash
487
+ # Choose your AI model
488
+ export AI_MODEL=gpt-5 # or claude-4-sonnet, llama-3.3-70b, etc.
489
+
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
577
494
  ```
578
495
 
579
- ### 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
580
504
 
581
505
  ```javascript
582
- const { ai, writeToFile, say } = global.bunosh;
506
+ const { ai, writeToFile } = global.bunosh;
583
507
 
584
508
  /**
585
- * Generate project documentation with AI
509
+ * Generate commit message from staged changes
586
510
  */
587
- export async function generateDocs() {
588
- const codebase = fs.readFileSync('src/index.js', 'utf8');
589
-
590
- const result = await ai(
591
- `Generate documentation for this code: ${codebase}`,
592
- {
593
- overview: 'Brief project overview',
594
- apiReference: 'API documentation',
595
- examples: 'Usage examples',
596
- installation: 'Installation instructions'
597
- }
598
- );
599
-
600
- writeToFile('README.md', (line) => {
601
- line`# ${result.overview}`;
602
- line``;
603
- line`## Installation`;
604
- line`${result.installation}`;
605
- line``;
606
- line`## API Reference`;
607
- line`${result.apiReference}`;
608
- line``;
609
- line`## Examples`;
610
- line`${result.examples}`;
611
- });
612
-
613
- say('πŸ“š Documentation generated!');
614
- }
511
+ export async function commit() {
512
+ const diff = await exec`git diff --staged`;
615
513
 
616
- /**
617
- * Analyze and optimize code with AI suggestions
618
- */
619
- export async function codeReview(filename) {
620
- const code = fs.readFileSync(filename, 'utf8');
621
-
622
- const analysis = await ai(
623
- `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}`,
624
521
  {
625
- issues: 'List of potential issues',
626
- suggestions: 'Specific improvement suggestions',
627
- security: 'Security considerations',
628
- performance: 'Performance optimization tips',
629
- 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'
630
526
  }
631
527
  );
632
-
633
- say(`πŸ” Code Review for ${filename}:`);
634
- console.log(`Rating: ${analysis.rating}/10`);
635
- console.log(`Issues: ${analysis.issues}`);
636
- console.log(`Suggestions: ${analysis.suggestions}`);
637
- console.log(`Security: ${analysis.security}`);
638
- 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');
639
535
  }
536
+ ```
537
+
538
+ See more ai usage examples below:
539
+
540
+ ## Examples
541
+
542
+ ### Development Examples
543
+
544
+ #### Feature Branch Workflow
545
+
546
+ ```
547
+ bunosh worktree:create
548
+ bunosh worktree:delete
549
+ ```
640
550
 
551
+ ```javascript
641
552
  /**
642
- * Generate test cases from code
553
+ * Create worktree for feature development
643
554
  */
644
- export async function generateTests(sourceFile) {
645
- const code = fs.readFileSync(sourceFile, 'utf8');
646
-
647
- const tests = await ai(
648
- `Generate comprehensive unit tests for this code: ${code}`,
649
- {
650
- testSuite: 'Complete test suite code',
651
- edgeCases: 'List of edge cases covered',
652
- mockSetup: 'Required mocks and setup code'
653
- }
654
- );
655
-
656
- const testFile = sourceFile.replace('.js', '.test.js');
657
- writeToFile(testFile, (line) => {
658
- line`${tests.mockSetup}`;
659
- line``;
660
- line`${tests.testSuite}`;
661
- });
662
-
663
- say(`πŸ§ͺ Tests generated: ${testFile}`);
664
- 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}`);
665
561
  }
666
562
 
667
563
  /**
668
- * Create commit messages from git diff
564
+ * Remove worktree when feature is merged
669
565
  */
670
- export async function smartCommit() {
671
- const diff = await exec`git diff --staged`;
672
-
673
- if (diff.hasFailed || !diff.output.trim()) {
674
- 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');
675
575
  return;
676
576
  }
677
-
678
- const commit = await ai(
679
- `Generate a commit message for these changes: ${diff.output}`,
680
- {
681
- title: 'Concise commit title (50 chars max)',
682
- body: 'Detailed commit body explaining what and why',
683
- type: 'Commit type (feat/fix/docs/refactor/test/chore)'
684
- }
685
- );
686
-
687
- const message = `${commit.type}: ${commit.title}\n\n${commit.body}`;
688
- await exec`git commit -m "${message}"`;
689
-
690
- say(`βœ… Committed with AI-generated message:`);
691
- 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}`);
692
588
  }
589
+ ```
590
+
591
+ #### Generate Release Notes with AI
693
592
 
593
+ ```javascript
694
594
  /**
695
- * Enterprise AI setup with custom provider
595
+ * Generate comprehensive release notes using AI
696
596
  */
697
- export async function setupEnterpriseAI() {
698
- // Import your enterprise AI provider
699
- import { bedrock } from '@ai-sdk/amazon-bedrock';
700
-
701
- // Configure for enterprise use
702
- const enterpriseModel = bedrock('anthropic.claude-3-sonnet-20240229-v1:0', {
703
- region: 'us-east-1'
704
- // Uses AWS credentials from environment/profile
705
- });
706
-
707
- ai.configure({ model: enterpriseModel });
708
-
709
- const analysis = await ai(
710
- '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.`,
711
624
  {
712
- summary: 'Executive summary of performance',
713
- risks: 'Identified business risks',
714
- opportunities: 'Growth opportunities',
715
- recommendations: 'Strategic recommendations'
625
+ features: 'New features (bullet points with emoji)',
626
+ fixes: 'Bug fixes',
627
+ acknowledgments: 'Contributors and acknowledgments'
716
628
  }
717
629
  );
718
-
719
- say('πŸ“Š Enterprise AI analysis complete');
720
- 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}`);
721
650
  }
722
651
  ```
723
652
 
724
- ### 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
+ ```
725
664
 
726
- For quick text generation without structured output:
665
+ #### Build and Publish Containers in Parallel
727
666
 
728
667
  ```javascript
729
668
  /**
730
- * Generate marketing copy
669
+ * Build and publish multiple services in parallel
731
670
  */
732
- export async function generateCopy(product) {
733
- const copy = await ai(`Write compelling marketing copy for: ${product}`);
734
- say('πŸ“ Generated copy:');
735
- console.log(copy);
736
- }
671
+ export async function publishContainers(registry = 'docker.io/myorg') {
672
+ const { exec, task, say, yell } = global.bunosh;
737
673
 
738
- /**
739
- * Translate content
740
- */
741
- export async function translate(text, language = 'Spanish') {
742
- const translation = await ai(`Translate to ${language}: ${text}`);
743
- say(`🌐 Translation to ${language}:`);
744
- console.log(translation);
745
- }
746
- ```
674
+ const services = ['api', 'web', 'worker', 'admin'];
675
+ const version = process.env.VERSION || 'latest';
747
676
 
748
- ### Progressive Enhancement
677
+ say(`🐳 Building ${services.length} containers...`);
749
678
 
750
- The AI task features:
751
- - **🎭 Animated Progress**: Braille spinner animation during generation
752
- - **πŸ“Š Token Tracking**: Shows token usage for cost monitoring
753
- - **⚑ Fast Inference**: Optimized for speed with Groq and other providers
754
- - **πŸ”§ Structured Output**: Get JSON responses with defined schemas
755
- - **🎯 Provider Auto-Detection**: Automatically detects available API keys
756
- - **πŸ’ͺ 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
+ );
757
686
 
758
- 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');
759
688
 
760
- ## Command Features
689
+ // Push all containers in parallel
690
+ say('πŸ“€ Publishing to registry...');
761
691
 
762
- ### Automatic CLI Generation
763
- - `functionName` β†’ `bunosh function:name`
764
- - Function parameters become command arguments
765
- - Last object parameter becomes CLI options
766
- - JSDoc comments become help descriptions
692
+ const pushResults = await Promise.all(
693
+ services.map(service =>
694
+ exec`docker push ${registry}/${service}:${version}`
695
+ )
696
+ );
767
697
 
768
- ### Smart Argument Handling
769
- ```javascript
770
- // Function definition
771
- export function deploy(env = 'staging', options = { force: false, verbose: false }) {
772
- // ...
698
+ yell('CONTAINERS PUBLISHED!');
699
+ say(`Published: ${pushResults.join(', ')}`);
700
+ say(`Registry: ${registry}`);
701
+ say(`Version: ${version}`);
773
702
  }
774
-
775
- // CLI usage
776
- bunosh deploy production --force --verbose
777
703
  ```
778
704
 
779
- ### Help and Documentation
780
- ```bash
781
- # List all commands
782
- bunosh
705
+ #### Kubernetes Deployment Control
783
706
 
784
- # Get help for specific command
785
- bunosh deploy --help
786
- ```
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
+ }
787
728
 
788
- ### Shell Auto-Completion
789
- Enable tab completion for faster command typing:
729
+ // Set kubectl context
730
+ await task('Setting context', () =>
731
+ exec`kubectl config use-context ${environment}`
732
+ );
790
733
 
791
- ```bash
792
- # πŸš€ Auto-setup (recommended) - detects your shell and installs completion
793
- bunosh setup-completion
734
+ // Apply configurations
735
+ await task('Applying configurations', () =>
736
+ exec`kubectl apply -f k8s/${environment}/`
737
+ );
794
738
 
795
- # Manual setup if needed
796
- bunosh completion bash > ~/.bunosh-completion.bash
797
- echo "source ~/.bunosh-completion.bash" >> ~/.bashrc
798
- 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
+ }
799
745
 
800
- # Now use tab completion
801
- bunosh dep<TAB> # Completes to 'deploy'
802
- bunosh <TAB><TAB> # Shows all available commands
803
- ```
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
+ }
804
752
 
805
- **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
+ }
806
768
 
807
- ### Staying Up to Date
769
+ /**
770
+ * Rollback Kubernetes deployment
771
+ */
772
+ export async function kubeRollback(environment = 'staging') {
773
+ const { exec, say, ask } = global.bunosh;
808
774
 
809
- **Single Executable:**
810
- ```bash
811
- # Check for updates
812
- bunosh upgrade --check
775
+ const confirmed = await ask(
776
+ `Rollback ${environment} deployment?`,
777
+ false
778
+ );
813
779
 
814
- # Upgrade to latest version
815
- bunosh upgrade
780
+ if (!confirmed) {
781
+ say('Rollback cancelled');
782
+ return;
783
+ }
816
784
 
817
- # Force reinstall current version
818
- bunosh upgrade --force
819
- ```
785
+ await exec`kubectl config use-context ${environment}`;
786
+ await exec`kubectl rollout undo deployment/app`;
787
+ await exec`kubectl rollout status deployment/app`;
820
788
 
821
- **NPM Installation:**
822
- ```bash
823
- npm update -g bunosh
789
+ say(`βœ… Rolled back ${environment} deployment`);
790
+ }
824
791
  ```
825
792
 
826
- ## Advanced Usage
793
+ #### AWS Infrastructure Management
827
794
 
828
- ### Parallel Task Execution
829
- ```javascript
830
- const results = await Promise.all([
831
- task('Task 1', () => exec`sleep 2 && echo "Done 1"`),
832
- task('Task 2', () => exec`sleep 2 && echo "Done 2"`),
833
- task('Task 3', () => exec`sleep 2 && echo "Done 3"`)
834
- ]);
795
+ ```
796
+ bunosh aws:spawn-server --count 3
835
797
  ```
836
798
 
837
- ### Error Handling
838
799
  ```javascript
839
- export async function deployWithRollback(env) {
840
- try {
841
- await deploy(env);
842
- } catch (error) {
843
- say('❌ Deployment failed, rolling back...');
844
- await exec`kubectl rollout undo deployment/myapp`;
845
- throw error;
846
- }
847
- }
848
- ```
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
+ });
849
830
 
850
- ### NPM Scripts Integration
851
- Bunosh automatically includes your package.json scripts:
852
- ```bash
853
- bunosh npm:test # runs npm run test
854
- bunosh npm:build # runs npm run build
855
- ```
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
+ });
856
837
 
857
- ## Contributing
838
+ return instances;
839
+ }
858
840
 
859
- 1. Fork the repository
860
- 2. Create a feature branch
861
- 3. Write tests for new functionality
862
- 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
+ ```
863
868
 
864
869
  ## License
865
870
 
@@ -867,4 +872,4 @@ MIT License - see LICENSE file for details.
867
872
 
868
873
  ---
869
874
 
870
- Built with ❀️ for modern JavaScript development
875
+ Cooked with ❀️ from Ukraine πŸ‡ΊπŸ‡¦