skrypt-ai 0.3.4 → 0.4.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/README.md +1 -1
- package/dist/auth/index.d.ts +0 -1
- package/dist/auth/index.js +3 -5
- package/dist/autofix/index.js +15 -3
- package/dist/cli.js +19 -4
- package/dist/commands/check-links.js +164 -174
- package/dist/commands/deploy.js +5 -2
- package/dist/commands/generate.js +206 -199
- package/dist/commands/i18n.js +3 -20
- package/dist/commands/init.js +47 -40
- package/dist/commands/lint.js +3 -20
- package/dist/commands/mcp.js +125 -122
- package/dist/commands/monitor.js +125 -108
- package/dist/commands/review-pr.js +1 -1
- package/dist/commands/sdk.js +1 -1
- package/dist/config/loader.js +21 -2
- package/dist/generator/organizer.d.ts +3 -0
- package/dist/generator/organizer.js +4 -9
- package/dist/generator/writer.js +2 -10
- package/dist/github/pr-comments.js +21 -8
- package/dist/plugins/index.js +1 -0
- package/dist/scanner/index.js +8 -2
- package/dist/template/docs.json +2 -1
- package/dist/template/next.config.mjs +2 -1
- package/dist/template/package.json +17 -15
- package/dist/template/public/favicon.svg +4 -0
- package/dist/template/public/search-index.json +1 -1
- package/dist/template/scripts/build-search-index.mjs +120 -25
- package/dist/template/src/app/api/chat/route.ts +11 -3
- package/dist/template/src/app/docs/README.md +28 -0
- package/dist/template/src/app/docs/[...slug]/page.tsx +139 -16
- package/dist/template/src/app/docs/auth/page.mdx +589 -0
- package/dist/template/src/app/docs/autofix/page.mdx +624 -0
- package/dist/template/src/app/docs/cli/page.mdx +217 -0
- package/dist/template/src/app/docs/config/page.mdx +428 -0
- package/dist/template/src/app/docs/configuration/page.mdx +86 -0
- package/dist/template/src/app/docs/deployment/page.mdx +112 -0
- package/dist/template/src/app/docs/error.tsx +20 -0
- package/dist/template/src/app/docs/generator/generator.md +504 -0
- package/dist/template/src/app/docs/generator/organizer.md +779 -0
- package/dist/template/src/app/docs/generator/page.mdx +613 -0
- package/dist/template/src/app/docs/github/page.mdx +502 -0
- package/dist/template/src/app/docs/llm/anthropic-client.md +549 -0
- package/dist/template/src/app/docs/llm/index.md +471 -0
- package/dist/template/src/app/docs/llm/page.mdx +428 -0
- package/dist/template/src/app/docs/llms-full.md +256 -0
- package/dist/template/src/app/docs/llms.txt +2971 -0
- package/dist/template/src/app/docs/not-found.tsx +23 -0
- package/dist/template/src/app/docs/page.mdx +0 -3
- package/dist/template/src/app/docs/plugins/page.mdx +1793 -0
- package/dist/template/src/app/docs/pro/page.mdx +121 -0
- package/dist/template/src/app/docs/quickstart/page.mdx +93 -0
- package/dist/template/src/app/docs/scanner/content-type.md +599 -0
- package/dist/template/src/app/docs/scanner/index.md +212 -0
- package/dist/template/src/app/docs/scanner/page.mdx +307 -0
- package/dist/template/src/app/docs/scanner/python.md +469 -0
- package/dist/template/src/app/docs/scanner/python_parser.md +1056 -0
- package/dist/template/src/app/docs/scanner/rust.md +325 -0
- package/dist/template/src/app/docs/scanner/typescript.md +201 -0
- package/dist/template/src/app/error.tsx +3 -3
- package/dist/template/src/app/icon.tsx +29 -0
- package/dist/template/src/app/layout.tsx +42 -0
- package/dist/template/src/app/not-found.tsx +35 -0
- package/dist/template/src/app/page.tsx +62 -28
- package/dist/template/src/components/ai-chat.tsx +26 -21
- package/dist/template/src/components/breadcrumbs.tsx +46 -2
- package/dist/template/src/components/copy-button.tsx +17 -3
- package/dist/template/src/components/docs-layout.tsx +142 -8
- package/dist/template/src/components/feedback.tsx +4 -2
- package/dist/template/src/components/footer.tsx +42 -0
- package/dist/template/src/components/header.tsx +29 -5
- package/dist/template/src/components/mdx/accordion.tsx +7 -6
- package/dist/template/src/components/mdx/card.tsx +19 -7
- package/dist/template/src/components/mdx/code-block.tsx +17 -3
- package/dist/template/src/components/mdx/code-group.tsx +65 -18
- package/dist/template/src/components/mdx/code-playground.tsx +3 -0
- package/dist/template/src/components/mdx/go-playground.tsx +3 -0
- package/dist/template/src/components/mdx/highlighted-code.tsx +171 -76
- package/dist/template/src/components/mdx/python-playground.tsx +2 -0
- package/dist/template/src/components/mdx/tabs.tsx +74 -6
- package/dist/template/src/components/page-header.tsx +19 -0
- package/dist/template/src/components/scroll-to-top.tsx +33 -0
- package/dist/template/src/components/search-dialog.tsx +206 -52
- package/dist/template/src/components/sidebar.tsx +136 -77
- package/dist/template/src/components/table-of-contents.tsx +23 -7
- package/dist/template/src/lib/highlight.ts +90 -31
- package/dist/template/src/lib/search.ts +14 -4
- package/dist/template/src/lib/theme-utils.ts +140 -0
- package/dist/template/src/styles/globals.css +307 -166
- package/dist/template/src/types/remark-gfm.d.ts +2 -0
- package/dist/utils/files.d.ts +9 -0
- package/dist/utils/files.js +33 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.js +38 -0
- package/package.json +1 -4
package/README.md
CHANGED
package/dist/auth/index.d.ts
CHANGED
|
@@ -17,5 +17,4 @@ export declare function clearAuth(): void;
|
|
|
17
17
|
export declare function checkPlan(apiKey: string): Promise<PlanCheckResponse>;
|
|
18
18
|
export declare function requirePro(commandName: string): Promise<boolean>;
|
|
19
19
|
export declare const PRO_COMMANDS: string[];
|
|
20
|
-
export declare function isProCommand(command: string): boolean;
|
|
21
20
|
export {};
|
package/dist/auth/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
4
|
const CONFIG_DIR = join(homedir(), '.skrypt');
|
|
@@ -16,8 +16,9 @@ export function getAuthConfig() {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export function saveAuthConfig(config) {
|
|
19
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
19
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
20
20
|
writeFileSync(AUTH_FILE, JSON.stringify(config, null, 2));
|
|
21
|
+
chmodSync(AUTH_FILE, 0o600);
|
|
21
22
|
}
|
|
22
23
|
export function clearAuth() {
|
|
23
24
|
if (existsSync(AUTH_FILE)) {
|
|
@@ -89,6 +90,3 @@ export const PRO_COMMANDS = [
|
|
|
89
90
|
'ci',
|
|
90
91
|
'mcp'
|
|
91
92
|
];
|
|
92
|
-
export function isProCommand(command) {
|
|
93
|
-
return PRO_COMMANDS.includes(command);
|
|
94
|
-
}
|
package/dist/autofix/index.js
CHANGED
|
@@ -5,13 +5,25 @@
|
|
|
5
5
|
* - Free tier: 3 fix attempts per example
|
|
6
6
|
* - Pro tier: 10 fix attempts per example
|
|
7
7
|
*/
|
|
8
|
+
import ts from 'typescript';
|
|
8
9
|
/**
|
|
9
|
-
* Default TypeScript/JavaScript validator using
|
|
10
|
+
* Default TypeScript/JavaScript validator using TypeScript compiler
|
|
10
11
|
*/
|
|
11
12
|
async function defaultValidator(code) {
|
|
12
13
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const result = ts.transpileModule(code, {
|
|
15
|
+
compilerOptions: {
|
|
16
|
+
module: ts.ModuleKind.ESNext,
|
|
17
|
+
target: ts.ScriptTarget.ES2020,
|
|
18
|
+
},
|
|
19
|
+
reportDiagnostics: true,
|
|
20
|
+
});
|
|
21
|
+
if (result.diagnostics && result.diagnostics.length > 0) {
|
|
22
|
+
return {
|
|
23
|
+
valid: false,
|
|
24
|
+
errors: result.diagnostics.map(d => typeof d.messageText === 'string' ? d.messageText : d.messageText.messageText),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
15
27
|
return { valid: true, errors: [] };
|
|
16
28
|
}
|
|
17
29
|
catch (err) {
|
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,21 @@ import { loginCommand, logoutCommand, whoamiCommand } from './commands/login.js'
|
|
|
18
18
|
import { cronCommand } from './commands/cron.js';
|
|
19
19
|
import { deployCommand } from './commands/deploy.js';
|
|
20
20
|
import { testCommand } from './commands/test.js';
|
|
21
|
-
|
|
21
|
+
import { createRequire } from 'module';
|
|
22
|
+
process.on('uncaughtException', (err) => {
|
|
23
|
+
console.error('\x1b[31mFatal error:\x1b[0m', err.message);
|
|
24
|
+
if (process.env.DEBUG)
|
|
25
|
+
console.error(err.stack);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
process.on('unhandledRejection', (reason) => {
|
|
29
|
+
console.error('\x1b[31mUnhandled promise rejection:\x1b[0m', reason);
|
|
30
|
+
if (process.env.DEBUG)
|
|
31
|
+
console.error(reason);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
34
|
+
const require = createRequire(import.meta.url);
|
|
35
|
+
const { version: VERSION } = require('../package.json');
|
|
22
36
|
async function checkForUpdates() {
|
|
23
37
|
try {
|
|
24
38
|
const res = await fetch('https://registry.npmjs.org/skrypt-ai/latest', {
|
|
@@ -26,15 +40,16 @@ async function checkForUpdates() {
|
|
|
26
40
|
});
|
|
27
41
|
if (res.ok) {
|
|
28
42
|
const data = await res.json();
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
43
|
+
const version = data.version;
|
|
44
|
+
if (typeof version === 'string' && /^\d+\.\d+\.\d+/.test(version) && version !== VERSION) {
|
|
45
|
+
const latest = version;
|
|
31
46
|
console.log(`\n Update available: ${VERSION} → ${latest}`);
|
|
32
47
|
console.log(` Run: npm install -g skrypt-ai@latest\n`);
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
50
|
}
|
|
36
51
|
catch {
|
|
37
|
-
// Silently
|
|
52
|
+
// Silently ignore — non-blocking update check
|
|
38
53
|
}
|
|
39
54
|
}
|
|
40
55
|
const program = new Command();
|
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { existsSync, readFileSync
|
|
3
|
-
import { resolve,
|
|
4
|
-
|
|
5
|
-
const files = [];
|
|
6
|
-
function walk(currentDir) {
|
|
7
|
-
const entries = readdirSync(currentDir);
|
|
8
|
-
for (const entry of entries) {
|
|
9
|
-
const fullPath = join(currentDir, entry);
|
|
10
|
-
const stat = statSync(fullPath);
|
|
11
|
-
if (stat.isDirectory() && !entry.startsWith('.') && entry !== 'node_modules') {
|
|
12
|
-
walk(fullPath);
|
|
13
|
-
}
|
|
14
|
-
else if (stat.isFile() && (extname(entry) === '.mdx' || extname(entry) === '.md')) {
|
|
15
|
-
files.push(fullPath);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
walk(dir);
|
|
20
|
-
return files;
|
|
21
|
-
}
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { resolve, dirname, relative } from 'path';
|
|
4
|
+
import { findMdxFiles } from '../utils/files.js';
|
|
22
5
|
function extractLinks(content) {
|
|
23
6
|
const links = [];
|
|
24
7
|
const lines = content.split('\n');
|
|
@@ -109,178 +92,185 @@ export const checkLinksCommand = new Command('check-links')
|
|
|
109
92
|
.option('--external', 'Also check external links (slower)')
|
|
110
93
|
.option('--timeout <ms>', 'Timeout for external links', '5000')
|
|
111
94
|
.action(async (path, options) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
|
|
95
|
+
try {
|
|
96
|
+
const targetPath = resolve(path);
|
|
97
|
+
if (!existsSync(targetPath)) {
|
|
98
|
+
console.error(`Error: Path not found: ${targetPath}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
console.log('skrypt check-links');
|
|
102
|
+
console.log(` path: ${targetPath}`);
|
|
103
|
+
console.log(` external: ${options.external ? 'yes' : 'no'}`);
|
|
104
|
+
console.log('');
|
|
105
|
+
// Find all MDX files
|
|
106
|
+
const files = findMdxFiles(targetPath);
|
|
107
|
+
if (files.length === 0) {
|
|
108
|
+
console.log('No .md or .mdx files found.');
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
console.log(`Checking ${files.length} files...\n`);
|
|
112
|
+
// Build a map of all files and their anchors
|
|
113
|
+
const fileMap = new Map();
|
|
114
|
+
const allAnchors = new Map();
|
|
115
|
+
for (const file of files) {
|
|
116
|
+
const content = readFileSync(file, 'utf-8');
|
|
117
|
+
const anchors = extractAnchors(content);
|
|
118
|
+
allAnchors.set(file, anchors);
|
|
119
|
+
// Map various path formats to this file
|
|
120
|
+
const relPath = relative(targetPath, file);
|
|
121
|
+
const withoutExt = relPath.replace(/\.mdx?$/, '');
|
|
122
|
+
fileMap.set(relPath, anchors);
|
|
123
|
+
fileMap.set(withoutExt, anchors);
|
|
124
|
+
fileMap.set('/' + relPath, anchors);
|
|
125
|
+
fileMap.set('/' + withoutExt, anchors);
|
|
126
|
+
}
|
|
127
|
+
const brokenLinks = [];
|
|
128
|
+
const externalToCheck = [];
|
|
129
|
+
// Check all links in all files
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
const content = readFileSync(file, 'utf-8');
|
|
132
|
+
const links = extractLinks(content);
|
|
133
|
+
const fileDir = dirname(file);
|
|
134
|
+
const relFile = relative(targetPath, file);
|
|
135
|
+
for (const { link, line } of links) {
|
|
136
|
+
// Skip empty links
|
|
137
|
+
if (!link || link.trim() === '')
|
|
138
|
+
continue;
|
|
139
|
+
// External link
|
|
140
|
+
if (link.startsWith('http://') || link.startsWith('https://')) {
|
|
141
|
+
if (options.external) {
|
|
142
|
+
externalToCheck.push({ file: relFile, line, url: link });
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
159
145
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
146
|
+
// Mailto, tel, etc.
|
|
147
|
+
if (link.startsWith('mailto:') || link.startsWith('tel:') || link.startsWith('javascript:')) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Anchor-only link
|
|
151
|
+
if (link.startsWith('#')) {
|
|
152
|
+
const anchor = link.slice(1);
|
|
153
|
+
const fileAnchors = allAnchors.get(file) || new Set();
|
|
154
|
+
if (!fileAnchors.has(anchor)) {
|
|
155
|
+
brokenLinks.push({
|
|
156
|
+
file: relFile,
|
|
157
|
+
line,
|
|
158
|
+
link,
|
|
159
|
+
type: 'anchor',
|
|
160
|
+
reason: 'Anchor not found in file',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Internal link
|
|
166
|
+
let targetFile = link;
|
|
167
|
+
let targetAnchor = '';
|
|
168
|
+
// Split path and anchor
|
|
169
|
+
const hashIndex = link.indexOf('#');
|
|
170
|
+
if (hashIndex !== -1) {
|
|
171
|
+
targetFile = link.slice(0, hashIndex);
|
|
172
|
+
targetAnchor = link.slice(hashIndex + 1);
|
|
173
|
+
}
|
|
174
|
+
// Remove query string
|
|
175
|
+
const queryIndex = targetFile.indexOf('?');
|
|
176
|
+
if (queryIndex !== -1) {
|
|
177
|
+
targetFile = targetFile.slice(0, queryIndex);
|
|
178
|
+
}
|
|
179
|
+
// Resolve relative path
|
|
180
|
+
let resolvedPath;
|
|
181
|
+
if (targetFile.startsWith('/')) {
|
|
182
|
+
resolvedPath = targetFile.slice(1);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
resolvedPath = relative(targetPath, resolve(fileDir, targetFile));
|
|
186
|
+
}
|
|
187
|
+
// Check if file exists
|
|
188
|
+
const foundAnchors = fileMap.get(resolvedPath) ||
|
|
189
|
+
fileMap.get(resolvedPath + '.mdx') ||
|
|
190
|
+
fileMap.get(resolvedPath + '.md') ||
|
|
191
|
+
fileMap.get(resolvedPath + '/index') ||
|
|
192
|
+
fileMap.get(resolvedPath + '/index.mdx') ||
|
|
193
|
+
fileMap.get(resolvedPath + '/index.md');
|
|
194
|
+
if (!foundAnchors && !existsSync(resolve(targetPath, resolvedPath))) {
|
|
195
|
+
// Check for image/asset files
|
|
196
|
+
const assetPath = resolve(targetPath, resolvedPath);
|
|
197
|
+
if (!existsSync(assetPath)) {
|
|
198
|
+
brokenLinks.push({
|
|
199
|
+
file: relFile,
|
|
200
|
+
line,
|
|
201
|
+
link,
|
|
202
|
+
type: 'internal',
|
|
203
|
+
reason: 'File not found',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// Check anchor if specified
|
|
209
|
+
if (targetAnchor && foundAnchors && !foundAnchors.has(targetAnchor)) {
|
|
171
210
|
brokenLinks.push({
|
|
172
211
|
file: relFile,
|
|
173
212
|
line,
|
|
174
213
|
link,
|
|
175
214
|
type: 'anchor',
|
|
176
|
-
reason:
|
|
215
|
+
reason: `Anchor #${targetAnchor} not found in target`,
|
|
177
216
|
});
|
|
178
217
|
}
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
// Internal link
|
|
182
|
-
let targetFile = link;
|
|
183
|
-
let targetAnchor = '';
|
|
184
|
-
// Split path and anchor
|
|
185
|
-
const hashIndex = link.indexOf('#');
|
|
186
|
-
if (hashIndex !== -1) {
|
|
187
|
-
targetFile = link.slice(0, hashIndex);
|
|
188
|
-
targetAnchor = link.slice(hashIndex + 1);
|
|
189
|
-
}
|
|
190
|
-
// Remove query string
|
|
191
|
-
const queryIndex = targetFile.indexOf('?');
|
|
192
|
-
if (queryIndex !== -1) {
|
|
193
|
-
targetFile = targetFile.slice(0, queryIndex);
|
|
194
218
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fileMap.get(resolvedPath + '.mdx') ||
|
|
206
|
-
fileMap.get(resolvedPath + '.md') ||
|
|
207
|
-
fileMap.get(resolvedPath + '/index') ||
|
|
208
|
-
fileMap.get(resolvedPath + '/index.mdx') ||
|
|
209
|
-
fileMap.get(resolvedPath + '/index.md');
|
|
210
|
-
if (!foundAnchors && !existsSync(resolve(targetPath, resolvedPath))) {
|
|
211
|
-
// Check for image/asset files
|
|
212
|
-
const assetPath = resolve(targetPath, resolvedPath);
|
|
213
|
-
if (!existsSync(assetPath)) {
|
|
219
|
+
}
|
|
220
|
+
// Check external links if requested
|
|
221
|
+
if (options.external && externalToCheck.length > 0) {
|
|
222
|
+
console.log(`Checking ${externalToCheck.length} external links...\n`);
|
|
223
|
+
const timeout = Number(options.timeout) || 5000;
|
|
224
|
+
for (let i = 0; i < externalToCheck.length; i++) {
|
|
225
|
+
const { file, line, url } = externalToCheck[i];
|
|
226
|
+
process.stdout.write(`\r [${i + 1}/${externalToCheck.length}] ${url.slice(0, 50)}...`.padEnd(80));
|
|
227
|
+
const result = await checkExternalLink(url, timeout);
|
|
228
|
+
if (!result.ok) {
|
|
214
229
|
brokenLinks.push({
|
|
215
|
-
file
|
|
230
|
+
file,
|
|
216
231
|
line,
|
|
217
|
-
link,
|
|
218
|
-
type: '
|
|
219
|
-
reason:
|
|
232
|
+
link: url,
|
|
233
|
+
type: 'external',
|
|
234
|
+
reason: result.reason,
|
|
220
235
|
});
|
|
221
236
|
}
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
// Check anchor if specified
|
|
225
|
-
if (targetAnchor && foundAnchors && !foundAnchors.has(targetAnchor)) {
|
|
226
|
-
brokenLinks.push({
|
|
227
|
-
file: relFile,
|
|
228
|
-
line,
|
|
229
|
-
link,
|
|
230
|
-
type: 'anchor',
|
|
231
|
-
reason: `Anchor #${targetAnchor} not found in target`,
|
|
232
|
-
});
|
|
233
237
|
}
|
|
238
|
+
console.log('\n');
|
|
234
239
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (!
|
|
245
|
-
|
|
246
|
-
file,
|
|
247
|
-
line,
|
|
248
|
-
link: url,
|
|
249
|
-
type: 'external',
|
|
250
|
-
reason: result.reason,
|
|
251
|
-
});
|
|
240
|
+
// Print results
|
|
241
|
+
if (brokenLinks.length === 0) {
|
|
242
|
+
console.log('✓ No broken links found!');
|
|
243
|
+
process.exit(0);
|
|
244
|
+
}
|
|
245
|
+
console.log(`Found ${brokenLinks.length} broken links:\n`);
|
|
246
|
+
// Group by file
|
|
247
|
+
const byFile = new Map();
|
|
248
|
+
for (const link of brokenLinks) {
|
|
249
|
+
if (!byFile.has(link.file)) {
|
|
250
|
+
byFile.set(link.file, []);
|
|
252
251
|
}
|
|
252
|
+
byFile.get(link.file).push(link);
|
|
253
253
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
console.log(`Found ${brokenLinks.length} broken links:\n`);
|
|
262
|
-
// Group by file
|
|
263
|
-
const byFile = new Map();
|
|
264
|
-
for (const link of brokenLinks) {
|
|
265
|
-
if (!byFile.has(link.file)) {
|
|
266
|
-
byFile.set(link.file, []);
|
|
254
|
+
for (const [file, links] of byFile) {
|
|
255
|
+
console.log(`\n${file}`);
|
|
256
|
+
for (const link of links) {
|
|
257
|
+
const icon = link.type === 'external' ? '🌐' : link.type === 'anchor' ? '⚓' : '📄';
|
|
258
|
+
console.log(` ${icon} Line ${link.line}: ${link.link}`);
|
|
259
|
+
console.log(` └─ ${link.reason}`);
|
|
260
|
+
}
|
|
267
261
|
}
|
|
268
|
-
|
|
262
|
+
// Summary
|
|
263
|
+
console.log('\n=== Summary ===');
|
|
264
|
+
console.log(` Files checked: ${files.length}`);
|
|
265
|
+
console.log(` Broken links: ${brokenLinks.length}`);
|
|
266
|
+
console.log(` Internal: ${brokenLinks.filter(l => l.type === 'internal').length}`);
|
|
267
|
+
console.log(` Anchors: ${brokenLinks.filter(l => l.type === 'anchor').length}`);
|
|
268
|
+
console.log(` External: ${brokenLinks.filter(l => l.type === 'external').length}`);
|
|
269
|
+
process.exit(1);
|
|
269
270
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
console.log(` ${icon} Line ${link.line}: ${link.link}`);
|
|
275
|
-
console.log(` └─ ${link.reason}`);
|
|
276
|
-
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
273
|
+
console.error(`Error: ${message}`);
|
|
274
|
+
process.exit(1);
|
|
277
275
|
}
|
|
278
|
-
// Summary
|
|
279
|
-
console.log('\n=== Summary ===');
|
|
280
|
-
console.log(` Files checked: ${files.length}`);
|
|
281
|
-
console.log(` Broken links: ${brokenLinks.length}`);
|
|
282
|
-
console.log(` Internal: ${brokenLinks.filter(l => l.type === 'internal').length}`);
|
|
283
|
-
console.log(` Anchors: ${brokenLinks.filter(l => l.type === 'anchor').length}`);
|
|
284
|
-
console.log(` External: ${brokenLinks.filter(l => l.type === 'external').length}`);
|
|
285
|
-
process.exit(1);
|
|
286
276
|
});
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { spawnSync, spawn } from 'child_process';
|
|
3
3
|
import { existsSync, readFileSync, statSync } from 'fs';
|
|
4
4
|
import { resolve, join } from 'path';
|
|
5
5
|
import { homedir } from 'os';
|
|
@@ -113,9 +113,12 @@ async function bundleOutput(outDir) {
|
|
|
113
113
|
const bundlePath = join(outDir, '..', 'deploy-bundle.tar.gz');
|
|
114
114
|
console.log(' Creating deployment bundle...');
|
|
115
115
|
// Use tar to create a gzipped tarball
|
|
116
|
-
|
|
116
|
+
const tarResult = spawnSync('tar', ['-czf', bundlePath, '-C', outDir, '.'], {
|
|
117
117
|
stdio: 'pipe'
|
|
118
118
|
});
|
|
119
|
+
if (tarResult.status !== 0) {
|
|
120
|
+
throw new Error(`tar failed: ${tarResult.stderr?.toString() || 'unknown error'}`);
|
|
121
|
+
}
|
|
119
122
|
const stats = statSync(bundlePath);
|
|
120
123
|
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
121
124
|
console.log(` Bundle size: ${sizeMB} MB`);
|