bunosh 0.2.3 → 0.3.1

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
@@ -373,23 +373,123 @@ Commands:
373
373
  All Bunosh functions are available via `global.bunosh`:
374
374
 
375
375
  ```javascript
376
- const { exec, fetch, writeToFile, copyFile, say, ask, yell, task } = global.bunosh;
376
+ const { exec, shell, fetch, writeToFile, copyFile, say, ask, yell, task } = global.bunosh;
377
377
  ```
378
378
 
379
- ### Shell Execution (`exec`)
379
+ ### Shell Execution
380
+
381
+ Bunosh provides two ways to execute shell commands:
382
+
383
+ #### `exec` - Universal Shell Execution
384
+
385
+ Best for complex commands, cross-platform compatibility, and when you need real-time streaming output.
386
+
380
387
  ```javascript
381
- // Simple commands
382
- await exec`echo "Hello World"`;
383
- await exec`npm install`;
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
391
+ await exec`docker build . | tee build.log`;
392
+ ```
393
+
394
+ #### `shell` - Native Bun Shell (with Node.js fallback)
395
+
396
+ Best for simple commands when running under Bun for maximum performance.
397
+
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`;
404
+ ```
384
405
 
385
- // With environment variables
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:
421
+
422
+ ```javascript
423
+ // Both tasks support environment variables
424
+ await shell`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
386
425
  await exec`echo $NODE_ENV`.env({ NODE_ENV: 'production' });
387
426
 
388
- // With working directory
427
+ // Both support working directory changes
428
+ await shell`pwd`.cwd('/tmp');
389
429
  await exec`ls -la`.cwd('/tmp');
390
430
 
391
- // Complex shell commands
392
- await exec`find . -name "*.js" | grep -v node_modules | wc -l`;
431
+ // Choose based on complexity and performance needs
432
+ await shell`cat package.json`; // Simple, fast
433
+ await exec`npm install --verbose`; // Complex, streaming
434
+ ```
435
+
436
+ #### TaskResult Object
437
+
438
+ Both `exec` and `shell` return a `TaskResult` object with the following properties and methods:
439
+
440
+ ```javascript
441
+ const result = await exec`ls -la`;
442
+ // or
443
+ const result = await shell`ls -la`;
444
+
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)
452
+ ```
453
+
454
+ #### Error Handling Examples
455
+
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
+ }
465
+
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
+ }
472
+
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
+ }
479
+
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
+ }
487
+
488
+ // ✅ New: Explicit success/failure handling
489
+ const result = await exec`failing-command`;
490
+ if (result.hasFailed) {
491
+ // Handle failure explicitly
492
+ }
393
493
  ```
394
494
 
395
495
  ### HTTP Requests (`fetch`)
@@ -414,20 +514,477 @@ copyFile('template.js', 'output.js');
414
514
  ```
415
515
 
416
516
  ### User Interaction
517
+
518
+ #### `ask()` - Interactive User Input
519
+
520
+ The `ask()` function provides flexible ways to get user input with smart parameter detection and multiple modes:
521
+
417
522
  ```javascript
418
- // Get user input
523
+ // === SIMPLE SYNTAX WITH SMART DETECTION ===
524
+
525
+ // Basic text input
419
526
  const name = await ask('What is your name?');
