@zenithbuild/core 0.6.2 → 0.6.4

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 (112) hide show
  1. package/CORE_CONTRACT.md +145 -0
  2. package/README.md +14 -29
  3. package/bin/zenith.js +89 -0
  4. package/package.json +39 -56
  5. package/src/config.js +136 -0
  6. package/src/core-template.js +30 -0
  7. package/src/errors.js +54 -0
  8. package/src/guards.js +61 -0
  9. package/src/hash.js +52 -0
  10. package/src/index.js +26 -0
  11. package/src/ir/index.js +1 -0
  12. package/src/order.js +69 -0
  13. package/src/path.js +131 -0
  14. package/src/schema.js +28 -0
  15. package/src/version.js +67 -0
  16. package/bin/zen-build.ts +0 -2
  17. package/bin/zen-dev.ts +0 -2
  18. package/bin/zen-preview.ts +0 -2
  19. package/bin/zenith.ts +0 -2
  20. package/cli/commands/add.ts +0 -37
  21. package/cli/commands/build.ts +0 -37
  22. package/cli/commands/create.ts +0 -702
  23. package/cli/commands/dev.ts +0 -388
  24. package/cli/commands/index.ts +0 -112
  25. package/cli/commands/preview.ts +0 -62
  26. package/cli/commands/remove.ts +0 -33
  27. package/cli/index.ts +0 -10
  28. package/cli/main.ts +0 -101
  29. package/cli/utils/branding.ts +0 -178
  30. package/cli/utils/content.ts +0 -112
  31. package/cli/utils/logger.ts +0 -46
  32. package/cli/utils/plugin-manager.ts +0 -114
  33. package/cli/utils/project.ts +0 -77
  34. package/compiler/README.md +0 -380
  35. package/compiler/build-analyzer.ts +0 -122
  36. package/compiler/css/index.ts +0 -317
  37. package/compiler/discovery/componentDiscovery.ts +0 -178
  38. package/compiler/discovery/layouts.ts +0 -70
  39. package/compiler/errors/compilerError.ts +0 -56
  40. package/compiler/finalize/finalizeOutput.ts +0 -192
  41. package/compiler/finalize/generateFinalBundle.ts +0 -82
  42. package/compiler/index.ts +0 -83
  43. package/compiler/ir/types.ts +0 -174
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/importTypes.ts +0 -78
  47. package/compiler/parse/parseImports.ts +0 -309
  48. package/compiler/parse/parseScript.ts +0 -46
  49. package/compiler/parse/parseTemplate.ts +0 -599
  50. package/compiler/parse/parseZenFile.ts +0 -66
  51. package/compiler/parse/scriptAnalysis.ts +0 -91
  52. package/compiler/parse/trackLoopContext.ts +0 -82
  53. package/compiler/runtime/dataExposure.ts +0 -317
  54. package/compiler/runtime/generateDOM.ts +0 -246
  55. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  56. package/compiler/runtime/hydration.ts +0 -309
  57. package/compiler/runtime/navigation.ts +0 -432
  58. package/compiler/runtime/thinRuntime.ts +0 -160
  59. package/compiler/runtime/transformIR.ts +0 -370
  60. package/compiler/runtime/wrapExpression.ts +0 -95
  61. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  62. package/compiler/spa-build.ts +0 -917
  63. package/compiler/ssg-build.ts +0 -422
  64. package/compiler/test/validate-test.ts +0 -104
  65. package/compiler/transform/classifyExpression.ts +0 -444
  66. package/compiler/transform/componentResolver.ts +0 -312
  67. package/compiler/transform/componentScriptTransformer.ts +0 -303
  68. package/compiler/transform/expressionTransformer.ts +0 -385
  69. package/compiler/transform/fragmentLowering.ts +0 -634
  70. package/compiler/transform/generateBindings.ts +0 -47
  71. package/compiler/transform/generateHTML.ts +0 -28
  72. package/compiler/transform/layoutProcessor.ts +0 -132
  73. package/compiler/transform/slotResolver.ts +0 -292
  74. package/compiler/transform/transformNode.ts +0 -126
  75. package/compiler/transform/transformTemplate.ts +0 -38
  76. package/compiler/validate/invariants.ts +0 -292
  77. package/compiler/validate/validateExpressions.ts +0 -168
  78. package/core/config/index.ts +0 -16
  79. package/core/config/loader.ts +0 -69
  80. package/core/config/types.ts +0 -89
  81. package/core/index.ts +0 -135
  82. package/core/lifecycle/index.ts +0 -49
  83. package/core/lifecycle/zen-mount.ts +0 -182
  84. package/core/lifecycle/zen-unmount.ts +0 -88
  85. package/core/plugins/index.ts +0 -7
  86. package/core/plugins/registry.ts +0 -81
  87. package/core/reactivity/index.ts +0 -54
  88. package/core/reactivity/tracking.ts +0 -167
  89. package/core/reactivity/zen-batch.ts +0 -57
  90. package/core/reactivity/zen-effect.ts +0 -139
  91. package/core/reactivity/zen-memo.ts +0 -146
  92. package/core/reactivity/zen-ref.ts +0 -52
  93. package/core/reactivity/zen-signal.ts +0 -121
  94. package/core/reactivity/zen-state.ts +0 -180
  95. package/core/reactivity/zen-untrack.ts +0 -44
  96. package/dist/cli.js +0 -11665
  97. package/dist/zen-build.js +0 -21172
  98. package/dist/zen-dev.js +0 -21172
  99. package/dist/zen-preview.js +0 -21172
  100. package/dist/zenith.js +0 -21172
  101. package/router/index.ts +0 -28
  102. package/router/manifest.ts +0 -314
  103. package/router/navigation/ZenLink.zen +0 -231
  104. package/router/navigation/index.ts +0 -78
  105. package/router/navigation/zen-link.ts +0 -584
  106. package/router/runtime.ts +0 -458
  107. package/router/types.ts +0 -168
  108. package/runtime/build.ts +0 -17
  109. package/runtime/bundle-generator.ts +0 -1247
  110. package/runtime/client-runtime.ts +0 -549
  111. package/runtime/serve.ts +0 -93
  112. package/tsconfig.json +0 -28
