@vertz/cli 0.2.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.
package/README.md ADDED
@@ -0,0 +1,226 @@
1
+ # @vertz/cli
2
+
3
+ The `vertz` command. Create, develop, build, and publish Vertz applications.
4
+
5
+ > **5-minute rule:** You should understand what this CLI does and how to use it in 5 minutes or less. If not, [open an issue](https://github.com/nicholasgriffintn/vertz/issues) — that's a bug in our docs.
6
+
7
+ ## What is this?
8
+
9
+ `@vertz/cli` is the developer tool for Vertz projects. It's the `vertz` binary you run in your terminal. If you're looking for terminal UI building blocks (spinners, task lists, select menus), that's `@vertz/tui`.
10
+
11
+ ---
12
+
13
+ ## You want to start a new project
14
+
15
+ ```bash
16
+ npx @vertz/cli create my-app
17
+ cd my-app
18
+ ```
19
+
20
+ This scaffolds a new Vertz app with a working `src/app.ts`, config file, and dev scripts. You'll have a running server in under a minute.
21
+
22
+ Your entry point will look something like this:
23
+
24
+ ```ts
25
+ import { createServer } from '@vertz/server';
26
+
27
+ const app = createServer();
28
+ // ... define your routes, modules, services
29
+ ```
30
+
31
+ ---
32
+
33
+ ## You want to develop locally
34
+
35
+ ```bash
36
+ vertz dev
37
+ ```
38
+
39
+ That's it. This starts your dev server with hot reload, background type-checking, and compiler diagnostics right in your terminal.
40
+
41
+ **Common options:**
42
+
43
+ ```bash
44
+ vertz dev --port 4000 # custom port
45
+ vertz dev --host 0.0.0.0 # expose to network
46
+ vertz dev --no-typecheck # skip background type-checking
47
+ ```
48
+
49
+ **What happens under the hood:**
50
+ 1. Compiles your `src/` directory
51
+ 2. Starts your server (default: `localhost:3000`)
52
+ 3. Watches for file changes and recompiles automatically
53
+ 4. Runs type-checking in the background so errors show inline
54
+
55
+ ---
56
+
57
+ ## You want to build for production
58
+
59
+ ```bash
60
+ vertz build
61
+ ```
62
+
63
+ Compiles your project, runs validation, and outputs production-ready code.
64
+
65
+ ```bash
66
+ vertz build --strict # treat warnings as errors
67
+ vertz build --output dist # custom output directory
68
+ ```
69
+
70
+ ---
71
+
72
+ ## You want to check your code without building
73
+
74
+ ```bash
75
+ vertz check
76
+ ```
77
+
78
+ Type-checks and validates your project without producing output. Useful in CI or as a pre-commit hook.
79
+
80
+ ```bash
81
+ vertz check --strict # fail on warnings
82
+ vertz check --format json # machine-readable output (text | json | github)
83
+ ```
84
+
85
+ ---
86
+
87
+ ## You want to generate code
88
+
89
+ ```bash
90
+ vertz generate module users
91
+ vertz generate service user --module users
92
+ vertz generate router api --module users
93
+ vertz generate schema user --module users
94
+ ```
95
+
96
+ Scaffolds modules, services, routers, and schemas. Use `--dry-run` to preview what will be generated.
97
+
98
+ You can also define [custom generators](#custom-generators) in your config.
99
+
100
+ ---
101
+
102
+ ## You want to deploy *(coming soon)*
103
+
104
+ ```bash
105
+ vertz publish
106
+ ```
107
+
108
+ One-command deployment to your configured target. **This command is not yet available** — it's on the roadmap.
109
+
110
+ ---
111
+
112
+ ## You want to see your routes
113
+
114
+ ```bash
115
+ vertz routes # table format
116
+ vertz routes --format json # JSON output
117
+ ```
118
+
119
+ Displays every route your application exposes.
120
+
121
+ ---
122
+
123
+ ## Installation
124
+
125
+ ```bash
126
+ npm install @vertz/cli # or bun add @vertz/cli
127
+ ```
128
+
129
+ **Requirements:** Node.js 18+ or Bun 1.0+, TypeScript 5.0+
130
+
131
+ ---
132
+
133
+ ## Configuration
134
+
135
+ Create `vertz.config.ts` in your project root:
136
+
137
+ ```ts
138
+ import type { CLIConfig } from '@vertz/cli';
139
+
140
+ const config: CLIConfig = {
141
+ compiler: {
142
+ sourceDir: 'src',
143
+ entryFile: 'src/app.ts',
144
+ outputDir: '.vertz/generated',
145
+ },
146
+ dev: {
147
+ port: 3000,
148
+ host: 'localhost',
149
+ typecheck: true,
150
+ },
151
+ };
152
+
153
+ export default config;
154
+ ```
155
+
156
+ Also supports `.js` and `.mjs`. See [Configuration Reference](#configuration-reference) for all options.
157
+
158
+ ---
159
+
160
+ ## Custom Generators
161
+
162
+ Extend `vertz generate` with your own templates:
163
+
164
+ ```ts
165
+ import type { CLIConfig, GeneratorDefinition } from '@vertz/cli';
166
+
167
+ const entity: GeneratorDefinition = {
168
+ name: 'entity',
169
+ description: 'Generate a domain entity with schema and service',
170
+ arguments: [{ name: 'name', description: 'Entity name', required: true }],
171
+ options: [
172
+ { name: 'timestamps', flag: '--timestamps', description: 'Include timestamp fields', default: 'true' },
173
+ ],
174
+ async run({ name, sourceDir }) {
175
+ return [
176
+ { path: `${sourceDir}/entities/${name}.schema.ts`, content: `export const ${name}Schema = s.object({});` },
177
+ { path: `${sourceDir}/entities/${name}.service.ts`, content: `export class ${name}Service {}` },
178
+ ];
179
+ },
180
+ };
181
+
182
+ const config: CLIConfig = {
183
+ generators: { entity },
184
+ };
185
+
186
+ export default config;
187
+ ```
188
+
189
+ ```bash
190
+ vertz generate entity product
191
+ vertz generate entity product --timestamps false
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Configuration Reference
197
+
198
+ | Option | Type | Default | Description |
199
+ |--------|------|---------|-------------|
200
+ | `strict` | `boolean` | `false` | Treat warnings as errors |
201
+ | `forceGenerate` | `boolean` | `false` | Force code generation even if up-to-date |
202
+ | `compiler.sourceDir` | `string` | `'src'` | Source directory |
203
+ | `compiler.entryFile` | `string` | `'src/app.ts'` | Entry file path |
204
+ | `compiler.outputDir` | `string` | `'.vertz/generated'` | Generated code output |
205
+ | `dev.port` | `number` | `3000` | Dev server port |
206
+ | `dev.host` | `string` | `'localhost'` | Dev server host |
207
+ | `dev.open` | `boolean` | `false` | Open browser on start |
208
+ | `dev.typecheck` | `boolean` | `true` | Background type-checking |
209
+
210
+ ---
211
+
212
+ ## Programmatic API
213
+
214
+ The CLI exports its internals for custom tooling. See the [Programmatic API docs](./docs/programmatic-api.md) for details on `buildAction`, `generateAction`, `createDevLoop`, `createTaskRunner`, and more.
215
+
216
+ ---
217
+
218
+ ## Related Packages
219
+
220
+ - [`@vertz/server`](../server) — Server framework (`createServer`)
221
+ - [`@vertz/compiler`](../compiler) — Vertz compiler
222
+ - [`@vertz/codegen`](../codegen) — Code generation utilities
223
+
224
+ ## License
225
+
226
+ MIT
@@ -0,0 +1,399 @@
1
+ import { Command } from "commander";
2
+ declare function createCLI(): Command;
3
+ /**
4
+ * Vertz Build Command - Production Build
5
+ *
6
+ * Production build command that orchestrates:
7
+ * 1. Codegen - runs the full pipeline to generate types, routes, OpenAPI
8
+ * 2. Typecheck - runs TypeScript compiler for type checking
9
+ * 3. Bundle - bundles the server for production (esbuild)
10
+ * 4. Manifest - generates build manifest for vertz publish
11
+ */
12
+ interface BuildCommandOptions {
13
+ strict?: boolean;
14
+ output?: string;
15
+ target?: "node" | "edge" | "worker";
16
+ noTypecheck?: boolean;
17
+ noMinify?: boolean;
18
+ sourcemap?: boolean;
19
+ verbose?: boolean;
20
+ }
21
+ /**
22
+ * Run the build command
23
+ * @returns Exit code (0 for success, 1 for failure)
24
+ */
25
+ declare function buildAction(options?: BuildCommandOptions): Promise<number>;
26
+ import { Compiler, Diagnostic } from "@vertz/compiler";
27
+ interface CheckOptions {
28
+ compiler: Compiler;
29
+ format: "text" | "json" | "github";
30
+ }
31
+ interface CheckResult {
32
+ success: boolean;
33
+ diagnostics: Diagnostic[];
34
+ output: string;
35
+ }
36
+ declare function checkAction(options: CheckOptions): Promise<CheckResult>;
37
+ interface CreateOptions {
38
+ projectName?: string;
39
+ runtime?: string;
40
+ example?: boolean;
41
+ }
42
+ declare function createAction(options: CreateOptions): Promise<void>;
43
+ import { VertzConfig } from "@vertz/compiler";
44
+ interface DevConfig {
45
+ port: number;
46
+ host: string;
47
+ open: boolean;
48
+ typecheck: boolean;
49
+ }
50
+ interface GeneratorArgument {
51
+ name: string;
52
+ description: string;
53
+ required: boolean;
54
+ }
55
+ interface GeneratorOption {
56
+ name: string;
57
+ flag: string;
58
+ description: string;
59
+ default?: string;
60
+ }
61
+ interface GeneratorContext {
62
+ name: string;
63
+ options: Record<string, string>;
64
+ projectRoot: string;
65
+ sourceDir: string;
66
+ config: VertzConfig;
67
+ }
68
+ interface GeneratedFile {
69
+ path: string;
70
+ content: string;
71
+ }
72
+ interface GeneratorDefinition {
73
+ name: string;
74
+ description: string;
75
+ arguments: GeneratorArgument[];
76
+ options?: GeneratorOption[];
77
+ run(context: GeneratorContext): Promise<GeneratedFile[]>;
78
+ }
79
+ interface CLIConfig extends VertzConfig {
80
+ dev?: DevConfig;
81
+ generators?: Record<string, GeneratorDefinition>;
82
+ }
83
+ declare const defaultCLIConfig: CLIConfig;
84
+ type DeployTarget = "fly" | "railway" | "docker";
85
+ declare function detectTarget(projectRoot: string, existsFn: (path: string) => boolean): DeployTarget | null;
86
+ interface DeployOptions {
87
+ target: DeployTarget;
88
+ runtime: "bun" | "node";
89
+ port: number;
90
+ projectRoot: string;
91
+ dryRun?: boolean;
92
+ }
93
+ type DeployResult = {
94
+ success: true;
95
+ files: GeneratedFile[];
96
+ } | {
97
+ success: false;
98
+ files: GeneratedFile[];
99
+ error: string;
100
+ };
101
+ declare function deployAction(options: DeployOptions): DeployResult;
102
+ import { Command as Command2 } from "commander";
103
+ interface DevCommandOptions {
104
+ port?: number;
105
+ host?: string;
106
+ open?: boolean;
107
+ typecheck?: boolean;
108
+ noTypecheck?: boolean;
109
+ verbose?: boolean;
110
+ }
111
+ /**
112
+ * Run the dev command
113
+ */
114
+ declare function devAction(options?: DevCommandOptions): Promise<void>;
115
+ /**
116
+ * Register the dev command with a Commander program
117
+ */
118
+ declare function registerDevCommand(program: Command2): void;
119
+ interface GenerateOptions {
120
+ type: string;
121
+ name: string;
122
+ module?: string;
123
+ sourceDir: string;
124
+ dryRun?: boolean;
125
+ }
126
+ type GenerateResult = {
127
+ success: true;
128
+ files: GeneratedFile[];
129
+ } | {
130
+ success: false;
131
+ files: GeneratedFile[];
132
+ error: string;
133
+ };
134
+ declare function generateAction(options: GenerateOptions): GenerateResult;
135
+ import { Compiler as Compiler2, HttpMethod } from "@vertz/compiler";
136
+ interface FlatRoute {
137
+ method: HttpMethod;
138
+ path: string;
139
+ fullPath: string;
140
+ operationId: string;
141
+ moduleName: string;
142
+ middleware: string[];
143
+ }
144
+ interface RoutesOptions {
145
+ compiler: Compiler2;
146
+ format: "table" | "json";
147
+ module?: string;
148
+ }
149
+ interface RoutesResult {
150
+ routes: FlatRoute[];
151
+ output: string;
152
+ }
153
+ declare function routesAction(options: RoutesOptions): Promise<RoutesResult>;
154
+ import { AppIR } from "@vertz/compiler";
155
+ import { GenerateResult as GenerateResult2 } from "@vertz/codegen";
156
+ /**
157
+ * Pipeline types - Core type definitions
158
+ */
159
+ /**
160
+ * Pipeline stages that can be executed
161
+ */
162
+ type PipelineStage = "analyze" | "codegen" | "build-ui" | "db-sync";
163
+ /**
164
+ * File categories for smart dispatch
165
+ */
166
+ type FileCategory = "domain" | "module" | "schema" | "service" | "route" | "component" | "config" | "other";
167
+ /**
168
+ * A file change event from the watcher
169
+ */
170
+ interface FileChange {
171
+ type: "add" | "change" | "remove";
172
+ path: string;
173
+ category?: FileCategory;
174
+ }
175
+ /**
176
+ * Watcher interface
177
+ */
178
+ interface Watcher {
179
+ on(event: "change", handler: (changes: FileChange[]) => void): void;
180
+ close(): void;
181
+ /** @internal — for testing only */
182
+ _emit(change: FileChange): void;
183
+ }
184
+ /**
185
+ * Configuration for the watcher
186
+ */
187
+ interface WatcherConfig {
188
+ /** Directory to watch */
189
+ dir: string;
190
+ /** Patterns to ignore */
191
+ ignorePatterns?: string[];
192
+ /** Debounce delay in ms */
193
+ debounceMs?: number;
194
+ /** Callback when files change */
195
+ onChange?: (changes: FileChange[]) => void;
196
+ }
197
+ /**
198
+ * Pipeline watcher event handlers
199
+ */
200
+ interface PipelineWatcherHandlers {
201
+ analyze: (changes: FileChange[]) => void;
202
+ codegen: (changes: FileChange[]) => void;
203
+ "build-ui": (changes: FileChange[]) => void;
204
+ error: (error: Error) => void;
205
+ }
206
+ /**
207
+ * Watcher that understands file semantics
208
+ */
209
+ interface PipelineWatcher {
210
+ on<K extends keyof PipelineWatcherHandlers>(event: K, handler: PipelineWatcherHandlers[K]): void;
211
+ close(): void;
212
+ }
213
+ /**
214
+ * Configuration for the pipeline orchestrator
215
+ */
216
+ interface PipelineConfig {
217
+ /** Source directory */
218
+ sourceDir: string;
219
+ /** Output directory for generated files */
220
+ outputDir: string;
221
+ /** Whether to enable type checking */
222
+ typecheck: boolean;
223
+ /** Whether to auto-sync DB schema in dev mode */
224
+ autoSyncDb: boolean;
225
+ /** Whether to open browser on start */
226
+ open: boolean;
227
+ /** Port for dev server */
228
+ port: number;
229
+ /** Host for dev server */
230
+ host: string;
231
+ }
232
+ /**
233
+ * Result from running a pipeline stage
234
+ */
235
+ interface StageResult {
236
+ stage: PipelineStage;
237
+ success: boolean;
238
+ durationMs: number;
239
+ error?: Error;
240
+ output?: string;
241
+ }
242
+ /**
243
+ * Complete result from running the pipeline
244
+ */
245
+ interface PipelineResult {
246
+ success: boolean;
247
+ stages: StageResult[];
248
+ totalDurationMs: number;
249
+ appIR?: AppIR;
250
+ generatedFiles?: GenerateResult2;
251
+ }
252
+ /**
253
+ * Pipeline Orchestrator
254
+ *
255
+ * Coordinates the full development pipeline:
256
+ * 1. Analyze (compiler → AppIR)
257
+ * 2. Generate (codegen → types, route map, DB client)
258
+ * 3. Build UI (components → ES modules)
259
+ * 4. Serve (dev server with HMR)
260
+ */
261
+ declare class PipelineOrchestrator {
262
+ private config;
263
+ private compiler;
264
+ private appIR;
265
+ private isRunning;
266
+ private stages;
267
+ constructor(config?: Partial<PipelineConfig>);
268
+ /**
269
+ * Initialize the pipeline - create compiler instance
270
+ */
271
+ initialize(): Promise<void>;
272
+ /**
273
+ * Run the full pipeline once
274
+ */
275
+ runFull(): Promise<PipelineResult>;
276
+ /**
277
+ * Run specific stages based on file changes
278
+ */
279
+ runStages(stages: PipelineStage[]): Promise<PipelineResult>;
280
+ /**
281
+ * Run the analyze stage
282
+ */
283
+ private runAnalyze;
284
+ /**
285
+ * Run the codegen stage
286
+ */
287
+ private runCodegen;
288
+ /**
289
+ * Run the UI build stage
290
+ * Note: This currently delegates to Vite. In the future, this will use @vertz/ui-compiler directly.
291
+ */
292
+ private runBuildUI;
293
+ /**
294
+ * Run the DB sync stage
295
+ */
296
+ private runDbSync;
297
+ /**
298
+ * Get the current AppIR
299
+ */
300
+ getAppIR(): AppIR | null;
301
+ /**
302
+ * Check if the pipeline is currently running
303
+ */
304
+ isPipelineRunning(): boolean;
305
+ /**
306
+ * Get the latest result for a specific stage
307
+ */
308
+ getStageResult(stage: PipelineStage): StageResult | undefined;
309
+ /**
310
+ * Clean up resources
311
+ */
312
+ dispose(): Promise<void>;
313
+ }
314
+ /**
315
+ * Create a new pipeline orchestrator
316
+ */
317
+ declare function createPipelineOrchestrator(config?: Partial<PipelineConfig>): PipelineOrchestrator;
318
+ /**
319
+ * Categorize a file change based on its path
320
+ */
321
+ declare function categorizeFileChange(path: string): FileCategory;
322
+ /**
323
+ * Determine which pipeline stages are affected by a file category
324
+ */
325
+ declare function getAffectedStages(category: FileCategory): PipelineStage[];
326
+ /**
327
+ * Create a pipeline watcher
328
+ */
329
+ declare function createPipelineWatcher(config: WatcherConfig): PipelineWatcher;
330
+ import { VertzConfig as VertzConfig2 } from "@vertz/compiler";
331
+ declare function findConfigFile(startDir?: string): string | undefined;
332
+ declare function loadConfig(configPath?: string): Promise<VertzConfig2>;
333
+ import { CompileResult } from "@vertz/compiler";
334
+ interface FileChange2 {
335
+ type: "add" | "change" | "remove";
336
+ path: string;
337
+ }
338
+ interface Watcher2 {
339
+ on(event: "change", handler: (changes: FileChange2[]) => void): void;
340
+ close(): void;
341
+ /** @internal — for testing only */
342
+ _emit(change: FileChange2): void;
343
+ }
344
+ declare function createWatcher2(_dir: string): Watcher2;
345
+ interface DevLoopDeps {
346
+ compile(): Promise<CompileResult>;
347
+ startProcess(): void;
348
+ stopProcess(): Promise<void>;
349
+ onFileChange(handler: (changes: FileChange2[]) => void): void;
350
+ onCompileSuccess(result: CompileResult): void;
351
+ onCompileError(result: CompileResult): void;
352
+ }
353
+ interface DevLoop {
354
+ start(): Promise<void>;
355
+ stop(): Promise<void>;
356
+ }
357
+ declare function createDevLoop(deps: DevLoopDeps): DevLoop;
358
+ import { ChildProcess } from "node:child_process";
359
+ interface ProcessManager {
360
+ start(entryPoint: string, env?: Record<string, string>): void;
361
+ stop(): Promise<void>;
362
+ restart(entryPoint: string, env?: Record<string, string>): Promise<void>;
363
+ isRunning(): boolean;
364
+ onOutput(handler: (data: string) => void): void;
365
+ onError(handler: (data: string) => void): void;
366
+ }
367
+ type SpawnFn = (entryPoint: string, env?: Record<string, string>) => ChildProcess;
368
+ declare function createProcessManager(spawnFn?: SpawnFn): ProcessManager;
369
+ import React from "react";
370
+ interface BannerProps {
371
+ version: string;
372
+ }
373
+ declare function Banner({ version }: BannerProps): React.ReactElement;
374
+ import { Diagnostic as Diagnostic2 } from "@vertz/compiler";
375
+ import React2 from "react";
376
+ interface DiagnosticDisplayProps {
377
+ diagnostic: Diagnostic2;
378
+ }
379
+ declare function DiagnosticDisplay({ diagnostic }: DiagnosticDisplayProps): React2.ReactElement;
380
+ import { Diagnostic as Diagnostic3 } from "@vertz/compiler";
381
+ import React3 from "react";
382
+ interface DiagnosticSummaryProps {
383
+ diagnostics: readonly Diagnostic3[];
384
+ }
385
+ declare function DiagnosticSummary({ diagnostics }: DiagnosticSummaryProps): React3.ReactElement;
386
+ import { Diagnostic as Diagnostic4 } from "@vertz/compiler";
387
+ declare function formatDiagnostic(diagnostic: Diagnostic4): string;
388
+ declare function formatDiagnosticSummary(diagnostics: readonly Diagnostic4[]): string;
389
+ import { colors, createTaskRunner, Message, SelectList, symbols, Task, TaskList } from "@vertz/tui";
390
+ import { TaskGroup, TaskHandle, TaskRunner } from "@vertz/tui";
391
+ declare function formatDuration(ms: number): string;
392
+ declare function formatFileSize(bytes: number): string;
393
+ declare function formatPath(absolutePath: string, cwd?: string): string;
394
+ declare function findProjectRoot(startDir?: string): string | undefined;
395
+ declare function isCI(): boolean;
396
+ declare function requireParam(value: string | undefined, name: string): string;
397
+ type Runtime = "bun" | "node";
398
+ declare function detectRuntime(): Runtime;
399
+ export { symbols, routesAction, requireParam, registerDevCommand, loadConfig, isCI, getAffectedStages, generateAction, formatPath, formatFileSize, formatDuration, formatDiagnosticSummary, formatDiagnostic, findProjectRoot, findConfigFile, devAction, detectTarget, detectRuntime, deployAction, defaultCLIConfig, createWatcher2 as createWatcher, createTaskRunner, createProcessManager, createPipelineWatcher, createPipelineOrchestrator, createDevLoop, createCLI, createAction, colors, checkAction, categorizeFileChange, buildAction, Watcher, TaskRunner, TaskList, TaskHandle, TaskGroup, Task, StageResult, SelectList, PipelineWatcher, PipelineStage, PipelineResult, PipelineOrchestrator, PipelineConfig, Message, GeneratorDefinition, GeneratedFile, FileChange, FileCategory, DiagnosticSummary, DiagnosticDisplay, DevConfig, CLIConfig, Banner };