docmk 1.0.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 (70) hide show
  1. package/.claude/skills/pdf/SKILL.md +89 -0
  2. package/.claude/skills/web-scraping/SKILL.md +78 -0
  3. package/CLAUDE.md +90 -0
  4. package/bin/docmk.js +3 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +636 -0
  7. package/dist/index.js.map +1 -0
  8. package/final-site/assets/main-B4orIFxK.css +1 -0
  9. package/final-site/assets/main-CSoKXua6.js +25 -0
  10. package/final-site/favicon.svg +4 -0
  11. package/final-site/index.html +26 -0
  12. package/final-site/robots.txt +4 -0
  13. package/final-site/sitemap.xml +14 -0
  14. package/my-docs/api/README.md +152 -0
  15. package/my-docs/api/advanced.md +260 -0
  16. package/my-docs/getting-started/README.md +24 -0
  17. package/my-docs/tutorials/README.md +272 -0
  18. package/my-docs/tutorials/customization.md +492 -0
  19. package/package.json +59 -0
  20. package/postcss.config.js +6 -0
  21. package/site/assets/main-BZUsYUCF.css +1 -0
  22. package/site/assets/main-q6laQtCD.js +114 -0
  23. package/site/favicon.svg +4 -0
  24. package/site/index.html +23 -0
  25. package/site/robots.txt +4 -0
  26. package/site/sitemap.xml +34 -0
  27. package/site-output/assets/main-B4orIFxK.css +1 -0
  28. package/site-output/assets/main-CSoKXua6.js +25 -0
  29. package/site-output/favicon.svg +4 -0
  30. package/site-output/index.html +26 -0
  31. package/site-output/robots.txt +4 -0
  32. package/site-output/sitemap.xml +14 -0
  33. package/src/builder/index.ts +189 -0
  34. package/src/builder/vite-dev.ts +117 -0
  35. package/src/cli/commands/build.ts +48 -0
  36. package/src/cli/commands/dev.ts +53 -0
  37. package/src/cli/commands/preview.ts +57 -0
  38. package/src/cli/index.ts +42 -0
  39. package/src/client/App.vue +15 -0
  40. package/src/client/components/SearchBox.vue +204 -0
  41. package/src/client/components/Sidebar.vue +18 -0
  42. package/src/client/components/SidebarItem.vue +108 -0
  43. package/src/client/index.html +21 -0
  44. package/src/client/layouts/AppLayout.vue +99 -0
  45. package/src/client/lib/utils.ts +6 -0
  46. package/src/client/main.ts +42 -0
  47. package/src/client/pages/Home.vue +279 -0
  48. package/src/client/pages/SkillPage.vue +565 -0
  49. package/src/client/router.ts +16 -0
  50. package/src/client/styles/global.css +92 -0
  51. package/src/client/utils/routes.ts +69 -0
  52. package/src/parser/index.ts +253 -0
  53. package/src/scanner/index.ts +127 -0
  54. package/src/types/index.ts +45 -0
  55. package/tailwind.config.js +65 -0
  56. package/test-build/assets/main-C2ARPC0e.css +1 -0
  57. package/test-build/assets/main-CHIQpV3B.js +25 -0
  58. package/test-build/favicon.svg +4 -0
  59. package/test-build/index.html +47 -0
  60. package/test-build/robots.txt +4 -0
  61. package/test-build/sitemap.xml +19 -0
  62. package/test-dist/assets/main-B4orIFxK.css +1 -0
  63. package/test-dist/assets/main-CSoKXua6.js +25 -0
  64. package/test-dist/favicon.svg +4 -0
  65. package/test-dist/index.html +26 -0
  66. package/test-dist/robots.txt +4 -0
  67. package/test-dist/sitemap.xml +14 -0
  68. package/tsconfig.json +30 -0
  69. package/tsup.config.ts +13 -0
  70. package/vite.config.ts +21 -0
