feat(skill): add WhatsApp reactions skill (emoji reactions + status tracker) (#509)

* feat(skill): add reactions skill (emoji reactions + status tracker)

* refactor(reactions): minimize overlays per upstream review

Address gavrielc's review on qwibitai/nanoclaw#509:
- SKILL.md: remove all inline code, follow add-telegram/add-whatsapp pattern (465→79 lines)
- Rebuild overlays as minimal deltas against upstream/main base
- ipc-mcp-stdio.ts: upstream base + only react_to_message tool (8% delta)
- ipc.ts: upstream base + only reactions delta (14% delta)
- group-queue.test.ts: upstream base + isActive tests only (5% delta)
- Remove group-queue.ts overlay (isActive provided by container-hardening)
- Remove group-queue.ts from manifest modifies list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yonatan Azrielant
2026-03-08 14:02:20 -04:00
committed by GitHub
parent 5b2bafd7bb
commit ab9abbb21a
16 changed files with 6985 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
// Database migration script for reactions table
// Run: npx tsx scripts/migrate-reactions.ts
import Database from 'better-sqlite3';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const STORE_DIR = process.env.STORE_DIR || path.join(process.cwd(), 'store');
const dbPath = path.join(STORE_DIR, 'messages.db');
console.log(`Migrating database at: ${dbPath}`);
const db = new Database(dbPath);
try {
db.transaction(() => {
db.exec(`
CREATE TABLE IF NOT EXISTS reactions (
message_id TEXT NOT NULL,
message_chat_jid TEXT NOT NULL,
reactor_jid TEXT NOT NULL,
reactor_name TEXT,
emoji TEXT NOT NULL,
timestamp TEXT NOT NULL,
PRIMARY KEY (message_id, message_chat_jid, reactor_jid)
);
`);
console.log('Created reactions table');
db.exec(`
CREATE INDEX IF NOT EXISTS idx_reactions_message ON reactions(message_id, message_chat_jid);
CREATE INDEX IF NOT EXISTS idx_reactions_reactor ON reactions(reactor_jid);
CREATE INDEX IF NOT EXISTS idx_reactions_emoji ON reactions(emoji);
CREATE INDEX IF NOT EXISTS idx_reactions_timestamp ON reactions(timestamp);
`);
console.log('Created indexes');
})();
const tableInfo = db.prepare(`PRAGMA table_info(reactions)`).all();
console.log('\nReactions table schema:');
console.table(tableInfo);
const count = db.prepare(`SELECT COUNT(*) as count FROM reactions`).get() as {
count: number;
};
console.log(`\nCurrent reaction count: ${count.count}`);
console.log('\nMigration complete!');
} catch (err) {
console.error('Migration failed:', err);
process.exit(1);
} finally {
db.close();
}