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.
Files changed (41) hide show
  1. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/PKG-INFO +7 -5
  2. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/README.md +6 -4
  3. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/repositories/history_repository.py +49 -1
  4. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/explainer.py +34 -6
  5. smart_linux_assistant-0.7.1/linux_assistant/utils/redactor.py +25 -0
  6. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/pyproject.toml +1 -1
  7. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/PKG-INFO +7 -5
  8. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/SOURCES.txt +2 -0
  9. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_history_repository.py +32 -1
  10. smart_linux_assistant-0.7.1/tests/test_redactor.py +29 -0
  11. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/LICENSE +0 -0
  12. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/__init__.py +0 -0
  13. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/cli/__init__.py +0 -0
  14. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/cli/main.py +0 -0
  15. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/__init__.py +0 -0
  16. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/config/settings.py +0 -0
  17. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/core/__init__.py +0 -0
  18. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/__init__.py +0 -0
  19. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/exceptions/base.py +0 -0
  20. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/__init__.py +0 -0
  21. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/command_result.py +0 -0
  22. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/models/history_entry.py +0 -0
  23. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/repositories/__init__.py +0 -0
  24. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/__init__.py +0 -0
  25. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/command_executor.py +0 -0
  26. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/services/search.py +0 -0
  27. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/__init__.py +0 -0
  28. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/groq_client.py +0 -0
  29. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/logger.py +0 -0
  30. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/linux_assistant/utils/shell.py +0 -0
  31. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/setup.cfg +0 -0
  32. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/dependency_links.txt +0 -0
  33. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/entry_points.txt +0 -0
  34. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/requires.txt +0 -0
  35. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/smart_linux_assistant.egg-info/top_level.txt +0 -0
  36. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_cli.py +0 -0
  37. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_command_executor.py +0 -0
  38. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_explainer.py +0 -0
  39. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_groq_client.py +0 -0
  40. {smart_linux_assistant-0.6.0 → smart_linux_assistant-0.7.1}/tests/test_search.py +0 -0
  41. {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.6.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-powered use of this history (e.g. `explain`/`fix` referencing past failures) is planned for a future version but not yet implemented.
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. Avoid running these commands on text that contains secrets, passwords, or sensitive data, since that content leaves your machine.
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
- Separately, `smart-linux run` records a local history of command invocations (command text, exit code, duration, working directory, and for failures only — a truncated stderr snippet) in a SQLite database on your machine. This data never leaves your machine and is not sent to any API. `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`.
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-powered use of this history (e.g. `explain`/`fix` referencing past failures) is planned for a future version but not yet implemented.
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. Avoid running these commands on text that contains secrets, passwords, or sensitive data, since that content leaves your machine.
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
- Separately, `smart-linux run` records a local history of command invocations (command text, exit code, duration, working directory, and for failures only — a truncated stderr snippet) in a SQLite database on your machine. This data never leaves your machine and is not sent to any API. `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`.
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}")
@@ -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
- from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client
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": FIX_SYSTEM_PROMPT},
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.6.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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart-linux-assistant
3
- Version: 0.6.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-powered use of this history (e.g. `explain`/`fix` referencing past failures) is planned for a future version but not yet implemented.
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. Avoid running these commands on text that contains secrets, passwords, or sensitive data, since that content leaves your machine.
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
- Separately, `smart-linux run` records a local history of command invocations (command text, exit code, duration, working directory, and for failures only — a truncated stderr snippet) in a SQLite database on your machine. This data never leaves your machine and is not sent to any API. `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`.
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
@@ -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