@chrysb/alphaclaw 0.8.1-beta.8 → 0.8.2
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 +32 -24
- package/bin/alphaclaw.js +13 -2
- 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 +10514 -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 +4 -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 +15 -25
- package/lib/public/js/components/nodes-tab/connected-nodes/index.js +32 -32
- package/lib/public/js/components/nodes-tab/connected-nodes/use-connected-nodes-card.js +57 -6
- 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/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/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 +3 -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 +22 -4
- package/lib/public/js/hooks/use-app-shell-ui.js +1 -1
- package/lib/public/js/hooks/use-browse-navigation.js +1 -1
- 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/tailwind-config.js +39 -0
- package/lib/public/login.html +3 -18
- package/lib/public/setup.html +2 -18
- package/lib/server/init/register-server-routes.js +2 -0
- package/lib/server/onboarding/github.js +39 -0
- package/lib/server/routes/nodes.js +12 -4
- 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.js +137 -51
- package/lib/server.js +2 -0
- package/package.json +14 -3
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
|
@@ -226,6 +226,7 @@ const watchdog = createWatchdog({
|
|
|
226
226
|
writeEnvFile,
|
|
227
227
|
reloadEnv,
|
|
228
228
|
resolveSetupUrl,
|
|
229
|
+
resolveGatewayHealthUrl: () => `${getGatewayUrl()}/health`,
|
|
229
230
|
});
|
|
230
231
|
const watchdogTerminal = createWatchdogTerminalService({
|
|
231
232
|
cwd: constants.OPENCLAW_DIR,
|
|
@@ -310,6 +311,7 @@ const { isAuthorizedRequest, gmailWatchService } = registerServerRoutes({
|
|
|
310
311
|
deleteOauthCallback,
|
|
311
312
|
markOauthCallbackUsed,
|
|
312
313
|
watchdog,
|
|
314
|
+
watchdogNotifier,
|
|
313
315
|
getRecentEvents,
|
|
314
316
|
readLogTail,
|
|
315
317
|
watchdogTerminal,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrysb/alphaclaw",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
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"
|