Rename Castle -> Wild PC across the repo

Repo-side rename only (Phases 1-3 of the migration plan); the live box
(~/.castle, systemd units, /data/castle, domains) is a separate cutover.

- Slug `castle` -> `wildpc`: CLI command, module names (wildpc_core/cli/api),
  dist names, entry point `wildpc = wildpc_cli.main:main`.
- Identifiers: CastleConfig/NATSClient/DirError/MDNS -> Wildpc*.
- Env/constants: CASTLE_* -> WILDPC_*; ~/.castle -> ~/.wildpc, castle.yaml ->
  wildpc.yaml, /data/castle -> /data/wildpc.
- Systemd UNIT_PREFIX castle- -> wildpc-; own programs castle-api/gateway/etc.
- Display prose "Castle" -> "Wild PC" in docs, agent-guide files, README, frontend.
- Package dirs and bootstrap yaml renamed via git mv; lockfiles regenerated;
  redundant nested uv.lock files dropped (workspace root lock is authoritative).

Tests: core 273, cli 47, wildpc-api 120 all pass. Frontend type-checks + builds.
Fixed a stale test fixture (secret_env_path kind arg) broken pre-rename.
This commit is contained in:
2026-07-18 22:55:08 -07:00
parent 25d7a522cc
commit 05b28cb584
190 changed files with 2428 additions and 3337 deletions

View File

@@ -4,12 +4,12 @@ from __future__ import annotations
import pytest
from castle_core.config import CastleConfig, GatewayConfig
from castle_core.generators.caddyfile import (
from wildpc_core.config import WildpcConfig, GatewayConfig
from wildpc_core.generators.caddyfile import (
compute_routes,
generate_caddyfile_from_registry,
)
from castle_core.manifest import (
from wildpc_core.manifest import (
CaddyDeployment,
DeploymentSpec,
ExposeSpec,
@@ -20,14 +20,14 @@ from castle_core.manifest import (
RunPython,
SystemdDeployment,
)
from castle_core.registry import Deployment, NodeConfig, NodeRegistry
from wildpc_core.registry import Deployment, NodeConfig, NodeRegistry
@pytest.fixture(autouse=True)
def _isolate_config(monkeypatch: pytest.MonkeyPatch) -> None:
"""Isolate the generator from the real ~/.castle config so static-frontend
"""Isolate the generator from the real ~/.wildpc config so static-frontend
routes don't leak into these registry-focused tests."""
import castle_core.config as config_mod
import wildpc_core.config as config_mod
def _no_config(*args: object, **kwargs: object) -> object:
raise FileNotFoundError("isolated in tests")
@@ -101,7 +101,7 @@ class TestAcmeMode:
def test_port_9000_redirects_to_dashboard(self) -> None:
cf = generate_caddyfile_from_registry(_acme({"api": _dep(9020, expose=True, name="api")}))
assert ":9000 {" in cf
assert "redir https://castle.example.com{uri}" in cf
assert "redir https://wildpc.example.com{uri}" in cf
def test_no_path_routes(self) -> None:
cf = generate_caddyfile_from_registry(_acme({"api": _dep(9020, expose=True, name="api")}))
@@ -114,7 +114,7 @@ class TestAcmeMode:
assert "pg.example.com" not in cf
def test_staging_toggle(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("CASTLE_ACME_STAGING", "1")
monkeypatch.setenv("WILDPC_ACME_STAGING", "1")
cf = generate_caddyfile_from_registry(_acme({"api": _dep(9020, expose=True, name="api")}))
assert "acme_ca https://acme-staging-v02.api.letsencrypt.org/directory" in cf
@@ -122,20 +122,20 @@ class TestAcmeMode:
self, monkeypatch: pytest.MonkeyPatch
) -> None:
# A static frontend is a `runner: static` service serving <source>/<root>.
import castle_core.config as config_mod
import wildpc_core.config as config_mod
cfg = _config(
deployments={
"castle": CaddyDeployment(
manager="caddy", program="castle", root="dist"
"wildpc": CaddyDeployment(
manager="caddy", program="wildpc", root="dist"
)
},
programs={"castle": ProgramSpec(source="/data/repos/castle/app")},
programs={"wildpc": ProgramSpec(source="/data/repos/wildpc/app")},
)
monkeypatch.setattr(config_mod, "load_config", lambda *a, **k: cfg)
cf = generate_caddyfile_from_registry(_acme({}))
assert "@host_castle host castle.example.com" in cf
assert "root * /data/repos/castle/app/dist" in cf
assert "@host_wildpc host wildpc.example.com" in cf
assert "root * /data/repos/wildpc/app/dist" in cf
assert "try_files {path} /index.html" in cf
assert "file_server" in cf
@@ -187,12 +187,12 @@ class TestPublicExposure:
class TestOffMode:
"""No domain → HTTP-only control plane on :<port>: dashboard at / + /api → castle-api.
"""No domain → HTTP-only control plane on :<port>: dashboard at / + /api → wildpc-api.
Other services are port-only (not routed)."""
def test_control_plane(self) -> None:
cf = generate_caddyfile_from_registry(
_make_registry(deployed={"castle-api": _dep(9020, expose=True, name="castle-api")})
_make_registry(deployed={"wildpc-api": _dep(9020, expose=True, name="wildpc-api")})
)
assert "auto_https off" in cf
assert "handle_path /api/* {" in cf
@@ -217,8 +217,8 @@ def _service(port: int, *, expose: bool) -> SystemdDeployment:
def _config(
deployments: dict[str, DeploymentSpec], programs: dict[str, ProgramSpec] | None = None
) -> CastleConfig:
return CastleConfig(
) -> WildpcConfig:
return WildpcConfig(
root=None, # type: ignore[arg-type]
gateway=GatewayConfig(port=9000),
repo=None,
@@ -228,7 +228,7 @@ def _config(
class TestConfigSourceOfTruth:
"""compute_routes derives exposure/port from castle.yaml (the checkbox), so a
"""compute_routes derives exposure/port from wildpc.yaml (the checkbox), so a
regenerated Caddyfile tracks the spec, not a stale registry."""
def test_exposed_service_becomes_a_route(self) -> None: