Skip to content

Commit 6c5deec

Browse files
committed
feat: add settings persistence with JSON and database options
1 parent e7b99cb commit 6c5deec

18 files changed

Lines changed: 560 additions & 37 deletions

File tree

docs/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ By default, the CLI:
2828
- Blocks non-`views://` renderer navigation unless `--navigation none` is passed.
2929
- Includes the starter RPC example unless `--examples none` is passed.
3030
- Includes a Bun test scaffold unless `--testing none` is passed.
31-
- Supports optional app lock auth, seed data, Turborepo task running, static API mode, and multiple package managers.
31+
- Supports optional app lock auth, settings persistence, seed data, Turborepo task running, static API mode, and multiple package managers.
3232
- Writes `ces.json` in the generated project root with Better-T-Stack-style metadata, a reproducible command, selected stack fields, and feature flags for future CLI commands.
3333

3434
## Default Stack
@@ -49,6 +49,7 @@ By default, the CLI:
4949
--database none
5050
--orm none
5151
--db-setup none
52+
--settings none
5253
--package-manager bun
5354
--testing bun
5455
--addons none
@@ -114,10 +115,10 @@ bun run format
114115

115116
## Generated Manifest
116117

117-
Every generated project includes `ces.json` at the project root. It uses a Better-T-Stack-inspired shape with `$schema`, `version`, `createdAt`, `reproducibleCommand`, project identifiers, flat stack fields such as `database`, `orm`, `frontend`, `addons`, `examples`, and a `features` map for future add-command checks.
118+
Every generated project includes `ces.json` at the project root. It uses a Better-T-Stack-inspired shape with `$schema`, `version`, `createdAt`, `reproducibleCommand`, project identifiers, flat stack fields such as `database`, `orm`, `settings`, `frontend`, `addons`, `examples`, and a `features` map for future add-command checks.
118119

119120
## Current Scope
120121

121-
The implemented templates are `minimal`, `standard`, and `full`; `standard` and `full` currently use the same stable Electrobun template profile while keeping their manifest identity. Tailwind CSS and plain CSS are supported, `--ui shadcn` adds shadcn/ui project config when using Tailwind CSS, SQLite is supported, `--db-setup seed` adds starter metadata, and `--orm drizzle` adds Drizzle ORM when paired with `--database sqlite`. `--api none` omits runtime RPC wiring, `--auth app-lock` adds a local UI lock, and `--addons turborepo` adds Turbo task config. Electrobun-specific options include `--app-menu edit|none`, `--navigation local-only|none`, `--window-style native|hidden-inset`, `--build-env dev|canary|stable`, and `--build-targets current|all`. The default `--testing bun` adds a Bun test script and manifest smoke test; `--testing none` omits it. The default `--examples rpc` renders the starter RPC greeting/logging demo; `--examples none` keeps the typed RPC bridge but omits the demo calls and README section.
122+
The implemented templates are `minimal`, `standard`, and `full`; `standard` and `full` currently use the same stable Electrobun template profile while keeping their manifest identity. Tailwind CSS and plain CSS are supported, `--ui shadcn` adds shadcn/ui project config when using Tailwind CSS, SQLite is supported, `--db-setup seed` adds starter metadata, and `--orm drizzle` adds Drizzle ORM when paired with `--database sqlite`. `--settings json` adds a VS Code-style `data/settings.json` store, and `--settings database` stores the same settings through SQLite when paired with `--database sqlite`. `--api none` omits runtime RPC wiring, `--auth app-lock` adds a local UI lock, and `--addons turborepo` adds Turbo task config. Electrobun-specific options include `--app-menu edit|none`, `--navigation local-only|none`, `--window-style native|hidden-inset`, `--build-env dev|canary|stable`, and `--build-targets current|all`. The default `--testing bun` adds a Bun test script and manifest smoke test; `--testing none` omits it. The default `--examples rpc` renders the starter RPC greeting/logging demo; `--examples none` keeps the typed RPC bridge but omits the demo calls and README section.
122123

123124
The CLI uses `@clack/prompts` for interactive prompts, spinners, and cancellation handling.

docs/ces.schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@
8181
"runtime": {
8282
"enum": ["bun"]
8383
},
84+
"settings": {
85+
"enum": ["none", "json", "database"]
86+
},
8487
"styling": {
8588
"enum": ["tailwindcss", "css"]
8689
},
@@ -115,6 +118,7 @@
115118
"database",
116119
"orm",
117120
"runtime",
121+
"settings",
118122
"buildEnv",
119123
"buildTargets",
120124
"frontend",

