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.
Files changed (120) hide show
  1. package/dist/auth/index.js +8 -1
  2. package/dist/autofix/index.d.ts +0 -4
  3. package/dist/autofix/index.js +0 -21
  4. package/dist/capture/browser.d.ts +11 -0
  5. package/dist/capture/browser.js +173 -0
  6. package/dist/capture/diff.d.ts +23 -0
  7. package/dist/capture/diff.js +52 -0
  8. package/dist/capture/index.d.ts +23 -0
  9. package/dist/capture/index.js +210 -0
  10. package/dist/capture/naming.d.ts +17 -0
  11. package/dist/capture/naming.js +45 -0
  12. package/dist/capture/parser.d.ts +15 -0
  13. package/dist/capture/parser.js +80 -0
  14. package/dist/capture/types.d.ts +57 -0
  15. package/dist/capture/types.js +1 -0
  16. package/dist/cli.js +4 -0
  17. package/dist/commands/autofix.js +136 -120
  18. package/dist/commands/cron.js +58 -47
  19. package/dist/commands/deploy.js +123 -102
  20. package/dist/commands/generate.js +88 -6
  21. package/dist/commands/heal.d.ts +10 -0
  22. package/dist/commands/heal.js +201 -0
  23. package/dist/commands/i18n.js +146 -111
  24. package/dist/commands/lint.js +50 -44
  25. package/dist/commands/llms-txt.js +59 -49
  26. package/dist/commands/login.js +61 -43
  27. package/dist/commands/mcp.js +6 -0
  28. package/dist/commands/monitor.js +13 -8
  29. package/dist/commands/qa.d.ts +2 -0
  30. package/dist/commands/qa.js +43 -0
  31. package/dist/commands/review-pr.js +114 -103
  32. package/dist/commands/sdk.js +128 -122
  33. package/dist/commands/security.js +86 -80
  34. package/dist/commands/test.js +91 -92
  35. package/dist/commands/version.js +104 -75
  36. package/dist/commands/watch.js +130 -114
  37. package/dist/config/types.js +2 -2
  38. package/dist/context-hub/index.d.ts +23 -0
  39. package/dist/context-hub/index.js +179 -0
  40. package/dist/context-hub/mappings.d.ts +8 -0
  41. package/dist/context-hub/mappings.js +55 -0
  42. package/dist/context-hub/types.d.ts +33 -0
  43. package/dist/context-hub/types.js +1 -0
  44. package/dist/generator/generator.js +39 -6
  45. package/dist/generator/types.d.ts +7 -0
  46. package/dist/generator/writer.d.ts +3 -1
  47. package/dist/generator/writer.js +24 -4
  48. package/dist/llm/anthropic-client.d.ts +1 -0
  49. package/dist/llm/anthropic-client.js +3 -1
  50. package/dist/llm/index.d.ts +6 -4
  51. package/dist/llm/index.js +76 -261
  52. package/dist/llm/openai-client.d.ts +1 -0
  53. package/dist/llm/openai-client.js +7 -2
  54. package/dist/qa/checks.d.ts +10 -0
  55. package/dist/qa/checks.js +492 -0
  56. package/dist/qa/fixes.d.ts +30 -0
  57. package/dist/qa/fixes.js +277 -0
  58. package/dist/qa/index.d.ts +29 -0
  59. package/dist/qa/index.js +187 -0
  60. package/dist/qa/types.d.ts +24 -0
  61. package/dist/qa/types.js +1 -0
  62. package/dist/scanner/csharp.d.ts +23 -0
  63. package/dist/scanner/csharp.js +421 -0
  64. package/dist/scanner/index.js +16 -2
  65. package/dist/scanner/java.d.ts +39 -0
  66. package/dist/scanner/java.js +318 -0
  67. package/dist/scanner/kotlin.d.ts +23 -0
  68. package/dist/scanner/kotlin.js +389 -0
  69. package/dist/scanner/php.d.ts +57 -0
  70. package/dist/scanner/php.js +351 -0
  71. package/dist/scanner/ruby.d.ts +36 -0
  72. package/dist/scanner/ruby.js +431 -0
  73. package/dist/scanner/swift.d.ts +25 -0
  74. package/dist/scanner/swift.js +392 -0
  75. package/dist/scanner/types.d.ts +1 -1
  76. package/dist/template/content/docs/_navigation.json +46 -0
  77. package/dist/template/content/docs/_sidebars.json +684 -0
  78. package/dist/template/content/docs/core.md +4544 -0
  79. package/dist/template/content/docs/index.mdx +89 -0
  80. package/dist/template/content/docs/integrations.md +1158 -0
  81. package/dist/template/content/docs/llms-full.md +403 -0
  82. package/dist/template/content/docs/llms.txt +4588 -0
  83. package/dist/template/content/docs/other.md +10379 -0
  84. package/dist/template/content/docs/tools.md +746 -0
  85. package/dist/template/content/docs/types.md +531 -0
  86. package/dist/template/docs.json +13 -11
  87. package/dist/template/mdx-components.tsx +27 -2
  88. package/dist/template/package.json +6 -0
  89. package/dist/template/public/search-index.json +1 -1
  90. package/dist/template/scripts/build-search-index.mjs +84 -6
  91. package/dist/template/src/app/api/chat/route.ts +83 -128
  92. package/dist/template/src/app/docs/[...slug]/page.tsx +75 -20
  93. package/dist/template/src/app/docs/llms-full.md +151 -4
  94. package/dist/template/src/app/docs/llms.txt +2464 -847
  95. package/dist/template/src/app/docs/page.mdx +48 -38
  96. package/dist/template/src/app/layout.tsx +3 -1
  97. package/dist/template/src/app/page.tsx +22 -8
  98. package/dist/template/src/components/ai-chat.tsx +73 -64
  99. package/dist/template/src/components/breadcrumbs.tsx +21 -23
  100. package/dist/template/src/components/copy-button.tsx +13 -9
  101. package/dist/template/src/components/copy-page-button.tsx +54 -0
  102. package/dist/template/src/components/docs-layout.tsx +37 -25
  103. package/dist/template/src/components/header.tsx +51 -10
  104. package/dist/template/src/components/mdx/card.tsx +17 -3
  105. package/dist/template/src/components/mdx/code-block.tsx +13 -9
  106. package/dist/template/src/components/mdx/code-group.tsx +13 -8
  107. package/dist/template/src/components/mdx/heading.tsx +15 -2
  108. package/dist/template/src/components/mdx/highlighted-code.tsx +13 -8
  109. package/dist/template/src/components/mdx/index.tsx +2 -0
  110. package/dist/template/src/components/mdx/mermaid.tsx +110 -0
  111. package/dist/template/src/components/mdx/screenshot.tsx +150 -0
  112. package/dist/template/src/components/scroll-to-hash.tsx +48 -0
  113. package/dist/template/src/components/sidebar.tsx +12 -18
  114. package/dist/template/src/components/table-of-contents.tsx +9 -0
  115. package/dist/template/src/lib/highlight.ts +3 -88
  116. package/dist/template/src/lib/navigation.ts +159 -0
  117. package/dist/template/src/styles/globals.css +17 -6
  118. package/dist/utils/validation.d.ts +0 -3
  119. package/dist/utils/validation.js +0 -26
  120. package/package.json +3 -2
