clawdbot 2026.1.4-1 → 2026.1.5

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 (117) hide show
  1. package/CHANGELOG.md +26 -6
  2. package/README.md +26 -1
  3. package/dist/agents/pi-embedded-runner.js +2 -0
  4. package/dist/agents/pi-embedded-subscribe.js +18 -3
  5. package/dist/agents/pi-tools.js +45 -6
  6. package/dist/agents/tools/browser-tool.js +38 -89
  7. package/dist/agents/tools/cron-tool.js +8 -8
  8. package/dist/agents/workspace.js +8 -1
  9. package/dist/auto-reply/command-detection.js +26 -0
  10. package/dist/auto-reply/reply/agent-runner.js +15 -8
  11. package/dist/auto-reply/reply/commands.js +36 -25
  12. package/dist/auto-reply/reply/directive-handling.js +4 -2
  13. package/dist/auto-reply/reply/directives.js +12 -0
  14. package/dist/auto-reply/reply/session-updates.js +2 -4
  15. package/dist/auto-reply/reply.js +26 -4
  16. package/dist/browser/config.js +22 -4
  17. package/dist/browser/profiles-service.js +3 -1
  18. package/dist/browser/profiles.js +14 -3
  19. package/dist/canvas-host/a2ui/.bundle.hash +2 -0
  20. package/dist/cli/gateway-cli.js +2 -2
  21. package/dist/cli/profile.js +81 -0
  22. package/dist/cli/program.js +10 -1
  23. package/dist/cli/run-main.js +33 -0
  24. package/dist/commands/configure.js +5 -0
  25. package/dist/commands/onboard-providers.js +1 -1
  26. package/dist/commands/setup.js +4 -1
  27. package/dist/config/defaults.js +56 -0
  28. package/dist/config/io.js +47 -6
  29. package/dist/config/paths.js +2 -2
  30. package/dist/config/port-defaults.js +32 -0
  31. package/dist/config/sessions.js +3 -2
  32. package/dist/config/validation.js +2 -2
  33. package/dist/config/zod-schema.js +16 -0
  34. package/dist/discord/monitor.js +75 -266
  35. package/dist/entry.js +16 -0
  36. package/dist/gateway/call.js +8 -1
  37. package/dist/gateway/server-methods/chat.js +1 -1
  38. package/dist/gateway/server.js +14 -3
  39. package/dist/index.js +2 -2
  40. package/dist/infra/control-ui-assets.js +118 -0
  41. package/dist/infra/dotenv.js +15 -0
  42. package/dist/infra/shell-env.js +79 -0
  43. package/dist/infra/system-events.js +50 -23
  44. package/dist/macos/relay.js +8 -2
  45. package/dist/telegram/bot.js +24 -1
  46. package/dist/utils.js +8 -2
  47. package/dist/web/auto-reply.js +18 -21
  48. package/dist/web/inbound.js +5 -1
  49. package/dist/web/qr-image.js +4 -4
  50. package/dist/web/session.js +2 -3
  51. package/docs/agent.md +0 -2
  52. package/docs/assets/markdown.css +4 -1
  53. package/docs/audio.md +0 -2
  54. package/docs/clawd.md +0 -2
  55. package/docs/configuration.md +62 -3
  56. package/docs/docs.json +9 -1
  57. package/docs/faq.md +32 -7
  58. package/docs/gateway.md +28 -0
  59. package/docs/images.md +0 -2
  60. package/docs/index.md +2 -4
  61. package/docs/mac/icon.md +1 -1
  62. package/docs/nix.md +57 -11
  63. package/docs/onboarding.md +0 -2
  64. package/docs/refactor/webagent-session.md +0 -2
  65. package/docs/research/memory.md +1 -1
  66. package/docs/skills.md +0 -2
  67. package/docs/templates/AGENTS.md +2 -2
  68. package/docs/tools.md +15 -0
  69. package/docs/whatsapp.md +2 -0
  70. package/package.json +8 -16
  71. package/dist/control-ui/assets/index-BFID3yAA.css +0 -1
  72. package/dist/control-ui/assets/index-CE_axlTS.js +0 -2235
  73. package/dist/control-ui/assets/index-CE_axlTS.js.map +0 -1
  74. package/dist/control-ui/index.html +0 -15
  75. package/dist/daemon/constants.js +0 -10
  76. package/dist/daemon/launchd.js +0 -276
  77. package/dist/daemon/legacy.js +0 -63
  78. package/dist/daemon/program-args.js +0 -76
  79. package/dist/daemon/schtasks.js +0 -257
  80. package/dist/daemon/service.js +0 -60
  81. package/dist/daemon/systemd.js +0 -266
  82. package/dist/imessage/client.js +0 -165
  83. package/dist/imessage/index.js +0 -3
  84. package/dist/imessage/monitor.js +0 -272
  85. package/dist/imessage/probe.js +0 -26
  86. package/dist/imessage/send.js +0 -83
  87. package/dist/imessage/targets.js +0 -176
  88. package/dist/sessions/send-policy.js +0 -68
  89. package/dist/signal/client.js +0 -134
  90. package/dist/signal/daemon.js +0 -69
  91. package/dist/signal/index.js +0 -3
  92. package/dist/signal/monitor.js +0 -336
  93. package/dist/signal/probe.js +0 -46
  94. package/dist/signal/send.js +0 -91
  95. package/dist/slack/actions.js +0 -97
  96. package/dist/slack/index.js +0 -5
  97. package/dist/slack/monitor.js +0 -1029
  98. package/dist/slack/probe.js +0 -47
  99. package/dist/slack/send.js +0 -131
  100. package/dist/slack/token.js +0 -10
  101. package/dist/tui/commands.js +0 -74
  102. package/dist/tui/components/assistant-message.js +0 -16
  103. package/dist/tui/components/chat-log.js +0 -92
  104. package/dist/tui/components/custom-editor.js +0 -53
  105. package/dist/tui/components/selectors.js +0 -8
  106. package/dist/tui/components/tool-execution.js +0 -111
  107. package/dist/tui/components/user-message.js +0 -17
  108. package/dist/tui/gateway-chat.js +0 -140
  109. package/dist/tui/layout.js +0 -41
  110. package/dist/tui/message-list.js +0 -57
  111. package/dist/tui/theme/theme.js +0 -80
  112. package/dist/tui/theme.js +0 -25
  113. package/dist/tui/tui.js +0 -708
  114. package/dist/wizard/clack-prompter.js +0 -56
  115. package/dist/wizard/onboarding.js +0 -452
  116. package/dist/wizard/prompts.js +0 -6
  117. package/dist/wizard/session.js +0 -203
