sanityops-cli 0.1.7__tar.gz → 0.1.8__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.
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/PKG-INFO +1 -1
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/pyproject.toml +1 -1
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/__init__.py +1 -1
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/llm_config.py +5 -2
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/test_llm_config.py +100 -67
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/dependabot.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/scripts/pr_review_bot.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/workflows/ai-review.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/workflows/ci.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.github/workflows/release.yml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/.gitignore +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/CHANGELOG.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/CODE_OF_CONDUCT.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/CONTRIBUTING.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/LICENSE +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/NOTICE +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/README.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/SECURITY.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-08-13-model-config-comments-in-init-template.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-08-14-loading-animations.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-08-14-skills-files-banner-readme.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-08-28-copyright-compliance.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-08-config-command.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-20-cross-artifact-rendering.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-20-help-panel-migration.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-20-repair-feature.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-08-13-model-config-comments-in-init-template-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-08-14-loading-animations-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-08-14-skills-files-banner-readme-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-08-28-copyright-compliance-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-09-08-config-command-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-09-20-cross-artifact-rendering-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-09-20-help-panel-migration-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/specs/2026-09-20-repair-feature-design.md +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/entry.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/release.sh +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/scripts/generate-checksums.ps1 +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/scripts/install.ps1 +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/scripts/install.sh +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/agent.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/prompts.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/tools/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/tools/store_repairs_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/agent.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/hooks/progress_hook.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/models/finding.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/prompts.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/tools/grep_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/tools/listfiles_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/tools/readfile_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/tools/storefindings_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/api/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/api/client.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/commands/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/commands/config.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/commands/init.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/commands/inspect.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/constants/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/constants/config_defaults.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/constants/exit_codes.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/checker.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/markdown_reporter.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/renderer.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/exceptions/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/exceptions/api_exceptions.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/exceptions/base_exceptions.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/help_panel.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/logging/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/logging/logger.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/main.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/progress/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/progress/tracker.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/renderers/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/renderers/command_renderer/inspect_command_renderer.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/templates/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/templates/inspect_config.yaml +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/utils/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/utils/artifact_packer.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/utils/config_loader.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/utils/config_resolver.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/utils/validators.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/commands/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/commands/test_config.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/commands/test_init.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/commands/test_inspect_repair.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/test_help_panel.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/repair_agent/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/repair_agent/test_agent.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/repair_agent/test_store_repairs_tool.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/models/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/models/test_finding.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/test_agent.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/test_deterministic_capture.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/test_progress_hook.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/test_prompts.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/api/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/api/test_client.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/commands/test_inspect.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/commands/test_version.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/test_checker.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/test_markdown_reporter.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/test_renderer.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/logging/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/logging/test_logger.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/progress/__init__.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/progress/test_tracker.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/utils/test_artifact_packer.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/utils/test_config_loader.py +0 -0
- {sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/utils/test_config_resolver.py +0 -0
|
@@ -102,10 +102,13 @@ def resolve_llm_config(config_path: str | None = None) -> dict[str, str]:
|
|
|
102
102
|
if config_values:
|
|
103
103
|
return config_values
|
|
104
104
|
|
|
105
|
-
# Fall back to ProviderConfig (env vars)
|
|
105
|
+
# Fall back to ProviderConfig (env vars). PROVIDER is the field that reads
|
|
106
|
+
# the documented LLM_PROVIDER variable (env_prefix is "LLM_"); the
|
|
107
|
+
# LLM_PROVIDER *alias* field listens on LLM_LLM_PROVIDER, so reading it here
|
|
108
|
+
# left llm_provider None and made the SDK refuse every env-configured run.
|
|
106
109
|
config = ProviderConfig()
|
|
107
110
|
return {
|
|
108
|
-
"llm_provider": config.
|
|
111
|
+
"llm_provider": config.PROVIDER,
|
|
109
112
|
"llm_api_key": config.API_KEY,
|
|
110
113
|
"llm_model_id": config.MODEL_ID,
|
|
111
114
|
"llm_base_url": config.BASE_URL or "",
|
|
@@ -1,47 +1,85 @@
|
|
|
1
1
|
"""Unit tests for LLM config resolution."""
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from unittest import mock
|
|
4
3
|
|
|
5
4
|
import yaml
|
|
6
5
|
|
|
7
6
|
from sanityops_cli.defect_checker.llm_config import resolve_llm_config
|
|
8
7
|
|
|
8
|
+
LLM_ENV_NAMES = (
|
|
9
|
+
"LLM_PROVIDER",
|
|
10
|
+
"LLM_LLM_PROVIDER",
|
|
11
|
+
"LLM_API_KEY",
|
|
12
|
+
"LLM_MODEL_ID",
|
|
13
|
+
"LLM_BASE_URL",
|
|
14
|
+
)
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
|
|
17
|
+
def _set_llm_env(monkeypatch, tmp_path: Path, **values: str) -> None:
|
|
18
|
+
"""Point the LLM_* environment variables at `values`, clearing the rest.
|
|
19
|
+
|
|
20
|
+
Also chdirs into tmp_path so ProviderConfig's `.env` lookup (env_file)
|
|
21
|
+
cannot leak values from the repository into the test.
|
|
22
|
+
"""
|
|
23
|
+
monkeypatch.chdir(tmp_path)
|
|
24
|
+
for name in LLM_ENV_NAMES:
|
|
25
|
+
monkeypatch.delenv(name, raising=False)
|
|
26
|
+
for name, value in values.items():
|
|
27
|
+
monkeypatch.setenv(name, value)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestResolveLlmConfigFromEnvironment:
|
|
31
|
+
"""The env fallback must read the documented LLM_* variable names.
|
|
32
|
+
|
|
33
|
+
Regression: resolve_llm_config read ``ProviderConfig.LLM_PROVIDER``, the
|
|
34
|
+
deprecated constructor alias, instead of ``ProviderConfig.PROVIDER``. The
|
|
35
|
+
settings model sets ``env_prefix="LLM_"``, so that alias listens on
|
|
36
|
+
``LLM_LLM_PROVIDER``; the documented ``LLM_PROVIDER`` never reached the
|
|
37
|
+
defect-check SDK, which refused the run with LLM_CONFIGURATION_MISSING and
|
|
38
|
+
left the report at zero defects with a PASS gate.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def test_returns_four_expected_keys(self, tmp_path: Path, monkeypatch):
|
|
42
|
+
_set_llm_env(monkeypatch, tmp_path)
|
|
12
43
|
cfg = resolve_llm_config()
|
|
13
44
|
assert set(cfg.keys()) == {"llm_provider", "llm_api_key", "llm_model_id", "llm_base_url"}
|
|
14
45
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
assert cfg == {
|
|
46
|
+
def test_reads_documented_env_var_names(self, tmp_path: Path, monkeypatch):
|
|
47
|
+
"""LLM_PROVIDER and friends resolve into the provider the SDK receives."""
|
|
48
|
+
_set_llm_env(
|
|
49
|
+
monkeypatch,
|
|
50
|
+
tmp_path,
|
|
51
|
+
LLM_PROVIDER="anthropic",
|
|
52
|
+
LLM_API_KEY="sk-test",
|
|
53
|
+
LLM_MODEL_ID="claude-sonnet-4-20250514",
|
|
54
|
+
LLM_BASE_URL="https://api.example.com",
|
|
55
|
+
)
|
|
56
|
+
assert resolve_llm_config() == {
|
|
27
57
|
"llm_provider": "anthropic",
|
|
28
58
|
"llm_api_key": "sk-test",
|
|
29
59
|
"llm_model_id": "claude-sonnet-4-20250514",
|
|
30
60
|
"llm_base_url": "https://api.example.com",
|
|
31
61
|
}
|
|
32
62
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
def test_deprecated_double_prefixed_provider_name_still_resolves(self, tmp_path: Path, monkeypatch):
|
|
64
|
+
"""LLM_LLM_PROVIDER is the deprecated alias' own env name; keep it working."""
|
|
65
|
+
_set_llm_env(
|
|
66
|
+
monkeypatch,
|
|
67
|
+
tmp_path,
|
|
68
|
+
LLM_LLM_PROVIDER="openai",
|
|
69
|
+
LLM_API_KEY="sk-test",
|
|
70
|
+
LLM_MODEL_ID="gpt-4o",
|
|
71
|
+
)
|
|
72
|
+
assert resolve_llm_config()["llm_provider"] == "openai"
|
|
73
|
+
|
|
74
|
+
def test_unset_base_url_becomes_empty_string(self, tmp_path: Path, monkeypatch):
|
|
75
|
+
_set_llm_env(
|
|
76
|
+
monkeypatch,
|
|
77
|
+
tmp_path,
|
|
78
|
+
LLM_PROVIDER="openai",
|
|
79
|
+
LLM_API_KEY="k",
|
|
80
|
+
LLM_MODEL_ID="gpt-4o",
|
|
81
|
+
)
|
|
82
|
+
assert resolve_llm_config()["llm_base_url"] == ""
|
|
45
83
|
|
|
46
84
|
|
|
47
85
|
class TestResolveLlmConfigFromConfigFile:
|
|
@@ -103,7 +141,7 @@ class TestResolveLlmConfigFromConfigFile:
|
|
|
103
141
|
|
|
104
142
|
def test_model_section_absent_falls_back_to_env_vars(self, tmp_path: Path, monkeypatch):
|
|
105
143
|
"""Should fall back to ProviderConfig when model section absent."""
|
|
106
|
-
monkeypatch
|
|
144
|
+
_set_llm_env(monkeypatch, tmp_path)
|
|
107
145
|
config_dir = tmp_path / ".sanityops"
|
|
108
146
|
config_dir.mkdir()
|
|
109
147
|
config_file = config_dir / "inspect_config.yaml"
|
|
@@ -117,17 +155,15 @@ class TestResolveLlmConfigFromConfigFile:
|
|
|
117
155
|
with open(config_file, "w") as f:
|
|
118
156
|
yaml.dump(config_content, f)
|
|
119
157
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
)
|
|
129
|
-
cfg = resolve_llm_config(str(config_file))
|
|
130
|
-
assert cfg == {
|
|
158
|
+
_set_llm_env(
|
|
159
|
+
monkeypatch,
|
|
160
|
+
tmp_path,
|
|
161
|
+
LLM_PROVIDER="env-provider",
|
|
162
|
+
LLM_API_KEY="env-key",
|
|
163
|
+
LLM_MODEL_ID="env-model",
|
|
164
|
+
LLM_BASE_URL="https://env.url",
|
|
165
|
+
)
|
|
166
|
+
assert resolve_llm_config(str(config_file)) == {
|
|
131
167
|
"llm_provider": "env-provider",
|
|
132
168
|
"llm_api_key": "env-key",
|
|
133
169
|
"llm_model_id": "env-model",
|
|
@@ -136,19 +172,14 @@ class TestResolveLlmConfigFromConfigFile:
|
|
|
136
172
|
|
|
137
173
|
def test_config_file_missing_falls_back_to_env_vars(self, tmp_path: Path, monkeypatch):
|
|
138
174
|
"""Should fall back to ProviderConfig when config file doesn't exist."""
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"sanityops_cli.defect_checker.llm_config.ProviderConfig",
|
|
148
|
-
return_value=fake,
|
|
149
|
-
):
|
|
150
|
-
cfg = resolve_llm_config("/nonexistent/config.yaml")
|
|
151
|
-
assert cfg == {
|
|
175
|
+
_set_llm_env(
|
|
176
|
+
monkeypatch,
|
|
177
|
+
tmp_path,
|
|
178
|
+
LLM_PROVIDER="fallback-provider",
|
|
179
|
+
LLM_API_KEY="fallback-key",
|
|
180
|
+
LLM_MODEL_ID="fallback-model",
|
|
181
|
+
)
|
|
182
|
+
assert resolve_llm_config("/nonexistent/config.yaml") == {
|
|
152
183
|
"llm_provider": "fallback-provider",
|
|
153
184
|
"llm_api_key": "fallback-key",
|
|
154
185
|
"llm_model_id": "fallback-model",
|
|
@@ -206,20 +237,22 @@ class TestResolveLlmConfigFromConfigFile:
|
|
|
206
237
|
with open(config_file, "w") as f:
|
|
207
238
|
yaml.dump(config_content, f)
|
|
208
239
|
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
240
|
+
# Env vars that must be ignored in favour of the config file's model: section
|
|
241
|
+
_set_llm_env(
|
|
242
|
+
monkeypatch,
|
|
243
|
+
tmp_path,
|
|
244
|
+
LLM_PROVIDER="env-provider-should-be-ignored",
|
|
245
|
+
LLM_API_KEY="env-key-should-be-ignored",
|
|
246
|
+
LLM_MODEL_ID="env-model-should-be-ignored",
|
|
247
|
+
LLM_BASE_URL="https://env.url.ignored",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
cfg = resolve_llm_config(str(config_file))
|
|
220
251
|
|
|
221
252
|
# Config values win
|
|
222
|
-
assert cfg
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
253
|
+
assert cfg == {
|
|
254
|
+
"llm_provider": "config-provider",
|
|
255
|
+
"llm_api_key": "config-key",
|
|
256
|
+
"llm_model_id": "config-model",
|
|
257
|
+
"llm_base_url": "",
|
|
258
|
+
}
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-08-14-loading-animations.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-08-config-command.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/docs/superpowers/plans/2026-09-20-repair-feature.md
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
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/prompts.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/repair_agent/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/models/finding.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/agents/scanner_agent/prompts.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
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/src/sanityops_cli/defect_checker/markdown_reporter.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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/models/__init__.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/models/test_finding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/agents/scanner_agent/test_progress_hook.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
|
{sanityops_cli-0.1.7 → sanityops_cli-0.1.8}/tests/unit/defect_checker/test_markdown_reporter.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
|