skrypt-ai 0.4.2 → 0.6.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/dist/auth/index.d.ts +13 -3
- package/dist/auth/index.js +101 -9
- package/dist/auth/keychain.d.ts +5 -0
- package/dist/auth/keychain.js +82 -0
- package/dist/auth/notices.d.ts +3 -0
- package/dist/auth/notices.js +42 -0
- package/dist/autofix/index.d.ts +0 -4
- package/dist/autofix/index.js +10 -24
- package/dist/capture/browser.d.ts +11 -0
- package/dist/capture/browser.js +173 -0
- package/dist/capture/diff.d.ts +23 -0
- package/dist/capture/diff.js +52 -0
- package/dist/capture/index.d.ts +23 -0
- package/dist/capture/index.js +210 -0
- package/dist/capture/naming.d.ts +17 -0
- package/dist/capture/naming.js +45 -0
- package/dist/capture/parser.d.ts +15 -0
- package/dist/capture/parser.js +80 -0
- package/dist/capture/types.d.ts +57 -0
- package/dist/capture/types.js +1 -0
- package/dist/cli.js +20 -3
- package/dist/commands/autofix.js +136 -120
- package/dist/commands/cron.js +58 -47
- package/dist/commands/deploy.js +123 -102
- package/dist/commands/generate.js +125 -7
- package/dist/commands/heal.d.ts +10 -0
- package/dist/commands/heal.js +201 -0
- package/dist/commands/i18n.js +146 -111
- package/dist/commands/import.d.ts +2 -0
- package/dist/commands/import.js +157 -0
- package/dist/commands/init.js +19 -7
- package/dist/commands/lint.js +50 -44
- package/dist/commands/llms-txt.js +59 -49
- package/dist/commands/login.js +63 -34
- package/dist/commands/mcp.js +6 -0
- package/dist/commands/monitor.js +13 -8
- package/dist/commands/qa.d.ts +2 -0
- package/dist/commands/qa.js +43 -0
- package/dist/commands/review-pr.js +108 -92
- package/dist/commands/sdk.js +128 -122
- package/dist/commands/security.d.ts +2 -0
- package/dist/commands/security.js +109 -0
- package/dist/commands/test.js +91 -92
- package/dist/commands/version.js +104 -75
- package/dist/commands/watch.js +130 -114
- package/dist/config/types.js +2 -2
- package/dist/context-hub/index.d.ts +23 -0
- package/dist/context-hub/index.js +179 -0
- package/dist/context-hub/mappings.d.ts +8 -0
- package/dist/context-hub/mappings.js +55 -0
- package/dist/context-hub/types.d.ts +33 -0
- package/dist/context-hub/types.js +1 -0
- package/dist/generator/generator.js +39 -6
- package/dist/generator/types.d.ts +7 -0
- package/dist/generator/writer.d.ts +3 -1
- package/dist/generator/writer.js +36 -7
- package/dist/importers/confluence.d.ts +5 -0
- package/dist/importers/confluence.js +137 -0
- package/dist/importers/detect.d.ts +20 -0
- package/dist/importers/detect.js +121 -0
- package/dist/importers/docusaurus.d.ts +5 -0
- package/dist/importers/docusaurus.js +279 -0
- package/dist/importers/gitbook.d.ts +5 -0
- package/dist/importers/gitbook.js +189 -0
- package/dist/importers/github.d.ts +8 -0
- package/dist/importers/github.js +99 -0
- package/dist/importers/index.d.ts +15 -0
- package/dist/importers/index.js +30 -0
- package/dist/importers/markdown.d.ts +6 -0
- package/dist/importers/markdown.js +105 -0
- package/dist/importers/mintlify.d.ts +5 -0
- package/dist/importers/mintlify.js +172 -0
- package/dist/importers/notion.d.ts +5 -0
- package/dist/importers/notion.js +174 -0
- package/dist/importers/readme.d.ts +5 -0
- package/dist/importers/readme.js +184 -0
- package/dist/importers/transform.d.ts +90 -0
- package/dist/importers/transform.js +457 -0
- package/dist/importers/types.d.ts +37 -0
- package/dist/importers/types.js +1 -0
- package/dist/llm/anthropic-client.d.ts +1 -0
- package/dist/llm/anthropic-client.js +3 -1
- package/dist/llm/index.d.ts +6 -4
- package/dist/llm/index.js +76 -261
- package/dist/llm/openai-client.d.ts +1 -0
- package/dist/llm/openai-client.js +7 -2
- package/dist/plugins/index.js +7 -0
- package/dist/qa/checks.d.ts +10 -0
- package/dist/qa/checks.js +492 -0
- package/dist/qa/fixes.d.ts +30 -0
- package/dist/qa/fixes.js +277 -0
- package/dist/qa/index.d.ts +29 -0
- package/dist/qa/index.js +187 -0
- package/dist/qa/types.d.ts +24 -0
- package/dist/qa/types.js +1 -0
- package/dist/scanner/csharp.d.ts +23 -0
- package/dist/scanner/csharp.js +421 -0
- package/dist/scanner/index.js +53 -26
- package/dist/scanner/java.d.ts +39 -0
- package/dist/scanner/java.js +318 -0
- package/dist/scanner/kotlin.d.ts +23 -0
- package/dist/scanner/kotlin.js +389 -0
- package/dist/scanner/php.d.ts +57 -0
- package/dist/scanner/php.js +351 -0
- package/dist/scanner/python.js +17 -0
- package/dist/scanner/ruby.d.ts +36 -0
- package/dist/scanner/ruby.js +431 -0
- package/dist/scanner/swift.d.ts +25 -0
- package/dist/scanner/swift.js +392 -0
- package/dist/scanner/types.d.ts +1 -1
- package/dist/template/content/docs/_navigation.json +46 -0
- package/dist/template/content/docs/_sidebars.json +684 -0
- package/dist/template/content/docs/core.md +4544 -0
- package/dist/template/content/docs/index.mdx +89 -0
- package/dist/template/content/docs/integrations.md +1158 -0
- package/dist/template/content/docs/llms-full.md +403 -0
- package/dist/template/content/docs/llms.txt +4588 -0
- package/dist/template/content/docs/other.md +10379 -0
- package/dist/template/content/docs/tools.md +746 -0
- package/dist/template/content/docs/types.md +531 -0
- package/dist/template/docs.json +13 -11
- package/dist/template/mdx-components.tsx +27 -2
- package/dist/template/package.json +6 -0
- package/dist/template/public/search-index.json +1 -1
- package/dist/template/scripts/build-search-index.mjs +149 -13
- package/dist/template/src/app/api/chat/route.ts +83 -128
- package/dist/template/src/app/docs/[...slug]/page.tsx +75 -20
- package/dist/template/src/app/docs/llms-full.md +151 -4
- package/dist/template/src/app/docs/llms.txt +2464 -847
- package/dist/template/src/app/docs/page.mdx +48 -38
- package/dist/template/src/app/layout.tsx +3 -1
- package/dist/template/src/app/page.tsx +22 -8
- package/dist/template/src/components/ai-chat.tsx +73 -64
- package/dist/template/src/components/breadcrumbs.tsx +21 -23
- package/dist/template/src/components/copy-button.tsx +13 -9
- package/dist/template/src/components/copy-page-button.tsx +54 -0
- package/dist/template/src/components/docs-layout.tsx +37 -25
- package/dist/template/src/components/header.tsx +51 -10
- package/dist/template/src/components/mdx/card.tsx +17 -3
- package/dist/template/src/components/mdx/code-block.tsx +13 -9
- package/dist/template/src/components/mdx/code-group.tsx +13 -8
- package/dist/template/src/components/mdx/heading.tsx +15 -2
- package/dist/template/src/components/mdx/highlighted-code.tsx +13 -8
- package/dist/template/src/components/mdx/index.tsx +2 -0
- package/dist/template/src/components/mdx/mermaid.tsx +110 -0
- package/dist/template/src/components/mdx/screenshot.tsx +150 -0
- package/dist/template/src/components/scroll-to-hash.tsx +48 -0
- package/dist/template/src/components/sidebar.tsx +12 -18
- package/dist/template/src/components/table-of-contents.tsx +9 -0
- package/dist/template/src/lib/highlight.ts +3 -88
- package/dist/template/src/lib/navigation.ts +159 -0
- package/dist/template/src/lib/search-types.ts +4 -1
- package/dist/template/src/lib/search.ts +30 -7
- package/dist/template/src/styles/globals.css +17 -6
- package/dist/utils/files.d.ts +9 -1
- package/dist/utils/files.js +59 -10
- package/dist/utils/validation.d.ts +0 -3
- package/dist/utils/validation.js +0 -26
- package/package.json +5 -1
package/dist/llm/index.js
CHANGED
|
@@ -9,6 +9,9 @@ export function createLLMClient(config) {
|
|
|
9
9
|
// Get API key from environment
|
|
10
10
|
const envKey = PROVIDER_ENV_KEYS[config.provider];
|
|
11
11
|
const apiKey = envKey ? process.env[envKey] || '' : '';
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
console.warn(`Warning: ${envKey} is not set. LLM calls will fail.`);
|
|
14
|
+
}
|
|
12
15
|
const clientConfig = {
|
|
13
16
|
provider: config.provider,
|
|
14
17
|
model: config.model,
|
|
@@ -43,176 +46,102 @@ export async function generateDocumentation(client, element, options) {
|
|
|
43
46
|
temperature: 0,
|
|
44
47
|
maxTokens: useMultiLang ? 4096 : 2048
|
|
45
48
|
});
|
|
46
|
-
|
|
47
|
-
?
|
|
48
|
-
:
|
|
49
|
+
const usage = response.usage
|
|
50
|
+
? { inputTokens: response.usage.inputTokens, outputTokens: response.usage.outputTokens }
|
|
51
|
+
: undefined;
|
|
52
|
+
const result = useMultiLang
|
|
53
|
+
? parseMultiLangResponse(response.content, element.name)
|
|
54
|
+
: parseDocResponse(response.content, element.name);
|
|
55
|
+
return { ...result, usage };
|
|
49
56
|
}
|
|
50
57
|
// Phase 2: Multi-language system prompt
|
|
51
|
-
const SYSTEM_PROMPT_MULTI_LANG = `You are an expert technical writer
|
|
52
|
-
|
|
53
|
-
Your goal: Help developers achieve their task FAST. Lead with "Use this to..." not "This function...".
|
|
54
|
-
|
|
55
|
-
## Documentation Rules
|
|
56
|
-
1. Do NOT include a heading with the function/class name - start directly with the use case
|
|
57
|
-
2. Start with the PRIMARY USE CASE - what problem does this solve?
|
|
58
|
-
3. Use a markdown table for parameters (Name | Type | Required | Description)
|
|
59
|
-
4. Clearly document what is returned and when
|
|
60
|
-
|
|
61
|
-
## Code Example Rules (CRITICAL)
|
|
62
|
-
Generate TWO self-contained examples: TypeScript AND Python.
|
|
63
|
-
|
|
64
|
-
Both examples MUST be:
|
|
65
|
-
1. COMPLETELY SELF-CONTAINED - no external imports from the library
|
|
66
|
-
2. EXECUTABLE standalone - inline all types and mock all functions
|
|
67
|
-
3. Using realistic data (API keys, user IDs, etc.)
|
|
68
|
-
4. Wrapped in try/except (Python) or try/catch (TypeScript)
|
|
69
|
-
5. Showing environment variable usage
|
|
70
|
-
6. Ending with print/console.log showing expected output
|
|
58
|
+
const SYSTEM_PROMPT_MULTI_LANG = `You are an expert technical writer. Write like the best devtool docs (Stripe, Vercel, Shopify): lead with the outcome, explain why this exists, then get technical.
|
|
71
59
|
|
|
72
|
-
##
|
|
73
|
-
\`\`\`typescript
|
|
74
|
-
// Inline types
|
|
75
|
-
type Config = { apiKey: string }
|
|
60
|
+
## Writing Rules
|
|
76
61
|
|
|
77
|
-
|
|
78
|
-
function createTool(config: Config) {
|
|
79
|
-
return { execute: async (q: string) => ({ results: [q] }) }
|
|
80
|
-
}
|
|
62
|
+
1. **Opening sentence**: Start with "Use [name] to [outcome]." Tell the developer what this ENABLES them to do. NOT "This function takes X and returns Y."
|
|
81
63
|
|
|
82
|
-
|
|
83
|
-
const tool = createTool({ apiKey: process.env.API_KEY || 'your-key' })
|
|
64
|
+
2. **When to use this** (1-2 sentences): What scenario would make a developer reach for this? If it's a method on a class, how does it fit into the typical workflow with that class? Connect it to a real task.
|
|
84
65
|
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const result = await tool.execute('query')
|
|
88
|
-
console.log('Result:', result)
|
|
89
|
-
// Output: { results: ['query'] }
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error('Failed:', error)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
main()
|
|
95
|
-
\`\`\`
|
|
66
|
+
3. **How it works** (1-3 sentences, only if the mechanism isn't obvious): Briefly explain the behavior. Skip this if the function name + params make it self-evident.
|
|
96
67
|
|
|
97
|
-
|
|
98
|
-
\`\`\`python
|
|
99
|
-
import os
|
|
100
|
-
from dataclasses import dataclass
|
|
101
|
-
from typing import Optional, List, Dict, Any
|
|
68
|
+
4. **Parameters**: Markdown table (Name | Type | Required | Description). Descriptions must explain IMPACT, not restate the type. Write "Maximum retry attempts before the request fails and throws" not "Number of retries." Write "Your Stripe secret key — find it at dashboard.stripe.com/apikeys" not "A string."
|
|
102
69
|
|
|
103
|
-
|
|
104
|
-
@dataclass
|
|
105
|
-
class Config:
|
|
106
|
-
api_key: str
|
|
107
|
-
timeout: int = 30
|
|
70
|
+
5. **Returns**: What you get back AND what to do with it next. "Returns the created user object. Pass user.id to subsequent API calls to act on behalf of this user."
|
|
108
71
|
|
|
109
|
-
|
|
110
|
-
class Tool:
|
|
111
|
-
def __init__(self, config: Config):
|
|
112
|
-
self.config = config
|
|
72
|
+
6. **Heads up** (only if non-obvious): 1-2 bullet points about common mistakes or surprising behavior. Omit entirely if there's nothing surprising.
|
|
113
73
|
|
|
114
|
-
|
|
115
|
-
|
|
74
|
+
Do NOT include a heading with the function/class name — start directly with the opening sentence.
|
|
75
|
+
Do NOT write filler like "This is a powerful utility for..." — be direct.
|
|
76
|
+
Do NOT just restate the function signature in prose — add information the signature doesn't convey.
|
|
116
77
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
async def main():
|
|
121
|
-
try:
|
|
122
|
-
tool = Tool(Config(api_key=os.getenv("API_KEY", "your-key")))
|
|
123
|
-
result = await tool.execute("query")
|
|
124
|
-
print(f"Result: {result}")
|
|
125
|
-
# Output: {'results': ['query']}
|
|
126
|
-
except Exception as e:
|
|
127
|
-
print(f"Failed: {e}")
|
|
78
|
+
## Code Examples
|
|
79
|
+
Generate TWO self-contained examples: TypeScript AND Python.
|
|
128
80
|
|
|
129
|
-
|
|
130
|
-
|
|
81
|
+
Both MUST be:
|
|
82
|
+
- COMPLETELY SELF-CONTAINED — no imports from the library being documented. Inline types and mock implementations.
|
|
83
|
+
- Using realistic data (real-looking API keys, user IDs, URLs)
|
|
84
|
+
- Wrapped in try/catch (TS) or try/except (Python)
|
|
85
|
+
- Ending with console.log/print showing expected output
|
|
86
|
+
- Short and focused — demonstrate the ONE primary use case, not every parameter
|
|
131
87
|
|
|
132
88
|
## Output Format
|
|
133
89
|
---MARKDOWN---
|
|
134
|
-
[
|
|
90
|
+
[Documentation following the rules above]
|
|
135
91
|
---TYPESCRIPT---
|
|
136
|
-
[Self-contained TypeScript example]
|
|
92
|
+
[Self-contained TypeScript example — no markdown fences]
|
|
137
93
|
---PYTHON---
|
|
138
|
-
[Self-contained Python example]
|
|
94
|
+
[Self-contained Python example — no markdown fences]
|
|
139
95
|
---END---`;
|
|
140
|
-
const SYSTEM_PROMPT = `You are an expert technical writer
|
|
96
|
+
const SYSTEM_PROMPT = `You are an expert technical writer. Write like the best devtool docs (Stripe, Vercel, Shopify): lead with the outcome, explain why this exists, then get technical.
|
|
141
97
|
|
|
142
|
-
|
|
98
|
+
## Writing Rules
|
|
143
99
|
|
|
144
|
-
|
|
145
|
-
1. Do NOT include a heading with the function/class name - start directly with the use case
|
|
146
|
-
2. Start with the PRIMARY USE CASE - what problem does this solve?
|
|
147
|
-
3. Use a markdown table for parameters (Name | Type | Required | Description)
|
|
148
|
-
4. Clearly document what is returned and when
|
|
100
|
+
1. **Opening sentence**: Start with "Use [name] to [outcome]." Tell the developer what this ENABLES them to do. NOT "This function takes X and returns Y."
|
|
149
101
|
|
|
150
|
-
|
|
151
|
-
Your code examples MUST be COMPLETELY SELF-CONTAINED and EXECUTABLE:
|
|
102
|
+
2. **When to use this** (1-2 sentences): What scenario would make a developer reach for this? If it's a method on a class, how does it fit into the typical workflow with that class? Connect it to a real task.
|
|
152
103
|
|
|
153
|
-
1.
|
|
154
|
-
2. Instead, INLINE any types or simple implementations needed
|
|
155
|
-
3. Use realistic but simple data (real-looking API keys, user IDs, etc.)
|
|
156
|
-
4. ALWAYS wrap async code in try/catch with meaningful error handling
|
|
157
|
-
5. ALWAYS show environment variable usage: process.env.API_KEY || 'your-api-key'
|
|
158
|
-
6. End with a console.log showing expected output
|
|
159
|
-
7. Include a brief comment showing what output to expect
|
|
104
|
+
3. **How it works** (1-3 sentences, only if the mechanism isn't obvious): Briefly explain the behavior. Skip this if the function name + params make it self-evident.
|
|
160
105
|
|
|
161
|
-
|
|
162
|
-
BAD (imports from library - will fail):
|
|
163
|
-
\`\`\`typescript
|
|
164
|
-
import { createTool } from '@mylib/tools'
|
|
165
|
-
const tool = createTool('key')
|
|
166
|
-
\`\`\`
|
|
106
|
+
4. **Parameters**: Markdown table (Name | Type | Required | Description). Descriptions must explain IMPACT, not restate the type. Write "Maximum retry attempts before the request fails and throws" not "Number of retries." Write "Your Stripe secret key — find it at dashboard.stripe.com/apikeys" not "A string."
|
|
167
107
|
|
|
168
|
-
|
|
169
|
-
\`\`\`typescript
|
|
170
|
-
// Define the types inline
|
|
171
|
-
type ToolConfig = { apiKey: string; timeout?: number }
|
|
108
|
+
5. **Returns**: What you get back AND what to do with it next. "Returns the created user object. Pass user.id to subsequent API calls to act on behalf of this user."
|
|
172
109
|
|
|
173
|
-
|
|
174
|
-
function createTool(config: ToolConfig) {
|
|
175
|
-
return {
|
|
176
|
-
execute: async (query: string) => {
|
|
177
|
-
console.log(\`Searching for: \${query}\`)
|
|
178
|
-
return { results: ['result1', 'result2'] }
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
110
|
+
6. **Heads up** (only if non-obvious): 1-2 bullet points about common mistakes or surprising behavior. Omit entirely if there's nothing surprising.
|
|
182
111
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
})
|
|
112
|
+
Do NOT include a heading with the function/class name — start directly with the opening sentence.
|
|
113
|
+
Do NOT write filler like "This is a powerful utility for..." — be direct.
|
|
114
|
+
Do NOT just restate the function signature in prose — add information the signature doesn't convey.
|
|
187
115
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
main()
|
|
199
|
-
\`\`\`
|
|
116
|
+
## Code Example
|
|
117
|
+
Generate ONE self-contained, executable example:
|
|
118
|
+
- Do NOT import from the library being documented — inline types and mock implementations
|
|
119
|
+
- Use realistic data (real-looking API keys, user IDs, URLs)
|
|
120
|
+
- Wrap async code in try/catch
|
|
121
|
+
- End with console.log showing expected output
|
|
122
|
+
- Short and focused — demonstrate the ONE primary use case
|
|
200
123
|
|
|
201
|
-
Output
|
|
124
|
+
## Output Format
|
|
202
125
|
---MARKDOWN---
|
|
203
|
-
[
|
|
126
|
+
[Documentation following the rules above]
|
|
204
127
|
---CODE---
|
|
205
|
-
[
|
|
128
|
+
[Self-contained example — no markdown fences]
|
|
206
129
|
---END---`;
|
|
207
130
|
function buildDocPrompt(element, multiLanguage = false) {
|
|
208
|
-
let prompt =
|
|
131
|
+
let prompt = '';
|
|
132
|
+
// Project context first — gives the LLM the "big picture" for better explanations
|
|
133
|
+
if (element.projectContext) {
|
|
134
|
+
prompt += `**Project context** (use this to explain WHY this ${element.kind} exists and how it fits in):\n`;
|
|
135
|
+
prompt += element.projectContext.slice(0, 1500) + '\n\n';
|
|
136
|
+
}
|
|
137
|
+
prompt += `Generate documentation for this ${element.kind}:\n\n`;
|
|
209
138
|
prompt += `**Name:** ${element.name}\n`;
|
|
210
139
|
prompt += `**Signature:** ${element.signature}\n`;
|
|
211
140
|
if (element.parentClass) {
|
|
212
141
|
prompt += `**Class:** ${element.parentClass}\n`;
|
|
213
142
|
}
|
|
214
143
|
if (element.packageName && element.packageName !== 'unknown') {
|
|
215
|
-
prompt += `**Package:** ${element.packageName} (DO NOT import from this
|
|
144
|
+
prompt += `**Package:** ${element.packageName} (DO NOT import from this — make example self-contained)\n`;
|
|
216
145
|
}
|
|
217
146
|
if (element.parameters.length > 0) {
|
|
218
147
|
prompt += `\n**Parameters:**\n`;
|
|
@@ -232,21 +161,25 @@ function buildDocPrompt(element, multiLanguage = false) {
|
|
|
232
161
|
prompt += `\n**Existing docstring:**\n${element.docstring}\n`;
|
|
233
162
|
}
|
|
234
163
|
if (element.sourceContext) {
|
|
235
|
-
prompt += `\n**Source context (
|
|
164
|
+
prompt += `\n**Source context (understand the code, but do NOT import from it):**\n\`\`\`\n${element.sourceContext}\n\`\`\`\n`;
|
|
236
165
|
}
|
|
237
166
|
if (element.imports && element.imports.length > 0) {
|
|
238
|
-
prompt += `\n**File imports (shows
|
|
167
|
+
prompt += `\n**File imports (shows what this code depends on — do NOT use in examples):**\n`;
|
|
239
168
|
prompt += element.imports.slice(0, 5).join('\n') + '\n';
|
|
240
169
|
}
|
|
241
|
-
if (
|
|
242
|
-
prompt +=
|
|
170
|
+
if (element.externalDocs) {
|
|
171
|
+
prompt += '\n**Third-party API reference (use for accurate API details):**\n';
|
|
172
|
+
prompt += element.externalDocs.slice(0, 3000) + '\n';
|
|
243
173
|
}
|
|
244
|
-
|
|
245
|
-
prompt += `\
|
|
174
|
+
if (multiLanguage) {
|
|
175
|
+
prompt += `\nGenerate BOTH TypeScript AND Python self-contained examples.`;
|
|
246
176
|
}
|
|
247
177
|
return prompt;
|
|
248
178
|
}
|
|
249
|
-
function parseDocResponse(content) {
|
|
179
|
+
function parseDocResponse(content, elementName) {
|
|
180
|
+
if (!content.includes('---MARKDOWN---')) {
|
|
181
|
+
console.warn(` Warning: LLM response missing expected format for ${elementName ?? 'unknown'}`);
|
|
182
|
+
}
|
|
250
183
|
// Extract markdown section
|
|
251
184
|
const markdownMatch = content.match(/---MARKDOWN---\s*([\s\S]*?)\s*---CODE---/);
|
|
252
185
|
const markdown = markdownMatch?.[1]?.trim() || content;
|
|
@@ -257,7 +190,10 @@ function parseDocResponse(content) {
|
|
|
257
190
|
codeExample = codeExample.replace(/^```\w*\n?/, '').replace(/\n?```$/, '');
|
|
258
191
|
return { markdown, codeExample, typescriptExample: codeExample };
|
|
259
192
|
}
|
|
260
|
-
function parseMultiLangResponse(content) {
|
|
193
|
+
function parseMultiLangResponse(content, elementName) {
|
|
194
|
+
if (!content.includes('---MARKDOWN---')) {
|
|
195
|
+
console.warn(` Warning: LLM response missing expected format for ${elementName ?? 'unknown'}`);
|
|
196
|
+
}
|
|
261
197
|
// Extract markdown section
|
|
262
198
|
const markdownMatch = content.match(/---MARKDOWN---\s*([\s\S]*?)\s*---TYPESCRIPT---/);
|
|
263
199
|
const markdown = markdownMatch?.[1]?.trim() || '';
|
|
@@ -277,124 +213,3 @@ function parseMultiLangResponse(content) {
|
|
|
277
213
|
pythonExample
|
|
278
214
|
};
|
|
279
215
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Helper to fix a broken code sample with smart strategies
|
|
282
|
-
*/
|
|
283
|
-
export async function fixCodeSample(client, code, error, context, iteration = 1) {
|
|
284
|
-
// Analyze error type to provide better fix guidance
|
|
285
|
-
const fixStrategy = analyzeErrorAndGetStrategy(error, code);
|
|
286
|
-
const response = await client.complete({
|
|
287
|
-
messages: [
|
|
288
|
-
{
|
|
289
|
-
role: 'system',
|
|
290
|
-
content: FIX_SYSTEM_PROMPT
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
role: 'user',
|
|
294
|
-
content: `Fix this code example. It must be COMPLETELY SELF-CONTAINED and runnable.
|
|
295
|
-
|
|
296
|
-
**Current code:**
|
|
297
|
-
\`\`\`
|
|
298
|
-
${code}
|
|
299
|
-
\`\`\`
|
|
300
|
-
|
|
301
|
-
**Error:**
|
|
302
|
-
${error}
|
|
303
|
-
|
|
304
|
-
**Fix strategy:** ${fixStrategy}
|
|
305
|
-
|
|
306
|
-
**Context:**
|
|
307
|
-
${context}
|
|
308
|
-
|
|
309
|
-
**Iteration ${iteration}:** ${iteration > 2 ? 'SIMPLIFY the example drastically - focus on demonstrating the concept, not real functionality.' : 'Make it self-contained.'}
|
|
310
|
-
|
|
311
|
-
Return ONLY the fixed code, no explanations or markdown fences.`
|
|
312
|
-
}
|
|
313
|
-
],
|
|
314
|
-
temperature: iteration > 3 ? 0.3 : 0, // Add creativity on later iterations
|
|
315
|
-
maxTokens: 1024
|
|
316
|
-
});
|
|
317
|
-
// Clean up any markdown fences
|
|
318
|
-
return response.content
|
|
319
|
-
.replace(/^```\w*\n?/, '')
|
|
320
|
-
.replace(/\n?```$/, '')
|
|
321
|
-
.trim();
|
|
322
|
-
}
|
|
323
|
-
const FIX_SYSTEM_PROMPT = `You are fixing a documentation code example to make it SELF-CONTAINED and RUNNABLE.
|
|
324
|
-
|
|
325
|
-
## Fix Strategies by Error Type
|
|
326
|
-
|
|
327
|
-
**Import/Module errors ("Cannot find module", "is not defined"):**
|
|
328
|
-
- DO NOT try to fix the import
|
|
329
|
-
- INLINE the type definitions
|
|
330
|
-
- MOCK the function behavior with a simple implementation
|
|
331
|
-
- Show what the function WOULD do conceptually
|
|
332
|
-
|
|
333
|
-
**Type errors ("Type X is not assignable"):**
|
|
334
|
-
- Define the type inline with \`type X = {...}\`
|
|
335
|
-
- Use simpler types if complex ones cause issues
|
|
336
|
-
|
|
337
|
-
**Runtime errors ("undefined is not a function", "Cannot read property"):**
|
|
338
|
-
- Initialize all variables
|
|
339
|
-
- Add null checks
|
|
340
|
-
- Use optional chaining (?.)
|
|
341
|
-
|
|
342
|
-
**Async errors ("await is only valid in async"):**
|
|
343
|
-
- Wrap in async function
|
|
344
|
-
- Add proper try/catch
|
|
345
|
-
- Call the async function at the end
|
|
346
|
-
|
|
347
|
-
## Example Fix Pattern
|
|
348
|
-
If the error is "Cannot find module '@mylib/tools'":
|
|
349
|
-
|
|
350
|
-
WRONG (trying to fix import):
|
|
351
|
-
\`\`\`
|
|
352
|
-
import { tool } from '@mylib/tools-v2' // Still fails
|
|
353
|
-
\`\`\`
|
|
354
|
-
|
|
355
|
-
RIGHT (inline everything):
|
|
356
|
-
\`\`\`
|
|
357
|
-
// Define types inline
|
|
358
|
-
type ToolResult = { data: string[] }
|
|
359
|
-
|
|
360
|
-
// Mock the tool behavior
|
|
361
|
-
const tool = {
|
|
362
|
-
search: async (query: string): Promise<ToolResult> => {
|
|
363
|
-
// Simulated behavior
|
|
364
|
-
return { data: ['result1', 'result2'] }
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Usage
|
|
369
|
-
async function main() {
|
|
370
|
-
const result = await tool.search('test')
|
|
371
|
-
console.log(result) // { data: ['result1', 'result2'] }
|
|
372
|
-
}
|
|
373
|
-
main()
|
|
374
|
-
\`\`\`
|
|
375
|
-
|
|
376
|
-
Return ONLY the fixed code.`;
|
|
377
|
-
function analyzeErrorAndGetStrategy(error, _code) {
|
|
378
|
-
const errorLower = error.toLowerCase();
|
|
379
|
-
if (errorLower.includes('cannot find module') || errorLower.includes('module not found')) {
|
|
380
|
-
const importMatch = error.match(/['"]([^'"]+)['"]/)?.[1] || 'the library';
|
|
381
|
-
return `IMPORT ERROR: Cannot import from "${importMatch}". Remove ALL imports and inline types/mock functions instead.`;
|
|
382
|
-
}
|
|
383
|
-
if (errorLower.includes('is not defined') || errorLower.includes('is not a function')) {
|
|
384
|
-
const undefinedMatch = error.match(/(\w+) is not (defined|a function)/)?.[1];
|
|
385
|
-
return `UNDEFINED: "${undefinedMatch}" is not available. Define it inline or mock it.`;
|
|
386
|
-
}
|
|
387
|
-
if (errorLower.includes('type') && (errorLower.includes('assignable') || errorLower.includes('missing'))) {
|
|
388
|
-
return `TYPE ERROR: Type mismatch. Simplify types or define them inline with correct structure.`;
|
|
389
|
-
}
|
|
390
|
-
if (errorLower.includes('await') && errorLower.includes('async')) {
|
|
391
|
-
return `ASYNC ERROR: Wrap code in async function and call it: async function main() {...} main()`;
|
|
392
|
-
}
|
|
393
|
-
if (errorLower.includes('timeout') || errorLower.includes('timed out')) {
|
|
394
|
-
return `TIMEOUT: Code took too long. Remove any actual API calls or network requests. Use mock data.`;
|
|
395
|
-
}
|
|
396
|
-
if (errorLower.includes('syntaxerror') || errorLower.includes('unexpected token')) {
|
|
397
|
-
return `SYNTAX ERROR: Fix syntax issues. Check for missing brackets, quotes, or semicolons.`;
|
|
398
|
-
}
|
|
399
|
-
return `GENERAL: Make the code self-contained. Define all types inline, mock all external calls, use try/catch.`;
|
|
400
|
-
}
|
|
@@ -9,6 +9,7 @@ export declare class OpenAICompatibleClient implements LLMClient {
|
|
|
9
9
|
private client;
|
|
10
10
|
private model;
|
|
11
11
|
private maxRetries;
|
|
12
|
+
private apiKey;
|
|
12
13
|
constructor(config: LLMClientConfig);
|
|
13
14
|
isConfigured(): boolean;
|
|
14
15
|
complete(request: CompletionRequest): Promise<CompletionResponse>;
|
|
@@ -9,14 +9,19 @@ export class OpenAICompatibleClient {
|
|
|
9
9
|
client;
|
|
10
10
|
model;
|
|
11
11
|
maxRetries;
|
|
12
|
+
apiKey;
|
|
12
13
|
constructor(config) {
|
|
13
14
|
this.provider = config.provider;
|
|
14
15
|
this.model = config.model;
|
|
15
16
|
this.maxRetries = config.maxRetries ?? 3;
|
|
16
17
|
const baseURL = config.baseUrl || PROVIDER_BASE_URLS[config.provider];
|
|
17
18
|
const extraHeaders = PROVIDER_EXTRA_HEADERS[config.provider] || {};
|
|
19
|
+
// Ollama doesn't need a real key; other providers get empty string
|
|
20
|
+
// (SDK validates on first request, not construction)
|
|
21
|
+
const effectiveKey = config.apiKey || (config.provider === 'ollama' ? 'ollama' : 'not-set');
|
|
22
|
+
this.apiKey = effectiveKey;
|
|
18
23
|
this.client = new OpenAI({
|
|
19
|
-
apiKey:
|
|
24
|
+
apiKey: effectiveKey,
|
|
20
25
|
baseURL,
|
|
21
26
|
timeout: config.timeout ?? 60000,
|
|
22
27
|
maxRetries: this.maxRetries,
|
|
@@ -24,7 +29,7 @@ export class OpenAICompatibleClient {
|
|
|
24
29
|
});
|
|
25
30
|
}
|
|
26
31
|
isConfigured() {
|
|
27
|
-
return
|
|
32
|
+
return this.apiKey !== '' && this.apiKey !== 'not-set';
|
|
28
33
|
}
|
|
29
34
|
async complete(request) {
|
|
30
35
|
const model = request.model || this.model;
|
package/dist/plugins/index.js
CHANGED
|
@@ -23,6 +23,8 @@ export class PluginManager {
|
|
|
23
23
|
if (!configFile)
|
|
24
24
|
return;
|
|
25
25
|
try {
|
|
26
|
+
console.log(` Loading config: ${configFile}`);
|
|
27
|
+
console.warn(' ⚠ Plugin configs execute code — only load trusted files');
|
|
26
28
|
const configUrl = pathToFileURL(configFile).href;
|
|
27
29
|
const module = await import(configUrl);
|
|
28
30
|
const config = module.default || module;
|
|
@@ -57,6 +59,11 @@ export class PluginManager {
|
|
|
57
59
|
return null;
|
|
58
60
|
}
|
|
59
61
|
async loadPluginByName(name) {
|
|
62
|
+
// Validate plugin name — must be a valid npm package name, no path traversal
|
|
63
|
+
if (!/^(@[a-zA-Z0-9._-]+\/)?[a-zA-Z0-9._-]+$/.test(name)) {
|
|
64
|
+
console.warn(`Skipping plugin with invalid name: ${name}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
60
67
|
// Try to load from node_modules
|
|
61
68
|
try {
|
|
62
69
|
const module = await import(name);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QAIssue } from './types.js';
|
|
2
|
+
export declare function checkFrontmatter(filePath: string, content: string, relPath: string): QAIssue[];
|
|
3
|
+
export declare function checkHeadings(content: string, relPath: string): QAIssue[];
|
|
4
|
+
export declare function checkCodeBlocks(content: string, relPath: string): QAIssue[];
|
|
5
|
+
export declare function checkComponents(content: string, relPath: string): QAIssue[];
|
|
6
|
+
export declare function checkLinks(content: string, relPath: string, _allFiles: Set<string>): QAIssue[];
|
|
7
|
+
export declare function checkSecurity(content: string, relPath: string): QAIssue[];
|
|
8
|
+
export declare function checkContentQuality(content: string, relPath: string): QAIssue[];
|
|
9
|
+
export declare function checkScreenshots(content: string, relPath: string, outputDir: string): QAIssue[];
|
|
10
|
+
export declare function checkMdxSyntax(content: string, relPath: string): QAIssue[];
|