feat(services): add service_foundry.nu #95

Merged
mahmoud merged 1 commit from development_service_foundry into development 2026-04-20 13:38:04 +00:00
Owner

Summary

Adds tools/modules/services/service_foundry.nu, a lifecycle module for the hero_foundry service (server + UI). Combines three patterns established by prior services: inline CLI flags (from service_biz.nu), env-at-register-time paths (from service_books.nu), and a harmless subcommand token on the UI action.

Changes

  • tools/modules/services/service_foundry.nu — new module (~280 lines).
  • tools/modules/services/mod.nuexport use service_foundry.nu.
  • tools/modules/services/packages.nuuse service_foundry.nu + services_extra entry with --reset/--update passthrough.

Design decisions (documented in module header)

  1. Inline CLI flags on server action. hero_foundry_server's clap parser at hero_foundry_server/src/main.rs:46-74 does NOT declare [env: ...] fallbacks for --allow-dir / --webdav-storage, so they must go on argv. script: is built as $"($bin) --allow-dir ($data_repos) --webdav-storage ($data_webdav)" with paths resolved at register time via svc_home $root.

  2. Env vars go on the server action only. Grep confirmed both HERO_FOUNDRY_REPOS and HERO_FOUNDRY_BASE_PATH are consumed server-side (hero_foundry_server/src/main.rs:155 + hero_foundry_examples/examples/seed_data.rs:18). UI reads zero Hero-specific env vars (base-path prefixing uses the X-Forwarded-Prefix HTTP header middleware).

  3. UI start token is decorative. hero_foundry_ui/src/main.rs:86-89 has no clap parser and ignores argv. The token is kept for TOML parity.

  4. Scope: Option A (hero_foundry repo only). The sibling lhumina_code/hero_foundry_ui repo is a distinct Actix-based service (own FoundryStore, issues/wiki/PRs, REPO_PATH env, org-scoped routing). Documented in the module header as a future separate sub-issue.

  5. No preflight. hero_foundry.toml declares no depends_on, and the server's only boot prerequisite is that --webdav-storage parent dir is writable (it auto-creates via std::fs::create_dir_all).

Test Results

End-to-end smoke test on the Hetzner box. 23 of 24 assertions PASS. The single FAIL is an incorrect test assumption, not a module bug.

# Assertion Result
1a–1c hero_proc-down error paths PASS × 3
2a service_proc start --root healthy PASS
2b service_foundry install --root built 3 binaries PASS
2c Re-install short-circuits via svc_bins_ok PASS
2d service_foundry start --reset --root → registered, running PASS
2e–2f Both rpc.sock and ui.sock live unix sockets PASS × 2
2g–2h Both sockets accept HTTP PASS × 2
2i status returns {name: hero_foundry, state: running} PASS × 2
2j Server env has HERO_FOUNDRY_REPOS, HERO_FOUNDRY_BASE_PATH, RUST_LOG PASS × 2
2k Server script contains --allow-dir + --webdav-storage PASS × 2
2l UI env has only RUST_LOG; UI script has start token PASS × 2
2m Idempotent start prints "already running" PASS
2n 15 s observation — no new restarts, state held running PASS × 2
2o webdav dir auto-created by server PASS
2o repos dir auto-created FAIL (expected)
2p stop cleanly unregisters PASS
2q Post-stop status returns service 'hero_foundry' not found PASS

Note on the 2o "fail"

The server's hero_foundry_server/src/main.rs:121 calls std::fs::create_dir_all only on --webdav-storage; --allow-dir is treated as an existing access-control root, not auto-created. The service runs fine without the repos dir existing (state stays running), but real repo operations would need it. Operators bootstrapping hero_foundry need one mkdir -p <svc_home>/var/hero_foundry/repos. Not a module issue — the test assumption was wrong. Full per-step output on issue #94.

