DeepL CLI is a command-line interface for the DeepL API that integrates translation, writing enhancement (DeepL Write API), and developer workflow automation.
- Version: 1.0.0
- Tests: 2757 tests passing (100% pass rate), ~91% coverage
- Test mix: ~70-75% unit, ~25-30% integration/e2e
- Next Milestone: 1.0.0 (stable public API)
CLI Commands (translate, write, watch, glossary, etc.)
↓
Service Layer (Translation, Write, Batch, Watch, GitHooks, Cache, Glossary)
↓
API Client (DeepL API: /v2/translate, /v2/write, /v3/glossaries)
↓
Storage (SQLite Cache, Config Management)
- Config: XDG default
~/.config/deepl-cli/config.json, legacy~/.deepl-cli/config.json - Cache: XDG default
~/.cache/deepl-cli/cache.db, legacy~/.deepl-cli/cache.db - Path priority:
DEEPL_CONFIG_DIR> legacy~/.deepl-cli/> XDG env vars > XDG defaults - Environment Variables:
DEEPL_API_KEY- API authenticationDEEPL_CONFIG_DIR- Override config and cache directory (used for test isolation)XDG_CONFIG_HOME- Override XDG config base (default:~/.config)XDG_CACHE_HOME- Override XDG cache base (default:~/.cache)NO_COLOR- Disable colored output
- CHANGELOG.md - Release history and version notes
- docs/API.md - Complete CLI command reference
- Always use the latest versions of packages
- Never downgrade packages to avoid ESM/CommonJS issues
- If a package is ESM-only, refactor code to use dynamic imports or ESM
This project follows strict TDD:
- Red - Write failing tests that define expected behavior
- Green - Write minimal code to make tests pass
- Refactor - Improve code quality while keeping tests green
- Commit - Save progress after each cycle
Always write tests before implementation code. Test behavior, not implementation. Keep tests isolated.
Use Semantic Versioning with Conventional Commits:
feat:→ MINOR,fix:→ PATCH,BREAKING CHANGE:→ MAJORdocs:, chore:, refactor:→ no bump unless behavior changes
- Add entries under Unreleased in
CHANGELOG.mdusing only the standard Keep a Changelog categories: Added, Changed, Deprecated, Removed, Fixed, Security. Do not invent custom categories (e.g., "Improved"). - Determine MAJOR/MINOR/PATCH from change scope
- Move Unreleased items to
## [X.Y.Z] - YYYY-MM-DD - Update
VERSIONandpackage.jsonversion - Create annotated tag:
git tag -a vX.Y.Z -m "Release vX.Y.Z: <summary>" - Push:
git push && git push --tags
- Comment sparingly - only when behavior is unclear
- Type everything - avoid
any - Prefer explicit over implicit
- Follow existing patterns in the codebase
- Files: kebab-case (
translation-service.ts) - Classes/Types/Interfaces: PascalCase (
TranslationService) - Functions/variables: camelCase (
translateText) - Constants: UPPER_SNAKE_CASE (
MAX_CACHE_SIZE)
src/
├── cli/ # CLI interface and commands
├── services/ # Business logic
├── api/ # DeepL API client
├── storage/ # Data persistence
├── utils/ # Utility functions
└── types/ # Type definitions
- Jest + ts-jest - Test runner with TypeScript support
- nock - HTTP request mocking for API tests
- memfs - File system mocking
All three are required for new features:
- Unit tests - Individual functions/classes in isolation, mock all dependencies. File:
tests/unit/<component>.test.ts - Integration tests - Component interactions with nock for HTTP mocking and
DEEPL_CONFIG_DIRfor isolation. File:tests/integration/<component>.integration.test.ts - E2E tests - Complete CLI workflows, exit codes, stdin/stdout, error messages. File:
tests/e2e/<workflow>.e2e.test.ts
describe('ComponentName', () => {
describe('methodName', () => {
it('should do something specific', () => {
// Arrange → Act → Assert
});
});
});Integration tests must cover:
- Happy path with valid inputs
- API key validation
- Argument validation
- Error handling (403, 429, 503)
- HTTP request structure (validated with nock)
- Response parsing
E2E tests must cover:
- Complete user workflows
- Stdin/stdout piping
- Exit codes (success = 0, errors > 0)
- Error messages are clear and actionable
- Flag combinations (valid and invalid)
- Unit tests: Jest mocks or nock for external APIs
- Integration tests: nock for HTTP, real implementations internally
- File system: memfs where needed
- Test isolation:
DEEPL_CONFIG_DIRenv var pointing to temp directory
Use conventional commits:
<type>(<scope>): <description>
[optional body]
Types: feat, fix, refactor, test, docs, chore, perf, style
- Make separate commits per logical change
- Group tests with the logic they test
- Run
npm run lintandnpm run type-checkbefore every commit
PR descriptions should include:
- Summary - What changed and why (1-2 sentences)
- Changes Made - Bullet points of specific changes
- Test Coverage - What tests were added/modified
- Backward Compatibility - Breaking changes or compatibility notes
- All tests pass (
npm test) - Linter passes (
npm run lint) - TypeScript compiles (
npm run type-check) - Unit, integration, and E2E tests written for new features
- HTTP mocking with nock for API interactions
- Test isolation using
DEEPL_CONFIG_DIR - CHANGELOG.md updated under Unreleased
- README.md updated if user-facing feature
- API.md updated if command/flag added
- Example script added to
examples/for new features - Commit messages follow conventional commits format
npm test # Run all tests
npm run test:unit # Unit tests only
npm run test:integration # Integration tests only
npm run test:e2e # E2E tests only
npm run test:coverage # Tests with coverage report
npm run lint # Lint code
npm run lint:fix # Fix lint issues
npm run type-check # TypeScript type checking
npm run build # Build project
npm run dev # Run CLI locally
npm run examples # Run all example scripts
npm run examples:fast # Run examples (skip slow ones)API.md must accurately reflect the implementation. When adding new flags or commands:
- Verify the flag exists in source:
grep "\.option.*--flag-name" src/cli/index.ts - Ensure synopsis matches commander.js definitions
- Verify default values match code
- Test documented examples against the actual CLI
New features should include an example script in examples/:
- Sequential numbering (
examples/13-new-feature.sh), executable (chmod +x) - Include API key check, use
/tmpfor temp files, clean up on exit - Add to
examples/run-all.shEXAMPLES array - Reference in
examples/README.md
When spawning multiple agents to work in parallel:
git worktree add /tmp/fix-watch fix/watch-infinite-loop
git worktree add /tmp/fix-write fix/write-bugsMap each task to files it will touch. Ensure no two agents modify the same file. If two tasks touch the same file, assign them to the same agent.
- Merge feature branches one at a time into main
- Run the full test suite after all merges (
npm test) - Delete feature branches after merge