Skip to content

feat: add CLI framework base and codex CLI integration #781

Merged
Devesh36 merged 18 commits intoTracer-Cloud:mainfrom
muddlebee:cli-base
Apr 23, 2026
Merged

feat: add CLI framework base and codex CLI integration #781
Devesh36 merged 18 commits intoTracer-Cloud:mainfrom
muddlebee:cli-base

Conversation

@muddlebee
Copy link
Copy Markdown
Collaborator

@muddlebee muddlebee commented Apr 23, 2026

Fixes #642

Describe the changes you have made in this PR -

Code specs/architecture as per #642 (comment)

Screenshots of the UI changes (If any) -

Success scenario - when codex binary present and logged in

Screencast.from.23-04-26.02.03.43.PM.IST.webm

Final Output 👇
image

Failure scenario - where codex binary path is not detected in default paths

Screencast.from.23-04-26.02.42.59.PM.IST.webm

Code Understanding and AI Usage

Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?

  • No, I wrote all the code myself
  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

Note: Please check Allow edits from maintainers if you would like us to assist in the PR.

- Introduced support for OpenAI Codex as a CLI provider, allowing non-interactive execution via subprocess.
- Updated `.env.example` to include optional Codex configuration parameters.
- Enhanced `AGENTS.md` with details on the new Codex integration and its usage.
- Modified `app/config.py` to include Codex in the list of valid LLM providers.
- Updated CLI wizard to handle Codex onboarding, including environment variable synchronization.
- Added tests for Codex integration and CLI onboarding process.
- Refactored related components to support the new CLI-based LLM interactions.
@muddlebee muddlebee marked this pull request as draft April 23, 2026 06:17
@muddlebee muddlebee changed the title feat: add CLI integration base framework (WIP) feat: add CLI integration base framework Apr 23, 2026
Comment thread tests/integrations/llm_cli/test_codex_adapter.py Fixed
Comment thread app/integrations/llm_cli/base.py Fixed
Comment thread app/integrations/llm_cli/base.py Fixed
Comment thread app/integrations/llm_cli/base.py Fixed
Comment thread app/integrations/llm_cli/base.py Fixed
Comment thread app/integrations/llm_cli/codex.py Fixed
@muddlebee muddlebee closed this Apr 23, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR adds a subprocess-backed LLM CLI framework (app/integrations/llm_cli/) and wires OpenAI Codex CLI as the first provider, allowing opensre investigate to run without an API key by delegating to codex exec. The wizard onboarding flow, LLMSettings validator, and LLMProvider literal are all extended to handle the credential-less "codex" provider.

Key changes:

  • New LLMCLIAdapter Protocol + CLIProbe/CLIInvocation dataclasses in base.py define the extensible subprocess adapter contract
  • CLIBackedLLMClient in runner.py drives any adapter with guardrail application, TTL probe caching (45 s), ANSI stripping, and structured-output delegation
  • CodexAdapter in codex.py handles binary resolution across env override → PATH → platform-specific fallbacks, and auth classification with the substring-collision fix (negative phrases checked first)
  • The wizard _run_cli_llm_onboarding loop gives users up to 10 attempts to install/authenticate, with repick/retry/path-override choices
  • All three prior review concerns (auth substring collision, per-invoke probe latency, unreachable GuardrailBlockedError handler) are addressed in this revision
  • _LLMClientType in llm_client.py uses | Any to avoid a circular import, which collapses the union's type safety — the TYPE_CHECKING guard pattern would preserve static analysis without a runtime cycle

Confidence Score: 4/5

Safe to merge after fixing the _LLMClientType | Any annotation; all prior P0/P1 bugs from earlier rounds are resolved

All three previously flagged issues (auth substring collision, per-invoke probe latency, unreachable exception handler) are addressed. The framework is well-tested with 9 wizard state-machine tests and thorough CodexAdapter unit tests. The one remaining P1 is the _LLMClientType | Any annotation that silently disables type safety for the entire client union — fixable in a single line with TYPE_CHECKING. Two P2 style nits do not affect correctness.

app/services/llm_client.py (line 440 — _LLMClientType | Any type annotation)

Important Files Changed

