@chrysb/alphaclaw 0.8.1 → 0.8.3-beta.0
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 +33 -24
- package/bin/alphaclaw.js +13 -2
- package/lib/public/css/chat.css +426 -0
- package/lib/public/css/explorer.css +101 -0
- package/lib/public/css/tailwind.generated.css +1 -0
- package/lib/public/css/tailwind.input.css +3 -0
- package/lib/public/css/theme.css +28 -0
- package/lib/public/css/vendor/xterm.css +218 -0
- package/lib/public/dist/app.bundle.js +10706 -0
- package/lib/public/dist/chunks/addon-fit-W4YZGRNV.js +1 -0
- package/lib/public/dist/chunks/chunk-72ZECFVW.js +1 -0
- package/lib/public/dist/chunks/xterm-KOX4YMOF.js +9 -0
- package/lib/public/js/app.js +38 -4
- package/lib/public/js/components/action-button.js +8 -8
- package/lib/public/js/components/add-channel-menu.js +2 -2
- package/lib/public/js/components/agent-send-modal.js +6 -6
- package/lib/public/js/components/agents-tab/agent-bindings-section/channel-item-trailing.js +7 -7
- package/lib/public/js/components/agents-tab/agent-bindings-section/index.js +3 -3
- package/lib/public/js/components/agents-tab/agent-bindings-section/use-agent-bindings.js +1 -1
- package/lib/public/js/components/agents-tab/agent-bindings-section/use-channel-items.js +4 -4
- package/lib/public/js/components/agents-tab/agent-detail-panel.js +5 -5
- package/lib/public/js/components/agents-tab/agent-identity-section.js +18 -18
- package/lib/public/js/components/agents-tab/agent-overview/index.js +2 -2
- package/lib/public/js/components/agents-tab/agent-overview/manage-card.js +2 -2
- package/lib/public/js/components/agents-tab/agent-overview/model-card.js +8 -8
- package/lib/public/js/components/agents-tab/agent-overview/tools-card.js +5 -5
- package/lib/public/js/components/agents-tab/agent-overview/use-model-card.js +1 -1
- package/lib/public/js/components/agents-tab/agent-overview/use-workspace-card.js +1 -1
- package/lib/public/js/components/agents-tab/agent-overview/workspace-card.js +4 -4
- package/lib/public/js/components/agents-tab/agent-pairing-section.js +4 -4
- package/lib/public/js/components/agents-tab/agent-tools/index.js +5 -5
- package/lib/public/js/components/agents-tab/agent-tools/use-agent-tools.js +1 -1
- package/lib/public/js/components/agents-tab/create-agent-modal.js +13 -13
- package/lib/public/js/components/agents-tab/create-channel-modal.js +34 -34
- package/lib/public/js/components/agents-tab/delete-agent-dialog.js +3 -3
- package/lib/public/js/components/agents-tab/edit-agent-modal.js +9 -9
- package/lib/public/js/components/agents-tab/index.js +3 -3
- package/lib/public/js/components/agents-tab/use-agents.js +1 -1
- package/lib/public/js/components/badge.js +6 -6
- package/lib/public/js/components/channel-account-status-badge.js +2 -2
- package/lib/public/js/components/channel-operations-panel.js +2 -2
- package/lib/public/js/components/channels.js +9 -9
- package/lib/public/js/components/confirm-dialog.js +5 -5
- package/lib/public/js/components/credentials-modal.js +22 -22
- package/lib/public/js/components/cron-tab/cron-calendar.js +6 -6
- package/lib/public/js/components/cron-tab/cron-insights-panel.js +10 -10
- package/lib/public/js/components/cron-tab/cron-job-detail.js +4 -4
- package/lib/public/js/components/cron-tab/cron-job-list.js +4 -4
- package/lib/public/js/components/cron-tab/cron-job-settings-card.js +15 -15
- package/lib/public/js/components/cron-tab/cron-job-trends-panel.js +5 -5
- package/lib/public/js/components/cron-tab/cron-job-usage.js +16 -16
- package/lib/public/js/components/cron-tab/cron-overview.js +10 -10
- package/lib/public/js/components/cron-tab/cron-prompt-editor.js +3 -3
- package/lib/public/js/components/cron-tab/cron-run-history-panel.js +39 -39
- package/lib/public/js/components/cron-tab/cron-runs-trend-card.js +4 -4
- package/lib/public/js/components/cron-tab/index.js +5 -5
- package/lib/public/js/components/cron-tab/use-cron-tab.js +1 -1
- package/lib/public/js/components/device-pairings.js +12 -12
- package/lib/public/js/components/doctor/findings-list.js +22 -22
- package/lib/public/js/components/doctor/fix-card-modal.js +2 -2
- package/lib/public/js/components/doctor/general-warning.js +5 -5
- package/lib/public/js/components/doctor/index.js +26 -26
- package/lib/public/js/components/doctor/summary-cards.js +5 -5
- package/lib/public/js/components/envars.js +16 -16
- package/lib/public/js/components/features.js +4 -4
- package/lib/public/js/components/file-tree.js +4 -4
- package/lib/public/js/components/file-viewer/diff-viewer.js +2 -2
- package/lib/public/js/components/file-viewer/editor-surface.js +2 -2
- package/lib/public/js/components/file-viewer/frontmatter-panel.js +2 -2
- package/lib/public/js/components/file-viewer/index.js +3 -3
- package/lib/public/js/components/file-viewer/markdown-split-view.js +2 -2
- package/lib/public/js/components/file-viewer/media-preview.js +2 -2
- package/lib/public/js/components/file-viewer/scroll-sync.js +1 -1
- package/lib/public/js/components/file-viewer/sqlite-viewer.js +2 -2
- package/lib/public/js/components/file-viewer/status-banners.js +2 -2
- package/lib/public/js/components/file-viewer/toolbar.js +2 -2
- package/lib/public/js/components/file-viewer/use-editor-line-number-sync.js +1 -1
- package/lib/public/js/components/file-viewer/use-editor-selection-restore.js +1 -1
- package/lib/public/js/components/file-viewer/use-file-diff.js +1 -1
- package/lib/public/js/components/file-viewer/use-file-loader.js +1 -1
- package/lib/public/js/components/file-viewer/use-file-viewer-draft-sync.js +1 -1
- package/lib/public/js/components/file-viewer/use-file-viewer-hotkeys.js +1 -1
- package/lib/public/js/components/file-viewer/use-file-viewer.js +2 -2
- package/lib/public/js/components/gateway.js +12 -12
- package/lib/public/js/components/general/index.js +7 -7
- package/lib/public/js/components/general/use-general-tab.js +1 -1
- package/lib/public/js/components/global-restart-banner.js +2 -2
- package/lib/public/js/components/google/account-row.js +7 -7
- package/lib/public/js/components/google/add-account-modal.js +8 -8
- package/lib/public/js/components/google/gmail-setup-wizard.js +24 -24
- package/lib/public/js/components/google/gmail-watch-toggle.js +5 -5
- package/lib/public/js/components/google/index.js +6 -6
- package/lib/public/js/components/google/use-gmail-watch.js +1 -1
- package/lib/public/js/components/google/use-google-accounts.js +1 -1
- package/lib/public/js/components/icons.js +2 -2
- package/lib/public/js/components/info-tooltip.js +3 -3
- package/lib/public/js/components/loading-spinner.js +2 -2
- package/lib/public/js/components/modal-shell.js +5 -5
- package/lib/public/js/components/models-tab/index.js +11 -11
- package/lib/public/js/components/models-tab/model-picker.js +9 -9
- package/lib/public/js/components/models-tab/provider-auth-card.js +12 -12
- package/lib/public/js/components/models-tab/use-models.js +1 -1
- package/lib/public/js/components/models.js +18 -18
- package/lib/public/js/components/nodes-tab/browser-attach/index.js +5 -5
- package/lib/public/js/components/nodes-tab/connected-nodes/index.js +34 -32
- package/lib/public/js/components/nodes-tab/connected-nodes/use-connected-nodes-card.js +18 -3
- package/lib/public/js/components/nodes-tab/exec-allowlist/index.js +10 -10
- package/lib/public/js/components/nodes-tab/exec-allowlist/use-exec-allowlist.js +1 -1
- package/lib/public/js/components/nodes-tab/exec-config/index.js +13 -13
- package/lib/public/js/components/nodes-tab/exec-config/use-exec-config.js +1 -1
- package/lib/public/js/components/nodes-tab/index.js +2 -2
- package/lib/public/js/components/nodes-tab/setup-wizard/index.js +14 -14
- package/lib/public/js/components/nodes-tab/setup-wizard/use-setup-wizard.js +1 -1
- package/lib/public/js/components/nodes-tab/use-nodes-tab.js +1 -1
- package/lib/public/js/components/onboarding/use-welcome-codex.js +1 -1
- package/lib/public/js/components/onboarding/use-welcome-pairing.js +1 -1
- package/lib/public/js/components/onboarding/use-welcome-storage.js +1 -1
- package/lib/public/js/components/onboarding/welcome-config.js +3 -3
- package/lib/public/js/components/onboarding/welcome-form-step.js +34 -34
- package/lib/public/js/components/onboarding/welcome-header.js +2 -2
- package/lib/public/js/components/onboarding/welcome-import-step.js +22 -22
- package/lib/public/js/components/onboarding/welcome-pairing-step.js +15 -15
- package/lib/public/js/components/onboarding/welcome-placeholder-review-step.js +7 -7
- package/lib/public/js/components/onboarding/welcome-pre-step.js +9 -9
- package/lib/public/js/components/onboarding/welcome-secret-review-step.js +15 -15
- package/lib/public/js/components/onboarding/welcome-setup-step.js +8 -8
- package/lib/public/js/components/overflow-menu.js +3 -3
- package/lib/public/js/components/page-header.js +2 -2
- package/lib/public/js/components/pairings.js +14 -14
- package/lib/public/js/components/pane-shell.js +2 -2
- package/lib/public/js/components/pill-tabs.js +4 -4
- package/lib/public/js/components/pop-actions.js +3 -3
- package/lib/public/js/components/providers.js +17 -17
- package/lib/public/js/components/routes/agents-route.js +2 -2
- package/lib/public/js/components/routes/browse-route.js +2 -2
- package/lib/public/js/components/routes/chat-route.js +1094 -0
- package/lib/public/js/components/routes/cron-route.js +2 -2
- package/lib/public/js/components/routes/doctor-route.js +2 -2
- package/lib/public/js/components/routes/envars-route.js +2 -2
- package/lib/public/js/components/routes/general-route.js +2 -2
- package/lib/public/js/components/routes/index.js +1 -0
- package/lib/public/js/components/routes/models-route.js +2 -2
- package/lib/public/js/components/routes/nodes-route.js +2 -2
- package/lib/public/js/components/routes/providers-route.js +2 -2
- package/lib/public/js/components/routes/route-redirect.js +2 -2
- package/lib/public/js/components/routes/telegram-route.js +2 -2
- package/lib/public/js/components/routes/usage-route.js +2 -2
- package/lib/public/js/components/routes/watchdog-route.js +2 -2
- package/lib/public/js/components/routes/webhooks-route.js +2 -2
- package/lib/public/js/components/scope-picker.js +9 -9
- package/lib/public/js/components/secret-input.js +5 -5
- package/lib/public/js/components/segmented-control.js +2 -2
- package/lib/public/js/components/session-select-field.js +7 -7
- package/lib/public/js/components/sidebar-git-panel.js +3 -3
- package/lib/public/js/components/sidebar.js +55 -3
- package/lib/public/js/components/summary-stat-card.js +3 -3
- package/lib/public/js/components/telegram-workspace/index.js +10 -10
- package/lib/public/js/components/telegram-workspace/manage.js +36 -36
- package/lib/public/js/components/telegram-workspace/onboarding.js +73 -73
- package/lib/public/js/components/toast.js +8 -8
- package/lib/public/js/components/toggle-switch.js +2 -2
- package/lib/public/js/components/tooltip.js +5 -5
- package/lib/public/js/components/update-action-button.js +2 -2
- package/lib/public/js/components/update-modal.js +9 -9
- package/lib/public/js/components/usage-tab/constants.js +2 -2
- package/lib/public/js/components/usage-tab/index.js +3 -3
- package/lib/public/js/components/usage-tab/overview-section.js +15 -15
- package/lib/public/js/components/usage-tab/sessions-section.js +19 -19
- package/lib/public/js/components/usage-tab/use-usage-tab.js +2 -2
- package/lib/public/js/components/watchdog-tab/console/index.js +22 -8
- package/lib/public/js/components/watchdog-tab/console/use-console.js +28 -2
- package/lib/public/js/components/watchdog-tab/helpers.js +35 -6
- package/lib/public/js/components/watchdog-tab/incidents/index.js +6 -6
- package/lib/public/js/components/watchdog-tab/incidents/use-incidents.js +1 -1
- package/lib/public/js/components/watchdog-tab/index.js +4 -2
- package/lib/public/js/components/watchdog-tab/resource-bar.js +5 -5
- package/lib/public/js/components/watchdog-tab/resources/index.js +14 -3
- package/lib/public/js/components/watchdog-tab/resources/use-resources.js +1 -1
- package/lib/public/js/components/watchdog-tab/settings/index.js +97 -30
- package/lib/public/js/components/watchdog-tab/settings/use-settings.js +1 -1
- package/lib/public/js/components/watchdog-tab/terminal/index.js +3 -3
- package/lib/public/js/components/watchdog-tab/terminal/use-terminal.js +41 -5
- package/lib/public/js/components/watchdog-tab/use-watchdog-tab.js +2 -0
- package/lib/public/js/components/webhooks/create-webhook-modal/index.js +17 -17
- package/lib/public/js/components/webhooks/helpers.js +3 -3
- package/lib/public/js/components/webhooks/index.js +4 -4
- package/lib/public/js/components/webhooks/request-history/index.js +14 -14
- package/lib/public/js/components/webhooks/request-history/use-request-history.js +1 -1
- package/lib/public/js/components/webhooks/webhook-detail/index.js +41 -41
- package/lib/public/js/components/webhooks/webhook-detail/use-webhook-detail.js +1 -1
- package/lib/public/js/components/webhooks/webhook-list/index.js +11 -11
- package/lib/public/js/components/webhooks/webhook-list/use-webhook-list.js +1 -1
- package/lib/public/js/components/welcome/index.js +3 -3
- package/lib/public/js/components/welcome/use-welcome.js +10 -10
- package/lib/public/js/hooks/use-app-shell-controller.js +1 -1
- package/lib/public/js/hooks/use-app-shell-ui.js +1 -1
- package/lib/public/js/hooks/use-browse-navigation.js +14 -3
- package/lib/public/js/hooks/use-cached-fetch.js +1 -1
- package/lib/public/js/hooks/use-destination-session-selection.js +1 -1
- package/lib/public/js/hooks/use-hash-location.js +1 -1
- package/lib/public/js/hooks/useAgentSessions.js +1 -1
- package/lib/public/js/hooks/usePolling.js +1 -1
- package/lib/public/js/lib/app-navigation.js +1 -0
- package/lib/public/js/lib/storage-keys.js +3 -0
- package/lib/public/js/tailwind-config.js +39 -0
- package/lib/public/login.html +3 -18
- package/lib/public/setup.html +3 -18
- package/lib/server/auth-profiles.js +1 -1
- package/lib/server/chat-ws.js +835 -0
- package/lib/server/init/register-server-routes.js +2 -0
- package/lib/server/onboarding/validation.js +15 -10
- package/lib/server/routes/nodes.js +10 -2
- package/lib/server/routes/pairings.js +5 -1
- package/lib/server/routes/system.js +5 -0
- package/lib/server/routes/watchdog.js +15 -0
- package/lib/server/watchdog-terminal-ws.js +14 -1
- package/lib/server/watchdog.js +137 -51
- package/lib/server.js +38 -0
- package/package.json +14 -3
|
@@ -68,6 +68,7 @@ const registerServerRoutes = ({
|
|
|
68
68
|
deleteOauthCallback,
|
|
69
69
|
markOauthCallbackUsed,
|
|
70
70
|
watchdog,
|
|
71
|
+
watchdogNotifier,
|
|
71
72
|
getRecentEvents,
|
|
72
73
|
readLogTail,
|
|
73
74
|
watchdogTerminal,
|
|
@@ -212,6 +213,7 @@ const registerServerRoutes = ({
|
|
|
212
213
|
app,
|
|
213
214
|
requireAuth,
|
|
214
215
|
watchdog,
|
|
216
|
+
watchdogNotifier,
|
|
215
217
|
getRecentEvents,
|
|
216
218
|
readLogTail,
|
|
217
219
|
watchdogTerminal,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { getEnvVarForApiKeyProvider } = require("../auth-profiles");
|
|
2
|
+
|
|
1
3
|
const kAnthropicSetupTokenPrefix = "sk-ant-oat01-";
|
|
2
4
|
const kAnthropicApiKeyPrefix = "sk-ant-api";
|
|
3
5
|
|
|
@@ -71,12 +73,6 @@ const validateOnboardingInput = ({ vars, modelKey, resolveModelProvider, hasCode
|
|
|
71
73
|
const githubRepoInput = String(varMap.GITHUB_WORKSPACE_REPO || "").trim();
|
|
72
74
|
const selectedProvider = resolveModelProvider(modelKey);
|
|
73
75
|
const hasCodexOauth = hasCodexOauthProfile();
|
|
74
|
-
const hasAiByProvider = {
|
|
75
|
-
anthropic: !!(varMap.ANTHROPIC_API_KEY || varMap.ANTHROPIC_TOKEN),
|
|
76
|
-
openai: !!varMap.OPENAI_API_KEY,
|
|
77
|
-
"openai-codex": !!hasCodexOauth,
|
|
78
|
-
google: !!varMap.GEMINI_API_KEY,
|
|
79
|
-
};
|
|
80
76
|
const hasAnyAi = !!(
|
|
81
77
|
varMap.ANTHROPIC_API_KEY ||
|
|
82
78
|
varMap.ANTHROPIC_TOKEN ||
|
|
@@ -84,10 +80,19 @@ const validateOnboardingInput = ({ vars, modelKey, resolveModelProvider, hasCode
|
|
|
84
80
|
varMap.GEMINI_API_KEY ||
|
|
85
81
|
hasCodexOauth
|
|
86
82
|
);
|
|
87
|
-
const hasAi =
|
|
88
|
-
selectedProvider
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
const hasAi = (() => {
|
|
84
|
+
if (selectedProvider === "openai-codex") {
|
|
85
|
+
return hasCodexOauth;
|
|
86
|
+
}
|
|
87
|
+
if (selectedProvider === "anthropic") {
|
|
88
|
+
return !!(varMap.ANTHROPIC_API_KEY || varMap.ANTHROPIC_TOKEN);
|
|
89
|
+
}
|
|
90
|
+
const envKey = getEnvVarForApiKeyProvider(selectedProvider);
|
|
91
|
+
if (envKey) {
|
|
92
|
+
return !!String(varMap[envKey] || "").trim();
|
|
93
|
+
}
|
|
94
|
+
return hasAnyAi;
|
|
95
|
+
})();
|
|
91
96
|
const hasGithub = !!(githubToken && githubRepoInput);
|
|
92
97
|
const hasChannel = !!(varMap.TELEGRAM_BOT_TOKEN || varMap.DISCORD_BOT_TOKEN || (varMap.SLACK_BOT_TOKEN && varMap.SLACK_APP_TOKEN));
|
|
93
98
|
|
|
@@ -10,6 +10,8 @@ const kSafeNodeIdPattern = /^[\w\-:.]+$/;
|
|
|
10
10
|
const kNodeBrowserInvokeTimeoutMs = 30000;
|
|
11
11
|
const kNodeBrowserCliTimeoutMs = 35000;
|
|
12
12
|
const kNodeRouteCliTimeoutMs = 12000;
|
|
13
|
+
const kNodesStatusCliTimeoutMs = 5000;
|
|
14
|
+
const kNodesPendingCliTimeoutMs = 5000;
|
|
13
15
|
|
|
14
16
|
const quoteCliArg = (value) => quoteShellArg(value, { strategy: "single" });
|
|
15
17
|
|
|
@@ -172,7 +174,10 @@ const registerNodeRoutes = ({
|
|
|
172
174
|
fsModule,
|
|
173
175
|
}) => {
|
|
174
176
|
app.get("/api/nodes", async (_req, res) => {
|
|
175
|
-
const statusResult = await clawCmd("nodes status --json", {
|
|
177
|
+
const statusResult = await clawCmd("nodes status --json", {
|
|
178
|
+
quiet: true,
|
|
179
|
+
timeoutMs: kNodesStatusCliTimeoutMs,
|
|
180
|
+
});
|
|
176
181
|
if (!statusResult.ok) {
|
|
177
182
|
return res.status(500).json({
|
|
178
183
|
ok: false,
|
|
@@ -180,7 +185,10 @@ const registerNodeRoutes = ({
|
|
|
180
185
|
});
|
|
181
186
|
}
|
|
182
187
|
const status = parseNodesStatus(statusResult.stdout);
|
|
183
|
-
const pendingResult = await clawCmd("nodes pending --json", {
|
|
188
|
+
const pendingResult = await clawCmd("nodes pending --json", {
|
|
189
|
+
quiet: true,
|
|
190
|
+
timeoutMs: kNodesPendingCliTimeoutMs,
|
|
191
|
+
});
|
|
184
192
|
const pending = pendingResult.ok
|
|
185
193
|
? parseNodesPending(pendingResult.stdout)
|
|
186
194
|
: status.pending;
|
|
@@ -7,6 +7,7 @@ const { quoteShellArg } = require("../utils/shell");
|
|
|
7
7
|
|
|
8
8
|
const kAllowedPairingChannels = new Set(["telegram", "discord", "slack"]);
|
|
9
9
|
const kSafePairingArgPattern = /^[\w\-:.]+$/;
|
|
10
|
+
const kDevicesListCliTimeoutMs = 5000;
|
|
10
11
|
const quoteCliArg = (value) => quoteShellArg(value, { strategy: "single" });
|
|
11
12
|
|
|
12
13
|
const resolvePairingStorePath = ({ openclawDir, channel }) =>
|
|
@@ -208,7 +209,10 @@ const registerPairingRoutes = ({ app, clawCmd, isOnboarded, fsModule = fs, openc
|
|
|
208
209
|
cliAutoApproveComplete: devicePairingCache.cliAutoApproveComplete,
|
|
209
210
|
});
|
|
210
211
|
}
|
|
211
|
-
const result = await clawCmd("devices list --json", {
|
|
212
|
+
const result = await clawCmd("devices list --json", {
|
|
213
|
+
quiet: true,
|
|
214
|
+
timeoutMs: kDevicesListCliTimeoutMs,
|
|
215
|
+
});
|
|
212
216
|
if (!result.ok) {
|
|
213
217
|
return res.json({ pending: [], cliAutoApproveComplete: hasCliAutoApproveMarker() });
|
|
214
218
|
}
|
|
@@ -532,6 +532,10 @@ const registerSystemRoutes = ({
|
|
|
532
532
|
const running = await isGatewayRunning();
|
|
533
533
|
const repo = process.env.GITHUB_WORKSPACE_REPO || "";
|
|
534
534
|
const openclawVersion = openclawVersionService.readOpenclawVersion();
|
|
535
|
+
const alphaclawVersion =
|
|
536
|
+
typeof alphaclawVersionService?.readAlphaclawVersion === "function"
|
|
537
|
+
? alphaclawVersionService.readAlphaclawVersion()
|
|
538
|
+
: null;
|
|
535
539
|
return {
|
|
536
540
|
gateway: running
|
|
537
541
|
? "running"
|
|
@@ -542,6 +546,7 @@ const registerSystemRoutes = ({
|
|
|
542
546
|
channels: getChannelStatus(),
|
|
543
547
|
repo,
|
|
544
548
|
openclawVersion,
|
|
549
|
+
alphaclawVersion,
|
|
545
550
|
syncCron: getSystemCronStatus(),
|
|
546
551
|
};
|
|
547
552
|
};
|
|
@@ -4,6 +4,7 @@ const registerWatchdogRoutes = ({
|
|
|
4
4
|
app,
|
|
5
5
|
requireAuth,
|
|
6
6
|
watchdog,
|
|
7
|
+
watchdogNotifier,
|
|
7
8
|
getRecentEvents,
|
|
8
9
|
readLogTail,
|
|
9
10
|
watchdogTerminal,
|
|
@@ -76,6 +77,20 @@ const registerWatchdogRoutes = ({
|
|
|
76
77
|
}
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
app.post("/api/watchdog/test-notification", requireAuth, async (req, res) => {
|
|
81
|
+
try {
|
|
82
|
+
if (!watchdogNotifier?.notify) {
|
|
83
|
+
return res.status(503).json({ ok: false, error: "Notifier not available" });
|
|
84
|
+
}
|
|
85
|
+
const result = await watchdogNotifier.notify(
|
|
86
|
+
"*AlphaClaw test notification* — your watchdog alerts are working.",
|
|
87
|
+
);
|
|
88
|
+
res.json({ ok: true, result });
|
|
89
|
+
} catch (err) {
|
|
90
|
+
res.status(500).json({ ok: false, error: err.message });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
79
94
|
app.post("/api/watchdog/terminal/session", requireAuth, (req, res) => {
|
|
80
95
|
try {
|
|
81
96
|
const terminalSession = watchdogTerminal.createOrReuseSession();
|
|
@@ -8,6 +8,7 @@ const createWatchdogTerminalWsBridge = ({
|
|
|
8
8
|
getGatewayUrl,
|
|
9
9
|
isAuthorizedRequest,
|
|
10
10
|
watchdogTerminal,
|
|
11
|
+
chatWsService = null,
|
|
11
12
|
}) => {
|
|
12
13
|
const watchdogTerminalWss = new WebSocketServer({ noServer: true });
|
|
13
14
|
|
|
@@ -84,7 +85,8 @@ const createWatchdogTerminalWsBridge = ({
|
|
|
84
85
|
);
|
|
85
86
|
if (
|
|
86
87
|
requestUrl.pathname.startsWith("/openclaw") ||
|
|
87
|
-
requestUrl.pathname === kWatchdogTerminalWsPath
|
|
88
|
+
requestUrl.pathname === kWatchdogTerminalWsPath ||
|
|
89
|
+
requestUrl.pathname === "/api/ws/chat"
|
|
88
90
|
) {
|
|
89
91
|
const upgradeReq = {
|
|
90
92
|
headers: req.headers,
|
|
@@ -105,6 +107,17 @@ const createWatchdogTerminalWsBridge = ({
|
|
|
105
107
|
});
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
110
|
+
if (requestUrl.pathname === "/api/ws/chat") {
|
|
111
|
+
if (!chatWsService || typeof chatWsService.handleUpgrade !== "function") {
|
|
112
|
+
socket.write(
|
|
113
|
+
"HTTP/1.1 503 Service Unavailable\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nChat websocket unavailable",
|
|
114
|
+
);
|
|
115
|
+
socket.destroy();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
chatWsService.handleUpgrade(req, socket, head);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
108
121
|
proxy.ws(req, socket, head, { target: getGatewayUrl() });
|
|
109
122
|
});
|
|
110
123
|
};
|
package/lib/server/watchdog.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
const kHealthStartupGraceMs = 30 * 1000;
|
|
11
11
|
const kBootstrapHealthCheckMs = 5 * 1000;
|
|
12
12
|
const kExpectedRestartWindowMs = 15 * 1000;
|
|
13
|
+
const kGatewayHealthTimeoutMs = 5 * 1000;
|
|
13
14
|
|
|
14
15
|
const isTruthy = (value) =>
|
|
15
16
|
["1", "true", "yes", "on"].includes(
|
|
@@ -18,32 +19,6 @@ const isTruthy = (value) =>
|
|
|
18
19
|
.toLowerCase(),
|
|
19
20
|
);
|
|
20
21
|
|
|
21
|
-
const parseHealthResult = (result) => {
|
|
22
|
-
if (!result?.ok)
|
|
23
|
-
return { ok: false, reason: result?.stderr || "health command failed" };
|
|
24
|
-
const raw = String(result.stdout || "").trim();
|
|
25
|
-
if (!raw) return { ok: true };
|
|
26
|
-
try {
|
|
27
|
-
const parsed = JSON.parse(raw);
|
|
28
|
-
if (parsed?.ok === false || parsed?.status === "unhealthy") {
|
|
29
|
-
return { ok: false, reason: parsed?.error || "gateway unhealthy" };
|
|
30
|
-
}
|
|
31
|
-
return { ok: true, details: parsed };
|
|
32
|
-
} catch {
|
|
33
|
-
const firstBrace = raw.indexOf("{");
|
|
34
|
-
const lastBrace = raw.lastIndexOf("}");
|
|
35
|
-
if (firstBrace >= 0 && lastBrace > firstBrace) {
|
|
36
|
-
try {
|
|
37
|
-
const parsed = JSON.parse(raw.slice(firstBrace, lastBrace + 1));
|
|
38
|
-
if (parsed?.ok === false || parsed?.status === "unhealthy") {
|
|
39
|
-
return { ok: false, reason: parsed?.error || "gateway unhealthy" };
|
|
40
|
-
}
|
|
41
|
-
return { ok: true, details: parsed };
|
|
42
|
-
} catch {}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return { ok: true };
|
|
46
|
-
};
|
|
47
22
|
const isDuplicateGatewayLaunchExit = ({ code, stderrTail = [] } = {}) => {
|
|
48
23
|
if (code !== 1) return false;
|
|
49
24
|
const stderrText = (Array.isArray(stderrTail) ? stderrTail : [])
|
|
@@ -66,6 +41,7 @@ const createWatchdog = ({
|
|
|
66
41
|
writeEnvFile,
|
|
67
42
|
reloadEnv,
|
|
68
43
|
resolveSetupUrl,
|
|
44
|
+
resolveGatewayHealthUrl = () => "",
|
|
69
45
|
}) => {
|
|
70
46
|
const state = {
|
|
71
47
|
lifecycle: "stopped",
|
|
@@ -85,11 +61,26 @@ const createWatchdog = ({
|
|
|
85
61
|
expectedRestartInProgress: false,
|
|
86
62
|
expectedRestartUntilMs: 0,
|
|
87
63
|
pendingRecoveryNoticeSource: "",
|
|
64
|
+
awaitingAutoRepairRecovery: false,
|
|
88
65
|
startupConsecutiveHealthFailures: 0,
|
|
89
66
|
};
|
|
90
67
|
let healthTimer = null;
|
|
91
68
|
let bootstrapHealthTimer = null;
|
|
92
69
|
let degradedHealthTimer = null;
|
|
70
|
+
let activeIncidentKey = "";
|
|
71
|
+
let sentIncidentNotifications = new Set();
|
|
72
|
+
|
|
73
|
+
const openIncident = (incidentKey = "gateway") => {
|
|
74
|
+
const normalizedKey = String(incidentKey || "gateway");
|
|
75
|
+
if (activeIncidentKey === normalizedKey) return;
|
|
76
|
+
activeIncidentKey = normalizedKey;
|
|
77
|
+
sentIncidentNotifications = new Set();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const closeIncident = () => {
|
|
81
|
+
activeIncidentKey = "";
|
|
82
|
+
sentIncidentNotifications = new Set();
|
|
83
|
+
};
|
|
93
84
|
|
|
94
85
|
const clearDegradedHealthCheckTimer = () => {
|
|
95
86
|
if (!degradedHealthTimer) return;
|
|
@@ -209,6 +200,27 @@ const createWatchdog = ({
|
|
|
209
200
|
return result;
|
|
210
201
|
};
|
|
211
202
|
|
|
203
|
+
const notifyOncePerIncident = async (
|
|
204
|
+
notificationKey,
|
|
205
|
+
message,
|
|
206
|
+
correlationId = "",
|
|
207
|
+
) => {
|
|
208
|
+
const key = String(notificationKey || "").trim();
|
|
209
|
+
if (!key) return notify(message, correlationId);
|
|
210
|
+
if (sentIncidentNotifications.has(key)) {
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
skipped: true,
|
|
214
|
+
reason: "incident_notification_already_sent",
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const result = await notify(message, correlationId);
|
|
218
|
+
if (result?.ok || result?.skipped) {
|
|
219
|
+
sentIncidentNotifications.add(key);
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
};
|
|
223
|
+
|
|
212
224
|
const getWatchdogSetupUrl = () => {
|
|
213
225
|
try {
|
|
214
226
|
const base =
|
|
@@ -241,12 +253,19 @@ const createWatchdog = ({
|
|
|
241
253
|
attempts = 0,
|
|
242
254
|
}) => {
|
|
243
255
|
if (source === "manual") return;
|
|
256
|
+
openIncident("gateway_recovery");
|
|
244
257
|
const title = ok
|
|
245
258
|
? verifiedHealthy
|
|
246
259
|
? "🟢 Auto-repair complete, gateway healthy"
|
|
247
260
|
: "🟡 Auto-repair started, awaiting health check"
|
|
248
261
|
: "🔴 Auto-repair failed";
|
|
249
|
-
|
|
262
|
+
const notificationKey = ok
|
|
263
|
+
? verifiedHealthy
|
|
264
|
+
? "auto_repair_complete"
|
|
265
|
+
: "auto_repair_awaiting_health"
|
|
266
|
+
: "auto_repair_failed";
|
|
267
|
+
await notifyOncePerIncident(
|
|
268
|
+
notificationKey,
|
|
250
269
|
[
|
|
251
270
|
"🐺 *AlphaClaw Watchdog*",
|
|
252
271
|
withViewLogsSuffix(title),
|
|
@@ -262,6 +281,59 @@ const createWatchdog = ({
|
|
|
262
281
|
notificationsEnabled: !state.notificationsDisabled,
|
|
263
282
|
});
|
|
264
283
|
|
|
284
|
+
const probeGatewayHealth = async () => {
|
|
285
|
+
const healthUrl = String(resolveGatewayHealthUrl() || "").trim();
|
|
286
|
+
if (!healthUrl) {
|
|
287
|
+
return {
|
|
288
|
+
ok: false,
|
|
289
|
+
reason: "gateway health URL unavailable",
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const controller = new AbortController();
|
|
293
|
+
const timeoutId = setTimeout(() => controller.abort(), kGatewayHealthTimeoutMs);
|
|
294
|
+
try {
|
|
295
|
+
const response = await fetch(healthUrl, {
|
|
296
|
+
method: "GET",
|
|
297
|
+
headers: { Accept: "application/json" },
|
|
298
|
+
signal: controller.signal,
|
|
299
|
+
});
|
|
300
|
+
const rawBody = await response.text();
|
|
301
|
+
let parsedBody = null;
|
|
302
|
+
try {
|
|
303
|
+
parsedBody = rawBody ? JSON.parse(rawBody) : null;
|
|
304
|
+
} catch {}
|
|
305
|
+
if (!response.ok) {
|
|
306
|
+
return {
|
|
307
|
+
ok: false,
|
|
308
|
+
reason:
|
|
309
|
+
parsedBody?.error ||
|
|
310
|
+
`gateway health returned HTTP ${response.status}`,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
if (parsedBody?.ok === false) {
|
|
314
|
+
return {
|
|
315
|
+
ok: false,
|
|
316
|
+
reason: parsedBody?.error || "gateway unhealthy",
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
ok: true,
|
|
321
|
+
details: parsedBody,
|
|
322
|
+
};
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const message =
|
|
325
|
+
error?.name === "AbortError"
|
|
326
|
+
? `gateway health timed out after ${kGatewayHealthTimeoutMs}ms`
|
|
327
|
+
: error?.message || "gateway health request failed";
|
|
328
|
+
return {
|
|
329
|
+
ok: false,
|
|
330
|
+
reason: message,
|
|
331
|
+
};
|
|
332
|
+
} finally {
|
|
333
|
+
clearTimeout(timeoutId);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
265
337
|
const updateSettings = ({ autoRepair, notificationsEnabled } = {}) => {
|
|
266
338
|
const hasAutoRepair = typeof autoRepair === "boolean";
|
|
267
339
|
const hasNotificationsEnabled = typeof notificationsEnabled === "boolean";
|
|
@@ -309,6 +381,9 @@ const createWatchdog = ({
|
|
|
309
381
|
if (!force && !state.autoRepair) {
|
|
310
382
|
return { ok: false, skipped: true, reason: "auto_repair_disabled" };
|
|
311
383
|
}
|
|
384
|
+
if (!force && state.awaitingAutoRepairRecovery) {
|
|
385
|
+
return { ok: false, skipped: true, reason: "awaiting_health_recovery" };
|
|
386
|
+
}
|
|
312
387
|
if (state.operationInProgress) {
|
|
313
388
|
return { ok: false, skipped: true, reason: "operation_in_progress" };
|
|
314
389
|
}
|
|
@@ -353,6 +428,7 @@ const createWatchdog = ({
|
|
|
353
428
|
state.lifecycle = "running";
|
|
354
429
|
state.repairAttempts = 0;
|
|
355
430
|
state.crashTimestamps = [];
|
|
431
|
+
state.awaitingAutoRepairRecovery = false;
|
|
356
432
|
const verifiedHealthy = await runHealthCheck({
|
|
357
433
|
allowDuringOperation: true,
|
|
358
434
|
source: "repair_verify",
|
|
@@ -367,8 +443,10 @@ const createWatchdog = ({
|
|
|
367
443
|
});
|
|
368
444
|
if (!verifiedHealthy && source !== "manual") {
|
|
369
445
|
state.pendingRecoveryNoticeSource = source;
|
|
446
|
+
state.awaitingAutoRepairRecovery = true;
|
|
370
447
|
} else {
|
|
371
448
|
state.pendingRecoveryNoticeSource = "";
|
|
449
|
+
state.awaitingAutoRepairRecovery = false;
|
|
372
450
|
}
|
|
373
451
|
return { ok: true, verifiedHealthy, launchedGateway, result };
|
|
374
452
|
}
|
|
@@ -413,8 +491,7 @@ const createWatchdog = ({
|
|
|
413
491
|
const gatewayStartedAtAtStart = state.gatewayStartedAt;
|
|
414
492
|
const correlationId = createCorrelationId();
|
|
415
493
|
state.lastHealthCheckAt = new Date().toISOString();
|
|
416
|
-
const
|
|
417
|
-
const parsed = parseHealthResult(result);
|
|
494
|
+
const parsed = await probeGatewayHealth();
|
|
418
495
|
const staleAfterRestart =
|
|
419
496
|
gatewayStartedAtAtStart != null &&
|
|
420
497
|
state.gatewayStartedAt != null &&
|
|
@@ -428,6 +505,11 @@ const createWatchdog = ({
|
|
|
428
505
|
if (parsed.ok) {
|
|
429
506
|
const wasUnhealthy = state.health !== "healthy";
|
|
430
507
|
const recoveredFromCrashLoop = state.lifecycle === "crash_loop";
|
|
508
|
+
const shouldNotifyRecovery =
|
|
509
|
+
!!activeIncidentKey ||
|
|
510
|
+
recoveredFromCrashLoop ||
|
|
511
|
+
!!state.pendingRecoveryNoticeSource ||
|
|
512
|
+
state.awaitingAutoRepairRecovery;
|
|
431
513
|
state.startupConsecutiveHealthFailures = 0;
|
|
432
514
|
clearDegradedHealthCheckTimer();
|
|
433
515
|
clearExpectedRestartWindow();
|
|
@@ -437,29 +519,25 @@ const createWatchdog = ({
|
|
|
437
519
|
state.uptimeStartedAt = Date.now();
|
|
438
520
|
state.repairAttempts = 0;
|
|
439
521
|
state.crashRecoveryActive = false;
|
|
440
|
-
|
|
522
|
+
state.awaitingAutoRepairRecovery = false;
|
|
523
|
+
if (shouldNotifyRecovery) {
|
|
441
524
|
logEvent(
|
|
442
525
|
"recovery",
|
|
443
526
|
source,
|
|
444
527
|
"ok",
|
|
445
|
-
{
|
|
446
|
-
previousLifecycle: "crash_loop",
|
|
447
|
-
health: "healthy",
|
|
448
|
-
},
|
|
449
|
-
correlationId,
|
|
450
|
-
);
|
|
451
|
-
await notify(
|
|
452
528
|
[
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
529
|
+
{
|
|
530
|
+
previousLifecycle: recoveredFromCrashLoop
|
|
531
|
+
? "crash_loop"
|
|
532
|
+
: null,
|
|
533
|
+
previousRecoverySource: state.pendingRecoveryNoticeSource || null,
|
|
534
|
+
health: "healthy",
|
|
535
|
+
},
|
|
536
|
+
][0],
|
|
456
537
|
correlationId,
|
|
457
538
|
);
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const recoverySource = state.pendingRecoveryNoticeSource;
|
|
461
|
-
state.pendingRecoveryNoticeSource = "";
|
|
462
|
-
await notify(
|
|
539
|
+
await notifyOncePerIncident(
|
|
540
|
+
"gateway_healthy_again",
|
|
463
541
|
[
|
|
464
542
|
"🐺 *AlphaClaw Watchdog*",
|
|
465
543
|
withViewLogsSuffix("🟢 Gateway healthy again"),
|
|
@@ -467,11 +545,13 @@ const createWatchdog = ({
|
|
|
467
545
|
correlationId,
|
|
468
546
|
);
|
|
469
547
|
}
|
|
548
|
+
state.pendingRecoveryNoticeSource = "";
|
|
549
|
+
closeIncident();
|
|
470
550
|
logEvent(
|
|
471
551
|
"health_check",
|
|
472
552
|
source,
|
|
473
553
|
"ok",
|
|
474
|
-
parsed.details ||
|
|
554
|
+
parsed.details || { ok: true },
|
|
475
555
|
correlationId,
|
|
476
556
|
);
|
|
477
557
|
return true;
|
|
@@ -485,7 +565,7 @@ const createWatchdog = ({
|
|
|
485
565
|
"ok",
|
|
486
566
|
{
|
|
487
567
|
reason: parsed.reason,
|
|
488
|
-
|
|
568
|
+
details: parsed.details || null,
|
|
489
569
|
skipped: true,
|
|
490
570
|
expectedRestartActive: true,
|
|
491
571
|
expectedRestartUntilMs: state.expectedRestartUntilMs,
|
|
@@ -509,7 +589,7 @@ const createWatchdog = ({
|
|
|
509
589
|
"ok",
|
|
510
590
|
{
|
|
511
591
|
reason: parsed.reason,
|
|
512
|
-
|
|
592
|
+
details: parsed.details || null,
|
|
513
593
|
skipped: true,
|
|
514
594
|
startupGraceActive: true,
|
|
515
595
|
startupGraceMs: kHealthStartupGraceMs,
|
|
@@ -531,7 +611,7 @@ const createWatchdog = ({
|
|
|
531
611
|
"ok",
|
|
532
612
|
{
|
|
533
613
|
reason: parsed.reason,
|
|
534
|
-
|
|
614
|
+
details: parsed.details || null,
|
|
535
615
|
skipped: true,
|
|
536
616
|
startupFailureRetryActive: true,
|
|
537
617
|
startupConsecutiveFailures: state.startupConsecutiveHealthFailures,
|
|
@@ -551,10 +631,11 @@ const createWatchdog = ({
|
|
|
551
631
|
"health_check",
|
|
552
632
|
source,
|
|
553
633
|
"failed",
|
|
554
|
-
{ reason: parsed.reason,
|
|
634
|
+
{ reason: parsed.reason, details: parsed.details || null },
|
|
555
635
|
correlationId,
|
|
556
636
|
);
|
|
557
637
|
if (!state.autoRepair || !allowAutoRepair) return false;
|
|
638
|
+
if (state.awaitingAutoRepairRecovery) return false;
|
|
558
639
|
await runRepair({ source, correlationId });
|
|
559
640
|
return false;
|
|
560
641
|
};
|
|
@@ -658,6 +739,7 @@ const createWatchdog = ({
|
|
|
658
739
|
|
|
659
740
|
if (state.crashTimestamps.length >= kWatchdogCrashLoopThreshold) {
|
|
660
741
|
state.lifecycle = "crash_loop";
|
|
742
|
+
openIncident("gateway_recovery");
|
|
661
743
|
logEvent(
|
|
662
744
|
"crash_loop",
|
|
663
745
|
"exit_event",
|
|
@@ -668,7 +750,8 @@ const createWatchdog = ({
|
|
|
668
750
|
},
|
|
669
751
|
correlationId,
|
|
670
752
|
);
|
|
671
|
-
void
|
|
753
|
+
void notifyOncePerIncident(
|
|
754
|
+
"crash_loop_detected",
|
|
672
755
|
[
|
|
673
756
|
"🐺 *AlphaClaw Watchdog*",
|
|
674
757
|
withViewLogsSuffix(
|
|
@@ -753,6 +836,9 @@ const createWatchdog = ({
|
|
|
753
836
|
state.lifecycle = "stopped";
|
|
754
837
|
state.uptimeStartedAt = null;
|
|
755
838
|
state.startupConsecutiveHealthFailures = 0;
|
|
839
|
+
state.awaitingAutoRepairRecovery = false;
|
|
840
|
+
state.pendingRecoveryNoticeSource = "";
|
|
841
|
+
closeIncident();
|
|
756
842
|
};
|
|
757
843
|
|
|
758
844
|
const getStatus = () => {
|
package/lib/server.js
CHANGED
|
@@ -74,6 +74,7 @@ const {
|
|
|
74
74
|
} = require("./server/env");
|
|
75
75
|
const {
|
|
76
76
|
gatewayEnv,
|
|
77
|
+
getGatewayPort,
|
|
77
78
|
getGatewayUrl,
|
|
78
79
|
isOnboarded,
|
|
79
80
|
isGatewayRunning,
|
|
@@ -120,6 +121,7 @@ const {
|
|
|
120
121
|
const { createDoctorService } = require("./server/doctor/service");
|
|
121
122
|
const { createAgentsService } = require("./server/agents/service");
|
|
122
123
|
const { createOperationEventsService } = require("./server/operation-events");
|
|
124
|
+
const { createChatWsService } = require("./server/chat-ws");
|
|
123
125
|
const { runOnboardedBootSequence } = require("./server/startup");
|
|
124
126
|
const { createCronService } = require("./server/cron-service");
|
|
125
127
|
const {
|
|
@@ -194,6 +196,11 @@ const openclawVersionService = createOpenclawVersionService({
|
|
|
194
196
|
const alphaclawVersionService = createAlphaclawVersionService();
|
|
195
197
|
const restartRequiredState = createRestartRequiredState({ isGatewayRunning });
|
|
196
198
|
const operationEvents = createOperationEventsService();
|
|
199
|
+
const chatWsService = createChatWsService({
|
|
200
|
+
fs,
|
|
201
|
+
openclawDir: constants.OPENCLAW_DIR,
|
|
202
|
+
getGatewayPort,
|
|
203
|
+
});
|
|
197
204
|
const cronService = createCronService({
|
|
198
205
|
clawCmd,
|
|
199
206
|
OPENCLAW_DIR: constants.OPENCLAW_DIR,
|
|
@@ -226,6 +233,7 @@ const watchdog = createWatchdog({
|
|
|
226
233
|
writeEnvFile,
|
|
227
234
|
reloadEnv,
|
|
228
235
|
resolveSetupUrl,
|
|
236
|
+
resolveGatewayHealthUrl: () => `${getGatewayUrl()}/health`,
|
|
229
237
|
});
|
|
230
238
|
const watchdogTerminal = createWatchdogTerminalService({
|
|
231
239
|
cwd: constants.OPENCLAW_DIR,
|
|
@@ -310,6 +318,7 @@ const { isAuthorizedRequest, gmailWatchService } = registerServerRoutes({
|
|
|
310
318
|
deleteOauthCallback,
|
|
311
319
|
markOauthCallbackUsed,
|
|
312
320
|
watchdog,
|
|
321
|
+
watchdogNotifier,
|
|
313
322
|
getRecentEvents,
|
|
314
323
|
readLogTail,
|
|
315
324
|
watchdogTerminal,
|
|
@@ -326,6 +335,34 @@ const { isAuthorizedRequest, gmailWatchService } = registerServerRoutes({
|
|
|
326
335
|
SETUP_API_PREFIXES,
|
|
327
336
|
webhookMiddleware,
|
|
328
337
|
});
|
|
338
|
+
app.get("/api/chat/history", async (req, res) => {
|
|
339
|
+
const upgradeReq = {
|
|
340
|
+
headers: req.headers,
|
|
341
|
+
path: req.path,
|
|
342
|
+
query: req.query || {},
|
|
343
|
+
};
|
|
344
|
+
if (!isAuthorizedRequest(upgradeReq)) {
|
|
345
|
+
return res.status(401).json({ ok: false, error: "Unauthorized" });
|
|
346
|
+
}
|
|
347
|
+
const sessionKey = String(req.query?.sessionKey || "").trim();
|
|
348
|
+
if (!sessionKey) {
|
|
349
|
+
return res.status(400).json({ ok: false, error: "sessionKey is required" });
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
const { messages, rawHistory } = await chatWsService.fetchHistory(sessionKey);
|
|
353
|
+
return res.json({
|
|
354
|
+
ok: true,
|
|
355
|
+
sessionKey,
|
|
356
|
+
messages,
|
|
357
|
+
rawHistory,
|
|
358
|
+
});
|
|
359
|
+
} catch (err) {
|
|
360
|
+
return res.status(502).json({
|
|
361
|
+
ok: false,
|
|
362
|
+
error: err?.message || "Could not load chat history",
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
});
|
|
329
366
|
|
|
330
367
|
const server = http.createServer(app);
|
|
331
368
|
createWatchdogTerminalWsBridge({
|
|
@@ -334,6 +371,7 @@ createWatchdogTerminalWsBridge({
|
|
|
334
371
|
getGatewayUrl,
|
|
335
372
|
isAuthorizedRequest,
|
|
336
373
|
watchdogTerminal,
|
|
374
|
+
chatWsService,
|
|
337
375
|
});
|
|
338
376
|
|
|
339
377
|
startServerLifecycle({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrysb/alphaclaw",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3-beta.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
25
|
"start": "node bin/alphaclaw.js start",
|
|
26
|
+
"build:ui": "node scripts/build-ui.mjs",
|
|
26
27
|
"test": "vitest run",
|
|
27
28
|
"test:watch": "vitest",
|
|
28
29
|
"test:watchdog": "vitest run tests/server/watchdog.test.js tests/server/watchdog-db.test.js tests/server/routes-watchdog.test.js",
|
|
29
|
-
"test:coverage": "vitest run --coverage"
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
|
+
"prepack": "npm run build:ui"
|
|
30
32
|
},
|
|
31
33
|
"dependencies": {
|
|
32
34
|
"express": "^4.21.0",
|
|
@@ -35,9 +37,18 @@
|
|
|
35
37
|
"ws": "^8.19.0"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
40
|
+
"@xterm/addon-fit": "^0.10.0",
|
|
41
|
+
"@xterm/xterm": "^5.5.0",
|
|
38
42
|
"@vitest/coverage-v8": "^4.0.18",
|
|
43
|
+
"chart.js": "^4.5.1",
|
|
44
|
+
"esbuild": "^0.25.9",
|
|
45
|
+
"htm": "^3.1.1",
|
|
46
|
+
"marked": "^16.4.1",
|
|
47
|
+
"preact": "^10.27.2",
|
|
39
48
|
"supertest": "^7.2.2",
|
|
40
|
-
"
|
|
49
|
+
"tailwindcss": "^3.4.17",
|
|
50
|
+
"vitest": "^4.0.18",
|
|
51
|
+
"wouter-preact": "^3.7.1"
|
|
41
52
|
},
|
|
42
53
|
"engines": {
|
|
43
54
|
"node": ">=22.12.0"
|