denchclaw 2.0.0 → 2.0.1

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 (86) hide show
  1. package/apps/web/.next/standalone/apps/web/.next/BUILD_ID +1 -1
  2. package/apps/web/.next/standalone/apps/web/.next/app-build-manifest.json +102 -102
  3. package/apps/web/.next/standalone/apps/web/.next/app-path-routes-manifest.json +34 -34
  4. package/apps/web/.next/standalone/apps/web/.next/build-manifest.json +2 -2
  5. package/apps/web/.next/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  6. package/apps/web/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
  7. package/apps/web/.next/standalone/apps/web/.next/server/app/_not-found.rsc +1 -1
  8. package/apps/web/.next/standalone/apps/web/.next/server/app/api/chat/active/route_client-reference-manifest.js +1 -1
  9. package/apps/web/.next/standalone/apps/web/.next/server/app/api/chat/route_client-reference-manifest.js +1 -1
  10. package/apps/web/.next/standalone/apps/web/.next/server/app/api/chat/stop/route_client-reference-manifest.js +1 -1
  11. package/apps/web/.next/standalone/apps/web/.next/server/app/api/chat/stream/route_client-reference-manifest.js +1 -1
  12. package/apps/web/.next/standalone/apps/web/.next/server/app/api/chat/subagents/route_client-reference-manifest.js +1 -1
  13. package/apps/web/.next/standalone/apps/web/.next/server/app/api/cron/jobs/[jobId]/runs/route_client-reference-manifest.js +1 -1
  14. package/apps/web/.next/standalone/apps/web/.next/server/app/api/cron/jobs/route_client-reference-manifest.js +1 -1
  15. package/apps/web/.next/standalone/apps/web/.next/server/app/api/cron/runs/[sessionId]/route_client-reference-manifest.js +1 -1
  16. package/apps/web/.next/standalone/apps/web/.next/server/app/api/cron/runs/search-transcript/route_client-reference-manifest.js +1 -1
  17. package/apps/web/.next/standalone/apps/web/.next/server/app/api/memories/route_client-reference-manifest.js +1 -1
  18. package/apps/web/.next/standalone/apps/web/.next/server/app/api/profiles/route_client-reference-manifest.js +1 -1
  19. package/apps/web/.next/standalone/apps/web/.next/server/app/api/profiles/switch/route_client-reference-manifest.js +1 -1
  20. package/apps/web/.next/standalone/apps/web/.next/server/app/api/sessions/[sessionId]/route_client-reference-manifest.js +1 -1
  21. package/apps/web/.next/standalone/apps/web/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
  22. package/apps/web/.next/standalone/apps/web/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  23. package/apps/web/.next/standalone/apps/web/.next/server/app/api/web-sessions/[id]/messages/route_client-reference-manifest.js +1 -1
  24. package/apps/web/.next/standalone/apps/web/.next/server/app/api/web-sessions/[id]/route_client-reference-manifest.js +1 -1
  25. package/apps/web/.next/standalone/apps/web/.next/server/app/api/web-sessions/route_client-reference-manifest.js +1 -1
  26. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/assets/[...path]/route_client-reference-manifest.js +1 -1
  27. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/browse/route_client-reference-manifest.js +1 -1
  28. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/browse-file/route_client-reference-manifest.js +1 -1
  29. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/context/route_client-reference-manifest.js +1 -1
  30. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/copy/route_client-reference-manifest.js +1 -1
  31. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/db/introspect/route_client-reference-manifest.js +1 -1
  32. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/db/query/route_client-reference-manifest.js +1 -1
  33. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/delete/route_client-reference-manifest.js +1 -1
  34. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/file/route_client-reference-manifest.js +1 -1
  35. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/init/route_client-reference-manifest.js +1 -1
  36. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/list/route_client-reference-manifest.js +1 -1
  37. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/mkdir/route_client-reference-manifest.js +1 -1
  38. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/move/route_client-reference-manifest.js +1 -1
  39. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/display-field/route_client-reference-manifest.js +1 -1
  40. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/entries/[id]/route_client-reference-manifest.js +1 -1
  41. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/entries/bulk-delete/route_client-reference-manifest.js +1 -1
  42. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/entries/options/route_client-reference-manifest.js +1 -1
  43. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/entries/route_client-reference-manifest.js +1 -1
  44. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/fields/[fieldId]/enum-rename/route_client-reference-manifest.js +1 -1
  45. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/fields/[fieldId]/route_client-reference-manifest.js +1 -1
  46. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/fields/reorder/route_client-reference-manifest.js +1 -1
  47. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/route_client-reference-manifest.js +1 -1
  48. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/objects/[name]/views/route_client-reference-manifest.js +1 -1
  49. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/open-file/route_client-reference-manifest.js +1 -1
  50. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/path-info/route_client-reference-manifest.js +1 -1
  51. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/query/route_client-reference-manifest.js +1 -1
  52. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/raw-file/route_client-reference-manifest.js +1 -1
  53. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/rename/route_client-reference-manifest.js +1 -1
  54. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/reports/execute/route_client-reference-manifest.js +1 -1
  55. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/search-index/route_client-reference-manifest.js +1 -1
  56. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/suggest-files/route_client-reference-manifest.js +1 -1
  57. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/switch/route_client-reference-manifest.js +1 -1
  58. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/thumbnail/route_client-reference-manifest.js +1 -1
  59. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/tree/route_client-reference-manifest.js +1 -1
  60. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/upload/route_client-reference-manifest.js +1 -1
  61. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/virtual-file/route_client-reference-manifest.js +1 -1
  62. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/watch/route_client-reference-manifest.js +1 -1
  63. package/apps/web/.next/standalone/apps/web/.next/server/app/api/workspace/write-binary/route_client-reference-manifest.js +1 -1
  64. package/apps/web/.next/standalone/apps/web/.next/server/app/index.html +2 -2
  65. package/apps/web/.next/standalone/apps/web/.next/server/app/index.rsc +1 -1
  66. package/apps/web/.next/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  67. package/apps/web/.next/standalone/apps/web/.next/server/app/workspace/page_client-reference-manifest.js +1 -1
  68. package/apps/web/.next/standalone/apps/web/.next/server/app/workspace.html +1 -1
  69. package/apps/web/.next/standalone/apps/web/.next/server/app/workspace.rsc +1 -1
  70. package/apps/web/.next/standalone/apps/web/.next/server/app-paths-manifest.json +34 -34
  71. package/apps/web/.next/standalone/apps/web/.next/server/functions-config-manifest.json +19 -19
  72. package/apps/web/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
  73. package/apps/web/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
  74. package/apps/web/.next/standalone/package.json +2 -2
  75. package/dist/{cli-name-DUQ-cavN.js → cli-name-8WJ6gVD5.js} +36 -3
  76. package/dist/entry.js +2 -21
  77. package/dist/{register.bootstrap-D9YhQgaK.js → program-DhxRjAOe.js} +926 -91
  78. package/dist/{run-main-buUOQk0k.js → run-main-oHgYgpCR.js} +5 -6
  79. package/package.json +2 -2
  80. package/dist/links-BTx7dmFj.js +0 -57
  81. package/dist/program-DahL9wBm.js +0 -195
  82. package/dist/theme-uCBEEejb.js +0 -36
  83. /package/apps/web/.next/standalone/apps/web/.next/static/{oOwR1DKioMELtFQgLgScE → InPdqFM6GAVmsiSfDz98A}/_buildManifest.js +0 -0
  84. /package/apps/web/.next/standalone/apps/web/.next/static/{oOwR1DKioMELtFQgLgScE → InPdqFM6GAVmsiSfDz98A}/_ssgManifest.js +0 -0
  85. /package/apps/web/.next/static/{oOwR1DKioMELtFQgLgScE → InPdqFM6GAVmsiSfDz98A}/_buildManifest.js +0 -0
  86. /package/apps/web/.next/static/{oOwR1DKioMELtFQgLgScE → InPdqFM6GAVmsiSfDz98A}/_ssgManifest.js +0 -0
@@ -1,18 +1,517 @@
1
- import { f as applyCliProfileEnv, i as defaultRuntime, m as resolveRequiredHomeDir, t as isTruthyEnvValue } from "./entry.js";
2
- import { t as formatDocsLink } from "./links-BTx7dmFj.js";
3
- import { n as theme, t as isRich } from "./theme-uCBEEejb.js";
4
- import { spawn } from "node:child_process";
1
+ import { c as hasFlag, d as applyCliProfileEnv, f as expandHomePrefix, i as defaultRuntime, p as resolveRequiredHomeDir, s as getPrimaryCommand, t as isTruthyEnvValue, u as hasRootVersionAlias } from "./entry.js";
2
+ import { a as hasEmittedCliBanner, c as theme, i as formatCliBannerLine, n as resolveCliName, o as VERSION, s as isRich, t as replaceCliName } from "./cli-name-8WJ6gVD5.js";
3
+ import { execFileSync, spawn } from "node:child_process";
5
4
  import process$1 from "node:process";
