@chorus-aidlc/openclaw-plugin 0.1.0

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.
@@ -0,0 +1,356 @@
1
+ import type { ChorusMcpClient } from "../mcp-client.js";
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ export function registerPmTools(api: any, mcpClient: ChorusMcpClient) {
5
+ // 1. chorus_claim_idea
6
+ api.registerTool({
7
+ name: "chorus_claim_idea",
8
+ description: "Claim an open Idea for elaboration (open -> elaborating). After claiming, start elaboration or create a proposal directly.",
9
+ parameters: {
10
+ type: "object",
11
+ properties: {
12
+ ideaUuid: { type: "string", description: "UUID of the idea to claim" },
13
+ },
14
+ required: ["ideaUuid"],
15
+ additionalProperties: false,
16
+ },
17
+ async execute(_id: string, { ideaUuid }: { ideaUuid: string }) {
18
+ const result = await mcpClient.callTool("chorus_claim_idea", { ideaUuid });
19
+ return JSON.stringify(result, null, 2);
20
+ },
21
+ });
22
+
23
+ // 2. chorus_start_elaboration
24
+ api.registerTool({
25
+ name: "chorus_start_elaboration",
26
+ description: "Start an elaboration round for an Idea. Creates structured questions for the stakeholder to answer before proposal creation.",
27
+ parameters: {
28
+ type: "object",
29
+ properties: {
30
+ ideaUuid: { type: "string", description: "UUID of the idea" },
31
+ depth: { type: "string", description: 'Elaboration depth: "minimal", "standard", or "comprehensive"' },
32
+ questions: {
33
+ type: "array",
34
+ description: "Array of questions. Each: { id, text, category, options: [{ id, label, description? }] }",
35
+ items: { type: "object" },
36
+ },
37
+ },
38
+ required: ["ideaUuid", "depth", "questions"],
39
+ additionalProperties: false,
40
+ },
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ async execute(_id: string, { ideaUuid, depth, questions }: { ideaUuid: string; depth: string; questions: any[] }) {
43
+ const result = await mcpClient.callTool("chorus_pm_start_elaboration", { ideaUuid, depth, questions });
44
+ return JSON.stringify(result, null, 2);
45
+ },
46
+ });
47
+
48
+ // 3. chorus_answer_elaboration
49
+ api.registerTool({
50
+ name: "chorus_answer_elaboration",
51
+ description: "Answer elaboration questions for an Idea. Submits answers for a specific elaboration round.",
52
+ parameters: {
53
+ type: "object",
54
+ properties: {
55
+ ideaUuid: { type: "string", description: "UUID of the idea" },
56
+ roundUuid: { type: "string", description: "UUID of the elaboration round" },
57
+ answers: {
58
+ type: "array",
59
+ description: "Array of answers. Each: { questionId, selectedOptionId, customText }",
60
+ items: { type: "object" },
61
+ },
62
+ },
63
+ required: ["ideaUuid", "roundUuid", "answers"],
64
+ additionalProperties: false,
65
+ },
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ async execute(_id: string, { ideaUuid, roundUuid, answers }: { ideaUuid: string; roundUuid: string; answers: any[] }) {
68
+ const result = await mcpClient.callTool("chorus_answer_elaboration", { ideaUuid, roundUuid, answers });
69
+ return JSON.stringify(result, null, 2);
70
+ },
71
+ });
72
+
73
+ // 4. chorus_validate_elaboration
74
+ api.registerTool({
75
+ name: "chorus_validate_elaboration",
76
+ description: "Validate answers from an elaboration round. Empty issues array = all valid, marks elaboration as resolved.",
77
+ parameters: {
78
+ type: "object",
79
+ properties: {
80
+ ideaUuid: { type: "string", description: "UUID of the idea" },
81
+ roundUuid: { type: "string", description: "UUID of the elaboration round" },
82
+ issues: {
83
+ type: "array",
84
+ description: 'Array of issues. Each: { questionId, type: "contradiction"|"ambiguity"|"incomplete", description }. Empty = valid.',
85
+ items: { type: "object" },
86
+ },
87
+ },
88
+ required: ["ideaUuid", "roundUuid", "issues"],
89
+ additionalProperties: false,
90
+ },
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ async execute(_id: string, { ideaUuid, roundUuid, issues }: { ideaUuid: string; roundUuid: string; issues: any[] }) {
93
+ const result = await mcpClient.callTool("chorus_pm_validate_elaboration", { ideaUuid, roundUuid, issues });
94
+ return JSON.stringify(result, null, 2);
95
+ },
96
+ });
97
+
98
+ // 5. chorus_create_proposal
99
+ api.registerTool({
100
+ name: "chorus_create_proposal",
101
+ description: "Create a Proposal container with optional document drafts and task drafts.",
102
+ parameters: {
103
+ type: "object",
104
+ properties: {
105
+ projectUuid: { type: "string", description: "Project UUID" },
106
+ title: { type: "string", description: "Proposal title" },
107
+ inputType: { type: "string", description: 'Input source type: "idea" or "document"' },
108
+ inputUuids: { type: "array", description: "Array of input UUIDs", items: { type: "string" } },
109
+ description: { type: "string", description: "Proposal description" },
110
+ documentDrafts: { type: "array", description: "Array of { type, title, content }", items: { type: "object" } },
111
+ taskDrafts: { type: "array", description: "Array of { title, description?, priority?, storyPoints?, acceptanceCriteria?, dependsOnDraftUuids? }", items: { type: "object" } },
112
+ },
113
+ required: ["projectUuid", "title", "inputType", "inputUuids"],
114
+ additionalProperties: false,
115
+ },
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ async execute(_id: string, { projectUuid, title, inputType, inputUuids, description, documentDrafts, taskDrafts }: any) {
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ const args: Record<string, any> = { projectUuid, title, inputType, inputUuids };
120
+ if (description !== undefined) args.description = description;
121
+ if (documentDrafts !== undefined) args.documentDrafts = documentDrafts;
122
+ if (taskDrafts !== undefined) args.taskDrafts = taskDrafts;
123
+ const result = await mcpClient.callTool("chorus_pm_create_proposal", args);
124
+ return JSON.stringify(result, null, 2);
125
+ },
126
+ });
127
+
128
+ // 6. chorus_add_document_draft
129
+ api.registerTool({
130
+ name: "chorus_add_document_draft",
131
+ description: "Add a document draft to a pending Proposal container.",
132
+ parameters: {
133
+ type: "object",
134
+ properties: {
135
+ proposalUuid: { type: "string", description: "Proposal UUID" },
136
+ type: { type: "string", description: "Document type (prd, tech_design, adr, spec, guide)" },
137
+ title: { type: "string", description: "Document title" },
138
+ content: { type: "string", description: "Document content (Markdown)" },
139
+ },
140
+ required: ["proposalUuid", "type", "title", "content"],
141
+ additionalProperties: false,
142
+ },
143
+ async execute(_id: string, { proposalUuid, type, title, content }: { proposalUuid: string; type: string; title: string; content: string }) {
144
+ const result = await mcpClient.callTool("chorus_pm_add_document_draft", { proposalUuid, type, title, content });
145
+ return JSON.stringify(result, null, 2);
146
+ },
147
+ });
148
+
149
+ // 7. chorus_add_task_draft
150
+ api.registerTool({
151
+ name: "chorus_add_task_draft",
152
+ description: "Add a task draft to a pending Proposal container.",
153
+ parameters: {
154
+ type: "object",
155
+ properties: {
156
+ proposalUuid: { type: "string", description: "Proposal UUID" },
157
+ title: { type: "string", description: "Task title" },
158
+ description: { type: "string", description: "Task description" },
159
+ priority: { type: "string", description: 'Priority: "low", "medium", or "high"' },
160
+ storyPoints: { type: "number", description: "Effort estimate in agent hours" },
161
+ acceptanceCriteria: { type: "string", description: "Acceptance criteria in Markdown" },
162
+ dependsOnDraftUuids: { type: "array", description: "Dependent task draft UUIDs", items: { type: "string" } },
163
+ },
164
+ required: ["proposalUuid", "title"],
165
+ additionalProperties: false,
166
+ },
167
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
168
+ async execute(_id: string, { proposalUuid, title, description, priority, storyPoints, acceptanceCriteria, dependsOnDraftUuids }: any) {
169
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
170
+ const args: Record<string, any> = { proposalUuid, title };
171
+ if (description !== undefined) args.description = description;
172
+ if (priority !== undefined) args.priority = priority;
173
+ if (storyPoints !== undefined) args.storyPoints = storyPoints;
174
+ if (acceptanceCriteria !== undefined) args.acceptanceCriteria = acceptanceCriteria;
175
+ if (dependsOnDraftUuids !== undefined) args.dependsOnDraftUuids = dependsOnDraftUuids;
176
+ const result = await mcpClient.callTool("chorus_pm_add_task_draft", args);
177
+ return JSON.stringify(result, null, 2);
178
+ },
179
+ });
180
+
181
+ // 8. chorus_get_proposal — View full proposal with all drafts
182
+ api.registerTool({
183
+ name: "chorus_get_proposal",
184
+ description: "Get detailed information for a Proposal, including all document drafts and task drafts with their UUIDs. Use this to inspect proposal contents before modifying or submitting.",
185
+ parameters: {
186
+ type: "object",
187
+ properties: {
188
+ proposalUuid: { type: "string", description: "Proposal UUID" },
189
+ },
190
+ required: ["proposalUuid"],
191
+ additionalProperties: false,
192
+ },
193
+ async execute(_id: string, { proposalUuid }: { proposalUuid: string }) {
194
+ const result = await mcpClient.callTool("chorus_get_proposal", { proposalUuid });
195
+ return JSON.stringify(result, null, 2);
196
+ },
197
+ });
198
+
199
+ // 9. chorus_update_document_draft — Modify an existing document draft
200
+ api.registerTool({
201
+ name: "chorus_update_document_draft",
202
+ description: "Update a document draft in a Proposal. Can change title, type, or content.",
203
+ parameters: {
204
+ type: "object",
205
+ properties: {
206
+ proposalUuid: { type: "string", description: "Proposal UUID" },
207
+ draftUuid: { type: "string", description: "Document draft UUID to update" },
208
+ title: { type: "string", description: "New document title" },
209
+ type: { type: "string", description: "New document type (prd, tech_design, adr, spec, guide)" },
210
+ content: { type: "string", description: "New document content (Markdown)" },
211
+ },
212
+ required: ["proposalUuid", "draftUuid"],
213
+ additionalProperties: false,
214
+ },
215
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
216
+ async execute(_id: string, { proposalUuid, draftUuid, title, type, content }: any) {
217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
218
+ const args: Record<string, any> = { proposalUuid, draftUuid };
219
+ if (title !== undefined) args.title = title;
220
+ if (type !== undefined) args.type = type;
221
+ if (content !== undefined) args.content = content;
222
+ const result = await mcpClient.callTool("chorus_pm_update_document_draft", args);
223
+ return JSON.stringify(result, null, 2);
224
+ },
225
+ });
226
+
227
+ // 10. chorus_update_task_draft — Modify an existing task draft (including dependencies)
228
+ api.registerTool({
229
+ name: "chorus_update_task_draft",
230
+ description: "Update a task draft in a Proposal. Use this to fix validation issues, add dependencies (dependsOnDraftUuids), change priority, etc.",
231
+ parameters: {
232
+ type: "object",
233
+ properties: {
234
+ proposalUuid: { type: "string", description: "Proposal UUID" },
235
+ draftUuid: { type: "string", description: "Task draft UUID to update" },
236
+ title: { type: "string", description: "New task title" },
237
+ description: { type: "string", description: "New task description" },
238
+ priority: { type: "string", description: 'Priority: "low", "medium", or "high"' },
239
+ storyPoints: { type: "number", description: "Effort estimate in agent hours" },
240
+ acceptanceCriteria: { type: "string", description: "Acceptance criteria in Markdown" },
241
+ dependsOnDraftUuids: { type: "array", description: "Task draft UUIDs this task depends on (sets execution order)", items: { type: "string" } },
242
+ },
243
+ required: ["proposalUuid", "draftUuid"],
244
+ additionalProperties: false,
245
+ },
246
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
+ async execute(_id: string, { proposalUuid, draftUuid, title, description, priority, storyPoints, acceptanceCriteria, dependsOnDraftUuids }: any) {
248
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
+ const args: Record<string, any> = { proposalUuid, draftUuid };
250
+ if (title !== undefined) args.title = title;
251
+ if (description !== undefined) args.description = description;
252
+ if (priority !== undefined) args.priority = priority;
253
+ if (storyPoints !== undefined) args.storyPoints = storyPoints;
254
+ if (acceptanceCriteria !== undefined) args.acceptanceCriteria = acceptanceCriteria;
255
+ if (dependsOnDraftUuids !== undefined) args.dependsOnDraftUuids = dependsOnDraftUuids;
256
+ const result = await mcpClient.callTool("chorus_pm_update_task_draft", args);
257
+ return JSON.stringify(result, null, 2);
258
+ },
259
+ });
260
+
261
+ // 11. chorus_remove_document_draft
262
+ api.registerTool({
263
+ name: "chorus_remove_document_draft",
264
+ description: "Remove a document draft from a Proposal.",
265
+ parameters: {
266
+ type: "object",
267
+ properties: {
268
+ proposalUuid: { type: "string", description: "Proposal UUID" },
269
+ draftUuid: { type: "string", description: "Document draft UUID to remove" },
270
+ },
271
+ required: ["proposalUuid", "draftUuid"],
272
+ additionalProperties: false,
273
+ },
274
+ async execute(_id: string, { proposalUuid, draftUuid }: { proposalUuid: string; draftUuid: string }) {
275
+ const result = await mcpClient.callTool("chorus_pm_remove_document_draft", { proposalUuid, draftUuid });
276
+ return JSON.stringify(result, null, 2);
277
+ },
278
+ });
279
+
280
+ // 12. chorus_remove_task_draft
281
+ api.registerTool({
282
+ name: "chorus_remove_task_draft",
283
+ description: "Remove a task draft from a Proposal.",
284
+ parameters: {
285
+ type: "object",
286
+ properties: {
287
+ proposalUuid: { type: "string", description: "Proposal UUID" },
288
+ draftUuid: { type: "string", description: "Task draft UUID to remove" },
289
+ },
290
+ required: ["proposalUuid", "draftUuid"],
291
+ additionalProperties: false,
292
+ },
293
+ async execute(_id: string, { proposalUuid, draftUuid }: { proposalUuid: string; draftUuid: string }) {
294
+ const result = await mcpClient.callTool("chorus_pm_remove_task_draft", { proposalUuid, draftUuid });
295
+ return JSON.stringify(result, null, 2);
296
+ },
297
+ });
298
+
299
+ // 13. chorus_validate_proposal
300
+ api.registerTool({
301
+ name: "chorus_validate_proposal",
302
+ description: "Validate a Proposal's completeness before submission. Returns errors (block submit), warnings, and info. ALWAYS call this before chorus_submit_proposal. If errors exist, use chorus_update_task_draft / chorus_update_document_draft to fix them, then validate again.",
303
+ parameters: {
304
+ type: "object",
305
+ properties: {
306
+ proposalUuid: { type: "string", description: "Proposal UUID to validate" },
307
+ },
308
+ required: ["proposalUuid"],
309
+ additionalProperties: false,
310
+ },
311
+ async execute(_id: string, { proposalUuid }: { proposalUuid: string }) {
312
+ const result = await mcpClient.callTool("chorus_pm_validate_proposal", { proposalUuid });
313
+ return JSON.stringify(result, null, 2);
314
+ },
315
+ });
316
+
317
+ // 9. chorus_submit_proposal
318
+ api.registerTool({
319
+ name: "chorus_submit_proposal",
320
+ description: "Submit a Proposal for approval (draft -> pending). Requires all input Ideas to have elaboration resolved.",
321
+ parameters: {
322
+ type: "object",
323
+ properties: {
324
+ proposalUuid: { type: "string", description: "Proposal UUID to submit" },
325
+ },
326
+ required: ["proposalUuid"],
327
+ additionalProperties: false,
328
+ },
329
+ async execute(_id: string, { proposalUuid }: { proposalUuid: string }) {
330
+ const result = await mcpClient.callTool("chorus_pm_submit_proposal", { proposalUuid });
331
+ return JSON.stringify(result, null, 2);
332
+ },
333
+ });
334
+
335
+ // 15. chorus_pm_create_idea
336
+ api.registerTool({
337
+ name: "chorus_pm_create_idea",
338
+ description: "Create a new Idea in a project. Use this when you discover a requirement, want to propose work, or record a user request.",
339
+ parameters: {
340
+ type: "object",
341
+ properties: {
342
+ projectUuid: { type: "string", description: "Project UUID" },
343
+ title: { type: "string", description: "Idea title" },
344
+ content: { type: "string", description: "Idea detailed description" },
345
+ },
346
+ required: ["projectUuid", "title"],
347
+ additionalProperties: false,
348
+ },
349
+ async execute(_id: string, { projectUuid, title, content }: { projectUuid: string; title: string; content?: string }) {
350
+ const args: Record<string, unknown> = { projectUuid, title };
351
+ if (content) args.content = content;
352
+ const result = await mcpClient.callTool("chorus_pm_create_idea", args);
353
+ return JSON.stringify(result, null, 2);
354
+ },
355
+ });
356
+ }