@palantir/pack.sdkgen 0.0.1-beta.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 (80) hide show
  1. package/LICENSE.txt +13 -0
  2. package/README.md +589 -0
  3. package/bin/cli.ts +7 -0
  4. package/build/esm/__tests__/createCommand.test.js +157 -0
  5. package/build/esm/__tests__/createCommand.test.js.map +1 -0
  6. package/build/esm/__tests__/generator.test.js +190 -0
  7. package/build/esm/__tests__/generator.test.js.map +1 -0
  8. package/build/esm/__tests__/schemaParser.test.js +67 -0
  9. package/build/esm/__tests__/schemaParser.test.js.map +1 -0
  10. package/build/esm/__tests__/templateLoader.test.js +67 -0
  11. package/build/esm/__tests__/templateLoader.test.js.map +1 -0
  12. package/build/esm/__tests__/templateUtils.test.js +94 -0
  13. package/build/esm/__tests__/templateUtils.test.js.map +1 -0
  14. package/build/esm/__tests__/types/testTypes.js +2 -0
  15. package/build/esm/__tests__/types/testTypes.js.map +1 -0
  16. package/build/esm/cli.js +25 -0
  17. package/build/esm/cli.js.map +1 -0
  18. package/build/esm/commands/create.js +173 -0
  19. package/build/esm/commands/create.js.map +1 -0
  20. package/build/esm/core/contextBuilder.js +33 -0
  21. package/build/esm/core/contextBuilder.js.map +1 -0
  22. package/build/esm/core/generator.js +248 -0
  23. package/build/esm/core/generator.js.map +1 -0
  24. package/build/esm/core/hookRunner.js +68 -0
  25. package/build/esm/core/hookRunner.js.map +1 -0
  26. package/build/esm/core/schemaParser.js +50 -0
  27. package/build/esm/core/schemaParser.js.map +1 -0
  28. package/build/esm/core/templateLoader.js +99 -0
  29. package/build/esm/core/templateLoader.js.map +1 -0
  30. package/build/esm/index.js +26 -0
  31. package/build/esm/index.js.map +1 -0
  32. package/build/esm/types/index.js +2 -0
  33. package/build/esm/types/index.js.map +1 -0
  34. package/build/esm/utils/fileSystem.js +72 -0
  35. package/build/esm/utils/fileSystem.js.map +1 -0
  36. package/build/esm/utils/logger.js +44 -0
  37. package/build/esm/utils/logger.js.map +1 -0
  38. package/build/esm/utils/prompts.js +25 -0
  39. package/build/esm/utils/prompts.js.map +1 -0
  40. package/build/esm/utils/templateUtils.js +61 -0
  41. package/build/esm/utils/templateUtils.js.map +1 -0
  42. package/build/types/__tests__/createCommand.test.d.ts +2 -0
  43. package/build/types/__tests__/createCommand.test.d.ts.map +1 -0
  44. package/build/types/__tests__/generator.test.d.ts +2 -0
  45. package/build/types/__tests__/generator.test.d.ts.map +1 -0
  46. package/build/types/__tests__/schemaParser.test.d.ts +2 -0
  47. package/build/types/__tests__/schemaParser.test.d.ts.map +1 -0
  48. package/build/types/__tests__/templateLoader.test.d.ts +2 -0
  49. package/build/types/__tests__/templateLoader.test.d.ts.map +1 -0
  50. package/build/types/__tests__/templateUtils.test.d.ts +2 -0
  51. package/build/types/__tests__/templateUtils.test.d.ts.map +1 -0
  52. package/build/types/__tests__/types/testTypes.d.ts +38 -0
  53. package/build/types/__tests__/types/testTypes.d.ts.map +1 -0
  54. package/build/types/cli.d.ts +2 -0
  55. package/build/types/cli.d.ts.map +1 -0
  56. package/build/types/commands/create.d.ts +3 -0
  57. package/build/types/commands/create.d.ts.map +1 -0
  58. package/build/types/core/contextBuilder.d.ts +5 -0
  59. package/build/types/core/contextBuilder.d.ts.map +1 -0
  60. package/build/types/core/generator.d.ts +15 -0
  61. package/build/types/core/generator.d.ts.map +1 -0
  62. package/build/types/core/hookRunner.d.ts +3 -0
  63. package/build/types/core/hookRunner.d.ts.map +1 -0
  64. package/build/types/core/schemaParser.d.ts +7 -0
  65. package/build/types/core/schemaParser.d.ts.map +1 -0
  66. package/build/types/core/templateLoader.d.ts +12 -0
  67. package/build/types/core/templateLoader.d.ts.map +1 -0
  68. package/build/types/index.d.ts +11 -0
  69. package/build/types/index.d.ts.map +1 -0
  70. package/build/types/types/index.d.ts +68 -0
  71. package/build/types/types/index.d.ts.map +1 -0
  72. package/build/types/utils/fileSystem.d.ts +8 -0
  73. package/build/types/utils/fileSystem.d.ts.map +1 -0
  74. package/build/types/utils/logger.d.ts +11 -0
  75. package/build/types/utils/logger.d.ts.map +1 -0
  76. package/build/types/utils/prompts.d.ts +3 -0
  77. package/build/types/utils/prompts.d.ts.map +1 -0
  78. package/build/types/utils/templateUtils.d.ts +3 -0
  79. package/build/types/utils/templateUtils.d.ts.map +1 -0
  80. package/package.json +61 -0
