fableforge-shell-whisperer 0.1.0__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.
@@ -0,0 +1,483 @@
1
+ Metadata-Version: 2.4
2
+ Name: fableforge-shell-whisperer
3
+ Version: 0.1.0
4
+ Summary: 1.5B edge-native shell agent — natural language to shell commands, 50ms latency on phone/edge
5
+ Author: FableForge Team
6
+ License: MIT
7
+ Keywords: shell,nlp,edge,onnx,llm,cli
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: System :: Shells
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: rich>=13.0
20
+ Requires-Dist: click>=8.1
21
+ Requires-Dist: pydantic>=2.0
22
+ Requires-Dist: httpx>=0.25
23
+ Requires-Dist: fastapi>=0.110.0
24
+ Requires-Dist: uvicorn>=0.29.0
25
+ Requires-Dist: websockets>=12.0
26
+ Provides-Extra: train
27
+ Requires-Dist: torch>=2.1.0; extra == "train"
28
+ Requires-Dist: transformers>=4.40.0; extra == "train"
29
+ Requires-Dist: peft>=0.10.0; extra == "train"
30
+ Requires-Dist: datasets>=2.18.0; extra == "train"
31
+ Requires-Dist: unsloth>=2024.1; extra == "train"
32
+ Requires-Dist: accelerate>=0.27.0; extra == "train"
33
+ Requires-Dist: trl>=0.8.0; extra == "train"
34
+ Requires-Dist: wandb>=0.16.0; extra == "train"
35
+ Provides-Extra: gpu
36
+ Requires-Dist: bitsandbytes>=0.43.0; extra == "gpu"
37
+ Requires-Dist: xformers>=0.0.23; extra == "gpu"
38
+ Provides-Extra: export
39
+ Requires-Dist: onnx>=1.16.0; extra == "export"
40
+ Requires-Dist: onnxruntime>=1.17.0; extra == "export"
41
+ Requires-Dist: optimum>=1.17.0; extra == "export"
42
+ Provides-Extra: gguf
43
+ Requires-Dist: llama-cpp-python>=0.2.50; extra == "gguf"
44
+ Provides-Extra: all
45
+ Requires-Dist: shell-whisperer[export,gguf,gpu,train]; extra == "all"
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
48
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
49
+ Requires-Dist: ruff>=0.3.0; extra == "dev"
50
+ Requires-Dist: mypy>=1.9.0; extra == "dev"
51
+ Dynamic: license-file
52
+
53
+ # ShellWhisperer
54
+
55
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/) [![Tests](https://img.shields.io/badge/tests-0-yellow.svg)](tests/)
56
+
57
+
58
+ > **Natural language → shell commands. 50ms on edge.**
59
+
60
+ A 1.5B parameter edge-native shell agent fine-tuned from Qwen3-1.5B. Converts natural language descriptions into safe, correct shell commands — designed to run on phones and edge devices via ONNX Runtime or llama.cpp GGUF.
61
+
62
+ ## Features
63
+
64
+ - **Edge-native**: Runs in <50ms on mobile/edge via ONNX or GGUF
65
+ - **Multi-OS**: Linux, macOS, Windows PowerShell prompts
66
+ - **Safety-first**: Built-in guardrails against destructive commands (rm -rf /, fork bombs, pipe-to-shell)
67
+ - **Context-aware**: Uses working directory, OS type, and recent command history
68
+ - **Multiple backends**: HuggingFace Transformers, ONNX Runtime, llama.cpp
69
+ - **Streaming**: WebSocket streaming for real-time output
70
+ - **Fine-tune your own**: LoRA training on Fable5 traces or custom data
71
+
72
+ ## Quick Start
73
+
74
+ ### Install
75
+
76
+ ```bash
77
+ pip install shell-whisperer
78
+
79
+ # With training support:
80
+ pip install "shell-whisperer[train]"
81
+
82
+ # With GGUF inference:
83
+ pip install "shell-whisperer[gguf]"
84
+
85
+ # Everything:
86
+ pip install "shell-whisperer[train,gguf,dev]"
87
+ ```
88
+
89
+ ### One-shot Prediction
90
+
91
+ ```bash
92
+ # Basic usage
93
+ sw "find all python files over 100 lines"
94
+ # → find . -name "*.py" -exec wc -l {} + | awk '$1 > 100'
95
+
96
+ sw "kill the process on port 8080"
97
+ # → lsof -ti:8080 | xargs kill -9
98
+
99
+ sw --os-type macos "install ffmpeg"
100
+ # → brew install ffmpeg
101
+
102
+ sw --os-type windows "show all listening ports"
103
+ # → Get-NetTCPConnection -State Listen | Format-Table LocalPort, OwningProcess -AutoSize
104
+ ```
105
+
106
+ ### Interactive Mode
107
+
108
+ ```bash
109
+ sw --interactive
110
+
111
+ sw> find all python files over 100 lines
112
+ ┌─────────────────────────────────────────────────────────┐
113
+ │ find . -name "*.py" -exec wc -l {} + | awk '$1 > 100' │
114
+ └─────────────────────────────────────────────────────────┘
115
+ 42.5ms
116
+
117
+ sw> !os macos
118
+ OS set to: macos
119
+
120
+ sw> install ffmpeg
121
+ ┌──────────────────────┐
122
+ │ brew install ffmpeg │
123
+ └──────────────────────┘
124
+ 28.1ms
125
+ ```
126
+
127
+ ### Start API Server
128
+
129
+ ```bash
130
+ sw --serve --port 8000
131
+ # Or specify model:
132
+ sw --serve --model ./models/shell-whisperer-merged --port 8000
133
+ ```
134
+
135
+ ## Fine-Tuning
136
+
137
+ ### Prepare Training Data
138
+
139
+ ShellWhisperer extracts training pairs from Fable5 trace formats:
140
+
141
+ ```python
142
+ from shell_whisperer.data_extractor import load_training_data
143
+
144
+ # Load from JSONL traces (auto-detects format)
145
+ pairs = load_training_data("./traces/glint_data.jsonl", fmt="auto")
146
+
147
+ # Or specify format explicitly
148
+ from shell_whisperer.data_extractor import (
149
+ extract_bash_from_glint,
150
+ extract_bash_from_armand0e,
151
+ extract_bash_from_vfable,
152
+ )
153
+
154
+ pairs = extract_bash_from_glint("./traces/glint.jsonl")
155
+ pairs = extract_bash_from_armand0e("./traces/armand0e.jsonl")
156
+ pairs = extract_bash_from_vfable("./traces/vfable.jsonl")
157
+ ```
158
+
159
+ #### Supported Trace Formats
160
+
161
+ **Glint** — Command traces with shell intent metadata:
162
+ ```jsonl
163
+ {"type": "shell_intent", "intent": "find all python files over 100 lines"}
164
+ {"type": "shell_command", "command": "find . -name '*.py' -exec wc -l {} + | awk '$1 > 100'", "shell": "bash", "exit_code": 0}
165
+ ```
166
+
167
+ **armand0e** — Structured shell session logs:
168
+ ```jsonl
169
+ {"event": "command_executed", "prompt": "show disk usage sorted by size", "command": "du -sh * | sort -rh", "exit_status": 0}
170
+ ```
171
+
172
+ **v-Fable** — Validated Fable traces with confirmation signals:
173
+ ```jsonl
174
+ {"role": "user", "utterance": "find all json files modified recently"}
175
+ {"role": "assistant", "tool_call": {"name": "execute_shell", "arguments": {"command": "find . -name '*.json' -mtime -7"}}, "validation": {"confirmed": true, "exit_code": 0}}
176
+ ```
177
+
178
+ ### Train with LoRA
179
+
180
+ ```bash
181
+ # LoRA fine-tune (default)
182
+ sw train --data ./traces/data.jsonl --epochs 3
183
+
184
+ # Full fine-tune
185
+ sw train --data ./traces/data.jsonl --full-finetune
186
+
187
+ # Custom parameters
188
+ sw train \
189
+ --data ./traces/data.jsonl \
190
+ --model-name Qwen/Qwen3-1.5B \
191
+ --output-dir ./models/my-shell-whisperer \
192
+ --epochs 5 \
193
+ --lr 1e-4 \
194
+ --batch-size 8 \
195
+ --os-type linux
196
+ ```
197
+
198
+ ### Training in Python
199
+
200
+ ```python
201
+ from shell_whisperer.trainer import TrainConfig, train_lora
202
+ from shell_whisperer.data_extractor import load_training_data
203
+
204
+ # Load data
205
+ pairs = load_training_data("./traces/data.jsonl", include_builtin=True)
206
+ print(f"Training with {len(pairs)} pairs")
207
+
208
+ # Configure and train
209
+ config = TrainConfig(
210
+ model_name="Qwen/Qwen3-1.5B",
211
+ output_dir="./models/shell-whisperer-lora",
212
+ epochs=3,
213
+ learning_rate=2e-4,
214
+ lora_r=16,
215
+ use_4bit=True,
216
+ use_unsloth=True,
217
+ )
218
+
219
+ adapter_path = train_lora(config=config, training_pairs=pairs)
220
+
221
+ # Merge adapter with base model
222
+ from shell_whisperer.trainer import merge_and_save
223
+
224
+ merge_and_save(
225
+ adapter_path=adapter_path,
226
+ output_dir="./models/shell-whisperer-merged",
227
+ )
228
+ ```
229
+
230
+ ## Export for Edge
231
+
232
+ ```bash
233
+ # Export to ONNX
234
+ sw export --format onnx --model ./models/shell-whisperer-merged
235
+
236
+ # Export to GGUF (for llama.cpp)
237
+ sw export --format gguf --model ./models/shell-whisperer-merged
238
+
239
+ # 4-bit quantization (smallest, fastest)
240
+ sw export --format 4bit --model ./models/shell-whisperer-merged
241
+
242
+ # 8-bit quantization
243
+ sw export --format 8bit --model ./models/shell-whisperer-merged
244
+
245
+ # Export all formats
246
+ sw export --format all --model ./models/shell-whisperer-merged
247
+ ```
248
+
249
+ ### Memory Estimates
250
+
251
+ | Format | RAM Required | Latency (edge) |
252
+ |--------|-------------|----------------|
253
+ | FP32 | ~6.0 GB | ~200ms |
254
+ | FP16 | ~3.0 GB | ~100ms |
255
+ | 8-bit | ~1.5 GB | ~60ms |
256
+ | 4-bit | ~0.75 GB | ~50ms |
257
+ | GGUF Q4_K_M | ~0.84 GB | ~50ms |
258
+
259
+ ## Inference
260
+
261
+ ### Python API
262
+
263
+ ```python
264
+ from shell_whisperer import ShellWhisperer
265
+
266
+ # Load model
267
+ sw = ShellWhisperer(os_type="linux")
268
+ sw.load_model("./models/shell-whisperer-merged")
269
+
270
+ # Predict
271
+ result = sw.predict("find all python files over 100 lines")
272
+ print(result.command)
273
+ # → find . -name "*.py" -exec wc -l {} + | awk '$1 > 100'
274
+
275
+ # Context-aware prediction
276
+ result = sw.predict(
277
+ "find config files",
278
+ working_directory="/etc",
279
+ recent_history=["ls -la", "cd /etc"],
280
+ os_type="linux",
281
+ )
282
+
283
+ # Batch prediction
284
+ results = sw.predict_batch([
285
+ "find all python files over 100 lines",
286
+ "kill the process on port 8080",
287
+ "show disk usage sorted by size",
288
+ ])
289
+
290
+ # Streaming
291
+ for token in sw.predict_stream("find all python files"):
292
+ print(token, end="", flush=True)
293
+
294
+ # Safety warnings
295
+ result = sw.predict("delete everything")
296
+ if result.safety_warnings:
297
+ for warning in result.safety_warnings:
298
+ print(f"⚠ {warning}")
299
+
300
+ sw.unload()
301
+ ```
302
+
303
+ ### REST API
304
+
305
+ ```bash
306
+ # Start server
307
+ sw --serve --port 8000
308
+
309
+ # Predict
310
+ curl -X POST http://localhost:8000/predict \
311
+ -H "Content-Type: application/json" \
312
+ -d '{"prompt": "find all python files over 100 lines", "os_type": "linux"}'
313
+
314
+ # Batch predict
315
+ curl -X POST http://localhost:8000/predict/batch \
316
+ -H "Content-Type: application/json" \
317
+ -d '{"prompts": ["find python files", "kill port 8080"]}'
318
+
319
+ # Health check
320
+ curl http://localhost:8000/health
321
+
322
+ # Model info
323
+ curl http://localhost:8000/info
324
+ ```
325
+
326
+ ### WebSocket Streaming
327
+
328
+ ```javascript
329
+ const ws = new WebSocket("ws://localhost:8000/ws/stream");
330
+
331
+ ws.onopen = () => {
332
+ ws.send(JSON.stringify({
333
+ prompt: "find all python files over 100 lines",
334
+ os_type: "linux"
335
+ }));
336
+ };
337
+
338
+ ws.onmessage = (event) => {
339
+ const data = JSON.parse(event.data);
340
+ if (data.token) {
341
+ process.stdout.write(data.token);
342
+ } else if (data.done) {
343
+ console.log("\nCommand:", data.command);
344
+ if (data.safety_warnings.length) {
345
+ console.log("Warnings:", data.safety_warnings);
346
+ }
347
+ }
348
+ };
349
+ ```
350
+
351
+ ## Example Training Pairs
352
+
353
+ Built-in high-quality pairs from real-world shell usage:
354
+
355
+ | Natural Language | Shell Command | Quality |
356
+ |----------------|---------------|---------|
357
+ | find all python files over 100 lines | `find . -name "*.py" -exec wc -l {} + \| awk '$1 > 100'` | 0.85 |
358
+ | kill the process on port 8080 | `lsof -ti:8080 \| xargs kill -9` | 0.80 |
359
+ | show disk usage sorted by size | `du -sh * \| sort -rh` | 0.75 |
360
+ | recursively search for TODO in all python files | `grep -rn "TODO" --include="*.py" .` | 0.83 |
361
+ | rename all .txt files to .md | `for f in *.txt; do mv "$f" "${f%.txt}.md"; done` | 0.84 |
362
+ | remove all stopped docker containers | `docker container prune -f` | 0.73 |
363
+ | show all git commits by the current user this month | `git log --author="$(git config user.name)" --since="$(date +%Y-%m-01)" --oneline` | 0.88 |
364
+ | list all unique IPs that connected via SSH | `grep "Accepted" /var/log/auth.log \| awk '{print $11}' \| sort -u` | 0.84 |
365
+
366
+ ## Safety System
367
+
368
+ ShellWhisperer includes a built-in safety layer that:
369
+
370
+ 1. **Blocks destructive commands**: `rm -rf /`, fork bombs, `dd` to disk
371
+ 2. **Warns on sudo**: Flags commands requiring elevated privileges
372
+ 3. **Flags pipe-to-shell**: Warns about `curl | bash` patterns
373
+ 4. **Prevents chmod 777**: Warns about insecure permissions
374
+
375
+ ```python
376
+ result = sw.predict("delete all files")
377
+ # Safety warning: ⚠ SAFETY: Destructive: recursive force-delete
378
+ ```
379
+
380
+ ## Architecture
381
+
382
+ ```
383
+ ┌─────────────────────────────────────────┐
384
+ │ Natural Language Input │
385
+ └──────────────┬──────────────────────────┘
386
+
387
+ ┌──────────────▼──────────────────────────┐
388
+ │ System Prompt (OS-specific) │
389
+ │ LINUX_PROMPT / MACOS_PROMPT / │
390
+ │ WINDOWS_PROMPT + Safety Rules │
391
+ └──────────────┬──────────────────────────┘
392
+
393
+ ┌──────────────▼──────────────────────────┐
394
+ │ Qwen3-1.5B (LoRA fine-tuned) │
395
+ │ 1.5B parameters │
396
+ └──────────────┬──────────────────────────┘
397
+
398
+ ┌──────────────▼──────────────────────────┐
399
+ │ Output Cleaning │
400
+ │ - Strip markdown/backticks │
401
+ │ - Remove model prefixes │
402
+ │ - Multi-line pipe/chain handling │
403
+ └──────────────┬──────────────────────────┘
404
+
405
+ ┌──────────────▼──────────────────────────┐
406
+ │ Safety Check │
407
+ │ - rm -rf protection │
408
+ │ - sudo warning │
409
+ │ - pipe-to-shell detection │
410
+ └──────────────┬──────────────────────────┘
411
+
412
+ ┌──────────────▼──────────────────────────┐
413
+ │ Shell Command Output │
414
+ └───────────────────────────────────────────┘
415
+ ```
416
+
417
+ ## Project Structure
418
+
419
+ ```
420
+ shell-whisperer/
421
+ ├── pyproject.toml
422
+ ├── README.md
423
+ ├── src/shell_whisperer/
424
+ │ ├── __init__.py # Package init + exports
425
+ │ ├── prompts.py # OS-specific system prompts + safety rules
426
+ │ ├── data_extractor.py # Fable5 trace extraction + quality filtering
427
+ │ ├── trainer.py # LoRA/Full fine-tuning on Qwen3-1.5B
428
+ │ ├── exporter.py # ONNX, GGUF, 4-bit/8-bit export + memory estimation
429
+ │ ├── inference.py # Multi-backend inference (Transformers, ONNX, llama.cpp)
430
+ │ ├── server.py # FastAPI server (REST + WebSocket)
431
+ │ └── cli.py # CLI: sw predict, train, export, serve
432
+ └── tests/
433
+ ├── test_data_extractor.py
434
+ └── test_inference.py
435
+ ```
436
+
437
+ ## Development
438
+
439
+ ```bash
440
+ # Install dev dependencies
441
+ pip install -e ".[dev]"
442
+
443
+ # Run tests
444
+ pytest
445
+
446
+ # Lint
447
+ ruff check src/ tests/
448
+
449
+ # Type check
450
+ mypy src/
451
+ ```
452
+
453
+ ## License
454
+
455
+ MIT
456
+
457
+ ## Ecosystem
458
+
459
+ Part of the [FableForge](../) ecosystem — 21 open-source projects built from 210K real agent traces:
460
+
461
+ | Project | Description |
462
+ | --- | --- |
463
+ | **[Anvil](../anvil)** | Self-verified coding agent |
464
+ | **[VerifyLoop](../verifyloop)** | Plan→Execute→Verify→Recover framework |
465
+ | **[ErrorRecovery](../error-recovery)** | Self-healing middleware (3,725 error patterns) |
466
+ | **[FableForge-14B](../fableforge-14b)** | The fine-tuned 14B model (4-stage training) |
467
+ | **[ShellWhisperer](../shell-whisperer)** | 1.5B edge agent (phone/RPi, 50ms) |
468
+ | **[ReasonCritic](../reason-critic)** | Verification model (130 benchmark tasks) |
469
+ | **[TraceCompiler](../trace-compiler)** | Compile traces → LoRA skills |
470
+ | **[AgentRuntime](../agent-runtime)** | Persistent agent daemon (systemd for AI) |
471
+ | **[AgentSwarm](../agent-swarm)** | Multi-agent from real trace transitions |
472
+ | **[AgentTelemetry](../agent-telemetry)** | Datadog for agents (token tracking, costs) |
473
+ | **[BenchAgent](../bench-agent)** | HumanEval for tool-use (107 tasks) |
474
+ | **[AgentDev](../agent-dev)** | VSCode extension with verification |
475
+ | **[TraceViz](../trace-viz)** | Trace replay visualizer (Next.js) |
476
+ | **[AgentSkills](../agent-skills)** | npm for agent behaviors |
477
+ | **[AgentCurriculum](../agent-curriculum)** | 5-stage progressive training |
478
+ | **[AgentFuzzer](../agent-fuzzer)** | Adversarial testing for agents |
479
+ | **[AgentConstitution](../agent-constitution)** | Safety guardrails from traces |
480
+ | **[CostOptimizer](../cost-optimizer)** | Token cost reduction (50-80%) |
481
+ | **[AgentProfiler](../agent-profiler)** | Behavioral fingerprinting |
482
+ | **[TrajectoryDistiller](../trajectory-distiller)** | Trace→training data pipeline |
483
+ | **[Fable5-Dataset](../fable5-dataset)** | HuggingFace dataset release |
@@ -0,0 +1,14 @@
1
+ fableforge_shell_whisperer-0.1.0.dist-info/licenses/LICENSE,sha256=w5aFYmJW6UW4AWlHHzPSfzaK9jMabxY0EPRzd12k7V0,1080
2
+ shell_whisperer/__init__.py,sha256=Uyz8rSbHjczxIN9M09kdTqObGFDzYfpNEDtqeWW7cE4,605
3
+ shell_whisperer/cli.py,sha256=EVU_HjXzzSnUvOJzpsarc4mD50OQ8lfnlZ_w6kOm59o,12533
4
+ shell_whisperer/data_extractor.py,sha256=tUVieI_uNJHRE_tFNWTC3Hn04-rkKJJvIw5P9tNHYwo,22989
5
+ shell_whisperer/exporter.py,sha256=nWsO6zxe8a5e-mUBL37qzYv8tVJ1TwOavf_8bNMFHoc,12622
6
+ shell_whisperer/inference.py,sha256=U1pIPAnP1pJ_MDiWBFkXw0o5fpQycy8uy6wH0F975cc,18277
7
+ shell_whisperer/prompts.py,sha256=AR1e5niwZFBQflRce-WTT-kWEwouUzQYQmjfweL1XMc,5501
8
+ shell_whisperer/server.py,sha256=jR0oxg5iQxrIwIqT2aHiQy51dQjxeW65sfBo9mmeFkw,8755
9
+ shell_whisperer/trainer.py,sha256=828YS8kU1wpHbgE4PZwrelerBqaR6fH5mo7Hf4cJ97c,10205
10
+ fableforge_shell_whisperer-0.1.0.dist-info/METADATA,sha256=403RzKuajdMO50tmTlXQtfv9jLJl8tcxXcDO1wpBfMA,16770
11
+ fableforge_shell_whisperer-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
12
+ fableforge_shell_whisperer-0.1.0.dist-info/entry_points.txt,sha256=-EAaZfXSHfIb-djNUgWqLJwv42l8raaF3tpF9WrxSaU,48
13
+ fableforge_shell_whisperer-0.1.0.dist-info/top_level.txt,sha256=Bwwv6h18RSeXq0vXzsia_YN2SDlcKt8rNX1QSostCIM,16
14
+ fableforge_shell_whisperer-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sw = shell_whisperer.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 FableForge 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 @@
1
+ shell_whisperer
@@ -0,0 +1,23 @@
1
+ """ShellWhisperer — 1.5B edge-native shell agent.
2
+
3
+ Converts natural language to shell commands. Runs on phone/edge
4
+ with 50ms latency via ONNX Runtime or llama.cpp GGUF.
5
+ """
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ from shell_whisperer.prompts import LINUX_PROMPT, MACOS_PROMPT, WINDOWS_PROMPT
10
+
11
+ __all__ = [
12
+ "ShellWhisperer",
13
+ "LINUX_PROMPT",
14
+ "MACOS_PROMPT",
15
+ "WINDOWS_PROMPT",
16
+ ]
17
+
18
+
19
+ def __getattr__(name: str):
20
+ if name == "ShellWhisperer":
21
+ from shell_whisperer.inference import ShellWhisperer
22
+ return ShellWhisperer
23
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")