@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.
- 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 +138 -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 +74 -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,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# End-to-end (best-effort) smoke test for hstack on Ubuntu.
|
|
5
|
+
#
|
|
6
|
+
# Intended usage (inside a Lima VM):
|
|
7
|
+
# curl -fsSL https://raw.githubusercontent.com/<org>/<repo>/<ref>/apps/stack/scripts/provision/linux-ubuntu-review-pr.sh -o /tmp/linux-ubuntu-review-pr.sh \
|
|
8
|
+
# && chmod +x /tmp/linux-ubuntu-review-pr.sh \
|
|
9
|
+
# && /tmp/linux-ubuntu-review-pr.sh
|
|
10
|
+
#
|
|
11
|
+
# curl -fsSL https://raw.githubusercontent.com/<org>/<repo>/<ref>/apps/stack/scripts/provision/linux-ubuntu-e2e.sh -o /tmp/linux-ubuntu-e2e.sh \
|
|
12
|
+
# && chmod +x /tmp/linux-ubuntu-e2e.sh \
|
|
13
|
+
# && HSTACK_VERSION=latest /tmp/linux-ubuntu-e2e.sh
|
|
14
|
+
#
|
|
15
|
+
# Notes:
|
|
16
|
+
# - This uses `npx` by default (no reliance on global installs).
|
|
17
|
+
# - All state is isolated under a hstack sandbox dir so it can be deleted cleanly.
|
|
18
|
+
# - Authentication / Tailscale / autostart / menubar are intentionally skipped.
|
|
19
|
+
#
|
|
20
|
+
# Env overrides:
|
|
21
|
+
# - HSTACK_VERSION: npm dist-tag or semver for @happier-dev/stack (default: latest)
|
|
22
|
+
# - HSTACK_TGZ: path to a local @happier-dev/stack tarball inside the VM (overrides HSTACK_VERSION)
|
|
23
|
+
# - HSTACK_E2E_DIR: where to store the sandbox + logs (default: /tmp/hstack-e2e-<timestamp>)
|
|
24
|
+
# - HSTACK_E2E_KEEP: set to 1 to keep the sandbox dir on exit (default: 0)
|
|
25
|
+
|
|
26
|
+
require_cmd() {
|
|
27
|
+
command -v "$1" >/dev/null 2>&1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fail() {
|
|
31
|
+
echo "[e2e] failed: $*" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
say() {
|
|
36
|
+
echo ""
|
|
37
|
+
echo "==> $*"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
timestamp() {
|
|
41
|
+
date +"%Y%m%d-%H%M%S"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for cmd in bash curl git node npx jq; do
|
|
45
|
+
require_cmd "$cmd" || fail "missing required command: $cmd"
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
STACK_VERSION="${HSTACK_VERSION:-latest}"
|
|
49
|
+
STACK_TGZ="${HSTACK_TGZ:-}"
|
|
50
|
+
E2E_DIR="${HSTACK_E2E_DIR:-/tmp/hstack-e2e-$(timestamp)}"
|
|
51
|
+
KEEP="${HSTACK_E2E_KEEP:-0}"
|
|
52
|
+
|
|
53
|
+
SANDBOX_DIR="${E2E_DIR}/sandbox"
|
|
54
|
+
NPM_CACHE="${E2E_DIR}/npm-cache"
|
|
55
|
+
LOG_DIR="${E2E_DIR}/logs"
|
|
56
|
+
|
|
57
|
+
mkdir -p "$LOG_DIR" "$NPM_CACHE"
|
|
58
|
+
|
|
59
|
+
hstack() {
|
|
60
|
+
local spec
|
|
61
|
+
if [[ -n "$STACK_TGZ" ]]; then
|
|
62
|
+
spec="$STACK_TGZ"
|
|
63
|
+
else
|
|
64
|
+
spec="-p @happier-dev/stack@${STACK_VERSION}"
|
|
65
|
+
fi
|
|
66
|
+
# shellcheck disable=SC2086
|
|
67
|
+
npm_config_cache="$NPM_CACHE" \
|
|
68
|
+
npm_config_update_notifier=false \
|
|
69
|
+
npx --yes ${spec} hstack "$@"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
cleanup() {
|
|
73
|
+
if [[ "$KEEP" == "1" ]]; then
|
|
74
|
+
echo ""
|
|
75
|
+
echo "[e2e] keeping sandbox dir: $E2E_DIR"
|
|
76
|
+
return
|
|
77
|
+
fi
|
|
78
|
+
rm -rf "$E2E_DIR" >/dev/null 2>&1 || true
|
|
79
|
+
}
|
|
80
|
+
trap cleanup EXIT
|
|
81
|
+
|
|
82
|
+
say "system info"
|
|
83
|
+
echo "[e2e] node: $(node --version)"
|
|
84
|
+
echo "[e2e] npm: $(npm --version)"
|
|
85
|
+
echo "[e2e] git: $(git --version)"
|
|
86
|
+
echo "[e2e] jq: $(jq --version)"
|
|
87
|
+
echo "[e2e] pkg: @happier-dev/stack@${STACK_VERSION}"
|
|
88
|
+
|
|
89
|
+
say "hstack help (sanity)"
|
|
90
|
+
hstack --help >/dev/null
|
|
91
|
+
|
|
92
|
+
say "hstack where --json (sandbox wiring)"
|
|
93
|
+
WHERE_JSON="$(hstack --sandbox-dir "$SANDBOX_DIR" where --json | tee "$LOG_DIR/where.json")"
|
|
94
|
+
echo "$WHERE_JSON" | jq -e '.sandbox.enabled == true' >/dev/null || fail "expected sandbox.enabled=true"
|
|
95
|
+
echo "$WHERE_JSON" | jq -e '.repoDir | startswith("/tmp/") or startswith("/var/") or startswith("/home/")' >/dev/null || true
|
|
96
|
+
|
|
97
|
+
say "selfhost setup (no auth/tailscale/autostart/menubar)"
|
|
98
|
+
export HAPPIER_STACK_UPDATE_CHECK=0
|
|
99
|
+
hstack --sandbox-dir "$SANDBOX_DIR" setup \
|
|
100
|
+
--profile=selfhost \
|
|
101
|
+
--no-auth \
|
|
102
|
+
--no-tailscale \
|
|
103
|
+
--no-autostart \
|
|
104
|
+
--no-menubar \
|
|
105
|
+
--bind=loopback \
|
|
106
|
+
2>&1 | tee "$LOG_DIR/setup-selfhost.log"
|
|
107
|
+
|
|
108
|
+
say "resolve server URL"
|
|
109
|
+
START_JSON="$(hstack --sandbox-dir "$SANDBOX_DIR" start --json | tee "$LOG_DIR/start.json")"
|
|
110
|
+
INTERNAL_URL="$(echo "$START_JSON" | jq -r '.internalServerUrl')"
|
|
111
|
+
if [[ -z "$INTERNAL_URL" || "$INTERNAL_URL" == "null" ]]; then
|
|
112
|
+
fail "missing internalServerUrl from start --json"
|
|
113
|
+
fi
|
|
114
|
+
echo "[e2e] internal url: $INTERNAL_URL"
|
|
115
|
+
|
|
116
|
+
say "health check"
|
|
117
|
+
curl -fsS "${INTERNAL_URL}/health" | tee "$LOG_DIR/health.json" | jq -e '.status == "ok"' >/dev/null
|
|
118
|
+
|
|
119
|
+
say "UI served by server-light"
|
|
120
|
+
HTML_HEAD="$(curl -fsS "${INTERNAL_URL}/" | head -n 5 || true)"
|
|
121
|
+
echo "$HTML_HEAD" | tee "$LOG_DIR/ui.head.txt" | grep -Eqi '<!doctype html|<html' || fail "expected HTML from ${INTERNAL_URL}/"
|
|
122
|
+
|
|
123
|
+
say "worktree smoke (monorepo-only)"
|
|
124
|
+
# Create a throwaway worktree based on the default remote (keeps this test stable even if upstream remotes vary).
|
|
125
|
+
hstack --sandbox-dir "$SANDBOX_DIR" wt new "tmp/e2e-$(timestamp)" --from=origin --use --json | tee "$LOG_DIR/wt-new.json" >/dev/null
|
|
126
|
+
hstack --sandbox-dir "$SANDBOX_DIR" wt status --json | tee "$LOG_DIR/wt-status.json" >/dev/null
|
|
127
|
+
|
|
128
|
+
say "stop main stack (clean shutdown)"
|
|
129
|
+
hstack --sandbox-dir "$SANDBOX_DIR" stop --yes --aggressive --sweep-owned --no-service 2>&1 | tee "$LOG_DIR/stop-main.log"
|
|
130
|
+
|
|
131
|
+
say "done"
|
|
132
|
+
echo "[e2e] ok"
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Provision an Ubuntu VM for running hstack (Happier Stack) in an isolated Linux environment.
|
|
5
|
+
#
|
|
6
|
+
# Intended usage (inside a Lima VM):
|
|
7
|
+
# curl -fsSL https://raw.githubusercontent.com/happier-dev/happier/main/apps/stack/scripts/provision/linux-ubuntu-review-pr.sh -o /tmp/linux-ubuntu-review-pr.sh \
|
|
8
|
+
# && chmod +x /tmp/linux-ubuntu-review-pr.sh \
|
|
9
|
+
# && /tmp/linux-ubuntu-review-pr.sh
|
|
10
|
+
#
|
|
11
|
+
# After provisioning, run:
|
|
12
|
+
# npx --yes -p @happier-dev/stack@latest hstack setup --profile=dev --bind=loopback
|
|
13
|
+
|
|
14
|
+
require_cmd() {
|
|
15
|
+
command -v "$1" >/dev/null 2>&1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
as_root() {
|
|
19
|
+
if [[ "$(id -u)" == "0" ]]; then
|
|
20
|
+
"$@"
|
|
21
|
+
return
|
|
22
|
+
fi
|
|
23
|
+
if require_cmd sudo; then
|
|
24
|
+
sudo "$@"
|
|
25
|
+
return
|
|
26
|
+
fi
|
|
27
|
+
echo "[provision] missing sudo; re-run as root" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
echo "[provision] updating apt..."
|
|
32
|
+
as_root apt-get update -y
|
|
33
|
+
|
|
34
|
+
echo "[provision] installing base packages..."
|
|
35
|
+
as_root apt-get install -y --no-install-recommends \
|
|
36
|
+
ca-certificates \
|
|
37
|
+
curl \
|
|
38
|
+
git \
|
|
39
|
+
gnupg \
|
|
40
|
+
jq \
|
|
41
|
+
build-essential \
|
|
42
|
+
python3
|
|
43
|
+
|
|
44
|
+
if ! require_cmd node; then
|
|
45
|
+
echo "[provision] installing Node.js (NodeSource 24.x)..."
|
|
46
|
+
as_root bash -lc 'curl -fsSL https://deb.nodesource.com/setup_24.x | bash -'
|
|
47
|
+
as_root apt-get install -y nodejs
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "[provision] node: $(node --version)"
|
|
51
|
+
|
|
52
|
+
if ! require_cmd corepack; then
|
|
53
|
+
echo "[provision] corepack not found (expected with Node >=16)."
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "[provision] enabling corepack + yarn..."
|
|
58
|
+
corepack enable
|
|
59
|
+
corepack prepare yarn@1.22.22 --activate
|
|
60
|
+
yarn --version
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
echo "[provision] done."
|
|
64
|
+
echo ""
|
|
65
|
+
echo "Next:"
|
|
66
|
+
echo " npx --yes -p @happier-dev/stack@latest hstack setup --profile=dev --bind=loopback"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Create/configure a Lima VM for testing hstack in an isolated Linux environment,
|
|
5
|
+
# while still opening the Expo web UI on the macOS host via localhost port forwarding
|
|
6
|
+
# (required for WebCrypto/secure-context APIs).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# ./scripts/provision/macos-lima-happy-vm.sh [vm-name]
|
|
10
|
+
#
|
|
11
|
+
# Defaults:
|
|
12
|
+
# vm-name: happy-test
|
|
13
|
+
# template: ubuntu-24.04
|
|
14
|
+
#
|
|
15
|
+
# What it does:
|
|
16
|
+
# - creates the VM (if missing)
|
|
17
|
+
# - injects port forwarding rules for the hstack VM port ranges
|
|
18
|
+
# - restarts the VM so the rules take effect
|
|
19
|
+
# - prints next steps (provision script + hstack commands)
|
|
20
|
+
|
|
21
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
22
|
+
cat <<'EOF'
|
|
23
|
+
Usage:
|
|
24
|
+
./scripts/provision/macos-lima-happy-vm.sh [vm-name]
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
./scripts/provision/macos-lima-happy-vm.sh # uses "happy-test"
|
|
28
|
+
./scripts/provision/macos-lima-happy-vm.sh happy # uses "happy"
|
|
29
|
+
./scripts/provision/macos-lima-happy-vm.sh happy-vm # uses "happy-vm"
|
|
30
|
+
|
|
31
|
+
Notes:
|
|
32
|
+
- This is intended to be run on the macOS host (not inside the VM).
|
|
33
|
+
- It configures localhost port forwarding so you can open http://localhost / http://*.localhost
|
|
34
|
+
in your macOS browser (required for WebCrypto APIs used by Expo web).
|
|
35
|
+
EOF
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
40
|
+
echo "[lima] expected macOS (Darwin); got: $(uname -s)" >&2
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if ! command -v limactl >/dev/null 2>&1; then
|
|
45
|
+
echo "[lima] limactl not found. Install Lima first (example: brew install lima)." >&2
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
VM_NAME="${1:-happy-test}"
|
|
50
|
+
TEMPLATE="${LIMA_TEMPLATE:-ubuntu-24.04}"
|
|
51
|
+
LIMA_MEMORY="${LIMA_MEMORY:-8GiB}"
|
|
52
|
+
LIMA_VM_TYPE="${LIMA_VM_TYPE:-}" # optional: vz|qemu|krunkit (see: limactl create --list-drivers)
|
|
53
|
+
TEMPLATE_LOCATOR="${TEMPLATE}"
|
|
54
|
+
if [[ "${TEMPLATE_LOCATOR}" == template://* ]]; then
|
|
55
|
+
TEMPLATE_LOCATOR="template:${TEMPLATE_LOCATOR#template://}"
|
|
56
|
+
elif [[ "${TEMPLATE_LOCATOR}" != template:* ]]; then
|
|
57
|
+
TEMPLATE_LOCATOR="template:${TEMPLATE_LOCATOR}"
|
|
58
|
+
fi
|
|
59
|
+
LIMA_HOME_DIR="${LIMA_HOME:-${HOME}/.lima}"
|
|
60
|
+
export LIMA_HOME="${LIMA_HOME_DIR}"
|
|
61
|
+
LIMA_DIR="${LIMA_HOME_DIR}/${VM_NAME}"
|
|
62
|
+
LIMA_YAML="${LIMA_DIR}/lima.yaml"
|
|
63
|
+
|
|
64
|
+
echo "[lima] vm: ${VM_NAME}"
|
|
65
|
+
echo "[lima] template: ${TEMPLATE}"
|
|
66
|
+
echo "[lima] memory: ${LIMA_MEMORY} (override with LIMA_MEMORY=...)"
|
|
67
|
+
echo "[lima] LIMA_HOME: ${LIMA_HOME_DIR}"
|
|
68
|
+
if [[ -n "${LIMA_VM_TYPE}" ]]; then
|
|
69
|
+
echo "[lima] vmType: ${LIMA_VM_TYPE}"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [[ ! -f "${LIMA_YAML}" ]]; then
|
|
73
|
+
echo "[lima] creating VM..."
|
|
74
|
+
if [[ "${LIMA_VM_TYPE}" == "qemu" ]]; then
|
|
75
|
+
if ! command -v qemu-system-aarch64 >/dev/null 2>&1; then
|
|
76
|
+
echo "[lima] qemu vmType requested but qemu-system-aarch64 is missing." >&2
|
|
77
|
+
echo "[lima] Fix: brew install qemu" >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
create_args=(create --name "${VM_NAME}" --tty=false)
|
|
82
|
+
if [[ -n "${LIMA_VM_TYPE}" ]]; then
|
|
83
|
+
create_args+=(--vm-type "${LIMA_VM_TYPE}")
|
|
84
|
+
fi
|
|
85
|
+
create_args+=("${TEMPLATE_LOCATOR}")
|
|
86
|
+
limactl "${create_args[@]}"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
if [[ ! -f "${LIMA_YAML}" ]]; then
|
|
90
|
+
echo "[lima] expected instance config at: ${LIMA_YAML}" >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo "[lima] stopping VM (if running)..."
|
|
95
|
+
limactl stop "${VM_NAME}" >/dev/null 2>&1 || true
|
|
96
|
+
|
|
97
|
+
echo "[lima] configuring port forwarding (localhost)..."
|
|
98
|
+
cp -a "${LIMA_YAML}" "${LIMA_YAML}.bak.$(date +%Y%m%d-%H%M%S)"
|
|
99
|
+
|
|
100
|
+
VM_NAME="${VM_NAME}" LIMA_YAML="${LIMA_YAML}" LIMA_MEMORY="${LIMA_MEMORY}" python3 - <<'PY'
|
|
101
|
+
import os, re
|
|
102
|
+
from pathlib import Path
|
|
103
|
+
|
|
104
|
+
vm_name = os.environ["VM_NAME"]
|
|
105
|
+
path = Path(os.environ["LIMA_YAML"])
|
|
106
|
+
memory = os.environ.get("LIMA_MEMORY", "8GiB")
|
|
107
|
+
text = path.read_text(encoding="utf-8")
|
|
108
|
+
|
|
109
|
+
MEM_MARK_BEGIN = "# --- hstack vm sizing (managed by hstack) ---"
|
|
110
|
+
MEM_MARK_END = "# --- /hstack vm sizing ---"
|
|
111
|
+
MARK_BEGIN = "# --- hstack port forwards (managed by hstack) ---"
|
|
112
|
+
MARK_END = "# --- /hstack port forwards ---"
|
|
113
|
+
|
|
114
|
+
entries = [
|
|
115
|
+
" - guestPortRange: [13000, 13999]\n hostPortRange: [13000, 13999]\n",
|
|
116
|
+
" - guestPortRange: [18000, 19099]\n hostPortRange: [18000, 19099]\n",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
mem_block = (
|
|
120
|
+
f"\n{MEM_MARK_BEGIN}\n"
|
|
121
|
+
f'memory: "{memory}"\n'
|
|
122
|
+
f"{MEM_MARK_END}\n"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
block_as_section = (
|
|
126
|
+
f"\n{MARK_BEGIN}\n"
|
|
127
|
+
"portForwards:\n"
|
|
128
|
+
+ "".join(entries) +
|
|
129
|
+
f"{MARK_END}\n"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
block_as_list_items = (
|
|
133
|
+
f" # --- hstack port forwards (managed by hstack) ---\n"
|
|
134
|
+
+ "".join(entries) +
|
|
135
|
+
f" # --- /hstack port forwards ---\n"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if MEM_MARK_BEGIN in text and MEM_MARK_END in text:
|
|
139
|
+
text = re.sub(
|
|
140
|
+
re.escape(MEM_MARK_BEGIN) + r"[\\s\\S]*?" + re.escape(MEM_MARK_END) + r"\\n?",
|
|
141
|
+
mem_block.strip("\n") + "\n",
|
|
142
|
+
text,
|
|
143
|
+
flags=re.MULTILINE,
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
m = re.search(r"^memory:\\s*.*$", text, flags=re.MULTILINE)
|
|
147
|
+
if m:
|
|
148
|
+
text = re.sub(r"^memory:\\s*.*$", f'memory: "{memory}"', text, flags=re.MULTILINE)
|
|
149
|
+
else:
|
|
150
|
+
text = text.rstrip() + mem_block
|
|
151
|
+
|
|
152
|
+
if MARK_BEGIN in text and MARK_END in text:
|
|
153
|
+
text = re.sub(
|
|
154
|
+
re.escape(MARK_BEGIN) + r"[\\s\\S]*?" + re.escape(MARK_END) + r"\\n?",
|
|
155
|
+
block_as_section.strip("\n") + "\n",
|
|
156
|
+
text,
|
|
157
|
+
flags=re.MULTILINE,
|
|
158
|
+
)
|
|
159
|
+
else:
|
|
160
|
+
m = re.search(r"^portForwards:\\s*$", text, flags=re.MULTILINE)
|
|
161
|
+
if m:
|
|
162
|
+
insert_at = m.end()
|
|
163
|
+
text = text[:insert_at] + "\n" + block_as_list_items + text[insert_at:]
|
|
164
|
+
else:
|
|
165
|
+
text = text.rstrip() + block_as_section
|
|
166
|
+
|
|
167
|
+
path.write_text(text, encoding="utf-8")
|
|
168
|
+
print(f"[lima] updated {path} ({vm_name})")
|
|
169
|
+
PY
|
|
170
|
+
|
|
171
|
+
echo "[lima] starting VM..."
|
|
172
|
+
limactl start "${VM_NAME}"
|
|
173
|
+
|
|
174
|
+
cat <<EOF
|
|
175
|
+
|
|
176
|
+
[lima] done.
|
|
177
|
+
|
|
178
|
+
Next steps:
|
|
179
|
+
limactl shell ${VM_NAME}
|
|
180
|
+
|
|
181
|
+
Inside the VM:
|
|
182
|
+
curl -fsSL https://raw.githubusercontent.com/happier-dev/happier/main/apps/stack/scripts/provision/linux-ubuntu-review-pr.sh -o /tmp/linux-ubuntu-review-pr.sh \\
|
|
183
|
+
&& chmod +x /tmp/linux-ubuntu-review-pr.sh \\
|
|
184
|
+
&& /tmp/linux-ubuntu-review-pr.sh
|
|
185
|
+
|
|
186
|
+
Then:
|
|
187
|
+
npx --yes -p @happier-dev/stack@latest hstack setup --profile=dev --bind=loopback
|
|
188
|
+
|
|
189
|
+
Tip:
|
|
190
|
+
Open the printed URLs on your macOS host via http://localhost:<port> or http://*.localhost:<port>.
|
|
191
|
+
For `npx --yes -p @happier-dev/stack hstack review-pr ...` inside the VM, pass `--vm-ports` so stack ports land in the forwarded ranges.
|
|
192
|
+
EOF
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Automated Lima VM E2E smoke test runner for hstack.
|
|
5
|
+
#
|
|
6
|
+
# Usage (macOS host):
|
|
7
|
+
# ./scripts/provision/macos-lima-hstack-e2e.sh [vm-name]
|
|
8
|
+
#
|
|
9
|
+
# Env:
|
|
10
|
+
# HSTACK_VERSION=latest # @happier-dev/stack version to test (default: latest)
|
|
11
|
+
# HSTACK_E2E_KEEP=1 # keep sandbox dir in the VM (default: 0)
|
|
12
|
+
# HSTACK_RAW_BASE=... # override raw github base (default: happier-dev/happier main)
|
|
13
|
+
#
|
|
14
|
+
# This script:
|
|
15
|
+
# - creates/configures a Lima VM (via macos-lima-happy-vm.sh)
|
|
16
|
+
# - provisions Node/Yarn inside the VM
|
|
17
|
+
# - runs a sandboxed `hstack` selfhost+worktree smoke test inside the VM
|
|
18
|
+
|
|
19
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
20
|
+
cat <<'EOF'
|
|
21
|
+
Usage:
|
|
22
|
+
./scripts/provision/macos-lima-hstack-e2e.sh [vm-name]
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
./scripts/provision/macos-lima-hstack-e2e.sh
|
|
26
|
+
HSTACK_VERSION=latest ./scripts/provision/macos-lima-hstack-e2e.sh happy-e2e
|
|
27
|
+
|
|
28
|
+
Notes:
|
|
29
|
+
- Run on macOS (Darwin) host.
|
|
30
|
+
- Uses a fully isolated sandbox inside the VM (does not touch ~/.happier-stack on the VM).
|
|
31
|
+
EOF
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
36
|
+
echo "[lima-e2e] expected macOS (Darwin); got: $(uname -s)" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if ! command -v limactl >/dev/null 2>&1; then
|
|
41
|
+
echo "[lima-e2e] limactl not found. Install Lima first (example: brew install lima)." >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
46
|
+
VM_NAME="${1:-happy-e2e}"
|
|
47
|
+
|
|
48
|
+
HSTACK_VERSION="${HSTACK_VERSION:-latest}"
|
|
49
|
+
HSTACK_E2E_KEEP="${HSTACK_E2E_KEEP:-0}"
|
|
50
|
+
|
|
51
|
+
pick_raw_base() {
|
|
52
|
+
if [[ -n "${HSTACK_RAW_BASE:-}" ]]; then
|
|
53
|
+
echo "${HSTACK_RAW_BASE}"
|
|
54
|
+
return 0
|
|
55
|
+
fi
|
|
56
|
+
local candidates=(
|
|
57
|
+
"https://raw.githubusercontent.com/happier-dev/happier/main/apps/stack"
|
|
58
|
+
)
|
|
59
|
+
local c
|
|
60
|
+
for c in "${candidates[@]}"; do
|
|
61
|
+
if curl -fsSL "${c}/scripts/provision/linux-ubuntu-review-pr.sh" -o /dev/null >/dev/null 2>&1; then
|
|
62
|
+
echo "$c"
|
|
63
|
+
return 0
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
return 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
HSTACK_RAW_BASE="$(pick_raw_base || true)"
|
|
70
|
+
if [[ -z "${HSTACK_RAW_BASE}" ]]; then
|
|
71
|
+
echo "[lima-e2e] failed to auto-detect raw GitHub base URL for scripts." >&2
|
|
72
|
+
echo "[lima-e2e] Fix: set HSTACK_RAW_BASE=https://raw.githubusercontent.com/<org>/<repo>/<ref>/apps/stack" >&2
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "[lima-e2e] vm: ${VM_NAME}"
|
|
77
|
+
echo "[lima-e2e] @happier-dev/stack: ${HSTACK_VERSION}"
|
|
78
|
+
echo "[lima-e2e] raw base: ${HSTACK_RAW_BASE}"
|
|
79
|
+
|
|
80
|
+
echo "[lima-e2e] ensure VM exists + port forwarding..."
|
|
81
|
+
"${SCRIPT_DIR}/macos-lima-happy-vm.sh" "${VM_NAME}"
|
|
82
|
+
|
|
83
|
+
echo "[lima-e2e] running provisioning + e2e inside VM..."
|
|
84
|
+
limactl shell "${VM_NAME}" -- bash -lc "
|
|
85
|
+
set -euo pipefail
|
|
86
|
+
echo '[vm] downloading provision + e2e scripts...'
|
|
87
|
+
curl -fsSL '${HSTACK_RAW_BASE}/scripts/provision/linux-ubuntu-review-pr.sh' -o /tmp/linux-ubuntu-review-pr.sh
|
|
88
|
+
chmod +x /tmp/linux-ubuntu-review-pr.sh
|
|
89
|
+
/tmp/linux-ubuntu-review-pr.sh
|
|
90
|
+
|
|
91
|
+
curl -fsSL '${HSTACK_RAW_BASE}/scripts/provision/linux-ubuntu-e2e.sh' -o /tmp/linux-ubuntu-e2e.sh
|
|
92
|
+
chmod +x /tmp/linux-ubuntu-e2e.sh
|
|
93
|
+
|
|
94
|
+
export HSTACK_VERSION='${HSTACK_VERSION}'
|
|
95
|
+
export HSTACK_E2E_KEEP='${HSTACK_E2E_KEEP}'
|
|
96
|
+
/tmp/linux-ubuntu-e2e.sh
|
|
97
|
+
"
|
|
98
|
+
|
|
99
|
+
echo ""
|
|
100
|
+
echo "[lima-e2e] done."
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
function run(cmd, args) {
|
|
4
|
+
const result = spawnSync(cmd, args, { stdio: "inherit" });
|
|
5
|
+
if (result.error) throw result.error;
|
|
6
|
+
if (typeof result.status === "number" && result.status !== 0) process.exit(result.status);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function usageAndExit() {
|
|
10
|
+
// Keep this very short; this is an internal dev script.
|
|
11
|
+
console.error("Usage: npm run release -- <patch|minor|major>");
|
|
12
|
+
console.error("");
|
|
13
|
+
console.error("Options:");
|
|
14
|
+
console.error(" --no-git Skip git commit/tag (allows dirty working tree).");
|
|
15
|
+
console.error(" --dry-run Run npm publish with --dry-run.");
|
|
16
|
+
process.exit(2);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
if (args[0] === "--") args.shift();
|
|
21
|
+
|
|
22
|
+
const noGit = args.includes("--no-git");
|
|
23
|
+
const dryRun = args.includes("--dry-run");
|
|
24
|
+
|
|
25
|
+
const bump = args.find((a) => ["patch", "minor", "major"].includes(a));
|
|
26
|
+
if (!bump) usageAndExit();
|
|
27
|
+
|
|
28
|
+
// Ensure we're authenticated before doing anything that creates a version commit/tag.
|
|
29
|
+
const whoami = spawnSync("npm", ["whoami"], { stdio: "ignore" });
|
|
30
|
+
if (typeof whoami.status === "number" && whoami.status !== 0) {
|
|
31
|
+
run("npm", ["login"]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!noGit) {
|
|
35
|
+
// `npm version` makes a git commit + tag by default; it requires a clean working tree.
|
|
36
|
+
const status = spawnSync("git", ["status", "--porcelain"], { encoding: "utf8" });
|
|
37
|
+
if (typeof status.status === "number" && status.status === 0) {
|
|
38
|
+
const out = (status.stdout ?? "").trim();
|
|
39
|
+
if (out.length > 0) {
|
|
40
|
+
console.error("Refusing to version: git working tree is not clean.");
|
|
41
|
+
console.error("`npm version` creates a commit + tag, so it requires a clean tree.");
|
|
42
|
+
console.error("Commit/stash your changes, or re-run with --no-git if you accept publishing uncommitted files.");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
run("npm", ["version", bump, "-m", "chore(release): %s"]);
|
|
48
|
+
} else {
|
|
49
|
+
// Allow dirty working trees by skipping commit/tagging.
|
|
50
|
+
run("npm", ["version", bump, "--no-git-tag-version", "--force"]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
run("npm", ["publish", ...(dryRun ? ["--dry-run"] : [])]);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdtemp, readdir } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import test from 'node:test';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
function commandExists(cmd) {
|
|
10
|
+
return spawnSync('bash', ['-lc', `command -v ${cmd} >/dev/null 2>&1`], { stdio: 'ignore' }).status === 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function currentTarget() {
|
|
14
|
+
const os = process.platform === 'linux' ? 'linux' : process.platform === 'darwin' ? 'darwin' : '';
|
|
15
|
+
const arch = process.arch === 'x64' ? 'x64' : process.arch === 'arm64' ? 'arm64' : '';
|
|
16
|
+
if (!os || !arch) return '';
|
|
17
|
+
return `${os}-${arch}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isLinuxTarget(target) {
|
|
21
|
+
return String(target).startsWith('linux-');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function extractBinaryFromArtifact({ artifactPath, binaryName }) {
|
|
25
|
+
const extractDir = await mkdtemp(join(tmpdir(), 'happier-release-binary-smoke-'));
|
|
26
|
+
const untar = spawnSync('tar', ['-xzf', artifactPath, '-C', extractDir], { encoding: 'utf-8' });
|
|
27
|
+
assert.equal(untar.status, 0, untar.stderr);
|
|
28
|
+
|
|
29
|
+
const entries = await readdir(extractDir);
|
|
30
|
+
assert.ok(entries.length > 0, `expected extracted root in ${artifactPath}`);
|
|
31
|
+
return {
|
|
32
|
+
extractDir,
|
|
33
|
+
binaryPath: join(extractDir, entries[0], binaryName),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test('compiled happier and server binaries execute from isolated cwd', async (t) => {
|
|
38
|
+
if (!commandExists('bun')) {
|
|
39
|
+
t.skip('bun is required for compiled binary smoke tests');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const target = currentTarget();
|
|
43
|
+
if (!target) {
|
|
44
|
+
t.skip(`unsupported platform for smoke test: ${process.platform}-${process.arch}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const repoRoot = resolve(fileURLToPath(new URL('../../..', import.meta.url)));
|
|
49
|
+
const version = `0.0.0-smoke.${Date.now()}`;
|
|
50
|
+
|
|
51
|
+
const buildCli = spawnSync(
|
|
52
|
+
process.execPath,
|
|
53
|
+
[
|
|
54
|
+
'scripts/release/build-cli-binaries.mjs',
|
|
55
|
+
'--channel=preview',
|
|
56
|
+
`--version=${version}`,
|
|
57
|
+
`--targets=${target}`,
|
|
58
|
+
],
|
|
59
|
+
{
|
|
60
|
+
cwd: repoRoot,
|
|
61
|
+
encoding: 'utf-8',
|
|
62
|
+
env: { ...process.env },
|
|
63
|
+
// `inherit` makes it easier to read interactively, but on CI failures we need the full output.
|
|
64
|
+
// Increase buffer because build logs can be large.
|
|
65
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
assert.equal(buildCli.status, 0, `${buildCli.stderr || ''}\n${buildCli.stdout || ''}`.trim());
|
|
69
|
+
|
|
70
|
+
const cliArtifactPath = join(repoRoot, 'dist', 'release-assets', 'cli', `happier-v${version}-${target}.tar.gz`);
|
|
71
|
+
const cliExtract = await extractBinaryFromArtifact({ artifactPath: cliArtifactPath, binaryName: 'happier' });
|
|
72
|
+
t.after(() => {
|
|
73
|
+
spawnSync('bash', ['-lc', `rm -rf "${cliExtract.extractDir.replaceAll('"', '\\"')}"`], { stdio: 'ignore' });
|
|
74
|
+
});
|
|
75
|
+
const cliVersion = spawnSync(cliExtract.binaryPath, ['--version'], {
|
|
76
|
+
cwd: '/tmp',
|
|
77
|
+
encoding: 'utf-8',
|
|
78
|
+
env: { ...process.env, HAPPIER_NONINTERACTIVE: '1' },
|
|
79
|
+
timeout: 7000,
|
|
80
|
+
});
|
|
81
|
+
const cliTimedOut = cliVersion.error && cliVersion.error.code === 'ETIMEDOUT';
|
|
82
|
+
const cliExited = (cliVersion.status ?? 1) === 0;
|
|
83
|
+
assert.ok(cliTimedOut || cliExited, cliVersion.stderr || cliVersion.stdout);
|
|
84
|
+
const versionText = `${cliVersion.stdout || ''}${cliVersion.stderr || ''}`.trim();
|
|
85
|
+
assert.ok(
|
|
86
|
+
/version/i.test(versionText) || /^\d+\.\d+\.\d+([-+][0-9A-Za-z.-]+)?$/.test(versionText),
|
|
87
|
+
`expected CLI version output, got: ${versionText || '<empty>'}`,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (isLinuxTarget(target)) {
|
|
91
|
+
const buildServer = spawnSync(
|
|
92
|
+
process.execPath,
|
|
93
|
+
[
|
|
94
|
+
'scripts/release/build-server-binaries.mjs',
|
|
95
|
+
'--channel=preview',
|
|
96
|
+
`--version=${version}`,
|
|
97
|
+
`--targets=${target}`,
|
|
98
|
+
],
|
|
99
|
+
{
|
|
100
|
+
cwd: repoRoot,
|
|
101
|
+
encoding: 'utf-8',
|
|
102
|
+
env: { ...process.env },
|
|
103
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
assert.equal(buildServer.status, 0, `${buildServer.stderr || ''}\n${buildServer.stdout || ''}`.trim());
|
|
107
|
+
|
|
108
|
+
const serverArtifactPath = join(repoRoot, 'dist', 'release-assets', 'server', `happier-server-v${version}-${target}.tar.gz`);
|
|
109
|
+
const serverExtract = await extractBinaryFromArtifact({ artifactPath: serverArtifactPath, binaryName: 'happier-server' });
|
|
110
|
+
t.after(() => {
|
|
111
|
+
spawnSync('bash', ['-lc', `rm -rf "${serverExtract.extractDir.replaceAll('"', '\\"')}"`], { stdio: 'ignore' });
|
|
112
|
+
});
|
|
113
|
+
const serverDataDir = await mkdtemp(join(tmpdir(), 'happier-server-binary-smoke-data-'));
|
|
114
|
+
t.after(() => {
|
|
115
|
+
spawnSync('bash', ['-lc', `rm -rf "${serverDataDir.replaceAll('"', '\\"')}"`], { stdio: 'ignore' });
|
|
116
|
+
});
|
|
117
|
+
const serverBoot = spawnSync(serverExtract.binaryPath, [], {
|
|
118
|
+
cwd: '/tmp',
|
|
119
|
+
encoding: 'utf-8',
|
|
120
|
+
env: {
|
|
121
|
+
...process.env,
|
|
122
|
+
PORT: '3905',
|
|
123
|
+
HAPPIER_SERVER_HOST: '127.0.0.1',
|
|
124
|
+
HAPPY_DB_PROVIDER: 'sqlite',
|
|
125
|
+
HAPPIER_DB_PROVIDER: 'sqlite',
|
|
126
|
+
DATABASE_URL: `file:${serverDataDir}/happier-server-light.sqlite`,
|
|
127
|
+
HAPPY_SERVER_LIGHT_DATA_DIR: serverDataDir,
|
|
128
|
+
HAPPIER_SERVER_LIGHT_DATA_DIR: serverDataDir,
|
|
129
|
+
},
|
|
130
|
+
timeout: 7000,
|
|
131
|
+
});
|
|
132
|
+
const timedOut = serverBoot.error && serverBoot.error.code === 'ETIMEDOUT';
|
|
133
|
+
const cleanExit = (serverBoot.status ?? 1) === 0;
|
|
134
|
+
const serverOutput = `${serverBoot.stderr || ''}\n${serverBoot.stdout || ''}`;
|
|
135
|
+
assert.ok(timedOut || cleanExit, serverOutput);
|
|
136
|
+
assert.doesNotMatch(serverOutput, /ERR_MODULE_NOT_FOUND|Cannot find module/i);
|
|
137
|
+
}
|
|
138
|
+
});
|