@elizaos/cli 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-2CUIHNPL.js → chunk-5GUS4CFO.js} +7 -2
- package/dist/{chunk-2ALAPQLV.js → chunk-E6XYTE3A.js} +296 -311
- package/dist/chunk-GXWWPFBO.js +39 -0
- package/dist/{chunk-I77ZRNYO.js → chunk-T2QDIXGU.js} +2 -2
- package/dist/commands/agent/actions/index.d.ts +5 -0
- package/dist/commands/agent/actions/index.js +2 -2
- package/dist/commands/agent/index.d.ts +2 -2
- package/dist/commands/agent/index.js +2 -2
- package/dist/commands/create/actions/index.js +3 -3
- package/dist/commands/create/index.js +4 -4
- package/dist/commands/shared/index.d.ts +11 -28
- package/dist/commands/shared/index.js +7 -3
- package/dist/index.js +541 -450
- package/dist/{registry-N626N4VG.js → registry-433S5F3Y.js} +2 -2
- package/dist/templates/plugin-quick-starter/.gitignore +66 -0
- package/dist/templates/plugin-quick-starter/.npmignore +5 -0
- package/dist/templates/plugin-quick-starter/package.json +11 -3
- package/dist/templates/plugin-quick-starter/src/__tests__/plugin.test.ts +499 -146
- package/dist/templates/plugin-quick-starter/src/__tests__/test-utils.ts +316 -115
- package/dist/templates/plugin-quick-starter/src/plugin.ts +7 -13
- package/dist/templates/plugin-starter/.gitignore +66 -0
- package/dist/templates/plugin-starter/.npmignore +5 -0
- package/dist/templates/plugin-starter/README.md +1 -1
- package/dist/templates/plugin-starter/package.json +11 -3
- package/dist/templates/plugin-starter/src/__tests__/integration.test.ts +13 -13
- package/dist/templates/plugin-starter/src/__tests__/plugin.test.ts +556 -129
- package/dist/templates/plugin-starter/src/__tests__/test-utils.ts +347 -115
- package/dist/templates/plugin-starter/src/plugin.ts +18 -22
- package/dist/templates/project-starter/.gitignore +57 -0
- package/dist/templates/project-starter/.npmignore +11 -0
- package/dist/templates/project-starter/README.md +1 -1
- package/dist/templates/project-starter/package.json +4 -4
- package/dist/templates/project-starter/src/__tests__/env.test.ts +3 -1
- package/dist/templates/project-starter/src/__tests__/file-structure.test.ts +3 -2
- package/dist/templates/project-starter/src/__tests__/integration.test.ts +1 -1
- package/dist/templates/project-starter/tsup.config.ts +2 -1
- package/dist/templates/project-tee-starter/.dockerignore +64 -14
- package/dist/templates/project-tee-starter/.gitignore +57 -0
- package/dist/templates/project-tee-starter/.npmignore +6 -0
- package/dist/templates/project-tee-starter/Dockerfile +9 -5
- package/dist/templates/project-tee-starter/GUIDE.md +103 -42
- package/dist/templates/project-tee-starter/README.md +39 -19
- package/dist/templates/project-tee-starter/__tests__/build-order.test.ts +62 -0
- package/dist/templates/project-tee-starter/__tests__/character.test.ts +19 -17
- package/dist/templates/project-tee-starter/__tests__/config.test.ts +10 -3
- package/dist/templates/project-tee-starter/__tests__/env.test.ts +2 -1
- package/dist/templates/project-tee-starter/__tests__/file-structure.test.ts +14 -3
- package/dist/templates/project-tee-starter/__tests__/frontend.test.ts +459 -0
- package/dist/templates/project-tee-starter/__tests__/plugin.test.ts +4 -2
- package/dist/templates/project-tee-starter/__tests__/routes.test.ts +15 -6
- package/dist/templates/project-tee-starter/__tests__/tee-validation.test.ts +295 -0
- package/dist/templates/project-tee-starter/__tests__/vite-config-utils.ts +39 -0
- package/dist/templates/project-tee-starter/docker-compose.yaml +5 -2
- package/dist/templates/{plugin-starter/dist → project-tee-starter}/index.html +3 -3
- package/dist/templates/project-tee-starter/package.json +34 -14
- package/dist/templates/project-tee-starter/postcss.config.js +3 -0
- package/dist/templates/project-tee-starter/scripts/install-test-deps.js +52 -0
- package/dist/templates/project-tee-starter/scripts/test-all.sh +82 -0
- package/dist/templates/project-tee-starter/src/frontend/index.css +106 -0
- package/dist/templates/project-tee-starter/src/frontend/index.html +20 -0
- package/dist/templates/project-tee-starter/src/frontend/index.tsx +370 -0
- package/dist/templates/project-tee-starter/src/frontend/panels.tsx +17 -0
- package/dist/templates/project-tee-starter/src/frontend/utils.ts +6 -0
- package/dist/templates/project-tee-starter/src/index.ts +6 -6
- package/dist/templates/project-tee-starter/src/plugin.ts +209 -59
- package/dist/templates/project-tee-starter/tailwind.config.js +62 -0
- package/dist/templates/project-tee-starter/tsconfig.build.json +2 -2
- package/dist/templates/project-tee-starter/tsconfig.json +8 -5
- package/dist/templates/project-tee-starter/tsup.config.ts +3 -2
- package/dist/templates/project-tee-starter/vite.config.ts +39 -0
- package/dist/url-utils-CKc_Ebt_.d.ts +35 -0
- package/dist/{utils-H66532NB.js → utils-DBLSDYBF.js} +2 -2
- package/package.json +12 -7
- package/templates/plugin-quick-starter/.gitignore +66 -0
- package/templates/plugin-quick-starter/.npmignore +5 -0
- package/templates/plugin-quick-starter/package.json +11 -3
- package/templates/plugin-quick-starter/src/__tests__/plugin.test.ts +499 -146
- package/templates/plugin-quick-starter/src/__tests__/test-utils.ts +316 -115
- package/templates/plugin-quick-starter/src/plugin.ts +7 -13
- package/templates/plugin-starter/.gitignore +66 -0
- package/templates/plugin-starter/.npmignore +5 -0
- package/templates/plugin-starter/README.md +1 -1
- package/templates/plugin-starter/package.json +11 -3
- package/templates/plugin-starter/src/__tests__/integration.test.ts +13 -13
- package/templates/plugin-starter/src/__tests__/plugin.test.ts +556 -129
- package/templates/plugin-starter/src/__tests__/test-utils.ts +347 -115
- package/templates/plugin-starter/src/plugin.ts +18 -22
- package/templates/project-starter/.gitignore +57 -0
- package/templates/project-starter/.npmignore +11 -0
- package/templates/project-starter/README.md +1 -1
- package/templates/project-starter/package.json +4 -4
- package/templates/project-starter/src/__tests__/env.test.ts +3 -1
- package/templates/project-starter/src/__tests__/file-structure.test.ts +3 -2
- package/templates/project-starter/src/__tests__/integration.test.ts +1 -1
- package/templates/project-starter/tsup.config.ts +2 -1
- package/templates/project-tee-starter/.dockerignore +64 -14
- package/templates/project-tee-starter/.gitignore +57 -0
- package/templates/project-tee-starter/.npmignore +6 -0
- package/templates/project-tee-starter/Dockerfile +9 -5
- package/templates/project-tee-starter/GUIDE.md +103 -42
- package/templates/project-tee-starter/README.md +39 -19
- package/templates/project-tee-starter/__tests__/build-order.test.ts +62 -0
- package/templates/project-tee-starter/__tests__/character.test.ts +19 -17
- package/templates/project-tee-starter/__tests__/config.test.ts +10 -3
- package/templates/project-tee-starter/__tests__/env.test.ts +2 -1
- package/templates/project-tee-starter/__tests__/file-structure.test.ts +14 -3
- package/templates/project-tee-starter/__tests__/frontend.test.ts +459 -0
- package/templates/project-tee-starter/__tests__/plugin.test.ts +4 -2
- package/templates/project-tee-starter/__tests__/routes.test.ts +15 -6
- package/templates/project-tee-starter/__tests__/tee-validation.test.ts +295 -0
- package/templates/project-tee-starter/__tests__/vite-config-utils.ts +39 -0
- package/templates/project-tee-starter/docker-compose.yaml +5 -2
- package/templates/{plugin-starter/dist → project-tee-starter}/index.html +3 -3
- package/templates/project-tee-starter/package.json +34 -14
- package/templates/project-tee-starter/postcss.config.js +3 -0
- package/templates/project-tee-starter/scripts/install-test-deps.js +52 -0
- package/templates/project-tee-starter/scripts/test-all.sh +82 -0
- package/templates/project-tee-starter/src/frontend/index.css +106 -0
- package/templates/project-tee-starter/src/frontend/index.html +20 -0
- package/templates/project-tee-starter/src/frontend/index.tsx +370 -0
- package/templates/project-tee-starter/src/frontend/panels.tsx +17 -0
- package/templates/project-tee-starter/src/frontend/utils.ts +6 -0
- package/templates/project-tee-starter/src/index.ts +6 -6
- package/templates/project-tee-starter/src/plugin.ts +209 -59
- package/templates/project-tee-starter/tailwind.config.js +62 -0
- package/templates/project-tee-starter/tsconfig.build.json +2 -2
- package/templates/project-tee-starter/tsconfig.json +8 -5
- package/templates/project-tee-starter/tsup.config.ts +3 -2
- package/templates/project-tee-starter/vite.config.ts +39 -0
- package/dist/chunk-4O6EZU37.js +0 -14
- package/dist/migration-guides/advanced-migration-guide.md +0 -459
- package/dist/migration-guides/completion-requirements.md +0 -379
- package/dist/migration-guides/integrated-migration-loop.md +0 -392
- package/dist/migration-guides/migration-guide.md +0 -712
- package/dist/migration-guides/prompt-and-generation-guide.md +0 -702
- package/dist/migration-guides/state-and-providers-guide.md +0 -544
- package/dist/migration-guides/testing-guide.md +0 -1021
- package/dist/templates/plugin-starter/dist/assets/index-CgkejLs_.css +0 -1
- package/dist/templates/plugin-starter/dist/assets/index-D1cHX53P.js +0 -49
- package/dist/templates/plugin-starter/dist/index.js +0 -387
- package/dist/templates/plugin-starter/dist/index.js.map +0 -1
- package/templates/plugin-starter/dist/.vite/manifest.json +0 -11
- package/templates/plugin-starter/dist/assets/index-CgkejLs_.css +0 -1
- package/templates/plugin-starter/dist/assets/index-D1cHX53P.js +0 -49
- package/templates/plugin-starter/dist/index.d.ts +0 -14
- package/templates/plugin-starter/dist/index.js +0 -387
- package/templates/plugin-starter/dist/index.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
2
|
import { mrTeeCharacter as character } from '../src/character';
|
|
3
|
-
import
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
|
|
6
6
|
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
|
@@ -44,26 +44,28 @@ describe('Mr. TEE Character Configuration', () => {
|
|
|
44
44
|
|
|
45
45
|
it('should have TEE-related message examples', () => {
|
|
46
46
|
let foundTeeExample = false;
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
if (character.messageExamples) {
|
|
48
|
+
for (const ex of character.messageExamples) {
|
|
49
|
+
const dialogue = ex.map((msg) => msg.content.text?.toLowerCase() || '').join(' ');
|
|
50
|
+
if (
|
|
51
|
+
dialogue.includes('attestation') ||
|
|
52
|
+
dialogue.includes('enclave') ||
|
|
53
|
+
dialogue.includes('tee')
|
|
54
|
+
) {
|
|
55
|
+
foundTeeExample = true;
|
|
56
|
+
const mrTeeResponse = ex.find((msg) => msg.name === 'Mr. TEE');
|
|
57
|
+
expect(mrTeeResponse).toBeDefined();
|
|
58
|
+
if (mrTeeResponse && mrTeeResponse.content.text) {
|
|
59
|
+
expect(mrTeeResponse.content.text.length).toBeGreaterThan(10);
|
|
60
|
+
if (mrTeeResponse.content.actions) {
|
|
61
|
+
expect(Array.isArray(mrTeeResponse.content.actions)).toBe(true);
|
|
62
|
+
}
|
|
61
63
|
}
|
|
64
|
+
break;
|
|
62
65
|
}
|
|
63
|
-
break;
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
|
-
expect(foundTeeExample
|
|
68
|
+
expect(foundTeeExample).toBe(true);
|
|
67
69
|
});
|
|
68
70
|
|
|
69
71
|
it('should have TEE-related post examples', () => {
|
|
@@ -18,14 +18,21 @@ describe('Plugin Configuration', () => {
|
|
|
18
18
|
);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it('should be a
|
|
22
|
-
// Verify
|
|
21
|
+
it('should be a TEE-focused plugin with appropriate components', () => {
|
|
22
|
+
// Verify plugin has TEE-specific components
|
|
23
23
|
expect(teeStarterPlugin.actions).toEqual([]);
|
|
24
24
|
expect(teeStarterPlugin.providers).toEqual([]);
|
|
25
25
|
expect(teeStarterPlugin.evaluators).toBeUndefined();
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
// Has StarterService for TEE functionality
|
|
28
|
+
expect(teeStarterPlugin.services).toBeDefined();
|
|
29
|
+
expect(teeStarterPlugin.services?.length).toBe(1);
|
|
30
|
+
|
|
31
|
+
// Has routes for TEE status and frontend
|
|
27
32
|
expect(teeStarterPlugin.routes).toBeDefined();
|
|
28
33
|
expect(teeStarterPlugin.routes?.length).toBeGreaterThan(0);
|
|
34
|
+
|
|
35
|
+
// Has events for logging
|
|
29
36
|
expect(teeStarterPlugin.events).toBeDefined();
|
|
30
37
|
});
|
|
31
38
|
});
|
|
@@ -39,7 +39,8 @@ describe('Environment Setup', () => {
|
|
|
39
39
|
expect(fs.existsSync(packageJsonPath)).toBe(true);
|
|
40
40
|
|
|
41
41
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
42
|
-
expect(packageJson).toHaveProperty('name'
|
|
42
|
+
expect(packageJson).toHaveProperty('name');
|
|
43
|
+
expect(typeof packageJson.name).toBe('string');
|
|
43
44
|
expect(packageJson).toHaveProperty('version');
|
|
44
45
|
expect(packageJson).toHaveProperty('type', 'module');
|
|
45
46
|
expect(packageJson).toHaveProperty('main');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test';
|
|
1
|
+
import { describe, expect, it, beforeAll } from 'bun:test';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { $ } from 'bun';
|
|
4
5
|
import { logger } from '@elizaos/core';
|
|
5
6
|
|
|
6
7
|
// Helper function to check if a file exists
|
|
@@ -15,6 +16,15 @@ function directoryExists(dirPath: string): boolean {
|
|
|
15
16
|
|
|
16
17
|
describe('Project Structure Validation', () => {
|
|
17
18
|
const rootDir = path.resolve(__dirname, '..');
|
|
19
|
+
const distDir = path.join(rootDir, 'dist');
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
// Build the project if dist doesn't exist
|
|
23
|
+
if (!fs.existsSync(distDir)) {
|
|
24
|
+
console.log('Building project for tests...');
|
|
25
|
+
await $`cd ${rootDir} && bun run build`;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
18
28
|
|
|
19
29
|
describe('Directory Structure', () => {
|
|
20
30
|
it('should have the expected directory structure', () => {
|
|
@@ -59,8 +69,9 @@ describe('Project Structure Validation', () => {
|
|
|
59
69
|
it('should have the correct package.json configuration', () => {
|
|
60
70
|
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
|
61
71
|
|
|
62
|
-
// Check package name
|
|
63
|
-
expect(packageJson.name).
|
|
72
|
+
// Check package name - should be valid (not checking exact name since it's dynamic in created projects)
|
|
73
|
+
expect(packageJson.name).toBeTruthy();
|
|
74
|
+
expect(typeof packageJson.name).toBe('string');
|
|
64
75
|
|
|
65
76
|
// Check scripts
|
|
66
77
|
expect(packageJson.scripts).toHaveProperty('build');
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
// Setup DOM environment for testing
|
|
5
|
+
import { JSDOM } from 'jsdom';
|
|
6
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body><div id="root"></div></body></html>', {
|
|
7
|
+
url: 'http://localhost',
|
|
8
|
+
pretendToBeVisual: true,
|
|
9
|
+
resources: 'usable',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
// Setup global objects
|
|
13
|
+
global.window = dom.window as any;
|
|
14
|
+
global.document = dom.window.document;
|
|
15
|
+
global.navigator = dom.window.navigator;
|
|
16
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
17
|
+
global.Element = dom.window.Element;
|
|
18
|
+
|
|
19
|
+
// Extend Window interface for TypeScript
|
|
20
|
+
declare global {
|
|
21
|
+
interface Window {
|
|
22
|
+
ELIZA_CONFIG?: {
|
|
23
|
+
agentId: string;
|
|
24
|
+
apiBase: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Mock the frontend components
|
|
30
|
+
const mockFetch = mock() as any;
|
|
31
|
+
global.fetch = mockFetch;
|
|
32
|
+
|
|
33
|
+
// Mock window.ELIZA_CONFIG
|
|
34
|
+
Object.defineProperty(global.window, 'ELIZA_CONFIG', {
|
|
35
|
+
value: {
|
|
36
|
+
agentId: 'test-agent-123',
|
|
37
|
+
apiBase: 'http://localhost:3000',
|
|
38
|
+
},
|
|
39
|
+
writable: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Mock document.getElementById for React rendering
|
|
43
|
+
const mockRoot = {
|
|
44
|
+
render: mock(),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
Object.defineProperty(global.document, 'getElementById', {
|
|
48
|
+
value: mock(() => mockRoot),
|
|
49
|
+
writable: true,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Mock createRoot
|
|
53
|
+
mock.module('react-dom/client', () => ({
|
|
54
|
+
createRoot: mock(() => mockRoot),
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
describe('TEE Frontend Components', () => {
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
mockFetch.mockClear();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
// Cleanup if needed
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('TEE Status API Response Handling', () => {
|
|
67
|
+
test('should handle successful TEE status response', async () => {
|
|
68
|
+
const mockResponse = {
|
|
69
|
+
message: 'Mr. TEE is operational, fool!',
|
|
70
|
+
tee_mode: 'development',
|
|
71
|
+
tee_vendor: 'intel',
|
|
72
|
+
timestamp: '2024-01-01T00:00:00.000Z',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
mockFetch.mockResolvedValueOnce({
|
|
76
|
+
ok: true,
|
|
77
|
+
json: async () => mockResponse,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Test the fetch logic directly
|
|
81
|
+
const response = await fetch('/mr-tee-status');
|
|
82
|
+
const data = await response.json();
|
|
83
|
+
|
|
84
|
+
expect(fetch).toHaveBeenCalledWith('/mr-tee-status');
|
|
85
|
+
expect(data).toEqual(mockResponse);
|
|
86
|
+
expect(data.tee_mode).toBe('development');
|
|
87
|
+
expect(data.tee_vendor).toBe('intel');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should handle network failure with proper error categorization', async () => {
|
|
91
|
+
const networkError = new Error('Failed to fetch');
|
|
92
|
+
networkError.name = 'NetworkError';
|
|
93
|
+
|
|
94
|
+
mockFetch.mockRejectedValueOnce(networkError);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await fetch('/mr-tee-status');
|
|
98
|
+
} catch (error) {
|
|
99
|
+
expect(error).toBeInstanceOf(Error);
|
|
100
|
+
expect((error as Error).name).toBe('NetworkError');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('should handle timeout errors', async () => {
|
|
105
|
+
const timeoutError = new Error('Request timeout');
|
|
106
|
+
timeoutError.name = 'AbortError';
|
|
107
|
+
|
|
108
|
+
mockFetch.mockRejectedValueOnce(timeoutError);
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await fetch('/mr-tee-status');
|
|
112
|
+
} catch (error) {
|
|
113
|
+
expect(error).toBeInstanceOf(Error);
|
|
114
|
+
expect((error as Error).name).toBe('AbortError');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should handle server errors (5xx)', async () => {
|
|
119
|
+
mockFetch.mockResolvedValueOnce({
|
|
120
|
+
ok: false,
|
|
121
|
+
status: 500,
|
|
122
|
+
statusText: 'Internal Server Error',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const response = await fetch('/mr-tee-status');
|
|
126
|
+
expect(response.ok).toBe(false);
|
|
127
|
+
expect(response.status).toBe(500);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('TEE Error Classification', () => {
|
|
132
|
+
// Test the error classification logic from the frontend
|
|
133
|
+
const createNetworkError = (error: Error) => {
|
|
134
|
+
// Network failure detection
|
|
135
|
+
if (error.name === 'NetworkError' || error.message.includes('Failed to fetch')) {
|
|
136
|
+
return {
|
|
137
|
+
type: 'network',
|
|
138
|
+
message: 'Network connection failed',
|
|
139
|
+
details: 'Unable to reach the TEE service. Please check your connection.',
|
|
140
|
+
retryable: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Timeout detection
|
|
145
|
+
if (error.name === 'AbortError' || error.message.includes('timeout')) {
|
|
146
|
+
return {
|
|
147
|
+
type: 'timeout',
|
|
148
|
+
message: 'Request timeout',
|
|
149
|
+
details: 'The TEE service is taking too long to respond.',
|
|
150
|
+
retryable: true,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Server error detection
|
|
155
|
+
if (error.message.includes('5')) {
|
|
156
|
+
return {
|
|
157
|
+
type: 'server',
|
|
158
|
+
message: 'Server error',
|
|
159
|
+
details: 'The TEE service encountered an internal error.',
|
|
160
|
+
retryable: true,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
type: 'unknown',
|
|
166
|
+
message: error.message || 'An unknown error occurred',
|
|
167
|
+
details: 'Please try again or contact support if the problem persists.',
|
|
168
|
+
retryable: true,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
test('should classify network errors correctly', () => {
|
|
173
|
+
const networkError = new Error('Failed to fetch');
|
|
174
|
+
networkError.name = 'NetworkError';
|
|
175
|
+
|
|
176
|
+
const classified = createNetworkError(networkError);
|
|
177
|
+
|
|
178
|
+
expect(classified.type).toBe('network');
|
|
179
|
+
expect(classified.retryable).toBe(true);
|
|
180
|
+
expect(classified.message).toBe('Network connection failed');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('should classify timeout errors correctly', () => {
|
|
184
|
+
const timeoutError = new Error('Request timeout');
|
|
185
|
+
timeoutError.name = 'AbortError';
|
|
186
|
+
|
|
187
|
+
const classified = createNetworkError(timeoutError);
|
|
188
|
+
|
|
189
|
+
expect(classified.type).toBe('timeout');
|
|
190
|
+
expect(classified.retryable).toBe(true);
|
|
191
|
+
expect(classified.message).toBe('Request timeout');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('should classify server errors correctly', () => {
|
|
195
|
+
const serverError = new Error('HTTP 500: Internal Server Error');
|
|
196
|
+
|
|
197
|
+
const classified = createNetworkError(serverError);
|
|
198
|
+
|
|
199
|
+
expect(classified.type).toBe('server');
|
|
200
|
+
expect(classified.retryable).toBe(true);
|
|
201
|
+
expect(classified.message).toBe('Server error');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('should classify unknown errors correctly', () => {
|
|
205
|
+
const unknownError = new Error('Something unexpected happened');
|
|
206
|
+
|
|
207
|
+
const classified = createNetworkError(unknownError);
|
|
208
|
+
|
|
209
|
+
expect(classified.type).toBe('unknown');
|
|
210
|
+
expect(classified.retryable).toBe(true);
|
|
211
|
+
expect(classified.message).toBe('Something unexpected happened');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('Fetch with Retry Logic', () => {
|
|
216
|
+
const fetchWithRetry = async (
|
|
217
|
+
url: string,
|
|
218
|
+
options: { timeout?: number; retries?: number } = {}
|
|
219
|
+
) => {
|
|
220
|
+
const { timeout = 10000, retries = 3 } = options;
|
|
221
|
+
|
|
222
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
223
|
+
try {
|
|
224
|
+
const controller = new AbortController();
|
|
225
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
226
|
+
|
|
227
|
+
const response = await fetch(url, {
|
|
228
|
+
...options,
|
|
229
|
+
signal: controller.signal,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
clearTimeout(timeoutId);
|
|
233
|
+
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return response;
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (attempt === retries) {
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Wait before retry (exponential backoff)
|
|
245
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt - 1) * 10)); // Shortened for tests
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
throw new Error('Max retries exceeded');
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
test('should succeed on first attempt when response is ok', async () => {
|
|
253
|
+
mockFetch.mockResolvedValueOnce({
|
|
254
|
+
ok: true,
|
|
255
|
+
json: async () => ({ status: 'success' }),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const response = await fetchWithRetry('/mr-tee-status');
|
|
259
|
+
expect(response.ok).toBe(true);
|
|
260
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('should retry on failure and succeed on second attempt', async () => {
|
|
264
|
+
mockFetch.mockRejectedValueOnce(new Error('Network error')).mockResolvedValueOnce({
|
|
265
|
+
ok: true,
|
|
266
|
+
json: async () => ({ status: 'success' }),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const response = await fetchWithRetry('/mr-tee-status', { retries: 2 });
|
|
270
|
+
expect(response.ok).toBe(true);
|
|
271
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('should fail after max retries', async () => {
|
|
275
|
+
mockFetch.mockRejectedValue(new Error('Persistent network error'));
|
|
276
|
+
|
|
277
|
+
await expect(fetchWithRetry('/mr-tee-status', { retries: 2 })).rejects.toThrow(
|
|
278
|
+
'Persistent network error'
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('should handle HTTP error status codes', async () => {
|
|
285
|
+
mockFetch.mockResolvedValue({
|
|
286
|
+
ok: false,
|
|
287
|
+
status: 500,
|
|
288
|
+
statusText: 'Internal Server Error',
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
await expect(fetchWithRetry('/mr-tee-status', { retries: 1 })).rejects.toThrow(
|
|
292
|
+
'HTTP 500: Internal Server Error'
|
|
293
|
+
);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe('TEE Status State Management', () => {
|
|
298
|
+
test('should initialize with loading state', () => {
|
|
299
|
+
const initialState = {
|
|
300
|
+
connected: false,
|
|
301
|
+
loading: true,
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
expect(initialState.loading).toBe(true);
|
|
305
|
+
expect(initialState.connected).toBe(false);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('should transition to connected state on successful fetch', () => {
|
|
309
|
+
const successState = {
|
|
310
|
+
connected: true,
|
|
311
|
+
loading: false,
|
|
312
|
+
mode: 'development',
|
|
313
|
+
vendor: 'intel',
|
|
314
|
+
lastUpdated: '2024-01-01T00:00:00.000Z',
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
expect(successState.connected).toBe(true);
|
|
318
|
+
expect(successState.loading).toBe(false);
|
|
319
|
+
expect(successState.mode).toBe('development');
|
|
320
|
+
expect(successState.vendor).toBe('intel');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test('should transition to error state on fetch failure', () => {
|
|
324
|
+
const errorState = {
|
|
325
|
+
connected: false,
|
|
326
|
+
loading: false,
|
|
327
|
+
error: {
|
|
328
|
+
type: 'network' as const,
|
|
329
|
+
message: 'Network connection failed',
|
|
330
|
+
retryable: true,
|
|
331
|
+
},
|
|
332
|
+
lastUpdated: '2024-01-01T00:00:00.000Z',
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
expect(errorState.connected).toBe(false);
|
|
336
|
+
expect(errorState.loading).toBe(false);
|
|
337
|
+
expect(errorState.error?.type).toBe('network');
|
|
338
|
+
expect(errorState.error?.retryable).toBe(true);
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe('Component Integration', () => {
|
|
343
|
+
test('should have valid ELIZA_CONFIG configuration', () => {
|
|
344
|
+
expect(global.window.ELIZA_CONFIG).toBeDefined();
|
|
345
|
+
expect(global.window.ELIZA_CONFIG?.agentId).toBe('test-agent-123');
|
|
346
|
+
expect(global.window.ELIZA_CONFIG?.apiBase).toBe('http://localhost:3000');
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test('should handle missing agentId gracefully', () => {
|
|
350
|
+
const originalConfig = global.window.ELIZA_CONFIG;
|
|
351
|
+
|
|
352
|
+
// Temporarily remove agentId
|
|
353
|
+
Object.defineProperty(global.window, 'ELIZA_CONFIG', {
|
|
354
|
+
value: { apiBase: 'http://localhost:3000' },
|
|
355
|
+
writable: true,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
expect(global.window.ELIZA_CONFIG?.agentId).toBeUndefined();
|
|
359
|
+
|
|
360
|
+
// Restore original config
|
|
361
|
+
Object.defineProperty(global.window, 'ELIZA_CONFIG', {
|
|
362
|
+
value: originalConfig,
|
|
363
|
+
writable: true,
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('should apply dark mode class on component mount', () => {
|
|
368
|
+
// Mock document.documentElement
|
|
369
|
+
const mockClassList = {
|
|
370
|
+
add: mock(),
|
|
371
|
+
remove: mock(),
|
|
372
|
+
contains: mock(),
|
|
373
|
+
toggle: mock(),
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
Object.defineProperty(global.document.documentElement, 'classList', {
|
|
377
|
+
value: mockClassList,
|
|
378
|
+
writable: true,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// In a real component, this would be called automatically
|
|
382
|
+
global.document.documentElement.classList.add('dark');
|
|
383
|
+
|
|
384
|
+
expect(mockClassList.add).toHaveBeenCalledWith('dark');
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
describe('Panel Configuration', () => {
|
|
389
|
+
test('should export valid panel configuration', () => {
|
|
390
|
+
const panels = [
|
|
391
|
+
{
|
|
392
|
+
name: 'TEE Status',
|
|
393
|
+
path: 'tee-status',
|
|
394
|
+
component: 'TEEStatusPanel', // In actual code this would be the component
|
|
395
|
+
icon: 'Shield',
|
|
396
|
+
public: false,
|
|
397
|
+
shortLabel: 'TEE',
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
|
|
401
|
+
expect(panels).toHaveLength(1);
|
|
402
|
+
expect(panels[0].name).toBe('TEE Status');
|
|
403
|
+
expect(panels[0].path).toBe('tee-status');
|
|
404
|
+
expect(panels[0].public).toBe(false);
|
|
405
|
+
expect(panels[0].shortLabel).toBe('TEE');
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
describe('TEE Frontend Performance', () => {
|
|
411
|
+
test('should handle multiple rapid status updates', async () => {
|
|
412
|
+
const responses = [
|
|
413
|
+
{ tee_mode: 'development', tee_vendor: 'intel' },
|
|
414
|
+
{ tee_mode: 'production', tee_vendor: 'amd' },
|
|
415
|
+
{ tee_mode: 'test', tee_vendor: 'arm' },
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
for (const response of responses) {
|
|
419
|
+
mockFetch.mockResolvedValueOnce({
|
|
420
|
+
ok: true,
|
|
421
|
+
json: async () => response,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const result = await fetch('/mr-tee-status');
|
|
425
|
+
const data = await result.json();
|
|
426
|
+
|
|
427
|
+
expect(data.tee_mode).toBe(response.tee_mode);
|
|
428
|
+
expect(data.tee_vendor).toBe(response.tee_vendor);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
expect(mockFetch).toHaveBeenCalledTimes(3);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test('should handle concurrent requests gracefully', async () => {
|
|
435
|
+
const mockResponse = {
|
|
436
|
+
tee_mode: 'development',
|
|
437
|
+
tee_vendor: 'intel',
|
|
438
|
+
timestamp: new Date().toISOString(),
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
mockFetch.mockResolvedValue({
|
|
442
|
+
ok: true,
|
|
443
|
+
json: async () => mockResponse,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// Simulate concurrent requests
|
|
447
|
+
const requests = Array(5)
|
|
448
|
+
.fill(null)
|
|
449
|
+
.map(() => fetch('/mr-tee-status').then((r) => r.json()));
|
|
450
|
+
|
|
451
|
+
const results = await Promise.all(requests);
|
|
452
|
+
|
|
453
|
+
expect(results).toHaveLength(5);
|
|
454
|
+
results.forEach((result) => {
|
|
455
|
+
expect(result.tee_mode).toBe('development');
|
|
456
|
+
expect(result.tee_vendor).toBe('intel');
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
});
|
|
@@ -32,7 +32,9 @@ describe('TEE Starter Plugin', () => {
|
|
|
32
32
|
expect(teeStarterPlugin.evaluators).toBeUndefined();
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
it('should have
|
|
36
|
-
expect(teeStarterPlugin.services).
|
|
35
|
+
it('should have the StarterService for TEE functionality', () => {
|
|
36
|
+
expect(teeStarterPlugin.services).toBeDefined();
|
|
37
|
+
expect(teeStarterPlugin.services?.length).toBe(1);
|
|
38
|
+
expect(teeStarterPlugin.services?.[0].name).toBe('StarterService');
|
|
37
39
|
});
|
|
38
40
|
});
|
|
@@ -2,13 +2,22 @@ import { describe, it, expect } from 'bun:test';
|
|
|
2
2
|
import teeStarterPlugin from '../src/plugin';
|
|
3
3
|
|
|
4
4
|
describe('Plugin Routes', () => {
|
|
5
|
-
it('should
|
|
6
|
-
// Our plugin
|
|
5
|
+
it('should have TEE-specific routes for status and frontend', () => {
|
|
6
|
+
// Our plugin has routes for TEE status and frontend panels
|
|
7
7
|
expect(teeStarterPlugin.routes).toBeDefined();
|
|
8
|
-
expect(teeStarterPlugin.routes?.length).toBe(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
expect(teeStarterPlugin.routes?.length).toBe(2);
|
|
9
|
+
|
|
10
|
+
// Check for mr-tee-status route
|
|
11
|
+
const statusRoute = teeStarterPlugin.routes?.find((r) => r.name === 'mr-tee-status-route');
|
|
12
|
+
expect(statusRoute).toBeDefined();
|
|
13
|
+
expect(statusRoute?.path).toBe('/mr-tee-status');
|
|
14
|
+
expect(statusRoute?.type).toBe('GET');
|
|
15
|
+
|
|
16
|
+
// Check for TEE Status panel route
|
|
17
|
+
const panelRoute = teeStarterPlugin.routes?.find((r) => r.name === 'TEE Status');
|
|
18
|
+
expect(panelRoute).toBeDefined();
|
|
19
|
+
expect(panelRoute?.path).toBe('/public/tee-status');
|
|
20
|
+
expect(panelRoute?.type).toBe('GET');
|
|
12
21
|
});
|
|
13
22
|
|
|
14
23
|
it('should have correct plugin configuration', () => {
|