kodu 2.1.3 → 3.0.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.
Files changed (131) hide show
  1. package/README.md +24 -3
  2. package/bin/kodu.js +23 -0
  3. package/package.json +11 -67
  4. package/scripts/postinstall.js +69 -0
  5. package/AGENTS.md +0 -214
  6. package/__tests__/core/fs/fs.service.test.ts +0 -72
  7. package/__tests__/shared/cleaner/cleaner.service.test.ts +0 -102
  8. package/__tests__/shared/git/git.service.test.ts +0 -84
  9. package/__tests__/shared/tokenizer/tokenizer.service.test.ts +0 -45
  10. package/biome.json +0 -50
  11. package/dist/package.json +0 -96
  12. package/dist/src/app.module.d.ts +0 -2
  13. package/dist/src/app.module.js +0 -36
  14. package/dist/src/app.module.js.map +0 -1
  15. package/dist/src/commands/clean/clean.command.d.ts +0 -37
  16. package/dist/src/commands/clean/clean.command.js +0 -240
  17. package/dist/src/commands/clean/clean.command.js.map +0 -1
  18. package/dist/src/commands/clean/clean.module.d.ts +0 -2
  19. package/dist/src/commands/clean/clean.module.js +0 -26
  20. package/dist/src/commands/clean/clean.module.js.map +0 -1
  21. package/dist/src/commands/init/init.command.d.ts +0 -10
  22. package/dist/src/commands/init/init.command.js +0 -96
  23. package/dist/src/commands/init/init.command.js.map +0 -1
  24. package/dist/src/commands/init/init.module.d.ts +0 -2
  25. package/dist/src/commands/init/init.module.js +0 -22
  26. package/dist/src/commands/init/init.module.js.map +0 -1
  27. package/dist/src/commands/pack/pack.command.d.ts +0 -51
  28. package/dist/src/commands/pack/pack.command.js +0 -355
  29. package/dist/src/commands/pack/pack.command.js.map +0 -1
  30. package/dist/src/commands/pack/pack.module.d.ts +0 -2
  31. package/dist/src/commands/pack/pack.module.js +0 -27
  32. package/dist/src/commands/pack/pack.module.js.map +0 -1
  33. package/dist/src/core/config/config.module.d.ts +0 -2
  34. package/dist/src/core/config/config.module.js +0 -23
  35. package/dist/src/core/config/config.module.js.map +0 -1
  36. package/dist/src/core/config/config.schema.d.ts +0 -19
  37. package/dist/src/core/config/config.schema.js +0 -56
  38. package/dist/src/core/config/config.schema.js.map +0 -1
  39. package/dist/src/core/config/config.service.d.ts +0 -7
  40. package/dist/src/core/config/config.service.js +0 -49
  41. package/dist/src/core/config/config.service.js.map +0 -1
  42. package/dist/src/core/config/prompt.service.d.ts +0 -10
  43. package/dist/src/core/config/prompt.service.js +0 -80
  44. package/dist/src/core/config/prompt.service.js.map +0 -1
  45. package/dist/src/core/file-system/fs.module.d.ts +0 -2
  46. package/dist/src/core/file-system/fs.module.js +0 -21
  47. package/dist/src/core/file-system/fs.module.js.map +0 -1
  48. package/dist/src/core/file-system/fs.service.d.ts +0 -27
  49. package/dist/src/core/file-system/fs.service.js +0 -203
  50. package/dist/src/core/file-system/fs.service.js.map +0 -1
  51. package/dist/src/core/ui/ui.module.d.ts +0 -2
  52. package/dist/src/core/ui/ui.module.js +0 -22
  53. package/dist/src/core/ui/ui.module.js.map +0 -1
  54. package/dist/src/core/ui/ui.service.d.ts +0 -22
  55. package/dist/src/core/ui/ui.service.js +0 -43
  56. package/dist/src/core/ui/ui.service.js.map +0 -1
  57. package/dist/src/main.d.ts +0 -2
  58. package/dist/src/main.js +0 -16
  59. package/dist/src/main.js.map +0 -1
  60. package/dist/src/shared/cleaner/cleaner.service.d.ts +0 -23
  61. package/dist/src/shared/cleaner/cleaner.service.js +0 -223
  62. package/dist/src/shared/cleaner/cleaner.service.js.map +0 -1
  63. package/dist/src/shared/cleaner/cleaner.types.d.ts +0 -21
  64. package/dist/src/shared/cleaner/cleaner.types.js +0 -3
  65. package/dist/src/shared/cleaner/cleaner.types.js.map +0 -1
  66. package/dist/src/shared/constants.d.ts +0 -4
  67. package/dist/src/shared/constants.js +0 -113
  68. package/dist/src/shared/constants.js.map +0 -1
  69. package/dist/src/shared/deps/deps.module.d.ts +0 -2
  70. package/dist/src/shared/deps/deps.module.js +0 -21
  71. package/dist/src/shared/deps/deps.module.js.map +0 -1
  72. package/dist/src/shared/deps/deps.service.d.ts +0 -15
  73. package/dist/src/shared/deps/deps.service.js +0 -114
  74. package/dist/src/shared/deps/deps.service.js.map +0 -1
  75. package/dist/src/shared/git/git.module.d.ts +0 -2
  76. package/dist/src/shared/git/git.module.js +0 -21
  77. package/dist/src/shared/git/git.module.js.map +0 -1
  78. package/dist/src/shared/git/git.service.d.ts +0 -5
  79. package/dist/src/shared/git/git.service.js +0 -56
  80. package/dist/src/shared/git/git.service.js.map +0 -1
  81. package/dist/src/shared/tokenizer/tokenizer.module.d.ts +0 -2
  82. package/dist/src/shared/tokenizer/tokenizer.module.js +0 -21
  83. package/dist/src/shared/tokenizer/tokenizer.module.js.map +0 -1
  84. package/dist/src/shared/tokenizer/tokenizer.service.d.ts +0 -10
  85. package/dist/src/shared/tokenizer/tokenizer.service.js +0 -36
  86. package/dist/src/shared/tokenizer/tokenizer.service.js.map +0 -1
  87. package/dist/tsconfig.build.tsbuildinfo +0 -1
  88. package/docs/todo.md +0 -7
  89. package/knip.json +0 -10
  90. package/kodu.json +0 -63
  91. package/kodu.schema.json +0 -100
  92. package/lefthook.yml +0 -11
  93. package/nest-cli.json +0 -8
  94. package/scripts/generate-json-schema.ts +0 -18
  95. package/skills/doc-gen/SKILL.md +0 -490
  96. package/skills/doc-gen/scripts/doc_gen.py +0 -911
  97. package/skills/implement-project/SKILL.md +0 -409
  98. package/skills/liteend-init/SKILL.md +0 -84
  99. package/skills/litefront-init/SKILL.md +0 -96
  100. package/skills/litefront-prototype/SKILL.md +0 -484
  101. package/skills/project-setup-standardizer/SKILL.md +0 -285
  102. package/skills/start/SKILL.md +0 -319
  103. package/skills/tech-blueprint/SKILL.md +0 -890
  104. package/skills/tech-blueprint/scripts/blueprint_validator.py +0 -417
  105. package/src/app.module.ts +0 -23
  106. package/src/commands/clean/clean.command.ts +0 -235
  107. package/src/commands/clean/clean.module.ts +0 -13
  108. package/src/commands/init/init.command.ts +0 -92
  109. package/src/commands/init/init.module.ts +0 -9
  110. package/src/commands/pack/pack.command.ts +0 -347
  111. package/src/commands/pack/pack.module.ts +0 -14
  112. package/src/core/config/config.module.ts +0 -10
  113. package/src/core/config/config.schema.ts +0 -58
  114. package/src/core/config/config.service.ts +0 -43
  115. package/src/core/config/prompt.service.ts +0 -80
  116. package/src/core/file-system/fs.module.ts +0 -8
  117. package/src/core/file-system/fs.service.ts +0 -248
  118. package/src/core/ui/ui.module.ts +0 -9
  119. package/src/core/ui/ui.service.ts +0 -39
  120. package/src/main.ts +0 -12
  121. package/src/shared/cleaner/cleaner.service.ts +0 -289
  122. package/src/shared/cleaner/cleaner.types.ts +0 -23
  123. package/src/shared/constants.ts +0 -118
  124. package/src/shared/deps/deps.module.ts +0 -8
  125. package/src/shared/deps/deps.service.ts +0 -175
  126. package/src/shared/git/git.module.ts +0 -8
  127. package/src/shared/git/git.service.ts +0 -47
  128. package/src/shared/tokenizer/tokenizer.module.ts +0 -8
  129. package/src/shared/tokenizer/tokenizer.service.ts +0 -30
  130. package/tsconfig.build.json +0 -7
  131. package/tsconfig.json +0 -28
