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.
- package/AGENTS.md +23 -1
- package/__tests__/core/fs/fs.service.test.ts +72 -0
- package/__tests__/shared/cleaner/cleaner.service.test.ts +102 -0
- package/__tests__/shared/git/git.service.test.ts +84 -0
- package/__tests__/shared/tokenizer/tokenizer.service.test.ts +45 -0
- package/dist/package.json +14 -3
- package/dist/src/commands/init/init.command.d.ts +1 -0
- package/dist/src/commands/init/init.command.js +34 -1
- package/dist/src/commands/init/init.command.js.map +1 -1
- package/dist/src/core/config/config.service.js +2 -4
- package/dist/src/core/config/config.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/lefthook.yml +9 -2
- package/package.json +14 -3
- package/skills/doc-gen/SKILL.md +490 -0
- package/skills/doc-gen/scripts/doc_gen.py +911 -0
- package/skills/implement-project/SKILL.md +409 -0
- package/skills/liteend-init/SKILL.md +84 -0
- package/skills/litefront-init/SKILL.md +96 -0
- package/skills/litefront-prototype/SKILL.md +484 -0
- package/skills/project-setup-standardizer/SKILL.md +285 -0
- package/skills/start/SKILL.md +319 -0
- package/skills/tech-blueprint/SKILL.md +890 -0
- package/skills/tech-blueprint/scripts/blueprint_validator.py +417 -0
- package/src/commands/init/init.command.ts +43 -1
- package/src/core/config/config.service.ts +3 -6
- package/tsconfig.build.json +3 -0
- package/tsconfig.json +5 -2
- package/dist/scripts/generate-json-schema.d.ts +0 -1
- package/dist/scripts/generate-json-schema.js +0 -17
- package/dist/scripts/generate-json-schema.js.map +0 -1
- 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.
|
|
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.
|
|
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
|
}
|
|
@@ -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: '
|
|
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;
|
|
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
|
-
|
|
29
|
-
|
|
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,
|
|
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"}
|