@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.
Files changed (59) hide show
  1. package/SUPPLEMENTAL_TERMS.md +40 -0
  2. package/dist/commands/create.d.ts +12 -0
  3. package/dist/commands/create.js +869 -0
  4. package/dist/config.d.ts +4 -4
  5. package/dist/index.js +5346 -20414
  6. package/package.json +15 -6
  7. package/dist/__tests__/api.test.d.ts +0 -1
  8. package/dist/__tests__/api.test.js +0 -257
  9. package/dist/__tests__/cli.test.d.ts +0 -1
  10. package/dist/__tests__/cli.test.js +0 -153
  11. package/dist/__tests__/commands/config.test.d.ts +0 -1
  12. package/dist/__tests__/commands/config.test.js +0 -154
  13. package/dist/__tests__/commands/init.test.d.ts +0 -1
  14. package/dist/__tests__/commands/init.test.js +0 -186
  15. package/dist/__tests__/commands/pull.test.d.ts +0 -1
  16. package/dist/__tests__/commands/pull.test.js +0 -54
  17. package/dist/__tests__/commands/push-spinner.test.d.ts +0 -1
  18. package/dist/__tests__/commands/push-spinner.test.js +0 -127
  19. package/dist/__tests__/commands/push.test.d.ts +0 -1
  20. package/dist/__tests__/commands/push.test.js +0 -265
  21. package/dist/__tests__/config-validation.test.d.ts +0 -1
  22. package/dist/__tests__/config-validation.test.js +0 -98
  23. package/dist/__tests__/package.test.d.ts +0 -1
  24. package/dist/__tests__/package.test.js +0 -82
  25. package/dist/__tests__/utils/json-comparator.test.d.ts +0 -1
  26. package/dist/__tests__/utils/json-comparator.test.js +0 -174
  27. package/dist/__tests__/utils/ts-loader.test.d.ts +0 -1
  28. package/dist/__tests__/utils/ts-loader.test.js +0 -232
  29. package/dist/api.d.ts +0 -23
  30. package/dist/api.js +0 -140
  31. package/dist/commands/chat-enhanced.d.ts +0 -7
  32. package/dist/commands/chat-enhanced.js +0 -396
  33. package/dist/commands/chat.d.ts +0 -5
  34. package/dist/commands/chat.js +0 -125
  35. package/dist/commands/config.d.ts +0 -6
  36. package/dist/commands/config.js +0 -128
  37. package/dist/commands/init.d.ts +0 -5
  38. package/dist/commands/init.js +0 -171
  39. package/dist/commands/list-graphs.d.ts +0 -6
  40. package/dist/commands/list-graphs.js +0 -131
  41. package/dist/commands/pull.d.ts +0 -15
  42. package/dist/commands/pull.js +0 -305
  43. package/dist/commands/pull.llm-generate.d.ts +0 -10
  44. package/dist/commands/pull.llm-generate.js +0 -184
  45. package/dist/commands/push.d.ts +0 -6
  46. package/dist/commands/push.js +0 -268
  47. package/dist/exports.d.ts +0 -2
  48. package/dist/exports.js +0 -2
  49. package/dist/index.js.map +0 -7
  50. package/dist/types/config.d.ts +0 -9
  51. package/dist/types/config.js +0 -3
  52. package/dist/types/graph.d.ts +0 -10
  53. package/dist/types/graph.js +0 -1
  54. package/dist/utils/json-comparator.d.ts +0 -60
  55. package/dist/utils/json-comparator.js +0 -222
  56. package/dist/utils/mcp-runner.d.ts +0 -6
  57. package/dist/utils/mcp-runner.js +0 -147
  58. package/dist/utils/ts-loader.d.ts +0 -5
  59. package/dist/utils/ts-loader.js +0 -145
