version_0_1_0-alpha

This commit is contained in:
王性驊 2026-09-16 15:06:53 +08:00
parent 1d2951478b
commit 42c159e42f
3 changed files with 54 additions and 53 deletions

View File

@ -1,7 +1,9 @@
# Local process control for LazyBoy. # Local process control for LazyBoy.
# make start API :8787 + Vite :5173 # make build cargo + production web UI (web/dist)
# make box Docker computer image (lazyboy-box:local)
# make start rebuild, then API :8787 + Vite :5173
# make restart stop, build, start
# make stop # make stop
# make restart
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
@ -10,6 +12,7 @@ RUNDIR := $(ROOT)/.run
BIN := $(ROOT)/target/debug/lazyboy BIN := $(ROOT)/target/debug/lazyboy
WEBDIR := $(ROOT)/web WEBDIR := $(ROOT)/web
HOST ?= 0.0.0.0
PORT_API ?= 8787 PORT_API ?= 8787
PORT_WEB ?= 5173 PORT_WEB ?= 5173
@ -18,7 +21,7 @@ PID_WEB := $(RUNDIR)/web.pid
LOG_SERVE := $(RUNDIR)/serve.log LOG_SERVE := $(RUNDIR)/serve.log
LOG_WEB := $(RUNDIR)/web.log LOG_WEB := $(RUNDIR)/web.log
.PHONY: help start stop restart status logs prepare-ui start-serve start-web stop-serve stop-web .PHONY: help build build-bin build-ui box start stop restart status logs prepare-ui start-serve start-web stop-serve stop-web
# Shared POSIX helpers. Sourced by each recipe. # Shared POSIX helpers. Sourced by each recipe.
define CTL define CTL
@ -153,17 +156,40 @@ endef
export CTL export CTL
help: help:
@echo "make start Start API (:$(PORT_API)) and frontend (:$(PORT_WEB))" @echo "make build Compile API + production web UI (web/dist; phone uses :$(PORT_API))"
@echo "make box Build Docker computer image lazyboy-box:local (first time / after box/)"
@echo "make start Rebuild and start API (:$(PORT_API)) and frontend (:$(PORT_WEB))"
@echo "make stop Stop both" @echo "make stop Stop both"
@echo "make restart Stop then start" @echo "make restart Stop, rebuild, start"
@echo "make status Show PIDs and ports" @echo "make status Show PIDs and ports"
@echo "make logs Tail both logs (Ctrl-C to leave)" @echo "make logs Tail both logs (Ctrl-C to leave)"
start: prepare-ui start-serve start-web build: build-bin build-ui
@echo "built $(BIN) and $(WEBDIR)/dist"
build-bin:
@echo "building lazyboy…"
@cargo build -p lazyboy
build-ui:
@if [ ! -d "$(WEBDIR)/node_modules" ]; then \
echo "npm install…"; \
(cd "$(WEBDIR)" && npm install) || exit 1; \
fi
@echo "building web UI…"
@(cd "$(WEBDIR)" && npm run build) || exit 1
box:
@echo "building computer image lazyboy-box:local…"
@bash "$(ROOT)/box/build.sh"
start: build
@$(MAKE) start-serve
@$(MAKE) start-web
@echo @echo
@echo "API http://127.0.0.1:$(PORT_API)" @echo "API http://127.0.0.1:$(PORT_API)"
@echo "UI http://127.0.0.1:$(PORT_WEB)" @echo "UI http://127.0.0.1:$(PORT_WEB)"
@lan=$$(hostname -I 2>/dev/null | awk '{print $$1}'); \ @lan=$$(awk '/手機同一個 Wi-Fi/ {sub("http://", "", $$NF); sub(/:[0-9]+$$/, "", $$NF); print $$NF; exit}' "$(LOG_SERVE)"); \
if [ -n "$$lan" ]; then \ if [ -n "$$lan" ]; then \
echo "Phone http://$$lan:$(PORT_API)"; \ echo "Phone http://$$lan:$(PORT_API)"; \
fi fi
@ -186,32 +212,17 @@ logs:
@echo "=== web $(LOG_WEB) ===" @echo "=== web $(LOG_WEB) ==="
@tail -f "$(LOG_SERVE)" "$(LOG_WEB)" @tail -f "$(LOG_SERVE)" "$(LOG_WEB)"
prepare-ui: prepare-ui: build-ui
@if [ ! -d "$(WEBDIR)/node_modules" ]; then \
echo "npm install…"; \
(cd "$(WEBDIR)" && npm install) || exit 1; \
fi
@if [ ! -f "$(WEBDIR)/dist/index.html" ]; then \
echo "building web UI (once, so :$(PORT_API) serves the app)…"; \
(cd "$(WEBDIR)" && npm run build) || exit 1; \
fi
start-serve: start-serve:
@mkdir -p "$(RUNDIR)" @mkdir -p "$(RUNDIR)"
@eval "$$CTL"; \ @eval "$$CTL"; \
if alive "$(PID_SERVE)"; then \ if alive "$(PID_SERVE)"; then \
fmt=$$(cat "$$HOME/.lazyboy/certs/format" 2>/dev/null || true); \ echo "restarting serve with rebuilt binary"; \
if [ "$$fmt" = "2" ]; then \
echo "serve already running pid=$$(cat "$(PID_SERVE)")"; \
exit 0; \
fi; \
echo "TLS certs need reissue; restarting serve"; \
stop_one serve "$(PID_SERVE)" "$(PORT_API)"; \ stop_one serve "$(PID_SERVE)" "$(PORT_API)"; \
fi; \ fi; \
echo "building lazyboy…"; \
cargo build -p lazyboy || exit 1; \
load_env; \ load_env; \
LAZYBOY_WEB_PORT="$(PORT_API)" nohup "$(BIN)" serve > "$(LOG_SERVE)" 2>&1 & echo $$! > "$(PID_SERVE)"; \ LAZYBOY_WEB_HOST="$(HOST)" LAZYBOY_WEB_PORT="$(PORT_API)" nohup "$(BIN)" serve > "$(LOG_SERVE)" 2>&1 < /dev/null & echo $$! > "$(PID_SERVE)"; \
wait_alive "$(PID_SERVE)" serve "$(LOG_SERVE)" || exit 1; \ wait_alive "$(PID_SERVE)" serve "$(LOG_SERVE)" || exit 1; \
wait_listen "$(PID_SERVE)" "$(PORT_API)" serve "$(LOG_SERVE)" || exit 1; \ wait_listen "$(PID_SERVE)" "$(PORT_API)" serve "$(LOG_SERVE)" || exit 1; \
echo "started serve pid=$$(cat "$(PID_SERVE)") :$(PORT_API) log=$(LOG_SERVE)" echo "started serve pid=$$(cat "$(PID_SERVE)") :$(PORT_API) log=$(LOG_SERVE)"
@ -220,19 +231,13 @@ start-web:
@mkdir -p "$(RUNDIR)" @mkdir -p "$(RUNDIR)"
@eval "$$CTL"; \ @eval "$$CTL"; \
if alive "$(PID_WEB)"; then \ if alive "$(PID_WEB)"; then \
if lsof -nP -iTCP:"$(PORT_WEB)" -sTCP:LISTEN 2>/dev/null | grep -q '127.0.0.1:$(PORT_WEB)'; then \ stop_one web "$(PID_WEB)" "$(PORT_WEB)"; \
echo "web is localhost-only; restarting so the phone can connect"; \
stop_one web "$(PID_WEB)" "$(PORT_WEB)"; \
else \
echo "web already running pid=$$(cat "$(PID_WEB)")"; \
exit 0; \
fi; \
fi; \ fi; \
if [ ! -d "$(WEBDIR)/node_modules" ]; then \ if [ ! -d "$(WEBDIR)/node_modules" ]; then \
echo "npm install…"; \ echo "npm install…"; \
(cd "$(WEBDIR)" && npm install) || exit 1; \ (cd "$(WEBDIR)" && npm install) || exit 1; \
fi; \ fi; \
nohup npm --prefix "$(WEBDIR)" run dev -- --host 0.0.0.0 --port "$(PORT_WEB)" > "$(LOG_WEB)" 2>&1 & echo $$! > "$(PID_WEB)"; \ LAZYBOY_WEB_PORT="$(PORT_API)" nohup npm --prefix "$(WEBDIR)" run dev -- --host "$(HOST)" --port "$(PORT_WEB)" > "$(LOG_WEB)" 2>&1 < /dev/null & echo $$! > "$(PID_WEB)"; \
wait_alive "$(PID_WEB)" web "$(LOG_WEB)" || exit 1; \ wait_alive "$(PID_WEB)" web "$(LOG_WEB)" || exit 1; \
wait_listen "$(PID_WEB)" "$(PORT_WEB)" web "$(LOG_WEB)" || exit 1; \ wait_listen "$(PID_WEB)" "$(PORT_WEB)" web "$(LOG_WEB)" || exit 1; \
echo "started web pid=$$(cat "$(PID_WEB)") :$(PORT_WEB) log=$(LOG_WEB)" echo "started web pid=$$(cat "$(PID_WEB)") :$(PORT_WEB) log=$(LOG_WEB)"

