kitstore-cli 1.0.0 → 1.0.1

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 (48) hide show
  1. package/dist/config.js +20 -4
  2. package/package.json +5 -1
  3. package/.env.test +0 -4
  4. package/.eslintrc.js +0 -29
  5. package/e2e/install.e2e.test.ts +0 -237
  6. package/e2e/integration.e2e.test.ts +0 -346
  7. package/e2e/login.e2e.test.ts +0 -188
  8. package/jest.config.js +0 -24
  9. package/openapitools.json +0 -7
  10. package/src/__tests__/commands/init.test.ts +0 -52
  11. package/src/__tests__/commands/install.test.ts +0 -449
  12. package/src/__tests__/commands/list.test.ts +0 -164
  13. package/src/__tests__/commands/login.test.ts +0 -293
  14. package/src/__tests__/commands/rule-check.test.ts +0 -52
  15. package/src/__tests__/commands/search.test.ts +0 -168
  16. package/src/__tests__/commands/upload.test.ts +0 -404
  17. package/src/__tests__/config.test.ts +0 -181
  18. package/src/__tests__/setup.ts +0 -11
  19. package/src/api/client.ts +0 -20
  20. package/src/api/generated/.openapi-generator/FILES +0 -17
  21. package/src/api/generated/.openapi-generator/VERSION +0 -1
  22. package/src/api/generated/.openapi-generator-ignore +0 -23
  23. package/src/api/generated/api.ts +0 -1171
  24. package/src/api/generated/base.ts +0 -62
  25. package/src/api/generated/common.ts +0 -113
  26. package/src/api/generated/configuration.ts +0 -121
  27. package/src/api/generated/docs/AuthApi.md +0 -158
  28. package/src/api/generated/docs/AuthResponseDto.md +0 -22
  29. package/src/api/generated/docs/AuthUserDto.md +0 -24
  30. package/src/api/generated/docs/HealthApi.md +0 -183
  31. package/src/api/generated/docs/LoginDto.md +0 -22
  32. package/src/api/generated/docs/RegisterDto.md +0 -24
  33. package/src/api/generated/docs/RuleAuthorDto.md +0 -22
  34. package/src/api/generated/docs/RuleResponseDto.md +0 -36
  35. package/src/api/generated/docs/RulesApi.md +0 -289
  36. package/src/api/generated/git_push.sh +0 -57
  37. package/src/api/generated/index.ts +0 -18
  38. package/src/commands/init.ts +0 -46
  39. package/src/commands/install.ts +0 -129
  40. package/src/commands/list.ts +0 -71
  41. package/src/commands/login.ts +0 -65
  42. package/src/commands/rule-check.ts +0 -49
  43. package/src/commands/search.ts +0 -66
  44. package/src/commands/upload.ts +0 -117
  45. package/src/config.ts +0 -66
  46. package/src/index.ts +0 -79
  47. package/test-cli-config.js +0 -118
  48. package/tsconfig.json +0 -24
