claw-dashboard 2.1.1 → 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 (89) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/docs/API.md +1 -2
  3. package/index.js +31 -41
  4. package/package.json +22 -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/.c8rc.json +0 -38
  14. package/.dockerignore +0 -68
  15. package/.github/dependabot.yml +0 -45
  16. package/.github/pull_request_template.md +0 -39
  17. package/.github/workflows/ci.yml +0 -147
  18. package/.github/workflows/release.yml +0 -40
  19. package/.github/workflows/security.yml +0 -84
  20. package/.husky/pre-commit +0 -1
  21. package/.planning/codebase/ARCHITECTURE.md +0 -206
  22. package/.planning/codebase/INTEGRATIONS.md +0 -150
  23. package/.planning/codebase/STACK.md +0 -122
  24. package/.planning/codebase/STRUCTURE.md +0 -201
  25. package/CONTRIBUTING.md +0 -378
  26. package/Dockerfile +0 -54
  27. package/FEATURES.md +0 -307
  28. package/TODO.md +0 -28
  29. package/ai.openclaw.dashboard.plist +0 -35
  30. package/build-cjs.js +0 -127
  31. package/cjs-shim.js +0 -13
  32. package/dist/clawdash +0 -1729
  33. package/dist/clawdash.meta.json +0 -2236
  34. package/dist/widgets.cjs +0 -6511
  35. package/docker-compose.yml +0 -67
  36. package/esbuild.config.js +0 -158
  37. package/eslint.config.js +0 -56
  38. package/examples/plugins/README.md +0 -122
  39. package/examples/plugins/api-status/index.js +0 -294
  40. package/examples/plugins/api-status/plugin.json +0 -19
  41. package/examples/plugins/hello-world/index.js +0 -104
  42. package/examples/plugins/hello-world/plugin.json +0 -15
  43. package/examples/plugins/system-metrics-chart/index.js +0 -339
  44. package/examples/plugins/system-metrics-chart/plugin.json +0 -18
  45. package/examples/plugins/weather-widget/index.js +0 -136
  46. package/examples/plugins/weather-widget/plugin.json +0 -19
  47. package/index.cjs +0 -23005
  48. package/jest.config.js +0 -11
  49. package/scripts/release.js +0 -595
  50. package/src/database.js +0 -734
  51. package/tests/alerts.test.js +0 -437
  52. package/tests/auto-save.test.js +0 -529
  53. package/tests/cache.test.js +0 -317
  54. package/tests/cli.test.js +0 -351
  55. package/tests/command-palette.test.js +0 -320
  56. package/tests/config-processor.test.js +0 -452
  57. package/tests/config-validator.test.js +0 -710
  58. package/tests/config-watcher.test.js +0 -594
  59. package/tests/config.test.js +0 -755
  60. package/tests/database.test.js +0 -438
  61. package/tests/errors.test.js +0 -189
  62. package/tests/example-plugins.test.js +0 -624
  63. package/tests/integration.test.js +0 -1321
  64. package/tests/loading-states.test.js +0 -300
  65. package/tests/manifest-validation-on-load.test.js +0 -671
  66. package/tests/performance-monitor.test.js +0 -190
  67. package/tests/plugin-api-rate-limit.test.js +0 -302
  68. package/tests/plugin-errors.test.js +0 -311
  69. package/tests/plugin-lifecycle-e2e.test.js +0 -1036
  70. package/tests/plugin-reload.test.js +0 -764
  71. package/tests/rate-limiter.test.js +0 -539
  72. package/tests/removed-dependencies.test.js +0 -74
  73. package/tests/retry.test.js +0 -308
  74. package/tests/security.test.js +0 -411
  75. package/tests/settings-modal.test.js +0 -226
  76. package/tests/theme-selector.test.js +0 -57
  77. package/tests/utils.js +0 -242
  78. package/tests/utils.test.js +0 -317
  79. package/tests/validate-plugin-cli.test.js +0 -359
  80. package/tests/validation.test.js +0 -837
  81. package/tests/web-server.test.js +0 -646
  82. package/tests/widget-arrange-mode.test.js +0 -183
  83. package/tests/widget-config-hot-reload.test.js +0 -465
  84. package/tests/widget-dependency.test.js +0 -591
  85. package/tests/widget-error-boundary.test.js +0 -749
  86. package/tests/widget-error-isolation.test.js +0 -469
  87. package/tests/widget-integration.test.js +0 -1147
  88. package/tests/widget-refresh-intervals.test.js +0 -284
  89. 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
- });