@@ -1,388 +0,0 @@
1
- import path from 'path'
2
- import fs from 'fs'
3
- import { serve, type ServerWebSocket } from 'bun'
4
- import { requireProject } from '../utils/project'
5
- import * as logger from '../utils/logger'
6
- import * as brand from '../utils/branding'
7
- import { compileZenSource } from '../../compiler/index'
8
- import { discoverLayouts } from '../../compiler/discovery/layouts'
9
- import { processLayout } from '../../compiler/transform/layoutProcessor'
10
- import { generateRouteDefinition } from '../../router/manifest'
11
- import { generateBundleJS } from '../../runtime/bundle-generator'
12
- import { loadContent } from '../utils/content'
13
- import { loadZenithConfig } from '../../core/config/loader'
14
- import { PluginRegistry, createPluginContext } from '../../core/plugins/registry'
15
- import type { ContentItem } from '../../core/config/types'
16
- import { compileCssAsync, resolveGlobalsCss } from '../../compiler/css'
17
-
18
- export interface DevOptions {
19
- port?: number
20
- }
21
-
22
- interface CompiledPage {
23
- html: string
24
- script: string
25
- styles: string[]
26
- route: string
27
- lastModified: number
28
- }
29
-
30
- const pageCache = new Map<string, CompiledPage>()
31
-
32
- /**
33
- * Bundle page script using Bun's bundler to resolve npm imports at compile time.
34
- * This allows ES module imports like `import { gsap } from 'gsap'` to work.
35
- */
36
- async function bundlePageScript(script: string, projectRoot: string): Promise<string> {
37
- // If no import statements, return as-is
38
- if (!script.includes('import ')) {
39
- return script
40
- }
41
-
42
- // Write temp file in PROJECT directory so Bun can find node_modules
43
- const tempDir = path.join(projectRoot, '.zenith-cache')
44
- if (!fs.existsSync(tempDir)) {
45
- fs.mkdirSync(tempDir, { recursive: true })
46
- }
47
- const tempFile = path.join(tempDir, `bundle-${Date.now()}.js`)
48
-
49
- try {
50
- // Write script to temp file
51
- fs.writeFileSync(tempFile, script, 'utf-8')
52
-
53
- // Use Bun.build to bundle with npm resolution from project's node_modules
54
- const result = await Bun.build({
55
- entrypoints: [tempFile],
56
- target: 'browser',
57
- format: 'esm',
58
- minify: false,
59
- external: [], // Bundle everything
60
- })
61
-
62
- if (!result.success || !result.outputs[0]) {
63
- console.error('[Zenith] Bundle errors:', result.logs)
64
- return script // Fall back to original
65
- }
66
-
67
- // Get the bundled output
68
- const bundledCode = await result.outputs[0].text()
69
- return bundledCode
70
- } catch (error: any) {
71
- console.error('[Zenith] Failed to bundle page script:', error.message)
72
- return script // Fall back to original
73
- } finally {
74
- // Clean up temp file
75
- try {
76
- fs.unlinkSync(tempFile)
77
- } catch { }
78
- }
79
- }
80
-
81
- export async function dev(options: DevOptions = {}): Promise<void> {
82
- const project = requireProject()
83
- const port = options.port || parseInt(process.env.PORT || '3000', 10)
84
- const pagesDir = project.pagesDir
85
- const rootDir = project.root
86
- const contentDir = path.join(rootDir, 'content')
87
-
88
- // Load zenith.config.ts if present
89
- const config = await loadZenithConfig(rootDir)
90
- const registry = new PluginRegistry()
91
-
92
- console.log('[Zenith] Config plugins:', config.plugins?.length ?? 0)
93
-
94
- // Register plugins from config
95
- for (const plugin of config.plugins || []) {
96
- console.log('[Zenith] Registering plugin:', plugin.name)
97
- registry.register(plugin)
98
- }
99
-
100
- // Initialize content data
101
- let contentData: Record<string, ContentItem[]> = {}
102
-
103
- // Initialize plugins with context
104
- const hasContentPlugin = registry.has('zenith-content')
105
- console.log('[Zenith] Has zenith-content plugin:', hasContentPlugin)
106
-
107
- if (hasContentPlugin) {
108
- await registry.initAll(createPluginContext(rootDir, (data) => {
109
- console.log('[Zenith] Content plugin set data, collections:', Object.keys(data))
110
- contentData = data
111
- }))
112
- } else {
113
- // Fallback to legacy content loading if no content plugin configured
114
- console.log('[Zenith] Using legacy content loading from:', contentDir)
115
- contentData = loadContent(contentDir)
116
- }
117
-
118
- console.log('[Zenith] Content collections loaded:', Object.keys(contentData))
119
-
120
- // ============================================
121
- // CSS Compilation (Compiler-Owned)
122
- // ============================================
123
- const globalsCssPath = resolveGlobalsCss(rootDir)
124
- let compiledCss = ''
125
-
126
- if (globalsCssPath) {
127
- console.log('[Zenith] Compiling CSS:', path.relative(rootDir, globalsCssPath))
128
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
129
- if (cssResult.success) {
130
- compiledCss = cssResult.css
131
- console.log(`[Zenith] CSS compiled in ${cssResult.duration}ms`)
132
- } else {
133
- console.error('[Zenith] CSS compilation failed:', cssResult.error)
134
- }
135
- }
136
-
137
- const clients = new Set<ServerWebSocket<unknown>>()
138
-
139
- // Branded Startup Panel
140
- brand.showServerPanel({
141
- project: project.root,
142
- pages: project.pagesDir,
143
- url: `http://localhost:${port}`,
144
- hmr: true,
145
- mode: 'In-memory compilation'
146
- })
147
-
148
- // File extensions that should be served as static assets
149
- const STATIC_EXTENSIONS = new Set([
150
- '.js', '.css', '.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg',
151
- '.webp', '.woff', '.woff2', '.ttf', '.eot', '.json', '.map'
152
- ])
153
-
154
- /**
155
- * Compile a .zen page in memory
156
- */
157
- async function compilePageInMemory(pagePath: string): Promise<CompiledPage | null> {
158
- try {
159
- const layoutsDir = path.join(pagesDir, '../layouts')
160
- const componentsDir = path.join(pagesDir, '../components')
161
- const layouts = discoverLayouts(layoutsDir)
162
- const source = fs.readFileSync(pagePath, 'utf-8')
163
-
164
- let processedSource = source
165
- let layoutToUse = layouts.get('DefaultLayout')
166
-
167
- if (layoutToUse) processedSource = processLayout(source, layoutToUse)
168
-
169
- const result = await compileZenSource(processedSource, pagePath, {
170
- componentsDir: fs.existsSync(componentsDir) ? componentsDir : undefined
171
- })
172
- if (!result.finalized) throw new Error('Compilation failed')
173
-
174
- const routeDef = generateRouteDefinition(pagePath, pagesDir)
175
-
176
- // Bundle the script to resolve npm imports at compile time
177
- const bundledScript = await bundlePageScript(result.finalized.js, rootDir)
178
-
179
- return {
180
- html: result.finalized.html,
181
- script: bundledScript,
182
- styles: result.finalized.styles,
183
- route: routeDef.path,
184
- lastModified: Date.now()
185
- }
186
- } catch (error: any) {
187
- logger.error(`Compilation error: ${error.message}`)
188
- return null
189
- }
190
- }
191
-
192
- // Set up file watching for HMR
193
- const watcher = fs.watch(path.join(pagesDir, '..'), { recursive: true }, async (event, filename) => {
194
- if (!filename) return
195
-
196
- if (filename.endsWith('.zen')) {
197
- logger.hmr('Page', filename)
198
-
199
- // Clear page cache to force fresh compilation on next request
200
- pageCache.clear()
201
-
202
- // Recompile CSS for new Tailwind classes in .zen files
203
- if (globalsCssPath) {
204
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
205
- if (cssResult.success) {
206
- compiledCss = cssResult.css
207
- }
208
- }
209
-
210
- // Broadcast page reload AFTER cache cleared and CSS ready
211
- for (const client of clients) {
212
- client.send(JSON.stringify({ type: 'reload' }))
213
- }
214
- } else if (filename.endsWith('.css')) {
215
- logger.hmr('CSS', filename)
216
- // Recompile CSS
217
- if (globalsCssPath) {
218
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
219
- if (cssResult.success) {
220
- compiledCss = cssResult.css
221
- }
222
- }
223
- for (const client of clients) {
224
- client.send(JSON.stringify({ type: 'style-update', url: '/assets/styles.css' }))
225
- }
226
- } else if (filename.startsWith('content') || filename.includes('zenith-docs')) {
227
- logger.hmr('Content', filename)
228
- // Reinitialize content plugin to reload data
229
- if (registry.has('zenith-content')) {
230
- registry.initAll(createPluginContext(rootDir, (data) => {
231
- contentData = data
232
- }))
233
- } else {
234
- contentData = loadContent(contentDir)
235
- }
236
- for (const client of clients) {
237
- client.send(JSON.stringify({ type: 'reload' }))
238
- }
239
- }
240
- })
241
-
242
- const server = serve({
243
- port,
244
- async fetch(req, server) {
245
- const startTime = performance.now()
246
- const url = new URL(req.url)
247
- const pathname = url.pathname
248
- const ext = path.extname(pathname).toLowerCase()
249
-
250
- // Upgrade to WebSocket for HMR
251
- if (pathname === '/hmr') {
252
- const upgraded = server.upgrade(req)
253
- if (upgraded) return undefined
254
- }
255
-
256
- // Handle Zenith assets
257
- if (pathname === '/runtime.js') {
258
- const response = new Response(generateBundleJS(), {
259
- headers: { 'Content-Type': 'application/javascript; charset=utf-8' }
260
- })
261
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
262
- return response
263
- }
264
-
265
- // Serve compiler-owned CSS (Tailwind compiled)
266
- if (pathname === '/assets/styles.css') {
267
- const response = new Response(compiledCss, {
268
- headers: { 'Content-Type': 'text/css; charset=utf-8' }
269
- })
270
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
271
- return response
272
- }
273
-
274
- // Legacy: also support /styles/globals.css or /styles/global.css for backwards compat
275
- if (pathname === '/styles/globals.css' || pathname === '/styles/global.css') {
276
- const response = new Response(compiledCss, {
277
- headers: { 'Content-Type': 'text/css; charset=utf-8' }
278
- })
279
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
280
- return response
281
- }
282
-
283
- // Static files
284
- if (STATIC_EXTENSIONS.has(ext)) {
285
- const publicPath = path.join(pagesDir, '../public', pathname)
286
- if (fs.existsSync(publicPath)) {
287
- const response = new Response(Bun.file(publicPath))
288
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
289
- return response
290
- }
291
- }
292
-
293
- // Zenith Pages
294
- const pagePath = findPageForRoute(pathname, pagesDir)
295
- if (pagePath) {
296
- const compileStart = performance.now()
297
- let cached = pageCache.get(pagePath)
298
- const stat = fs.statSync(pagePath)
299
-
300
- if (!cached || stat.mtimeMs > cached.lastModified) {
301
- cached = await compilePageInMemory(pagePath) || undefined
302
- if (cached) pageCache.set(pagePath, cached)
303
- }
304
- const compileEnd = performance.now()
305
-
306
- if (cached) {
307
- const renderStart = performance.now()
308
- const html = generateDevHTML(cached, contentData)
309
- const renderEnd = performance.now()
310
-
311
- const totalTime = Math.round(performance.now() - startTime)
312
- const compileTime = Math.round(compileEnd - compileStart)
313
- const renderTime = Math.round(renderEnd - renderStart)
314
-
315
- logger.route('GET', pathname, 200, totalTime, compileTime, renderTime)
316
- return new Response(html, { headers: { 'Content-Type': 'text/html' } })
317
- }
318
- }
319
-
320
- logger.route('GET', pathname, 404, Math.round(performance.now() - startTime), 0, 0)
321
- return new Response('Not Found', { status: 404 })
322
- },
323
- websocket: {
324
- open(ws) {
325
- clients.add(ws)
326
- },
327
- close(ws) {
328
- clients.delete(ws)
329
- },
330
- message() { }
331
- }
332
- })
333
-
334
- process.on('SIGINT', () => {
335
- watcher.close()
336
- server.stop()
337
- process.exit(0)
338
- })
339
-
340
- await new Promise(() => { })
341
- }
342
-
343
- function findPageForRoute(route: string, pagesDir: string): string | null {
344
- // 1. Try exact match first (e.g., /about -> about.zen)
345
- const exactPath = path.join(pagesDir, route === '/' ? 'index.zen' : `${route.slice(1)}.zen`)
346
- if (fs.existsSync(exactPath)) return exactPath
347
-
348
- // 2. Try index.zen in directory (e.g., /about -> about/index.zen)
349
- const indexPath = path.join(pagesDir, route === '/' ? 'index.zen' : `${route.slice(1)}/index.zen`)
350
- if (fs.existsSync(indexPath)) return indexPath
351
-
352
- // 3. Try dynamic routes [slug].zen, [...slug].zen
353
- // Walk up the path looking for dynamic segments
354
- const segments = route === '/' ? [] : route.slice(1).split('/').filter(Boolean)
355
-
356
- // Try matching with dynamic [slug].zen at each level
357
- for (let i = segments.length - 1; i >= 0; i--) {
358
- const staticPart = segments.slice(0, i).join('/')
359
- const baseDir = staticPart ? path.join(pagesDir, staticPart) : pagesDir
360
-
361
- // Check for [slug].zen (single segment catch)
362
- const singleDynamicPath = path.join(baseDir, '[slug].zen')
363
- if (fs.existsSync(singleDynamicPath)) return singleDynamicPath
364
-
365
- // Check for [...slug].zen (catch-all)
366
- const catchAllPath = path.join(baseDir, '[...slug].zen')
367
- if (fs.existsSync(catchAllPath)) return catchAllPath
368
- }
369
-
370
- // 4. Check for catch-all at root
371
- const rootCatchAll = path.join(pagesDir, '[...slug].zen')
372
- if (fs.existsSync(rootCatchAll)) return rootCatchAll
373
-
374
- return null
375
- }
376
-
377
- function generateDevHTML(page: CompiledPage, contentData: any = {}): string {
378
- const runtimeTag = `<script src="/runtime.js"></script>`
379
- // Escape </script> sequences in JSON content to prevent breaking the script tag
380
- const contentJson = JSON.stringify(contentData).replace(/<\//g, '<\\/')
381
- const contentTag = `<script>window.__ZENITH_CONTENT__ = ${contentJson};</script>`
382
- // Use type="module" to support ES6 imports from npm packages
383
- const scriptTag = `<script type="module">\n${page.script}\n</script>`
384
- const allScripts = `${runtimeTag}\n${contentTag}\n${scriptTag}`
385
- return page.html.includes('</body>')
386
- ? page.html.replace('</body>', `${allScripts}\n</body>`)
387
- : `${page.html}\n${allScripts}`
388
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * @zenith/cli - Command Registry
3
- *
4
- * Central registry for all CLI commands
5
- */
6
-
7
- import { dev, type DevOptions } from './dev'
8
- import { preview, type PreviewOptions } from './preview'
9
- import { build, type BuildOptions } from './build'
10
- import { add, type AddOptions } from './add'
11
- import { remove } from './remove'
12
- import { create } from './create'
13
- import * as logger from '../utils/logger'
14
-
15
- export interface Command {
16
- name: string
17
- description: string
18
- usage: string
19
- run: (args: string[], options: Record<string, string>) => Promise<void>
20
- }
21
-
22
- export const commands: Command[] = [
23
- {
24
- name: 'create',
25
- description: 'Create a new Zenith project',
26
- usage: 'zenith create [project-name]',
27
- async run(args) {
28
- const projectName = args[0]
29
- await create(projectName)
30
- }
31
- },
32
- {
33
- name: 'dev',
34
- description: 'Start development server',
35
- usage: 'zenith dev [--port <port>]',
36
- async run(args, options) {
37
- const opts: DevOptions = {}
38
- if (options.port) opts.port = parseInt(options.port, 10)
39
- await dev(opts)
40
- }
41
- },
42
- {
43
- name: 'preview',
44
- description: 'Preview production build',
45
- usage: 'zenith preview [--port <port>]',
46
- async run(args, options) {
47
- const opts: PreviewOptions = {}
48
- if (options.port) opts.port = parseInt(options.port, 10)
49
- await preview(opts)
50
- }
51
- },
52
- {
53
- name: 'build',
54
- description: 'Build for production',
55
- usage: 'zenith build [--outDir <dir>]',
56
- async run(args, options) {
57
- const opts: BuildOptions = {}
58
- if (options.outDir) opts.outDir = options.outDir
59
- await build(opts)
60
- }
61
- },
62
- {
63
- name: 'add',
64
- description: 'Add a plugin',
65
- usage: 'zenith add <plugin>',
66
- async run(args) {
67
- const pluginName = args[0]
68
- if (!pluginName) {
69
- logger.error('Plugin name required')
70
- process.exit(1)
71
- }
72
- await add(pluginName)
73
- }
74
- },
75
- {
76
- name: 'remove',
77
- description: 'Remove a plugin',
78
- usage: 'zenith remove <plugin>',
79
- async run(args) {
80
- const pluginName = args[0]
81
- if (!pluginName) {
82
- logger.error('Plugin name required')
83
- process.exit(1)
84
- }
85
- await remove(pluginName)
86
- }
87
- }
88
- ]
89
-
90
- // Placeholder commands for future expansion
91
- export const placeholderCommands = ['test', 'export', 'deploy']
92
-
93
- export function getCommand(name: string): Command | undefined {
94
- return commands.find(c => c.name === name)
95
- }
96
-
97
- export function showHelp(): void {
98
- logger.header('Zenith CLI')
99
- console.log('Usage: zenith <command> [options]\n')
100
- console.log('Commands:')
101
-
102
- for (const cmd of commands) {
103
- console.log(` ${cmd.name.padEnd(12)} ${cmd.description}`)
104
- }
105
-
106
- console.log('\nComing soon:')
107
- for (const cmd of placeholderCommands) {
108
- console.log(` ${cmd.padEnd(12)} (not yet implemented)`)
109
- }
110
-
111
- console.log('\nRun `zenith <command> --help` for command-specific help.')
112
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * @zenith/cli - Preview Command
3
- *
4
- * Serves the production build from the distribution directory.
5
- */
6
-
7
- import path from 'path'
8
- import { serve } from 'bun'
9
- import { requireProject } from '../utils/project'
10
- import * as logger from '../utils/logger'
11
-
12
- export interface PreviewOptions {
13
- port?: number
14
- }
15
-
16
- export async function preview(options: PreviewOptions = {}): Promise<void> {
17
- const project = requireProject()
18
- const distDir = project.distDir
19
- const port = options.port || parseInt(process.env.PORT || '4173', 10)
20
-
21
- logger.header('Zenith Preview Server')
22
- logger.log(`Serving: ${distDir}`)
23
-
24
- // File extensions that should be served as static assets
25
- const STATIC_EXTENSIONS = new Set([
26
- '.js', '.css', '.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg',
27
- '.webp', '.woff', '.woff2', '.ttf', '.eot', '.json', '.map'
28
- ])
29
-
30
- const server = serve({
31
- port,
32
- async fetch(req) {
33
- const url = new URL(req.url)
34
- const pathname = url.pathname
35
- const ext = path.extname(pathname).toLowerCase()
36
-
37
- if (STATIC_EXTENSIONS.has(ext)) {
38
- const filePath = path.join(distDir, pathname)
39
- const file = Bun.file(filePath)
40
- if (await file.exists()) {
41
- return new Response(file)
42
- }
43
- return new Response('Not found', { status: 404 })
44
- }
45
-
46
- const indexPath = path.join(distDir, 'index.html')
47
- const indexFile = Bun.file(indexPath)
48
- if (await indexFile.exists()) {
49
- return new Response(indexFile, {
50
- headers: { 'Content-Type': 'text/html; charset=utf-8' }
51
- })
52
- }
53
-
54
- return new Response('No production build found. Run `zenith build` first.', { status: 500 })
55
- }
56
- })
57
-
58
- logger.success(`Preview server running at http://localhost:${server.port}`)
59
- logger.info('Press Ctrl+C to stop')
60
-
61
- await new Promise(() => { })
62
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * @zenith/cli - Remove Command
3
- *
4
- * Removes a plugin from the project registry
5
- */
6
-
7
- import { requireProject } from '../utils/project'
8
- import { removePlugin, hasPlugin } from '../utils/plugin-manager'
9
- import * as logger from '../utils/logger'
10
-
11
- export async function remove(pluginName: string): Promise<void> {
12
- requireProject()
13
-
14
- logger.header('Remove Plugin')
15
-
16
- if (!pluginName) {
17
- logger.error('Plugin name required. Usage: zenith remove <plugin>')
18
- process.exit(1)
19
- }
20
-
21
- if (!hasPlugin(pluginName)) {
22
- logger.warn(`Plugin "${pluginName}" is not registered`)
23
- return
24
- }
25
-
26
- const success = removePlugin(pluginName)
27
-
28
- if (success) {
29
- logger.info(`Plugin "${pluginName}" has been unregistered.`)
30
- logger.info('Note: You may want to remove the package manually:')
31
- logger.log(` bun remove @zenith/plugin-${pluginName}`)
32
- }
33
- }
package/cli/index.ts DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * @zenith/cli
3
- *
4
- * CLI for Zenith framework - dev server, build tools, and plugin management
5
- */
6
-
7
- export * from './commands/index'
8
- export * from './utils/logger'
9
- export * from './utils/project'
10
- export * from './utils/plugin-manager'