docs/cli.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ bun run src/index.ts <project-name> [options]
3030

3131
## Generated Manifest
3232

33-
The CLI writes `ces.json` in the generated project root. The manifest follows a Better-T-Stack-inspired shape with `$schema`, `version`, `createdAt`, `reproducibleCommand`, project identifiers, flat stack fields such as `database`, `orm`, `frontend`, `addons`, `examples`, and `features` booleans for integrations such as `shadcn`, `sqlite`, `drizzle`, `bunTest`, `appLock`, and `turborepo`.
33+
The CLI writes `ces.json` in the generated project root. The manifest follows a Better-T-Stack-inspired shape with `$schema`, `version`, `createdAt`, `reproducibleCommand`, project identifiers, flat stack fields such as `database`, `orm`, `settings`, `frontend`, `addons`, `examples`, and `features` booleans for integrations such as `shadcn`, `sqlite`, `drizzle`, `bunTest`, `appLock`, `settingsStore`, and `turborepo`.
3434

3535
## Stack Options
3636

@@ -53,6 +53,7 @@ These options intentionally mirror the shape of stack scaffolders like `better-t
5353
| `--database` | `none`, `sqlite` | implemented |
5454
| `--orm` | `none`, `drizzle` | `drizzle` implemented with SQLite |
5555
| `--db-setup` | `none`, `seed` | `seed` adds starter SQLite metadata |
56+
| `--settings` | `none`, `json`, `database` | `json` adds `data/settings.json`; `database` stores settings in SQLite |
5657
| `--package-manager` | `bun`, `npm`, `pnpm`, `yarn` | controls dependency install command |
5758
| `--testing` | `bun`, `none` | `bun` adds a Bun test script and generated manifest smoke test |
5859
| `--addons` | `none`, `turborepo` | `turborepo` adds `turbo.json` and Turbo scripts |
@@ -84,6 +85,7 @@ bunx create-electrobun-stack my-app \
8485
--database none \
8586
--orm none \
8687
--db-setup none \
88+
--settings none \
8789
--package-manager bun \
8890
--testing bun \
8991
--addons none \
@@ -109,6 +111,20 @@ bunx create-electrobun-stack my-app \
109111

110112
Invalid combinations, such as `--db-setup seed` without SQLite, fail before files are written.
111113

114+
Create with a VS Code-style JSON settings file:
115+
116+
```bash
117+
bunx create-electrobun-stack my-app --settings json
118+
```
119+
120+
Create with database-backed settings:
121+
122+
```bash
123+
bunx create-electrobun-stack my-app \
124+
--database sqlite \
125+
--settings database
126+
```
127+
112128
Create with SQLite and Drizzle:
113129

114130
```bash

docs/llm.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Default behavior:
3434
- --api none is implemented and omits BrowserWindow RPC wiring.
3535
- --auth app-lock is implemented as a local app-name lock screen.
3636
- --db-setup seed is implemented when paired with --database sqlite.
37+
- --settings json is implemented and adds a VS Code-style data/settings.json store.
38+
- --settings database is implemented when paired with --database sqlite and stores settings in SQLite.
3739
- --addons turborepo is implemented.
3840
- --package-manager supports bun, npm, pnpm, and yarn for dependency installation.
3941
- The default --app-menu edit adds an Electrobun ApplicationMenu with standard Edit roles.
@@ -49,6 +51,7 @@ Default behavior:
4951
- --examples none keeps the RPC bridge but omits the demo calls and generated README section.
5052
- Every generated project includes ces.json for future create-electrobun-stack commands.
5153
- ces.json has top-level fields like version, createdAt, reproducibleCommand, database, orm, frontend, addons, examples, api, and testing.
54+
- Settings modes require the native Electrobun RPC bridge; database settings also require SQLite.
5255

5356
Default stack flags:
5457

@@ -67,6 +70,7 @@ Default stack flags:
6770
--database none
6871
--orm none
6972
--db-setup none
73+
--settings none
7074
--package-manager bun
7175
--testing bun
7276
--addons none
@@ -132,6 +136,7 @@ Supported options:
132136
- --database none|sqlite
133137
- --orm none|drizzle
134138
- --db-setup none|seed
139+
- --settings none|json|database
135140
- --package-manager bun|npm|pnpm|yarn
136141
- --testing bun|none
137142
- --addons none|turborepo

