@chorus-aidlc/chorus-openclaw-plugin 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -60,29 +60,41 @@ Chorus Server
60
60
 
61
61
  ## Installation
62
62
 
63
- ### From local path (development)
63
+ ### 1. Install the plugin
64
64
 
65
- Add to your `~/.openclaw/openclaw.json`:
65
+ ```bash
66
+ openclaw plugins install @chorus-aidlc/chorus-openclaw-plugin
67
+ ```
68
+
69
+ ### 2. Enable hooks
70
+
71
+ Hooks are required for the agent wake mechanism. Add to your `~/.openclaw/openclaw.json`:
66
72
 
67
73
  ```json
68
74
  {
69
75
  "hooks": {
70
76
  "enabled": true,
71
77
  "token": "your-hooks-token"
72
- },
78
+ }
79
+ }
80
+ ```
81
+
82
+ > The `hooks.token` must be different from `gateway.auth.token`.
83
+
84
+ ### 3. Configure the plugin
85
+
86
+ Add the plugin entry to `~/.openclaw/openclaw.json`:
87
+
88
+ ```json
89
+ {
73
90
  "plugins": {
74
91
  "enabled": true,
75
- "allow": ["@chorus-aidlc/chorus-openclaw-plugin"],
76
- "load": {
77
- "paths": ["/path/to/openclaw-plugin"]
78
- },
79
92
  "entries": {
80
- "@chorus-aidlc/chorus-openclaw-plugin": {
93
+ "chorus-openclaw-plugin": {
81
94
  "enabled": true,
82
95
  "config": {
83
96
  "chorusUrl": "https://chorus.example.com",
84
97
  "apiKey": "cho_your_api_key_here",
85
- "projectUuids": [],
86
98
  "autoStart": true
87
99
  }
88
100
  }
@@ -91,13 +103,6 @@ Add to your `~/.openclaw/openclaw.json`:
91
103
  }
92
104
  ```
93
105
 
94
- ### From npm (planned)
95
-
96
- ```bash
97
- # Coming soon
98
- pnpm add @chorus-aidlc/chorus-openclaw-plugin
99
- ```
100
-
101
106
  ## Configuration
102
107
 
103
108
  | Field | Type | Required | Default | Description |
@@ -247,24 +252,10 @@ Wraps `@modelcontextprotocol/sdk` with:
247
252
  - Routes by notification `action` type
248
253
  - All handlers catch errors internally — never crashes the gateway
249
254
 
250
- ## Development
251
-
252
- ```bash
253
- # In the openclaw-plugin directory
254
- pnpm install
255
- pnpm dev # Watch mode (tsc --watch)
256
- pnpm build # Production build
257
-
258
- # Test with OpenClaw gateway
259
- cd /path/to/openclaw && node openclaw.mjs gateway
260
- ```
261
-
262
- No build step needed for development — OpenClaw loads `.ts` files directly via `jiti`.
263
-
264
255
  ## Troubleshooting
265
256
 
266
257
  ### "plugin id mismatch" warning
267
- Ensure `package.json` `name`, `openclaw.plugin.json` `id`, and `index.ts` `id` all match `@chorus-aidlc/chorus-openclaw-plugin`.
258
+ Ensure `openclaw.plugin.json` `id` and `index.ts` `id` both equal `chorus-openclaw-plugin`.
268
259
 
269
260
  ### "Wake agent failed: HTTP 405"
270
261
  Hooks are not enabled. Add to `openclaw.json`:
@@ -282,6 +273,38 @@ OpenClaw tool `execute` signature is `execute(toolCallId, params)` — the first
282
273
  ### Bedrock "inputSchema.json.type must be object"
283
274
  All tool `parameters` must be full JSON Schema with `type: "object"` at the top level, not shorthand `{ key: { type: "string" } }`.
284
275
 
276
+ ## Appendix: Local Development Install
277
+
278
+ If you're developing the plugin from the Chorus repo source:
279
+
280
+ ```bash
281
+ # No build needed — OpenClaw loads .ts files directly via jiti
282
+ cd /path/to/Chorus/packages/openclaw-plugin
283
+ ```
284
+
285
+ Add to `~/.openclaw/openclaw.json`:
286
+
287
+ ```json
288
+ {
289
+ "plugins": {
290
+ "enabled": true,
291
+ "load": {
292
+ "paths": ["/path/to/Chorus/packages/openclaw-plugin"]
293
+ },
294
+ "entries": {
295
+ "chorus-openclaw-plugin": {
296
+ "enabled": true,
297
+ "config": {
298
+ "chorusUrl": "http://localhost:3000",
299
+ "apiKey": "cho_your_dev_key",
300
+ "autoStart": true
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+ ```
307
+
285
308
  ## License
286
309
 
287
310
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chorus-aidlc/chorus-openclaw-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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/commands.ts CHANGED
@@ -49,14 +49,14 @@ interface AssignmentsResponse {
49
49
  function formatStatus(checkin: CheckinResponse, connectionStatus: string): string {
50
50
  const lines: string[] = [
51
51
  `Connection: ${connectionStatus}`,
52
- `Assignments: ${checkin.pending.ideasCount} ideas, ${checkin.pending.tasksCount} tasks`,
53
- `Notifications: ${checkin.notifications.unreadCount} unread`,
52
+ `Assignments: ${checkin?.pending?.ideasCount ?? 0} ideas, ${checkin?.pending?.tasksCount ?? 0} tasks`,
53
+ `Notifications: ${checkin?.notifications?.unreadCount ?? 0} unread`,
54
54
  ];
55
55
  return lines.join("\n");
56
56
  }
57
57
 
58
- function formatTaskList(tasks: AssignedTask[]): string {
59
- if (tasks.length === 0) {
58
+ function formatTaskList(tasks: AssignedTask[] | undefined): string {
59
+ if (!tasks?.length) {
60
60
  return "No assigned tasks.";
61
61
  }
62
62
 
@@ -66,8 +66,8 @@ function formatTaskList(tasks: AssignedTask[]): string {
66
66
  return `Assigned tasks (${tasks.length}):\n${lines.join("\n")}`;
67
67
  }
68
68
 
69
- function formatIdeaList(ideas: AssignedIdea[]): string {
70
- if (ideas.length === 0) {
69
+ function formatIdeaList(ideas: AssignedIdea[] | undefined): string {
70
+ if (!ideas?.length) {
71
71
  return "No assigned ideas.";
72
72
  }
73
73
 
@@ -115,7 +115,7 @@ export function registerChorusCommands(
115
115
  "chorus_get_my_assignments",
116
116
  {}
117
117
  )) as AssignmentsResponse;
118
- return { text: formatTaskList(data.tasks) };
118
+ return { text: formatTaskList(data?.tasks) };
119
119
  } catch (err) {
120
120
  return { text: `Failed to fetch tasks: ${err instanceof Error ? err.message : String(err)}` };
121
121
  }
@@ -128,7 +128,7 @@ export function registerChorusCommands(
128
128
  "chorus_get_my_assignments",
129
129
  {}
130
130
  )) as AssignmentsResponse;
131
- return { text: formatIdeaList(data.ideas) };
131
+ return { text: formatIdeaList(data?.ideas) };
132
132
  } catch (err) {
133
133
  return { text: `Failed to fetch ideas: ${err instanceof Error ? err.message : String(err)}` };
134
134
  }
@@ -38,7 +38,7 @@ export class ChorusEventRouter {
38
38
  this.config = opts.config;
39
39
  this.triggerAgent = opts.triggerAgent;
40
40
  this.logger = opts.logger;
41
- this.projectFilter = new Set(opts.config.projectUuids);
41
+ this.projectFilter = new Set(opts.config.projectUuids ?? []);
42
42
  }
43
43
 
44
44
  /**
package/src/index.ts CHANGED
@@ -48,9 +48,20 @@ const plugin = {
48
48
  configSchema: chorusConfigSchema,
49
49
 
50
50
  register(api: OpenClawPluginApi) {
51
- const config = api.pluginConfig as ChorusPluginConfig;
51
+ const rawConfig = api.pluginConfig ?? {};
52
+ const config: ChorusPluginConfig = {
53
+ chorusUrl: rawConfig.chorusUrl ?? "",
54
+ apiKey: rawConfig.apiKey ?? "",
55
+ projectUuids: rawConfig.projectUuids ?? [],
56
+ autoStart: rawConfig.autoStart ?? true,
57
+ };
52
58
  const logger = api.logger;
53
59
 
60
+ if (!config.chorusUrl || !config.apiKey) {
61
+ logger.error("Chorus plugin missing required config: chorusUrl and apiKey");
62
+ return;
63
+ }
64
+
54
65
  // Resolve gateway URL and hooks token from OpenClaw config
55
66
  const gatewayPort = api.config?.gateway?.port ?? 18789;
56
67
  const gatewayUrl = `http://127.0.0.1:${gatewayPort}`;