kitstore-cli 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/default-config.json +1 -0
  2. package/dist/config.js +20 -4
  3. package/package.json +5 -1
  4. package/.env.test +0 -4
  5. package/.eslintrc.js +0 -29
  6. package/e2e/install.e2e.test.ts +0 -237
  7. package/e2e/integration.e2e.test.ts +0 -346
  8. package/e2e/login.e2e.test.ts +0 -188
  9. package/jest.config.js +0 -24
  10. package/openapitools.json +0 -7
  11. package/src/__tests__/commands/init.test.ts +0 -52
  12. package/src/__tests__/commands/install.test.ts +0 -449
  13. package/src/__tests__/commands/list.test.ts +0 -164
  14. package/src/__tests__/commands/login.test.ts +0 -293
  15. package/src/__tests__/commands/rule-check.test.ts +0 -52
  16. package/src/__tests__/commands/search.test.ts +0 -168
  17. package/src/__tests__/commands/upload.test.ts +0 -404
  18. package/src/__tests__/config.test.ts +0 -181
  19. package/src/__tests__/setup.ts +0 -11
  20. package/src/api/client.ts +0 -20
  21. package/src/api/generated/.openapi-generator/FILES +0 -17
  22. package/src/api/generated/.openapi-generator/VERSION +0 -1
  23. package/src/api/generated/.openapi-generator-ignore +0 -23
  24. package/src/api/generated/api.ts +0 -1171
  25. package/src/api/generated/base.ts +0 -62
  26. package/src/api/generated/common.ts +0 -113
  27. package/src/api/generated/configuration.ts +0 -121
  28. package/src/api/generated/docs/AuthApi.md +0 -158
  29. package/src/api/generated/docs/AuthResponseDto.md +0 -22
  30. package/src/api/generated/docs/AuthUserDto.md +0 -24
  31. package/src/api/generated/docs/HealthApi.md +0 -183
  32. package/src/api/generated/docs/LoginDto.md +0 -22
  33. package/src/api/generated/docs/RegisterDto.md +0 -24
  34. package/src/api/generated/docs/RuleAuthorDto.md +0 -22
  35. package/src/api/generated/docs/RuleResponseDto.md +0 -36
  36. package/src/api/generated/docs/RulesApi.md +0 -289
  37. package/src/api/generated/git_push.sh +0 -57
  38. package/src/api/generated/index.ts +0 -18
  39. package/src/commands/init.ts +0 -46
  40. package/src/commands/install.ts +0 -129
  41. package/src/commands/list.ts +0 -71
  42. package/src/commands/login.ts +0 -65
  43. package/src/commands/rule-check.ts +0 -49
  44. package/src/commands/search.ts +0 -66
  45. package/src/commands/upload.ts +0 -117
  46. package/src/config.ts +0 -66
  47. package/src/index.ts +0 -79
  48. package/test-cli-config.js +0 -118
  49. package/tsconfig.json +0 -24
@@ -0,0 +1 @@
1
+ {"server": "https://test-backend.example.com"}
package/dist/config.js CHANGED
@@ -44,21 +44,37 @@ const path = __importStar(require("path"));
44
44
  const os = __importStar(require("os"));
45
45
  const CONFIG_DIR = process.env.KITSTORE_CONFIG_DIR || path.join(os.homedir(), '.kitstore');
