kodu 2.2.0 → 3.0.2
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/README.md +24 -3
- package/bin/kodu.js +40 -0
- package/package.json +12 -67
- package/scripts/install.js +68 -0
- package/scripts/postinstall.js +22 -0
- package/AGENTS.md +0 -214
- package/__tests__/core/fs/fs.service.test.ts +0 -72
- package/__tests__/core/registry/registry.service.test.ts +0 -82
- package/__tests__/shared/cleaner/cleaner.service.test.ts +0 -102
- package/__tests__/shared/git/git.service.test.ts +0 -84
- package/__tests__/shared/runbook/runbook.service.test.ts +0 -104
- package/__tests__/shared/tokenizer/tokenizer.service.test.ts +0 -45
- package/biome.json +0 -50
- package/dist/package.json +0 -96
- package/dist/src/app.module.d.ts +0 -2
- package/dist/src/app.module.js +0 -42
- package/dist/src/app.module.js.map +0 -1
- package/dist/src/commands/clean/clean.command.d.ts +0 -37
- package/dist/src/commands/clean/clean.command.js +0 -240
- package/dist/src/commands/clean/clean.command.js.map +0 -1
- package/dist/src/commands/clean/clean.module.d.ts +0 -2
- package/dist/src/commands/clean/clean.module.js +0 -26
- package/dist/src/commands/clean/clean.module.js.map +0 -1
- package/dist/src/commands/init/init.command.d.ts +0 -10
- package/dist/src/commands/init/init.command.js +0 -96
- package/dist/src/commands/init/init.command.js.map +0 -1
- package/dist/src/commands/init/init.module.d.ts +0 -2
- package/dist/src/commands/init/init.module.js +0 -22
- package/dist/src/commands/init/init.module.js.map +0 -1
- package/dist/src/commands/ops/ops-add.command.d.ts +0 -18
- package/dist/src/commands/ops/ops-add.command.js +0 -102
- package/dist/src/commands/ops/ops-add.command.js.map +0 -1
- package/dist/src/commands/ops/ops-init.command.d.ts +0 -22
- package/dist/src/commands/ops/ops-init.command.js +0 -130
- package/dist/src/commands/ops/ops-init.command.js.map +0 -1
- package/dist/src/commands/ops/ops-list.command.d.ts +0 -12
- package/dist/src/commands/ops/ops-list.command.js +0 -73
- package/dist/src/commands/ops/ops-list.command.js.map +0 -1
- package/dist/src/commands/ops/ops-path.command.d.ts +0 -9
- package/dist/src/commands/ops/ops-path.command.js +0 -52
- package/dist/src/commands/ops/ops-path.command.js.map +0 -1
- package/dist/src/commands/ops/ops-runbook.command.d.ts +0 -12
- package/dist/src/commands/ops/ops-runbook.command.js +0 -81
- package/dist/src/commands/ops/ops-runbook.command.js.map +0 -1
- package/dist/src/commands/ops/ops-status.command.d.ts +0 -11
- package/dist/src/commands/ops/ops-status.command.js +0 -62
- package/dist/src/commands/ops/ops-status.command.js.map +0 -1
- package/dist/src/commands/ops/ops-use.command.d.ts +0 -12
- package/dist/src/commands/ops/ops-use.command.js +0 -76
- package/dist/src/commands/ops/ops-use.command.js.map +0 -1
- package/dist/src/commands/ops/ops.command.d.ts +0 -7
- package/dist/src/commands/ops/ops.command.js +0 -56
- package/dist/src/commands/ops/ops.command.js.map +0 -1
- package/dist/src/commands/ops/ops.helpers.d.ts +0 -2
- package/dist/src/commands/ops/ops.helpers.js +0 -11
- package/dist/src/commands/ops/ops.helpers.js.map +0 -1
- package/dist/src/commands/ops/ops.module.d.ts +0 -2
- package/dist/src/commands/ops/ops.module.js +0 -36
- package/dist/src/commands/ops/ops.module.js.map +0 -1
- package/dist/src/commands/pack/pack.command.d.ts +0 -51
- package/dist/src/commands/pack/pack.command.js +0 -355
- package/dist/src/commands/pack/pack.command.js.map +0 -1
- package/dist/src/commands/pack/pack.module.d.ts +0 -2
- package/dist/src/commands/pack/pack.module.js +0 -27
- package/dist/src/commands/pack/pack.module.js.map +0 -1
- package/dist/src/core/config/config.module.d.ts +0 -2
- package/dist/src/core/config/config.module.js +0 -23
- package/dist/src/core/config/config.module.js.map +0 -1
- package/dist/src/core/config/config.schema.d.ts +0 -19
- package/dist/src/core/config/config.schema.js +0 -56
- package/dist/src/core/config/config.schema.js.map +0 -1
- package/dist/src/core/config/config.service.d.ts +0 -7
- package/dist/src/core/config/config.service.js +0 -49
- package/dist/src/core/config/config.service.js.map +0 -1
- package/dist/src/core/config/prompt.service.d.ts +0 -10
- package/dist/src/core/config/prompt.service.js +0 -80
- package/dist/src/core/config/prompt.service.js.map +0 -1
- package/dist/src/core/file-system/fs.module.d.ts +0 -2
- package/dist/src/core/file-system/fs.module.js +0 -21
- package/dist/src/core/file-system/fs.module.js.map +0 -1
- package/dist/src/core/file-system/fs.service.d.ts +0 -27
- package/dist/src/core/file-system/fs.service.js +0 -203
- package/dist/src/core/file-system/fs.service.js.map +0 -1
- package/dist/src/core/registry/registry.module.d.ts +0 -2
- package/dist/src/core/registry/registry.module.js +0 -22
- package/dist/src/core/registry/registry.module.js.map +0 -1
- package/dist/src/core/registry/registry.schema.d.ts +0 -24
- package/dist/src/core/registry/registry.schema.js +0 -21
- package/dist/src/core/registry/registry.schema.js.map +0 -1
- package/dist/src/core/registry/registry.service.d.ts +0 -16
- package/dist/src/core/registry/registry.service.js +0 -91
- package/dist/src/core/registry/registry.service.js.map +0 -1
- package/dist/src/core/ui/ui.module.d.ts +0 -2
- package/dist/src/core/ui/ui.module.js +0 -22
- package/dist/src/core/ui/ui.module.js.map +0 -1
- package/dist/src/core/ui/ui.service.d.ts +0 -22
- package/dist/src/core/ui/ui.service.js +0 -43
- package/dist/src/core/ui/ui.service.js.map +0 -1
- package/dist/src/main.d.ts +0 -2
- package/dist/src/main.js +0 -16
- package/dist/src/main.js.map +0 -1
- package/dist/src/shared/cleaner/cleaner.service.d.ts +0 -23
- package/dist/src/shared/cleaner/cleaner.service.js +0 -223
- package/dist/src/shared/cleaner/cleaner.service.js.map +0 -1
- package/dist/src/shared/cleaner/cleaner.types.d.ts +0 -21
- package/dist/src/shared/cleaner/cleaner.types.js +0 -3
- package/dist/src/shared/cleaner/cleaner.types.js.map +0 -1
- package/dist/src/shared/constants.d.ts +0 -4
- package/dist/src/shared/constants.js +0 -113
- package/dist/src/shared/constants.js.map +0 -1
- package/dist/src/shared/deps/deps.module.d.ts +0 -2
- package/dist/src/shared/deps/deps.module.js +0 -21
- package/dist/src/shared/deps/deps.module.js.map +0 -1
- package/dist/src/shared/deps/deps.service.d.ts +0 -15
- package/dist/src/shared/deps/deps.service.js +0 -114
- package/dist/src/shared/deps/deps.service.js.map +0 -1
- package/dist/src/shared/git/git.module.d.ts +0 -2
- package/dist/src/shared/git/git.module.js +0 -21
- package/dist/src/shared/git/git.module.js.map +0 -1
- package/dist/src/shared/git/git.service.d.ts +0 -5
- package/dist/src/shared/git/git.service.js +0 -56
- package/dist/src/shared/git/git.service.js.map +0 -1
- package/dist/src/shared/runbook/runbook.module.d.ts +0 -2
- package/dist/src/shared/runbook/runbook.module.js +0 -22
- package/dist/src/shared/runbook/runbook.module.js.map +0 -1
- package/dist/src/shared/runbook/runbook.service.d.ts +0 -20
- package/dist/src/shared/runbook/runbook.service.js +0 -118
- package/dist/src/shared/runbook/runbook.service.js.map +0 -1
- package/dist/src/shared/runbook/runbook.templates.d.ts +0 -6
- package/dist/src/shared/runbook/runbook.templates.js +0 -49
- package/dist/src/shared/runbook/runbook.templates.js.map +0 -1
- package/dist/src/shared/tokenizer/tokenizer.module.d.ts +0 -2
- package/dist/src/shared/tokenizer/tokenizer.module.js +0 -21
- package/dist/src/shared/tokenizer/tokenizer.module.js.map +0 -1
- package/dist/src/shared/tokenizer/tokenizer.service.d.ts +0 -10
- package/dist/src/shared/tokenizer/tokenizer.service.js +0 -36
- package/dist/src/shared/tokenizer/tokenizer.service.js.map +0 -1
- package/dist/tsconfig.build.tsbuildinfo +0 -1
- package/docs/todo.md +0 -7
- package/knip.json +0 -10
- package/kodu.json +0 -63
- package/kodu.schema.json +0 -100
- package/lefthook.yml +0 -11
- package/nest-cli.json +0 -8
- package/registry.schema.json +0 -39
- package/scripts/generate-json-schema.ts +0 -27
- package/skills/ac/SKILL.md +0 -239
- package/skills/al/SKILL.md +0 -98
- package/skills/audit/SKILL.md +0 -205
- package/skills/audit/audit-baseline-template.yml +0 -188
- package/skills/audit/runtime-detect.md +0 -64
- package/skills/audit/stacks/_generic.md +0 -41
- package/skills/audit/stacks/_registry.md +0 -47
- package/skills/audit/stacks/go.md +0 -66
- package/skills/audit/stacks/java.md +0 -44
- package/skills/audit/stacks/node.md +0 -57
- package/skills/audit/stacks/python.md +0 -45
- package/skills/audit/stacks/rust.md +0 -44
- package/skills/audit-api-contracts/SKILL.md +0 -201
- package/skills/audit-architecture/SKILL.md +0 -200
- package/skills/audit-bugs/SKILL.md +0 -226
- package/skills/audit-concurrency/SKILL.md +0 -197
- package/skills/audit-deployment/SKILL.md +0 -218
- package/skills/audit-docs/SKILL.md +0 -209
- package/skills/audit-errors/SKILL.md +0 -216
- package/skills/audit-logging/SKILL.md +0 -197
- package/skills/audit-matrix/SKILL.md +0 -245
- package/skills/audit-meta/SKILL.md +0 -120
- package/skills/audit-naming/SKILL.md +0 -200
- package/skills/audit-owasp/SKILL.md +0 -223
- package/skills/audit-performance/SKILL.md +0 -199
- package/skills/audit-reinvention/SKILL.md +0 -214
- package/skills/audit-secrets/SKILL.md +0 -198
- package/skills/audit-tests/SKILL.md +0 -210
- package/skills/audit-validation/SKILL.md +0 -206
- package/skills/audit-verify/SKILL.md +0 -139
- package/skills/audit-yagni/SKILL.md +0 -188
- package/skills/doc-gen/SKILL.md +0 -490
- package/skills/doc-gen/scripts/doc_gen.py +0 -911
- package/skills/generate-project-docs/SKILL.md +0 -380
- package/skills/implement-project/SKILL.md +0 -409
- package/skills/liteend-init/SKILL.md +0 -84
- package/skills/litefront-init/SKILL.md +0 -96
- package/skills/litefront-prototype/SKILL.md +0 -484
- package/skills/ops/SKILL.md +0 -94
- package/skills/post-call-task-builder/SKILL.md +0 -419
- package/skills/project-setup-standardizer/SKILL.md +0 -285
- package/skills/skills-best-practices/SKILL.md +0 -415
- package/skills/start/SKILL.md +0 -319
- package/skills/tech-blueprint/SKILL.md +0 -890
- package/skills/tech-blueprint/scripts/blueprint_validator.py +0 -417
- package/src/app.module.ts +0 -29
- package/src/commands/clean/clean.command.ts +0 -235
- package/src/commands/clean/clean.module.ts +0 -13
- package/src/commands/init/init.command.ts +0 -92
- package/src/commands/init/init.module.ts +0 -9
- package/src/commands/ops/ops-add.command.ts +0 -83
- package/src/commands/ops/ops-init.command.ts +0 -125
- package/src/commands/ops/ops-list.command.ts +0 -57
- package/src/commands/ops/ops-path.command.ts +0 -38
- package/src/commands/ops/ops-runbook.command.ts +0 -74
- package/src/commands/ops/ops-status.command.ts +0 -47
- package/src/commands/ops/ops-use.command.ts +0 -76
- package/src/commands/ops/ops.command.ts +0 -42
- package/src/commands/ops/ops.helpers.ts +0 -20
- package/src/commands/ops/ops.module.ts +0 -23
- package/src/commands/pack/pack.command.ts +0 -347
- package/src/commands/pack/pack.module.ts +0 -14
- package/src/core/config/config.module.ts +0 -10
- package/src/core/config/config.schema.ts +0 -58
- package/src/core/config/config.service.ts +0 -43
- package/src/core/config/prompt.service.ts +0 -80
- package/src/core/file-system/fs.module.ts +0 -8
- package/src/core/file-system/fs.service.ts +0 -248
- package/src/core/registry/registry.module.ts +0 -9
- package/src/core/registry/registry.schema.ts +0 -46
- package/src/core/registry/registry.service.ts +0 -128
- package/src/core/ui/ui.module.ts +0 -9
- package/src/core/ui/ui.service.ts +0 -39
- package/src/main.ts +0 -12
- package/src/shared/cleaner/cleaner.service.ts +0 -289
- package/src/shared/cleaner/cleaner.types.ts +0 -23
- package/src/shared/constants.ts +0 -118
- package/src/shared/deps/deps.module.ts +0 -8
- package/src/shared/deps/deps.service.ts +0 -175
- package/src/shared/git/git.module.ts +0 -8
- package/src/shared/git/git.service.ts +0 -47
- package/src/shared/runbook/runbook.module.ts +0 -9
- package/src/shared/runbook/runbook.service.ts +0 -164
- package/src/shared/runbook/runbook.templates.ts +0 -66
- package/src/shared/tokenizer/tokenizer.module.ts +0 -8
- package/src/shared/tokenizer/tokenizer.service.ts +0 -30
- package/tsconfig.build.json +0 -7
- 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
|
-
|
|
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
|
-
|
|
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`
|
|
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,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin launcher: runs the native kodu binary downloaded by postinstall.
|
|
3
|
+
// If the binary is missing (the package manager skipped the postinstall hook —
|
|
4
|
+
// bun does this by default, or `npm i --ignore-scripts` — or the download failed),
|
|
5
|
+
// it is fetched lazily from GitHub Releases on first run.
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const fs = require('node:fs');
|
|
10
|
+
const { spawnSync } = require('node:child_process');
|
|
11
|
+
const { install, binNameFor, REPO } = require('../scripts/install');
|
|
12
|
+
|
|
13
|
+
const goos = process.platform === 'win32' ? 'windows' : process.platform;
|
|
14
|
+
const binName = binNameFor(goos);
|
|
15
|
+
const binDir = __dirname;
|
|
16
|
+
const binPath = path.join(binDir, binName);
|
|
17
|
+
|
|
18
|
+
function run() {
|
|
19
|
+
const res = spawnSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
|
|
20
|
+
if (res.error) {
|
|
21
|
+
console.error(`[kodu] ${res.error.message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
process.exit(res.status ?? 0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(binPath)) {
|
|
28
|
+
run();
|
|
29
|
+
} else {
|
|
30
|
+
console.error('[kodu] Native binary not found, downloading it now…');
|
|
31
|
+
install(binDir)
|
|
32
|
+
.then(run)
|
|
33
|
+
.catch((err) => {
|
|
34
|
+
console.error(`[kodu] Failed to download the binary: ${err.message}`);
|
|
35
|
+
console.error('[kodu] Reinstall the package or build it from source:');
|
|
36
|
+
console.error('[kodu] go install github.com/uxname/kodu/cmd/kodu@latest');
|
|
37
|
+
console.error(`[kodu] https://github.com/${REPO}/releases`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kodu",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "High-performance CLI to prepare codebase for LLMs, automate reviews, and draft commits.",
|
|
3
|
+
"version": "3.0.2",
|
|
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,26 @@
|
|
|
16
16
|
"llm",
|
|
17
17
|
"developer-tools",
|
|
18
18
|
"productivity",
|
|
19
|
-
"
|
|
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": "
|
|
28
|
+
"kodu": "bin/kodu.js"
|
|
30
29
|
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin/kodu.js",
|
|
32
|
+
"scripts/postinstall.js",
|
|
33
|
+
"scripts/install.js"
|
|
34
|
+
],
|
|
31
35
|
"scripts": {
|
|
32
|
-
"
|
|
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"
|
|
36
|
+
"postinstall": "node scripts/postinstall.js"
|
|
76
37
|
},
|
|
77
|
-
"
|
|
78
|
-
"
|
|
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"
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
95
40
|
}
|
|
96
41
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Shared installer: downloads the native kodu binary for the current platform
|
|
2
|
+
// from GitHub Releases. Used by the postinstall hook AND by the launcher's
|
|
3
|
+
// lazy fallback (so the package works even when the package manager skipped
|
|
4
|
+
// postinstall — e.g. bun by default, or `npm i --ignore-scripts`).
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const https = require('node:https');
|
|
10
|
+
const { execFileSync } = require('node:child_process');
|
|
11
|
+
|
|
12
|
+
const REPO = 'uxname/kodu';
|
|
13
|
+
const pkg = require('../package.json');
|
|
14
|
+
|
|
15
|
+
const PLATFORMS = { linux: 'linux', darwin: 'darwin', win32: 'windows' };
|
|
16
|
+
const ARCHES = { x64: 'amd64', arm64: 'arm64' };
|
|
17
|
+
|
|
18
|
+
function download(u, dest, redirects = 0) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
if (redirects > 5) return reject(new Error('too many redirects'));
|
|
21
|
+
https.get(u, (res) => {
|
|
22
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
23
|
+
res.resume();
|
|
24
|
+
return resolve(download(res.headers.location, dest, redirects + 1));
|
|
25
|
+
}
|
|
26
|
+
if (res.statusCode !== 200) {
|
|
27
|
+
res.resume();
|
|
28
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${u}`));
|
|
29
|
+
}
|
|
30
|
+
const file = fs.createWriteStream(dest);
|
|
31
|
+
res.pipe(file);
|
|
32
|
+
file.on('finish', () => file.close(resolve));
|
|
33
|
+
file.on('error', reject);
|
|
34
|
+
}).on('error', reject);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Resolves the binary path for the running platform, or null if unsupported.
|
|
39
|
+
function binNameFor(goos) {
|
|
40
|
+
return goos === 'windows' ? 'kodu.exe' : 'kodu';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Downloads + extracts the native binary into binDir. Returns the absolute
|
|
44
|
+
// binary path on success; throws on any failure (caller decides how to log).
|
|
45
|
+
async function install(binDir) {
|
|
46
|
+
const goos = PLATFORMS[process.platform];
|
|
47
|
+
const goarch = ARCHES[process.arch];
|
|
48
|
+
if (!goos || !goarch) {
|
|
49
|
+
throw new Error(`Platform ${process.platform}/${process.arch} is not supported by a prebuilt binary.`);
|
|
50
|
+
}
|
|
51
|
+
const ext = goos === 'windows' ? 'zip' : 'tar.gz';
|
|
52
|
+
const binName = binNameFor(goos);
|
|
53
|
+
const asset = `kodu_v${pkg.version}_${goos}_${goarch}.${ext}`;
|
|
54
|
+
const url = `https://github.com/${REPO}/releases/download/v${pkg.version}/${asset}`;
|
|
55
|
+
|
|
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
|
+
return { binPath, goos, goarch, version: pkg.version };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = { install, download, binNameFor, REPO, pkg };
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
// The launcher (bin/kodu.js) will also download lazily on first run if this hook
|
|
5
|
+
// was skipped (bun) or failed, so a missing binary here is never fatal.
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const { install, REPO } = require('./install');
|
|
10
|
+
|
|
11
|
+
const binDir = path.join(__dirname, '..', 'bin');
|
|
12
|
+
|
|
13
|
+
install(binDir)
|
|
14
|
+
.then(({ goos, goarch, version }) =>
|
|
15
|
+
console.log(`[kodu] Installed binary ${goos}/${goarch} v${version}`))
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
console.warn(`\n[kodu] Failed to download the binary: ${err.message}`);
|
|
18
|
+
console.warn('[kodu] It will be downloaded automatically on first run, or install manually:');
|
|
19
|
+
console.warn('[kodu] go install github.com/uxname/kodu/cmd/kodu@latest');
|
|
20
|
+
console.warn(`[kodu] https://github.com/${REPO}/releases\n`);
|
|
21
|
+
process.exit(0); // do not block npm install
|
|
22
|
+
});
|
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,82 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { RegistryService } from '../../../src/core/registry/registry.service';
|
|
6
|
-
|
|
7
|
-
describe('RegistryService', () => {
|
|
8
|
-
let tmpDir: string;
|
|
9
|
-
let originalXdg: string | undefined;
|
|
10
|
-
let service: RegistryService;
|
|
11
|
-
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'kodu-registry-'));
|
|
14
|
-
originalXdg = process.env.XDG_CONFIG_HOME;
|
|
15
|
-
process.env.XDG_CONFIG_HOME = tmpDir;
|
|
16
|
-
// Путь реестра читается в конструкторе — создаём после установки env.
|
|
17
|
-
service = new RegistryService();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(async () => {
|
|
21
|
-
if (originalXdg === undefined) {
|
|
22
|
-
delete process.env.XDG_CONFIG_HOME;
|
|
23
|
-
} else {
|
|
24
|
-
process.env.XDG_CONFIG_HOME = originalXdg;
|
|
25
|
-
}
|
|
26
|
-
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('returns empty registry when file does not exist', async () => {
|
|
30
|
-
const registry = await service.load();
|
|
31
|
-
expect(registry.projects).toEqual({});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('does not create the file until something is saved', async () => {
|
|
35
|
-
await service.load();
|
|
36
|
-
await expect(fs.access(service.getFilePath())).rejects.toBeTruthy();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('adds a project and persists it to disk', async () => {
|
|
40
|
-
await service.add('my-api', { path: '/work/my-api', stands: ['dev'] });
|
|
41
|
-
|
|
42
|
-
const onDisk = JSON.parse(await fs.readFile(service.getFilePath(), 'utf8'));
|
|
43
|
-
expect(onDisk.projects['my-api']).toEqual({
|
|
44
|
-
path: '/work/my-api',
|
|
45
|
-
stands: ['dev'],
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('rejects a duplicate project name by default', async () => {
|
|
50
|
-
await service.add('my-api', { path: '/work/my-api', stands: ['dev'] });
|
|
51
|
-
|
|
52
|
-
await expect(
|
|
53
|
-
service.add('my-api', { path: '/other', stands: ['dev'] }),
|
|
54
|
-
).rejects.toThrow(/уже есть в реестре/);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('overwrites when overwrite option is set', async () => {
|
|
58
|
-
await service.add('my-api', { path: '/work/my-api', stands: ['dev'] });
|
|
59
|
-
await service.add(
|
|
60
|
-
'my-api',
|
|
61
|
-
{ path: '/new', stands: ['prod'] },
|
|
62
|
-
{ overwrite: true },
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const entry = await service.get('my-api');
|
|
66
|
-
expect(entry?.path).toBe('/new');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('updates an existing project', async () => {
|
|
70
|
-
await service.add('my-api', { path: '/work/my-api', stands: ['dev'] });
|
|
71
|
-
await service.update('my-api', { path: '/moved' });
|
|
72
|
-
|
|
73
|
-
expect((await service.get('my-api'))?.path).toBe('/moved');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('throws when reading an invalid registry file', async () => {
|
|
77
|
-
await fs.mkdir(path.dirname(service.getFilePath()), { recursive: true });
|
|
78
|
-
await fs.writeFile(service.getFilePath(), '{ not json', 'utf8');
|
|
79
|
-
|
|
80
|
-
await expect(service.load()).rejects.toThrow();
|
|
81
|
-
});
|
|
82
|
-
});
|