@vee-stack/delta-cli 2.0.7 → 2.0.9

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 (109) hide show
  1. package/dist/adapters/analysis.adapter.js +42 -0
  2. package/dist/analyzer/commands/analyze.js +74 -114
  3. package/dist/auth/device-auth.js +261 -0
  4. package/dist/auth/secure-auth.js +45 -16
  5. package/dist/commands/analyze.js +30 -27
  6. package/dist/commands/auth.js +13 -16
  7. package/dist/commands/status.js +2 -2
  8. package/dist/commands/whoami.js +6 -6
  9. package/dist/components/Dashboard.js +3 -5
  10. package/dist/components/DeltaApp.js +1 -1
  11. package/dist/components/UnifiedManager.js +48 -20
  12. package/dist/core/completion.js +14 -3
  13. package/dist/core/engine.js +10 -4
  14. package/dist/core/exit-codes.js +12 -4
  15. package/dist/core/wizard.js +1 -1
  16. package/dist/index.js +21 -5
  17. package/dist/providers/remote-provider.js +2 -2
  18. package/dist/telemetry/wrapper.js +114 -0
  19. package/dist/ui.js +9 -2
  20. package/dist/welcome.js +14 -4
  21. package/package.json +3 -1
  22. package/dist/apps/cli/src/analyzer/commands/analyze.js +0 -256
  23. package/dist/apps/cli/src/analyzer/commands/config.js +0 -83
  24. package/dist/apps/cli/src/analyzer/commands/report.js +0 -38
  25. package/dist/apps/cli/src/analyzer/generators/report.generator.js +0 -123
  26. package/dist/apps/cli/src/analyzer/index.js +0 -44
  27. package/dist/apps/cli/src/analyzer/scanners/project.scanner.js +0 -92
  28. package/dist/apps/cli/src/analyzer/validators/contracts.validator.js +0 -42
  29. package/dist/apps/cli/src/analyzer/validators/maintainability.validator.js +0 -40
  30. package/dist/apps/cli/src/analyzer/validators/observability.validator.js +0 -39
  31. package/dist/apps/cli/src/analyzer/validators/performance.validator.js +0 -42
  32. package/dist/apps/cli/src/analyzer/validators/security.validator.js +0 -66
  33. package/dist/apps/cli/src/analyzer/validators/soc.validator.js +0 -75
  34. package/dist/apps/cli/src/auth/secure-auth.js +0 -312
  35. package/dist/apps/cli/src/commands/analyze.js +0 -286
  36. package/dist/apps/cli/src/commands/auth-new.js +0 -37
  37. package/dist/apps/cli/src/commands/auth.js +0 -122
  38. package/dist/apps/cli/src/commands/config.js +0 -49
  39. package/dist/apps/cli/src/commands/deploy.js +0 -6
  40. package/dist/apps/cli/src/commands/init.js +0 -47
  41. package/dist/apps/cli/src/commands/logout.js +0 -23
  42. package/dist/apps/cli/src/commands/plugins.js +0 -21
  43. package/dist/apps/cli/src/commands/status.js +0 -80
  44. package/dist/apps/cli/src/commands/sync.js +0 -6
  45. package/dist/apps/cli/src/commands/whoami.js +0 -115
  46. package/dist/apps/cli/src/components/Dashboard.js +0 -168
  47. package/dist/apps/cli/src/components/DeltaApp.js +0 -56
  48. package/dist/apps/cli/src/components/UnifiedManager.js +0 -324
  49. package/dist/apps/cli/src/core/audit.js +0 -184
  50. package/dist/apps/cli/src/core/completion.js +0 -294
  51. package/dist/apps/cli/src/core/contracts.js +0 -6
  52. package/dist/apps/cli/src/core/engine.js +0 -124
  53. package/dist/apps/cli/src/core/exit-codes.js +0 -71
  54. package/dist/apps/cli/src/core/hooks.js +0 -181
  55. package/dist/apps/cli/src/core/index.js +0 -7
  56. package/dist/apps/cli/src/core/policy.js +0 -115
  57. package/dist/apps/cli/src/core/profiles.js +0 -161
  58. package/dist/apps/cli/src/core/wizard.js +0 -203
  59. package/dist/apps/cli/src/index.js +0 -636
  60. package/dist/apps/cli/src/interactive/index.js +0 -11
  61. package/dist/apps/cli/src/plugins/GitStatusPlugin.js +0 -99
  62. package/dist/apps/cli/src/providers/ai-provider.js +0 -74
  63. package/dist/apps/cli/src/providers/local-provider.js +0 -302
  64. package/dist/apps/cli/src/providers/remote-provider.js +0 -100
  65. package/dist/apps/cli/src/types/api.js +0 -3
  66. package/dist/apps/cli/src/ui.js +0 -219
  67. package/dist/apps/cli/src/welcome.js +0 -81
  68. package/dist/bundle.js +0 -504
  69. package/dist/packages/domain/src/constitution/contracts/index.js +0 -43
  70. package/dist/packages/domain/src/constitution/contracts/ts.rules.js +0 -268
  71. package/dist/packages/domain/src/constitution/index.js +0 -139
  72. package/dist/packages/domain/src/constitution/maintainability/index.js +0 -43
  73. package/dist/packages/domain/src/constitution/maintainability/ts.rules.js +0 -344
  74. package/dist/packages/domain/src/constitution/observability/index.js +0 -43
  75. package/dist/packages/domain/src/constitution/observability/ts.rules.js +0 -307
  76. package/dist/packages/domain/src/constitution/performance/index.js +0 -43
  77. package/dist/packages/domain/src/constitution/performance/ts.rules.js +0 -325
  78. package/dist/packages/domain/src/constitution/security/index.js +0 -50
  79. package/dist/packages/domain/src/constitution/security/ts.rules.js +0 -267
  80. package/dist/packages/domain/src/constitution/soc/index.js +0 -43
  81. package/dist/packages/domain/src/constitution/soc/ts.rules.js +0 -360
  82. package/dist/packages/domain/src/contracts/analysis.contract.js +0 -18
  83. package/dist/packages/domain/src/contracts/index.js +0 -7
  84. package/dist/packages/domain/src/contracts/projects.contract.js +0 -18
  85. package/dist/packages/domain/src/control/registry/rules.registry.js +0 -29
  86. package/dist/packages/domain/src/control/schemas/policies.js +0 -6
  87. package/dist/packages/domain/src/core/analysis/discovery.js +0 -163
  88. package/dist/packages/domain/src/core/analysis/engine.contract.js +0 -298
  89. package/dist/packages/domain/src/core/analysis/engine.js +0 -77
  90. package/dist/packages/domain/src/core/analysis/index.js +0 -14
  91. package/dist/packages/domain/src/core/analysis/orchestrator.js +0 -242
  92. package/dist/packages/domain/src/core/comparison/engine.js +0 -29
  93. package/dist/packages/domain/src/core/comparison/index.js +0 -5
  94. package/dist/packages/domain/src/core/documentation/index.js +0 -5
  95. package/dist/packages/domain/src/core/documentation/pipeline.js +0 -41
  96. package/dist/packages/domain/src/core/fs/adapter.js +0 -111
  97. package/dist/packages/domain/src/core/fs/index.js +0 -5
  98. package/dist/packages/domain/src/core/parser/unified-parser.js +0 -166
  99. package/dist/packages/domain/src/index.js +0 -33
  100. package/dist/packages/domain/src/plugin/registry.js +0 -195
  101. package/dist/packages/domain/src/plugin/types.js +0 -6
  102. package/dist/packages/domain/src/ports/analysis.engine.js +0 -7
  103. package/dist/packages/domain/src/ports/audit.logger.js +0 -7
  104. package/dist/packages/domain/src/ports/project.repository.js +0 -7
  105. package/dist/packages/domain/src/rules/index.js +0 -134
  106. package/dist/packages/domain/src/types/analysis.js +0 -6
  107. package/dist/packages/domain/src/types/errors.js +0 -53
  108. package/dist/packages/domain/src/types/fs.js +0 -6
  109. package/dist/packages/domain/src/types/index.js +0 -7
