@heretek-ai/openclaw 2026.3.30 → 2026.3.32
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/.buildstamp +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/chunks/command-registry-BeAmVjny.mjs +214 -0
- package/dist/chunks/command-registry-BnmWhMEa.mjs +214 -0
- package/dist/chunks/command-registry-CCc0vZoH.mjs +14 -0
- package/dist/chunks/command-registry-CLOY087q.mjs +14 -0
- package/dist/chunks/command-registry-CjAG33h3.mjs +14 -0
- package/dist/chunks/command-registry-DPx6M6gw.mjs +214 -0
- package/dist/chunks/completion-cli-BDWbmV-o.mjs +448 -0
- package/dist/chunks/completion-cli-CBrKGQfJ.mjs +17 -0
- package/dist/chunks/completion-cli-CpJ8IzQO.mjs +448 -0
- package/dist/chunks/completion-cli-CwouPhbG.mjs +17 -0
- package/dist/chunks/completion-cli-DuMZk0lN.mjs +448 -0
- package/dist/chunks/completion-cli-DxUdlYt0.mjs +17 -0
- package/dist/chunks/doctor-completion-1UqU9aiy.mjs +92 -0
- package/dist/chunks/doctor-completion-B_LLsQm-.mjs +92 -0
- package/dist/chunks/doctor-completion-CCuL-Cen.mjs +92 -0
- package/dist/chunks/gateway-cli-Bc4J6-zj.mjs +43508 -0
- package/dist/chunks/gateway-cli-CqAlS2xh.mjs +43508 -0
- package/dist/chunks/gateway-cli-CxfnMGx8.mjs +43508 -0
- package/dist/chunks/onboard-CRZ2jxOE.mjs +601 -0
- package/dist/chunks/onboard-CyzbNCBF.mjs +601 -0
- package/dist/chunks/onboard-Y9qZW5yw.mjs +601 -0
- package/dist/chunks/program-B27s-BhZ.mjs +163 -0
- package/dist/chunks/program-B3JSAo3Q.mjs +163 -0
- package/dist/chunks/program-DVTI5ouc.mjs +163 -0
- package/dist/chunks/prompt-select-styled-AhC9B2Sr.mjs +5035 -0
- package/dist/chunks/prompt-select-styled-DWTJpQCH.mjs +5035 -0
- package/dist/chunks/prompt-select-styled-PxJbW1Dj.mjs +5035 -0
- package/dist/chunks/register.maintenance-DkQKQI29.mjs +685 -0
- package/dist/chunks/register.maintenance-DrxPWWzR.mjs +685 -0
- package/dist/chunks/register.maintenance-ofEvddjM.mjs +685 -0
- package/dist/chunks/register.onboard-3m3OGP7x.mjs +168 -0
- package/dist/chunks/register.onboard-BpL-OvP9.mjs +168 -0
- package/dist/chunks/register.onboard-CvtQ4Z6V.mjs +168 -0
- package/dist/chunks/register.setup-Dz3jKcQw.mjs +188 -0
- package/dist/chunks/register.setup-NRV53Eo_.mjs +188 -0
- package/dist/chunks/register.setup-xf9cH3sc.mjs +188 -0
- package/dist/chunks/register.subclis-B6xOze_R.mjs +319 -0
- package/dist/chunks/register.subclis-B_qUKZPW.mjs +13 -0
- package/dist/chunks/register.subclis-BvClctGE.mjs +319 -0
- package/dist/chunks/register.subclis-CXtcQnsP.mjs +13 -0
- package/dist/chunks/register.subclis-Dd7Q2x2W.mjs +13 -0
- package/dist/chunks/register.subclis-Dj9qGYdr.mjs +319 -0
- package/dist/chunks/run-main-BYaCWOd9.mjs +437 -0
- package/dist/chunks/run-main-CpZzBbaq.mjs +437 -0
- package/dist/chunks/run-main-nT8E6iSo.mjs +437 -0
- package/dist/chunks/setup-BufxzaUK.mjs +399 -0
- package/dist/chunks/setup-DHU6h2yc.mjs +399 -0
- package/dist/chunks/setup-Ddj3KzQ7.mjs +399 -0
- package/dist/chunks/setup.finalize-Cc2mg8-p.mjs +544 -0
- package/dist/chunks/setup.finalize-DVacBRaT.mjs +544 -0
- package/dist/chunks/setup.finalize-ZR-Hv0hQ.mjs +544 -0
- package/dist/chunks/update-cli-DK2TX2U4.mjs +1632 -0
- package/dist/chunks/update-cli-DWGkI141.mjs +1632 -0
- package/dist/chunks/update-cli-JcUKNsam.mjs +1632 -0
- package/dist/entry.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +134 -134
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
import { u as resolveGatewayPort } from "./paths-CNST7z3O.mjs";
|
|
2
|
+
import { g as restoreTerminalState, h as writeRuntimeJson, 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 { s as isValidEnvSecretRefId } from "./types.secrets-CKipkqRX.mjs";
|
|
6
|
+
import { t as assertSupportedRuntime } from "./runtime-guard-CWHkkioa.mjs";
|
|
7
|
+
import { l as resolveDefaultSecretProviderAlias } from "./ref-contract-UXicez0Y.mjs";
|
|
8
|
+
import { t as formatCliCommand } from "./command-format-D1DrcTDP.mjs";
|
|
9
|
+
import { t as DEFAULT_GATEWAY_DAEMON_RUNTIME } from "./daemon-runtime-D8rTbK9d.mjs";
|
|
10
|
+
import { a as ensureWorkspaceAndSessions, b as waitForGatewayReachable, c as handleReset, g as resolveControlUiLinks, m as randomToken, n as applyWizardMetadata, t as DEFAULT_WORKSPACE, u as normalizeGatewayTokenInput } from "./onboard-helpers-C5GCWoDO.mjs";
|
|
11
|
+
import { t as WizardCancelledError } from "./prompts-BqZHJHEi.mjs";
|
|
12
|
+
import { n as logConfigUpdated } from "./logging-CcQ-gmqC.mjs";
|
|
13
|
+
import { t as createClackPrompter } from "./clack-prompter-C0PG2vbx.mjs";
|
|
14
|
+
import { t as runSetupWizard } from "./setup-DHU6h2yc.mjs";
|
|
15
|
+
import { i as resolveManifestProviderOnboardAuthFlags } from "./provider-auth-choices-DFywK1Pz.mjs";
|
|
16
|
+
import { n as isDeprecatedAuthChoice, r as normalizeLegacyOnboardAuthChoice } from "./auth-choice-legacy-WiHuT2El.mjs";
|
|
17
|
+
import { r as applyLocalSetupWorkspaceConfig } from "./onboard-config-B4gx9Ky_.mjs";
|
|
18
|
+
|
|
19
|
+
//#region src/commands/onboard-core-auth-flags.ts
|
|
20
|
+
const CORE_ONBOARD_AUTH_FLAGS = [{
|
|
21
|
+
optionKey: "litellmApiKey",
|
|
22
|
+
authChoice: "litellm-api-key",
|
|
23
|
+
cliFlag: "--litellm-api-key",
|
|
24
|
+
cliOption: "--litellm-api-key <key>",
|
|
25
|
+
description: "LiteLLM API key"
|
|
26
|
+
}];
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/commands/onboard-interactive.ts
|
|
30
|
+
async function runInteractiveSetup(opts, runtime = defaultRuntime) {
|
|
31
|
+
const prompter = createClackPrompter();
|
|
32
|
+
let exitCode = null;
|
|
33
|
+
try {
|
|
34
|
+
await runSetupWizard(opts, runtime, prompter);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err instanceof WizardCancelledError) {
|
|
37
|
+
exitCode = 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
} finally {
|
|
42
|
+
restoreTerminalState("setup finish", { resumeStdinIfPaused: false });
|
|
43
|
+
if (exitCode !== null) runtime.exit(exitCode);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/commands/onboard-non-interactive/local/auth-choice-inference.ts
|
|
49
|
+
function hasStringValue(value) {
|
|
50
|
+
return typeof value === "string" ? value.trim().length > 0 : Boolean(value);
|
|
51
|
+
}
|
|
52
|
+
function inferAuthChoiceFromFlags(opts) {
|
|
53
|
+
const matches = [...CORE_ONBOARD_AUTH_FLAGS, ...resolveManifestProviderOnboardAuthFlags()].filter(({ optionKey }) => hasStringValue(opts[optionKey])).map((flag) => ({
|
|
54
|
+
optionKey: flag.optionKey,
|
|
55
|
+
authChoice: flag.authChoice,
|
|
56
|
+
label: flag.cliFlag
|
|
57
|
+
}));
|
|
58
|
+
if (hasStringValue(opts.customBaseUrl) || hasStringValue(opts.customModelId) || hasStringValue(opts.customApiKey)) matches.push({
|
|
59
|
+
optionKey: "customBaseUrl",
|
|
60
|
+
authChoice: "custom-api-key",
|
|
61
|
+
label: "--custom-base-url/--custom-model-id/--custom-api-key"
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
choice: matches[0]?.authChoice,
|
|
65
|
+
matches
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/commands/onboard-non-interactive/local/gateway-config.ts
|
|
71
|
+
function applyNonInteractiveGatewayConfig(params) {
|
|
72
|
+
const { opts, runtime } = params;
|
|
73
|
+
const hasGatewayPort = opts.gatewayPort !== void 0;
|
|
74
|
+
if (hasGatewayPort && (!Number.isFinite(opts.gatewayPort) || (opts.gatewayPort ?? 0) <= 0)) {
|
|
75
|
+
runtime.error("Invalid --gateway-port");
|
|
76
|
+
runtime.exit(1);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const port = hasGatewayPort ? opts.gatewayPort : params.defaultPort;
|
|
80
|
+
let bind = opts.gatewayBind ?? "loopback";
|
|
81
|
+
const authModeRaw = opts.gatewayAuth ?? "token";
|
|
82
|
+
if (authModeRaw !== "token" && authModeRaw !== "password") {
|
|
83
|
+
runtime.error("Invalid --gateway-auth (use token|password).");
|
|
84
|
+
runtime.exit(1);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
let authMode = authModeRaw;
|
|
88
|
+
const tailscaleMode = opts.tailscale ?? "off";
|
|
89
|
+
const tailscaleResetOnExit = Boolean(opts.tailscaleResetOnExit);
|
|
90
|
+
if (tailscaleMode !== "off" && bind !== "loopback") bind = "loopback";
|
|
91
|
+
if (tailscaleMode === "funnel" && authMode !== "password") authMode = "password";
|
|
92
|
+
let nextConfig = params.nextConfig;
|
|
93
|
+
const explicitGatewayToken = normalizeGatewayTokenInput(opts.gatewayToken);
|
|
94
|
+
const envGatewayToken = normalizeGatewayTokenInput(process.env.OPENCLAW_GATEWAY_TOKEN);
|
|
95
|
+
let gatewayToken = explicitGatewayToken || envGatewayToken || void 0;
|
|
96
|
+
const gatewayTokenRefEnv = String(opts.gatewayTokenRefEnv ?? "").trim();
|
|
97
|
+
if (authMode === "token") if (gatewayTokenRefEnv) {
|
|
98
|
+
if (!isValidEnvSecretRefId(gatewayTokenRefEnv)) {
|
|
99
|
+
runtime.error("Invalid --gateway-token-ref-env (use env var name like OPENCLAW_GATEWAY_TOKEN).");
|
|
100
|
+
runtime.exit(1);
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (explicitGatewayToken) {
|
|
104
|
+
runtime.error("Use either --gateway-token or --gateway-token-ref-env, not both.");
|
|
105
|
+
runtime.exit(1);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const resolvedFromEnv = process.env[gatewayTokenRefEnv]?.trim();
|
|
109
|
+
if (!resolvedFromEnv) {
|
|
110
|
+
runtime.error(`Environment variable "${gatewayTokenRefEnv}" is missing or empty.`);
|
|
111
|
+
runtime.exit(1);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
gatewayToken = resolvedFromEnv;
|
|
115
|
+
nextConfig = {
|
|
116
|
+
...nextConfig,
|
|
117
|
+
gateway: {
|
|
118
|
+
...nextConfig.gateway,
|
|
119
|
+
auth: {
|
|
120
|
+
...nextConfig.gateway?.auth,
|
|
121
|
+
mode: "token",
|
|
122
|
+
token: {
|
|
123
|
+
source: "env",
|
|
124
|
+
provider: resolveDefaultSecretProviderAlias(nextConfig, "env", { preferFirstProviderForSource: true }),
|
|
125
|
+
id: gatewayTokenRefEnv
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
} else {
|
|
131
|
+
if (!gatewayToken) gatewayToken = randomToken();
|
|
132
|
+
nextConfig = {
|
|
133
|
+
...nextConfig,
|
|
134
|
+
gateway: {
|
|
135
|
+
...nextConfig.gateway,
|
|
136
|
+
auth: {
|
|
137
|
+
...nextConfig.gateway?.auth,
|
|
138
|
+
mode: "token",
|
|
139
|
+
token: gatewayToken
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (authMode === "password") {
|
|
145
|
+
const password = opts.gatewayPassword?.trim();
|
|
146
|
+
if (!password) {
|
|
147
|
+
runtime.error("Missing --gateway-password for password auth.");
|
|
148
|
+
runtime.exit(1);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
nextConfig = {
|
|
152
|
+
...nextConfig,
|
|
153
|
+
gateway: {
|
|
154
|
+
...nextConfig.gateway,
|
|
155
|
+
auth: {
|
|
156
|
+
...nextConfig.gateway?.auth,
|
|
157
|
+
mode: "password",
|
|
158
|
+
password
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
nextConfig = {
|
|
164
|
+
...nextConfig,
|
|
165
|
+
gateway: {
|
|
166
|
+
...nextConfig.gateway,
|
|
167
|
+
port,
|
|
168
|
+
bind,
|
|
169
|
+
tailscale: {
|
|
170
|
+
...nextConfig.gateway?.tailscale,
|
|
171
|
+
mode: tailscaleMode,
|
|
172
|
+
resetOnExit: tailscaleResetOnExit
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
nextConfig,
|
|
178
|
+
port,
|
|
179
|
+
bind,
|
|
180
|
+
authMode,
|
|
181
|
+
tailscaleMode,
|
|
182
|
+
tailscaleResetOnExit,
|
|
183
|
+
gatewayToken
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//#endregion
|
|
188
|
+
//#region src/commands/onboard-non-interactive/local/output.ts
|
|
189
|
+
function logNonInteractiveOnboardingJson(params) {
|
|
190
|
+
if (!params.opts.json) return;
|
|
191
|
+
writeRuntimeJson(params.runtime, {
|
|
192
|
+
ok: true,
|
|
193
|
+
mode: params.mode,
|
|
194
|
+
workspace: params.workspaceDir,
|
|
195
|
+
authChoice: params.authChoice,
|
|
196
|
+
gateway: params.gateway,
|
|
197
|
+
installDaemon: Boolean(params.installDaemon),
|
|
198
|
+
daemonInstall: params.daemonInstall,
|
|
199
|
+
daemonRuntime: params.daemonRuntime,
|
|
200
|
+
skipSkills: Boolean(params.skipSkills),
|
|
201
|
+
skipHealth: Boolean(params.skipHealth)
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function formatGatewayRuntimeSummary(diagnostics) {
|
|
205
|
+
const service = diagnostics?.service;
|
|
206
|
+
if (!service?.runtimeStatus) return;
|
|
207
|
+
const parts = [service.runtimeStatus];
|
|
208
|
+
if (typeof service.pid === "number") parts.push(`pid ${service.pid}`);
|
|
209
|
+
if (service.state) parts.push(`state ${service.state}`);
|
|
210
|
+
if (typeof service.lastExitStatus === "number") parts.push(`last exit ${service.lastExitStatus}`);
|
|
211
|
+
if (service.lastExitReason) parts.push(`reason ${service.lastExitReason}`);
|
|
212
|
+
return parts.join(", ");
|
|
213
|
+
}
|
|
214
|
+
function logNonInteractiveOnboardingFailure(params) {
|
|
215
|
+
const hints = params.hints?.filter(Boolean) ?? [];
|
|
216
|
+
const gatewayRuntime = formatGatewayRuntimeSummary(params.diagnostics);
|
|
217
|
+
if (params.opts.json) {
|
|
218
|
+
writeRuntimeJson(params.runtime, {
|
|
219
|
+
ok: false,
|
|
220
|
+
mode: params.mode,
|
|
221
|
+
phase: params.phase,
|
|
222
|
+
message: params.message,
|
|
223
|
+
detail: params.detail,
|
|
224
|
+
gateway: params.gateway,
|
|
225
|
+
installDaemon: Boolean(params.installDaemon),
|
|
226
|
+
daemonInstall: params.daemonInstall,
|
|
227
|
+
daemonRuntime: params.daemonRuntime,
|
|
228
|
+
diagnostics: params.diagnostics,
|
|
229
|
+
hints: hints.length > 0 ? hints : void 0
|
|
230
|
+
});
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const lines = [
|
|
234
|
+
params.message,
|
|
235
|
+
params.detail ? `Last probe: ${params.detail}` : void 0,
|
|
236
|
+
params.diagnostics?.service ? `Service: ${params.diagnostics.service.label} (${params.diagnostics.service.loaded ? params.diagnostics.service.loadedText : "not loaded"})` : void 0,
|
|
237
|
+
gatewayRuntime ? `Runtime: ${gatewayRuntime}` : void 0,
|
|
238
|
+
params.diagnostics?.lastGatewayError ? `Last gateway error: ${params.diagnostics.lastGatewayError}` : void 0,
|
|
239
|
+
params.diagnostics?.inspectError ? `Diagnostics warning: ${params.diagnostics.inspectError}` : void 0,
|
|
240
|
+
hints.length > 0 ? hints.join("\n") : void 0
|
|
241
|
+
].filter(Boolean).join("\n");
|
|
242
|
+
params.runtime.error(lines);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/commands/onboard-non-interactive/local/skills-config.ts
|
|
247
|
+
function applyNonInteractiveSkillsConfig(params) {
|
|
248
|
+
const { nextConfig, opts, runtime } = params;
|
|
249
|
+
if (opts.skipSkills) return nextConfig;
|
|
250
|
+
const nodeManager = opts.nodeManager ?? "npm";
|
|
251
|
+
if (![
|
|
252
|
+
"npm",
|
|
253
|
+
"pnpm",
|
|
254
|
+
"bun"
|
|
255
|
+
].includes(nodeManager)) {
|
|
256
|
+
runtime.error("Invalid --node-manager (use npm, pnpm, or bun)");
|
|
257
|
+
runtime.exit(1);
|
|
258
|
+
return nextConfig;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
...nextConfig,
|
|
262
|
+
skills: {
|
|
263
|
+
...nextConfig.skills,
|
|
264
|
+
install: {
|
|
265
|
+
...nextConfig.skills?.install,
|
|
266
|
+
nodeManager
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/commands/onboard-non-interactive/local/workspace.ts
|
|
274
|
+
function resolveNonInteractiveWorkspaceDir(params) {
|
|
275
|
+
return resolveUserPath((params.opts.workspace ?? params.baseConfig.agents?.defaults?.workspace ?? params.defaultWorkspaceDir).trim());
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/commands/onboard-non-interactive/local.ts
|
|
280
|
+
const INSTALL_DAEMON_HEALTH_DEADLINE_MS = 45e3;
|
|
281
|
+
const ATTACH_EXISTING_GATEWAY_HEALTH_DEADLINE_MS = 15e3;
|
|
282
|
+
async function collectGatewayHealthFailureDiagnostics() {
|
|
283
|
+
const diagnostics = {};
|
|
284
|
+
try {
|
|
285
|
+
const { resolveGatewayService } = await import("./service-BdQxMPOx.mjs");
|
|
286
|
+
const service = resolveGatewayService();
|
|
287
|
+
const env = process.env;
|
|
288
|
+
const [loaded, runtime] = await Promise.all([service.isLoaded({ env }).catch(() => false), service.readRuntime(env).catch(() => void 0)]);
|
|
289
|
+
diagnostics.service = {
|
|
290
|
+
label: service.label,
|
|
291
|
+
loaded,
|
|
292
|
+
loadedText: service.loadedText,
|
|
293
|
+
runtimeStatus: runtime?.status,
|
|
294
|
+
state: runtime?.state,
|
|
295
|
+
pid: runtime?.pid,
|
|
296
|
+
lastExitStatus: runtime?.lastExitStatus,
|
|
297
|
+
lastExitReason: runtime?.lastExitReason
|
|
298
|
+
};
|
|
299
|
+
} catch (err) {
|
|
300
|
+
diagnostics.inspectError = `service diagnostics failed: ${String(err)}`;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const { readLastGatewayErrorLine } = await import("./diagnostics-CFvH6Rsr.mjs");
|
|
304
|
+
diagnostics.lastGatewayError = await readLastGatewayErrorLine(process.env) ?? void 0;
|
|
305
|
+
} catch (err) {
|
|
306
|
+
diagnostics.inspectError = diagnostics.inspectError ? `${diagnostics.inspectError}; log diagnostics failed: ${String(err)}` : `log diagnostics failed: ${String(err)}`;
|
|
307
|
+
}
|
|
308
|
+
return diagnostics.service || diagnostics.lastGatewayError || diagnostics.inspectError ? diagnostics : void 0;
|
|
309
|
+
}
|
|
310
|
+
async function runNonInteractiveLocalSetup(params) {
|
|
311
|
+
const { opts, runtime, baseConfig } = params;
|
|
312
|
+
const mode = "local";
|
|
313
|
+
const workspaceDir = resolveNonInteractiveWorkspaceDir({
|
|
314
|
+
opts,
|
|
315
|
+
baseConfig,
|
|
316
|
+
defaultWorkspaceDir: DEFAULT_WORKSPACE
|
|
317
|
+
});
|
|
318
|
+
let nextConfig = applyLocalSetupWorkspaceConfig(baseConfig, workspaceDir);
|
|
319
|
+
const inferredAuthChoice = inferAuthChoiceFromFlags(opts);
|
|
320
|
+
if (!opts.authChoice && inferredAuthChoice.matches.length > 1) {
|
|
321
|
+
runtime.error([
|
|
322
|
+
"Multiple API key flags were provided for non-interactive setup.",
|
|
323
|
+
"Use a single provider flag or pass --auth-choice explicitly.",
|
|
324
|
+
`Flags: ${inferredAuthChoice.matches.map((match) => match.label).join(", ")}`
|
|
325
|
+
].join("\n"));
|
|
326
|
+
runtime.exit(1);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const authChoice = opts.authChoice ?? inferredAuthChoice.choice ?? "skip";
|
|
330
|
+
if (authChoice !== "skip") {
|
|
331
|
+
const { applyNonInteractiveAuthChoice } = await import("./auth-choice-Dig4eYbk.mjs");
|
|
332
|
+
const nextConfigAfterAuth = await applyNonInteractiveAuthChoice({
|
|
333
|
+
nextConfig,
|
|
334
|
+
authChoice,
|
|
335
|
+
opts,
|
|
336
|
+
runtime,
|
|
337
|
+
baseConfig
|
|
338
|
+
});
|
|
339
|
+
if (!nextConfigAfterAuth) return;
|
|
340
|
+
nextConfig = nextConfigAfterAuth;
|
|
341
|
+
}
|
|
342
|
+
const gatewayBasePort = resolveGatewayPort(baseConfig);
|
|
343
|
+
const gatewayResult = applyNonInteractiveGatewayConfig({
|
|
344
|
+
nextConfig,
|
|
345
|
+
opts,
|
|
346
|
+
runtime,
|
|
347
|
+
defaultPort: gatewayBasePort
|
|
348
|
+
});
|
|
349
|
+
if (!gatewayResult) return;
|
|
350
|
+
nextConfig = gatewayResult.nextConfig;
|
|
351
|
+
nextConfig = applyNonInteractiveSkillsConfig({
|
|
352
|
+
nextConfig,
|
|
353
|
+
opts,
|
|
354
|
+
runtime
|
|
355
|
+
});
|
|
356
|
+
nextConfig = applyWizardMetadata(nextConfig, {
|
|
357
|
+
command: "onboard",
|
|
358
|
+
mode
|
|
359
|
+
});
|
|
360
|
+
await writeConfigFile(nextConfig);
|
|
361
|
+
logConfigUpdated(runtime);
|
|
362
|
+
await ensureWorkspaceAndSessions(workspaceDir, runtime, { skipBootstrap: Boolean(nextConfig.agents?.defaults?.skipBootstrap) });
|
|
363
|
+
const daemonRuntimeRaw = opts.daemonRuntime ?? DEFAULT_GATEWAY_DAEMON_RUNTIME;
|
|
364
|
+
let daemonInstallStatus;
|
|
365
|
+
if (opts.installDaemon) {
|
|
366
|
+
const { installGatewayDaemonNonInteractive } = await import("./daemon-install-C8HGWXLQ.mjs");
|
|
367
|
+
const daemonInstall = await installGatewayDaemonNonInteractive({
|
|
368
|
+
nextConfig,
|
|
369
|
+
opts,
|
|
370
|
+
runtime,
|
|
371
|
+
port: gatewayResult.port
|
|
372
|
+
});
|
|
373
|
+
daemonInstallStatus = daemonInstall.installed ? {
|
|
374
|
+
requested: true,
|
|
375
|
+
installed: true
|
|
376
|
+
} : {
|
|
377
|
+
requested: true,
|
|
378
|
+
installed: false,
|
|
379
|
+
skippedReason: daemonInstall.skippedReason
|
|
380
|
+
};
|
|
381
|
+
if (!daemonInstall.installed && !opts.skipHealth) {
|
|
382
|
+
logNonInteractiveOnboardingFailure({
|
|
383
|
+
opts,
|
|
384
|
+
runtime,
|
|
385
|
+
mode,
|
|
386
|
+
phase: "daemon-install",
|
|
387
|
+
message: daemonInstall.skippedReason === "systemd-user-unavailable" ? "Gateway service install is unavailable because systemd user services are not reachable in this Linux session." : "Gateway service install did not complete successfully.",
|
|
388
|
+
installDaemon: true,
|
|
389
|
+
daemonInstall: {
|
|
390
|
+
requested: true,
|
|
391
|
+
installed: false,
|
|
392
|
+
skippedReason: daemonInstall.skippedReason
|
|
393
|
+
},
|
|
394
|
+
daemonRuntime: daemonRuntimeRaw,
|
|
395
|
+
hints: daemonInstall.skippedReason === "systemd-user-unavailable" ? ["Fix: rerun without `--install-daemon` for one-shot setup, or enable a working user-systemd session and retry.", "If your auth profile uses env-backed refs, keep those env vars set in the shell that runs `openclaw gateway run` or `openclaw agent --local`."] : [`Run \`${formatCliCommand("openclaw gateway status --deep")}\` for more detail.`]
|
|
396
|
+
});
|
|
397
|
+
runtime.exit(1);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!opts.skipHealth) {
|
|
402
|
+
const { healthCommand } = await import("./health-Co9G83gO.mjs");
|
|
403
|
+
const links = resolveControlUiLinks({
|
|
404
|
+
bind: gatewayResult.bind,
|
|
405
|
+
port: gatewayResult.port,
|
|
406
|
+
customBindHost: nextConfig.gateway?.customBindHost,
|
|
407
|
+
basePath: void 0
|
|
408
|
+
});
|
|
409
|
+
const probe = await waitForGatewayReachable({
|
|
410
|
+
url: links.wsUrl,
|
|
411
|
+
token: gatewayResult.gatewayToken,
|
|
412
|
+
deadlineMs: opts.installDaemon ? INSTALL_DAEMON_HEALTH_DEADLINE_MS : ATTACH_EXISTING_GATEWAY_HEALTH_DEADLINE_MS
|
|
413
|
+
});
|
|
414
|
+
if (!probe.ok) {
|
|
415
|
+
const diagnostics = opts.installDaemon ? await collectGatewayHealthFailureDiagnostics() : void 0;
|
|
416
|
+
logNonInteractiveOnboardingFailure({
|
|
417
|
+
opts,
|
|
418
|
+
runtime,
|
|
419
|
+
mode,
|
|
420
|
+
phase: "gateway-health",
|
|
421
|
+
message: `Gateway did not become reachable at ${links.wsUrl}.`,
|
|
422
|
+
detail: probe.detail,
|
|
423
|
+
gateway: {
|
|
424
|
+
wsUrl: links.wsUrl,
|
|
425
|
+
httpUrl: links.httpUrl
|
|
426
|
+
},
|
|
427
|
+
installDaemon: Boolean(opts.installDaemon),
|
|
428
|
+
daemonInstall: daemonInstallStatus,
|
|
429
|
+
daemonRuntime: opts.installDaemon ? daemonRuntimeRaw : void 0,
|
|
430
|
+
diagnostics,
|
|
431
|
+
hints: !opts.installDaemon ? [
|
|
432
|
+
"Non-interactive local setup only waits for an already-running gateway unless you pass --install-daemon.",
|
|
433
|
+
`Fix: start \`${formatCliCommand("openclaw gateway run")}\`, re-run with \`--install-daemon\`, or use \`--skip-health\`.`,
|
|
434
|
+
process.platform === "win32" ? "Native Windows managed gateway install tries Scheduled Tasks first and falls back to a per-user Startup-folder login item when task creation is denied." : void 0
|
|
435
|
+
].filter((value) => Boolean(value)) : [`Run \`${formatCliCommand("openclaw gateway status --deep")}\` for more detail.`]
|
|
436
|
+
});
|
|
437
|
+
runtime.exit(1);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
await healthCommand({
|
|
441
|
+
json: false,
|
|
442
|
+
timeoutMs: 1e4
|
|
443
|
+
}, runtime);
|
|
444
|
+
}
|
|
445
|
+
logNonInteractiveOnboardingJson({
|
|
446
|
+
opts,
|
|
447
|
+
runtime,
|
|
448
|
+
mode,
|
|
449
|
+
workspaceDir,
|
|
450
|
+
authChoice,
|
|
451
|
+
gateway: {
|
|
452
|
+
port: gatewayResult.port,
|
|
453
|
+
bind: gatewayResult.bind,
|
|
454
|
+
authMode: gatewayResult.authMode,
|
|
455
|
+
tailscaleMode: gatewayResult.tailscaleMode
|
|
456
|
+
},
|
|
457
|
+
installDaemon: Boolean(opts.installDaemon),
|
|
458
|
+
daemonInstall: daemonInstallStatus,
|
|
459
|
+
daemonRuntime: opts.installDaemon ? daemonRuntimeRaw : void 0,
|
|
460
|
+
skipSkills: Boolean(opts.skipSkills),
|
|
461
|
+
skipHealth: Boolean(opts.skipHealth)
|
|
462
|
+
});
|
|
463
|
+
if (!opts.json) runtime.log(`Tip: run \`${formatCliCommand("openclaw configure --section web")}\` to store your Brave API key for web_search. Docs: https://docs.openclaw.ai/tools/web`);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
//#endregion
|
|
467
|
+
//#region src/commands/onboard-non-interactive/remote.ts
|
|
468
|
+
async function runNonInteractiveRemoteSetup(params) {
|
|
469
|
+
const { opts, runtime, baseConfig } = params;
|
|
470
|
+
const mode = "remote";
|
|
471
|
+
const remoteUrl = opts.remoteUrl?.trim();
|
|
472
|
+
if (!remoteUrl) {
|
|
473
|
+
runtime.error("Missing --remote-url for remote mode.");
|
|
474
|
+
runtime.exit(1);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
let nextConfig = {
|
|
478
|
+
...baseConfig,
|
|
479
|
+
gateway: {
|
|
480
|
+
...baseConfig.gateway,
|
|
481
|
+
mode: "remote",
|
|
482
|
+
remote: {
|
|
483
|
+
url: remoteUrl,
|
|
484
|
+
token: opts.remoteToken?.trim() || void 0
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
nextConfig = applyWizardMetadata(nextConfig, {
|
|
489
|
+
command: "onboard",
|
|
490
|
+
mode
|
|
491
|
+
});
|
|
492
|
+
await writeConfigFile(nextConfig);
|
|
493
|
+
logConfigUpdated(runtime);
|
|
494
|
+
const payload = {
|
|
495
|
+
mode,
|
|
496
|
+
remoteUrl,
|
|
497
|
+
auth: opts.remoteToken ? "token" : "none"
|
|
498
|
+
};
|
|
499
|
+
if (opts.json) writeRuntimeJson(runtime, payload);
|
|
500
|
+
else {
|
|
501
|
+
runtime.log(`Remote gateway: ${remoteUrl}`);
|
|
502
|
+
runtime.log(`Auth: ${payload.auth}`);
|
|
503
|
+
runtime.log(`Tip: run \`${formatCliCommand("openclaw configure --section web")}\` to store your Brave API key for web_search. Docs: https://docs.openclaw.ai/tools/web`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/commands/onboard-non-interactive.ts
|
|
509
|
+
async function runNonInteractiveSetup(opts, runtime = defaultRuntime) {
|
|
510
|
+
const snapshot = await readConfigFileSnapshot();
|
|
511
|
+
if (snapshot.exists && !snapshot.valid) {
|
|
512
|
+
runtime.error(`Config invalid. Run \`${formatCliCommand("openclaw doctor")}\` to repair it, then re-run setup.`);
|
|
513
|
+
runtime.exit(1);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const baseConfig = snapshot.valid ? snapshot.exists ? snapshot.config : {} : {};
|
|
517
|
+
const mode = opts.mode ?? "local";
|
|
518
|
+
if (mode !== "local" && mode !== "remote") {
|
|
519
|
+
runtime.error(`Invalid --mode "${String(mode)}" (use local|remote).`);
|
|
520
|
+
runtime.exit(1);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (mode === "remote") {
|
|
524
|
+
await runNonInteractiveRemoteSetup({
|
|
525
|
+
opts,
|
|
526
|
+
runtime,
|
|
527
|
+
baseConfig
|
|
528
|
+
});
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
await runNonInteractiveLocalSetup({
|
|
532
|
+
opts,
|
|
533
|
+
runtime,
|
|
534
|
+
baseConfig
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
//#endregion
|
|
539
|
+
//#region src/commands/onboard.ts
|
|
540
|
+
const VALID_RESET_SCOPES = new Set([
|
|
541
|
+
"config",
|
|
542
|
+
"config+creds+sessions",
|
|
543
|
+
"full"
|
|
544
|
+
]);
|
|
545
|
+
async function setupWizardCommand(opts, runtime = defaultRuntime) {
|
|
546
|
+
assertSupportedRuntime(runtime);
|
|
547
|
+
const originalAuthChoice = opts.authChoice;
|
|
548
|
+
const normalizedAuthChoice = normalizeLegacyOnboardAuthChoice(originalAuthChoice);
|
|
549
|
+
if (opts.nonInteractive && isDeprecatedAuthChoice(originalAuthChoice)) {
|
|
550
|
+
runtime.error([`Auth choice "${String(originalAuthChoice)}" is deprecated.`, "Use \"--auth-choice token\" (Anthropic setup-token) or \"--auth-choice openai-codex\"."].join("\n"));
|
|
551
|
+
runtime.exit(1);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (originalAuthChoice === "claude-cli") runtime.log("Auth choice \"claude-cli\" is deprecated; using setup-token flow instead.");
|
|
555
|
+
if (originalAuthChoice === "codex-cli") runtime.log("Auth choice \"codex-cli\" is deprecated; using OpenAI Codex OAuth instead.");
|
|
556
|
+
const flow = opts.flow === "manual" ? "advanced" : opts.flow;
|
|
557
|
+
const normalizedOpts = normalizedAuthChoice === opts.authChoice && flow === opts.flow ? opts : {
|
|
558
|
+
...opts,
|
|
559
|
+
authChoice: normalizedAuthChoice,
|
|
560
|
+
flow
|
|
561
|
+
};
|
|
562
|
+
if (normalizedOpts.secretInputMode && normalizedOpts.secretInputMode !== "plaintext" && normalizedOpts.secretInputMode !== "ref") {
|
|
563
|
+
runtime.error("Invalid --secret-input-mode. Use \"plaintext\" or \"ref\".");
|
|
564
|
+
runtime.exit(1);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (normalizedOpts.resetScope && !VALID_RESET_SCOPES.has(normalizedOpts.resetScope)) {
|
|
568
|
+
runtime.error("Invalid --reset-scope. Use \"config\", \"config+creds+sessions\", or \"full\".");
|
|
569
|
+
runtime.exit(1);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (normalizedOpts.nonInteractive && normalizedOpts.acceptRisk !== true) {
|
|
573
|
+
runtime.error([
|
|
574
|
+
"Non-interactive setup requires explicit risk acknowledgement.",
|
|
575
|
+
"Read: https://docs.openclaw.ai/security",
|
|
576
|
+
`Re-run with: ${formatCliCommand("openclaw onboard --non-interactive --accept-risk ...")}`
|
|
577
|
+
].join("\n"));
|
|
578
|
+
runtime.exit(1);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (normalizedOpts.reset) {
|
|
582
|
+
const snapshot = await readConfigFileSnapshot();
|
|
583
|
+
const baseConfig = snapshot.valid ? snapshot.config : {};
|
|
584
|
+
const workspaceDefault = normalizedOpts.workspace ?? baseConfig.agents?.defaults?.workspace ?? DEFAULT_WORKSPACE;
|
|
585
|
+
await handleReset(normalizedOpts.resetScope ?? "config+creds+sessions", resolveUserPath(workspaceDefault), runtime);
|
|
586
|
+
}
|
|
587
|
+
if (process.platform === "win32") runtime.log([
|
|
588
|
+
"Windows detected - OpenClaw runs great on WSL2!",
|
|
589
|
+
"Native Windows might be trickier.",
|
|
590
|
+
"Quick setup: wsl --install (one command, one reboot)",
|
|
591
|
+
"Guide: https://docs.openclaw.ai/windows"
|
|
592
|
+
].join("\n"));
|
|
593
|
+
if (normalizedOpts.nonInteractive) {
|
|
594
|
+
await runNonInteractiveSetup(normalizedOpts, runtime);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
await runInteractiveSetup(normalizedOpts, runtime);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
//#endregion
|
|
601
|
+
export { CORE_ONBOARD_AUTH_FLAGS as n, setupWizardCommand as t };
|