claw-dashboard 2.1.0 → 2.2.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 (90) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/docs/API.md +1 -2
  3. package/index.js +32 -42
  4. package/package.json +23 -12
  5. package/src/auto-save.js +11 -5
  6. package/src/cli/export-snapshot.js +3 -1
  7. package/src/cli/import-snapshot.js +3 -1
  8. package/src/config.js +9 -15
  9. package/src/errors.js +0 -9
  10. package/src/security.js +6 -2
  11. package/src/snapshot.js +73 -26
  12. package/src/web-server.js +7 -10
  13. package/src/widgets/builtin-widgets.js +0 -94
  14. package/src/widgets/index.js +0 -1
  15. package/.c8rc.json +0 -38
  16. package/.dockerignore +0 -68
  17. package/.github/dependabot.yml +0 -45
  18. package/.github/pull_request_template.md +0 -39
  19. package/.github/workflows/ci.yml +0 -147
  20. package/.github/workflows/release.yml +0 -40
  21. package/.github/workflows/security.yml +0 -84
  22. package/.husky/pre-commit +0 -1
  23. package/.planning/codebase/ARCHITECTURE.md +0 -206
  24. package/.planning/codebase/INTEGRATIONS.md +0 -150
  25. package/.planning/codebase/STACK.md +0 -122
  26. package/.planning/codebase/STRUCTURE.md +0 -201
  27. package/CONTRIBUTING.md +0 -378
  28. package/Dockerfile +0 -54
  29. package/FEATURES.md +0 -307
  30. package/TODO.md +0 -28
  31. package/ai.openclaw.dashboard.plist +0 -35
  32. package/build-cjs.js +0 -127
  33. package/cjs-shim.js +0 -13
  34. package/dist/clawdash +0 -1729
  35. package/dist/clawdash.meta.json +0 -2236
  36. package/dist/widgets.cjs +0 -6511
  37. package/docker-compose.yml +0 -67
  38. package/esbuild.config.js +0 -158
  39. package/eslint.config.js +0 -56
  40. package/examples/plugins/README.md +0 -122
  41. package/examples/plugins/api-status/index.js +0 -294
  42. package/examples/plugins/api-status/plugin.json +0 -19
  43. package/examples/plugins/hello-world/index.js +0 -104
  44. package/examples/plugins/hello-world/plugin.json +0 -15
  45. package/examples/plugins/system-metrics-chart/index.js +0 -339
  46. package/examples/plugins/system-metrics-chart/plugin.json +0 -18
  47. package/examples/plugins/weather-widget/index.js +0 -136
  48. package/examples/plugins/weather-widget/plugin.json +0 -19
  49. package/index.cjs +0 -23005
  50. package/jest.config.js +0 -11
  51. package/scripts/release.js +0 -595
  52. package/src/database.js +0 -734
  53. package/tests/alerts.test.js +0 -437
  54. package/tests/auto-save.test.js +0 -529
  55. package/tests/cache.test.js +0 -317
  56. package/tests/cli.test.js +0 -351
  57. package/tests/command-palette.test.js +0 -320
  58. package/tests/config-processor.test.js +0 -452
  59. package/tests/config-validator.test.js +0 -710
  60. package/tests/config-watcher.test.js +0 -594
  61. package/tests/config.test.js +0 -755
  62. package/tests/database.test.js +0 -438
  63. package/tests/errors.test.js +0 -189
  64. package/tests/example-plugins.test.js +0 -624
  65. package/tests/integration.test.js +0 -1321
  66. package/tests/loading-states.test.js +0 -300
  67. package/tests/manifest-validation-on-load.test.js +0 -671
  68. package/tests/performance-monitor.test.js +0 -190
  69. package/tests/plugin-api-rate-limit.test.js +0 -302
  70. package/tests/plugin-errors.test.js +0 -311
  71. package/tests/plugin-lifecycle-e2e.test.js +0 -1036
  72. package/tests/plugin-reload.test.js +0 -764
  73. package/tests/rate-limiter.test.js +0 -539
  74. package/tests/retry.test.js +0 -308
  75. package/tests/security.test.js +0 -411
  76. package/tests/settings-modal.test.js +0 -226
  77. package/tests/theme-selector.test.js +0 -57
  78. package/tests/utils.js +0 -242
  79. package/tests/utils.test.js +0 -317
  80. package/tests/validate-plugin-cli.test.js +0 -359
  81. package/tests/validation.test.js +0 -837
  82. package/tests/web-server.test.js +0 -646
  83. package/tests/widget-arrange-mode.test.js +0 -183
  84. package/tests/widget-config-hot-reload.test.js +0 -465
  85. package/tests/widget-dependency.test.js +0 -591
  86. package/tests/widget-error-boundary.test.js +0 -749
  87. package/tests/widget-error-isolation.test.js +0 -469
  88. package/tests/widget-integration.test.js +0 -1147
  89. package/tests/widget-refresh-intervals.test.js +0 -284
  90. package/tests/worker-pool.test.js +0 -522
