Merge branch 'main' into upstream-pr/refresh-tasks-snapshot

This commit is contained in:
Gabi Simons
2026-03-18 01:05:29 -07:00
committed by GitHub
30 changed files with 1179 additions and 165 deletions

View File

@@ -46,6 +46,11 @@ import { GroupQueue } from './group-queue.js';
import { resolveGroupFolderPath } from './group-folder.js';
import { startIpcWatcher } from './ipc.js';
import { findChannel, formatMessages, formatOutbound } from './router.js';
import {
restoreRemoteControl,
startRemoteControl,
stopRemoteControl,
} from './remote-control.js';
import {
isSenderAllowed,
isTriggerAllowed,
@@ -470,6 +475,7 @@ async function main(): Promise<void> {
initDatabase();
logger.info('Database initialized');
loadState();
restoreRemoteControl();
// Start credential proxy (containers route API calls through this)
const proxyServer = await startCredentialProxy(
@@ -488,9 +494,60 @@ async function main(): Promise<void> {
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
// Handle /remote-control and /remote-control-end commands
async function handleRemoteControl(
command: string,
chatJid: string,
msg: NewMessage,
): Promise<void> {
const group = registeredGroups[chatJid];
if (!group?.isMain) {
logger.warn(
{ chatJid, sender: msg.sender },
'Remote control rejected: not main group',
);
return;
}
const channel = findChannel(channels, chatJid);
if (!channel) return;
if (command === '/remote-control') {
const result = await startRemoteControl(
msg.sender,
chatJid,
process.cwd(),
);
if (result.ok) {
await channel.sendMessage(chatJid, result.url);
} else {
await channel.sendMessage(
chatJid,
`Remote Control failed: ${result.error}`,
);
}
} else {
const result = stopRemoteControl();
if (result.ok) {
await channel.sendMessage(chatJid, 'Remote Control session ended.');
} else {
await channel.sendMessage(chatJid, result.error);
}
}
}
// Channel callbacks (shared by all channels)
const channelOpts = {
onMessage: (chatJid: string, msg: NewMessage) => {
// Remote control commands — intercept before storage
const trimmed = msg.content.trim();
if (trimmed === '/remote-control' || trimmed === '/remote-control-end') {
handleRemoteControl(trimmed, chatJid, msg).catch((err) =>
logger.error({ err, chatJid }, 'Remote control command error'),
);
return;
}
// Sender allowlist drop mode: discard messages from denied senders before storing
if (!msg.is_from_me && !msg.is_bot_message && registeredGroups[chatJid]) {
const cfg = loadSenderAllowlist();