package/README.md CHANGED
@@ -23,14 +23,32 @@
23
23
 
24
24
  ## Install
25
25
 
26
+ Kodu is a single native binary (written in Go). Pick any channel:
27
+
26
28
  ```bash
29
+ # npm (downloads the prebuilt binary for your platform on install)
27
30
  npm install -g kodu
31
+
32
+ # Go toolchain
33
+ go install github.com/uxname/kodu/cmd/kodu@latest
34
+
35
+ # Prebuilt binaries (linux/macOS/windows × amd64/arm64)
36
+ # https://github.com/uxname/kodu/releases
28
37
  ```
29
38
 
30
- Or run without installing:
39
+ > The npm package ships a thin launcher whose `postinstall` fetches the matching
40
+ > binary from GitHub Releases. If the download fails (offline, proxy), it prints
41
+ > a hint to use `go install` instead — `npm install` itself never breaks.
42
+
43
+ ### Build from source
44
+
45
+ Requires Go 1.25+ and a C toolchain (CGO is used for the tree-sitter parsers).
31
46
 
32
47
  ```bash
33
- npx kodu pack --copy
48
+ git clone https://github.com/uxname/kodu.git && cd kodu
49
+ make build # → dist/kodu
50
+ make test # run the test suite
51
+ make lint # gofmt + go vet + golangci-lint
34
52
  ```
