@ww-ai-lab/openclaw-office 2026.3.6 → 2026.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -5
- package/README.zh.md +25 -5
- package/bin/openclaw-office-config.d.ts +44 -0
- package/bin/openclaw-office-config.js +219 -0
- package/bin/openclaw-office-server.d.ts +34 -0
- package/bin/openclaw-office-server.js +342 -0
- package/bin/openclaw-office.js +16 -207
- package/dist/assets/{ActivityHeatmap-yoOrzNpC.js → ActivityHeatmap-CnKWcUWF.js} +1 -1
- package/dist/assets/{CostPieChart-7UZWefGa.js → CostPieChart-DmUzkXKt.js} +1 -1
- package/dist/assets/{NetworkGraph-DztAZ-1C.js → NetworkGraph-C0F11y9I.js} +1 -1
- package/dist/assets/{Scene3D-CQ4mdanW.js → Scene3D-q5P1N1qu.js} +1 -1
- package/dist/assets/{TokenLineChart-1c-hlIcN.js → TokenLineChart-odcmdCAg.js} +1 -1
- package/dist/assets/{generateCategoricalChart-a2LW5o0y.js → generateCategoricalChart-Onj3oDrM.js} +1 -1
- package/dist/assets/index-DweWoR1-.css +1 -0
- package/dist/assets/index-QZYyP0qG.js +462 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/assets/index-4lyIF-sI.css +0 -1
- package/dist/assets/index-Qn7uixse.js +0 -441
- package/dist/assets/ws-adapter-DI4FTsvI.js +0 -1
package/README.md
CHANGED
|
@@ -33,7 +33,19 @@
|
|
|
33
33
|
|
|
34
34
|
#### Demo Video
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
<p align="center">
|
|
37
|
+
<a href="https://www.youtube.com/watch?v=ACXSFTSlVLY">
|
|
38
|
+
<img src="https://img.youtube.com/vi/ACXSFTSlVLY/maxresdefault.jpg" alt="OpenClaw Office Demo Video" width="100%" />
|
|
39
|
+
</a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
▶ Click the preview image above to play on YouTube
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
> GitHub sanitizes repository README content and does not allow embedded YouTube/iframe players, so the most reliable “preview + click-to-play” pattern is a linked video thumbnail.
|
|
47
|
+
|
|
48
|
+
[Watch on YouTube](https://www.youtube.com/watch?v=ACXSFTSlVLY)
|
|
37
49
|
|
|
38
50
|
### Console
|
|
39
51
|
|
|
@@ -124,6 +136,15 @@ OPENCLAW_GATEWAY_TOKEN=<token> openclaw-office
|
|
|
124
136
|
| `--host <host>` | Bind address | `0.0.0.0` |
|
|
125
137
|
| `-h, --help` | Show help | — |
|
|
126
138
|
|
|
139
|
+
The production server exposes Office publicly and proxies browser WebSocket traffic through the same origin path `/gateway-ws`. Its upstream Gateway address is resolved in this order:
|
|
140
|
+
|
|
141
|
+
1. `--gateway`
|
|
142
|
+
2. `OPENCLAW_GATEWAY_URL`
|
|
143
|
+
3. persisted Office config at `~/.openclaw/openclaw-office.json`
|
|
144
|
+
4. default `ws://localhost:18789`
|
|
145
|
+
|
|
146
|
+
When `--gateway` or `OPENCLAW_GATEWAY_URL` is provided, Office automatically persists the value to `~/.openclaw/openclaw-office.json` for future restarts.
|
|
147
|
+
|
|
127
148
|
> **Note:** This serves the pre-built production bundle. For development with hot reload, see [Development](#development) below.
|
|
128
149
|
|
|
129
150
|
---
|
|
@@ -138,11 +159,10 @@ pnpm install
|
|
|
138
159
|
|
|
139
160
|
### 2. Configure Gateway Connection
|
|
140
161
|
|
|
141
|
-
Create a `.env.local` file (gitignored) with your Gateway
|
|
162
|
+
Create a `.env.local` file (gitignored) with your Gateway token. `VITE_GATEWAY_URL` is optional and only needed if you want dev mode to proxy to a Gateway address other than the default `ws://localhost:18789`.
|
|
142
163
|
|
|
143
164
|
```bash
|
|
144
165
|
cat > .env.local << 'EOF'
|
|
145
|
-
VITE_GATEWAY_URL=ws://localhost:18789
|
|
146
166
|
VITE_GATEWAY_TOKEN=<your-gateway-token>
|
|
147
167
|
EOF
|
|
148
168
|
```
|
|
@@ -179,13 +199,13 @@ Ensure the OpenClaw Gateway is running on the configured address (default `local
|
|
|
179
199
|
pnpm dev
|
|
180
200
|
```
|
|
181
201
|
|
|
182
|
-
Open `http://localhost:5180` in your browser.
|
|
202
|
+
Open `http://localhost:5180` in your browser. In dev mode, the frontend always connects to the same-origin path `/gateway-ws`, and Vite proxies that path to the configured Gateway upstream (default `ws://localhost:18789`). `VITE_GATEWAY_URL` configures the proxy upstream and is not used as a browser-direct websocket URL.
|
|
183
203
|
|
|
184
204
|
### Environment Variables
|
|
185
205
|
|
|
186
206
|
| Variable | Required | Default | Description |
|
|
187
207
|
| -------------------- | ------------------------------------- | ---------------------- | ------------------------------------ |
|
|
188
|
-
| `VITE_GATEWAY_URL` | No | `ws://localhost:18789` | Gateway
|
|
208
|
+
| `VITE_GATEWAY_URL` | No | `ws://localhost:18789` | Optional override for the dev proxy upstream Gateway address |
|
|
189
209
|
| `VITE_GATEWAY_TOKEN` | Yes (when connecting to real Gateway) | — | Gateway auth token |
|
|
190
210
|
| `VITE_MOCK` | No | `false` | Enable mock mode (no Gateway needed) |
|
|
191
211
|
|
package/README.zh.md
CHANGED
|
@@ -33,7 +33,19 @@
|
|
|
33
33
|
|
|
34
34
|
#### 演示视频
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
<p align="center">
|
|
37
|
+
<a href="https://www.youtube.com/watch?v=ACXSFTSlVLY">
|
|
38
|
+
<img src="https://img.youtube.com/vi/ACXSFTSlVLY/maxresdefault.jpg" alt="OpenClaw Office 演示视频" width="100%" />
|
|
39
|
+
</a>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
▶ 点击上方预览图即可跳转播放
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
> GitHub 会清洗仓库 README 内容,不允许真正内嵌 YouTube / iframe 播放器,所以最稳妥的实现方式就是“预览图 + 点击播放跳转”。
|
|
47
|
+
|
|
48
|
+
[在 YouTube 观看](https://www.youtube.com/watch?v=ACXSFTSlVLY)
|
|
37
49
|
|
|
38
50
|
### 控制台
|
|
39
51
|
|
|
@@ -124,6 +136,15 @@ OPENCLAW_GATEWAY_TOKEN=<token> openclaw-office
|
|
|
124
136
|
| `--host <host>` | 绑定地址 | `0.0.0.0` |
|
|
125
137
|
| `-h, --help` | 显示帮助 | — |
|
|
126
138
|
|
|
139
|
+
生产服务端会对外暴露 Office,并通过同源路径 `/gateway-ws` 代理浏览器的 WebSocket 流量。其上游 Gateway 地址按以下优先级解析:
|
|
140
|
+
|
|
141
|
+
1. `--gateway`
|
|
142
|
+
2. `OPENCLAW_GATEWAY_URL`
|
|
143
|
+
3. Office 持久化配置 `~/.openclaw/openclaw-office.json`
|
|
144
|
+
4. 默认值 `ws://localhost:18789`
|
|
145
|
+
|
|
146
|
+
当提供 `--gateway` 或 `OPENCLAW_GATEWAY_URL` 时,Office 会自动将该值持久化到 `~/.openclaw/openclaw-office.json`,供后续重启复用。
|
|
147
|
+
|
|
127
148
|
> **说明:** 此方式运行的是预构建的生产版本。如需热重载开发,请参见下方 [开发](#开发) 部分。
|
|
128
149
|
|
|
129
150
|
---
|
|
@@ -138,11 +159,10 @@ pnpm install
|
|
|
138
159
|
|
|
139
160
|
### 2. 配置 Gateway 连接
|
|
140
161
|
|
|
141
|
-
创建 `.env.local` 文件(已在 `.gitignore` 中,不会被提交),填入 Gateway
|
|
162
|
+
创建 `.env.local` 文件(已在 `.gitignore` 中,不会被提交),填入 Gateway token。`VITE_GATEWAY_URL` 是可选项,仅在你希望 dev 模式代理到非默认 `ws://localhost:18789` 地址时才需要填写:
|
|
142
163
|
|
|
143
164
|
```bash
|
|
144
165
|
cat > .env.local << 'EOF'
|
|
145
|
-
VITE_GATEWAY_URL=ws://localhost:18789
|
|
146
166
|
VITE_GATEWAY_TOKEN=<你的 gateway token>
|
|
147
167
|
EOF
|
|
148
168
|
```
|
|
@@ -179,13 +199,13 @@ openclaw config set gateway.controlUi.dangerouslyDisableDeviceAuth true
|
|
|
179
199
|
pnpm dev
|
|
180
200
|
```
|
|
181
201
|
|
|
182
|
-
在浏览器中打开 `http://localhost:5180
|
|
202
|
+
在浏览器中打开 `http://localhost:5180`。在 dev 模式下,前端始终连接同源路径 `/gateway-ws`,再由 Vite 将该路径代理到配置的 Gateway 上游地址(默认 `ws://localhost:18789`)。`VITE_GATEWAY_URL` 仅用于配置代理上游,不会作为浏览器直连 WebSocket 地址使用。
|
|
183
203
|
|
|
184
204
|
### 环境变量
|
|
185
205
|
|
|
186
206
|
| 变量 | 必须 | 默认值 | 说明 |
|
|
187
207
|
| -------------------- | ------------------------- | ---------------------- | -------------------------------- |
|
|
188
|
-
| `VITE_GATEWAY_URL` | 否 | `ws://localhost:18789` | Gateway
|
|
208
|
+
| `VITE_GATEWAY_URL` | 否 | `ws://localhost:18789` | 可选:覆盖 dev 代理的上游 Gateway 地址 |
|
|
189
209
|
| `VITE_GATEWAY_TOKEN` | 是(连接真实 Gateway 时) | — | Gateway 认证 token |
|
|
190
210
|
| `VITE_MOCK` | 否 | `false` | 启用 Mock 模式(不需要 Gateway) |
|
|
191
211
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const DEFAULT_GATEWAY_URL: string;
|
|
2
|
+
export const DEFAULT_PORT: number;
|
|
3
|
+
export const DEFAULT_HOST: string;
|
|
4
|
+
export const DEFAULT_PROXY_PATH: string;
|
|
5
|
+
|
|
6
|
+
export interface ParsedArgs {
|
|
7
|
+
token: string;
|
|
8
|
+
gatewayUrl: string;
|
|
9
|
+
port: number;
|
|
10
|
+
host: string;
|
|
11
|
+
help?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ResolvedConfig {
|
|
15
|
+
token: string;
|
|
16
|
+
tokenSource: string;
|
|
17
|
+
gatewayUrl: string;
|
|
18
|
+
gatewayUrlSource: string;
|
|
19
|
+
port: number;
|
|
20
|
+
host: string;
|
|
21
|
+
officeConfigPath: string;
|
|
22
|
+
browserGatewayUrl: string;
|
|
23
|
+
shouldPersistGatewayUrl: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getOfficeConfigPath(homeDir?: string): string;
|
|
27
|
+
export function parseArgs(argv?: string[]): ParsedArgs;
|
|
28
|
+
export function printHelp(): void;
|
|
29
|
+
export function readTokenFromConfig(
|
|
30
|
+
homeDir?: string,
|
|
31
|
+
): { token: string; source: string } | null;
|
|
32
|
+
export function readPersistedOfficeConfig(
|
|
33
|
+
configPath?: string,
|
|
34
|
+
): { gatewayUrl: string } | null;
|
|
35
|
+
export function writePersistedOfficeConfig(gatewayUrl: string, configPath?: string): void;
|
|
36
|
+
export function normalizeGatewayAccessUrl(rawGatewayUrl: string): {
|
|
37
|
+
gatewayUrl: string;
|
|
38
|
+
token: string;
|
|
39
|
+
};
|
|
40
|
+
export function resolveConfig(options?: {
|
|
41
|
+
argv?: string[];
|
|
42
|
+
env?: NodeJS.ProcessEnv | Record<string, string>;
|
|
43
|
+
homeDir?: string;
|
|
44
|
+
}): ResolvedConfig;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_GATEWAY_URL = "ws://localhost:18789";
|
|
6
|
+
export const DEFAULT_PORT = 5180;
|
|
7
|
+
export const DEFAULT_HOST = "0.0.0.0";
|
|
8
|
+
export const DEFAULT_PROXY_PATH = "/gateway-ws";
|
|
9
|
+
const TOKEN_QUERY_PARAM = "token";
|
|
10
|
+
|
|
11
|
+
export function getOfficeConfigPath(homeDir = homedir()) {
|
|
12
|
+
return join(homeDir, ".openclaw", "openclaw-office.json");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function parseArgs(argv = process.argv.slice(2)) {
|
|
16
|
+
const result = { token: "", gatewayUrl: "", port: 0, host: "" };
|
|
17
|
+
for (let i = 0; i < argv.length; i++) {
|
|
18
|
+
const arg = argv[i];
|
|
19
|
+
const next = argv[i + 1];
|
|
20
|
+
if ((arg === "--token" || arg === "-t") && next) {
|
|
21
|
+
result.token = next;
|
|
22
|
+
i++;
|
|
23
|
+
} else if ((arg === "--gateway" || arg === "-g") && next) {
|
|
24
|
+
result.gatewayUrl = next;
|
|
25
|
+
i++;
|
|
26
|
+
} else if ((arg === "--port" || arg === "-p") && next) {
|
|
27
|
+
result.port = parseInt(next, 10);
|
|
28
|
+
i++;
|
|
29
|
+
} else if (arg === "--host" && next) {
|
|
30
|
+
result.host = next;
|
|
31
|
+
i++;
|
|
32
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
33
|
+
result.help = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function printHelp() {
|
|
40
|
+
console.log(`
|
|
41
|
+
\x1b[36mOpenClaw Office\x1b[0m — Visual monitoring frontend for OpenClaw
|
|
42
|
+
|
|
43
|
+
\x1b[1mUsage:\x1b[0m
|
|
44
|
+
openclaw-office [options]
|
|
45
|
+
|
|
46
|
+
\x1b[1mOptions:\x1b[0m
|
|
47
|
+
-t, --token <token> Gateway auth token
|
|
48
|
+
-g, --gateway <url> Gateway WebSocket URL (default: ws://localhost:18789)
|
|
49
|
+
-p, --port <port> Server port (default: 5180, or PORT env)
|
|
50
|
+
--host <host> Bind address (default: 0.0.0.0)
|
|
51
|
+
-h, --help Show this help
|
|
52
|
+
|
|
53
|
+
\x1b[1mGateway URL persistence:\x1b[0m
|
|
54
|
+
The upstream Gateway URL is resolved in this order:
|
|
55
|
+
1. --gateway flag
|
|
56
|
+
2. OPENCLAW_GATEWAY_URL environment variable
|
|
57
|
+
3. Persisted Office config at ~/.openclaw/openclaw-office.json
|
|
58
|
+
4. Default ws://localhost:18789
|
|
59
|
+
|
|
60
|
+
\x1b[1mToken auto-detection:\x1b[0m
|
|
61
|
+
The token is resolved in this order:
|
|
62
|
+
1. --token flag
|
|
63
|
+
2. OPENCLAW_GATEWAY_TOKEN environment variable
|
|
64
|
+
3. Auto-read from ~/.openclaw/openclaw.json
|
|
65
|
+
|
|
66
|
+
\x1b[1mExamples:\x1b[0m
|
|
67
|
+
openclaw-office
|
|
68
|
+
openclaw-office --token my-secret-token
|
|
69
|
+
openclaw-office --gateway ws://192.168.1.100:18789
|
|
70
|
+
PORT=3000 openclaw-office
|
|
71
|
+
`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function readTokenFromConfig(homeDir = homedir()) {
|
|
75
|
+
const candidates = [
|
|
76
|
+
join(homeDir, ".openclaw", "openclaw.json"),
|
|
77
|
+
join(homeDir, ".clawdbot", "clawdbot.json"),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
for (const filePath of candidates) {
|
|
81
|
+
try {
|
|
82
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
83
|
+
const config = JSON.parse(raw);
|
|
84
|
+
const token = config?.gateway?.auth?.token;
|
|
85
|
+
if (token && typeof token === "string") {
|
|
86
|
+
return { token, source: filePath };
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
// file not found or parse error
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function readPersistedOfficeConfig(configPath = getOfficeConfigPath()) {
|
|
97
|
+
if (!existsSync(configPath)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
103
|
+
const parsed = JSON.parse(raw);
|
|
104
|
+
const gatewayUrl = parsed?.gatewayUrl;
|
|
105
|
+
if (typeof gatewayUrl !== "string" || gatewayUrl.length === 0) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return { gatewayUrl };
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function writePersistedOfficeConfig(
|
|
115
|
+
gatewayUrl,
|
|
116
|
+
configPath = getOfficeConfigPath(),
|
|
117
|
+
) {
|
|
118
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
119
|
+
writeFileSync(configPath, `${JSON.stringify({ gatewayUrl }, null, 2)}\n`, "utf-8");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function formatParsedUrl(parsed, original) {
|
|
123
|
+
const serialized = parsed.toString();
|
|
124
|
+
if (/^[a-z]+:\/\/[^/?#]+(?:\?[^#]*)?(?:#.*)?$/i.test(original)) {
|
|
125
|
+
return serialized.replace(/\/$/, "");
|
|
126
|
+
}
|
|
127
|
+
return serialized;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function normalizeGatewayAccessUrl(rawGatewayUrl) {
|
|
131
|
+
if (!rawGatewayUrl) {
|
|
132
|
+
return { gatewayUrl: rawGatewayUrl, token: "" };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const parsed = new URL(rawGatewayUrl);
|
|
137
|
+
const token = parsed.searchParams.get(TOKEN_QUERY_PARAM) ?? "";
|
|
138
|
+
parsed.searchParams.delete(TOKEN_QUERY_PARAM);
|
|
139
|
+
|
|
140
|
+
if (parsed.protocol === "http:") {
|
|
141
|
+
parsed.protocol = "ws:";
|
|
142
|
+
} else if (parsed.protocol === "https:") {
|
|
143
|
+
parsed.protocol = "wss:";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return { gatewayUrl: formatParsedUrl(parsed, rawGatewayUrl), token };
|
|
147
|
+
} catch {
|
|
148
|
+
return { gatewayUrl: rawGatewayUrl, token: "" };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function resolveConfig({
|
|
153
|
+
argv = process.argv.slice(2),
|
|
154
|
+
env = process.env,
|
|
155
|
+
homeDir = homedir(),
|
|
156
|
+
} = {}) {
|
|
157
|
+
const args = parseArgs(argv);
|
|
158
|
+
const officeConfigPath = getOfficeConfigPath(homeDir);
|
|
159
|
+
const persisted = readPersistedOfficeConfig(officeConfigPath);
|
|
160
|
+
|
|
161
|
+
let token = "";
|
|
162
|
+
let tokenSource = "";
|
|
163
|
+
|
|
164
|
+
if (args.token) {
|
|
165
|
+
token = args.token;
|
|
166
|
+
tokenSource = "command line --token";
|
|
167
|
+
} else if (env.OPENCLAW_GATEWAY_TOKEN) {
|
|
168
|
+
token = env.OPENCLAW_GATEWAY_TOKEN;
|
|
169
|
+
tokenSource = "OPENCLAW_GATEWAY_TOKEN env";
|
|
170
|
+
} else {
|
|
171
|
+
const fromFile = readTokenFromConfig(homeDir);
|
|
172
|
+
if (fromFile) {
|
|
173
|
+
token = fromFile.token;
|
|
174
|
+
tokenSource = fromFile.source;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let gatewayUrl = DEFAULT_GATEWAY_URL;
|
|
179
|
+
let gatewayUrlSource = "default";
|
|
180
|
+
if (persisted?.gatewayUrl) {
|
|
181
|
+
gatewayUrl = persisted.gatewayUrl;
|
|
182
|
+
gatewayUrlSource = officeConfigPath;
|
|
183
|
+
}
|
|
184
|
+
if (env.OPENCLAW_GATEWAY_URL) {
|
|
185
|
+
gatewayUrl = env.OPENCLAW_GATEWAY_URL;
|
|
186
|
+
gatewayUrlSource = "OPENCLAW_GATEWAY_URL env";
|
|
187
|
+
}
|
|
188
|
+
if (args.gatewayUrl) {
|
|
189
|
+
gatewayUrl = args.gatewayUrl;
|
|
190
|
+
gatewayUrlSource = "command line --gateway";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const normalizedGateway = normalizeGatewayAccessUrl(gatewayUrl);
|
|
194
|
+
gatewayUrl = normalizedGateway.gatewayUrl || gatewayUrl;
|
|
195
|
+
|
|
196
|
+
if (!token && normalizedGateway.token) {
|
|
197
|
+
token = normalizedGateway.token;
|
|
198
|
+
tokenSource = `${gatewayUrlSource} token query`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const port = args.port || parseInt(env.PORT || `${DEFAULT_PORT}`, 10);
|
|
202
|
+
const host = args.host || env.HOST || DEFAULT_HOST;
|
|
203
|
+
const shouldPersistGatewayUrl =
|
|
204
|
+
!!gatewayUrl &&
|
|
205
|
+
(gatewayUrlSource === "command line --gateway" || gatewayUrlSource === "OPENCLAW_GATEWAY_URL env") &&
|
|
206
|
+
gatewayUrl !== persisted?.gatewayUrl;
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
token,
|
|
210
|
+
tokenSource,
|
|
211
|
+
gatewayUrl,
|
|
212
|
+
gatewayUrlSource,
|
|
213
|
+
port,
|
|
214
|
+
host,
|
|
215
|
+
officeConfigPath,
|
|
216
|
+
browserGatewayUrl: DEFAULT_PROXY_PATH,
|
|
217
|
+
shouldPersistGatewayUrl,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Server as HttpServer, IncomingMessage } from "node:http";
|
|
2
|
+
import type { Duplex } from "node:stream";
|
|
3
|
+
|
|
4
|
+
export const MIME_TYPES: Record<string, string>;
|
|
5
|
+
|
|
6
|
+
export interface OfficeServerConfig {
|
|
7
|
+
gatewayUrl: string;
|
|
8
|
+
browserGatewayUrl: string;
|
|
9
|
+
token: string;
|
|
10
|
+
port?: number;
|
|
11
|
+
host?: string;
|
|
12
|
+
gatewayUrlSource?: string;
|
|
13
|
+
tokenSource?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createRuntimeConfigScript(config: {
|
|
17
|
+
browserGatewayUrl: string;
|
|
18
|
+
token: string;
|
|
19
|
+
}): string;
|
|
20
|
+
export function formatStartupSummary(config: OfficeServerConfig): string;
|
|
21
|
+
export function proxyWebSocketUpgrade(
|
|
22
|
+
req: IncomingMessage,
|
|
23
|
+
downstreamSocket: Duplex,
|
|
24
|
+
downstreamHead: Buffer,
|
|
25
|
+
config: OfficeServerConfig,
|
|
26
|
+
): void;
|
|
27
|
+
export function createOfficeServer(options: {
|
|
28
|
+
config: OfficeServerConfig;
|
|
29
|
+
distDir: string;
|
|
30
|
+
createHttpServer?: typeof import("node:http").createServer;
|
|
31
|
+
}): {
|
|
32
|
+
server: HttpServer;
|
|
33
|
+
getIndexHtml: () => Promise<string>;
|
|
34
|
+
};
|