clawup 1.0.0

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.
Files changed (190) hide show
  1. package/README.md +245 -0
  2. package/dist/adapters/api-adapter.d.ts +76 -0
  3. package/dist/adapters/api-adapter.js +250 -0
  4. package/dist/adapters/api-adapter.js.map +1 -0
  5. package/dist/adapters/cli-adapter.d.ts +15 -0
  6. package/dist/adapters/cli-adapter.js +208 -0
  7. package/dist/adapters/cli-adapter.js.map +1 -0
  8. package/dist/adapters/index.d.ts +22 -0
  9. package/dist/adapters/index.js +32 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/adapters/types.d.ts +135 -0
  12. package/dist/adapters/types.js +14 -0
  13. package/dist/adapters/types.js.map +1 -0
  14. package/dist/bin.d.ts +8 -0
  15. package/dist/bin.js +221 -0
  16. package/dist/bin.js.map +1 -0
  17. package/dist/commands/config.d.ts +21 -0
  18. package/dist/commands/config.js +323 -0
  19. package/dist/commands/config.js.map +1 -0
  20. package/dist/commands/deploy.d.ts +7 -0
  21. package/dist/commands/deploy.js +13 -0
  22. package/dist/commands/deploy.js.map +1 -0
  23. package/dist/commands/destroy.d.ts +7 -0
  24. package/dist/commands/destroy.js +13 -0
  25. package/dist/commands/destroy.js.map +1 -0
  26. package/dist/commands/init.d.ts +13 -0
  27. package/dist/commands/init.js +698 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/list.d.ts +8 -0
  30. package/dist/commands/list.js +42 -0
  31. package/dist/commands/list.js.map +1 -0
  32. package/dist/commands/push.d.ts +7 -0
  33. package/dist/commands/push.js +19 -0
  34. package/dist/commands/push.js.map +1 -0
  35. package/dist/commands/redeploy.d.ts +7 -0
  36. package/dist/commands/redeploy.js +13 -0
  37. package/dist/commands/redeploy.js.map +1 -0
  38. package/dist/commands/secrets.d.ts +16 -0
  39. package/dist/commands/secrets.js +169 -0
  40. package/dist/commands/secrets.js.map +1 -0
  41. package/dist/commands/ssh.d.ts +9 -0
  42. package/dist/commands/ssh.js +108 -0
  43. package/dist/commands/ssh.js.map +1 -0
  44. package/dist/commands/status.d.ts +7 -0
  45. package/dist/commands/status.js +13 -0
  46. package/dist/commands/status.js.map +1 -0
  47. package/dist/commands/update.d.ts +7 -0
  48. package/dist/commands/update.js +126 -0
  49. package/dist/commands/update.js.map +1 -0
  50. package/dist/commands/validate.d.ts +7 -0
  51. package/dist/commands/validate.js +13 -0
  52. package/dist/commands/validate.js.map +1 -0
  53. package/dist/commands/webhooks.d.ts +7 -0
  54. package/dist/commands/webhooks.js +13 -0
  55. package/dist/commands/webhooks.js.map +1 -0
  56. package/dist/lib/__tests__/identity.test.d.ts +1 -0
  57. package/dist/lib/__tests__/identity.test.js +186 -0
  58. package/dist/lib/__tests__/identity.test.js.map +1 -0
  59. package/dist/lib/__tests__/validate-agent.test.d.ts +1 -0
  60. package/dist/lib/__tests__/validate-agent.test.js +38 -0
  61. package/dist/lib/__tests__/validate-agent.test.js.map +1 -0
  62. package/dist/lib/config.d.ts +69 -0
  63. package/dist/lib/config.js +218 -0
  64. package/dist/lib/config.js.map +1 -0
  65. package/dist/lib/constants.d.ts +5 -0
  66. package/dist/lib/constants.js +29 -0
  67. package/dist/lib/constants.js.map +1 -0
  68. package/dist/lib/exec.d.ts +24 -0
  69. package/dist/lib/exec.js +63 -0
  70. package/dist/lib/exec.js.map +1 -0
  71. package/dist/lib/prerequisites.d.ts +8 -0
  72. package/dist/lib/prerequisites.js +146 -0
  73. package/dist/lib/prerequisites.js.map +1 -0
  74. package/dist/lib/process.d.ts +18 -0
  75. package/dist/lib/process.js +37 -0
  76. package/dist/lib/process.js.map +1 -0
  77. package/dist/lib/pulumi.d.ts +37 -0
  78. package/dist/lib/pulumi.js +87 -0
  79. package/dist/lib/pulumi.js.map +1 -0
  80. package/dist/lib/tailscale.d.ts +75 -0
  81. package/dist/lib/tailscale.js +251 -0
  82. package/dist/lib/tailscale.js.map +1 -0
  83. package/dist/lib/tool-helpers.d.ts +15 -0
  84. package/dist/lib/tool-helpers.js +35 -0
  85. package/dist/lib/tool-helpers.js.map +1 -0
  86. package/dist/lib/ui.d.ts +26 -0
  87. package/dist/lib/ui.js +86 -0
  88. package/dist/lib/ui.js.map +1 -0
  89. package/dist/lib/update-check.d.ts +8 -0
  90. package/dist/lib/update-check.js +151 -0
  91. package/dist/lib/update-check.js.map +1 -0
  92. package/dist/lib/vendor.d.ts +34 -0
  93. package/dist/lib/vendor.js +128 -0
  94. package/dist/lib/vendor.js.map +1 -0
  95. package/dist/lib/workspace.d.ts +21 -0
  96. package/dist/lib/workspace.js +170 -0
  97. package/dist/lib/workspace.js.map +1 -0
  98. package/dist/tools/deploy.d.ts +16 -0
  99. package/dist/tools/deploy.js +181 -0
  100. package/dist/tools/deploy.js.map +1 -0
  101. package/dist/tools/destroy.d.ts +16 -0
  102. package/dist/tools/destroy.js +119 -0
  103. package/dist/tools/destroy.js.map +1 -0
  104. package/dist/tools/index.d.ts +20 -0
  105. package/dist/tools/index.js +34 -0
  106. package/dist/tools/index.js.map +1 -0
  107. package/dist/tools/push.d.ts +29 -0
  108. package/dist/tools/push.js +341 -0
  109. package/dist/tools/push.js.map +1 -0
  110. package/dist/tools/redeploy.d.ts +17 -0
  111. package/dist/tools/redeploy.js +181 -0
  112. package/dist/tools/redeploy.js.map +1 -0
  113. package/dist/tools/status.d.ts +16 -0
  114. package/dist/tools/status.js +205 -0
  115. package/dist/tools/status.js.map +1 -0
  116. package/dist/tools/validate.d.ts +16 -0
  117. package/dist/tools/validate.js +219 -0
  118. package/dist/tools/validate.js.map +1 -0
  119. package/dist/tools/webhooks.d.ts +17 -0
  120. package/dist/tools/webhooks.js +181 -0
  121. package/dist/tools/webhooks.js.map +1 -0
  122. package/dist/types.d.ts +6 -0
  123. package/dist/types.js +10 -0
  124. package/dist/types.js.map +1 -0
  125. package/infra/Pulumi.yaml +6 -0
  126. package/infra/dist/components/cloud-init.js +412 -0
  127. package/infra/dist/components/config-generator.js +254 -0
  128. package/infra/dist/components/hetzner-agent.js +162 -0
  129. package/infra/dist/components/index.js +18 -0
  130. package/infra/dist/components/openclaw-agent.js +287 -0
  131. package/infra/dist/components/shared.js +132 -0
  132. package/infra/dist/components/types.js +6 -0
  133. package/infra/dist/index.js +387 -0
  134. package/infra/dist/shared-vpc.js +167 -0
  135. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts +2 -0
  136. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts.map +1 -0
  137. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js +124 -0
  138. package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js.map +1 -0
  139. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts +32 -0
  140. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts.map +1 -0
  141. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js +56 -0
  142. package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js.map +1 -0
  143. package/infra/node_modules/@clawup/core/dist/constants.d.ts +137 -0
  144. package/infra/node_modules/@clawup/core/dist/constants.d.ts.map +1 -0
  145. package/infra/node_modules/@clawup/core/dist/constants.js +314 -0
  146. package/infra/node_modules/@clawup/core/dist/constants.js.map +1 -0
  147. package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts +25 -0
  148. package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts.map +1 -0
  149. package/infra/node_modules/@clawup/core/dist/dep-registry.js +46 -0
  150. package/infra/node_modules/@clawup/core/dist/dep-registry.js.map +1 -0
  151. package/infra/node_modules/@clawup/core/dist/deps.d.ts +18 -0
  152. package/infra/node_modules/@clawup/core/dist/deps.d.ts.map +1 -0
  153. package/infra/node_modules/@clawup/core/dist/deps.js +39 -0
  154. package/infra/node_modules/@clawup/core/dist/deps.js.map +1 -0
  155. package/infra/node_modules/@clawup/core/dist/identity.d.ts +20 -0
  156. package/infra/node_modules/@clawup/core/dist/identity.d.ts.map +1 -0
  157. package/infra/node_modules/@clawup/core/dist/identity.js +217 -0
  158. package/infra/node_modules/@clawup/core/dist/identity.js.map +1 -0
  159. package/infra/node_modules/@clawup/core/dist/index.d.ts +18 -0
  160. package/infra/node_modules/@clawup/core/dist/index.d.ts.map +1 -0
  161. package/infra/node_modules/@clawup/core/dist/index.js +52 -0
  162. package/infra/node_modules/@clawup/core/dist/index.js.map +1 -0
  163. package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts +13 -0
  164. package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts.map +1 -0
  165. package/infra/node_modules/@clawup/core/dist/plugin-registry.js +24 -0
  166. package/infra/node_modules/@clawup/core/dist/plugin-registry.js.map +1 -0
  167. package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts +74 -0
  168. package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts.map +1 -0
  169. package/infra/node_modules/@clawup/core/dist/schemas/identity.js +45 -0
  170. package/infra/node_modules/@clawup/core/dist/schemas/identity.js.map +1 -0
  171. package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts +6 -0
  172. package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts.map +1 -0
  173. package/infra/node_modules/@clawup/core/dist/schemas/index.js +13 -0
  174. package/infra/node_modules/@clawup/core/dist/schemas/index.js.map +1 -0
  175. package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts +159 -0
  176. package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts.map +1 -0
  177. package/infra/node_modules/@clawup/core/dist/schemas/manifest.js +54 -0
  178. package/infra/node_modules/@clawup/core/dist/schemas/manifest.js.map +1 -0
  179. package/infra/node_modules/@clawup/core/dist/skills.d.ts +30 -0
  180. package/infra/node_modules/@clawup/core/dist/skills.d.ts.map +1 -0
  181. package/infra/node_modules/@clawup/core/dist/skills.js +52 -0
  182. package/infra/node_modules/@clawup/core/dist/skills.js.map +1 -0
  183. package/infra/node_modules/@clawup/core/dist/types.d.ts +59 -0
  184. package/infra/node_modules/@clawup/core/dist/types.d.ts.map +1 -0
  185. package/infra/node_modules/@clawup/core/dist/types.js +30 -0
  186. package/infra/node_modules/@clawup/core/dist/types.js.map +1 -0
  187. package/infra/node_modules/@clawup/core/package.json +46 -0
  188. package/infra/package.json +12 -0
  189. package/package.json +43 -0
  190. package/scripts/postinstall.mjs +395 -0
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ /**
3
+ * OpenClaw configuration generator
4
+ * Builds the openclaw.json configuration file content
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.generateOpenClawConfig = generateOpenClawConfig;
8
+ exports.generateOpenClawConfigJson = generateOpenClawConfigJson;
9
+ exports.generateConfigPatchScript = generateConfigPatchScript;
10
+ const core_1 = require("@clawup/core");
11
+ /**
12
+ * Generates an openclaw.json configuration object
13
+ */
14
+ function generateOpenClawConfig(options) {
15
+ const config = {
16
+ gateway: {
17
+ port: options.gatewayPort ?? 18789,
18
+ bind: "127.0.0.1", // Bind to loopback for Tailscale Serve
19
+ trustedProxies: options.trustedProxies ?? ["127.0.0.1"],
20
+ controlUi: {
21
+ enabled: options.enableControlUi ?? true,
22
+ allowInsecureAuth: true, // Safe behind Tailscale
23
+ },
24
+ auth: {
25
+ mode: "token",
26
+ token: options.gatewayToken,
27
+ },
28
+ },
29
+ };
30
+ if (options.browserPort) {
31
+ config.browser = {
32
+ port: options.browserPort,
33
+ };
34
+ }
35
+ if (options.enableSandbox !== undefined) {
36
+ config.sandbox = {
37
+ enabled: options.enableSandbox,
38
+ };
39
+ }
40
+ // Note: model config is now handled in generateConfigPatchScript() via agents.defaults.model
41
+ if (options.braveApiKey) {
42
+ config.web = { braveApiKey: options.braveApiKey };
43
+ }
44
+ // Merge custom config
45
+ if (options.customConfig) {
46
+ Object.assign(config, options.customConfig);
47
+ }
48
+ return config;
49
+ }
50
+ /**
51
+ * Generates openclaw.json as a JSON string
52
+ */
53
+ function generateOpenClawConfigJson(options) {
54
+ return JSON.stringify(generateOpenClawConfig(options), null, 2);
55
+ }
56
+ /**
57
+ * Generates Python code to configure a single plugin in openclaw.json.
58
+ * Secrets are injected from environment variables.
59
+ *
60
+ * Slack is special-cased: it writes to config["channels"]["slack"] (channel config)
61
+ * AND config["plugins"]["entries"]["slack"] (plugin entry).
62
+ */
63
+ function generatePluginPython(plugin) {
64
+ if (plugin.name === "slack") {
65
+ return generateSlackPluginPython(plugin);
66
+ }
67
+ // Build the config dict, injecting secrets from env vars
68
+ const configEntries = [];
69
+ // Secret env var values
70
+ if (plugin.secretEnvVars) {
71
+ for (const [configKey, envVar] of Object.entries(plugin.secretEnvVars)) {
72
+ configEntries.push(` "${configKey}": os.environ.get("${envVar}", "")`);
73
+ }
74
+ }
75
+ // Non-secret config values
76
+ for (const [key, value] of Object.entries(plugin.config)) {
77
+ configEntries.push(` "${key}": ${JSON.stringify(value)}`);
78
+ }
79
+ const configBlock = configEntries.length > 0
80
+ ? `{
81
+ ${configEntries.join(",\n")}
82
+ }`
83
+ : "{}";
84
+ return `
85
+ # Configure ${plugin.name} plugin
86
+ config.setdefault("plugins", {})
87
+ config["plugins"].setdefault("entries", {})
88
+ config["plugins"]["entries"]["${plugin.name}"] = {
89
+ "enabled": ${plugin.enabled ? "True" : "False"},
90
+ "config": ${configBlock}
91
+ }
92
+ print("Configured ${plugin.name} plugin")
93
+ `;
94
+ }
95
+ /**
96
+ * Generates Python code for Slack channel + plugin configuration.
97
+ * Slack writes to config["channels"]["slack"] with secrets from env vars
98
+ * and non-secret config from plugin defaults, plus enables the plugin entry.
99
+ */
100
+ function generateSlackPluginPython(plugin) {
101
+ // Build channel config entries from non-secret plugin config
102
+ const channelEntries = [];
103
+ // Secret env var values (botToken, appToken)
104
+ if (plugin.secretEnvVars) {
105
+ for (const [configKey, envVar] of Object.entries(plugin.secretEnvVars)) {
106
+ channelEntries.push(` "${configKey}": os.environ.get("${envVar}", "")`);
107
+ }
108
+ }
109
+ // Non-secret config values (mode, userTokenReadOnly, groupPolicy, dm, etc.)
110
+ for (const [key, value] of Object.entries(plugin.config)) {
111
+ channelEntries.push(` "${key}": ${JSON.stringify(value)}`);
112
+ }
113
+ // Add enabled: True
114
+ channelEntries.push(` "enabled": True`);
115
+ const channelBlock = channelEntries.length > 0
116
+ ? `{
117
+ ${channelEntries.join(",\n")}
118
+ }`
119
+ : "{}";
120
+ return `
121
+ # Configure Slack channel (Socket Mode) and plugin
122
+ config.setdefault("channels", {})
123
+ config["channels"]["slack"] = ${channelBlock}
124
+ config.setdefault("plugins", {})
125
+ config["plugins"].setdefault("entries", {})
126
+ config["plugins"]["entries"]["slack"] = {"enabled": ${plugin.enabled ? "True" : "False"}}
127
+ print("Configured Slack channel with Socket Mode")
128
+ `;
129
+ }
130
+ /**
131
+ * Generates Python script for modifying existing openclaw.json
132
+ * Used in cloud-init after onboarding creates the initial config
133
+ */
134
+ function generateConfigPatchScript(options) {
135
+ const configPatches = {
136
+ trustedProxies: options.trustedProxies ?? ["127.0.0.1"],
137
+ enableControlUi: options.enableControlUi ?? true,
138
+ };
139
+ // Build model config (primary + optional fallbacks)
140
+ const model = options.model ?? "anthropic/claude-opus-4-6";
141
+ const backupModel = options.backupModel;
142
+ // Build cliBackends config from coding agent registry
143
+ const codingAgentName = options.codingAgent ?? "claude-code";
144
+ const codingAgentEntry = core_1.CODING_AGENT_REGISTRY[codingAgentName];
145
+ const cliBackendsJson = codingAgentEntry
146
+ ? JSON.stringify({ "claude-cli": codingAgentEntry.cliBackend })
147
+ : "{}";
148
+ // Build dynamic plugin config sections
149
+ const pluginConfigs = (options.plugins ?? [])
150
+ .map((plugin) => generatePluginPython(plugin))
151
+ .join("");
152
+ return `
153
+ import json
154
+ import os
155
+
156
+ config_path = "/home/ubuntu/.openclaw/openclaw.json"
157
+
158
+ with open(config_path) as f:
159
+ config = json.load(f)
160
+
161
+ # Configure gateway for Tailscale Serve
162
+ config["gateway"]["trustedProxies"] = ${JSON.stringify(configPatches.trustedProxies)}
163
+ config["gateway"]["controlUi"] = {
164
+ "enabled": ${configPatches.enableControlUi ? "True" : "False"},
165
+ "allowInsecureAuth": True
166
+ }
167
+ config["gateway"]["auth"] = {
168
+ "mode": "token",
169
+ "token": os.environ["GATEWAY_TOKEN"]
170
+ }
171
+
172
+ # Configure environment variables for child processes (including Claude Code, Linear CLI)
173
+ # Auto-detect credential type: OAuth token (oat) vs API key (api)
174
+ anthropic_cred = os.environ.get("ANTHROPIC_API_KEY", "")
175
+ if anthropic_cred.startswith("sk-ant-oat"):
176
+ # OAuth token from Claude Pro/Max subscription (use with CLAUDE_CODE_OAUTH_TOKEN)
177
+ config["env"] = {
178
+ "CLAUDE_CODE_OAUTH_TOKEN": anthropic_cred
179
+ }
180
+ print("Configured environment variables: CLAUDE_CODE_OAUTH_TOKEN (OAuth/subscription)")
181
+ else:
182
+ # API key from Anthropic Console (use with ANTHROPIC_API_KEY)
183
+ config["env"] = {
184
+ "ANTHROPIC_API_KEY": anthropic_cred
185
+ }
186
+ print("Configured environment variables: ANTHROPIC_API_KEY (API key)")
187
+
188
+ # Configure heartbeat (proactive mode)
189
+ config.setdefault("agents", {})
190
+ config["agents"].setdefault("defaults", {})
191
+ config["agents"]["defaults"]["heartbeat"] = {
192
+ "every": "1m",
193
+ "session": "main"
194
+ }
195
+ print("Configured heartbeat: every 1m")
196
+
197
+ # Configure model with optional fallbacks
198
+ ${backupModel
199
+ ? `config["agents"]["defaults"]["model"] = {
200
+ "primary": "${model}",
201
+ "fallbacks": ["${backupModel}"]
202
+ }
203
+ print("Configured model: ${model} (fallback: ${backupModel})")`
204
+ : `config["agents"]["defaults"]["model"] = "${model}"
205
+ print("Configured model: ${model}")`}
206
+
207
+ # Configure coding agent CLI backend
208
+ config["agents"]["defaults"]["cliBackends"] = ${cliBackendsJson}
209
+ print("Configured cliBackends for ${codingAgentName}")
210
+ ${pluginConfigs}
211
+ # Configure agent identity for Slack mentions/tags
212
+ agent_name = os.environ.get("AGENT_NAME", "")
213
+ agent_emoji = os.environ.get("AGENT_EMOJI", "")
214
+ if agent_name:
215
+ config.setdefault("agents", {})
216
+ config["agents"].setdefault("list", [])
217
+ # Find or create the "default" agent entry
218
+ default_agent = None
219
+ for agent in config["agents"]["list"]:
220
+ if agent.get("id") == "default":
221
+ default_agent = agent
222
+ break
223
+ if not default_agent:
224
+ default_agent = {"id": "default"}
225
+ config["agents"]["list"].append(default_agent)
226
+ default_agent.setdefault("identity", {})
227
+ default_agent["identity"]["name"] = agent_name
228
+ if agent_emoji:
229
+ default_agent["identity"]["emoji"] = agent_emoji
230
+ print(f"Configured agent identity: {agent_name} (:{agent_emoji}:)")
231
+
232
+ # Enable allowBots so agents can see each other's messages in shared channels
233
+ if "channels" in config and "slack" in config["channels"]:
234
+ config["channels"]["slack"]["allowBots"] = True
235
+ print("Enabled allowBots for Slack channel")
236
+
237
+ # Add ack reaction for visual feedback when processing messages
238
+ config.setdefault("messages", {})
239
+ config["messages"]["ackReaction"] = "eyes"
240
+ print("Configured ackReaction: eyes")
241
+
242
+ # Configure web search (Brave API key) if available
243
+ brave_api_key = os.environ.get("BRAVE_API_KEY", "")
244
+ if brave_api_key:
245
+ config["web"] = {"braveApiKey": brave_api_key}
246
+ print("Configured web search with Brave API key")
247
+
248
+ with open(config_path, "w") as f:
249
+ json.dump(config, f, indent=2)
250
+
251
+ print("Configured gateway with trustedProxies, controlUi, and token auth")
252
+ `.trim();
253
+ }
254
+ //# sourceMappingURL=config-generator.js.map
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ /**
3
+ * HetznerOpenClaw Agent - Reusable Pulumi ComponentResource
4
+ * Provisions a single OpenClaw agent on Hetzner Cloud
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.HetznerOpenClawAgent = void 0;
41
+ const pulumi = __importStar(require("@pulumi/pulumi"));
42
+ const hcloud = __importStar(require("@pulumi/hcloud"));
43
+ const shared_1 = require("./shared");
44
+ /**
45
+ * HetznerOpenClaw Agent ComponentResource
46
+ *
47
+ * Provisions a complete OpenClaw agent on Hetzner Cloud including:
48
+ * - SSH key for access
49
+ * - Firewall allowing only SSH inbound
50
+ * - Server with Ubuntu 24.04
51
+ * - Docker, Node.js 22, and OpenClaw installation
52
+ * - Tailscale for secure HTTPS access
53
+ * - Systemd service for auto-start
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const agent = new HetznerOpenClawAgent("my-agent", {
58
+ * anthropicApiKey: config.requireSecret("anthropicApiKey"),
59
+ * tailscaleAuthKey: config.requireSecret("tailscaleAuthKey"),
60
+ * tailnetDnsName: config.require("tailnetDnsName"),
61
+ * });
62
+ *
63
+ * export const url = agent.tailscaleUrl;
64
+ * ```
65
+ */
66
+ class HetznerOpenClawAgent extends pulumi.ComponentResource {
67
+ /** Server public IP (IPv4) */
68
+ publicIp;
69
+ /** Tailscale URL with authentication token */
70
+ tailscaleUrl;
71
+ /** Gateway authentication token */
72
+ gatewayToken;
73
+ /** SSH private key (Ed25519) */
74
+ sshPrivateKey;
75
+ /** SSH public key */
76
+ sshPublicKey;
77
+ /** Hetzner server ID */
78
+ serverId;
79
+ /** Firewall ID */
80
+ firewallId;
81
+ constructor(name, args, opts) {
82
+ super("clawup:hetzner:HetznerOpenClawAgent", name, {}, opts);
83
+ const defaultResourceOptions = { parent: this };
84
+ // Defaults
85
+ const serverType = args.serverType ?? "cx22";
86
+ const location = args.location ?? "nbg1";
87
+ const baseLabels = args.labels ?? {};
88
+ // Generate SSH key pair + gateway token
89
+ const { sshKey, gatewayTokenValue } = (0, shared_1.generateKeyPairAndToken)(name, defaultResourceOptions);
90
+ // Create Hetzner SSH key
91
+ const hcloudSshKey = new hcloud.SshKey(`${name}-sshkey`, {
92
+ publicKey: sshKey.publicKeyOpenssh,
93
+ labels: pulumi.output(baseLabels).apply((labels) => ({
94
+ ...labels,
95
+ name: name,
96
+ })),
97
+ }, defaultResourceOptions);
98
+ // Create firewall allowing only SSH inbound
99
+ const firewall = new hcloud.Firewall(`${name}-firewall`, {
100
+ labels: pulumi.output(baseLabels).apply((labels) => ({
101
+ ...labels,
102
+ name: name,
103
+ })),
104
+ // Only add SSH rule if allowedSshIps is explicitly provided
105
+ // Tailscale is the primary access method; SSH is optional fallback
106
+ rules: pulumi
107
+ .output(args.allowedSshIps ?? [])
108
+ .apply((ips) => ips.length > 0
109
+ ? [
110
+ {
111
+ direction: "in",
112
+ protocol: "tcp",
113
+ port: "22",
114
+ sourceIps: ips,
115
+ description: "SSH access (restricted)",
116
+ },
117
+ ]
118
+ : []),
119
+ }, defaultResourceOptions);
120
+ // Generate cloud-init user data (compressed for Hetzner's 32KB limit)
121
+ const userData = (0, shared_1.buildCloudInitUserData)(name, args, gatewayTokenValue, {
122
+ createUbuntuUser: true,
123
+ compress: true,
124
+ });
125
+ // Create Hetzner server
126
+ const server = new hcloud.Server(`${name}-server`, {
127
+ serverType: serverType,
128
+ image: "ubuntu-24.04",
129
+ location: location,
130
+ sshKeys: [hcloudSshKey.id],
131
+ firewallIds: [firewall.id.apply((id) => parseInt(id, 10))],
132
+ userData: userData,
133
+ labels: pulumi.output(baseLabels).apply((labels) => ({
134
+ ...labels,
135
+ name: name,
136
+ component: "openclaw-agent",
137
+ })),
138
+ }, defaultResourceOptions);
139
+ // Set outputs
140
+ this.publicIp = server.ipv4Address;
141
+ this.serverId = server.id;
142
+ this.firewallId = firewall.id;
143
+ this.sshPrivateKey = pulumi.secret(sshKey.privateKeyOpenssh);
144
+ this.sshPublicKey = sshKey.publicKeyOpenssh;
145
+ this.gatewayToken = pulumi.secret(gatewayTokenValue);
146
+ // Tailscale hostname includes stack name to avoid conflicts (e.g., dev-agent-pm)
147
+ const tsHostname = `${pulumi.getStack()}-${name}`;
148
+ this.tailscaleUrl = pulumi.secret(pulumi.interpolate `https://${tsHostname}.${args.tailnetDnsName}/?token=${gatewayTokenValue}`);
149
+ // Register outputs
150
+ this.registerOutputs({
151
+ publicIp: this.publicIp,
152
+ tailscaleUrl: this.tailscaleUrl,
153
+ gatewayToken: this.gatewayToken,
154
+ sshPrivateKey: this.sshPrivateKey,
155
+ sshPublicKey: this.sshPublicKey,
156
+ serverId: this.serverId,
157
+ firewallId: this.firewallId,
158
+ });
159
+ }
160
+ }
161
+ exports.HetznerOpenClawAgent = HetznerOpenClawAgent;
162
+ //# sourceMappingURL=hetzner-agent.js.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCloudInitUserData = exports.generateKeyPairAndToken = exports.generateConfigPatchScript = exports.generateOpenClawConfigJson = exports.generateOpenClawConfig = exports.interpolateCloudInit = exports.generateCloudInit = exports.HetznerOpenClawAgent = exports.OpenClawAgent = void 0;
4
+ var openclaw_agent_1 = require("./openclaw-agent");
5
+ Object.defineProperty(exports, "OpenClawAgent", { enumerable: true, get: function () { return openclaw_agent_1.OpenClawAgent; } });
6
+ var hetzner_agent_1 = require("./hetzner-agent");
7
+ Object.defineProperty(exports, "HetznerOpenClawAgent", { enumerable: true, get: function () { return hetzner_agent_1.HetznerOpenClawAgent; } });
8
+ var cloud_init_1 = require("./cloud-init");
9
+ Object.defineProperty(exports, "generateCloudInit", { enumerable: true, get: function () { return cloud_init_1.generateCloudInit; } });
10
+ Object.defineProperty(exports, "interpolateCloudInit", { enumerable: true, get: function () { return cloud_init_1.interpolateCloudInit; } });
11
+ var config_generator_1 = require("./config-generator");
12
+ Object.defineProperty(exports, "generateOpenClawConfig", { enumerable: true, get: function () { return config_generator_1.generateOpenClawConfig; } });
13
+ Object.defineProperty(exports, "generateOpenClawConfigJson", { enumerable: true, get: function () { return config_generator_1.generateOpenClawConfigJson; } });
14
+ Object.defineProperty(exports, "generateConfigPatchScript", { enumerable: true, get: function () { return config_generator_1.generateConfigPatchScript; } });
15
+ var shared_1 = require("./shared");
16
+ Object.defineProperty(exports, "generateKeyPairAndToken", { enumerable: true, get: function () { return shared_1.generateKeyPairAndToken; } });
17
+ Object.defineProperty(exports, "buildCloudInitUserData", { enumerable: true, get: function () { return shared_1.buildCloudInitUserData; } });
18
+ //# sourceMappingURL=index.js.map