@zhin.js/adapter-onebot12 1.1.21 → 1.1.23
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/CHANGELOG.md +62 -0
- package/adapters/onebot12/index.js +16 -4
- package/adapters/onebot12/index.ts +16 -4
- package/lib/protocol.d.ts +2 -0
- package/lib/protocol.js +13 -0
- package/lib/side-event-dispatch.js +1 -1
- package/lib/webhook.js +6 -1
- package/lib/ws-endpoint.js +10 -1
- package/lib/ws-types.d.ts +1 -0
- package/lib/wss-endpoint.js +10 -1
- package/package.json +16 -15
- package/plugin.js +1 -0
- package/src/protocol.ts +12 -0
- package/src/side-event-dispatch.ts +1 -1
- package/src/webhook.ts +6 -0
- package/src/ws-endpoint.ts +10 -0
- package/src/ws-types.ts +1 -0
- package/src/wss-endpoint.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot12
|
|
2
2
|
|
|
3
|
+
## 1.1.23
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- bc6ccb1: Deep audit bug fixes and 7 architectural improvements:
|
|
8
|
+
- Sink Agent Turn ingress pipeline from `@zhin.js/cli` into `@zhin.js/agent/runtime` (`plugin-runtime/ingress/`) and decompose `ingress-route.ts` into modular pipeline stages.
|
|
9
|
+
- Bind Session State Plane (`JsxButtonRegistry`, `InteractionRuntime`, `RuntimeInteractiveRouter`) to `PluginIncarnationRef` so active buttons and interactions survive unrelated-plugin HMR while expiring when the owning plugin reloads, and support per-conversation fallback numbering (`numberingScope: 'conversation'`).
|
|
10
|
+
- Establish `conversation_events` as the canonical message SSOT and reference `conversation_event_id`, `conversation_key`, `platform_message_id`, and `message_key` in `agent_messages` (`AGENT_MESSAGE_QUERY_VERSION = 2`), threading `conversationSequence` across inbound and outbound delivery receipts.
|
|
11
|
+
- Push down `DatabaseContextRepository` and `DatabaseScheduleJobStorage` full-session/full-table memory scans to indexed SQL queries.
|
|
12
|
+
- Add kernel-level inbound `replyTo` and `mentioned` auto-promotion (`promoteInboundMessagePayload`) plus reusable `InboundDeduper` and `TtlLookupCache` primitives in `@zhin.js/adapter`.
|
|
13
|
+
- Add `MiddlewareContext.dispatch` (`InboundDispatchSummary`) and `onAfterDispatch` hooks for `after-dispatch` middlewares, and support incremental rendering of in-place `envelope.payload` array mutations in `OutboundDeliveryRuntime`.
|
|
14
|
+
- Unify `HistoryWindowTracker` and `AgentCompactionRuntime` token/message budgets (`resolveUnifiedHistoryAndCompactionBudget`).
|
|
15
|
+
- Fix schema validation, database transaction connection cleanup and SQLite WAL mode, schedule timer wheel head-of-line blocking, security policy bash read paths and subagent guard propagation, group merge window permission carrier handoff, micro-compact namespaced tool matching, and WebSocket force-close / inbound segment mapping across adapters.
|
|
16
|
+
- Updated dependencies [6163abc]
|
|
17
|
+
- Updated dependencies [fed2c27]
|
|
18
|
+
- Updated dependencies [bc6ccb1]
|
|
19
|
+
- Updated dependencies [72b5a12]
|
|
20
|
+
- Updated dependencies [aa41889]
|
|
21
|
+
- Updated dependencies [4427e72]
|
|
22
|
+
- Updated dependencies [22bd14a]
|
|
23
|
+
- @zhin.js/core@1.1.57
|
|
24
|
+
- @zhin.js/client@1.1.25
|
|
25
|
+
- @zhin.js/page@1.1.15
|
|
26
|
+
- @zhin.js/im-contract@1.1.12
|
|
27
|
+
- @zhin.js/adapter@1.1.29
|
|
28
|
+
- @zhin.js/host-http@1.1.15
|
|
29
|
+
- @zhin.js/feature-kit@1.1.13
|
|
30
|
+
- @zhin.js/adapter-onebot-events@0.0.2
|
|
31
|
+
- @zhin.js/skill@1.1.14
|
|
32
|
+
|
|
33
|
+
## 1.1.22
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- b249e5e: ADR 0044 C4:事件映射迁出 core。新增 `@zhin.js/adapter-onebot-events`,承载 OneBot v11 / NapCat / icqq 的原始通知与请求 → 标准事件映射(`receiveOneBotLikeSideEvent`、`mapNoticeParts`、`mapRequestParts`、`resolveSideEventDedupeKey` 及 OneBot 映射表,icqq 差异用覆盖表表达);KOOK、Slack 的映射迁入各自适配器;`@zhin.js/core` 只保留标准事件名、类型与 `buildNotice` / `buildRequest` / `buildSystem` / `senderFromId`,不再含任何平台名。core 不再导出上述映射函数与 `ONEBOT_/KOOK_/SLACK_NOTICE_PARTS_MAP`、`SideEventPlatform`、`OneBotLike*` 类型,适配器改从共享包导入。
|
|
38
|
+
- 41ff1a5: ADR 0044 C5: every official adapter now declares a capability `profile` (its `segments` moved into `profile.default.messaging.segments`). icqq declares the complete profile (per conversation kind: scene, all 14 actions with real limits, events, feedback, delivery) and implements the seven new management ports (`pokeUser`, `unmuteGroupMember`, `muteAllGroupMembers`, `setGroupCard`, `setGroupTitle`, `setGroupEssence`, `inviteGroupMember`) with fresh bot-role reads. qq official declares its passive reply windows; undeclared capabilities stay unsupported.
|
|
39
|
+
- cbd3f14: ADR 0044 integration and C6 guard. `delivery.spool` now reproduces the pre-0044 media rule (icqq `false`, every other official adapter `true`). icqq narrows `actions.recall.others` unless the Bot is admin or owner, and declares recall for groups. Endpoint kind capabilities merge the Endpoint's `operations` (Discord reactions keep working; Discord declares reaction feedback). Adapters in the `@zhin.js/` scope are trusted: their custom prompt text is not labelled `external_content`. Core no longer keeps a telegram/discord interactive-policy table (adapters declare `segments.interactive`). New `pnpm check:no-platform-branches` blocks platform-name branches in runtime code.
|
|
40
|
+
- 4fe49b5: 支持配置按需生效:分离保存与有效版本,独立变更先应用,账号资料更新保留连接,模型按回合使用确定版本;Console 返回结构化应用结果。监听改为仅显式 --watch 启用,开发模板显式选择源码和配置监听。
|
|
41
|
+
|
|
42
|
+
自变更消费配置应用回执,避免已处理配置被二次重载;持久化本次写入修订和应用结果,未知结果或修订冲突时停止自动续作并保留现场,恢复不会覆盖未经本次变更确认的配置。
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [b249e5e]
|
|
45
|
+
- Updated dependencies [57661f6]
|
|
46
|
+
- Updated dependencies [cbd3f14]
|
|
47
|
+
- Updated dependencies [299863a]
|
|
48
|
+
- Updated dependencies [aaa93d7]
|
|
49
|
+
- Updated dependencies [bd524d1]
|
|
50
|
+
- Updated dependencies [126ae99]
|
|
51
|
+
- Updated dependencies [4fe49b5]
|
|
52
|
+
- Updated dependencies [cce07db]
|
|
53
|
+
- Updated dependencies [b652db3]
|
|
54
|
+
- Updated dependencies [0315ba0]
|
|
55
|
+
- @zhin.js/adapter-onebot-events@0.0.1
|
|
56
|
+
- @zhin.js/core@1.1.56
|
|
57
|
+
- @zhin.js/adapter@1.1.28
|
|
58
|
+
- @zhin.js/im-contract@1.1.11
|
|
59
|
+
- @zhin.js/skill@1.1.13
|
|
60
|
+
- @zhin.js/host-http@1.1.14
|
|
61
|
+
- @zhin.js/feature-kit@1.1.12
|
|
62
|
+
- @zhin.js/client@1.1.24
|
|
63
|
+
- @zhin.js/page@1.1.14
|
|
64
|
+
|
|
3
65
|
## 1.1.21
|
|
4
66
|
|
|
5
67
|
### Patch Changes
|
|
@@ -10,12 +10,24 @@ export { OneBot12WsEndpoint } from "../../lib/ws-endpoint.js";
|
|
|
10
10
|
export { OneBot12WssEndpoint } from "../../lib/wss-endpoint.js";
|
|
11
11
|
export default defineAdapter({
|
|
12
12
|
capabilities: ['inbound', 'outbound'],
|
|
13
|
-
operations: ['recall'],
|
|
14
13
|
// 媒体段经 upload_file 物化为 file_id(spec 正式投递);上传失败降级扩展字段透传。
|
|
15
14
|
// 无卡片交互面,交互段降级纯文本。
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
profile: {
|
|
16
|
+
default: {
|
|
17
|
+
messaging: {
|
|
18
|
+
segments: {
|
|
19
|
+
outboundMedia: ['url', 'path', 'base64', 'upload'],
|
|
20
|
+
interactive: 'text',
|
|
21
|
+
},
|
|
22
|
+
quote: true,
|
|
23
|
+
recall: {},
|
|
24
|
+
},
|
|
25
|
+
actions: {
|
|
26
|
+
recall: { scopes: ['private', 'group'] },
|
|
27
|
+
quoteReply: { scopes: ['private', 'group'] },
|
|
28
|
+
},
|
|
29
|
+
delivery: { send: true, proactive: true, spool: true },
|
|
30
|
+
},
|
|
19
31
|
},
|
|
20
32
|
createAdapter: context => new Onebot12Adapter(context),
|
|
21
33
|
});
|
|
@@ -17,12 +17,24 @@ export type { OneBot12WsSocket, OneBot12WsCreateOptions } from '../../src/ws-typ
|
|
|
17
17
|
|
|
18
18
|
export default defineAdapter<OneBot12EndpointConfig>({
|
|
19
19
|
capabilities: ['inbound', 'outbound'],
|
|
20
|
-
operations: ['recall'],
|
|
21
20
|
// 媒体段经 upload_file 物化为 file_id(spec 正式投递);上传失败降级扩展字段透传。
|
|
22
21
|
// 无卡片交互面,交互段降级纯文本。
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
profile: {
|
|
23
|
+
default: {
|
|
24
|
+
messaging: {
|
|
25
|
+
segments: {
|
|
26
|
+
outboundMedia: ['url', 'path', 'base64', 'upload'],
|
|
27
|
+
interactive: 'text',
|
|
28
|
+
},
|
|
29
|
+
quote: true,
|
|
30
|
+
recall: {},
|
|
31
|
+
},
|
|
32
|
+
actions: {
|
|
33
|
+
recall: { scopes: ['private', 'group'] },
|
|
34
|
+
quoteReply: { scopes: ['private', 'group'] },
|
|
35
|
+
},
|
|
36
|
+
delivery: { send: true, proactive: true, spool: true },
|
|
37
|
+
},
|
|
26
38
|
},
|
|
27
39
|
createAdapter: context => new Onebot12Adapter(context),
|
|
28
40
|
});
|
package/lib/protocol.d.ts
CHANGED
|
@@ -121,6 +121,8 @@ export declare function senderNickname(ev: OneBot12Event): string | undefined;
|
|
|
121
121
|
* 新 Plugin Runtime 的 Message.content 为纯文本,mention 信息只能经 metadata.mentioned 传递。
|
|
122
122
|
*/
|
|
123
123
|
export declare function isBotMentioned(ev: OneBot12Event): boolean;
|
|
124
|
+
/** 提取入站消息中的回复引用 message_id。 */
|
|
125
|
+
export declare function extractQuoteId(ev: OneBot12Event): string | undefined;
|
|
124
126
|
/**
|
|
125
127
|
* canonical MediaRef → OneBot 12 媒体字段(扩展字段降级形状)。
|
|
126
128
|
* spec 正式投递形状是 `file_id`(先 upload_file 物化,见
|
package/lib/protocol.js
CHANGED
|
@@ -159,6 +159,19 @@ export function isBotMentioned(ev) {
|
|
|
159
159
|
return false;
|
|
160
160
|
return ev.message.some((seg) => seg.type === 'mention' && String(seg.data?.['user_id'] ?? '') === selfId);
|
|
161
161
|
}
|
|
162
|
+
/** 提取入站消息中的回复引用 message_id。 */
|
|
163
|
+
export function extractQuoteId(ev) {
|
|
164
|
+
if (!Array.isArray(ev.message))
|
|
165
|
+
return undefined;
|
|
166
|
+
for (const seg of ev.message) {
|
|
167
|
+
if (seg?.type === 'reply') {
|
|
168
|
+
const id = seg.data?.['message_id'] ?? seg.data?.['id'];
|
|
169
|
+
if (id != null && String(id).trim() !== '')
|
|
170
|
+
return String(id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
162
175
|
/** OneBot 12 携带媒体的段类型。 */
|
|
163
176
|
const ONEBOT12_MEDIA_TYPES = new Set(['image', 'voice', 'audio', 'video', 'file']);
|
|
164
177
|
/** 媒体段 data 里的 canonical 字段,归一后不重复进 wire。 */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { receiveOneBotLikeSideEvent } from '@zhin.js/
|
|
1
|
+
import { receiveOneBotLikeSideEvent } from '@zhin.js/adapter-onebot-events';
|
|
2
2
|
import { formatCompact } from '@zhin.js/logger';
|
|
3
3
|
export function receiveOneBot12SideEvent(raw, context) {
|
|
4
4
|
const { emit, endpointKey, caller, logger } = context;
|
package/lib/webhook.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
import { acceptHttpIngress } from 'imhelper';
|
|
3
4
|
import { createEndpointSpecification, endpointSpec, createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
4
5
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
5
6
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
6
|
-
import { buildSendMessageParams, matchesOneBot12Self, callOneBot12Action, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
7
|
+
import { buildSendMessageParams, matchesOneBot12Self, callOneBot12Action, extractQuoteId, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
7
8
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
8
9
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
9
10
|
import { callOnebot12Client, readOnebot12Response, onebot12ClientOptions, forwardOnebot12ClientEvents, Onebot12Client } from './client.js';
|
|
@@ -125,15 +126,19 @@ export class OneBot12WebhookEndpoint extends Onebot12Client {
|
|
|
125
126
|
const content = formatInboundContent(ev);
|
|
126
127
|
const nickname = senderNickname(ev);
|
|
127
128
|
const mentioned = isBotMentioned(ev);
|
|
129
|
+
const quoteId = extractQuoteId(ev);
|
|
130
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
128
131
|
void this[endpointSpec].events.message({
|
|
129
132
|
event: ev,
|
|
130
133
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
131
134
|
conversation,
|
|
132
135
|
message: { conversation, id: ev.message_id },
|
|
133
136
|
content,
|
|
137
|
+
...(segments?.length ? { segments } : {}),
|
|
134
138
|
sender: { id: senderUserId(ev), ...(nickname ? { name: nickname } : {}) },
|
|
135
139
|
endpointId: this.#options.config.id,
|
|
136
140
|
...(mentioned ? { mentioned: true } : {}),
|
|
141
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
137
142
|
metadata: Object.freeze({
|
|
138
143
|
detail_type: ev.detail_type,
|
|
139
144
|
user_id: ev.user_id,
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot12 WS client endpoint — outbound connect to OneBot implementation.
|
|
4
5
|
*/
|
|
@@ -6,7 +7,7 @@ import WebSocket from 'ws';
|
|
|
6
7
|
import { createEndpointSpecification, endpointSpec, createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
|
|
7
8
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
9
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
9
|
-
import { buildSendMessageParams, matchesOneBot12Self, buildWsConnectOptions, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
10
|
+
import { buildSendMessageParams, matchesOneBot12Self, buildWsConnectOptions, extractQuoteId, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
10
11
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
11
12
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
12
13
|
import { callOnebot12Client, readOnebot12Response, onebot12ClientOptions, forwardOnebot12ClientEvents, Onebot12Client } from './client.js';
|
|
@@ -143,15 +144,19 @@ export class OneBot12WsEndpoint extends Onebot12Client {
|
|
|
143
144
|
const content = formatInboundContent(ev);
|
|
144
145
|
const nickname = senderNickname(ev);
|
|
145
146
|
const mentioned = isBotMentioned(ev);
|
|
147
|
+
const quoteId = extractQuoteId(ev);
|
|
148
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
146
149
|
void this[endpointSpec].events.message({
|
|
147
150
|
event: ev,
|
|
148
151
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
149
152
|
conversation,
|
|
150
153
|
message: { conversation, id: ev.message_id },
|
|
151
154
|
content,
|
|
155
|
+
...(segments?.length ? { segments } : {}),
|
|
152
156
|
sender: { id: senderUserId(ev), name: senderNickname(ev) },
|
|
153
157
|
endpointId: this.#options.config.id,
|
|
154
158
|
...(mentioned ? { mentioned: true } : {}),
|
|
159
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
155
160
|
metadata: Object.freeze({
|
|
156
161
|
detail_type: ev.detail_type,
|
|
157
162
|
user_id: ev.user_id,
|
|
@@ -185,8 +190,12 @@ export class OneBot12WsEndpoint extends Onebot12Client {
|
|
|
185
190
|
const ws = create(url, { headers });
|
|
186
191
|
this.#ws = ws;
|
|
187
192
|
handle.onForceClose(() => {
|
|
193
|
+
if (this.#ws === ws) {
|
|
194
|
+
this.#rpc.disconnect();
|
|
195
|
+
}
|
|
188
196
|
try {
|
|
189
197
|
ws.close();
|
|
198
|
+
ws.terminate?.();
|
|
190
199
|
}
|
|
191
200
|
catch {
|
|
192
201
|
/* ignore */
|
package/lib/ws-types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface OneBot12WsSocket {
|
|
|
3
3
|
readonly readyState: number;
|
|
4
4
|
send(data: string): void;
|
|
5
5
|
close(code?: number, reason?: string): void;
|
|
6
|
+
terminate?(): void;
|
|
6
7
|
on(event: 'open' | 'message' | 'close' | 'error', listener: (...args: unknown[]) => void): void;
|
|
7
8
|
}
|
|
8
9
|
export interface OneBot12WsCreateOptions {
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot12 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
4
5
|
*/
|
|
5
6
|
import { createEndpointSpecification, endpointSpec, createEndpointLifecycle, createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
6
7
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
7
8
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
8
|
-
import { buildSendMessageParams, matchesOneBot12Self, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
9
|
+
import { buildSendMessageParams, matchesOneBot12Self, extractQuoteId, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
9
10
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
10
11
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
11
12
|
import { callOnebot12Client, readOnebot12Response, onebot12ClientOptions, forwardOnebot12ClientEvents, Onebot12Client } from './client.js';
|
|
@@ -144,15 +145,19 @@ export class OneBot12WssEndpoint extends Onebot12Client {
|
|
|
144
145
|
const conversation = { ...onebot12InboundConversation(String(this.#options.id), ev), endpoint: this[endpointSpec].identity };
|
|
145
146
|
const nickname = senderNickname(ev);
|
|
146
147
|
const mentioned = isBotMentioned(ev);
|
|
148
|
+
const quoteId = extractQuoteId(ev);
|
|
149
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
147
150
|
void this[endpointSpec].events.message({
|
|
148
151
|
event: ev,
|
|
149
152
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
150
153
|
conversation,
|
|
151
154
|
message: { conversation, id: ev.message_id },
|
|
152
155
|
content: formatInboundContent(ev),
|
|
156
|
+
...(segments?.length ? { segments } : {}),
|
|
153
157
|
sender: { id: senderUserId(ev), name: senderNickname(ev) },
|
|
154
158
|
endpointId: this.#options.config.id,
|
|
155
159
|
...(mentioned ? { mentioned: true } : {}),
|
|
160
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
156
161
|
metadata: Object.freeze({
|
|
157
162
|
detail_type: ev.detail_type,
|
|
158
163
|
user_id: ev.user_id,
|
|
@@ -188,8 +193,12 @@ export class OneBot12WssEndpoint extends Onebot12Client {
|
|
|
188
193
|
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
189
194
|
this.#ws = socket;
|
|
190
195
|
lifecycleHandle.onForceClose(() => {
|
|
196
|
+
if (this.#ws === socket) {
|
|
197
|
+
this.#rpc.disconnect();
|
|
198
|
+
}
|
|
191
199
|
try {
|
|
192
200
|
socket.close();
|
|
201
|
+
socket.terminate?.();
|
|
193
202
|
}
|
|
194
203
|
catch {
|
|
195
204
|
/* ignore */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-onebot12",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.23",
|
|
4
4
|
"description": "Zhin.js OneBot 12 adapter for Plugin Runtime (WebSocket client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -42,30 +42,31 @@
|
|
|
42
42
|
"@imhelper/onebot-v12": "1.0.7",
|
|
43
43
|
"imhelper": "1.0.7",
|
|
44
44
|
"ws": "^8.21.1",
|
|
45
|
-
"@zhin.js/adapter": "
|
|
46
|
-
"@zhin.js/
|
|
45
|
+
"@zhin.js/adapter-onebot-events": "0.0.2",
|
|
46
|
+
"@zhin.js/adapter": "1.1.29",
|
|
47
|
+
"@zhin.js/client": "1.1.25",
|
|
47
48
|
"@zhin.js/console-contract": "1.1.3",
|
|
48
|
-
"@zhin.js/core": "1.1.
|
|
49
|
-
"@zhin.js/feature-kit": "1.1.
|
|
50
|
-
"@zhin.js/host-http": "1.1.
|
|
51
|
-
"@zhin.js/im-contract": "1.1.
|
|
49
|
+
"@zhin.js/core": "1.1.57",
|
|
50
|
+
"@zhin.js/feature-kit": "1.1.13",
|
|
51
|
+
"@zhin.js/host-http": "1.1.15",
|
|
52
|
+
"@zhin.js/im-contract": "1.1.12",
|
|
52
53
|
"@zhin.js/logger": "1.1.2",
|
|
53
|
-
"@zhin.js/page": "1.1.
|
|
54
|
-
"@zhin.js/skill": "1.1.
|
|
54
|
+
"@zhin.js/page": "1.1.15",
|
|
55
|
+
"@zhin.js/skill": "1.1.14"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@types/node": "^26.1.2",
|
|
58
59
|
"@types/ws": "^8.18.1",
|
|
59
60
|
"typescript": "^6.0.3",
|
|
60
61
|
"vitest": "^4.1.10",
|
|
61
|
-
"@zhin.js/host-http": "1.1.
|
|
62
|
-
"zhin.js": "1.1.
|
|
62
|
+
"@zhin.js/host-http": "1.1.15",
|
|
63
|
+
"zhin.js": "1.1.22"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
|
-
"@zhin.js/adapter": "^1.1.
|
|
66
|
-
"@zhin.js/command": "^1.1.
|
|
67
|
-
"@zhin.js/core": "^1.1.
|
|
68
|
-
"zhin.js": "^1.1.
|
|
66
|
+
"@zhin.js/adapter": "^1.1.29",
|
|
67
|
+
"@zhin.js/command": "^1.1.15",
|
|
68
|
+
"@zhin.js/core": "^1.1.57",
|
|
69
|
+
"zhin.js": "^1.1.22"
|
|
69
70
|
},
|
|
70
71
|
"peerDependenciesMeta": {
|
|
71
72
|
"@zhin.js/command": {
|
package/plugin.js
CHANGED
|
@@ -3,6 +3,7 @@ import { definePlugin, pluginConsoleRpcToken } from 'zhin.js';
|
|
|
3
3
|
import { createOnebot12ConsoleRpc } from "./lib/console.js";
|
|
4
4
|
export default definePlugin({
|
|
5
5
|
name: 'onebot12',
|
|
6
|
+
configUpdate: { featurePaths: [['nickname'], ['profile'], ['endpoints']] },
|
|
6
7
|
metadata: {
|
|
7
8
|
displayName: 'OneBot 12 Adapter',
|
|
8
9
|
},
|
package/src/protocol.ts
CHANGED
|
@@ -278,6 +278,18 @@ export function isBotMentioned(ev: OneBot12Event): boolean {
|
|
|
278
278
|
);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
/** 提取入站消息中的回复引用 message_id。 */
|
|
282
|
+
export function extractQuoteId(ev: OneBot12Event): string | undefined {
|
|
283
|
+
if (!Array.isArray(ev.message)) return undefined;
|
|
284
|
+
for (const seg of ev.message) {
|
|
285
|
+
if (seg?.type === 'reply') {
|
|
286
|
+
const id = seg.data?.['message_id'] ?? seg.data?.['id'];
|
|
287
|
+
if (id != null && String(id).trim() !== '') return String(id);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
|
|
281
293
|
/** OneBot 12 携带媒体的段类型。 */
|
|
282
294
|
const ONEBOT12_MEDIA_TYPES = new Set(['image', 'voice', 'audio', 'video', 'file']);
|
|
283
295
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { receiveOneBotLikeSideEvent } from '@zhin.js/
|
|
1
|
+
import { receiveOneBotLikeSideEvent } from '@zhin.js/adapter-onebot-events';
|
|
2
2
|
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
3
3
|
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
4
|
import type { OneBot12Event } from './protocol.js';
|
package/src/webhook.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
import { acceptHttpIngress } from 'imhelper';
|
|
3
4
|
/**
|
|
4
5
|
* OneBot12 HTTP webhook endpoint — POST inbound + api_url outbound.
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
buildSendMessageParams,
|
|
22
23
|
matchesOneBot12Self,
|
|
23
24
|
callOneBot12Action,
|
|
25
|
+
extractQuoteId,
|
|
24
26
|
formatInboundContent,
|
|
25
27
|
formatOutboundSegments,
|
|
26
28
|
isBotMentioned,
|
|
@@ -164,15 +166,19 @@ export class OneBot12WebhookEndpoint extends Onebot12Client implements Endpoint
|
|
|
164
166
|
const content = formatInboundContent(ev);
|
|
165
167
|
const nickname = senderNickname(ev);
|
|
166
168
|
const mentioned = isBotMentioned(ev);
|
|
169
|
+
const quoteId = extractQuoteId(ev);
|
|
170
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
167
171
|
void this[endpointSpec].events.message({
|
|
168
172
|
event: ev,
|
|
169
173
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
170
174
|
conversation,
|
|
171
175
|
message: { conversation, id: ev.message_id },
|
|
172
176
|
content,
|
|
177
|
+
...(segments?.length ? { segments } : {}),
|
|
173
178
|
sender: { id: senderUserId(ev), ...(nickname ? { name: nickname } : {}) },
|
|
174
179
|
endpointId: this.#options.config.id,
|
|
175
180
|
...(mentioned ? { mentioned: true } : {}),
|
|
181
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
176
182
|
metadata: Object.freeze({
|
|
177
183
|
detail_type: ev.detail_type,
|
|
178
184
|
user_id: ev.user_id,
|
package/src/ws-endpoint.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot12 WS client endpoint — outbound connect to OneBot implementation.
|
|
4
5
|
*/
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
buildSendMessageParams,
|
|
23
24
|
matchesOneBot12Self,
|
|
24
25
|
buildWsConnectOptions,
|
|
26
|
+
extractQuoteId,
|
|
25
27
|
formatInboundContent,
|
|
26
28
|
formatOutboundSegments,
|
|
27
29
|
isBotMentioned,
|
|
@@ -182,15 +184,19 @@ export class OneBot12WsEndpoint extends Onebot12Client implements Endpoint {
|
|
|
182
184
|
const content = formatInboundContent(ev);
|
|
183
185
|
const nickname = senderNickname(ev);
|
|
184
186
|
const mentioned = isBotMentioned(ev);
|
|
187
|
+
const quoteId = extractQuoteId(ev);
|
|
188
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
185
189
|
void this[endpointSpec].events.message({
|
|
186
190
|
event: ev,
|
|
187
191
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
188
192
|
conversation,
|
|
189
193
|
message: { conversation, id: ev.message_id },
|
|
190
194
|
content,
|
|
195
|
+
...(segments?.length ? { segments } : {}),
|
|
191
196
|
sender: { id: senderUserId(ev), name: senderNickname(ev) },
|
|
192
197
|
endpointId: this.#options.config.id,
|
|
193
198
|
...(mentioned ? { mentioned: true } : {}),
|
|
199
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
194
200
|
metadata: Object.freeze({
|
|
195
201
|
detail_type: ev.detail_type,
|
|
196
202
|
user_id: ev.user_id,
|
|
@@ -228,8 +234,12 @@ export class OneBot12WsEndpoint extends Onebot12Client implements Endpoint {
|
|
|
228
234
|
const ws = create(url, { headers });
|
|
229
235
|
this.#ws = ws;
|
|
230
236
|
handle.onForceClose(() => {
|
|
237
|
+
if (this.#ws === ws) {
|
|
238
|
+
this.#rpc.disconnect();
|
|
239
|
+
}
|
|
231
240
|
try {
|
|
232
241
|
ws.close();
|
|
242
|
+
ws.terminate?.();
|
|
233
243
|
} catch {
|
|
234
244
|
/* ignore */
|
|
235
245
|
}
|
package/src/ws-types.ts
CHANGED
package/src/wss-endpoint.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOnebot12SelfProfile } from './self-profile.js';
|
|
2
|
+
import { toCanonicalSegments } from '@zhin.js/core';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot12 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
4
5
|
*/
|
|
@@ -20,6 +21,7 @@ import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
|
20
21
|
import {
|
|
21
22
|
buildSendMessageParams,
|
|
22
23
|
matchesOneBot12Self,
|
|
24
|
+
extractQuoteId,
|
|
23
25
|
formatInboundContent,
|
|
24
26
|
formatOutboundSegments,
|
|
25
27
|
isBotMentioned,
|
|
@@ -179,15 +181,19 @@ export class OneBot12WssEndpoint extends Onebot12Client implements Endpoint {
|
|
|
179
181
|
const conversation = { ...onebot12InboundConversation(String(this.#options.id), ev), endpoint: this[endpointSpec].identity };
|
|
180
182
|
const nickname = senderNickname(ev);
|
|
181
183
|
const mentioned = isBotMentioned(ev);
|
|
184
|
+
const quoteId = extractQuoteId(ev);
|
|
185
|
+
const segments = Array.isArray(ev.message) ? toCanonicalSegments(ev.message) : undefined;
|
|
182
186
|
void this[endpointSpec].events.message({
|
|
183
187
|
event: ev,
|
|
184
188
|
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
185
189
|
conversation,
|
|
186
190
|
message: { conversation, id: ev.message_id },
|
|
187
191
|
content: formatInboundContent(ev),
|
|
192
|
+
...(segments?.length ? { segments } : {}),
|
|
188
193
|
sender: { id: senderUserId(ev), name: senderNickname(ev) },
|
|
189
194
|
endpointId: this.#options.config.id,
|
|
190
195
|
...(mentioned ? { mentioned: true } : {}),
|
|
196
|
+
...(quoteId ? { replyTo: { id: quoteId } } : {}),
|
|
191
197
|
metadata: Object.freeze({
|
|
192
198
|
detail_type: ev.detail_type,
|
|
193
199
|
user_id: ev.user_id,
|
|
@@ -225,8 +231,12 @@ export class OneBot12WssEndpoint extends Onebot12Client implements Endpoint {
|
|
|
225
231
|
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
226
232
|
this.#ws = socket;
|
|
227
233
|
lifecycleHandle.onForceClose(() => {
|
|
234
|
+
if (this.#ws === socket) {
|
|
235
|
+
this.#rpc.disconnect();
|
|
236
|
+
}
|
|
228
237
|
try {
|
|
229
238
|
socket.close();
|
|
239
|
+
socket.terminate?.();
|
|
230
240
|
} catch {
|
|
231
241
|
/* ignore */
|
|
232
242
|
}
|