smart-linux-assistant 0.8.1__tar.gz → 0.8.2__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.8.1/smart_linux_assistant.egg-info → smart_linux_assistant-0.8.2}/PKG-INFO +32 -1
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/README.md +31 -0
- smart_linux_assistant-0.8.2/linux_assistant/config/defaults.py +37 -0
- smart_linux_assistant-0.8.2/linux_assistant/config/loader.py +64 -0
- smart_linux_assistant-0.8.2/linux_assistant/config/models.py +55 -0
- smart_linux_assistant-0.8.2/linux_assistant/config/validator.py +154 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/explainer.py +5 -1
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/search.py +5 -3
- smart_linux_assistant-0.8.2/linux_assistant/utils/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/groq_client.py +6 -6
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/pyproject.toml +1 -1
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2/smart_linux_assistant.egg-info}/PKG-INFO +32 -1
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/SOURCES.txt +6 -0
- smart_linux_assistant-0.8.2/tests/test_config_validator.py +57 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/LICENSE +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/cli/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/cli/main.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/__init__.py +0 -0
- /smart_linux_assistant-0.8.1/linux_assistant/core/__init__.py → /smart_linux_assistant-0.8.2/linux_assistant/config/exceptions.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/settings.py +0 -0
- {smart_linux_assistant-0.8.1/linux_assistant/utils → smart_linux_assistant-0.8.2/linux_assistant/core}/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/core/safety.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/base.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/command_result.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/history_entry.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/repositories/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/repositories/history_repository.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/__init__.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/command_executor.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/logger.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/redactor.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/shell.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/setup.cfg +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/dependency_links.txt +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/entry_points.txt +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/requires.txt +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/smart_linux_assistant.egg-info/top_level.txt +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_cli.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_command_executor.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_explainer.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_groq_client.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_history_repository.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_redactor.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_safety.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_search.py +0 -0
- {smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_shell.py +0 -0
{smart_linux_assistant-0.8.1/smart_linux_assistant.egg-info → smart_linux_assistant-0.8.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smart-linux-assistant
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
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
|
|
@@ -100,6 +100,37 @@ This project does not require any environment variables for its core CLI functio
|
|
|
100
100
|
| --- | --- | --- |
|
|
101
101
|
| (none) | No required environment variables for CLI execution | - |
|
|
102
102
|
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
|
|
107
|
+
|
|
108
|
+
By default, the application looks for:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
~/.config/smart-linux-assistant/config.toml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
A complete example configuration is available in the repository as:
|
|
115
|
+
```
|
|
116
|
+
config.toml.example
|
|
117
|
+
```
|
|
118
|
+
Copy it into your local configuration directory and modify only the values you want to customize.
|
|
119
|
+
Example:
|
|
120
|
+
```
|
|
121
|
+
mkdir -p ~/.config/smart-linux-assistant
|
|
122
|
+
cp config.toml.example ~/.config/smart-linux-assistant/config.toml
|
|
123
|
+
```
|
|
124
|
+
Current configurable options include:
|
|
125
|
+
|
|
126
|
+
- AI provider
|
|
127
|
+
- AI model
|
|
128
|
+
- API timeout
|
|
129
|
+
- Retry count
|
|
130
|
+
- Command history settings
|
|
131
|
+
- Logging verbosity
|
|
132
|
+
- Privacy (secret redaction)
|
|
133
|
+
|
|
103
134
|
## Usage / API Reference
|
|
104
135
|
|
|
105
136
|
The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
|
|
@@ -73,6 +73,37 @@ This project does not require any environment variables for its core CLI functio
|
|
|
73
73
|
| --- | --- | --- |
|
|
74
74
|
| (none) | No required environment variables for CLI execution | - |
|
|
75
75
|
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
|
|
80
|
+
|
|
81
|
+
By default, the application looks for:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
~/.config/smart-linux-assistant/config.toml
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A complete example configuration is available in the repository as:
|
|
88
|
+
```
|
|
89
|
+
config.toml.example
|
|
90
|
+
```
|
|
91
|
+
Copy it into your local configuration directory and modify only the values you want to customize.
|
|
92
|
+
Example:
|
|
93
|
+
```
|
|
94
|
+
mkdir -p ~/.config/smart-linux-assistant
|
|
95
|
+
cp config.toml.example ~/.config/smart-linux-assistant/config.toml
|
|
96
|
+
```
|
|
97
|
+
Current configurable options include:
|
|
98
|
+
|
|
99
|
+
- AI provider
|
|
100
|
+
- AI model
|
|
101
|
+
- API timeout
|
|
102
|
+
- Retry count
|
|
103
|
+
- Command history settings
|
|
104
|
+
- Logging verbosity
|
|
105
|
+
- Privacy (secret redaction)
|
|
106
|
+
|
|
76
107
|
## Usage / API Reference
|
|
77
108
|
|
|
78
109
|
The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from linux_assistant.config.models import (
|
|
4
|
+
AIConfig,
|
|
5
|
+
AppConfig,
|
|
6
|
+
HistoryConfig,
|
|
7
|
+
LoggingConfig,
|
|
8
|
+
PrivacyConfig,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DEFAULT_AI_CONFIG = AIConfig(
|
|
13
|
+
provider="groq",
|
|
14
|
+
model="llama-3.3-70b-versatile",
|
|
15
|
+
timeout_seconds=30.0,
|
|
16
|
+
max_retries=3,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
DEFAULT_HISTORY_CONFIG = HistoryConfig(
|
|
20
|
+
enabled=True,
|
|
21
|
+
max_entries=5000,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
DEFAULT_LOGGING_CONFIG = LoggingConfig(
|
|
25
|
+
verbose=False,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
DEFAULT_PRIVACY_CONFIG = PrivacyConfig(
|
|
29
|
+
redaction_enabled=True,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
DEFAULT_CONFIG = AppConfig(
|
|
33
|
+
ai=DEFAULT_AI_CONFIG,
|
|
34
|
+
history=DEFAULT_HISTORY_CONFIG,
|
|
35
|
+
logging=DEFAULT_LOGGING_CONFIG,
|
|
36
|
+
privacy=DEFAULT_PRIVACY_CONFIG,
|
|
37
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import tomllib
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from linux_assistant.config.defaults import DEFAULT_CONFIG
|
|
8
|
+
from linux_assistant.config.models import AppConfig
|
|
9
|
+
from linux_assistant.config.validator import validate_config
|
|
10
|
+
from linux_assistant.exceptions import ConfigurationError
|
|
11
|
+
|
|
12
|
+
CONFIG_FILE_NAME = "config.toml"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_config_path() -> Path:
|
|
16
|
+
"""
|
|
17
|
+
Return the location of the user configuration file.
|
|
18
|
+
|
|
19
|
+
The configuration file follows the XDG Base Directory specification.
|
|
20
|
+
If XDG_CONFIG_HOME is not set, ~/.config is used.
|
|
21
|
+
"""
|
|
22
|
+
xdg_config_home = os.getenv("XDG_CONFIG_HOME")
|
|
23
|
+
|
|
24
|
+
if xdg_config_home:
|
|
25
|
+
config_home = Path(xdg_config_home)
|
|
26
|
+
else:
|
|
27
|
+
config_home = Path.home() / ".config"
|
|
28
|
+
|
|
29
|
+
return config_home / "smart-linux-assistant" / CONFIG_FILE_NAME
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load_config() -> AppConfig:
|
|
33
|
+
"""
|
|
34
|
+
Load the application configuration.
|
|
35
|
+
|
|
36
|
+
Returns the default configuration if no configuration file exists.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ConfigurationError:
|
|
40
|
+
If the configuration file cannot be read or contains
|
|
41
|
+
invalid TOML or invalid configuration values.
|
|
42
|
+
"""
|
|
43
|
+
config_path = get_config_path()
|
|
44
|
+
|
|
45
|
+
if not config_path.exists():
|
|
46
|
+
return DEFAULT_CONFIG
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
with config_path.open("rb") as file:
|
|
50
|
+
data = tomllib.load(file)
|
|
51
|
+
|
|
52
|
+
except tomllib.TOMLDecodeError as exc:
|
|
53
|
+
raise ConfigurationError(
|
|
54
|
+
f"Invalid TOML syntax in '{config_path}'."
|
|
55
|
+
) from exc
|
|
56
|
+
|
|
57
|
+
except OSError as exc:
|
|
58
|
+
raise ConfigurationError(
|
|
59
|
+
f"Unable to read configuration file '{config_path}'."
|
|
60
|
+
) from exc
|
|
61
|
+
|
|
62
|
+
print(f"Using config: {config_path}")
|
|
63
|
+
print(f"Model: {data['ai']['model']}")
|
|
64
|
+
return validate_config(data)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True, slots=True)
|
|
7
|
+
class PrivacyConfig:
|
|
8
|
+
"""
|
|
9
|
+
Privacy-related configuration.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
redaction_enabled: bool
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True, slots=True)
|
|
16
|
+
class LoggingConfig:
|
|
17
|
+
"""
|
|
18
|
+
Logging-related configuration.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
verbose: bool
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, slots=True)
|
|
25
|
+
class HistoryConfig:
|
|
26
|
+
"""
|
|
27
|
+
History-related configuration.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
enabled: bool
|
|
31
|
+
max_entries: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class AIConfig:
|
|
36
|
+
"""
|
|
37
|
+
AI provider configuration.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
provider: str
|
|
41
|
+
model: str
|
|
42
|
+
timeout_seconds: float
|
|
43
|
+
max_retries: int
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True, slots=True)
|
|
47
|
+
class AppConfig:
|
|
48
|
+
"""
|
|
49
|
+
Root application configuration.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
ai: AIConfig
|
|
53
|
+
history: HistoryConfig
|
|
54
|
+
logging: LoggingConfig
|
|
55
|
+
privacy: PrivacyConfig
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from linux_assistant.config.defaults import DEFAULT_CONFIG
|
|
6
|
+
from linux_assistant.config.models import (
|
|
7
|
+
AIConfig,
|
|
8
|
+
AppConfig,
|
|
9
|
+
HistoryConfig,
|
|
10
|
+
LoggingConfig,
|
|
11
|
+
PrivacyConfig,
|
|
12
|
+
)
|
|
13
|
+
from linux_assistant.exceptions import ConfigurationError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def validate_config(data: dict[str, Any]) -> AppConfig:
|
|
17
|
+
"""
|
|
18
|
+
Validate and normalize a parsed TOML configuration.
|
|
19
|
+
Missing sections and fields fall back to DEFAULT_CONFIG.
|
|
20
|
+
Invalid field types raise ConfigurationError.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
if not isinstance(data, dict):
|
|
24
|
+
raise ConfigurationError(
|
|
25
|
+
"Configuration root must be a TOML table."
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
ai = data.get("ai", {})
|
|
29
|
+
history = data.get("history", {})
|
|
30
|
+
logging = data.get("logging", {})
|
|
31
|
+
privacy = data.get("privacy", {})
|
|
32
|
+
|
|
33
|
+
_require_table(ai, "ai")
|
|
34
|
+
_require_table(history, "history")
|
|
35
|
+
_require_table(logging, "logging")
|
|
36
|
+
_require_table(privacy, "privacy")
|
|
37
|
+
|
|
38
|
+
return AppConfig(
|
|
39
|
+
ai=AIConfig(
|
|
40
|
+
provider=_get_str(
|
|
41
|
+
ai,
|
|
42
|
+
"provider",
|
|
43
|
+
DEFAULT_CONFIG.ai.provider,
|
|
44
|
+
),
|
|
45
|
+
model=_get_str(
|
|
46
|
+
ai,
|
|
47
|
+
"model",
|
|
48
|
+
DEFAULT_CONFIG.ai.model,
|
|
49
|
+
),
|
|
50
|
+
timeout_seconds=_get_float(
|
|
51
|
+
ai,
|
|
52
|
+
"timeout_seconds",
|
|
53
|
+
DEFAULT_CONFIG.ai.timeout_seconds,
|
|
54
|
+
),
|
|
55
|
+
max_retries=_get_int(
|
|
56
|
+
ai,
|
|
57
|
+
"max_retries",
|
|
58
|
+
DEFAULT_CONFIG.ai.max_retries,
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
history=HistoryConfig(
|
|
62
|
+
enabled=_get_bool(
|
|
63
|
+
history,
|
|
64
|
+
"enabled",
|
|
65
|
+
DEFAULT_CONFIG.history.enabled,
|
|
66
|
+
),
|
|
67
|
+
max_entries=_get_int(
|
|
68
|
+
history,
|
|
69
|
+
"max_entries",
|
|
70
|
+
DEFAULT_CONFIG.history.max_entries,
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
logging=LoggingConfig(
|
|
74
|
+
verbose=_get_bool(
|
|
75
|
+
logging,
|
|
76
|
+
"verbose",
|
|
77
|
+
DEFAULT_CONFIG.logging.verbose,
|
|
78
|
+
),
|
|
79
|
+
),
|
|
80
|
+
privacy=PrivacyConfig(
|
|
81
|
+
redaction_enabled=_get_bool(
|
|
82
|
+
privacy,
|
|
83
|
+
"redaction_enabled",
|
|
84
|
+
DEFAULT_CONFIG.privacy.redaction_enabled,
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _require_table(value: Any, section: str) -> None:
|
|
91
|
+
if not isinstance(value, dict):
|
|
92
|
+
raise ConfigurationError(
|
|
93
|
+
f"Configuration section '{section}' must be a TOML table."
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _get_str(
|
|
98
|
+
table: dict[str, Any],
|
|
99
|
+
key: str,
|
|
100
|
+
default: str,
|
|
101
|
+
) -> str:
|
|
102
|
+
value = table.get(key, default)
|
|
103
|
+
|
|
104
|
+
if not isinstance(value, str):
|
|
105
|
+
raise ConfigurationError(
|
|
106
|
+
f"'{key}' must be a string."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return value
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _get_int(
|
|
113
|
+
table: dict[str, Any],
|
|
114
|
+
key: str,
|
|
115
|
+
default: int,
|
|
116
|
+
) -> int:
|
|
117
|
+
value = table.get(key, default)
|
|
118
|
+
|
|
119
|
+
if not isinstance(value, int):
|
|
120
|
+
raise ConfigurationError(
|
|
121
|
+
f"'{key}' must be an integer."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return value
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _get_float(
|
|
128
|
+
table: dict[str, Any],
|
|
129
|
+
key: str,
|
|
130
|
+
default: float,
|
|
131
|
+
) -> float:
|
|
132
|
+
value = table.get(key, default)
|
|
133
|
+
|
|
134
|
+
if not isinstance(value, (int, float)):
|
|
135
|
+
raise ConfigurationError(
|
|
136
|
+
f"'{key}' must be a number."
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return float(value)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _get_bool(
|
|
143
|
+
table: dict[str, Any],
|
|
144
|
+
key: str,
|
|
145
|
+
default: bool,
|
|
146
|
+
) -> bool:
|
|
147
|
+
value = table.get(key, default)
|
|
148
|
+
|
|
149
|
+
if not isinstance(value, bool):
|
|
150
|
+
raise ConfigurationError(
|
|
151
|
+
f"'{key}' must be a boolean."
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return value
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/explainer.py
RENAMED
|
@@ -4,7 +4,11 @@ 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
|
|
7
|
+
from linux_assistant.utils.groq_client import (
|
|
8
|
+
GROQ_MODEL,
|
|
9
|
+
build_groq_client,
|
|
10
|
+
truncate_for_api,
|
|
11
|
+
)
|
|
8
12
|
from linux_assistant.exceptions import MissingAPIKeyError, ServiceError, ValidationError, RateLimitError, HistoryError
|
|
9
13
|
from linux_assistant.utils.logger import get_logger
|
|
10
14
|
from linux_assistant.repositories.history_repository import HistoryRepository
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/search.py
RENAMED
|
@@ -5,10 +5,12 @@ AI-powered natural-language search for Linux commands and tasks.
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
import groq
|
|
7
7
|
from linux_assistant.exceptions import ServiceError, ValidationError, RateLimitError
|
|
8
|
-
from linux_assistant.utils.groq_client import
|
|
8
|
+
from linux_assistant.utils.groq_client import (
|
|
9
|
+
GROQ_MODEL,
|
|
10
|
+
build_groq_client,
|
|
11
|
+
truncate_for_api,
|
|
12
|
+
)
|
|
9
13
|
from linux_assistant.utils.logger import get_logger
|
|
10
|
-
from linux_assistant.utils.groq_client import GROQ_MODEL, build_groq_client, truncate_for_api
|
|
11
|
-
|
|
12
14
|
logger = get_logger(__name__)
|
|
13
15
|
|
|
14
16
|
SEARCH_SYSTEM_PROMPT = """You are a Linux command lookup tool operating in a raw terminal. The user will describe a desired action in plain language. Your objective is to provide a concrete, ready-to-run command and a brief explanation.
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/groq_client.py
RENAMED
|
@@ -5,14 +5,14 @@ Shared Groq client construction for AI-powered services.
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
import os
|
|
7
7
|
from groq import Groq
|
|
8
|
+
from linux_assistant.config.loader import load_config
|
|
8
9
|
from linux_assistant.exceptions import MissingAPIKeyError
|
|
9
10
|
|
|
10
11
|
GROQ_API_KEY = "GROQ_API_KEY"
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
CONFIG = load_config()
|
|
13
|
+
GROQ_MODEL = CONFIG.ai.model
|
|
13
14
|
MAX_INPUT_CHARACTERS = 4000
|
|
14
|
-
|
|
15
|
-
MAX_RETRIES = 2
|
|
15
|
+
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def build_groq_client() -> Groq:
|
|
@@ -34,8 +34,8 @@ def build_groq_client() -> Groq:
|
|
|
34
34
|
|
|
35
35
|
return Groq(
|
|
36
36
|
api_key=api_key,
|
|
37
|
-
timeout=
|
|
38
|
-
max_retries=
|
|
37
|
+
timeout=CONFIG.ai.timeout_seconds,
|
|
38
|
+
max_retries=CONFIG.ai.max_retries,
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
def truncate_for_api(text: str, *, keep_end: bool = False) -> str:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "smart-linux-assistant"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.2"
|
|
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.8.1 → smart_linux_assistant-0.8.2/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.8.
|
|
3
|
+
Version: 0.8.2
|
|
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
|
|
@@ -100,6 +100,37 @@ This project does not require any environment variables for its core CLI functio
|
|
|
100
100
|
| --- | --- | --- |
|
|
101
101
|
| (none) | No required environment variables for CLI execution | - |
|
|
102
102
|
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Smart Linux Assistant supports a user configuration file. If no configuration file is present, the application automatically falls back to built-in defaults.
|
|
107
|
+
|
|
108
|
+
By default, the application looks for:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
~/.config/smart-linux-assistant/config.toml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
A complete example configuration is available in the repository as:
|
|
115
|
+
```
|
|
116
|
+
config.toml.example
|
|
117
|
+
```
|
|
118
|
+
Copy it into your local configuration directory and modify only the values you want to customize.
|
|
119
|
+
Example:
|
|
120
|
+
```
|
|
121
|
+
mkdir -p ~/.config/smart-linux-assistant
|
|
122
|
+
cp config.toml.example ~/.config/smart-linux-assistant/config.toml
|
|
123
|
+
```
|
|
124
|
+
Current configurable options include:
|
|
125
|
+
|
|
126
|
+
- AI provider
|
|
127
|
+
- AI model
|
|
128
|
+
- API timeout
|
|
129
|
+
- Retry count
|
|
130
|
+
- Command history settings
|
|
131
|
+
- Logging verbosity
|
|
132
|
+
- Privacy (secret redaction)
|
|
133
|
+
|
|
103
134
|
## Usage / API Reference
|
|
104
135
|
|
|
105
136
|
The project exposes the console scripts `smart-linux` and `sla` (configured in `pyproject.toml`).
|
|
@@ -5,7 +5,12 @@ linux_assistant/__init__.py
|
|
|
5
5
|
linux_assistant/cli/__init__.py
|
|
6
6
|
linux_assistant/cli/main.py
|
|
7
7
|
linux_assistant/config/__init__.py
|
|
8
|
+
linux_assistant/config/defaults.py
|
|
9
|
+
linux_assistant/config/exceptions.py
|
|
10
|
+
linux_assistant/config/loader.py
|
|
11
|
+
linux_assistant/config/models.py
|
|
8
12
|
linux_assistant/config/settings.py
|
|
13
|
+
linux_assistant/config/validator.py
|
|
9
14
|
linux_assistant/core/__init__.py
|
|
10
15
|
linux_assistant/core/safety.py
|
|
11
16
|
linux_assistant/exceptions/__init__.py
|
|
@@ -32,6 +37,7 @@ smart_linux_assistant.egg-info/requires.txt
|
|
|
32
37
|
smart_linux_assistant.egg-info/top_level.txt
|
|
33
38
|
tests/test_cli.py
|
|
34
39
|
tests/test_command_executor.py
|
|
40
|
+
tests/test_config_validator.py
|
|
35
41
|
tests/test_explainer.py
|
|
36
42
|
tests/test_groq_client.py
|
|
37
43
|
tests/test_history_repository.py
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from linux_assistant.config.defaults import DEFAULT_CONFIG
|
|
4
|
+
from linux_assistant.config.validator import validate_config
|
|
5
|
+
from linux_assistant.exceptions import ConfigurationError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_empty_configuration_returns_defaults() -> None:
|
|
9
|
+
config = validate_config({})
|
|
10
|
+
|
|
11
|
+
assert config == DEFAULT_CONFIG
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_partial_configuration_overrides_defaults() -> None:
|
|
15
|
+
config = validate_config(
|
|
16
|
+
{
|
|
17
|
+
"logging": {
|
|
18
|
+
"verbose": True,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
assert config.logging.verbose is True
|
|
24
|
+
assert config.ai == DEFAULT_CONFIG.ai
|
|
25
|
+
assert config.history == DEFAULT_CONFIG.history
|
|
26
|
+
assert config.privacy == DEFAULT_CONFIG.privacy
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_invalid_boolean_raises_configuration_error() -> None:
|
|
30
|
+
with pytest.raises(ConfigurationError):
|
|
31
|
+
validate_config(
|
|
32
|
+
{
|
|
33
|
+
"logging": {
|
|
34
|
+
"verbose": "yes",
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_invalid_integer_raises_configuration_error() -> None:
|
|
41
|
+
with pytest.raises(ConfigurationError):
|
|
42
|
+
validate_config(
|
|
43
|
+
{
|
|
44
|
+
"history": {
|
|
45
|
+
"max_entries": "5000",
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_invalid_section_type_raises_configuration_error() -> None:
|
|
52
|
+
with pytest.raises(ConfigurationError):
|
|
53
|
+
validate_config(
|
|
54
|
+
{
|
|
55
|
+
"history": True,
|
|
56
|
+
}
|
|
57
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/config/settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/exceptions/base.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/__init__.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/command_result.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/models/history_entry.py
RENAMED
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/repositories/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/services/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/linux_assistant/utils/redactor.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
|
{smart_linux_assistant-0.8.1 → smart_linux_assistant-0.8.2}/tests/test_history_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|