feat: terminal startup command and container tools

- Add startup_command field to ToolType model and API
- Execute startup command before interactive shell in terminal sessions
- Add tmux and ranger to OpenCode container spec
- Update Tool Workshop UI with startup_command input for terminal types
- Add backend tests for startup_command CRUD operations
- Sync specs: tool-terminal, tool-types-definition, opencode-web-server
- New spec: tool-terminal-startup-command

Quality gates: Frontend typecheck/lint passed. Backend tests blocked by environment (Python/Docker not available).

OpenSpec: terminal-startup-and-container-tools
This commit is contained in:
OpenCode Agent
2026-05-24 22:21:55 +00:00
parent a4c429d53a
commit 01a0ef46c9
22 changed files with 1060 additions and 78 deletions
@@ -9,6 +9,8 @@ The system SHALL configure OpenCode containers to run a web server accessible on
- **WHEN** the container starts
- **THEN** a web server is running on port 3000 inside the container
- **AND** the server serves a web terminal interface
- **AND** the container has `tmux` installed
- **AND** the container has `ranger` installed
### Requirement: OpenCode exposes web interface
@@ -37,3 +39,4 @@ The system SHALL serve a functional web terminal interface for OpenCode.
- **WHEN** the user clicks the "Open" button
- **THEN** a new tab opens with the OpenCode web interface
- **AND** the interface shows a terminal connected to the OpenCode process
- **AND** the user can run `tmux` and `ranger` commands
@@ -0,0 +1,66 @@
# Terminal Startup Command Specification
## Purpose
Allow tool type authors to define a startup command that executes for each new terminal session.
## Requirements
### Requirement: Terminal tool types can define a startup command
The system SHALL allow tool types to specify a `startup_command` that runs before the interactive shell for each new terminal session.
#### Scenario: Tool type with startup command
- **GIVEN** a tool type with `interface_type` = "terminal" and `startup_command` = "cd /workspace && ls"
- **WHEN** a user opens a terminal session to an instance of this tool type
- **THEN** the startup command executes before the interactive shell starts
- **AND** the user sees the output of the startup command in the terminal
#### Scenario: Tool type without startup command
- **GIVEN** a tool type with `interface_type` = "terminal" and no `startup_command`
- **WHEN** a user opens a terminal session
- **THEN** the interactive shell starts immediately without any startup execution
#### Scenario: Startup command failure does not block shell
- **GIVEN** a tool type with `startup_command` = "exit 1"
- **WHEN** a user opens a terminal session
- **THEN** the startup command runs and fails
- **AND** the interactive shell still starts afterward
### Requirement: Startup command is stored on the tool type
The system SHALL persist `startup_command` as a field on the `tool_types` table.
#### Scenario: Create tool type with startup command
- **GIVEN** a user creating a tool type
- **WHEN** they provide `startup_command` = "source /etc/profile"
- **THEN** the tool type is created with the startup command stored
#### Scenario: Update tool type startup command
- **GIVEN** an existing tool type with a startup command
- **WHEN** an admin updates `startup_command` to a new value
- **THEN** the tool type is updated
- **AND** new terminal sessions use the updated startup command
### Requirement: Startup command is optional
The system SHALL treat `startup_command` as an optional field on tool types.
#### Scenario: Create tool type without startup command
- **GIVEN** a user creating a terminal tool type
- **WHEN** they omit `startup_command`
- **THEN** the tool type is created successfully
- **AND** terminal sessions start normally without a startup command
## Dependencies
- tool-types-definition (model and API)
- tool-terminal (session execution)
## Quality Gates
- `pytest` must pass
- `mypy .` must pass
- `ruff check .` must pass
- `npm run typecheck` must pass
- `npm run lint` must pass
+19
View File
@@ -16,6 +16,19 @@ The system SHALL provide terminal sessions via WebSocket.
- THEN a WebSocket connection is established
- AND a shell is spawned in the container via `docker exec`
#### Scenario: Open terminal with startup command
- GIVEN a running tool instance with a tool type that has `startup_command` set
- WHEN the user opens the terminal
- THEN a WebSocket connection is established
- AND the startup command is executed before the interactive shell
- AND the shell is spawned in the container via `docker exec`
#### Scenario: Open terminal without startup command
- GIVEN a running tool instance with a tool type that has no `startup_command`
- WHEN the user opens the terminal
- THEN a WebSocket connection is established
- AND the shell spawns directly without any startup execution
### Requirement: Terminal I/O
The system SHALL stream terminal I/O via WebSocket.
@@ -51,6 +64,12 @@ The system SHALL manage terminal sessions.
- THEN the session is cleaned up
- AND the shell process is terminated
#### Scenario: Reset terminal session runs startup command
- GIVEN an active terminal session
- WHEN the user resets the session
- THEN a new shell is spawned
- AND the startup command executes before the new interactive shell
### Requirement: Access Control
The system SHALL restrict terminal access.
+8 -2
View File
@@ -18,6 +18,7 @@ The system SHALL provide a `ToolType` model to store tool definitions.
- `dockerfile_template`: Dockerfile string
- `definition_type`: string — "compose" or "dockerfile"
- `required_variables`: list of required template variables
- `startup_command`: optional text — command to run before interactive shell for terminal sessions
- `is_builtin`: boolean flag for system-defined types
- `created_at`/`updated_at`: timestamps
@@ -39,6 +40,7 @@ The system SHALL provide REST API endpoints for tool type management.
- AND validates `requires_port` is boolean
- AND validates the compose template YAML (if definition_type is "compose")
- AND validates all required variables are present in template
- AND accepts optional `startup_command` field
- AND returns 201 Created with the new tool type
#### Scenario: Get tool type
@@ -51,10 +53,14 @@ The system SHALL provide REST API endpoints for tool type management.
- GIVEN an admin user
- WHEN they PUT /api/tool-types/{id} with valid data
- THEN the system updates the tool type
- AND validates `interface_type` is "web" or "terminal" if provided
- AND re-validates the compose template
- AND accepts optional `startup_command` field
- AND returns 200 OK with updated tool type
#### Scenario: Get tool type includes startup command
- GIVEN an authenticated user
- WHEN they GET /api/tool-types/{id}
- THEN the response includes `startup_command` if set
#### Scenario: Delete tool type
- GIVEN an admin user
- WHEN they DELETE /api/tool-types/{id}