ruby-shell 3.4.8 → 3.5.0
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.
- checksums.yaml +4 -4
- data/bin/rsh +144 -21
- metadata +5 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: bac3cf4ea368be8c2991ee650e1977c7fafd7b1548645c1e3daaa94fd29bae2d
         | 
| 4 | 
            +
              data.tar.gz: 31b8ae6ffcf460c7a236c72c8188254243879ab8b83ac690fcf8e61fc0aa46ad
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: bb8eb4cef6df5403bc751cf29d440a4289877fd9f7684f153e82196a3f24e425f88fabbe2ccae63c0ef108cae205feb241e84b52f138ad07975d03bd38834a7b
         | 
| 7 | 
            +
              data.tar.gz: 96eb9e448ffd6c20b469e1b0d0f11e7f8dc274e809c4cc543dea3aa7ff5b5a5121a1aae6de7522cb3af1b3ff59e8e655df7af68ed54322f96844c5df910b4904
         | 
    
        data/bin/rsh
    CHANGED
    
    | @@ -8,7 +8,7 @@ | |
| 8 8 | 
             
            # Web_site:   http://isene.com/
         | 
| 9 9 | 
             
            # Github:     https://github.com/isene/rsh
         | 
| 10 10 | 
             
            # License:    Public domain
         | 
| 11 | 
            -
            @version    = "3. | 
| 11 | 
            +
            @version    = "3.5.0" # Polish release: Nick/history export, default nicks, expanded completions, startup tips, validation templates
         | 
| 12 12 |  | 
| 13 13 | 
             
            # MODULES, CLASSES AND EXTENSIONS
         | 
| 14 14 | 
             
            class String # Add coloring to strings (with escaping for Readline)
         | 
| @@ -137,8 +137,18 @@ begin # Initialization | |
| 137 137 | 
             
                "cargo" => %w[build run test check clean doc new init add search publish install update],
         | 
| 138 138 | 
             
                "npm" => %w[install uninstall update run build test start init publish],
         | 
| 139 139 | 
             
                "gem" => %w[install uninstall update list search build push],
         | 
| 140 | 
            -
                "bundle" => %w[install update exec check config]
         | 
| 140 | 
            +
                "bundle" => %w[install update exec check config],
         | 
| 141 | 
            +
                "kubectl" => %w[get describe create delete apply edit logs exec port-forward scale rollout top explain diff patch],
         | 
| 142 | 
            +
                "terraform" => %w[init plan apply destroy import output show],
         | 
| 143 | 
            +
                "aws" => %w[s3 ec2 lambda cloudformation iam rds dynamodb sns sqs],
         | 
| 144 | 
            +
                "brew" => %w[install uninstall update upgrade search info list],
         | 
| 145 | 
            +
                "yarn" => %w[add remove install build test start init],
         | 
| 146 | 
            +
                "make" => %w[clean install build test all],
         | 
| 147 | 
            +
                "ansible" => %w[playbook galaxy vault inventory],
         | 
| 148 | 
            +
                "poetry" => %w[add remove install update build publish],
         | 
| 149 | 
            +
                "pipenv" => %w[install uninstall update shell run]
         | 
| 141 150 | 
             
              }
         | 
| 151 | 
            +
              @show_tips = true                           # Show startup tips (configurable)
         | 
| 142 152 | 
             
              # New v3.0 features initialization
         | 
| 143 153 | 
             
              @switch_cache = {}                      # Cache for command switches from --help
         | 
| 144 154 | 
             
              @switch_cache_time = {}                 # Timestamp for cache expiry
         | 
| @@ -277,7 +287,9 @@ def firstrun | |
| 277 287 | 
             
              @completion_show_descriptions = false # Show help text inline
         | 
| 278 288 | 
             
              @completion_fuzzy = true            # Enable fuzzy matching
         | 
