项目文件夹

文件
Ali Khokhar 26cc73e6ce Use installed metadata as the single package version source (#1051)
## Problem

FCC runtime surfaces reported stale, unrelated versions, and users could
not inspect the installed FCC version without starting the server or
scaffolding configuration.

## Changes

| Before | After |
| --- | --- |
| FastAPI/OpenAPI and the web-tools user agent duplicated stale release
literals. | Every FCC runtime surface reads installed distribution
metadata through one `core.version` owner. |
| FCC-owned commands had no side-effect-free version query. |
`fcc-server`, `free-claude-code`, and `fcc-init` print the installed
version whenever `--version` is present, before any configuration or
process work. |
| Wrapped Claude and Codex argument handling was adjacent to FCC command
behavior. | Claude and Codex launchers remain transparent and pass
`--version` to their wrapped clients unchanged. |
| A source-only checkout had no explicit fallback contract. | Missing
distribution metadata reports `0+unknown`, while malformed installed
metadata still fails visibly. |
| Version behavior lacked end-to-end contract coverage. | API, CLI,
metadata, user-agent, feature-inventory, and live command tests verify
one value and zero CLI side effects; the complete 2,077-test CI gate
passes. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes installed package metadata the single source for the FCC
version. The main changes are:

- Adds `core.version.package_version()` with a source-checkout fallback.
- Uses that version in FastAPI/OpenAPI metadata and web-tool User-Agent
headers.
- Adds side-effect-free `--version` handling for FCC-owned CLI
entrypoints.
- Keeps Claude and Codex launchers transparent to wrapped client
arguments.
- Updates tests, smoke coverage, docs, and package metadata to `3.5.0`.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

No files need attention.

<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**
- The version contract pytest run completed successfully with
EXIT\_CODE: 0, as captured in the version contract pytest log.
- The direct CLI version commands sequence completed with final
EXIT\_CODE: 0, as recorded in the CLI version commands log.

<a
href="https://app.greptile.com/trex/runs/14086115/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 |
|----------|----------|
| src/free_claude_code/core/version.py | Adds the canonical
installed-metadata version helper with an explicit missing-metadata
fallback. |
| src/free_claude_code/cli/entrypoints.py | Adds early `--version`
output for FCC-owned server and init commands before startup or config
work. |
| src/free_claude_code/api/app.py | Uses the centralized package version
for FastAPI and OpenAPI metadata. |
| src/free_claude_code/api/web_tools/constants.py | Uses the centralized
package version in the outbound web-tool User-Agent. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Use installed metadata as the
package
ve..."](https://github.com/alishahryar1/free-claude-code/commit/f240f9c363115e63f407d7ac8d5c35833f6b66c8)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43500448)</sub>

<!-- /greptile_comment -->
2026-07-11 03:45:06 -07:00

43 行
1.4 KiB
Python

import tomllib
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as distribution_version
from pathlib import Path
import pytest
import free_claude_code.core.version as version_module
def test_package_version_uses_installed_distribution_metadata() -> None:
assert version_module.package_version() == distribution_version("free-claude-code")
def test_package_version_has_explicit_uninstalled_source_fallback(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def missing(_distribution_name: str) -> str:
raise PackageNotFoundError("free-claude-code")
monkeypatch.setattr(version_module, "distribution_version", missing)
assert version_module.package_version() == "0+unknown"
def test_package_version_does_not_hide_invalid_installed_metadata(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def invalid(_distribution_name: str) -> str:
raise ValueError("invalid metadata")
monkeypatch.setattr(version_module, "distribution_version", invalid)
with pytest.raises(ValueError, match="invalid metadata"):
version_module.package_version()
def test_project_release_version_matches_installed_metadata() -> None:
repo_root = Path(__file__).resolve().parents[2]
pyproject = tomllib.loads((repo_root / "pyproject.toml").read_text("utf-8"))
assert pyproject["project"]["version"] == distribution_version("free-claude-code")