@happier-dev/stack 0.1.0-preview.74.1

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.
Files changed (439) hide show
  1. package/README.md +501 -0
  2. package/bin/hstack.mjs +348 -0
  3. package/docs/codex-mcp-resume.md +129 -0
  4. package/docs/edison.md +74 -0
  5. package/docs/forking-and-branding.md +189 -0
  6. package/docs/happy-development.md +22 -0
  7. package/docs/isolated-linux-vm.md +243 -0
  8. package/docs/menubar.md +244 -0
  9. package/docs/mobile-ios.md +322 -0
  10. package/docs/monorepo-migration.md +20 -0
  11. package/docs/paths-and-env.md +154 -0
  12. package/docs/remote-access.md +43 -0
  13. package/docs/server-flavors.md +147 -0
  14. package/docs/stacks.md +330 -0
  15. package/docs/tauri.md +60 -0
  16. package/docs/worktrees-and-forks.md +133 -0
  17. package/extras/swiftbar/auth-login.sh +29 -0
  18. package/extras/swiftbar/git-cache-refresh.sh +122 -0
  19. package/extras/swiftbar/hstack-term.sh +133 -0
  20. package/extras/swiftbar/hstack.5s.sh +296 -0
  21. package/extras/swiftbar/hstack.sh +35 -0
  22. package/extras/swiftbar/icons/happy-green.png +0 -0
  23. package/extras/swiftbar/icons/happy-orange.png +0 -0
  24. package/extras/swiftbar/icons/happy-red.png +0 -0
  25. package/extras/swiftbar/icons/logo-white.png +0 -0
  26. package/extras/swiftbar/install.sh +265 -0
  27. package/extras/swiftbar/lib/git.sh +629 -0
  28. package/extras/swiftbar/lib/icons.sh +92 -0
  29. package/extras/swiftbar/lib/render.sh +999 -0
  30. package/extras/swiftbar/lib/system.sh +244 -0
  31. package/extras/swiftbar/lib/utils.sh +717 -0
  32. package/extras/swiftbar/set-interval.sh +65 -0
  33. package/extras/swiftbar/set-server-flavor.sh +61 -0
  34. package/extras/swiftbar/wt-pr.sh +140 -0
  35. package/node_modules/@happier-dev/cli-common/README.md +6 -0
  36. package/node_modules/@happier-dev/cli-common/dist/index.d.ts +4 -0
  37. package/node_modules/@happier-dev/cli-common/dist/index.d.ts.map +1 -0
  38. package/node_modules/@happier-dev/cli-common/dist/index.js +4 -0
  39. package/node_modules/@happier-dev/cli-common/dist/index.js.map +1 -0
  40. package/node_modules/@happier-dev/cli-common/dist/links/index.d.ts +18 -0
  41. package/node_modules/@happier-dev/cli-common/dist/links/index.d.ts.map +1 -0
  42. package/node_modules/@happier-dev/cli-common/dist/links/index.js +25 -0
  43. package/node_modules/@happier-dev/cli-common/dist/links/index.js.map +1 -0
  44. package/node_modules/@happier-dev/cli-common/dist/links.d.ts +2 -0
  45. package/node_modules/@happier-dev/cli-common/dist/links.d.ts.map +1 -0
  46. package/node_modules/@happier-dev/cli-common/dist/links.js +2 -0
  47. package/node_modules/@happier-dev/cli-common/dist/links.js.map +1 -0
  48. package/node_modules/@happier-dev/cli-common/dist/update/index.d.ts +67 -0
  49. package/node_modules/@happier-dev/cli-common/dist/update/index.d.ts.map +1 -0
  50. package/node_modules/@happier-dev/cli-common/dist/update/index.js +259 -0
  51. package/node_modules/@happier-dev/cli-common/dist/update/index.js.map +1 -0
  52. package/node_modules/@happier-dev/cli-common/dist/workspaces/index.d.ts +17 -0
  53. package/node_modules/@happier-dev/cli-common/dist/workspaces/index.d.ts.map +1 -0
  54. package/node_modules/@happier-dev/cli-common/dist/workspaces/index.js +80 -0
  55. package/node_modules/@happier-dev/cli-common/dist/workspaces/index.js.map +1 -0
  56. package/node_modules/@happier-dev/cli-common/package.json +26 -0
  57. package/package.json +77 -0
  58. package/scripts/auth.mjs +1829 -0
  59. package/scripts/auth_copy_from_pglite_lock_in_use.integration.test.mjs +90 -0
  60. package/scripts/auth_copy_from_runCapture.integration.test.mjs +447 -0
  61. package/scripts/auth_help_cmd.test.mjs +28 -0
  62. package/scripts/auth_login_flow_in_tty.test.mjs +100 -0
  63. package/scripts/auth_login_force_default.test.mjs +66 -0
  64. package/scripts/auth_login_guided_server_no_expo.test.mjs +126 -0
  65. package/scripts/auth_login_method_override.test.mjs +67 -0
  66. package/scripts/auth_login_print_includes_configure_links.test.mjs +99 -0
  67. package/scripts/auth_status_server_validation.integration.test.mjs +140 -0
  68. package/scripts/build.mjs +266 -0
  69. package/scripts/bundleWorkspaceDeps.mjs +38 -0
  70. package/scripts/bundleWorkspaceDeps.test.mjs +77 -0
  71. package/scripts/ci.mjs +135 -0
  72. package/scripts/ci.test.mjs +50 -0
  73. package/scripts/cli-link.mjs +57 -0
  74. package/scripts/completion.mjs +395 -0
  75. package/scripts/contrib.mjs +333 -0
  76. package/scripts/daemon.mjs +1160 -0
  77. package/scripts/daemon.status_scope.test.mjs +51 -0
  78. package/scripts/daemon_cmd.mjs +26 -0
  79. package/scripts/daemon_dist_guard.test.mjs +171 -0
  80. package/scripts/daemon_invalid_auth_reseed_stack_name.integration.test.mjs +608 -0
  81. package/scripts/daemon_server_scoped_state.test.mjs +49 -0
  82. package/scripts/daemon_start_verification.integration.test.mjs +296 -0
  83. package/scripts/dev.mjs +545 -0
  84. package/scripts/doctor.mjs +340 -0
  85. package/scripts/doctor_cmd.test.mjs +22 -0
  86. package/scripts/doctor_ui_index_missing.test.mjs +37 -0
  87. package/scripts/eas.mjs +367 -0
  88. package/scripts/eas_platform_parsing.test.mjs +63 -0
  89. package/scripts/edison.mjs +1848 -0
  90. package/scripts/env.mjs +149 -0
  91. package/scripts/env_cmd.test.mjs +118 -0
  92. package/scripts/exit_cleanup_kills_detached_children_on_crash.integration.test.mjs +80 -0
  93. package/scripts/happier.mjs +82 -0
  94. package/scripts/import.mjs +1327 -0
  95. package/scripts/init.mjs +464 -0
  96. package/scripts/install.mjs +550 -0
  97. package/scripts/lint.mjs +177 -0
  98. package/scripts/menubar.mjs +202 -0
  99. package/scripts/migrate.mjs +318 -0
  100. package/scripts/mobile.mjs +353 -0
  101. package/scripts/mobile_dev_client.mjs +87 -0
  102. package/scripts/monorepo.mjs +2234 -0
  103. package/scripts/monorepo_port.apply.integration.test.mjs +680 -0
  104. package/scripts/monorepo_port.conflicts.integration.test.mjs +454 -0
  105. package/scripts/monorepo_port.validation.integration.test.mjs +486 -0
  106. package/scripts/orchestrated_stack_auth_flow.test.mjs +134 -0
  107. package/scripts/orchestrated_stack_auth_flow_resolve_port.test.mjs +98 -0
  108. package/scripts/orchestrated_stack_auth_flow_webapp_url.test.mjs +119 -0
  109. package/scripts/pack.mjs +257 -0
  110. package/scripts/pack.test.mjs +68 -0
  111. package/scripts/pglite_lock.integration.test.mjs +152 -0
  112. package/scripts/provision/linux-ubuntu-e2e.sh +132 -0
  113. package/scripts/provision/linux-ubuntu-review-pr.sh +66 -0
  114. package/scripts/provision/macos-lima-happy-vm.sh +192 -0
  115. package/scripts/provision/macos-lima-hstack-e2e.sh +100 -0
  116. package/scripts/release.mjs +53 -0
  117. package/scripts/release_binary_smoke.integration.test.mjs +138 -0
  118. package/scripts/review.mjs +1752 -0
  119. package/scripts/review_pr.mjs +435 -0
  120. package/scripts/run.mjs +561 -0
  121. package/scripts/run_script_with_stack_env.restart_port_reuse.test.mjs +30 -0
  122. package/scripts/self.mjs +465 -0
  123. package/scripts/self_host.mjs +9 -0
  124. package/scripts/self_host_binary_smoke.integration.test.mjs +74 -0
  125. package/scripts/self_host_runtime.mjs +883 -0
  126. package/scripts/self_host_runtime.test.mjs +82 -0
  127. package/scripts/self_host_systemd.real.integration.test.mjs +367 -0
  128. package/scripts/server_flavor.mjs +148 -0
  129. package/scripts/service.mjs +868 -0
  130. package/scripts/service_mode_help.test.mjs +27 -0
  131. package/scripts/setup.mjs +1324 -0
  132. package/scripts/setup_non_interactive_flag.test.mjs +60 -0
  133. package/scripts/setup_pr.mjs +605 -0
  134. package/scripts/setup_pr_orchestrated_auth_flow_util_import.test.mjs +117 -0
  135. package/scripts/stack/command_arguments.mjs +91 -0
  136. package/scripts/stack/copy_auth_from_stack.mjs +111 -0
  137. package/scripts/stack/delegated_script_commands.mjs +92 -0
  138. package/scripts/stack/help_text.mjs +110 -0
  139. package/scripts/stack/port_reservation.mjs +74 -0
  140. package/scripts/stack/repo_checkout_resolution.mjs +31 -0
  141. package/scripts/stack/run_script_with_stack_env.mjs +634 -0
  142. package/scripts/stack/stack_daemon_command.mjs +219 -0
  143. package/scripts/stack/stack_delegated_help.mjs +81 -0
  144. package/scripts/stack/stack_environment.mjs +151 -0
  145. package/scripts/stack/stack_environment.sanitization.test.mjs +75 -0
  146. package/scripts/stack/stack_happier_passthrough_command.mjs +63 -0
  147. package/scripts/stack/stack_info_snapshot.mjs +167 -0
  148. package/scripts/stack/stack_mobile_install_command.mjs +61 -0
  149. package/scripts/stack/stack_resume_command.mjs +76 -0
  150. package/scripts/stack/stack_stop_command.mjs +34 -0
  151. package/scripts/stack/stack_workspace_command.mjs +83 -0
  152. package/scripts/stack/transient_repo_overrides.mjs +29 -0
  153. package/scripts/stack.mjs +2388 -0
  154. package/scripts/stack_archive_cmd.integration.test.mjs +31 -0
  155. package/scripts/stack_audit_fix_light_env.test.mjs +129 -0
  156. package/scripts/stack_background_pinned_stack_json.test.mjs +81 -0
  157. package/scripts/stack_copy_auth_server_scoped.test.mjs +243 -0
  158. package/scripts/stack_daemon_cmd.integration.test.mjs +484 -0
  159. package/scripts/stack_eas_help.test.mjs +72 -0
  160. package/scripts/stack_editor_workspace_monorepo_root.test.mjs +102 -0
  161. package/scripts/stack_env_cmd.test.mjs +107 -0
  162. package/scripts/stack_guided_login_bundle_error_parse.test.mjs +20 -0
  163. package/scripts/stack_guided_login_inner_invocation.test.mjs +46 -0
  164. package/scripts/stack_happy_cmd.integration.test.mjs +263 -0
  165. package/scripts/stack_info_snapshot_running_status.test.mjs +186 -0
  166. package/scripts/stack_interactive_monorepo_group.test.mjs +128 -0
  167. package/scripts/stack_monorepo_defaults.test.mjs +31 -0
  168. package/scripts/stack_monorepo_repo_dev_token.test.mjs +32 -0
  169. package/scripts/stack_monorepo_server_light_from_happy_spec.test.mjs +37 -0
  170. package/scripts/stack_new_name_normalize_cmd.test.mjs +38 -0
  171. package/scripts/stack_pr_name_normalize_cmd.test.mjs +84 -0
  172. package/scripts/stack_resume_cmd.integration.test.mjs +134 -0
  173. package/scripts/stack_server_flavors_defaults.test.mjs +64 -0
  174. package/scripts/stack_shorthand_cmd.integration.test.mjs +74 -0
  175. package/scripts/stack_stop_sweeps_legacy_infra_without_kind.integration.test.mjs +44 -0
  176. package/scripts/stack_stop_sweeps_when_runtime_missing.integration.test.mjs +42 -0
  177. package/scripts/stack_stop_sweeps_when_runtime_stale.integration.test.mjs +50 -0
  178. package/scripts/stack_wt_list.test.mjs +117 -0
  179. package/scripts/start_ui_required_default.test.mjs +63 -0
  180. package/scripts/stop.mjs +190 -0
  181. package/scripts/stopStackWithEnv_no_autosweep_when_runtime_missing.integration.test.mjs +95 -0
  182. package/scripts/swiftbar_git_monorepo_cmd.test.mjs +75 -0
  183. package/scripts/swiftbar_render_monorepo_wt_actions.integration.test.mjs +116 -0
  184. package/scripts/swiftbar_utils_cmd.test.mjs +92 -0
  185. package/scripts/swiftbar_wt_pr_backcompat.test.mjs +162 -0
  186. package/scripts/systemd_unit_info.test.mjs +24 -0
  187. package/scripts/tailscale.mjs +490 -0
  188. package/scripts/test_ci.mjs +36 -0
  189. package/scripts/test_cmd.mjs +274 -0
  190. package/scripts/test_cmd.test.mjs +133 -0
  191. package/scripts/test_integration.mjs +33 -0
  192. package/scripts/testkit/auth_testkit.mjs +121 -0
  193. package/scripts/testkit/doctor_testkit.mjs +68 -0
  194. package/scripts/testkit/monorepo_port_testkit.mjs +157 -0
  195. package/scripts/testkit/stack_archive_command_testkit.mjs +55 -0
  196. package/scripts/testkit/stack_new_monorepo_testkit.mjs +83 -0
  197. package/scripts/testkit/stack_script_command_testkit.mjs +27 -0
  198. package/scripts/testkit/stack_stop_sweeps_testkit.mjs +172 -0
  199. package/scripts/testkit/worktrees_monorepo_testkit.mjs +53 -0
  200. package/scripts/tools.mjs +70 -0
  201. package/scripts/tui.mjs +914 -0
  202. package/scripts/tui_stopStackForTuiExit_no_autosweep.integration.test.mjs +95 -0
  203. package/scripts/typecheck.mjs +178 -0
  204. package/scripts/ui_gateway.mjs +247 -0
  205. package/scripts/uninstall.mjs +179 -0
  206. package/scripts/utils/auth/credentials_paths.mjs +181 -0
  207. package/scripts/utils/auth/credentials_paths.test.mjs +187 -0
  208. package/scripts/utils/auth/daemon_gate.mjs +66 -0
  209. package/scripts/utils/auth/daemon_gate.test.mjs +116 -0
  210. package/scripts/utils/auth/decode_jwt_payload_unsafe.mjs +16 -0
  211. package/scripts/utils/auth/dev_key.mjs +163 -0
  212. package/scripts/utils/auth/files.mjs +56 -0
  213. package/scripts/utils/auth/guided_pr_auth.mjs +86 -0
  214. package/scripts/utils/auth/guided_stack_web_login.mjs +56 -0
  215. package/scripts/utils/auth/handy_master_secret.mjs +42 -0
  216. package/scripts/utils/auth/interactive_stack_auth.mjs +70 -0
  217. package/scripts/utils/auth/login_ux.mjs +105 -0
  218. package/scripts/utils/auth/orchestrated_stack_auth_flow.mjs +291 -0
  219. package/scripts/utils/auth/sources.mjs +28 -0
  220. package/scripts/utils/auth/stable_scope_id.mjs +91 -0
  221. package/scripts/utils/auth/stable_scope_id.test.mjs +51 -0
  222. package/scripts/utils/auth/stack_guided_login.mjs +438 -0
  223. package/scripts/utils/cli/arg_values.mjs +23 -0
  224. package/scripts/utils/cli/arg_values.test.mjs +43 -0
  225. package/scripts/utils/cli/args.mjs +17 -0
  226. package/scripts/utils/cli/cli.mjs +24 -0
  227. package/scripts/utils/cli/cli_registry.mjs +440 -0
  228. package/scripts/utils/cli/cwd_scope.mjs +158 -0
  229. package/scripts/utils/cli/cwd_scope.test.mjs +154 -0
  230. package/scripts/utils/cli/flags.mjs +17 -0
  231. package/scripts/utils/cli/log_forwarder.mjs +157 -0
  232. package/scripts/utils/cli/normalize.mjs +16 -0
  233. package/scripts/utils/cli/prereqs.mjs +103 -0
  234. package/scripts/utils/cli/prereqs.test.mjs +33 -0
  235. package/scripts/utils/cli/progress.mjs +141 -0
  236. package/scripts/utils/cli/smoke_help.mjs +44 -0
  237. package/scripts/utils/cli/verbosity.mjs +11 -0
  238. package/scripts/utils/cli/wizard.mjs +139 -0
  239. package/scripts/utils/cli/wizard_promptSelect.test.mjs +44 -0
  240. package/scripts/utils/cli/wizard_prompt_worktree_source_lazy.test.mjs +132 -0
  241. package/scripts/utils/cli/wizard_worktree_slug.test.mjs +33 -0
  242. package/scripts/utils/crypto/tokens.mjs +14 -0
  243. package/scripts/utils/dev/daemon.mjs +232 -0
  244. package/scripts/utils/dev/daemon_watch_resilience.test.mjs +224 -0
  245. package/scripts/utils/dev/expo_dev.buildEnv.test.mjs +35 -0
  246. package/scripts/utils/dev/expo_dev.mjs +478 -0
  247. package/scripts/utils/dev/expo_dev.test.mjs +89 -0
  248. package/scripts/utils/dev/expo_dev_restart_port_reservation.test.mjs +120 -0
  249. package/scripts/utils/dev/expo_dev_verbose_logs.test.mjs +60 -0
  250. package/scripts/utils/dev/server.mjs +180 -0
  251. package/scripts/utils/dev_auth_key.mjs +7 -0
  252. package/scripts/utils/edison/git_roots.mjs +30 -0
  253. package/scripts/utils/edison/git_roots.test.mjs +49 -0
  254. package/scripts/utils/env/config.mjs +52 -0
  255. package/scripts/utils/env/dotenv.mjs +32 -0
  256. package/scripts/utils/env/dotenv.test.mjs +32 -0
  257. package/scripts/utils/env/env.mjs +130 -0
  258. package/scripts/utils/env/env_file.mjs +98 -0
  259. package/scripts/utils/env/env_file.test.mjs +49 -0
  260. package/scripts/utils/env/env_local.mjs +25 -0
  261. package/scripts/utils/env/load_env_file.mjs +34 -0
  262. package/scripts/utils/env/read.mjs +30 -0
  263. package/scripts/utils/env/sandbox.mjs +13 -0
  264. package/scripts/utils/env/scrub_env.mjs +69 -0
  265. package/scripts/utils/env/scrub_env.test.mjs +102 -0
  266. package/scripts/utils/env/values.mjs +13 -0
  267. package/scripts/utils/expo/command.mjs +65 -0
  268. package/scripts/utils/expo/expo.mjs +139 -0
  269. package/scripts/utils/expo/expo_state_running.test.mjs +48 -0
  270. package/scripts/utils/expo/metro_ports.mjs +101 -0
  271. package/scripts/utils/expo/metro_ports.test.mjs +35 -0
  272. package/scripts/utils/fs/atomic_dir_swap.mjs +55 -0
  273. package/scripts/utils/fs/atomic_dir_swap.test.mjs +54 -0
  274. package/scripts/utils/fs/file_has_content.mjs +10 -0
  275. package/scripts/utils/fs/fs.mjs +11 -0
  276. package/scripts/utils/fs/json.mjs +25 -0
  277. package/scripts/utils/fs/ops.mjs +29 -0
  278. package/scripts/utils/fs/package_json.mjs +8 -0
  279. package/scripts/utils/fs/tail.mjs +12 -0
  280. package/scripts/utils/git/dev_checkout.mjs +127 -0
  281. package/scripts/utils/git/dev_checkout.test.mjs +115 -0
  282. package/scripts/utils/git/git.mjs +67 -0
  283. package/scripts/utils/git/parse_name_status_z.mjs +21 -0
  284. package/scripts/utils/git/refs.mjs +26 -0
  285. package/scripts/utils/git/worktrees.mjs +323 -0
  286. package/scripts/utils/git/worktrees_monorepo.test.mjs +60 -0
  287. package/scripts/utils/git/worktrees_pathstyle.test.mjs +53 -0
  288. package/scripts/utils/llm/assist.mjs +260 -0
  289. package/scripts/utils/llm/codex_exec.mjs +61 -0
  290. package/scripts/utils/llm/codex_exec.test.mjs +46 -0
  291. package/scripts/utils/llm/hstack_runner.mjs +59 -0
  292. package/scripts/utils/llm/tools.mjs +56 -0
  293. package/scripts/utils/llm/tools.test.mjs +67 -0
  294. package/scripts/utils/menubar/swiftbar.mjs +121 -0
  295. package/scripts/utils/menubar/swiftbar.test.mjs +85 -0
  296. package/scripts/utils/mobile/config.mjs +35 -0
  297. package/scripts/utils/mobile/dev_client_links.mjs +59 -0
  298. package/scripts/utils/mobile/identifiers.mjs +46 -0
  299. package/scripts/utils/mobile/identifiers.test.mjs +41 -0
  300. package/scripts/utils/mobile/ios_xcodeproj_patch.mjs +128 -0
  301. package/scripts/utils/mobile/ios_xcodeproj_patch.test.mjs +131 -0
  302. package/scripts/utils/net/bind_mode.mjs +39 -0
  303. package/scripts/utils/net/dns.mjs +10 -0
  304. package/scripts/utils/net/lan_ip.mjs +24 -0
  305. package/scripts/utils/net/ports.mjs +110 -0
  306. package/scripts/utils/net/tcp_forward.mjs +162 -0
  307. package/scripts/utils/net/url.mjs +30 -0
  308. package/scripts/utils/net/url.test.mjs +29 -0
  309. package/scripts/utils/paths/canonical_home.mjs +15 -0
  310. package/scripts/utils/paths/canonical_home.test.mjs +28 -0
  311. package/scripts/utils/paths/localhost_host.mjs +112 -0
  312. package/scripts/utils/paths/localhost_host.test.mjs +58 -0
  313. package/scripts/utils/paths/paths.mjs +302 -0
  314. package/scripts/utils/paths/paths_env_win32.test.mjs +36 -0
  315. package/scripts/utils/paths/paths_monorepo.test.mjs +58 -0
  316. package/scripts/utils/paths/paths_server_flavors.test.mjs +50 -0
  317. package/scripts/utils/paths/runtime.mjs +41 -0
  318. package/scripts/utils/pglite_lock.mjs +107 -0
  319. package/scripts/utils/proc/commands.mjs +33 -0
  320. package/scripts/utils/proc/exit_cleanup.mjs +57 -0
  321. package/scripts/utils/proc/happy_monorepo_deps.mjs +37 -0
  322. package/scripts/utils/proc/happy_monorepo_deps.test.mjs +89 -0
  323. package/scripts/utils/proc/ownership.mjs +217 -0
  324. package/scripts/utils/proc/ownership_killProcessGroupOwnedByStack.test.mjs +216 -0
  325. package/scripts/utils/proc/ownership_listPidsWithEnvNeedles.test.mjs +88 -0
  326. package/scripts/utils/proc/package_scripts.mjs +38 -0
  327. package/scripts/utils/proc/package_scripts.test.mjs +58 -0
  328. package/scripts/utils/proc/parallel.mjs +25 -0
  329. package/scripts/utils/proc/pids.mjs +11 -0
  330. package/scripts/utils/proc/pm.mjs +478 -0
  331. package/scripts/utils/proc/pm_spawn.integration.test.mjs +131 -0
  332. package/scripts/utils/proc/pm_stack_cache_env.test.mjs +313 -0
  333. package/scripts/utils/proc/proc.mjs +331 -0
  334. package/scripts/utils/proc/proc.test.mjs +85 -0
  335. package/scripts/utils/proc/terminate.mjs +69 -0
  336. package/scripts/utils/proc/terminate.test.mjs +54 -0
  337. package/scripts/utils/proc/watch.mjs +63 -0
  338. package/scripts/utils/review/augment_runner_integration.test.mjs +105 -0
  339. package/scripts/utils/review/base_ref.mjs +82 -0
  340. package/scripts/utils/review/base_ref.test.mjs +89 -0
  341. package/scripts/utils/review/chunks.mjs +55 -0
  342. package/scripts/utils/review/chunks.test.mjs +107 -0
  343. package/scripts/utils/review/detached_worktree.mjs +61 -0
  344. package/scripts/utils/review/detached_worktree.test.mjs +61 -0
  345. package/scripts/utils/review/findings.mjs +278 -0
  346. package/scripts/utils/review/findings.test.mjs +203 -0
  347. package/scripts/utils/review/head_slice.mjs +132 -0
  348. package/scripts/utils/review/head_slice.test.mjs +117 -0
  349. package/scripts/utils/review/instructions/deep.md +20 -0
  350. package/scripts/utils/review/prompts.mjs +279 -0
  351. package/scripts/utils/review/prompts.test.mjs +77 -0
  352. package/scripts/utils/review/run_reviewers_safe.mjs +12 -0
  353. package/scripts/utils/review/run_reviewers_safe.test.mjs +45 -0
  354. package/scripts/utils/review/runners/augment.mjs +91 -0
  355. package/scripts/utils/review/runners/augment.test.mjs +64 -0
  356. package/scripts/utils/review/runners/claude.mjs +92 -0
  357. package/scripts/utils/review/runners/claude.test.mjs +47 -0
  358. package/scripts/utils/review/runners/coderabbit.mjs +105 -0
  359. package/scripts/utils/review/runners/coderabbit.test.mjs +32 -0
  360. package/scripts/utils/review/runners/codex.mjs +129 -0
  361. package/scripts/utils/review/runners/codex.test.mjs +115 -0
  362. package/scripts/utils/review/slice_mode.mjs +20 -0
  363. package/scripts/utils/review/slice_mode.test.mjs +69 -0
  364. package/scripts/utils/review/sliced_runner.mjs +39 -0
  365. package/scripts/utils/review/sliced_runner.test.mjs +57 -0
  366. package/scripts/utils/review/slices.mjs +140 -0
  367. package/scripts/utils/review/slices.test.mjs +41 -0
  368. package/scripts/utils/review/targets.mjs +23 -0
  369. package/scripts/utils/review/targets.test.mjs +31 -0
  370. package/scripts/utils/review/tool_home_seed.mjs +106 -0
  371. package/scripts/utils/review/tool_home_seed.test.mjs +124 -0
  372. package/scripts/utils/review/uncommitted_ops.mjs +77 -0
  373. package/scripts/utils/review/uncommitted_ops.test.mjs +117 -0
  374. package/scripts/utils/sandbox/review_pr_sandbox.mjs +105 -0
  375. package/scripts/utils/server/apply_server_light_env_defaults.mjs +14 -0
  376. package/scripts/utils/server/flavor_scripts.mjs +138 -0
  377. package/scripts/utils/server/flavor_scripts.test.mjs +115 -0
  378. package/scripts/utils/server/infra/happy_server_infra.mjs +444 -0
  379. package/scripts/utils/server/mobile_api_url.mjs +60 -0
  380. package/scripts/utils/server/mobile_api_url.test.mjs +58 -0
  381. package/scripts/utils/server/port.mjs +55 -0
  382. package/scripts/utils/server/prisma_import.mjs +36 -0
  383. package/scripts/utils/server/prisma_import.test.mjs +78 -0
  384. package/scripts/utils/server/server.mjs +109 -0
  385. package/scripts/utils/server/ui_build_check.mjs +37 -0
  386. package/scripts/utils/server/ui_build_check.test.mjs +70 -0
  387. package/scripts/utils/server/ui_env.mjs +13 -0
  388. package/scripts/utils/server/ui_env.test.mjs +57 -0
  389. package/scripts/utils/server/urls.mjs +100 -0
  390. package/scripts/utils/server/validate.mjs +60 -0
  391. package/scripts/utils/server/validate.test.mjs +76 -0
  392. package/scripts/utils/service/autostart_darwin.mjs +198 -0
  393. package/scripts/utils/service/autostart_darwin.test.mjs +49 -0
  394. package/scripts/utils/service/autostart_darwin_keepalive.test.mjs +19 -0
  395. package/scripts/utils/stack/cli_identities.mjs +29 -0
  396. package/scripts/utils/stack/context.mjs +19 -0
  397. package/scripts/utils/stack/dirs.mjs +26 -0
  398. package/scripts/utils/stack/editor_workspace.mjs +126 -0
  399. package/scripts/utils/stack/interactive_stack_config.mjs +266 -0
  400. package/scripts/utils/stack/interactive_stack_config.port_validation.test.mjs +93 -0
  401. package/scripts/utils/stack/interactive_stack_config.remote_validation.test.mjs +122 -0
  402. package/scripts/utils/stack/interactive_stack_config.stack_name_validation.test.mjs +76 -0
  403. package/scripts/utils/stack/interactive_stack_config_testkit.mjs +18 -0
  404. package/scripts/utils/stack/names.mjs +27 -0
  405. package/scripts/utils/stack/names.test.mjs +26 -0
  406. package/scripts/utils/stack/pr_stack_name.mjs +16 -0
  407. package/scripts/utils/stack/runtime_state.mjs +88 -0
  408. package/scripts/utils/stack/stacks.mjs +40 -0
  409. package/scripts/utils/stack/startup.mjs +370 -0
  410. package/scripts/utils/stack/startup_server_light_dirs.test.mjs +119 -0
  411. package/scripts/utils/stack/startup_server_light_generate.test.mjs +20 -0
  412. package/scripts/utils/stack/startup_server_light_legacy.test.mjs +79 -0
  413. package/scripts/utils/stack/startup_server_light_testkit.mjs +106 -0
  414. package/scripts/utils/stack/stop.mjs +284 -0
  415. package/scripts/utils/stack_context.mjs +1 -0
  416. package/scripts/utils/stack_runtime_state.mjs +1 -0
  417. package/scripts/utils/stacks.mjs +1 -0
  418. package/scripts/utils/tailscale/ip.mjs +116 -0
  419. package/scripts/utils/tauri/stack_overrides.mjs +22 -0
  420. package/scripts/utils/test/collect_test_files.mjs +29 -0
  421. package/scripts/utils/time/get_today_ymd.mjs +7 -0
  422. package/scripts/utils/tui/cleanup.mjs +38 -0
  423. package/scripts/utils/ui/ansi.mjs +47 -0
  424. package/scripts/utils/ui/browser.mjs +31 -0
  425. package/scripts/utils/ui/browser.test.mjs +56 -0
  426. package/scripts/utils/ui/clipboard.mjs +38 -0
  427. package/scripts/utils/ui/layout.mjs +44 -0
  428. package/scripts/utils/ui/qr.mjs +17 -0
  429. package/scripts/utils/ui/terminal_launcher.mjs +129 -0
  430. package/scripts/utils/ui/text.mjs +16 -0
  431. package/scripts/utils/update/auto_update_notice.mjs +93 -0
  432. package/scripts/utils/validate.mjs +5 -0
  433. package/scripts/where.mjs +138 -0
  434. package/scripts/worktrees.mjs +2174 -0
  435. package/scripts/worktrees_archive_cmd.integration.test.mjs +228 -0
  436. package/scripts/worktrees_cursor_monorepo_root.test.mjs +23 -0
  437. package/scripts/worktrees_list_specs_no_recurse.test.mjs +32 -0
  438. package/scripts/worktrees_monorepo_testkit.test.mjs +29 -0
  439. package/scripts/worktrees_monorepo_use_group.test.mjs +41 -0