Filename Overview
app/integrations/llm_cli/base.py New Protocol definition for LLMCLIAdapter with CLIProbe, CLIInvocation, and PromptDelivery types; well-structured and clean
app/integrations/llm_cli/runner.py New CLIBackedLLMClient with probe TTL caching (45s), guardrail application, and subprocess execution; ANSI regex only strips SGR sequences
app/integrations/llm_cli/codex.py CodexAdapter with robust binary resolution (env, PATH, fallbacks), auth classification (negative phrases checked first), and non-interactive exec via codex exec --ephemeral
app/services/llm_client.py Added codex provider branch and widened StructuredOutputClient to Any; _LLMClientType
app/cli/wizard/flow.py Added _run_cli_llm_onboarding loop (up to 10 attempts), repick/abort/retry flow for CLI providers, and credential_line in saved summary
app/cli/wizard/config.py Added CredentialKind literal, adapter_factory field to ProviderOption, CODEX_MODELS tuple, and codex ProviderOption with credential_kind=cli
app/config.py Added codex to LLMProvider literal and exempt from API key validation in LLMSettings model validator
app/cli/wizard/env_sync.py Fixed _provider_specific_keys to skip empty api_key_env; fixed sync_provider_env early-return guard to only apply when api_key_env is set
tests/integrations/llm_cli/test_codex_adapter.py Comprehensive unit tests for CodexAdapter: binary resolution, auth classification (including exit-0 Not logged in case), probe caching, and platform-specific path fallbacks
tests/cli/wizard/test_flow.py Added 9 new tests covering the full _run_cli_llm_onboarding state machine (ok, repick, retry, path-override, abort after max retries) and wizard codex path
app/nodes/chat.py Added guard raising ValueError when codex is selected for interactive chat, with a clear user-facing error message

Sequence Diagram

sequenceDiagram
    participant W as Wizard (flow.py)
    participant OB as _run_cli_llm_onboarding
    participant CA as CodexAdapter
    participant SP as subprocess
    participant C as CLIBackedLLMClient
    participant GR as GuardrailEngine

    W->>OB: provider (credential_kind=cli)
    loop up to 10 attempts
        OB->>CA: detect()
        CA->>SP: codex --version
        SP-->>CA: version / error
        CA->>SP: codex login status
        SP-->>CA: auth output
        CA-->>OB: CLIProbe(installed, logged_in, detail)
        alt installed and logged_in=True
            OB-->>W: ok
        else installed and logged_in not True
            OB->>W: show login menu retry or repick
        else not installed
            OB->>W: show install menu retry or path or repick
        end
    end
    OB-->>W: abort (max retries)

    note over C,GR: At invocation time
    C->>GR: engine.apply(flat_prompt)
    C->>C: _probe() TTL cache 45s
    C->>CA: build(prompt, model, workspace)
    CA->>SP: codex exec --ephemeral -s read-only -C ws -
    SP-->>CA: stdout / stderr / returncode
    CA-->>C: parse() content
    C-->>C: LLMResponse(content)
Loading

Reviews (3): Last reviewed commit: "fix(codeql): revert TYPE_CHECKING guard,..." | Re-trigger Greptile

Comment thread app/integrations/llm_cli/codex.py Outdated
Comment thread app/integrations/llm_cli/runner.py Outdated
Comment thread app/integrations/llm_cli/runner.py Outdated
@muddlebee muddlebee reopened this Apr 23, 2026
- Modified `.env.example` to clarify that an empty `CODEX_MODEL` uses the Codex CLI's configured default model.
- Removed `CODEX_LLM_CONFIG` from `app/config.py` as it is no longer needed.
- Updated `CODEX_MODELS` in `app/cli/wizard/config.py` to reflect the new model handling.
- Adjusted `CodexAdapter` in `app/integrations/llm_cli/codex.py` to accommodate the empty model value.
- Refactored `llm_client.py` to use `None` for the model when `CODEX_MODEL` is empty.
- Updated tests to ensure the new behavior is correctly implemented and validated.
- Normalize repo map table formatting

- Use checklist checkboxes in integration section

- Drop redundant llm_cli bullet (matches main layout)

