frame-cli 0.3.0

CLI for Frame — five intention-verbs over one application: frame new scaffolds it, frame run serves it, frame test proves it (real browser included), frame check verifies it statically, frame doctor walks the prerequisites
Documentation
//! The embedded scaffold templates and the placeholder renderer.

// Named project-Cargo.toml, not Cargo.toml: cargo package treats any
// subdirectory containing a file with that exact name as a nested package
// and silently excludes the whole directory from the publish tarball. The
// same law names project-gitignore: cargo package applies ignore rules to
// its own file list, so a literal `.gitignore` inside `templates/` would
// alter what ships in the frame-cli tarball.
pub const ROOT_CARGO: &str = include_str!("../../templates/project-Cargo.toml");
pub const ROOT_GITIGNORE: &str = include_str!("../../templates/project-gitignore");
pub const FRAME_TOML: &str = include_str!("../../templates/frame.toml");
pub const HOST_CARGO: &str = include_str!("../../templates/host-Cargo.toml");
pub const BUILD_RS: &str = include_str!("../../templates/build.rs");
pub const HOST_LIB: &str = include_str!("../../templates/host-lib.rs");
pub const HOST_MAIN: &str = include_str!("../../templates/host-main.rs");
pub const HOST_E2E: &str = include_str!("../../templates/host-e2e.rs");
pub const GLEAM_TOML: &str = include_str!("../../templates/gleam.toml");
pub const COMPONENT: &str = include_str!("../../templates/component.gleam");
pub const COMPONENT_FFI: &str = include_str!("../../templates/component_ffi.erl");
pub const COMPONENT_TEST: &str = include_str!("../../templates/component_test.gleam");
pub const README: &str = include_str!("../../templates/README.md");
pub const PAGE_PACKAGE_JSON: &str = include_str!("../../templates/page-package.json");
pub const PAGE_TSCONFIG: &str = include_str!("../../templates/page-tsconfig.json");
pub const PAGE_INDEX_HTML: &str = include_str!("../../templates/page-index.html");
pub const PAGE_STYLES_CSS: &str = include_str!("../../templates/page-styles.css");
pub const PAGE_CONFIG_TS: &str = include_str!("../../templates/page-config.ts");
pub const PAGE_APP_STATUS_TS: &str = include_str!("../../templates/page-app-status.ts");
pub const PAGE_CONNECTION_TS: &str = include_str!("../../templates/page-connection.ts");
pub const PAGE_MAIN_TS: &str = include_str!("../../templates/page-main.ts");
pub const PAGE_E2E_MJS: &str = include_str!("../../templates/page-e2e.mjs");

// The page modules PRE-COMPILED: byte-exact `tsc` output (typescript 5.8.3,
// the exact version the generated `page/package.json` pins) of the four
// `page-*.ts` template sources above, compiled with the shipped
// `page-tsconfig.json`. Emitting them into `page/dist` at scaffold time
// makes the servable root COMPLETE the moment `frame new` returns, so the
// first session — `frame new x && cd x && frame run` — boots a working page
// with no npm involvement at all. `tsc` never rewrites string content, so
// compiling the raw templates (placeholders intact) and rendering the
// compiled output is byte-identical to rendering the sources and compiling
// those; the scaffold acceptance gate proves that identity by comparing
// these emitted bytes against a real `npm run build` over the generated
// sources.
pub const PAGE_DIST_MAIN_JS: &str = include_str!("../../templates/page-dist-main.js");
pub const PAGE_DIST_CONFIG_JS: &str = include_str!("../../templates/page-dist-config.js");
pub const PAGE_DIST_APP_STATUS_JS: &str = include_str!("../../templates/page-dist-app-status.js");
pub const PAGE_DIST_CONNECTION_JS: &str = include_str!("../../templates/page-dist-connection.js");

// The SDK's own published browser artifact for the page's one runtime
// dependency, `@ablative/liminal`, embedded byte-exact so every scaffold
// carries it offline and the generated page needs no bundler: the import map
// in the generated `page/dist/index.html` resolves the bare specifier to
// this one file. It is a single self-contained ES module — the protocol
// WebAssembly core is inlined as base64 and instantiated with zero fetch,
// zero imports — exposed by the package as `exports["./browser"]`. It never
// passes through `render()`: vendored artifacts are byte-exact, never
// templated.
//
// Provenance (ONE chain — the CLI embeds the SDK's own artifact, never a
// bundle of its own): github.com/ablative-io/liminal @
// 829b3c30a9f27bab8aa31cbe21470e687c59937d (liminal main; the wasm-pack
// 0.13.1 → 0.15.0 toolchain-bump commit, @ablative/liminal 0.3.3),
// directory `sdks/liminal-ts`, `npm run build` → `dist/browser/liminal.js`,
// built with wasm-pack 0.15.0, 155,614 bytes, sha256
// cc35d872f5723e8a19c43cc21619c3ec2f9a97df294a824290a9690955b4d6b6 — this
// is the exact artifact `npm publish` will ship for 0.3.3, so the byte wall
// keeps the vendored copy identical to the registry build. The SDK's build
// is byte-deterministic and self-verifying (double-pass byte-identity,
// no-import/no-fetch walls enforced by its scripts/build-browser.mjs).
// Across the wasm-pack 0.13.1 → 0.15.0 toolchain bump the optimized wasm
// payload is byte-identical (liminal_protocol_wasm_bg.wasm, sha256
// 063886d95b2f614c8a49b41c6b7a6a839581746aa3dc5f482216d5e04c86b53d); the
// browser bundle's only content change from the prior vendored build (0.3.1,
// sha 4ad53d6aa628056fa1da4e86778431b430a495d9268d0d4e8f5561a82eec1356) is
// the embedded package-version banner (0.3.1 → 0.3.3), which is why the size
// is unchanged at 155,614.
pub const PAGE_VENDOR_LIMINAL_JS: &str = include_str!("../../templates/page-vendor-liminal.js");

/// Substitutes the scaffold placeholders into one template.
pub fn render(template: &str, name: &str, gleam_name: &str) -> String {
    template
        .replace("{{NAME}}", name)
        .replace("{{GLEAM_NAME}}", gleam_name)
}