Skip to content

Commit a977740

Browse files
committed
Document V1 public contract
1 parent 543dcb8 commit a977740

6 files changed

Lines changed: 112 additions & 4 deletions

File tree

docs/cli.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ bun run src/index.ts add --cwd <project-directory> [options]
1919

2020
The npm package exposes `create-electrobun-stack` from the built `dist/index.mjs` file. Plain npm and npx execution require Node.js `>=20.19.0`; `bunx --bun create-electrobun-stack@latest` forces Bun to run the same bin. Use `npm install -g create-electrobun-stack` if you want the global command.
2121

22+
## V1 Public Contract
23+
24+
V1 supports two command shapes:
25+
26+
- `create-electrobun-stack <project-name> [options]`
27+
- `create-electrobun-stack add [options]`
28+
29+
The supported operational flags are `--dry-run`, `--yes`, `--cwd`, `--app-id`, `--install`, `--no-install`, `--git`, `--no-git`, `--list-templates`, `--version`, and `--help`.
30+
31+
The supported stack flags are the flags listed in the Stack Options and Electrobun Feature Options tables below. New flags may be added in minor releases, but V1-compatible generators should not silently change or remove these command shapes.
32+
33+
For V1, `minimal` is the canonical template. `standard` and `full` remain accepted aliases for compatibility and manifest identity, but they intentionally render the same file set as `minimal`.
34+
2235
## Commands
2336

2437
### Create

docs/options.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,34 @@ Some categories are intentionally narrow for V1:
1313
- `--database sqlite` and `--orm drizzle` are the only persistence stack with generated files because they map cleanly to Bun SQLite and local desktop storage.
1414
- `--template standard` and `--template full` are accepted compatibility aliases for the same V1 template source as `minimal`; they are not advertised as distinct stacks until their generated output differs and has release-gate coverage.
1515

16+
## V1 Option Depth Decisions
17+
18+
| Category | V1 decision |
19+
| --- | --- |
20+
| Template | `minimal` is canonical; `standard` and `full` are accepted aliases only. |
21+
| Frontend | Fixed to React for V1. Additional renderers are post-V1 work. |
22+
| Router | `tanstack-router`, `react-router`, and `none` are distinct supported choices. |
23+
| Query | `tanstack-query` and `none` are enough for V1. |
24+
| Styling | Tailwind CSS and plain CSS cover framework and no-framework styling. |
25+
| UI | shadcn config and `none` are supported; generated components are left to the app. |
26+
| Auth | `app-lock` is a local UI lock, not remote auth; deeper auth is post-V1 work. |
27+
| Database | SQLite is the V1 persistence target because it is local and Bun-native. |
28+
| ORM | Drizzle is the V1 ORM option; another ORM needs clear desktop value before inclusion. |
29+
| DB setup | Seed data and `none` are the V1 setup choices. |
30+
| Settings | JSON and database-backed settings are both supported through the same typed RPC surface. |
31+
| Package manager | Bun, npm, pnpm, and Yarn are supported for install/run command text. |
32+
| Testing | Bun tests and `none` are supported; desktop E2E testing is post-V1 work. |
33+
| Addons | Turborepo and `none` are supported. |
34+
| Examples | RPC example and `none` are supported; option-specific examples are post-V1 work. |
35+
| API | Electrobun RPC and static/no-RPC modes are supported. |
36+
| App menu | Native Edit menu and `none` are supported. |
37+
| Build env | `dev`, `canary`, and `stable` map directly to Electrobun build flags. |
38+
| Build targets | `current` and `all` map directly to Electrobun build flags. |
39+
| Navigation | Local-only navigation rules and `none` are supported. |
40+
| Native utils | File dialogs and `none` are supported. More utilities are post-V1 work. |
41+
| Window style | Native and hidden inset titlebar modes are supported. |
42+
| Runtime | Fixed to Bun for V1 because Electrobun runs the native process through Bun. |
43+
1644
## Core App
1745

1846
### `--template minimal|standard|full`

docs/v1-plan.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ The release is ready when:
3030

3131
Goal: decide what V1 promises and avoid accidental breaking changes after release.
3232

33+
Status: completed in the repo. Evidence lives in `docs/cli.md`, `docs/options.md`, `docs/manifest.md`, `docs/add-command.md`, `src/cli.ts`, `src/prompts.ts`, and `tests/cli.test.ts`.
34+
3335
- Freeze the V1 CLI command shape:
3436
- `create-electrobun-stack <project>`
3537
- `create-electrobun-stack add`
@@ -52,6 +54,8 @@ Exit criteria:
5254

5355
Goal: make the stack chooser feel complete before V1 without adding new categories or padding the CLI with weak options.
5456

57+
Status: scoped for V1. The option set includes multiple meaningful choices in the categories that are ready for V1, and intentionally narrow categories are documented in `docs/options.md`. Post-V1 option expansion is tracked in GitHub issue #3.
58+
5559
Use these rules for the V1 option depth pass:
5660

5761
- Add options only inside existing categories.
@@ -104,6 +108,8 @@ Exit criteria:
104108

105109
Goal: test real generated projects, not just renderer template output.
106110

