@tyvm/knowhow 0.0.36 โ†’ 0.0.38

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 (103) hide show
  1. package/package.json +1 -1
  2. package/src/agents/base/base.ts +8 -0
  3. package/src/agents/tools/aiClient.ts +36 -0
  4. package/src/agents/tools/lintFile.ts +1 -1
  5. package/src/agents/tools/list.ts +34 -0
  6. package/src/ai.ts +5 -4
  7. package/src/auth/browserLogin.ts +283 -0
  8. package/src/auth/errors.ts +6 -0
  9. package/src/auth/spinner.ts +23 -0
  10. package/src/chat/CliChatService.ts +25 -6
  11. package/src/chat/modules/AgentModule.ts +1 -2
  12. package/src/chat/modules/AskModule.ts +1 -2
  13. package/src/chat/types.ts +14 -4
  14. package/src/chat-old.ts +446 -0
  15. package/src/chat.ts +48 -433
  16. package/src/cli.ts +9 -14
  17. package/src/clients/index.ts +35 -2
  18. package/src/embeddings.ts +1 -1
  19. package/src/index.ts +1 -8
  20. package/src/login.ts +14 -1
  21. package/src/microphone.ts +0 -1
  22. package/src/plugins/downloader/downloader.ts +4 -2
  23. package/src/services/KnowhowClient.ts +1 -1
  24. package/src/services/index.ts +1 -2
  25. package/tests/manual/browser-login/README.md +189 -0
  26. package/tests/manual/browser-login/test_browser_login_basic.ts +115 -0
  27. package/tests/manual/browser-login/test_cli_integration.ts +169 -0
  28. package/tests/manual/browser-login/test_cross_platform_browser.ts +186 -0
  29. package/tests/manual/browser-login/test_error_scenarios.ts +223 -0
  30. package/tests/manual/cli/no-env.sh +267 -0
  31. package/ts_build/src/agents/base/base.js +4 -0
  32. package/ts_build/src/agents/base/base.js.map +1 -1
  33. package/ts_build/src/agents/tools/aiClient.d.ts +2 -0
  34. package/ts_build/src/agents/tools/aiClient.js +21 -1
  35. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  36. package/ts_build/src/agents/tools/lintFile.js +1 -1
  37. package/ts_build/src/agents/tools/lintFile.js.map +1 -1
  38. package/ts_build/src/agents/tools/list.js +32 -0
  39. package/ts_build/src/agents/tools/list.js.map +1 -1
  40. package/ts_build/src/ai.d.ts +1 -1
  41. package/ts_build/src/ai.js +2 -1
  42. package/ts_build/src/ai.js.map +1 -1
  43. package/ts_build/src/auth/browserLogin.d.ts +11 -0
  44. package/ts_build/src/auth/browserLogin.js +197 -0
  45. package/ts_build/src/auth/browserLogin.js.map +1 -0
  46. package/ts_build/src/auth/errors.d.ts +4 -0
  47. package/ts_build/src/auth/errors.js +13 -0
  48. package/ts_build/src/auth/errors.js.map +1 -0
  49. package/ts_build/src/auth/spinner.d.ts +7 -0
  50. package/ts_build/src/auth/spinner.js +23 -0
  51. package/ts_build/src/auth/spinner.js.map +1 -0
  52. package/ts_build/src/chat/CliChatService.d.ts +4 -3
  53. package/ts_build/src/chat/CliChatService.js +18 -4
  54. package/ts_build/src/chat/CliChatService.js.map +1 -1
  55. package/ts_build/src/chat/modules/AgentModule.d.ts +1 -1
  56. package/ts_build/src/chat/modules/AgentModule.js +1 -2
  57. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  58. package/ts_build/src/chat/modules/AskModule.js +1 -2
  59. package/ts_build/src/chat/modules/AskModule.js.map +1 -1
  60. package/ts_build/src/chat/types.d.ts +5 -3
  61. package/ts_build/src/chat-old.d.ts +13 -0
  62. package/ts_build/src/chat-old.js +340 -0
  63. package/ts_build/src/chat-old.js.map +1 -0
  64. package/ts_build/src/chat.d.ts +3 -13
  65. package/ts_build/src/chat.js +38 -331
  66. package/ts_build/src/chat.js.map +1 -1
  67. package/ts_build/src/chat2.d.ts +1 -1
  68. package/ts_build/src/chat2.js +2 -2
  69. package/ts_build/src/chat2.js.map +1 -1
  70. package/ts_build/src/cli.js +7 -11
  71. package/ts_build/src/cli.js.map +1 -1
  72. package/ts_build/src/clients/index.d.ts +2 -2
  73. package/ts_build/src/clients/index.js +16 -1
  74. package/ts_build/src/clients/index.js.map +1 -1
  75. package/ts_build/src/embeddings.js.map +1 -1
  76. package/ts_build/src/index.d.ts +1 -2
  77. package/ts_build/src/index.js +2 -9
  78. package/ts_build/src/index.js.map +1 -1
  79. package/ts_build/src/login.d.ts +1 -1
  80. package/ts_build/src/login.js +14 -0
  81. package/ts_build/src/login.js.map +1 -1
  82. package/ts_build/src/microphone.js.map +1 -1
  83. package/ts_build/src/plugins/downloader/downloader.d.ts +1 -3
  84. package/ts_build/src/plugins/downloader/downloader.js +4 -4
  85. package/ts_build/src/plugins/downloader/downloader.js.map +1 -1
  86. package/ts_build/src/services/KnowhowClient.js +1 -1
  87. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  88. package/ts_build/src/services/index.js +1 -2
  89. package/ts_build/src/services/index.js.map +1 -1
  90. package/ts_build/tests/manual/browser-login/test_browser_login_basic.d.ts +2 -0
  91. package/ts_build/tests/manual/browser-login/test_browser_login_basic.js +108 -0
  92. package/ts_build/tests/manual/browser-login/test_browser_login_basic.js.map +1 -0
  93. package/ts_build/tests/manual/browser-login/test_cli_integration.d.ts +2 -0
  94. package/ts_build/tests/manual/browser-login/test_cli_integration.js +153 -0
  95. package/ts_build/tests/manual/browser-login/test_cli_integration.js.map +1 -0
  96. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.d.ts +2 -0
  97. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js +159 -0
  98. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js.map +1 -0
  99. package/ts_build/tests/manual/browser-login/test_error_scenarios.d.ts +2 -0
  100. package/ts_build/tests/manual/browser-login/test_error_scenarios.js +197 -0
  101. package/ts_build/tests/manual/browser-login/test_error_scenarios.js.map +1 -0
  102. package/src/agents/vim/vim.ts +0 -152
  103. package/src/chat2.ts +0 -62
