Commit Graph

6 Commits

Author SHA1 Message Date
Paul Payne
6929bd89d3 Detail pages: rename the 'Runs' field to 'Launch' (matches the launcher concept)
The field showing a deployment's launcher + target is now labelled 'Launch'
(consistent with launcher/manager vocabulary) on ServiceDetail and the Service/
Job/Create field editors.
2026-07-01 13:35:02 -07:00
Paul Payne
01505328ad Dashboard: programs list deployments; Tools page; statics on Services; editable launcher
- Programs page: each card lists the program's deployments (name · kind) instead
  of a single kind badge; kind-filter chips removed (nav is the kind lens now).
  protonmail honestly shows tool + job.
- New Tools nav page (Wrench) — programs with a tool deployment (/programs?kind=tool).
- Services page now shows statics too: /services returns service + static, and a
  static renders as a caddy-served card (KindBadge, served URL, no start/stop).
- Program detail: DeploymentsSection + deleteConfirm rebuilt over program.deployments;
  header drops the (now nonexistent) program kind.
- ServiceFields / JobFields: launcher is now an editable select (python|command|
  container|compose|node), persisted into run.launcher via the normal save.

clean pnpm build + tsc --noEmit.
2026-07-01 12:32:09 -07:00
Paul Payne
317232ca6a Manager-first deployment model: split runner, merge service/job, frontend→static
Replace the conflated `runner` axis with two orthogonal ones: `manager`
(systemd|caddy|path|none) — who supervises/realizes a deployment — and, for
systemd only, a nested `launcher` (python|command|container|compose|node) — how
the process starts. ServiceSpec and JobSpec collapse into one manager-
discriminated DeploymentSpec union (Systemd/Caddy/Path/Remote); the services/
and jobs/ config dirs collapse into one deployments/ dir. The human "kind"
(service|job|tool|static|reference) is fully derived (kind_for), never stored —
the frontend kind is renamed static. behavior is gone.

- core: DeploymentSpec union + LaunchSpec + kind_for; legacy-aware loader
  normalizes old runner shapes; CastleConfig.deployments with derived
  services/jobs/tools views; registry.Deployment carries manager/launcher/kind.
- cli: service/job/tool as filtered views + a deployment group; --behavior→--kind,
  create --runner→--launcher; lifecycle dispatches over config.deployments.
- castle-api: /deployments primary with /services,/jobs as views; summaries
  derive kind; PUT/DELETE /config/deployments/{name} (services/jobs aliased).
- app: KindBadge, frontend→static everywhere, pick-a-kind creation wizard,
  per-kind config editors.
- docs: single deployments/ layout, manager/launcher, static kind throughout.

Live migration verified byte-identical: regenerated Caddyfile and every unit
ExecStart line unchanged, so nothing restarted. Suites: core 124, cli 25,
castle-api 55; dashboard build + type-check clean.
2026-07-01 10:23:03 -07:00
Paul Payne
ba60019a52 ui: field help text + editable program commands
- Add a 'hint' to the shared Field/TextField; annotate the config forms with
  short, accurate descriptions of each field:
  - program: source (working copy castle builds from), behavior (tool/daemon/
    frontend), stack (optional toolchain template), repo/ref (for clone),
    system deps (listed for reference, NOT auto-installed), commands.
  - service: port (listened-on, health-checked, proxied; map via ${port}),
    health path, proxy path vs proxy host, runs.
  - job: schedule (cron → systemd timer), runs.
- ProgramFields: the Commands section is now editable (build/test/lint/
  type-check/run), so a program with no stack can declare its own dev verbs
  by hand — a declared command overrides the stack default. Verified the
  commands/build shape round-trips through the config API.

App builds clean.
2026-06-15 08:50:03 -07:00
Paul Payne
82f12c9d61 Remove buttons: confirm + block program removal with active deployments
The Stage 2 editor split dropped the old confirm() — Remove program/service/job
deleted immediately on click. Restored confirmation on all three (FormFooter
window.confirm with a per-type message).

Removing a program that still has services/jobs referencing it would orphan
their program: ref. Now blocked:
- API: DELETE /config/programs/{name} → 409 'Programs with active jobs or
  services cannot be removed. Delete these first: …' (authoritative).
- App: ProgramFields shows the blocked reason instead of a Remove button when
  the program has deployments.
- CLI: castle delete refuses a program with referencing deployments not named
  the same (which would survive the delete dangling).

Verified live: DELETE program lakehouse → 409. api 52 / cli 24 green; build clean.
2026-06-14 15:52:57 -07:00
Paul Payne
73698fafe7 Stage 2: App — split the one editor into typed program/service/job forms
The single service-shaped DeploymentFields was reused for all three sections,
so the program page bled service fields (port/proxy/health) and couldn't edit
program config, and the job page couldn't edit its schedule. Replaced it with:

- ProgramFields  — description, source, stack, behavior, version, repo/ref,
  system deps (+ read-only commands). Edits the program catalog entry.
- ServiceFields  — run target, port, port_env, health, proxy path + host,
  env/secrets. Prefills correctly now (Stage 1) and round-trips through PUT.
- JobFields      — schedule, run target, env/secrets.

ConfigPanel selects the form by section. Shared Field/TextField/useEnvSecrets/
FormFooter helpers in detail/fields.tsx. Retired DeploymentFields. run editing
only touches python/command specs (container/node/remote run blocks preserved).

Verified: GET service manifest → PUT back validates 200. App type-checks/builds.
2026-06-14 15:34:07 -07:00