86 lines
3 KiB
TypeScript
86 lines
3 KiB
TypeScript
import type { FastMCP } from 'fastmcp';
|
|
import { z } from 'zod';
|
|
|
|
import { getController } from '../controller';
|
|
import { jsonTextContent } from '../utils/format';
|
|
import { assertConfiguredTeam } from '../utils/teamConfig';
|
|
|
|
const controlContextSchema = {
|
|
teamName: z.string().min(1),
|
|
claudeDir: z.string().min(1).optional(),
|
|
controlUrl: z.string().optional(),
|
|
waitTimeoutMs: z.number().int().min(1000).max(600000).optional(),
|
|
};
|
|
|
|
const reportStateSchema = z.enum(['still_working', 'blocked', 'caught_up']);
|
|
|
|
export function registerWorkSyncTools(server: Pick<FastMCP, 'addTool'>) {
|
|
server.addTool({
|
|
name: 'member_work_sync_status',
|
|
description:
|
|
'Read your current actionable-work agenda and agendaFingerprint before reporting whether you are still working, blocked, or caught up.',
|
|
parameters: z.object({
|
|
...controlContextSchema,
|
|
memberName: z.string().min(1).optional(),
|
|
from: z.string().min(1).optional(),
|
|
}),
|
|
execute: async ({ teamName, claudeDir, controlUrl, waitTimeoutMs, memberName, from }) => {
|
|
assertConfiguredTeam(teamName, claudeDir);
|
|
return jsonTextContent(
|
|
await getController(teamName, claudeDir).workSync.memberWorkSyncStatus({
|
|
...(memberName ? { memberName } : {}),
|
|
...(from ? { from } : {}),
|
|
...(controlUrl ? { controlUrl } : {}),
|
|
...(waitTimeoutMs ? { waitTimeoutMs } : {}),
|
|
})
|
|
);
|
|
},
|
|
});
|
|
|
|
server.addTool({
|
|
name: 'member_work_sync_report',
|
|
description:
|
|
'Report your validated work-sync state for the current agendaFingerprint. This never completes tasks. Use still_working while actively continuing, blocked only when the board has blocker evidence, and caught_up only when the status agenda is empty.',
|
|
parameters: z.object({
|
|
...controlContextSchema,
|
|
memberName: z.string().min(1).optional(),
|
|
from: z.string().min(1).optional(),
|
|
state: reportStateSchema,
|
|
agendaFingerprint: z.string().min(1),
|
|
reportToken: z.string().min(1),
|
|
taskIds: z.array(z.string().min(1)).optional(),
|
|
note: z.string().optional(),
|
|
leaseTtlMs: z.number().int().min(60000).max(3600000).optional(),
|
|
}),
|
|
execute: async ({
|
|
teamName,
|
|
claudeDir,
|
|
controlUrl,
|
|
waitTimeoutMs,
|
|
memberName,
|
|
from,
|
|
state,
|
|
agendaFingerprint,
|
|
reportToken,
|
|
taskIds,
|
|
note,
|
|
leaseTtlMs,
|
|
}) => {
|
|
assertConfiguredTeam(teamName, claudeDir);
|
|
return jsonTextContent(
|
|
await getController(teamName, claudeDir).workSync.memberWorkSyncReport({
|
|
...(memberName ? { memberName } : {}),
|
|
...(from ? { from } : {}),
|
|
state,
|
|
agendaFingerprint,
|
|
reportToken,
|
|
...(taskIds ? { taskIds } : {}),
|
|
...(note ? { note } : {}),
|
|
...(leaseTtlMs ? { leaseTtlMs } : {}),
|
|
...(controlUrl ? { controlUrl } : {}),
|
|
...(waitTimeoutMs ? { waitTimeoutMs } : {}),
|
|
})
|
|
);
|
|
},
|
|
});
|
|
}
|