@@ -1,186 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { initCommand } from '../../commands/init.js';
3
- // Mock inquirer
4
- vi.mock('inquirer', () => ({
5
- default: {
6
- prompt: vi.fn(),
7
- },
8
- }));
9
- // Mock fs functions
10
- vi.mock('node:fs', async () => {
11
- const actual = await vi.importActual('node:fs');
12
- return {
13
- ...actual,
14
- existsSync: vi.fn(),
15
- writeFileSync: vi.fn(),
16
- readdirSync: vi.fn(),
17
- };
18
- });
19
- describe('Init Command', () => {
20
- let consoleLogSpy;
21
- let consoleErrorSpy;
22
- let processExitSpy;
23
- beforeEach(() => {
24
- consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
25
- consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
26
- processExitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
27
- throw new Error('process.exit called');
28
- });
29
- vi.clearAllMocks();
30
- });
31
- afterEach(() => {
32
- consoleLogSpy.mockRestore();
33
- consoleErrorSpy.mockRestore();
34
- processExitSpy.mockRestore();
35
- });
36
- describe('initCommand', () => {
37
- it('should create a new config file when none exists', async () => {
38
- const { existsSync, writeFileSync, readdirSync } = await import('node:fs');
39
- const inquirer = await import('inquirer');
40
- vi.mocked(existsSync).mockReturnValue(false);
41
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
42
- const promptMock = vi.mocked(inquirer.default.prompt);
43
- promptMock
44
- .mockResolvedValueOnce({
45
- confirmedPath: './inkeep.config.ts',
46
- })
47
- .mockResolvedValueOnce({
48
- tenantId: 'test-tenant-123',
49
- apiUrl: 'http://localhost:3002',
50
- });
51
- await initCommand();
52
- expect(existsSync).toHaveBeenCalledWith(expect.stringContaining('inkeep.config.ts'));
53
- expect(writeFileSync).toHaveBeenCalledWith(expect.stringContaining('inkeep.config.ts'), expect.stringContaining("tenantId: 'test-tenant-123'"));
54
- expect(writeFileSync).toHaveBeenCalledWith(expect.stringContaining('inkeep.config.ts'), expect.stringContaining("apiUrl: 'http://localhost:3002'"));
55
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.any(String), // The checkmark
56
- expect.stringContaining('Created'));
57
- });
58
- it('should prompt for overwrite when config file exists', async () => {
59
- const { existsSync, writeFileSync, readdirSync } = await import('node:fs');
60
- const inquirer = await import('inquirer');
61
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
62
- vi.mocked(existsSync).mockImplementation((path) => {
63
- return path.toString().includes('inkeep.config.ts');
64
- });
65
- const promptMock = vi.mocked(inquirer.default.prompt);
66
- promptMock
67
- .mockResolvedValueOnce({ confirmedPath: './inkeep.config.ts' })
68
- .mockResolvedValueOnce({ overwrite: true })
69
- .mockResolvedValueOnce({
70
- tenantId: 'new-tenant-456',
71
- apiUrl: 'https://api.example.com',
72
- });
73
- await initCommand();
74
- expect(inquirer.default.prompt).toHaveBeenCalledWith(expect.arrayContaining([
75
- expect.objectContaining({
76
- type: 'confirm',
77
- name: 'overwrite',
78
- message: expect.stringContaining('already exists'),
79
- }),
80
- ]));
81
- expect(writeFileSync).toHaveBeenCalledWith(expect.stringContaining('inkeep.config.ts'), expect.stringContaining("tenantId: 'new-tenant-456'"));
82
- });
83
- it('should cancel when user chooses not to overwrite', async () => {
84
- const { existsSync, writeFileSync, readdirSync } = await import('node:fs');
85
- const inquirer = await import('inquirer');
86
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
87
- vi.mocked(existsSync).mockImplementation((path) => {
88
- return path.toString().includes('inkeep.config.ts');
89
- });
90
- const promptMock = vi.mocked(inquirer.default.prompt);
91
- promptMock
92
- .mockResolvedValueOnce({ confirmedPath: './inkeep.config.ts' })
93
- .mockResolvedValueOnce({ overwrite: false });
94
- await initCommand();
95
- expect(writeFileSync).not.toHaveBeenCalled();
96
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Init cancelled'));
97
- });
98
- it('should validate tenant ID is not empty', async () => {
99
- const { existsSync, readdirSync } = await import('node:fs');
100
- const inquirer = await import('inquirer');
101
- vi.mocked(existsSync).mockReturnValue(false);
102
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
103
- let pathCallCount = 0;
104
- const promptMock = vi.mocked(inquirer.default.prompt);
105
- promptMock.mockImplementation(async (questions) => {
106
- pathCallCount++;
107
- if (pathCallCount === 1) {
108
- // First call is for path confirmation
109
- return { confirmedPath: './inkeep.config.ts' };
110
- }
111
- else {
112
- // Second call is for tenant ID and API URL
113
- const tenantIdQuestion = questions.find((q) => q.name === 'tenantId');
114
- expect(tenantIdQuestion.validate('')).toBe('Tenant ID is required');
115
- expect(tenantIdQuestion.validate(' ')).toBe('Tenant ID is required');
116
- expect(tenantIdQuestion.validate('valid-tenant')).toBe(true);
117
- return {
118
- tenantId: 'valid-tenant',
119
- apiUrl: 'http://localhost:3002',
120
- };
121
- }
122
- });
123
- await initCommand();
124
- });
125
- it('should validate API URL format', async () => {
126
- const { existsSync, readdirSync } = await import('node:fs');
127
- const inquirer = await import('inquirer');
128
- vi.mocked(existsSync).mockReturnValue(false);
129
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
130
- let pathCallCount = 0;
131
- const promptMock = vi.mocked(inquirer.default.prompt);
132
- promptMock.mockImplementation(async (questions) => {
133
- pathCallCount++;
134
- if (pathCallCount === 1) {
135
- // First call is for path confirmation
136
- return { confirmedPath: './inkeep.config.ts' };
137
- }
138
- else {
139
- // Second call is for tenant ID and API URL
140
- const apiUrlQuestion = questions.find((q) => q.name === 'apiUrl');
141
- expect(apiUrlQuestion.validate('not-a-url')).toBe('Please enter a valid URL');
142
- expect(apiUrlQuestion.validate('http://localhost:3002')).toBe(true);
143
- expect(apiUrlQuestion.validate('https://api.example.com')).toBe(true);
144
- return {
145
- tenantId: 'test-tenant',
146
- apiUrl: 'http://localhost:3002',
147
- };
148
- }
149
- });
150
- await initCommand();
151
- });
152
- it('should accept a path parameter', async () => {
153
- const { existsSync, writeFileSync } = await import('node:fs');
154
- const inquirer = await import('inquirer');
155
- vi.mocked(existsSync).mockReturnValue(false);
156
- const promptMock = vi.mocked(inquirer.default.prompt);
157
- promptMock.mockResolvedValue({
158
- tenantId: 'test-tenant',
159
- apiUrl: 'http://localhost:3002',
160
- });
161
- await initCommand({ path: './custom/path' });
162
- expect(writeFileSync).toHaveBeenCalledWith(expect.stringContaining('custom/path/inkeep.config.ts'), expect.any(String));
163
- });
164
- it('should handle write errors gracefully', async () => {
165
- const { existsSync, writeFileSync, readdirSync } = await import('node:fs');
166
- const inquirer = await import('inquirer');
167
- vi.mocked(existsSync).mockReturnValue(false);
168
- vi.mocked(readdirSync).mockReturnValue(['package.json']);
169
- const promptMock = vi.mocked(inquirer.default.prompt);
170
- promptMock
171
- .mockResolvedValueOnce({
172
- confirmedPath: './inkeep.config.ts',
173
- })
174
- .mockResolvedValueOnce({
175
- tenantId: 'test-tenant',
176
- apiUrl: 'http://localhost:3002',
177
- });
178
- vi.mocked(writeFileSync).mockImplementation(() => {
179
- throw new Error('Permission denied');
180
- });
181
- await expect(initCommand()).rejects.toThrow('process.exit called');
182
- expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Failed to create config file'), expect.any(Error));
183
- expect(processExitSpy).toHaveBeenCalledWith(1);
184
- });
185
- });
186
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,54 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { convertTypeScriptToJson } from '../../commands/pull.js';
3
- // Mock the convertTypeScriptToJson function
4
- vi.mock('../../commands/pull.js', async () => {
5
- const actual = await vi.importActual('../../commands/pull.js');
6
- return {
7
- ...actual,
8
- convertTypeScriptToJson: vi.fn(),
9
- };
10
- });
11
- describe('Pull Command', () => {
12
- beforeEach(() => {
13
- vi.clearAllMocks();
14
- });
15
- describe('convertTypeScriptToJson', () => {
16
- it('should convert TypeScript file to JSON using tsx spawn', async () => {
17
- const mockResult = { id: 'test-graph', name: 'Test Graph' };
18
- convertTypeScriptToJson.mockResolvedValue(mockResult);
19
- const result = await convertTypeScriptToJson('test-graph.ts');
20
- expect(convertTypeScriptToJson).toHaveBeenCalledWith('test-graph.ts');
21
- expect(result).toEqual(mockResult);
22
- });
23
- it('should handle tsx spawn errors', async () => {
24
- convertTypeScriptToJson.mockRejectedValue(new Error('Failed to load TypeScript file: tsx not found'));
25
- await expect(convertTypeScriptToJson('test-graph.ts')).rejects.toThrow('Failed to load TypeScript file: tsx not found');
26
- });
27
- it('should handle tsx exit with non-zero code', async () => {
28
- convertTypeScriptToJson.mockRejectedValue(new Error('Conversion failed: Error: Module not found'));
29
- await expect(convertTypeScriptToJson('test-graph.ts')).rejects.toThrow('Conversion failed: Error: Module not found');
30
- });
31
- it('should handle missing JSON markers in tsx output', async () => {
32
- convertTypeScriptToJson.mockRejectedValue(new Error('JSON markers not found in output'));
33
- await expect(convertTypeScriptToJson('test-graph.ts')).rejects.toThrow('JSON markers not found in output');
34
- });
35
- it('should handle invalid JSON in tsx output', async () => {
36
- convertTypeScriptToJson.mockRejectedValue(new Error('Failed to parse conversion result'));
37
- await expect(convertTypeScriptToJson('test-graph.ts')).rejects.toThrow('Failed to parse conversion result');
38
- });
39
- it('should handle file not found error', async () => {
40
- convertTypeScriptToJson.mockRejectedValue(new Error('File not found: nonexistent.ts'));
41
- await expect(convertTypeScriptToJson('nonexistent.ts')).rejects.toThrow('File not found: nonexistent.ts');
42
- });
43
- it('should handle non-TypeScript files directly', async () => {
44
- const mockResult = { id: 'test-graph' };
45
- convertTypeScriptToJson.mockResolvedValue(mockResult);
46
- const result = await convertTypeScriptToJson('test-graph.js');
47
- expect(result).toEqual(mockResult);
48
- });
49
- it('should handle modules with no graph exports', async () => {
50
- convertTypeScriptToJson.mockRejectedValue(new Error('No AgentGraph exported from configuration file'));
51
- await expect(convertTypeScriptToJson('test-graph.js')).rejects.toThrow('No AgentGraph exported from configuration file');
52
- });
53
- });
54
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,127 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { spawn } from 'node:child_process';
3
- import { pushCommand } from '../../commands/push.js';
4
- import { existsSync } from 'node:fs';
5
- // Mock dependencies
6
- vi.mock('node:fs');
7
- vi.mock('node:child_process');
8
- vi.mock('@inkeep/agents-core');
9
- vi.mock('../../config.js', () => ({
10
- validateConfiguration: vi.fn().mockResolvedValue({
11
- tenantId: 'test-tenant',
12
- projectId: 'test-project',
13
- managementApiUrl: 'http://localhost:3002',
14
- sources: {
15
- tenantId: 'config',
16
- projectId: 'config',
17
- managementApiUrl: 'config',
18
- },
19
- }),
20
- }));
21
- // Store the actual ora mock instance
22
- let oraInstance;
23
- vi.mock('ora', () => ({
24
- default: vi.fn(() => {
25
- oraInstance = {
26
- start: vi.fn().mockReturnThis(),
27
- succeed: vi.fn().mockReturnThis(),
28
- fail: vi.fn().mockReturnThis(),
29
- warn: vi.fn().mockReturnThis(),
30
- stop: vi.fn().mockReturnThis(),
31
- text: '',
32
- };
33
- return oraInstance;
34
- }),
35
- }));
36
- describe('Push Command - TypeScript Spinner Fix', () => {
37
- let mockSpawn;
38
- let mockExit;
39
- beforeEach(() => {
40
- vi.clearAllMocks();
41
- // Reset ora instance
42
- oraInstance = null;
43
- // Ensure TSX_RUNNING is not set
44
- delete process.env.TSX_RUNNING;
45
- // Mock file exists
46
- existsSync.mockReturnValue(true);
47
- // Mock process.exit
48
- mockExit = vi.fn();
49
- vi.spyOn(process, 'exit').mockImplementation(mockExit);
50
- // Mock console methods
51
- vi.spyOn(console, 'log').mockImplementation(vi.fn());
52
- vi.spyOn(console, 'error').mockImplementation(vi.fn());
53
- // Setup spawn mock
54
- mockSpawn = vi.fn().mockReturnValue({
55
- on: vi.fn((event, callback) => {
56
- if (event === 'exit') {
57
- // Simulate successful exit
58
- setTimeout(() => callback(0), 10);
59
- }
60
- }),
61
- });
62
- spawn.mockImplementation(mockSpawn);
63
- });
64
- it('should stop spinner before spawning tsx process for TypeScript files', async () => {
65
- await pushCommand('/test/path/graph.ts', {});
66
- // Wait for async operations
67
- await new Promise(resolve => setTimeout(resolve, 20));
68
- // Verify spinner was created and stopped
69
- expect(oraInstance).toBeDefined();
70
- expect(oraInstance.start).toHaveBeenCalled();
71
- expect(oraInstance.stop).toHaveBeenCalled();
72
- // Verify spinner.stop() was called before spawn
73
- const stopCallOrder = oraInstance.stop.mock.invocationCallOrder[0];
74
- const spawnCallOrder = mockSpawn.mock.invocationCallOrder[0];
75
- expect(stopCallOrder).toBeLessThan(spawnCallOrder);
76
- });
77
- it('should spawn tsx process with correct arguments for TypeScript files', async () => {
78
- const options = {
79
- tenantId: 'custom-tenant',
80
- managementApiUrl: 'https://api.example.com',
81
- configFilePath: '/path/to/config.json',
82
- };
83
- await pushCommand('/test/path/graph.ts', options);
84
- // Wait for async operations
85
- await new Promise(resolve => setTimeout(resolve, 20));
86
- // Verify spawn was called with correct arguments
87
- expect(mockSpawn).toHaveBeenCalledWith('npx', expect.arrayContaining([
88
- 'tsx',
89
- expect.stringContaining('index.js'),
90
- 'push',
91
- '/test/path/graph.ts',
92
- '--tenant-id',
93
- 'custom-tenant',
94
- '--management-api-url',
95
- 'https://api.example.com',
96
- '--config-file-path',
97
- '/path/to/config.json',
98
- ]), expect.objectContaining({
99
- cwd: process.cwd(),
100
- stdio: 'inherit',
101
- env: expect.objectContaining({
102
- TSX_RUNNING: '1',
103
- }),
104
- }));
105
- });
106
- it('should handle spawn errors correctly without spinner', async () => {
107
- // Setup spawn to simulate an error
108
- mockSpawn.mockReturnValue({
109
- on: vi.fn((event, callback) => {
110
- if (event === 'error') {
111
- setTimeout(() => callback(new Error('Spawn failed')), 10);
112
- }
113
- }),
114
- });
115
- await pushCommand('/test/path/graph.ts', {});
116
- // Wait for async operations
117
- await new Promise(resolve => setTimeout(resolve, 20));
118
- // Verify spinner was stopped before error handling
119
- expect(oraInstance.stop).toHaveBeenCalled();
120
- // Verify error was logged without using spinner.fail
121
- expect(oraInstance.fail).not.toHaveBeenCalled();
122
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Failed to load TypeScript file'));
123
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Error'), 'Spawn failed');
124
- // Verify process exited with error code
125
- expect(mockExit).toHaveBeenCalledWith(1);
126
- });
127
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,265 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { pushCommand } from '../../commands/push.js';
3
- import * as core from '@inkeep/agents-core';
4
- import inquirer from 'inquirer';
5
- import { existsSync } from 'node:fs';
6
- // Mock all external dependencies
7
- vi.mock('node:fs');
8
- vi.mock('@inkeep/agents-core');
9
- vi.mock('inquirer');
10
- vi.mock('chalk', () => ({
11
- default: {
12
- red: vi.fn((text) => text),
13
- yellow: vi.fn((text) => text),
14
- green: vi.fn((text) => text),
15
- cyan: vi.fn((text) => text),
16
- gray: vi.fn((text) => text),
17
- },
18
- }));
19
- vi.mock('ora', () => ({
20
- default: vi.fn(() => ({
21
- start: vi.fn().mockReturnThis(),
22
- succeed: vi.fn().mockReturnThis(),
23
- fail: vi.fn().mockReturnThis(),
24
- warn: vi.fn().mockReturnThis(),
25
- stop: vi.fn().mockReturnThis(),
26
- text: '',
27
- })),
28
- }));
29
- vi.mock('../../api.js', () => ({
30
- ApiClient: {
31
- create: vi.fn().mockResolvedValue({}),
32
- },
33
- }));
34
- vi.mock('../../config.js', () => ({
35
- validateConfiguration: vi.fn().mockResolvedValue({
36
- tenantId: 'test-tenant',
37
- projectId: 'test-project',
38
- apiUrl: 'http://localhost:3002',
39
- sources: {
40
- tenantId: 'config',
41
- projectId: 'config',
42
- apiUrl: 'config',
43
- },
44
- }),
45
- }));
46
- describe('Push Command - Project Validation', () => {
47
- let mockDbClient;
48
- let mockGetProject;
49
- let mockCreateProject;
50
- let mockExit;
51
- let mockLog;
52
- beforeEach(() => {
53
- vi.clearAllMocks();
54
- // Setup database client mock
55
- mockDbClient = {};
56
- mockGetProject = vi.fn();
57
- mockCreateProject = vi.fn();
58
- core.createDatabaseClient.mockReturnValue(mockDbClient);
59
- core.getProject.mockReturnValue(mockGetProject);
60
- core.createProject.mockReturnValue(mockCreateProject);
61
- // Mock process.exit to prevent test runner from exiting
62
- mockExit = vi.fn();
63
- vi.spyOn(process, 'exit').mockImplementation(mockExit);
64
- // Mock console methods
65
- mockLog = vi.fn();
66
- vi.spyOn(console, 'log').mockImplementation(mockLog);
67
- vi.spyOn(console, 'error').mockImplementation(vi.fn());
68
- // Mock file existence check for graph file
69
- existsSync.mockReturnValue(true);
70
- // Default environment
71
- process.env.DB_FILE_NAME = 'test.db';
72
- });
73
- it('should validate project exists before pushing graph', async () => {
74
- // Mock project exists
75
- mockGetProject.mockResolvedValue({
76
- id: 'test-project',
77
- name: 'Test Project',
78
- tenantId: 'test-tenant',
79
- });
80
- // Mock graph file import
81
- const mockGraph = {
82
- init: vi.fn().mockResolvedValue(undefined),
83
- getId: vi.fn().mockReturnValue('test-graph'),
84
- getName: vi.fn().mockReturnValue('Test Graph'),
85
- getAgents: vi.fn().mockReturnValue([]),
86
- getStats: vi.fn().mockReturnValue({
87
- agentCount: 1,
88
- toolCount: 0,
89
- relationCount: 0,
90
- }),
91
- getDefaultAgent: vi.fn().mockReturnValue(null),
92
- setConfig: vi.fn(),
93
- };
94
- vi.doMock('/test/path/graph.js', () => ({
95
- default: mockGraph,
96
- }));
97
- // Run in TypeScript mode (skip tsx spawn)
98
- process.env.TSX_RUNNING = '1';
99
- await pushCommand('/test/path/graph.js', {});
100
- // Verify project validation was called
101
- expect(mockGetProject).toHaveBeenCalledWith({
102
- scopes: { tenantId: 'test-tenant', projectId: 'test-project' },
103
- });
104
- });
105
- it('should prompt to create project when it does not exist', async () => {
106
- // Mock project doesn't exist
107
- mockGetProject.mockResolvedValue(null);
108
- // Mock user confirms project creation
109
- inquirer.prompt
110
- .mockResolvedValueOnce({ shouldCreate: true })
111
- .mockResolvedValueOnce({
112
- projectName: 'New Project',
113
- projectDescription: 'Test description',
114
- });
115
- // Mock project creation success
116
- mockCreateProject.mockResolvedValue({
117
- id: 'test-project',
118
- name: 'New Project',
119
- description: 'Test description',
120
- tenantId: 'test-tenant',
121
- });
122
- // Mock graph file import
123
- const mockGraph = {
124
- init: vi.fn().mockResolvedValue(undefined),
125
- getId: vi.fn().mockReturnValue('test-graph'),
126
- getName: vi.fn().mockReturnValue('Test Graph'),
127
- getAgents: vi.fn().mockReturnValue([]),
128
- getStats: vi.fn().mockReturnValue({
129
- agentCount: 1,
130
- toolCount: 0,
131
- relationCount: 0,
132
- }),
133
- getDefaultAgent: vi.fn().mockReturnValue(null),
134
- setConfig: vi.fn(),
135
- };
136
- vi.doMock('/test/path/graph.js', () => ({
137
- default: mockGraph,
138
- }));
139
- process.env.TSX_RUNNING = '1';
140
- await pushCommand('/test/path/graph.js', {});
141
- // Verify project creation was prompted
142
- expect(inquirer.prompt).toHaveBeenCalledWith(expect.arrayContaining([
143
- expect.objectContaining({
144
- type: 'confirm',
145
- name: 'shouldCreate',
146
- message: expect.stringContaining('does not exist'),
147
- }),
148
- ]));
149
- // Verify project was created
150
- expect(mockCreateProject).toHaveBeenCalledWith({
151
- id: 'test-project',
152
- tenantId: 'test-tenant',
153
- name: 'New Project',
154
- description: 'Test description',
155
- });
156
- });
157
- it('should exit if user declines to create missing project', async () => {
158
- // Mock project doesn't exist
159
- mockGetProject.mockResolvedValue(null);
160
- // Mock user declines project creation
161
- inquirer.prompt.mockResolvedValueOnce({ shouldCreate: false });
162
- // Mock graph file import (needed to prevent errors)
163
- const mockGraph = {
164
- init: vi.fn().mockResolvedValue(undefined),
165
- getId: vi.fn().mockReturnValue('test-graph'),
166
- getName: vi.fn().mockReturnValue('Test Graph'),
167
- getAgents: vi.fn().mockReturnValue([]),
168
- getStats: vi.fn().mockReturnValue({
169
- agentCount: 1,
170
- toolCount: 0,
171
- relationCount: 0,
172
- }),
173
- getDefaultAgent: vi.fn().mockReturnValue(null),
174
- setConfig: vi.fn(),
175
- };
176
- vi.doMock('/test/path/graph.js', () => ({
177
- default: mockGraph,
178
- }));
179
- process.env.TSX_RUNNING = '1';
180
- await pushCommand('/test/path/graph.js', {});
181
- // Verify push was cancelled
182
- expect(mockExit).toHaveBeenCalledWith(0);
183
- expect(mockLog).toHaveBeenCalledWith(expect.stringContaining('Push cancelled'));
184
- // Verify project was not created
185
- expect(mockCreateProject).not.toHaveBeenCalled();
186
- });
187
- it('should handle project creation errors gracefully', async () => {
188
- // Mock project doesn't exist
189
- mockGetProject.mockResolvedValue(null);
190
- // Mock user confirms project creation
191
- inquirer.prompt
192
- .mockResolvedValueOnce({ shouldCreate: true })
193
- .mockResolvedValueOnce({
194
- projectName: 'New Project',
195
- projectDescription: '',
196
- });
197
- // Mock project creation failure
198
- mockCreateProject.mockRejectedValue(new Error('Database error'));
199
- process.env.TSX_RUNNING = '1';
200
- await pushCommand('/test/path/graph.js', {});
201
- // Verify error handling
202
- expect(mockExit).toHaveBeenCalledWith(1);
203
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Error'), 'Database error');
204
- });
205
- it('should use DB_FILE_NAME environment variable for database location', async () => {
206
- process.env.DB_FILE_NAME = 'custom-location.db';
207
- mockGetProject.mockResolvedValue({
208
- id: 'test-project',
209
- name: 'Test Project',
210
- tenantId: 'test-tenant',
211
- });
212
- const mockGraph = {
213
- init: vi.fn().mockResolvedValue(undefined),
214
- getId: vi.fn().mockReturnValue('test-graph'),
215
- getName: vi.fn().mockReturnValue('Test Graph'),
216
- getAgents: vi.fn().mockReturnValue([]),
217
- getStats: vi.fn().mockReturnValue({
218
- agentCount: 1,
219
- toolCount: 0,
220
- relationCount: 0,
221
- }),
222
- getDefaultAgent: vi.fn().mockReturnValue(null),
223
- setConfig: vi.fn(),
224
- };
225
- vi.doMock('/test/path/graph.js', () => ({
226
- default: mockGraph,
227
- }));
228
- process.env.TSX_RUNNING = '1';
229
- await pushCommand('/test/path/graph.js', {});
230
- // Verify correct database URL was used
231
- expect(core.createDatabaseClient).toHaveBeenCalledWith({
232
- url: expect.stringContaining('custom-location.db'),
233
- });
234
- });
235
- it('should default to local.db when DB_FILE_NAME is not set', async () => {
236
- delete process.env.DB_FILE_NAME;
237
- mockGetProject.mockResolvedValue({
238
- id: 'test-project',
239
- name: 'Test Project',
240
- tenantId: 'test-tenant',
241
- });
242
- const mockGraph = {
243
- init: vi.fn().mockResolvedValue(undefined),
244
- getId: vi.fn().mockReturnValue('test-graph'),
245
- getName: vi.fn().mockReturnValue('Test Graph'),
246
- getAgents: vi.fn().mockReturnValue([]),
247
- getStats: vi.fn().mockReturnValue({
248
- agentCount: 1,
249
- toolCount: 0,
250
- relationCount: 0,
251
- }),
252
- getDefaultAgent: vi.fn().mockReturnValue(null),
253
- setConfig: vi.fn(),
254
- };
255
- vi.doMock('/test/path/graph.js', () => ({
256
- default: mockGraph,
257
- }));
258
- process.env.TSX_RUNNING = '1';
259
- await pushCommand('/test/path/graph.js', {});
260
- // Verify default database URL was used
261
- expect(core.createDatabaseClient).toHaveBeenCalledWith({
262
- url: expect.stringContaining('local.db'),
263
- });
264
- });
265
- });
@@ -1 +0,0 @@
1
- export {};