feat: add YAML-first source workspace host deps

This commit is contained in:
Codex
2026-06-29 09:16:16 +00:00
parent d30e5853fa
commit c9fd499fd2
3 changed files with 369 additions and 4 deletions
+34
View File
@@ -354,6 +354,7 @@ export interface HwlabRuntimeCodeAgentRuntimeSpec {
export interface HwlabRuntimeSourceWorkspaceSpec {
readonly requiredCommands: readonly string[];
readonly requiredFiles: readonly string[];
readonly hostDependencies?: HwlabRuntimeSourceWorkspaceHostDependenciesSpec;
readonly install: {
readonly dependencyCommand: string;
readonly browserCommand: string;
@@ -361,6 +362,15 @@ export interface HwlabRuntimeSourceWorkspaceSpec {
};
}
export interface HwlabRuntimeSourceWorkspaceHostDependenciesSpec {
readonly checkCommands: readonly string[];
readonly stateDir: string;
readonly install: {
readonly command: string;
readonly timeoutSeconds: number;
};
}
export interface HwlabRuntimeLaneSpec {
readonly lane: HwlabRuntimeLane;
readonly nodeId: string;
@@ -852,6 +862,14 @@ function relativeWorkspacePathField(value: string, path: string): string {
return value;
}
function absoluteHostPathField(value: string, path: string): string {
const parts = value.slice(1).split("/");
if (!value.startsWith("/") || value.includes("\0") || parts.some((part) => part === ".." || part === "")) {
throw new Error(`${path} must be an absolute host path without empty components or ..`);
}
return value;
}
function sourceWorkspaceConfig(value: unknown, path: string): HwlabRuntimeSourceWorkspaceSpec | undefined {
if (value === undefined) return undefined;
const raw = asRecord(value, path);
@@ -861,6 +879,7 @@ function sourceWorkspaceConfig(value: unknown, path: string): HwlabRuntimeSource
.map((item, index) => commandNameField(item, `${path}.requiredCommands[${index}]`)),
requiredFiles: stringArrayField(raw, "requiredFiles", path)
.map((item, index) => relativeWorkspacePathField(item, `${path}.requiredFiles[${index}]`)),
hostDependencies: sourceWorkspaceHostDependenciesConfig(raw.hostDependencies, `${path}.hostDependencies`),
install: {
dependencyCommand: stringField(install, "dependencyCommand", `${path}.install`),
browserCommand: stringField(install, "browserCommand", `${path}.install`),
@@ -869,6 +888,21 @@ function sourceWorkspaceConfig(value: unknown, path: string): HwlabRuntimeSource
};
}
function sourceWorkspaceHostDependenciesConfig(value: unknown, path: string): HwlabRuntimeSourceWorkspaceHostDependenciesSpec | undefined {
if (value === undefined) return undefined;
const raw = asRecord(value, path);
const install = asRecord(raw.install, `${path}.install`);
return {
checkCommands: stringArrayField(raw, "checkCommands", path)
.map((item, index) => commandNameField(item, `${path}.checkCommands[${index}]`)),
stateDir: absoluteHostPathField(stringField(raw, "stateDir", path), `${path}.stateDir`),
install: {
command: stringField(install, "command", `${path}.install`),
timeoutSeconds: numberField(install, "timeoutSeconds", `${path}.install`),
},
};
}
function externalPostgresComponentConfig(value: unknown, path: string): HwlabRuntimeExternalPostgresComponentSpec {
const raw = asRecord(value, path);
return {