ngpt 3.8.1__py3-none-any.whl → 3.8.2__py3-none-any.whl
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.
- ngpt/cli/modes/shell.py +332 -51
- ngpt/cli/ui.py +33 -4
- {ngpt-3.8.1.dist-info → ngpt-3.8.2.dist-info}/METADATA +143 -1
- {ngpt-3.8.1.dist-info → ngpt-3.8.2.dist-info}/RECORD +7 -7
- {ngpt-3.8.1.dist-info → ngpt-3.8.2.dist-info}/WHEEL +0 -0
- {ngpt-3.8.1.dist-info → ngpt-3.8.2.dist-info}/entry_points.txt +0 -0
- {ngpt-3.8.1.dist-info → ngpt-3.8.2.dist-info}/licenses/LICENSE +0 -0
ngpt/cli/modes/shell.py
CHANGED
@@ -14,6 +14,9 @@ import time
|
|
14
14
|
# System prompt for shell command generation
|
15
15
|
SHELL_SYSTEM_PROMPT = """Your role: Provide only plain text without Markdown formatting. Do not show any warnings or information regarding your capabilities. Do not provide any description. If you need to store any data, assume it will be stored in the chat. Provide only {shell_name} command for {operating_system} without any description. If there is a lack of details, provide most logical solution. Ensure the output is a valid shell command. If multiple steps required try to combine them together.
|
16
16
|
|
17
|
+
*** SHELL TYPE: {shell_name} ***
|
18
|
+
*** OS: {operating_system} ***
|
19
|
+
|
17
20
|
Command:"""
|
18
21
|
|
19
22
|
# System prompt to use when preprompt is provided
|
@@ -34,16 +37,18 @@ If the preprompt contradicts ANY OTHER instruction in this prompt,
|
|
34
37
|
including the {operating_system}/{shell_name} specification below,
|
35
38
|
YOU MUST FOLLOW THE PREPROMPT INSTRUCTION INSTEAD. NO EXCEPTIONS.
|
36
39
|
|
40
|
+
*** SHELL TYPE: {shell_name} ***
|
41
|
+
*** OS: {operating_system} ***
|
42
|
+
|
37
43
|
Your role: Provide only plain text without Markdown formatting. Do not show any warnings or information regarding your capabilities. Do not provide any description. If you need to store any data, assume it will be stored in the chat. Provide only {shell_name} command for {operating_system} without any description. If there is a lack of details, provide most logical solution. Ensure the output is a valid shell command. If multiple steps required try to combine them together.
|
38
44
|
|
39
45
|
Command:"""
|
40
46
|
|
41
|
-
def
|
42
|
-
"""Detect the current
|
47
|
+
def detect_os():
|
48
|
+
"""Detect the current operating system with detailed information.
|
43
49
|
|
44
50
|
Returns:
|
45
|
-
tuple: (
|
46
|
-
appropriate syntax highlighting language, and operating system
|
51
|
+
tuple: (os_type, operating_system) - the basic OS type and detailed OS description
|
47
52
|
"""
|
48
53
|
os_type = platform.system()
|
49
54
|
|
@@ -73,60 +78,322 @@ def detect_shell():
|
|
73
78
|
except:
|
74
79
|
pass
|
75
80
|
|
76
|
-
|
81
|
+
return os_type, operating_system, is_wsl
|
82
|
+
|
83
|
+
|
84
|
+
def detect_gitbash_shell(operating_system):
|
85
|
+
"""Detect if we're running in a Git Bash / MINGW environment.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
operating_system: The detected operating system string
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
tuple or None: (shell_name, highlight_language, operating_system) if Git Bash detected,
|
92
|
+
None otherwise
|
93
|
+
"""
|
94
|
+
# Check for Git Bash / MINGW environments
|
95
|
+
if any(env_var in os.environ for env_var in ["MSYSTEM", "MINGW_PREFIX"]):
|
96
|
+
# We're definitely in a MINGW environment (Git Bash)
|
97
|
+
return "bash", "bash", operating_system
|
98
|
+
|
99
|
+
if "MSYSTEM" in os.environ and any(msys_type in os.environ.get("MSYSTEM", "")
|
100
|
+
for msys_type in ["MINGW", "MSYS"]):
|
101
|
+
return "bash", "bash", operating_system
|
102
|
+
|
103
|
+
# Check command PATH for mingw
|
104
|
+
if os.environ.get("PATH") and any(
|
105
|
+
mingw_pattern in path.lower()
|
106
|
+
for mingw_pattern in ["/mingw/", "\\mingw\\", "/usr/bin", "\\usr\\bin"]
|
107
|
+
for path in os.environ.get("PATH", "").split(os.pathsep)
|
108
|
+
):
|
109
|
+
return "bash", "bash", operating_system
|
110
|
+
|
111
|
+
return None
|
112
|
+
|
113
|
+
|
114
|
+
def detect_unix_shell(operating_system):
|
115
|
+
"""Detect shell type on Unix-like systems (Linux, macOS, BSD).
|
116
|
+
|
117
|
+
Args:
|
118
|
+
operating_system: The detected operating system string
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
tuple: (shell_name, highlight_language, operating_system) - the detected shell information
|
122
|
+
"""
|
123
|
+
# Try multiple methods to detect the shell
|
124
|
+
|
125
|
+
# Method 1: Check shell-specific environment variables
|
126
|
+
# These are very reliable indicators of the actual shell
|
127
|
+
if "BASH_VERSION" in os.environ:
|
128
|
+
return "bash", "bash", operating_system
|
129
|
+
|
130
|
+
if "ZSH_VERSION" in os.environ:
|
131
|
+
return "zsh", "zsh", operating_system
|
132
|
+
|
133
|
+
if "FISH_VERSION" in os.environ:
|
134
|
+
return "fish", "fish", operating_system
|
135
|
+
|
136
|
+
# Method 2: Try to get shell from process information
|
77
137
|
try:
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
138
|
+
# Try to get parent process name using ps command
|
139
|
+
current_pid = os.getpid()
|
140
|
+
parent_pid = os.getppid()
|
141
|
+
|
142
|
+
# Method 2a: Try to get the parent process command line from /proc
|
143
|
+
try:
|
144
|
+
with open(f'/proc/{parent_pid}/cmdline', 'r') as f:
|
145
|
+
cmdline = f.read().split('\0')
|
146
|
+
if cmdline and cmdline[0]:
|
147
|
+
cmd = os.path.basename(cmdline[0])
|
148
|
+
if "zsh" in cmd:
|
149
|
+
return "zsh", "zsh", operating_system
|
150
|
+
elif "bash" in cmd:
|
151
|
+
return "bash", "bash", operating_system
|
152
|
+
elif "fish" in cmd:
|
153
|
+
return "fish", "fish", operating_system
|
154
|
+
except:
|
155
|
+
pass
|
156
|
+
|
157
|
+
# Method 2b: Try using ps command with different formats
|
158
|
+
for fmt in ["comm=", "command=", "args="]:
|
159
|
+
try:
|
160
|
+
ps_cmd = ["ps", "-p", str(parent_pid), "-o", fmt]
|
161
|
+
result = subprocess.run(ps_cmd, capture_output=True, text=True)
|
162
|
+
process_info = result.stdout.strip()
|
83
163
|
|
84
|
-
|
85
|
-
|
86
|
-
|
164
|
+
if process_info:
|
165
|
+
if "zsh" in process_info.lower():
|
166
|
+
return "zsh", "zsh", operating_system
|
167
|
+
elif "bash" in process_info.lower():
|
168
|
+
return "bash", "bash", operating_system
|
169
|
+
elif "fish" in process_info.lower():
|
170
|
+
return "fish", "fish", operating_system
|
171
|
+
elif any(sh in process_info.lower() for sh in ["csh", "tcsh"]):
|
172
|
+
shell_name = "csh" if "csh" in process_info.lower() else "tcsh"
|
173
|
+
return shell_name, "csh", operating_system
|
174
|
+
elif "ksh" in process_info.lower():
|
175
|
+
return "ksh", "ksh", operating_system
|
176
|
+
except:
|
177
|
+
continue
|
178
|
+
|
179
|
+
# Method 2c: Try to find parent shell by traversing process hierarchy
|
180
|
+
# This handles Python wrappers, uv run, etc.
|
181
|
+
for _ in range(5): # Check up to 5 levels up the process tree
|
182
|
+
try:
|
183
|
+
# Try to get process command
|
184
|
+
ps_cmd = ["ps", "-p", str(parent_pid), "-o", "comm="]
|
185
|
+
result = subprocess.run(ps_cmd, capture_output=True, text=True)
|
186
|
+
process_name = result.stdout.strip()
|
187
|
+
|
188
|
+
# If it's a known shell, return it
|
189
|
+
if process_name:
|
190
|
+
process_basename = os.path.basename(process_name)
|
191
|
+
if "bash" in process_basename:
|
192
|
+
return "bash", "bash", operating_system
|
193
|
+
elif "zsh" in process_basename:
|
194
|
+
return "zsh", "zsh", operating_system
|
195
|
+
elif "fish" in process_basename:
|
196
|
+
return "fish", "fish", operating_system
|
197
|
+
elif any(sh in process_basename for sh in ["csh", "tcsh"]):
|
198
|
+
return process_basename, "csh", operating_system
|
199
|
+
elif "ksh" in process_basename:
|
200
|
+
return process_basename, "ksh", operating_system
|
87
201
|
|
88
|
-
|
89
|
-
|
202
|
+
# Check if we've reached init/systemd (PID 1)
|
203
|
+
if parent_pid <= 1:
|
204
|
+
break
|
205
|
+
|
206
|
+
# Move up to next parent
|
207
|
+
try:
|
208
|
+
# Get the parent of our current parent
|
209
|
+
with open(f'/proc/{parent_pid}/status', 'r') as f:
|
210
|
+
for line in f:
|
211
|
+
if line.startswith('PPid:'):
|
212
|
+
parent_pid = int(line.split()[1])
|
213
|
+
break
|
214
|
+
except:
|
215
|
+
break # Can't determine next parent, stop here
|
216
|
+
except:
|
217
|
+
break
|
218
|
+
except:
|
219
|
+
# Process detection failed, continue with other methods
|
220
|
+
pass
|
221
|
+
|
222
|
+
# Method 3: Try running a command that prints info about the parent shell
|
223
|
+
try:
|
224
|
+
# Get parent's process ID and use it to get more info
|
225
|
+
cmd = f"ps -p $PPID -o cmd="
|
226
|
+
result = subprocess.run(['bash', '-c', cmd], capture_output=True, text=True, timeout=1)
|
227
|
+
parent_cmd = result.stdout.strip()
|
228
|
+
|
229
|
+
if "zsh" in parent_cmd.lower():
|
230
|
+
return "zsh", "zsh", operating_system
|
231
|
+
elif "bash" in parent_cmd.lower():
|
232
|
+
return "bash", "bash", operating_system
|
233
|
+
elif "fish" in parent_cmd.lower():
|
234
|
+
return "fish", "fish", operating_system
|
235
|
+
except:
|
236
|
+
pass
|
237
|
+
|
238
|
+
# Method 4: Check for shell-specific environment variables beyond the basic ones
|
239
|
+
try:
|
240
|
+
for env_var in os.environ:
|
241
|
+
if env_var.startswith("BASH_"):
|
90
242
|
return "bash", "bash", operating_system
|
243
|
+
elif env_var.startswith("ZSH_"):
|
244
|
+
return "zsh", "zsh", operating_system
|
245
|
+
elif env_var.startswith("FISH_"):
|
246
|
+
return "fish", "fish", operating_system
|
247
|
+
except:
|
248
|
+
pass
|
249
|
+
|
250
|
+
# Method 5: Check SHELL environment variable
|
251
|
+
if os.environ.get("SHELL"):
|
252
|
+
shell_path = os.environ.get("SHELL")
|
253
|
+
shell_name = os.path.basename(shell_path)
|
254
|
+
|
255
|
+
# Match against known shell types - use exact matches first
|
256
|
+
if shell_name == "zsh":
|
257
|
+
return "zsh", "zsh", operating_system
|
258
|
+
elif shell_name == "bash":
|
259
|
+
return "bash", "bash", operating_system
|
260
|
+
elif shell_name == "fish":
|
261
|
+
return "fish", "fish", operating_system
|
262
|
+
elif shell_name in ["csh", "tcsh"]:
|
263
|
+
return shell_name, "csh", operating_system
|
264
|
+
elif shell_name == "ksh":
|
265
|
+
return shell_name, "ksh", operating_system
|
91
266
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
267
|
+
# If no exact match, try substring
|
268
|
+
if "zsh" in shell_name:
|
269
|
+
return "zsh", "zsh", operating_system
|
270
|
+
elif "bash" in shell_name:
|
271
|
+
return "bash", "bash", operating_system
|
272
|
+
elif "fish" in shell_name:
|
273
|
+
return "fish", "fish", operating_system
|
274
|
+
elif any(sh in shell_name for sh in ["csh", "tcsh"]):
|
275
|
+
return shell_name, "csh", operating_system
|
276
|
+
elif "ksh" in shell_name:
|
277
|
+
return shell_name, "ksh", operating_system
|
278
|
+
|
279
|
+
# Fallback: default to bash for Unix-like systems if all else fails
|
280
|
+
return "bash", "bash", operating_system
|
281
|
+
|
282
|
+
|
283
|
+
def detect_windows_shell(operating_system):
|
284
|
+
"""Detect shell type on Windows systems.
|
285
|
+
|
286
|
+
Args:
|
287
|
+
operating_system: The detected operating system string
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
tuple: (shell_name, highlight_language, operating_system) - the detected shell information
|
291
|
+
"""
|
292
|
+
# First check for the process name - most reliable indicator
|
293
|
+
try:
|
294
|
+
# Check parent process name for the most accurate detection
|
295
|
+
if os.name == 'nt':
|
296
|
+
import ctypes
|
297
|
+
from ctypes import wintypes
|
298
|
+
|
299
|
+
# Get parent process ID
|
300
|
+
GetCurrentProcessId = ctypes.windll.kernel32.GetCurrentProcessId
|
301
|
+
GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
|
302
|
+
GetProcessTimes = ctypes.windll.kernel32.GetProcessTimes
|
303
|
+
OpenProcess = ctypes.windll.kernel32.OpenProcess
|
304
|
+
GetModuleFileNameEx = ctypes.windll.psapi.GetModuleFileNameExW
|
305
|
+
QueryFullProcessImageName = ctypes.windll.kernel32.QueryFullProcessImageNameW
|
306
|
+
CloseHandle = ctypes.windll.kernel32.CloseHandle
|
307
|
+
|
308
|
+
# Try to get process path
|
309
|
+
try:
|
310
|
+
# First try to check current process executable name
|
311
|
+
process_path = sys.executable.lower()
|
312
|
+
if "powershell" in process_path:
|
313
|
+
if "pwsh" in process_path:
|
314
|
+
return "pwsh", "powershell", operating_system
|
315
|
+
else:
|
316
|
+
return "powershell.exe", "powershell", operating_system
|
317
|
+
elif "cmd.exe" in process_path:
|
102
318
|
return "cmd.exe", "batch", operating_system
|
103
|
-
|
104
|
-
|
319
|
+
except Exception as e:
|
320
|
+
pass
|
321
|
+
|
322
|
+
# If that fails, check environment variables that strongly indicate shell type
|
323
|
+
if "PROMPT" in os.environ and "$P$G" in os.environ.get("PROMPT", ""):
|
324
|
+
# CMD.exe uses $P$G as default prompt
|
325
|
+
return "cmd.exe", "batch", operating_system
|
326
|
+
|
105
327
|
if os.environ.get("PSModulePath"):
|
106
|
-
#
|
328
|
+
# PowerShell has this environment variable
|
107
329
|
if "pwsh" in os.environ.get("PSModulePath", "").lower():
|
108
330
|
return "pwsh", "powershell", operating_system
|
109
331
|
else:
|
110
332
|
return "powershell.exe", "powershell", operating_system
|
111
|
-
|
112
|
-
|
333
|
+
except Exception as e:
|
334
|
+
# If process detection fails, continue with environment checks
|
335
|
+
pass
|
336
|
+
|
337
|
+
# Check for WSL within Windows
|
338
|
+
if any(("wsl" in path.lower() or "microsoft" in path.lower()) for path in os.environ.get("PATH", "").split(os.pathsep)):
|
339
|
+
return "bash", "bash", operating_system
|
340
|
+
|
341
|
+
# Check for explicit shell path in environment
|
342
|
+
if os.environ.get("SHELL"):
|
343
|
+
shell_path = os.environ.get("SHELL").lower()
|
344
|
+
if "bash" in shell_path:
|
345
|
+
return "bash", "bash", operating_system
|
346
|
+
elif "zsh" in shell_path:
|
347
|
+
return "zsh", "zsh", operating_system
|
348
|
+
elif "powershell" in shell_path:
|
349
|
+
return "powershell.exe", "powershell", operating_system
|
350
|
+
elif "cmd" in shell_path:
|
351
|
+
return "cmd.exe", "batch", operating_system
|
352
|
+
|
353
|
+
# Final fallback - Check common environment variables that indicate shell type
|
354
|
+
if "ComSpec" in os.environ:
|
355
|
+
comspec = os.environ.get("ComSpec", "").lower()
|
356
|
+
if "powershell" in comspec:
|
357
|
+
return "powershell.exe", "powershell", operating_system
|
358
|
+
elif "cmd.exe" in comspec:
|
359
|
+
return "cmd.exe", "batch", operating_system
|
360
|
+
|
361
|
+
# Last resort fallback to PowerShell (most common modern Windows shell)
|
362
|
+
return "powershell.exe", "powershell", operating_system
|
363
|
+
|
364
|
+
|
365
|
+
def detect_shell():
|
366
|
+
"""Detect the current shell type and OS more accurately.
|
367
|
+
|
368
|
+
Returns:
|
369
|
+
tuple: (shell_name, highlight_language, operating_system) - the detected shell name,
|
370
|
+
appropriate syntax highlighting language, and operating system
|
371
|
+
"""
|
372
|
+
try:
|
373
|
+
# First detect the OS
|
374
|
+
os_type, operating_system, is_wsl = detect_os()
|
375
|
+
|
376
|
+
# Use the appropriate detection method based on OS
|
377
|
+
if os_type in ["Linux", "Darwin", "FreeBSD"] or is_wsl:
|
378
|
+
return detect_unix_shell(operating_system)
|
379
|
+
elif os_type == "Windows":
|
380
|
+
# On Windows, first check for Git Bash / MINGW environment
|
381
|
+
gitbash_result = detect_gitbash_shell(operating_system)
|
382
|
+
if gitbash_result:
|
383
|
+
return gitbash_result
|
384
|
+
|
385
|
+
# If not Git Bash, use regular Windows shell detection
|
386
|
+
return detect_windows_shell(operating_system)
|
113
387
|
else:
|
114
|
-
#
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# Map shell name to syntax highlight language
|
119
|
-
if shell_name == "zsh":
|
120
|
-
return shell_name, "zsh", operating_system
|
121
|
-
elif shell_name == "fish":
|
122
|
-
return shell_name, "fish", operating_system
|
123
|
-
elif "csh" in shell_name:
|
124
|
-
return shell_name, "csh", operating_system
|
388
|
+
# Fallback for unknown OS types
|
389
|
+
if os_type == "Windows":
|
390
|
+
return "powershell.exe", "powershell", operating_system
|
125
391
|
else:
|
126
|
-
|
127
|
-
return shell_name, "bash", operating_system
|
392
|
+
return "bash", "bash", operating_system
|
128
393
|
except Exception as e:
|
129
394
|
# Fall back to simple detection if anything fails
|
395
|
+
os_type = platform.system()
|
396
|
+
operating_system = os_type
|
130
397
|
if os_type == "Windows":
|
131
398
|
return "powershell.exe", "powershell", operating_system
|
132
399
|
else:
|
@@ -172,7 +439,7 @@ def setup_streaming(args, logger=None):
|
|
172
439
|
elif args.no_stream:
|
173
440
|
# Second priority: no-stream
|
174
441
|
should_stream = False
|
175
|
-
use_regular_prettify = False
|
442
|
+
use_regular_prettify = False # No prettify if no streaming
|
176
443
|
elif args.prettify:
|
177
444
|
# Third priority: prettify (requires disabling stream)
|
178
445
|
if has_markdown_renderer(args.renderer):
|
@@ -240,8 +507,8 @@ def setup_streaming(args, logger=None):
|
|
240
507
|
return (should_stream, use_stream_prettify, use_regular_prettify, stream_setup)
|
241
508
|
|
242
509
|
def generate_with_model(client, prompt, messages, args, stream_setup,
|
243
|
-
|
244
|
-
|
510
|
+
use_stream_prettify, should_stream, spinner_message="Generating...",
|
511
|
+
temp_override=None, logger=None):
|
245
512
|
"""Generate content using the model with proper streaming and spinner handling.
|
246
513
|
|
247
514
|
Args:
|
@@ -537,7 +804,7 @@ def shell_mode(client, args, logger=None):
|
|
537
804
|
# Add a small delay to ensure terminal rendering is complete,
|
538
805
|
# especially important for stream-prettify mode
|
539
806
|
if use_stream_prettify:
|
540
|
-
time.sleep(0.
|
807
|
+
time.sleep(0.5)
|
541
808
|
|
542
809
|
# Print prompt and flush to ensure it appears
|
543
810
|
sys.stdout.write(prompt_text)
|
@@ -550,9 +817,9 @@ def shell_mode(client, args, logger=None):
|
|
550
817
|
if response:
|
551
818
|
response = response.lower()
|
552
819
|
else:
|
553
|
-
# If get_terminal_input fails, default to
|
554
|
-
print("\nFailed to get terminal input. Defaulting to
|
555
|
-
response = '
|
820
|
+
# If get_terminal_input fails, default to abort
|
821
|
+
print("\nFailed to get terminal input. Defaulting to abort option.")
|
822
|
+
response = 'a'
|
556
823
|
except KeyboardInterrupt:
|
557
824
|
print("\nCommand execution cancelled by user.")
|
558
825
|
return
|
@@ -565,7 +832,21 @@ def shell_mode(client, args, logger=None):
|
|
565
832
|
try:
|
566
833
|
try:
|
567
834
|
print("\nExecuting command... (Press Ctrl+C to cancel)")
|
568
|
-
|
835
|
+
|
836
|
+
# Special handling for Windows PowerShell commands
|
837
|
+
if shell_name in ["powershell.exe", "pwsh"] and platform.system() == "Windows":
|
838
|
+
# Execute PowerShell commands properly on Windows
|
839
|
+
result = subprocess.run(
|
840
|
+
["powershell.exe", "-Command", command],
|
841
|
+
shell=True,
|
842
|
+
check=True,
|
843
|
+
capture_output=True,
|
844
|
+
text=True
|
845
|
+
)
|
846
|
+
else:
|
847
|
+
# Regular command execution for other shells
|
848
|
+
result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True)
|
849
|
+
|
569
850
|
output = result.stdout
|
570
851
|
|
571
852
|
# Log the command output if logging is enabled
|
ngpt/cli/ui.py
CHANGED
@@ -159,10 +159,39 @@ def get_terminal_input():
|
|
159
159
|
try:
|
160
160
|
import msvcrt
|
161
161
|
sys.stdout.flush()
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
162
|
+
|
163
|
+
# Wait for a complete line (including Enter key)
|
164
|
+
input_chars = []
|
165
|
+
while True:
|
166
|
+
# Get a character
|
167
|
+
char = msvcrt.getch()
|
168
|
+
|
169
|
+
# If it's Enter (CR or LF), break the loop
|
170
|
+
if char in [b'\r', b'\n']:
|
171
|
+
print() # Move to the next line after Enter
|
172
|
+
break
|
173
|
+
|
174
|
+
# If it's backspace, handle it
|
175
|
+
if char == b'\x08':
|
176
|
+
if input_chars:
|
177
|
+
# Remove the last character
|
178
|
+
input_chars.pop()
|
179
|
+
# Erase the character on screen (backspace + space + backspace)
|
180
|
+
sys.stdout.write('\b \b')
|
181
|
+
sys.stdout.flush()
|
182
|
+
continue
|
183
|
+
|
184
|
+
# For regular characters, add to input and echo
|
185
|
+
try:
|
186
|
+
char_decoded = char.decode('utf-8').lower()
|
187
|
+
input_chars.append(char_decoded)
|
188
|
+
print(char_decoded, end='', flush=True) # Echo the character without newline
|
189
|
+
except UnicodeDecodeError:
|
190
|
+
# Skip characters that can't be decoded
|
191
|
+
continue
|
192
|
+
|
193
|
+
# Join all characters and return
|
194
|
+
return ''.join(input_chars).strip().lower()
|
166
195
|
except ImportError:
|
167
196
|
# Fallback if msvcrt is not available
|
168
197
|
return None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ngpt
|
3
|
-
Version: 3.8.
|
3
|
+
Version: 3.8.2
|
4
4
|
Summary: Swiss army knife for LLMs: powerful CLI and interactive chatbot in one package. Seamlessly work with OpenAI, Ollama, Groq, Claude, Gemini, or any OpenAI-compatible API to generate code, craft git commits, rewrite text, and execute shell commands.
|
5
5
|
Project-URL: Homepage, https://github.com/nazdridoy/ngpt
|
6
6
|
Project-URL: Repository, https://github.com/nazdridoy/ngpt
|
@@ -493,6 +493,8 @@ In interactive mode:
|
|
493
493
|
- For security, your API key is not displayed when editing configurations
|
494
494
|
- When removing a configuration, you'll be asked to confirm before deletion
|
495
495
|
|
496
|
+

|
497
|
+
|
496
498
|
For more details on configuring nGPT, see the [Configuration Guide](https://nazdridoy.github.io/ngpt/configuration/).
|
497
499
|
|
498
500
|
### Configuration File
|
@@ -541,6 +543,146 @@ nGPT determines configuration values in the following order (highest priority fi
|
|
541
543
|
4. Main configuration file `ngpt.conf` or `custom-config-file`
|
542
544
|
5. Default values
|
543
545
|
|
546
|
+
### Real-World Demonstrations with nGPT
|
547
|
+
|
548
|
+
Let's see nGPT in action! Here are some practical ways you can use it every day:
|
549
|
+
|
550
|
+
#### Quick Q&A and Coding
|
551
|
+
|
552
|
+
```bash
|
553
|
+
# Get a quick explanation
|
554
|
+
ngpt "Explain the difference between threads and processes in Python"
|
555
|
+
|
556
|
+
# Generate code with real-time syntax highlighting
|
557
|
+
ngpt --code --stream-prettify "Write a Python function to reverse a linked list"
|
558
|
+
```
|
559
|
+
|
560
|
+
With the `--code` flag, nGPT gives you clean code without explanations or markdown, just what you need to copy and paste into your project. The `--stream-prettify` option shows real-time syntax highlighting as the code comes in.
|
561
|
+
|
562
|
+
#### Shell Command Generation (OS-Aware)
|
563
|
+
|
564
|
+
```bash
|
565
|
+
# Let nGPT generate the correct command for your OS
|
566
|
+
ngpt --shell "list all files in the current directory including hidden ones"
|
567
|
+
# On Linux/macOS: ls -la
|
568
|
+
# On Windows: dir /a
|
569
|
+
```
|
570
|
+
|
571
|
+
One of my favorite features! No more Googling obscure command flags, nGPT generates the right command for your operating system. It'll even execute it for you if you approve.
|
572
|
+
|
573
|
+

|
574
|
+
|
575
|
+
#### Text Rewriting and Summarization
|
576
|
+
|
577
|
+
```bash
|
578
|
+
# Pipe text to rewrite it (e.g., improve clarity)
|
579
|
+
echo "This is a rough draft of my email." | ngpt -r
|
580
|
+
|
581
|
+
# Summarize a file using the pipe placeholder
|
582
|
+
cat long-article.txt | ngpt --pipe "Summarize this document concisely: {}"
|
583
|
+
```
|
584
|
+
|
585
|
+
The text rewriting feature is perfect for quickly improving documentation, emails, or reports. And with pipe placeholders, you can feed in content from files or other commands.
|
586
|
+
|
587
|
+
#### Git Commit Message Generation
|
588
|
+
|
589
|
+
```bash
|
590
|
+
# Stage your changes
|
591
|
+
git add .
|
592
|
+
|
593
|
+
# Let nGPT generate a conventional commit message based on the diff
|
594
|
+
ngpt -g
|
595
|
+
|
596
|
+
# Generate git commit message from a diff file
|
597
|
+
ngpt -g --diff changes.diff
|
598
|
+
```
|
599
|
+
|
600
|
+
This is a huge time-saver. nGPT analyzes your git diff and generates a properly formatted conventional commit message that actually describes what you changed. No more staring at the blank commit message prompt!
|
601
|
+
|
602
|
+

|
603
|
+
|
604
|
+
#### Web Search Integration
|
605
|
+
|
606
|
+
```bash
|
607
|
+
# Ask questions that require up-to-date information
|
608
|
+
ngpt --web-search "What's the latest news about AI regulation?"
|
609
|
+
```
|
610
|
+
|
611
|
+
The `--web-search` flag lets nGPT consult the web for recent information, making it useful for questions about current events or topics that might have changed since the AI's training data cutoff.
|
612
|
+
|
613
|
+

|
614
|
+
|
615
|
+
### Real-World Integration Examples
|
616
|
+
|
617
|
+
Let's look at how nGPT can fit into your everyday workflow with some practical examples:
|
618
|
+
|
619
|
+
#### Developer Workflow
|
620
|
+
|
621
|
+
As a developer, I use nGPT throughout my day:
|
622
|
+
|
623
|
+
**Morning code review**:
|
624
|
+
```bash
|
625
|
+
# Get explanations of complex code
|
626
|
+
git show | ngpt --pipe "Explain what this code change does and any potential issues: {}"
|
627
|
+
```
|
628
|
+
|
629
|
+
**Debugging help**:
|
630
|
+
```bash
|
631
|
+
# Help understand a cryptic error message
|
632
|
+
npm run build 2>&1 | grep Error | ngpt --pipe "What does this error mean and how can I fix it: {}"
|
633
|
+
```
|
634
|
+
|
635
|
+
**Documentation generation**:
|
636
|
+
```bash
|
637
|
+
# Generate JSDoc comments for functions
|
638
|
+
cat src/utils.js | ngpt --pipe "Write proper JSDoc comments for these functions: {}"
|
639
|
+
```
|
640
|
+
|
641
|
+
**Commit messages**:
|
642
|
+
```bash
|
643
|
+
# After finishing a feature
|
644
|
+
git add .
|
645
|
+
ngpt -g
|
646
|
+
```
|
647
|
+
|
648
|
+
#### Writer's Assistant
|
649
|
+
|
650
|
+
For content creators and writers:
|
651
|
+
|
652
|
+
**Overcoming writer's block**:
|
653
|
+
```bash
|
654
|
+
ngpt "Give me 5 different angles to approach an article about sustainable technology"
|
655
|
+
```
|
656
|
+
|
657
|
+
**Editing assistance**:
|
658
|
+
```bash
|
659
|
+
cat draft.md | ngpt -r
|
660
|
+
```
|
661
|
+
|
662
|
+
**Research summaries**:
|
663
|
+
```bash
|
664
|
+
curl -s https://example.com/research-paper.html | ngpt --pipe "Summarize the key findings from this research: {}"
|
665
|
+
```
|
666
|
+
|
667
|
+
#### System Administrator
|
668
|
+
|
669
|
+
For sysadmins and DevOps folks:
|
670
|
+
|
671
|
+
**Generating complex commands**:
|
672
|
+
```bash
|
673
|
+
ngpt -s "find all log files larger than 100MB that haven't been modified in the last 30 days"
|
674
|
+
```
|
675
|
+
|
676
|
+
*Creating configuration files**:
|
677
|
+
```bash
|
678
|
+
ngpt --code "Create a Docker Compose file for a Redis, PostgreSQL, and Node.js application"
|
679
|
+
```
|
680
|
+
|
681
|
+
**Troubleshooting systems**:
|
682
|
+
```bash
|
683
|
+
dmesg | tail -50 | ngpt --pipe "Explain what might be causing the issues based on these system logs: {}"
|
684
|
+
```
|
685
|
+
|
544
686
|
## Contributing
|
545
687
|
|
546
688
|
We welcome contributions to nGPT! Whether it's bug fixes, feature additions, or documentation improvements, your help is appreciated.
|
@@ -7,14 +7,14 @@ ngpt/cli/config_manager.py,sha256=NQQcWnjUppAAd0s0p9YAf8EyKS1ex5-0EB4DvKdB4dk,36
|
|
7
7
|
ngpt/cli/formatters.py,sha256=HBYGlx_7eoAKyzfy0Vq5L0yn8yVKjngqYBukMmXCcz0,9401
|
8
8
|
ngpt/cli/main.py,sha256=PVulo8Pm53-oQ2Pgc4G90YhwyPImt8j7HKmY38SJ7CM,28696
|
9
9
|
ngpt/cli/renderers.py,sha256=m71BeUXKynpKKGXFzwRSW1XngvyKiZ_xEsdujUbU0MA,16597
|
10
|
-
ngpt/cli/ui.py,sha256=
|
10
|
+
ngpt/cli/ui.py,sha256=4RFxIf51di5EsytVr7OoyCWF_d40KJ0Mbom0VWgPlCc,10870
|
11
11
|
ngpt/cli/modes/__init__.py,sha256=KP7VR6Xw9k1p5Jcu0F38RDxSFvFIzH3j1ThDLNwznUI,363
|
12
12
|
ngpt/cli/modes/chat.py,sha256=1mH3nTDwU52qQJRliNUAFSqJWyyiJ6j0T5uVso-VnxE,6828
|
13
13
|
ngpt/cli/modes/code.py,sha256=QBFgMRPKJhxkYCmumoSkNSF15XNRGUDum5yuK8aBnyM,12662
|
14
14
|
ngpt/cli/modes/gitcommsg.py,sha256=iTg3KlZwI0lGMcmUa62b0ashwLcxegdEEvT29PPtpBc,49595
|
15
15
|
ngpt/cli/modes/interactive.py,sha256=TtBrZUX45CVfKOPvkb1ya7dIQhXLILtn7ajmfM9ohso,17419
|
16
16
|
ngpt/cli/modes/rewrite.py,sha256=yPmJPPkMHNxrnV-eoM0j6lMNRhdSAMXmcw2s9xG6TIo,10918
|
17
|
-
ngpt/cli/modes/shell.py,sha256=
|
17
|
+
ngpt/cli/modes/shell.py,sha256=nXkUbLLNdXQrdsOqGXMwdfnr2y7MtqbmBkYlwZbI5JA,41415
|
18
18
|
ngpt/cli/modes/text.py,sha256=7t5WWXMFxGkBM5HMP4irbN9aQwxE2YgywjiVPep710k,6417
|
19
19
|
ngpt/utils/__init__.py,sha256=_92f8eGMMOtQQA3uwgSRVwUEl1EIRFjWPUjcfGgI-eI,1244
|
20
20
|
ngpt/utils/cli_config.py,sha256=Ug8cECBTIuzOwkBWidLTfs-OAdOsCMJ2bNa70pOADfw,11195
|
@@ -22,8 +22,8 @@ ngpt/utils/config.py,sha256=wsArA4osnh8fKqOvtsPqqBxAz3DpdjtaWUFaRtnUdyc,10452
|
|
22
22
|
ngpt/utils/log.py,sha256=f1jg2iFo35PAmsarH8FVL_62plq4VXH0Mu2QiP6RJGw,15934
|
23
23
|
ngpt/utils/pipe.py,sha256=qRHF-Ma7bbU0cOcb1Yhe4S-kBavivtnnvLA3EYS4FY4,2162
|
24
24
|
ngpt/utils/web_search.py,sha256=w5ke4KJMRxq7r5jtbUXvspja6XhjoPZloVkZ0IvBXIE,30731
|
25
|
-
ngpt-3.8.
|
26
|
-
ngpt-3.8.
|
27
|
-
ngpt-3.8.
|
28
|
-
ngpt-3.8.
|
29
|
-
ngpt-3.8.
|
25
|
+
ngpt-3.8.2.dist-info/METADATA,sha256=2LazTO2smhA2gBILZQ9vA0Xqqn2RByEIfclp999Y6KA,28919
|
26
|
+
ngpt-3.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
27
|
+
ngpt-3.8.2.dist-info/entry_points.txt,sha256=SqAAvLhMrsEpkIr4YFRdUeyuXQ9o0IBCeYgE6AVojoI,44
|
28
|
+
ngpt-3.8.2.dist-info/licenses/LICENSE,sha256=mQkpWoADxbHqE0HRefYLJdm7OpdrXBr3vNv5bZ8w72M,1065
|
29
|
+
ngpt-3.8.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|