happy-stacks 0.1.0 → 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 +130 -74
- package/bin/happys.mjs +140 -9
- 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/server-flavors.md +61 -2
- package/docs/stacks.md +55 -4
- package/extras/swiftbar/auth-login.sh +10 -7
- package/extras/swiftbar/git-cache-refresh.sh +130 -0
- package/extras/swiftbar/happy-stacks.5s.sh +175 -83
- package/extras/swiftbar/happys-term.sh +128 -0
- package/extras/swiftbar/happys.sh +35 -0
- 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 +279 -132
- package/extras/swiftbar/lib/system.sh +64 -10
- package/extras/swiftbar/lib/utils.sh +469 -10
- package/extras/swiftbar/pnpm-term.sh +2 -122
- package/extras/swiftbar/pnpm.sh +4 -14
- package/extras/swiftbar/set-interval.sh +10 -5
- package/extras/swiftbar/set-server-flavor.sh +19 -10
- package/extras/swiftbar/wt-pr.sh +10 -3
- package/package.json +2 -1
- package/scripts/auth.mjs +833 -14
- package/scripts/build.mjs +24 -4
- package/scripts/cli-link.mjs +3 -3
- package/scripts/completion.mjs +15 -8
- package/scripts/daemon.mjs +200 -23
- package/scripts/dev.mjs +230 -57
- package/scripts/doctor.mjs +26 -21
- package/scripts/edison.mjs +1828 -0
- package/scripts/happy.mjs +3 -7
- package/scripts/init.mjs +275 -46
- package/scripts/install.mjs +14 -8
- package/scripts/lint.mjs +145 -0
- package/scripts/menubar.mjs +81 -8
- package/scripts/migrate.mjs +302 -0
- package/scripts/mobile.mjs +59 -21
- package/scripts/run.mjs +222 -43
- package/scripts/self.mjs +3 -7
- package/scripts/server_flavor.mjs +3 -3
- package/scripts/service.mjs +190 -38
- package/scripts/setup.mjs +790 -0
- package/scripts/setup_pr.mjs +182 -0
- package/scripts/stack.mjs +2273 -92
- package/scripts/stop.mjs +160 -0
- package/scripts/tailscale.mjs +164 -23
- package/scripts/test.mjs +144 -0
- package/scripts/tui.mjs +556 -0
- package/scripts/typecheck.mjs +145 -0
- package/scripts/ui_gateway.mjs +248 -0
- package/scripts/uninstall.mjs +21 -13
- 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} +71 -0
- package/scripts/utils/{wizard.mjs → cli/wizard.mjs} +1 -1
- package/scripts/utils/config.mjs +13 -1
- 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 +94 -23
- package/scripts/utils/env_file.mjs +36 -0
- package/scripts/utils/expo.mjs +96 -0
- package/scripts/utils/handy_master_secret.mjs +94 -0
- package/scripts/utils/happy_server_infra.mjs +484 -0
- 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 +132 -22
- package/scripts/utils/ports.mjs +51 -13
- package/scripts/utils/proc.mjs +75 -7
- package/scripts/utils/runtime.mjs +1 -3
- package/scripts/utils/sandbox.mjs +14 -0
- package/scripts/utils/server.mjs +61 -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 +255 -0
- package/scripts/utils/stacks.mjs +38 -0
- package/scripts/utils/validate.mjs +42 -1
- package/scripts/utils/watch.mjs +63 -0
- package/scripts/utils/worktrees.mjs +57 -1
- package/scripts/where.mjs +14 -7
- package/scripts/worktrees.mjs +135 -15
- /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
|
@@ -21,9 +21,16 @@ level_from_server_daemon() {
|
|
|
21
21
|
|
|
22
22
|
color_for_level() {
|
|
23
23
|
local level="$1"
|
|
24
|
-
if [[ "$level" == "green" ]]; then echo "
|
|
25
|
-
if [[ "$level" == "orange" ]]; then echo "
|
|
26
|
-
echo "
|
|
24
|
+
if [[ "$level" == "green" ]]; then echo "#16a34a"; return; fi
|
|
25
|
+
if [[ "$level" == "orange" ]]; then echo "#f59e0b"; return; fi
|
|
26
|
+
echo "#e74c3c"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
sfconfig_for_level() {
|
|
30
|
+
local level="$1"
|
|
31
|
+
local color="$(color_for_level "$level")"
|
|
32
|
+
# sfconfig SFSymbol configuration Configures Rendering Mode for sfimage. Accepts a json encoded as base64, example json {"renderingMode":"Palette", "colors":["red","blue"], "scale": "large", "weight": "bold"}. Original issue #354
|
|
33
|
+
echo "{\"colors\":[\"$color\"], \"scale\": \"small\"}" | base64 -b 0
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
sf_for_level() {
|
|
@@ -33,6 +40,13 @@ sf_for_level() {
|
|
|
33
40
|
echo "xmark.circle.fill"
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
sf_suffix_for_level() {
|
|
44
|
+
local level="$1"
|
|
45
|
+
if [[ "$level" == "green" ]]; then echo "badge.checkmark"; return; fi
|
|
46
|
+
if [[ "$level" == "orange" ]]; then echo "trianglebadge.exclamationmark"; return; fi
|
|
47
|
+
echo "badge.xmark"
|
|
48
|
+
}
|
|
49
|
+
|
|
36
50
|
print_item() {
|
|
37
51
|
local prefix="$1"
|
|
38
52
|
shift
|
|
@@ -60,12 +74,16 @@ render_component_server() {
|
|
|
60
74
|
|
|
61
75
|
local label="Server (${server_component})"
|
|
62
76
|
local sf="$(sf_for_level "$level")"
|
|
63
|
-
local
|
|
64
|
-
print_item "$prefix" "$label | sfimage=$sf
|
|
77
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
78
|
+
print_item "$prefix" "$label | sfimage=$sf sfconfig=$sfconfig"
|
|
65
79
|
|
|
66
80
|
local p2="${prefix}--"
|
|
67
81
|
print_item "$p2" "Status: $server_status"
|
|
68
|
-
|
|
82
|
+
if [[ -n "$port" ]]; then
|
|
83
|
+
print_item "$p2" "Internal: http://127.0.0.1:${port}"
|
|
84
|
+
else
|
|
85
|
+
print_item "$p2" "Port: ephemeral (allocated at start time)"
|
|
86
|
+
fi
|
|
69
87
|
if [[ -n "$server_pid" ]]; then
|
|
70
88
|
if [[ -n "$server_metrics" ]]; then
|
|
71
89
|
local cpu mem etime
|
|
@@ -77,20 +95,24 @@ render_component_server() {
|
|
|
77
95
|
print_item "$p2" "PID: ${server_pid}"
|
|
78
96
|
fi
|
|
79
97
|
fi
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
if [[ -n "$port" ]]; then
|
|
99
|
+
print_item "$p2" "Open UI (local) | href=http://localhost:${port}/"
|
|
100
|
+
print_item "$p2" "Open Health | href=http://127.0.0.1:${port}/health"
|
|
101
|
+
fi
|
|
82
102
|
if [[ -n "$tailscale_url" ]]; then
|
|
83
103
|
print_item "$p2" "Open UI (Tailscale) | href=$tailscale_url"
|
|
84
104
|
fi
|
|
85
105
|
|
|
86
106
|
# Start/stop shortcuts (so you can control from the Server submenu too).
|
|
87
107
|
if [[ -n "$PNPM_BIN" ]]; then
|
|
88
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
108
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
89
109
|
local plist=""
|
|
90
110
|
local svc_installed="0"
|
|
91
|
-
if
|
|
92
|
-
|
|
93
|
-
|
|
111
|
+
if ! swiftbar_is_sandboxed; then
|
|
112
|
+
if [[ -n "$launch_label" ]]; then
|
|
113
|
+
plist="$HOME/Library/LaunchAgents/${launch_label}.plist"
|
|
114
|
+
[[ -f "$plist" ]] && svc_installed="1"
|
|
115
|
+
fi
|
|
94
116
|
fi
|
|
95
117
|
|
|
96
118
|
print_sep "$p2"
|
|
@@ -104,7 +126,7 @@ render_component_server() {
|
|
|
104
126
|
print_item "$p2" "Restart stack (service) | bash=$PNPM_BIN param1=service:restart dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
105
127
|
else
|
|
106
128
|
if [[ "$server_status" == "running" ]]; then
|
|
107
|
-
print_item "$p2" "Stop
|
|
129
|
+
print_item "$p2" "Stop stack | bash=$PNPM_BIN param1=stack param2=stop param3=main dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
108
130
|
else
|
|
109
131
|
print_item "$p2" "Start stack (foreground) | bash=$PNPM_TERM param1=start dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
110
132
|
fi
|
|
@@ -119,7 +141,7 @@ render_component_server() {
|
|
|
119
141
|
print_item "$p2" "Restart stack (service) | bash=$PNPM_BIN param1=stack param2=service:restart param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
120
142
|
else
|
|
121
143
|
if [[ "$server_status" == "running" ]]; then
|
|
122
|
-
print_item "$p2" "Stop
|
|
144
|
+
print_item "$p2" "Stop stack | bash=$PNPM_BIN param1=stack param2=stop param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
123
145
|
else
|
|
124
146
|
print_item "$p2" "Start stack (foreground) | bash=$PNPM_TERM param1=stack param2=start param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
125
147
|
fi
|
|
@@ -130,7 +152,7 @@ render_component_server() {
|
|
|
130
152
|
# Flavor switching (status-aware: only show switching to the other option).
|
|
131
153
|
local helper="$HAPPY_LOCAL_DIR/extras/swiftbar/set-server-flavor.sh"
|
|
132
154
|
if [[ -n "$PNPM_BIN" ]]; then
|
|
133
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
155
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
134
156
|
print_sep "$p2"
|
|
135
157
|
if [[ "$server_component" == "happy-server" ]]; then
|
|
136
158
|
print_item "$p2" "Switch to happy-server-light (restart if service installed) | bash=$helper param1=$stack_name param2=happy-server-light dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
@@ -159,9 +181,10 @@ render_component_daemon() {
|
|
|
159
181
|
if [[ "$daemon_status" == "running" ]]; then level="green"; fi
|
|
160
182
|
if [[ "$daemon_status" == "running-no-http" || "$daemon_status" == "stale" || "$daemon_status" == "auth_required" || "$daemon_status" == "starting" ]]; then level="orange"; fi
|
|
161
183
|
|
|
184
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
185
|
+
|
|
162
186
|
local sf="$(sf_for_level "$level")"
|
|
163
|
-
|
|
164
|
-
print_item "$prefix" "Daemon | sfimage=$sf color=$color"
|
|
187
|
+
print_item "$prefix" "Daemon | sfimage=$sf sfconfig=$sfconfig"
|
|
165
188
|
|
|
166
189
|
local p2="${prefix}--"
|
|
167
190
|
print_item "$p2" "Status: $daemon_status"
|
|
@@ -187,28 +210,29 @@ render_component_daemon() {
|
|
|
187
210
|
# Provide a direct "fix" action for the common first-run problem under launchd.
|
|
188
211
|
local auth_helper="$HAPPY_LOCAL_DIR/extras/swiftbar/auth-login.sh"
|
|
189
212
|
local server_url="http://127.0.0.1:$(resolve_main_port)"
|
|
190
|
-
local webapp_url
|
|
191
|
-
webapp_url="$(get_tailscale_url)"
|
|
192
|
-
[[ -z "$webapp_url" ]] && webapp_url="http://localhost:$(resolve_main_port)"
|
|
213
|
+
local webapp_url="http://localhost:$(resolve_main_port)"
|
|
193
214
|
if [[ "$stack_name" == "main" ]]; then
|
|
194
|
-
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=main
|
|
215
|
+
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=main dir=$HAPPY_LOCAL_DIR terminal=false refresh=false"
|
|
195
216
|
else
|
|
196
217
|
# For stacks, best-effort use the stack's configured port if available (fallback to main port).
|
|
197
|
-
local env_file
|
|
218
|
+
local env_file
|
|
219
|
+
env_file="$(resolve_stack_env_file "$stack_name")"
|
|
198
220
|
local port
|
|
199
|
-
port="$(dotenv_get "$env_file" "
|
|
221
|
+
port="$(dotenv_get "$env_file" "HAPPY_STACKS_SERVER_PORT")"
|
|
222
|
+
[[ -z "$port" ]] && port="$(dotenv_get "$env_file" "HAPPY_LOCAL_SERVER_PORT")"
|
|
200
223
|
[[ -z "$port" ]] && port="$(resolve_main_port)"
|
|
201
224
|
server_url="http://127.0.0.1:${port}"
|
|
202
|
-
webapp_url="
|
|
203
|
-
|
|
204
|
-
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=$stack_name param2=$server_url param3=$webapp_url param4=$HOME/.happy/stacks/$stack_name/cli dir=$HAPPY_LOCAL_DIR terminal=false refresh=false"
|
|
225
|
+
webapp_url="http://localhost:${port}"
|
|
226
|
+
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=false"
|
|
205
227
|
fi
|
|
206
228
|
print_sep "$p2"
|
|
207
229
|
fi
|
|
208
|
-
if
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
230
|
+
if ! swiftbar_is_sandboxed; then
|
|
231
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
232
|
+
print_item "$p2" "Restart stack (service) | bash=$PNPM_BIN param1=service:restart dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
233
|
+
else
|
|
234
|
+
print_item "$p2" "Restart stack (service) | bash=$PNPM_BIN param1=stack param2=service:restart param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
235
|
+
fi
|
|
212
236
|
fi
|
|
213
237
|
fi
|
|
214
238
|
}
|
|
@@ -222,13 +246,20 @@ render_component_autostart() {
|
|
|
222
246
|
local autostart_metrics="$6"
|
|
223
247
|
local logs_dir="$7"
|
|
224
248
|
|
|
249
|
+
if swiftbar_is_sandboxed; then
|
|
250
|
+
print_item "$prefix" "Autostart | sfimage=exclamationmark.triangle sfconfig=light"
|
|
251
|
+
local p2="${prefix}--"
|
|
252
|
+
print_item "$p2" "Status: disabled in sandbox"
|
|
253
|
+
return
|
|
254
|
+
fi
|
|
255
|
+
|
|
225
256
|
local level="red"
|
|
226
257
|
if [[ "$launchagent_status" == "loaded" ]]; then level="green"; fi
|
|
227
258
|
if [[ "$launchagent_status" == "unloaded" ]]; then level="orange"; fi
|
|
228
259
|
|
|
229
260
|
local sf="$(sf_for_level "$level")"
|
|
230
|
-
local
|
|
231
|
-
print_item "$prefix" "Autostart | sfimage=$sf
|
|
261
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
262
|
+
print_item "$prefix" "Autostart | sfimage=$sf sfconfig=$sfconfig"
|
|
232
263
|
|
|
233
264
|
local p2="${prefix}--"
|
|
234
265
|
print_item "$p2" "Status: $launchagent_status"
|
|
@@ -292,8 +323,8 @@ render_component_tailscale() {
|
|
|
292
323
|
[[ -n "$tailscale_url" ]] && level="green"
|
|
293
324
|
|
|
294
325
|
local sf="$(sf_for_level "$level")"
|
|
295
|
-
local
|
|
296
|
-
print_item "$prefix" "Tailscale | sfimage=$sf
|
|
326
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
327
|
+
print_item "$prefix" "Tailscale | sfimage=$sf sfconfig=$sfconfig"
|
|
297
328
|
|
|
298
329
|
local p2="${prefix}--"
|
|
299
330
|
if [[ -n "$tailscale_url" ]]; then
|
|
@@ -306,13 +337,18 @@ render_component_tailscale() {
|
|
|
306
337
|
print_item "$p2" "Status: not configured / unknown"
|
|
307
338
|
fi
|
|
308
339
|
|
|
340
|
+
# Tailscale Serve is global machine state; never offer enable/disable actions in sandbox mode.
|
|
341
|
+
if swiftbar_is_sandboxed; then
|
|
342
|
+
return
|
|
343
|
+
fi
|
|
344
|
+
|
|
309
345
|
if [[ -z "$PNPM_BIN" ]]; then
|
|
310
346
|
return
|
|
311
347
|
fi
|
|
312
348
|
print_sep "$p2"
|
|
313
349
|
|
|
314
350
|
if [[ "$stack_name" == "main" ]]; then
|
|
315
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
351
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
316
352
|
print_item "$p2" "Tailscale status | bash=$PNPM_TERM param1=tailscale:status dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
317
353
|
if [[ -n "$tailscale_url" ]]; then
|
|
318
354
|
print_item "$p2" "Disable Tailscale Serve | bash=$PNPM_BIN param1=tailscale:disable dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
@@ -323,7 +359,7 @@ render_component_tailscale() {
|
|
|
323
359
|
return
|
|
324
360
|
fi
|
|
325
361
|
|
|
326
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
362
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
327
363
|
print_item "$p2" "Tailscale status | bash=$PNPM_TERM param1=stack param2=tailscale:status param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
328
364
|
if [[ -n "$tailscale_url" ]]; then
|
|
329
365
|
print_item "$p2" "Disable Tailscale Serve | bash=$PNPM_BIN param1=stack param2=tailscale:disable param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
@@ -344,8 +380,12 @@ render_component_repo() {
|
|
|
344
380
|
local stack_name="$4"
|
|
345
381
|
local env_file="$5"
|
|
346
382
|
|
|
383
|
+
local t0 t1
|
|
384
|
+
t0="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
385
|
+
|
|
347
386
|
local active_dir=""
|
|
348
|
-
|
|
387
|
+
# If we have an env file for the current context, prefer it (stack env is authoritative).
|
|
388
|
+
if [[ -n "$env_file" && -f "$env_file" ]]; then
|
|
349
389
|
active_dir="$(resolve_component_dir_from_env_file "$env_file" "$component")"
|
|
350
390
|
else
|
|
351
391
|
active_dir="$(resolve_component_dir_from_env "$component")"
|
|
@@ -353,25 +393,51 @@ render_component_repo() {
|
|
|
353
393
|
|
|
354
394
|
local level="red"
|
|
355
395
|
local detail="missing"
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
396
|
+
|
|
397
|
+
local git_mode
|
|
398
|
+
git_mode="$(git_cache_mode)"
|
|
399
|
+
|
|
400
|
+
local stale="0"
|
|
401
|
+
local meta="" info="" wts=""
|
|
402
|
+
if [[ "$git_mode" == "cached" ]]; then
|
|
403
|
+
# Never refresh synchronously during menu render.
|
|
404
|
+
IFS=$'\t' read -r meta info wts stale <<<"$(git_cache_load_or_refresh "$context" "$stack_name" "$component" "$active_dir" "0")"
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
local status="missing"
|
|
408
|
+
local dirty="" ahead="" behind="" wt_count=""
|
|
409
|
+
local branch="" head="" upstream=""
|
|
410
|
+
local main_branch="" main_upstream="" main_ahead="" main_behind=""
|
|
411
|
+
local oref="" o_ahead="" o_behind="" uref="" u_ahead="" u_behind=""
|
|
412
|
+
|
|
413
|
+
if [[ "$git_mode" == "cached" && -f "$info" ]]; then
|
|
414
|
+
IFS=$'\t' read -r status _ad branch head upstream dirty ahead behind main_branch main_upstream main_ahead main_behind oref o_ahead o_behind uref u_ahead u_behind wt_count <"$info" || true
|
|
415
|
+
elif [[ "$git_mode" == "live" ]]; then
|
|
416
|
+
# live mode only: do git work on every refresh
|
|
417
|
+
if is_git_repo "$active_dir"; then
|
|
418
|
+
status="ok"
|
|
419
|
+
dirty="$(git_dirty_flag "$active_dir")"
|
|
420
|
+
local ab
|
|
421
|
+
ab="$(git_ahead_behind "$active_dir")"
|
|
422
|
+
if [[ -n "$ab" ]]; then
|
|
423
|
+
ahead="$(echo "$ab" | cut -d'|' -f1)"
|
|
424
|
+
behind="$(echo "$ab" | cut -d'|' -f2)"
|
|
425
|
+
fi
|
|
365
426
|
fi
|
|
427
|
+
fi
|
|
366
428
|
|
|
429
|
+
if [[ "$status" == "ok" ]]; then
|
|
430
|
+
detail="ok"
|
|
367
431
|
if [[ "$dirty" == "dirty" ]] || [[ -n "$behind" && "$behind" != "0" ]]; then
|
|
368
432
|
level="orange"
|
|
369
433
|
else
|
|
370
434
|
level="green"
|
|
371
435
|
fi
|
|
372
|
-
detail="ok"
|
|
373
436
|
fi
|
|
374
437
|
|
|
438
|
+
t1="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
439
|
+
swiftbar_profile_log "time" "label=render_component_repo" "component=${component}" "context=${context}" "ms=$((t1 - t0))" "detail=${detail}"
|
|
440
|
+
|
|
375
441
|
local sf color
|
|
376
442
|
sf="$(sf_for_level "$level")"
|
|
377
443
|
color="$(color_for_level "$level")"
|
|
@@ -380,31 +446,50 @@ render_component_repo() {
|
|
|
380
446
|
local p2="${prefix}--"
|
|
381
447
|
print_item "$p2" "Dir: $(shorten_path "$active_dir" 52)"
|
|
382
448
|
if [[ "$detail" != "ok" ]]; then
|
|
383
|
-
|
|
449
|
+
if [[ "$git_mode" == "cached" ]]; then
|
|
450
|
+
print_item "$p2" "Status: git cache missing (or not a git repo)"
|
|
451
|
+
local refresh="$HAPPY_LOCAL_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
452
|
+
if [[ -x "$refresh" ]]; then
|
|
453
|
+
print_sep "$p2"
|
|
454
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
455
|
+
print_item "$p2" "Refresh Git cache (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
456
|
+
else
|
|
457
|
+
print_item "$p2" "Refresh Git cache (main) | bash=$refresh param1=main dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
458
|
+
fi
|
|
459
|
+
fi
|
|
460
|
+
else
|
|
461
|
+
print_item "$p2" "Status: not a git repo / missing"
|
|
462
|
+
fi
|
|
384
463
|
if [[ -n "$PNPM_BIN" ]]; then
|
|
385
464
|
print_sep "$p2"
|
|
386
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
465
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
387
466
|
print_item "$p2" "Bootstrap (clone missing components) | bash=$PNPM_TERM param1=bootstrap dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
388
467
|
fi
|
|
389
468
|
return
|
|
390
469
|
fi
|
|
391
470
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
471
|
+
# Cache status + refresh actions
|
|
472
|
+
if [[ "$git_mode" == "cached" ]]; then
|
|
473
|
+
local age=""
|
|
474
|
+
age="$(git_cache_age_sec "$meta")"
|
|
475
|
+
if [[ -n "$age" ]]; then
|
|
476
|
+
if [[ "$stale" == "1" ]]; then
|
|
477
|
+
print_item "$p2" "Git cache: stale (${age}s old) | color=$YELLOW"
|
|
478
|
+
else
|
|
479
|
+
print_item "$p2" "Git cache: fresh (${age}s old) | color=$GRAY"
|
|
480
|
+
fi
|
|
481
|
+
fi
|
|
482
|
+
local refresh="$HAPPY_LOCAL_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
483
|
+
if [[ -x "$refresh" ]]; then
|
|
484
|
+
print_sep "$p2"
|
|
485
|
+
print_item "$p2" "Refresh Git cache (this component) | bash=$refresh param1=component param2=$context param3=$stack_name param4=$component dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
486
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
487
|
+
print_item "$p2" "Refresh Git cache (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
488
|
+
fi
|
|
489
|
+
fi
|
|
406
490
|
fi
|
|
407
491
|
|
|
492
|
+
print_sep "$p2"
|
|
408
493
|
print_item "$p2" "HEAD: ${branch:-"(unknown)"} ${head:+($head)}"
|
|
409
494
|
print_item "$p2" "Upstream: ${upstream:-"(none)"}"
|
|
410
495
|
if [[ -n "$ahead" && -n "$behind" ]]; then
|
|
@@ -412,31 +497,22 @@ render_component_repo() {
|
|
|
412
497
|
fi
|
|
413
498
|
print_item "$p2" "Working tree: ${dirty}"
|
|
414
499
|
|
|
415
|
-
local main_branch main_upstream main_ab
|
|
416
|
-
main_branch="$(git_main_branch_name "$active_dir")"
|
|
417
500
|
if [[ -n "$main_branch" ]]; then
|
|
418
|
-
main_upstream="$(git_branch_upstream_short "$active_dir" "$main_branch")"
|
|
419
|
-
main_ab="$(git_branch_ahead_behind "$active_dir" "$main_branch")"
|
|
420
501
|
if [[ -n "$main_upstream" ]]; then
|
|
421
502
|
print_item "$p2" "Main: ${main_branch} → ${main_upstream}"
|
|
422
503
|
else
|
|
423
504
|
print_item "$p2" "Main: ${main_branch} → (no upstream)"
|
|
424
505
|
fi
|
|
425
|
-
if [[ -n "$
|
|
426
|
-
print_item "$p2" "Main ahead/behind: $
|
|
506
|
+
if [[ -n "$main_ahead" && -n "$main_behind" ]]; then
|
|
507
|
+
print_item "$p2" "Main ahead/behind: ${main_ahead}/${main_behind}"
|
|
427
508
|
fi
|
|
428
509
|
|
|
429
510
|
# Always show comparisons against origin/* and upstream/* when those remote refs exist.
|
|
430
511
|
# (These reflect your last fetch; we do not auto-fetch in the menu.)
|
|
431
|
-
local oref uref
|
|
432
|
-
oref="$(git_remote_main_ref "$active_dir" "origin")"
|
|
433
|
-
uref="$(git_remote_main_ref "$active_dir" "upstream")"
|
|
434
512
|
if [[ -n "$oref" ]]; then
|
|
435
513
|
local oref_short="${oref#refs/remotes/}"
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if [[ -n "$oab" ]]; then
|
|
439
|
-
print_item "$p2" "Origin: ${oref_short} ahead/behind: $(echo "$oab" | cut -d'|' -f1)/$(echo "$oab" | cut -d'|' -f2)"
|
|
514
|
+
if [[ -n "$o_ahead" && -n "$o_behind" ]]; then
|
|
515
|
+
print_item "$p2" "Origin: ${oref_short} ahead/behind: ${o_ahead}/${o_behind}"
|
|
440
516
|
else
|
|
441
517
|
print_item "$p2" "Origin: ${oref_short}"
|
|
442
518
|
fi
|
|
@@ -445,10 +521,8 @@ render_component_repo() {
|
|
|
445
521
|
fi
|
|
446
522
|
if [[ -n "$uref" ]]; then
|
|
447
523
|
local uref_short="${uref#refs/remotes/}"
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if [[ -n "$uab" ]]; then
|
|
451
|
-
print_item "$p2" "Upstream: ${uref_short} ahead/behind: $(echo "$uab" | cut -d'|' -f1)/$(echo "$uab" | cut -d'|' -f2)"
|
|
524
|
+
if [[ -n "$u_ahead" && -n "$u_behind" ]]; then
|
|
525
|
+
print_item "$p2" "Upstream: ${uref_short} ahead/behind: ${u_ahead}/${u_behind}"
|
|
452
526
|
else
|
|
453
527
|
print_item "$p2" "Upstream: ${uref_short}"
|
|
454
528
|
fi
|
|
@@ -457,15 +531,16 @@ render_component_repo() {
|
|
|
457
531
|
fi
|
|
458
532
|
fi
|
|
459
533
|
|
|
460
|
-
|
|
461
|
-
|
|
534
|
+
local wt_count
|
|
535
|
+
# If cache didn't populate wt_count, fall back to empty string.
|
|
536
|
+
wt_count="${wt_count:-}"
|
|
462
537
|
|
|
463
538
|
# Quick actions
|
|
464
539
|
print_sep "$p2"
|
|
465
540
|
print_item "$p2" "Open folder | bash=/usr/bin/open param1='$active_dir' terminal=false"
|
|
466
541
|
|
|
467
542
|
if [[ -n "$PNPM_BIN" ]]; then
|
|
468
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
543
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
469
544
|
# Run via stack wrappers when in a stack context so env-file stays authoritative.
|
|
470
545
|
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
471
546
|
print_item "$p2" "Status (active) | bash=$PNPM_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=status param6=$component dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
@@ -518,11 +593,19 @@ render_component_repo() {
|
|
|
518
593
|
print_item "$p2" "$wt_label"
|
|
519
594
|
local p3="${p2}--"
|
|
520
595
|
local tsv
|
|
521
|
-
|
|
596
|
+
if [[ "$git_mode" == "cached" && -f "$wts" ]]; then
|
|
597
|
+
tsv="$(cat "$wts" 2>/dev/null || true)"
|
|
598
|
+
else
|
|
599
|
+
tsv="$(git_worktrees_tsv "$active_dir" 2>/dev/null || true)"
|
|
600
|
+
fi
|
|
522
601
|
if [[ -z "$tsv" ]]; then
|
|
523
602
|
print_item "$p3" "No worktrees found | color=$GRAY"
|
|
524
603
|
else
|
|
525
|
-
|
|
604
|
+
# Worktrees live alongside the component checkout at: <componentsRoot>/.worktrees/<component>/...
|
|
605
|
+
local components_root default_path root
|
|
606
|
+
components_root="$(dirname "$active_dir")"
|
|
607
|
+
default_path="$components_root/$component"
|
|
608
|
+
root="$components_root/.worktrees/$component/"
|
|
526
609
|
local shown=0
|
|
527
610
|
while IFS=$'\t' read -r wt_path wt_branchref; do
|
|
528
611
|
[[ -n "$wt_path" ]] || continue
|
|
@@ -534,11 +617,13 @@ render_component_repo() {
|
|
|
534
617
|
|
|
535
618
|
local label=""
|
|
536
619
|
local spec=""
|
|
537
|
-
if [[ "$wt_path" == "$
|
|
620
|
+
if [[ "$wt_path" == "$default_path" ]]; then
|
|
621
|
+
spec="default"
|
|
622
|
+
label="default"
|
|
623
|
+
elif [[ "$wt_path" == "$root"* ]]; then
|
|
538
624
|
spec="${wt_path#"$root"}"
|
|
539
625
|
label="$spec"
|
|
540
626
|
else
|
|
541
|
-
spec="$wt_path"
|
|
542
627
|
label="$(shorten_path "$wt_path" 52)"
|
|
543
628
|
fi
|
|
544
629
|
|
|
@@ -549,18 +634,24 @@ render_component_repo() {
|
|
|
549
634
|
label="(active) $label"
|
|
550
635
|
fi
|
|
551
636
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
637
|
+
print_item "$p3" "$label"
|
|
638
|
+
|
|
639
|
+
# Only show "use" actions when we can express the worktree as a spec (default or under .worktrees).
|
|
640
|
+
# Some git worktrees can exist outside our managed tree; for those we only offer open/shell actions.
|
|
641
|
+
if [[ -n "$spec" ]]; then
|
|
642
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
643
|
+
print_item "${p3}--" "Use in stack | bash=$PNPM_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=use param6=$component param7=$spec dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
644
|
+
print_item "${p3}--" "Shell (new window) | bash=$PNPM_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=shell param6=$component param7=$spec param8=--new-window dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
645
|
+
print_item "${p3}--" "Open in VS Code | bash=$PNPM_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=code param6=$component param7=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
646
|
+
print_item "${p3}--" "Open in Cursor | bash=$PNPM_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=cursor param6=$component param7=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
647
|
+
else
|
|
648
|
+
print_item "${p3}--" "Use (main) | bash=$PNPM_BIN param1=wt param2=use param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
649
|
+
print_item "${p3}--" "Shell (new window) | bash=$PNPM_TERM param1=wt param2=shell param3=$component param4=$spec param5=--new-window dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
650
|
+
print_item "${p3}--" "Open in VS Code | bash=$PNPM_BIN param1=wt param2=code param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
651
|
+
print_item "${p3}--" "Open in Cursor | bash=$PNPM_BIN param1=wt param2=cursor param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
652
|
+
fi
|
|
558
653
|
else
|
|
559
|
-
print_item "$p3" "$
|
|
560
|
-
print_item "${p3}--" "Use (main) | bash=$PNPM_BIN param1=wt param2=use param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
561
|
-
print_item "${p3}--" "Shell (new window) | bash=$PNPM_TERM param1=wt param2=shell param3=$component param4=$spec param5=--new-window dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
562
|
-
print_item "${p3}--" "Open in VS Code | bash=$PNPM_BIN param1=wt param2=code param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
563
|
-
print_item "${p3}--" "Open in Cursor | bash=$PNPM_BIN param1=wt param2=cursor param3=$component param4=$spec dir=$HAPPY_LOCAL_DIR terminal=false"
|
|
654
|
+
print_item "${p3}--" "Open folder | bash=/usr/bin/open param1='$wt_path' terminal=false"
|
|
564
655
|
fi
|
|
565
656
|
done <<<"$tsv"
|
|
566
657
|
fi
|
|
@@ -574,26 +665,55 @@ render_components_menu() {
|
|
|
574
665
|
local stack_name="$3"
|
|
575
666
|
local env_file="$4"
|
|
576
667
|
|
|
668
|
+
local t0 t1
|
|
669
|
+
t0="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
670
|
+
|
|
577
671
|
print_item "$prefix" "Components | sfimage=cube"
|
|
578
672
|
local p2="${prefix}--"
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
if [[
|
|
582
|
-
|
|
583
|
-
|
|
673
|
+
|
|
674
|
+
# Background auto-refresh: keep menu refresh snappy but update git cache when TTL expires.
|
|
675
|
+
if [[ "$(git_cache_mode)" == "cached" ]]; then
|
|
676
|
+
local scope
|
|
677
|
+
scope="$(git_cache_auto_refresh_scope)"
|
|
678
|
+
local refresh="$HAPPY_LOCAL_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
679
|
+
if [[ -x "$refresh" ]]; then
|
|
680
|
+
if [[ "$scope" == "all" ]]; then
|
|
681
|
+
git_cache_maybe_refresh_async "all" "$refresh" all
|
|
682
|
+
elif [[ "$scope" == "main" && "$context" == "main" ]]; then
|
|
683
|
+
git_cache_maybe_refresh_async "main" "$refresh" main
|
|
684
|
+
fi
|
|
685
|
+
fi
|
|
584
686
|
fi
|
|
585
687
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
688
|
+
# Git cache controls (to keep the menu refresh fast while retaining rich inline worktrees UI).
|
|
689
|
+
local refresh="$HAPPY_LOCAL_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
690
|
+
if [[ -f "$refresh" ]]; then
|
|
691
|
+
local mode ttl
|
|
692
|
+
mode="$(git_cache_mode)"
|
|
693
|
+
ttl="$(git_cache_ttl_sec)"
|
|
694
|
+
print_item "$p2" "Git cache | sfimage=arrow.triangle.2.circlepath"
|
|
695
|
+
local p3="${p2}--"
|
|
696
|
+
print_item "$p3" "Mode: ${mode} (default: cached)"
|
|
697
|
+
print_item "$p3" "TTL: ${ttl}s (set HAPPY_STACKS_SWIFTBAR_GIT_TTL_SEC)"
|
|
698
|
+
print_sep "$p3"
|
|
699
|
+
if [[ "$context" == "main" ]]; then
|
|
700
|
+
print_item "$p3" "Refresh now (main components) | bash=$refresh param1=main dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
701
|
+
print_item "$p3" "Refresh now (all stacks/components) | bash=$refresh param1=all dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
702
|
+
else
|
|
703
|
+
print_item "$p3" "Refresh now (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
592
704
|
fi
|
|
593
|
-
|
|
594
|
-
if [[ "$any" == "0" ]]; then
|
|
595
|
-
print_item "$p2" "No components found under components/ | color=$GRAY"
|
|
705
|
+
print_sep "$p2"
|
|
596
706
|
fi
|
|
707
|
+
|
|
708
|
+
# Always render the known components using the resolved component dirs (env file → env.local/.env → fallback),
|
|
709
|
+
# instead of assuming they live under `~/.happy-stacks/workspace/components`.
|
|
710
|
+
for c in happy happy-cli happy-server-light happy-server; do
|
|
711
|
+
render_component_repo "$p2" "$c" "$context" "$stack_name" "$env_file"
|
|
712
|
+
print_sep "$p2"
|
|
713
|
+
done
|
|
714
|
+
|
|
715
|
+
t1="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
716
|
+
swiftbar_profile_log "time" "label=render_components_menu" "context=${context}" "stack=${stack_name}" "ms=$((t1 - t0))"
|
|
597
717
|
}
|
|
598
718
|
|
|
599
719
|
render_stack_overview_item() {
|
|
@@ -644,14 +764,20 @@ collect_stack_status() {
|
|
|
644
764
|
daemon_uptime="$(get_daemon_uptime "$cli_home_dir")"
|
|
645
765
|
last_heartbeat="$(get_last_heartbeat "$cli_home_dir")"
|
|
646
766
|
|
|
647
|
-
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
|
|
648
767
|
local launchagent_status autostart_pid autostart_metrics
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
768
|
+
if swiftbar_is_sandboxed; then
|
|
769
|
+
launchagent_status="sandbox_disabled"
|
|
770
|
+
autostart_pid=""
|
|
771
|
+
autostart_metrics=""
|
|
772
|
+
else
|
|
773
|
+
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
|
|
774
|
+
launchagent_status="$(check_launchagent_status "$label" "$plist_path")"
|
|
775
|
+
autostart_pid=""
|
|
776
|
+
autostart_metrics=""
|
|
777
|
+
if [[ "$launchagent_status" != "not_installed" ]]; then
|
|
778
|
+
autostart_pid="$(launchagent_pid_for_label "$label")"
|
|
779
|
+
autostart_metrics="$(get_process_metrics "$autostart_pid")"
|
|
780
|
+
fi
|
|
655
781
|
fi
|
|
656
782
|
|
|
657
783
|
local level
|
|
@@ -688,10 +814,21 @@ render_stack_info() {
|
|
|
688
814
|
local tailscale_url="$9" # optional
|
|
689
815
|
|
|
690
816
|
# Avoid low-contrast gray in the main list; keep it readable in both light/dark.
|
|
691
|
-
print_item "$prefix" "Stack details | sfimage=
|
|
817
|
+
print_item "$prefix" "Stack details | sfimage=server.rack"
|
|
692
818
|
local p2="${prefix}--"
|
|
693
819
|
print_item "$p2" "Server component: ${server_component}"
|
|
694
|
-
|
|
820
|
+
local pinned_port=""
|
|
821
|
+
if [[ -n "$env_file" && -f "$env_file" ]]; then
|
|
822
|
+
pinned_port="$(dotenv_get "$env_file" "HAPPY_STACKS_SERVER_PORT")"
|
|
823
|
+
[[ -z "$pinned_port" ]] && pinned_port="$(dotenv_get "$env_file" "HAPPY_LOCAL_SERVER_PORT")"
|
|
824
|
+
fi
|
|
825
|
+
local port_display="$port"
|
|
826
|
+
if [[ -z "$port_display" ]]; then
|
|
827
|
+
port_display="ephemeral (not running)"
|
|
828
|
+
elif [[ -z "$pinned_port" ]]; then
|
|
829
|
+
port_display="${port_display} (ephemeral)"
|
|
830
|
+
fi
|
|
831
|
+
print_item "$p2" "Port: ${port_display}"
|
|
695
832
|
print_item "$p2" "Label: ${label}"
|
|
696
833
|
[[ -n "$env_file" ]] && print_item "$p2" "Env: $(shorten_path "$env_file" 52)"
|
|
697
834
|
[[ -n "$tailscale_url" ]] && print_item "$p2" "Tailscale: $(shorten_text "$tailscale_url" 52)"
|
|
@@ -718,12 +855,16 @@ render_stack_info() {
|
|
|
718
855
|
fi
|
|
719
856
|
print_sep "$p2"
|
|
720
857
|
|
|
721
|
-
local plist="$HOME/Library/LaunchAgents/${label}.plist"
|
|
722
858
|
local svc_installed="0"
|
|
723
|
-
|
|
859
|
+
if ! swiftbar_is_sandboxed; then
|
|
860
|
+
local plist="$HOME/Library/LaunchAgents/${label}.plist"
|
|
861
|
+
[[ -f "$plist" ]] && svc_installed="1"
|
|
862
|
+
fi
|
|
863
|
+
local menu_mode
|
|
864
|
+
menu_mode="$(resolve_menubar_mode)"
|
|
724
865
|
|
|
725
866
|
if [[ "$stack_name" == "main" ]]; then
|
|
726
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
867
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
727
868
|
if [[ "$svc_installed" == "1" ]]; then
|
|
728
869
|
# Status-aware: only show start/stop based on whether the stack is running.
|
|
729
870
|
if [[ "${MAIN_LEVEL:-}" == "red" ]]; then
|
|
@@ -736,16 +877,18 @@ render_stack_info() {
|
|
|
736
877
|
if [[ "${MAIN_LEVEL:-}" == "red" ]]; then
|
|
737
878
|
print_item "$p2" "Start (foreground) | bash=$PNPM_TERM param1=start dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
738
879
|
else
|
|
739
|
-
print_item "$p2" "Stop
|
|
880
|
+
print_item "$p2" "Stop stack | bash=$PNPM_BIN param1=stack param2=stop param3=main dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
740
881
|
fi
|
|
741
882
|
fi
|
|
742
|
-
|
|
883
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
884
|
+
print_item "$p2" "Dev mode | bash=$PNPM_TERM param1=dev dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
885
|
+
fi
|
|
743
886
|
print_item "$p2" "Build UI | bash=$PNPM_TERM param1=build dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
744
887
|
print_item "$p2" "Doctor | bash=$PNPM_TERM param1=stack:doctor dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
745
888
|
return
|
|
746
889
|
fi
|
|
747
890
|
|
|
748
|
-
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/
|
|
891
|
+
local PNPM_TERM="$HAPPY_LOCAL_DIR/extras/swiftbar/happys-term.sh"
|
|
749
892
|
if [[ "$svc_installed" == "1" ]]; then
|
|
750
893
|
# Status-aware: only show start/stop based on whether the stack is running.
|
|
751
894
|
if [[ "$STACK_LEVEL" == "red" ]]; then
|
|
@@ -758,17 +901,21 @@ render_stack_info() {
|
|
|
758
901
|
if [[ "$STACK_LEVEL" == "red" ]]; then
|
|
759
902
|
print_item "$p2" "Start (foreground) | bash=$PNPM_TERM param1=stack param2=start param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
760
903
|
else
|
|
761
|
-
print_item "$p2" "Stop
|
|
904
|
+
print_item "$p2" "Stop stack | bash=$PNPM_BIN param1=stack param2=stop param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
762
905
|
fi
|
|
763
906
|
fi
|
|
764
|
-
|
|
907
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
908
|
+
print_item "$p2" "Dev mode | bash=$PNPM_TERM param1=stack param2=dev param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
909
|
+
fi
|
|
765
910
|
print_item "$p2" "Build UI | bash=$PNPM_TERM param1=stack param2=build param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
766
911
|
print_item "$p2" "Doctor | bash=$PNPM_TERM param1=stack param2=doctor param3=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
767
|
-
|
|
768
|
-
|
|
912
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
913
|
+
print_item "$p2" "Edit stack (interactive) | bash=$PNPM_TERM param1=stack param2=edit param3=$stack_name param4=--interactive dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
914
|
+
print_item "$p2" "Select worktrees (interactive) | bash=$PNPM_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=use param6=--interactive dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
915
|
+
fi
|
|
769
916
|
|
|
770
917
|
local pr_helper="$HAPPY_LOCAL_DIR/extras/swiftbar/wt-pr.sh"
|
|
771
|
-
if [[ -x "$pr_helper" ]]; then
|
|
918
|
+
if [[ "$menu_mode" != "selfhost" && -x "$pr_helper" ]]; then
|
|
772
919
|
print_item "$p2" "PR worktree into this stack (prompt) | bash=$pr_helper param1=_prompt_ param2=$stack_name dir=$HAPPY_LOCAL_DIR terminal=false refresh=true"
|
|
773
920
|
fi
|
|
774
921
|
}
|