Made-with: Cursor
- Updated the onboarding process to handle authentication status more effectively, allowing users to retry or repick providers based on their login state.
- Introduced clearer prompts for users when authentication is required or unclear.
- Adjusted tests to validate the new onboarding behavior, ensuring correct handling of login states and user choices during the onboarding process.
@muddlebee muddlebee marked this pull request as ready for review April 23, 2026 09:17
@muddlebee muddlebee changed the title (WIP) feat: add CLI integration base framework feat: add CLI integration base framework Apr 23, 2026
@muddlebee muddlebee marked this pull request as draft April 23, 2026 09:38
- Introduced a new method to identify candidate binary names for Codex, improving compatibility across platforms.
- Refactored fallback path logic to include environment variables and npm prefix directories, ensuring more robust detection of the Codex binary.
- Updated tests to validate the new fallback mechanism and ensure correct binary detection behavior.
Comment thread tests/integrations/llm_cli/test_codex_adapter.py Fixed
- Satisfy CodeQL: avoid mixed import and import-from for the same module.

- Import CodexAdapter, _fallback_codex_paths, _npm_prefix_bin_dirs from one from-block; use pathlib.Path for home paths.

Made-with: Cursor
- Match main: do not version the uv lockfile.

- Remove uv.lock from the index; file may remain locally.

Made-with: Cursor
- Fix CI ruff format --check on app/ and tests/.

Made-with: Cursor
- Updated the `argv` attribute in `CLIInvocation` to use a tuple instead of a list for better immutability.
- Adjusted the instantiation of `CLIInvocation` in `CodexAdapter` to reflect this change.
- Modified the `subprocess.run` call in `CLIBackedLLMClient` to convert `argv` back to a list for compatibility.
- Updated type hints in `llm_client.py` to use `Union` for forward references, avoiding import cycles.
Comment thread app/integrations/llm_cli/runner.py Fixed
Comment thread app/services/llm_client.py Fixed
Comment thread app/services/llm_client.py Fixed
@muddlebee muddlebee marked this pull request as ready for review April 23, 2026 12:21
Comment thread app/services/llm_client.py Outdated

_LLMClientType = LLMClient | OpenAILLMClient | BedrockLLMClient
# CLIBackedLLMClient is included but omitted from the union to avoid import cycles.
_LLMClientType = LLMClient | OpenAILLMClient | BedrockLLMClient | Any
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 | Any collapses the union to Any, defeating type safety

In Python's typing system, X | Any evaluates to Any — the entire union annotation is silently erased by mypy. The comment says "CLIBackedLLMClient is included" but it isn't really: the annotation carries no structural information about the CLI client.

The project enables warn_return_any in mypy, which means call-sites that receive this type will get untracked Any returns rather than proper type narrowing.

The idiomatic fix for a circular-import situation is TYPE_CHECKING:

from typing import TYPE_CHECKING, Union

if TYPE_CHECKING:
    from app.integrations.llm_cli.runner import CLIBackedLLMClient

_LLMClientType = Union[LLMClient, OpenAILLMClient, BedrockLLMClient, "CLIBackedLLMClient"]

This import is never executed at runtime (only during static analysis), so the circular import is avoided while keeping real type information.

Context Used: Code style and conventions (source)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sticking to "Any" type as add proper types like "CLIBackedLLMClient" is giving "Module-level cyclic import" lint errors as tried in this commit

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If any suggestions, feel free to push commits into this branch :) glad for any help or suggestions

@muddlebee muddlebee changed the title feat: add CLI integration base framework feat: add CLI framework base and codex CLI integration Apr 23, 2026
@muddlebee
Copy link
Copy Markdown
Collaborator Author

muddlebee commented Apr 23, 2026

Steps to test locally

Negative flow

  • Try opensre onboarding without installing codex cli and without codex login
  • Try opensre onboarding with installing codex cli and without codex login

Positive flow

  • Install Codex CLI
  • Codex login

Comment thread app/integrations/llm_cli/runner.py Outdated

invocation = self._adapter.build(prompt=flat, model=self._model, workspace="")
merged_env = os.environ.copy()
if invocation.env:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every env var from the parent process — ANTHROPIC_API_KEY, OPENAI_API_KEY, database URLs, etc. — is handed to the Codex CLI subprocess. If the CLI logs env vars on error or spawns its own children, credentials leak.


