skrypt-ai 0.5.0 → 0.6.1
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.js +8 -1
- package/dist/autofix/index.d.ts +0 -4
- package/dist/autofix/index.js +0 -21
- 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 +4 -0
- 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 +88 -6
- 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/lint.js +50 -44
- package/dist/commands/llms-txt.js +59 -49
- package/dist/commands/login.js +61 -43
- 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 +114 -103
- package/dist/commands/sdk.js +128 -122
- package/dist/commands/security.js +86 -80
- 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 +24 -4
- 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/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 +16 -2
- 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/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 +84 -6
- 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/styles/globals.css +17 -6
- package/dist/utils/validation.d.ts +0 -3
- package/dist/utils/validation.js +0 -26
- package/package.json +3 -2
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract <Screenshot> directives from MDX files.
|
|
3
|
+
*
|
|
4
|
+
* Scans MDX content for <Screenshot> tags outside code blocks.
|
|
5
|
+
* Uses the same code-block-aware scanning pattern as src/qa/checks.ts.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Parse all <Screenshot> directives from MDX content.
|
|
9
|
+
*
|
|
10
|
+
* Supports both self-closing (<Screenshot ... />) and open/close tags.
|
|
11
|
+
* Extracts url, selector, alt, caption props via regex.
|
|
12
|
+
* Resolves relative URLs against baseUrl.
|
|
13
|
+
*/
|
|
14
|
+
export function parseScreenshotDirectives(content, filePath, baseUrl) {
|
|
15
|
+
const directives = [];
|
|
16
|
+
const lines = content.split('\n');
|
|
17
|
+
let inCodeBlock = false;
|
|
18
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19
|
+
const line = lines[i];
|
|
20
|
+
if (line === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
if (line.startsWith('```')) {
|
|
23
|
+
inCodeBlock = !inCodeBlock;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (inCodeBlock)
|
|
27
|
+
continue;
|
|
28
|
+
// Match <Screenshot ...> or <Screenshot ... />
|
|
29
|
+
const tagMatches = line.matchAll(/<Screenshot\s+([^>]*?)\/?>/g);
|
|
30
|
+
for (const match of tagMatches) {
|
|
31
|
+
const propsStr = match[1];
|
|
32
|
+
if (!propsStr)
|
|
33
|
+
continue;
|
|
34
|
+
const url = extractProp(propsStr, 'url');
|
|
35
|
+
const alt = extractProp(propsStr, 'alt');
|
|
36
|
+
if (!url || !alt)
|
|
37
|
+
continue;
|
|
38
|
+
const selector = extractProp(propsStr, 'selector');
|
|
39
|
+
const caption = extractProp(propsStr, 'caption');
|
|
40
|
+
// Resolve relative URLs against baseUrl
|
|
41
|
+
let resolvedUrl;
|
|
42
|
+
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
43
|
+
resolvedUrl = url;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Ensure baseUrl doesn't have trailing slash for clean join
|
|
47
|
+
const base = baseUrl.replace(/\/+$/, '');
|
|
48
|
+
const path = url.startsWith('/') ? url : `/${url}`;
|
|
49
|
+
resolvedUrl = `${base}${path}`;
|
|
50
|
+
}
|
|
51
|
+
directives.push({
|
|
52
|
+
url: resolvedUrl,
|
|
53
|
+
selector: selector || undefined,
|
|
54
|
+
alt,
|
|
55
|
+
caption: caption || undefined,
|
|
56
|
+
sourceFile: filePath,
|
|
57
|
+
sourceLine: i + 1,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return directives;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract a prop value from a JSX props string.
|
|
65
|
+
* Handles both quoted values: prop="value" and prop='value'
|
|
66
|
+
* Also handles JSX expressions: prop={"value"} and prop={'value'}
|
|
67
|
+
*/
|
|
68
|
+
function extractProp(propsStr, propName) {
|
|
69
|
+
// Match prop="value" or prop='value'
|
|
70
|
+
const quoteRegex = new RegExp(`${propName}\\s*=\\s*["']([^"']*?)["']`);
|
|
71
|
+
const quoteMatch = propsStr.match(quoteRegex);
|
|
72
|
+
if (quoteMatch?.[1] !== undefined)
|
|
73
|
+
return quoteMatch[1];
|
|
74
|
+
// Match prop={"value"} or prop={'value'}
|
|
75
|
+
const jsxRegex = new RegExp(`${propName}\\s*=\\s*\\{\\s*["']([^"']*?)["']\\s*\\}`);
|
|
76
|
+
const jsxMatch = propsStr.match(jsxRegex);
|
|
77
|
+
if (jsxMatch?.[1] !== undefined)
|
|
78
|
+
return jsxMatch[1];
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface ScreenshotDirective {
|
|
2
|
+
url: string;
|
|
3
|
+
selector?: string;
|
|
4
|
+
alt: string;
|
|
5
|
+
caption?: string;
|
|
6
|
+
sourceFile: string;
|
|
7
|
+
sourceLine: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ScreenshotResult {
|
|
10
|
+
directive: ScreenshotDirective;
|
|
11
|
+
filename: string;
|
|
12
|
+
darkFilename?: string;
|
|
13
|
+
status: 'captured' | 'unchanged' | 'failed';
|
|
14
|
+
error?: string;
|
|
15
|
+
hash?: string;
|
|
16
|
+
duration: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CaptureReport {
|
|
19
|
+
directives: number;
|
|
20
|
+
captured: number;
|
|
21
|
+
unchanged: number;
|
|
22
|
+
failed: number;
|
|
23
|
+
duration: number;
|
|
24
|
+
results: ScreenshotResult[];
|
|
25
|
+
}
|
|
26
|
+
export interface ScreenshotManifest {
|
|
27
|
+
version: 1;
|
|
28
|
+
capturedAt: string;
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
viewport: {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
screenshots: Record<string, {
|
|
35
|
+
url: string;
|
|
36
|
+
selector?: string;
|
|
37
|
+
filename: string;
|
|
38
|
+
darkFilename?: string;
|
|
39
|
+
capturedAt: string;
|
|
40
|
+
hash: string;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface CaptureOptions {
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
outputDir: string;
|
|
46
|
+
viewport: {
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
};
|
|
50
|
+
dark: boolean;
|
|
51
|
+
diff: boolean;
|
|
52
|
+
dryRun: boolean;
|
|
53
|
+
timeout: number;
|
|
54
|
+
wait: number;
|
|
55
|
+
device?: string;
|
|
56
|
+
concurrency: number;
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { watchCommand } from './commands/watch.js';
|
|
|
6
6
|
import { autofixCommand } from './commands/autofix.js';
|
|
7
7
|
import { reviewPRCommand } from './commands/review-pr.js';
|
|
8
8
|
import { lintCommand } from './commands/lint.js';
|
|
9
|
+
import { qaCommand } from './commands/qa.js';
|
|
9
10
|
import { checkLinksCommand } from './commands/check-links.js';
|
|
10
11
|
import { mcpCommand } from './commands/mcp.js';
|
|
11
12
|
import { versionCommand } from './commands/version.js';
|
|
@@ -20,6 +21,7 @@ import { deployCommand } from './commands/deploy.js';
|
|
|
20
21
|
import { testCommand } from './commands/test.js';
|
|
21
22
|
import { securityCommand } from './commands/security.js';
|
|
22
23
|
import { importCommand } from './commands/import.js';
|
|
24
|
+
import { healCommand } from './commands/heal.js';
|
|
23
25
|
import { createRequire } from 'module';
|
|
24
26
|
process.on('uncaughtException', (err) => {
|
|
25
27
|
console.error('\x1b[31mFatal error:\x1b[0m', err.message);
|
|
@@ -77,6 +79,7 @@ program.addCommand(watchCommand);
|
|
|
77
79
|
program.addCommand(autofixCommand);
|
|
78
80
|
program.addCommand(reviewPRCommand);
|
|
79
81
|
program.addCommand(lintCommand);
|
|
82
|
+
program.addCommand(qaCommand);
|
|
80
83
|
program.addCommand(checkLinksCommand);
|
|
81
84
|
program.addCommand(mcpCommand);
|
|
82
85
|
program.addCommand(versionCommand);
|
|
@@ -93,4 +96,5 @@ program.addCommand(deployCommand);
|
|
|
93
96
|
program.addCommand(testCommand);
|
|
94
97
|
program.addCommand(securityCommand);
|
|
95
98
|
program.addCommand(importCommand);
|
|
99
|
+
program.addCommand(healCommand);
|
|
96
100
|
program.parse();
|
package/dist/commands/autofix.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { readFileSync, writeFileSync } from 'fs';
|
|
3
|
-
import { resolve } from 'path';
|
|
3
|
+
import { resolve, dirname } from 'path';
|
|
4
4
|
import { loadConfig, checkApiKey } from '../config/index.js';
|
|
5
5
|
import { createLLMClient } from '../llm/index.js';
|
|
6
6
|
import { autoFixExample, createTypeScriptValidator, createPythonValidator } from '../autofix/index.js';
|
|
7
7
|
import { requirePro } from '../auth/index.js';
|
|
8
|
+
import { runQA, printQAReport, fixQAIssues, printFixReport } from '../qa/index.js';
|
|
8
9
|
export const autofixCommand = new Command('autofix')
|
|
9
10
|
.description('Auto-fix broken code examples in documentation')
|
|
10
11
|
.argument('<file>', 'Documentation file to fix (markdown/mdx)')
|
|
@@ -15,134 +16,149 @@ export const autofixCommand = new Command('autofix')
|
|
|
15
16
|
.option('--dry-run', 'Show fixes without writing')
|
|
16
17
|
.option('--language <lang>', 'Force language for validation')
|
|
17
18
|
.action(async (file, options) => {
|
|
18
|
-
// Pro feature - requires subscription
|
|
19
|
-
if (!await requirePro('autofix')) {
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
const config = loadConfig(options.config);
|
|
23
|
-
if (options.provider)
|
|
24
|
-
config.llm.provider = options.provider;
|
|
25
|
-
if (options.model)
|
|
26
|
-
config.llm.model = options.model;
|
|
27
|
-
const { ok, envKey } = checkApiKey(config.llm.provider);
|
|
28
|
-
if (!ok && envKey) {
|
|
29
|
-
console.error(`Error: ${envKey} environment variable required`);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
const filePath = resolve(file);
|
|
33
|
-
console.log(`skrypt autofix`);
|
|
34
|
-
console.log(` file: ${filePath}`);
|
|
35
|
-
console.log(` provider: ${config.llm.provider}`);
|
|
36
|
-
console.log(` max iterations: ${options.maxIterations}`);
|
|
37
|
-
console.log('');
|
|
38
|
-
// Read the file
|
|
39
|
-
let content;
|
|
40
19
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const errObj = err;
|
|
45
|
-
if (errObj.code === 'ENOENT') {
|
|
46
|
-
console.error(`Error: File not found: ${filePath}`);
|
|
20
|
+
// Pro feature - requires subscription
|
|
21
|
+
if (!await requirePro('autofix')) {
|
|
22
|
+
process.exit(1);
|
|
47
23
|
}
|
|
48
|
-
|
|
49
|
-
|
|
24
|
+
const config = loadConfig(options.config);
|
|
25
|
+
if (options.provider)
|
|
26
|
+
config.llm.provider = options.provider;
|
|
27
|
+
if (options.model)
|
|
28
|
+
config.llm.model = options.model;
|
|
29
|
+
const { ok, envKey } = checkApiKey(config.llm.provider);
|
|
30
|
+
if (!ok && envKey) {
|
|
31
|
+
console.error(`Error: ${envKey} environment variable required`);
|
|
32
|
+
process.exit(1);
|
|
50
33
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
const filePath = resolve(file);
|
|
35
|
+
console.log(`skrypt autofix`);
|
|
36
|
+
console.log(` file: ${filePath}`);
|
|
37
|
+
console.log(` provider: ${config.llm.provider}`);
|
|
38
|
+
console.log(` max iterations: ${options.maxIterations}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
// Read the file
|
|
41
|
+
let content;
|
|
42
|
+
try {
|
|
43
|
+
content = readFileSync(filePath, 'utf-8');
|
|
54
44
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
code,
|
|
69
|
-
index: match.index,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if (codeBlocks.length === 0) {
|
|
73
|
-
console.log('No code blocks found in file.');
|
|
74
|
-
process.exit(0);
|
|
75
|
-
}
|
|
76
|
-
console.log(`Found ${codeBlocks.length} code block(s)`);
|
|
77
|
-
console.log('');
|
|
78
|
-
const client = createLLMClient({
|
|
79
|
-
provider: config.llm.provider,
|
|
80
|
-
model: config.llm.model,
|
|
81
|
-
baseUrl: config.llm.baseUrl,
|
|
82
|
-
});
|
|
83
|
-
const maxIterations = parseInt(options.maxIterations);
|
|
84
|
-
// Create validators
|
|
85
|
-
const validators = {
|
|
86
|
-
javascript: createTypeScriptValidator(),
|
|
87
|
-
typescript: createTypeScriptValidator(),
|
|
88
|
-
ts: createTypeScriptValidator(),
|
|
89
|
-
js: createTypeScriptValidator(),
|
|
90
|
-
python: createPythonValidator(),
|
|
91
|
-
py: createPythonValidator(),
|
|
92
|
-
};
|
|
93
|
-
let fixedCount = 0;
|
|
94
|
-
let failedCount = 0;
|
|
95
|
-
let newContent = content;
|
|
96
|
-
for (let i = 0; i < codeBlocks.length; i++) {
|
|
97
|
-
const block = codeBlocks[i];
|
|
98
|
-
if (!block)
|
|
99
|
-
continue;
|
|
100
|
-
const validator = validators[block.language.toLowerCase()];
|
|
101
|
-
if (!validator) {
|
|
102
|
-
console.log(`[${i + 1}/${codeBlocks.length}] Skipping ${block.language} (no validator)`);
|
|
103
|
-
continue;
|
|
45
|
+
catch (err) {
|
|
46
|
+
const errObj = err;
|
|
47
|
+
if (errObj.code === 'ENOENT') {
|
|
48
|
+
console.error(`Error: File not found: ${filePath}`);
|
|
49
|
+
}
|
|
50
|
+
else if (errObj.code === 'EACCES') {
|
|
51
|
+
console.error(`Error: Permission denied: ${filePath}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
55
|
+
console.error(`Error: Could not read file: ${filePath} (${message})`);
|
|
56
|
+
}
|
|
57
|
+
process.exit(1);
|
|
104
58
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
59
|
+
// Find all code blocks
|
|
60
|
+
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
|
|
61
|
+
const codeBlocks = [];
|
|
62
|
+
let match;
|
|
63
|
+
while ((match = codeBlockRegex.exec(content)) !== null) {
|
|
64
|
+
const code = match[2];
|
|
65
|
+
if (!code)
|
|
66
|
+
continue;
|
|
67
|
+
codeBlocks.push({
|
|
68
|
+
match: match[0],
|
|
69
|
+
language: options.language || match[1] || 'javascript',
|
|
70
|
+
code,
|
|
71
|
+
index: match.index,
|
|
72
|
+
});
|
|
111
73
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
74
|
+
if (codeBlocks.length === 0) {
|
|
75
|
+
console.log('No code blocks found in file.');
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
console.log(`Found ${codeBlocks.length} code block(s)`);
|
|
79
|
+
console.log('');
|
|
80
|
+
const client = createLLMClient({
|
|
81
|
+
provider: config.llm.provider,
|
|
82
|
+
model: config.llm.model,
|
|
83
|
+
baseUrl: config.llm.baseUrl,
|
|
122
84
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const newBlock = '```' + block.language + '\n' + result.fixedCode + '```';
|
|
128
|
-
newContent = newContent.replace(block.match, newBlock);
|
|
85
|
+
const maxIterations = parseInt(options.maxIterations, 10);
|
|
86
|
+
if (isNaN(maxIterations) || maxIterations < 1) {
|
|
87
|
+
console.error('Error: --max-iterations must be a positive number');
|
|
88
|
+
process.exit(1);
|
|
129
89
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
90
|
+
// Create validators
|
|
91
|
+
const validators = {
|
|
92
|
+
javascript: createTypeScriptValidator(),
|
|
93
|
+
typescript: createTypeScriptValidator(),
|
|
94
|
+
ts: createTypeScriptValidator(),
|
|
95
|
+
js: createTypeScriptValidator(),
|
|
96
|
+
python: createPythonValidator(),
|
|
97
|
+
py: createPythonValidator(),
|
|
98
|
+
};
|
|
99
|
+
let fixedCount = 0;
|
|
100
|
+
let failedCount = 0;
|
|
101
|
+
let newContent = content;
|
|
102
|
+
for (let i = 0; i < codeBlocks.length; i++) {
|
|
103
|
+
const block = codeBlocks[i];
|
|
104
|
+
if (!block)
|
|
105
|
+
continue;
|
|
106
|
+
const validator = validators[block.language.toLowerCase()];
|
|
107
|
+
if (!validator) {
|
|
108
|
+
console.log(`[${i + 1}/${codeBlocks.length}] Skipping ${block.language} (no validator)`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
console.log(`[${i + 1}/${codeBlocks.length}] Checking ${block.language} example...`);
|
|
112
|
+
// First check if it's valid
|
|
113
|
+
const initial = await validator(block.code);
|
|
114
|
+
if (initial.valid) {
|
|
115
|
+
console.log(` ✓ Already valid`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
console.log(` ✗ Invalid: ${initial.errors[0]?.slice(0, 60)}...`);
|
|
119
|
+
console.log(` → Attempting to fix...`);
|
|
120
|
+
const result = await autoFixExample({
|
|
121
|
+
code: block.code,
|
|
122
|
+
language: block.language,
|
|
123
|
+
context: `Code example from documentation file: ${file}`,
|
|
124
|
+
}, client, {
|
|
125
|
+
maxIterations,
|
|
126
|
+
validateFn: validator,
|
|
127
|
+
language: block.language,
|
|
128
|
+
});
|
|
129
|
+
if (result.success) {
|
|
130
|
+
console.log(` ✓ Fixed in ${result.iterations} iteration(s)`);
|
|
131
|
+
fixedCount++;
|
|
132
|
+
// Replace in content
|
|
133
|
+
const newBlock = '```' + block.language + '\n' + result.fixedCode + '```';
|
|
134
|
+
newContent = newContent.replace(block.match, newBlock);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log(` ✗ Could not fix after ${result.iterations} iterations`);
|
|
138
|
+
failedCount++;
|
|
139
|
+
}
|
|
133
140
|
}
|
|
141
|
+
console.log('');
|
|
142
|
+
console.log('=== Summary ===');
|
|
143
|
+
console.log(` Checked: ${codeBlocks.length}`);
|
|
144
|
+
console.log(` Fixed: ${fixedCount}`);
|
|
145
|
+
console.log(` Failed: ${failedCount}`);
|
|
146
|
+
if (fixedCount > 0 && !options.dryRun) {
|
|
147
|
+
writeFileSync(filePath, newContent);
|
|
148
|
+
console.log(`\nWrote fixes to ${filePath}`);
|
|
149
|
+
// Auto-fix then run QA on the fixed file's directory
|
|
150
|
+
const fixReport = fixQAIssues(dirname(filePath));
|
|
151
|
+
printFixReport(fixReport);
|
|
152
|
+
const qaReport = runQA(dirname(filePath));
|
|
153
|
+
printQAReport(qaReport);
|
|
154
|
+
}
|
|
155
|
+
else if (fixedCount > 0 && options.dryRun) {
|
|
156
|
+
console.log(`\n[dry run - no changes written]`);
|
|
157
|
+
}
|
|
158
|
+
console.log('\nDone!');
|
|
134
159
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
console.log(` Fixed: ${fixedCount}`);
|
|
139
|
-
console.log(` Failed: ${failedCount}`);
|
|
140
|
-
if (fixedCount > 0 && !options.dryRun) {
|
|
141
|
-
writeFileSync(filePath, newContent);
|
|
142
|
-
console.log(`\nWrote fixes to ${filePath}`);
|
|
143
|
-
}
|
|
144
|
-
else if (fixedCount > 0 && options.dryRun) {
|
|
145
|
-
console.log(`\n[dry run - no changes written]`);
|
|
160
|
+
catch (err) {
|
|
161
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
162
|
+
process.exit(1);
|
|
146
163
|
}
|
|
147
|
-
console.log('\nDone!');
|
|
148
164
|
});
|
package/dist/commands/cron.js
CHANGED
|
@@ -54,53 +54,64 @@ export const cronCommand = new Command('cron')
|
|
|
54
54
|
.option('-s, --schedule <cron>', 'Cron schedule (default: daily at 2am UTC)', '0 2 * * *')
|
|
55
55
|
.option('-f, --force', 'Overwrite existing workflow')
|
|
56
56
|
.action(async (repoPath, options) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
try {
|
|
58
|
+
const resolvedPath = resolve(repoPath);
|
|
59
|
+
const workflowDir = join(resolvedPath, '.github', 'workflows');
|
|
60
|
+
const workflowPath = join(workflowDir, 'skrypt-docs.yml');
|
|
61
|
+
console.log('skrypt cron');
|
|
62
|
+
console.log(` repo: ${resolvedPath}`);
|
|
63
|
+
console.log(` schedule: ${options.schedule}`);
|
|
64
|
+
console.log('');
|
|
65
|
+
// Validate cron schedule format
|
|
66
|
+
if (options.schedule && !/^[\d\s*,\-/]+$/.test(options.schedule)) {
|
|
67
|
+
console.error('Error: Invalid cron schedule format');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
// Check if workflow exists
|
|
71
|
+
if (existsSync(workflowPath) && !options.force) {
|
|
72
|
+
console.log('Workflow already exists. Use --force to overwrite.');
|
|
73
|
+
console.log(` ${workflowPath}`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Create workflow directory
|
|
77
|
+
mkdirSync(workflowDir, { recursive: true });
|
|
78
|
+
// Customize schedule if provided
|
|
79
|
+
let workflow = CRON_WORKFLOW;
|
|
80
|
+
if (options.schedule && options.schedule !== '0 2 * * *') {
|
|
81
|
+
workflow = workflow.replace("cron: '0 2 * * *'", `cron: '${options.schedule}'`);
|
|
82
|
+
}
|
|
83
|
+
// Write workflow
|
|
84
|
+
writeFileSync(workflowPath, workflow);
|
|
85
|
+
console.log(`✓ Created: ${workflowPath}`);
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log('=== Setup Instructions ===');
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log('1. Add secrets to your GitHub repository:');
|
|
90
|
+
console.log(' Settings > Secrets and variables > Actions');
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log(' Required:');
|
|
93
|
+
console.log(' - SKRYPT_API_KEY: Get from https://skrypt.sh/dashboard/settings');
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(' For AI generation (one of):');
|
|
96
|
+
console.log(' - OPENAI_API_KEY');
|
|
97
|
+
console.log(' - ANTHROPIC_API_KEY');
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log('2. Commit and push:');
|
|
100
|
+
console.log(' git add .github/');
|
|
101
|
+
console.log(' git commit -m "Add Skrypt auto-update workflow"');
|
|
102
|
+
console.log(' git push');
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log('3. Trigger manually (optional):');
|
|
105
|
+
console.log(' Go to Actions > Skrypt Auto-Update Docs > Run workflow');
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log('Common schedules:');
|
|
108
|
+
console.log(' "0 2 * * *" - Daily at 2am UTC');
|
|
109
|
+
console.log(' "0 2 * * 1" - Weekly on Monday');
|
|
110
|
+
console.log(' "0 2 1 * *" - Monthly on the 1st');
|
|
111
|
+
console.log(' "0 */6 * * *" - Every 6 hours');
|
|
69
112
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
let workflow = CRON_WORKFLOW;
|
|
74
|
-
if (options.schedule && options.schedule !== '0 2 * * *') {
|
|
75
|
-
workflow = workflow.replace("cron: '0 2 * * *'", `cron: '${options.schedule}'`);
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
115
|
+
process.exit(1);
|
|
76
116
|
}
|
|
77
|
-
// Write workflow
|
|
78
|
-
writeFileSync(workflowPath, workflow);
|
|
79
|
-
console.log(`✓ Created: ${workflowPath}`);
|
|
80
|
-
console.log('');
|
|
81
|
-
console.log('=== Setup Instructions ===');
|
|
82
|
-
console.log('');
|
|
83
|
-
console.log('1. Add secrets to your GitHub repository:');
|
|
84
|
-
console.log(' Settings > Secrets and variables > Actions');
|
|
85
|
-
console.log('');
|
|
86
|
-
console.log(' Required:');
|
|
87
|
-
console.log(' - SKRYPT_API_KEY: Get from https://skrypt.sh/dashboard/settings');
|
|
88
|
-
console.log('');
|
|
89
|
-
console.log(' For AI generation (one of):');
|
|
90
|
-
console.log(' - OPENAI_API_KEY');
|
|
91
|
-
console.log(' - ANTHROPIC_API_KEY');
|
|
92
|
-
console.log('');
|
|
93
|
-
console.log('2. Commit and push:');
|
|
94
|
-
console.log(' git add .github/');
|
|
95
|
-
console.log(' git commit -m "Add Skrypt auto-update workflow"');
|
|
96
|
-
console.log(' git push');
|
|
97
|
-
console.log('');
|
|
98
|
-
console.log('3. Trigger manually (optional):');
|
|
99
|
-
console.log(' Go to Actions > Skrypt Auto-Update Docs > Run workflow');
|
|
100
|
-
console.log('');
|
|
101
|
-
console.log('Common schedules:');
|
|
102
|
-
console.log(' "0 2 * * *" - Daily at 2am UTC');
|
|
103
|
-
console.log(' "0 2 * * 1" - Weekly on Monday');
|
|
104
|
-
console.log(' "0 2 1 * *" - Monthly on the 1st');
|
|
105
|
-
console.log(' "0 */6 * * *" - Every 6 hours');
|
|
106
117
|
});
|