kodu 2.1.1 → 2.1.3

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 (32) hide show
  1. package/AGENTS.md +23 -1
  2. package/__tests__/core/fs/fs.service.test.ts +72 -0
  3. package/__tests__/shared/cleaner/cleaner.service.test.ts +102 -0
  4. package/__tests__/shared/git/git.service.test.ts +84 -0
  5. package/__tests__/shared/tokenizer/tokenizer.service.test.ts +45 -0
  6. package/dist/package.json +14 -3
  7. package/dist/src/commands/init/init.command.d.ts +1 -0
  8. package/dist/src/commands/init/init.command.js +34 -1
  9. package/dist/src/commands/init/init.command.js.map +1 -1
  10. package/dist/src/core/config/config.service.js +2 -4
  11. package/dist/src/core/config/config.service.js.map +1 -1
  12. package/dist/tsconfig.build.tsbuildinfo +1 -1
  13. package/lefthook.yml +9 -2
  14. package/package.json +14 -3
  15. package/skills/doc-gen/SKILL.md +490 -0
  16. package/skills/doc-gen/scripts/doc_gen.py +911 -0
  17. package/skills/implement-project/SKILL.md +409 -0
  18. package/skills/liteend-init/SKILL.md +84 -0
  19. package/skills/litefront-init/SKILL.md +96 -0
  20. package/skills/litefront-prototype/SKILL.md +484 -0
  21. package/skills/project-setup-standardizer/SKILL.md +285 -0
  22. package/skills/start/SKILL.md +319 -0
  23. package/skills/tech-blueprint/SKILL.md +890 -0
  24. package/skills/tech-blueprint/scripts/blueprint_validator.py +417 -0
  25. package/src/commands/init/init.command.ts +43 -1
  26. package/src/core/config/config.service.ts +3 -6
  27. package/tsconfig.build.json +3 -0
  28. package/tsconfig.json +5 -2
  29. package/dist/scripts/generate-json-schema.d.ts +0 -1
  30. package/dist/scripts/generate-json-schema.js +0 -17
  31. package/dist/scripts/generate-json-schema.js.map +0 -1
  32. package/skills/kodu-ops/SKILL.md +0 -184
package/AGENTS.md CHANGED
@@ -184,7 +184,29 @@ This executes: TypeScript check + Biome lint + Knip dead code detection.
184
184
  - **No Legacy Tests:** Project relies on strict static typing
185
185
  - If tests exist: place in `__tests__/` or `*.test.ts` files
186
186
 
187
- ## 11. Handling Uncertainties
187
+ ## 11. Release Process
188
+
189
+ ### Prerequisites
190
+ - Working directory must be clean (`git status` — no dirty files)
191
+ - All changes committed and pushed
192
+ - You have npm publish access
193
+
194
+ ### Steps
195
+ ```bash
196
+ # 1. Ensure clean working directory
197
+ git status
198
+
199
+ # 2. Bump version, build, publish
200
+ npm version patch && npm run build && npm publish --access public
201
+
202
+ # 3. Push the version bump commit and tag
203
+ git push && git push --tags
204
+ ```
205
+
206
+ - Use `npm version minor` for new features, `npm version major` for breaking changes
207
+ - The `npm version` command creates a git tag automatically (e.g. `v2.1.3`)
208
+
209
+ ## 12. Handling Uncertainties
188
210
 
189
211
  - Unclear requirements? Ask the user first
190
212
  - Library not in Tech Stack section? Prefer native Node.js APIs
@@ -0,0 +1,72 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { ConfigService } from '../../../src/core/config/config.service';
3
+ import { FsService } from '../../../src/core/file-system/fs.service';
4
+ import { UiService } from '../../../src/core/ui/ui.service';
5
+
6
+ vi.mock('../../../src/core/config/config.service', () => ({
7
+ ConfigService: vi.fn().mockImplementation(() => ({
8
+ getConfig: () => ({
9
+ cleaner: { whitelist: [], keepJSDoc: false },
10
+ packer: { ignore: ['node_modules', 'dist'], useGitignore: false },
11
+ }),
12
+ })),
13
+ }));
14
+
15
+ vi.mock('../../../src/core/ui/ui.service', () => ({
16
+ UiService: vi.fn().mockImplementation(() => ({
17
+ log: { warn: vi.fn() },
18
+ })),
19
+ }));
20
+
21
+ describe('FsService', () => {
22
+ let fsService: FsService;
23
+
24
+ beforeEach(() => {
25
+ vi.clearAllMocks();
26
+ const configService = new ConfigService() as never;
27
+ const uiService = new UiService() as never;
28
+ fsService = new FsService(configService, uiService);
29
+ });
30
+
31
+ describe('findProjectFiles', () => {
32
+ it('should find ts files in current directory', async () => {
33
+ const files = await fsService.findProjectFiles({
34
+ ignore: ['node_modules', 'dist'],
35
+ useGitignore: false,
36
+ });
37
+
38
+ const tsFiles = files.filter((f) => f.endsWith('.ts'));
39
+ expect(tsFiles.length).toBeGreaterThan(0);
40
+ });
41
+
42
+ it('should exclude node_modules by default', async () => {
43
+ const files = await fsService.findProjectFiles({
44
+ ignore: ['node_modules', 'dist'],
45
+ useGitignore: false,
46
+ });
47
+
48
+ const hasNodeModules = files.some((f) => f.includes('node_modules'));
49
+ expect(hasNodeModules).toBe(false);
50
+ });
51
+
52
+ it('should return relative paths', async () => {
53
+ const files = await fsService.findProjectFiles({
54
+ ignore: [],
55
+ useGitignore: false,
56
+ });
57
+
58
+ const hasAbsolute = files.some((f) => f.startsWith('/'));
59
+ expect(hasAbsolute).toBe(false);
60
+ });
61
+
62
+ it('should return sorted paths', async () => {
63
+ const files = await fsService.findProjectFiles({
64
+ ignore: [],
65
+ useGitignore: false,
66
+ });
67
+
68
+ const sorted = [...files].sort((a, b) => a.localeCompare(b));
69
+ expect(files).toEqual(sorted);
70
+ });
71
+ });
72
+ });
@@ -0,0 +1,102 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { ConfigService } from '../../../src/core/config/config.service';
3
+
4
+ vi.mock('../../../src/core/config/config.service', () => ({
5
+ ConfigService: vi.fn().mockImplementation(() => ({
6
+ getConfig: () => ({
7
+ cleaner: {
8
+ whitelist: [],
9
+ keepJSDoc: false,
10
+ useGitignore: false,
11
+ },
12
+ packer: {
13
+ ignore: [],
14
+ useGitignore: false,
15
+ },
16
+ }),
17
+ })),
18
+ }));
19
+
20
+ vi.mock('../../../src/core/file-system/fs.service', () => ({
21
+ FsService: vi.fn().mockImplementation(() => ({})),
22
+ }));
23
+
24
+ describe('CleanerService', () => {
25
+ beforeEach(() => {
26
+ vi.clearAllMocks();
27
+ });
28
+
29
+ it('should remove single-line comments', async () => {
30
+ const { CleanerService } = await import(
31
+ '../../../src/shared/cleaner/cleaner.service'
32
+ );
33
+ const configService = new ConfigService() as never;
34
+ const fsService = {} as never;
35
+ const cleaner = new CleanerService(configService, fsService);
36
+
37
+ const input = `const x = 1; // comment
38
+ const y = 2;`;
39
+ const result = cleaner.cleanContent('test.ts', input);
40
+
41
+ expect(result).toBe('const x = 1; \nconst y = 2;');
42
+ });
43
+
44
+ it('should remove multi-line comments', async () => {
45
+ const { CleanerService } = await import(
46
+ '../../../src/shared/cleaner/cleaner.service'
47
+ );
48
+ const configService = new ConfigService() as never;
49
+ const fsService = {} as never;
50
+ const cleaner = new CleanerService(configService, fsService);
51
+
52
+ const input = `/* comment */
53
+ const x = 1;`;
54
+ const result = cleaner.cleanContent('test.ts', input);
55
+
56
+ expect(result).toBe('\nconst x = 1;');
57
+ });
58
+
59
+ it('should preserve comments in whitelist', async () => {
60
+ const { CleanerService } = await import(
61
+ '../../../src/shared/cleaner/cleaner.service'
62
+ );
63
+ const configService = new ConfigService() as never;
64
+ const fsService = {} as never;
65
+ const cleaner = new CleanerService(configService, fsService);
66
+
67
+ const input = `const x = 1; // eslint-disable-line
68
+ const y = 2;`;
69
+ const result = cleaner.cleanContent('test.ts', input);
70
+
71
+ expect(result).toBe('const x = 1; // eslint-disable-line\nconst y = 2;');
72
+ });
73
+
74
+ it('should keep JSDoc when option is set', async () => {
75
+ const { CleanerService } = await import(
76
+ '../../../src/shared/cleaner/cleaner.service'
77
+ );
78
+ const configService = new ConfigService() as never;
79
+ const fsService = {} as never;
80
+ const cleaner = new CleanerService(configService, fsService);
81
+
82
+ const input = `/** JSDoc */
83
+ const x = 1;`;
84
+ const result = cleaner.cleanContent('test.ts', input, true);
85
+
86
+ expect(result).toBe('/** JSDoc */\nconst x = 1;');
87
+ });
88
+
89
+ it('should remove JSX expression without content', async () => {
90
+ const { CleanerService } = await import(
91
+ '../../../src/shared/cleaner/cleaner.service'
92
+ );
93
+ const configService = new ConfigService() as never;
94
+ const fsService = {} as never;
95
+ const cleaner = new CleanerService(configService, fsService);
96
+
97
+ const input = `const x = <>{/* comment */}</>;`;
98
+ const result = cleaner.cleanContent('test.tsx', input);
99
+
100
+ expect(result).toBe('const x = <></>;');
101
+ });
102
+ });
@@ -0,0 +1,84 @@
1
+ import { execa } from 'execa';
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { GitService } from '../../../src/shared/git/git.service';
4
+
5
+ vi.mock('execa');
6
+
7
+ const mockExeca = vi.mocked(execa);
8
+
9
+ describe('GitService', () => {
10
+ let gitService: GitService;
11
+
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ gitService = new GitService();
15
+ });
16
+
17
+ afterEach(() => {
18
+ vi.resetAllMocks();
19
+ });
20
+
21
+ describe('ensureRepo', () => {
22
+ it('should resolve when inside git repo', async () => {
23
+ mockExeca.mockResolvedValue({ stdout: '' } as never);
24
+
25
+ await expect(gitService.ensureRepo()).resolves.not.toThrow();
26
+ });
27
+
28
+ it('should reject when not in git repo', async () => {
29
+ mockExeca.mockRejectedValue(new Error('fatal: not a git repository'));
30
+
31
+ await expect(gitService.ensureRepo()).rejects.toThrow();
32
+ });
33
+ });
34
+
35
+ describe('getChangedFiles', () => {
36
+ it('should return empty array when no changes', async () => {
37
+ mockExeca.mockResolvedValue({ stdout: '' } as never);
38
+
39
+ const files = await gitService.getChangedFiles();
40
+
41
+ expect(files).toEqual([]);
42
+ });
43
+
44
+ it('should return changed files from all sources', async () => {
45
+ const mockCalls = [
46
+ { stdout: '' }, // ensureRepo
47
+ { stdout: 'src/a.ts\nsrc/b.ts' }, // diff
48
+ { stdout: '' }, // diff --staged
49
+ { stdout: '' }, // ls-files
50
+ ];
51
+ mockExeca
52
+ .mockResolvedValueOnce(mockCalls[0] as never)
53
+ .mockResolvedValueOnce(mockCalls[1] as never)
54
+ .mockResolvedValueOnce(mockCalls[2] as never)
55
+ .mockResolvedValueOnce(mockCalls[3] as never);
56
+
57
+ const files = await gitService.getChangedFiles();
58
+
59
+ expect(files).toEqual(['src/a.ts', 'src/b.ts']);
60
+ });
61
+ });
62
+
63
+ describe('getStagedFiles', () => {
64
+ it('should return empty array when no staged files', async () => {
65
+ mockExeca
66
+ .mockResolvedValueOnce({ stdout: '' } as never)
67
+ .mockResolvedValueOnce({ stdout: '' } as never);
68
+
69
+ const files = await gitService.getStagedFiles();
70
+
71
+ expect(files).toEqual([]);
72
+ });
73
+
74
+ it('should return staged files', async () => {
75
+ mockExeca
76
+ .mockResolvedValueOnce({ stdout: '' } as never)
77
+ .mockResolvedValueOnce({ stdout: 'src/new.ts' } as never);
78
+
79
+ const files = await gitService.getStagedFiles();
80
+
81
+ expect(files).toEqual(['src/new.ts']);
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,45 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+
3
+ describe('TokenizerService', () => {
4
+ let tokenizer: {
5
+ count: (text: string) => { tokens: number; usdEstimate: number };
6
+ };
7
+
8
+ beforeEach(async () => {
9
+ const { TokenizerService } = await import(
10
+ '../../../src/shared/tokenizer/tokenizer.service'
11
+ );
12
+ tokenizer = new TokenizerService();
13
+ });
14
+
15
+ it('should count tokens for empty string', () => {
16
+ const result = tokenizer.count('');
17
+
18
+ expect(result.tokens).toBe(0);
19
+ expect(result.usdEstimate).toBe(0);
20
+ });
21
+
22
+ it('should count tokens for simple text', () => {
23
+ const result = tokenizer.count('hello world');
24
+
25
+ expect(result.tokens).toBeGreaterThan(0);
26
+ expect(result.usdEstimate).toBeGreaterThan(0);
27
+ });
28
+
29
+ it('should estimate cost correctly based on DEFAULT_PRICE_PER_MILLION', () => {
30
+ const result = tokenizer.count('a'.repeat(1000));
31
+
32
+ expect(result.tokens).toBeGreaterThan(0);
33
+ // DEFAULT_PRICE_PER_MILLION = 5 means $5 per 1M tokens
34
+ const expectedCost = (result.tokens / 1_000_000) * 5;
35
+ expect(result.usdEstimate).toBe(expectedCost);
36
+ });
37
+
38
+ it('should handle large text', () => {
39
+ const longText = 'test '.repeat(10000);
40
+ const result = tokenizer.count(longText);
41
+
42
+ expect(result.tokens).toBeGreaterThan(10000);
43
+ expect(result.usdEstimate).toBeGreaterThan(0);
44
+ });
45
+ });
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kodu",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "High-performance CLI to prepare codebase for LLMs, automate reviews, and draft commits.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,6 +34,7 @@
34
34
  "generate:schema": "ts-node scripts/generate-json-schema.ts",
35
35
  "postbuild": "npm run generate:schema",
36
36
  "start:prod": "node dist/main.js",
37
+ "start:dev": "nest start --watch",
37
38
  "new:command": "nest g -c nest-commander-schematics command",
38
39
  "new:question": "nest g -c nest-commander-schematics question",
39
40
  "________________ FORMAT AND LINT ________________": "",
@@ -43,8 +44,14 @@
43
44
  "ts:check": "tsc --noEmit",
44
45
  "knip": "knip --production",
45
46
  "check": "run-p ts:check lint:fix knip",
47
+ "________________ TEST ________________": "",
48
+ "test": "vitest run",
49
+ "test:watch": "vitest",
50
+ "test:cov": "vitest run --coverage",
46
51
  "________________ OTHER ________________": "",
47
- "prepare": "lefthook install"
52
+ "prepare": "is-ci || lefthook install",
53
+ "update": "npx npm-check-updates -u && rimraf node_modules package-lock.json && npm i",
54
+ "postupdate": "npm run lint:fix && npm run check"
48
55
  },
49
56
  "dependencies": {
50
57
  "@inquirer/confirm": "^6.0.4",
@@ -73,13 +80,17 @@
73
80
  "@nestjs/schematics": "^11.0.0",
74
81
  "@nestjs/testing": "^11.0.1",
75
82
  "@types/node": "^22.10.7",
83
+ "is-ci": "^4.1.0",
76
84
  "knip": "^5.82.1",
77
85
  "lefthook": "^2.0.15",
78
86
  "nest-commander-schematics": "^3.2.0",
87
+ "npm-check-updates": "^18.3.1",
79
88
  "npm-run-all": "^4.1.5",
89
+ "rimraf": "^6.1.3",
80
90
  "ts-loader": "^9.5.2",
81
91
  "ts-node": "^10.9.2",
82
92
  "tsconfig-paths": "^4.2.0",
83
- "typescript": "^5.7.3"
93
+ "typescript": "^5.7.3",
94
+ "vitest": "^3.2.4"
84
95
  }
85
96
  }
@@ -4,6 +4,7 @@ export declare class InitCommand extends CommandRunner {
4
4
  private readonly ui;
5
5
  constructor(ui: UiService);
6
6
  run(): Promise<void>;
7
+ private ensureKoduJson;
7
8
  private updateGitignore;
8
9
  private exists;
9
10
  }
@@ -18,6 +18,29 @@ const node_path_1 = __importDefault(require("node:path"));
18
18
  const nest_commander_1 = require("nest-commander");
19
19
  const ui_service_1 = require("../../core/ui/ui.service");
20
20
  const GITIGNORE_ENTRY = '.kodu/context.txt';
21
+ const DEFAULT_KODU_JSON = {
22
+ $schema: 'https://raw.githubusercontent.com/anomalyco/kodu/main/kodu.schema.json',
23
+ cleaner: {
24
+ whitelist: ['//!'],
25
+ keepJSDoc: true,
26
+ useGitignore: true,
27
+ ignore: [],
28
+ },
29
+ packer: {
30
+ ignore: [
31
+ 'package-lock.json',
32
+ 'yarn.lock',
33
+ 'pnpm-lock.yaml',
34
+ '.git',
35
+ '.kodu',
36
+ 'node_modules',
37
+ 'dist',
38
+ 'coverage',
39
+ ],
40
+ useGitignore: true,
41
+ contentBasedBinaryDetection: false,
42
+ },
43
+ };
21
44
  let InitCommand = class InitCommand extends nest_commander_1.CommandRunner {
22
45
  ui;
23
46
  constructor(ui) {
@@ -25,9 +48,19 @@ let InitCommand = class InitCommand extends nest_commander_1.CommandRunner {
25
48
  this.ui = ui;
26
49
  }
27
50
  async run() {
51
+ await this.ensureKoduJson();
28
52
  await this.updateGitignore();
29
53
  this.ui.log.success('Done.');
30
54
  }
55
+ async ensureKoduJson() {
56
+ const configPath = node_path_1.default.join(process.cwd(), 'kodu.json');
57
+ if (await this.exists(configPath)) {
58
+ this.ui.log.info('kodu.json already exists');
59
+ return;
60
+ }
61
+ await node_fs_1.promises.writeFile(configPath, `${JSON.stringify(DEFAULT_KODU_JSON, null, 2)}\n`, 'utf8');
62
+ this.ui.log.success('Created kodu.json');
63
+ }
31
64
  async updateGitignore() {
32
65
  const gitignorePath = node_path_1.default.join(process.cwd(), '.gitignore');
33
66
  if (!(await this.exists(gitignorePath))) {
@@ -57,7 +90,7 @@ let InitCommand = class InitCommand extends nest_commander_1.CommandRunner {
57
90
  };
58
91
  exports.InitCommand = InitCommand;
59
92
  exports.InitCommand = InitCommand = __decorate([
60
- (0, nest_commander_1.Command)({ name: 'init', description: 'Add kodu output to .gitignore' }),
93
+ (0, nest_commander_1.Command)({ name: 'init', description: 'Initialize kodu configuration' }),
61
94
  __metadata("design:paramtypes", [ui_service_1.UiService])
62
95
  ], InitCommand);
63
96
  //# sourceMappingURL=init.command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.command.js","sourceRoot":"","sources":["../../../../src/commands/init/init.command.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,qCAAyC;AACzC,0DAA6B;AAC7B,mDAAwD;AACxD,yDAAqD;AAErD,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAGrC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,8BAAa;IACf;IAA7B,YAA6B,EAAa;QACxC,KAAK,EAAE,CAAC;QADmB,OAAE,GAAF,EAAE,CAAW;IAE1C,CAAC;IAED,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,MAAM,aAAa,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,CAAC;QAE7D,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAErC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,eAAe,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,eAAe,wBAAwB,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GACR,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,eAAe,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QAC1E,MAAM,kBAAE,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;QACvD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,eAAe,gBAAgB,CAAC,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,MAAc;QACjC,IAAI,CAAC;YACH,MAAM,kBAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAA;AAzCY,kCAAW;sBAAX,WAAW;IADvB,IAAA,wBAAO,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,+BAA+B,EAAE,CAAC;qCAErC,sBAAS;GAD/B,WAAW,CAyCvB"}
1
+ {"version":3,"file":"init.command.js","sourceRoot":"","sources":["../../../../src/commands/init/init.command.ts"],"names":[],"mappings":"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"}
@@ -25,10 +25,8 @@ let ConfigService = class ConfigService {
25
25
  loadConfig() {
26
26
  const explorer = (0, lilconfig_1.lilconfigSync)('kodu', { searchPlaces: ['kodu.json'] });
27
27
  const result = explorer.search(process.cwd());
28
- if (!result || result.isEmpty || !result.config) {
29
- this.terminate('kodu.json not found. Create it in the project root to configure kodu.');
30
- }
31
- const parsed = config_schema_1.configSchema.safeParse(result.config);
28
+ const rawConfig = result && !result.isEmpty && result.config ? result.config : {};
29
+ const parsed = config_schema_1.configSchema.safeParse(rawConfig);
32
30
  if (!parsed.success) {
33
31
  console.error(picocolors_1.default.red('kodu.json is invalid:'));
34
32
  parsed.error.issues.forEach((issue) => {
@@ -1 +1 @@
1
- {"version":3,"file":"config.service.js","sourceRoot":"","sources":["../../../../src/core/config/config.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,yCAA0C;AAC1C,4DAA4B;AAC5B,mDAAgE;AAGzD,IAAM,aAAa,GAAnB,MAAM,aAAa;IAChB,MAAM,CAAc;IAE5B,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,UAAU;QAChB,MAAM,QAAQ,GAAG,IAAA,yBAAa,EAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAE9C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAChD,IAAI,CAAC,SAAS,CACZ,uEAAuE,CACxE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,4BAAY,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAErD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;gBAC9C,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,2CAA2C,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAEO,SAAS,CAAC,OAAe;QAC/B,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;CACF,CAAA;AAvCY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAuCzB"}
1
+ {"version":3,"file":"config.service.js","sourceRoot":"","sources":["../../../../src/core/config/config.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,yCAA0C;AAC1C,4DAA4B;AAC5B,mDAAgE;AAGzD,IAAM,aAAa,GAAnB,MAAM,aAAa;IAChB,MAAM,CAAc;IAE5B,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEO,UAAU;QAChB,MAAM,QAAQ,GAAG,IAAA,yBAAa,EAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAE9C,MAAM,SAAS,GACb,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAElE,MAAM,MAAM,GAAG,4BAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;gBAC9C,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,2CAA2C,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAEO,SAAS,CAAC,OAAe;QAC/B,OAAO,CAAC,KAAK,CAAC,oBAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;CACF,CAAA;AApCY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAoCzB"}