sanityops-cli 0.1.3__tar.gz → 0.1.4__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.3 → sanityops_cli-0.1.4}/PKG-INFO +85 -1
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/README.md +84 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/pyproject.toml +1 -1
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/__init__.py +1 -1
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/commands/config.py +6 -3
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/utils/config_resolver.py +15 -11
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/utils/test_config_resolver.py +25 -7
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/dependabot.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/scripts/pr_review_bot.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/workflows/ai-review.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/workflows/ci.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.github/workflows/release.yml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/.gitignore +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/CHANGELOG.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/CODE_OF_CONDUCT.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/CONTRIBUTING.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/LICENSE +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/NOTICE +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/SECURITY.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-08-13-model-config-comments-in-init-template.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-08-14-loading-animations.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-08-14-skills-files-banner-readme.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-08-28-copyright-compliance.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-09-08-config-command.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-09-20-cross-artifact-rendering.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-09-20-help-panel-migration.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-09-20-repair-feature.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-08-13-model-config-comments-in-init-template-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-08-14-loading-animations-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-08-14-skills-files-banner-readme-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-08-28-copyright-compliance-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-09-08-config-command-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-09-20-cross-artifact-rendering-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-09-20-help-panel-migration-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/specs/2026-09-20-repair-feature-design.md +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/entry.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/release.sh +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/scripts/generate-checksums.ps1 +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/scripts/install.ps1 +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/scripts/install.sh +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/agent.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/prompts.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/tools/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/tools/store_repairs_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/agent.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/hooks/progress_hook.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/models/finding.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/prompts.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/tools/grep_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/tools/listfiles_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/tools/readfile_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/tools/storefindings_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/api/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/api/client.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/commands/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/commands/init.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/commands/inspect.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/constants/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/constants/config_defaults.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/constants/exit_codes.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/defect_checker/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/defect_checker/checker.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/defect_checker/llm_config.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/defect_checker/markdown_reporter.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/defect_checker/renderer.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/exceptions/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/exceptions/api_exceptions.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/exceptions/base_exceptions.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/help_panel.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/logging/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/logging/logger.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/main.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/progress/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/progress/tracker.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/renderers/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/renderers/command_renderer/inspect_command_renderer.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/templates/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/templates/inspect_config.yaml +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/utils/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/utils/artifact_packer.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/utils/config_loader.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/utils/validators.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/commands/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/commands/test_config.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/commands/test_init.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/commands/test_inspect_repair.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/test_help_panel.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/repair_agent/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/repair_agent/test_agent.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/repair_agent/test_store_repairs_tool.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/models/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/models/test_finding.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/test_agent.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/test_progress_hook.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/test_prompts.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/api/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/api/test_client.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/commands/test_inspect.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/commands/test_version.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/defect_checker/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/defect_checker/test_checker.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/defect_checker/test_llm_config.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/defect_checker/test_markdown_reporter.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/defect_checker/test_renderer.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/logging/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/logging/test_logger.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/progress/__init__.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/progress/test_tracker.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/utils/test_artifact_packer.py +0 -0
- {sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/utils/test_config_loader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sanityops-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI tool for static defect inspection of AI logical artifacts
|
|
5
5
|
Project-URL: Homepage, https://sanityops.org
|
|
6
6
|
Project-URL: Documentation, https://sanityops.org
|
|
@@ -147,6 +147,90 @@ sanityops-cli inspect --skip-defect-check
|
|
|
147
147
|
sanityops-cli inspect --config path/to/config.yaml
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
### 4. Generate Repairs (Optional)
|
|
151
|
+
|
|
152
|
+
After inspection, generate repaired artifacts from the report:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Use the latest inspection report
|
|
156
|
+
sanityops-cli inspect repair
|
|
157
|
+
|
|
158
|
+
# Use a specific report
|
|
159
|
+
sanityops-cli inspect repair --report .sanityops/results/inspect-20250115-120000.md
|
|
160
|
+
|
|
161
|
+
# Specify timeout and token budget for large projects
|
|
162
|
+
sanityops-cli inspect repair --timeout 3600 --token-budget 500000
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Repairs are written to `.sanityops/repairs/repair-<timestamp>.md` without modifying source files.
|
|
166
|
+
|
|
167
|
+
## Configuration
|
|
168
|
+
|
|
169
|
+
### Config Command
|
|
170
|
+
|
|
171
|
+
Manage server-side configuration (base URL, API key) using the `config` command:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Read a config value
|
|
175
|
+
sanityops-cli config server.base_url
|
|
176
|
+
|
|
177
|
+
# Set a global config value
|
|
178
|
+
sanityops-cli config server.base_url https://api.sanityops.org
|
|
179
|
+
|
|
180
|
+
# Set a project-level config value
|
|
181
|
+
sanityops-cli config server.base_url https://api.sanityops.org --local
|
|
182
|
+
|
|
183
|
+
# Set API key (prompts for masked input if no value provided)
|
|
184
|
+
sanityops-cli config server.api_key
|
|
185
|
+
|
|
186
|
+
# List all config values
|
|
187
|
+
sanityops-cli config --list
|
|
188
|
+
|
|
189
|
+
# Remove a config key
|
|
190
|
+
sanityops-cli config --unset server.base_url
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Configuration Precedence
|
|
194
|
+
|
|
195
|
+
Values are resolved in this priority order (highest to lowest):
|
|
196
|
+
|
|
197
|
+
1. **Environment Variable** — e.g., `SANITYOPS_BASE_URL`
|
|
198
|
+
2. **Project-level** — `.sanityops/inspect_config.yaml`
|
|
199
|
+
3. **Global** — `~/.sanityops/config`
|
|
200
|
+
4. **Default** — built-in fallback
|
|
201
|
+
|
|
202
|
+
This ordering ensures CI/CD pipelines can override any project config by injecting environment variables.
|
|
203
|
+
|
|
204
|
+
### Environment Variables
|
|
205
|
+
|
|
206
|
+
| Variable | Description |
|
|
207
|
+
|----------|-------------|
|
|
208
|
+
| `SANITYOPS_BASE_URL` | Override `server.base_url` |
|
|
209
|
+
| `SANITYOPS_API_KEY` | Override `server.api_key` |
|
|
210
|
+
| `LLM_PROVIDER` | LLM provider (e.g., `anthropic`, `openai`) |
|
|
211
|
+
| `LLM_API_KEY` | LLM API key for defect checking |
|
|
212
|
+
| `LLM_MODEL_ID` | LLM model ID (e.g., `claude-sonnet-4-20250514`) |
|
|
213
|
+
| `LLM_BASE_URL` | Custom LLM base URL |
|
|
214
|
+
|
|
215
|
+
## Advanced Configuration
|
|
216
|
+
|
|
217
|
+
### Agent Settings
|
|
218
|
+
|
|
219
|
+
You can tune the scanner agent behavior in `.sanityops/inspect_config.yaml`:
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
agent:
|
|
223
|
+
max_loops: 60 # Maximum agent execution loops
|
|
224
|
+
token_budget: 200000 # Token budget for agent execution
|
|
225
|
+
timeout: 1800 # Timeout in seconds (default: 1800 = 30min)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
CLI flags (`--timeout`, `--token-budget`) override these values when explicitly set.
|
|
229
|
+
|
|
230
|
+
### Logging
|
|
231
|
+
|
|
232
|
+
All CLI operations are logged to `~/.sanityops/logs/sanityops-cli-<YYYY-MM-DD>.log`. Logs include timestamps, log levels, and redacted API keys for security.
|
|
233
|
+
|
|
150
234
|
### Check Levels
|
|
151
235
|
|
|
152
236
|
| Level | Description | Use Case |
|
|
@@ -107,6 +107,90 @@ sanityops-cli inspect --skip-defect-check
|
|
|
107
107
|
sanityops-cli inspect --config path/to/config.yaml
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
### 4. Generate Repairs (Optional)
|
|
111
|
+
|
|
112
|
+
After inspection, generate repaired artifacts from the report:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Use the latest inspection report
|
|
116
|
+
sanityops-cli inspect repair
|
|
117
|
+
|
|
118
|
+
# Use a specific report
|
|
119
|
+
sanityops-cli inspect repair --report .sanityops/results/inspect-20250115-120000.md
|
|
120
|
+
|
|
121
|
+
# Specify timeout and token budget for large projects
|
|
122
|
+
sanityops-cli inspect repair --timeout 3600 --token-budget 500000
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Repairs are written to `.sanityops/repairs/repair-<timestamp>.md` without modifying source files.
|
|
126
|
+
|
|
127
|
+
## Configuration
|
|
128
|
+
|
|
129
|
+
### Config Command
|
|
130
|
+
|
|
131
|
+
Manage server-side configuration (base URL, API key) using the `config` command:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Read a config value
|
|
135
|
+
sanityops-cli config server.base_url
|
|
136
|
+
|
|
137
|
+
# Set a global config value
|
|
138
|
+
sanityops-cli config server.base_url https://api.sanityops.org
|
|
139
|
+
|
|
140
|
+
# Set a project-level config value
|
|
141
|
+
sanityops-cli config server.base_url https://api.sanityops.org --local
|
|
142
|
+
|
|
143
|
+
# Set API key (prompts for masked input if no value provided)
|
|
144
|
+
sanityops-cli config server.api_key
|
|
145
|
+
|
|
146
|
+
# List all config values
|
|
147
|
+
sanityops-cli config --list
|
|
148
|
+
|
|
149
|
+
# Remove a config key
|
|
150
|
+
sanityops-cli config --unset server.base_url
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Configuration Precedence
|
|
154
|
+
|
|
155
|
+
Values are resolved in this priority order (highest to lowest):
|
|
156
|
+
|
|
157
|
+
1. **Environment Variable** — e.g., `SANITYOPS_BASE_URL`
|
|
158
|
+
2. **Project-level** — `.sanityops/inspect_config.yaml`
|
|
159
|
+
3. **Global** — `~/.sanityops/config`
|
|
160
|
+
4. **Default** — built-in fallback
|
|
161
|
+
|
|
162
|
+
This ordering ensures CI/CD pipelines can override any project config by injecting environment variables.
|
|
163
|
+
|
|
164
|
+
### Environment Variables
|
|
165
|
+
|
|
166
|
+
| Variable | Description |
|
|
167
|
+
|----------|-------------|
|
|
168
|
+
| `SANITYOPS_BASE_URL` | Override `server.base_url` |
|
|
169
|
+
| `SANITYOPS_API_KEY` | Override `server.api_key` |
|
|
170
|
+
| `LLM_PROVIDER` | LLM provider (e.g., `anthropic`, `openai`) |
|
|
171
|
+
| `LLM_API_KEY` | LLM API key for defect checking |
|
|
172
|
+
| `LLM_MODEL_ID` | LLM model ID (e.g., `claude-sonnet-4-20250514`) |
|
|
173
|
+
| `LLM_BASE_URL` | Custom LLM base URL |
|
|
174
|
+
|
|
175
|
+
## Advanced Configuration
|
|
176
|
+
|
|
177
|
+
### Agent Settings
|
|
178
|
+
|
|
179
|
+
You can tune the scanner agent behavior in `.sanityops/inspect_config.yaml`:
|
|
180
|
+
|
|
181
|
+
```yaml
|
|
182
|
+
agent:
|
|
183
|
+
max_loops: 60 # Maximum agent execution loops
|
|
184
|
+
token_budget: 200000 # Token budget for agent execution
|
|
185
|
+
timeout: 1800 # Timeout in seconds (default: 1800 = 30min)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
CLI flags (`--timeout`, `--token-budget`) override these values when explicitly set.
|
|
189
|
+
|
|
190
|
+
### Logging
|
|
191
|
+
|
|
192
|
+
All CLI operations are logged to `~/.sanityops/logs/sanityops-cli-<YYYY-MM-DD>.log`. Logs include timestamps, log levels, and redacted API keys for security.
|
|
193
|
+
|
|
110
194
|
### Check Levels
|
|
111
195
|
|
|
112
196
|
| Level | Description | Use Case |
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
Config keys use dot notation, e.g. ``server.base_url``. They correspond to
|
|
19
19
|
the sanityops SaaS backend (NOT the LLM model config, which lives under
|
|
20
|
-
``model.*``). Precedence: project-level > global >
|
|
20
|
+
``model.*``). Precedence: environment variable > project-level > global > default.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
from __future__ import annotations
|
|
@@ -110,8 +110,11 @@ def _get_config_usage_panel():
|
|
|
110
110
|
|
|
111
111
|
usage_text = f"""\
|
|
112
112
|
Configuration Priority:
|
|
113
|
-
Project-level (.sanityops/inspect_config.yaml)
|
|
114
|
-
>
|
|
113
|
+
Environment Variable > Project-level (.sanityops/inspect_config.yaml)
|
|
114
|
+
> Global (~/.sanityops/config) > Default
|
|
115
|
+
|
|
116
|
+
This ordering ensures CI/CD pipelines can override project config by
|
|
117
|
+
injecting environment variables (e.g., SANITYOPS_BASE_URL).
|
|
115
118
|
|
|
116
119
|
Available Keys:
|
|
117
120
|
server.base_url Sanityops SaaS backend URL (default: {DEFAULT_SERVER_BASE_URL})
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
|
|
16
|
-
"""Generic config resolver with precedence chain:
|
|
16
|
+
"""Generic config resolver with precedence chain: env > project > global > default."""
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
@@ -214,7 +214,11 @@ def _unset_nested_value(data: dict[str, Any], key: str) -> bool:
|
|
|
214
214
|
class ConfigResolver:
|
|
215
215
|
"""Generic config resolver with precedence chain.
|
|
216
216
|
|
|
217
|
-
Precedence: project-level > global >
|
|
217
|
+
Precedence: environment variable > project-level > global > default.
|
|
218
|
+
|
|
219
|
+
This ordering ensures CI/CD pipelines can override project config by
|
|
220
|
+
injecting environment variables, while local development uses project-level
|
|
221
|
+
files as the primary source.
|
|
218
222
|
|
|
219
223
|
Attributes:
|
|
220
224
|
config_key: Dot-separated config key (e.g., "server.base_url").
|
|
@@ -238,25 +242,25 @@ class ConfigResolver:
|
|
|
238
242
|
Returns:
|
|
239
243
|
The resolved value, or None if not found and no default.
|
|
240
244
|
"""
|
|
241
|
-
# 1.
|
|
245
|
+
# 1. Environment variable (highest priority for CI/CD overrides)
|
|
246
|
+
if self.env_var:
|
|
247
|
+
env_value = os.environ.get(self.env_var)
|
|
248
|
+
if env_value is not None:
|
|
249
|
+
return env_value
|
|
250
|
+
|
|
251
|
+
# 2. Project-level config
|
|
242
252
|
project_config = _read_yaml_file(get_project_config_path())
|
|
243
253
|
value = _get_nested_value(project_config, self.config_key)
|
|
244
254
|
if value is not None:
|
|
245
255
|
return str(value) if not isinstance(value, str) else value
|
|
246
256
|
|
|
247
|
-
#
|
|
257
|
+
# 3. Global config
|
|
248
258
|
global_config = _read_yaml_file(get_global_config_path())
|
|
249
259
|
value = _get_nested_value(global_config, self.config_key)
|
|
250
260
|
if value is not None:
|
|
251
261
|
return str(value) if not isinstance(value, str) else value
|
|
252
262
|
|
|
253
|
-
#
|
|
254
|
-
if self.env_var:
|
|
255
|
-
env_value = os.environ.get(self.env_var)
|
|
256
|
-
if env_value is not None:
|
|
257
|
-
return env_value
|
|
258
|
-
|
|
259
|
-
# 4. Default
|
|
263
|
+
# 4. Default (lowest priority)
|
|
260
264
|
return self.default
|
|
261
265
|
|
|
262
266
|
def resolve_all_sources(self) -> dict[str, str | None]:
|
|
@@ -232,7 +232,7 @@ class TestNestedKeyOperations:
|
|
|
232
232
|
|
|
233
233
|
|
|
234
234
|
class TestConfigResolverPrecedence:
|
|
235
|
-
"""Test precedence chain:
|
|
235
|
+
"""Test precedence chain: env > project > global > default."""
|
|
236
236
|
|
|
237
237
|
def test_resolve_returns_default_when_nothing_set(self, monkeypatch, tmp_path: Path):
|
|
238
238
|
"""Should return default when no config or env set."""
|
|
@@ -258,8 +258,8 @@ class TestConfigResolverPrecedence:
|
|
|
258
258
|
result = resolver.resolve()
|
|
259
259
|
assert result == "https://env.example.com"
|
|
260
260
|
|
|
261
|
-
def
|
|
262
|
-
"""
|
|
261
|
+
def test_resolve_env_overrides_global(self, monkeypatch, tmp_path: Path):
|
|
262
|
+
"""Environment variable should override global config and default."""
|
|
263
263
|
from sanityops_cli.utils.config_resolver import ConfigResolver
|
|
264
264
|
|
|
265
265
|
monkeypatch.chdir(tmp_path)
|
|
@@ -275,16 +275,15 @@ class TestConfigResolverPrecedence:
|
|
|
275
275
|
|
|
276
276
|
resolver = ConfigResolver("server.base_url", env_var="SANITYOPS_BASE_URL", default="https://default.com")
|
|
277
277
|
result = resolver.resolve()
|
|
278
|
-
assert result == "https://
|
|
278
|
+
assert result == "https://env.example.com"
|
|
279
279
|
|
|
280
280
|
def test_resolve_project_overrides_global(self, monkeypatch, tmp_path: Path):
|
|
281
|
-
"""Project config should override global
|
|
281
|
+
"""Project config should override global and default."""
|
|
282
282
|
from sanityops_cli.utils.config_resolver import ConfigResolver
|
|
283
283
|
|
|
284
284
|
monkeypatch.chdir(tmp_path)
|
|
285
285
|
home_dir = tmp_path / "home"
|
|
286
286
|
monkeypatch.setattr(Path, "home", lambda: home_dir)
|
|
287
|
-
monkeypatch.setenv("SANITYOPS_BASE_URL", "https://env.example.com")
|
|
288
287
|
|
|
289
288
|
# Create global config
|
|
290
289
|
global_config_dir = home_dir / ".sanityops"
|
|
@@ -302,8 +301,27 @@ class TestConfigResolverPrecedence:
|
|
|
302
301
|
result = resolver.resolve()
|
|
303
302
|
assert result == "https://project.example.com"
|
|
304
303
|
|
|
304
|
+
def test_resolve_env_overrides_project(self, monkeypatch, tmp_path: Path):
|
|
305
|
+
"""Environment variable should override project config."""
|
|
306
|
+
from sanityops_cli.utils.config_resolver import ConfigResolver
|
|
307
|
+
|
|
308
|
+
monkeypatch.chdir(tmp_path)
|
|
309
|
+
home_dir = tmp_path / "home"
|
|
310
|
+
monkeypatch.setattr(Path, "home", lambda: home_dir)
|
|
311
|
+
monkeypatch.setenv("SANITYOPS_BASE_URL", "https://env.example.com")
|
|
312
|
+
|
|
313
|
+
# Create project config
|
|
314
|
+
project_config_dir = tmp_path / ".sanityops"
|
|
315
|
+
project_config_dir.mkdir(parents=True)
|
|
316
|
+
project_config = project_config_dir / "inspect_config.yaml"
|
|
317
|
+
project_config.write_text("server:\n base_url: https://project.example.com\n")
|
|
318
|
+
|
|
319
|
+
resolver = ConfigResolver("server.base_url", env_var="SANITYOPS_BASE_URL", default="https://default.com")
|
|
320
|
+
result = resolver.resolve()
|
|
321
|
+
assert result == "https://env.example.com"
|
|
322
|
+
|
|
305
323
|
def test_resolve_all_sources_returns_all_values(self, monkeypatch, tmp_path: Path):
|
|
306
|
-
"""Should return values from project, global,
|
|
324
|
+
"""Should return values from env, project, global, and default sources."""
|
|
307
325
|
from sanityops_cli.utils.config_resolver import ConfigResolver
|
|
308
326
|
|
|
309
327
|
monkeypatch.chdir(tmp_path)
|
|
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.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-08-14-loading-animations.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/docs/superpowers/plans/2026-09-08-config-command.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/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.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/repair_agent/prompts.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/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.3 → sanityops_cli-0.1.4}/src/sanityops_cli/agents/scanner_agent/models/finding.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/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.3 → sanityops_cli-0.1.4}/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
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/models/__init__.py
RENAMED
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/tests/unit/agents/scanner_agent/models/test_finding.py
RENAMED
|
File without changes
|
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/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
|
|
File without changes
|
{sanityops_cli-0.1.3 → sanityops_cli-0.1.4}/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
|