smart-linux-assistant 0.6.0__tar.gz → 0.7.1__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.
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/PKG-INFO +7 -5
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/README.md +6 -4
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/repositories/history_repository.py +49 -1
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/explainer.py +34 -6
- smart_linux_assistant-0.7.1/linux_assistant/utils/redactor.py +25 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/pyproject.toml +1 -1
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/PKG-INFO +7 -5
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/SOURCES.txt +2 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_history_repository.py +32 -1
- smart_linux_assistant-0.7.1/tests/test_redactor.py +29 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/LICENSE +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/cli/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/cli/main.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/settings.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/core/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/base.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/command_result.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/history_entry.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/repositories/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/command_executor.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/search.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/__init__.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/groq_client.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/logger.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/shell.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/setup.cfg +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/dependency_links.txt +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/entry_points.txt +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/requires.txt +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/top_level.txt +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_cli.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_command_executor.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_explainer.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_groq_client.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_search.py +0 -0
- {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_shell.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smart-linux-assistant
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management.
|
|
5
5
|
Author: Shubham Kumar Jha
|
|
6
6
|
License: MIT
|
|
@@ -212,8 +212,8 @@ Suggested fix:
|
|
|
212
212
|
- AI-powered explanations: implemented — `smart-linux explain` uses the Groq API (`llama-3.3-70b-versatile`) to generate plain-language explanations of commands and error messages, via `linux_assistant.services.explainer.Explainer`. Requires a user-supplied `GROQ_API_KEY` environment variable.
|
|
213
213
|
- AI-powered fix suggestions: implemented — `smart-linux fix` runs a failing command and suggests a corrected version; `smart-linux run --check --suggest-fix` offers the same suggestion inline as part of normal command execution. Both use `linux_assistant.services.explainer.Explainer.suggest_fix()`.
|
|
214
214
|
- AI-powered search: implemented — `smart-linux search` answers natural-language questions about Linux tasks via `linux_assistant.services.search.Searcher`.
|
|
215
|
-
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, and documented OS/privacy limitations across all AI-backed commands.
|
|
216
|
-
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI
|
|
215
|
+
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, regex-based secret redaction (scrubbing passwords and API keys before LLM transit), and documented OS/privacy limitations across all AI-backed commands.
|
|
216
|
+
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI Context Injection is implemented: `explain` and `fix` commands dynamically fetch the last 5 chronological commands to give the LLM workflow awareness, protected by graceful degradation if the database is locked.
|
|
217
217
|
- Additional AI features (documentation lookup) are planned but not yet implemented.
|
|
218
218
|
|
|
219
219
|
## Known Limitations
|
|
@@ -222,9 +222,11 @@ Suggested fix:
|
|
|
222
222
|
|
|
223
223
|
## Privacy Note
|
|
224
224
|
|
|
225
|
-
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing.
|
|
225
|
+
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing. The explain, fix, and search commands send your terminal queries to Groq's API for processing. Starting in v0.7.0, `explain` and `fix` also securely read your recent local command history to provide context-aware solutions.
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
Security First: Before any history leaves your machine, it passes through a local Regex Redactor `(linux_assistant.utils.redactor)` which automatically scrubs standard environment variables, inline passwords, and Bearer tokens, replacing them with [REDACTED]. However, you should still exercise caution and avoid running these commands on highly sensitive plaintext data.
|
|
228
|
+
|
|
229
|
+
Separately, `smart-linux run` records your command invocations (command text, exit code, duration, working directory, and truncated stderr) in a local SQLite database. `stdout` is never recorded. To disable history recording entirely, set `SMART_LINUX_NO_HISTORY=1`. To view or erase recorded history, use `smart-linux history` and `smart-linux history clear`.
|
|
228
230
|
|
|
229
231
|
## Install from PyPI
|
|
230
232
|
|
|
@@ -185,8 +185,8 @@ Suggested fix:
|
|
|
185
185
|
- AI-powered explanations: implemented — `smart-linux explain` uses the Groq API (`llama-3.3-70b-versatile`) to generate plain-language explanations of commands and error messages, via `linux_assistant.services.explainer.Explainer`. Requires a user-supplied `GROQ_API_KEY` environment variable.
|
|
186
186
|
- AI-powered fix suggestions: implemented — `smart-linux fix` runs a failing command and suggests a corrected version; `smart-linux run --check --suggest-fix` offers the same suggestion inline as part of normal command execution. Both use `linux_assistant.services.explainer.Explainer.suggest_fix()`.
|
|
187
187
|
- AI-powered search: implemented — `smart-linux search` answers natural-language questions about Linux tasks via `linux_assistant.services.search.Searcher`.
|
|
188
|
-
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, and documented OS/privacy limitations across all AI-backed commands.
|
|
189
|
-
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI
|
|
188
|
+
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, regex-based secret redaction (scrubbing passwords and API keys before LLM transit), and documented OS/privacy limitations across all AI-backed commands.
|
|
189
|
+
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI Context Injection is implemented: `explain` and `fix` commands dynamically fetch the last 5 chronological commands to give the LLM workflow awareness, protected by graceful degradation if the database is locked.
|
|
190
190
|
- Additional AI features (documentation lookup) are planned but not yet implemented.
|
|
191
191
|
|
|
192
192
|
## Known Limitations
|
|
@@ -195,9 +195,11 @@ Suggested fix:
|
|
|
195
195
|
|
|
196
196
|
## Privacy Note
|
|
197
197
|
|
|
198
|
-
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing.
|
|
198
|
+
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing. The explain, fix, and search commands send your terminal queries to Groq's API for processing. Starting in v0.7.0, `explain` and `fix` also securely read your recent local command history to provide context-aware solutions.
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
Security First: Before any history leaves your machine, it passes through a local Regex Redactor `(linux_assistant.utils.redactor)` which automatically scrubs standard environment variables, inline passwords, and Bearer tokens, replacing them with [REDACTED]. However, you should still exercise caution and avoid running these commands on highly sensitive plaintext data.
|
|
201
|
+
|
|
202
|
+
Separately, `smart-linux run` records your command invocations (command text, exit code, duration, working directory, and truncated stderr) in a local SQLite database. `stdout` is never recorded. To disable history recording entirely, set `SMART_LINUX_NO_HISTORY=1`. To view or erase recorded history, use `smart-linux history` and `smart-linux history clear`.
|
|
201
203
|
|
|
202
204
|
## Install from PyPI
|
|
203
205
|
|
|
@@ -170,4 +170,52 @@ class HistoryRepository:
|
|
|
170
170
|
with self._connect() as connection:
|
|
171
171
|
connection.execute("DELETE FROM history")
|
|
172
172
|
except sqlite3.Error as exc:
|
|
173
|
-
raise HistoryError(f"Could not clear command history: {exc}") from exc
|
|
173
|
+
raise HistoryError(f"Could not clear command history: {exc}") from exc
|
|
174
|
+
|
|
175
|
+
def get_recent_context(self, limit: int = 5) -> list['HistoryEntry']:
|
|
176
|
+
"""
|
|
177
|
+
Fetch the most recent commands in chronological order (oldest first).
|
|
178
|
+
This is specifically formatted for AI context injection.
|
|
179
|
+
"""
|
|
180
|
+
query = """
|
|
181
|
+
SELECT id, executed_at, command, exit_code, duration_seconds, working_directory, stderr_snippet
|
|
182
|
+
FROM (
|
|
183
|
+
SELECT * FROM history
|
|
184
|
+
ORDER BY executed_at DESC
|
|
185
|
+
LIMIT ?
|
|
186
|
+
)
|
|
187
|
+
ORDER BY executed_at ASC
|
|
188
|
+
"""
|
|
189
|
+
import sqlite3
|
|
190
|
+
from linux_assistant.exceptions import HistoryError
|
|
191
|
+
from linux_assistant.repositories.history_repository import HistoryEntry
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
with sqlite3.connect(self._db_path, timeout=2.0) as conn:
|
|
195
|
+
conn.row_factory = sqlite3.Row
|
|
196
|
+
cursor = conn.cursor()
|
|
197
|
+
cursor.execute(query, (limit,))
|
|
198
|
+
rows = cursor.fetchall()
|
|
199
|
+
|
|
200
|
+
# Explicitly map the SQLite rows to HistoryEntry objects
|
|
201
|
+
entries = []
|
|
202
|
+
for row in rows:
|
|
203
|
+
entries.append(
|
|
204
|
+
HistoryEntry(
|
|
205
|
+
id=row["id"],
|
|
206
|
+
executed_at=row["executed_at"],
|
|
207
|
+
command=row["command"],
|
|
208
|
+
exit_code=row["exit_code"],
|
|
209
|
+
duration_seconds=row["duration_seconds"],
|
|
210
|
+
working_directory=row["working_directory"],
|
|
211
|
+
stderr_snippet=row["stderr_snippet"]
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
return entries
|
|
215
|
+
|
|
216
|
+
except sqlite3.OperationalError as e:
|
|
217
|
+
# If the database is brand new and the table isn't created yet, return empty history
|
|
218
|
+
if "no such table" in str(e):
|
|
219
|
+
return []
|
|
220
|
+
# Otherwise, it's a real lock/access issue, so we raise it for graceful degradation
|
|
221
|
+
raise HistoryError(f"Database locked or inaccessible: {e}")
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/explainer.py
RENAMED
|
@@ -4,10 +4,12 @@ AI-powered explanations for Linux commands and error messages.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
import groq
|
|
7
|
-
|
|
8
|
-
from linux_assistant.exceptions import MissingAPIKeyError, ServiceError, ValidationError, RateLimitError
|
|
9
|
-
from linux_assistant.utils.logger import get_logger
|
|
7
|
+
import typer
|
|
10
8
|
from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client, truncate_for_api
|
|
9
|
+
from linux_assistant.exceptions import MissingAPIKeyError, ServiceError, ValidationError, RateLimitError, HistoryError
|
|
10
|
+
from linux_assistant.utils.logger import get_logger
|
|
11
|
+
from linux_assistant.repositories.history_repository import HistoryRepository
|
|
12
|
+
from linux_assistant.utils.redactor import scrub_secrets
|
|
11
13
|
|
|
12
14
|
logger = get_logger(__name__)
|
|
13
15
|
|
|
@@ -93,7 +95,8 @@ class Explainer:
|
|
|
93
95
|
|
|
94
96
|
def suggest_fix(self, command: str, error: str) -> str | None:
|
|
95
97
|
"""
|
|
96
|
-
Suggest a corrected version of a failed shell command
|
|
98
|
+
Suggest a corrected version of a failed shell command,
|
|
99
|
+
utilizing recent command history for context if available.
|
|
97
100
|
"""
|
|
98
101
|
command = command.strip()
|
|
99
102
|
|
|
@@ -103,16 +106,41 @@ class Explainer:
|
|
|
103
106
|
raise ValidationError("Command to fix cannot be empty.")
|
|
104
107
|
|
|
105
108
|
error = truncate_for_api(error, keep_end=True)
|
|
106
|
-
|
|
107
109
|
user_content = f"Command: {command}\nError: {error.strip()}"
|
|
108
110
|
|
|
111
|
+
# Fetch History
|
|
112
|
+
history_context = ""
|
|
113
|
+
try:
|
|
114
|
+
repo = HistoryRepository()
|
|
115
|
+
recent_entries = repo.get_recent_context(limit=5)
|
|
116
|
+
|
|
117
|
+
if recent_entries:
|
|
118
|
+
scrubbed_lines = []
|
|
119
|
+
for entry in recent_entries:
|
|
120
|
+
status = "SUCCESS" if entry.exit_code == 0 else f"FAILED ({entry.exit_code})"
|
|
121
|
+
scrubbed_cmd = scrub_secrets(entry.command)
|
|
122
|
+
scrubbed_lines.append(f"[{status}] {scrubbed_cmd}")
|
|
123
|
+
|
|
124
|
+
history_context = "\n".join(scrubbed_lines)
|
|
125
|
+
except HistoryError:
|
|
126
|
+
# GRACEFUL DEGRADATION: Print a warning, but don't crash
|
|
127
|
+
typer.secho(
|
|
128
|
+
"⚠ Warning: Could not read local history (database locked). Falling back to generic explanation.",
|
|
129
|
+
fg=typer.colors.YELLOW
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Inject into the System Prompt
|
|
133
|
+
dynamic_system_prompt = FIX_SYSTEM_PROMPT
|
|
134
|
+
if history_context:
|
|
135
|
+
dynamic_system_prompt += f"\n\nUser's Recent Command History (Chronological):\n{history_context}"
|
|
136
|
+
|
|
109
137
|
logger.info("Requesting fix suggestion for: %s", command)
|
|
110
138
|
|
|
111
139
|
try:
|
|
112
140
|
response = self._client.chat.completions.create(
|
|
113
141
|
model=GROQ_MODEL,
|
|
114
142
|
messages=[
|
|
115
|
-
{"role": "system", "content":
|
|
143
|
+
{"role": "system", "content": dynamic_system_prompt},
|
|
116
144
|
{"role": "user", "content": user_content},
|
|
117
145
|
],
|
|
118
146
|
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
def scrub_secrets(command: str) -> str:
|
|
4
|
+
"""
|
|
5
|
+
Scans a raw terminal command and replaces sensitive API keys, passwords, tokens with [REDACTED] to ensure safe LLM transit.
|
|
6
|
+
"""
|
|
7
|
+
command = re.sub(
|
|
8
|
+
r'(?i)([A-Z0-9_]*(?:KEY|TOKEN|PASSWORD|SECRET|PASS)[A-Z0-9_]*\s*=\s*["\']?)[^"\'\s]+(["\']?)',
|
|
9
|
+
r'\g<1>[REDACTED]\g<2>',
|
|
10
|
+
command
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
command = re.sub(
|
|
14
|
+
r'(-p|--password=?)\s*(["\']?)[^"\'\s]+(["\']?)',
|
|
15
|
+
r'\1\2[REDACTED]\3',
|
|
16
|
+
command
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
command = re.sub(
|
|
20
|
+
r'([Bb]earer\s+)(["\']?)[^"\'\s]+(["\']?)',
|
|
21
|
+
r'\1\2[REDACTED]\3',
|
|
22
|
+
command
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return command
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "smart-linux-assistant"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.1"
|
|
8
8
|
description = "An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smart-linux-assistant
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: An AI-powered Linux productivity assistant for command analysis, troubleshooting, and knowledge management.
|
|
5
5
|
Author: Shubham Kumar Jha
|
|
6
6
|
License: MIT
|
|
@@ -212,8 +212,8 @@ Suggested fix:
|
|
|
212
212
|
- AI-powered explanations: implemented — `smart-linux explain` uses the Groq API (`llama-3.3-70b-versatile`) to generate plain-language explanations of commands and error messages, via `linux_assistant.services.explainer.Explainer`. Requires a user-supplied `GROQ_API_KEY` environment variable.
|
|
213
213
|
- AI-powered fix suggestions: implemented — `smart-linux fix` runs a failing command and suggests a corrected version; `smart-linux run --check --suggest-fix` offers the same suggestion inline as part of normal command execution. Both use `linux_assistant.services.explainer.Explainer.suggest_fix()`.
|
|
214
214
|
- AI-powered search: implemented — `smart-linux search` answers natural-language questions about Linux tasks via `linux_assistant.services.search.Searcher`.
|
|
215
|
-
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, and documented OS/privacy limitations across all AI-backed commands.
|
|
216
|
-
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI
|
|
215
|
+
- Production hardening: implemented — API timeouts, retry logic, rate-limit-specific handling, input truncation, regex-based secret redaction (scrubbing passwords and API keys before LLM transit), and documented OS/privacy limitations across all AI-backed commands.
|
|
216
|
+
- Command history: implemented — `smart-linux run` records every invocation locally via `linux_assistant.repositories.history_repository.HistoryRepository` (SQLite-backed, FIFO-capped at 5,000 rows). View with `smart-linux history` (supports `--failures-only`), erase with `smart-linux history clear`, or disable entirely via `SMART_LINUX_NO_HISTORY=1`. AI Context Injection is implemented: `explain` and `fix` commands dynamically fetch the last 5 chronological commands to give the LLM workflow awareness, protected by graceful degradation if the database is locked.
|
|
217
217
|
- Additional AI features (documentation lookup) are planned but not yet implemented.
|
|
218
218
|
|
|
219
219
|
## Known Limitations
|
|
@@ -222,9 +222,11 @@ Suggested fix:
|
|
|
222
222
|
|
|
223
223
|
## Privacy Note
|
|
224
224
|
|
|
225
|
-
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing.
|
|
225
|
+
The `explain`, `fix`, and `search` commands send the command text, error output, or your query to Groq's API for processing. The explain, fix, and search commands send your terminal queries to Groq's API for processing. Starting in v0.7.0, `explain` and `fix` also securely read your recent local command history to provide context-aware solutions.
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
Security First: Before any history leaves your machine, it passes through a local Regex Redactor `(linux_assistant.utils.redactor)` which automatically scrubs standard environment variables, inline passwords, and Bearer tokens, replacing them with [REDACTED]. However, you should still exercise caution and avoid running these commands on highly sensitive plaintext data.
|
|
228
|
+
|
|
229
|
+
Separately, `smart-linux run` records your command invocations (command text, exit code, duration, working directory, and truncated stderr) in a local SQLite database. `stdout` is never recorded. To disable history recording entirely, set `SMART_LINUX_NO_HISTORY=1`. To view or erase recorded history, use `smart-linux history` and `smart-linux history clear`.
|
|
228
230
|
|
|
229
231
|
## Install from PyPI
|
|
230
232
|
|
|
@@ -21,6 +21,7 @@ linux_assistant/services/search.py
|
|
|
21
21
|
linux_assistant/utils/__init__.py
|
|
22
22
|
linux_assistant/utils/groq_client.py
|
|
23
23
|
linux_assistant/utils/logger.py
|
|
24
|
+
linux_assistant/utils/redactor.py
|
|
24
25
|
linux_assistant/utils/shell.py
|
|
25
26
|
smart_linux_assistant.egg-info/PKG-INFO
|
|
26
27
|
smart_linux_assistant.egg-info/SOURCES.txt
|
|
@@ -33,5 +34,6 @@ tests/test_command_executor.py
|
|
|
33
34
|
tests/test_explainer.py
|
|
34
35
|
tests/test_groq_client.py
|
|
35
36
|
tests/test_history_repository.py
|
|
37
|
+
tests/test_redactor.py
|
|
36
38
|
tests/test_search.py
|
|
37
39
|
tests/test_shell.py
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_history_repository.py
RENAMED
|
@@ -218,4 +218,35 @@ class TestClear:
|
|
|
218
218
|
|
|
219
219
|
repo.clear()
|
|
220
220
|
|
|
221
|
-
assert repo.list_recent() == []
|
|
221
|
+
assert repo.list_recent() == []
|
|
222
|
+
|
|
223
|
+
class TestGetRecentContext:
|
|
224
|
+
"""Tests for HistoryRepository.get_recent_context()."""
|
|
225
|
+
|
|
226
|
+
def test_get_recent_context_returns_chronological_order(self, repo: HistoryRepository) -> None:
|
|
227
|
+
repo.clear()
|
|
228
|
+
|
|
229
|
+
# Simulate a user typing 3 commands over time
|
|
230
|
+
repo.record(
|
|
231
|
+
command="mkdir my_project", exit_code=0, duration_seconds=0.1,
|
|
232
|
+
working_directory=TEST_CWD, stderr=""
|
|
233
|
+
)
|
|
234
|
+
repo.record(
|
|
235
|
+
command="cd my_project", exit_code=0, duration_seconds=0.1,
|
|
236
|
+
working_directory=TEST_CWD, stderr=""
|
|
237
|
+
)
|
|
238
|
+
repo.record(
|
|
239
|
+
command="npm run build", exit_code=1, duration_seconds=1.2,
|
|
240
|
+
working_directory=TEST_CWD, stderr="missing package.json"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Fetch the last 2 commands for context
|
|
244
|
+
context = repo.get_recent_context(limit=2)
|
|
245
|
+
|
|
246
|
+
assert len(context) == 2
|
|
247
|
+
# The AI needs to read them in the order they happened (Chronological)
|
|
248
|
+
assert context[0].command == "cd my_project"
|
|
249
|
+
assert context[1].command == "npm run build"
|
|
250
|
+
|
|
251
|
+
def test_get_recent_context_empty_db(self, repo: HistoryRepository) -> None:
|
|
252
|
+
assert repo.get_recent_context(limit=5) == []
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from linux_assistant.utils.redactor import scrub_secrets
|
|
3
|
+
|
|
4
|
+
def test_scrub_export_statements():
|
|
5
|
+
raw = 'export GROQ_API_KEY="gsk_123456789"'
|
|
6
|
+
expected = 'export GROQ_API_KEY="[REDACTED]"'
|
|
7
|
+
assert scrub_secrets(raw) == expected
|
|
8
|
+
|
|
9
|
+
def test_scrub_inline_passwords():
|
|
10
|
+
raw = 'mysql -u admin -pMySecretPassword123 database'
|
|
11
|
+
# We want to catch standard password flags
|
|
12
|
+
assert "[REDACTED]" in scrub_secrets(raw)
|
|
13
|
+
assert "MySecretPassword123" not in scrub_secrets(raw)
|
|
14
|
+
|
|
15
|
+
def test_scrub_bearer_tokens():
|
|
16
|
+
raw = 'curl -H "Authorization: Bearer eyJhbGciOi..." http://api.com'
|
|
17
|
+
expected = 'curl -H "Authorization: Bearer [REDACTED]" http://api.com'
|
|
18
|
+
assert scrub_secrets(raw) == expected
|
|
19
|
+
|
|
20
|
+
def test_leave_safe_commands_alone():
|
|
21
|
+
raw = 'ls -la /var/log'
|
|
22
|
+
assert scrub_secrets(raw) == raw
|
|
23
|
+
|
|
24
|
+
def test_multiple_secrets_in_one_line():
|
|
25
|
+
raw = 'export DB_PASS=pass123 && curl -H "Authorization: Bearer abc" http://x'
|
|
26
|
+
scrubbed = scrub_secrets(raw)
|
|
27
|
+
assert "pass123" not in scrubbed
|
|
28
|
+
assert "abc" not in scrubbed
|
|
29
|
+
assert scrubbed.count("[REDACTED]") == 2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/settings.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/core/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/base.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/command_result.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/history_entry.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/repositories/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/search.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/groq_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|