Add docs.installTemplate RPC method #102

Closed
opened 2026-04-26 12:23:50 +00:00 by mahmoud · 4 comments
Owner

Parent: #101

What to add

Method: docs.installTemplate
Params: { path: string, reset?: bool }
Returns: { job_id: string }
Wraps: DocSite::install_template(reset) at lib.rs:85

Implementation steps

  1. Verify hero_docs install-template subcommand exists in hero_docs binary
  2. Add handle_docs_install_template(id, params, config) -> RpcResponse in crates/hero_books_server/src/web/rpc.rs
  3. Add dispatch arm "docs.installTemplate" in match block at rpc.rs:155
  4. Add method entry in crates/hero_books_server/openrpc.json with params, result, and examples block matching existing docs.* style
  5. Bump info.version in openrpc.json
  6. Update doc-comment header at rpc.rs:9-28

Acceptance Criteria

  • hero_docs install-template subcommand exists
  • Handler shells out via hero_docs (not in-process)
  • Returns { job_id } immediately; client polls docs.jobStatus
  • spec/impl parity check passes (see verification script in parent)
Parent: #101 ## What to add **Method:** `docs.installTemplate` **Params:** `{ path: string, reset?: bool }` **Returns:** `{ job_id: string }` **Wraps:** `DocSite::install_template(reset)` at `lib.rs:85` ## Implementation steps 1. Verify `hero_docs install-template` subcommand exists in `hero_docs` binary 2. Add `handle_docs_install_template(id, params, config) -> RpcResponse` in `crates/hero_books_server/src/web/rpc.rs` 3. Add dispatch arm `"docs.installTemplate"` in match block at `rpc.rs:155` 4. Add method entry in `crates/hero_books_server/openrpc.json` with params, result, and examples block matching existing `docs.*` style 5. Bump `info.version` in `openrpc.json` 6. Update doc-comment header at `rpc.rs:9-28` ## Acceptance Criteria - [x] `hero_docs install-template` subcommand exists - [x] Handler shells out via hero_docs (not in-process) - [x] Returns `{ job_id }` immediately; client polls `docs.jobStatus` - [x] spec/impl parity check passes (see verification script in parent)
rawdaGastan added this to the ACTIVE project 2026-04-26 14:08:16 +00:00
Member

Implementation Spec for Issue #102

Objective

Expose DocSite::install_template over the OpenRPC interface as docs.installTemplate. The method submits a hero_proc job that shells out to the hero_docs binary, follows the existing async/dedup pattern of docs.new and docs.generate, and returns { "job_id": "<n>" } for clients to poll via docs.jobStatus. The hero_docs binary itself grows a matching install-template subcommand so the handler has something to invoke.

Requirements

  • docs.installTemplate is dispatchable from crates/hero_books_server/src/web/rpc.rs and reaches a new handler handle_docs_install_template.
  • The new method has a matching entry in crates/hero_books_server/openrpc.json mirroring the existing docs.new / docs.generate style (no examples block — none exist today).
  • info.version in openrpc.json is bumped (0.1.5 -> 0.1.6).
  • The # Available Methods doc-comment header in rpc.rs (lines 9-28) gains a ## Docs section listing all currently exposed docs.* methods (docs.new, docs.generate, docs.installTemplate, docs.jobStatus).
  • hero_docs (src/bin/hero_docs.rs) gains a new install-template subcommand: hero_docs install-template --path <path> [--reset]. It calls hero_books_docusaurus::template::install_template(&path, reset) directly — no heroscript loading required, since the underlying function only needs a build-directory path.
  • The handler shells out via config.hero_docs_bin, never calling DocSite in-process.
  • The handler reuses submit_or_dedup_docs_job(...) with action name docs_install_template_<input_hash>.
  • handle_docs_job_status's prefix-strip block (rpc.rs:1508-1519) is updated so it recognises docs_install_template_ as a known prefix that produces no output_path (the user-supplied path is not recoverable from the input hash, and there is no deterministic build artifact to surface).
  • Invalid-params responses use RpcResponse::invalid_params (-32602); internal failures use RpcResponse::error(id, -32000, ...).
  • The verification diff from INSTRUCTIONS_OPENRPC.md §Verification produces an empty diff (spec list and dispatcher list match).

