zero-doc 1.0.12 → 1.0.14
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/ai-analyzer.d.ts +2 -0
- package/dist/ai-analyzer.js +9 -3
- package/dist/cli.js +126 -124
- package/package.json +1 -1
package/dist/ai-analyzer.d.ts
CHANGED
|
@@ -3,11 +3,13 @@ export interface AIAnalyzerOptions {
|
|
|
3
3
|
apiUrl: string;
|
|
4
4
|
projectRoot: string;
|
|
5
5
|
filePatterns: string[];
|
|
6
|
+
token?: string;
|
|
6
7
|
}
|
|
7
8
|
export declare class AIAnalyzer {
|
|
8
9
|
private apiUrl;
|
|
9
10
|
private projectRoot;
|
|
10
11
|
private filePatterns;
|
|
12
|
+
private token?;
|
|
11
13
|
constructor(options: AIAnalyzerOptions);
|
|
12
14
|
analyzeProject(): Promise<APIInventory>;
|
|
13
15
|
private findProjectFiles;
|
package/dist/ai-analyzer.js
CHANGED
|
@@ -42,6 +42,7 @@ class AIAnalyzer {
|
|
|
42
42
|
this.apiUrl = options.apiUrl;
|
|
43
43
|
this.projectRoot = options.projectRoot;
|
|
44
44
|
this.filePatterns = options.filePatterns;
|
|
45
|
+
this.token = options.token;
|
|
45
46
|
}
|
|
46
47
|
async analyzeProject() {
|
|
47
48
|
const files = await this.findProjectFiles();
|
|
@@ -151,11 +152,16 @@ class AIAnalyzer {
|
|
|
151
152
|
throw new Error(`Invalid API URL: "${url}". URL must start with http:// or https://`);
|
|
152
153
|
}
|
|
153
154
|
try {
|
|
155
|
+
const headers = {
|
|
156
|
+
'Content-Type': 'application/json',
|
|
157
|
+
};
|
|
158
|
+
// Add authorization token if available
|
|
159
|
+
if (this.token) {
|
|
160
|
+
headers['Authorization'] = `Bearer ${this.token}`;
|
|
161
|
+
}
|
|
154
162
|
const response = await fetch(url, {
|
|
155
163
|
method: 'POST',
|
|
156
|
-
headers
|
|
157
|
-
'Content-Type': 'application/json',
|
|
158
|
-
},
|
|
164
|
+
headers,
|
|
159
165
|
body: JSON.stringify({ prompt }),
|
|
160
166
|
});
|
|
161
167
|
if (!response.ok) {
|
package/dist/cli.js
CHANGED
|
@@ -74,6 +74,20 @@ function getBaseUrl() {
|
|
|
74
74
|
return config.baseUrl;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
return 'https://zero-doc.com';
|
|
78
|
+
}
|
|
79
|
+
function getToken() {
|
|
80
|
+
try {
|
|
81
|
+
const tokenFile = path.join(os.homedir(), '.zero-doc', 'token.json');
|
|
82
|
+
if (fs.existsSync(tokenFile)) {
|
|
83
|
+
const tokenData = JSON.parse(fs.readFileSync(tokenFile, 'utf-8'));
|
|
84
|
+
return tokenData.token;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
// Token file doesn't exist or is invalid
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
77
91
|
}
|
|
78
92
|
function displayPlansLink() {
|
|
79
93
|
const reset = '\x1b[0m';
|
|
@@ -116,91 +130,7 @@ commander_1.program
|
|
|
116
130
|
}
|
|
117
131
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
118
132
|
console.log('✅ Created zero-doc.config.json');
|
|
119
|
-
console.log('💡 Run: zero-doc
|
|
120
|
-
});
|
|
121
|
-
commander_1.program
|
|
122
|
-
.command('generate')
|
|
123
|
-
.description('Generate API inventory from project using AI')
|
|
124
|
-
.option('-i, --input <pattern>', 'Source files glob pattern', 'src/**/*.{ts,js,py,java,go,rs,php,rb}')
|
|
125
|
-
.option('-o, --output <path>', 'Output file path', 'api-inventory.json')
|
|
126
|
-
.option('-n, --name <name>', 'Project name')
|
|
127
|
-
.option('--ai-provider <provider>', 'AI provider: gemini', 'gemini')
|
|
128
|
-
.action(async (options) => {
|
|
129
|
-
console.log('🤖 Analyzing project with AI...\n');
|
|
130
|
-
const configPath = path.join(process.cwd(), 'zero-doc.config.json');
|
|
131
|
-
let config = {};
|
|
132
|
-
if (fs.existsSync(configPath)) {
|
|
133
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
134
|
-
}
|
|
135
|
-
try {
|
|
136
|
-
let generateApiUrl;
|
|
137
|
-
const generateConfigPath = path.join(__dirname, 'config.json');
|
|
138
|
-
if (fs.existsSync(generateConfigPath)) {
|
|
139
|
-
try {
|
|
140
|
-
const generateConfig = JSON.parse(fs.readFileSync(generateConfigPath, 'utf-8'));
|
|
141
|
-
generateApiUrl = generateConfig.apiUrl;
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (!generateApiUrl || generateApiUrl.trim() === '') {
|
|
147
|
-
console.error('❌ Error: API configuration not found');
|
|
148
|
-
console.error('💡 This should not happen. The package should include the configuration.');
|
|
149
|
-
console.error('💡 Please reinstall: npm install -g zero-doc');
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
152
|
-
let projectName = options.name || config.name;
|
|
153
|
-
let projectVersion;
|
|
154
|
-
let projectDescription;
|
|
155
|
-
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
156
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
157
|
-
try {
|
|
158
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
159
|
-
projectName = projectName || packageJson.name;
|
|
160
|
-
projectVersion = packageJson.version;
|
|
161
|
-
projectDescription = packageJson.description;
|
|
162
|
-
}
|
|
163
|
-
catch (error) {
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const inputPattern = options.input || config.input || 'src/**/*.{ts,js}';
|
|
167
|
-
const patterns = inputPattern.includes('{') && inputPattern.includes('}')
|
|
168
|
-
? [inputPattern]
|
|
169
|
-
: inputPattern.split(',').map(p => p.trim());
|
|
170
|
-
console.log(`📋 Using patterns: ${patterns.join(', ')}\n`);
|
|
171
|
-
const analyzer = new ai_analyzer_1.AIAnalyzer({
|
|
172
|
-
apiUrl: generateApiUrl,
|
|
173
|
-
projectRoot: process.cwd(),
|
|
174
|
-
filePatterns: patterns,
|
|
175
|
-
});
|
|
176
|
-
const inventory = await analyzer.analyzeProject();
|
|
177
|
-
inventory.project.name = inventory.project.name || projectName;
|
|
178
|
-
inventory.project.version = inventory.project.version || projectVersion;
|
|
179
|
-
inventory.project.description = inventory.project.description || projectDescription;
|
|
180
|
-
if (!inventory.baseUrl) {
|
|
181
|
-
inventory.baseUrl = 'https://api.example.com';
|
|
182
|
-
}
|
|
183
|
-
const outputPath = options.output || config.output || 'api-inventory.json';
|
|
184
|
-
const json = JSON.stringify(inventory, null, 2);
|
|
185
|
-
const dir = path.dirname(outputPath);
|
|
186
|
-
if (!fs.existsSync(dir)) {
|
|
187
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
188
|
-
}
|
|
189
|
-
fs.writeFileSync(outputPath, json, 'utf-8');
|
|
190
|
-
console.log('✅ Analysis complete!\n');
|
|
191
|
-
console.log(`📊 Statistics:`);
|
|
192
|
-
console.log(` Total endpoints: ${inventory.stats.totalEndpoints}`);
|
|
193
|
-
console.log(` Framework: ${inventory.project.framework}`);
|
|
194
|
-
console.log('');
|
|
195
|
-
Object.entries(inventory.stats.byMethod).forEach(([method, count]) => {
|
|
196
|
-
console.log(` ${method}: ${count}`);
|
|
197
|
-
});
|
|
198
|
-
console.log(`\n💾 File generated: ${outputPath}`);
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
console.error('❌ Error:', error instanceof Error ? error.message : error);
|
|
202
|
-
process.exit(1);
|
|
203
|
-
}
|
|
133
|
+
console.log('💡 Run: zero-doc preview');
|
|
204
134
|
});
|
|
205
135
|
commander_1.program
|
|
206
136
|
.command('preview')
|
|
@@ -303,10 +233,12 @@ commander_1.program
|
|
|
303
233
|
const patterns = inputPattern.includes('{') && inputPattern.includes('}')
|
|
304
234
|
? [inputPattern]
|
|
305
235
|
: inputPattern.split(',').map(p => p.trim());
|
|
236
|
+
const token = getToken();
|
|
306
237
|
const analyzer = new ai_analyzer_1.AIAnalyzer({
|
|
307
238
|
apiUrl: apiUrl,
|
|
308
239
|
projectRoot: process.cwd(),
|
|
309
240
|
filePatterns: patterns,
|
|
241
|
+
token: token,
|
|
310
242
|
});
|
|
311
243
|
updateProgress(20, 100, 'Analyzing project');
|
|
312
244
|
const inventory = await analyzer.analyzeProject();
|
|
@@ -529,15 +461,26 @@ commander_1.program
|
|
|
529
461
|
timeout = null;
|
|
530
462
|
}
|
|
531
463
|
if (server) {
|
|
532
|
-
server.close()
|
|
464
|
+
server.close(() => {
|
|
465
|
+
// Server closed
|
|
466
|
+
});
|
|
533
467
|
server = null;
|
|
534
468
|
}
|
|
535
469
|
};
|
|
470
|
+
const finish = () => {
|
|
471
|
+
cleanup();
|
|
472
|
+
resolve();
|
|
473
|
+
// Exit after resolving promise
|
|
474
|
+
setTimeout(() => {
|
|
475
|
+
process.exit(0);
|
|
476
|
+
}, 100);
|
|
477
|
+
};
|
|
536
478
|
// 5 minute timeout
|
|
537
479
|
timeout = setTimeout(() => {
|
|
538
|
-
cleanup();
|
|
539
480
|
console.error('❌ Timeout: Login was not completed within 5 minutes');
|
|
540
|
-
|
|
481
|
+
cleanup();
|
|
482
|
+
resolve();
|
|
483
|
+
setTimeout(() => process.exit(1), 100);
|
|
541
484
|
}, 5 * 60 * 1000);
|
|
542
485
|
server = http.createServer((req, res) => {
|
|
543
486
|
if (req.url?.startsWith('/callback')) {
|
|
@@ -564,9 +507,10 @@ commander_1.program
|
|
|
564
507
|
</body>
|
|
565
508
|
</html>
|
|
566
509
|
`);
|
|
567
|
-
cleanup();
|
|
568
510
|
console.error(`❌ Error: ${error}`);
|
|
569
|
-
|
|
511
|
+
cleanup();
|
|
512
|
+
resolve();
|
|
513
|
+
setTimeout(() => process.exit(1), 100);
|
|
570
514
|
return;
|
|
571
515
|
}
|
|
572
516
|
if (token) {
|
|
@@ -583,63 +527,121 @@ commander_1.program
|
|
|
583
527
|
<head>
|
|
584
528
|
<title>Login Successful</title>
|
|
585
529
|
<style>
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
530
|
+
* {
|
|
531
|
+
margin: 0;
|
|
532
|
+
padding: 0;
|
|
533
|
+
box-sizing: border-box;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
body {
|
|
537
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
538
|
+
min-height: 100vh;
|
|
539
|
+
display: flex;
|
|
540
|
+
align-items: center;
|
|
541
|
+
justify-content: center;
|
|
542
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
543
|
+
padding: 20px;
|
|
591
544
|
}
|
|
545
|
+
|
|
592
546
|
.container {
|
|
593
547
|
background: white;
|
|
594
|
-
border-radius:
|
|
595
|
-
padding: 40px;
|
|
596
|
-
box-shadow: 0
|
|
597
|
-
max-width:
|
|
598
|
-
|
|
548
|
+
border-radius: 16px;
|
|
549
|
+
padding: 48px 40px;
|
|
550
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
551
|
+
max-width: 420px;
|
|
552
|
+
width: 100%;
|
|
553
|
+
text-align: center;
|
|
554
|
+
animation: slideIn 0.3s ease-out;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
@keyframes slideIn {
|
|
558
|
+
from {
|
|
559
|
+
opacity: 0;
|
|
560
|
+
transform: translateY(-20px);
|
|
561
|
+
}
|
|
562
|
+
to {
|
|
563
|
+
opacity: 1;
|
|
564
|
+
transform: translateY(0);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.icon {
|
|
569
|
+
width: 80px;
|
|
570
|
+
height: 80px;
|
|
571
|
+
margin: 0 auto 24px;
|
|
572
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
573
|
+
border-radius: 50%;
|
|
574
|
+
display: flex;
|
|
575
|
+
align-items: center;
|
|
576
|
+
justify-content: center;
|
|
577
|
+
font-size: 48px;
|
|
578
|
+
animation: scaleIn 0.4s ease-out 0.1s both;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
@keyframes scaleIn {
|
|
582
|
+
from {
|
|
583
|
+
transform: scale(0);
|
|
584
|
+
}
|
|
585
|
+
to {
|
|
586
|
+
transform: scale(1);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
h1 {
|
|
591
|
+
font-size: 28px;
|
|
592
|
+
font-weight: 700;
|
|
593
|
+
color: #1f2937;
|
|
594
|
+
margin-bottom: 12px;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.subtitle {
|
|
598
|
+
font-size: 16px;
|
|
599
|
+
color: #6b7280;
|
|
600
|
+
margin-bottom: 32px;
|
|
601
|
+
line-height: 1.5;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.message {
|
|
605
|
+
font-size: 14px;
|
|
606
|
+
color: #9ca3af;
|
|
607
|
+
margin-top: 24px;
|
|
608
|
+
padding-top: 24px;
|
|
609
|
+
border-top: 1px solid #e5e7eb;
|
|
599
610
|
}
|
|
600
|
-
.success { color: #16a34a; }
|
|
601
|
-
.icon { font-size: 48px; margin-bottom: 20px; }
|
|
602
611
|
</style>
|
|
603
612
|
<script>
|
|
604
|
-
//
|
|
605
|
-
function
|
|
613
|
+
// Close window after 5 seconds
|
|
614
|
+
setTimeout(function() {
|
|
606
615
|
try {
|
|
607
616
|
window.close();
|
|
608
|
-
|
|
617
|
+
} catch (e) {
|
|
618
|
+
// If close fails, try again
|
|
609
619
|
setTimeout(function() {
|
|
610
|
-
// Try again - some browsers allow close after user interaction
|
|
611
620
|
window.close();
|
|
612
621
|
}, 100);
|
|
613
|
-
} catch (e) {
|
|
614
|
-
// Ignore errors
|
|
615
622
|
}
|
|
616
|
-
}
|
|
623
|
+
}, 5000);
|
|
617
624
|
|
|
618
|
-
//
|
|
619
|
-
|
|
620
|
-
|
|
625
|
+
// Also allow manual close on click
|
|
626
|
+
document.addEventListener('click', function() {
|
|
627
|
+
try {
|
|
628
|
+
window.close();
|
|
629
|
+
} catch (e) {}
|
|
621
630
|
});
|
|
622
|
-
|
|
623
|
-
// Also try on user interaction (some browsers require this)
|
|
624
|
-
document.addEventListener('click', tryClose);
|
|
625
|
-
document.addEventListener('keydown', tryClose);
|
|
626
631
|
</script>
|
|
627
632
|
</head>
|
|
628
633
|
<body>
|
|
629
634
|
<div class="container">
|
|
630
|
-
<div class="icon"
|
|
631
|
-
<h1
|
|
632
|
-
<p>
|
|
633
|
-
<p
|
|
634
|
-
You can close this window and return to your terminal.
|
|
635
|
-
</p>
|
|
635
|
+
<div class="icon">✓</div>
|
|
636
|
+
<h1>Login Successful!</h1>
|
|
637
|
+
<p class="subtitle">Your token has been saved successfully.</p>
|
|
638
|
+
<p class="message">This window will close automatically in a few seconds...</p>
|
|
636
639
|
</div>
|
|
637
640
|
</body>
|
|
638
641
|
</html>
|
|
639
642
|
`);
|
|
640
|
-
cleanup();
|
|
641
643
|
console.log('✅ Login successful!');
|
|
642
|
-
|
|
644
|
+
finish();
|
|
643
645
|
}
|
|
644
646
|
else {
|
|
645
647
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|