Skip to content

Feat: interactive notification setup#14

Merged
utkarsh232005 merged 7 commits into
KDM-cli:mainfrom
utkarsh232005:feat/interactive-config
May 14, 2026
Merged

Feat: interactive notification setup#14
utkarsh232005 merged 7 commits into
KDM-cli:mainfrom
utkarsh232005:feat/interactive-config

Conversation

@utkarsh232005
Copy link
Copy Markdown
Member

@utkarsh232005 utkarsh232005 commented May 14, 2026

This PR introduces a comprehensive interactive set up flow for notifications:

  • Service Selection: Choose between Discord, Email, or None using a TUI menu.
  • Credential Collection: Interactively collect Discord Webhooks or SMTP details with real-time validation.
  • Improved Validation: Added regex validation for SMTP ports (1-65535), email addresses, and full Discord webhook URLs.
  • Atomicity: Configuration is only persisted if the entire set up flow completes successfully.
  • Credential Isolation: Automatically clears old notification credentials when switching services.
  • Unit Tests: Full test coverage for the new interactive logic using vitest.
  • Bug Fix: Fixed a missing import that caused the setup command to fail in runtime and CI.

Summary by CodeRabbit

  • New Features

    • Interactive "config setup" command to choose a notification service (Discord, Email SMTP, or None); collects service-specific details, confirms success, and shows an error on cancel/failure. Reminds to set SMTP password via environment variable.
    • Configuration now supports a notification service setting and clearing of notification credentials.
  • Tests

    • Added and refactored tests for interactive setup flows (none/Discord/Email) and updated mocks/assertions for related flows and table rendering.
  • Chores

    • Added repository review configuration and CI review rules.
    • Updated dependencies: added a runtime package and bumped a dev dependency version.

Review Change Stack

Copilot AI review requested due to automatic review settings May 14, 2026 07:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an interactive kdm config setup flow for choosing a notification service and expands the config model/tests to recognize that selection.

Changes:

  • Adds notification_service to stored configuration.
  • Adds config setup using @vr_patel/tui selection prompts.
  • Adds unit test coverage for the new setup command registration and Discord selection path.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/utils/config.ts Adds the notification service setting to the config interface.
src/commands/config.ts Adds the interactive setup subcommand and follow-up guidance.
src/__tests__/config.test.ts Mocks the TUI selector and tests setup command registration/Discord selection.
package.json Adds the TUI dependency.
package-lock.json Locks the new TUI dependency version.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/commands/config.ts Outdated
],
});