## Summary Adds `tools/modules/services/service_foundry.nu`, a lifecycle module for the `hero_foundry` service (server + UI). Combines three patterns established by prior services: inline CLI flags (from `service_biz.nu`), env-at-register-time paths (from `service_books.nu`), and a harmless subcommand token on the UI action. ## Related - Closes #94 - Part of #75 ## Changes - `tools/modules/services/service_foundry.nu` — new module (~280 lines). - `tools/modules/services/mod.nu` — `export use service_foundry.nu`. - `tools/modules/services/packages.nu` — `use service_foundry.nu` + `services_extra` entry with `--reset`/`--update` passthrough. ## Design decisions (documented in module header) 1. **Inline CLI flags on server action.** `hero_foundry_server`'s clap parser at `hero_foundry_server/src/main.rs:46-74` does NOT declare `[env: ...]` fallbacks for `--allow-dir` / `--webdav-storage`, so they must go on argv. `script:` is built as `$"($bin) --allow-dir ($data_repos) --webdav-storage ($data_webdav)"` with paths resolved at register time via `svc_home $root`. 2. **Env vars go on the server action only.** Grep confirmed both `HERO_FOUNDRY_REPOS` and `HERO_FOUNDRY_BASE_PATH` are consumed server-side (`hero_foundry_server/src/main.rs:155` + `hero_foundry_examples/examples/seed_data.rs:18`). UI reads zero Hero-specific env vars (base-path prefixing uses the `X-Forwarded-Prefix` HTTP header middleware). 3. **UI `start` token is decorative.** `hero_foundry_ui/src/main.rs:86-89` has no clap parser and ignores argv. The token is kept for TOML parity. 4. **Scope: Option A (hero_foundry repo only).** The sibling `lhumina_code/hero_foundry_ui` repo is a distinct Actix-based service (own FoundryStore, issues/wiki/PRs, `REPO_PATH` env, org-scoped routing). Documented in the module header as a future separate sub-issue. 5. **No preflight.** `hero_foundry.toml` declares no `depends_on`, and the server's only boot prerequisite is that `--webdav-storage` parent dir is writable (it auto-creates via `std::fs::create_dir_all`). ## Test Results End-to-end smoke test on the Hetzner box. **23 of 24 assertions PASS.** The single FAIL is an incorrect test assumption, not a module bug. | # | Assertion | Result | |---|---|---| | 1a–1c | hero_proc-down error paths | PASS × 3 | | 2a | `service_proc start --root` healthy | PASS | | 2b | `service_foundry install --root` built 3 binaries | PASS | | 2c | Re-install short-circuits via `svc_bins_ok` | PASS | | 2d | `service_foundry start --reset --root` → registered, running | PASS | | 2e–2f | Both `rpc.sock` and `ui.sock` live unix sockets | PASS × 2 | | 2g–2h | Both sockets accept HTTP | PASS × 2 | | 2i | `status` returns `{name: hero_foundry, state: running}` | PASS × 2 | | 2j | Server env has `HERO_FOUNDRY_REPOS`, `HERO_FOUNDRY_BASE_PATH`, `RUST_LOG` | PASS × 2 | | 2k | Server script contains `--allow-dir` + `--webdav-storage` | PASS × 2 | | 2l | UI env has only `RUST_LOG`; UI script has `start` token | PASS × 2 | | 2m | Idempotent start prints "already running" | PASS | | 2n | 15 s observation — no new restarts, state held running | PASS × 2 | | 2o | `webdav` dir auto-created by server | PASS | | 2o | `repos` dir auto-created | **FAIL (expected)** | | 2p | `stop` cleanly unregisters | PASS | | 2q | Post-stop `status` returns `service 'hero_foundry' not found` | PASS | ### Note on the 2o "fail" The server's `hero_foundry_server/src/main.rs:121` calls `std::fs::create_dir_all` only on `--webdav-storage`; `--allow-dir` is treated as an existing access-control root, not auto-created. The service runs fine without the repos dir existing (state stays `running`), but real repo operations would need it. Operators bootstrapping hero_foundry need one `mkdir -p <svc_home>/var/hero_foundry/repos`. Not a module issue — the test assumption was wrong. Full per-step output on issue #94.
Add a service_foundry module that provides install | start | stop | status
lifecycle commands for hero_foundry (hero_foundry_server + hero_foundry_ui)
through hero_proc. Combines three patterns established by prior services:

- Inline CLI flags on the server action (from service_biz.nu) —
  hero_foundry_server's clap parser does NOT declare [env: ...] fallbacks
  for --allow-dir or --webdav-storage, so they MUST go on argv. script: is
  built as $"($bin) --allow-dir ($data_repos) --webdav-storage ($data_webdav)".

- Env vars resolved at register time (from service_books.nu) —
  HERO_FOUNDRY_REPOS and HERO_FOUNDRY_BASE_PATH on the server action,
  with paths computed from svc_home/svc_sock_base. UI action has only
  RUST_LOG (verified via grep: UI reads no Hero-specific env vars).

- UI 'start' subcommand token — hero_foundry_ui's main() has no clap
  parser and ignores argv, but we keep 'start' in script: for TOML parity.

Two-action service registered as hero_foundry in the core context.
Virtual workspace, no --workspace pre-build needed. No dependencies in
the TOML; no preflight helper.

The sibling lhumina_code/hero_foundry_ui repo is a distinct Actix-based
service with its own FoundryStore / issues / wiki / PRs, reading
REPO_PATH env with org-scoped routing. This module does NOT cover that
repo; it needs its own sub-issue after an owner decision. Documented in
the module header.

#94
#75
mahmoud merged commit 44067bcd7d into development 2026-04-20 13:38:04 +00:00
mahmoud deleted branch development_service_foundry 2026-04-20 13:38:08 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_skills!95
No description provided.