Files to Modify/Create

  • src/bin/hero_docs.rs — add InstallTemplate(InstallTemplateArgs) variant, args struct, run_install_template runner.
  • crates/hero_books_server/src/web/rpc.rs — add handle_docs_install_template, dispatch arm, doc-header ## Docs section, prefix recognition in handle_docs_job_status.
  • crates/hero_books_server/openrpc.json — add docs.installTemplate method entry, bump info.version to "0.1.6".

No new files.

Implementation Plan

Step 1 — Add install-template subcommand to hero_docs

Files: src/bin/hero_docs.rs

  • Extend the Commands enum with a new InstallTemplate(InstallTemplateArgs) variant. Keep the existing kebab-case CLI surface clap derives by default (install-template).
  • Add the args struct:
    #[derive(Args)]
    struct InstallTemplateArgs {
        /// Path to the Docusaurus build directory where the template is installed
        #[arg(long)]
        path: String,
        /// Reset the build directory before installing (recreates from scratch)
        #[arg(long)]
        reset: bool,
    }
    
  • Add the runner:
    fn run_install_template(args: InstallTemplateArgs) -> Result<(), Box<dyn std::error::Error>> {
        let path = std::path::PathBuf::from(&args.path);
        hero_books_docusaurus::template::install_template(&path, args.reset)?;
        log::info!("Template installed at {}", path.display());
        Ok(())
    }
    
  • Dispatch from main() alongside Commands::New / Commands::Generate.

Dependencies: none.

Step 2 — Add handle_docs_install_template handler in rpc.rs

Files: crates/hero_books_server/src/web/rpc.rs

  • Add the function below handle_docs_generate (around the existing handle_docs_job_status neighbourhood) with the standard signature fn handle_docs_install_template(id: Option<Value>, params: Option<Value>, config: &ServerConfig) -> RpcResponse.
  • Body:
    • Extract path (required, non-empty string) and reset (optional bool, default false) from the params object. Reject empty / missing path with RpcResponse::invalid_params(id, "missing or empty 'path' parameter").
    • let input_hash = calculate_docs_input_hash(&[&path, &reset.to_string()]); — both raw inputs included so dedup is stable across calls with different reset.
    • Build the script:
      let hero_docs = shell_quote(&config.hero_docs_bin.to_string_lossy());
      let path_q = shell_quote(&path);
      let reset_flag = if reset { " --reset" } else { "" };
      let script = format!("{} install-template --path {}{}", hero_docs, path_q, reset_flag);
      
    • Submit via submit_or_dedup_docs_job(id, config, &format!("docs_install_template_{}", input_hash), &script).

Dependencies: Step 1 (the install-template subcommand must exist for runtime invocations to succeed; not required for compilation).

Step 3 — Wire dispatch arm

Files: crates/hero_books_server/src/web/rpc.rs

  • In the match request.method.as_str() block (lines 155-205), inside the // Docs API group, add after the existing docs.generate arm and before docs.jobStatus:
    "docs.installTemplate" => handle_docs_install_template(request.id, request.params, config),
    

Dependencies: Step 2.

Step 4 — Recognise the new prefix in handle_docs_job_status

