twindex-openclaw-plugin 0.7.6 → 0.8.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/openclaw.plugin.json +5 -1
- package/package.json +1 -1
- package/skills/twindex/SKILL.md +17 -17
- package/src/index.ts +41 -30
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "twindex",
|
|
3
3
|
"name": "New Lore",
|
|
4
4
|
"description": "Music intelligence for AI agents. Get notified about tours, merch drops, releases, and presales for your favorite artists.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.8.1",
|
|
6
6
|
"skills": ["./skills"],
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"enum": ["telegram", "slack"],
|
|
33
33
|
"default": "telegram",
|
|
34
34
|
"description": "Delivery channel."
|
|
35
|
+
},
|
|
36
|
+
"city": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "User's city. Tour notifications highlight shows near this city."
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
},
|
package/package.json
CHANGED
package/skills/twindex/SKILL.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
name: New Lore
|
|
3
3
|
description: Music intelligence — tours, merch drops, releases, presales for your favorite artists.
|
|
4
4
|
tools:
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
5
|
+
- newlore_setup
|
|
6
|
+
- newlore_subscribe
|
|
7
|
+
- newlore_unsubscribe
|
|
8
|
+
- newlore_check
|
|
9
|
+
- newlore_subscriptions
|
|
10
|
+
- newlore_artist
|
|
11
|
+
- newlore_search
|
|
12
|
+
- newlore_artists
|
|
13
|
+
- newlore_upload_photo
|
|
14
|
+
- newlore_try_on
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
# New Lore — Music Intelligence
|
|
@@ -24,7 +24,7 @@ YOU to set it up using your tools. Do NOT tell them to visit a website.
|
|
|
24
24
|
|
|
25
25
|
When a user asks for artist updates (tours, merch, releases):
|
|
26
26
|
1. Ask which artists and how often (realtime/periodic/daily)
|
|
27
|
-
2. Call `
|
|
27
|
+
2. Call `newlore_setup` with the artist slugs, frequency, and their chat ID
|
|
28
28
|
3. That's it — notifications auto-deliver from then on
|
|
29
29
|
|
|
30
30
|
You already know the user's chat ID from the conversation context.
|
|
@@ -32,36 +32,36 @@ Artist slugs are lowercase with hyphens: "linkin-park", "nick-cave-the-bad-seeds
|
|
|
32
32
|
|
|
33
33
|
## Adding more artists
|
|
34
34
|
|
|
35
|
-
Use `
|
|
35
|
+
Use `newlore_subscribe`. The existing delivery schedule picks them up automatically.
|
|
36
36
|
|
|
37
37
|
## Merch Try-On
|
|
38
38
|
|
|
39
39
|
This is the killer feature. Users can see themselves wearing merch.
|
|
40
40
|
|
|
41
41
|
**When a user sends a photo/selfie:**
|
|
42
|
-
1. Call `
|
|
42
|
+
1. Call `newlore_upload_photo` with NO parameters (it auto-finds the photo)
|
|
43
43
|
2. Tell them they're all set for try-ons
|
|
44
44
|
|
|
45
45
|
**When a user asks to try on a product:**
|
|
46
|
-
1. Call `
|
|
46
|
+
1. Call `newlore_try_on` with the artist slug and product name
|
|
47
47
|
2. The server does FUZZY MATCHING — you don't need the exact name
|
|
48
48
|
3. Partial names work: "the hat", "black hoodie", "tour tee" are all fine
|
|
49
49
|
4. If the user references something you just showed them in a notification, use that product name
|
|
50
50
|
|
|
51
51
|
**After a merch notification:**
|
|
52
52
|
- If you showed a product and the user says "try that on" or "let me see it on me", you ALREADY KNOW the product name from the notification you just delivered. Use it directly.
|
|
53
|
-
- If the user says "try that on" after a merch notification, just call `
|
|
53
|
+
- If the user says "try that on" after a merch notification, just call `newlore_try_on` with only the artist slug — no product name needed. The server remembers which product was shown.
|
|
54
54
|
- Do NOT browse the store or ask for clarification. Just call the tool.
|
|
55
55
|
|
|
56
56
|
If try-on returns a 404 (no photo), ask the user to send a selfie first.
|
|
57
57
|
|
|
58
58
|
## Checking manually
|
|
59
59
|
|
|
60
|
-
Use `
|
|
60
|
+
Use `newlore_check` to look for updates right now.
|
|
61
61
|
|
|
62
62
|
## Viewing artist details
|
|
63
63
|
|
|
64
|
-
Use `
|
|
64
|
+
Use `newlore_artist` with a slug to get their full page.
|
|
65
65
|
|
|
66
66
|
## Rules
|
|
67
67
|
|
package/src/index.ts
CHANGED
|
@@ -26,9 +26,9 @@ export default function register(api: any) {
|
|
|
26
26
|
if (!disk.plugins.entries.twindex) disk.plugins.entries.twindex = {};
|
|
27
27
|
disk.plugins.entries.twindex.config = api.config.plugins.entries.twindex.config;
|
|
28
28
|
writeFileSync(configPath, JSON.stringify(disk, null, 2) + "\n", "utf-8");
|
|
29
|
-
api.logger?.info?.("
|
|
29
|
+
api.logger?.info?.("NewLore: config persisted to disk");
|
|
30
30
|
} catch (err: any) {
|
|
31
|
-
api.logger?.warn?.(`
|
|
31
|
+
api.logger?.warn?.(`NewLore: failed to persist config: ${err.message}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -78,10 +78,10 @@ export default function register(api: any) {
|
|
|
78
78
|
for (const artist of config.artists) {
|
|
79
79
|
try {
|
|
80
80
|
await twindex.subscribe(apiKey, artist);
|
|
81
|
-
api.logger?.info?.(`
|
|
81
|
+
api.logger?.info?.(`NewLore: auto-subscribed to ${artist}`);
|
|
82
82
|
} catch (err: any) {
|
|
83
83
|
api.logger?.warn?.(
|
|
84
|
-
`
|
|
84
|
+
`NewLore: failed to subscribe to ${artist}: ${err.message}`,
|
|
85
85
|
);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -92,17 +92,28 @@ export default function register(api: any) {
|
|
|
92
92
|
if (chatTarget) {
|
|
93
93
|
updates.chatTarget = chatTarget;
|
|
94
94
|
updates.chatChannel = inferChatChannel();
|
|
95
|
-
api.logger?.info?.(`
|
|
95
|
+
api.logger?.info?.(`NewLore: auto-detected chatTarget=${chatTarget}`);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
persistConfig(updates);
|
|
99
|
+
|
|
100
|
+
// Set city if configured
|
|
101
|
+
if (config.city) {
|
|
102
|
+
try {
|
|
103
|
+
await twindex.setCity(apiKey, config.city);
|
|
104
|
+
api.logger?.info?.(`NewLore: city set to ${config.city}`);
|
|
105
|
+
} catch (err: any) {
|
|
106
|
+
api.logger?.warn?.(`NewLore: failed to set city: ${err.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
99
110
|
pollService.start();
|
|
100
111
|
api.logger?.info?.(
|
|
101
|
-
"
|
|
112
|
+
"NewLore: auto-bootstrap complete. Delivery via polling.",
|
|
102
113
|
);
|
|
103
114
|
}
|
|
104
115
|
} catch (err: any) {
|
|
105
|
-
api.logger?.warn?.(`
|
|
116
|
+
api.logger?.warn?.(`NewLore: auto-bootstrap failed: ${err.message}`);
|
|
106
117
|
} finally {
|
|
107
118
|
bootstrapping = false;
|
|
108
119
|
}
|
|
@@ -111,7 +122,7 @@ export default function register(api: any) {
|
|
|
111
122
|
// ── Tools ──────────────────────────────────────────────────────────
|
|
112
123
|
|
|
113
124
|
api.registerTool({
|
|
114
|
-
name: "
|
|
125
|
+
name: "newlore_setup",
|
|
115
126
|
description:
|
|
116
127
|
"Set up New Lore music notifications for the user. YOU are the user's interface to New Lore — do NOT tell them to visit a website. Registers, subscribes to artists, and starts polling. Call this when the user asks for music updates, mentions newlore.ai, or wants to follow artists.",
|
|
117
128
|
parameters: {
|
|
@@ -207,9 +218,9 @@ export default function register(api: any) {
|
|
|
207
218
|
});
|
|
208
219
|
|
|
209
220
|
api.registerTool({
|
|
210
|
-
name: "
|
|
221
|
+
name: "newlore_subscribe",
|
|
211
222
|
description:
|
|
212
|
-
"Subscribe to a new artist on
|
|
223
|
+
"Subscribe to a new artist on New Lore. The existing delivery schedule will automatically pick up notifications for this artist.",
|
|
213
224
|
parameters: {
|
|
214
225
|
type: "object",
|
|
215
226
|
properties: {
|
|
@@ -225,7 +236,7 @@ export default function register(api: any) {
|
|
|
225
236
|
if (!apiKey) {
|
|
226
237
|
return {
|
|
227
238
|
content: [
|
|
228
|
-
{ type: "text", text: "Not set up yet. Use
|
|
239
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
229
240
|
],
|
|
230
241
|
};
|
|
231
242
|
}
|
|
@@ -254,8 +265,8 @@ export default function register(api: any) {
|
|
|
254
265
|
});
|
|
255
266
|
|
|
256
267
|
api.registerTool({
|
|
257
|
-
name: "
|
|
258
|
-
description: "Unsubscribe from an artist on
|
|
268
|
+
name: "newlore_unsubscribe",
|
|
269
|
+
description: "Unsubscribe from an artist on New Lore.",
|
|
259
270
|
parameters: {
|
|
260
271
|
type: "object",
|
|
261
272
|
properties: {
|
|
@@ -271,7 +282,7 @@ export default function register(api: any) {
|
|
|
271
282
|
if (!apiKey) {
|
|
272
283
|
return {
|
|
273
284
|
content: [
|
|
274
|
-
{ type: "text", text: "Not set up yet. Use
|
|
285
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
275
286
|
],
|
|
276
287
|
};
|
|
277
288
|
}
|
|
@@ -297,9 +308,9 @@ export default function register(api: any) {
|
|
|
297
308
|
});
|
|
298
309
|
|
|
299
310
|
api.registerTool({
|
|
300
|
-
name: "
|
|
311
|
+
name: "newlore_check",
|
|
301
312
|
description:
|
|
302
|
-
"Check for unread
|
|
313
|
+
"Check for unread New Lore notifications right now. Returns any pending artist updates.",
|
|
303
314
|
parameters: {
|
|
304
315
|
type: "object",
|
|
305
316
|
properties: {},
|
|
@@ -309,7 +320,7 @@ export default function register(api: any) {
|
|
|
309
320
|
if (!apiKey) {
|
|
310
321
|
return {
|
|
311
322
|
content: [
|
|
312
|
-
{ type: "text", text: "Not set up yet. Use
|
|
323
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
313
324
|
],
|
|
314
325
|
};
|
|
315
326
|
}
|
|
@@ -352,8 +363,8 @@ export default function register(api: any) {
|
|
|
352
363
|
});
|
|
353
364
|
|
|
354
365
|
api.registerTool({
|
|
355
|
-
name: "
|
|
356
|
-
description: "List your current
|
|
366
|
+
name: "newlore_subscriptions",
|
|
367
|
+
description: "List your current New Lore subscriptions.",
|
|
357
368
|
parameters: {
|
|
358
369
|
type: "object",
|
|
359
370
|
properties: {},
|
|
@@ -363,7 +374,7 @@ export default function register(api: any) {
|
|
|
363
374
|
if (!apiKey) {
|
|
364
375
|
return {
|
|
365
376
|
content: [
|
|
366
|
-
{ type: "text", text: "Not set up yet. Use
|
|
377
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
367
378
|
],
|
|
368
379
|
};
|
|
369
380
|
}
|
|
@@ -396,9 +407,9 @@ export default function register(api: any) {
|
|
|
396
407
|
});
|
|
397
408
|
|
|
398
409
|
api.registerTool({
|
|
399
|
-
name: "
|
|
410
|
+
name: "newlore_artist",
|
|
400
411
|
description:
|
|
401
|
-
"Get the full
|
|
412
|
+
"Get the full New Lore page for an artist. Returns detailed info including tours, merch, releases.",
|
|
402
413
|
parameters: {
|
|
403
414
|
type: "object",
|
|
404
415
|
properties: {
|
|
@@ -429,9 +440,9 @@ export default function register(api: any) {
|
|
|
429
440
|
});
|
|
430
441
|
|
|
431
442
|
api.registerTool({
|
|
432
|
-
name: "
|
|
443
|
+
name: "newlore_search",
|
|
433
444
|
description:
|
|
434
|
-
"Search the
|
|
445
|
+
"Search the New Lore music index. Find artists by name, genre, or keyword.",
|
|
435
446
|
parameters: {
|
|
436
447
|
type: "object",
|
|
437
448
|
properties: {
|
|
@@ -469,7 +480,7 @@ export default function register(api: any) {
|
|
|
469
480
|
});
|
|
470
481
|
|
|
471
482
|
api.registerTool({
|
|
472
|
-
name: "
|
|
483
|
+
name: "newlore_upload_photo",
|
|
473
484
|
description:
|
|
474
485
|
"Upload the user's selfie for personalized merch try-on. When the user sends a photo in chat, call this tool with NO parameters — it automatically finds the most recent photo from the conversation. One photo per user — uploading replaces the previous one.",
|
|
475
486
|
parameters: {
|
|
@@ -487,7 +498,7 @@ export default function register(api: any) {
|
|
|
487
498
|
if (!apiKey) {
|
|
488
499
|
return {
|
|
489
500
|
content: [
|
|
490
|
-
{ type: "text", text: "Not set up yet. Use
|
|
501
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
491
502
|
],
|
|
492
503
|
};
|
|
493
504
|
}
|
|
@@ -563,7 +574,7 @@ export default function register(api: any) {
|
|
|
563
574
|
});
|
|
564
575
|
|
|
565
576
|
api.registerTool({
|
|
566
|
-
name: "
|
|
577
|
+
name: "newlore_try_on",
|
|
567
578
|
description:
|
|
568
579
|
"Generate an image of the user wearing a merch product. Requires a photo uploaded first. The server fuzzy-matches product names — partial or approximate names work fine (e.g. 'the hat', 'black hoodie', 'tour tee'). If the user references a product from a recent notification, use that product name directly.",
|
|
569
580
|
parameters: {
|
|
@@ -588,7 +599,7 @@ export default function register(api: any) {
|
|
|
588
599
|
if (!apiKey) {
|
|
589
600
|
return {
|
|
590
601
|
content: [
|
|
591
|
-
{ type: "text", text: "Not set up yet. Use
|
|
602
|
+
{ type: "text", text: "Not set up yet. Use newlore_setup first." },
|
|
592
603
|
],
|
|
593
604
|
};
|
|
594
605
|
}
|
|
@@ -634,8 +645,8 @@ export default function register(api: any) {
|
|
|
634
645
|
});
|
|
635
646
|
|
|
636
647
|
api.registerTool({
|
|
637
|
-
name: "
|
|
638
|
-
description: "List all artists currently indexed on
|
|
648
|
+
name: "newlore_artists",
|
|
649
|
+
description: "List all artists currently indexed on New Lore.",
|
|
639
650
|
parameters: {
|
|
640
651
|
type: "object",
|
|
641
652
|
properties: {},
|