Skip to content

feat(cli): add 'init' command for configuration setup#45

Merged
hurshore merged 10 commits intomainfrom
ft/vectorlint-init
Dec 30, 2025
Merged

feat(cli): add 'init' command for configuration setup#45
hurshore merged 10 commits intomainfrom
ft/vectorlint-init

Conversation

@ayo6706
Copy link
Collaborator

@ayo6706 ayo6706 commented Dec 21, 2025

Introduces a vectorlint init command that automates the setup process by generating configuration files with verified templates.

Changes

  • New: src/cli/init-command.ts - Init command implementation
  • New: tests/init-command.test.ts - Unit tests (5 tests)
  • Modified: src/index.ts - Register init command
  • Modified: eslint.config.mjs - Add init-command to process.exit exemptions

Usage

vectorlint init          # Generate config files
vectorlint init --force  # Overwrite existing files

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an init command to create local and global configuration files (with --force to overwrite) and load global config at startup; global [env] entries are merged without overwriting existing environment variables.

* **Documentation**
  * Updated README and configuration docs to reflect the init flow, global config location, and revised quick-start steps.

* **Tests**
  * Added tests for init behavior and global config loading (env merging, safety, and error cases).

* **Chores**
  * Added a runtime dependency for TOML parsing.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

- Add vectorlint init command to generate .vectorlint.ini and .env.vectorlint
- Include --force flag to overwrite existing files
- Print user-friendly next steps after generation
- Add unit tests for init command
@coderabbitai
Copy link

coderabbitai bot commented Dec 21, 2025

📝 Walkthrough

Walkthrough

Adds a new init CLI command and global configuration support: new init command registration, global config creation/loading (TOML), env injection, startup environment loader changes, constants and schema additions, tests, docs updates, ESLint exemption, and a TOML runtime dependency.

Changes

Cohort / File(s) Summary
Init command
src/cli/init-command.ts
New exported registerInitCommand(program: Command) registering vectorlint init with --force; checks existing files, writes local config(s), calls ensureGlobalConfig(), prints success/next steps, and exits non‑zero on failure.
CLI entry / startup
src/index.ts
Registers init command, replaces prior dotenv loading with loadEnvironment that loads local env and calls loadGlobalConfig, and invokes program.parse() at startup.
Global config support
src/config/global-config.ts, src/config/constants.ts, src/schemas/env-schemas.ts
New global-config module with getGlobalConfigPath(), ensureGlobalConfig(), loadGlobalConfig(); adds GLOBAL_CONFIG_DIR/GLOBAL_CONFIG_FILE constants and GLOBAL_CONFIG_SCHEMA; parses TOML via smol-toml, validates schema, and injects [env] keys into process.env without overwriting.
Tests
tests/init-command.test.ts, tests/global-config.test.ts
New Vitest suites covering init CLI behavior (file creation, non-overwrite, --force) and global-config loader behavior (TOML parsing, env injection, non-overwrite, missing/invalid file handling).
Docs / README
CONFIGURATION.md, README.md
Updates documenting global config (~/.vectorlint/config.toml), .env precedence, new vectorlint init flow, quick-start reworked to an init-first workflow.
ESLint config
eslint.config.mjs
Adds src/cli/init-command.ts to process-exit rule exemption list.
Dependency
package.json
Adds runtime dependency smol-toml: ^1.6.0 for TOML parsing.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant CLI as Commander Program
participant Init as init-command
participant FS as Filesystem
participant Global as global-config
participant TOML as smol-toml
Note over CLI,Init: vectorlint init execution
User->>CLI: run vectorlint init [--force]
CLI->>Init: dispatch init handler
Init->>FS: stat local config
alt exists and no --force
Init->>CLI: print error & exit 1
else write allowed
Init->>FS: write local config files
Init->>Global: ensureGlobalConfig()
Global->>FS: ensure dir & file
Global->>FS: read global config (if exists)
Global->>TOML: parse TOML
TOML-->>Global: parsed data
Global->>Init: return global path
Init->>CLI: print success & guidance
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • oshorefueled
  • hurshore