46
46
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
47
+ async function loadBundledDefaultConfig() {
48
+ try {
49
+ // Try to load the bundled default config file
50
+ const defaultConfigPath = path.join(__dirname, '..', 'default-config.json');
51
+ if (await fs.pathExists(defaultConfigPath)) {
52
+ const defaultConfig = await fs.readJson(defaultConfigPath);
53
+ return defaultConfig;
54
+ }
55
+ }
56
+ catch (err) {
57
+ // Ignore errors - bundled config may not exist
58
+ }
59
+ return null;
60
+ }
47
61
  async function getConfig() {
48
62
  try {
49
63
  await fs.ensureDir(CONFIG_DIR);
50
64
  if (await fs.pathExists(CONFIG_FILE)) {
51
65
  const content = await fs.readJson(CONFIG_FILE);
52
- // Environment variable takes precedence over config file, fallback to localhost for development
53
- const server = process.env.AGENTKIT_BACKEND_URL || content.server || 'http://localhost:3000';
66
+ // Environment variable takes precedence over config file, bundled default, then localhost
67
+ const defaultConfig = await loadBundledDefaultConfig();
68
+ const server = process.env.AGENTKIT_BACKEND_URL || content.server || defaultConfig?.server || 'http://localhost:3000';
54
69
  return { ...content, server };
55
70
  }
56
71
  }
57
72
  catch (err) {
58
73
  // Ignore errors
59
74
  }
60
- // Use production backend URL if available, fallback to localhost for development
61
- const server = process.env.AGENTKIT_BACKEND_URL || 'http://localhost:3000';
75
+ // No local config file - try bundled default config
76
+ const defaultConfig = await loadBundledDefaultConfig();
77
+ const server = process.env.AGENTKIT_BACKEND_URL || defaultConfig?.server || 'http://localhost:3000';
62
78
  return { server };
63
79
  }
64
80
  async function saveConfig(config) {
package/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "kitstore-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "CLI tool for Cursor Kit",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "kitstore": "./dist/index.js"
8
8
  },
