@heretek-ai/openclaw 2026.3.27 → 2026.3.29

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.
@@ -0,0 +1,399 @@
1
+ import { n as DEFAULT_GATEWAY_PORT, u as resolveGatewayPort } from "./paths-CNST7z3O.mjs";
2
+ import { m as defaultRuntime } from "./subsystem-yLe4Gjha.mjs";
3
+ import { y as resolveUserPath } from "./utils-Dc9DiBqf.mjs";
4
+ import { d as readConfigFileSnapshot, g as writeConfigFile } from "./io-CDQGJKjg.mjs";
5
+ import { l as normalizeSecretInputString } from "./types.secrets-CKipkqRX.mjs";
6
+ import { t as formatCliCommand } from "./command-format-D1DrcTDP.mjs";
7
+ import { t as WizardCancelledError } from "./prompts-BqZHJHEi.mjs";
8
+ import { n as buildPluginCompatibilityNotices, o as formatPluginCompatibilityNotice } from "./status-Baz1y8H2.mjs";
9
+ import { t as resolveSetupSecretInputString } from "./setup.secret-input-DPX4L6ht.mjs";
10
+
11
+ //#region src/wizard/setup.ts
12
+ async function requireRiskAcknowledgement(params) {
13
+ if (params.opts.acceptRisk === true) return;
14
+ await params.prompter.note([
15
+ "Security warning — please read.",
16
+ "",
17
+ "OpenClaw is a hobby project and still in beta. Expect sharp edges.",
18
+ "By default, OpenClaw is a personal agent: one trusted operator boundary.",
19
+ "This bot can read files and run actions if tools are enabled.",
20
+ "A bad prompt can trick it into doing unsafe things.",
21
+ "",
22
+ "OpenClaw is not a hostile multi-tenant boundary by default.",
23
+ "If multiple users can message one tool-enabled agent, they share that delegated tool authority.",
24
+ "",
25
+ "If you’re not comfortable with security hardening and access control, don’t run OpenClaw.",
26
+ "Ask someone experienced to help before enabling tools or exposing it to the internet.",
27
+ "",
28
+ "Recommended baseline:",
29
+ "- Pairing/allowlists + mention gating.",
30
+ "- Multi-user/shared inbox: split trust boundaries (separate gateway/credentials, ideally separate OS users/hosts).",
31
+ "- Sandbox + least-privilege tools.",
32
+ "- Shared inboxes: isolate DM sessions (`session.dmScope: per-channel-peer`) and keep tool access minimal.",
33
+ "- Keep secrets out of the agent’s reachable filesystem.",
34
+ "- Use the strongest available model for any bot with tools or untrusted inboxes.",
35
+ "",
36
+ "Run regularly:",
37
+ "openclaw security audit --deep",
38
+ "openclaw security audit --fix",
39
+ "",
40
+ "Must read: https://docs.openclaw.ai/gateway/security"
41
+ ].join("\n"), "Security");
42
+ if (!await params.prompter.confirm({
43
+ message: "I understand this is personal-by-default and shared/multi-user use requires lock-down. Continue?",
44
+ initialValue: false
45
+ })) throw new WizardCancelledError("risk not accepted");
46
+ }
47
+ async function runSetupWizard(opts, runtime = defaultRuntime, prompter) {
48
+ const onboardHelpers = await import("./onboard-helpers-yNblKlzQ.mjs");
49
+ onboardHelpers.printWizardHeader(runtime);
50
+ await prompter.intro("OpenClaw setup");
51
+ await requireRiskAcknowledgement({
52
+ opts,
53
+ prompter
54
+ });
55
+ const snapshot = await readConfigFileSnapshot();
56
+ let baseConfig = snapshot.valid ? snapshot.exists ? snapshot.config : {} : {};
57
+ if (snapshot.exists && !snapshot.valid) {
58
+ await prompter.note(onboardHelpers.summarizeExistingConfig(baseConfig), "Invalid config");
59
+ if (snapshot.issues.length > 0) await prompter.note([
60
+ ...snapshot.issues.map((iss) => `- ${iss.path}: ${iss.message}`),
61
+ "",
62
+ "Docs: https://docs.openclaw.ai/gateway/configuration"
63
+ ].join("\n"), "Config issues");
64
+ await prompter.outro(`Config invalid. Run \`${formatCliCommand("openclaw doctor")}\` to repair it, then re-run setup.`);
65
+ runtime.exit(1);
66
+ return;
67
+ }
68
+ const compatibilityNotices = snapshot.valid ? buildPluginCompatibilityNotices({ config: baseConfig }) : [];
69
+ if (compatibilityNotices.length > 0) await prompter.note([
70
+ `Detected ${compatibilityNotices.length} plugin compatibility notice${compatibilityNotices.length === 1 ? "" : "s"} in the current config.`,
71
+ ...compatibilityNotices.slice(0, 4).map((notice) => `- ${formatPluginCompatibilityNotice(notice)}`),
72
+ ...compatibilityNotices.length > 4 ? [`- ... +${compatibilityNotices.length - 4} more`] : [],
73
+ "",
74
+ `Review: ${formatCliCommand("openclaw doctor")}`,
75
+ `Inspect: ${formatCliCommand("openclaw plugins inspect --all")}`
76
+ ].join("\n"), "Plugin compatibility");
77
+ const quickstartHint = `Configure details later via ${formatCliCommand("openclaw configure")}.`;
78
+ const manualHint = "Configure port, network, Tailscale, and auth options.";
79
+ const explicitFlowRaw = opts.flow?.trim();
80
+ const normalizedExplicitFlow = explicitFlowRaw === "manual" ? "advanced" : explicitFlowRaw;
81
+ if (normalizedExplicitFlow && normalizedExplicitFlow !== "quickstart" && normalizedExplicitFlow !== "advanced") {
82
+ runtime.error("Invalid --flow (use quickstart, manual, or advanced).");
83
+ runtime.exit(1);
84
+ return;
85
+ }
86
+ let flow = (normalizedExplicitFlow === "quickstart" || normalizedExplicitFlow === "advanced" ? normalizedExplicitFlow : void 0) ?? await prompter.select({
87
+ message: "Setup mode",
88
+ options: [{
89
+ value: "quickstart",
90
+ label: "QuickStart",
91
+ hint: quickstartHint
92
+ }, {
93
+ value: "advanced",
94
+ label: "Manual",
95
+ hint: manualHint
96
+ }],
97
+ initialValue: "quickstart"
98
+ });
99
+ if (opts.mode === "remote" && flow === "quickstart") {
100
+ await prompter.note("QuickStart only supports local gateways. Switching to Manual mode.", "QuickStart");
101
+ flow = "advanced";
102
+ }
103
+ if (snapshot.exists) {
104
+ await prompter.note(onboardHelpers.summarizeExistingConfig(baseConfig), "Existing config detected");
105
+ if (await prompter.select({
106
+ message: "Config handling",
107
+ options: [
108
+ {
109
+ value: "keep",
110
+ label: "Use existing values"
111
+ },
112
+ {
113
+ value: "modify",
114
+ label: "Update values"
115
+ },
116
+ {
117
+ value: "reset",
118
+ label: "Reset"
119
+ }
120
+ ]
121
+ }) === "reset") {
122
+ const workspaceDefault = baseConfig.agents?.defaults?.workspace ?? onboardHelpers.DEFAULT_WORKSPACE;
123
+ const resetScope = await prompter.select({
124
+ message: "Reset scope",
125
+ options: [
126
+ {
127
+ value: "config",
128
+ label: "Config only"
129
+ },
130
+ {
131
+ value: "config+creds+sessions",
132
+ label: "Config + creds + sessions"
133
+ },
134
+ {
135
+ value: "full",
136
+ label: "Full reset (config + creds + sessions + workspace)"
137
+ }
138
+ ]
139
+ });
140
+ await onboardHelpers.handleReset(resetScope, resolveUserPath(workspaceDefault), runtime);
141
+ baseConfig = {};
142
+ }
143
+ }
144
+ const quickstartGateway = (() => {
145
+ const hasExisting = typeof baseConfig.gateway?.port === "number" || baseConfig.gateway?.bind !== void 0 || baseConfig.gateway?.auth?.mode !== void 0 || baseConfig.gateway?.auth?.token !== void 0 || baseConfig.gateway?.auth?.password !== void 0 || baseConfig.gateway?.customBindHost !== void 0 || baseConfig.gateway?.tailscale?.mode !== void 0;
146
+ const bindRaw = baseConfig.gateway?.bind;
147
+ const bind = bindRaw === "loopback" || bindRaw === "lan" || bindRaw === "auto" || bindRaw === "custom" || bindRaw === "tailnet" ? bindRaw : "loopback";
148
+ let authMode = "token";
149
+ if (baseConfig.gateway?.auth?.mode === "token" || baseConfig.gateway?.auth?.mode === "password") authMode = baseConfig.gateway.auth.mode;
150
+ else if (baseConfig.gateway?.auth?.token) authMode = "token";
151
+ else if (baseConfig.gateway?.auth?.password) authMode = "password";
152
+ const tailscaleRaw = baseConfig.gateway?.tailscale?.mode;
153
+ const tailscaleMode = tailscaleRaw === "off" || tailscaleRaw === "serve" || tailscaleRaw === "funnel" ? tailscaleRaw : "off";
154
+ return {
155
+ hasExisting,
156
+ port: resolveGatewayPort(baseConfig),
157
+ bind,
158
+ authMode,
159
+ tailscaleMode,
160
+ token: baseConfig.gateway?.auth?.token,
161
+ password: baseConfig.gateway?.auth?.password,
162
+ customBindHost: baseConfig.gateway?.customBindHost,
163
+ tailscaleResetOnExit: baseConfig.gateway?.tailscale?.resetOnExit ?? false
164
+ };
165
+ })();
166
+ if (flow === "quickstart") {
167
+ const formatBind = (value) => {
168
+ if (value === "loopback") return "Loopback (127.0.0.1)";
169
+ if (value === "lan") return "LAN";
170
+ if (value === "custom") return "Custom IP";
171
+ if (value === "tailnet") return "Tailnet (Tailscale IP)";
172
+ return "Auto";
173
+ };
174
+ const formatAuth = (value) => {
175
+ if (value === "token") return "Token (default)";
176
+ return "Password";
177
+ };
178
+ const formatTailscale = (value) => {
179
+ if (value === "off") return "Off";
180
+ if (value === "serve") return "Serve";
181
+ return "Funnel";
182
+ };
183
+ const quickstartLines = quickstartGateway.hasExisting ? [
184
+ "Keeping your current gateway settings:",
185
+ `Gateway port: ${quickstartGateway.port}`,
186
+ `Gateway bind: ${formatBind(quickstartGateway.bind)}`,
187
+ ...quickstartGateway.bind === "custom" && quickstartGateway.customBindHost ? [`Gateway custom IP: ${quickstartGateway.customBindHost}`] : [],
188
+ `Gateway auth: ${formatAuth(quickstartGateway.authMode)}`,
189
+ `Tailscale exposure: ${formatTailscale(quickstartGateway.tailscaleMode)}`,
190
+ "Direct to chat channels."
191
+ ] : [
192
+ `Gateway port: ${DEFAULT_GATEWAY_PORT}`,
193
+ "Gateway bind: Loopback (127.0.0.1)",
194
+ "Gateway auth: Token (default)",
195
+ "Tailscale exposure: Off",
196
+ "Direct to chat channels."
197
+ ];
198
+ await prompter.note(quickstartLines.join("\n"), "QuickStart");
199
+ }
200
+ const localPort = resolveGatewayPort(baseConfig);
201
+ const localUrl = `ws://127.0.0.1:${localPort}`;
202
+ let localGatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN;
203
+ try {
204
+ const resolvedGatewayToken = await resolveSetupSecretInputString({
205
+ config: baseConfig,
206
+ value: baseConfig.gateway?.auth?.token,
207
+ path: "gateway.auth.token",
208
+ env: process.env
209
+ });
210
+ if (resolvedGatewayToken) localGatewayToken = resolvedGatewayToken;
211
+ } catch (error) {
212
+ await prompter.note(["Could not resolve gateway.auth.token SecretRef for setup probe.", error instanceof Error ? error.message : String(error)].join("\n"), "Gateway auth");
213
+ }
214
+ let localGatewayPassword = process.env.OPENCLAW_GATEWAY_PASSWORD;
215
+ try {
216
+ const resolvedGatewayPassword = await resolveSetupSecretInputString({
217
+ config: baseConfig,
218
+ value: baseConfig.gateway?.auth?.password,
219
+ path: "gateway.auth.password",
220
+ env: process.env
221
+ });
222
+ if (resolvedGatewayPassword) localGatewayPassword = resolvedGatewayPassword;
223
+ } catch (error) {
224
+ await prompter.note(["Could not resolve gateway.auth.password SecretRef for setup probe.", error instanceof Error ? error.message : String(error)].join("\n"), "Gateway auth");
225
+ }
226
+ const localProbe = await onboardHelpers.probeGatewayReachable({
227
+ url: localUrl,
228
+ token: localGatewayToken,
229
+ password: localGatewayPassword
230
+ });
231
+ const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? "";
232
+ let remoteGatewayToken = normalizeSecretInputString(baseConfig.gateway?.remote?.token);
233
+ try {
234
+ const resolvedRemoteGatewayToken = await resolveSetupSecretInputString({
235
+ config: baseConfig,
236
+ value: baseConfig.gateway?.remote?.token,
237
+ path: "gateway.remote.token",
238
+ env: process.env
239
+ });
240
+ if (resolvedRemoteGatewayToken) remoteGatewayToken = resolvedRemoteGatewayToken;
241
+ } catch (error) {
242
+ await prompter.note(["Could not resolve gateway.remote.token SecretRef for setup probe.", error instanceof Error ? error.message : String(error)].join("\n"), "Gateway auth");
243
+ }
244
+ const remoteProbe = remoteUrl ? await onboardHelpers.probeGatewayReachable({
245
+ url: remoteUrl,
246
+ token: remoteGatewayToken
247
+ }) : null;
248
+ const mode = opts.mode ?? (flow === "quickstart" ? "local" : await prompter.select({
249
+ message: "What do you want to set up?",
250
+ options: [{
251
+ value: "local",
252
+ label: "Local gateway (this machine)",
253
+ hint: localProbe.ok ? `Gateway reachable (${localUrl})` : `No gateway detected (${localUrl})`
254
+ }, {
255
+ value: "remote",
256
+ label: "Remote gateway (info-only)",
257
+ hint: !remoteUrl ? "No remote URL configured yet" : remoteProbe?.ok ? `Gateway reachable (${remoteUrl})` : `Configured but unreachable (${remoteUrl})`
258
+ }]
259
+ }));
260
+ if (mode === "remote") {
261
+ const { promptRemoteGatewayConfig } = await import("./onboard-remote-CRNeWdAr.mjs");
262
+ const { logConfigUpdated: logConfigUpdated$1 } = await import("./logging-CMnQ2lwx.mjs");
263
+ let nextConfig$1 = await promptRemoteGatewayConfig(baseConfig, prompter, { secretInputMode: opts.secretInputMode });
264
+ nextConfig$1 = onboardHelpers.applyWizardMetadata(nextConfig$1, {
265
+ command: "onboard",
266
+ mode
267
+ });
268
+ await writeConfigFile(nextConfig$1);
269
+ logConfigUpdated$1(runtime);
270
+ await prompter.outro("Remote gateway configured.");
271
+ return;
272
+ }
273
+ const workspaceDir = resolveUserPath((opts.workspace ?? (flow === "quickstart" ? baseConfig.agents?.defaults?.workspace ?? onboardHelpers.DEFAULT_WORKSPACE : await prompter.text({
274
+ message: "Workspace directory",
275
+ initialValue: baseConfig.agents?.defaults?.workspace ?? onboardHelpers.DEFAULT_WORKSPACE
276
+ }))).trim() || onboardHelpers.DEFAULT_WORKSPACE);
277
+ const { applyLocalSetupWorkspaceConfig } = await import("./onboard-config-DDVUZ_ep.mjs");
278
+ let nextConfig = applyLocalSetupWorkspaceConfig(baseConfig, workspaceDir);
279
+ const { ensureAuthProfileStore } = await import("./auth-profiles.runtime-CBC0dso5.mjs");
280
+ const { promptAuthChoiceGrouped } = await import("./auth-choice-prompt-BQyfn30v.mjs");
281
+ const { promptCustomApiConfig } = await import("./onboard-custom-NVhhzO9B.mjs");
282
+ const { applyAuthChoice, resolvePreferredProviderForAuthChoice, warnIfModelConfigLooksOff } = await import("./auth-choice-CqTHhkAf.mjs");
283
+ const { applyPrimaryModel, promptDefaultModel } = await import("./model-picker-CsiewqeZ.mjs");
284
+ const authStore = ensureAuthProfileStore(void 0, { allowKeychainPrompt: false });
285
+ const authChoiceFromPrompt = opts.authChoice === void 0;
286
+ const authChoice = opts.authChoice ?? await promptAuthChoiceGrouped({
287
+ prompter,
288
+ store: authStore,
289
+ includeSkip: true,
290
+ config: nextConfig,
291
+ workspaceDir
292
+ });
293
+ if (authChoice === "custom-api-key") nextConfig = (await promptCustomApiConfig({
294
+ prompter,
295
+ runtime,
296
+ config: nextConfig,
297
+ secretInputMode: opts.secretInputMode
298
+ })).config;
299
+ else {
300
+ const authResult = await applyAuthChoice({
301
+ authChoice,
302
+ config: nextConfig,
303
+ prompter,
304
+ runtime,
305
+ setDefaultModel: true,
306
+ opts: {
307
+ tokenProvider: opts.tokenProvider,
308
+ token: opts.authChoice === "apiKey" && opts.token ? opts.token : void 0
309
+ }
310
+ });
311
+ nextConfig = authResult.config;
312
+ if (authResult.agentModelOverride) nextConfig = applyPrimaryModel(nextConfig, authResult.agentModelOverride);
313
+ }
314
+ if (authChoice !== "custom-api-key" && (authChoiceFromPrompt || authChoice === "ollama")) {
315
+ const modelSelection = await promptDefaultModel({
316
+ config: nextConfig,
317
+ prompter,
318
+ allowKeep: authChoice !== "ollama",
319
+ ignoreAllowlist: true,
320
+ includeProviderPluginSetups: true,
321
+ preferredProvider: await resolvePreferredProviderForAuthChoice({
322
+ choice: authChoice,
323
+ config: nextConfig,
324
+ workspaceDir
325
+ }),
326
+ workspaceDir,
327
+ runtime
328
+ });
329
+ if (modelSelection.config) nextConfig = modelSelection.config;
330
+ if (modelSelection.model) nextConfig = applyPrimaryModel(nextConfig, modelSelection.model);
331
+ }
332
+ await warnIfModelConfigLooksOff(nextConfig, prompter);
333
+ const { configureGatewayForSetup } = await import("./setup.gateway-config-D56aZGFi.mjs");
334
+ const gateway = await configureGatewayForSetup({
335
+ flow,
336
+ baseConfig,
337
+ nextConfig,
338
+ localPort,
339
+ quickstartGateway,
340
+ secretInputMode: opts.secretInputMode,
341
+ prompter,
342
+ runtime
343
+ });
344
+ nextConfig = gateway.nextConfig;
345
+ const settings = gateway.settings;
346
+ if (opts.skipChannels ?? opts.skipProviders) await prompter.note("Skipping channel setup.", "Channels");
347
+ else {
348
+ const { listChannelPlugins } = await import("./plugins-BlfLo1YX.mjs");
349
+ const { setupChannels } = await import("./onboard-channels-Bjl7Zcw9.mjs");
350
+ const quickstartAllowFromChannels = flow === "quickstart" ? listChannelPlugins().filter((plugin) => plugin.meta.quickstartAllowFrom).map((plugin) => plugin.id) : [];
351
+ nextConfig = await setupChannels(nextConfig, runtime, prompter, {
352
+ allowSignalInstall: true,
353
+ forceAllowFromChannels: quickstartAllowFromChannels,
354
+ skipDmPolicyPrompt: flow === "quickstart",
355
+ skipConfirm: flow === "quickstart",
356
+ quickstartDefaults: flow === "quickstart",
357
+ secretInputMode: opts.secretInputMode
358
+ });
359
+ }
360
+ await writeConfigFile(nextConfig);
361
+ const { logConfigUpdated } = await import("./logging-CMnQ2lwx.mjs");
362
+ logConfigUpdated(runtime);
363
+ await onboardHelpers.ensureWorkspaceAndSessions(workspaceDir, runtime, { skipBootstrap: Boolean(nextConfig.agents?.defaults?.skipBootstrap) });
364
+ if (opts.skipSearch) await prompter.note("Skipping search setup.", "Search");
365
+ else {
366
+ const { setupSearch } = await import("./onboard-search-DxFHQULC.mjs");
367
+ nextConfig = await setupSearch(nextConfig, runtime, prompter, {
368
+ quickstartDefaults: flow === "quickstart",
369
+ secretInputMode: opts.secretInputMode
370
+ });
371
+ }
372
+ if (opts.skipSkills) await prompter.note("Skipping skills setup.", "Skills");
373
+ else {
374
+ const { setupSkills } = await import("./onboard-skills-DpIv1YxW.mjs");
375
+ nextConfig = await setupSkills(nextConfig, workspaceDir, runtime, prompter);
376
+ }
377
+ const { setupInternalHooks } = await import("./onboard-hooks-CtPGBMBE.mjs");
378
+ nextConfig = await setupInternalHooks(nextConfig, runtime, prompter);
379
+ nextConfig = onboardHelpers.applyWizardMetadata(nextConfig, {
380
+ command: "onboard",
381
+ mode
382
+ });
383
+ await writeConfigFile(nextConfig);
384
+ const { finalizeSetupWizard } = await import("./setup.finalize-DvAFcLhU.mjs");
385
+ const { launchedTui } = await finalizeSetupWizard({
386
+ flow,
387
+ opts,
388
+ baseConfig,
389
+ nextConfig,
390
+ workspaceDir,
391
+ settings,
392
+ prompter,
393
+ runtime
394
+ });
395
+ if (launchedTui) return;
396
+ }
397
+
398
+ //#endregion
399
+ export { runSetupWizard as t };