@happier-dev/stack 0.1.0-preview.5.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.
- package/README.md +501 -0
- package/bin/hstack.mjs +348 -0
- package/docs/codex-mcp-resume.md +129 -0
- package/docs/edison.md +74 -0
- package/docs/forking-and-branding.md +189 -0
- package/docs/happy-development.md +22 -0
- package/docs/isolated-linux-vm.md +243 -0
- package/docs/menubar.md +244 -0
- package/docs/mobile-ios.md +322 -0
- package/docs/monorepo-migration.md +20 -0
- package/docs/paths-and-env.md +154 -0
- package/docs/remote-access.md +43 -0
- package/docs/server-flavors.md +147 -0
- package/docs/stacks.md +330 -0
- package/docs/tauri.md +60 -0
- package/docs/worktrees-and-forks.md +133 -0
- package/extras/swiftbar/auth-login.sh +29 -0
- package/extras/swiftbar/git-cache-refresh.sh +122 -0
- package/extras/swiftbar/hstack-term.sh +133 -0
- package/extras/swiftbar/hstack.5s.sh +296 -0
- package/extras/swiftbar/hstack.sh +35 -0
- package/extras/swiftbar/icons/happy-green.png +0 -0
- package/extras/swiftbar/icons/happy-orange.png +0 -0
- package/extras/swiftbar/icons/happy-red.png +0 -0
- package/extras/swiftbar/icons/logo-white.png +0 -0
- package/extras/swiftbar/install.sh +265 -0
- package/extras/swiftbar/lib/git.sh +629 -0
- package/extras/swiftbar/lib/icons.sh +92 -0
- package/extras/swiftbar/lib/render.sh +999 -0
- package/extras/swiftbar/lib/system.sh +244 -0
- package/extras/swiftbar/lib/utils.sh +717 -0
- package/extras/swiftbar/set-interval.sh +65 -0
- package/extras/swiftbar/set-server-flavor.sh +61 -0
- package/extras/swiftbar/wt-pr.sh +140 -0
- package/node_modules/@happier-dev/cli-common/README.md +6 -0
- package/node_modules/@happier-dev/cli-common/dist/index.d.ts +4 -0
- package/node_modules/@happier-dev/cli-common/dist/index.d.ts.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/index.js +4 -0
- package/node_modules/@happier-dev/cli-common/dist/index.js.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/links/index.d.ts +18 -0
- package/node_modules/@happier-dev/cli-common/dist/links/index.d.ts.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/links/index.js +25 -0
- package/node_modules/@happier-dev/cli-common/dist/links/index.js.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/links.d.ts +2 -0
- package/node_modules/@happier-dev/cli-common/dist/links.d.ts.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/links.js +2 -0
- package/node_modules/@happier-dev/cli-common/dist/links.js.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/update/index.d.ts +67 -0
- package/node_modules/@happier-dev/cli-common/dist/update/index.d.ts.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/update/index.js +259 -0
- package/node_modules/@happier-dev/cli-common/dist/update/index.js.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/workspaces/index.d.ts +17 -0
- package/node_modules/@happier-dev/cli-common/dist/workspaces/index.d.ts.map +1 -0
- package/node_modules/@happier-dev/cli-common/dist/workspaces/index.js +80 -0
- package/node_modules/@happier-dev/cli-common/dist/workspaces/index.js.map +1 -0
- package/node_modules/@happier-dev/cli-common/package.json +26 -0
- package/package.json +77 -0
- package/scripts/auth.mjs +1829 -0
- package/scripts/auth_copy_from_pglite_lock_in_use.integration.test.mjs +90 -0
- package/scripts/auth_copy_from_runCapture.integration.test.mjs +447 -0
- package/scripts/auth_help_cmd.test.mjs +28 -0
- package/scripts/auth_login_flow_in_tty.test.mjs +100 -0
- package/scripts/auth_login_force_default.test.mjs +66 -0
- package/scripts/auth_login_guided_server_no_expo.test.mjs +126 -0
- package/scripts/auth_login_method_override.test.mjs +67 -0
- package/scripts/auth_login_print_includes_configure_links.test.mjs +99 -0
- package/scripts/auth_status_server_validation.integration.test.mjs +140 -0
- package/scripts/build.mjs +266 -0
- package/scripts/bundleWorkspaceDeps.mjs +38 -0
- package/scripts/bundleWorkspaceDeps.test.mjs +77 -0
- package/scripts/ci.mjs +135 -0
- package/scripts/ci.test.mjs +50 -0
- package/scripts/cli-link.mjs +57 -0
- package/scripts/completion.mjs +395 -0
- package/scripts/contrib.mjs +333 -0
- package/scripts/daemon.mjs +1160 -0
- package/scripts/daemon.status_scope.test.mjs +51 -0
- package/scripts/daemon_cmd.mjs +26 -0
- package/scripts/daemon_dist_guard.test.mjs +171 -0
- package/scripts/daemon_invalid_auth_reseed_stack_name.integration.test.mjs +608 -0
- package/scripts/daemon_server_scoped_state.test.mjs +49 -0
- package/scripts/daemon_start_verification.integration.test.mjs +296 -0
- package/scripts/dev.mjs +545 -0
- package/scripts/doctor.mjs +340 -0
- package/scripts/doctor_cmd.test.mjs +22 -0
- package/scripts/doctor_ui_index_missing.test.mjs +37 -0
- package/scripts/eas.mjs +367 -0
- package/scripts/eas_platform_parsing.test.mjs +63 -0
- package/scripts/edison.mjs +1848 -0
- package/scripts/env.mjs +149 -0
- package/scripts/env_cmd.test.mjs +118 -0
- package/scripts/exit_cleanup_kills_detached_children_on_crash.integration.test.mjs +80 -0
- package/scripts/happier.mjs +82 -0
- package/scripts/import.mjs +1327 -0
- package/scripts/init.mjs +464 -0
- package/scripts/install.mjs +550 -0
- package/scripts/lint.mjs +177 -0
- package/scripts/menubar.mjs +202 -0
- package/scripts/migrate.mjs +318 -0
- package/scripts/mobile.mjs +353 -0
- package/scripts/mobile_dev_client.mjs +87 -0
- package/scripts/monorepo.mjs +2234 -0
- package/scripts/monorepo_port.apply.integration.test.mjs +680 -0
- package/scripts/monorepo_port.conflicts.integration.test.mjs +454 -0
- package/scripts/monorepo_port.validation.integration.test.mjs +486 -0
- package/scripts/orchestrated_stack_auth_flow.test.mjs +134 -0
- package/scripts/orchestrated_stack_auth_flow_resolve_port.test.mjs +98 -0
- package/scripts/orchestrated_stack_auth_flow_webapp_url.test.mjs +119 -0
- package/scripts/pack.mjs +257 -0
- package/scripts/pack.test.mjs +68 -0
- package/scripts/pglite_lock.integration.test.mjs +152 -0
- package/scripts/provision/linux-ubuntu-e2e.sh +132 -0
- package/scripts/provision/linux-ubuntu-review-pr.sh +66 -0
- package/scripts/provision/macos-lima-happy-vm.sh +192 -0
- package/scripts/provision/macos-lima-hstack-e2e.sh +100 -0
- package/scripts/release.mjs +53 -0
- package/scripts/release_binary_smoke.integration.test.mjs +159 -0
- package/scripts/review.mjs +1752 -0
- package/scripts/review_pr.mjs +435 -0
- package/scripts/run.mjs +561 -0
- package/scripts/run_script_with_stack_env.restart_port_reuse.test.mjs +30 -0
- package/scripts/self.mjs +465 -0
- package/scripts/self_host.mjs +9 -0
- package/scripts/self_host_binary_smoke.integration.test.mjs +94 -0
- package/scripts/self_host_runtime.mjs +883 -0
- package/scripts/self_host_runtime.test.mjs +82 -0
- package/scripts/self_host_systemd.real.integration.test.mjs +367 -0
- package/scripts/server_flavor.mjs +148 -0
- package/scripts/service.mjs +868 -0
- package/scripts/service_mode_help.test.mjs +27 -0
- package/scripts/setup.mjs +1324 -0
- package/scripts/setup_non_interactive_flag.test.mjs +60 -0
- package/scripts/setup_pr.mjs +605 -0
- package/scripts/setup_pr_orchestrated_auth_flow_util_import.test.mjs +117 -0
- package/scripts/stack/command_arguments.mjs +91 -0
- package/scripts/stack/copy_auth_from_stack.mjs +111 -0
- package/scripts/stack/delegated_script_commands.mjs +92 -0
- package/scripts/stack/help_text.mjs +110 -0
- package/scripts/stack/port_reservation.mjs +74 -0
- package/scripts/stack/repo_checkout_resolution.mjs +31 -0
- package/scripts/stack/run_script_with_stack_env.mjs +634 -0
- package/scripts/stack/stack_daemon_command.mjs +219 -0
- package/scripts/stack/stack_delegated_help.mjs +81 -0
- package/scripts/stack/stack_environment.mjs +151 -0
- package/scripts/stack/stack_environment.sanitization.test.mjs +75 -0
- package/scripts/stack/stack_happier_passthrough_command.mjs +63 -0
- package/scripts/stack/stack_info_snapshot.mjs +167 -0
- package/scripts/stack/stack_mobile_install_command.mjs +61 -0
- package/scripts/stack/stack_resume_command.mjs +76 -0
- package/scripts/stack/stack_stop_command.mjs +34 -0
- package/scripts/stack/stack_workspace_command.mjs +83 -0
- package/scripts/stack/transient_repo_overrides.mjs +29 -0
- package/scripts/stack.mjs +2388 -0
- package/scripts/stack_archive_cmd.integration.test.mjs +31 -0
- package/scripts/stack_audit_fix_light_env.test.mjs +129 -0
- package/scripts/stack_background_pinned_stack_json.test.mjs +81 -0
- package/scripts/stack_copy_auth_server_scoped.test.mjs +243 -0
- package/scripts/stack_daemon_cmd.integration.test.mjs +484 -0
- package/scripts/stack_eas_help.test.mjs +72 -0
- package/scripts/stack_editor_workspace_monorepo_root.test.mjs +102 -0
- package/scripts/stack_env_cmd.test.mjs +107 -0
- package/scripts/stack_guided_login_bundle_error_parse.test.mjs +20 -0
- package/scripts/stack_guided_login_inner_invocation.test.mjs +46 -0
- package/scripts/stack_happy_cmd.integration.test.mjs +263 -0
- package/scripts/stack_info_snapshot_running_status.test.mjs +186 -0
- package/scripts/stack_interactive_monorepo_group.test.mjs +128 -0
- package/scripts/stack_monorepo_defaults.test.mjs +31 -0
- package/scripts/stack_monorepo_repo_dev_token.test.mjs +32 -0
- package/scripts/stack_monorepo_server_light_from_happy_spec.test.mjs +37 -0
- package/scripts/stack_new_name_normalize_cmd.test.mjs +38 -0
- package/scripts/stack_pr_name_normalize_cmd.test.mjs +84 -0
- package/scripts/stack_resume_cmd.integration.test.mjs +134 -0
- package/scripts/stack_server_flavors_defaults.test.mjs +64 -0
- package/scripts/stack_shorthand_cmd.integration.test.mjs +74 -0
- package/scripts/stack_stop_sweeps_legacy_infra_without_kind.integration.test.mjs +44 -0
- package/scripts/stack_stop_sweeps_when_runtime_missing.integration.test.mjs +42 -0
- package/scripts/stack_stop_sweeps_when_runtime_stale.integration.test.mjs +50 -0
- package/scripts/stack_wt_list.test.mjs +117 -0
- package/scripts/start_ui_required_default.test.mjs +63 -0
- package/scripts/stop.mjs +190 -0
- package/scripts/stopStackWithEnv_no_autosweep_when_runtime_missing.integration.test.mjs +95 -0
- package/scripts/swiftbar_git_monorepo_cmd.test.mjs +75 -0
- package/scripts/swiftbar_render_monorepo_wt_actions.integration.test.mjs +116 -0
- package/scripts/swiftbar_utils_cmd.test.mjs +92 -0
- package/scripts/swiftbar_wt_pr_backcompat.test.mjs +162 -0
- package/scripts/systemd_unit_info.test.mjs +24 -0
- package/scripts/tailscale.mjs +490 -0
- package/scripts/test_ci.mjs +36 -0
- package/scripts/test_cmd.mjs +274 -0
- package/scripts/test_cmd.test.mjs +133 -0
- package/scripts/test_integration.mjs +33 -0
- package/scripts/testkit/auth_testkit.mjs +121 -0
- package/scripts/testkit/doctor_testkit.mjs +68 -0
- package/scripts/testkit/monorepo_port_testkit.mjs +157 -0
- package/scripts/testkit/stack_archive_command_testkit.mjs +55 -0
- package/scripts/testkit/stack_new_monorepo_testkit.mjs +83 -0
- package/scripts/testkit/stack_script_command_testkit.mjs +27 -0
- package/scripts/testkit/stack_stop_sweeps_testkit.mjs +172 -0
- package/scripts/testkit/worktrees_monorepo_testkit.mjs +53 -0
- package/scripts/tools.mjs +70 -0
- package/scripts/tui.mjs +914 -0
- package/scripts/tui_stopStackForTuiExit_no_autosweep.integration.test.mjs +95 -0
- package/scripts/typecheck.mjs +178 -0
- package/scripts/ui_gateway.mjs +247 -0
- package/scripts/uninstall.mjs +179 -0
- package/scripts/utils/auth/credentials_paths.mjs +181 -0
- package/scripts/utils/auth/credentials_paths.test.mjs +187 -0
- package/scripts/utils/auth/daemon_gate.mjs +66 -0
- package/scripts/utils/auth/daemon_gate.test.mjs +116 -0
- package/scripts/utils/auth/decode_jwt_payload_unsafe.mjs +16 -0
- package/scripts/utils/auth/dev_key.mjs +163 -0
- package/scripts/utils/auth/files.mjs +56 -0
- package/scripts/utils/auth/guided_pr_auth.mjs +86 -0
- package/scripts/utils/auth/guided_stack_web_login.mjs +56 -0
- package/scripts/utils/auth/handy_master_secret.mjs +42 -0
- package/scripts/utils/auth/interactive_stack_auth.mjs +70 -0
- package/scripts/utils/auth/login_ux.mjs +105 -0
- package/scripts/utils/auth/orchestrated_stack_auth_flow.mjs +291 -0
- package/scripts/utils/auth/sources.mjs +28 -0
- package/scripts/utils/auth/stable_scope_id.mjs +91 -0
- package/scripts/utils/auth/stable_scope_id.test.mjs +51 -0
- package/scripts/utils/auth/stack_guided_login.mjs +438 -0
- package/scripts/utils/cli/arg_values.mjs +23 -0
- package/scripts/utils/cli/arg_values.test.mjs +43 -0
- package/scripts/utils/cli/args.mjs +17 -0
- package/scripts/utils/cli/cli.mjs +24 -0
- package/scripts/utils/cli/cli_registry.mjs +440 -0
- package/scripts/utils/cli/cwd_scope.mjs +158 -0
- package/scripts/utils/cli/cwd_scope.test.mjs +154 -0
- package/scripts/utils/cli/flags.mjs +17 -0
- package/scripts/utils/cli/log_forwarder.mjs +157 -0
- package/scripts/utils/cli/normalize.mjs +16 -0
- package/scripts/utils/cli/prereqs.mjs +103 -0
- package/scripts/utils/cli/prereqs.test.mjs +33 -0
- package/scripts/utils/cli/progress.mjs +141 -0
- package/scripts/utils/cli/smoke_help.mjs +44 -0
- package/scripts/utils/cli/verbosity.mjs +11 -0
- package/scripts/utils/cli/wizard.mjs +139 -0
- package/scripts/utils/cli/wizard_promptSelect.test.mjs +44 -0
- package/scripts/utils/cli/wizard_prompt_worktree_source_lazy.test.mjs +132 -0
- package/scripts/utils/cli/wizard_worktree_slug.test.mjs +33 -0
- package/scripts/utils/crypto/tokens.mjs +14 -0
- package/scripts/utils/dev/daemon.mjs +232 -0
- package/scripts/utils/dev/daemon_watch_resilience.test.mjs +224 -0
- package/scripts/utils/dev/expo_dev.buildEnv.test.mjs +35 -0
- package/scripts/utils/dev/expo_dev.mjs +478 -0
- package/scripts/utils/dev/expo_dev.test.mjs +89 -0
- package/scripts/utils/dev/expo_dev_restart_port_reservation.test.mjs +120 -0
- package/scripts/utils/dev/expo_dev_verbose_logs.test.mjs +60 -0
- package/scripts/utils/dev/server.mjs +180 -0
- package/scripts/utils/dev_auth_key.mjs +7 -0
- package/scripts/utils/edison/git_roots.mjs +30 -0
- package/scripts/utils/edison/git_roots.test.mjs +49 -0
- package/scripts/utils/env/config.mjs +52 -0
- package/scripts/utils/env/dotenv.mjs +32 -0
- package/scripts/utils/env/dotenv.test.mjs +32 -0
- package/scripts/utils/env/env.mjs +130 -0
- package/scripts/utils/env/env_file.mjs +98 -0
- package/scripts/utils/env/env_file.test.mjs +49 -0
- package/scripts/utils/env/env_local.mjs +25 -0
- package/scripts/utils/env/load_env_file.mjs +34 -0
- package/scripts/utils/env/read.mjs +30 -0
- package/scripts/utils/env/sandbox.mjs +13 -0
- package/scripts/utils/env/scrub_env.mjs +69 -0
- package/scripts/utils/env/scrub_env.test.mjs +102 -0
- package/scripts/utils/env/values.mjs +13 -0
- package/scripts/utils/expo/command.mjs +65 -0
- package/scripts/utils/expo/expo.mjs +139 -0
- package/scripts/utils/expo/expo_state_running.test.mjs +48 -0
- package/scripts/utils/expo/metro_ports.mjs +101 -0
- package/scripts/utils/expo/metro_ports.test.mjs +35 -0
- package/scripts/utils/fs/atomic_dir_swap.mjs +55 -0
- package/scripts/utils/fs/atomic_dir_swap.test.mjs +54 -0
- package/scripts/utils/fs/file_has_content.mjs +10 -0
- package/scripts/utils/fs/fs.mjs +11 -0
- package/scripts/utils/fs/json.mjs +25 -0
- package/scripts/utils/fs/ops.mjs +29 -0
- package/scripts/utils/fs/package_json.mjs +8 -0
- package/scripts/utils/fs/tail.mjs +12 -0
- package/scripts/utils/git/dev_checkout.mjs +127 -0
- package/scripts/utils/git/dev_checkout.test.mjs +115 -0
- package/scripts/utils/git/git.mjs +67 -0
- package/scripts/utils/git/parse_name_status_z.mjs +21 -0
- package/scripts/utils/git/refs.mjs +26 -0
- package/scripts/utils/git/worktrees.mjs +323 -0
- package/scripts/utils/git/worktrees_monorepo.test.mjs +60 -0
- package/scripts/utils/git/worktrees_pathstyle.test.mjs +53 -0
- package/scripts/utils/llm/assist.mjs +260 -0
- package/scripts/utils/llm/codex_exec.mjs +61 -0
- package/scripts/utils/llm/codex_exec.test.mjs +46 -0
- package/scripts/utils/llm/hstack_runner.mjs +59 -0
- package/scripts/utils/llm/tools.mjs +56 -0
- package/scripts/utils/llm/tools.test.mjs +67 -0
- package/scripts/utils/menubar/swiftbar.mjs +121 -0
- package/scripts/utils/menubar/swiftbar.test.mjs +85 -0
- package/scripts/utils/mobile/config.mjs +35 -0
- package/scripts/utils/mobile/dev_client_links.mjs +59 -0
- package/scripts/utils/mobile/identifiers.mjs +46 -0
- package/scripts/utils/mobile/identifiers.test.mjs +41 -0
- package/scripts/utils/mobile/ios_xcodeproj_patch.mjs +128 -0
- package/scripts/utils/mobile/ios_xcodeproj_patch.test.mjs +131 -0
- package/scripts/utils/net/bind_mode.mjs +39 -0
- package/scripts/utils/net/dns.mjs +10 -0
- package/scripts/utils/net/lan_ip.mjs +24 -0
- package/scripts/utils/net/ports.mjs +110 -0
- package/scripts/utils/net/tcp_forward.mjs +162 -0
- package/scripts/utils/net/url.mjs +30 -0
- package/scripts/utils/net/url.test.mjs +29 -0
- package/scripts/utils/paths/canonical_home.mjs +15 -0
- package/scripts/utils/paths/canonical_home.test.mjs +28 -0
- package/scripts/utils/paths/localhost_host.mjs +112 -0
- package/scripts/utils/paths/localhost_host.test.mjs +58 -0
- package/scripts/utils/paths/paths.mjs +302 -0
- package/scripts/utils/paths/paths_env_win32.test.mjs +36 -0
- package/scripts/utils/paths/paths_monorepo.test.mjs +58 -0
- package/scripts/utils/paths/paths_server_flavors.test.mjs +50 -0
- package/scripts/utils/paths/runtime.mjs +41 -0
- package/scripts/utils/pglite_lock.mjs +107 -0
- package/scripts/utils/proc/commands.mjs +33 -0
- package/scripts/utils/proc/exit_cleanup.mjs +57 -0
- package/scripts/utils/proc/happy_monorepo_deps.mjs +37 -0
- package/scripts/utils/proc/happy_monorepo_deps.test.mjs +89 -0
- package/scripts/utils/proc/ownership.mjs +217 -0
- package/scripts/utils/proc/ownership_killProcessGroupOwnedByStack.test.mjs +216 -0
- package/scripts/utils/proc/ownership_listPidsWithEnvNeedles.test.mjs +88 -0
- package/scripts/utils/proc/package_scripts.mjs +38 -0
- package/scripts/utils/proc/package_scripts.test.mjs +58 -0
- package/scripts/utils/proc/parallel.mjs +25 -0
- package/scripts/utils/proc/pids.mjs +11 -0
- package/scripts/utils/proc/pm.mjs +478 -0
- package/scripts/utils/proc/pm_spawn.integration.test.mjs +131 -0
- package/scripts/utils/proc/pm_stack_cache_env.test.mjs +313 -0
- package/scripts/utils/proc/proc.mjs +331 -0
- package/scripts/utils/proc/proc.test.mjs +85 -0
- package/scripts/utils/proc/terminate.mjs +69 -0
- package/scripts/utils/proc/terminate.test.mjs +54 -0
- package/scripts/utils/proc/watch.mjs +63 -0
- package/scripts/utils/review/augment_runner_integration.test.mjs +105 -0
- package/scripts/utils/review/base_ref.mjs +82 -0
- package/scripts/utils/review/base_ref.test.mjs +89 -0
- package/scripts/utils/review/chunks.mjs +55 -0
- package/scripts/utils/review/chunks.test.mjs +107 -0
- package/scripts/utils/review/detached_worktree.mjs +61 -0
- package/scripts/utils/review/detached_worktree.test.mjs +61 -0
- package/scripts/utils/review/findings.mjs +278 -0
- package/scripts/utils/review/findings.test.mjs +203 -0
- package/scripts/utils/review/head_slice.mjs +132 -0
- package/scripts/utils/review/head_slice.test.mjs +117 -0
- package/scripts/utils/review/instructions/deep.md +20 -0
- package/scripts/utils/review/prompts.mjs +279 -0
- package/scripts/utils/review/prompts.test.mjs +77 -0
- package/scripts/utils/review/run_reviewers_safe.mjs +12 -0
- package/scripts/utils/review/run_reviewers_safe.test.mjs +45 -0
- package/scripts/utils/review/runners/augment.mjs +91 -0
- package/scripts/utils/review/runners/augment.test.mjs +64 -0
- package/scripts/utils/review/runners/claude.mjs +92 -0
- package/scripts/utils/review/runners/claude.test.mjs +47 -0
- package/scripts/utils/review/runners/coderabbit.mjs +105 -0
- package/scripts/utils/review/runners/coderabbit.test.mjs +32 -0
- package/scripts/utils/review/runners/codex.mjs +129 -0
- package/scripts/utils/review/runners/codex.test.mjs +115 -0
- package/scripts/utils/review/slice_mode.mjs +20 -0
- package/scripts/utils/review/slice_mode.test.mjs +69 -0
- package/scripts/utils/review/sliced_runner.mjs +39 -0
- package/scripts/utils/review/sliced_runner.test.mjs +57 -0
- package/scripts/utils/review/slices.mjs +140 -0
- package/scripts/utils/review/slices.test.mjs +41 -0
- package/scripts/utils/review/targets.mjs +23 -0
- package/scripts/utils/review/targets.test.mjs +31 -0
- package/scripts/utils/review/tool_home_seed.mjs +106 -0
- package/scripts/utils/review/tool_home_seed.test.mjs +124 -0
- package/scripts/utils/review/uncommitted_ops.mjs +77 -0
- package/scripts/utils/review/uncommitted_ops.test.mjs +117 -0
- package/scripts/utils/sandbox/review_pr_sandbox.mjs +105 -0
- package/scripts/utils/server/apply_server_light_env_defaults.mjs +14 -0
- package/scripts/utils/server/flavor_scripts.mjs +138 -0
- package/scripts/utils/server/flavor_scripts.test.mjs +115 -0
- package/scripts/utils/server/infra/happy_server_infra.mjs +444 -0
- package/scripts/utils/server/mobile_api_url.mjs +60 -0
- package/scripts/utils/server/mobile_api_url.test.mjs +58 -0
- package/scripts/utils/server/port.mjs +55 -0
- package/scripts/utils/server/prisma_import.mjs +36 -0
- package/scripts/utils/server/prisma_import.test.mjs +78 -0
- package/scripts/utils/server/server.mjs +109 -0
- package/scripts/utils/server/ui_build_check.mjs +37 -0
- package/scripts/utils/server/ui_build_check.test.mjs +70 -0
- package/scripts/utils/server/ui_env.mjs +13 -0
- package/scripts/utils/server/ui_env.test.mjs +57 -0
- package/scripts/utils/server/urls.mjs +100 -0
- package/scripts/utils/server/validate.mjs +60 -0
- package/scripts/utils/server/validate.test.mjs +76 -0
- package/scripts/utils/service/autostart_darwin.mjs +198 -0
- package/scripts/utils/service/autostart_darwin.test.mjs +49 -0
- package/scripts/utils/service/autostart_darwin_keepalive.test.mjs +19 -0
- package/scripts/utils/stack/cli_identities.mjs +29 -0
- package/scripts/utils/stack/context.mjs +19 -0
- package/scripts/utils/stack/dirs.mjs +26 -0
- package/scripts/utils/stack/editor_workspace.mjs +126 -0
- package/scripts/utils/stack/interactive_stack_config.mjs +266 -0
- package/scripts/utils/stack/interactive_stack_config.port_validation.test.mjs +93 -0
- package/scripts/utils/stack/interactive_stack_config.remote_validation.test.mjs +122 -0
- package/scripts/utils/stack/interactive_stack_config.stack_name_validation.test.mjs +76 -0
- package/scripts/utils/stack/interactive_stack_config_testkit.mjs +18 -0
- package/scripts/utils/stack/names.mjs +27 -0
- package/scripts/utils/stack/names.test.mjs +26 -0
- package/scripts/utils/stack/pr_stack_name.mjs +16 -0
- package/scripts/utils/stack/runtime_state.mjs +88 -0
- package/scripts/utils/stack/stacks.mjs +40 -0
- package/scripts/utils/stack/startup.mjs +370 -0
- package/scripts/utils/stack/startup_server_light_dirs.test.mjs +119 -0
- package/scripts/utils/stack/startup_server_light_generate.test.mjs +20 -0
- package/scripts/utils/stack/startup_server_light_legacy.test.mjs +79 -0
- package/scripts/utils/stack/startup_server_light_testkit.mjs +106 -0
- package/scripts/utils/stack/stop.mjs +284 -0
- package/scripts/utils/stack_context.mjs +1 -0
- package/scripts/utils/stack_runtime_state.mjs +1 -0
- package/scripts/utils/stacks.mjs +1 -0
- package/scripts/utils/tailscale/ip.mjs +116 -0
- package/scripts/utils/tauri/stack_overrides.mjs +22 -0
- package/scripts/utils/test/collect_test_files.mjs +29 -0
- package/scripts/utils/time/get_today_ymd.mjs +7 -0
- package/scripts/utils/tui/cleanup.mjs +38 -0
- package/scripts/utils/ui/ansi.mjs +47 -0
- package/scripts/utils/ui/browser.mjs +31 -0
- package/scripts/utils/ui/browser.test.mjs +56 -0
- package/scripts/utils/ui/clipboard.mjs +38 -0
- package/scripts/utils/ui/layout.mjs +44 -0
- package/scripts/utils/ui/qr.mjs +17 -0
- package/scripts/utils/ui/terminal_launcher.mjs +129 -0
- package/scripts/utils/ui/text.mjs +16 -0
- package/scripts/utils/update/auto_update_notice.mjs +93 -0
- package/scripts/utils/validate.mjs +5 -0
- package/scripts/where.mjs +138 -0
- package/scripts/worktrees.mjs +2174 -0
- package/scripts/worktrees_archive_cmd.integration.test.mjs +228 -0
- package/scripts/worktrees_cursor_monorepo_root.test.mjs +23 -0
- package/scripts/worktrees_list_specs_no_recurse.test.mjs +32 -0
- package/scripts/worktrees_monorepo_testkit.test.mjs +29 -0
- package/scripts/worktrees_monorepo_use_group.test.mjs +41 -0
|
@@ -0,0 +1,999 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Requires:
|
|
4
|
+
# - utils.sh
|
|
5
|
+
# - icons.sh
|
|
6
|
+
# - system.sh
|
|
7
|
+
|
|
8
|
+
# This file is sourced/executed under strict bash modes in some contexts.
|
|
9
|
+
# Ensure these env vars are always defined to avoid `set -u` crashes in tests.
|
|
10
|
+
hstack_BIN="${hstack_BIN:-}"
|
|
11
|
+
hstack_TERM="${hstack_TERM:-$hstack_BIN}"
|
|
12
|
+
hstack_ROOT_DIR="${hstack_ROOT_DIR:-}"
|
|
13
|
+
|
|
14
|
+
level_from_server_daemon() {
|
|
15
|
+
local server_status="$1"
|
|
16
|
+
local daemon_status="$2"
|
|
17
|
+
if [[ "$server_status" == "running" && "$daemon_status" == "running" ]]; then
|
|
18
|
+
echo "green"
|
|
19
|
+
return
|
|
20
|
+
fi
|
|
21
|
+
if [[ "$server_status" == "running" || "$daemon_status" == "running" ]]; then
|
|
22
|
+
echo "orange"
|
|
23
|
+
return
|
|
24
|
+
fi
|
|
25
|
+
echo "red"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
color_for_level() {
|
|
29
|
+
local level="$1"
|
|
30
|
+
if [[ "$level" == "green" ]]; then echo "#16a34a"; return; fi
|
|
31
|
+
if [[ "$level" == "orange" ]]; then echo "#f59e0b"; return; fi
|
|
32
|
+
echo "#e74c3c"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
sfconfig_for_level() {
|
|
36
|
+
local level="$1"
|
|
37
|
+
local color="$(color_for_level "$level")"
|
|
38
|
+
# 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
|
|
39
|
+
echo "{\"colors\":[\"$color\"], \"scale\": \"small\"}" | base64 -b 0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
sf_for_level() {
|
|
43
|
+
local level="$1"
|
|
44
|
+
if [[ "$level" == "green" ]]; then echo "checkmark.circle.fill"; return; fi
|
|
45
|
+
if [[ "$level" == "orange" ]]; then echo "exclamationmark.triangle.fill"; return; fi
|
|
46
|
+
echo "xmark.circle.fill"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
sf_suffix_for_level() {
|
|
50
|
+
local level="$1"
|
|
51
|
+
if [[ "$level" == "green" ]]; then echo "badge.checkmark"; return; fi
|
|
52
|
+
if [[ "$level" == "orange" ]]; then echo "trianglebadge.exclamationmark"; return; fi
|
|
53
|
+
echo "badge.xmark"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
print_item() {
|
|
57
|
+
local prefix="$1"
|
|
58
|
+
shift
|
|
59
|
+
echo "${prefix}$*"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
print_sep() {
|
|
63
|
+
local prefix="$1"
|
|
64
|
+
print_item "$prefix" "---"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
render_component_server() {
|
|
68
|
+
local prefix="$1" # "" for top-level, "--" for stack submenu
|
|
69
|
+
local stack_name="$2" # main | <name>
|
|
70
|
+
local port="$3"
|
|
71
|
+
local server_component="$4"
|
|
72
|
+
local server_status="$5"
|
|
73
|
+
local server_pid="$6"
|
|
74
|
+
local server_metrics="$7"
|
|
75
|
+
local tailscale_url="$8" # main only (optional)
|
|
76
|
+
local launch_label="${9:-}" # optional (com.happier.stacks[.<stack>])
|
|
77
|
+
|
|
78
|
+
local level="red"
|
|
79
|
+
[[ "$server_status" == "running" ]] && level="green"
|
|
80
|
+
|
|
81
|
+
local label="Server (${server_component})"
|
|
82
|
+
local sf="$(sf_for_level "$level")"
|
|
83
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
84
|
+
print_item "$prefix" "$label | sfimage=$sf sfconfig=$sfconfig"
|
|
85
|
+
|
|
86
|
+
local p2="${prefix}--"
|
|
87
|
+
print_item "$p2" "Status: $server_status"
|
|
88
|
+
if [[ -n "$port" ]]; then
|
|
89
|
+
print_item "$p2" "Internal: http://127.0.0.1:${port}"
|
|
90
|
+
else
|
|
91
|
+
print_item "$p2" "Port: ephemeral (allocated at start time)"
|
|
92
|
+
fi
|
|
93
|
+
if [[ -n "$server_pid" ]]; then
|
|
94
|
+
if [[ -n "$server_metrics" ]]; then
|
|
95
|
+
local cpu mem etime
|
|
96
|
+
cpu="$(echo "$server_metrics" | cut -d'|' -f1)"
|
|
97
|
+
mem="$(echo "$server_metrics" | cut -d'|' -f2)"
|
|
98
|
+
etime="$(echo "$server_metrics" | cut -d'|' -f3)"
|
|
99
|
+
print_item "$p2" "PID: ${server_pid}, CPU: ${cpu}%, RAM: ${mem}MB, Uptime: ${etime}"
|
|
100
|
+
else
|
|
101
|
+
print_item "$p2" "PID: ${server_pid}"
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
if [[ -n "$port" ]]; then
|
|
105
|
+
print_item "$p2" "Open UI (local) | href=http://localhost:${port}/"
|
|
106
|
+
print_item "$p2" "Open Health | href=http://127.0.0.1:${port}/health"
|
|
107
|
+
fi
|
|
108
|
+
if [[ -n "$tailscale_url" ]]; then
|
|
109
|
+
print_item "$p2" "Open UI (Tailscale) | href=$tailscale_url"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Start/stop shortcuts (so you can control from the Server submenu too).
|
|
113
|
+
if [[ -n "$hstack_BIN" ]]; then
|
|
114
|
+
local plist=""
|
|
115
|
+
local svc_installed="0"
|
|
116
|
+
if ! swiftbar_is_sandboxed; then
|
|
117
|
+
if [[ -n "$launch_label" ]]; then
|
|
118
|
+
plist="$HOME/Library/LaunchAgents/${launch_label}.plist"
|
|
119
|
+
[[ -f "$plist" ]] && svc_installed="1"
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
print_sep "$p2"
|
|
124
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
125
|
+
if [[ "$svc_installed" == "1" ]]; then
|
|
126
|
+
if [[ "$server_status" == "running" ]]; then
|
|
127
|
+
print_item "$p2" "Stop stack (service) | bash=$hstack_BIN param1=service:stop dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
128
|
+
else
|
|
129
|
+
print_item "$p2" "Start stack (service) | bash=$hstack_BIN param1=service:start dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
130
|
+
fi
|
|
131
|
+
print_item "$p2" "Restart stack (service) | bash=$hstack_BIN param1=service:restart dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
132
|
+
else
|
|
133
|
+
if [[ "$server_status" == "running" ]]; then
|
|
134
|
+
print_item "$p2" "Stop stack | bash=$hstack_BIN param1=stack param2=stop param3=main dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
135
|
+
else
|
|
136
|
+
print_item "$p2" "Start stack (foreground) | bash=$hstack_TERM param1=start dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
else
|
|
140
|
+
if [[ "$svc_installed" == "1" ]]; then
|
|
141
|
+
if [[ "$server_status" == "running" ]]; then
|
|
142
|
+
print_item "$p2" "Stop stack (service) | bash=$hstack_BIN param1=stack param2=service:stop param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
143
|
+
else
|
|
144
|
+
print_item "$p2" "Start stack (service) | bash=$hstack_BIN param1=stack param2=service:start param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
145
|
+
fi
|
|
146
|
+
print_item "$p2" "Restart stack (service) | bash=$hstack_BIN param1=stack param2=service:restart param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
147
|
+
else
|
|
148
|
+
if [[ "$server_status" == "running" ]]; then
|
|
149
|
+
print_item "$p2" "Stop stack | bash=$hstack_BIN param1=stack param2=stop param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
150
|
+
else
|
|
151
|
+
print_item "$p2" "Start stack (foreground) | bash=$hstack_TERM param1=stack param2=start param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# Flavor switching (status-aware: only show switching to the other option).
|
|
158
|
+
local helper="$hstack_ROOT_DIR/extras/swiftbar/set-server-flavor.sh"
|
|
159
|
+
if [[ -n "$hstack_BIN" ]]; then
|
|
160
|
+
print_sep "$p2"
|
|
161
|
+
if [[ "$server_component" == "happier-server" ]]; then
|
|
162
|
+
print_item "$p2" "Switch to happier-server-light (restart if service installed) | bash=$helper param1=$stack_name param2=happier-server-light dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
163
|
+
else
|
|
164
|
+
print_item "$p2" "Switch to happier-server (restart if service installed) | bash=$helper param1=$stack_name param2=happier-server dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
165
|
+
fi
|
|
166
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
167
|
+
print_item "$p2" "Show flavor status | bash=$hstack_TERM param1=srv param2=-- param3=status dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
168
|
+
else
|
|
169
|
+
print_item "$p2" "Show flavor status | bash=$hstack_TERM param1=stack param2=srv param3=$stack_name param4=-- param5=status dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
render_component_daemon() {
|
|
175
|
+
local prefix="$1"
|
|
176
|
+
local daemon_status="$2" # running|stale|stopped|unknown|running-no-http|auth_required|starting
|
|
177
|
+
local daemon_pid="$3"
|
|
178
|
+
local daemon_metrics="$4"
|
|
179
|
+
local daemon_uptime="$5"
|
|
180
|
+
local last_heartbeat="$6"
|
|
181
|
+
local state_file="$7"
|
|
182
|
+
local stack_name="$8"
|
|
183
|
+
|
|
184
|
+
local level="red"
|
|
185
|
+
if [[ "$daemon_status" == "running" ]]; then level="green"; fi
|
|
186
|
+
if [[ "$daemon_status" == "running-no-http" || "$daemon_status" == "stale" || "$daemon_status" == "auth_required" || "$daemon_status" == "starting" ]]; then level="orange"; fi
|
|
187
|
+
|
|
188
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
189
|
+
|
|
190
|
+
local sf="$(sf_for_level "$level")"
|
|
191
|
+
print_item "$prefix" "Daemon | sfimage=$sf sfconfig=$sfconfig"
|
|
192
|
+
|
|
193
|
+
local p2="${prefix}--"
|
|
194
|
+
print_item "$p2" "Status: $daemon_status"
|
|
195
|
+
if [[ -n "$daemon_pid" ]]; then
|
|
196
|
+
if [[ -n "$daemon_metrics" ]]; then
|
|
197
|
+
local cpu mem etime
|
|
198
|
+
cpu="$(echo "$daemon_metrics" | cut -d'|' -f1)"
|
|
199
|
+
mem="$(echo "$daemon_metrics" | cut -d'|' -f2)"
|
|
200
|
+
etime="$(echo "$daemon_metrics" | cut -d'|' -f3)"
|
|
201
|
+
print_item "$p2" "PID: ${daemon_pid}, CPU: ${cpu}%, RAM: ${mem}MB, Uptime: ${etime}"
|
|
202
|
+
else
|
|
203
|
+
print_item "$p2" "PID: ${daemon_pid}"
|
|
204
|
+
fi
|
|
205
|
+
fi
|
|
206
|
+
[[ -n "$daemon_uptime" ]] && print_item "$p2" "Started: $(shorten_text "$daemon_uptime" 52)"
|
|
207
|
+
[[ -n "$last_heartbeat" ]] && print_item "$p2" "Last heartbeat: $(shorten_text "$last_heartbeat" 52)"
|
|
208
|
+
# State file may not exist yet (e.g. daemon is waiting for auth).
|
|
209
|
+
print_item "$p2" "State file: $(shorten_path "$state_file" 52)"
|
|
210
|
+
|
|
211
|
+
if [[ -n "$hstack_BIN" ]]; then
|
|
212
|
+
print_sep "$p2"
|
|
213
|
+
if [[ "$daemon_status" == "auth_required" ]]; then
|
|
214
|
+
# Provide a direct "fix" action for the common first-run problem under launchd.
|
|
215
|
+
local auth_helper="$hstack_ROOT_DIR/extras/swiftbar/auth-login.sh"
|
|
216
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
217
|
+
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=main dir=$hstack_ROOT_DIR terminal=false refresh=false"
|
|
218
|
+
else
|
|
219
|
+
# For stacks, best-effort use the stack's configured port if available (fallback to main port).
|
|
220
|
+
local env_file
|
|
221
|
+
env_file="$(resolve_stack_env_file "$stack_name")"
|
|
222
|
+
local port
|
|
223
|
+
port="$(dotenv_get "$env_file" "HAPPIER_STACK_SERVER_PORT")"
|
|
224
|
+
[[ -z "$port" ]] && port="$(resolve_main_port)"
|
|
225
|
+
print_item "$p2" "Auth login (opens browser) | bash=$auth_helper param1=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=false"
|
|
226
|
+
fi
|
|
227
|
+
print_sep "$p2"
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
print_item "$p2" "Restart daemon | bash=$hstack_BIN param1=stack param2=daemon param3=$stack_name param4=restart dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
231
|
+
print_item "$p2" "Show daemon status (CLI) | bash=$hstack_TERM param1=stack param2=daemon param3=$stack_name param4=status dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
232
|
+
|
|
233
|
+
if ! swiftbar_is_sandboxed; then
|
|
234
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
235
|
+
print_item "$p2" "Restart stack (service) | bash=$hstack_BIN param1=service:restart dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
236
|
+
else
|
|
237
|
+
print_item "$p2" "Restart stack (service) | bash=$hstack_BIN param1=stack param2=service:restart param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
238
|
+
fi
|
|
239
|
+
fi
|
|
240
|
+
fi
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
render_component_autostart() {
|
|
244
|
+
local prefix="$1"
|
|
245
|
+
local stack_name="$2"
|
|
246
|
+
local label="$3"
|
|
247
|
+
local launchagent_status="$4" # loaded|unloaded|not_installed
|
|
248
|
+
local autostart_pid="$5"
|
|
249
|
+
local autostart_metrics="$6"
|
|
250
|
+
local logs_dir="$7"
|
|
251
|
+
|
|
252
|
+
if swiftbar_is_sandboxed; then
|
|
253
|
+
print_item "$prefix" "Autostart | sfimage=exclamationmark.triangle sfconfig=light"
|
|
254
|
+
local p2="${prefix}--"
|
|
255
|
+
print_item "$p2" "Status: disabled in sandbox"
|
|
256
|
+
return
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
local level="red"
|
|
260
|
+
if [[ "$launchagent_status" == "loaded" ]]; then level="green"; fi
|
|
261
|
+
if [[ "$launchagent_status" == "unloaded" ]]; then level="orange"; fi
|
|
262
|
+
|
|
263
|
+
local sf="$(sf_for_level "$level")"
|
|
264
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
265
|
+
print_item "$prefix" "Autostart | sfimage=$sf sfconfig=$sfconfig"
|
|
266
|
+
|
|
267
|
+
local p2="${prefix}--"
|
|
268
|
+
print_item "$p2" "Status: $launchagent_status"
|
|
269
|
+
print_item "$p2" "Plist: $(shorten_path "$HOME/Library/LaunchAgents/${label}.plist" 52)"
|
|
270
|
+
if [[ -n "$autostart_pid" ]]; then
|
|
271
|
+
if [[ -n "$autostart_metrics" ]]; then
|
|
272
|
+
local cpu mem etime
|
|
273
|
+
cpu="$(echo "$autostart_metrics" | cut -d'|' -f1)"
|
|
274
|
+
mem="$(echo "$autostart_metrics" | cut -d'|' -f2)"
|
|
275
|
+
etime="$(echo "$autostart_metrics" | cut -d'|' -f3)"
|
|
276
|
+
print_item "$p2" "PID: ${autostart_pid}, CPU: ${cpu}%, RAM: ${mem}MB, Uptime: ${etime}"
|
|
277
|
+
else
|
|
278
|
+
print_item "$p2" "PID: ${autostart_pid}"
|
|
279
|
+
fi
|
|
280
|
+
fi
|
|
281
|
+
local stdout_file="hstack.out.log"
|
|
282
|
+
local stderr_file="hstack.err.log"
|
|
283
|
+
print_item "$p2" "Open logs (stdout) | bash=/usr/bin/open param1=-a param2=Console param3='${logs_dir}/${stdout_file}' terminal=false"
|
|
284
|
+
print_item "$p2" "Open logs (stderr) | bash=/usr/bin/open param1=-a param2=Console param3='${logs_dir}/${stderr_file}' terminal=false"
|
|
285
|
+
|
|
286
|
+
if [[ -z "$hstack_BIN" ]]; then
|
|
287
|
+
return
|
|
288
|
+
fi
|
|
289
|
+
print_sep "$p2"
|
|
290
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
291
|
+
if [[ "$launchagent_status" == "not_installed" ]]; then
|
|
292
|
+
print_item "$p2" "Install Autostart | bash=$hstack_BIN param1=service:install dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
293
|
+
return
|
|
294
|
+
fi
|
|
295
|
+
# Status-aware: show only the relevant toggle (enable vs disable).
|
|
296
|
+
if [[ "$launchagent_status" == "loaded" ]]; then
|
|
297
|
+
print_item "$p2" "Disable Autostart | bash=$hstack_BIN param1=service:disable dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
298
|
+
else
|
|
299
|
+
print_item "$p2" "Enable Autostart | bash=$hstack_BIN param1=service:enable dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
300
|
+
fi
|
|
301
|
+
print_item "$p2" "Uninstall Autostart | bash=$hstack_BIN param1=service:uninstall dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
302
|
+
return
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
if [[ "$launchagent_status" == "not_installed" ]]; then
|
|
306
|
+
print_item "$p2" "Install Autostart | bash=$hstack_BIN param1=stack param2=service:install param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
307
|
+
return
|
|
308
|
+
fi
|
|
309
|
+
# Status-aware: show only the relevant toggle (enable vs disable).
|
|
310
|
+
if [[ "$launchagent_status" == "loaded" ]]; then
|
|
311
|
+
print_item "$p2" "Disable Autostart | bash=$hstack_BIN param1=stack param2=service:disable param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
312
|
+
else
|
|
313
|
+
print_item "$p2" "Enable Autostart | bash=$hstack_BIN param1=stack param2=service:enable param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
314
|
+
fi
|
|
315
|
+
print_item "$p2" "Uninstall Autostart | bash=$hstack_BIN param1=stack param2=service:uninstall param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
render_component_tailscale() {
|
|
319
|
+
local prefix="$1"
|
|
320
|
+
local stack_name="$2"
|
|
321
|
+
local tailscale_url="$3"
|
|
322
|
+
|
|
323
|
+
local level="red"
|
|
324
|
+
[[ -n "$tailscale_url" ]] && level="green"
|
|
325
|
+
|
|
326
|
+
local sf="$(sf_for_level "$level")"
|
|
327
|
+
local sfconfig="$(sfconfig_for_level "$level")"
|
|
328
|
+
print_item "$prefix" "Tailscale | sfimage=$sf sfconfig=$sfconfig"
|
|
329
|
+
|
|
330
|
+
local p2="${prefix}--"
|
|
331
|
+
if [[ -n "$tailscale_url" ]]; then
|
|
332
|
+
local display="$tailscale_url"
|
|
333
|
+
[[ ${#display} -gt 48 ]] && display="${display:0:48}..."
|
|
334
|
+
print_item "$p2" "URL: $display"
|
|
335
|
+
print_item "$p2" "Copy URL | bash=/bin/bash param1=-c param2='echo -n \"$tailscale_url\" | pbcopy' terminal=false"
|
|
336
|
+
print_item "$p2" "Open URL | href=$tailscale_url"
|
|
337
|
+
else
|
|
338
|
+
print_item "$p2" "Status: not configured / unknown"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
# Tailscale Serve is global machine state; never offer enable/disable actions in sandbox mode.
|
|
342
|
+
if swiftbar_is_sandboxed; then
|
|
343
|
+
return
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
if [[ -z "$hstack_BIN" ]]; then
|
|
347
|
+
return
|
|
348
|
+
fi
|
|
349
|
+
print_sep "$p2"
|
|
350
|
+
|
|
351
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
352
|
+
print_item "$p2" "Tailscale status | bash=$hstack_TERM param1=tailscale:status dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
353
|
+
if [[ -n "$tailscale_url" ]]; then
|
|
354
|
+
print_item "$p2" "Disable Tailscale Serve | bash=$hstack_BIN param1=tailscale:disable dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
355
|
+
else
|
|
356
|
+
print_item "$p2" "Enable Tailscale Serve | bash=$hstack_TERM param1=tailscale:enable dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
357
|
+
fi
|
|
358
|
+
print_item "$p2" "Print URL | bash=$hstack_TERM param1=tailscale:url dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
359
|
+
return
|
|
360
|
+
fi
|
|
361
|
+
|
|
362
|
+
print_item "$p2" "Tailscale status | bash=$hstack_TERM param1=stack param2=tailscale:status param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
363
|
+
if [[ -n "$tailscale_url" ]]; then
|
|
364
|
+
print_item "$p2" "Disable Tailscale Serve | bash=$hstack_BIN param1=stack param2=tailscale:disable param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
365
|
+
else
|
|
366
|
+
print_item "$p2" "Enable Tailscale Serve | bash=$hstack_TERM param1=stack param2=tailscale:enable param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
367
|
+
fi
|
|
368
|
+
print_item "$p2" "Print URL | bash=$hstack_TERM param1=stack param2=tailscale:url param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
render_component_repo() {
|
|
372
|
+
# Git/worktree component view (unified UI).
|
|
373
|
+
# Usage:
|
|
374
|
+
# render_component_repo <prefix> <component> <context> <stack_name> <env_file> <shared_repo_root?>
|
|
375
|
+
# context: main|stack
|
|
376
|
+
local prefix="$1"
|
|
377
|
+
local component="$2"
|
|
378
|
+
local context="$3"
|
|
379
|
+
local stack_name="$4"
|
|
380
|
+
local env_file="$5"
|
|
381
|
+
local shared_repo_root="${6:-}"
|
|
382
|
+
|
|
383
|
+
local t0 t1
|
|
384
|
+
t0="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
385
|
+
|
|
386
|
+
local active_dir=""
|
|
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
|
|
389
|
+
active_dir="$(resolve_component_dir_from_env_file "$env_file" "$component")"
|
|
390
|
+
else
|
|
391
|
+
active_dir="$(resolve_component_dir_from_env "$component")"
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
local level="red"
|
|
395
|
+
local detail="missing"
|
|
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
|
|
426
|
+
fi
|
|
427
|
+
fi
|
|
428
|
+
|
|
429
|
+
if [[ "$status" == "ok" ]]; then
|
|
430
|
+
detail="ok"
|
|
431
|
+
if [[ "$dirty" == "dirty" ]] || [[ -n "$behind" && "$behind" != "0" ]]; then
|
|
432
|
+
level="orange"
|
|
433
|
+
else
|
|
434
|
+
level="green"
|
|
435
|
+
fi
|
|
436
|
+
fi
|
|
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
|
+
|
|
441
|
+
local sf color
|
|
442
|
+
sf="$(sf_for_level "$level")"
|
|
443
|
+
color="$(color_for_level "$level")"
|
|
444
|
+
print_item "$prefix" "${component} | sfimage=$sf color=$color"
|
|
445
|
+
|
|
446
|
+
local p2="${prefix}--"
|
|
447
|
+
local repo_root=""
|
|
448
|
+
local rel_dir=""
|
|
449
|
+
repo_root="$(swiftbar_find_git_root_upwards "$active_dir" 2>/dev/null || true)"
|
|
450
|
+
local repo_key=""
|
|
451
|
+
repo_key="$(swiftbar_repo_key_from_path "$active_dir" 2>/dev/null || true)"
|
|
452
|
+
[[ -n "$repo_key" ]] || repo_key="$component"
|
|
453
|
+
local mono_repo="0"
|
|
454
|
+
if [[ -n "$shared_repo_root" && -n "$repo_root" && "$shared_repo_root" == "$repo_root" ]]; then
|
|
455
|
+
mono_repo="1"
|
|
456
|
+
fi
|
|
457
|
+
|
|
458
|
+
if [[ -n "$repo_root" && "$repo_root" != "$active_dir" && "$active_dir" == "$repo_root/"* ]]; then
|
|
459
|
+
rel_dir="${active_dir#"$repo_root"/}"
|
|
460
|
+
if [[ -n "$shared_repo_root" && "$shared_repo_root" == "$repo_root" ]]; then
|
|
461
|
+
print_item "$p2" "Dir: $(shorten_text "$rel_dir" 52)"
|
|
462
|
+
else
|
|
463
|
+
print_item "$p2" "Repo: $(shorten_path "$repo_root" 52)"
|
|
464
|
+
print_item "$p2" "Dir: $(shorten_text "$rel_dir" 52)"
|
|
465
|
+
fi
|
|
466
|
+
else
|
|
467
|
+
print_item "$p2" "Dir: $(shorten_path "$active_dir" 52)"
|
|
468
|
+
repo_root=""
|
|
469
|
+
rel_dir=""
|
|
470
|
+
fi
|
|
471
|
+
if [[ "$detail" != "ok" ]]; then
|
|
472
|
+
if [[ "$git_mode" == "cached" ]]; then
|
|
473
|
+
print_item "$p2" "Status: git cache missing (or not a git repo)"
|
|
474
|
+
local refresh="$hstack_ROOT_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
475
|
+
if [[ -x "$refresh" ]]; then
|
|
476
|
+
print_sep "$p2"
|
|
477
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
478
|
+
print_item "$p2" "Refresh Git cache (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
479
|
+
else
|
|
480
|
+
print_item "$p2" "Refresh Git cache (main) | bash=$refresh param1=main dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
481
|
+
fi
|
|
482
|
+
fi
|
|
483
|
+
else
|
|
484
|
+
print_item "$p2" "Status: not a git repo / missing"
|
|
485
|
+
fi
|
|
486
|
+
if [[ -n "$hstack_BIN" ]]; then
|
|
487
|
+
print_sep "$p2"
|
|
488
|
+
print_item "$p2" "Bootstrap (clone missing repos) | bash=$hstack_TERM param1=bootstrap dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
489
|
+
fi
|
|
490
|
+
return
|
|
491
|
+
fi
|
|
492
|
+
|
|
493
|
+
# Cache status + refresh actions
|
|
494
|
+
if [[ "$git_mode" == "cached" ]]; then
|
|
495
|
+
local age=""
|
|
496
|
+
age="$(git_cache_age_sec "$meta")"
|
|
497
|
+
if [[ -n "$age" ]]; then
|
|
498
|
+
if [[ "$stale" == "1" ]]; then
|
|
499
|
+
print_item "$p2" "Git cache: stale (${age}s old) | color=$YELLOW"
|
|
500
|
+
else
|
|
501
|
+
print_item "$p2" "Git cache: fresh (${age}s old) | color=$GRAY"
|
|
502
|
+
fi
|
|
503
|
+
fi
|
|
504
|
+
local refresh="$hstack_ROOT_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
505
|
+
if [[ -x "$refresh" ]]; then
|
|
506
|
+
print_sep "$p2"
|
|
507
|
+
print_item "$p2" "Refresh Git cache (this component) | bash=$refresh param1=component param2=$context param3=$stack_name param4=$component dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
508
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
509
|
+
print_item "$p2" "Refresh Git cache (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
510
|
+
fi
|
|
511
|
+
fi
|
|
512
|
+
fi
|
|
513
|
+
|
|
514
|
+
print_sep "$p2"
|
|
515
|
+
print_item "$p2" "HEAD: ${branch:-"(unknown)"} ${head:+($head)}"
|
|
516
|
+
print_item "$p2" "Upstream: ${upstream:-"(none)"}"
|
|
517
|
+
if [[ -n "$ahead" && -n "$behind" ]]; then
|
|
518
|
+
print_item "$p2" "Ahead/Behind: ${ahead}/${behind}"
|
|
519
|
+
fi
|
|
520
|
+
print_item "$p2" "Working tree: ${dirty}"
|
|
521
|
+
|
|
522
|
+
if [[ -n "$main_branch" ]]; then
|
|
523
|
+
if [[ -n "$main_upstream" ]]; then
|
|
524
|
+
print_item "$p2" "Main: ${main_branch} → ${main_upstream}"
|
|
525
|
+
else
|
|
526
|
+
print_item "$p2" "Main: ${main_branch} → (no upstream)"
|
|
527
|
+
fi
|
|
528
|
+
if [[ -n "$main_ahead" && -n "$main_behind" ]]; then
|
|
529
|
+
print_item "$p2" "Main ahead/behind: ${main_ahead}/${main_behind}"
|
|
530
|
+
fi
|
|
531
|
+
|
|
532
|
+
# Always show comparisons against origin/* and upstream/* when those remote refs exist.
|
|
533
|
+
# (These reflect your last fetch; we do not auto-fetch in the menu.)
|
|
534
|
+
if [[ -n "$oref" ]]; then
|
|
535
|
+
local oref_short="${oref#refs/remotes/}"
|
|
536
|
+
if [[ -n "$o_ahead" && -n "$o_behind" ]]; then
|
|
537
|
+
print_item "$p2" "Origin: ${oref_short} ahead/behind: ${o_ahead}/${o_behind}"
|
|
538
|
+
else
|
|
539
|
+
print_item "$p2" "Origin: ${oref_short}"
|
|
540
|
+
fi
|
|
541
|
+
else
|
|
542
|
+
print_item "$p2" "Origin: (no origin/main|master ref)"
|
|
543
|
+
fi
|
|
544
|
+
if [[ -n "$uref" ]]; then
|
|
545
|
+
local uref_short="${uref#refs/remotes/}"
|
|
546
|
+
if [[ -n "$u_ahead" && -n "$u_behind" ]]; then
|
|
547
|
+
print_item "$p2" "Upstream: ${uref_short} ahead/behind: ${u_ahead}/${u_behind}"
|
|
548
|
+
else
|
|
549
|
+
print_item "$p2" "Upstream: ${uref_short}"
|
|
550
|
+
fi
|
|
551
|
+
else
|
|
552
|
+
print_item "$p2" "Upstream: (no upstream/main|master ref)"
|
|
553
|
+
fi
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
local wt_count
|
|
557
|
+
# If cache didn't populate wt_count, fall back to empty string.
|
|
558
|
+
wt_count="${wt_count:-}"
|
|
559
|
+
|
|
560
|
+
# Quick actions
|
|
561
|
+
print_sep "$p2"
|
|
562
|
+
if [[ -n "$repo_root" ]]; then
|
|
563
|
+
print_item "$p2" "Open package folder | bash=/usr/bin/open param1='$active_dir' terminal=false"
|
|
564
|
+
print_item "$p2" "Open repo root | bash=/usr/bin/open param1='$repo_root' terminal=false"
|
|
565
|
+
else
|
|
566
|
+
print_item "$p2" "Open folder | bash=/usr/bin/open param1='$active_dir' terminal=false"
|
|
567
|
+
fi
|
|
568
|
+
|
|
569
|
+
if [[ -n "${hstack_BIN:-}" ]]; then
|
|
570
|
+
# Run via stack wrappers when in a stack context so env-file stays authoritative.
|
|
571
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
572
|
+
print_item "$p2" "Status (active) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=status param6=active dir=$hstack_ROOT_DIR terminal=false"
|
|
573
|
+
print_item "$p2" "Sync mirror (upstream/main) | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=sync dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
574
|
+
print_item "$p2" "Update (dry-run) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=update param6=active param7=--dry-run dir=$hstack_ROOT_DIR terminal=false"
|
|
575
|
+
print_item "$p2" "Update (apply) | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=update param6=active dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
576
|
+
print_item "$p2" "Update (apply + stash) | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=update param6=active param7=--stash dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
577
|
+
else
|
|
578
|
+
print_item "$p2" "Status (active) | bash=$hstack_TERM param1=wt param2=status param3=active dir=$hstack_ROOT_DIR terminal=false"
|
|
579
|
+
print_item "$p2" "Sync mirror (upstream/main) | bash=$hstack_BIN param1=wt param2=sync dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
580
|
+
print_item "$p2" "Update (dry-run) | bash=$hstack_TERM param1=wt param2=update param3=active param4=--dry-run dir=$hstack_ROOT_DIR terminal=false"
|
|
581
|
+
print_item "$p2" "Update (apply) | bash=$hstack_BIN param1=wt param2=update param3=active dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
582
|
+
print_item "$p2" "Update (apply + stash) | bash=$hstack_BIN param1=wt param2=update param3=active param4=--stash dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
583
|
+
fi
|
|
584
|
+
|
|
585
|
+
print_sep "$p2"
|
|
586
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
587
|
+
print_item "$p2" "Use worktree in stack (interactive) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=use param6=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
588
|
+
print_item "$p2" "New worktree (interactive) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=new param6=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
589
|
+
print_item "$p2" "List worktrees (terminal) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=list dir=$hstack_ROOT_DIR terminal=false"
|
|
590
|
+
else
|
|
591
|
+
print_item "$p2" "Use worktree (interactive) | bash=$hstack_TERM param1=wt param2=use param3=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
592
|
+
print_item "$p2" "New worktree (interactive) | bash=$hstack_TERM param1=wt param2=new param3=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
593
|
+
print_item "$p2" "List worktrees (terminal) | bash=$hstack_TERM param1=wt param2=list dir=$hstack_ROOT_DIR terminal=false"
|
|
594
|
+
fi
|
|
595
|
+
|
|
596
|
+
# PR worktree (prompt)
|
|
597
|
+
local pr_helper="$hstack_ROOT_DIR/extras/swiftbar/wt-pr.sh"
|
|
598
|
+
if [[ -x "$pr_helper" ]]; then
|
|
599
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
600
|
+
print_item "$p2" "PR worktree (prompt) | bash=$pr_helper param1=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
601
|
+
else
|
|
602
|
+
print_item "$p2" "PR worktree (prompt) | bash=$pr_helper dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
603
|
+
fi
|
|
604
|
+
fi
|
|
605
|
+
|
|
606
|
+
print_sep "$p2"
|
|
607
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
608
|
+
print_item "$p2" "Shell (active, new window) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=shell param6=active param7=--new-window dir=$hstack_ROOT_DIR terminal=false"
|
|
609
|
+
print_item "$p2" "Open in VS Code (active) | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=code param6=active dir=$hstack_ROOT_DIR terminal=false"
|
|
610
|
+
print_item "$p2" "Open in Cursor (active) | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=cursor param6=active dir=$hstack_ROOT_DIR terminal=false"
|
|
611
|
+
else
|
|
612
|
+
print_item "$p2" "Shell (active, new window) | bash=$hstack_TERM param1=wt param2=shell param3=active param4=--new-window dir=$hstack_ROOT_DIR terminal=false"
|
|
613
|
+
print_item "$p2" "Open in VS Code (active) | bash=$hstack_BIN param1=wt param2=code param3=active dir=$hstack_ROOT_DIR terminal=false"
|
|
614
|
+
print_item "$p2" "Open in Cursor (active) | bash=$hstack_BIN param1=wt param2=cursor param3=active dir=$hstack_ROOT_DIR terminal=false"
|
|
615
|
+
fi
|
|
616
|
+
|
|
617
|
+
# Worktrees listing (inline in SwiftBar, plus stack-aware switch).
|
|
618
|
+
local wt_label="Worktrees: ${wt_count:-0} | sfimage=arrow.triangle.branch"
|
|
619
|
+
print_item "$p2" "$wt_label"
|
|
620
|
+
local p3="${p2}--"
|
|
621
|
+
local tsv
|
|
622
|
+
if [[ "$git_mode" == "cached" && -f "$wts" ]]; then
|
|
623
|
+
tsv="$(cat "$wts" 2>/dev/null || true)"
|
|
624
|
+
else
|
|
625
|
+
tsv="$(git_worktrees_tsv "$active_dir" 2>/dev/null || true)"
|
|
626
|
+
fi
|
|
627
|
+
if [[ -z "$tsv" ]]; then
|
|
628
|
+
print_item "$p3" "No worktrees found | color=$GRAY"
|
|
629
|
+
else
|
|
630
|
+
# Map worktree paths back to hstack specs (main/dev or workspace/{pr,local,tmp}/...).
|
|
631
|
+
local repo_key
|
|
632
|
+
repo_key="$(swiftbar_repo_key_from_path "$active_dir" 2>/dev/null || true)"
|
|
633
|
+
local root=""
|
|
634
|
+
if [[ -n "$repo_key" ]]; then
|
|
635
|
+
root="$(resolve_workspace_dir)/"
|
|
636
|
+
fi
|
|
637
|
+
local shown=0
|
|
638
|
+
while IFS=$'\t' read -r wt_path wt_branchref; do
|
|
639
|
+
[[ -n "$wt_path" ]] || continue
|
|
640
|
+
shown=$((shown + 1))
|
|
641
|
+
if [[ $shown -gt 30 ]]; then
|
|
642
|
+
if [[ -n "$root" ]]; then
|
|
643
|
+
print_item "$p3" "More… (open folder) | bash=/usr/bin/open param1='$root' terminal=false"
|
|
644
|
+
fi
|
|
645
|
+
break
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
local label=""
|
|
649
|
+
local spec=""
|
|
650
|
+
if [[ -n "$repo_key" ]]; then
|
|
651
|
+
spec="$(swiftbar_worktree_spec_from_path "$wt_path" "$repo_key" 2>/dev/null || true)"
|
|
652
|
+
fi
|
|
653
|
+
if [[ -n "$spec" ]]; then
|
|
654
|
+
label="$spec"
|
|
655
|
+
else
|
|
656
|
+
label="$(shorten_path "$wt_path" 52)"
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
if [[ -n "$wt_branchref" && "$wt_branchref" == refs/heads/* ]]; then
|
|
660
|
+
label="$label ($(basename "$wt_branchref"))"
|
|
661
|
+
fi
|
|
662
|
+
# Active worktree: for monorepo packages, active_dir is under the worktree root.
|
|
663
|
+
local wt_component_dir="$wt_path"
|
|
664
|
+
if [[ -n "$rel_dir" ]]; then
|
|
665
|
+
wt_component_dir="$wt_path/$rel_dir"
|
|
666
|
+
fi
|
|
667
|
+
if [[ "$wt_component_dir" == "$active_dir" ]]; then
|
|
668
|
+
label="(active) $label"
|
|
669
|
+
fi
|
|
670
|
+
|
|
671
|
+
print_item "$p3" "$label"
|
|
672
|
+
|
|
673
|
+
# Only show "use" actions when we can express the worktree as a spec (main/dev or under pr/local/tmp).
|
|
674
|
+
# Some git worktrees can exist outside our managed tree; for those we only offer open/shell actions.
|
|
675
|
+
if [[ -n "$spec" ]]; then
|
|
676
|
+
if [[ "$context" == "stack" && -n "$stack_name" ]]; then
|
|
677
|
+
print_item "${p3}--" "Use in stack | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=use param6=$spec dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
678
|
+
print_item "${p3}--" "Shell (new window) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=shell param6=$spec param7=--new-window dir=$hstack_ROOT_DIR terminal=false"
|
|
679
|
+
print_item "${p3}--" "Open in VS Code | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=code param6=$spec dir=$hstack_ROOT_DIR terminal=false"
|
|
680
|
+
print_item "${p3}--" "Open in Cursor | bash=$hstack_BIN param1=stack param2=wt param3=$stack_name param4=-- param5=cursor param6=$spec dir=$hstack_ROOT_DIR terminal=false"
|
|
681
|
+
else
|
|
682
|
+
print_item "${p3}--" "Use | bash=$hstack_BIN param1=wt param2=use param3=$spec dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
683
|
+
print_item "${p3}--" "Shell (new window) | bash=$hstack_TERM param1=wt param2=shell param3=$spec param4=--new-window dir=$hstack_ROOT_DIR terminal=false"
|
|
684
|
+
print_item "${p3}--" "Open in VS Code | bash=$hstack_BIN param1=wt param2=code param3=$spec dir=$hstack_ROOT_DIR terminal=false"
|
|
685
|
+
print_item "${p3}--" "Open in Cursor | bash=$hstack_BIN param1=wt param2=cursor param3=$spec dir=$hstack_ROOT_DIR terminal=false"
|
|
686
|
+
fi
|
|
687
|
+
else
|
|
688
|
+
print_item "${p3}--" "Open folder | bash=/usr/bin/open param1='$wt_path' terminal=false"
|
|
689
|
+
fi
|
|
690
|
+
done <<<"$tsv"
|
|
691
|
+
fi
|
|
692
|
+
fi
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
render_components_menu() {
|
|
696
|
+
# Usage: render_components_menu <prefix> <context> <stack_name> <env_file>
|
|
697
|
+
local prefix="$1" # "" for main menu, "--" for inside a stack
|
|
698
|
+
local context="$2" # main|stack
|
|
699
|
+
local stack_name="$3"
|
|
700
|
+
local env_file="$4"
|
|
701
|
+
|
|
702
|
+
local t0 t1
|
|
703
|
+
t0="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
704
|
+
|
|
705
|
+
print_item "$prefix" "Components | sfimage=cube"
|
|
706
|
+
local p2="${prefix}--"
|
|
707
|
+
|
|
708
|
+
# Background auto-refresh: keep menu refresh snappy but update git cache when TTL expires.
|
|
709
|
+
if [[ "$(git_cache_mode)" == "cached" ]]; then
|
|
710
|
+
local scope
|
|
711
|
+
scope="$(git_cache_auto_refresh_scope)"
|
|
712
|
+
local refresh="$hstack_ROOT_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
713
|
+
if [[ -x "$refresh" ]]; then
|
|
714
|
+
if [[ "$scope" == "all" ]]; then
|
|
715
|
+
git_cache_maybe_refresh_async "all" "$refresh" all
|
|
716
|
+
elif [[ "$scope" == "main" && "$context" == "main" ]]; then
|
|
717
|
+
git_cache_maybe_refresh_async "main" "$refresh" main
|
|
718
|
+
fi
|
|
719
|
+
fi
|
|
720
|
+
fi
|
|
721
|
+
|
|
722
|
+
# Git cache controls (to keep the menu refresh fast while retaining rich inline worktrees UI).
|
|
723
|
+
local refresh="$hstack_ROOT_DIR/extras/swiftbar/git-cache-refresh.sh"
|
|
724
|
+
if [[ -f "$refresh" ]]; then
|
|
725
|
+
local mode ttl
|
|
726
|
+
mode="$(git_cache_mode)"
|
|
727
|
+
ttl="$(git_cache_ttl_sec)"
|
|
728
|
+
print_item "$p2" "Git cache | sfimage=arrow.triangle.2.circlepath"
|
|
729
|
+
local p3="${p2}--"
|
|
730
|
+
print_item "$p3" "Mode: ${mode} (default: cached)"
|
|
731
|
+
print_item "$p3" "TTL: ${ttl}s (set HAPPIER_STACK_SWIFTBAR_GIT_TTL_SEC)"
|
|
732
|
+
print_sep "$p3"
|
|
733
|
+
if [[ "$context" == "main" ]]; then
|
|
734
|
+
print_item "$p3" "Refresh now (main components) | bash=$refresh param1=main dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
735
|
+
print_item "$p3" "Refresh now (all stacks/components) | bash=$refresh param1=all dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
736
|
+
else
|
|
737
|
+
print_item "$p3" "Refresh now (this stack) | bash=$refresh param1=stack param2=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
738
|
+
fi
|
|
739
|
+
print_sep "$p2"
|
|
740
|
+
fi
|
|
741
|
+
|
|
742
|
+
# Always render the known components using the resolved component dirs (env file → env.local/.env → fallback),
|
|
743
|
+
# instead of assuming they live under a fixed workspace path.
|
|
744
|
+
local shared_repo_root=""
|
|
745
|
+
if [[ -n "$env_file" && -f "$env_file" ]]; then
|
|
746
|
+
local dir_h dir_c dir_s
|
|
747
|
+
dir_h="$(resolve_component_dir_from_env_file "$env_file" "happier-ui")"
|
|
748
|
+
dir_c="$(resolve_component_dir_from_env_file "$env_file" "happier-cli")"
|
|
749
|
+
dir_s="$(resolve_component_dir_from_env_file "$env_file" "happier-server")"
|
|
750
|
+
local root_h root_c root_s
|
|
751
|
+
root_h="$(swiftbar_find_git_root_upwards "$dir_h" 2>/dev/null || true)"
|
|
752
|
+
root_c="$(swiftbar_find_git_root_upwards "$dir_c" 2>/dev/null || true)"
|
|
753
|
+
root_s="$(swiftbar_find_git_root_upwards "$dir_s" 2>/dev/null || true)"
|
|
754
|
+
if [[ -n "$root_h" && "$root_h" == "$root_c" && "$root_h" == "$root_s" ]]; then
|
|
755
|
+
shared_repo_root="$root_h"
|
|
756
|
+
fi
|
|
757
|
+
fi
|
|
758
|
+
for c in happier-ui happier-cli happier-server-light happier-server; do
|
|
759
|
+
render_component_repo "$p2" "$c" "$context" "$stack_name" "$env_file" "$shared_repo_root"
|
|
760
|
+
print_sep "$p2"
|
|
761
|
+
done
|
|
762
|
+
|
|
763
|
+
t1="$(swiftbar_now_ms 2>/dev/null || echo 0)"
|
|
764
|
+
swiftbar_profile_log "time" "label=render_components_menu" "context=${context}" "stack=${stack_name}" "ms=$((t1 - t0))"
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
render_stack_overview_item() {
|
|
768
|
+
local title="$1"
|
|
769
|
+
local level="$2" # green|orange|red
|
|
770
|
+
local prefix="$3"
|
|
771
|
+
|
|
772
|
+
local icon_b64
|
|
773
|
+
icon_b64="$(status_icon_b64 "$level" 14)"
|
|
774
|
+
if [[ -n "$icon_b64" ]]; then
|
|
775
|
+
print_item "$prefix" "$title | image=$icon_b64"
|
|
776
|
+
else
|
|
777
|
+
print_item "$prefix" "$title"
|
|
778
|
+
fi
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
collect_stack_status() {
|
|
782
|
+
# Output (tab-separated):
|
|
783
|
+
# level server_status server_pid server_metrics daemon_status daemon_pid daemon_metrics daemon_uptime last_heartbeat launchagent_status autostart_pid autostart_metrics
|
|
784
|
+
local port="$1"
|
|
785
|
+
local cli_home_dir="$2"
|
|
786
|
+
local label="$3"
|
|
787
|
+
local base_dir="$4"
|
|
788
|
+
|
|
789
|
+
local server_status server_pid server_metrics
|
|
790
|
+
server_status="$(check_server_health "$port")"
|
|
791
|
+
server_pid=""
|
|
792
|
+
server_metrics=""
|
|
793
|
+
if [[ "$server_status" == "running" ]]; then
|
|
794
|
+
server_pid="$(get_port_listener_pid "$port")"
|
|
795
|
+
server_metrics="$(get_process_metrics "$server_pid")"
|
|
796
|
+
fi
|
|
797
|
+
|
|
798
|
+
local daemon_raw daemon_status daemon_pid daemon_metrics
|
|
799
|
+
daemon_raw="$(check_daemon_status "$cli_home_dir")"
|
|
800
|
+
daemon_status="$daemon_raw"
|
|
801
|
+
daemon_pid=""
|
|
802
|
+
if [[ "$daemon_raw" == running:* ]] || [[ "$daemon_raw" == running-no-http:* ]]; then
|
|
803
|
+
daemon_pid="${daemon_raw#*:}"
|
|
804
|
+
daemon_status="${daemon_raw%%:*}"
|
|
805
|
+
fi
|
|
806
|
+
daemon_metrics=""
|
|
807
|
+
if [[ -n "$daemon_pid" ]]; then
|
|
808
|
+
daemon_metrics="$(get_process_metrics "$daemon_pid")"
|
|
809
|
+
fi
|
|
810
|
+
|
|
811
|
+
local daemon_uptime last_heartbeat
|
|
812
|
+
daemon_uptime="$(get_daemon_uptime "$cli_home_dir")"
|
|
813
|
+
last_heartbeat="$(get_last_heartbeat "$cli_home_dir")"
|
|
814
|
+
|
|
815
|
+
local launchagent_status autostart_pid autostart_metrics
|
|
816
|
+
if swiftbar_is_sandboxed; then
|
|
817
|
+
launchagent_status="sandbox_disabled"
|
|
818
|
+
autostart_pid=""
|
|
819
|
+
autostart_metrics=""
|
|
820
|
+
else
|
|
821
|
+
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
|
|
822
|
+
launchagent_status="$(check_launchagent_status "$label" "$plist_path")"
|
|
823
|
+
autostart_pid=""
|
|
824
|
+
autostart_metrics=""
|
|
825
|
+
if [[ "$launchagent_status" != "not_installed" ]]; then
|
|
826
|
+
autostart_pid="$(launchagent_pid_for_label "$label")"
|
|
827
|
+
autostart_metrics="$(get_process_metrics "$autostart_pid")"
|
|
828
|
+
fi
|
|
829
|
+
fi
|
|
830
|
+
|
|
831
|
+
local level
|
|
832
|
+
level="$(level_from_server_daemon "$server_status" "$daemon_status")"
|
|
833
|
+
|
|
834
|
+
# Important: callers use `read` with IFS=$'\t' which collapses consecutive delimiters.
|
|
835
|
+
# Emit "-" placeholders for optional/empty fields so parsing stays stable.
|
|
836
|
+
local spid="${server_pid:-"-"}"
|
|
837
|
+
local smet="${server_metrics:-"-"}"
|
|
838
|
+
local dpid="${daemon_pid:-"-"}"
|
|
839
|
+
local dmet="${daemon_metrics:-"-"}"
|
|
840
|
+
local dupt="${daemon_uptime:-"-"}"
|
|
841
|
+
local dhb="${last_heartbeat:-"-"}"
|
|
842
|
+
local apid="${autostart_pid:-"-"}"
|
|
843
|
+
local amet="${autostart_metrics:-"-"}"
|
|
844
|
+
|
|
845
|
+
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
|
846
|
+
"$level" \
|
|
847
|
+
"$server_status" "$spid" "$smet" \
|
|
848
|
+
"$daemon_status" "$dpid" "$dmet" "$dupt" "$dhb" \
|
|
849
|
+
"$launchagent_status" "$apid" "$amet"
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
render_stack_info() {
|
|
853
|
+
# Renders a single "Info" item (with actions) at the given prefix.
|
|
854
|
+
local prefix="$1" # "" or "--"
|
|
855
|
+
local stack_name="$2"
|
|
856
|
+
local port="$3"
|
|
857
|
+
local server_component="$4"
|
|
858
|
+
local base_dir="$5"
|
|
859
|
+
local cli_home_dir="$6"
|
|
860
|
+
local label="$7"
|
|
861
|
+
local env_file="$8" # optional
|
|
862
|
+
local tailscale_url="$9" # optional
|
|
863
|
+
local server_metrics="${10:-}"
|
|
864
|
+
local daemon_metrics="${11:-}"
|
|
865
|
+
local autostart_metrics="${12:-}"
|
|
866
|
+
|
|
867
|
+
# Avoid low-contrast gray in the main list; keep it readable in both light/dark.
|
|
868
|
+
print_item "$prefix" "Stack details | sfimage=server.rack"
|
|
869
|
+
local p2="${prefix}--"
|
|
870
|
+
print_item "$p2" "Server component: ${server_component}"
|
|
871
|
+
local pinned_port=""
|
|
872
|
+
if [[ -n "$env_file" && -f "$env_file" ]]; then
|
|
873
|
+
pinned_port="$(dotenv_get "$env_file" "HAPPIER_STACK_SERVER_PORT")"
|
|
874
|
+
fi
|
|
875
|
+
local port_display="$port"
|
|
876
|
+
if [[ -z "$port_display" ]]; then
|
|
877
|
+
port_display="ephemeral (not running)"
|
|
878
|
+
elif [[ -z "$pinned_port" ]]; then
|
|
879
|
+
port_display="${port_display} (ephemeral)"
|
|
880
|
+
fi
|
|
881
|
+
print_item "$p2" "Port: ${port_display}"
|
|
882
|
+
print_item "$p2" "Label: ${label}"
|
|
883
|
+
[[ -n "$env_file" ]] && print_item "$p2" "Env: $(shorten_path "$env_file" 52)"
|
|
884
|
+
[[ -n "$tailscale_url" ]] && print_item "$p2" "Tailscale: $(shorten_text "$tailscale_url" 52)"
|
|
885
|
+
|
|
886
|
+
# Monorepo hint: if happier-ui + happier-cli + happier-server all share the same git root, show it once here.
|
|
887
|
+
if [[ -n "$env_file" && -f "$env_file" ]]; then
|
|
888
|
+
local dir_h dir_c dir_s
|
|
889
|
+
dir_h="$(resolve_component_dir_from_env_file "$env_file" "happier-ui")"
|
|
890
|
+
dir_c="$(resolve_component_dir_from_env_file "$env_file" "happier-cli")"
|
|
891
|
+
dir_s="$(resolve_component_dir_from_env_file "$env_file" "happier-server")"
|
|
892
|
+
local root_h root_c root_s
|
|
893
|
+
root_h="$(swiftbar_find_git_root_upwards "$dir_h" 2>/dev/null || true)"
|
|
894
|
+
root_c="$(swiftbar_find_git_root_upwards "$dir_c" 2>/dev/null || true)"
|
|
895
|
+
root_s="$(swiftbar_find_git_root_upwards "$dir_s" 2>/dev/null || true)"
|
|
896
|
+
if [[ -n "$root_h" && "$root_h" == "$root_c" && "$root_h" == "$root_s" ]]; then
|
|
897
|
+
print_item "$p2" "Happier monorepo: $(shorten_path "$root_h" 52) | color=$GRAY"
|
|
898
|
+
fi
|
|
899
|
+
fi
|
|
900
|
+
|
|
901
|
+
# Aggregate metrics (best-effort): sum the per-component process snapshots.
|
|
902
|
+
# NOTE: CPU may exceed 100% on multi-core machines.
|
|
903
|
+
local totals cpu_total mem_total
|
|
904
|
+
totals="$(swiftbar_sum_metrics_cpu_mem "$server_metrics" "$daemon_metrics" "$autostart_metrics" 2>/dev/null || true)"
|
|
905
|
+
cpu_total="$(echo "$totals" | cut -d'|' -f1)"
|
|
906
|
+
mem_total="$(echo "$totals" | cut -d'|' -f2)"
|
|
907
|
+
if [[ -n "$cpu_total" && -n "$mem_total" ]]; then
|
|
908
|
+
# Only show when we have at least one metric (avoid "0.0|0" noise on stopped stacks).
|
|
909
|
+
if [[ "$cpu_total" != "0.0" || "$mem_total" != "0" ]]; then
|
|
910
|
+
print_item "$p2" "Usage (server+daemon+autostart): CPU ${cpu_total}%, RAM ${mem_total}MB | color=$GRAY"
|
|
911
|
+
fi
|
|
912
|
+
fi
|
|
913
|
+
|
|
914
|
+
print_sep "$p2"
|
|
915
|
+
print_item "$p2" "Open repo | bash=/usr/bin/open param1='$hstack_ROOT_DIR' terminal=false"
|
|
916
|
+
print_item "$p2" "Open data dir | bash=/usr/bin/open param1='$base_dir' terminal=false"
|
|
917
|
+
print_item "$p2" "Open logs dir | bash=/usr/bin/open param1='${base_dir}/logs' terminal=false"
|
|
918
|
+
print_item "$p2" "Open CLI home | bash=/usr/bin/open param1='$cli_home_dir' terminal=false"
|
|
919
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
920
|
+
local main_env
|
|
921
|
+
main_env="$(resolve_main_env_file)"
|
|
922
|
+
if [[ -n "$main_env" ]]; then
|
|
923
|
+
print_item "$p2" "Edit main env | bash=/usr/bin/open param1=-a param2=TextEdit param3='$main_env' terminal=false"
|
|
924
|
+
else
|
|
925
|
+
local home
|
|
926
|
+
home="$(resolve_home_dir)"
|
|
927
|
+
print_item "$p2" "Edit env.local | bash=/usr/bin/open param1=-a param2=TextEdit param3='${home}/env.local' terminal=false"
|
|
928
|
+
fi
|
|
929
|
+
else
|
|
930
|
+
print_item "$p2" "Open stack env | bash=/usr/bin/open param1='$env_file' terminal=false"
|
|
931
|
+
fi
|
|
932
|
+
|
|
933
|
+
if [[ -z "$hstack_BIN" ]]; then
|
|
934
|
+
return
|
|
935
|
+
fi
|
|
936
|
+
print_sep "$p2"
|
|
937
|
+
|
|
938
|
+
local svc_installed="0"
|
|
939
|
+
if ! swiftbar_is_sandboxed; then
|
|
940
|
+
local plist="$HOME/Library/LaunchAgents/${label}.plist"
|
|
941
|
+
[[ -f "$plist" ]] && svc_installed="1"
|
|
942
|
+
fi
|
|
943
|
+
local menu_mode
|
|
944
|
+
menu_mode="$(resolve_menubar_mode)"
|
|
945
|
+
|
|
946
|
+
if [[ "$stack_name" == "main" ]]; then
|
|
947
|
+
if [[ "$svc_installed" == "1" ]]; then
|
|
948
|
+
# Status-aware: only show start/stop based on whether the stack is running.
|
|
949
|
+
if [[ "${MAIN_LEVEL:-}" == "red" ]]; then
|
|
950
|
+
print_item "$p2" "Start (service) | bash=$hstack_BIN param1=service:start dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
951
|
+
else
|
|
952
|
+
print_item "$p2" "Stop (service) | bash=$hstack_BIN param1=service:stop dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
953
|
+
fi
|
|
954
|
+
print_item "$p2" "Restart (service) | bash=$hstack_BIN param1=service:restart dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
955
|
+
else
|
|
956
|
+
if [[ "${MAIN_LEVEL:-}" == "red" ]]; then
|
|
957
|
+
print_item "$p2" "Start (foreground) | bash=$hstack_TERM param1=start dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
958
|
+
else
|
|
959
|
+
print_item "$p2" "Stop stack | bash=$hstack_BIN param1=stack param2=stop param3=main dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
960
|
+
fi
|
|
961
|
+
fi
|
|
962
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
963
|
+
print_item "$p2" "Dev mode | bash=$hstack_TERM param1=dev dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
964
|
+
fi
|
|
965
|
+
print_item "$p2" "Build UI | bash=$hstack_TERM param1=build dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
966
|
+
print_item "$p2" "Doctor | bash=$hstack_TERM param1=stack:doctor dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
967
|
+
return
|
|
968
|
+
fi
|
|
969
|
+
|
|
970
|
+
if [[ "$svc_installed" == "1" ]]; then
|
|
971
|
+
# Status-aware: only show start/stop based on whether the stack is running.
|
|
972
|
+
if [[ "$STACK_LEVEL" == "red" ]]; then
|
|
973
|
+
print_item "$p2" "Start (service) | bash=$hstack_BIN param1=stack param2=service:start param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
974
|
+
else
|
|
975
|
+
print_item "$p2" "Stop (service) | bash=$hstack_BIN param1=stack param2=service:stop param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
976
|
+
fi
|
|
977
|
+
print_item "$p2" "Restart (service) | bash=$hstack_BIN param1=stack param2=service:restart param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
978
|
+
else
|
|
979
|
+
if [[ "$STACK_LEVEL" == "red" ]]; then
|
|
980
|
+
print_item "$p2" "Start (foreground) | bash=$hstack_TERM param1=stack param2=start param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
981
|
+
else
|
|
982
|
+
print_item "$p2" "Stop stack | bash=$hstack_BIN param1=stack param2=stop param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
983
|
+
fi
|
|
984
|
+
fi
|
|
985
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
986
|
+
print_item "$p2" "Dev mode | bash=$hstack_TERM param1=stack param2=dev param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
987
|
+
fi
|
|
988
|
+
print_item "$p2" "Build UI | bash=$hstack_TERM param1=stack param2=build param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
989
|
+
print_item "$p2" "Doctor | bash=$hstack_TERM param1=stack param2=doctor param3=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
990
|
+
if [[ "$menu_mode" != "selfhost" ]]; then
|
|
991
|
+
print_item "$p2" "Edit stack (interactive) | bash=$hstack_TERM param1=stack param2=edit param3=$stack_name param4=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
992
|
+
print_item "$p2" "Select worktrees (interactive) | bash=$hstack_TERM param1=stack param2=wt param3=$stack_name param4=-- param5=use param6=--interactive dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
993
|
+
fi
|
|
994
|
+
|
|
995
|
+
local pr_helper="$hstack_ROOT_DIR/extras/swiftbar/wt-pr.sh"
|
|
996
|
+
if [[ "$menu_mode" != "selfhost" && -x "$pr_helper" ]]; then
|
|
997
|
+
print_item "$p2" "PR worktree into this stack (prompt) | bash=$pr_helper param1=_prompt_ param2=$stack_name dir=$hstack_ROOT_DIR terminal=false refresh=true"
|
|
998
|
+
fi
|
|
999
|
+
}
|