View File

@ -8,11 +8,18 @@ For action tasks the agent briefly explains its approach, then starts. Multi-sta
```bash ```bash
# 可設項目與說明:複製 .env.example 成 .env 後填 LAZYBOY_API_KEY # 可設項目與說明:複製 .env.example 成 .env 後填 LAZYBOY_API_KEY
# make start 會載入 .env # make start / restart 會載入 .env
make build # API + 正式 UIweb/dist手機走 :8787 需要這步)
make start # 每次重建 API + UI再啟動預設綁定 0.0.0.0
make restart # 停止後重建並啟動
make box # 第一次/改 box/ 之後Docker 電腦映像 lazyboy-box:local
make stop
export LAZYBOY_API_KEY=your_key # or XAI_API_KEY export LAZYBOY_API_KEY=your_key # or XAI_API_KEY
cargo run -p lazyboy -- agent cargo run -p lazyboy -- agent
# API daemon (named Agents) + HTTP on :8787 # API daemon (named Agents) + HTTP on :8787
cargo run -p lazyboy -- serve cargo run -p lazyboy -- serve
# 開發前端使用 HTTP不會因本機殘留憑證自動切換 HTTPS。
# 本機http://127.0.0.1:5173其他裝置http://本機區網IP:5173或 :8787
# Independent frontend: # Independent frontend:
cd web && npm install && npm run dev cd web && npm install && npm run dev
# Production UI: npm run build then lazyboy serve hosts web/dist # Production UI: npm run build then lazyboy serve hosts web/dist