Poem

🐇 I hop with a pen and a plan,
I plant ~/.vectorlint in the land.
Init writes files, TOML says hello,
Env vars settle, lint seeds grow.
Off we go—happy checks, here we stand ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cli): add init command for configuration setup' directly and clearly summarizes the main change: adding a new CLI init command for configuration generation.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c2444d and 35abcc7.

📒 Files selected for processing (1)
  • src/index.ts
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with no any; use unknown + schema validation for external data
Use custom error types with proper inheritance; catch blocks use unknown type

Files:

  • src/index.ts
🧬 Code graph analysis (1)
src/index.ts (2)
src/config/global-config.ts (1)
  • loadGlobalConfig (82-106)
src/cli/init-command.ts (1)
  • registerInitCommand (28-71)
🔇 Additional comments (5)
src/index.ts (5)

8-9: LGTM! Clean imports for new functionality.

The imports are explicit and follow TypeScript ESM conventions. Both exports are confirmed in the relevant code snippets.


14-17: Verify precedence order aligns with requirements.

The comment correctly documents the implementation: CLI/Shell environment variables have the highest precedence, followed by local .env files, with global config having the lowest precedence. This follows the common pattern where more specific (local) configurations override more general (global) ones.

However, a past review comment questioned whether global config should have higher precedence than local .env. Please confirm this precedence order matches the intended design, as it impacts how users configure projects with both local and global settings.


18-57: LGTM! Global config integration is clean and resilient.

The function renaming from loadDotEnv to loadEnvironment better reflects its expanded scope. The integration of global config loading (lines 53-56) is correct:

  • Preserves the intended precedence order (local .env loaded before global config)
  • loadGlobalConfig() has internal error handling that warns but doesn't crash startup (confirmed in relevant snippet)
  • Both loaders respect existing environment variables by checking process.env[key] === undefined

60-60: LGTM! Function call updated to match rename.


69-69: LGTM! Init command registration is properly placed.

The command is registered before other commands, which makes sense for a setup/initialization command. The implementation in init-command.ts includes proper error handling and exit codes.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/cli/init-command.ts (1)

56-56: Consider moving ENV_FILENAME to constants.ts for consistency.

The constant DEFAULT_CONFIG_FILENAME is imported from src/config/constants.ts, while ENV_FILENAME is defined locally. For better maintainability and consistency, consider moving ENV_FILENAME to the constants file alongside DEFAULT_CONFIG_FILENAME.

🔎 Proposed refactor

In src/config/constants.ts, add:

export const ENV_FILENAME = '.env.vectorlint';

Then update the import in this file:

-import { DEFAULT_CONFIG_FILENAME } from '../config/constants';
+import { DEFAULT_CONFIG_FILENAME, ENV_FILENAME } from '../config/constants';

And remove the local constant definition:

-const ENV_FILENAME = '.env.vectorlint';
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 659ea2e and 8d74038.

📒 Files selected for processing (4)
  • eslint.config.mjs (1 hunks)
  • src/cli/init-command.ts (1 hunks)
  • src/index.ts (2 hunks)
  • tests/init-command.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/cli/init-command.ts (1)
src/config/constants.ts (1)
  • DEFAULT_CONFIG_FILENAME (5-5)
tests/init-command.test.ts (2)
src/config/constants.ts (1)
  • DEFAULT_CONFIG_FILENAME (5-5)
src/cli/init-command.ts (1)
  • registerInitCommand (66-115)
src/index.ts (1)
src/cli/init-command.ts (1)
  • registerInitCommand (66-115)
🔇 Additional comments (11)
src/cli/init-command.ts (5)

6-16: LGTM! Well-structured configuration template.

The template provides sensible defaults and clear structure. Leaving RulesPath empty is appropriate since users need to specify their rules directory, and this is clearly communicated in the success message.


18-54: LGTM! Excellent environment template with good security practices.

