twindex-openclaw-plugin 0.8.20260409 → 0.8.20260411
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 +1 -1
- package/package.json +1 -1
- package/src/index.ts +59 -29
- package/src/plugin-config.ts +62 -9
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "twindex-openclaw-plugin",
|
|
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.8.
|
|
5
|
+
"version": "0.8.20260411",
|
|
6
6
|
"skills": ["./skills"],
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -53,34 +53,64 @@ export default function register(api: any) {
|
|
|
53
53
|
return "telegram";
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function isGatewayRuntime(): boolean {
|
|
57
|
+
const [command] = process.argv.slice(2);
|
|
58
|
+
return command === "gateway";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function ensureArtistSubscriptions(
|
|
62
|
+
apiKey: string,
|
|
63
|
+
artists: string[],
|
|
64
|
+
): Promise<string[]> {
|
|
65
|
+
let existing = new Set<string>();
|
|
66
|
+
try {
|
|
67
|
+
const subscriptions = await twindex.listSubscriptions(apiKey);
|
|
68
|
+
existing = new Set(subscriptions.map((subscription) => subscription.brand));
|
|
69
|
+
} catch (err: any) {
|
|
70
|
+
api.logger?.warn?.(
|
|
71
|
+
`NewLore: failed to list existing subscriptions: ${err.message}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const results: string[] = [];
|
|
76
|
+
for (const artist of artists) {
|
|
77
|
+
if (existing.has(artist)) {
|
|
78
|
+
api.logger?.info?.(`NewLore: already subscribed to ${artist}`);
|
|
79
|
+
results.push(`Already subscribed to ${artist}`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await twindex.subscribe(apiKey, artist);
|
|
85
|
+
api.logger?.info?.(`NewLore: auto-subscribed to ${artist}`);
|
|
86
|
+
results.push(`Subscribed to ${artist}`);
|
|
87
|
+
} catch (err: any) {
|
|
88
|
+
api.logger?.warn?.(
|
|
89
|
+
`NewLore: failed to subscribe to ${artist}: ${err.message}`,
|
|
90
|
+
);
|
|
91
|
+
results.push(`${artist}: ${err.message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
|
|
56
98
|
// ── Auto-bootstrap: register + subscribe ────────────────────────
|
|
57
99
|
|
|
58
100
|
(async () => {
|
|
101
|
+
if (!isGatewayRuntime()) {
|
|
102
|
+
api.logger?.info?.("NewLore: skipping auto-bootstrap outside gateway runtime");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
59
106
|
if (bootstrapping) return;
|
|
60
107
|
bootstrapping = true;
|
|
61
108
|
try {
|
|
62
109
|
const config = cfg();
|
|
63
110
|
if (config.artists?.length > 0 && !config.apiKey) {
|
|
64
|
-
const
|
|
65
|
-
api.agentId ?? api.config?.agentId ?? `openclaw-${crypto.randomUUID()}`;
|
|
66
|
-
const reg = await twindex.register(agentId);
|
|
67
|
-
const apiKey = reg.api_key;
|
|
68
|
-
|
|
69
|
-
for (const artist of config.artists) {
|
|
70
|
-
try {
|
|
71
|
-
await twindex.subscribe(apiKey, artist);
|
|
72
|
-
api.logger?.info?.(`NewLore: auto-subscribed to ${artist}`);
|
|
73
|
-
} catch (err: any) {
|
|
74
|
-
api.logger?.warn?.(
|
|
75
|
-
`NewLore: failed to subscribe to ${artist}: ${err.message}`,
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Auto-detect chatTarget from channel config if not explicitly set
|
|
111
|
+
const frequency = config.frequency ?? "periodic";
|
|
81
112
|
const updates: Record<string, any> = {
|
|
82
|
-
|
|
83
|
-
frequency: config.frequency ?? "periodic",
|
|
113
|
+
frequency,
|
|
84
114
|
};
|
|
85
115
|
const chatTarget = inferChatTarget();
|
|
86
116
|
if (chatTarget) {
|
|
@@ -89,7 +119,15 @@ export default function register(api: any) {
|
|
|
89
119
|
api.logger?.info?.(`NewLore: auto-detected chatTarget=${chatTarget}`);
|
|
90
120
|
}
|
|
91
121
|
|
|
92
|
-
|
|
122
|
+
const agentId =
|
|
123
|
+
api.agentId ?? api.config?.agentId ?? `openclaw-${crypto.randomUUID()}`;
|
|
124
|
+
const reg = await twindex.register(agentId);
|
|
125
|
+
const apiKey = reg.api_key;
|
|
126
|
+
persistConfig({
|
|
127
|
+
apiKey,
|
|
128
|
+
...updates,
|
|
129
|
+
});
|
|
130
|
+
await ensureArtistSubscriptions(apiKey, config.artists);
|
|
93
131
|
|
|
94
132
|
// Set city if configured
|
|
95
133
|
if (config.city) {
|
|
@@ -217,15 +255,7 @@ export default function register(api: any) {
|
|
|
217
255
|
}
|
|
218
256
|
}
|
|
219
257
|
|
|
220
|
-
const results
|
|
221
|
-
for (const artist of params.artists) {
|
|
222
|
-
try {
|
|
223
|
-
await twindex.subscribe(apiKey, artist);
|
|
224
|
-
results.push(`Subscribed to ${artist}`);
|
|
225
|
-
} catch (err: any) {
|
|
226
|
-
results.push(`${artist}: ${err.message}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
258
|
+
const results = await ensureArtistSubscriptions(apiKey, params.artists);
|
|
229
259
|
|
|
230
260
|
pollService.start();
|
|
231
261
|
results.push("Notification polling enabled");
|
package/src/plugin-config.ts
CHANGED
|
@@ -39,6 +39,60 @@ function ensurePluginEntry(api: any, pluginId: string): Record<string, any> {
|
|
|
39
39
|
return api.config.plugins.entries[pluginId];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function pruneLegacyPluginState(target: any, pluginId: string): boolean {
|
|
43
|
+
if (!isRecord(target?.plugins) || LEGACY_PLUGIN_IDS.includes(pluginId)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let changed = false;
|
|
48
|
+
|
|
49
|
+
if (isRecord(target.plugins.entries)) {
|
|
50
|
+
for (const legacyPluginId of LEGACY_PLUGIN_IDS) {
|
|
51
|
+
if (legacyPluginId !== pluginId && legacyPluginId in target.plugins.entries) {
|
|
52
|
+
delete target.plugins.entries[legacyPluginId];
|
|
53
|
+
changed = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isRecord(target.plugins.installs)) {
|
|
59
|
+
for (const legacyPluginId of LEGACY_PLUGIN_IDS) {
|
|
60
|
+
if (legacyPluginId !== pluginId && legacyPluginId in target.plugins.installs) {
|
|
61
|
+
delete target.plugins.installs[legacyPluginId];
|
|
62
|
+
changed = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return changed;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function persistConfigToDisk(
|
|
71
|
+
pluginId: string,
|
|
72
|
+
nextConfig?: NewLorePluginConfig,
|
|
73
|
+
): boolean {
|
|
74
|
+
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
75
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
76
|
+
const disk = JSON.parse(raw);
|
|
77
|
+
let changed = false;
|
|
78
|
+
|
|
79
|
+
if (nextConfig) {
|
|
80
|
+
if (!isRecord(disk.plugins)) disk.plugins = {};
|
|
81
|
+
if (!isRecord(disk.plugins.entries)) disk.plugins.entries = {};
|
|
82
|
+
if (!isRecord(disk.plugins.entries[pluginId])) disk.plugins.entries[pluginId] = {};
|
|
83
|
+
disk.plugins.entries[pluginId].config = nextConfig;
|
|
84
|
+
changed = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
changed = pruneLegacyPluginState(disk, pluginId) || changed;
|
|
88
|
+
|
|
89
|
+
if (changed) {
|
|
90
|
+
writeFileSync(configPath, JSON.stringify(disk, null, 2) + "\n", "utf-8");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return changed;
|
|
94
|
+
}
|
|
95
|
+
|
|
42
96
|
export function getPluginId(api: any): string {
|
|
43
97
|
if (typeof api?.id === "string" && api.id.trim()) return api.id.trim();
|
|
44
98
|
return LEGACY_PLUGIN_IDS[0];
|
|
@@ -69,18 +123,12 @@ export function persistPluginConfig(
|
|
|
69
123
|
};
|
|
70
124
|
|
|
71
125
|
ensurePluginEntry(api, pluginId).config = nextConfig;
|
|
126
|
+
pruneLegacyPluginState(api.config, pluginId);
|
|
72
127
|
api.pluginConfig = nextConfig;
|
|
73
128
|
|
|
74
129
|
// OpenClaw does not currently expose a config.save() helper to plugins.
|
|
75
130
|
try {
|
|
76
|
-
|
|
77
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
78
|
-
const disk = JSON.parse(raw);
|
|
79
|
-
if (!isRecord(disk.plugins)) disk.plugins = {};
|
|
80
|
-
if (!isRecord(disk.plugins.entries)) disk.plugins.entries = {};
|
|
81
|
-
if (!isRecord(disk.plugins.entries[pluginId])) disk.plugins.entries[pluginId] = {};
|
|
82
|
-
disk.plugins.entries[pluginId].config = nextConfig;
|
|
83
|
-
writeFileSync(configPath, JSON.stringify(disk, null, 2) + "\n", "utf-8");
|
|
131
|
+
persistConfigToDisk(pluginId, nextConfig);
|
|
84
132
|
} catch (err: any) {
|
|
85
133
|
api.logger?.warn?.(`NewLore: failed to persist config: ${err.message}`);
|
|
86
134
|
}
|
|
@@ -95,7 +143,12 @@ export function migrateLegacyPluginConfig(api: any): boolean {
|
|
|
95
143
|
const currentConfig = api?.config?.plugins?.entries?.[pluginId]?.config;
|
|
96
144
|
if (isRecord(currentConfig) && Object.keys(currentConfig).length > 0) {
|
|
97
145
|
api.pluginConfig = currentConfig;
|
|
98
|
-
|
|
146
|
+
try {
|
|
147
|
+
return pruneLegacyPluginState(api.config, pluginId) || persistConfigToDisk(pluginId);
|
|
148
|
+
} catch (err: any) {
|
|
149
|
+
api.logger?.warn?.(`NewLore: failed to prune legacy config: ${err.message}`);
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
99
152
|
}
|
|
100
153
|
|
|
101
154
|
const legacyConfig = resolveLegacyConfig(api);
|