Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/context_engine/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,19 @@ def init(ctx: click.Context, agent: str) -> None:
section = _editor_section(editor, project_dir)
click.echo(_dim(f" ~/{editor['config_path']} → [{section}]"))

# In auto mode, show which agents weren't detected so the user knows
# they can use --agent <name> to force configuration.
if agent == "auto":
# Only mention agents that can be forced via --agent <name>
configurable_keys = set()
for _agent_name, editor_keys in _INIT_AGENT_TO_EDITORS.items():
configurable_keys.update(editor_keys)
skipped = configurable_keys - editor_targets
if skipped:
agent_names = [a for a, keys in _INIT_AGENT_TO_EDITORS.items() if keys & skipped]
names = ", ".join(sorted(agent_names))
click.echo(_dim(f" Not detected: {names}. Use --agent <name> to configure manually."))

# Write instruction files for the selected editors. In `auto` mode, also
# pick up instruction files whose marker exists even if the editor itself
# wasn't detected (e.g. an `AGENTS.md` checked in without a `~/.codex/`).
Expand Down
21 changes: 20 additions & 1 deletion src/context_engine/editors.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,17 +217,36 @@ def _toml_quote(s: str) -> str:

def detect_editors(project_dir: Path) -> list[str]:
"""Return list of editor keys detected for this project. Markers are
looked up under each editor's scope root (project dir or home dir)."""
looked up under each editor's scope root (project dir or home dir).

For Codex, also checks for the VS Code extension directory
(``~/.vscode/extensions/openai.*``) since the extension doesn't
create ``~/.codex`` until the CLI is run separately.
"""
found = []
for key, editor in EDITORS.items():
root = _scope_root(editor, project_dir)
for marker in editor["detect"]:
if (root / marker).exists():
found.append(key)
break
else:
# Secondary detection for Codex: VS Code extension installed
if key == "codex" and _has_vscode_openai_extension():
found.append(key)
return found


def _has_vscode_openai_extension() -> bool:
"""Check if any OpenAI VS Code extension is installed (as a proxy for Codex)
by looking for extension directories matching ``openai.*`` under
``~/.vscode/extensions``. No subprocess needed, works cross-platform."""
ext_dir = Path.home() / ".vscode" / "extensions"
if not ext_dir.is_dir():
return False
return any(ext_dir.glob("openai.*"))


def _codex_toml_block(command: str, project_dir: str, *, section: str) -> str:
"""Generate one TOML mcp_servers block. Section is the full dotted key
rendered from the editor's section_template (e.g. `mcp_servers.cce-myapp-a3f2`).
Expand Down
16 changes: 16 additions & 0 deletions tests/test_editors_codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,22 @@ def test_no_codex_detection_when_home_codex_absent(fake_home, project_dir):
assert "codex" not in detect_editors(project_dir)


def test_detect_codex_via_vscode_extension(fake_home, project_dir):
"""Codex VS Code extension installed but ~/.codex doesn't exist yet.
Detection should still fire via the extension directory."""
ext_dir = fake_home / ".vscode" / "extensions" / "openai.openai-chatgpt-adhoc-1.0.0"
ext_dir.mkdir(parents=True)
# ~/.codex does NOT exist
assert not (fake_home / ".codex").exists()
detected = detect_editors(project_dir)
assert "codex" in detected


def test_no_codex_detection_without_any_signal(fake_home, project_dir):
"""Neither ~/.codex nor VS Code extension present — no detection."""
assert "codex" not in detect_editors(project_dir)


# ── Configure: writes to ~/.codex/config.toml ────────────────────────────────

def test_configure_writes_to_user_global_codex_config(fake_home, project_dir):
Expand Down
Loading