6
5
  import os from "node:os";
7
6
  import path from "node:path";
8
- import { copyFileSync, cpSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
9
- import { fileURLToPath } from "node:url";
7
+ import fs, { copyFileSync, cpSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
8
+ import { Command } from "commander";
10
9
  import { confirm, isCancel, spinner } from "@clack/prompts";
10
+ import { fileURLToPath } from "node:url";
11
11
  import { createConnection } from "node:net";
12
12
 
13
+ //#region src/infra/ports-lsof.ts
14
+ const LSOF_CANDIDATES = process.platform === "darwin" ? ["/usr/sbin/lsof", "/usr/bin/lsof"] : ["/usr/bin/lsof", "/usr/sbin/lsof"];
15
+ function resolveLsofCommandSync() {
16
+ for (const candidate of LSOF_CANDIDATES) try {
17
+ fs.accessSync(candidate, fs.constants.X_OK);
18
+ return candidate;
19
+ } catch {}
20
+ return "lsof";
21
+ }
22
+
23
+ //#endregion
24
+ //#region src/utils.ts
25
+ /**
26
+ * Escapes special regex characters in a string so it can be used in a RegExp constructor.
27
+ */
28
+ function escapeRegExp(value) {
29
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
30
+ }
31
+ function sleep$1(ms) {
32
+ return new Promise((resolve) => setTimeout(resolve, ms));
33
+ }
34
+ function resolveUserPath(input) {
35
+ const trimmed = input.trim();
36
+ if (!trimmed) return trimmed;
37
+ if (trimmed.startsWith("~")) {
38
+ const expanded = expandHomePrefix(trimmed, {
39
+ home: resolveRequiredHomeDir(process.env, os.homedir),
40
+ env: process.env,
41
+ homedir: os.homedir
42
+ });
43
+ return path.resolve(expanded);
44
+ }
45
+ return path.resolve(trimmed);
46
+ }
47
+ function resolveConfigDir(env = process.env, homedir = os.homedir) {
48
+ const override = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
49
+ if (override) return resolveUserPath(override);
50
+ const newDir = path.join(resolveRequiredHomeDir(env, homedir), ".openclaw");
51
+ try {
52
+ if (fs.existsSync(newDir)) return newDir;
53
+ } catch {}
54
+ return newDir;
55
+ }
56
+ function formatTerminalLink(label, url, opts) {
57
+ const esc = "\x1B";
58
+ const safeLabel = label.replaceAll(esc, "");
59
+ const safeUrl = url.replaceAll(esc, "");
60
+ if (!(opts?.force === true ? true : opts?.force === false ? false : Boolean(process.stdout.isTTY))) return opts?.fallback ?? `${safeLabel} (${safeUrl})`;
61
+ return `\u001b]8;;${safeUrl}\u0007${safeLabel}\u001b]8;;\u0007`;
62
+ }
63
+ const CONFIG_DIR = resolveConfigDir();
64
+
65
+ //#endregion
66
+ //#region src/cli/ports.ts
67
+ function parseLsofOutput(output) {
68
+ const lines = output.split(/\r?\n/).filter(Boolean);
69
+ const results = [];
70
+ let current = {};
71
+ for (const line of lines) if (line.startsWith("p")) {
72
+ if (current.pid) results.push(current);
73
+ current = { pid: Number.parseInt(line.slice(1), 10) };
74
+ } else if (line.startsWith("c")) current.command = line.slice(1);
75
+ if (current.pid) results.push(current);
76
+ return results;
77
+ }
78
+ function listPortListeners(port) {
79
+ try {
80
+ return parseLsofOutput(execFileSync(resolveLsofCommandSync(), [
81
+ "-nP",
82
+ `-iTCP:${port}`,
83
+ "-sTCP:LISTEN",
84
+ "-FpFc"
85
+ ], { encoding: "utf-8" }));
86
+ } catch (err) {
87
+ const status = err.status;
88
+ if (err.code === "ENOENT") throw new Error("lsof not found; required for --force", { cause: err });
89
+ if (status === 1) return [];
90
+ throw err instanceof Error ? err : new Error(String(err));
91
+ }
92
+ }
93
+
94
+ //#endregion
95
+ //#region src/terminal/links.ts
96
+ const DOCS_ROOT = "https://docs.openclaw.ai";
97
+ function formatDocsLink(path, label, opts) {
98
+ const trimmed = path.trim();
99
+ const url = trimmed.startsWith("http") ? trimmed : `${DOCS_ROOT}${trimmed.startsWith("/") ? trimmed : `/${trimmed}`}`;
100
+ return formatTerminalLink(label ?? url, url, {
101
+ fallback: opts?.fallback ?? url,
102
+ force: opts?.force
103
+ });
104
+ }
105
+
106
+ //#endregion
13
107
  //#region src/terminal/prompt-style.ts
14
108
  const stylePromptMessage = (message) => isRich() ? theme.accent(message) : message;
15
109
 
110
+ //#endregion
111
+ //#region src/cli/web-runtime.ts
112
+ const DEFAULT_WEB_APP_PORT = 3100;
113
+ const WEB_RUNTIME_DIRNAME = "web-runtime";
114
+ const WEB_RUNTIME_APP_DIRNAME = "app";
115
+ const WEB_RUNTIME_MANIFEST_FILENAME = "manifest.json";
116
+ const WEB_RUNTIME_PROCESS_FILENAME = "process.json";
117
+ const WEB_APP_PROBE_ATTEMPTS = 20;
118
+ const WEB_APP_PROBE_DELAY_MS = 750;
119
+ const WEB_APP_PROBE_TIMEOUT_MS = 1500;
120
+ const LEGACY_STANDALONE_SEGMENT = "/apps/web/.next/standalone/apps/web";
121
+ function normalizePathForMatch(value) {
122
+ return value.replaceAll("\\", "/").toLowerCase();
123
+ }
124
+ function isPathWithin(parentDir, candidatePath) {
125
+ const relative = path.relative(path.resolve(parentDir), path.resolve(candidatePath));
126
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
127
+ }
128
+ function parseOptionalPositiveInt(value) {
129
+ if (value === void 0) return;
130
+ const parsed = typeof value === "number" ? value : Number.parseInt(String(value), 10);
131
+ if (!Number.isFinite(parsed) || parsed <= 0) return;
132
+ return parsed;
133
+ }
134
+ function ensureParentDir(filePath) {
135
+ mkdirSync(path.dirname(filePath), { recursive: true });
136
+ }
137
+ function readJsonFile(filePath) {
138
+ if (!existsSync(filePath)) return null;
139
+ try {
140
+ return JSON.parse(readFileSync(filePath, "utf-8"));
141
+ } catch {
142
+ return null;
143
+ }
144
+ }
145
+ function writeJsonFile(filePath, value) {
146
+ ensureParentDir(filePath);
147
+ writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
148
+ }
149
+ function isProcessAlive(pid) {
150
+ try {
151
+ process$1.kill(pid, 0);
152
+ return true;
153
+ } catch (error) {
154
+ return error.code !== "ESRCH";
155
+ }
156
+ }
157
+ async function terminatePidWithEscalation(pid) {
158
+ try {
159
+ process$1.kill(pid, "SIGTERM");
160
+ } catch (error) {
161
+ if (error.code === "ESRCH") return;
162
+ throw error;
163
+ }
164
+ for (let i = 0; i < 8; i += 1) {
165
+ if (!isProcessAlive(pid)) return;
166
+ await sleep$1(100);
167
+ }
168
+ if (!isProcessAlive(pid)) return;
169
+ try {
170
+ process$1.kill(pid, "SIGKILL");
171
+ } catch (error) {
172
+ if (error.code === "ESRCH") return;
173
+ throw error;
174
+ }
175
+ for (let i = 0; i < 8; i += 1) {
176
+ if (!isProcessAlive(pid)) return;
177
+ await sleep$1(100);
178
+ }
179
+ }
180
+ function resolveCliPackageRoot() {
181
+ let dir = path.dirname(fileURLToPath(import.meta.url));
182
+ for (let i = 0; i < 5; i += 1) {
183
+ if (existsSync(path.join(dir, "package.json"))) return dir;
184
+ dir = path.dirname(dir);
185
+ }
186
+ return process$1.cwd();
187
+ }
188
+ function resolveProfileStateDir(profile, env = process$1.env) {
189
+ const home = resolveRequiredHomeDir(env, os.homedir);
190
+ return path.join(home, ".openclaw-dench");
191
+ }
192
+ function resolveManagedWebRuntimeDir(stateDir) {
193
+ return path.join(stateDir, WEB_RUNTIME_DIRNAME);
194
+ }
195
+ function resolveManagedWebRuntimeAppDir(stateDir) {
196
+ return path.join(resolveManagedWebRuntimeDir(stateDir), WEB_RUNTIME_APP_DIRNAME);
197
+ }
198
+ function resolveManagedWebRuntimeServerPath(stateDir) {
199
+ return path.join(resolveManagedWebRuntimeAppDir(stateDir), "server.js");
200
+ }
201
+ function resolveManagedWebRuntimeManifestPath(stateDir) {
202
+ return path.join(resolveManagedWebRuntimeDir(stateDir), WEB_RUNTIME_MANIFEST_FILENAME);
203
+ }
204
+ function resolveManagedWebRuntimeProcessPath(stateDir) {
205
+ return path.join(resolveManagedWebRuntimeDir(stateDir), WEB_RUNTIME_PROCESS_FILENAME);
206
+ }
207
+ function resolvePackagedStandaloneServerPath(packageRoot) {
208
+ return path.join(packageRoot, "apps/web/.next/standalone/apps/web/server.js");
209
+ }
210
+ function resolvePackagedStandaloneAppDir(packageRoot) {
211
+ return path.dirname(resolvePackagedStandaloneServerPath(packageRoot));
212
+ }
213
+ function readManagedWebRuntimeManifest(stateDir) {
214
+ return readJsonFile(resolveManagedWebRuntimeManifestPath(stateDir));
215
+ }
216
+ function readManagedWebRuntimeProcess(stateDir) {
217
+ return readJsonFile(resolveManagedWebRuntimeProcessPath(stateDir));
218
+ }
219
+ function writeManagedWebRuntimeManifest(stateDir, manifest) {
220
+ writeJsonFile(resolveManagedWebRuntimeManifestPath(stateDir), manifest);
221
+ return manifest;
222
+ }
223
+ function writeManagedWebRuntimeProcess(stateDir, processMeta) {
224
+ writeJsonFile(resolveManagedWebRuntimeProcessPath(stateDir), processMeta);
225
+ }
226
+ function clearManagedWebRuntimeProcess(stateDir) {
227
+ rmSync(resolveManagedWebRuntimeProcessPath(stateDir), { force: true });
228
+ }
229
+ function updateManifestLastPort(stateDir, webPort, gatewayPort) {
230
+ const manifest = readManagedWebRuntimeManifest(stateDir);
231
+ if (!manifest) return null;
232
+ return writeManagedWebRuntimeManifest(stateDir, {
233
+ ...manifest,
234
+ lastPort: webPort,
235
+ lastGatewayPort: gatewayPort
236
+ });
237
+ }
238
+ function evaluateWebProfilesPayload(payload) {
239
+ if (!payload || typeof payload !== "object") return {
240
+ ok: false,
241
+ reason: "response payload is not an object"
242
+ };
243
+ const data = payload;
244
+ if (!(Array.isArray(data.profiles) ? data.profiles : Array.isArray(data.workspaces) ? data.workspaces : void 0)) return {
245
+ ok: false,
246
+ reason: "response payload missing profiles/workspaces array"
247
+ };
248
+ if ((data.activeProfile === null || typeof data.activeProfile === "string" ? data.activeProfile : data.activeWorkspace === null || typeof data.activeWorkspace === "string" ? data.activeWorkspace : void 0) === void 0) return {
249
+ ok: false,
250
+ reason: "response payload missing active profile/workspace field"
251
+ };
252
+ return {
253
+ ok: true,
254
+ reason: "profiles payload shape is valid"
255
+ };
256
+ }
257
+ async function probeWebRuntime(port) {
258
+ const controller = new AbortController();
259
+ const timer = setTimeout(() => controller.abort(), WEB_APP_PROBE_TIMEOUT_MS);
260
+ try {
261
+ const response = await fetch(`http://127.0.0.1:${port}/api/profiles`, {
262
+ method: "GET",
263
+ signal: controller.signal,
264
+ redirect: "manual"
265
+ });
266
+ if (response.status < 200 || response.status >= 400) return {
267
+ ok: false,
268
+ status: response.status,
269
+ reason: `/api/profiles returned status ${response.status}`
270
+ };
271
+ const evaluation = evaluateWebProfilesPayload(await response.json().catch(() => null));
272
+ return {
273
+ ok: evaluation.ok,
274
+ status: response.status,
275
+ reason: evaluation.reason
276
+ };
277
+ } catch (error) {
278
+ return {
279
+ ok: false,
280
+ reason: (error instanceof Error ? error.message : String(error)) || "probe failed"
281
+ };
282
+ } finally {
283
+ clearTimeout(timer);
284
+ }
285
+ }
286
+ async function waitForWebRuntime(port) {
287
+ let lastResult = {
288
+ ok: false,
289
+ reason: "web runtime did not respond"
290
+ };
291
+ for (let attempt = 0; attempt < WEB_APP_PROBE_ATTEMPTS; attempt += 1) {
292
+ const result = await probeWebRuntime(port);
293
+ if (result.ok) return result;
294
+ lastResult = result;
295
+ await sleep$1(WEB_APP_PROBE_DELAY_MS);
296
+ }
297
+ return lastResult;
298
+ }
299
+ function classifyWebPortListener(params) {
300
+ if (!params.cwd) return "foreign";
301
+ if (isPathWithin(params.managedRuntimeAppDir, params.cwd)) return "managed";
302
+ if (normalizePathForMatch(params.cwd).includes(LEGACY_STANDALONE_SEGMENT)) return "legacy-standalone";
303
+ return "foreign";
304
+ }
305
+ function parseSemverMajor(version) {
306
+ if (!version) return null;
307
+ const match = version.trim().match(/^v?(\d+)(?:\.\d+)?(?:\.\d+)?(?:[-+].*)?$/u);
308
+ if (!match) return null;
309
+ const major = Number.parseInt(match[1], 10);
310
+ if (!Number.isFinite(major)) return null;
311
+ return major;
312
+ }
313
+ function evaluateMajorVersionTransition(params) {
314
+ const previousMajor = parseSemverMajor(params.previousVersion);
315
+ const currentMajor = parseSemverMajor(params.currentVersion);
316
+ return {
317
+ previousMajor,
318
+ currentMajor,
319
+ isMajorTransition: previousMajor !== null && currentMajor !== null && previousMajor !== currentMajor
320
+ };
321
+ }
322
+ function resolveProcessCwd(pid) {
323
+ try {
324
+ const output = execFileSync(resolveLsofCommandSync(), [
325
+ "-nP",
326
+ "-a",
327
+ "-p",
328
+ String(pid),
329
+ "-d",
330
+ "cwd",
331
+ "-Fn"
332
+ ], { encoding: "utf-8" });
333
+ for (const line of output.split(/\r?\n/)) if (line.startsWith("n")) {
334
+ const cwd = line.slice(1).trim();
335
+ if (cwd.length > 0) return cwd;
336
+ }
337
+ return;
338
+ } catch {
339
+ return;
340
+ }
341
+ }
342
+ function inspectWebPortListeners(port, stateDir) {
343
+ if (process$1.env.VITEST === "true" && process$1.env.OPENCLAW_TEST_REAL_PORTS !== "1") return [];
344
+ const listeners = listPortListeners(port);
345
+ const managedRuntimeAppDir = resolveManagedWebRuntimeAppDir(stateDir);
346
+ return listeners.map((listener) => {
347
+ const cwd = resolveProcessCwd(listener.pid);
348
+ const ownership = classifyWebPortListener({
349
+ cwd,
350
+ managedRuntimeAppDir
351
+ });
352
+ return {
353
+ ...listener,
354
+ cwd,
355
+ ownership
356
+ };
357
+ });
358
+ }
359
+ function readLastKnownWebPort(stateDir) {
360
+ const processPort = parseOptionalPositiveInt(readManagedWebRuntimeProcess(stateDir)?.port);
361
+ if (processPort) return processPort;
362
+ const manifestPort = parseOptionalPositiveInt(readManagedWebRuntimeManifest(stateDir)?.lastPort);
363
+ if (manifestPort) return manifestPort;
364
+ return DEFAULT_WEB_APP_PORT;
365
+ }
366
+ function installManagedWebRuntime(params) {
367
+ const runtimeDir = resolveManagedWebRuntimeDir(params.stateDir);
368
+ const runtimeAppDir = resolveManagedWebRuntimeAppDir(params.stateDir);
369
+ const runtimeServerPath = resolveManagedWebRuntimeServerPath(params.stateDir);
370
+ const sourceStandaloneServer = resolvePackagedStandaloneServerPath(params.packageRoot);
371
+ const sourceAppDir = resolvePackagedStandaloneAppDir(params.packageRoot);
372
+ if (!existsSync(sourceStandaloneServer)) return {
373
+ installed: false,
374
+ runtimeDir,
375
+ runtimeAppDir,
376
+ runtimeServerPath,
377
+ reason: "standalone-missing"
378
+ };
379
+ mkdirSync(runtimeDir, { recursive: true });
380
+ rmSync(runtimeAppDir, {
381
+ recursive: true,
382
+ force: true
383
+ });
384
+ cpSync(sourceAppDir, runtimeAppDir, {
385
+ recursive: true,
386
+ force: true
387
+ });
388
+ const manifest = {
389
+ schemaVersion: 1,
390
+ deployedDenchVersion: params.denchVersion,
391
+ deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
392
+ sourceStandaloneServer,
393
+ ...typeof params.webPort === "number" ? { lastPort: params.webPort } : {},
394
+ ...typeof params.gatewayPort === "number" ? { lastGatewayPort: params.gatewayPort } : {}
395
+ };
396
+ writeManagedWebRuntimeManifest(params.stateDir, manifest);
397
+ return {
398
+ installed: true,
399
+ runtimeDir,
400
+ runtimeAppDir,
401
+ runtimeServerPath,
402
+ manifest
403
+ };
404
+ }
405
+ async function stopManagedWebRuntime(params) {
406
+ const listeners = inspectWebPortListeners(params.port, params.stateDir);
407
+ const includeLegacyStandalone = params.includeLegacyStandalone ?? true;
408
+ const stoppable = listeners.filter((listener) => listener.ownership === "managed" || includeLegacyStandalone && listener.ownership === "legacy-standalone");
409
+ const skippedForeign = listeners.filter((listener) => listener.ownership === "foreign");
410
+ const uniquePids = [...new Set(stoppable.map((listener) => listener.pid))];
411
+ const stoppedPids = [];
412
+ for (const pid of uniquePids) {
413
+ await terminatePidWithEscalation(pid);
414
+ if (!isProcessAlive(pid)) stoppedPids.push(pid);
415
+ }
416
+ const processMeta = readManagedWebRuntimeProcess(params.stateDir);
417
+ if (processMeta?.port === params.port && stoppedPids.includes(processMeta.pid)) clearManagedWebRuntimeProcess(params.stateDir);
418
+ if (inspectWebPortListeners(params.port, params.stateDir).filter((listener) => listener.ownership === "managed").length === 0) clearManagedWebRuntimeProcess(params.stateDir);
419
+ return {
420
+ port: params.port,
421
+ stoppedPids,
422
+ skippedForeignPids: [...new Set(skippedForeign.map((listener) => listener.pid))]
423
+ };
424
+ }
425
+ function startManagedWebRuntime(params) {
426
+ const runtimeServerPath = resolveManagedWebRuntimeServerPath(params.stateDir);
427
+ if (!existsSync(runtimeServerPath)) return {
428
+ started: false,
429
+ runtimeServerPath,
430
+ reason: "runtime-missing"
431
+ };
432
+ const logsDir = path.join(params.stateDir, "logs");
433
+ mkdirSync(logsDir, { recursive: true });
434
+ const outFd = openSync(path.join(logsDir, "web-app.log"), "a");
435
+ const errFd = openSync(path.join(logsDir, "web-app.err.log"), "a");
436
+ const child = spawn(process$1.execPath, [runtimeServerPath], {
437
+ cwd: path.dirname(runtimeServerPath),
438
+ detached: true,
439
+ stdio: [
440
+ "ignore",
441
+ outFd,
442
+ errFd
443
+ ],
444
+ env: {
445
+ ...process$1.env,
446
+ ...params.env,
447
+ PORT: String(params.port),
448
+ HOSTNAME: "127.0.0.1",
449
+ OPENCLAW_GATEWAY_PORT: String(params.gatewayPort)
450
+ }
451
+ });
452
+ child.unref();
453
+ writeManagedWebRuntimeProcess(params.stateDir, {
454
+ pid: child.pid ?? -1,
455
+ port: params.port,
456
+ gatewayPort: params.gatewayPort,
457
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
458
+ runtimeAppDir: path.dirname(runtimeServerPath)
459
+ });
460
+ updateManifestLastPort(params.stateDir, params.port, params.gatewayPort);
461
+ return {
462
+ started: true,
463
+ pid: child.pid ?? -1,
464
+ runtimeServerPath
465
+ };
466
+ }
467
+ async function ensureManagedWebRuntime(params) {
468
+ if (!installManagedWebRuntime({
469
+ stateDir: params.stateDir,
470
+ packageRoot: params.packageRoot,
471
+ denchVersion: params.denchVersion,
472
+ webPort: params.port,
473
+ gatewayPort: params.gatewayPort
474
+ }).installed) return {
475
+ ready: false,
476
+ reason: "standalone web build is missing from package"
477
+ };
478
+ await stopManagedWebRuntime({
479
+ stateDir: params.stateDir,
480
+ port: params.port,
481
+ includeLegacyStandalone: true
482
+ });
483
+ const foreign = inspectWebPortListeners(params.port, params.stateDir).filter((listener) => listener.ownership === "foreign");
484
+ if (foreign.length > 0) {
485
+ const detail = foreign.map((listener) => `${listener.pid}${listener.command ? `:${listener.command}` : ""}`).join(", ");
486
+ return {
487
+ ready: false,
488
+ reason: `port ${params.port} is owned by non-Dench process(es): ${detail}`
489
+ };
490
+ }
491
+ if (!startManagedWebRuntime({
492
+ stateDir: params.stateDir,
493
+ port: params.port,
494
+ gatewayPort: params.gatewayPort
495
+ }).started) return {
496
+ ready: false,
497
+ reason: "managed web runtime is missing after install"
498
+ };
499
+ const probe = await waitForWebRuntime(params.port);
500
+ return {
501
+ ready: probe.ok,
502
+ reason: probe.reason
503
+ };
504
+ }
505
+ function resolveOpenClawCommandOrThrow() {
506
+ try {
507
+ const first = execFileSync(process$1.platform === "win32" ? "where" : "which", ["openclaw"], { encoding: "utf-8" }).trim().split(/\r?\n/).map((line) => line.trim()).find(Boolean);
508
+ if (first) return first;
509
+ throw new Error("openclaw command not found");
510
+ } catch {
511
+ throw new Error("Global `openclaw` CLI was not found on PATH. Install it with: npm install -g openclaw");
512
+ }
513
+ }
514
+
16
515
  //#endregion
17
516
  //#region src/cli/workspace-seed.ts
18
517
  const SEED_OBJECTS = [
@@ -328,13 +827,9 @@ function seedWorkspaceFromAssets(params) {
328
827
  //#endregion
329
828
  //#region src/cli/bootstrap-external.ts
330
829
  const DEFAULT_DENCHCLAW_PROFILE = "dench";
331
- const DENCHCLAW_STATE_DIRNAME = ".openclaw-dench";
332
830
  const DEFAULT_GATEWAY_PORT = 18789;
333
831
  const DENCHCLAW_GATEWAY_PORT_START = 19001;
334
832
  const MAX_PORT_SCAN_ATTEMPTS = 100;
335
- const DEFAULT_WEB_APP_PORT = 3100;
336
- const WEB_APP_PROBE_ATTEMPTS = 20;
337
- const WEB_APP_PROBE_DELAY_MS = 750;
338
833
  const DEFAULT_BOOTSTRAP_ROLLOUT_STAGE = "default";
339
834
  const DEFAULT_GATEWAY_LAUNCH_AGENT_LABEL = "ai.openclaw.gateway";
340
835
  const REQUIRED_TOOLS_PROFILE = "full";
@@ -397,7 +892,7 @@ async function runCommandWithTimeout(argv, options) {
397
892
  });
398
893
  });
399
894
  }
