alishahryar1--free-claude-code
5305bd7e08
## Problem
FCC still publishes `fcc-init` and the `free-claude-code` server alias
from an obsolete installation flow. Configuration creation now belongs
to the Admin UI, while `fcc-server` owns startup and legacy migration.
## Changes
| Before | After |
| --- | --- |
| The package installs six console commands. | The package installs only
`fcc-server`, `fcc-claude`, `fcc-codex`, and `fcc-pi`. |
| `fcc-init` duplicates configuration creation outside the Admin UI. |
The Admin UI exclusively creates managed configuration, and server
startup retains legacy migration. |
| Smoke contracts and architecture describe the retired commands. |
Smoke contracts and architecture describe the supported command surface.
|
| Installer safety lists contain unexplained retired names. | Installer
safety lists document why retired names remain detectable during updates
and uninstall. |
| The package version is `4.11.4`. | The package version is `4.11.5`. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR retires the obsolete initialization command and server alias.
The main changes are:
- Removes `fcc-init` and `free-claude-code` from package scripts.
- Moves fresh configuration creation exclusively to the Admin UI.
- Keeps legacy environment migration in `fcc-server` startup.
- Updates smoke coverage, installer comments, documentation, and package
metadata.
</details>
<h3>Confidence Score: 4/5</h3>
The CLI removal needs a compatible release version or temporary aliases
before merging.
Existing automation can lose `fcc-init` and `free-claude-code` after a
patch upgrade. Fresh installs can still start the server and create
configuration through the Admin UI.
pyproject.toml and uv.lock; legacy configuration migration remains
before settings loading.
<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>
**What T-Rex did**
- I reproduced the patch upgrade path by installing base revision
d37b34b02f in an isolated Python 3.14
environment and verified that fcc-init --version and free-claude-code
--version reported 4.11.4 with exit code 0. After upgrading to head
revision 9a65f654f5e06c0ca96a31d3ad03db8c63d8dec7, the installed version
changed to 4.11.5 and both entrypoints disappeared, with subsequent
invocations yielding command-not-found errors (exit code 127).
- Local smoke tests and server migrations completed successfully: the
CLI local smoke test exited with code 0, the installed-entrypoints
checks passed, and the server migrated to a healthy state with the
health endpoint responding.
<a
href="https://app.greptile.com/trex/runs/15196662/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>
<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>
<details open><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| pyproject.toml | Removes two public console commands while applying a
patch version bump. |
| src/free_claude_code/cli/commands.py | Removes template-based
initialization while preserving startup migration. |
| src/free_claude_code/cli/entrypoints.py | Removes the retired
initialization entrypoint and retains server version handling. |
| smoke/lib/child_process.py | Removes the init helper and renames the
server helper consistently. |
| scripts/install.sh | Keeps retired names in process detection for safe
upgrades. |
| scripts/uninstall.sh | Keeps retired names in removal checks for older
installations. |
| uv.lock | Tracks the patch version that must change if the command
removal remains breaking. |
</details>
<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22remove-obsolete-cli-commands%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22remove-obsolete-cli-commands%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apyproject.toml%3A7%0A**Breaking%20Commands%20Ship%20as%20Patch**%0A%0AUpgrading%20from%204.11.4%20removes%20the%20published%20%60fcc-init%60%20and%20%60free-claude-code%60%20commands%2C%20so%20existing%20scripts%20fail%20with%20%E2%80%9Ccommand%20not%20found.%E2%80%9D%20The%20repository%20policy%20classifies%20incompatible%20CLI%20removals%20as%20major%20changes%3B%20keep%20compatibility%20aliases%20for%204.x%20or%20publish%20this%20removal%20as%205.0.0.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1220&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>
<sub>Reviews (1): Last reviewed commit: ["Remove obsolete CLI entry
points"](https://github.com/alishahryar1/free-claude-code/commit/9a65f654f5e06c0ca96a31d3ad03db8c63d8dec7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=45848525)</sub>
> Greptile also left **1 inline comment** on this PR.
<!-- /greptile_comment -->
562 行
20 KiB
Python
562 行
20 KiB
Python
"""Public feature inventory for contract, prerequisite, and product smoke tests.
|
|
|
|
The inventory is intentionally explicit. README-advertised behavior and exposed
|
|
public surface area must have deterministic pytest contract coverage plus a
|
|
product E2E scenario when that behavior is a user-facing product path. Liveness
|
|
and route probes live in ``smoke/prereq`` and do not count as product coverage.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Literal
|
|
|
|
FeatureSource = Literal["readme", "public_surface"]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class FeatureCoverage:
|
|
feature_id: str
|
|
title: str
|
|
source: FeatureSource
|
|
pytest_contract_tests: tuple[str, ...]
|
|
live_prereq_tests: tuple[str, ...]
|
|
product_e2e_tests: tuple[str, ...]
|
|
smoke_targets: tuple[str, ...]
|
|
required_env: tuple[str, ...]
|
|
skip_policy: str
|
|
product_e2e_reason: str = ""
|
|
|
|
@property
|
|
def has_pytest_coverage(self) -> bool:
|
|
return bool(self.pytest_contract_tests)
|
|
|
|
|
|
README_FEATURES: tuple[str, ...] = (
|
|
"zero_cost_provider_access",
|
|
"drop_in_claude_code_replacement",
|
|
"drop_in_codex_replacement",
|
|
"pi_cli_integration",
|
|
"provider_matrix",
|
|
"per_model_mapping",
|
|
"thinking_token_support",
|
|
"heuristic_tool_parser",
|
|
"discord_telegram_bot",
|
|
"optional_authentication",
|
|
"vscode_extension",
|
|
"intellij_extension",
|
|
"voice_notes",
|
|
)
|
|
|
|
|
|
FEATURE_INVENTORY: tuple[FeatureCoverage, ...] = (
|
|
FeatureCoverage(
|
|
"zero_cost_provider_access",
|
|
"Configured provider accepts real conversation turns",
|
|
"readme",
|
|
("tests/api/test_dependencies.py", "tests/providers/"),
|
|
("test_configured_provider_models_stream_successfully",),
|
|
("test_provider_text_multiturn_e2e",),
|
|
("providers",),
|
|
("configured provider credentials or local provider endpoint",),
|
|
"missing providers are missing_env unless FCC_ALLOW_NO_PROVIDER_SMOKE=1",
|
|
),
|
|
FeatureCoverage(
|
|
"drop_in_claude_code_replacement",
|
|
"Claude-compatible API, CLI, and editor protocol flows work",
|
|
"readme",
|
|
("tests/api/test_api.py", "tests/cli/test_cli.py"),
|
|
("test_probe_and_models_routes", "test_claude_cli_prompt_when_available"),
|
|
(
|
|
"test_api_basic_conversation_e2e",
|
|
"test_claude_cli_adaptive_thinking_e2e",
|
|
"test_claude_cli_provider_error_e2e",
|
|
"test_nvidia_nim_cli_matrix_e2e",
|
|
"test_openrouter_free_cli_matrix_e2e",
|
|
"test_vscode_protocol_e2e",
|
|
"test_jetbrains_protocol_e2e",
|
|
),
|
|
("api", "cli", "clients", "nvidia_nim_cli", "openrouter_free_cli"),
|
|
(
|
|
"configured provider",
|
|
"FCC_SMOKE_CLAUDE_BIN for real Claude CLI",
|
|
"NVIDIA_NIM_API_KEY",
|
|
"OPENROUTER_API_KEY",
|
|
),
|
|
"skip real CLI when binary is absent; configured providers must pass",
|
|
),
|
|
FeatureCoverage(
|
|
"drop_in_codex_replacement",
|
|
"OpenAI Responses API and Codex CLI adapter route through the proxy",
|
|
"readme",
|
|
(
|
|
"tests/api/test_openai_responses.py",
|
|
"tests/cli/test_entrypoints.py",
|
|
"tests/cli/test_codex_model_catalog.py",
|
|
"tests/core/openai_responses/test_sse.py",
|
|
),
|
|
("test_probe_and_models_routes",),
|
|
("test_provider_codex_responses_text_e2e",),
|
|
("api", "providers"),
|
|
("configured provider credentials or local provider endpoint",),
|
|
"missing providers are missing_env unless FCC_ALLOW_NO_PROVIDER_SMOKE=1",
|
|
),
|
|
FeatureCoverage(
|
|
"pi_cli_integration",
|
|
"Pi discovers FCC models and sends Anthropic Messages through the proxy",
|
|
"readme",
|
|
("tests/cli/test_entrypoints.py",),
|
|
("test_probe_and_models_routes",),
|
|
("test_pi_cli_prompt_e2e",),
|
|
("clients",),
|
|
("Pi CLI", "configured provider credentials or local provider endpoint"),
|
|
"skip only when Pi is absent; configured providers must pass",
|
|
),
|
|
FeatureCoverage(
|
|
"provider_matrix",
|
|
"Every configured provider prefix can satisfy conversation scenarios",
|
|
"readme",
|
|
("tests/api/test_dependencies.py", "tests/providers/"),
|
|
("test_configured_provider_models_stream_successfully",),
|
|
("test_provider_matrix_presence_e2e", "test_provider_text_multiturn_e2e"),
|
|
("providers",),
|
|
("configured provider credentials/endpoints", "optional FCC_SMOKE_MODEL_*"),
|
|
"selected providers missing credentials are failing missing_env",
|
|
),
|
|
FeatureCoverage(
|
|
"per_model_mapping",
|
|
"Fable, Opus, Sonnet, Haiku, and fallback mappings route explicitly",
|
|
"readme",
|
|
("tests/application/test_routing.py", "tests/config/test_config.py"),
|
|
("test_model_mapping_configuration_is_consistent",),
|
|
("test_model_mapping_matrix_e2e",),
|
|
("providers",),
|
|
("MODEL", "MODEL_FABLE", "MODEL_OPUS", "MODEL_SONNET", "MODEL_HAIKU"),
|
|
"skip only when live smoke is intentionally allowed to run with no provider",
|
|
),
|
|
FeatureCoverage(
|
|
"mixed_provider_mapping",
|
|
"Model-specific overrides can route to different providers",
|
|
"public_surface",
|
|
("tests/application/test_routing.py", "tests/config/test_config.py"),
|
|
("test_mixed_provider_model_mapping_when_configured",),
|
|
("test_model_mapping_matrix_e2e",),
|
|
("providers",),
|
|
("MODEL", "MODEL_FABLE", "MODEL_OPUS", "MODEL_SONNET", "MODEL_HAIKU"),
|
|
"configured mixed-provider mappings must resolve consistently",
|
|
),
|
|
FeatureCoverage(
|
|
"thinking_token_support",
|
|
"Thinking history, adaptive thinking, and redacted blocks are accepted",
|
|
"readme",
|
|
(
|
|
"tests/contracts/test_stream_contracts.py",
|
|
"tests/providers/test_open_router.py",
|
|
),
|
|
(),
|
|
(
|
|
"test_provider_adaptive_thinking_history_e2e",
|
|
"test_provider_reasoning_tool_continuation_e2e",
|
|
"test_gemini_thought_signature_tool_continuation_e2e",
|
|
"test_claude_cli_adaptive_thinking_e2e",
|
|
"test_route_reasoning_config_e2e",
|
|
),
|
|
("providers", "cli", "config"),
|
|
("configured provider",),
|
|
"configured providers must not reject adaptive thinking payloads",
|
|
),
|
|
FeatureCoverage(
|
|
"heuristic_tool_parser",
|
|
"Tool use and tool result continuation survive provider/client paths",
|
|
"readme",
|
|
("tests/providers/test_parsers.py", "tests/contracts/test_stream_contracts.py"),
|
|
("test_live_tool_use_when_configured_model_supports_tools",),
|
|
(
|
|
"test_provider_interleaved_thinking_tool_e2e",
|
|
"test_provider_tool_result_continuation_e2e",
|
|
"test_gemini_thought_signature_tool_continuation_e2e",
|
|
"test_provider_reasoning_tool_continuation_e2e",
|
|
),
|
|
("tools", "providers"),
|
|
("configured tool-capable provider",),
|
|
"tool-capable configured providers must emit or continue tool results",
|
|
),
|
|
FeatureCoverage(
|
|
"request_optimization",
|
|
"Local request optimizations return product responses without providers",
|
|
"public_surface",
|
|
(
|
|
"tests/api/test_optimization_handlers.py",
|
|
"tests/api/test_routes_optimizations.py",
|
|
),
|
|
("test_optimization_fast_paths_do_not_need_provider",),
|
|
("test_api_request_optimizations_e2e",),
|
|
("api",),
|
|
(),
|
|
"always runnable once the local smoke server starts",
|
|
),
|
|
FeatureCoverage(
|
|
"smart_rate_limiting",
|
|
"Transient retries and disconnect cleanup preserve follow-up requests",
|
|
"public_surface",
|
|
(
|
|
"tests/providers/test_provider_admission.py",
|
|
"tests/providers/test_nvidia_nim_degraded_retry.py",
|
|
),
|
|
("test_client_disconnect_mid_stream_does_not_crash_server",),
|
|
("test_provider_disconnect_e2e",),
|
|
("rate_limit", "providers"),
|
|
("configured provider",),
|
|
"upstream disconnects are skips only when classified upstream_unavailable",
|
|
),
|
|
FeatureCoverage(
|
|
"provider_hot_swap",
|
|
"Provider config changes preserve active streams while new requests switch",
|
|
"public_surface",
|
|
(
|
|
"tests/runtime/test_provider_manager.py",
|
|
"tests/api/test_response_streams.py",
|
|
"tests/api/test_admin.py",
|
|
),
|
|
(),
|
|
("test_provider_hot_swap_preserves_inflight_stream_e2e",),
|
|
("api",),
|
|
(),
|
|
"credential-free local fake upstreams make the scenario always runnable",
|
|
),
|
|
FeatureCoverage(
|
|
"discord_telegram_bot",
|
|
"Discord and Telegram product flows render progress and transcripts",
|
|
"readme",
|
|
(
|
|
"tests/messaging/test_discord_platform.py",
|
|
"tests/messaging/test_telegram.py",
|
|
"tests/messaging/test_limiter.py",
|
|
"tests/messaging/test_platform_outbox.py",
|
|
"tests/runtime/test_application_runtime.py",
|
|
),
|
|
(
|
|
"test_telegram_bot_api_permissions",
|
|
"test_discord_bot_api_permissions",
|
|
),
|
|
(
|
|
"test_messaging_fake_full_flow_e2e",
|
|
"test_telegram_live_permissions_e2e",
|
|
"test_discord_live_permissions_e2e",
|
|
),
|
|
("messaging", "telegram", "discord"),
|
|
("bot tokens/channels only for side-effectful live platform tests",),
|
|
"fake platform is required; real platforms skip without explicit env",
|
|
),
|
|
FeatureCoverage(
|
|
"subagent_control",
|
|
"Task-like tool output is rendered and controlled as foreground work",
|
|
"public_surface",
|
|
("tests/providers/test_subagent_interception.py",),
|
|
(),
|
|
("test_messaging_subagent_control_e2e",),
|
|
("messaging",),
|
|
(),
|
|
"fake platform exercises tool transcript behavior without spawning agents",
|
|
),
|
|
FeatureCoverage(
|
|
"extensible_provider_platform_abcs",
|
|
"Provider and platform factories expose built-in extension points",
|
|
"public_surface",
|
|
(
|
|
"tests/contracts/test_feature_manifest.py",
|
|
"tests/providers/test_provider_runtime.py",
|
|
),
|
|
(),
|
|
("test_provider_runtime_config_e2e", "test_platform_factory_e2e"),
|
|
("extensibility",),
|
|
(),
|
|
"always runnable with isolated settings",
|
|
),
|
|
FeatureCoverage(
|
|
"optional_authentication",
|
|
"Canonical bearer proxy authentication is enforced",
|
|
"readme",
|
|
("tests/api/test_auth.py",),
|
|
("test_bearer_auth_is_the_only_supported_header_shape",),
|
|
("test_api_bearer_auth_contract_e2e",),
|
|
("auth",),
|
|
("ANTHROPIC_AUTH_TOKEN",),
|
|
"product test starts an isolated token-protected server",
|
|
),
|
|
FeatureCoverage(
|
|
"vscode_extension",
|
|
"VS Code protocol-shaped requests work against the proxy",
|
|
"readme",
|
|
(
|
|
"tests/core/anthropic/test_models.py::test_messages_request_accepts_adaptive_thinking_type",
|
|
),
|
|
("test_vscode_and_jetbrains_shaped_requests",),
|
|
("test_vscode_protocol_e2e",),
|
|
("clients",),
|
|
("configured provider",),
|
|
"extension source is external; protocol payload is covered here",
|
|
),
|
|
FeatureCoverage(
|
|
"intellij_extension",
|
|
"JetBrains/ACP protocol-shaped requests work against the proxy",
|
|
"readme",
|
|
(
|
|
"tests/core/anthropic/test_models.py::test_messages_request_accepts_adaptive_thinking_type",
|
|
),
|
|
("test_vscode_and_jetbrains_shaped_requests",),
|
|
("test_jetbrains_protocol_e2e",),
|
|
("clients",),
|
|
("configured provider",),
|
|
"extension source is external; protocol payload is covered here",
|
|
),
|
|
FeatureCoverage(
|
|
"voice_notes",
|
|
"Voice note intake, cancellation, and transcription backends work",
|
|
"readme",
|
|
(
|
|
"tests/messaging/test_voice_handlers.py",
|
|
"tests/messaging/test_transcription.py",
|
|
),
|
|
("test_voice_transcription_backend_when_explicitly_enabled",),
|
|
(
|
|
"test_voice_platform_fake_e2e",
|
|
"test_voice_local_backend_e2e",
|
|
"test_voice_nim_backend_e2e",
|
|
),
|
|
("messaging", "voice"),
|
|
("VOICE_NOTE_ENABLED", "FCC_SMOKE_RUN_VOICE", "WHISPER_DEVICE"),
|
|
"fake cancellation is required; backend transcription is opt-in",
|
|
),
|
|
FeatureCoverage(
|
|
"anthropic_api_routes",
|
|
"Messages, count_tokens, errors, and stop use Anthropic-compatible shapes",
|
|
"public_surface",
|
|
("tests/api/test_api.py",),
|
|
("test_probe_and_models_routes", "test_stop_endpoint_reports_no_messaging"),
|
|
(
|
|
"test_api_basic_conversation_e2e",
|
|
"test_api_count_tokens_full_payload_e2e",
|
|
"test_api_error_shape_e2e",
|
|
"test_api_stop_e2e",
|
|
),
|
|
("api",),
|
|
("configured provider for streaming messages",),
|
|
"route pings are prereqs; product route behavior is covered by E2E cases",
|
|
),
|
|
FeatureCoverage(
|
|
"probe_routes",
|
|
"HEAD and OPTIONS compatibility probes are accepted",
|
|
"public_surface",
|
|
("tests/api/test_api.py::test_probe_endpoints_return_204_with_allow_headers",),
|
|
("test_probe_and_models_routes",),
|
|
(),
|
|
("api",),
|
|
(),
|
|
"always runnable once the local smoke server starts",
|
|
"probe routes are compatibility prerequisites, not product behavior",
|
|
),
|
|
FeatureCoverage(
|
|
"count_tokens_contract",
|
|
"Token counting accepts full Claude content payloads",
|
|
"public_surface",
|
|
("tests/api/test_request_utils.py",),
|
|
("test_count_tokens_accepts_thinking_tools_and_results",),
|
|
("test_api_count_tokens_full_payload_e2e",),
|
|
("api",),
|
|
(),
|
|
"always runnable once the local smoke server starts",
|
|
),
|
|
FeatureCoverage(
|
|
"provider_proxy_timeout_config",
|
|
"Provider proxies and HTTP timeout settings reach provider config",
|
|
"public_surface",
|
|
("tests/api/test_dependencies.py", "tests/providers/test_provider_runtime.py"),
|
|
(),
|
|
("test_proxy_timeout_config_e2e",),
|
|
("config",),
|
|
(),
|
|
"always runnable with isolated env files",
|
|
),
|
|
FeatureCoverage(
|
|
"lmstudio_endpoint",
|
|
"LM Studio Messages and local no-key operation work when running",
|
|
"public_surface",
|
|
("tests/providers/test_lmstudio.py",),
|
|
("test_lmstudio_models_endpoint_when_available",),
|
|
("test_lmstudio_messages_e2e",),
|
|
("lmstudio",),
|
|
("LM_STUDIO_BASE_URL with running LM Studio server",),
|
|
"skip when local upstream is unavailable",
|
|
),
|
|
FeatureCoverage(
|
|
"llamacpp_endpoint",
|
|
"llama.cpp OpenAI Chat and local no-key operation work when running",
|
|
"public_surface",
|
|
("tests/providers/test_llamacpp.py",),
|
|
("test_llamacpp_models_endpoint_when_available",),
|
|
("test_llamacpp_openai_chat_e2e",),
|
|
("llamacpp",),
|
|
("LLAMACPP_BASE_URL with running llama-server",),
|
|
"skip when local upstream is unavailable",
|
|
),
|
|
FeatureCoverage(
|
|
"ollama_endpoint",
|
|
"Ollama OpenAI Chat and local no-key operation work when running",
|
|
"public_surface",
|
|
("tests/providers/test_ollama.py",),
|
|
("test_ollama_models_endpoint_when_available",),
|
|
("test_ollama_openai_chat_e2e",),
|
|
("ollama",),
|
|
("OLLAMA_BASE_URL with running Ollama server",),
|
|
"skip when local upstream is unavailable",
|
|
),
|
|
FeatureCoverage(
|
|
"package_cli_entrypoints",
|
|
"Installed package scripts report version and start the server",
|
|
"public_surface",
|
|
("tests/cli/test_entrypoints.py", "tests/core/test_version.py"),
|
|
("test_fcc_server_entrypoint_starts_server",),
|
|
(
|
|
"test_entrypoint_server_e2e",
|
|
"test_entrypoint_version_e2e",
|
|
),
|
|
("cli",),
|
|
(),
|
|
"always runnable once uv project dependencies are available",
|
|
),
|
|
FeatureCoverage(
|
|
"claude_cli_drop_in",
|
|
"Claude CLI can send adaptive thinking and tool-shaped history",
|
|
"public_surface",
|
|
("tests/cli/test_cli.py",),
|
|
("test_claude_cli_prompt_when_available",),
|
|
(
|
|
"test_claude_cli_adaptive_thinking_e2e",
|
|
"test_claude_cli_multiturn_tool_protocol_e2e",
|
|
"test_nvidia_nim_cli_matrix_e2e",
|
|
"test_openrouter_free_cli_matrix_e2e",
|
|
),
|
|
("cli", "nvidia_nim_cli", "openrouter_free_cli"),
|
|
(
|
|
"FCC_SMOKE_CLAUDE_BIN",
|
|
"configured provider",
|
|
"NVIDIA_NIM_API_KEY",
|
|
"OPENROUTER_API_KEY",
|
|
),
|
|
"skip only when Claude CLI binary is absent",
|
|
),
|
|
FeatureCoverage(
|
|
"messaging_commands",
|
|
"Messaging commands clear exact reply subtrees or whole managed chats",
|
|
"public_surface",
|
|
(
|
|
"tests/messaging/test_handler.py",
|
|
"tests/messaging/test_handler_integration.py",
|
|
"tests/messaging/test_tree_ownership_concurrency.py",
|
|
),
|
|
(),
|
|
(
|
|
"test_messaging_commands_stop_clear_stats_e2e",
|
|
"test_reply_clear_uses_literal_platform_subtree_e2e",
|
|
"test_messaging_startup_notice_is_clearable_e2e",
|
|
"test_messaging_active_stop_uses_status_only_e2e",
|
|
"test_messaging_queued_scoped_cancel_e2e",
|
|
),
|
|
("messaging",),
|
|
(),
|
|
"required fake-platform product flow",
|
|
),
|
|
FeatureCoverage(
|
|
"tree_threading",
|
|
"Reply-based branches fork sessions and stay scoped",
|
|
"public_surface",
|
|
(
|
|
"tests/messaging/test_tree_queue.py",
|
|
"tests/messaging/test_tree_concurrency.py",
|
|
"tests/messaging/test_message_tree_transitions.py",
|
|
"tests/messaging/test_tree_ownership_concurrency.py",
|
|
),
|
|
(),
|
|
(
|
|
"test_tree_threading_e2e",
|
|
"test_messaging_queued_scoped_cancel_e2e",
|
|
"test_same_message_ids_are_isolated_by_chat_e2e",
|
|
),
|
|
("messaging",),
|
|
(),
|
|
"required fake-platform product flow",
|
|
),
|
|
FeatureCoverage(
|
|
"restart_restore",
|
|
"Persisted tree state restores reply routing after restart",
|
|
"public_surface",
|
|
("tests/messaging/test_restart_reply_restore.py",),
|
|
(),
|
|
("test_restart_restore_and_session_persistence_e2e",),
|
|
("messaging",),
|
|
(),
|
|
"required fake-platform persistence flow",
|
|
),
|
|
FeatureCoverage(
|
|
"session_persistence",
|
|
"Session JSON preserves scoped trees and message logs",
|
|
"public_surface",
|
|
("tests/messaging/test_session_store_edge_cases.py",),
|
|
(),
|
|
("test_restart_restore_and_session_persistence_e2e",),
|
|
("messaging",),
|
|
(),
|
|
"required fake-platform persistence flow",
|
|
),
|
|
FeatureCoverage(
|
|
"config_env_precedence",
|
|
"FCC_ENV_FILE, dotenv, and process env precedence are deterministic",
|
|
"public_surface",
|
|
("tests/config/test_config.py",),
|
|
(),
|
|
("test_env_precedence_e2e",),
|
|
("config",),
|
|
(),
|
|
"always runnable with isolated env files",
|
|
),
|
|
FeatureCoverage(
|
|
"removed_env_migration",
|
|
"Removed thinking env vars are ignored without changing defaults",
|
|
"public_surface",
|
|
("tests/config/test_config.py",),
|
|
(),
|
|
("test_removed_env_migration_e2e",),
|
|
("config",),
|
|
(),
|
|
"always runnable with isolated env files",
|
|
),
|
|
FeatureCoverage(
|
|
"streaming_error_mapping",
|
|
"Canonical execution failures map to protocol-correct terminal output",
|
|
"public_surface",
|
|
(
|
|
"tests/api/test_execution_failure_contract.py",
|
|
"tests/core/test_failure_protocol_mapping.py",
|
|
"tests/providers/test_execution_failure_boundary.py",
|
|
"tests/providers/test_failure_policy.py",
|
|
),
|
|
(),
|
|
(
|
|
"test_api_error_shape_e2e",
|
|
"test_provider_error_e2e",
|
|
"test_claude_cli_provider_error_e2e",
|
|
),
|
|
("api", "providers", "cli"),
|
|
("configured provider for provider error scenario",),
|
|
"invalid request path is required; provider error path requires provider",
|
|
),
|
|
)
|
|
|
|
|
|
def feature_ids(*, source: FeatureSource | None = None) -> set[str]:
|
|
"""Return feature IDs covered by the inventory."""
|
|
return {
|
|
feature.feature_id
|
|
for feature in FEATURE_INVENTORY
|
|
if source is None or feature.source == source
|
|
}
|