The Gitea release build failed because aws/aws-sdk-php 3.371+ requires PHP
>= 8.1, while composer.json's platform was pinned to 8.0. Production runs
PHP 8.5.4, so bumping the minimum to 8.1 is well within the runtime envelope.
Changes:
composer.json — require php >=8.1, platform.php = 8.1
.gitea/workflows/release.yml — setup-php now installs PHP 8.1
added pre-install step that runs
`composer update --no-install` only when
composer.lock is absent. If a lock file is
ever committed later, CI uses it directly
for deterministic installs instead of
regenerating.
twilio-wp-plugin.php — added "Requires PHP: 8.1" header so
WordPress itself enforces the minimum
README.md, CLAUDE.md — doc bump from 8.0 to 8.1, with note that
the AWS SDK is the constraint driver
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Gradle wrapper jar and properties were already tracked but the matching
gradlew (bash) and gradlew.bat (Windows) launcher scripts were not, leaving
the wrapper unusable without a separately-installed Gradle. Adding both so
./gradlew works on a fresh clone.
.flutter-plugins is a generated file containing absolute machine-specific
pub-cache paths and is explicitly marked "do not check into version control"
in its own header. Adding it to mobile/.gitignore alongside the already-
ignored .flutter-plugins-dependencies.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gitea release workflow now runs composer install --no-dev before zipping, so
each release ships vendor/ with both Twilio and AWS SDKs. The plugin's loader
priority is flipped to match: internal vendor/autoload.php first (always
current after every plugin update), external wp-content/twilio-sdk/ second
(legacy/manual install fallback).
AWS SDK detection wired in alongside Twilio: composer's bundled autoloader
covers Aws\… natively when present; otherwise plugin falls back to a new
external location wp-content/aws-sdk/ via install-aws-sdk-external.sh, which
drops the AWS SDK PHAR with a tiny autoload shim. AWS-missing admin notice
fires only when twp_sms_provider === 'aws_sns' so existing Twilio SMS users
see no new noise.
Loader priority flip applied in three places that all had the same
external-first pattern: twilio-wp-plugin.php (twp_check_sdk_installation),
class-twp-twilio-api.php (init_sdk_client), class-twp-webhooks.php
(constructor). twp_check_sdk_after_update messaging updated to reflect that
plugin updates now bundle the SDK.
Files:
.gitea/workflows/release.yml — composer install before ZIP
twilio-wp-plugin.php — TWP_EXTERNAL_AWS_SDK_DIR, dual-SDK
detection, twp_aws_sdk_missing_notice
includes/class-twp-twilio-api.php — internal-first autoloader
includes/class-twp-webhooks.php — internal-first autoloader
install-aws-sdk-external.sh — new AWS SDK PHAR installer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The activator class was only loaded during plugin activation, on admin_init
when the DB version differed, and in a few explicit admin handlers. Twilio
webhook callbacks (voicemail in particular, but also any non-admin caller of
TWP_Activator::force_table_updates() / ::ensure_tables_exist()) hit the public
REST endpoint where none of those load paths fire, so the static call fataled.
Load class-twp-activator.php in TWP_Core::load_dependencies() so every plugin
context — webhook, REST, cron, admin — has the class available. The activator
file is a pure class definition with no load-time side effects.
This single change covers all 9 runtime call sites (webhook, scheduler, and
six admin sites) that previously assumed the class would already be loaded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prevents screen sleep during calls and auto-reconnects the Twilio device
after app backgrounding. JS handles Screen Wake Lock API and 30s keepalive
polling; Flutter coordinates via WakelockPlus and synthetic visibilitychange
events on app resume.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
curl_close() is a no-op since PHP 8.0 (curl handles auto-cleanup as objects),
deprecated in 8.0, and generates warnings in 8.5. Removed from auto-updater
and FCM classes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The RECORD_AUDIO permission was declared in the manifest but never
requested at runtime, causing WebRTC to fail on Android 6+. Now
requests microphone permission on app startup before initializing
the WebView.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix silent insert failure in FCM token registration (missing NOT NULL
refresh_token column) so WebView app tokens are actually stored
- Add 1-minute queue reminder cron that re-sends FCM alerts for calls
still waiting, with transient-based throttle to prevent duplicates
- Send FCM cancel on queue dequeue (answered/hangup/timeout), not just
on final call status webhook
- Clean up new cron hook on plugin deactivation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phone page improvements:
- Clear caller number display after call disconnects
- Add "Recent" tab with session call history (tap to call back)
- Persist outbound caller ID selection in localStorage
- Fix button overlap with proper z-index layering
- Add manual dark mode toggle (System/Light/Dark) in Settings
- Improve dark mode CSS for all UI elements
Refactor phone page into separate files:
- assets/mobile/phone.css (848 lines) — all CSS
- assets/mobile/phone.js (1065 lines) — all JavaScript
- assets/mobile/phone-template.php (267 lines) — HTML template
- includes/class-twp-mobile-phone-page.php (211 lines) — PHP controller
- PHP values passed to JS via window.twpConfig bridge
Flutter app:
- Replace FAB with slim AppBar (refresh + menu buttons)
- Fix dark mode colors using theme-aware colorScheme
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrites the mobile app from a native Twilio Voice SDK integration
(Android Telecom/ConnectionService) to a thin WebView shell that loads
a standalone browser phone page from WordPress. This eliminates the
buggy Android phone account registration, fixes frequent logouts by
using 7-day WP session cookies instead of JWT tokens, and maintains
all existing call features (dialpad, queues, hold, transfer, requeue,
recording, caller ID, agent status).
Server-side:
- Add class-twp-mobile-phone-page.php: standalone /twp-phone/ endpoint
with mobile-optimized UI, dark mode, tab navigation, and Flutter
WebView JS bridge
- Extend auth cookie to 7 days for phone agents
- Add WP AJAX handler for FCM token registration (cookie auth)
Flutter app (v2.0.0):
- Replace 18 native files with 5-file WebView shell
- Login via wp-login.php in WebView (auto-detect redirect on success)
- Full-screen WebView with auto microphone grant for WebRTC
- FCM push notifications preserved for queue alerts
- Remove: twilio_voice, dio, provider, JWT auth, SSE, native call UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-side:
- Add push credential auto-creation for FCM incoming call notifications
- Add queue alert FCM notifications (data-only for background delivery)
- Add queue alert cancellation on call accept/disconnect
- Fix caller ID to show caller's number instead of Twilio number
- Fix FCM token storage when refresh_token is null
- Add pre_call_status tracking to revert agent status 30s after call ends
- Add SSE fallback polling for mobile app connectivity
Mobile app:
- Add Android telecom permissions and phone account registration
- Add VoiceFirebaseMessagingService for incoming call push handling
- Add insistent queue alert notifications with custom sound
- Fix caller number display on active call screen
- Add caller ID selection dropdown on dashboard
- Add phone numbers endpoint and provider support
- Add unit tests for CallInfo, QueueState, and CallProvider
- Remove local.properties from tracking, add .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store authenticated user ID on the auth object instance instead of
trying to retrieve it from the REST server request. This was the root
cause of all mobile API 500 errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use /releases?limit=1 instead of /releases/latest which sorts by
semver tag. Date-based tags (2026.03.06-1805) have a hyphen that
semver treats as a prerelease separator, causing incorrect ordering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Relocate update section (version check, repo config, token) to Settings
- Fix download URL for private repos: append Gitea auth token
- Mobile App page now only has FCM/notification settings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Voice token: use AccessToken + VoiceGrant instead of browser-only ClientToken
- Agent status: delegate to TWP_Agent_Manager matching browser phone behavior
- Queue loading: add missing require_once for TWP_User_Queue_Manager
- Add /phone-numbers endpoint for caller ID selection
- Webhook: support CallerId param from mobile extraOptions
- Flutter: caller ID dropdown in dialer, error logging in all catch blocks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix queue queries in mobile API and SSE to use twp_group_members
(matching browser phone) instead of twp_queue_assignments
- Auto-create personal queues if user has no extension
- Make all model JSON parsing null-safe (handle null, string ints, bools)
- Add AutofillGroup and autofill hints to login form
- Add outbound calling with dialpad bottom sheet on dashboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile voice token endpoint now uses TWP_Twilio_API::generate_capability_token()
instead of separate API Key SID/Secret. Removes duplicate Twilio credential
fields from Mobile App settings page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All FCM push notifications are handled by WordPress backend (TWP_FCM),
so Twilio Push Credentials are unnecessary. Also replaces placeholder
google-services.json with real Firebase project config (twp-softphone).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace deprecated FCM server key authentication with Google service
account OAuth2 flow. The class now creates a signed JWT from the
service account credentials, exchanges it for a short-lived access
token (cached via WordPress transients), and sends messages to the
FCM v2 endpoint (projects/{id}/messages:send).
Settings page updated: FCM Server Key field replaced with Firebase
Project ID + Service Account JSON textarea with validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add preload hint for Twilio SDK to start loading earlier
- Add DNS prefetch and preconnect for Twilio servers
- Check SDK immediately instead of waiting 500ms
- Reduce polling interval from 100ms to 50ms
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Debug code was added to diagnose mobile connection issues. The fix
(polling for SDK instead of waiting for window.load) is now working,
so removing the temporary debug output.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The window.load event was never firing on mobile tablets, preventing
the browser phone from initializing. Changed to poll for Twilio SDK
availability instead of waiting for window.load event.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds visible debug output to track SDK loading and device registration
steps on mobile devices where the phone stays stuck on "Connecting".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SDK files are at twilio/sdk/Twilio/Rest/Client.php but the
autoloader was looking at twilio/sdk/Rest/Client.php. Fixed by
using the full class name in the path instead of stripping the
Twilio\ prefix.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added detailed debugging documentation for troubleshooting browser phone
issues on Android tablets. Covers USB debugging setup, Chrome DevTools
connection, common issues, error codes, and testing procedures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves issues where browser phone PWA failed to connect and calls would
immediately hang up when answered on Android tablets. Adds proper mobile
audio handling, device connection monitoring, and PWA notifications for
incoming calls.
Key changes:
- Add AudioContext initialization with mobile unlock for autoplay support
- Add Android-specific WebRTC constraints (echo cancellation, ICE restart)
- Add device connection state monitoring and auto-reconnection
- Add incoming call ringtone with vibration fallback
- Add PWA service worker notifications for background calls
- Add Page Visibility API for background call detection
- Improve call answer handler with connection state validation
- Add touch event support for mobile dialpad
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The workflow was only updating the Version comment but not the TWP_VERSION constant, causing the local repository to show the placeholder while releases showed the actual version.
Now updates both:
- Version: header comment
- TWP_VERSION constant
This matches the release.yml workflow and ensures version consistency.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace hardcoded version with {auto_update_value_on_deploy} placeholder that gets replaced during the Gitea workflow build process.
Changes:
- Updated Version comment to use placeholder
- Updated TWP_VERSION constant to use placeholder
- Modified release workflow to replace both instances of the placeholder
This matches the pattern used in the fourthwall plugin and ensures the version is automatically set during the release build process.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add automated release creation and versioning workflows similar to the fourthwall plugin.
Features:
- Automatically creates a release on every push to main branch
- Generates release notes from commit messages since last tag
- Updates plugin version using timestamp-based versioning (YYYY.MM.DD-HHMM)
- Creates and uploads plugin zip file to release
- Supports manual release creation/editing to update version
Workflows:
- .gitea/workflows/release.yml - Triggers on push to main
- .gitea/workflows/update-version.yml - Triggers on release creation/edit
The release zip will be automatically picked up by the Gitea auto-updater for WordPress.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit adds comprehensive mobile app support to enable a native Android app that won't timeout or sleep when the screen goes dark.
New Features:
- JWT-based authentication system (no WordPress session dependency)
- REST API endpoints for mobile app (agent status, queue management, call control)
- Server-Sent Events (SSE) for real-time updates to mobile app
- Firebase Cloud Messaging (FCM) integration for push notifications
- Gitea-based automatic plugin updates
- Mobile app admin settings page
New Files:
- includes/class-twp-mobile-auth.php - JWT authentication with login/refresh/logout
- includes/class-twp-mobile-api.php - REST API endpoints under /twilio-mobile/v1
- includes/class-twp-mobile-sse.php - Real-time event streaming
- includes/class-twp-fcm.php - Push notification handling
- includes/class-twp-auto-updater.php - Gitea-based auto-updates
- admin/mobile-app-settings.php - Admin configuration page
Modified Files:
- includes/class-twp-activator.php - Added twp_mobile_sessions table
- includes/class-twp-core.php - Load and initialize mobile classes
- admin/class-twp-admin.php - Added Mobile App menu item and settings page
Database Changes:
- New table: twp_mobile_sessions (stores JWT refresh tokens and FCM tokens)
API Endpoints:
- POST /twilio-mobile/v1/auth/login
- POST /twilio-mobile/v1/auth/refresh
- POST /twilio-mobile/v1/auth/logout
- GET/POST /twilio-mobile/v1/agent/status
- GET /twilio-mobile/v1/queues/state
- POST /twilio-mobile/v1/calls/{call_sid}/accept
- GET /twilio-mobile/v1/stream/events (SSE)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated the format_phone_number_for_speech function to properly read phone numbers digit by digit instead of as large numbers.
Changes:
- Phone number 9095737372 now reads as "9 0 9, 5 7 3, 7 3 7 2"
- Instead of "nine hundred nine, five hundred seventy three"
- Added proper digit separation with commas for natural speech flow
- Handles both 10-digit and 11-digit (with country code) numbers
- Strips all non-numeric characters before processing
This makes the agent announcement much clearer when receiving forwarded calls.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replaced problematic Number URL approach with conference-based forwarding to eliminate the "call cannot be completed" issue.
Key improvements:
- Forward calls now use Conference instead of direct Dial with URL
- Caller is placed in conference with hold music while waiting for agent
- Agent receives outbound call to join conference with proper caller ID
- Agent hears "Incoming call from XXX XXX XXXX" announcement
- Conference-based architecture enables future DTMF features
- Proper call flow without TwiML interference
Technical details:
- Added conference status monitoring webhooks
- Agent call includes proper caller announcement
- Conference starts when agent joins, ends when caller leaves
- Hold music plays while waiting for agent
- Eliminated URL attribute on Number elements that caused audio issues
- Added Conference element support in append_twiml_element function
This resolves the voicemail and "call cannot be completed" issues while maintaining call forwarding functionality and preparing for advanced agent features.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major enhancement to workflow forwarding that solves voicemail issues and adds agent call control capabilities.
Key improvements:
- Converted direct forwarding to bridged forwarding to avoid self-call voicemail issues
- Added DTMF-based agent features during calls:
* *9 - Hold/Unhold customer
* *0 - Start/Stop call recording
* *5 - Transfer to another extension
* *1 - Mute/Unmute (placeholder for future conference mode)
- Added webhook handlers for agent features and forward results
- Agent features URL attached to Number elements for DTMF detection
- Continuous DTMF listening during active calls
- Proper call leg detection for hold/resume operations
Technical details:
- Added /agent-features webhook for DTMF capture
- Added /agent-action webhook for processing commands
- Added /forward-result webhook for handling dial outcomes
- Modified append_twiml_element to preserve Number attributes (url, method)
- Enhanced logging throughout for debugging
This eliminates the issue where calling yourself would go straight to voicemail and provides professional call control features for agents.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated forward and ring group tasks to use the incoming number (To) as the caller ID for outbound calls instead of the original caller's number (From).
Changes:
- Forward task now sets callerId attribute to the number that was called
- Ring group task also defaults to using the incoming number as caller ID
- Both functions check multiple sources for the To number (GLOBALS, POST, REQUEST)
- Added detailed logging for caller ID selection
This ensures that when calls are forwarded, the receiving party sees the business number that was called, not the original caller's personal number.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed critical bug where forward tasks in workflows would immediately disconnect calls instead of forwarding them properly.
Changes:
- Fixed append_twiml_element function to properly handle Dial elements with child Number elements
- Enhanced create_forward_twiml to extract numbers from nested data structures
- Added comprehensive error handling for missing forward numbers
- Added detailed logging throughout workflow execution for debugging
- Set default timeout of 30 seconds for forward operations
The issue was caused by the Dial element being converted to string which lost all child Number elements, resulting in an empty dial that would immediately disconnect.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major Fixes:
- Fixed extension transfers going directly to voicemail for available agents
- Resolved browser phone call disconnections during transfers
- Fixed voicemail transcription placeholder text issue
- Added Firefox compatibility with automatic media permissions
Extension Transfer Improvements:
- Changed from active client dialing to proper queue-based system
- Fixed client name generation consistency (user_login vs display_name)
- Added 2-minute timeout with automatic voicemail fallback
- Enhanced agent availability detection for browser phone users
Browser Phone Enhancements:
- Added automatic microphone/speaker permission requests
- Improved Firefox compatibility with explicit getUserMedia calls
- Fixed client naming consistency across capability tokens and call acceptance
- Added comprehensive error handling for permission denials
Database & System Updates:
- Added auto_busy_at column for automatic agent status reversion
- Implemented 1-minute auto-revert system for busy agents with cron job
- Updated database version to 1.6.2 for automatic migration
- Fixed voicemail user_id association for extension voicemails
Call Statistics & Logging:
- Fixed browser phone calls not appearing in agent statistics
- Enhanced call logging with proper agent_id association in JSON format
- Improved customer number detection for complex call topologies
- Added comprehensive debugging for call leg detection
Voicemail & Transcription:
- Replaced placeholder transcription with real Twilio API integration
- Added manual transcription request capability for existing voicemails
- Enhanced voicemail callback handling with user_id support
- Fixed transcription webhook processing for extension voicemails
Technical Improvements:
- Standardized client name generation across all components
- Added ElevenLabs TTS integration to agent connection messages
- Enhanced error handling and logging throughout transfer system
- Fixed TwiML generation syntax errors in dial() methods
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL FIXES:
- Fixed hold/resume functions to use proper Hold Queue system instead of empty TwiML
- Enhanced customer number detection for voicemail and call recording interfaces
- Resolved customer disconnections during hold/resume operations on outbound calls
Hold/Resume System Improvements:
- Updated ajax_toggle_hold() to use TWP_User_Queue_Manager for proper queue management
- Fixed resume function to redirect calls back to appropriate queues (personal/shared)
- Added comprehensive logging for hold queue operations and call leg detection
- Enhanced hold experience with proper TTS messages and queue tracking
Customer Number Detection Enhancements:
- Enhanced handle_voicemail_callback() with fallback logic for missing From parameters
- Added browser phone detection to identify client: calls and find real customer numbers
- Enhanced call recording to use find_customer_call_leg() for proper customer identification
- Fixed admin interfaces to show actual phone numbers instead of "client:agentname"
Technical Improvements:
- Integrated Hold Queue system with existing call leg detection infrastructure
- Added proper TwiML generation for hold/resume operations
- Enhanced error handling and logging for debugging complex call topologies
- Maintains database consistency with queue position tracking
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>