npcsh 1.1.12__py3-none-any.whl → 1.1.14__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.
- npcsh/_state.py +700 -377
- npcsh/alicanto.py +54 -1153
- npcsh/completion.py +206 -0
- npcsh/config.py +163 -0
- npcsh/corca.py +35 -1462
- npcsh/execution.py +185 -0
- npcsh/guac.py +31 -1986
- npcsh/npc_team/jinxs/code/sh.jinx +11 -15
- npcsh/npc_team/jinxs/modes/alicanto.jinx +186 -80
- npcsh/npc_team/jinxs/modes/corca.jinx +243 -22
- npcsh/npc_team/jinxs/modes/guac.jinx +313 -42
- npcsh/npc_team/jinxs/modes/plonk.jinx +209 -48
- npcsh/npc_team/jinxs/modes/pti.jinx +167 -25
- npcsh/npc_team/jinxs/modes/spool.jinx +158 -37
- npcsh/npc_team/jinxs/modes/wander.jinx +179 -74
- npcsh/npc_team/jinxs/modes/yap.jinx +258 -21
- npcsh/npc_team/jinxs/utils/chat.jinx +39 -12
- npcsh/npc_team/jinxs/utils/cmd.jinx +44 -0
- npcsh/npc_team/jinxs/utils/search.jinx +3 -3
- npcsh/npc_team/jinxs/utils/usage.jinx +33 -0
- npcsh/npcsh.py +76 -20
- npcsh/parsing.py +118 -0
- npcsh/plonk.py +41 -329
- npcsh/pti.py +41 -201
- npcsh/spool.py +34 -239
- npcsh/ui.py +199 -0
- npcsh/wander.py +54 -542
- npcsh/yap.py +38 -570
- npcsh-1.1.14.data/data/npcsh/npc_team/alicanto.jinx +194 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/chat.jinx +44 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/cmd.jinx +44 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/corca.jinx +249 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/guac.jinx +317 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/plonk.jinx +214 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/pti.jinx +170 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/search.jinx +3 -3
- npcsh-1.1.14.data/data/npcsh/npc_team/sh.jinx +34 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/spool.jinx +161 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/usage.jinx +33 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/wander.jinx +186 -0
- npcsh-1.1.14.data/data/npcsh/npc_team/yap.jinx +262 -0
- {npcsh-1.1.12.dist-info → npcsh-1.1.14.dist-info}/METADATA +1 -1
- npcsh-1.1.14.dist-info/RECORD +135 -0
- npcsh-1.1.12.data/data/npcsh/npc_team/alicanto.jinx +0 -88
- npcsh-1.1.12.data/data/npcsh/npc_team/chat.jinx +0 -17
- npcsh-1.1.12.data/data/npcsh/npc_team/corca.jinx +0 -28
- npcsh-1.1.12.data/data/npcsh/npc_team/guac.jinx +0 -46
- npcsh-1.1.12.data/data/npcsh/npc_team/plonk.jinx +0 -53
- npcsh-1.1.12.data/data/npcsh/npc_team/pti.jinx +0 -28
- npcsh-1.1.12.data/data/npcsh/npc_team/sh.jinx +0 -38
- npcsh-1.1.12.data/data/npcsh/npc_team/spool.jinx +0 -40
- npcsh-1.1.12.data/data/npcsh/npc_team/wander.jinx +0 -81
- npcsh-1.1.12.data/data/npcsh/npc_team/yap.jinx +0 -25
- npcsh-1.1.12.dist-info/RECORD +0 -126
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/agent.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/compress.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/jinxs.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/npc-studio.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
- {npcsh-1.1.12.data → npcsh-1.1.14.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.12.dist-info → npcsh-1.1.14.dist-info}/WHEEL +0 -0
- {npcsh-1.1.12.dist-info → npcsh-1.1.14.dist-info}/entry_points.txt +0 -0
- {npcsh-1.1.12.dist-info → npcsh-1.1.14.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.12.dist-info → npcsh-1.1.14.dist-info}/top_level.txt +0 -0
npcsh/execution.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command execution utilities for npcsh
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from typing import List, Tuple, Any, Optional
|
|
9
|
+
|
|
10
|
+
from termcolor import colored
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Commands that require interactive terminal handling
|
|
14
|
+
TERMINAL_EDITORS = ['vim', 'nvim', 'nano', 'vi', 'emacs', 'less', 'more', 'man']
|
|
15
|
+
|
|
16
|
+
# Interactive commands that need special handling (command -> args)
|
|
17
|
+
INTERACTIVE_COMMANDS = {
|
|
18
|
+
'ipython': ['ipython'],
|
|
19
|
+
'python': ['python', '-i'],
|
|
20
|
+
'python3': ['python3', '-i'],
|
|
21
|
+
'node': ['node'],
|
|
22
|
+
'irb': ['irb'],
|
|
23
|
+
'ghci': ['ghci'],
|
|
24
|
+
'mysql': ['mysql'],
|
|
25
|
+
'psql': ['psql'],
|
|
26
|
+
'sqlite3': ['sqlite3'],
|
|
27
|
+
'redis-cli': ['redis-cli'],
|
|
28
|
+
'mongo': ['mongo'],
|
|
29
|
+
'ssh': ['ssh'],
|
|
30
|
+
'telnet': ['telnet'],
|
|
31
|
+
'ftp': ['ftp'],
|
|
32
|
+
'sftp': ['sftp'],
|
|
33
|
+
'top': ['top'],
|
|
34
|
+
'htop': ['htop'],
|
|
35
|
+
'watch': ['watch'],
|
|
36
|
+
'r': ['R', '--interactive'],
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def validate_bash_command(command_parts: List[str]) -> bool:
|
|
41
|
+
"""
|
|
42
|
+
Check if the command is a valid bash command.
|
|
43
|
+
|
|
44
|
+
Returns True if the command exists in PATH or is a shell builtin.
|
|
45
|
+
"""
|
|
46
|
+
if not command_parts:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
cmd = command_parts[0]
|
|
50
|
+
|
|
51
|
+
# Check shell builtins
|
|
52
|
+
builtins = {'cd', 'pwd', 'echo', 'export', 'source', 'alias', 'unalias',
|
|
53
|
+
'history', 'set', 'unset', 'read', 'eval', 'exec', 'exit',
|
|
54
|
+
'return', 'shift', 'trap', 'wait', 'jobs', 'fg', 'bg',
|
|
55
|
+
'kill', 'ulimit', 'umask', 'type', 'hash', 'true', 'false'}
|
|
56
|
+
|
|
57
|
+
if cmd in builtins:
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
# Check if command exists in PATH
|
|
61
|
+
return shutil.which(cmd) is not None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def handle_bash_command(
|
|
65
|
+
cmd_parts: List[str],
|
|
66
|
+
full_cmd: str,
|
|
67
|
+
stdin_input: Optional[str],
|
|
68
|
+
state: Any
|
|
69
|
+
) -> Tuple[bool, str]:
|
|
70
|
+
"""
|
|
71
|
+
Execute a bash command and return the result.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
cmd_parts: Parsed command parts
|
|
75
|
+
full_cmd: Full command string
|
|
76
|
+
stdin_input: Input to pipe to command
|
|
77
|
+
state: Shell state
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Tuple of (success, output)
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
result = subprocess.run(
|
|
84
|
+
full_cmd,
|
|
85
|
+
shell=True,
|
|
86
|
+
capture_output=True,
|
|
87
|
+
text=True,
|
|
88
|
+
cwd=state.current_path,
|
|
89
|
+
input=stdin_input,
|
|
90
|
+
timeout=300
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
if result.returncode == 0:
|
|
94
|
+
output = result.stdout
|
|
95
|
+
if result.stderr:
|
|
96
|
+
output += f"\n{result.stderr}"
|
|
97
|
+
return True, output.strip()
|
|
98
|
+
else:
|
|
99
|
+
error = result.stderr or result.stdout or f"Command exited with code {result.returncode}"
|
|
100
|
+
return False, error.strip()
|
|
101
|
+
|
|
102
|
+
except subprocess.TimeoutExpired:
|
|
103
|
+
return False, "Command timed out after 5 minutes"
|
|
104
|
+
except Exception as e:
|
|
105
|
+
return False, str(e)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def open_terminal_editor(command: str) -> str:
|
|
109
|
+
"""Open a terminal editor command interactively"""
|
|
110
|
+
try:
|
|
111
|
+
subprocess.run(command, shell=True)
|
|
112
|
+
return "Editor session completed"
|
|
113
|
+
except Exception as e:
|
|
114
|
+
return f"Editor error: {e}"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def handle_cd_command(cmd_parts: List[str], state: Any) -> Tuple[Any, str]:
|
|
118
|
+
"""Handle the cd command"""
|
|
119
|
+
if len(cmd_parts) < 2:
|
|
120
|
+
new_path = os.path.expanduser("~")
|
|
121
|
+
else:
|
|
122
|
+
new_path = os.path.expanduser(cmd_parts[1])
|
|
123
|
+
|
|
124
|
+
if not os.path.isabs(new_path):
|
|
125
|
+
new_path = os.path.join(state.current_path, new_path)
|
|
126
|
+
|
|
127
|
+
new_path = os.path.normpath(new_path)
|
|
128
|
+
|
|
129
|
+
if os.path.isdir(new_path):
|
|
130
|
+
state.current_path = new_path
|
|
131
|
+
os.chdir(new_path)
|
|
132
|
+
return state, f"Changed to: {new_path}"
|
|
133
|
+
else:
|
|
134
|
+
return state, colored(f"Directory not found: {new_path}", "red")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def handle_interactive_command(cmd_parts: List[str], state: Any) -> Tuple[Any, str]:
|
|
138
|
+
"""Handle interactive commands by running them in a subprocess"""
|
|
139
|
+
command = ' '.join(cmd_parts)
|
|
140
|
+
try:
|
|
141
|
+
subprocess.run(command, shell=True, cwd=state.current_path)
|
|
142
|
+
return state, f"Interactive session ({cmd_parts[0]}) completed"
|
|
143
|
+
except KeyboardInterrupt:
|
|
144
|
+
return state, colored("Session interrupted", "yellow")
|
|
145
|
+
except Exception as e:
|
|
146
|
+
return state, colored(f"Error: {e}", "red")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def start_interactive_session(command: str) -> int:
|
|
150
|
+
"""Start an interactive shell session"""
|
|
151
|
+
try:
|
|
152
|
+
return subprocess.call(command, shell=True)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
print(colored(f"Error starting session: {e}", "red"))
|
|
155
|
+
return 1
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def list_directory(args: List[str]) -> None:
|
|
159
|
+
"""List directory contents with formatting"""
|
|
160
|
+
path = args[0] if args else "."
|
|
161
|
+
path = os.path.expanduser(path)
|
|
162
|
+
|
|
163
|
+
if not os.path.exists(path):
|
|
164
|
+
print(colored(f"Path not found: {path}", "red"))
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
if os.path.isfile(path):
|
|
168
|
+
print(path)
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
entries = os.listdir(path)
|
|
173
|
+
entries.sort()
|
|
174
|
+
|
|
175
|
+
for entry in entries:
|
|
176
|
+
full_path = os.path.join(path, entry)
|
|
177
|
+
if os.path.isdir(full_path):
|
|
178
|
+
print(colored(entry + "/", "blue", attrs=["bold"]))
|
|
179
|
+
elif os.access(full_path, os.X_OK):
|
|
180
|
+
print(colored(entry, "green", attrs=["bold"]))
|
|
181
|
+
else:
|
|
182
|
+
print(entry)
|
|
183
|
+
|
|
184
|
+
except PermissionError:
|
|
185
|
+
print(colored(f"Permission denied: {path}", "red"))
|