@inkeep/create-agents 0.0.0-dev-20260224144914 → 0.0.0-dev-20260224165929

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.
@@ -2,7 +2,7 @@ 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
4
  import { cloneTemplate, cloneTemplateLocal, getAvailableTemplates } from '../templates';
5
- import { createAgents, defaultMockModelConfigurations } from '../utils';
5
+ import { createAgents, defaultMockModelConfigurations, syncTemplateDependencies } from '../utils';
6
6
  // Create the mock execAsync function that will be used by promisify - hoisted so it's available in mocks
7
7
  const { mockExecAsync } = vi.hoisted(() => ({
8
8
  mockExecAsync: vi.fn().mockResolvedValue({ stdout: '', stderr: '' }),
@@ -23,6 +23,20 @@ vi.mock('node:child_process', () => ({
23
23
  vi.mock('node:util', () => ({
24
24
  promisify: vi.fn(() => mockExecAsync),
25
25
  }));
26
+ vi.mock('node:fs', async (importOriginal) => {
27
+ const actual = await importOriginal();
28
+ return {
29
+ ...actual,
30
+ readFileSync: vi.fn(() => JSON.stringify({ version: '1.2.3' })),
31
+ };
32
+ });
33
+ vi.mock('node:url', async (importOriginal) => {
34
+ const actual = await importOriginal();
35
+ return {
36
+ ...actual,
37
+ fileURLToPath: vi.fn(() => '/fake/dist/utils.js'),
38
+ };
39
+ });
26
40
  // Setup default mocks
27
41
  const mockSpinner = {
28
42
  start: vi.fn().mockReturnThis(),
@@ -46,7 +60,7 @@ const mockEnvExample = [
46
60
  'NANGO_SECRET_KEY=',
47
61
  'NANGO_SERVER_URL=http://localhost:3050',
48
62
  'SIGNOZ_URL=http://localhost:3080',
49
- 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:14318/v1/traces',
63
+ 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=',
50
64
  'INKEEP_AGENTS_MANAGE_UI_USERNAME=admin@example.com',
51
65
  'INKEEP_AGENTS_MANAGE_UI_PASSWORD=adminADMIN!@12',
52
66
  'BETTER_AUTH_SECRET=your-secret-key-change-in-production',
@@ -466,3 +480,179 @@ function setupDefaultMocks() {
466
480
  vi.mocked(cloneTemplateLocal).mockResolvedValue(undefined);
467
481
  mockExecAsync.mockResolvedValue({ stdout: '', stderr: '' });
468
482
  }
483
+ describe('syncTemplateDependencies', () => {
484
+ function mockDirent(name, isDir) {
485
+ return { name, isDirectory: () => isDir, isFile: () => !isDir };
486
+ }
487
+ function setupFlatTemplate(rootPkg) {
488
+ vi.mocked(fs.pathExists).mockResolvedValue(true);
489
+ vi.mocked(fs.readdir).mockResolvedValue([]);
490
+ vi.mocked(fs.readJson).mockResolvedValue(rootPkg);
491
+ vi.mocked(fs.writeJson).mockResolvedValue(undefined);
492
+ }
493
+ beforeEach(() => {
494
+ vi.clearAllMocks();
495
+ });
496
+ it('should update @inkeep/* dependencies to match CLI version', async () => {
497
+ const mockPkg = {
498
+ name: 'test-project',
499
+ dependencies: {
500
+ '@inkeep/agents-core': '^0.50.3',
501
+ '@inkeep/agents-sdk': '^0.50.3',
502
+ 'some-other-package': '^1.0.0',
503
+ },
504
+ };
505
+ setupFlatTemplate(mockPkg);
506
+ await syncTemplateDependencies('/test/path');
507
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
508
+ dependencies: {
509
+ '@inkeep/agents-core': '^1.2.3',
510
+ '@inkeep/agents-sdk': '^1.2.3',
511
+ 'some-other-package': '^1.0.0',
512
+ },
513
+ }), { spaces: 2 });
514
+ });
515
+ it('should skip if template package.json does not exist', async () => {
516
+ vi.mocked(fs.pathExists).mockResolvedValue(false);
517
+ vi.mocked(fs.readdir).mockResolvedValue([]);
518
+ await syncTemplateDependencies('/test/path');
519
+ expect(fs.readJson).not.toHaveBeenCalled();
520
+ expect(fs.writeJson).not.toHaveBeenCalled();
521
+ });
522
+ it('should handle template with no @inkeep/* dependencies', async () => {
523
+ const mockPkg = {
524
+ name: 'test-project',
525
+ dependencies: {
526
+ 'some-other-package': '^1.0.0',
527
+ },
528
+ };
529
+ setupFlatTemplate(mockPkg);
530
+ await syncTemplateDependencies('/test/path');
531
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
532
+ dependencies: {
533
+ 'some-other-package': '^1.0.0',
534
+ },
535
+ }), { spaces: 2 });
536
+ });
537
+ it('should handle template with no devDependencies', async () => {
538
+ const mockPkg = {
539
+ name: 'test-project',
540
+ dependencies: {
541
+ '@inkeep/agents-core': '^0.50.3',
542
+ },
543
+ };
544
+ setupFlatTemplate(mockPkg);
545
+ await syncTemplateDependencies('/test/path');
546
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
547
+ dependencies: {
548
+ '@inkeep/agents-core': '^1.2.3',
549
+ },
550
+ }), { spaces: 2 });
551
+ });
552
+ it('should update devDependencies @inkeep/* packages', async () => {
553
+ const mockPkg = {
554
+ name: 'test-project',
555
+ dependencies: {},
556
+ devDependencies: {
557
+ '@inkeep/agents-sdk': '^0.49.0',
558
+ vitest: '^1.0.0',
559
+ },
560
+ };
561
+ setupFlatTemplate(mockPkg);
562
+ await syncTemplateDependencies('/test/path');
563
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
564
+ devDependencies: {
565
+ '@inkeep/agents-sdk': '^1.2.3',
566
+ vitest: '^1.0.0',
567
+ },
568
+ }), { spaces: 2 });
569
+ });
570
+ it('should not modify non-@inkeep dependencies', async () => {
571
+ const mockPkg = {
572
+ name: 'test-project',
573
+ dependencies: {
574
+ '@inkeep/agents-core': '^0.50.3',
575
+ react: '^18.0.0',
576
+ next: '^14.0.0',
577
+ },
578
+ };
579
+ setupFlatTemplate(mockPkg);
580
+ await syncTemplateDependencies('/test/path');
581
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
582
+ dependencies: {
583
+ '@inkeep/agents-core': '^1.2.3',
584
+ react: '^18.0.0',
585
+ next: '^14.0.0',
586
+ },
587
+ }), { spaces: 2 });
588
+ });
589
+ it('should skip sync when CLI version cannot be determined', async () => {
590
+ const nodeFs = await import('node:fs');
591
+ vi.mocked(nodeFs.readFileSync).mockImplementation(() => {
592
+ throw new Error('ENOENT');
593
+ });
594
+ vi.mocked(fs.pathExists).mockResolvedValue(true);
595
+ vi.mocked(fs.readdir).mockResolvedValue([]);
596
+ vi.mocked(fs.readJson).mockResolvedValue({
597
+ name: 'test-project',
598
+ dependencies: { '@inkeep/agents-core': '^0.50.3' },
599
+ });
600
+ await syncTemplateDependencies('/test/path');
601
+ expect(fs.writeJson).not.toHaveBeenCalled();
602
+ });
603
+ it('should sync nested package.json files in subdirectories', async () => {
604
+ const nodeFs = await import('node:fs');
605
+ vi.mocked(nodeFs.readFileSync).mockReturnValue(JSON.stringify({ version: '1.2.3' }));
606
+ const rootPkg = {
607
+ name: 'monorepo',
608
+ dependencies: { '@inkeep/agents-core': '^0.50.3' },
609
+ };
610
+ const nestedPkg = {
611
+ name: 'nested-app',
612
+ dependencies: { '@inkeep/agents-sdk': '^0.50.3', express: '^4.0.0' },
613
+ };
614
+ vi.mocked(fs.pathExists).mockResolvedValue(true);
615
+ vi.mocked(fs.readdir)
616
+ .mockResolvedValueOnce([mockDirent('apps', true), mockDirent('README.md', false)])
617
+ .mockResolvedValueOnce([mockDirent('api', true)])
618
+ .mockResolvedValueOnce([]);
619
+ vi.mocked(fs.readJson)
620
+ .mockResolvedValueOnce(rootPkg)
621
+ .mockResolvedValueOnce(nestedPkg)
622
+ .mockResolvedValueOnce(nestedPkg);
623
+ vi.mocked(fs.writeJson).mockResolvedValue(undefined);
624
+ await syncTemplateDependencies('/test/path');
625
+ expect(fs.writeJson).toHaveBeenCalledTimes(3);
626
+ expect(fs.writeJson).toHaveBeenCalledWith('/test/path/package.json', expect.objectContaining({
627
+ dependencies: { '@inkeep/agents-core': '^1.2.3' },
628
+ }), { spaces: 2 });
629
+ expect(fs.writeJson).toHaveBeenCalledWith(expect.stringContaining('apps/package.json'), expect.anything(), { spaces: 2 });
630
+ expect(fs.writeJson).toHaveBeenCalledWith(expect.stringContaining('apps/api/package.json'), expect.objectContaining({
631
+ dependencies: { '@inkeep/agents-sdk': '^1.2.3', express: '^4.0.0' },
632
+ }), { spaces: 2 });
633
+ });
634
+ it('should skip node_modules and dot directories', async () => {
635
+ const nodeFs = await import('node:fs');
636
+ vi.mocked(nodeFs.readFileSync).mockReturnValue(JSON.stringify({ version: '1.2.3' }));
637
+ const rootPkg = {
638
+ name: 'test-project',
639
+ dependencies: { '@inkeep/agents-core': '^0.50.3' },
640
+ };
641
+ vi.mocked(fs.pathExists).mockResolvedValue(true);
642
+ vi.mocked(fs.readdir)
643
+ .mockResolvedValueOnce([
644
+ mockDirent('node_modules', true),
645
+ mockDirent('.git', true),
646
+ mockDirent('src', true),
647
+ ])
648
+ .mockResolvedValueOnce([]);
649
+ vi.mocked(fs.readJson).mockResolvedValue(rootPkg);
650
+ vi.mocked(fs.writeJson).mockResolvedValue(undefined);
651
+ await syncTemplateDependencies('/test/path');
652
+ expect(fs.readdir).toHaveBeenCalledTimes(2);
653
+ expect(fs.readdir).toHaveBeenCalledWith('/test/path', { withFileTypes: true });
654
+ expect(fs.readdir).toHaveBeenCalledWith(expect.stringContaining('src'), {
655
+ withFileTypes: true,
656
+ });
657
+ });
658
+ });
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export declare function syncTemplateDependencies(templatePath: string): Promise<void>;
1
2
  export declare const defaultGoogleModelConfigurations: {
2
3
  base: {
3
4
  model: "google/gemini-2.5-flash";
package/dist/utils.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { exec } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
2
3
  import os from 'node:os';
3
4
  import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
4
6
  import { promisify } from 'node:util';
5
7
  import * as p from '@clack/prompts';
6
8
  import { ANTHROPIC_MODELS, GOOGLE_MODELS, OPENAI_MODELS } from '@inkeep/agents-core';
@@ -32,6 +34,52 @@ const agentsTemplateRepo = 'https://github.com/inkeep/agents/create-agents-templ
32
34
  const projectTemplateRepo = 'https://github.com/inkeep/agents/agents-cookbook/template-projects';
33
35
  const execAsync = promisify(exec);
34
36
  const agentsApiPort = '3002';
37
+ function getCliVersion() {
38
+ try {
39
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
40
+ const pkgJson = JSON.parse(readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
41
+ return pkgJson.version;
42
+ }
43
+ catch {
44
+ return '';
45
+ }
46
+ }
47
+ export async function syncTemplateDependencies(templatePath) {
48
+ const cliVersion = getCliVersion();
49
+ if (!cliVersion)
50
+ return;
51
+ const packageJsonPaths = await findPackageJsonFiles(templatePath);
52
+ await Promise.all(packageJsonPaths.map(async (pkgPath) => {
53
+ const pkg = await fs.readJson(pkgPath);
54
+ for (const depType of ['dependencies', 'devDependencies']) {
55
+ const deps = pkg[depType];
56
+ if (!deps)
57
+ continue;
58
+ for (const name of Object.keys(deps)) {
59
+ if (name.startsWith('@inkeep/') && name !== '@inkeep/agents-ui') {
60
+ deps[name] = `^${cliVersion}`;
61
+ }
62
+ }
63
+ }
64
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
65
+ }));
66
+ }
67
+ async function findPackageJsonFiles(dir) {
68
+ const results = [];
69
+ const rootPkg = path.join(dir, 'package.json');
70
+ if (await fs.pathExists(rootPkg)) {
71
+ results.push(rootPkg);
72
+ }
73
+ const entries = await fs.readdir(dir, { withFileTypes: true });
74
+ for (const entry of entries) {
75
+ if (!entry.isDirectory() || entry.name === 'node_modules' || entry.name.startsWith('.')) {
76
+ continue;
77
+ }
78
+ const nested = await findPackageJsonFiles(path.join(dir, entry.name));
79
+ results.push(...nested);
80
+ }
81
+ return results;
82
+ }
35
83
  export const defaultGoogleModelConfigurations = {
36
84
  base: {
37
85
  model: GOOGLE_MODELS.GEMINI_2_5_FLASH,
@@ -313,6 +361,7 @@ export const createAgents = async (args = {}) => {
313
361
  localPrefix: localAgentsPrefix,
314
362
  });
315
363
  process.chdir(directoryPath);
364
+ await syncTemplateDependencies('.');
316
365
  const config = {
317
366
  dirName,
318
367
  tenantId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/create-agents",
3
- "version": "0.0.0-dev-20260224144914",
3
+ "version": "0.0.0-dev-20260224165929",
4
4
  "description": "Create an Inkeep Agent Framework project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,7 +33,7 @@
33
33
  "degit": "^2.8.4",
34
34
  "fs-extra": "^11.0.0",
35
35
  "picocolors": "^1.0.0",
36
- "@inkeep/agents-core": "0.0.0-dev-20260224144914"
36
+ "@inkeep/agents-core": "0.0.0-dev-20260224165929"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/degit": "^2.8.6",