feat: add heartbeat/ping to terminal WebSocket
- Backend: Send ping every 30s from WebSocket endpoint - Frontend: Respond to pings with pongs, detect missed pings (60s timeout) - Update type definitions to include 'resetting' status Refs: persistent-terminal-sessions task 6.4
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Profile Ownership And Scope
|
||||
The system SHALL manage config profiles as user-owned launch configuration records with optional project and tool type references that derive compatibility scope.
|
||||
|
||||
#### Scenario: Create portable profile
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** they create a config profile without a project or tool type
|
||||
- **THEN** the profile is stored for that user
|
||||
- **AND** the profile is compatible with any project and tool type owned or accessible by that user
|
||||
|
||||
#### Scenario: Create scoped profile
|
||||
- **GIVEN** an authenticated user with access to a project and a tool type
|
||||
- **WHEN** they create a config profile with `project_id`, `tool_type_id`, or both
|
||||
- **THEN** the profile is stored with those references
|
||||
- **AND** compatibility is derived from the non-null references
|
||||
|
||||
#### Scenario: Reject cross-user references
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** they create or update a profile with a project, tool type, include, or default reference they cannot access
|
||||
- **THEN** the request is rejected
|
||||
|
||||
### Requirement: Profile Content
|
||||
The system SHALL store profile content as plain environment variables, runtime hints, and one or more mount roots containing UTF-8 text files.
|
||||
|
||||
#### Scenario: Save env vars and runtime hints
|
||||
- **GIVEN** an authenticated user editing a config profile
|
||||
- **WHEN** they save plain-text environment variables and runtime hints such as start command, working directory, and port
|
||||
- **THEN** the system persists those values on the profile
|
||||
- **AND** returns them through the profile API
|
||||
|
||||
#### Scenario: Save mounted text files
|
||||
- **GIVEN** an authenticated user editing a config profile
|
||||
- **WHEN** they add a mount with an absolute `target_path`, mode `ro` or `rw`, and relative UTF-8 text file paths
|
||||
- **THEN** the system persists the mount and files
|
||||
- **AND** preserves file content exactly as UTF-8 text
|
||||
|
||||
#### Scenario: Reject unsafe file paths
|
||||
- **GIVEN** an authenticated user editing a config profile mount
|
||||
- **WHEN** they submit an absolute file path, an empty relative path, or a relative path containing `..`
|
||||
- **THEN** the request is rejected
|
||||
|
||||
### Requirement: Ordered Profile Includes
|
||||
The system SHALL allow a config profile to include other compatible profiles in a deterministic order.
|
||||
|
||||
#### Scenario: Add ordered includes
|
||||
- **GIVEN** an authenticated user with multiple config profiles
|
||||
- **WHEN** they configure profile A to include profile B then profile C
|
||||
- **THEN** the include order is stored
|
||||
- **AND** resolution processes B before C before A
|
||||
|
||||
#### Scenario: Reject include cycle on save
|
||||
- **GIVEN** an authenticated user with profiles A and B where A already includes B
|
||||
- **WHEN** they update B to include A
|
||||
- **THEN** the request is rejected with a cycle error
|
||||
|
||||
#### Scenario: Guard against cycle during resolution
|
||||
- **GIVEN** stored profile include data contains a cycle
|
||||
- **WHEN** the system resolves a selected profile
|
||||
- **THEN** resolution fails safely without launching a partially resolved configuration
|
||||
|
||||
### Requirement: Profile Resolution
|
||||
The system SHALL resolve a selected profile by recursively applying included profiles in order and then applying the selected profile itself.
|
||||
|
||||
#### Scenario: Resolve layered env vars
|
||||
- **GIVEN** profile A includes profile B then profile C
|
||||
- **AND** B, C, and A define the same environment variable
|
||||
- **WHEN** profile A is resolved
|
||||
- **THEN** the value from A wins over C and B
|
||||
- **AND** the value from C wins over B for keys not set by A
|
||||
|
||||
#### Scenario: Resolve mount file conflicts
|
||||
- **GIVEN** multiple resolved layers define the same mount `target_path`
|
||||
- **WHEN** they contain different files under that mount
|
||||
- **THEN** their file trees are merged
|
||||
- **AND** later layers replace earlier content for the same relative file path
|
||||
|
||||
#### Scenario: Resolve mount mode conflicts
|
||||
- **GIVEN** multiple resolved layers define the same mount `target_path` with different modes
|
||||
- **WHEN** the profile is resolved
|
||||
- **THEN** the mode from the latest layer wins
|
||||
|
||||
### Requirement: Profile Defaults
|
||||
The system SHALL select the default compatible profile by explicit default specificity, then by first created compatible profile, then no profile.
|
||||
|
||||
#### Scenario: Choose most specific explicit default
|
||||
- **GIVEN** a user has explicit default profiles for global, tool, project, and project+tool scopes
|
||||
- **WHEN** they start a matching project/tool combination
|
||||
- **THEN** the project+tool default is selected
|
||||
- **AND** project, tool, and global defaults are used only when no more-specific explicit default matches
|
||||
|
||||
#### Scenario: Fall back to first compatible profile
|
||||
- **GIVEN** a user has compatible profiles but no explicit matching default
|
||||
- **WHEN** they start a session for a project/tool combination
|
||||
- **THEN** the oldest compatible profile is selected by default
|
||||
|
||||
#### Scenario: No compatible profile
|
||||
- **GIVEN** a user has no compatible profile for a project/tool combination
|
||||
- **WHEN** they start a session
|
||||
- **THEN** the default profile selection is `None`
|
||||
|
||||
### Requirement: Profile Compatibility Filtering
|
||||
The system SHALL list compatible config profiles for a selected project and tool type by default.
|
||||
|
||||
#### Scenario: List compatible profiles
|
||||
- **GIVEN** an authenticated user has portable, project-specific, tool-specific, and unrelated profiles
|
||||
- **WHEN** the launch UI requests profiles for a selected project and tool type
|
||||
- **THEN** the response includes portable profiles and profiles matching that project, tool type, or both
|
||||
- **AND** excludes unrelated project-specific or tool-specific profiles
|
||||
|
||||
### Requirement: Resolved Profile Preview
|
||||
The system SHALL expose a resolved profile preview for a selected profile and project/tool context.
|
||||
|
||||
#### Scenario: Preview resolved output
|
||||
- **GIVEN** an authenticated user selects a compatible config profile
|
||||
- **WHEN** they request a resolved preview
|
||||
- **THEN** the response includes the final environment variables, runtime hints, mount targets, mount modes, and relative file paths
|
||||
- **AND** indicates overridden values where practical
|
||||
@@ -0,0 +1,29 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Tool config supports runtime fields
|
||||
The system SHALL keep tool config runtime fields available for tool configuration, while reusable launch setup for user-owned files, mounts, and env var bundles SHALL be handled by config profiles.
|
||||
|
||||
#### Scenario: Create config with runtime fields
|
||||
- **WHEN** user creates a tool config with start_command="npm start", port=3000, working_directory="/app"
|
||||
- **THEN** the config is saved with all fields populated
|
||||
|
||||
#### Scenario: Environment variables as JSON
|
||||
- **WHEN** user sets environment_variables to {"NODE_ENV": "production", "API_KEY": "secret"}
|
||||
- **THEN** the system stores and returns the config with the JSON object preserved
|
||||
- **AND** reusable per-launch environment bundles are managed through config profiles
|
||||
|
||||
#### Scenario: Volumes as JSON
|
||||
- **WHEN** user sets volumes to [{"host": "/data", "container": "/app/data", "mode": "rw"}]
|
||||
- **THEN** the system stores and returns the config with the JSON array preserved
|
||||
- **AND** user-owned mounted file trees are managed through config profiles
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Active config folders auto-mount during launch
|
||||
The system SHALL NOT automatically mount all active config folders when starting tool instances.
|
||||
|
||||
#### Scenario: Start instance after config profiles replace folders
|
||||
- **GIVEN** a user has legacy active config folders
|
||||
- **WHEN** they start a tool instance without selecting a config profile
|
||||
- **THEN** those folders are not automatically mounted
|
||||
- **AND** only selected config profile output is applied for user-owned launch files and mounts
|
||||
@@ -0,0 +1,55 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Clone mode instance creation
|
||||
The system SHALL support creating tool instances with a clone mode and an optional selected config profile.
|
||||
|
||||
#### Scenario: Create instance in clone mode
|
||||
- **GIVEN** an authenticated user with a repository that has an SSH key and remote URL
|
||||
- **WHEN** they create an instance with `clone_mode: "clone"`, `branch: "main"`, and a compatible config profile selection
|
||||
- **THEN** the system clones the repository into the instance directory
|
||||
- **AND** the compose file uses the clone path as `REPO_PATH`
|
||||
- **AND** the instance record stores `clone_mode="clone"`, `branch="main"`, and the selected config profile ID
|
||||
|
||||
#### Scenario: Create instance in mount mode
|
||||
- **GIVEN** an authenticated user with a repository
|
||||
- **WHEN** they create an instance with `clone_mode: "mount"` (or omit the field)
|
||||
- **THEN** the compose file uses the host repository path as `REPO_PATH`
|
||||
- **AND** the instance record stores `clone_mode="mount"`
|
||||
|
||||
#### Scenario: Create instance with no config profile
|
||||
- **GIVEN** an authenticated user creating a tool instance
|
||||
- **WHEN** they select `None` for config profile
|
||||
- **THEN** the instance record stores no selected config profile
|
||||
- **AND** profile-owned env vars, files, mounts, and runtime hints are not applied at start
|
||||
|
||||
#### Scenario: Reject incompatible config profile selection
|
||||
- **GIVEN** an authenticated user creating a tool instance for a project and tool type
|
||||
- **WHEN** they select a config profile scoped to a different project or tool type
|
||||
- **THEN** instance creation or start is rejected
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Config profile launch application
|
||||
The system SHALL apply the selected config profile's resolved output when starting a tool instance.
|
||||
|
||||
#### Scenario: Start instance with selected profile
|
||||
- **GIVEN** a pending tool instance with a selected compatible config profile
|
||||
- **WHEN** the instance is started
|
||||
- **THEN** the system resolves the selected profile
|
||||
- **AND** writes resolved env vars into the instance environment
|
||||
- **AND** stages resolved profile files under the instance directory
|
||||
- **AND** adds Docker bind mounts for resolved profile mounts
|
||||
- **AND** applies supported runtime hints before starting the container
|
||||
|
||||
#### Scenario: Restart uses stored profile selection
|
||||
- **GIVEN** an existing instance was started with config profile A
|
||||
- **AND** the user's default profile later changes to profile B
|
||||
- **WHEN** the instance is restarted
|
||||
- **THEN** the system uses stored profile A for restart behavior
|
||||
- **AND** does not switch to profile B automatically
|
||||
|
||||
#### Scenario: Start fails on profile resolution error
|
||||
- **GIVEN** an instance references a selected config profile that cannot be resolved
|
||||
- **WHEN** the instance is started
|
||||
- **THEN** the start request fails before launching the container
|
||||
- **AND** the error explains the profile resolution problem
|
||||
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Config Profile Settings Editor
|
||||
The system SHALL expose a settings interface for managing the authenticated user's config profiles.
|
||||
|
||||
#### Scenario: Browse config profiles in settings
|
||||
- **GIVEN** an authenticated user
|
||||
- **WHEN** they open settings
|
||||
- **THEN** they can view their config profiles
|
||||
- **AND** see each profile's name, compatibility scope, default status, and included profiles
|
||||
|
||||
#### Scenario: Edit profile content in settings
|
||||
- **GIVEN** an authenticated user editing a config profile
|
||||
- **WHEN** they update env vars, runtime hints, mounts, text files, or include order
|
||||
- **THEN** the settings UI saves those changes through the config profile API
|
||||
- **AND** validation errors are shown without losing the user's draft edits
|
||||
|
||||
#### Scenario: Configure profile defaults in settings
|
||||
- **GIVEN** an authenticated user editing config profiles
|
||||
- **WHEN** they mark a profile as the default for a global, project, tool, or project+tool context
|
||||
- **THEN** subsequent launches for matching contexts preselect that profile according to default specificity
|
||||
|
||||
### Requirement: Launch Profile Selection UI
|
||||
The system SHALL allow the authenticated user to select one compatible config profile or `None` when starting a session.
|
||||
|
||||
#### Scenario: Preselect default compatible profile
|
||||
- **GIVEN** an authenticated user has a default compatible profile for a selected project and tool type
|
||||
- **WHEN** they open the start session form
|
||||
- **THEN** the form preselects that profile
|
||||
- **AND** also offers `None` as a selectable option
|
||||
|
||||
#### Scenario: Select no profile
|
||||
- **GIVEN** an authenticated user starts a session
|
||||
- **WHEN** they choose `None` in the config profile selector
|
||||
- **THEN** the start request records no selected config profile
|
||||
Reference in New Issue
Block a user