docs/templates.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Includes:
1818
- Native or hidden-inset window chrome through `--window-style`
1919
- Optional Bun test scaffold through `--testing bun`
2020
- Optional app lock through `--auth app-lock`
21+
- Optional JSON or database settings persistence through `--settings`
2122
- Optional Turborepo config through `--addons turborepo`
2223
- Typed Electrobun RPC bridge
2324
- Optional starter RPC example through `--examples rpc`
@@ -42,6 +43,11 @@ templates/minimal/
4243
orm/
4344
drizzle/
4445
**/*.hbs
46+
settings/
47+
json/
48+
**/*.hbs
49+
database/
50+
**/*.hbs
4551
testing/
4652
bun/
4753
**/*.hbs
@@ -55,6 +61,8 @@ The default `--testing bun` adds `bun test`, includes `tests` in `tsconfig.json`
5561

5662
Passing `--api none` omits BrowserWindow RPC wiring. Passing `--auth app-lock` renders a local app-name lock screen. Passing `--db-setup seed` with SQLite inserts starter metadata when the database is empty. Passing `--addons turborepo` adds `turbo.json`, a `check` script, and the Turbo dev dependency.
5763

64+
Passing `--settings json` adds a Bun-side settings store backed by `data/settings.json`, with VS Code-style dotted keys such as `app.theme`. Passing `--settings database` stores the same key/value settings in SQLite and requires `--database sqlite`. Both settings modes expose `getSettingsStatus` and `updateSetting` through the typed Electrobun RPC bridge.
65+
5866
The default `--examples rpc` renders a greeting/logging RPC demo in the route, handlers, shared RPC schema, and generated README. Passing `--examples none` keeps the typed RPC bridge and environment request but omits that demo surface.
5967

6068
Generated structure:
@@ -71,6 +79,8 @@ src/
7179
rpc/
7280
handlers.ts
7381
router.ts
82+
settings/
83+
store.ts
7484
views/
7585
main/
7686
index.html

