@wecode-ai/weibo-openclaw-plugin 1.0.0 → 1.0.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/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/src/accounts.d.ts +10 -0
- package/dist/src/accounts.d.ts.map +1 -0
- package/dist/src/accounts.js +113 -0
- package/dist/src/accounts.js.map +1 -0
- package/dist/src/bot.d.ts +26 -0
- package/dist/src/bot.d.ts.map +1 -0
- package/dist/src/bot.js +385 -0
- package/dist/src/bot.js.map +1 -0
- package/dist/src/channel.d.ts +4 -0
- package/dist/src/channel.d.ts.map +1 -0
- package/dist/src/channel.js +317 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/client.d.ts +51 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +336 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/config-schema.d.ts +86 -0
- package/dist/src/config-schema.d.ts.map +1 -0
- package/{src/config-schema.ts → dist/src/config-schema.js} +19 -24
- package/dist/src/config-schema.js.map +1 -0
- package/dist/src/fingerprint.d.ts +4 -0
- package/dist/src/fingerprint.d.ts.map +1 -0
- package/dist/src/fingerprint.js +19 -0
- package/dist/src/fingerprint.js.map +1 -0
- package/dist/src/monitor.d.ts +13 -0
- package/dist/src/monitor.d.ts.map +1 -0
- package/dist/src/monitor.js +169 -0
- package/dist/src/monitor.js.map +1 -0
- package/dist/src/outbound-stream.d.ts +32 -0
- package/dist/src/outbound-stream.d.ts.map +1 -0
- package/dist/src/outbound-stream.js +184 -0
- package/dist/src/outbound-stream.js.map +1 -0
- package/dist/src/outbound.d.ts +3 -0
- package/dist/src/outbound.d.ts.map +1 -0
- package/dist/src/outbound.js +38 -0
- package/dist/src/outbound.js.map +1 -0
- package/dist/src/plugin-sdk-compat.d.ts +21 -0
- package/dist/src/plugin-sdk-compat.d.ts.map +1 -0
- package/dist/src/plugin-sdk-compat.js +47 -0
- package/dist/src/plugin-sdk-compat.js.map +1 -0
- package/dist/src/policy.d.ts +5 -0
- package/dist/src/policy.d.ts.map +1 -0
- package/dist/src/policy.js +6 -0
- package/dist/src/policy.js.map +1 -0
- package/dist/src/runtime.d.ts +4 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +11 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/search-schema.d.ts +6 -0
- package/dist/src/search-schema.d.ts.map +1 -0
- package/dist/src/search-schema.js +5 -0
- package/dist/src/search-schema.js.map +1 -0
- package/dist/src/send.d.ts +14 -0
- package/dist/src/send.d.ts.map +1 -0
- package/dist/src/send.js +58 -0
- package/dist/src/send.js.map +1 -0
- package/dist/src/sim-page.d.ts +51 -0
- package/dist/src/sim-page.d.ts.map +1 -0
- package/dist/src/sim-page.js +72 -0
- package/dist/src/sim-page.js.map +1 -0
- package/dist/src/sim-store.d.ts +54 -0
- package/dist/src/sim-store.d.ts.map +1 -0
- package/dist/src/sim-store.js +117 -0
- package/dist/src/sim-store.js.map +1 -0
- package/dist/src/targets.d.ts +4 -0
- package/dist/src/targets.d.ts.map +1 -0
- package/dist/src/targets.js +15 -0
- package/dist/src/targets.js.map +1 -0
- package/dist/src/token.d.ts +27 -0
- package/dist/src/token.d.ts.map +1 -0
- package/dist/src/token.js +144 -0
- package/dist/src/token.js.map +1 -0
- package/dist/src/tools-config.d.ts +21 -0
- package/dist/src/tools-config.d.ts.map +1 -0
- package/dist/src/tools-config.js +42 -0
- package/dist/src/tools-config.js.map +1 -0
- package/dist/src/types.d.ts +76 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/weibo-hot-search.d.ts +44 -0
- package/dist/src/weibo-hot-search.d.ts.map +1 -0
- package/dist/src/weibo-hot-search.js +215 -0
- package/dist/src/weibo-hot-search.js.map +1 -0
- package/dist/src/weibo-search.d.ts +71 -0
- package/dist/src/weibo-search.d.ts.map +1 -0
- package/dist/src/weibo-search.js +182 -0
- package/dist/src/weibo-search.js.map +1 -0
- package/dist/src/weibo-status.d.ts +61 -0
- package/dist/src/weibo-status.d.ts.map +1 -0
- package/dist/src/weibo-status.js +194 -0
- package/dist/src/weibo-status.js.map +1 -0
- package/openclaw.plugin.json +12 -0
- package/package.json +4 -5
- package/skills/weibo-hot-search/SKILL.md +161 -0
- package/skills/weibo-search/SKILL.md +116 -0
- package/skills/weibo-status/SKILL.md +97 -0
- package/index.ts +0 -67
- package/src/accounts.ts +0 -134
- package/src/bot.ts +0 -486
- package/src/channel.ts +0 -391
- package/src/client.ts +0 -435
- package/src/fingerprint.ts +0 -25
- package/src/monitor.ts +0 -206
- package/src/outbound-stream.ts +0 -241
- package/src/outbound.ts +0 -49
- package/src/plugin-sdk-compat.ts +0 -82
- package/src/policy.ts +0 -10
- package/src/runtime.ts +0 -14
- package/src/search-schema.ts +0 -7
- package/src/send.ts +0 -80
- package/src/sim-page.ts +0 -140
- package/src/sim-store.ts +0 -186
- package/src/targets.ts +0 -14
- package/src/token.ts +0 -207
- package/src/tools-config.ts +0 -55
- package/src/types.ts +0 -95
- package/src/weibo-hot-search.ts +0 -345
- package/src/weibo-search.ts +0 -333
- package/src/weibo-status.ts +0 -341
package/src/outbound-stream.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
export type WeiboChunkMode = "length" | "newline" | "raw";
|
|
2
|
-
|
|
3
|
-
type StreamDebugFn = (tag: string, data?: Record<string, unknown>) => void;
|
|
4
|
-
|
|
5
|
-
export type WeiboOutboundEmitFn = (params: {
|
|
6
|
-
text: string;
|
|
7
|
-
done: boolean;
|
|
8
|
-
source: "partial" | "deliver" | "settled";
|
|
9
|
-
}) => Promise<void>;
|
|
10
|
-
|
|
11
|
-
type CreateWeiboOutboundStreamParams = {
|
|
12
|
-
chunkMode: WeiboChunkMode;
|
|
13
|
-
textChunkLimit: number;
|
|
14
|
-
emit: WeiboOutboundEmitFn;
|
|
15
|
-
chunkTextWithMode: (text: string, limit: number, mode: "length" | "newline") => Iterable<string>;
|
|
16
|
-
streamDebug?: StreamDebugFn;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type StreamStateSnapshot = {
|
|
20
|
-
hasSeenPartial: boolean;
|
|
21
|
-
hasEmittedChunks: boolean;
|
|
22
|
-
hasEmittedDone: boolean;
|
|
23
|
-
newlineBufferLen: number;
|
|
24
|
-
pendingDeliverBufferLen: number;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const PARAGRAPH_DELIMITER_RE = /\n[\t ]*\n+/g;
|
|
28
|
-
|
|
29
|
-
function findLastParagraphDelimiterEnd(value: string): number {
|
|
30
|
-
let lastEnd = -1;
|
|
31
|
-
let match: RegExpExecArray | null = null;
|
|
32
|
-
while ((match = PARAGRAPH_DELIMITER_RE.exec(value)) !== null) {
|
|
33
|
-
lastEnd = match.index + match[0].length;
|
|
34
|
-
}
|
|
35
|
-
return lastEnd;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function resolveDeltaFromSnapshot(previous: string, next: string): {
|
|
39
|
-
delta: string;
|
|
40
|
-
nextSnapshot: string;
|
|
41
|
-
nonMonotonic: boolean;
|
|
42
|
-
} {
|
|
43
|
-
if (!next || next === previous) {
|
|
44
|
-
return { delta: "", nextSnapshot: next, nonMonotonic: false };
|
|
45
|
-
}
|
|
46
|
-
if (next.startsWith(previous)) {
|
|
47
|
-
return {
|
|
48
|
-
delta: next.slice(previous.length),
|
|
49
|
-
nextSnapshot: next,
|
|
50
|
-
nonMonotonic: false,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (previous.startsWith(next)) {
|
|
54
|
-
return {
|
|
55
|
-
delta: "",
|
|
56
|
-
nextSnapshot: next,
|
|
57
|
-
nonMonotonic: true,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let prefixLen = 0;
|
|
62
|
-
const maxLen = Math.min(previous.length, next.length);
|
|
63
|
-
while (prefixLen < maxLen && previous.charCodeAt(prefixLen) === next.charCodeAt(prefixLen)) {
|
|
64
|
-
prefixLen += 1;
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
delta: next.slice(prefixLen),
|
|
68
|
-
nextSnapshot: next,
|
|
69
|
-
nonMonotonic: true,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function createWeiboOutboundStream(params: CreateWeiboOutboundStreamParams) {
|
|
74
|
-
const {
|
|
75
|
-
chunkMode,
|
|
76
|
-
textChunkLimit,
|
|
77
|
-
emit,
|
|
78
|
-
chunkTextWithMode,
|
|
79
|
-
streamDebug,
|
|
80
|
-
} = params;
|
|
81
|
-
|
|
82
|
-
let hasSeenPartial = false;
|
|
83
|
-
let hasEmittedChunks = false;
|
|
84
|
-
let hasEmittedDone = false;
|
|
85
|
-
let lastPartialSnapshot = "";
|
|
86
|
-
let newlineBuffer = "";
|
|
87
|
-
let pendingDeliverBuffer = "";
|
|
88
|
-
|
|
89
|
-
const splitOutboundText = (text: string): string[] =>
|
|
90
|
-
chunkMode === "raw"
|
|
91
|
-
? [text]
|
|
92
|
-
: Array.from(chunkTextWithMode(text, textChunkLimit, chunkMode));
|
|
93
|
-
|
|
94
|
-
const emitChunks = async (chunks: string[], markLastDone: boolean, source: "partial" | "deliver" | "settled"): Promise<boolean> => {
|
|
95
|
-
const normalizedChunks = chunks.filter((chunk) => chunk.length > 0);
|
|
96
|
-
streamDebug?.("emit_chunks_prepare", {
|
|
97
|
-
candidateCount: chunks.length,
|
|
98
|
-
normalizedCount: normalizedChunks.length,
|
|
99
|
-
markLastDone,
|
|
100
|
-
chunkMode,
|
|
101
|
-
source,
|
|
102
|
-
});
|
|
103
|
-
if (normalizedChunks.length === 0) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
for (let index = 0; index < normalizedChunks.length; index += 1) {
|
|
108
|
-
const done = markLastDone && index === normalizedChunks.length - 1;
|
|
109
|
-
await emit({
|
|
110
|
-
text: normalizedChunks[index] ?? "",
|
|
111
|
-
done,
|
|
112
|
-
source,
|
|
113
|
-
});
|
|
114
|
-
hasEmittedChunks = true;
|
|
115
|
-
if (done) {
|
|
116
|
-
hasEmittedDone = true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return true;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const flushText = async (text: string, isFinal: boolean, source: "partial" | "deliver" | "settled"): Promise<boolean> => {
|
|
123
|
-
if (chunkMode === "newline") {
|
|
124
|
-
if (!isFinal) {
|
|
125
|
-
newlineBuffer += text;
|
|
126
|
-
const flushBoundary = findLastParagraphDelimiterEnd(newlineBuffer);
|
|
127
|
-
streamDebug?.("newline_buffered", {
|
|
128
|
-
source,
|
|
129
|
-
incomingLen: text.length,
|
|
130
|
-
bufferLen: newlineBuffer.length,
|
|
131
|
-
flushBoundary,
|
|
132
|
-
});
|
|
133
|
-
if (flushBoundary <= 0) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
const flushableText = newlineBuffer.slice(0, flushBoundary);
|
|
137
|
-
newlineBuffer = newlineBuffer.slice(flushBoundary);
|
|
138
|
-
streamDebug?.("newline_flush", {
|
|
139
|
-
source,
|
|
140
|
-
flushableLen: flushableText.length,
|
|
141
|
-
remainingBufferLen: newlineBuffer.length,
|
|
142
|
-
});
|
|
143
|
-
return emitChunks(splitOutboundText(flushableText), false, source);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const textToSend = `${newlineBuffer}${text}`;
|
|
147
|
-
newlineBuffer = "";
|
|
148
|
-
return emitChunks(splitOutboundText(textToSend), true, source);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return emitChunks(splitOutboundText(text), isFinal, source);
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const finalizeWithDoneMarker = async (source: "deliver" | "settled"): Promise<void> => {
|
|
155
|
-
if (hasEmittedDone) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const emitted = await flushText("", true, source);
|
|
159
|
-
if (!emitted && hasEmittedChunks && !hasEmittedDone) {
|
|
160
|
-
streamDebug?.("emit_done_marker", { source, reason: "final_without_text" });
|
|
161
|
-
await emit({
|
|
162
|
-
text: "",
|
|
163
|
-
done: true,
|
|
164
|
-
source,
|
|
165
|
-
});
|
|
166
|
-
hasEmittedDone = true;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
async pushPartialSnapshot(snapshot: string): Promise<void> {
|
|
172
|
-
if (!snapshot) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
hasSeenPartial = true;
|
|
177
|
-
const previousSnapshotLen = lastPartialSnapshot.length;
|
|
178
|
-
const deltaResult = resolveDeltaFromSnapshot(lastPartialSnapshot, snapshot);
|
|
179
|
-
lastPartialSnapshot = deltaResult.nextSnapshot;
|
|
180
|
-
|
|
181
|
-
streamDebug?.("partial_snapshot", {
|
|
182
|
-
snapshotLen: snapshot.length,
|
|
183
|
-
prevLen: previousSnapshotLen,
|
|
184
|
-
deltaLen: deltaResult.delta.length,
|
|
185
|
-
nonMonotonic: deltaResult.nonMonotonic,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
if (!deltaResult.delta) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
await flushText(deltaResult.delta, false, "partial");
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
async pushDeliverText(params: { text: string; isFinal: boolean }): Promise<void> {
|
|
195
|
-
const text = params.text ?? "";
|
|
196
|
-
if (!params.isFinal) {
|
|
197
|
-
if (!hasSeenPartial && text.length > 0) {
|
|
198
|
-
pendingDeliverBuffer += text;
|
|
199
|
-
streamDebug?.("deliver_buffered", {
|
|
200
|
-
kind: "block",
|
|
201
|
-
incomingLen: text.length,
|
|
202
|
-
pendingDeliverBufferLen: pendingDeliverBuffer.length,
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (hasSeenPartial) {
|
|
209
|
-
if (text.length > 0) {
|
|
210
|
-
await this.pushPartialSnapshot(text);
|
|
211
|
-
}
|
|
212
|
-
await finalizeWithDoneMarker("deliver");
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const fallbackText = `${pendingDeliverBuffer}${text}`;
|
|
217
|
-
pendingDeliverBuffer = "";
|
|
218
|
-
await flushText(fallbackText, true, "deliver");
|
|
219
|
-
await finalizeWithDoneMarker("deliver");
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
async settle(): Promise<void> {
|
|
223
|
-
if (!hasSeenPartial && pendingDeliverBuffer.length > 0) {
|
|
224
|
-
const buffered = pendingDeliverBuffer;
|
|
225
|
-
pendingDeliverBuffer = "";
|
|
226
|
-
await flushText(buffered, true, "settled");
|
|
227
|
-
}
|
|
228
|
-
await finalizeWithDoneMarker("settled");
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
snapshot(): StreamStateSnapshot {
|
|
232
|
-
return {
|
|
233
|
-
hasSeenPartial,
|
|
234
|
-
hasEmittedChunks,
|
|
235
|
-
hasEmittedDone,
|
|
236
|
-
newlineBufferLen: newlineBuffer.length,
|
|
237
|
-
pendingDeliverBufferLen: pendingDeliverBuffer.length,
|
|
238
|
-
};
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
}
|
package/src/outbound.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ChannelOutboundAdapter,
|
|
3
|
-
ChannelOutboundContext,
|
|
4
|
-
} from "openclaw/plugin-sdk";
|
|
5
|
-
import { sendMessageWeibo } from "./send.js";
|
|
6
|
-
|
|
7
|
-
// Simple text chunker - splits by character length
|
|
8
|
-
// Mode is handled by the SDK's chunkTextWithMode helper
|
|
9
|
-
function chunkText(text: string, limit: number): string[] {
|
|
10
|
-
if (text.length <= limit) {
|
|
11
|
-
return [text];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const chunks: string[] = [];
|
|
15
|
-
for (let i = 0; i < text.length; i += limit) {
|
|
16
|
-
chunks.push(text.slice(i, i + limit));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return chunks;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const weiboOutbound: ChannelOutboundAdapter = {
|
|
23
|
-
deliveryMode: "direct",
|
|
24
|
-
chunker: chunkText,
|
|
25
|
-
chunkerMode: "text",
|
|
26
|
-
textChunkLimit: 2000, // Weibo DM text limit is around 2000 chars
|
|
27
|
-
|
|
28
|
-
sendText: async (ctx: ChannelOutboundContext) => {
|
|
29
|
-
const { cfg, to, text, accountId } = ctx;
|
|
30
|
-
|
|
31
|
-
const result = await sendMessageWeibo({
|
|
32
|
-
cfg,
|
|
33
|
-
to: to ?? "",
|
|
34
|
-
text: text ?? "",
|
|
35
|
-
accountId: accountId ?? undefined,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
channel: "weibo" as const,
|
|
40
|
-
messageId: result.messageId,
|
|
41
|
-
chatId: result.chatId,
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
sendMedia: async (_ctx: ChannelOutboundContext) => {
|
|
46
|
-
// Weibo plugin doesn't support media
|
|
47
|
-
throw new Error("Weibo channel does not support media messages");
|
|
48
|
-
},
|
|
49
|
-
};
|
package/src/plugin-sdk-compat.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import * as pluginSdk from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
export type MediaItem = {
|
|
4
|
-
path: string;
|
|
5
|
-
contentType?: string | null;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export type AgentMediaPayload = {
|
|
9
|
-
MediaPath?: string;
|
|
10
|
-
MediaPaths?: string[];
|
|
11
|
-
MediaType?: string;
|
|
12
|
-
MediaTypes?: string[];
|
|
13
|
-
MediaUrl?: string;
|
|
14
|
-
MediaUrls?: string[];
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type PluginSdkCompat = {
|
|
18
|
-
buildAgentMediaPayload?: (mediaList: MediaItem[]) => AgentMediaPayload;
|
|
19
|
-
buildMediaPayload?: (mediaList: MediaItem[]) => AgentMediaPayload;
|
|
20
|
-
waitUntilAbort?: (abortSignal?: AbortSignal) => Promise<void>;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
function buildAgentMediaPayloadFallback(mediaList: MediaItem[]): AgentMediaPayload {
|
|
24
|
-
const normalized = mediaList.filter((item) => typeof item.path === "string" && item.path.trim().length > 0);
|
|
25
|
-
if (normalized.length === 0) {
|
|
26
|
-
return {};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const paths = normalized.map((item) => item.path);
|
|
30
|
-
const types = normalized.map((item) => item.contentType ?? undefined).filter((value): value is string => typeof value === "string");
|
|
31
|
-
const payload: AgentMediaPayload = {
|
|
32
|
-
MediaPath: paths[0],
|
|
33
|
-
MediaPaths: paths,
|
|
34
|
-
MediaUrl: paths[0],
|
|
35
|
-
MediaUrls: paths,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (types.length > 0) {
|
|
39
|
-
payload.MediaType = types[0];
|
|
40
|
-
payload.MediaTypes = types;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return payload;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function waitUntilAbortFallback(abortSignal?: AbortSignal): Promise<void> {
|
|
47
|
-
if (!abortSignal) {
|
|
48
|
-
return new Promise<void>(() => undefined);
|
|
49
|
-
}
|
|
50
|
-
if (abortSignal.aborted) {
|
|
51
|
-
return Promise.resolve();
|
|
52
|
-
}
|
|
53
|
-
return new Promise<void>((resolve) => {
|
|
54
|
-
abortSignal.addEventListener("abort", () => resolve(), { once: true });
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function buildAgentMediaPayloadCompat(
|
|
59
|
-
mediaList: MediaItem[],
|
|
60
|
-
sdk: PluginSdkCompat = pluginSdk as PluginSdkCompat,
|
|
61
|
-
): AgentMediaPayload {
|
|
62
|
-
if (typeof sdk.buildAgentMediaPayload === "function") {
|
|
63
|
-
return sdk.buildAgentMediaPayload(mediaList);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (typeof sdk.buildMediaPayload === "function") {
|
|
67
|
-
return sdk.buildMediaPayload(mediaList);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return buildAgentMediaPayloadFallback(mediaList);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function waitUntilAbortCompat(
|
|
74
|
-
abortSignal?: AbortSignal,
|
|
75
|
-
sdk: PluginSdkCompat = pluginSdk as PluginSdkCompat,
|
|
76
|
-
): Promise<void> {
|
|
77
|
-
if (typeof sdk.waitUntilAbort === "function") {
|
|
78
|
-
return sdk.waitUntilAbort(abortSignal);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return waitUntilAbortFallback(abortSignal);
|
|
82
|
-
}
|
package/src/policy.ts
DELETED
package/src/runtime.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
-
|
|
3
|
-
let weiboRuntime: PluginRuntime | undefined;
|
|
4
|
-
|
|
5
|
-
export function setWeiboRuntime(runtime: PluginRuntime): void {
|
|
6
|
-
weiboRuntime = runtime;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function getWeiboRuntime(): PluginRuntime {
|
|
10
|
-
if (!weiboRuntime) {
|
|
11
|
-
throw new Error("Weibo runtime not initialized");
|
|
12
|
-
}
|
|
13
|
-
return weiboRuntime;
|
|
14
|
-
}
|
package/src/search-schema.ts
DELETED
package/src/send.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
import type { WeiboSendResult } from "./types.js";
|
|
3
|
-
import { resolveWeiboAccount } from "./accounts.js";
|
|
4
|
-
import { createWeiboClient } from "./client.js";
|
|
5
|
-
import { normalizeWeiboTarget } from "./targets.js";
|
|
6
|
-
|
|
7
|
-
export type SendWeiboMessageParams = {
|
|
8
|
-
cfg: ClawdbotConfig;
|
|
9
|
-
to: string;
|
|
10
|
-
text: string;
|
|
11
|
-
accountId?: string;
|
|
12
|
-
messageId?: string;
|
|
13
|
-
chunkId?: number;
|
|
14
|
-
done?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export function generateWeiboMessageId(): string {
|
|
18
|
-
return `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function normalizeChunkId(chunkId?: number): number {
|
|
22
|
-
if (typeof chunkId !== "number" || !Number.isFinite(chunkId) || chunkId < 0) {
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
return Math.floor(chunkId);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function sendMessageWeibo(params: SendWeiboMessageParams): Promise<WeiboSendResult> {
|
|
29
|
-
const { cfg, to, text, accountId, messageId, chunkId, done } = params;
|
|
30
|
-
const streamDebugEnabled = process.env.WEIBO_STREAM_DEBUG === "1";
|
|
31
|
-
const account = resolveWeiboAccount({ cfg, accountId });
|
|
32
|
-
|
|
33
|
-
if (!account.configured) {
|
|
34
|
-
throw new Error(`Weibo account "${account.accountId}" not configured`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const client = createWeiboClient(account);
|
|
38
|
-
const receiveId = normalizeWeiboTarget(to);
|
|
39
|
-
|
|
40
|
-
if (!receiveId) {
|
|
41
|
-
throw new Error(`Invalid Weibo target: ${to}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const userId = receiveId.replace(/^user:/, "");
|
|
45
|
-
const outboundMessageId = typeof messageId === "string" && messageId.trim()
|
|
46
|
-
? messageId.trim()
|
|
47
|
-
: generateWeiboMessageId();
|
|
48
|
-
const outboundChunkId = normalizeChunkId(chunkId);
|
|
49
|
-
const outboundDone = typeof done === "boolean" ? done : true;
|
|
50
|
-
|
|
51
|
-
client.send({
|
|
52
|
-
type: "send_message",
|
|
53
|
-
payload: {
|
|
54
|
-
toUserId: userId,
|
|
55
|
-
text: text ?? "",
|
|
56
|
-
messageId: outboundMessageId,
|
|
57
|
-
chunkId: outboundChunkId,
|
|
58
|
-
done: outboundDone,
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
if (streamDebugEnabled) {
|
|
62
|
-
console.log(
|
|
63
|
-
`[weibo][stream-debug] ws_send ${JSON.stringify({
|
|
64
|
-
toUserId: userId,
|
|
65
|
-
messageId: outboundMessageId,
|
|
66
|
-
chunkId: outboundChunkId,
|
|
67
|
-
done: outboundDone,
|
|
68
|
-
textLen: (text ?? "").length,
|
|
69
|
-
preview: (text ?? "").slice(0, 80),
|
|
70
|
-
})}`,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
messageId: outboundMessageId,
|
|
76
|
-
chatId: receiveId,
|
|
77
|
-
chunkId: outboundChunkId,
|
|
78
|
-
done: outboundDone,
|
|
79
|
-
};
|
|
80
|
-
}
|
package/src/sim-page.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import type { WeiboResponseContentPart, WeiboResponseMessageInputItem } from "./types.js";
|
|
2
|
-
|
|
3
|
-
type SimStateLike = {
|
|
4
|
-
credentials?: Array<{
|
|
5
|
-
appId?: unknown;
|
|
6
|
-
appSecret?: unknown;
|
|
7
|
-
createdAt?: unknown;
|
|
8
|
-
}>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type LatestCredential = {
|
|
12
|
-
appId: string;
|
|
13
|
-
appSecret: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type SimPageEndpoints = {
|
|
17
|
-
tokenUrl: string;
|
|
18
|
-
wsUrl: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type SimInboundPayload = {
|
|
22
|
-
messageId: string;
|
|
23
|
-
fromUserId: string;
|
|
24
|
-
text: string;
|
|
25
|
-
timestamp: number;
|
|
26
|
-
input?: WeiboResponseMessageInputItem[];
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type SimComposerAttachment = {
|
|
30
|
-
kind: "image" | "file";
|
|
31
|
-
filename: string;
|
|
32
|
-
mimeType: string;
|
|
33
|
-
dataBase64: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export function getLatestCredentialFromState(state: SimStateLike): LatestCredential | null {
|
|
37
|
-
const credentials = Array.isArray(state.credentials) ? state.credentials : [];
|
|
38
|
-
if (credentials.length === 0) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const sorted = [...credentials].sort((a, b) => {
|
|
43
|
-
const aTs = typeof a.createdAt === "number" ? a.createdAt : 0;
|
|
44
|
-
const bTs = typeof b.createdAt === "number" ? b.createdAt : 0;
|
|
45
|
-
return bTs - aTs;
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const first = sorted[0];
|
|
49
|
-
const appId = String(first?.appId ?? "").trim();
|
|
50
|
-
const appSecret = String(first?.appSecret ?? "").trim();
|
|
51
|
-
|
|
52
|
-
if (!appId || !appSecret) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return { appId, appSecret };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function getSimPageEndpoints({
|
|
60
|
-
pageOrigin,
|
|
61
|
-
wsPort,
|
|
62
|
-
}: {
|
|
63
|
-
pageOrigin: string;
|
|
64
|
-
wsPort: number;
|
|
65
|
-
}): SimPageEndpoints {
|
|
66
|
-
const origin = new URL(pageOrigin);
|
|
67
|
-
const wsProtocol = origin.protocol === "https:" ? "wss:" : "ws:";
|
|
68
|
-
const tokenUrl = new URL("/open/auth/ws_token", origin).toString();
|
|
69
|
-
const wsUrl = `${wsProtocol}//${origin.hostname}:${wsPort}/ws/stream`;
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
tokenUrl,
|
|
73
|
-
wsUrl,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function getSimUiUrl({
|
|
78
|
-
host,
|
|
79
|
-
httpPort,
|
|
80
|
-
}: {
|
|
81
|
-
host: string;
|
|
82
|
-
httpPort: number;
|
|
83
|
-
}): string {
|
|
84
|
-
return `http://${host}:${httpPort}/`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function buildSimInputItems(params: {
|
|
88
|
-
text: string;
|
|
89
|
-
attachments?: SimComposerAttachment[];
|
|
90
|
-
}): WeiboResponseMessageInputItem[] | undefined {
|
|
91
|
-
const content: WeiboResponseContentPart[] = [];
|
|
92
|
-
const text = params.text.trim();
|
|
93
|
-
|
|
94
|
-
if (text) {
|
|
95
|
-
content.push({
|
|
96
|
-
type: "input_text",
|
|
97
|
-
text,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
for (const attachment of params.attachments ?? []) {
|
|
102
|
-
content.push({
|
|
103
|
-
type: attachment.kind === "image" ? "input_image" : "input_file",
|
|
104
|
-
filename: attachment.filename,
|
|
105
|
-
source: {
|
|
106
|
-
type: "base64",
|
|
107
|
-
media_type: attachment.mimeType,
|
|
108
|
-
data: attachment.dataBase64,
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (content.length === 0) {
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return [
|
|
118
|
-
{
|
|
119
|
-
type: "message",
|
|
120
|
-
role: "user",
|
|
121
|
-
content,
|
|
122
|
-
},
|
|
123
|
-
];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function buildSimInboundPayload(params: {
|
|
127
|
-
messageId: string;
|
|
128
|
-
fromUserId: string;
|
|
129
|
-
text: string;
|
|
130
|
-
timestamp: number;
|
|
131
|
-
input?: WeiboResponseMessageInputItem[];
|
|
132
|
-
}): SimInboundPayload {
|
|
133
|
-
return {
|
|
134
|
-
messageId: params.messageId,
|
|
135
|
-
fromUserId: params.fromUserId,
|
|
136
|
-
text: params.text,
|
|
137
|
-
timestamp: params.timestamp,
|
|
138
|
-
...(params.input?.length ? { input: params.input } : {}),
|
|
139
|
-
};
|
|
140
|
-
}
|