fix(xtask): give mobile starters app-owned commands

Make app new --mobile write hemx-app with HEMX_APP_* release settings, app-scoped release output, and docs that name Workout only as the concrete starter flow instead of leaking Workout command identity.

req: ceremony/006
This commit is contained in:
slhx agent
2026-06-12 16:15:09 +02:00
parent 3f824a83f8
commit 79b4d1e167
2 changed files with 34 additions and 6 deletions
+32 -4
View File
@@ -91,7 +91,7 @@ fn run_app_new(operands: &[String]) -> ExitCode {
);
if mobile {
println!(
"next\tHEMX_WORKOUT_ORIGIN=https://app.example.com {}/hemx-workout mobile-release",
"next\tHEMX_APP_ORIGIN=https://app.example.com {}/hemx-app mobile-release",
destination.display()
);
}
@@ -217,9 +217,31 @@ fn create_app_scaffold(destination: &Path) -> std::io::Result<()> {
fn create_mobile_app_scaffold(destination: &Path) -> std::io::Result<()> {
// req: ceremony/006 req: examples/006
create_workout_app(destination)?;
fs::rename(
destination.join("hemx-workout"),
destination.join("hemx-app"),
)?;
for (from, to) in [
("hemx_workout_app", "hemx_app"),
("hemx-workout-app", "hemx-app"),
("workout-app", "hemx-app"),
("./hemx-workout", "./hemx-app"),
("hemx-workout", "hemx-app"),
("HEMX_WORKOUT_", "HEMX_APP_"),
("target/hemx-mobile/workout", "target/hemx-mobile/app"),
("com.hemx.workout", "com.hemx.app"),
("hemx Workout Copilot", "hemx App"),
(
"# Workout mobile external blockers",
"# hemx app mobile external blockers",
),
("workout-mobile", "app-mobile"),
] {
replace_in_tree(destination, from, to)?;
}
fs::write(
destination.join("MOBILE_STARTER.md"),
"# Mobile hemx starter\n\nThis starter is the phone-first Workout path exposed through `app new --mobile`: it has a real page/form/keyed partial/notice flow, typed host haptics/share calls returning through Rust handlers, app-owned command/event/projection recovery truth, and the same `hemx-workout mobile-release` / `hemx-workout mobile-verify` release-kit commands.\n\nIt deliberately does not add a hemx mobile framework, client store, signing secret owner, or store submission bot. req: ceremony/006 req: examples/006\n",
"# Mobile hemx starter\n\nThis starter is the phone-first path exposed through `app new --mobile`: it has a real page/form/keyed partial/notice flow, typed host haptics/share calls returning through Rust handlers, app-owned command/event/projection recovery truth, and app-owned `hemx-app mobile-release` / `hemx-app mobile-verify` release-kit commands.\n\nThe starter uses the Workout product flow as a concrete first app, but its command surface, crate name, binary name, release output, and environment variables are owned by the created app. It deliberately does not add a hemx mobile framework, client store, signing secret owner, or store submission bot. req: ceremony/006 req: examples/006\n",
)?;
Ok(())
}
@@ -1250,17 +1272,21 @@ mod tests {
create_mobile_app_scaffold(&destination).expect("create mobile app scaffold");
let mobile_readme =
fs::read_to_string(destination.join("MOBILE_STARTER.md")).expect("mobile docs");
let command = fs::read_to_string(destination.join("hemx-workout")).expect("command");
let command = fs::read_to_string(destination.join("hemx-app")).expect("command");
let lib_rs = fs::read_to_string(destination.join("src/lib.rs")).expect("lib rs");
let template =
fs::read_to_string(destination.join("templates/workout.heml")).expect("template");
assert!(mobile_readme.contains("phone-first Workout path"));
assert!(mobile_readme.contains("phone-first path"));
assert!(mobile_readme.contains("typed host haptics/share calls"));
assert!(mobile_readme.contains("command/event/projection recovery truth"));
assert!(mobile_readme.contains("app-owned `hemx-app mobile-release`"));
assert!(mobile_readme.contains("does not add a hemx mobile framework"));
assert!(command.contains("mobile-release"));
assert!(command.contains("mobile-verify"));
assert!(command.contains("HEMX_APP_ORIGIN"));
assert!(command.contains("target/hemx-mobile/app"));
assert!(!command.contains("HEMX_WORKOUT_"));
assert!(command.contains("app-owned command/event/projection records"));
assert!(command.contains("external_blockers"));
assert!(lib_rs.contains("HostCall::Share"));
@@ -1269,6 +1295,8 @@ mod tests {
assert!(template.contains("<form"));
assert!(template.contains("data-hemx-slot"));
assert!(destination.join("tests/e2e.rs").exists());
assert!(destination.join("hemx-app").exists());
assert!(!destination.join("hemx-workout").exists());
let _ = fs::remove_dir_all(&destination);
}