diff --git a/config/platform-infra/webterm.yaml b/config/platform-infra/webterm.yaml index 874b61da..4479a82a 100644 --- a/config/platform-infra/webterm.yaml +++ b/config/platform-infra/webterm.yaml @@ -5,6 +5,19 @@ metadata: id: webterm-public owner: unidesk +sessionStartModes: + defaultMode: mycx + options: + bash: + label: Bash + command: exec bash -l + mycx: + label: mycx + command: mycx + oncx: + label: oncx + command: oncx + defaults: targetId: local-7683 @@ -40,7 +53,7 @@ targets: command: mycx resume 019f4937-9820-7b31-9178-344ae93d5a4c cols: 100 rows: 30 - - title: 71-FILTER + - title: CONSTAR cwd: /root/unidesk command: mycx resume 019f4b5f-b5ce-76b3-8ccb-508790e9662d cols: 100 diff --git a/scripts/src/platform-infra-webterm.ts b/scripts/src/platform-infra-webterm.ts index 3893dc7d..3830cdbc 100644 --- a/scripts/src/platform-infra-webterm.ts +++ b/scripts/src/platform-infra-webterm.ts @@ -21,9 +21,15 @@ const serviceName = "webterm"; interface WebtermConfig { defaults: { targetId: string }; + sessionStartModes: SessionStartModes; targets: WebtermTarget[]; } +interface SessionStartModes { + defaultMode: string; + options: Array<{ id: string; label: string; command: string }>; +} + interface WebtermTarget { id: string; enabled: boolean; @@ -42,6 +48,7 @@ interface WebtermTarget { pid: "host" | "container"; sourceMounts: Array<{ source: string; target: string; readOnly: boolean }>; autoStartSessions: Array<{ title: string; cwd: string; command: string; cols: number; rows: number }>; + sessionStartModes: SessionStartModes; environment: Record; }; publicExposure: { @@ -237,15 +244,17 @@ function validate(targetId: string | null): Record { function readWebtermConfig(): WebtermConfig { const yaml = readYamlRecord(configPath, "platform-infra-webterm"); const defaults = recordField(yaml, "defaults", "webterm"); + const sessionStartModes = parseSessionStartModes(recordField(yaml, "sessionStartModes", "webterm"), "webterm.sessionStartModes"); const targetsRaw = yaml.targets; if (!Array.isArray(targetsRaw)) throw new Error("webterm.targets must be an array"); return { defaults: { targetId: stringField(defaults, "targetId", "webterm.defaults") }, - targets: targetsRaw.map((item, index) => parseTarget(asRecord(item, `webterm.targets[${index}]`), `webterm.targets[${index}]`)), + sessionStartModes, + targets: targetsRaw.map((item, index) => parseTarget(asRecord(item, `webterm.targets[${index}]`), `webterm.targets[${index}]`, sessionStartModes)), }; } -function parseTarget(record: Record, path: string): WebtermTarget { +function parseTarget(record: Record, path: string, sessionStartModes: SessionStartModes): WebtermTarget { const runtime = recordField(record, "runtime", path); const exposure = recordField(record, "publicExposure", path); const dns = recordField(exposure, "dns", `${path}.publicExposure`); @@ -272,6 +281,7 @@ function parseTarget(record: Record, path: string): WebtermTarg pid: parsePid(stringField(runtime, "pid", `${path}.runtime`), `${path}.runtime.pid`), sourceMounts, autoStartSessions, + sessionStartModes, environment, }, publicExposure: { @@ -312,6 +322,8 @@ function renderCompose(target: WebtermTarget): string { const environment = { ...target.runtime.environment, AUTO_START_SESSIONS_JSON: JSON.stringify(target.runtime.autoStartSessions), + SESSION_START_MODES_JSON: JSON.stringify(target.runtime.sessionStartModes.options), + SESSION_START_DEFAULT_MODE: target.runtime.sessionStartModes.defaultMode, }; const envLines = Object.entries(environment) .map(([key, value]) => ` ${key}: ${quoteYaml(value)}`) @@ -386,6 +398,10 @@ function targetSummary(target: WebtermTarget): Record { containerName: target.runtime.containerName, image: target.runtime.image, autoStartSessions: target.runtime.autoStartSessions.map((session) => session.title), + sessionStartModes: { + defaultMode: target.runtime.sessionStartModes.defaultMode, + options: target.runtime.sessionStartModes.options.map((mode) => mode.id), + }, sourceMounts: target.runtime.sourceMounts.map((mount) => `${mount.source}->${mount.target}${mount.readOnly ? ":ro" : ""}`), hostPort: target.runtime.hostPort, containerPort: target.runtime.containerPort, @@ -504,6 +520,29 @@ function parseAutoStartSessions(value: unknown, path: string): WebtermTarget["ru }); } +function parseSessionStartModes(record: Record, path: string): SessionStartModes { + const defaultMode = stringField(record, "defaultMode", path); + const optionsRecord = recordField(record, "options", path); + const options = Object.entries(optionsRecord).map(([id, item]) => { + const itemPath = `${path}.options.${id}`; + const option = asRecord(item, itemPath); + return { + id, + label: stringField(option, "label", itemPath), + command: commandField(option, itemPath), + }; + }); + if (options.length === 0) throw new Error(`${path}.options must be a non-empty record`); + if (!options.some((option) => option.id === defaultMode)) throw new Error(`${path}.defaultMode must reference an option id`); + return { defaultMode, options }; +} + +function commandField(record: Record, path: string): string { + const value = record.command; + if (typeof value !== "string") throw new Error(`${path}.command must be a string`); + return value.trim(); +} + function parseLiteral(value: string, expected: T, path: string): T { if (value !== expected) throw new Error(`${path} must be ${expected}`); return expected;