@inkeep/create-agents 0.29.11 → 0.30.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.
- package/dist/__tests__/e2e/quickstart.test.js +7 -2
- package/dist/__tests__/utils.test.js +11 -9
- package/dist/index.js +4 -0
- package/dist/templates.d.ts +2 -2
- package/dist/templates.js +12 -5
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +37 -10
- package/package.json +2 -2
|
@@ -3,7 +3,6 @@ import { execa } from 'execa';
|
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
4
|
import { cleanupDir, createTempDir, linkLocalPackages, runCommand, runCreateAgentsCLI, verifyDirectoryStructure, verifyFile, waitForServerReady, } from './utils';
|
|
5
5
|
const manageApiUrl = 'http://localhost:3002';
|
|
6
|
-
const runApiUrl = 'http://localhost:3003';
|
|
7
6
|
describe('create-agents quickstart e2e', () => {
|
|
8
7
|
let testDir;
|
|
9
8
|
let projectDir;
|
|
@@ -18,6 +17,9 @@ describe('create-agents quickstart e2e', () => {
|
|
|
18
17
|
await cleanupDir(testDir);
|
|
19
18
|
});
|
|
20
19
|
it('should work e2e', async () => {
|
|
20
|
+
const monorepoRoot = path.join(__dirname, '../../../../../');
|
|
21
|
+
const createAgentsPrefix = path.join(monorepoRoot, 'create-agents-template');
|
|
22
|
+
const projectTemplatesPrefix = path.join(monorepoRoot, 'agents-cookbook/template-projects');
|
|
21
23
|
// Run the CLI with all options (non-interactive mode)
|
|
22
24
|
console.log('Running CLI with options:');
|
|
23
25
|
console.log(`Working directory: ${testDir}`);
|
|
@@ -26,6 +28,10 @@ describe('create-agents quickstart e2e', () => {
|
|
|
26
28
|
'--openai-key',
|
|
27
29
|
'test-openai-key',
|
|
28
30
|
'--disable-git', // Skip git init for faster tests
|
|
31
|
+
'--local-agents-prefix',
|
|
32
|
+
createAgentsPrefix,
|
|
33
|
+
'--local-templates-prefix',
|
|
34
|
+
projectTemplatesPrefix,
|
|
29
35
|
], testDir);
|
|
30
36
|
// Verify the CLI completed successfully
|
|
31
37
|
expect(result.exitCode).toBe(0);
|
|
@@ -114,7 +120,6 @@ describe('create-agents quickstart e2e', () => {
|
|
|
114
120
|
expect(data.data.tenantId).toBe('default');
|
|
115
121
|
expect(data.data.id).toBe(projectId);
|
|
116
122
|
// Link to local monorepo packages
|
|
117
|
-
const monorepoRoot = path.join(__dirname, '../../../../../'); // Go up to repo root
|
|
118
123
|
await linkLocalPackages(projectDir, monorepoRoot);
|
|
119
124
|
const pushResultLocal = await runCommand('pnpm', [
|
|
120
125
|
'inkeep',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import { cloneTemplate, getAvailableTemplates } from '../templates';
|
|
4
|
+
import { cloneTemplate, cloneTemplateLocal, getAvailableTemplates } from '../templates';
|
|
5
5
|
import { createAgents } from '../utils';
|
|
6
6
|
// Mock all dependencies
|
|
7
7
|
vi.mock('fs-extra');
|
|
@@ -55,6 +55,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
55
55
|
'data-analysis',
|
|
56
56
|
]);
|
|
57
57
|
vi.mocked(cloneTemplate).mockResolvedValue(undefined);
|
|
58
|
+
vi.mocked(cloneTemplateLocal).mockResolvedValue(undefined);
|
|
58
59
|
// Mock util.promisify to return a mock exec function
|
|
59
60
|
const mockExecAsync = vi.fn().mockResolvedValue({ stdout: '', stderr: '' });
|
|
60
61
|
const util = require('node:util');
|
|
@@ -79,10 +80,10 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
79
80
|
openAiKey: 'test-openai-key',
|
|
80
81
|
anthropicKey: 'test-anthropic-key',
|
|
81
82
|
});
|
|
82
|
-
// Should clone base template and
|
|
83
|
+
// Should clone base template and activities-planner template
|
|
83
84
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
84
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
85
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/activities-planner', 'src/projects/activities-planner', expect.arrayContaining([
|
|
85
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/create-agents-template', expect.any(String), undefined);
|
|
86
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/agents-cookbook/template-projects/activities-planner', 'src/projects/activities-planner', expect.arrayContaining([
|
|
86
87
|
expect.objectContaining({
|
|
87
88
|
filePath: 'index.ts',
|
|
88
89
|
replacements: expect.objectContaining({
|
|
@@ -117,8 +118,8 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
117
118
|
expect(getAvailableTemplates).toHaveBeenCalled();
|
|
118
119
|
// Should clone base template and the specified template
|
|
119
120
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
120
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
121
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/chatbot', 'src/projects/chatbot', expect.arrayContaining([
|
|
121
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/create-agents-template', expect.any(String), undefined);
|
|
122
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/agents-cookbook/template-projects/chatbot', 'src/projects/chatbot', expect.arrayContaining([
|
|
122
123
|
expect.objectContaining({
|
|
123
124
|
filePath: 'index.ts',
|
|
124
125
|
replacements: expect.objectContaining({
|
|
@@ -168,7 +169,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
168
169
|
});
|
|
169
170
|
// Should clone base template but NOT project template
|
|
170
171
|
expect(cloneTemplate).toHaveBeenCalledTimes(1);
|
|
171
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
172
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/create-agents-template', expect.any(String), undefined);
|
|
172
173
|
// Should NOT validate templates
|
|
173
174
|
expect(getAvailableTemplates).not.toHaveBeenCalled();
|
|
174
175
|
// Should create empty project directory
|
|
@@ -190,7 +191,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
190
191
|
});
|
|
191
192
|
// Should only clone base template, not project template
|
|
192
193
|
expect(cloneTemplate).toHaveBeenCalledTimes(1);
|
|
193
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/create-agents-template', expect.any(String));
|
|
194
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/create-agents-template', expect.any(String), undefined);
|
|
194
195
|
expect(getAvailableTemplates).not.toHaveBeenCalled();
|
|
195
196
|
expect(fs.ensureDir).toHaveBeenCalledWith('src/projects/my-custom-project');
|
|
196
197
|
// Check that .env file is created
|
|
@@ -214,7 +215,7 @@ describe('createAgents - Template and Project ID Logic', () => {
|
|
|
214
215
|
anthropicKey: 'test-key',
|
|
215
216
|
});
|
|
216
217
|
expect(cloneTemplate).toHaveBeenCalledTimes(2);
|
|
217
|
-
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents-cookbook/template-projects/my-complex-template', 'src/projects/my-complex-template', expect.arrayContaining([
|
|
218
|
+
expect(cloneTemplate).toHaveBeenCalledWith('https://github.com/inkeep/agents/agents-cookbook/template-projects/my-complex-template', 'src/projects/my-complex-template', expect.arrayContaining([
|
|
218
219
|
expect.objectContaining({
|
|
219
220
|
filePath: 'index.ts',
|
|
220
221
|
replacements: expect.objectContaining({
|
|
@@ -328,4 +329,5 @@ function setupDefaultMocks() {
|
|
|
328
329
|
vi.mocked(fs.writeFile).mockResolvedValue(undefined);
|
|
329
330
|
vi.mocked(getAvailableTemplates).mockResolvedValue(['event-planner', 'chatbot', 'data-analysis']);
|
|
330
331
|
vi.mocked(cloneTemplate).mockResolvedValue(undefined);
|
|
332
|
+
vi.mocked(cloneTemplateLocal).mockResolvedValue(undefined);
|
|
331
333
|
}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,8 @@ program
|
|
|
11
11
|
.option('--anthropic-key <anthropic-key>', 'Anthropic API key')
|
|
12
12
|
.option('--custom-project-id <custom-project-id>', 'Custom project id for experienced users who want an empty project directory')
|
|
13
13
|
.option('--disable-git', 'Disable git initialization')
|
|
14
|
+
.option('--local-agents-prefix <local-agents-prefix>', 'Local prefix for create-agents-template')
|
|
15
|
+
.option('--local-templates-prefix <local-templates-prefix>', 'Local prefix for project templates')
|
|
14
16
|
.parse();
|
|
15
17
|
async function main() {
|
|
16
18
|
const options = program.opts();
|
|
@@ -23,6 +25,8 @@ async function main() {
|
|
|
23
25
|
customProjectId: options.customProjectId,
|
|
24
26
|
template: options.template,
|
|
25
27
|
disableGit: options.disableGit,
|
|
28
|
+
localAgentsPrefix: options.localAgentsPrefix,
|
|
29
|
+
localTemplatesPrefix: options.localTemplatesPrefix,
|
|
26
30
|
});
|
|
27
31
|
}
|
|
28
32
|
catch (error) {
|
package/dist/templates.d.ts
CHANGED
|
@@ -5,7 +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
|
|
8
|
+
export declare function cloneTemplateLocal(templatePath: string, targetPath: string, replacements?: ContentReplacement[]): Promise<void>;
|
|
9
9
|
/**
|
|
10
10
|
* Replace content in cloned template files
|
|
11
11
|
*/
|
|
@@ -14,4 +14,4 @@ export declare function replaceContentInFiles(targetPath: string, replacements:
|
|
|
14
14
|
* Replace object properties in TypeScript code content
|
|
15
15
|
*/
|
|
16
16
|
export declare function replaceObjectProperties(content: string, replacements: Record<string, any>): Promise<string>;
|
|
17
|
-
export declare function getAvailableTemplates(): Promise<string[]>;
|
|
17
|
+
export declare function getAvailableTemplates(localPrefix?: string): Promise<string[]>;
|
package/dist/templates.js
CHANGED
|
@@ -253,9 +253,16 @@ function injectPropertyIntoObject(content, propertyPath, replacement) {
|
|
|
253
253
|
console.warn(`Could not inject property "${propertyPath}" - no suitable object found in content`);
|
|
254
254
|
return content;
|
|
255
255
|
}
|
|
256
|
-
export async function getAvailableTemplates() {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
256
|
+
export async function getAvailableTemplates(localPrefix) {
|
|
257
|
+
if (localPrefix && localPrefix.length > 0) {
|
|
258
|
+
const fullTemplatePath = path.join(localPrefix, 'template-projects');
|
|
259
|
+
const response = await fs.readdir(fullTemplatePath);
|
|
260
|
+
return response.filter((item) => fs.stat(path.join(fullTemplatePath, item)).then((stat) => stat.isDirectory()));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Fetch the list of templates from your repo
|
|
264
|
+
const response = await fetch(`https://api.github.com/repos/inkeep/agents/contents/agents-cookbook/template-projects`);
|
|
265
|
+
const contents = await response.json();
|
|
266
|
+
return contents.filter((item) => item.type === 'dir').map((item) => item.name);
|
|
267
|
+
}
|
|
261
268
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -40,5 +40,7 @@ export declare const createAgents: (args?: {
|
|
|
40
40
|
template?: string;
|
|
41
41
|
customProjectId?: string;
|
|
42
42
|
disableGit?: boolean;
|
|
43
|
+
localAgentsPrefix?: string;
|
|
44
|
+
localTemplatesPrefix?: string;
|
|
43
45
|
}) => Promise<void>;
|
|
44
46
|
export declare function createCommand(dirName?: string, options?: any): Promise<void>;
|
package/dist/utils.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as p from '@clack/prompts';
|
|
|
6
6
|
import { ANTHROPIC_MODELS, GOOGLE_MODELS, OPENAI_MODELS } from '@inkeep/agents-core';
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import color from 'picocolors';
|
|
9
|
-
import { cloneTemplate, getAvailableTemplates } from './templates.js';
|
|
9
|
+
import { cloneTemplate, cloneTemplateLocal, getAvailableTemplates, } from './templates.js';
|
|
10
10
|
// Shared validation utility
|
|
11
11
|
const DIRECTORY_VALIDATION = {
|
|
12
12
|
pattern: /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/,
|
|
@@ -28,6 +28,8 @@ const DIRECTORY_VALIDATION = {
|
|
|
28
28
|
return undefined;
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
|
+
const agentsTemplateRepo = 'https://github.com/inkeep/agents/create-agents-template';
|
|
32
|
+
const projectTemplateRepo = 'https://github.com/inkeep/agents/agents-cookbook/template-projects';
|
|
31
33
|
const execAsync = promisify(exec);
|
|
32
34
|
const manageApiPort = '3002';
|
|
33
35
|
const runApiPort = '3003';
|
|
@@ -65,7 +67,7 @@ export const defaultAnthropicModelConfigurations = {
|
|
|
65
67
|
},
|
|
66
68
|
};
|
|
67
69
|
export const createAgents = async (args = {}) => {
|
|
68
|
-
let { dirName, openAiKey, anthropicKey, googleKey, template, customProjectId, disableGit } = args;
|
|
70
|
+
let { dirName, openAiKey, anthropicKey, googleKey, template, customProjectId, disableGit, localAgentsPrefix, localTemplatesPrefix, } = args;
|
|
69
71
|
const tenantId = 'default';
|
|
70
72
|
let projectId;
|
|
71
73
|
let templateName;
|
|
@@ -74,7 +76,7 @@ export const createAgents = async (args = {}) => {
|
|
|
74
76
|
templateName = '';
|
|
75
77
|
}
|
|
76
78
|
else if (template) {
|
|
77
|
-
const availableTemplates = await getAvailableTemplates();
|
|
79
|
+
const availableTemplates = await getAvailableTemplates(localTemplatesPrefix);
|
|
78
80
|
if (!availableTemplates.includes(template)) {
|
|
79
81
|
p.cancel(`${color.red('✗')} Template "${template}" not found\n\n` +
|
|
80
82
|
`${color.yellow('Available templates:')}\n` +
|
|
@@ -188,10 +190,6 @@ export const createAgents = async (args = {}) => {
|
|
|
188
190
|
const s = p.spinner();
|
|
189
191
|
s.start('Creating directory structure...');
|
|
190
192
|
try {
|
|
191
|
-
const agentsTemplateRepo = 'https://github.com/inkeep/create-agents-template';
|
|
192
|
-
const projectTemplateRepo = templateName
|
|
193
|
-
? `https://github.com/inkeep/agents-cookbook/template-projects/${templateName}`
|
|
194
|
-
: null;
|
|
195
193
|
const directoryPath = path.resolve(process.cwd(), dirName);
|
|
196
194
|
if (await fs.pathExists(directoryPath)) {
|
|
197
195
|
s.stop();
|
|
@@ -206,7 +204,10 @@ export const createAgents = async (args = {}) => {
|
|
|
206
204
|
await fs.emptyDir(directoryPath);
|
|
207
205
|
}
|
|
208
206
|
s.message('Building template...');
|
|
209
|
-
await
|
|
207
|
+
await cloneTemplateHelper({
|
|
208
|
+
targetPath: directoryPath,
|
|
209
|
+
localPrefix: localAgentsPrefix,
|
|
210
|
+
});
|
|
210
211
|
process.chdir(directoryPath);
|
|
211
212
|
const config = {
|
|
212
213
|
dirName,
|
|
@@ -223,7 +224,7 @@ export const createAgents = async (args = {}) => {
|
|
|
223
224
|
await createWorkspaceStructure();
|
|
224
225
|
s.message('Setting up environment files...');
|
|
225
226
|
await createEnvironmentFiles(config);
|
|
226
|
-
if (
|
|
227
|
+
if (templateName && templateName.length > 0) {
|
|
227
228
|
s.message('Creating project template folder...');
|
|
228
229
|
const templateTargetPath = `src/projects/${projectId}`;
|
|
229
230
|
const contentReplacements = [
|
|
@@ -234,7 +235,12 @@ export const createAgents = async (args = {}) => {
|
|
|
234
235
|
},
|
|
235
236
|
},
|
|
236
237
|
];
|
|
237
|
-
await
|
|
238
|
+
await cloneTemplateHelper({
|
|
239
|
+
templateName,
|
|
240
|
+
targetPath: templateTargetPath,
|
|
241
|
+
localPrefix: localTemplatesPrefix,
|
|
242
|
+
replacements: contentReplacements,
|
|
243
|
+
});
|
|
238
244
|
}
|
|
239
245
|
else {
|
|
240
246
|
s.message('Creating empty project folder...');
|
|
@@ -505,6 +511,27 @@ async function setupDatabase() {
|
|
|
505
511
|
throw new Error(`Failed to setup database: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
506
512
|
}
|
|
507
513
|
}
|
|
514
|
+
async function cloneTemplateHelper(options) {
|
|
515
|
+
const { targetPath, templateName, localPrefix, replacements } = options;
|
|
516
|
+
// If local prefix is provided, use it to clone the template. This is useful for local development and testing.
|
|
517
|
+
if (localPrefix && localPrefix.length > 0) {
|
|
518
|
+
if (templateName) {
|
|
519
|
+
const fullTemplatePath = path.join(localPrefix, templateName);
|
|
520
|
+
await cloneTemplateLocal(fullTemplatePath, targetPath, replacements);
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
await cloneTemplateLocal(localPrefix, targetPath, replacements);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
if (templateName) {
|
|
528
|
+
await cloneTemplate(`${projectTemplateRepo}/${templateName}`, targetPath, replacements);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
await cloneTemplate(agentsTemplateRepo, targetPath, replacements);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
508
535
|
export async function createCommand(dirName, options) {
|
|
509
536
|
await createAgents({
|
|
510
537
|
dirName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/create-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Create an Inkeep Agent Framework project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"drizzle-kit": "^0.31.5",
|
|
35
35
|
"fs-extra": "^11.0.0",
|
|
36
36
|
"picocolors": "^1.0.0",
|
|
37
|
-
"@inkeep/agents-core": "0.
|
|
37
|
+
"@inkeep/agents-core": "0.30.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/degit": "^2.8.6",
|