shellsage-mcp 0.3.0__tar.gz
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.
- shellsage_mcp-0.3.0/LICENSE +21 -0
- shellsage_mcp-0.3.0/PKG-INFO +605 -0
- shellsage_mcp-0.3.0/README.md +567 -0
- shellsage_mcp-0.3.0/pyproject.toml +87 -0
- shellsage_mcp-0.3.0/setup.cfg +4 -0
- shellsage_mcp-0.3.0/shellsage/__init__.py +7 -0
- shellsage_mcp-0.3.0/shellsage/__main__.py +3 -0
- shellsage_mcp-0.3.0/shellsage/cli.py +441 -0
- shellsage_mcp-0.3.0/shellsage/config.py +30 -0
- shellsage_mcp-0.3.0/shellsage/daemon.py +163 -0
- shellsage_mcp-0.3.0/shellsage/models.py +207 -0
- shellsage_mcp-0.3.0/shellsage/rules.py +717 -0
- shellsage_mcp-0.3.0/shellsage/seed.py +743 -0
- shellsage_mcp-0.3.0/shellsage/server.py +378 -0
- shellsage_mcp-0.3.0/shellsage/setup_wizard.py +486 -0
- shellsage_mcp-0.3.0/shellsage/store.py +376 -0
- shellsage_mcp-0.3.0/shellsage/translator.py +259 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/PKG-INFO +605 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/SOURCES.txt +24 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/dependency_links.txt +1 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/entry_points.txt +2 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/requires.txt +17 -0
- shellsage_mcp-0.3.0/shellsage_mcp.egg-info/top_level.txt +1 -0
- shellsage_mcp-0.3.0/tests/test_models.py +219 -0
- shellsage_mcp-0.3.0/tests/test_rules.py +450 -0
- shellsage_mcp-0.3.0/tests/test_seed.py +46 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ShellSage Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shellsage-mcp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Shell command translation layer for AI agent IDEs — no external services required.
|
|
5
|
+
Author: ShellSage Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/shellsage/shellsage
|
|
8
|
+
Project-URL: Issues, https://github.com/shellsage/shellsage/issues
|
|
9
|
+
Keywords: claude-code,copilot,vscode,kiro,mcp,powershell,tokens
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: click>=8.1.0
|
|
24
|
+
Requires-Dist: rich>=13.0.0
|
|
25
|
+
Provides-Extra: mcp
|
|
26
|
+
Requires-Dist: mcp>=1.9.4; extra == "mcp"
|
|
27
|
+
Requires-Dist: uvicorn>=0.29.0; extra == "mcp"
|
|
28
|
+
Requires-Dist: httpx>=0.27.0; extra == "mcp"
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: shellsage[mcp]; extra == "all"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
35
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
36
|
+
Requires-Dist: types-click; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
<div align="center"><pre>
|
|
40
|
+
██████╗██╗ ██╗███████╗██╗ ██╗ ███████╗ █████╗ ██████╗ ███████╗
|
|
41
|
+
██╔════╝██║ ██║██╔════╝██║ ██║ ██╔════╝██╔══██╗██╔════╝ ██╔════╝
|
|
42
|
+
╚█████╗ ███████║█████╗ ██║ ██║ ███████╗███████║██║ ███╗█████╗
|
|
43
|
+
╚═══██╗██╔══██║██╔══╝ ██║ ██║ ╚════██║██╔══██║██║ ██║██╔══╝
|
|
44
|
+
██████╔╝██║ ██║███████╗███████╗███████╗███████║██║ ██║╚██████╔╝███████╗
|
|
45
|
+
╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
|
|
46
|
+
The shell translation layer for AI coding agents
|
|
47
|
+
</pre></div>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<strong>fast rule engine · optional vector memory · MCP server · hooks · local-first · zero token waste</strong>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://github.com/shellsage/shellsage/actions/workflows/ci.yml">
|
|
55
|
+
<img src="https://github.com/shellsage/shellsage/actions/workflows/ci.yml/badge.svg" alt="CI">
|
|
56
|
+
</a>
|
|
57
|
+
<a href="https://pypi.org/project/shellsage/">
|
|
58
|
+
<img src="https://img.shields.io/pypi/v/shellsage.svg" alt="PyPI">
|
|
59
|
+
</a>
|
|
60
|
+
<a href="https://pypi.org/project/shellsage/">
|
|
61
|
+
<img src="https://img.shields.io/pypi/pyversions/shellsage.svg" alt="Python">
|
|
62
|
+
</a>
|
|
63
|
+
<a href="LICENSE">
|
|
64
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
|
65
|
+
</a>
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
<p align="center">
|
|
69
|
+
<a href="#what-it-does">What it does</a> ·
|
|
70
|
+
<a href="#quickstart">Quickstart</a> ·
|
|
71
|
+
<a href="#setup-guides">Setup</a> ·
|
|
72
|
+
<a href="#command-translation-reference">Translation Reference</a> ·
|
|
73
|
+
<a href="#configuration">Configuration</a> ·
|
|
74
|
+
<a href="#cli-reference">CLI</a> ·
|
|
75
|
+
<a href="#architecture">Architecture</a>
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
ShellSage intercepts Bash-style tool calls made by your AI coding agent (Claude Code, Cursor, Windsurf, Kiro, Cline …) and silently rewrites bash syntax into correct PowerShell/CMD before the shell sees it. It works immediately with a local rule engine and a SQLite memory that learns from your sessions — no external services required.
|
|
81
|
+
|
|
82
|
+
**No API key. No cloud. No Docker. Runs entirely on your machine.**
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## What it does
|
|
87
|
+
|
|
88
|
+
| Without ShellSage | With ShellSage |
|
|
89
|
+
|---|---|
|
|
90
|
+
| Agent writes `ls -la` → PowerShell fails → retry loop → 45k wasted tokens | Agent writes `ls -la` → silently becomes `Get-ChildItem -Force` → works ✓ |
|
|
91
|
+
| 3 bash failures per session = ~135k wasted tokens | 0 failures · 0 wasted tokens |
|
|
92
|
+
| Error traces pollute all future turns | Errors never reach the LLM context |
|
|
93
|
+
|
|
94
|
+
**How it translates:**
|
|
95
|
+
|
|
96
|
+
1. **Rule-based translation** — 100+ regex patterns covering common bash constructs. Instant, zero DB dependency.
|
|
97
|
+
2. **SQLite memory** — BM25-style lookup over 400+ curated seed translations plus anything learned from your own sessions. Stored locally in `~/.shellsage/memory.db`.
|
|
98
|
+
3. **Passthrough** — if no translation is needed (native PowerShell, git, docker), the command passes through unchanged.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Quickstart
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# 1. Install
|
|
106
|
+
pip install "shellsage[mcp]"
|
|
107
|
+
|
|
108
|
+
# 2. One-command setup (detects your IDE automatically)
|
|
109
|
+
shellsage setup
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The setup wizard:
|
|
113
|
+
- detects which IDE/agent you have (Claude Code, Cursor, Windsurf)
|
|
114
|
+
- seeds the local SQLite database with 400+ curated translations
|
|
115
|
+
- starts the background MCP server
|
|
116
|
+
- registers the MCP server with your IDE
|
|
117
|
+
- optionally installs Claude Code hooks for transparent pre-execution translation
|
|
118
|
+
|
|
119
|
+
If you have multiple IDEs installed it will ask which to configure.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Setup Guides
|
|
124
|
+
|
|
125
|
+
`shellsage setup` handles everything automatically. The manual steps below are for reference or scripted environments.
|
|
126
|
+
|
|
127
|
+
### Claude Code (recommended — hooks + MCP)
|
|
128
|
+
|
|
129
|
+
Claude Code supports **hooks** (silently rewrite before execution) and **MCP** (tools the model can call).
|
|
130
|
+
|
|
131
|
+
#### Option A — automatic (recommended)
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
shellsage setup
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Option B — manual
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# 1. Start the background server
|
|
141
|
+
shellsage start
|
|
142
|
+
|
|
143
|
+
# 2. Register the MCP server
|
|
144
|
+
claude mcp add --transport sse shellsage http://127.0.0.1:7842/sse
|
|
145
|
+
|
|
146
|
+
# 3. Install project hooks (run inside your project directory)
|
|
147
|
+
shellsage hooks install
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`shellsage hooks install` creates `.claude/hooks/pre_tool_use.py` and `post_tool_use.py` and prints the settings snippet to add to `.claude/settings.json`.
|
|
151
|
+
|
|
152
|
+
**What each hook does:**
|
|
153
|
+
- `pre_tool_use.py` — translates the command before execution; caches original→translated to a temp file
|
|
154
|
+
- `post_tool_use.py` — reads the cache and records the outcome to local SQLite memory
|
|
155
|
+
|
|
156
|
+
### Cursor
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
shellsage setup # auto-writes ~/.cursor/mcp.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Or add manually to `~/.cursor/mcp.json`:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"mcpServers": {
|
|
167
|
+
"shellsage": {
|
|
168
|
+
"url": "http://127.0.0.1:7842/sse"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Start the server first: `shellsage start`
|
|
175
|
+
|
|
176
|
+
### Windsurf
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
shellsage setup # auto-writes ~/.codeium/windsurf/mcp_config.json
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Or add manually to `~/.codeium/windsurf/mcp_config.json`:
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"mcpServers": {
|
|
187
|
+
"shellsage": {
|
|
188
|
+
"serverUrl": "http://127.0.0.1:7842/sse"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Start the server first: `shellsage start`
|
|
195
|
+
|
|
196
|
+
### Other IDEs (stdio transport)
|
|
197
|
+
|
|
198
|
+
For any MCP-compatible IDE that supports stdio transport:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"mcpServers": {
|
|
203
|
+
"shellsage": {
|
|
204
|
+
"command": "shellsage",
|
|
205
|
+
"args": ["mcp"]
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Command Translation Reference
|
|
214
|
+
|
|
215
|
+
The rule engine handles these commands immediately. If vector memory is installed, `shellsage init` loads a limited curated seed set by default; use `shellsage init --all` to load the complete corpus.
|
|
216
|
+
|
|
217
|
+
### File Listing
|
|
218
|
+
|
|
219
|
+
| bash | PowerShell |
|
|
220
|
+
|------|-----------|
|
|
221
|
+
| `ls` | `Get-ChildItem` |
|
|
222
|
+
| `ls -la` | `Get-ChildItem -Force` |
|
|
223
|
+
| `ls -l` | `Get-ChildItem \| Format-List` |
|
|
224
|
+
| `ls -R` | `Get-ChildItem -Recurse` |
|
|
225
|
+
| `ls *.py` | `Get-ChildItem *.py` |
|
|
226
|
+
| `ls -la src/` | `Get-ChildItem -Force 'src/'` |
|
|
227
|
+
| `ls ~` | `Get-ChildItem $HOME` |
|
|
228
|
+
|
|
229
|
+
### Find / Locate
|
|
230
|
+
|
|
231
|
+
| bash | PowerShell |
|
|
232
|
+
|------|-----------|
|
|
233
|
+
| `find . -name '*.py'` | `Get-ChildItem -Recurse -Filter '*.py'` |
|
|
234
|
+
| `find . -type f` | `Get-ChildItem -Recurse -File` |
|
|
235
|
+
| `find . -type d` | `Get-ChildItem -Recurse -Directory` |
|
|
236
|
+
| `find . -type f -name '*.log'` | `Get-ChildItem -Recurse -File -Filter '*.log'` |
|
|
237
|
+
| `find src/ -name '*.py'` | `Get-ChildItem -Path 'src/' -Recurse -Filter '*.py'` |
|
|
238
|
+
| `find . -mtime -7` | `Get-ChildItem -Recurse \| Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) }` |
|
|
239
|
+
| `find . -size +1M` | `Get-ChildItem -Recurse \| Where-Object { $_.Length -gt 1MB }` |
|
|
240
|
+
| `find . -name '*.tmp' -delete` | `Get-ChildItem -Recurse -Filter '*.tmp' \| Remove-Item -Force` |
|
|
241
|
+
| `find . -name '*.pyc' -delete` | `Get-ChildItem -Recurse -Filter '*.pyc' \| Remove-Item -Force` |
|
|
242
|
+
|
|
243
|
+
### Grep / Search
|
|
244
|
+
|
|
245
|
+
| bash | PowerShell |
|
|
246
|
+
|------|-----------|
|
|
247
|
+
| `grep 'error' app.log` | `Select-String -Pattern 'error' -Path 'app.log'` |
|
|
248
|
+
| `grep -r 'TODO' .` | `Get-ChildItem -Recurse \| Select-String -Pattern 'TODO'` |
|
|
249
|
+
| `grep -rn 'import' src/` | `Get-ChildItem -Recurse 'src/' \| Select-String -Pattern 'import'` |
|
|
250
|
+
| `grep -i 'error' app.log` | `Select-String -Pattern 'error' -Path 'app.log' -CaseSensitive:$false` |
|
|
251
|
+
| `grep -v 'debug' app.log` | `Get-Content 'app.log' \| Where-Object { $_ -notmatch 'debug' }` |
|
|
252
|
+
| `grep -c 'error' app.log` | `(Select-String -Pattern 'error' -Path 'app.log').Count` |
|
|
253
|
+
| `grep -l 'TODO' *.py` | `Select-String -Pattern 'TODO' -Path '*.py' \| Select-Object -ExpandProperty Path -Unique` |
|
|
254
|
+
| `grep 'error' *.log` | `Select-String -Pattern 'error' -Path '*.log'` |
|
|
255
|
+
| `grep -r 'password' . --include='*.py'` | `Get-ChildItem -Recurse -Filter '*.py' \| Select-String -Pattern 'password'` |
|
|
256
|
+
|
|
257
|
+
### View Files
|
|
258
|
+
|
|
259
|
+
| bash | PowerShell |
|
|
260
|
+
|------|-----------|
|
|
261
|
+
| `cat README.md` | `Get-Content 'README.md'` |
|
|
262
|
+
| `cat file1.txt file2.txt` | `Get-Content 'file1.txt', 'file2.txt'` |
|
|
263
|
+
| `head -n 20 file.txt` | `Get-Content 'file.txt' -TotalCount 20` |
|
|
264
|
+
| `tail -n 50 app.log` | `Get-Content 'app.log' -Tail 50` |
|
|
265
|
+
| `tail -f server.log` | `Get-Content -Wait 'server.log'` |
|
|
266
|
+
|
|
267
|
+
### File Management
|
|
268
|
+
|
|
269
|
+
| bash | PowerShell |
|
|
270
|
+
|------|-----------|
|
|
271
|
+
| `mkdir -p src/utils` | `New-Item -ItemType Directory -Force -Path 'src/utils'` |
|
|
272
|
+
| `rm -rf node_modules` | `Remove-Item -Recurse -Force 'node_modules'` |
|
|
273
|
+
| `rm -rf dist/` | `Remove-Item -Recurse -Force 'dist/'` |
|
|
274
|
+
| `rm -f output.log` | `Remove-Item -Force 'output.log'` |
|
|
275
|
+
| `cp -r src/ backup/` | `Copy-Item -Recurse 'src/' 'backup/'` |
|
|
276
|
+
| `cp config.json config.json.bak` | `Copy-Item 'config.json' 'config.json.bak'` |
|
|
277
|
+
| `mv old.txt new.txt` | `Move-Item 'old.txt' 'new.txt'` |
|
|
278
|
+
| `touch .gitkeep` | `New-Item -ItemType File -Force '.gitkeep'` |
|
|
279
|
+
| `ln -s src dest` | `New-Item -ItemType SymbolicLink -Name 'dest' -Target 'src'` |
|
|
280
|
+
|
|
281
|
+
### Text Processing
|
|
282
|
+
|
|
283
|
+
| bash | PowerShell |
|
|
284
|
+
|------|-----------|
|
|
285
|
+
| `wc -l file.txt` | `(Get-Content 'file.txt').Count` |
|
|
286
|
+
| `sort file.txt` | `Get-Content 'file.txt' \| Sort-Object` |
|
|
287
|
+
| `sort -u file.txt` | `Get-Content 'file.txt' \| Sort-Object -Unique` |
|
|
288
|
+
| `sort -r file.txt` | `Get-Content 'file.txt' \| Sort-Object -Descending` |
|
|
289
|
+
| `sort file.txt \| uniq -c` | `Get-Content 'file.txt' \| Group-Object \| Select-Object Count, Name` |
|
|
290
|
+
| `sed -i 's/foo/bar/g' file.txt` | `(Get-Content 'file.txt') -replace 'foo','bar' \| Set-Content 'file.txt'` |
|
|
291
|
+
| `sed '/^#/d' file.txt` | `Get-Content 'file.txt' \| Where-Object { $_ -notmatch '^#' }` |
|
|
292
|
+
| `awk '{print $1}' file.txt` | `Get-Content 'file.txt' \| ForEach-Object { ($_ -split '\s+')[0] }` |
|
|
293
|
+
|
|
294
|
+
### Echo / Redirect
|
|
295
|
+
|
|
296
|
+
| bash | PowerShell |
|
|
297
|
+
|------|-----------|
|
|
298
|
+
| `echo 'hello world'` | `Write-Output 'hello world'` |
|
|
299
|
+
| `echo $PATH` | `$env:PATH` |
|
|
300
|
+
| `echo $HOME` | `$env:USERPROFILE` |
|
|
301
|
+
| `echo 'line' > file.txt` | `Set-Content 'file.txt' 'line'` |
|
|
302
|
+
| `echo 'line' >> file.txt` | `Add-Content 'file.txt' 'line'` |
|
|
303
|
+
|
|
304
|
+
### Environment Variables
|
|
305
|
+
|
|
306
|
+
| bash | PowerShell |
|
|
307
|
+
|------|-----------|
|
|
308
|
+
| `export NODE_ENV=production` | `$env:NODE_ENV = 'production'` |
|
|
309
|
+
| `export PORT=3000` | `$env:PORT = '3000'` |
|
|
310
|
+
| `export DATABASE_URL=postgres://localhost/db` | `$env:DATABASE_URL = 'postgres://localhost/db'` |
|
|
311
|
+
| `unset NODE_ENV` | `Remove-Item Env:\NODE_ENV` |
|
|
312
|
+
| `env` | `Get-ChildItem Env:` |
|
|
313
|
+
| `printenv PATH` | `$env:PATH` |
|
|
314
|
+
|
|
315
|
+
### Process Management
|
|
316
|
+
|
|
317
|
+
| bash | PowerShell |
|
|
318
|
+
|------|-----------|
|
|
319
|
+
| `ps aux` | `Get-Process` |
|
|
320
|
+
| `ps aux \| grep node` | `Get-Process \| Where-Object { $_.Name -match 'node' }` |
|
|
321
|
+
| `pgrep python` | `Get-Process -Name '*python*'` |
|
|
322
|
+
| `pkill node` | `Stop-Process -Name 'node' -Force` |
|
|
323
|
+
| `kill -9 1234` | `Stop-Process -Id 1234 -Force` |
|
|
324
|
+
| `killall python` | `Stop-Process -Name 'python' -Force` |
|
|
325
|
+
| `sleep 5` | `Start-Sleep 5` |
|
|
326
|
+
| `nohup python app.py &` | `Start-Process -NoNewWindow python -ArgumentList 'app.py' -RedirectStandardOutput 'nohup.out'` |
|
|
327
|
+
|
|
328
|
+
### Network
|
|
329
|
+
|
|
330
|
+
| bash | PowerShell |
|
|
331
|
+
|------|-----------|
|
|
332
|
+
| `curl https://example.com` | `Invoke-WebRequest -Uri 'https://example.com'` |
|
|
333
|
+
| `curl -s https://api.github.com` | `Invoke-RestMethod 'https://api.github.com'` |
|
|
334
|
+
| `curl -o file.zip https://example.com/a.zip` | `Invoke-WebRequest -Uri 'https://example.com/a.zip' -OutFile 'file.zip'` |
|
|
335
|
+
| `curl -X POST URL -d '{"k":"v"}'` | `Invoke-RestMethod -Method POST -Uri URL -Body '{"k":"v"}' -ContentType 'application/json'` |
|
|
336
|
+
| `curl -H 'Authorization: Bearer TOKEN' URL` | `Invoke-RestMethod -Uri URL -Headers @{ Authorization = 'Bearer TOKEN' }` |
|
|
337
|
+
| `wget https://example.com/file.zip` | `Invoke-WebRequest -Uri 'https://example.com/file.zip' -OutFile 'file.zip'` |
|
|
338
|
+
| `ping google.com` | `Test-Connection -ComputerName 'google.com'` |
|
|
339
|
+
| `ping -c 4 google.com` | `Test-Connection -ComputerName 'google.com' -Count 4` |
|
|
340
|
+
| `netstat -tulpn` | `Get-NetTCPConnection \| Where-Object { $_.State -eq 'Listen' }` |
|
|
341
|
+
| `nslookup google.com` | `Resolve-DnsName 'google.com'` |
|
|
342
|
+
|
|
343
|
+
### Archive / Compression
|
|
344
|
+
|
|
345
|
+
| bash | PowerShell |
|
|
346
|
+
|------|-----------|
|
|
347
|
+
| `tar -czf archive.tar.gz dist/` | `Compress-Archive -Path 'dist/' -DestinationPath 'archive.zip'` |
|
|
348
|
+
| `tar -xzf archive.tar.gz` | `Expand-Archive -Path 'archive.zip' -DestinationPath '.'` |
|
|
349
|
+
| `tar -xzf archive.tar.gz -C out/` | `Expand-Archive -Path 'archive.zip' -DestinationPath 'out/'` |
|
|
350
|
+
| `zip -r archive.zip src/` | `Compress-Archive -Path 'src/' -DestinationPath 'archive.zip'` |
|
|
351
|
+
| `unzip archive.zip -d output/` | `Expand-Archive -Path 'archive.zip' -DestinationPath 'output/'` |
|
|
352
|
+
|
|
353
|
+
### Disk / System Info
|
|
354
|
+
|
|
355
|
+
| bash | PowerShell |
|
|
356
|
+
|------|-----------|
|
|
357
|
+
| `df -h` | `Get-PSDrive -PSProvider FileSystem` |
|
|
358
|
+
| `du -sh .` | `(Get-ChildItem -Recurse \| Measure-Object -Property Length -Sum).Sum / 1MB` |
|
|
359
|
+
| `du -sh node_modules/` | `(Get-ChildItem -Recurse 'node_modules/' \| Measure-Object -Property Length -Sum).Sum / 1MB` |
|
|
360
|
+
| `uname -a` | `Get-ComputerInfo \| Select-Object WindowsProductName, WindowsVersion` |
|
|
361
|
+
| `hostname` | `$env:COMPUTERNAME` |
|
|
362
|
+
| `whoami` | `$env:USERNAME` |
|
|
363
|
+
| `date` | `Get-Date` |
|
|
364
|
+
| `date '+%Y-%m-%d'` | `Get-Date -Format 'yyyy-MM-dd'` |
|
|
365
|
+
| `uptime` | `(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime` |
|
|
366
|
+
|
|
367
|
+
### Permissions
|
|
368
|
+
|
|
369
|
+
| bash | PowerShell |
|
|
370
|
+
|------|-----------|
|
|
371
|
+
| `chmod +x script.sh` | `# Rename to script.ps1 or use Set-ExecutionPolicy` |
|
|
372
|
+
| `chmod 755 dir/` | `# Use icacls for Windows ACL management` |
|
|
373
|
+
| `chown user file` | `# Use icacls: icacls 'file' /setowner 'user'` |
|
|
374
|
+
| `sudo command` | `# Run PowerShell as Administrator, then: command` |
|
|
375
|
+
|
|
376
|
+
### Python
|
|
377
|
+
|
|
378
|
+
| bash | PowerShell |
|
|
379
|
+
|------|-----------|
|
|
380
|
+
| `python3 script.py` | `python script.py` |
|
|
381
|
+
| `python3 -m pytest` | `python -m pytest` |
|
|
382
|
+
| `python3 -m pytest -v` | `python -m pytest -v` |
|
|
383
|
+
| `python3 -m pip install -r requirements.txt` | `python -m pip install -r requirements.txt` |
|
|
384
|
+
| `python3 -m pip install -e .` | `python -m pip install -e .` |
|
|
385
|
+
| `python3 -m venv .venv` | `python -m venv .venv` |
|
|
386
|
+
| `source .venv/bin/activate` | `.venv\Scripts\Activate.ps1` |
|
|
387
|
+
| `python3 -m pip freeze > requirements.txt` | `python -m pip freeze \| Set-Content 'requirements.txt'` |
|
|
388
|
+
| `which python3` | `(Get-Command python).Source` |
|
|
389
|
+
|
|
390
|
+
### Node.js / npm
|
|
391
|
+
|
|
392
|
+
| bash | PowerShell |
|
|
393
|
+
|------|-----------|
|
|
394
|
+
| `npm install` | `npm install` |
|
|
395
|
+
| `npm install package` | `npm install package` |
|
|
396
|
+
| `npm run build` | `npm run build` |
|
|
397
|
+
| `npm run dev` | `npm run dev` |
|
|
398
|
+
| `npm test` | `npm test` |
|
|
399
|
+
| `npx tsc` | `npx tsc` |
|
|
400
|
+
| `yarn install` | `yarn install` |
|
|
401
|
+
| `yarn add package` | `yarn add package` |
|
|
402
|
+
|
|
403
|
+
### Docker
|
|
404
|
+
|
|
405
|
+
| bash | PowerShell |
|
|
406
|
+
|------|-----------|
|
|
407
|
+
| `docker ps -a` | `docker ps -a` |
|
|
408
|
+
| `docker build -t myapp .` | `docker build -t myapp .` |
|
|
409
|
+
| `docker run -d -p 8080:8080 myapp` | `docker run -d -p 8080:8080 myapp` |
|
|
410
|
+
| `docker exec -it mycontainer bash` | `docker exec -it mycontainer bash` |
|
|
411
|
+
| `docker logs -f mycontainer` | `docker logs -f mycontainer` |
|
|
412
|
+
| `docker-compose up -d` | `docker-compose up -d` |
|
|
413
|
+
| `docker-compose down` | `docker-compose down` |
|
|
414
|
+
| `docker system prune -f` | `docker system prune -f` |
|
|
415
|
+
|
|
416
|
+
### Git
|
|
417
|
+
|
|
418
|
+
Git commands are identical on all platforms — ShellSage passes them through unchanged.
|
|
419
|
+
|
|
420
|
+
| bash / PowerShell |
|
|
421
|
+
|---|
|
|
422
|
+
| `git init` · `git clone URL` · `git status` · `git add .` |
|
|
423
|
+
| `git commit -m 'message'` · `git push origin main` · `git pull` |
|
|
424
|
+
| `git checkout -b feature/name` · `git merge branch` · `git rebase main` |
|
|
425
|
+
| `git log --oneline -10` · `git diff --stat` · `git stash` |
|
|
426
|
+
|
|
427
|
+
### Directory Navigation
|
|
428
|
+
|
|
429
|
+
| bash | PowerShell |
|
|
430
|
+
|------|-----------|
|
|
431
|
+
| `pwd` | `Get-Location` |
|
|
432
|
+
| `cd src/` | `Set-Location 'src/'` |
|
|
433
|
+
| `cd ..` | `Set-Location ..` |
|
|
434
|
+
| `cd ~` | `Set-Location $HOME` |
|
|
435
|
+
| `pushd src/` | `Push-Location 'src/'` |
|
|
436
|
+
| `popd` | `Pop-Location` |
|
|
437
|
+
|
|
438
|
+
### Pipes and Redirects
|
|
439
|
+
|
|
440
|
+
| bash | PowerShell |
|
|
441
|
+
|------|-----------|
|
|
442
|
+
| `ls \| grep '.py'` | `Get-ChildItem \| Where-Object { $_.Name -match '\.py' }` |
|
|
443
|
+
| `ls \| wc -l` | `(Get-ChildItem).Count` |
|
|
444
|
+
| `cat file.txt \| sort \| uniq` | `Get-Content 'file.txt' \| Sort-Object -Unique` |
|
|
445
|
+
| `find . -name '*.py' \| xargs grep 'import'` | `Get-ChildItem -Recurse -Filter '*.py' \| Select-String -Pattern 'import'` |
|
|
446
|
+
| `command > /dev/null 2>&1` | `command > $null 2>&1` |
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Configuration
|
|
451
|
+
|
|
452
|
+
All settings can be overridden via environment variables:
|
|
453
|
+
|
|
454
|
+
| Variable | Default | Description |
|
|
455
|
+
|---|---|---|
|
|
456
|
+
| `SHELLSAGE_DB_PATH` | `~/.shellsage/memory.db` | SQLite database path |
|
|
457
|
+
| `SHELLSAGE_PORT` | `7842` | Background MCP server port |
|
|
458
|
+
| `SHELLSAGE_HOST` | `127.0.0.1` | Background MCP server host |
|
|
459
|
+
| `SHELLSAGE_SCORE_THRESHOLD` | `0.1` | Minimum score to accept a stored-translation hit |
|
|
460
|
+
| `SHELLSAGE_SEED_LIMIT` | `75` | Number of seed examples loaded by `shellsage init` |
|
|
461
|
+
| `SHELLSAGE_SEED_CONFIDENCE` | `0.95` | Confidence assigned to seed translations |
|
|
462
|
+
| `SHELLSAGE_OUTCOME_CONFIDENCE` | `0.99` | Confidence assigned when a command succeeds in practice |
|
|
463
|
+
|
|
464
|
+
Example — custom port:
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
export SHELLSAGE_PORT=8888
|
|
468
|
+
shellsage setup --port 8888
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## MCP Tools
|
|
474
|
+
|
|
475
|
+
The MCP server exposes 4 tools that your AI agent can call directly:
|
|
476
|
+
|
|
477
|
+
| Tool | Description |
|
|
478
|
+
|---|---|
|
|
479
|
+
| `translate_command(command, project_root)` | Translate a bash command for the current shell |
|
|
480
|
+
| `store_command_result(original, translated, shell, os_name, project_type, exit_code, error_snippet)` | Record command outcome when vector memory is installed |
|
|
481
|
+
| `get_shell_context(project_root)` | Return detected OS/shell/project environment |
|
|
482
|
+
| `get_stats()` | Health check — return Qdrant collection counts |
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## CLI Reference
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
shellsage setup # Interactive one-command install wizard (auto-detects IDE)
|
|
490
|
+
shellsage setup --port 8888 # Wizard with custom port
|
|
491
|
+
|
|
492
|
+
shellsage init # Seed the local SQLite DB (75 examples by default)
|
|
493
|
+
shellsage init --all # Load the complete 400+ seed corpus
|
|
494
|
+
|
|
495
|
+
shellsage translate "ls -la" # Translate a single command
|
|
496
|
+
shellsage translate "ls -la" --json-out # Machine-readable output
|
|
497
|
+
|
|
498
|
+
shellsage stats # Show local DB counts
|
|
499
|
+
shellsage replay # Show recent failure patterns
|
|
500
|
+
|
|
501
|
+
shellsage start # Start background MCP server (HTTP/SSE)
|
|
502
|
+
shellsage stop # Stop background MCP server
|
|
503
|
+
shellsage status # Show daemon and DB status
|
|
504
|
+
|
|
505
|
+
shellsage mcp # Start MCP server in foreground (stdio)
|
|
506
|
+
shellsage mcp --http # Start MCP server in foreground (HTTP/SSE)
|
|
507
|
+
|
|
508
|
+
shellsage hooks install # Write pre/post hook scripts to .claude/hooks/
|
|
509
|
+
|
|
510
|
+
shellsage --version # Print version
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Architecture
|
|
516
|
+
|
|
517
|
+
```
|
|
518
|
+
Claude Code / Cursor / Windsurf / Kiro / Cline
|
|
519
|
+
│ bash command
|
|
520
|
+
▼
|
|
521
|
+
┌───────────────────────────────────────────────┐
|
|
522
|
+
│ PreToolUse Hook (.claude/hooks/pre_*.py) │ ← Claude Code only
|
|
523
|
+
│ ───────────────────────────────────────── │
|
|
524
|
+
│ 1. Rule-based translation (100+ patterns) │
|
|
525
|
+
│ 2. SQLite hybrid search (BM25 + learned) │
|
|
526
|
+
│ 3. Passthrough if no match │
|
|
527
|
+
│ Caches: original → translated (temp file) │
|
|
528
|
+
└───────────────────────────────────────────────┘
|
|
529
|
+
│ corrected PowerShell command
|
|
530
|
+
▼
|
|
531
|
+
[Shell execution]
|
|
532
|
+
│
|
|
533
|
+
▼
|
|
534
|
+
┌───────────────────────────────────────────────┐
|
|
535
|
+
│ PostToolUse Hook (.claude/hooks/post_*.py) │ ← Claude Code only
|
|
536
|
+
│ Reads cache, records outcome to SQLite │
|
|
537
|
+
│ Success → upsert translation (conf=0.99) │
|
|
538
|
+
│ Failure → upsert failure pattern │
|
|
539
|
+
└───────────────────────────────────────────────┘
|
|
540
|
+
│
|
|
541
|
+
▼
|
|
542
|
+
SQLite (~/.shellsage/memory.db) — always local, zero config
|
|
543
|
+
├─ translations (400+ seeds + session-learned)
|
|
544
|
+
└─ failures (error patterns for replay)
|
|
545
|
+
|
|
546
|
+
─────────────────────────────────────────────────
|
|
547
|
+
MCP server (http://127.0.0.1:7842/sse)
|
|
548
|
+
├─ translate_command → rules + SQLite lookup
|
|
549
|
+
├─ store_command_result → write back to SQLite
|
|
550
|
+
├─ get_shell_context → OS / shell / project detection
|
|
551
|
+
└─ get_stats → health check
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
**Module map:**
|
|
555
|
+
|
|
556
|
+
| Module | Role |
|
|
557
|
+
|---|---|
|
|
558
|
+
| `config.py` | Env-var-backed settings (single source of truth) |
|
|
559
|
+
| `models.py` | `ShellContext`, `Translation`, `CommandOutcome` — zero deps |
|
|
560
|
+
| `rules.py` | 100+ regex patterns (instant, no DB needed) |
|
|
561
|
+
| `seed.py` | 400+ curated bash→PS pairs; `init` loads a bounded set by default |
|
|
562
|
+
| `store.py` | SQLite: translations + failures, BM25-style lookup |
|
|
563
|
+
| `translator.py` | 2-tier resolution: rules → SQLite lookup → passthrough |
|
|
564
|
+
| `server.py` | FastMCP server (4 tools, stdio or HTTP/SSE) |
|
|
565
|
+
| `daemon.py` | Background process management (start / stop / status) |
|
|
566
|
+
| `setup_wizard.py` | Interactive installer with IDE auto-detection |
|
|
567
|
+
| `cli.py` | Click CLI (10 commands) |
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Development
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
git clone https://github.com/shellsage/shellsage.git
|
|
575
|
+
cd shellsage
|
|
576
|
+
pip install -e ".[mcp,dev]"
|
|
577
|
+
|
|
578
|
+
# Run tests
|
|
579
|
+
pytest
|
|
580
|
+
|
|
581
|
+
# Lint
|
|
582
|
+
ruff check shellsage/ tests/
|
|
583
|
+
ruff format shellsage/ tests/
|
|
584
|
+
|
|
585
|
+
# Type check
|
|
586
|
+
mypy shellsage/
|
|
587
|
+
|
|
588
|
+
# Validate seed data
|
|
589
|
+
python -c "from shellsage.seed import SEED_TRANSLATIONS; print(len(SEED_TRANSLATIONS))"
|
|
590
|
+
|
|
591
|
+
# Test a translation (no Qdrant needed)
|
|
592
|
+
shellsage translate "find . -name '*.py'"
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for full contribution guidelines.
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## License
|
|
600
|
+
|
|
601
|
+
MIT — see [LICENSE](LICENSE).
|
|
602
|
+
|
|
603
|
+
## Security
|
|
604
|
+
|
|
605
|
+
Please report vulnerabilities to **security@shellsage.dev** — see [SECURITY.md](SECURITY.md).
|