twindex-openclaw-plugin 0.6.4 → 0.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twindex-openclaw-plugin",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "description": "Music intelligence for AI agents. Tours, merch drops, releases, presales.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -599,6 +599,8 @@ export default function register(api: any) {
599
599
  ``,
600
600
  `$${result.product.price} — grab it here: ${result.product.buy_url}`,
601
601
  ``,
602
+ `From now on, whenever there's a new drop from artists you follow, I'll automatically show you how it looks on you.`,
603
+ ``,
602
604
  `CRITICAL: The first URL (${result.image_url}) is the try-on photo. It MUST appear first in your message so Telegram shows the preview. Do NOT put any other URL before it.`,
603
605
  ].join("\n"),
604
606
  },
@@ -7,7 +7,7 @@ import { execFile } from "child_process";
7
7
  import * as twindex from "./client.js";
8
8
 
9
9
  const FREQUENCY_MS: Record<string, number> = {
10
- realtime: 5 * 60 * 1000, // 5 min
10
+ realtime: 20 * 1000, // 20 sec (demo speed)
11
11
  periodic: 60 * 60 * 1000, // 1 hour
12
12
  daily: 24 * 60 * 60 * 1000, // 24 hours
13
13
  };
@@ -92,16 +92,43 @@ export function createNotificationService(api: any) {
92
92
  const notifications = await twindex.getNotifications(apiKey);
93
93
  if (!notifications || notifications.length === 0) return;
94
94
 
95
- // Filter to unread only
96
- const unread = notifications.filter((n) => !n.read_at);
97
- if (unread.length === 0) return;
95
+ // Filter to unread, skip internal events (page updates)
96
+ const unread = notifications.filter(
97
+ (n) => !n.read_at && n.event_type !== "update",
98
+ );
99
+ if (unread.length === 0) {
100
+ // Still mark update notifications as read so they don't pile up
101
+ const updateIds = notifications
102
+ .filter((n) => !n.read_at && n.event_type === "update")
103
+ .map((n) => n.id);
104
+ if (updateIds.length > 0) {
105
+ try { await twindex.markRead(apiKey, updateIds); } catch {}
106
+ }
107
+ return;
108
+ }
98
109
 
99
110
  logger?.info?.(`Twindex: ${unread.length} unread notification(s)`);
100
111
 
101
112
  for (const notif of unread) {
102
- let message = `🎸 ${notif.brand} ${notif.event_type}\n${notif.summary}`;
113
+ // Format brand name: "sam-smith" "Sam Smith"
114
+ const brandName = notif.brand
115
+ .split("-")
116
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
117
+ .join(" ");
118
+
119
+ // Just the summary — no raw metadata
120
+ let message = `${notif.summary}`;
103
121
  if (notif.media_url) {
104
- message += `\n\nHere's how it looks on you: ${notif.media_url}`;
122
+ // Try-on images come from our server, product images from Shopify CDN
123
+ const isTryOn = notif.media_url.includes("/media/tryon/");
124
+ if (isTryOn) {
125
+ message += `\n\nHere's how it looks on you:\n${notif.media_url}`;
126
+ } else {
127
+ message += `\n\n${notif.media_url}`;
128
+ }
129
+ }
130
+ if (notif.twindex_url) {
131
+ message += `\n\n${notif.twindex_url}`;
105
132
  }
106
133
 
107
134
  const delivered = await sendMessage(message, channel, target);