350 lines
21 KiB
TypeScript
350 lines
21 KiB
TypeScript
import { resolve } from "node:path";
|
|
|
|
import { runCommand } from "./command";
|
|
import { resolveConfigRef } from "./ops/config-refs";
|
|
import { readEnvSourceFile, requiredEnvValue } from "./secrets";
|
|
import { hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneSpecForNode, isHwlabRuntimeLane, type HwlabRuntimeLaneSpec, type HwlabRuntimeNativeDevelopmentSpec } from "./hwlab-node-lanes";
|
|
|
|
type Application = "workbench" | "hwpod" | "caserun";
|
|
type Service = "api" | "worker" | "web";
|
|
type Action = "start" | "stop" | "restart" | "status" | "logs";
|
|
|
|
export function hwlabNativeDevelopmentHelp(): Record<string, unknown> {
|
|
return {
|
|
ok: true,
|
|
command: "hwlab nodes native-development workbench",
|
|
usage: [
|
|
"bun scripts/cli.ts hwlab nodes native-development workbench status --node <node> --lane <lane>",
|
|
"bun scripts/cli.ts hwlab nodes native-development workbench api|worker|web start|stop|restart|status|logs --node <node> --lane <lane>",
|
|
"bun scripts/cli.ts hwlab nodes native-development workbench cli <health|session|turn|events ...> --node <node> --lane <lane>",
|
|
"bun scripts/cli.ts hwlab nodes native-development hwpod status --node <node> --lane <lane>",
|
|
"bun scripts/cli.ts hwlab nodes native-development hwpod api|worker|web start|stop|restart|status|logs --node <node> --lane <lane>",
|
|
"bun scripts/cli.ts hwlab nodes native-development caserun api|web start|stop|restart|status|logs --node <node> --lane <lane>",
|
|
],
|
|
contract: "L1 API/Web 用户入口只输出 owning YAML 解析出的固定 HTTPS 域名;IP、port 和 bind/probe 地址不作为用户入口。",
|
|
configPath: hwlabRuntimeLaneConfigPath(),
|
|
};
|
|
}
|
|
|
|
export function runHwlabNativeDevelopmentCommand(args: string[]): Record<string, unknown> {
|
|
if (args.length === 0 || args.includes("--help") || args.includes("-h")) return hwlabNativeDevelopmentHelp();
|
|
const [applicationRaw, serviceRaw, actionRaw] = args;
|
|
const application = parseApplication(applicationRaw);
|
|
const node = requiredOption(args, "--node");
|
|
const lane = requiredOption(args, "--lane");
|
|
if (!isHwlabRuntimeLane(lane)) throw new Error(`--lane must be declared in ${hwlabRuntimeLaneConfigPath()}`);
|
|
const spec = hwlabRuntimeLaneSpecForNode(lane, node);
|
|
const native = spec.nativeDevelopment?.[application];
|
|
if (native === undefined) throw new Error(`${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.${application} is required`);
|
|
const env = application === "workbench"
|
|
? workbenchEnvironment(spec, native as HwlabRuntimeNativeDevelopmentSpec["workbench"])
|
|
: application === "hwpod"
|
|
? hwlabHwpodNativeDevelopmentEnvironment(native as NonNullable<HwlabRuntimeNativeDevelopmentSpec["hwpod"]>)
|
|
: hwlabCaseRunNativeDevelopmentEnvironment(native as NonNullable<HwlabRuntimeNativeDevelopmentSpec["caserun"]>);
|
|
if (application === "workbench" && serviceRaw === "cli") {
|
|
const commandArgs = withoutOptions(args.slice(2), ["--node", "--lane"]);
|
|
if (commandArgs.length === 0) throw new Error("native-development workbench cli requires a Workbench command");
|
|
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", "workbench", ...commandArgs];
|
|
const result = runCommand(command, spec.workspace, {
|
|
timeoutMs: cliTimeoutMs(commandArgs),
|
|
env: { ...process.env, ...env, WORKBENCH_API_URL: env.WORKBENCH_NATIVE_API_URL },
|
|
});
|
|
return {
|
|
ok: result.exitCode === 0,
|
|
command: "hwlab nodes native-development workbench cli",
|
|
node,
|
|
lane,
|
|
transport: commandArgs.includes("--over-api") ? "native-api" : "local-dispatcher",
|
|
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.workbench`,
|
|
workbenchResult: parsePayload(result.stdout),
|
|
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_cli_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
|
|
};
|
|
}
|
|
if (application === "hwpod" && serviceRaw === "cli") {
|
|
const commandArgs = withoutOptions(args.slice(2), ["--node", "--lane"]);
|
|
if (commandArgs.length === 0) throw new Error("native-development hwpod cli requires a HWPOD command");
|
|
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", "hwpod", ...commandArgs];
|
|
const result = runCommand(command, spec.workspace, {
|
|
timeoutMs: cliTimeoutMs(commandArgs),
|
|
env: { ...process.env, ...env, HWLAB_RUNTIME_API_URL: env.HWPOD_NATIVE_API_URL },
|
|
});
|
|
return {
|
|
ok: result.exitCode === 0,
|
|
command: "hwlab nodes native-development hwpod cli",
|
|
node,
|
|
lane,
|
|
transport: commandArgs.includes("--over-api") ? "native-api" : "local-function",
|
|
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.hwpod`,
|
|
hwpodResult: parsePayload(result.stdout),
|
|
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_cli_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
|
|
};
|
|
}
|
|
if (application === "workbench" && serviceRaw === "status") {
|
|
const remaining = withoutOptions(args.slice(2), ["--node", "--lane"]);
|
|
if (remaining.length > 0) throw new Error(`native-development workbench status does not accept positional arguments: ${remaining.join(" ")}`);
|
|
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", "workbench", "service", "status"];
|
|
const result = runCommand(command, spec.workspace, { timeoutMs: 15_000, env: { ...process.env, ...env } });
|
|
const payload = parsePayload(result.stdout);
|
|
return {
|
|
ok: result.exitCode === 0 && payload.ok !== false,
|
|
command: "hwlab nodes native-development workbench status",
|
|
node,
|
|
lane,
|
|
action: "status",
|
|
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.workbench`,
|
|
userEndpoint: { url: `${native.publicExposure.publicBaseUrl}/workbench` },
|
|
serviceResult: payload,
|
|
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_cli_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
|
|
};
|
|
}
|
|
if (application === "hwpod" && serviceRaw === "status") {
|
|
const remaining = withoutOptions(args.slice(2), ["--node", "--lane"]);
|
|
if (remaining.length > 0) throw new Error(`native-development hwpod status does not accept positional arguments: ${remaining.join(" ")}`);
|
|
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", "hwpod", "service", "status"];
|
|
const result = runCommand(command, spec.workspace, { timeoutMs: 30_000, env: { ...process.env, ...env } });
|
|
const payload = parsePayload(result.stdout);
|
|
return {
|
|
ok: result.exitCode === 0 && payload.ok !== false,
|
|
command: "hwlab nodes native-development hwpod status",
|
|
node,
|
|
lane,
|
|
action: "status",
|
|
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.hwpod`,
|
|
userEndpoint: { url: `${native.publicExposure.publicBaseUrl}${(native as NonNullable<HwlabRuntimeNativeDevelopmentSpec["hwpod"]>).web.accessProfile.startPath}` },
|
|
serviceResult: payload,
|
|
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_cli_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
|
|
};
|
|
}
|
|
const service = parseService(serviceRaw, application);
|
|
const action = parseAction(actionRaw);
|
|
const command = ["bun", "tools/hwlab-cli/bin/hwlab-cli.ts", application, "service", service, action];
|
|
const result = runCommand(command, spec.workspace, { timeoutMs: 15_000, env: { ...process.env, ...env } });
|
|
const payload = parsePayload(result.stdout);
|
|
const publicEndpoint = service === "api"
|
|
? { url: native.publicExposure.publicBaseUrl }
|
|
: service === "web"
|
|
? { url: application === "hwpod" ? `${native.publicExposure.publicBaseUrl}${(native as NonNullable<HwlabRuntimeNativeDevelopmentSpec["hwpod"]>).web.accessProfile.startPath}` : `${native.publicExposure.publicBaseUrl}/${application === "workbench" ? "workbench" : "caserun"}` }
|
|
: null;
|
|
return {
|
|
ok: result.exitCode === 0 && payload.ok !== false,
|
|
command: `hwlab nodes native-development ${application} ${service} ${action}`,
|
|
node,
|
|
lane,
|
|
service,
|
|
action,
|
|
configSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.${application}`,
|
|
publicExposureSource: `${hwlabRuntimeLaneConfigPath()}#lanes.${lane}.targets.${node}.nativeDevelopment.${application}.publicExposure`,
|
|
userEndpoint: publicEndpoint,
|
|
serviceResult: payload,
|
|
...(result.exitCode === 0 ? {} : { error: { code: "hwlab_native_service_failed", exitCode: result.exitCode, stderr: result.stderr.trim().slice(-2000) } }),
|
|
};
|
|
}
|
|
|
|
function workbenchEnvironment(spec: HwlabRuntimeLaneSpec, native: HwlabRuntimeNativeDevelopmentSpec["workbench"]): NodeJS.ProcessEnv {
|
|
const sourceCommitResult = runCommand(["git", "rev-parse", "HEAD"], spec.workspace, { timeoutMs: 5_000 });
|
|
if (sourceCommitResult.exitCode !== 0 || !/^[0-9a-f]{40}$/iu.test(sourceCommitResult.stdout.trim())) throw new Error(`cannot resolve current HWLAB source commit from ${spec.workspace}`);
|
|
return hwlabNativeDevelopmentEnvironment(native, spec, sourceCommitResult.stdout.trim());
|
|
}
|
|
|
|
export function hwlabNativeDevelopmentEnvironment(native: HwlabRuntimeNativeDevelopmentSpec["workbench"], spec: HwlabRuntimeLaneSpec, sourceCommit: string): NodeJS.ProcessEnv {
|
|
const codeAgent = spec.codeAgentRuntime;
|
|
if (codeAgent === undefined) throw new Error(`${hwlabRuntimeLaneConfigPath()}#lanes.${spec.lane}.targets.${spec.nodeId}.codeAgentRuntime is required`);
|
|
const kafkaBridge = codeAgent.kafkaEventBridge;
|
|
if (kafkaBridge === undefined) throw new Error(`${hwlabRuntimeLaneConfigPath()}#lanes.${spec.lane}.targets.${spec.nodeId}.${native.kafka.configRef} is required`);
|
|
if (native.kafka.hwlabEventConsumerGroupId === kafkaBridge.hwlabEventConsumerGroupId) throw new Error("native Workbench Kafka consumer group must be distinct from the Cloud API live SSE consumer group");
|
|
if (!/^[0-9a-f]{40}$/iu.test(sourceCommit)) throw new Error("sourceCommit must be the current HWLAB workspace 40-hex git SHA");
|
|
const providerSecretNames = codeAgent.providerSecretNames;
|
|
if (providerSecretNames === undefined) throw new Error(`${hwlabRuntimeLaneConfigPath()}#lanes.${spec.lane}.targets.${spec.nodeId}.codeAgentRuntime.providerSecretNames is required`);
|
|
const defaultProviderKey = codeAgent.defaultProviderProfile.toLowerCase().replace(/[^a-z0-9]+/gu, "-");
|
|
if (!providerSecretNames[defaultProviderKey]) throw new Error(`codeAgentRuntime.providerSecretNames.${defaultProviderKey} is required for defaultProviderProfile=${codeAgent.defaultProviderProfile}`);
|
|
const authorizationSource = readEnvSourceFile({
|
|
root: "/root/.unidesk/.state/secrets",
|
|
sourceRef: codeAgent.apiKeySourceRef,
|
|
});
|
|
const agentRunApiKey = requiredEnvValue(authorizationSource.values, codeAgent.apiKeySourceKey, codeAgent.apiKeySourceRef);
|
|
const sessionIndex = native.kafka.refreshReplay.sessionIndex;
|
|
return {
|
|
WORKBENCH_MODE: native.mode,
|
|
WORKBENCH_TEMPORAL_ADDRESS: native.temporal.address,
|
|
WORKBENCH_TEMPORAL_NAMESPACE: native.temporal.namespace,
|
|
WORKBENCH_TEMPORAL_TASK_QUEUE: native.temporal.taskQueue,
|
|
WORKBENCH_ACTIVITY_START_TO_CLOSE_TIMEOUT_MS: String(native.temporal.activity.startToCloseTimeoutMs),
|
|
WORKBENCH_ACTIVITY_RETRY_INITIAL_INTERVAL_MS: String(native.temporal.activity.retryInitialIntervalMs),
|
|
WORKBENCH_ACTIVITY_RETRY_MAXIMUM_INTERVAL_MS: String(native.temporal.activity.retryMaximumIntervalMs),
|
|
WORKBENCH_ACTIVITY_RETRY_MAXIMUM_ATTEMPTS: String(native.temporal.activity.retryMaximumAttempts),
|
|
AGENTRUN_MGR_URL: native.agentRun.managerUrl,
|
|
AGENTRUN_API_KEY: agentRunApiKey,
|
|
HWLAB_CODE_AGENT_ADAPTER: codeAgent.adapter,
|
|
HWLAB_CODE_AGENT_AGENTRUN_ALLOW_PRIVATE_URL: "1",
|
|
HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID: spec.nodeId,
|
|
HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE: codeAgent.defaultProviderProfile,
|
|
HWLAB_CODE_AGENT_AGENTRUN_RUNNER_NAMESPACE: codeAgent.runnerNamespace,
|
|
HWLAB_CODE_AGENT_AGENTRUN_SECRET_NAMESPACE: codeAgent.secretNamespace,
|
|
...providerSecretNameEnvironment(providerSecretNames),
|
|
HWLAB_CODE_AGENT_AGENTRUN_GITHUB_TOOL_SECRET_NAME: codeAgent.toolSecretNames.githubPr,
|
|
HWLAB_CODE_AGENT_AGENTRUN_UNIDESK_SSH_TOOL_SECRET_NAME: codeAgent.toolSecretNames.unideskSsh,
|
|
HWLAB_CODE_AGENT_AGENTRUN_REPO_URL: spec.gitReadUrl,
|
|
HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT: sourceCommit,
|
|
HWLAB_RUNTIME_API_URL: native.agentRun.runtimeApiUrl,
|
|
HWLAB_RUNTIME_WEB_URL: native.agentRun.runtimeWebUrl,
|
|
HWLAB_RUNTIME_NAMESPACE: spec.runtimeNamespace,
|
|
HWLAB_RUNTIME_LANE: spec.lane,
|
|
HWLAB_RUNTIME_ENDPOINT_LOCKED: "1",
|
|
HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME: "1",
|
|
HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED: "false",
|
|
HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED: "true",
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED: "true",
|
|
HWLAB_KAFKA_TRANSACTIONAL_PROJECTOR_ENABLED: "false",
|
|
HWLAB_KAFKA_PROJECTION_OUTBOX_RELAY_ENABLED: "false",
|
|
HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED: "false",
|
|
HWLAB_KAFKA_BOOTSTRAP_SERVERS: native.kafka.bootstrapServers,
|
|
HWLAB_KAFKA_DNS_SERVERS: native.kafka.dnsServers.join(","),
|
|
HWLAB_KAFKA_DNS_SEARCH_DOMAINS: native.kafka.dnsSearchDomains.join(","),
|
|
HWLAB_KAFKA_AGENTRUN_EVENT_TOPIC: kafkaBridge.agentRunEventTopic,
|
|
HWLAB_KAFKA_EVENT_TOPIC: kafkaBridge.hwlabEventTopic,
|
|
HWLAB_KAFKA_CLIENT_ID: native.kafka.clientId,
|
|
HWLAB_KAFKA_HWLAB_EVENT_GROUP_ID: native.kafka.hwlabEventConsumerGroupId,
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_GROUP_PREFIX: native.kafka.refreshReplay.groupIdPrefix,
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_TIMEOUT_MS: String(native.kafka.refreshReplay.timeoutMs),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_SCAN_LIMIT: String(native.kafka.refreshReplay.scanLimit),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_MATCHED_EVENT_LIMIT: String(native.kafka.refreshReplay.matchedEventLimit),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_LIVE_BUFFER_LIMIT: String(native.kafka.refreshReplay.liveBufferLimit),
|
|
...(sessionIndex === undefined ? {} : {
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_ENABLED: String(sessionIndex.enabled),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_MAX_EVENTS: String(sessionIndex.maxEvents),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_MAX_EVENTS_PER_SESSION: String(sessionIndex.maxEventsPerSession),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_BOOTSTRAP_TIMEOUT_MS: String(sessionIndex.bootstrapTimeoutMs),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_REBUILD_INTERVAL_MS: String(sessionIndex.rebuildIntervalMs),
|
|
HWLAB_WORKBENCH_KAFKA_REFRESH_INDEX_REBUILD_COOLDOWN_MS: String(sessionIndex.rebuildCooldownMs),
|
|
}),
|
|
WORKBENCH_NATIVE_SERVICE_STATE_DIR: native.stateDir,
|
|
WORKBENCH_NATIVE_STATE_FILE: resolve(spec.workspace, native.stateFile),
|
|
WORKBENCH_API_BIND_HOST: native.api.bindHost,
|
|
WORKBENCH_API_PROBE_HOST: native.api.probeHost,
|
|
WORKBENCH_PUBLIC_BASE_URL: native.publicExposure.publicBaseUrl,
|
|
WORKBENCH_API_PORT: String(native.api.port),
|
|
WORKBENCH_API_IDLE_TIMEOUT_SECONDS: String(native.api.idleTimeoutSeconds),
|
|
WORKBENCH_WORKER_BIND_HOST: native.worker.bindHost,
|
|
WORKBENCH_WORKER_PROBE_HOST: native.worker.probeHost,
|
|
WORKBENCH_WORKER_HEALTH_PORT: String(native.worker.healthPort),
|
|
WORKBENCH_WEB_BIND_HOST: native.web.bindHost,
|
|
WORKBENCH_WEB_PROBE_HOST: native.web.probeHost,
|
|
WORKBENCH_WEB_PORT: String(native.web.port),
|
|
WORKBENCH_NATIVE_API_URL: `http://${native.api.probeHost}:${native.api.port}`,
|
|
WORKBENCH_WEB_RUNTIME_CONFIG: JSON.stringify(native.web.runtimeConfig),
|
|
};
|
|
}
|
|
|
|
function providerSecretNameEnvironment(providerSecretNames: Readonly<Record<string, string>>): NodeJS.ProcessEnv {
|
|
return Object.fromEntries(Object.entries(providerSecretNames).map(([profile, secretName]) => {
|
|
const profileKey = profile.toUpperCase().replace(/[^A-Z0-9]+/gu, "_");
|
|
return [`HWLAB_CODE_AGENT_AGENTRUN_${profileKey}_SECRET_NAME`, secretName];
|
|
}));
|
|
}
|
|
|
|
function parsePayload(stdout: string): Record<string, unknown> {
|
|
const parsed = JSON.parse(stdout) as unknown;
|
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("HWLAB Workbench CLI returned invalid JSON");
|
|
return parsed as Record<string, unknown>;
|
|
}
|
|
|
|
function parseApplication(value: string | undefined): Application {
|
|
if (value === "workbench" || value === "hwpod" || value === "caserun") return value;
|
|
throw new Error("native-development application must be workbench, hwpod, or caserun");
|
|
}
|
|
|
|
function parseService(value: string | undefined, application: Application): Service {
|
|
if (value === "api" || value === "web" || (application !== "caserun" && value === "worker")) return value;
|
|
throw new Error(`native-development ${application} service must be ${application === "caserun" ? "api or web" : "api, worker, or web"}`);
|
|
}
|
|
|
|
function parseAction(value: string | undefined): Action {
|
|
if (value === "start" || value === "stop" || value === "restart" || value === "status" || value === "logs") return value;
|
|
throw new Error("native-development workbench action must be start, stop, restart, status, or logs");
|
|
}
|
|
|
|
function requiredOption(args: string[], option: string): string {
|
|
const index = args.indexOf(option);
|
|
const value = index < 0 ? undefined : args[index + 1];
|
|
if (!value || value.startsWith("--")) throw new Error(`${option} requires a value`);
|
|
return value;
|
|
}
|
|
|
|
function withoutOptions(args: string[], options: string[]): string[] {
|
|
const result: string[] = [];
|
|
for (let index = 0; index < args.length; index += 1) {
|
|
if (options.includes(args[index])) {
|
|
index += 1;
|
|
continue;
|
|
}
|
|
result.push(args[index]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function cliTimeoutMs(args: string[]): number {
|
|
const index = args.indexOf("--timeout-ms");
|
|
const requested = index >= 0 ? Number.parseInt(args[index + 1] ?? "", 10) : 0;
|
|
return Number.isSafeInteger(requested) && requested > 0 ? requested + 5_000 : 30_000;
|
|
}
|
|
|
|
function hwlabCaseRunNativeDevelopmentEnvironment(native: NonNullable<HwlabRuntimeNativeDevelopmentSpec["caserun"]>): NodeJS.ProcessEnv {
|
|
return {
|
|
CASERUN_NATIVE_SERVICE_STATE_DIR: native.stateDir,
|
|
CASERUN_PUBLIC_BASE_URL: native.publicExposure.publicBaseUrl,
|
|
CASERUN_PROBE_HOST: native.api.probeHost,
|
|
CASERUN_API_BIND_HOST: native.api.bindHost,
|
|
CASERUN_API_PORT: String(native.api.port),
|
|
CASERUN_WEB_BIND_HOST: native.web.bindHost,
|
|
CASERUN_WEB_PORT: String(native.web.port),
|
|
};
|
|
}
|
|
|
|
export function hwlabHwpodNativeDevelopmentEnvironment(native: NonNullable<HwlabRuntimeNativeDevelopmentSpec["hwpod"]>): NodeJS.ProcessEnv {
|
|
const nodeAuthSource = readEnvSourceFile({
|
|
root: "/root/.unidesk/.state/secrets",
|
|
sourceRef: native.nodeAuth.sourceRef,
|
|
});
|
|
const nodeToken = requiredEnvValue(nodeAuthSource.values, native.nodeAuth.sourceKey, native.nodeAuth.sourceRef);
|
|
const databaseSource = readEnvSourceFile({
|
|
root: "/root/.unidesk/.state/secrets",
|
|
sourceRef: native.specRegistry.database.sourceRef,
|
|
});
|
|
const databaseUrl = requiredEnvValue(databaseSource.values, native.specRegistry.database.sourceKey, native.specRegistry.database.sourceRef);
|
|
const builtInSpecs = native.specRegistry.builtInConfigRefs.map((configRef) => {
|
|
const resolved = resolveConfigRef(configRef, "nativeDevelopment.hwpod.specRegistry.builtInConfigRefs");
|
|
return { configRef, sha256: resolved.sha256, document: resolved.value };
|
|
});
|
|
return {
|
|
HWPOD_NATIVE_SERVICE_STATE_DIR: native.stateDir,
|
|
HWPOD_HEALTH_TIMEOUT_MS: String(native.healthTimeoutMs),
|
|
HWPOD_PUBLIC_BASE_URL: native.publicExposure.publicBaseUrl,
|
|
HWPOD_TEMPORAL_ADDRESS: native.temporal.address,
|
|
HWPOD_TEMPORAL_NAMESPACE: native.temporal.namespace,
|
|
HWPOD_TEMPORAL_TASK_QUEUE: native.temporal.taskQueue,
|
|
HWPOD_ACTIVITY_START_TO_CLOSE_TIMEOUT_MS: String(native.temporal.activity.startToCloseTimeoutMs),
|
|
HWPOD_ACTIVITY_RETRY_INITIAL_INTERVAL_MS: String(native.temporal.activity.retryInitialIntervalMs),
|
|
HWPOD_ACTIVITY_RETRY_MAXIMUM_INTERVAL_MS: String(native.temporal.activity.retryMaximumIntervalMs),
|
|
HWPOD_ACTIVITY_RETRY_MAXIMUM_ATTEMPTS: String(native.temporal.activity.retryMaximumAttempts),
|
|
HWPOD_NODE_WS_TOKEN: nodeToken,
|
|
HWPOD_SPEC_DATABASE_URL: databaseUrl,
|
|
HWPOD_SPEC_DATABASE_SCHEMA: native.specRegistry.database.schema,
|
|
HWPOD_SPEC_DATABASE_TABLE: native.specRegistry.database.table,
|
|
HWPOD_SPEC_DATABASE_CONNECTION_TIMEOUT_MS: String(native.specRegistry.database.connectionTimeoutMs),
|
|
HWPOD_BUILTIN_SPEC_DOCUMENTS_JSON: JSON.stringify(builtInSpecs),
|
|
HWPOD_API_BIND_HOST: native.api.bindHost,
|
|
HWPOD_API_PROBE_HOST: native.api.probeHost,
|
|
HWPOD_API_PORT: String(native.api.port),
|
|
HWPOD_WORKER_BIND_HOST: native.worker.bindHost,
|
|
HWPOD_WORKER_PROBE_HOST: native.worker.probeHost,
|
|
HWPOD_WORKER_HEALTH_PORT: String(native.worker.healthPort),
|
|
HWPOD_WEB_BIND_HOST: native.web.bindHost,
|
|
HWPOD_WEB_PROBE_HOST: native.web.probeHost,
|
|
HWPOD_WEB_PORT: String(native.web.port),
|
|
HWPOD_WEB_RUNTIME_CONFIG: JSON.stringify(native.web.runtimeConfig),
|
|
HWPOD_WEB_ACCESS_PROFILE_JSON: JSON.stringify(native.web.accessProfile),
|
|
HWPOD_NATIVE_API_URL: `http://${native.api.probeHost}:${native.api.port}`,
|
|
HWPOD_NODE_OPS_API_URL: `http://${native.api.probeHost}:${native.api.port}`,
|
|
};
|
|
}
|