Skip to content

feat(ergonomics): MVP — rich --version, error hints, in-help examples (#108)#156

Merged
EffortlessSteven merged 5 commits into
mainfrom
feat/108-ergonomics-mvp
Apr 21, 2026
Merged

feat(ergonomics): MVP — rich --version, error hints, in-help examples (#108)#156
EffortlessSteven merged 5 commits into
mainfrom
feat/108-ergonomics-mvp

Conversation

@EffortlessSteven

Copy link
Copy Markdown
Member

Summary

  • Rich shipper --version --verbose prints git SHA + build profile + rustc version so operators can audit exactly what binary they're running.
  • Preflight / publish / resume failures now attach actionable hints that point at the next recovery step instead of leaving users to guess.
  • plan, preflight, and publish subcommands gained in-help examples (clap long_about) so shipper <cmd> --help is self-sufficient.

Lands the Ergonomics competency MVP from issue #108. Scoped tight: no man pages, no demo workspace, no cargo-shipper alias — those can follow in separate PRs.

What changed

  • crates/shipper-cli/build.rs (new): stdlib-only build script that emits SHIPPER_GIT_SHA / SHIPPER_BUILD_PROFILE / SHIPPER_RUSTC_VERSION via cargo::rustc-env. Re-runs on .git/HEAD and .git/refs/heads changes. No vergen dep — deliberately keeping the supply chain small.
  • crates/shipper-cli/Cargo.toml: wires up the build script (build = "build.rs").
  • crates/shipper-cli/src/lib.rs: long --version formatter; long_about blocks with worked examples on the three most-used subcommands; hint-attaching error paths for preflight / publish / resume.
  • crates/shipper-cli/tests/{cli_snapshots,e2e_expanded}.rs and snapshot files: updated to cover the new help output, the rich version string, and the new error hints.

No behavior changes in shipper-core; this is a pure CLI-adapter layer change, exactly per the three-crate architecture from #95.

Test plan

  • cargo fmt --all -- --check clean
  • cargo clippy --workspace --all-targets --all-features -- -D warnings clean
  • cargo test -p shipper-cli — one pre-existing Windows cargo file-lock flake (preflight_command_finishability_proven); passes on rerun in isolation, unrelated to this PR
  • cargo test --workspace — same pre-existing Windows packaging flake (preflight_command_snapshot, "failed to rename .crate — os error 2"); passes on rerun in isolation. Documented in CLAUDE.md guidance.
  • Snapshots updated for: cli_snapshots__{plan,preflight,publish}_help, cli_snapshots__version_flag, e2e_expanded__help_{plan,preflight,publish}, e2e_expanded__preflight_{json_format_non_git,non_git_directory}, e2e_expanded__resume_{corrupted,empty,minimal_json,no,wrong_plan_id}_state_file, e2e_expanded__version_output

@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 29 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 18 minutes and 29 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb72a40a-3723-4a6d-99b9-c14c679dd173

📥 Commits

Reviewing files that changed from the base of the PR and between 49408e2 and 3099b21.

⛔ Files ignored due to path filters (45)
  • crates/shipper-cli/tests/snapshots/cli_snapshots__ci_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__clean_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__config_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__doctor_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__help_text.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__no_subcommand_error.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__plan_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__preflight_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__publish_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__resume_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__status_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__unknown_subcommand_error.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__version_flag.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__version_flag_verbose.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__error_missing_ci_subcommand.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__error_missing_config_subcommand.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__error_unknown_subcommand.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_ci.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_ci_github_actions.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_ci_gitlab.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_clean.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_completion.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_config.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_config_init.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_config_validate.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_doctor.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_fix_forward.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_inspect_events.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_inspect_receipt.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_plan.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_plan_yank.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_preflight.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_publish.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_resume.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_root.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_status.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_yank.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__preflight_json_format_non_git.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__preflight_non_git_directory.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_corrupted_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_empty_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_minimal_json_state.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_no_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_wrong_plan_id.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__version_output.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • crates/shipper-cli/Cargo.toml
  • crates/shipper-cli/build.rs
  • crates/shipper-cli/src/lib.rs
  • crates/shipper-cli/tests/cli_snapshots.rs
  • crates/shipper-cli/tests/e2e_expanded.rs

Walkthrough

Add build-time version metadata generation and a global --version flag to the shipper-cli package. A build script captures git SHA, build profile, and rustc version at compile-time, which the CLI's --version flag displays, with optional verbose output showing build details.

Changes

Cohort / File(s) Summary
Build Configuration
crates/shipper-cli/Cargo.toml, crates/shipper-cli/build.rs
Added build script that computes and emits git SHA, build profile, and rustc version as rustc-env variables (SHIPPER_GIT_SHA, SHIPPER_BUILD_PROFILE, SHIPPER_RUSTC_VERSION) with fallback handling for missing git or toolchain info.
CLI Implementation
crates/shipper-cli/src/lib.rs
Added global --version/-V flag with optional --verbose output for build metadata; made cmd field optional in Cli struct to handle missing subcommands; added error context helpers (preflight_failure_hint, publish_failure_hint, resume_failure_hint) for state-dir–specific failure messages.
Test Updates
crates/shipper-cli/tests/cli_snapshots.rs, crates/shipper-cli/tests/e2e_expanded.rs
Added version metadata redaction helpers to normalize build-specific lines (commit:, build:, rustc:) in snapshots; added tests for --version flag and --version --verbose output; updated snapshot assertions to handle new verbose version format.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A version command hops into view,
Build-time metadata shines through and through,
Git sha, rustc, and profile so neat,
Make our CLI version info complete!
The tests now redact and capture with care,
Our shipper-cli stands tall in the air! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: introducing rich --version output with build metadata, error hints, and in-help examples for the CLI ergonomics MVP.
Description check ✅ Passed The description thoroughly explains the three main changes (rich --version, error hints, in-help examples), references the issue number, lists all modified files, and provides a comprehensive test plan.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/108-ergonomics-mvp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the CLI by embedding build-time metadata (Git SHA, build profile, and rustc version) into a new long-form version output and significantly expanding the help documentation for the plan, preflight, and publish subcommands. It also introduces context-aware failure hints to guide users during errors. Review feedback highlights a potential issue with build script triggers in non-git environments, a configuration error in clap that causes --version to display the long version instead of remaining terse, and the duplication of test redaction logic across multiple files.

Comment thread crates/shipper-cli/build.rs Outdated
Comment on lines +23 to +24
println!("cargo:rerun-if-changed=../../.git/HEAD");
println!("cargo:rerun-if-changed=../../.git/refs/heads");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Emitting cargo:rerun-if-changed for non-existent files or directories causes Cargo to rerun the build script on every build. In environments where the .git directory is missing (e.g., when building from a source tarball or a crates.io package), these lines will trigger unnecessary rebuilds. It is recommended to check for the existence of the .git directory before printing these instructions.

Suggested change
println!("cargo:rerun-if-changed=../../.git/HEAD");
println!("cargo:rerun-if-changed=../../.git/refs/heads");
let git_dir = std::path::Path::new("../../.git");
if git_dir.exists() {
println!("cargo:rerun-if-changed=../../.git/HEAD");
println!("cargo:rerun-if-changed=../../.git/refs/heads");
}

Comment thread crates/shipper-cli/src/lib.rs Outdated
Comment on lines +47 to +68
/// `-V --verbose`). The plain `--version` stays terse ("shipper X.Y.Z")
/// so scripts parsing it don't need to adapt.
///
/// Format:
/// ```text
/// shipper 0.3.0
/// commit: abc1234
/// build: release
/// rustc: rustc 1.92.0 (... )
/// ```
const LONG_VERSION: &str = concat!(
env!("CARGO_PKG_VERSION"),
"\ncommit: ",
env!("SHIPPER_GIT_SHA"),
"\nbuild: ",
env!("SHIPPER_BUILD_PROFILE"),
"\nrustc: ",
env!("SHIPPER_RUSTC_VERSION"),
);

#[derive(Parser, Debug)]
#[command(name = "shipper", version)]
#[command(name = "shipper", version, long_version = LONG_VERSION)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a contradiction between the documentation and the implementation. The comments and PR description state that --version stays terse for script compatibility, but by assigning LONG_VERSION to long_version in the clap command definition, --version will now output the rich multi-line version. In clap, -V shows the short version while --version shows the long version. If the goal is to keep --version terse, LONG_VERSION should not be assigned to long_version.

Comment on lines +22 to 40
fn redact_version_metadata(s: &str) -> String {
let trailing_nl = s.ends_with('\n');
let joined = s
.lines()
.map(|line| {
if line.starts_with("commit: ") {
"commit: [GIT_SHA]".to_string()
} else if line.starts_with("build: ") {
"build: [PROFILE]".to_string()
} else if line.starts_with("rustc: ") {
"rustc: [RUSTC_VERSION]".to_string()
} else {
line.to_string()
}
})
.collect::<Vec<_>>()
.join("\n");
if trailing_nl { joined + "\n" } else { joined }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The redact_version_metadata function is duplicated here and in crates/shipper-cli/tests/e2e_expanded.rs. To improve maintainability and follow DRY principles, consider moving this shared logic to a common test utility module (e.g., tests/common/mod.rs).

References
  1. Code duplication should be avoided to improve maintainability and reduce the risk of inconsistent logic.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5cb5cbd569

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/shipper-cli/src/lib.rs Outdated

#[derive(Parser, Debug)]
#[command(name = "shipper", version)]
#[command(name = "shipper", version, long_version = LONG_VERSION)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep plain --version output single-line

Setting long_version = LONG_VERSION makes shipper --version print the multi-line metadata block unconditionally, so callers that consume the full output as a single version string now break. This also contradicts the nearby contract comment that plain --version should remain terse and only the verbose form should be rich, so the current wiring does not match the intended CLI compatibility behavior.

Useful? React with 👍 / 👎.

Comment thread crates/shipper-cli/build.rs Outdated
Comment on lines +23 to +24
println!("cargo:rerun-if-changed=../../.git/HEAD");
println!("cargo:rerun-if-changed=../../.git/refs/heads");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve git metadata paths dynamically in build script

The rerun triggers hardcode ../../.git/..., which only works when .git is a directory exactly two levels up; in git worktrees/submodules (where .git is a file) or different checkout layouts, these paths do not track ref updates. In those environments Cargo won’t rerun the build script when HEAD moves, so SHIPPER_GIT_SHA can stay stale across commits and the reported binary provenance becomes inaccurate.

Useful? React with 👍 / 👎.

@codecov

codecov Bot commented Apr 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@EffortlessSteven EffortlessSteven force-pushed the feat/108-ergonomics-mvp branch from 56f328a to 19f585e Compare April 21, 2026 12:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/shipper-cli/src/lib.rs`:
- Around line 708-709: The failure hints currently use opts.state_dir which may
be a relative path, causing hints to point at the wrong locations; update the
code that builds the hint (invoked around engine::run_preflight_in_place and
preflight_failure_hint) to resolve opts.state_dir against planned.workspace_root
(i.e., if state_dir is relative, join it with planned.workspace_root and
canonicalize/normalize) before passing it into preflight_failure_hint so
generated paths point at the real on-disk state (apply same change for other
call sites that pass opts.state_dir into failure-hint helpers).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c38cafdd-6840-4256-a433-2e2f3ff56eb9

📥 Commits

Reviewing files that changed from the base of the PR and between d5c2d82 and 49408e2.

⛔ Files ignored due to path filters (19)
  • crates/shipper-cli/tests/snapshots/cli_snapshots__help_text.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__no_subcommand_error.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__plan_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__preflight_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__publish_help.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__version_flag.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/cli_snapshots__version_flag_verbose.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_plan.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_preflight.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_publish.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__help_root.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__preflight_json_format_non_git.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__preflight_non_git_directory.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_corrupted_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_empty_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_minimal_json_state.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_no_state_file.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__resume_wrong_plan_id.snap is excluded by !**/*.snap
  • crates/shipper-cli/tests/snapshots/e2e_expanded__version_output.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • crates/shipper-cli/Cargo.toml
  • crates/shipper-cli/build.rs
  • crates/shipper-cli/src/lib.rs
  • crates/shipper-cli/tests/cli_snapshots.rs
  • crates/shipper-cli/tests/e2e_expanded.rs

Comment on lines +708 to +709
let rep = engine::run_preflight_in_place(&mut planned, &opts, &mut reporter)
.with_context(|| preflight_failure_hint(&opts.state_dir))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Resolve relative state-dir paths before rendering failure hints.

opts.state_dir can be relative, but the actual state files live under planned.workspace_root. With --manifest-path /tmp/ws/Cargo.toml, these hints can incorrectly point operators at ./.shipper/events.jsonl instead of /tmp/ws/.shipper/events.jsonl, undermining recovery after a failed publish/resume.

🛠️ Proposed fix
+fn resolve_state_dir(workspace_root: &Path, state_dir: &Path) -> PathBuf {
+    if state_dir.is_absolute() {
+        state_dir.to_path_buf()
+    } else {
+        workspace_root.join(state_dir)
+    }
+}
+
 fn preflight_failure_hint(state_dir: &Path) -> String {
     format!(
         "preflight failed — next steps:\n  \
         Commands::Preflight => {
+            let state_dir = resolve_state_dir(&planned.workspace_root, &opts.state_dir);
             let rep = engine::run_preflight_in_place(&mut planned, &opts, &mut reporter)
-                .with_context(|| preflight_failure_hint(&opts.state_dir))?;
+                .with_context(|| preflight_failure_hint(&state_dir))?;
             print_preflight(&rep, &cli.format);
         }
-                let receipt = engine::run_publish(&current_planned, &current_opts, &mut reporter)
-                    .with_context(|| publish_failure_hint(&current_opts.state_dir))?;
+                let state_dir =
+                    resolve_state_dir(&current_planned.workspace_root, &current_opts.state_dir);
+                let receipt = engine::run_publish(&current_planned, &current_opts, &mut reporter)
+                    .with_context(|| publish_failure_hint(&state_dir))?;
-                let receipt = engine::run_resume(&current_planned, &current_opts, &mut reporter)
-                    .with_context(|| resume_failure_hint(&current_opts.state_dir))?;
+                let state_dir =
+                    resolve_state_dir(&current_planned.workspace_root, &current_opts.state_dir);
+                let receipt = engine::run_resume(&current_planned, &current_opts, &mut reporter)
+                    .with_context(|| resume_failure_hint(&state_dir))?;

Also applies to: 745-746, 790-791, 1238-1281

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/shipper-cli/src/lib.rs` around lines 708 - 709, The failure hints
currently use opts.state_dir which may be a relative path, causing hints to
point at the wrong locations; update the code that builds the hint (invoked
around engine::run_preflight_in_place and preflight_failure_hint) to resolve
opts.state_dir against planned.workspace_root (i.e., if state_dir is relative,
join it with planned.workspace_root and canonicalize/normalize) before passing
it into preflight_failure_hint so generated paths point at the real on-disk
state (apply same change for other call sites that pass opts.state_dir into
failure-hint helpers).

… MVP)

Lands the Ergonomics competency MVP from the scout's plan: (1) a stdlib-only build.rs emits SHIPPER_GIT_SHA, SHIPPER_BUILD_PROFILE, and SHIPPER_RUSTC_VERSION so shipper --version --verbose prints a rich supply-chain-auditable identity; (2) preflight/publish/resume failure paths now attach actionable hints that point users at the next recovery step; (3) plan/preflight/publish subcommands gained clap long_about blocks with concrete copy-paste examples, surfaced directly in --help. Snapshots updated to match the new help and version output; no behavior changes in shipper-core.
@EffortlessSteven EffortlessSteven force-pushed the feat/108-ergonomics-mvp branch from 99b091f to 3099b21 Compare April 21, 2026 13:30
@EffortlessSteven EffortlessSteven merged commit bc2bb0d into main Apr 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant