Expose managed dev runtime entrypoint

This commit is contained in:
rcourtman 2026-03-24 14:46:58 +00:00
parent 530b2f215e
commit c9b3ade048
5 changed files with 85 additions and 1 deletions

View file

@ -87,6 +87,32 @@ docker run -d \
Access the dashboard at `http://<your-ip>: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.

View file

@ -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

View file

@ -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",

View file

@ -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

View file

@ -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 \