skrypt-ai 0.1.0
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/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/autofix/index.d.ts +46 -0
- package/dist/autofix/index.js +240 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +40 -0
- package/dist/commands/autofix.d.ts +2 -0
- package/dist/commands/autofix.js +143 -0
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.js +320 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +56 -0
- package/dist/commands/review-pr.d.ts +2 -0
- package/dist/commands/review-pr.js +117 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +142 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +2 -0
- package/dist/config/loader.d.ts +9 -0
- package/dist/config/loader.js +82 -0
- package/dist/config/types.d.ts +24 -0
- package/dist/config/types.js +34 -0
- package/dist/generator/generator.d.ts +15 -0
- package/dist/generator/generator.js +144 -0
- package/dist/generator/index.d.ts +4 -0
- package/dist/generator/index.js +4 -0
- package/dist/generator/organizer.d.ts +29 -0
- package/dist/generator/organizer.js +222 -0
- package/dist/generator/types.d.ts +83 -0
- package/dist/generator/types.js +1 -0
- package/dist/generator/writer.d.ts +28 -0
- package/dist/generator/writer.js +320 -0
- package/dist/github/pr-comments.d.ts +40 -0
- package/dist/github/pr-comments.js +308 -0
- package/dist/llm/anthropic-client.d.ts +16 -0
- package/dist/llm/anthropic-client.js +92 -0
- package/dist/llm/index.d.ts +53 -0
- package/dist/llm/index.js +400 -0
- package/dist/llm/llm.manual-test.d.ts +1 -0
- package/dist/llm/llm.manual-test.js +112 -0
- package/dist/llm/llm.mock-test.d.ts +4 -0
- package/dist/llm/llm.mock-test.js +79 -0
- package/dist/llm/openai-client.d.ts +17 -0
- package/dist/llm/openai-client.js +90 -0
- package/dist/llm/types.d.ts +60 -0
- package/dist/llm/types.js +20 -0
- package/dist/scanner/content-type.d.ts +39 -0
- package/dist/scanner/content-type.js +194 -0
- package/dist/scanner/content-type.test.d.ts +1 -0
- package/dist/scanner/content-type.test.js +231 -0
- package/dist/scanner/go.d.ts +20 -0
- package/dist/scanner/go.js +269 -0
- package/dist/scanner/index.d.ts +21 -0
- package/dist/scanner/index.js +137 -0
- package/dist/scanner/python.d.ts +6 -0
- package/dist/scanner/python.js +57 -0
- package/dist/scanner/python_parser.py +230 -0
- package/dist/scanner/rust.d.ts +23 -0
- package/dist/scanner/rust.js +304 -0
- package/dist/scanner/scanner.test.d.ts +1 -0
- package/dist/scanner/scanner.test.js +210 -0
- package/dist/scanner/types.d.ts +50 -0
- package/dist/scanner/types.js +1 -0
- package/dist/scanner/typescript.d.ts +34 -0
- package/dist/scanner/typescript.js +327 -0
- package/dist/scanner/typescript.manual-test.d.ts +1 -0
- package/dist/scanner/typescript.manual-test.js +112 -0
- package/dist/template/docs.json +32 -0
- package/dist/template/mdx-components.tsx +62 -0
- package/dist/template/next-env.d.ts +6 -0
- package/dist/template/next.config.mjs +17 -0
- package/dist/template/package.json +39 -0
- package/dist/template/postcss.config.mjs +5 -0
- package/dist/template/public/search-index.json +1 -0
- package/dist/template/scripts/build-search-index.mjs +120 -0
- package/dist/template/src/app/api/mock/[...path]/route.ts +224 -0
- package/dist/template/src/app/api/openapi/route.ts +48 -0
- package/dist/template/src/app/api/rate-limit/route.ts +84 -0
- package/dist/template/src/app/docs/[...slug]/page.tsx +81 -0
- package/dist/template/src/app/docs/layout.tsx +9 -0
- package/dist/template/src/app/docs/page.mdx +67 -0
- package/dist/template/src/app/error.tsx +63 -0
- package/dist/template/src/app/layout.tsx +71 -0
- package/dist/template/src/app/page.tsx +18 -0
- package/dist/template/src/app/reference/route.ts +36 -0
- package/dist/template/src/app/robots.ts +14 -0
- package/dist/template/src/app/sitemap.ts +64 -0
- package/dist/template/src/components/breadcrumbs.tsx +41 -0
- package/dist/template/src/components/copy-button.tsx +29 -0
- package/dist/template/src/components/docs-layout.tsx +35 -0
- package/dist/template/src/components/edit-link.tsx +39 -0
- package/dist/template/src/components/feedback.tsx +52 -0
- package/dist/template/src/components/header.tsx +66 -0
- package/dist/template/src/components/mdx/accordion.tsx +48 -0
- package/dist/template/src/components/mdx/api-badge.tsx +57 -0
- package/dist/template/src/components/mdx/callout.tsx +111 -0
- package/dist/template/src/components/mdx/card.tsx +62 -0
- package/dist/template/src/components/mdx/changelog.tsx +57 -0
- package/dist/template/src/components/mdx/code-block.tsx +42 -0
- package/dist/template/src/components/mdx/code-group.tsx +125 -0
- package/dist/template/src/components/mdx/code-playground.tsx +322 -0
- package/dist/template/src/components/mdx/go-playground.tsx +235 -0
- package/dist/template/src/components/mdx/heading.tsx +37 -0
- package/dist/template/src/components/mdx/highlighted-code.tsx +89 -0
- package/dist/template/src/components/mdx/index.tsx +15 -0
- package/dist/template/src/components/mdx/param-table.tsx +71 -0
- package/dist/template/src/components/mdx/python-playground.tsx +293 -0
- package/dist/template/src/components/mdx/steps.tsx +43 -0
- package/dist/template/src/components/mdx/tabs.tsx +81 -0
- package/dist/template/src/components/rate-limit-display.tsx +183 -0
- package/dist/template/src/components/search-dialog.tsx +178 -0
- package/dist/template/src/components/sidebar.tsx +129 -0
- package/dist/template/src/components/syntax-theme-selector.tsx +50 -0
- package/dist/template/src/components/table-of-contents.tsx +84 -0
- package/dist/template/src/components/theme-toggle.tsx +46 -0
- package/dist/template/src/components/version-selector.tsx +61 -0
- package/dist/template/src/contexts/syntax-theme.tsx +52 -0
- package/dist/template/src/lib/highlight.ts +83 -0
- package/dist/template/src/lib/search-types.ts +37 -0
- package/dist/template/src/lib/search.ts +125 -0
- package/dist/template/src/lib/utils.ts +6 -0
- package/dist/template/src/styles/globals.css +152 -0
- package/dist/template/tsconfig.json +25 -0
- package/dist/template/tsconfig.tsbuildinfo +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock tests for LLM client - tests structure without API calls
|
|
3
|
+
*/
|
|
4
|
+
import { createLLMClient, PROVIDER_BASE_URLS } from './index.js';
|
|
5
|
+
function runMockTests() {
|
|
6
|
+
console.log('=== LLM Client Mock Tests ===\n');
|
|
7
|
+
// Test 1: Client creation for each provider
|
|
8
|
+
console.log('Test 1: Create client for each provider');
|
|
9
|
+
const providers = ['deepseek', 'openai', 'anthropic', 'google', 'ollama', 'openrouter'];
|
|
10
|
+
for (const provider of providers) {
|
|
11
|
+
try {
|
|
12
|
+
// Create client to verify no errors thrown
|
|
13
|
+
createLLMClient({
|
|
14
|
+
provider,
|
|
15
|
+
model: 'test-model'
|
|
16
|
+
});
|
|
17
|
+
console.log(` ✓ ${provider}: client created`);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
console.log(` ✗ ${provider}: ${err}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
console.log('');
|
|
25
|
+
// Test 2: Verify base URLs
|
|
26
|
+
console.log('Test 2: Verify provider base URLs');
|
|
27
|
+
const expectedUrls = {
|
|
28
|
+
deepseek: 'https://api.deepseek.com/v1',
|
|
29
|
+
openai: 'https://api.openai.com/v1',
|
|
30
|
+
anthropic: 'https://api.anthropic.com',
|
|
31
|
+
google: 'https://generativelanguage.googleapis.com/v1beta/openai',
|
|
32
|
+
ollama: 'http://localhost:11434/v1',
|
|
33
|
+
openrouter: 'https://openrouter.ai/api/v1'
|
|
34
|
+
};
|
|
35
|
+
for (const [provider, expectedUrl] of Object.entries(expectedUrls)) {
|
|
36
|
+
const actualUrl = PROVIDER_BASE_URLS[provider];
|
|
37
|
+
if (actualUrl === expectedUrl) {
|
|
38
|
+
console.log(` ✓ ${provider}: ${actualUrl}`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log(` ✗ ${provider}: expected ${expectedUrl}, got ${actualUrl}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
console.log('');
|
|
46
|
+
// Test 3: Anthropic vs OpenAI-compatible client selection
|
|
47
|
+
console.log('Test 3: Client type selection');
|
|
48
|
+
const anthropicClient = createLLMClient({ provider: 'anthropic', model: 'claude-3' });
|
|
49
|
+
const openaiClient = createLLMClient({ provider: 'openai', model: 'gpt-4' });
|
|
50
|
+
const deepseekClient = createLLMClient({ provider: 'deepseek', model: 'deepseek-v3' });
|
|
51
|
+
// Check they're different implementations for anthropic vs others
|
|
52
|
+
const anthropicType = anthropicClient.constructor.name;
|
|
53
|
+
const openaiType = openaiClient.constructor.name;
|
|
54
|
+
const deepseekType = deepseekClient.constructor.name;
|
|
55
|
+
console.log(` anthropic client: ${anthropicType}`);
|
|
56
|
+
console.log(` openai client: ${openaiType}`);
|
|
57
|
+
console.log(` deepseek client: ${deepseekType}`);
|
|
58
|
+
if (anthropicType !== openaiType) {
|
|
59
|
+
console.log(' ✓ anthropic uses different client than openai');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log(' ✗ anthropic should use different client');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
if (openaiType === deepseekType) {
|
|
66
|
+
console.log(' ✓ deepseek uses same client as openai (OpenAI-compatible)');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.log(' ✗ deepseek should use same client as openai');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
console.log('');
|
|
73
|
+
console.log('✓ All mock tests passed\n');
|
|
74
|
+
console.log('To run real API tests, set an API key and run:');
|
|
75
|
+
console.log(' DEEPSEEK_API_KEY=your-key npx tsx src/llm/llm.test.ts');
|
|
76
|
+
console.log(' ANTHROPIC_API_KEY=your-key npx tsx src/llm/llm.test.ts');
|
|
77
|
+
console.log(' Or start Ollama locally');
|
|
78
|
+
}
|
|
79
|
+
runMockTests();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LLMClient, LLMClientConfig, CompletionRequest, CompletionResponse } from './types.js';
|
|
2
|
+
import { LLMProvider } from '../config/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI-compatible client
|
|
5
|
+
* Works with: OpenAI, DeepSeek, Ollama, OpenRouter, Google Gemini
|
|
6
|
+
*/
|
|
7
|
+
export declare class OpenAICompatibleClient implements LLMClient {
|
|
8
|
+
provider: LLMProvider;
|
|
9
|
+
private client;
|
|
10
|
+
private model;
|
|
11
|
+
private maxRetries;
|
|
12
|
+
constructor(config: LLMClientConfig);
|
|
13
|
+
isConfigured(): boolean;
|
|
14
|
+
complete(request: CompletionRequest): Promise<CompletionResponse>;
|
|
15
|
+
private mapFinishReason;
|
|
16
|
+
private handleError;
|
|
17
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { PROVIDER_BASE_URLS, PROVIDER_EXTRA_HEADERS } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI-compatible client
|
|
5
|
+
* Works with: OpenAI, DeepSeek, Ollama, OpenRouter, Google Gemini
|
|
6
|
+
*/
|
|
7
|
+
export class OpenAICompatibleClient {
|
|
8
|
+
provider;
|
|
9
|
+
client;
|
|
10
|
+
model;
|
|
11
|
+
maxRetries;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.provider = config.provider;
|
|
14
|
+
this.model = config.model;
|
|
15
|
+
this.maxRetries = config.maxRetries ?? 3;
|
|
16
|
+
const baseURL = config.baseUrl || PROVIDER_BASE_URLS[config.provider];
|
|
17
|
+
const extraHeaders = PROVIDER_EXTRA_HEADERS[config.provider] || {};
|
|
18
|
+
this.client = new OpenAI({
|
|
19
|
+
apiKey: config.apiKey || 'ollama', // Ollama doesn't need a real key
|
|
20
|
+
baseURL,
|
|
21
|
+
timeout: config.timeout ?? 60000,
|
|
22
|
+
maxRetries: this.maxRetries,
|
|
23
|
+
defaultHeaders: extraHeaders
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
isConfigured() {
|
|
27
|
+
return true; // OpenAI SDK handles validation
|
|
28
|
+
}
|
|
29
|
+
async complete(request) {
|
|
30
|
+
const model = request.model || this.model;
|
|
31
|
+
try {
|
|
32
|
+
const response = await this.client.chat.completions.create({
|
|
33
|
+
model,
|
|
34
|
+
messages: request.messages.map(m => ({
|
|
35
|
+
role: m.role,
|
|
36
|
+
content: m.content
|
|
37
|
+
})),
|
|
38
|
+
temperature: request.temperature ?? 0,
|
|
39
|
+
max_tokens: request.maxTokens ?? 4096
|
|
40
|
+
});
|
|
41
|
+
const choice = response.choices[0];
|
|
42
|
+
const content = choice?.message?.content || '';
|
|
43
|
+
return {
|
|
44
|
+
content,
|
|
45
|
+
model: response.model,
|
|
46
|
+
usage: {
|
|
47
|
+
inputTokens: response.usage?.prompt_tokens ?? 0,
|
|
48
|
+
outputTokens: response.usage?.completion_tokens ?? 0,
|
|
49
|
+
totalTokens: response.usage?.total_tokens ?? 0
|
|
50
|
+
},
|
|
51
|
+
finishReason: this.mapFinishReason(choice?.finish_reason)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
throw this.handleError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
mapFinishReason(reason) {
|
|
59
|
+
switch (reason) {
|
|
60
|
+
case 'stop':
|
|
61
|
+
case 'end_turn':
|
|
62
|
+
return 'stop';
|
|
63
|
+
case 'length':
|
|
64
|
+
case 'max_tokens':
|
|
65
|
+
return 'length';
|
|
66
|
+
default:
|
|
67
|
+
return 'error';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
handleError(error) {
|
|
71
|
+
if (error instanceof OpenAI.APIError) {
|
|
72
|
+
const status = error.status;
|
|
73
|
+
const message = error.message;
|
|
74
|
+
if (status === 401) {
|
|
75
|
+
return new Error(`Authentication failed for ${this.provider}: Invalid API key`);
|
|
76
|
+
}
|
|
77
|
+
if (status === 429) {
|
|
78
|
+
return new Error(`Rate limited by ${this.provider}: ${message}`);
|
|
79
|
+
}
|
|
80
|
+
if (status === 500 || status === 502 || status === 503) {
|
|
81
|
+
return new Error(`${this.provider} service error: ${message}`);
|
|
82
|
+
}
|
|
83
|
+
return new Error(`${this.provider} API error (${status}): ${message}`);
|
|
84
|
+
}
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
return error;
|
|
87
|
+
}
|
|
88
|
+
return new Error(`Unknown error from ${this.provider}: ${String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LLMProvider } from '../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Message in a conversation
|
|
4
|
+
*/
|
|
5
|
+
export interface Message {
|
|
6
|
+
role: 'system' | 'user' | 'assistant';
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Request to generate a completion
|
|
11
|
+
*/
|
|
12
|
+
export interface CompletionRequest {
|
|
13
|
+
messages: Message[];
|
|
14
|
+
model?: string;
|
|
15
|
+
temperature?: number;
|
|
16
|
+
maxTokens?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Response from a completion request
|
|
20
|
+
*/
|
|
21
|
+
export interface CompletionResponse {
|
|
22
|
+
content: string;
|
|
23
|
+
model: string;
|
|
24
|
+
usage: {
|
|
25
|
+
inputTokens: number;
|
|
26
|
+
outputTokens: number;
|
|
27
|
+
totalTokens: number;
|
|
28
|
+
};
|
|
29
|
+
finishReason: 'stop' | 'length' | 'error';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* LLM client configuration
|
|
33
|
+
*/
|
|
34
|
+
export interface LLMClientConfig {
|
|
35
|
+
provider: LLMProvider;
|
|
36
|
+
model: string;
|
|
37
|
+
apiKey: string;
|
|
38
|
+
baseUrl?: string;
|
|
39
|
+
timeout?: number;
|
|
40
|
+
maxRetries?: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* LLM client interface
|
|
44
|
+
*/
|
|
45
|
+
export interface LLMClient {
|
|
46
|
+
/** The provider this client uses */
|
|
47
|
+
provider: LLMProvider;
|
|
48
|
+
/** Generate a completion */
|
|
49
|
+
complete(request: CompletionRequest): Promise<CompletionResponse>;
|
|
50
|
+
/** Check if the client is properly configured */
|
|
51
|
+
isConfigured(): boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Provider base URLs
|
|
55
|
+
*/
|
|
56
|
+
export declare const PROVIDER_BASE_URLS: Record<LLMProvider, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Extra headers needed per provider
|
|
59
|
+
*/
|
|
60
|
+
export declare const PROVIDER_EXTRA_HEADERS: Partial<Record<LLMProvider, Record<string, string>>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider base URLs
|
|
3
|
+
*/
|
|
4
|
+
export const PROVIDER_BASE_URLS = {
|
|
5
|
+
deepseek: 'https://api.deepseek.com/v1',
|
|
6
|
+
openai: 'https://api.openai.com/v1',
|
|
7
|
+
anthropic: 'https://api.anthropic.com',
|
|
8
|
+
google: 'https://generativelanguage.googleapis.com/v1beta/openai',
|
|
9
|
+
ollama: 'http://localhost:11434/v1',
|
|
10
|
+
openrouter: 'https://openrouter.ai/api/v1'
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Extra headers needed per provider
|
|
14
|
+
*/
|
|
15
|
+
export const PROVIDER_EXTRA_HEADERS = {
|
|
16
|
+
openrouter: {
|
|
17
|
+
'HTTP-Referer': 'https://github.com/debgotwired/skrypt',
|
|
18
|
+
'X-Title': 'skrypt'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { APIElement } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Content type detection for documentation
|
|
4
|
+
* Determines if code should be documented as API reference, guide, or tutorial
|
|
5
|
+
*/
|
|
6
|
+
export type ContentType = 'api' | 'guide' | 'tutorial' | 'overview';
|
|
7
|
+
export interface ContentClassification {
|
|
8
|
+
type: ContentType;
|
|
9
|
+
confidence: number;
|
|
10
|
+
reasons: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Classify what type of documentation an API element needs
|
|
14
|
+
*/
|
|
15
|
+
export declare function classifyElement(element: APIElement): ContentClassification;
|
|
16
|
+
/**
|
|
17
|
+
* Batch classify elements and group by content type
|
|
18
|
+
*/
|
|
19
|
+
export declare function classifyElements(elements: APIElement[]): Map<ContentType, APIElement[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Get recommended documentation structure for a set of elements
|
|
22
|
+
*/
|
|
23
|
+
export declare function getRecommendedStructure(elements: APIElement[]): {
|
|
24
|
+
sections: {
|
|
25
|
+
name: string;
|
|
26
|
+
type: ContentType;
|
|
27
|
+
elements: APIElement[];
|
|
28
|
+
}[];
|
|
29
|
+
stats: {
|
|
30
|
+
api: number;
|
|
31
|
+
guide: number;
|
|
32
|
+
tutorial: number;
|
|
33
|
+
overview: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Generate documentation prompt based on content type
|
|
38
|
+
*/
|
|
39
|
+
export declare function getPromptForContentType(type: ContentType): string;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify what type of documentation an API element needs
|
|
3
|
+
*/
|
|
4
|
+
export function classifyElement(element) {
|
|
5
|
+
const reasons = [];
|
|
6
|
+
let apiScore = 0;
|
|
7
|
+
let guideScore = 0;
|
|
8
|
+
let tutorialScore = 0;
|
|
9
|
+
// API Reference indicators
|
|
10
|
+
if (element.parameters.length >= 3) {
|
|
11
|
+
apiScore += 2;
|
|
12
|
+
reasons.push('Multiple parameters suggest API reference');
|
|
13
|
+
}
|
|
14
|
+
if (element.returnType && element.returnType.length > 10) {
|
|
15
|
+
apiScore += 1;
|
|
16
|
+
reasons.push('Complex return type');
|
|
17
|
+
}
|
|
18
|
+
if (element.kind === 'method' && element.parentClass) {
|
|
19
|
+
apiScore += 1;
|
|
20
|
+
reasons.push('Method on a class');
|
|
21
|
+
}
|
|
22
|
+
if (element.signature.includes('async') || element.signature.includes('Promise')) {
|
|
23
|
+
apiScore += 1;
|
|
24
|
+
reasons.push('Async pattern suggests API');
|
|
25
|
+
}
|
|
26
|
+
// Check for HTTP/REST patterns
|
|
27
|
+
const httpPatterns = /\b(GET|POST|PUT|DELETE|PATCH|http|request|response|fetch|axios)\b/i;
|
|
28
|
+
if (httpPatterns.test(element.signature) || httpPatterns.test(element.docstring || '')) {
|
|
29
|
+
apiScore += 3;
|
|
30
|
+
reasons.push('HTTP/REST patterns detected');
|
|
31
|
+
}
|
|
32
|
+
// Check for handler/endpoint patterns - no strict word boundaries for camelCase
|
|
33
|
+
const handlerPatterns = /(handler|endpoint|route|controller|middleware)/i;
|
|
34
|
+
if (handlerPatterns.test(element.name) || handlerPatterns.test(element.filePath)) {
|
|
35
|
+
apiScore += 2;
|
|
36
|
+
reasons.push('Handler/endpoint pattern');
|
|
37
|
+
}
|
|
38
|
+
// Guide indicators - use case-insensitive match without strict word boundaries
|
|
39
|
+
// to handle camelCase names like configureAuth, setupDatabase
|
|
40
|
+
const guidePatterns = /(config|setup|init|configure|options|settings)/i;
|
|
41
|
+
if (guidePatterns.test(element.name)) {
|
|
42
|
+
guideScore += 2;
|
|
43
|
+
reasons.push('Configuration/setup function');
|
|
44
|
+
}
|
|
45
|
+
if (element.docstring && element.docstring.length > 200) {
|
|
46
|
+
guideScore += 1;
|
|
47
|
+
reasons.push('Extensive documentation');
|
|
48
|
+
}
|
|
49
|
+
// Check for integration patterns - no strict word boundaries for camelCase
|
|
50
|
+
const integrationPatterns = /(connect|integrate|provider|client)/i;
|
|
51
|
+
if (integrationPatterns.test(element.name) || integrationPatterns.test(element.docstring || '')) {
|
|
52
|
+
guideScore += 1;
|
|
53
|
+
reasons.push('Integration pattern');
|
|
54
|
+
}
|
|
55
|
+
// Tutorial indicators
|
|
56
|
+
const tutorialPatterns = /\b(example|demo|sample|tutorial|quickstart|getting.?started)\b/i;
|
|
57
|
+
if (tutorialPatterns.test(element.filePath) || tutorialPatterns.test(element.docstring || '')) {
|
|
58
|
+
tutorialScore += 3;
|
|
59
|
+
reasons.push('Example/tutorial pattern in path or docs');
|
|
60
|
+
}
|
|
61
|
+
if (element.name.toLowerCase().includes('example') || element.name.toLowerCase().includes('demo')) {
|
|
62
|
+
tutorialScore += 2;
|
|
63
|
+
reasons.push('Name suggests example');
|
|
64
|
+
}
|
|
65
|
+
// Simple functions with few params = tutorial
|
|
66
|
+
if (element.parameters.length <= 1 && element.kind === 'function') {
|
|
67
|
+
tutorialScore += 1;
|
|
68
|
+
reasons.push('Simple function, good for tutorial');
|
|
69
|
+
}
|
|
70
|
+
// Determine winner
|
|
71
|
+
const maxScore = Math.max(apiScore, guideScore, tutorialScore);
|
|
72
|
+
const totalScore = apiScore + guideScore + tutorialScore;
|
|
73
|
+
if (maxScore === 0) {
|
|
74
|
+
return {
|
|
75
|
+
type: 'overview',
|
|
76
|
+
confidence: 0.5,
|
|
77
|
+
reasons: ['No strong indicators, defaulting to overview']
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
let type;
|
|
81
|
+
if (apiScore === maxScore) {
|
|
82
|
+
type = 'api';
|
|
83
|
+
}
|
|
84
|
+
else if (guideScore === maxScore) {
|
|
85
|
+
type = 'guide';
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
type = 'tutorial';
|
|
89
|
+
}
|
|
90
|
+
const confidence = totalScore > 0 ? maxScore / totalScore : 0.5;
|
|
91
|
+
return { type, confidence, reasons };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Batch classify elements and group by content type
|
|
95
|
+
*/
|
|
96
|
+
export function classifyElements(elements) {
|
|
97
|
+
const groups = new Map([
|
|
98
|
+
['api', []],
|
|
99
|
+
['guide', []],
|
|
100
|
+
['tutorial', []],
|
|
101
|
+
['overview', []]
|
|
102
|
+
]);
|
|
103
|
+
for (const element of elements) {
|
|
104
|
+
const classification = classifyElement(element);
|
|
105
|
+
const group = groups.get(classification.type);
|
|
106
|
+
group.push(element);
|
|
107
|
+
}
|
|
108
|
+
return groups;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get recommended documentation structure for a set of elements
|
|
112
|
+
*/
|
|
113
|
+
export function getRecommendedStructure(elements) {
|
|
114
|
+
const classified = classifyElements(elements);
|
|
115
|
+
const sections = [];
|
|
116
|
+
const stats = { api: 0, guide: 0, tutorial: 0, overview: 0 };
|
|
117
|
+
// API Reference section
|
|
118
|
+
const apiElements = classified.get('api');
|
|
119
|
+
if (apiElements.length > 0) {
|
|
120
|
+
sections.push({
|
|
121
|
+
name: 'API Reference',
|
|
122
|
+
type: 'api',
|
|
123
|
+
elements: apiElements
|
|
124
|
+
});
|
|
125
|
+
stats.api = apiElements.length;
|
|
126
|
+
}
|
|
127
|
+
// Guides section
|
|
128
|
+
const guideElements = classified.get('guide');
|
|
129
|
+
if (guideElements.length > 0) {
|
|
130
|
+
sections.push({
|
|
131
|
+
name: 'Guides',
|
|
132
|
+
type: 'guide',
|
|
133
|
+
elements: guideElements
|
|
134
|
+
});
|
|
135
|
+
stats.guide = guideElements.length;
|
|
136
|
+
}
|
|
137
|
+
// Tutorials section
|
|
138
|
+
const tutorialElements = classified.get('tutorial');
|
|
139
|
+
if (tutorialElements.length > 0) {
|
|
140
|
+
sections.push({
|
|
141
|
+
name: 'Tutorials',
|
|
142
|
+
type: 'tutorial',
|
|
143
|
+
elements: tutorialElements
|
|
144
|
+
});
|
|
145
|
+
stats.tutorial = tutorialElements.length;
|
|
146
|
+
}
|
|
147
|
+
// Overview/Other
|
|
148
|
+
const overviewElements = classified.get('overview');
|
|
149
|
+
if (overviewElements.length > 0) {
|
|
150
|
+
sections.push({
|
|
151
|
+
name: 'Overview',
|
|
152
|
+
type: 'overview',
|
|
153
|
+
elements: overviewElements
|
|
154
|
+
});
|
|
155
|
+
stats.overview = overviewElements.length;
|
|
156
|
+
}
|
|
157
|
+
return { sections, stats };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Generate documentation prompt based on content type
|
|
161
|
+
*/
|
|
162
|
+
export function getPromptForContentType(type) {
|
|
163
|
+
switch (type) {
|
|
164
|
+
case 'api':
|
|
165
|
+
return `Generate detailed API reference documentation. Include:
|
|
166
|
+
- Clear parameter descriptions with types
|
|
167
|
+
- Return value documentation
|
|
168
|
+
- Error cases and edge conditions
|
|
169
|
+
- Code example showing typical usage
|
|
170
|
+
Focus on technical accuracy and completeness.`;
|
|
171
|
+
case 'guide':
|
|
172
|
+
return `Generate a practical guide for this functionality. Include:
|
|
173
|
+
- What problem it solves
|
|
174
|
+
- Step-by-step setup instructions
|
|
175
|
+
- Configuration options explained
|
|
176
|
+
- Best practices and common patterns
|
|
177
|
+
Focus on helping developers integrate this into their projects.`;
|
|
178
|
+
case 'tutorial':
|
|
179
|
+
return `Generate a beginner-friendly tutorial. Include:
|
|
180
|
+
- What you'll learn
|
|
181
|
+
- Prerequisites
|
|
182
|
+
- Step-by-step walkthrough with explanations
|
|
183
|
+
- Complete working example
|
|
184
|
+
- Next steps for learning more
|
|
185
|
+
Focus on teaching concepts through hands-on examples.`;
|
|
186
|
+
case 'overview':
|
|
187
|
+
return `Generate an overview of this functionality. Include:
|
|
188
|
+
- What it does at a high level
|
|
189
|
+
- When to use it
|
|
190
|
+
- Basic example
|
|
191
|
+
- Links to related documentation
|
|
192
|
+
Keep it concise but informative.`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|