@@ -1,293 +0,0 @@
1
- import { loginCommand } from '../../commands/login';
2
- import * as config from '../../config';
3
- import * as apiClient from '../../api/client';
4
- import axios from 'axios';
5
- import inquirer from 'inquirer';
6
-
7
- // Mock dependencies
8
- jest.mock('../../config', () => ({
9
- getConfig: jest.fn(),
10
- saveConfig: jest.fn(),
11
- }));
12
-
13
- jest.mock('../../api/client', () => ({
14
- createApi: jest.fn(),
15
- }));
16
-
17
- jest.mock('axios');
18
- jest.mock('inquirer', () => ({
19
- prompt: jest.fn(),
20
- }));
21
-
22
- const mockInquirer = require('inquirer');
23
-
24
- // TC-UNIT-CLI-001 to TC-UNIT-CLI-002
25
- describe('Login Command', () => {
26
- const mockGetConfig = config.getConfig as jest.MockedFunction<typeof config.getConfig>;
27
- const mockSaveConfig = config.saveConfig as jest.MockedFunction<typeof config.saveConfig>;
28
- const mockCreateApi = apiClient.createApi as jest.MockedFunction<typeof apiClient.createApi>;
29
-
30
- beforeEach(() => {
31
- jest.clearAllMocks();
32
- (axios.isAxiosError as unknown as jest.Mock).mockImplementation((err: any) => err?.isAxiosError === true);
33
- jest.spyOn(console, 'log').mockImplementation();
34
- jest.spyOn(console, 'error').mockImplementation();
35
- jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
36
- throw new Error(`Process exit with code ${code}`);
37
- });
38
- });
39
-
40
- afterEach(() => {
41
- jest.restoreAllMocks();
42
- });
43
-
44
- // TC-UNIT-CLI-001: Login command (success)
45
- describe('login success', () => {
46
- it('should login successfully and save token', async () => {
47
- const mockAuthApi = {
48
- authControllerLogin: jest.fn().mockResolvedValue({
49
- data: {
50
- token: 'test-token-123',
51
- user: {
52
- id: 'user-id',
53
- username: 'testuser',
54
- email: 'test@example.com',
55
- },
56
- },
57
- }),
58
- };
59
-
60
- mockGetConfig.mockResolvedValue({
61
- server: 'http://localhost:3000',
62
- token: undefined,
63
- user: undefined,
64
- lastLogin: undefined,
65
- });
66
-
67
- mockCreateApi.mockResolvedValue({
68
- authApi: mockAuthApi,
69
- rulesApi: {} as any,
70
- } as any);
71
-
72
- await loginCommand({
73
- email: 'test@example.com',
74
- password: 'Password123!',
75
- });
76
-
77
- expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
78
- expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
79
- email: 'test@example.com',
80
- password: 'Password123!',
81
- });
82
- expect(mockSaveConfig).toHaveBeenCalledWith({
83
- token: 'test-token-123',
84
- server: 'http://localhost:3000',
85
- user: {
86
- id: 'user-id',
87
- username: 'testuser',
88
- email: 'test@example.com',
89
- },
90
- lastLogin: expect.any(String),
91
- });
92
- });
93
- });
94
-
95
- // TC-UNIT-CLI-002: Login command (failure)
96
- describe('login failure', () => {
97
- it('should handle 401 error', async () => {
98
- const axiosError = {
99
- isAxiosError: true,
100
- response: {
101
- status: 401,
102
- data: { error: 'Invalid credentials' },
103
- },
104
- message: 'Request failed with status code 401',
105
- } as any;
106
-
107
- const mockAuthApi = {
108
- authControllerLogin: jest.fn().mockRejectedValue(axiosError),
109
- };
110
-
111
- mockGetConfig.mockResolvedValue({
112
- server: 'http://localhost:3000',
113
- token: undefined,
114
- user: undefined,
115
- lastLogin: undefined,
116
- });
117
-
118
- mockCreateApi.mockResolvedValue({
119
- authApi: mockAuthApi,
120
- rulesApi: {} as any,
121
- } as any);
122
-
123
- await expect(
124
- loginCommand({
125
- email: 'test@example.com',
126
- password: 'WrongPassword',
127
- }),
128
- ).rejects.toThrow();
129
-
130
- expect(mockSaveConfig).not.toHaveBeenCalled();
131
- });
132
-
133
- // TC-UNIT-CLI-003: Interactive login prompts
134
- it('should prompt for email and password when not provided', async () => {
135
- mockInquirer.prompt
136
- .mockResolvedValueOnce({ email: 'prompted@example.com' })
137
- .mockResolvedValueOnce({ password: 'promptedpassword' });
138
-
139
- const mockAuthApi = {
140
- authControllerLogin: jest.fn().mockResolvedValue({
141
- data: {
142
- token: 'test-token-123',
143
- user: {
144
- id: 'user-id',
145
- username: 'testuser',
146
- email: 'prompted@example.com',
147
- },
148
- },
149
- }),
150
- };
151
-
152
- mockGetConfig.mockResolvedValue({
153
- server: 'http://localhost:3000',
154
- token: undefined,
155
- user: undefined,
156
- lastLogin: undefined,
157
- });
158
-
159
- mockCreateApi.mockResolvedValue({
160
- authApi: mockAuthApi,
161
- rulesApi: {} as any,
162
- } as any);
163
-
164
- await loginCommand({});
165
-
166
- expect(mockInquirer.prompt).toHaveBeenCalledTimes(2);
167
- expect(mockInquirer.prompt).toHaveBeenNthCalledWith(1, [
168
- { type: 'input', name: 'email', message: 'Email:' }
169
- ]);
170
- expect(mockInquirer.prompt).toHaveBeenNthCalledWith(2, [
171
- { type: 'password', name: 'password', message: 'Password:' }
172
- ]);
173
- expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
174
- email: 'prompted@example.com',
175
- password: 'promptedpassword',
176
- });
177
- });
178
-
179
- // TC-UNIT-CLI-004: Empty credentials after prompts
180
- it('should exit with error when email/password are empty after prompts', async () => {
181
- mockInquirer.prompt
182
- .mockResolvedValueOnce({ email: '' })
183
- .mockResolvedValueOnce({ password: '' });
184
-
185
- mockGetConfig.mockResolvedValue({
186
- server: 'http://localhost:3000',
187
- token: undefined,
188
- user: undefined,
189
- lastLogin: undefined,
190
- });
191
-
192
- await expect(loginCommand({})).rejects.toThrow('Process exit with code 1');
193
- expect(console.error).toHaveBeenCalledWith('❌ Login failed: Email and password are required');
194
- });
195
-
196
- // TC-UNIT-CLI-005: Login response without token
197
- it('should handle login response without token', async () => {
198
- const mockAuthApi = {
199
- authControllerLogin: jest.fn().mockResolvedValue({
200
- data: {
201
- user: {
202
- id: 'user-id',
203
- username: 'testuser',
204
- email: 'test@example.com',
205
- },
206
- },
207
- }),
208
- };
209
-
210
- mockGetConfig.mockResolvedValue({
211
- server: 'http://localhost:3000',
212
- token: undefined,
213
- user: undefined,
214
- lastLogin: undefined,
215
- });
216
-
217
- mockCreateApi.mockResolvedValue({
218
- authApi: mockAuthApi,
219
- rulesApi: {} as any,
220
- } as any);
221
-
222
- await expect(loginCommand({ email: 'test@example.com', password: 'password123' }))
223
- .rejects.toThrow('Process exit with code 1');
224
-
225
- expect(console.error).toHaveBeenCalledWith('❌ Login failed');
226
- });
227
-
228
- // TC-UNIT-CLI-006: Other axios errors
229
- it('should handle other axios errors', async () => {
230
- const axiosError = {
231
- isAxiosError: true,
232
- response: {
233
- status: 500,
234
- data: { error: 'Internal server error' },
235
- },
236
- message: 'Request failed with status code 500',
237
- } as any;
238
-
239
- const mockAuthApi = {
240
- authControllerLogin: jest.fn().mockRejectedValue(axiosError),
241
- };
242
-
243
- mockGetConfig.mockResolvedValue({
244
- server: 'http://localhost:3000',
245
- token: undefined,
246
- user: undefined,
247
- lastLogin: undefined,
248
- });
249
-
250
- mockCreateApi.mockResolvedValue({
251
- authApi: mockAuthApi,
252
- rulesApi: {} as any,
253
- } as any);
254
-
255
- await expect(
256
- loginCommand({
257
- email: 'test@example.com',
258
- password: 'Password123!',
259
- }),
260
- ).rejects.toThrow('Process exit with code 1');
261
-
262
- expect(console.error).toHaveBeenCalledWith('❌ Login failed: Internal server error');
263
- });
264
-
265
- // TC-UNIT-CLI-007: Non-axios errors
266
- it('should handle non-axios errors', async () => {
267
- const mockAuthApi = {
268
- authControllerLogin: jest.fn().mockRejectedValue(new Error('Network error')),
269
- };
270
-
271
- mockGetConfig.mockResolvedValue({
272
- server: 'http://localhost:3000',
273
- token: undefined,
274
- user: undefined,
275
- lastLogin: undefined,
276
- });
277
-
278
- mockCreateApi.mockResolvedValue({
279
- authApi: mockAuthApi,
280
- rulesApi: {} as any,
281
- } as any);
282
-
283
- await expect(
284
- loginCommand({
285
- email: 'test@example.com',
286
- password: 'Password123!',
287
- }),
288
- ).rejects.toThrow('Process exit with code 1');
289
-
290
- expect(console.error).toHaveBeenCalledWith('❌ Login failed: Network error');
291
- });
292
- });
293
- });
@@ -1,52 +0,0 @@
1
- import { ruleCheckCommand } from '../../commands/rule-check';
2
- import * as fs from 'fs-extra';
3
- import chalk from 'chalk';
4
-
5
- jest.mock('fs-extra');
6
-
7
- describe('Rule Check Command', () => {
8
- beforeEach(() => {
9
- jest.clearAllMocks();
10
- jest.spyOn(console, 'log').mockImplementation();
11
- jest.spyOn(console, 'error').mockImplementation();
12
- jest.spyOn(console, 'warn').mockImplementation();
13
- jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
14
- throw new Error(`Process exit with code ${code}`);
15
- }) as any;
16
- });
17
-
18
- it('should pass for a valid rule file', async () => {
19
- (fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
20
- (fs.readFile as unknown as jest.Mock).mockResolvedValue('@requirement TC-UNIT-001\nValid rule content');
21
-
22
- await ruleCheckCommand('valid-rule.md');
23
-
24
- expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Rule validation passed!'));
25
- });
26
-
27
- it('should exit if file not found', async () => {
28
- (fs.pathExists as unknown as jest.Mock).mockResolvedValue(false);
29
-
30
- await expect(ruleCheckCommand('non-existent.md')).rejects.toThrow('Process exit with code 1');
31
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining('File not found'));
32
- });
33
-
34
- it('should warn about missing @requirement tag', async () => {
35
- (fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
36
- (fs.readFile as unknown as jest.Mock).mockResolvedValue('Rule without requirement tag');
37
-
38
- await ruleCheckCommand('no-tag.md');
39
-
40
- expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('Warning: Missing @requirement tag'));
41
- });
42
-
43
- it('should error if file is empty', async () => {
44
- (fs.pathExists as unknown as jest.Mock).mockResolvedValue(true);
45
- (fs.readFile as unknown as jest.Mock).mockResolvedValue('');
46
-
47
- await ruleCheckCommand('empty.md');
48
-
49
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Error: File is empty'));
50
- });
51
- });
52
-
@@ -1,168 +0,0 @@
1
- import { searchCommand } from '../../commands/search';
2
- import * as config from '../../config';
3
-
4
- // Mock dependencies
5
- jest.mock('../../config', () => ({
6
- getConfig: jest.fn(),
7
- }));
8
-
9
- jest.mock('../../api/client', () => ({
10
- createApi: jest.fn(),
11
- }));
12
-
13
- describe('Search Command', () => {
14
- const mockGetConfig = config.getConfig as jest.MockedFunction<typeof config.getConfig>;
15
- const mockCreateApi = require('../../api/client').createApi as jest.MockedFunction<any>;
16
-
17
- beforeEach(() => {
18
- jest.clearAllMocks();
19
- jest.spyOn(console, 'log').mockImplementation();
20
- jest.spyOn(console, 'error').mockImplementation();
21
- // Re-establish process.exit mock for each test
22
- jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
23
- throw new Error(`Process exit with code ${code}`);
24
- }) as any;
25
- });
26
-
27
- afterEach(() => {
28
- jest.restoreAllMocks();
29
- });
30
-
31
- describe('search success', () => {
32
- it('should search rules by query', async () => {
33
- mockGetConfig.mockResolvedValue({
34
- server: 'http://localhost:3000',
35
- token: 'test-token',
36
- user: { id: 'user-id', username: 'testuser' },
37
- lastLogin: new Date().toISOString(),
38
- });
39
-
40
- const mockRulesApi = {
41
- rulesControllerFindAll: jest.fn().mockResolvedValue({
42
- data: [
43
- {
44
- id: 'rule-1',
45
- name: 'Authentication Rule',
46
- tag: 'auth',
47
- type: 'rule',
48
- description: 'Handles user authentication',
49
- version: '1.0.0',
50
- author: { username: 'user1' },
51
- createdAt: '2024-01-01T00:00:00.000Z',
52
- },
53
- ],
54
- }),
55
- };
56
-
57
- mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
58
-
59
- await searchCommand('auth', {});
60
-
61
- expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
62
- expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({
63
- name: 'auth',
64
- });
65
- expect(console.log).toHaveBeenCalledWith('🔍 Search results for "auth":');
66
- });
67
-
68
- it('should apply additional filters with search query', async () => {
69
- mockGetConfig.mockResolvedValue({
70
- server: 'http://localhost:3000',
71
- token: 'test-token',
72
- user: { id: 'user-id', username: 'testuser' },
73
- lastLogin: new Date().toISOString(),
74
- });
75
-
76
- const mockRulesApi = {
77
- rulesControllerFindAll: jest.fn().mockResolvedValue({
78
- data: [
79
- {
80
- id: 'rule-1',
81
- name: 'Validation Rule',
82
- tag: 'validation',
83
- type: 'rule',
84
- description: 'Input validation rule',
85
- version: '1.0.0',
86
- author: { username: 'user1' },
87
- createdAt: '2024-01-01T00:00:00.000Z',
88
- },
89
- ],
90
- }),
91
- };
92
-
93
- mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
94
-
95
- await searchCommand('validation', { type: 'rule', limit: '5' });
96
-
97
- expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith({
98
- name: 'validation',
99
- type: 'rule',
100
- limit: 5,
101
- });
102
- });
103
-
104
- it('should handle no search results', async () => {
105
- mockGetConfig.mockResolvedValue({
106
- server: 'http://localhost:3000',
107
- token: 'test-token',
108
- user: { id: 'user-id', username: 'testuser' },
109
- lastLogin: new Date().toISOString(),
110
- });
111
-
112
- const mockRulesApi = {
113
- rulesControllerFindAll: jest.fn().mockResolvedValue({
114
- data: [],
115
- }),
116
- };
117
-
118
- mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
119
-
120
- await searchCommand('nonexistent', {});
121
-
122
- expect(console.log).toHaveBeenCalledWith('🔍 No rules or commands found matching "nonexistent".');
123
- });
124
- });
125
-
126
- describe('search failure', () => {
127
- it('should exit with error when not logged in', async () => {
128
- mockGetConfig.mockResolvedValue({
129
- server: 'http://localhost:3000',
130
- token: undefined,
131
- user: undefined,
132
- });
133
-
134
- await expect(searchCommand('test', {})).rejects.toThrow('Process exit with code 1');
135
- expect(console.error).toHaveBeenCalledWith('❌ Not logged in. Please run `kitstore login` first.');
136
- });
137
-
138
- it('should validate query parameter', async () => {
139
- mockGetConfig.mockResolvedValue({
140
- server: 'http://localhost:3000',
141
- token: 'test-token',
142
- user: { id: 'user-id', username: 'testuser' },
143
- lastLogin: new Date().toISOString(),
144
- });
145
-
146
- await expect(searchCommand('', {})).rejects.toThrow('Process exit with code 1');
147
- expect(console.error).toHaveBeenCalledWith('❌ Search query is required.');
148
- });
149
-
150
- it('should handle API errors gracefully', async () => {
151
- mockGetConfig.mockResolvedValue({
152
- server: 'http://localhost:3000',
153
- token: 'test-token',
154
- user: { id: 'user-id', username: 'testuser' },
155
- lastLogin: new Date().toISOString(),
156
- });
157
-
158
- const mockRulesApi = {
159
- rulesControllerFindAll: jest.fn().mockRejectedValue(new Error('API Error')),
160
- };
161
-
162
- mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
163
-
164
- await expect(searchCommand('test', {})).rejects.toThrow('Process exit with code 1');
165
- expect(console.error).toHaveBeenCalledWith('❌ Search failed:', expect.any(Error));
166
- });
167
- });
168
- });