claw-dashboard 1.9.0 → 2.0.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.
Files changed (135) hide show
  1. package/.c8rc.json +38 -0
  2. package/.dockerignore +68 -0
  3. package/.github/dependabot.yml +45 -0
  4. package/.github/pull_request_template.md +39 -0
  5. package/.github/workflows/ci.yml +147 -0
  6. package/.github/workflows/release.yml +40 -0
  7. package/.github/workflows/security.yml +84 -0
  8. package/.husky/pre-commit +1 -0
  9. package/.planning/codebase/ARCHITECTURE.md +206 -0
  10. package/.planning/codebase/INTEGRATIONS.md +150 -0
  11. package/.planning/codebase/STACK.md +122 -0
  12. package/.planning/codebase/STRUCTURE.md +201 -0
  13. package/CHANGELOG.md +293 -0
  14. package/CONTRIBUTING.md +378 -0
  15. package/Dockerfile +54 -0
  16. package/FEATURES.md +195 -21
  17. package/README.md +83 -6
  18. package/TODO.md +28 -0
  19. package/build-cjs.js +127 -0
  20. package/cjs-shim.js +13 -0
  21. package/dist/clawdash +1729 -0
  22. package/dist/clawdash.meta.json +2236 -0
  23. package/dist/widgets.cjs +6511 -0
  24. package/docker-compose.yml +67 -0
  25. package/docs/API.md +1050 -0
  26. package/docs/PLUGINS.md +1504 -0
  27. package/esbuild.config.js +158 -0
  28. package/eslint.config.js +56 -0
  29. package/examples/plugins/README.md +122 -0
  30. package/examples/plugins/api-status/index.js +294 -0
  31. package/examples/plugins/api-status/plugin.json +19 -0
  32. package/examples/plugins/hello-world/index.js +104 -0
  33. package/examples/plugins/hello-world/plugin.json +15 -0
  34. package/examples/plugins/system-metrics-chart/index.js +339 -0
  35. package/examples/plugins/system-metrics-chart/plugin.json +18 -0
  36. package/examples/plugins/weather-widget/index.js +136 -0
  37. package/examples/plugins/weather-widget/plugin.json +19 -0
  38. package/index.cjs +23005 -0
  39. package/index.js +5236 -566
  40. package/jest.config.js +11 -0
  41. package/man/clawdash.1 +276 -0
  42. package/package.json +54 -5
  43. package/schemas/plugin-manifest.json +128 -0
  44. package/scripts/release.js +595 -0
  45. package/src/alerts.js +693 -0
  46. package/src/auto-save.js +584 -0
  47. package/src/cache.js +390 -0
  48. package/src/checksum.js +146 -0
  49. package/src/cli/args.js +110 -0
  50. package/src/cli/export-schedule.js +423 -0
  51. package/src/cli/export-snapshot.js +138 -0
  52. package/src/cli/help.js +69 -0
  53. package/src/cli/import-snapshot.js +230 -0
  54. package/src/cli/index.js +14 -0
  55. package/src/cli/list-templates.js +69 -0
  56. package/src/cli/validate-config.js +76 -0
  57. package/src/cli/validate-plugin.js +187 -0
  58. package/src/cli/version.js +15 -0
  59. package/src/config-validator.js +586 -0
  60. package/src/config-watcher.js +401 -0
  61. package/src/config.js +684 -0
  62. package/src/container-detector.js +499 -0
  63. package/src/database.js +734 -0
  64. package/src/differential-render.js +327 -0
  65. package/src/errors.js +169 -0
  66. package/src/export-scheduler.js +581 -0
  67. package/src/gateway-manager.js +685 -0
  68. package/src/hints.js +371 -0
  69. package/src/loading-states.js +509 -0
  70. package/src/logger.js +185 -0
  71. package/src/memory-pressure.js +467 -0
  72. package/src/performance-monitor.js +374 -0
  73. package/src/plugin-errors.js +586 -0
  74. package/src/plugin-manifest-validator.js +219 -0
  75. package/src/plugin-reload.js +481 -0
  76. package/src/plugin-scaffold.js +1941 -0
  77. package/src/plugin-validator.js +284 -0
  78. package/src/retry.js +218 -0
  79. package/src/security.js +860 -0
  80. package/src/snapshot.js +372 -0
  81. package/src/splash.js +115 -0
  82. package/src/theme-selector.js +411 -0
  83. package/src/themes.js +874 -0
  84. package/src/transitions.js +534 -0
  85. package/src/types.d.ts +174 -0
  86. package/src/validation.js +926 -0
  87. package/src/web-server.js +885 -0
  88. package/src/widgets/builtin-widgets.js +1057 -0
  89. package/src/widgets/config-processor.js +401 -0
  90. package/src/widgets/dependency-resolver.js +596 -0
  91. package/src/widgets/index.js +79 -0
  92. package/src/widgets/plugin-api.js +845 -0
  93. package/src/widgets/widget-error-boundary.js +773 -0
  94. package/src/widgets/widget-error-isolation.js +551 -0
  95. package/src/widgets/widget-loader.js +1437 -0
  96. package/src/workers/system-worker.js +130 -0
  97. package/src/workers/worker-pool.js +633 -0
  98. package/tests/alerts.test.js +437 -0
  99. package/tests/auto-save.test.js +529 -0
  100. package/tests/cache.test.js +317 -0
  101. package/tests/cli.test.js +351 -0
  102. package/tests/command-palette.test.js +320 -0
  103. package/tests/config-processor.test.js +452 -0
  104. package/tests/config-validator.test.js +710 -0
  105. package/tests/config-watcher.test.js +594 -0
  106. package/tests/config.test.js +755 -0
  107. package/tests/database.test.js +438 -0
  108. package/tests/errors.test.js +189 -0
  109. package/tests/example-plugins.test.js +624 -0
  110. package/tests/integration.test.js +1321 -0
  111. package/tests/loading-states.test.js +300 -0
  112. package/tests/manifest-validation-on-load.test.js +671 -0
  113. package/tests/performance-monitor.test.js +190 -0
  114. package/tests/plugin-api-rate-limit.test.js +302 -0
  115. package/tests/plugin-errors.test.js +311 -0
  116. package/tests/plugin-lifecycle-e2e.test.js +1036 -0
  117. package/tests/plugin-reload.test.js +764 -0
  118. package/tests/rate-limiter.test.js +539 -0
  119. package/tests/retry.test.js +308 -0
  120. package/tests/security.test.js +411 -0
  121. package/tests/settings-modal.test.js +226 -0
  122. package/tests/theme-selector.test.js +57 -0
  123. package/tests/utils.js +242 -0
  124. package/tests/utils.test.js +317 -0
  125. package/tests/validate-plugin-cli.test.js +359 -0
  126. package/tests/validation.test.js +837 -0
  127. package/tests/web-server.test.js +646 -0
  128. package/tests/widget-arrange-mode.test.js +183 -0
  129. package/tests/widget-config-hot-reload.test.js +465 -0
  130. package/tests/widget-dependency.test.js +591 -0
  131. package/tests/widget-error-boundary.test.js +749 -0
  132. package/tests/widget-error-isolation.test.js +469 -0
  133. package/tests/widget-integration.test.js +1147 -0
  134. package/tests/widget-refresh-intervals.test.js +284 -0
  135. package/tests/worker-pool.test.js +522 -0