View File

@ -1,39 +1,26 @@
import { existsSync, readFileSync } from "node:fs"; import { dirname, resolve } from "node:path";
import { homedir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { defineConfig, loadEnv, type ServerOptions } from "vite"; import { defineConfig, loadEnv, type ServerOptions } from "vite";
import react from "@vitejs/plugin-react"; import react from "@vitejs/plugin-react";
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
function localCerts(): { cert: Buffer; key: Buffer } | undefined {
const home = homedir();
for (const dir of [join(home, ".lazyboy", "certs"), join(home, ".grokboy", "certs")]) {
const cert = join(dir, "server.pem");
const key = join(dir, "server.key");
if (existsSync(cert) && existsSync(key)) {
return { cert: readFileSync(cert), key: readFileSync(key) };
}
}
return undefined;
}
export default defineConfig(({ mode }) => { export default defineConfig(({ mode }) => {
const env = loadEnv(mode, rootDir, ""); const env = loadEnv(mode, rootDir, "");
const version = (process.env.LAZYBOY_VERSION || env.LAZYBOY_VERSION || "0.1.0").trim() || "0.1.0"; const version = (process.env.LAZYBOY_VERSION || env.LAZYBOY_VERSION || "0.1.0").trim() || "0.1.0";
const https = localCerts(); // The API accepts HTTP even when its optional TLS listener is enabled.
const backend = https ? "https://127.0.0.1:8787" : "http://127.0.0.1:8787"; const backendPort = process.env.LAZYBOY_WEB_PORT || env.LAZYBOY_WEB_PORT || "8787";
const backend = `http://127.0.0.1:${backendPort}`;
const server: ServerOptions = { const server: ServerOptions = {
port: 5173, port: 5173,
host: true, host: "0.0.0.0",
strictPort: true,
proxy: { proxy: {
"/api": { target: backend, secure: false }, "/api": { target: backend, secure: false },
"/novnc": { target: backend, ws: true, secure: false }, "/novnc": { target: backend, ws: true, secure: false },
"/lazyboy-ca.crt": { target: backend, secure: false }, "/lazyboy-ca.crt": { target: backend, secure: false },
}, },
}; };
if (https) server.https = https;
return { return {
plugins: [react()], plugins: [react()],
define: { define: {
@ -42,6 +29,8 @@ export default defineConfig(({ mode }) => {
server, server,
preview: { preview: {
port: 4173, port: 4173,
host: "0.0.0.0",
strictPort: true,
}, },
}; };
}); });