Skip to content

feat(tui): make netclaw init reentrant — detect existing config and allow modification #455

@Aaronontheweb

Description

@Aaronontheweb

Summary

PR #432 decomposed the monolithic init wizard into composable step classes and intentionally laid architectural foundations for making netclaw init reentrant. This issue tracks the remaining work to complete that capability: re-running netclaw init should detect existing configuration and allow the user to modify it rather than starting from scratch.

PRD-004 explicitly requires this:

The wizard is reentrant — re-running netclaw init detects existing config and shows a section dashboard with status per section. Each section is independently enterable for modification. First-run guides linearly through all steps.

Foundations already in place (from #432)

1. WizardContext.ExistingConfig — deferred pre-population hook

File: src/Netclaw.Cli/Tui/Wizard/WizardContext.cs (lines 48-56)

/// Null for fresh init. When populated, steps should pre-populate their
/// fields from the existing config. (Deferred — not implemented yet.)
///
/// Re-edit UX intent: when existing config is detected, the wizard should
/// offer "Start fresh" vs "Modify existing". "Start fresh" does NOT wipe
/// existing files until the health check/validate stage completes successfully.
public Dictionary<string, object>? ExistingConfig { get; init; }

This property is declared and documented but never populated. Each step's OnEnter() would read from it to pre-fill fields.

2. ConfigFileHelper — load/merge/write utilities

File: src/Netclaw.Cli/Config/ConfigFileHelper.cs

Already supports the full merge workflow:

  • LoadConfigFiles(paths) — loads existing netclaw.json + secrets.json as mutable dictionaries (returns default skeleton if missing)
  • GetOrCreateSection(dict, key) — gets or creates nested sections, handling JsonElement deserialization
  • GetSectionOrNull(dict, key) — non-creating variant
  • WriteConfigFile(path, data) — writes merged dictionary back to disk

3. ProviderCredentialWriter — proof-of-concept merge pattern

File: src/Netclaw.Cli/Config/ProviderCredentialWriter.cs

Already demonstrates the load → merge → write pattern used by netclaw provider add:

Load existing config → GetOrCreateSection("Providers") → update entry → WriteConfigFile()

This preserves other providers and other config sections. The same pattern can be applied to WizardConfigBuilder.

4. IWizardStepViewModel.OnEnter(context, direction) — direction-aware entry

File: src/Netclaw.Cli/Tui/Wizard/IWizardStepViewModel.cs

Each step receives a NavigationDirection (Forward/Back) on entry. This same mechanism can distinguish "entering from existing config" vs "fresh entry" — steps would check context.ExistingConfig in their OnEnter() and pre-populate fields accordingly.

5. IsApplicable(WizardContext) — conditional step inclusion

File: src/Netclaw.Cli/Tui/Wizard/IWizardStepViewModel.cs

Steps are dynamically included/excluded based on context, re-evaluated on each transition. This enables a re-edit mode where only changed sections need to be shown.

6. WizardConfigBuilder — typed config sections

File: src/Netclaw.Cli/Tui/Wizard/WizardConfigBuilder.cs

Each config area (Provider, Slack, Security, Search, etc.) is an independent typed section. This makes partial updates straightforward — only populate the sections being modified.

7. WizardOrchestrator — composable step sequencing

File: src/Netclaw.Cli/Tui/Wizard/WizardOrchestrator.cs

Manages step sequencing with upfront instantiation (all 8 steps created once, preserving internal state) and dynamic applicability filtering. The orchestrator's WriteConfig() collects contributions from all steps — this is where merge-vs-overwrite behavior would be controlled.

What remains to implement

1. Detect existing config at init entry point

At the netclaw init entry point, check whether netclaw.json already exists. If so, load it and populate WizardContext.ExistingConfig.

2. "Start fresh" vs "Modify existing" UX

When existing config is detected, present a choice screen before entering the wizard steps. Per the documented intent, "Start fresh" should NOT wipe existing files until the health check/validate stage completes successfully.

3. Pre-population logic in each step's OnEnter()

Each of the 8 step ViewModels needs to check context.ExistingConfig on forward entry and pre-fill their fields from the matching config section:

Step Config section to read
ProviderStepViewModel Providers, Models
SecurityPostureStepViewModel Security
SlackStepViewModel Slack
ChannelsStepViewModel channel audience data
SearchStepViewModel Search
BrowserAutomationStepViewModel McpServers
IdentityStepViewModel identity files on disk
HealthCheckStepViewModel N/A (final validation)

Step files are all in src/Netclaw.Cli/Tui/Wizard/Steps/.

4. Change WizardConfigBuilder.WriteConfigFile() to merge instead of overwrite

Currently WriteConfigFile() builds a fresh dictionary and overwrites the file. For reentrant mode, it should load the existing config first and merge step contributions into it, preserving sections that weren't modified. The pattern from ProviderCredentialWriter can be followed.

5. Section dashboard for re-edit mode (PRD-004)

PRD-004 describes a section dashboard showing per-section status, where each section is independently enterable. This would be a new view that replaces the linear wizard flow when existing config is detected.

6. Secrets file merging

WizardSecretsBuilder.WriteSecretsFile() also builds fresh and overwrites. Same merge treatment needed as the config builder, preserving secrets for sections not being re-configured.

Key files map

src/Netclaw.Cli/Tui/Wizard/
├── WizardContext.cs              # ExistingConfig property (deferred)
├── WizardOrchestrator.cs         # Step sequencing + WriteConfig()
├── WizardConfigBuilder.cs        # Config assembly (needs merge mode)
├── IWizardStepViewModel.cs       # Step interface + NavigationDirection
├── HealthCheckRunner.cs          # Health check collection
└── Steps/
    ├── ProviderStepViewModel.cs
    ├── SecurityPostureStepViewModel.cs
    ├── SlackStepViewModel.cs
    ├── ChannelsStepViewModel.cs
    ├── SearchStepViewModel.cs
    ├── BrowserAutomationStepViewModel.cs
    ├── IdentityStepViewModel.cs
    └── HealthCheckStepViewModel.cs

src/Netclaw.Cli/Config/
├── ConfigFileHelper.cs           # Load/merge/write utilities (ready to use)
└── ProviderCredentialWriter.cs   # Merge pattern proof-of-concept

docs/prd/PRD-004-cli-onboarding-and-config.md  # Reentrant init requirement

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions