Skip to content

Add ktavi config set command #101

@mayashavin

Description

@mayashavin

Sub-task of #96

Summary

Add a ktavi config set <key> <value> command to update individual config values in the project or global config file. Use dot-notation keys (e.g. ktavi config set ai.textModel gpt-4o-mini). Validate values against the zod schema before writing.

Command signature

ktavi config set <key> <value> [--global]
  • --global — Update global config at ~/.config/ktavi/config.js instead of project config

Examples

ktavi config set ai.textModel gpt-4o-mini
ktavi config set writing.defaultMode strong
ktavi config set storage.provider cloudinary
ktavi config set markdown.preserveFrontmatterOrder false
ktavi config set image.style "watercolor illustration"
ktavi config set storage.local.outputDir ./out/images --global

Valid keys and value constraints

Key Type Valid values
ai.provider enum openai
ai.textModel string any
ai.imageModel string any
markdown.coverField enum cover, image, heroImage, ogImage, thumbnail
markdown.preserveFrontmatterOrder boolean true, false
writing.defaultMode enum light, medium, strong
image.size enum 1024x1024, 1536x1024, 1792x1024
image.style string any
storage.provider enum local, cloudinary
storage.local.outputDir string any
storage.local.publicPathPrefix string any
storage.cloudinary.folder string any

Implementation steps

1. Export validation from config.ts

Export a validateConfig() function wrapping ktaviConfigSchema.parse() so config set can validate before writing. Keeps the schema encapsulated.

2. Extract serializeConfig to shared utility

Currently lives in configInit.ts. Move to src/utils/configSerializer.ts so both config init and config set can use it.

3. Core logic (configSet.ts)

1. Parse dot-notation key into path segments
2. Coerce string value to correct type (boolean for preserveFrontmatterOrder)
3. Determine target file: --global → ~/.config/ktavi/config.js, else → ktavi.config.ts/.js
4. Load existing config via loadSingleConfigFile (or start with {} if none exists)
5. Set the nested value on the config object
6. Validate the full merged config with validateConfig()
7. Serialize and write back
8. Print confirmation: "Set ai.textModel = gpt-4o-mini in ktavi.config.ts"

Key design decisions

  • Value coercion: CLI args are always strings. Coerce "true"/"false" → boolean for preserveFrontmatterOrder. Everything else stays as string (enums are string-based).
  • Unknown key handling: Reject keys not in the schema with a clear error listing valid keys.
  • Missing config file: If no config file exists, create one with just the set value. Detect .ts vs .js by checking for tsconfig.json.
  • Validation timing: Validate the complete merged config (defaults + existing + new value) through the zod schema before writing.
  • Empty string clears optional fields: config set ai.imageModel "" removes the field from config.

Error messages

$ ktavi config set writing.defaultMode turbo
Error: Invalid value "turbo" for writing.defaultMode
Valid values: light, medium, strong

$ ktavi config set ai.foo bar
Error: Unknown config key "ai.foo"
Valid keys: ai.provider, ai.textModel, ai.imageModel, writing.defaultMode, ...

$ ktavi config set ai.textModel gpt-4o-mini
✔ Set ai.textModel = "gpt-4o-mini" in ktavi.config.ts

Files to create/modify

File Change
src/core/config.ts Export validateConfig() function
src/utils/configSerializer.ts New — extract serializeConfig from configInit.ts
src/cli/commands/configInit.ts Import serializeConfig from shared utility
src/cli/commands/configSet.ts New — set command logic
src/cli/commands/config.ts Register config set subcommand
tests/cli/configSet.test.ts New — tests

Test plan

Case Input Expected
Set string value config set ai.textModel gpt-4o-mini Config file updated, confirmed
Set enum value config set writing.defaultMode strong Writes strong, validates
Set boolean value config set markdown.preserveFrontmatterOrder false Coerces to boolean, writes
Set nested 3-level key config set storage.local.outputDir ./out Deep-sets correctly
Invalid enum value config set writing.defaultMode turbo Error with valid options listed
Invalid key config set ai.foo bar Error with valid keys listed
No config file exists config set ai.textModel gpt-4o-mini Creates new config file
Existing config preserved Set one field Other fields unchanged
--global flag config set ai.textModel gpt-4o-mini --global Writes to global config
Overwrite existing value Set field with existing value Old value replaced
Optional field set config set image.style "pixel art" Writes optional field
Optional field clear config set ai.imageModel "" Removes field from config

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions