@shenhh/popo 0.1.19 → 0.1.20

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": "@shenhh/popo",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "description": "OpenClaw POPO channel plugin",
6
6
  "license": "MIT",
@@ -237,16 +237,6 @@ Common errors:
237
237
 
238
238
  Recall (retract) a sent message within the allowed time window.
239
239
 
240
- ```json
241
- {
242
- "action": "recall",
243
- "msgId": "794076f2-68b1-4d0e-94eb-c15946580b56",
244
- "target": "user@corp.netease.com"
245
- }
246
- ```
247
-
248
- Or using POPO-specific parameters:
249
-
250
240
  ```json
251
241
  {
252
242
  "action": "recall",
@@ -258,11 +248,8 @@ Or using POPO-specific parameters:
258
248
 
259
249
  **Parameters:**
260
250
  - `msgId` (required): Message ID to recall
261
- - `target` (required*): Target user email or group ID (OpenClaw standard)
262
- - `sessionId` (required*): Session ID (user email for P2P, group ID for group) - alias for target
263
- - `sessionType` (optional): `1` for P2P, `3` for group (auto-detected from target if not provided)
264
-
265
- \* Either `target` or `sessionId` must be provided.
251
+ - `sessionId` (required): Session ID (user email for P2P, group ID for group)
252
+ - `sessionType` (required): `1` for P2P, `3` for group
266
253
 
267
254
  **Note:** Messages can only be recalled within a limited time (typically 2 minutes).
268
255
 
@@ -270,20 +257,6 @@ Or using POPO-specific parameters:
270
257
 
271
258
  Query read/unread status for group messages.
272
259
 
273
- ```json
274
- {
275
- "action": "read-ack",
276
- "msgId": "1000016836-0000000004",
277
- "target": "group:1234567",
278
- "type": 1,
279
- "st": 1672221224000,
280
- "page": 1,
281
- "size": 30
282
- }
283
- ```
284
-
285
- Or using POPO-specific parameters:
286
-
287
260
  ```json
