@vee-stack/delta-cli 2.0.6 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -141,120 +141,53 @@ export async function startOAuthFlow(method = 'oauth') {
141
141
  // Get API URL from environment or use default
142
142
  const apiUrl = process.env.DELTA_API_URL || 'http://localhost:3000';
143
143
  const { verifier, challenge } = generatePKCE();
144
- const redirectUri = 'http://localhost:3456/callback';
145
144
  const state = crypto.randomBytes(16).toString('hex');
146
- // Build OAuth URL
147
- const oauthUrl = new URL(`${apiUrl}/api/auth/authorize`);
148
- oauthUrl.searchParams.set('response_type', 'code');
149
- oauthUrl.searchParams.set('client_id', 'delta-cli');
150
- oauthUrl.searchParams.set('redirect_uri', redirectUri);
151
- oauthUrl.searchParams.set('code_challenge', challenge);
152
- oauthUrl.searchParams.set('code_challenge_method', 'S256');
153
- oauthUrl.searchParams.set('state', state);
154
- oauthUrl.searchParams.set('scope', 'read write analyze');
155
- if (method === 'github') {
156
- oauthUrl.searchParams.set('provider', 'github');
157
- }
158
- else if (method === 'google') {
159
- oauthUrl.searchParams.set('provider', 'google');
160
- }
161
- stopSpinner(true, 'OAuth server ready');
162
- // Open browser
163
- printInfo(`Opening browser for authentication...`);
164
- printInfo(`URL: ${oauthUrl.toString().substring(0, 80)}...`);
165
- await open(oauthUrl.toString());
166
- // Start local server to capture callback
167
- const authCode = await new Promise((resolve, reject) => {
145
+ // Start local server FIRST to capture callback and get actual port
146
+ const { authCode, redirectUri } = await new Promise((resolve, reject) => {
168
147
  const server = createServer(async (req, res) => {
169
- // Get actual port from server address
170
- const address = server.address();
171
- const actualPort = typeof address === 'object' && address ? address.port : 3000;
172
- const url = new URL(req.url || '/', `http://localhost:${actualPort}`);
148
+ const url = new URL(req.url || '/', `http://localhost:${redirectPort}`);
173
149
  if (url.pathname === '/callback') {
174
150
  const code = url.searchParams.get('code');
175
151
  const returnedState = url.searchParams.get('state');
176
152
  const error = url.searchParams.get('error');
177
153
  if (error) {
178
154
  res.writeHead(400, { 'Content-Type': 'text/html' });
179
- res.end(`
180
- <html>
181
- <body style="font-family: system-ui; text-align: center; padding: 50px;">
182
- <h1 style="color: #e74c3c;">❌ Authentication Failed</h1>
183
- <p>${error}</p>
184
- <p>You can close this window.</p>
185
- </body>
186
- </html>
187
- `);
155
+ res.end(`<html><body><h1>❌ Authentication Failed</h1><p>${error}</p></body></html>`);
188
156
  reject(new Error(error));
189
157
  server.close();
190
158
  return;
191
159
  }
192
160
  if (!code || returnedState !== state) {
193
161
  res.writeHead(400, { 'Content-Type': 'text/html' });
194
- res.end(`
195
- <html>
196
- <body style="font-family: system-ui; text-align: center; padding: 50px;">
197
- <h1 style="color: #e74c3c;">❌ Invalid Response</h1>
198
- <p>You can close this window.</p>
199
- </body>
200
- </html>
201
- `);
162
+ res.end(`<html><body><h1>❌ Invalid Response</h1></body></html>`);
202
163
  reject(new Error('Invalid OAuth response'));
203
164
  server.close();
204
165
  return;
205
166
  }
206
167
  res.writeHead(200, { 'Content-Type': 'text/html' });
207
- res.end(`
208
- <html>
209
- <head>
210
- <style>
211
- body {
212
- font-family: system-ui, -apple-system, sans-serif;
213
- text-align: center;
214
- padding: 50px;
215
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
216
- color: white;
217
- min-height: 100vh;
218
- display: flex;
219
- align-items: center;
220
- justify-content: center;
221
- }
222
- .container {
223
- background: rgba(255,255,255,0.1);
224
- backdrop-filter: blur(10px);
225
- padding: 40px;
226
- border-radius: 20px;
227
- box-shadow: 0 20px 60px rgba(0,0,0,0.3);
228
- }
229
- h1 { margin: 0 0 20px; font-size: 48px; }
230
- .check { font-size: 64px; margin-bottom: 20px; }
231
- p { font-size: 18px; opacity: 0.9; }
232
- </style>
233
- </head>
234
- <body>
235
- <div class="container">
236
- <div class="check">✓</div>
237
- <h1>Successfully Signed In!</h1>
238
- <p>You can close this window and return to the terminal.</p>
239
- </div>
240
- </body>
241
- </html>
242
- `);
243
- resolve(code);
168
+ res.end(`<html><body style="text-align:center;padding:50px;"><h1>✓ Successfully Signed In!</h1><p>You can close this window.</p></body></html>`);
169
+ const address = server.address();
170
+ const actualPort = typeof address === 'object' && address ? address.port : 3456;
171
+ resolve({ authCode: code, redirectUri: `http://localhost:${actualPort}/callback` });
244
172
  server.close();
245
173
  }
246
174
  });
247
- // Try to listen on port 3456, or let OS assign available port if busy
175
+ let redirectPort = 3456;
176
+ // Try to listen on port 3456
248
177
  server.listen(3456, '127.0.0.1', () => {
249
- const address = server.address();
250
- const actualPort = typeof address === 'object' && address ? address.port : 3456;
251
- console.log(chalk.dim(` Waiting for authentication on port ${actualPort}...`));
178
+ console.log(chalk.dim(` Waiting for authentication on port ${redirectPort}...`));
252
179
  });
253
180
  // Handle port in use error by trying random port
254
181
  server.on('error', (err) => {
255
182
  if (err.code === 'EADDRINUSE') {
256
183
  printWarning('Port 3456 is busy, trying alternative port...');
257
- server.listen(0, '127.0.0.1'); // Let OS assign available port
184
+ redirectPort = 0; // Let OS assign
185
+ server.listen(0, '127.0.0.1', () => {
186
+ const address = server.address();
187
+ const actualPort = typeof address === 'object' && address ? address.port : 3456;
188
+ redirectPort = actualPort;
189
+ console.log(chalk.dim(` Waiting for authentication on port ${actualPort}...`));
190
+ });
258
191
  }
259
192
  else {
260
193
  reject(err);
@@ -266,6 +199,27 @@ export async function startOAuthFlow(method = 'oauth') {
266
199
  reject(new Error('Authentication timeout'));
267
200
  }, 5 * 60 * 1000);
268
201
  });
202
+ // NOW build OAuth URL with correct redirect_uri
203
+ const oauthUrl = new URL(`${apiUrl}/api/auth/authorize`);
204
+ oauthUrl.searchParams.set('response_type', 'code');
205
+ oauthUrl.searchParams.set('client_id', 'delta-cli');
206
+ oauthUrl.searchParams.set('redirect_uri', redirectUri);
207
+ oauthUrl.searchParams.set('code_challenge', challenge);
208
+ oauthUrl.searchParams.set('code_challenge_method', 'S256');
209
+ oauthUrl.searchParams.set('state', state);
210
+ oauthUrl.searchParams.set('scope', 'read write analyze');
211
+ if (method === 'github') {
212
+ oauthUrl.searchParams.set('provider', 'github');
213
+ }
214
+ else if (method === 'google') {
215
+ oauthUrl.searchParams.set('provider', 'google');
216
+ }
217
+ stopSpinner(true, 'OAuth server ready');
218
+ // Open browser with correct URL
219
+ printInfo(`Opening browser for authentication...`);
220
+ printInfo(`Full URL: ${oauthUrl.toString()}`);
221
+ await open(oauthUrl.toString());
222
+ // Wait for authCode (already resolved above)
269
223
  // Exchange code for tokens
270
224
  startSpinner('Exchanging authorization code...');
271
225
  const tokenResponse = await fetch(`${apiUrl}/api/auth/token`, {
@@ -173,13 +173,19 @@ export async function analyzeCommand(projectPath, options) {
173
173
  printSuccess('✨ No issues found! Great job!');
174
174
  }
175
175
  console.log();
176
- // Save report to file
177
- const outputDir = path.resolve(options.output);
178
- await fs.mkdir(outputDir, { recursive: true });
179
- const reportFile = path.join(outputDir, `report-${Date.now()}.json`);
180
- await fs.writeFile(reportFile, JSON.stringify(report, null, 2));
181
- printInfo(`${icons.chart} Report saved: ${chalk.cyan(reportFile)}`);
182
- console.log();
176
+ // Save report to file ONLY if not uploading
177
+ if (!options.upload) {
178
+ const outputDir = path.resolve(options.output);
179
+ await fs.mkdir(outputDir, { recursive: true });
180
+ const reportFile = path.join(outputDir, `report-${Date.now()}.json`);
181
+ await fs.writeFile(reportFile, JSON.stringify(report, null, 2));
182
+ printInfo(`${icons.chart} Report saved: ${chalk.cyan(reportFile)}`);
183
+ console.log();
184
+ }
185
+ else {
186
+ printInfo(`${icons.chart} Report will be available on Delta Cloud Dashboard`);
187
+ console.log();
188
+ }
183
189
  // Upload to cloud if requested
184
190
  if (options.upload) {
185
191
  console.log(`${icons.rocket} Uploading to Delta Cloud...`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vee-stack/delta-cli",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Delta CLI v2 - Next-gen terminal interface with React Ink",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",