| 279 289 |  | 
| 280 | 
            -
              @nick = { | 
| 290 | 
            +
              @nick = {
         | 
| 291 | 
            +
                "ls" => "ls --color -F"
         | 
| 292 | 
            +
              }
         | 
| 281 293 | 
             
            RSHRC
         | 
| 282 294 | 
             
              File.write(Dir.home+'/.rshrc', rc)
         | 
| 283 295 | 
             
            end
         | 
| @@ -1063,11 +1075,25 @@ def suggest_command(cmd) # Smart command suggestions for typos | |
| 1063 1075 | 
             
              return nil if cmd.nil? || cmd.empty?
         | 
| 1064 1076 | 
             
              return nil if @exe.include?(cmd) || @nick.include?(cmd)
         | 
| 1065 1077 |  | 
| 1078 | 
            +
              max_dist = [cmd.length / 3, 2].max
         | 
| 1079 | 
            +
             | 
| 1080 | 
            +
              # Pre-filter by length and first letter (huge optimization for large @exe)
         | 
| 1081 | 
            +
              length_range = (cmd.length - max_dist)..(cmd.length + max_dist)
         | 
| 1082 | 
            +
              first_letter = cmd[0]
         | 
| 1083 | 
            +
             | 
| 1084 | 
            +
              # Filter: similar length AND (same first letter OR within 1 char distance)
         | 
| 1085 | 
            +
              pool = (@exe + @nick.keys).select do |c|
         | 
| 1086 | 
            +
                c.length >= 2 &&
         | 
| 1087 | 
            +
                length_range.include?(c.length) &&
         | 
| 1088 | 
            +
                (c[0] == first_letter || (c[0].ord - first_letter.ord).abs <= 1)
         | 
| 1089 | 
            +
              end
         | 
| 1090 | 
            +
             | 
| 1091 | 
            +
              # Hard limit to prevent any hang
         | 
| 1092 | 
            +
              pool = pool.first(100)
         | 
| 1093 | 
            +
             | 
| 1066 1094 | 
             
              # Find commands with small edit distance
         | 
| 1067 | 
            -
              candidates =  | 
| 1068 | 
            -
                next false if c.length < 2
         | 
| 1095 | 
            +
              candidates = pool.select do |c|
         | 
| 1069 1096 | 
             
                dist = levenshtein_distance(cmd, c)
         | 
| 1070 | 
            -
                max_dist = [cmd.length / 3, 2].max
         | 
| 1071 1097 | 
             
                dist <= max_dist && dist > 0
         | 
| 1072 1098 | 
             
              end
         | 
| 1073 1099 |  | 
| @@ -1115,6 +1141,7 @@ def config(*args) # Configure rsh settings | |
| 1115 1141 | 
             
                puts "    auto_correct:       #{@auto_correct ? 'on' : 'off'}"
         | 
| 1116 1142 | 
             
                puts "    slow_command_threshold: #{@slow_command_threshold}s #{@slow_command_threshold > 0 ? '(enabled)' : '(disabled)'}"
         | 
| 1117 1143 | 
             
                puts "    completion_learning: #{@completion_learning ? 'on' : 'off'}"
         | 
| 1144 | 
            +
                puts "    show_tips:          #{@show_tips ? 'on' : 'off'}"
         | 
| 1118 1145 | 
             
                puts "    completion_limit:   #{@completion_limit}"
         | 
| 1119 1146 | 
             
                puts "    completion_fuzzy:   #{@completion_fuzzy}"
         | 
| 1120 1147 | 
             
                puts "    completion_case_sensitive: #{@completion_case_sensitive}"
         | 
| @@ -1155,9 +1182,13 @@ def config(*args) # Configure rsh settings | |
| 1155 1182 | 
             
                @completion_show_metadata = %w[on true yes 1].include?(value.to_s.downcase)
         | 
| 1156 1183 | 
             
                puts "Completion metadata display #{@completion_show_metadata ? 'enabled' : 'disabled'}"
         | 
| 1157 1184 | 
             
                rshrc
         | 
| 1185 | 
            +
              when 'show_tips'
         | 
| 1186 | 
            +
                @show_tips = %w[on true yes 1].include?(value.to_s.downcase)
         | 
| 1187 | 
            +
                puts "Startup tips #{@show_tips ? 'enabled' : 'disabled'}"
         | 
| 1188 | 
            +
                rshrc
         | 
| 1158 1189 | 
             
              else
         | 
| 1159 1190 | 
             
                puts "Unknown setting '#{setting}'"
         | 
| 1160 | 
            -
                puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning,  | 
| 1191 | 
            +
                puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning, show_tips, completion_limit"
         | 
| 1161 1192 | 
             
              end
         | 
| 1162 1193 | 
             
            end
         | 
| 1163 1194 | 
             
            def env(*args) # Environment variable management
         | 
| @@ -1588,15 +1619,38 @@ def help | |
| 1588 1619 | 
             
              end
         | 
| 1589 1620 | 
             
              puts
         | 
| 1590 1621 | 
             
            end
         | 
| 1591 | 
            -
            def info
         | 
| 1592 | 
            -
               | 
| 1622 | 
            +
            def info(*args)
         | 
| 1623 | 
            +
              option = args[0]
         | 
| 1624 | 
            +
             | 
| 1625 | 
            +
              if option == '--quick'
         | 
| 1626 | 
            +
                puts "\nrsh v#{@version} - Ruby SHell"
         | 
| 1627 | 
            +
                puts "Type :help for commands, :info for full intro"
         | 
| 1628 | 
            +
              elsif option == '--features'
         | 
| 1629 | 
            +
                puts "\nKey Features:"
         | 
| 1630 | 
            +
                puts "• Nicks (aliases) with {{parameters}}"
         | 
| 1631 | 
            +
                puts "• Completion learning (adapts to you)"
         | 
| 1632 | 
            +
                puts "• Command recording & replay"
         | 
| 1633 | 
            +
                puts "• Plugin system"
         | 
| 1634 | 
            +
                puts "• Stats & analytics"
         | 
| 1635 | 
            +
                puts "• 6 color themes"
         | 
| 1636 | 
            +
                puts "• AI integration"
         | 
| 1637 | 
            +
                puts "Type :help for details"
         | 
| 1638 | 
            +
              else
         | 
| 1639 | 
            +
                puts @info
         | 
| 1640 | 
            +
              end
         | 
| 1593 1641 | 
             
            end
         | 
| 1594 1642 | 
             
            def version
         | 
| 1595 1643 | 
             
              puts "rsh version = #{@version} (latest RubyGems version is #{Gem.latest_version_for("ruby-shell").version} - https://github.com/isene/rsh)"
         | 
| 1596 1644 | 
             
            end
         | 
| 1597 | 
            -
            def history # Show most recent history (up to 50 entries)
         | 
| 1598 | 
            -
               | 
| 1599 | 
            -
             | 
| 1645 | 
            +
            def history(*args) # Show most recent history (up to 50 entries)
         | 
| 1646 | 
            +
              if args[0] == '--export'
         | 
| 1647 | 
            +
                filename = args[1] || 'history.txt'
         | 
| 1648 | 
            +
                File.write(filename, @history.join("\n"))
         | 
| 1649 | 
            +
                puts "History exported to #{filename} (#{@history.length} commands)"
         | 
| 1650 | 
            +
              else
         | 
| 1651 | 
            +
                puts "History:"
         | 
| 1652 | 
            +
                @history.each_with_index {|h,i| puts i.to_s + "; " + h if i < 50}
         | 
| 1653 | 
            +
              end
         | 
| 1600 1654 | 
             
            end
         | 
| 1601 1655 | 
             
            def rmhistory # Delete history
         | 
| 1602 1656 | 
             
              @history = []
         | 
| @@ -1620,6 +1674,19 @@ def nick(nick_str = nil)  # Define a new nick like this: `:nick "ls = ls --color | |
| 1620 1674 | 
             
                  @nick.sort.each {|key, value| puts "  #{key.c(@c_nick)} = #{value}"}
         | 
| 1621 1675 | 
             
                end
         | 
| 1622 1676 | 
             
                puts
         | 
| 1677 | 
            +
              elsif nick_str =~ /^--export\s*(.*)/
         | 
| 1678 | 
            +
                filename = $1.strip.empty? ? 'nicks.json' : $1.strip
         | 
| 1679 | 
            +
                require 'json' unless defined?(JSON)
         | 
| 1680 | 
            +
                File.write(filename, JSON.pretty_generate(@nick))
         | 
| 1681 | 
            +
                puts "Nicks exported to #{filename}"
         | 
| 1682 | 
            +
              elsif nick_str =~ /^--import\s+(.*)/
         | 
| 1683 | 
            +
                filename = $1.strip
         | 
| 1684 | 
            +
                return puts "File '#{filename}' not found" unless File.exist?(filename)
         | 
| 1685 | 
            +
                require 'json' unless defined?(JSON)
         | 
| 1686 | 
            +
                imported = JSON.parse(File.read(filename))
         | 
| 1687 | 
            +
                imported.each { |k, v| @nick[k] = v }
         | 
| 1688 | 
            +
                puts "Imported #{imported.length} nicks"
         | 
| 1689 | 
            +
                rshrc
         | 
| 1623 1690 | 
             
              elsif nick_str.match(/^\s*-/)
         | 
| 1624 1691 | 
             
                source = nick_str.sub(/^\s*-/, '')
         | 
| 1625 1692 | 
             
                if @nick.delete(source)
         | 
| @@ -2515,24 +2582,46 @@ def validate_command(cmd) # Syntax validation before execution | |
| 2515 2582 | 
             
            end
         | 
| 2516 2583 | 
             
            def calc(*args) # Inline calculator using Ruby's Math library
         | 
| 2517 2584 | 
             
              if args.empty?
         | 
| 2518 | 
            -
                puts "Usage: calc <expression>"
         | 
| 2585 | 
            +
                puts "Usage: :calc <expression>"
         | 
| 2519 2586 | 
             
                puts "Examples:"
         | 
| 2520 | 
            -
                puts "  calc 2 + 2"
         | 
| 2521 | 
            -
                puts "  calc  | 
| 2522 | 
            -
                puts "  calc  | 
| 2587 | 
            +
                puts "  :calc 2 + 2"
         | 
| 2588 | 
            +
                puts "  :calc Math.sqrt(16)"
         | 
| 2589 | 
            +
                puts "  :calc Math::PI * 2"
         | 
| 2590 | 
            +
                puts "  :calc sin(PI/4)"
         | 
| 2591 | 
            +
                puts "Available: +, -, *, /, **, %, sqrt, sin, cos, tan, log, exp, abs, PI, E, etc."
         | 
| 2523 2592 | 
             
                return
         | 
| 2524 2593 | 
             
              end
         | 
| 2525 2594 |  | 
| 2526 2595 | 
             
              expression = args.join(' ')
         | 
| 2527 2596 |  | 
| 2597 | 
            +
              # Create sandbox with Math module for safer evaluation
         | 
| 2598 | 
            +
              sandbox = Object.new
         | 
| 2599 | 
            +
              sandbox.extend(Math)
         | 
| 2600 | 
            +
             | 
| 2528 2601 | 
             
              begin
         | 
| 2529 | 
            -
                 | 
| 2530 | 
            -
                result = eval(expression, binding, __FILE__, __LINE__)
         | 
| 2602 | 
            +
                result = sandbox.instance_eval(expression)
         | 
| 2531 2603 | 
             
                puts result
         | 
| 2604 | 
            +
              rescue ZeroDivisionError
         | 
| 2605 | 
            +
                puts "Error: Division by zero"
         | 
| 2606 | 
            +
              rescue NameError => e
         | 
| 2607 | 
            +
                # Extract the undefined name (sandbox format)
         | 
| 2608 | 
            +
                if e.message =~ /undefined method `(\w+)'/
         | 
| 2609 | 
            +
                  undefined = $1
         | 
| 2610 | 
            +
                  puts "Error: Unknown function '#{undefined}'"
         | 
| 2611 | 
            +
                  puts "Available Math functions: sqrt, sin, cos, tan, log, exp, abs, ceil, floor, round"
         | 
| 2612 | 
            +
                  puts "Constants: PI, E"
         | 
| 2613 | 
            +
                else
         | 
| 2614 | 
            +
                  puts "Error: #{e.message}"
         | 
| 2615 | 
            +
                end
         | 
| 2532 2616 | 
             
              rescue SyntaxError => e
         | 
| 2533 | 
            -
                puts " | 
| 2617 | 
            +
                puts "Error: Invalid expression syntax"
         | 
| 2618 | 
            +
                puts "Check parentheses, operators, and spacing"
         | 
| 2619 | 
            +
              rescue ArgumentError => e
         | 
| 2620 | 
            +
                puts "Error: Invalid argument - #{e.message}"
         | 
| 2621 | 
            +
              rescue TypeError => e
         | 
| 2622 | 
            +
                puts "Error: Type mismatch - #{e.message}"
         | 
| 2534 2623 | 
             
              rescue => e
         | 
| 2535 | 
            -
                puts "Error | 
| 2624 | 
            +
                puts "Error: #{e.message}"
         | 
| 2536 2625 | 
             
              end
         | 
| 2537 2626 | 
             
            end
         | 
| 2538 2627 | 
             
            def validate(rule_str = nil) # Custom validation rule management
         | 
| @@ -2542,6 +2631,7 @@ def validate(rule_str = nil) # Custom validation rule management | |
| 2542 2631 | 
             
                  puts "\nNo validation rules defined"
         | 
| 2543 2632 | 
             
                  puts "Usage: :validate pattern = action"
         | 
| 2544 2633 | 
             
                  puts "Actions: block, confirm, warn, log"
         | 
| 2634 | 
            +
                  puts "Or try: :validate --templates"
         | 
| 2545 2635 | 
             
                  return
         | 
| 2546 2636 | 
             
                end
         | 
| 2547 2637 | 
             
                puts "\n  Validation Rules:".c(@c_prompt).b
         | 
| @@ -2549,6 +2639,21 @@ def validate(rule_str = nil) # Custom validation rule management | |
| 2549 2639 | 
             
                  puts "  #{i+1}. #{rule[:pattern].inspect} → #{rule[:action]}"
         | 
| 2550 2640 | 
             
                end
         | 
| 2551 2641 | 
             
                puts
         | 
| 2642 | 
            +
              elsif rule_str == '--templates'
         | 
| 2643 | 
            +
                puts "\n  Common Validation Rule Templates:".c(@c_prompt).b
         | 
| 2644 | 
            +
                puts "  Safety:"
         | 
| 2645 | 
            +
                puts "    :validate rm -rf / = block"
         | 
| 2646 | 
            +
                puts "    :validate DROP TABLE = block"
         | 
| 2647 | 
            +
                puts "  Confirmation:"
         | 
| 2648 | 
            +
                puts "    :validate git push --force = confirm"
         | 
| 2649 | 
            +
                puts "    :validate npm publish = confirm"
         | 
| 2650 | 
            +
                puts "  Warnings:"
         | 
| 2651 | 
            +
                puts "    :validate sudo = warn"
         | 
| 2652 | 
            +
                puts "    :validate chmod 777 = warn"
         | 
| 2653 | 
            +
                puts "  Logging:"
         | 
| 2654 | 
            +
                puts "    :validate npm install = log"
         | 
| 2655 | 
            +
                puts "    :validate pip install = log"
         | 
| 2656 | 
            +
                puts
         | 
| 2552 2657 | 
             
              elsif rule_str =~ /^-(\d+)$/
         | 
| 2553 2658 | 
             
                # Delete rule by index
         | 
| 2554 2659 | 
             
                index = $1.to_i - 1
         | 
| @@ -3373,6 +3478,20 @@ loop do | |
| 3373 3478 | 
             
                unless @plugins_loaded
         | 
| 3374 3479 | 
             
                  load_plugins
         | 
| 3375 3480 | 
             
                  @plugins_loaded = true
         | 
| 3481 | 
            +
                  # Show startup tip (30% chance, if enabled)
         | 
| 3482 | 
            +
                  if @show_tips && rand < 0.3
         | 
| 3483 | 
            +
                    tips = [
         | 
| 3484 | 
            +
                      "Tip: Use :nick gp={{branch}} for parametrized aliases!",
         | 
| 3485 | 
            +
                      "Tip: Press Ctrl-G to edit commands in $EDITOR",
         | 
| 3486 | 
            +
                      "Tip: :stats --graph shows visual analytics",
         | 
| 3487 | 
            +
                      "Tip: :record your workflows and :replay them later",
         | 
| 3488 | 
            +
                      "Tip: :validate rm -rf / = block for safety rules",
         | 
| 3489 | 
            +
                      "Tip: :completion_stats shows what you use most",
         | 
| 3490 | 
            +
                      "Tip: Type :help for quick reference",
         | 
| 3491 | 
            +
                      "Tip: Disable tips with: :config show_tips off"
         | 
| 3492 | 
            +
                    ]
         | 
| 3493 | 
            +
                    puts tips.sample.c(244)
         | 
| 3494 | 
            +
                  end
         | 
| 3376 3495 | 
             
                end
         | 
| 3377 3496 | 
             
                # Build display prompt with plugin additions (don't modify @prompt)
         | 
| 3378 3497 | 
             
                plugin_prompts = call_plugin_hook(:on_prompt)
         | 
| @@ -3600,11 +3719,12 @@ loop do | |
| 3600 3719 | 
             
                        puts "Bookmark '#{@cmd}' points to non-existent directory: #{bm_dir}".c(196)
         | 
| 3601 3720 | 
             
                      end
         | 
| 3602 3721 | 
             
                    else
         | 
| 3603 | 
            -
                      puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
         | 
| 3604 3722 | 
             
                      if @cmd == "f" # fzf integration (https://github.com/junegunn/fzf)
         | 
| 3723 | 
            +
                        puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
         | 
| 3605 3724 | 
             
                        res = `fzf`.chomp
         | 
| 3606 3725 | 
             
                        Dir.chdir(File.dirname(res))
         | 
| 3607 3726 | 
             
                      elsif File.exist?(@cmd) and not File.executable?(@cmd) and not @cmd.include?(" ")
         | 
| 3727 | 
            +
                        puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
         | 
| 3608 3728 | 
             
                        # Only auto-open files if it's a single filename (no spaces = no command with args)
         | 
| 3609 3729 | 
             
                        if File.read(@cmd).force_encoding("UTF-8").valid_encoding?
         | 
| 3610 3730 | 
             
                          system("#{ENV['EDITOR']} #{@cmd}") # Try open with user's editor
         | 
| @@ -3622,6 +3742,9 @@ loop do | |
| 3622 3742 | 
             
                          # Apply auto-correct if enabled (before validation)
         | 
| 3623 3743 | 
             
                          @cmd = apply_auto_correct(@cmd)
         | 
| 3624 3744 |  | 
| 3745 | 
            +
                          # Print timestamp AFTER auto-correct (shows what actually executes)
         | 
| 3746 | 
            +
                          puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
         | 
| 3747 | 
            +
             | 
| 3625 3748 | 
             
                          # Validate command after auto-correction
         | 
| 3626 3749 | 
             
                          warnings = validate_command(@cmd)
         | 
| 3627 3750 | 
             
                          if warnings && !warnings.empty?
         | 
    
        metadata
    CHANGED
    
    | @@ -1,19 +1,20 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ruby-shell
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3. | 
| 4 | 
            +
              version: 3.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Geir Isene
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2025-10- | 
| 11 | 
            +
            date: 2025-10-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies: []
         | 
| 13 13 | 
             
            description: 'A shell written in Ruby with extensive tab completions, aliases/nicks,
         | 
| 14 14 | 
             
              history, syntax highlighting, theming, auto-cd, auto-opening files and more. UPDATE
         | 
| 15 | 
            -
              v3. | 
| 16 | 
            -
               | 
| 15 | 
            +
              v3.5.0: Nick/history export, 9 new tool completions (kubectl, terraform, aws, brew,
         | 
| 16 | 
            +
              etc.), validation templates, startup tips, improved :info, aggressive suggest_command
         | 
| 17 | 
            +
              optimization for huge PATHs (18K+ executables), timestamp shows corrected commands!'
         | 
| 17 18 | 
             
            email: g@isene.com
         | 
| 18 19 | 
             
            executables:
         | 
| 19 20 | 
             
            - rsh
         |