src/manifest.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ export type CesFeatureFlags = {
1313
editMenu: boolean;
1414
electrobun: boolean;
1515
electrobunRpc: boolean;
16+
databaseSettings: boolean;
1617
hiddenInsetTitlebar: boolean;
18+
jsonSettings: boolean;
1719
localNavigationGuard: boolean;
1820
plainCss: boolean;
1921
react: boolean;
2022
rpcExample: boolean;
2123
shadcn: boolean;
24+
settingsStore: boolean;
2225
sqlite: boolean;
2326
tailwindcss: boolean;
2427
tanstackRouter: boolean;
@@ -50,6 +53,7 @@ export type CesManifest = {
5053
projectName: string;
5154
reproducibleCommand: string;
5255
runtime: StackOptions["runtime"];
56+
settings: StackOptions["settings"];
5357
styling: StackOptions["styling"];
5458
template: TemplateName;
5559
testing: StackOptions["testing"];
@@ -80,12 +84,15 @@ const createFeatureFlags = (stack: StackOptions): CesFeatureFlags => ({
8084
editMenu: stack.appMenu === "edit",
8185
electrobun: true,
8286
electrobunRpc: stack.api === "electrobun-rpc",
87+
databaseSettings: stack.settings === "database",
8388
hiddenInsetTitlebar: stack.windowStyle === "hidden-inset",
89+
jsonSettings: stack.settings === "json",
8490
localNavigationGuard: stack.navigation === "local-only",
8591
plainCss: stack.styling === "css",
8692
react: stack.frontend === "react",
8793
rpcExample: stack.examples === "rpc",
8894
shadcn: stack.ui === "shadcn",
95+
settingsStore: stack.settings !== "none",
8996
sqlite: stack.database === "sqlite",
9097
tailwindcss: stack.styling === "tailwindcss",
9198
tanstackRouter: stack.frontend === "react",
@@ -119,6 +126,14 @@ const createAddonsList = (stack: StackOptions): Array<string> => {
119126
addons.push("navigation-guard");
120127
}
121128

129+
if (stack.settings === "json") {
130+
addons.push("settings-json");
131+
}
132+
133+
if (stack.settings === "database") {
134+
addons.push("settings-database");
135+
}
136+
122137
if (stack.addons === "turborepo") {
123138
addons.push("turborepo");
124139
}
@@ -164,6 +179,8 @@ const createReproducibleCommand = (options: CesManifestOptions): string => {
164179
options.stack.orm,
165180
"--db-setup",
166181
options.stack.dbSetup,
182+
"--settings",
183+
options.stack.settings,
167184
"--package-manager",
168185
options.stack.packageManager,
169186
"--testing",
@@ -206,6 +223,7 @@ export const createCesManifest = (
206223
auth: options.stack.auth,
207224
packageManager: options.stack.packageManager,
208225
dbSetup: options.stack.dbSetup,
226+
settings: options.stack.settings,
209227
api: options.stack.api,
210228
navigation: options.stack.navigation,
211229
windowStyle: options.stack.windowStyle,

templates/minimal/base/README.md.hbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ Generated with `create-electrobun-stack`.
4545
{{#if hasDrizzle}}
4646
- Drizzle ORM
4747
{{/if}}
48+
{{#if hasJsonSettings}}
49+
- VS Code-style JSON settings store
50+
{{/if}}
51+
{{#if hasDatabaseSettings}}
52+
- Database-backed settings store
53+
{{/if}}
4854

4955
`ces.json` records the generated stack, reproducible command, and feature flags for future `create-electrobun-stack` commands.
5056
{{#if hasRpcExample}}

templates/minimal/base/src/bun/rpc/handlers.ts.hbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { APP_NAME } from "../../shared/constants";
22
import type { AppEnvironment } from "../../shared/types";
33
{{#if hasDatabase}}import { getDatabaseStatus } from "../db/client";
44
{{/if}}
5+
{{#if hasSettings}}import { getSettingsStatus, updateSetting } from "../settings/store";
6+
{{/if}}
57

68
const startedAt = new Date().toISOString();
79

@@ -24,3 +26,7 @@ export const logToBun = ({ message }: { message: string }): void => {
2426

2527
export { getDatabaseStatus };
2628
{{/if}}
29+
{{#if hasSettings}}
30+
31+
export { getSettingsStatus, updateSetting };
32+
{{/if}}

templates/minimal/base/src/bun/rpc/router.ts.hbs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
{{#if hasElectrobunRpc}}
22
import { BrowserView } from "electrobun/bun";
33
import type { MainViewRPC } from "../../shared/rpc/types";
4+
import {
45
{{#if hasDatabase}}
5-
{{#if hasRpcExample}}
6-
import { getDatabaseStatus, getEnvironment, greet, logToBun } from "./handlers";
7-
{{else}}
8-
import { getDatabaseStatus, getEnvironment } from "./handlers";
6+
getDatabaseStatus,
97
{{/if}}
10-
{{else}}
118
{{#if hasRpcExample}}
12-
import { getEnvironment, greet, logToBun } from "./handlers";
13-
{{else}}
14-
import { getEnvironment } from "./handlers";
9+
greet,
10+
logToBun,
1511
{{/if}}
12+
getEnvironment,
13+
{{#if hasSettings}}
14+
getSettingsStatus,
15+
updateSetting,
1616
{{/if}}
17+
} from "./handlers";
1718

1819
export const mainViewRPC = BrowserView.defineRPC<MainViewRPC>({
1920
handlers: {
@@ -27,8 +28,14 @@ export const mainViewRPC = BrowserView.defineRPC<MainViewRPC>({
2728
getDatabaseStatus,
2829
{{/if}}
2930
getEnvironment,
31+
{{#if hasSettings}}
32+
getSettingsStatus,
33+
{{/if}}
3034
{{#if hasRpcExample}}
3135
greet,
36+
{{/if}}
37+
{{#if hasSettings}}
38+
updateSetting,
3239
{{/if}}
3340
},
3441
},

templates/minimal/base/src/shared/rpc/schema.ts.hbs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{{#if hasElectrobunRpc}}
22
import type { RPCSchema } from "electrobun";
3-
import type { AppEnvironment{{#if hasDatabase}}, DatabaseStatus{{/if}} } from "../types";
3+
import type {
4+
AppEnvironment,
5+
{{#if hasDatabase}}
6+
DatabaseStatus,
7+
{{/if}}
8+
{{#if hasSettings}}
9+
SettingValue,
10+
SettingsStatus,
11+
{{/if}}
12+
} from "../types";
413

514
export type MainViewRPC = {
615
bun: RPCSchema<{
@@ -32,6 +41,19 @@ export type MainViewRPC = {
3241
response: DatabaseStatus;
3342
};
3443
{{/if}}
44+
{{#if hasSettings}}
45+
getSettingsStatus: {
46+
params: null;
47+
response: SettingsStatus;
48+
};
49+
updateSetting: {
50+
params: {
51+
key: string;
52+
value: SettingValue;
53+
};
54+
response: SettingsStatus;
55+
};
56+
{{/if}}
3557
};
3658
}>;
3759
webview: RPCSchema<{

0 commit comments

Comments
 (0)