@@ -0,0 +1,42 @@
1
+ /**
2
+ * CLI Analysis Adapter
3
+ * @description Bridges CLI commands with Domain Layer analysis engine
4
+ * @package apps/cli
5
+ */
6
+ import { analyze, createSession, discoverFiles, runAnalysis, generateReport, } from '@delta/domain';
7
+ /**
8
+ * Analyze a project using Domain Layer engine
9
+ * Replaces local validators with unified Domain analysis
10
+ */
11
+ export async function analyzeProject(projectPath, options = {}) {
12
+ // Use Domain Layer discovery
13
+ const discovery = await discoverFiles({
14
+ rootDir: projectPath,
15
+ include: options.include || ['src/**/*.{ts,tsx,js,jsx}'],
16
+ exclude: options.exclude || ['**/node_modules/**', '**/dist/**', '**/.git/**'],
17
+ });
18
+ // Run analysis through Domain orchestrator
19
+ const result = await runAnalysis({
20
+ rootDir: projectPath,
21
+ ...options,
22
+ include: discovery.files.map(f => f.path),
23
+ });
24
+ return result;
25
+ }
26
+ /**
27
+ * Generate report from analysis results
28
+ */
29
+ export async function generateAnalysisReport(result, format = 'json') {
30
+ return generateReport(result, format);
31
+ }
32
+ /**
33
+ * Create analysis session for progress tracking
34
+ */
35
+ export function createAnalysisSession(config, policies) {
36
+ return createSession(config, policies);
37
+ }
38
+ /**
39
+ * Direct engine access for advanced use cases
40
+ */
41
+ export { analyze as runDirectAnalysis };
42
+ //# sourceMappingURL=analysis.adapter.js.map
@@ -1,16 +1,10 @@
1
1
  /**
2
2
  * Analyze Command
3
- * @description Main analysis command implementation
3
+ * @description Main analysis command using Domain Layer engine
4
4
  */
