refactor: remove register_group legacy surface

This commit is contained in:
Eyejoker
2026-03-31 21:59:01 +09:00
parent a2d4651a82
commit 2070e0391f
5 changed files with 21 additions and 122 deletions

View File

@@ -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);

View File

@@ -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',

View File

@@ -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(

View File

@@ -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(
{ {

View File

@@ -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(