@hazeljs/cli 0.2.0-alpha.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 (121) hide show
  1. package/@template/.eslintrc.js +36 -0
  2. package/@template/.lintstagedrc +6 -0
  3. package/@template/README.md +61 -0
  4. package/@template/jest.config.js +28 -0
  5. package/@template/jest.setup.js +81 -0
  6. package/@template/package.json +34 -0
  7. package/@template/src/app.module.ts +7 -0
  8. package/@template/src/hello.controller.ts +9 -0
  9. package/@template/src/index.ts +18 -0
  10. package/@template/tsconfig.json +25 -0
  11. package/LICENSE +192 -0
  12. package/README.md +683 -0
  13. package/dist/commands/add.d.ts +2 -0
  14. package/dist/commands/add.js +176 -0
  15. package/dist/commands/add.test.d.ts +1 -0
  16. package/dist/commands/add.test.js +51 -0
  17. package/dist/commands/build.d.ts +2 -0
  18. package/dist/commands/build.js +52 -0
  19. package/dist/commands/generate-agent.d.ts +2 -0
  20. package/dist/commands/generate-agent.js +58 -0
  21. package/dist/commands/generate-agent.test.d.ts +1 -0
  22. package/dist/commands/generate-agent.test.js +36 -0
  23. package/dist/commands/generate-ai-service.d.ts +2 -0
  24. package/dist/commands/generate-ai-service.js +48 -0
  25. package/dist/commands/generate-ai-service.test.d.ts +1 -0
  26. package/dist/commands/generate-ai-service.test.js +41 -0
  27. package/dist/commands/generate-app.d.ts +2 -0
  28. package/dist/commands/generate-app.js +448 -0
  29. package/dist/commands/generate-auth.d.ts +2 -0
  30. package/dist/commands/generate-auth.js +194 -0
  31. package/dist/commands/generate-auth.test.d.ts +1 -0
  32. package/dist/commands/generate-auth.test.js +48 -0
  33. package/dist/commands/generate-cache.d.ts +2 -0
  34. package/dist/commands/generate-cache.js +64 -0
  35. package/dist/commands/generate-cache.test.d.ts +1 -0
  36. package/dist/commands/generate-cache.test.js +36 -0
  37. package/dist/commands/generate-config.d.ts +2 -0
  38. package/dist/commands/generate-config.js +57 -0
  39. package/dist/commands/generate-config.test.d.ts +1 -0
  40. package/dist/commands/generate-config.test.js +35 -0
  41. package/dist/commands/generate-controller.d.ts +2 -0
  42. package/dist/commands/generate-controller.js +60 -0
  43. package/dist/commands/generate-controller.test.d.ts +1 -0
  44. package/dist/commands/generate-controller.test.js +48 -0
  45. package/dist/commands/generate-cron.d.ts +2 -0
  46. package/dist/commands/generate-cron.js +59 -0
  47. package/dist/commands/generate-cron.test.d.ts +1 -0
  48. package/dist/commands/generate-cron.test.js +42 -0
  49. package/dist/commands/generate-crud.d.ts +2 -0
  50. package/dist/commands/generate-crud.js +177 -0
  51. package/dist/commands/generate-crud.test.d.ts +1 -0
  52. package/dist/commands/generate-crud.test.js +52 -0
  53. package/dist/commands/generate-discovery.d.ts +2 -0
  54. package/dist/commands/generate-discovery.js +61 -0
  55. package/dist/commands/generate-discovery.test.d.ts +1 -0
  56. package/dist/commands/generate-discovery.test.js +36 -0
  57. package/dist/commands/generate-dto.d.ts +2 -0
  58. package/dist/commands/generate-dto.js +69 -0
  59. package/dist/commands/generate-dto.test.d.ts +1 -0
  60. package/dist/commands/generate-dto.test.js +44 -0
  61. package/dist/commands/generate-exception-filter.d.ts +2 -0
  62. package/dist/commands/generate-exception-filter.js +48 -0
  63. package/dist/commands/generate-exception-filter.test.d.ts +1 -0
  64. package/dist/commands/generate-exception-filter.test.js +43 -0
  65. package/dist/commands/generate-guard.d.ts +2 -0
  66. package/dist/commands/generate-guard.js +36 -0
  67. package/dist/commands/generate-guard.test.d.ts +1 -0
  68. package/dist/commands/generate-guard.test.js +41 -0
  69. package/dist/commands/generate-interceptor.d.ts +2 -0
  70. package/dist/commands/generate-interceptor.js +37 -0
  71. package/dist/commands/generate-interceptor.test.d.ts +1 -0
  72. package/dist/commands/generate-interceptor.test.js +41 -0
  73. package/dist/commands/generate-middleware.d.ts +2 -0
  74. package/dist/commands/generate-middleware.js +46 -0
  75. package/dist/commands/generate-middleware.test.d.ts +1 -0
  76. package/dist/commands/generate-middleware.test.js +41 -0
  77. package/dist/commands/generate-module.d.ts +2 -0
  78. package/dist/commands/generate-module.js +106 -0
  79. package/dist/commands/generate-module.test.d.ts +1 -0
  80. package/dist/commands/generate-module.test.js +54 -0
  81. package/dist/commands/generate-pipe.d.ts +2 -0
  82. package/dist/commands/generate-pipe.js +33 -0
  83. package/dist/commands/generate-pipe.test.d.ts +1 -0
  84. package/dist/commands/generate-pipe.test.js +35 -0
  85. package/dist/commands/generate-rag.d.ts +2 -0
  86. package/dist/commands/generate-rag.js +66 -0
  87. package/dist/commands/generate-rag.test.d.ts +1 -0
  88. package/dist/commands/generate-rag.test.js +35 -0
  89. package/dist/commands/generate-repository.d.ts +2 -0
  90. package/dist/commands/generate-repository.js +40 -0
  91. package/dist/commands/generate-repository.test.d.ts +1 -0
  92. package/dist/commands/generate-repository.test.js +41 -0
  93. package/dist/commands/generate-serverless-handler.d.ts +2 -0
  94. package/dist/commands/generate-serverless-handler.js +46 -0
  95. package/dist/commands/generate-serverless-handler.test.d.ts +1 -0
  96. package/dist/commands/generate-serverless-handler.test.js +42 -0
  97. package/dist/commands/generate-service.d.ts +2 -0
  98. package/dist/commands/generate-service.js +52 -0
  99. package/dist/commands/generate-service.test.d.ts +1 -0
  100. package/dist/commands/generate-service.test.js +41 -0
  101. package/dist/commands/generate-websocket-gateway.d.ts +2 -0
  102. package/dist/commands/generate-websocket-gateway.js +47 -0
  103. package/dist/commands/generate-websocket-gateway.test.d.ts +1 -0
  104. package/dist/commands/generate-websocket-gateway.test.js +41 -0
  105. package/dist/commands/info.d.ts +2 -0
  106. package/dist/commands/info.js +91 -0
  107. package/dist/commands/pdf-to-audio.d.ts +2 -0
  108. package/dist/commands/pdf-to-audio.js +170 -0
  109. package/dist/commands/start.d.ts +2 -0
  110. package/dist/commands/start.js +61 -0
  111. package/dist/commands/test.d.ts +2 -0
  112. package/dist/commands/test.js +63 -0
  113. package/dist/index.d.ts +2 -0
  114. package/dist/index.js +75 -0
  115. package/dist/index.test.d.ts +1 -0
  116. package/dist/index.test.js +93 -0
  117. package/dist/utils/generator.d.ts +25 -0
  118. package/dist/utils/generator.js +107 -0
  119. package/dist/utils/generator.test.d.ts +1 -0
  120. package/dist/utils/generator.test.js +137 -0
  121. package/package.json +73 -0
@@ -0,0 +1,176 @@
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.addCommand = addCommand;
7
+ const child_process_1 = require("child_process");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const HAZEL_PACKAGES = {
11
+ ai: {
12
+ npm: '@hazeljs/ai',
13
+ hint: 'import { AIModule } from "@hazeljs/ai";',
14
+ },
15
+ agent: {
16
+ npm: '@hazeljs/agent',
17
+ hint: 'import { AgentModule } from "@hazeljs/agent";',
18
+ },
19
+ audit: {
20
+ npm: '@hazeljs/audit',
21
+ hint: 'import { AuditModule, ConsoleAuditTransport } from "@hazeljs/audit";\n // AuditModule.forRoot({ transports: [new ConsoleAuditTransport()] })',
22
+ },
23
+ auth: {
24
+ npm: '@hazeljs/auth',
25
+ hint: 'import { JwtModule } from "@hazeljs/auth";\n // JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })',
26
+ },
27
+ oauth: {
28
+ npm: '@hazeljs/oauth',
29
+ hint: 'import { OAuthModule } from "@hazeljs/oauth";\n // OAuthModule.forRoot({ providers: { google: {...}, microsoft: {...}, github: {...} } })',
30
+ },
31
+ cache: {
32
+ npm: '@hazeljs/cache',
33
+ hint: 'import { CacheModule } from "@hazeljs/cache";',
34
+ },
35
+ config: {
36
+ npm: '@hazeljs/config',
37
+ hint: 'import { ConfigModule } from "@hazeljs/config";\n // ConfigModule.forRoot({ envFilePath: ".env" })',
38
+ },
39
+ cron: {
40
+ npm: '@hazeljs/cron',
41
+ hint: 'import { CronModule } from "@hazeljs/cron";',
42
+ },
43
+ data: {
44
+ npm: '@hazeljs/data',
45
+ hint: 'import { DataModule } from "@hazeljs/data";',
46
+ },
47
+ discovery: {
48
+ npm: '@hazeljs/discovery',
49
+ hint: 'import { ServiceRegistry, DiscoveryClient } from "@hazeljs/discovery";',
50
+ },
51
+ 'event-emitter': {
52
+ npm: '@hazeljs/event-emitter',
53
+ hint: 'import { EventEmitterModule } from "@hazeljs/event-emitter";',
54
+ },
55
+ gateway: {
56
+ npm: '@hazeljs/gateway',
57
+ hint: 'import { GatewayModule } from "@hazeljs/gateway";',
58
+ },
59
+ guardrails: {
60
+ npm: '@hazeljs/guardrails',
61
+ hint: 'import { GuardrailsModule } from "@hazeljs/guardrails";\n // GuardrailsModule.forRoot({ redactPIIByDefault: true })',
62
+ },
63
+ graphql: {
64
+ npm: '@hazeljs/graphql',
65
+ hint: 'import { GraphQLModule } from "@hazeljs/graphql";',
66
+ },
67
+ grpc: {
68
+ npm: '@hazeljs/grpc',
69
+ hint: 'import { GrpcModule } from "@hazeljs/grpc";',
70
+ },
71
+ kafka: {
72
+ npm: '@hazeljs/kafka',
73
+ hint: 'import { KafkaModule } from "@hazeljs/kafka";',
74
+ },
75
+ messaging: {
76
+ npm: '@hazeljs/messaging',
77
+ hint: 'import { MessagingModule } from "@hazeljs/messaging";',
78
+ },
79
+ mcp: {
80
+ npm: '@hazeljs/mcp',
81
+ hint: 'import { createMcpServer } from "@hazeljs/mcp";\n // createMcpServer({ name, version, toolRegistry }).listenStdio();',
82
+ },
83
+ ml: {
84
+ npm: '@hazeljs/ml',
85
+ hint: 'import { MLModule } from "@hazeljs/ml";',
86
+ },
87
+ prompts: {
88
+ npm: '@hazeljs/prompts',
89
+ hint: 'import { PromptTemplate, PromptRegistry } from "@hazeljs/prompts";',
90
+ },
91
+ prisma: {
92
+ npm: '@hazeljs/prisma',
93
+ hint: 'import { PrismaModule } from "@hazeljs/prisma";',
94
+ },
95
+ typeorm: {
96
+ npm: '@hazeljs/typeorm',
97
+ hint: 'import { TypeOrmModule } from "@hazeljs/typeorm";',
98
+ },
99
+ queue: {
100
+ npm: '@hazeljs/queue',
101
+ hint: 'import { QueueModule } from "@hazeljs/queue";',
102
+ },
103
+ rag: {
104
+ npm: '@hazeljs/rag',
105
+ hint: 'import { RAGPipeline } from "@hazeljs/rag";',
106
+ },
107
+ resilience: {
108
+ npm: '@hazeljs/resilience',
109
+ hint: 'import { CircuitBreaker, WithRetry, WithTimeout } from "@hazeljs/resilience";',
110
+ },
111
+ 'pdf-to-audio': {
112
+ npm: '@hazeljs/pdf-to-audio',
113
+ hint: 'import { PdfToAudioModule } from "@hazeljs/pdf-to-audio";\n // PdfToAudioModule converts PDFs to audio via TTS',
114
+ },
115
+ serverless: {
116
+ npm: '@hazeljs/serverless',
117
+ hint: 'import { createLambdaHandler } from "@hazeljs/serverless";',
118
+ },
119
+ swagger: {
120
+ npm: '@hazeljs/swagger',
121
+ hint: 'import { SwaggerModule } from "@hazeljs/swagger";',
122
+ },
123
+ websocket: {
124
+ npm: '@hazeljs/websocket',
125
+ hint: 'import { WebSocketModule } from "@hazeljs/websocket";',
126
+ },
127
+ };
128
+ function addCommand(program) {
129
+ program
130
+ .command('add [package]')
131
+ .description('Add a HazelJS package to your project')
132
+ .option('--dev', 'Install as dev dependency')
133
+ .action(async (packageName, options) => {
134
+ try {
135
+ let selectedPackage = packageName;
136
+ // If no package specified, show interactive selection
137
+ if (!selectedPackage) {
138
+ const { package: pkg } = await inquirer_1.default.prompt([
139
+ {
140
+ type: 'list',
141
+ name: 'package',
142
+ message: 'Which HazelJS package would you like to add?',
143
+ choices: Object.keys(HAZEL_PACKAGES).map((key) => ({
144
+ name: `${key} - ${HAZEL_PACKAGES[key].npm}`,
145
+ value: key,
146
+ })),
147
+ },
148
+ ]);
149
+ selectedPackage = pkg;
150
+ }
151
+ // Get the package info
152
+ const pkgInfo = HAZEL_PACKAGES[selectedPackage];
153
+ if (!pkgInfo) {
154
+ console.log(chalk_1.default.yellow(`Unknown package: ${selectedPackage}`));
155
+ console.log(chalk_1.default.gray('\nAvailable packages:'));
156
+ Object.keys(HAZEL_PACKAGES).forEach((key) => {
157
+ console.log(chalk_1.default.gray(` - ${key}: ${HAZEL_PACKAGES[key].npm}`));
158
+ });
159
+ return;
160
+ }
161
+ console.log(chalk_1.default.blue(`\n\uD83D\uDCE6 Installing ${pkgInfo.npm}...`));
162
+ const devFlag = options?.dev ? '--save-dev' : '';
163
+ const command = `npm install ${pkgInfo.npm} ${devFlag}`.trim();
164
+ (0, child_process_1.execSync)(command, { stdio: 'inherit' });
165
+ console.log(chalk_1.default.green(`\n\u2713 Successfully installed ${pkgInfo.npm}`));
166
+ // Show usage hints
167
+ console.log(chalk_1.default.gray('\nUsage:'));
168
+ console.log(chalk_1.default.gray(` ${pkgInfo.hint}`));
169
+ console.log(chalk_1.default.gray(`\nDocumentation: https://hazeljs.com/docs/packages/${selectedPackage}`));
170
+ }
171
+ catch (error) {
172
+ console.error(chalk_1.default.red('Error installing package:'), error);
173
+ process.exit(1);
174
+ }
175
+ });
176
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const child_process_1 = require("child_process");
4
+ const commander_1 = require("commander");
5
+ const add_1 = require("./add");
6
+ jest.mock('child_process');
7
+ jest.mock('inquirer');
8
+ describe('addCommand', () => {
9
+ const mockExecSync = child_process_1.execSync;
10
+ let program;
11
+ beforeEach(() => {
12
+ jest.clearAllMocks();
13
+ mockExecSync.mockImplementation(() => Buffer.from(''));
14
+ jest.spyOn(console, 'log').mockImplementation();
15
+ program = new commander_1.Command();
16
+ });
17
+ afterEach(() => {
18
+ jest.restoreAllMocks();
19
+ });
20
+ it('should register the add command', () => {
21
+ (0, add_1.addCommand)(program);
22
+ const cmd = program.commands.find(c => c.name() === 'add');
23
+ expect(cmd).toBeDefined();
24
+ });
25
+ it('should install a known package', async () => {
26
+ (0, add_1.addCommand)(program);
27
+ await program.parseAsync(['node', 'test', 'add', 'auth']);
28
+ expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining('@hazeljs/auth'), expect.objectContaining({ stdio: 'inherit' }));
29
+ });
30
+ it('should handle unknown packages gracefully', async () => {
31
+ const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
32
+ (0, add_1.addCommand)(program);
33
+ await program.parseAsync(['node', 'test', 'add', 'unknown-package']);
34
+ expect(mockExecSync).not.toHaveBeenCalled();
35
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Unknown package'));
36
+ consoleSpy.mockRestore();
37
+ });
38
+ it('should include all hazeljs packages', async () => {
39
+ (0, add_1.addCommand)(program);
40
+ // Test that all documented packages are available
41
+ const expectedPackages = [
42
+ 'ai', 'agent', 'auth', 'cache', 'config', 'cron',
43
+ 'discovery', 'mcp', 'prompts', 'prisma', 'typeorm', 'rag', 'serverless', 'swagger', 'websocket'
44
+ ];
45
+ for (const pkg of expectedPackages) {
46
+ mockExecSync.mockClear();
47
+ await program.parseAsync(['node', 'test', 'add', pkg]);
48
+ expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining(`@hazeljs/${pkg}`), expect.any(Object));
49
+ }
50
+ });
51
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function buildCommand(program: Command): void;
@@ -0,0 +1,52 @@
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.buildCommand = buildCommand;
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 buildCommand(program) {
12
+ program
13
+ .command('build')
14
+ .description('Build the HazelJS project')
15
+ .option('-w, --watch', 'Watch mode')
16
+ .option('-p, --production', 'Production build')
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
+ if (!packageJson.scripts?.build) {
27
+ console.log(chalk_1.default.yellow('⚠ No build script found in package.json'));
28
+ console.log(chalk_1.default.gray('\nAdd a build script to your package.json:'));
29
+ console.log(chalk_1.default.gray(' "scripts": {'));
30
+ console.log(chalk_1.default.gray(' "build": "tsc"'));
31
+ console.log(chalk_1.default.gray(' }'));
32
+ process.exit(1);
33
+ }
34
+ console.log(chalk_1.default.blue('🔨 Building project...\n'));
35
+ let command = 'npm run build';
36
+ if (options.watch) {
37
+ command = 'npm run build -- --watch';
38
+ }
39
+ if (options.production) {
40
+ process.env.NODE_ENV = 'production';
41
+ }
42
+ (0, child_process_1.execSync)(command, { stdio: 'inherit' });
43
+ if (!options.watch) {
44
+ console.log(chalk_1.default.green('\n✓ Build completed successfully'));
45
+ }
46
+ }
47
+ catch {
48
+ console.error(chalk_1.default.red('\n✗ Build failed'));
49
+ process.exit(1);
50
+ }
51
+ });
52
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateAgent(program: Command): void;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateAgent = generateAgent;
4
+ const generator_1 = require("../utils/generator");
5
+ const AGENT_TEMPLATE = `import { Agent, Tool } from '@hazeljs/agent';
6
+
7
+ @Agent({
8
+ name: '{{fileName}}',
9
+ description: '{{description}}',
10
+ systemPrompt: 'You are a helpful {{className}} agent.',
11
+ enableMemory: true,
12
+ enableRAG: true,
13
+ })
14
+ export class {{className}}Agent {
15
+ @Tool({
16
+ description: 'Example tool for {{fileName}}',
17
+ parameters: [
18
+ {
19
+ name: 'input',
20
+ type: 'string',
21
+ description: 'Input parameter',
22
+ required: true,
23
+ },
24
+ ],
25
+ })
26
+ async exampleTool(input: { input: string }): Promise<{ result: string }> {
27
+ // Implement your tool logic here
28
+ return {
29
+ result: \`Processed: \${input.input}\`,
30
+ };
31
+ }
32
+ }
33
+ `;
34
+ class AgentGenerator extends generator_1.Generator {
35
+ constructor() {
36
+ super(...arguments);
37
+ this.suffix = 'agent';
38
+ }
39
+ getDefaultTemplate() {
40
+ return AGENT_TEMPLATE;
41
+ }
42
+ }
43
+ function generateAgent(program) {
44
+ program
45
+ .command('agent <name>')
46
+ .description('Generate a new AI agent with @Agent and @Tool decorators')
47
+ .option('-p, --path <path>', 'Path where the agent should be generated')
48
+ .option('--dry-run', 'Preview files without writing them')
49
+ .action(async (name, options) => {
50
+ const generator = new AgentGenerator();
51
+ await generator.generate({
52
+ name,
53
+ path: options.path,
54
+ dryRun: options.dryRun,
55
+ data: { description: `A ${name} agent` },
56
+ });
57
+ });
58
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
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 generate_agent_1 = require("./generate-agent");
9
+ jest.mock('fs');
10
+ describe('generateAgent', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should generate an agent file with correct suffix', async () => {
24
+ (0, generate_agent_1.generateAgent)(program);
25
+ await program.parseAsync(['node', 'test', 'agent', 'research']);
26
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('research.agent.ts'), expect.stringContaining('ResearchAgent'));
27
+ });
28
+ it('should import from @hazeljs/agent', async () => {
29
+ (0, generate_agent_1.generateAgent)(program);
30
+ await program.parseAsync(['node', 'test', 'agent', 'research']);
31
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
32
+ expect(writtenContent).toContain("from '@hazeljs/agent'");
33
+ expect(writtenContent).toContain('@Agent');
34
+ expect(writtenContent).toContain('@Tool');
35
+ });
36
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateAIService(program: Command): void;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateAIService = generateAIService;
4
+ const generator_1 = require("../utils/generator");
5
+ const AI_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
6
+ import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';
7
+
8
+ @Service()
9
+ export class {{className}}AIService {
10
+ constructor(private readonly aiService: AIService) {}
11
+
12
+ @AIFunction({
13
+ provider: 'openai',
14
+ model: 'gpt-4',
15
+ streaming: false,
16
+ })
17
+ async {{camelName}}Task(@AIPrompt() prompt: string): Promise<unknown> {
18
+ const result = await this.aiService.complete({
19
+ provider: 'openai',
20
+ model: 'gpt-4',
21
+ messages: [{ role: 'user', content: prompt }],
22
+ });
23
+
24
+ return result;
25
+ }
26
+ }
27
+ `;
28
+ class AIServiceGenerator extends generator_1.Generator {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.suffix = 'ai-service';
32
+ }
33
+ getDefaultTemplate() {
34
+ return AI_SERVICE_TEMPLATE;
35
+ }
36
+ }
37
+ function generateAIService(program) {
38
+ program
39
+ .command('ai-service <name>')
40
+ .description('Generate a new AI service with decorators')
41
+ .alias('ai')
42
+ .option('-p, --path <path>', 'Path where the AI service should be generated')
43
+ .option('--dry-run', 'Preview files without writing them')
44
+ .action(async (name, options) => {
45
+ const generator = new AIServiceGenerator();
46
+ await generator.generate({ name, path: options.path, dryRun: options.dryRun });
47
+ });
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
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 generate_ai_service_1 = require("./generate-ai-service");
9
+ jest.mock('fs');
10
+ describe('generateAIService', () => {
11
+ const mockFs = fs_1.default;
12
+ let program;
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ mockFs.existsSync.mockReturnValue(true);
16
+ mockFs.writeFileSync.mockImplementation(() => { });
17
+ jest.spyOn(console, 'log').mockImplementation();
18
+ program = new commander_1.Command();
19
+ });
20
+ afterEach(() => {
21
+ jest.restoreAllMocks();
22
+ });
23
+ it('should register the ai-service command with alias', () => {
24
+ (0, generate_ai_service_1.generateAIService)(program);
25
+ const cmd = program.commands.find(c => c.name() === 'ai-service');
26
+ expect(cmd).toBeDefined();
27
+ expect(cmd?.alias()).toBe('ai');
28
+ });
29
+ it('should generate an AI service file with correct suffix', async () => {
30
+ (0, generate_ai_service_1.generateAIService)(program);
31
+ await program.parseAsync(['node', 'test', 'ai-service', 'chat']);
32
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('chat.ai-service.ts'), expect.stringContaining('ChatAIService'));
33
+ });
34
+ it('should import from @hazeljs/ai', async () => {
35
+ (0, generate_ai_service_1.generateAIService)(program);
36
+ await program.parseAsync(['node', 'test', 'ai-service', 'chat']);
37
+ const writtenContent = mockFs.writeFileSync.mock.calls[0][1];
38
+ expect(writtenContent).toContain("from '@hazeljs/ai'");
39
+ expect(writtenContent).toContain('AIFunction');
40
+ });
41
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateApp(program: Command): void;