35
53
 
36
54
  ---
@@ -101,7 +119,10 @@ src/core/config/config.service.ts ← import from src/core/config/config.module
101
119
  src/shared/constants.ts ← import from src/core/file-system/fs.service.ts
102
120
  ```
103
121
 
104
- `--deps` uses `ts-morph` to resolve the TypeScript import graph, so it correctly handles tsconfig path aliases, re-exports, index files, and type-only imports. `node_modules` are excluded automatically.
122
+ `--deps` resolves the TypeScript/JavaScript import graph (relative imports, file
123
+ extensions, index files, `tsconfig` path aliases, re-exports, and type-only
124
+ imports), excluding `node_modules`. Resolution is best-effort and does not cover
125
+ exotic cases like package.json `exports` maps.
105
126
 
106
127
  ### Output format
107
128
 
package/bin/kodu.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ // Thin launcher: runs the native kodu binary downloaded by postinstall.
3
+ 'use strict';
4
+
5
+ const path = require('node:path');
6
+ const fs = require('node:fs');
7
+ const { spawnSync } = require('node:child_process');
8
+
9
+ const binName = process.platform === 'win32' ? 'kodu.exe' : 'kodu';
10
+ const binPath = path.join(__dirname, binName);
11
+
12
+ if (!fs.existsSync(binPath)) {
13
+ console.error('[kodu] Native binary not found. Reinstall the package or build it from source:');
14
+ console.error('[kodu] go install github.com/uxname/kodu/cmd/kodu@latest');
15
+ process.exit(1);
16
+ }
17
+
18
+ const res = spawnSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
19
+ if (res.error) {
20
+ console.error(`[kodu] ${res.error.message}`);
21
+ process.exit(1);
22
+ }
23
+ process.exit(res.status ?? 0);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kodu",
3
- "version": "2.1.3",
4
- "description": "High-performance CLI to prepare codebase for LLMs, automate reviews, and draft commits.",
3
+ "version": "3.0.1",
4
+ "description": "High-performance CLI to prepare a codebase for LLMs, automate reviews, and draft commits. Native Go binary.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/uxname/kodu.git"
@@ -16,81 +16,25 @@
16
16
  "llm",
17
17
  "developer-tools",
18
18
  "productivity",
19
- "typescript",
19
+ "golang",
20
20
  "openai",
21
21
  "automation",
22
22
  "code-review",
23
23
  "context-window",
24
24
  "git-tools"
25
25
  ],
26
- "private": false,
27
26
  "license": "MIT",
28
27
  "bin": {
29
- "kodu": "dist/src/main.js"
28
+ "kodu": "bin/kodu.js"
30
29
  },
30
+ "files": [
31
+ "bin/kodu.js",
32
+ "scripts/postinstall.js"
33
+ ],
31
34
  "scripts": {
32
- "________________ BUILD AND RUN ________________": "",
33
- "build": "nest build && chmod +x dist/src/main.js",
34
- "generate:schema": "ts-node scripts/generate-json-schema.ts",
35
- "postbuild": "npm run generate:schema",
36
- "start:prod": "node dist/main.js",
37
- "start:dev": "nest start --watch",
38
- "new:command": "nest g -c nest-commander-schematics command",
39
- "new:question": "nest g -c nest-commander-schematics question",
40
- "________________ FORMAT AND LINT ________________": "",
41
- "lint": "biome check",
42
- "lint:fix": "biome check --write",
43
- "lint:fix:unsafe": "biome check --write --unsafe",
44
- "ts:check": "tsc --noEmit",
45
- "knip": "knip --production",
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",
51
- "________________ OTHER ________________": "",
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"
55
- },
56
- "dependencies": {
57
- "@inquirer/confirm": "^6.0.4",
58
- "@inquirer/input": "^5.0.4",
59
- "@inquirer/select": "^5.0.4",
60
- "@nestjs/common": "^11.0.1",
61
- "@nestjs/core": "^11.0.1",
62
- "clipboardy": "^5.0.2",
63
- "execa": "^9.6.1",
64
- "ignore": "^7.0.5",
65
- "js-tiktoken": "^1.0.21",
66
- "lilconfig": "^3.1.3",
67
- "nest-commander": "^3.20.1",
68
- "picocolors": "^1.1.1",
69
- "reflect-metadata": "^0.2.2",
70
- "rxjs": "^7.8.1",
71
- "source-map-support": "^0.5.21",
72
- "tinyglobby": "^0.2.15",
73
- "ts-morph": "^24.0.0",
74
- "yocto-spinner": "^1.0.0",
75
- "zod": "^4.3.6"
35
+ "postinstall": "node scripts/postinstall.js"
76
36
  },
77
- "devDependencies": {
78
- "@biomejs/biome": "^2.3.12",
79
- "@nestjs/cli": "^11.0.0",
80
- "@nestjs/schematics": "^11.0.0",
81
- "@nestjs/testing": "^11.0.1",
82
- "@types/node": "^22.10.7",
83
- "is-ci": "^4.1.0",
84
- "knip": "^5.82.1",
85
- "lefthook": "^2.0.15",
86
- "nest-commander-schematics": "^3.2.0",
87
- "npm-check-updates": "^18.3.1",
88
- "npm-run-all": "^4.1.5",
89
- "rimraf": "^6.1.3",
90
- "ts-loader": "^9.5.2",
91
- "ts-node": "^10.9.2",
92
- "tsconfig-paths": "^4.2.0",
93
- "typescript": "^5.7.3",
94
- "vitest": "^3.2.4"
37
+ "engines": {
38
+ "node": ">=18"
95
39
  }
96
40
  }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ // Downloads the native kodu binary for the current platform from GitHub Releases.
3
+ // On failure it does not break the install — it prints a hint (graceful degradation).
4
+ 'use strict';
5
+
6
+ const fs = require('node:fs');
7
+ const path = require('node:path');
8
+ const https = require('node:https');
9
+ const { execFileSync } = require('node:child_process');
10
+
11
+ const REPO = 'uxname/kodu';
12
+ const pkg = require('../package.json');
13
+
14
+ const PLATFORMS = { linux: 'linux', darwin: 'darwin', win32: 'windows' };
15
+ const ARCHES = { x64: 'amd64', arm64: 'arm64' };
16
+
17
+ function fail(msg) {
18
+ console.warn(`\n[kodu] ${msg}`);
19
+ console.warn('[kodu] Install manually: go install github.com/uxname/kodu/cmd/kodu@latest');
20
+ console.warn(`[kodu] or download the binary: https://github.com/${REPO}/releases\n`);
21
+ process.exit(0); // do not block npm install
22
+ }
23
+
24
+ const goos = PLATFORMS[process.platform];
25
+ const goarch = ARCHES[process.arch];
26
+ if (!goos || !goarch) fail(`Platform ${process.platform}/${process.arch} is not supported by a prebuilt binary.`);
27
+
28
+ const ext = goos === 'windows' ? 'zip' : 'tar.gz';
29
+ const binName = goos === 'windows' ? 'kodu.exe' : 'kodu';
30
+ const asset = `kodu_v${pkg.version}_${goos}_${goarch}.${ext}`;
31
+ const url = `https://github.com/${REPO}/releases/download/v${pkg.version}/${asset}`;
32
+ const binDir = path.join(__dirname, '..', 'bin');
33
+
34
+ function download(u, dest, redirects = 0) {
35
+ return new Promise((resolve, reject) => {
36
+ if (redirects > 5) return reject(new Error('too many redirects'));
37
+ https.get(u, (res) => {
38
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
39
+ res.resume();
40
+ return resolve(download(res.headers.location, dest, redirects + 1));
41
+ }
42
+ if (res.statusCode !== 200) {
43
+ res.resume();
44
+ return reject(new Error(`HTTP ${res.statusCode} for ${u}`));
45
+ }
46
+ const file = fs.createWriteStream(dest);
47
+ res.pipe(file);
48
+ file.on('finish', () => file.close(resolve));
49
+ file.on('error', reject);
50
+ }).on('error', reject);
51
+ });
52
+ }
53
+
54
+ (async () => {
55
+ try {
56
+ fs.mkdirSync(binDir, { recursive: true });
57
+ const archivePath = path.join(binDir, asset);
58
+ await download(url, archivePath);
59
+ // bsdtar (tar) extracts both .tar.gz and .zip on Linux/macOS/Win10+.
60
+ execFileSync('tar', ['-xf', archivePath, '-C', binDir], { stdio: 'ignore' });
61
+ fs.rmSync(archivePath, { force: true });
62
+ const binPath = path.join(binDir, binName);
63
+ if (!fs.existsSync(binPath)) throw new Error('binary not found after extraction');
64
+ if (goos !== 'windows') fs.chmodSync(binPath, 0o755);
65
+ console.log(`[kodu] Installed binary ${goos}/${goarch} v${pkg.version}`);
66
+ } catch (err) {
67
+ fail(`Failed to download the binary: ${err.message}`);
68
+ }
69
+ })();
package/AGENTS.md DELETED
@@ -1,214 +0,0 @@
1
- # AGENTS.md
2
-
3
- This file provides guidelines and instructions for AI assistants working on the Kodu project.
4
-
5
- ## 1. Project Overview
6
-
7
- **Kodu** is a high-performance CLI utility that bridges local development environments with LLMs. It automates context preparation and code cleaning.
8
-
9
- - **Key Goals:** Speed (<0.5s startup), Determinism (no AI for critical file ops), DX (Developer Experience)
10
- - **Available Commands:** `pack`, `clean`
11
-
12
- ## 2. Technology Stack (Enforced)
13
-
14
- | Category | USE | DO NOT USE |
15
- |----------|-----|------------|
16
- | Framework | NestJS + nest-commander | Pure Node.js, Oclif |
17
- | File System | node:fs/promises + tinyglobby | fs-extra, glob, rimraf |
18
- | Config | lilconfig | cosmiconfig, rc |
19
- | Validation | zod | class-validator, joi |
20
- | CLI UI | @inquirer/prompts + picocolors | inquirer (legacy), chalk |
21
- | Spinners | yocto-spinner | ora, cli-spinners |
22
- | AST/Parsing | ts-morph | Regex, babel |
23
- | Tokens | js-tiktoken | gpt-3-encoder |
24
- | Clipboard | clipboardy | Native APIs |
25
-
26
- ## 3. Architecture
27
-
28
- ```
29
- src/
30
- ├── app.module.ts # Root Orchestrator
31
- ├── main.ts # Entry Point
32
- ├── core/ # Global Infrastructure
33
- │ ├── config/ # ConfigModule (Zod + lilconfig)
34
- │ ├── file-system/ # FsModule (tinyglobby)
35
- │ └── ui/ # UiModule (spinners, loggers)
36
- ├── shared/ # Shared Business Logic
37
- │ ├── tokenizer/ # TokenizerModule
38
- │ ├── git/ # GitModule
39
- │ └── cleaner/ # CleanerService (AST)
40
- └── commands/ # Feature Commands
41
- ├── pack/ # kodu pack
42
- └── clean/ # kodu clean
43
- ```
44
-
45
- ## 4. Build, Lint & Test Commands
46
-
47
- ### Essential Commands
48
- ```bash
49
- # Build the project
50
- npm run build # Full build (Nest build) + make executable
51
-
52
- # Run the built artifact
53
- npm run start:prod # Run from dist/
54
-
55
- # Type check
56
- npm run ts:check # TypeScript compilation check
57
-
58
- # Lint and format
59
- npm run lint # Run Biome linter
60
- npm run lint:fix # Biome with auto-fix
61
-
62
- # Full check (required before commit)
63
- npm run check # TypeCheck + Biome + Knip
64
- ```
65
-
66
- ## 5. Code Style Guidelines
67
-
68
- ### General
69
- - **ESM Only:** Use `import` statements (nodenext mode)
70
- - **Strict Mode:** `strictNullChecks` is ON. Avoid `any`; use `unknown` with narrowing
71
- - **Quotes:** Single quotes preferred
72
- - **Indentation:** 2 spaces
73
- - **No Comments:** Unless explicitly requested by user
74
-
75
- ### Imports
76
- - Use explicit relative imports: `import { Foo } from './foo'`
77
- - Avoid barrel exports (`index.ts`) unless necessary
78
- - No circular dependencies (NestJS module structure enforces this)
79
-
80
- ### Types
81
- - Prefer explicit types over `any`
82
- - Use `unknown` and narrow with type guards or Zod validation
83
- - Interface over type for object shapes
84
- - Use readonly for immutable data
85
-
86
- ### Naming Conventions
87
- - **Files:** kebab-case (`my-file.ts`)
88
- - **Classes:** PascalCase (`MyClass`)
89
- - **Functions:** camelCase (`myFunction`)
90
- - **Constants:** UPPER_SNAKE_CASE for compile-time constants
91
- - **Interfaces:** PascalCase, no `I` prefix (`User` not `IUser`)
92
-
93
- ### Error Handling
94
- - Use custom error classes extending `Error`
95
- - Never swallow errors silently
96
- - Provide meaningful error messages
97
- - Use try/catch with specific error types
98
- - Validate inputs with Zod schemas
99
-
100
- ### NestJS Specifics
101
- - All commands extend `CommandRunner` from `nest-commander`
102
- - Use Dependency Injection - never import services directly
103
- - Register modules in `app.module.ts`
104
- - Use `@Injectable()` decorator for services
105
-
106
- ## 6. Configuration (kodu.json)
107
-
108
- ```json
109
- {
110
- "cleaner": {
111
- "whitelist": ["//!"],
112
- "keepJSDoc": true,
113
- "useGitignore": true
114
- },
115
- "packer": {
116
- "ignore": ["*.lock", "node_modules", "dist"],
117
- "useGitignore": true
118
- }
119
- }
120
- ```
121
-
122
- - Config validated via Zod on startup
123
- - `kodu.json` must be in current working directory
124
-
125
- ## 7. Commands Reference
126
-
127
- ### `kodu init`
128
-
129
- Add `.kodu/context.txt` to `.gitignore` (if `.gitignore` exists). Run once after cloning or setting up a project.
130
-
131
- ### `kodu pack`
132
-
133
- Bundle project files into a single context file for LLMs.
134
-
135
- | Option | Description |
136
- |--------|-------------|
137
- | `-c, --copy` | Copy result to clipboard |
138
- | `-o, --out <path>` | Path to save result (default: `.kodu/context.txt`) |
139
- | `-p, --path <path>` | Directory or glob to include (repeatable) |
140
- | `-e, --exclude <pattern>` | Additional exclude pattern (repeatable) |
141
- | `-l, --list` | Print file list only, without content |
142
- | `-f, --format <format>` | Output format: `xml` (default) or `text` |
143
- | `-t, --template <name>` | Template name from `.kodu/prompts` |
144
-
145
- Output format `xml` wraps each file in `<file path="...">` tags — recommended for LLM consumption. Format `text` uses `// file: ...` header comments.
146
-
147
- ### `kodu clean`
148
-
149
- Remove comments from source files using AST-based parsing (deterministic, no AI).
150
-
151
- | Option | Description |
152
- |--------|-------------|
153
- | `-d, --dry-run` | Show what will be removed without modifying files |
154
- | `-c, --changed` | Clean only git-changed files |
155
-
156
- ## 8. Critical Constraints
157
-
158
- 1. **No AI:** Both commands are deterministic — no AI integration
159
- 2. **Validation First:** Invalid `kodu.json` causes graceful crash with Zod error
160
- 3. **Performance:** Mindful of import costs. Use lightweight libraries
161
- 4. **Config Location:** `kodu.json` must be in current working directory
162
-
163
- ## 9. Development Workflow
164
-
165
- ### Adding a New Command
166
- 1. Create `src/commands/<name>/`
167
- 2. Create `<name>.command.ts` and `<name>.module.ts`
168
- 3. Implement `run()` extending `CommandRunner`
169
- 4. Decorate with `@Command()` from `nest-commander`
170
- 5. Register module in `app.module.ts`
171
- 6. Test: `npm run build && node dist/src/main.js <name>`
172
-
173
- ### Before Commit
174
- Always run:
175
- ```bash
176
- npm run check
177
- ```
178
-
179
- This executes: TypeScript check + Biome lint + Knip dead code detection.
180
-
181
- ## 10. Testing Strategy
182
-
183
- - **Primary Gate:** Static analysis (TypeScript + Biome + Knip)
184
- - **No Legacy Tests:** Project relies on strict static typing
185
- - If tests exist: place in `__tests__/` or `*.test.ts` files
186
-
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
210
-
211
- - Unclear requirements? Ask the user first
212
- - Library not in Tech Stack section? Prefer native Node.js APIs
213
- - New dependency? Ensure it follows "Fresh & Modern" strategy
214
- - Breaking changes? Create an OpenSpec proposal
@@ -1,72 +0,0 @@
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
- });
@@ -1,102 +0,0 @@
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
- });