happy-stacks 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -83
- package/bin/happys.mjs +70 -10
- package/docs/edison.md +381 -0
- package/docs/happy-development.md +733 -0
- package/docs/menubar.md +54 -0
- package/docs/paths-and-env.md +141 -0
- package/docs/stacks.md +39 -0
- package/extras/swiftbar/auth-login.sh +5 -2
- package/extras/swiftbar/git-cache-refresh.sh +130 -0
- package/extras/swiftbar/happy-stacks.5s.sh +131 -81
- package/extras/swiftbar/happys-term.sh +15 -38
- package/extras/swiftbar/happys.sh +15 -32
- package/extras/swiftbar/install.sh +99 -13
- package/extras/swiftbar/lib/git.sh +309 -1
- package/extras/swiftbar/lib/icons.sh +2 -2
- package/extras/swiftbar/lib/render.sh +209 -80
- package/extras/swiftbar/lib/system.sh +27 -4
- package/extras/swiftbar/lib/utils.sh +311 -28
- package/extras/swiftbar/pnpm.sh +2 -1
- package/extras/swiftbar/set-interval.sh +10 -5
- package/extras/swiftbar/set-server-flavor.sh +11 -2
- package/extras/swiftbar/wt-pr.sh +9 -2
- package/package.json +2 -1
- package/scripts/auth.mjs +560 -112
- package/scripts/build.mjs +24 -4
- package/scripts/cli-link.mjs +3 -3
- package/scripts/completion.mjs +15 -8
- package/scripts/daemon.mjs +130 -20
- package/scripts/dev.mjs +201 -133
- package/scripts/doctor.mjs +26 -21
- package/scripts/edison.mjs +1828 -0
- package/scripts/happy.mjs +3 -7
- package/scripts/init.mjs +43 -20
- package/scripts/install.mjs +14 -8
- package/scripts/lint.mjs +145 -0
- package/scripts/menubar.mjs +81 -8
- package/scripts/migrate.mjs +25 -15
- package/scripts/mobile.mjs +13 -7
- package/scripts/run.mjs +114 -27
- package/scripts/self.mjs +3 -7
- package/scripts/server_flavor.mjs +3 -3
- package/scripts/service.mjs +15 -2
- package/scripts/setup.mjs +790 -0
- package/scripts/setup_pr.mjs +182 -0
- package/scripts/stack.mjs +1792 -254
- package/scripts/stop.mjs +6 -3
- package/scripts/tailscale.mjs +17 -2
- package/scripts/test.mjs +144 -0
- package/scripts/tui.mjs +556 -0
- package/scripts/typecheck.mjs +2 -2
- package/scripts/ui_gateway.mjs +2 -2
- package/scripts/uninstall.mjs +18 -10
- package/scripts/utils/auth_files.mjs +58 -0
- package/scripts/utils/auth_login_ux.mjs +76 -0
- package/scripts/utils/auth_sources.mjs +12 -0
- package/scripts/utils/browser.mjs +22 -0
- package/scripts/utils/canonical_home.mjs +20 -0
- package/scripts/utils/{cli_registry.mjs → cli/cli_registry.mjs} +48 -0
- package/scripts/utils/{wizard.mjs → cli/wizard.mjs} +1 -1
- package/scripts/utils/config.mjs +6 -2
- package/scripts/utils/dev_auth_key.mjs +169 -0
- package/scripts/utils/dev_daemon.mjs +104 -0
- package/scripts/utils/dev_expo_web.mjs +112 -0
- package/scripts/utils/dev_server.mjs +183 -0
- package/scripts/utils/env.mjs +60 -11
- package/scripts/utils/env_file.mjs +36 -0
- package/scripts/utils/expo.mjs +4 -2
- package/scripts/utils/handy_master_secret.mjs +94 -0
- package/scripts/utils/happy_server_infra.mjs +100 -46
- package/scripts/utils/localhost_host.mjs +17 -0
- package/scripts/utils/ownership.mjs +135 -0
- package/scripts/utils/paths.mjs +5 -2
- package/scripts/utils/pm.mjs +121 -20
- package/scripts/utils/proc.mjs +29 -2
- package/scripts/utils/runtime.mjs +1 -3
- package/scripts/utils/sandbox.mjs +14 -0
- package/scripts/utils/server.mjs +24 -0
- package/scripts/utils/server_port.mjs +9 -0
- package/scripts/utils/server_urls.mjs +54 -0
- package/scripts/utils/stack_context.mjs +23 -0
- package/scripts/utils/stack_runtime_state.mjs +104 -0
- package/scripts/utils/stack_startup.mjs +208 -0
- package/scripts/utils/stack_stop.mjs +79 -30
- package/scripts/utils/stacks.mjs +38 -0
- package/scripts/utils/watch.mjs +63 -0
- package/scripts/utils/worktrees.mjs +57 -1
- package/scripts/where.mjs +14 -7
- package/scripts/worktrees.mjs +82 -8
- /package/scripts/utils/{args.mjs → cli/args.mjs} +0 -0
- /package/scripts/utils/{cli.mjs → cli/cli.mjs} +0 -0
- /package/scripts/utils/{smoke_help.mjs → cli/smoke_help.mjs} +0 -0
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
# Happy component development (Happy Stacks)
|
|
2
|
+
|
|
3
|
+
This doc explains **how to develop the Happy components** using **Happy Stacks**:
|
|
4
|
+
|
|
5
|
+
- `happy` (UI)
|
|
6
|
+
- `happy-cli` (CLI + daemon)
|
|
7
|
+
- `happy-server-light` (SQLite “light” server)
|
|
8
|
+
- `happy-server` (Postgres “full” server)
|
|
9
|
+
|
|
10
|
+
It’s intended to be a “one-stop” guide for **humans and LLMs** to iterate safely and repeatably.
|
|
11
|
+
|
|
12
|
+
If you’re new to the project, start here:
|
|
13
|
+
|
|
14
|
+
- Self-hosting / running locally: `README.md`
|
|
15
|
+
- Worktrees + fork workflow: `docs/worktrees-and-forks.md`
|
|
16
|
+
- Stacks: `docs/stacks.md`
|
|
17
|
+
- Server flavors: `docs/server-flavors.md`
|
|
18
|
+
- Paths/env precedence: `docs/paths-and-env.md`
|
|
19
|
+
- Edison workflow (tasks/QA/evidence): `docs/edison.md`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Core concepts (the mental model)
|
|
24
|
+
|
|
25
|
+
### Components
|
|
26
|
+
|
|
27
|
+
Happy Stacks is a launcher/orchestrator repo. The actual product code lives in component repos under:
|
|
28
|
+
|
|
29
|
+
- `components/happy`
|
|
30
|
+
- `components/happy-cli`
|
|
31
|
+
- `components/happy-server-light`
|
|
32
|
+
- `components/happy-server`
|
|
33
|
+
|
|
34
|
+
Each component is its own Git repo.
|
|
35
|
+
|
|
36
|
+
### Worktrees (where you do development)
|
|
37
|
+
|
|
38
|
+
**Never develop directly** in the default checkouts under `components/<component>`.
|
|
39
|
+
Treat them as **read-only launcher defaults**.
|
|
40
|
+
|
|
41
|
+
All development should happen inside **component worktrees** under:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
components/.worktrees/<component>/<owner>/<branch...>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Worktrees make it easy to:
|
|
48
|
+
|
|
49
|
+
- keep your fork “distribution” branches stable
|
|
50
|
+
- create clean upstream PR branches
|
|
51
|
+
- work on multiple PRs/features in parallel
|
|
52
|
+
|
|
53
|
+
See: `docs/worktrees-and-forks.md`.
|
|
54
|
+
|
|
55
|
+
### Stacks (how you test changes safely)
|
|
56
|
+
|
|
57
|
+
A **stack** is an isolated runtime environment (ports + dirs + DB + CLI home) stored under:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
~/.happy/stacks/<stack>/...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Stacks are configured by an env file:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
~/.happy/stacks/<stack>/env
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
You should test worktrees inside a non-`main` stack (recommended).
|
|
70
|
+
|
|
71
|
+
See: `docs/stacks.md`.
|
|
72
|
+
|
|
73
|
+
### Server flavor (which backend you’re running)
|
|
74
|
+
|
|
75
|
+
You run exactly one server implementation per stack:
|
|
76
|
+
|
|
77
|
+
- **`happy-server-light`** (default): SQLite, serves built UI in “start” mode
|
|
78
|
+
- **`happy-server`** (full): Postgres + Redis + S3 (Minio), managed per stack (Docker Compose)
|
|
79
|
+
|
|
80
|
+
See: `docs/server-flavors.md`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Non‑negotiables (discipline that keeps stacks safe)
|
|
85
|
+
|
|
86
|
+
- **Use `happys` as the only entrypoint**
|
|
87
|
+
- Don’t run raw `pnpm`, `yarn`, `expo`, `tsc`, `docker`, etc. directly.
|
|
88
|
+
- Happy Stacks needs stack-scoped env + runtime bookkeeping to stay isolated.
|
|
89
|
+
- **Develop only in worktrees**
|
|
90
|
+
- Work inside `components/.worktrees/...`, not `components/<component>`.
|
|
91
|
+
- **Test/validate stack‑scoped**
|
|
92
|
+
- Prefer `happys stack <stack> ...` commands (typecheck/lint/build/test/dev/start).
|
|
93
|
+
- **Do not “kill all daemons”**
|
|
94
|
+
- Multiple stack daemons are expected. Stop stacks explicitly (`happys stack stop …` or `happys stop …`).
|
|
95
|
+
- **Main stack safety**
|
|
96
|
+
- Avoid repointing `main` stack component dirs to worktrees. Use a new stack.
|
|
97
|
+
- `happys wt use …` will warn/refuse for `main` unless you pass `--force`.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Quickstarts (common development flows)
|
|
102
|
+
|
|
103
|
+
### 1) UI-only change (Happy UI)
|
|
104
|
+
|
|
105
|
+
Create a stack and point it at a UI worktree:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
happys stack new ui1 --interactive
|
|
109
|
+
|
|
110
|
+
# Create a worktree (upstream-first recommended)
|
|
111
|
+
happys wt new happy pr/my-ui-change --from=upstream --use
|
|
112
|
+
|
|
113
|
+
# Pin the stack to that worktree
|
|
114
|
+
happys stack wt ui1 -- use happy slopus/pr/my-ui-change
|
|
115
|
+
|
|
116
|
+
# Run dev (server + daemon + Expo web)
|
|
117
|
+
happys stack dev ui1
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Validate:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
happys stack typecheck ui1 happy
|
|
124
|
+
happys stack lint ui1 happy
|
|
125
|
+
happys stack test ui1 happy
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 2) UI + CLI change (Happy + happy-cli)
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
happys stack new feat1 --interactive
|
|
132
|
+
|
|
133
|
+
happys wt new happy pr/resume-ui --from=upstream --use
|
|
134
|
+
happys wt new happy-cli pr/resume-cli --from=upstream --use
|
|
135
|
+
|
|
136
|
+
happys stack wt feat1 -- use happy slopus/pr/resume-ui
|
|
137
|
+
happys stack wt feat1 -- use happy-cli slopus/pr/resume-cli
|
|
138
|
+
|
|
139
|
+
happys stack dev feat1
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Validate both:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
happys stack typecheck feat1 happy happy-cli
|
|
146
|
+
happys stack lint feat1 happy happy-cli
|
|
147
|
+
happys stack test feat1 happy happy-cli
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 3) Developing server changes (full server)
|
|
151
|
+
|
|
152
|
+
Create a stack that uses `happy-server`:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
happys stack new server1 --interactive
|
|
156
|
+
happys stack srv server1 -- use happy-server
|
|
157
|
+
|
|
158
|
+
happys wt new happy-server pr/my-server-fix --from=upstream --use
|
|
159
|
+
happys stack wt server1 -- use happy-server slopus/pr/my-server-fix
|
|
160
|
+
|
|
161
|
+
happys stack dev server1
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Notes:
|
|
165
|
+
|
|
166
|
+
- Full server stacks may manage per-stack infra automatically (Postgres/Redis/Minio) via Docker Compose.
|
|
167
|
+
- Use stack-safe commands to stop infra cleanly: `happys stack stop server1` (or `happys stop …`).
|
|
168
|
+
|
|
169
|
+
### 4) Testing an upstream PR locally
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
happys wt pr happy 123 --slug=123-fix-thing --use
|
|
173
|
+
happys stack new pr123
|
|
174
|
+
happys stack wt pr123 -- use happy slopus/pr/123-fix-thing
|
|
175
|
+
happys stack dev pr123
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Worktrees: upstream-first workflow + fork integration
|
|
181
|
+
|
|
182
|
+
Happy Stacks is designed for an **upstream-first** workflow:
|
|
183
|
+
|
|
184
|
+
- Implement on an **upstream-based** worktree/branch (`--from=upstream`).
|
|
185
|
+
- Open a clean PR to upstream (`slopus/*`) when appropriate.
|
|
186
|
+
- Then validate/ship to your fork via **test-merge → cherry-pick fallback** (in a fork-based worktree).
|
|
187
|
+
|
|
188
|
+
See the full guide: `docs/worktrees-and-forks.md`.
|
|
189
|
+
|
|
190
|
+
### Concrete walkthrough: upstream PR → fork integration
|
|
191
|
+
|
|
192
|
+
This is the most common “ship it everywhere without polluting history” flow.
|
|
193
|
+
|
|
194
|
+
#### 1) Create an upstream-based worktree and implement
|
|
195
|
+
|
|
196
|
+
Example: implement a UI fix intended for upstream:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
happys wt new happy pr/my-ui-fix --from=upstream --use
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Notes:
|
|
203
|
+
|
|
204
|
+
- When you use `--from=upstream`, the worktree branch name is owner-prefixed. This example produces a branch named:
|
|
205
|
+
- `slopus/pr/my-ui-fix`
|
|
206
|
+
|
|
207
|
+
Do your work inside the worktree path under `components/.worktrees/...`.
|
|
208
|
+
|
|
209
|
+
When ready, push to upstream:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
happys wt push happy active --remote=upstream
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### 2) Validate the same commits on your fork (test-merge)
|
|
216
|
+
|
|
217
|
+
Create a fork-based “integration” worktree (temporary branch) and try merging the upstream branch into it:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
happys wt new happy tmp/merge-pr-my-ui-fix --from=origin --use
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Then merge the upstream branch/commit(s) inside that worktree:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# optional: confirm the upstream branch name before merging
|
|
227
|
+
happys wt status happy slopus/pr/my-ui-fix --json
|
|
228
|
+
|
|
229
|
+
happys wt git happy active -- merge --no-ff slopus/pr/my-ui-fix
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
If it merges cleanly, push to your fork and open a fork PR:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
happys wt push happy active --remote=origin
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### 3) If it conflicts: cherry-pick fallback
|
|
239
|
+
|
|
240
|
+
If the test-merge conflicts, abort the merge, then cherry-pick the upstream commits onto a fork PR branch/worktree and resolve conflicts there:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
happys wt git happy active -- merge --abort
|
|
244
|
+
|
|
245
|
+
# cherry-pick the upstream commits you want (examples):
|
|
246
|
+
happys wt git happy active -- cherry-pick <commit1> <commit2>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Notes:
|
|
250
|
+
|
|
251
|
+
- This keeps the upstream PR history clean and makes fork PRs reproducible.
|
|
252
|
+
- The same pattern applies to `happy-cli` and server repos too.
|
|
253
|
+
|
|
254
|
+
### Server repos: shipping the same change to both fork flavors
|
|
255
|
+
|
|
256
|
+
Server development has one extra twist: **our fork uses a single GitHub repo with two “main” branches**.
|
|
257
|
+
|
|
258
|
+
- **Upstream repo**: `slopus/happy-server` (base branch typically `main`)
|
|
259
|
+
- **Fork repo**: `leeroybrun/happy-server-light`
|
|
260
|
+
- full server fork “main” branch: `happy-server`
|
|
261
|
+
- light server fork “main” branch: `happy-server-light`
|
|
262
|
+
|
|
263
|
+
Local checkouts:
|
|
264
|
+
|
|
265
|
+
- `components/happy-server` and `components/happy-server-light` are **separate local repos** (separate clones) so branch names do not automatically exist in both.
|
|
266
|
+
- In these server repos, the fork remote name is often `fork` (not `origin`), but **`happys wt` normalizes `origin` ↔ `fork`** automatically.
|
|
267
|
+
|
|
268
|
+
#### Goal: one upstream PR, two fork PRs (one per target branch)
|
|
269
|
+
|
|
270
|
+
1) Implement on an upstream-based worktree (recommended use the full server component):
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
happys wt new happy-server pr/my-server-fix --from=upstream --use
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Push upstream (to open the upstream PR):
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
happys wt push happy-server active --remote=upstream
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
2) Check out that upstream PR in the other local server component too (so you can reuse the exact same commits there).
|
|
283
|
+
|
|
284
|
+
Example (use the upstream PR URL/number):
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
happys wt pr happy-server-light https://github.com/slopus/happy-server/pull/<N> --use
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
3) For each fork flavor, create a fork-based integration worktree and merge the PR branch into it, then push.
|
|
291
|
+
|
|
292
|
+
Full server fork branch (`happy-server`):
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
happys wt new happy-server tmp/merge-pr-my-server-fix --from=origin --use
|
|
296
|
+
happys wt status happy-server --json
|
|
297
|
+
# merge the upstream PR branch name shown by wt/pr (example: slopus/pr/<N>-<slug>)
|
|
298
|
+
happys wt git happy-server active -- merge --no-ff slopus/pr/<N>-<slug>
|
|
299
|
+
happys wt push happy-server active --remote=origin
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Light server fork branch (`happy-server-light`):
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
happys wt new happy-server-light tmp/merge-pr-my-server-fix --from=origin --use
|
|
306
|
+
happys wt status happy-server-light --json
|
|
307
|
+
# merge the upstream PR branch name shown by wt/pr (example: slopus/pr/<N>-<slug>)
|
|
308
|
+
happys wt git happy-server-light active -- merge --no-ff slopus/pr/<N>-<slug>
|
|
309
|
+
happys wt push happy-server-light active --remote=origin
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Then open **two PRs** to `leeroybrun/happy-server-light`:
|
|
313
|
+
|
|
314
|
+
- one targeting base branch `happy-server`
|
|
315
|
+
- one targeting base branch `happy-server-light`
|
|
316
|
+
|
|
317
|
+
If a merge conflicts, use the same **cherry-pick fallback** described above, but do it separately for each fork target branch/worktree.
|
|
318
|
+
|
|
319
|
+
High-signal commands:
|
|
320
|
+
|
|
321
|
+
- **Sync mirror branches** (update local `<owner>/<defaultBranch>` mirrors):
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
happys wt sync-all
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- **Update worktrees** (rebase/merge against mirrors):
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
happys wt update-all --dry-run
|
|
331
|
+
happys wt update-all --stash
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
- **Switch active checkout**:
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
happys wt use happy slopus/pr/my-feature
|
|
338
|
+
happys wt use happy default
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Running: `start` vs `dev`
|
|
344
|
+
|
|
345
|
+
### `happys start` (production-like)
|
|
346
|
+
|
|
347
|
+
- Runs the stack in a stable mode.
|
|
348
|
+
- Typically serves a built UI via `happy-server-light` (unless using full server with UI gateway).
|
|
349
|
+
|
|
350
|
+
### `happys dev` (development)
|
|
351
|
+
|
|
352
|
+
Runs the “full local dev loop”:
|
|
353
|
+
|
|
354
|
+
- **server** (light or full, per stack)
|
|
355
|
+
- **daemon** (`happy-cli`) pointing at that server
|
|
356
|
+
- **UI** via Expo web dev server
|
|
357
|
+
|
|
358
|
+
### Web UI origin isolation (IMPORTANT)
|
|
359
|
+
|
|
360
|
+
When running **non-main stacks**, Happy Stacks will use a stack-specific localhost hostname:
|
|
361
|
+
|
|
362
|
+
- `http://happy-<stack>.localhost:<uiPort>`
|
|
363
|
+
|
|
364
|
+
This intentionally creates a **unique browser origin per stack** so browser storage (localStorage/cookies) does not collide between stacks (which can otherwise cause “no machine” / auth confusion).
|
|
365
|
+
|
|
366
|
+
### Browser auto-open (`--no-browser`)
|
|
367
|
+
|
|
368
|
+
In interactive TTY runs, `happys dev` / `happys start` may auto-open the UI in your browser.
|
|
369
|
+
|
|
370
|
+
- Disable: `--no-browser`
|
|
371
|
+
- Stack mode uses the stack-specific hostname shown above (not plain `localhost`) for correctness.
|
|
372
|
+
|
|
373
|
+
**Dev reliability features** (implemented in Happy Stacks):
|
|
374
|
+
|
|
375
|
+
- **Dependency install**: ensures component deps are installed when needed.
|
|
376
|
+
- **Schema readiness**:
|
|
377
|
+
- `happy-server` (Postgres): applies `prisma migrate deploy` (configurable via `HAPPY_STACKS_PRISMA_MIGRATE`)
|
|
378
|
+
- `happy-server-light` (SQLite): upstream dev normally runs `prisma db push` (toggle via `HAPPY_STACKS_PRISMA_PUSH`)
|
|
379
|
+
- **Auth seeding for new stacks** (non-main + non-interactive default):
|
|
380
|
+
- Uses the configured seed stack via `HAPPY_STACKS_AUTH_SEED_FROM` (default: `main`) when the stack looks uninitialized.
|
|
381
|
+
- Recommended for development: create + log into a dedicated seed stack once (usually `dev-auth`) and set:
|
|
382
|
+
- `HAPPY_STACKS_AUTH_SEED_FROM=dev-auth`
|
|
383
|
+
- `HAPPY_STACKS_AUTO_AUTH_SEED=1`
|
|
384
|
+
- This copies credentials/master secret and seeds the minimal DB rows (Accounts) without copying full DB files.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## “Smart builds” + watch mode (hot-reload-ish)
|
|
389
|
+
|
|
390
|
+
### happy-cli build behavior
|
|
391
|
+
|
|
392
|
+
`happys dev` / `happys start` will ensure `happy-cli` is built when needed:
|
|
393
|
+
|
|
394
|
+
- If `dist/index.mjs` is missing, it builds.
|
|
395
|
+
- If source/deps changed since the last build, it rebuilds (git-based signature cache).
|
|
396
|
+
|
|
397
|
+
Controls:
|
|
398
|
+
|
|
399
|
+
- `HAPPY_STACKS_CLI_BUILD_MODE=auto|always|never` (legacy: `HAPPY_LOCAL_CLI_BUILD_MODE`)
|
|
400
|
+
- `HAPPY_STACKS_CLI_BUILD=0` to hard-disable build
|
|
401
|
+
|
|
402
|
+
### Watch mode
|
|
403
|
+
|
|
404
|
+
In interactive TTY runs, `happys dev` enables a watcher by default (disable with `--no-watch`):
|
|
405
|
+
|
|
406
|
+
- **happy-cli changes** → rebuild CLI + restart daemon
|
|
407
|
+
- **happy-server changes** (full server only, where we run `start`) → restart server
|
|
408
|
+
|
|
409
|
+
Important:
|
|
410
|
+
|
|
411
|
+
- Server watch is **stack-only** and is enabled only when Happy Stacks can identify the current **stack-owned server PID**.
|
|
412
|
+
- If the server was already running and the PID can’t be resolved, `dev` will disable server watch and tell you to re-run with `--restart`.
|
|
413
|
+
|
|
414
|
+
Why only full server gets an external watcher:
|
|
415
|
+
|
|
416
|
+
- `happy-server-light` upstream `dev` already provides the correct dev loop.
|
|
417
|
+
- `happy-server` upstream `dev` is not stack-safe, so we run `start` and add our own watcher.
|
|
418
|
+
|
|
419
|
+
### Runtime state + ports during restarts
|
|
420
|
+
|
|
421
|
+
When watchers restart components:
|
|
422
|
+
|
|
423
|
+
- Happy Stacks updates per-stack runtime state with the **new PIDs**
|
|
424
|
+
- It reuses the **same ports** for the run (restarts reuse the same `PORT`)
|
|
425
|
+
- Ports are allocated once per `stack dev/start` invocation and are kept stable for the lifetime of that run.
|
|
426
|
+
|
|
427
|
+
See “Process isolation + runtime state” below.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Developer-only: set up a `dev-auth` seed stack + dev UI key
|
|
432
|
+
|
|
433
|
+
This is a **one-time developer machine setup**. LLM agents should **not** do this; agents should only consume existing seeds/keys.
|
|
434
|
+
|
|
435
|
+
### Create the seed stack (wizard)
|
|
436
|
+
|
|
437
|
+
Run:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
happys stack create-dev-auth-seed
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
This will (interactive, in a TTY):
|
|
444
|
+
|
|
445
|
+
- create (or reuse) the `dev-auth` stack
|
|
446
|
+
- start a temporary server + Expo UI
|
|
447
|
+
- guide you through creating/restoring an account in the UI
|
|
448
|
+
- prompt to save the dev key locally (never committed)
|
|
449
|
+
- run `happys stack auth dev-auth login` to authenticate the CLI/daemon for that seed stack
|
|
450
|
+
|
|
451
|
+
### Make it the default seed for new stacks
|
|
452
|
+
|
|
453
|
+
Add to `~/.happy-stacks/env.local`:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
HAPPY_STACKS_AUTH_SEED_FROM=dev-auth
|
|
457
|
+
HAPPY_STACKS_AUTO_AUTH_SEED=1
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Repair / seed existing stacks (bulk)
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
happys auth copy-from dev-auth --all --except=main,dev-auth
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
If you have full-server (`happy-server`) stacks and want seeding to bring up infra automatically:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
happys auth copy-from dev-auth --all --except=main,dev-auth --with-infra
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Print the UI-accepted dev key format (for UI login / agents)
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
happys auth dev-key --print
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
By default, in a TTY this prints the UI “backup” format (`XXXXX-...`). For automation, use `--format=base64url`.
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Process isolation + runtime state (why stops/restarts are safe)
|
|
483
|
+
|
|
484
|
+
Happy Stacks is “stack-safe” by design:
|
|
485
|
+
|
|
486
|
+
- It tracks PIDs it starts (runner/server/UI/daemon)
|
|
487
|
+
- It refuses to kill processes unless they look **owned by the target stack**
|
|
488
|
+
- ownership is validated using process env (stack name + env file path)
|
|
489
|
+
|
|
490
|
+
### Runtime state file
|
|
491
|
+
|
|
492
|
+
Non-persisted runtime details (ephemeral ports + PIDs) live in:
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
~/.happy/stacks/<stack>/stack.runtime.json
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
This file is intentionally separate from the stack env file:
|
|
499
|
+
|
|
500
|
+
- Env file = stable configuration you *intend* to persist
|
|
501
|
+
- Runtime state = transient state for the currently running processes
|
|
502
|
+
|
|
503
|
+
### Stopping stacks safely
|
|
504
|
+
|
|
505
|
+
Stop a single stack:
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
happys stack stop <stack>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Stop everything except main:
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
happys stop --except-stacks=main --yes
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Useful flags:
|
|
518
|
+
|
|
519
|
+
- `--aggressive`: stops daemon-tracked sessions (but still only stack-owned)
|
|
520
|
+
- `--sweep-owned`: final “owned process sweep” (kills any remaining processes that still have the stack env in their process env)
|
|
521
|
+
- `--no-docker`: skip managed infra shutdown (when you know Docker is irrelevant)
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## Validation commands (typecheck / lint / build / test)
|
|
526
|
+
|
|
527
|
+
Run against the **active checkouts**:
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
happys typecheck
|
|
531
|
+
happys lint
|
|
532
|
+
happys build
|
|
533
|
+
happys test
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
Run stack-scoped (recommended when developing):
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
happys stack typecheck <stack> [component...]
|
|
540
|
+
happys stack lint <stack> [component...]
|
|
541
|
+
happys stack build <stack>
|
|
542
|
+
happys stack test <stack> [component...]
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Examples:
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
happys stack typecheck exp1 happy happy-cli
|
|
549
|
+
happys stack lint exp1 happy
|
|
550
|
+
happys stack test exp1 happy-cli
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## CLI reference (high-signal)
|
|
556
|
+
|
|
557
|
+
Most commands support `--help` and `--json`.
|
|
558
|
+
|
|
559
|
+
### Core run commands
|
|
560
|
+
|
|
561
|
+
- **`happys start`**: production-like run (no Expo)
|
|
562
|
+
- Flags: `--server=happy-server|happy-server-light`, `--restart`, `--no-daemon`, `--no-ui`, `--no-browser`
|
|
563
|
+
- **`happys dev`**: dev run (server + daemon + Expo web)
|
|
564
|
+
- Flags: `--server=happy-server|happy-server-light`, `--restart`, `--no-daemon`, `--no-ui`, `--watch`, `--no-watch`, `--no-browser`
|
|
565
|
+
- **`happys stop`**: stop stacks and related processes
|
|
566
|
+
- Flags: `--except-stacks=main,exp1`, `--yes`, `--aggressive`, `--sweep-owned`, `--no-docker`, `--no-service`
|
|
567
|
+
|
|
568
|
+
### TUI (optional)
|
|
569
|
+
|
|
570
|
+
If you want a split-pane view while running a command:
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
happys tui stack dev <stack>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Stack-scoped commands
|
|
577
|
+
|
|
578
|
+
All `happys stack <name> ...` commands apply that stack’s env file (and keep stacks isolated).
|
|
579
|
+
|
|
580
|
+
- **Lifecycle**:
|
|
581
|
+
- `happys stack new <name> [--interactive] [--server=...] [--port=...] [--copy-auth-from=main|--no-copy-auth]`
|
|
582
|
+
- `happys stack dev <name>`
|
|
583
|
+
- `happys stack start <name>`
|
|
584
|
+
- `happys stack stop <name> [--aggressive] [--sweep-owned] [--no-docker]`
|
|
585
|
+
- `happys stack build <name>`
|
|
586
|
+
- **Quality**:
|
|
587
|
+
- `happys stack typecheck <name> [component...]`
|
|
588
|
+
- `happys stack lint <name> [component...]`
|
|
589
|
+
- `happys stack test <name> [component...]`
|
|
590
|
+
- **One-shot component overrides (do not persist)**:
|
|
591
|
+
- Many stack commands accept one-shot overrides like `--happy=...` / `--happy-cli=...` / `--happy-server-light=...` / `--happy-server=...`
|
|
592
|
+
- Example:
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
happys stack typecheck exp1 --happy=slopus/pr/my-ui-pr happy
|
|
596
|
+
```
|
|
597
|
+
- **Selection / diagnosis / auth**:
|
|
598
|
+
- `happys stack wt <name> -- <wt args...>`
|
|
599
|
+
- `happys stack srv <name> -- use happy-server|happy-server-light`
|
|
600
|
+
- `happys stack doctor <name>`
|
|
601
|
+
- `happys stack auth <name> status|login|copy-from <seed>`
|
|
602
|
+
- `happys stack audit --fix-workspace --fix-paths --fix-ports`
|
|
603
|
+
|
|
604
|
+
### Worktrees
|
|
605
|
+
|
|
606
|
+
- `happys wt new <component> <branch> --from=upstream|origin --use`
|
|
607
|
+
- `happys wt pr <component> <pr-url|number> --use [--update] [--stash]`
|
|
608
|
+
- `happys wt use <component> <spec>`
|
|
609
|
+
- `happys wt sync-all`
|
|
610
|
+
- `happys wt update-all [--dry-run] [--stash]`
|
|
611
|
+
|
|
612
|
+
### Edison wrapper (mandatory in this repo)
|
|
613
|
+
|
|
614
|
+
- `happys edison --stack=<stack> -- <edison args...>`
|
|
615
|
+
- `happys edison --stack=<stack> -- evidence capture <task-id>`
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Useful environment knobs (high-signal)
|
|
620
|
+
|
|
621
|
+
Happy Stacks uses `HAPPY_STACKS_*` as the canonical prefix; most settings also accept the legacy `HAPPY_LOCAL_*` alias.
|
|
622
|
+
|
|
623
|
+
- **Server flavor**:
|
|
624
|
+
- `HAPPY_STACKS_SERVER_COMPONENT=happy-server-light|happy-server`
|
|
625
|
+
- **Ports**:
|
|
626
|
+
- `HAPPY_STACKS_SERVER_PORT=<n>` (pinned)
|
|
627
|
+
- `HAPPY_STACKS_EPHEMERAL_PORTS=1` (prefer ephemeral ports for stacks; default for non-main stacks)
|
|
628
|
+
- **Full server infra** (happy-server):
|
|
629
|
+
- `HAPPY_STACKS_MANAGED_INFRA=0` (disable Docker-managed Postgres/Redis/Minio; provide URLs yourself)
|
|
630
|
+
- **Prisma behavior**:
|
|
631
|
+
- `HAPPY_STACKS_PRISMA_PUSH=0` (server-light: avoid `prisma db push` in dev mode)
|
|
632
|
+
- `HAPPY_STACKS_PRISMA_MIGRATE=0` (full server: disable `prisma migrate deploy`)
|
|
633
|
+
- **happy-cli build behavior**:
|
|
634
|
+
- `HAPPY_STACKS_CLI_BUILD_MODE=auto|always|never`
|
|
635
|
+
- `HAPPY_STACKS_CLI_BUILD=0` (hard-disable)
|
|
636
|
+
|
|
637
|
+
See also: `docs/paths-and-env.md` for env precedence and where the files live.
|
|
638
|
+
|
|
639
|
+
---
|
|
640
|
+
|
|
641
|
+
## Debug / inspect commands
|
|
642
|
+
|
|
643
|
+
- **“Where is this running from?”**:
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
happys where
|
|
647
|
+
happys where --json
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
- **Stack health / diagnosis**:
|
|
651
|
+
|
|
652
|
+
```bash
|
|
653
|
+
happys stack doctor <stack>
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
- **Fix common stack hygiene issues** (foreign component paths, inconsistent dirs, port collisions):
|
|
657
|
+
|
|
658
|
+
```bash
|
|
659
|
+
happys stack audit --fix-workspace --fix-paths --fix-ports
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
- **Stop stacks safely**:
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
happys stack stop <stack>
|
|
666
|
+
happys stop --except-stacks=main --yes
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
## Edison integration (tasks/QA/evidence/validation)
|
|
672
|
+
|
|
673
|
+
Edison is supported in this repo, but **does not provide isolation** here.
|
|
674
|
+
Isolation is provided by **Happy Stacks** (stacks + component worktrees).
|
|
675
|
+
|
|
676
|
+
Key rule: **do not run `edison ...` directly** in this repo.
|
|
677
|
+
Use the wrapper:
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
happys edison --stack=<stack> -- evidence capture <task-id>
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
This wrapper:
|
|
684
|
+
|
|
685
|
+
- forces stack-scoped env
|
|
686
|
+
- fingerprints the correct multi-repo state
|
|
687
|
+
- enables fail-closed guards (task → stack → worktrees)
|
|
688
|
+
|
|
689
|
+
See: `docs/edison.md`.
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## Troubleshooting (high-signal fixes)
|
|
694
|
+
|
|
695
|
+
### “No machine” / auth required
|
|
696
|
+
|
|
697
|
+
Check auth:
|
|
698
|
+
|
|
699
|
+
```bash
|
|
700
|
+
happys stack auth <stack> status
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Login (interactive):
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
happys stack auth <stack> login
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Non-interactive repair (copy credentials + seed accounts from `main`):
|
|
710
|
+
|
|
711
|
+
```bash
|
|
712
|
+
happys stack auth <stack> copy-from <seed>
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Notes:
|
|
716
|
+
|
|
717
|
+
- `<seed>` should be the stack you use as your auth seed (recommended: `dev-auth`).
|
|
718
|
+
- Creating/logging into the seed stack is a **developer-only** setup step; agents should only consume it.
|
|
719
|
+
|
|
720
|
+
### Port collisions / foreign component paths / weird stack dirs
|
|
721
|
+
|
|
722
|
+
Run the audit fixer:
|
|
723
|
+
|
|
724
|
+
```bash
|
|
725
|
+
happys stack audit --fix-workspace --fix-paths --fix-ports
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### Stack is unhealthy / can’t reach server
|
|
729
|
+
|
|
730
|
+
```bash
|
|
731
|
+
happys stack doctor <stack>
|
|
732
|
+
```
|
|
733
|
+
|