kitstore-cli 1.0.39 → 1.0.41

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.
@@ -42,6 +42,13 @@ const apiClient = __importStar(require("../../api/client"));
42
42
  const axios_1 = __importDefault(require("axios"));
43
43
  const fs = __importStar(require("fs-extra"));
44
44
  const path = __importStar(require("path"));
45
+ const fs_1 = require("fs");
46
+ // Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
47
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
48
+ const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
49
+ ? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
50
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
51
+ const DEFAULT_SERVER_URL = defaultConfig.server;
45
52
  // Mock dependencies
46
53
  jest.mock('../../config', () => ({
47
54
  getConfig: jest.fn(),
@@ -83,7 +90,7 @@ describe('Install Command', () => {
83
90
  });
84
91
  it('should install rule successfully', async () => {
85
92
  mockGetConfig.mockResolvedValue({
86
- server: 'http://localhost:3000',
93
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
87
94
  token: 'test-token',
88
95
  user: { id: 'user-id', username: 'testuser' },
89
96
  lastLogin: new Date().toISOString(),
@@ -136,7 +143,7 @@ describe('Install Command', () => {
136
143
  // TC-UNIT-CLI-026: Install with tag filtering
137
144
  it('should filter rules by tag', async () => {
138
145
  mockGetConfig.mockResolvedValue({
139
- server: 'http://localhost:3000',
146
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
140
147
  token: 'test-token',
141
148
  user: { id: 'user-id', username: 'testuser' },
142
149
  lastLogin: new Date().toISOString(),
@@ -183,7 +190,7 @@ describe('Install Command', () => {
183
190
  // TC-UNIT-CLI-027: Install with type filtering
184
191
  it('should filter rules by type', async () => {
185
192
  mockGetConfig.mockResolvedValue({
186
- server: 'http://localhost:3000',
193
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
187
194
  token: 'test-token',
188
195
  user: { id: 'user-id', username: 'testuser' },
189
196
  lastLogin: new Date().toISOString(),
@@ -229,7 +236,7 @@ describe('Install Command', () => {
229
236
  // TC-UNIT-CLI-028: Install with file download failure
230
237
  it('should handle file download failure', async () => {
231
238
  mockGetConfig.mockResolvedValue({
232
- server: 'http://localhost:3000',
239
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
233
240
  token: 'test-token',
234
241
  user: { id: 'user-id', username: 'testuser' },
235
242
  lastLogin: new Date().toISOString(),
@@ -271,7 +278,7 @@ describe('Install Command', () => {
271
278
  // TC-UNIT-CLI-029: Install with directory permission issues
272
279
  it('should handle directory creation permission issues', async () => {
273
280
  mockGetConfig.mockResolvedValue({
274
- server: 'http://localhost:3000',
281
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
275
282
  token: 'test-token',
276
283
  user: { id: 'user-id', username: 'testuser' },
277
284
  lastLogin: new Date().toISOString(),
@@ -312,7 +319,7 @@ describe('Install Command', () => {
312
319
  // TC-UNIT-CLI-030: Install with force overwrite
313
320
  it('should handle force overwrite option', async () => {
314
321
  mockGetConfig.mockResolvedValue({
315
- server: 'http://localhost:3000',
322
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
316
323
  token: 'test-token',
317
324
  user: { id: 'user-id', username: 'testuser' },
318
325
  lastLogin: new Date().toISOString(),
@@ -353,7 +360,7 @@ describe('Install Command', () => {
353
360
  // TC-UNIT-CLI-031: Install with no rules found
354
361
  it('should handle no rules found', async () => {
355
362
  mockGetConfig.mockResolvedValue({
356
- server: 'http://localhost:3000',
363
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
357
364
  token: 'test-token',
358
365
  user: { id: 'user-id', username: 'testuser' },
359
366
  lastLogin: new Date().toISOString(),
@@ -375,7 +382,7 @@ describe('Install Command', () => {
375
382
  const mockInquirer = require('inquirer');
376
383
  mockInquirer.prompt = jest.fn().mockResolvedValue({ rule: 'rule-id-2' });
377
384
  mockGetConfig.mockResolvedValue({
378
- server: 'http://localhost:3000',
385
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
379
386
  token: 'test-token',
380
387
  user: { id: 'user-id', username: 'testuser' },
381
388
  lastLogin: new Date().toISOString(),
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const list_1 = require("../../commands/list");
37
37
  const config = __importStar(require("../../config"));
38
+ const fs = __importStar(require("fs-extra"));
39
+ const path = __importStar(require("path"));
40
+ // Load default-config server URL for unit tests
41
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
42
+ const defaultConfig = fs.existsSync(defaultConfigPath)
43
+ ? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
44
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
45
+ const DEFAULT_SERVER_URL = defaultConfig.server;
38
46
  // Mock dependencies
39
47
  jest.mock('../../config', () => ({
40
48
  getConfig: jest.fn(),
@@ -60,7 +68,7 @@ describe('List Command', () => {
60
68
  describe('list success', () => {
61
69
  it('should list all rules when no filters provided', async () => {
62
70
  mockGetConfig.mockResolvedValue({
63
- server: 'http://localhost:3000',
71
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
64
72
  token: 'test-token',
65
73
  user: { id: 'user-id', username: 'testuser' },
66
74
  lastLogin: new Date().toISOString(),
@@ -93,7 +101,7 @@ describe('List Command', () => {
93
101
  };
94
102
  mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
95
103
  await (0, list_1.listCommand)({});
96
- expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
104
+ expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
97
105
  expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith(undefined, // page
98
106
  undefined, // limit
99
107
  undefined, // tag
@@ -105,7 +113,7 @@ describe('List Command', () => {
105
113
  });
106
114
  it('should apply filters when provided', async () => {
107
115
  mockGetConfig.mockResolvedValue({
108
- server: 'http://localhost:3000',
116
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
109
117
  token: 'test-token',
110
118
  user: { id: 'user-id', username: 'testuser' },
111
119
  lastLogin: new Date().toISOString(),
@@ -138,7 +146,7 @@ describe('List Command', () => {
138
146
  });
139
147
  it('should handle empty results', async () => {
140
148
  mockGetConfig.mockResolvedValue({
141
- server: 'http://localhost:3000',
149
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
142
150
  token: 'test-token',
143
151
  user: { id: 'user-id', username: 'testuser' },
144
152
  lastLogin: new Date().toISOString(),
@@ -156,7 +164,7 @@ describe('List Command', () => {
156
164
  describe('list failure', () => {
157
165
  it('should exit with error when not logged in', async () => {
158
166
  mockGetConfig.mockResolvedValue({
159
- server: 'http://localhost:3000',
167
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
160
168
  token: undefined,
161
169
  user: undefined,
162
170
  });
@@ -165,7 +173,7 @@ describe('List Command', () => {
165
173
  });
166
174
  it('should handle API errors gracefully', async () => {
167
175
  mockGetConfig.mockResolvedValue({
168
- server: 'http://localhost:3000',
176
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
169
177
  token: 'test-token',
170
178
  user: { id: 'user-id', username: 'testuser' },
171
179
  lastLogin: new Date().toISOString(),
@@ -40,6 +40,14 @@ const login_1 = require("../../commands/login");
40
40
  const config = __importStar(require("../../config"));
41
41
  const apiClient = __importStar(require("../../api/client"));
42
42
  const axios_1 = __importDefault(require("axios"));
43
+ const fs = __importStar(require("fs-extra"));
44
+ const path = __importStar(require("path"));
45
+ // Load default-config server URL for unit tests
46
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
47
+ const defaultConfig = fs.existsSync(defaultConfigPath)
48
+ ? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
49
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
50
+ const DEFAULT_SERVER_URL = defaultConfig.server;
43
51
  // Mock dependencies
44
52
  jest.mock('../../config', () => ({
45
53
  getConfig: jest.fn(),
@@ -86,7 +94,7 @@ describe('Login Command', () => {
86
94
  }),
87
95
  };
88
96
  mockGetConfig.mockResolvedValue({
89
- server: 'http://localhost:3000',
97
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
90
98
  token: undefined,
91
99
  user: undefined,
92
100
  lastLogin: undefined,
@@ -99,14 +107,14 @@ describe('Login Command', () => {
99
107
  email: 'test@example.com',
100
108
  password: 'Password123!',
101
109
  });
102
- expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
110
+ expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
103
111
  expect(mockAuthApi.authControllerLogin).toHaveBeenCalledWith({
104
112
  email: 'test@example.com',
105
113
  password: 'Password123!',
106
114
  });
107
115
  expect(mockSaveConfig).toHaveBeenCalledWith({
108
116
  token: 'test-token-123',
109
- server: 'http://localhost:3000',
117
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
110
118
  user: {
111
119
  id: 'user-id',
112
120
  username: 'testuser',
@@ -137,7 +145,7 @@ describe('Login Command', () => {
137
145
  authControllerLogin: jest.fn().mockRejectedValue(axiosError),
138
146
  };
139
147
  mockGetConfig.mockResolvedValue({
140
- server: 'http://localhost:3000',
148
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
141
149
  token: undefined,
142
150
  user: undefined,
143
151
  lastLogin: undefined,
@@ -151,7 +159,7 @@ describe('Login Command', () => {
151
159
  password: 'WrongPassword',
152
160
  })).rejects.toThrow();
153
161
  expect(mockSaveConfig).not.toHaveBeenCalled();
154
- expect(console.error).toHaveBeenCalledWith('❌ Login failed: Invalid credentials');
162
+ expect(console.error).toHaveBeenCalledWith('❌ Login failed: Invalid email or password');
155
163
  });
156
164
  // TC-UNIT-CLI-003: Interactive login prompts
157
165
  it('should prompt for email and password when not provided', async () => {
@@ -171,7 +179,7 @@ describe('Login Command', () => {
171
179
  }),
172
180
  };
173
181
  mockGetConfig.mockResolvedValue({
174
- server: 'http://localhost:3000',
182
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
175
183
  token: undefined,
176
184
  user: undefined,
177
185
  lastLogin: undefined,
@@ -199,7 +207,7 @@ describe('Login Command', () => {
199
207
  .mockResolvedValueOnce({ email: '' })
200
208
  .mockResolvedValueOnce({ password: '' });
201
209
  mockGetConfig.mockResolvedValue({
202
- server: 'http://localhost:3000',
210
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
203
211
  token: undefined,
204
212
  user: undefined,
205
213
  lastLogin: undefined,
@@ -221,7 +229,7 @@ describe('Login Command', () => {
221
229
  }),
222
230
  };
223
231
  mockGetConfig.mockResolvedValue({
224
- server: 'http://localhost:3000',
232
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
225
233
  token: undefined,
226
234
  user: undefined,
227
235
  lastLogin: undefined,
@@ -254,7 +262,7 @@ describe('Login Command', () => {
254
262
  authControllerLogin: jest.fn().mockRejectedValue(axiosError),
255
263
  };
256
264
  mockGetConfig.mockResolvedValue({
257
- server: 'http://localhost:3000',
265
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
258
266
  token: undefined,
259
267
  user: undefined,
260
268
  lastLogin: undefined,
@@ -275,7 +283,7 @@ describe('Login Command', () => {
275
283
  authControllerLogin: jest.fn().mockRejectedValue(new Error('Network error')),
276
284
  };
277
285
  mockGetConfig.mockResolvedValue({
278
- server: 'http://localhost:3000',
286
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
279
287
  token: undefined,
280
288
  user: undefined,
281
289
  lastLogin: undefined,
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const search_1 = require("../../commands/search");
37
37
  const config = __importStar(require("../../config"));
38
+ const fs = __importStar(require("fs-extra"));
39
+ const path = __importStar(require("path"));
40
+ // Load default-config server URL for unit tests
41
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
42
+ const defaultConfig = fs.existsSync(defaultConfigPath)
43
+ ? JSON.parse(fs.readFileSync(defaultConfigPath, 'utf8'))
44
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
45
+ const DEFAULT_SERVER_URL = defaultConfig.server;
38
46
  // Mock dependencies
39
47
  jest.mock('../../config', () => ({
40
48
  getConfig: jest.fn(),
@@ -60,7 +68,7 @@ describe('Search Command', () => {
60
68
  describe('search success', () => {
61
69
  it('should search rules by query', async () => {
62
70
  mockGetConfig.mockResolvedValue({
63
- server: 'http://localhost:3000',
71
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
64
72
  token: 'test-token',
65
73
  user: { id: 'user-id', username: 'testuser' },
66
74
  lastLogin: new Date().toISOString(),
@@ -83,7 +91,7 @@ describe('Search Command', () => {
83
91
  };
84
92
  mockCreateApi.mockResolvedValue({ rulesApi: mockRulesApi });
85
93
  await (0, search_1.searchCommand)('auth', {});
86
- expect(mockCreateApi).toHaveBeenCalledWith({ server: 'http://localhost:3000' });
94
+ expect(mockCreateApi).toHaveBeenCalledWith({ server: DEFAULT_SERVER_URL });
87
95
  expect(mockRulesApi.rulesControllerFindAll).toHaveBeenCalledWith(undefined, // page
88
96
  undefined, // limit
89
97
  undefined, // tag
@@ -95,7 +103,7 @@ describe('Search Command', () => {
95
103
  });
96
104
  it('should apply additional filters with search query', async () => {
97
105
  mockGetConfig.mockResolvedValue({
98
- server: 'http://localhost:3000',
106
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
99
107
  token: 'test-token',
100
108
  user: { id: 'user-id', username: 'testuser' },
101
109
  lastLogin: new Date().toISOString(),
@@ -128,7 +136,7 @@ describe('Search Command', () => {
128
136
  });
129
137
  it('should handle no search results', async () => {
130
138
  mockGetConfig.mockResolvedValue({
131
- server: 'http://localhost:3000',
139
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
132
140
  token: 'test-token',
133
141
  user: { id: 'user-id', username: 'testuser' },
134
142
  lastLogin: new Date().toISOString(),
@@ -146,7 +154,7 @@ describe('Search Command', () => {
146
154
  describe('search failure', () => {
147
155
  it('should exit with error when not logged in', async () => {
148
156
  mockGetConfig.mockResolvedValue({
149
- server: 'http://localhost:3000',
157
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
150
158
  token: undefined,
151
159
  user: undefined,
152
160
  });
@@ -155,7 +163,7 @@ describe('Search Command', () => {
155
163
  });
156
164
  it('should validate query parameter', async () => {
157
165
  mockGetConfig.mockResolvedValue({
158
- server: 'http://localhost:3000',
166
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
159
167
  token: 'test-token',
160
168
  user: { id: 'user-id', username: 'testuser' },
161
169
  lastLogin: new Date().toISOString(),
@@ -165,7 +173,7 @@ describe('Search Command', () => {
165
173
  });
166
174
  it('should handle API errors gracefully', async () => {
167
175
  mockGetConfig.mockResolvedValue({
168
- server: 'http://localhost:3000',
176
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
169
177
  token: 'test-token',
170
178
  user: { id: 'user-id', username: 'testuser' },
171
179
  lastLogin: new Date().toISOString(),
@@ -41,6 +41,14 @@ const config = __importStar(require("../../config"));
41
41
  const axios_1 = __importDefault(require("axios"));
42
42
  const fs = __importStar(require("fs-extra"));
43
43
  const form_data_1 = __importDefault(require("form-data"));
44
+ const fs_1 = require("fs");
45
+ const path = __importStar(require("path"));
46
+ // Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
47
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
48
+ const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
49
+ ? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
50
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
51
+ const DEFAULT_SERVER_URL = defaultConfig.server;
44
52
  // Mock dependencies
45
53
  jest.mock('../../config', () => ({
46
54
  getConfig: jest.fn(),
@@ -89,7 +97,7 @@ describe('Upload Command', () => {
89
97
  describe('upload success', () => {
90
98
  it('should upload file successfully', async () => {
91
99
  mockGetConfig.mockResolvedValue({
92
- server: 'http://localhost:3000',
100
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
93
101
  token: 'test-token',
94
102
  user: { id: 'user-id', username: 'testuser' },
95
103
  lastLogin: new Date().toISOString(),
@@ -118,7 +126,8 @@ describe('Upload Command', () => {
118
126
  description: 'Test description',
119
127
  });
120
128
  expect(mockFsPathExists).toHaveBeenCalledWith('./test.md');
121
- expect(mockAxiosPost).toHaveBeenCalledWith('http://localhost:3000/api/rules', expect.any(Object), expect.objectContaining({
129
+ expect(mockAxiosPost).toHaveBeenCalledWith(`${DEFAULT_SERVER_URL}/api/rules`, // Use default-config server URL
130
+ expect.any(Object), expect.objectContaining({
122
131
  headers: expect.objectContaining({
123
132
  Authorization: 'Bearer test-token',
124
133
  }),
@@ -129,7 +138,7 @@ describe('Upload Command', () => {
129
138
  describe('upload failure', () => {
130
139
  it('should handle file not found error', async () => {
131
140
  mockGetConfig.mockResolvedValue({
132
- server: 'http://localhost:3000',
141
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
133
142
  token: 'test-token',
134
143
  user: { id: 'user-id', username: 'testuser' },
135
144
  lastLogin: new Date().toISOString(),
@@ -145,7 +154,7 @@ describe('Upload Command', () => {
145
154
  // TC-UNIT-CLI-033: Upload with file size validation
146
155
  it('should validate file size limits', async () => {
147
156
  mockGetConfig.mockResolvedValue({
148
- server: 'http://localhost:3000',
157
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
149
158
  token: 'test-token',
150
159
  user: { id: 'user-id', username: 'testuser' },
151
160
  lastLogin: new Date().toISOString(),
@@ -164,7 +173,7 @@ describe('Upload Command', () => {
164
173
  // TC-UNIT-CLI-034: Upload with file type validation
165
174
  it('should validate file type', async () => {
166
175
  mockGetConfig.mockResolvedValue({
167
- server: 'http://localhost:3000',
176
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
168
177
  token: 'test-token',
169
178
  user: { id: 'user-id', username: 'testuser' },
170
179
  lastLogin: new Date().toISOString(),
@@ -182,7 +191,7 @@ describe('Upload Command', () => {
182
191
  // TC-UNIT-CLI-035: Upload with API failure
183
192
  it.skip('should handle API upload failure', async () => {
184
193
  mockGetConfig.mockResolvedValue({
185
- server: 'http://localhost:3000',
194
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
186
195
  token: 'test-token',
187
196
  user: { id: 'user-id', username: 'testuser' },
188
197
  lastLogin: new Date().toISOString(),
@@ -206,7 +215,7 @@ describe('Upload Command', () => {
206
215
  // TC-UNIT-CLI-036: Upload with authentication error
207
216
  it.skip('should handle authentication errors', async () => {
208
217
  mockGetConfig.mockResolvedValue({
209
- server: 'http://localhost:3000',
218
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
210
219
  token: 'invalid-token',
211
220
  user: { id: 'user-id', username: 'testuser' },
212
221
  lastLogin: new Date().toISOString(),
@@ -230,7 +239,7 @@ describe('Upload Command', () => {
230
239
  // TC-UNIT-CLI-037: Upload with network error
231
240
  it.skip('should handle network errors', async () => {
232
241
  mockGetConfig.mockResolvedValue({
233
- server: 'http://localhost:3000',
242
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
234
243
  token: 'test-token',
235
244
  user: { id: 'user-id', username: 'testuser' },
236
245
  lastLogin: new Date().toISOString(),
@@ -249,7 +258,7 @@ describe('Upload Command', () => {
249
258
  // TC-UNIT-CLI-038: Upload with metadata extraction
250
259
  it.skip('should extract and send metadata correctly', async () => {
251
260
  mockGetConfig.mockResolvedValue({
252
- server: 'http://localhost:3000',
261
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
253
262
  token: 'test-token',
254
263
  user: { id: 'user-id', username: 'testuser' },
255
264
  lastLogin: new Date().toISOString(),
@@ -289,7 +298,7 @@ describe('Upload Command', () => {
289
298
  // TC-UNIT-CLI-039: Upload with default version
290
299
  it.skip('should use default version when not specified', async () => {
291
300
  mockGetConfig.mockResolvedValue({
292
- server: 'http://localhost:3000',
301
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
293
302
  token: 'test-token',
294
303
  user: { id: 'user-id', username: 'testuser' },
295
304
  lastLogin: new Date().toISOString(),
@@ -315,7 +324,7 @@ describe('Upload Command', () => {
315
324
  // TC-UNIT-CLI-040: Upload with missing required parameters
316
325
  it.skip('should validate required parameters', async () => {
317
326
  mockGetConfig.mockResolvedValue({
318
- server: 'http://localhost:3000',
327
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
319
328
  token: 'test-token',
320
329
  user: { id: 'user-id', username: 'testuser' },
321
330
  lastLogin: new Date().toISOString(),
@@ -333,7 +342,7 @@ describe('Upload Command', () => {
333
342
  // TC-UNIT-CLI-041: Upload command success with all parameters
334
343
  it.skip('should handle successful upload with all parameters', async () => {
335
344
  mockGetConfig.mockResolvedValue({
336
- server: 'http://localhost:3000',
345
+ server: DEFAULT_SERVER_URL, // Use default-config server URL
337
346
  token: 'test-token',
338
347
  user: { id: 'user-id', username: 'testuser' },
339
348
  lastLogin: new Date().toISOString(),
@@ -35,6 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const globals_1 = require("@jest/globals");
37
37
  const config_1 = require("../config");
38
+ const fs_1 = require("fs");
39
+ const path = __importStar(require("path"));
40
+ // Load default-config server URL for unit tests (use Node.js fs, not fs-extra which is mocked)
41
+ const defaultConfigPath = path.join(process.cwd(), 'default-config.json');
42
+ const defaultConfig = (0, fs_1.existsSync)(defaultConfigPath)
43
+ ? JSON.parse((0, fs_1.readFileSync)(defaultConfigPath, 'utf8'))
44
+ : { server: 'https://cursorkit-backend-pending-deployment.us-central1.run.app' };
45
+ const DEFAULT_SERVER_URL = defaultConfig.server;
38
46
  // Mock dependencies
39
47
  globals_1.jest.mock('fs-extra');
40
48
  globals_1.jest.mock('os', () => ({
@@ -42,7 +50,6 @@ globals_1.jest.mock('os', () => ({
42
50
  }));
43
51
  const fs = __importStar(require("fs-extra"));
44
52
  const os = __importStar(require("os"));
45
- const path = __importStar(require("path"));
46
53
  describe('Config', () => {
47
54
  const mockHomeDir = 'C:\\Users\\trieu';
48
55
  const mockConfigDir = path.join(mockHomeDir, '.kitstore');
@@ -64,10 +71,23 @@ describe('Config', () => {
64
71
  describe('getConfig', () => {
65
72
  it('should return default config when config file does not exist', async () => {
66
73
  // @ts-ignore
67
- fs.pathExists.mockResolvedValue(false);
74
+ fs.pathExists.mockImplementation((filePath) => {
75
+ // Return true for default-config.json path, false for config.json
76
+ if (filePath.includes('default-config.json')) {
77
+ return Promise.resolve(true);
78
+ }
79
+ return Promise.resolve(false);
80
+ });
81
+ // @ts-ignore
82
+ fs.readJson.mockImplementation((filePath) => {
83
+ if (filePath.includes('default-config.json')) {
84
+ return Promise.resolve({ server: DEFAULT_SERVER_URL });
85
+ }
86
+ return Promise.reject(new Error('File not found'));
87
+ });
68
88
  const result = await (0, config_1.getConfig)();
69
89
  expect(result).toEqual({
70
- server: 'http://localhost:3000'
90
+ server: DEFAULT_SERVER_URL // Use default-config server URL
71
91
  });
72
92
  expect(fs.ensureDir).toHaveBeenCalledWith(mockConfigDir);
73
93
  expect(fs.pathExists).toHaveBeenCalledWith(mockConfigFile);
@@ -79,9 +99,20 @@ describe('Config', () => {
79
99
  user: { id: '123', username: 'testuser' }
80
100
  };
81
101
  // @ts-ignore
82
- fs.pathExists.mockResolvedValue(true);
102
+ fs.pathExists.mockImplementation((filePath) => {
103
+ // Return true for config.json, false for default-config.json (file config takes precedence)
104
+ if (filePath === mockConfigFile) {
105
+ return Promise.resolve(true);
106
+ }
107
+ return Promise.resolve(false);
108
+ });
83
109
  // @ts-ignore
84
- fs.readJson.mockResolvedValue(fileConfig);
110
+ fs.readJson.mockImplementation((filePath) => {
111
+ if (filePath === mockConfigFile) {
112
+ return Promise.resolve(fileConfig);
113
+ }
114
+ return Promise.reject(new Error('File not found'));
115
+ });
85
116
  const result = await (0, config_1.getConfig)();
86
117
  expect(result).toEqual({
87
118
  server: 'https://api.example.com', // From file
@@ -92,20 +123,47 @@ describe('Config', () => {
92
123
  });
93
124
  it('should handle file read errors gracefully', async () => {
94
125
  // @ts-ignore
95
- fs.pathExists.mockResolvedValue(true);
126
+ fs.pathExists.mockImplementation((filePath) => {
127
+ // Return true for default-config.json path, true for config.json (exists but read fails)
128
+ if (filePath.includes('default-config.json')) {
129
+ return Promise.resolve(true);
130
+ }
131
+ return Promise.resolve(true); // config.json exists
132
+ });
96
133
  // @ts-ignore
97
- fs.readJson.mockRejectedValue(new Error('Read failed'));
134
+ fs.readJson.mockImplementation((filePath) => {
135
+ if (filePath.includes('default-config.json')) {
136
+ return Promise.resolve({ server: DEFAULT_SERVER_URL });
137
+ }
138
+ // config.json read fails
139
+ return Promise.reject(new Error('Read failed'));
140
+ });
98
141
  const result = await (0, config_1.getConfig)();
99
142
  expect(result).toEqual({
100
- server: 'http://localhost:3000'
143
+ server: DEFAULT_SERVER_URL // Use default-config server URL
101
144
  });
102
145
  });
103
146
  it('should handle ensureDir errors gracefully', async () => {
104
147
  // @ts-ignore
105
148
  fs.ensureDir.mockRejectedValue(new Error('Permission denied'));
149
+ // @ts-ignore
150
+ fs.pathExists.mockImplementation((filePath) => {
151
+ // Return true for default-config.json path
152
+ if (filePath.includes('default-config.json')) {
153
+ return Promise.resolve(true);
154
+ }
155
+ return Promise.resolve(false);
156
+ });
157
+ // @ts-ignore
158
+ fs.readJson.mockImplementation((filePath) => {
159
+ if (filePath.includes('default-config.json')) {
160
+ return Promise.resolve({ server: DEFAULT_SERVER_URL });
161
+ }
162
+ return Promise.reject(new Error('File not found'));
163
+ });
106
164
  const result = await (0, config_1.getConfig)();
107
165
  expect(result).toEqual({
108
- server: 'http://localhost:3000'
166
+ server: DEFAULT_SERVER_URL // Use default-config server URL
109
167
  });
110
168
  });
111
169
  });
@@ -121,7 +179,7 @@ describe('Config', () => {
121
179
  expect(fs.writeJson).toHaveBeenCalledWith(mockConfigFile, config, { spaces: 2 });
122
180
  });
123
181
  it('should handle write errors', async () => {
124
- const config = { server: 'http://localhost:3000' };
182
+ const config = { server: DEFAULT_SERVER_URL }; // Use default-config server URL
125
183
  // @ts-ignore
126
184
  fs.writeJson.mockRejectedValue(new Error('Write failed'));
127
185
  await expect((0, config_1.saveConfig)(config)).rejects.toThrow('Write failed');
@@ -168,9 +226,9 @@ describe('Config', () => {
168
226
  });
169
227
  it('should allow optional properties', () => {
170
228
  const minimalConfig = {
171
- server: 'http://localhost:3000'
229
+ server: DEFAULT_SERVER_URL // Use default-config server URL
172
230
  };
173
- expect(minimalConfig.server).toBe('http://localhost:3000');
231
+ expect(minimalConfig.server).toBe(DEFAULT_SERVER_URL); // Use default-config server URL
174
232
  expect(minimalConfig.token).toBeUndefined();
175
233
  expect(minimalConfig.user).toBeUndefined();
176
234
  expect(minimalConfig.lastLogin).toBeUndefined();
@@ -12,9 +12,9 @@ const client_1 = require("../api/client");
12
12
  * @requirement TC-UNIT-CLI-001, TC-UNIT-CLI-002, TC-E2E-CLI-001
13
13
  */
14
14
  async function loginCommand(options) {
15
+ const config = await (0, config_1.getConfig)();
16
+ const server = options.server || config.server;
15
17
  try {
16
- const config = await (0, config_1.getConfig)();
17
- const server = options.server || config.server;
18
18
  let email = options.email;
19
19
  let password = options.password;
20
20
  if (!email) {
@@ -52,15 +52,44 @@ async function loginCommand(options) {
52
52
  }
53
53
  }
54
54
  catch (err) {
55
+ let errorMessage = 'Unknown error';
55
56
  if (axios_1.default.isAxiosError(err)) {
56
- console.error(`❌ Login failed: ${err.response?.data?.message?.message || err.response?.data?.message || err.message}`);
57
+ // Handle Axios errors (network, HTTP errors)
58
+ const status = err.response?.status;
59
+ const message = err.response?.data?.message?.message ||
60
+ err.response?.data?.message ||
61
+ err.message;
62
+ if (status === 401) {
63
+ errorMessage = 'Invalid email or password';
64
+ }
65
+ else if (status === 429) {
66
+ errorMessage = 'Rate limit exceeded. Please try again later';
67
+ }
68
+ else if (err.code === 'ECONNREFUSED') {
69
+ errorMessage = `Cannot connect to server at ${err.config?.url || server}. Is the server running?`;
70
+ }
71
+ else if (err.code === 'ENOTFOUND') {
72
+ errorMessage = `Server not found: ${err.config?.url || server}. Check your server URL.`;
73
+ }
74
+ else if (err.code === 'ETIMEDOUT' || err.code === 'ECONNABORTED') {
75
+ errorMessage = `Connection timeout. Server at ${err.config?.url || server} did not respond in time.`;
76
+ }
77
+ else {
78
+ errorMessage = message || `HTTP ${status || 'error'}`;
79
+ }
57
80
  }
58
81
  else if (err instanceof Error) {
59
- console.error(`❌ Login failed: ${err.message}`);
82
+ errorMessage = err.message;
60
83
  }
61
- else {
62
- console.error(`❌ Login failed: ${err}`);
84
+ else if (typeof err === 'string') {
85
+ errorMessage = err;
86
+ }
87
+ else if (err && typeof err === 'object') {
88
+ // Try to extract meaningful information from object
89
+ const errObj = err;
90
+ errorMessage = errObj.message || errObj.error || errObj.toString() || 'Unknown error occurred';
63
91
  }
92
+ console.error(`❌ Login failed: ${errorMessage}`);
64
93
  process.exit(1);
65
94
  }
66
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitstore-cli",
3
- "version": "1.0.39",
3
+ "version": "1.0.41",
4
4
  "description": "CLI tool for Cursor Kit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {