@inkeep/create-agents 0.21.0 → 0.22.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/dist/__tests__/utils.test.js +26 -30
- package/dist/templates.d.ts +1 -0
- package/dist/templates.js +16 -0
- package/dist/utils.js +11 -48
- package/package.json +2 -2
|
@@ -49,7 +49,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
49
49
|
vi.mocked(fs.remove).mockResolvedValue(undefined);
|
|
50
50
|
// Mock templates
|
|
51
51
|
vi.mocked(getAvailableTemplates).mockResolvedValue([
|
|
52
|
-
'
|
|
52
|
+
'event-planner',
|
|
53
53
|
'chatbot',
|
|
54
54
|
'data-analysis',
|
|
55
55
|
]);
|
|
@@ -72,7 +72,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
72
72
|
processChdirSpy.mockRestore();
|
|
73
73
|
});
|
|
74
74
|
describe('Default behavior (no template or customProjectId)', () => {
|
|
75
|
-
it('should use
|
|
75
|
+
it('should use event-planner as default template and project ID', async () => {
|
|
76
76
|
await createAgents({
|
|
77
77
|
dirName: 'test-dir',
|
|
78
78
|
openAiKey: 'test-openai-key',
|
|
@@ -81,18 +81,18 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
81
81
|
// Should clone base template and weather-project template
|
|
82
82
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
83
83
|
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
84
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/
|
|
84
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/event-planner', 'src/projects/event-planner', expect.arrayContaining([
|
|
85
85
|
expect.objectContaining({
|
|
86
86
|
filePath: 'index.ts',
|
|
87
87
|
replacements: expect.objectContaining({
|
|
88
|
-
models: expect.any(Object)
|
|
89
|
-
})
|
|
90
|
-
})
|
|
88
|
+
models: expect.any(Object),
|
|
89
|
+
}),
|
|
90
|
+
}),
|
|
91
91
|
]));
|
|
92
92
|
// Should not call getAvailableTemplates since no template validation needed
|
|
93
93
|
expect(getAvailableTemplates).not.toHaveBeenCalled();
|
|
94
94
|
});
|
|
95
|
-
it('should create project with
|
|
95
|
+
it('should create project with event-planner as project ID', async () => {
|
|
96
96
|
await createAgents({
|
|
97
97
|
dirName: 'test-dir',
|
|
98
98
|
openAiKey: 'test-openai-key',
|
|
@@ -117,13 +117,13 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
117
117
|
// Should clone base template and the specified template
|
|
118
118
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
119
119
|
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
120
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/chatbot', 'src/chatbot', expect.arrayContaining([
|
|
120
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/chatbot', 'src/projects/chatbot', expect.arrayContaining([
|
|
121
121
|
expect.objectContaining({
|
|
122
122
|
filePath: 'index.ts',
|
|
123
123
|
replacements: expect.objectContaining({
|
|
124
|
-
models: expect.any(Object)
|
|
125
|
-
})
|
|
126
|
-
})
|
|
124
|
+
models: expect.any(Object),
|
|
125
|
+
}),
|
|
126
|
+
}),
|
|
127
127
|
]));
|
|
128
128
|
// Check that .env file is created
|
|
129
129
|
expect(fs.writeFile).toHaveBeenCalledWith('.env', expect.stringContaining('ENVIRONMENT=development'));
|
|
@@ -131,7 +131,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
131
131
|
expect(fs.writeFile).toHaveBeenCalledWith('src/inkeep.config.ts', expect.stringContaining('tenantId: "default"'));
|
|
132
132
|
});
|
|
133
133
|
it('should exit with error when template does not exist', async () => {
|
|
134
|
-
vi.mocked(getAvailableTemplates).mockResolvedValue(['
|
|
134
|
+
vi.mocked(getAvailableTemplates).mockResolvedValue(['event-planner', 'chatbot']);
|
|
135
135
|
await expect(createAgents({
|
|
136
136
|
dirName: 'test-dir',
|
|
137
137
|
template: 'non-existent-template',
|
|
@@ -142,7 +142,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
142
142
|
});
|
|
143
143
|
it('should show available templates when invalid template is provided', async () => {
|
|
144
144
|
vi.mocked(getAvailableTemplates).mockResolvedValue([
|
|
145
|
-
'
|
|
145
|
+
'event-planner',
|
|
146
146
|
'chatbot',
|
|
147
147
|
'data-analysis',
|
|
148
148
|
]);
|
|
@@ -152,7 +152,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
152
152
|
openAiKey: 'test-openai-key',
|
|
153
153
|
})).rejects.toThrow('process.exit called');
|
|
154
154
|
const cancelCall = vi.mocked(p.cancel).mock.calls[0][0];
|
|
155
|
-
expect(cancelCall).toContain('
|
|
155
|
+
expect(cancelCall).toContain('event-planner');
|
|
156
156
|
expect(cancelCall).toContain('chatbot');
|
|
157
157
|
expect(cancelCall).toContain('data-analysis');
|
|
158
158
|
});
|
|
@@ -171,13 +171,13 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
171
171
|
// Should NOT validate templates
|
|
172
172
|
expect(getAvailableTemplates).not.toHaveBeenCalled();
|
|
173
173
|
// Should create empty project directory
|
|
174
|
-
expect(fs.ensureDir).toHaveBeenCalledWith('src/my-custom-project');
|
|
174
|
+
expect(fs.ensureDir).toHaveBeenCalledWith('src/projects/my-custom-project');
|
|
175
175
|
// Check that .env file is created
|
|
176
176
|
expect(fs.writeFile).toHaveBeenCalledWith('.env', expect.stringContaining('ENVIRONMENT=development'));
|
|
177
177
|
// Check that inkeep.config.ts is created in src directory
|
|
178
178
|
expect(fs.writeFile).toHaveBeenCalledWith('src/inkeep.config.ts', expect.stringContaining('tenantId: "default"'));
|
|
179
179
|
// Check that custom project index.ts is created
|
|
180
|
-
expect(fs.writeFile).toHaveBeenCalledWith('src/my-custom-project/index.ts', expect.stringContaining('id: "my-custom-project"'));
|
|
180
|
+
expect(fs.writeFile).toHaveBeenCalledWith('src/projects/my-custom-project/index.ts', expect.stringContaining('id: "my-custom-project"'));
|
|
181
181
|
});
|
|
182
182
|
it('should prioritize custom project ID over template if both are provided', async () => {
|
|
183
183
|
await createAgents({
|
|
@@ -191,13 +191,13 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
191
191
|
expect(cloneTemplate).toHaveBeenCalledTimes(1);
|
|
192
192
|
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
193
193
|
expect(getAvailableTemplates).not.toHaveBeenCalled();
|
|
194
|
-
expect(fs.ensureDir).toHaveBeenCalledWith('src/my-custom-project');
|
|
194
|
+
expect(fs.ensureDir).toHaveBeenCalledWith('src/projects/my-custom-project');
|
|
195
195
|
// Check that .env file is created
|
|
196
196
|
expect(fs.writeFile).toHaveBeenCalledWith('.env', expect.stringContaining('ENVIRONMENT=development'));
|
|
197
197
|
// Check that inkeep.config.ts is created in src directory
|
|
198
198
|
expect(fs.writeFile).toHaveBeenCalledWith('src/inkeep.config.ts', expect.stringContaining('tenantId: "default"'));
|
|
199
199
|
// Check that custom project index.ts is created
|
|
200
|
-
expect(fs.writeFile).toHaveBeenCalledWith('src/my-custom-project/index.ts', expect.stringContaining('id: "my-custom-project"'));
|
|
200
|
+
expect(fs.writeFile).toHaveBeenCalledWith('src/projects/my-custom-project/index.ts', expect.stringContaining('id: "my-custom-project"'));
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
203
|
describe('Edge cases and validation', () => {
|
|
@@ -213,13 +213,13 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
213
213
|
anthropicKey: 'test-key',
|
|
214
214
|
});
|
|
215
215
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
216
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/my-complex-template', 'src/my-complex-template', expect.arrayContaining([
|
|
216
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/my-complex-template', 'src/projects/my-complex-template', expect.arrayContaining([
|
|
217
217
|
expect.objectContaining({
|
|
218
218
|
filePath: 'index.ts',
|
|
219
219
|
replacements: expect.objectContaining({
|
|
220
|
-
models: expect.any(Object)
|
|
221
|
-
})
|
|
222
|
-
})
|
|
220
|
+
models: expect.any(Object),
|
|
221
|
+
}),
|
|
222
|
+
}),
|
|
223
223
|
]));
|
|
224
224
|
});
|
|
225
225
|
it('should handle custom project IDs with special characters', async () => {
|
|
@@ -229,13 +229,13 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
229
229
|
openAiKey: 'test-key',
|
|
230
230
|
anthropicKey: 'test-key',
|
|
231
231
|
});
|
|
232
|
-
expect(fs.ensureDir).toHaveBeenCalledWith('src/my_project-123');
|
|
232
|
+
expect(fs.ensureDir).toHaveBeenCalledWith('src/projects/my_project-123');
|
|
233
233
|
// Check that .env file is created
|
|
234
234
|
expect(fs.writeFile).toHaveBeenCalledWith('.env', expect.stringContaining('ENVIRONMENT=development'));
|
|
235
235
|
// Check that inkeep.config.ts is created in src directory
|
|
236
236
|
expect(fs.writeFile).toHaveBeenCalledWith('src/inkeep.config.ts', expect.stringContaining('tenantId: "default"'));
|
|
237
237
|
// Check that custom project index.ts is created
|
|
238
|
-
expect(fs.writeFile).toHaveBeenCalledWith('src/my_project-123/index.ts', expect.stringContaining('id: "my_project-123"'));
|
|
238
|
+
expect(fs.writeFile).toHaveBeenCalledWith('src/projects/my_project-123/index.ts', expect.stringContaining('id: "my_project-123"'));
|
|
239
239
|
});
|
|
240
240
|
it('should create correct folder structure for all scenarios', async () => {
|
|
241
241
|
// Test default
|
|
@@ -267,7 +267,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
267
267
|
anthropicKey: 'key',
|
|
268
268
|
});
|
|
269
269
|
expect(fs.ensureDir).toHaveBeenCalledWith('src');
|
|
270
|
-
expect(fs.ensureDir).toHaveBeenCalledWith('src/custom');
|
|
270
|
+
expect(fs.ensureDir).toHaveBeenCalledWith('src/projects/custom');
|
|
271
271
|
});
|
|
272
272
|
});
|
|
273
273
|
});
|
|
@@ -277,10 +277,6 @@ function setupDefaultMocks() {
|
|
|
277
277
|
vi.mocked(fs.pathExists).mockResolvedValue(false);
|
|
278
278
|
vi.mocked(fs.ensureDir).mockResolvedValue(undefined);
|
|
279
279
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
280
|
-
vi.mocked(getAvailableTemplates).mockResolvedValue([
|
|
281
|
-
'weather-project',
|
|
282
|
-
'chatbot',
|
|
283
|
-
'data-analysis',
|
|
284
|
-
]);
|
|
280
|
+
vi.mocked(getAvailableTemplates).mockResolvedValue(['event-planner', 'chatbot', 'data-analysis']);
|
|
285
281
|
vi.mocked(cloneTemplate).mockResolvedValue(undefined);
|
|
286
282
|
}
|
package/dist/templates.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface ContentReplacement {
|
|
|
5
5
|
replacements: Record<string, any>;
|
|
6
6
|
}
|
|
7
7
|
export declare function cloneTemplate(templatePath: string, targetPath: string, replacements?: ContentReplacement[]): Promise<void>;
|
|
8
|
+
export declare function cloneTemplateLocal(templatePath: string, targetPath: string, replacements: ContentReplacement[]): Promise<void>;
|
|
8
9
|
/**
|
|
9
10
|
* Replace content in cloned template files
|
|
10
11
|
*/
|
package/dist/templates.js
CHANGED
|
@@ -17,6 +17,22 @@ export async function cloneTemplate(templatePath, targetPath, replacements) {
|
|
|
17
17
|
process.exit(1);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
export async function cloneTemplateLocal(templatePath, targetPath, replacements) {
|
|
21
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
22
|
+
try {
|
|
23
|
+
await fs.copy(templatePath, targetPath, {
|
|
24
|
+
overwrite: true,
|
|
25
|
+
errorOnExist: false,
|
|
26
|
+
});
|
|
27
|
+
if (replacements && replacements.length > 0) {
|
|
28
|
+
await replaceContentInFiles(targetPath, replacements);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(`Failed to clone template from ${templatePath}:`, error);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
20
36
|
/**
|
|
21
37
|
* Replace content in cloned template files
|
|
22
38
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -2,9 +2,9 @@ import { exec } from 'node:child_process';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
|
+
import { ANTHROPIC_MODELS, GOOGLE_MODELS, OPENAI_MODELS } from '@inkeep/agents-core';
|
|
5
6
|
import fs from 'fs-extra';
|
|
6
7
|
import color from 'picocolors';
|
|
7
|
-
import { ANTHROPIC_MODELS, OPENAI_MODELS, GOOGLE_MODELS } from '@inkeep/agents-core';
|
|
8
8
|
import { cloneTemplate, getAvailableTemplates } from './templates.js';
|
|
9
9
|
const execAsync = promisify(exec);
|
|
10
10
|
export const defaultGoogleModelConfigurations = {
|
|
@@ -47,14 +47,11 @@ export const createAgents = async (args = {}) => {
|
|
|
47
47
|
const runApiPort = '3003';
|
|
48
48
|
let projectId;
|
|
49
49
|
let templateName;
|
|
50
|
-
// Determine project ID and template based on user input
|
|
51
50
|
if (customProjectId) {
|
|
52
|
-
// User provided custom project ID - use it as-is, no template needed
|
|
53
51
|
projectId = customProjectId;
|
|
54
|
-
templateName = '';
|
|
52
|
+
templateName = '';
|
|
55
53
|
}
|
|
56
54
|
else if (template) {
|
|
57
|
-
// User provided template - validate it exists and use template name as project ID
|
|
58
55
|
const availableTemplates = await getAvailableTemplates();
|
|
59
56
|
if (!availableTemplates.includes(template)) {
|
|
60
57
|
p.cancel(`${color.red('✗')} Template "${template}" not found\n\n` +
|
|
@@ -66,12 +63,10 @@ export const createAgents = async (args = {}) => {
|
|
|
66
63
|
templateName = template;
|
|
67
64
|
}
|
|
68
65
|
else {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
templateName = 'weather-project';
|
|
66
|
+
projectId = 'event-planner';
|
|
67
|
+
templateName = 'event-planner';
|
|
72
68
|
}
|
|
73
69
|
p.intro(color.inverse(' Create Agents Directory '));
|
|
74
|
-
// Prompt for directory name if not provided
|
|
75
70
|
if (!dirName) {
|
|
76
71
|
const dirResponse = await p.text({
|
|
77
72
|
message: 'What do you want to name your agents directory?',
|
|
@@ -90,8 +85,6 @@ export const createAgents = async (args = {}) => {
|
|
|
90
85
|
}
|
|
91
86
|
dirName = dirResponse;
|
|
92
87
|
}
|
|
93
|
-
// Project ID is already determined above based on template/customProjectId logic
|
|
94
|
-
// If keys aren't provided via CLI args, prompt for provider selection and keys
|
|
95
88
|
if (!anthropicKey && !openAiKey && !googleKey) {
|
|
96
89
|
const providerChoice = await p.select({
|
|
97
90
|
message: 'Which AI provider would you like to use?',
|
|
@@ -105,7 +98,6 @@ export const createAgents = async (args = {}) => {
|
|
|
105
98
|
p.cancel('Operation cancelled');
|
|
106
99
|
process.exit(0);
|
|
107
100
|
}
|
|
108
|
-
// Prompt for keys based on selection
|
|
109
101
|
if (providerChoice === 'anthropic') {
|
|
110
102
|
const anthropicKeyResponse = await p.text({
|
|
111
103
|
message: 'Enter your Anthropic API key:',
|
|
@@ -168,7 +160,6 @@ export const createAgents = async (args = {}) => {
|
|
|
168
160
|
else if (googleKey) {
|
|
169
161
|
defaultModelSettings = defaultGoogleModelConfigurations;
|
|
170
162
|
}
|
|
171
|
-
// Ensure models are always configured - fail if none were set
|
|
172
163
|
if (Object.keys(defaultModelSettings).length === 0) {
|
|
173
164
|
p.cancel('Cannot continue without a model configuration for project. Please provide an API key for at least one AI provider.');
|
|
174
165
|
process.exit(1);
|
|
@@ -181,7 +172,6 @@ export const createAgents = async (args = {}) => {
|
|
|
181
172
|
? `https://github.com/inkeep/agents-cookbook/template-projects/${templateName}`
|
|
182
173
|
: null;
|
|
183
174
|
const directoryPath = path.resolve(process.cwd(), dirName);
|
|
184
|
-
// Check if directory already exists
|
|
185
175
|
if (await fs.pathExists(directoryPath)) {
|
|
186
176
|
s.stop();
|
|
187
177
|
const overwrite = await p.confirm({
|
|
@@ -194,10 +184,8 @@ export const createAgents = async (args = {}) => {
|
|
|
194
184
|
s.start('Cleaning existing directory...');
|
|
195
185
|
await fs.emptyDir(directoryPath);
|
|
196
186
|
}
|
|
197
|
-
// Clone the template repository
|
|
198
187
|
s.message('Building template...');
|
|
199
188
|
await cloneTemplate(agentsTemplateRepo, directoryPath);
|
|
200
|
-
// Change to the project directory
|
|
201
189
|
process.chdir(directoryPath);
|
|
202
190
|
const config = {
|
|
203
191
|
dirName,
|
|
@@ -211,17 +199,13 @@ export const createAgents = async (args = {}) => {
|
|
|
211
199
|
modelSettings: defaultModelSettings,
|
|
212
200
|
customProject: !!customProjectId,
|
|
213
201
|
};
|
|
214
|
-
// Create workspace structure for project-specific files
|
|
215
202
|
s.message('Setting up project structure...');
|
|
216
203
|
await createWorkspaceStructure();
|
|
217
|
-
// Create environment files
|
|
218
204
|
s.message('Setting up environment files...');
|
|
219
205
|
await createEnvironmentFiles(config);
|
|
220
|
-
// Create project template folder (only if template is specified)
|
|
221
206
|
if (projectTemplateRepo) {
|
|
222
207
|
s.message('Creating project template folder...');
|
|
223
|
-
const templateTargetPath = `src/${projectId}`;
|
|
224
|
-
// Prepare content replacements for model settings
|
|
208
|
+
const templateTargetPath = `src/projects/${projectId}`;
|
|
225
209
|
const contentReplacements = [
|
|
226
210
|
{
|
|
227
211
|
filePath: 'index.ts',
|
|
@@ -234,23 +218,18 @@ export const createAgents = async (args = {}) => {
|
|
|
234
218
|
}
|
|
235
219
|
else {
|
|
236
220
|
s.message('Creating empty project folder...');
|
|
237
|
-
await fs.ensureDir(`src/${projectId}`);
|
|
221
|
+
await fs.ensureDir(`src/projects/${projectId}`);
|
|
238
222
|
}
|
|
239
|
-
// create or overwrite inkeep.config.ts
|
|
240
223
|
s.message('Creating inkeep.config.ts...');
|
|
241
224
|
await createInkeepConfig(config);
|
|
242
|
-
// Install dependencies
|
|
243
225
|
s.message('Installing dependencies (this may take a while)...');
|
|
244
226
|
await installDependencies();
|
|
245
|
-
// Setup database
|
|
246
227
|
s.message('Setting up database...');
|
|
247
228
|
await setupDatabase();
|
|
248
|
-
// Setup project in database
|
|
249
229
|
s.message('Pushing project...');
|
|
250
230
|
await setupProjectInDatabase(config);
|
|
251
231
|
s.message('Project setup complete!');
|
|
252
232
|
s.stop();
|
|
253
|
-
// Success message with next steps
|
|
254
233
|
p.note(`${color.green('✓')} Project created at: ${color.cyan(directoryPath)}\n\n` +
|
|
255
234
|
`${color.yellow('Ready to go!')}\n\n` +
|
|
256
235
|
`${color.green('✓')} Project created in file system\n` +
|
|
@@ -265,7 +244,7 @@ export const createAgents = async (args = {}) => {
|
|
|
265
244
|
` • Manage UI: Available with management API\n` +
|
|
266
245
|
`\n${color.yellow('Configuration:')}\n` +
|
|
267
246
|
` • Edit .env for environment variables\n` +
|
|
268
|
-
` • Edit files in src/${projectId}/ for agent definitions\n` +
|
|
247
|
+
` • Edit files in src/projects/${projectId}/ for agent definitions\n` +
|
|
269
248
|
` • Use 'inkeep push' to deploy agents to the platform\n` +
|
|
270
249
|
` • Use 'inkeep chat' to test your agents locally\n`, 'Ready to go!');
|
|
271
250
|
}
|
|
@@ -276,11 +255,9 @@ export const createAgents = async (args = {}) => {
|
|
|
276
255
|
}
|
|
277
256
|
};
|
|
278
257
|
async function createWorkspaceStructure() {
|
|
279
|
-
// Create the workspace directory structure
|
|
280
258
|
await fs.ensureDir(`src`);
|
|
281
259
|
}
|
|
282
260
|
async function createEnvironmentFiles(config) {
|
|
283
|
-
// Root .env file
|
|
284
261
|
const envContent = `# Environment
|
|
285
262
|
ENVIRONMENT=development
|
|
286
263
|
|
|
@@ -330,48 +307,36 @@ export const myProject = project({
|
|
|
330
307
|
agent: () => [],
|
|
331
308
|
models: ${JSON.stringify(config.modelSettings, null, 2)},
|
|
332
309
|
});`;
|
|
333
|
-
await fs.writeFile(`src/${config.projectId}/index.ts`, customIndexContent);
|
|
310
|
+
await fs.writeFile(`src/projects/${config.projectId}/index.ts`, customIndexContent);
|
|
334
311
|
}
|
|
335
312
|
}
|
|
336
313
|
async function installDependencies() {
|
|
337
314
|
await execAsync('pnpm install');
|
|
338
315
|
}
|
|
339
316
|
async function setupProjectInDatabase(config) {
|
|
340
|
-
// Start development servers in background
|
|
341
317
|
const { spawn } = await import('node:child_process');
|
|
342
318
|
const devProcess = spawn('pnpm', ['dev:apis'], {
|
|
343
319
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
344
|
-
detached: true,
|
|
320
|
+
detached: true,
|
|
345
321
|
cwd: process.cwd(),
|
|
346
322
|
});
|
|
347
|
-
// Give servers time to start
|
|
348
323
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
349
|
-
// Run inkeep push
|
|
350
324
|
try {
|
|
351
|
-
|
|
352
|
-
await execAsync(`pnpm inkeep push --project src/${config.projectId} --config src/inkeep.config.ts`);
|
|
325
|
+
await execAsync(`pnpm inkeep push --project src/projects/${config.projectId} --config src/inkeep.config.ts`);
|
|
353
326
|
}
|
|
354
327
|
catch (_error) {
|
|
355
|
-
//Continue despite error - user can setup project manually
|
|
356
328
|
}
|
|
357
329
|
finally {
|
|
358
|
-
// Kill the dev servers and their child processes
|
|
359
330
|
if (devProcess.pid) {
|
|
360
331
|
try {
|
|
361
|
-
// Kill the entire process group
|
|
362
332
|
process.kill(-devProcess.pid, 'SIGTERM');
|
|
363
|
-
// Wait a moment for graceful shutdown
|
|
364
333
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
365
|
-
// Force kill if still running
|
|
366
334
|
try {
|
|
367
335
|
process.kill(-devProcess.pid, 'SIGKILL');
|
|
368
336
|
}
|
|
369
|
-
catch {
|
|
370
|
-
// Process already terminated
|
|
371
|
-
}
|
|
337
|
+
catch { }
|
|
372
338
|
}
|
|
373
339
|
catch (_error) {
|
|
374
|
-
// Process might already be dead, that's fine
|
|
375
340
|
console.log('Note: Dev servers may still be running in background');
|
|
376
341
|
}
|
|
377
342
|
}
|
|
@@ -379,7 +344,6 @@ async function setupProjectInDatabase(config) {
|
|
|
379
344
|
}
|
|
380
345
|
async function setupDatabase() {
|
|
381
346
|
try {
|
|
382
|
-
// Run drizzle-kit migrate to apply migrations to database
|
|
383
347
|
await execAsync('pnpm db:migrate');
|
|
384
348
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
385
349
|
}
|
|
@@ -387,7 +351,6 @@ async function setupDatabase() {
|
|
|
387
351
|
throw new Error(`Failed to setup database: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
388
352
|
}
|
|
389
353
|
}
|
|
390
|
-
// Export the command function for the CLI
|
|
391
354
|
export async function createCommand(dirName, options) {
|
|
392
355
|
await createAgents({
|
|
393
356
|
dirName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/create-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Create an Inkeep Agent Framework project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"fs-extra": "^11.0.0",
|
|
35
35
|
"picocolors": "^1.0.0",
|
|
36
36
|
"drizzle-kit": "^0.31.5",
|
|
37
|
-
"@inkeep/agents-core": "0.
|
|
37
|
+
"@inkeep/agents-core": "0.22.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/degit": "^2.8.6",
|