@vee-stack/delta-cli 2.0.5 → 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.
package/dist/auth/secure-auth.js
CHANGED
|
@@ -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
|
-
//
|
|
147
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
175
|
+
let redirectPort = 3456;
|
|
176
|
+
// Try to listen on port 3456
|
|
248
177
|
server.listen(3456, '127.0.0.1', () => {
|
|
249
|
-
|
|
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
|
-
|
|
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`, {
|
package/dist/commands/analyze.js
CHANGED
|
@@ -22,6 +22,26 @@ function extractApiErrorPayload(payload) {
|
|
|
22
22
|
}
|
|
23
23
|
export async function analyzeCommand(projectPath, options) {
|
|
24
24
|
const targetPath = path.resolve(projectPath);
|
|
25
|
+
// Check authentication FIRST if upload is requested
|
|
26
|
+
if (options.upload) {
|
|
27
|
+
printInfo('🔐 Checking authentication...');
|
|
28
|
+
const config = await loadConfig();
|
|
29
|
+
const pat = await SecureTokenStore.getAccessToken();
|
|
30
|
+
if (!pat) {
|
|
31
|
+
console.error();
|
|
32
|
+
console.error(chalk.red('❌ Error: You must be logged in to upload reports.'));
|
|
33
|
+
console.error();
|
|
34
|
+
console.error(chalk.yellow('Please authenticate first:'));
|
|
35
|
+
console.error(chalk.cyan(' delta login'));
|
|
36
|
+
console.error();
|
|
37
|
+
console.error(chalk.dim('Or use --upload with a valid PAT:'));
|
|
38
|
+
console.error(chalk.cyan(' delta analyze . --upload --token <your-pat>'));
|
|
39
|
+
console.error();
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
printSuccess('✓ Authenticated');
|
|
43
|
+
console.log();
|
|
44
|
+
}
|
|
25
45
|
printInfo('🔍 Starting Delta Analysis Engine...');
|
|
26
46
|
printDivider();
|
|
27
47
|
console.log(`${icons.folder} Project: ${chalk.cyan(targetPath)}`);
|
|
@@ -153,18 +173,25 @@ export async function analyzeCommand(projectPath, options) {
|
|
|
153
173
|
printSuccess('✨ No issues found! Great job!');
|
|
154
174
|
}
|
|
155
175
|
console.log();
|
|
156
|
-
// Save report to file
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
+
}
|
|
163
189
|
// Upload to cloud if requested
|
|
164
190
|
if (options.upload) {
|
|
165
191
|
console.log(`${icons.rocket} Uploading to Delta Cloud...`);
|
|
166
192
|
await uploadReport(report);
|
|
167
193
|
}
|
|
194
|
+
process.exit(0);
|
|
168
195
|
}
|
|
169
196
|
async function uploadReport(report) {
|
|
170
197
|
const config = await loadConfig();
|
package/dist/commands/auth.js
CHANGED
|
@@ -44,7 +44,7 @@ export const authCommands = {
|
|
|
44
44
|
console.log();
|
|
45
45
|
printCommandHint('delta whoami', 'to see account details');
|
|
46
46
|
printCommandHint('delta analyze', 'to start analyzing code');
|
|
47
|
-
|
|
47
|
+
process.exit(0);
|
|
48
48
|
}
|
|
49
49
|
// PAT Token flow (when token is provided)
|
|
50
50
|
// Validate token format
|
|
@@ -102,6 +102,7 @@ export const authCommands = {
|
|
|
102
102
|
console.log();
|
|
103
103
|
printCommandHint('delta whoami', 'to see full account details');
|
|
104
104
|
printCommandHint('delta analyze', 'to start analyzing code');
|
|
105
|
+
process.exit(0);
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
107
108
|
stopSpinner(false, 'Authentication failed');
|
package/dist/commands/config.js
CHANGED
|
@@ -13,7 +13,7 @@ export async function configCommand(options) {
|
|
|
13
13
|
else {
|
|
14
14
|
console.log(`${options.get}: (not set)`);
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
process.exit(0);
|
|
17
17
|
}
|
|
18
18
|
if (options.set) {
|
|
19
19
|
const [key, value] = options.set.split('=');
|
|
@@ -28,7 +28,7 @@ export async function configCommand(options) {
|
|
|
28
28
|
};
|
|
29
29
|
await saveConfig(newConfig);
|
|
30
30
|
console.log(`✅ Set ${key} = ${value}`);
|
|
31
|
-
|
|
31
|
+
process.exit(0);
|
|
32
32
|
}
|
|
33
33
|
if (options.list || (!options.get && !options.set)) {
|
|
34
34
|
console.log('🔧 Delta CLI Configuration');
|
|
@@ -45,6 +45,7 @@ export async function configCommand(options) {
|
|
|
45
45
|
if (config.lastUsedAt) {
|
|
46
46
|
console.log(` Last used: ${new Date(config.lastUsedAt).toLocaleString()}`);
|
|
47
47
|
}
|
|
48
|
+
process.exit(0);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
//# sourceMappingURL=config.js.map
|
package/dist/commands/logout.js
CHANGED
|
@@ -9,7 +9,7 @@ export async function logoutCommand() {
|
|
|
9
9
|
const hasToken = await SecureTokenStore.hasTokens();
|
|
10
10
|
if (!hasToken) {
|
|
11
11
|
console.log('ℹ️ Not currently authenticated');
|
|
12
|
-
|
|
12
|
+
process.exit(0);
|
|
13
13
|
}
|
|
14
14
|
// Clear tokens from keychain and remove config file
|
|
15
15
|
await SecureTokenStore.clearTokens();
|
|
@@ -21,6 +21,7 @@ export async function logoutCommand() {
|
|
|
21
21
|
}
|
|
22
22
|
console.log('✅ Successfully logged out');
|
|
23
23
|
console.log(' Authentication data removed');
|
|
24
|
+
process.exit(0);
|
|
24
25
|
}
|
|
25
26
|
catch (error) {
|
|
26
27
|
console.error('❌ Error during logout:', error instanceof Error ? error.message : String(error));
|
package/dist/commands/whoami.js
CHANGED