The template is comprehensive and well-documented. Having all sensitive configurations commented out by default prevents users from accidentally committing API keys. The multi-provider support with clear setup instructions will help users get started quickly.


76-93: LGTM! Excellent safety checks with clear user feedback.

The logic correctly prevents accidental overwrites and provides helpful error messages. Collecting and displaying all existing files at once (rather than failing on the first one) improves the user experience.


95-103: LGTM! Robust error handling.

The error handling properly catches write failures, safely handles unknown error types, and provides descriptive error messages. Specifying UTF-8 encoding explicitly is good practice.


105-114: LGTM! Clear and actionable success messages.

The success output provides users with a clear roadmap for the next steps. Using template literals to reference actual filenames ensures the messages stay accurate if constants change.

eslint.config.mjs (1)

129-134: LGTM! Appropriate ESLint exemption for CLI command.

Adding src/cli/init-command.ts to the process-exit exemption list is correct since CLI commands need to exit with appropriate status codes. This follows the established pattern for other CLI command modules.

src/index.ts (1)

8-8: LGTM! Clean integration of the init command.

The import and registration follow the established pattern for CLI commands. Registering the init command first is sensible since it's a setup/bootstrap command that users would typically run before other commands.

Also applies to: 64-64

tests/init-command.test.ts (4)

15-24: LGTM! Excellent test isolation and cleanup.

The setup/teardown properly isolates each test in a unique temporary directory and ensures thorough cleanup. Saving and restoring process.cwd() prevents test pollution.


26-71: LGTM! Comprehensive file generation tests.

The tests properly verify both file creation and content validity. Using dynamic imports ensures test isolation. The content assertions check for key configuration values without being overly brittle.


73-111: LGTM! Thorough safety check tests.

The tests properly verify that existing files are not overwritten without the --force flag. Using exitOverride() to test error cases and verifying that original content is preserved are both excellent testing practices.


113-136: LGTM! Force flag test properly verifies overwrite behavior.

The test correctly verifies that existing files are overwritten when --force is provided. Pre-populating files with old content ensures the test actually validates overwrite behavior rather than just file creation.

…injection

- Create global-config.ts module for managing user-level configuration
- Add getGlobalConfigPath() to resolve global config location in user home directory
- Implement ensureGlobalConfig() to create config file with template if missing
- Implement loadGlobalConfig() to parse TOML and inject [env] variables into process.env
- Add GLOBAL_CONFIG_SCHEMA validation for configuration structure
- Include comprehensive template with examples for all supported LLM providers
- Ensure CLI/shell environment variables take precedence over global config
- Add graceful error handling to prevent crashes on config load failures
- Enable users to store API keys and provider settings in a centralized location
- Add smol-toml dependency for TOML file parsing
- Create comprehensive test suite for global config loader functionality
- Add tests for environment variable injection from TOML configuration
- Add tests to verify existing environment variables are not overwritten
- Add tests for graceful handling of missing config files
- Add tests for invalid TOML error handling
- Update init command tests to mock global config module
- Replace .env.vectorlint file generation with global config initialization
- Simplify init command test by removing environment file assertions
- Remove redundant file overwrite protection tests for env files
- Reorganize quick start steps to prioritize initialization command
- Update configuration instructions to reflect global config at ~/.vectorlint/config.toml
- Add reference to vectorlint init command for automatic file generation
- Clarify precedence of project-scoped .env over global configuration
- Simplify LLM provider setup instructions with TOML example
- Update CONFIGURATION.md to document global and project-scoped configuration options
- Improve documentation flow to guide users through initialization before rule creation
- Remove unused zod import from global-config.ts
- Remove unused getGlobalConfigPath import from global-config.test.ts
- Rename mockEnsureGlobalConfig to MOCK_ENSURE_GLOBAL_CONFIG for consistency with constant naming conventions
- Update all references to use the new constant name in init-command.test.ts
- Improve code clarity and reduce unnecessary dependencies
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
README.md (1)

53-66: Consider documenting the --force flag for re-initialization scenarios.

