Improve reconnection reliability and surface disconnect events in chat#89
Closed
zmanian wants to merge 185 commits intomcintyre94:mainfrom
Closed
Improve reconnection reliability and surface disconnect events in chat#89zmanian wants to merge 185 commits intomcintyre94:mainfrom
zmanian wants to merge 185 commits intomcintyre94:mainfrom
Conversation
Inspired by the Chowder iOS app's approach to showing AI activity:
instead of a generic bouncing-dots indicator, show what Claude is
actually doing ("Running npm test...", "Reading config.ts...") with
a shimmer animation, and render completed tools as compact step rows
with elapsed time rather than bordered expandable cards.
- ThinkingShimmerView: pulsing purple dot + shimmer gradient text
- ToolStepRow: compact icon + label + elapsed time, tap for details
- ToolDetailSheet: half-sheet with input/output for completed tools
- Haptic feedback on tool completion (light) and first text (medium)
- ToolUseCard.result links tool uses to their results for elapsed time
- 10 new tests for activityLabel, elapsedString, and result linking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ActivityKit Live Activity shows Claude's progress in the Dynamic Island and Lock Screen while the app is backgrounded. Compact view shows a status dot and current intent; expanded view adds sprite name, step count, and previous completed intent. Lock Screen banner shows intent card stack with depth effect and a live timer. New files: WispActivityAttributes (shared model), LiveActivityManager (debounced singleton), WispActivityWidget extension (WispLiveActivity + bundle). ChatViewModel hooks start/update/end the activity at tool use, tool result, first text response, and result events. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Truncate userTask (200 chars) and intent strings (100 chars) to stay under ActivityKit's 4KB payload limit. Surface startActivity failures via return value and lastError property. Improve logging with activity IDs. Bump build to 4 for TestFlight. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lower URLRequest timeoutInterval from 3600s to 120s on both service streaming methods so silently dropped connections trigger reconnect within 2 minutes instead of hanging for up to an hour. Replace silent try? decode with do/catch + logging to surface malformed service events that could cause the stream loop to wait indefinitely. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document thinking shimmer, inline tool steps, Dynamic Island Live Activity, and stream reliability improvements over upstream. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace regex-based code highlighter with tree-sitter AST parsing for correct syntax highlighting across 11 languages (Swift, Python, JS, TS, Rust, Go, Bash, JSON, YAML, HTML, CSS). Add unified diff view for Edit tool results, custom markdown theme, screenshot previews, and various dashboard/auth UI improvements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace default iOS blue with sprites green for AccentColor asset, user chat bubbles, send button, and thinking shimmer dot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts keeping Live Activity features from branch, upstream's streaming/typing sync fix, auto-checkpoint setting, swipe-to-delete restoration, queriesURL syntax highlighting fix, and init-time diff computation optimization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…esponse - Queue prompt without adding to messages; PendingUserBubbleView renders it - Add user message to messages only when execution actually starts - PendingUserBubbleView: faded blue bubble with a "Queued" clock label Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve conflicts in ChatViewModel (duplicate cancelQueuedPrompt), ChatInputBar (send button tint), ChatView (pending bubble edit/cancel, duplicate onChange), and PendingUserBubbleView (take upstream edit+cancel buttons over local swipe-to-dismiss). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace confirmationDialog with inline Menu on attachment button - Add AttachedFile model and attachment chips view instead of raw paths - Show removable capsule chips above input bar for pending attachments - Add upload success feedback with auto-clearing filename indicator - Convert SpriteFileBrowserView from binding to callback pattern - Change file browser loading label to "Connecting to sprite..." - Fix duplicate PendingUserBubbleView entry in project file Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Render TodoWrite tool uses as a dedicated plan card instead of a generic tool step row. Shows todo items with status-colored icons (completed, in_progress, pending), a progress counter, and collapsible item list that auto-collapses when the tool result arrives. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # Wisp/Assets.xcassets/AccentColor.colorset/Contents.json # Wisp/Assets.xcassets/AppIcon.appiconset/Contents.json # Wisp/Views/SpriteDetail/Chat/ChatInputBar.swift
Also strip alpha channel from app icon to fix App Store Connect upload validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SpritesAPIClient stream methods now use the existing instance decoder. GitHubAPIClient shares a single static decoder across all decode sites. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a shellEscape() helper for safe single-quote wrapping and apply it to all shell command construction sites: - ChatViewModel: workingDirectory, tokens, sessionId, MCP config - SpriteOverviewViewModel: GitHub and Sprites CLI token auth - ClaudeQuestionTool: validate sessionId chars in file paths/JSON Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # Wisp.xcodeproj/project.pbxproj
# Conflicts: # Wisp/Services/KeychainService.swift
# Conflicts: # Wisp/Views/SpriteDetail/Chat/ChatInputBar.swift
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously processServiceStream only upgraded status from .connecting to .streaming, so a reconnect that was actively receiving data stayed stuck on .reconnecting the whole time. Extend the same transition to also fire from .reconnecting so the UI reflects that streaming is live. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
reconnectIfNeeded now captures the service status it fetches rather than discarding it. If the service is already stopped, we pass serviceAlreadyStopped to reconnectToServiceLogs so it exits after a single log fetch instead of making a redundant status API call and looping. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously ChatViewModel was recreated on every chat switch, cancelling the active stream and requiring a reconnect on return. ChatSessionManager is an @observable cache keyed by chat UUID, injected app-wide, so VMs (and their streams) survive switching chats or navigating between sprites. switchToChat now looks up the cached VM instead of creating a new one. The scenePhase handler resumes all cached VMs on foreground, not just the active one. clearAllChats detaches all VMs before wiping the chat list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
# Conflicts: # Wisp.xcodeproj/project.pbxproj # Wisp/Views/SpriteDetail/Chat/ChatView.swift
Remove stale SideChat references in ChatView ThinkingShimmerView and remove invalid isStreaming parameter from ScreenshotPreviews. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…s-bda906b6' into zaki-main
…utputs-e3bc1cba' into zaki-main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t-6e54d330' into zaki-main # Conflicts: # Wisp/App/WispApp.swift
…87e' into zaki-main
Remove duplicate addAttachedFile tests and update ServiceInfo mock constructor to match new upstream API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Index user and assistant text content in SpriteChat.fullTextContent (updated on every saveMessages call). Wire up .searchable in both ChatSwitcherSheet (iPhone modal) and SpriteNavigationPanel (iPad/Mac sidebar) to filter chats by name or conversation content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a global Quick Messages store (SwiftData) with full CRUD in Settings, and a picker sheet accessible from the chat attachment menu that appends the selected message to the current input. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
# Conflicts: # Wisp/Views/QuickActions/QuickActionsView.swift
…ts-c59cf06d' into zaki-main # Conflicts: # Wisp/Views/SpriteDetail/Chat/ChatSwitcherSheet.swift
…af6' into zaki-main # Conflicts: # Wisp/App/WispApp.swift # Wisp/Views/SpriteDetail/Chat/ChatInputBar.swift # Wisp/Views/SpriteDetail/Chat/ChatView.swift
Add QuickMessage files to Xcode project, add QuickMessage.self to model container, fix ChatInputBar parameter order in ChatView. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass max_run_after_disconnect=300 on service creation so Claude keeps running for 5 minutes even if the client disconnects - Increase idle timeout from 30s to 45s to avoid false timeouts during Claude thinking pauses (requires 2+ missed heartbeats) - Increase post-stop retries from 1 to 3 with exponential backoff (1s, 2s, 4s) - Add exponential backoff to reconnect polling (2s to 30s, resets on new events) - Add WebSocket ping every 15s in ExecSession to detect dead connections - Add .systemNotice content type to show disconnect/reconnect events inline in chat history (persisted across sessions) - Prepend disconnect context to next --resume prompt so Claude knows its previous output may be incomplete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Author
|
Replacing with a cleaner branch based off origin/main |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
max_run_after_disconnect=300on service creation so Claude keeps running for 5 minutes even if the iOS client disconnects (phone lock, background, network blip).systemNoticecontent type renders inline capsule banners showing "Connection lost — reconnecting...", "Reconnected — response complete", or "Reconnection gave up — response may be incomplete"Test plan
🤖 Generated with Claude Code