420
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
+ ]);
542
+
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 });
547
+
548
+ // === ADVANCED OPTIONS SYNTAX ===
549
+
550
+ // Multiline text input (opens system editor)
551
+ const description = await ask('Enter project description:', {
552
+ multiline: true // Same as editor: true
553
+ });
554
+
555
+ // Editor input with default content
556
+ const config = await ask('Edit configuration:', {
557
+ editor: true,
558
+ default: 'Initial content here...'
559
+ });
560
+
561
+ // Password input (hidden)
562
+ const password = await ask('Enter password:', {
563
+ type: 'password'
564
+ });
565
+
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
+ ```
571
+
572
+ #### Ask Function Signatures
573
+
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
586
+ ```
587
+
588
+ #### Ask Options Reference
589
+
590
+ | Parameter/Option | Type | Description | Example |
591
+ |------------------|------|-------------|---------|
592
+ | **Smart Detection** | | |
593
+ | `defaultValue` | String/Number | Sets default value for text/number input | `'John'`, `3000` |
594
+ | `defaultValue` | Boolean | Auto-detects as confirmation prompt | `true`, `false` |
595
+ | `choices` | Array | Auto-detects as selection list | `['A', 'B', 'C']` |
596
+ | **Options Object** | | |
597
+ | `multiple` | Boolean | Enables multiple selections (requires `choices`) | `true` |
598
+ | `multiline` | Boolean | Opens system editor for multi-line input | `true` |
599
+ | `editor` | Boolean | Opens system editor for multi-line input (same as `multiline`) | `true` |
600
+ | `default` | Any | Default value or content (when using options object) | `'default value'` |
601
+ | `type` | String | Input type: `'input'`, `'confirm'`, `'password'`, `'number'` | `'password'` |
602
+ | `validate` | Function | Custom validation function | `(input) => input.length > 0` |
603
+
604
+ #### Advanced Ask Examples
605
+
606
+ ```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
+ }
641
+
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
+ }
654
+
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
+ }
679
+
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
+ }
704
+ ```
705
+
706
+ #### Output Functions
707
+
708
+ ```javascript
421
709
  // Output messages
422
- say('Building project...'); // Normal output
423
- yell('BUILD COMPLETE!'); // Emphasized output
710
+ say('Building project...'); // Normal output with !
711
+ yell('BUILD COMPLETE!'); // Emphasized ASCII art output
424
712
 
425
- // Wrap long operations
713
+ // Wrap long operations with progress
426
714
  await task('Installing dependencies', async () => {
427
715
  await exec`npm install`;
428
716
  });
429
717
  ```
430
718
 
719
+ ## 🤖 AI-Powered Tasks
720
+
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.
722
+
723
+ ### Quick Setup
724
+
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.
729
+
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
+ ```
735
+
736
+ ### Built-in AI Providers
737
+
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`)
741
+
742
+ ### Custom AI Providers
743
+
744
+ For enterprise and custom setups, you can import and register any AI provider manually:
745
+
746
+ ```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'
756
+ }
757
+ });
758
+
759
+ ai.configure({ model: bedrockModel });
760
+
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
+ }
769
+ }
770
+ });
771
+
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
+ });
782
+
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
+ });
798
+
799
+ // Reset to environment variable configuration
800
+ ai.reset();
801
+
802
+ // Check current configuration
803
+ const config = ai.getConfig();
804
+ console.log('Current AI config:', config);
805
+ ```
806
+
807
+ ### AI Task Examples
808
+
809
+ ```javascript
810
+ const { ai, writeToFile, say } = global.bunosh;
811
+
812
+ /**
813
+ * Generate project documentation with AI
814
+ */
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
+ }
843
+
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}`,
852
+ {
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)'
858
+ }
859
+ );
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}`);
867
+ }
868
+
869
+ /**
870
+ * Generate test cases from code
871
+ */
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}`);
893
+ }
894
+
895
+ /**
896
+ * Create commit messages from git diff
897
+ */
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');
903
+ return;
904
+ }
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);
920
+ }
921
+
922
+ /**
923
+ * Enterprise AI setup with custom provider
924
+ */
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]',
939
+ {
940
+ summary: 'Executive summary of performance',
941
+ risks: 'Identified business risks',
942
+ opportunities: 'Growth opportunities',
943
+ recommendations: 'Strategic recommendations'
944
+ }
945
+ );
946
+
947
+ say('📊 Enterprise AI analysis complete');
948
+ console.log(analysis);
949
+ }
950
+ ```
951
+
952
+ ### Simple Text Generation
953
+
954
+ For quick text generation without structured output:
955
+
956
+ ```javascript
957
+ /**
958
+ * Generate marketing copy
959
+ */
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
+ }
965
+
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
+ ```
975
+
976
+ ### Progressive Enhancement
977
+
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
985
+
986
+ Transform your development workflow with AI-powered automation! Generate documentation, analyze code, create tests, write commit messages, and much more.
987
+
431
988
  ## Command Features
432
989
 
433
990
  ### Automatic CLI Generation