@inkeep/agents-cli 0.1.5 → 0.1.7
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/SUPPLEMENTAL_TERMS.md +40 -0
- package/dist/commands/create.d.ts +12 -0
- package/dist/commands/create.js +869 -0
- package/dist/config.d.ts +4 -4
- package/dist/index.js +5346 -20414
- package/package.json +15 -6
- package/dist/__tests__/api.test.d.ts +0 -1
- package/dist/__tests__/api.test.js +0 -257
- package/dist/__tests__/cli.test.d.ts +0 -1
- package/dist/__tests__/cli.test.js +0 -153
- package/dist/__tests__/commands/config.test.d.ts +0 -1
- package/dist/__tests__/commands/config.test.js +0 -154
- package/dist/__tests__/commands/init.test.d.ts +0 -1
- package/dist/__tests__/commands/init.test.js +0 -186
- package/dist/__tests__/commands/pull.test.d.ts +0 -1
- package/dist/__tests__/commands/pull.test.js +0 -54
- package/dist/__tests__/commands/push-spinner.test.d.ts +0 -1
- package/dist/__tests__/commands/push-spinner.test.js +0 -127
- package/dist/__tests__/commands/push.test.d.ts +0 -1
- package/dist/__tests__/commands/push.test.js +0 -265
- package/dist/__tests__/config-validation.test.d.ts +0 -1
- package/dist/__tests__/config-validation.test.js +0 -98
- package/dist/__tests__/package.test.d.ts +0 -1
- package/dist/__tests__/package.test.js +0 -82
- package/dist/__tests__/utils/json-comparator.test.d.ts +0 -1
- package/dist/__tests__/utils/json-comparator.test.js +0 -174
- package/dist/__tests__/utils/ts-loader.test.d.ts +0 -1
- package/dist/__tests__/utils/ts-loader.test.js +0 -232
- package/dist/api.d.ts +0 -23
- package/dist/api.js +0 -140
- package/dist/commands/chat-enhanced.d.ts +0 -7
- package/dist/commands/chat-enhanced.js +0 -396
- package/dist/commands/chat.d.ts +0 -5
- package/dist/commands/chat.js +0 -125
- package/dist/commands/config.d.ts +0 -6
- package/dist/commands/config.js +0 -128
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.js +0 -171
- package/dist/commands/list-graphs.d.ts +0 -6
- package/dist/commands/list-graphs.js +0 -131
- package/dist/commands/pull.d.ts +0 -15
- package/dist/commands/pull.js +0 -305
- package/dist/commands/pull.llm-generate.d.ts +0 -10
- package/dist/commands/pull.llm-generate.js +0 -184
- package/dist/commands/push.d.ts +0 -6
- package/dist/commands/push.js +0 -268
- package/dist/exports.d.ts +0 -2
- package/dist/exports.js +0 -2
- package/dist/index.js.map +0 -7
- package/dist/types/config.d.ts +0 -9
- package/dist/types/config.js +0 -3
- package/dist/types/graph.d.ts +0 -10
- package/dist/types/graph.js +0 -1
- package/dist/utils/json-comparator.d.ts +0 -60
- package/dist/utils/json-comparator.js +0 -222
- package/dist/utils/mcp-runner.d.ts +0 -6
- package/dist/utils/mcp-runner.js +0 -147
- package/dist/utils/ts-loader.d.ts +0 -5
- package/dist/utils/ts-loader.js +0 -145
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { validateConfiguration } from '../config.js';
|
|
3
|
-
// Save original env and cwd
|
|
4
|
-
const originalEnv = process.env;
|
|
5
|
-
const originalCwd = process.cwd();
|
|
6
|
-
// Mock the file system to prevent finding actual config files
|
|
7
|
-
vi.mock('node:fs', () => ({
|
|
8
|
-
existsSync: vi.fn(() => false),
|
|
9
|
-
}));
|
|
10
|
-
// Mock process.cwd to avoid loading the actual config file
|
|
11
|
-
vi.mock('node:process', () => ({
|
|
12
|
-
cwd: () => '/tmp/test-cli',
|
|
13
|
-
}));
|
|
14
|
-
describe('Configuration Validation', () => {
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
vi.clearAllMocks();
|
|
17
|
-
process.env = { ...originalEnv };
|
|
18
|
-
delete process.env.INKEEP_API_URL;
|
|
19
|
-
delete process.env.INKEEP_AGENTS_MANAGE_API_URL;
|
|
20
|
-
delete process.env.INKEEP_EXECUTION_API_URL;
|
|
21
|
-
});
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
process.env = originalEnv;
|
|
24
|
-
vi.restoreAllMocks();
|
|
25
|
-
});
|
|
26
|
-
describe('validateConfiguration', () => {
|
|
27
|
-
describe('Valid Configurations', () => {
|
|
28
|
-
it('should accept --tenant-id with --management-api-url and --execution-api-url flags', async () => {
|
|
29
|
-
const config = await validateConfiguration('test-tenant', 'http://localhost:3002', 'http://localhost:3003', undefined);
|
|
30
|
-
expect(config.tenantId).toBe('test-tenant');
|
|
31
|
-
expect(config.managementApiUrl).toBe('http://localhost:3002');
|
|
32
|
-
expect(config.executionApiUrl).toBe('http://localhost:3003');
|
|
33
|
-
expect(config.sources.tenantId).toBe('command-line flag (--tenant-id)');
|
|
34
|
-
expect(config.sources.managementApiUrl).toBe('command-line flag (--management-api-url)');
|
|
35
|
-
expect(config.sources.executionApiUrl).toBe('command-line flag (--execution-api-url)');
|
|
36
|
-
});
|
|
37
|
-
it('should use environment variables when no flags provided', async () => {
|
|
38
|
-
process.env.INKEEP_AGENTS_MANAGE_API_URL = 'http://localhost:9090';
|
|
39
|
-
process.env.INKEEP_EXECUTION_API_URL = 'http://localhost:9091';
|
|
40
|
-
const config = await validateConfiguration(undefined, undefined, undefined, undefined);
|
|
41
|
-
expect(config.tenantId).toBe('env-tenant');
|
|
42
|
-
expect(config.managementApiUrl).toBe('http://localhost:9090');
|
|
43
|
-
expect(config.executionApiUrl).toBe('http://localhost:9091');
|
|
44
|
-
expect(config.sources.managementApiUrl).toBe('environment variable (INKEEP_AGENTS_MANAGE_API_URL)');
|
|
45
|
-
expect(config.sources.executionApiUrl).toBe('environment variable (INKEEP_EXECUTION_API_URL)');
|
|
46
|
-
});
|
|
47
|
-
it('should allow command-line flags to override environment variables', async () => {
|
|
48
|
-
process.env.INKEEP_AGENTS_MANAGE_API_URL = 'http://localhost:9090';
|
|
49
|
-
process.env.INKEEP_EXECUTION_API_URL = 'http://localhost:9091';
|
|
50
|
-
const config = await validateConfiguration('cli-tenant', 'http://cli-management', 'http://cli-execution', undefined);
|
|
51
|
-
expect(config.tenantId).toBe('cli-tenant');
|
|
52
|
-
expect(config.managementApiUrl).toBe('http://cli-management');
|
|
53
|
-
expect(config.executionApiUrl).toBe('http://cli-execution');
|
|
54
|
-
expect(config.sources.tenantId).toBe('command-line flag (--tenant-id)');
|
|
55
|
-
expect(config.sources.managementApiUrl).toBe('command-line flag (--management-api-url)');
|
|
56
|
-
expect(config.sources.executionApiUrl).toBe('command-line flag (--execution-api-url)');
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe('Invalid Configurations', () => {
|
|
60
|
-
it('should reject --config-file-path with --tenant-id', async () => {
|
|
61
|
-
await expect(validateConfiguration('test-tenant', undefined, undefined, '/path/to/config.js')).rejects.toThrow('Invalid configuration combination');
|
|
62
|
-
});
|
|
63
|
-
it('should reject --tenant-id without both API URLs', async () => {
|
|
64
|
-
await expect(validateConfiguration('test-tenant', undefined, undefined, undefined)).rejects.toThrow('--tenant-id requires --management-api-url and --execution-api-url');
|
|
65
|
-
});
|
|
66
|
-
it('should reject when no configuration is provided', async () => {
|
|
67
|
-
await expect(validateConfiguration(undefined, undefined, undefined, undefined)).rejects.toThrow('No configuration found');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
describe('Configuration Source Tracking', () => {
|
|
71
|
-
it('should correctly identify command-line flag sources', async () => {
|
|
72
|
-
const config = await validateConfiguration('cli-tenant', 'http://cli-management', 'http://cli-execution', undefined);
|
|
73
|
-
expect(config.sources.tenantId).toBe('command-line flag (--tenant-id)');
|
|
74
|
-
expect(config.sources.managementApiUrl).toBe('command-line flag (--management-api-url)');
|
|
75
|
-
expect(config.sources.executionApiUrl).toBe('command-line flag (--execution-api-url)');
|
|
76
|
-
expect(config.sources.configFile).toBeUndefined();
|
|
77
|
-
});
|
|
78
|
-
it('should correctly identify environment variable sources', async () => {
|
|
79
|
-
process.env.INKEEP_AGENTS_MANAGE_API_URL = 'http://env-management';
|
|
80
|
-
process.env.INKEEP_EXECUTION_API_URL = 'http://env-execution';
|
|
81
|
-
const config = await validateConfiguration(undefined, undefined, undefined, undefined);
|
|
82
|
-
expect(config.sources.managementApiUrl).toBe('environment variable (INKEEP_AGENTS_MANAGE_API_URL)');
|
|
83
|
-
expect(config.sources.executionApiUrl).toBe('environment variable (INKEEP_EXECUTION_API_URL)');
|
|
84
|
-
});
|
|
85
|
-
it('should correctly identify mixed sources with env and flag', async () => {
|
|
86
|
-
process.env.INKEEP_AGENTS_MANAGE_API_URL = 'http://env-management';
|
|
87
|
-
process.env.INKEEP_EXECUTION_API_URL = 'http://env-execution';
|
|
88
|
-
// Override only the management API URL with a flag
|
|
89
|
-
const config = await validateConfiguration(undefined, 'http://override-management', undefined, undefined);
|
|
90
|
-
expect(config.tenantId).toBe('env-tenant');
|
|
91
|
-
expect(config.managementApiUrl).toBe('http://override-management');
|
|
92
|
-
expect(config.executionApiUrl).toBe('http://env-execution');
|
|
93
|
-
expect(config.sources.managementApiUrl).toBe('command-line flag (--management-api-url)');
|
|
94
|
-
expect(config.sources.executionApiUrl).toBe('environment variable (INKEEP_EXECUTION_API_URL)');
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = dirname(__filename);
|
|
7
|
-
describe('Package Configuration', () => {
|
|
8
|
-
const packageJsonPath = join(__dirname, '..', '..', 'package.json');
|
|
9
|
-
const tsConfigTypeCheckPath = join(__dirname, '..', '..', 'tsconfig.typecheck.json');
|
|
10
|
-
let packageJson;
|
|
11
|
-
let tsConfigTypeCheck;
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
const packageJsonContent = readFileSync(packageJsonPath, 'utf-8');
|
|
14
|
-
packageJson = JSON.parse(packageJsonContent);
|
|
15
|
-
const tsConfigTypeCheckContent = readFileSync(tsConfigTypeCheckPath, 'utf-8');
|
|
16
|
-
tsConfigTypeCheck = JSON.parse(tsConfigTypeCheckContent);
|
|
17
|
-
});
|
|
18
|
-
describe('package.json', () => {
|
|
19
|
-
it('should have correct package name', () => {
|
|
20
|
-
expect(packageJson.name).toBe('@inkeep/agents-cli');
|
|
21
|
-
});
|
|
22
|
-
it('should have a valid version', () => {
|
|
23
|
-
expect(packageJson.version).toMatch(/^\d+\.\d+\.\d+$/);
|
|
24
|
-
});
|
|
25
|
-
it('should have correct bin configuration', () => {
|
|
26
|
-
expect(packageJson.bin).toEqual({
|
|
27
|
-
inkeep: './dist/index.js',
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
it('should have correct main entry point', () => {
|
|
31
|
-
expect(packageJson.main).toBe('./dist/exports.js');
|
|
32
|
-
});
|
|
33
|
-
it('should be set to module type', () => {
|
|
34
|
-
expect(packageJson.type).toBe('module');
|
|
35
|
-
});
|
|
36
|
-
it('should have required dependencies', () => {
|
|
37
|
-
expect(packageJson.dependencies).toHaveProperty('commander');
|
|
38
|
-
expect(packageJson.dependencies).toHaveProperty('chalk');
|
|
39
|
-
});
|
|
40
|
-
it('should have required dev dependencies', () => {
|
|
41
|
-
expect(packageJson.devDependencies).toHaveProperty('typescript');
|
|
42
|
-
expect(packageJson.devDependencies).toHaveProperty('vitest');
|
|
43
|
-
expect(packageJson.devDependencies).toHaveProperty('@types/node');
|
|
44
|
-
});
|
|
45
|
-
it('should have test scripts', () => {
|
|
46
|
-
expect(packageJson.scripts).toHaveProperty('test');
|
|
47
|
-
expect(packageJson.scripts).toHaveProperty('test:watch');
|
|
48
|
-
expect(packageJson.scripts).toHaveProperty('test:coverage');
|
|
49
|
-
});
|
|
50
|
-
it('should have typecheck script', () => {
|
|
51
|
-
expect(packageJson.scripts).toHaveProperty('typecheck');
|
|
52
|
-
expect(packageJson.scripts.typecheck).toBe('tsc --noEmit --project tsconfig.typecheck.json');
|
|
53
|
-
});
|
|
54
|
-
it('should have correct Node.js engine requirement', () => {
|
|
55
|
-
expect(packageJson.engines.node).toBe('>=20.x');
|
|
56
|
-
});
|
|
57
|
-
it('should have correct author', () => {
|
|
58
|
-
expect(packageJson.author).toBe('Inkeep <support@inkeep.com>');
|
|
59
|
-
});
|
|
60
|
-
it('should have correct license reference', () => {
|
|
61
|
-
expect(packageJson.license).toBe('SEE LICENSE IN LICENSE.md');
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
describe('tsconfig.typecheck.json', () => {
|
|
65
|
-
it('should extend base tsconfig', () => {
|
|
66
|
-
expect(tsConfigTypeCheck.extends).toBe('./tsconfig.json');
|
|
67
|
-
});
|
|
68
|
-
it('should have correct compiler options', () => {
|
|
69
|
-
expect(tsConfigTypeCheck.compilerOptions).toHaveProperty('noEmit', true);
|
|
70
|
-
expect(tsConfigTypeCheck.compilerOptions).toHaveProperty('skipLibCheck', true);
|
|
71
|
-
});
|
|
72
|
-
it('should include src files', () => {
|
|
73
|
-
expect(tsConfigTypeCheck.include).toContain('src/**/*');
|
|
74
|
-
});
|
|
75
|
-
it('should exclude test files and build artifacts', () => {
|
|
76
|
-
expect(tsConfigTypeCheck.exclude).toContain('node_modules');
|
|
77
|
-
expect(tsConfigTypeCheck.exclude).toContain('dist');
|
|
78
|
-
expect(tsConfigTypeCheck.exclude).toContain('**/*.test.ts');
|
|
79
|
-
expect(tsConfigTypeCheck.exclude).toContain('src/__tests__/**/*');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { compareJsonObjects, getDifferenceSummary, normalizeJsonObject, } from '../../utils/json-comparator.js';
|
|
3
|
-
describe('json-comparator', () => {
|
|
4
|
-
describe('compareJsonObjects', () => {
|
|
5
|
-
it('should return true for identical objects', () => {
|
|
6
|
-
const obj1 = { a: 1, b: 'test', c: [1, 2, 3] };
|
|
7
|
-
const obj2 = { a: 1, b: 'test', c: [1, 2, 3] };
|
|
8
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
9
|
-
expect(result.isEqual).toBe(true);
|
|
10
|
-
expect(result.differences).toHaveLength(0);
|
|
11
|
-
});
|
|
12
|
-
it('should return false for different objects', () => {
|
|
13
|
-
const obj1 = { a: 1, b: 'test' };
|
|
14
|
-
const obj2 = { a: 2, b: 'test' };
|
|
15
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
16
|
-
expect(result.isEqual).toBe(false);
|
|
17
|
-
expect(result.differences).toHaveLength(1);
|
|
18
|
-
expect(result.differences[0].path).toBe('a');
|
|
19
|
-
expect(result.differences[0].type).toBe('different');
|
|
20
|
-
});
|
|
21
|
-
it('should handle arrays with different order when ignoreArrayOrder is true', () => {
|
|
22
|
-
const obj1 = { items: [1, 2, 3] };
|
|
23
|
-
const obj2 = { items: [3, 1, 2] };
|
|
24
|
-
const result = compareJsonObjects(obj1, obj2, { ignoreArrayOrder: true });
|
|
25
|
-
expect(result.isEqual).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
it('should detect arrays with different order when ignoreArrayOrder is false', () => {
|
|
28
|
-
const obj1 = { items: [1, 2, 3] };
|
|
29
|
-
const obj2 = { items: [3, 1, 2] };
|
|
30
|
-
const result = compareJsonObjects(obj1, obj2, { ignoreArrayOrder: false });
|
|
31
|
-
expect(result.isEqual).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
it('should handle missing keys', () => {
|
|
34
|
-
const obj1 = { a: 1, b: 2 };
|
|
35
|
-
const obj2 = { a: 1 };
|
|
36
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
37
|
-
expect(result.isEqual).toBe(false);
|
|
38
|
-
expect(result.differences).toHaveLength(1);
|
|
39
|
-
expect(result.differences[0].type).toBe('extra');
|
|
40
|
-
expect(result.differences[0].path).toBe('b');
|
|
41
|
-
});
|
|
42
|
-
it('should handle extra keys', () => {
|
|
43
|
-
const obj1 = { a: 1 };
|
|
44
|
-
const obj2 = { a: 1, b: 2 };
|
|
45
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
46
|
-
expect(result.isEqual).toBe(false);
|
|
47
|
-
expect(result.differences).toHaveLength(1);
|
|
48
|
-
expect(result.differences[0].type).toBe('missing');
|
|
49
|
-
expect(result.differences[0].path).toBe('b');
|
|
50
|
-
});
|
|
51
|
-
it('should handle nested objects', () => {
|
|
52
|
-
const obj1 = { user: { name: 'John', age: 30 } };
|
|
53
|
-
const obj2 = { user: { name: 'John', age: 31 } };
|
|
54
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
55
|
-
expect(result.isEqual).toBe(false);
|
|
56
|
-
expect(result.differences).toHaveLength(1);
|
|
57
|
-
expect(result.differences[0].path).toBe('user.age');
|
|
58
|
-
});
|
|
59
|
-
it('should handle type mismatches', () => {
|
|
60
|
-
const obj1 = { value: '123' };
|
|
61
|
-
const obj2 = { value: 123 };
|
|
62
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
63
|
-
expect(result.isEqual).toBe(false);
|
|
64
|
-
expect(result.differences).toHaveLength(1);
|
|
65
|
-
expect(result.differences[0].type).toBe('type_mismatch');
|
|
66
|
-
});
|
|
67
|
-
it('should ignore specified paths', () => {
|
|
68
|
-
const obj1 = { a: 1, b: 2, c: 3 };
|
|
69
|
-
const obj2 = { a: 1, b: 999, c: 3 };
|
|
70
|
-
const result = compareJsonObjects(obj1, obj2, { ignorePaths: ['b'] });
|
|
71
|
-
expect(result.isEqual).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it('should ignore paths with wildcards', () => {
|
|
74
|
-
const obj1 = { user: { name: 'John', age: 30 }, meta: { created: '2023-01-01' } };
|
|
75
|
-
const obj2 = { user: { name: 'John', age: 30 }, meta: { created: '2023-01-02' } };
|
|
76
|
-
const result = compareJsonObjects(obj1, obj2, { ignorePaths: ['meta.*'] });
|
|
77
|
-
expect(result.isEqual).toBe(true);
|
|
78
|
-
});
|
|
79
|
-
it('should handle case insensitive comparison', () => {
|
|
80
|
-
const obj1 = { name: 'John' };
|
|
81
|
-
const obj2 = { name: 'JOHN' };
|
|
82
|
-
const result = compareJsonObjects(obj1, obj2, { ignoreCase: true });
|
|
83
|
-
expect(result.isEqual).toBe(true);
|
|
84
|
-
});
|
|
85
|
-
it('should handle whitespace insensitive comparison', () => {
|
|
86
|
-
const obj1 = { description: 'Hello world' };
|
|
87
|
-
const obj2 = { description: ' Hello world ' };
|
|
88
|
-
const result = compareJsonObjects(obj1, obj2, { ignoreWhitespace: true });
|
|
89
|
-
expect(result.isEqual).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
it('should provide accurate statistics', () => {
|
|
92
|
-
const obj1 = { a: 1, b: 2, c: 3 };
|
|
93
|
-
const obj2 = { a: 1, b: 999, d: 4 };
|
|
94
|
-
const result = compareJsonObjects(obj1, obj2);
|
|
95
|
-
expect(result.stats.totalKeys).toBe(4);
|
|
96
|
-
expect(result.stats.differentKeys).toBe(1); // 'b' has different values
|
|
97
|
-
expect(result.stats.missingKeys).toBe(1); // 'd' is missing in obj1
|
|
98
|
-
expect(result.stats.extraKeys).toBe(1); // 'c' is extra in obj1
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
describe('normalizeJsonObject', () => {
|
|
102
|
-
it('should normalize strings with case and whitespace options', () => {
|
|
103
|
-
const obj = { name: ' John DOE ', items: ['A', 'B', 'C'] };
|
|
104
|
-
const normalized = normalizeJsonObject(obj, {
|
|
105
|
-
ignoreCase: true,
|
|
106
|
-
ignoreWhitespace: true,
|
|
107
|
-
ignoreArrayOrder: true,
|
|
108
|
-
});
|
|
109
|
-
expect(normalized.name).toBe('john doe');
|
|
110
|
-
expect(normalized.items).toEqual(['a', 'b', 'c']); // Sorted alphabetically and case normalized
|
|
111
|
-
});
|
|
112
|
-
it('should sort object keys', () => {
|
|
113
|
-
const obj = { c: 3, a: 1, b: 2 };
|
|
114
|
-
const normalized = normalizeJsonObject(obj);
|
|
115
|
-
expect(Object.keys(normalized)).toEqual(['a', 'b', 'c']);
|
|
116
|
-
});
|
|
117
|
-
it('should handle nested objects', () => {
|
|
118
|
-
const obj = { user: { name: 'John', age: 30 }, meta: { version: '1.0' } };
|
|
119
|
-
const normalized = normalizeJsonObject(obj);
|
|
120
|
-
expect(Object.keys(normalized)).toEqual(['meta', 'user']);
|
|
121
|
-
expect(Object.keys(normalized.user)).toEqual(['age', 'name']);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
describe('getDifferenceSummary', () => {
|
|
125
|
-
it('should return success message for equal objects', () => {
|
|
126
|
-
const result = {
|
|
127
|
-
isEqual: true,
|
|
128
|
-
differences: [],
|
|
129
|
-
stats: { totalKeys: 0, differentKeys: 0, missingKeys: 0, extraKeys: 0 },
|
|
130
|
-
};
|
|
131
|
-
const summary = getDifferenceSummary(result);
|
|
132
|
-
expect(summary).toBe('✅ Objects are equivalent');
|
|
133
|
-
});
|
|
134
|
-
it('should return detailed summary for different objects', () => {
|
|
135
|
-
const result = {
|
|
136
|
-
isEqual: false,
|
|
137
|
-
differences: [
|
|
138
|
-
{
|
|
139
|
-
path: 'a',
|
|
140
|
-
type: 'different',
|
|
141
|
-
value1: 1,
|
|
142
|
-
value2: 2,
|
|
143
|
-
description: 'Value mismatch',
|
|
144
|
-
},
|
|
145
|
-
{ path: 'b', type: 'missing', value2: 3, description: 'Missing key' },
|
|
146
|
-
],
|
|
147
|
-
stats: { totalKeys: 2, differentKeys: 1, missingKeys: 1, extraKeys: 0 },
|
|
148
|
-
};
|
|
149
|
-
const summary = getDifferenceSummary(result);
|
|
150
|
-
expect(summary).toContain('❌ Objects differ');
|
|
151
|
-
expect(summary).toContain('Total keys: 2');
|
|
152
|
-
expect(summary).toContain('Different values: 1');
|
|
153
|
-
expect(summary).toContain('Missing keys: 1');
|
|
154
|
-
expect(summary).toContain('a: Value mismatch');
|
|
155
|
-
expect(summary).toContain('b: Missing key');
|
|
156
|
-
});
|
|
157
|
-
it('should limit displayed differences to 10', () => {
|
|
158
|
-
const differences = Array.from({ length: 15 }, (_, i) => ({
|
|
159
|
-
path: `key${i}`,
|
|
160
|
-
type: 'different',
|
|
161
|
-
value1: i,
|
|
162
|
-
value2: i + 1,
|
|
163
|
-
description: `Difference ${i}`,
|
|
164
|
-
}));
|
|
165
|
-
const result = {
|
|
166
|
-
isEqual: false,
|
|
167
|
-
differences,
|
|
168
|
-
stats: { totalKeys: 15, differentKeys: 15, missingKeys: 0, extraKeys: 0 },
|
|
169
|
-
};
|
|
170
|
-
const summary = getDifferenceSummary(result);
|
|
171
|
-
expect(summary).toContain('... and 5 more differences');
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { loadTypeScriptModule } from '../../utils/ts-loader.js';
|
|
6
|
-
describe('TypeScript Loader', () => {
|
|
7
|
-
let testDir;
|
|
8
|
-
let testGraphFile;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
// Create a unique test directory with process ID to avoid conflicts
|
|
11
|
-
const uniqueId = `${process.pid}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
12
|
-
testDir = join(tmpdir(), 'ts-loader-test', uniqueId);
|
|
13
|
-
mkdirSync(testDir, { recursive: true });
|
|
14
|
-
testGraphFile = join(testDir, 'test-graph.ts');
|
|
15
|
-
});
|
|
16
|
-
afterEach(async () => {
|
|
17
|
-
// Small delay to ensure file handles are released
|
|
18
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
19
|
-
// Clean up test directory with retries
|
|
20
|
-
if (existsSync(testDir)) {
|
|
21
|
-
rmSync(testDir, { recursive: true, force: true, maxRetries: 3 });
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
describe('loadTypeScriptModule', () => {
|
|
25
|
-
it('should load a simple TypeScript module with exports', async () => {
|
|
26
|
-
// Create a simple test module
|
|
27
|
-
const moduleContent = `
|
|
28
|
-
export const simpleValue = 'test-value';
|
|
29
|
-
export const numberValue = 42;
|
|
30
|
-
export const booleanValue = true;
|
|
31
|
-
|
|
32
|
-
export function testFunction() {
|
|
33
|
-
return 'hello world';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const testObject = {
|
|
37
|
-
id: 'test-id',
|
|
38
|
-
name: 'Test Object',
|
|
39
|
-
description: 'A test object for testing',
|
|
40
|
-
port: 3000,
|
|
41
|
-
};
|
|
42
|
-
`;
|
|
43
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
44
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
45
|
-
expect(result.simpleValue).toBe('test-value');
|
|
46
|
-
expect(result.numberValue).toBe(42);
|
|
47
|
-
expect(result.booleanValue).toBe(true);
|
|
48
|
-
expect(result.testFunction).toEqual({
|
|
49
|
-
__type: 'function',
|
|
50
|
-
name: 'testFunction',
|
|
51
|
-
});
|
|
52
|
-
expect(result.testObject).toEqual({
|
|
53
|
-
__type: 'object',
|
|
54
|
-
id: 'test-id',
|
|
55
|
-
name: 'Test Object',
|
|
56
|
-
description: 'A test object for testing',
|
|
57
|
-
port: 3000,
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
it('should handle array exports', async () => {
|
|
61
|
-
const moduleContent = `
|
|
62
|
-
export const servers = [
|
|
63
|
-
{
|
|
64
|
-
id: 'server1',
|
|
65
|
-
name: 'Test Server 1',
|
|
66
|
-
port: 3001,
|
|
67
|
-
deployment: 'local'
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: 'server2',
|
|
71
|
-
name: 'Test Server 2',
|
|
72
|
-
serverUrl: 'http://localhost:3002',
|
|
73
|
-
deployment: 'remote'
|
|
74
|
-
}
|
|
75
|
-
];
|
|
76
|
-
|
|
77
|
-
export const simpleArray = ['item1', 'item2', 'item3'];
|
|
78
|
-
`;
|
|
79
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
80
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
81
|
-
expect(result.servers.__type).toBe('array');
|
|
82
|
-
expect(result.servers.items).toHaveLength(2);
|
|
83
|
-
expect(result.servers.items[0]).toEqual({
|
|
84
|
-
id: 'server1',
|
|
85
|
-
name: 'Test Server 1',
|
|
86
|
-
port: 3001,
|
|
87
|
-
deployment: 'local',
|
|
88
|
-
});
|
|
89
|
-
expect(result.servers.items[1]).toEqual({
|
|
90
|
-
id: 'server2',
|
|
91
|
-
name: 'Test Server 2',
|
|
92
|
-
serverUrl: 'http://localhost:3002',
|
|
93
|
-
deployment: 'remote',
|
|
94
|
-
});
|
|
95
|
-
expect(result.simpleArray.__type).toBe('array');
|
|
96
|
-
expect(result.simpleArray.items).toEqual(['item1', 'item2', 'item3']);
|
|
97
|
-
});
|
|
98
|
-
it('should handle objects with methods', async () => {
|
|
99
|
-
const moduleContent = `
|
|
100
|
-
export const toolWithMethods = {
|
|
101
|
-
id: 'tool-with-methods',
|
|
102
|
-
name: 'Tool With Methods',
|
|
103
|
-
|
|
104
|
-
execute() {
|
|
105
|
-
return 'executed';
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
init() {
|
|
109
|
-
return 'initialized';
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
getServerUrl() {
|
|
113
|
-
return 'http://localhost:3000';
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
export const graphObject = {
|
|
118
|
-
getId() {
|
|
119
|
-
return 'test-graph-id';
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
`;
|
|
123
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
124
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
125
|
-
expect(result.toolWithMethods).toEqual({
|
|
126
|
-
__type: 'object',
|
|
127
|
-
id: 'tool-with-methods',
|
|
128
|
-
name: 'Tool With Methods',
|
|
129
|
-
hasExecute: true,
|
|
130
|
-
hasInit: true,
|
|
131
|
-
hasGetServerUrl: true,
|
|
132
|
-
});
|
|
133
|
-
expect(result.graphObject).toEqual({
|
|
134
|
-
__type: 'object',
|
|
135
|
-
graphId: 'test-graph-id',
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
it('should handle module loading errors gracefully', async () => {
|
|
139
|
-
// Create a module with syntax errors
|
|
140
|
-
const moduleContent = `
|
|
141
|
-
export const badSyntax = {
|
|
142
|
-
// Missing closing brace
|
|
143
|
-
id: 'test'
|
|
144
|
-
`;
|
|
145
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
146
|
-
await expect(loadTypeScriptModule(testGraphFile)).rejects.toThrow();
|
|
147
|
-
});
|
|
148
|
-
it('should handle non-existent files', async () => {
|
|
149
|
-
const nonExistentFile = join(testDir, 'non-existent.ts');
|
|
150
|
-
await expect(loadTypeScriptModule(nonExistentFile)).rejects.toThrow();
|
|
151
|
-
});
|
|
152
|
-
it('should handle empty modules', async () => {
|
|
153
|
-
writeFileSync(testGraphFile, '');
|
|
154
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
155
|
-
// Empty modules may have a default export object
|
|
156
|
-
expect(result).toEqual(expect.objectContaining({
|
|
157
|
-
default: expect.objectContaining({
|
|
158
|
-
__type: 'object',
|
|
159
|
-
}),
|
|
160
|
-
}));
|
|
161
|
-
});
|
|
162
|
-
it('should handle complex nested objects', async () => {
|
|
163
|
-
const moduleContent = `
|
|
164
|
-
export const complexConfig = {
|
|
165
|
-
servers: [
|
|
166
|
-
{
|
|
167
|
-
id: 'nested-server',
|
|
168
|
-
name: 'Nested Server',
|
|
169
|
-
transport: 'http',
|
|
170
|
-
deployment: 'local'
|
|
171
|
-
}
|
|
172
|
-
],
|
|
173
|
-
metadata: {
|
|
174
|
-
version: '1.0.0',
|
|
175
|
-
author: 'test'
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
`;
|
|
179
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
180
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
181
|
-
expect(result.complexConfig.__type).toBe('object');
|
|
182
|
-
// Note: The loader has specific handling for certain property names
|
|
183
|
-
// It may not serialize arbitrary nested structures completely
|
|
184
|
-
});
|
|
185
|
-
it('should use test environment defaults when no environment is set', async () => {
|
|
186
|
-
// Clear environment variables that might affect the test
|
|
187
|
-
const originalEnv = process.env.ENVIRONMENT;
|
|
188
|
-
delete process.env.ENVIRONMENT;
|
|
189
|
-
const moduleContent = `
|
|
190
|
-
export const envValue = process.env.ENVIRONMENT;
|
|
191
|
-
export const dbFileName = process.env.DB_FILE_NAME;
|
|
192
|
-
`;
|
|
193
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
194
|
-
try {
|
|
195
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
196
|
-
// The loader should set test defaults
|
|
197
|
-
expect(result.envValue).toBe('test');
|
|
198
|
-
expect(result.dbFileName).toBe(':memory:');
|
|
199
|
-
expect(result.tenantId).toBe('test-tenant');
|
|
200
|
-
}
|
|
201
|
-
finally {
|
|
202
|
-
if (originalEnv !== undefined) {
|
|
203
|
-
process.env.ENVIRONMENT = originalEnv;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
it('should preserve existing environment variables', async () => {
|
|
208
|
-
const originalEnv = process.env.ENVIRONMENT;
|
|
209
|
-
process.env.ENVIRONMENT = 'production';
|
|
210
|
-
process.env.CUSTOM_VAR = 'custom-value';
|
|
211
|
-
const moduleContent = `
|
|
212
|
-
export const envValue = process.env.ENVIRONMENT;
|
|
213
|
-
export const customVar = process.env.CUSTOM_VAR;
|
|
214
|
-
`;
|
|
215
|
-
writeFileSync(testGraphFile, moduleContent);
|
|
216
|
-
try {
|
|
217
|
-
const result = await loadTypeScriptModule(testGraphFile);
|
|
218
|
-
expect(result.envValue).toBe('production');
|
|
219
|
-
expect(result.customVar).toBe('custom-value');
|
|
220
|
-
}
|
|
221
|
-
finally {
|
|
222
|
-
if (originalEnv !== undefined) {
|
|
223
|
-
process.env.ENVIRONMENT = originalEnv;
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
delete process.env.ENVIRONMENT;
|
|
227
|
-
}
|
|
228
|
-
delete process.env.CUSTOM_VAR;
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
});
|
package/dist/api.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
declare abstract class BaseApiClient {
|
|
2
|
-
protected apiUrl: string;
|
|
3
|
-
protected tenantId: string | undefined;
|
|
4
|
-
protected projectId: string;
|
|
5
|
-
protected constructor(apiUrl: string, tenantId: string | undefined, projectId: string);
|
|
6
|
-
protected checkTenantId(): string;
|
|
7
|
-
getTenantId(): string | undefined;
|
|
8
|
-
getProjectId(): string;
|
|
9
|
-
getApiUrl(): string;
|
|
10
|
-
}
|
|
11
|
-
export declare class ManagementApiClient extends BaseApiClient {
|
|
12
|
-
private constructor();
|
|
13
|
-
static create(apiUrl?: string, configPath?: string, tenantIdOverride?: string, projectIdOverride?: string): Promise<ManagementApiClient>;
|
|
14
|
-
listGraphs(): Promise<any[]>;
|
|
15
|
-
getGraph(graphId: string): Promise<any>;
|
|
16
|
-
pushGraph(graphDefinition: any): Promise<any>;
|
|
17
|
-
}
|
|
18
|
-
export declare class ExecutionApiClient extends BaseApiClient {
|
|
19
|
-
private constructor();
|
|
20
|
-
static create(apiUrl?: string, configPath?: string, tenantIdOverride?: string, projectIdOverride?: string): Promise<ExecutionApiClient>;
|
|
21
|
-
chatCompletion(graphId: string, messages: any[], conversationId?: string): Promise<ReadableStream<Uint8Array> | string>;
|
|
22
|
-
}
|
|
23
|
-
export {};
|