Add Gherkin feature files for interactive TUI session

Amolith created

Specify the interactive session behaviour across four feature files:

- session_shell: terminal session lifecycle, theme detection, colour
  palette, help bar, breadcrumb, screen titles, and Ctrl+C handling
- navigation: Esc back-navigation, state retention, screen skipping
  when values are already resolved, and CLI-provided value handling
- restore_flow: restore-specific screens for snapshot selection, file
  picking, target directory, and overwrite behaviour
- command_preview: confirmation screen, command execution, and
  --show-command integration

Add bubbletint/v2 dependency for terminal colour palette support.

Change summary

features/command_preview.feature | 34 +++++++++++++
features/navigation.feature      | 68 +++++++++++++++++++++++++++
features/restore_flow.feature    | 84 ++++++++++++++++++++++++++++++++++
features/session_shell.feature   | 82 +++++++++++++++++++++++++++++++++
go.mod                           |  1 
go.sum                           |  2 
6 files changed, 271 insertions(+)

Detailed changes

features/command_preview.feature 🔗

@@ -0,0 +1,34 @@
+Feature: Command preview and execution
+
+  Before handing off to restic, the session shows the resolved
+  command and asks the user to confirm. This gives the user a
+  chance to review what will run and go back to correct mistakes.
+
+  Rule: The confirmation screen shows the resolved restic command
+
+    Scenario: Reviewing the command before execution
+      Given the user has completed all required screens
+      When the confirmation screen is shown
+      Then it displays the resolved restic command line
+      And it displays any environment variables that will be set
+      And the user can confirm to proceed
+
+    Scenario: Confirming execution
+      Given the confirmation screen is showing
+      When the user confirms
+      Then restic is executed with the resolved configuration
+
+    Scenario: Going back from the confirmation screen
+      Given the confirmation screen is showing
+      When the user presses Esc
+      Then they return to the last visible screen of the flow
+      And their previous answers are preserved
+
+  Rule: --show-command prints the command and exits without executing
+
+    Scenario: --show-command in interactive mode
+      Given the user launched keld interactively with --show-command
+      When the confirmation screen would normally appear
+      Then the resolved command is printed as text
+      And the output format matches non-interactive --show-command
+      And the session exits without executing restic

features/navigation.feature 🔗

@@ -0,0 +1,68 @@
+Feature: Navigation and state retention
+
+  Users navigate forward through screens by making selections, and
+  backward with Esc. The session remembers previous answers so users
+  can review and revise without re-entering everything.
+
+  Rule: Esc navigates back one visible screen at a time
+
+    Scenario: Going back from a command-specific screen
+      Given the user is on the first screen of a command flow
+      When they press Esc
+      Then the preset selection screen is shown
+      And their previous preset choice is preserved
+
+    Scenario: Going back from the preset selection
+      Given the user is on the preset selection screen
+      When they press Esc
+      Then the command menu is shown
+      And their previous command selection is highlighted
+
+    Scenario: Going back step by step through a multi-screen flow
+      Given the user has progressed through several screens
+      When they press Esc repeatedly
+      Then they step back through each previously-visited screen
+      And each screen shows their earlier answer
+
+    Scenario: Esc on the command menu exits the session
+      Given the user is on the command menu
+      When they press Esc
+      Then the session exits without executing restic
+
+  Rule: Screens are skipped when the needed value is already resolved
+
+    Scenario: Command provided on the command line
+      Given the user invokes keld with a command argument
+      Then the command menu is not shown
+      And the session begins at the preset selection
+
+    Scenario: Preset provided on the command line
+      Given the user invokes keld with --preset
+      Then the preset selection screen is not shown
+
+    Scenario: No presets defined in configuration
+      Given the configuration defines no presets
+      Then the preset selection screen is not shown
+
+    Scenario: Exactly one preset defined
+      Given the configuration defines exactly one preset
+      Then that preset is selected automatically
+      And the preset selection screen is not shown
+
+    Scenario: All required values already resolved
+      Given the command, preset, and all command-specific values are already provided
+      Then the session skips directly to the confirmation screen
+
+  Rule: Skipped screens are also skipped during back navigation
+
+    Scenario: Navigating back past a skipped screen
+      Given a screen was skipped because its value was already resolved
+      When the user navigates back from the screen after it
+      Then they land on the screen before the skipped one
+
+  Rule: CLI-provided values are always skipped regardless of navigation
+
+    Scenario: CLI-provided values cannot be reached via back navigation
+      Given the user provided a value on the command line
+      Then that value's screen is never shown
+      And back navigation passes over it in both directions

features/restore_flow.feature 🔗

