aicli 0.1.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 +7 -0
- data/CHANGELOG.md +151 -0
- data/LICENSE +22 -0
- data/README.md +176 -0
- data/bin/ai +6 -0
- data/bin/aicli +6 -0
- data/lib/aicli/cli.rb +104 -0
- data/lib/aicli/commands/chat.rb +60 -0
- data/lib/aicli/commands/config.rb +49 -0
- data/lib/aicli/commands/update.rb +21 -0
- data/lib/aicli/helpers/completion.rb +275 -0
- data/lib/aicli/helpers/config.rb +161 -0
- data/lib/aicli/helpers/constants.rb +11 -0
- data/lib/aicli/helpers/error.rb +28 -0
- data/lib/aicli/helpers/i18n.rb +70 -0
- data/lib/aicli/helpers/os_detect.rb +31 -0
- data/lib/aicli/helpers/shell_history.rb +48 -0
- data/lib/aicli/helpers/strip_regex_patterns.rb +21 -0
- data/lib/aicli/prompt.rb +192 -0
- data/lib/aicli/version.rb +5 -0
- data/lib/aicli.rb +19 -0
- data/locales/ar.yml +60 -0
- data/locales/de.yml +63 -0
- data/locales/en.yml +61 -0
- data/locales/es.yml +62 -0
- data/locales/fr.yml +62 -0
- data/locales/id.yml +62 -0
- data/locales/it.yml +60 -0
- data/locales/jp.yml +58 -0
- data/locales/ko.yml +58 -0
- data/locales/pt.yml +62 -0
- data/locales/ru.yml +62 -0
- data/locales/tr.yml +60 -0
- data/locales/uk.yml +61 -0
- data/locales/vi.yml +63 -0
- data/locales/zh-Hans.yml +58 -0
- data/locales/zh-Hant.yml +58 -0
- metadata +154 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 38ddbde1455388bed7ee62cff84c0aaa5cbc7329b0210fb88aacdf9fe39a0e13
|
|
4
|
+
data.tar.gz: 645ca62e82b191c88951293c8b04263428c7d5c3e4dfa7e6481db6ff59771a1c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a36e4429798ec0261b2d65b39d038e6276d7680ed87d042d8b8a20b5ede788b5ba5010303103d36c87f25b69ebdcd520ed651f4668110d0ad3d341fb6d0852bf
|
|
7
|
+
data.tar.gz: 68d9f6c8c3789eca4c5b9ff4e65e31d3598ab5f917985293dab89048c3651ba20ba7761fa46c06f04b06f247b0316adb785c0d0cb611955ae1db032a42f6a85c
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
## 1.0.12
|
|
2
|
+
|
|
3
|
+
- Bug fixes
|
|
4
|
+
- Default to gpt-4o-mini instead of gpt-3.5-turbo
|
|
5
|
+
|
|
6
|
+
## 1.0.8
|
|
7
|
+
|
|
8
|
+
- Fix a bug causing completions to not display in some cases
|
|
9
|
+
- Allow hitting "q" or "esc" to stop the streaming output
|
|
10
|
+
|
|
11
|
+
## 1.0.7
|
|
12
|
+
|
|
13
|
+
- Fix a bug causing completions to not display in some cases
|
|
14
|
+
|
|
15
|
+
## 1.0.6
|
|
16
|
+
|
|
17
|
+
- Fix for streaming data including the shell command name erroneously, causing the command to fail
|
|
18
|
+
|
|
19
|
+
## 1.0.5
|
|
20
|
+
|
|
21
|
+
- Fix using the configured model in all cases
|
|
22
|
+
|
|
23
|
+
## 1.0.4
|
|
24
|
+
|
|
25
|
+
- Improve `--help` menu descriptions
|
|
26
|
+
|
|
27
|
+
## 1.0.3
|
|
28
|
+
|
|
29
|
+
- Fix choosing custom models
|
|
30
|
+
|
|
31
|
+
## 1.0.2
|
|
32
|
+
|
|
33
|
+
- Add Turkish language support
|
|
34
|
+
- Improve config UX (correctly `await` on setting configs)
|
|
35
|
+
|
|
36
|
+
## 1.0.1
|
|
37
|
+
|
|
38
|
+
- Fix a typo ("to to" -> "to") [#78](https://github.com/BuilderIO/ai-shell/pull/78)
|
|
39
|
+
|
|
40
|
+
## 1.0.0
|
|
41
|
+
|
|
42
|
+
- Overdue major version bump to signify the stability of this CLI
|
|
43
|
+
- Add Indonesian language support
|
|
44
|
+
|
|
45
|
+
## 0.1.23
|
|
46
|
+
|
|
47
|
+
- Add support for Android [#75](https://github.com/BuilderIO/ai-shell/pull/75)
|
|
48
|
+
|
|
49
|
+
## 0.1.22
|
|
50
|
+
|
|
51
|
+
- Fix a crash on linux [#64](https://github.com/BuilderIO/ai-shell/issues/64)
|
|
52
|
+
|
|
53
|
+
## 0.1.21
|
|
54
|
+
|
|
55
|
+
- Fix a bug preventing initial configuration [#69](https://github.com/BuilderIO/ai-shell/issues/69)
|
|
56
|
+
|
|
57
|
+
## 0.1.20
|
|
58
|
+
|
|
59
|
+
- Multi language support [#62](https://github.com/BuilderIO/ai-shell/pull/62)
|
|
60
|
+
|
|
61
|
+
## 0.1.19
|
|
62
|
+
|
|
63
|
+
- Support Azure keys
|
|
64
|
+
|
|
65
|
+
## 0.1.18
|
|
66
|
+
|
|
67
|
+
- Option to copy the generated script to the clipboard
|
|
68
|
+
|
|
69
|
+
## 0.1.15
|
|
70
|
+
|
|
71
|
+
- Fix chat mode to support chat history
|
|
72
|
+
|
|
73
|
+
## 0.1.14
|
|
74
|
+
|
|
75
|
+
- Adds chat mode
|
|
76
|
+
- Fixes "ai update" to not eagerly capture
|
|
77
|
+
- Improve operating system identification
|
|
78
|
+
|
|
79
|
+
## 0.1.13
|
|
80
|
+
|
|
81
|
+
- Fix for using cloudflare proxy (fix streaming logic to handle partial chunks)
|
|
82
|
+
|
|
83
|
+
## 0.1.12
|
|
84
|
+
|
|
85
|
+
- Support custom API endpoints
|
|
86
|
+
|
|
87
|
+
## 0.1.11
|
|
88
|
+
|
|
89
|
+
- `ai update` command
|
|
90
|
+
- Minor UX improvements and fixes
|
|
91
|
+
|
|
92
|
+
## 0.1.10
|
|
93
|
+
|
|
94
|
+
- Obfuscate API key from config UI
|
|
95
|
+
|
|
96
|
+
## 0.1.9
|
|
97
|
+
|
|
98
|
+
- Visual config UI (from `ai config ui`)
|
|
99
|
+
|
|
100
|
+
## 0.1.8
|
|
101
|
+
|
|
102
|
+
- Better error handling (handle streams and non streams, JSON and strings)
|
|
103
|
+
|
|
104
|
+
## 0.1.7
|
|
105
|
+
|
|
106
|
+
- Option to edit script before running
|
|
107
|
+
- Fix error with String.prototype.replaceAll not existing
|
|
108
|
+
|
|
109
|
+
## 0.1.6
|
|
110
|
+
|
|
111
|
+
- Silent mode (skip explanation)
|
|
112
|
+
|
|
113
|
+
## 0.1.5
|
|
114
|
+
|
|
115
|
+
- Improve error messaging UX, again x3
|
|
116
|
+
|
|
117
|
+
## 0.1.4
|
|
118
|
+
|
|
119
|
+
- Improve error messaging, again again
|
|
120
|
+
|
|
121
|
+
## 0.1.3
|
|
122
|
+
|
|
123
|
+
- Improve error messaging, again
|
|
124
|
+
|
|
125
|
+
## 0.1.2
|
|
126
|
+
|
|
127
|
+
- Improve error messaging
|
|
128
|
+
|
|
129
|
+
## 0.1.1
|
|
130
|
+
|
|
131
|
+
- Minor UX improvement ("AI Shell" vs "ai-shell")
|
|
132
|
+
|
|
133
|
+
## 0.1.0
|
|
134
|
+
|
|
135
|
+
- Minor error message improvements
|
|
136
|
+
|
|
137
|
+
## 0.0.18
|
|
138
|
+
|
|
139
|
+
- Better error handling
|
|
140
|
+
|
|
141
|
+
## 0.0.17
|
|
142
|
+
|
|
143
|
+
- Minor improvements to the UX of the revision flow
|
|
144
|
+
|
|
145
|
+
## 0.0.16
|
|
146
|
+
|
|
147
|
+
- Take the current operating system into account
|
|
148
|
+
|
|
149
|
+
## 0.0.15
|
|
150
|
+
|
|
151
|
+
- Stream responses
|
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Antonio Molinari
|
|
4
|
+
Copyright (c) 2023 Builder.io (original Node.js implementation)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<h2 align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fb5b9997cec2c4fffb3e5c5e9bb4fed7d">
|
|
4
|
+
<img width="300" alt="aicli logo" src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fb7f9d2d9911a4199a9d26f8ba210b3f8">
|
|
5
|
+
</picture>
|
|
6
|
+
</h2>
|
|
7
|
+
|
|
8
|
+
<h4 align="center">
|
|
9
|
+
A CLI that converts natural language to shell commands.
|
|
10
|
+
</h4>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
Inspired by the <a href="https://githubnext.com/projects/copilot-cli">GitHub Copilot X CLI</a>, but open source for everyone.
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<br>
|
|
17
|
+
|
|
18
|
+
# aicli
|
|
19
|
+
|
|
20
|
+
Ruby port by [Antonio Molinari](https://github.com/magnum), inspired by the original [BuilderIO/ai-shell](https://github.com/BuilderIO/ai-shell) CLI.
|
|
21
|
+
|
|
22
|
+
## Setup
|
|
23
|
+
|
|
24
|
+
> Requires Ruby 3.0+
|
|
25
|
+
|
|
26
|
+
1. Install _aicli_:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
gem install aicli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or from this repository:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
bundle install
|
|
36
|
+
bundle exec rake install
|
|
37
|
+
# or
|
|
38
|
+
gem build aicli.gemspec && gem install ./aicli-*.gem
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
2. Retrieve your API key from [OpenAI](https://platform.openai.com/account/api-keys)
|
|
42
|
+
|
|
43
|
+
> Note: If you haven't already, you'll have to create an account and set up billing.
|
|
44
|
+
|
|
45
|
+
3. Set the key so aicli can use it:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
aicli config set OPENAI_KEY=<your token>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This will create a `.aicli` file in your home directory.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
aicli <prompt>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For example:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
aicli list all log files
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then you will get an output where you can choose to run the suggested command, revise it via a prompt, edit it, copy it, or cancel.
|
|
66
|
+
|
|
67
|
+
The short alias `ai` is also available.
|
|
68
|
+
|
|
69
|
+
### Special characters
|
|
70
|
+
|
|
71
|
+
Some shells handle characters like `?` or `*` specially. Wrap the prompt in quotes if needed:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
aicli 'what is my ip address'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Chat mode
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
aicli chat
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Engage in a conversation with the AI directly through the CLI.
|
|
84
|
+
|
|
85
|
+
### Silent mode (skip explanations)
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
aicli -s list all log files
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or save the preference:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
aicli config set SILENT_MODE=true
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Custom API endpoint
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
aicli config set OPENAI_API_ENDPOINT=<your proxy endpoint>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Default: `https://api.openai.com/v1`
|
|
104
|
+
|
|
105
|
+
### Set Language
|
|
106
|
+
|
|
107
|
+
| Language | Key |
|
|
108
|
+
| ------------------- | ------- |
|
|
109
|
+
| English | en |
|
|
110
|
+
| Simplified Chinese | zh-Hans |
|
|
111
|
+
| Traditional Chinese | zh-Hant |
|
|
112
|
+
| Spanish | es |
|
|
113
|
+
| Japanese | jp |
|
|
114
|
+
| Korean | ko |
|
|
115
|
+
| French | fr |
|
|
116
|
+
| German | de |
|
|
117
|
+
| Russian | ru |
|
|
118
|
+
| Ukrainian | uk |
|
|
119
|
+
| Vietnamese | vi |
|
|
120
|
+
| Arabic | ar |
|
|
121
|
+
| Portuguese | pt |
|
|
122
|
+
| Turkish | tr |
|
|
123
|
+
| Indonesian | id |
|
|
124
|
+
| Italian | it |
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
aicli config set LANGUAGE=zh-Hans
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Config UI
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
aicli config
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Upgrading
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
aicli --version
|
|
140
|
+
gem update aicli
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Or:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
aicli update
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
bundle install
|
|
153
|
+
bundle exec bin/aicli --help
|
|
154
|
+
bundle exec bin/aicli config set OPENAI_KEY=<your token>
|
|
155
|
+
bundle exec bin/aicli list all log files
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Common Issues
|
|
159
|
+
|
|
160
|
+
### 429 error
|
|
161
|
+
|
|
162
|
+
This is due to incorrect billing setup or excessive quota usage. Please follow [this guide](https://help.openai.com/en/articles/6891831-error-code-429-you-exceeded-your-current-quota-please-check-your-plan-and-billing-details) to fix it.
|
|
163
|
+
|
|
164
|
+
You can activate billing at [this link](https://platform.openai.com/account/billing/overview).
|
|
165
|
+
|
|
166
|
+
## Motivation
|
|
167
|
+
|
|
168
|
+
I am not a bash wizard, and am dying for access to the copilot CLI, and got impatient.
|
|
169
|
+
|
|
170
|
+
## Credit
|
|
171
|
+
|
|
172
|
+
- Ruby port by [Antonio Molinari](https://github.com/magnum)
|
|
173
|
+
- Inspired by [BuilderIO/ai-shell](https://github.com/BuilderIO/ai-shell)
|
|
174
|
+
- Thanks to GitHub Copilot for their amazing tools and the idea for this
|
|
175
|
+
- Thanks to Hassan and his work on [aicommits](https://github.com/Nutlope/aicommits), which inspired the workflow and some parts of the code and flows
|
|
176
|
+
- Original Node.js implementation by [Builder.io](https://www.builder.io)
|
data/bin/ai
ADDED
data/bin/aicli
ADDED
data/lib/aicli/cli.rb
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
require 'pastel'
|
|
5
|
+
|
|
6
|
+
module AiCli
|
|
7
|
+
class CLI < Thor
|
|
8
|
+
KNOWN_COMMANDS = %w[config chat update help version tree].freeze
|
|
9
|
+
|
|
10
|
+
def self.exit_on_failure?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.start(given_args = ARGV, config = {})
|
|
15
|
+
args = given_args.dup
|
|
16
|
+
|
|
17
|
+
# Extract global flags that may appear before the prompt text
|
|
18
|
+
silent = args.delete('--silent') || args.delete('-s')
|
|
19
|
+
version_flag = args.delete('--version') || args.delete('-v')
|
|
20
|
+
help_flag = args.delete('--help') || args.delete('-h')
|
|
21
|
+
|
|
22
|
+
if version_flag
|
|
23
|
+
puts AiCli::VERSION
|
|
24
|
+
return
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if help_flag && (args.empty? || !KNOWN_COMMANDS.include?(args.first))
|
|
28
|
+
new.help
|
|
29
|
+
return
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Prompt flag: -p / --prompt
|
|
33
|
+
prompt_from_flag = nil
|
|
34
|
+
if (idx = args.index('-p') || args.index('--prompt'))
|
|
35
|
+
prompt_from_flag = args[idx + 1]
|
|
36
|
+
args.slice!(idx, 2)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
first = args.first
|
|
40
|
+
|
|
41
|
+
if first.nil? || !KNOWN_COMMANDS.include?(first)
|
|
42
|
+
# Treat remaining args as the natural-language prompt
|
|
43
|
+
prompt_text = prompt_from_flag || args.join(' ')
|
|
44
|
+
invoke_prompt(prompt_text, silent: !silent.nil?)
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Rebuild argv for Thor subcommands, preserving silent if relevant
|
|
49
|
+
thor_args = args
|
|
50
|
+
thor_args = ['--silent'] + thor_args if silent && first == 'chat'
|
|
51
|
+
super(thor_args, config)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.invoke_prompt(prompt_text, silent: false)
|
|
55
|
+
pastel = Pastel.new
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
config = Helpers::Config.get
|
|
59
|
+
Helpers::I18n.set_language(config['LANGUAGE'])
|
|
60
|
+
rescue StandardError
|
|
61
|
+
Helpers::I18n.set_language('en')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Prompt.run(use_prompt: prompt_text, silent_mode: silent)
|
|
65
|
+
rescue Helpers::KnownError, StandardError => e
|
|
66
|
+
puts "\n#{pastel.red('✖')} #{e.message}"
|
|
67
|
+
Helpers::Error.handle_cli_error(e)
|
|
68
|
+
exit 1
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'config [MODE] [KEY=VALUE...]', 'Configure the CLI'
|
|
72
|
+
def config(mode = nil, *key_values)
|
|
73
|
+
init_i18n
|
|
74
|
+
Commands::Config.run(mode, *key_values)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
desc 'chat', 'Start a new chat session'
|
|
78
|
+
def chat
|
|
79
|
+
init_i18n
|
|
80
|
+
Commands::Chat.run
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
desc 'update', 'Update aicli to the latest version'
|
|
84
|
+
def update
|
|
85
|
+
init_i18n
|
|
86
|
+
Commands::Update.run
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
map %w[--version -v] => :__print_version
|
|
90
|
+
desc 'version', 'Print version'
|
|
91
|
+
def __print_version
|
|
92
|
+
puts AiCli::VERSION
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def init_i18n
|
|
98
|
+
config = Helpers::Config.get
|
|
99
|
+
Helpers::I18n.set_language(config['LANGUAGE'])
|
|
100
|
+
rescue StandardError
|
|
101
|
+
Helpers::I18n.set_language('en')
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pastel'
|
|
4
|
+
require 'tty-prompt'
|
|
5
|
+
require 'tty-spinner'
|
|
6
|
+
|
|
7
|
+
module AiCli
|
|
8
|
+
module Commands
|
|
9
|
+
module Chat
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
config = Helpers::Config.get
|
|
14
|
+
key = config['OPENAI_KEY']
|
|
15
|
+
model = config['MODEL']
|
|
16
|
+
api_endpoint = config['OPENAI_API_ENDPOINT']
|
|
17
|
+
chat_history = []
|
|
18
|
+
|
|
19
|
+
pastel = Pastel.new
|
|
20
|
+
prompt = TTY::Prompt.new(interrupt: :exit)
|
|
21
|
+
|
|
22
|
+
puts ''
|
|
23
|
+
puts "┌ #{Helpers::I18n.t('Starting new conversation')}"
|
|
24
|
+
|
|
25
|
+
loop do
|
|
26
|
+
user_prompt = prompt.ask(pastel.cyan("#{Helpers::I18n.t('You')}:")) do |q|
|
|
27
|
+
q.required true
|
|
28
|
+
q.validate(/.+/, Helpers::I18n.t('Please enter a prompt.'))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if user_prompt.nil? || user_prompt == 'exit'
|
|
32
|
+
puts "└ #{Helpers::I18n.t('Goodbye!')}"
|
|
33
|
+
exit 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
spinner = TTY::Spinner.new("[:spinner] #{Helpers::I18n.t('THINKING...')}", format: :dots)
|
|
37
|
+
spinner.auto_spin
|
|
38
|
+
|
|
39
|
+
chat_history << { 'role' => 'user', 'content' => user_prompt }
|
|
40
|
+
|
|
41
|
+
stream_lines = Helpers::Completion.generate_completion(
|
|
42
|
+
prompt: chat_history,
|
|
43
|
+
key: key,
|
|
44
|
+
model: model,
|
|
45
|
+
api_endpoint: api_endpoint
|
|
46
|
+
)
|
|
47
|
+
enumerator = stream_lines.each
|
|
48
|
+
read_response = Helpers::Completion.read_data(enumerator)
|
|
49
|
+
|
|
50
|
+
spinner.success(pastel.green('aicli:'))
|
|
51
|
+
puts ''
|
|
52
|
+
full_response = read_response.call(->(chunk) { print chunk })
|
|
53
|
+
chat_history << { 'role' => 'assistant', 'content' => full_response }
|
|
54
|
+
puts ''
|
|
55
|
+
puts ''
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pastel'
|
|
4
|
+
|
|
5
|
+
module AiCli
|
|
6
|
+
module Commands
|
|
7
|
+
module Config
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def run(mode = nil, *key_values)
|
|
11
|
+
pastel = Pastel.new
|
|
12
|
+
|
|
13
|
+
if mode.nil? || mode == 'ui'
|
|
14
|
+
Helpers::Config.show_config_ui
|
|
15
|
+
return
|
|
16
|
+
end
|
|
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
|
+
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
|
|
32
|
+
end
|
|
33
|
+
when 'set'
|
|
34
|
+
pairs = key_values.map do |kv|
|
|
35
|
+
k, v = kv.split('=', 2)
|
|
36
|
+
[k, v]
|
|
37
|
+
end
|
|
38
|
+
Helpers::Config.set(pairs)
|
|
39
|
+
else
|
|
40
|
+
raise Helpers::KnownError, "#{Helpers::I18n.t('Invalid mode')}: #{mode}"
|
|
41
|
+
end
|
|
42
|
+
rescue Helpers::KnownError, StandardError => e
|
|
43
|
+
puts "\n#{pastel.red('✖')} #{e.message}"
|
|
44
|
+
Helpers::Error.handle_cli_error(e)
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pastel'
|
|
4
|
+
|
|
5
|
+
module AiCli
|
|
6
|
+
module Commands
|
|
7
|
+
module Update
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
pastel = Pastel.new
|
|
12
|
+
puts ''
|
|
13
|
+
command = 'gem update aicli'
|
|
14
|
+
puts pastel.dim("#{Helpers::I18n.t('Running')}: #{command}")
|
|
15
|
+
puts ''
|
|
16
|
+
system(command)
|
|
17
|
+
puts ''
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|