Files: crates/hero_books_server/src/web/rpc.rs

  • Today the prefix-strip block at rpc.rs:1508-1519 strips docs_new_ / docs_generate_ to recover the hash for output_path. Update it so docs_install_template_ is a recognised but output_path-less prefix:
    if let Some(name) = summary.name.as_deref() {
        // Methods that produce a deterministic build artifact (path = cache/<hash>/build).
        let hash = name
            .strip_prefix("docs_new_")
            .or_else(|| name.strip_prefix("docs_generate_"));
        if let Some(hash) = hash {
            let path = get_docusaurus_cache_dir().join(hash).join("build");
            out.insert(
                "output_path".to_string(),
                Value::String(path.to_string_lossy().to_string()),
            );
        }
        // Methods whose output path is not recoverable from the input hash —
        // recognised so we don't accidentally synthesise a bogus output_path.
        // (docs.installTemplate writes into a user-supplied build directory.)
        // Add new prefixes here as more docs.* methods land (#103-#107).
    }
    
    The recognition is implicit (we simply don't try to strip these prefixes), but the comment makes future maintenance obvious.

Dependencies: Step 2.

Step 5 — Update doc-comment header in rpc.rs

Files: crates/hero_books_server/src/web/rpc.rs

  • The header at lines 9-28 currently has no ## Docs section. Add one:
    //! ## Docs (async docusaurus generation, submitted as hero_proc jobs)
    //! - `docs.new` - Scaffold and build a new Docusaurus site
    //! - `docs.generate` - Generate a site from an ebook directory or book id
    //! - `docs.installTemplate` - Install the Docusaurus template at a build path
    //! - `docs.jobStatus` - Poll the status of a docs.* job
    
    Insert between the ## Collections block and the ## Legacy (deprecated) / other trailing items so the header reads naturally.

Dependencies: none (purely documentation).

Step 6 — Add docs.installTemplate entry in openrpc.json

Files: crates/hero_books_server/openrpc.json

  • Bump info.version from "0.1.5" to "0.1.6".
  • Insert a new method object into the methods array between docs.generate and docs.jobStatus:
    {
      "name": "docs.installTemplate",
      "summary": "Submit a hero_proc job that installs the Docusaurus template at the given build path. Returns the hero_proc job id as a string; poll via docs.jobStatus.",
      "params": [
        { "name": "path",  "schema": { "type": "string"  }, "required": true },
        { "name": "reset", "schema": { "type": "boolean" }, "required": false }
      ],
      "result": {
        "name": "jobRef",
        "schema": {
          "type": "object",
          "properties": { "job_id": { "type": "string" } }
        }
      }
    }
    

Dependencies: Step 3 (so the verification diff in Step 7 passes).

Step 7 — Verify spec/impl parity and build

Files: none (read-only check + cargo).

  • Run the verification snippet from INSTRUCTIONS_OPENRPC.md §Verification:
    jq -r '.methods[].name' crates/hero_books_server/openrpc.json | sort > /tmp/spec.txt
    rg -o '"(docs|books|collections|libraries|search|server|admin|rpc)\.[a-zA-Z.]+"\s*=>' \
       crates/hero_books_server/src/web/rpc.rs | tr -d '"' | awk '{print $1}' | sort > /tmp/impl.txt
    diff /tmp/spec.txt /tmp/impl.txt
    
  • Run cargo check -p hero_books_server and cargo check --bin hero_docs.
  • Run cargo test -p hero_books_server to confirm no regressions.
  • Smoke test: cargo run --bin hero_docs -- install-template --help.

Dependencies: Steps 1-6.

Acceptance Criteria

  • hero_docs install-template --help prints usage with --path (required) and --reset (flag) options.
  • hero_docs install-template --path /tmp/test_docs (from a clean state) succeeds and creates a Docusaurus template at the path.
  • crates/hero_books_server/src/web/rpc.rs defines handle_docs_install_template matching the existing handle_docs_* signature.
  • The docs.installTemplate arm is wired into the dispatcher match block, ordered between docs.generate and docs.jobStatus.
  • handle_docs_job_status does not synthesise an output_path for jobs whose action name starts with docs_install_template_.
  • The doc-header at rpc.rs:9-28 lists docs.* methods including docs.installTemplate under a ## Docs section.
  • crates/hero_books_server/openrpc.json contains the docs.installTemplate method entry with the params/result shape above.
  • info.version in openrpc.json is "0.1.6".
  • The verification diff command from INSTRUCTIONS_OPENRPC.md §Verification produces empty output.
  • cargo check -p hero_books_server succeeds.
  • cargo check --bin hero_docs succeeds.
  • cargo test -p hero_books_server passes (no regressions).

Notes

  • Scope discipline: this PR adds only docs.installTemplate. Sibling methods (docs.updateTemplate, docs.build, docs.dev, docs.publish, docs.publishDev) are tracked in #103-#107 and ship in their own PRs. Resist the urge to bundle them.
  • Path semantics: path is the Docusaurus build directory — the same kind of path the underlying template::install_template(&Path, bool) expects. It is not a heroscript path. We bypass DocSite::from_heroscript because install_template only needs path_build, and forcing a heroscript at the target would add round-trips with no benefit. (Compare: docs.new also takes a target directory rather than a heroscript.)
  • Output_path policy: per INSTRUCTIONS_OPENRPC.md, methods whose effective output path cannot be recovered from the input hash do not synthesise a bogus output_path. We extend the prefix recognition in handle_docs_job_status rather than emitting one. If a future change wants output_path for docs.installTemplate, it requires augmenting the action-name encoding (e.g. embedding base64 of path) — out of scope for #102.
  • Dedup keying: input_hash is computed from the raw path and reset flag string. Calling docs.installTemplate({path:"/x"}) twice in quick succession returns the same job id; calling it with reset:true produces a distinct job, which is what we want — the operations are not equivalent.
  • info.version bump: required by INSTRUCTIONS_OPENRPC.md whenever the spec changes. 0.1.5 -> 0.1.6 on this PR; subsequent child issues will continue bumping (0.1.7, ...).
  • Error codes: -32602 for invalid params, -32000 for hero_proc / internal failures — match handle_docs_new.
  • Long-running jobs: not relevant for install-template (it's bounded by the bun install). The 10-minute default timeout in submit_or_dedup_docs_job is fine.
## Implementation Spec for Issue #102 ### Objective Expose `DocSite::install_template` over the OpenRPC interface as `docs.installTemplate`. The method submits a `hero_proc` job that shells out to the `hero_docs` binary, follows the existing async/dedup pattern of `docs.new` and `docs.generate`, and returns `{ "job_id": "<n>" }` for clients to poll via `docs.jobStatus`. The `hero_docs` binary itself grows a matching `install-template` subcommand so the handler has something to invoke. ### Requirements - `docs.installTemplate` is dispatchable from `crates/hero_books_server/src/web/rpc.rs` and reaches a new handler `handle_docs_install_template`. - The new method has a matching entry in `crates/hero_books_server/openrpc.json` mirroring the existing `docs.new` / `docs.generate` style (no `examples` block — none exist today). - `info.version` in `openrpc.json` is bumped (`0.1.5` -> `0.1.6`). - The `# Available Methods` doc-comment header in `rpc.rs` (lines 9-28) gains a `## Docs` section listing all currently exposed `docs.*` methods (`docs.new`, `docs.generate`, `docs.installTemplate`, `docs.jobStatus`). - `hero_docs` (`src/bin/hero_docs.rs`) gains a new `install-template` subcommand: `hero_docs install-template --path <path> [--reset]`. It calls `hero_books_docusaurus::template::install_template(&path, reset)` directly — no heroscript loading required, since the underlying function only needs a build-directory path. - The handler shells out via `config.hero_docs_bin`, never calling `DocSite` in-process. - The handler reuses `submit_or_dedup_docs_job(...)` with action name `docs_install_template_<input_hash>`. - `handle_docs_job_status`'s prefix-strip block (`rpc.rs:1508-1519`) is updated so it recognises `docs_install_template_` as a known prefix that produces no `output_path` (the user-supplied path is not recoverable from the input hash, and there is no deterministic build artifact to surface). - Invalid-params responses use `RpcResponse::invalid_params` (-32602); internal failures use `RpcResponse::error(id, -32000, ...)`. - The verification diff from INSTRUCTIONS_OPENRPC.md §Verification produces an empty diff (spec list and dispatcher list match). ### Files to Modify/Create - `src/bin/hero_docs.rs` — add `InstallTemplate(InstallTemplateArgs)` variant, args struct, `run_install_template` runner. - `crates/hero_books_server/src/web/rpc.rs` — add `handle_docs_install_template`, dispatch arm, doc-header `## Docs` section, prefix recognition in `handle_docs_job_status`. - `crates/hero_books_server/openrpc.json` — add `docs.installTemplate` method entry, bump `info.version` to `"0.1.6"`. No new files. ### Implementation Plan #### Step 1 — Add `install-template` subcommand to `hero_docs` Files: `src/bin/hero_docs.rs` - Extend the `Commands` enum with a new `InstallTemplate(InstallTemplateArgs)` variant. Keep the existing kebab-case CLI surface clap derives by default (`install-template`). - Add the args struct: ```rust #[derive(Args)] struct InstallTemplateArgs { /// Path to the Docusaurus build directory where the template is installed #[arg(long)] path: String, /// Reset the build directory before installing (recreates from scratch) #[arg(long)] reset: bool, } ``` - Add the runner: ```rust fn run_install_template(args: InstallTemplateArgs) -> Result<(), Box<dyn std::error::Error>> { let path = std::path::PathBuf::from(&args.path); hero_books_docusaurus::template::install_template(&path, args.reset)?; log::info!("Template installed at {}", path.display()); Ok(()) } ``` - Dispatch from `main()` alongside `Commands::New` / `Commands::Generate`. Dependencies: none. #### Step 2 — Add `handle_docs_install_template` handler in `rpc.rs` Files: `crates/hero_books_server/src/web/rpc.rs` - Add the function below `handle_docs_generate` (around the existing `handle_docs_job_status` neighbourhood) with the standard signature `fn handle_docs_install_template(id: Option<Value>, params: Option<Value>, config: &ServerConfig) -> RpcResponse`. - Body: - Extract `path` (required, non-empty string) and `reset` (optional bool, default `false`) from the params object. Reject empty / missing `path` with `RpcResponse::invalid_params(id, "missing or empty 'path' parameter")`. - `let input_hash = calculate_docs_input_hash(&[&path, &reset.to_string()]);` — both raw inputs included so dedup is stable across calls with different `reset`. - Build the script: ```rust let hero_docs = shell_quote(&config.hero_docs_bin.to_string_lossy()); let path_q = shell_quote(&path); let reset_flag = if reset { " --reset" } else { "" }; let script = format!("{} install-template --path {}{}", hero_docs, path_q, reset_flag); ``` - Submit via `submit_or_dedup_docs_job(id, config, &format!("docs_install_template_{}", input_hash), &script)`. Dependencies: Step 1 (the `install-template` subcommand must exist for runtime invocations to succeed; not required for compilation). #### Step 3 — Wire dispatch arm Files: `crates/hero_books_server/src/web/rpc.rs` - In the `match request.method.as_str()` block (lines 155-205), inside the `// Docs API` group, add after the existing `docs.generate` arm and before `docs.jobStatus`: ```rust "docs.installTemplate" => handle_docs_install_template(request.id, request.params, config), ``` Dependencies: Step 2. #### Step 4 — Recognise the new prefix in `handle_docs_job_status` Files: `crates/hero_books_server/src/web/rpc.rs` - Today the prefix-strip block at `rpc.rs:1508-1519` strips `docs_new_` / `docs_generate_` to recover the hash for `output_path`. Update it so `docs_install_template_` is a recognised but `output_path`-less prefix: ```rust if let Some(name) = summary.name.as_deref() { // Methods that produce a deterministic build artifact (path = cache/<hash>/build). let hash = name .strip_prefix("docs_new_") .or_else(|| name.strip_prefix("docs_generate_")); if let Some(hash) = hash { let path = get_docusaurus_cache_dir().join(hash).join("build"); out.insert( "output_path".to_string(), Value::String(path.to_string_lossy().to_string()), ); } // Methods whose output path is not recoverable from the input hash — // recognised so we don't accidentally synthesise a bogus output_path. // (docs.installTemplate writes into a user-supplied build directory.) // Add new prefixes here as more docs.* methods land (#103-#107). } ``` The recognition is implicit (we simply don't try to strip these prefixes), but the comment makes future maintenance obvious. Dependencies: Step 2. #### Step 5 — Update doc-comment header in `rpc.rs` Files: `crates/hero_books_server/src/web/rpc.rs` - The header at lines 9-28 currently has no `## Docs` section. Add one: ```rust //! ## Docs (async docusaurus generation, submitted as hero_proc jobs) //! - `docs.new` - Scaffold and build a new Docusaurus site //! - `docs.generate` - Generate a site from an ebook directory or book id //! - `docs.installTemplate` - Install the Docusaurus template at a build path //! - `docs.jobStatus` - Poll the status of a docs.* job ``` Insert between the `## Collections` block and the `## Legacy (deprecated)` / other trailing items so the header reads naturally. Dependencies: none (purely documentation). #### Step 6 — Add `docs.installTemplate` entry in `openrpc.json` Files: `crates/hero_books_server/openrpc.json` - Bump `info.version` from `"0.1.5"` to `"0.1.6"`. - Insert a new method object into the `methods` array between `docs.generate` and `docs.jobStatus`: ```json { "name": "docs.installTemplate", "summary": "Submit a hero_proc job that installs the Docusaurus template at the given build path. Returns the hero_proc job id as a string; poll via docs.jobStatus.", "params": [ { "name": "path", "schema": { "type": "string" }, "required": true }, { "name": "reset", "schema": { "type": "boolean" }, "required": false } ], "result": { "name": "jobRef", "schema": { "type": "object", "properties": { "job_id": { "type": "string" } } } } } ``` Dependencies: Step 3 (so the verification diff in Step 7 passes). #### Step 7 — Verify spec/impl parity and build Files: none (read-only check + cargo). - Run the verification snippet from INSTRUCTIONS_OPENRPC.md §Verification: ```sh jq -r '.methods[].name' crates/hero_books_server/openrpc.json | sort > /tmp/spec.txt rg -o '"(docs|books|collections|libraries|search|server|admin|rpc)\.[a-zA-Z.]+"\s*=>' \ crates/hero_books_server/src/web/rpc.rs | tr -d '"' | awk '{print $1}' | sort > /tmp/impl.txt diff /tmp/spec.txt /tmp/impl.txt ``` - Run `cargo check -p hero_books_server` and `cargo check --bin hero_docs`. - Run `cargo test -p hero_books_server` to confirm no regressions. - Smoke test: `cargo run --bin hero_docs -- install-template --help`. Dependencies: Steps 1-6. ### Acceptance Criteria - [ ] `hero_docs install-template --help` prints usage with `--path` (required) and `--reset` (flag) options. - [ ] `hero_docs install-template --path /tmp/test_docs` (from a clean state) succeeds and creates a Docusaurus template at the path. - [ ] `crates/hero_books_server/src/web/rpc.rs` defines `handle_docs_install_template` matching the existing `handle_docs_*` signature. - [ ] The `docs.installTemplate` arm is wired into the dispatcher `match` block, ordered between `docs.generate` and `docs.jobStatus`. - [ ] `handle_docs_job_status` does not synthesise an `output_path` for jobs whose action name starts with `docs_install_template_`. - [ ] The doc-header at `rpc.rs:9-28` lists `docs.*` methods including `docs.installTemplate` under a `## Docs` section. - [ ] `crates/hero_books_server/openrpc.json` contains the `docs.installTemplate` method entry with the params/result shape above. - [ ] `info.version` in `openrpc.json` is `"0.1.6"`. - [ ] The verification diff command from INSTRUCTIONS_OPENRPC.md §Verification produces empty output. - [ ] `cargo check -p hero_books_server` succeeds. - [ ] `cargo check --bin hero_docs` succeeds. - [ ] `cargo test -p hero_books_server` passes (no regressions). ### Notes - **Scope discipline**: this PR adds *only* `docs.installTemplate`. Sibling methods (`docs.updateTemplate`, `docs.build`, `docs.dev`, `docs.publish`, `docs.publishDev`) are tracked in #103-#107 and ship in their own PRs. Resist the urge to bundle them. - **Path semantics**: `path` is the Docusaurus *build directory* — the same kind of path the underlying `template::install_template(&Path, bool)` expects. It is not a heroscript path. We bypass `DocSite::from_heroscript` because `install_template` only needs `path_build`, and forcing a heroscript at the target would add round-trips with no benefit. (Compare: `docs.new` also takes a target directory rather than a heroscript.) - **Output_path policy**: per INSTRUCTIONS_OPENRPC.md, methods whose effective output path cannot be recovered from the input hash *do not* synthesise a bogus `output_path`. We extend the prefix recognition in `handle_docs_job_status` rather than emitting one. If a future change wants `output_path` for `docs.installTemplate`, it requires augmenting the action-name encoding (e.g. embedding base64 of `path`) — out of scope for #102. - **Dedup keying**: `input_hash` is computed from the raw `path` and `reset` flag string. Calling `docs.installTemplate({path:"/x"})` twice in quick succession returns the same job id; calling it with `reset:true` produces a distinct job, which is what we want — the operations are not equivalent. - **`info.version` bump**: required by INSTRUCTIONS_OPENRPC.md whenever the spec changes. `0.1.5` -> `0.1.6` on this PR; subsequent child issues will continue bumping (`0.1.7`, ...). - **Error codes**: `-32602` for invalid params, `-32000` for hero_proc / internal failures — match `handle_docs_new`. - **Long-running jobs**: not relevant for `install-template` (it's bounded by the bun install). The 10-minute default timeout in `submit_or_dedup_docs_job` is fine.
Member

Test Results

Suite: cargo test -p hero_books_server --lib
Total: 17 — Passed: 17 — Failed: 0

New test added with this change:

  • web::rpc::tests::test_docs_install_template_missing_params — covers missing path, empty path, and missing params object. All assertions pass.

Existing docs.* validation tests still green (test_docs_new_missing_params, test_docs_generate_missing_params, test_docs_generate_invalid_book_id, test_docs_job_status_rejects_non_numeric_id).

Spec/impl parity

INSTRUCTIONS_OPENRPC.md §Verification diff command produces empty output — openrpc.json and the dispatcher in rpc.rs agree, with docs.installTemplate listed in both.

Build

  • cargo check -p hero_books_server — OK
  • cargo check --bin hero_docs — OK

CLI smoke test

$ hero_docs install-template --help
Install the Docusaurus template at a build directory

Usage: hero_docs install-template [OPTIONS] --path <PATH>

Options:
      --path <PATH>  Path to the Docusaurus build directory where the template is installed
      --reset        Reset the build directory before installing (recreates from scratch)
  -h, --help         Print help

Live end-to-end RPC test (against running hero_books_server + hero_proc)

Step Result
rpc.discover lists docs.installTemplate with correct params/result schema pass
Validation: missing path returns -32602 "missing or empty 'path' parameter" pass
Submit returns {"job_id":"76"} pass
Re-submit with same params dedupes to the same job_id: "76" pass
Job dispatched to hero_proc and ran hero_docs install-template ... pass
Failure tail surfaces correctly via docs.jobStatus pass
No output_path field on the response (per design — input path not recoverable from hash) pass

The single live failure was an environment issue (bun is not installed) inside template::install_template, which docs.new / docs.generate already exercise — not a defect introduced by this change. The full RPC chain (dispatch → handler → hero_proc → hero_docs install-template → status reporting) executed end-to-end.

## Test Results **Suite:** `cargo test -p hero_books_server --lib` **Total:** 17 — Passed: 17 — Failed: 0 New test added with this change: - `web::rpc::tests::test_docs_install_template_missing_params` — covers missing `path`, empty `path`, and missing `params` object. All assertions pass. Existing `docs.*` validation tests still green (`test_docs_new_missing_params`, `test_docs_generate_missing_params`, `test_docs_generate_invalid_book_id`, `test_docs_job_status_rejects_non_numeric_id`). ### Spec/impl parity INSTRUCTIONS_OPENRPC.md §Verification diff command produces empty output — `openrpc.json` and the dispatcher in `rpc.rs` agree, with `docs.installTemplate` listed in both. ### Build - `cargo check -p hero_books_server` — OK - `cargo check --bin hero_docs` — OK ### CLI smoke test ``` $ hero_docs install-template --help Install the Docusaurus template at a build directory Usage: hero_docs install-template [OPTIONS] --path <PATH> Options: --path <PATH> Path to the Docusaurus build directory where the template is installed --reset Reset the build directory before installing (recreates from scratch) -h, --help Print help ``` ### Live end-to-end RPC test (against running hero_books_server + hero_proc) | Step | Result | | --- | --- | | `rpc.discover` lists `docs.installTemplate` with correct params/result schema | pass | | Validation: missing `path` returns `-32602 "missing or empty 'path' parameter"` | pass | | Submit returns `{"job_id":"76"}` | pass | | Re-submit with same params dedupes to the same `job_id: "76"` | pass | | Job dispatched to `hero_proc` and ran `hero_docs install-template ...` | pass | | Failure tail surfaces correctly via `docs.jobStatus` | pass | | No `output_path` field on the response (per design — input path not recoverable from hash) | pass | The single live failure was an environment issue (`bun is not installed`) inside `template::install_template`, which `docs.new` / `docs.generate` already exercise — not a defect introduced by this change. The full RPC chain (dispatch → handler → hero_proc → `hero_docs install-template` → status reporting) executed end-to-end.
Member

Implementation Summary

docs.installTemplate is now exposed over JSON-RPC. The handler shells out via hero_proc to a new hero_docs install-template subcommand, mirroring the async/dedup pattern of docs.new and docs.generate.

Files changed

  • src/bin/hero_docs.rs — new InstallTemplate(InstallTemplateArgs) subcommand, wired into main().
  • crates/hero_books_server/src/web/rpc.rs
    • handle_docs_install_template handler (-32602 for invalid params, dedup key docs_install_template_<input_hash>).
    • Dispatch arm "docs.installTemplate" between docs.generate and docs.jobStatus.
    • handle_docs_job_status updated with a comment block documenting why no output_path is synthesised for docs_install_template_* jobs (user-supplied path is not recoverable from the input hash).
    • New ## Docs section in the file-level doc-comment header listing docs.new, docs.generate, docs.installTemplate, docs.jobStatus.
    • New unit test test_docs_install_template_missing_params covering missing path, empty path, and missing params object.
  • crates/hero_books_server/src/web/rpc_spec.rs — inline schema (used by rpc.discover) updated with the same docs.installTemplate entry.
  • crates/hero_books_server/openrpc.json — new method entry; info.version bumped 0.1.5 -> 0.1.6.
  • crates/hero_books_server/openrpc.client.generated.rs — auto-regenerated by the openrpc_client! macro to reflect the new method.

Test results

  • 17/17 lib tests pass (one new).
  • Verification diff (spec ↔ dispatcher) is empty.
  • Live RPC test against running hero_books_server/hero_proc confirmed: discovery, validation, submission, idempotent dedup, hero_proc dispatch, error-tail surfacing through docs.jobStatus. The bun runtime not being installed produced a failed state from template::install_template, which is shared infrastructure exercised by the existing docs.* methods and out of scope for #102.

Notes

  • Path semantics: path is the Docusaurus build directory — passed straight to template::install_template(&Path, bool). No heroscript loading. Same convention as docs.new's --path.
  • info.version will continue bumping in the sibling PRs for #103-#107.
## Implementation Summary `docs.installTemplate` is now exposed over JSON-RPC. The handler shells out via `hero_proc` to a new `hero_docs install-template` subcommand, mirroring the async/dedup pattern of `docs.new` and `docs.generate`. ### Files changed - `src/bin/hero_docs.rs` — new `InstallTemplate(InstallTemplateArgs)` subcommand, wired into `main()`. - `crates/hero_books_server/src/web/rpc.rs` - `handle_docs_install_template` handler (`-32602` for invalid params, dedup key `docs_install_template_<input_hash>`). - Dispatch arm `"docs.installTemplate"` between `docs.generate` and `docs.jobStatus`. - `handle_docs_job_status` updated with a comment block documenting why no `output_path` is synthesised for `docs_install_template_*` jobs (user-supplied `path` is not recoverable from the input hash). - New `## Docs` section in the file-level doc-comment header listing `docs.new`, `docs.generate`, `docs.installTemplate`, `docs.jobStatus`. - New unit test `test_docs_install_template_missing_params` covering missing `path`, empty `path`, and missing `params` object. - `crates/hero_books_server/src/web/rpc_spec.rs` — inline schema (used by `rpc.discover`) updated with the same `docs.installTemplate` entry. - `crates/hero_books_server/openrpc.json` — new method entry; `info.version` bumped `0.1.5 -> 0.1.6`. - `crates/hero_books_server/openrpc.client.generated.rs` — auto-regenerated by the `openrpc_client!` macro to reflect the new method. ### Test results - 17/17 lib tests pass (one new). - Verification diff (spec ↔ dispatcher) is empty. - Live RPC test against running `hero_books_server`/`hero_proc` confirmed: discovery, validation, submission, idempotent dedup, hero_proc dispatch, error-tail surfacing through `docs.jobStatus`. The `bun` runtime not being installed produced a `failed` state from `template::install_template`, which is shared infrastructure exercised by the existing `docs.*` methods and out of scope for #102. ### Notes - Path semantics: `path` is the Docusaurus *build directory* — passed straight to `template::install_template(&Path, bool)`. No heroscript loading. Same convention as `docs.new`'s `--path`. - `info.version` will continue bumping in the sibling PRs for #103-#107.
Member

Pull request opened: #108

This PR implements the changes discussed in this issue. It is the rolling PR covering all six child issues of #101 — the next iteration will add #103 (docs.updateTemplate).

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_books/pulls/108 This PR implements the changes discussed in this issue. It is the rolling PR covering all six child issues of #101 — the next iteration will add #103 (`docs.updateTemplate`).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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_books#102
No description provided.