coding-cli-runtime 0.3.0__tar.gz → 0.4.0__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.
- coding_cli_runtime-0.4.0/CHANGELOG.md +96 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/PKG-INFO +78 -6
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/README.md +77 -5
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/pyproject.toml +2 -2
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/__init__.py +20 -2
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_contracts.py +176 -1
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/PKG-INFO +78 -6
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/SOURCES.txt +3 -1
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_stage2_tier1.py +1 -1
- coding_cli_runtime-0.4.0/tests/test_stage3_io_contracts.py +119 -0
- coding_cli_runtime-0.4.0/tests/test_stage4_helpers.py +105 -0
- coding_cli_runtime-0.3.0/CHANGELOG.md +0 -101
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/CONTRIBUTING.md +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/LICENSE +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/MANIFEST.in +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/setup.cfg +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/auth.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/codex_cli.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/contracts.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/copilot_reasoning_baseline.json +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/copilot_reasoning_logs.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/failure_classification.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/headless.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/json_io.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_controls.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_specs.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/py.typed +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/reasoning.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/redaction.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/schema_validation.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/schemas/normalized_run_result.v1.json +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/schemas/reasoning_metadata.v1.json +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/session_execution.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/session_logs.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/subprocess_runner.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/dependency_links.txt +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/top_level.txt +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_copilot_reasoning_logs.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_coverage_gaps.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_package_resources.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_packaging.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_playground_probe_smoke.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_provider_catalog_resolution.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_provider_contracts.py +0 -0
- {coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_runtime_parity.py +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.4.0] - 2026-04-09
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `OutputContract`, `IoContract`, `SessionDiscoveryContract`,
|
|
13
|
+
`DiagnosticsContract` sub-contracts on `ProviderContract`, with data
|
|
14
|
+
populated for all four providers.
|
|
15
|
+
- `WorkspaceEnvVar` structured type with `name` + `value_source` semantics
|
|
16
|
+
(replaces bare env-var name strings in `IoContract.workspace_env_vars`).
|
|
17
|
+
- `WorkspaceEnvValueSource` — closed vocabulary (`"execution_dir"` /
|
|
18
|
+
`"workspace_root"`) for `WorkspaceEnvVar.value_source`.
|
|
19
|
+
- `resolve_workspace_env()` — turns `IoContract.workspace_env_vars` into a
|
|
20
|
+
concrete env overlay from an execution directory.
|
|
21
|
+
- `resolve_session_search_paths()` — expands `SessionDiscoveryContract`
|
|
22
|
+
roots into concrete host paths.
|
|
23
|
+
- `is_provider_installed()` — checks whether a provider CLI binary is on
|
|
24
|
+
PATH.
|
|
25
|
+
- README sections: "Query provider I/O conventions" and "Common integration
|
|
26
|
+
tasks" with copy-pasteable examples.
|
|
27
|
+
- `WorkspaceEnvVar` added to key-types table in README.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Gemini `session_glob` tightened from `"*.json"` to `"*/chats/session-*.json"`
|
|
31
|
+
to match the real `tmp/{hash}/chats/session-*.json` layout.
|
|
32
|
+
- Claude `session_glob` tightened from `"*.jsonl"` to
|
|
33
|
+
`"*/conversation.jsonl"` to match per-project subdirectory structure.
|
|
34
|
+
|
|
35
|
+
## [0.3.0] - 2026-04-09
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Per-provider headless launch helpers: `build_claude_headless_core()`,
|
|
39
|
+
`build_codex_headless_core()`, `build_copilot_headless_core()`,
|
|
40
|
+
`build_gemini_headless_core()`. These emit the standard non-interactive
|
|
41
|
+
flags for each provider; callers append app-specific tails.
|
|
42
|
+
- Session log discovery section in README.
|
|
43
|
+
- API summary table in README.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- `build_codex_exec_spec()` now delegates to `build_codex_headless_core()`.
|
|
47
|
+
`full_auto` and `skip_git_repo_check` params preserved.
|
|
48
|
+
- README rewritten with task-oriented examples, `run_interactive_session`
|
|
49
|
+
usage, `uv add` install, and API summary.
|
|
50
|
+
|
|
51
|
+
## [0.2.0] - 2026-04-08
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- `ProviderContract` API — structured, nested metadata for all four provider
|
|
55
|
+
CLIs (Claude, Codex, Gemini, Copilot). Composed of `AuthContract`,
|
|
56
|
+
`PathContract`, `HeadlessContract`, `PromptTransport`, `ApprovalContract`,
|
|
57
|
+
`SandboxContract`.
|
|
58
|
+
- `get_provider_contract(provider_id)` — returns structured contract for a
|
|
59
|
+
provider.
|
|
60
|
+
- `build_env_overlay(contract, api_key, base_url)` — builds provider-specific
|
|
61
|
+
env var overlay from contract metadata.
|
|
62
|
+
- `resolve_config_paths(contract, containerized)` — resolves host and container
|
|
63
|
+
config directory paths.
|
|
64
|
+
- `render_prompt(transport, prompt)` — resolves prompt delivery into argv args +
|
|
65
|
+
stdin text based on provider transport mode.
|
|
66
|
+
- `PromptPayload` dataclass for resolved prompt delivery.
|
|
67
|
+
- `resolve_auth()` — resolves provider auth status from environment.
|
|
68
|
+
- `__version__` attribute.
|
|
69
|
+
- `CONTRIBUTING.md` with development setup and quality checks.
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
- `run_interactive_session()` observability kwargs (`job_name`, `phase_tag`)
|
|
73
|
+
now have sensible defaults so callers don't need to supply them.
|
|
74
|
+
- `CliRunResult.command` type widened from `tuple[str, ...]` to `Sequence[str]`.
|
|
75
|
+
- Provider model catalogs resolved with three-tier fallback: user override
|
|
76
|
+
file > live CLI discovery > hardcoded fallback.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
- Copilot BYOK (`COPILOT_PROVIDER_API_KEY`) now discoverable via contract
|
|
80
|
+
but not reported as "required" in `resolve_auth()` — BYOK is opt-in.
|
|
81
|
+
|
|
82
|
+
## [0.1.0] - 2026-04-07
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
- Provider metadata and controls for Claude, Codex, Copilot, and Gemini CLIs.
|
|
86
|
+
- Shared request/result contracts (`CliRunRequest`, `CliRunResult`, `CliLaunchSpec`).
|
|
87
|
+
- Schema loading and payload validation (`load_schema`, `validate_payload`).
|
|
88
|
+
- Synchronous and asynchronous subprocess execution helpers.
|
|
89
|
+
- Interactive session execution with transcript mirroring.
|
|
90
|
+
- Session log discovery and parsing utilities.
|
|
91
|
+
- Claude reasoning policy resolution.
|
|
92
|
+
- Log redaction helpers.
|
|
93
|
+
- Copilot reasoning log parsing and classification.
|
|
94
|
+
- PEP 561 `py.typed` markers for both `coding_cli_runtime` and `shared_cli_runtime`.
|
|
95
|
+
- Packaged JSON schemas and Copilot reasoning baseline data.
|
|
96
|
+
- Playground knowledge base with probing guides and experiment templates.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-cli-runtime
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Reusable CLI runtime primitives for provider-backed automation workflows
|
|
5
5
|
Author-email: LLM Eval maintainers <llm-eval-maintainers@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -152,6 +152,44 @@ else:
|
|
|
152
152
|
Works for all four providers. Recognizes auth failures, rate limits,
|
|
153
153
|
network transients, and other provider-specific error patterns.
|
|
154
154
|
|
|
155
|
+
### Common integration tasks
|
|
156
|
+
|
|
157
|
+
#### Check whether a provider CLI is installed
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from coding_cli_runtime import is_provider_installed
|
|
161
|
+
|
|
162
|
+
if not is_provider_installed("claude"):
|
|
163
|
+
raise RuntimeError("Claude Code is not available on PATH")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This is intentionally minimal: it checks whether the provider binary exists on
|
|
167
|
+
PATH. Deeper CLI drift validation belongs in maintainer tooling, not the
|
|
168
|
+
runtime API.
|
|
169
|
+
|
|
170
|
+
#### Resolve workspace env vars and session search paths
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from coding_cli_runtime import (
|
|
174
|
+
get_provider_contract,
|
|
175
|
+
resolve_session_search_paths,
|
|
176
|
+
resolve_workspace_env,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
gemini = get_provider_contract("gemini")
|
|
180
|
+
|
|
181
|
+
# Derive provider-specific workspace env vars from contract metadata
|
|
182
|
+
env = resolve_workspace_env(gemini, "/tmp/run-dir")
|
|
183
|
+
# {"GEMINI_CLI_IDE_WORKSPACE_PATH": "/tmp/run-dir"}
|
|
184
|
+
|
|
185
|
+
# Expand concrete host paths for session log searches
|
|
186
|
+
paths = resolve_session_search_paths(gemini)
|
|
187
|
+
# (Path.home() / ".gemini" / "tmp",)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use these helpers when you want the contract facts turned into concrete
|
|
191
|
+
filesystem/env values without rebuilding the same glue logic in each consumer.
|
|
192
|
+
|
|
155
193
|
### Look up provider contract metadata
|
|
156
194
|
|
|
157
195
|
```python
|
|
@@ -179,11 +217,43 @@ payload = render_prompt(contract.headless.prompt, "Fix the bug")
|
|
|
179
217
|
```
|
|
180
218
|
|
|
181
219
|
`ProviderContract` is structured as nested sub-contracts
|
|
182
|
-
(`AuthContract`, `PathContract`, `HeadlessContract`
|
|
220
|
+
(`AuthContract`, `PathContract`, `HeadlessContract`, `OutputContract`,
|
|
221
|
+
`IoContract`, `SessionDiscoveryContract`, `DiagnosticsContract`) so consumers
|
|
183
222
|
can drill into whichever aspect they need. This is reference metadata,
|
|
184
|
-
not a command-construction control plane —
|
|
223
|
+
not a command-construction control plane — callers keep their own
|
|
185
224
|
command assembly and adopt contract fields selectively.
|
|
186
225
|
|
|
226
|
+
### Query provider I/O conventions
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from coding_cli_runtime import get_provider_contract
|
|
230
|
+
|
|
231
|
+
gemini = get_provider_contract("gemini")
|
|
232
|
+
|
|
233
|
+
# Workspace env vars with value semantics
|
|
234
|
+
for wev in gemini.io.workspace_env_vars:
|
|
235
|
+
print(f"{wev.name} = {wev.value_source}")
|
|
236
|
+
# GEMINI_CLI_IDE_WORKSPACE_PATH = execution_dir
|
|
237
|
+
|
|
238
|
+
# Session discovery (where session logs live)
|
|
239
|
+
sd = gemini.session_discovery
|
|
240
|
+
print(sd.session_roots) # ("tmp",)
|
|
241
|
+
print(sd.session_glob) # "*/chats/session-*.json"
|
|
242
|
+
|
|
243
|
+
# Output format support
|
|
244
|
+
codex = get_provider_contract("codex")
|
|
245
|
+
print(codex.output.output_path_flag) # "-o"
|
|
246
|
+
print(codex.output.schema_path_flag) # "--output-schema"
|
|
247
|
+
|
|
248
|
+
# Diagnostics (Copilot only)
|
|
249
|
+
copilot = get_provider_contract("copilot")
|
|
250
|
+
if copilot.diagnostics:
|
|
251
|
+
print(copilot.diagnostics.log_glob) # "logs/process-*.log"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`WorkspaceEnvVar.value_source` uses a closed vocabulary:
|
|
255
|
+
`"execution_dir"` or `"workspace_root"`.
|
|
256
|
+
|
|
187
257
|
### Build headless launch commands
|
|
188
258
|
|
|
189
259
|
```python
|
|
@@ -224,7 +294,8 @@ files matching the working directory and time window.
|
|
|
224
294
|
| `CliRunResult` | Result: returncode, stdout/stderr, duration, error code |
|
|
225
295
|
| `ErrorCode` | `none` · `spawn_failed` · `timed_out` · `non_zero_exit` |
|
|
226
296
|
| `ProviderSpec` | Provider catalog entry with models, controls, defaults |
|
|
227
|
-
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless
|
|
297
|
+
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless, I/O, sessions) |
|
|
298
|
+
| `WorkspaceEnvVar` | Env var with value-source semantics (`execution_dir`, `workspace_root`) |
|
|
228
299
|
| `FailureClassification` | Classified error with retryable flag and category |
|
|
229
300
|
|
|
230
301
|
### Run long-lived CLI sessions
|
|
@@ -249,7 +320,7 @@ result = await run_interactive_session(
|
|
|
249
320
|
```
|
|
250
321
|
|
|
251
322
|
Only `cmd_parts`, `cwd`, `stdin_text`, and `logger` are required.
|
|
252
|
-
|
|
323
|
+
Other parameters have sensible defaults.
|
|
253
324
|
|
|
254
325
|
## API summary
|
|
255
326
|
|
|
@@ -260,10 +331,11 @@ Key function groups:
|
|
|
260
331
|
|-------|-----------|
|
|
261
332
|
| Execution | `run_cli_command`, `run_cli_command_sync`, `run_interactive_session` |
|
|
262
333
|
| Provider metadata | `get_provider_contract`, `get_provider_spec`, `list_provider_specs` |
|
|
263
|
-
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth` |
|
|
334
|
+
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth`, `resolve_workspace_env`, `resolve_session_search_paths` |
|
|
264
335
|
| Headless launch | `build_claude_headless_core`, `build_codex_headless_core`, `build_copilot_headless_core`, `build_gemini_headless_core` |
|
|
265
336
|
| Codex batch | `build_codex_exec_spec` |
|
|
266
337
|
| Failure handling | `classify_provider_failure` |
|
|
338
|
+
| Installation check | `is_provider_installed` |
|
|
267
339
|
| Session logs | `find_codex_session`, `find_claude_session` |
|
|
268
340
|
| Schema | `load_schema`, `validate_payload` |
|
|
269
341
|
| Utilities | `redact_text`, `build_model_id`, `normalize_path_str` |
|
|
@@ -126,6 +126,44 @@ else:
|
|
|
126
126
|
Works for all four providers. Recognizes auth failures, rate limits,
|
|
127
127
|
network transients, and other provider-specific error patterns.
|
|
128
128
|
|
|
129
|
+
### Common integration tasks
|
|
130
|
+
|
|
131
|
+
#### Check whether a provider CLI is installed
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from coding_cli_runtime import is_provider_installed
|
|
135
|
+
|
|
136
|
+
if not is_provider_installed("claude"):
|
|
137
|
+
raise RuntimeError("Claude Code is not available on PATH")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This is intentionally minimal: it checks whether the provider binary exists on
|
|
141
|
+
PATH. Deeper CLI drift validation belongs in maintainer tooling, not the
|
|
142
|
+
runtime API.
|
|
143
|
+
|
|
144
|
+
#### Resolve workspace env vars and session search paths
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from coding_cli_runtime import (
|
|
148
|
+
get_provider_contract,
|
|
149
|
+
resolve_session_search_paths,
|
|
150
|
+
resolve_workspace_env,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
gemini = get_provider_contract("gemini")
|
|
154
|
+
|
|
155
|
+
# Derive provider-specific workspace env vars from contract metadata
|
|
156
|
+
env = resolve_workspace_env(gemini, "/tmp/run-dir")
|
|
157
|
+
# {"GEMINI_CLI_IDE_WORKSPACE_PATH": "/tmp/run-dir"}
|
|
158
|
+
|
|
159
|
+
# Expand concrete host paths for session log searches
|
|
160
|
+
paths = resolve_session_search_paths(gemini)
|
|
161
|
+
# (Path.home() / ".gemini" / "tmp",)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Use these helpers when you want the contract facts turned into concrete
|
|
165
|
+
filesystem/env values without rebuilding the same glue logic in each consumer.
|
|
166
|
+
|
|
129
167
|
### Look up provider contract metadata
|
|
130
168
|
|
|
131
169
|
```python
|
|
@@ -153,11 +191,43 @@ payload = render_prompt(contract.headless.prompt, "Fix the bug")
|
|
|
153
191
|
```
|
|
154
192
|
|
|
155
193
|
`ProviderContract` is structured as nested sub-contracts
|
|
156
|
-
(`AuthContract`, `PathContract`, `HeadlessContract`
|
|
194
|
+
(`AuthContract`, `PathContract`, `HeadlessContract`, `OutputContract`,
|
|
195
|
+
`IoContract`, `SessionDiscoveryContract`, `DiagnosticsContract`) so consumers
|
|
157
196
|
can drill into whichever aspect they need. This is reference metadata,
|
|
158
|
-
not a command-construction control plane —
|
|
197
|
+
not a command-construction control plane — callers keep their own
|
|
159
198
|
command assembly and adopt contract fields selectively.
|
|
160
199
|
|
|
200
|
+
### Query provider I/O conventions
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from coding_cli_runtime import get_provider_contract
|
|
204
|
+
|
|
205
|
+
gemini = get_provider_contract("gemini")
|
|
206
|
+
|
|
207
|
+
# Workspace env vars with value semantics
|
|
208
|
+
for wev in gemini.io.workspace_env_vars:
|
|
209
|
+
print(f"{wev.name} = {wev.value_source}")
|
|
210
|
+
# GEMINI_CLI_IDE_WORKSPACE_PATH = execution_dir
|
|
211
|
+
|
|
212
|
+
# Session discovery (where session logs live)
|
|
213
|
+
sd = gemini.session_discovery
|
|
214
|
+
print(sd.session_roots) # ("tmp",)
|
|
215
|
+
print(sd.session_glob) # "*/chats/session-*.json"
|
|
216
|
+
|
|
217
|
+
# Output format support
|
|
218
|
+
codex = get_provider_contract("codex")
|
|
219
|
+
print(codex.output.output_path_flag) # "-o"
|
|
220
|
+
print(codex.output.schema_path_flag) # "--output-schema"
|
|
221
|
+
|
|
222
|
+
# Diagnostics (Copilot only)
|
|
223
|
+
copilot = get_provider_contract("copilot")
|
|
224
|
+
if copilot.diagnostics:
|
|
225
|
+
print(copilot.diagnostics.log_glob) # "logs/process-*.log"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`WorkspaceEnvVar.value_source` uses a closed vocabulary:
|
|
229
|
+
`"execution_dir"` or `"workspace_root"`.
|
|
230
|
+
|
|
161
231
|
### Build headless launch commands
|
|
162
232
|
|
|
163
233
|
```python
|
|
@@ -198,7 +268,8 @@ files matching the working directory and time window.
|
|
|
198
268
|
| `CliRunResult` | Result: returncode, stdout/stderr, duration, error code |
|
|
199
269
|
| `ErrorCode` | `none` · `spawn_failed` · `timed_out` · `non_zero_exit` |
|
|
200
270
|
| `ProviderSpec` | Provider catalog entry with models, controls, defaults |
|
|
201
|
-
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless
|
|
271
|
+
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless, I/O, sessions) |
|
|
272
|
+
| `WorkspaceEnvVar` | Env var with value-source semantics (`execution_dir`, `workspace_root`) |
|
|
202
273
|
| `FailureClassification` | Classified error with retryable flag and category |
|
|
203
274
|
|
|
204
275
|
### Run long-lived CLI sessions
|
|
@@ -223,7 +294,7 @@ result = await run_interactive_session(
|
|
|
223
294
|
```
|
|
224
295
|
|
|
225
296
|
Only `cmd_parts`, `cwd`, `stdin_text`, and `logger` are required.
|
|
226
|
-
|
|
297
|
+
Other parameters have sensible defaults.
|
|
227
298
|
|
|
228
299
|
## API summary
|
|
229
300
|
|
|
@@ -234,10 +305,11 @@ Key function groups:
|
|
|
234
305
|
|-------|-----------|
|
|
235
306
|
| Execution | `run_cli_command`, `run_cli_command_sync`, `run_interactive_session` |
|
|
236
307
|
| Provider metadata | `get_provider_contract`, `get_provider_spec`, `list_provider_specs` |
|
|
237
|
-
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth` |
|
|
308
|
+
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth`, `resolve_workspace_env`, `resolve_session_search_paths` |
|
|
238
309
|
| Headless launch | `build_claude_headless_core`, `build_codex_headless_core`, `build_copilot_headless_core`, `build_gemini_headless_core` |
|
|
239
310
|
| Codex batch | `build_codex_exec_spec` |
|
|
240
311
|
| Failure handling | `classify_provider_failure` |
|
|
312
|
+
| Installation check | `is_provider_installed` |
|
|
241
313
|
| Session logs | `find_codex_session`, `find_claude_session` |
|
|
242
314
|
| Schema | `load_schema`, `validate_payload` |
|
|
243
315
|
| Utilities | `redact_text`, `build_model_id`, `normalize_path_str` |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coding-cli-runtime"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Reusable CLI runtime primitives for provider-backed automation workflows"
|
|
9
9
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
10
10
|
license = "MIT"
|
|
@@ -94,7 +94,7 @@ disallow_untyped_defs = false
|
|
|
94
94
|
warn_return_any = false
|
|
95
95
|
|
|
96
96
|
[tool.bumpversion]
|
|
97
|
-
current_version = "0.
|
|
97
|
+
current_version = "0.4.0"
|
|
98
98
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
99
99
|
serialize = ["{major}.{minor}.{patch}"]
|
|
100
100
|
commit = true
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__version__ = "0.3.0"
|
|
6
|
-
|
|
7
5
|
from .auth import AuthResolution, resolve_auth
|
|
8
6
|
from .codex_cli import CodexExecSpec, build_codex_exec_spec
|
|
9
7
|
from .contracts import (
|
|
@@ -24,16 +22,25 @@ from .headless import (
|
|
|
24
22
|
from .provider_contracts import (
|
|
25
23
|
ApprovalContract,
|
|
26
24
|
AuthContract,
|
|
25
|
+
DiagnosticsContract,
|
|
27
26
|
HeadlessContract,
|
|
27
|
+
IoContract,
|
|
28
|
+
OutputContract,
|
|
28
29
|
PathContract,
|
|
29
30
|
PromptPayload,
|
|
30
31
|
PromptTransport,
|
|
31
32
|
ProviderContract,
|
|
32
33
|
SandboxContract,
|
|
34
|
+
SessionDiscoveryContract,
|
|
35
|
+
WorkspaceEnvValueSource,
|
|
36
|
+
WorkspaceEnvVar,
|
|
33
37
|
build_env_overlay,
|
|
34
38
|
get_provider_contract,
|
|
39
|
+
is_provider_installed,
|
|
35
40
|
render_prompt,
|
|
36
41
|
resolve_config_paths,
|
|
42
|
+
resolve_session_search_paths,
|
|
43
|
+
resolve_workspace_env,
|
|
37
44
|
)
|
|
38
45
|
from .provider_controls import build_model_id, resolve_provider_model_controls
|
|
39
46
|
from .provider_specs import (
|
|
@@ -75,6 +82,8 @@ from .session_logs import (
|
|
|
75
82
|
)
|
|
76
83
|
from .subprocess_runner import run_cli_command, run_cli_command_sync
|
|
77
84
|
|
|
85
|
+
__version__ = "0.4.0"
|
|
86
|
+
|
|
78
87
|
__all__ = [
|
|
79
88
|
"ApprovalContract",
|
|
80
89
|
"AuthContract",
|
|
@@ -87,10 +96,13 @@ __all__ = [
|
|
|
87
96
|
"ClaudeReasoningPolicy",
|
|
88
97
|
"CliLaunchSpec",
|
|
89
98
|
"ControlSpec",
|
|
99
|
+
"DiagnosticsContract",
|
|
90
100
|
"ErrorCode",
|
|
91
101
|
"FailureClassification",
|
|
92
102
|
"HeadlessContract",
|
|
103
|
+
"IoContract",
|
|
93
104
|
"ModelSpec",
|
|
105
|
+
"OutputContract",
|
|
94
106
|
"PathContract",
|
|
95
107
|
"PromptPayload",
|
|
96
108
|
"PromptTransport",
|
|
@@ -98,6 +110,9 @@ __all__ = [
|
|
|
98
110
|
"ProviderSpec",
|
|
99
111
|
"SandboxContract",
|
|
100
112
|
"SchemaValidationError",
|
|
113
|
+
"SessionDiscoveryContract",
|
|
114
|
+
"WorkspaceEnvVar",
|
|
115
|
+
"WorkspaceEnvValueSource",
|
|
101
116
|
"InteractiveCliRunResult",
|
|
102
117
|
"SessionProgressEvent",
|
|
103
118
|
"SessionRetryDecision",
|
|
@@ -121,6 +136,7 @@ __all__ = [
|
|
|
121
136
|
"get_gemini_model_options",
|
|
122
137
|
"get_provider_contract",
|
|
123
138
|
"get_provider_spec",
|
|
139
|
+
"is_provider_installed",
|
|
124
140
|
"list_provider_specs",
|
|
125
141
|
"build_model_id",
|
|
126
142
|
"classify_provider_failure",
|
|
@@ -130,6 +146,8 @@ __all__ = [
|
|
|
130
146
|
"resolve_claude_reasoning_policy",
|
|
131
147
|
"resolve_config_paths",
|
|
132
148
|
"resolve_provider_model_controls",
|
|
149
|
+
"resolve_session_search_paths",
|
|
150
|
+
"resolve_workspace_env",
|
|
133
151
|
"redact_text",
|
|
134
152
|
"claude_project_key",
|
|
135
153
|
"find_claude_session",
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_contracts.py
RENAMED
|
@@ -5,7 +5,8 @@ config paths, and headless launch conventions. It exposes frozen dataclasses
|
|
|
5
5
|
that consumers can read selectively — no obligation to use the full structure.
|
|
6
6
|
|
|
7
7
|
Public stable API:
|
|
8
|
-
get_provider_contract, build_env_overlay, resolve_config_paths, render_prompt
|
|
8
|
+
get_provider_contract, build_env_overlay, resolve_config_paths, render_prompt,
|
|
9
|
+
resolve_workspace_env, resolve_session_search_paths, is_provider_installed
|
|
9
10
|
|
|
10
11
|
Internal (not exported from __init__):
|
|
11
12
|
_build_non_interactive_run
|
|
@@ -13,8 +14,10 @@ Internal (not exported from __init__):
|
|
|
13
14
|
|
|
14
15
|
from __future__ import annotations
|
|
15
16
|
|
|
17
|
+
import shutil
|
|
16
18
|
from dataclasses import dataclass
|
|
17
19
|
from pathlib import Path
|
|
20
|
+
from typing import Literal, TypeAlias
|
|
18
21
|
|
|
19
22
|
from .contracts import AuthMode
|
|
20
23
|
|
|
@@ -105,6 +108,51 @@ class HeadlessContract:
|
|
|
105
108
|
default_stream_mode: str | None
|
|
106
109
|
|
|
107
110
|
|
|
111
|
+
@dataclass(frozen=True)
|
|
112
|
+
class OutputContract:
|
|
113
|
+
"""How the CLI delivers structured output."""
|
|
114
|
+
|
|
115
|
+
format_flag: str | None
|
|
116
|
+
supported_formats: tuple[str, ...]
|
|
117
|
+
default_format: str | None
|
|
118
|
+
output_path_flag: str | None
|
|
119
|
+
schema_path_flag: str | None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
WorkspaceEnvValueSource: TypeAlias = Literal["execution_dir", "workspace_root"]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass(frozen=True)
|
|
126
|
+
class WorkspaceEnvVar:
|
|
127
|
+
"""An environment variable expected by the provider CLI."""
|
|
128
|
+
|
|
129
|
+
name: str
|
|
130
|
+
value_source: WorkspaceEnvValueSource
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@dataclass(frozen=True)
|
|
134
|
+
class IoContract:
|
|
135
|
+
"""Provider-specific I/O conventions beyond prompt transport."""
|
|
136
|
+
|
|
137
|
+
file_reference_prefix: str | None
|
|
138
|
+
workspace_env_vars: tuple[WorkspaceEnvVar, ...]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass(frozen=True)
|
|
142
|
+
class SessionDiscoveryContract:
|
|
143
|
+
"""Where session logs live and how to find them."""
|
|
144
|
+
|
|
145
|
+
session_roots: tuple[str, ...]
|
|
146
|
+
session_glob: str
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass(frozen=True)
|
|
150
|
+
class DiagnosticsContract:
|
|
151
|
+
"""Where provider diagnostic logs live."""
|
|
152
|
+
|
|
153
|
+
log_glob: str
|
|
154
|
+
|
|
155
|
+
|
|
108
156
|
@dataclass(frozen=True)
|
|
109
157
|
class ProviderContract:
|
|
110
158
|
"""Structured metadata about a provider CLI.
|
|
@@ -118,6 +166,10 @@ class ProviderContract:
|
|
|
118
166
|
auth: AuthContract
|
|
119
167
|
paths: PathContract
|
|
120
168
|
headless: HeadlessContract
|
|
169
|
+
output: OutputContract
|
|
170
|
+
io: IoContract
|
|
171
|
+
session_discovery: SessionDiscoveryContract | None
|
|
172
|
+
diagnostics: DiagnosticsContract | None
|
|
121
173
|
notes: tuple[str, ...]
|
|
122
174
|
|
|
123
175
|
|
|
@@ -178,6 +230,22 @@ _CLAUDE_CONTRACT = ProviderContract(
|
|
|
178
230
|
stream_modes=None,
|
|
179
231
|
default_stream_mode=None,
|
|
180
232
|
),
|
|
233
|
+
output=OutputContract(
|
|
234
|
+
format_flag="--output-format",
|
|
235
|
+
supported_formats=("text", "json", "stream-json"),
|
|
236
|
+
default_format="text",
|
|
237
|
+
output_path_flag=None,
|
|
238
|
+
schema_path_flag=None,
|
|
239
|
+
),
|
|
240
|
+
io=IoContract(
|
|
241
|
+
file_reference_prefix=None,
|
|
242
|
+
workspace_env_vars=(),
|
|
243
|
+
),
|
|
244
|
+
session_discovery=SessionDiscoveryContract(
|
|
245
|
+
session_roots=("projects",),
|
|
246
|
+
session_glob="*/conversation.jsonl",
|
|
247
|
+
),
|
|
248
|
+
diagnostics=None,
|
|
181
249
|
notes=(),
|
|
182
250
|
)
|
|
183
251
|
|
|
@@ -217,6 +285,22 @@ _CODEX_CONTRACT = ProviderContract(
|
|
|
217
285
|
stream_modes=None,
|
|
218
286
|
default_stream_mode=None,
|
|
219
287
|
),
|
|
288
|
+
output=OutputContract(
|
|
289
|
+
format_flag=None,
|
|
290
|
+
supported_formats=("json",),
|
|
291
|
+
default_format="json",
|
|
292
|
+
output_path_flag="-o",
|
|
293
|
+
schema_path_flag="--output-schema",
|
|
294
|
+
),
|
|
295
|
+
io=IoContract(
|
|
296
|
+
file_reference_prefix=None,
|
|
297
|
+
workspace_env_vars=(),
|
|
298
|
+
),
|
|
299
|
+
session_discovery=SessionDiscoveryContract(
|
|
300
|
+
session_roots=("sessions", "archived_sessions"),
|
|
301
|
+
session_glob="*.jsonl",
|
|
302
|
+
),
|
|
303
|
+
diagnostics=None,
|
|
220
304
|
notes=(
|
|
221
305
|
"codex exec defaults to a read-only sandbox in non-interactive mode; "
|
|
222
306
|
"use --sandbox danger-full-access for write access.",
|
|
@@ -258,9 +342,32 @@ _GEMINI_CONTRACT = ProviderContract(
|
|
|
258
342
|
stream_modes=None,
|
|
259
343
|
default_stream_mode=None,
|
|
260
344
|
),
|
|
345
|
+
output=OutputContract(
|
|
346
|
+
format_flag=None,
|
|
347
|
+
supported_formats=(),
|
|
348
|
+
default_format=None,
|
|
349
|
+
output_path_flag=None,
|
|
350
|
+
schema_path_flag=None,
|
|
351
|
+
),
|
|
352
|
+
io=IoContract(
|
|
353
|
+
file_reference_prefix="@",
|
|
354
|
+
workspace_env_vars=(
|
|
355
|
+
WorkspaceEnvVar(
|
|
356
|
+
name="GEMINI_CLI_IDE_WORKSPACE_PATH",
|
|
357
|
+
value_source="execution_dir",
|
|
358
|
+
),
|
|
359
|
+
),
|
|
360
|
+
),
|
|
361
|
+
session_discovery=SessionDiscoveryContract(
|
|
362
|
+
session_roots=("tmp",),
|
|
363
|
+
session_glob="*/chats/session-*.json",
|
|
364
|
+
),
|
|
365
|
+
diagnostics=None,
|
|
261
366
|
notes=(
|
|
262
367
|
'Gemini requires --prompt "" to activate headless mode; '
|
|
263
368
|
"the real prompt is delivered on stdin.",
|
|
369
|
+
"Gemini output format is prompt-directed, not CLI-flag-driven.",
|
|
370
|
+
"File references in prompts use @filename syntax.",
|
|
264
371
|
),
|
|
265
372
|
)
|
|
266
373
|
|
|
@@ -295,6 +402,24 @@ _COPILOT_CONTRACT = ProviderContract(
|
|
|
295
402
|
stream_modes=("on", "off"),
|
|
296
403
|
default_stream_mode="on",
|
|
297
404
|
),
|
|
405
|
+
output=OutputContract(
|
|
406
|
+
format_flag=None,
|
|
407
|
+
supported_formats=("markdown",),
|
|
408
|
+
default_format="markdown",
|
|
409
|
+
output_path_flag="--share",
|
|
410
|
+
schema_path_flag=None,
|
|
411
|
+
),
|
|
412
|
+
io=IoContract(
|
|
413
|
+
file_reference_prefix=None,
|
|
414
|
+
workspace_env_vars=(),
|
|
415
|
+
),
|
|
416
|
+
session_discovery=SessionDiscoveryContract(
|
|
417
|
+
session_roots=("session-state",),
|
|
418
|
+
session_glob="*/events.jsonl",
|
|
419
|
+
),
|
|
420
|
+
diagnostics=DiagnosticsContract(
|
|
421
|
+
log_glob="logs/process-*.log",
|
|
422
|
+
),
|
|
298
423
|
notes=(
|
|
299
424
|
"Copilot default auth is CLI login (api_key_env_var is None). "
|
|
300
425
|
"BYOK is available via COPILOT_PROVIDER_API_KEY.",
|
|
@@ -350,6 +475,33 @@ def build_env_overlay(
|
|
|
350
475
|
return overlay
|
|
351
476
|
|
|
352
477
|
|
|
478
|
+
def resolve_workspace_env(
|
|
479
|
+
contract: ProviderContract,
|
|
480
|
+
execution_dir: str | Path,
|
|
481
|
+
*,
|
|
482
|
+
workspace_root: str | Path | None = None,
|
|
483
|
+
) -> dict[str, str]:
|
|
484
|
+
"""Resolve provider workspace env vars from contract metadata."""
|
|
485
|
+
resolved: dict[str, str] = {}
|
|
486
|
+
execution_dir_str = str(Path(execution_dir).expanduser())
|
|
487
|
+
workspace_root_str = None
|
|
488
|
+
if workspace_root is not None:
|
|
489
|
+
workspace_root_str = str(Path(workspace_root).expanduser())
|
|
490
|
+
|
|
491
|
+
for item in contract.io.workspace_env_vars:
|
|
492
|
+
if item.value_source == "execution_dir":
|
|
493
|
+
resolved[item.name] = execution_dir_str
|
|
494
|
+
continue
|
|
495
|
+
if item.value_source == "workspace_root":
|
|
496
|
+
if workspace_root_str is None:
|
|
497
|
+
raise ValueError(f"{item.name} requires workspace_root, but none was provided")
|
|
498
|
+
resolved[item.name] = workspace_root_str
|
|
499
|
+
continue
|
|
500
|
+
raise ValueError(f"Unknown workspace env value source: {item.value_source!r}")
|
|
501
|
+
|
|
502
|
+
return resolved
|
|
503
|
+
|
|
504
|
+
|
|
353
505
|
def resolve_config_paths(
|
|
354
506
|
contract: ProviderContract,
|
|
355
507
|
*,
|
|
@@ -366,6 +518,23 @@ def resolve_config_paths(
|
|
|
366
518
|
return host, host
|
|
367
519
|
|
|
368
520
|
|
|
521
|
+
def resolve_session_search_paths(
|
|
522
|
+
contract: ProviderContract,
|
|
523
|
+
*,
|
|
524
|
+
config_dir: str | Path | None = None,
|
|
525
|
+
) -> tuple[Path, ...]:
|
|
526
|
+
"""Expand contract session roots into concrete host paths."""
|
|
527
|
+
discovery = contract.session_discovery
|
|
528
|
+
if discovery is None:
|
|
529
|
+
return ()
|
|
530
|
+
base_dir = (
|
|
531
|
+
Path(config_dir).expanduser()
|
|
532
|
+
if config_dir is not None
|
|
533
|
+
else Path(contract.paths.config_dir).expanduser()
|
|
534
|
+
)
|
|
535
|
+
return tuple(base_dir / root for root in discovery.session_roots)
|
|
536
|
+
|
|
537
|
+
|
|
369
538
|
def render_prompt(
|
|
370
539
|
transport: PromptTransport,
|
|
371
540
|
prompt: str,
|
|
@@ -387,6 +556,12 @@ def render_prompt(
|
|
|
387
556
|
raise ValueError(f"Unknown prompt delivery mode: {transport.delivery!r}")
|
|
388
557
|
|
|
389
558
|
|
|
559
|
+
def is_provider_installed(provider_id: str) -> bool:
|
|
560
|
+
"""Return whether the provider CLI binary is available on PATH."""
|
|
561
|
+
contract = get_provider_contract(provider_id)
|
|
562
|
+
return shutil.which(contract.binary) is not None
|
|
563
|
+
|
|
564
|
+
|
|
390
565
|
# ---------------------------------------------------------------------------
|
|
391
566
|
# Private builder (internal convenience, not public API)
|
|
392
567
|
# ---------------------------------------------------------------------------
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coding-cli-runtime
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Reusable CLI runtime primitives for provider-backed automation workflows
|
|
5
5
|
Author-email: LLM Eval maintainers <llm-eval-maintainers@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -152,6 +152,44 @@ else:
|
|
|
152
152
|
Works for all four providers. Recognizes auth failures, rate limits,
|
|
153
153
|
network transients, and other provider-specific error patterns.
|
|
154
154
|
|
|
155
|
+
### Common integration tasks
|
|
156
|
+
|
|
157
|
+
#### Check whether a provider CLI is installed
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from coding_cli_runtime import is_provider_installed
|
|
161
|
+
|
|
162
|
+
if not is_provider_installed("claude"):
|
|
163
|
+
raise RuntimeError("Claude Code is not available on PATH")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This is intentionally minimal: it checks whether the provider binary exists on
|
|
167
|
+
PATH. Deeper CLI drift validation belongs in maintainer tooling, not the
|
|
168
|
+
runtime API.
|
|
169
|
+
|
|
170
|
+
#### Resolve workspace env vars and session search paths
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from coding_cli_runtime import (
|
|
174
|
+
get_provider_contract,
|
|
175
|
+
resolve_session_search_paths,
|
|
176
|
+
resolve_workspace_env,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
gemini = get_provider_contract("gemini")
|
|
180
|
+
|
|
181
|
+
# Derive provider-specific workspace env vars from contract metadata
|
|
182
|
+
env = resolve_workspace_env(gemini, "/tmp/run-dir")
|
|
183
|
+
# {"GEMINI_CLI_IDE_WORKSPACE_PATH": "/tmp/run-dir"}
|
|
184
|
+
|
|
185
|
+
# Expand concrete host paths for session log searches
|
|
186
|
+
paths = resolve_session_search_paths(gemini)
|
|
187
|
+
# (Path.home() / ".gemini" / "tmp",)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use these helpers when you want the contract facts turned into concrete
|
|
191
|
+
filesystem/env values without rebuilding the same glue logic in each consumer.
|
|
192
|
+
|
|
155
193
|
### Look up provider contract metadata
|
|
156
194
|
|
|
157
195
|
```python
|
|
@@ -179,11 +217,43 @@ payload = render_prompt(contract.headless.prompt, "Fix the bug")
|
|
|
179
217
|
```
|
|
180
218
|
|
|
181
219
|
`ProviderContract` is structured as nested sub-contracts
|
|
182
|
-
(`AuthContract`, `PathContract`, `HeadlessContract`
|
|
220
|
+
(`AuthContract`, `PathContract`, `HeadlessContract`, `OutputContract`,
|
|
221
|
+
`IoContract`, `SessionDiscoveryContract`, `DiagnosticsContract`) so consumers
|
|
183
222
|
can drill into whichever aspect they need. This is reference metadata,
|
|
184
|
-
not a command-construction control plane —
|
|
223
|
+
not a command-construction control plane — callers keep their own
|
|
185
224
|
command assembly and adopt contract fields selectively.
|
|
186
225
|
|
|
226
|
+
### Query provider I/O conventions
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from coding_cli_runtime import get_provider_contract
|
|
230
|
+
|
|
231
|
+
gemini = get_provider_contract("gemini")
|
|
232
|
+
|
|
233
|
+
# Workspace env vars with value semantics
|
|
234
|
+
for wev in gemini.io.workspace_env_vars:
|
|
235
|
+
print(f"{wev.name} = {wev.value_source}")
|
|
236
|
+
# GEMINI_CLI_IDE_WORKSPACE_PATH = execution_dir
|
|
237
|
+
|
|
238
|
+
# Session discovery (where session logs live)
|
|
239
|
+
sd = gemini.session_discovery
|
|
240
|
+
print(sd.session_roots) # ("tmp",)
|
|
241
|
+
print(sd.session_glob) # "*/chats/session-*.json"
|
|
242
|
+
|
|
243
|
+
# Output format support
|
|
244
|
+
codex = get_provider_contract("codex")
|
|
245
|
+
print(codex.output.output_path_flag) # "-o"
|
|
246
|
+
print(codex.output.schema_path_flag) # "--output-schema"
|
|
247
|
+
|
|
248
|
+
# Diagnostics (Copilot only)
|
|
249
|
+
copilot = get_provider_contract("copilot")
|
|
250
|
+
if copilot.diagnostics:
|
|
251
|
+
print(copilot.diagnostics.log_glob) # "logs/process-*.log"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`WorkspaceEnvVar.value_source` uses a closed vocabulary:
|
|
255
|
+
`"execution_dir"` or `"workspace_root"`.
|
|
256
|
+
|
|
187
257
|
### Build headless launch commands
|
|
188
258
|
|
|
189
259
|
```python
|
|
@@ -224,7 +294,8 @@ files matching the working directory and time window.
|
|
|
224
294
|
| `CliRunResult` | Result: returncode, stdout/stderr, duration, error code |
|
|
225
295
|
| `ErrorCode` | `none` · `spawn_failed` · `timed_out` · `non_zero_exit` |
|
|
226
296
|
| `ProviderSpec` | Provider catalog entry with models, controls, defaults |
|
|
227
|
-
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless
|
|
297
|
+
| `ProviderContract` | Structured provider CLI metadata (auth, paths, headless, I/O, sessions) |
|
|
298
|
+
| `WorkspaceEnvVar` | Env var with value-source semantics (`execution_dir`, `workspace_root`) |
|
|
228
299
|
| `FailureClassification` | Classified error with retryable flag and category |
|
|
229
300
|
|
|
230
301
|
### Run long-lived CLI sessions
|
|
@@ -249,7 +320,7 @@ result = await run_interactive_session(
|
|
|
249
320
|
```
|
|
250
321
|
|
|
251
322
|
Only `cmd_parts`, `cwd`, `stdin_text`, and `logger` are required.
|
|
252
|
-
|
|
323
|
+
Other parameters have sensible defaults.
|
|
253
324
|
|
|
254
325
|
## API summary
|
|
255
326
|
|
|
@@ -260,10 +331,11 @@ Key function groups:
|
|
|
260
331
|
|-------|-----------|
|
|
261
332
|
| Execution | `run_cli_command`, `run_cli_command_sync`, `run_interactive_session` |
|
|
262
333
|
| Provider metadata | `get_provider_contract`, `get_provider_spec`, `list_provider_specs` |
|
|
263
|
-
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth` |
|
|
334
|
+
| Contract helpers | `build_env_overlay`, `resolve_config_paths`, `render_prompt`, `resolve_auth`, `resolve_workspace_env`, `resolve_session_search_paths` |
|
|
264
335
|
| Headless launch | `build_claude_headless_core`, `build_codex_headless_core`, `build_copilot_headless_core`, `build_gemini_headless_core` |
|
|
265
336
|
| Codex batch | `build_codex_exec_spec` |
|
|
266
337
|
| Failure handling | `classify_provider_failure` |
|
|
338
|
+
| Installation check | `is_provider_installed` |
|
|
267
339
|
| Session logs | `find_codex_session`, `find_claude_session` |
|
|
268
340
|
| Schema | `load_schema`, `validate_payload` |
|
|
269
341
|
| Utilities | `redact_text`, `build_model_id`, `normalize_path_str` |
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/SOURCES.txt
RENAMED
|
@@ -37,4 +37,6 @@ tests/test_playground_probe_smoke.py
|
|
|
37
37
|
tests/test_provider_catalog_resolution.py
|
|
38
38
|
tests/test_provider_contracts.py
|
|
39
39
|
tests/test_runtime_parity.py
|
|
40
|
-
tests/test_stage2_tier1.py
|
|
40
|
+
tests/test_stage2_tier1.py
|
|
41
|
+
tests/test_stage3_io_contracts.py
|
|
42
|
+
tests/test_stage4_helpers.py
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Tests for provider I/O contract types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import get_args, get_type_hints
|
|
6
|
+
|
|
7
|
+
from coding_cli_runtime.provider_contracts import (
|
|
8
|
+
WorkspaceEnvValueSource,
|
|
9
|
+
WorkspaceEnvVar,
|
|
10
|
+
get_provider_contract,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
ALL_PROVIDERS = ("claude", "codex", "gemini", "copilot")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ── OutputContract ────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestOutputContract:
|
|
20
|
+
def test_claude_has_format_flag(self) -> None:
|
|
21
|
+
c = get_provider_contract("claude")
|
|
22
|
+
assert c.output.format_flag == "--output-format"
|
|
23
|
+
assert "text" in c.output.supported_formats
|
|
24
|
+
assert "json" in c.output.supported_formats
|
|
25
|
+
assert "stream-json" in c.output.supported_formats
|
|
26
|
+
assert c.output.default_format == "text"
|
|
27
|
+
|
|
28
|
+
def test_codex_has_output_path_flag(self) -> None:
|
|
29
|
+
c = get_provider_contract("codex")
|
|
30
|
+
assert c.output.output_path_flag == "-o"
|
|
31
|
+
assert c.output.schema_path_flag == "--output-schema"
|
|
32
|
+
assert c.output.format_flag is None
|
|
33
|
+
|
|
34
|
+
def test_gemini_has_no_output_flags(self) -> None:
|
|
35
|
+
c = get_provider_contract("gemini")
|
|
36
|
+
assert c.output.format_flag is None
|
|
37
|
+
assert c.output.output_path_flag is None
|
|
38
|
+
assert len(c.output.supported_formats) == 0
|
|
39
|
+
|
|
40
|
+
def test_copilot_has_share_flag(self) -> None:
|
|
41
|
+
c = get_provider_contract("copilot")
|
|
42
|
+
assert c.output.output_path_flag == "--share"
|
|
43
|
+
assert c.output.format_flag is None
|
|
44
|
+
assert "markdown" in c.output.supported_formats
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ── IoContract ────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestIoContract:
|
|
51
|
+
def test_workspace_env_value_source_is_closed_vocabulary(self) -> None:
|
|
52
|
+
hints = get_type_hints(WorkspaceEnvVar)
|
|
53
|
+
assert hints["value_source"] == WorkspaceEnvValueSource
|
|
54
|
+
assert get_args(WorkspaceEnvValueSource) == ("execution_dir", "workspace_root")
|
|
55
|
+
|
|
56
|
+
def test_gemini_file_reference_prefix(self) -> None:
|
|
57
|
+
c = get_provider_contract("gemini")
|
|
58
|
+
assert c.io.file_reference_prefix == "@"
|
|
59
|
+
|
|
60
|
+
def test_other_providers_no_file_reference(self) -> None:
|
|
61
|
+
for pid in ("claude", "codex", "copilot"):
|
|
62
|
+
c = get_provider_contract(pid)
|
|
63
|
+
assert c.io.file_reference_prefix is None
|
|
64
|
+
|
|
65
|
+
def test_gemini_workspace_env_var(self) -> None:
|
|
66
|
+
c = get_provider_contract("gemini")
|
|
67
|
+
assert len(c.io.workspace_env_vars) == 1
|
|
68
|
+
wev = c.io.workspace_env_vars[0]
|
|
69
|
+
assert wev.name == "GEMINI_CLI_IDE_WORKSPACE_PATH"
|
|
70
|
+
assert wev.value_source == "execution_dir"
|
|
71
|
+
|
|
72
|
+
def test_other_providers_no_workspace_env_vars(self) -> None:
|
|
73
|
+
for pid in ("claude", "codex", "copilot"):
|
|
74
|
+
c = get_provider_contract(pid)
|
|
75
|
+
assert c.io.workspace_env_vars == ()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# ── SessionDiscoveryContract ──────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TestSessionDiscoveryContract:
|
|
82
|
+
def test_all_providers_have_session_discovery(self) -> None:
|
|
83
|
+
for pid in ALL_PROVIDERS:
|
|
84
|
+
c = get_provider_contract(pid)
|
|
85
|
+
assert c.session_discovery is not None
|
|
86
|
+
|
|
87
|
+
def test_codex_session_roots(self) -> None:
|
|
88
|
+
c = get_provider_contract("codex")
|
|
89
|
+
assert "sessions" in c.session_discovery.session_roots
|
|
90
|
+
assert "archived_sessions" in c.session_discovery.session_roots
|
|
91
|
+
|
|
92
|
+
def test_claude_session_glob(self) -> None:
|
|
93
|
+
c = get_provider_contract("claude")
|
|
94
|
+
assert c.session_discovery.session_glob == "*/conversation.jsonl"
|
|
95
|
+
|
|
96
|
+
def test_copilot_session_discovery(self) -> None:
|
|
97
|
+
c = get_provider_contract("copilot")
|
|
98
|
+
assert "session-state" in c.session_discovery.session_roots
|
|
99
|
+
assert "events.jsonl" in c.session_discovery.session_glob
|
|
100
|
+
|
|
101
|
+
def test_gemini_session_discovery(self) -> None:
|
|
102
|
+
c = get_provider_contract("gemini")
|
|
103
|
+
assert "tmp" in c.session_discovery.session_roots
|
|
104
|
+
assert c.session_discovery.session_glob == "*/chats/session-*.json"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# ── DiagnosticsContract ───────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class TestDiagnosticsContract:
|
|
111
|
+
def test_copilot_has_diagnostics(self) -> None:
|
|
112
|
+
c = get_provider_contract("copilot")
|
|
113
|
+
assert c.diagnostics is not None
|
|
114
|
+
assert "process-*.log" in c.diagnostics.log_glob
|
|
115
|
+
|
|
116
|
+
def test_other_providers_no_diagnostics(self) -> None:
|
|
117
|
+
for pid in ("claude", "codex", "gemini"):
|
|
118
|
+
c = get_provider_contract(pid)
|
|
119
|
+
assert c.diagnostics is None
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Tests for consumer-UX helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import replace
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from coding_cli_runtime import (
|
|
11
|
+
IoContract,
|
|
12
|
+
WorkspaceEnvVar,
|
|
13
|
+
get_provider_contract,
|
|
14
|
+
is_provider_installed,
|
|
15
|
+
resolve_session_search_paths,
|
|
16
|
+
resolve_workspace_env,
|
|
17
|
+
)
|
|
18
|
+
from coding_cli_runtime import provider_contracts as provider_contracts_mod
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestResolveWorkspaceEnv:
|
|
22
|
+
def test_gemini_workspace_env_uses_execution_dir(self) -> None:
|
|
23
|
+
contract = get_provider_contract("gemini")
|
|
24
|
+
|
|
25
|
+
env = resolve_workspace_env(contract, "/tmp/run-dir")
|
|
26
|
+
|
|
27
|
+
assert env == {"GEMINI_CLI_IDE_WORKSPACE_PATH": "/tmp/run-dir"}
|
|
28
|
+
|
|
29
|
+
def test_provider_with_no_workspace_env_vars_returns_empty_dict(self) -> None:
|
|
30
|
+
contract = get_provider_contract("claude")
|
|
31
|
+
|
|
32
|
+
env = resolve_workspace_env(contract, "/tmp/run-dir")
|
|
33
|
+
|
|
34
|
+
assert env == {}
|
|
35
|
+
|
|
36
|
+
def test_workspace_root_value_source_requires_workspace_root(self) -> None:
|
|
37
|
+
base = get_provider_contract("claude")
|
|
38
|
+
contract = replace(
|
|
39
|
+
base,
|
|
40
|
+
io=IoContract(
|
|
41
|
+
file_reference_prefix=None,
|
|
42
|
+
workspace_env_vars=(
|
|
43
|
+
WorkspaceEnvVar(
|
|
44
|
+
name="TEST_WORKSPACE_ROOT",
|
|
45
|
+
value_source="workspace_root",
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
with pytest.raises(ValueError, match="requires workspace_root"):
|
|
52
|
+
resolve_workspace_env(contract, "/tmp/execution-dir")
|
|
53
|
+
|
|
54
|
+
env = resolve_workspace_env(
|
|
55
|
+
contract,
|
|
56
|
+
"/tmp/execution-dir",
|
|
57
|
+
workspace_root="/tmp/workspace-root",
|
|
58
|
+
)
|
|
59
|
+
assert env == {"TEST_WORKSPACE_ROOT": "/tmp/workspace-root"}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TestResolveSessionSearchPaths:
|
|
63
|
+
def test_gemini_defaults_to_config_dir_tmp_root(self) -> None:
|
|
64
|
+
contract = get_provider_contract("gemini")
|
|
65
|
+
|
|
66
|
+
paths = resolve_session_search_paths(contract)
|
|
67
|
+
|
|
68
|
+
assert paths == (Path("~/.gemini").expanduser() / "tmp",)
|
|
69
|
+
|
|
70
|
+
def test_defaults_to_contract_config_dir(self) -> None:
|
|
71
|
+
contract = get_provider_contract("claude")
|
|
72
|
+
|
|
73
|
+
paths = resolve_session_search_paths(contract)
|
|
74
|
+
|
|
75
|
+
assert paths == (Path("~/.claude").expanduser() / "projects",)
|
|
76
|
+
|
|
77
|
+
def test_honors_config_dir_override(self) -> None:
|
|
78
|
+
contract = get_provider_contract("codex")
|
|
79
|
+
|
|
80
|
+
paths = resolve_session_search_paths(contract, config_dir="/tmp/codex-config")
|
|
81
|
+
|
|
82
|
+
assert paths == (
|
|
83
|
+
Path("/tmp/codex-config") / "sessions",
|
|
84
|
+
Path("/tmp/codex-config") / "archived_sessions",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def test_returns_empty_tuple_when_session_discovery_is_none(self) -> None:
|
|
88
|
+
base = get_provider_contract("copilot")
|
|
89
|
+
contract = replace(base, session_discovery=None)
|
|
90
|
+
|
|
91
|
+
paths = resolve_session_search_paths(contract)
|
|
92
|
+
|
|
93
|
+
assert paths == ()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class TestIsProviderInstalled:
|
|
97
|
+
def test_returns_true_when_binary_is_found(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
98
|
+
monkeypatch.setattr(provider_contracts_mod.shutil, "which", lambda _: "/usr/bin/claude")
|
|
99
|
+
|
|
100
|
+
assert is_provider_installed("claude") is True
|
|
101
|
+
|
|
102
|
+
def test_returns_false_when_binary_is_missing(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
103
|
+
monkeypatch.setattr(provider_contracts_mod.shutil, "which", lambda _: None)
|
|
104
|
+
|
|
105
|
+
assert is_provider_installed("copilot") is False
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
|
-
|
|
7
|
-
## [Unreleased]
|
|
8
|
-
|
|
9
|
-
## [0.3.0] - 2026-04-09
|
|
10
|
-
|
|
11
|
-
### Added
|
|
12
|
-
- **Headless launch core helpers** — per-provider arg renderers derived from
|
|
13
|
-
`ProviderContract.headless`: `build_claude_headless_core()`,
|
|
14
|
-
`build_codex_headless_core()`, `build_copilot_headless_core()`,
|
|
15
|
-
`build_gemini_headless_core()`. All consumers (app-generation, feather,
|
|
16
|
-
codex_cli, provider_contracts builder) now delegate to these.
|
|
17
|
-
- `scan_session_dir()` — generic directory-scanning primitive for session log
|
|
18
|
-
discovery with `extract_fn` callback (internal, not in public `__all__`).
|
|
19
|
-
- Session log discovery section in README.
|
|
20
|
-
- API summary table in README.
|
|
21
|
-
- 27 new Stage 2 tests for headless cores, builder delegation, and
|
|
22
|
-
`scan_session_dir`.
|
|
23
|
-
|
|
24
|
-
### Changed
|
|
25
|
-
- `build_codex_exec_spec()` now delegates to `build_codex_headless_core()`.
|
|
26
|
-
`full_auto` and `skip_git_repo_check` params preserved and passed through.
|
|
27
|
-
- `_build_non_interactive_run()` now delegates to per-provider headless core
|
|
28
|
-
helpers instead of assembling flags inline.
|
|
29
|
-
- Feather `report_data.py` and `report_sections.py` use headless core helpers
|
|
30
|
-
with fallback for environments without `coding_cli_runtime`.
|
|
31
|
-
- Feather `generate_report.py` Codex session discovery replaced with
|
|
32
|
-
`find_codex_session()` from `coding_cli_runtime`.
|
|
33
|
-
- App-generation `claude_impl.py`, `copilot_impl.py`, `gemini_impl.py`
|
|
34
|
-
`build_command()` functions delegate to headless core helpers.
|
|
35
|
-
- Dead headless opt-out flags removed from Copilot (`--allow-all`, `--ask-user`,
|
|
36
|
-
`--use-custom-instructions`) and Gemini (`--auto-approve`) CLI specs —
|
|
37
|
-
these were never used in batch runs and are now handled by the headless core.
|
|
38
|
-
- README rewritten: user-action feature list, `run_interactive_session` example,
|
|
39
|
-
`uv add` install, API summary, Contributing link, session log discovery.
|
|
40
|
-
|
|
41
|
-
## [0.2.0] - 2026-04-08
|
|
42
|
-
|
|
43
|
-
### Added
|
|
44
|
-
- **ProviderContract API** — structured, nested metadata for all four provider CLIs
|
|
45
|
-
(Claude, Codex, Gemini, Copilot). Composed of `AuthContract`, `PathContract`,
|
|
46
|
-
`HeadlessContract`, `PromptTransport`, `ApprovalContract`, `SandboxContract`.
|
|
47
|
-
- `get_provider_contract(provider_id)` — returns structured contract for a provider.
|
|
48
|
-
- `build_env_overlay(contract, api_key, base_url)` — builds provider-specific env
|
|
49
|
-
var overlay from contract metadata.
|
|
50
|
-
- `resolve_config_paths(contract, containerized)` — resolves host and container
|
|
51
|
-
config directory paths.
|
|
52
|
-
- `render_prompt(transport, prompt)` — resolves prompt delivery into argv args +
|
|
53
|
-
stdin text based on provider transport mode.
|
|
54
|
-
- `PromptPayload` dataclass for resolved prompt delivery.
|
|
55
|
-
- `__version__` attribute in `coding_cli_runtime`.
|
|
56
|
-
- `CONTRIBUTING.md`, `MANIFEST.in`, `.pre-commit-config.yaml`.
|
|
57
|
-
- PyPI / Python / Build / License badges in `README.md`.
|
|
58
|
-
- `bump-my-version` configuration syncing `pyproject.toml` and `__init__.py`.
|
|
59
|
-
- `ruff`, `mypy` (strict), and `pytest-cov` added to dev dependencies.
|
|
60
|
-
- CI quality gates: ruff check, ruff format, mypy, pytest-cov.
|
|
61
|
-
- README section documenting the new ProviderContract API with examples.
|
|
62
|
-
- 75 new tests for provider contracts, helpers, internal builder, failure
|
|
63
|
-
classification, codex_cli, schema validation (including nested), reasoning,
|
|
64
|
-
redaction, json_io, provider_controls, and auth. Package coverage 47% → 62%.
|
|
65
|
-
|
|
66
|
-
### Changed
|
|
67
|
-
- Consolidated `shared_cli_runtime` into `coding_cli_runtime`. The package now
|
|
68
|
-
ships a single top-level package; the `shared_cli_runtime` directory is removed.
|
|
69
|
-
- `MANIFEST.in` and docs updated to reference `coding_cli_runtime` paths.
|
|
70
|
-
- `run_interactive_session()` observability kwargs (`provider_label`, `job_name`,
|
|
71
|
-
`phase_tag`, `process_label`, `timeout_seconds`) now have sensible defaults so
|
|
72
|
-
external callers don't need to supply internal batch-system labels.
|
|
73
|
-
- Provider model catalogs are now resolved with a three-tier fallback:
|
|
74
|
-
user override file > live CLI discovery > hardcoded fallback.
|
|
75
|
-
- `auth.py`: `_PROVIDER_ENV_HINTS` now derived from `provider_contracts.py`
|
|
76
|
-
(single source of truth for auth env var names).
|
|
77
|
-
- `CliRunResult.command` type widened from `tuple[str, ...]` to `Sequence[str]`.
|
|
78
|
-
- Publish workflow path corrected (`shared-cli-runtime` → `coding-cli-runtime`).
|
|
79
|
-
|
|
80
|
-
### Fixed
|
|
81
|
-
- mypy strict compliance: return-type annotations, per-module overrides.
|
|
82
|
-
- ruff lint and format compliance across all source and test files.
|
|
83
|
-
- Copilot BYOK (`COPILOT_PROVIDER_API_KEY`) now discoverable via contract
|
|
84
|
-
but not reported as "required" in `resolve_auth()` — BYOK is opt-in.
|
|
85
|
-
|
|
86
|
-
## [0.1.0] - 2026-04-07
|
|
87
|
-
|
|
88
|
-
### Added
|
|
89
|
-
- Initial extraction from `llm-eval` monorepo.
|
|
90
|
-
- Provider metadata and controls for Claude, Codex, Copilot, and Gemini CLIs.
|
|
91
|
-
- Shared request/result contracts (`CliRunRequest`, `CliRunResult`, `CliLaunchSpec`).
|
|
92
|
-
- Schema loading and payload validation (`load_schema`, `validate_payload`).
|
|
93
|
-
- Synchronous and asynchronous subprocess execution helpers.
|
|
94
|
-
- Interactive session execution with transcript mirroring.
|
|
95
|
-
- Session log discovery and parsing utilities.
|
|
96
|
-
- Claude reasoning policy resolution.
|
|
97
|
-
- Log redaction helpers.
|
|
98
|
-
- Copilot reasoning log parsing and classification.
|
|
99
|
-
- PEP 561 `py.typed` markers for both `coding_cli_runtime` and `shared_cli_runtime`.
|
|
100
|
-
- Packaged JSON schemas and Copilot reasoning baseline data.
|
|
101
|
-
- Playground knowledge base with probing guides and experiment templates.
|
|
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
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_controls.py
RENAMED
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/provider_specs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/schema_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/session_execution.py
RENAMED
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/session_logs.py
RENAMED
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime/subprocess_runner.py
RENAMED
|
File without changes
|
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/src/coding_cli_runtime.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{coding_cli_runtime-0.3.0 → coding_cli_runtime-0.4.0}/tests/test_provider_catalog_resolution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|