Files
pikasTech-unidesk/scripts/src/hwlab-native-development.ts
T
2026-07-17 18:40:25 +02:00

96 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { runCommand } from "./command";
import { hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneSpecForNode, isHwlabRuntimeLane, type HwlabRuntimeNativeDevelopmentSpec } from "./hwlab-node-lanes";
type Service = "api" | "worker" | "web";
type Action = "start" | "stop" | "restart" | "status" | "logs";
export function hwlabNativeDevelopmentHelp(): Record<string, unknown> {
return {
ok: true,
command: "hwlab nodes native-development workbench",
usage: [
"bun scripts/cli.ts hwlab nodes native-development workbench api|worker|web start|stop|restart|status|logs --node <node> --lane <lane>",
],
contract: "L1 API/Web 用户入口只输出 owning YAML 解析出的公网 IP 和 portbind/probe 地址不作为用户入口。",
configPath: hwlabRuntimeLaneConfigPath(),
};
}
export function runHwlabNativeDevelopmentCommand(args: string[]): Record<string, unknown> {
if (args.length === 0 || args.includes("--help") || args.includes("-h")) return hwlabNativeDevelopmentHelp();
const [application, serviceRaw, actionRaw] = args;
if (application !== "workbench") throw new Error("native-development currently supports workbench");
const service = parseService(serviceRaw);
const action = parseAction(actionRaw);
const node = requiredOption(args, "--node");
const lane = requiredOption(args, "--lane");
if (!isHwlabRuntimeLane(lane)) throw new Error(`--lane must be declared in ${hwlabRuntimeLaneConfigPath()}`);
const spec = hwlabRuntimeLaneSpecForNode(lane, node);
const native = spec.nativeDevelopment?.workbench;
if (native === undefined) throw new Error(`${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.workbench is required`);
const env = hwlabNativeDevelopmentEnvironment(native);
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", "workbench", "service", service, action];
const result = runCommand(command, spec.workspace, { timeoutMs: 15_000, env: { ...process.env, ...env } });
const payload = parsePayload(result.stdout);
const publicEndpoint = service === "api"
? { ip: native.publicHost, port: native.api.port, url: `http://${native.publicHost}:${native.api.port}` }
: service === "web"
? { ip: native.publicHost, port: native.web.port, url: `http://${native.publicHost}:${native.web.port}/workbench` }
: null;
return {
ok: result.exitCode === 0 && payload.ok !== false,
command: `hwlab nodes native-development workbench ${service} ${action}`,
node,
lane,
service,
action,
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.workbench`,
publicHostSource: native.publicHostRef,
userEndpoint: publicEndpoint,
serviceResult: payload,
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_service_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
};
}
export function hwlabNativeDevelopmentEnvironment(native: HwlabRuntimeNativeDevelopmentSpec["workbench"]): NodeJS.ProcessEnv {
return {
WORKBENCH_NATIVE_SERVICE_STATE_DIR: native.stateDir,
WORKBENCH_API_BIND_HOST: native.api.bindHost,
WORKBENCH_API_PROBE_HOST: native.api.probeHost,
WORKBENCH_API_PUBLIC_HOST: native.publicHost,
WORKBENCH_API_PORT: String(native.api.port),
WORKBENCH_WORKER_BIND_HOST: native.worker.bindHost,
WORKBENCH_WORKER_PROBE_HOST: native.worker.probeHost,
WORKBENCH_WORKER_HEALTH_PORT: String(native.worker.healthPort),
WORKBENCH_WEB_BIND_HOST: native.web.bindHost,
WORKBENCH_WEB_PROBE_HOST: native.web.probeHost,
WORKBENCH_WEB_PUBLIC_HOST: native.publicHost,
WORKBENCH_WEB_PORT: String(native.web.port),
WORKBENCH_NATIVE_API_URL: `http://${native.api.probeHost}:${native.api.port}`,
WORKBENCH_WEB_RUNTIME_CONFIG: JSON.stringify(native.web.runtimeConfig),
};
}
function parsePayload(stdout: string): Record<string, unknown> {
const parsed = JSON.parse(stdout) as unknown;
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("HWLAB Workbench CLI returned invalid JSON");
return parsed as Record<string, unknown>;
}
function parseService(value: string | undefined): Service {
if (value === "api" || value === "worker" || value === "web") return value;
throw new Error("native-development workbench service must be api, worker, or web");
}
function parseAction(value: string | undefined): Action {
if (value === "start" || value === "stop" || value === "restart" || value === "status" || value === "logs") return value;
throw new Error("native-development workbench action must be start, stop, restart, status, or logs");
}
function requiredOption(args: string[], option: string): string {
const index = args.indexOf(option);
const value = index < 0 ? undefined : args[index + 1];
if (!value || value.startsWith("--")) throw new Error(`${option} requires a value`);
return value;
}