shadowdocs 2.1.5 → 2.1.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/CONTRIBUTING.md +34 -66
- package/LICENSE +1 -1
- package/README.md +119 -78
- package/SECURITY.md +25 -42
- package/dist/services/ai.d.ts +7 -0
- package/dist/services/ai.d.ts.map +1 -1
- package/dist/services/ai.js +167 -77
- package/dist/services/ai.js.map +1 -1
- package/dist/ui/components/Generator.d.ts.map +1 -1
- package/dist/ui/components/Generator.js +22 -10
- package/dist/ui/components/Generator.js.map +1 -1
- package/dist/ui/components/Menu.d.ts.map +1 -1
- package/dist/ui/components/Menu.js +3 -3
- package/dist/ui/components/Menu.js.map +1 -1
- package/package.json +1 -1
- package/src/services/ai.ts +185 -80
- package/src/ui/components/Generator.tsx +30 -12
- package/src/ui/components/Menu.tsx +6 -11
package/src/services/ai.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { DocResult } from '../core/types.js';
|
|
|
5
5
|
const GROQ_API_URL = 'https://api.groq.com/openai/v1/chat/completions';
|
|
6
6
|
const MODEL = 'llama-3.3-70b-versatile';
|
|
7
7
|
|
|
8
|
-
const SYSTEM_PROMPT = `You are a senior open-source maintainer and technical documentation expert.
|
|
8
|
+
const SYSTEM_PROMPT = `You are a senior open-source maintainer and technical documentation expert with 15+ years of experience. You generate comprehensive, production-grade documentation that is practical, accurate, and developer-friendly. NEVER hallucinate features - only document what exists in the codebase.`;
|
|
9
9
|
|
|
10
10
|
const MAX_RETRIES = 3;
|
|
11
11
|
const BASE_DELAY = 1000;
|
|
@@ -61,6 +61,14 @@ async function withRetry<T>(
|
|
|
61
61
|
throw lastError || new Error('Request failed after retries');
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
export interface GeneratedDocs {
|
|
65
|
+
content?: string;
|
|
66
|
+
readme: string;
|
|
67
|
+
contributing: string;
|
|
68
|
+
license: string;
|
|
69
|
+
security: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
export async function generateDocs(projectData: Record<string, unknown>, mode: 'generate' | 'improve' | 'explain' = 'generate'): Promise<DocResult> {
|
|
65
73
|
const apiKey = await loadApiKey();
|
|
66
74
|
|
|
@@ -68,124 +76,221 @@ export async function generateDocs(projectData: Record<string, unknown>, mode: '
|
|
|
68
76
|
throw new Error('API key not configured. Run shadowdocs setup.');
|
|
69
77
|
}
|
|
70
78
|
|
|
71
|
-
let userPrompt = '';
|
|
72
|
-
|
|
73
|
-
switch (mode) {
|
|
74
|
-
case 'generate':
|
|
75
|
-
userPrompt = buildGeneratePrompt(projectData);
|
|
76
|
-
break;
|
|
77
|
-
case 'improve':
|
|
78
|
-
userPrompt = buildImprovePrompt(projectData);
|
|
79
|
-
break;
|
|
80
|
-
case 'explain':
|
|
81
|
-
userPrompt = buildExplainPrompt(projectData);
|
|
82
|
-
break;
|
|
83
|
-
default:
|
|
84
|
-
userPrompt = buildGeneratePrompt(projectData);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const response = await withRetry(() => makeRequest(apiKey, userPrompt));
|
|
88
|
-
|
|
89
79
|
if (mode === 'explain') {
|
|
80
|
+
const response = await withRetry(() => makeRequest(apiKey, buildExplainPrompt(projectData)));
|
|
90
81
|
return { type: 'text', content: response };
|
|
91
82
|
}
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
|
|
84
|
+
if (mode === 'generate') {
|
|
85
|
+
const [readme, contributing, license, security] = await Promise.all([
|
|
86
|
+
withRetry(() => makeRequest(apiKey, buildReadmePrompt(projectData))),
|
|
87
|
+
withRetry(() => makeRequest(apiKey, buildContributingPrompt(projectData))),
|
|
88
|
+
withRetry(() => makeRequest(apiKey, buildLicensePrompt(projectData))),
|
|
89
|
+
withRetry(() => makeRequest(apiKey, buildSecurityPrompt(projectData)))
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
type: 'markdown',
|
|
94
|
+
content: readme,
|
|
95
|
+
contributing,
|
|
96
|
+
license,
|
|
97
|
+
security
|
|
98
|
+
} as unknown as DocResult;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (mode === 'improve') {
|
|
102
|
+
const [readme, contributing, license, security] = await Promise.all([
|
|
103
|
+
withRetry(() => makeRequest(apiKey, buildImproveReadmePrompt(projectData))),
|
|
104
|
+
withRetry(() => makeRequest(apiKey, buildImproveContributingPrompt(projectData))),
|
|
105
|
+
withRetry(() => makeRequest(apiKey, buildImproveLicensePrompt(projectData))),
|
|
106
|
+
withRetry(() => makeRequest(apiKey, buildImproveSecurityPrompt(projectData)))
|
|
107
|
+
]);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
type: 'markdown',
|
|
111
|
+
content: readme,
|
|
112
|
+
contributing,
|
|
113
|
+
license,
|
|
114
|
+
security
|
|
115
|
+
} as unknown as DocResult;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new Error('Unknown mode');
|
|
94
119
|
}
|
|
95
120
|
|
|
96
|
-
function
|
|
97
|
-
return `Generate a
|
|
121
|
+
function buildReadmePrompt(projectData: Record<string, unknown>): string {
|
|
122
|
+
return `You are an expert technical writer. Generate a comprehensive, production-ready README.md for this project.
|
|
123
|
+
|
|
124
|
+
Analyze the project structure and package.json thoroughly. Document ONLY what's actually present in the codebase.
|
|
98
125
|
|
|
99
|
-
|
|
126
|
+
Requirements:
|
|
127
|
+
1. Overview: What the project does, target audience, primary use case
|
|
128
|
+
2. Features: List ACTUAL features from package.json scripts and dependencies - NO made-up features
|
|
129
|
+
3. Installation: Exact commands for npm/pnpm/yarn
|
|
130
|
+
4. Usage: Real code examples based on actual entry points and exports
|
|
131
|
+
5. API: Document actual functions/endpoints/components found in the code
|
|
132
|
+
6. Configuration: Actual config options if any
|
|
133
|
+
7. Development: Real npm scripts from package.json
|
|
134
|
+
8. Testing: How tests are run (from scripts)
|
|
135
|
+
9. Project Structure: Actual directory layout
|
|
136
|
+
10. Technologies: Real stack based on dependencies
|
|
100
137
|
|
|
101
|
-
|
|
102
|
-
2-3 sentences about what this project does and its purpose.
|
|
138
|
+
IMPORTANT: Use the project data provided and INFER realistic content. Don't leave placeholder text.
|
|
103
139
|
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
Project Data:
|
|
141
|
+
${JSON.stringify(projectData, null, 2)}
|
|
106
142
|
|
|
107
|
-
|
|
108
|
-
|
|
143
|
+
Return ONLY complete README.md markdown.`;
|
|
144
|
+
}
|
|
109
145
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- Do NOT add fake features
|
|
146
|
+
function buildContributingPrompt(projectData: Record<string, unknown>): string {
|
|
147
|
+
return `Generate a professional CONTRIBUTING.md for this project.
|
|
113
148
|
|
|
114
|
-
|
|
115
|
-
|
|
149
|
+
Requirements:
|
|
150
|
+
1. How to contribute (fork, clone, branch workflow)
|
|
151
|
+
2. Development setup steps
|
|
152
|
+
3. Code style guidelines (linting, formatting)
|
|
153
|
+
4. Commit message conventions
|
|
154
|
+
5. PR process and requirements
|
|
155
|
+
6. Testing requirements
|
|
156
|
+
7. Types of contributions welcome
|
|
157
|
+
8. Issue templates or guidelines
|
|
158
|
+
9. Recognition for contributors
|
|
159
|
+
10. Code of conduct reference
|
|
116
160
|
|
|
117
|
-
|
|
118
|
-
Show actual usage examples with code snippets.
|
|
161
|
+
Base it on the project's package.json scripts and known best practices.
|
|
119
162
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
If frontend: document components/hooks
|
|
123
|
-
If library: document exports/functions
|
|
163
|
+
Project Data:
|
|
164
|
+
${JSON.stringify(projectData, null, 2)}
|
|
124
165
|
|
|
125
|
-
|
|
126
|
-
|
|
166
|
+
Return ONLY complete CONTRIBUTING.md markdown.`;
|
|
167
|
+
}
|
|
127
168
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
npm install
|
|
131
|
-
npm run [script] - description
|
|
169
|
+
function buildLicensePrompt(projectData: Record<string, unknown>): string {
|
|
170
|
+
return `Generate a complete LICENSE file. Use MIT License as default. Include:
|
|
132
171
|
|
|
133
|
-
|
|
134
|
-
|
|
172
|
+
1. Full MIT License text
|
|
173
|
+
2. Copyright year (current year: ${new Date().getFullYear()})
|
|
174
|
+
3. Project name: ${projectData.name || 'Project'}
|
|
175
|
+
4. Author name if available in package.json
|
|
135
176
|
|
|
136
|
-
|
|
137
|
-
|
|
177
|
+
Project Data:
|
|
178
|
+
${JSON.stringify(projectData, null, 2)}
|
|
138
179
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- Fork and create feature branch
|
|
142
|
-
- Follow existing code style
|
|
143
|
-
- Add tests if applicable
|
|
144
|
-
- Submit PR
|
|
180
|
+
Return ONLY complete LICENSE file content (plain text, not markdown).`;
|
|
181
|
+
}
|
|
145
182
|
|
|
146
|
-
|
|
147
|
-
|
|
183
|
+
function buildSecurityPrompt(projectData: Record<string, unknown>): string {
|
|
184
|
+
return `Generate a professional SECURITY.md for this project.
|
|
148
185
|
|
|
149
|
-
|
|
150
|
-
|
|
186
|
+
Requirements:
|
|
187
|
+
1. How to report vulnerabilities
|
|
188
|
+
2. Security policy scope
|
|
189
|
+
3. Response timeline
|
|
190
|
+
4. Disclosure guidelines
|
|
191
|
+
5. Security update process
|
|
192
|
+
6. Contact information
|
|
193
|
+
7. Dependencies security info if applicable
|
|
151
194
|
|
|
152
195
|
Project Data:
|
|
153
196
|
${JSON.stringify(projectData, null, 2)}
|
|
154
197
|
|
|
155
|
-
Return ONLY complete markdown.`;
|
|
198
|
+
Return ONLY complete SECURITY.md markdown.`;
|
|
156
199
|
}
|
|
157
200
|
|
|
158
|
-
function
|
|
201
|
+
function buildImproveReadmePrompt(projectData: Record<string, unknown>): string {
|
|
159
202
|
return `Improve the existing README.md for this project.
|
|
160
203
|
|
|
161
|
-
|
|
162
|
-
|
|
204
|
+
Requirements:
|
|
205
|
+
1. Fix unclear sections
|
|
206
|
+
2. Add missing important sections
|
|
207
|
+
3. Improve code examples to be more practical
|
|
208
|
+
4. Make installation more clear
|
|
209
|
+
5. Enhance usage examples with real code
|
|
210
|
+
6. Add API documentation if missing
|
|
211
|
+
7. Improve structure and readability
|
|
212
|
+
8. Keep existing good content
|
|
213
|
+
9. Add project structure visualization if missing
|
|
214
|
+
|
|
215
|
+
EXISTING README:
|
|
216
|
+
${projectData.existingReadme || 'No existing README'}
|
|
217
|
+
|
|
218
|
+
Project Data:
|
|
219
|
+
${JSON.stringify(projectData, null, 2)}
|
|
220
|
+
|
|
221
|
+
Return ONLY improved README.md markdown.`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function buildImproveContributingPrompt(projectData: Record<string, unknown>): string {
|
|
225
|
+
return `Improve the existing CONTRIBUTING.md for this project.
|
|
226
|
+
|
|
227
|
+
Requirements:
|
|
228
|
+
1. Make contribution process clearer
|
|
229
|
+
2. Add missing guidelines
|
|
230
|
+
3. Improve development setup instructions
|
|
231
|
+
4. Add testing requirements
|
|
232
|
+
5. Update for current project state
|
|
233
|
+
|
|
234
|
+
EXISTING CONTRIBUTING:
|
|
235
|
+
${projectData.existingContributing || 'No existing CONTRIBUTING.md'}
|
|
236
|
+
|
|
237
|
+
Project Data:
|
|
238
|
+
${JSON.stringify(projectData, null, 2)}
|
|
239
|
+
|
|
240
|
+
Return ONLY improved CONTRIBUTING.md markdown.`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function buildImproveLicensePrompt(projectData: Record<string, unknown>): string {
|
|
244
|
+
return `Review and improve the LICENSE if needed.
|
|
245
|
+
|
|
246
|
+
Requirements:
|
|
247
|
+
1. Ensure correct copyright year
|
|
248
|
+
2. Verify project name is correct
|
|
249
|
+
3. Add any missing clauses
|
|
250
|
+
|
|
251
|
+
EXISTING LICENSE:
|
|
252
|
+
${projectData.existingLicense || 'No existing LICENSE'}
|
|
163
253
|
|
|
164
254
|
Project Data:
|
|
165
255
|
${JSON.stringify(projectData, null, 2)}
|
|
166
256
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
257
|
+
Return ONLY complete LICENSE file content.`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function buildImproveSecurityPrompt(projectData: Record<string, unknown>): string {
|
|
261
|
+
return `Improve the existing SECURITY.md for this project.
|
|
262
|
+
|
|
263
|
+
Requirements:
|
|
264
|
+
1. Make reporting process clearer
|
|
265
|
+
2. Add missing security information
|
|
266
|
+
3. Update contact info if needed
|
|
267
|
+
4. Improve response timeline clarity
|
|
268
|
+
|
|
269
|
+
EXISTING SECURITY:
|
|
270
|
+
${projectData.existingSecurity || 'No existing SECURITY.md'}
|
|
172
271
|
|
|
173
|
-
|
|
272
|
+
Project Data:
|
|
273
|
+
${JSON.stringify(projectData, null, 2)}
|
|
274
|
+
|
|
275
|
+
Return ONLY improved SECURITY.md markdown.`;
|
|
174
276
|
}
|
|
175
277
|
|
|
176
278
|
function buildExplainPrompt(projectData: Record<string, unknown>): string {
|
|
177
|
-
return `Explain this project in simple terms for developers.
|
|
279
|
+
return `Explain this project in simple, practical terms for developers.
|
|
280
|
+
|
|
281
|
+
Requirements:
|
|
282
|
+
1. What the project does (one sentence)
|
|
283
|
+
2. Who it's for
|
|
284
|
+
3. Main features (top 3-5)
|
|
285
|
+
4. How to use it (quick start)
|
|
286
|
+
5. Why someone would use it
|
|
287
|
+
6. Tech stack briefly
|
|
288
|
+
|
|
289
|
+
Be conversational but professional. No markdown.
|
|
178
290
|
|
|
179
291
|
Project Data:
|
|
180
292
|
${JSON.stringify(projectData, null, 2)}
|
|
181
293
|
|
|
182
|
-
Rules:
|
|
183
|
-
- Be concise
|
|
184
|
-
- Explain what the project does
|
|
185
|
-
- Explain how to use it
|
|
186
|
-
- Mention key features
|
|
187
|
-
- Keep it conversational
|
|
188
|
-
|
|
189
294
|
Return as plain text explanation.`;
|
|
190
295
|
}
|
|
191
296
|
|
|
@@ -198,7 +303,7 @@ async function makeRequest(apiKey: string, userPrompt: string): Promise<string>
|
|
|
198
303
|
{ role: 'system', content: SYSTEM_PROMPT },
|
|
199
304
|
{ role: 'user', content: userPrompt }
|
|
200
305
|
],
|
|
201
|
-
temperature: 0.
|
|
306
|
+
temperature: 0.5,
|
|
202
307
|
max_tokens: 8192
|
|
203
308
|
},
|
|
204
309
|
{
|
|
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import { loadApiKey } from '../../core/config.js';
|
|
5
|
-
import { generateDocs } from '../../services/ai.js';
|
|
5
|
+
import { generateDocs, GeneratedDocs } from '../../services/ai.js';
|
|
6
6
|
import { analyzeProject, summarizeProject } from '../../services/analyzer.js';
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
8
|
import path from 'path';
|
|
@@ -13,8 +13,8 @@ interface GeneratorProps {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const titles = {
|
|
16
|
-
generate: 'Generate
|
|
17
|
-
improve: 'Improve
|
|
16
|
+
generate: 'Generate Documentation',
|
|
17
|
+
improve: 'Improve Documentation',
|
|
18
18
|
explain: 'Explain Project',
|
|
19
19
|
};
|
|
20
20
|
|
|
@@ -64,16 +64,34 @@ export default function Generator({ mode, onBack }: GeneratorProps) {
|
|
|
64
64
|
setStatus('generating');
|
|
65
65
|
spinner.text = 'Generating documentation...';
|
|
66
66
|
|
|
67
|
-
const docResult = await generateDocs(summary as unknown as Record<string, unknown>, mode);
|
|
67
|
+
const docResult = await generateDocs(summary as unknown as Record<string, unknown>, mode) as unknown as GeneratedDocs;
|
|
68
68
|
|
|
69
|
-
if (mode === 'generate') {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
if (mode === 'generate' || mode === 'improve') {
|
|
70
|
+
const files: string[] = [];
|
|
71
|
+
|
|
72
|
+
if (docResult.content) {
|
|
73
|
+
await fs.writeFile(path.join(projectPath, 'README.md'), docResult.content);
|
|
74
|
+
files.push('README.md');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (docResult.contributing) {
|
|
78
|
+
await fs.writeFile(path.join(projectPath, 'CONTRIBUTING.md'), docResult.contributing);
|
|
79
|
+
files.push('CONTRIBUTING.md');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (docResult.license) {
|
|
83
|
+
await fs.writeFile(path.join(projectPath, 'LICENSE'), docResult.license);
|
|
84
|
+
files.push('LICENSE');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (docResult.security) {
|
|
88
|
+
await fs.writeFile(path.join(projectPath, 'SECURITY.md'), docResult.security);
|
|
89
|
+
files.push('SECURITY.md');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
setResult(`${files.join(', ')} ${files.length === 1 ? 'created' : 'created'} successfully!`);
|
|
73
93
|
} else if (mode === 'explain') {
|
|
74
|
-
setResult(docResult.content);
|
|
75
|
-
} else {
|
|
76
|
-
setResult('Documentation improved!');
|
|
94
|
+
setResult(docResult.content as string);
|
|
77
95
|
}
|
|
78
96
|
|
|
79
97
|
spinner.succeed('Done!');
|
|
@@ -94,7 +112,7 @@ export default function Generator({ mode, onBack }: GeneratorProps) {
|
|
|
94
112
|
{status === 'checking' && <Text>Checking API key...</Text>}
|
|
95
113
|
{status === 'scanning' && <Text>Scanning project...</Text>}
|
|
96
114
|
{status === 'analyzing' && <Text>Analyzing project...</Text>}
|
|
97
|
-
{status === 'generating' && <Text>Generating documentation...</Text>}
|
|
115
|
+
{status === 'generating' && <Text>Generating documentation (README, CONTRIBUTING, LICENSE, SECURITY)...</Text>}
|
|
98
116
|
|
|
99
117
|
{status === 'done' && (
|
|
100
118
|
<>
|
|
@@ -12,8 +12,8 @@ interface MenuProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const menuItems: MenuItem[] = [
|
|
15
|
-
{ key: 'g', label: 'Generate
|
|
16
|
-
{ key: 'i', label: 'Improve
|
|
15
|
+
{ key: 'g', label: 'Generate Docs', desc: 'Create README, CONTRIBUTING, LICENSE, SECURITY' },
|
|
16
|
+
{ key: 'i', label: 'Improve Docs', desc: 'Enhance existing documentation' },
|
|
17
17
|
{ key: 'e', label: 'Explain Project', desc: 'Terminal explanation' },
|
|
18
18
|
{ key: 's', label: 'Settings', desc: 'Configure API key' },
|
|
19
19
|
{ key: 'h', label: 'Help', desc: 'Usage guide' },
|
|
@@ -41,14 +41,9 @@ export default function Menu({ onSelect }: MenuProps) {
|
|
|
41
41
|
return (
|
|
42
42
|
<Box flexDirection="column" padding={1}>
|
|
43
43
|
<Text bold color="cyan">
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
██║ ███╗██████╔╝██████╔╝██║ ██║██║ █████╗ ███████╗
|
|
48
|
-
██║ ██║██╔══██╗██╔══██╗██║ ██║██║ ██╔══╝ ╚════██║
|
|
49
|
-
╚██████╔╝██║ ██║██║ ██║╚██████╔╝███████╗███████╗███████║
|
|
50
|
-
╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝
|
|
51
|
-
|
|
44
|
+
.-. . . .-. .-. .-. . . . .-. .-. .-. .-.
|
|
45
|
+
`-. |-| |-| | ) | | | | | | ) | | | `-.
|
|
46
|
+
`-' ' ` ` ' `-' `-' `.'.' `-' `-' `-' `-'
|
|
52
47
|
</Text>
|
|
53
48
|
|
|
54
49
|
<Text dimColor>AI-Powered Documentation Generator</Text>
|
|
@@ -75,7 +70,7 @@ export default function Menu({ onSelect }: MenuProps) {
|
|
|
75
70
|
|
|
76
71
|
<Text>{"\n"}</Text>
|
|
77
72
|
<Text dimColor>Use w/s or arrow keys to navigate, Enter or key to select, q to quit</Text>
|
|
78
|
-
<Text dimColor>Version 2.1.
|
|
73
|
+
<Text dimColor>Version 2.1.6</Text>
|
|
79
74
|
</Box>
|
|
80
75
|
);
|
|
81
76
|
}
|