wolfpack-mcp 1.0.90 → 1.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentBuilderTools.js +81 -2
- package/dist/agentBuilderTools.test.js +65 -0
- package/dist/client.js +12 -0
- package/dist/index.js +90 -1
- package/package.json +1 -1
|
@@ -113,6 +113,10 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
113
113
|
items: { type: 'string' },
|
|
114
114
|
description: 'Replace the full set of MCP permissions granted to the agent\'s session API key (e.g. ["mcp:work_items:read", "mcp:comments:create"]). Grant only what the agent\'s tasks need. An empty array falls back to a read-only default.',
|
|
115
115
|
},
|
|
116
|
+
scheduling_enabled: {
|
|
117
|
+
type: 'boolean',
|
|
118
|
+
description: "The agent-level scheduling switch. No schedule fires while it is off, whatever the schedule's own enabled flag says.",
|
|
119
|
+
},
|
|
116
120
|
...ORG_SLUG_PROP,
|
|
117
121
|
},
|
|
118
122
|
required: ['agent_id'],
|
|
@@ -532,6 +536,23 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
532
536
|
description: 'When true, tasks run once with access to all assigned projects. ' +
|
|
533
537
|
'When false, tasks run once per project.',
|
|
534
538
|
},
|
|
539
|
+
preflight_check: {
|
|
540
|
+
type: 'string',
|
|
541
|
+
enum: ['claimable-work', 'claimable-check'],
|
|
542
|
+
description: 'LLM-free condition evaluated when the schedule fires; a false result skips the fire with no session and no cost. ' +
|
|
543
|
+
'"claimable-work": an approved, unclaimed item is assigned to the agent or sits in one of its work pools. ' +
|
|
544
|
+
'"claimable-check": a pending, unclaimed review check sits on an item in one of its pools. Null to clear.',
|
|
545
|
+
},
|
|
546
|
+
check_kinds: {
|
|
547
|
+
type: 'array',
|
|
548
|
+
items: { type: 'string' },
|
|
549
|
+
description: 'With "claimable-check": only checks of these kinds wake the schedule (e.g. ["security-review"]), so reviewers ' +
|
|
550
|
+
'sharing a pool each answer their own kind. Empty for every kind.',
|
|
551
|
+
},
|
|
552
|
+
skip_while_active: {
|
|
553
|
+
type: 'boolean',
|
|
554
|
+
description: 'Skip a fire entirely while the agent still has a queued or running task, or leads an item awaiting review.',
|
|
555
|
+
},
|
|
535
556
|
task_ids: {
|
|
536
557
|
type: 'array',
|
|
537
558
|
items: { type: 'string' },
|
|
@@ -575,6 +596,23 @@ export const AGENT_BUILDER_TOOLS = [
|
|
|
575
596
|
type: 'boolean',
|
|
576
597
|
description: 'Run once across all projects (true) or once per project (false)',
|
|
577
598
|
},
|
|
599
|
+
preflight_check: {
|
|
600
|
+
type: 'string',
|
|
601
|
+
enum: ['claimable-work', 'claimable-check'],
|
|
602
|
+
description: 'LLM-free condition evaluated when the schedule fires; a false result skips the fire with no session and no cost. ' +
|
|
603
|
+
'"claimable-work": an approved, unclaimed item is assigned to the agent or sits in one of its work pools. ' +
|
|
604
|
+
'"claimable-check": a pending, unclaimed review check sits on an item in one of its pools. Null to clear.',
|
|
605
|
+
},
|
|
606
|
+
check_kinds: {
|
|
607
|
+
type: 'array',
|
|
608
|
+
items: { type: 'string' },
|
|
609
|
+
description: 'With "claimable-check": only checks of these kinds wake the schedule (e.g. ["security-review"]), so reviewers ' +
|
|
610
|
+
'sharing a pool each answer their own kind. Empty for every kind.',
|
|
611
|
+
},
|
|
612
|
+
skip_while_active: {
|
|
613
|
+
type: 'boolean',
|
|
614
|
+
description: 'Skip a fire entirely while the agent still has a queued or running task, or leads an item awaiting review.',
|
|
615
|
+
},
|
|
578
616
|
task_ids: {
|
|
579
617
|
type: 'array',
|
|
580
618
|
items: { type: 'string' },
|
|
@@ -798,6 +836,19 @@ const AgentTaskSchema = z.object({
|
|
|
798
836
|
org_slug: orgSlugField,
|
|
799
837
|
});
|
|
800
838
|
const SkillIdSchema = z.object({ skill_id: z.string(), org_slug: orgSlugField });
|
|
839
|
+
/**
|
|
840
|
+
* A schedule enabled on an agent whose own scheduling switch is off never
|
|
841
|
+
* fires (#2083) — say so in the result rather than letting the caller find
|
|
842
|
+
* out from a schedule that stays silent.
|
|
843
|
+
*/
|
|
844
|
+
async function schedulingOffWarning(client, agentId, scheduleEnabled, orgSlug) {
|
|
845
|
+
if (!scheduleEnabled)
|
|
846
|
+
return '';
|
|
847
|
+
const agent = await client.getAgent(agentId, orgSlug);
|
|
848
|
+
return !agent || agent.schedulingEnabled
|
|
849
|
+
? ''
|
|
850
|
+
: "\n\nWARNING: this agent's scheduling is switched off, so the schedule will not fire until update_agent sets scheduling_enabled: true.";
|
|
851
|
+
}
|
|
801
852
|
export async function handleAgentBuilderTool(name, args, client) {
|
|
802
853
|
const text = (t) => JSON.stringify(t, null, 2);
|
|
803
854
|
switch (name) {
|
|
@@ -855,6 +906,7 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
855
906
|
llm_model: z.string().nullable().optional(),
|
|
856
907
|
llm_family: z.string().nullable().optional(),
|
|
857
908
|
api_key_permissions: z.array(z.string()).optional(),
|
|
909
|
+
scheduling_enabled: z.boolean().optional(),
|
|
858
910
|
org_slug: orgSlugField,
|
|
859
911
|
})
|
|
860
912
|
.parse(args);
|
|
@@ -878,6 +930,8 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
878
930
|
fields.llmFamily = rest.llm_family;
|
|
879
931
|
if (rest.api_key_permissions !== undefined)
|
|
880
932
|
fields.apiKeyPermissions = rest.api_key_permissions;
|
|
933
|
+
if (rest.scheduling_enabled !== undefined)
|
|
934
|
+
fields.schedulingEnabled = rest.scheduling_enabled;
|
|
881
935
|
const agent = await client.updateAgent(agent_id, fields, resolveOrg(parsed));
|
|
882
936
|
return { content: [{ type: 'text', text: `Updated agent\n\n${text(agent)}` }] };
|
|
883
937
|
}
|
|
@@ -1166,6 +1220,9 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
1166
1220
|
timezone: z.string().optional(),
|
|
1167
1221
|
dst_aware: z.boolean().optional(),
|
|
1168
1222
|
multi_project: z.boolean().optional(),
|
|
1223
|
+
preflight_check: z.enum(['claimable-work', 'claimable-check']).nullable().optional(),
|
|
1224
|
+
check_kinds: z.array(z.string()).optional(),
|
|
1225
|
+
skip_while_active: z.boolean().optional(),
|
|
1169
1226
|
task_ids: z.array(z.string()).optional(),
|
|
1170
1227
|
org_slug: orgSlugField,
|
|
1171
1228
|
})
|
|
@@ -1190,12 +1247,22 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
1190
1247
|
body.dstAware = rest.dst_aware;
|
|
1191
1248
|
if (rest.multi_project !== undefined)
|
|
1192
1249
|
body.multiProject = rest.multi_project;
|
|
1250
|
+
if (rest.preflight_check !== undefined)
|
|
1251
|
+
body.preflightCheck = rest.preflight_check;
|
|
1252
|
+
if (rest.check_kinds !== undefined)
|
|
1253
|
+
body.checkKinds = rest.check_kinds;
|
|
1254
|
+
if (rest.skip_while_active !== undefined)
|
|
1255
|
+
body.skipWhileActive = rest.skip_while_active;
|
|
1193
1256
|
if (rest.task_ids !== undefined)
|
|
1194
1257
|
body.taskIds = rest.task_ids;
|
|
1195
1258
|
const schedule = await client.createAgentSchedule(agent_id, body, resolveOrg(parsed));
|
|
1259
|
+
const warning = await schedulingOffWarning(client, agent_id, schedule.enabled, resolveOrg(parsed));
|
|
1196
1260
|
return {
|
|
1197
1261
|
content: [
|
|
1198
|
-
{
|
|
1262
|
+
{
|
|
1263
|
+
type: 'text',
|
|
1264
|
+
text: `Created schedule "${schedule.name}"${warning}\n\n${text(schedule)}`,
|
|
1265
|
+
},
|
|
1199
1266
|
],
|
|
1200
1267
|
};
|
|
1201
1268
|
}
|
|
@@ -1213,6 +1280,9 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
1213
1280
|
timezone: z.string().optional(),
|
|
1214
1281
|
dst_aware: z.boolean().optional(),
|
|
1215
1282
|
multi_project: z.boolean().optional(),
|
|
1283
|
+
preflight_check: z.enum(['claimable-work', 'claimable-check']).nullable().optional(),
|
|
1284
|
+
check_kinds: z.array(z.string()).optional(),
|
|
1285
|
+
skip_while_active: z.boolean().optional(),
|
|
1216
1286
|
task_ids: z.array(z.string()).optional(),
|
|
1217
1287
|
org_slug: orgSlugField,
|
|
1218
1288
|
})
|
|
@@ -1237,10 +1307,19 @@ export async function handleAgentBuilderTool(name, args, client) {
|
|
|
1237
1307
|
body.dstAware = rest.dst_aware;
|
|
1238
1308
|
if (rest.multi_project !== undefined)
|
|
1239
1309
|
body.multiProject = rest.multi_project;
|
|
1310
|
+
if (rest.preflight_check !== undefined)
|
|
1311
|
+
body.preflightCheck = rest.preflight_check;
|
|
1312
|
+
if (rest.check_kinds !== undefined)
|
|
1313
|
+
body.checkKinds = rest.check_kinds;
|
|
1314
|
+
if (rest.skip_while_active !== undefined)
|
|
1315
|
+
body.skipWhileActive = rest.skip_while_active;
|
|
1240
1316
|
if (rest.task_ids !== undefined)
|
|
1241
1317
|
body.taskIds = rest.task_ids;
|
|
1242
1318
|
const schedule = await client.updateAgentSchedule(agent_id, schedule_id, body, resolveOrg(parsed));
|
|
1243
|
-
|
|
1319
|
+
const warning = await schedulingOffWarning(client, agent_id, schedule.enabled, resolveOrg(parsed));
|
|
1320
|
+
return {
|
|
1321
|
+
content: [{ type: 'text', text: `Updated schedule${warning}\n\n${text(schedule)}` }],
|
|
1322
|
+
};
|
|
1244
1323
|
}
|
|
1245
1324
|
// ─── Skills ─────────────────────────────────────────────────────────────
|
|
1246
1325
|
case 'create_skill': {
|
|
@@ -98,3 +98,68 @@ describe('extra instructions on a task run over MCP (#2048)', () => {
|
|
|
98
98
|
expect(runAgentTask.mock.calls[0][6]).toBeUndefined();
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
|
+
// #2083: everything the schedule editor can set is settable over MCP, and a
|
|
102
|
+
// schedule enabled on an agent whose scheduling switch is off says so.
|
|
103
|
+
describe('schedule pre-flight and scheduling switch over MCP (#2083)', () => {
|
|
104
|
+
const SCHEDULE_FIELDS = ['preflight_check', 'check_kinds', 'skip_while_active'];
|
|
105
|
+
it.each(['create_agent_schedule', 'update_agent_schedule'])('%s advertises the pre-flight fields', (name) => {
|
|
106
|
+
const properties = toolNamed(name).inputSchema.properties;
|
|
107
|
+
expect(Object.keys(properties)).toEqual(expect.arrayContaining(SCHEDULE_FIELDS));
|
|
108
|
+
});
|
|
109
|
+
it('update_agent advertises the scheduling switch', () => {
|
|
110
|
+
const properties = toolNamed('update_agent').inputSchema.properties;
|
|
111
|
+
expect(Object.keys(properties)).toContain('scheduling_enabled');
|
|
112
|
+
});
|
|
113
|
+
function scheduleClient(schedulingEnabled) {
|
|
114
|
+
const schedule = { id: 'sched-1', name: 'Reviews', enabled: true };
|
|
115
|
+
const createAgentSchedule = vi.fn().mockResolvedValue(schedule);
|
|
116
|
+
const updateAgentSchedule = vi.fn().mockResolvedValue(schedule);
|
|
117
|
+
const updateAgent = vi.fn().mockResolvedValue({ id: 'agent-1', schedulingEnabled });
|
|
118
|
+
const getAgent = vi.fn().mockResolvedValue({ id: 'agent-1', schedulingEnabled });
|
|
119
|
+
return {
|
|
120
|
+
client: {
|
|
121
|
+
createAgentSchedule,
|
|
122
|
+
updateAgentSchedule,
|
|
123
|
+
updateAgent,
|
|
124
|
+
getAgent,
|
|
125
|
+
},
|
|
126
|
+
createAgentSchedule,
|
|
127
|
+
updateAgentSchedule,
|
|
128
|
+
updateAgent,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
it('sends the pre-flight, kinds and skip-while-active when creating a schedule', async () => {
|
|
132
|
+
const { client, createAgentSchedule } = scheduleClient(true);
|
|
133
|
+
await handleAgentBuilderTool('create_agent_schedule', {
|
|
134
|
+
agent_id: 'agent-1',
|
|
135
|
+
preflight_check: 'claimable-check',
|
|
136
|
+
check_kinds: ['security-review'],
|
|
137
|
+
skip_while_active: true,
|
|
138
|
+
}, client);
|
|
139
|
+
expect(createAgentSchedule.mock.calls[0][1]).toMatchObject({
|
|
140
|
+
preflightCheck: 'claimable-check',
|
|
141
|
+
checkKinds: ['security-review'],
|
|
142
|
+
skipWhileActive: true,
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
it('sends the same fields when updating a schedule', async () => {
|
|
146
|
+
const { client, updateAgentSchedule } = scheduleClient(true);
|
|
147
|
+
await handleAgentBuilderTool('update_agent_schedule', { agent_id: 'agent-1', schedule_id: 'sched-1', preflight_check: null, check_kinds: [] }, client);
|
|
148
|
+
expect(updateAgentSchedule.mock.calls[0][2]).toEqual({ preflightCheck: null, checkKinds: [] });
|
|
149
|
+
});
|
|
150
|
+
it('sends the scheduling switch when updating an agent', async () => {
|
|
151
|
+
const { client, updateAgent } = scheduleClient(true);
|
|
152
|
+
await handleAgentBuilderTool('update_agent', { agent_id: 'agent-1', scheduling_enabled: true }, client);
|
|
153
|
+
expect(updateAgent.mock.calls[0][1]).toEqual({ schedulingEnabled: true });
|
|
154
|
+
});
|
|
155
|
+
it('warns when an enabled schedule lands on an agent whose scheduling is off', async () => {
|
|
156
|
+
const { client } = scheduleClient(false);
|
|
157
|
+
const result = await handleAgentBuilderTool('create_agent_schedule', { agent_id: 'agent-1', enabled: true }, client);
|
|
158
|
+
expect(result.content[0].text).toContain('scheduling is switched off');
|
|
159
|
+
});
|
|
160
|
+
it('stays quiet when the agent is scheduling', async () => {
|
|
161
|
+
const { client } = scheduleClient(true);
|
|
162
|
+
const result = await handleAgentBuilderTool('create_agent_schedule', { agent_id: 'agent-1', enabled: true }, client);
|
|
163
|
+
expect(result.content[0].text).not.toContain('WARNING');
|
|
164
|
+
});
|
|
165
|
+
});
|
package/dist/client.js
CHANGED
|
@@ -247,6 +247,8 @@ export class WolfpackClient {
|
|
|
247
247
|
params.set('workItemId', filter.workItemId);
|
|
248
248
|
if (filter.status)
|
|
249
249
|
params.set('status', filter.status);
|
|
250
|
+
if (filter.kind)
|
|
251
|
+
params.set('kind', filter.kind);
|
|
250
252
|
const query = params.toString();
|
|
251
253
|
return this.api.get(this.withTeamSlug(`/work-item-checks${query ? `?${query}` : ''}`, teamSlug));
|
|
252
254
|
}
|
|
@@ -502,6 +504,16 @@ export class WolfpackClient {
|
|
|
502
504
|
const query = params.toString();
|
|
503
505
|
return this.api.get(`/categories${query ? `?${query}` : ''}`);
|
|
504
506
|
}
|
|
507
|
+
// Work pool methods (#2083)
|
|
508
|
+
async listWorkPools(teamSlug) {
|
|
509
|
+
return this.api.get(this.withTeamSlug('/work-pools', teamSlug));
|
|
510
|
+
}
|
|
511
|
+
async addWorkPoolMember(workPool, userId, teamSlug) {
|
|
512
|
+
return this.api.post(this.withTeamSlug(`/work-pools/${encodeURIComponent(workPool)}/members`, teamSlug), { userId });
|
|
513
|
+
}
|
|
514
|
+
async removeWorkPoolMember(workPool, userId, teamSlug) {
|
|
515
|
+
await this.api.delete(this.withTeamSlug(`/work-pools/${encodeURIComponent(workPool)}/members/${encodeURIComponent(userId)}`, teamSlug));
|
|
516
|
+
}
|
|
505
517
|
// Tag methods
|
|
506
518
|
async listTags(teamSlug) {
|
|
507
519
|
const params = new URLSearchParams();
|
package/dist/index.js
CHANGED
|
@@ -215,11 +215,20 @@ const SubmitWorkItemFormSchema = z.object({
|
|
|
215
215
|
.optional()
|
|
216
216
|
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
217
217
|
});
|
|
218
|
+
const WorkPoolMemberSchema = z.object({
|
|
219
|
+
work_pool: z.string().describe('Work pool id or name'),
|
|
220
|
+
user_id: z.string().describe('The user id to add or remove'),
|
|
221
|
+
project_slug: z
|
|
222
|
+
.string()
|
|
223
|
+
.optional()
|
|
224
|
+
.describe('Project slug (required for multi-project users, use list_projects to get slugs)'),
|
|
225
|
+
});
|
|
218
226
|
const ListWorkItemChecksSchema = z.object({
|
|
219
227
|
work_item_id: refIdString()
|
|
220
228
|
.optional()
|
|
221
229
|
.describe('The refId of a work item; omit for your reviewer inbox'),
|
|
222
230
|
status: z.enum(['pending', 'passed', 'failed']).optional().describe('Filter by check status'),
|
|
231
|
+
kind: z.string().optional().describe('Filter by check kind, e.g. code-review or security-review'),
|
|
223
232
|
project_slug: z
|
|
224
233
|
.string()
|
|
225
234
|
.optional()
|
|
@@ -1100,6 +1109,10 @@ class WolfpackMCPServer {
|
|
|
1100
1109
|
enum: ['pending', 'passed', 'failed'],
|
|
1101
1110
|
description: 'Filter by check status',
|
|
1102
1111
|
},
|
|
1112
|
+
kind: {
|
|
1113
|
+
type: 'string',
|
|
1114
|
+
description: 'Filter by check kind (code-review, security-review, ...). A reviewer that answers one kind lists only that kind.',
|
|
1115
|
+
},
|
|
1103
1116
|
project_slug: {
|
|
1104
1117
|
type: 'string',
|
|
1105
1118
|
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
@@ -1837,6 +1850,52 @@ class WolfpackMCPServer {
|
|
|
1837
1850
|
},
|
|
1838
1851
|
},
|
|
1839
1852
|
},
|
|
1853
|
+
// Work pool tools (#2083)
|
|
1854
|
+
{
|
|
1855
|
+
name: 'list_work_pools',
|
|
1856
|
+
description: 'List the work pools in a project with their members. Reviewer and DevOps agents find their checks through pool membership, so this is how to see who is routed where.',
|
|
1857
|
+
inputSchema: {
|
|
1858
|
+
type: 'object',
|
|
1859
|
+
properties: {
|
|
1860
|
+
project_slug: {
|
|
1861
|
+
type: 'string',
|
|
1862
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1863
|
+
},
|
|
1864
|
+
},
|
|
1865
|
+
},
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
name: 'add_work_pool_member',
|
|
1869
|
+
description: "Add a user or agent (by user id, e.g. an agent profile's userId) to a work pool, named by id or name. Requires mcp:agents:update.",
|
|
1870
|
+
inputSchema: {
|
|
1871
|
+
type: 'object',
|
|
1872
|
+
properties: {
|
|
1873
|
+
work_pool: { type: 'string', description: 'Work pool id or name' },
|
|
1874
|
+
user_id: { type: 'string', description: 'The user id to add' },
|
|
1875
|
+
project_slug: {
|
|
1876
|
+
type: 'string',
|
|
1877
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1878
|
+
},
|
|
1879
|
+
},
|
|
1880
|
+
required: ['work_pool', 'user_id'],
|
|
1881
|
+
},
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
name: 'remove_work_pool_member',
|
|
1885
|
+
description: 'Remove a user or agent from a work pool. Requires mcp:agents:update.',
|
|
1886
|
+
inputSchema: {
|
|
1887
|
+
type: 'object',
|
|
1888
|
+
properties: {
|
|
1889
|
+
work_pool: { type: 'string', description: 'Work pool id or name' },
|
|
1890
|
+
user_id: { type: 'string', description: 'The user id to remove' },
|
|
1891
|
+
project_slug: {
|
|
1892
|
+
type: 'string',
|
|
1893
|
+
description: 'Project slug (required for multi-project users, use list_projects to get slugs)',
|
|
1894
|
+
},
|
|
1895
|
+
},
|
|
1896
|
+
required: ['work_pool', 'user_id'],
|
|
1897
|
+
},
|
|
1898
|
+
},
|
|
1840
1899
|
// Tag tools
|
|
1841
1900
|
{
|
|
1842
1901
|
name: 'list_tags',
|
|
@@ -2439,7 +2498,7 @@ class WolfpackMCPServer {
|
|
|
2439
2498
|
case 'list_work_item_checks': {
|
|
2440
2499
|
const parsed = ListWorkItemChecksSchema.parse(args);
|
|
2441
2500
|
const teamSlug = parsed.project_slug || this.client.getProjectSlug() || undefined;
|
|
2442
|
-
const checks = await this.client.listWorkItemChecks({ workItemId: parsed.work_item_id, status: parsed.status }, teamSlug);
|
|
2501
|
+
const checks = await this.client.listWorkItemChecks({ workItemId: parsed.work_item_id, status: parsed.status, kind: parsed.kind }, teamSlug);
|
|
2443
2502
|
const text = checks.length === 0
|
|
2444
2503
|
? parsed.work_item_id
|
|
2445
2504
|
? 'No review checks on this work item'
|
|
@@ -2938,6 +2997,36 @@ class WolfpackMCPServer {
|
|
|
2938
2997
|
content: [{ type: 'text', text: JSON.stringify(categories, null, 2) }],
|
|
2939
2998
|
};
|
|
2940
2999
|
}
|
|
3000
|
+
// Work pool handlers (#2083)
|
|
3001
|
+
case 'list_work_pools': {
|
|
3002
|
+
const parsed = ListCategoriesSchema.parse(args);
|
|
3003
|
+
const pools = await this.client.listWorkPools(parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3004
|
+
return { content: [{ type: 'text', text: JSON.stringify(pools, null, 2) }] };
|
|
3005
|
+
}
|
|
3006
|
+
case 'add_work_pool_member': {
|
|
3007
|
+
const parsed = WorkPoolMemberSchema.parse(args);
|
|
3008
|
+
await this.client.addWorkPoolMember(parsed.work_pool, parsed.user_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3009
|
+
return {
|
|
3010
|
+
content: [
|
|
3011
|
+
{
|
|
3012
|
+
type: 'text',
|
|
3013
|
+
text: `Added ${parsed.user_id} to work pool "${parsed.work_pool}"`,
|
|
3014
|
+
},
|
|
3015
|
+
],
|
|
3016
|
+
};
|
|
3017
|
+
}
|
|
3018
|
+
case 'remove_work_pool_member': {
|
|
3019
|
+
const parsed = WorkPoolMemberSchema.parse(args);
|
|
3020
|
+
await this.client.removeWorkPoolMember(parsed.work_pool, parsed.user_id, parsed.project_slug || this.client.getProjectSlug() || undefined);
|
|
3021
|
+
return {
|
|
3022
|
+
content: [
|
|
3023
|
+
{
|
|
3024
|
+
type: 'text',
|
|
3025
|
+
text: `Removed ${parsed.user_id} from work pool "${parsed.work_pool}"`,
|
|
3026
|
+
},
|
|
3027
|
+
],
|
|
3028
|
+
};
|
|
3029
|
+
}
|
|
2941
3030
|
// Tag handlers
|
|
2942
3031
|
case 'list_tags': {
|
|
2943
3032
|
const parsed = ListTagsSchema.parse(args);
|