5
5
import atexit
6
6
from datetime import datetime
7
7
import pandas as pd
8
+
8
9
# Configure logging
9
10
import sqlite3
10
11
from termcolor import colored
18
19
enter_spool_mode ,
19
20
)
20
21
from .helpers import (
21
- log_action ,
22
+ log_action ,
22
23
load_npc_from_file ,
23
- list_directory ,
24
- read_file ,
24
+ list_directory ,
25
+ read_file ,
25
26
ensure_npcshrc_exists ,
26
27
setup_npcsh_config ,
27
- execute_java ,
28
- execute_scala ,
29
- execute_r ,
30
- execute_sql ,
31
- execute_python ,
32
- BASH_COMMANDS ,
33
- TERMINAL_EDITORS ,
34
- open_terminal_editor ,
35
- get_npc_from_command ,
28
+ execute_java ,
29
+ execute_scala ,
30
+ execute_r ,
31
+ execute_sql ,
32
+ execute_python ,
33
+ BASH_COMMANDS ,
34
+ TERMINAL_EDITORS ,
35
+ open_terminal_editor ,
36
+ get_npc_from_command ,
36
37
is_valid_npc ,
37
- get_npc_path ,
38
- initialize_base_npcs_if_needed ,
38
+ get_npc_path ,
39
+ initialize_base_npcs_if_needed ,
39
40
is_npcsh_initialized ,
40
- set_npcsh_initialized ,
41
- get_valid_npcs
41
+ set_npcsh_initialized ,
42
+ get_valid_npcs ,
42
43
)
43
44
44
45
from .npc_compiler import NPCCompiler , NPC
45
46
from colorama import Fore , Back , Style
46
47
47
48
import shlex
48
49
import subprocess
50
+
51
+
49
52
def get_file_color (filepath ):
50
53
if os .path .isdir (filepath ):
51
54
return "blue" , ["bold" ]
52
55
elif os .access (filepath , os .X_OK ):
53
56
return "green" , []
54
- elif filepath .endswith ((' .zip' , ' .tar' , ' .gz' , ' .bz2' , ' .xz' , ' .7z' )):
57
+ elif filepath .endswith ((" .zip" , " .tar" , " .gz" , " .bz2" , " .xz" , " .7z" )):
55
58
return "red" , []
56
- elif filepath .endswith ((' .jpg' , ' .jpeg' , ' .png' , ' .gif' , ' .bmp' , ' .tiff' )):
59
+ elif filepath .endswith ((" .jpg" , " .jpeg" , " .png" , " .gif" , " .bmp" , " .tiff" )):
57
60
return "magenta" , []
58
- elif filepath .endswith ((' .py' , ' .pyw' )):
61
+ elif filepath .endswith ((" .py" , " .pyw" )):
59
62
return "yellow" , []
60
- elif filepath .endswith ((' .sh' , ' .bash' , ' .zsh' )):
63
+ elif filepath .endswith ((" .sh" , " .bash" , " .zsh" )):
61
64
return "green" , []
62
- elif filepath .endswith (('.c' , ' .cpp' , '.h' , ' .hpp' )):
65
+ elif filepath .endswith ((".c" , " .cpp" , ".h" , " .hpp" )):
63
66
return "cyan" , []
64
- elif filepath .endswith ((' .js' , ' .ts' , ' .jsx' , ' .tsx' )):
67
+ elif filepath .endswith ((" .js" , " .ts" , " .jsx" , " .tsx" )):
65
68
return "yellow" , []
66
- elif filepath .endswith ((' .html' , ' .css' , ' .scss' , ' .sass' )):
69
+ elif filepath .endswith ((" .html" , " .css" , " .scss" , " .sass" )):
67
70
return "magenta" , []
68
- elif filepath .endswith ((' .md' , ' .txt' , ' .log' )):
71
+ elif filepath .endswith ((" .md" , " .txt" , " .log" )):
69
72
return "white" , []
70
- elif filepath .startswith ('.' ):
73
+ elif filepath .startswith ("." ):
71
74
return "cyan" , []
72
75
else :
73
76
return "white" , []
77
+
78
+
74
79
def execute_command (command , command_history , db_path , npc_compiler , current_npc = None ):
75
80
subcommands = []
76
81
output = ""
@@ -80,15 +85,15 @@ def execute_command(command, command_history, db_path, npc_compiler, current_npc
80
85
81
86
if current_npc is None :
82
87
valid_npcs = get_valid_npcs (db_path )
83
-
88
+
84
89
npc_name = get_npc_from_command (command )
85
90
if npc_name is None :
86
91
npc_name = "base" # Default NPC
87
- #print(npc_name)
92
+ # print(npc_name)
88
93
npc_path = get_npc_path (npc_name , db_path )
89
- npc = load_npc_from_file (npc_path , db_conn )
94
+ npc = load_npc_from_file (npc_path , db_conn )
90
95
else :
91
- npc = current_npc
96
+ npc = current_npc
92
97
if command .startswith ("/" ):
93
98
command = command [1 :]
94
99
log_action ("Command Executed" , command )
@@ -98,10 +103,10 @@ def execute_command(command, command_history, db_path, npc_compiler, current_npc
98
103
args = command_parts [1 :]
99
104
if current_npc is None and command_name in valid_npcs :
100
105
npc_path = get_npc_path (command_name , db_path )
101
- npc = load_npc_from_file (npc_path , db_conn )
102
-
106
+ npc = load_npc_from_file (npc_path , db_conn )
107
+
103
108
if command_name == "compile" or command_name == "com" :
104
- try :
109
+ try :
105
110
compiled_script = npc_compiler .compile (npc )
106
111
output = f"Compiled NPC profile: { compiled_script } "
107
112
print (output )
@@ -119,12 +124,12 @@ def execute_command(command, command_history, db_path, npc_compiler, current_npc
119
124
# output = enter_observation_mode(command_history, npc=npc)
120
125
elif command_name == "cmd" or command_name == "command" :
121
126
output = execute_llm_command (command , command_history , npc = npc )
122
- elif command_name == "set" :
127
+ elif command_name == "set" :
123
128
parts = command .split ()
124
129
if len (parts ) == 3 and parts [1 ] in ["model" , "provider" , "db_path" ]:
125
- output = execute_set_command (parts [1 ], parts [2 ])
130
+ output = execute_set_command (parts [1 ], parts [2 ])
126
131
else :
127
- return "Invalid set command. Usage: /set [model|provider|db_path] 'value_in_quotes' "
132
+ return "Invalid set command. Usage: /set [model|provider|db_path] 'value_in_quotes' "
128
133
elif command_name == "sample" :
129
134
output = execute_llm_question (command , command_history , npc = npc )
130
135
elif command_name == "spool" or command_name == "sp" :
@@ -139,7 +144,7 @@ def execute_command(command, command_history, db_path, npc_compiler, current_npc
139
144
140
145
output = enter_spool_mode (command_history , inherit_last , npc = npc )
141
146
return output
142
-
147
+
143
148
else :
144
149
output = f"Unknown command: { command_name } "
145
150
@@ -151,73 +156,81 @@ def execute_command(command, command_history, db_path, npc_compiler, current_npc
151
156
language = command_parts [0 ].lower ()
152
157
code = " " .join (command_parts [1 :])
153
158
154
- if language == ' python' :
159
+ if language == " python" :
155
160
output = execute_python (code )
156
- elif language == 'r' :
161
+ elif language == "r" :
157
162
output = execute_r (code )
158
- elif language == ' sql' :
163
+ elif language == " sql" :
159
164
output = execute_sql (code )
160
- elif language == ' scala' :
165
+ elif language == " scala" :
161
166
output = execute_scala (code )
162
- elif language == ' java' :
167
+ elif language == " java" :
163
168
output = execute_java (code )
164
169
else :
165
170
output = check_llm_command (command , command_history , npc = npc )
166
171
else :
167
172
# Check if it's a bash command
168
- #print(command)
173
+ # print(command)
169
174
command_parts = shlex .split (command )
170
-
171
- if command_parts [0 ] == 'cd' :
175
+
176
+ if command_parts [0 ] == "cd" :
172
177
try :
173
178
if len (command_parts ) > 1 :
174
179
new_dir = os .path .expanduser (command_parts [1 ])
175
180
else :
176
- new_dir = os .path .expanduser ('~' )
181
+ new_dir = os .path .expanduser ("~" )
177
182
os .chdir (new_dir )
178
183
return f"Changed directory to { os .getcwd ()} "
179
184
except FileNotFoundError :
180
185
return f"Directory not found: { new_dir } "
181
186
except PermissionError :
182
187
return f"Permission denied: { new_dir } "
183
-
188
+
184
189
elif command_parts [0 ] in BASH_COMMANDS :
185
190
if command_parts [0 ] in TERMINAL_EDITORS :
186
191
return open_terminal_editor (command )
187
192
else :
188
193
try :
189
- result = subprocess .run (command_parts , capture_output = True , text = True )
194
+ result = subprocess .run (
195
+ command_parts , capture_output = True , text = True
196
+ )
190
197
output = result .stdout
191
198
if result .stderr :
192
199
output += colored (f"\n Error: { result .stderr } " , "red" )
193
-
200
+
194
201
# Color code the output
195
202
colored_output = ""
196
- for line in output .split (' \n ' ):
203
+ for line in output .split (" \n " ):
197
204
parts = line .split ()
198
205
if parts :
199
206
filepath = parts [- 1 ]
200
207
color , attrs = get_file_color (filepath )
201
208
colored_filepath = colored (filepath , color , attrs = attrs )
202
- colored_line = ' ' .join (parts [:- 1 ] + [colored_filepath ])
209
+ colored_line = " " .join (parts [:- 1 ] + [colored_filepath ])
203
210
colored_output += colored_line + "\n "
204
211
else :
205
212
colored_output += line + "\n "
206
-
213
+
207
214
output = colored_output .rstrip ()
208
-
215
+
209
216
if not output and result .returncode == 0 :
210
- output = colored (f"Command '{ command } ' executed successfully (no output)." , "green" )
217
+ output = colored (
218
+ f"Command '{ command } ' executed successfully (no output)." ,
219
+ "green" ,
220
+ )
211
221
except Exception as e :
212
222
output = colored (f"Error executing command: { e } " , "red" )
213
223
224
+ else :
225
+ output = check_llm_command (command , command_history , npc = npc )
226
+
214
227
# Add command to history
215
228
command_history .add (command , subcommands , output , location )
216
229
217
230
# Print the output
218
231
if output :
219
232
print (output )
220
-
233
+
221
234
return output
222
235
223
236
@@ -227,7 +240,7 @@ def setup_readline():
227
240
readline .read_history_file (history_file )
228
241
except FileNotFoundError :
229
242
pass
230
-
243
+
231
244
readline .set_history_length (1000 )
232
245
readline .parse_and_bind ("set editing-mode vi" )
233
246
readline .parse_and_bind ('"\e[A": history-search-backward' )
@@ -236,47 +249,52 @@ def setup_readline():
236
249
237
250
return history_file
238
251
252
+
239
253
def save_readline_history ():
240
254
readline .write_history_file (os .path .expanduser ("~/.npcsh_readline_history" ))
241
255
256
+
242
257
def orange (text ):
243
258
return f"\033 [38;2;255;165;0m{ text } { Style .RESET_ALL } "
244
259
260
+
245
261
def main ():
246
262
setup_npcsh_config ()
247
263
if "NPCSH_DB_PATH" in os .environ :
248
264
db_path = os .path .expanduser (os .environ ["NPCSH_DB_PATH" ])
249
265
else :
250
- db_path = os .path .expanduser (' ~/npcsh_history.db' )
251
-
266
+ db_path = os .path .expanduser (" ~/npcsh_history.db" )
267
+
252
268
command_history = CommandHistory (db_path )
253
-
269
+
254
270
os .makedirs ("./npc_profiles" , exist_ok = True )
255
271
npc_directory = os .path .expanduser ("./npc_profiles" )
256
272
npc_compiler = NPCCompiler (npc_directory )
257
-
273
+
258
274
if not is_npcsh_initialized ():
259
275
print ("Initializing NPCSH..." )
260
276
initialize_base_npcs_if_needed (db_path )
261
- print ("NPCSH initialization complete. Please restart your terminal or run 'source ~/.npcshrc' for the changes to take effect." )
277
+ print (
278
+ "NPCSH initialization complete. Please restart your terminal or run 'source ~/.npcshrc' for the changes to take effect."
279
+ )
262
280
history_file = setup_readline ()
263
281
atexit .register (readline .write_history_file , history_file )
264
282
atexit .register (command_history .close )
265
-
283
+
266
284
print ("Welcome to npcsh!" )
267
-
285
+
268
286
current_npc = None
269
287
while True :
270
288
try :
271
289
if current_npc :
272
290
prompt = f"{ colored (os .getcwd (), 'blue' )} :{ orange (current_npc .name )} > "
273
291
else :
274
292
prompt = f"{ colored (os .getcwd (), 'blue' )} :{ orange ('npcsh' )} > "
275
-
293
+
276
294
# After executing the command
277
- #print(f"{colored(os.getcwd(), 'blue')}$")
295
+ # print(f"{colored(os.getcwd(), 'blue')}$")
278
296
user_input = input (prompt ).strip ()
279
-
297
+
280
298
if user_input .lower () in ["exit" , "quit" ]:
281
299
if current_npc :
282
300
print (f"Exiting { current_npc .name } mode." )
@@ -293,10 +311,14 @@ def main():
293
311
npc_path = get_npc_path (command_name , db_path )
294
312
db_conn = sqlite3 .connect (db_path )
295
313
current_npc = load_npc_from_file (npc_path , db_conn )
296
- print (f"Entered { current_npc .name } mode. Type 'exit' to return to main shell." )
314
+ print (
315
+ f"Entered { current_npc .name } mode. Type 'exit' to return to main shell."
316
+ )
297
317
continue
298
-
299
- execute_command (user_input , command_history , db_path , npc_compiler , current_npc )
318
+
319
+ execute_command (
320
+ user_input , command_history , db_path , npc_compiler , current_npc
321
+ )
300
322
except (KeyboardInterrupt , EOFError ):
301
323
if current_npc :
302
324
print (f"\n Exiting { current_npc .name } mode." )
@@ -305,5 +327,6 @@ def main():
305
327
print ("\n Goodbye!" )
306
328
break
307
329
330
+
308
331
if __name__ == "__main__" :
309
- main ()
332
+ main ()
0 commit comments