@@ -0,0 +1,84 @@
+Feature: Restore interactive flow
+
+  The restore flow guides the user through selecting a snapshot,
+  optionally choosing specific files, setting a target directory,
+  and choosing overwrite behaviour. Each step is skipped when the
+  resolved configuration already provides the needed value.
+
+  Background:
+    Given the user has selected the "restore" command
+
+  Rule: A snapshot is selected from the repository or entered manually
+
+    Scenario: Snapshots loaded from the repository
+      Given the repository is accessible
+      When the snapshot selection screen is reached
+      Then a spinner is shown while snapshots are fetched
+      And the fetched snapshots are presented in a filterable list
+
+    Scenario: Snapshot listing fails
+      Given the repository is not accessible
+      When the snapshot selection screen is reached
+      Then an error notice is displayed
+      And the user is offered a text input for manual snapshot ID entry
+
+    Scenario: No snapshots in the repository
+      Given the repository contains no snapshots
+      When the snapshot selection screen is reached
+      Then a notice indicates the repository is empty
+      And the user is offered a text input for manual snapshot ID entry
+
+    Scenario: Snapshot ID already provided
+      Given a snapshot ID is already resolved
+      Then the snapshot selection screen is not shown
+
+  Rule: The user may select specific files to restore from the snapshot
+
+    Scenario: File listing loaded from the snapshot
+      Given a snapshot has been selected
+      When the file selection screen is reached
+      Then a spinner is shown while the file listing is fetched
+      And a file picker is presented for the snapshot's contents
+
+    Scenario: Full restore when all files are selected
+      Given the file picker is showing
+      When the user confirms with all files selected
+      Then no include paths are added to the restore command
+
+    Scenario: Partial restore when specific files are selected
+      Given the file picker is showing
+      When the user selects specific files and confirms
+      Then the selected paths are added as include paths
+
+    Scenario: File listing fetch fails
+      Given a snapshot has been selected
+      When the file listing cannot be fetched
+      Then a notice is displayed
+      And the file picker is skipped
+      And the flow proceeds with a full restore
+
+    Scenario: File selection already configured
+      Given include paths are already resolved
+      Then the file selection screen is not shown
+
+  Rule: A target directory is specified for the restored files
+
+    Scenario: Target directory prompted
+      Given no target directory is resolved
+      When the target directory screen is reached
+      Then a text input prompts for the restore destination
+
+    Scenario: Target directory already configured
+      Given a target directory is already resolved
+      Then the target directory screen is not shown
+
+  Rule: The overwrite behaviour is chosen before restoring
+
+    Scenario: Overwrite behaviour prompted
+      Given no overwrite behaviour is resolved
+      When the overwrite screen is reached
+      Then a selector presents the available overwrite options
+
+    Scenario: Overwrite behaviour already configured
+      Given an overwrite behaviour is already resolved
+      Then the overwrite screen is not shown

features/session_shell.feature 🔗

@@ -0,0 +1,82 @@
+Feature: Interactive session shell
+
+  The interactive session provides a single, cohesive terminal interface
+  for all of keld's interactive flows. It manages the visual frame —
+  theme, help bar, breadcrumb, and cancellation — so that individual
+  screens do not have to.
+
+  Rule: The interface runs as a single continuous terminal session
+
+    Scenario: Transitioning between screens
+      Given the user launches keld interactively
+      When they progress from one screen to the next
+      Then the interface transitions directly without returning to the shell
+
+  Rule: The terminal background is detected once and determines the colour palette
+
+    Scenario: Dark terminal
+      Given the terminal has a dark background
+      When the session starts
+      Then the dark colour palette is used for all screens
+
+    Scenario: Light terminal
+      Given the terminal has a light background
+      When the session starts
+      Then the light colour palette is used for all screens
+
+    Scenario: Background detection is unavailable
+      Given the terminal background cannot be detected
+      When the session starts
+      Then the dark colour palette is used as a default
+
+  Rule: Colour is used intentionally to highlight actionable elements
+
+    Scenario: Body text uses the terminal's default foreground
+      Given any screen in the session
+      Then descriptive and body text is not styled with a custom colour
+
+    Scenario: No text is rendered in a muted or dim style
+      Given any screen in the session
+      Then all text is rendered at full brightness
+
+  Rule: A help bar at the bottom shows available key bindings for the current screen
+
+    Scenario: Help bar reflects the current screen
+      Given the user is on any screen
+      Then the help bar shows the key bindings relevant to that screen
+      And the help bar uses the same visual format on every screen
+
+  Rule: The highlighted item in any list is indicated with a consistent cursor
+
+    Scenario: Cursor on a selectable list
+      Given any screen with a selectable list
+      Then the highlighted item is marked with a consistent visual indicator
+
+  Rule: A breadcrumb at the top shows the path of selections made so far
+
+    Scenario: No breadcrumb on the first screen
+      Given the user is on the command menu
+      Then no breadcrumb is displayed
+
+    Scenario: Breadcrumb builds as selections are made
+      Given the user has selected a command and a preset
+      When they reach a command-specific screen
+      Then the breadcrumb shows their prior selections in order
+
+    Scenario: Breadcrumb updates on back navigation
+      Given the user has progressed several screens into a flow
+      When they navigate back one step
+      Then the breadcrumb removes the most recent selection
+
+  Rule: The current screen's title is displayed below the breadcrumb
+
+    Scenario: Screen title is always visible
+      Given the user is on any screen
+      Then the screen's title is displayed below the breadcrumb
+
+  Rule: Ctrl+C exits the session cleanly from any screen
+
+    Scenario: Cancelling during a flow
+      Given the user is on any screen
+      When they press Ctrl+C
+      Then the session exits without executing restic

go.mod 🔗

@@ -28,6 +28,7 @@ require (
 	github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
+	github.com/lrstanley/bubbletint/v2 v2.0.1 // indirect
 	github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
 	github.com/mattn/go-runewidth v0.0.20 // indirect
 	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect

go.sum 🔗

@@ -57,6 +57,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/lrstanley/bubbletint/v2 v2.0.1 h1:ELxRFzrm9X5DIz7Y1Yp0gfGhsJo+4U3w8WJe6x/Beso=
+github.com/lrstanley/bubbletint/v2 v2.0.1/go.mod h1:fL833lvIEbec7VBi9F8wZ/1008jBiDrvQtuIac9AG/k=
 github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
 github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=