refactor: remove register_group legacy surface
This commit is contained in:
@@ -495,7 +495,7 @@ server.tool(
|
|||||||
'assign_room',
|
'assign_room',
|
||||||
`Assign or update a room using room-level settings. Main group only.
|
`Assign or update a room using room-level settings. Main group only.
|
||||||
|
|
||||||
This is the room-level replacement for legacy register_group. If folder is omitted, the host generates one automatically.`,
|
If folder is omitted, the host generates one automatically.`,
|
||||||
{
|
{
|
||||||
jid: z.string().describe('The chat JID (e.g., "120363336345536173@g.us", "tg:-1001234567890", "dc:1234567890123456")'),
|
jid: z.string().describe('The chat JID (e.g., "120363336345536173@g.us", "tg:-1001234567890", "dc:1234567890123456")'),
|
||||||
name: z.string().describe('Display name for the room'),
|
name: z.string().describe('Display name for the room'),
|
||||||
@@ -547,42 +547,6 @@ This is the room-level replacement for legacy register_group. If folder is omitt
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
server.tool(
|
|
||||||
'register_group',
|
|
||||||
`Register a new chat/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 must be channel-prefixed: "{channel}_{group-name}" (e.g., "whatsapp_family-chat", "telegram_dev-team", "discord_general"). Use lowercase with hyphens for the group name part.`,
|
|
||||||
{
|
|
||||||
jid: z.string().describe('The chat JID (e.g., "120363336345536173@g.us", "tg:-1001234567890", "dc:1234567890123456")'),
|
|
||||||
name: z.string().describe('Display name for the group'),
|
|
||||||
folder: z.string().describe('Channel-prefixed folder name (e.g., "whatsapp_family-chat", "telegram_dev-team")'),
|
|
||||||
trigger: z.string().describe('Trigger word (e.g., "@Andy")'),
|
|
||||||
},
|
|
||||||
async (args: { jid: string; name: string; folder: string; trigger: string }) => {
|
|
||||||
if (!isMain) {
|
|
||||||
return {
|
|
||||||
content: [{ type: 'text' as const, 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' as const, text: `Group "${args.name}" registration requested.` }],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Start the stdio transport
|
// Start the stdio transport
|
||||||
const transport = new StdioServerTransport();
|
const transport = new StdioServerTransport();
|
||||||
await server.connect(transport);
|
await server.connect(transport);
|
||||||
|
|||||||
@@ -965,7 +965,7 @@ describe('paired room registration', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps room-level metadata synced on legacy register_group writes', () => {
|
it('keeps room-level metadata synced on setRegisteredGroup helper writes', () => {
|
||||||
setRegisteredGroup('dc:room-settings', {
|
setRegisteredGroup('dc:room-settings', {
|
||||||
name: 'Room Settings Test',
|
name: 'Room Settings Test',
|
||||||
folder: 'room-settings-test',
|
folder: 'room-settings-test',
|
||||||
|
|||||||
41
src/index.ts
41
src/index.ts
@@ -216,46 +216,6 @@ function clearSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerGroup(jid: string, group: RegisteredGroup): void {
|
|
||||||
const assignedGroup = assignRoom(jid, {
|
|
||||||
name: group.name,
|
|
||||||
ownerAgentType: group.agentType,
|
|
||||||
folder: group.folder,
|
|
||||||
trigger: group.trigger,
|
|
||||||
requiresTrigger: group.requiresTrigger,
|
|
||||||
isMain: group.isMain,
|
|
||||||
workDir: group.workDir,
|
|
||||||
addedAt: group.added_at,
|
|
||||||
ownerAgentConfig: group.agentConfig,
|
|
||||||
});
|
|
||||||
if (!assignedGroup) {
|
|
||||||
logger.warn({ jid }, 'Failed to assign room during legacy registration');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let groupDir: string;
|
|
||||||
try {
|
|
||||||
groupDir = resolveGroupFolderPath(assignedGroup.folder);
|
|
||||||
} catch (err) {
|
|
||||||
logger.warn(
|
|
||||||
{ jid, folder: assignedGroup.folder, err },
|
|
||||||
'Rejecting group registration with invalid folder',
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { jid: _ignoredJid, ...storedGroup } = assignedGroup;
|
|
||||||
registeredGroups[jid] = storedGroup;
|
|
||||||
|
|
||||||
// Create group folder
|
|
||||||
fs.mkdirSync(path.join(groupDir, 'logs'), { recursive: true });
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
{ jid, name: assignedGroup.name, folder: assignedGroup.folder },
|
|
||||||
'Group registered',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assignRoomForIpc(jid: string, input: AssignRoomInput): void {
|
function assignRoomForIpc(jid: string, input: AssignRoomInput): void {
|
||||||
const assignedGroup = assignRoom(jid, input);
|
const assignedGroup = assignRoom(jid, input);
|
||||||
if (!assignedGroup) {
|
if (!assignedGroup) {
|
||||||
@@ -521,7 +481,6 @@ async function main(): Promise<void> {
|
|||||||
},
|
},
|
||||||
nudgeScheduler: nudgeSchedulerLoop,
|
nudgeScheduler: nudgeSchedulerLoop,
|
||||||
registeredGroups: () => registeredGroups,
|
registeredGroups: () => registeredGroups,
|
||||||
registerGroup,
|
|
||||||
assignRoom: assignRoomForIpc,
|
assignRoom: assignRoomForIpc,
|
||||||
syncGroups: async (force: boolean) => {
|
syncGroups: async (force: boolean) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|||||||
@@ -60,11 +60,6 @@ beforeEach(() => {
|
|||||||
sendMessage: async () => {},
|
sendMessage: async () => {},
|
||||||
nudgeScheduler: vi.fn(),
|
nudgeScheduler: vi.fn(),
|
||||||
registeredGroups: () => groups,
|
registeredGroups: () => groups,
|
||||||
registerGroup: (jid, group) => {
|
|
||||||
groups[jid] = group;
|
|
||||||
setRegisteredGroup(jid, group);
|
|
||||||
// Mock the fs.mkdirSync that registerGroup does
|
|
||||||
},
|
|
||||||
assignRoom: (jid, room) => {
|
assignRoom: (jid, room) => {
|
||||||
const assigned = assignRoom(jid, room);
|
const assigned = assignRoom(jid, room);
|
||||||
if (!assigned) return;
|
if (!assigned) return;
|
||||||
@@ -384,13 +379,13 @@ describe('cancel_task authorization', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- register_group authorization ---
|
// --- assign_room authorization ---
|
||||||
|
|
||||||
describe('register_group authorization', () => {
|
describe('assign_room authorization', () => {
|
||||||
it('non-main group cannot register a group', async () => {
|
it('non-main group cannot assign a room', async () => {
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
type: 'register_group',
|
type: 'assign_room',
|
||||||
jid: 'new@g.us',
|
jid: 'new@g.us',
|
||||||
name: 'New Group',
|
name: 'New Group',
|
||||||
folder: 'new-group',
|
folder: 'new-group',
|
||||||
@@ -405,10 +400,10 @@ describe('register_group authorization', () => {
|
|||||||
expect(groups['new@g.us']).toBeUndefined();
|
expect(groups['new@g.us']).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('main group cannot register with unsafe folder path', async () => {
|
it('main group cannot assign with unsafe folder path', async () => {
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
type: 'register_group',
|
type: 'assign_room',
|
||||||
jid: 'new@g.us',
|
jid: 'new@g.us',
|
||||||
name: 'New Group',
|
name: 'New Group',
|
||||||
folder: '../../outside',
|
folder: '../../outside',
|
||||||
@@ -779,13 +774,13 @@ describe('schedule_task context_mode', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- register_group success path ---
|
// --- assign_room success path ---
|
||||||
|
|
||||||
describe('register_group success', () => {
|
describe('assign_room success', () => {
|
||||||
it('main group can register a new group', async () => {
|
it('main group can assign a new room', async () => {
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
type: 'register_group',
|
type: 'assign_room',
|
||||||
jid: 'new@g.us',
|
jid: 'new@g.us',
|
||||||
name: 'New Group',
|
name: 'New Group',
|
||||||
folder: 'new-group',
|
folder: 'new-group',
|
||||||
@@ -796,7 +791,6 @@ describe('register_group success', () => {
|
|||||||
deps,
|
deps,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify group was registered in DB
|
|
||||||
const group = getRegisteredGroup('new@g.us');
|
const group = getRegisteredGroup('new@g.us');
|
||||||
expect(group).toBeDefined();
|
expect(group).toBeDefined();
|
||||||
expect(group!.name).toBe('New Group');
|
expect(group!.name).toBe('New Group');
|
||||||
@@ -804,10 +798,10 @@ describe('register_group success', () => {
|
|||||||
expect(group!.trigger).toBe('@Andy');
|
expect(group!.trigger).toBe('@Andy');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('register_group auto-fills missing folder and trigger for single rooms', async () => {
|
it('assign_room auto-fills missing folder and trigger for single rooms', async () => {
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
type: 'register_group',
|
type: 'assign_room',
|
||||||
jid: 'partial@g.us',
|
jid: 'partial@g.us',
|
||||||
name: 'Partial',
|
name: 'Partial',
|
||||||
},
|
},
|
||||||
@@ -823,7 +817,7 @@ describe('register_group success', () => {
|
|||||||
expect(getStoredRoomSettings('partial@g.us')?.roomMode).toBe('single');
|
expect(getStoredRoomSettings('partial@g.us')?.roomMode).toBe('single');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('register_group preserves an existing tribunal room mode', async () => {
|
it('assign_room preserves an existing tribunal room mode when room_mode is omitted', async () => {
|
||||||
assignRoom('legacy-tribunal@g.us', {
|
assignRoom('legacy-tribunal@g.us', {
|
||||||
name: 'Legacy Tribunal',
|
name: 'Legacy Tribunal',
|
||||||
roomMode: 'tribunal',
|
roomMode: 'tribunal',
|
||||||
@@ -833,7 +827,7 @@ describe('register_group success', () => {
|
|||||||
|
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
type: 'register_group',
|
type: 'assign_room',
|
||||||
jid: 'legacy-tribunal@g.us',
|
jid: 'legacy-tribunal@g.us',
|
||||||
name: 'Legacy Tribunal Renamed',
|
name: 'Legacy Tribunal Renamed',
|
||||||
folder: 'legacy-tribunal',
|
folder: 'legacy-tribunal',
|
||||||
@@ -854,9 +848,7 @@ describe('register_group success', () => {
|
|||||||
'codex',
|
'codex',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('assign_room success', () => {
|
|
||||||
it('main group can assign a tribunal room and materialize capability rows', async () => {
|
it('main group can assign a tribunal room and materialize capability rows', async () => {
|
||||||
await processTaskIpc(
|
await processTaskIpc(
|
||||||
{
|
{
|
||||||
|
|||||||
26
src/ipc.ts
26
src/ipc.ts
@@ -26,7 +26,6 @@ export interface IpcDeps {
|
|||||||
sendMessage: (jid: string, text: string) => Promise<void>;
|
sendMessage: (jid: string, text: string) => Promise<void>;
|
||||||
nudgeScheduler?: () => void;
|
nudgeScheduler?: () => void;
|
||||||
registeredGroups: () => Record<string, RegisteredGroup>;
|
registeredGroups: () => Record<string, RegisteredGroup>;
|
||||||
registerGroup: (jid: string, group: RegisteredGroup) => void;
|
|
||||||
assignRoom: (jid: string, room: AssignRoomInput) => void;
|
assignRoom: (jid: string, room: AssignRoomInput) => void;
|
||||||
syncGroups: (force: boolean) => Promise<void>;
|
syncGroups: (force: boolean) => Promise<void>;
|
||||||
getAvailableGroups: () => AvailableGroup[];
|
getAvailableGroups: () => AvailableGroup[];
|
||||||
@@ -294,7 +293,7 @@ export async function processTaskIpc(
|
|||||||
groupFolder?: string;
|
groupFolder?: string;
|
||||||
chatJid?: string;
|
chatJid?: string;
|
||||||
targetJid?: string;
|
targetJid?: string;
|
||||||
// For assign_room / register_group
|
// For assign_room
|
||||||
jid?: string;
|
jid?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
folder?: string;
|
folder?: string;
|
||||||
@@ -304,7 +303,6 @@ export async function processTaskIpc(
|
|||||||
owner_agent_type?: AgentType;
|
owner_agent_type?: AgentType;
|
||||||
isMain?: boolean;
|
isMain?: boolean;
|
||||||
workDir?: string;
|
workDir?: string;
|
||||||
agentConfig?: RegisteredGroup['agentConfig'];
|
|
||||||
},
|
},
|
||||||
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
|
||||||
@@ -602,8 +600,7 @@ export async function processTaskIpc(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'assign_room':
|
case 'assign_room':
|
||||||
case 'register_group':
|
// Only main group can assign rooms
|
||||||
// Only main group can assign/register rooms
|
|
||||||
if (!isMain) {
|
if (!isMain) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
{ sourceGroup, type: data.type },
|
{ sourceGroup, type: data.type },
|
||||||
@@ -642,28 +639,15 @@ export async function processTaskIpc(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'assign_room') {
|
|
||||||
deps.assignRoom(data.jid, {
|
|
||||||
name: data.name,
|
|
||||||
roomMode: data.room_mode,
|
|
||||||
ownerAgentType: data.owner_agent_type,
|
|
||||||
folder: data.folder,
|
|
||||||
trigger: data.trigger,
|
|
||||||
requiresTrigger: data.requiresTrigger,
|
|
||||||
isMain: data.isMain,
|
|
||||||
workDir: data.workDir,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
deps.assignRoom(data.jid, {
|
deps.assignRoom(data.jid, {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
|
roomMode: data.room_mode,
|
||||||
ownerAgentType: data.owner_agent_type,
|
ownerAgentType: data.owner_agent_type,
|
||||||
folder: data.folder,
|
folder: data.folder,
|
||||||
trigger: data.trigger,
|
trigger: data.trigger,
|
||||||
requiresTrigger: data.requiresTrigger,
|
requiresTrigger: data.requiresTrigger,
|
||||||
ownerAgentConfig: data.agentConfig,
|
isMain: data.isMain,
|
||||||
addedAt: new Date().toISOString(),
|
workDir: data.workDir,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
|||||||
Reference in New Issue
Block a user