@@ -1,359 +0,0 @@
1
- import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'fs';
2
- import { join } from 'path';
3
- import os from 'os';
4
- import { execSync } from 'child_process';
5
-
6
- const CLI_PATH = join(process.cwd(), 'index.js');
7
-
8
- describe('validate-plugin CLI', () => {
9
- let tempDir;
10
- let pluginDir;
11
-
12
- beforeEach(() => {
13
- tempDir = mkdtempSync(join(os.tmpdir(), 'validate-plugin-test-'));
14
- pluginDir = join(tempDir, 'test-widget');
15
- mkdirSync(pluginDir, { recursive: true });
16
- });
17
-
18
- afterEach(() => {
19
- try {
20
- rmSync(tempDir, { recursive: true, force: true });
21
- } catch {}
22
- });
23
-
24
- const runCli = (args) => {
25
- try {
26
- const output = execSync(`node ${CLI_PATH} ${args}`, {
27
- encoding: 'utf8',
28
- cwd: process.cwd(),
29
- });
30
- return { exitCode: 0, output, stderr: '' };
31
- } catch (error) {
32
- return {
33
- exitCode: error.status || 1,
34
- output: error.stdout || '',
35
- stderr: error.stderr || error.message,
36
- };
37
- }
38
- };
39
-
40
- describe('help', () => {
41
- test('shows help with --help', () => {
42
- const result = runCli('validate-plugin --help');
43
- expect(result.exitCode).toBe(0);
44
- expect(result.output).toContain('Validate Plugin Manifest');
45
- expect(result.output).toContain('Usage:');
46
- expect(result.output).toContain('Options:');
47
- expect(result.output).toContain('--json');
48
- });
49
-
50
- test('shows help with -h', () => {
51
- const result = runCli('validate-plugin -h');
52
- expect(result.exitCode).toBe(0);
53
- expect(result.output).toContain('Validate Plugin Manifest');
54
- });
55
- });
56
-
57
- describe('validation', () => {
58
- test('returns error when no path provided', () => {
59
- const result = runCli('validate-plugin');
60
- expect(result.exitCode).toBe(1);
61
- expect(result.stderr).toContain('required');
62
- });
63
-
64
- test('returns error for non-existent path', () => {
65
- const result = runCli('validate-plugin /nonexistent/path/12345');
66
- expect(result.exitCode).toBe(1);
67
- expect(result.stderr).toContain('does not exist');
68
- });
69
-
70
- test('returns error for directory without plugin.json', () => {
71
- const result = runCli(`validate-plugin ${pluginDir}`);
72
- expect(result.exitCode).toBe(1);
73
- expect(result.stderr).toContain('No plugin.json found');
74
- });
75
- });
76
-
77
- describe('valid manifests', () => {
78
- test('validates a valid plugin.json file', () => {
79
- const validManifest = {
80
- id: 'test-widget',
81
- name: 'Test Widget',
82
- version: '1.0.0',
83
- type: 'widget',
84
- category: 'custom',
85
- };
86
- const manifestPath = join(pluginDir, 'plugin.json');
87
- writeFileSync(manifestPath, JSON.stringify(validManifest, null, 2));
88
-
89
- const result = runCli(`validate-plugin ${manifestPath}`);
90
- expect(result.exitCode).toBe(0);
91
- expect(result.output).toContain('Valid plugin manifest');
92
- expect(result.output).toContain('test-widget');
93
- expect(result.output).toContain('Test Widget');
94
- });
95
-
96
- test('validates a valid plugin directory', () => {
97
- const validManifest = {
98
- id: 'test-widget',
99
- name: 'Test Widget',
100
- version: '1.0.0',
101
- type: 'widget',
102
- category: 'custom',
103
- };
104
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
105
-
106
- const result = runCli(`validate-plugin ${pluginDir}`);
107
- expect(result.exitCode).toBe(0);
108
- expect(result.output).toContain('Valid plugin manifest');
109
- });
110
-
111
- test('accepts full manifest with all fields', () => {
112
- const fullManifest = {
113
- id: 'system-metrics',
114
- name: 'System Metrics',
115
- description: 'Shows system metrics',
116
- version: '2.1.0-beta.1',
117
- author: 'Test Author <test@example.com>',
118
- category: 'system',
119
- type: 'widget',
120
- lazyLoad: true,
121
- priority: 50,
122
- config: {
123
- refreshInterval: 5000,
124
- maxDataPoints: 30,
125
- },
126
- permissions: ['network', 'system'],
127
- dependencies: ['base-widget'],
128
- __version: 1,
129
- };
130
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(fullManifest, null, 2));
131
-
132
- const result = runCli(`validate-plugin ${pluginDir}`);
133
- expect(result.exitCode).toBe(0);
134
- expect(result.output).toContain('Valid plugin manifest');
135
- expect(result.output).toContain('system-metrics');
136
- });
137
- });
138
-
139
- describe('invalid manifests', () => {
140
- test('detects missing required fields', () => {
141
- const invalidManifest = {
142
- name: 'Test Widget',
143
- // missing id, version, type
144
- };
145
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
146
-
147
- const result = runCli(`validate-plugin ${pluginDir}`);
148
- expect(result.exitCode).toBe(1);
149
- expect(result.stderr).toContain('Invalid');
150
- expect(result.stderr).toContain('Errors:');
151
- });
152
-
153
- test('detects invalid id format', () => {
154
- const invalidManifest = {
155
- id: '_invalid-id',
156
- name: 'Test',
157
- version: '1.0.0',
158
- type: 'widget',
159
- };
160
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
161
-
162
- const result = runCli(`validate-plugin ${pluginDir}`);
163
- expect(result.exitCode).toBe(1);
164
- expect(result.stderr).toContain('Invalid');
165
- });
166
-
167
- test('detects invalid semver version', () => {
168
- const invalidManifest = {
169
- id: 'test-widget',
170
- name: 'Test',
171
- version: 'not-a-version',
172
- type: 'widget',
173
- };
174
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
175
-
176
- const result = runCli(`validate-plugin ${pluginDir}`);
177
- expect(result.exitCode).toBe(1);
178
- expect(result.stderr).toContain('semantic version');
179
- });
180
-
181
- test('detects invalid type', () => {
182
- const invalidManifest = {
183
- id: 'test-widget',
184
- name: 'Test',
185
- version: '1.0.0',
186
- type: 'invalid-type',
187
- };
188
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
189
-
190
- const result = runCli(`validate-plugin ${pluginDir}`);
191
- expect(result.exitCode).toBe(1);
192
- expect(result.stderr).toContain('widget');
193
- });
194
-
195
- test('detects invalid category', () => {
196
- const invalidManifest = {
197
- id: 'test-widget',
198
- name: 'Test',
199
- version: '1.0.0',
200
- type: 'widget',
201
- category: 'invalid-category',
202
- };
203
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
204
-
205
- const result = runCli(`validate-plugin ${pluginDir}`);
206
- expect(result.exitCode).toBe(1);
207
- expect(result.stderr).toContain('custom');
208
- });
209
-
210
- test('detects priority out of range', () => {
211
- const invalidManifest = {
212
- id: 'test-widget',
213
- name: 'Test',
214
- version: '1.0.0',
215
- type: 'widget',
216
- priority: 2000,
217
- };
218
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
219
-
220
- const result = runCli(`validate-plugin ${pluginDir}`);
221
- expect(result.exitCode).toBe(1);
222
- expect(result.stderr).toContain('at most');
223
- });
224
- });
225
-
226
- describe('json output', () => {
227
- test('outputs valid result as JSON with --json', () => {
228
- const validManifest = {
229
- id: 'test-widget',
230
- name: 'Test Widget',
231
- version: '1.0.0',
232
- type: 'widget',
233
- };
234
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
235
-
236
- const result = runCli(`validate-plugin ${pluginDir} --json`);
237
- expect(result.exitCode).toBe(0);
238
- const json = JSON.parse(result.output);
239
- expect(json.valid).toBe(true);
240
- expect(json.id).toBe('test-widget');
241
- expect(json.name).toBe('Test Widget');
242
- expect(json.version).toBe('1.0.0');
243
- });
244
-
245
- test('outputs invalid result as JSON with -j', () => {
246
- const invalidManifest = {
247
- id: 'test-widget',
248
- // missing required fields
249
- };
250
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
251
-
252
- const result = runCli(`validate-plugin ${pluginDir} -j`);
253
- expect(result.exitCode).toBe(1);
254
- const json = JSON.parse(result.output);
255
- expect(json.valid).toBe(false);
256
- expect(json.errors).toBeDefined();
257
- expect(json.errors.length).toBeGreaterThan(0);
258
- });
259
-
260
- test('includes path in JSON output', () => {
261
- const validManifest = {
262
- id: 'test-widget',
263
- name: 'Test Widget',
264
- version: '1.0.0',
265
- type: 'widget',
266
- };
267
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
268
-
269
- const result = runCli(`validate-plugin ${pluginDir} --json`);
270
- const json = JSON.parse(result.output);
271
- expect(json.path).toContain('test-widget');
272
- expect(json.path).toContain('plugin.json');
273
- });
274
- });
275
-
276
- describe('path handling', () => {
277
- test('handles absolute paths', () => {
278
- const validManifest = {
279
- id: 'test-widget',
280
- name: 'Test Widget',
281
- version: '1.0.0',
282
- type: 'widget',
283
- };
284
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
285
-
286
- const result = runCli(`validate-plugin ${pluginDir}/plugin.json`);
287
- expect(result.exitCode).toBe(0);
288
- });
289
-
290
- test('handles ~ in path', () => {
291
- const validManifest = {
292
- id: 'test-widget',
293
- name: 'Test Widget',
294
- version: '1.0.0',
295
- type: 'widget',
296
- };
297
- const homePluginDir = join(os.homedir(), '.openclaw', 'plugins', 'test-widget');
298
- mkdirSync(homePluginDir, { recursive: true });
299
- writeFileSync(join(homePluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
300
-
301
- const result = runCli('validate-plugin ~/.openclaw/plugins/test-widget');
302
- expect(result.exitCode).toBe(0);
303
-
304
- // Cleanup
305
- try {
306
- rmSync(join(os.homedir(), '.openclaw', 'plugins', 'test-widget'), { recursive: true, force: true });
307
- } catch {}
308
- });
309
- });
310
-
311
- describe('edge cases', () => {
312
- test('handles invalid JSON', () => {
313
- writeFileSync(join(pluginDir, 'plugin.json'), 'not valid json {');
314
-
315
- const result = runCli(`validate-plugin ${pluginDir}`);
316
- expect(result.exitCode).toBe(1);
317
- expect(result.stderr).toContain('parse');
318
- });
319
-
320
- test('handles empty JSON object', () => {
321
- writeFileSync(join(pluginDir, 'plugin.json'), '{}');
322
-
323
- const result = runCli(`validate-plugin ${pluginDir}`);
324
- expect(result.exitCode).toBe(1);
325
- expect(result.stderr).toContain('Errors:');
326
- });
327
-
328
- test('handles file instead of directory for path with ~', () => {
329
- // This test ensures path resolution works correctly
330
- const validManifest = {
331
- id: 'test-widget',
332
- name: 'Test Widget',
333
- version: '1.0.0',
334
- type: 'widget',
335
- };
336
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(validManifest, null, 2));
337
-
338
- const result = runCli(`validate-plugin ${pluginDir}/plugin.json`);
339
- expect(result.exitCode).toBe(0);
340
- });
341
-
342
- test('validates multiple errors at once', () => {
343
- const invalidManifest = {
344
- id: 'test',
345
- name: '',
346
- version: 'invalid',
347
- type: 'wrong',
348
- category: 'bad',
349
- priority: -5,
350
- };
351
- writeFileSync(join(pluginDir, 'plugin.json'), JSON.stringify(invalidManifest, null, 2));
352
-
353
- const result = runCli(`validate-plugin ${pluginDir} --json`);
354
- expect(result.exitCode).toBe(1);
355
- const json = JSON.parse(result.output);
356
- expect(json.errors.length).toBeGreaterThan(1);
357
- });
358
- });
359
- });