Add register_group IPC command for dynamic group registration
Main agent can now register new groups via MCP tool without restart. Host updates both in-memory state and JSON file, creates group folders. Authorization enforced at both agent and host level. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -276,6 +276,45 @@ SCHEDULE VALUE FORMAT (all times are LOCAL timezone):
|
|||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
tool(
|
||||||
|
'register_group',
|
||||||
|
`Register a new WhatsApp group so the agent can respond to messages there. Main group only.
|
||||||
|
|
||||||
|
Use available_groups.json to find the JID for a group. The folder name should be lowercase with hyphens (e.g., "family-chat").`,
|
||||||
|
{
|
||||||
|
jid: z.string().describe('The WhatsApp JID (e.g., "120363336345536173@g.us")'),
|
||||||
|
name: z.string().describe('Display name for the group'),
|
||||||
|
folder: z.string().describe('Folder name for group files (lowercase, hyphens, e.g., "family-chat")'),
|
||||||
|
trigger: z.string().describe('Trigger word (e.g., "@Andy")')
|
||||||
|
},
|
||||||
|
async (args) => {
|
||||||
|
if (!isMain) {
|
||||||
|
return {
|
||||||
|
content: [{ type: 'text', text: 'Only the main group can register new groups.' }],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
type: 'register_group',
|
||||||
|
jid: args.jid,
|
||||||
|
name: args.name,
|
||||||
|
folder: args.folder,
|
||||||
|
trigger: args.trigger,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
writeIpcFile(TASKS_DIR, data);
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: `Group "${args.name}" registered. It will start receiving messages immediately.`
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
36
src/index.ts
36
src/index.ts
@@ -61,6 +61,17 @@ function saveState(): void {
|
|||||||
saveJson(path.join(DATA_DIR, 'sessions.json'), sessions);
|
saveJson(path.join(DATA_DIR, 'sessions.json'), sessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerGroup(jid: string, group: RegisteredGroup): void {
|
||||||
|
registeredGroups[jid] = group;
|
||||||
|
saveJson(path.join(DATA_DIR, 'registered_groups.json'), registeredGroups);
|
||||||
|
|
||||||
|
// Create group folder
|
||||||
|
const groupDir = path.join(DATA_DIR, '..', 'groups', group.folder);
|
||||||
|
fs.mkdirSync(path.join(groupDir, 'logs'), { recursive: true });
|
||||||
|
|
||||||
|
logger.info({ jid, name: group.name, folder: group.folder }, 'Group registered');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync group metadata from WhatsApp.
|
* Sync group metadata from WhatsApp.
|
||||||
* Fetches all participating groups and stores their names in the database.
|
* Fetches all participating groups and stores their names in the database.
|
||||||
@@ -306,6 +317,12 @@ async function processTaskIpc(
|
|||||||
context_mode?: string;
|
context_mode?: string;
|
||||||
groupFolder?: string;
|
groupFolder?: string;
|
||||||
chatJid?: string;
|
chatJid?: string;
|
||||||
|
// For register_group
|
||||||
|
jid?: string;
|
||||||
|
name?: string;
|
||||||
|
folder?: string;
|
||||||
|
trigger?: string;
|
||||||
|
containerConfig?: RegisteredGroup['containerConfig'];
|
||||||
},
|
},
|
||||||
sourceGroup: string, // Verified identity from IPC directory
|
sourceGroup: string, // Verified identity from IPC directory
|
||||||
isMain: boolean // Verified from directory path
|
isMain: boolean // Verified from directory path
|
||||||
@@ -431,6 +448,25 @@ async function processTaskIpc(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'register_group':
|
||||||
|
// Only main group can register new groups
|
||||||
|
if (!isMain) {
|
||||||
|
logger.warn({ sourceGroup }, 'Unauthorized register_group attempt blocked');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data.jid && data.name && data.folder && data.trigger) {
|
||||||
|
registerGroup(data.jid, {
|
||||||
|
name: data.name,
|
||||||
|
folder: data.folder,
|
||||||
|
trigger: data.trigger,
|
||||||
|
added_at: new Date().toISOString(),
|
||||||
|
containerConfig: data.containerConfig
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.warn({ data }, 'Invalid register_group request - missing required fields');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger.warn({ type: data.type }, 'Unknown IPC task type');
|
logger.warn({ type: data.type }, 'Unknown IPC task type');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user