def _probe(self) -> CLIProbe:
now = time.monotonic()
if self._cached_probe is not None and (now - self._probe_cached_at) < _PROBE_CACHE_TTL_SEC:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_cached_probe and _probe_cached_at are written without a lock. In a multi-threaded LangGraph pipeline where the same CLIBackedLLMClient instance is shared, two threads could simultaneously find the cache stale and both call detect(), with one overwriting the other mid-write. Add a threading.Lock acquired around the stale-check-and-set block.

) -> None:
"""Wraps any LLM client with `.invoke` (API or CLI subprocess) for Pydantic JSON parsing."""

def __init__(self, base: Any, model: type[BaseModel]) -> None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replacing the union with Any suppresses mypy errors on all callers, not just the new CLI-backed one. A Protocol with a single .invoke(...) method is the correct fix and would have caught this at the type level without widening.

Comment thread app/nodes/chat.py Outdated
def _resolve_models(provider: str) -> tuple[str, str]:
"""Resolve tool and reasoning model names for the active provider."""
if provider == "codex":
raise ValueError(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ValueError raised inside a LangGraph node will propagate as an unhandled exception unless the graph has a catch-all error handler. A user-facing message or a typed UnsupportedProviderError that the graph runner knows to catch and format would be safer.

Copy link
Copy Markdown
Collaborator

@yashksaini-coder yashksaini-coder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @muddlebee, really nice work on the architecture here — the Protocol-based adapter design, probe caching, and onboarding recovery loop are all solid. A few issues I caught that need fixing before this lands:

Comment thread app/integrations/llm_cli/text.py
Comment thread app/integrations/llm_cli/codex.py Outdated
Comment thread app/integrations/llm_cli/codex.py
Comment thread app/cli/wizard/config.py
Comment thread app/services/llm_client.py Fixed
Comment thread app/services/llm_client.py Fixed
Comment thread app/services/llm_client.py Fixed
Comment thread app/services/llm_client.py Fixed
Comment thread app/services/llm_client.py Fixed
… environment handling

- Reduced the default execution timeout in CodexAdapter from 900 seconds to 120 seconds for improved responsiveness.
- Introduced a new function to build a safe subprocess environment, ensuring only necessary environment variables are passed to subprocesses.
- Added thread safety to the probe caching mechanism in CLIBackedLLMClient to prevent race conditions.
- Updated tests to verify the new timeout and environment handling behavior.
@muddlebee
Copy link
Copy Markdown
Collaborator Author

@Devesh36 addressed your review in latest commit

- Reformat llm_cli runner probe cache conditional
- Wrap long assert in chat node test
- Normalize sync_release_version error message string

Made-with: Cursor
- Patch shutil.which so CI without codex on PATH passes

Made-with: Cursor
Copy link
Copy Markdown
Collaborator

@yashksaini-coder yashksaini-coder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good progress on addressing the review feedback — env var allowlist, thread-safe probe cache, Protocol-based typing, and the 900s → 120s timeout fix all look solid. Approving. The one thing still worth a follow-up PR is the LangChain message handling in text.py (non-dict messages stringify as garbage), but that can be a quick patch after merge. Nice work overall @muddlebee 🚀

@muddlebee
Copy link
Copy Markdown
Collaborator Author

@yashksaini-coder thank your for your review. anyway we are planning migration away from LangGraph, check #650

So adding the reference to this PR, to cater such cases. noted!

@Devesh36 Devesh36 merged commit 6449841 into Tracer-Cloud:main Apr 23, 2026
7 checks passed
muddlebee added a commit that referenced this pull request Apr 30, 2026
* fix(llm-cli): address post-review issues in CLI integration

- fix: set os.environ[env_key] after sync_env_values so in-process retry
  loop sees the user-provided binary path immediately (#781 follow-up)
- fix: validate user-supplied binary path (isfile + executable) before
  persisting to .env to prevent silently storing broken paths
- fix: bump npm_prefix_bin_dirs subprocess timeout from 0.3s to 2.0s to
  avoid false-empty cache on slow nvm/volta shim startup
- refactor: use None sentinels for resolve_cli_binary defaults so
  shutil.which and is_runnable_binary are looked up at call time, making
  the function patchable in tests without explicit overrides
- refactor: drop redundant shutil import and explicit which_resolver /
  runnable_check kwargs from CodexAdapter._resolve_binary
- refactor: consolidate four separate binary_resolver import blocks into one
- fix: _ver_tuple now uses re.findall to correctly parse versions with
  non-digit segments (e.g. "1.2a.3", "1.2.3-beta.4")
- feat: log CLI stderr at DEBUG level after successful parse so warnings
  from the CLI are not silently discarded
- test: update patch targets from codex.shutil.which to
  binary_resolver.shutil.which after resolution moved to shared module

* docs(llm-cli): document auth probe pattern and env allowlist in AGENTS.md

- Add three-state logged_in contract table (True/False/None) with wizard behaviour
- Document _classify_*_auth pattern and negative-phrases-first rule
- Warn about _SAFE_SUBPROCESS_ENV_PREFIXES coupling in runner.py for new CLIs
- Update provider checklist with auth probe and env forwarding steps

* fix(llm-cli): use is_runnable_binary for path validation on all platforms

Replace os.path.isfile + os.access(X_OK) with shared is_runnable_binary
from binary_resolver, which already handles Windows extension checks
(.cmd, .exe, .ps1, .bat). os.access(X_OK) returns False for valid
Windows executables that lack Unix-style execute bits.

* fix(llm-cli): diagnose broken symlinks in binary path resolution

- add diagnose_binary_path() to binary_resolver: distinguishes broken
  symlinks (with target path in message) from missing files and
  non-executable files, returning an actionable string or None
- resolve_cli_binary now logs a WARNING with the diagnostic when an
  explicit *_BIN env var is set but unusable, instead of silently
  falling through to PATH lookup
- wizard flow uses diagnose_binary_path so users see e.g. "'~/bin/codex'
  is a broken symlink (points to '/usr/local/bin/codex'). Remove or fix it."
  instead of the generic "not a valid executable" message
- tests: missing file, broken symlink, valid exe, non-executable,
  and resolver warning on broken symlink

* docs(llm-cli): add module docstring with path-state table to binary_resolver

- document resolve_cli_binary, diagnose_binary_path, and is_runnable_binary
  at the top of binary_resolver.py with path state -> message reference table
  and platform notes (Windows extension check, lru_cache, readlink fallback)
- move inline `import sys` and `import logging` to top-level in test file
- guard symlink-creation tests against Windows hosts without elevation:
  catch OSError/NotImplementedError and skip rather than fail, preserving
  full coverage on Linux/macOS CI and graceful no-op on restricted runners

* fix(tests): tighten chmod masks for CodeQL

- set executable test fixture permissions to 0700
- set non-executable test fixture permissions to 0600

* fix(llm-cli): align windows diagnostics and onboarding test

- add Windows executable extension validation in diagnose_binary_path
- expand binary_resolver docstring path-state table for Windows mismatch case
- harden onboarding path override test with real executable and env cleanup
- assert in-process CODEX_BIN propagation without leaking env across tests

* style(llm-cli): format binary_resolver for CI

- reformat Windows executable diagnostic branch to satisfy ruff format-check

* feat(llm-cli): add CLI registry and generic wizard summary

- add registry mapping LLM_PROVIDER to adapter factory and model env key
- wire _create_llm_client through registry instead of codex-only branch
- derive saved-summary credential line from adapter auth_hint
- drop unused prompt_delivery from LLMCLIAdapter; document prompt via build()
- update AGENTS.md wiring checklist; add registry and summary tests

* fix(llm-cli): lazy-load CLI registry to break import cycle

- defer get_cli_provider_registration import until _create_llm_client runs
- avoid loading llm_cli package __init__ (runner) during llm_client import
gitsofaryan pushed a commit to gitsofaryan/opensre that referenced this pull request May 3, 2026
…loud#1097)

* fix(llm-cli): address post-review issues in CLI integration

- fix: set os.environ[env_key] after sync_env_values so in-process retry
  loop sees the user-provided binary path immediately (Tracer-Cloud#781 follow-up)
- fix: validate user-supplied binary path (isfile + executable) before
  persisting to .env to prevent silently storing broken paths
- fix: bump npm_prefix_bin_dirs subprocess timeout from 0.3s to 2.0s to
  avoid false-empty cache on slow nvm/volta shim startup
- refactor: use None sentinels for resolve_cli_binary defaults so
  shutil.which and is_runnable_binary are looked up at call time, making
  the function patchable in tests without explicit overrides
- refactor: drop redundant shutil import and explicit which_resolver /
  runnable_check kwargs from CodexAdapter._resolve_binary
- refactor: consolidate four separate binary_resolver import blocks into one
- fix: _ver_tuple now uses re.findall to correctly parse versions with
  non-digit segments (e.g. "1.2a.3", "1.2.3-beta.4")
- feat: log CLI stderr at DEBUG level after successful parse so warnings
  from the CLI are not silently discarded
- test: update patch targets from codex.shutil.which to
  binary_resolver.shutil.which after resolution moved to shared module

* docs(llm-cli): document auth probe pattern and env allowlist in AGENTS.md

- Add three-state logged_in contract table (True/False/None) with wizard behaviour
- Document _classify_*_auth pattern and negative-phrases-first rule
- Warn about _SAFE_SUBPROCESS_ENV_PREFIXES coupling in runner.py for new CLIs
- Update provider checklist with auth probe and env forwarding steps

* fix(llm-cli): use is_runnable_binary for path validation on all platforms

Replace os.path.isfile + os.access(X_OK) with shared is_runnable_binary
from binary_resolver, which already handles Windows extension checks
(.cmd, .exe, .ps1, .bat). os.access(X_OK) returns False for valid
Windows executables that lack Unix-style execute bits.

* fix(llm-cli): diagnose broken symlinks in binary path resolution

- add diagnose_binary_path() to binary_resolver: distinguishes broken
  symlinks (with target path in message) from missing files and
  non-executable files, returning an actionable string or None
- resolve_cli_binary now logs a WARNING with the diagnostic when an
  explicit *_BIN env var is set but unusable, instead of silently
  falling through to PATH lookup
- wizard flow uses diagnose_binary_path so users see e.g. "'~/bin/codex'
  is a broken symlink (points to '/usr/local/bin/codex'). Remove or fix it."
  instead of the generic "not a valid executable" message
- tests: missing file, broken symlink, valid exe, non-executable,
  and resolver warning on broken symlink

* docs(llm-cli): add module docstring with path-state table to binary_resolver

- document resolve_cli_binary, diagnose_binary_path, and is_runnable_binary
  at the top of binary_resolver.py with path state -> message reference table
  and platform notes (Windows extension check, lru_cache, readlink fallback)
- move inline `import sys` and `import logging` to top-level in test file
- guard symlink-creation tests against Windows hosts without elevation:
  catch OSError/NotImplementedError and skip rather than fail, preserving
  full coverage on Linux/macOS CI and graceful no-op on restricted runners

* fix(tests): tighten chmod masks for CodeQL

- set executable test fixture permissions to 0700
- set non-executable test fixture permissions to 0600

* fix(llm-cli): align windows diagnostics and onboarding test

- add Windows executable extension validation in diagnose_binary_path
- expand binary_resolver docstring path-state table for Windows mismatch case
- harden onboarding path override test with real executable and env cleanup
- assert in-process CODEX_BIN propagation without leaking env across tests

* style(llm-cli): format binary_resolver for CI

- reformat Windows executable diagnostic branch to satisfy ruff format-check

* feat(llm-cli): add CLI registry and generic wizard summary

- add registry mapping LLM_PROVIDER to adapter factory and model env key
- wire _create_llm_client through registry instead of codex-only branch
- derive saved-summary credential line from adapter auth_hint
- drop unused prompt_delivery from LLMCLIAdapter; document prompt via build()
- update AGENTS.md wiring checklist; add registry and summary tests

* fix(llm-cli): lazy-load CLI registry to break import cycle

- defer get_cli_provider_registration import until _create_llm_client runs
- avoid loading llm_cli package __init__ (runner) during llm_client import
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] :Support CLI backends (Codex, Claude Code, Gemini, Cursor)

4 participants