288
261
  {
289
262
  "action": "read-ack",
@@ -298,15 +271,12 @@ Or using POPO-specific parameters:
298
271
 
299
272
  **Parameters:**
300
273
  - `msgId` (required): Message ID
301
- - `target` (optional): Group ID for context (e.g., `group:1234567` or `1234567`)
302
- - `sessionType` (optional): Must be `3` (group), default is 3
303
- - `type` (optional): `1` for read list, `2` for unread list, default 1
304
- - `st` (optional): Query end timestamp (milliseconds), default is current time
274
+ - `sessionType` (required): Must be `3` (group)
275
+ - `type` (required): `1` for read list, `2` for unread list
276
+ - `st` (required): Query end timestamp (milliseconds)
305
277
  - `page` (optional): Page number, default 1
306
278
  - `size` (optional): Page size, default 30
307
279
 
308
- **Note:** Read-ack only works for group messages, not P2P.
309
-
310
280
  **Response:**
311
281
  ```json
312
282
  {
package/src/channel.ts CHANGED
@@ -60,6 +60,7 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
60
60
  agentPrompt: {
61
61
  messageToolHints: () => [
62
62
  "- POPO targeting: omit `target` to reply to the current conversation (auto-inferred). Explicit targets: `user:email@example.com` or `group:groupId`.",
63
+ "- POPO actions: send, card, unsend (target=to), addParticipant (target=tid), channel-info/channel-edit/channel-delete (channelId=tid), channel-create (no target), member-info (tid param). Custom actions without target: read-ack (msgId), download-file (fileId), update-team-mgmt, view-scope, modify-view-scope, publish-robot, update-instruction-options, configure-card-callback.",
63
64
  ],
64
65
  },
65
66
  groups: {
@@ -171,18 +172,22 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
171
172
  const enabled = cfg.channels?.popo?.enabled !== false;
172
173
  if (!enabled) return [];
173
174
  // Return all supported actions
175
+ // Use built-in action names to work with OpenClaw's target mode system:
176
+ // - unsend (recall), channel-create (create-team), addParticipant (invite-team)
177
+ // - channel-delete (drop-team), member-info (team-members), channel-info (team-info)
178
+ // - channel-edit (update-team-info)
174
179
  return [
175
180
  "send",
176
181
  "card",
177
- "recall",
182
+ "unsend",
183
+ "channel-create",
184
+ "addParticipant",
185
+ "channel-delete",
186
+ "member-info",
187
+ "channel-info",
188
+ "channel-edit",
178
189
  "read-ack",
179
190
  "download-file",
180
- "create-team",
181
- "invite-team",
182
- "drop-team",
183
- "team-members",
184
- "team-info",
185
- "update-team-info",
186
191
  "update-team-mgmt",
187
192
  "view-scope",
188
193
  "modify-view-scope",
@@ -310,17 +315,22 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
310
315
  };
311
316
  }
312
317
 
313
- // Handle recall action
314
- if (action === "recall") {
315
- const msgId = typeof params.msgId === "string" ? params.msgId : typeof params.messageId === "string" ? params.messageId : "";
316
- // Support both target (OpenClaw standard) and sessionId (POPO-specific)
317
- const target = typeof params.target === "string" ? params.target : "";
318
- const sessionId = typeof params.sessionId === "string" ? params.sessionId : target;
319
- const sessionType = typeof params.sessionType === "number" ? params.sessionType : (target.includes("@") ? 1 : 3);
318
+ // Handle unsend action (recall message) - uses built-in "unsend" which has proper target mode
319
+ // Accepts: target (to), messageId, sessionId, sessionType
320
+ if (action === "unsend") {
321
+ const msgId = typeof params.messageId === "string" ? params.messageId : typeof params.msgId === "string" ? params.msgId : "";
322
+ // For unsend, sessionId can come from "to" (target) or explicit sessionId
323
+ const sessionId =
324
+ typeof params.sessionId === "string"
325
+ ? params.sessionId
326
+ : typeof params.to === "string"
327
+ ? params.to.trim()
328
+ : "";
329
+ const sessionType = typeof params.sessionType === "number" ? params.sessionType : 1;
320
330
  if (!msgId || !sessionId) {
321
331
  return {
322
332
  isError: true,
323
- content: [{ type: "text", text: "Recall requires msgId and target (or sessionId)." }],
333
+ content: [{ type: "text", text: "Unsend requires messageId and target (or sessionId)." }],
324
334
  };
325
335
  }
326
336
  const result = await recallMessagePopo({ cfg, msgId, sessionId, sessionType: sessionType as 1 | 3 });
@@ -341,8 +351,6 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
341
351
  // Handle read-ack action
342
352
  if (action === "read-ack") {
343
353
  const msgId = typeof params.msgId === "string" ? params.msgId : "";
344
- // Support target (OpenClaw standard) for group identification
345
- const target = typeof params.target === "string" ? params.target : "";
346
354
  const type = typeof params.type === "number" ? params.type : 1;
347
355
  const st = typeof params.st === "number" ? params.st : Date.now();
348
356
  const page = typeof params.page === "number" ? params.page : 1;
@@ -353,13 +361,6 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
353
361
  content: [{ type: "text", text: "Read-ack requires msgId." }],
354
362
  };
355
363
  }
356
- // If target is provided, validate it's a group (read-ack only works for groups)
357
- if (target && target.includes("@")) {
358
- return {
359
- isError: true,
360
- content: [{ type: "text", text: "Read-ack only works for group messages, not P2P." }],
361
- };
362
- }
363
364
  const result = await getMessageReadAckPopo({
364
365
  cfg,
365
366
  msgId,
@@ -413,8 +414,9 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
413
414
 
414
415
  // ==================== Team Management Actions ====================
415
416
 
416
- // Handle create-team action
417
- if (action === "create-team") {
417
+ // Handle channel-create action (create team)
418
+ // Built-in action with targetMode: none
419
+ if (action === "channel-create") {
418
420
  const uid = typeof params.uid === "string" ? params.uid : "";
419
421
  const name = typeof params.name === "string" ? params.name : undefined;
420
422
  const uidList = Array.isArray(params.uidList) ? params.uidList : [];
@@ -422,7 +424,7 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
422
424
  if (!uid || uidList.length === 0) {
423
425
  return {
424
426
  isError: true,
425
- content: [{ type: "text", text: "Create-team requires uid (owner) and uidList (members)." }],
427
+ content: [{ type: "text", text: "channel-create requires uid (owner) and uidList (members)." }],
426
428
  };
427
429
  }
428
430
  const result = await createTeam({ cfg, uid, name, uidList, photoUrl });
@@ -443,16 +445,22 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
443
445
  };
444
446
  }
445
447
 
446
- // Handle invite-team action
447
- if (action === "invite-team") {
448
- const tid = typeof params.tid === "string" ? params.tid : "";
449
- const inviteList = Array.isArray(params.inviteList) ? params.inviteList : [];
448
+ // Handle addParticipant action (invite to team)
449
+ // Built-in action with targetMode: to (tid comes from target/to)
450
+ if (action === "addParticipant") {
451
+ const tid =
452
+ typeof params.tid === "string"
453
+ ? params.tid
454
+ : typeof params.to === "string"
455
+ ? params.to.trim()
456
+ : "";
457
+ const inviteList = Array.isArray(params.inviteList) ? params.inviteList : Array.isArray(params.participant) ? params.participant : [];
450
458
  const type = typeof params.type === "string" ? (params.type as "1" | "2") : "1";
451
459
  const text = typeof params.text === "string" ? params.text : undefined;
452
460
  if (!tid || inviteList.length === 0) {
453
461
  return {
454
462
  isError: true,
455
- content: [{ type: "text", text: "Invite-team requires tid and inviteList." }],
463
+ content: [{ type: "text", text: "addParticipant requires target (tid) and inviteList/participant." }],
456
464
  };
457
465
  }
458
466
  const result = await inviteToTeam({ cfg, tid, inviteList, type, text });
@@ -472,13 +480,19 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
472
480
  };
473
481
  }
474
482
 
475
- // Handle drop-team action
476
- if (action === "drop-team") {
477
- const tid = typeof params.tid === "string" ? params.tid : "";
483
+ // Handle channel-delete action (drop/disband team)
484
+ // Built-in action with targetMode: channelId
485
+ if (action === "channel-delete") {
486
+ const tid =
487
+ typeof params.tid === "string"
488
+ ? params.tid
489
+ : typeof params.channelId === "string"
490
+ ? params.channelId.trim()
491
+ : "";
478
492
  if (!tid) {
479
493
  return {
480
494
  isError: true,
481
- content: [{ type: "text", text: "Drop-team requires tid (team ID)." }],
495
+ content: [{ type: "text", text: "channel-delete requires channelId (team ID)." }],
482
496
  };
483
497
  }
484
498
  const result = await dropTeam({ cfg, tid });
@@ -496,15 +510,16 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
496
510
  };
497
511
  }
498
512
 
499
- // Handle team-members action
500
- if (action === "team-members") {
513
+ // Handle member-info action (get team members)
514
+ // Built-in action with targetMode: none
515
+ if (action === "member-info") {
501
516
  const tid = typeof params.tid === "string" ? params.tid : "";
502
517
  const page = typeof params.page === "number" ? params.page : 1;
503
518
  const limit = typeof params.limit === "number" ? params.limit : 20;
504
519
  if (!tid) {
505
520
  return {
506
521
  isError: true,
507
- content: [{ type: "text", text: "Team-members requires tid (team ID)." }],
522
+ content: [{ type: "text", text: "member-info requires tid (team ID)." }],
508
523
  };
509
524
  }
510
525
  const result = await getTeamMembers({ cfg, tid, page, limit });
@@ -526,14 +541,20 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
526
541
  };
527
542
  }
528
543
 
529
- // Handle team-info action
530
- if (action === "team-info") {
531
- const tid = typeof params.tid === "string" ? params.tid : "";
544
+ // Handle channel-info action (get team info)
545
+ // Built-in action with targetMode: channelId
546
+ if (action === "channel-info") {
547
+ const tid =
548
+ typeof params.tid === "string"
549
+ ? params.tid
550
+ : typeof params.channelId === "string"
551
+ ? params.channelId.trim()
552
+ : "";
532
553
  const scopes = Array.isArray(params.scopes) ? params.scopes : undefined;
533
554
  if (!tid) {
534
555
  return {
535
556
  isError: true,
536
- content: [{ type: "text", text: "Team-info requires tid (team ID)." }],
557
+ content: [{ type: "text", text: "channel-info requires channelId (team ID)." }],
537
558
  };
538
559
  }
539
560
  const result = await getTeamInfo({ cfg, tid, scopes });
@@ -552,16 +573,22 @@ export const popoPlugin: ChannelPlugin<ResolvedPopoAccount> = {
552
573
  };
553
574
  }
554
575
 
555
- // Handle update-team-info action
556
- if (action === "update-team-info") {
557
- const tid = typeof params.tid === "string" ? params.tid : "";
576
+ // Handle channel-edit action (update team info)
577
+ // Built-in action with targetMode: channelId
578
+ if (action === "channel-edit") {
579
+ const tid =
580
+ typeof params.tid === "string"
581
+ ? params.tid
582
+ : typeof params.channelId === "string"
583
+ ? params.channelId.trim()
584
+ : "";
558
585
  const name = typeof params.name === "string" ? params.name : "";
559
586
  const board = typeof params.board === "string" ? params.board : "";
560
587
  const type = typeof params.type === "number" ? params.type : undefined;
561
588
  if (!tid || !name || !board) {
562
589
  return {
563
590
  isError: true,
564
- content: [{ type: "text", text: "Update-team-info requires tid, name, and board." }],
591
+ content: [{ type: "text", text: "channel-edit requires channelId (tid), name, and board." }],
565
592
  };
566
593
  }
567
594
  const result = await updateTeamInfo({ cfg, tid, name, board, type });