package/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2025 Palantir Technologies, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,589 @@
1
+ # @palantir/pack.sdkgen
2
+
3
+ A flexible CLI tool for generating TypeScript/JavaScript SDKs from schema definitions using customizable templates. The intention is for this to remain generic and not pack-specific,
4
+ the pack-specific parts are up to the template scripts that are used!
5
+
6
+ ## Table of Contents
7
+
8
+ - [Overview](#overview)
9
+ - [Installation](#installation)
10
+ - [Usage](#usage)
11
+ - [Creating Templates](#creating-templates)
12
+ - [CLI Development Guide](#cli-development-guide)
13
+ - [API Reference](#api-reference)
14
+ - [Examples](#examples)
15
+
16
+ ## Overview
17
+
18
+ `@palantir/pack.sdkgen` is a scaffolding tool that generates SDK packages from schema files using pluggable templates. Similar to `create-react-app`, it allows you to:
19
+
20
+ - Transform schema definitions into fully-configured SDK projects
21
+ - Customize generation through configuration and hooks
22
+ - Apply template substitutions and run initialization scripts
23
+
24
+ ## Usage
25
+
26
+ ### Basic Usage
27
+
28
+ ```bash
29
+ # Create a new SDK using the default template
30
+ npx @palantir/pack.sdkgen create my-sdk --schema ./my-schema.json
31
+
32
+ # Use a specific template
33
+ npx @palantir/pack.sdkgen create my-sdk \
34
+ --template @myorg/custom-template \
35
+ --schema ./my-schema.json
36
+
37
+ # Use a local template
38
+ npx @palantir/pack.sdkgen create my-sdk \
39
+ --template ./path/to/template \
40
+ --schema ./my-schema.yaml
41
+
42
+ # Skip dependency installation
43
+ npx @palantir/pack.sdkgen create my-sdk \
44
+ --schema ./my-schema.json \
45
+ --skip-install
46
+ ```
47
+
48
+ ### Available Commands
49
+
50
+ ```
51
+ Usage: sdkgen [options] [command]
52
+
53
+ Generate TypeScript/JavaScript SDKs from schema definitions
54
+
55
+ Options:
56
+ -V, --version output the version number
57
+ -h, --help display help for command
58
+
59
+ Commands:
60
+ create [options] <project-name> Create a new SDK project
61
+ help [command] display help for command
62
+ ```
63
+
64
+ ### Create Command Options
65
+
66
+ ```
67
+ Usage: sdkgen create [options] <project-name>
68
+
69
+ Create a new SDK project
70
+
71
+ Options:
72
+ -t, --template <template> template to use (default: "default")
73
+ -s, --schema <path> path to schema file
74
+ --skip-install skip dependency installation
75
+ --verbose enable verbose logging
76
+ --dry-run preview without writing files
77
+ --non-interactive run in non-interactive mode using defaults
78
+ --config <path> path to JSON config file with template configuration
79
+ --overwrite overwrite existing directory
80
+ -h, --help display help for command
81
+ ```
82
+
83
+ ## Creating Templates
84
+
85
+ Templates are npm packages or local directories with a specific structure that defines how to generate SDK code.
86
+
87
+ ### Template Structure
88
+
89
+ ```
90
+ my-sdk-template/
91
+ ├── package.json # Template package metadata
92
+ ├── template.config.js # Template configuration
93
+ ├── template/ # File templates
94
+ │ ├── package.json.ejs
95
+ │ ├── src/
96
+ │ │ ├── index.ts.ejs
97
+ │ │ └── types.ts.ejs
98
+ │ ├── README.md.ejs
99
+ │ └── .gitignore
100
+ ├── scripts/ # Hook scripts
101
+ │ ├── pre-generate.js
102
+ │ └── post-generate.js
103
+ └── transformers/ # Schema transformers (optional)
104
+ └── default.js
105
+ ```
106
+
107
+ ### Minimal Template Example
108
+
109
+ Here's a simple template that generates a "Hello World" SDK:
110
+
111
+ #### `template.config.js`
112
+
113
+ ```javascript
114
+ module.exports = {
115
+ name: "hello-world-template",
116
+ description: "A simple Hello World SDK template",
117
+
118
+ // Define prompts for user input
119
+ prompts: [
120
+ {
121
+ type: "input",
122
+ name: "greeting",
123
+ message: "What greeting would you like to use?",
124
+ default: "Hello, World!",
125
+ },
126
+ {
127
+ type: "input",
128
+ name: "author",
129
+ message: "Author name?",
130
+ default: "Palantir SDK Generator",
131
+ },
132
+ ],
133
+
134
+ // Files to process as EJS templates
135
+ templateFiles: ["**/*.ejs"],
136
+
137
+ // Files to copy without processing
138
+ staticFiles: [".gitignore", "**/*.md"],
139
+
140
+ // Hooks for custom logic
141
+ hooks: {
142
+ beforeGenerate: "./scripts/pre-generate.js",
143
+ afterGenerate: "./scripts/post-generate.js",
144
+ },
145
+ };
146
+ ```
147
+
148
+ #### `template/package.json.ejs`
149
+
150
+ ```json
151
+ {
152
+ "name": "<%= projectName %>",
153
+ "version": "1.0.0",
154
+ "description": "SDK generated from schema",
155
+ "main": "dist/index.js",
156
+ "types": "dist/index.d.ts",
157
+ "author": "<%= author %>",
158
+ "license": "<%= license %>",
159
+ "scripts": {
160
+ "build": "tsc",
161
+ "test": "jest"
162
+ },
163
+ "devDependencies": {
164
+ "typescript": "^5.0.0",
165
+ "@types/node": "^20.0.0"
166
+ }
167
+ }
168
+ ```
169
+
170
+ #### `template/src/helloWorld.ts.ejs`
171
+
172
+ ```typescript
173
+ /**
174
+ * Generated on <%= new Date().toISOString() %>
175
+ * Author: <%= author %>
176
+ */
177
+
178
+ export class HelloWorld {
179
+ private greeting: string = '<%= greeting %>';
180
+
181
+ constructor(customGreeting?: string) {
182
+ if (customGreeting) {
183
+ this.greeting = customGreeting;
184
+ }
185
+ }
186
+
187
+ greet(name: string = 'World'): string {
188
+ return `${this.greeting}, ${name}!`;
189
+ }
190
+
191
+ // Schema information
192
+ getSchemaInfo(): object {
193
+ return <%- JSON.stringify(schema, null, 2) %>;
194
+ }
195
+ }
196
+
197
+ export default HelloWorld;
198
+ ```
199
+
200
+ #### `scripts/pre-generate.js`
201
+
202
+ ```javascript
203
+ module.exports = async function preGenerate(context) {
204
+ const { projectName, schema, answers, templateConfig } = context;
205
+
206
+ console.log(`🚀 Preparing to generate ${projectName}`);
207
+ console.log(`📋 Using template: ${templateConfig.name}`);
208
+ console.log(`👤 Author: ${answers.author}`);
209
+
210
+ // Validate schema
211
+ if (!schema || Object.keys(schema).length === 0) {
212
+ console.warn("⚠️ Warning: Schema is empty");
213
+ }
214
+
215
+ // Modify context if needed
216
+ context.additionalData = {
217
+ generatedAt: new Date().toISOString(),
218
+ nodeVersion: process.version,
219
+ };
220
+
221
+ return context;
222
+ };
223
+ ```
224
+
225
+ #### `scripts/post-generate.js`
226
+
227
+ ```javascript
228
+ const fs = require("fs-extra");
229
+ const path = require("path");
230
+
231
+ module.exports = async function postGenerate(context, outputPath) {
232
+ const { projectName, answers } = context;
233
+
234
+ console.log(`✨ Finalizing ${projectName}`);
235
+
236
+ // Create additional directories
237
+ await fs.ensureDir(path.join(outputPath, "dist"));
238
+ await fs.ensureDir(path.join(outputPath, "tests"));
239
+
240
+ // Create a simple test file
241
+ const testContent = `
242
+ import HelloWorld from '../src/helloWorld';
243
+
244
+ describe('HelloWorld', () => {
245
+ it('should greet correctly', () => {
246
+ const hw = new HelloWorld();
247
+ expect(hw.greet('SDK')).toBe('${answers.greeting}, SDK!');
248
+ });
249
+ });
250
+ `;
251
+
252
+ await fs.writeFile(
253
+ path.join(outputPath, "tests", "helloWorld.test.ts"),
254
+ testContent.trim(),
255
+ );
256
+
257
+ // Create TypeScript config
258
+ const tsConfig = {
259
+ compilerOptions: {
260
+ target: "ES2020",
261
+ module: "commonjs",
262
+ declaration: true,
263
+ outDir: "./dist",
264
+ rootDir: "./src",
265
+ strict: true,
266
+ esModuleInterop: true,
267
+ skipLibCheck: true,
268
+ forceConsistentCasingInFileNames: true,
269
+ },
270
+ include: ["src/**/*"],
271
+ exclude: ["node_modules", "dist", "tests"],
272
+ };
273
+
274
+ await fs.writeJSON(
275
+ path.join(outputPath, "tsconfig.json"),
276
+ tsConfig,
277
+ { spaces: 2 },
278
+ );
279
+
280
+ console.log("📦 Package structure created successfully!");
281
+ };
282
+ ```
283
+
284
+ ### Hook Execution Model
285
+
286
+ **Important**: Template hooks run as separate Node.js processes in the template's directory context. This means:
287
+
288
+ 1. **Dependency Isolation**: Hooks have access to the template package's `node_modules`, not the CLI's
289
+ 2. **Version Independence**: The template can depend on a specific version of `@palantir/pack.sdkgen` and other tools
290
+ 3. **Context Passing**: Hook context is serialized to JSON and passed via command-line arguments
291
+ 4. **Return Values**: Hooks can return modified context (for `beforeGenerate`) via stdout
292
+
293
+ Example hook that uses template dependencies:
294
+
295
+ ```javascript
296
+ // hooks/afterGenerate.js
297
+ import { execSync } from "child_process";
298
+
299
+ export default async function afterGenerate(context) {
300
+ const { outputPath, schemaPath } = context;
301
+
302
+ // This uses the template's own dependencies
303
+ const typeGenPath = require.resolve("@my-org/type-generator/bin/cli.js");
304
+
305
+ execSync(
306
+ `node "${typeGenPath}" -i "${schemaPath}" -o "${outputPath}/types"`,
307
+ {
308
+ stdio: "inherit",
309
+ cwd: outputPath,
310
+ },
311
+ );
312
+ }
313
+ ```
314
+
315
+ ### Advanced Template Features
316
+
317
+ #### Custom Schema Transformers
318
+
319
+ ```javascript
320
+ // transformers/default.js
321
+ module.exports = {
322
+ async transform(schema, context) {
323
+ // Transform the raw schema into a format your templates can use
324
+ return {
325
+ version: schema.version || "1.0.0",
326
+ endpoints: extractEndpoints(schema),
327
+ types: extractTypes(schema),
328
+ metadata: {
329
+ generatedAt: new Date().toISOString(),
330
+ sourceFile: context.schemaPath,
331
+ },
332
+ };
333
+ },
334
+ };
335
+
336
+ function extractEndpoints(schema) {
337
+ // Your schema parsing logic
338
+ return [];
339
+ }
340
+
341
+ function extractTypes(schema) {
342
+ // Your type extraction logic
343
+ return [];
344
+ }
345
+ ```
346
+
347
+ #### Template Variables
348
+
349
+ Templates have access to these variables:
350
+
351
+ - `projectName` - The name of the project being created
352
+ - `schema` - The transformed schema data
353
+ - `answers` - User responses to prompts
354
+ - `utils` - Helper functions (see below)
355
+ - Any additional data added by hooks
356
+
357
+ #### Utility Functions
358
+
359
+ ```javascript
360
+ // Available in templates as `utils`
361
+ {
362
+ camelCase: (str) => string, // Convert to camelCase
363
+ pascalCase: (str) => string, // Convert to PascalCase
364
+ kebabCase: (str) => string, // Convert to kebab-case
365
+ snakeCase: (str) => string, // Convert to snake_case
366
+ pluralize: (str) => string, // Pluralize a word
367
+ singularize: (str) => string, // Singularize a word
368
+ capitalize: (str) => string, // Capitalize first letter
369
+ lower: (str) => string, // Convert to lowercase
370
+ upper: (str) => string // Convert to uppercase
371
+ }
372
+ ```
373
+
374
+ ## CLI Development Guide
375
+
376
+ ### Project Structure
377
+
378
+ ```
379
+ sdkgen/
380
+ ├── src/
381
+ │ ├── cli.ts # CLI entry point
382
+ │ ├── commands/
383
+ │ │ └── create.ts # Create command implementation
384
+ │ ├── core/
385
+ │ │ ├── generator.ts # Core generation engine
386
+ │ │ ├── template-loader.ts # Template loading logic
387
+ │ │ └── schema-parser.ts # Schema parsing utilities
388
+ │ ├── utils/
389
+ │ │ ├── prompts.ts # User prompt utilities
390
+ │ │ ├── logger.ts # Logging utilities
391
+ │ │ └── file-system.ts # File system helpers
392
+ │ └── types/
393
+ │ └── index.ts # TypeScript type definitions
394
+ ├── templates/
395
+ │ └── default/ # Default template
396
+ ├── bin/
397
+ │ └── cli.js # Executable entry point
398
+ ├── package.json
399
+ ├── tsconfig.json
400
+ └── README.md
401
+ ```
402
+
403
+ ### Implementation Steps
404
+
405
+ 1. **Set up the project**
406
+ ```bash
407
+ mkdir sdkgen
408
+ cd sdkgen
409
+ npm init -y
410
+ npm install commander inquirer ejs fs-extra glob chalk
411
+ npm install -D typescript @types/node @types/inquirer @types/ejs
412
+ ```
413
+
414
+ 2. **Create the CLI entry point**
415
+ ```typescript
416
+ // src/cli.ts
417
+ #!/usr/bin/env node
418
+ import { Command } from 'commander';
419
+ import { create } from './commands/create';
420
+
421
+ const program = new Command();
422
+
423
+ program
424
+ .name('sdkgen')
425
+ .description('Generate SDKs from schema definitions')
426
+ .version('1.0.0');
427
+
428
+ program
429
+ .command('create <project-name>')
430
+ .description('Create a new SDK project')
431
+ .option('-t, --template <template>', 'template to use', 'default')
432
+ .option('-s, --schema <path>', 'path to schema file')
433
+ .option('--skip-install', 'skip dependency installation')
434
+ .option('--verbose', 'enable verbose logging')
435
+ .option('--dry-run', 'preview without writing files')
436
+ .action(create);
437
+
438
+ program.parse();
439
+ ```
440
+
441
+ 3. **Implement the generator core**
442
+ ```typescript
443
+ // src/core/generator.ts
444
+ import ejs from "ejs";
445
+ import fs from "fs-extra";
446
+ import glob from "glob";
447
+ import path from "path";
448
+
449
+ export class Generator {
450
+ constructor(private context: GeneratorContext) {}
451
+
452
+ async generate(outputPath: string): Promise<void> {
453
+ // Implementation as shown in architecture section
454
+ }
455
+ }
456
+ ```
457
+
458
+ 4. **Build and link for testing**
459
+ ```bash
460
+ npm run build
461
+ npm link
462
+ npx @palantir/pack.sdkgen create test-project --schema ./test.json
463
+ ```
464
+
465
+ ## API Reference
466
+
467
+ ### Generator Context
468
+
469
+ ```typescript
470
+ interface GeneratorContext {
471
+ projectName: string;
472
+ schema: any;
473
+ answers: Record<string, any>;
474
+ templateConfig: TemplateConfig;
475
+ schemaPath: string;
476
+ outputPath: string;
477
+ options: {
478
+ skipInstall?: boolean;
479
+ verbose?: boolean;
480
+ dryRun?: boolean;
481
+ };
482
+ }
483
+ ```
484
+
485
+ ### Template Configuration
486
+
487
+ ```typescript
488
+ interface TemplateConfig {
489
+ name: string;
490
+ description: string;
491
+ prompts?: PromptQuestion[];
492
+ templateFiles?: string[];
493
+ staticFiles?: string[];
494
+ hooks?: {
495
+ beforeGenerate?: string | Function;
496
+ afterGenerate?: string | Function;
497
+ beforeInstall?: string | Function;
498
+ afterInstall?: string | Function;
499
+ };
500
+ transformers?: {
501
+ [key: string]: string | Function;
502
+ };
503
+ dependencies?: Record<string, string>;
504
+ devDependencies?: Record<string, string>;
505
+ }
506
+ ```
507
+
508
+ ### Hook Functions
509
+
510
+ ```typescript
511
+ // Pre-generate hook
512
+ type PreGenerateHook = (context: GeneratorContext) => Promise<GeneratorContext>;
513
+
514
+ // Post-generate hook
515
+ type PostGenerateHook = (
516
+ context: GeneratorContext,
517
+ outputPath: string,
518
+ ) => Promise<void>;
519
+ ```
520
+
521
+ ## Examples
522
+
523
+ ### Creating a REST API Client Template
524
+
525
+ ```javascript
526
+ // template.config.js
527
+ module.exports = {
528
+ name: "rest-api-client",
529
+ prompts: [
530
+ {
531
+ type: "input",
532
+ name: "baseUrl",
533
+ message: "API base URL?",
534
+ default: "https://api.example.com",
535
+ },
536
+ {
537
+ type: "list",
538
+ name: "httpClient",
539
+ message: "HTTP client library?",
540
+ choices: ["fetch", "axios", "node-fetch"],
541
+ },
542
+ ],
543
+ hooks: {
544
+ afterGenerate: async (context, outputPath) => {
545
+ // Install selected HTTP client
546
+ const { httpClient } = context.answers;
547
+ if (httpClient === "axios") {
548
+ // Add axios to package.json dependencies
549
+ }
550
+ },
551
+ },
552
+ };
553
+ ```
554
+
555
+ ### Using Environment-Specific Configuration
556
+
557
+ ```bash
558
+ # Development
559
+ TEMPLATE_ENV=dev npx @palantir/pack.sdkgen create my-sdk \
560
+ --schema ./schema.json
561
+
562
+ # Production
563
+ TEMPLATE_ENV=prod npx @palantir/pack.sdkgen create my-sdk \
564
+ --schema ./schema.json
565
+ ```
566
+
567
+ ---
568
+
569
+ ## Troubleshooting
570
+
571
+ ### Common Issues
572
+
573
+ **Template not found**
574
+
575
+ - Ensure the template package is published to npm
576
+ - Check that the template path is correct for local templates
577
+ - Verify the template has a valid `template.config.js`
578
+
579
+ **Schema parsing errors**
580
+
581
+ - Validate your schema file is valid JSON/YAML
582
+ - Check that the schema transformer matches your schema format
583
+ - Use `--verbose` flag for detailed error messages
584
+
585
+ **Generation fails**
586
+
587
+ - Run with `--dry-run` first to preview changes
588
+ - Check hook scripts for errors
589
+ - Ensure all required template variables are provided
package/bin/cli.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env -S npx bun@1.3.0
2
+
3
+ // We run the CLI using tsx so certain commands can import ts files and take
4
+ // advantage of the ts loader. We use the built version for packaging reasons.
5
+
6
+ import { cli } from "../build/esm/index.js";
7
+ cli(process.argv);