restore: reset past source tree deletion, apply pending work

This commit is contained in:
Timmy
2026-03-27 10:49:39 +00:00
parent 04214ca155
commit 3571511349
21 changed files with 2799 additions and 37 deletions
@@ -1,31 +0,0 @@
---
name: "CLI --port flag with project.toml persistence"
---
# Story 399: CLI --port flag with project.toml persistence
## User Story
As a developer, I want to set the server port via a --port CLI flag that persists to project.toml, so that I don't have to remember an environment variable on every run.
## Acceptance Criteria
- [ ] `storkit --help` shows a `--port` option
- [ ] `storkit --port 4000` starts the server on port 4000
- [ ] After first run with `--port`, the port is saved to `project.toml`
- [ ] On subsequent runs without `--port`, the port from `project.toml` is used
- [ ] CLI `--port` overrides the value in `project.toml`
- [ ] Default port is 3001 when neither `--port` nor `project.toml` port is set
- [ ] `STORKIT_PORT` env var is removed — no longer read or respected
- [ ] `.storkit_port` lock file mechanism is removed (`write_port_file` / `remove_port_file`)
## Out of Scope
- Docker compose changes (can update `STORKIT_PORT` references separately)
- Adding other CLI flags beyond `--port`
## Technical Notes
Port resolution priority: `--port` flag > `project.toml` `port` field > default 3001
The port should be written to `project.toml` on startup so subsequent runs remember it. Use the existing `config.rs` / `ProjectConfig` struct — add a `port` field.
@@ -1,45 +0,0 @@
---
name: "WhatsApp and Slack missing reset command handler"
---
# Bug 400: WhatsApp and Slack missing reset command handler
## Description
The reset command has a fallback handler in chat/commands/mod.rs that returns None with a comment saying it's handled before try_handle_command. This is only true for Matrix. WhatsApp and Slack don't have pre-dispatch handling, so None causes fallthrough to LLM. This caused a real outage when stale session IDs couldn't be cleared via the bot after switching from Docker to bare-metal.
## Implementation Note
Follow the **rebuild pattern** established in story 402, with one complication: `handle_reset` in `server/src/chat/transport/matrix/reset.rs` takes a Matrix-specific `ConversationHistory` (`Arc<TokioMutex<HashMap<OwnedRoomId, RoomConversation>>>`), so it cannot be called directly from WhatsApp or Slack.
**WhatsApp session storage** (`server/src/chat/transport/whatsapp.rs`):
- Type: `WhatsAppConversationHistory = Arc<TokioMutex<HashMap<String, RoomConversation>>>` (key = sender phone number)
- Persisted to `.storkit/whatsapp_history.json` via `save_whatsapp_history`
**Slack session storage** (`server/src/chat/transport/slack.rs`):
- Type: `SlackConversationHistory = Arc<TokioMutex<HashMap<String, RoomConversation>>>` (key = channel ID)
- Persisted to `.storkit/slack_history.json` via `save_slack_history`
**Approach:**
- Use `extract_reset_command` from `server/src/chat/transport/matrix/reset.rs` to detect the command (it works transport-agnostically)
- Implement the reset inline in each transport's async message handler: clear `session_id` and `entries` for the sender/channel key, call the transport's own `save_*_history`, reply with confirmation
- Add async intercepts in `whatsapp.rs` (~line 1107, after the rebuild intercept) and `slack.rs` (~line 845, after the rebuild intercept)
- The fallback handler in `chat/commands/mod.rs` (`handle_reset_fallback`) stays as-is
## How to Reproduce
1. Configure bot with transport = "whatsapp" or "slack"\n2. Send "reset" to the bot\n3. Check server logs
## Actual Result
Log shows "No command matched, forwarding to LLM" — reset is sent to the LLM as a conversational message instead of clearing the session.
## Expected Result
The bot clears the sender's session_id from conversation history and replies with confirmation like "Session cleared."
## Acceptance Criteria
- [ ] WhatsApp transport handles reset command: clears sender session_id and replies with confirmation
- [ ] Slack transport handles reset command: clears channel session_id and replies with confirmation
- [ ] Fallback handler in chat/commands/mod.rs no longer silently swallows the reset command
@@ -1,35 +0,0 @@
---
name: "WhatsApp and Slack missing start command handler"
---
# Bug 401: WhatsApp and Slack missing start command handler
## Description
The start command has a fallback handler in chat/commands/mod.rs that returns None. Only Matrix has pre-dispatch handling for this command. On WhatsApp and Slack, the command falls through to the LLM path.
## Implementation Note
Follow the **rebuild pattern** established in story 402.
- `extract_start_command` and `handle_start` already exist in `server/src/chat/transport/matrix/start.rs`
- Add an async intercept in `server/src/chat/transport/whatsapp.rs` (see rebuild intercept ~line 1107) and `server/src/chat/transport/slack.rs` (see rebuild intercept ~line 845)
- Call `crate::chat::transport::matrix::start::extract_start_command` to detect the command, then `crate::chat::transport::matrix::start::handle_start` to execute it
- The fallback handler in `chat/commands/mod.rs` (`handle_start_fallback`) stays as-is — it exists only so `help` lists the command
## How to Reproduce
1. Configure bot with transport = "whatsapp" or "slack"\n2. Send "start <story_id>" to the bot\n3. Check server logs
## Actual Result
Command falls through to LLM instead of starting an agent.
## Expected Result
The bot starts an agent for the specified story and replies with confirmation.
## Acceptance Criteria
- [ ] WhatsApp transport handles start command: starts agent and replies with confirmation
- [ ] Slack transport handles start command: starts agent and replies with confirmation
@@ -1,30 +0,0 @@
---
name: "Auto-refresh expired OAuth token for Claude Code PTY"
---
# Story 405: Auto-refresh expired OAuth token for Claude Code PTY
## User Story
As a storkit user with a Claude Max subscription, I want the server to automatically refresh my expired OAuth token so that chat, Matrix, and WhatsApp integrations don't stop working when the token expires.
## Acceptance Criteria
### Detection
- [ ] When the Claude Code PTY returns an `authentication_failed` error, storkit detects it instead of passing the raw 401 JSON to the user
### Auto-refresh (credentials exist, refresh token valid)
- [ ] Storkit reads the OAuth refresh token from `~/.claude/.credentials.json`
- [ ] Storkit calls the Anthropic OAuth token refresh endpoint (`https://console.anthropic.com/v1/oauth/token` with `grant_type=refresh_token`) to obtain a new access token
- [ ] Storkit writes the refreshed access token (and new expiresAt) back to `~/.claude/.credentials.json`
- [ ] After a successful refresh, storkit automatically retries the original chat request
- [ ] The refresh+retry is transparent to the user — they see no error
### Full login required (no credentials, or refresh token also expired)
- [ ] If `.credentials.json` doesn't exist or the refresh call itself fails, storkit surfaces a clear error: "OAuth session expired. Please run `claude login` to re-authenticate."
- [ ] The error message is surfaced through the normal chat stream (not just server logs)
## Out of Scope
- Implementing the full interactive `claude login` browser OAuth flow inside storkit
- Proactive token refresh before expiry (refreshing on demand when the error occurs is sufficient)
@@ -1,21 +0,0 @@
---
name: "Browser-based OAuth login flow from web UI and chat integrations"
---
# Story 406: Browser-based OAuth login flow from web UI and chat integrations
## User Story
As a new storkit user (or one whose refresh token has expired), I want to complete the full Claude OAuth login flow from the web UI, Matrix, or WhatsApp so that I don't need terminal access to run `claude login`.
## Acceptance Criteria
- [ ] From the web UI, the user can initiate OAuth login — storkit generates the Anthropic authorize URL and opens it in a new tab
- [ ] After the user authenticates in the browser, the OAuth callback writes accessToken, refreshToken, and expiresAt to ~/.claude/.credentials.json
- [ ] From Matrix or WhatsApp, storkit sends the user a clickable OAuth authorize link when credentials are missing or fully expired
- [ ] After successful login, the user can immediately start chatting without restarting storkit
- [ ] If the OAuth callback fails or the user cancels, a clear error is shown
## Out of Scope
- TBD