@@ -6,7 +6,12 @@ const CONFIG_FILE = 'skrypt.i18n.json';
6
6
  function loadI18nConfig(docsPath) {
7
7
  const configPath = join(docsPath, CONFIG_FILE);
8
8
  if (existsSync(configPath)) {
9
- return JSON.parse(readFileSync(configPath, 'utf-8'));
9
+ try {
10
+ return JSON.parse(readFileSync(configPath, 'utf-8'));
11
+ }
12
+ catch {
13
+ return { defaultLocale: 'en', locales: ['en'] };
14
+ }
10
15
  }
11
16
  return { defaultLocale: 'en', locales: ['en'] };
12
17
  }
@@ -22,25 +27,31 @@ i18nCommand
22
27
  .argument('[docs-path]', 'Documentation directory', './docs')
23
28
  .option('--default <locale>', 'Default locale', 'en')
24
29
  .action((docsPath, options) => {
25
- const resolvedPath = resolve(docsPath);
26
- if (!existsSync(resolvedPath)) {
27
- console.error(`Directory not found: ${resolvedPath}`);
28
- process.exit(1);
30
+ try {
31
+ const resolvedPath = resolve(docsPath);
32
+ if (!existsSync(resolvedPath)) {
33
+ console.error(`Directory not found: ${resolvedPath}`);
34
+ process.exit(1);
35
+ }
36
+ const config = {
37
+ defaultLocale: options.default,
38
+ locales: [options.default],
39
+ };
40
+ saveI18nConfig(resolvedPath, config);
41
+ // Create locale directory structure
42
+ const localeDir = join(resolvedPath, options.default);
43
+ if (!existsSync(localeDir)) {
44
+ mkdirSync(localeDir, { recursive: true });
45
+ console.log(`Created locale directory: ${localeDir}`);
46
+ }
47
+ console.log('i18n initialized.');
48
+ console.log(` Default locale: ${options.default}`);
49
+ console.log(` Config: ${join(resolvedPath, CONFIG_FILE)}`);
29
50
  }
30
- const config = {
31
- defaultLocale: options.default,
32
- locales: [options.default],
33
- };
34
- saveI18nConfig(resolvedPath, config);
35
- // Create locale directory structure
36
- const localeDir = join(resolvedPath, options.default);
37
- if (!existsSync(localeDir)) {
38
- mkdirSync(localeDir, { recursive: true });
39
- console.log(`Created locale directory: ${localeDir}`);
51
+ catch (err) {
52
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
53
+ process.exit(1);
40
54
  }
41
- console.log('i18n initialized.');
42
- console.log(` Default locale: ${options.default}`);
43
- console.log(` Config: ${join(resolvedPath, CONFIG_FILE)}`);
44
55
  });
45
56
  i18nCommand
46
57
  .command('add')
@@ -48,53 +59,65 @@ i18nCommand
48
59
  .argument('<locale>', 'Locale code (e.g., ja, fr, de)')
49
60
  .argument('[docs-path]', 'Documentation directory', './docs')
50
61
  .action((locale, docsPath) => {
51
- const resolvedPath = resolve(docsPath);
52
- const config = loadI18nConfig(resolvedPath);
53
- if (config.locales.includes(locale)) {
54
- console.log(`Locale ${locale} already exists.`);
55
- return;
62
+ try {
63
+ const resolvedPath = resolve(docsPath);
64
+ const config = loadI18nConfig(resolvedPath);
65
+ if (config.locales.includes(locale)) {
66
+ console.log(`Locale ${locale} already exists.`);
67
+ return;
68
+ }
69
+ config.locales.push(locale);
70
+ saveI18nConfig(resolvedPath, config);
71
+ // Create locale directory
72
+ const localeDir = join(resolvedPath, locale);
73
+ mkdirSync(localeDir, { recursive: true });
74
+ console.log(`Added locale: ${locale}`);
75
+ console.log(` Directory: ${localeDir}`);
76
+ }
77
+ catch (err) {
78
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
79
+ process.exit(1);
56
80
  }
57
- config.locales.push(locale);
58
- saveI18nConfig(resolvedPath, config);
59
- // Create locale directory
60
- const localeDir = join(resolvedPath, locale);
61
- mkdirSync(localeDir, { recursive: true });
62
- console.log(`Added locale: ${locale}`);
63
- console.log(` Directory: ${localeDir}`);
64
81
  });
65
82
  i18nCommand
66
83
  .command('status')
67
84
  .description('Show translation status')
68
85
  .argument('[docs-path]', 'Documentation directory', './docs')
69
86
  .action((docsPath) => {
70
- const resolvedPath = resolve(docsPath);
71
- const config = loadI18nConfig(resolvedPath);
72
- console.log('i18n Status');
73
- console.log(` Default locale: ${config.defaultLocale}`);
74
- console.log(` Locales: ${config.locales.join(', ')}`);
75
- console.log('');
76
- // Get files from default locale
77
- const defaultDir = join(resolvedPath, config.defaultLocale);
78
- if (!existsSync(defaultDir)) {
79
- console.log(`Default locale directory not found: ${defaultDir}`);
80
- return;
81
- }
82
- const defaultFiles = findMdxFiles(defaultDir);
83
- console.log(`Default locale (${config.defaultLocale}): ${defaultFiles.length} files`);
84
- // Check each other locale
85
- for (const locale of config.locales) {
86
- if (locale === config.defaultLocale)
87
- continue;
88
- const localeDir = join(resolvedPath, locale);
89
- if (!existsSync(localeDir)) {
90
- console.log(`${locale}: 0/${defaultFiles.length} (directory missing)`);
91
- continue;
87
+ try {
88
+ const resolvedPath = resolve(docsPath);
89
+ const config = loadI18nConfig(resolvedPath);
90
+ console.log('i18n Status');
91
+ console.log(` Default locale: ${config.defaultLocale}`);
92
+ console.log(` Locales: ${config.locales.join(', ')}`);
93
+ console.log('');
94
+ // Get files from default locale
95
+ const defaultDir = join(resolvedPath, config.defaultLocale);
96
+ if (!existsSync(defaultDir)) {
97
+ console.log(`Default locale directory not found: ${defaultDir}`);
98
+ return;
99
+ }
100
+ const defaultFiles = findMdxFiles(defaultDir);
101
+ console.log(`Default locale (${config.defaultLocale}): ${defaultFiles.length} files`);
102
+ // Check each other locale
103
+ for (const locale of config.locales) {
104
+ if (locale === config.defaultLocale)
105
+ continue;
106
+ const localeDir = join(resolvedPath, locale);
107
+ if (!existsSync(localeDir)) {
108
+ console.log(`${locale}: 0/${defaultFiles.length} (directory missing)`);
109
+ continue;
110
+ }
111
+ const localeFiles = findMdxFiles(localeDir);
112
+ const translated = localeFiles.length;
113
+ const total = defaultFiles.length;
114
+ const pct = total > 0 ? Math.round((translated / total) * 100) : 0;
115
+ console.log(`${locale}: ${translated}/${total} (${pct}%)`);
92
116
  }
93
- const localeFiles = findMdxFiles(localeDir);
94
- const translated = localeFiles.length;
95
- const total = defaultFiles.length;
96
- const pct = total > 0 ? Math.round((translated / total) * 100) : 0;
97
- console.log(`${locale}: ${translated}/${total} (${pct}%)`);
117
+ }
118
+ catch (err) {
119
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
120
+ process.exit(1);
98
121
  }
99
122
  });
100
123
  i18nCommand
@@ -103,34 +126,40 @@ i18nCommand
103
126
  .argument('<locale>', 'Locale to check')
104
127
  .argument('[docs-path]', 'Documentation directory', './docs')
105
128
  .action((locale, docsPath) => {
106
- const resolvedPath = resolve(docsPath);
107
- const config = loadI18nConfig(resolvedPath);
108
- if (!config.locales.includes(locale)) {
109
- console.error(`Locale ${locale} not configured.`);
110
- process.exit(1);
111
- }
112
- const defaultDir = join(resolvedPath, config.defaultLocale);
113
- const localeDir = join(resolvedPath, locale);
114
- if (!existsSync(defaultDir)) {
115
- console.error(`Default locale directory not found: ${defaultDir}`);
116
- process.exit(1);
117
- }
118
- const defaultFiles = findMdxFiles(defaultDir);
119
- const missing = [];
120
- for (const file of defaultFiles) {
121
- const relPath = relative(defaultDir, file);
122
- const localePath = join(localeDir, relPath);
123
- if (!existsSync(localePath)) {
124
- missing.push(relPath);
129
+ try {
130
+ const resolvedPath = resolve(docsPath);
131
+ const config = loadI18nConfig(resolvedPath);
132
+ if (!config.locales.includes(locale)) {
133
+ console.error(`Locale ${locale} not configured.`);
134
+ process.exit(1);
135
+ }
136
+ const defaultDir = join(resolvedPath, config.defaultLocale);
137
+ const localeDir = join(resolvedPath, locale);
138
+ if (!existsSync(defaultDir)) {
139
+ console.error(`Default locale directory not found: ${defaultDir}`);
140
+ process.exit(1);
141
+ }
142
+ const defaultFiles = findMdxFiles(defaultDir);
143
+ const missing = [];
144
+ for (const file of defaultFiles) {
145
+ const relPath = relative(defaultDir, file);
146
+ const localePath = join(localeDir, relPath);
147
+ if (!existsSync(localePath)) {
148
+ missing.push(relPath);
149
+ }
150
+ }
151
+ if (missing.length === 0) {
152
+ console.log(`All files translated for ${locale}!`);
153
+ return;
154
+ }
155
+ console.log(`Missing translations for ${locale} (${missing.length} files):`);
156
+ for (const file of missing) {
157
+ console.log(` ${file}`);
125
158
  }
126
159
  }
127
- if (missing.length === 0) {
128
- console.log(`All files translated for ${locale}!`);
129
- return;
130
- }
131
- console.log(`Missing translations for ${locale} (${missing.length} files):`);
132
- for (const file of missing) {
133
- console.log(` ${file}`);
160
+ catch (err) {
161
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
162
+ process.exit(1);
134
163
  }
135
164
  });
136
165
  i18nCommand
@@ -139,35 +168,41 @@ i18nCommand
139
168
  .argument('[docs-path]', 'Documentation directory', './docs')
140
169
  .option('-o, --output <file>', 'Output file', 'strings.json')
141
170
  .action((docsPath, options) => {
142
- const resolvedPath = resolve(docsPath);
143
- const config = loadI18nConfig(resolvedPath);
144
- const defaultDir = join(resolvedPath, config.defaultLocale);
145
- if (!existsSync(defaultDir)) {
146
- console.error(`Default locale directory not found: ${defaultDir}`);
147
- process.exit(1);
148
- }
149
- const files = findMdxFiles(defaultDir);
150
- const strings = {};
151
- for (const file of files) {
152
- const relPath = relative(defaultDir, file);
153
- const content = readFileSync(file, 'utf-8');
154
- const lines = content.split('\n');
155
- const fileStrings = {};
156
- for (const line of lines) {
157
- // Extract headings
158
- const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
159
- if (headingMatch) {
160
- const key = `heading_${Object.keys(fileStrings).length}`;
161
- fileStrings[key] = headingMatch[2];
162
- }
171
+ try {
172
+ const resolvedPath = resolve(docsPath);
173
+ const config = loadI18nConfig(resolvedPath);
174
+ const defaultDir = join(resolvedPath, config.defaultLocale);
175
+ if (!existsSync(defaultDir)) {
176
+ console.error(`Default locale directory not found: ${defaultDir}`);
177
+ process.exit(1);
163
178
  }
164
- if (Object.keys(fileStrings).length > 0) {
165
- strings[relPath] = fileStrings;
179
+ const files = findMdxFiles(defaultDir);
180
+ const strings = {};
181
+ for (const file of files) {
182
+ const relPath = relative(defaultDir, file);
183
+ const content = readFileSync(file, 'utf-8');
184
+ const lines = content.split('\n');
185
+ const fileStrings = {};
186
+ for (const line of lines) {
187
+ // Extract headings
188
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
189
+ if (headingMatch) {
190
+ const key = `heading_${Object.keys(fileStrings).length}`;
191
+ fileStrings[key] = headingMatch[2];
192
+ }
193
+ }
194
+ if (Object.keys(fileStrings).length > 0) {
195
+ strings[relPath] = fileStrings;
196
+ }
166
197
  }
198
+ const outputPath = resolve(options.output);
199
+ writeFileSync(outputPath, JSON.stringify(strings, null, 2));
200
+ console.log(`Extracted strings to: ${outputPath}`);
201
+ console.log(` Files: ${Object.keys(strings).length}`);
202
+ console.log(` Strings: ${Object.values(strings).reduce((a, b) => a + Object.keys(b).length, 0)}`);
203
+ }
204
+ catch (err) {
205
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
206
+ process.exit(1);
167
207
  }
168
- const outputPath = resolve(options.output);
169
- writeFileSync(outputPath, JSON.stringify(strings, null, 2));
170
- console.log(`Extracted strings to: ${outputPath}`);
171
- console.log(` Files: ${Object.keys(strings).length}`);
172
- console.log(` Strings: ${Object.values(strings).reduce((a, b) => a + Object.keys(b).length, 0)}`);
173
208
  });
@@ -198,55 +198,61 @@ export const lintCommand = new Command('lint')
198
198
  .option('--fix', 'Attempt to fix issues automatically')
199
199
  .option('-c, --config <file>', 'Config file with custom rules')
200
200
  .action(async (path, _options) => {
201
- const targetPath = resolve(path);
202
- if (!existsSync(targetPath)) {
203
- console.error(`Error: Path not found: ${targetPath}`);
204
- process.exit(1);
205
- }
206
- console.log('skrypt lint');
207
- console.log(` path: ${targetPath}`);
208
- console.log('');
209
- // Find all MDX files
210
- const files = statSync(targetPath).isDirectory()
211
- ? findMdxFiles(targetPath)
212
- : [targetPath];
213
- if (files.length === 0) {
214
- console.log('No .md or .mdx files found.');
215
- process.exit(0);
216
- }
217
- console.log(`Linting ${files.length} files...\n`);
218
- let totalErrors = 0;
219
- let totalWarnings = 0;
220
- const results = [];
221
- for (const file of files) {
222
- const result = lintFile(file);
223
- if (result.issues.length > 0) {
224
- results.push(result);
201
+ try {
202
+ const targetPath = resolve(path);
203
+ if (!existsSync(targetPath)) {
204
+ console.error(`Error: Path not found: ${targetPath}`);
205
+ process.exit(1);
206
+ }
207
+ console.log('skrypt lint');
208
+ console.log(` path: ${targetPath}`);
209
+ console.log('');
210
+ // Find all MDX files
211
+ const files = statSync(targetPath).isDirectory()
212
+ ? findMdxFiles(targetPath)
213
+ : [targetPath];
214
+ if (files.length === 0) {
215
+ console.log('No .md or .mdx files found.');
216
+ process.exit(0);
217
+ }
218
+ console.log(`Linting ${files.length} files...\n`);
219
+ let totalErrors = 0;
220
+ let totalWarnings = 0;
221
+ const results = [];
222
+ for (const file of files) {
223
+ const result = lintFile(file);
224
+ if (result.issues.length > 0) {
225
+ results.push(result);
226
+ for (const issue of result.issues) {
227
+ if (issue.severity === 'error')
228
+ totalErrors++;
229
+ else
230
+ totalWarnings++;
231
+ }
232
+ }
233
+ }
234
+ // Print results
235
+ for (const result of results) {
236
+ const relPath = result.file.replace(targetPath + '/', '');
237
+ console.log(`\n${relPath}`);
225
238
  for (const issue of result.issues) {
226
- if (issue.severity === 'error')
227
- totalErrors++;
228
- else
229
- totalWarnings++;
239
+ const icon = issue.severity === 'error' ? '✖' : '⚠';
240
+ const color = issue.severity === 'error' ? '\x1b[31m' : '\x1b[33m';
241
+ const reset = '\x1b[0m';
242
+ console.log(` ${color}${icon}${reset} ${issue.line}:${issue.column} ${issue.message} ${color}${issue.rule}${reset}`);
230
243
  }
231
244
  }
232
- }
233
- // Print results
234
- for (const result of results) {
235
- const relPath = result.file.replace(targetPath + '/', '');
236
- console.log(`\n${relPath}`);
237
- for (const issue of result.issues) {
238
- const icon = issue.severity === 'error' ? '✖' : '⚠';
239
- const color = issue.severity === 'error' ? '\x1b[31m' : '\x1b[33m';
240
- const reset = '\x1b[0m';
241
- console.log(` ${color}${icon}${reset} ${issue.line}:${issue.column} ${issue.message} ${color}${issue.rule}${reset}`);
245
+ // Summary
246
+ console.log('\n=== Summary ===');
247
+ console.log(` Files: ${files.length}`);
248
+ console.log(` Errors: ${totalErrors}`);
249
+ console.log(` Warnings: ${totalWarnings}`);
250
+ if (totalErrors > 0) {
251
+ process.exit(1);
242
252
  }
243
253
  }
244
- // Summary
245
- console.log('\n=== Summary ===');
246
- console.log(` Files: ${files.length}`);
247
- console.log(` Errors: ${totalErrors}`);
248
- console.log(` Warnings: ${totalWarnings}`);
249
- if (totalErrors > 0) {
254
+ catch (err) {
255
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
250
256
  process.exit(1);
251
257
  }
252
258
  });
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
- import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
3
- import { resolve, join, extname } from 'path';
2
+ import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, mkdirSync } from 'fs';
3
+ import { resolve, join, extname, dirname } from 'path';
4
4
  function extractFrontmatter(content) {
5
5
  const match = content.match(/^---\n([\s\S]*?)\n---/);
6
6
  if (!match)
@@ -136,54 +136,64 @@ export const llmsTxtCommand = new Command('llms-txt')
136
136
  .option('--title <title>', 'Documentation title', 'Documentation')
137
137
  .option('--description <desc>', 'Documentation description', 'API and usage documentation')
138
138
  .action(async (docsPath, options) => {
139
- const resolvedDocs = resolve(docsPath);
140
- const outputDir = resolve(options.output || './public');
141
- console.log('skrypt llms-txt');
142
- console.log(` docs: ${resolvedDocs}`);
143
- console.log(` output: ${outputDir}`);
144
- console.log(` base-url: ${options.baseUrl}`);
145
- console.log('');
146
- // Check if docs directory exists
147
- if (!existsSync(resolvedDocs)) {
148
- console.error(`Error: Documentation directory not found: ${resolvedDocs}`);
149
- process.exit(1);
139
+ try {
140
+ const resolvedDocs = resolve(docsPath);
141
+ const outputDir = resolve(options.output || './public');
142
+ console.log('skrypt llms-txt');
143
+ console.log(` docs: ${resolvedDocs}`);
144
+ console.log(` output: ${outputDir}`);
145
+ console.log(` base-url: ${options.baseUrl}`);
146
+ console.log('');
147
+ // Check if docs directory exists
148
+ if (!existsSync(resolvedDocs)) {
149
+ console.error(`Error: Documentation directory not found: ${resolvedDocs}`);
150
+ process.exit(1);
151
+ }
152
+ // Scan documentation
153
+ console.log('Step 1: Scanning documentation...');
154
+ const docs = walkDocs(resolvedDocs);
155
+ if (docs.length === 0) {
156
+ console.error('Error: No documentation files found');
157
+ process.exit(1);
158
+ }
159
+ console.log(` Found ${docs.length} documentation files`);
160
+ // Ensure output directory exists
161
+ mkdirSync(outputDir, { recursive: true });
162
+ // Generate llms.txt (summary)
163
+ console.log('\nStep 2: Generating llms.txt...');
164
+ const llmsTxt = generateLLMsTxt(docs, {
165
+ title: options.title || 'Documentation',
166
+ description: options.description || 'API and usage documentation',
167
+ baseUrl: options.baseUrl || 'https://docs.example.com'
168
+ });
169
+ const llmsTxtPath = join(outputDir, 'llms.txt');
170
+ mkdirSync(dirname(llmsTxtPath), { recursive: true });
171
+ writeFileSync(llmsTxtPath, llmsTxt);
172
+ console.log(` Written: ${llmsTxtPath}`);
173
+ // Generate llms-full.txt (complete content)
174
+ console.log('\nStep 3: Generating llms-full.txt...');
175
+ const llmsFullTxt = generateLLMsFullTxt(docs, {
176
+ title: options.title || 'Documentation',
177
+ description: options.description || 'API and usage documentation',
178
+ baseUrl: options.baseUrl || 'https://docs.example.com'
179
+ });
180
+ const llmsFullTxtPath = join(outputDir, 'llms-full.txt');
181
+ mkdirSync(dirname(llmsFullTxtPath), { recursive: true });
182
+ writeFileSync(llmsFullTxtPath, llmsFullTxt);
183
+ console.log(` Written: ${llmsFullTxtPath}`);
184
+ // Summary
185
+ console.log('\n=== Summary ===');
186
+ console.log(` Documentation files: ${docs.length}`);
187
+ console.log(` llms.txt: ${(llmsTxt.length / 1024).toFixed(1)} KB`);
188
+ console.log(` llms-full.txt: ${(llmsFullTxt.length / 1024).toFixed(1)} KB`);
189
+ console.log('');
190
+ console.log('Add these to your robots.txt:');
191
+ console.log(' Sitemap: /llms.txt');
192
+ console.log('');
193
+ console.log('AI agents (GPTBot, ClaudeBot, etc.) will automatically discover your docs!');
150
194
  }
151
- // Scan documentation
152
- console.log('Step 1: Scanning documentation...');
153
- const docs = walkDocs(resolvedDocs);
154
- if (docs.length === 0) {
155
- console.error('Error: No documentation files found');
195
+ catch (err) {
196
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
156
197
  process.exit(1);
157
198
  }
158
- console.log(` Found ${docs.length} documentation files`);
159
- // Generate llms.txt (summary)
160
- console.log('\nStep 2: Generating llms.txt...');
161
- const llmsTxt = generateLLMsTxt(docs, {
162
- title: options.title || 'Documentation',
163
- description: options.description || 'API and usage documentation',
164
- baseUrl: options.baseUrl || 'https://docs.example.com'
165
- });
166
- const llmsTxtPath = join(outputDir, 'llms.txt');
167
- writeFileSync(llmsTxtPath, llmsTxt);
168
- console.log(` Written: ${llmsTxtPath}`);
169
- // Generate llms-full.txt (complete content)
170
- console.log('\nStep 3: Generating llms-full.txt...');
171
- const llmsFullTxt = generateLLMsFullTxt(docs, {
172
- title: options.title || 'Documentation',
173
- description: options.description || 'API and usage documentation',
174
- baseUrl: options.baseUrl || 'https://docs.example.com'
175
- });
176
- const llmsFullTxtPath = join(outputDir, 'llms-full.txt');
177
- writeFileSync(llmsFullTxtPath, llmsFullTxt);
178
- console.log(` Written: ${llmsFullTxtPath}`);
179
- // Summary
180
- console.log('\n=== Summary ===');
181
- console.log(` Documentation files: ${docs.length}`);
182
- console.log(` llms.txt: ${(llmsTxt.length / 1024).toFixed(1)} KB`);
183
- console.log(` llms-full.txt: ${(llmsFullTxt.length / 1024).toFixed(1)} KB`);
184
- console.log('');
185
- console.log('Add these to your robots.txt:');
186
- console.log(' Sitemap: /llms.txt');
187
- console.log('');
188
- console.log('AI agents (GPTBot, ClaudeBot, etc.) will automatically discover your docs!');
189
199
  });
@@ -18,59 +18,77 @@ export const loginCommand = new Command('login')
18
18
  .description('Login to Skrypt Pro')
19
19
  .option('--key <api-key>', 'API key (or set SKRYPT_API_KEY env var)')
20
20
  .action(async (options) => {
21
- console.log('skrypt login\n');
22
- let apiKey = options.key || process.env.SKRYPT_API_KEY;
23
- if (!apiKey) {
24
- console.log(' Get your API key at: https://skrypt.sh/dashboard/settings\n');
25
- apiKey = await prompt(' Enter API key: ');
26
- }
27
- if (!apiKey) {
28
- console.error(' Error: No API key provided');
29
- process.exit(1);
21
+ try {
22
+ console.log('skrypt login\n');
23
+ let apiKey = options.key || process.env.SKRYPT_API_KEY;
24
+ if (!apiKey) {
25
+ console.log(' Get your API key at: https://skrypt.sh/dashboard/settings\n');
26
+ apiKey = await prompt(' Enter API key: ');
27
+ }
28
+ if (!apiKey) {
29
+ console.error(' Error: No API key provided');
30
+ process.exit(1);
31
+ }
32
+ console.log('\n Verifying...');
33
+ const result = await checkPlan(apiKey);
34
+ if (!result.valid) {
35
+ console.error(`\n Error: ${result.error || 'Invalid API key'}`);
36
+ process.exit(1);
37
+ }
38
+ await saveAuthConfig({
39
+ apiKey,
40
+ email: result.email,
41
+ plan: result.plan,
42
+ expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString()
43
+ });
44
+ console.log(`\n ✓ Logged in as ${result.email}`);
45
+ console.log(` Plan: ${result.plan.toUpperCase()}\n`);
46
+ // Trust signals
47
+ const storageMethod = await getKeyStorageMethod();
48
+ if (storageMethod === 'keychain') {
49
+ console.log(` 🔒 API key stored in ${getKeychainPlatformName()}`);
50
+ }
51
+ else if (storageMethod === 'file') {
52
+ console.log(' 🔒 API key stored in ~/.skrypt/auth.json (0600 permissions)');
53
+ }
54
+ console.log(' Your key is hashed (SHA-256) on our servers — never stored in plaintext');
55
+ console.log('');
56
+ if (result.plan === 'free') {
57
+ console.log(' Upgrade to Pro: https://skrypt.sh/pro\n');
58
+ }
30
59
  }
31
- console.log('\n Verifying...');
32
- const result = await checkPlan(apiKey);
33
- if (!result.valid) {
34
- console.error(`\n Error: ${result.error || 'Invalid API key'}`);
60
+ catch (err) {
61
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
35
62
  process.exit(1);
36
63
  }
37
- await saveAuthConfig({
38
- apiKey,
39
- email: result.email,
40
- plan: result.plan,
41
- expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString()
42
- });
43
- console.log(`\n ✓ Logged in as ${result.email}`);
44
- console.log(` Plan: ${result.plan.toUpperCase()}\n`);
45
- // Trust signals
46
- const storageMethod = await getKeyStorageMethod();
47
- if (storageMethod === 'keychain') {
48
- console.log(` 🔒 API key stored in ${getKeychainPlatformName()}`);
49
- }
50
- else if (storageMethod === 'file') {
51
- console.log(' 🔒 API key stored in ~/.skrypt/auth.json (0600 permissions)');
52
- }
53
- console.log(' Your key is hashed (SHA-256) on our servers — never stored in plaintext');
54
- console.log('');
55
- if (result.plan === 'free') {
56
- console.log(' Upgrade to Pro: https://skrypt.sh/pro\n');
57
- }
58
64
  });
59
65
  export const logoutCommand = new Command('logout')
60
66
  .description('Logout from Skrypt')
61
67
  .action(async () => {
62
- await clearAuth();
63
- console.log(' Logged out successfully\n');
68
+ try {
69
+ await clearAuth();
70
+ console.log(' Logged out successfully\n');
71
+ }
72
+ catch (err) {
73
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
74
+ process.exit(1);
75
+ }
64
76
  });
65
77
  export const whoamiCommand = new Command('whoami')
66
78
  .description('Show current login status')
67
79
  .action(async () => {
68
- const config = await getAuthConfigAsync();
69
- if (!config.apiKey) {
70
- console.log(' Not logged in');
71
- console.log(' Run: skrypt login\n');
72
- return;
80
+ try {
81
+ const config = await getAuthConfigAsync();
82
+ if (!config.apiKey) {
83
+ console.log(' Not logged in');
84
+ console.log(' Run: skrypt login\n');
85
+ return;
86
+ }
87
+ console.log(` Email: ${config.email || 'Unknown'}`);
88
+ console.log(` Plan: ${(config.plan || 'free').toUpperCase()}\n`);
89
+ }
90
+ catch (err) {
91
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
92
+ process.exit(1);
73
93
  }
74
- console.log(` Email: ${config.email || 'Unknown'}`);
75
- console.log(` Plan: ${(config.plan || 'free').toUpperCase()}\n`);
76
94
  });