- Rust 98.4%
- Makefile 1.1%
- Shell 0.5%
Workspace canonical-base migration on all 3 binary crates (CLI + server + admin) — none of them
had service.toml on disk pre-sweep (s102/s104-shape wholesale), with the post-b814ec07
service_base!() macro providing both SERVICE_TOML and BUILD_NR constants.
D-10 acceptance (5/5):
1. Branch is literal `development_mik` (per feedback_branch_name_development_mik).
2. `cargo update` absorbed the 4-pin cascade — hero_lib b814ec07 (BUILD_NR macro extension),
hero_proc_sdk 7fcea44 (socket/SSE helpers + service.toml metadata cleanup), hero_rpc f17dcd71,
hero_proxy 8bd8ad5. Cascade clean — no Run-API drift to absorb (hero_office uses
hero_proc_factory().restart_service() directly, no job_create / run_create).
3. `lab infocheck`: 3 crate(s) clean, 0 finding(s) total. All 3 binaries pass --info ok via
handle_info_flag(SERVICE_TOML) from herolib_core::base.
4. Conservative dep audit per crate (grep src/+tests/+benches/+build.rs, zero-match strip):
- hero_office_server: strip async-trait, clap, thiserror, tower-service
- hero_office_admin: strip async-trait, http-body-util, mime_guess, tower-service
- hero_office_sdk: strip anyhow, thiserror, tokio, tracing
- hero_office_examples: strip serde_json
Total 13 zero-match deps stripped. cargo check --workspace --release clean after each batch
(s103/s104 transitive-feature trap check — no breakage).
5. lab smoke: 4 of 4 server (GET /health, /openrpc.json, /.well-known/heroservice.json, POST /rpc system.ping)
+ 2 of 2 admin (GET /health, /.well-known/heroservice.json) = 6/6 passed. cargo test
--workspace --release: 0 failed, 0 passed, 3 ignored (live-server integration tests).
Wholesale canonical-base migration on 3 main.rs:
- hero_office/src/main.rs (CLI): added service_base!() + validate_service_toml(SERVICE_TOML) +
handle_info_flag(SERVICE_TOML) before Args::parse(). No bare-invocation shim needed (CLI is
pure flag-driven `--start`/`--stop` Args; bare invocation defaults to --help).
- hero_office_server/src/main.rs (daemon): added service_base!() + validate + handle_info_flag +
print_startup_banner + prepare_sockets. Removed manual create_dir_all + remove_file (now
handled by prepare_sockets). Added /.well-known/heroservice.json route for the new lab smoke
gate (sibling pattern from hero_collab_server::http_manifest).
- hero_office_admin/src/main.rs (daemon): same canonical wiring as server. Added
/.well-known/heroservice.json route via handlers::well_known.
3 new service.toml files (per-crate, all-binaries-in-each canonical pattern per
hero_service_toml_info skill line 220 — matches today's hero_proc post-7fcea44 shape):
- crates/hero_office/service.toml (kind=cli)
- crates/hero_office_server/service.toml (kind=server, rpc.sock openrpc)
- crates/hero_office_admin/service.toml (kind=admin, admin.sock http+webui)
Each [[binaries]] block lists all 3 binaries with their sockets and kinds. [[env]] entries
declared for: HERO_SOCKET_DIR (required workaround — see latent below), DEFAULT_CONTEXT,
ONLYOFFICE_JWT_SECRET, CONNECTOR_EXTERNAL_URL, OO_UPSTREAM_BASE, OO_PUBLIC_PROTO.
[[dependencies]] block initially included hero_foundry (server's onlyoffice.rs reads
document mtimes from foundry's UDS) but DROPPED because the installed ~/hero/bin/hero_foundry
is s7x-vintage without --info support, and lab service triggers dep bootstrap. Per the skill
("Most services need no [[dependencies]] at all") and the runtime degradation path at
crates/hero_office_server/src/onlyoffice.rs:63 ("Degraded mode: foundry's last_modified
couldn't be read; using time-bucket fallback"), hero_foundry is a soft dep. Re-add when the
sibling hero_foundry repo gets its own D-10 sweep and --info wiring.
LATENT (out of D-10 scope):
- herolib_core::base::resolve_socket_dir() doc claims a `~/hero/var/sockets` fallback when
neither HERO_SOCKET_DIR nor PATH_VAR is set, but the impl (service.rs:299-308 post-b814ec07)
panics via path_var(). This forces every D-10 service.toml to keep an [[env]] entry for
HERO_SOCKET_DIR even though the hero_service_toml_info skill says not to. Workaround
honoured here for the supervised-process path. Fix belongs in herolib_core.
- crates/hero_office_server/openrpc.client.generated.rs is committed at a non-canonical path
(sdk generated files normally live under crates/<sdk>/src/generated/openrpc.client.generated.rs).
Left in place; reorganisation belongs in a separate refactor.
- Workspace `rust-version = "1.92"` (D-08 SSOT is 1.95). Pre-existing; bump out of D-10 scope.
Refs: lhumina_code/hero_proc#102
Signed-off-by: mik-tf
|
||
|---|---|---|
| .forgejo/workflows | ||
| crates | ||
| doc | ||
| .gitignore | ||
| buildenv.sh | ||
| Cargo.lock | ||
| Cargo.toml | ||
| Makefile | ||
| README.md | ||
hero_office
OnlyOffice document editor connector for the Hero stack, backed by per-context hero_fossil WebDAV storage.
hero_office hosts OnlyOffice Docs editor surfaces (documents, spreadsheets, presentations, PDFs, diagrams) and persists files through the tenant's hero_fossil instance. The UI is embedded into hero_os as a set of apps under the "Office" archipelago.
Workspace layout
| crate | role |
|---|---|
hero_office_server |
OpenRPC JSON-RPC daemon on rpc.sock — all business logic |
hero_office_sdk |
Generated typed client via openrpc_client! macro |
hero_office_admin |
HTTP UI on admin.sock — admin dashboard + OnlyOffice wrapper pages |
hero_office_examples |
Examples and integration tests |
Sockets
| socket | purpose |
|---|---|
$HERO_SOCKET_DIR/hero_office/rpc.sock |
server OpenRPC endpoint |
$HERO_SOCKET_DIR/hero_office/ui.sock |
UI HTTP endpoint (iframed) |
$HERO_SOCKET_DIR/<context>/hero_fossil_server.sock |
per-context fossil backend |
HERO_SOCKET_DIR defaults to $HOME/hero/var/sockets.
Lifecycle
Managed through hero_proc via the Nushell service module at
scripts/nu_service.nu (per the nu_service skill).
use scripts/nu_service.nu
nu_service install # cargo build --release + copy to ~/hero/bin
nu_service start # register actions + service, then start
nu_service status
nu_service stop
Environment variables
| variable | purpose |
|---|---|
ONLYOFFICE_JWT_SECRET |
shared JWT secret for signing editor configs (must match the OO container) |
OO_SERVER_URL |
public URL of the OnlyOffice Docs server (loaded by the user's browser) |
CONNECTOR_EXTERNAL_URL |
URL of this service as seen by the OnlyOffice container |
DEFAULT_CONTEXT |
fallback context shown on / (default: default) |
HERO_SOCKET_DIR |
socket directory (default: $HOME/hero/var/sockets) |
URL surface (admin.sock, proxied by hero_router under /hero_office/)
| route | method | purpose |
|---|---|---|
/health |
GET | JSON health check |
/admin/?context=<ctx> |
GET | operator dashboard |
/<ctx>/<type>/ |
GET | file browser filtered to one OnlyOffice type |
/<ctx>/edit/<filename> |
GET | OnlyOffice editor wrapper page |
/<ctx>/files/<filename> |
GET | byte proxy for the OO container |
/<ctx>/callback |
POST | OnlyOffice save callback |
Where <type> is one of word, cell, slide, pdf, diagram.
hero_os integration
The "Office" archipelago (hierarchical) contains five islands, each an iframe pointing at the corresponding filtered surface:
- Documents →
/hero_office/<ctx>/word/ - Spreadsheets →
/hero_office/<ctx>/cell/ - Presentations →
/hero_office/<ctx>/slide/ - PDF →
/hero_office/<ctx>/pdf/ - Diagrams →
/hero_office/<ctx>/diagram/
See hero_os/crates/hero_os_app/src/registry.rs and island_content.rs.