9
+ "files": [
10
+ "dist/",
11
+ "default-config.json"
12
+ ],
9
13
  "scripts": {
10
14
  "build": "tsc",
11
15
  "dev": "tsx src/index.ts",
package/.env.test DELETED
@@ -1,4 +0,0 @@
1
- # Test environment configuration for CLI
2
- NODE_ENV=test
3
- API_BASE_URL=http://localhost:3001
4
- JWT_SECRET=test-secret-key-for-cli-tests-min-32-chars-long
package/.eslintrc.js DELETED
@@ -1,29 +0,0 @@
1
- module.exports = {
2
- parser: '@typescript-eslint/parser',
3
- parserOptions: {
4
- project: 'tsconfig.json',
5
- tsconfigRootDir: __dirname,
6
- sourceType: 'module',
7
- },
8
- plugins: ['@typescript-eslint/eslint-plugin'],
9
- extends: [
10
- 'eslint:recommended',
11
- '@typescript-eslint/recommended',
12
- ],
13
- root: true,
14
- env: {
15
- node: true,
16
- jest: true,
17
- },
18
- ignorePatterns: ['.eslintrc.js', 'dist'],
19
- rules: {
20
- '@typescript-eslint/interface-name-prefix': 'off',
21
- '@typescript-eslint/explicit-function-return-type': 'off',
22
- '@typescript-eslint/explicit-module-boundary-types': 'off',
23
- '@typescript-eslint/no-explicit-any': 'off',
24
- '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
25
- },
26
- };
27
-
28
-
29
-
@@ -1,237 +0,0 @@
1
- import { execSync } from 'child_process';
2
- import { existsSync, unlinkSync, readFileSync, mkdirSync, rmSync } from 'fs';
3
- import * as path from 'path';
4
-
5
- // TC-E2E-CLI-002: Install rule flow
6
- // TC-E2E-CLI-005: List rules
7
- // TC-E2E-CLI-011: Search rules
8
- describe('CLI Install E2E Tests', () => {
9
- const tempHome = path.join(process.cwd(), 'temp-home-install');
10
- const configDir = path.join(tempHome, '.kitstore');
11
- const configPath = path.join(configDir, 'config.json');
12
- const installDir = path.join(tempHome, '.cursor');
13
- const rulesDir = path.join(installDir, 'rules');
14
- const cliPath = path.join(process.cwd(), 'dist', 'index.js');
15
-
16
- beforeAll(() => {
17
- if (!existsSync(tempHome)) {
18
- mkdirSync(tempHome, { recursive: true });
19
- }
20
- });
21
-
22
- beforeEach(() => {
23
- // Setup mock config for authenticated user
24
- const config = {
25
- server: 'http://localhost:3000',
26
- token: 'test-token',
27
- user: { id: 'test-user-id', username: 'testuser' },
28
- lastLogin: new Date().toISOString(),
29
- };
30
-
31
- // Ensure config directory exists
32
- if (!existsSync(configDir)) {
33
- mkdirSync(configDir, { recursive: true });
34
- }
35
- require('fs').writeFileSync(configPath, JSON.stringify(config, null, 2));
36
- });
37
-
38
- afterAll(() => {
39
- // Clean up temp home
40
- if (existsSync(tempHome)) {
41
- rmSync(tempHome, { recursive: true, force: true });
42
- }
43
- });
44
-
45
- afterEach(() => {
46
- // Clean up config and installed rules
47
- if (existsSync(configPath)) {
48
- unlinkSync(configPath);
49
- }
50
- if (existsSync(rulesDir)) {
51
- rmSync(rulesDir, { recursive: true, force: true });
52
- }
53
- });
54
-
55
- // TC-E2E-CLI-005: List rules
56
- test('should list rules successfully', () => {
57
- // Skip if CLI is not built
58
- if (!existsSync(cliPath)) {
59
- console.warn('Skipping test: CLI not built');
60
- return;
61
- }
62
-
63
- try {
64
- // Run list command
65
- const result = execSync(`node ${cliPath} list`, {
66
- encoding: 'utf8',
67
- timeout: 10000,
68
- env: {
69
- ...process.env,
70
- NODE_ENV: 'test',
71
- AGENTKIT_CONFIG_DIR: configDir,
72
- HOME: tempHome,
73
- USERPROFILE: tempHome,
74
- HOMEDRIVE: tempHome.substring(0, 2),
75
- HOMEPATH: tempHome.substring(2)
76
- }
77
- });
78
-
79
- // Should show found rules or empty message
80
- expect(result).toMatch(/📋 Found \d+ rules\/commands|📭 No rules or commands found/);
81
-
82
- } catch (error: any) {
83
- // If backend not running, skip test
84
- const output = (error.stdout || '') + (error.stderr || '');
85
- if (
86
- output.includes('ECONNREFUSED') ||
87
- output.includes('ENOTFOUND') ||
88
- output.includes('Not logged in') ||
89
- output.includes('Failed to list rules') ||
90
- output.includes('failed: Error')
91
- ) {
92
- console.warn('Skipping test: Backend server not running or unauthorized');
93
- return;
94
- } else {
95
- throw error;
96
- }
97
- }
98
- });
99
-
100
- // TC-E2E-CLI-011: Search rules
101
- test('should search rules successfully', () => {
102
- // Skip if CLI is not built
103
- if (!existsSync(cliPath)) {
104
- console.warn('Skipping test: CLI not built');
105
- return;
106
- }
107
-
108
- try {
109
- // Run search command
110
- const result = execSync(`node ${cliPath} search "test"`, {
111
- encoding: 'utf8',
112
- timeout: 10000,
113
- env: {
114
- ...process.env,
115
- NODE_ENV: 'test',
116
- AGENTKIT_CONFIG_DIR: configDir,
117
- HOME: tempHome,
118
- USERPROFILE: tempHome,
119
- HOMEDRIVE: tempHome.substring(0, 2),
120
- HOMEPATH: tempHome.substring(2)
121
- }
122
- });
123
-
124
- // Should show search results
125
- expect(result).toMatch(/🔍 Search results for "test"|🔍 No rules or commands found matching "test"/);
126
-
127
- } catch (error: any) {
128
- // If backend not running, skip test
129
- const output = (error.stdout || '') + (error.stderr || '');
130
- if (
131
- output.includes('ECONNREFUSED') ||
132
- output.includes('ENOTFOUND') ||
133
- output.includes('Not logged in') ||
134
- output.includes('Failed to list rules') ||
135
- output.includes('failed: Error')
136
- ) {
137
- console.warn('Skipping test: Backend server not running or unauthorized');
138
- return;
139
- } else {
140
- throw error;
141
- }
142
- }
143
- });
144
-
145
- // TC-E2E-CLI-012: List with filters
146
- test('should list rules with tag filter', () => {
147
- // Skip if CLI is not built
148
- if (!existsSync(cliPath)) {
149
- console.warn('Skipping test: CLI not built');
150
- return;
151
- }
152
-
153
- try {
154
- // Run list command with tag filter
155
- const result = execSync(`node ${cliPath} list --tag test`, {
156
- encoding: 'utf8',
157
- timeout: 10000,
158
- env: {
159
- ...process.env,
160
- NODE_ENV: 'test',
161
- AGENTKIT_CONFIG_DIR: configDir,
162
- HOME: tempHome,
163
- USERPROFILE: tempHome,
164
- HOMEDRIVE: tempHome.substring(0, 2),
165
- HOMEPATH: tempHome.substring(2)
166
- }
167
- });
168
-
169
- // Should show filtered results
170
- expect(result).toMatch(/📋 Found \d+ rules\/commands|📭 No rules or commands found/);
171
-
172
- } catch (error: any) {
173
- // If backend not running, skip test
174
- const output = (error.stdout || '') + (error.stderr || '');
175
- if (
176
- output.includes('ECONNREFUSED') ||
177
- output.includes('ENOTFOUND') ||
178
- output.includes('Not logged in') ||
179
- output.includes('Failed to list rules') ||
180
- output.includes('failed: Error')
181
- ) {
182
- console.warn('Skipping test: Backend server not running or unauthorized');
183
- return;
184
- } else {
185
- throw error;
186
- }
187
- }
188
- });
189
-
190
- // TC-E2E-CLI-013: List with type filter
191
- test('should list rules with type filter', () => {
192
- // Skip if CLI is not built
193
- if (!existsSync(cliPath)) {
194
- console.warn('Skipping test: CLI not built');
195
- return;
196
- }
197
-
198
- try {
199
- // Run list command with type filter
200
- const result = execSync(`node ${cliPath} list --type rule`, {
201
- encoding: 'utf8',
202
- timeout: 10000,
203
- env: {
204
- ...process.env,
205
- NODE_ENV: 'test',
206
- AGENTKIT_CONFIG_DIR: configDir,
207
- HOME: tempHome,
208
- USERPROFILE: tempHome,
209
- HOMEDRIVE: tempHome.substring(0, 2),
210
- HOMEPATH: tempHome.substring(2)
211
- }
212
- });
213
-
214
- // Should show filtered results
215
- expect(result).toMatch(/📋 Found \d+ rules\/commands|📭 No rules or commands found/);
216
-
217
- } catch (error: any) {
218
- // If backend not running, skip test
219
- const output = (error.stdout || '') + (error.stderr || '');
220
- if (
221
- output.includes('ECONNREFUSED') ||
222
- output.includes('ENOTFOUND') ||
223
- output.includes('Not logged in') ||
224
- output.includes('Failed to list rules') ||
225
- output.includes('failed: Error')
226
- ) {
227
- console.warn('Skipping test: Backend server not running or unauthorized');
228
- return;
229
- } else {
230
- throw error;
231
- }
232
- }
233
- });
234
- });
235
-
236
-
237
-
@@ -1,346 +0,0 @@
1
- import { execSync } from 'child_process';
2
- import { existsSync, readFileSync, unlinkSync } from 'fs';
3
- import * as path from 'path';
4
-
5
- // TC-E2E-CLI-026 to TC-E2E-CLI-030
6
- describe('CLI Integration E2E Tests', () => {
7
- const tempHome = path.join(process.cwd(), 'temp-home-integration');
8
- const configDir = path.join(tempHome, '.kitstore');
9
- const configPath = path.join(configDir, 'config.json');
10
- const cliPath = path.join(process.cwd(), 'dist', 'index.js');
11
-
12
- beforeAll(() => {
13
- if (!existsSync(tempHome)) {
14
- require('fs').mkdirSync(tempHome, { recursive: true });
15
- }
16
- });
17
-
18
- beforeEach(() => {
19
- // Setup authenticated config for integration tests
20
- const config = {
21
- server: 'http://localhost:3000',
22
- token: 'test-token',
23
- user: { id: 'test-user-id', username: 'testuser' },
24
- lastLogin: new Date().toISOString(),
25
- };
26
-
27
- // Ensure config directory exists
28
- if (!existsSync(configDir)) {
29
- require('fs').mkdirSync(configDir, { recursive: true });
30
- }
31
- require('fs').writeFileSync(configPath, JSON.stringify(config, null, 2));
32
- });
33
-
34
- afterAll(() => {
35
- // Clean up temp home
36
- if (existsSync(tempHome)) {
37
- require('fs-extra').removeSync(tempHome);
38
- }
39
- });
40
-
41
- afterEach(() => {
42
- // Clean up config
43
- if (existsSync(configPath)) {
44
- unlinkSync(configPath);
45
- }
46
- });
47
-
48
- // TC-E2E-CLI-026: CLI ↔ Backend ↔ Database integration (list command)
49
- test('should integrate CLI list with backend API and database', () => {
50
- if (!existsSync(cliPath)) {
51
- console.warn('Skipping test: CLI not built');
52
- return;
53
- }
54
-
55
- try {
56
- const result = execSync(`node ${cliPath} list`, {
57
- encoding: 'utf8',
58
- timeout: 15000,
59
- env: {
60
- ...process.env,
61
- NODE_ENV: 'test',
62
- AGENTKIT_CONFIG_DIR: configDir,
63
- HOME: tempHome,
64
- USERPROFILE: tempHome,
65
- HOMEDRIVE: tempHome.substring(0, 2),
66
- HOMEPATH: tempHome.substring(2)
67
- }
68
- });
69
-
70
- // Should successfully query database through backend API
71
- expect(result).toMatch(/📋 Found \d+ rules\/commands|📭 No rules or commands found/);
72
-
73
- // Verify the command completed without errors
74
- expect(result).not.toContain('❌');
75
-
76
- } catch (error: any) {
77
- const output = (error.stdout || '') + (error.stderr || '');
78
- if (
79
- output.includes('ECONNREFUSED') ||
80
- output.includes('ENOTFOUND') ||
81
- output.includes('Not logged in') ||
82
- output.includes('failed: Error') ||
83
- output.includes('AggregateError')
84
- ) {
85
- console.warn('Skipping test: Backend server not running or unauthorized');
86
- return;
87
- } else {
88
- throw error;
89
- }
90
- }
91
- });
92
-
93
- // TC-E2E-CLI-027: CLI ↔ Backend ↔ Database integration (search command)
94
- test('should integrate CLI search with backend API and database filtering', () => {
95
- if (!existsSync(cliPath)) {
96
- console.warn('Skipping test: CLI not built');
97
- return;
98
- }
99
-
100
- try {
101
- const result = execSync(`node ${cliPath} search "test"`, {
102
- encoding: 'utf8',
103
- timeout: 15000,
104
- env: {
105
- ...process.env,
106
- NODE_ENV: 'test',
107
- AGENTKIT_CONFIG_DIR: configDir,
108
- HOME: tempHome,
109
- USERPROFILE: tempHome,
110
- HOMEDRIVE: tempHome.substring(0, 2),
111
- HOMEPATH: tempHome.substring(2)
112
- }
113
- });
114
-
115
- // Should successfully query and filter database through backend API
116
- expect(result).toMatch(/🔍 Search results for "test"|🔍 No rules or commands found matching "test"/);
117
-
118
- // Verify search functionality works
119
- expect(result).not.toContain('❌');
120
-
121
- } catch (error: any) {
122
- const output = (error.stdout || '') + (error.stderr || '');
123
- if (
124
- output.includes('ECONNREFUSED') ||
125
- output.includes('ENOTFOUND') ||
126
- output.includes('Not logged in') ||
127
- output.includes('failed: Error') ||
128
- output.includes('AggregateError')
129
- ) {
130
- console.warn('Skipping test: Backend server not running or unauthorized');
131
- return;
132
- } else {
133
- throw error;
134
- }
135
- }
136
- });
137
-
138
- // TC-E2E-CLI-028: File upload → storage → download cycle
139
- test('should complete full file upload-storage-download cycle', () => {
140
- if (!existsSync(cliPath)) {
141
- console.warn('Skipping test: CLI not built');
142
- return;
143
- }
144
-
145
- try {
146
- // Create a test file to upload
147
- const testFilePath = path.join(process.cwd(), 'test-upload.md');
148
- const testContent = '# Test Rule for Integration\nThis is a test rule for CLI integration testing.';
149
- require('fs').writeFileSync(testFilePath, testContent);
150
-
151
- try {
152
- // Upload the file
153
- const uploadResult = execSync(
154
- `node ${cliPath} upload "${testFilePath}" --name "Integration Test Rule" --tag "integration" --type "rule" --description "Test rule for integration"`,
155
- {
156
- encoding: 'utf8',
157
- timeout: 30000,
158
- env: {
159
- ...process.env,
160
- NODE_ENV: 'test',
161
- AGENTKIT_CONFIG_DIR: configDir,
162
- HOME: tempHome,
163
- USERPROFILE: tempHome,
164
- HOMEDRIVE: tempHome.substring(0, 2),
165
- HOMEPATH: tempHome.substring(2)
166
- }
167
- }
168
- );
169
-
170
- // Verify upload succeeded
171
- expect(uploadResult).toContain('✅ Successfully uploaded rule');
172
-
173
- // Extract rule ID from output for download test
174
- const ruleIdMatch = uploadResult.match(/📋 Rule ID: ([^\s]+)/);
175
- if (ruleIdMatch) {
176
- const ruleId = ruleIdMatch[1];
177
-
178
- // Test download functionality if rule was created
179
- // Note: Download would require install command and actual file storage
180
- // This tests the upload portion of the cycle
181
- }
182
-
183
- } finally {
184
- // Clean up test file
185
- if (existsSync(testFilePath)) {
186
- unlinkSync(testFilePath);
187
- }
188
- }
189
-
190
- } catch (error: any) {
191
- const output = (error.stdout || '') + (error.stderr || '');
192
- if (
193
- output.includes('ECONNREFUSED') ||
194
- output.includes('ENOTFOUND') ||
195
- output.includes('Not logged in') ||
196
- output.includes('failed: Error') ||
197
- output.includes('AggregateError')
198
- ) {
199
- console.warn('Skipping test: Backend server not running or unauthorized');
200
- return;
201
- } else {
202
- throw error;
203
- }
204
- }
205
- });
206
-
207
- // TC-E2E-CLI-029: Authentication token lifecycle
208
- test('should handle authentication token lifecycle correctly', () => {
209
- if (!existsSync(cliPath)) {
210
- console.warn('Skipping test: CLI not built');
211
- return;
212
- }
213
-
214
- try {
215
- // Clear existing config to test login flow
216
- if (existsSync(configPath)) {
217
- unlinkSync(configPath);
218
- }
219
-
220
- // Attempt to run authenticated command without login
221
- try {
222
- execSync(`node ${cliPath} list`, {
223
- encoding: 'utf8',
224
- timeout: 10000,
225
- env: {
226
- ...process.env,
227
- NODE_ENV: 'test',
228
- AGENTKIT_CONFIG_DIR: configDir,
229
- HOME: tempHome,
230
- USERPROFILE: tempHome,
231
- HOMEDRIVE: tempHome.substring(0, 2),
232
- HOMEPATH: tempHome.substring(2)
233
- }
234
- });
235
- fail('Expected command to fail without authentication');
236
- } catch (error: any) {
237
- expect(error.status).toBe(1);
238
- expect(error.stderr || error.stdout).toContain('Not logged in');
239
- }
240
-
241
- // Now test login (mock successful login)
242
- // Note: Actual login requires backend, so we'll test the error handling
243
-
244
- } catch (error: any) {
245
- const output = (error.stdout || '') + (error.stderr || '');
246
- if (
247
- output.includes('ECONNREFUSED') ||
248
- output.includes('ENOTFOUND') ||
249
- output.includes('Not logged in') ||
250
- output.includes('failed: Error') ||
251
- output.includes('AggregateError')
252
- ) {
253
- console.warn('Skipping test: Backend server not running or unauthorized');
254
- return;
255
- } else {
256
- throw error;
257
- }
258
- }
259
- });
260
-
261
- // TC-E2E-CLI-030: Configuration persistence across sessions
262
- test('should persist configuration across multiple CLI sessions', () => {
263
- if (!existsSync(cliPath)) {
264
- console.warn('Skipping test: CLI not built');
265
- return;
266
- }
267
-
268
- try {
269
- // First session - list command
270
- const result1 = execSync(`node ${cliPath} list`, {
271
- encoding: 'utf8',
272
- timeout: 10000,
273
- env: {
274
- ...process.env,
275
- NODE_ENV: 'test',
276
- AGENTKIT_CONFIG_DIR: configDir,
277
- HOME: tempHome,
278
- USERPROFILE: tempHome,
279
- HOMEDRIVE: tempHome.substring(0, 2),
280
- HOMEPATH: tempHome.substring(2)
281
- }
282
- });
283
-
284
- expect(result1).not.toContain('❌');
285
-
286
- // Verify config still exists
287
- expect(existsSync(configPath)).toBe(true);
288
-
289
- // Second session - search command
290
- const result2 = execSync(`node ${cliPath} search "test"`, {
291
- encoding: 'utf8',
292
- timeout: 10000,
293
- env: {
294
- ...process.env,
295
- NODE_ENV: 'test',
296
- AGENTKIT_CONFIG_DIR: configDir,
297
- HOME: tempHome,
298
- USERPROFILE: tempHome,
299
- HOMEDRIVE: tempHome.substring(0, 2),
300
- HOMEPATH: tempHome.substring(2)
301
- }
302
- });
303
-
304
- expect(result2).not.toContain('❌');
305
-
306
- // Verify config persists
307
- expect(existsSync(configPath)).toBe(true);
308
- const config = JSON.parse(readFileSync(configPath, 'utf8'));
309
- expect(config.token).toBe('test-token');
310
- expect(config.user.username).toBe('testuser');
311
-
312
- // Third session - help command
313
- const result3 = execSync(`node ${cliPath} --help`, {
314
- encoding: 'utf8',
315
- timeout: 5000,
316
- env: {
317
- ...process.env,
318
- NODE_ENV: 'test',
319
- AGENTKIT_CONFIG_DIR: configDir,
320
- HOME: tempHome,
321
- USERPROFILE: tempHome,
322
- HOMEDRIVE: tempHome.substring(0, 2),
323
- HOMEPATH: tempHome.substring(2)
324
- }
325
- });
326
-
327
- expect(result3).toContain('kitstore');
328
- expect(result3).toContain('login');
329
-
330
- } catch (error: any) {
331
- const output = (error.stdout || '') + (error.stderr || '');
332
- if (
333
- output.includes('ECONNREFUSED') ||
334
- output.includes('ENOTFOUND') ||
335
- output.includes('Not logged in') ||
336
- output.includes('failed: Error') ||
337
- output.includes('AggregateError')
338
- ) {
339
- console.warn('Skipping test: Backend server not running or unauthorized');
340
- return;
341
- } else {
342
- throw error;
343
- }
344
- }
345
- });
346
- });