@@ -0,0 +1,189 @@
1
+ import { build } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import path from 'path'
4
+ import fs from 'fs/promises'
5
+ import { DocGenConfig, BuildOptions } from '../types/index.js'
6
+
7
+ export async function buildSite(options: BuildOptions, config: DocGenConfig) {
8
+ console.log('šŸ—ļø Building documentation site...')
9
+
10
+ // Ensure output directory exists
11
+ await fs.mkdir(options.output, { recursive: true })
12
+
13
+ // Write config to a temporary file for the build process
14
+ const configPath = path.join(process.cwd(), 'temp-config.json')
15
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2))
16
+
17
+ try {
18
+ // Build the client application
19
+ await build({
20
+ root: path.resolve(process.cwd(), 'src/client'),
21
+ base: config.siteConfig.baseUrl,
22
+ build: {
23
+ outDir: options.output,
24
+ emptyOutDir: true,
25
+ rollupOptions: {
26
+ input: {
27
+ main: path.resolve(process.cwd(), 'src/client/index.html')
28
+ }
29
+ }
30
+ },
31
+ plugins: [
32
+ vue(),
33
+ // Plugin to inject config during build
34
+ {
35
+ name: 'docgen-build',
36
+ transformIndexHtml: {
37
+ order: 'pre',
38
+ handler(html) {
39
+ // Encode config as base64 with proper UTF-8 handling
40
+ const configJson = JSON.stringify(config)
41
+ // Use encodeURIComponent to handle UTF-8 properly before base64
42
+ const utf8Encoded = unescape(encodeURIComponent(configJson))
43
+ const configBase64 = Buffer.from(utf8Encoded, 'binary').toString('base64')
44
+ // Decode: atob -> decodeURIComponent(escape()) to restore UTF-8
45
+ const configScript = `<script>globalThis.__DOCGEN_CONFIG__=JSON.parse(decodeURIComponent(escape(atob("${configBase64}"))));</script>`
46
+ return html.replace('</head>', `${configScript}\n</head>`)
47
+ }
48
+ }
49
+ }
50
+ ],
51
+ resolve: {
52
+ alias: {
53
+ '@': path.resolve(process.cwd(), 'src/client')
54
+ }
55
+ },
56
+ define: {
57
+ __DOCGEN_CONFIG__: JSON.stringify(config)
58
+ }
59
+ })
60
+
61
+ // Generate additional static files
62
+ await generateSitemap(options.output, config)
63
+ await generateRobotsTxt(options.output, config)
64
+ await copyAssets(options.output)
65
+
66
+ console.log('āœ… Build completed successfully!')
67
+
68
+ } finally {
69
+ // Clean up temporary config file
70
+ try {
71
+ await fs.unlink(configPath)
72
+ } catch {
73
+ // Ignore if file doesn't exist
74
+ }
75
+ }
76
+ }
77
+
78
+ async function generateSitemap(outputDir: string, config: DocGenConfig) {
79
+ console.log('šŸ“„ Generating sitemap...')
80
+
81
+ const baseUrl = config.siteConfig.baseUrl.replace(/\/$/, '')
82
+ const urls: string[] = []
83
+
84
+ // Add home page
85
+ urls.push(`${baseUrl}/`)
86
+
87
+ // Add all skill pages
88
+ for (const file of config.files) {
89
+ const route = getFileRoute(file.path, config.siteConfig.skillsDir)
90
+ if (route !== '/') {
91
+ urls.push(`${baseUrl}${route}`)
92
+ }
93
+ }
94
+
95
+ const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
96
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
97
+ ${urls.map(url => ` <url>
98
+ <loc>${url}</loc>
99
+ <lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
100
+ <changefreq>weekly</changefreq>
101
+ <priority>0.8</priority>
102
+ </url>`).join('\\n')}
103
+ </urlset>`
104
+
105
+ await fs.writeFile(path.join(outputDir, 'sitemap.xml'), sitemap)
106
+ }
107
+
108
+ async function generateRobotsTxt(outputDir: string, config: DocGenConfig) {
109
+ console.log('šŸ¤– Generating robots.txt...')
110
+
111
+ const baseUrl = config.siteConfig.baseUrl.replace(/\/$/, '')
112
+ const robotsTxt = `User-agent: *
113
+ Allow: /
114
+
115
+ Sitemap: ${baseUrl}/sitemap.xml`
116
+
117
+ await fs.writeFile(path.join(outputDir, 'robots.txt'), robotsTxt)
118
+ }
119
+
120
+ async function copyAssets(outputDir: string) {
121
+ console.log('šŸ“ Copying static assets...')
122
+
123
+ // Create a simple favicon if it doesn't exist
124
+ const faviconPath = path.join(outputDir, 'favicon.ico')
125
+
126
+ try {
127
+ await fs.access(faviconPath)
128
+ } catch {
129
+ // Create a simple SVG favicon
130
+ const faviconSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
131
+ <rect width="32" height="32" rx="4" fill="#3182ce"/>
132
+ <text x="16" y="22" text-anchor="middle" fill="white" font-family="system-ui" font-size="18" font-weight="bold">D</text>
133
+ </svg>`
134
+
135
+ await fs.writeFile(path.join(outputDir, 'favicon.svg'), faviconSvg)
136
+ }
137
+ }
138
+
139
+ function getFileRoute(filePath: string, baseDir: string): string {
140
+ // Normalize paths for comparison
141
+ const normalizedFilePath = path.normalize(filePath)
142
+ const normalizedBaseDir = path.normalize(baseDir)
143
+
144
+ // Check if file is within base directory
145
+ if (!normalizedFilePath.startsWith(normalizedBaseDir)) {
146
+ return '/'
147
+ }
148
+
149
+ // Get relative path from base directory
150
+ const relativePath = normalizedFilePath.slice(normalizedBaseDir.length)
151
+ const segments = relativePath.split(path.sep).filter(Boolean)
152
+
153
+ if (segments.length === 0) return '/'
154
+
155
+ const lastSegment = segments[segments.length - 1]
156
+ if (lastSegment.endsWith('.md')) {
157
+ segments[segments.length - 1] = lastSegment.slice(0, -3)
158
+ }
159
+
160
+ // SKILL.md and README.md should map to parent directory route
161
+ const finalSegment = segments[segments.length - 1]
162
+ if (finalSegment === 'SKILL' || finalSegment === 'README') {
163
+ segments.pop()
164
+ }
165
+
166
+ return '/' + segments.join('/')
167
+ }
168
+
169
+ export async function buildForProduction(sourceDir: string, outputDir: string): Promise<DocGenConfig> {
170
+ const { scanSkillsDirectory } = await import('../scanner/index.js')
171
+ const { parseSkillsToConfig } = await import('../parser/index.js')
172
+
173
+ const directories = await scanSkillsDirectory(sourceDir)
174
+ const config = await parseSkillsToConfig(directories, {
175
+ title: 'Documentation',
176
+ description: 'Documentation generated from source directory',
177
+ baseUrl: '/',
178
+ skillsDir: sourceDir,
179
+ outputDir
180
+ })
181
+
182
+ await buildSite({
183
+ input: sourceDir,
184
+ output: outputDir,
185
+ mode: 'production'
186
+ }, config)
187
+
188
+ return config
189
+ }
@@ -0,0 +1,117 @@
1
+ import { createServer, ViteDevServer } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import path from 'path'
4
+ import { DocGenConfig } from '../types/index.js'
5
+ import { scanSkillsDirectory, watchSkillsDirectory } from '../scanner/index.js'
6
+ import { parseSkillsToConfig } from '../parser/index.js'
7
+
8
+ interface DevServerOptions {
9
+ port: number
10
+ skillsDir: string
11
+ config: DocGenConfig
12
+ }
13
+
14
+ export async function createViteDevServer(options: DevServerOptions): Promise<ViteDevServer> {
15
+ let currentConfig = options.config
16
+
17
+ const server = await createServer({
18
+ root: path.resolve(process.cwd(), 'src/client'),
19
+ server: {
20
+ port: options.port,
21
+ host: 'localhost'
22
+ },
23
+ plugins: [
24
+ vue(),
25
+ // Custom plugin to inject config and handle API routes
26
+ {
27
+ name: 'docgen-dev',
28
+ configureServer(server) {
29
+ // API endpoint for configuration
30
+ server.middlewares.use('/api/config', (req, res, next) => {
31
+ if (req.method === 'GET') {
32
+ res.setHeader('Content-Type', 'application/json')
33
+ res.end(JSON.stringify(currentConfig))
34
+ } else {
35
+ next()
36
+ }
37
+ })
38
+
39
+ // Inject config into HTML
40
+ server.middlewares.use((req, res, next) => {
41
+ if (req.url === '/' || req.url === '/index.html') {
42
+ // Let Vite handle the HTML transformation
43
+ next()
44
+ } else {
45
+ next()
46
+ }
47
+ })
48
+ },
49
+ transformIndexHtml: {
50
+ order: 'pre',
51
+ handler(html) {
52
+ // Inject lightweight config placeholder
53
+ // Full config will be loaded via API to avoid HTML parsing issues
54
+ const configScript = `
55
+ <script>
56
+ // Config will be loaded from /api/config
57
+ globalThis.__DOCGEN_CONFIG__ = null;
58
+ </script>
59
+ `
60
+ return html.replace('<head>', `<head>${configScript}`)
61
+ }
62
+ }
63
+ }
64
+ ],
65
+ resolve: {
66
+ alias: {
67
+ '@': path.resolve(process.cwd(), 'src/client')
68
+ }
69
+ },
70
+ define: {
71
+ __DOCGEN_CONFIG__: JSON.stringify(currentConfig)
72
+ }
73
+ })
74
+
75
+ // Watch skills directory for changes
76
+ const watcher = await watchSkillsDirectory(options.skillsDir, async (directories) => {
77
+ console.log('šŸ“ Skills directory changed, updating configuration...')
78
+
79
+ try {
80
+ currentConfig = await parseSkillsToConfig(directories, currentConfig.siteConfig)
81
+
82
+ // Notify all connected clients to reload
83
+ server.ws.send({
84
+ type: 'full-reload'
85
+ })
86
+
87
+ console.log('āœ… Configuration updated')
88
+ } catch (error) {
89
+ console.error('āŒ Failed to update configuration:', error)
90
+
91
+ // Send error to clients
92
+ server.ws.send({
93
+ type: 'error',
94
+ err: {
95
+ message: `Failed to update configuration: ${error.message}`,
96
+ stack: error.stack
97
+ }
98
+ })
99
+ }
100
+ })
101
+
102
+ // Start the server
103
+ await server.listen()
104
+
105
+ // Extend server with cleanup method
106
+ const originalClose = server.close.bind(server)
107
+ server.close = async () => {
108
+ await watcher?.close()
109
+ return originalClose()
110
+ }
111
+
112
+ return server
113
+ }
114
+
115
+ export async function createProductionBuild() {
116
+ // This will be implemented in the builder
117
+ }
@@ -0,0 +1,48 @@
1
+ import path from 'path'
2
+ import { buildSite } from '../../builder/index.js'
3
+ import { scanSkillsDirectory } from '../../scanner/index.js'
4
+ import { parseSkillsToConfig } from '../../parser/index.js'
5
+
6
+ interface BuildOptions {
7
+ dir: string
8
+ output: string
9
+ }
10
+
11
+ export async function buildCommand(options: BuildOptions) {
12
+ console.log('šŸ—ļø Building DocGen documentation site...')
13
+
14
+ const sourceDir = path.resolve(process.cwd(), options.dir)
15
+ const outputDir = path.resolve(process.cwd(), options.output)
16
+
17
+ try {
18
+ // Scan source directory
19
+ console.log(`šŸ“ Scanning source directory: ${sourceDir}`)
20
+ const directories = await scanSkillsDirectory(sourceDir)
21
+
22
+ console.log(`āœ… Found ${directories.length} directories`)
23
+
24
+ // Parse to config
25
+ const config = await parseSkillsToConfig(directories, {
26
+ title: 'Documentation',
27
+ description: 'Documentation generated from source directory',
28
+ baseUrl: '/',
29
+ skillsDir: sourceDir,
30
+ outputDir
31
+ })
32
+
33
+ // Build site
34
+ console.log(`šŸ“¦ Building to: ${outputDir}`)
35
+ await buildSite({
36
+ input: sourceDir,
37
+ output: outputDir,
38
+ mode: 'production'
39
+ }, config)
40
+
41
+ console.log('āœ… Build completed successfully!')
42
+ console.log(`šŸ“‚ Built files are in: ${outputDir}`)
43
+
44
+ } catch (error) {
45
+ console.error('āŒ Build failed:', error)
46
+ process.exit(1)
47
+ }
48
+ }
@@ -0,0 +1,53 @@
1
+ import path from 'path'
2
+ import { createViteDevServer } from '../../builder/vite-dev.js'
3
+ import { scanSkillsDirectory } from '../../scanner/index.js'
4
+ import { parseSkillsToConfig } from '../../parser/index.js'
5
+
6
+ interface DevOptions {
7
+ port: string
8
+ dir: string
9
+ }
10
+
11
+ export async function devCommand(options: DevOptions) {
12
+ console.log('šŸš€ Starting DocGen development server...')
13
+
14
+ const sourceDir = path.resolve(process.cwd(), options.dir)
15
+ const port = parseInt(options.port, 10)
16
+
17
+ try {
18
+ // Check if source directory exists
19
+ console.log(`šŸ“ Scanning source directory: ${sourceDir}`)
20
+ const directories = await scanSkillsDirectory(sourceDir)
21
+
22
+ console.log(`āœ… Found ${directories.length} directories`)
23
+
24
+ // Parse to config
25
+ const config = await parseSkillsToConfig(directories, {
26
+ title: 'Documentation',
27
+ description: 'Documentation generated from source directory',
28
+ baseUrl: '/',
29
+ skillsDir: sourceDir,
30
+ outputDir: 'dist'
31
+ })
32
+
33
+ // Start Vite dev server
34
+ const server = await createViteDevServer({
35
+ port,
36
+ skillsDir: sourceDir,
37
+ config
38
+ })
39
+
40
+ console.log(`šŸŽ‰ Dev server running at http://localhost:${port}`)
41
+
42
+ // Handle graceful shutdown
43
+ process.on('SIGINT', async () => {
44
+ console.log('\\nšŸ‘‹ Shutting down dev server...')
45
+ await server.close()
46
+ process.exit(0)
47
+ })
48
+
49
+ } catch (error) {
50
+ console.error('āŒ Failed to start dev server:', error)
51
+ process.exit(1)
52
+ }
53
+ }
@@ -0,0 +1,57 @@
1
+ import path from 'path'
2
+ import fs from 'fs/promises'
3
+ import sirv from 'sirv'
4
+ import { createServer } from 'http'
5
+
6
+ interface PreviewOptions {
7
+ port: string
8
+ output: string
9
+ }
10
+
11
+ export async function previewCommand(options: PreviewOptions) {
12
+ console.log('šŸ‘€ Starting DocGen preview server...')
13
+
14
+ const outputDir = path.resolve(process.cwd(), options.output)
15
+ const port = parseInt(options.port, 10)
16
+
17
+ try {
18
+ // Check if build directory exists
19
+ try {
20
+ await fs.access(outputDir)
21
+ } catch {
22
+ console.error(`āŒ Build directory not found: ${outputDir}`)
23
+ console.log('šŸ’” Run "docgen build" first to generate the static site')
24
+ process.exit(1)
25
+ }
26
+
27
+ // Create static file server
28
+ const serve = sirv(outputDir, {
29
+ single: true, // SPA mode
30
+ dev: false,
31
+ setHeaders: (res, pathname) => {
32
+ if (pathname.endsWith('.html') || pathname === '/') {
33
+ res.setHeader('Content-Type', 'text/html; charset=utf-8')
34
+ }
35
+ }
36
+ })
37
+
38
+ const server = createServer(serve)
39
+
40
+ server.listen(port, () => {
41
+ console.log(`šŸŽ‰ Preview server running at http://localhost:${port}`)
42
+ console.log(`šŸ“‚ Serving files from: ${outputDir}`)
43
+ })
44
+
45
+ // Handle graceful shutdown
46
+ process.on('SIGINT', () => {
47
+ console.log('\\nšŸ‘‹ Shutting down preview server...')
48
+ server.close(() => {
49
+ process.exit(0)
50
+ })
51
+ })
52
+
53
+ } catch (error) {
54
+ console.error('āŒ Failed to start preview server:', error)
55
+ process.exit(1)
56
+ }
57
+ }
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander'
4
+ import { devCommand } from './commands/dev.js'
5
+ import { buildCommand } from './commands/build.js'
6
+ import { previewCommand } from './commands/preview.js'
7
+
8
+ const program = new Command()
9
+
10
+ program
11
+ .name('docmk')
12
+ .description('CLI tool for generating documentation from any directory')
13
+ .version('1.0.0')
14
+ .argument('[directory]', 'Source directory path (starts dev server)', './docs')
15
+ .option('-p, --port <port>', 'Port to run dev server on', '3000')
16
+ .action((directory, options) => {
17
+ // Default action: start dev server
18
+ devCommand({ dir: directory, port: options.port })
19
+ })
20
+
21
+ program
22
+ .command('dev')
23
+ .description('Start development server')
24
+ .option('-p, --port <port>', 'Port to run dev server on', '3000')
25
+ .option('-d, --dir <directory>', 'Source directory path', './docs')
26
+ .action(devCommand)
27
+
28
+ program
29
+ .command('build')
30
+ .description('Build static documentation site')
31
+ .option('-d, --dir <directory>', 'Source directory path', './docs')
32
+ .option('-o, --output <directory>', 'Output directory', 'dist')
33
+ .action(buildCommand)
34
+
35
+ program
36
+ .command('preview')
37
+ .description('Preview built documentation site')
38
+ .option('-p, --port <port>', 'Port to run preview server on', '4173')
39
+ .option('-o, --output <directory>', 'Built site directory', 'dist')
40
+ .action(previewCommand)
41
+
42
+ program.parse()
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div id="app">
3
+ <AppLayout />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import AppLayout from './layouts/AppLayout.vue'
9
+ </script>
10
+
11
+ <style scoped>
12
+ #app {
13
+ min-height: 100vh;
14
+ }
15
+ </style>