podwatch 1.1.6 → 1.1.9
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/dist/activity-tracker.d.ts +36 -0
- package/dist/activity-tracker.d.ts.map +1 -0
- package/dist/activity-tracker.js +56 -0
- package/dist/activity-tracker.js.map +1 -0
- package/dist/hooks/auth-monitor.d.ts +87 -0
- package/dist/hooks/auth-monitor.d.ts.map +1 -0
- package/dist/hooks/auth-monitor.js +305 -0
- package/dist/hooks/auth-monitor.js.map +1 -0
- package/dist/hooks/channel-monitor.d.ts +96 -0
- package/dist/hooks/channel-monitor.d.ts.map +1 -0
- package/dist/hooks/channel-monitor.js +260 -0
- package/dist/hooks/channel-monitor.js.map +1 -0
- package/dist/hooks/config-doctor.d.ts +135 -0
- package/dist/hooks/config-doctor.d.ts.map +1 -0
- package/dist/hooks/config-doctor.js +760 -0
- package/dist/hooks/config-doctor.js.map +1 -0
- package/dist/hooks/lifecycle.d.ts.map +1 -1
- package/dist/hooks/lifecycle.js +62 -7
- package/dist/hooks/lifecycle.js.map +1 -1
- package/dist/hooks/security.d.ts.map +1 -1
- package/dist/hooks/security.js +24 -0
- package/dist/hooks/security.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-watcher.d.ts +65 -0
- package/dist/memory-watcher.d.ts.map +1 -0
- package/dist/memory-watcher.js +672 -0
- package/dist/memory-watcher.js.map +1 -0
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +0 -2
- package/dist/redact.js.map +1 -1
- package/dist/scanner.d.ts +13 -0
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +31 -0
- package/dist/scanner.js.map +1 -1
- package/dist/transmitter.d.ts.map +1 -1
- package/dist/transmitter.js +72 -2
- package/dist/transmitter.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/updater.d.ts +39 -3
- package/dist/updater.d.ts.map +1 -1
- package/dist/updater.js +164 -12
- package/dist/updater.js.map +1 -1
- package/lib/installer.js +274 -12
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity tracker — singleton module that records agent activity timestamps.
|
|
3
|
+
*
|
|
4
|
+
* Used by the auto-updater to defer gateway restarts until the agent is idle,
|
|
5
|
+
* preventing mid-conversation disruptions.
|
|
6
|
+
*
|
|
7
|
+
* Hook handlers call recordActivity() on every meaningful event
|
|
8
|
+
* (before_agent_start, before_tool_call, message_received, etc.).
|
|
9
|
+
* The updater calls isInactive() to check if enough idle time has passed.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Record that agent activity just occurred.
|
|
13
|
+
* Call this from hook handlers on every meaningful event.
|
|
14
|
+
*/
|
|
15
|
+
export declare function recordActivity(): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get the timestamp of the last recorded activity.
|
|
18
|
+
* Returns 0 if no activity has been recorded yet.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getLastActivityTs(): number;
|
|
21
|
+
/**
|
|
22
|
+
* Check whether the agent has been inactive for at least `thresholdMs`.
|
|
23
|
+
*
|
|
24
|
+
* Returns true if:
|
|
25
|
+
* - No activity has ever been recorded (lastActivityTs === 0), OR
|
|
26
|
+
* - The time since last activity exceeds the threshold.
|
|
27
|
+
*
|
|
28
|
+
* @param thresholdMs Minimum idle time in ms (default: 15 minutes)
|
|
29
|
+
*/
|
|
30
|
+
export declare function isInactive(thresholdMs?: number): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Reset the activity tracker state. Used for testing.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function _resetForTesting(): void;
|
|
36
|
+
//# sourceMappingURL=activity-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-tracker.d.ts","sourceRoot":"","sources":["../src/activity-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,WAAW,GAAE,MAA6B,GAAG,OAAO,CAG9E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Activity tracker — singleton module that records agent activity timestamps.
|
|
4
|
+
*
|
|
5
|
+
* Used by the auto-updater to defer gateway restarts until the agent is idle,
|
|
6
|
+
* preventing mid-conversation disruptions.
|
|
7
|
+
*
|
|
8
|
+
* Hook handlers call recordActivity() on every meaningful event
|
|
9
|
+
* (before_agent_start, before_tool_call, message_received, etc.).
|
|
10
|
+
* The updater calls isInactive() to check if enough idle time has passed.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.recordActivity = recordActivity;
|
|
14
|
+
exports.getLastActivityTs = getLastActivityTs;
|
|
15
|
+
exports.isInactive = isInactive;
|
|
16
|
+
exports._resetForTesting = _resetForTesting;
|
|
17
|
+
// Default inactivity threshold: 15 minutes
|
|
18
|
+
const DEFAULT_THRESHOLD_MS = 15 * 60 * 1000;
|
|
19
|
+
/** Module-level singleton timestamp of the last recorded activity. */
|
|
20
|
+
let lastActivityTs = 0;
|
|
21
|
+
/**
|
|
22
|
+
* Record that agent activity just occurred.
|
|
23
|
+
* Call this from hook handlers on every meaningful event.
|
|
24
|
+
*/
|
|
25
|
+
function recordActivity() {
|
|
26
|
+
lastActivityTs = Date.now();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the timestamp of the last recorded activity.
|
|
30
|
+
* Returns 0 if no activity has been recorded yet.
|
|
31
|
+
*/
|
|
32
|
+
function getLastActivityTs() {
|
|
33
|
+
return lastActivityTs;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check whether the agent has been inactive for at least `thresholdMs`.
|
|
37
|
+
*
|
|
38
|
+
* Returns true if:
|
|
39
|
+
* - No activity has ever been recorded (lastActivityTs === 0), OR
|
|
40
|
+
* - The time since last activity exceeds the threshold.
|
|
41
|
+
*
|
|
42
|
+
* @param thresholdMs Minimum idle time in ms (default: 15 minutes)
|
|
43
|
+
*/
|
|
44
|
+
function isInactive(thresholdMs = DEFAULT_THRESHOLD_MS) {
|
|
45
|
+
if (lastActivityTs === 0)
|
|
46
|
+
return true;
|
|
47
|
+
return Date.now() - lastActivityTs >= thresholdMs;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reset the activity tracker state. Used for testing.
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
function _resetForTesting() {
|
|
54
|
+
lastActivityTs = 0;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=activity-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-tracker.js","sourceRoot":"","sources":["../src/activity-tracker.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAYH,wCAEC;AAMD,8CAEC;AAWD,gCAGC;AAMD,4CAEC;AA1CD,2CAA2C;AAC3C,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE5C,sEAAsE;AACtE,IAAI,cAAc,GAAW,CAAC,CAAC;AAE/B;;;GAGG;AACH,SAAgB,cAAc;IAC5B,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,cAAsB,oBAAoB;IACnE,IAAI,cAAc,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,IAAI,WAAW,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB;IAC9B,cAAc,GAAG,CAAC,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth profile health monitor — reads OpenClaw auth profiles from disk,
|
|
3
|
+
* computes health status, and sends changes to the Podwatch dashboard.
|
|
4
|
+
*
|
|
5
|
+
* Status classification:
|
|
6
|
+
* healthy — no issues
|
|
7
|
+
* expiring_soon — token/oauth expires within 24h
|
|
8
|
+
* expired — token/oauth is past expiry
|
|
9
|
+
* cooldown — cooldownUntil is in the future
|
|
10
|
+
* disabled — disabledUntil is in the future
|
|
11
|
+
*/
|
|
12
|
+
export type AuthProfileStatus = "healthy" | "expiring_soon" | "expired" | "cooldown" | "disabled";
|
|
13
|
+
export interface AuthProfileHealth {
|
|
14
|
+
id: string;
|
|
15
|
+
provider: string;
|
|
16
|
+
authType: string;
|
|
17
|
+
status: AuthProfileStatus;
|
|
18
|
+
expiresAt?: string;
|
|
19
|
+
cooldownUntil?: string;
|
|
20
|
+
disabledUntil?: string;
|
|
21
|
+
disabledReason?: string;
|
|
22
|
+
errorCount?: number;
|
|
23
|
+
}
|
|
24
|
+
interface AuthProfileFile {
|
|
25
|
+
version?: number;
|
|
26
|
+
profiles?: Record<string, ProfileEntry>;
|
|
27
|
+
usageStats?: Record<string, UsageStatsEntry>;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
interface ProfileEntry {
|
|
31
|
+
type?: string;
|
|
32
|
+
provider?: string;
|
|
33
|
+
expires?: number | string;
|
|
34
|
+
expiresAt?: number | string;
|
|
35
|
+
disabledUntil?: number | string;
|
|
36
|
+
disabledReason?: string;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
interface UsageStatsEntry {
|
|
40
|
+
errorCount?: number;
|
|
41
|
+
cooldownUntil?: number | string;
|
|
42
|
+
disabledUntil?: number | string;
|
|
43
|
+
disabledReason?: string;
|
|
44
|
+
failureCounts?: Record<string, number>;
|
|
45
|
+
lastFailureAt?: number;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the OpenClaw state directory.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveStateDir(): string;
|
|
52
|
+
/**
|
|
53
|
+
* Find auth-profiles.json. Checks multiple known locations.
|
|
54
|
+
*/
|
|
55
|
+
export declare function findAuthProfilesPath(stateDir?: string): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* Read and parse the auth profiles file.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readAuthProfiles(filePath: string): AuthProfileFile | null;
|
|
60
|
+
/**
|
|
61
|
+
* Compute health status for a single auth profile.
|
|
62
|
+
*/
|
|
63
|
+
export declare function computeProfileHealth(id: string, profile: ProfileEntry, usageStats?: UsageStatsEntry, now?: number): AuthProfileHealth;
|
|
64
|
+
/**
|
|
65
|
+
* Compute health for all profiles in the file.
|
|
66
|
+
*/
|
|
67
|
+
export declare function computeAllProfileHealth(data: AuthProfileFile, now?: number): AuthProfileHealth[];
|
|
68
|
+
/**
|
|
69
|
+
* Check auth profiles and send changes to the dashboard.
|
|
70
|
+
* Returns the computed profiles (for testing).
|
|
71
|
+
*/
|
|
72
|
+
export declare function checkAuthHealth(stateDir?: string): AuthProfileHealth[];
|
|
73
|
+
/**
|
|
74
|
+
* Reset cached snapshot (for testing or re-init).
|
|
75
|
+
*/
|
|
76
|
+
export declare function resetAuthSnapshot(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Start periodic auth health monitoring.
|
|
79
|
+
*/
|
|
80
|
+
export declare function startAuthMonitor(intervalMs?: number, // 15 minutes
|
|
81
|
+
stateDir?: string, endpoint?: string, apiKey?: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Stop the periodic auth health monitor.
|
|
84
|
+
*/
|
|
85
|
+
export declare function stopAuthMonitor(): void;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=auth-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-monitor.d.ts","sourceRoot":"","sources":["../../src/hooks/auth-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,eAAe,GACf,SAAS,GACT,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,eAAe;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAqBD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAOxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAerE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CASzE;AAcD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,YAAY,EACrB,UAAU,CAAC,EAAE,eAAe,EAC5B,GAAG,CAAC,EAAE,MAAM,GACX,iBAAiB,CA0DnB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,eAAe,EACrB,GAAG,CAAC,EAAE,MAAM,GACX,iBAAiB,EAAE,CAcrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA+BtE;AAwCD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,GAAE,MAAgB,EAAE,aAAa;AAC3C,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAgBN;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAKtC"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auth profile health monitor — reads OpenClaw auth profiles from disk,
|
|
4
|
+
* computes health status, and sends changes to the Podwatch dashboard.
|
|
5
|
+
*
|
|
6
|
+
* Status classification:
|
|
7
|
+
* healthy — no issues
|
|
8
|
+
* expiring_soon — token/oauth expires within 24h
|
|
9
|
+
* expired — token/oauth is past expiry
|
|
10
|
+
* cooldown — cooldownUntil is in the future
|
|
11
|
+
* disabled — disabledUntil is in the future
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.resolveStateDir = resolveStateDir;
|
|
48
|
+
exports.findAuthProfilesPath = findAuthProfilesPath;
|
|
49
|
+
exports.readAuthProfiles = readAuthProfiles;
|
|
50
|
+
exports.computeProfileHealth = computeProfileHealth;
|
|
51
|
+
exports.computeAllProfileHealth = computeAllProfileHealth;
|
|
52
|
+
exports.checkAuthHealth = checkAuthHealth;
|
|
53
|
+
exports.resetAuthSnapshot = resetAuthSnapshot;
|
|
54
|
+
exports.startAuthMonitor = startAuthMonitor;
|
|
55
|
+
exports.stopAuthMonitor = stopAuthMonitor;
|
|
56
|
+
const fs = __importStar(require("node:fs"));
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
58
|
+
const os = __importStar(require("node:os"));
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Constants
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
const EXPIRY_WARNING_MS = 24 * 60 * 60 * 1_000; // 24 hours
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// State
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
let lastSnapshot = null;
|
|
67
|
+
let monitorTimer = null;
|
|
68
|
+
let configuredEndpoint = null;
|
|
69
|
+
let configuredApiKey = null;
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Core logic
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Resolve the OpenClaw state directory.
|
|
75
|
+
*/
|
|
76
|
+
function resolveStateDir() {
|
|
77
|
+
const override = process.env.OPENCLAW_STATE_DIR?.trim() ||
|
|
78
|
+
process.env.CLAWDBOT_STATE_DIR?.trim();
|
|
79
|
+
if (override)
|
|
80
|
+
return override;
|
|
81
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? os.homedir();
|
|
82
|
+
return path.join(home, ".openclaw");
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find auth-profiles.json. Checks multiple known locations.
|
|
86
|
+
*/
|
|
87
|
+
function findAuthProfilesPath(stateDir) {
|
|
88
|
+
const base = stateDir ?? resolveStateDir();
|
|
89
|
+
const candidates = [
|
|
90
|
+
path.join(base, "credentials", "auth-profiles.json"),
|
|
91
|
+
path.join(base, "agents", "main", "agent", "auth-profiles.json"),
|
|
92
|
+
];
|
|
93
|
+
for (const candidate of candidates) {
|
|
94
|
+
try {
|
|
95
|
+
fs.accessSync(candidate, fs.constants.R_OK);
|
|
96
|
+
return candidate;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Try next
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Read and parse the auth profiles file.
|
|
106
|
+
*/
|
|
107
|
+
function readAuthProfiles(filePath) {
|
|
108
|
+
try {
|
|
109
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
110
|
+
const parsed = JSON.parse(raw);
|
|
111
|
+
if (!parsed || typeof parsed !== "object")
|
|
112
|
+
return null;
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Parse a timestamp value that could be a number (epoch ms) or ISO string.
|
|
121
|
+
*/
|
|
122
|
+
function parseTimestamp(value) {
|
|
123
|
+
if (typeof value === "number" && value > 0)
|
|
124
|
+
return value;
|
|
125
|
+
if (typeof value === "string" && value.length > 0) {
|
|
126
|
+
const parsed = Date.parse(value);
|
|
127
|
+
if (!isNaN(parsed))
|
|
128
|
+
return parsed;
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Compute health status for a single auth profile.
|
|
134
|
+
*/
|
|
135
|
+
function computeProfileHealth(id, profile, usageStats, now) {
|
|
136
|
+
const currentTime = now ?? Date.now();
|
|
137
|
+
const provider = profile.provider ?? id.split(":")[0] ?? "unknown";
|
|
138
|
+
const authType = profile.type ?? "unknown";
|
|
139
|
+
const result = {
|
|
140
|
+
id,
|
|
141
|
+
provider,
|
|
142
|
+
authType,
|
|
143
|
+
status: "healthy",
|
|
144
|
+
};
|
|
145
|
+
// Check disabled status (from profile or usageStats)
|
|
146
|
+
const disabledUntilRaw = profile.disabledUntil ?? usageStats?.disabledUntil;
|
|
147
|
+
const disabledUntil = parseTimestamp(disabledUntilRaw);
|
|
148
|
+
if (disabledUntil !== null && disabledUntil > currentTime) {
|
|
149
|
+
result.status = "disabled";
|
|
150
|
+
result.disabledUntil = new Date(disabledUntil).toISOString();
|
|
151
|
+
result.disabledReason =
|
|
152
|
+
profile.disabledReason ?? usageStats?.disabledReason ?? undefined;
|
|
153
|
+
}
|
|
154
|
+
// Check cooldown (from usageStats)
|
|
155
|
+
const cooldownUntilRaw = usageStats?.cooldownUntil;
|
|
156
|
+
const cooldownUntil = parseTimestamp(cooldownUntilRaw);
|
|
157
|
+
if (cooldownUntil !== null &&
|
|
158
|
+
cooldownUntil > currentTime &&
|
|
159
|
+
result.status === "healthy") {
|
|
160
|
+
result.status = "cooldown";
|
|
161
|
+
result.cooldownUntil = new Date(cooldownUntil).toISOString();
|
|
162
|
+
}
|
|
163
|
+
// Check token/oauth expiry
|
|
164
|
+
const expiresRaw = profile.expires ?? profile.expiresAt;
|
|
165
|
+
const expiresAt = parseTimestamp(expiresRaw);
|
|
166
|
+
if (expiresAt !== null) {
|
|
167
|
+
result.expiresAt = new Date(expiresAt).toISOString();
|
|
168
|
+
if (expiresAt <= currentTime && result.status === "healthy") {
|
|
169
|
+
result.status = "expired";
|
|
170
|
+
}
|
|
171
|
+
else if (expiresAt <= currentTime + EXPIRY_WARNING_MS &&
|
|
172
|
+
result.status === "healthy") {
|
|
173
|
+
result.status = "expiring_soon";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Attach error count if present
|
|
177
|
+
const errorCount = usageStats?.errorCount;
|
|
178
|
+
if (typeof errorCount === "number" && errorCount > 0) {
|
|
179
|
+
result.errorCount = errorCount;
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Compute health for all profiles in the file.
|
|
185
|
+
*/
|
|
186
|
+
function computeAllProfileHealth(data, now) {
|
|
187
|
+
const profiles = data.profiles;
|
|
188
|
+
if (!profiles || typeof profiles !== "object")
|
|
189
|
+
return [];
|
|
190
|
+
const usageStats = data.usageStats ?? {};
|
|
191
|
+
const results = [];
|
|
192
|
+
for (const [id, profile] of Object.entries(profiles)) {
|
|
193
|
+
if (!profile || typeof profile !== "object")
|
|
194
|
+
continue;
|
|
195
|
+
const stats = usageStats[id];
|
|
196
|
+
results.push(computeProfileHealth(id, profile, stats, now));
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check auth profiles and send changes to the dashboard.
|
|
202
|
+
* Returns the computed profiles (for testing).
|
|
203
|
+
*/
|
|
204
|
+
function checkAuthHealth(stateDir) {
|
|
205
|
+
try {
|
|
206
|
+
const filePath = findAuthProfilesPath(stateDir);
|
|
207
|
+
if (!filePath)
|
|
208
|
+
return [];
|
|
209
|
+
const data = readAuthProfiles(filePath);
|
|
210
|
+
if (!data)
|
|
211
|
+
return [];
|
|
212
|
+
const profiles = computeAllProfileHealth(data);
|
|
213
|
+
if (profiles.length === 0)
|
|
214
|
+
return [];
|
|
215
|
+
// Compute snapshot for change detection
|
|
216
|
+
const snapshot = JSON.stringify(profiles);
|
|
217
|
+
if (snapshot === lastSnapshot) {
|
|
218
|
+
return profiles; // No changes
|
|
219
|
+
}
|
|
220
|
+
lastSnapshot = snapshot;
|
|
221
|
+
// Send auth_health directly to the dedicated endpoint
|
|
222
|
+
void sendAuthHealthToApi(profiles);
|
|
223
|
+
return profiles;
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
try {
|
|
227
|
+
console.error("[podwatch/auth-monitor] Error checking auth health:", err);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Swallow
|
|
231
|
+
}
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Send auth health data directly to the Podwatch API.
|
|
237
|
+
*/
|
|
238
|
+
async function sendAuthHealthToApi(profiles) {
|
|
239
|
+
if (!configuredEndpoint || !configuredApiKey)
|
|
240
|
+
return;
|
|
241
|
+
try {
|
|
242
|
+
const response = await fetch(`${configuredEndpoint}/auth-health`, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers: {
|
|
245
|
+
"Content-Type": "application/json",
|
|
246
|
+
Authorization: `Bearer ${configuredApiKey}`,
|
|
247
|
+
},
|
|
248
|
+
body: JSON.stringify({
|
|
249
|
+
type: "auth_health",
|
|
250
|
+
profiles: profiles.map((p) => ({
|
|
251
|
+
id: p.id,
|
|
252
|
+
provider: p.provider,
|
|
253
|
+
authType: p.authType,
|
|
254
|
+
status: p.status,
|
|
255
|
+
expiresAt: p.expiresAt,
|
|
256
|
+
cooldownUntil: p.cooldownUntil,
|
|
257
|
+
disabledUntil: p.disabledUntil,
|
|
258
|
+
disabledReason: p.disabledReason,
|
|
259
|
+
errorCount: p.errorCount,
|
|
260
|
+
})),
|
|
261
|
+
}),
|
|
262
|
+
signal: AbortSignal.timeout(10_000),
|
|
263
|
+
});
|
|
264
|
+
if (!response.ok) {
|
|
265
|
+
console.error(`[podwatch/auth-monitor] API ${response.status}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
console.error("[podwatch/auth-monitor] Failed to send auth health:", err);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Reset cached snapshot (for testing or re-init).
|
|
274
|
+
*/
|
|
275
|
+
function resetAuthSnapshot() {
|
|
276
|
+
lastSnapshot = null;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Start periodic auth health monitoring.
|
|
280
|
+
*/
|
|
281
|
+
function startAuthMonitor(intervalMs = 900_000, // 15 minutes
|
|
282
|
+
stateDir, endpoint, apiKey) {
|
|
283
|
+
stopAuthMonitor();
|
|
284
|
+
resetAuthSnapshot();
|
|
285
|
+
// Store API config for sending health data
|
|
286
|
+
configuredEndpoint = endpoint ?? null;
|
|
287
|
+
configuredApiKey = apiKey ?? null;
|
|
288
|
+
// Initial check
|
|
289
|
+
checkAuthHealth(stateDir);
|
|
290
|
+
// Periodic checks
|
|
291
|
+
monitorTimer = setInterval(() => checkAuthHealth(stateDir), intervalMs);
|
|
292
|
+
if (monitorTimer && typeof monitorTimer === "object" && "unref" in monitorTimer) {
|
|
293
|
+
monitorTimer.unref();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Stop the periodic auth health monitor.
|
|
298
|
+
*/
|
|
299
|
+
function stopAuthMonitor() {
|
|
300
|
+
if (monitorTimer) {
|
|
301
|
+
clearInterval(monitorTimer);
|
|
302
|
+
monitorTimer = null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=auth-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-monitor.js","sourceRoot":"","sources":["../../src/hooks/auth-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel connectivity monitor — queries the local gateway for channel
|
|
3
|
+
* runtime status, computes health, and sends changes to the Podwatch dashboard.
|
|
4
|
+
*
|
|
5
|
+
* Health classification:
|
|
6
|
+
* healthy — enabled, configured, running, recent messages
|
|
7
|
+
* degraded — running but no recent inbound/outbound (>30 min)
|
|
8
|
+
* down — not running, or not configured, or has errors
|
|
9
|
+
*
|
|
10
|
+
* Uses `openclaw gateway call channels.status` (no probe) for fast local data.
|
|
11
|
+
*/
|
|
12
|
+
export type ChannelHealthStatus = "healthy" | "degraded" | "down";
|
|
13
|
+
export interface ChannelHealth {
|
|
14
|
+
channelId: string;
|
|
15
|
+
accountId: string;
|
|
16
|
+
name: string;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
configured: boolean;
|
|
19
|
+
running: boolean;
|
|
20
|
+
mode: string | null;
|
|
21
|
+
lastInboundAt: string | null;
|
|
22
|
+
lastOutboundAt: string | null;
|
|
23
|
+
lastError: string | null;
|
|
24
|
+
status: ChannelHealthStatus;
|
|
25
|
+
warnings: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Raw shape returned by `openclaw gateway call channels.status`.
|
|
29
|
+
*/
|
|
30
|
+
interface GatewayChannelsStatusResponse {
|
|
31
|
+
ts: number;
|
|
32
|
+
channelOrder?: string[];
|
|
33
|
+
channelLabels?: Record<string, string>;
|
|
34
|
+
channels?: Record<string, ChannelSummary>;
|
|
35
|
+
channelAccounts?: Record<string, AccountSnapshot[]>;
|
|
36
|
+
channelDefaultAccountId?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
interface ChannelSummary {
|
|
39
|
+
configured?: boolean;
|
|
40
|
+
running?: boolean;
|
|
41
|
+
mode?: string;
|
|
42
|
+
lastStartAt?: number | null;
|
|
43
|
+
lastStopAt?: number | null;
|
|
44
|
+
lastError?: string | null;
|
|
45
|
+
lastProbeAt?: number | null;
|
|
46
|
+
tokenSource?: string;
|
|
47
|
+
}
|
|
48
|
+
interface AccountSnapshot {
|
|
49
|
+
accountId: string;
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
configured?: boolean;
|
|
52
|
+
running?: boolean;
|
|
53
|
+
mode?: string;
|
|
54
|
+
lastStartAt?: number | null;
|
|
55
|
+
lastStopAt?: number | null;
|
|
56
|
+
lastError?: string | null;
|
|
57
|
+
lastInboundAt?: number | null;
|
|
58
|
+
lastOutboundAt?: number | null;
|
|
59
|
+
tokenSource?: string;
|
|
60
|
+
allowUnmentionedGroups?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fetch channel status from the local gateway via CLI.
|
|
64
|
+
*/
|
|
65
|
+
export declare function fetchChannelStatus(): Promise<GatewayChannelsStatusResponse | null>;
|
|
66
|
+
/**
|
|
67
|
+
* Compute health status for a single channel account.
|
|
68
|
+
*/
|
|
69
|
+
export declare function computeChannelHealth(channelId: string, label: string, account: AccountSnapshot, now?: number): ChannelHealth;
|
|
70
|
+
/**
|
|
71
|
+
* Build channel health list from gateway response.
|
|
72
|
+
*/
|
|
73
|
+
export declare function buildChannelHealthList(response: GatewayChannelsStatusResponse, now?: number): ChannelHealth[];
|
|
74
|
+
/**
|
|
75
|
+
* Check channel health and send changes to the dashboard.
|
|
76
|
+
* Returns the computed channels (for testing).
|
|
77
|
+
*/
|
|
78
|
+
export declare function checkChannelHealth(): Promise<ChannelHealth[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Send channel health data to the Podwatch API.
|
|
81
|
+
*/
|
|
82
|
+
export declare function sendChannelHealthToApi(channels: ChannelHealth[]): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Start the channel health monitor.
|
|
85
|
+
*/
|
|
86
|
+
export declare function startChannelMonitor(intervalMs: number, stateDir?: string, endpoint?: string, apiKey?: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Stop the channel health monitor.
|
|
89
|
+
*/
|
|
90
|
+
export declare function stopChannelMonitor(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Reset cached snapshot (for testing).
|
|
93
|
+
*/
|
|
94
|
+
export declare function _resetChannelMonitorState(): void;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=channel-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-monitor.d.ts","sourceRoot":"","sources":["../../src/hooks/channel-monitor.ts"],"names":[],"mappings":"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"}
|