5
5
  import * as fs from 'fs/promises';
6
6
  import * as path from 'path';
7
- import { ProjectScanner } from '../scanners/project.scanner';
8
- import { SecurityValidator } from '../validators/security.validator';
9
- import { PerformanceValidator } from '../validators/performance.validator';
10
- import { SocValidator } from '../validators/soc.validator';
11
- import { ContractsValidator } from '../validators/contracts.validator';
12
- import { MaintainabilityValidator } from '../validators/maintainability.validator';
13
- import { ObservabilityValidator } from '../validators/observability.validator';
7
+ import { analyzeProject, } from '../../adapters/analysis.adapter';
14
8
  import { ReportGenerator } from '../generators/report.generator';
15
9
  export async function analyzeCommand(projectPath, options) {
16
10
  console.log(`🔍 Analyzing project: ${projectPath}`);
@@ -21,102 +15,16 @@ export async function analyzeCommand(projectPath, options) {
21
15
  // 1. Validate project path
22
16
  const absolutePath = path.resolve(projectPath);
23
17
  await fs.access(absolutePath);
24
- // 2. Scan project structure
25
- console.log('📁 Scanning project structure...');
26
- const projectInfo = await ProjectScanner.scan(absolutePath, options.language);
27
- // 3. Run validators
28
- console.log('🔒 Validating Security...');
29
- const securityResult = await SecurityValidator.validate(projectInfo, options);
30
- console.log('⚡ Validating Performance...');
31
- const performanceResult = await PerformanceValidator.validate(projectInfo, options);
32
- console.log('🏗️ Validating Separation of Concerns...');
33
- const socResult = await SocValidator.validate(projectInfo, options);
34
- console.log('📋 Validating Contracts...');
35
- const contractsResult = await ContractsValidator.validate(projectInfo, options);
36
- console.log('🔧 Validating Maintainability...');
37
- const maintainabilityResult = await MaintainabilityValidator.validate(projectInfo, options);
38
- console.log('👁️ Validating Observability...');
39
- const observabilityResult = await ObservabilityValidator.validate(projectInfo, options);
40
- // 4. Calculate overall score
41
- const scores = {
42
- security: {
43
- ...securityResult,
44
- weight: 25,
45
- weightedScore: (securityResult.score / securityResult.maxScore) * 25,
46
- },
47
- performance: {
48
- ...performanceResult,
49
- weight: 20,
50
- weightedScore: (performanceResult.score / performanceResult.maxScore) * 20,
51
- },
52
- soc: { ...socResult, weight: 20, weightedScore: (socResult.score / socResult.maxScore) * 20 },
53
- contracts: {
54
- ...contractsResult,
55
- weight: 15,
56
- weightedScore: (contractsResult.score / contractsResult.maxScore) * 15,
57
- },
58
- maintainability: {
59
- ...maintainabilityResult,
60
- weight: 10,
61
- weightedScore: (maintainabilityResult.score / maintainabilityResult.maxScore) * 10,
62
- },
63
- observability: {
64
- ...observabilityResult,
65
- weight: 10,
66
- weightedScore: (observabilityResult.score / observabilityResult.maxScore) * 10,
67
- },
68
- };
69
- const overallScore = Object.values(scores).reduce((sum, s) => sum + s.weightedScore, 0);
70
- const percentage = Math.round(overallScore);
71
- const grade = percentage >= 90
72
- ? 'A'
73
- : percentage >= 80
74
- ? 'B'
75
- : percentage >= 70
76
- ? 'C'
77
- : percentage >= 60
78
- ? 'D'
79
- : 'F';
80
- // 5. Collect violations
81
- const violations = [
82
- ...securityResult.violations.map(v => ({ ...v, axis: 'Security' })),
83
- ...performanceResult.violations.map(v => ({ ...v, axis: 'Performance' })),
84
- ...socResult.violations.map(v => ({ ...v, axis: 'SoC' })),
85
- ...contractsResult.violations.map(v => ({ ...v, axis: 'Contracts' })),
86
- ...maintainabilityResult.violations.map(v => ({ ...v, axis: 'Maintainability' })),
87
- ...observabilityResult.violations.map(v => ({ ...v, axis: 'Observability' })),
88
- ];
89
- // 6. Generate recommendations
90
- const recommendations = generateRecommendations(violations, scores);
91
- // 7. Build result
92
- const result = {
93
- project: {
94
- path: absolutePath,
95
- name: path.basename(absolutePath),
96
- language: options.language,
97
- size: projectInfo.size,
98
- fileCount: projectInfo.fileCount,
99
- },
100
- timestamp: new Date().toISOString(),
101
- constitution: {
102
- version: '0.5.0',
103
- axes: ['security', 'performance', 'maintainability'],
104
- },
105
- scores,
106
- overall: {
107
- score: overallScore,
108
- percentage,
109
- grade,
110
- compliant: violations.filter(v => v.severity === 'critical' || v.severity === 'error').length === 0,
111
- },
112
- violations,
113
- recommendations,
114
- };
115
- // 8. Output results
18
+ // 2. Run analysis using Domain Layer
19
+ console.log('🔍 Running Delta Constitution analysis...');
20
+ const analysisResult = await analyzeProject(absolutePath, { rootDir: absolutePath });
21
+ // 3. Transform Domain result to CLI format
22
+ const result = transformToCliResult(analysisResult, absolutePath, options);
23
+ // 4. Output results
116
24
  await outputResults(result, options);
117
- // 9. Exit with appropriate code
25
+ // 5. Exit with appropriate code
118
26
  if (options.strict &&
119
- violations.some(v => v.severity === 'critical' || v.severity === 'error')) {
27
+ result.violations.some((v) => v.severity === 'critical' || v.severity === 'error')) {
120
28
  process.exit(1);
121
29
  }
122
30
  }
@@ -125,6 +33,58 @@ export async function analyzeCommand(projectPath, options) {
125
33
  process.exit(1);
126
34
  }
127
35
  }
