aicli 0.3.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3502a13ce44daa62a15e1e9bfe0bb20d372bca46b782f35dae8be05dac9dba1f
4
- data.tar.gz: 7d4462f9b8bd94263aaf5da5ec87d35406f2b814842ad6217b0db0434ff027b1
3
+ metadata.gz: 8134338cc00872e289ea3980bc6367cb8c6231ba5c09879a80cc3ff5d8ebf32d
4
+ data.tar.gz: 4c53b4eb29d4f93cb2dba0709a7121219945a37aebf6edb45db288dba373002b
5
5
  SHA512:
6
- metadata.gz: 3f6c788b8aa265951ac9dd7ad859659c8c695f57c0760e68b4f2d8683bd11070c78c714836a077e8c9cc161790e77899f0fdc83823b4a2c9657725a6340d4536
7
- data.tar.gz: 0ac353b46b92efc2a4fc887e0732d767017c313bd54c0ff8dddfdf8300ffa2eba386c3c15843aa4bbfd99b0c5c17d94616cdf36c162e02838bf118711023ae62
6
+ metadata.gz: 0b89932ed8a62cce86bd1feb3e6da8e3026fe8448ae3a11a55bfdffa7180addee78cbfeeaad8ef19a556e865fb016c2277edfb31448bb6675606919cef528da4
7
+ data.tar.gz: ae512d71dfdd1c65fb2d5d18130180eb6d6f5d00673b030743e5cf3cc195e87e2db6856816601d9b617ad8e250e5ed3223b749b2032480ea08a2e30c32d2f64f
data/README.md CHANGED
@@ -46,6 +46,14 @@ The gem is named **aicli**; the shell command is **`ai`** (also available as `ai
46
46
 
47
47
  Config lives in `~/.aicli/config`. Chat/prompt history is stored in `~/.aicli/context` (last 40 messages) and reloaded on the next run.
48
48
 
49
+ 3. **Shell history** (optional): when you run a suggested command, store that command in your shell history instead of the original `ai ...` line (so ↑ recalls `for f in *.mp4; do ...` rather than `ai bash ...`):
50
+
51
+ ```sh
52
+ ai config shell
53
+ ```
54
+
55
+ Then add the printed `source` line to `~/.zshrc` or `~/.bashrc` and restart your shell (or `source` the file).
56
+
49
57
  ## Usage
50
58
 
51
59
  ```bash
@@ -112,7 +112,7 @@ module AiCli
112
112
  puts "#{Helpers::I18n.t('Running')}: #{command}"
113
113
  puts ''
114
114
  system(ENV['SHELL'] || 'bash', '-c', command)
115
- Helpers::ShellHistory.append(command)
115
+ Helpers::ShellHistory.record_executed(command)
116
116
  end
117
117
 
118
118
  private_class_method :offer_to_run_commands, :ask_to_run?, :run_command
@@ -15,27 +15,34 @@ module AiCli
15
15
  return
16
16
  end
17
17
 
18
- if key_values.empty?
19
- puts "#{Helpers::I18n.t('Error')}: #{Helpers::I18n.t('Missing required parameter')} \"key=value\"\n"
20
- exit 1
21
- end
22
-
23
18
  case mode
24
- when 'get'
25
- config = Helpers::Config.get
26
- key_values.each do |key|
27
- if Helpers::Config.has_own?(config, key)
28
- puts "#{key}=#{config[key]}"
29
- else
30
- raise Helpers::KnownError, "#{Helpers::I18n.t('Invalid config property')}: #{key}"
31
- end
19
+ when 'shell'
20
+ Helpers::ShellHistory.install_shell_integration!
21
+ puts pastel.green('✔') + ' ' + Helpers::I18n.t('Shell integration installed.')
22
+ hint = Helpers::ShellHistory.shell_integration_hint
23
+ puts hint unless hint.empty?
24
+ when 'get', 'set'
25
+ if key_values.empty?
26
+ puts "#{Helpers::I18n.t('Error')}: #{Helpers::I18n.t('Missing required parameter')} \"key=value\"\n"
27
+ exit 1
32
28
  end
33
- when 'set'
34
- pairs = key_values.map do |kv|
35
- k, v = kv.split('=', 2)
36
- [k, v]
29
+
30
+ if mode == 'get'
31
+ config = Helpers::Config.get
32
+ key_values.each do |key|
33
+ if Helpers::Config.has_own?(config, key)
34
+ puts "#{key}=#{config[key]}"
35
+ else
36
+ raise Helpers::KnownError, "#{Helpers::I18n.t('Invalid config property')}: #{key}"
37
+ end
38
+ end
39
+ else
40
+ pairs = key_values.map do |kv|
41
+ k, v = kv.split('=', 2)
42
+ [k, v]
43
+ end
44
+ Helpers::Config.set(pairs)
37
45
  end
38
- Helpers::Config.set(pairs)
39
46
  else
40
47
  raise Helpers::KnownError, "#{Helpers::I18n.t('Invalid mode')}: #{mode}"
41
48
  end
@@ -5,43 +5,114 @@ module AiCli
5
5
  module ShellHistory
6
6
  module_function
7
7
 
8
- def append(command)
9
- history_file = history_file_path
10
- return unless history_file
8
+ # Queue the executed command for the shell wrapper to store in history
9
+ # instead of the original `ai ...` invocation.
10
+ def record_executed(command)
11
+ text = command.to_s.strip
12
+ return if text.empty?
11
13
 
12
- last = last_command(history_file)
13
- return if last == command
14
-
15
- File.open(history_file, 'a') { |f| f.puts(command) }
14
+ Config.ensure_home!
15
+ File.write(pending_path, text)
16
16
  rescue StandardError
17
17
  # Ignore history write errors
18
18
  end
19
19
 
20
- def history_file_path
21
- shell = File.basename(ENV['SHELL'] || '')
22
- home = Dir.home
20
+ def install_shell_integration!
21
+ Config.ensure_home!
22
+ target_dir = Config.home_dir
23
+
24
+ {
25
+ 'ai.zsh' => zsh_wrapper,
26
+ 'ai.bash' => bash_wrapper
27
+ }.each do |name, contents|
28
+ File.write(File.join(target_dir, name), contents)
29
+ end
30
+ end
23
31
 
24
- case shell
25
- when 'bash', 'sh'
26
- File.join(home, '.bash_history')
32
+ def shell_integration_hint
33
+ home = Config.home_dir
34
+ case current_shell
27
35
  when 'zsh'
28
- File.join(home, '.zsh_history')
29
- when 'fish'
30
- File.join(home, '.local', 'share', 'fish', 'fish_history')
31
- when 'ksh'
32
- File.join(home, '.ksh_history')
33
- when 'tcsh'
34
- File.join(home, '.history')
36
+ <<~HINT.strip
37
+ Add to ~/.zshrc for shell history integration:
38
+
39
+ source #{home}/ai.zsh
40
+ HINT
41
+ when 'bash'
42
+ <<~HINT.strip
43
+ Add to ~/.bashrc for shell history integration:
44
+
45
+ source #{home}/ai.bash
46
+ HINT
47
+ else
48
+ ''
35
49
  end
36
50
  end
37
51
 
38
- def last_command(history_file)
39
- return nil unless File.exist?(history_file)
52
+ def pending_path
53
+ File.join(Config.home_dir, 'history.pending')
54
+ end
40
55
 
41
- lines = File.read(history_file).strip.split("\n")
42
- lines.last
43
- rescue StandardError
44
- nil
56
+ def current_shell
57
+ File.basename(ENV['SHELL'] || 'bash')
58
+ end
59
+
60
+ def zsh_wrapper
61
+ <<~'ZSH'
62
+ # aicli shell history integration for zsh
63
+ if [[ -z "$AICLI_SHELL_WRAPPER" ]]; then
64
+ _aicli_zshaddhistory() {
65
+ if [[ -n "$AICLI_PENDING_HISTORY" ]]; then
66
+ print -s -- "$AICLI_PENDING_HISTORY"
67
+ unset AICLI_PENDING_HISTORY
68
+ return 1
69
+ fi
70
+ }
71
+
72
+ ai() {
73
+ AICLI_SHELL_WRAPPER=1 command ai "$@"
74
+ local ret=$?
75
+ if [[ -f "$HOME/.aicli/history.pending" ]]; then
76
+ AICLI_PENDING_HISTORY=$(<"$HOME/.aicli/history.pending")
77
+ rm -f "$HOME/.aicli/history.pending"
78
+ fi
79
+ return $ret
80
+ }
81
+
82
+ zshaddhistory_functions+=(_aicli_zshaddhistory)
83
+ fi
84
+ ZSH
85
+ end
86
+
87
+ def bash_wrapper
88
+ <<~'BASH'
89
+ # aicli shell history integration for bash
90
+ if [[ -z "$AICLI_SHELL_WRAPPER" ]]; then
91
+ _aicli_bash_history() {
92
+ if [[ -n "$AICLI_PENDING_HISTORY" ]]; then
93
+ local cmd="$AICLI_PENDING_HISTORY"
94
+ unset AICLI_PENDING_HISTORY
95
+ history -d "$HISTCMD" 2>/dev/null
96
+ history -s "$cmd"
97
+ fi
98
+ }
99
+
100
+ ai() {
101
+ AICLI_SHELL_WRAPPER=1 command ai "$@"
102
+ local ret=$?
103
+ if [[ -f "$HOME/.aicli/history.pending" ]]; then
104
+ AICLI_PENDING_HISTORY=$(<"$HOME/.aicli/history.pending")
105
+ rm -f "$HOME/.aicli/history.pending"
106
+ fi
107
+ return $ret
108
+ }
109
+
110
+ if [[ -z "$AICLI_BASH_PROMPT_HOOK" ]]; then
111
+ AICLI_BASH_PROMPT_HOOK=1
112
+ PROMPT_COMMAND="_aicli_bash_history${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
113
+ fi
114
+ fi
115
+ BASH
45
116
  end
46
117
  end
47
118
  end
data/lib/aicli/prompt.rb CHANGED
@@ -118,7 +118,7 @@ module AiCli
118
118
  puts "#{Helpers::I18n.t('Running')}: #{script}"
119
119
  puts ''
120
120
  system(ENV['SHELL'] || 'bash', '-c', script)
121
- Helpers::ShellHistory.append(script)
121
+ Helpers::ShellHistory.record_executed(script)
122
122
  end
123
123
 
124
124
  def run_or_revise_flow(script, config, silent_mode)
data/lib/aicli/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AiCli
4
- VERSION = '0.3.0'
4
+ VERSION = '0.3.1'
5
5
  end
data/locales/en.yml CHANGED
@@ -69,3 +69,4 @@ You: You
69
69
  Ask for a shell command. Type exit to quit.: Ask for a shell command. Type exit to quit.
70
70
  Restored context: Restored context
71
71
  messages: messages
72
+ Shell integration installed.: Shell integration installed.
data/locales/it.yml CHANGED
@@ -68,3 +68,4 @@ You: Tu
68
68
  Ask for a shell command. Type exit to quit.: Chiedi un comando shell. Digita exit per uscire.
69
69
  Restored context: Contesto ripristinato
70
70
  messages: messaggi
71
+ Shell integration installed.: Integrazione shell installata.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aicli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Molinari