@hazeljs/cli 0.5.4 → 0.6.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 (101) hide show
  1. package/@template-ai-native/package.json +1 -1
  2. package/README.md +122 -591
  3. package/dist/commands/add.js +26 -126
  4. package/dist/commands/generate-app.js +17 -230
  5. package/dist/commands/generate-simple.d.ts +27 -0
  6. package/dist/commands/generate-simple.js +448 -0
  7. package/dist/commands/generate-simple.test.js +100 -0
  8. package/dist/index.js +5 -47
  9. package/dist/index.list.test.js +8 -22
  10. package/dist/index.test.js +19 -56
  11. package/dist/utils/generator-registry.js +29 -65
  12. package/dist/utils/generator.d.ts +0 -1
  13. package/dist/utils/generator.js +0 -22
  14. package/dist/utils/generator.test.js +0 -28
  15. package/dist/utils/packages-registry.d.ts +25 -0
  16. package/dist/utils/packages-registry.js +371 -0
  17. package/package.json +3 -5
  18. package/dist/commands/build.d.ts +0 -2
  19. package/dist/commands/build.js +0 -52
  20. package/dist/commands/generate-agent.d.ts +0 -4
  21. package/dist/commands/generate-agent.js +0 -64
  22. package/dist/commands/generate-agent.test.js +0 -36
  23. package/dist/commands/generate-ai-service.d.ts +0 -4
  24. package/dist/commands/generate-ai-service.js +0 -54
  25. package/dist/commands/generate-ai-service.test.d.ts +0 -1
  26. package/dist/commands/generate-ai-service.test.js +0 -41
  27. package/dist/commands/generate-cache.d.ts +0 -4
  28. package/dist/commands/generate-cache.js +0 -66
  29. package/dist/commands/generate-cache.test.d.ts +0 -1
  30. package/dist/commands/generate-cache.test.js +0 -36
  31. package/dist/commands/generate-config.d.ts +0 -4
  32. package/dist/commands/generate-config.js +0 -59
  33. package/dist/commands/generate-config.test.d.ts +0 -1
  34. package/dist/commands/generate-config.test.js +0 -35
  35. package/dist/commands/generate-controller.d.ts +0 -4
  36. package/dist/commands/generate-controller.js +0 -66
  37. package/dist/commands/generate-controller.test.d.ts +0 -1
  38. package/dist/commands/generate-controller.test.js +0 -48
  39. package/dist/commands/generate-cron.d.ts +0 -4
  40. package/dist/commands/generate-cron.js +0 -61
  41. package/dist/commands/generate-cron.test.d.ts +0 -1
  42. package/dist/commands/generate-cron.test.js +0 -42
  43. package/dist/commands/generate-discovery.d.ts +0 -4
  44. package/dist/commands/generate-discovery.js +0 -63
  45. package/dist/commands/generate-discovery.test.d.ts +0 -1
  46. package/dist/commands/generate-discovery.test.js +0 -36
  47. package/dist/commands/generate-exception-filter.d.ts +0 -4
  48. package/dist/commands/generate-exception-filter.js +0 -54
  49. package/dist/commands/generate-exception-filter.test.d.ts +0 -1
  50. package/dist/commands/generate-exception-filter.test.js +0 -43
  51. package/dist/commands/generate-guard.d.ts +0 -4
  52. package/dist/commands/generate-guard.js +0 -42
  53. package/dist/commands/generate-guard.test.d.ts +0 -1
  54. package/dist/commands/generate-guard.test.js +0 -41
  55. package/dist/commands/generate-interceptor.d.ts +0 -4
  56. package/dist/commands/generate-interceptor.js +0 -43
  57. package/dist/commands/generate-interceptor.test.d.ts +0 -1
  58. package/dist/commands/generate-interceptor.test.js +0 -41
  59. package/dist/commands/generate-middleware.d.ts +0 -4
  60. package/dist/commands/generate-middleware.js +0 -47
  61. package/dist/commands/generate-middleware.test.d.ts +0 -1
  62. package/dist/commands/generate-middleware.test.js +0 -41
  63. package/dist/commands/generate-pipe.d.ts +0 -4
  64. package/dist/commands/generate-pipe.js +0 -39
  65. package/dist/commands/generate-pipe.test.d.ts +0 -1
  66. package/dist/commands/generate-pipe.test.js +0 -35
  67. package/dist/commands/generate-rag.d.ts +0 -4
  68. package/dist/commands/generate-rag.js +0 -68
  69. package/dist/commands/generate-rag.test.d.ts +0 -1
  70. package/dist/commands/generate-rag.test.js +0 -35
  71. package/dist/commands/generate-repository.d.ts +0 -4
  72. package/dist/commands/generate-repository.js +0 -46
  73. package/dist/commands/generate-repository.test.d.ts +0 -1
  74. package/dist/commands/generate-repository.test.js +0 -41
  75. package/dist/commands/generate-serverless-handler.d.ts +0 -4
  76. package/dist/commands/generate-serverless-handler.js +0 -57
  77. package/dist/commands/generate-serverless-handler.test.d.ts +0 -1
  78. package/dist/commands/generate-serverless-handler.test.js +0 -42
  79. package/dist/commands/generate-service.d.ts +0 -4
  80. package/dist/commands/generate-service.js +0 -58
  81. package/dist/commands/generate-service.test.d.ts +0 -1
  82. package/dist/commands/generate-service.test.js +0 -41
  83. package/dist/commands/generate-setup.d.ts +0 -4
  84. package/dist/commands/generate-setup.js +0 -187
  85. package/dist/commands/generate-setup.test.d.ts +0 -1
  86. package/dist/commands/generate-setup.test.js +0 -50
  87. package/dist/commands/generate-websocket-gateway.d.ts +0 -4
  88. package/dist/commands/generate-websocket-gateway.js +0 -53
  89. package/dist/commands/generate-websocket-gateway.test.d.ts +0 -1
  90. package/dist/commands/generate-websocket-gateway.test.js +0 -41
  91. package/dist/commands/pdf-to-audio.d.ts +0 -2
  92. package/dist/commands/pdf-to-audio.js +0 -170
  93. package/dist/commands/pdf-to-audio.test.d.ts +0 -1
  94. package/dist/commands/pdf-to-audio.test.js +0 -92
  95. package/dist/commands/start.d.ts +0 -2
  96. package/dist/commands/start.js +0 -61
  97. package/dist/commands/test.d.ts +0 -2
  98. package/dist/commands/test.js +0 -63
  99. package/dist/commands/utility-commands.test.d.ts +0 -1
  100. package/dist/commands/utility-commands.test.js +0 -95
  101. /package/dist/commands/{generate-agent.test.d.ts → generate-simple.test.d.ts} +0 -0
