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.
Files changed (159) hide show
  1. package/dist/auth/index.d.ts +13 -3
  2. package/dist/auth/index.js +101 -9
  3. package/dist/auth/keychain.d.ts +5 -0
  4. package/dist/auth/keychain.js +82 -0
  5. package/dist/auth/notices.d.ts +3 -0
  6. package/dist/auth/notices.js +42 -0
  7. package/dist/autofix/index.d.ts +0 -4
  8. package/dist/autofix/index.js +10 -24
  9. package/dist/capture/browser.d.ts +11 -0
  10. package/dist/capture/browser.js +173 -0
  11. package/dist/capture/diff.d.ts +23 -0
  12. package/dist/capture/diff.js +52 -0
  13. package/dist/capture/index.d.ts +23 -0
  14. package/dist/capture/index.js +210 -0
  15. package/dist/capture/naming.d.ts +17 -0
  16. package/dist/capture/naming.js +45 -0
  17. package/dist/capture/parser.d.ts +15 -0
  18. package/dist/capture/parser.js +80 -0
  19. package/dist/capture/types.d.ts +57 -0
  20. package/dist/capture/types.js +1 -0
  21. package/dist/cli.js +20 -3
  22. package/dist/commands/autofix.js +136 -120
  23. package/dist/commands/cron.js +58 -47
  24. package/dist/commands/deploy.js +123 -102
  25. package/dist/commands/generate.js +125 -7
  26. package/dist/commands/heal.d.ts +10 -0
  27. package/dist/commands/heal.js +201 -0
  28. package/dist/commands/i18n.js +146 -111
  29. package/dist/commands/import.d.ts +2 -0
  30. package/dist/commands/import.js +157 -0
  31. package/dist/commands/init.js +19 -7
  32. package/dist/commands/lint.js +50 -44
  33. package/dist/commands/llms-txt.js +59 -49
  34. package/dist/commands/login.js +63 -34
  35. package/dist/commands/mcp.js +6 -0
  36. package/dist/commands/monitor.js +13 -8
  37. package/dist/commands/qa.d.ts +2 -0
  38. package/dist/commands/qa.js +43 -0
  39. package/dist/commands/review-pr.js +108 -92
  40. package/dist/commands/sdk.js +128 -122
  41. package/dist/commands/security.d.ts +2 -0
  42. package/dist/commands/security.js +109 -0
  43. package/dist/commands/test.js +91 -92
  44. package/dist/commands/version.js +104 -75
  45. package/dist/commands/watch.js +130 -114
  46. package/dist/config/types.js +2 -2
  47. package/dist/context-hub/index.d.ts +23 -0
  48. package/dist/context-hub/index.js +179 -0
  49. package/dist/context-hub/mappings.d.ts +8 -0
  50. package/dist/context-hub/mappings.js +55 -0
  51. package/dist/context-hub/types.d.ts +33 -0
  52. package/dist/context-hub/types.js +1 -0
  53. package/dist/generator/generator.js +39 -6
  54. package/dist/generator/types.d.ts +7 -0
  55. package/dist/generator/writer.d.ts +3 -1
  56. package/dist/generator/writer.js +36 -7
  57. package/dist/importers/confluence.d.ts +5 -0
  58. package/dist/importers/confluence.js +137 -0
  59. package/dist/importers/detect.d.ts +20 -0
  60. package/dist/importers/detect.js +121 -0
  61. package/dist/importers/docusaurus.d.ts +5 -0
  62. package/dist/importers/docusaurus.js +279 -0
  63. package/dist/importers/gitbook.d.ts +5 -0
  64. package/dist/importers/gitbook.js +189 -0
  65. package/dist/importers/github.d.ts +8 -0
  66. package/dist/importers/github.js +99 -0
  67. package/dist/importers/index.d.ts +15 -0
  68. package/dist/importers/index.js +30 -0
  69. package/dist/importers/markdown.d.ts +6 -0
  70. package/dist/importers/markdown.js +105 -0
  71. package/dist/importers/mintlify.d.ts +5 -0
  72. package/dist/importers/mintlify.js +172 -0
  73. package/dist/importers/notion.d.ts +5 -0
  74. package/dist/importers/notion.js +174 -0
  75. package/dist/importers/readme.d.ts +5 -0
  76. package/dist/importers/readme.js +184 -0
  77. package/dist/importers/transform.d.ts +90 -0
  78. package/dist/importers/transform.js +457 -0
  79. package/dist/importers/types.d.ts +37 -0
  80. package/dist/importers/types.js +1 -0
  81. package/dist/llm/anthropic-client.d.ts +1 -0
  82. package/dist/llm/anthropic-client.js +3 -1
  83. package/dist/llm/index.d.ts +6 -4
  84. package/dist/llm/index.js +76 -261
  85. package/dist/llm/openai-client.d.ts +1 -0
  86. package/dist/llm/openai-client.js +7 -2
  87. package/dist/plugins/index.js +7 -0
  88. package/dist/qa/checks.d.ts +10 -0
  89. package/dist/qa/checks.js +492 -0
  90. package/dist/qa/fixes.d.ts +30 -0
  91. package/dist/qa/fixes.js +277 -0
  92. package/dist/qa/index.d.ts +29 -0
  93. package/dist/qa/index.js +187 -0
  94. package/dist/qa/types.d.ts +24 -0
  95. package/dist/qa/types.js +1 -0
  96. package/dist/scanner/csharp.d.ts +23 -0
  97. package/dist/scanner/csharp.js +421 -0
  98. package/dist/scanner/index.js +53 -26
  99. package/dist/scanner/java.d.ts +39 -0
  100. package/dist/scanner/java.js +318 -0
  101. package/dist/scanner/kotlin.d.ts +23 -0
  102. package/dist/scanner/kotlin.js +389 -0
  103. package/dist/scanner/php.d.ts +57 -0
  104. package/dist/scanner/php.js +351 -0
  105. package/dist/scanner/python.js +17 -0
  106. package/dist/scanner/ruby.d.ts +36 -0
  107. package/dist/scanner/ruby.js +431 -0
  108. package/dist/scanner/swift.d.ts +25 -0
  109. package/dist/scanner/swift.js +392 -0
  110. package/dist/scanner/types.d.ts +1 -1
  111. package/dist/template/content/docs/_navigation.json +46 -0
  112. package/dist/template/content/docs/_sidebars.json +684 -0
  113. package/dist/template/content/docs/core.md +4544 -0
  114. package/dist/template/content/docs/index.mdx +89 -0
  115. package/dist/template/content/docs/integrations.md +1158 -0
  116. package/dist/template/content/docs/llms-full.md +403 -0
  117. package/dist/template/content/docs/llms.txt +4588 -0
  118. package/dist/template/content/docs/other.md +10379 -0
  119. package/dist/template/content/docs/tools.md +746 -0
  120. package/dist/template/content/docs/types.md +531 -0
  121. package/dist/template/docs.json +13 -11
  122. package/dist/template/mdx-components.tsx +27 -2
  123. package/dist/template/package.json +6 -0
  124. package/dist/template/public/search-index.json +1 -1
  125. package/dist/template/scripts/build-search-index.mjs +149 -13
  126. package/dist/template/src/app/api/chat/route.ts +83 -128
  127. package/dist/template/src/app/docs/[...slug]/page.tsx +75 -20
  128. package/dist/template/src/app/docs/llms-full.md +151 -4
  129. package/dist/template/src/app/docs/llms.txt +2464 -847
  130. package/dist/template/src/app/docs/page.mdx +48 -38
  131. package/dist/template/src/app/layout.tsx +3 -1
  132. package/dist/template/src/app/page.tsx +22 -8
  133. package/dist/template/src/components/ai-chat.tsx +73 -64
  134. package/dist/template/src/components/breadcrumbs.tsx +21 -23
  135. package/dist/template/src/components/copy-button.tsx +13 -9
  136. package/dist/template/src/components/copy-page-button.tsx +54 -0
  137. package/dist/template/src/components/docs-layout.tsx +37 -25
  138. package/dist/template/src/components/header.tsx +51 -10
  139. package/dist/template/src/components/mdx/card.tsx +17 -3
  140. package/dist/template/src/components/mdx/code-block.tsx +13 -9
  141. package/dist/template/src/components/mdx/code-group.tsx +13 -8
  142. package/dist/template/src/components/mdx/heading.tsx +15 -2
  143. package/dist/template/src/components/mdx/highlighted-code.tsx +13 -8
  144. package/dist/template/src/components/mdx/index.tsx +2 -0
  145. package/dist/template/src/components/mdx/mermaid.tsx +110 -0
  146. package/dist/template/src/components/mdx/screenshot.tsx +150 -0
  147. package/dist/template/src/components/scroll-to-hash.tsx +48 -0
  148. package/dist/template/src/components/sidebar.tsx +12 -18
  149. package/dist/template/src/components/table-of-contents.tsx +9 -0
  150. package/dist/template/src/lib/highlight.ts +3 -88
  151. package/dist/template/src/lib/navigation.ts +159 -0
  152. package/dist/template/src/lib/search-types.ts +4 -1
  153. package/dist/template/src/lib/search.ts +30 -7
  154. package/dist/template/src/styles/globals.css +17 -6
  155. package/dist/utils/files.d.ts +9 -1
  156. package/dist/utils/files.js +59 -10
  157. package/dist/utils/validation.d.ts +0 -3
  158. package/dist/utils/validation.js +0 -26
  159. package/package.json +5 -1
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Screenshot capture orchestrator.
3
+ *
4
+ * Coordinates MDX parsing, browser capture, diff detection, and file output.
5
+ */
6
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs';
7
+ import { join, resolve } from 'path';
8
+ import { findMdxFiles } from '../utils/files.js';
9
+ import { parseScreenshotDirectives } from './parser.js';
10
+ import { captureScreenshots } from './browser.js';
11
+ import { loadHashStore, saveHashStore, computeHash, hasChanged } from './diff.js';
12
+ /**
13
+ * Run the screenshot capture pipeline.
14
+ *
15
+ * 1. Find all MDX files in docsDir
16
+ * 2. Parse <Screenshot> directives from each
17
+ * 3. Validate base URL reachability
18
+ * 4. Capture screenshots via headless browser
19
+ * 5. Compare hashes for --diff mode
20
+ * 6. Write changed files to outputDir
21
+ * 7. Write manifest and hash store
22
+ */
23
+ export async function runCapture(docsDir, options) {
24
+ const startTime = Date.now();
25
+ const resolvedDocsDir = resolve(docsDir);
26
+ const resolvedOutputDir = resolve(options.outputDir);
27
+ // 1. Find MDX files
28
+ const mdxFiles = findMdxFiles(resolvedDocsDir);
29
+ // 2. Parse directives
30
+ const allDirectives = mdxFiles.flatMap(filePath => {
31
+ const content = readFileSync(filePath, 'utf-8');
32
+ return parseScreenshotDirectives(content, filePath, options.baseUrl);
33
+ });
34
+ if (allDirectives.length === 0) {
35
+ return {
36
+ directives: 0,
37
+ captured: 0,
38
+ unchanged: 0,
39
+ failed: 0,
40
+ duration: Date.now() - startTime,
41
+ results: [],
42
+ };
43
+ }
44
+ // 3. Dry run
45
+ if (options.dryRun) {
46
+ console.log(`\n Found ${allDirectives.length} screenshot directive(s):`);
47
+ for (const d of allDirectives) {
48
+ const sel = d.selector ? ` (${d.selector})` : ' (full page)';
49
+ console.log(` ${d.url}${sel} → ${d.alt}`);
50
+ }
51
+ console.log('\n [dry run — no files written]\n');
52
+ return {
53
+ directives: allDirectives.length,
54
+ captured: 0,
55
+ unchanged: 0,
56
+ failed: 0,
57
+ duration: Date.now() - startTime,
58
+ results: [],
59
+ };
60
+ }
61
+ // 4. Validate base URL reachability
62
+ try {
63
+ const response = await fetch(options.baseUrl, {
64
+ method: 'HEAD',
65
+ signal: AbortSignal.timeout(5000),
66
+ });
67
+ if (!response.ok) {
68
+ console.error(`\n Base URL ${options.baseUrl} returned ${response.status}`);
69
+ console.error(' Make sure your dev server is running.\n');
70
+ return {
71
+ directives: allDirectives.length,
72
+ captured: 0,
73
+ unchanged: 0,
74
+ failed: allDirectives.length,
75
+ duration: Date.now() - startTime,
76
+ results: [],
77
+ };
78
+ }
79
+ }
80
+ catch {
81
+ console.error(`\n Cannot reach ${options.baseUrl}`);
82
+ console.error(' Start your dev server first, then run heal again.\n');
83
+ return {
84
+ directives: allDirectives.length,
85
+ captured: 0,
86
+ unchanged: 0,
87
+ failed: allDirectives.length,
88
+ duration: Date.now() - startTime,
89
+ results: [],
90
+ };
91
+ }
92
+ // 5. Load hash store for diff mode
93
+ const projectDir = resolvedDocsDir;
94
+ const hashStore = options.diff ? loadHashStore(projectDir) : {};
95
+ // 6. Capture all screenshots
96
+ console.log(`\n Capturing ${allDirectives.length} screenshot(s)...`);
97
+ const results = await captureScreenshots(allDirectives, options);
98
+ // 7. Process results — write files, check diffs
99
+ mkdirSync(resolvedOutputDir, { recursive: true });
100
+ let captured = 0;
101
+ let unchanged = 0;
102
+ let failed = 0;
103
+ const newHashStore = { ...hashStore };
104
+ const manifestEntries = {};
105
+ for (const result of results) {
106
+ if (result.status === 'failed') {
107
+ failed++;
108
+ continue;
109
+ }
110
+ const lightBuffer = getBuffer(result, 'light');
111
+ if (!lightBuffer) {
112
+ failed++;
113
+ result.status = 'failed';
114
+ result.error = 'No screenshot data captured';
115
+ continue;
116
+ }
117
+ const hash = computeHash(lightBuffer);
118
+ // Diff check
119
+ if (options.diff && !hasChanged(result.filename, hash, hashStore)) {
120
+ unchanged++;
121
+ result.status = 'unchanged';
122
+ continue;
123
+ }
124
+ // Write light screenshot
125
+ const outputPath = join(resolvedOutputDir, result.filename);
126
+ writeFileSync(outputPath, lightBuffer);
127
+ newHashStore[result.filename] = hash;
128
+ captured++;
129
+ // Write dark variant if present
130
+ if (result.darkFilename) {
131
+ const darkBuffer = getBuffer(result, 'dark');
132
+ if (darkBuffer) {
133
+ const darkPath = join(resolvedOutputDir, result.darkFilename);
134
+ writeFileSync(darkPath, darkBuffer);
135
+ newHashStore[result.darkFilename] = computeHash(darkBuffer);
136
+ }
137
+ }
138
+ // Build manifest entry
139
+ manifestEntries[result.filename] = {
140
+ url: result.directive.url,
141
+ selector: result.directive.selector,
142
+ filename: result.filename,
143
+ darkFilename: result.darkFilename,
144
+ capturedAt: new Date().toISOString(),
145
+ hash,
146
+ };
147
+ }
148
+ // 8. Write manifest
149
+ const manifest = {
150
+ version: 1,
151
+ capturedAt: new Date().toISOString(),
152
+ baseUrl: options.baseUrl,
153
+ viewport: options.viewport,
154
+ screenshots: manifestEntries,
155
+ };
156
+ writeFileSync(join(resolvedOutputDir, '_manifest.json'), JSON.stringify(manifest, null, 2), 'utf-8');
157
+ // 9. Save hash store
158
+ if (options.diff) {
159
+ saveHashStore(projectDir, newHashStore);
160
+ }
161
+ return {
162
+ directives: allDirectives.length,
163
+ captured,
164
+ unchanged,
165
+ failed,
166
+ duration: Date.now() - startTime,
167
+ results,
168
+ };
169
+ }
170
+ /**
171
+ * Extract buffer from result (stored as internal _buffer or _buffers property).
172
+ */
173
+ function getBuffer(result, variant) {
174
+ const r = result;
175
+ if (r._buffers) {
176
+ return variant === 'light' ? r._buffers.light : r._buffers.dark;
177
+ }
178
+ if (variant === 'light' && r._buffer) {
179
+ return r._buffer;
180
+ }
181
+ return null;
182
+ }
183
+ /**
184
+ * Print a capture report to stdout.
185
+ */
186
+ export function printCaptureReport(report) {
187
+ if (report.directives === 0) {
188
+ console.log('\n No <Screenshot> directives found in docs.\n');
189
+ return;
190
+ }
191
+ const parts = [];
192
+ if (report.captured > 0)
193
+ parts.push(`${report.captured} captured`);
194
+ if (report.unchanged > 0)
195
+ parts.push(`${report.unchanged} unchanged`);
196
+ if (report.failed > 0)
197
+ parts.push(`${report.failed} failed`);
198
+ console.log(`\n Screenshots: ${parts.join(', ')} (${report.duration}ms)`);
199
+ // Show failures
200
+ const failures = report.results.filter(r => r.status === 'failed');
201
+ for (const f of failures) {
202
+ const loc = f.directive.selector
203
+ ? `${f.directive.url} (${f.directive.selector})`
204
+ : f.directive.url;
205
+ console.log(` ✗ ${loc}: ${f.error}`);
206
+ }
207
+ if (report.captured > 0) {
208
+ console.log('');
209
+ }
210
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Deterministic screenshot filename generation.
3
+ *
4
+ * Derives stable, human-readable filenames from URL + optional CSS selector.
5
+ *
6
+ * Examples:
7
+ * /dashboard + .billing-panel → dashboard--billing-panel.png
8
+ * /settings/account + #profile → settings-account--profile.png
9
+ * /dashboard (no selector) → dashboard.png
10
+ */
11
+ export declare function screenshotFilename(url: string, selector?: string): string;
12
+ /**
13
+ * Dark mode variant filename.
14
+ * dashboard.png → dashboard-dark.png
15
+ * dashboard--panel.png → dashboard--panel-dark.png
16
+ */
17
+ export declare function darkVariantFilename(filename: string): string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Deterministic screenshot filename generation.
3
+ *
4
+ * Derives stable, human-readable filenames from URL + optional CSS selector.
5
+ *
6
+ * Examples:
7
+ * /dashboard + .billing-panel → dashboard--billing-panel.png
8
+ * /settings/account + #profile → settings-account--profile.png
9
+ * /dashboard (no selector) → dashboard.png
10
+ */
11
+ export function screenshotFilename(url, selector) {
12
+ // Extract pathname from full URL or use as-is if just a path
13
+ let pathname;
14
+ try {
15
+ pathname = new URL(url).pathname;
16
+ }
17
+ catch {
18
+ pathname = url;
19
+ }
20
+ // Strip leading /
21
+ let slug = pathname.replace(/^\/+/, '');
22
+ // Replace / with -
23
+ slug = slug.replace(/\//g, '-');
24
+ // If empty (root path), use "index"
25
+ if (!slug)
26
+ slug = 'index';
27
+ // Sanitize: only keep alphanumeric and hyphens
28
+ slug = slug.replace(/[^a-zA-Z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
29
+ if (selector) {
30
+ // Strip CSS selector prefix (. or #)
31
+ let selectorSlug = selector.replace(/^[.#]/, '');
32
+ // Sanitize selector the same way
33
+ selectorSlug = selectorSlug.replace(/[^a-zA-Z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
34
+ slug = `${slug}--${selectorSlug}`;
35
+ }
36
+ return `${slug}.png`;
37
+ }
38
+ /**
39
+ * Dark mode variant filename.
40
+ * dashboard.png → dashboard-dark.png
41
+ * dashboard--panel.png → dashboard--panel-dark.png
42
+ */
43
+ export function darkVariantFilename(filename) {
44
+ return filename.replace(/\.png$/, '-dark.png');
45
+ }
@@ -0,0 +1,15 @@
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
+ import type { ScreenshotDirective } from './types.js';
8
+ /**
9
+ * Parse all <Screenshot> directives from MDX content.
10
+ *
11
+ * Supports both self-closing (<Screenshot ... />) and open/close tags.
12
+ * Extracts url, selector, alt, caption props via regex.
13
+ * Resolves relative URLs against baseUrl.
14
+ */
15
+ export declare function parseScreenshotDirectives(content: string, filePath: string, baseUrl: string): ScreenshotDirective[];
@@ -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';
@@ -18,6 +19,9 @@ import { loginCommand, logoutCommand, whoamiCommand } from './commands/login.js'
18
19
  import { cronCommand } from './commands/cron.js';
19
20
  import { deployCommand } from './commands/deploy.js';
20
21
  import { testCommand } from './commands/test.js';
22
+ import { securityCommand } from './commands/security.js';
23
+ import { importCommand } from './commands/import.js';
24
+ import { healCommand } from './commands/heal.js';
21
25
  import { createRequire } from 'module';
22
26
  process.on('uncaughtException', (err) => {
23
27
  console.error('\x1b[31mFatal error:\x1b[0m', err.message);
@@ -33,6 +37,16 @@ process.on('unhandledRejection', (reason) => {
33
37
  });
34
38
  const require = createRequire(import.meta.url);
35
39
  const { version: VERSION } = require('../package.json');
40
+ function semverNewer(latest, current) {
41
+ const parse = (v) => v.split('.').map(Number);
42
+ const [lMaj, lMin, lPatch] = parse(latest);
43
+ const [cMaj, cMin, cPatch] = parse(current);
44
+ if (lMaj !== cMaj)
45
+ return lMaj > cMaj;
46
+ if (lMin !== cMin)
47
+ return lMin > cMin;
48
+ return lPatch > cPatch;
49
+ }
36
50
  async function checkForUpdates() {
37
51
  try {
38
52
  const res = await fetch('https://registry.npmjs.org/skrypt-ai/latest', {
@@ -41,9 +55,8 @@ async function checkForUpdates() {
41
55
  if (res.ok) {
42
56
  const data = await res.json();
43
57
  const version = data.version;
44
- if (typeof version === 'string' && /^\d+\.\d+\.\d+/.test(version) && version !== VERSION) {
45
- const latest = version;
46
- console.log(`\n Update available: ${VERSION} → ${latest}`);
58
+ if (typeof version === 'string' && /^\d+\.\d+\.\d+$/.test(version) && semverNewer(version, VERSION)) {
59
+ console.log(`\n Update available: ${VERSION} → ${version}`);
47
60
  console.log(` Run: npm install -g skrypt-ai@latest\n`);
48
61
  }
49
62
  }
@@ -66,6 +79,7 @@ program.addCommand(watchCommand);
66
79
  program.addCommand(autofixCommand);
67
80
  program.addCommand(reviewPRCommand);
68
81
  program.addCommand(lintCommand);
82
+ program.addCommand(qaCommand);
69
83
  program.addCommand(checkLinksCommand);
70
84
  program.addCommand(mcpCommand);
71
85
  program.addCommand(versionCommand);
@@ -80,4 +94,7 @@ program.addCommand(whoamiCommand);
80
94
  program.addCommand(cronCommand);
81
95
  program.addCommand(deployCommand);
82
96
  program.addCommand(testCommand);
97
+ program.addCommand(securityCommand);
98
+ program.addCommand(importCommand);
99
+ program.addCommand(healCommand);
83
100
  program.parse();