@@ -1,56 +0,0 @@
1
- import { cancel, confirm, intro, isCancel, multiselect, note, outro, select, spinner, text, } from "@clack/prompts";
2
- import { WizardCancelledError } from "./prompts.js";
3
- function guardCancel(value) {
4
- if (isCancel(value)) {
5
- cancel("Setup cancelled.");
6
- throw new WizardCancelledError();
7
- }
8
- return value;
9
- }
10
- export function createClackPrompter() {
11
- return {
12
- intro: async (title) => {
13
- intro(title);
14
- },
15
- outro: async (message) => {
16
- outro(message);
17
- },
18
- note: async (message, title) => {
19
- note(message, title);
20
- },
21
- select: async (params) => guardCancel(await select({
22
- message: params.message,
23
- options: params.options.map((opt) => {
24
- const base = { value: opt.value, label: opt.label };
25
- return opt.hint === undefined ? base : { ...base, hint: opt.hint };
26
- }),
27
- initialValue: params.initialValue,
28
- })),
29
- multiselect: async (params) => guardCancel(await multiselect({
30
- message: params.message,
31
- options: params.options.map((opt) => {
32
- const base = { value: opt.value, label: opt.label };
33
- return opt.hint === undefined ? base : { ...base, hint: opt.hint };
34
- }),
35
- initialValues: params.initialValues,
36
- })),
37
- text: async (params) => guardCancel(await text({
38
- message: params.message,
39
- initialValue: params.initialValue,
40
- placeholder: params.placeholder,
41
- validate: params.validate,
42
- })),
43
- confirm: async (params) => guardCancel(await confirm({
44
- message: params.message,
45
- initialValue: params.initialValue,
46
- })),
47
- progress: (label) => {
48
- const spin = spinner();
49
- spin.start(label);
50
- return {
51
- update: (message) => spin.message(message),
52
- stop: (message) => spin.stop(message),
53
- };
54
- },
55
- };
56
- }
@@ -1,452 +0,0 @@
1
- import path from "node:path";
2
- import { loginAnthropic } from "@mariozechner/pi-ai";
3
- import { isRemoteEnvironment, loginAntigravityVpsAware, } from "../commands/antigravity-oauth.js";
4
- import { healthCommand } from "../commands/health.js";
5
- import { applyMinimaxConfig, setAnthropicApiKey, writeOAuthCredentials, } from "../commands/onboard-auth.js";
6
- import { applyWizardMetadata, DEFAULT_WORKSPACE, detectBrowserOpenSupport, ensureWorkspaceAndSessions, formatControlUiSshHint, handleReset, openUrl, printWizardHeader, probeGatewayReachable, randomToken, resolveControlUiLinks, summarizeExistingConfig, } from "../commands/onboard-helpers.js";
7
- import { setupProviders } from "../commands/onboard-providers.js";
8
- import { promptRemoteGatewayConfig } from "../commands/onboard-remote.js";
9
- import { setupSkills } from "../commands/onboard-skills.js";
10
- import { CONFIG_PATH_CLAWDBOT, readConfigFileSnapshot, resolveGatewayPort, writeConfigFile, } from "../config/config.js";
11
- import { GATEWAY_LAUNCH_AGENT_LABEL } from "../daemon/constants.js";
12
- import { resolveGatewayProgramArguments } from "../daemon/program-args.js";
13
- import { resolveGatewayService } from "../daemon/service.js";
14
- import { defaultRuntime } from "../runtime.js";
15
- import { resolveUserPath, sleep } from "../utils.js";
16
- export async function runOnboardingWizard(opts, runtime = defaultRuntime, prompter) {
17
- printWizardHeader(runtime);
18
- await prompter.intro("Clawdbot onboarding");
19
- const snapshot = await readConfigFileSnapshot();
20
- let baseConfig = snapshot.valid ? snapshot.config : {};
21
- if (snapshot.exists) {
22
- const title = snapshot.valid
23
- ? "Existing config detected"
24
- : "Invalid config";
25
- await prompter.note(summarizeExistingConfig(baseConfig), title);
26
- if (!snapshot.valid && snapshot.issues.length > 0) {
27
- await prompter.note(snapshot.issues
28
- .map((iss) => `- ${iss.path}: ${iss.message}`)
29
- .join("\n"), "Config issues");
30
- }
31
- const action = (await prompter.select({
32
- message: "Config handling",
33
- options: [
34
- { value: "keep", label: "Use existing values" },
35
- { value: "modify", label: "Update values" },
36
- { value: "reset", label: "Reset" },
37
- ],
38
- }));
39
- if (action === "reset") {
40
- const workspaceDefault = baseConfig.agent?.workspace ?? DEFAULT_WORKSPACE;
41
- const resetScope = (await prompter.select({
42
- message: "Reset scope",
43
- options: [
44
- { value: "config", label: "Config only" },
45
- {
46
- value: "config+creds+sessions",
47
- label: "Config + creds + sessions",
48
- },
49
- {
50
- value: "full",
51
- label: "Full reset (config + creds + sessions + workspace)",
52
- },
53
- ],
54
- }));
55
- await handleReset(resetScope, resolveUserPath(workspaceDefault), runtime);
56
- baseConfig = {};
57
- }
58
- else if (action === "keep" && !snapshot.valid) {
59
- baseConfig = {};
60
- }
61
- }
62
- const localPort = resolveGatewayPort(baseConfig);
63
- const localUrl = `ws://127.0.0.1:${localPort}`;
64
- const localProbe = await probeGatewayReachable({
65
- url: localUrl,
66
- token: process.env.CLAWDBOT_GATEWAY_TOKEN,
67
- password: baseConfig.gateway?.auth?.password ??
68
- process.env.CLAWDBOT_GATEWAY_PASSWORD,
69
- });
70
- const remoteUrl = baseConfig.gateway?.remote?.url?.trim() ?? "";
71
- const remoteProbe = remoteUrl
72
- ? await probeGatewayReachable({
73
- url: remoteUrl,
74
- token: baseConfig.gateway?.remote?.token,
75
- })
76
- : null;
77
- const mode = opts.mode ??
78
- (await prompter.select({
79
- message: "Where will the Gateway run?",
80
- options: [
81
- {
82
- value: "local",
83
- label: "Local (this machine)",
84
- hint: localProbe.ok
85
- ? `Gateway reachable (${localUrl})`
86
- : `No gateway detected (${localUrl})`,
87
- },
88
- {
89
- value: "remote",
90
- label: "Remote (info-only)",
91
- hint: !remoteUrl
92
- ? "No remote URL configured yet"
93
- : remoteProbe?.ok
94
- ? `Gateway reachable (${remoteUrl})`
95
- : `Configured but unreachable (${remoteUrl})`,
96
- },
97
- ],
98
- }));
99
- if (mode === "remote") {
100
- let nextConfig = await promptRemoteGatewayConfig(baseConfig, prompter);
101
- nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
102
- await writeConfigFile(nextConfig);
103
- runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
104
- await prompter.outro("Remote gateway configured.");
105
- return;
106
- }
107
- const workspaceInput = opts.workspace ??
108
- (await prompter.text({
109
- message: "Workspace directory",
110
- initialValue: baseConfig.agent?.workspace ?? DEFAULT_WORKSPACE,
111
- }));
112
- const workspaceDir = resolveUserPath(workspaceInput.trim() || DEFAULT_WORKSPACE);
113
- let nextConfig = {
114
- ...baseConfig,
115
- agent: {
116
- ...baseConfig.agent,
117
- workspace: workspaceDir,
118
- },
119
- gateway: {
120
- ...baseConfig.gateway,
121
- mode: "local",
122
- },
123
- };
124
- const authChoice = (await prompter.select({
125
- message: "Model/auth choice",
126
- options: [
127
- { value: "oauth", label: "Anthropic OAuth (Claude Pro/Max)" },
128
- {
129
- value: "antigravity",
130
- label: "Google Antigravity (Claude Opus 4.5, Gemini 3, etc.)",
131
- },
132
- { value: "apiKey", label: "Anthropic API key" },
133
- { value: "minimax", label: "Minimax M2.1 (LM Studio)" },
134
- { value: "skip", label: "Skip for now" },
135
- ],
136
- }));
137
- if (authChoice === "oauth") {
138
- await prompter.note("Browser will open. Paste the code shown after login (code#state).", "Anthropic OAuth");
139
- const spin = prompter.progress("Waiting for authorization…");
140
- let oauthCreds = null;
141
- try {
142
- oauthCreds = await loginAnthropic(async (url) => {
143
- await openUrl(url);
144
- runtime.log(`Open: ${url}`);
145
- }, async () => {
146
- const code = await prompter.text({
147
- message: "Paste authorization code (code#state)",
148
- validate: (value) => (value?.trim() ? undefined : "Required"),
149
- });
150
- return String(code);
151
- });
152
- spin.stop("OAuth complete");
153
- if (oauthCreds) {
154
- await writeOAuthCredentials("anthropic", oauthCreds);
155
- }
156
- }
157
- catch (err) {
158
- spin.stop("OAuth failed");
159
- runtime.error(String(err));
160
- }
161
- }
162
- else if (authChoice === "antigravity") {
163
- const isRemote = isRemoteEnvironment();
164
- await prompter.note(isRemote
165
- ? [
166
- "You are running in a remote/VPS environment.",
167
- "A URL will be shown for you to open in your LOCAL browser.",
168
- "After signing in, copy the redirect URL and paste it back here.",
169
- ].join("\n")
170
- : [
171
- "Browser will open for Google authentication.",
172
- "Sign in with your Google account that has Antigravity access.",
173
- "The callback will be captured automatically on localhost:51121.",
174
- ].join("\n"), "Google Antigravity OAuth");
175
- const spin = prompter.progress("Starting OAuth flow…");
176
- let oauthCreds = null;
177
- try {
178
- oauthCreds = await loginAntigravityVpsAware(async (url) => {
179
- if (isRemote) {
180
- spin.stop("OAuth URL ready");
181
- runtime.log(`\nOpen this URL in your LOCAL browser:\n\n${url}\n`);
182
- }
183
- else {
184
- spin.update("Complete sign-in in browser…");
185
- await openUrl(url);
186
- runtime.log(`Open: ${url}`);
187
- }
188
- }, (msg) => spin.update(msg));
189
- spin.stop("Antigravity OAuth complete");
190
- if (oauthCreds) {
191
- await writeOAuthCredentials("google-antigravity", oauthCreds);
192
- nextConfig = {
193
- ...nextConfig,
194
- agent: {
195
- ...nextConfig.agent,
196
- model: "google-antigravity/claude-opus-4-5-thinking",
197
- },
198
- };
199
- await prompter.note("Default model set to google-antigravity/claude-opus-4-5-thinking", "Model configured");
200
- }
201
- }
202
- catch (err) {
203
- spin.stop("Antigravity OAuth failed");
204
- runtime.error(String(err));
205
- }
206
- }
207
- else if (authChoice === "apiKey") {
208
- const key = await prompter.text({
209
- message: "Enter Anthropic API key",
210
- validate: (value) => (value?.trim() ? undefined : "Required"),
211
- });
212
- await setAnthropicApiKey(String(key).trim());
213
- }
214
- else if (authChoice === "minimax") {
215
- nextConfig = applyMinimaxConfig(nextConfig);
216
- }
217
- const portRaw = await prompter.text({
218
- message: "Gateway port",
219
- initialValue: String(localPort),
220
- validate: (value) => Number.isFinite(Number(value)) ? undefined : "Invalid port",
221
- });
222
- const port = Number.parseInt(String(portRaw), 10);
223
- let bind = (await prompter.select({
224
- message: "Gateway bind",
225
- options: [
226
- { value: "loopback", label: "Loopback (127.0.0.1)" },
227
- { value: "lan", label: "LAN" },
228
- { value: "tailnet", label: "Tailnet" },
229
- { value: "auto", label: "Auto" },
230
- ],
231
- }));
232
- let authMode = (await prompter.select({
233
- message: "Gateway auth",
234
- options: [
235
- {
236
- value: "off",
237
- label: "Off (loopback only)",
238
- hint: "Recommended for single-machine setups",
239
- },
240
- {
241
- value: "token",
242
- label: "Token",
243
- hint: "Use for multi-machine access or non-loopback binds",
244
- },
245
- { value: "password", label: "Password" },
246
- ],
247
- }));
248
- const tailscaleMode = (await prompter.select({
249
- message: "Tailscale exposure",
250
- options: [
251
- { value: "off", label: "Off", hint: "No Tailscale exposure" },
252
- {
253
- value: "serve",
254
- label: "Serve",
255
- hint: "Private HTTPS for your tailnet (devices on Tailscale)",
256
- },
257
- {
258
- value: "funnel",
259
- label: "Funnel",
260
- hint: "Public HTTPS via Tailscale Funnel (internet)",
261
- },
262
- ],
263
- }));
264
- let tailscaleResetOnExit = false;
265
- if (tailscaleMode !== "off") {
266
- tailscaleResetOnExit = Boolean(await prompter.confirm({
267
- message: "Reset Tailscale serve/funnel on exit?",
268
- initialValue: false,
269
- }));
270
- }
271
- if (tailscaleMode !== "off" && bind !== "loopback") {
272
- await prompter.note("Tailscale requires bind=loopback. Adjusting bind to loopback.", "Note");
273
- bind = "loopback";
274
- }
275
- if (authMode === "off" && bind !== "loopback") {
276
- await prompter.note("Non-loopback bind requires auth. Switching to token auth.", "Note");
277
- authMode = "token";
278
- }
279
- if (tailscaleMode === "funnel" && authMode !== "password") {
280
- await prompter.note("Tailscale funnel requires password auth.", "Note");
281
- authMode = "password";
282
- }
283
- let gatewayToken;
284
- if (authMode === "token") {
285
- const tokenInput = await prompter.text({
286
- message: "Gateway token (blank to generate)",
287
- placeholder: "Needed for multi-machine or non-loopback access",
288
- initialValue: randomToken(),
289
- });
290
- gatewayToken = String(tokenInput).trim() || randomToken();
291
- }
292
- if (authMode === "password") {
293
- const password = await prompter.text({
294
- message: "Gateway password",
295
- validate: (value) => (value?.trim() ? undefined : "Required"),
296
- });
297
- nextConfig = {
298
- ...nextConfig,
299
- gateway: {
300
- ...nextConfig.gateway,
301
- auth: {
302
- ...nextConfig.gateway?.auth,
303
- mode: "password",
304
- password: String(password).trim(),
305
- },
306
- },
307
- };
308
- }
309
- else if (authMode === "token") {
310
- nextConfig = {
311
- ...nextConfig,
312
- gateway: {
313
- ...nextConfig.gateway,
314
- auth: {
315
- ...nextConfig.gateway?.auth,
316
- mode: "token",
317
- token: gatewayToken,
318
- },
319
- },
320
- };
321
- }
322
- nextConfig = {
323
- ...nextConfig,
324
- gateway: {
325
- ...nextConfig.gateway,
326
- port,
327
- bind,
328
- tailscale: {
329
- ...nextConfig.gateway?.tailscale,
330
- mode: tailscaleMode,
331
- resetOnExit: tailscaleResetOnExit,
332
- },
333
- },
334
- };
335
- nextConfig = await setupProviders(nextConfig, runtime, prompter, {
336
- allowSignalInstall: true,
337
- });
338
- await writeConfigFile(nextConfig);
339
- runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
340
- await ensureWorkspaceAndSessions(workspaceDir, runtime);
341
- nextConfig = await setupSkills(nextConfig, workspaceDir, runtime, prompter);
342
- nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
343
- await writeConfigFile(nextConfig);
344
- const installDaemon = await prompter.confirm({
345
- message: "Install Gateway daemon (recommended)",
346
- initialValue: true,
347
- });
348
- if (installDaemon) {
349
- const service = resolveGatewayService();
350
- const loaded = await service.isLoaded({ env: process.env });
351
- if (loaded) {
352
- const action = (await prompter.select({
353
- message: "Gateway service already installed",
354
- options: [
355
- { value: "restart", label: "Restart" },
356
- { value: "reinstall", label: "Reinstall" },
357
- { value: "skip", label: "Skip" },
358
- ],
359
- }));
360
- if (action === "restart") {
361
- await service.restart({ stdout: process.stdout });
362
- }
363
- else if (action === "reinstall") {
364
- await service.uninstall({ env: process.env, stdout: process.stdout });
365
- }
366
- }
367
- if (!loaded ||
368
- (loaded && (await service.isLoaded({ env: process.env })) === false)) {
369
- const devMode = process.argv[1]?.includes(`${path.sep}src${path.sep}`) &&
370
- process.argv[1]?.endsWith(".ts");
371
- const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({ port, dev: devMode });
372
- const environment = {
373
- PATH: process.env.PATH,
374
- CLAWDBOT_GATEWAY_TOKEN: gatewayToken,
375
- CLAWDBOT_LAUNCHD_LABEL: process.platform === "darwin"
376
- ? GATEWAY_LAUNCH_AGENT_LABEL
377
- : undefined,
378
- };
379
- await service.install({
380
- env: process.env,
381
- stdout: process.stdout,
382
- programArguments,
383
- workingDirectory,
384
- environment,
385
- });
386
- }
387
- }
388
- await sleep(1500);
389
- try {
390
- await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
391
- }
392
- catch (err) {
393
- runtime.error(`Health check failed: ${String(err)}`);
394
- }
395
- await prompter.note([
396
- "Add nodes for extra features:",
397
- "- macOS app (system + notifications)",
398
- "- iOS app (camera/canvas)",
399
- "- Android app (camera/canvas)",
400
- ].join("\n"), "Optional apps");
401
- await prompter.note((() => {
402
- const links = resolveControlUiLinks({
403
- bind,
404
- port,
405
- basePath: baseConfig.gateway?.controlUi?.basePath,
406
- });
407
- const tokenParam = authMode === "token" && gatewayToken
408
- ? `?token=${encodeURIComponent(gatewayToken)}`
409
- : "";
410
- const authedUrl = `${links.httpUrl}${tokenParam}`;
411
- return [
412
- `Web UI: ${links.httpUrl}`,
413
- tokenParam ? `Web UI (with token): ${authedUrl}` : undefined,
414
- `Gateway WS: ${links.wsUrl}`,
415
- ]
416
- .filter(Boolean)
417
- .join("\n");
418
- })(), "Control UI");
419
- const browserSupport = await detectBrowserOpenSupport();
420
- if (!browserSupport.ok) {
421
- await prompter.note(formatControlUiSshHint({
422
- port,
423
- basePath: baseConfig.gateway?.controlUi?.basePath,
424
- token: authMode === "token" ? gatewayToken : undefined,
425
- }), "Open Control UI");
426
- }
427
- else {
428
- const wantsOpen = await prompter.confirm({
429
- message: "Open Control UI now?",
430
- initialValue: true,
431
- });
432
- if (wantsOpen) {
433
- const links = resolveControlUiLinks({
434
- bind,
435
- port,
436
- basePath: baseConfig.gateway?.controlUi?.basePath,
437
- });
438
- const tokenParam = authMode === "token" && gatewayToken
439
- ? `?token=${encodeURIComponent(gatewayToken)}`
440
- : "";
441
- const opened = await openUrl(`${links.httpUrl}${tokenParam}`);
442
- if (!opened) {
443
- await prompter.note(formatControlUiSshHint({
444
- port,
445
- basePath: baseConfig.gateway?.controlUi?.basePath,
446
- token: authMode === "token" ? gatewayToken : undefined,
447
- }), "Open Control UI");
448
- }
449
- }
450
- }
451
- await prompter.outro("Onboarding complete.");
452
- }
@@ -1,6 +0,0 @@
1
- export class WizardCancelledError extends Error {
2
- constructor(message = "wizard cancelled") {
3
- super(message);
4
- this.name = "WizardCancelledError";
5
- }
6
- }