@agent-vm/openclaw-gateway 0.0.44 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -58,13 +58,13 @@ function buildOpenClawBootstrapCommand(zone, resolvedSecrets) {
|
|
|
58
58
|
" )",
|
|
59
59
|
"fi"
|
|
60
60
|
];
|
|
61
|
-
return `mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << ENVEOF\n` + environmentLines.join("\n") + `
|
|
61
|
+
return `mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << 'ENVEOF'\n` + environmentLines.join("\n") + `
|
|
62
62
|
ENVEOF
|
|
63
|
-
chmod 644 ${openClawShellEnvFilePath} && cat > ${openClawRuntimeSecretsEnvFilePath} << ENVEOF\n` + secretEnvironmentLines.join("\n") + `
|
|
63
|
+
chmod 644 ${openClawShellEnvFilePath} && cat > ${openClawRuntimeSecretsEnvFilePath} << 'ENVEOF'\n` + secretEnvironmentLines.join("\n") + `
|
|
64
64
|
ENVEOF
|
|
65
|
-
chmod 600 ${openClawRuntimeSecretsEnvFilePath} && cat > ${openClawGatewayAuthEnvFilePath} << ENVEOF\n` + gatewayAuthLines.join("\n") + `
|
|
65
|
+
chmod 600 ${openClawRuntimeSecretsEnvFilePath} && cat > ${openClawGatewayAuthEnvFilePath} << 'ENVEOF'\n` + gatewayAuthLines.join("\n") + `
|
|
66
66
|
ENVEOF
|
|
67
|
-
chmod 600 ${openClawGatewayAuthEnvFilePath} && cat > ${openClawAdminShellEnvFilePath} << ENVEOF\n` + adminShellLines.join("\n") + `
|
|
67
|
+
chmod 600 ${openClawGatewayAuthEnvFilePath} && cat > ${openClawAdminShellEnvFilePath} << 'ENVEOF'\n` + adminShellLines.join("\n") + `
|
|
68
68
|
ENVEOF
|
|
69
69
|
chmod 644 ${openClawAdminShellEnvFilePath} && touch /root/.bashrc && grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && grep -qxF 'source ${openClawAdminShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawAdminShellEnvFilePath}' >> /root/.bashrc && touch /root/.bash_profile && grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile`;
|
|
70
70
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["openClawGatewayTokenSecretRef: OpenClawSecretRef","tcpHosts: Record<string, string>","parsedBaseConfig: unknown","openclawLifecycle: GatewayLifecycle","buildGatewaySessionLabelValue"],"sources":["../src/openclaw-lifecycle.ts"],"sourcesContent":["import { chmod, mkdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {\n\tBuildGatewayVmSpecOptions,\n\tGatewayLifecycle,\n\tGatewayProcessSpec,\n\tGatewayZoneConfig,\n\tGatewayVmSpec,\n} from '@agent-vm/gateway-interface';\nimport {\n\tbuildGatewaySessionLabel as buildGatewaySessionLabelValue,\n\tsplitResolvedGatewaySecrets,\n} from '@agent-vm/gateway-interface';\nimport {\n\ttype SecretRef,\n\ttype SecretResolver,\n\twriteFileAtomically,\n} from '@agent-vm/gondolin-adapter';\n\nconst effectiveOpenClawConfigFileName = 'effective-openclaw.json';\nconst effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;\nconst openClawStateDirVmPath = '/home/openclaw/.openclaw/state';\nconst openClawCacheDirVmPath = '/home/openclaw/.openclaw/cache';\nconst openClawZoneFilesDirVmPath = '/zone';\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\nconst openClawAdminShellEnvFilePath = '/etc/profile.d/openclaw-admin.sh';\nconst openClawRuntimeSecretsEnvFilePath = '/run/openclaw/secrets.env';\nconst openClawGatewayAuthEnvFilePath = '/run/openclaw/gateway-auth.env';\nconst openClawGatewayTokenEnvVar = 'OPENCLAW_GATEWAY_TOKEN';\n\ninterface OpenClawSecretRef {\n\treadonly id: string;\n\treadonly provider: string;\n\treadonly source: 'env';\n}\n\nconst openClawGatewayTokenSecretRef: OpenClawSecretRef = {\n\tid: openClawGatewayTokenEnvVar,\n\tprovider: 'default',\n\tsource: 'env',\n};\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction buildGatewayTcpHosts(\n\tzone: GatewayZoneConfig,\n\tcontrollerPort: number,\n\ttcpPool: { readonly basePort: number; readonly size: number },\n): Record<string, string> {\n\tconst tcpHosts: Record<string, string> = {\n\t\t'controller.vm.host:18800': `127.0.0.1:${controllerPort}`,\n\t};\n\n\tfor (let slot = 0; slot < tcpPool.size; slot += 1) {\n\t\ttcpHosts[`tool-${slot}.vm.host:22`] = `127.0.0.1:${tcpPool.basePort + slot}`;\n\t}\n\n\tfor (const websocketHost of zone.websocketBypass) {\n\t\ttcpHosts[websocketHost] = websocketHost;\n\t}\n\n\treturn tcpHosts;\n}\n\nfunction buildOpenClawBootstrapCommand(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n): string {\n\tconst { environmentSecrets } = splitResolvedGatewaySecrets(zone, resolvedSecrets);\n\tconst environmentLines = [\n\t\t'export OPENCLAW_HOME=/home/openclaw',\n\t\t`export OPENCLAW_CONFIG_PATH=${effectiveOpenClawConfigVmPath}`,\n\t\t`export OPENCLAW_STATE_DIR=${openClawStateDirVmPath}`,\n\t\t'export PNPM_HOME=/pnpm',\n\t\t'export PATH=/pnpm:$PATH',\n\t\t'export TMPDIR=/work/tmp',\n\t\t'export TMP=/work/tmp',\n\t\t'export TEMP=/work/tmp',\n\t\t'export npm_config_cache=/work/cache/npm',\n\t\t'export pnpm_config_store_dir=/work/cache/pnpm/store',\n\t\t'export PIP_CACHE_DIR=/work/cache/pip',\n\t\t'export UV_CACHE_DIR=/work/cache/uv',\n\t\t'export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt',\n\t];\n\tconst secretEnvironmentLines = Object.entries(environmentSecrets).map(\n\t\t([secretName, secretValue]) => `export ${secretName}=${shellQuote(secretValue)}`,\n\t);\n\tconst gatewayToken = resolvedSecrets[openClawGatewayTokenEnvVar];\n\tconst gatewayAuthLines =\n\t\ttypeof gatewayToken === 'string'\n\t\t\t? [`export ${openClawGatewayTokenEnvVar}=${shellQuote(gatewayToken)}`]\n\t\t\t: [];\n\tconst adminShellLines = [\n\t\t'if [ \"$(id -u)\" = \"0\" ]; then',\n\t\t'\\topenclaw() (',\n\t\t'\\t\\tset -a',\n\t\t`\\t\\t[ -r ${openClawGatewayAuthEnvFilePath} ] && . ${openClawGatewayAuthEnvFilePath}`,\n\t\t'\\t\\tset +a',\n\t\t'\\t\\tcommand openclaw \"$@\"',\n\t\t'\\t)',\n\t\t'fi',\n\t];\n\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << ENVEOF\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\t`cat > ${openClawRuntimeSecretsEnvFilePath} << ENVEOF\\n` +\n\t\tsecretEnvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 600 ${openClawRuntimeSecretsEnvFilePath} && ` +\n\t\t`cat > ${openClawGatewayAuthEnvFilePath} << ENVEOF\\n` +\n\t\tgatewayAuthLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 600 ${openClawGatewayAuthEnvFilePath} && ` +\n\t\t`cat > ${openClawAdminShellEnvFilePath} << ENVEOF\\n` +\n\t\tadminShellLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawAdminShellEnvFilePath} && ` +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t`grep -qxF 'source ${openClawAdminShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawAdminShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t'touch /root/.bash_profile && ' +\n\t\t\"grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile\"\n\t);\n}\n\nfunction getEffectiveOpenClawConfigHostPath(zone: GatewayZoneConfig): string {\n\treturn path.join(zone.gateway.stateDir, effectiveOpenClawConfigFileName);\n}\n\nfunction shellQuote(value: string): string {\n\treturn `'${value.replace(/'/gu, `'\\\\''`)}'`;\n}\n\ntype SourceAwareSecretReference =\n\t| {\n\t\t\treadonly source: 'environment';\n\t\t\treadonly envVar: string;\n\t }\n\t| {\n\t\t\treadonly source: '1password';\n\t\t\treadonly ref: string;\n\t };\n\nfunction isSourceAwareSecretReference(value: unknown): value is SourceAwareSecretReference {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn false;\n\t}\n\n\tif (!('source' in value) || typeof value.source !== 'string') {\n\t\treturn false;\n\t}\n\n\tif (value.source === 'environment') {\n\t\treturn 'envVar' in value && typeof value.envVar === 'string';\n\t}\n\n\tif (value.source === '1password') {\n\t\treturn 'ref' in value && typeof value.ref === 'string';\n\t}\n\n\treturn false;\n}\n\nfunction toSecretRef(secret: SourceAwareSecretReference): SecretRef {\n\treturn secret.source === 'environment'\n\t\t? {\n\t\t\t\tsource: 'environment',\n\t\t\t\tref: secret.envVar,\n\t\t\t}\n\t\t: {\n\t\t\t\tsource: '1password',\n\t\t\t\tref: secret.ref,\n\t\t\t};\n}\n\nfunction describeSecretReference(secret: SourceAwareSecretReference): string {\n\treturn secret.source === 'environment' ? secret.envVar : secret.ref;\n}\n\nfunction buildEffectiveSecretsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingSecretsConfig = isObjectRecord(parsedBaseConfig.secrets)\n\t\t? parsedBaseConfig.secrets\n\t\t: {};\n\tconst existingProvidersConfig = isObjectRecord(existingSecretsConfig.providers)\n\t\t? existingSecretsConfig.providers\n\t\t: {};\n\n\treturn {\n\t\t...existingSecretsConfig,\n\t\tproviders: {\n\t\t\t...existingProvidersConfig,\n\t\t\tdefault: {\n\t\t\t\tsource: 'env',\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function writeAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst authProfilesByAgent = {\n\t\t...(zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {}),\n\t\t...(zone.gateway.type === 'openclaw' ? (zone.gateway.authProfilesByAgent ?? {}) : {}),\n\t};\n\n\tconst writeResults = await Promise.allSettled(\n\t\tObject.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {\n\t\t\tif (!isSourceAwareSecretReference(authProfilesSecretCandidate)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst authProfilesSecret = authProfilesSecretCandidate;\n\n\t\t\ttry {\n\t\t\t\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', agentId, 'agent');\n\t\t\t\tawait mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\t\t\tawait chmod(authProfilesDirectory, 0o700);\n\t\t\t\tconst authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));\n\t\t\t\tawait writeFileAtomically(\n\t\t\t\t\tpath.join(authProfilesDirectory, 'auth-profiles.json'),\n\t\t\t\t\tauthProfiles,\n\t\t\t\t\t{ mode: 0o600 },\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to write OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`,\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}),\n\t);\n\tconst writeErrors = writeResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (writeErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\twriteErrors,\n\t\t\t`Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n}\n\nasync function writeEffectiveOpenClawConfig(zone: GatewayZoneConfig): Promise<void> {\n\tconst gatewayTokenSecret = zone.secrets.OPENCLAW_GATEWAY_TOKEN;\n\tif (!gatewayTokenSecret) {\n\t\tthrow new Error(\n\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing. Add an explicit 1Password or environment reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t);\n\t}\n\tif (!isSourceAwareSecretReference(gatewayTokenSecret)) {\n\t\tthrow new Error(`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' has an invalid shape.`);\n\t}\n\n\ttry {\n\t\tif (gatewayTokenSecret.source === '1password' && !gatewayTokenSecret.ref) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing 'ref'. Add an explicit 1Password reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t\t);\n\t\t}\n\t\tif (gatewayTokenSecret.source === 'environment' && !gatewayTokenSecret.envVar) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing 'envVar'. Add an explicit environment variable name.`,\n\t\t\t);\n\t\t}\n\t\tconst rawBaseConfig = await readFile(zone.gateway.config, 'utf8');\n\t\tconst parsedBaseConfig: unknown = JSON.parse(rawBaseConfig);\n\t\tif (!isObjectRecord(parsedBaseConfig)) {\n\t\t\tthrow new Error(`OpenClaw config at '${zone.gateway.config}' must be a JSON object.`);\n\t\t}\n\t\tconst config = isObjectRecord(parsedBaseConfig.gateway) ? parsedBaseConfig.gateway : {};\n\t\tconst existingAuthConfig = isObjectRecord(config.auth) ? config.auth : {};\n\t\tconst effectiveConfig = {\n\t\t\t...parsedBaseConfig,\n\t\t\tgateway: {\n\t\t\t\t...config,\n\t\t\t\tauth: {\n\t\t\t\t\t...existingAuthConfig,\n\t\t\t\t\tmode: 'token',\n\t\t\t\t\ttoken: openClawGatewayTokenSecretRef,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeta: {\n\t\t\t\t...(isObjectRecord(parsedBaseConfig.meta) ? parsedBaseConfig.meta : {}),\n\t\t\t\tlastTouchedAt: new Date().toISOString(),\n\t\t\t\tlastTouchedVersion: 'agent-vm',\n\t\t\t},\n\t\t\tsecrets: buildEffectiveSecretsConfig(parsedBaseConfig),\n\t\t};\n\t\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\t\tawait mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait chmod(zone.gateway.stateDir, 0o700);\n\t\tawait writeFileAtomically(\n\t\t\teffectiveConfigPath,\n\t\t\t`${JSON.stringify(effectiveConfig, null, 2)}\\n`,\n\t\t\t{ mode: 0o600 },\n\t\t);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`Failed to write effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nexport const openclawLifecycle: GatewayLifecycle = {\n\tauthConfig: {\n\t\tlistProvidersCommand: 'openclaw models auth list --format plain 2>/dev/null || echo \"\"',\n\t\tbuildLoginCommand: (\n\t\t\tprovider: string,\n\t\t\toptions: { readonly deviceCode?: boolean; readonly setDefault?: boolean } = {},\n\t\t): string =>\n\t\t\t[\n\t\t\t\t`openclaw models auth login --provider ${shellQuote(provider)}`,\n\t\t\t\t...(options.deviceCode === true ? ['--device-code'] : []),\n\t\t\t\t...(options.setDefault === true ? ['--set-default'] : []),\n\t\t\t].join(' '),\n\t},\n\n\tbuildVmSpec({\n\t\tcontrollerPort,\n\t\tgatewayCacheDir,\n\t\tprojectNamespace,\n\t\tresolvedSecrets,\n\t\ttcpPool,\n\t\tzone,\n\t}: BuildGatewayVmSpecOptions): GatewayVmSpec {\n\t\tif (zone.gateway.type !== 'openclaw') {\n\t\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t\t}\n\t\tconst configDirectory = path.dirname(path.resolve(zone.gateway.config));\n\t\tconst { environmentSecrets, mediatedSecrets } = splitResolvedGatewaySecrets(\n\t\t\tzone,\n\t\t\tresolvedSecrets,\n\t\t);\n\n\t\treturn {\n\t\t\tallowedHosts: [...zone.allowedHosts],\n\t\t\tenvironment: {\n\t\t\t\tHOME: '/home/openclaw',\n\t\t\t\tNODE_EXTRA_CA_CERTS: '/run/gondolin/ca-certificates.crt',\n\t\t\t\tOPENCLAW_CONFIG_PATH: effectiveOpenClawConfigVmPath,\n\t\t\t\tOPENCLAW_HOME: '/home/openclaw',\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\tPATH: `/pnpm:${process.env.PATH ?? ''}`,\n\t\t\t\tPIP_CACHE_DIR: '/work/cache/pip',\n\t\t\t\tPNPM_HOME: '/pnpm',\n\t\t\t\tTEMP: '/work/tmp',\n\t\t\t\tTMP: '/work/tmp',\n\t\t\t\tTMPDIR: '/work/tmp',\n\t\t\t\tUV_CACHE_DIR: '/work/cache/uv',\n\t\t\t\tnpm_config_cache: '/work/cache/npm',\n\t\t\t\tpnpm_config_store_dir: '/work/cache/pnpm/store',\n\t\t\t\t...environmentSecrets,\n\t\t\t},\n\t\t\tmediatedSecrets,\n\t\t\trootfsMode: 'cow',\n\t\t\tsessionLabel: buildGatewaySessionLabelValue(projectNamespace, zone.id),\n\t\t\ttcpHosts: buildGatewayTcpHosts(zone, controllerPort, tcpPool),\n\t\t\tvfsMounts: {\n\t\t\t\t'/home/openclaw/.openclaw/config': {\n\t\t\t\t\thostPath: configDirectory,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawCacheDirVmPath]: {\n\t\t\t\t\thostPath: gatewayCacheDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t'/home/openclaw/.openclaw/state': {\n\t\t\t\t\thostPath: zone.gateway.stateDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawZoneFilesDirVmPath]: {\n\t\t\t\t\thostPath: zone.gateway.zoneFilesDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n\n\tbuildProcessSpec(\n\t\tzone: GatewayZoneConfig,\n\t\tresolvedSecrets: Record<string, string>,\n\t): GatewayProcessSpec {\n\t\treturn {\n\t\t\tbootstrapCommand: buildOpenClawBootstrapCommand(zone, resolvedSecrets),\n\t\t\tstartCommand: `set -a && . ${openClawRuntimeSecretsEnvFilePath} && set +a && cd /home/openclaw && nohup openclaw gateway --port 18789 > /tmp/openclaw.log 2>&1 &`,\n\t\t\thealthCheck: {\n\t\t\t\ttype: 'http',\n\t\t\t\tport: 18789,\n\t\t\t\tpath: '/readyz',\n\t\t\t},\n\t\t\tguestListenPort: 18789,\n\t\t\tlogPath: '/tmp/openclaw.log',\n\t\t};\n\t},\n\n\tasync prepareHostState(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void> {\n\t\tawait writeEffectiveOpenClawConfig(zone);\n\t\tawait writeAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n};\n"],"mappings":";;;;;;AAoBA,MAAM,kCAAkC;AACxC,MAAM,gCAAgC,kCAAkC;AACxE,MAAM,yBAAyB;AAC/B,MAAM,yBAAyB;AAC/B,MAAM,6BAA6B;AACnC,MAAM,2BAA2B;AACjC,MAAM,gCAAgC;AACtC,MAAM,oCAAoC;AAC1C,MAAM,iCAAiC;AACvC,MAAM,6BAA6B;AAQnC,MAAMA,gCAAmD;CACxD,IAAI;CACJ,UAAU;CACV,QAAQ;CACR;AAED,SAAS,eAAe,OAAkD;AACzE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,qBACR,MACA,gBACA,SACyB;CACzB,MAAMC,WAAmC,EACxC,4BAA4B,aAAa,kBACzC;AAED,MAAK,IAAI,OAAO,GAAG,OAAO,QAAQ,MAAM,QAAQ,EAC/C,UAAS,QAAQ,KAAK,gBAAgB,aAAa,QAAQ,WAAW;AAGvE,MAAK,MAAM,iBAAiB,KAAK,gBAChC,UAAS,iBAAiB;AAG3B,QAAO;;AAGR,SAAS,8BACR,MACA,iBACS;CACT,MAAM,EAAE,uBAAuB,4BAA4B,MAAM,gBAAgB;CACjF,MAAM,mBAAmB;EACxB;EACA,+BAA+B;EAC/B,6BAA6B;EAC7B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,MAAM,yBAAyB,OAAO,QAAQ,mBAAmB,CAAC,KAChE,CAAC,YAAY,iBAAiB,UAAU,WAAW,GAAG,WAAW,YAAY,GAC9E;CACD,MAAM,eAAe,gBAAgB;CACrC,MAAM,mBACL,OAAO,iBAAiB,WACrB,CAAC,UAAU,2BAA2B,GAAG,WAAW,aAAa,GAAG,GACpE,EAAE;CACN,MAAM,kBAAkB;EACvB;EACA;EACA;EACA,YAAY,+BAA+B,UAAU;EACrD;EACA;EACA;EACA;EACA;AAED,QACC,4KAA4K,yBAAyB,gBACrM,iBAAiB,KAAK,KAAK,GAC3B;;YACa,yBAAyB,YAC7B,kCAAkC,gBAC3C,uBAAuB,KAAK,KAAK,GACjC;;YACa,kCAAkC,YACtC,+BAA+B,gBACxC,iBAAiB,KAAK,KAAK,GAC3B;;YACa,+BAA+B,YACnC,8BAA8B,gBACvC,gBAAgB,KAAK,KAAK,GAC1B;;YACa,8BAA8B,+CAEtB,yBAAyB,kCAAkC,yBAAyB,0CACpF,8BAA8B,kCAAkC,8BAA8B;;AAMrH,SAAS,mCAAmC,MAAiC;AAC5E,QAAO,KAAK,KAAK,KAAK,QAAQ,UAAU,gCAAgC;;AAGzE,SAAS,WAAW,OAAuB;AAC1C,QAAO,IAAI,MAAM,QAAQ,OAAO,QAAQ,CAAC;;AAa1C,SAAS,6BAA6B,OAAqD;AAC1F,KAAI,OAAO,UAAU,YAAY,UAAU,KAC1C,QAAO;AAGR,KAAI,EAAE,YAAY,UAAU,OAAO,MAAM,WAAW,SACnD,QAAO;AAGR,KAAI,MAAM,WAAW,cACpB,QAAO,YAAY,SAAS,OAAO,MAAM,WAAW;AAGrD,KAAI,MAAM,WAAW,YACpB,QAAO,SAAS,SAAS,OAAO,MAAM,QAAQ;AAG/C,QAAO;;AAGR,SAAS,YAAY,QAA+C;AACnE,QAAO,OAAO,WAAW,gBACtB;EACA,QAAQ;EACR,KAAK,OAAO;EACZ,GACA;EACA,QAAQ;EACR,KAAK,OAAO;EACZ;;AAGJ,SAAS,wBAAwB,QAA4C;AAC5E,QAAO,OAAO,WAAW,gBAAgB,OAAO,SAAS,OAAO;;AAGjE,SAAS,4BACR,kBAC0B;CAC1B,MAAM,wBAAwB,eAAe,iBAAiB,QAAQ,GACnE,iBAAiB,UACjB,EAAE;CACL,MAAM,0BAA0B,eAAe,sBAAsB,UAAU,GAC5E,sBAAsB,YACtB,EAAE;AAEL,QAAO;EACN,GAAG;EACH,WAAW;GACV,GAAG;GACH,SAAS,EACR,QAAQ,OACR;GACD;EACD;;AAGF,eAAe,8BACd,MACA,gBACgB;CAChB,MAAM,sBAAsB;EAC3B,GAAI,KAAK,QAAQ,kBAAkB,EAAE,MAAM,KAAK,QAAQ,iBAAiB,GAAG,EAAE;EAC9E,GAAI,KAAK,QAAQ,SAAS,aAAc,KAAK,QAAQ,uBAAuB,EAAE,GAAI,EAAE;EACpF;CA8BD,MAAM,eA5Be,MAAM,QAAQ,WAClC,OAAO,QAAQ,oBAAoB,CAAC,IAAI,OAAO,CAAC,SAAS,iCAAiC;AACzF,MAAI,CAAC,6BAA6B,4BAA4B,CAC7D,OAAM,IAAI,MACT,SAAS,KAAK,GAAG,iDAAiD,QAAQ,IAC1E;EAEF,MAAM,qBAAqB;AAE3B,MAAI;GACH,MAAM,wBAAwB,KAAK,KAAK,KAAK,QAAQ,UAAU,UAAU,SAAS,QAAQ;AAC1F,SAAM,MAAM,uBAAuB;IAAE,WAAW;IAAM,MAAM;IAAO,CAAC;AACpE,SAAM,MAAM,uBAAuB,IAAM;GACzC,MAAM,eAAe,MAAM,eAAe,QAAQ,YAAY,mBAAmB,CAAC;AAClF,SAAM,oBACL,KAAK,KAAK,uBAAuB,qBAAqB,EACtD,cACA,EAAE,MAAM,KAAO,CACf;WACO,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,SAAM,IAAI,MACT,oDAAoD,KAAK,GAAG,WAAW,QAAQ,UAAU,wBAAwB,mBAAmB,CAAC,KAAK,WAC1I,EAAE,OAAO,OAAO,CAChB;;GAED,CACF,EAEC,QAAQ,WAA4C,OAAO,WAAW,WAAW,CACjF,KAAK,WACL,OAAO,kBAAkB,QAAQ,OAAO,SAAS,IAAI,MAAM,OAAO,OAAO,OAAO,CAAC,CACjF;AACF,KAAI,YAAY,SAAS,EACxB,OAAM,IAAI,eACT,aACA,mBAAmB,OAAO,YAAY,OAAO,CAAC,2CAA2C,KAAK,GAAG,IACjG;;AAIH,eAAe,6BAA6B,MAAwC;CACnF,MAAM,qBAAqB,KAAK,QAAQ;AACxC,KAAI,CAAC,mBACJ,OAAM,IAAI,MACT,SAAS,KAAK,GAAG,0HAA0H,KAAK,GAAG,0BACnJ;AAEF,KAAI,CAAC,6BAA6B,mBAAmB,CACpD,OAAM,IAAI,MAAM,SAAS,KAAK,GAAG,yDAAyD;AAG3F,KAAI;AACH,MAAI,mBAAmB,WAAW,eAAe,CAAC,mBAAmB,IACpE,OAAM,IAAI,MACT,SAAS,KAAK,GAAG,iHAAiH,KAAK,GAAG,0BAC1I;AAEF,MAAI,mBAAmB,WAAW,iBAAiB,CAAC,mBAAmB,OACtE,OAAM,IAAI,MACT,SAAS,KAAK,GAAG,mGACjB;EAEF,MAAM,gBAAgB,MAAM,SAAS,KAAK,QAAQ,QAAQ,OAAO;EACjE,MAAMC,mBAA4B,KAAK,MAAM,cAAc;AAC3D,MAAI,CAAC,eAAe,iBAAiB,CACpC,OAAM,IAAI,MAAM,uBAAuB,KAAK,QAAQ,OAAO,0BAA0B;EAEtF,MAAM,SAAS,eAAe,iBAAiB,QAAQ,GAAG,iBAAiB,UAAU,EAAE;EACvF,MAAM,qBAAqB,eAAe,OAAO,KAAK,GAAG,OAAO,OAAO,EAAE;EACzE,MAAM,kBAAkB;GACvB,GAAG;GACH,SAAS;IACR,GAAG;IACH,MAAM;KACL,GAAG;KACH,MAAM;KACN,OAAO;KACP;IACD;GACD,MAAM;IACL,GAAI,eAAe,iBAAiB,KAAK,GAAG,iBAAiB,OAAO,EAAE;IACtE,gCAAe,IAAI,MAAM,EAAC,aAAa;IACvC,oBAAoB;IACpB;GACD,SAAS,4BAA4B,iBAAiB;GACtD;EACD,MAAM,sBAAsB,mCAAmC,KAAK;AACpE,QAAM,MAAM,KAAK,QAAQ,UAAU;GAAE,WAAW;GAAM,MAAM;GAAO,CAAC;AACpE,QAAM,MAAM,KAAK,QAAQ,UAAU,IAAM;AACzC,QAAM,oBACL,qBACA,GAAG,KAAK,UAAU,iBAAiB,MAAM,EAAE,CAAC,KAC5C,EAAE,MAAM,KAAO,CACf;UACO,OAAO;EACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAM,IAAI,MACT,uDAAuD,KAAK,GAAG,UAAU,KAAK,QAAQ,OAAO,kBAAkB,wBAAwB,mBAAmB,CAAC,KAAK,WAChK,EAAE,OAAO,OAAO,CAChB;;;AAIH,MAAaC,oBAAsC;CAClD,YAAY;EACX,sBAAsB;EACtB,oBACC,UACA,UAA4E,EAAE,KAE9E;GACC,yCAAyC,WAAW,SAAS;GAC7D,GAAI,QAAQ,eAAe,OAAO,CAAC,gBAAgB,GAAG,EAAE;GACxD,GAAI,QAAQ,eAAe,OAAO,CAAC,gBAAgB,GAAG,EAAE;GACxD,CAAC,KAAK,IAAI;EACZ;CAED,YAAY,EACX,gBACA,iBACA,kBACA,iBACA,SACA,QAC4C;AAC5C,MAAI,KAAK,QAAQ,SAAS,WACzB,OAAM,IAAI,MAAM,iDAAiD,KAAK,QAAQ,KAAK,IAAI;EAExF,MAAM,kBAAkB,KAAK,QAAQ,KAAK,QAAQ,KAAK,QAAQ,OAAO,CAAC;EACvE,MAAM,EAAE,oBAAoB,oBAAoB,4BAC/C,MACA,gBACA;AAED,SAAO;GACN,cAAc,CAAC,GAAG,KAAK,aAAa;GACpC,aAAa;IACZ,MAAM;IACN,qBAAqB;IACrB,sBAAsB;IACtB,eAAe;IACf,oBAAoB;IACpB,MAAM,SAAS,QAAQ,IAAI,QAAQ;IACnC,eAAe;IACf,WAAW;IACX,MAAM;IACN,KAAK;IACL,QAAQ;IACR,cAAc;IACd,kBAAkB;IAClB,uBAAuB;IACvB,GAAG;IACH;GACD;GACA,YAAY;GACZ,cAAcC,yBAA8B,kBAAkB,KAAK,GAAG;GACtE,UAAU,qBAAqB,MAAM,gBAAgB,QAAQ;GAC7D,WAAW;IACV,mCAAmC;KAClC,UAAU;KACV,MAAM;KACN;KACA,yBAAyB;KACzB,UAAU;KACV,MAAM;KACN;IACD,kCAAkC;KACjC,UAAU,KAAK,QAAQ;KACvB,MAAM;KACN;KACA,6BAA6B;KAC7B,UAAU,KAAK,QAAQ;KACvB,MAAM;KACN;IACD;GACD;;CAGF,iBACC,MACA,iBACqB;AACrB,SAAO;GACN,kBAAkB,8BAA8B,MAAM,gBAAgB;GACtE,cAAc,eAAe,kCAAkC;GAC/D,aAAa;IACZ,MAAM;IACN,MAAM;IACN,MAAM;IACN;GACD,iBAAiB;GACjB,SAAS;GACT;;CAGF,MAAM,iBAAiB,MAAyB,gBAA+C;AAC9F,QAAM,6BAA6B,KAAK;AACxC,QAAM,8BAA8B,MAAM,eAAe;;CAE1D"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["openClawGatewayTokenSecretRef: OpenClawSecretRef","tcpHosts: Record<string, string>","parsedBaseConfig: unknown","openclawLifecycle: GatewayLifecycle","buildGatewaySessionLabelValue"],"sources":["../src/openclaw-lifecycle.ts"],"sourcesContent":["import { chmod, mkdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {\n\tBuildGatewayVmSpecOptions,\n\tGatewayLifecycle,\n\tGatewayProcessSpec,\n\tGatewayZoneConfig,\n\tGatewayVmSpec,\n} from '@agent-vm/gateway-interface';\nimport {\n\tbuildGatewaySessionLabel as buildGatewaySessionLabelValue,\n\tsplitResolvedGatewaySecrets,\n} from '@agent-vm/gateway-interface';\nimport {\n\ttype SecretRef,\n\ttype SecretResolver,\n\twriteFileAtomically,\n} from '@agent-vm/gondolin-adapter';\n\nconst effectiveOpenClawConfigFileName = 'effective-openclaw.json';\nconst effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;\nconst openClawStateDirVmPath = '/home/openclaw/.openclaw/state';\nconst openClawCacheDirVmPath = '/home/openclaw/.openclaw/cache';\nconst openClawZoneFilesDirVmPath = '/zone';\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\nconst openClawAdminShellEnvFilePath = '/etc/profile.d/openclaw-admin.sh';\nconst openClawRuntimeSecretsEnvFilePath = '/run/openclaw/secrets.env';\nconst openClawGatewayAuthEnvFilePath = '/run/openclaw/gateway-auth.env';\nconst openClawGatewayTokenEnvVar = 'OPENCLAW_GATEWAY_TOKEN';\n\ninterface OpenClawSecretRef {\n\treadonly id: string;\n\treadonly provider: string;\n\treadonly source: 'env';\n}\n\nconst openClawGatewayTokenSecretRef: OpenClawSecretRef = {\n\tid: openClawGatewayTokenEnvVar,\n\tprovider: 'default',\n\tsource: 'env',\n};\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction buildGatewayTcpHosts(\n\tzone: GatewayZoneConfig,\n\tcontrollerPort: number,\n\ttcpPool: { readonly basePort: number; readonly size: number },\n): Record<string, string> {\n\tconst tcpHosts: Record<string, string> = {\n\t\t'controller.vm.host:18800': `127.0.0.1:${controllerPort}`,\n\t};\n\n\tfor (let slot = 0; slot < tcpPool.size; slot += 1) {\n\t\ttcpHosts[`tool-${slot}.vm.host:22`] = `127.0.0.1:${tcpPool.basePort + slot}`;\n\t}\n\n\tfor (const websocketHost of zone.websocketBypass) {\n\t\ttcpHosts[websocketHost] = websocketHost;\n\t}\n\n\treturn tcpHosts;\n}\n\nfunction buildOpenClawBootstrapCommand(\n\tzone: GatewayZoneConfig,\n\tresolvedSecrets: Record<string, string>,\n): string {\n\tconst { environmentSecrets } = splitResolvedGatewaySecrets(zone, resolvedSecrets);\n\tconst environmentLines = [\n\t\t'export OPENCLAW_HOME=/home/openclaw',\n\t\t`export OPENCLAW_CONFIG_PATH=${effectiveOpenClawConfigVmPath}`,\n\t\t`export OPENCLAW_STATE_DIR=${openClawStateDirVmPath}`,\n\t\t'export PNPM_HOME=/pnpm',\n\t\t'export PATH=/pnpm:$PATH',\n\t\t'export TMPDIR=/work/tmp',\n\t\t'export TMP=/work/tmp',\n\t\t'export TEMP=/work/tmp',\n\t\t'export npm_config_cache=/work/cache/npm',\n\t\t'export pnpm_config_store_dir=/work/cache/pnpm/store',\n\t\t'export PIP_CACHE_DIR=/work/cache/pip',\n\t\t'export UV_CACHE_DIR=/work/cache/uv',\n\t\t'export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt',\n\t];\n\tconst secretEnvironmentLines = Object.entries(environmentSecrets).map(\n\t\t([secretName, secretValue]) => `export ${secretName}=${shellQuote(secretValue)}`,\n\t);\n\tconst gatewayToken = resolvedSecrets[openClawGatewayTokenEnvVar];\n\tconst gatewayAuthLines =\n\t\ttypeof gatewayToken === 'string'\n\t\t\t? [`export ${openClawGatewayTokenEnvVar}=${shellQuote(gatewayToken)}`]\n\t\t\t: [];\n\tconst adminShellLines = [\n\t\t'if [ \"$(id -u)\" = \"0\" ]; then',\n\t\t'\\topenclaw() (',\n\t\t'\\t\\tset -a',\n\t\t`\\t\\t[ -r ${openClawGatewayAuthEnvFilePath} ] && . ${openClawGatewayAuthEnvFilePath}`,\n\t\t'\\t\\tset +a',\n\t\t'\\t\\tcommand openclaw \"$@\"',\n\t\t'\\t)',\n\t\t'fi',\n\t];\n\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d /run/openclaw /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && chown -R openclaw:openclaw /work && cat > ${openClawShellEnvFilePath} << 'ENVEOF'\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\t`cat > ${openClawRuntimeSecretsEnvFilePath} << 'ENVEOF'\\n` +\n\t\tsecretEnvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 600 ${openClawRuntimeSecretsEnvFilePath} && ` +\n\t\t`cat > ${openClawGatewayAuthEnvFilePath} << 'ENVEOF'\\n` +\n\t\tgatewayAuthLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 600 ${openClawGatewayAuthEnvFilePath} && ` +\n\t\t`cat > ${openClawAdminShellEnvFilePath} << 'ENVEOF'\\n` +\n\t\tadminShellLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawAdminShellEnvFilePath} && ` +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t`grep -qxF 'source ${openClawAdminShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawAdminShellEnvFilePath}' >> /root/.bashrc && ` +\n\t\t'touch /root/.bash_profile && ' +\n\t\t\"grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile\"\n\t);\n}\n\nfunction getEffectiveOpenClawConfigHostPath(zone: GatewayZoneConfig): string {\n\treturn path.join(zone.gateway.stateDir, effectiveOpenClawConfigFileName);\n}\n\nfunction shellQuote(value: string): string {\n\treturn `'${value.replace(/'/gu, `'\\\\''`)}'`;\n}\n\ntype SourceAwareSecretReference =\n\t| {\n\t\t\treadonly source: 'environment';\n\t\t\treadonly envVar: string;\n\t }\n\t| {\n\t\t\treadonly source: '1password';\n\t\t\treadonly ref: string;\n\t };\n\nfunction isSourceAwareSecretReference(value: unknown): value is SourceAwareSecretReference {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn false;\n\t}\n\n\tif (!('source' in value) || typeof value.source !== 'string') {\n\t\treturn false;\n\t}\n\n\tif (value.source === 'environment') {\n\t\treturn 'envVar' in value && typeof value.envVar === 'string';\n\t}\n\n\tif (value.source === '1password') {\n\t\treturn 'ref' in value && typeof value.ref === 'string';\n\t}\n\n\treturn false;\n}\n\nfunction toSecretRef(secret: SourceAwareSecretReference): SecretRef {\n\treturn secret.source === 'environment'\n\t\t? {\n\t\t\t\tsource: 'environment',\n\t\t\t\tref: secret.envVar,\n\t\t\t}\n\t\t: {\n\t\t\t\tsource: '1password',\n\t\t\t\tref: secret.ref,\n\t\t\t};\n}\n\nfunction describeSecretReference(secret: SourceAwareSecretReference): string {\n\treturn secret.source === 'environment' ? secret.envVar : secret.ref;\n}\n\nfunction buildEffectiveSecretsConfig(\n\tparsedBaseConfig: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst existingSecretsConfig = isObjectRecord(parsedBaseConfig.secrets)\n\t\t? parsedBaseConfig.secrets\n\t\t: {};\n\tconst existingProvidersConfig = isObjectRecord(existingSecretsConfig.providers)\n\t\t? existingSecretsConfig.providers\n\t\t: {};\n\n\treturn {\n\t\t...existingSecretsConfig,\n\t\tproviders: {\n\t\t\t...existingProvidersConfig,\n\t\t\tdefault: {\n\t\t\t\tsource: 'env',\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function writeAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst authProfilesByAgent = {\n\t\t...(zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {}),\n\t\t...(zone.gateway.type === 'openclaw' ? (zone.gateway.authProfilesByAgent ?? {}) : {}),\n\t};\n\n\tconst writeResults = await Promise.allSettled(\n\t\tObject.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {\n\t\t\tif (!isSourceAwareSecretReference(authProfilesSecretCandidate)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst authProfilesSecret = authProfilesSecretCandidate;\n\n\t\t\ttry {\n\t\t\t\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', agentId, 'agent');\n\t\t\t\tawait mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\t\t\tawait chmod(authProfilesDirectory, 0o700);\n\t\t\t\tconst authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));\n\t\t\t\tawait writeFileAtomically(\n\t\t\t\t\tpath.join(authProfilesDirectory, 'auth-profiles.json'),\n\t\t\t\t\tauthProfiles,\n\t\t\t\t\t{ mode: 0o600 },\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to write OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`,\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}),\n\t);\n\tconst writeErrors = writeResults\n\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t.map((result) =>\n\t\t\tresult.reason instanceof Error ? result.reason : new Error(String(result.reason)),\n\t\t);\n\tif (writeErrors.length > 0) {\n\t\tthrow new AggregateError(\n\t\t\twriteErrors,\n\t\t\t`Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`,\n\t\t);\n\t}\n}\n\nasync function writeEffectiveOpenClawConfig(zone: GatewayZoneConfig): Promise<void> {\n\tconst gatewayTokenSecret = zone.secrets.OPENCLAW_GATEWAY_TOKEN;\n\tif (!gatewayTokenSecret) {\n\t\tthrow new Error(\n\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing. Add an explicit 1Password or environment reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t);\n\t}\n\tif (!isSourceAwareSecretReference(gatewayTokenSecret)) {\n\t\tthrow new Error(`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' has an invalid shape.`);\n\t}\n\n\ttry {\n\t\tif (gatewayTokenSecret.source === '1password' && !gatewayTokenSecret.ref) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing 'ref'. Add an explicit 1Password reference such as 'op://agent-vm/${zone.id}-gateway-auth/password'.`,\n\t\t\t);\n\t\t}\n\t\tif (gatewayTokenSecret.source === 'environment' && !gatewayTokenSecret.envVar) {\n\t\t\tthrow new Error(\n\t\t\t\t`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing 'envVar'. Add an explicit environment variable name.`,\n\t\t\t);\n\t\t}\n\t\tconst rawBaseConfig = await readFile(zone.gateway.config, 'utf8');\n\t\tconst parsedBaseConfig: unknown = JSON.parse(rawBaseConfig);\n\t\tif (!isObjectRecord(parsedBaseConfig)) {\n\t\t\tthrow new Error(`OpenClaw config at '${zone.gateway.config}' must be a JSON object.`);\n\t\t}\n\t\tconst config = isObjectRecord(parsedBaseConfig.gateway) ? parsedBaseConfig.gateway : {};\n\t\tconst existingAuthConfig = isObjectRecord(config.auth) ? config.auth : {};\n\t\tconst effectiveConfig = {\n\t\t\t...parsedBaseConfig,\n\t\t\tgateway: {\n\t\t\t\t...config,\n\t\t\t\tauth: {\n\t\t\t\t\t...existingAuthConfig,\n\t\t\t\t\tmode: 'token',\n\t\t\t\t\ttoken: openClawGatewayTokenSecretRef,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeta: {\n\t\t\t\t...(isObjectRecord(parsedBaseConfig.meta) ? parsedBaseConfig.meta : {}),\n\t\t\t\tlastTouchedAt: new Date().toISOString(),\n\t\t\t\tlastTouchedVersion: 'agent-vm',\n\t\t\t},\n\t\t\tsecrets: buildEffectiveSecretsConfig(parsedBaseConfig),\n\t\t};\n\t\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\t\tawait mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait chmod(zone.gateway.stateDir, 0o700);\n\t\tawait writeFileAtomically(\n\t\t\teffectiveConfigPath,\n\t\t\t`${JSON.stringify(effectiveConfig, null, 2)}\\n`,\n\t\t\t{ mode: 0o600 },\n\t\t);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`Failed to write effective OpenClaw config for zone '${zone.id}' from '${zone.gateway.config}' using secret '${describeSecretReference(gatewayTokenSecret)}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nexport const openclawLifecycle: GatewayLifecycle = {\n\tauthConfig: {\n\t\tlistProvidersCommand: 'openclaw models auth list --format plain 2>/dev/null || echo \"\"',\n\t\tbuildLoginCommand: (\n\t\t\tprovider: string,\n\t\t\toptions: { readonly deviceCode?: boolean; readonly setDefault?: boolean } = {},\n\t\t): string =>\n\t\t\t[\n\t\t\t\t`openclaw models auth login --provider ${shellQuote(provider)}`,\n\t\t\t\t...(options.deviceCode === true ? ['--device-code'] : []),\n\t\t\t\t...(options.setDefault === true ? ['--set-default'] : []),\n\t\t\t].join(' '),\n\t},\n\n\tbuildVmSpec({\n\t\tcontrollerPort,\n\t\tgatewayCacheDir,\n\t\tprojectNamespace,\n\t\tresolvedSecrets,\n\t\ttcpPool,\n\t\tzone,\n\t}: BuildGatewayVmSpecOptions): GatewayVmSpec {\n\t\tif (zone.gateway.type !== 'openclaw') {\n\t\t\tthrow new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);\n\t\t}\n\t\tconst configDirectory = path.dirname(path.resolve(zone.gateway.config));\n\t\tconst { environmentSecrets, mediatedSecrets } = splitResolvedGatewaySecrets(\n\t\t\tzone,\n\t\t\tresolvedSecrets,\n\t\t);\n\n\t\treturn {\n\t\t\tallowedHosts: [...zone.allowedHosts],\n\t\t\tenvironment: {\n\t\t\t\tHOME: '/home/openclaw',\n\t\t\t\tNODE_EXTRA_CA_CERTS: '/run/gondolin/ca-certificates.crt',\n\t\t\t\tOPENCLAW_CONFIG_PATH: effectiveOpenClawConfigVmPath,\n\t\t\t\tOPENCLAW_HOME: '/home/openclaw',\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\tPATH: `/pnpm:${process.env.PATH ?? ''}`,\n\t\t\t\tPIP_CACHE_DIR: '/work/cache/pip',\n\t\t\t\tPNPM_HOME: '/pnpm',\n\t\t\t\tTEMP: '/work/tmp',\n\t\t\t\tTMP: '/work/tmp',\n\t\t\t\tTMPDIR: '/work/tmp',\n\t\t\t\tUV_CACHE_DIR: '/work/cache/uv',\n\t\t\t\tnpm_config_cache: '/work/cache/npm',\n\t\t\t\tpnpm_config_store_dir: '/work/cache/pnpm/store',\n\t\t\t\t...environmentSecrets,\n\t\t\t},\n\t\t\tmediatedSecrets,\n\t\t\trootfsMode: 'cow',\n\t\t\tsessionLabel: buildGatewaySessionLabelValue(projectNamespace, zone.id),\n\t\t\ttcpHosts: buildGatewayTcpHosts(zone, controllerPort, tcpPool),\n\t\t\tvfsMounts: {\n\t\t\t\t'/home/openclaw/.openclaw/config': {\n\t\t\t\t\thostPath: configDirectory,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawCacheDirVmPath]: {\n\t\t\t\t\thostPath: gatewayCacheDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t'/home/openclaw/.openclaw/state': {\n\t\t\t\t\thostPath: zone.gateway.stateDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t\t[openClawZoneFilesDirVmPath]: {\n\t\t\t\t\thostPath: zone.gateway.zoneFilesDir,\n\t\t\t\t\tkind: 'realfs',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n\n\tbuildProcessSpec(\n\t\tzone: GatewayZoneConfig,\n\t\tresolvedSecrets: Record<string, string>,\n\t): GatewayProcessSpec {\n\t\treturn {\n\t\t\tbootstrapCommand: buildOpenClawBootstrapCommand(zone, resolvedSecrets),\n\t\t\tstartCommand: `set -a && . ${openClawRuntimeSecretsEnvFilePath} && set +a && cd /home/openclaw && nohup openclaw gateway --port 18789 > /tmp/openclaw.log 2>&1 &`,\n\t\t\thealthCheck: {\n\t\t\t\ttype: 'http',\n\t\t\t\tport: 18789,\n\t\t\t\tpath: '/readyz',\n\t\t\t},\n\t\t\tguestListenPort: 18789,\n\t\t\tlogPath: '/tmp/openclaw.log',\n\t\t};\n\t},\n\n\tasync prepareHostState(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void> {\n\t\tawait writeEffectiveOpenClawConfig(zone);\n\t\tawait writeAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-vm/openclaw-gateway",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.45",
|
|
4
4
|
"description": "OpenClaw gateway lifecycle running inside a Gondolin VM.",
|
|
5
5
|
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@agent-vm/gateway-interface": "0.0.
|
|
33
|
-
"@agent-vm/gondolin-adapter": "0.0.
|
|
32
|
+
"@agent-vm/gateway-interface": "0.0.45",
|
|
33
|
+
"@agent-vm/gondolin-adapter": "0.0.45"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsdown",
|