package/src/login.ts CHANGED
@@ -5,8 +5,9 @@ import { chmod } from "fs/promises";
5
5
  import { ask } from "./utils";
6
6
  import { getConfig, updateConfig } from "./config";
7
7
  import { KNOWHOW_API_URL } from "./services/KnowhowClient";
8
+ import { BrowserLoginService } from "./auth/browserLogin";
8
9
 
9
- export async function login(jwtFlag?: string): Promise<void> {
10
+ export async function login(jwtFlag?: boolean): Promise<void> {
10
11
  if (!KNOWHOW_API_URL) {
11
12
  throw new Error("Error: KNOWHOW_API_URL environment variable not set.");
12
13
  }
@@ -24,6 +25,18 @@ export async function login(jwtFlag?: string): Promise<void> {
24
25
  fs.writeFileSync(jwtFile, jwt);
25
26
  fs.chmodSync(jwtFile, 0o600);
26
27
  console.log("JWT updated successfully.");
28
+ } else {
29
+ // Use browser login as default method
30
+ console.log("Starting browser-based authentication...");
31
+ try {
32
+ const browserLoginService = new BrowserLoginService();
33
+ await browserLoginService.login();
34
+ console.log("Successfully authenticated via browser!");
35
+ } catch (error) {
36
+ console.error("Browser authentication failed:", error.message);
37
+ console.log("You can try manual JWT login with: knowhow login --jwt");
38
+ throw error;
39
+ }
27
40
  }
28
41
 
29
42
  // Get current user/org information
package/src/microphone.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { exec } from "child_process";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
- import { openai } from "./ai";
5
4
  import { execAsync, ask } from "./utils";
6
5
  import { convertToText, convertAudioToText } from "./conversion";
7
6
 
@@ -8,11 +8,12 @@ import { execAsync, fileExists, readFile, mkdir } from "../../utils";
8
8
  import OpenAI from "openai";
9
9
  import { Clients } from "../../clients";
10
10
  import { Models } from "../../types";
11
+ import { openai } from "../../ai";
11
12
 
12
13
  const logger = Logger();
13
14
 
14
15
  export class DownloaderService {
15
- constructor(private openAi: OpenAI, private clients: typeof Clients) {}
16
+ constructor(private clients: typeof Clients) {}
16
17
 
17
18
  async askGptVision(
18
19
  imageUrl: string,
@@ -131,6 +132,7 @@ export class DownloaderService {
131
132
  }
132
133
 
133
134
  const allTranscripts = [];
135
+ const openAi = openai();
134
136
  for (const file of files) {
135
137
  const chunkName = path.parse(file).name;
136
138
  const chunkTranscriptPath = path.join(
@@ -157,7 +159,7 @@ export class DownloaderService {
157
159
  }
158
160
 
159
161
  console.log("Transcribing", file);
160
- const transcript = await this.openAi.audio.transcriptions
162
+ const transcript = await openAi.audio.transcriptions
161
163
  .create({
162
164
  file: fs.createReadStream(file),
163
165
  model: "whisper-1",
@@ -127,7 +127,7 @@ export class KnowhowSimpleClient {
127
127
 
128
128
  getModels() {
129
129
  this.checkJwt();
130
- return axios.get(`${this.baseUrl}/api/proxy/v1/models`, {
130
+ return axios.get(`${this.baseUrl}/api/proxy/v1/models?type=all`, {
131
131
  headers: this.headers,
132
132
  });
133
133
  }
@@ -1,4 +1,3 @@
1
- import { openai } from "../ai";
2
1
  import { DownloaderService } from "../plugins/downloader/downloader";
3
2
  import { Clients } from "../clients";
4
3
  import { Plugins } from "../plugins/plugins";
@@ -41,7 +40,7 @@ export const services = (): typeof Singletons => {
41
40
  const Tools = new ToolsService();
42
41
  const Events = new EventService();
43
42
  const Agents = new AgentService(Tools, Events);
44
- const Downloader = new DownloaderService(openai, Clients);
43
+ const Downloader = new DownloaderService(Clients);
45
44
  Singletons = {
46
45
  Tools,
47
46
  Events,
@@ -0,0 +1,189 @@
1
+ # Browser Login Manual Tests
2
+
3
+ This directory contains comprehensive manual tests for the browser-based login functionality in the Knowhow CLI.
4
+
5
+ ## Test Overview
6
+
7
+ The browser login implementation includes the following key features:
8
+ - Browser-based authentication as the default login method
9
+ - Cross-platform browser opening (macOS, Windows, Linux)
10
+ - Polling mechanism with exponential backoff
11
+ - JWT token retrieval and secure storage
12
+ - Graceful error handling and user cancellation
13
+ - Backwards compatibility with `--jwt` flag
14
+
15
+ ## Test Files
16
+
17
+ ### 1. `test_browser_login_basic.ts`
18
+ **Purpose**: Tests the core browser login flow end-to-end
19
+
20
+ **What it tests**:
21
+ - Session creation with the API
22
+ - Browser opening for user authentication
23
+ - Authentication polling and completion
24
+ - JWT retrieval and secure storage
25
+ - File permissions (0o600)
26
+ - JWT format validation
27
+
28
+ **Prerequisites**:
29
+ - Valid `KNOWHOW_API_URL` environment variable
30
+ - Network connection to Knowhow API
31
+ - Default browser available
32
+
33
+ **Usage**:
34
+ ```bash
35
+ npx tsx ./tests/manual/browser-login/test_browser_login_basic.ts
36
+ ```
37
+
38
+ **Manual steps required**:
39
+ - Complete authentication in the opened browser window
40
+ - Verify browser opened to correct URL
41
+
42
+ ### 2. `test_cli_integration.ts`
43
+ **Purpose**: Tests CLI command integration and backwards compatibility
44
+
45
+ **What it tests**:
46
+ - `knowhow login` uses browser login by default
47
+ - `knowhow login --jwt` prompts for manual JWT input
48
+ - Command help shows correct options
49
+ - JWT file creation through CLI
50
+
51
+ **Prerequisites**:
52
+ - Built CLI application (`npm run build`)
53
+ - Valid `KNOWHOW_API_URL` environment variable
54
+
55
+ **Usage**:
56
+ ```bash
57
+ npx tsx ./tests/manual/browser-login/test_cli_integration.ts
58
+ ```
59
+
60
+ **Manual steps required**:
61
+ - Complete browser authentication when prompted
62
+ - Verify help output is correct
63
+
64
+ ### 3. `test_cross_platform_browser.ts`
65
+ **Purpose**: Tests browser opening across different operating systems
66
+
67
+ **What it tests**:
68
+ - Platform detection (macOS, Windows, Linux)
69
+ - Correct browser command selection (`open`, `start`, `xdg-open`)
70
+ - Browser command availability
71
+ - URL handling with special characters
72
+ - Graceful fallback when browser opening fails
73
+
74
+ **Prerequisites**:
75
+ - Default browser installed
76
+ - Platform-specific browser commands available
77
+
78
+ **Usage**:
79
+ ```bash
80
+ npx tsx ./tests/manual/browser-login/test_cross_platform_browser.ts
81
+ ```
82
+
83
+ **Manual steps required**:
84
+ - Verify browser opens to test URLs
85
+ - Confirm platform-specific behavior
86
+
87
+ ### 4. `test_error_scenarios.ts`
88
+ **Purpose**: Tests error handling and edge cases
89
+
90
+ **What it tests**:
91
+ - Invalid API URL handling
92
+ - Missing API URL configuration
93
+ - JWT validation with various inputs
94
+ - File permission handling
95
+ - Error code propagation
96
+ - Graceful cancellation mechanisms
97
+
98
+ **Prerequisites**:
99
+ - Ability to modify environment variables temporarily
100
+
101
+ **Usage**:
102
+ ```bash
103
+ npx tsx ./tests/manual/browser-login/test_error_scenarios.ts
104
+ ```
105
+
106
+ **Manual steps required**:
107
+ - None (fully automated error scenario testing)
108
+
109
+ ## Running All Tests
110
+
111
+ To run all tests in sequence:
112
+
113
+ ```bash
114
+ # Run individual tests
115
+ npx tsx ./tests/manual/browser-login/test_error_scenarios.ts
116
+ npx tsx ./tests/manual/browser-login/test_cross_platform_browser.ts
117
+ npx tsx ./tests/manual/browser-login/test_cli_integration.ts
118
+ npx tsx ./tests/manual/browser-login/test_browser_login_basic.ts
119
+ ```
120
+
121
+ ## Test Results Interpretation
122
+
123
+ ### โœ… PASSED
124
+ Test completed successfully with expected behavior.
125
+
126
+ ### โš ๏ธ WARNING
127
+ Test completed but with minor issues or platform-specific concerns that don't prevent functionality.
128
+
129
+ ### โŒ FAILED
130
+ Test failed due to errors or unexpected behavior that needs to be addressed.
131
+
132
+ ### Manual Verification Required
133
+ Some tests require manual verification (e.g., confirming browser opened correctly) as they test user interaction flows.
134
+
135
+ ## Common Issues and Troubleshooting
136
+
137
+ ### Browser Not Opening
138
+ - **Symptoms**: Browser opening fails or command not found
139
+ - **Solutions**:
140
+ - Ensure default browser is installed
141
+ - Check platform-specific command availability (`open`, `start`, `xdg-open`)
142
+ - Verify display environment for Linux systems
143
+
144
+ ### Network Errors
145
+ - **Symptoms**: API connection failures or timeouts
146
+ - **Solutions**:
147
+ - Verify `KNOWHOW_API_URL` is set correctly
148
+ - Check network connectivity
149
+ - Confirm API endpoints are accessible
150
+
151
+ ### Permission Errors
152
+ - **Symptoms**: Cannot create or write JWT files
153
+ - **Solutions**:
154
+ - Check write permissions in project directory
155
+ - Verify `.knowhow` directory can be created
156
+ - Check for filesystem restrictions
157
+
158
+ ### Authentication Timeout
159
+ - **Symptoms**: Polling times out before user completes authentication
160
+ - **Solutions**:
161
+ - Complete authentication more quickly
162
+ - Check if browser session is blocked by ad blockers
163
+ - Verify correct authentication URL
164
+
165
+ ## Integration with CI/CD
166
+
167
+ These manual tests are designed for human verification and are not suitable for automated CI/CD pipelines. For automated testing, consider:
168
+
169
+ 1. Mocking the browser opening functionality
170
+ 2. Creating integration tests with test authentication endpoints
171
+ 3. Unit testing individual components separately
172
+
173
+ ## Security Considerations
174
+
175
+ When running these tests:
176
+ - JWT tokens are stored temporarily and cleaned up
177
+ - File permissions are tested to ensure secure storage (0o600)
178
+ - No sensitive data should be logged or persisted beyond test execution
179
+ - Tests clean up after themselves to avoid leaving test artifacts
180
+
181
+ ## Contributing
182
+
183
+ When adding new tests:
184
+ 1. Follow the existing test file naming pattern
185
+ 2. Include comprehensive error handling
186
+ 3. Provide clear manual steps in comments
187
+ 4. Clean up any created files or state
188
+ 5. Add appropriate timeout handling
189
+ 6. Update this README with new test descriptions
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ /**
4
+ * Manual Test: Basic Browser Login Flow
5
+ *
6
+ * This test validates the complete browser-based authentication flow:
7
+ * 1. Creates a login session with the API
8
+ * 2. Opens browser for user authentication
9
+ * 3. Polls for authentication completion
10
+ * 4. Retrieves and stores JWT token
11
+ *
12
+ * Prerequisites:
13
+ * - Valid KNOWHOW_API_URL environment variable
14
+ * - Network connection to Knowhow API
15
+ * - Browser available on the system
16
+ *
17
+ * Usage: npx tsx ./tests/manual/browser-login/test_browser_login_basic.ts
18
+ */
19
+
20
+ import { BrowserLoginService } from '../../../src/auth/browserLogin';
21
+ import * as fs from 'fs';
22
+ import * as path from 'path';
23
+
24
+ async function testBasicBrowserLogin(): Promise<void> {
25
+ console.log('\n=== Basic Browser Login Test ===\n');
26
+
27
+ let success = false;
28
+ const configDir = path.join(process.cwd(), '.knowhow');
29
+ const jwtFile = path.join(configDir, '.jwt');
30
+
31
+ // Clean up any existing JWT file
32
+ if (fs.existsSync(jwtFile)) {
33
+ fs.unlinkSync(jwtFile);
34
+ console.log('๐Ÿงน Cleaned up existing JWT file');
35
+ }
36
+
37
+ try {
38
+ console.log('1. Initializing BrowserLoginService...');
39
+ const browserLogin = new BrowserLoginService();
40
+
41
+ console.log('2. Starting browser login flow...');
42
+ console.log(' Note: This will open your browser and require manual authentication');
43
+ console.log(' Please complete the authentication process in your browser');
44
+
45
+ await browserLogin.login();
46
+
47
+ console.log('3. Verifying JWT file was created...');
48
+ if (fs.existsSync(jwtFile)) {
49
+ const jwtContent = fs.readFileSync(jwtFile, 'utf8');
50
+
51
+ // Check file permissions
52
+ const stats = fs.statSync(jwtFile);
53
+ const permissions = stats.mode & parseInt('777', 8);
54
+
55
+ console.log(` โœ… JWT file created: ${jwtFile}`);
56
+ console.log(` โœ… JWT length: ${jwtContent.length} characters`);
57
+ console.log(` โœ… File permissions: ${permissions.toString(8)} (should be 600)`);
58
+
59
+ // Basic JWT validation
60
+ const parts = jwtContent.split('.');
61
+ if (parts.length === 3) {
62
+ console.log(' โœ… JWT has correct structure (3 parts)');
63
+ success = true;
64
+ } else {
65
+ console.log(' โŒ JWT has incorrect structure');
66
+ }
67
+
68
+ if (permissions === parseInt('600', 8)) {
69
+ console.log(' โœ… JWT file has correct permissions (600)');
70
+ } else {
71
+ console.log(` โš ๏ธ JWT file permissions may be incorrect: ${permissions.toString(8)}`);
72
+ }
73
+
74
+ } else {
75
+ console.log(' โŒ JWT file was not created');
76
+ }
77
+
78
+ } catch (error) {
79
+ console.error('โŒ Test failed with error:', error.message);
80
+
81
+ if (error.code === 'USER_CANCELLED') {
82
+ console.log(' โ„น๏ธ Authentication was cancelled by user (this is expected for Ctrl+C)');
83
+ } else if (error.code === 'TIMEOUT') {
84
+ console.log(' โš ๏ธ Authentication timed out (user may not have completed authentication)');
85
+ } else if (error.code === 'NETWORK_ERROR') {
86
+ console.log(' โŒ Network error - check API connectivity');
87
+ }
88
+ }
89
+
90
+ console.log('\n=== Test Results ===');
91
+ if (success) {
92
+ console.log('โœ… Browser login test PASSED');
93
+ console.log(' - Session created successfully');
94
+ console.log(' - Browser opened for authentication');
95
+ console.log(' - JWT retrieved and stored securely');
96
+ process.exit(0);
97
+ } else {
98
+ console.log('โŒ Browser login test FAILED');
99
+ console.log(' See error details above');
100
+ process.exit(1);
101
+ }
102
+ }
103
+
104
+ // Handle graceful shutdown
105
+ process.on('SIGINT', () => {
106
+ console.log('\n\n๐Ÿ›‘ Test interrupted by user (Ctrl+C)');
107
+ console.log(' This tests the graceful cancellation feature');
108
+ process.exit(0);
109
+ });
110
+
111
+ // Run the test
112
+ testBasicBrowserLogin().catch((error) => {
113
+ console.error('Unhandled error:', error);
114
+ process.exit(1);
115
+ });
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ /**
4
+ * Manual Test: CLI Integration Test
5
+ *
6
+ * This test validates the integration of browser login with the CLI command system:
7
+ * 1. Tests `knowhow login` (browser login as default)
8
+ * 2. Tests `knowhow login --jwt` (legacy JWT input)
9
+ * 3. Verifies backwards compatibility
10
+ * 4. Tests login status verification
11
+ *
12
+ * Prerequisites:
13
+ * - Built CLI application
14
+ * - Valid KNOWHOW_API_URL environment variable
15
+ * - Network connection to Knowhow API
16
+ *
17
+ * Usage: npx tsx ./tests/manual/browser-login/test_cli_integration.ts
18
+ */
19
+
20
+ import { exec } from 'child_process';
21
+ import { promisify } from 'util';
22
+ import * as fs from 'fs';
23
+ import * as path from 'path';
24
+
25
+ const execAsync = promisify(exec);
26
+
27
+ async function testCliIntegration(): Promise<void> {
28
+ console.log('\n=== CLI Integration Test ===\n');
29
+
30
+ const configDir = path.join(process.cwd(), '.knowhow');
31
+ const jwtFile = path.join(configDir, '.jwt');
32
+ let testResults: string[] = [];
33
+
34
+ try {
35
+ // Clean up any existing JWT file
36
+ if (fs.existsSync(jwtFile)) {
37
+ fs.unlinkSync(jwtFile);
38
+ console.log('๐Ÿงน Cleaned up existing JWT file\n');
39
+ }
40
+
41
+ console.log('=== Test 1: Browser Login as Default ===');
42
+ console.log('Testing: knowhow login (should use browser login)');
43
+ console.log('Note: This will open your browser - please complete authentication\n');
44
+
45
+ try {
46
+ // This should use browser login by default
47
+ const { stdout, stderr } = await execAsync('npm run build && node dist/cli.js login', {
48
+ timeout: 120000 // 2 minutes timeout
49
+ });
50
+
51
+ console.log('Command output:', stdout);
52
+ if (stderr) console.log('Command stderr:', stderr);
53
+
54
+ // Check if JWT file was created
55
+ if (fs.existsSync(jwtFile)) {
56
+ const jwtContent = fs.readFileSync(jwtFile, 'utf8');
57
+ if (jwtContent.split('.').length === 3) {
58
+ console.log('โœ… Test 1 PASSED: Browser login created valid JWT');
59
+ testResults.push('โœ… Browser login as default: PASSED');
60
+ } else {
61
+ console.log('โŒ Test 1 FAILED: Invalid JWT created');
62
+ testResults.push('โŒ Browser login as default: FAILED (invalid JWT)');
63
+ }
64
+ } else {
65
+ console.log('โŒ Test 1 FAILED: No JWT file created');
66
+ testResults.push('โŒ Browser login as default: FAILED (no JWT file)');
67
+ }
68
+
69
+ } catch (error) {
70
+ if (error.killed && error.signal === 'SIGTERM') {
71
+ console.log('โš ๏ธ Test 1 TIMEOUT: User may not have completed authentication');
72
+ testResults.push('โš ๏ธ Browser login as default: TIMEOUT');
73
+ } else {
74
+ console.log('โŒ Test 1 ERROR:', error.message);
75
+ testResults.push('โŒ Browser login as default: ERROR');
76
+ }
77
+ }
78
+
79
+ // Clean up for next test
80
+ if (fs.existsSync(jwtFile)) {
81
+ fs.unlinkSync(jwtFile);
82
+ }
83
+
84
+ console.log('\n=== Test 2: Legacy JWT Input ===');
85
+ console.log('Testing: knowhow login --jwt (should prompt for manual JWT input)');
86
+
87
+ // Create a mock interaction that immediately exits
88
+ try {
89
+ const { stdout, stderr } = await execAsync('echo "" | npm run build && echo "" | node dist/cli.js login --jwt', {
90
+ timeout: 10000
91
+ });
92
+
93
+ console.log('Command output:', stdout);
94
+ if (stderr) console.log('Command stderr:', stderr);
95
+
96
+ // The command should have prompted for JWT input
97
+ if (stdout.includes('JWT') || stdout.includes('token') || stderr.includes('JWT') || stderr.includes('token')) {
98
+ console.log('โœ… Test 2 PASSED: --jwt flag triggers manual JWT input');
99
+ testResults.push('โœ… Legacy JWT input: PASSED');
100
+ } else {
101
+ console.log('โŒ Test 2 FAILED: --jwt flag not working correctly');
102
+ testResults.push('โŒ Legacy JWT input: FAILED');
103
+ }
104
+
105
+ } catch (error) {
106
+ // This is expected since we're not providing valid JWT input
107
+ if (error.message.includes('JWT') || error.message.includes('token')) {
108
+ console.log('โœ… Test 2 PASSED: --jwt flag triggered JWT input prompt');
109
+ testResults.push('โœ… Legacy JWT input: PASSED');
110
+ } else {
111
+ console.log('โŒ Test 2 FAILED:', error.message);
112
+ testResults.push('โŒ Legacy JWT input: FAILED');
113
+ }
114
+ }
115
+
116
+ console.log('\n=== Test 3: Command Help ===');
117
+ console.log('Testing: knowhow login --help');
118
+
119
+ try {
120
+ const { stdout, stderr } = await execAsync('npm run build && node dist/cli.js login --help');
121
+
122
+ console.log('Help output:', stdout);
123
+
124
+ if (stdout.includes('--jwt') && stdout.includes('browser')) {
125
+ console.log('โœ… Test 3 PASSED: Help shows both browser and JWT options');
126
+ testResults.push('โœ… Command help: PASSED');
127
+ } else {
128
+ console.log('โŒ Test 3 FAILED: Help missing expected options');
129
+ testResults.push('โŒ Command help: FAILED');
130
+ }
131
+
132
+ } catch (error) {
133
+ console.log('โŒ Test 3 ERROR:', error.message);
134
+ testResults.push('โŒ Command help: ERROR');
135
+ }
136
+
137
+ } catch (error) {
138
+ console.error('โŒ Test suite failed:', error.message);
139
+ }
140
+
141
+ // Print summary
142
+ console.log('\n=== Test Summary ===');
143
+ testResults.forEach(result => console.log(result));
144
+
145
+ const passedTests = testResults.filter(r => r.includes('PASSED')).length;
146
+ const totalTests = testResults.length;
147
+
148
+ console.log(`\nResults: ${passedTests}/${totalTests} tests passed`);
149
+
150
+ if (passedTests === totalTests) {
151
+ console.log('๐ŸŽ‰ All CLI integration tests PASSED!');
152
+ process.exit(0);
153
+ } else {
154
+ console.log('โŒ Some CLI integration tests FAILED');
155
+ process.exit(1);
156
+ }
157
+ }
158
+
159
+ // Handle graceful shutdown
160
+ process.on('SIGINT', () => {
161
+ console.log('\n\n๐Ÿ›‘ Test interrupted by user (Ctrl+C)');
162
+ process.exit(0);
163
+ });
164
+
165
+ // Run the test
166
+ testCliIntegration().catch((error) => {
167
+ console.error('Unhandled error:', error);
168
+ process.exit(1);
169
+ });