111+
Status: implemented locally. `tests/cli.test.ts` keeps the fast parser, manifest, add-command, and template-render behavior covered. `scripts/validate-generated-projects.ts` scaffolds the representative matrix below; `bun run validate:render` runs the fast render check in CI, and `bun run validate` runs dependency install plus typecheck, lint, tests when present, and build for release validation.
112+
107113
- Add integration tests that scaffold representative projects into temp directories.
108114
- For each representative project, run:
109115
- dependency installation with the selected package manager when practical,
@@ -133,6 +139,8 @@ Exit criteria:
133139

134140
Goal: make npm release boring.
135141

142+
Status: implemented locally, pending an actual workflow dry run from GitHub. `bun run pack:check` verifies package contents, and `bun run pack:smoke` packs the tarball, installs it into a temp consumer project, checks `--version`, dry-runs a scaffold, and scaffolds a real app without installing generated dependencies. The publish workflow supports GitHub releases and `workflow_dispatch` dry runs.
143+
136144
- Confirm `npm pack --dry-run` includes only intended files.
137145
- Add package smoke tests against the packed tarball:
138146
- install the tarball into a temp project,
@@ -154,6 +162,8 @@ Exit criteria:
154162

155163
Goal: make the first-run path clear and keep generated project docs accurate.
156164

165+
Status: in progress, with the V1 public contract, option boundaries, manifest compatibility, generated-project lifecycle, troubleshooting notes, release checks, and changelog now represented in docs. The final pass should be repeated after RC feedback and before `1.0.0`.
166+
157167
- Verify root README commands against the packed package.
158168
- Keep `docs/cli.md` aligned with `parseArgs`.
159169
- Keep `docs/options.md` aligned with `src/options.ts`.

src/cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ const createAppIdentifier = (packageName: string): string => {
9999
const printTemplates = (): void => {
100100
logger.heading("Templates");
101101
logger.info(" minimal implemented, default");
102-
logger.info(" standard implemented profile");
103-
logger.info(" full implemented profile");
102+
logger.info(" standard accepted alias for minimal in V1");
103+
logger.info(" full accepted alias for minimal in V1");
104104
};
105105

106106
const printHelp = (): void => {

src/prompts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ const templateChoices = [
2121
{
2222
value: "standard",
2323
label: "Standard",
24-
hint: "standard profile using the stable scaffold",
24+
hint: "V1 alias for the stable minimal scaffold",
2525
},
2626
{
2727
value: "full",
2828
label: "Full",
29-
hint: "full profile using the stable scaffold",
29+
hint: "V1 alias for the stable minimal scaffold",
3030
},
3131
] satisfies Array<Option<TemplateName>>;
3232

tests/cli.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,20 @@ describe("CLI process", () => {
260260
expect(result.stderr).toBe("");
261261
});
262262

263+
test("--list-templates describes standard and full as V1 aliases", async () => {
264+
const result = await runCliProcess(["--list-templates"]);
265+
266+
expect(result.exitCode).toBe(0);
267+
expect(result.stdout).toContain("minimal implemented, default");
268+
expect(result.stdout).toContain(
269+
"standard accepted alias for minimal in V1",
270+
);
271+
expect(result.stdout).toContain(
272+
"full accepted alias for minimal in V1",
273+
);
274+
expect(result.stderr).toBe("");
275+
});
276+
263277
test("--dry-run does not create the target directory", async () => {
264278
const root = await makeTempRoot();
265279
const result = await runCliProcess([
@@ -503,6 +517,49 @@ describe("final screen", () => {
503517
});
504518

505519
describe("generated minimal template", () => {
520+
test("records accepted template aliases while rendering the same stable source", async () => {
521+
const root = await makeTempRoot();
522+
const stack = { ...defaultStackOptions, testing: "none" };
523+
const templates = ["minimal", "standard", "full"] as const;
524+
525+
for (const template of templates) {
526+
await scaffoldProject({
527+
appIdentifier: "dev.electrobun.sampleapp",
528+
packageName: "sample-app",
529+
projectName: "sample-app",
530+
stack,
531+
targetDirectory: join(root, template),
532+
template,
533+
});
534+
}
535+
536+
const minimalHome = await readGenerated(
537+
join(root, "minimal"),
538+
"src/views/main/home.tsx",
539+
);
540+
const standardHome = await readGenerated(
541+
join(root, "standard"),
542+
"src/views/main/home.tsx",
543+
);
544+
const fullHome = await readGenerated(
545+
join(root, "full"),
546+
"src/views/main/home.tsx",
547+
);
548+
const standardManifest = await readGeneratedManifest(
549+
join(root, "standard"),
550+
);
551+
const fullManifest = await readGeneratedManifest(join(root, "full"));
552+
553+
expect(standardHome).toBe(minimalHome);
554+
expect(fullHome).toBe(minimalHome);
555+
expect(standardManifest.template).toBe("standard");
556+
expect(standardManifest.reproducibleCommand).toContain(
557+
"--template standard",
558+
);
559+
expect(fullManifest.template).toBe("full");
560+
expect(fullManifest.reproducibleCommand).toContain("--template full");
561+
});
562+
506563
test("renders Biome-clean representative projects", async () => {
507564
const representativeStacks = [
508565
{ ...defaultStackOptions },

0 commit comments

Comments
 (0)