From c9b3ade048b6423a36d7cc5a23253d074db0a970 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 24 Mar 2026 14:46:58 +0000 Subject: [PATCH] Expose managed dev runtime entrypoint --- README.md | 26 +++++++++++++ .../subsystems/deployment-installability.md | 9 ++++- package.json | 8 ++++ scripts/tests/test-hot-dev-bg.sh | 37 +++++++++++++++++++ tests/integration/README.md | 6 +++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c330dff0..5913edcdc 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,32 @@ docker run -d \ Access the dashboard at `http://:7655`. +## Local Development + +Use the managed dev runtime from the repo root: + +```bash +npm run dev +``` + +Open `http://127.0.0.1:5173` in the browser. `5173` is the frontend dev shell, +and it proxies `/api` and `/ws` to the backend on `7655`. `7655` is the backend +dependency for API and websocket traffic, not the primary browser URL for local +frontend development. + +Canonical local dev commands: + +- `npm run dev` — start the managed runtime and reclaim the canonical dev ports if an older unmanaged session is still using them +- `npm run dev:status` — show frontend shell health, proxied API health, direct backend health, and listener ownership +- `npm run dev:verify` — run the managed browser recovery proof against the live dev runtime +- `npm run dev:logs` — tail the managed runtime log +- `npm run dev:backend-restart` — bounce only the managed backend through the launcher contract +- `npm run dev:stop` — stop the managed runtime +- `npm run dev:foreground` — run the foreground hot-reload launcher intentionally if you need an attached shell + +If `npm run dev:verify` passes, the managed dev shell, proxy path, backend +health endpoint, and browser recovery path are all aligned. + ## 📚 Documentation - **[Installation Guide](docs/INSTALL.md)**: Detailed instructions for Docker, Kubernetes, and bare metal. diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index b2acaffbc..43e520bd5 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -32,6 +32,7 @@ server-side update execution surfaces. 10. `scripts/hot-dev.sh` 11. `scripts/hot-dev-bg.sh` 12. `tests/integration/scripts/managed-dev-runtime.mjs` +13. `package.json` ## Shared Boundaries @@ -46,7 +47,7 @@ server-side update execution surfaces. 2. Add or change release-build metadata injection, release artifact assembly, or governed promotion metadata resolution through `scripts/build-release.sh`, `scripts/release_ldflags.sh`, and `scripts/release_control/resolve_release_promotion.py`, plus the container Dockerfile and governed release workflows that consume those same contracts 3. Add or change shell installer, Windows installer, container-agent installer, or auto-update script behavior through `scripts/install.sh`, `scripts/install.ps1`, `scripts/install-container-agent.sh`, and `scripts/pulse-auto-update.sh` 4. Add or change server update transport through `internal/api/updates.go` and `frontend-modern/src/api/updates.ts` -5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, or frontend/backend coherence diagnostics through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, and `tests/integration/scripts/managed-dev-runtime.mjs` +5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, frontend/backend coherence diagnostics, or the canonical root dev-entry wrappers through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, `tests/integration/scripts/managed-dev-runtime.mjs`, and `package.json` ## Forbidden Paths @@ -167,6 +168,12 @@ managed runtime, run the canonical browser recovery proof with the managed dev credentials and browser entrypoint defaults, and fail with ownership or health diagnostics instead of leaving operators to remember the exact Playwright command and env combination by hand. +That same launcher boundary now also owns the canonical repo-root developer +entry surface. `package.json` must expose the managed runtime as the default +local dev path, including explicit status, log, stop, backend-restart, and +verification wrappers, instead of requiring developers to remember +lane-specific shell paths or continue discovering the runtime through a stale +unmanaged `5173` process by accident. That shared `scripts/install.sh` boundary must also keep one canonical service argument builder for the runtime flags it persists. Token-bearing install paths, token-file systemd paths, wrapper-script launches, and later service diff --git a/package.json b/package.json index 590774f39..02fbe53f9 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,14 @@ "test": "tests" }, "scripts": { + "dev": "./scripts/hot-dev-bg.sh start --takeover", + "dev:status": "./scripts/hot-dev-bg.sh status", + "dev:logs": "./scripts/hot-dev-bg.sh logs", + "dev:stop": "./scripts/hot-dev-bg.sh stop", + "dev:restart": "./scripts/hot-dev-bg.sh restart --takeover", + "dev:backend-restart": "./scripts/hot-dev-bg.sh backend-restart", + "dev:verify": "./scripts/hot-dev-bg.sh verify --takeover", + "dev:foreground": "./scripts/hot-dev.sh", "test": "echo \"Error: no test specified\" && exit 1", "prepare": "husky", "mock:on": "sed -i 's/PULSE_MOCK_MODE=.*/PULSE_MOCK_MODE=true/' .env || echo 'PULSE_MOCK_MODE=true' >> .env", diff --git a/scripts/tests/test-hot-dev-bg.sh b/scripts/tests/test-hot-dev-bg.sh index 295808fa6..f7356b8fa 100755 --- a/scripts/tests/test-hot-dev-bg.sh +++ b/scripts/tests/test-hot-dev-bg.sh @@ -6,6 +6,7 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" HOT_DEV_BG="${ROOT_DIR}/scripts/hot-dev-bg.sh" +PACKAGE_JSON="${ROOT_DIR}/package.json" if [[ ! -x "${HOT_DEV_BG}" ]]; then echo "hot-dev-bg.sh not found or not executable at ${HOT_DEV_BG}" >&2 @@ -143,6 +144,41 @@ PY" assert_contains "verify proof defaults password" "${output}" "password=admin" } +test_root_package_exposes_managed_runtime_entrypoints() { + local output + output="$( + PACKAGE_JSON_PATH="${PACKAGE_JSON}" \ + python3 - <<'PY' +import json +import os + +with open(os.environ["PACKAGE_JSON_PATH"], "r", encoding="utf-8") as fh: + scripts = json.load(fh)["scripts"] + +for key in [ + "dev", + "dev:status", + "dev:logs", + "dev:stop", + "dev:restart", + "dev:backend-restart", + "dev:verify", + "dev:foreground", +]: + print(f"{key}={scripts.get(key, '')}") +PY + )" + + assert_contains "root package exposes managed dev start" "${output}" "dev=./scripts/hot-dev-bg.sh start --takeover" + assert_contains "root package exposes managed dev status" "${output}" "dev:status=./scripts/hot-dev-bg.sh status" + assert_contains "root package exposes managed dev logs" "${output}" "dev:logs=./scripts/hot-dev-bg.sh logs" + assert_contains "root package exposes managed dev stop" "${output}" "dev:stop=./scripts/hot-dev-bg.sh stop" + assert_contains "root package exposes managed dev restart" "${output}" "dev:restart=./scripts/hot-dev-bg.sh restart --takeover" + assert_contains "root package exposes managed backend restart" "${output}" "dev:backend-restart=./scripts/hot-dev-bg.sh backend-restart" + assert_contains "root package exposes managed dev verify" "${output}" "dev:verify=./scripts/hot-dev-bg.sh verify --takeover" + assert_contains "root package keeps foreground escape hatch" "${output}" "dev:foreground=./scripts/hot-dev.sh" +} + test_backend_restart_requires_managed_runtime() { local frontend_port backend_port output local state_dir @@ -218,6 +254,7 @@ test_detects_unmanaged_listeners() { main() { test_cli_parses_takeover_flag test_verify_command_injects_managed_runtime_env + test_root_package_exposes_managed_runtime_entrypoints test_backend_restart_requires_managed_runtime test_status_without_runtime test_detects_unmanaged_listeners diff --git a/tests/integration/README.md b/tests/integration/README.md index 55b93676d..1d7a4ba6a 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -123,6 +123,12 @@ This mode starts an isolated Pulse backend from the local repo binary in a tempo Each `npm test` invocation gets its own runtime-state file and managed-backend root automatically, so separate managed-local-backend runs can execute in parallel without sharing PID or cleanup state. Shared embedded-frontend and backend-binary refreshes are serialized by the harness. ### Run Against The Managed Hot-Dev Browser Runtime +Canonical one-command verification from the repo root: +```bash +npm run dev:verify +``` + +Equivalent direct proof command from the integration harness: ```bash cd tests/integration PULSE_E2E_USE_HOT_DEV=1 \