fix(hwlab): close d518 yaml cutover gaps

This commit is contained in:
Codex
2026-06-27 15:40:25 +00:00
parent fc032d829a
commit 1968c43a6a
14 changed files with 831 additions and 13 deletions
+44
View File
@@ -313,6 +313,16 @@ export interface HwlabRuntimeCodeAgentProviderSpec {
readonly opencodeSourceKey?: string;
}
export interface HwlabRuntimeSourceWorkspaceSpec {
readonly requiredCommands: readonly string[];
readonly requiredFiles: readonly string[];
readonly install: {
readonly dependencyCommand: string;
readonly browserCommand: string;
readonly timeoutSeconds: number;
};
}
export interface HwlabRuntimeLaneSpec {
readonly lane: HwlabRuntimeLane;
readonly nodeId: string;
@@ -351,6 +361,7 @@ export interface HwlabRuntimeLaneSpec {
readonly buildkit?: HwlabRuntimeBuildkitSpec;
readonly bootstrapAdmin?: HwlabRuntimeBootstrapAdminSpec;
readonly codeAgentProvider?: HwlabRuntimeCodeAgentProviderSpec;
readonly sourceWorkspace?: HwlabRuntimeSourceWorkspaceSpec;
readonly externalPostgres?: HwlabRuntimeExternalPostgresSpec;
readonly runtimeStore?: HwlabRuntimeStoreSpec;
readonly webProbe?: HwlabRuntimeWebProbeSpec;
@@ -401,6 +412,7 @@ interface HwlabLaneConfig {
readonly buildkit?: HwlabRuntimeBuildkitSpec;
readonly bootstrapAdmin?: HwlabRuntimeBootstrapAdminSpec;
readonly codeAgentProvider?: HwlabRuntimeCodeAgentProviderSpec;
readonly sourceWorkspace?: HwlabRuntimeSourceWorkspaceSpec;
readonly externalPostgres?: HwlabRuntimeExternalPostgresSpec;
readonly runtimeStore?: HwlabRuntimeStoreSpec;
readonly webProbe?: HwlabRuntimeWebProbeSpec;
@@ -643,6 +655,7 @@ function laneConfig(id: HwlabRuntimeLane, raw: Record<string, unknown>): HwlabLa
buildkit: buildkitConfig(raw.buildkit, `lanes.${id}.buildkit`),
bootstrapAdmin: bootstrapAdminConfig(raw.bootstrapAdmin, `lanes.${id}.bootstrapAdmin`),
codeAgentProvider: codeAgentProviderConfig(raw.codeAgentProvider, `lanes.${id}.codeAgentProvider`),
sourceWorkspace: sourceWorkspaceConfig(raw.sourceWorkspace, `lanes.${id}.sourceWorkspace`),
externalPostgres: externalPostgresConfig(raw.externalPostgres, `lanes.${id}.externalPostgres`),
runtimeStore: runtimeStoreConfig(raw.runtimeStore, `lanes.${id}.runtimeStore`),
webProbe: webProbeConfig(raw.webProbe, `lanes.${id}.webProbe`),
@@ -666,6 +679,7 @@ function laneTargetConfig(id: HwlabRuntimeLane, nodeId: string, baseRaw: Record<
buildkit: mergeOptionalRecord(baseRaw.buildkit, targetRaw.buildkit),
bootstrapAdmin: mergeOptionalRecord(baseRaw.bootstrapAdmin, targetRaw.bootstrapAdmin),
codeAgentProvider: mergeOptionalRecord(baseRaw.codeAgentProvider, targetRaw.codeAgentProvider),
sourceWorkspace: mergeOptionalRecord(baseRaw.sourceWorkspace, targetRaw.sourceWorkspace),
externalPostgres: mergeOptionalRecord(baseRaw.externalPostgres, targetRaw.externalPostgres),
runtimeStore: mergeOptionalRecord(baseRaw.runtimeStore, targetRaw.runtimeStore),
webProbe: mergeOptionalRecord(baseRaw.webProbe, targetRaw.webProbe),
@@ -732,6 +746,35 @@ function codeAgentProviderConfig(value: unknown, path: string): HwlabRuntimeCode
};
}
function commandNameField(value: string, path: string): string {
if (!/^[A-Za-z0-9._+-]+$/u.test(value)) throw new Error(`${path} must be a simple command name`);
return value;
}
function relativeWorkspacePathField(value: string, path: string): string {
if (value.startsWith("/") || value.includes("\0") || value.split("/").some((part) => part === "..")) {
throw new Error(`${path} must be a relative workspace path without ..`);
}
return value;
}
function sourceWorkspaceConfig(value: unknown, path: string): HwlabRuntimeSourceWorkspaceSpec | undefined {
if (value === undefined) return undefined;
const raw = asRecord(value, path);
const install = asRecord(raw.install, `${path}.install`);
return {
requiredCommands: stringArrayField(raw, "requiredCommands", path)
.map((item, index) => commandNameField(item, `${path}.requiredCommands[${index}]`)),
requiredFiles: stringArrayField(raw, "requiredFiles", path)
.map((item, index) => relativeWorkspacePathField(item, `${path}.requiredFiles[${index}]`)),
install: {
dependencyCommand: stringField(install, "dependencyCommand", `${path}.install`),
browserCommand: stringField(install, "browserCommand", `${path}.install`),
timeoutSeconds: numberField(install, "timeoutSeconds", `${path}.install`),
},
};
}
function externalPostgresComponentConfig(value: unknown, path: string): HwlabRuntimeExternalPostgresComponentSpec {
const raw = asRecord(value, path);
return {
@@ -1308,6 +1351,7 @@ function buildRuntimeLaneSpec(config: HwlabLaneConfig): HwlabRuntimeLaneSpec {
...(config.buildkit === undefined ? {} : { buildkit: config.buildkit }),
...(config.bootstrapAdmin === undefined ? {} : { bootstrapAdmin: config.bootstrapAdmin }),
...(config.codeAgentProvider === undefined ? {} : { codeAgentProvider: config.codeAgentProvider }),
...(config.sourceWorkspace === undefined ? {} : { sourceWorkspace: config.sourceWorkspace }),
...(config.externalPostgres === undefined ? {} : { externalPostgres: config.externalPostgres }),
...(config.runtimeStore === undefined ? {} : { runtimeStore: config.runtimeStore }),
...(config.webProbe === undefined ? {} : { webProbe: config.webProbe }),