@@ -1,170 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.pdfToAudioCommand = pdfToAudioCommand;
7
- const chalk_1 = __importDefault(require("chalk"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
- const form_data_1 = __importDefault(require("form-data"));
11
- const DEFAULT_API_URL = process.env.HAZEL_API_URL || 'http://localhost:3000';
12
- async function submitJob(apiUrl, filePath, options) {
13
- const formData = new form_data_1.default();
14
- formData.append('file', fs_1.default.createReadStream(filePath), path_1.default.basename(filePath));
15
- if (options.voice)
16
- formData.append('voice', options.voice);
17
- if (options.includeSummary === false)
18
- formData.append('includeSummary', 'false');
19
- if (options.summaryOnly === true)
20
- formData.append('summaryOnly', 'true');
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- const res = await fetch(`${apiUrl}/api/pdf-to-audio/convert`, {
23
- method: 'POST',
24
- body: formData,
25
- headers: formData.getHeaders(),
26
- });
27
- if (!res.ok) {
28
- const text = await res.text();
29
- throw new Error(`Submit failed (${res.status}): ${text}`);
30
- }
31
- const json = (await res.json());
32
- if (!json.jobId)
33
- throw new Error('No jobId in response');
34
- return json.jobId;
35
- }
36
- async function getStatus(apiUrl, jobId) {
37
- const res = await fetch(`${apiUrl}/api/pdf-to-audio/status/${encodeURIComponent(jobId)}`);
38
- if (!res.ok) {
39
- if (res.status === 404)
40
- return null;
41
- throw new Error(`Status failed (${res.status}): ${await res.text()}`);
42
- }
43
- return (await res.json());
44
- }
45
- async function downloadAudio(apiUrl, jobId) {
46
- const res = await fetch(`${apiUrl}/api/pdf-to-audio/download/${encodeURIComponent(jobId)}`);
47
- if (!res.ok)
48
- throw new Error(`Download failed (${res.status}): ${await res.text()}`);
49
- const arrayBuffer = await res.arrayBuffer();
50
- return Buffer.from(arrayBuffer);
51
- }
52
- function pdfToAudioCommand(program) {
53
- const pdfToAudio = program
54
- .command('pdf-to-audio')
55
- .description('Convert PDF to audio via async job (submit, poll status, download)');
56
- pdfToAudio
57
- .command('convert <file.pdf>')
58
- .description('Submit PDF for conversion, returns job ID')
59
- .option('-o, --output <path>', 'Output MP3 path (used with --wait)')
60
- .option('--voice <name>', 'TTS voice (alloy, echo, fable, onyx, nova, shimmer, ash, sage, coral)', 'alloy')
61
- .option('--no-summary', 'Skip AI-generated document summary')
62
- .option('--summary-only', 'Output only the summary, do not read the full document')
63
- .option('--api-url <url>', 'API base URL', DEFAULT_API_URL)
64
- .option('--wait', 'Poll until complete and download to --output')
65
- .option('--poll-interval <ms>', 'Poll interval in ms', '3000')
66
- .action(async (filePath, opts) => {
67
- try {
68
- if (!filePath?.toLowerCase().endsWith('.pdf')) {
69
- console.log(chalk_1.default.red('✗ Please provide a PDF file path'));
70
- process.exit(1);
71
- }
72
- const resolvedPath = path_1.default.isAbsolute(filePath) ? filePath : path_1.default.resolve(process.cwd(), filePath);
73
- if (!fs_1.default.existsSync(resolvedPath)) {
74
- console.log(chalk_1.default.red(`✗ File not found: ${resolvedPath}`));
75
- process.exit(1);
76
- }
77
- const apiUrl = (opts.apiUrl || DEFAULT_API_URL).replace(/\/$/, '');
78
- const includeSummary = opts.summary !== false;
79
- const summaryOnly = opts.summaryOnly === true;
80
- console.log(chalk_1.default.blue('📄 Submitting PDF for conversion...'));
81
- console.log(chalk_1.default.gray(` API: ${apiUrl}`));
82
- console.log(chalk_1.default.gray(` File: ${resolvedPath}`));
83
- console.log(chalk_1.default.gray(` Voice: ${opts.voice || 'alloy'}`));
84
- if (summaryOnly)
85
- console.log(chalk_1.default.gray(` Mode: summary only`));
86
- const jobId = await submitJob(apiUrl, resolvedPath, {
87
- voice: opts.voice,
88
- includeSummary,
89
- summaryOnly,
90
- });
91
- console.log(chalk_1.default.green(`\n✓ Job submitted: ${jobId}`));
92
- if (opts.wait) {
93
- const outputPath = opts.output ||
94
- path_1.default.join(path_1.default.dirname(resolvedPath), path_1.default.basename(resolvedPath, '.pdf') + '.mp3');
95
- const interval = parseInt(opts.pollInterval || '3000', 10);
96
- console.log(chalk_1.default.gray(`\nPolling every ${interval}ms...`));
97
- // eslint-disable-next-line no-constant-condition
98
- while (true) {
99
- const status = await getStatus(apiUrl, jobId);
100
- if (!status) {
101
- console.log(chalk_1.default.red('✗ Job not found or expired'));
102
- process.exit(1);
103
- }
104
- const pct = status.progress ?? 0;
105
- const msg = status.message ? ` - ${status.message}` : '';
106
- process.stdout.write(chalk_1.default.gray(` Status: ${status.status} ${pct}%${msg}`));
107
- if (status.status === 'completed') {
108
- console.log(chalk_1.default.gray(' done'));
109
- const audio = await downloadAudio(apiUrl, jobId);
110
- fs_1.default.writeFileSync(outputPath, audio);
111
- console.log(chalk_1.default.green(`\n✓ Saved: ${outputPath}`));
112
- return;
113
- }
114
- if (status.status === 'failed') {
115
- console.log(chalk_1.default.red(`\n✗ Conversion failed: ${status.error || 'Unknown error'}`));
116
- process.exit(1);
117
- }
118
- console.log('');
119
- await new Promise((r) => setTimeout(r, interval));
120
- }
121
- }
122
- console.log(chalk_1.default.gray('\nCheck status: hazel pdf-to-audio status ' + jobId + ' --api-url ' + apiUrl));
123
- if (opts.output) {
124
- console.log(chalk_1.default.gray('Download when ready: hazel pdf-to-audio status ' + jobId + ' -o ' + opts.output + ' --api-url ' + apiUrl));
125
- }
126
- }
127
- catch (error) {
128
- console.error(chalk_1.default.red('\n✗ Error:'), error instanceof Error ? error.message : error);
129
- process.exit(1);
130
- }
131
- });
132
- pdfToAudio
133
- .command('status <jobId>')
134
- .description('Check job status and optionally download when ready')
135
- .option('-o, --output <path>', 'Download audio to this path when completed')
136
- .option('--api-url <url>', 'API base URL', DEFAULT_API_URL)
137
- .action(async (jobId, opts) => {
138
- try {
139
- const apiUrl = (opts.apiUrl || DEFAULT_API_URL).replace(/\/$/, '');
140
- const status = await getStatus(apiUrl, jobId);
141
- if (!status) {
142
- console.log(chalk_1.default.red('✗ Job not found or expired'));
143
- process.exit(1);
144
- }
145
- console.log(chalk_1.default.blue('Job status:'));
146
- console.log(chalk_1.default.gray(` ID: ${status.jobId}`));
147
- console.log(chalk_1.default.gray(` Status: ${status.status}`));
148
- console.log(chalk_1.default.gray(` Progress: ${status.progress}%`));
149
- if (status.message)
150
- console.log(chalk_1.default.gray(` Message: ${status.message}`));
151
- if (status.totalChunks != null) {
152
- console.log(chalk_1.default.gray(` Chunks: ${status.completedChunks ?? 0}/${status.totalChunks}`));
153
- }
154
- if (status.error)
155
- console.log(chalk_1.default.red(` Error: ${status.error}`));
156
- if (status.status === 'completed' && opts.output) {
157
- const audio = await downloadAudio(apiUrl, jobId);
158
- fs_1.default.writeFileSync(opts.output, audio);
159
- console.log(chalk_1.default.green(`\n✓ Downloaded: ${opts.output}`));
160
- }
161
- else if (status.status === 'completed' && !opts.output) {
162
- console.log(chalk_1.default.gray('\nDownload: GET ' + apiUrl + '/api/pdf-to-audio/download/' + jobId));
163
- }
164
- }
165
- catch (error) {
166
- console.error(chalk_1.default.red('\n✗ Error:'), error instanceof Error ? error.message : error);
167
- process.exit(1);
168
- }
169
- });
170
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,92 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const fs_1 = __importDefault(require("fs"));
7
- const commander_1 = require("commander");
8
- const form_data_1 = __importDefault(require("form-data"));
9
- const pdf_to_audio_1 = require("./pdf-to-audio");
10
- jest.mock('fs');
11
- jest.mock('form-data', () => {
12
- return jest.fn().mockImplementation(() => ({
13
- append: jest.fn(),
14
- getHeaders: jest.fn(() => ({})),
15
- }));
16
- });
17
- describe('pdf-to-audio', () => {
18
- const mockFs = fs_1.default;
19
- const MockFormData = form_data_1.default;
20
- let exitSpy;
21
- let logSpy;
22
- let errSpy;
23
- beforeAll(() => {
24
- exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined);
25
- logSpy = jest.spyOn(console, 'log').mockImplementation(() => undefined);
26
- errSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
27
- });
28
- afterAll(() => {
29
- exitSpy.mockRestore();
30
- logSpy.mockRestore();
31
- errSpy.mockRestore();
32
- });
33
- beforeEach(() => {
34
- jest.clearAllMocks();
35
- global.fetch = jest.fn();
36
- mockFs.createReadStream.mockReturnValue({});
37
- });
38
- it('convert: exits when file is not a PDF', async () => {
39
- const program = new commander_1.Command();
40
- (0, pdf_to_audio_1.pdfToAudioCommand)(program);
41
- await program.parseAsync(['pdf-to-audio', 'convert', 'not-a-pdf.txt'], { from: 'user' });
42
- expect(exitSpy).toHaveBeenCalledWith(1);
43
- });
44
- it('convert: exits when file does not exist', async () => {
45
- mockFs.existsSync.mockReturnValue(false);
46
- const program = new commander_1.Command();
47
- (0, pdf_to_audio_1.pdfToAudioCommand)(program);
48
- await program.parseAsync(['pdf-to-audio', 'convert', 'file.pdf'], { from: 'user' });
49
- expect(exitSpy).toHaveBeenCalledWith(1);
50
- });
51
- it('convert: submits job and prints job id (no wait)', async () => {
52
- mockFs.existsSync.mockReturnValue(true);
53
- global.fetch.mockResolvedValue({
54
- ok: true,
55
- json: async () => ({ jobId: 'job-123' }),
56
- });
57
- const program = new commander_1.Command();
58
- (0, pdf_to_audio_1.pdfToAudioCommand)(program);
59
- await program.parseAsync(['pdf-to-audio', 'convert', 'file.pdf', '--api-url', 'http://x'], { from: 'user' });
60
- expect(MockFormData).toHaveBeenCalled();
61
- expect(global.fetch).toHaveBeenCalled();
62
- const out = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
63
- expect(out).toContain('Job submitted: job-123');
64
- });
65
- it('status: prints download hint when completed without output', async () => {
66
- global.fetch.mockResolvedValue({
67
- ok: true,
68
- json: async () => ({ jobId: 'job-1', status: 'completed', progress: 100 }),
69
- });
70
- const program = new commander_1.Command();
71
- (0, pdf_to_audio_1.pdfToAudioCommand)(program);
72
- await program.parseAsync(['pdf-to-audio', 'status', 'job-1', '--api-url', 'http://x'], { from: 'user' });
73
- const out = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
74
- expect(out).toContain('Download: GET');
75
- });
76
- it('status: downloads audio when completed with output', async () => {
77
- global.fetch
78
- .mockResolvedValueOnce({
79
- ok: true,
80
- json: async () => ({ jobId: 'job-2', status: 'completed', progress: 100 }),
81
- })
82
- .mockResolvedValueOnce({
83
- ok: true,
84
- arrayBuffer: async () => new ArrayBuffer(3),
85
- text: async () => '',
86
- });
87
- const program = new commander_1.Command();
88
- (0, pdf_to_audio_1.pdfToAudioCommand)(program);
89
- await program.parseAsync(['pdf-to-audio', 'status', 'job-2', '--api-url', 'http://x', '--output', 'out.mp3'], { from: 'user' });
90
- expect(mockFs.writeFileSync).toHaveBeenCalledWith('out.mp3', expect.any(Buffer));
91
- });
92
- });
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function startCommand(program: Command): void;
@@ -1,61 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.startCommand = startCommand;
7
- const child_process_1 = require("child_process");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const fs_1 = __importDefault(require("fs"));
10
- const path_1 = __importDefault(require("path"));
11
- function startCommand(program) {
12
- program
13
- .command('start')
14
- .description('Start the HazelJS application')
15
- .option('-d, --dev', 'Start in development mode')
16
- .option('-p, --port <port>', 'Specify port')
17
- .action((options) => {
18
- try {
19
- const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
20
- if (!fs_1.default.existsSync(packageJsonPath)) {
21
- console.log(chalk_1.default.red('✗ No package.json found'));
22
- console.log(chalk_1.default.gray('Run this command from your project root'));
23
- process.exit(1);
24
- }
25
- const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
26
- let command;
27
- if (options.dev) {
28
- if (!packageJson.scripts?.dev) {
29
- console.log(chalk_1.default.yellow('⚠ No dev script found in package.json'));
30
- console.log(chalk_1.default.gray('\nAdd a dev script to your package.json:'));
31
- console.log(chalk_1.default.gray(' "scripts": {'));
32
- console.log(chalk_1.default.gray(' "dev": "ts-node-dev --respawn src/index.ts"'));
33
- console.log(chalk_1.default.gray(' }'));
34
- process.exit(1);
35
- }
36
- command = 'npm run dev';
37
- console.log(chalk_1.default.blue('🚀 Starting in development mode...\n'));
38
- }
39
- else {
40
- if (!packageJson.scripts?.start) {
41
- console.log(chalk_1.default.yellow('⚠ No start script found in package.json'));
42
- console.log(chalk_1.default.gray('\nAdd a start script to your package.json:'));
43
- console.log(chalk_1.default.gray(' "scripts": {'));
44
- console.log(chalk_1.default.gray(' "start": "node dist/index.js"'));
45
- console.log(chalk_1.default.gray(' }'));
46
- process.exit(1);
47
- }
48
- command = 'npm start';
49
- console.log(chalk_1.default.blue('🚀 Starting application...\n'));
50
- }
51
- if (options.port) {
52
- process.env.PORT = options.port;
53
- }
54
- (0, child_process_1.execSync)(command, { stdio: 'inherit' });
55
- }
56
- catch {
57
- console.error(chalk_1.default.red('\n✗ Failed to start application'));
58
- process.exit(1);
59
- }
60
- });
61
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function testCommand(program: Command): void;
@@ -1,63 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.testCommand = testCommand;
7
- const child_process_1 = require("child_process");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const fs_1 = __importDefault(require("fs"));
10
- const path_1 = __importDefault(require("path"));
11
- function testCommand(program) {
12
- program
13
- .command('test [pattern]')
14
- .description('Run tests')
15
- .option('-w, --watch', 'Watch mode')
16
- .option('-c, --coverage', 'Generate coverage report')
17
- .option('--ci', 'Run in CI mode')
18
- .action((pattern, options) => {
19
- try {
20
- const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
21
- if (!fs_1.default.existsSync(packageJsonPath)) {
22
- console.log(chalk_1.default.red('✗ No package.json found'));
23
- console.log(chalk_1.default.gray('Run this command from your project root'));
24
- process.exit(1);
25
- }
26
- const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
27
- if (!packageJson.scripts?.test) {
28
- console.log(chalk_1.default.yellow('⚠ No test script found in package.json'));
29
- console.log(chalk_1.default.gray('\nAdd a test script to your package.json:'));
30
- console.log(chalk_1.default.gray(' "scripts": {'));
31
- console.log(chalk_1.default.gray(' "test": "jest"'));
32
- console.log(chalk_1.default.gray(' }'));
33
- process.exit(1);
34
- }
35
- console.log(chalk_1.default.blue('🧪 Running tests...\n'));
36
- let command = 'npm test';
37
- const args = [];
38
- if (pattern) {
39
- args.push(pattern);
40
- }
41
- if (options?.watch) {
42
- args.push('--watch');
43
- }
44
- if (options?.coverage) {
45
- args.push('--coverage');
46
- }
47
- if (options?.ci) {
48
- command = packageJson.scripts['test:ci'] ? 'npm run test:ci' : 'npm test -- --ci';
49
- }
50
- if (args.length > 0 && !options?.ci) {
51
- command += ' -- ' + args.join(' ');
52
- }
53
- (0, child_process_1.execSync)(command, { stdio: 'inherit' });
54
- if (!options?.watch) {
55
- console.log(chalk_1.default.green('\n✓ Tests completed'));
56
- }
57
- }
58
- catch {
59
- console.error(chalk_1.default.red('\n✗ Tests failed'));
60
- process.exit(1);
61
- }
62
- });
63
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,95 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const fs_1 = __importDefault(require("fs"));
7
- const child_process_1 = require("child_process");
8
- const commander_1 = require("commander");
9
- const build_1 = require("./build");
10
- const start_1 = require("./start");
11
- const test_1 = require("./test");
12
- const info_1 = require("./info");
13
- jest.mock('fs');
14
- jest.mock('child_process', () => ({ execSync: jest.fn() }));
15
- describe('utility commands', () => {
16
- const mockFs = fs_1.default;
17
- const mockExec = child_process_1.execSync;
18
- let exitSpy;
19
- let logSpy;
20
- let errSpy;
21
- beforeAll(() => {
22
- exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined);
23
- logSpy = jest.spyOn(console, 'log').mockImplementation(() => undefined);
24
- errSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
25
- });
26
- afterAll(() => {
27
- exitSpy.mockRestore();
28
- logSpy.mockRestore();
29
- errSpy.mockRestore();
30
- });
31
- beforeEach(() => {
32
- jest.clearAllMocks();
33
- mockExec.mockImplementation(() => undefined);
34
- exitSpy.mockClear();
35
- logSpy.mockClear();
36
- errSpy.mockClear();
37
- delete process.env.PORT;
38
- });
39
- it('build: exits when package.json missing', async () => {
40
- mockFs.existsSync.mockReturnValue(false);
41
- const program = new commander_1.Command();
42
- (0, build_1.buildCommand)(program);
43
- await program.parseAsync(['build'], { from: 'user' });
44
- expect(exitSpy).toHaveBeenCalled();
45
- });
46
- it('build: uses watch command when --watch is set', async () => {
47
- mockFs.existsSync.mockReturnValue(true);
48
- mockFs.readFileSync.mockReturnValue(JSON.stringify({ scripts: { build: 'tsc' } }));
49
- const program = new commander_1.Command();
50
- (0, build_1.buildCommand)(program);
51
- await program.parseAsync(['build', '--watch'], { from: 'user' });
52
- expect(mockExec).toHaveBeenCalledWith('npm run build -- --watch', { stdio: 'inherit' });
53
- });
54
- it('start: dev mode exits when dev script missing', async () => {
55
- mockFs.existsSync.mockReturnValue(true);
56
- mockFs.readFileSync.mockReturnValue(JSON.stringify({ scripts: { start: 'node dist/index.js' } }));
57
- const program = new commander_1.Command();
58
- (0, start_1.startCommand)(program);
59
- await program.parseAsync(['start', '--dev'], { from: 'user' });
60
- expect(exitSpy).toHaveBeenCalled();
61
- });
62
- it('start: sets PORT when provided', async () => {
63
- mockFs.existsSync.mockReturnValue(true);
64
- mockFs.readFileSync.mockReturnValue(JSON.stringify({ scripts: { start: 'node dist/index.js' } }));
65
- const program = new commander_1.Command();
66
- (0, start_1.startCommand)(program);
67
- await program.parseAsync(['start', '--port', '7777'], { from: 'user' });
68
- expect(process.env.PORT).toBe('7777');
69
- expect(mockExec).toHaveBeenCalledWith('npm start', { stdio: 'inherit' });
70
- });
71
- it('test: uses test:ci when present', async () => {
72
- mockFs.existsSync.mockReturnValue(true);
73
- mockFs.readFileSync.mockReturnValue(JSON.stringify({ scripts: { test: 'jest', 'test:ci': 'jest --ci' } }));
74
- const program = new commander_1.Command();
75
- (0, test_1.testCommand)(program);
76
- await program.parseAsync(['test', '--ci'], { from: 'user' });
77
- expect(mockExec).toHaveBeenCalledWith('npm run test:ci', { stdio: 'inherit' });
78
- });
79
- it('test: adds pattern and coverage args when not in ci', async () => {
80
- mockFs.existsSync.mockReturnValue(true);
81
- mockFs.readFileSync.mockReturnValue(JSON.stringify({ scripts: { test: 'jest' } }));
82
- const program = new commander_1.Command();
83
- (0, test_1.testCommand)(program);
84
- await program.parseAsync(['test', 'user.test', '--coverage'], { from: 'user' });
85
- expect(mockExec).toHaveBeenCalledWith('npm test -- user.test --coverage', { stdio: 'inherit' });
86
- });
87
- it('info: returns early when package.json missing', async () => {
88
- mockFs.existsSync.mockReturnValue(false);
89
- const program = new commander_1.Command();
90
- (0, info_1.infoCommand)(program);
91
- await program.parseAsync(['info'], { from: 'user' });
92
- expect(exitSpy).not.toHaveBeenCalled();
93
- expect(logSpy).toHaveBeenCalled();
94
- });
95
- });