getcodexy 1.2.2__tar.gz → 1.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getcodexy
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: Version-pinned MCP runtime bootstrap tools for Codexy
5
5
  Author: Eunsoo Lee
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "getcodexy"
7
- version = "1.2.2"
7
+ version = "1.3.0"
8
8
  description = "Version-pinned MCP runtime bootstrap tools for Codexy"
9
9
  requires-python = ">=3.10"
10
10
  license = "MIT"
@@ -0,0 +1,149 @@
1
+ """Immutable, standalone runtime-release contract validation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import re
8
+ import tarfile
9
+ from dataclasses import dataclass
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from .identity import Compatibility, compatibility, digest, document, object, platforms, string
14
+
15
+
16
+ REPOSITORY = "https://github.com/eunsoogi/codexy"
17
+ RELEASE_SCHEMA = "codexy-runtime-release/v1"
18
+ CANDIDATE_SCHEMA = "codexy-runtime-candidate/v1"
19
+ _COMMIT = re.compile(r"[0-9a-f]{40}\Z")
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class Source:
24
+ repository: str
25
+ commit: str
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class Artifact:
30
+ tag: str
31
+ url: str
32
+ sha256: str
33
+ payload_manifest_sha256: str
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class RuntimeRelease:
38
+ state: str
39
+ source: Source
40
+ artifact: Artifact
41
+ compatibility: Compatibility
42
+ platforms: dict[str, dict[str, dict[str, str]]]
43
+
44
+ def advertises(self, *, platform: str) -> bool:
45
+ return platform in self.platforms
46
+
47
+ def supports(self, *, server: str, platform: str, bootstrap_api: int,
48
+ plugin_runtime_api: int, transport: str, mcp_protocol: str) -> bool:
49
+ return (
50
+ server in self.platforms.get(platform, {})
51
+ and self.compatibility == Compatibility(
52
+ bootstrap_api, plugin_runtime_api, transport, mcp_protocol
53
+ )
54
+ )
55
+
56
+ def cache_key(self, *, platform: str, server: str) -> str:
57
+ return "v3-" + hashlib.sha256(_encoded(self.identity(platform=platform, server=server))).hexdigest()
58
+
59
+ def identity(self, *, platform: str, server: str) -> dict[str, Any]:
60
+ binary = self.platforms.get(platform, {}).get(server)
61
+ if binary is None:
62
+ raise ValueError("runtime release does not advertise the selected binary")
63
+ return {"schema": RELEASE_SCHEMA, "state": self.state, "source": self.source.__dict__,
64
+ "artifact": self.artifact.__dict__, "compatibility": self.compatibility.__dict__,
65
+ "platform": platform, "server": server, "binarySha256": binary["sha256"]}
66
+
67
+ def marker(self, *, platform: str, server: str, binary_sha256: str) -> dict[str, Any]:
68
+ return {"schema": "codexy-runtime-marker/v1", "identity": self.identity(platform=platform, server=server),
69
+ "installedBinarySha256": binary_sha256}
70
+
71
+ def valid_marker(self, marker: Any, *, platform: str, server: str, binary: bytes) -> bool:
72
+ return marker == self.marker(platform=platform, server=server,
73
+ binary_sha256=hashlib.sha256(binary).hexdigest())
74
+
75
+ def verify_archive(self, archive: Path, *, platform: str) -> bool:
76
+ if self.state == "legacy-public":
77
+ return True
78
+ try:
79
+ with tarfile.open(archive, "r:gz") as package:
80
+ names = [member.name for member in package.getmembers()]
81
+ if len({name.casefold() for name in names}) != len(names):
82
+ raise ValueError("runtime archive has duplicate or casefold paths")
83
+ package.getmember("plugins/codexy/.codex-plugin/plugin.json")
84
+ candidate = document(package.extractfile("plugins/codexy/runtime-candidate.json").read())
85
+ if _canonical(candidate) != self.artifact.payload_manifest_sha256:
86
+ raise ValueError("runtime candidate digest does not match release")
87
+ _validate_candidate(candidate, self, package, platform)
88
+ except (AttributeError, KeyError, OSError, tarfile.TarError, TypeError, json.JSONDecodeError) as error:
89
+ raise ValueError(f"invalid runtime candidate: {error}") from error
90
+ return True
91
+
92
+
93
+ def _canonical(value: Any) -> str:
94
+ return hashlib.sha256(_encoded(value)).hexdigest()
95
+
96
+
97
+ def _encoded(value: Any) -> bytes:
98
+ return json.dumps(value, sort_keys=True, separators=(",", ":")).encode()
99
+
100
+
101
+ def load(plugin_root: Path) -> RuntimeRelease:
102
+ path = plugin_root / "runtime-release.json"
103
+ try:
104
+ value = document(path.read_text(encoding="utf-8"))
105
+ except (OSError, json.JSONDecodeError) as error:
106
+ raise ValueError(f"runtime release is missing or invalid: {error}") from error
107
+ value = object(value, "document")
108
+ if set(value) != {"schema", "state", "source", "artifact", "compatibility", "platforms"}:
109
+ raise ValueError("runtime release has unknown or missing fields")
110
+ if value.get("schema") != RELEASE_SCHEMA:
111
+ raise ValueError("runtime release schema must be codexy-runtime-release/v1")
112
+ state = value.get("state")
113
+ if state not in {"legacy-public", "candidate-proven"}:
114
+ raise ValueError("runtime release state must be legacy-public or candidate-proven")
115
+ source = object(value.get("source"), "source")
116
+ if set(source) != {"repository", "commit"}:
117
+ raise ValueError("runtime release source has unknown or missing fields")
118
+ commit = string(source.get("commit"), "source.commit")
119
+ if source.get("repository") != REPOSITORY or not _COMMIT.fullmatch(commit):
120
+ raise ValueError("runtime release source must use the canonical repository and lowercase commit")
121
+ artifact = object(value.get("artifact"), "artifact")
122
+ if set(artifact) != {"tag", "url", "sha256", "payloadManifestSha256"}:
123
+ raise ValueError("runtime release artifact has unknown or missing fields")
124
+ tag = string(artifact.get("tag"), "artifact.tag")
125
+ url = string(artifact.get("url"), "artifact.url")
126
+ if url != f"{REPOSITORY}/releases/download/{tag}/codexy-marketplace-plugin.tar.gz":
127
+ raise ValueError("runtime release artifact URL is not canonical")
128
+ return RuntimeRelease(state, Source(REPOSITORY, commit), Artifact(tag, url,
129
+ digest(artifact.get("sha256"), "artifact.sha256"),
130
+ digest(artifact.get("payloadManifestSha256"), "artifact.payloadManifestSha256")),
131
+ compatibility(value.get("compatibility")),
132
+ platforms(value.get("platforms"), require_path=state == "candidate-proven"))
133
+
134
+
135
+ def _validate_candidate(candidate: Any, release: RuntimeRelease, package: tarfile.TarFile, platform: str) -> None:
136
+ candidate = object(candidate, "candidate")
137
+ if release.state != "candidate-proven":
138
+ raise ValueError("legacy runtime release has no candidate payload")
139
+ if set(candidate) != {"schema", "source", "artifact", "compatibility", "platforms"} or candidate.get("schema") != CANDIDATE_SCHEMA or candidate.get("source") != {"repository": release.source.repository, "commit": release.source.commit}:
140
+ raise ValueError("runtime candidate identity does not match release")
141
+ if candidate.get("artifact") != {"tag": release.artifact.tag} or compatibility(candidate.get("compatibility")) != release.compatibility:
142
+ raise ValueError("runtime candidate metadata does not match release")
143
+ inventory = platforms(candidate.get("platforms"), require_path=True)
144
+ if inventory != release.platforms or platform not in inventory:
145
+ raise ValueError("runtime candidate inventory does not match release")
146
+ for binary in inventory[platform].values():
147
+ member = package.extractfile(f"plugins/codexy/{binary['path']}")
148
+ if member is None or hashlib.sha256(member.read()).hexdigest() != binary["sha256"]:
149
+ raise ValueError("runtime candidate binary digest does not match")
@@ -0,0 +1,89 @@
1
+ """Strict JSON and normalized runtime inventory primitives."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ from dataclasses import dataclass
8
+ from typing import Any
9
+
10
+
11
+ _DIGEST = re.compile(r"[0-9a-f]{64}\Z")
12
+ PLATFORMS = {"darwin-arm64", "linux-x86_64"}
13
+ SERVERS = {"lsp", "codegraph"}
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class Compatibility:
18
+ bootstrap_api: int
19
+ plugin_runtime_api: int
20
+ transport: str
21
+ mcp_protocol: str
22
+
23
+
24
+ def document(text: str) -> Any:
25
+ def pairs(items: list[tuple[str, Any]]) -> dict[str, Any]:
26
+ value: dict[str, Any] = {}
27
+ for key, item in items:
28
+ if key in value:
29
+ raise ValueError(f"runtime release has duplicate JSON key: {key}")
30
+ value[key] = item
31
+ return value
32
+ return json.loads(text, object_pairs_hook=pairs)
33
+
34
+
35
+ def object(value: Any, name: str) -> dict[str, Any]:
36
+ if not isinstance(value, dict):
37
+ raise ValueError(f"runtime release {name} must be an object")
38
+ return value
39
+
40
+
41
+ def string(value: Any, name: str) -> str:
42
+ if not isinstance(value, str) or not value:
43
+ raise ValueError(f"runtime release {name} must be a non-empty string")
44
+ return value
45
+
46
+
47
+ def digest(value: Any, name: str) -> str:
48
+ value = string(value, name)
49
+ if not _DIGEST.fullmatch(value):
50
+ raise ValueError(f"runtime release {name} must be a lowercase SHA-256")
51
+ return value
52
+
53
+
54
+ def compatibility(value: Any) -> Compatibility:
55
+ value = object(value, "compatibility")
56
+ if set(value) != {"bootstrapApi", "pluginRuntimeApi", "transport", "mcpProtocol"}:
57
+ raise ValueError("runtime release compatibility has unknown or missing fields")
58
+ if value.get("bootstrapApi") != 1 or value.get("pluginRuntimeApi") != 1:
59
+ raise ValueError("runtime release compatibility APIs must be 1")
60
+ if value.get("transport") != "stdio-newline-v1" or value.get("mcpProtocol") != "2024-11-05":
61
+ raise ValueError("runtime release compatibility transport or MCP protocol is unsupported")
62
+ return Compatibility(1, 1, "stdio-newline-v1", "2024-11-05")
63
+
64
+
65
+ def platforms(value: Any, *, require_path: bool) -> dict[str, dict[str, dict[str, str]]]:
66
+ value = object(value, "platforms")
67
+ if set(value) != PLATFORMS:
68
+ raise ValueError("runtime release has unknown or missing platform")
69
+ result: dict[str, dict[str, dict[str, str]]] = {}
70
+ for platform, inventory in value.items():
71
+ inventory = object(inventory, f"platforms.{platform}")
72
+ if set(inventory) != SERVERS:
73
+ raise ValueError("runtime release has unknown or missing server")
74
+ binaries: dict[str, dict[str, str]] = {}
75
+ for server, item in inventory.items():
76
+ item = object(item, "binary")
77
+ fields = {"path", "sha256"} if require_path else {"sha256"}
78
+ if set(item) != fields:
79
+ raise ValueError("runtime release binary has unknown or missing fields")
80
+ binary = {"sha256": digest(item.get("sha256"), "binary.sha256")}
81
+ if require_path:
82
+ path = string(item.get("path"), "binary.path")
83
+ expected = f"runtime/codexy-mcp-{server}-{platform}.bin"
84
+ if path != expected or path.casefold() != path:
85
+ raise ValueError("runtime release binary path is not canonical")
86
+ binary["path"] = path
87
+ binaries[server] = binary
88
+ result[platform] = binaries
89
+ return result
@@ -0,0 +1,140 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import re
5
+ import shutil
6
+ import stat
7
+ import subprocess
8
+ import tempfile
9
+ from pathlib import Path
10
+ from typing import NoReturn, Protocol
11
+
12
+ from .cache import releases_match
13
+ from .package import acquire_package, unpack_runtime
14
+
15
+
16
+ class InstallConfig(Protocol):
17
+ server: str
18
+ manifest: Path
19
+ runtime_name: str
20
+ package_path: str
21
+ package_url: str
22
+ artifacts_api: str
23
+ package_override: bool
24
+ package_sha256: str
25
+ git_repository: str
26
+ git_ref: str
27
+ source_identity: object
28
+
29
+
30
+ def executable(path: Path) -> bool:
31
+ try:
32
+ metadata = os.lstat(path)
33
+ except FileNotFoundError:
34
+ return False
35
+ reparse = getattr(stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
36
+ return (
37
+ stat.S_ISREG(metadata.st_mode)
38
+ and not stat.S_ISLNK(metadata.st_mode)
39
+ and not bool(getattr(metadata, "st_file_attributes", 0) & reparse)
40
+ and os.access(path, os.X_OK)
41
+ )
42
+
43
+
44
+ def _publish_executable(
45
+ source: Path, destination: Path, *, require_staged_executable: bool = True
46
+ ) -> None:
47
+ if require_staged_executable and not executable(source):
48
+ raise RuntimeError(f"staged runtime is not executable: {source}")
49
+ destination.parent.mkdir(parents=True, exist_ok=True)
50
+ temporary = destination.with_name(f".{destination.name}.{os.getpid()}.tmp")
51
+ try:
52
+ shutil.copyfile(source, temporary)
53
+ mode = (
54
+ stat.S_IMODE(source.stat().st_mode) & 0o777
55
+ if require_staged_executable
56
+ else 0o755
57
+ )
58
+ temporary.chmod(mode)
59
+ if not executable(temporary):
60
+ raise RuntimeError(f"copied runtime is not executable: {temporary}")
61
+ os.replace(temporary, destination)
62
+ finally:
63
+ temporary.unlink(missing_ok=True)
64
+
65
+
66
+ def execute(
67
+ path: Path | str, arguments: list[str], environment: dict[str, str] | None = None
68
+ ) -> NoReturn:
69
+ command = str(path)
70
+ runtime_environment = os.environ.copy()
71
+ runtime_environment.update(environment or {})
72
+ os.execvpe(command, [command, *arguments], runtime_environment)
73
+ raise AssertionError("exec returned unexpectedly")
74
+
75
+
76
+ def install_package(config: InstallConfig, install_root: Path, installed: Path) -> None:
77
+ install_root.mkdir(parents=True, exist_ok=True)
78
+ with tempfile.TemporaryDirectory(prefix="package-", dir=install_root) as temporary:
79
+ work = Path(temporary)
80
+ archive = acquire_package(
81
+ path=config.package_path,
82
+ url=config.package_url,
83
+ artifacts_api=config.artifacts_api,
84
+ expected_sha256=config.package_sha256,
85
+ work=work,
86
+ )
87
+ source_identity = getattr(config, "source_identity", None)
88
+ release_contract = getattr(config, "release_contract", None)
89
+ if source_identity is not None:
90
+ source_identity.verify_archive(archive, platform=config.platform)
91
+ elif release_contract is not None:
92
+ release_contract.verify_archive(archive, platform=config.platform)
93
+ packaged_runtime, package_manifest = unpack_runtime(
94
+ archive=archive, work=work, runtime_name=config.runtime_name
95
+ )
96
+ if not config.package_override and release_contract is None:
97
+ matches, message = releases_match(config.manifest, package_manifest)
98
+ if not matches:
99
+ raise RuntimeError(message)
100
+ _publish_executable(
101
+ packaged_runtime, installed, require_staged_executable=False
102
+ )
103
+ if not config.package_override:
104
+ shutil.copyfile(package_manifest, install_root / "plugin.json")
105
+
106
+
107
+ def install_git(config: InstallConfig, install_root: Path, installed: Path) -> None:
108
+ cargo = shutil.which("cargo")
109
+ if not cargo:
110
+ raise RuntimeError("cargo is unavailable for the configured Git runtime source")
111
+ if config.git_repository != "https://github.com/eunsoogi/codexy" or not re.fullmatch(r"[0-9a-f]{40}", config.git_ref):
112
+ raise RuntimeError("Git fallback requires the canonical repository and lowercase 40-hex commit")
113
+ install_root.mkdir(parents=True, exist_ok=True)
114
+ with tempfile.TemporaryDirectory(prefix="git-", dir=install_root) as temporary:
115
+ staged_root = Path(temporary) / "root"
116
+ staged_runtime = staged_root / "bin" / f"codexy-mcp-{config.server}"
117
+ command = [
118
+ cargo,
119
+ "install",
120
+ "--force",
121
+ "--locked",
122
+ "--git",
123
+ config.git_repository,
124
+ "--rev",
125
+ config.git_ref,
126
+ "--root",
127
+ str(staged_root),
128
+ "--bin",
129
+ f"codexy-mcp-{config.server}",
130
+ ]
131
+ environment = {key: value for key, value in os.environ.items() if key not in {"GH_TOKEN", "GITHUB_TOKEN"}}
132
+ completed = subprocess.run(command, check=False, env=environment)
133
+ if completed.returncode:
134
+ raise RuntimeError(f"cargo install exited with status {completed.returncode}")
135
+ try:
136
+ _publish_executable(staged_runtime, installed)
137
+ except RuntimeError as error:
138
+ raise RuntimeError(
139
+ f"cargo install exited with status {completed.returncode}: {error}"
140
+ ) from error
@@ -68,16 +68,17 @@ def _extract_tar(archive: Path, destination: Path) -> None:
68
68
  raise ValueError("runtime package contains too many members")
69
69
  if sum(member.size for member in members) > MAX_UNPACKED_BYTES:
70
70
  raise ValueError("runtime package exceeds the unpacked size limit")
71
- destinations: set[Path] = set()
71
+ destinations: set[str] = set()
72
72
  for member in members:
73
73
  if not (member.isdir() or member.isfile()):
74
74
  raise ValueError(f"runtime package contains unsafe link or device: {member.name}")
75
75
  member_path = (destination / member.name).resolve()
76
76
  if destination_resolved not in member_path.parents and member_path != destination_resolved:
77
77
  raise ValueError(f"runtime package contains unsafe path: {member.name}")
78
- if member_path in destinations:
78
+ identity = str(member_path).casefold()
79
+ if identity in destinations:
79
80
  raise ValueError(f"runtime package contains duplicate path: {member.name}")
80
- destinations.add(member_path)
81
+ destinations.add(identity)
81
82
  package.extractall(destination)
82
83
 
83
84
 
@@ -96,7 +97,7 @@ def _extract_zip(archive: Path, destination: Path) -> None:
96
97
  raise ValueError("artifact archive contains too many members")
97
98
  if sum(member.file_size for member in members) > MAX_UNPACKED_BYTES:
98
99
  raise ValueError("artifact archive exceeds the unpacked size limit")
99
- destinations: set[Path] = set()
100
+ destinations: set[str] = set()
100
101
  for member in members:
101
102
  member_path = (destination / member.filename).resolve()
102
103
  unix_mode = member.external_attr >> 16
@@ -104,9 +105,10 @@ def _extract_zip(archive: Path, destination: Path) -> None:
104
105
  raise ValueError(f"artifact archive contains unsafe link: {member.filename}")
105
106
  if destination_resolved not in member_path.parents and member_path != destination_resolved:
106
107
  raise ValueError(f"artifact archive contains unsafe path: {member.filename}")
107
- if member_path in destinations:
108
+ identity = str(member_path).casefold()
109
+ if identity in destinations:
108
110
  raise ValueError(f"artifact archive contains duplicate path: {member.filename}")
109
- destinations.add(member_path)
111
+ destinations.add(identity)
110
112
  zipped.extractall(destination)
111
113
 
112
114
 
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ from .updater import _absolute, _validate_real_path
7
+
8
+ OFFICIAL = "https://github.com/eunsoogi/codexy.git"
9
+ PLUGIN_REPOSITORY = "https://github.com/eunsoogi/codexy"
10
+
11
+
12
+ def named_marketplace(payload: object) -> bool:
13
+ return any(
14
+ isinstance(item, dict) and item.get("name") == "codexy"
15
+ for item in _items(payload, "marketplaces")
16
+ )
17
+
18
+
19
+ def official_marketplace(payload: object) -> Path:
20
+ named = [
21
+ item
22
+ for item in _items(payload, "marketplaces")
23
+ if isinstance(item, dict) and item.get("name") == "codexy"
24
+ ]
25
+ if len(named) != 1 or named[0].get("marketplaceSource") != {
26
+ "sourceType": "git",
27
+ "source": OFFICIAL,
28
+ }:
29
+ raise ValueError("expected exactly one official Codexy marketplace")
30
+ root_value = named[0].get("root")
31
+ if not isinstance(root_value, str):
32
+ raise ValueError("official Codexy marketplace root is missing")
33
+ if not Path(root_value).is_absolute():
34
+ raise ValueError("official Codexy marketplace root must be absolute")
35
+ root = _absolute(root_value)
36
+ _validate_real_path(root, require_exists=True)
37
+ return root
38
+
39
+
40
+ def preflight_install(payload: object, marketplace_root: Path) -> None:
41
+ marketplace_root = _absolute(marketplace_root)
42
+ _validate_real_path(marketplace_root, require_exists=True)
43
+ entries = _codexy_enabled(payload)
44
+ if len(entries) > 1:
45
+ raise ValueError("expected zero or one enabled official Codexy install")
46
+ if entries:
47
+ _require_official(entries[0])
48
+ _source_root(entries[0], marketplace_root)
49
+
50
+
51
+ def official_install(
52
+ payload: object,
53
+ marketplace_root: Path,
54
+ distribution_version: str,
55
+ ) -> tuple[Path, str]:
56
+ marketplace_root = _absolute(marketplace_root)
57
+ _validate_real_path(marketplace_root, require_exists=True)
58
+ entries = _codexy_enabled(payload)
59
+ if len(entries) != 1:
60
+ raise ValueError("expected exactly one enabled official Codexy install")
61
+ item = entries[0]
62
+ _require_official(item)
63
+ root = _source_root(item, marketplace_root)
64
+ version = item.get("version")
65
+ if not isinstance(version, str):
66
+ raise ValueError("official Codexy install has invalid metadata")
67
+ if version != distribution_version:
68
+ raise ValueError("Codexy plugin version must match the getcodexy distribution")
69
+
70
+ manifest = root / ".codex-plugin" / "plugin.json"
71
+ _validate_real_path(manifest, require_exists=True)
72
+ data = json.loads(manifest.read_text(encoding="utf-8"))
73
+ if not isinstance(data, dict) or (
74
+ data.get("name"),
75
+ data.get("repository"),
76
+ data.get("version"),
77
+ ) != ("codexy", PLUGIN_REPOSITORY, version):
78
+ raise ValueError("official Codexy install identity does not match its manifest")
79
+ return root, version
80
+
81
+
82
+ def _items(payload: object, key: str) -> list[object]:
83
+ if not isinstance(payload, dict):
84
+ return []
85
+ value = payload.get(key)
86
+ return value if isinstance(value, list) else []
87
+
88
+
89
+ def _codexy_enabled(payload: object) -> list[dict[str, object]]:
90
+ return [
91
+ item
92
+ for item in _items(payload, "installed")
93
+ if isinstance(item, dict)
94
+ and item.get("enabled") is True
95
+ and (
96
+ item.get("pluginId") == "codexy@codexy"
97
+ or item.get("name") == "codexy"
98
+ or item.get("marketplaceName") == "codexy"
99
+ )
100
+ ]
101
+
102
+
103
+ def _require_official(item: dict[str, object]) -> None:
104
+ source = item.get("source")
105
+ if not (
106
+ item.get("pluginId") == "codexy@codexy"
107
+ and item.get("name") == "codexy"
108
+ and item.get("marketplaceName") == "codexy"
109
+ and item.get("installed") is True
110
+ and item.get("enabled") is True
111
+ and isinstance(source, dict)
112
+ and source.get("source") == "local"
113
+ and item.get("marketplaceSource")
114
+ == {"sourceType": "git", "source": OFFICIAL}
115
+ ):
116
+ raise ValueError("expected zero or one enabled official Codexy install")
117
+
118
+
119
+ def _source_root(item: dict[str, object], marketplace_root: Path) -> Path:
120
+ source = item.get("source")
121
+ path_value = source.get("path") if isinstance(source, dict) else None
122
+ if not isinstance(path_value, str):
123
+ raise ValueError("official Codexy install has invalid metadata")
124
+ if not Path(path_value).is_absolute():
125
+ raise ValueError("official Codexy install path must be absolute")
126
+ root = _absolute(path_value)
127
+ expected = marketplace_root / "plugins" / "codexy"
128
+ if root != expected:
129
+ raise ValueError("official Codexy install must be inside its marketplace root")
130
+ _validate_real_path(root, require_exists=True)
131
+ return root