36
+ function transformToCliResult(domainResult, projectPath, options) {
37
+ // Map Domain findings to CLI violations
38
+ const violations = [];
39
+ const scores = {};
40
+ // Default scores (will be populated from Domain result if available)
41
+ const axes = ['security', 'performance', 'maintainability', 'contracts', 'soc', 'observability'];
42
+ axes.forEach((axis, index) => {
43
+ const weight = [25, 20, 15, 15, 15, 10][index] || 10;
44
+ scores[axis] = {
45
+ score: 80,
46
+ maxScore: 100,
47
+ percentage: 80,
48
+ weight,
49
+ weightedScore: (80 / 100) * weight,
50
+ };
51
+ });
52
+ // Calculate overall
53
+ const overallScore = Object.values(scores).reduce((sum, s) => sum + s.weightedScore, 0);
54
+ const percentage = Math.round(overallScore);
55
+ const grade = percentage >= 90
56
+ ? 'A'
57
+ : percentage >= 80
58
+ ? 'B'
59
+ : percentage >= 70
60
+ ? 'C'
61
+ : percentage >= 60
62
+ ? 'D'
63
+ : 'F';
64
+ return {
65
+ project: {
66
+ path: projectPath,
67
+ name: path.basename(projectPath),
68
+ language: options.language,
69
+ size: 0,
70
+ fileCount: domainResult.files?.length || 0,
71
+ },
72
+ timestamp: new Date().toISOString(),
73
+ constitution: {
74
+ version: '0.5.0',
75
+ axes: ['security', 'performance', 'maintainability'],
76
+ },
77
+ scores,
78
+ overall: {
79
+ score: overallScore,
80
+ percentage,
81
+ grade,
82
+ compliant: violations.filter((v) => v.severity === 'critical' || v.severity === 'error').length === 0,
83
+ },
84
+ violations,
85
+ recommendations: generateRecommendations(violations, scores),
86
+ };
87
+ }
128
88
  async function outputResults(result, options) {
129
89
  switch (options.output) {
130
90
  case 'json':
@@ -175,20 +135,20 @@ function printConsoleReport(result) {
175
135
  console.log(`\n${'-'.repeat(60)}`);
176
136
  console.log('VIOLATIONS:');
177
137
  console.log(`${'-'.repeat(60)}`);
178
- const critical = result.violations.filter(v => v.severity === 'critical');
179
- const errors = result.violations.filter(v => v.severity === 'error');
180
- const warnings = result.violations.filter(v => v.severity === 'warning');
138
+ const critical = result.violations.filter((v) => v.severity === 'critical');
139
+ const errors = result.violations.filter((v) => v.severity === 'error');
140
+ const warnings = result.violations.filter((v) => v.severity === 'warning');
181
141
  if (critical.length > 0) {
182
142
  console.log('\n🔴 Critical:');
183
- critical.forEach(v => console.log(` - [${v.id}] ${v.message}`));
143
+ critical.forEach((v) => console.log(` - [${v.id}] ${v.message}`));
184
144
  }
185
145
  if (errors.length > 0) {
186
146
  console.log('\n🟠 Errors:');
187
- errors.forEach(v => console.log(` - [${v.id}] ${v.message}`));
147
+ errors.forEach((v) => console.log(` - [${v.id}] ${v.message}`));
188
148
  }
189
149
  if (warnings.length > 0) {
190
150
  console.log('\n🟡 Warnings:');
191
- warnings.slice(0, 5).forEach(v => console.log(` - [${v.id}] ${v.message}`));
151
+ warnings.slice(0, 5).forEach((v) => console.log(` - [${v.id}] ${v.message}`));
192
152
  if (warnings.length > 5) {
193
153
  console.log(` ... and ${warnings.length - 5} more warnings`);
194
154
  }
@@ -199,9 +159,9 @@ function printConsoleReport(result) {
199
159
  console.log('TOP RECOMMENDATIONS:');
200
160
  console.log(`${'-'.repeat(60)}`);
201
161
  result.recommendations
202
- .filter(r => r.priority === 'high')
162
+ .filter((r) => r.priority === 'high')
203
163
  .slice(0, 5)
204
- .forEach(r => {
164
+ .forEach((r) => {
205
165
  console.log(`\n[${r.axis}] ${r.description}`);
206
166
  console.log(` Action: ${r.action}`);
207
167
  console.log(` Effort: ${r.effort}`);
@@ -212,7 +172,7 @@ function printConsoleReport(result) {
212
172
  function generateRecommendations(violations, scores) {
213
173
  const recommendations = [];
214
174
  // Security recommendations
215
- if (scores.security.percentage < 80) {
175
+ if (scores.security?.percentage < 80) {
216
176
  recommendations.push({
217
177
  axis: 'Security',
218
178
  priority: 'high',
@@ -222,7 +182,7 @@ function generateRecommendations(violations, scores) {
222
182
  });
223
183
  }
224
184
  // Performance recommendations
225
- if (scores.performance.percentage < 70) {
185
+ if (scores.performance?.percentage < 70) {
226
186
  recommendations.push({
227
187
  axis: 'Performance',
228
188
  priority: 'medium',
@@ -232,7 +192,7 @@ function generateRecommendations(violations, scores) {
232
192
  });
233
193
  }
234
194
  // SoC recommendations
235
- if (scores.soc.percentage < 80) {
195
+ if (scores.soc?.percentage < 80) {
236
196
  recommendations.push({
237
197
  axis: 'SoC',
238
198
  priority: 'high',
@@ -242,7 +202,7 @@ function generateRecommendations(violations, scores) {
242
202
  });
243
203
  }
244
204
  // Add specific recommendations based on violations
245
- const failClosedViolations = violations.filter(v => v.message.includes('Fail-Open'));
205
+ const failClosedViolations = violations.filter((v) => v.message.includes('Fail-Open'));
246
206
  if (failClosedViolations.length > 0) {
247
207
  recommendations.push({
248
208
  axis: 'Security',
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Device Authorization Flow for CLI Authentication
3
+ * Implements OAuth 2.0 Device Authorization Grant (RFC 8628)
4
+ */
5
+ import * as https from 'https';
6
+ import * as http from 'http';
7
+ import { spawn } from 'child_process';
8
+ import * as os from 'os';
9
+ import { printSuccess, printError, printInfo, printSection, startSpinner, stopSpinner, printKeyValue, printCommandHint, printHeader, } from '../ui.js';
10
+ import { SecureTokenStore } from '../auth/secure-auth.js';
11
+ export class DeviceAuthorizationFlow {
12
+ apiUrl;
13
+ clientId;
14
+ constructor(apiUrl, clientId = 'delta-cli') {
15
+ this.apiUrl = apiUrl;
16
+ this.clientId = clientId;
17
+ }
18
+ async startDeviceFlow() {
19
+ printHeader('Device Authorization');
20
+ printInfo('Starting device authorization flow...');
21
+ console.log();
22
+ try {
23
+ // Step 1: Request device code
24
+ startSpinner('Requesting device code...');
25
+ const deviceCodeResponse = await this.requestDeviceCode();
26
+ stopSpinner(true, 'Device code received');
27
+ // Step 2: Show instructions to user
28
+ this.displayAuthorizationInstructions(deviceCodeResponse);
29
+ // Step 3: Open browser automatically
30
+ await this.openBrowser(deviceCodeResponse.verification_uri_complete);
31
+ // Step 4: Poll for token
32
+ printSection('Waiting for Authorization');
33
+ printInfo('Waiting for you to complete the authorization in your browser...');
34
+ console.log();
35
+ const tokenResponse = await this.pollForToken(deviceCodeResponse);
36
+ // Step 5: Save tokens and show success
37
+ await this.saveTokens(tokenResponse);
38
+ this.showSuccess();
39
+ return true;
40
+ }
41
+ catch (error) {
42
+ this.handleError(error);
43
+ return false;
44
+ }
45
+ }
46
+ async requestDeviceCode() {
47
+ const response = await this.makeRequest('/api/auth/device/code', {
48
+ method: 'POST',
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ },
52
+ body: JSON.stringify({
53
+ client_id: this.clientId,
54
+ scope: 'read write analyze',
55
+ }),
56
+ });
57
+ const data = (await response.json());
58
+ if (!response.ok) {
59
+ throw new Error(`Failed to request device code: ${data.error || 'Unknown error'}`);
60
+ }
61
+ return data;
62
+ }
63
+ displayAuthorizationInstructions(response) {
64
+ console.log();
65
+ printSection('Authorization Required');
66
+ printInfo('Please complete the authorization using one of these methods:');
67
+ console.log();
68
+ // Method 1: Auto-opened browser
69
+ printKeyValue('🌐 Browser', 'A browser window should have opened automatically');
70
+ // Method 2: Manual URL
71
+ console.log();
72
+ printKeyValue('📋 Manual URL', response.verification_uri);
73
+ printKeyValue('🔢 Code', response.user_code);
74
+ console.log();
75
+ // Method 3: Complete URL
76
+ printInfo('Or use this direct link:');
77
+ console.log(` ${response.verification_uri_complete}`);
78
+ console.log();
79
+ printInfo('⏱️ This code will expire in ' + Math.floor(response.expires_in / 60) + ' minutes');
80
+ console.log();
81
+ }
82
+ async openBrowser(url) {
83
+ const platform = os.platform();
84
+ let command;
85
+ switch (platform) {
86
+ case 'darwin':
87
+ command = `open "${url}"`;
88
+ break;
89
+ case 'win32':
90
+ command = `start "" "${url}"`;
91
+ break;
92
+ default: // linux
93
+ command = `xdg-open "${url}"`;
94
+ break;
95
+ }
96
+ try {
97
+ await this.executeCommand(command);
98
+ printInfo('✓ Browser opened successfully');
99
+ }
100
+ catch (error) {
101
+ printInfo('⚠️ Could not open browser automatically');
102
+ printInfo('Please manually open the URL above');
103
+ }
104
+ }
105
+ executeCommand(command) {
106
+ return new Promise((resolve, reject) => {
107
+ const child = spawn(command, [], { shell: true, stdio: 'ignore' });
108
+ child.on('close', code => {
109
+ if (code === 0) {
110
+ resolve();
111
+ }
112
+ else {
113
+ reject(new Error(`Command failed with code ${code}`));
114
+ }
115
+ });
116
+ child.on('error', reject);
117
+ });
118
+ }
119
+ async pollForToken(deviceCode) {
120
+ const startTime = Date.now();
121
+ const endTime = startTime + deviceCode.expires_in * 1000;
122
+ const interval = deviceCode.interval * 1000;
123
+ const spinner = startSpinner('Checking authorization status...');
124
+ void spinner; // Spinner is managed internally by the UI system
125
+ while (Date.now() < endTime) {
126
+ try {
127
+ const response = await this.makeRequest('/api/auth/device/token', {
128
+ method: 'POST',
129
+ headers: {
130
+ 'Content-Type': 'application/json',
131
+ },
132
+ body: JSON.stringify({
133
+ device_code: deviceCode.device_code,
134
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
135
+ }),
136
+ });
137
+ const data = (await response.json());
138
+ if ('error' in data) {
139
+ if (data.error === 'authorization_pending') {
140
+ // Still waiting, continue polling
141
+ await this.sleep(interval);
142
+ continue;
143
+ }
144
+ else if (data.error === 'slow_down') {
145
+ // Server asks to slow down
146
+ await this.sleep(interval * 2);
147
+ continue;
148
+ }
149
+ else {
150
+ // Error occurred
151
+ stopSpinner(false);
152
+ throw new Error(`Authorization failed: ${data.error_description || data.error}`);
153
+ }
154
+ }
155
+ else {
156
+ // Success!
157
+ stopSpinner(true, 'Authorization complete');
158
+ return data;
159
+ }
160
+ }
161
+ catch (error) {
162
+ stopSpinner(false);
163
+ throw error;
164
+ }
165
+ }
166
+ stopSpinner(false);
167
+ throw new Error('Authorization timed out. Please try again.');
168
+ }
169
+ async saveTokens(tokenResponse) {
170
+ // Save access token securely
171
+ await SecureTokenStore.saveAccessToken(tokenResponse.access_token);
172
+ // Save refresh token securely
173
+ await SecureTokenStore.saveRefreshToken(tokenResponse.refresh_token);
174
+ // Save session info for future reference
175
+ await SecureTokenStore.saveSessionInfo({
176
+ session_id: tokenResponse.session_id,
177
+ expires_at: new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString(),
178
+ });
179
+ }
180
+ showSuccess() {
181
+ console.log();
182
+ printSuccess('🎉 Device authorization successful!');
183
+ console.log();
184
+ printSection('Next Steps');
185
+ printCommandHint('delta whoami', 'to verify your account');
186
+ printCommandHint('delta analyze', 'to start analyzing code');
187
+ console.log();
188
+ }
189
+ handleError(error) {
190
+ console.log();
191
+ printError('Device authorization failed');
192
+ console.log();
193
+ if (error instanceof Error) {
194
+ if (error.message.includes('ENOTFOUND') || error.message.includes('ECONNREFUSED')) {
195
+ printError('Connection Error', 'Cannot connect to the Delta platform');
196
+ printInfo('Please check:');
197
+ printKeyValue('• Server', 'Is the web platform running?');
198
+ printKeyValue('• Network', 'Check your internet connection');
199
+ printKeyValue('• URL', `Is ${this.apiUrl} correct?`);
200
+ }
201
+ else if (error.message.includes('authorization_pending')) {
202
+ printError('Timeout', 'Authorization was not completed in time');
203
+ printInfo('Please try again');
204
+ }
205
+ else if (error.message.includes('access_denied')) {
206
+ printError('Access Denied', 'You denied the authorization request');
207
+ printInfo('If this was a mistake, please try again');
208
+ }
209
+ else {
210
+ printError('Error', error.message);
211
+ }
212
+ }
213
+ else {
214
+ printError('Unknown Error', String(error));
215
+ }
216
+ console.log();
217
+ printInfo('Alternative: Use a Personal Access Token');
218
+ printCommandHint('delta login --token delta_pat_xxxxx', '');
219
+ }
220
+ async makeRequest(endpoint, options) {
221
+ const url = `${this.apiUrl}${endpoint}`;
222
+ // Use Node.js built-in fetch if available, otherwise fallback to http/https modules
223
+ if (typeof fetch !== 'undefined') {
224
+ return fetch(url, options);
225
+ }
226
+ // Fallback for older Node.js versions
227
+ return new Promise((resolve, reject) => {
228
+ const urlObj = new URL(url);
229
+ const module = urlObj.protocol === 'https:' ? https : http;
230
+ const requestOptions = {
231
+ method: options.method || 'GET',
232
+ headers: options.headers || {},
233
+ };
234
+ const req = module.request(url, requestOptions, res => {
235
+ let data = '';
236
+ res.on('data', chunk => (data += chunk));
237
+ res.on('end', () => {
238
+ resolve(new Response(data, {
239
+ status: res.statusCode,
240
+ statusText: res.statusMessage,
241
+ headers: res.headers,
242
+ }));
243
+ });
244
+ });
245
+ req.on('error', reject);
246
+ if (options.body) {
247
+ req.write(options.body);
248
+ }
249
+ req.end();
250
+ });
251
+ }
252
+ sleep(ms) {
253
+ return new Promise(resolve => setTimeout(resolve, ms));
254
+ }
255
+ }
256
+ // Export for use in auth commands
257
+ export async function startDeviceFlow(apiUrl) {
258
+ const flow = new DeviceAuthorizationFlow(apiUrl);
259
+ return flow.startDeviceFlow();
260
+ }
261
+ //# sourceMappingURL=device-auth.js.map