package/src/config.js ADDED
@@ -0,0 +1,684 @@
1
+ /**
2
+ * Centralized configuration file for Claw Dashboard
3
+ * Contains all magic numbers, constants, and configurable values
4
+ */
5
+
6
+ import os from 'os';
7
+ import fs from 'fs';
8
+ import { fileURLToPath } from 'url';
9
+ import { dirname, join } from 'path';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+
14
+ // Load dashboard version from package.json
15
+ let DASHBOARD_VERSION = 'unknown';
16
+ try {
17
+ const pkg = JSON.parse(fs.readFileSync(join(__dirname, '../package.json'), 'utf8'));
18
+ DASHBOARD_VERSION = pkg.version || 'unknown';
19
+ } catch {}
20
+
21
+ export { DASHBOARD_VERSION };
22
+
23
+ // ============================================================================
24
+ // REFRESH & TIMING SETTINGS
25
+ // ============================================================================
26
+
27
+ export const REFRESH_INTERVALS = {
28
+ DEFAULT: 2000,
29
+ ACTIVE: 2000, // 2 seconds when agents active
30
+ IDLE: 10000, // 10 seconds when idle (no active agents)
31
+ OPTIONS: [1000, 2000, 5000, 10000], // Available refresh interval options
32
+ };
33
+
34
+ export const IDLE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes to consider session idle
35
+
36
+ // ============================================================================
37
+ // HISTORY & DISPLAY LIMITS
38
+ // ============================================================================
39
+
40
+ export const HISTORY = {
41
+ LENGTH: 60, // Default history length for charts
42
+ NETWORK_LENGTH: 30, // Network history length
43
+ };
44
+
45
+ // ============================================================================
46
+ // GATEWAY CONFIGURATION
47
+ // ============================================================================
48
+
49
+ export const GATEWAY = {
50
+ DEFAULT_PORT: 18789,
51
+ TIMEOUT_MS: 3000,
52
+ MAX_ENDPOINTS: 10, // Maximum number of gateway endpoints
53
+ DEFAULT_ENDPOINT_NAME: 'local', // Default name for local gateway
54
+ };
55
+
56
+ // Default gateway endpoint configuration
57
+ export const DEFAULT_GATEWAY_ENDPOINT = {
58
+ name: 'local',
59
+ host: 'localhost',
60
+ port: 18789,
61
+ token: null,
62
+ enabled: true,
63
+ type: 'local', // 'local', 'remote', 'cloud'
64
+ };
65
+
66
+ // ============================================================================
67
+ // UI DIMENSIONS & DEFAULTS
68
+ // ============================================================================
69
+
70
+ export const UI = {
71
+ GAUGE_WIDTH: 15,
72
+ SPARKLINE_WIDTH: 15,
73
+ LOG_BOX_MIN_HEIGHT: 10,
74
+ DEFAULT_WIDTH: 80,
75
+ DEFAULT_HEIGHT: 24,
76
+ };
77
+
78
+ // ============================================================================
79
+ // CACHE TTL SETTINGS (in milliseconds)
80
+ // ============================================================================
81
+
82
+ export const CACHE_TTL = {
83
+ CPU: 1000, // 1 second TTL for CPU
84
+ MEMORY: 1000, // 1 second TTL for memory
85
+ GPU: 5000, // 5 second TTL for GPU (expensive)
86
+ NETWORK: 5000, // 5 second TTL for network (was 1s, causes timeouts)
87
+ DISK: 60000, // 60 second TTL for disk (rarely changes)
88
+ SYSTEM: 3600000, // 1 HOUR TTL for system info (OS version rarely changes!)
89
+ CONTAINER: 300000, // 5 minute TTL for container detection
90
+ DEFAULT: 2000, // Default TTL fallback
91
+ };
92
+
93
+ // Cache configuration object (for direct use)
94
+ export const CACHE_CONFIG = {
95
+ cpu: { ttl: CACHE_TTL.CPU },
96
+ memory: { ttl: CACHE_TTL.MEMORY },
97
+ gpu: { ttl: CACHE_TTL.GPU },
98
+ network: { ttl: CACHE_TTL.NETWORK },
99
+ disk: { ttl: CACHE_TTL.DISK },
100
+ system: { ttl: CACHE_TTL.SYSTEM },
101
+ container: { ttl: CACHE_TTL.CONTAINER },
102
+ };
103
+
104
+ // ============================================================================
105
+ // DATABASE SETTINGS
106
+ // ============================================================================
107
+
108
+ export const DATABASE = {
109
+ PATH: os.homedir() + '/.openclaw/dashboard-history.db',
110
+ SAVE_INTERVAL_MS: 30000, // Save every 30 seconds
111
+ CLEANUP_INTERVAL_MS: 60 * 60 * 1000, // Cleanup every hour
112
+ DEFAULT_RETENTION_DAYS: 30,
113
+ };
114
+
115
+ // ============================================================================
116
+ // CHECKSUM VERIFICATION SETTINGS
117
+ // ============================================================================
118
+
119
+ export const CHECKSUM = {
120
+ ENABLED: true, // Enable checksum verification by default
121
+ ALGORITHM: 'sha256', // Hash algorithm: sha256, sha512, md5
122
+ HEADER_NAME: 'x-response-checksum', // HTTP header containing the checksum
123
+ STRICT_MODE: false, // If true, reject responses without checksums
124
+ MAX_AGE_MS: 300000, // Maximum age of checksum (5 minutes)
125
+ };
126
+
127
+ // ============================================================================
128
+ // RETRY SETTINGS
129
+ // ============================================================================
130
+
131
+ export const RETRY = {
132
+ DEFAULT_MAX_RETRIES: 3,
133
+ DEFAULT_INITIAL_DELAY: 1000, // 1 second
134
+ DEFAULT_MAX_DELAY: 10000, // 10 seconds
135
+ DEFAULT_BACKOFF_MULTIPLIER: 2,
136
+ TIMEOUT: 30000, // Max time to keep retrying
137
+ INTERVAL: 1000, // Time between retries
138
+ JITTER_FACTOR: 0.1, // ±10% jitter
139
+ RETRYABLE_STATUSES: [408, 429, 500, 502, 503, 504],
140
+ RETRYABLE_ERRORS: [
141
+ 'ECONNREFUSED',
142
+ 'ETIMEDOUT',
143
+ 'ENOTFOUND',
144
+ 'EAI_AGAIN',
145
+ 'ECONNRESET',
146
+ 'EPIPE'
147
+ ],
148
+ };
149
+
150
+ // Retry configuration object (for direct use)
151
+ export const DEFAULT_RETRY_OPTIONS = {
152
+ maxRetries: RETRY.DEFAULT_MAX_RETRIES,
153
+ initialDelay: RETRY.DEFAULT_INITIAL_DELAY,
154
+ maxDelay: RETRY.DEFAULT_MAX_DELAY,
155
+ backoffMultiplier: RETRY.DEFAULT_BACKOFF_MULTIPLIER,
156
+ retryableStatuses: RETRY.RETRYABLE_STATUSES,
157
+ retryableErrors: RETRY.RETRYABLE_ERRORS,
158
+ };
159
+
160
+ // ============================================================================
161
+ // AUTO-RETRY SETTINGS (Gateway connectivity)
162
+ // ============================================================================
163
+
164
+ export const AUTO_RETRY = {
165
+ ENABLED: true, // Enable auto-retry by default
166
+ DEFAULT_INTERVAL_MS: 30000, // Default: 30 seconds between auto-retries
167
+ MIN_INTERVAL_MS: 5000, // Minimum: 5 seconds (prevent hammering)
168
+ MAX_INTERVAL_MS: 300000, // Maximum: 5 minutes
169
+ EXPONENTIAL_BACKOFF: true, // Enable exponential backoff for consecutive failures
170
+ BACKOFF_MULTIPLIER: 2, // Multiply interval by this after each failure
171
+ MAX_BACKOFF_INTERVAL_MS: 300000, // Cap backoff at 5 minutes
172
+ RESET_AFTER_SUCCESS: true, // Reset backoff after successful connection
173
+ CONSECUTIVE_FAILURE_THRESHOLD: 3, // Number of failures before applying backoff
174
+ };
175
+
176
+ // ============================================================================
177
+ // ALERT THRESHOLDS
178
+ // ============================================================================
179
+
180
+ export const ALERT_THRESHOLDS = {
181
+ CPU: { warning: 70, critical: 90 },
182
+ MEMORY: { warning: 75, critical: 90 },
183
+ DISK: { warning: 80, critical: 95 },
184
+ };
185
+
186
+ // Alert rate limiting
187
+ export const ALERT_RATE_LIMIT = {
188
+ ENABLED: true,
189
+ WINDOW_MS: 60000, // 1 minute window
190
+ MAX_ALERTS: 5, // Max alerts per window per type
191
+ };
192
+
193
+ // Alert history limit
194
+ export const MAX_ALERT_HISTORY = 100;
195
+
196
+ // ============================================================================
197
+ // MEMORY PRESSURE DETECTION SETTINGS
198
+ // ============================================================================
199
+
200
+ export const MEMORY_PRESSURE = {
201
+ // Thresholds for memory pressure detection (applies to dashboard process itself)
202
+ THRESHOLDS: {
203
+ WARNING_MB: 512, // Warning when heap reaches 512MB
204
+ CRITICAL_MB: 1024, // Critical when heap reaches 1GB
205
+ EMERGENCY_MB: 1536, // Emergency when heap reaches 1.5GB
206
+ },
207
+ // Trend detection settings
208
+ TREND: {
209
+ SAMPLE_COUNT: 10, // Number of samples to analyze for trend
210
+ GROWTH_THRESHOLD_MB: 50, // Minimum MB growth to consider a trend
211
+ TIME_WINDOW_MS: 60000, // 1 minute window for trend analysis
212
+ },
213
+ // Sustained pressure detection
214
+ SUSTAINED: {
215
+ DURATION_MS: 120000, // 2 minutes of high memory to trigger sustained alert
216
+ CHECK_INTERVAL_MS: 10000, // Check every 10 seconds
217
+ },
218
+ // Actions
219
+ ACTIONS: {
220
+ // Automatically clear old performance history when memory is high
221
+ AUTO_CLEAR_HISTORY: true,
222
+ // Request garbage collection hint (if available)
223
+ REQUEST_GC: true,
224
+ },
225
+ };
226
+
227
+ // ============================================================================
228
+ // VALIDATION CONSTRAINTS
229
+ // ============================================================================
230
+
231
+ export const VALIDATION = {
232
+ REFRESH_INTERVAL: {
233
+ MIN: 500,
234
+ MAX: 60000,
235
+ },
236
+ VALID_THEMES: ['default', 'dark', 'high-contrast', 'ocean', 'auto'],
237
+ VALID_SORT_MODES: ['time', 'tokens', 'idle', 'name'],
238
+ VALID_LOG_LEVELS: ['all', 'error', 'warn', 'info', 'debug'],
239
+ VALID_EXPORT_FORMATS: ['json', 'csv'],
240
+ VALID_ENDPOINT_TYPES: ['local', 'remote', 'cloud'],
241
+ ENDPOINT_NAME: {
242
+ MIN_LENGTH: 1,
243
+ MAX_LENGTH: 32,
244
+ PATTERN: /^[a-zA-Z0-9_-]+$/,
245
+ },
246
+ AUTO_RETRY: {
247
+ INTERVAL_MS: {
248
+ MIN: 5000, // Minimum 5 seconds
249
+ MAX: 300000, // Maximum 5 minutes
250
+ },
251
+ BACKOFF_MULTIPLIER: {
252
+ MIN: 1,
253
+ MAX: 10,
254
+ },
255
+ MAX_BACKOFF_INTERVAL_MS: {
256
+ MIN: 10000, // Minimum 10 seconds
257
+ MAX: 600000, // Maximum 10 minutes
258
+ },
259
+ CONSECUTIVE_FAILURE_THRESHOLD: {
260
+ MIN: 1,
261
+ MAX: 10,
262
+ },
263
+ },
264
+ };
265
+
266
+ // ============================================================================
267
+ // COMMAND TIMEOUTS (in milliseconds)
268
+ // ============================================================================
269
+
270
+ export const COMMAND_TIMEOUTS = {
271
+ LAUNCHCTL: 2000,
272
+ PS: 2000,
273
+ SYSTEM_PROFILER: 5000,
274
+ IOREG: 3000,
275
+ POWERMETRICS: 3000,
276
+ OPENCLAW_VERSION: 3000,
277
+ OPENCLAW_LOGS: 5000,
278
+ NVIDIA_SMI: 3000,
279
+ LSPCI: 3000,
280
+ RADEONTOP: 3000,
281
+ POWERSHELL: 5000, // Windows PowerShell WMI queries
282
+ WSL_SMI: 5000, // WSL2 nvidia-smi.exe via Windows host
283
+ };
284
+
285
+ // ============================================================================
286
+ // WORKER THREAD SETTINGS
287
+ // ============================================================================
288
+
289
+ export const WORKERS = {
290
+ ENABLED: true, // Enable worker threads for heavy operations
291
+ MAX_WORKERS: 2, // Number of worker threads to spawn
292
+ TASK_TIMEOUT: 10000, // Task timeout in milliseconds (10 seconds)
293
+ FALLBACK_ON_ERROR: true, // Fall back to direct execution if workers fail
294
+ };
295
+
296
+ // ============================================================================
297
+ // GRACEFUL DEGRADATION SETTINGS (Worker Pool Overload Handling)
298
+ // ============================================================================
299
+
300
+ export const WORKER_DEGRADATION = {
301
+ // Queue size thresholds
302
+ QUEUE: {
303
+ WARNING_SIZE: 10, // Warn when queue reaches this size
304
+ CRITICAL_SIZE: 25, // Critical when queue reaches this size
305
+ MAX_SIZE: 50, // Max queue size before rejecting tasks
306
+ },
307
+ // Worker utilization thresholds (percentage)
308
+ UTILIZATION: {
309
+ WARNING_PCT: 75, // Warning when utilization exceeds this
310
+ CRITICAL_PCT: 90, // Critical when utilization exceeds this
311
+ },
312
+ // Degradation strategies
313
+ STRATEGIES: {
314
+ // Increase timeout during overload (multiplier)
315
+ ADAPTIVE_TIMEOUT: {
316
+ ENABLED: true,
317
+ WARNING_MULTIPLIER: 1.5, // 1.5x timeout at warning level
318
+ CRITICAL_MULTIPLIER: 2.0, // 2x timeout at critical level
319
+ },
320
+ // Shed load by rejecting non-critical tasks
321
+ SHED_LOAD: {
322
+ ENABLED: true,
323
+ SHED_NON_CRITICAL: true, // Reject non-critical tasks when overloaded
324
+ },
325
+ // Circuit breaker for repeated failures
326
+ CIRCUIT_BREAKER: {
327
+ ENABLED: true,
328
+ FAILURE_THRESHOLD: 5, // Open circuit after N consecutive failures
329
+ RESET_TIMEOUT_MS: 30000, // Try to close circuit after 30s
330
+ },
331
+ },
332
+ // Recovery settings
333
+ RECOVERY: {
334
+ COOLDOWN_MS: 5000, // Time before lowering degradation level
335
+ MIN_NORMAL_OPERATIONS: 5, // Successful ops before marking healthy
336
+ },
337
+ };
338
+
339
+ // ============================================================================
340
+ // WORKER POOL OVERLOAD SETTINGS
341
+ // ============================================================================
342
+
343
+ export const WORKER_OVERLOAD = {
344
+ // Queue size thresholds
345
+ QUEUE: {
346
+ WARNING_SIZE: 10, // Warning when queue reaches this size
347
+ CRITICAL_SIZE: 25, // Critical when queue reaches this size
348
+ MAX_SIZE: 50, // Maximum queue size (reject new tasks when exceeded)
349
+ },
350
+ // Degradation levels
351
+ DEGRADATION: {
352
+ NONE: 'none',
353
+ PARTIAL: 'partial', // Queue warning threshold exceeded
354
+ SEVERE: 'severe', // Queue critical threshold exceeded
355
+ CRITICAL: 'critical', // Queue max threshold exceeded
356
+ },
357
+ // Adaptive timeout settings
358
+ TIMEOUTS: {
359
+ // Extend timeouts as degradation increases
360
+ PARTIAL_MULTIPLIER: 1.2, // 20% longer timeouts
361
+ SEVERE_MULTIPLIER: 1.5, // 50% longer timeouts
362
+ CRITICAL_MULTIPLIER: 2.0, // 100% longer timeouts (double)
363
+ },
364
+ // Recovery settings
365
+ RECOVERY: {
366
+ COOL_DOWN_MS: 5000, // Time before attempting to recover from overload
367
+ CHECK_INTERVAL_MS: 1000, // How often to check for recovery
368
+ MIN_HEALTHY_CHECKS: 3, // Number of healthy checks before full recovery
369
+ },
370
+ };
371
+
372
+ // ============================================================================
373
+ // WEB INTERFACE SETTINGS
374
+ // ============================================================================
375
+
376
+ export const WEB = {
377
+ DEFAULT_PORT: 18790, // Default port for web interface
378
+ HOST: '0.0.0.0', // Bind to all interfaces by default
379
+ CORS_ORIGIN: '*', // CORS origin (restrict in production)
380
+ REQUEST_TIMEOUT: 30000, // Request timeout in milliseconds
381
+ REFRESH_CACHE_MS: 2000, // Cache data for 2 seconds
382
+ ENDPOINTS: {
383
+ HEALTH: '/health', // Health check endpoint
384
+ METRICS: '/metrics', // System metrics endpoint
385
+ SESSIONS: '/sessions', // Sessions list endpoint
386
+ AGENTS: '/agents', // Agents list endpoint
387
+ LOGS: '/logs', // Logs endpoint
388
+ STATUS: '/status', // Full dashboard status endpoint
389
+ },
390
+ // Rate limiting configuration
391
+ RATE_LIMIT: {
392
+ ENABLED: true, // Enable rate limiting by default
393
+ WINDOW_MS: 60000, // Time window in milliseconds (1 minute)
394
+ MAX_REQUESTS: 100, // Max requests per IP per window
395
+ TRUST_PROXY: false, // Trust X-Forwarded-For header (set true behind reverse proxy)
396
+ },
397
+ // CORS configuration
398
+ CORS: {
399
+ // Production: specify allowed origins as array (e.g., ['https://example.com'])
400
+ // Development: use '*' to allow all origins
401
+ ALLOWED_ORIGINS: '*', // Default to allow all (restrict in production)
402
+ ALLOWED_METHODS: ['GET', 'POST', 'OPTIONS'],
403
+ ALLOWED_HEADERS: ['Content-Type', 'Authorization'],
404
+ CREDENTIALS: false, // Allow cookies/credentials
405
+ MAX_AGE: 86400, // Preflight cache duration (24 hours)
406
+ },
407
+ // Authentication configuration
408
+ AUTH: {
409
+ ENABLED: false, // Disabled by default (enable explicitly)
410
+ HEADER_NAME: 'Authorization', // HTTP header for API key
411
+ SCHEME: 'Bearer', // Auth scheme (Bearer, ApiKey, etc.)
412
+ KEY_PREFIX: 'cd_', // Prefix for auto-generated API keys
413
+ KEY_LENGTH: 32, // Length of random API key
414
+ KEY_PATTERN: /^cd_[a-zA-Z0-9]{32}$/, // Pattern for valid keys
415
+ MAX_KEYS: 10, // Maximum number of API keys allowed
416
+ KEY_NAME_MIN_LENGTH: 1, // Minimum length for key name
417
+ KEY_NAME_MAX_LENGTH: 64, // Maximum length for key name
418
+ },
419
+ };
420
+
421
+ // ============================================================================
422
+ // WIDGET SETTINGS
423
+ // ============================================================================
424
+
425
+ export const WIDGETS = {
426
+ ENABLED: true, // Enable widget lazy loading
427
+ AUTO_DISCOVER: true, // Auto-discover plugins in plugins directory
428
+ PRELOAD_PRIORITY: ['cpu', 'memory', 'gpu'], // Widgets to preload immediately
429
+ LAZY_LOAD_DELAY: 500, // Delay before loading non-priority widgets (ms)
430
+ MAX_CONCURRENT_LOADS: 3, // Maximum concurrent widget loads
431
+ FALLBACK_ON_ERROR: true, // Fall back to default widgets if loading fails
432
+ CACHE_TTL: 60000, // Widget data cache TTL (ms)
433
+ BUILTIN: {
434
+ cpu: { priority: 10, lazyLoad: false },
435
+ memory: { priority: 20, lazyLoad: false },
436
+ gpu: { priority: 30, lazyLoad: false },
437
+ network: { priority: 40, lazyLoad: true },
438
+ disk: { priority: 50, lazyLoad: true },
439
+ system: { priority: 60, lazyLoad: true },
440
+ uptime: { priority: 70, lazyLoad: true },
441
+ dataHealth: { priority: 80, lazyLoad: true },
442
+ },
443
+ };
444
+
445
+ // ============================================================================
446
+ // WIDGET REFRESH INTERVAL SETTINGS
447
+ // ============================================================================
448
+
449
+ export const WIDGET_REFRESH_INTERVALS = {
450
+ // Per-widget refresh intervals (in milliseconds)
451
+ // null = use global refresh interval
452
+ DEFAULT: null, // Default: use global interval
453
+ CPU: 1000, // CPU updates frequently (1 second)
454
+ MEMORY: 1000, // Memory updates frequently (1 second)
455
+ GPU: 5000, // GPU is expensive to query (5 seconds)
456
+ NETWORK: 1000, // Network updates frequently (1 second)
457
+ DISK: 30000, // Disk rarely changes (30 seconds)
458
+ SYSTEM: 5000, // System info changes occasionally (5 seconds)
459
+ UPTIME: 60000, // Uptime only changes every minute (60 seconds)
460
+ DATA_HEALTH: 10000, // Data health checks every 10 seconds
461
+ };
462
+
463
+ // Widget size presets
464
+ export const WIDGET_SIZE_PRESETS = {
465
+ SMALL: 'small',
466
+ MEDIUM: 'medium',
467
+ LARGE: 'large',
468
+ WIDE: 'wide',
469
+ };
470
+
471
+ // Default widget sizes by type (in rows)
472
+ export const WIDGET_SIZES = {
473
+ [WIDGET_SIZE_PRESETS.SMALL]: 3,
474
+ [WIDGET_SIZE_PRESETS.MEDIUM]: 5,
475
+ [WIDGET_SIZE_PRESETS.LARGE]: 8,
476
+ [WIDGET_SIZE_PRESETS.WIDE]: 5, // Wide uses medium height by default
477
+ };
478
+
479
+ // Default widget size for each built-in widget
480
+ export const WIDGET_DEFAULT_SIZES = {
481
+ cpu: WIDGET_SIZE_PRESETS.MEDIUM,
482
+ mem: WIDGET_SIZE_PRESETS.MEDIUM,
483
+ gpu: WIDGET_SIZE_PRESETS.MEDIUM,
484
+ net: WIDGET_SIZE_PRESETS.MEDIUM,
485
+ disk: WIDGET_SIZE_PRESETS.MEDIUM,
486
+ sys: WIDGET_SIZE_PRESETS.MEDIUM,
487
+ uptime: WIDGET_SIZE_PRESETS.MEDIUM,
488
+ health: WIDGET_SIZE_PRESETS.MEDIUM,
489
+ gateway: WIDGET_SIZE_PRESETS.MEDIUM,
490
+ };
491
+
492
+ // Widget refresh validation constraints
493
+ export const WIDGET_REFRESH_VALIDATION = {
494
+ MIN_INTERVAL: 500, // Minimum 500ms between refreshes
495
+ MAX_INTERVAL: 60000, // Maximum 60 seconds between refreshes
496
+ ALLOWED_CUSTOM_INTERVALS: [500, 1000, 2000, 5000, 10000, 30000, 60000],
497
+ };
498
+
499
+ // Graceful degradation settings for widgets under worker pool overload
500
+ export const WIDGET_DEGRADATION = {
501
+ // When degradation level is WARNING
502
+ WARNING: {
503
+ SKIP_NON_CRITICAL: false, // Don't skip updates, just extend intervals
504
+ EXTEND_INTERVAL_MULTIPLIER: 1.5, // 1.5x refresh intervals
505
+ PRIORITY_THRESHOLD: 50, // Only update widgets with priority <= 50
506
+ },
507
+ // When degradation level is CRITICAL
508
+ CRITICAL: {
509
+ SKIP_NON_CRITICAL: true, // Skip non-critical widgets
510
+ EXTEND_INTERVAL_MULTIPLIER: 2.0, // 2x refresh intervals
511
+ PRIORITY_THRESHOLD: 30, // Only update widgets with priority <= 30
512
+ },
513
+ // Widget categories for degradation decisions
514
+ CRITICAL_WIDGETS: ['cpu', 'memory'], // Always update these if possible
515
+ NON_CRITICAL_WIDGETS: ['disk', 'system', 'uptime', 'dataHealth'], // Can be skipped
516
+ };
517
+
518
+ // ============================================================================
519
+ // PATH SETTINGS
520
+ // ============================================================================
521
+
522
+ export const PATHS = {
523
+ SETTINGS: os.homedir() + '/.openclaw/dashboard-settings.json',
524
+ STATE: os.homedir() + '/.openclaw/dashboard-state.json',
525
+ EXPORTS: os.homedir() + '/.openclaw/exports',
526
+ OPENCLAW_CONFIG: os.homedir() + '/.openclaw/openclaw.json',
527
+ LOG: os.homedir() + '/.openclaw/claw-dashboard.log',
528
+ HOME_DIR: os.homedir(),
529
+ OPENCLAW_DIR: os.homedir() + '/.openclaw',
530
+ AGENTS_DIR: os.homedir() + '/.openclaw/agents',
531
+ WIDGETS_DIR: os.homedir() + '/.openclaw/widgets',
532
+ PLUGINS_DIR: os.homedir() + '/.openclaw/plugins',
533
+ };
534
+
535
+ // ============================================================================
536
+ // AUTO-SAVE SETTINGS
537
+ // ============================================================================
538
+
539
+ export const AUTO_SAVE = {
540
+ ENABLED: true, // Enable auto-save by default
541
+ INTERVAL_MS: 30000, // Auto-save every 30 seconds
542
+ SAVE_ON_EXIT: true, // Save on graceful shutdown
543
+ MAX_CONSECUTIVE_FAILURES: 3, // Disable auto-save after N failures
544
+ BACKUP_COUNT: 3, // Keep N backup state files
545
+ };
546
+
547
+ // ============================================================================
548
+ // EXPORT SCHEDULER SETTINGS
549
+ // ============================================================================
550
+
551
+ export const EXPORT_SCHEDULE = {
552
+ ENABLED: false, // Disabled by default (must explicitly enable)
553
+ DEFAULT_FORMAT: 'json', // Default export format: 'json' or 'csv'
554
+ DEFAULT_SCHEDULE: '0 * * * *', // Default: every hour at minute 0
555
+ MIN_RETENTION_DAYS: 0, // Minimum retention (0 = forever)
556
+ MAX_RETENTION_DAYS: 365, // Maximum retention days
557
+ DEFAULT_RETENTION_DAYS: 30, // Default: keep 30 days of exports
558
+ MAX_SCHEDULED_EXPORTS_PER_DAY: 1440, // Max exports per day (once per minute)
559
+ };
560
+
561
+ // ============================================================================
562
+ // DEFAULT SETTINGS
563
+ // ============================================================================
564
+
565
+ export const DEFAULT_SETTINGS = {
566
+ refreshInterval: REFRESH_INTERVALS.DEFAULT,
567
+ logLevelFilter: 'all',
568
+ sessionSortMode: 'time',
569
+ showWidget1: true, // CPU
570
+ showWidget2: true, // Memory
571
+ showWidget3: true, // GPU
572
+ showWidget4: true, // Network
573
+ showWidget5: true, // Disk
574
+ showWidget6: true, // System
575
+ showWidget7: true, // Uptime
576
+ showWidget8: true, // Data Health
577
+ showWidget9: true, // Gateway Status
578
+ showPerformanceMetrics: false, // Show performance metrics in footer
579
+ theme: 'auto',
580
+ exportFormat: 'json',
581
+ exportDirectory: PATHS.EXPORTS,
582
+ sessionSearchQuery: '',
583
+ favorites: {}, // Map of sessionId -> true
584
+ showFavoritesOnly: false,
585
+ pinnedWidgets: [], // Array of widget IDs (1-9) pinned to favorites row (max 4)
586
+ firstRun: true, // Show tooltip hints on first run
587
+ gatewayEndpoints: [ // Support for multiple gateway endpoints
588
+ { ...DEFAULT_GATEWAY_ENDPOINT }
589
+ ],
590
+ activeGatewayEndpoint: 'local', // Currently selected/active endpoint
591
+ webInterface: {
592
+ enabled: false, // Web interface disabled by default
593
+ port: WEB.DEFAULT_PORT,
594
+ host: WEB.HOST,
595
+ cors: true, // Enable CORS by default
596
+ // CORS origins - set to specific origins in production (e.g., ['https://example.com'])
597
+ // Use '*' for development to allow all origins
598
+ corsOrigins: WEB.CORS.ALLOWED_ORIGINS,
599
+ // Rate limiting configuration
600
+ rateLimit: {
601
+ enabled: WEB.RATE_LIMIT.ENABLED,
602
+ windowMs: WEB.RATE_LIMIT.WINDOW_MS,
603
+ maxRequests: WEB.RATE_LIMIT.MAX_REQUESTS,
604
+ trustProxy: WEB.RATE_LIMIT.TRUST_PROXY,
605
+ },
606
+ // Authentication configuration
607
+ auth: {
608
+ enabled: WEB.AUTH.ENABLED, // Disabled by default - must explicitly enable
609
+ keys: [], // Array of { id, name, createdAt, keyHash } - keys are not stored in plain text
610
+ },
611
+ },
612
+ widgetLoading: {
613
+ enabled: true, // Enable lazy loading
614
+ preloadPriority: ['cpu', 'memory', 'gpu'], // Widgets to load immediately
615
+ lazyLoadDelay: 500, // Delay before loading other widgets
616
+ maxConcurrent: 3, // Max concurrent widget loads
617
+ autoDiscover: true, // Auto-discover plugins
618
+ },
619
+ widgetSizes: {}, // Map of widget name -> size preset (small, medium, large, wide)
620
+ plugins: {}, // Plugin-specific configurations
621
+ autoRetry: { // Auto-retry configuration for gateway connectivity
622
+ enabled: AUTO_RETRY.ENABLED,
623
+ intervalMs: AUTO_RETRY.DEFAULT_INTERVAL_MS,
624
+ exponentialBackoff: AUTO_RETRY.EXPONENTIAL_BACKOFF,
625
+ backoffMultiplier: AUTO_RETRY.BACKOFF_MULTIPLIER,
626
+ maxBackoffIntervalMs: AUTO_RETRY.MAX_BACKOFF_INTERVAL_MS,
627
+ resetAfterSuccess: AUTO_RETRY.RESET_AFTER_SUCCESS,
628
+ consecutiveFailureThreshold: AUTO_RETRY.CONSECUTIVE_FAILURE_THRESHOLD,
629
+ },
630
+ autoSave: { // Dashboard auto-save configuration
631
+ enabled: AUTO_SAVE.ENABLED,
632
+ intervalMs: AUTO_SAVE.INTERVAL_MS,
633
+ saveOnExit: AUTO_SAVE.SAVE_ON_EXIT,
634
+ },
635
+ exportSchedule: { // Scheduled metric exports configuration
636
+ enabled: EXPORT_SCHEDULE.ENABLED,
637
+ format: EXPORT_SCHEDULE.DEFAULT_FORMAT,
638
+ schedule: EXPORT_SCHEDULE.DEFAULT_SCHEDULE,
639
+ retentionDays: EXPORT_SCHEDULE.DEFAULT_RETENTION_DAYS,
640
+ directory: null, // null = use default snapshots directory
641
+ includeMetrics: true,
642
+ },
643
+ };
644
+
645
+ // ============================================================================
646
+ // EXPORT DEFAULT OBJECT (for backward compatibility)
647
+ // ============================================================================
648
+
649
+ export default {
650
+ REFRESH_INTERVALS,
651
+ IDLE_THRESHOLD_MS,
652
+ HISTORY,
653
+ GATEWAY,
654
+ DEFAULT_GATEWAY_ENDPOINT,
655
+ CHECKSUM,
656
+ UI,
657
+ CACHE_TTL,
658
+ CACHE_CONFIG,
659
+ DATABASE,
660
+ RETRY,
661
+ DEFAULT_RETRY_OPTIONS,
662
+ AUTO_RETRY,
663
+ AUTO_SAVE,
664
+ EXPORT_SCHEDULE,
665
+ ALERT_THRESHOLDS,
666
+ ALERT_RATE_LIMIT,
667
+ MAX_ALERT_HISTORY,
668
+ MEMORY_PRESSURE,
669
+ VALIDATION,
670
+ COMMAND_TIMEOUTS,
671
+ PATHS,
672
+ DEFAULT_SETTINGS,
673
+ WORKERS,
674
+ WORKER_DEGRADATION,
675
+ WEB,
676
+ WIDGETS,
677
+ WIDGET_REFRESH_INTERVALS,
678
+ WIDGET_REFRESH_VALIDATION,
679
+ WIDGET_DEGRADATION,
680
+ WIDGET_SIZE_PRESETS,
681
+ WIDGET_SIZES,
682
+ WIDGET_DEFAULT_SIZES,
683
+ DASHBOARD_VERSION,
684
+ };