@chorus-aidlc/chorus-openclaw-plugin 0.1.8 → 0.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chorus-aidlc/chorus-openclaw-plugin",
3
- "version": "0.1.8",
3
+ "version": "0.2.1",
4
4
  "description": "OpenClaw plugin for Chorus AI-DLC collaboration platform — SSE real-time events + MCP tool integration",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import { ChorusEventRouter } from "./event-router.js";
8
8
  import { registerPmTools } from "./tools/pm-tools.js";
9
9
  import { registerDevTools } from "./tools/dev-tools.js";
10
10
  import { registerCommonTools } from "./tools/common-tools.js";
11
+ import { registerAdminTools } from "./tools/admin-tools.js";
11
12
  import { registerChorusCommands } from "./commands.js";
12
13
 
13
14
  /**
@@ -134,6 +135,7 @@ const plugin = {
134
135
  registerPmTools(api, mcpClient);
135
136
  registerDevTools(api, mcpClient);
136
137
  registerCommonTools(api, mcpClient);
138
+ registerAdminTools(api, mcpClient);
137
139
 
138
140
  // --- Commands ---
139
141
  registerChorusCommands(api, mcpClient, () => sseListener?.status ?? "disconnected");
@@ -0,0 +1,76 @@
1
+ import type { ChorusMcpClient } from "../mcp-client.js";
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ export function registerAdminTools(api: any, mcpClient: ChorusMcpClient) {
5
+ api.registerTool({
6
+ name: "chorus_admin_create_project",
7
+ description: "Create a new project. Call chorus_get_project_groups first to find the right groupUuid.",
8
+ parameters: {
9
+ type: "object",
10
+ properties: {
11
+ name: { type: "string", description: "Project name" },
12
+ description: { type: "string", description: "Project description" },
13
+ groupUuid: { type: "string", description: "Project group UUID (optional, use chorus_get_project_groups to list groups)" },
14
+ },
15
+ required: ["name"],
16
+ additionalProperties: false,
17
+ },
18
+ async execute(_id: string, { name, description, groupUuid }: { name: string; description?: string; groupUuid?: string }) {
19
+ const args: Record<string, unknown> = { name };
20
+ if (description) args.description = description;
21
+ if (groupUuid) args.groupUuid = groupUuid;
22
+ const result = await mcpClient.callTool("chorus_admin_create_project", args);
23
+ return JSON.stringify(result, null, 2);
24
+ },
25
+ });
26
+
27
+ api.registerTool({
28
+ name: "chorus_admin_create_project_group",
29
+ description: "Create a new project group for organizing projects.",
30
+ parameters: {
31
+ type: "object",
32
+ properties: {
33
+ name: { type: "string", description: "Group name" },
34
+ description: { type: "string", description: "Group description" },
35
+ },
36
+ required: ["name"],
37
+ additionalProperties: false,
38
+ },
39
+ async execute(_id: string, { name, description }: { name: string; description?: string }) {
40
+ const args: Record<string, unknown> = { name };
41
+ if (description) args.description = description;
42
+ const result = await mcpClient.callTool("chorus_admin_create_project_group", args);
43
+ return JSON.stringify(result, null, 2);
44
+ },
45
+ });
46
+
47
+ api.registerTool({
48
+ name: "chorus_mark_acceptance_criteria",
49
+ description: "Mark acceptance criteria as passed or failed (admin verification). Blocked criteria prevent task from being verified (to_verify -> done).",
50
+ parameters: {
51
+ type: "object",
52
+ properties: {
53
+ taskUuid: { type: "string", description: "Task UUID" },
54
+ criteria: {
55
+ type: "array",
56
+ description: "Array of { uuid, status: 'passed'|'failed', evidence?: string }",
57
+ items: {
58
+ type: "object",
59
+ properties: {
60
+ uuid: { type: "string", description: "AcceptanceCriterion UUID" },
61
+ status: { type: "string", description: "Verification result: passed | failed" },
62
+ evidence: { type: "string", description: "Optional evidence/notes" },
63
+ },
64
+ required: ["uuid", "status"],
65
+ },
66
+ },
67
+ },
68
+ required: ["taskUuid", "criteria"],
69
+ additionalProperties: false,
70
+ },
71
+ async execute(_id: string, { taskUuid, criteria }: { taskUuid: string; criteria: Array<{ uuid: string; status: string; evidence?: string }> }) {
72
+ const result = await mcpClient.callTool("chorus_mark_acceptance_criteria", { taskUuid, criteria });
73
+ return JSON.stringify(result, null, 2);
74
+ },
75
+ });
76
+ }
@@ -351,26 +351,35 @@ export function registerCommonTools(api: any, mcpClient: ChorusMcpClient) {
351
351
  },
352
352
  });
353
353
 
354
- // --- Admin tools ---
354
+ // --- Project group tools ---
355
355
 
356
356
  api.registerTool({
357
- name: "chorus_admin_create_project",
358
- description: "Create a new project. Call chorus_get_project_groups first to find the right groupUuid.",
357
+ name: "chorus_get_project_groups",
358
+ description: "List all project groups. Returns groups with project counts and completion rates.",
359
+ parameters: {
360
+ type: "object",
361
+ properties: {},
362
+ additionalProperties: false,
363
+ },
364
+ async execute() {
365
+ const result = await mcpClient.callTool("chorus_get_project_groups", {});
366
+ return JSON.stringify(result, null, 2);
367
+ },
368
+ });
369
+
370
+ api.registerTool({
371
+ name: "chorus_get_project_group",
372
+ description: "Get a single project group with its projects and stats.",
359
373
  parameters: {
360
374
  type: "object",
361
375
  properties: {
362
- name: { type: "string", description: "Project name" },
363
- description: { type: "string", description: "Project description" },
364
- groupUuid: { type: "string", description: "Project group UUID (optional, use chorus_get_project_groups to list groups)" },
376
+ groupUuid: { type: "string", description: "Project group UUID" },
365
377
  },
366
- required: ["name"],
378
+ required: ["groupUuid"],
367
379
  additionalProperties: false,
368
380
  },
369
- async execute(_id: string, { name, description, groupUuid }: { name: string; description?: string; groupUuid?: string }) {
370
- const args: Record<string, unknown> = { name };
371
- if (description) args.description = description;
372
- if (groupUuid) args.groupUuid = groupUuid;
373
- const result = await mcpClient.callTool("chorus_admin_create_project", args);
381
+ async execute(_id: string, { groupUuid }: { groupUuid: string }) {
382
+ const result = await mcpClient.callTool("chorus_get_project_group", { groupUuid });
374
383
  return JSON.stringify(result, null, 2);
375
384
  },
376
385
  });
@@ -82,4 +82,35 @@ export function registerDevTools(api: any, mcpClient: ChorusMcpClient) {
82
82
  return JSON.stringify(result, null, 2);
83
83
  },
84
84
  });
85
+
86
+ api.registerTool({
87
+ name: "chorus_report_criteria_self_check",
88
+ description: "Report self-check results on acceptance criteria for a task you're working on. For required criteria, keep working until all pass. Only mark optional criteria as failed if out of scope.",
89
+ parameters: {
90
+ type: "object",
91
+ properties: {
92
+ taskUuid: { type: "string", description: "Task UUID" },
93
+ criteria: {
94
+ type: "array",
95
+ description: "Array of { uuid, devStatus: 'passed'|'failed', devEvidence?: string }",
96
+ items: {
97
+ type: "object",
98
+ properties: {
99
+ uuid: { type: "string", description: "AcceptanceCriterion UUID" },
100
+ devStatus: { type: "string", description: "Self-check result: passed | failed" },
101
+ devEvidence: { type: "string", description: "Optional evidence/notes" },
102
+ },
103
+ required: ["uuid", "devStatus"],
104
+ },
105
+ },
106
+ },
107
+ required: ["taskUuid", "criteria"],
108
+ additionalProperties: false,
109
+ },
110
+ async execute(_id: string, { taskUuid, criteria }: { taskUuid: string; criteria: Array<{ uuid: string; devStatus: string; devEvidence?: string }> }) {
111
+ const result = await mcpClient.callTool("chorus_report_criteria_self_check", { taskUuid, criteria });
112
+ return JSON.stringify(result, null, 2);
113
+ },
114
+ });
115
+
85
116
  }
@@ -108,7 +108,7 @@ export function registerPmTools(api: any, mcpClient: ChorusMcpClient) {
108
108
  inputUuids: { type: "array", description: "Array of input UUIDs", items: { type: "string" } },
109
109
  description: { type: "string", description: "Proposal description" },
110
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" } },
111
+ taskDrafts: { type: "array", description: "Array of { title, description?, priority?, storyPoints?, acceptanceCriteriaItems?, dependsOnDraftUuids? }", items: { type: "object" } },
112
112
  },
113
113
  required: ["projectUuid", "title", "inputType", "inputUuids"],
114
114
  additionalProperties: false,
@@ -158,20 +158,20 @@ export function registerPmTools(api: any, mcpClient: ChorusMcpClient) {
158
158
  description: { type: "string", description: "Task description" },
159
159
  priority: { type: "string", description: 'Priority: "low", "medium", or "high"' },
160
160
  storyPoints: { type: "number", description: "Effort estimate in agent hours" },
161
- acceptanceCriteria: { type: "string", description: "Acceptance criteria in Markdown" },
161
+ acceptanceCriteriaItems: { type: "array", description: "Structured acceptance criteria: [{ description, required? }]", items: { type: "object", properties: { description: { type: "string" }, required: { type: "boolean" } }, required: ["description"] } },
162
162
  dependsOnDraftUuids: { type: "array", description: "Dependent task draft UUIDs", items: { type: "string" } },
163
163
  },
164
164
  required: ["proposalUuid", "title"],
165
165
  additionalProperties: false,
166
166
  },
167
167
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
168
- async execute(_id: string, { proposalUuid, title, description, priority, storyPoints, acceptanceCriteria, dependsOnDraftUuids }: any) {
168
+ async execute(_id: string, { proposalUuid, title, description, priority, storyPoints, acceptanceCriteriaItems, dependsOnDraftUuids }: any) {
169
169
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
170
170
  const args: Record<string, any> = { proposalUuid, title };
171
171
  if (description !== undefined) args.description = description;
172
172
  if (priority !== undefined) args.priority = priority;
173
173
  if (storyPoints !== undefined) args.storyPoints = storyPoints;
174
- if (acceptanceCriteria !== undefined) args.acceptanceCriteria = acceptanceCriteria;
174
+ if (acceptanceCriteriaItems !== undefined) args.acceptanceCriteriaItems = acceptanceCriteriaItems;
175
175
  if (dependsOnDraftUuids !== undefined) args.dependsOnDraftUuids = dependsOnDraftUuids;
176
176
  const result = await mcpClient.callTool("chorus_pm_add_task_draft", args);
177
177
  return JSON.stringify(result, null, 2);
@@ -237,21 +237,21 @@ export function registerPmTools(api: any, mcpClient: ChorusMcpClient) {
237
237
  description: { type: "string", description: "New task description" },
238
238
  priority: { type: "string", description: 'Priority: "low", "medium", or "high"' },
239
239
  storyPoints: { type: "number", description: "Effort estimate in agent hours" },
240
- acceptanceCriteria: { type: "string", description: "Acceptance criteria in Markdown" },
240
+ acceptanceCriteriaItems: { type: "array", description: "Structured acceptance criteria: [{ description, required? }]", items: { type: "object", properties: { description: { type: "string" }, required: { type: "boolean" } }, required: ["description"] } },
241
241
  dependsOnDraftUuids: { type: "array", description: "Task draft UUIDs this task depends on (sets execution order)", items: { type: "string" } },
242
242
  },
243
243
  required: ["proposalUuid", "draftUuid"],
244
244
  additionalProperties: false,
245
245
  },
246
246
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
- async execute(_id: string, { proposalUuid, draftUuid, title, description, priority, storyPoints, acceptanceCriteria, dependsOnDraftUuids }: any) {
247
+ async execute(_id: string, { proposalUuid, draftUuid, title, description, priority, storyPoints, acceptanceCriteriaItems, dependsOnDraftUuids }: any) {
248
248
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
249
  const args: Record<string, any> = { proposalUuid, draftUuid };
250
250
  if (title !== undefined) args.title = title;
251
251
  if (description !== undefined) args.description = description;
252
252
  if (priority !== undefined) args.priority = priority;
253
253
  if (storyPoints !== undefined) args.storyPoints = storyPoints;
254
- if (acceptanceCriteria !== undefined) args.acceptanceCriteria = acceptanceCriteria;
254
+ if (acceptanceCriteriaItems !== undefined) args.acceptanceCriteriaItems = acceptanceCriteriaItems;
255
255
  if (dependsOnDraftUuids !== undefined) args.dependsOnDraftUuids = dependsOnDraftUuids;
256
256
  const result = await mcpClient.callTool("chorus_pm_update_task_draft", args);
257
257
  return JSON.stringify(result, null, 2);