setConfig('notification_service', choice);
Comment thread src/commands/config.ts Outdated
if (choice === 'discord') {
console.log(chalk.yellow('! Remember to set your webhook URL:'), chalk.cyan('kdm config set discord_webhook <url>'));
} else if (choice === 'email') {
console.log(chalk.yellow('! Remember to set your SMTP details (email_host, email_port, email_user, email_to)'));
Comment thread src/commands/config.ts Outdated
Comment on lines +17 to +21
message: "Select notification service:",
options: [
{ label: "Discord", value: "discord", description: "Send alerts to a Discord channel via Webhook" },
{ label: "Email (SMTP)", value: "email", description: "Send alerts via Email SMTP" },
{ label: "None", value: "none", description: "Disable notifications" },
Comment thread src/commands/config.ts Outdated
Comment on lines +28 to +31
if (choice === 'discord') {
console.log(chalk.yellow('! Remember to set your webhook URL:'), chalk.cyan('kdm config set discord_webhook <url>'));
} else if (choice === 'email') {
console.log(chalk.yellow('! Remember to set your SMTP details (email_host, email_port, email_user, email_to)'));
Comment thread src/commands/config.ts Outdated

config
.command('setup')
.description('Interactively setup notification service')
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: String must contain at most 250 character(s) at "tone_instructions"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 62fab711-cf8b-4928-a5e5-428d9d5eadef

📥 Commits

Reviewing files that changed from the base of the PR and between 3af02e2 and 92b927a.

📒 Files selected for processing (2)
  • .coderabbit.yaml
  • src/__tests__/show.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/tests/show.test.ts
  • .coderabbit.yaml

📝 Walkthrough

Walkthrough

Adds an interactive config setup subcommand: introduces a TUI dependency, extends the config schema with notification_service, implements prompts and validation to configure Discord or SMTP settings (with credential clearing), persists settings via setConfig, and updates tests and review config.

Changes

Notification Service Configuration Setup

Layer / File(s) Summary
Config schema and TUI dependency
src/utils/config.ts, package.json
KDMConfig gains optional notification_service ('discord' | 'email' | 'none') and exports clearNotificationCredentials(). @vr_patel/tui added to dependencies; @types/react devDependency bumped.
Interactive setup command
src/commands/config.ts
Adds config setup using select/input from TUI, validates Discord webhook and SMTP fields (including port parsing), clears prior notifier credentials, stores values via setConfig, and logs success/error.
Setup command testing
src/__tests__/config.test.ts
Mocks @vr_patel/tui select/input, adds async tests for config setup covering none/discord/email flows, updates command-registration expectation to include setup, and adapts existing set/list/clear tests to use configUtils namespace mocks.
Show command test tweak
src/__tests__/show.test.ts
Replaces dynamic import with static tableUtils import and asserts tableUtils.renderTable is called on Kubernetes connection failure.
Repository review config
.coderabbit.yaml
Adds CodeRabbit review configuration with path filters and path-specific instructions for commands, config utils, and tests.

Sequence Diagram

sequenceDiagram
  participant User
  participant ConfigSetup as config setup
  participant TUISelect as select()
  participant TUIInput as input()
  participant ConfigClear as clearNotificationCredentials()
  participant ConfigStore as setConfig()
  participant Console

  User->>ConfigSetup: run `config setup`
  ConfigSetup->>TUISelect: prompt for notification service
  TUISelect-->>ConfigSetup: returns selected service
  ConfigSetup->>ConfigClear: clearNotificationCredentials()
  alt discord
    ConfigSetup->>TUIInput: prompt for Discord webhook
    TUIInput-->>ConfigSetup: webhook URL
    ConfigSetup->>ConfigStore: setConfig('discord_webhook', url)
  else email
    ConfigSetup->>TUIInput: prompt for SMTP host/port/user/to
    TUIInput-->>ConfigSetup: smtp values
    ConfigSetup->>ConfigStore: setConfig('email_host'/'email_port'/'email_user'/'email_to', values)
  else none
    ConfigSetup->>ConfigStore: setConfig('notification_service','none')
  end
  ConfigSetup->>ConfigStore: setConfig('notification_service', selected_service)
  ConfigSetup->>Console: log success or error
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through prompts with care,
Selects Discord or Email, types with flair,
Secrets cleared, new keys tucked in tight,
Green success glows, errors flee the night,
Hooray — the notifier is set just right! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat: interactive notification setup' directly and clearly summarizes the main change—adding an interactive TUI-based notification service configuration flow with service selection and credential validation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

Copilot AI review requested due to automatic review settings May 14, 2026 07:46
Copy link
Copy Markdown
Contributor

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/config.test.ts`:
- Line 5: The test misses mocking input() so when select() returns 'discord'
setup calls input() in src/commands/config.ts and throws; update the test import
to include input (alongside select) from '@vr_patel/tui', add a jest.mock for
input (or mockImplementation) where select is mocked, set input to return the
webhook URL expected by the command, and add an assertion that input was called
with the expected prompt and/or that its return value was used (e.g.,
expect(input).toHaveBeenCalled() or matching args) to allow the success
console.log path to run.

In `@src/commands/config.ts`:
- Line 25: The code currently calls setConfig('notification_service', choice)
immediately which persists the selection even if subsequent setup fails or is
cancelled; instead, keep the user's choice in a local variable (e.g.,
notificationChoice) and run the rest of the setup flow (the logic surrounding
the existing setup/validation and the error handling at the block that catches
failures around lines 64-66); only call setConfig('notification_service',
notificationChoice) after the setup completes successfully, and ensure no
persistence occurs in the failure/cancel paths.
- Around line 40-44: The input validator for SMTP port (the input(...) call that
assigns portStr) currently uses parseInt and accepts values like "587abc";
change the validator to require a fully numeric string (e.g. /^\d+$/) and then
convert to a Number and validate the range 1–65535 before accepting; also ensure
the code that stores the port (the SMTP port variable assignment that uses
portStr) saves it as a numeric value (Number or parseInt result) after the range
check.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c4cc1d3e-1a4b-41aa-bb6b-4db29f9d45f6

📥 Commits

Reviewing files that changed from the base of the PR and between 032e6a5 and 2b20076.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json
  • src/__tests__/config.test.ts
  • src/commands/config.ts
  • src/utils/config.ts

Comment thread src/__tests__/config.test.ts Outdated
Comment thread src/commands/config.ts Outdated
Comment thread src/commands/config.ts
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

An unexpected error occurred while generating fixes: Not Found - https://docs.github.com/rest/git/refs#get-a-reference

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (3)

src/commands/config.ts:57

  • Switching to email setup does not clear an existing discord_webhook, and the current alert code sends Discord notifications whenever that key is present. A user who previously configured Discord and then selects Email here will still receive Discord alerts as well, contrary to the single-service selection flow.
          setConfig('email_host', host);
          setConfig('email_port', parseInt(portStr, 10));
          setConfig('email_user', user);
          setConfig('email_to', to);

src/commands/config.ts:32

  • Switching to Discord setup does not clear existing SMTP settings, and the alert code sends email whenever the SMTP fields and password are present. A user who previously configured email and then selects Discord here will still receive email alerts too, so the selected service is not actually exclusive.
          setConfig('discord_webhook', webhook);

src/commands/config.ts:51

  • The email validation accepts any string containing @, including invalid values like @ or user@. Those values are then persisted and later passed to Nodemailer, so setup can report success while saving unusable addresses.
            validate: (v) => v.includes('@') || "Must be a valid email",
          });
          const to = await input({
            message: "Alert Recipient Email:",
            validate: (v) => v.includes('@') || "Must be a valid email",

Comment thread src/commands/config.ts Outdated
Comment on lines +21 to +25
{ label: "None", value: "none", description: "Disable notifications" },
],
});

setConfig('notification_service', choice);
Comment thread src/commands/config.ts Outdated
],
});

setConfig('notification_service', choice);
Comment thread src/commands/config.ts Outdated
Comment on lines +43 to +55
validate: (v) => !isNaN(parseInt(v)) || "Must be a number",
});
const user = await input({
message: "SMTP User:",
validate: (v) => v.includes('@') || "Must be a valid email",
});
const to = await input({
message: "Alert Recipient Email:",
validate: (v) => v.includes('@') || "Must be a valid email",
});

setConfig('email_host', host);
setConfig('email_port', parseInt(portStr, 10));
Comment thread src/commands/config.ts Outdated
options: [
{ label: "Discord", value: "discord", description: "Send alerts to a Discord channel via Webhook" },
{ label: "Email (SMTP)", value: "email", description: "Send alerts via Email SMTP" },
{ label: "None", value: "none", description: "Disable notifications" },
Comment thread src/commands/config.ts
Comment on lines +28 to +31
const webhook = await input({
message: "Discord Webhook URL:",
validate: (v) => v.startsWith('https://discord.com/api/webhooks/') || v.startsWith('https://ptb.discord.com/api/webhooks/') || "Must be a valid Discord webhook URL",
});
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/config.test.ts`:
- Line 42: The tests re-import `setConfig` inside the setup blocks which breaks
the mock call tracking; remove the inline imports at the three spots and use the
originally imported mocked `setConfig` (the one brought in at the top of the
file) for assertions and call checks (replace any `await
import('../utils/config')` usages with references to the top-level `setConfig`
mock so all expectations target the same mock instance).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6199e713-c914-48d2-a0e4-516aab8fcd72

📥 Commits

Reviewing files that changed from the base of the PR and between caa8f84 and 24b1869.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json
  • src/__tests__/config.test.ts
  • src/commands/config.ts
  • src/utils/config.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/commands/config.ts

Comment thread src/__tests__/config.test.ts Outdated
Copilot AI review requested due to automatic review settings May 14, 2026 07:55
Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (1)
src/__tests__/config.test.ts (1)

43-82: ⚡ Quick win

Add one abort-path test to lock in atomic-save behavior.

Line 43-82 currently covers only success flows. Add a failure/cancel scenario and assert that no config mutations occur, so the atomic-save requirement is explicitly protected.

Suggested additional test
+  it('should not persist partial config if setup aborts mid-flow', async () => {
+    vi.mocked(tui.select).mockResolvedValue('discord');
+    vi.mocked(tui.input).mockRejectedValue(new Error('cancelled'));
+
+    await program.parseAsync(['node', 'test', 'config', 'setup']);
+
+    expect(configUtils.clearNotificationCredentials).not.toHaveBeenCalled();
+    expect(configUtils.setConfig).not.toHaveBeenCalled();
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/config.test.ts` around lines 43 - 82, Add a new test that
simulates the abort/failure path of the config setup (e.g., mock tui.select or
tui.input to return a cancel value or throw) and assert that no configuration
mutations occur: verify configUtils.clearNotificationCredentials and
configUtils.setConfig were NOT called after await
program.parseAsync(['node','test','config','setup']); use the same helpers
referenced in the file (tui.select, tui.input, program.parseAsync,
configUtils.clearNotificationCredentials, configUtils.setConfig) to locate where
to insert the test and to assert atomic-save behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/config.test.ts`:
- Around line 67-82: The test currently verifies setting email fields but
doesn't assert that previous notification credentials are cleared; update the
'should call select, multiple inputs and setConfig on email setup' test to also
assert that configUtils.clearNotificationCredentials() is invoked when switching
services: keep the existing mocks for tui.select and tui.input, run
program.parseAsync(['node','test','config','setup']) as before, then add an
expectation like
expect(configUtils.clearNotificationCredentials).toHaveBeenCalled() after the
parse to ensure credentials cleanup occurs alongside the setConfig assertions
for 'notification_service', 'email_host', 'email_port', 'email_user', and
'email_to'.

---

Nitpick comments:
In `@src/__tests__/config.test.ts`:
- Around line 43-82: Add a new test that simulates the abort/failure path of the
config setup (e.g., mock tui.select or tui.input to return a cancel value or
throw) and assert that no configuration mutations occur: verify
configUtils.clearNotificationCredentials and configUtils.setConfig were NOT
called after await program.parseAsync(['node','test','config','setup']); use the
same helpers referenced in the file (tui.select, tui.input, program.parseAsync,
configUtils.clearNotificationCredentials, configUtils.setConfig) to locate where
to insert the test and to assert atomic-save behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d4fa6479-203f-4a85-86d6-a741f2105cdd

📥 Commits

Reviewing files that changed from the base of the PR and between 24b1869 and 3af02e2.

📒 Files selected for processing (2)
  • src/__tests__/config.test.ts
  • src/commands/config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/commands/config.ts

Comment on lines +67 to 82
it('should call select, multiple inputs and setConfig on email setup', async () => {
vi.mocked(tui.select).mockResolvedValue('email');
vi.mocked(tui.input)
.mockResolvedValueOnce('smtp.gmail.com') // host
.mockResolvedValueOnce('587') // port
.mockResolvedValueOnce('user@test.com') // user
.mockResolvedValueOnce('to@test.com'); // to

await program.parseAsync(['node', 'test', 'config', 'setup']);

expect(configUtils.setConfig).toHaveBeenCalledWith('notification_service', 'email');
expect(configUtils.setConfig).toHaveBeenCalledWith('email_host', 'smtp.gmail.com');
expect(configUtils.setConfig).toHaveBeenCalledWith('email_port', 587);
expect(configUtils.setConfig).toHaveBeenCalledWith('email_user', 'user@test.com');
expect(configUtils.setConfig).toHaveBeenCalledWith('email_to', 'to@test.com');
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert credential cleanup for the email setup path.

Line 67-82 validates email field persistence, but it doesn’t verify that configUtils.clearNotificationCredentials() is called when switching services. This leaves the cleanup requirement only partially covered.

Suggested test adjustment
   it('should call select, multiple inputs and setConfig on email setup', async () => {
     vi.mocked(tui.select).mockResolvedValue('email');
     vi.mocked(tui.input)
       .mockResolvedValueOnce('smtp.gmail.com') // host
       .mockResolvedValueOnce('587')            // port
       .mockResolvedValueOnce('user@test.com')  // user
       .mockResolvedValueOnce('to@test.com');    // to

     await program.parseAsync(['node', 'test', 'config', 'setup']);

+    expect(tui.select).toHaveBeenCalled();
+    expect(tui.input).toHaveBeenCalledTimes(4);
+    expect(configUtils.clearNotificationCredentials).toHaveBeenCalled();
     expect(configUtils.setConfig).toHaveBeenCalledWith('notification_service', 'email');
     expect(configUtils.setConfig).toHaveBeenCalledWith('email_host', 'smtp.gmail.com');
     expect(configUtils.setConfig).toHaveBeenCalledWith('email_port', 587);
     expect(configUtils.setConfig).toHaveBeenCalledWith('email_user', 'user@test.com');
     expect(configUtils.setConfig).toHaveBeenCalledWith('email_to', 'to@test.com');
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/config.test.ts` around lines 67 - 82, The test currently
verifies setting email fields but doesn't assert that previous notification
credentials are cleared; update the 'should call select, multiple inputs and
setConfig on email setup' test to also assert that
configUtils.clearNotificationCredentials() is invoked when switching services:
keep the existing mocks for tui.select and tui.input, run
program.parseAsync(['node','test','config','setup']) as before, then add an
expectation like
expect(configUtils.clearNotificationCredentials).toHaveBeenCalled() after the
parse to ensure credentials cleanup occurs alongside the setConfig assertions
for 'notification_service', 'email_host', 'email_port', 'email_user', and
'email_to'.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

src/commands/config.ts:43

  • This sequence is not atomic: credentials are cleared and then the new Discord values are written in separate operations. If the second setConfig fails, the command catches the error after leaving a partially updated config, which contradicts the setup flow's atomicity guarantee and can leave notifications misconfigured.
          clearNotificationCredentials();
          setConfig('discord_webhook', webhook);
          setConfig('notification_service', 'discord');

src/commands/config.ts:73

  • This sequence is not atomic: existing credentials are cleared and the email fields are then written one by one. If any later setConfig call fails, the old notification config is already deleted and a partial email config may remain, so the setup flow can leave notifications broken after a failed persistence step.
          clearNotificationCredentials();
          setConfig('email_host', host);
          setConfig('email_port', parseInt(portStr, 10));
          setConfig('email_user', user);
          setConfig('email_to', to);
          setConfig('notification_service', 'email');

Comment thread src/utils/config.ts
import Conf from 'conf';

interface KDMConfig {
notification_service?: 'discord' | 'email' | 'none';
Comment on lines +54 to +58
it('should call select, input and setConfig on discord setup', async () => {
vi.mocked(tui.select).mockResolvedValue('discord');
vi.mocked(tui.input).mockResolvedValue('https://discord.com/api/webhooks/123456789/token-here');

await program.parseAsync(['node', 'test', 'config', 'setup']);
Comment thread src/commands/config.ts
Comment on lines +25 to +27
if (choice === 'none') {
clearNotificationCredentials();
setConfig('notification_service', 'none');
@utkarsh232005 utkarsh232005 merged commit 810d2d0 into KDM-cli:main May 14, 2026
2 checks passed
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