Skill: dispo-orphan-recovery
Scans SalesMsg inbound messages for conversations with no pending draft and generates Kimi drafts for all of them, posting @aurora notes so Henry can review and approve immediately.
Trigger
User says any of:
/dispo-orphan-recovery- “check for missed drafts”
- “messages with no draft”
- “unanswered inbounds”
- “orphan recovery”
- “drafts for missed messages”
- “generate drafts for unanswered”
- “salesmsg messages without a response”
Usage
# Default: last 24h, live
node /home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js
# Custom window
node /home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js --since-hours 6
# Dry run — scan only, no writes, no LLM calls
node /home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js --dry-run
# Single phone recovery
node /home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js --phone +16198551646
# JSON output for automation
node /home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js --json --dry-runWhat it does
- Queries
salesmsg_inboxfor inbound messages (non-note) in the last N hours - Deduplicates to one (most recent) message per phone
- Checks
message_approvalsfor any pending/approved record for those phones (48h window) - For each phone with NO draft: calls
generateResponse(Kimi via response-generator.js) - Inserts pending
message_approvalsrow with full telemetry inai_context - Posts @aurora internal note in the SalesMsg conversation with draft + confidence score
- Reports results — queued count, errors, dry-run list
Output
Each orphan gets:
- A
message_approvalsrow withstatus: 'pending'andsource: 'dispo-orphan-recovery'inai_context - An internal note in the SalesMsg conversation (visible to Henry immediately)
- The approval poller picks it up and sends within 5 minutes if auto-send is enabled
Root cause context
The groundedResult is not defined bug (scoping error in salesmessage-handler-v4-complete.js, fixed 2026-04-29) caused PM2 crashes during draft generation, leaving 12+ inbounds without drafts. This skill is the recovery mechanism AND an ongoing safety net.
When to run on-demand
- After a PM2 restart (handler loses in-memory state, may have missed messages during restart window)
- After any deploy to salesmsg-webhook service
- When Henry notices a buyer conversation has no draft in SalesMsg
- Morning check:
--since-hours 8to cover overnight
Scheduled sweep (optional)
To run automatically every hour as a safety net:
# Check status
systemctl --user status dispo-orphan-recovery.timer
# Install (if not yet running)
# Service + timer files should be created if Henry wants this automatedFiles
- Script:
/home/opsadmin/.openclaw/workspace/scripts/dispo-orphan-recovery.js - Tables read:
salesmsg_inbox,message_approvals - Tables written:
message_approvals - Token used:
data/salesmessage-oauth.json(Henry’s token — required for notes; Aurora’s token can’t post notes)
Limitations
- Processes 2 orphans concurrently (rate-limit friendly)
- Skips phones already covered by a pending/approved draft (safe to re-run)
- If Kimi returns empty draft, logs a warning and skips that phone (does not insert blank approval)