193 lines
5.2 KiB
JavaScript
193 lines
5.2 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { DEV_ENDPOINT } from "../../../internal/protocol/index.mjs";
|
|
|
|
const DEFAULT_PROJECTS = [
|
|
{
|
|
projectId: "proj_mvp-l6",
|
|
name: "HWLAB L6 MVP",
|
|
status: "active",
|
|
environment: "dev",
|
|
updatedAt: "2026-05-21T00:00:00.000Z"
|
|
},
|
|
{
|
|
projectId: "proj_cloud-web",
|
|
name: "Cloud Web Skeleton",
|
|
status: "active",
|
|
environment: "dev",
|
|
updatedAt: "2026-05-20T12:00:00.000Z"
|
|
}
|
|
];
|
|
|
|
function loadRuntimeFixture(cwd) {
|
|
const fixturePath = path.resolve(cwd, "fixtures/mvp/runtime.json");
|
|
if (!fs.existsSync(fixturePath)) {
|
|
return null;
|
|
}
|
|
const raw = fs.readFileSync(fixturePath, "utf8");
|
|
return JSON.parse(raw);
|
|
}
|
|
|
|
function resolveRuntime(cwd) {
|
|
const fixture = loadRuntimeFixture(cwd);
|
|
if (fixture) {
|
|
return fixture;
|
|
}
|
|
return {
|
|
endpoints: { dev: DEV_ENDPOINT },
|
|
projects: DEFAULT_PROJECTS,
|
|
mvpSteps: [
|
|
"browser/CLI/gateway",
|
|
"master hwlab-edge-proxy",
|
|
"frp",
|
|
"D601 hwlab-dev/hwlab-router",
|
|
"cloud-web/cloud-api",
|
|
"hardware trusted closed loop",
|
|
"agent automation closed loop",
|
|
"evidence record",
|
|
"worker cleanup"
|
|
],
|
|
loops: [
|
|
{ name: "hardware trusted closed loop" },
|
|
{ name: "agent automation closed loop" }
|
|
],
|
|
evidence: [],
|
|
cleanup: []
|
|
};
|
|
}
|
|
|
|
function formatJson(value) {
|
|
return JSON.stringify(value, null, 2);
|
|
}
|
|
|
|
function writeLine(stream, line = "") {
|
|
stream.write(`${line}\n`);
|
|
}
|
|
|
|
function writeProjectList(runtime, stdout) {
|
|
writeLine(stdout, "hwlab-cli project list");
|
|
writeLine(stdout, `endpoint: ${runtime.endpoints?.dev ?? DEV_ENDPOINT}`);
|
|
for (const project of runtime.projects ?? []) {
|
|
writeLine(
|
|
stdout,
|
|
`${project.projectId} | ${project.name} | ${project.status} | ${project.environment} | ${project.updatedAt}`
|
|
);
|
|
}
|
|
}
|
|
|
|
function writeHealth(runtime, stdout) {
|
|
writeLine(stdout, "hwlab-cli health");
|
|
writeLine(stdout, "status: ok");
|
|
writeLine(stdout, `environment: dev`);
|
|
writeLine(stdout, `endpoint: ${runtime.endpoints?.dev ?? DEV_ENDPOINT}`);
|
|
writeLine(stdout, `projects: ${(runtime.projects ?? []).length}`);
|
|
}
|
|
|
|
function writeDryRun(runtime, stdout) {
|
|
writeLine(stdout, "hwlab-cli test e2e --env dev --mvp --dry-run");
|
|
writeLine(stdout, `endpoint: ${runtime.endpoints?.dev ?? DEV_ENDPOINT}`);
|
|
writeLine(stdout, "mvp route:");
|
|
writeLine(
|
|
stdout,
|
|
` ${runtime.serviceRoute?.join(" -> ") ?? "browser/CLI/gateway -> master hwlab-edge-proxy -> frp -> D601 hwlab-dev/hwlab-router -> cloud-web/cloud-api"}`
|
|
);
|
|
for (const step of runtime.mvpSteps ?? []) {
|
|
writeLine(stdout, `- ${step}`);
|
|
}
|
|
writeLine(stdout, "closed loops:");
|
|
for (const loop of runtime.loops ?? []) {
|
|
writeLine(stdout, `- ${loop.name}${loop.description ? `: ${loop.description}` : ""}`);
|
|
}
|
|
writeLine(stdout, "evidence record:");
|
|
for (const evidence of runtime.evidence ?? []) {
|
|
writeLine(
|
|
stdout,
|
|
`- ${evidence.evidenceId} | ${evidence.kind} | ${evidence.serviceId} | ${evidence.uri}`
|
|
);
|
|
}
|
|
writeLine(stdout, "worker cleanup:");
|
|
for (const step of runtime.cleanup ?? []) {
|
|
writeLine(stdout, `- ${step}`);
|
|
}
|
|
writeLine(stdout, "dry-run only: no DEV/PROD changes were made");
|
|
}
|
|
|
|
function writeHelp(stdout) {
|
|
writeLine(stdout, "hwlab-cli");
|
|
writeLine(stdout, "commands:");
|
|
writeLine(stdout, " health");
|
|
writeLine(stdout, " project list");
|
|
writeLine(stdout, " test e2e --env dev --mvp --dry-run");
|
|
}
|
|
|
|
function parseArgs(args) {
|
|
const flags = new Set();
|
|
const options = new Map();
|
|
const rest = [];
|
|
for (let index = 0; index < args.length; index += 1) {
|
|
const arg = args[index];
|
|
if (arg.startsWith("--")) {
|
|
flags.add(arg);
|
|
const next = args[index + 1];
|
|
if (next && !next.startsWith("--")) {
|
|
options.set(arg, next);
|
|
index += 1;
|
|
}
|
|
} else {
|
|
rest.push(arg);
|
|
}
|
|
}
|
|
return { flags, options, rest };
|
|
}
|
|
|
|
export async function runCli(argv, io) {
|
|
const stdout = io.stdout ?? process.stdout;
|
|
const stderr = io.stderr ?? process.stderr;
|
|
const runtime = resolveRuntime(io.cwd ?? process.cwd());
|
|
const [command = "help", subcommand, ...rest] = argv;
|
|
const { flags, options } = parseArgs(rest);
|
|
|
|
if (command === "health") {
|
|
writeHealth(runtime, stdout);
|
|
return 0;
|
|
}
|
|
|
|
if (command === "project" && subcommand === "list") {
|
|
writeProjectList(runtime, stdout);
|
|
return 0;
|
|
}
|
|
|
|
if (command === "test" && subcommand === "e2e") {
|
|
const env = options.get("--env") ?? null;
|
|
const isDryRun = flags.has("--dry-run");
|
|
const isMvp = flags.has("--mvp");
|
|
if (env !== "dev") {
|
|
writeLine(stderr, "only --env dev is supported in the skeleton");
|
|
return 1;
|
|
}
|
|
if (!isMvp || !isDryRun) {
|
|
writeLine(stderr, "use --mvp --dry-run for the skeleton");
|
|
return 1;
|
|
}
|
|
writeDryRun(runtime, stdout);
|
|
return 0;
|
|
}
|
|
|
|
if (command === "project" && !subcommand) {
|
|
writeLine(stderr, "usage: hwlab-cli project list");
|
|
return 1;
|
|
}
|
|
|
|
if (command === "test" && !subcommand) {
|
|
writeLine(stderr, "usage: hwlab-cli test e2e --env dev --mvp --dry-run");
|
|
return 1;
|
|
}
|
|
|
|
writeHelp(stdout);
|
|
return 0;
|
|
}
|
|
|
|
export function formatRuntime(runtime) {
|
|
return formatJson(runtime);
|
|
}
|