From 15f1fb352d02503063e19b3b628a8868078d9cc5 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 14:06:37 +0800 Subject: [PATCH 01/10] fix(identity): reorder payment QR instructions --- genmeta-identity/src/checkout.rs | 64 +++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/genmeta-identity/src/checkout.rs b/genmeta-identity/src/checkout.rs index 6115ee9..aa846ee 100644 --- a/genmeta-identity/src/checkout.rs +++ b/genmeta-identity/src/checkout.rs @@ -61,12 +61,18 @@ fn render_terminal_qr(url: &str) -> Result { } pub(crate) fn payment_instruction_block(url: &str) -> Result { - let mut block = render_terminal_qr(url)?.trim_end().to_string(); - block.push_str("\n\n"); + let qr = render_terminal_qr(url)?; + let mut block = String::from( + "[!] Please complete your payment within 15 minutes.\n Open the link, or scan the QR code below\n\n", + ); + + for line in qr.trim_end().lines() { + block.push_str(" "); + block.push_str(line); + block.push('\n'); + } - block.push_str("[!] Please complete your payment within 15 minutes.\n"); - block.push_str(" Open the link below, or scan the QR code above\n\n"); - block.push_str(" Link: "); + block.push_str("\n Link: "); block.push_str(url); Ok(block) } @@ -185,29 +191,43 @@ mod tests { } #[test] - fn payment_block_always_keeps_the_qr_above_the_link() { - let block = payment_instruction_block("https://pay.example.test/checkout/ckt_123").unwrap(); - - assert!(block.contains(['▀', '▄', '█'])); - assert!(block.contains( - "Open the link below, or scan the QR code above\n\n Link: https://pay.example.test/checkout/ckt_123" - )); - } - - #[test] - fn payment_block_places_compact_qr_before_the_link() { - let rendered = payment_instruction_block("https://pay.example.test/checkout").unwrap(); - let qr = rendered.find('█').unwrap(); + fn payment_block_keeps_instruction_qr_and_link_in_order() { + let rendered = + payment_instruction_block("https://pay.example.test/checkout/ckt_123").unwrap(); let notice = rendered .find("[!] Please complete your payment within 15 minutes.") .unwrap(); + let instruction = rendered + .find("Open the link, or scan the QR code below") + .unwrap(); + let qr = rendered.find('█').unwrap(); let link = rendered - .find("Link: https://pay.example.test/checkout") + .find("Link: https://pay.example.test/checkout/ckt_123") .unwrap(); - assert!(qr < notice && notice < link, "{rendered}"); - assert!(rendered.contains("Open the link below, or scan the QR code above")); - assert!(!rendered.contains("Open link:")); + assert!( + notice < instruction && instruction < qr && qr < link, + "{rendered}" + ); + assert!(!rendered.contains("Open the link below, or scan the QR code above")); + } + + #[test] + fn payment_block_indents_every_qr_row_by_four_spaces() { + let rendered = payment_instruction_block("https://pay.example.test/checkout").unwrap(); + let qr = rendered + .split_once("Open the link, or scan the QR code below\n\n") + .unwrap() + .1 + .split_once("\n\n Link: https://pay.example.test/checkout") + .unwrap() + .0; + + assert!(!qr.is_empty()); + assert!( + qr.lines().all(|line| line.starts_with(" ")), + "{rendered}" + ); } #[test] From 81e11cd75b39dd5ae04dfe4ffc806365a0a70218 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 17:28:09 +0800 Subject: [PATCH 02/10] fix(identity): retain completion milestones --- genmeta-identity/src/cli/flow/progress.rs | 116 ++++++++++++---------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/genmeta-identity/src/cli/flow/progress.rs b/genmeta-identity/src/cli/flow/progress.rs index 48b603f..53f9f0b 100644 --- a/genmeta-identity/src/cli/flow/progress.rs +++ b/genmeta-identity/src/cli/flow/progress.rs @@ -9,7 +9,7 @@ use tracing_indicatif::span_ext::IndicatifSpanExt; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum CompletionPolicy { Clear, - RetainOnTty, + Retain, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -28,42 +28,56 @@ impl ProgressCopy { } } - const fn retain_on_tty(running: &'static str, success: &'static str) -> Self { + const fn retain(running: &'static str, success: &'static str) -> Self { Self { running, success, - completion: CompletionPolicy::RetainOnTty, + completion: CompletionPolicy::Retain, } } - fn completion_message(self, is_terminal: bool) -> Option<&'static str> { - if !is_terminal { - return None; - } + fn completion_message(self, _is_terminal: bool) -> Option<&'static str> { match self.completion { CompletionPolicy::Clear => None, - CompletionPolicy::RetainOnTty => Some(self.success), + CompletionPolicy::Retain => Some(self.success), } } } +const KEY_GENERATED: &str = "✔ Generated secp384r1 ECC key pair locally."; +const CERTIFICATE_REQUESTED: &str = "✔ Generated CSR locally and requested certificate."; + pub(crate) const CHECK_NAME: ProgressCopy = ProgressCopy::clear("Checking the validity of this name..."); pub(crate) const SEND_CODE: ProgressCopy = ProgressCopy::clear("Sending verification code..."); pub(crate) const VERIFY_EMAIL: ProgressCopy = ProgressCopy::clear("Verifying with email..."); -pub(crate) const GENERATE_KEY: ProgressCopy = ProgressCopy::retain_on_tty( +pub(crate) const GENERATE_KEY: ProgressCopy = ProgressCopy::retain( "Generating secp384r1 ECC key pair locally...", - "Generated secp384r1 ECC key pair locally.", + KEY_GENERATED, ); -pub(crate) const REQUEST_CERT: ProgressCopy = ProgressCopy::retain_on_tty( +pub(crate) const REQUEST_CERT: ProgressCopy = ProgressCopy::retain( "Generating CSR locally and requesting certificate...", - "Generated CSR locally and requested certificate.", + CERTIFICATE_REQUESTED, ); pub(crate) const WAIT_FOR_PAYMENT: ProgressCopy = ProgressCopy::clear("Waiting for payment completion..."); -pub(crate) const RENEW_IDENTITY: ProgressCopy = ProgressCopy::clear("Renewing identity..."); +pub(crate) const RENEW_IDENTITY: ProgressCopy = + ProgressCopy::retain("Renewing identity...", CERTIFICATE_REQUESTED); pub(crate) const SAVE_DEFAULT: ProgressCopy = ProgressCopy::clear("Saving default identity..."); +fn finish_success(span: &tracing::Span, copy: ProgressCopy) { + let is_terminal = io::stderr().is_terminal(); + let Some(success) = copy.completion_message(is_terminal) else { + return; + }; + + if is_terminal { + span.pb_set_finish_message(success); + } else { + super::transcript::print_line(success); + } +} + pub(crate) async fn run( copy: ProgressCopy, future: impl Future>, @@ -72,10 +86,8 @@ pub(crate) async fn run( span.pb_set_message(copy.running); span.pb_start(); let result = future.await; - if result.is_ok() - && let Some(success) = copy.completion_message(io::stderr().is_terminal()) - { - span.pb_set_finish_message(success); + if result.is_ok() { + finish_success(&span, copy); } drop(span); result @@ -89,10 +101,8 @@ pub(crate) fn run_sync( span.pb_set_message(copy.running); span.pb_start(); let result = operation(); - if result.is_ok() - && let Some(success) = copy.completion_message(io::stderr().is_terminal()) - { - span.pb_set_finish_message(success); + if result.is_ok() { + finish_success(&span, copy); } drop(span); result @@ -115,45 +125,45 @@ mod tests { }; #[test] - fn only_key_and_certificate_request_retain_success_on_tty() { - assert_eq!( - GENERATE_KEY.completion_message(true), - Some("Generated secp384r1 ECC key pair locally.") - ); + fn key_and_certificate_completions_are_stable_in_every_output_mode() { + for is_terminal in [true, false] { + assert_eq!( + GENERATE_KEY.completion_message(is_terminal), + Some("✔ Generated secp384r1 ECC key pair locally.") + ); + assert_eq!( + REQUEST_CERT.completion_message(is_terminal), + Some("✔ Generated CSR locally and requested certificate.") + ); + assert_eq!( + RENEW_IDENTITY.completion_message(is_terminal), + Some("✔ Generated CSR locally and requested certificate.") + ); + } + assert_eq!( REQUEST_CERT.running, "Generating CSR locally and requesting certificate..." ); - assert_eq!( - REQUEST_CERT.completion_message(true), - Some("Generated CSR locally and requested certificate.") - ); - - for copy in [ - CHECK_NAME, - SEND_CODE, - VERIFY_EMAIL, - WAIT_FOR_PAYMENT, - RENEW_IDENTITY, - SAVE_DEFAULT, - ] { - assert_eq!(copy.completion_message(true), None, "copy: {copy:?}"); - } + assert_eq!(RENEW_IDENTITY.running, "Renewing identity..."); } #[test] - fn non_tty_progress_has_no_completion_copy() { - for copy in [ - CHECK_NAME, - SEND_CODE, - VERIFY_EMAIL, - GENERATE_KEY, - REQUEST_CERT, - WAIT_FOR_PAYMENT, - RENEW_IDENTITY, - SAVE_DEFAULT, - ] { - assert_eq!(copy.completion_message(false), None, "copy: {copy:?}"); + fn transient_progress_has_no_completion_copy() { + for is_terminal in [true, false] { + for copy in [ + CHECK_NAME, + SEND_CODE, + VERIFY_EMAIL, + WAIT_FOR_PAYMENT, + SAVE_DEFAULT, + ] { + assert_eq!( + copy.completion_message(is_terminal), + None, + "copy: {copy:?}, terminal: {is_terminal}" + ); + } } } From 93c0fe6fdc27822bb46342a8f50416737529a13a Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 17:28:38 +0800 Subject: [PATCH 03/10] fix(identity): mark committed identity results --- genmeta-identity/src/cli/flow/apply.rs | 7 +++++-- genmeta-identity/src/cli/flow/renew.rs | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/genmeta-identity/src/cli/flow/apply.rs b/genmeta-identity/src/cli/flow/apply.rs index 9b56549..365be69 100644 --- a/genmeta-identity/src/cli/flow/apply.rs +++ b/genmeta-identity/src/cli/flow/apply.rs @@ -18,7 +18,7 @@ use crate::{ }; const APPLY_OPENING: &str = "Applying identity, generating ECC key pair locally, then requesting and deploying certificate."; -const INSTALLED: &str = "Identity successfully installed on this device."; +const INSTALLED: &str = "✔ Identity successfully installed on this device."; const NEW_NAME_FREE: &str = "This new name is yours now."; fn interactive_name_unavailable_message() -> &'static str { @@ -635,7 +635,10 @@ mod tests { "Applying identity, generating ECC key pair locally, then requesting and deploying certificate." ); assert_eq!(NEW_NAME_FREE, "This new name is yours now."); - assert_eq!(INSTALLED, "Identity successfully installed on this device."); + assert_eq!( + INSTALLED, + "✔ Identity successfully installed on this device." + ); } #[test] diff --git a/genmeta-identity/src/cli/flow/renew.rs b/genmeta-identity/src/cli/flow/renew.rs index 7cddf06..274fc62 100644 --- a/genmeta-identity/src/cli/flow/renew.rs +++ b/genmeta-identity/src/cli/flow/renew.rs @@ -12,7 +12,7 @@ use crate::{ cli::{Error, Renew}, }; -const RENEWED: &str = "Identity successfully renewed on this device."; +const RENEWED: &str = "✔ Identity successfully renewed on this device."; fn renew_not_saved_root_message(short_name: &str) -> String { format!("Failed to renew: {short_name} not found!") @@ -468,7 +468,7 @@ mod tests { fn renewed_success_copy_is_visible_and_stable() { assert_eq!( super::RENEWED, - "Identity successfully renewed on this device." + "✔ Identity successfully renewed on this device." ); } } From 2cf07585367da8105710d1fdd618f8a1ce351283 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 17:29:14 +0800 Subject: [PATCH 04/10] fix(identity): mount welcome page at welcome --- genmeta-identity/src/cli/flow/welcome.rs | 33 +++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/genmeta-identity/src/cli/flow/welcome.rs b/genmeta-identity/src/cli/flow/welcome.rs index 3f72329..2f297e8 100644 --- a/genmeta-identity/src/cli/flow/welcome.rs +++ b/genmeta-identity/src/cli/flow/welcome.rs @@ -53,8 +53,8 @@ pub enum WelcomeServiceError { const SERVER_CONF_TEMPLATE: &str = "server { listen all 0; - location / { - root templates/welcome; + location /welcome { + root templates; index index.html; } } @@ -115,9 +115,7 @@ pub(crate) async fn maybe_create_welcome_service( } pub(crate) fn format_welcome_service_created(name: &str) -> String { - format!( - "A sample welcome page has been created. After starting the service, access it with `genmeta curl https://{name}/`." - ) + format!("`genmeta curl https://{name}~/welcome`") } fn render_welcome_page() -> &'static str { @@ -256,7 +254,9 @@ mod tests { use dhttp::{home::DhttpHome, name::DhttpName}; - use super::{format_welcome_service_created, maybe_create_welcome_service}; + use super::{ + SERVER_CONF_TEMPLATE, format_welcome_service_created, maybe_create_welcome_service, + }; use crate::cli::flow::local::IdentityUsage; fn unique_test_home_path(label: &str) -> PathBuf { @@ -323,10 +323,10 @@ mod tests { let server_conf = tokio::fs::read_to_string(&created.server_conf_path) .await .unwrap(); - assert!( - server_conf.contains("root templates/welcome;"), - "{server_conf}" - ); + assert!(server_conf.contains("location /welcome {"), "{server_conf}"); + assert!(server_conf.contains("root templates;"), "{server_conf}"); + assert!(!server_conf.contains("location / {"), "{server_conf}"); + assert!(!server_conf.contains("root templates/welcome;"), "{server_conf}"); let welcome_page = tokio::fs::read_to_string(&created.welcome_page_path) .await @@ -438,10 +438,19 @@ mod tests { } #[test] - fn welcome_success_copy_is_one_line() { + fn welcome_service_is_mounted_at_welcome() { + assert!(SERVER_CONF_TEMPLATE.contains("location /welcome {")); + assert!(SERVER_CONF_TEMPLATE.contains("root templates;")); + assert!(SERVER_CONF_TEMPLATE.contains("index index.html;")); + assert!(!SERVER_CONF_TEMPLATE.contains("location / {")); + assert!(!SERVER_CONF_TEMPLATE.contains("root templates/welcome;")); + } + + #[test] + fn welcome_success_copy_is_only_the_copyable_command() { assert_eq!( format_welcome_service_created("alice.smith"), - "A sample welcome page has been created. After starting the service, access it with `genmeta curl https://alice.smith/`." + "`genmeta curl https://alice.smith~/welcome`" ); } } From dc4b5a900a07860cd341d4b5baa94515f260cc4f Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 17:54:35 +0800 Subject: [PATCH 05/10] fix(identity): defer welcome output until after default --- genmeta-identity/src/cli/flow/apply.rs | 13 ++++++++----- genmeta-identity/src/cli/flow/welcome.rs | 5 ++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/genmeta-identity/src/cli/flow/apply.rs b/genmeta-identity/src/cli/flow/apply.rs index 365be69..8d15208 100644 --- a/genmeta-identity/src/cli/flow/apply.rs +++ b/genmeta-identity/src/cli/flow/apply.rs @@ -505,13 +505,17 @@ async fn install_and_finish( IdentityKind::Primary => super::local::IdentityUsage::BothClientAndServer, IdentityKind::Secondary => super::local::IdentityUsage::ClientOnly, }; - match super::welcome::maybe_create_welcome_service( + let welcome = super::welcome::maybe_create_welcome_service( dhttp_home, resolved.target.dhttp_name(), usage, ) - .await - { + .await; + + super::epilogue::run_lifecycle_epilogue(dhttp_home, resolved.target.dhttp_name(), interactive) + .await?; + + match welcome { Ok(Some(_)) => super::transcript::print_line( super::welcome::format_welcome_service_created(resolved.target.short_name()), ), @@ -520,8 +524,7 @@ async fn install_and_finish( "The identity was installed, but the sample welcome page could not be created: {error}" )), } - super::epilogue::run_lifecycle_epilogue(dhttp_home, resolved.target.dhttp_name(), interactive) - .await + Ok(()) } pub(crate) async fn run( diff --git a/genmeta-identity/src/cli/flow/welcome.rs b/genmeta-identity/src/cli/flow/welcome.rs index 2f297e8..c765aa0 100644 --- a/genmeta-identity/src/cli/flow/welcome.rs +++ b/genmeta-identity/src/cli/flow/welcome.rs @@ -326,7 +326,10 @@ mod tests { assert!(server_conf.contains("location /welcome {"), "{server_conf}"); assert!(server_conf.contains("root templates;"), "{server_conf}"); assert!(!server_conf.contains("location / {"), "{server_conf}"); - assert!(!server_conf.contains("root templates/welcome;"), "{server_conf}"); + assert!( + !server_conf.contains("root templates/welcome;"), + "{server_conf}" + ); let welcome_page = tokio::fs::read_to_string(&created.welcome_page_path) .await From 9c945bf8a223eb9a8461d08bc4095146c4f7e83c Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 17:54:40 +0800 Subject: [PATCH 06/10] docs(identity): record completion transcript changes --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3dede4..2fddd3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Identity apply and renew retain checkmarked local key generation, CSR request, + and committed installation or renewal milestones. Non-interactive execution + emits the same successful milestones without progress animation. New welcome + services are mounted at `/welcome`, and onboarding leaves one copyable access + command after the default-identity prompt without reload instructions. + ## [0.8.0-beta.5] - 2026-07-17 ### Changed From 9251938c5d4d42c9652c204fb2c69bf958d33c23 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 20:44:43 +0800 Subject: [PATCH 07/10] fix(identity): clarify completion and welcome copy --- CHANGELOG.md | 5 +++-- genmeta-identity/src/cli/flow/apply.rs | 4 ++-- genmeta-identity/src/cli/flow/progress.rs | 10 +++++----- genmeta-identity/src/cli/flow/welcome.rs | 10 +++++++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fddd3a..72c59f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Identity apply and renew retain checkmarked local key generation, CSR request, and committed installation or renewal milestones. Non-interactive execution emits the same successful milestones without progress animation. New welcome - services are mounted at `/welcome`, and onboarding leaves one copyable access - command after the default-identity prompt without reload instructions. + services are mounted at `/welcome`, and onboarding follows the default-identity + prompt with a brief reload reminder and one copyable access command, without + printing a concrete service-management command. ## [0.8.0-beta.5] - 2026-07-17 diff --git a/genmeta-identity/src/cli/flow/apply.rs b/genmeta-identity/src/cli/flow/apply.rs index 8d15208..a8947b7 100644 --- a/genmeta-identity/src/cli/flow/apply.rs +++ b/genmeta-identity/src/cli/flow/apply.rs @@ -516,8 +516,8 @@ async fn install_and_finish( .await?; match welcome { - Ok(Some(_)) => super::transcript::print_line( - super::welcome::format_welcome_service_created(resolved.target.short_name()), + Ok(Some(_)) => super::transcript::print_block( + &super::welcome::format_welcome_service_created(resolved.target.short_name()), ), Ok(None) => {} Err(error) => super::transcript::print_warning(&format!( diff --git a/genmeta-identity/src/cli/flow/progress.rs b/genmeta-identity/src/cli/flow/progress.rs index 53f9f0b..5b0d509 100644 --- a/genmeta-identity/src/cli/flow/progress.rs +++ b/genmeta-identity/src/cli/flow/progress.rs @@ -44,8 +44,8 @@ impl ProgressCopy { } } -const KEY_GENERATED: &str = "✔ Generated secp384r1 ECC key pair locally."; -const CERTIFICATE_REQUESTED: &str = "✔ Generated CSR locally and requested certificate."; +const KEY_GENERATED: &str = "✔ Generate secp384r1 ECC key pair locally."; +const CERTIFICATE_REQUESTED: &str = "✔ Generate CSR locally and request certificate."; pub(crate) const CHECK_NAME: ProgressCopy = ProgressCopy::clear("Checking the validity of this name..."); @@ -129,15 +129,15 @@ mod tests { for is_terminal in [true, false] { assert_eq!( GENERATE_KEY.completion_message(is_terminal), - Some("✔ Generated secp384r1 ECC key pair locally.") + Some("✔ Generate secp384r1 ECC key pair locally.") ); assert_eq!( REQUEST_CERT.completion_message(is_terminal), - Some("✔ Generated CSR locally and requested certificate.") + Some("✔ Generate CSR locally and request certificate.") ); assert_eq!( RENEW_IDENTITY.completion_message(is_terminal), - Some("✔ Generated CSR locally and requested certificate.") + Some("✔ Generate CSR locally and request certificate.") ); } diff --git a/genmeta-identity/src/cli/flow/welcome.rs b/genmeta-identity/src/cli/flow/welcome.rs index c765aa0..07c695c 100644 --- a/genmeta-identity/src/cli/flow/welcome.rs +++ b/genmeta-identity/src/cli/flow/welcome.rs @@ -115,7 +115,10 @@ pub(crate) async fn maybe_create_welcome_service( } pub(crate) fn format_welcome_service_created(name: &str) -> String { - format!("`genmeta curl https://{name}~/welcome`") + format!( + "A sample welcome page has been generated. Reload pishoo, then visit it with:\n\ +`genmeta curl https://{name}~/welcome`" + ) } fn render_welcome_page() -> &'static str { @@ -450,10 +453,11 @@ mod tests { } #[test] - fn welcome_success_copy_is_only_the_copyable_command() { + fn welcome_success_copy_introduces_the_sample_and_copyable_command() { assert_eq!( format_welcome_service_created("alice.smith"), - "`genmeta curl https://alice.smith~/welcome`" + "A sample welcome page has been generated. Reload pishoo, then visit it with:\n\ +`genmeta curl https://alice.smith~/welcome`" ); } } From b080295861c1889ef61142ca473b34590478cfc5 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 21:03:58 +0800 Subject: [PATCH 08/10] fix(identity): print platform reload guidance --- CHANGELOG.md | 5 +++-- genmeta-identity/src/cli/flow/welcome.rs | 26 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72c59f9..3f4f977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 and committed installation or renewal milestones. Non-interactive execution emits the same successful milestones without progress animation. New welcome services are mounted at `/welcome`, and onboarding follows the default-identity - prompt with a brief reload reminder and one copyable access command, without - printing a concrete service-management command. + prompt with the platform reload command (`sudo brew service reload pishoo` on + macOS or `sudo systemctl reload pishoo` elsewhere) and a copyable access command + containing the newly created identity. ## [0.8.0-beta.5] - 2026-07-17 diff --git a/genmeta-identity/src/cli/flow/welcome.rs b/genmeta-identity/src/cli/flow/welcome.rs index 07c695c..5675863 100644 --- a/genmeta-identity/src/cli/flow/welcome.rs +++ b/genmeta-identity/src/cli/flow/welcome.rs @@ -62,6 +62,12 @@ const SERVER_CONF_TEMPLATE: &str = "server { const WELCOME_PAGE_PATH: &str = "templates/welcome/index.html"; +#[cfg(target_os = "macos")] +const PISHOO_RELOAD_COMMAND: &str = "sudo brew service reload pishoo"; + +#[cfg(not(target_os = "macos"))] +const PISHOO_RELOAD_COMMAND: &str = "sudo systemctl reload pishoo"; + pub(crate) async fn maybe_create_welcome_service( dhttp_home: &DhttpHome, name: DhttpName<'_>, @@ -116,7 +122,8 @@ pub(crate) async fn maybe_create_welcome_service( pub(crate) fn format_welcome_service_created(name: &str) -> String { format!( - "A sample welcome page has been generated. Reload pishoo, then visit it with:\n\ + "Now, you can reload pishoo and visit the welcome page!\n\n\ +`{PISHOO_RELOAD_COMMAND}`\n\ `genmeta curl https://{name}~/welcome`" ) } @@ -452,11 +459,24 @@ mod tests { assert!(!SERVER_CONF_TEMPLATE.contains("root templates/welcome;")); } + #[cfg(not(target_os = "macos"))] + #[test] + fn welcome_success_copy_includes_systemd_reload_and_created_identity() { + assert_eq!( + format_welcome_service_created("alice.smith"), + "Now, you can reload pishoo and visit the welcome page!\n\n\ +`sudo systemctl reload pishoo`\n\ +`genmeta curl https://alice.smith~/welcome`" + ); + } + + #[cfg(target_os = "macos")] #[test] - fn welcome_success_copy_introduces_the_sample_and_copyable_command() { + fn welcome_success_copy_includes_brew_reload_and_created_identity() { assert_eq!( format_welcome_service_created("alice.smith"), - "A sample welcome page has been generated. Reload pishoo, then visit it with:\n\ + "Now, you can reload pishoo and visit the welcome page!\n\n\ +`sudo brew service reload pishoo`\n\ `genmeta curl https://alice.smith~/welcome`" ); } From 32f1301e681c330f81a4c48d38f690190a0c033c Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 21:20:19 +0800 Subject: [PATCH 09/10] fix(identity): compact welcome reload guidance --- CHANGELOG.md | 7 ++++--- genmeta-identity/src/cli/flow/welcome.rs | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f4f977..fb951a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 and committed installation or renewal milestones. Non-interactive execution emits the same successful milestones without progress animation. New welcome services are mounted at `/welcome`, and onboarding follows the default-identity - prompt with the platform reload command (`sudo brew service reload pishoo` on - macOS or `sudo systemctl reload pishoo` elsewhere) and a copyable access command - containing the newly created identity. + prompt immediately, without blank separator lines. It prints the platform + reload command (`sudo brew service reload pishoo` on macOS or `sudo systemctl + reload pishoo` elsewhere) and the copyable access command for the newly created + identity with four spaces of indentation. ## [0.8.0-beta.5] - 2026-07-17 diff --git a/genmeta-identity/src/cli/flow/welcome.rs b/genmeta-identity/src/cli/flow/welcome.rs index 5675863..828c07f 100644 --- a/genmeta-identity/src/cli/flow/welcome.rs +++ b/genmeta-identity/src/cli/flow/welcome.rs @@ -122,9 +122,7 @@ pub(crate) async fn maybe_create_welcome_service( pub(crate) fn format_welcome_service_created(name: &str) -> String { format!( - "Now, you can reload pishoo and visit the welcome page!\n\n\ -`{PISHOO_RELOAD_COMMAND}`\n\ -`genmeta curl https://{name}~/welcome`" + "Now, you can reload pishoo and visit the welcome page!\n `{PISHOO_RELOAD_COMMAND}`\n `genmeta curl https://{name}~/welcome`" ) } @@ -464,9 +462,11 @@ mod tests { fn welcome_success_copy_includes_systemd_reload_and_created_identity() { assert_eq!( format_welcome_service_created("alice.smith"), - "Now, you can reload pishoo and visit the welcome page!\n\n\ -`sudo systemctl reload pishoo`\n\ -`genmeta curl https://alice.smith~/welcome`" + concat!( + "Now, you can reload pishoo and visit the welcome page!\n", + " `sudo systemctl reload pishoo`\n", + " `genmeta curl https://alice.smith~/welcome`", + ) ); } @@ -475,9 +475,11 @@ mod tests { fn welcome_success_copy_includes_brew_reload_and_created_identity() { assert_eq!( format_welcome_service_created("alice.smith"), - "Now, you can reload pishoo and visit the welcome page!\n\n\ -`sudo brew service reload pishoo`\n\ -`genmeta curl https://alice.smith~/welcome`" + concat!( + "Now, you can reload pishoo and visit the welcome page!\n", + " `sudo brew service reload pishoo`\n", + " `genmeta curl https://alice.smith~/welcome`", + ) ); } } From 7b07585c3276e23a595ecbaa159e8fb83ad817b3 Mon Sep 17 00:00:00 2001 From: eareimu Date: Fri, 17 Jul 2026 20:20:50 +0800 Subject: [PATCH 10/10] chore: prepare genmeta v0.8.0-beta.6 --- CHANGELOG.md | 21 +++++++++++++++------ Cargo.lock | 4 ++-- Cargo.toml | 2 +- genmeta-identity/Cargo.toml | 2 +- genmeta/Cargo.toml | 2 +- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb951a6..8afcf14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.8.0-beta.6] - 2026-07-17 + ### Changed +- Paid identity checkout guidance puts the payment deadline and action before + the indented QR code and leaves the copyable payment link last. - Identity apply and renew retain checkmarked local key generation, CSR request, and committed installation or renewal milestones. Non-interactive execution - emits the same successful milestones without progress animation. New welcome - services are mounted at `/welcome`, and onboarding follows the default-identity - prompt immediately, without blank separator lines. It prints the platform - reload command (`sudo brew service reload pishoo` on macOS or `sudo systemctl - reload pishoo` elsewhere) and the copyable access command for the newly created - identity with four spaces of indentation. + emits the same successful milestones without progress animation. +- New welcome services are mounted at `/welcome`. Immediately after default + identity selection, onboarding prints a compact, consistently indented block + with the platform-specific pishoo reload command and the copyable `genmeta + curl` command for the new identity. + +### Components + +- `genmeta` v0.8.0-beta.6 +- `genmeta-identity` v0.4.0-beta.6 +- All other gmutils workspace member versions are unchanged from v0.8.0-beta.5. ## [0.8.0-beta.5] - 2026-07-17 diff --git a/Cargo.lock b/Cargo.lock index 63ada96..d4559ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "genmeta" -version = "0.8.0-beta.5" +version = "0.8.0-beta.6" dependencies = [ "clap", "genmeta-access", @@ -1677,7 +1677,7 @@ dependencies = [ [[package]] name = "genmeta-identity" -version = "0.4.0-beta.5" +version = "0.4.0-beta.6" dependencies = [ "base64", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 1d6459c..49813d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,7 +102,7 @@ dhttp = "0.6.0-beta.4" genmeta-curl = { path = "genmeta-curl", version = "0.7.0-beta.4" } genmeta-discover = { path = "genmeta-discover", version = "0.4.0-beta.3" } genmeta-doctor = { path = "genmeta-doctor", version = "0.4.0-beta.3" } -genmeta-identity = { path = "genmeta-identity", version = "0.4.0-beta.5", default-features = false } +genmeta-identity = { path = "genmeta-identity", version = "0.4.0-beta.6", default-features = false } genmeta-nat = { path = "genmeta-nat", version = "0.5.0-beta.3" } genmeta-nslookup = { path = "genmeta-nslookup", version = "0.5.0-beta.3" } genmeta-ssh = { path = "genmeta-ssh", version = "0.7.0-beta.4" } diff --git a/genmeta-identity/Cargo.toml b/genmeta-identity/Cargo.toml index 56651a1..4686bc8 100644 --- a/genmeta-identity/Cargo.toml +++ b/genmeta-identity/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "genmeta-identity" description = "managing identities for genmeta network" -version = "0.4.0-beta.5" +version = "0.4.0-beta.6" edition.workspace = true license.workspace = true repository.workspace = true diff --git a/genmeta/Cargo.toml b/genmeta/Cargo.toml index 450ed1a..71d9952 100644 --- a/genmeta/Cargo.toml +++ b/genmeta/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "genmeta" description = "Genmeta Binary Utilities" -version = "0.8.0-beta.5" +version = "0.8.0-beta.6" edition.workspace = true license.workspace = true repository.workspace = true