The PR objectives mention a --force flag to overwrite existing files. This might be helpful to document in the Quick Start section for users who need to regenerate or reset their configuration.

Consider adding a brief note after line 59:

To regenerate configuration files and overwrite existing ones, use:
```bash
vectorlint init --force

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8d7403854e2b57e2772bf86ed0e2329b335f23d2 and d9c41b32a6cd6720eaed01135eb18ee74016b323.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (10)</summary>

* `CONFIGURATION.md`
* `README.md`
* `package.json`
* `src/cli/init-command.ts`
* `src/config/constants.ts`
* `src/config/global-config.ts`
* `src/index.ts`
* `src/schemas/env-schemas.ts`
* `tests/global-config.test.ts`
* `tests/init-command.test.ts`

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* tests/init-command.test.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (2)</summary>

<details>
<summary>src/**/*.ts</summary>


**📄 CodeRabbit inference engine (AGENTS.md)**

> `src/**/*.ts`: Use TypeScript ESM with explicit imports and narrow types
> Use 2-space indentation; avoid trailing whitespace
> Maintain strict TypeScript with no `any`; use `unknown` + schema validation for external data
> Use custom error types with proper inheritance; catch blocks use `unknown` type

Files:
- `src/config/constants.ts`
- `src/cli/init-command.ts`
- `src/config/global-config.ts`
- `src/schemas/env-schemas.ts`
- `src/index.ts`

</details>
<details>
<summary>tests/**/*.test.ts</summary>


**📄 CodeRabbit inference engine (AGENTS.md)**

> `tests/**/*.test.ts`: Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
> Use dependency injection in tests: mock providers; do not hit network in unit tests

Files:
- `tests/global-config.test.ts`

</details>

</details><details>
<summary>🧠 Learnings (6)</summary>

<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/providers/**/*.ts : Depend on LLMProvider and SearchProvider interfaces; keep providers thin (transport only)


**Applied to files:**
- `CONFIGURATION.md`

</details>
<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Never commit secrets; .env is gitignored and should be copied from .env.example


**Applied to files:**
- `src/cli/init-command.ts`

</details>
<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/boundaries/env-parser.ts : All environment variables must be validated via Zod schemas in src/boundaries/env-parser.ts


**Applied to files:**
- `src/schemas/env-schemas.ts`

</details>
<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/boundaries/**/*.ts : Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries


**Applied to files:**
- `src/schemas/env-schemas.ts`

</details>
<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to tests/**/*.test.ts : Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator


**Applied to files:**
- `tests/global-config.test.ts`

</details>
<details>
<summary>📚 Learning: 2025-12-28T19:43:51.176Z</summary>

Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to tests/**/*.test.ts : Use dependency injection in tests: mock providers; do not hit network in unit tests


**Applied to files:**
- `tests/global-config.test.ts`

</details>

</details><details>
<summary>🧬 Code graph analysis (4)</summary>

<details>
<summary>src/cli/init-command.ts (2)</summary><blockquote>

<details>
<summary>src/config/constants.ts (1)</summary>

* `DEFAULT_CONFIG_FILENAME` (6-6)

</details>
<details>
<summary>src/config/global-config.ts (2)</summary>

* `ensureGlobalConfig` (63-76)
* `getGlobalConfigPath` (9-11)

</details>

</blockquote></details>
<details>
<summary>src/config/global-config.ts (3)</summary><blockquote>

<details>
<summary>src/config/constants.ts (2)</summary>

* `GLOBAL_CONFIG_DIR` (7-7)
* `GLOBAL_CONFIG_FILE` (8-8)

</details>
<details>
<summary>src/schemas/env-schemas.ts (1)</summary>

* `GLOBAL_CONFIG_SCHEMA` (47-49)

</details>
<details>
<summary>src/errors/index.ts (1)</summary>

* `handleUnknownError` (46-51)

</details>

</blockquote></details>
<details>
<summary>tests/global-config.test.ts (2)</summary><blockquote>

<details>
<summary>src/config/constants.ts (2)</summary>

* `GLOBAL_CONFIG_DIR` (7-7)
* `GLOBAL_CONFIG_FILE` (8-8)

</details>
<details>
<summary>src/config/global-config.ts (1)</summary>

* `loadGlobalConfig` (82-106)

</details>

</blockquote></details>
<details>
<summary>src/index.ts (2)</summary><blockquote>

<details>
<summary>src/config/global-config.ts (1)</summary>

* `loadGlobalConfig` (82-106)

</details>
<details>
<summary>src/cli/init-command.ts (1)</summary>

* `registerInitCommand` (28-71)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (13)</summary><blockquote>

<details>
<summary>src/schemas/env-schemas.ts (1)</summary><blockquote>

`47-49`: **LGTM!**

The schema correctly validates the global configuration structure with appropriate type constraints. The optional `env` field and union type for values align well with TOML capabilities and the injection behavior in `loadGlobalConfig`.

</blockquote></details>
<details>
<summary>CONFIGURATION.md (1)</summary><blockquote>

`65-67`: **LGTM!**

The documentation accurately reflects the configuration hierarchy and provides clear guidance on using the global config alongside project-level `.env` files.

</blockquote></details>
<details>
<summary>src/config/constants.ts (1)</summary><blockquote>

`7-8`: **LGTM!**

The constants are well-named and provide a single source of truth for the global configuration file location.

</blockquote></details>
<details>
<summary>src/index.ts (1)</summary><blockquote>

`8-9`: **LGTM!**

The environment loading refactor correctly implements the documented precedence hierarchy (Shell/CLI > Local .env > Global config). The integration of global config loading and init command registration is clean and preserves existing error handling patterns.




Also applies to: 18-57, 60-60, 69-69

</blockquote></details>
<details>
<summary>tests/global-config.test.ts (1)</summary><blockquote>

`26-86`: **LGTM!**

The test suite provides comprehensive coverage of the global config loader, including success paths (loading and type conversion), preservation of existing environment variables, and graceful error handling for missing or invalid configs. The use of mocks properly isolates the tests from the filesystem.

</blockquote></details>
<details>
<summary>src/cli/init-command.ts (2)</summary><blockquote>

`8-17`: **LGTM!**

The configuration template provides sensible defaults and clear placeholders for users to customize.

---

`28-70`: **LGTM!**

The init command implementation is clean and user-friendly. It properly validates existing files, provides clear error messages, creates both local and global configs, and offers helpful next-step guidance. The error handling is appropriate for a CLI command.

</blockquote></details>
<details>
<summary>src/config/global-config.ts (4)</summary><blockquote>

`9-11`: **LGTM!**

The path resolution correctly uses the home directory and config constants.

---

`13-57`: **LGTM!**

The template provides comprehensive examples for all supported providers with helpful comments. The commented-out configuration approach allows users to uncomment only what they need.

---

`63-76`: **LGTM!**

The function properly ensures the directory and file exist with appropriate defaults, using recursive directory creation for reliability.

---

`82-106`: **LGTM!**

The loader implements correct environment variable injection with proper precedence (existing env vars are preserved). The graceful error handling ensures the application remains resilient even if the global config is malformed.

</blockquote></details>
<details>
<summary>package.json (1)</summary><blockquote>

`64-64`: **smol-toml version ^1.6.0 is valid, stable, and free from known vulnerabilities.**

Version 1.6.0 is the current latest release on npm, actively maintained, and has no known security advisories.

</blockquote></details>
<details>
<summary>README.md (1)</summary><blockquote>

`67-77`: **Excellent documentation of global config and environment variable precedence.**

The explanation of how to configure API keys in the global config is clear, and explicitly noting that local `.env` takes precedence is valuable context for users.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@hurshore hurshore merged commit 4694e64 into main Dec 30, 2025
3 checks passed
oshorefueled pushed a commit that referenced this pull request Mar 2, 2026
feat(cli): add 'init' command for configuration setup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants