refactor: split control-plane cli modules
This commit is contained in:
@@ -0,0 +1,526 @@
|
||||
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. entry module for scripts/src/hwlab-node-impl.ts.
|
||||
|
||||
// Moved mechanically from scripts/src/hwlab-node-impl.ts:1-439 for #903.
|
||||
|
||||
// SPEC: PJ2026-01060505 Workbench Performance draft-2026-06-17-p0.
|
||||
// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-25-p0-web-probe-sentinel.
|
||||
// Responsibility: YAML-first node/lane operations, including Workbench observability control commands.
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { repoRoot, rootPath, type Config } from "../config";
|
||||
import { runCommand, type CommandResult } from "../command";
|
||||
import { startJob } from "../jobs";
|
||||
import { classifySshTcpPoolFailure } from "../ssh";
|
||||
import { HWLAB_NODE_CONTROL_PLANE_CONFIG_PATH, hwlabNodeControlPlaneInfraHelp, runHwlabNodeControlPlaneInfra } from "../hwlab-node-control-plane";
|
||||
import { hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec, hwlabRuntimeLaneSpecForNode, hwlabRuntimeNodeIds, isHwlabRuntimeLane, type HwlabRuntimeLane, type HwlabRuntimeLaneSpec, type HwlabRuntimeObservabilityRecordingRuleSpec, type HwlabRuntimeObservabilitySpec, type HwlabRuntimeObservabilityWarningAlertSpec, type HwlabRuntimePublicExposureSpec, type HwlabRuntimeWebProbeAlertThresholdsSpec, type HwlabRuntimeWebProbeProjectManagementSpec } from "../hwlab-node-lanes";
|
||||
import { nodeWebProbeScriptRunnerSource } from "../hwlab-node-web-probe-runner-source";
|
||||
import { nodeWebObserveAnalyzerSource } from "../hwlab-node-web-observe-analyzer-source";
|
||||
import { nodeWebObserveRunnerSource } from "../hwlab-node-web-observe-runner-source";
|
||||
import { nodeWebObserveCollectViewNodeScript, parseNodeWebProbeObserveCollectView, type NodeWebProbeObserveCollectView } from "../hwlab-node-web-observe-collect";
|
||||
import { withWebObserveCollectRendered, withWebObserveCommandRendered, withWebObserveStatusRendered } from "../hwlab-node-web-observe-render";
|
||||
import { buildWebObserveWrapperForObserveOptions, webObserveWrapperStateDirFromStatus } from "../hwlab-node-web-observe-wrapper";
|
||||
import { renderWebObserveWrapperContract } from "../hwlab-node-web-observe-wrapper-render";
|
||||
import { runWebProbeSentinelCommand, type WebProbeSentinelOptions } from "../hwlab-node-web-sentinel-cicd";
|
||||
import { hwlabNodeHelp, hwlabNodeObservabilityHelp, hwlabNodeWebProbeHelp } from "../hwlab-node-help";
|
||||
import { compactWebProbeResult, compactWebProbeScriptResult } from "../hwlab-node-web-probe-summary";
|
||||
import { nodeObservabilityRecordingRuleExpression, nodeObservabilityRecordingRuleSummaries, nodeObservabilityWarningAlertExpression, nodeObservabilityWarningAlertSummaries } from "../hwlab-node-observability-promql";
|
||||
import { runDelegatedHwlabNodeCommand, type DelegatedNodeDomain } from "../hwlab-node-transport";
|
||||
import type { RenderedCliResult } from "../output";
|
||||
|
||||
import { nodeRuntimeControlPlaneRun } from "./cleanup";
|
||||
import { nodeRuntimeBaseImageCommand } from "./control-actions";
|
||||
import { withNodeRuntimeControlPlanePlanRendered, withNodeRuntimeControlPlaneStatusFullRendered, withNodeRuntimeControlPlaneStatusRendered } from "./git-mirror";
|
||||
import { nodeRuntimeControlPlanePlan, runNodeObservability } from "./observability";
|
||||
import { parseNodeScopedDelegatedOptions } from "./plan";
|
||||
import { parseSecretOptions, runNodePublicExposure, runNodeSecret } from "./public-exposure";
|
||||
import { nodeRuntimeControlPlaneStatus } from "./render";
|
||||
import { nodeRuntimeUnsupportedAction } from "./runtime-common";
|
||||
import { runNodeEndpointBridge } from "./secret-scripts";
|
||||
import { nodeRuntimeGitMirrorRun, nodeRuntimeGitMirrorStatus, nodeScopedFullOutput, withNodeRuntimeGitMirrorRendered } from "./status";
|
||||
import { assertNodeId, positiveIntegerOption, requiredOption, stripOption } from "./utils";
|
||||
import { parseNodeWebProbeOptions, rewriteDelegatedNodeResult, startNodeDelegatedJob } from "./web-probe";
|
||||
import { assertKnownOptions, runNodeWebProbe } from "./web-probe-observe";
|
||||
|
||||
export { hwlabNodeHelp, hwlabNodeWebProbeHelp, hwlabNodeObservabilityHelp } from "../hwlab-node-help";
|
||||
|
||||
export type SecretAction = "status" | "ensure" | "cleanup-owned-postgres" | "cleanup-obsolete";
|
||||
|
||||
export type SecretPreset = "openfga" | "master-server-admin-api-key" | "bootstrap-admin" | "code-agent-provider" | "cloud-api-db" | "owned-postgres-cleanup" | "obsolete-secret-cleanup";
|
||||
|
||||
export type NodeRuntimeRenderLocation = "node-host" | "local";
|
||||
|
||||
export type WebProbeBrowserProxyMode = "auto" | "direct";
|
||||
|
||||
export interface NodeWebProbeRunOptions {
|
||||
action: "run";
|
||||
node: string;
|
||||
lane: string;
|
||||
url: string;
|
||||
timeoutMs: number;
|
||||
waitAfterSubmitMs: number;
|
||||
waitMessagesMs: number;
|
||||
waitAgentTerminalMs: number;
|
||||
traceSampleCount: number;
|
||||
traceSampleIntervalMs: number;
|
||||
message: string | null;
|
||||
conversationId: string | null;
|
||||
freshSession: boolean;
|
||||
cancelRunning: boolean;
|
||||
commandTimeoutSeconds: number;
|
||||
commandTimeoutAutoSeconds: number;
|
||||
commandTimeoutUserProvided: boolean;
|
||||
}
|
||||
|
||||
export interface NodeWebProbeScriptOptions {
|
||||
action: "script";
|
||||
node: string;
|
||||
lane: string;
|
||||
url: string;
|
||||
timeoutMs: number;
|
||||
viewport: string;
|
||||
browserProxyMode: WebProbeBrowserProxyMode;
|
||||
commandTimeoutSeconds: number;
|
||||
scriptText: string;
|
||||
scriptSource: {
|
||||
kind: "stdin" | "file";
|
||||
path: string | null;
|
||||
byteCount: number;
|
||||
sha256: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type NodeWebProbeObserveAction = "start" | "status" | "command" | "stop" | "collect" | "analyze";
|
||||
|
||||
export type NodeWebProbeObserveCommandType =
|
||||
| "login"
|
||||
| "preflight"
|
||||
| "goto"
|
||||
| "gotoProjectMdtodo"
|
||||
| "newSession"
|
||||
| "sendPrompt"
|
||||
| "steer"
|
||||
| "cancel"
|
||||
| "selectProvider"
|
||||
| "clickSession"
|
||||
| "selectProjectSource"
|
||||
| "selectMdtodoSource"
|
||||
| "selectMdtodoFile"
|
||||
| "selectMdtodoTask"
|
||||
| "expandMdtodoTask"
|
||||
| "openMdtodoSourceConfig"
|
||||
| "configureMdtodoHwpodSource"
|
||||
| "probeMdtodoSource"
|
||||
| "reindexMdtodoSource"
|
||||
| "editMdtodoTaskTitle"
|
||||
| "editMdtodoTaskBody"
|
||||
| "toggleMdtodoTaskStatus"
|
||||
| "addMdtodoRootTask"
|
||||
| "addMdtodoSubTask"
|
||||
| "continueMdtodoTask"
|
||||
| "deleteMdtodoTask"
|
||||
| "launchWorkbenchFromTask"
|
||||
| "launchWorkbenchFromMdtodo"
|
||||
| "screenshot"
|
||||
| "mark"
|
||||
| "stop";
|
||||
|
||||
export interface NodeWebProbeObserveOptions {
|
||||
action: "observe";
|
||||
observeAction: NodeWebProbeObserveAction;
|
||||
id: string | null;
|
||||
node: string;
|
||||
lane: string;
|
||||
url: string;
|
||||
targetPath: string;
|
||||
viewport: string;
|
||||
browserProxyMode: WebProbeBrowserProxyMode;
|
||||
sampleIntervalMs: number;
|
||||
screenshotIntervalMs: number;
|
||||
observerRefreshIntervalMs: number;
|
||||
maxSamples: number;
|
||||
commandTimeoutSeconds: number;
|
||||
waitMs: number;
|
||||
tailLines: number;
|
||||
maxFiles: number;
|
||||
collectView: NodeWebProbeObserveCollectView;
|
||||
collectFile: string | null;
|
||||
collectFinding: string | null;
|
||||
collectGrep: string | null;
|
||||
collectTraceId: string | null;
|
||||
collectSampleSeq: number | null;
|
||||
collectTimestamp: string | null;
|
||||
collectTurn: number | null;
|
||||
analyzeArchivePrefix: string | null;
|
||||
analyzeTailSamples: number | null;
|
||||
full: boolean;
|
||||
stateDir: string | null;
|
||||
jobId: string | null;
|
||||
force: boolean;
|
||||
commandType: NodeWebProbeObserveCommandType | null;
|
||||
commandText: string | null;
|
||||
commandPath: string | null;
|
||||
commandLabel: string | null;
|
||||
commandSessionId: string | null;
|
||||
commandProvider: string | null;
|
||||
commandSourceId: string | null;
|
||||
commandFileRef: string | null;
|
||||
commandTaskRef: string | null;
|
||||
commandTaskId: string | null;
|
||||
commandTitle: string | null;
|
||||
commandBody: string | null;
|
||||
commandStatus: string | null;
|
||||
commandHwpodId: string | null;
|
||||
commandNodeId: string | null;
|
||||
commandWorkspaceRoot: string | null;
|
||||
commandRoot: string | null;
|
||||
}
|
||||
|
||||
export interface NodeWebProbeSentinelOptions {
|
||||
action: "sentinel";
|
||||
sentinel: WebProbeSentinelOptions;
|
||||
node: string;
|
||||
lane: string;
|
||||
}
|
||||
|
||||
export type NodeWebProbeOptions = NodeWebProbeRunOptions | NodeWebProbeScriptOptions | NodeWebProbeObserveOptions | NodeWebProbeSentinelOptions;
|
||||
|
||||
export interface WebObserveIndexEntry {
|
||||
id: string;
|
||||
node: string;
|
||||
lane: string;
|
||||
workspace: string;
|
||||
stateDir: string;
|
||||
url: string;
|
||||
targetPath: string;
|
||||
status: string | null;
|
||||
pid: number | null;
|
||||
startedAt: string | null;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export type NodeObservabilityAction = "plan" | "apply" | "status" | "workbench-summary" | "performance-summary";
|
||||
|
||||
export interface NodeObservabilityOptions {
|
||||
action: NodeObservabilityAction;
|
||||
node: string;
|
||||
lane: HwlabRuntimeLane;
|
||||
confirm: boolean;
|
||||
dryRun: boolean;
|
||||
full: boolean;
|
||||
timeoutSeconds: number;
|
||||
spec: HwlabRuntimeLaneSpec;
|
||||
}
|
||||
|
||||
export interface NodeRuntimeRenderResult {
|
||||
readonly result: CommandResult;
|
||||
readonly renderDir: string;
|
||||
readonly worktreeDir: string;
|
||||
readonly location: NodeRuntimeRenderLocation;
|
||||
}
|
||||
|
||||
export interface NodeRuntimeCleanupPipelineRunRow {
|
||||
name: string;
|
||||
createdAt: string | null;
|
||||
ageMinutes: number | null;
|
||||
status: string | null;
|
||||
reason: string | null;
|
||||
selected?: boolean;
|
||||
selectedReason?: string;
|
||||
}
|
||||
|
||||
export interface NodeRuntimeCleanupOptions {
|
||||
minAgeMinutes: number;
|
||||
limit: number;
|
||||
sourceCommit?: string;
|
||||
pipelineRun?: string;
|
||||
targetPipelineRun?: string;
|
||||
includeActive: boolean;
|
||||
dryRun: boolean;
|
||||
}
|
||||
|
||||
export interface NodeSecretOptions {
|
||||
action: SecretAction;
|
||||
node: string;
|
||||
lane: string;
|
||||
name: string;
|
||||
key?: string;
|
||||
preset: SecretPreset;
|
||||
dryRun: boolean;
|
||||
confirm: boolean;
|
||||
force?: boolean;
|
||||
timeoutSeconds: number;
|
||||
}
|
||||
|
||||
export interface BootstrapAdminSecretMaterial {
|
||||
ok: boolean;
|
||||
sourceRef: string | null;
|
||||
sourceKey: string | null;
|
||||
sourcePath: string | null;
|
||||
sourcePresent: boolean;
|
||||
sourceFingerprint: string | null;
|
||||
passwordHash: string | null;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export interface BootstrapAdminPasswordMaterial {
|
||||
ok: boolean;
|
||||
sourceRef: string | null;
|
||||
sourceKey: string | null;
|
||||
sourcePath: string | null;
|
||||
sourcePresent: boolean;
|
||||
sourceFingerprint: string | null;
|
||||
password: string | null;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export interface NodePublicExposureOptions {
|
||||
action: "public-exposure";
|
||||
node: string;
|
||||
lane: HwlabRuntimeLane;
|
||||
dryRun: boolean;
|
||||
confirm: boolean;
|
||||
timeoutSeconds: number;
|
||||
spec: HwlabRuntimeLaneSpec;
|
||||
}
|
||||
|
||||
export interface RuntimeSecretSpec {
|
||||
node: string;
|
||||
lane: string;
|
||||
namespace: string;
|
||||
platformDb: boolean;
|
||||
runtimeLaneSpec?: HwlabRuntimeLaneSpec;
|
||||
externalPostgres?: NonNullable<HwlabRuntimeLaneSpec["externalPostgres"]>;
|
||||
platformPostgresService: string;
|
||||
platformPostgresEndpointAddress?: string;
|
||||
platformPostgresEndpointSlice: string;
|
||||
postgresSecret: string;
|
||||
postgresStatefulSet: string;
|
||||
postgresAdminUser: string;
|
||||
openFgaSecret: string;
|
||||
openFgaDbName: string;
|
||||
openFgaDbUser: string;
|
||||
openFgaDbHost: string;
|
||||
masterAdminApiKeySecret: string;
|
||||
bootstrapAdminSecret: string;
|
||||
bootstrapAdminPasswordHashKey: string;
|
||||
bootstrapAdminUsername: string;
|
||||
bootstrapAdminDisplayName: string;
|
||||
bootstrapAdminPasswordSourceRef?: string;
|
||||
bootstrapAdminPasswordSourceKey?: string;
|
||||
bootstrapAdminPasswordHashTransform?: "hwlab-sha256";
|
||||
bootstrapAdminSourceNamespace: string;
|
||||
bootstrapAdminSourceSecret: string;
|
||||
cloudApiDbSecret: string;
|
||||
cloudApiDbKey: string;
|
||||
cloudApiDbName: string;
|
||||
cloudApiDbUser: string;
|
||||
cloudApiDbHost: string;
|
||||
cloudApiDeployment: string;
|
||||
obsoleteHwpodDbSecret: string;
|
||||
obsoleteHwpodDbName: string;
|
||||
obsoleteHwpodDbUser: string;
|
||||
codeAgentProviderSecret: string;
|
||||
codeAgentProviderSourceNamespace: string;
|
||||
codeAgentProviderSourceSecret: string;
|
||||
fieldManager: string;
|
||||
}
|
||||
|
||||
export interface NodeRuntimeGitMirrorTargetSpec {
|
||||
id: string;
|
||||
node: string;
|
||||
lane: string;
|
||||
namespace: string;
|
||||
serviceReadName: string;
|
||||
serviceWriteName: string;
|
||||
cachePvcName: string;
|
||||
cachePvcStorage: string;
|
||||
cacheHostPath: string | null;
|
||||
servicePort: number;
|
||||
secretName: string;
|
||||
syncConfigMapName: string;
|
||||
syncJobPrefix: string;
|
||||
flushJobPrefix: string;
|
||||
toolsImage: string;
|
||||
toolsImagePullPolicy: "Always" | "IfNotPresent" | "Never";
|
||||
sourceRepository: string;
|
||||
sourceBranch: string;
|
||||
gitopsBranch: string;
|
||||
egressProxy: NodeRuntimeGitMirrorEgressProxySpec;
|
||||
githubTransport: NodeRuntimeGitMirrorGithubTransportSpec;
|
||||
}
|
||||
|
||||
export type NodeRuntimeGitMirrorGithubTransportSpec =
|
||||
| { mode: "ssh" }
|
||||
| {
|
||||
mode: "https";
|
||||
username: string;
|
||||
tokenSecretName: string;
|
||||
tokenSecretKey: string;
|
||||
tokenSourceRef: string;
|
||||
tokenSourceKey: string;
|
||||
};
|
||||
|
||||
export type NodeRuntimeGitMirrorEgressProxySpec =
|
||||
| { mode: "direct"; required: false }
|
||||
| {
|
||||
mode: "k8s-service-cluster-ip";
|
||||
clientName: string;
|
||||
namespace: string;
|
||||
serviceName: string;
|
||||
port: number;
|
||||
sourceRef: string;
|
||||
sourceKey: string;
|
||||
sourceType: "subscription-url";
|
||||
noProxy: string[];
|
||||
};
|
||||
|
||||
export const MASTER_ADMIN_API_KEY_KEY = "api-key";
|
||||
|
||||
export const BOOTSTRAP_ADMIN_PASSWORD_HASH_KEY = "password-hash";
|
||||
|
||||
export const BOOTSTRAP_ADMIN_SOURCE_NAMESPACE = "hwlab-v02";
|
||||
|
||||
export const BOOTSTRAP_ADMIN_SOURCE_SECRET = "hwlab-v02-bootstrap-admin";
|
||||
|
||||
export const OPENFGA_AUTHN_KEY = "authn-preshared-key";
|
||||
|
||||
export const OPENFGA_DATASTORE_URI_KEY = "datastore-uri";
|
||||
|
||||
export const OPENFGA_POSTGRES_PASSWORD_KEY = "postgres-password";
|
||||
|
||||
export const CLOUD_API_DB_KEY = "database-url";
|
||||
|
||||
export const CODE_AGENT_PROVIDER_OPENAI_KEY = "openai-api-key";
|
||||
|
||||
export const CODE_AGENT_PROVIDER_OPENCODE_KEY = "opencode-api-key";
|
||||
|
||||
export const CODE_AGENT_PROVIDER_SOURCE_NAMESPACE = "hwlab-v02";
|
||||
|
||||
export const CODE_AGENT_PROVIDER_SOURCE_SECRET = "hwlab-v02-code-agent-provider";
|
||||
|
||||
export const HWLAB_CI_NAMESPACE = "hwlab-ci";
|
||||
|
||||
export const NODE_RUNTIME_CICD_WAIT_WARNING_SECONDS = 120;
|
||||
|
||||
export const NODE_RUNTIME_TRIGGER_SEVERE_WARNING_MS = NODE_RUNTIME_CICD_WAIT_WARNING_SECONDS * 1000;
|
||||
|
||||
export async function runHwlabNodeCommand(_config: Config, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
|
||||
if (args.length === 0) return hwlabNodeHelp();
|
||||
const [domain] = args;
|
||||
if (domain === "control-plane" && args[1] === "infra") {
|
||||
if (args.length === 2 || args.includes("--help") || args.includes("-h") || args[2] === "help") return hwlabNodeControlPlaneInfraHelp();
|
||||
return runHwlabNodeControlPlaneInfra(args.slice(2));
|
||||
}
|
||||
if (domain === "test-accounts") {
|
||||
const { runHwlabTestAccountsCommand } = await import("../hwlab-test-accounts");
|
||||
return runHwlabTestAccountsCommand(args.slice(1));
|
||||
}
|
||||
if (domain === "web-probe") {
|
||||
if (args.length === 1 || args.includes("--help") || args.includes("-h") || args[1] === "help") return hwlabNodeWebProbeHelp();
|
||||
return runNodeWebProbe(parseNodeWebProbeOptions(args.slice(1)));
|
||||
}
|
||||
if (domain === "observability") {
|
||||
if (args.length === 1 || args.includes("--help") || args.includes("-h") || args[1] === "help") return hwlabNodeObservabilityHelp();
|
||||
return runNodeObservability(parseNodeObservabilityOptions(args.slice(1)));
|
||||
}
|
||||
if (args.includes("--help") || args.includes("-h")) return hwlabNodeHelp();
|
||||
if (domain === "control-plane" || domain === "git-mirror") {
|
||||
return runNodeDelegatedDomain(_config, domain, args.slice(1));
|
||||
}
|
||||
if (domain !== "secret") {
|
||||
return { ok: false, command: `hwlab nodes ${domain ?? ""}`.trim(), message: "supported commands: hwlab nodes control-plane, hwlab nodes git-mirror, hwlab nodes observability, hwlab nodes secret, hwlab nodes test-accounts, hwlab nodes web-probe" };
|
||||
}
|
||||
const options = parseSecretOptions(args.slice(1));
|
||||
return runNodeSecret(options);
|
||||
}
|
||||
|
||||
export function parseNodeObservabilityOptions(args: string[]): NodeObservabilityOptions {
|
||||
const [actionRaw] = args;
|
||||
if (typeof actionRaw !== "string" || actionRaw.startsWith("--")) {
|
||||
throw new Error("observability usage: observability ACTION --node NODE --lane vNN [--dry-run|--confirm]");
|
||||
}
|
||||
if (actionRaw !== "plan" && actionRaw !== "apply" && actionRaw !== "status" && actionRaw !== "workbench-summary" && actionRaw !== "performance-summary") {
|
||||
throw new Error(`observability action must be plan, apply, status, workbench-summary, or performance-summary; got ${actionRaw}`);
|
||||
}
|
||||
assertKnownOptions(args, new Set(["--node", "--lane", "--timeout-seconds"]), new Set(["--dry-run", "--confirm", "--full", "--raw"]));
|
||||
const node = requiredOption(args, "--node");
|
||||
assertNodeId(node);
|
||||
const laneRaw = requiredOption(args, "--lane");
|
||||
if (!isHwlabRuntimeLane(laneRaw)) throw new Error(`--lane must be one of v02, v03; got ${laneRaw}`);
|
||||
const confirm = args.includes("--confirm");
|
||||
const dryRun = args.includes("--dry-run");
|
||||
if (confirm && dryRun) throw new Error("observability accepts only one of --confirm or --dry-run");
|
||||
if (actionRaw === "apply" && !confirm && !dryRun) throw new Error("observability apply requires --dry-run or --confirm");
|
||||
if (actionRaw !== "apply" && (confirm || dryRun)) throw new Error(`observability ${actionRaw} is read-only and does not accept --confirm or --dry-run`);
|
||||
return {
|
||||
action: actionRaw,
|
||||
node,
|
||||
lane: laneRaw,
|
||||
confirm,
|
||||
dryRun,
|
||||
full: args.includes("--full") || args.includes("--raw"),
|
||||
timeoutSeconds: positiveIntegerOption(args, "--timeout-seconds", 120, 600),
|
||||
spec: hwlabRuntimeLaneSpecForNode(laneRaw, node),
|
||||
};
|
||||
}
|
||||
|
||||
export async function runNodeDelegatedDomain(config: Config, domain: DelegatedNodeDomain, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
|
||||
const scoped = parseNodeScopedDelegatedOptions(domain, args);
|
||||
const defaultSpec = hwlabRuntimeLaneSpec(scoped.lane);
|
||||
if (domain === "control-plane" && scoped.action === "public-exposure") {
|
||||
return runNodePublicExposure({
|
||||
action: "public-exposure",
|
||||
node: scoped.node,
|
||||
lane: scoped.lane,
|
||||
dryRun: scoped.dryRun || !scoped.confirm,
|
||||
confirm: scoped.confirm,
|
||||
timeoutSeconds: scoped.timeoutSeconds,
|
||||
spec: scoped.spec,
|
||||
});
|
||||
}
|
||||
if (domain === "control-plane" && scoped.action === "runtime-image") {
|
||||
return nodeRuntimeBaseImageCommand(scoped);
|
||||
}
|
||||
if (domain === "control-plane" && scoped.action === "plan") {
|
||||
const result = nodeRuntimeControlPlanePlan(scoped);
|
||||
return nodeScopedFullOutput(scoped) ? result : withNodeRuntimeControlPlanePlanRendered(result, scoped);
|
||||
}
|
||||
if (domain === "control-plane" && scoped.node !== defaultSpec.nodeId) {
|
||||
if (scoped.action === "status") {
|
||||
const result = nodeRuntimeControlPlaneStatus(scoped);
|
||||
if (scoped.originalArgs.includes("--raw")) return result;
|
||||
if (scoped.originalArgs.includes("--full")) return withNodeRuntimeControlPlaneStatusFullRendered(result, scoped);
|
||||
return withNodeRuntimeControlPlaneStatusRendered(result, scoped);
|
||||
}
|
||||
if (scoped.action === "apply" || scoped.action === "trigger-current" || scoped.action === "refresh" || scoped.action === "sync" || scoped.action === "runtime-migration" || scoped.action === "cleanup-runs") {
|
||||
if (scoped.confirm && !scoped.dryRun && !scoped.wait) return startNodeDelegatedJob(scoped);
|
||||
return nodeRuntimeControlPlaneRun(scoped);
|
||||
}
|
||||
return nodeRuntimeUnsupportedAction(scoped);
|
||||
}
|
||||
if (domain === "git-mirror" && scoped.node !== defaultSpec.nodeId) {
|
||||
if (scoped.action === "status") {
|
||||
const result = nodeRuntimeGitMirrorStatus(scoped);
|
||||
return nodeScopedFullOutput(scoped) ? result : withNodeRuntimeGitMirrorRendered(result, scoped);
|
||||
}
|
||||
if (scoped.action === "sync" || scoped.action === "flush") {
|
||||
if (scoped.confirm && !scoped.dryRun && !scoped.wait) return startNodeDelegatedJob(scoped);
|
||||
const result = nodeRuntimeGitMirrorRun(scoped);
|
||||
return nodeScopedFullOutput(scoped) ? result : withNodeRuntimeGitMirrorRendered(result, scoped);
|
||||
}
|
||||
return nodeRuntimeUnsupportedAction(scoped);
|
||||
}
|
||||
if (domain === "control-plane" && scoped.action === "allow-endpoint-bridge") {
|
||||
return runNodeEndpointBridge(scoped);
|
||||
}
|
||||
if (domain === "control-plane" && scoped.action === "trigger-current" && scoped.confirm && !scoped.dryRun && !scoped.wait) {
|
||||
return startNodeDelegatedJob(scoped);
|
||||
}
|
||||
if (domain === "git-mirror" && (scoped.action === "sync" || scoped.action === "flush") && scoped.confirm && !scoped.dryRun && !scoped.wait) {
|
||||
return startNodeDelegatedJob(scoped);
|
||||
}
|
||||
const delegatedArgs = stripOption(args, "--node");
|
||||
const result = await runDelegatedHwlabNodeCommand(config, domain, delegatedArgs);
|
||||
return rewriteDelegatedNodeResult(result, scoped);
|
||||
}
|
||||
Reference in New Issue
Block a user