400
- function parseOptionalPort(value) {
895
+ function parseOptionalPort$1(value) {
401
896
  if (value === void 0) return;
402
897
  const raw = typeof value === "number" ? value : Number.parseInt(String(value), 10);
403
898
  if (!Number.isFinite(raw) || raw <= 0) return;
@@ -447,16 +942,12 @@ function normalizeVersionOutput(raw) {
447
942
  const first = raw?.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
448
943
  return first && first.length > 0 ? first : void 0;
449
944
  }
450
- function firstNonEmptyLine(...values) {
945
+ function firstNonEmptyLine$1(...values) {
451
946
  for (const value of values) {
452
947
  const first = value?.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
453
948
  if (first) return first;
454
949
  }
455
950
  }
456
- function resolveProfileStateDir(profile, env = process$1.env) {
457
- const home = resolveRequiredHomeDir(env, os.homedir);
458
- return path.join(home, DENCHCLAW_STATE_DIRNAME);
459
- }
460
951
  function resolveGatewayLaunchAgentLabel(profile) {
461
952
  const normalized = profile.trim().toLowerCase();
462
953
  if (!normalized || normalized === "default") return DEFAULT_GATEWAY_LAUNCH_AGENT_LABEL;
@@ -551,67 +1042,6 @@ async function ensureToolsProfile(openclawCommand, profile) {
551
1042
  errorMessage: `Failed to set tools.profile=${REQUIRED_TOOLS_PROFILE}.`
552
1043
  });
553
1044
  }
554
- async function probeForWebApp(port) {
555
- const controller = new AbortController();
556
- const timer = setTimeout(() => controller.abort(), 1500);
557
- try {
558
- const response = await fetch(`http://127.0.0.1:${port}/api/profiles`, {
559
- method: "GET",
560
- signal: controller.signal,
561
- redirect: "manual"
562
- });
563
- if (response.status < 200 || response.status >= 400) return false;
564
- const payload = await response.json().catch(() => null);
565
- return Boolean(payload && typeof payload === "object" && Array.isArray(payload.profiles) && typeof payload.activeProfile === "string");
566
- } catch {
567
- return false;
568
- } finally {
569
- clearTimeout(timer);
570
- }
571
- }
572
- async function waitForWebApp(preferredPort) {
573
- for (let attempt = 0; attempt < WEB_APP_PROBE_ATTEMPTS; attempt += 1) {
574
- if (await probeForWebApp(preferredPort)) return true;
575
- await sleep(WEB_APP_PROBE_DELAY_MS);
576
- }
577
- return false;
578
- }
579
- function resolveCliPackageRoot() {
580
- let dir = path.dirname(fileURLToPath(import.meta.url));
581
- for (let i = 0; i < 5; i++) {
582
- if (existsSync(path.join(dir, "package.json"))) return dir;
583
- dir = path.dirname(dir);
584
- }
585
- return process$1.cwd();
586
- }
587
- /**
588
- * Spawn the pre-built standalone Next.js server as a detached background
589
- * process if it isn't already running on the target port.
590
- */
591
- function startWebAppIfNeeded(port, stateDir, gatewayPort) {
592
- const pkgRoot = resolveCliPackageRoot();
593
- const standaloneServer = path.join(pkgRoot, "apps/web/.next/standalone/apps/web/server.js");
594
- if (!existsSync(standaloneServer)) return;
595
- const logDir = path.join(stateDir, "logs");
596
- mkdirSync(logDir, { recursive: true });
597
- const outFd = openSync(path.join(logDir, "web-app.log"), "a");
598
- const errFd = openSync(path.join(logDir, "web-app.err.log"), "a");
599
- spawn(process$1.execPath, [standaloneServer], {
600
- cwd: path.dirname(standaloneServer),
601
- detached: true,
602
- stdio: [
603
- "ignore",
604
- outFd,
605
- errFd
606
- ],
607
- env: {
608
- ...process$1.env,
609
- PORT: String(port),
610
- HOSTNAME: "127.0.0.1",
611
- OPENCLAW_GATEWAY_PORT: String(gatewayPort)
612
- }
613
- }).unref();
614
- }
615
1045
  async function runOpenClaw(openclawCommand, args, timeoutMs, ioMode = "capture", env) {
616
1046
  return await runCommandWithTimeout([openclawCommand, ...args], {
617
1047
  timeoutMs,
@@ -622,7 +1052,7 @@ async function runOpenClaw(openclawCommand, args, timeoutMs, ioMode = "capture",
622
1052
  async function runOpenClawOrThrow(params) {
623
1053
  const result = await runOpenClaw(params.openclawCommand, params.args, params.timeoutMs);
624
1054
  if (result.code === 0) return result;
625
- const detail = firstNonEmptyLine(result.stderr, result.stdout);
1055
+ const detail = firstNonEmptyLine$1(result.stderr, result.stdout);
626
1056
  throw new Error(detail ? `${params.errorMessage}\n${detail}` : params.errorMessage);
627
1057
  }
628
1058
  /**
@@ -632,7 +1062,7 @@ async function runOpenClawOrThrow(params) {
632
1062
  async function runOpenClawInteractiveOrThrow(params) {
633
1063
  const result = await runOpenClaw(params.openclawCommand, params.args, params.timeoutMs, "inherit");
634
1064
  if (result.code === 0) return result;
635
- const detail = firstNonEmptyLine(result.stderr, result.stdout);
1065
+ const detail = firstNonEmptyLine$1(result.stderr, result.stdout);
636
1066
  throw new Error(detail ? `${params.errorMessage}\n${detail}` : params.errorMessage);
637
1067
  }
638
1068
  /**
@@ -689,7 +1119,7 @@ async function runOpenClawWithProgress(params) {
689
1119
  s.stop(params.successMessage);
690
1120
  return result;
691
1121
  }
692
- const detail = firstNonEmptyLine(result.stderr, result.stdout);
1122
+ const detail = firstNonEmptyLine$1(result.stderr, result.stdout);
693
1123
  const stopMessage = detail ? `${params.errorMessage}: ${detail}` : params.errorMessage;
694
1124
  s.stop(stopMessage);
695
1125
  throw new Error(detail ? `${params.errorMessage}\n${detail}` : params.errorMessage);
@@ -737,7 +1167,7 @@ async function resolveNpmGlobalBinDir() {
737
1167
  "-g"
738
1168
  ], { timeoutMs: 8e3 }).catch(() => null);
739
1169
  if (!result || result.code !== 0) return;
740
- const prefix = firstNonEmptyLine(result.stdout);
1170
+ const prefix = firstNonEmptyLine$1(result.stdout);
741
1171
  if (!prefix) return;
742
1172
  return process$1.platform === "win32" ? prefix : path.join(prefix, "bin");
743
1173
  }
@@ -748,7 +1178,7 @@ function resolveGlobalOpenClawCommand(globalBinDir) {
748
1178
  async function resolveShellOpenClawPath() {
749
1179
  const result = await runCommandWithTimeout([process$1.platform === "win32" ? "where" : "which", "openclaw"], { timeoutMs: 4e3 }).catch(() => null);
750
1180
  if (!result || result.code !== 0) return;
751
- return firstNonEmptyLine(result.stdout);
1181
+ return firstNonEmptyLine$1(result.stdout);
752
1182
  }
753
1183
  function isProjectLocalOpenClawPath(commandPath) {
754
1184
  if (!commandPath) return false;
@@ -803,7 +1233,7 @@ async function probeGateway(openclawCommand, profile, gatewayPort) {
803
1233
  if (result.code === 0) return { ok: true };
804
1234
  return {
805
1235
  ok: false,
806
- detail: firstNonEmptyLine(result.stderr, result.stdout)
1236
+ detail: firstNonEmptyLine$1(result.stderr, result.stdout)
807
1237
  };
808
1238
  }
809
1239
  function readLogTail(logPath, maxLines = 16) {
@@ -911,7 +1341,7 @@ async function attemptGatewayAutoFix(params) {
911
1341
  steps.push({
912
1342
  name: command.name,
913
1343
  ok: result.code === 0,
914
- detail: result.code === 0 ? void 0 : firstNonEmptyLine(result.stderr, result.stdout)
1344
+ detail: result.code === 0 ? void 0 : firstNonEmptyLine$1(result.stderr, result.stdout)
915
1345
  });
916
1346
  }
917
1347
  let finalProbe = await probeGateway(params.openclawCommand, params.profile, params.gatewayPort);
@@ -948,7 +1378,11 @@ function remediationForGatewayFailure(detail, port, profile) {
948
1378
  return `Run \`openclaw --profile ${profile} doctor --fix\` and retry \`denchclaw bootstrap --profile ${profile} --force-onboard\`.`;
949
1379
  }
950
1380
  function remediationForWebUiFailure(port) {
951
- return `Web UI did not respond on ${port}. Ensure the apps/web directory exists and rerun with \`denchclaw bootstrap --web-port <port>\` if needed.`;
1381
+ return [
1382
+ `Web UI did not respond on ${port}.`,
1383
+ `Run \`dench update --web-port ${port}\` to refresh the managed web runtime.`,
1384
+ `If the port is stuck, run \`dench stop --web-port ${port}\` first.`
1385
+ ].join(" ");
952
1386
  }
953
1387
  function describeWorkspaceSeedResult(result) {
954
1388
  if (result.seeded) return `seeded ${result.dbPath}`;
@@ -1116,7 +1550,7 @@ async function bootstrapCommand(opts, runtime = defaultRuntime) {
1116
1550
  successMessage: "OpenClaw is up to date.",
1117
1551
  errorMessage: "OpenClaw update failed"
1118
1552
  });
1119
- const explicitPort = parseOptionalPort(opts.gatewayPort);
1553
+ const explicitPort = parseOptionalPort$1(opts.gatewayPort);
1120
1554
  let gatewayPort;
1121
1555
  let portAutoAssigned = false;
1122
1556
  if (explicitPort) gatewayPort = explicitPort;
@@ -1156,9 +1590,10 @@ async function bootstrapCommand(opts, runtime = defaultRuntime) {
1156
1590
  timeoutMs: 12 * 6e4,
1157
1591
  errorMessage: "OpenClaw onboarding failed."
1158
1592
  });
1593
+ const packageRoot = resolveCliPackageRoot();
1159
1594
  const workspaceSeed = seedWorkspaceFromAssets({
1160
1595
  workspaceDir,
1161
- packageRoot: resolveCliPackageRoot()
1596
+ packageRoot
1162
1597
  });
1163
1598
  await ensureGatewayModeLocal(openclawCommand, profile);
1164
1599
  await ensureGatewayPort(openclawCommand, profile, gatewayPort);
@@ -1180,9 +1615,15 @@ async function bootstrapCommand(opts, runtime = defaultRuntime) {
1180
1615
  };
1181
1616
  }
1182
1617
  const gatewayUrl = `ws://127.0.0.1:${gatewayPort}`;
1183
- const preferredWebPort = parseOptionalPort(opts.webPort) ?? DEFAULT_WEB_APP_PORT;
1184
- if (!await probeForWebApp(preferredWebPort)) startWebAppIfNeeded(preferredWebPort, stateDir, gatewayPort);
1185
- const webReachable = await waitForWebApp(preferredWebPort);
1618
+ const preferredWebPort = parseOptionalPort$1(opts.webPort) ?? DEFAULT_WEB_APP_PORT;
1619
+ const webRuntimeStatus = await ensureManagedWebRuntime({
1620
+ stateDir,
1621
+ packageRoot,
1622
+ denchVersion: VERSION,
1623
+ port: preferredWebPort,
1624
+ gatewayPort
1625
+ });
1626
+ const webReachable = webRuntimeStatus.ready;
1186
1627
  const webUrl = `http://localhost:${preferredWebPort}`;
1187
1628
  const diagnostics = buildBootstrapDiagnostics({
1188
1629
  profile,
@@ -1200,6 +1641,7 @@ async function bootstrapCommand(opts, runtime = defaultRuntime) {
1200
1641
  const shouldOpen = !opts.noOpen && !opts.json;
1201
1642
  const opened = shouldOpen ? await openUrl(webUrl) : false;
1202
1643
  if (!opts.json) {
1644
+ if (!webRuntimeStatus.ready) runtime.log(theme.warn(`Managed web runtime check failed: ${webRuntimeStatus.reason}`));
1203
1645
  if (installResult.installed) runtime.log(theme.muted("Installed global OpenClaw CLI via npm."));
1204
1646
  if (isProjectLocalOpenClawPath(installResult.shellCommandPath)) {
1205
1647
  runtime.log(theme.warn(`\`openclaw\` currently resolves to a project-local binary (${installResult.shellCommandPath}).`));
@@ -1327,4 +1769,397 @@ function registerBootstrapCommand(program) {
1327
1769
  }
1328
1770
 
1329
1771
  //#endregion
1330
- export { registerBootstrapCommand };
1772
+ //#region src/cli/web-runtime-command.ts
1773
+ function parseOptionalPort(value) {
1774
+ if (value === void 0) return;
1775
+ const parsed = typeof value === "number" ? value : Number.parseInt(String(value), 10);
1776
+ if (!Number.isFinite(parsed) || parsed <= 0) return;
1777
+ return parsed;
1778
+ }
1779
+ function firstNonEmptyLine(...values) {
1780
+ for (const value of values) {
1781
+ const first = value?.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
1782
+ if (first) return first;
1783
+ }
1784
+ }
1785
+ async function runOpenClawUpdateWithProgress(openclawCommand) {
1786
+ const s = spinner();
1787
+ s.start("Updating OpenClaw (required for this major Dench upgrade)...");
1788
+ const result = await new Promise((resolve, reject) => {
1789
+ const child = spawn(openclawCommand, ["update", "--yes"], {
1790
+ stdio: [
1791
+ "ignore",
1792
+ "pipe",
1793
+ "pipe"
1794
+ ],
1795
+ env: process$1.env
1796
+ });
1797
+ let stdout = "";
1798
+ let stderr = "";
1799
+ let settled = false;
1800
+ const timer = setTimeout(() => {
1801
+ if (!settled) child.kill("SIGKILL");
1802
+ }, 8 * 6e4);
1803
+ const updateSpinner = (chunk) => {
1804
+ const line = chunk.split(/\r?\n/).map((item) => item.trim()).filter(Boolean).at(-1);
1805
+ if (line) s.message(line.length > 72 ? `${line.slice(0, 69)}...` : line);
1806
+ };
1807
+ child.stdout?.on("data", (chunk) => {
1808
+ const text = String(chunk);
1809
+ stdout += text;
1810
+ updateSpinner(text);
1811
+ });
1812
+ child.stderr?.on("data", (chunk) => {
1813
+ const text = String(chunk);
1814
+ stderr += text;
1815
+ updateSpinner(text);
1816
+ });
1817
+ child.once("error", (error) => {
1818
+ if (settled) return;
1819
+ settled = true;
1820
+ clearTimeout(timer);
1821
+ reject(error);
1822
+ });
1823
+ child.once("close", (code) => {
1824
+ if (settled) return;
1825
+ settled = true;
1826
+ clearTimeout(timer);
1827
+ resolve({
1828
+ code: typeof code === "number" ? code : 1,
1829
+ stdout,
1830
+ stderr
1831
+ });
1832
+ });
1833
+ });
1834
+ if (result.code === 0) {
1835
+ s.stop("OpenClaw update complete.");
1836
+ return;
1837
+ }
1838
+ const detail = firstNonEmptyLine(result.stderr, result.stdout);
1839
+ s.stop(detail ? `OpenClaw update failed: ${detail}` : "OpenClaw update failed.");
1840
+ throw new Error(detail ? `OpenClaw update failed.\n${detail}` : "OpenClaw update failed. Fix this before running `dench update` again.");
1841
+ }
1842
+ async function ensureMajorUpgradeAcknowledged(params) {
1843
+ if (!params.required) return;
1844
+ if (params.nonInteractive || !process$1.stdin.isTTY) {
1845
+ if (!params.yes) throw new Error(`Major Dench upgrade detected (${params.previousVersion ?? "unknown"} -> ${params.currentVersion}). Re-run with --yes to approve the required OpenClaw update.`);
1846
+ return;
1847
+ }
1848
+ if (params.yes) return;
1849
+ const decision = await confirm({
1850
+ message: stylePromptMessage(`Major Dench upgrade detected (${params.previousVersion ?? "unknown"} -> ${params.currentVersion}). Continue with mandatory OpenClaw update now?`),
1851
+ initialValue: true
1852
+ });
1853
+ if (isCancel(decision) || !decision) {
1854
+ params.runtime.log(theme.warn("Update cancelled. OpenClaw update is required for major upgrades."));
1855
+ throw new Error("Major upgrade requires OpenClaw update approval.");
1856
+ }
1857
+ }
1858
+ function resolveGatewayPort(stateDir) {
1859
+ const manifest = readManagedWebRuntimeManifest(stateDir);
1860
+ if (typeof manifest?.lastGatewayPort === "number" && Number.isFinite(manifest.lastGatewayPort) && manifest.lastGatewayPort > 0) return manifest.lastGatewayPort;
1861
+ for (const name of ["openclaw.json", "config.json"]) {
1862
+ const port = readConfigGatewayPort(path.join(stateDir, name));
1863
+ if (typeof port === "number") return port;
1864
+ }
1865
+ return 18789;
1866
+ }
1867
+ function readConfigGatewayPort(configPath) {
1868
+ try {
1869
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
1870
+ const parsedPort = typeof raw.gateway?.port === "number" ? raw.gateway.port : typeof raw.gateway?.port === "string" ? Number.parseInt(raw.gateway.port, 10) : void 0;
1871
+ if (typeof parsedPort === "number" && Number.isFinite(parsedPort) && parsedPort > 0) return parsedPort;
1872
+ return;
1873
+ } catch {
1874
+ return;
1875
+ }
1876
+ }
1877
+ async function updateWebRuntimeCommand(opts, runtime = defaultRuntime) {
1878
+ const appliedProfile = applyCliProfileEnv({ profile: opts.profile });
1879
+ const profile = appliedProfile.effectiveProfile;
1880
+ if (appliedProfile.warning && !opts.json) runtime.log(theme.warn(appliedProfile.warning));
1881
+ const stateDir = resolveProfileStateDir(profile);
1882
+ const packageRoot = resolveCliPackageRoot();
1883
+ const previousManifest = readManagedWebRuntimeManifest(stateDir);
1884
+ const transition = evaluateMajorVersionTransition({
1885
+ previousVersion: previousManifest?.deployedDenchVersion,
1886
+ currentVersion: VERSION
1887
+ });
1888
+ const nonInteractive = Boolean(opts.nonInteractive || opts.json);
1889
+ await ensureMajorUpgradeAcknowledged({
1890
+ required: transition.isMajorTransition,
1891
+ previousVersion: previousManifest?.deployedDenchVersion,
1892
+ currentVersion: VERSION,
1893
+ nonInteractive,
1894
+ yes: Boolean(opts.yes),
1895
+ runtime
1896
+ });
1897
+ if (transition.isMajorTransition) await runOpenClawUpdateWithProgress(resolveOpenClawCommandOrThrow());
1898
+ const selectedPort = parseOptionalPort(opts.webPort) ?? parseOptionalPort(previousManifest?.lastPort) ?? readLastKnownWebPort(stateDir) ?? DEFAULT_WEB_APP_PORT;
1899
+ const gatewayPort = resolveGatewayPort(stateDir);
1900
+ const stopResult = await stopManagedWebRuntime({
1901
+ stateDir,
1902
+ port: selectedPort,
1903
+ includeLegacyStandalone: true
1904
+ });
1905
+ const ensureResult = await ensureManagedWebRuntime({
1906
+ stateDir,
1907
+ packageRoot,
1908
+ denchVersion: VERSION,
1909
+ port: selectedPort,
1910
+ gatewayPort
1911
+ });
1912
+ const summary = {
1913
+ profile,
1914
+ webPort: selectedPort,
1915
+ version: VERSION,
1916
+ majorGate: {
1917
+ required: transition.isMajorTransition,
1918
+ previousVersion: previousManifest?.deployedDenchVersion,
1919
+ currentVersion: VERSION
1920
+ },
1921
+ stoppedPids: stopResult.stoppedPids,
1922
+ skippedForeignPids: stopResult.skippedForeignPids,
1923
+ ready: ensureResult.ready,
1924
+ reason: ensureResult.reason
1925
+ };
1926
+ if (!opts.json) {
1927
+ runtime.log("");
1928
+ runtime.log(theme.heading("Dench web update"));
1929
+ runtime.log(`Profile: ${profile}`);
1930
+ runtime.log(`Version: ${VERSION}`);
1931
+ runtime.log(`Web port: ${selectedPort}`);
1932
+ runtime.log(`Stopped web processes: ${summary.stoppedPids.length}`);
1933
+ if (summary.skippedForeignPids.length > 0) runtime.log(theme.warn(`Skipped non-Dench listeners on ${selectedPort}: ${summary.skippedForeignPids.join(", ")}`));
1934
+ runtime.log(`Web runtime: ${summary.ready ? "ready" : "not ready"}`);
1935
+ if (!summary.ready) runtime.log(theme.warn(summary.reason));
1936
+ }
1937
+ if (!summary.ready) throw new Error(`Web runtime update failed: ${summary.reason}`);
1938
+ if (opts.json) runtime.log(JSON.stringify(summary, null, 2));
1939
+ return summary;
1940
+ }
1941
+ async function stopWebRuntimeCommand(opts, runtime = defaultRuntime) {
1942
+ const appliedProfile = applyCliProfileEnv({ profile: opts.profile });
1943
+ const profile = appliedProfile.effectiveProfile;
1944
+ if (appliedProfile.warning && !opts.json) runtime.log(theme.warn(appliedProfile.warning));
1945
+ const stateDir = resolveProfileStateDir(profile);
1946
+ const selectedPort = parseOptionalPort(opts.webPort) ?? readLastKnownWebPort(stateDir);
1947
+ const stopResult = await stopManagedWebRuntime({
1948
+ stateDir,
1949
+ port: selectedPort,
1950
+ includeLegacyStandalone: true
1951
+ });
1952
+ const summary = {
1953
+ profile,
1954
+ webPort: selectedPort,
1955
+ stoppedPids: stopResult.stoppedPids,
1956
+ skippedForeignPids: stopResult.skippedForeignPids
1957
+ };
1958
+ if (opts.json) {
1959
+ runtime.log(JSON.stringify(summary, null, 2));
1960
+ return summary;
1961
+ }
1962
+ runtime.log("");
1963
+ runtime.log(theme.heading("Dench web stop"));
1964
+ runtime.log(`Profile: ${profile}`);
1965
+ runtime.log(`Web port: ${selectedPort}`);
1966
+ runtime.log(summary.stoppedPids.length > 0 ? `Stopped web processes: ${summary.stoppedPids.join(", ")}` : "Stopped web processes: none");
1967
+ if (summary.skippedForeignPids.length > 0) runtime.log(theme.warn(`Left non-Dench listener(s) running on ${selectedPort}: ${summary.skippedForeignPids.join(", ")}`));
1968
+ return summary;
1969
+ }
1970
+
1971
+ //#endregion
1972
+ //#region src/cli/program/register.stop.ts
1973
+ function registerStopCommand(program) {
1974
+ program.command("stop").description("Stop Dench managed web runtime on the configured port").option("--profile <name>", "Compatibility flag; non-dench values are ignored with a warning").option("--web-port <port>", "Web runtime port override").option("--json", "Output summary as JSON", false).action(async (opts) => {
1975
+ await runCommandWithRuntime(defaultRuntime, async () => {
1976
+ await stopWebRuntimeCommand({
1977
+ profile: opts.profile,
1978
+ webPort: opts.webPort,
1979
+ json: Boolean(opts.json)
1980
+ });
1981
+ });
1982
+ });
1983
+ }
1984
+
1985
+ //#endregion
1986
+ //#region src/cli/program/register.update.ts
1987
+ function registerUpdateCommand(program) {
1988
+ program.command("update").description("Update Dench managed web runtime without onboarding").option("--profile <name>", "Compatibility flag; non-dench values are ignored with a warning").option("--web-port <port>", "Web runtime port override").option("--non-interactive", "Fail instead of prompting for major-gate approval", false).option("--yes", "Approve mandatory major-gate OpenClaw update", false).option("--json", "Output summary as JSON", false).action(async (opts) => {
1989
+ await runCommandWithRuntime(defaultRuntime, async () => {
1990
+ await updateWebRuntimeCommand({
1991
+ profile: opts.profile,
1992
+ webPort: opts.webPort,
1993
+ nonInteractive: Boolean(opts.nonInteractive),
1994
+ yes: Boolean(opts.yes),
1995
+ json: Boolean(opts.json)
1996
+ });
1997
+ });
1998
+ });
1999
+ }
2000
+
2001
+ //#endregion
2002
+ //#region src/cli/program/command-registry.ts
2003
+ const CORE_CLI_ENTRIES = [
2004
+ {
2005
+ name: "bootstrap",
2006
+ description: "Bootstrap DenchClaw + OpenClaw and launch the web UI",
2007
+ register: ({ program }) => {
2008
+ registerBootstrapCommand(program);
2009
+ }
2010
+ },
2011
+ {
2012
+ name: "update",
2013
+ description: "Update Dench web runtime without onboarding",
2014
+ register: ({ program }) => {
2015
+ registerUpdateCommand(program);
2016
+ }
2017
+ },
2018
+ {
2019
+ name: "stop",
2020
+ description: "Stop Dench managed web runtime",
2021
+ register: ({ program }) => {
2022
+ registerStopCommand(program);
2023
+ }
2024
+ }
2025
+ ];
2026
+ const CORE_CLI_ENTRY_BY_NAME = new Map(CORE_CLI_ENTRIES.map((entry) => [entry.name, entry]));
2027
+ function getCoreCliCommandsWithSubcommands() {
2028
+ return [];
2029
+ }
2030
+ function registerCoreCliCommands(program, ctx, argv) {
2031
+ const primary = getPrimaryCommand(argv);
2032
+ if (primary) {
2033
+ const entry = CORE_CLI_ENTRY_BY_NAME.get(primary);
2034
+ if (!entry) return;
2035
+ entry.register({
2036
+ program,
2037
+ ctx,
2038
+ argv
2039
+ });
2040
+ return;
2041
+ }
2042
+ for (const entry of CORE_CLI_ENTRIES) entry.register({
2043
+ program,
2044
+ ctx,
2045
+ argv
2046
+ });
2047
+ }
2048
+ function registerProgramCommands(program, ctx, argv = process.argv) {
2049
+ registerCoreCliCommands(program, ctx, argv);
2050
+ }
2051
+
2052
+ //#endregion
2053
+ //#region src/cli/program/context.ts
2054
+ function createProgramContext() {
2055
+ const channelOptions = ["web"];
2056
+ return {
2057
+ programVersion: VERSION,
2058
+ channelOptions,
2059
+ messageChannelOptions: channelOptions.join("|"),
2060
+ agentChannelOptions: ["last", ...channelOptions].join("|")
2061
+ };
2062
+ }
2063
+
2064
+ //#endregion
2065
+ //#region src/cli/program/help.ts
2066
+ const CLI_NAME = resolveCliName();
2067
+ const CLI_NAME_PATTERN = escapeRegExp(CLI_NAME);
2068
+ const ROOT_COMMANDS_WITH_SUBCOMMANDS = new Set(getCoreCliCommandsWithSubcommands());
2069
+ const ROOT_COMMANDS_HINT = "Hint: commands suffixed with * have subcommands. Run <command> --help for details.";
2070
+ const EXAMPLES = [
2071
+ ["openclaw update", "Refresh the managed web runtime and enforce major upgrade gates."],
2072
+ ["openclaw stop --web-port 3100", "Stop only the managed web runtime on a specific port."],
2073
+ ["openclaw models --help", "Show detailed help for the models command."],
2074
+ ["openclaw channels login --verbose", "Link personal WhatsApp Web and show QR + connection logs."],
2075
+ ["openclaw message send --target +15555550123 --message \"Hi\" --json", "Send via your web session and print JSON result."],
2076
+ ["openclaw gateway --port 18789", "Run the WebSocket Gateway locally."],
2077
+ ["openclaw --profile team-a gateway", "Compatibility flag example: warns and still runs with --profile dench."],
2078
+ ["openclaw gateway --force", "Kill anything bound to the default gateway port, then start it."],
2079
+ ["openclaw gateway ...", "Gateway control via WebSocket."],
2080
+ ["openclaw agent --to +15555550123 --message \"Run summary\" --deliver", "Talk directly to the agent using the Gateway; optionally send the WhatsApp reply."],
2081
+ ["openclaw message send --channel telegram --target @mychat --message \"Hi\"", "Send via your Telegram bot."]
2082
+ ];
2083
+ function configureProgramHelp(program, ctx) {
2084
+ program.name(CLI_NAME).description("").version(ctx.programVersion).option("--dev", "Compatibility flag; DenchClaw always uses --profile dench and ~/.openclaw-dench").option("--profile <name>", "Compatibility flag; non-dench values are ignored with a warning");
2085
+ program.option("--no-color", "Disable ANSI colors", false);
2086
+ program.helpOption("-h, --help", "Display help for command");
2087
+ program.helpCommand("help [command]", "Display help for command");
2088
+ program.configureHelp({
2089
+ sortSubcommands: true,
2090
+ sortOptions: true,
2091
+ optionTerm: (option) => theme.option(option.flags),
2092
+ subcommandTerm: (cmd) => {
2093
+ const hasSubcommands = cmd.parent === program && ROOT_COMMANDS_WITH_SUBCOMMANDS.has(cmd.name());
2094
+ return theme.command(hasSubcommands ? `${cmd.name()} *` : cmd.name());
2095
+ }
2096
+ });
2097
+ const formatHelpOutput = (str) => {
2098
+ let output = str;
2099
+ if (new RegExp(`^Usage:\\s+${CLI_NAME_PATTERN}\\s+\\[options\\]\\s+\\[command\\]\\s*$`, "m").test(output) && /^Commands:/m.test(output)) output = output.replace(/^Commands:/m, `Commands:\n ${theme.muted(ROOT_COMMANDS_HINT)}`);
2100
+ return output.replace(/^Usage:/gm, theme.heading("Usage:")).replace(/^Options:/gm, theme.heading("Options:")).replace(/^Commands:/gm, theme.heading("Commands:"));
2101
+ };
2102
+ program.configureOutput({
2103
+ writeOut: (str) => {
2104
+ process.stdout.write(formatHelpOutput(str));
2105
+ },
2106
+ writeErr: (str) => {
2107
+ process.stderr.write(formatHelpOutput(str));
2108
+ },
2109
+ outputError: (str, write) => write(theme.error(str))
2110
+ });
2111
+ if (hasFlag(process.argv, "-V") || hasFlag(process.argv, "--version") || hasRootVersionAlias(process.argv)) {
2112
+ console.log(ctx.programVersion);
2113
+ process.exit(0);
2114
+ }
2115
+ program.addHelpText("beforeAll", () => {
2116
+ if (hasEmittedCliBanner()) return "";
2117
+ const rich = isRich();
2118
+ return `\n${formatCliBannerLine(ctx.programVersion, { richTty: rich })}\n`;
2119
+ });
2120
+ const fmtExamples = EXAMPLES.map(([cmd, desc]) => ` ${theme.command(replaceCliName(cmd, CLI_NAME))}\n ${theme.muted(desc)}`).join("\n");
2121
+ program.addHelpText("afterAll", ({ command }) => {
2122
+ if (command !== program) return "";
2123
+ const docs = formatDocsLink("/cli", "docs.openclaw.ai/cli");
2124
+ return `\n${theme.heading("Examples:")}\n${fmtExamples}\n\n${theme.muted("Docs:")} ${docs}\n`;
2125
+ });
2126
+ }
2127
+
2128
+ //#endregion
2129
+ //#region src/cli/program/preaction.ts
2130
+ function setProcessTitleForCommand(actionCommand) {
2131
+ let current = actionCommand;
2132
+ while (current.parent && current.parent.parent) current = current.parent;
2133
+ const name = current.name();
2134
+ const cliName = resolveCliName();
2135
+ if (!name || name === cliName) return;
2136
+ process.title = `${cliName}-${name}`;
2137
+ }
2138
+ function registerPreActionHooks(program, programVersion) {
2139
+ program.hook("preAction", (_thisCommand, actionCommand) => {
2140
+ setProcessTitleForCommand(actionCommand);
2141
+ });
2142
+ }
2143
+
2144
+ //#endregion
2145
+ //#region src/cli/program/program-context.ts
2146
+ const PROGRAM_CONTEXT_SYMBOL = Symbol.for("openclaw.cli.programContext");
2147
+ function setProgramContext(program, ctx) {
2148
+ program[PROGRAM_CONTEXT_SYMBOL] = ctx;
2149
+ }
2150
+
2151
+ //#endregion
2152
+ //#region src/cli/program/build-program.ts
2153
+ function buildProgram() {
2154
+ const program = new Command();
2155
+ const ctx = createProgramContext();
2156
+ const argv = process.argv;
2157
+ setProgramContext(program, ctx);
2158
+ configureProgramHelp(program, ctx);
2159
+ registerPreActionHooks(program, ctx.programVersion);
2160
+ registerProgramCommands(program, ctx, argv);
2161
+ return program;
2162
+ }
2163
+
2164
+ //#endregion
2165
+ export { buildProgram };