@agent-vm/openclaw-gateway 0.0.31 → 0.0.33

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.d.ts CHANGED
@@ -5,6 +5,15 @@ type GatewayType = (typeof gatewayTypeValues)[number];
5
5
  //#endregion
6
6
  //#region ../gondolin-adapter/dist/index.d.ts
7
7
 
8
+ //#endregion
9
+ //#region src/pinned-realfs.d.ts
10
+ interface PinnedRealFsRoot {
11
+ readonly hostPath: string;
12
+ readonly realPath: string;
13
+ readonly fd: number;
14
+ readonly device: number;
15
+ readonly inode: number;
16
+ }
8
17
  //#endregion
9
18
  //#region src/types.d.ts
10
19
  interface SecretSpec {
@@ -28,6 +37,7 @@ interface SecretResolver {
28
37
  interface VfsMountSpec {
29
38
  readonly kind: 'realfs' | 'realfs-readonly' | 'memory' | 'shadow';
30
39
  readonly hostPath?: string;
40
+ readonly pinnedHostRoot?: PinnedRealFsRoot;
31
41
  readonly shadowConfig?: {
32
42
  readonly deny: readonly string[];
33
43
  readonly tmpfs: readonly string[];
@@ -90,28 +100,42 @@ interface GatewayAuthConfig {
90
100
  readonly setDefault?: boolean;
91
101
  }) => string;
92
102
  }
103
+ interface GatewayAuthProfilesRef {
104
+ readonly source: '1password' | 'environment';
105
+ }
106
+ interface OnePasswordGatewayAuthProfilesRef extends GatewayAuthProfilesRef {
107
+ readonly source: '1password';
108
+ readonly ref: string;
109
+ }
110
+ interface EnvironmentGatewayAuthProfilesRef extends GatewayAuthProfilesRef {
111
+ readonly source: 'environment';
112
+ readonly envVar: string;
113
+ }
114
+ interface GatewayZoneBaseGatewayConfig {
115
+ readonly type: GatewayType;
116
+ readonly memory: string;
117
+ readonly cpus: number;
118
+ readonly port: number;
119
+ readonly config: string;
120
+ readonly stateDir: string;
121
+ readonly authProfilesRef?: OnePasswordGatewayAuthProfilesRef | EnvironmentGatewayAuthProfilesRef | undefined;
122
+ }
123
+ interface OpenClawGatewayZoneGatewayConfig extends GatewayZoneBaseGatewayConfig {
124
+ readonly type: 'openclaw';
125
+ readonly zoneFilesDir: string;
126
+ readonly authProfilesByAgent?: Readonly<Record<string, OnePasswordGatewayAuthProfilesRef | EnvironmentGatewayAuthProfilesRef>>;
127
+ }
128
+ interface WorkerGatewayZoneGatewayConfig extends GatewayZoneBaseGatewayConfig {
129
+ readonly type: 'worker';
130
+ }
131
+ type GatewayZoneGatewayConfig = OpenClawGatewayZoneGatewayConfig | WorkerGatewayZoneGatewayConfig;
93
132
  /**
94
133
  * Zone config as the lifecycle sees it.
95
134
  * Decoupled from SystemConfig — the controller maps into this shape.
96
135
  */
97
136
  interface GatewayZoneConfig {
98
137
  readonly id: string;
99
- readonly gateway: {
100
- readonly type: GatewayType;
101
- readonly memory: string;
102
- readonly cpus: number;
103
- readonly port: number;
104
- readonly config: string;
105
- readonly stateDir: string;
106
- readonly workspaceDir: string;
107
- readonly authProfilesRef?: {
108
- readonly source: '1password';
109
- readonly ref: string;
110
- } | {
111
- readonly source: 'environment';
112
- readonly envVar: string;
113
- } | undefined;
114
- };
138
+ readonly gateway: GatewayZoneGatewayConfig;
115
139
  readonly secrets: Record<string, {
116
140
  readonly source: '1password';
117
141
  readonly ref: string;
@@ -125,7 +149,7 @@ interface GatewayZoneConfig {
125
149
  }>;
126
150
  readonly allowedHosts: readonly string[];
127
151
  readonly websocketBypass: readonly string[];
128
- readonly toolProfile?: string;
152
+ readonly defaultToolVmProfile?: string;
129
153
  }
130
154
  interface BuildGatewayVmSpecOptions {
131
155
  readonly controllerPort: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["gatewayTypeValues","GatewayType","buildGatewaySessionLabel","buildToolSessionLabel","SecretSpec","SecretRef","SecretResolver","Promise","Record","VfsMountSpec","GatewayHealthCheck","GatewayProcessSpec","GatewayVmSpec","GatewayAuthConfig","GatewayZoneConfig","BuildGatewayVmSpecOptions","GatewayLifecycle","SplitResolvedGatewaySecretsResult","splitResolvedGatewaySecrets"],"sources":["../../gateway-interface/dist/index.d.ts","../src/openclaw-lifecycle.ts"],"sourcesContent":["//#region src/gateway-runtime-contract.d.ts\ndeclare const gatewayTypeValues: readonly [\"openclaw\", \"worker\"];\ntype GatewayType = (typeof gatewayTypeValues)[number];\ndeclare function buildGatewaySessionLabel(projectNamespace: string, zoneId: string): string;\ndeclare function buildToolSessionLabel(projectNamespace: string, zoneId: string, tcpSlot: number): string;\n//#endregion\n//#region ../gondolin-adapter/dist/index.d.ts\n\n//#endregion\n//#region src/types.d.ts\ninterface SecretSpec {\n readonly hosts: readonly string[];\n readonly value: string;\n}\ntype SecretRef = {\n readonly source: '1password';\n readonly ref: string;\n} | {\n readonly source: 'environment';\n readonly ref: string;\n};\n//#endregion\n//#region src/secret-resolver.d.ts\n\ninterface SecretResolver {\n resolve(ref: SecretRef): Promise<string>;\n resolveAll(refs: Record<string, SecretRef>): Promise<Record<string, string>>;\n}\ninterface VfsMountSpec {\n readonly kind: 'realfs' | 'realfs-readonly' | 'memory' | 'shadow';\n readonly hostPath?: string;\n readonly shadowConfig?: {\n readonly deny: readonly string[];\n readonly tmpfs: readonly string[];\n };\n}\n//#endregion\n//#region src/gateway-process-spec.d.ts\ntype GatewayHealthCheck = {\n readonly type: 'http';\n readonly port: number;\n readonly path: string;\n} | {\n readonly type: 'command';\n readonly command: string;\n};\n/**\n * Everything about the process running inside the VM.\n * Retained by the running gateway handle for logs, health, restart.\n */\ninterface GatewayProcessSpec {\n readonly bootstrapCommand: string;\n readonly startCommand: string;\n readonly healthCheck: GatewayHealthCheck;\n readonly guestListenPort: number;\n readonly logPath: string;\n}\n//#endregion\n//#region src/gateway-vm-spec.d.ts\n/**\n * Everything the controller needs to create the Gondolin VM.\n * Lifecycle implementations own the full Gondolin-facing contract.\n */\ninterface GatewayVmSpec {\n readonly environment: Record<string, string>;\n readonly vfsMounts: Record<string, VfsMountSpec>;\n readonly mediatedSecrets: Record<string, SecretSpec>;\n readonly tcpHosts: Record<string, string>;\n readonly allowedHosts: readonly string[];\n readonly rootfsMode: 'readonly' | 'memory' | 'cow';\n readonly sessionLabel: string;\n}\n//#endregion\n//#region src/gateway-lifecycle.d.ts\n/**\n * Describes how to run interactive auth for a gateway type.\n * Static property — available without a running VM.\n */\ninterface GatewayAuthConfig {\n /**\n * Shell command to list available auth providers inside the VM.\n * Should output one provider name per line to stdout.\n */\n readonly listProvidersCommand: string;\n /**\n * Build the shell command for interactive auth login.\n * The CLI passes this as the SSH remote command with -t (TTY).\n */\n readonly buildLoginCommand: (provider: string, options?: {\n readonly deviceCode?: boolean;\n readonly setDefault?: boolean;\n }) => string;\n}\n/**\n * Zone config as the lifecycle sees it.\n * Decoupled from SystemConfig the controller maps into this shape.\n */\ninterface GatewayZoneConfig {\n readonly id: string;\n readonly gateway: {\n readonly type: GatewayType;\n readonly memory: string;\n readonly cpus: number;\n readonly port: number;\n readonly config: string;\n readonly stateDir: string;\n readonly workspaceDir: string;\n readonly authProfilesRef?: {\n readonly source: '1password';\n readonly ref: string;\n } | {\n readonly source: 'environment';\n readonly envVar: string;\n } | undefined;\n };\n readonly secrets: Record<string, {\n readonly source: '1password';\n readonly ref: string;\n readonly injection: 'env' | 'http-mediation';\n readonly hosts?: readonly string[] | undefined;\n } | {\n readonly source: 'environment';\n readonly envVar: string;\n readonly injection: 'env' | 'http-mediation';\n readonly hosts?: readonly string[] | undefined;\n }>;\n readonly allowedHosts: readonly string[];\n readonly websocketBypass: readonly string[];\n readonly toolProfile?: string;\n}\ninterface BuildGatewayVmSpecOptions {\n readonly controllerPort: number;\n readonly gatewayCacheDir: string;\n readonly projectNamespace: string;\n readonly resolvedSecrets: Record<string, string>;\n readonly tcpPool: {\n readonly basePort: number;\n readonly size: number;\n };\n readonly zone: GatewayZoneConfig;\n}\ninterface GatewayLifecycle {\n /**\n * How to run interactive auth for this gateway type.\n * Absent means the gateway type does not support interactive auth.\n */\n readonly authConfig?: GatewayAuthConfig | undefined;\n /**\n * Build the full VM spec — everything Gondolin needs to create the VM.\n * Pure data assembly — no side effects.\n */\n buildVmSpec(options: BuildGatewayVmSpecOptions): GatewayVmSpec;\n /**\n * Build the process spec — everything about startup, health, and logging.\n * Pure data assembly — no side effects.\n */\n buildProcessSpec(zone: GatewayZoneConfig, resolvedSecrets: Record<string, string>): GatewayProcessSpec;\n /**\n * Optional hook to prepare host-side state before the VM boots.\n * Example: writing auth-profiles.json from 1Password.\n */\n prepareHostState?(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void>;\n}\n//#endregion\n//#region src/split-resolved-gateway-secrets.d.ts\ninterface SplitResolvedGatewaySecretsResult {\n readonly environmentSecrets: Record<string, string>;\n readonly mediatedSecrets: Record<string, SecretSpec>;\n}\ndeclare function splitResolvedGatewaySecrets(zone: GatewayZoneConfig, resolvedSecrets: Record<string, string>): SplitResolvedGatewaySecretsResult;\n//#endregion\nexport { type BuildGatewayVmSpecOptions, type GatewayAuthConfig, type GatewayHealthCheck, type GatewayLifecycle, type GatewayProcessSpec, type GatewayType, type GatewayVmSpec, type GatewayZoneConfig, type SplitResolvedGatewaySecretsResult, buildGatewaySessionLabel, buildToolSessionLabel, gatewayTypeValues, splitResolvedGatewaySecrets };\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;cACcA,iBAAkD,EAAA,SAAA,CAAA,UAAA,EAAA,QAAA,CAAA;AAAA,KAC3DC,WAAAA,GAAW,CAAA,OAAWD,iBAAAA,CAAAA,CAAAA,MAAiB,CAAA;AAY9B;;;;;UAJJI,UAAAA,CAgB6CI;EAARD,SAAAA,KAAAA,EAAAA,SAAAA,MAAAA,EAAAA;EAAO,SAAA,KAAA,EAAA,MAAA;AAAA;AAEhC,KAdjBF,SAAAA,GAwBAK;EAAkB,SAYbC,MAAAA,EAAAA,WAAkB;EAGc,SAUhCC,GAAAA,EAAAA,MAAa;CACCJ,GAAAA;EACaC,SAAAA,MAAAA,EAAAA,aAAAA;EAAfD,SAAAA,GAAAA,EAAAA,MAAAA;CACqBJ;;;;AAChB,UA3CjBE,cAAAA,CAsDiB;EAAA,OAmBjBQ,CAAAA,GAAAA,EAxEKT,SAwEY,CAAA,EAxEAE,OAwEA,CAAA,MAGRN,CAAAA;EAeO,UAehBc,CAAAA,IAAAA,EAxGSP,MAwGTO,CAAAA,MAAyB,EAxGDV,SAwGC,CAIPG,CAAAA,EA5GmBD,OAiH9BO,CAjHsCN,MAiHtCM,CAAAA,MAAAA,EAAiB,MAAA,CAAA,CAAA;AAAA;UA/GxBL,YAAAA,CAsHcI;EAKDE,SAAAA,IAAAA,EAAAA,QAAAA,GAAAA,iBAAAA,GAAAA,QAAAA,GAAAA,QAAAA;EAA4BH,SAAAA,QAAAA,CAAAA,EAAAA,MAAAA;EAK1BE,SAAAA,YAAAA,CAAAA,EAAAA;IAAoCN,SAAAA,IAAAA,EAAAA,SAAAA,MAAAA,EAAAA;IAAyBG,SAAAA,KAAAA,EAAAA,SAAAA,MAAAA,EAAAA;EAK5DG,CAAAA;;;;KA3HrBJ,kBAAAA;;;ECwLL,SAAa,IAAA,EAAA,MAAA;;;;;;;;;UD5KHC,kBAAAA;;;wBAGcD;;;;;;;;;;UAUdE,aAAAA;wBACcJ;sBACFA,eAAeC;4BACTD,eAAeJ;qBACtBI;;;;;;;;;;;UAWXK,iBAAAA;;;;;;;;;;;;;;;;;;;UAmBAC,iBAAAA;;;mBAGSb;;;;;;;;;;;;;;;oBAeCO;;;;;;;;;;;;;;;UAeVO,yBAAAA;;;;4BAIkBP;;;;;iBAKXM;;UAEPE,gBAAAA;;;;;wBAKcH;;;;;uBAKDE,4BAA4BH;;;;;yBAK1BE,oCAAoCN,yBAAyBG;;;;;0BAK5DG,mCAAmCR,iBAAiBC;;;;;;AAhKhEP,cC6ND,iBD7NmD,EC6NhC,gBD7NgC"}
1
+ {"version":3,"file":"index.d.ts","names":["gatewayTypeValues","GatewayType","buildGatewaySessionLabel","buildToolSessionLabel","PinnedRealFsRoot","SecretSpec","SecretRef","SecretResolver","Promise","Record","VfsMountSpec","GatewayHealthCheck","GatewayProcessSpec","GatewayVmSpec","GatewayAuthConfig","GatewayAuthProfilesRef","OnePasswordGatewayAuthProfilesRef","EnvironmentGatewayAuthProfilesRef","GatewayZoneBaseGatewayConfig","OpenClawGatewayZoneGatewayConfig","Readonly","WorkerGatewayZoneGatewayConfig","GatewayZoneGatewayConfig","GatewayZoneConfig","BuildGatewayVmSpecOptions","GatewayLifecycle","SplitResolvedGatewaySecretsResult","splitResolvedGatewaySecrets"],"sources":["../../gateway-interface/dist/index.d.ts","../src/openclaw-lifecycle.ts"],"sourcesContent":["//#region src/gateway-runtime-contract.d.ts\ndeclare const gatewayTypeValues: readonly [\"openclaw\", \"worker\"];\ntype GatewayType = (typeof gatewayTypeValues)[number];\ndeclare function buildGatewaySessionLabel(projectNamespace: string, zoneId: string): string;\ndeclare function buildToolSessionLabel(projectNamespace: string, zoneId: string, tcpSlot: number): string;\n//#endregion\n//#region ../gondolin-adapter/dist/index.d.ts\n\n//#endregion\n//#region src/pinned-realfs.d.ts\ninterface PinnedRealFsRoot {\n readonly hostPath: string;\n readonly realPath: string;\n readonly fd: number;\n readonly device: number;\n readonly inode: number;\n}\n//#endregion\n//#region src/types.d.ts\ninterface SecretSpec {\n readonly hosts: readonly string[];\n readonly value: string;\n}\ntype SecretRef = {\n readonly source: '1password';\n readonly ref: string;\n} | {\n readonly source: 'environment';\n readonly ref: string;\n};\n//#endregion\n//#region src/secret-resolver.d.ts\n\ninterface SecretResolver {\n resolve(ref: SecretRef): Promise<string>;\n resolveAll(refs: Record<string, SecretRef>): Promise<Record<string, string>>;\n}\ninterface VfsMountSpec {\n readonly kind: 'realfs' | 'realfs-readonly' | 'memory' | 'shadow';\n readonly hostPath?: string;\n readonly pinnedHostRoot?: PinnedRealFsRoot;\n readonly shadowConfig?: {\n readonly deny: readonly string[];\n readonly tmpfs: readonly string[];\n };\n}\n//#endregion\n//#region src/gateway-process-spec.d.ts\ntype GatewayHealthCheck = {\n readonly type: 'http';\n readonly port: number;\n readonly path: string;\n} | {\n readonly type: 'command';\n readonly command: string;\n};\n/**\n * Everything about the process running inside the VM.\n * Retained by the running gateway handle for logs, health, restart.\n */\ninterface GatewayProcessSpec {\n readonly bootstrapCommand: string;\n readonly startCommand: string;\n readonly healthCheck: GatewayHealthCheck;\n readonly guestListenPort: number;\n readonly logPath: string;\n}\n//#endregion\n//#region src/gateway-vm-spec.d.ts\n/**\n * Everything the controller needs to create the Gondolin VM.\n * Lifecycle implementations own the full Gondolin-facing contract.\n */\ninterface GatewayVmSpec {\n readonly environment: Record<string, string>;\n readonly vfsMounts: Record<string, VfsMountSpec>;\n readonly mediatedSecrets: Record<string, SecretSpec>;\n readonly tcpHosts: Record<string, string>;\n readonly allowedHosts: readonly string[];\n readonly rootfsMode: 'readonly' | 'memory' | 'cow';\n readonly sessionLabel: string;\n}\n//#endregion\n//#region src/gateway-lifecycle.d.ts\n/**\n * Describes how to run interactive auth for a gateway type.\n * Static property — available without a running VM.\n */\ninterface GatewayAuthConfig {\n /**\n * Shell command to list available auth providers inside the VM.\n * Should output one provider name per line to stdout.\n */\n readonly listProvidersCommand: string;\n /**\n * Build the shell command for interactive auth login.\n * The CLI passes this as the SSH remote command with -t (TTY).\n */\n readonly buildLoginCommand: (provider: string, options?: {\n readonly deviceCode?: boolean;\n readonly setDefault?: boolean;\n }) => string;\n}\ninterface GatewayAuthProfilesRef {\n readonly source: '1password' | 'environment';\n}\ninterface OnePasswordGatewayAuthProfilesRef extends GatewayAuthProfilesRef {\n readonly source: '1password';\n readonly ref: string;\n}\ninterface EnvironmentGatewayAuthProfilesRef extends GatewayAuthProfilesRef {\n readonly source: 'environment';\n readonly envVar: string;\n}\ninterface GatewayZoneBaseGatewayConfig {\n readonly type: GatewayType;\n readonly memory: string;\n readonly cpus: number;\n readonly port: number;\n readonly config: string;\n readonly stateDir: string;\n readonly authProfilesRef?: OnePasswordGatewayAuthProfilesRef | EnvironmentGatewayAuthProfilesRef | undefined;\n}\ninterface OpenClawGatewayZoneGatewayConfig extends GatewayZoneBaseGatewayConfig {\n readonly type: 'openclaw';\n readonly zoneFilesDir: string;\n readonly authProfilesByAgent?: Readonly<Record<string, OnePasswordGatewayAuthProfilesRef | EnvironmentGatewayAuthProfilesRef>>;\n}\ninterface WorkerGatewayZoneGatewayConfig extends GatewayZoneBaseGatewayConfig {\n readonly type: 'worker';\n}\ntype GatewayZoneGatewayConfig = OpenClawGatewayZoneGatewayConfig | WorkerGatewayZoneGatewayConfig;\n/**\n * Zone config as the lifecycle sees it.\n * Decoupled from SystemConfig — the controller maps into this shape.\n */\ninterface GatewayZoneConfig {\n readonly id: string;\n readonly gateway: GatewayZoneGatewayConfig;\n readonly secrets: Record<string, {\n readonly source: '1password';\n readonly ref: string;\n readonly injection: 'env' | 'http-mediation';\n readonly hosts?: readonly string[] | undefined;\n } | {\n readonly source: 'environment';\n readonly envVar: string;\n readonly injection: 'env' | 'http-mediation';\n readonly hosts?: readonly string[] | undefined;\n }>;\n readonly allowedHosts: readonly string[];\n readonly websocketBypass: readonly string[];\n readonly defaultToolVmProfile?: string;\n}\ninterface BuildGatewayVmSpecOptions {\n readonly controllerPort: number;\n readonly gatewayCacheDir: string;\n readonly projectNamespace: string;\n readonly resolvedSecrets: Record<string, string>;\n readonly tcpPool: {\n readonly basePort: number;\n readonly size: number;\n };\n readonly zone: GatewayZoneConfig;\n}\ninterface GatewayLifecycle {\n /**\n * How to run interactive auth for this gateway type.\n * Absent means the gateway type does not support interactive auth.\n */\n readonly authConfig?: GatewayAuthConfig | undefined;\n /**\n * Build the full VM spec — everything Gondolin needs to create the VM.\n * Pure data assembly — no side effects.\n */\n buildVmSpec(options: BuildGatewayVmSpecOptions): GatewayVmSpec;\n /**\n * Build the process spec — everything about startup, health, and logging.\n * Pure data assembly — no side effects.\n */\n buildProcessSpec(zone: GatewayZoneConfig, resolvedSecrets: Record<string, string>): GatewayProcessSpec;\n /**\n * Optional hook to prepare host-side state before the VM boots.\n * Example: writing auth-profiles.json from 1Password.\n */\n prepareHostState?(zone: GatewayZoneConfig, secretResolver: SecretResolver): Promise<void>;\n}\n//#endregion\n//#region src/split-resolved-gateway-secrets.d.ts\ninterface SplitResolvedGatewaySecretsResult {\n readonly environmentSecrets: Record<string, string>;\n readonly mediatedSecrets: Record<string, SecretSpec>;\n}\ndeclare function splitResolvedGatewaySecrets(zone: GatewayZoneConfig, resolvedSecrets: Record<string, string>): SplitResolvedGatewaySecretsResult;\n//#endregion\nexport { type BuildGatewayVmSpecOptions, type GatewayAuthConfig, type GatewayHealthCheck, type GatewayLifecycle, type GatewayProcessSpec, type GatewayType, type GatewayVmSpec, type GatewayZoneConfig, type SplitResolvedGatewaySecretsResult, buildGatewaySessionLabel, buildToolSessionLabel, gatewayTypeValues, splitResolvedGatewaySecrets };\n//# sourceMappingURL=index.d.ts.map"],"mappings":";;cACcA,iBAAkD,EAAA,SAAA,CAAA,UAAA,EAAA,QAAA,CAAA;AAAA,KAC3DC,WAAAA,GAAW,CAAA,OAAWD,iBAAAA,CAAAA,CAAAA,MAAiB,CAAA;AAiBxB;AAIN;;;;UAbJI,gBAAAA,CAyBSK;EAAoCA,SAAAA,QAAAA,EAAAA,MAAAA;EAARD,SAAAA,QAAAA,EAAAA,MAAAA;EAAO,SAAA,EAAA,EAAA,MAAA;EAAA,SAE5CE,MAAAA,EAAY,MAAA;EAGsB,SAQvCC,KAAAA,EAAAA,MAAAA;AAAkB;AAemB;;UA5ChCN,UAAAA,CAwD2BK;EAAfD,SAAAA,KAAAA,EAAAA,SAAAA,MAAAA,EAAAA;EACqBJ,SAAAA,KAAAA,EAAAA,MAAAA;;KArDtCC,SAAAA,GAsDgBG;EAAM,SAAA,MAAA,EAAA,WAAA;EAAA,SAWjBK,GAAAA,EAAAA,MAAAA;AAAiB,CAAA,GAejBC;EAAsB,SAGtBC,MAAAA,EAAAA,aAAAA;EAAgE,SAIhEC,GAAAA,EAAAA,MAAAA;AAAgE,CAAA;;;;UA7EhEV,cAAAA,CAwFwF;EAAA,OAExFY,CAAAA,GAAAA,EAzFKb,SAyFLa,CAAAA,EAzFiBX,OAyFjBW,CAAAA,MAAgC,CAAA;EAGeH,UAAAA,CAAAA,IAAAA,EA3FtCP,MA2FsCO,CAAAA,MAAAA,EA3FvBV,SA2FuBU,CAAAA,CAAAA,EA3FVR,OA2FUQ,CA3FFP,MA2FEO,CAAAA,MAAAA,EAAAA,MAAAA,CAAAA,CAAAA;;UAzF/CN,YAAAA,CAyFgCD;EAATW,SAAAA,IAAAA,EAAAA,QAAAA,GAAAA,iBAAAA,GAAAA,QAAAA,GAAAA,QAAAA;EAHkBF,SAAAA,QAAAA,CAAAA,EAAAA,MAAAA;EAA4B,SAAA,cAAA,CAAA,EAnFnDd,gBAmFmD;EAAA,SAKrEiB,YAAAA,CAAAA,EAAAA;IAGLC,SAAAA,IAAAA,EAAAA,SAAAA,MAAwB,EAAA;IAKnBC,SAAAA,KAAAA,EAAAA,SAAiB,MAAA,EAEPD;EACM,CAAA;AAwBQ;;;KAnH7BX,kBAAAA,GA+H8CE;EAK1BU,SAAAA,IAAAA,EAAAA,MAAAA;EAAoCd,SAAAA,IAAAA,EAAAA,MAAAA;EAAyBG,SAAAA,IAAAA,EAAAA,MAAAA;CAK5DW,GAAAA;EAAmChB,SAAAA,IAAAA,EAAAA,SAAAA;EAAiBC,SAAAA,OAAAA,EAAAA,MAAAA;CAAO;;;;ACoErF;UDjMUI,kBAAAA;;;wBAGcD;;;;;;;;;;UAUdE,aAAAA;wBACcJ;sBACFA,eAAeC;4BACTD,eAAeJ;qBACtBI;;;;;;;;;;;UAWXK,iBAAAA;;;;;;;;;;;;;;;UAeAC,sBAAAA;;;UAGAC,iCAAAA,SAA0CD;;;;UAI1CE,iCAAAA,SAA0CF;;;;UAI1CG,4BAAAA;iBACOjB;;;;;;6BAMYe,oCAAoCC;;UAEvDE,gCAAAA,SAAyCD;;;iCAGlBE,SAASX,eAAeO,oCAAoCC;;UAEnFI,8BAAAA,SAAuCH;;;KAG5CI,wBAAAA,GAA2BH,mCAAmCE;;;;;UAKzDE,iBAAAA;;oBAEUD;oBACAb;;;;;;;;;;;;;;;UAeVe,yBAAAA;;;;4BAIkBf;;;;;iBAKXc;;UAEPE,gBAAAA;;;;;wBAKcX;;;;;uBAKDU,4BAA4BX;;;;;yBAK1BU,oCAAoCd,yBAAyBG;;;;;0BAK5DW,mCAAmChB,iBAAiBC;;;;;;AAxLhER,cC4PD,iBD5PmD,EC4PhC,gBD5PgC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import fs from "node:fs/promises";
1
+ import { chmod, mkdir, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { buildGatewaySessionLabel, splitResolvedGatewaySecrets } from "@agent-vm/gateway-interface";
4
4
  import { writeFileAtomically } from "@agent-vm/gondolin-adapter";
@@ -8,7 +8,8 @@ const effectiveOpenClawConfigFileName = "effective-openclaw.json";
8
8
  const effectiveOpenClawConfigVmPath = `/home/openclaw/.openclaw/state/${effectiveOpenClawConfigFileName}`;
9
9
  const openClawStateDirVmPath = "/home/openclaw/.openclaw/state";
10
10
  const openClawCacheDirVmPath = "/home/openclaw/.openclaw/cache";
11
- const openClawPluginStageDirVmPath = `${openClawCacheDirVmPath}/plugin-runtime-deps`;
11
+ const openClawZoneFilesDirVmPath = "/zone";
12
+ const openClawPluginStageDirVmPath = "/opt/openclaw/plugin-runtime-deps";
12
13
  const openClawShellEnvFilePath = "/etc/profile.d/openclaw-env.sh";
13
14
  function isObjectRecord(value) {
14
15
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -25,9 +26,16 @@ function buildOpenClawBootstrapCommand(_zone, _resolvedSecrets) {
25
26
  `export OPENCLAW_CONFIG_PATH=${effectiveOpenClawConfigVmPath}`,
26
27
  `export OPENCLAW_STATE_DIR=${openClawStateDirVmPath}`,
27
28
  `export OPENCLAW_PLUGIN_STAGE_DIR=${openClawPluginStageDirVmPath}`,
29
+ "export TMPDIR=/work/tmp",
30
+ "export TMP=/work/tmp",
31
+ "export TEMP=/work/tmp",
32
+ "export npm_config_cache=/work/cache/npm",
33
+ "export pnpm_config_store_dir=/work/cache/pnpm/store",
34
+ "export PIP_CACHE_DIR=/work/cache/pip",
35
+ "export UV_CACHE_DIR=/work/cache/uv",
28
36
  "export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt"
29
37
  ];
30
- return `mkdir -p /root /etc/profile.d && cat > ${openClawShellEnvFilePath} << ENVEOF\n` + environmentLines.join("\n") + `
38
+ return `mkdir -p /root /etc/profile.d /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && cat > ${openClawShellEnvFilePath} << ENVEOF\n` + environmentLines.join("\n") + `
31
39
  ENVEOF
32
40
  chmod 644 ${openClawShellEnvFilePath} && touch /root/.bashrc && grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /root/.bashrc && touch /root/.bash_profile && grep -qxF 'source /root/.bashrc' /root/.bash_profile || echo 'source /root/.bashrc' >> /root/.bash_profile`;
33
41
  }
@@ -57,23 +65,28 @@ function describeSecretReference(secret) {
57
65
  return secret.source === "environment" ? secret.envVar : secret.ref;
58
66
  }
59
67
  async function writeAuthProfilesIfConfigured(zone, secretResolver) {
60
- const authProfilesSecretCandidate = zone.gateway.authProfilesRef;
61
- if (authProfilesSecretCandidate === void 0) return;
62
- if (!isSourceAwareSecretReference(authProfilesSecretCandidate)) throw new Error(`Zone '${zone.id}' has an invalid authProfilesRef shape.`);
63
- const authProfilesSecret = authProfilesSecretCandidate;
64
- try {
65
- const authProfilesDirectory = path.join(zone.gateway.stateDir, "agents", "main", "agent");
66
- await fs.mkdir(authProfilesDirectory, {
67
- recursive: true,
68
- mode: 448
69
- });
70
- await fs.chmod(authProfilesDirectory, 448);
71
- const authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));
72
- await writeFileAtomically(path.join(authProfilesDirectory, "auth-profiles.json"), authProfiles, { mode: 384 });
73
- } catch (error) {
74
- const message = error instanceof Error ? error.message : String(error);
75
- throw new Error(`Failed to write OpenClaw auth profiles for zone '${zone.id}' from '${describeSecretReference(authProfilesSecret)}': ${message}`, { cause: error });
76
- }
68
+ const authProfilesByAgent = {
69
+ ...zone.gateway.authProfilesRef ? { main: zone.gateway.authProfilesRef } : {},
70
+ ...zone.gateway.type === "openclaw" ? zone.gateway.authProfilesByAgent ?? {} : {}
71
+ };
72
+ const writeErrors = (await Promise.allSettled(Object.entries(authProfilesByAgent).map(async ([agentId, authProfilesSecretCandidate]) => {
73
+ if (!isSourceAwareSecretReference(authProfilesSecretCandidate)) throw new Error(`Zone '${zone.id}' has an invalid auth profile shape for agent '${agentId}'.`);
74
+ const authProfilesSecret = authProfilesSecretCandidate;
75
+ try {
76
+ const authProfilesDirectory = path.join(zone.gateway.stateDir, "agents", agentId, "agent");
77
+ await mkdir(authProfilesDirectory, {
78
+ recursive: true,
79
+ mode: 448
80
+ });
81
+ await chmod(authProfilesDirectory, 448);
82
+ const authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));
83
+ await writeFileAtomically(path.join(authProfilesDirectory, "auth-profiles.json"), authProfiles, { mode: 384 });
84
+ } catch (error) {
85
+ const message = error instanceof Error ? error.message : String(error);
86
+ throw new Error(`Failed to write OpenClaw auth profiles for zone '${zone.id}' agent '${agentId}' from '${describeSecretReference(authProfilesSecret)}': ${message}`, { cause: error });
87
+ }
88
+ }))).filter((result) => result.status === "rejected").map((result) => result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
89
+ if (writeErrors.length > 0) throw new AggregateError(writeErrors, `Failed to write ${String(writeErrors.length)} OpenClaw auth profile file(s) for zone '${zone.id}'.`);
77
90
  }
78
91
  async function writeEffectiveOpenClawConfig(zone, secretResolver) {
79
92
  const gatewayTokenSecret = zone.secrets.OPENCLAW_GATEWAY_TOKEN;
@@ -83,7 +96,7 @@ async function writeEffectiveOpenClawConfig(zone, secretResolver) {
83
96
  if (gatewayTokenSecret.source === "1password" && !gatewayTokenSecret.ref) throw new Error(`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'.`);
84
97
  if (gatewayTokenSecret.source === "environment" && !gatewayTokenSecret.envVar) throw new Error(`Zone '${zone.id}' secret 'OPENCLAW_GATEWAY_TOKEN' is missing 'envVar'. Add an explicit environment variable name.`);
85
98
  const gatewayToken = await secretResolver.resolve(toSecretRef(gatewayTokenSecret));
86
- const rawBaseConfig = await fs.readFile(zone.gateway.config, "utf8");
99
+ const rawBaseConfig = await readFile(zone.gateway.config, "utf8");
87
100
  const parsedBaseConfig = JSON.parse(rawBaseConfig);
88
101
  if (!isObjectRecord(parsedBaseConfig)) throw new Error(`OpenClaw config at '${zone.gateway.config}' must be a JSON object.`);
89
102
  const config = isObjectRecord(parsedBaseConfig.gateway) ? parsedBaseConfig.gateway : {};
@@ -97,14 +110,19 @@ async function writeEffectiveOpenClawConfig(zone, secretResolver) {
97
110
  mode: "token",
98
111
  token: gatewayToken
99
112
  }
113
+ },
114
+ meta: {
115
+ ...isObjectRecord(parsedBaseConfig.meta) ? parsedBaseConfig.meta : {},
116
+ lastTouchedAt: (/* @__PURE__ */ new Date()).toISOString(),
117
+ lastTouchedVersion: "agent-vm"
100
118
  }
101
119
  };
102
120
  const effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);
103
- await fs.mkdir(zone.gateway.stateDir, {
121
+ await mkdir(zone.gateway.stateDir, {
104
122
  recursive: true,
105
123
  mode: 448
106
124
  });
107
- await fs.chmod(zone.gateway.stateDir, 448);
125
+ await chmod(zone.gateway.stateDir, 448);
108
126
  await writeFileAtomically(effectiveConfigPath, `${JSON.stringify(effectiveConfig, null, 2)}\n`, { mode: 384 });
109
127
  } catch (error) {
110
128
  const message = error instanceof Error ? error.message : String(error);
@@ -121,6 +139,7 @@ const openclawLifecycle = {
121
139
  ].join(" ")
122
140
  },
123
141
  buildVmSpec({ controllerPort, gatewayCacheDir, projectNamespace, resolvedSecrets, tcpPool, zone }) {
142
+ if (zone.gateway.type !== "openclaw") throw new Error(`OpenClaw lifecycle cannot build gateway type '${zone.gateway.type}'.`);
124
143
  const configDirectory = path.dirname(path.resolve(zone.gateway.config));
125
144
  const { environmentSecrets, mediatedSecrets } = splitResolvedGatewaySecrets(zone, resolvedSecrets);
126
145
  const { OPENCLAW_GATEWAY_TOKEN: _gatewayToken,...environmentSecretsWithoutGatewayToken } = environmentSecrets;
@@ -133,6 +152,13 @@ const openclawLifecycle = {
133
152
  OPENCLAW_HOME: "/home/openclaw",
134
153
  OPENCLAW_PLUGIN_STAGE_DIR: openClawPluginStageDirVmPath,
135
154
  OPENCLAW_STATE_DIR: openClawStateDirVmPath,
155
+ PIP_CACHE_DIR: "/work/cache/pip",
156
+ TEMP: "/work/tmp",
157
+ TMP: "/work/tmp",
158
+ TMPDIR: "/work/tmp",
159
+ UV_CACHE_DIR: "/work/cache/uv",
160
+ npm_config_cache: "/work/cache/npm",
161
+ pnpm_config_store_dir: "/work/cache/pnpm/store",
136
162
  ...environmentSecretsWithoutGatewayToken
137
163
  },
138
164
  mediatedSecrets,
@@ -152,8 +178,8 @@ const openclawLifecycle = {
152
178
  hostPath: zone.gateway.stateDir,
153
179
  kind: "realfs"
154
180
  },
155
- "/home/openclaw/workspace": {
156
- hostPath: zone.gateway.workspaceDir,
181
+ [openClawZoneFilesDirVmPath]: {
182
+ hostPath: zone.gateway.zoneFilesDir,
157
183
  kind: "realfs"
158
184
  }
159
185
  }
@@ -164,9 +190,8 @@ const openclawLifecycle = {
164
190
  bootstrapCommand: buildOpenClawBootstrapCommand(zone, resolvedSecrets),
165
191
  startCommand: "cd /home/openclaw && nohup openclaw gateway --port 18789 > /tmp/openclaw.log 2>&1 &",
166
192
  healthCheck: {
167
- type: "http",
168
- port: 18789,
169
- path: "/"
193
+ type: "command",
194
+ command: `grep -q 'ready (' /tmp/openclaw.log`
170
195
  },
171
196
  guestListenPort: 18789,
172
197
  logPath: "/tmp/openclaw.log"
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["tcpHosts: Record<string, string>","authProfilesSecretCandidate: unknown","parsedBaseConfig: unknown","openclawLifecycle: GatewayLifecycle","buildGatewaySessionLabelValue"],"sources":["../src/openclaw-lifecycle.ts"],"sourcesContent":["import fs 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 openClawPluginStageDirVmPath = `${openClawCacheDirVmPath}/plugin-runtime-deps`;\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\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\t_zone: GatewayZoneConfig,\n\t_resolvedSecrets: Record<string, string>,\n): string {\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 OPENCLAW_PLUGIN_STAGE_DIR=${openClawPluginStageDirVmPath}`,\n\t\t'export NODE_EXTRA_CA_CERTS=/run/gondolin/ca-certificates.crt',\n\t];\n\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d && cat > ${openClawShellEnvFilePath} << ENVEOF\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /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\nasync function writeAuthProfilesIfConfigured(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): Promise<void> {\n\tconst authProfilesSecretCandidate: unknown = zone.gateway.authProfilesRef;\n\tif (authProfilesSecretCandidate === undefined) {\n\t\treturn;\n\t}\n\tif (!isSourceAwareSecretReference(authProfilesSecretCandidate)) {\n\t\tthrow new Error(`Zone '${zone.id}' has an invalid authProfilesRef shape.`);\n\t}\n\tconst authProfilesSecret = authProfilesSecretCandidate;\n\n\ttry {\n\t\tconst authProfilesDirectory = path.join(zone.gateway.stateDir, 'agents', 'main', 'agent');\n\t\tawait fs.mkdir(authProfilesDirectory, { recursive: true, mode: 0o700 });\n\t\tawait fs.chmod(authProfilesDirectory, 0o700);\n\t\tconst authProfiles = await secretResolver.resolve(toSecretRef(authProfilesSecret));\n\t\tawait writeFileAtomically(\n\t\t\tpath.join(authProfilesDirectory, 'auth-profiles.json'),\n\t\t\tauthProfiles,\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 OpenClaw auth profiles for zone '${zone.id}' from '${describeSecretReference(authProfilesSecret)}': ${message}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\nasync function writeEffectiveOpenClawConfig(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): 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 gatewayToken = await secretResolver.resolve(toSecretRef(gatewayTokenSecret));\n\t\tconst rawBaseConfig = await fs.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: gatewayToken,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\tconst effectiveConfigPath = getEffectiveOpenClawConfigHostPath(zone);\n\t\tawait fs.mkdir(zone.gateway.stateDir, { recursive: true, mode: 0o700 });\n\t\tawait fs.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\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\t\tconst { OPENCLAW_GATEWAY_TOKEN: _gatewayToken, ...environmentSecretsWithoutGatewayToken } =\n\t\t\tenvironmentSecrets;\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_PLUGIN_STAGE_DIR: openClawPluginStageDirVmPath,\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\t...environmentSecretsWithoutGatewayToken,\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'/home/openclaw/workspace': {\n\t\t\t\t\thostPath: zone.gateway.workspaceDir,\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:\n\t\t\t\t'cd /home/openclaw && nohup openclaw gateway --port 18789 > /tmp/openclaw.log 2>&1 &',\n\t\t\thealthCheck: { type: 'http', port: 18789, path: '/' },\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, secretResolver);\n\t\tawait writeAuthProfilesIfConfigured(zone, secretResolver);\n\t},\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["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 openClawPluginStageDirVmPath = '/opt/openclaw/plugin-runtime-deps';\nconst openClawShellEnvFilePath = '/etc/profile.d/openclaw-env.sh';\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\t_zone: GatewayZoneConfig,\n\t_resolvedSecrets: Record<string, string>,\n): string {\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 OPENCLAW_PLUGIN_STAGE_DIR=${openClawPluginStageDirVmPath}`,\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\n\treturn (\n\t\t`mkdir -p /root /etc/profile.d /work/tmp /work/cache/npm /work/cache/pnpm/store /work/cache/pip /work/cache/uv && cat > ${openClawShellEnvFilePath} << ENVEOF\\n` +\n\t\tenvironmentLines.join('\\n') +\n\t\t'\\nENVEOF\\n' +\n\t\t`chmod 644 ${openClawShellEnvFilePath} && ` +\n\t\t'touch /root/.bashrc && ' +\n\t\t`grep -qxF 'source ${openClawShellEnvFilePath}' /root/.bashrc || echo 'source ${openClawShellEnvFilePath}' >> /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\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(\n\tzone: GatewayZoneConfig,\n\tsecretResolver: SecretResolver,\n): 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 gatewayToken = await secretResolver.resolve(toSecretRef(gatewayTokenSecret));\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: gatewayToken,\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};\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\t\tconst { OPENCLAW_GATEWAY_TOKEN: _gatewayToken, ...environmentSecretsWithoutGatewayToken } =\n\t\t\tenvironmentSecrets;\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_PLUGIN_STAGE_DIR: openClawPluginStageDirVmPath,\n\t\t\t\tOPENCLAW_STATE_DIR: openClawStateDirVmPath,\n\t\t\t\tPIP_CACHE_DIR: '/work/cache/pip',\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...environmentSecretsWithoutGatewayToken,\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:\n\t\t\t\t'cd /home/openclaw && nohup openclaw gateway --port 18789 > /tmp/openclaw.log 2>&1 &',\n\t\t\thealthCheck: {\n\t\t\t\ttype: 'command',\n\t\t\t\tcommand: `grep -q 'ready (' /tmp/openclaw.log`,\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, secretResolver);\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.31",
3
+ "version": "0.0.33",
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.31",
33
- "@agent-vm/gondolin-adapter": "0.0.31"
32
+ "@agent-vm/gateway-interface": "0.0.33",
33
+ "@agent-vm/gondolin-adapter": "0.0.33"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsdown",