@chrysb/alphaclaw 0.7.0 → 0.7.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 (31) hide show
  1. package/lib/public/css/cron.css +26 -17
  2. package/lib/public/css/theme.css +14 -0
  3. package/lib/public/js/components/cron-tab/cron-calendar.js +17 -12
  4. package/lib/public/js/components/cron-tab/cron-job-list.js +11 -1
  5. package/lib/public/js/components/cron-tab/index.js +16 -2
  6. package/lib/public/js/components/icons.js +11 -0
  7. package/lib/public/js/components/routes/watchdog-route.js +1 -1
  8. package/lib/public/js/components/watchdog-tab/console/index.js +115 -0
  9. package/lib/public/js/components/watchdog-tab/console/use-console.js +137 -0
  10. package/lib/public/js/components/watchdog-tab/helpers.js +106 -0
  11. package/lib/public/js/components/watchdog-tab/incidents/index.js +56 -0
  12. package/lib/public/js/components/watchdog-tab/incidents/use-incidents.js +33 -0
  13. package/lib/public/js/components/watchdog-tab/index.js +84 -0
  14. package/lib/public/js/components/watchdog-tab/resource-bar.js +76 -0
  15. package/lib/public/js/components/watchdog-tab/resources/index.js +85 -0
  16. package/lib/public/js/components/watchdog-tab/resources/use-resources.js +13 -0
  17. package/lib/public/js/components/watchdog-tab/settings/index.js +44 -0
  18. package/lib/public/js/components/watchdog-tab/settings/use-settings.js +117 -0
  19. package/lib/public/js/components/watchdog-tab/terminal/index.js +20 -0
  20. package/lib/public/js/components/watchdog-tab/terminal/use-terminal.js +263 -0
  21. package/lib/public/js/components/watchdog-tab/use-watchdog-tab.js +55 -0
  22. package/lib/public/js/lib/api.js +39 -0
  23. package/lib/server/init/register-server-routes.js +239 -0
  24. package/lib/server/init/runtime-init.js +44 -0
  25. package/lib/server/init/server-lifecycle.js +55 -0
  26. package/lib/server/routes/watchdog.js +62 -0
  27. package/lib/server/watchdog-terminal-ws.js +114 -0
  28. package/lib/server/watchdog-terminal.js +262 -0
  29. package/lib/server.js +89 -215
  30. package/package.json +3 -2
  31. package/lib/public/js/components/watchdog-tab.js +0 -535
@@ -0,0 +1,263 @@
1
+ import { useEffect, useRef, useState } from "https://esm.sh/preact/hooks";
2
+ import { closeWatchdogTerminalSession } from "../../../lib/api.js";
3
+ import { showToast } from "../../toast.js";
4
+ import {
5
+ ensureXtermStylesheet,
6
+ fitTerminalWhenVisible,
7
+ kWatchdogTerminalWsPath,
8
+ loadXtermModules,
9
+ } from "../helpers.js";
10
+
11
+ export const useWatchdogTerminal = ({
12
+ active = false,
13
+ panelRef = null,
14
+ hostRef = null,
15
+ } = {}) => {
16
+ const [connectingTerminal, setConnectingTerminal] = useState(false);
17
+ const [terminalConnected, setTerminalConnected] = useState(false);
18
+ const [terminalEnded, setTerminalEnded] = useState(false);
19
+ const [terminalStatusText, setTerminalStatusText] = useState("");
20
+ const [terminalUiSettling, setTerminalUiSettling] = useState(false);
21
+ const [terminalSessionId, setTerminalSessionId] = useState("");
22
+ const [terminalReconnectToken, setTerminalReconnectToken] = useState(0);
23
+ const terminalInstanceRef = useRef(null);
24
+ const terminalFitAddonRef = useRef(null);
25
+ const terminalSocketRef = useRef(null);
26
+ const terminalSessionIdRef = useRef("");
27
+
28
+ useEffect(() => {
29
+ terminalSessionIdRef.current = String(terminalSessionId || "");
30
+ }, [terminalSessionId]);
31
+
32
+ useEffect(() => {
33
+ if (!active) return;
34
+ let cancelled = false;
35
+ let resizeTimer = null;
36
+ const setupTerminal = async () => {
37
+ try {
38
+ setConnectingTerminal(true);
39
+ ensureXtermStylesheet();
40
+ const [{ Terminal }, { FitAddon }] = await loadXtermModules();
41
+ if (cancelled) return;
42
+ if (!terminalInstanceRef.current && hostRef?.current) {
43
+ const terminal = new Terminal({
44
+ cursorBlink: true,
45
+ fontFamily:
46
+ "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, monospace",
47
+ fontSize: 12,
48
+ lineHeight: 1.2,
49
+ letterSpacing: 0,
50
+ convertEol: false,
51
+ theme: {
52
+ background: "rgba(0, 0, 0, 0)",
53
+ foreground: "#d1d5db",
54
+ cursor: "#67e8f9",
55
+ },
56
+ });
57
+ const fitAddon = new FitAddon();
58
+ terminal.loadAddon(fitAddon);
59
+ terminal.open(hostRef.current);
60
+ fitAddon.fit();
61
+ terminal.attachCustomKeyEventHandler((event) => {
62
+ if (event.type !== "keydown") return true;
63
+ const pressedKey = String(event.key || "").toLowerCase();
64
+ if (
65
+ !event.metaKey ||
66
+ event.ctrlKey ||
67
+ event.altKey ||
68
+ event.shiftKey
69
+ ) {
70
+ return true;
71
+ }
72
+ if (pressedKey !== "k") return true;
73
+ event.preventDefault();
74
+ terminal.clear();
75
+ return false;
76
+ });
77
+ window.setTimeout(() => {
78
+ terminalFitAddonRef.current?.fit();
79
+ }, 120);
80
+ terminal.focus();
81
+ terminal.onData((data) => {
82
+ const socket = terminalSocketRef.current;
83
+ if (!socket || socket.readyState !== 1) return;
84
+ socket.send(
85
+ JSON.stringify({
86
+ type: "input",
87
+ data,
88
+ }),
89
+ );
90
+ });
91
+ terminalInstanceRef.current = terminal;
92
+ terminalFitAddonRef.current = fitAddon;
93
+ }
94
+
95
+ const existingSocket = terminalSocketRef.current;
96
+ if (existingSocket && existingSocket.readyState <= 1) {
97
+ setConnectingTerminal(false);
98
+ setTerminalUiSettling(false);
99
+ fitTerminalWhenVisible({
100
+ panel: panelRef?.current,
101
+ fitAddon: terminalFitAddonRef.current,
102
+ });
103
+ terminalInstanceRef.current?.focus();
104
+ return;
105
+ }
106
+
107
+ const protocol = window.location.protocol === "https:" ? "wss" : "ws";
108
+ const socket = new WebSocket(
109
+ `${protocol}://${window.location.host}${kWatchdogTerminalWsPath}`,
110
+ );
111
+ terminalSocketRef.current = socket;
112
+ socket.onopen = () => {
113
+ if (cancelled) return;
114
+ setConnectingTerminal(false);
115
+ setTerminalUiSettling(false);
116
+ setTerminalConnected(true);
117
+ setTerminalEnded(false);
118
+ setTerminalStatusText("Connected");
119
+ fitTerminalWhenVisible({
120
+ panel: panelRef?.current,
121
+ fitAddon: terminalFitAddonRef.current,
122
+ });
123
+ terminalInstanceRef.current?.focus();
124
+ };
125
+ socket.onmessage = (event) => {
126
+ let payload = null;
127
+ try {
128
+ payload = JSON.parse(String(event.data || ""));
129
+ } catch {
130
+ return;
131
+ }
132
+ const type = String(payload?.type || "");
133
+ if (type === "session") {
134
+ const sessionId = String(payload?.session?.id || "");
135
+ if (sessionId) setTerminalSessionId(sessionId);
136
+ setTerminalStatusText("Connected");
137
+ return;
138
+ }
139
+ if (type === "output") {
140
+ terminalInstanceRef.current?.write(String(payload?.data || ""));
141
+ return;
142
+ }
143
+ if (type === "exit") {
144
+ setTerminalEnded(true);
145
+ setTerminalConnected(false);
146
+ setTerminalStatusText("Session ended");
147
+ }
148
+ };
149
+ socket.onclose = () => {
150
+ if (cancelled) return;
151
+ setConnectingTerminal(false);
152
+ setTerminalUiSettling(false);
153
+ setTerminalConnected(false);
154
+ if (!terminalEnded) setTerminalStatusText("Disconnected");
155
+ };
156
+ socket.onerror = () => {
157
+ if (cancelled) return;
158
+ setConnectingTerminal(false);
159
+ setTerminalUiSettling(false);
160
+ setTerminalConnected(false);
161
+ setTerminalStatusText("Connection error");
162
+ showToast("Watchdog terminal connection failed", "error");
163
+ };
164
+ } catch {
165
+ if (cancelled) return;
166
+ setConnectingTerminal(false);
167
+ setTerminalUiSettling(false);
168
+ setTerminalConnected(false);
169
+ setTerminalStatusText("Terminal failed to load");
170
+ showToast("Could not initialize terminal", "error");
171
+ }
172
+ };
173
+ setupTerminal();
174
+
175
+ const onResize = () => {
176
+ if (resizeTimer) window.clearTimeout(resizeTimer);
177
+ resizeTimer = window.setTimeout(() => {
178
+ fitTerminalWhenVisible({
179
+ panel: panelRef?.current,
180
+ fitAddon: terminalFitAddonRef.current,
181
+ });
182
+ }, 60);
183
+ };
184
+ window.addEventListener("resize", onResize);
185
+ return () => {
186
+ cancelled = true;
187
+ if (resizeTimer) window.clearTimeout(resizeTimer);
188
+ window.removeEventListener("resize", onResize);
189
+ };
190
+ }, [active, terminalEnded, terminalReconnectToken, panelRef, hostRef]);
191
+
192
+ useEffect(
193
+ () => () => {
194
+ const activeSessionId = String(terminalSessionIdRef.current || "");
195
+ if (activeSessionId) {
196
+ closeWatchdogTerminalSession(activeSessionId).catch(() => {});
197
+ }
198
+ const socket = terminalSocketRef.current;
199
+ if (socket && socket.readyState <= 1) socket.close();
200
+ terminalSocketRef.current = null;
201
+ terminalFitAddonRef.current = null;
202
+ if (terminalInstanceRef.current) {
203
+ terminalInstanceRef.current.dispose();
204
+ }
205
+ terminalInstanceRef.current = null;
206
+ },
207
+ [],
208
+ );
209
+
210
+ const prepareForActivate = () => {
211
+ const hasOpenSocket =
212
+ !!terminalSocketRef.current && terminalSocketRef.current.readyState <= 1;
213
+ if (hasOpenSocket && terminalConnected) {
214
+ setTerminalUiSettling(false);
215
+ setConnectingTerminal(false);
216
+ return;
217
+ }
218
+ setTerminalUiSettling(true);
219
+ setConnectingTerminal(true);
220
+ };
221
+
222
+ const clearSettling = () => {
223
+ setTerminalUiSettling(false);
224
+ };
225
+
226
+ const restartSession = () => {
227
+ const activeSessionId = String(terminalSessionId || "");
228
+ if (activeSessionId) {
229
+ closeWatchdogTerminalSession(activeSessionId).catch(() => {});
230
+ }
231
+ const socket = terminalSocketRef.current;
232
+ if (socket && socket.readyState <= 1) socket.close();
233
+ terminalSocketRef.current = null;
234
+ terminalInstanceRef.current?.clear();
235
+ setConnectingTerminal(true);
236
+ setTerminalUiSettling(true);
237
+ setTerminalEnded(false);
238
+ setTerminalConnected(false);
239
+ setTerminalSessionId("");
240
+ setTerminalStatusText("Connecting...");
241
+ setTerminalReconnectToken((value) => value + 1);
242
+ };
243
+
244
+ const fitNow = () => {
245
+ fitTerminalWhenVisible({
246
+ panel: panelRef?.current,
247
+ fitAddon: terminalFitAddonRef.current,
248
+ });
249
+ };
250
+
251
+ return {
252
+ connectingTerminal,
253
+ terminalConnected,
254
+ terminalEnded,
255
+ terminalStatusText,
256
+ terminalUiSettling,
257
+ terminalInstanceRef,
258
+ fitNow,
259
+ prepareForActivate,
260
+ clearSettling,
261
+ restartSession,
262
+ };
263
+ };
@@ -0,0 +1,55 @@
1
+ import { useWatchdogConsole } from "./console/use-console.js";
2
+ import { useWatchdogIncidents } from "./incidents/use-incidents.js";
3
+ import { useWatchdogResources } from "./resources/use-resources.js";
4
+ import { useWatchdogSettings } from "./settings/use-settings.js";
5
+
6
+ export const useWatchdogTab = ({
7
+ watchdogStatus = null,
8
+ onRefreshStatuses = () => {},
9
+ restartSignal = 0,
10
+ } = {}) => {
11
+ const currentWatchdogStatus = watchdogStatus || {};
12
+ const incidents = useWatchdogIncidents({
13
+ restartSignal,
14
+ onRefreshStatuses,
15
+ });
16
+ const resources = useWatchdogResources();
17
+ const settings = useWatchdogSettings({
18
+ watchdogStatus: currentWatchdogStatus,
19
+ onRefreshStatuses,
20
+ onRefreshIncidents: incidents.refreshEvents,
21
+ });
22
+ const consoleState = useWatchdogConsole();
23
+
24
+ return {
25
+ currentWatchdogStatus,
26
+ events: incidents.events,
27
+ refreshEvents: incidents.refreshEvents,
28
+ resources: resources.resources,
29
+ memoryExpanded: resources.memoryExpanded,
30
+ setMemoryExpanded: resources.setMemoryExpanded,
31
+ settings: settings.settings,
32
+ savingSettings: settings.savingSettings,
33
+ onToggleAutoRepair: settings.onToggleAutoRepair,
34
+ onToggleNotifications: settings.onToggleNotifications,
35
+ onRepair: settings.onRepair,
36
+ isRepairInProgress: settings.isRepairInProgress,
37
+ logs: consoleState.logs,
38
+ loadingLogs: consoleState.loadingLogs,
39
+ stickToBottom: consoleState.stickToBottom,
40
+ setStickToBottom: consoleState.setStickToBottom,
41
+ activeConsoleTab: consoleState.activeConsoleTab,
42
+ handleSelectConsoleTab: consoleState.handleSelectConsoleTab,
43
+ connectingTerminal: consoleState.connectingTerminal,
44
+ terminalConnected: consoleState.terminalConnected,
45
+ terminalEnded: consoleState.terminalEnded,
46
+ terminalStatusText: consoleState.terminalStatusText,
47
+ terminalUiSettling: consoleState.terminalUiSettling,
48
+ onRestartTerminalSession: consoleState.onRestartTerminalSession,
49
+ logsPanelHeightPx: consoleState.logsPanelHeightPx,
50
+ logsRef: consoleState.logsRef,
51
+ terminalPanelRef: consoleState.terminalPanelRef,
52
+ terminalHostRef: consoleState.terminalHostRef,
53
+ terminalInstanceRef: consoleState.terminalInstanceRef,
54
+ };
55
+ };
@@ -365,6 +365,45 @@ export async function fetchWatchdogLogs(tail = 65536) {
365
365
  return res.text();
366
366
  }
367
367
 
368
+ export async function createWatchdogTerminalSession() {
369
+ const res = await authFetch("/api/watchdog/terminal/session", {
370
+ method: "POST",
371
+ });
372
+ return parseJsonOrThrow(res, "Could not start watchdog terminal");
373
+ }
374
+
375
+ export async function fetchWatchdogTerminalOutput(sessionId, cursor = 0) {
376
+ const params = new URLSearchParams({
377
+ sessionId: String(sessionId || ""),
378
+ cursor: String(cursor || 0),
379
+ });
380
+ const res = await authFetch(`/api/watchdog/terminal/output?${params.toString()}`);
381
+ return parseJsonOrThrow(res, "Could not read watchdog terminal output");
382
+ }
383
+
384
+ export async function sendWatchdogTerminalInput(sessionId, input = "") {
385
+ const res = await authFetch("/api/watchdog/terminal/input", {
386
+ method: "POST",
387
+ headers: { "Content-Type": "application/json" },
388
+ body: JSON.stringify({
389
+ sessionId: String(sessionId || ""),
390
+ input: String(input || ""),
391
+ }),
392
+ });
393
+ return parseJsonOrThrow(res, "Could not send watchdog terminal input");
394
+ }
395
+
396
+ export async function closeWatchdogTerminalSession(sessionId) {
397
+ const res = await authFetch("/api/watchdog/terminal/close", {
398
+ method: "POST",
399
+ headers: { "Content-Type": "application/json" },
400
+ body: JSON.stringify({
401
+ sessionId: String(sessionId || ""),
402
+ }),
403
+ });
404
+ return parseJsonOrThrow(res, "Could not close watchdog terminal");
405
+ }
406
+
368
407
  export async function triggerWatchdogRepair() {
369
408
  const res = await authFetch("/api/watchdog/repair", { method: "POST" });
370
409
  return parseJsonOrThrow(res, "Could not trigger watchdog repair");
@@ -0,0 +1,239 @@
1
+ const { registerAuthRoutes } = require("../routes/auth");
2
+ const { registerPageRoutes } = require("../routes/pages");
3
+ const { registerModelRoutes } = require("../routes/models");
4
+ const { registerOnboardingRoutes } = require("../routes/onboarding");
5
+ const { registerSystemRoutes } = require("../routes/system");
6
+ const { registerPairingRoutes } = require("../routes/pairings");
7
+ const { registerCodexRoutes } = require("../routes/codex");
8
+ const { registerGoogleRoutes } = require("../routes/google");
9
+ const { registerBrowseRoutes } = require("../routes/browse");
10
+ const { registerProxyRoutes } = require("../routes/proxy");
11
+ const { registerTelegramRoutes } = require("../routes/telegram");
12
+ const { registerWebhookRoutes } = require("../routes/webhooks");
13
+ const { registerWatchdogRoutes } = require("../routes/watchdog");
14
+ const { registerUsageRoutes } = require("../routes/usage");
15
+ const { registerGmailRoutes } = require("../routes/gmail");
16
+ const { registerDoctorRoutes } = require("../routes/doctor");
17
+ const { registerAgentRoutes } = require("../routes/agents");
18
+ const { registerCronRoutes } = require("../routes/cron");
19
+
20
+ const registerServerRoutes = ({
21
+ app,
22
+ fs,
23
+ constants,
24
+ loginThrottle,
25
+ shellCmd,
26
+ clawCmd,
27
+ gogCmd,
28
+ gatewayEnv,
29
+ parseJsonFromNoisyOutput,
30
+ normalizeOnboardingModels,
31
+ authProfiles,
32
+ readEnvFile,
33
+ writeEnvFile,
34
+ reloadEnv,
35
+ isOnboarded,
36
+ isGatewayRunning,
37
+ resolveGithubRepoUrl,
38
+ resolveModelProvider,
39
+ ensureGatewayProxyConfig,
40
+ getBaseUrl,
41
+ startGateway,
42
+ syncChannelConfig,
43
+ getChannelStatus,
44
+ openclawVersionService,
45
+ alphaclawVersionService,
46
+ restartGateway,
47
+ restartRequiredState,
48
+ topicRegistry,
49
+ createPkcePair,
50
+ parseCodexAuthorizationInput,
51
+ getCodexAccountId,
52
+ readGoogleCredentials,
53
+ getApiEnableUrl,
54
+ telegramApi,
55
+ doSyncPromptFiles,
56
+ getRequests,
57
+ getRequestById,
58
+ getHookSummaries,
59
+ deleteRequestsByHook,
60
+ watchdog,
61
+ getRecentEvents,
62
+ readLogTail,
63
+ watchdogTerminal,
64
+ getDailySummary,
65
+ getSessionsList,
66
+ getSessionDetail,
67
+ getSessionTimeSeries,
68
+ cronService,
69
+ doctorService,
70
+ agentsService,
71
+ operationEvents,
72
+ proxy,
73
+ getGatewayUrl,
74
+ SETUP_API_PREFIXES,
75
+ webhookMiddleware,
76
+ }) => {
77
+ const { requireAuth, isAuthorizedRequest } = registerAuthRoutes({
78
+ app,
79
+ loginThrottle,
80
+ });
81
+
82
+ registerPageRoutes({ app, requireAuth, isGatewayRunning });
83
+ registerModelRoutes({
84
+ app,
85
+ shellCmd,
86
+ gatewayEnv,
87
+ parseJsonFromNoisyOutput,
88
+ normalizeOnboardingModels,
89
+ authProfiles,
90
+ readEnvFile,
91
+ writeEnvFile,
92
+ reloadEnv,
93
+ });
94
+ registerOnboardingRoutes({
95
+ app,
96
+ fs,
97
+ constants,
98
+ shellCmd,
99
+ gatewayEnv,
100
+ readEnvFile,
101
+ writeEnvFile,
102
+ reloadEnv,
103
+ isOnboarded,
104
+ resolveGithubRepoUrl,
105
+ resolveModelProvider,
106
+ hasCodexOauthProfile: authProfiles.hasCodexOauthProfile,
107
+ authProfiles,
108
+ ensureGatewayProxyConfig,
109
+ getBaseUrl,
110
+ startGateway,
111
+ });
112
+ registerSystemRoutes({
113
+ app,
114
+ fs,
115
+ readEnvFile,
116
+ writeEnvFile,
117
+ reloadEnv,
118
+ kKnownVars: constants.kKnownVars,
119
+ kKnownKeys: constants.kKnownKeys,
120
+ kSystemVars: constants.kSystemVars,
121
+ syncChannelConfig,
122
+ isGatewayRunning,
123
+ isOnboarded,
124
+ getChannelStatus,
125
+ openclawVersionService,
126
+ alphaclawVersionService,
127
+ clawCmd,
128
+ restartGateway,
129
+ OPENCLAW_DIR: constants.OPENCLAW_DIR,
130
+ restartRequiredState,
131
+ topicRegistry,
132
+ authProfiles,
133
+ });
134
+ registerBrowseRoutes({
135
+ app,
136
+ fs,
137
+ kRootDir: constants.OPENCLAW_DIR,
138
+ });
139
+ registerPairingRoutes({ app, clawCmd, isOnboarded });
140
+ registerCodexRoutes({
141
+ app,
142
+ createPkcePair,
143
+ parseCodexAuthorizationInput,
144
+ getCodexAccountId,
145
+ authProfiles,
146
+ });
147
+ registerGoogleRoutes({
148
+ app,
149
+ fs,
150
+ isGatewayRunning,
151
+ gogCmd,
152
+ getBaseUrl,
153
+ readGoogleCredentials,
154
+ getApiEnableUrl,
155
+ constants,
156
+ });
157
+ const gmailWatchService = registerGmailRoutes({
158
+ app,
159
+ fs,
160
+ constants,
161
+ gogCmd,
162
+ getBaseUrl,
163
+ readGoogleCredentials,
164
+ readEnvFile,
165
+ writeEnvFile,
166
+ reloadEnv,
167
+ restartRequiredState,
168
+ });
169
+ registerTelegramRoutes({
170
+ app,
171
+ telegramApi,
172
+ syncPromptFiles: doSyncPromptFiles,
173
+ shellCmd,
174
+ });
175
+ registerWebhookRoutes({
176
+ app,
177
+ fs,
178
+ constants,
179
+ getBaseUrl,
180
+ shellCmd,
181
+ webhooksDb: {
182
+ getRequests,
183
+ getRequestById,
184
+ getHookSummaries,
185
+ deleteRequestsByHook,
186
+ },
187
+ restartRequiredState,
188
+ });
189
+ registerWatchdogRoutes({
190
+ app,
191
+ requireAuth,
192
+ watchdog,
193
+ getRecentEvents,
194
+ readLogTail,
195
+ watchdogTerminal,
196
+ });
197
+ registerUsageRoutes({
198
+ app,
199
+ requireAuth,
200
+ getDailySummary,
201
+ getSessionsList,
202
+ getSessionDetail,
203
+ getSessionTimeSeries,
204
+ });
205
+ registerCronRoutes({
206
+ app,
207
+ requireAuth,
208
+ cronService,
209
+ });
210
+ registerDoctorRoutes({
211
+ app,
212
+ requireAuth,
213
+ doctorService,
214
+ });
215
+ registerAgentRoutes({
216
+ app,
217
+ agentsService,
218
+ restartRequiredState,
219
+ operationEvents,
220
+ });
221
+ registerProxyRoutes({
222
+ app,
223
+ proxy,
224
+ getGatewayUrl,
225
+ SETUP_API_PREFIXES,
226
+ requireAuth,
227
+ webhookMiddleware,
228
+ });
229
+
230
+ return {
231
+ requireAuth,
232
+ isAuthorizedRequest,
233
+ gmailWatchService,
234
+ };
235
+ };
236
+
237
+ module.exports = {
238
+ registerServerRoutes,
239
+ };
@@ -0,0 +1,44 @@
1
+ const initializeServerRuntime = ({
2
+ fs,
3
+ constants,
4
+ startEnvWatcher,
5
+ attachGatewaySignalHandlers,
6
+ cleanupStaleImportTempDirs,
7
+ migrateManagedInternalFiles,
8
+ }) => {
9
+ startEnvWatcher();
10
+ attachGatewaySignalHandlers();
11
+ cleanupStaleImportTempDirs();
12
+ migrateManagedInternalFiles({
13
+ fs,
14
+ openclawDir: constants.OPENCLAW_DIR,
15
+ });
16
+ };
17
+
18
+ const initializeServerDatabases = ({
19
+ constants,
20
+ initWebhooksDb,
21
+ initWatchdogDb,
22
+ initUsageDb,
23
+ initDoctorDb,
24
+ }) => {
25
+ initWebhooksDb({
26
+ rootDir: constants.kRootDir,
27
+ pruneDays: constants.kWebhookPruneDays,
28
+ });
29
+ initWatchdogDb({
30
+ rootDir: constants.kRootDir,
31
+ pruneDays: constants.kWatchdogLogRetentionDays,
32
+ });
33
+ initUsageDb({
34
+ rootDir: constants.kRootDir,
35
+ });
36
+ initDoctorDb({
37
+ rootDir: constants.kRootDir,
38
+ });
39
+ };
40
+
41
+ module.exports = {
42
+ initializeServerRuntime,
43
+ initializeServerDatabases,
44
+ };
@@ -0,0 +1,55 @@
1
+ const startServerLifecycle = ({
2
+ server,
3
+ PORT,
4
+ isOnboarded,
5
+ runOnboardedBootSequence,
6
+ doSyncPromptFiles,
7
+ reloadEnv,
8
+ syncChannelConfig,
9
+ readEnvFile,
10
+ ensureGatewayProxyConfig,
11
+ resolveSetupUrl,
12
+ startGateway,
13
+ watchdog,
14
+ gmailWatchService,
15
+ }) => {
16
+ server.listen(PORT, "0.0.0.0", () => {
17
+ console.log(`[alphaclaw] Express listening on :${PORT}`);
18
+ if (isOnboarded()) {
19
+ runOnboardedBootSequence({
20
+ doSyncPromptFiles,
21
+ reloadEnv,
22
+ syncChannelConfig,
23
+ readEnvFile,
24
+ ensureGatewayProxyConfig,
25
+ resolveSetupUrl,
26
+ startGateway,
27
+ watchdog,
28
+ gmailWatchService,
29
+ });
30
+ } else {
31
+ console.log("[alphaclaw] Awaiting onboarding via Setup UI");
32
+ }
33
+ });
34
+ };
35
+
36
+ const registerServerShutdown = ({ gmailWatchService, watchdogTerminal }) => {
37
+ const shutdownGmailWatchService = async () => {
38
+ try {
39
+ await gmailWatchService.stop();
40
+ } catch {}
41
+ watchdogTerminal.disposeSession();
42
+ };
43
+
44
+ process.on("SIGTERM", () => {
45
+ shutdownGmailWatchService();
46
+ });
47
+ process.on("SIGINT", () => {
48
+ shutdownGmailWatchService();
49
+ });
50
+ };
51
+
52
+ module.exports = {
53
+ startServerLifecycle,
54
+ registerServerShutdown,
55
+ };