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.
- package/README.md +245 -0
- package/dist/adapters/api-adapter.d.ts +76 -0
- package/dist/adapters/api-adapter.js +250 -0
- package/dist/adapters/api-adapter.js.map +1 -0
- package/dist/adapters/cli-adapter.d.ts +15 -0
- package/dist/adapters/cli-adapter.js +208 -0
- package/dist/adapters/cli-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +22 -0
- package/dist/adapters/index.js +32 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +135 -0
- package/dist/adapters/types.js +14 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.js +221 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/config.d.ts +21 -0
- package/dist/commands/config.js +323 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/deploy.d.ts +7 -0
- package/dist/commands/deploy.js +13 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/destroy.d.ts +7 -0
- package/dist/commands/destroy.js +13 -0
- package/dist/commands/destroy.js.map +1 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +698 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +8 -0
- package/dist/commands/list.js +42 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/push.d.ts +7 -0
- package/dist/commands/push.js +19 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/redeploy.d.ts +7 -0
- package/dist/commands/redeploy.js +13 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/secrets.d.ts +16 -0
- package/dist/commands/secrets.js +169 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +108 -0
- package/dist/commands/ssh.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +13 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.js +126 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.js +13 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/webhooks.d.ts +7 -0
- package/dist/commands/webhooks.js +13 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/lib/__tests__/identity.test.d.ts +1 -0
- package/dist/lib/__tests__/identity.test.js +186 -0
- package/dist/lib/__tests__/identity.test.js.map +1 -0
- package/dist/lib/__tests__/validate-agent.test.d.ts +1 -0
- package/dist/lib/__tests__/validate-agent.test.js +38 -0
- package/dist/lib/__tests__/validate-agent.test.js.map +1 -0
- package/dist/lib/config.d.ts +69 -0
- package/dist/lib/config.js +218 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +5 -0
- package/dist/lib/constants.js +29 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/exec.d.ts +24 -0
- package/dist/lib/exec.js +63 -0
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/prerequisites.d.ts +8 -0
- package/dist/lib/prerequisites.js +146 -0
- package/dist/lib/prerequisites.js.map +1 -0
- package/dist/lib/process.d.ts +18 -0
- package/dist/lib/process.js +37 -0
- package/dist/lib/process.js.map +1 -0
- package/dist/lib/pulumi.d.ts +37 -0
- package/dist/lib/pulumi.js +87 -0
- package/dist/lib/pulumi.js.map +1 -0
- package/dist/lib/tailscale.d.ts +75 -0
- package/dist/lib/tailscale.js +251 -0
- package/dist/lib/tailscale.js.map +1 -0
- package/dist/lib/tool-helpers.d.ts +15 -0
- package/dist/lib/tool-helpers.js +35 -0
- package/dist/lib/tool-helpers.js.map +1 -0
- package/dist/lib/ui.d.ts +26 -0
- package/dist/lib/ui.js +86 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/lib/update-check.d.ts +8 -0
- package/dist/lib/update-check.js +151 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/vendor.d.ts +34 -0
- package/dist/lib/vendor.js +128 -0
- package/dist/lib/vendor.js.map +1 -0
- package/dist/lib/workspace.d.ts +21 -0
- package/dist/lib/workspace.js +170 -0
- package/dist/lib/workspace.js.map +1 -0
- package/dist/tools/deploy.d.ts +16 -0
- package/dist/tools/deploy.js +181 -0
- package/dist/tools/deploy.js.map +1 -0
- package/dist/tools/destroy.d.ts +16 -0
- package/dist/tools/destroy.js +119 -0
- package/dist/tools/destroy.js.map +1 -0
- package/dist/tools/index.d.ts +20 -0
- package/dist/tools/index.js +34 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/push.d.ts +29 -0
- package/dist/tools/push.js +341 -0
- package/dist/tools/push.js.map +1 -0
- package/dist/tools/redeploy.d.ts +17 -0
- package/dist/tools/redeploy.js +181 -0
- package/dist/tools/redeploy.js.map +1 -0
- package/dist/tools/status.d.ts +16 -0
- package/dist/tools/status.js +205 -0
- package/dist/tools/status.js.map +1 -0
- package/dist/tools/validate.d.ts +16 -0
- package/dist/tools/validate.js +219 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tools/webhooks.d.ts +17 -0
- package/dist/tools/webhooks.js +181 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/infra/Pulumi.yaml +6 -0
- package/infra/dist/components/cloud-init.js +412 -0
- package/infra/dist/components/config-generator.js +254 -0
- package/infra/dist/components/hetzner-agent.js +162 -0
- package/infra/dist/components/index.js +18 -0
- package/infra/dist/components/openclaw-agent.js +287 -0
- package/infra/dist/components/shared.js +132 -0
- package/infra/dist/components/types.js +6 -0
- package/infra/dist/index.js +387 -0
- package/infra/dist/shared-vpc.js +167 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts +2 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js +124 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts +32 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js +56 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/constants.d.ts +137 -0
- package/infra/node_modules/@clawup/core/dist/constants.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/constants.js +314 -0
- package/infra/node_modules/@clawup/core/dist/constants.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts +25 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.js +46 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/deps.d.ts +18 -0
- package/infra/node_modules/@clawup/core/dist/deps.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/deps.js +39 -0
- package/infra/node_modules/@clawup/core/dist/deps.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/identity.d.ts +20 -0
- package/infra/node_modules/@clawup/core/dist/identity.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/identity.js +217 -0
- package/infra/node_modules/@clawup/core/dist/identity.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/index.d.ts +18 -0
- package/infra/node_modules/@clawup/core/dist/index.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/index.js +52 -0
- package/infra/node_modules/@clawup/core/dist/index.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts +13 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.js +24 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts +74 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.js +45 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts +6 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.js +13 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts +159 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.js +54 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/skills.d.ts +30 -0
- package/infra/node_modules/@clawup/core/dist/skills.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/skills.js +52 -0
- package/infra/node_modules/@clawup/core/dist/skills.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/types.d.ts +59 -0
- package/infra/node_modules/@clawup/core/dist/types.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/types.js +30 -0
- package/infra/node_modules/@clawup/core/dist/types.js.map +1 -0
- package/infra/node_modules/@clawup/core/package.json +46 -0
- package/infra/package.json +12 -0
- package/package.json +43 -0
- 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
|