@@ -0,0 +1,133 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # Open preferred terminal and run a hstack command.
5
+ #
6
+ # Preference order follows wt shell semantics:
7
+ # - HAPPIER_STACK_WT_TERMINAL=ghostty|iterm|terminal|current
8
+ # (also accepts "auto" which tries ghostty->iterm->terminal->current)
9
+ #
10
+ # Notes:
11
+ # - iTerm / Terminal: we run the command automatically via AppleScript.
12
+ # - Ghostty: best-effort; if we can't run the command, we open Ghostty in the dir and copy the command to clipboard.
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ DEFAULT_HOME_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
16
+
17
+ # Prefer explicit env vars, but default to the install location inferred from this script path.
18
+ CANONICAL_HOME_DIR="${HAPPIER_STACK_CANONICAL_HOME_DIR:-$DEFAULT_HOME_DIR}"
19
+ HOME_DIR="${HAPPIER_STACK_HOME_DIR:-$DEFAULT_HOME_DIR}"
20
+
21
+ export HAPPIER_STACK_HOME_DIR="$HOME_DIR"
22
+ export HAPPIER_STACK_CANONICAL_HOME_DIR="$CANONICAL_HOME_DIR"
23
+
24
+ # Prefer running against an explicit repo checkout if provided.
25
+ ROOT_DIR="${HAPPIER_STACK_CLI_ROOT_DIR:-$HOME_DIR}"
26
+
27
+ LIB_DIR="$ROOT_DIR/extras/swiftbar/lib"
28
+ if [[ -f "$LIB_DIR/utils.sh" ]]; then
29
+ # shellcheck source=/dev/null
30
+ source "$LIB_DIR/utils.sh"
31
+ fi
32
+
33
+ WORKDIR="${HAPPIER_STACK_WORKSPACE_DIR:-$(resolve_workspace_dir 2>/dev/null || true)}"
34
+ [[ -z "$WORKDIR" ]] && WORKDIR="$HOME_DIR/workspace"
35
+ if [[ ! -d "$WORKDIR" ]]; then
36
+ WORKDIR="$HOME"
37
+ fi
38
+
39
+ hstack_SH="$ROOT_DIR/extras/swiftbar/hstack.sh"
40
+ if [[ ! -x "$hstack_SH" ]]; then
41
+ echo "missing hstack wrapper: $hstack_SH" >&2
42
+ exit 1
43
+ fi
44
+
45
+ pref_raw="$(echo "${HAPPIER_STACK_WT_TERMINAL:-auto}" | tr '[:upper:]' '[:lower:]')"
46
+ pref="$pref_raw"
47
+ if [[ "$pref" == "" ]]; then pref="auto"; fi
48
+
49
+ cmd=( "$hstack_SH" "$@" )
50
+
51
+ escape_for_osascript_string() {
52
+ local s="$1"
53
+ s="${s//\\/\\\\}"
54
+ s="${s//\"/\\\"}"
55
+ echo "$s"
56
+ }
57
+
58
+ shell_cmd() {
59
+ local joined=""
60
+ local q
61
+ joined="cd \"${WORKDIR//\"/\\\"}\"; "
62
+ for q in "${cmd[@]}"; do
63
+ local escaped
64
+ escaped="$(printf "%s" "$q" | sed "s/'/'\\\\''/g")"
65
+ joined+="'${escaped}' "
66
+ done
67
+ joined+="; echo; echo \"[hstack] done\"; exec /bin/zsh -i"
68
+ echo "$joined"
69
+ }
70
+
71
+ run_iterm() {
72
+ if ! command -v osascript >/dev/null 2>&1; then
73
+ return 1
74
+ fi
75
+ local s
76
+ s="$(shell_cmd)"
77
+ s="$(escape_for_osascript_string "$s")"
78
+ osascript \
79
+ -e 'tell application "iTerm" to activate' \
80
+ -e 'tell application "iTerm" to create window with default profile' \
81
+ -e "tell application \"iTerm\" to tell current session of current window to write text \"${s}\"" >/dev/null
82
+ }
83
+
84
+ run_terminal_app() {
85
+ if ! command -v osascript >/dev/null 2>&1; then
86
+ return 1
87
+ fi
88
+ local s
89
+ s="$(shell_cmd)"
90
+ s="$(escape_for_osascript_string "$s")"
91
+ osascript \
92
+ -e 'tell application "Terminal" to activate' \
93
+ -e "tell application \"Terminal\" to do script \"${s}\"" >/dev/null
94
+ }
95
+
96
+ run_ghostty() {
97
+ if ! command -v ghostty >/dev/null 2>&1; then
98
+ return 1
99
+ fi
100
+
101
+ local s
102
+ s="$(shell_cmd)"
103
+ if ghostty --working-directory "$WORKDIR" -e /bin/zsh -lc "$s" >/dev/null 2>&1; then
104
+ return 0
105
+ fi
106
+
107
+ echo -n "$s" | pbcopy 2>/dev/null || true
108
+ ghostty --working-directory "$WORKDIR" >/dev/null 2>&1 || true
109
+ return 0
110
+ }
111
+
112
+ try_one() {
113
+ local t="$1"
114
+ case "$t" in
115
+ ghostty) run_ghostty ;;
116
+ iterm) run_iterm ;;
117
+ terminal) run_terminal_app ;;
118
+ current) ( cd "$WORKDIR"; exec "${cmd[@]}" ) ;;
119
+ *) return 1 ;;
120
+ esac
121
+ }
122
+
123
+ if [[ "$pref" == "auto" ]]; then
124
+ for t in ghostty iterm terminal current; do
125
+ if try_one "$t"; then
126
+ exit 0
127
+ fi
128
+ done
129
+ exit 1
130
+ fi
131
+
132
+ try_one "$pref"
133
+
@@ -0,0 +1,296 @@
1
+ #!/bin/bash
2
+
3
+ # <xbar.title>hstack</xbar.title>
4
+ # <xbar.version>1.0.0</xbar.version>
5
+ # <xbar.author>hstack</xbar.author>
6
+ # <xbar.author.github>happier-dev</xbar.author.github>
7
+ # <xbar.desc>Monitor and control your Happier stacks from the menu bar</xbar.desc>
8
+ # <xbar.dependencies>node</xbar.dependencies>
9
+ # <swiftbar.hideAbout>true</swiftbar.hideAbout>
10
+ # <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>
11
+ # <swiftbar.hideLastUpdated>false</swiftbar.hideLastUpdated>
12
+ # <swiftbar.hideDisablePlugin>true</swiftbar.hideDisablePlugin>
13
+ # <swiftbar.hideSwiftBar>true</swiftbar.hideSwiftBar>
14
+ # <swiftbar.refreshOnOpen>false</swiftbar.refreshOnOpen>
15
+
16
+ # ============================================================================
17
+ # Configuration
18
+ # ============================================================================
19
+
20
+ # SwiftBar runs with a minimal environment, so users often won't have
21
+ # HAPPIER_STACK_HOME_DIR / HAPPIER_STACK_WORKSPACE_DIR exported.
22
+ # Treat <canonicalHomeDir>/.env as the canonical pointer file (written by `hstack init`).
23
+ # Default: ~/.happier-stack/.env
24
+ CANONICAL_HOME_DIR="${HAPPIER_STACK_CANONICAL_HOME_DIR:-$HOME/.happier-stack}"
25
+ CANONICAL_ENV_FILE="$CANONICAL_HOME_DIR/.env"
26
+
27
+ _dotenv_get_quick() {
28
+ # Usage: _dotenv_get_quick /path/to/env KEY
29
+ local file="$1"
30
+ local key="$2"
31
+ [[ -n "$file" && -n "$key" && -f "$file" ]] || return 0
32
+ local line
33
+ line="$(grep -E "^${key}=" "$file" 2>/dev/null | head -n 1 || true)"
34
+ [[ -n "$line" ]] || return 0
35
+ local v="${line#*=}"
36
+ v="${v%$'\r'}"
37
+ # Strip simple surrounding quotes.
38
+ if [[ "$v" == \"*\" && "$v" == *\" ]]; then v="${v#\"}"; v="${v%\"}"; fi
39
+ if [[ "$v" == \'*\' && "$v" == *\' ]]; then v="${v#\'}"; v="${v%\'}"; fi
40
+ echo "$v"
41
+ }
42
+
43
+ _expand_home_quick() {
44
+ local p="$1"
45
+ if [[ "$p" == "~/"* ]]; then
46
+ echo "$HOME/${p#~/}"
47
+ else
48
+ echo "$p"
49
+ fi
50
+ }
51
+
52
+ _home_from_canonical=""
53
+ if [[ -f "$CANONICAL_ENV_FILE" ]]; then
54
+ _home_from_canonical="$(_dotenv_get_quick "$CANONICAL_ENV_FILE" "HAPPIER_STACK_HOME_DIR")"
55
+ fi
56
+ _home_from_canonical="$(_expand_home_quick "${_home_from_canonical:-}")"
57
+
58
+ export HAPPIER_STACK_HOME_DIR="${HAPPIER_STACK_HOME_DIR:-${_home_from_canonical:-$CANONICAL_HOME_DIR}}"
59
+ export HAPPIER_STACK_CANONICAL_HOME_DIR="$CANONICAL_HOME_DIR"
60
+
61
+ # Colors
62
+ GREEN="#34C759"
63
+ RED="#FF3B30"
64
+ YELLOW="#FFCC00"
65
+ GRAY="#8E8E93"
66
+ BLUE="#007AFF"
67
+
68
+ # ============================================================================
69
+ # Load libs
70
+ # ============================================================================
71
+
72
+ hstack_ROOT_DIR="${HAPPIER_STACK_CLI_ROOT_DIR:-$HAPPIER_STACK_HOME_DIR}"
73
+ LIB_DIR="$hstack_ROOT_DIR/extras/swiftbar/lib"
74
+ if [[ ! -f "$LIB_DIR/utils.sh" ]]; then
75
+ echo "hstack"
76
+ echo "---"
77
+ echo "SwiftBar libs missing at: $LIB_DIR"
78
+ echo "↪ run: hstack menubar install"
79
+ exit 0
80
+ fi
81
+
82
+ # shellcheck source=/dev/null
83
+ source "$LIB_DIR/utils.sh"
84
+ hstack_ROOT_DIR="$(resolve_hstack_root_dir)"
85
+ LIB_DIR="$hstack_ROOT_DIR/extras/swiftbar/lib"
86
+ # shellcheck source=/dev/null
87
+ source "$LIB_DIR/icons.sh"
88
+ # shellcheck source=/dev/null
89
+ source "$LIB_DIR/system.sh"
90
+ # shellcheck source=/dev/null
91
+ source "$LIB_DIR/git.sh"
92
+ # shellcheck source=/dev/null
93
+ source "$LIB_DIR/render.sh"
94
+
95
+ # ============================================================================
96
+ # Menu
97
+ # ============================================================================
98
+
99
+ hstack_BIN="$(resolve_hstack_bin)"
100
+ hstack_TERM="$hstack_ROOT_DIR/extras/swiftbar/hstack-term.sh"
101
+ MAIN_PORT="$(resolve_main_port)"
102
+ MAIN_SERVER_COMPONENT="$(resolve_main_server_component)"
103
+ TAILSCALE_URL="$(get_tailscale_url)"
104
+ if swiftbar_is_sandboxed; then
105
+ # Never probe Tailscale (global machine state) when sandboxing.
106
+ TAILSCALE_URL=""
107
+ fi
108
+ MAIN_ENV_FILE="$(resolve_main_env_file)"
109
+ MENUBAR_MODE="$(resolve_menubar_mode)"
110
+
111
+ ensure_launchctl_cache
112
+
113
+ if [[ -z "$MAIN_ENV_FILE" ]]; then
114
+ MAIN_ENV_FILE="$(resolve_stack_env_file main)"
115
+ fi
116
+ HAPPIER_HOME_DIR="$(resolve_stack_base_dir main "$MAIN_ENV_FILE")"
117
+ CLI_HOME_DIR="$(resolve_stack_cli_home_dir main "$MAIN_ENV_FILE")"
118
+ LOGS_DIR="$HAPPIER_HOME_DIR/logs"
119
+ MAIN_LABEL="$(resolve_stack_label main)"
120
+
121
+ MAIN_COLLECT="$(collect_stack_status "$MAIN_PORT" "$CLI_HOME_DIR" "$MAIN_LABEL" "$HAPPIER_HOME_DIR")"
122
+ IFS=$'\t' read -r MAIN_LEVEL MAIN_SERVER_STATUS MAIN_SERVER_PID MAIN_SERVER_METRICS MAIN_DAEMON_STATUS MAIN_DAEMON_PID MAIN_DAEMON_METRICS MAIN_DAEMON_UPTIME MAIN_LAST_HEARTBEAT MAIN_LAUNCHAGENT_STATUS MAIN_AUTOSTART_PID MAIN_AUTOSTART_METRICS <<<"$MAIN_COLLECT"
123
+ for v in MAIN_SERVER_PID MAIN_SERVER_METRICS MAIN_DAEMON_PID MAIN_DAEMON_METRICS MAIN_DAEMON_UPTIME MAIN_LAST_HEARTBEAT MAIN_AUTOSTART_PID MAIN_AUTOSTART_METRICS; do
124
+ if [[ "${!v}" == "-" ]]; then
125
+ printf -v "$v" '%s' ""
126
+ fi
127
+ done
128
+
129
+ # Menu bar icon
130
+ MENU_STATUS_ICON_B64="$(status_icon_b64 "$MAIN_LEVEL" 18)"
131
+ if [[ -n "$MENU_STATUS_ICON_B64" ]]; then
132
+ echo " | image=$MENU_STATUS_ICON_B64"
133
+ else
134
+ STATUS_COLOR="$(color_for_level "$MAIN_LEVEL")"
135
+ ICON_B64="$(get_menu_icon_b64)"
136
+ if [[ -n "$ICON_B64" ]]; then
137
+ echo "● | templateImage=$ICON_B64 color=$STATUS_COLOR"
138
+ else
139
+ echo "hstack"
140
+ fi
141
+ fi
142
+
143
+ echo "---"
144
+ echo "hstack | size=14 font=SF Pro Display"
145
+ echo "---"
146
+
147
+ # Mode (selfhost vs dev)
148
+ if [[ "$MENUBAR_MODE" == "selfhost" ]]; then
149
+ echo "Mode: Selfhost | sfimage=house"
150
+ else
151
+ echo "Mode: Dev | sfimage=hammer"
152
+ fi
153
+ if [[ -n "$hstack_BIN" ]]; then
154
+ if [[ "$MENUBAR_MODE" == "selfhost" ]]; then
155
+ echo "--Switch to Dev mode | bash=$hstack_BIN param1=menubar param2=mode param3=dev dir=$hstack_ROOT_DIR terminal=false refresh=true"
156
+ else
157
+ echo "--Switch to Selfhost mode | bash=$hstack_BIN param1=menubar param2=mode param3=selfhost dir=$hstack_ROOT_DIR terminal=false refresh=true"
158
+ fi
159
+ fi
160
+ echo "---"
161
+
162
+ # Main stack (inline)
163
+ echo "Main stack"
164
+ echo "---"
165
+ export MAIN_LEVEL="$MAIN_LEVEL"
166
+ render_stack_info "" "main" "$MAIN_PORT" "$MAIN_SERVER_COMPONENT" "$HAPPIER_HOME_DIR" "$CLI_HOME_DIR" "$MAIN_LABEL" "$MAIN_ENV_FILE" "$TAILSCALE_URL" "$MAIN_SERVER_METRICS" "$MAIN_DAEMON_METRICS" "$MAIN_AUTOSTART_METRICS"
167
+ render_component_server "" "main" "$MAIN_PORT" "$MAIN_SERVER_COMPONENT" "$MAIN_SERVER_STATUS" "$MAIN_SERVER_PID" "$MAIN_SERVER_METRICS" "$TAILSCALE_URL" "$MAIN_LABEL"
168
+ render_component_daemon "" "$MAIN_DAEMON_STATUS" "$MAIN_DAEMON_PID" "$MAIN_DAEMON_METRICS" "$MAIN_DAEMON_UPTIME" "$MAIN_LAST_HEARTBEAT" "$CLI_HOME_DIR/daemon.state.json" "main"
169
+ render_component_autostart "" "main" "$MAIN_LABEL" "$MAIN_LAUNCHAGENT_STATUS" "$MAIN_AUTOSTART_PID" "$MAIN_AUTOSTART_METRICS" "$LOGS_DIR"
170
+ render_component_tailscale "" "main" "$TAILSCALE_URL"
171
+
172
+ echo "---"
173
+ if [[ "$MENUBAR_MODE" == "selfhost" ]]; then
174
+ echo "Maintenance | sfimage=wrench.and.screwdriver"
175
+ if [[ -n "$hstack_BIN" ]]; then
176
+ UPDATE_JSON="${hstack_ROOT_DIR}/cache/update.json"
177
+ update_available=""
178
+ latest=""
179
+ current=""
180
+ if [[ -f "$UPDATE_JSON" ]]; then
181
+ update_available="$(grep -oE '\"updateAvailable\"[[:space:]]*:[[:space:]]*(true|false)' "$UPDATE_JSON" 2>/dev/null | head -1 | grep -oE '(true|false)' || true)"
182
+ latest="$(grep -oE '\"latest\"[[:space:]]*:[[:space:]]*\"[^\"]+\"' "$UPDATE_JSON" 2>/dev/null | head -1 | sed -E 's/.*\"latest\"[[:space:]]*:[[:space:]]*\"([^\"]+)\".*/\\1/' || true)"
183
+ current="$(grep -oE '\"current\"[[:space:]]*:[[:space:]]*\"[^\"]+\"' "$UPDATE_JSON" 2>/dev/null | head -1 | sed -E 's/.*\"current\"[[:space:]]*:[[:space:]]*\"([^\"]+)\".*/\\1/' || true)"
184
+ fi
185
+ if [[ "$update_available" == "true" && -n "$latest" ]]; then
186
+ echo "--Update available: ${current:-current} → ${latest} | color=$YELLOW"
187
+ else
188
+ echo "--Updates: up to date | color=$GRAY"
189
+ fi
190
+ echo "--Check for updates | bash=$hstack_BIN param1=self param2=check dir=$hstack_ROOT_DIR terminal=false refresh=true"
191
+ echo "--Update hstack runtime | bash=$hstack_BIN param1=self param2=update dir=$hstack_ROOT_DIR terminal=false refresh=true"
192
+ echo "--Doctor | bash=$hstack_BIN param1=doctor dir=$hstack_ROOT_DIR terminal=false refresh=true"
193
+ else
194
+ echo "--⚠️ hstack not found (run: npx @happier-dev/stack@latest init)"
195
+ fi
196
+ else
197
+ echo "Stacks | sfimage=server.rack"
198
+ STACKS_PREFIX="--"
199
+
200
+ if [[ -n "$hstack_BIN" ]]; then
201
+ echo "${STACKS_PREFIX}New stack (interactive) | bash=$hstack_TERM param1=stack param2=new param3=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
202
+ echo "${STACKS_PREFIX}List stacks | bash=$hstack_TERM param1=stack param2=list dir=$hstack_ROOT_DIR terminal=false"
203
+ print_sep "$STACKS_PREFIX"
204
+ fi
205
+
206
+ STACKS_DIR="$(resolve_stacks_storage_root)"
207
+ if [[ -d "$STACKS_DIR" ]]; then
208
+ STACK_NAMES="$(
209
+ {
210
+ ls -1 "$STACKS_DIR" 2>/dev/null || true
211
+ } | sort -u
212
+ )"
213
+ if [[ -z "$STACK_NAMES" ]]; then
214
+ echo "${STACKS_PREFIX}No stacks found | color=$GRAY"
215
+ fi
216
+ for s in $STACK_NAMES; do
217
+ env_file="$(resolve_stack_env_file "$s")"
218
+ [[ -f "$env_file" ]] || continue
219
+
220
+ # Ports may be ephemeral (runtime-only). Do not skip stacks if the env file does not pin a port.
221
+ port="$(resolve_stack_server_port "$s" "$env_file")"
222
+
223
+ server_component="$(dotenv_get "$env_file" "HAPPIER_STACK_SERVER_COMPONENT")"
224
+ [[ -n "$server_component" ]] || server_component="happier-server-light"
225
+
226
+ base_dir="$(resolve_stack_base_dir "$s" "$env_file")"
227
+ cli_home_dir="$(resolve_stack_cli_home_dir "$s" "$env_file")"
228
+ label="$(resolve_stack_label "$s")"
229
+
230
+ COLLECT="$(collect_stack_status "$port" "$cli_home_dir" "$label" "$base_dir")"
231
+ IFS=$'\t' read -r LEVEL SERVER_STATUS SERVER_PID SERVER_METRICS DAEMON_STATUS DAEMON_PID DAEMON_METRICS DAEMON_UPTIME LAST_HEARTBEAT LAUNCHAGENT_STATUS AUTOSTART_PID AUTOSTART_METRICS <<<"$COLLECT"
232
+ for v in SERVER_PID SERVER_METRICS DAEMON_PID DAEMON_METRICS DAEMON_UPTIME LAST_HEARTBEAT AUTOSTART_PID AUTOSTART_METRICS; do
233
+ if [[ "${!v}" == "-" ]]; then
234
+ printf -v "$v" '%s' ""
235
+ fi
236
+ done
237
+
238
+ render_stack_overview_item "Stack: $s" "$LEVEL" "$STACKS_PREFIX"
239
+ export STACK_LEVEL="$LEVEL"
240
+ render_stack_info "${STACKS_PREFIX}--" "$s" "$port" "$server_component" "$base_dir" "$cli_home_dir" "$label" "$env_file" "" "$SERVER_METRICS" "$DAEMON_METRICS" "$AUTOSTART_METRICS"
241
+ render_component_server "${STACKS_PREFIX}--" "$s" "$port" "$server_component" "$SERVER_STATUS" "$SERVER_PID" "$SERVER_METRICS" "" "$label"
242
+ render_component_daemon "${STACKS_PREFIX}--" "$DAEMON_STATUS" "$DAEMON_PID" "$DAEMON_METRICS" "$DAEMON_UPTIME" "$LAST_HEARTBEAT" "$cli_home_dir/daemon.state.json" "$s"
243
+ render_component_autostart "${STACKS_PREFIX}--" "$s" "$label" "$LAUNCHAGENT_STATUS" "$AUTOSTART_PID" "$AUTOSTART_METRICS" "$base_dir/logs"
244
+ render_component_tailscale "${STACKS_PREFIX}--" "$s" ""
245
+ render_components_menu "${STACKS_PREFIX}--" "stack" "$s" "$env_file"
246
+ done
247
+ else
248
+ echo "${STACKS_PREFIX}No stacks dir found at: $(shorten_path "$STACKS_DIR" 52) | color=$GRAY"
249
+ fi
250
+
251
+ echo "---"
252
+ render_components_menu "" "main" "main" "$MAIN_ENV_FILE"
253
+
254
+ echo "Worktrees | sfimage=arrow.triangle.branch"
255
+ if [[ -z "$hstack_BIN" ]]; then
256
+ echo "--⚠️ hstack not found (run: npx @happier-dev/stack@latest init)"
257
+ else
258
+ echo "--Use (interactive) | bash=$hstack_TERM param1=wt param2=use param3=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
259
+ echo "--New (interactive) | bash=$hstack_TERM param1=wt param2=new param3=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
260
+ echo "--PR worktree (prompt) | bash=$hstack_ROOT_DIR/extras/swiftbar/wt-pr.sh dir=$hstack_ROOT_DIR terminal=false refresh=true"
261
+ echo "--Sync mirrors (all) | bash=$hstack_BIN param1=wt param2=sync-all dir=$hstack_ROOT_DIR terminal=false refresh=true"
262
+ echo "--Update all (dry-run) | bash=$hstack_TERM param1=wt param2=update-all param3=--dry-run dir=$hstack_ROOT_DIR terminal=false refresh=true"
263
+ echo "--Update all (apply) | bash=$hstack_BIN param1=wt param2=update-all dir=$hstack_ROOT_DIR terminal=false refresh=true"
264
+ fi
265
+
266
+ echo "---"
267
+ echo "Setup / Tools"
268
+ if [[ -z "$hstack_BIN" ]]; then
269
+ echo "--⚠️ hstack not found (run: npx @happier-dev/stack@latest init)"
270
+ else
271
+ echo "--Setup (guided) | bash=$hstack_TERM param1=setup dir=$hstack_ROOT_DIR terminal=false refresh=true"
272
+ echo "--Bootstrap (clone/install) | bash=$hstack_TERM param1=bootstrap dir=$hstack_ROOT_DIR terminal=false refresh=true"
273
+ echo "--CLI link (install happier wrapper) | bash=$hstack_TERM param1=cli:link dir=$hstack_ROOT_DIR terminal=false refresh=true"
274
+ echo "--Mobile dev helper | bash=$hstack_TERM param1=mobile dir=$hstack_ROOT_DIR terminal=false"
275
+ fi
276
+ fi
277
+
278
+ echo "---"
279
+ echo "Refresh | sfimage=arrow.clockwise refresh=true"
280
+ echo "---"
281
+ echo "Refresh interval | sfimage=timer"
282
+ SET_INTERVAL="$hstack_ROOT_DIR/extras/swiftbar/set-interval.sh"
283
+ echo "--10s | bash=$SET_INTERVAL param1=10s dir=$hstack_ROOT_DIR terminal=false refresh=true"
284
+ echo "--30s | bash=$SET_INTERVAL param1=30s dir=$hstack_ROOT_DIR terminal=false refresh=true"
285
+ echo "--1m | bash=$SET_INTERVAL param1=1m dir=$hstack_ROOT_DIR terminal=false refresh=true"
286
+ echo "--5m (recommended) | bash=$SET_INTERVAL param1=5m dir=$hstack_ROOT_DIR terminal=false refresh=true"
287
+ echo "--10m | bash=$SET_INTERVAL param1=10m dir=$hstack_ROOT_DIR terminal=false refresh=true"
288
+ echo "--15m | bash=$SET_INTERVAL param1=15m dir=$hstack_ROOT_DIR terminal=false refresh=true"
289
+ echo "--30m | bash=$SET_INTERVAL param1=30m dir=$hstack_ROOT_DIR terminal=false refresh=true"
290
+ echo "--1h | bash=$SET_INTERVAL param1=1h dir=$hstack_ROOT_DIR terminal=false refresh=true"
291
+ echo "--2h | bash=$SET_INTERVAL param1=2h dir=$hstack_ROOT_DIR terminal=false refresh=true"
292
+ echo "--6h | bash=$SET_INTERVAL param1=6h dir=$hstack_ROOT_DIR terminal=false refresh=true"
293
+ echo "--12h | bash=$SET_INTERVAL param1=12h dir=$hstack_ROOT_DIR terminal=false refresh=true"
294
+ echo "--1d | bash=$SET_INTERVAL param1=1d dir=$hstack_ROOT_DIR terminal=false refresh=true"
295
+
296
+ exit 0
@@ -0,0 +1,35 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # SwiftBar menu action wrapper.
5
+ # Runs `hstack` using the stable shim installed under <homeDir>/bin.
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ DEFAULT_HOME_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
9
+
10
+ # Prefer explicit env vars, but default to the install location inferred from this script path.
11
+ CANONICAL_HOME_DIR="${HAPPIER_STACK_CANONICAL_HOME_DIR:-$DEFAULT_HOME_DIR}"
12
+ CANONICAL_ENV_FILE="${CANONICAL_HOME_DIR%/}/.env"
13
+
14
+ HOME_DIR="${HAPPIER_STACK_HOME_DIR:-}"
15
+ if [[ -z "$HOME_DIR" && -f "$CANONICAL_ENV_FILE" ]]; then
16
+ HOME_DIR="$(grep -E '^HAPPIER_STACK_HOME_DIR=' "$CANONICAL_ENV_FILE" 2>/dev/null | head -n 1 | sed 's/^HAPPIER_STACK_HOME_DIR=//' || true)"
17
+ fi
18
+ HOME_DIR="${HOME_DIR:-$DEFAULT_HOME_DIR}"
19
+
20
+ export HAPPIER_STACK_HOME_DIR="$HOME_DIR"
21
+ export HAPPIER_STACK_CANONICAL_HOME_DIR="$CANONICAL_HOME_DIR"
22
+
23
+ hstack_BIN="$HOME_DIR/bin/hstack"
24
+
25
+ if [[ ! -x "$hstack_BIN" ]]; then
26
+ # Fall back to PATH (best-effort).
27
+ hstack_BIN="$(command -v hstack 2>/dev/null || true)"
28
+ fi
29
+
30
+ if [[ -z "${hstack_BIN:-}" ]]; then
31
+ echo "hstack not found. Run: npx @happier-dev/stack@latest init" >&2
32
+ exit 1
33
+ fi
34
+
35
+ exec "$hstack_BIN" "$@"