micro-fix: quickstart dashboard auto-launch for PowerShell (#6655)
* Fix quickstart dashboard auto-launch on Windows * chore: refresh locks * fix: gate quickstart hive shim to Git Bash * chore: revert unrelated frontend lockfile churn
This commit is contained in:
committed by
GitHub
parent
a2cd96a1a7
commit
27d5061d97
@@ -1561,6 +1561,22 @@ def _open_browser(url: str) -> None:
|
||||
pass # Best-effort — don't crash if browser can't open
|
||||
|
||||
|
||||
def _format_subprocess_output(output: str | bytes | None, limit: int = 2000) -> str:
|
||||
"""Return subprocess output as trimmed text safe for console logging."""
|
||||
if not output:
|
||||
return ""
|
||||
|
||||
if isinstance(output, bytes):
|
||||
text = output.decode(errors="replace")
|
||||
else:
|
||||
text = output
|
||||
|
||||
text = text.strip()
|
||||
if len(text) <= limit:
|
||||
return text
|
||||
return text[-limit:]
|
||||
|
||||
|
||||
def _build_frontend() -> bool:
|
||||
"""Build the frontend if source is newer than dist. Returns True if dist exists."""
|
||||
import subprocess
|
||||
@@ -1596,18 +1612,25 @@ def _build_frontend() -> bool:
|
||||
|
||||
# Need to build
|
||||
print("Building frontend...")
|
||||
npm_cmd = "npm.cmd" if sys.platform == "win32" else "npm"
|
||||
try:
|
||||
# Incremental tsc caches can drift across branch changes and block builds.
|
||||
for cache_file in frontend_dir.glob("tsconfig*.tsbuildinfo"):
|
||||
cache_file.unlink(missing_ok=True)
|
||||
|
||||
# Ensure deps are installed
|
||||
subprocess.run(
|
||||
["npm", "install", "--no-fund", "--no-audit"],
|
||||
[npm_cmd, "install", "--no-fund", "--no-audit"],
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
cwd=frontend_dir,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["npm", "run", "build"],
|
||||
[npm_cmd, "run", "build"],
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
cwd=frontend_dir,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
@@ -1618,8 +1641,14 @@ def _build_frontend() -> bool:
|
||||
print("Node.js not found — skipping frontend build.")
|
||||
return dist_dir.is_dir()
|
||||
except subprocess.CalledProcessError as exc:
|
||||
stderr = exc.stderr.decode(errors="replace") if exc.stderr else ""
|
||||
print(f"Frontend build failed: {stderr[:500]}")
|
||||
stdout = _format_subprocess_output(exc.stdout)
|
||||
stderr = _format_subprocess_output(exc.stderr)
|
||||
cmd = " ".join(exc.cmd) if isinstance(exc.cmd, (list, tuple)) else str(exc.cmd)
|
||||
details = "\n".join(part for part in [stdout, stderr] if part).strip()
|
||||
if details:
|
||||
print(f"Frontend build failed while running {cmd}:\n{details}")
|
||||
else:
|
||||
print(f"Frontend build failed while running {cmd} (exit {exc.returncode}).")
|
||||
return dist_dir.is_dir()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Tests for frontend build fallback in the runner CLI."""
|
||||
|
||||
import subprocess
|
||||
|
||||
from framework.runner import cli as runner_cli
|
||||
|
||||
|
||||
def _write_frontend_tree(tmp_path, *, with_dist: bool = False):
|
||||
frontend_dir = tmp_path / "core" / "frontend"
|
||||
(frontend_dir / "src").mkdir(parents=True)
|
||||
(frontend_dir / "package.json").write_text("{}", encoding="utf-8")
|
||||
(frontend_dir / "src" / "main.tsx").write_text("console.log('hi')", encoding="utf-8")
|
||||
if with_dist:
|
||||
(frontend_dir / "dist").mkdir()
|
||||
(frontend_dir / "dist" / "index.html").write_text("<!doctype html>", encoding="utf-8")
|
||||
return frontend_dir
|
||||
|
||||
|
||||
def test_build_frontend_handles_text_calledprocesserror(monkeypatch, tmp_path, capsys):
|
||||
_write_frontend_tree(tmp_path)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
raise subprocess.CalledProcessError(
|
||||
1,
|
||||
cmd,
|
||||
output="npm output",
|
||||
stderr="vite config failed",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", fake_run)
|
||||
|
||||
assert runner_cli._build_frontend() is False
|
||||
|
||||
output = capsys.readouterr().out
|
||||
assert "Frontend build failed while running" in output
|
||||
assert "vite config failed" in output
|
||||
|
||||
|
||||
def test_build_frontend_cleans_cache_and_uses_windows_npm_cmd(monkeypatch, tmp_path):
|
||||
frontend_dir = _write_frontend_tree(tmp_path)
|
||||
cache_file = frontend_dir / "tsconfig.app.tsbuildinfo"
|
||||
cache_file.write_text("stale", encoding="utf-8")
|
||||
monkeypatch.chdir(tmp_path)
|
||||
monkeypatch.setattr(runner_cli.sys, "platform", "win32")
|
||||
|
||||
commands = []
|
||||
|
||||
def fake_run(cmd, **kwargs):
|
||||
commands.append(cmd)
|
||||
return subprocess.CompletedProcess(cmd, 0, stdout="", stderr="")
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", fake_run)
|
||||
|
||||
assert runner_cli._build_frontend() is True
|
||||
assert not cache_file.exists()
|
||||
assert commands == [
|
||||
["npm.cmd", "install", "--no-fund", "--no-audit"],
|
||||
["npm.cmd", "run", "build"],
|
||||
]
|
||||
+47
-9
@@ -66,6 +66,32 @@ function Write-Fail {
|
||||
Write-Color -Text " X $Text" -Color Red
|
||||
}
|
||||
|
||||
function Write-CommandFailureDetails {
|
||||
param(
|
||||
[object[]]$Output,
|
||||
[int]$Tail = 40
|
||||
)
|
||||
|
||||
$lines = @($Output | Where-Object { $_ -ne $null } | ForEach-Object { "$_" })
|
||||
if ($lines.Count -eq 0) {
|
||||
return
|
||||
}
|
||||
|
||||
$start = [Math]::Max(0, $lines.Count - $Tail)
|
||||
if ($start -gt 0) {
|
||||
Write-Host " ... showing last $($lines.Count - $start) lines ..." -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
for ($i = $start; $i -lt $lines.Count; $i++) {
|
||||
Write-Host " $($lines[$i])" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
function Test-FrontendDistReady {
|
||||
param([string]$RootDir)
|
||||
return (Test-Path (Join-Path $RootDir "core\frontend\dist\index.html"))
|
||||
}
|
||||
|
||||
function Prompt-YesNo {
|
||||
param(
|
||||
[string]$Prompt,
|
||||
@@ -540,6 +566,7 @@ Write-Host ""
|
||||
|
||||
# Build frontend (if Node.js is available)
|
||||
$FrontendBuilt = $false
|
||||
$FrontendDistReady = Test-FrontendDistReady -RootDir $ScriptDir
|
||||
if ($NodeAvailable) {
|
||||
Write-Step -Number "" -Text "Building frontend dashboard..."
|
||||
Write-Host ""
|
||||
@@ -548,30 +575,33 @@ if ($NodeAvailable) {
|
||||
Write-Host " Installing npm packages... " -NoNewline
|
||||
Push-Location $frontendDir
|
||||
try {
|
||||
$null = & npm install --no-fund --no-audit 2>&1
|
||||
$installOutput = & npm install --no-fund --no-audit 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "ok"
|
||||
# Clean stale tsbuildinfo cache — tsc -b incremental builds fail
|
||||
# silently when these are out of sync with source files
|
||||
Get-ChildItem -Path $frontendDir -Filter "tsconfig*.tsbuildinfo" -ErrorAction SilentlyContinue | Remove-Item -Force
|
||||
Write-Host " Building frontend... " -NoNewline
|
||||
$null = & npm run build 2>&1
|
||||
$buildOutput = & npm run build 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "ok"
|
||||
Write-Ok "Frontend built -> core/frontend/dist/"
|
||||
$FrontendBuilt = $true
|
||||
$FrontendDistReady = $true
|
||||
} else {
|
||||
Write-Warn "build failed"
|
||||
Write-Host " Run 'cd core\frontend && npm run build' manually to debug." -ForegroundColor DarkGray
|
||||
Write-CommandFailureDetails -Output $buildOutput -Tail 60
|
||||
Write-Host " Quickstart will still try '.\hive.ps1 open' if Hive can rebuild the dashboard." -ForegroundColor DarkGray
|
||||
}
|
||||
} else {
|
||||
Write-Warn "npm install failed"
|
||||
$NodeAvailable = $false
|
||||
Write-CommandFailureDetails -Output $installOutput -Tail 60
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
$FrontendDistReady = Test-FrontendDistReady -RootDir $ScriptDir
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
@@ -2016,13 +2046,21 @@ Write-Color -Text "hive open" -Color Cyan -NoNewline
|
||||
Write-Host ". Run .\quickstart.ps1 again to reconfigure." -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
if ($FrontendBuilt) {
|
||||
Write-Color -Text "Launching dashboard..." -Color White
|
||||
if ($FrontendDistReady -or $NodeAvailable) {
|
||||
if ($FrontendDistReady) {
|
||||
Write-Color -Text "Launching dashboard..." -Color White
|
||||
} else {
|
||||
Write-Color -Text "Launching dashboard (retrying frontend build via hive open)..." -Color White
|
||||
}
|
||||
Write-Host ""
|
||||
& hive open
|
||||
& $hivePs1Path open
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warn "Dashboard launch failed"
|
||||
Write-Host " Run '.\hive.ps1 open' manually to inspect the error." -ForegroundColor DarkGray
|
||||
}
|
||||
} else {
|
||||
Write-Color -Text "Frontend build was skipped or failed." -Color Yellow -NoNewline
|
||||
Write-Color -Text "Frontend build was skipped or failed, and no built dashboard is available." -Color Yellow -NoNewline
|
||||
Write-Host " Launch manually when ready:"
|
||||
Write-Color -Text " hive open" -Color Cyan
|
||||
Write-Color -Text " .\hive.ps1 open" -Color Cyan
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
+17
-5
@@ -1792,15 +1792,27 @@ echo ""
|
||||
# Ensure ~/.local/bin exists and is in PATH
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
|
||||
# Create/update symlink
|
||||
# Git Bash on Windows may materialize `ln -s` as a plain file copy.
|
||||
# Use a launcher shim there, but prefer a real symlink on Linux/macOS.
|
||||
HIVE_SCRIPT="$SCRIPT_DIR/hive"
|
||||
HIVE_LINK="$HOME/.local/bin/hive"
|
||||
HIVE_SCRIPT_ESCAPED=$(printf '%q' "$HIVE_SCRIPT")
|
||||
|
||||
if [ -L "$HIVE_LINK" ] || [ -e "$HIVE_LINK" ]; then
|
||||
rm -f "$HIVE_LINK"
|
||||
fi
|
||||
|
||||
ln -s "$HIVE_SCRIPT" "$HIVE_LINK"
|
||||
if [ -n "$MSYSTEM" ] || [ -n "$MINGW_PREFIX" ]; then
|
||||
cat > "$HIVE_LINK" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
HIVE_SCRIPT=$HIVE_SCRIPT_ESCAPED
|
||||
exec "\$HIVE_SCRIPT" "\$@"
|
||||
EOF
|
||||
chmod +x "$HIVE_LINK"
|
||||
else
|
||||
ln -s "$HIVE_SCRIPT" "$HIVE_LINK"
|
||||
fi
|
||||
echo -e "${GREEN} ✓ hive CLI installed to ~/.local/bin/hive${NC}"
|
||||
|
||||
# Check if ~/.local/bin is in PATH
|
||||
@@ -1894,15 +1906,15 @@ if [ "$CODEX_AVAILABLE" = true ]; then
|
||||
fi
|
||||
|
||||
echo -e "${DIM}API keys saved to ${CYAN}$SHELL_RC_FILE${NC}${DIM}. New terminals pick them up automatically.${NC}"
|
||||
echo -e "${DIM}Launch anytime with ${CYAN}hive open${NC}${DIM}. Run ./quickstart.sh again to reconfigure.${NC}"
|
||||
echo -e "${DIM}Launch anytime from this project root with ${CYAN}./hive open${NC}${DIM}. Run ./quickstart.sh again to reconfigure.${NC}"
|
||||
echo ""
|
||||
|
||||
if [ "$FRONTEND_BUILT" = true ]; then
|
||||
echo -e "${BOLD}Launching dashboard...${NC}"
|
||||
echo ""
|
||||
hive open
|
||||
"$SCRIPT_DIR/hive" open
|
||||
else
|
||||
echo -e "${YELLOW}Frontend build was skipped or failed.${NC} Launch manually when ready:"
|
||||
echo -e " ${CYAN}hive open${NC}"
|
||||
echo -e " ${CYAN}./hive open${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user